diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..b25c15b81f --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*~ 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" diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000000..cb1e39b845 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,45 @@ +Maintainers: + +Gwenole Beauchesne - Lead developer +Sreerenj Balachandran - Lead developer +Halley Zhao - MPEG-4:2 decoder + +This project is maintained by Intel Corporation. + +Contributors (sorted by first name): + +Adrian Cox +Alban Browaeys +Changzhi Wei +Cong Zhong +Emilio Lopez +Fabrice Bellet +Feng Yuan +Guangxin Xu +Haihao Xiang +Holger Kaelberer +Jacobo Aragunde Pérez +Jan Schmidt +Javier Jardon +Julien Isorce +Junfeng Xu +Kristian Hogsberg +Lim Siew Hoon +Lionel Landwerlin +Mark Nauwelaerts +Martin Sherburn +Matthew Waters +Matthieu Bouron +Michael Olbrich +Nicolas Dufresne +Olivier Crete +Philip Lorenz +Robert Bradford +Ross Burton +Sebastian Dröge +Simon Farnsworth +Thibault Saunier +Victor Manuel Jaquez Leal +Warly +Xiaowei Li +Yan Yin diff --git a/COPYING.LIB b/COPYING.LIB new file mode 100644 index 0000000000..4362b49151 --- /dev/null +++ b/COPYING.LIB @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000000..b04e5478d8 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,35983 @@ +=== release 1.19.2 === + +2021-09-23 01:35:54 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * gstreamer-vaapi.doap: + * meson.build: + Release 1.19.2 + +2021-08-26 15:06:53 +0800 Zhang Yuankun + + * gst/vaapi/gstvaapidecode.c: + vaapi: decoder: modify the condition to judge whether dma buffer is supported + It seems "GST_VAAPI_PLUGIN_BASE_SRC_PAD_CAN_DMABUF (decode)" will + return false even if this platform support the mem_type dma buffer. + And media-driver will return GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF2 + on Gen12(such as TGL). + Without this patch, The command such as: + gst-launch-1.0 videotestsrc num-buffers=100 ! video/x-raw, format=I420 ! \ + x264enc ! h264parse ! vaapih264dec ! video/x-raw\(memory:DMABuf\) ! fakesink + will return not-negotiated. + Signed-off-by: Zhang Yuankun + Part-of: + +2021-05-14 12:04:04 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst/vaapi/gstvaapivideocontext.c: + Display: Add a property to export the VA display handle. + Just like what we do in VA plugins. The display can be seen as a + generic gst object and we can add a property to get the internal + VA handle. + Part-of: + +2021-05-14 11:49:01 +0800 He Junyan + + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + plugins: video memory: Add a GST_MAP_VAAPI flag to peek the surface. + Just like what we do in VA plugins, the GST_MAP_VAAPI can directly + peek the surface of the VA buffers. The old flag 0 just peek the + surface proxy, which may not be convenient for the users who do not + want to include our headers. + Part-of: + +2021-07-09 11:01:14 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapidecode.c: + Revert "vaapi: Demote vaapidecodebin to rank NONE." + This reverts commit 7a25c5d4ec95aefeca6515ac023b23c5dd330194. + Part-of: + +2021-06-23 16:23:00 +0800 He Junyan + + * gst/vaapi/gstvaapiencode.c: + plugins: encode: fix a deadlock because of _drain() + We call gst_vaapiencode_drain() in gst_vaapiencode_change_state(), + whose context does not hold the stream lock of the encoder. The + current gst_vaapiencode_drain inside unlock/lock pair adds a extra + lock count to the stream lock of encoder and causes hang later. + We just remove the gst_vaapiencode_drain() and expand its logic + correctly according to the lock/unlock context. + Part-of: + +2021-06-29 15:09:13 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapidecoder_av1.c: + libs: decoder: av1: Clean the film_grain_info field. + We need to clean all film_grain_info fields when the film grain + feature is not enabled. It may have random data because the picture + parameter buffer is not cleaned. + Part-of: + +2021-06-03 22:12:04 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiutils_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiutils_mpeg2.h: + libs: encoder: mpeg2: Add highP level for 1080@50p/60p. + The MPEG2 spec has amendment 3 to introduce a new level highP, which + is used for 1080@50p/60p streams. We need to add this level to avoid + encoding failure because of the level check. + Fix: #306 + Part-of: + +2021-05-11 16:59:07 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + Decoder: H264: Add the support for frame packing arrangement SEI message. + Frame packing arrangement SEI message is an alternative simple stereo 3D + manner for AVC. We need to recognize that SEI message and report the correct + 3D caps. + Part-of: + +2021-05-22 18:54:49 +0100 Tim-Philipp Müller + + * gst-libs/gst/vaapi/gstvaapifilter.c: + * meson.build: + Use g_memdup2() where available and add fallback for older GLib versions + Alloc size is based on existing allocations and struct sizes. + g_memdup() is deprecated since GLib 2.68 and we want to avoid + deprecation warnings with recent versions of GLib. + Part-of: + +2021-06-01 15:29:16 +0100 Tim-Philipp Müller + + * meson.build: + Back to development + +=== release 1.19.1 === + +2021-06-01 00:16:31 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * gstreamer-vaapi.doap: + * meson.build: + Release 1.19.1 + +2021-04-23 19:01:54 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapidecode.c: + vaapi: Demote vaapidecodebin to rank NONE. + One of the main reasons of vaapidecodebin was because it mitigated the + possible surface exhaustion. But that problem is currently + solved. Nowadays, vaapidecodebin brings more problems than it + solves. Thus this patch demotes vaapidecodebin to NONE rank while + bumping PRIMARY + 1 the most common decoders. + Part-of: + +2021-05-20 10:28:05 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapioverlay.c: + plugins: Demote rank of vaapipostproc and vaapioverlay. + Since almost all video filters have rank NONE, these both elements + should be NONE too. + This is useful for autovideoconvert and other bins, and users might + force to use these by setting the environment variable + GST_PLUGIN_FEATURE_RANK. + Part-of: + +2021-04-21 10:55:45 +0200 François Laignel + + * tests/check/elements/vaapioverlay.c: + Use gst_element_request_pad_simple... + Instead of the deprecated gst_element_get_request_pad. + Part-of: + +2021-04-23 11:02:05 +0800 Zhang yuankun + + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + libs: encoder: VP9: fix > 4k encode fail issue + The VP9 spec defines the MAX_TILE_WIDTH_B64(64), which is the maximum + width of a tile in units of superblocks. So the max width of one tile + should not be larger than 64x64=4096. When the width exceeds 4k, we + need to split it into multiple tiles in columns. The current vp9 encoder + does not handle this correctly. + The command such as: + gst-launch-1.0 videotestsrc ! video/x-raw,width=7680,height=4320 ! \ + vaapivp9enc ! fakesink + will crash. + Part-of: + +2021-04-02 15:43:45 +0800 Haihao Xiang + + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + libs: display: drm: don't fallback to default device if explicitly specified device can't load/init + Otherwise user will be misled that the specified device is using + This fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi/-/issues/305 + Part-of: + +2021-03-22 13:41:13 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_objects.h: + decoder: H265: Enable cu_qp_delta_enabled_flag when ROI + If ROI is enabled, the CUs within the ROI region may have different + QP from the other part of the picture. This needs us to enable the + cu_qp_delta_enabled_flag even in the CQP mode. + Part-of: + +2021-03-19 17:42:36 +1100 Matthew Waters + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapiminiobject.c: + * gst-libs/gst/vaapi/gstvaapiminiobject.h: + * gst-libs/gst/vaapi/gstvaapitexture_glx.c: + * gst-libs/gst/vaapi/gstvaapiutils_egl.c: + * gst-libs/gst/vaapi/gstvaapiutils_egl.h: + * gst-libs/gst/vaapi/gstvaapivalue.c: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + * gst/vaapi/gstvaapivideocontext.c: + * gst/vaapi/gstvaapivideomemory.c: + * tests/internal/simple-decoder.c: + gst: don't use volatile to mean atomic + volatile is not sufficient to provide atomic guarantees and real atomics + should be used instead. GCC 11 has started warning about using volatile + with atomic operations. + https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1719 + Discovered in https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/868 + Part-of: + +2021-02-24 17:41:02 +0100 Paul Goulpié + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + gstvaapiencoder_h264: add ENCODER_EXPOSURE on aud propertie + forgot during the following mainline commit: https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi/-/commit/bc2f8fd19e924aa0e193708307326acd037691ce# + Signed-off-by: Paul Goulpié + +2021-02-04 15:05:55 +0800 He Junyan + + * gst/vaapi/gstvaapipostproc.c: + plugins: postproc: Fix a problem of propose_allocation when passthrough. + We should query the downstream element to answer a precise allocation + query when the passthrough mode is enabled. + The current way still decides the allocation by the postproc itself. The + pipeline such as: + gst-launch-1.0 -v filesrc location=xxx.264 ! h264parse ! vaapih264dec ! \ + vaapipostproc ! fakevideosink silent=false sync=true + will lose some info such as the GST_VIDEO_META_API_TYPE. + Part-of: + +2021-01-27 12:05:44 +0800 Haihao Xiang + + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.h: + * gst/vaapi/gstvaapivideocontext.c: + libs: display: drm: support gst.vaapi.app.Display context for drm backend + Attributes for drm backend: + - va-display : ponter of VADisplay + - drm-device-fd : the DRM device file descriptor + Part-of: + +2021-01-13 14:43:20 +0800 Haihao Xiang + + * docs/index.md: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + libs: display: drm: allow user specify a drm device via an env variable + Currently the default drm device is always used on a system with + multiple drm devices. This patch allows user to specify the required + drm device via GST_VAAPI_DRM_DEVICE env variable + Example: + GST_VAAPI_DRM_DEVICE=/dev/dri/renderD129 gst-launch-1.0 videotestsrc ! + vaapih264enc ! fakesink + Part-of: + +2021-01-25 14:45:47 +0800 Haihao Xiang + + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + libs: display: drm: fix set_device_path_from_fd + drmGetBusid() (GET_UNIQUE ioctl) won't return a valid bus id when + drmSetInterfaceVersion() (SET_VERSION ioctl) hasn't been called(see[1]), + so we can't get the right device path. Running test-display will get the + error below: + ** (test-display:18630): ERROR **: 10:26:00.434: could not create Gst/VA + display + Calling drmSetInterfaceVersion() before drmGetBusid() can't fix this + issue because a special permission is required for SET_VERSION ioctl. + This patch retrieves the device path from file descriptor via + g_file_read_link() + [1] https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/drm_ioctl.c#L48-L104 + Part-of: + +2021-01-20 10:42:09 +0100 Rafał Dzięgiel + + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + glx: Iterate over FBConfig and select 8 bit color size + Texture upload mechanism used by gstreamer-vaapi relies on 8 bpc. + In latest mesa versions the first fbconfig might not be 8 bit, so iterate + over it to find the correct config with supported values. + This also adds 8 bit alpha size to the framebuffer configuration which is + required to get it working properly. + Part-of: + +2021-01-11 09:57:03 +0800 Ung, Teng En + + * gst-libs/gst/vaapi/gstvaapiutils.c: + vaapipostproc: fix code style. + Part-of: + +2020-12-21 05:42:00 +0000 Ung, Teng En + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapifilter.c: + vaapipostproc: Remove YUV to/from RGB color primary quirk since iHD driver has fixed in https://github.com/intel/media-driver/commit/a39fe9bc051a8c3efa8f35122a1585981ec7f816. + Part-of: + +2020-12-21 05:36:29 +0000 Ung, Teng En + + * gst-libs/gst/vaapi/gstvaapiutils.c: + vaapipostproc: Added gstreamer BT2020 color standard support. + Part-of: + +2021-01-09 16:05:48 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapidecoder_av1.c: + decoder: AV1: Fix a static analysis problem of update_state(). + No need to check the picture pointer after we have already dereferenced it. + Fix: #298 + Part-of: + +2020-12-22 23:43:52 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapidecoder_av1.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + libs: decoder: Add decode_with_surface_id for AV1 film_grain. + The AV1 film_graim feature needs two surfaces the same time for + decoding. One is for recon surface which will be used as reference + later, and the other one is for display. The GstVaapiPicture should + contain the surface for display, while the vaBeginPicture() need + the recon surface as the target. + We add a gst_vaapi_picture_decode_with_surface_id API to handle this + kind of requirement. + Part-of: + +2020-08-27 21:46:41 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapidecoder_av1.c: + * gst-libs/gst/vaapi/gstvaapidecoder_av1.h: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/meson.build: + * gst/vaapi/gstvaapidecode.c: + * meson.build: + libs: decoder: AV1: Add the av1 decoder support. + Part-of: + +2020-08-27 21:39:35 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapicodec_objects.c: + * gst-libs/gst/vaapi/gstvaapicodec_objects.h: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + libs: codecobject: Add number of elements when create codec object. + One slice data may need several slice parameter buffers at one time. + Part-of: + +2020-12-12 10:30:41 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecodebin.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapivideobufferpool.c: + vaapi: use gst_clear_object instead of g_clear_object + Part-of: + +2020-12-08 13:34:35 +0800 He Junyan + + * gst/vaapi/gstvaapiencode.c: + plugins: encode: unlock the stream lock before _flush() + The current encoder will hang when EOS comes. When we call the + gst_vaapi_encoder_encode_and_queue(), we should release the stream + lock, just like what we do in gst_vaapiencode_handle_frame(). + The deadlock happens when: The input thread holding the stream lock + is using gst_vaapi_encoder_create_coded_buffer() to acquire a coded + buffer, while the output thread which holding the coded buffer resource + is acquiring the stream lock in _push_frame() to push the data to + down stream element. + Part-of: + +2020-12-09 00:04:33 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + libs: encoder: H264: Fix one assert in get_pending_reordered(). + gst_vaapi_encoder_h264_get_pending_reordered() does not consider the + case for HIERARCHICAL_B mode. The pipeline: + gst-launch-1.0 videotestsrc num-buffers=48 ! vaapih264enc prediction-type=2 \ + keyframe-period=32 ! fakesink + get a assert: + ERROR:../gst-libs/gst/vaapi/gstvaapiencoder_h264.c:1996:reflist1_init_hierarchical_b: + assertion failed: (count != 0) + The last few B frames are not fetched in correct order when HIERARCHICAL_B + is enabled. + We also fix a latent bug for normal mode. The g_queue_pop_tail() of B frames + make the last several frames encoded in reverse order. The NAL of last few + frames come in reverse order in the bit stream, though it can still output + the correct image. + Part-of: + +2020-06-25 16:25:21 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + libs: encoder: H265: Add screen content coding extensions support. + In scc mode, the I frame can ref to itself and it needs the L0 reference + list enabled. So we should set the I frame to P_SLICE type. We do not need + to change the ref_pic_list0/1 passed to VA driver, just need to enable the + VAEncPictureParameterBufferHEVC->pps_curr_pic_ref_enabled_flag to notify + the driver consider the current frame as reference. For bits conformance, + the NumRpsCurrTempList0 should be incremented by one to include the current + picture as the reference frame. We manually do it when packing the slice header. + Command line like: + gst-launch-1.0 videotestsrc num-buffers=10 ! \ + capsfilter caps=video/x-raw,format=NV12, framerate=30/1,width=640,height=360 ! \ + vaapih265enc ! capsfilter caps=video/x-h265,profile="{ (string)screen-extended-main }" ! \ + filesink location=out.265 + Can be used to specify that the encoder should use SCC profiles. + Part-of: + +2020-07-11 23:37:29 +0800 He Junyan + + * gst/vaapi/gstvaapiencode_vp9.c: + plugin: encode: vp9: Implement the set_config(). + We store the allowed profiles list to encoder in set_config(). + Part-of: + +2020-07-11 23:39:40 +0800 He Junyan + + * gst/vaapi/gstvaapiencode_vp9.c: + plugin: encode: vp9: Add the profile into output caps. + Part-of: + +2020-07-11 23:27:21 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + libs: encoder: vp9: no need to ensure_hw_profile. + Once we decide the profile and can get the valid entrypoint for + that profile, hw must already support this profile/entrypoint pair. + No need to check it again in set_context_info(). + Part-of: + +2020-07-11 23:22:55 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + libs: encoder: vp9: Improve the manner to decide the profile. + We should decide the VP9 encoder's profile based on the chroma and + depth of the input format, then make sure it is included in the + allowed list. + Part-of: + +2020-07-11 23:17:02 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiutils_vpx.c: + * gst-libs/gst/vaapi/gstvaapiutils_vpx.h: + libs: util: vpx: add get_chroma_format_idc for VP9 + Part-of: + +2020-07-11 23:09:59 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.h: + libs: encoder: vp9: Add allowed_profiles. + We need the allowed_profiles to store the allowed profiles in down + stream's caps. + Command line like: + vaapivp9enc ! capsfilter caps=video/x-vp9,profile="{ (string)1, \ + (string)3 }" + We need to store GST_VAAPI_PROFILE_VP9_1 and GST_VAAPI_PROFILE_VP9_3 + in this list. + Part-of: + +2020-11-30 18:00:30 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + libs: decoder: H265: Fix a typo in scc reference setting. + Part-of: + +2020-07-17 18:00:30 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + * gst-libs/gst/vaapi/video-format.c: + * gst/vaapi/gstvaapidecode.c: + libs: decoder: H265: Add MAIN_422_12 profile supporting. + Part-of: + +2020-07-31 14:38:42 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/video-format.c: + * gst-libs/gst/vaapi/video-format.h: + video-format: Add Y212_LE format. + It can be used as HEVC YUV_4:2:2 12bits stream's decoder output, and + also can be used as the input format for encoding HEVC YUV_4:2:2 12bits + stream. + Part-of: + +2020-07-30 23:21:06 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + * gst-libs/gst/vaapi/video-format.c: + * gst/vaapi/gstvaapidecode.c: + libs: decoder: H265: Add MAIN_444_12 profile supporting. + Part-of: + +2020-07-30 23:13:10 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/video-format.c: + * gst-libs/gst/vaapi/video-format.h: + video-format: Add Y412_LE format. + It can be used as HEVC YUV_4:4:4 12bits stream's decoder output, and + also can be used as the input format for encoding HEVC YUV_4:4:4 12bits + stream. + Part-of: + +2020-09-17 16:47:43 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + libs: decoder: h265: fill missing predictor_palette_size field. + The predictor_palette_size of VAPictureParameterBufferHEVCScc is + forgotten and need to be filled when streams have palettes. + Part-of: + +2020-09-17 15:35:11 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + libs: utils: h265: Use get_profile_from_sps to get profile. + We now use gst_h265_get_profile_from_sps() to replace the old way + of gst_h265_profile_tier_level_get_profile() to get more precise + profile. The new function consider the unstandard cases and give + a more suitable profile decision. + Part-of: + +2020-10-19 13:46:44 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + libs: decoder: vp9: 0xff segment pred probs if no temporal update + According to the spec (6.2.11 Segmentation params syntax) + segmentation_pred_prob[i] ast to be 0xff if not temporal_update. + Part-of: + +2020-10-19 13:42:53 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + libs: decoder: vp9: avoid reference rewriting + The removed code set all the reference frames to the current frame it is a key + one, but later, all the reference frames were rewritten with the decoded picture + buffers or VA_INVALID_SURFACE if they were not available. + Basically, all this time the first reference frame assignment has been ignored, + and it's not described by the spec, and this patch removes that code. + Part-of: + +2020-09-20 09:56:40 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + decoder: don't reply src caps query with allowed if pad is fixed + If the pad is already fixed the caps query have to be reply with the + current fixed caps. Otherwise the query has to be replied with the + autogeneratd src caps. + This path fix this by falling back to the normal caps query processing + if the pad is already fixed. Otherwise it will fetch the allowed src + pad caps. + Part-of: + +2020-09-15 00:11:30 +0800 He Junyan + + * gst/vaapi/gstvaapidecode.c: + plugins: decode: fix a DMA caps typo in ensure_allowed_srcpad_caps. + Part-of: + +2020-09-01 09:31:33 +0200 Marc Leeman + + * gst/vaapi/gstvaapisink.c: + vaapisink: when updating the caps, reset rotation + When an element upstream changes settings (e.g. crop), new caps are sent + to vaapisink. When vaapisink was rotating the image, it needs to + re-evaluate if the sink needs to rotate the image. + Part-of: + +2020-09-08 17:31:02 +0100 Tim-Philipp Müller + + * .gitlab-ci.yml: + ci: include template from gst-ci master branch again + +2020-09-08 16:59:07 +0100 Tim-Philipp Müller + + * meson.build: + Back to development + +=== release 1.18.0 === + +2020-09-08 00:09:51 +0100 Tim-Philipp Müller + + * .gitlab-ci.yml: + * ChangeLog: + * NEWS: + * RELEASE: + * gstreamer-vaapi.doap: + * meson.build: + Release 1.18.0 + +2020-09-07 12:15:43 +0300 Sebastian Dröge + + * gst-libs/gst/vaapi/gstvaapifilter.c: + Update for gst_video_transfer_function_*() function renaming + Part-of: + +2020-08-22 12:53:12 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + Revert "libs: decoder: h264, h265: in context at least 16 reference surfaces" + This reverts commit b387081a4d77d3da202da72686ab40fb9c83ee1e as discussed in + https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi/-/commit/b387081a4d77d3da202da72686ab40fb9c83ee1e + +=== release 1.17.90 === + +2020-08-20 16:16:25 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * gstreamer-vaapi.doap: + * meson.build: + Release 1.17.90 + +2020-08-17 11:43:53 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapisurface_egl.c: + libs: surface: egl: guard memory type + Part-of: + +2020-08-17 19:26:43 +0800 He Junyan + + * gst/vaapi/gstvaapidecode.c: + plugin: decode: Fix two mem leaks because of caps. + Part-of: + +2020-08-16 01:57:15 +0800 He Junyan + + * gst/vaapi/gstvaapivideomemory.c: + plugin: allocator: No need to ref allocator when create mem. + We do not need to ref the allocator when creating GstVaapiVideoMemory + kind memory, and then release it in _free(). The framework already + does it for us. + Part-of: + +2020-08-14 10:42:51 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode_h264.c: + vaapiencode: h264: ignore level without breaking negotiation + Since commit 9f627ef2 if the user sets level in the encoder src caps + the caps negotiation is rejected. + But since the same commit the same encoder set the autoconfigured + level in caps. Some change in the base class might fixed the operation + order so now the caps are set and later negotiated. + This patch removes the level check. + Fixes: #273 + Part-of: + +2019-07-09 19:17:48 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/egl_vtable.h: + * gst-libs/gst/vaapi/gstvaapisurface_egl.c: + * gst-libs/gst/vaapi/gstvaapisurface_egl.h: + * gst-libs/gst/vaapi/gstvaapitexture_egl.c: + libs: egl: surface: export EGLImage as DMABuf if GEM not supported + This code path is used when frames are rendered as textures through + GstVideoGLTextureUploadMeta with EGL, mainly under Wayland. + Originally the EGLImage was exported as GEM, which was handled by + Intel drivers, but Gallium ones cannot create VA surfaces from + GEM buffers, only DMABuf. + This patch checks the memory types supported by VA driver to choose + the render the EGLImages from GEM or DMABuf, because GEM is still + better where supported. + DMABuf is well handled either by intel-vaapi-driver and gallium. + Fixes: #137 + Part-of: + +2020-05-26 16:18:32 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapifilter.h: + libs: filter: gst_vaapi_filter_get_memory_types() + Part-of: + +2020-08-12 18:48:59 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + plugins: remove gst_vaapi_plugin_base_get_allowed_srcpad_raw_caps() + Since nobody uses it, just remove it. + Thus extract_allowed_surface_formats() is refactored to attend only + gst_vaapi_plugin_base_get_allowed_sinkpad_raw_caps(). + Now a surface is created when the image chorma is different from the + previous one. And if the driver has the quirk, it outputs all the + supported image formats without trying them. + Part-of: + +2020-08-12 17:50:50 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: expose raw src caps with same chroma + The try-and-error approach for getting the possible image formats from + a surface has brought several problems in different drivers, from + crashes to drop in performance. + Instead of that we change the algorithm to determine the possible + image formats based in the surface chroma: only those available image + formats with same chroma are exposed as possible raw caps. + Do this is important to avoid performance degrading in raw sinks + which doesn't handle NV12 but it does YV12 or I420. + Part-of: + +2020-07-10 17:05:38 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + libs: util: h265: use common parser API to get vaapi profiles. + We can reuse H265 parser's API to recognize the correct profile and + then just need to convert them to VAAPI profiles. + Part-of: + +2020-08-07 16:41:49 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/meson.build: + * gst/vaapi/meson.build: + * meson.build: + build: update for gl pkg-config file split + Part-of: + +2020-08-06 12:51:27 +0800 Xu Guangxin + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264dec: mark remaining frames as unreference before exec_picture_refs_modification + 8.2.4.2 required this. Some clips will crash if we do not fill the reference list like this. + Part-of: + +2020-07-31 18:22:46 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + libs: encoder: H265: Enable Main 12 profile support. + Part-of: + +2020-07-31 19:17:39 +0800 He Junyan + + * gst-libs/gst/vaapi/video-format.c: + video format: Fix P012_LE's chrome type typo. + Part-of: + +2020-08-04 21:15:01 +0300 Jordan Petridis + + * gst-libs/gst/vaapi/gstvaapiminiobject.c: + gstvaapiminiobject.c: fix clang 10 warnings + the typesystem checks in g_atomic_pointer_compare_and_exchange + seem to trigger some false positives with clang 10 + similar to gstreamer!584 + Part-of: + +2020-07-31 11:07:23 +0200 Michael Olbrich + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + libs: window: wayland: destroy all wayland buffers during finalize + Some buffers and the associated FrameState state may still be pending at + that point. If the wayland connection is shared, then messages for the + buffer may still arrive. However, the associated event queue is already + deleted. So the result is a crash. + With a private connection the associated memory is leaked instead. + Part-of: + +2020-06-18 20:25:18 +0200 Michael Olbrich + + * tests/examples/test-vaapicontext.c: + test: vaapicontext: fix draw callback with multiple videos + The callback is called for both windows. So make sure that + gst_video_overlay_set_render_rectangle() is called for the correct one. + Otherwise, the left video will be randomly moved behind the right video. + Part-of: + +2020-06-19 09:23:52 +0200 Michael Olbrich + + * tests/examples/meson.build: + * tests/examples/test-vaapicontext.c: + test: vaapicontext: support wayland display + On Wayland, The whole gtk window is one Wayland surface. So + gtk_widget_get_window() must be called on the top-level widget. + For any other widget the following gdk_window_ensure_native() may create a + new top-level Wayland surface that is never visible. + As a result, the coordinates passed to + gst_video_overlay_set_render_rectangle() must be relativ to the top-level + window. Otherwise the video is placed incorrectly. + Original-Patch-By: Víctor Manuel Jáquez Leal + Part-of: + +2017-12-01 20:18:28 +0100 Víctor Manuel Jáquez Leal + + * tests/examples/test-vaapicontext.c: + test: vaapicontext: use playbin to test files + Part-of: + +2017-11-29 11:11:39 +0100 Víctor Manuel Jáquez Leal + + * tests/examples/test-vaapicontext.c: + test: vaapicontext: add PLAY and NULL buttons + They only appear when only one sink is instanciated and their purpose + is to test the NULL-PLAY use case in context sharing. + Part-of: + +2020-06-19 21:26:52 +0200 Michael Olbrich + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + libs: wayland: update the opaque region in set_render_rect + gst_vaapi_window_wayland_set_render_rect() may be called from an arbitrary + thread. That thread may be responsible for making the window visible. + At that point another thread will block in gst_vaapi_window_wayland_sync() + because the frame callback will not be called until the window is visible. + If that happens, then acquiring the display lock in + gst_vaapi_window_wayland_set_render_rect() would result in a deadlock. + Cache the size of the opaque rectangle separately and create the opaque + region right before applying it to the surface. + Part-of: + +2020-06-19 09:21:16 +0200 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + * gst/vaapi/gstvaapisink.c: + libs: window: implements gst_vaapi_window_set_render_rectangle + Implements new vmethod gst_vaapi_window_set_render_rectangle, + which is doing set the information of the rendered rectangle set by + user. + This is necessary on wayland at least to get exact information of + external surface. + And vaapisink calls this when gst_video_overlay_set_render_rectangle is + called. + Part-of: + +2017-11-08 13:23:39 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapisink.c: + vaapisink: implements gst_vaapisink_wayland_create_window_from_handle() + Implements gst_vaapisink_wayland_create_window_from_handle() to support + using external wl_surface. + Part-of: + +2020-06-19 09:11:20 +0200 Michael Olbrich + + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.h: + libs: wayland: implement video overlay API + The Wayland sub-surfaces API is used to embed the video into an application + window. + See Appendix A. Wayland Protocol Specification as the following. + """ + The aim of sub-surfaces is to offload some of the compositing work + within a window from clients to the compositor. A prime example is + a video player with decorations and video in separate wl_surface + objects. + This should allow the compositor to pass YUV video buffer processing to + dedicated overlay hardware when possible. + """ + Added new method gst_vaapi_window_wayland_new_with_surface() + Original-Patch-By: Víctor Manuel Jáquez Leal + Zhao Halley + changzhix.wei@intel.com + Hyunjun Ko + Part-of: + +2020-06-19 21:54:52 +0200 Michael Olbrich + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + doc: libs: wayland: add 'transfer full' to the returnvalye of gst_vaapi_window_wayland_new + Part-of: + +2020-06-11 08:25:57 +0200 Michael Olbrich + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + libs: display: always call close_display() + All close_display() have their own checks for use_foreign_display and only + destroy locally created objects in that case. + Without this objects other than the actuall foreign display itself are + leaked. + Part-of: + +2020-07-30 23:37:10 +0800 He Junyan + + * gst-libs/gst/vaapi/video-format.h: + video-format: Add the missing P012_LE into GST_VAAPI_FORMATS_ALL. + Part-of: + +2020-05-25 17:02:26 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + plugins: add gst_vaapi_caps_set_width_and_height_range() + This utility function is called internally by + gst_vaapi_build_caps_from_formats() and can be used outside. + This function sets frame size and framerates ranges. + Also gst_vaapi_build_caps_from_formats() is simplified. + Part-of: + +2020-07-31 15:27:38 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + libs: decoder: fix a crash issue when get_surface_formats. + Some context does not report any valid format that we can support. + For example, the HEVC 444 12 bits decoder context, all the formats + it reports is not supported now, which make the formats list a NULL + array. We should check that pointer before we use it. + Part-of: + +2020-07-03 19:28:28 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: choose the profile based on allowed list. + We can decide the profile in ensure_profile(), based on allowed list + passed by the encode. We also need to check whether the entrypoint is + available. Once it is decided, no need to check the hw entrypoint + them again. + Part-of: + +2020-07-29 22:05:41 +0800 He Junyan + + * gst/vaapi/gstvaapiencode_h265.c: + plugins: encode: h265: set all allowed profiles to encoder. + We should collect all allowed profiles and pass them to the inside + encoder, rather than just calculate the max profile idc. + The allowed profiles should also be supported by the HW. + Part-of: + +2020-07-29 22:32:55 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + libs: display: Add a helper function to get profiles by codec. + Part-of: + +2020-07-03 01:28:28 +0800 He Junyan + + * gst/vaapi/gstvaapiencode_h265.c: + plugins: encode: h265: collect all allowed profiles to encoder. + We should collect all allowed profiles and pass them to the inside + encoder, rather than just calculate the max profile idc. + Part-of: + +2020-07-03 00:53:31 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.h: + * gst/vaapi/gstvaapiencode_h265.c: + libs: encoder: h265: modify set_max_profile to set_allowed_profiles. + In h265, bigger profile idc may not be compatible with the small profile + idc. And more important, there are multi profiles with the same profile + idc. Such as main-422-10, main-444 and main-444-10, they all have profile + idc 4. + So recording the max profile idc is not enough, the encoder needs to know + all allowed profiles when deciding the real profile. + Part-of: + +2020-07-02 23:33:31 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: No need to check hw_max_profile. + In h265, higher profile idc number does not mean better compression + performance and may be not compatible with the lower profile idc. + So, it is not suitable to find the heighest idc for hw to ensure the + compatibility. + On the other side, when the entrypoint of the selected profile is valid, + it means the hw really support this profile, no need to check it again. + Part-of: + +2020-04-08 19:41:09 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: early return if fixate srcpad caps fails + Part-of: + +2020-07-29 13:39:44 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + vaapipluginutil: simplify gst_vaapi_find_preferred_caps_feature() + Generalize the way how the preferred color format is chosen. Also + use new GStreamre API as syntatic sugar. + Part-of: + +2020-07-29 14:22:18 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapiencode.c: + libs: profile: Use get_codec_from_caps to get codec type. + There is no need to get a profile from the caps and then convert + that profile into codec type. We can get the codec type by caps's + name easily. + Part-of: + +2020-07-12 19:42:40 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + libs: profile: h265: Fix return value of from_codec_data_h265. + profile_from_codec_data_h265() returns wrong GstVaapiProfile for h265. + The codec data of caps contain the profile IDC, but the mapping between + profile IDC and GstVaapiProfile is wrong. + Part-of: + +2020-07-07 00:46:23 +0800 He Junyan + + * gst/vaapi/gstvaapiencode_vp9.c: + plugins: encode: vp9: Implement vp9's allowed_profiles() func. + Part-of: + +2020-07-08 16:30:17 +0800 He Junyan + + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h265.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + plugin: util: rename h26x_encoder_get_profiles_from_caps(). + Change its name to encoder_get_profiles_from_caps(). Other codecs such + as VP9 also needs to use this function. + Part-of: + +2020-07-06 23:35:12 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiutils_vpx.c: + * gst-libs/gst/vaapi/gstvaapiutils_vpx.h: + * gst-libs/gst/vaapi/meson.build: + libs: utils: vpx: Add utils vpx to handle VP8/9 misc things. + Part-of: + +2020-07-29 10:17:31 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + libs: display, context: handle broken jpeg decoder for i965 driver + JPEG decoding in i965 driver is pretty much broken, and the driver is + deprecated which mean authors only accept trivial fixes. + Surfaces for JPEG decoder context in i965 only handle IMC3[1] color + format which is not a common format in GStreamer. It can export it to + I420 at mapping raw bytes, but DMABuf exporting is problematic. + This patch artificially adds NV12 to the context format list when it's + JPEG decoder for i965 and force the usage of old VA-API for surface + creation without specifying color format. Also it artificially + disables the DMABuf announcement. + 1. https://docs.microsoft.com/en-us/windows/win32/medfound/recommended-8-bit-yuv-formats-for-video-rendering#420-formats-16-bits-per-pixel + Part-of: + +2020-07-29 12:02:50 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapicontext.c: + libs: context: change function to internal code style + Instead of a getter the function `get_preferred_format()` to + `ensure_preferred_format()` which aligns to the code style. + Part-of: + +2020-07-28 20:00:09 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: always merge profile caps in sink caps + This commit fixes a regression of e962069d, where if the profile's + caps doesn't have a caps profile, it's ignored. + This patch add a conditional jump if the caps doesn't have a profile + field to merge it. + Fixes: #271 + Part-of: + +2020-07-28 12:22:40 +0200 Víctor Manuel Jáquez Leal + + * meson.build: + build: request libdrm >= 2.4.98 and fallback + Fixes: #270 + Part-of: + +2020-05-18 17:32:27 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: dma caps only use reported color format + This fix pipelines without vaapipostproc after vaapi decoder, such as + gst-launch-1.0 filesrc location=~/file.mp4 ! parsebin ! vaapih264dec ! glimagesink + On EGL platforms, so DMABuf is used. + Part-of: + +2020-02-07 17:10:45 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: use allowed srcpad caps for caps query + Instead of using just the template caps use the current allowed + srcpad caps, which is created considering the current decoder + context. + Part-of: + +2020-01-22 17:41:28 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst/vaapi/gstvaapidecode.c: + vaapidecode: build allowed srcpad caps from va context + Instead of generating allowed srcpad caps with generic information, + now it takes the size an formats limits from the decoder's context. + This is possible since srcpad caps are generated after the internal + decoder is created. + The patch replaces gst_vaapi_decoder_get_surface_formats() with + gst_vaapi_decoder_get_suface_attributes(). + From these attributes, formats are only used for VASurface memory + caps feature. For system memory caps feature, the old + gst_vaapi_plugin_get_allowed_srcpad_caps() is still used, since + i965 jpeg decoder cannot deliver mappable format for gstreamer. + And for the other caps features (dmabuf and texture upload) the + same static list are used. + This patch also adds DMABuf caps feature only if the context + supports that memory type. Nonetheless, we keep the pre-defined + formats since they are the subset of common derive formats formats + supported either by amd/gallium and both intel drivers, since, + when exporting the fd through vaAcquireBufferHandle()/ + vaReleaseBufferHandle(), the formats of the derivable image cannot + be retriebable from the driver. Later we'll use the attribute + formats for the DMABuf feature too, when the code be ported to + vaExportSurfaceHandle(). + Finally, the allowed srcpad caps are removed if the internal decoder + is destroyed, since context attribues will change. + Part-of: + +2020-02-07 16:50:52 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: reorder src caps template + Since negotiation depends on caps order, first is VA, then DMABuf, + later GLUploadTexture (deprecated) and finally raw. + Also, for decoders, the possible available color formats for DMABuf + is extended to all the possible VA color formats. + Part-of: + +2020-07-22 10:01:41 +0200 Michael Olbrich + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + libs: window: wayland: use dmabuf protocol if available + Currently vaGetSurfaceBufferWl() is used to create wayland buffers. + Unfortunately this is not implemented by the 'media-driver' and Mesa VA-API + drivers. And the implementation provided by 'intel-vaapi-driver' is not + compatible with a Wayland server that uses the iris Mesa driver. + So create the Wayland buffers manually with the zwp_linux_dmabuf_v1 wayland + protocol. Formats and modifiers supported by the Wayland server are taken + into account. If necessary, VPP is enabled to convert the buffer into a + supported format. + Fall back to vaGetSurfaceBufferWl() if creating buffers via dambuf protocol + fails. + Part-of: + +2020-07-21 10:03:19 +0200 Michael Olbrich + + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow_priv.h: + libs: window: allow choosing the format for the vpp pool + Signed-off-by: Michael Olbrich + Part-of: + +2020-06-28 17:42:29 +0200 Michael Olbrich + + * gst-libs/gst/vaapi/video-format.c: + * gst-libs/gst/vaapi/video-format.h: + video-format: add DRM formats to the mapping table + This will be needed for the DMABuf protocol support to map DRM formats to + vaapi and gstreamer formats. + Part-of: + +2020-07-22 09:36:18 +0200 Michael Olbrich + + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland_priv.h: + * gst-libs/gst/vaapi/meson.build: + libs: display: wayland: add basic dmabuf protocol support + This is just the basic infrastructure. Hook up the interface and collect + all supported formats. + Part-of: + +2020-07-06 09:59:40 +0200 Michael Olbrich + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + libs: window: wayland: wait for configure before committing the first buffer + Committing the first buffer for a surface must not be done before + ack_configure() has been sent for the xdg_surface. + With weston, the commit will fail with "error 3: xdg_surface has never been + configured". + Wait in gst_vaapi_window_wayland_show() until configure is done to avoid + this. + Part-of: + +2020-07-01 14:50:51 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: set no P frame automatically. + The double reference lists may be required by drivers and there should + be no P frames in the of stream. The old way of converting P frames to + B frames is by setting `low-delay-b` property, which is unconvenient + and has bad user experience, since most of the users do not know when + to set this property, and if it is not set correctly, the encoding + pipeline fails or even hangs on some platforms. VA driver now provides + a attribute to query whether both reference lists must be un-NULL for + a profile/entrypoint pair. + Part-of: + +2020-04-15 16:26:55 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: Deprecate the low-delay-b property. + In HEVC, P and B definitions are different from AVC: P frames have + just one reference list and so 1 MV, while B frames have two reference + lists and so 2 MVs. No matter B or P, ist reference lists can contain + forward/backward reference. So P and B can both have bi-directions + dependency, the difference is just their reference list + number (i.e. MV number). This is different from the AVC. + The *low delay b mode* refers to a special HEVC mode, in which the + stream just contain I and B frames, without P frames, and all B frames + only have forward direction dependencies (i.e. all inter frames have 2 + reference lists but no backward reference in both lists). This is + similar to AVC I/P mode, but changing the P to the forward dependent + B. + The `low-delay-b` property is now just used to simply convert all P + frames to B frames when driver does not support P frames (so both + reference lists have the same references frames). This is a little + different from the meaning of low delay b mode (the two ref lists may + have the different reference frames). And the driver now can report + whether it supports P frames correctly, so there is no need to use + this property and deprecate it. + Part-of: + +2020-07-24 12:54:31 +0200 Marc Leeman + + * gst/vaapi/gstvaapipostproc.c: + postproc: reconfigure after changing cropping values + Part-of: + +2020-07-09 13:49:29 +0800 He Junyan + + * gst/vaapi/gstvaapiencode.h: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h265.c: + * gst/vaapi/gstvaapiencode_jpeg.c: + * gst/vaapi/gstvaapiencode_mpeg2.c: + * gst/vaapi/gstvaapiencode_vp8.c: + * gst/vaapi/gstvaapiencode_vp9.c: + plugin: encode: Add static caps for template documentation. + Part-of: + +2020-07-08 19:03:14 +0800 He Junyan + + * gst/vaapi/gstvaapiencode_vp9.c: + plugin: encode: vp9: Use the dynamically built src template caps. + Part-of: + +2020-07-08 19:02:45 +0800 He Junyan + + * gst/vaapi/gstvaapiencode_vp8.c: + plugin: encode: vp8: Use the dynamically built src template caps. + Part-of: + +2020-07-08 19:02:23 +0800 He Junyan + + * gst/vaapi/gstvaapiencode_jpeg.c: + plugin: encode: jpeg: Use the dynamically built src template caps. + Part-of: + +2020-07-08 19:00:39 +0800 He Junyan + + * gst/vaapi/gstvaapiencode_mpeg2.c: + plugin: encode: mpeg2: Use the dynamically built src template caps. + Part-of: + +2020-07-08 18:59:18 +0800 He Junyan + + * gst/vaapi/gstvaapiencode_h265.c: + plugin: encode: h265: Use the dynamically built src template caps. + Part-of: + +2020-07-08 18:57:26 +0800 He Junyan + + * gst/vaapi/gstvaapiencode_h264.c: + plugin: encode: h264: Use the dynamically built src template caps. + Part-of: + +2020-07-08 18:46:58 +0800 He Junyan + + * gst/vaapi/gstvaapiencode.h: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h265.c: + * gst/vaapi/gstvaapiencode_jpeg.c: + * gst/vaapi/gstvaapiencode_mpeg2.c: + * gst/vaapi/gstvaapiencode_vp8.c: + * gst/vaapi/gstvaapiencode_vp9.c: + plugin: encode: Store the coded caps in type's init data. + Part-of: + +2020-07-08 18:30:00 +0800 He Junyan + + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + plugin: util: add helper function build_template_coded_caps_by_codec() + Like build_template_raw_caps_by_codec(), this function can detect and + build the caps for specified codec based on the query of the profiles. + The result is coded caps such as video/x-h265, video/x-h264. The result + can be used as the template of encode's src or decode's sink. + Part-of: + +2020-07-07 17:16:41 +0800 He Junyan + + * gst/vaapi/gstvaapiencode.h: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + plugins: utils: rename build_template_caps_by_codec. + Rename the function build_template_caps_by_codec() to the name of + build_template_raw_caps_by_codec(). It can be used to collect all + raw video formats for encode's sink and decode's src. + Part-of: + +2020-07-21 20:14:57 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + vaapidecode: merge common profiles before setting size range + The synthetic profiles, such as H264 baseline, H265 intra, etc. are + added at the end of processing all available VA profiles. This + generated an non-optimal caps for negotiation, since the synthetic + profiles don't have frame size ranges. + This patch adds those possible synthetic profiles when the associated + profile is processed, with its frame size ranges. + Now allowed sink caps are simpler. + Part-of: + +2020-07-21 22:05:08 +0800 He Junyan + + * gst/vaapi/gstvaapipluginutil.c: + plugin: util: Add the missing DMA buffer input in template caps. + We pass the wrong parameter to gst_vaapi_build_caps_from_formats() + and lose the DMA feature in caps. + Part-of: + +2020-07-14 18:13:56 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + * gst-libs/gst/vaapi/video-format.c: + * gst/vaapi/gstvaapidecode.c: + libs: decoder: H265: Add MAIN_12 profile supporting. + Part-of: + +2020-07-09 23:07:38 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/video-format.c: + video-format: Add P012_LE format. + It can be used as HEVC YUV_4:2:0 12bits stream's decoder output, and + also can be used as the input format for encoding HEVC YUV_4:2:0 12bits + stream. + Part-of: + +2020-07-17 00:45:53 +0800 He Junyan + + * gst/vaapi/gstvaapidecode.c: + plugin: decode: correct ensure_allowed_sinkpad_caps's caps. + The decode allowed caps returned by ensure_allowed_sinkpad_caps() + contains all profiles of the whole VAAPI, like: + image/jpeg, width=(int)[ 0, 1638 4 ], height=(int)[ 0, 16384 ]; + video/mpeg, mpegversion=(int)2, profile=(string){ simple, main }, + width=(int)[ 0, 2048 ], height=(int)[ 0, 2048 ]; video/x-h264, + profile=(string){ main, high, constrained-baseline }, width=(int)[ 0, + 4096 ], height=(int)[ 0, 4096 ]; video/x-h264, profile=(string){ + constrained-high, progressive-high, baseline }; video/x-h265, + profile=(string){ main, main-intra }, width=(int)[ 0, 8192 ], + height=(int)[ 0, 8192 ]; video/x-vp8, width=(int)[ 0, 4096 ], + height=(int)[ 0, 4096 ]; video/x-wmv, wmvversion=(int)3, + format=(string)WVC1, profile=(string)advanced, width=(int)[ 0, 3840 ], + height=(int)[ 0, 3840 ]; video/x-wmv, wmvversion=(int)3, + profile=(string){ simple, main }, width=(int)[ 0, 3840 ], + height=(int)[ 0, 3840 ] + Which is verbose and may have latent problems. It should only contains + the profiles belong to its codec type. For example, h265 should only + return: + video/x-h265, profile=(string){ main, main-intra }, + width=(int)[ 0, 8192 ], height=(int)[ 0, 8192 ] + Part-of: + +2020-07-13 11:06:18 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecodebin.c: + vaapidecodebin: don't force NV12 since P010_10LE is now possible + Part-of: + +2020-07-12 20:34:31 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + libs: profile: The VP9 profiles' name should be just "0,1,2,3" + Part-of: + +2020-07-08 17:33:32 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + * tests/internal/simple-decoder.c: + vaapidecode: Remove NO_SURFACE error handling + Since surfaces are not bounded to decoding context it makes no sense + to keep the surface semaphore. This patch removes the handling of + this error. + Part-of: + +2020-07-08 17:48:57 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + Revert "vaapidecode: drop non-keyframe in reverse playback" + Since the number of surfaces are not bounded to decoder context, + this hack is no longer needed. + This reverts commit 19c0c8a97385ce119440c4aad2d689fc79297435. + Part-of: + +2019-12-06 14:21:33 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapicontext.c: + libs: decoder: context: remove surfaces binding from context. + The vaCreateContext do not need to specify the surfaces for the + context creation now. So we do not need to bind any surface to the + context anymore. Surfaces should be the resource belong to display + and just be used in encoder/decoder context. + The previous manner has big limitation for decoder. The context's + surface number is decided by dpb size. All the surfaces in dpb will + be attached to a gstbuffer and be pushed to down stream, and the + decoder need to wait down stream free the surface and go on if not + enough surface available. For more and more use cases, this causes + deadlock. For example, + gst-launch-1.0 filesrc location=a.h264 ! h264parse ! vaapih264dec + ! x264enc ! filesink location=./output.h264 + will cause deadlock and make the whole pipeline hang. + the x264enc encoder need to cache more than dpb size surfaces. + The best solution is seperating the surfaces number and the dpb size. + dpb and dpb size shoule be virtual concepts maintained by the decoder. + And let the surfaces_pool in context maintain the re-use of all surfaces. + For encoder, the situation is better, all the surfaces are just used + as reference frame and no need to be pushed to down stream. We can + just reserve and set the capacity of the surfaces_pool to meet the + request. + Fix: #147 + Fix: #88 + Co-Author: Víctor Manuel Jáquez Leal + Part-of: + +2020-07-08 17:50:51 +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-08 11:57:52 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: use VA allocator by default on raw caps + Instead of using dmabuf allocator in source pad, when raw video caps + are negotiated, it uses VA allocator as before, since it is stable + in more use cases, for example transcoding, and more backend drivers. + Dmabuf allocator is only used when dmabuf caps feature is negotiated. + Part-of: + +2020-06-06 18:47:35 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapi.c: + vaapisink: rank it as secondary + iHD doesn't provide a full implemention for rendering surfaces and + i965 has problems in wayland. And I suspect this path is followed + by other driver implementations. + This patch demotes the rank of vaapisink to secondary, so it will + not be autoplugged avoiding bad experience of users. + Part-of: + +2020-06-19 10:44:50 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + libs: decoder: h264, h265: in context at least 16 reference surfaces + Registering only stream's DBP size number of surfaces for decoding VA + surfaces brings issues for certain streams. This change register all + possible number of reference surfaces in a stream, which is 16. + Fixes: #94 + +2020-07-04 21:21:57 +0800 He Junyan + + * gst/vaapi/gstvaapiencode_h265.c: + plugins: encode: h265: Add profile,level,tier to output caps. + Part-of: + +2020-07-04 21:08:20 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: init tier to GST_VAAPI_TIER_H265_UNKNOWN. + Part-of: + +2020-07-04 21:05:49 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: fix a bug to get get_profile_tier_level. + 0 is a valid value for h265 tier. + Part-of: + +2020-07-02 19:19:35 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: no need to check the high compression tune. + The h265 encoder just support tune mode: + (0): none - None + (3): low-power - Low power mode + So, no need to check and set the high compression parameters. + And by the way, the current ensure_tuning_high_compression manner + of choosing the hightest profile idc as the best compression profile + is not correct. Unlike h264, in h265 the higher profile idc number + does not mean it has more compression tools, and so it has better + compression performance. It may even be un-compatible with the lower + profile idc. For example, the SCREEN_CONTENT_CODING profile with idc + 9 is not compatible with 3D_MAIN profile with idc 8. + Part-of: + +2020-07-03 02:04:14 +0100 Tim-Philipp Müller + + * meson.build: + Back to development + +=== release 1.17.2 === + +2020-07-03 00:36:40 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * gstreamer-vaapi.doap: + * meson.build: + Release 1.17.2 + +2020-06-23 10:20:46 -0400 Thibault Saunier + + * docs/gst_plugins_cache.json: + * gst/vaapi/gstvaapiencode.c: + docs: Mark parent classes as plugin API + +2020-06-23 00:07:57 +0200 Mathieu Duponchelle + + * docs/meson.build: + meson: mark plugins cache target as always stale + +2020-06-19 23:34:11 -0400 Thibault Saunier + + * docs/gst_plugins_cache.json: + doc: Stop documenting properties from parents + +2020-06-20 00:28:35 +0100 Tim-Philipp Müller + + * meson.build: + Back to development + +=== release 1.17.1 === + +2020-06-19 19:27:11 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * gstreamer-vaapi.doap: + * meson.build: + Release 1.17.1 + +2020-06-19 15:21:56 +0100 Tim-Philipp Müller + + * docs/gst_plugins_cache.json: + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + Update plugin docs and add more plugins + Part-of: + +2020-06-11 08:32:05 +0200 Michael Olbrich + + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + libs: wayland: display: only handle the first output + Right now, all outputs are handled. The means that the registry object for + all but the last are leaked. As a result the sizes are not used correctly. + With two outputs, at first the mode and physical size of the second output + are used. If the first output changes the mode, then the physical size of + the second output is used in combination with the resolution of the first + output. The resulting pixel aspect ratio is incorrect. + There seems to be no way to determine on which output the window is shown, + so just use the first one to get consistent results. + Part-of: + +2020-06-11 18:15:17 +0800 He Junyan + + * gst/vaapi/gstvaapipluginbase.c: + plugins: pluginbase: Do not destroy display when _close() + When the element's state changes to NULL, it can still receive + queries, such as the image formats. The display is needed in such + queries but not well protected for MT safe. + For example, ensure_allowed_raw_caps() may still use the display + while it is disposed by gst_vaapi_plugin_base_close() because of + the state change. + We can keep the display until the element is destroyed. When the + state changes to NULL, and then changes to PAUSED again, the display + can be correctly set(if type changes), or leave untouched. + Fix: #260 + Part-of: + +2020-06-09 21:19:11 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapicontext.c: + libs: context: use correct printing modifier + GstVaapiID is an alias of gsize, thus its modifier is platform + dependant. + Part-of: + +2020-06-06 00:42:46 +0200 Mathieu Duponchelle + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapivalue.c: + plugins: uddate gst_type_mark_as_plugin_api() calls + +2020-03-05 18:12:27 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: Enable tile in VA command. + Part-of: + +2020-03-05 17:56:51 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: Add ensure_tile to calculate tiles. + We need consider tiles and slices together, separate tiles uniformly + and then assign slices uniformly to each tiles. + Part-of: + +2020-04-30 14:19:29 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + libs: display: add a quirk for iHD driver tile encoding. + The iHD driver has a requirement that one slice can not span tiles + when tile is enabled, which is not required by hevc spec. + Part-of: + +2020-03-05 17:40:43 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: Add tile info to bitstream. + Part-of: + +2020-03-05 17:29:41 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: promote level if tile is enabled. + Part-of: + +2020-03-05 17:07:28 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiutils_h265.h: + libs: encoder: h265: Add num-tile-cols/rows properties. + These properties are used for support of tile encoding. We just + support uniform mode of tile encoding, that is, separating picture + equally by (num-tile-cols X num-tile-rows). + According to HEVC spec A1, the max number of tiles in column is 20 + and in rows is 22, so add two constant definitions. + Part-of: + +2020-03-05 16:21:24 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: extract slice creation from add_slice_headers + extract slice creation details from add_slice_headers, and let the + add_slice_headers just focuses on calculating slice start address + and CTU number. + Part-of: + +2020-03-05 12:44:45 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + libs: encoder: Add a helper function to check the tile support. + Encoding by tiles separation now is a very common feature for all + relative new codecs, such as HEVC, AV1, and VP9. Just make this + check as a common helper function of the encoder base class. + Part-of: + +2020-05-13 18:02:07 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + libs: decoder: H265: Add SCC_MAIN_444_10 profile support. + Part-of: + +2020-05-13 16:05:59 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + libs: decoder: update reference list for SCC. + Part-of: + +2020-05-13 15:46:29 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + libs: decoder: H265: Fill picture and slice SCC parameters. + Part-of: + +2020-05-13 15:00:53 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + libs: util: H265: recognize the SCC profiles. + Part-of: + +2020-05-13 14:53:46 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + libs: profile: Add screen extended main/main10/main444 define. + Part-of: + +2020-04-03 14:53:40 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + * gst/vaapi/gstvaapiencode_h265.c: + libs: encoder: h265: Add support for MAIN 4:2:2 10 profile. + Using YUY2 as the input of the encoder can generate main 4:2:2 bit + streams and using Y210 as the input of the encoder can generate main + 4:2:2 10 bit streams. + Part-of: + +2020-05-29 16:40:20 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: Use correct index for SubWidthC and SubHeightC. + We need to use the chroma_format_idc as the index for getting the + SubWidthC and SubHeightC values as the spec 6.1(table 6-1) defines. + The wrong SubWidthC or SubHeightC make us calculate a wrong right + or bottom offset for crop size and generate garbage in output. + Part-of: + +2020-05-29 15:37:24 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + libs: encoder: h265: Fix chrome idc for 444 10 bits + GST_VAAPI_CHROMA_TYPE_YUV444_10BPP should also set chroma_format_idc + to 3 as GST_VAAPI_CHROMA_TYPE_YUV444 does. + Part-of: + +2020-06-03 18:37:22 -0400 Thibault Saunier + + * docs/meson.build: + doc: Require hotdoc >= 0.11.0 + +2020-06-03 18:49:53 -0400 Thibault Saunier + + * gst/vaapi/gstvaapipostproc.c: + doc: Fix wrong link to GstVideoDirectionMethod + +2020-06-03 17:38:10 -0400 Thibault Saunier + + * docs/gst_plugins_cache.json: + * meson_options.txt: + docs: Update plugin cache with the new format + And fix the default URL which should not be inside quotes. + +2020-06-03 17:37:48 -0400 Thibault Saunier + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapivalue.c: + * gst/vaapi/gstvaapipostproc.c: + Use gst_type_mark_as_plugin_api() for all non-element plugin types + +2020-05-23 22:09:17 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapibufferproxy.c: + * gst-libs/gst/vaapi/gstvaapibufferproxy_priv.h: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapiobject.h: + * gst-libs/gst/vaapi/gstvaapiobject_priv.h: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.h: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy_priv.h: + * gst-libs/gst/vaapi/gstvaapivideopool.c: + * gst-libs/gst/vaapi/meson.build: + libs: delete all gstvaapiobject related files. + Part-of: + +2020-05-23 20:48:54 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapisurface.c: + libs: surface: return fail immediately if can not create subpicture + Part-of: + +2020-05-23 14:00:58 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.h: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * tests/internal/image.c: + libs: subpicture: Make subpicture a standard GstMiniObject. + Part-of: + +2020-05-26 02:19:15 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + libs: decoder: h264: Add ref flags for splited field. + When split one frame into fields, the second field should also + copy the reference flags. + Part-of: + +2020-05-25 15:46:58 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + libs: decoder: h264: disallow multiple slice group + As far as we know there are no VAAPI drivers supporting FMO, which + migth be used in baseline streams. + This commit is a continuation of + https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi/-/merge_requests/328 + Part-of: + +2020-05-20 10:50:05 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.h: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode_props.c: + * gst/vaapi/gstvaapidecode_props.h: + vaapidecoder: h264: remove baseline as constrained property + From now on always the baseline is going to be treated as constrained without + need of setting a property. + Since the property was added along the development cycle (1.17 / commit + 866a9f06) and never released, we assume that it is safe to remove it. + Fixes: #252 + Part-of: + +2020-05-21 11:37:36 +0200 Víctor Manuel Jáquez Leal + + * README: + README: update VP9 decoder and encoder + Part-of: + +2020-05-21 13:42:47 +0800 Haihao Xiang + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + vaapiencoder_h264: set direct_spatial_mv_pred_flag to true by default + This flag is set to true by default in both MediaSDK and FFmpeg-vaapi, + so let's align this plugin with other libraries / softwares. + Part-of: + +2020-05-18 18:29:05 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapivideobufferpool: fix meta overwrite + commit 7ac2a207 added a regression by erroneously assumed that + GstVaapiVideoMeta is actually a GstMeta, which is not. + Part-of: + +2020-05-17 09:55:42 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideobufferpool.c: + * gst/vaapi/gstvaapivideometa_texture.c: + * gst/vaapi/gstvaapivideometa_texture.h: + vaapivideopool: Set pooled flag to added metas. + So this could hint filters how to use these metas. + Had to change the return value for texutre upload meta in order + to flag it. + Part-of: + +2020-05-16 20:49:31 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapiparser_frame.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + libs: use array_unref() rather than array_free() + It is more convinience and thread-safe. + Part-of: + +2020-04-10 22:20:35 +0800 He Junyan + + * gst/vaapi/gstvaapi.c: + plugin: use register_type to replace get_type for encode init. + xxx_register_type will detect the template sink caps and is needed + to be called at init time. + Part-of: + +2020-04-10 22:05:50 +0800 He Junyan + + * gst/vaapi/gstvaapiencode_vp9.c: + * gst/vaapi/gstvaapiencode_vp9.h: + plugins: encode: Modify sink template of vp9 encode. + Use gst_vaapi_detect_codec_caps to get more precise template caps. + Also implement gst_vaapiencode_vp9_register_type, which should be + called at plugin register time. + Part-of: + +2020-04-10 22:05:18 +0800 He Junyan + + * gst/vaapi/gstvaapiencode_vp8.c: + * gst/vaapi/gstvaapiencode_vp8.h: + plugins: encode: Modify sink template of vp8 encode. + Use gst_vaapi_detect_codec_caps to get more precise template caps. + Also implement gst_vaapiencode_vp8_register_type, which should be + called at plugin register time. + Part-of: + +2020-04-10 22:04:34 +0800 He Junyan + + * gst/vaapi/gstvaapiencode_mpeg2.c: + * gst/vaapi/gstvaapiencode_mpeg2.h: + plugins: encode: Modify sink template of mpeg2 encode. + Use gst_vaapi_detect_codec_caps to get more precise template caps. + Also implement gst_vaapiencode_mpeg2_register_type, which should be + called at plugin register time. + Part-of: + +2020-04-10 22:03:49 +0800 He Junyan + + * gst/vaapi/gstvaapiencode_h265.c: + * gst/vaapi/gstvaapiencode_h265.h: + plugins: encode: Modify sink template of h265 encode. + Use gst_vaapi_detect_codec_caps to get more precise template caps. + Also implement gst_vaapiencode_h265_register_type, which should be + called at plugin register time. + Part-of: + +2020-04-10 22:00:38 +0800 He Junyan + + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h264.h: + plugins: encode: Modify sink template of h264 encode. + Use gst_vaapi_detect_codec_caps to get more precise template caps. + Also implement gst_vaapiencode_h264_register_type, which should be + called at plugin register time. + Part-of: + +2020-04-10 22:11:34 +0800 He Junyan + + * gst/vaapi/gstvaapiencode_jpeg.c: + * gst/vaapi/gstvaapiencode_jpeg.h: + plugins: encode: Modify sink template of jpeg encode. + Use gst_vaapi_detect_codec_caps to get more precise template caps. + Also implement gst_vaapiencode_jpeg_register_type, which should be + called at plugin register time. + Part-of: + +2020-04-23 00:02:02 +0800 He Junyan + + * gst/vaapi/gstvaapiencode.h: + plugin: encode: add a helper macro to register encode type. + Part-of: + +2020-04-10 21:44:05 +0800 He Junyan + + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + plugins: util: Add a helper function to detect supported caps. + This helper function iterate all profiles and entrypoints belong + to the specified codec, query the VAConfigAttribRTFormat and list + all possible video formats. + This function is used by each codec to get the template sink caps + (for encode) or src caps(for decode) at register time, when just + all possible formats are listed and no need to be very accurate. + So there is no context created for the performance reason. Most + codecs just use YUV kinds of formats as the input/output, so we do + not include RGB kinds of formats. User can specified more formats + in extra_fmts(For example, jpeg may need BGRA) if needed. + Part-of: + +2020-04-10 21:27:32 +0800 He Junyan + + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + plugin: encode: extract the allowed caps maker as a helper function. + Extract all logic about making caps for encode's sink as a standalone + helper function. It can be reused. + Part-of: + +2020-04-10 21:21:43 +0800 He Junyan + + * gst-libs/gst/vaapi/video-format.c: + * gst-libs/gst/vaapi/video-format.h: + libs: video-format: add a helper function of get_formats_by_chroma. + The function iterates all supported video formats and returns the + formats belong to the specified chroma type. + Part-of: + +2020-05-16 21:03:32 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapitexture_priv.h: + libs: texture: remove unused headers include + This is continuation of + https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi/-/merge_requests/317 + Part-of: + +2020-05-16 19:58:25 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapicodedbuffer.h: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst-libs/gst/vaapi/gstvaapisurface.h: + libs: removed duplicated function declarations + Some headers had duplicated inlined function declaration. This was + for gtkdoc, but now GStreamer uses hotdoc and the internal library + documentation is not generated. So let's remove these extra lines. + Part-of: + +2020-04-18 19:32:24 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapitexture.h: + * gst-libs/gst/vaapi/gstvaapitexture_egl.c: + * gst-libs/gst/vaapi/gstvaapitexture_glx.c: + * gst-libs/gst/vaapi/gstvaapitexture_priv.h: + * gst-libs/gst/vaapi/gstvaapitexturemap.c: + * gst-libs/gst/vaapi/gstvaapiwindow_egl.c: + * gst/vaapi/gstvaapivideometa_texture.c: + * tests/internal/test-textures.c: + libs: texture: Make texture a standard GstMiniObject. + We store GstVaapiTextureGLX and GstVaapiTextureEGL's private data in + the qdata of miniobject and avoid extending the base texture class. + Part-of: + +2020-04-26 12:33:29 +0200 Víctor Manuel Jáquez Leal + + * README: + Update README + Part-of: + +2020-04-21 18:00:26 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + libs: display: drm: use g_strcmp0 to be null safe + Part-of: + +2020-04-26 13:30:16 +0800 Haihao Xiang + + * gst/vaapi/gstvaapipluginutil.c: + vaapipluginutil: Use GST_VAAPI_DISPLAY_TYPE_DRM for Mesa3D GBM + We may build this plugin with window system support but run it without + window system. Without this patch, the following pipeline will trigger a + segfault when running it without window system. + gst-launch-1.0 filesrc location=input.264 ! h264parse ! vaapih264dec ! fakesink + Part-of: + +2020-04-21 11:16:37 +0200 Víctor Manuel Jáquez Leal + + * meson.build: + build: use join_paths() for driverdir + +2020-04-21 09:04:51 +0000 Veerabadhran G + + * README: + README: Update supported hardware + Added the AMD hardware list to the "Hardware Requirements" section. + +2020-04-04 13:58:00 +0200 He Junyan + + * gst-libs/gst/vaapi/gstvaapibufferproxy.c: + * gst-libs/gst/vaapi/gstvaapibufferproxy.h: + * gst-libs/gst/vaapi/gstvaapibufferproxy_priv.h: + libs: bufferproxy: remove GstMemory reference + Since bufferproxy and surface are not referenced circularly, there's + no need to keep, in the buffer proxy, a reference to the GstMemory + where it is held. This patch removes that handling. + +2020-03-15 23:29:05 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapibufferproxy.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface_drm.c: + * gst-libs/gst/vaapi/gstvaapisurface_drm.h: + * gst/vaapi/gstvaapivideomemory.c: + libs,plugin: break surface-bufferproxy circular reference + The bufferproxy may reference the surface and the surface may also + reference the bufferproxy, producing a circular reference, which might + lead to serious resource leak problems. + Now make the relationship clearer, the bufferproxy's references is + transfered to surface, while bufferproxy just keeps the surface's + address without increasing its reference count. + The surface can be created through a bufferproxy like in + gst_vaapi_surface_new_with_dma_buf_handle(), and the surface might + get its bufferproxy via gst_vaapi_surface_get_dma_buf_handle(). In + both cases the surface holds a bufferproxy's reference. + +2020-04-03 18:43:52 +0200 He Junyan + + * gst-libs/gst/vaapi/gstvaapibufferproxy.c: + * gst-libs/gst/vaapi/gstvaapibufferproxy_priv.h: + * gst-libs/gst/vaapi/gstvaapisurface_drm.c: + libs: bufferproxy: rename parent memeber as surface + +2020-03-15 22:07:31 +0800 He Junyan + + * gst/vaapi/gstvaapivideobufferpool.c: + plugin: bufferpool: use hashmap to cache dmabuf mem-surface + The old way of refer memory by bufferproxy is not a good one, since it + make the logic error prone. + Now it is established a map between surface-bufferproxy and its GstMemory, + caching the memory bound by a surface looked for the specified surface. + +2020-03-15 21:50:24 +0800 He Junyan + + * gst/vaapi/gstvaapivideobufferpool.c: + * gst/vaapi/gstvaapivideobufferpool.h: + plugin: bufferpool: Delete ACQUIRE_FLAG_NO_ALLOC flag. + Delete the GST_VAAPI_VIDEO_BUFFER_POOL_ACQUIRE_FLAG_NO_ALLOC flag. + In fact, no one is using that flag, and all vaapi buffers should + have GstVaapiVideoMeta. + +2020-02-13 09:43:38 -0800 U. Artie Eoff + + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + vaapipostproc: enable HDR10 tone mapping + +2020-02-13 09:00:18 -0800 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapifilter.h: + libs: filter: HDR10 tone mapping support + Add support for HDR10 tone mapping (since VA-API 1.4.0). + +2020-04-02 15:14:15 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + * gst/vaapi/gstvaapiencode_h265.c: + libs: encoder: h265: Support MAIN 4:4:4 10 profile. + Using Y410 as the input of the encoder can generate main_444_10 bit + streams. + +2020-04-02 15:19:41 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: fix an inexact trace info in chroma type check. + +2020-03-31 12:22:31 +0800 Haihao Xiang + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: make sure format array is not NULL when returning TRUE + This fixed segfault when running the pipeline below with iHD driver + (commit efe5e9a) on ICL + gst-launch-1.0 videotestsrc ! vaapivp9enc tune=low-power ! vaapivp9dec ! \ + fakesink + +2020-03-18 13:28:00 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.h: + * gst-libs/gst/vaapi/gstvaapidecoder_h265.h: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.h: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.h: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.h: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.h: + * gst-libs/gst/vaapi/gstvaapidecoder_vp8.h: + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.h: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.h: + * gst-libs/gst/vaapi/gstvaapidisplay_egl.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.h: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.h: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.h: + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.h: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.h: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.h: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.h: + * gst-libs/gst/vaapi/gstvaapifilter.h: + * gst-libs/gst/vaapi/gstvaapitexturemap.h: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_drm.h: + * gst-libs/gst/vaapi/gstvaapiwindow_egl.h: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.h: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.h: + libs: extend g_autoptr support + +2020-03-26 22:40:40 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideometa.c: + vaapivideometa: remove compiler warning + +2020-03-22 20:59:20 +0100 Víctor Manuel Jáquez Leal + + * meson.build: + * meson_options.txt: + build: Add meson's option package-origin. + This options is added to synchronize with other gstreamer packages + build configuration. + Though, to avoid breaking distro configuration it is set, as default, + the issues gitlab's url, instead of the used string + "Unkown package origin". + Also, set_quoted is used for string based cdata. + +2020-02-25 13:45:05 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: deprecate format, width and size parameters + Since they should only be controlled by caps negotiation. + +2020-03-18 16:41:01 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + * gst/vaapi/gstvaapidecode.c: + libs,plugins: decoder: Add -intra profile support for hevc. + In hevc, we can consider the -intra profile a subset of the none + -intra profile. The -intra profiles just contain I frames and we + definitely can use the none -intra profiles's context to decode + them. + Signed-off-by: Víctor Manuel Jáquez Leal + +2020-03-04 12:35:42 -0800 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: support ICQ/QVBR BRC + Enable support for ICQ and QVBR bitrate control. + The code is essentially the same for h264 ICQ/QVBR support + which was added in commit 9e0c133a2403. + +2020-03-19 11:19:18 -0700 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: set VA HRD param before RC param + This is a workaround for intel-media-driver bug + https://github.com/intel/media-driver/issues/865 + The driver will force the RC method to CBR for HEVCe + when it parses the HRD param. Thus, any RC method + param submitted "prior" to the HRD param will be lost. + Therefore, VBR, ICQ and QVBR for HEVCe can't be + effectively enabled if the RC method param "precedes" + the HRD param. + To work around this issue, set the HRD param before + the RC method param so the driver will parse the RC + method param "after" the HRD param. + Afaict, other codecs in the driver (and other drivers) + do not appear to be dependent on the order of HRD and + RC param submission. + +2019-11-25 14:16:30 +0800 Haihao Xiang + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c: + vaapijpegenc: Add a quantization quirk for iHD driver + iHD driver shifts the value by 50 when calculating quantization for JPEG + encoding, so we should add 50 in this plugin for iHD driver too. + +2020-03-13 21:49:15 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h: + * gst-libs/gst/vaapi/gstvaapipixmap.c: + * gst-libs/gst/vaapi/gstvaapipixmap.h: + * gst-libs/gst/vaapi/gstvaapipixmap_priv.h: + * gst-libs/gst/vaapi/gstvaapipixmap_x11.c: + * gst-libs/gst/vaapi/gstvaapipixmap_x11.h: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_egl.c: + * gst-libs/gst/vaapi/gstvaapiwindow_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11_priv.h: + * gst-libs/gst/vaapi/meson.build: + * meson.build: + * tests/internal/output.c: + * tests/internal/output.h: + * tests/internal/simple-decoder.c: + * tests/internal/test-decode.c: + libs: remove GstVaapiPixmap + GstVaapiPixmap is an abstract base class which only implementation + were GstVaapiPixmapX11. This class were used for a special type of + rendering in the tests apps, utterly unrelated in GStreamer. + Since gstreamer-vaapi is no longer a general-user wrapper for VA-API + we should remove this unused API. + This removal drops libxrender dependency. + +2020-03-17 18:51:19 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiutils.c: + libs: utils: Add HEVC Main444 sting in string_of_VAProfile + HEVCMain444_10 is already a supported profile and misses the strings. + +2020-03-17 12:47:33 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapi.c: + plugin: don't error if cannot create display + This might generated errors on automatic tools such as CI. Let's + rather just raise a warning and let continue. + +2020-03-09 01:52:57 +0800 He Junyan + + * tests/check/meson.build: + test: fix a ninja test failure for vaapioverlay. + That test case only works with drm display, so the build such as + meson -Dwith_x11=yes -Dwith_wayland=no -Dwith_drm=no -Dwith_egl=no + -Dwith_glx=no + gets a failure when run ninja test. Just enable this test when drm + is enabled. + +2020-02-07 23:56:13 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapivideopool.c: + libs: videopool: fix a condition race for pool allocate. + +2020-03-05 13:22:23 -0800 U. Artie Eoff + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapivideobufferpool: force video meta if sizes are different + The strides and offsets could be the same, but the allocation + size might be different (e.g. alignment). Thus, ensure we also + set the flag to copy from VA memory to system memory when alloc + size differs. + Fixes #243 + +2020-03-05 14:18:32 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: don't set base sink caps twice + Base class's sink pad caps are already set when calling set_format(). + There's no need to call it again in gst_vaapidecode_negotiate(). + +2020-03-05 13:26:38 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: unlock stream if caps update fails + If caps update fail a dead lock occurs since the stream mutex is not + unlocked. + +2020-03-03 15:24:32 +0800 Xu Guangxin + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + libs: decoder: h265: parser state after update dependent slice + If the dependent_slice_segment_flag is true, most slice info derived from last slice. + So we need check the slice type after we call populate_dependent_slice_hdr + +2020-02-16 12:21:28 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + libs: display: force RGBA image format for i965 driver + Since commit 32bf6f1e GLTextureUpload is broken because i965 + doesn't report properly RGBA support. It could be possible to use RGBx + but GLTextureUpload only regotiates RGBA. + The simplest fix to this regression is adding synthetically the RGBA + format in the internal format map. + +2020-02-14 19:30:54 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + libs: display: iterate all quirks table + Instead of break at the fist foud quirk in the table, iterate all over + so it would be feasible to add several quirks for one driver per + element in array. + +2020-02-25 12:05:28 -0800 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapifilter.c: + libs: filter: handle RGB to/from YUV color primary driver quirk + The intel-media-driver (iHD) can't convert output color + primaries when doing YUV to/from RGB CSC. Thus, we must + keep the output color primaries the same as the input + color primaries for this case. + fixes #238 + +2020-02-25 12:00:36 -0800 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + libs: display: add YUV to/from RGB color primary quirk + The intel-media-driver (iHD) can't convert output color + primaries when doing YUV to/from RGB CSC. + +2020-02-28 11:33:18 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + Revert "vaapivideomemory: Store surface allocation flags." + This reverts commit dd428cc4a12c2d5c694fcd3303811cf486002c9d because + it rewrites the buffer size whilst surface allocation flags are + stored when allocator_params_init() is called since fab890ce. + Fix: #239 + +2020-01-27 18:19:57 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: Try surface with allocation flags. + When a vaapi allocator is instantiated, it first try to generate a + surface with the specified configuration. + This patch adds, in this tried buffer, the requested allocation flags. + +2020-01-27 18:10:18 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: Store surface allocation flags. + Store surface allocation flags passed to the vaapi allocator in + GObject's qdata, because it might be used by the vaapivideobufferpool + when recreating the allocator given any resolution change. + +2020-01-24 19:32:52 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + libs: surface: Add hints to allocation flags. + When creating surfaces it is possible to pass to VA hints of its usage, + so the driver may do some optimizations. + This commit adds the handling of encoding/decoding hints. + +2020-01-24 22:08:50 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapisurface_egl.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.h: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * tests/internal/test-filter.c: + * tests/internal/test-surfaces.c: + libs: surface: surfacepool: Add allocation flags in constructors. + +2020-02-22 16:06:13 +0800 He Junyan + + * meson.build: + build: let the build fail if none if X11, wayland or drm. + In fact, gst_vaapi_create_test_display only test x11, wayland and + drm, no glx and egl entries. So if none of them is enabled, no + vaapi element can be detected. + +2020-02-21 00:58:47 +0800 He Junyan + + * tests/internal/test-display.c: + test: avoid unused warning for test-display + meson -Dwith_x11=yes -Dwith_wayland=no -Dwith_drm=no -Dwith_egl=no + -Dwith_glx=no buildir + generate unused warnings. + +2020-02-21 00:50:47 +0800 He Junyan + + * meson.build: + build: fix meson build error when without x11. + meson -Dwith_x11=no build_dir + can not success build the project because the glx is still enabled. + We need to disable GLX when X11 is disabled. + +2020-02-14 19:53:09 +0800 Haihao Xiang + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: h265enc: Set max_transform_hierarchy_depth_{inter, intra} to 2 + Intel HW has limitation on max_transform_hierarchy_depth_inter and + max_transform_hierarchy_depth_intra (see [1]). We can provide a quirk for + other HWs if other HWs may support other values + [1] https://01.org/sites/default/files/documentation/intel-gfx-prm-osrc-kbl-vol10-hevc.pdf + +2020-02-21 07:37:50 -0800 U. Artie Eoff + + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostprocutil.c: + vaapipostproc: do not compensate for crop/direction if no VPP + If we do not have functional VPP, then cropping and video + direction is non-functional and we should avoid calling + any of the gst_vaapi_filter* APIs. + +2020-02-21 06:54:47 -0800 U. Artie Eoff + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: only set VPP colorimetry when VPP is available + If we don't have functional vpp then we should not call + gst_vaapi_filter_set_colorimetry. + +2020-02-16 01:25:37 +0800 He Junyan + + * gst/vaapi/gstvaapivideobufferpool.c: + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + videobufferpool: don't reset surface when created internally + The bug fixing, in commit 89f202ea, just considers the case when + surface's DMABuf is set through gst_buffer_pool_acquire_buffer(), + which is typically a decoder's behavior. But vaapipostproc doesn't + provide any surface when calling gst_buffer_pool_acquire_buffer(), + thus a surface is created when GstMemory is allocated. + If the surface proxy in buffer's meta is reset at + buffer_pool_reset_buffer(), that surface will be destroyed and it + won't be available anymore. But GstBuffers are cached in the buffer + pool and they are reused again, hence only those images are rendered + repeatedly. + Fixes: #232 + +2020-02-16 17:19:04 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiblend.c: + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst/vaapi/gstvaapi.c: + libs: blend: filter: handle finalize() if display isn't assigned + I've just discovered iHD driver in Skylake doesn't have VideoProc + entry point, hence, in this platform, when vaapioverlay is tried to be + registered, critical warnings are raised because blend doesn't have a + display assigned. + As it is possible to have drivers without EntryPointVideoProc it is + required to handle it gracefully. This patch does that: only tries to + register vaapioverlay if the testing display has VPP and finalize() + vmethods, in filter and blend, bail out if display is NULL. + +2020-02-15 11:02:49 -0800 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapiutils.c: + libs: filter: guard all color properties to VA-API 1.2.0 + Older VA-API (0.39.0) doesn't have VAProcColorProperties. + Thus, guard all colorimetry -> VA-API support to version + 1.2.0. + Fixes #234 + +2020-02-17 08:55:36 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + libs: decoder: h265: set parser info state at decoding codec data + Commit 1168d6d5 showed up a regression: decode_sps() stores the unit's + parser info in sps array. If that parser info comes from decoding + codec data, that parser info will have an undefined state which might + break ensure_sps(). + This patch sets the parser info state, at decoding codec data, with + the internal parser state. This is similar with h264 decoder apprach. + Original-patch-by: Xu Guangxin + +2020-02-07 15:24:18 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: demote log message to trace level + +2020-02-14 14:45:56 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/video-format.c: + libs: video-format: set general vaapi log category + Instead of logging in an unspecified category, set the default vaapi. + +2020-02-15 11:44:48 -0800 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapiutils.c: + libs: utils: guard EncSliceLP for VA-API < 0.39.1 + Relates to #234 + +2020-02-14 16:17:04 +0800 Haihao Xiang + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: h265enc: Set VA_PICTURE_HEVC_INVALID flag for invalid picture + +2020-02-11 11:31:31 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: remove crumbs of libva < 0.39 + All these guarded code seem like leftovers of commit 920b1ec7a. This + patch completes that missing clean up. + +2020-02-11 00:38:40 -0800 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapiutils.c: + libs: VA explicit color standard not supported until 1.2.0 + VAProcColorStandardExplicit and associated VAProcColorProperties + (primaries, transfer and matrix) are not supported until + VA-API 1.2.0. + Use VAProcColorStandardNone instead of VAProcColorStandardExplicit + if VA-API < 1.2.0. + Fixes #231 + +2020-02-10 09:31:15 -0800 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapiutils.c: + libs: utils: WA: use explicit for sRGB colorimetry + Addresses #228 on iHD side. It seems iHD can't handle + VAProcColorStandardSRGB in all situations for vpp. But + it has no problem when we specify the sRGB parameters + via VAProcColorStandardExplicit parameters. + +2020-02-07 11:25:31 -0800 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapifilter.c: + libs: filter: set vpp input/output color range + We've always sent VA_SOURCE_RANGE_UNKNOWN to the driver. + And, the [iHD] driver essentially computes the same color + range as gstreamer when we send VA_SOURCE_RANGE_UNKNOWN for + cases were gstreamer computes it automatically. But, + if the user wants to make it explicit, we should try + to honor it. + +2020-02-07 11:20:11 -0800 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + libs: utils: map GstVideoColorRange to VAAPI VPP + +2020-02-07 15:28:24 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: don't remove chroma-site nor colorimetry + Since now they can be handled by vaapipostproc. + +2020-02-04 14:17:43 -0800 U. Artie Eoff + + * gst/vaapi/gstvaapipostprocutil.c: + vaapipostproc: use sink resolution to calculate src colorimetry + The default output colorimetry is persuaded by the output + resolution, which is too naive when doing VPP cropping + and/or scaling. For example, scaling 4K(sink)->1080P(src) + resolution (i.e. both YUV) results in bt2020(sink)->bt709(src) + colorimetry selection and some drivers don't support that + mode in vpp. + Thus, if output (i.e. downstream) does not specify a + colorimetry then we use the input resolution instead of the + output resolution to create the default colorimetry. Also, + note that we still use the output format since it may be a + different color space than the input. As in the example + above, this will result in bt2020(sink)->bt2020(src) + colorimetry selection and all drivers (afaik) should support + that in vpp. + +2020-02-04 09:57:42 -0800 U. Artie Eoff + + * gst/vaapi/gstvaapipostprocutil.c: + vaapipostproc: set srcpad colorimetry unconditionally + We always need a srcpad colorimetry for VAAPI VPP + operations. + Also, check the return value of _set_colorimetry. + +2020-01-30 12:34:07 -0800 U. Artie Eoff + + * gst/vaapi/gstvaapipostprocutil.c: + vaapipostproc: do not override explicit srcpad colorimetry + If colorimetry has been set by a capsfilter (e.g. + vaapipostproc ! video/x-raw,colorimetry=bt709) then + don't try to override it. Previously, the aforementioned + capsfilter will fail to negotiate if default colorimetry + is not the same as the capsfilter (e.g. 4K resolutions). + +2020-01-30 09:37:18 -0800 U. Artie Eoff + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: set vpp filter colorimetry + Set the input and output colorimetry for vpp filter. + +2020-01-30 09:34:10 -0800 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapifilter.h: + libs: filter: support vpp input/output color standard + Add API function to allow setting the input and output vpp + color standard from GstVideoColorimetry. + +2020-02-04 11:32:54 -0800 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + libs: utils: map GstVideoColorimetry to VAAPI VPP + Fallback to VAProcColorStandardExplicit if there is no + 1:1 mapping. + +2020-02-04 10:27:23 -0800 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + libs: display: add vpp color standard quirk for i965 driver + The i965 does not properly report supported vpp color + standards. + +2020-02-02 18:04:35 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapivideobufferpool: dmabuf implies allocator + Some code can be optimized since only if the dmabuf allocator is set, + the internal flag of dmabuf is TRUE, thus there's no need to evaluate + the allocator address. + +2020-01-29 11:55:39 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapivideobufferpool: reject configuration if allocator isn't vaapi + If the requested allocator in set_config() is not a VAAPI valid one, + reject the configuration, instead of lying and using a private one. + This patch superseeds !254 and !24 + +2020-01-29 11:55:28 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapivideobufferpool: add explanation for allocator reconfig + +2020-01-29 11:54:38 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapivideobufferpool: check for vaapi meta first + If the configured meta doesn't request vaapi meta then it is not a + vaapi buffer pool. Bail out as soon as possible. + +2020-01-29 11:52:38 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapivideobufferpool: turn errors into warnings + set_config() vmethod should fail gracefully, thus upstream could + negotiate another pool if possible. + Instead of sending error messages to the bus, let demote the level + to warning. + +2020-01-29 11:51:47 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + libs: display: log out vendor string when available + This is useful while asking for logs to know the used driver. + +2020-01-27 11:49:26 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapisurface.c: + libs: surface: initialize VASurfaceAttribExternalBuffers + Initialize VASurfaceAttribExternalBuffers using compiler's syntax + rather than using memset(). + +2020-01-27 11:44:49 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapisurface.c: + libs: surface: merge two loops into one + Merge two loops into one for setting offsets and strides in the + external buffer descriptor. + +2020-01-22 10:42:35 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.h: + libs: surface: surfacepool: rename variable for clearity + In order to be readable, the meaningless 'flags' is renamed to + surface_allocation_flags, which is clearer. + +2020-01-27 18:40:46 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapivideobufferpool: Reuse internal allocator is possible. + Instead of creating a new allocator when upstream requests a different + allocator, this patch tries to reuse the internal allocator if it was + already initializated. + If the stream changes, then either one will be unref and a new + allocator is created. + +2020-01-27 18:05:14 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapivideobufferpool: Log messages in proper category. + The log messages where logged in the GstBufferPool category because + the instance was not properly casted. This fix that situation. + +2020-01-16 11:49:21 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst/vaapi/gstvaapipluginbase.c: + libs: display: driver quirks mechanism + This mechanism comes from ffmpeg vaapi implementation, where they have + their own quirks. + A specific driver is identified by a substring present in the vendor + string. If that substring is found, a set of bitwise flags are store. + These flags can be accessed through the function + gst_vaapi_display_has_driver_quirks(). + The purpose for this first quirks is to disable the put image try for + AMD Gallium driver (see [1]). + 1. https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi/merge_requests/72 + +2020-01-15 23:07:29 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + plugins: renable Mesa Gallium driver + +2020-01-24 11:55:22 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapivideobufferpool: validate returned meta + Validate if the meta returned by gst_buffer_get_vaapi_video_meta() in + the acquired buffer is not null. + This situation should be very "pathological", but still it is better + be safe since that meta might be used later to create a new dma + buffer. + +2020-01-22 18:50:36 +0100 Philipp Zabel + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapivideobufferpool: always update/release the underlying surface proxy + gst_vaapi_video_buffer_pool_reset_buffer() is called when the sink + releases the last reference on an exported DMA buffer. This should + release the underlying surface proxy. To avoid releasing the wrong + surface due to a stale surface proxy reference in the buffer's + GstVaapiVideoMeta, always update the reference to the correct surface + in gst_vaapi_video_buffer_pool_acquire_buffer(). + +2020-01-23 16:56:44 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + libs: context: select vaCreateSurfaces version according attributes + This commit tries to centralize the selection of vaCreateSurfaces + version, instead of having fallbacks everywhere. + These fallbacks are hacks, added because new drivers use the latest + version of vaCreateSurfaces (with surface attributes) [1], meanwhile + old drivers (or profiles as JPEG decoder in i965) might rather use the + old version. + In order to select which method, there's detected hack: each config + context has a list of valid formats, in the case of JPEG decoder the + list only contains "rare" 4:2:2 formats (ICM3, GRAY8) which aren't + handled correctly by the current gstreamer-vaapi code [2]. + The hack consist in identify if the format list contains an arbitrary + preferred format (which is suposedly well supported by + gstreamer-vaapi, mostly NV12). If no prefered colour format is found, + the the old version of vaCreateSurfaces is used, and the surfaces wil + be mapped into a image with their own color format. + 1. https://bugzilla.gnome.org/show_bug.cgi?id=797143 + 2. https://bugzilla.gnome.org/show_bug.cgi?id=797222 + +2020-01-21 19:35:02 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapicontext.c: + libs: context: add debug category for context + +2020-01-22 20:20:30 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiblend.c: + libs: blend: guard VA_BLEND_GLOBAL_ALPHA + +2020-01-21 14:09:33 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode_h264.c: + vaapiencode: promote info to warning + Let's notify user about using constrained-baseline instead on + requested basline profile. + +2019-06-28 15:41:16 -0400 Nicolas Dufresne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.h: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode_props.c: + * gst/vaapi/gstvaapidecode_props.h: + vaapih264dec: Add a property to assume constrained-baseline + When baseline-as-constrained is set, the decoder will expose support + for baseline decoding and assume that the baseline content is + constrained-baseline. This can be handy to decode streams in hardware + that would otherwise not be possible to decode. A lot of baseline + content is in fact constrained. + +2020-01-17 16:19:52 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapipluginutil.c: + vaapih264enc: accept baseline as constrained baseline compatible + +2020-01-17 14:24:37 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode_h264.c: + vaapih264enc: update level in src caps + And, if downstream requests a specific level, the caps are not + negotiated, because there is no mechanism right now to specify a + custom level in the internal encoder. + +2020-01-17 17:12:53 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + libs: encoder: h264: document gst_vaapi_encoder_h264_supports_avc() + +2020-01-17 13:38:29 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode_h264.c: + vaapih264enc: force byte-stream if avc isn't supported + Removing the validation in gst_vaapiencode_h264_get_caps() since that + ought be handled in gst_vaapiencode_h264_set_config() + +2020-01-08 17:37:22 +0100 Philipp Zabel + + * gst/vaapi/gstvaapiencode_h264.c: + vaaph264enc: suppress avc if the driver does not support packed headers + Do not negotiate AVC output if the driver does not support it. + +2020-01-08 17:16:35 +0100 Philipp Zabel + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + libs: encoder: h264: Add gst_vaapi_encoder_h264_supports_avc() + AVC output requires packed header support in the driver. + +2020-01-17 13:07:04 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode_h264.c: + vaapih264enc: intersect the new proposed caps + Instead of just leave to keep the proposed caps, with the best profile + in the allowed caps, is its intersected again. + +2020-01-17 12:58:58 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode_h264.c: + vaapih264enc: propose new profile caps and fixate it + When the available caps doesn't intersect with the allowed caps in the + pipeline, a new caps is proposed rather than just expecting to + iterate. + Later, the intersected caps (profile_caps) is fixated in order to + extract the configuration. + +2020-01-17 13:18:28 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode_h264.c: + vaapih264enc: common fail for gst_vaapiencode_h264_set_config() + Add a common fail code path for gst_vaapiencode_h264_set_config(). + +2020-01-17 12:54:21 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: unref formats array if none + The formats array is always created, in order to keep the logic and + to avoid broken caps, if this formats array doesn't contain any + elements, it has to be unref and the function should return NULL. + +2020-01-17 14:22:48 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode_h264.c: + vaapih264enc: fix log message + Before the log wasn't processed because wrong instance pointer. + +2019-06-22 00:44:25 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + * gst/vaapi/gstvaapiencode_h265.c: + plugin: encode: Add H265 main-444 profile. + Expose the main-444 profile to h265enc caps, when the upstream + chooses to use VUYA as input, we choose main 4:4:4 profile to encode + the frames. + +2020-01-15 19:36:00 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: Consider main-444 profile when encoding. + Add support of main-444 profile for parameter setting and packed header + generation. + +2020-01-15 23:04:08 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiprofilecaps.c: + * gst-libs/gst/vaapi/gstvaapiprofilecaps.h: + * gst/vaapi/gstvaapiencode.c: + vaapiencode: DMABuf only if PRIME is available + Add DMABuf capsfeature in encoders' allowed sinkcaps only if PRIME + memory type is available in the VA surface attributes of codec + context. + +2020-01-16 09:14:30 +0800 Haihao Xiang + + * hooks/pre-commit.hook: + Add hooks/pre-commit.hook + meson.build in gstreamer-vaapi requires hooks/pre-commit.hook + Copied and pasted pre-commit.hook from other gstreamer modules to make + sure gstreamer-vaapi follows the same code style + +2019-12-26 16:45:51 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: Set encoder paramters base on entrypoint. + When the tune is NONE, we now can choose entrypoint freely. So the + GST_VAAPI_ENCODER_TUNE macro may not return the correct current + entrypoint. + We also delay CTU size calculation after entrypoint has been decided. + +2019-12-28 19:18:12 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapicodedbufferproxy.c: + * gst-libs/gst/vaapi/gstvaapicodedbufferproxy.h: + * gst-libs/gst/vaapi/gstvaapicodedbufferproxy_priv.h: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.h: + * gst-libs/gst/vaapi/gstvaapiencoder_objects.c: + * gst-libs/gst/vaapi/gstvaapiencoder_objects.h: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + * gst-libs/gst/vaapi/gstvaapifei_objects.c: + * gst-libs/gst/vaapi/gstvaapifei_objects.h: + * gst-libs/gst/vaapi/gstvaapifei_objects_priv.h: + * gst-libs/gst/vaapi/gstvaapifeienc_h264.c: + * gst-libs/gst/vaapi/gstvaapifeienc_h264.h: + * gst-libs/gst/vaapi/gstvaapifeipak_h264.c: + * gst-libs/gst/vaapi/gstvaapifeipak_h264.h: + * gst-libs/gst/vaapi/gstvaapifeiutils_h264.c: + * gst-libs/gst/vaapi/gstvaapifeiutils_h264.h: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy_priv.h: + * gst-libs/gst/vaapi/meson.build: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode.h: + * gst/vaapi/gstvaapiencode_h264_fei.c: + * gst/vaapi/gstvaapiencode_h264_fei.h: + * gst/vaapi/gstvaapifeivideometa.c: + * gst/vaapi/gstvaapifeivideometa.h: + * gst/vaapi/meson.build: + * meson.build: + * tests/internal/meson.build: + * tests/internal/test-fei-enc-in.c: + * tests/internal/test-fei-enc-out.c: + Remove all FEI related + FEI encoders are not actively mantained neither tested, and it is + using infrastructure that is changing and FEI is stopping this + effort. + Also it is required to rethink how FEI can be used in GStreamer. + +2020-01-14 11:17:49 -0800 U. Artie Eoff + + * gst/vaapi/gstvaapioverlay.c: + vaapioverlay: ensure sinkpad has current buffer + Use the gst_video_aggregator_pad_has_current_buffer API + to check if the current sinkpad has a queued buffer before + attempting to obtain a input buffer from the base plugin. + If the sinkpad does not have a current buffer, then it is + either not producing them yet (e.g. current time < sinkpad + start time) or it has reached EOS. + Previously, we only handled EOS case. + Example: + gst-launch-1.0 videotestsrc num-buffers=100 \ + ! vaapipostproc ! vaapioverlay name=overlay \ + ! vaapisink videotestsrc timestamp-offset=1000000000 \ + num-buffers=100 ! video/x-raw,width=160,height=120 \ + ! overlay. + +2020-01-14 18:57:31 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapioverlay.c: + vaapioverlay: unroll the recursive call + Recursive functions are elegant but dangerous since they might + overflow the stack. It is better to turn them into a list tranversal + if possible, as this case. + +2020-01-14 18:46:49 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiblend.c: + * gst/vaapi/gstvaapioverlay.c: + vaapioverlay: add minimal documentation + +2020-01-14 18:25:11 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiblend.c: + * gst-libs/gst/vaapi/gstvaapiblend.h: + * gst/vaapi/gstvaapioverlay.c: + libs: blend: simplify generator API + Instead of using a parent structure that has to be derived by API + consumers, this change propse a simplification by using the common + pattern of GTK of passing a function pointer and user data which will + be passed as its parameter. That user data contains the state and the + function will be called to update that state. + +2020-01-10 10:14:38 -0800 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapiblend.c: + * gst-libs/gst/vaapi/gstvaapiblend.h: + libs: blend: remove begin/render/end API + This API was risky and is superseded by the surface + generator (process) API. + Resolves #219 + +2020-01-10 10:12:36 -0800 U. Artie Eoff + + * gst/vaapi/gstvaapioverlay.c: + vaapioverlay: use blend surface generator API + See #219 + +2020-01-10 09:54:30 -0800 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapiblend.c: + * gst-libs/gst/vaapi/gstvaapiblend.h: + libs: blend: add surface generator API + This new API allows the user to call a single method (process) + which handles the [display] lock/unlock logic internally for + them. + This API supersedes the risky begin, render, end API. + It eliminates the need for the user to call a lock method + (process_begin) before processing the input buffers + (process_render) and calling an unlock method (process_end) + afterwards. + See #219 + +2019-12-23 14:29:08 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode.h: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h265.c: + plugin: encode: List all possible profiles to detect input formats. + The current get_profile just return one possible profile for the encode, + which is not enough. For example, if we want to support HEVC 4:4:4 + profile, the input of encode should be VYUA rather than NV12 in HEVC + main profile. So the command line: + gst-launch-1.0 videotestsrc num-buffers=200 ! capsfilter \ + caps=video/x-raw,format=VUYA,width=800,height=600 ! vaapih265enc \ + tune=low-power init-qp=30 ! fakesink + can not work because vaapih265enc just report NV12 in sink caps, we need + to specify the profile obviously like: + gst-launch-1.0 videotestsrc num-buffers=200 ! capsfilter \ + caps=video/x-raw,format=VUYA,width=800,height=600 ! vaapih265enc \ + tune=low-power init-qp=30 ! capsfilter caps=video/x-h265, \ + profile=main-444 ! fakesink + The encode should have the ability to choose the profile based on input + format automatically. If the input video format is VUYA, the main-444 + profile should be auto choosed. + We modify to let get_allowed_profiles of each encode sub class to return + an array of all supported profiles based on downstream's allowed caps, or + return NULL if no valid profiles specified by downstream. + If no allowed profiles found, all profiles which belong to the current + encoder's codec will be the candidates. + The function gst_vaapi_encoder_get_surface_attributes collects the surface's + attributes for that profile list we just get. + So for this case, both NV12 and VUYA should be returned. + TODO: some codec like VP9, need to implement the get_profile() function. + +2020-01-08 15:07:36 +0800 He Junyan + + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + plugin: util: add helper function to detect profiles in caps. + +2020-01-08 15:04:18 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + libs: encoder: add a helper function to get all supported profiles + +2020-01-13 15:34:54 +0900 Seungha Yang + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + libs: decoder: Don't unref null object + ** (gst-launch-1.0:9789): CRITICAL **: 15:29:09.330: + gst_vaapi_context_unref: assertion 'context != NULL' failed + +2020-01-10 09:26:44 -0800 U. Artie Eoff + + * gst/vaapi/gstvaapioverlay.c: + plugins: overlay: use proper NULL check on double pointer + Check the address of the variable is not NULL, + not the address of the pointer. + +2020-01-08 23:42:21 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapicodedbuffer_priv.h: + libs: codedbuf: delete a useless field. + The context field in GstVaapiCodedBuffer is not inited correctly + and is never used, just delete it. + +2019-12-29 17:57:52 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + plugins: add iHD driver in whitelist + +2020-01-02 21:02:40 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: modify 265 SPS header's profile compatibility flag. + Make the SPS profile compatibility flags more precisely conform to + the HEVC Spec. + +2020-01-06 19:39:06 +0100 Víctor Manuel Jáquez Leal + + * tests/check/elements/vaapioverlay.c: + test: vaapioverlay: bail test if not available + vaapioverlay is only registered if the VA driver support the blend + operation. + This patch only executes the test if vaapioverlay is available, + otherwise the test is bail out without raising an error. + +2020-01-06 14:53:28 +0100 Víctor Manuel Jáquez Leal + + * tests/check/elements/vaapioverlay.c: + tests: vaapioverlay: force drm backend + +2019-12-22 17:32:19 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiblend.c: + libs: blend: update to new mini-object API + +2019-11-19 13:48:22 -0800 U. Artie Eoff + + * tests/check/elements/vaapioverlay.c: + * tests/check/meson.build: + tests: check: add basic vaapioverlay test + Add test_overlay_position test to verify sink_1 input + is overlayed onto sink_0 input at the appropriate + position. + +2019-11-14 12:03:57 -0800 U. Artie Eoff + + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapioverlay.c: + * gst/vaapi/gstvaapioverlay.h: + * gst/vaapi/meson.build: + plugins: add vaapioverlay plugin + A plugin similar to the base compositor element but + uses VA-API VPP blend functions to accelerate the + overlay/compositing. + Simple example: + 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. + +2019-11-14 12:02:19 -0800 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapiblend.c: + * gst-libs/gst/vaapi/gstvaapiblend.h: + * gst-libs/gst/vaapi/meson.build: + libs: add a vaapi blend class + Support for the VA-API VPP blend functions. + +2019-11-14 11:54:59 -0800 U. Artie Eoff + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + plugins: base: add GstVideoAggregator subclass support + +2020-01-05 19:32:16 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiimage.c: + libs: image: init all image fields correctly. + +2020-01-06 17:41:53 +0100 Stéphane Cerveau + + * gst/vaapi/gstvaapipostproc.c: + doc: fix pipeline typo in vaapipostproc + +2020-01-02 21:11:44 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: modify 265 VPS header fields. + vps_base_layer_internal_flag and vps_base_layer_available_flag + have been clearly defined now. + +2020-01-01 19:54:13 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + libs: display: fix a resource leak in X11 pixmap format. + +2020-01-02 18:00:21 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiprofilecaps.c: + * gst-libs/gst/vaapi/gstvaapiprofilecaps.h: + libs: utils: delete useless gst_vaapi_profile_caps_append_encoder. + +2019-12-30 14:09:17 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst/vaapi/gstvaapiencode.c: + libs: encoder: get surfaces resolution the same time with formats. + We can get all the information about the video format at one shot + when we create the test context for getting the supported formats. + The current way to get the width and height ranges are inefficient, + since it calls the function gst_vaapi_profile_caps_append_encoder() + and it creates another temporal context to detect the resolution + information. + Signed-off-by: Víctor Manuel Jáquez Leal + +2019-12-28 17:42:55 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + libs: encoder: vp9: fix code style + +2019-12-16 23:19:46 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + libs: encoder: set entrypoint based on tune automatically + Some profile, such as H265_MAIN_444 on new Intel platform, may only + support ENTRYPOINT_SLICE_ENCODE_LP entrypoint. This leads two + problems: + 1. We need to specify the tune mode like `vaapih265enc tune=low-power` + every time when we need to use this kind of profile. Or we can not + create the encoder context successfully. + 2. More seriously, we set the entrypoint to a fixed value in + init_context_info() and so the create_test_context_config() can not + create the test context for these profile and can not get the + supported video formats, either. + We now change the entrypoint setting based on the tune option of the + encoder. If no tune property provided, we just choose the first + available entrypoint. + +2019-12-16 23:19:46 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + libs: encoder: set context info profile by encoder + Instead of init_context_info() setting the passed profile, it is + assumed that it has to be set by each encoder. + Signed-off-by: Víctor Manuel Jáquez Leal + +2019-12-27 18:49:02 +0100 He Junyan + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + libs: context: add invalid entrypoint symbol + The symbol GST_VAAPI_ENTRYPOINT_INVALID is just a representation of + zero, which was already used as an invalid value tacitly. This patch + only makes it explicit. + Signed-off-by: Víctor Manuel Jáquez Leal + +2019-12-29 01:13:29 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapipixmap_x11.c: + libs: pixmap: Fix a pixmap creation crash. + We use GST_VAAPI_OBJECT_NATIVE_DISPLAY with wrong parameter for x11 + pixmap creation, which causes crash if we run the internal test case + of: + test-decode --pixmap + +2019-12-22 14:35:18 +0800 He Junyan + + * gst/vaapi/gstvaapiencode.c: + plugin: encode: set allowed_sinkpad_caps to empty. + We now set encode->allowed_sinkpad_caps to NULL if we fail to get + surfaces formats. This causes two problem: + 1. gst_video_encoder_proxy_getcaps use NULL as its caps parameter, + which changes its behavior. It will use encode's sinkpad template + rather than empty caps to do the clip job. So even if we fail to set + allowed_sinkpad_caps, gst_video_encoder_proxy_getcaps can still return + valid caps. + 2. We should just set the allowed_sinkpad_caps once. The NULL point + make the ensure_allowed_sinkpad_caps function works again and again. + +2019-12-22 15:22:57 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: Add NULL pointer check for context when finalize. + Context may be NULL if pipeline fail in early stage, and the + ensure_context will not be called. Need to add a pointer protection + for it. + +2019-12-20 06:38:42 -0800 U. Artie Eoff + + * gst/vaapi/gstvaapipluginbase.c: + plugins: base: do not reset can_dmabuf + Don't reset the can_dmabuf field. This restores the + close/reset logic that existed prior to commit + ca2942176b5632e07eebac23336954f9aaf1cb26 in regards to + dmabuf support. + Plugins only call gst_vaapi_plugin_base_set_srcpad_can_dmabuf + once during startup, but may need to reset the other private + fields multiple times during negotiation. Thus, can_dmabuf + should be exempt from the resets. + Fixes #208 + +2019-12-06 00:21:12 +0800 He Junyan + + * gst/vaapi/gstvaapiencode.c: + plugin: encode: Refine encode's sink caps. + The old manner to get the encode's sink caps is not correct. + Such as 264 encode, it gets: + video/x-raw(memory:VASurface), + format=(string){ ENCODED, NV12, I420, YV12, YUY2, UYVY, Y210, + P010_10LE, AYUV, Y410, Y444 }, width=(int)[ 32, 4096 ], + height=(int)[ 32, 4096 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; + video/x-raw(memory:DMABuf), format=(string){ I420, YV12, RGBA }, + width=(int)[ 32, 4096 ], height=(int)[ 32, 4096 ], + framerate=(fraction)[ 0/1, 2147483647/1 ]; + video/x-raw, format=(string){ NV12 }, width=(int)[ 32, 4096 ], + height=(int)[ 32, 4096 ], framerate=(fraction)[ 0/1, 2147483647/1 ] + where the formats for memory:VASurface and memory:DMABuf are superfluous. + All the "I420, YV12, YUY2, UYVY, Y210, RGBA" can not be really used as + input format for encoder. + We should get: + video/x-raw, format=(string){ NV12 }, width=(int)[ 32, 4096 ], + height=(int)[ 32, 4096 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; + video/x-raw(memory:VASurface), format=(string){ NV12 }, + width=(int)[ 32, 4096 ], height=(int)[ 32, 4096 ], + framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw(memory:DMABuf), + format=(string){ NV12 }, width=(int)[ 32, 4096 ], + height=(int)[ 32, 4096 ], framerate=(fraction)[ 0/1, 2147483647/1 ] + as the correct result. + +2019-12-20 08:37:11 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + libs: display: code clean up + +2019-12-12 21:34:21 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + libs: display: refine the profile/entrypoint map. + The old way make the one config for each profile/entrypoint pair, + which is not very convenient for description the relationship + between them. One profile may contain more than one entrypoints + to within it, so a set like data structure should be more suitable. + +2019-12-19 14:19:10 +0100 He Junyan + + * gst-libs/gst/vaapi/gstvaapibufferproxy.c: + * gst-libs/gst/vaapi/gstvaapibufferproxy_priv.h: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + * gst-libs/gst/vaapi/gstvaapiencoder_objects.c: + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapipixmap_x11.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapisurface_drm.c: + * gst-libs/gst/vaapi/gstvaapisurface_egl.c: + * gst-libs/gst/vaapi/gstvaapisurface_priv.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy_priv.h: + * gst-libs/gst/vaapi/gstvaapitexture_egl.c: + * gst-libs/gst/vaapi/gstvaapitexture_glx.c: + * gst-libs/gst/vaapi/gstvaapivideopool.c: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideometa.c: + * gst/vaapi/gstvaapivideometa_texture.c: + * tests/internal/image.c: + * tests/internal/test-filter.c: + * tests/internal/test-surfaces.c: + * tests/internal/test-windows.c: + libs: surface: port to GstMiniObject + GstVaapiMiniObject and GstVaapiObject are deprecated. + This is the first step to remove them by porting GstVaapiSurface as + a GstMiniBuffer descendant. + Signed-off-by: Víctor Manuel Jáquez Leal + +2019-12-19 18:26:10 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapisurface.c: + libs: surface: rename create function names to init + There are several internal functions with 'create' name, but they + don't create any new structure, but rather it initializes that + structure. Renaming those function to reflect better their purpose. + +2019-12-19 14:17:34 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapisurface.c: + libs: surface: use macro accessors + +2019-12-19 13:46:09 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapisurface_priv.h: + libs: surface: fix internal documentation + +2019-12-18 18:00:49 +0100 He Junyan + + * gst-libs/gst/vaapi/gstvaapicodedbuffer.c: + * gst-libs/gst/vaapi/gstvaapicodedbuffer.h: + * gst-libs/gst/vaapi/gstvaapicodedbuffer_priv.h: + * gst-libs/gst/vaapi/gstvaapicodedbufferproxy.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + * gst-libs/gst/vaapi/gstvaapifeienc_h264.c: + * gst-libs/gst/vaapi/gstvaapifeipak_h264.c: + * gst-libs/gst/vaapi/gstvaapivideopool.c: + libs: codedbuffer: port to GstMiniObject + GstVaapiMiniObject and GstVaapiObject are deprecated. + This is the first step to remove them by porting GstVaapiCodedBuffer + as a GstMiniBuffer descendant. + Signed-off-by: Víctor Manuel Jáquez Leal + +2019-12-18 12:57:01 +0100 He Junyan + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst-libs/gst/vaapi/gstvaapiimage_priv.h: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface_drm.c: + * gst-libs/gst/vaapi/gstvaapivideopool.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideometa.c: + * tests/internal/image.c: + * tests/internal/simple-encoder.c: + * tests/internal/test-fei-enc-in.c: + * tests/internal/test-filter.c: + * tests/internal/test-windows.c: + libs: image: port to GstMiniObject base class + GstVaapiMiniObject and GstVaapiObject are deprecrated. This is the + first step to remove them, by porting GstVaapiImage as a + GstMiniObject. + Signed-off-by: Víctor Manuel Jáquez Leal + +2019-09-24 01:01:22 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapicodedbuffer.c: + * gst-libs/gst/vaapi/gstvaapicodedbufferpool.c: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + * gst-libs/gst/vaapi/gstvaapiprofilecaps.c: + libs: context: port to a plain C structure + The GstVaapiMiniObject is obsolete and we need to replace it. This + patch turns GstVaapiContext into a plain C structure with its own + reference counting mechanism. + Also this patch removes unused overlays attributes. + Signed-off-by: Víctor Manuel Jáquez Leal + +2019-12-18 00:40:58 +0800 He Junyan + + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h264_fei.c: + * gst/vaapi/gstvaapiencode_h265.c: + * gst/vaapi/gstvaapiencode_jpeg.c: + * gst/vaapi/gstvaapiencode_mpeg2.c: + * gst/vaapi/gstvaapiencode_vp8.c: + * gst/vaapi/gstvaapiencode_vp9.c: + plugin: encode: change the dmabuf caps to all supported formats. + The encode's dmabuf caps definition is obsolete, it can support + more formats now. Re-define it to include all supported formats + in video format map. + +2019-12-17 17:09:37 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + libs: encoder: h264fei: remove unnecessary check + Issue detected by Coverity + `info_to_pack.h264_slice_header` is always allocated by + gst_vaapi_feipak_h264_encode(), thus checking it to free it afterwards + in doesn't make much sense. But it requires to be free on the error + path. + There may be a null pointer dereference, or else the comparison + against null is unnecessary. + In gst_vaapi_encoder_h264_fei_encode: All paths that lead to this null + pointer comparison already dereference the pointer earlier + +2019-12-17 17:05:22 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapifeienc_h264.c: + libs: encoder: h264fei: remove unnecessary assert + Issue detected by Coverity + An unsigned value can never be negative, so this test will always + evaluate the same way. + In add_slice_headers: An unsigned value can never be less than 0 + +2019-12-17 16:57:41 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + libs: encoder: h264fei: remove unnecessary check + Issue detected by Coverity + There may be a null pointer dereference, or else the comparison + against null is unnecessary. + In gst_vaapi_encoder_h264_fei_encode: All paths that lead to this null + pointer comparison already dereference the pointer earlier + +2019-12-17 16:49:47 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + * gst-libs/gst/vaapi/gstvaapifeienc_h264.c: + libs: encoder: h264fei: don't free memory on stack + Issue detected by Coverity + `info_to_pak` variable in gst_vaapi_encoder_h264_fei_encode() is + declared in the stack, but it is free in + gst_vaapi_feienc_h264_encode() as if declared on the heap. + This patch initializes the structure and removes the free. + A non-heap pointer is placed on the free list, likely causing a crash + later. + In gst_vaapi_encoder_h264_fei_encode: Free of an address-of + expression, which can never be heap allocated. + +2019-12-17 13:22:12 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + libs: encoder: h264fei: fix surface leak + Issue detected by Coverity + If the FEI mode is not handled the created resources should be + released and return and error code. + The system resource will not be reclaimed and reused, reducing the + future availability of the resource. + In gst_vaapi_encoder_h264_fei_encode: Leak of memory or pointers to + system resources + +2019-12-17 13:09:58 +0100 Víctor Manuel Jáquez Leal + + * tests/check/elements/vaapipostproc.c: + tests: check return calling of gst_navigation_event_parse.* + This issue was detected by Coverity. + If the function returns an error value, the error value may be mistaken + for a normal value. + In cb_mouse_event: Value returned from a function is not checked for + errors before being used + +2019-12-16 16:25:02 +0800 He Junyan + + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h264_fei.c: + * gst/vaapi/gstvaapiencode_h265.c: + * gst/vaapi/gstvaapiencode_jpeg.c: + * gst/vaapi/gstvaapiencode_mpeg2.c: + * gst/vaapi/gstvaapiencode_vp8.c: + * gst/vaapi/gstvaapiencode_vp9.c: + plugin: encode: set sink's raw caps to GST_VAAPI_FORMATS_ALL. + Then encode plugin just supports raw formats declared in vaapi video + format map. This modification makes the template caps more precise. + +2019-11-14 11:13:51 -0800 U. Artie Eoff + + * gst/vaapi/gstvaapipluginbase.c: + plugins: base: add GstPad param to internal helper functions + The base plugin public API function implementations determine + which pad should be passed to the internal helper functions. + Currently, only the base plugin static sinkpad and static + srcpad are supported/used. However, this change enables future + API functions to be added that can accept a pad (i.e. request pad) + from an element subclass (e.g. a GstVideoAggregator subclass). + +2019-11-12 12:21:52 -0800 U. Artie Eoff + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + plugins: base: manage pad-specific data in a single struct + Define a struct (GstVaapiPadPrivate) to encapsulate the + pad-specific data (i.e. buffer pool, allocator, info, + caps, etc.). + Add an interface to retrieve the data struct for a given + pad. + Finally, update the base plugin to use the data struct + throughout the implementation. + This will enable us to easily extend the base plugin in the + future to allow for N-to-1 pad subclasses (e.g. overlay/ + composite). + +2019-10-29 15:13:44 -0700 U. Artie Eoff + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapipluginbase.h: + * gst/vaapi/gstvaapipostproc.c: + plugins: use plugin base macros to access pad specific data + Don't access base struct fields directly since the underlying + definition can change. Instead, use the accessor macros. + +2019-12-03 00:52:45 +0800 He Junyan + + * gst/vaapi/gstvaapidecode.c: + libs: decoder: Modify decode src's template raw formats + We do not need to maintain a standalone list of decoder's output + template for raw formats and that is easy to make mistake(for + example, the AYVU is wrong in that list, should be VUYA). + Just use GST_VAAPI_FORMATS_ALL to replace the raw formats list for + src template. + +2019-12-11 14:11:13 +0800 He Junyan + + * gst/vaapi/gstvaapipostproc.c: + libs: postproc: Modify src/sink template raw formats + We need to provide more precise template caps for postproc's src + and sink pads. The GST_VIDEO_FORMATS_ALL make all video formats + available which are really superfluous. + +2019-12-10 18:40:42 -0300 Thibault Saunier + + * tests/check/elements/vaapipostproc.c: + Do not mix declaration and code + +2019-11-03 17:59:01 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + libs: decoder: h265: skip all pictures prior the first I-frame + Don't try to decode until the first I-frame is received within the + currently active sequence. i965 H265 decoder don't show any artifact + but it crashes. + Fixes: #98 + +2019-11-27 01:44:05 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/video-format.c: + libs: video-format: remove dead code + +2019-10-31 00:59:34 +0800 He Junyan + + * gst-libs/gst/vaapi/video-format.c: + * gst-libs/gst/vaapi/video-format.h: + * gst/vaapi/gstvaapipluginutil.h: + libs: video-format: add GST_VAAPI_FORMATS_ALL + GST_VAAPI_FORMATS_ALL collects all declared formats in video-format + as a caps template string, and make them available in caps with + memory:VASurface feature. + Fixes: #199 + +2019-11-06 22:37:12 +0800 He Junyan + + * gst-libs/gst/vaapi/video-format.c: + * tests/internal/test-windows.c: + libs: video-format: change GST_VIDEO_FORMAT_AYUV to VUYA. + We only support VUYA format in gst vaapi now, need to correct + the mapping. + +2019-10-09 15:13:09 -0700 U. Artie Eoff + + * tests/check/elements/vaapipostproc.c: + tests: check: vaapipostproc test_orientation_mouse_events + Test that vaapipostproc properly translates mouse events + when using video-direction (orientation). + +2019-10-09 10:11:54 -0700 U. Artie Eoff + + * tests/check/elements/vaapipostproc.c: + * tests/check/meson.build: + tests: check: vaapipostproc test_crop_mouse_events + Test that vaapipostproc properly translates mouse events + when cropping. + +2019-10-08 12:20:26 -0700 U. Artie Eoff + + * meson.build: + * meson_options.txt: + * tests/check/elements/vaapipostproc.c: + * tests/check/meson.build: + * tests/meson.build: + tests: check: initial unit test support + Add minimal unit test toolchain files and a simple + vaapipostproc unit test. + +2019-10-08 12:19:06 -0700 U. Artie Eoff + + * meson.build: + * tests/examples/meson.build: + * tests/examples/test-roi.c: + * tests/examples/test-vaapicontext.c: + * tests/examples/test-vaapipostproc.c: + * tests/examples/test-vaapisink.c: + * tests/internal/codec.c: + * tests/internal/codec.h: + * tests/internal/decoder.c: + * tests/internal/decoder.h: + * tests/internal/image.c: + * tests/internal/image.h: + * tests/internal/meson.build: + * tests/internal/output.c: + * tests/internal/output.h: + * tests/internal/simple-decoder.c: + * tests/internal/simple-encoder.c: + * tests/internal/test-decode.c: + * tests/internal/test-decode.h: + * tests/internal/test-display.c: + * tests/internal/test-fei-enc-in.c: + * tests/internal/test-fei-enc-out.c: + * tests/internal/test-filter.c: + * tests/internal/test-h264.c: + * tests/internal/test-h264.h: + * tests/internal/test-jpeg.c: + * tests/internal/test-jpeg.h: + * tests/internal/test-mpeg2.c: + * tests/internal/test-mpeg2.h: + * tests/internal/test-mpeg4.c: + * tests/internal/test-mpeg4.h: + * tests/internal/test-subpicture-data.c: + * tests/internal/test-subpicture-data.h: + * tests/internal/test-subpicture.c: + * tests/internal/test-surfaces.c: + * tests/internal/test-textures.c: + * tests/internal/test-vc1.c: + * tests/internal/test-vc1.h: + * tests/internal/test-windows.c: + * tests/internal/y4mreader.c: + * tests/internal/y4mreader.h: + * tests/meson.build: + tests: move examples and tests to subfolders + This makes way for adding unit (check) tests. + +2019-10-14 01:01:27 +0100 Tim-Philipp Müller + + * .gitmodules: + * Makefile.am: + * autogen.sh: + * common: + * configure.ac: + * git.mk: + * gst-libs/Makefile.am: + * gst-libs/gst/Makefile.am: + * gst-libs/gst/vaapi/Makefile.am: + * gst/Makefile.am: + * gst/vaapi/Makefile.am: + * m4/Makefile.am: + * tests/Makefile.am: + * tests/elements/Makefile.am: + Remove autotools build + +2019-10-10 15:26:36 -0700 U. Artie Eoff + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: fix off-by-one coord translations + When translating navigation x,y coordinates for + video-direction, it is necessary to subtract 1 + when using the video dimensions to compute the + new x,y coordinates. That is, a 100x200 image + should map coordinates in x=[0-99],y=[0-199]. + This issue was found with unit tests provided + in !182. + +2019-10-11 17:34:06 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + libs: window: x11: Avoid usage of deprecated API + +2019-10-11 17:13:34 +0200 Víctor Manuel Jáquez Leal + + * meson.build: + build: halt meson configuration if no renderer API + We should halt meson configuration if there is no render API + installed (either DRM, Wayland or X11). + That behavior was already in autotools but missed in meson. This patch + brings it back. + Fixes: #196 + +2019-10-09 12:12:18 -0700 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapifilter.c: + libs: filter: fix default orientation regression + Fix regression introduced in f232f87f7082 + +2019-10-07 11:53:23 -0700 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapifilter.c: + libs: filter: use OP_DATA_DEFAULT_VALUE macro + +2019-10-07 11:39:19 -0700 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapifilter.c: + libs: filter: use macro for returning op default value + The code is essentially the same for getting all op default + values. Thus, use a macro to help minimize code duplication + and [hopefully] encourage using the same mechanism for all + default getters. + +2019-10-07 09:56:37 -0700 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapifilter.c: + libs: filter: query param spec for default scale method + Related: #159 + +2019-10-07 09:44:06 -0700 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapifilter.c: + libs: filter: query param spec for default skin-tone values + Related: #159 + +2019-10-02 12:54:52 -0700 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapifilter.c: + libs: filter: query param spec for default video-direction + Related: #159 + +2019-10-07 10:23:09 -0700 U. Artie Eoff + + * .gitignore: + add .gitignore + +2019-09-05 16:40:52 +0800 Yan Wang + + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapifilter.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + vaapipostproc: Use level value for skin-tone-enhancement filter. + Currently the parameter of skin-tone-enhancement filter is forced + to zero. In fact it could be set different value by the user. + So create a new property named as "skin-tone-enhancement-level" + for accepting the used defined parameter value. + At the same time, skin-tone-enhancement is marked as deprecated. + When skin-tone-enhancement-level is set, skin-tone-enhancement + will be ignored. + +2019-09-21 13:39:42 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + libs: decoder: h264, h266: fix g_return_val_if_fail() missuse + g_return_val_fail() documentations says: + If expr evaluates to FALSE, the current function should be + considered to have undefined behaviour (a programmer error). + The only correct solution to such an error is to change the + module that is calling the current function, so that it avoids + this incorrect call. + So it was missused in a couple parts of the H264 and H265 internal + decoders. This patch changes that to plain conditionals. + Also, it was included a couple code-style fixes. + +2019-09-23 19:52:20 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * tests/simple-encoder.c: + * tests/test-fei-enc-in.c: + libs: encoder: remove gst_vaapi_encoder_{ref,unref}() + Since GstVaapiEncoder is a descendant of of GstObject, there is no + need to keep a custom ref()/unref() methods. This patch deletes them. + +2019-09-24 01:03:02 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: correct encoder's ref/unref function. + GstVaapiEncoder now is a standard gstobject and need to use + gst_object_ref/unref functions. + +2019-09-19 12:09:20 -0700 U. Artie Eoff + + * gst/vaapi/gstvaapiencode_h264_fei.c: + gst: encode: h264_fei: remove useless comparison + The expression "len >= 0" is always true since "len" + is an unsigned type. And it is clear that the writers + intention was not to write "len > 0" since we handle + len == 0 in the ensuing "if (len < 3)" conditional + block. + +2019-09-19 11:17:24 -0700 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + libs: encoder: h264_fei: fix potential overflow before widen + Found by static analysis. encoder->mb_width * encoder->mb_height + is evaluated using 32-bit arithmetic before widen. Thus, cast + at least one of these to guint64 to avoid overflow. + +2019-09-19 10:56:13 -0700 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + libs: encoder: h264_fei: remove dead error condition + Found by static analysis. The feipak is always null + when we reach the error target. + +2019-09-19 10:49:11 -0700 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapiutils.c: + libs: utils: add missing break in switch + +2019-09-11 11:56:35 +0800 He Junyan + + * gst-libs/gst/vaapi/video-format.c: + libs: video-format: Make all YUV format available + The YUV formats have no ambiguity for drivers, so we can add them all. + Some old driver(i965) does not implement full get/put image functions + but can use derive image funtions for the YUV format. It does not + report that kind of formats correctly in image query, but will derive + that YUV format image from surface. The dynamic mapping of YUV format + will block that manner. + Adding more YUV format mapping has no side effect. So considering the + legacy driver conformance, we add all YUV formats mapping statically + and dynamic mapping RBG formats + Fix: #189 + Fix: #190 + +2019-09-18 15:30:03 +1000 Matthew Waters + + * gst-libs/gst/vaapi/gstvaapiutils_egl.c: + * gst-libs/gst/vaapi/gstvaapiutils_egl.h: + egl: Fix racyness in display thread creation + Multiple different scenarios could break the display thread creation and + end up blocking waiting for thread o be created. Fix them all by + correctly waiting for a new boolean to become valid. + +2019-09-18 15:29:03 +1000 Matthew Waters + + * gst-libs/gst/vaapi/gstvaapiutils_egl.c: + egl: don't advertise a wrapped EGLContext as actually wrapped + It's not actually wrapped as we create a new EGLContext from the passed + in EGLContext. As a result, the created EGLContext was never destroyed. + +2019-09-16 23:28:31 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + libs: h264decoder: do not return error for unhandled NAL unit. + Some streams have error data introducing unknown NAL type. There are + also kinds of NAL types we do not want to handle. The old manner will + set a decoder error when encounter this, which cause a latent crash bug. + The decoder may successfully decode the picture and insert it into DPB. + But there are error NAL units after the AU which cause the post unit error + and make that frame dropped. The later output of the picture still want + to ref that frame and crash. + No need to set decoder error when can not recognize or handle the NAL + unit, just skip it and continue. + Fix: #191 + +2019-09-11 14:32:22 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + * gst-libs/gst/vaapi/gstvaapifeienc_h264.c: + * gst/vaapi/gstvaapiencode.c: + libs: encoders: use GST_PARAM_USER_SHIFT to define internal params + This patch makes use of GST_PARAM_USER_SHIFT to define the internal + param in encoders to decide which parameters to expose. Thus + gstreamer-vaapi will not interfere with any change in GStreamer in the + future. + Also, the internal symbol was change to + GST_VAAPI_PARAM_ENCODER_EXPOSURE to keep the namespacing. + +2019-09-09 18:06:51 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/video-format.c: + libs: Add BGR10A2_LE support for color space conversion. + Fix: #179 + +2019-08-23 14:41:06 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapisurface.c: + libs: surface: add pointer check for surface_new_from_formats. + The command line: + gst-launch-1.0 filesrc location=some_name.mjpeg ! jpegparse ! + vaapijpegdec ! videoconvert ! video/x-raw,format=I420 ! vaapisink + will crash on i965 driver because of no pointer check. + We now generate the video format map between GST format and VA format + dynamically based on the image format returned by vaQueryImageFormats. + i965 driver does to report image format of 444P and Y800 forcc, while + the jpeg decoder context VASurfaceAttribPixelFormat use them. We can + not recognize these format and pass a NULL pointer to + gst_vaapi_surface_new_from_formats. + We need to add a pointer check here and let the fallback logic handle + this case correctly. + Other drivers work well. + +2019-09-07 13:23:01 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiutils.c: + libs: utils: guard the VAEntrypointFEI symbol + VAEntrypointFEI appeared in libva 2.0.0 (API version 1.0.0) + +2019-09-05 14:48:22 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/video-format.c: + * gst-libs/gst/vaapi/video-format.h: + libs: video-format: Refine the video format mapping. + Improve the mapping between va format and gst format. The new map + will be generated dynamically, based on the query result of image + format in VA driver. Also consider the ambiguity of RGB color + format in LSB mode. + +2019-04-15 16:51:26 +0100 Philippe Normand + + * gst/vaapi/gstvaapipluginutil.c: + pluginutil: Remove Mesa from drivers white list + The Mesa Gallium driver is poorly tested currently, leading to bad user + experience for AMD users. The driver can be added back to the white list at + runtime using the GST_VAAPI_ALL_DRIVERS environment variable. + +2019-07-08 14:18:00 -0700 U. Artie Eoff + + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + * gst/vaapi/gstvaapipostprocutil.c: + vaapipostproc: allow cropping via properties + Add crop-left, crop-right, crop-top and crop-bottom + properties to vaapipostproc. + +2019-08-30 17:31:45 -0700 U. Artie Eoff + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: rotate outbuf and crop meta if forwarding + When forwarding crop meta to downstream, the output + buffer and crop meta need to be rotated, too. + Test: + for i in 90r 180 90l vert horiz ul-lr ur-ll + do + gst-launch-1.0 -vf videotestsrc num-buffers=500 \ + ! videocrop top=100 bottom=30 left=40 right=20 \ + ! vaapipostproc video-direction=$i \ + ! vaapisink & \ + gst-launch-1.0 -vf videotestsrc num-buffers=500 \ + ! videocrop top=100 bottom=30 left=40 right=20 \ + ! vaapipostproc video-direction=$i \ + ! identity drop-allocation=true \ + ! vaapisink + done + +2019-08-30 14:14:30 -0700 U. Artie Eoff + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: fix output buffer WxH for crop meta forwarding + Adding crop meta x,y to w,h only compensates for left,top + cropping. But we also need to compensate for right,bottom + cropping. + The video meta contains the appropriate w,h (uncropped) + values, so use it instead. + Test: + gst-launch-1.0 -vf videotestsrc num-buffers=500 \ + ! videocrop top=50 bottom=30 left=40 right=20 \ + ! vaapipostproc ! vaapisink & \ + gst-launch-1.0 -vf videotestsrc num-buffers=500 \ + ! videocrop top=50 bottom=30 left=40 right=20 \ + ! vaapipostproc ! identity drop-allocation=1 \ + ! vaapisink + +2019-09-04 10:52:51 -0700 U. Artie Eoff + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: handle size and direction together in src events + Mapping a pointer event needs to consider both size and + video-direction operations together, not just one or the other. + This fixes an issue where x,y were not being mapped correctly + for 90r, 90l, ur-ll and ul-lr video-direction. In these directions, + the WxH are swapped and GST_VAAPI_POSTPROC_FLAG_SIZE is set. Thus, + the first condition in the pointer event handling was entered and + x,y scale factor were incorrectly computed due to srcpad WxH + swap. + This also fixes all cases where both video-direction and scaling + are enabled at the same time. + Test that all pointer events map appropriately: + for i in `seq 0 7` + do + GST_DEBUG=vaapipostproc:5 gst-launch-1.0 -vf videotestsrc \ + ! vaapipostproc video-direction=${i} width=300 \ + ! vaapisink + GST_DEBUG=vaapipostproc:5 gst-launch-1.0 -vf videotestsrc \ + ! vaapipostproc video-direction=${i} width=300 height=200 \ + ! vaapisink + GST_DEBUG=vaapipostproc:5 gst-launch-1.0 -vf videotestsrc \ + ! vaapipostproc video-direction=${i} height=200 \ + ! vaapisink + GST_DEBUG=vaapipostproc:5 gst-launch-1.0 -vf videotestsrc \ + ! vaapipostproc video-direction=${i} \ + ! vaapisink + done + +2019-08-20 14:22:57 -0700 U. Artie Eoff + + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + vaapipostproc: advertise crop meta is handled + Advertise to upstream that vaapipostproc can handle + crop meta. + When used in conjunction with videocrop plugin, the + videocrop plugin will only do in-place transform on the + crop meta when vaapipostproc advertises the ability to + handle it. This allows vaapipostproc to apply the crop + meta on the output buffer using vaapi acceleration. + Without this advertisement, the videocrop plugin will + crop the output buffer directly via software methods, + which is not what we desire. + vaapipostproc will not apply the crop meta if downstream + advertises crop meta handling; vaapipostproc will just + forward the crop meta to downstream. If crop meta is + not advertised by downstream, then vaapipostproc will + apply the crop meta. + Examples: + 1. vaapipostproc will forward crop meta to vaapisink + gst-launch-1.0 videotestsrc \ + ! videocrop left=10 \ + ! vaapipostproc \ + ! vaapisink + 2. vaapipostproc will do the cropping + gst-launch-1.0 videotestsrc \ + ! videocrop left=10 \ + ! vaapipostproc \ + ! identity drop-allocation=1 \ + ! vaapisink + +2019-08-29 18:44:36 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + libs: encoder: clean two virtual func in encoder class + set_property and get_default_properties functions are no longer + needed for encoder class. + +2019-08-29 18:43:30 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapifeienc_h264.c: + * gst-libs/gst/vaapi/gstvaapifeienc_h264.h: + libs: encoder: delete old set_property and property enum feienc264 + +2019-08-29 18:39:27 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.h: + libs: encoder: delete old set_property and property enum in h264 fei + +2019-08-29 18:37:58 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.h: + libs: encoder: delete old set_property and property enum in vp9 + +2019-08-29 18:36:51 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.h: + libs: encoder: delete old set_property and property enum in vp8 + +2019-08-29 18:35:59 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.h: + libs: encoder: delete old set_property and property enum in mpeg2 + +2019-08-29 18:34:57 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.h: + libs: encoder: delete old set_property and property enum in jpeg + +2019-08-29 18:31:56 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.h: + libs: encoder: delete old set_property and property enum in h265 + +2019-08-29 18:30:07 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + libs: encoder: delete old set_property and property enum in h264 + +2019-08-29 18:17:42 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + libs: encoder: delete EncoderPropInfo related functions + +2019-08-29 16:13:19 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + libs: encoder: delete encoder_set_property + We no longer need this obsolete set_property function now after + switch to standard gobject's property manner. + Also delete the old encoder's property enum in the header file. + +2019-08-29 15:59:43 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + libs: encoder: delete properties_get_default for base class + +2019-08-29 15:52:04 +0800 He Junyan + + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode.h: + plugin: encode: delete useless init_properties. + Also delete the get_properties function in encode class. We now + use g_object_class_list_properties to get all properties for + internal encoder class. + +2019-08-29 15:43:45 +0800 He Junyan + + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode.h: + plugin: encode: delete set/get_property func in encode class + Use standard gobject's property functions to replace the old way. + +2019-08-29 15:31:16 +0800 He Junyan + + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode.h: + plugin: encode: delete gst_vaapiencode_init_properties + No need to init the properties got by get_default_properties func + now. The properties are inited correctly in internal encoder class. + +2019-08-29 15:19:10 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + libs: encoder: delete 3 useless init macro + +2019-08-29 15:16:26 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapifeienc_h264.c: + * gst-libs/gst/vaapi/gstvaapifeienc_h264.h: + libs: encoder: delete get_default_properties of feienc + +2019-08-29 15:14:14 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.h: + libs: encoder: delete get_default_properties of H264 Fei + +2019-08-29 15:07:17 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.h: + libs: encoder: delete get_default_properties of VP9 + +2019-08-29 15:06:25 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.h: + libs: encoder: delete get_default_properties of VP8 + +2019-08-29 15:03:52 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.h: + libs: encoder: delete get_default_properties of MPEG2 + +2019-08-29 15:03:19 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.h: + libs: encoder: delete get_default_properties of JPEG + +2019-08-30 19:15:38 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.h: + libs: encoder: delete get_default_properties of H265 + +2019-08-29 14:59:12 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + libs: encoder: delete get_default_properties of H264 + +2019-08-29 14:53:59 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: delete the useless constructed func for encoder. + +2019-08-26 23:16:33 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + * gst-libs/gst/vaapi/gstvaapifeienc_h264.c: + libs: encoder: implement get_view_ids for h264 encoder. + +2019-08-20 23:56:33 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h264_fei.c: + * gst/vaapi/gstvaapiencode_h265.c: + * gst/vaapi/gstvaapiencode_jpeg.c: + * gst/vaapi/gstvaapiencode_mpeg2.c: + * gst/vaapi/gstvaapiencode_vp8.c: + * gst/vaapi/gstvaapiencode_vp9.c: + gst: encode: enable new type of property mechanism. + +2019-08-20 22:16:35 +0800 He Junyan + + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode.h: + gst: encode: add property help functions for encoder properties. + The encoder is a true gstobject now and all the properties are using + gobject's properties mechanism. Add help functions to handle the properties + between encode and encoder class. + The basic idea is mapping the same property between encoder and encode. All + the encoder's properties will have the same name, the same type in encode. + The set/get property function just forward the property setting/getting to + the encoder using the same property name and value. Because the encoder is + created on needed, we need to cache the property setting in encode. + +2019-08-30 18:39:32 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + * gst-libs/gst/vaapi/gstvaapifeienc_h264.c: + libs: encoder: add flags to all encoder properties. + G_PARAM_CONSTRUCT make all properties init correctly, we do not + need to init the properties manually. + G_PARAM_FLAG_VAAPI_ENCODER_EXPOSURE is a vaapi encoder specific + flag, means need to expose the property to according encode class. + +2019-08-20 17:00:39 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + libs: encoder: Add properties for h264 encoder fei. + Install properties for h264 encoder fei class. Also set the new get/set + property functions for gobject class. Still use the old properties + way now and this new feature will be enabled later. + +2019-08-20 15:58:30 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapifeienc_h264.c: + libs: encoder: Add properties for h264 fei encoder. + Install properties for h264 fei encoder class. Also set the new get/set + property functions for gobject class. Still use the old properties + way now and this new feature will be enabled later. + +2019-08-20 15:29:27 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + libs: encoder: Add properties for vp9 encoder. + Install properties for vp9 encoder class. Also set the new get/set + property functions for gobject class. Still use the old properties + way now and this new feature will be enabled later. + +2019-08-20 15:01:02 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + libs: encoder: Add properties for vp8 encoder. + Install properties for vp8 encoder class. Also set the new get/set + property functions for gobject class. Still use the old properties + way now and this new feature will be enabled later. + +2019-08-20 14:31:58 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + libs: encoder: Add properties for mpeg2 encoder. + Install properties for mpeg2 encoder class. Also set the new get/set + property functions for gobject class. Still use the old properties + way now and this new feature will be enabled later. + +2019-08-20 14:53:06 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c: + libs: encoder: Add properties for jpeg encoder. + Install properties for jpeg encoder class. Also set the new get/set + property functions for gobject class. Still use the old properties + way now and this new feature will be enabled later. + +2019-08-20 14:12:36 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: Add properties for h265 encoder. + Install properties for h265 encoder class. Also set the new get/set + property functions for gobject class. Still use the old properties + way now and this new feature will be enabled later. + +2019-08-20 01:33:40 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + libs: encoder: Add properties for h264 encoder. + Install properties for h264 encoder class. Also set the new get/set + property functions for gobject class. Still use the old properties + way now and this new feature will be enabled later. + +2019-08-19 15:38:09 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: add properties and prop help functions + Add all common properties to encoder base class. rate-control and + tune are moved to sub class. + +2019-08-29 14:38:49 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + libs: encoder: delete useless gst_vaapi_encoder_new func. + GstVaapiEncoder is a abstract gobject and never be created directly. + +2019-07-27 00:55:53 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.h: + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.h: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.h: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.h: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.h: + * gst-libs/gst/vaapi/gstvaapifeienc_h264.c: + * gst-libs/gst/vaapi/gstvaapifeienc_h264.h: + lib: encoder: gstobjectfy all vaapi encoders. + Replace all gstvaapiobject in vaapi encoders with standard gstobject. + Let the gstobject common logic to handle all the init and finalize + works. But the property install/set/get still use the old way, need + to be improved later. + +2019-08-29 12:11:36 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: check for filter before appending caps + While ensuring the allowed sink pad caps, the filter attributes set + the frame size restriction, but it is not ensured, at that moment, + that the filter is already instantiaded. + In order to silence the glib logs, this patch add only calls + gst_vaapi_filter_append_caps() if the filter is instantiated. + +2019-08-28 12:49:03 -0400 Thibault Saunier + + * gst/vaapi/gstvaapidecodebin.c: + Classify vaapidecodebin as a hardware decoder + +2019-08-27 18:12:45 +0800 He Junyan + + * gst/vaapi/gstvaapipostproc.c: + libs: postproc: fix a memory leak point. + filter_ops and filter_formats should already have valid value when + the function gst_vaapipostproc_ensure_filter_caps re-enter + +2019-08-27 01:30:36 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiutils_core.c: + libs: util: Fix a memory leak in config_surface_attributes_get + +2019-08-22 14:33:54 +0800 Wangfei + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: support transform ROI meta + This will benefit the use case like: + src ---> encode ---> decode ---> circle ROI ---> sink + | | + --> analyse to --> + get ROI + +2019-08-23 19:10:15 +0200 Mathieu Duponchelle + + * gst/vaapi/gstvaapidecodedoc.c: + docstrings: port ulinks to markdown links + +2019-08-20 17:05:14 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext_overlay.c: + * gst-libs/gst/vaapi/gstvaapicontext_overlay.h: + * gst-libs/gst/vaapi/meson.build: + libs: remove context's overlay + The context overlay was an optimization to apply a video composition + to all the surfaces bound to a context. + But since commit 18031dc6 this optimization was disabled, so it is + better just get rid of it. + +2019-08-20 16:50:46 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapisurface_priv.h: + * gst/vaapi/gstvaapipluginutil.c: + * tests/test-subpicture.c: + libs: remove surface's parent context + In commit 18031dc6 surface's parent context is not assigned because of + circular references. Since then (2013), there's has no issue with + subpictures attached to a context, the current only users of this API. + This patch cleans up all of related code with the unused surface's + parent context. + +2019-08-18 13:53:53 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: guard if no structure is available in caps + +2019-08-18 13:53:19 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapifilter.h: + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: append frame size restrictions in caps + +2019-08-18 13:09:58 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiprofilecaps.c: + libs: profilecaps: refactor common code + +2019-08-16 19:35:58 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode.c: + vaapiencode: set frame size restrictions in caps + Fixes: #12 + +2019-08-16 19:28:27 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst/vaapi/gstvaapiencode.c: + vaapiencode: enhance how the profile is defined + This code doesn't define the profile used by the internal encoder, but + it used to "predict" which is going to be used and to get the caps + restrictions. + Before the profile was predicted by checking the donwstream caps, but + sometimes they are not defined, setting an unknown profile. In order + to enhances this situation, the encoder asks to internal encoder if it + has one. If so, it is used. + To ask the internal encoder's profile a new accessor function was + added: gst_vaapi_encoder_get_profile() + +2019-08-16 19:26:36 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiprofilecaps.c: + * gst-libs/gst/vaapi/gstvaapiprofilecaps.h: + libs: profilecaps: defines gst_vaapi_profile_caps_append_encoder() + Previously it was just a boilerplate. Now it is real implementation. + +2019-08-16 19:17:48 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiutils.c: + libs: utils: treat va_rt_format as bitwise flag + The return value of vaGetConfigAttributes() of VAConfigAttribRTFormat + is a bitwise flag with *all* the supported chroma types. + Previously it was assumed that the return value was a single value, + thus when returning the GST_VAAPI_CHROMA_TYPE_XXX the code was a + simple case. But it is wrong. + This patch changes the case block with a sequence of ifs testing the + bitwise. For now we assume a "priority" list in the testing sequence. + +2019-08-16 18:07:43 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + * tests/test-display.c: + libs: profile: add gst_vaapi_profile_get_va_name() + gst_vaapi_profile_get_name() returns a proper name for + GstCaps. Nonetheless, there are many profiles which don't have a name + representation for that realm. + gst_vaapi_profile_get_va_name() returns the name of the profile + according to its VAProfile name. + This new funtion is used in the encoder error message. + +2019-08-05 19:47:30 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiprofilecaps.c: + * gst-libs/gst/vaapi/gstvaapiprofilecaps.h: + * gst-libs/gst/vaapi/meson.build: + * gst/vaapi/gstvaapidecode.c: + libs: profilecaps: move caps config into a new file + Implement all the appending of frame size restrictions in caps, for + encoders and decoders, in a new source file. + +2019-08-05 19:45:49 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + libs: decoder: ref the caps as property + +2019-08-02 16:56:17 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + libs: context: add gst_vaapi_context_get_surface_attributes() + This function copies the surface attributes from the context's object + to the caller. + +2019-08-02 12:46:55 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapibufferproxy.c: + * gst-libs/gst/vaapi/gstvaapibufferproxy.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + libs: move memory types conversions to gstvaapiutils + And add more supported memory types by current VA. + +2019-08-01 19:48:21 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiutils_core.c: + * gst-libs/gst/vaapi/gstvaapiutils_core.h: + libs: utils: remove unused function gst_vaapi_get_surface_formats() + +2019-08-01 19:46:17 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapifilter.c: + libs: context, filter: use new surface attributes API + +2019-08-01 19:13:39 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiutils_core.c: + * gst-libs/gst/vaapi/gstvaapiutils_core.h: + libs: utils: add gst_vaapi_config_surface_attributes_get() + To extract the surface restrictions per config using a new structure: + GstVaapiConfigSurfaceAttributes + +2019-07-31 13:08:43 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiutils_core.c: + Split the surface attribute retrieval + +2019-07-15 21:51:46 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: handle navigation downstream event + When navigation events contains coordiantes those have to be mapped + to the new size and/or orientation. + +2019-07-15 21:23:21 +0200 Víctor Manuel Jáquez Leal + + * tests/elements/test-vaapisink.c: + test-vaapisink: also use vaapipostproc to change orientation + +2019-07-15 21:27:20 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapifilter.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + * gst/vaapi/gstvaapipostprocutil.c: + vaapipostproc: handle image-orientation upstream event + Now that vaapipostproc can possible handle video-direction, it + should also handle the image-orientation event from upstream if + video-direction property is set to auto. + +2019-07-26 22:09:37 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: add missing locks when adding flags + +2019-07-26 22:05:29 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: update filter before fixate caps + It is requiered to know if postproc is capable to change the video + direction before fixating the source caps. + In order to do it, it'ss required to know if there's a functional VPP, + but that's checked at create() vmethod, which occurs after caps + fixating. + This patch checks for a functional VPP at fixate caps and, if so, + checks for the enabled filtes and later do the caps fixations. + +2019-07-26 19:46:09 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapivalue.c: + * gst-libs/gst/vaapi/gstvaapivalue.h: + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: element warning if video direction is unsupported + If the video direction is unsupported by the driver, an element + warning is posted in the bus to notify the application. + gst_vaapi_enum_type_get_nick() was added in the library thus it can + be used elsewhere. It retrives the nick from an enum gtype. + +2019-07-26 19:09:54 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapifilter.c: + libs: filter: check mirror and rotation caps only once + This patch locks the display before querying the pipeline caps and + stores the mirror and rotation capabilities, thus they are not queried + every time the video direction is set. + +2019-08-16 19:51:29 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + libs: encoder: vp9: set VP9_0 profile as default + Commit 0afc8131 introduced a regression and only NV12 format were + admitted, failing in any other valid color format. + This patch sets the profile to GST_VAAPI_PROFILE_VP9_0 by default. + +2019-08-16 13:25:06 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapifilter.c: + libs: filter: fail if first color balance value is invalid + +2019-08-06 19:24:08 +0800 Yan Wang + + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + libs: filter: set all color balance values + When set multiple settings of color balance like hue, saturation, + brightness and contrast for vaapipostproc, they should be set as + parameters of color balance filter, at the same color balance + filter calling. + Otherwise, multiple color balance filter calling will cause + previous setting get reset by the last calling with default value. + Fixes #182. + Signed-off-by: Yan Wang + +2019-08-16 11:02:08 +0800 Wangfei + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + libs: h265dec: remove limitation of get iq matrix + According hevc spec, scaling_list_data is not related + to chroma_format_idc. + +2019-05-30 23:52:51 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapivideopool.c: + libs: videopool: fix undocumented behavior and counting + gst_vaapi_video_pool_reserve_unlocked() hit an undocumented behavoir + because it locks twice the same mutex. + Also, n had different meanings in the current code: as an increase + value and as a new total of allocated surfaces. + This patche removes the undocumented behavoir (usually a deadlock) and + fixes the meaning of n as the new total of allocated surfaces. + Signed-off-by: Víctor Manuel Jáquez Leal + +2019-07-17 11:56:45 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiutils.c: + libs: utils: Add missing entries for string_of_VAEntrypoint. + +2019-07-18 22:01:01 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + libs: encoder: Consider vp9 profiles based on input format. + Only support GST_VAAPI_PROFILE_VP9_0 and GST_VAAPI_PROFILE_VP9_2 now. + Fix: #184 + +2019-08-12 18:41:52 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: demote error message to info + The main reason to demote the message's level is because it is not an + error, it's a possible output of the trial and there's a code path + that handles it. + Secondly, it's very annoying when using gallium driver for radeon. + +2019-07-18 13:32:46 +0800 Wangfei + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + * gst-libs/gst/vaapi/gstvaapitypes.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapivalue.c: + libs: encoder: h264: support ICQ/QVBR bitrate control mode + ICQ is Intelligent Constant Quality. It will use the initial QP + vaule of icq-quality-factor to adjust QP at MB level intelligently + to improve subjective quality. + QVBR is Quality defined VBR. It will use qvbr-quality-factor to + adjust QP for each MB to get enough quality picture without waste + of bits. + +2019-08-05 10:51:24 +0800 Wangfei + + * gst-libs/gst/vaapi/gstvaapitypes.h: + libs: Let GST_VAAPI_RATECONTROL_MASK return unsigned int + The value return from GST_VAAPI_RATECONTROL_MASK will be used by + GST_VAAPI_POPCOUNT32 as its inpput. GST_VAAPI_POPCOUNT32 can only + deal with unsigned int. Otherwise there may be an error of out of + range of integer if we define few more rate-control mode. + +2019-06-07 09:54:12 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecodebin.c: + vaapidecodebin: set queue's max size buffers to 1 + Otherwise the queue will swallow all the available decoder's surfaces + reaching a dead-lock. + This setting might impact the bin's peformance, but it's a trade-off. + +2019-06-07 09:53:08 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecodebin.c: + vaapidecodebin: set properties default values + +2019-05-31 13:12:35 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: don't error if can't push buffers downtream + When the code path goes to push buffers downstream when no surface + available in decoder context, and it fails the code bails out with a + fatal error. + That behavior is wrong, since it shouldn't be fatal. The use case is + when the video stream is disabled. + This patch just ignores the errors in this situation and demotes the + level of a log message. + +2019-05-18 13:24:35 +0800 Wangfei + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.h: + libs: encoder: h264,h265: add new property "max-qp" + Add new property "max-qp" to allow set the maximum quantisation + parameter values. + +2019-05-23 10:18:52 -0400 Wangfei + + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + libs: encoder: vp9: add low power mode encode + By now, this feature only support by media-driver on Ice Lake + platform, more information you can reference: + https://github.com/intel/media-driver + +2019-07-15 15:33:07 -0700 U. Artie Eoff + + * gst/vaapi/gstvaapipostprocutil.c: + vaapipostproc: update PAR when rotating + When rotating, swap pixel-aspect-ratio during + negotiation. + Fixes #181 + +2019-07-01 15:26:18 -0700 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + * gst/vaapi/gstvaapipostprocutil.c: + vaapipostproc: add rotation support + Adds vpp rotation support to vaapipostproc. Uses + property video-direction. Default is identity (no + rotation). + Closes #104 + +2019-05-22 10:47:30 -0400 Wangfei + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: pass diff_cu_qp_delta_depth flag to driver + Intel media-driver requires enablement of diff_cu_qp_delta_depth when + cu_qp_delta_enabled_flag enabled. + Fixes: #177 + +2019-07-01 17:02:33 +0800 Wangfei + + * gst-libs/gst/vaapi/gstvaapiutils.c: + libs: encoder: Add MB ratecontrol mode to get its string + +2019-07-01 16:52:00 +0800 Wangfei + + * gst-libs/gst/vaapi/gstvaapiutils.c: + libs: encoder: refine guard of bitrate control mode + Remove useless guard of all bitrate control mode's guard except MB + which is define in VA-API version 0.39.1. + +2019-06-29 00:08:40 +1000 Jan Schmidt + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: Update for parse_vui_params parameter removal. + Update calls to the h264 parser lib for removal of the + parse_vui_params parameter. + +2019-06-24 16:26:56 -0400 Wang Zhanjun + + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + libs: dec: vp9: do not use display size as decoded size + If display size is smaller than current frame size, then the crop size + will be set as display size, which either crashes the pipeline or the + output MD5 does not match. Rather it should use the actual decoded size. + This patch removes the cropping set. For rendering we can use aspect + ratio to set display size. + Fixes #175 + Signed-off-by: Wang Zhanjun + Signed-off-by: Xu Guangxin + +2019-06-28 16:32:51 +0200 Víctor Manuel Jáquez Leal + + * README: + Update README + +2019-06-25 19:11:12 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + * gst-libs/gst/vaapi/gstvaapiutils_h265_priv.h: + libs: dec: h265: Consider chroma_bit_depth to choose chrome type + For some main-10 stream, sometime the luma is 8 bits while chrome is more + than 8 bits, which cause using the wrong NV12 surface as the render target + and decoding error. + Fix #176 + +2019-06-25 10:31:20 +0800 Wangfei + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: set initial decode format according surface chroma type + For surfaces with different chroma type, it is prefer to initialize + a format which chroma type should be same with surface chroma type + instead of using fixed NV12. + +2019-05-30 09:48:51 -0400 Wangfei + + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/video-format.c: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginutil.h: + libs: decoder: jpeg: add support 400/411/422/444 chroma type + When create vaapi surface, it is better to use the chroma type get + from jpeg file instead of using fixed 420 format. And the correct + chroma type can be determined by horizontal_factor/vertical_factor + flags that get from jpegparse. + +2019-06-22 00:05:24 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + libs: dec: h265: Fix profile_idc mapping. + The old mapping values return by gst_vaapi_utils_h265_get_profile_idc is + wrong, though GST_H265_PROFILE_IDC_MAIN and GST_H265_PROFILE_IDC_MAIN_10 + happened to be the correct value. + We only support Annex A profile_idc (1-4). + +2019-06-10 20:46:30 -0700 U. Artie Eoff + + * gst/vaapi/gstvaapipluginbase.c: + plugins: remove last negotiated video info if caps are same + If the allocation caps and negotiated caps are the same, + then ensure any previously negotiated video info is also + removed. This can occur when multi-resolution video + decoding returns to it's original resolution. + Fixes #170 + +2019-06-10 20:39:28 -0700 U. Artie Eoff + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: allow negotiated info to be removed + Allow NULL negotiated_vinfo to be passed into + gst_allocator_set_vaapi_negotiated_video_info to allow + any previously set info to be removed. + +2019-06-06 17:24:30 +0300 Freyr + + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + libs: encoder: vp8,vp9: reset frame_counter when input frame's format changes + When input frame's formate changes, vp{8,9} encoders don't reset their frame + counter, hence the newly created frame could become a P-frame, leading to some + major troubles (sigabrt in libdrm in case of vp9). This patch adds some frame + prediction-related reset logic to the `flush' methods of GstVaapiEncoderVP8 and + GstVaapiEncoderVP9 implementations. + +2019-05-31 12:30:03 -0700 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: increase bitrate prop max value + There are many profile levels that can support + more than 102400 kbps. Thus, increase the max + allowed bitrate property value from 102400 kbps + to 2048000 kbps (same as msdk encoder plugins). + +2019-06-04 13:27:50 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + libs: mpeg2 encoder: No packed header for SPS and PPS + Dislable passing down packed PPS and PPS to driver if driver does + not want it. + Fix: #168 + +2019-05-31 23:10:33 +0200 Niels De Graef + + * configure.ac: + * meson.build: + * tests/output.c: + 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 13:08:39 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + libs: dec: vp9: clear parser pointer after release + Fix an use-after-release of the parser pointer in VP9 decoder. + +2019-05-28 12:09:36 +0300 Freyr666 + + * gst/vaapi/gstvaapiencode.c: + vaapiencode: Fixes deadlock in gst_vaapiencode_change_state function + This fixes a deadlock in gst_vaapiencode_change_state, which was due to + srcpad's chain function was locked waiting for available buffers. Since the + coded buffers in codedbuf_queue become available after sinkpad consume the + encoded frames, Paused -> Ready state change leads to deadlock. Coded buffers + are never consumed and marked free, hence gst_vaapiencode_handle_frame waits for + available buffers and holds the stream_lock of the srcpad. + +2019-05-29 23:08:22 +0200 Mathieu Duponchelle + + * gst-libs/gst/vaapi/gstvaapitypes.h: + * gst/vaapi/gstvaapidecodebin.c: + * gst/vaapi/gstvaapidecodedoc.c: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h264_fei.c: + * gst/vaapi/gstvaapiencode_h265.c: + * gst/vaapi/gstvaapiencode_jpeg.c: + * gst/vaapi/gstvaapiencode_mpeg2.c: + * gst/vaapi/gstvaapiencode_vp8.c: + * gst/vaapi/gstvaapiencode_vp9.c: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + doc: remove xml from comments + +2019-05-13 16:39:33 -0700 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapifilter.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + vaapipostproc: add mirror support + Adds vpp mirroring support to vaapipostproc. Use + property video-direction. Valid values are identity, + horiz or vert. Default is identity (no mirror). + Closes #89 + v2: Use GstVideoOrientationMethod enum + v3: Don't warn for VA_MIRROR_NONE. + Use GST_TYPE_VIDEO_ORIENTATION_METHOD type. + v4: Query VAAPI caps when setting mirror value + instead of during per-frame processing. + v5: Return TRUE in warning cases when setting mirror value. + +2019-05-29 01:35:17 +0200 Mathieu Duponchelle + + * gst-libs/gst/vaapi/gstvaapiutils_x11.c: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11_priv.h: + * gst/vaapi/gstvaapidecodebin.c: + * gst/vaapi/gstvaapisink.c: + doc: fix some incorrect gtk-doc links + +2019-05-16 09:22:42 -0400 Thibault Saunier + + * docs/gst_plugins_cache.json: + docs: Update plugin cache + Fixes https://gitlab.freedesktop.org/gstreamer/gst-docs/issues/36 + +2019-05-16 16:46:43 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapisurface.h: + libs: surface: fix documentation format + +2019-05-16 10:05:17 +0800 Wangfei + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: enc: h265: reset num_ref_idx_l1_active_minus1 when low delay B. + When enable low delay B, the reference list 1 will be same with + reference list 0, so need reset the num_ref_idx_l1_active_minus1 + to num_ref_idx_l0_active_minus1. + Fixes: #160 + +2019-05-13 19:05:43 -0400 Thibault Saunier + + * docs/meson.build: + meson: Fix call to wrong function + +2018-10-22 11:48:29 +0200 Thibault Saunier + + * Makefile.am: + * configure.ac: + * docs/Makefile.am: + * docs/gst_plugins_cache.json: + * docs/index.md: + * docs/meson.build: + * docs/plugins/Makefile.am: + * docs/plugins/gstreamer-vaapi-plugins-docs.xml.in: + * docs/plugins/gstreamer-vaapi-plugins-sections.txt: + * docs/plugins/gstreamer-vaapi-plugins.types: + * docs/plugins/inspect/plugin-vaapi.xml: + * docs/plugins/running.xml: + * docs/sitemap.txt: + * docs/version.entities.in: + * gst/vaapi/meson.build: + * meson.build: + * meson_options.txt: + docs: Port to hotdoc + +2019-05-10 18:29:10 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: not call ensure_num_slices inside g_assert + g_assert will take no effect when glib's G_DISABLE_ASSERT macro is + defined. The function inside the g_assert will take no effect and + we will fail to set the correct slice number. + +2019-04-29 09:52:39 +0800 Wangfei + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + libs: h265: dec: Add extension flags setting. + Use VAPictureParameterBufferHEVCExtension& + VASliceParameterBufferHEVCExtension to pass extension setting from + some extension profile clips which may include these information. + The hevc extension setting only supported after libva release 2.2.0 + (API 1.2.0). + +2019-05-01 12:56:55 -0700 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + libs: encoder: add target-percentage property + Allow users to set the target-percentage for + variable rate controls. The default value is + 70 (as hard-coded prior). + v2: minimum allowed value changed from 0 to 1 + v3: target-percentage unchanged if CBR used + Resolves #129 + +2019-05-09 00:09:21 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder.h: + libs: encoder: Add a missing comment for DEFAULT_ROI_VALUE property. + +2019-05-08 23:39:20 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_objects.h: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + libs: encoder: Enable trellis quantization method. + The advanced trellis algorithm is supported in VA driver. We add + its support as a property named "trellis" of encoder. + It only works for H264 now, should be more in future. + +2019-05-07 11:03:51 +0800 Wangfei + + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + libs: decoder: vp9: support 422/444 8bit/10bit chroma type. + According to the vp9 sepc, profile 1/3 support 422/440/444 chroma + type, so we need to add subsampling_x&subsampling_y to fix it. + Here is the relationship between chroma type and profile and + subsampling_x&subsampling_y according to vp9 spec: + ------------------------------------------ + Profile | Bit depth | Chroma subsampling | + ------------------------------------------ + 0 | 8 | 420 | + ------------------------------------------ + 1 | 8 | 422,440,444 | + ------------------------------------------ + 2 | 10, 12 | 420 | + ------------------------------------------ + 3 | 10, 12 | 422,440,444 | + ------------------------------------------ + ----------------------------------------------- + Subsampling_x | Subsampling_y | Chroma format | + ----------------------------------------------- + 0 | 0 | 444 | + ----------------------------------------------- + 0 | 1 | 440 | + ----------------------------------------------- + 1 | 0 | 422 | + ----------------------------------------------- + 1 | 1 | 420 | + ----------------------------------------------- + +2019-04-16 18:33:54 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/video-format.c: + libs: Add packed 24 RGB format support. + Can not find a suitable chrome_type for this GST_VIDEO_FORMAT_RGB + packed 24 format. Just use GST_VAAPI_CHROMA_TYPE_RGB32 as its chrome + type. This kind of surface will just be created by new API with fourcc + and no old style chrome based creation is available. + fixes: #151 + +2019-03-15 14:29:41 +0800 Wangfei + + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h264_fei.c: + * gst/vaapi/gstvaapiencode_h265.c: + * gst/vaapi/gstvaapiencode_jpeg.c: + * gst/vaapi/gstvaapiencode_mpeg2.c: + * gst/vaapi/gstvaapiencode_vp8.c: + * gst/vaapi/gstvaapiencode_vp9.c: + vaapiencode: handle DMABuf caps feature in sink pad + Add DMABuff caps features in all encoders' sink pad. + +2019-05-03 10:31:52 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: continue if roi meta is NULL + Coverity scan bug: + If the function actually returns a null value, a null pointer + dereference will occur. + In gst_vaapi_encoder_ensure_param_roi_regions(): Return value of + function which returns null is dereferenced without checking + +2019-04-15 19:58:14 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + lib: decoder: vp9: Set chroma_type by VP9 bit_depth + The decoder's surface chroma type should depend on the bit depth + of VP9's parser. For 10bits VP9 stream, we need to use P10LE kind + 10 bits surface as the decoder result. + Fixes #155 + +2019-05-02 16:00:57 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostprocutil.c: + vaapipostproc: don't do any color conversion when GL_TEXTURE_UPLOAD + https://bugzilla.gnome.org/show_bug.cgi?id=748184 has resurrected + with commit 3e992d8a + Since gst_vaapi_find_preferred_caps_feature() returns a color format + from caps negotiation, different from the default one (NV12), the + postproc enables the color transformation. But when GL_TEXTURE_UPLOAD + feature is negotiated, no color transformation shall be done. + Nonetheless, with commit 3e992d8a the requested format changes + firstly, because there's no video sink yet, so ANY caps are + negotiated; but later, when there's a video sink and a caps + renegotiation, the GL_TEXTURE_UPLOAD is negotiated though the color + format conversion still ongoing. It is required to reset that + conversion. + This patch force default color format when GL_TEXTURE_UPLOAD is + selected as preferred, thus avoiding the color conversion. + Fixes: #157 + +2019-04-19 15:49:37 -0700 Julien Isorce + + * gst-libs/gst/vaapi/gstvaapisurface_drm.c: + libs: surface: fix double free when dmabuf export fails + Happens if vaAcquireBufferHandle fails. + +2019-04-29 20:10:39 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + libs: h264encoder: fix a typo of GstVaapiEncoderH264PredictionType + +2019-04-19 10:43:35 +0100 Tim-Philipp Müller + + * RELEASE: + * configure.ac: + * docs/plugins/inspect/plugin-vaapi.xml: + * meson.build: + Back to development + +=== release 1.16.0 === + +2019-04-19 00:38:12 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gstreamer-vaapi.doap: + * meson.build: + Release 1.16.0 + +2019-04-19 00:38:12 +0100 Tim-Philipp Müller + + * docs/plugins/inspect/plugin-vaapi.xml: + Update docs + +2019-04-15 19:34:05 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h264,h265: guard VA version for max_qp property + This patch fixes a regression from commit 5b1fe9c6. + max_qp, in rate control configuration, appeared in libva release + 2.1 (API 1.1), thus it is required to guard the VA API version. + Fixes: #150 + +2019-04-08 18:29:35 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/video-format.c: + libs: Add RGB565 image format support. + +2019-04-10 13:59:05 +0200 Víctor Manuel Jáquez Leal + + * configure.ac: + build: configure: delay USE_GTK conditional until check libva-x11 + libva-x11 is used for X11 applications, so it is required to build + any GTK application. + Later, when Wayland test is added, we should change this. + +2019-04-10 13:25:10 +0200 Víctor Manuel Jáquez Leal + + * configure.ac: + build: configure: disable GLX if libva-x11 is not found + +2019-04-15 13:55:26 +0200 He Junyan + + * gst-libs/gst/vaapi/gstvaapiutils.c: + libs: utils: avoid macro evaluation when stringify + string_of_va_chroma_format() gets a wrong string format description. + For example, the YUV420_10BPP get a string of 0x00000100 as output. + It's because VA_RT_FORMAT_xxx values are macro definitions. And + STRINGIFY(VA_RT_FORMAT_xxx) will expand to its real value + 0x00000XXX. + To avoid the macro evaluation, it is changed to show only the color + format without VA_RT_FORMAT_ prefix. + +2019-04-15 13:54:15 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiutils.c: + libs: utils: use glib's macros + Don't reinvent the wheel. + +2019-04-11 15:05:02 +0800 Wangfei + + * gst/vaapi/gstvaapipluginutil.c: + plugins: find the preferred format from right caps. + When the downstream has any caps, then raw video feature will + be used. At this situation, the preferred format should be chose + from caps which contains "vide/x-raw" feature instead of from + the fist allowed caps. + Fixes #142 + +2019-04-10 11:43:33 -0700 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: fill tier in va seq param buf + Now that tier is calculated in commit 58e74f9440fe (!68), + ensure we fill in the general_tier_flag in the + VAEncSequenceParameterBufferHEVC. + +=== release 1.15.90 === + +2019-04-11 00:40:03 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gstreamer-vaapi.doap: + * meson.build: + Release 1.15.90 + +2019-04-11 00:40:03 +0100 Tim-Philipp Müller + + * docs/plugins/inspect/plugin-vaapi.xml: + Update docs + +2019-04-09 20:42:04 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: Recognize the correct level and tier. + The current manner can not recognize the correct level and always + set the tier to main. Need to add frame rate check to recognize + levels such as 4.1, 6.2, etc. We also add a logic to check main + and high tier based on bitrate. + Fixes: #145 + +2019-04-03 14:12:23 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h264,h265: Set max_qp if min_qp is non-zero. + media-driver currently fails to set a correct value of max_qp when + min_qp is different to zero, in CBR and VBR mode, generating full + quality frames, thus unexpected huge output. + This patch sets max_qp to an arbitrary value to avoid this output + temporary. + Fixes: #144 + +2019-04-09 12:42:56 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h264,h265: initial and minimal QP can be zero + Currently the minimal value for either min_qp and init_qp are 1, + but VA documentation specifiy that zero is also valid and means + to ignore the quantiser. + The default value is not changed though to avoid behaivor changes + to users. + +2019-04-09 09:20:23 +0800 Haihao Xiang + + * tests/elements/meson.build: + meson: build test-vaapicontext when using X11 + x11_dep and libva_x11_dep are optional and meson ignores these + dependencies even if they are added into the dependency list. + This fixes the error below when libva-x11 is not avaiblabe: + cc -Itests/elements/tests@elements@@test-vaapicontext@exe + -Itests/elements -I../../gstreamer-vaapi/tests/elements -I. + -I../../gstreamer-vaapi/ -Igst-libs -I../../gstreamer-vaapi/gst-libs + -I/usr/include/gstreamer-1.0 -I/usr/include/glib-2.0 + -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/orc-0.4 + -I/usr/include/at-spi2-atk/2.0 -I/usr/include/at-spi-2.0 + -I/usr/include/dbus-1.0 -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include + -I/usr/include/gtk-3.0 -I/usr/include/gio-unix-2.0/ + -I/usr/include/libdrm -I/usr/include/harfbuzz -I/usr/include/pango-1.0 + -I/usr/include/fribidi -I/usr/include/atk-1.0 -I/usr/include/cairo + -I/usr/include/pixman-1 -I/usr/include/uuid -I/usr/include/freetype2 + -I/usr/include/libpng16 -I/usr/include/gdk-pixbuf-2.0 + -fdiagnostics-color=always -pipe -D_FILE_OFFSET_BITS=64 -Wall + -Winvalid-pch -O2 -g -fvisibility=hidden -fno-strict-aliasing -pthread + -DHAVE_CONFIG_H -MD -MQ + 'tests/elements/tests@elements@@test-vaapicontext@exe/test-vaapicontext.c.o' + -MF + 'tests/elements/tests@elements@@test-vaapicontext@exe/test-vaapicontext.c.o.d' + -o + 'tests/elements/tests@elements@@test-vaapicontext@exe/test-vaapicontext.c.o' + -c ../../gstreamer-vaapi/tests/elements/test-vaapicontext.c + ../../gstreamer-vaapi/tests/elements/test-vaapicontext.c:29:10: fatal + error: va/va_x11.h: No such file or directory + #include + +2019-04-01 12:56:28 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + * gst-libs/gst/vaapi/gstvaapifeienc_h264.c: + * gst-libs/gst/vaapi/gstvaapifeipak_h264.c: + libs: encoder: h264_fei: Use gst_param_spec_array for view-ids + GValueArray is deprecated. Use GstValueArray instead. + +2019-03-30 18:29:31 +0100 Danilo Spinella + + * gst/vaapi/gstvaapipluginutil.c: + vaapipluginutil: Fix #endif for USE_X11 + +2019-03-29 18:29:51 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + libs: encoder: h264: simplify the view-ids setting + +2019-03-26 14:54:47 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + libs: encoder: h264: Use gst_param_spec_array for view-ids + GValueArray is deprecated. Use GstValueArray instead. + gst_param_spec_array can be deserialized from command line using: + vaapih264enc view-ids="<(uint)40,(uint)100>" num-views=2 + While the g_param_spec_value_array() can not, and always get + error: "gst_value_deserialize_g_value_array: unimplemented" + Also fixed an out-of-range bug. + +2019-03-29 13:33:41 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapiencoder_objects.c: + libs: Change the parameter setting order when encode picture. + The order in gst_vaapi_enc_picture_encode when encoding one + picture is not very correct. The misc parameters are set before + the picture parameters. Some of the misc parameters such as + ROI may change the current picture parameters. But the later + setting of picture parameter will re-init all picture related + parameters and clear the previous setting. The right order + should be picture parameter first and then misc parameters. + Signed-off-by: He Junyan + +2019-03-26 14:20:34 +0800 Wangfei + + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + libs: decoder: jpeg: support dynamic resolution change decode. + Add size_changed flag to watch out resolution. if change, reset + jpeg decoder's context. + +2019-03-23 15:34:03 +0800 Wangfei + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: add low power mode encode. + By now, this feature only support by media-driver on Ice Lake + platform, more information you can reference: + https://github.com/intel/media-driver + +2019-03-15 18:40:21 +0800 He Junyan + + * gst/vaapi/gstvaapiencode.c: + vaapiencode: gobject's prop_id differ from vaapi encoder + The vaapi internal encoder's property id are negative, thus they are + different from GObject's property ids. + gst_vaapi_encoder_set_property() should map to the internal encoder + property id, assigned in gst_vaapiencode_default_set_property(). + +2019-03-21 16:56:34 +0000 Tim-Philipp Müller + + * meson.build: + meson: disable compiler warnings for unused vars and args if gst debug system is disabled + +2019-03-21 13:31:57 +0000 Tim-Philipp Müller + + * meson.build: + meson: use new 'python' module instead of deprecated 'python3' one + +2019-03-11 18:38:36 -0300 Thibault Saunier + + * common: + Update common submodule back to 59cb678164719ff59dcf6c8b93df4617a1075d11 + It was wrongly changed in 3d9555a86d45565870c684fe00ec8bbb0fed7205 + +2019-03-04 09:16:17 +0000 Tim-Philipp Müller + + * NEWS: + * RELEASE: + * configure.ac: + * docs/plugins/inspect/plugin-vaapi.xml: + * meson.build: + Back to development + +2019-03-01 12:33:26 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + libs: Fix a typo in comments. + Fix a typo in function description of + gst_vaapi_surface_pool_new_with_chroma_type. + Signed-off-by: He Junyan + +2019-02-27 13:02:10 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + plugin: if any caps in downstream, negotiate raw video + When downstream has any caps, vaapi should not shovel vaapi featured + buffers, but rather plain raw video, assuming always the worst case + scenario (downstream cannot handle featured video memory but raw + system memory buffers). + This patch query the peer caps without any filter, to know if + donwstream just ask for any caps, if so jump to the color space + checking, otherwise do the caps intersection and continue with the + feature selection algorithm. + Fixes: #139 + +=== release 1.15.2 === + +2019-02-26 12:01:53 +0000 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gstreamer-vaapi.doap: + * meson.build: + Release 1.15.2 + +2019-02-26 12:01:53 +0000 Tim-Philipp Müller + + * docs/plugins/inspect/plugin-vaapi.xml: + Update docs + +2019-02-05 16:59:40 +0800 He Junyan + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: Prefer same format for surface and image + We prefer to use the same format between image and surface for gst + vaapi allocator. The old way may choose different formats between + image and surface. For example, the RGBA image may have a NV12 surface. + So we need to do format conversion when we put/get image to surface. + Some drivers such as iHD can not support such conversion and always + cause a data flow error. There may also have some performance cost + for format conversion when put/get images. + So we prefer to use the same format for image and surface in the + allocator. If the surface can not support that format, we then + fallback to find a best one as the surface format. + Co-authored-by: Víctor Jáquez + +2019-02-15 15:19:51 +0800 He Junyan + + * gst-libs/gst/vaapi/video-format.c: + libs: Delete the duplicated ARGB video format. + Two ARGB formats with the same format information. + Should be verbose and delete one. + Signed-off-by: He Junyan + +2019-02-13 10:39:59 -0500 Adam Jackson + + * common: + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + glx: Stop specifying GLX_DEPTH_SIZE + This code is just confused. It's asking for at least as many bits of + (z-axis) depth as the root window has bits of (color) depth. For rgb565 + or rgb888 this is harmless, but at 10 bits per channel this demands a + 30-bit or deeper Z buffer. While some hardware could in principle do a + 32-bit Z buffer, Mesa does not expose such fbconfigs (at least on Intel + and AMD). + We're not actually using the Z buffer, so just stop asking for one. + +2019-01-14 11:30:48 +0100 Niels De Graef + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + * gst-libs/gst/vaapi/meson.build: + * gst/vaapi/gstvaapisink.c: + * meson.build: + libs: wayland: add support for XDG-shell protocol + [wl_shell] is officially [deprecated], so provide support for the + XDG-shell protocol should be provided by all desktop-like compositors. + (In case they don't, we can of course fall back to wl_shell). + Note that the XML file is directly provided by the `wayland-protocols` + dependency and generates the protocol marshalling code. + [wl_shell]: https://people.freedesktop.org/~whot/wayland-doxygen/wayland/Client/group__iface__wl__shell.html + [deprecated]: https://github.com/wayland-project/wayland/commit/698dde195837f3d0844b2725ba4ea8ce9ee7518c + +2019-02-16 19:09:50 +0100 Niels De Graef + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + libs: window: wayland: Prefix wl_shell_surface field with `wl_` + It will help us to distinguish from other Wayland shell surface + (such as XDG-shell) later on. + +2019-01-14 09:58:19 +0100 Niels De Graef + + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + libs: wayland: Prefix wl_shell field with `wl_` + It will help us to distinguish from other Wayland shells (such as + XDG-shell) later on. + +2019-02-08 09:21:28 +0300 Denis Nagorny + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + libs: display: lock ensure_profile() + Thread safety patch for ensure_profile() function + Fixes #133 + +2019-02-08 16:35:39 +0100 Víctor Manuel Jáquez Leal + + * meson.build: + meson: bump the minimum wayland version requirement to 1.11.0 + This was missed on commit 77bb3424 + +2019-01-24 21:08:07 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst/vaapi/gstvaapisink.c: + vaapisink: x11: trap WM_DELETE_WINDOW message + Register the WM_DELETE_WINDOW message from window manager and + trap it to stop the pipeline cleanly. + Fixes: https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi/issues/130 + +2019-01-21 19:22:58 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiwindow.c: + libs: window: remove native-id property + native-id property is problematic since the variable that stores it is + gsize, which is platform specific, and in some is bigger than unsigned + long, and there are not way to handle gsize properties. + Also, GST_VAAPI_ID_INVALID is defined in gsize terms, and we would + like to keep using it for this scope. + This patch removes the native-id property and set it manually in + gst_vaapi_window_new_internal(). + +2019-01-18 10:33:37 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiwindow.c: + libs: window: use G_GSIZE_MODIFIER for window id + gsize type is not equal in all platforms, then the 'l' print modifier + shall not be used always. + This issue was found in Debian builds. + +2019-01-17 10:27:13 +0800 Wangfei + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + encoder: h264/h265: set SPS cbr_flag with correct value. + The flag only set as 1 when the rate-control mode is CBR. + +=== release 1.15.1 === + +2019-01-17 02:36:52 +0000 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gstreamer-vaapi.doap: + * meson.build: + Release 1.15.1 + +2019-01-17 02:36:52 +0000 Tim-Philipp Müller + + * docs/plugins/inspect/plugin-vaapi.xml: + Update docs + +2019-01-14 19:35:34 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: refactor to avoid code duplication + gst_vaapi_encoder_put_frame() and gst_vaapi_encoder_flush() duplicates + the same code segment where the coded buffer is created, the picture + encoded on it and pushed to the async queue. + The function gst_vaapi_encoder_encode_and_queue() refactor this. + +2019-01-14 18:21:30 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + libs: encoder: h264/h265: flush pending ordered pictures + In order to flush the pending pictures, a new internal encoder vmethod + is used: get_pending_reordered() + This method follows an iterator pattern which will return the next + picture to encode and push. + The base encoder will call this function in a loop when flush() is called. + For now, only H.264 and H.265 encoders implement this flushing mechanism. + +2018-12-06 10:18:53 +0800 Wangfei + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h264/h265: fix encode lose frame issue. + Instead of dropping all remain frames in reorder_frame_list during + flush, keep encoding. + https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi/issues/97 + +2019-01-15 14:33:11 +0800 Wangfei + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: before set surface proxy, check if it already been created and exist. + Fix the deinterlace black frame when playing with glimagesink: + gst-launch-1.0 filesrc location=test.264 ! h264parse ! vaapih264dec \ + ! vaapipostproc deinterlace-mode=1 deinterlace-method=1 ! glimagesink + +2019-01-11 13:48:29 +0800 Wangfei + + * gst-libs/gst/vaapi/gstvaapiutils.c: + vaapipostproc: clean up USE_VA_VPP macro since it already removed from configure file. + +2018-12-26 14:36:23 +0800 Haihao Xiang + + * gst-libs/gst/vaapi/meson.build: + * gst/vaapi/meson.build: + * meson.build: + * tests/meson.build: + meson: build h264 fei encoder if possible + +2018-12-26 14:04:08 +0800 Haihao Xiang + + * configure.ac: + configure: bump the minimum wayland version requirement to 1.11.0 + +2018-12-24 12:58:53 +0800 Haihao Xiang + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapibufferproxy.c: + * gst-libs/gst/vaapi/gstvaapibufferproxy_priv.h: + * gst-libs/gst/vaapi/gstvaapicodec_objects.c: + * gst-libs/gst/vaapi/gstvaapicompat.h: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapiencoder_objects.c: + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils_core.c: + * gst-libs/gst/vaapi/meson.build: + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecodebin.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/meson.build: + * meson.build: + * tests/decoder.c: + * tests/simple-decoder.c: + vaapi: bump the minimum vaapi version requirement to 0.39.0 + And reduce unnecessary API version and structures check as well. + https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi/issues/108 + +2018-12-22 18:07:35 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * tests/test-decode.c: + * tests/test-filter.c: + * tests/test-subpicture.c: + * tests/test-textures.c: + * tests/test-windows.c: + libs: window: remove custom ref() and unref() + Use gst_object_ref() and gst_object_unref() instead. + +2018-12-22 13:25:09 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow_drm.c: + * gst-libs/gst/vaapi/gstvaapiwindow_egl.c: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + libs: window: use its own debug category + +2018-12-22 18:02:38 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_drm.c: + * gst-libs/gst/vaapi/gstvaapiwindow_drm.h: + * gst-libs/gst/vaapi/gstvaapiwindow_egl.c: + * gst-libs/gst/vaapi/gstvaapiwindow_egl.h: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.h: + * gst-libs/gst/vaapi/gstvaapiwindow_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11_priv.h: + libs: window: refactor as gobject + This is another step in the gobjectification of the internal library + of gstreamer-vaapi. Now it is the turn of GstVaapiWindow and its + derivates. + The idea is to minimize the changeset keeping the same design as + much as possible. + GstVaapiWindow is defined as an abstract class with two properties: + the GstVaapiDisplay and the native ID. Thus, many of the + GstVaapiObject macros were copied as GstVaapiWindow macros. + The function gst_vaapi_window_new_internal() is kept as a decorator + of for calling gst_vaapi_window_create() and the possibility of + failure. + The descendant classes, such as glx, still use the private + structures, but through the gobject mechanism. + +2018-12-03 22:05:29 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapifilter.c: + libs: filter: use its own debug category + +2018-12-24 14:08:42 +0800 He Junyan + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + plugins: Add more check for allowed raw caps. + The gst_vaapi_plugin_base_get_allowed_raw_caps is used for both sink + pad and src pad, which cause some bugs. For sink pad, we need to verify + vaPutImage() while for the src pad we need to verify vaGetImage(). + For vaapidecoderXXX kind of plugins, the case is more complex. We need + to verify whether the decoded result(in some surface, NV12 format most + of the time) can be vaGetImage to some raw image format. Add more check + to fix all these problems. + https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi/issues/123 + Signed-off-by: He Junyan + +2018-12-18 10:44:21 +0800 Wangfei + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: fix csc fail when only change width or height. + +2018-12-15 09:47:15 +0900 Wonchul Lee + + * tests/elements/meson.build: + meson: Add gtk guard + +2018-12-15 14:48:03 +0800 Wangfei + + * gst/vaapi/gstvaapiencode_h264.c: + libs: enc: h264: set max profile idc with correct profile. + Use the highest rank of available profile as the max profile to + set max idc value. + https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi/issues/124 + +2018-12-03 13:56:52 +0100 Niels De Graef + + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + Use G_DEFINE_TYPE_WITH_PRIVATE if applicable + This gets rid of the strange `do_init` macro and makes the intent a bit + more clear. + +2018-12-05 17:24:53 -0300 Thibault Saunier + + * common: + Automatic update of common submodule + From ed78bee to 59cb678 + +2018-11-27 09:47:44 -0500 Wangfei + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + * gst-libs/gst/vaapi/video-format.c: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginutil.h: + libs: dec: h265: support decode for main-444 10bit streams. + Add 444 10bit yuv format Y410, which can be used to decode + main-444 10bit streams. Currently, this feature is only + supported by media-driver in Icelake. + +2018-11-28 05:56:44 +0200 Jordan Petridis + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapisink.c: + Run gst-indent through the files + This is required before we enabled an indent test in the CI. + https://gitlab.freedesktop.org/gstreamer/gstreamer-project/issues/33 + +2018-11-14 13:11:56 +0800 He Junyan + + * gst/vaapi/gstvaapipluginbase.c: + plugins: modify image check of extract_allowed_surface_formats. + The extract_allowed_surface_formats function just check whether + we can support some kind of surface/image format pair. We just + need to create a surface, create an image with the same video-format + and putImage from image to surface. All these operations success, + that kind of video-format is supported. + The old manner do not work for some kind of video-format. For example, + the RGBA kind of format will create a NV12 surface and RGBA image, + and the putImage will fail because the format is not same. And so + the RGBA format is not supported but actually it is supported. + +2018-11-14 11:34:20 +0100 Michael Olbrich + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: add some missing locking + gst_vaapi_plugin_base_close() removed the raw caps that are used indirectly + in gst_vaapipostproc_transform_caps(). The usage is already protected by + the mutex. + This is needed when the pipeline is stopped during startup. + +2018-11-20 16:07:44 +0800 Xiang, Haihao + + * gst/vaapi/gstvaapivideomemory.c: + Close dmabuf_fd + Otherwise it will result in resource leak when failed to create + dmabuf memory + +2018-11-12 13:39:51 +0100 Michael Olbrich + + * gst/vaapi/gstvaapiencode.c: + vaapiencode: don't start src pad task in set_format + Otherwise the task may be restarted during shutdown. Start the task in + gst_vaapiencode_handle_frame() instead. + +2018-11-14 13:52:48 +0800 Wangfei + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginutil.h: + libs: dec: h265: support decode for main-444 8bit streams. + Add 444 8bit yuv format AYUV, which can be used to decode + main-444 8bit streams. Currently, this feature is only + supported by media-driver in Icelake. + https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi/issues/119 + +2018-11-12 17:43:54 +0100 Víctor Manuel Jáquez Leal + + * .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-09 22:03:43 +0800 He Junyan + + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + libs: Sync the GstVaapiChromaType to VA header file. + Add more kinds of chrometype which will be used to describe + new video formats. Sync it with 1.4.0 version header file. + Alse delete useless GST_VAAPI_CHROMA_TYPE_YUV410 chrome type. + Signed-off-by: He Junyan + +2018-11-09 23:55:05 +0000 Tim-Philipp Müller + + * gst-libs/gst/vaapi/meson.build: + meson: link with -lm + Fixes #117 hopefully. + +2018-11-09 23:46:53 +0000 Tim-Philipp Müller + + * meson.build: + meson: bump meson required to 0.47 for feature options + +2018-11-06 14:38:08 +0800 Junyan He + + * gst-libs/gst/vaapi/video-format.c: + libs: Modify the video format of endianness. + We lack some video format because endianness declare. + The video format should not directly relate to endianness. For example, + ARGB on big endian should not be simplely seen as BGRA on little endian + machine. We should provide endianess convert or format convert help + functions if endianness does not match. + https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi/issues/112 + Signed-off-by: Junyan He + +2018-10-17 18:36:52 +0800 Junyan He + + * gst/vaapi/gstvaapipluginutil.c: + plugins: Fix build error when GL is enabled while EGL is disabled. + gl_platform_type in gst_vaapi_get_display_type_from_gl_env generate + unused-variable warning and may block build when Werror enabled. + Several functions like gst_vaapi_display_egl_new_with_native_display + have no prototype warning and link error when GL is enabled but EGL + is disabled. Fix all these warning and link error. + https://bugzilla.gnome.org/show_bug.cgi?id=797358 + Signed-off-by: Junyan He + +2018-11-03 15:06:09 +0800 Wangfei + + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + * gst-libs/gst/vaapi/gstvaapifeienc_h264.c: + libs: encoder: h264/h264fei: remove unuseless code. + The variable are set twice, remove previous one. + https://bugzilla.gnome.org/show_bug.cgi?id=797365 + +2018-11-03 15:28:35 +0800 Wangfei + + * tests/simple-encoder.c: + * tests/test-fei-enc-in.c: + tests: check return value when using gst_buffer_map. + https://bugzilla.gnome.org/show_bug.cgi?id=797366 + +2018-11-02 16:50:47 +0100 Víctor Manuel Jáquez Leal + + * meson.build: + * meson_options.txt: + * tests/elements/meson.build: + * tests/meson.build: + build: meson: build examples + +2018-11-02 16:50:00 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/meson.build: + build: meson: declare headers for libgstvaapi + Thus handling its recompilation if needed. + +2018-11-05 05:41:13 +0000 Matthew Waters + + * .gitmodules: + Update common submodule location + Remove the git directory + +2018-11-05 13:00:28 +0800 Haihao Xiang + + * .gitmodules: + * gstreamer-vaapi.doap: + Clone the code from gitlab + This fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi/issues/116 + +2018-10-24 14:18:37 -0400 Wangfei + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + * gst-libs/gst/vaapi/video-format.c: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginutil.h: + libs: dec: h265: support decode for main-10-422 10bit streams. + Add 422 10bit yuv format Y210, which can be used to decode + main-10-422 10bit streams. Currently, this feature is only + supported by media-driver in Icelake. + https://bugzilla.gnome.org/show_bug.cgi?id=797264 + +2018-10-13 15:00:32 +0800 Wangfei + + * gst-libs/gst/vaapi/gstvaapicontext.c: + libs: context: roi_rc_qp_delta_support should not be checked when CQP. + VA_ROI_RC_QP_DELTA_SUPPORT return value will be ignored when the + rate control mode is set as CQP. In CQP mode, it shouldn't check + roi_rc_qp_delta_support return value from driver backend. + https://bugzilla.gnome.org/show_bug.cgi?id=797087 + +2018-10-15 17:55:24 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: fix classification string + The classification string is splitted by '/' and then looks for the + components. + This patch removes the ';' by unifying all the components. + +2018-10-15 16:05:02 +0100 Philippe Normand + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: Add Hardware classifier to metadata + +2018-10-12 16:37:34 +0800 Wangfei + + * gst-libs/gst/vaapi/gstvaapicontext.c: + libs: context: create context first before using it to create surface. + In gst_vaapi_context_reset(), if the context has to be destroyed, make + sure to create it first before allocating its associated surfaces. + This patch fixes a regression introduced in commit 82872f4 because + the formats available in the current context now are ensured before + creating the context's surfaces. + https://bugzilla.gnome.org/show_bug.cgi?id=797277 + +2018-10-12 15:39:53 +0100 Philippe Normand + + * docs/plugins/inspect/plugin-vaapi.xml: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h264_fei.c: + * gst/vaapi/gstvaapiencode_h265.c: + * gst/vaapi/gstvaapiencode_jpeg.c: + * gst/vaapi/gstvaapiencode_mpeg2.c: + * gst/vaapi/gstvaapiencode_vp8.c: + * gst/vaapi/gstvaapiencode_vp9.c: + gst: Advertise elements interacting with hardware devices + +2018-10-01 09:26:05 +0800 Wangfei + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + libs: context: query surface format before context to create surface. + Before using context to create surface, the supported surface format + should be checked first. + https://bugzilla.gnome.org/show_bug.cgi?id=797222 + +2018-10-09 17:23:55 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapivalue.c: + libs: replace g_error with GST_ERROR + And handle those errors rather than halting. + +2018-10-09 17:23:30 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + libs: replace g_warning with GST_WARNING + +2018-09-26 14:55:32 -0500 Matteo Valdina + + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + * gst-libs/gst/vaapi/gstvaapiutils_h264.c: + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + * gst-libs/gst/vaapi/gstvaapiutils_mpeg2.c: + libs: Move from g_debug to GST_DEBUG. + https://bugzilla.gnome.org/show_bug.cgi?id=797202 + +2018-10-04 02:20:10 +0800 Soon, Thean Siew + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: change the way of handling deinterlace + The current vaapipostproc calls driver's video processing + pipeline for deinterlacing only if it is Advance deinterlacing. + Modify in the way that it always tries with driver's video + processing pipeline for deinterlacing, and falls back to software + method of appending picture structure meta data only if it fails + with driver's method. + https://bugzilla.gnome.org/show_bug.cgi?id=797095 + +2018-09-24 16:54:29 -0500 Matteo Valdina + + * gst-libs/gst/vaapi/gstvaapiutils_h264.c: + * gst-libs/gst/vaapi/gstvaapiutils_h264.h: + libs: h264: Update level table to "Recommendation H.264 (04/17)". + Added level 6, 6.1 and 6.2. Reference Table A-1 – Level limits + from T-REC-H.264-201704. + https://bugzilla.gnome.org/show_bug.cgi?id=797202 + +2018-09-20 09:57:33 +0800 Wangfei + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + * gst-libs/gst/vaapi/gstvaapiutils_h265_priv.h: + * gst-libs/gst/vaapi/video-format.c: + * gst-libs/gst/vaapi/video-format.h: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginutil.h: + libs: dec: h265: add 422 chroma format support. + Add main-422-10 profile which support 422 chroma format stream. + Currently, this feature is only supported by media-driver in Icelake. + https://bugzilla.gnome.org/show_bug.cgi?id=797143 + +2018-09-26 19:34:06 +0200 U. Artie Eoff + + * tests/y4mreader.c: + tests: include sysdeps.h in compilation unit + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=797204 + Signed-off-by: U. Artie Eoff + +2018-09-26 18:04:53 +0200 Víctor Manuel Jáquez Leal + + * tests/y4mreader.c: + * tests/y4mreader.h: + tests: fix compilation + https://bugzilla.gnome.org/show_bug.cgi?id=797204 + +2018-09-25 20:28:02 +0200 Víctor Manuel Jáquez Leal + + * tests/y4mreader.h: + tests: don's use sysdeps.h in header + +2018-09-14 19:30:56 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiutils.h: + libs: utils: no need of include config.h + +2018-09-13 18:12:02 +0200 Víctor Manuel Jáquez Leal + + * tests/decoder.c: + * tests/output.c: + * tests/test-decode.c: + * tests/test-subpicture.c: + tests: remove already include string.h + Since sysdeps.h includes string.h there's no need to include it again. + +2018-09-13 18:11:25 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapicodec_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + libs: remove already include string.h + Since sysdeps.h includes string.h there's no need to include it again. + +2018-09-13 18:26:27 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiobject.h: + * gst-libs/gst/vaapi/gstvaapiobject_priv.h: + * gst/vaapi/gstvaapivideometa_texture.c: + libs: object: separation of internal API and plugins + Removed exposed macros GST_VAAPI_OBJECT_DISPLAY() and + GST_VAAPI_OBJECT_ID() to plugins, keeping them only for internal + library usage. + The purpose is readability. + https://bugzilla.gnome.org/show_bug.cgi?id=797139 + +2018-09-13 16:34:54 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiparser_frame.h: + libs: parser_frame: change macros for inlined functions + https://bugzilla.gnome.org/show_bug.cgi?id=797139 + +2018-09-13 16:10:13 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapicodedbufferproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapivideopool.c: + * gst-libs/gst/vaapi/gstvaapivideopool_priv.h: + libs: videopool: remove unneeded code + The removed code comes frome the bad practice of copy&paste. Better + move it as internal function. + https://bugzilla.gnome.org/show_bug.cgi?id=797139 + +2018-09-13 12:22:42 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapibufferproxy.c: + * gst-libs/gst/vaapi/gstvaapibufferproxy_priv.h: + * gst-libs/gst/vaapi/gstvaapiminiobject.c: + * gst-libs/gst/vaapi/gstvaapiminiobject.h: + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapiobject_priv.h: + * gst-libs/gst/vaapi/gstvaapipixmap.c: + * gst-libs/gst/vaapi/gstvaapipixmap_priv.h: + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapitexture_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow_priv.h: + * gst-libs/gst/vaapi/meson.build: + libs: remove dependency on IN_LIBGSTVAAPI_CORE + This conditional code was when libgstvaapi was intended to be library + used outside GStreamer. This not the case anymore, thus removing it. + https://bugzilla.gnome.org/show_bug.cgi?id=797139 + +2018-09-19 10:16:36 +0800 Wangfei + + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + libs: dec: h265: fix the macros used for IDC profile + profile_idc flag in SPS only indicate the IDC profile, which may + need some other flags together to get the real profile. + https://bugzilla.gnome.org/show_bug.cgi?id=797160 + +2018-09-12 19:06:22 +0900 Jimmy Ohn + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + libs: use g_clear_pointer() when possible + https://bugzilla.gnome.org/show_bug.cgi?id=797131 + +2018-09-03 13:56:52 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapifilter.h: + libs: filter: add gobject's cleanup function + +2018-05-22 14:28:40 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapifilter.h: + * gst-libs/gst/vaapi/gstvaapisurface_egl.c: + * tests/test-filter.c: + libs: filter: remove custom ref() and unref() + Replacing them by gst_object_ref() and gst_object_unref() + https://bugzilla.gnome.org/show_bug.cgi?id=796308 + +2018-05-22 14:26:48 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapifilter.h: + libs: filter: refactor filter as gobject + https://bugzilla.gnome.org/show_bug.cgi?id=796308 + +2018-05-21 13:38:00 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + libs: decoder: remove destoy() and create() callbacks + They were all replaced by reset() + https://bugzilla.gnome.org/show_bug.cgi?id=796308 + +2018-05-21 13:26:01 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + libs: decoder: vp9: implement reset() callback + remove destroy() and create() callback + https://bugzilla.gnome.org/show_bug.cgi?id=796308 + +2018-05-21 13:25:37 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_vp8.c: + libs: decoder: vp8: implement reset() callback + remove create() and destroy() callbacks + https://bugzilla.gnome.org/show_bug.cgi?id=796308 + +2018-05-21 13:24:39 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + libs: decoder: vc1: implement reset() callback + remove destroy() and create() callbacks + use g_clear_pointer for rbdu_buffer + no cast for enum + https://bugzilla.gnome.org/show_bug.cgi?id=796308 + +2018-05-21 13:24:13 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + libs: decoder: mpeg4: implement reset() callback + remove destroy() and create() callback + https://bugzilla.gnome.org/show_bug.cgi?id=796308 + +2018-05-21 13:22:45 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + libs: decoder: mpeg2: implement reset() callback + remove create() and destroy() callbacks + https://bugzilla.gnome.org/show_bug.cgi?id=796308 + +2018-05-21 13:22:07 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + libs: decoder: jpeg: implement reset() callback + and remove create() and destroy() callbacks. + https://bugzilla.gnome.org/show_bug.cgi?id=796308 + +2018-05-21 13:13:31 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + libs: decoder: h265: implement reset() callback + and remove create() and destroy() + and use g_clear_pointer for dpb structure + https://bugzilla.gnome.org/show_bug.cgi?id=796308 + +2018-05-21 13:11:41 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + libs: decoder: h264: remove create() and destroy() callbacks + https://bugzilla.gnome.org/show_bug.cgi?id=796308 + +2018-05-21 11:56:11 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * tests/test-decode.c: + * tests/test-subpicture.c: + libs: decoder: remove gst_vaapi_decoder_unref() + Replaced by gst_object_unref() in tests + https://bugzilla.gnome.org/show_bug.cgi?id=796308 + +2018-05-21 11:51:14 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + libs: decoder: remove gst_vaapi_decoder_ref() + https://bugzilla.gnome.org/show_bug.cgi?id=796308 + +2018-05-21 11:50:17 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + libs: decoder: remove gst_vaapi_decoder_new() + https://bugzilla.gnome.org/show_bug.cgi?id=796308 + +2018-05-18 16:09:31 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.h: + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h265.h: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.h: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.h: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.h: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.h: + * gst-libs/gst/vaapi/gstvaapidecoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vp8.h: + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.h: + libs: decoder: refactor decoders as gobject + https://bugzilla.gnome.org/show_bug.cgi?id=796308 + +2018-08-31 20:56:13 -0500 Matteo Valdina + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: Requests upstream a key unit at parse or decode error. + This is done to resume decoding after a parse error or decode error. + Bugzilla: https://bugzilla.gnome.org/show_bug.cgi?id=797006 + +2018-08-31 20:48:13 -0500 Matteo Valdina + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: sets return value in failure case. + In gst_vaapidecode_handle_frame, when there is a decode error + there is a code path the returns an uninitialized value. + Bugzilla: https://bugzilla.gnome.org/show_bug.cgi?id=797006 + +2018-08-30 18:56:40 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + libs: display: lock at extracting available image formates + When running several vaapi elements at the concurrently, at + initialization, there is a race condition when extractin the avaible + formats for images and subpictures. + This patch add a lock when the those arrays are filled. + https://bugzilla.gnome.org/show_bug.cgi?id=797039 + +2018-08-31 14:47:55 +0530 Nirbheek Chauhan + + * meson.build: + meson: Sync libversion and osxversion code from other repos + gstreamer-vaapi does not build any libraries, only plugins, so this is + not used, but sync it just in case someone does add it in the future. + +2018-08-29 13:44:44 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.h: + libs: encoder: h265: trivial documentation fix + +2018-08-30 11:08:07 +0800 Wangfei + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.h: + libs: encoder: h265: add low delay B frame support. + Low delay B frame provide the function of transforming + P frame into low delay B frame which frame type is B, but + only reference predictive frames. This can be used when P + frame unsupported. Especially for P and B both unsupported, + in this case, I and low delay B frame can be encoded in a + stream. + https://bugzilla.gnome.org/show_bug.cgi?id=796984 + +2018-08-27 20:42:15 -0400 Nicolas Dufresne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + libs: decoder: h264: Avoid using picture after it has been free + In some cases, the found_picture ended up being evicted and freed, which + would lead to a use after free when accessing picture->base.poc. In this + fix, we take a ref on the picture before calling dpb_evict. + https://bugzilla.gnome.org/show_bug.cgi?id=787124 + +2018-07-25 17:03:19 -0400 Nicolas Dufresne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264decoder: Fail decoding slice with missing inter-view reference + Similarly to previous patch, we have no error concealment. As a side + effect, it's better to skip slices with missing references then passing + NULL pointers to the accelerator. Passing NULL pointer would lead to + major visual artifact, a behaviour that is likely undefined. + https://bugzilla.gnome.org/show_bug.cgi?id=787124 + +2017-09-14 14:25:41 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + libs: decoder: h264: reset context when the number of view is increased + Usually in case of MVC decoding, dpb size is increasedi if subset sps. + That's why it resets context without this patch. + But for some media it doesn't increase dpb size. Even in this case we + should reset context to deal with MVC decoding. + Otherwise, it leads to assert. + https://bugzilla.gnome.org/show_bug.cgi?id=787124 + +2018-07-25 13:50:23 -0400 Nicolas Dufresne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + * gst/vaapi/gstvaapidecode.c: + vaapidecode: Skip unparsable units from adapter + If the unit could not be parsed, just skip this nal and keep parsing + what is left in the adapter. We need to flush the broken unit in the + decoder specific parser because the generic code does not know about + units boundary. This increases error resilliance. + Before this, the broken unit would stay in the adapter and EOS would be + returned. Which stopped the streaming. Just removing the EOS would have + lead to the adapter size growing indefinitely. + https://bugzilla.gnome.org/show_bug.cgi?id=796863 + +2018-07-24 12:40:00 -0400 Nicolas Dufresne + + * gst/vaapi/gstvaapidecode.c: + vaapidecoder: Don't error out on decode errors + This is problematic on live pipeline where loosing network can + cause an important amount of errors. + https://bugzilla.gnome.org/show_bug.cgi?id=796832 + +2018-07-25 15:47:49 -0400 Nicolas Dufresne + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + h265decoder: Don't scan empty buffer + Same as what we did for H264 decoder, this is to avoid an assertion + in the adapter. + https://bugzilla.gnome.org/show_bug.cgi?id=796832 + +2018-07-25 20:21:51 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + libs: h264: renable the vaapi category for logging + h264 log messages were logged in default category because a regression + in code. This patch renable the usage of vaapi logging category. + This regression was introduced in commit 7c365bdd. + +2018-07-18 13:09:42 -0400 Nicolas Dufresne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264decoder: Fail decoding slice if modification process failed + This patch chains up failure to executing the modification process. The + end result is that we now fail decoding the slice if this process fails. + This avoid sending a corrupted state to the accelerator. In some special + cases, this could lead to unrecoverable errors. + https://bugzilla.gnome.org/show_bug.cgi?id=796832 + +2018-07-18 13:07:51 -0400 Nicolas Dufresne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264decoder: Don't scan empty buffer + gst_adapter_masked_scan_uint32_peek() asserts if size is 0. Don't + try and scan in that case. This fixes assertion that would some times + happen when the stream is corrupted. + https://bugzilla.gnome.org/show_bug.cgi?id=796832 + +2018-07-04 12:51:10 +0800 Tianhao Liu + + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c: + libs: encoder: jpeg: set component id and Tqi + This change is due a problem encoding JPEGs with Intel's + media-driver: green/black image when playback jpeg + This patch sets component identifier and quantization table + destination selector in frame header to support packing headers + by Intel's media-driver that does not accept packed header + in AP level. + https://bugzilla.gnome.org/show_bug.cgi?id=796705 + +2018-06-25 14:20:32 +0200 Mathieu Duponchelle + + * gst/vaapi/gstvaapipluginutil.c: + pluginutil: downgrade unsupported driver logging + On systems with an Nvidia card, this error is output each time + the registry is rebuilt, which happens pretty often when + using gst-build as a development environment. + https://bugzilla.gnome.org/show_bug.cgi?id=796663 + +2018-06-24 13:07:20 +0200 Tim-Philipp Müller + + * gst/vaapi/gstvaapivideobufferpool.c: + Update for g_type_class_add_private() deprecation in recent GLib + +2018-05-30 16:01:36 -0400 Nicolas Dufresne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264dec: Remove false assumption about parity order + The decoder was trying to detect earlier that a field was lost base + on guessing the parity order. This breaks in streams were the parity + order changes. + This patch reverts the field order prediction code added by commit + 8dd93e9c8. + https://bugzilla.gnome.org/show_bug.cgi?id=796169 + +2018-05-18 17:03:57 -0400 Nicolas Dufresne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264dec: Properly set sentinel in ref frame list + This ensure that we always have sentinels set in the reference + pictures arrays. The code wasn't unsafe, this simply improve the + tracing, so instead of printing 32 lines of zeros, va tracer + prints proper empty lists. + https://bugzilla.gnome.org/show_bug.cgi?id=796169 + +2018-06-13 18:00:18 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapivideopool.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapivideometa.c: + * tests/test-decode.c: + libs: display: remove gst_vaapi_display_ref() + Replace it with gst_object_ref() + https://bugzilla.gnome.org/show_bug.cgi?id=796470 + +2018-06-13 17:54:23 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginutil.c: + * tests/output.c: + * tests/simple-encoder.c: + * tests/test-decode.c: + * tests/test-display.c: + * tests/test-fei-enc-in.c: + * tests/test-filter.c: + * tests/test-subpicture.c: + * tests/test-surfaces.c: + * tests/test-textures.c: + * tests/test-windows.c: + libs: display: remove gst_vaapi_display_unref() + Use gst_object_unref() instead. + https://bugzilla.gnome.org/show_bug.cgi?id=796470 + +2018-06-13 18:10:28 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapibufferpool: declare parameter display as object + We have neglected to update this code since GstVaapiDisplay turned + into a GstObject descendant. + https://bugzilla.gnome.org/show_bug.cgi?id=796470 + +2018-06-01 12:36:51 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + * gst-libs/gst/vaapi/gstvaapidisplay_egl.c: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.c: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + libs: display: replace gst_vaapi_display_new() with gst_vaapi_display_config() + Gobjectification for GstVaapiDisplay was almost done by the commit 185da3d1. + But still something breaking GObject code convention remains, which is + calling gst_vaapi_display_new() in each decendants. + This patch replaces it with gst_vaapi_display_config(), defined in private + header. + https://bugzilla.gnome.org/show_bug.cgi?id=796470 + +2018-06-13 17:05:40 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + libs: display: redefine gst_vaapi_display_create() + The function name was gst_vaapi_display_create_unlocked(), nonetheless + it wasn't called unlocked. In order to keep the semantics this patch + renames the gst_vaapi_display_create_unlocked() as + gst_vaapi_display_create(), removing the previous function + gst_vaapi_display_create(). + https://bugzilla.gnome.org/show_bug.cgi?id=796470 + +2018-06-12 15:53:04 +0200 Víctor Manuel Jáquez Leal + + * meson.build: + Revert "build: meson: libva gst-uninstall friendly" + This reverts commit fc3eef9c432c1628cb92ab56e74924cf1182da30. + +2018-06-12 15:13:33 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + plugins: fix compilation + gstvaapipluginutil.c:171:1: error: old-style function definition [-Werror=old-style-definition] + +2018-04-20 18:05:30 +0200 Víctor Manuel Jáquez Leal + + * meson.build: + build: meson: libva gst-uninstall friendly + Make gstreamer-vaapi to use libva uninstalled. + +2018-06-10 10:44:35 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + plugins: refactor gst_vaapi_create_display_from_gl_context() + gst_vaapi_create_display_from_gl_context() was a spaghetti mess. + This path refactors it, in order to make the code readable and + easy to follow. + https://bugzilla.gnome.org/show_bug.cgi?id=796564 + +2018-05-25 12:17:21 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay_egl.c: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + libs: display: resurrect parent private member + This is, practically, a revert of commit dcf135e2. + The parent logic is useful for the EGL display, which is a decorator + of the real windowing subsystem (X11 or Wayland). Thus it is avoided + calling vaInitialize() and vaTerminate() twice. + https://bugzilla.gnome.org/show_bug.cgi?id=795391 + +2018-04-27 18:35:30 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay_egl.c: + libs: display: egl: initialize params structure + Statically initialise the internal params structure. + https://bugzilla.gnome.org/show_bug.cgi?id=795391 + +2018-04-27 18:34:37 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + plugins: handle EGL when creating VAAPI display from gl + If GstGL reports a EGL platform force to create a EGL display using + the native EGL display. + https://bugzilla.gnome.org/show_bug.cgi?id=795391 + +2018-04-24 18:17:24 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapidisplay_egl.c: + * gst/vaapi/gstvaapipluginutil.c: + display: egl: create VaapiDisplayEGL with native EGL display + gst_vaapi_display_egl_new_with_native_display() has been broken since + it wasn't used. + Currently it's needed to call this API to create a display providing + the EGL display, so it could avoid duplicated calls to the native + display (eg. eglTerminate). + Signed-off-by: Victor Jaquez + https://bugzilla.gnome.org/show_bug.cgi?id=795391 + +2018-06-07 09:34:11 +0800 Tianhao Liu + + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + libs: decoder: release VA buffers after vaEndPicture + This change is due a problem decoding JPEGs with Intel's media-driver: + no image was generated. + This patch relases the VA buffers after vaEndPicture() is called, + and not before (after vaRenderPicture()). + https://bugzilla.gnome.org/show_bug.cgi?id=796505 + +2018-06-07 19:49:02 +0100 Tim-Philipp Müller + + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11_priv.h: + meson: fix build when xrender or xrandr are not available + HAVE_XRENDER are defined to 1 or 0, not defined or undefined. + +2018-05-25 16:47:00 +0200 Michael Olbrich + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: don't copy the GstParentBufferMeta if use_vpp + Otherwise a reference to a DMABuf input buffer is kept until the output + buffer is deleted. + https://bugzilla.gnome.org/show_bug.cgi?id=796399 + +2018-05-22 21:13:08 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + libs: display: remove unnecessary legacy code since gobjectification + https://bugzilla.gnome.org/show_bug.cgi?id=796470 + +2018-05-22 21:05:54 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + libs: display: remove unused code + https://bugzilla.gnome.org/show_bug.cgi?id=796470 + +2018-06-05 15:16:53 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode_h264.c: + vaapiencode: h264: log output caps + +2018-06-05 22:38:37 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode_h264.c: + vaapiencode: h264: find profile in available and allowed caps + The commit 67e33d3de225d0e006d7bf606e7abb20d4544eab ("vaapiencode: h264: + find best profile in those available") changed the code to pick a profile + that is actually supported by the hardware. Unfortunately it dropped the + downstream constraints. This can cause negotiation failures under certain + circumstances. + The fix is split in two cases: + 1\ the available VA-API caps doesn't intersect with pipeline's allowed + caps: + * The best allowed profile (pipeline's caps) is set as the encoding + target profile (it will be adjusted later by the available profiles + and properties) + 2\ the available VA-API caps does intersect with pipeline's allowed + caps: + * The intersected caps are fixed, and its profile is set as the + encoding target profile. In this case the is not the best profile, + but the minimal one (if VA-API reports the profiles in order). + Setting the minimal profile of the intersected caps is better for + compatibility. + This patch fixes other tests related with caps negotiation, for + example, it handles baseline profile, even when VA only supports + constrained-baseline. + Original-patch-by: Michael Olbrich + https://bugzilla.gnome.org/show_bug.cgi?id=794306 + +2018-06-01 15:27:25 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: increase log2_max_pic_order_cnt range according to spec + The specification says, + "log2_max_pic_order_cnt_lsb_minus4 shall be in the range of 0 to 12, inclusive." + This patch changes the upper limit from 6 to 12. + https://bugzilla.gnome.org/show_bug.cgi?id=796179 + +2018-05-21 13:27:14 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + plugins: guard GstGL code + +2018-05-18 18:23:18 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + libs: decoder: h264: use g_clear_pointer() + +2018-05-18 17:27:46 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.h: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.h: + libs: decoder: mpeg4, vc1: remove unused header + +2018-05-18 11:09:58 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + libs: decoder: remove unused forward declaration + +2018-05-07 07:59:25 -0700 U. Artie Eoff + + * configure.ac: + fix configure.ac regression + Fixes regression introduced by 77527d67abe + https://bugzilla.gnome.org/show_bug.cgi?id=795885 + +2018-05-05 17:57:49 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/Makefile.am: + * gst-libs/gst/base/Makefile.am: + * gst-libs/gst/base/gstbitwriter.c: + * gst-libs/gst/base/gstbitwriter.h: + * gst-libs/gst/base/meson.build: + * gst-libs/gst/meson.build: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapifeipak_h264.c: + * gst-libs/gst/vaapi/meson.build: + libs: remove gstbitwriter + Since it is deployed in gstreamer-core, there is no need to use + our custom version. + https://bugzilla.gnome.org/show_bug.cgi?id=795848 + +2018-04-28 16:10:46 +0800 Wang,Fei + + * gst/vaapi/gstvaapidecode.c: + vaapih264dec: add constrained and progressive profiles + Those profiles have been added in the version 2012-01 + and 2011-06 of the AVC spec (A.2.4.1 and A.2.4.2). + Both are supported by VAProfileH264High + https://bugzilla.gnome.org/show_bug.cgi?id=795624 + +2018-04-26 18:15:47 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapivideocontext.c: + * gst/vaapi/gstvaapivideocontext.h: + plugin: remove custom GstGL context handling + Instead of using our own context handling for looking for GstGL + parameters (display, context and other context), this patch changes + the logic to use the utility function offered by GstGL. + https://bugzilla.gnome.org/show_bug.cgi?id=793643 + +2018-04-26 15:03:23 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: GstGL API must use the member variables + This commit basically is a revert of commits 8092537 and fc1c415 + https://bugzilla.gnome.org/show_bug.cgi?id=793643 + +2018-04-25 16:24:32 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapipluginbase.c: + plugins: pass members as parameters of gst_gl_ensure_element_data() + The parameters of gst_gl_ensure_element_data() have to be not + local variable since they are going to be used to see if they're + set in gst_element_set_context() inside the API. + This is basically a revert of commit 3d56306c + https://bugzilla.gnome.org/show_bug.cgi?id=793643 + +2018-04-25 17:50:14 +0200 Víctor Manuel Jáquez Leal + + * meson.build: + meson: fix USE_GLES_VERSION_MASK + 1. The macro in the code is USE_GLES_VERSION_MASK + 2. glesv3 is provided by glesv2 pkg-config, then it's required to + check headers + https://bugzilla.gnome.org/show_bug.cgi?id=795391 + +2018-04-24 18:12:44 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiutils_egl.c: + libs: egl: utils: mark context as wrapped when it is + The returning egl context may be null, so we should check the + return value. + https://bugzilla.gnome.org/show_bug.cgi?id=795391 + +2018-04-24 10:02:33 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiutils_egl.c: + libs: egl: utils: fix usage of GstGL macros + Include gl.h for the required GstGL symbols. + https://bugzilla.gnome.org/show_bug.cgi?id=795391 + +2018-04-25 11:01:45 +0100 Tim-Philipp Müller + + * meson.build: + meson: use -Wl,-Bsymbolic-functions where supported + Just like the autotools build. + +2018-04-20 16:01:29 +0200 Víctor Manuel Jáquez Leal + + * meson.build: + meson: use get_pkgconfig_variable() + Use get_pkgconfig_variable() method, of dependency class, rather + than using run_command(). + +2018-04-20 11:50:55 +0100 Tim-Philipp Müller + + * gst-libs/gst/base/meson.build: + * gst-libs/gst/vaapi/meson.build: + * meson.build: + meson: fix miscellaneous meson warnings + WARNING: Passed invalid keyword argument "rqeuired". + gst-libs/gst/base/meson.build:11: WARNING: Passed invalid keyword argument "version". + gst-libs/gst/base/meson.build:11: WARNING: Passed invalid keyword argument "soversion". + gst-libs/gst/vaapi/meson.build:223: WARNING: Passed invalid keyword argument "version". + gst-libs/gst/vaapi/meson.build:223: WARNING: Passed invalid keyword argument "soversion". + +2018-03-30 13:41:39 +0200 Paul Kocialkowski + + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + display: drm: Allow finding DRM paths out of the PCI subsystem + This removes hard-coded checks on the parent subsystem of potential DRM + devices. These checks were set to exlude devices that do not originate + from the PCI bus, which is only a valid approach on x86 devices. + Other devices may have a DRM device originating from the platform + subsystem, so the checks that were previously restricted to PCI are + extended to cover platform devices as well. + https://bugzilla.gnome.org/show_bug.cgi?id=794840 + Signed-off-by: Paul Kocialkowski + +2017-11-08 13:27:06 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapivideocontext.c: + videocontext: support wl-display in "gst.vaapi.app.Display" + Through "gst.vaapi.app.Display" context, users can set their own + VADisplay and native display of their backend. + So far we support only X11 display, from now we also support Wayland + display. + Attributes: + - wl-display : pointer of struct wl_display . + https://bugzilla.gnome.org/show_bug.cgi?id=705821 + +2017-11-08 13:26:38 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.h: + libs: display: wayland: add gst_vaapi_display_wayland_new_with_va_display() + Implements new API function so that users could create GstVaapiDisplay + with their own VADisplay within a native display as backend. + https://bugzilla.gnome.org/show_bug.cgi?id=705821 + +2018-04-13 09:28:53 +0200 Michael Olbrich + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + wayland: don't poll if there are no pending frames + Otherwise the following poll may not return for an arbitrary amount of + time. This can happen if another wayland event queue has flushed and read + our events. + https://bugzilla.gnome.org/show_bug.cgi?id=795224 + +2017-10-16 12:09:08 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: 16 bit rounding of picture width and height + pic_width_in_luma_samples/pic_height_in_luma_samples can be 16-bit rounded + instead of 32-bit. + In addition, codedbuf_size must be calculated according to this change. + https://bugzilla.gnome.org/show_bug.cgi?id=753229 + +2018-04-16 10:53:47 +0100 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 3fa2c9e to ed78bee + +2018-03-30 20:39:18 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode_h264.c: + vaapiencode: h264: find best profile in those available + Instead to look for the best profile in the allowed profiles by + downstream, the encoder should look for the base profile in the + available profile in VA-API. + https://bugzilla.gnome.org/show_bug.cgi?id=794306 + +2018-03-20 10:49:10 +0000 Tim-Philipp Müller + + * NEWS: + * RELEASE: + * configure.ac: + * docs/plugins/inspect/plugin-vaapi.xml: + * meson.build: + Back to development + +=== release 1.14.0 === + +2018-03-19 20:30:28 +0000 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * configure.ac: + * gstreamer-vaapi.doap: + * meson.build: + Release 1.14.0 + +2018-03-12 16:59:01 +0000 Julien Isorce + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + libs: decoder: h264: ensure num_ref_frames is greater than 0 + Even if it is the h264parse fault or bad video file, vaapih264dec + should set a proper value for VAPictureParameterBufferH264.num_ref_frames + as the driver might use it. + Also see "info.ref_frames = dpb_size;" in + gstvaapidecoder_h264.c::ensure_context + https://bugzilla.gnome.org/show_bug.cgi?id=793836 + +=== release 1.13.91 === + +2018-03-13 19:32:05 +0000 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * configure.ac: + * gstreamer-vaapi.doap: + * meson.build: + Release 1.13.91 + +=== release 1.13.90 === + +2018-03-03 22:59:30 +0000 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * configure.ac: + * gstreamer-vaapi.doap: + * meson.build: + Release 1.13.90 + +2018-03-01 07:33:27 -0600 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: change how the metadata is copied + Instead of copying the metada in prepare_output_buffer() vmethod, + it is done in append_output_buffer_metadata() thus deinterlaced + buffers could also have the proper metas. + GstVideoCropMeta now it is copied internally and it is decided via + transform_meta() vmethod. + A new internal method, copy_metadata() was added to handle VPP + transformation where non-GstVideoVaapiMeta metas were lost. + +2018-02-27 16:20:15 -0500 Nicolas Dufresne + + * gst/vaapi/gstvaapipostproc.c: + postproc: Copy meta data from input to output + This will ensure that meta data without memory tags will be copied. This + was noticed when testing ROI. + https://bugzilla.gnome.org/show_bug.cgi?id=768248 + +2018-02-23 10:48:36 -0600 Víctor Manuel Jáquez Leal + + * tests/elements/test-roi.c: + tests: element: rewrite ROI test + Rewrote the ROI test to use GstVideoRegionOfInterest meta rather + than injecting GstEvents. These meta are added as a pad probe in + the queue src pad. + Also + * Use of navigation messages to control de test + * Use signal watch for processing messages + * Change to H265 rather than H264 since current intel-vaapi-driver + only supports ROI on kabylake. + TODO: add a parameter to change the encoder/decoder to test. + https://bugzilla.gnome.org/show_bug.cgi?id=768248 + +2018-02-22 14:20:42 -0600 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + libs: encoder: reimplement ROI using meta + Check input buffers for ROI metas and pass them to VA. Also added a + new "default-roi-delta-qp" property in order to tell the encoder what + delta QP should be applied to ROI by default. + Enabled it for H264 and H265 encoders. + https://bugzilla.gnome.org/show_bug.cgi?id=768248 + +2018-02-22 08:22:35 -0600 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + Revert "libs: encoder: add api gst_vaapi_encoder_add/del_roi" + This reverts commit 7a6f690340dcb3b82c59efa777d4453227851de8. + https://bugzilla.gnome.org/show_bug.cgi?id=768248 + +2018-02-22 14:29:19 -0600 Víctor Manuel Jáquez Leal + + * tests/simple-encoder.c: + Revert "tests: simple-encoder: add an option to set ROI" + This reverts commit c21345c4787bb6342adddea1190f53fe62abff04. + https://bugzilla.gnome.org/show_bug.cgi?id=768248 + +2018-02-21 10:56:47 -0600 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode_h264.c: + Revert "vaapiencode: handle custom event GstVaapiEncoderRegionOfInterest" + This reverts commit 8f1b88dac0e64a211325cdcb2cda693b80229bd1. + https://bugzilla.gnome.org/show_bug.cgi?id=768248 + +2018-02-23 09:25:51 -0600 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: copy input buffer metas + When importing buffers to a VA-base buffer, it is required to copy + the metas in the original buffer, otherwise information will be + lost, such as GstVideoRegionOfInterestMeta. + https://bugzilla.gnome.org/show_bug.cgi?id=768248 + +2018-02-27 06:10:09 -0600 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapisurface.c: + libs: surface: cast to uintptr_t pointer + According to Debian package auto-building, uintptr_t is not an + unsigned long in i386 arch, raising an "incompatible pointer type" + error. + This patch adds a casting for compiler's satisfaction in i386. + +2018-02-25 20:46:56 -0600 Matteo Valdina + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: add zero as valid value for periodic keyframe. + Enabled zero as valid value for keyframe-period property. + https://bugzilla.gnome.org/show_bug.cgi?id=793829 + +2018-02-22 08:24:12 -0600 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: code-style fix + +2018-02-17 18:32:11 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: generate system allocated buffers + Generate system allocated output buffers when downstream doesn't + support GstVideoMeta. + The VA buffer content is copied to the new output buffer, and it + replaces the VA buffer. + https://bugzilla.gnome.org/show_bug.cgi?id=785054 + +2018-02-15 19:32:37 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: handle system allocated buffers when required + When downstream can't handle GstVideoMeta it is required to send + system allocated buffers. + The system allocated buffers are produced in prepare_output_buffer() + vmethod if downstream can't handl GstVideoMeta. + At transform() vmethod if the buffer is a system allocated buffer, + a VA buffer is instanciated and replaces the out buffer. Later + the VA buffer is copied to the system allocate buffer and it + replaces the output buffer. + https://bugzilla.gnome.org/show_bug.cgi?id=785054 + +2018-02-15 19:32:19 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + plugins: add gst_vaapi_copy_va_buffer() + This helper function aims to copy buffers with VA memory to dumb + buffers, when GstVideoMeta is not available dowstream. + https://bugzilla.gnome.org/show_bug.cgi?id=785054 + +2018-02-15 19:29:51 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + plugins: add COPY_OUTPUT_FRAME flag + This patch add the member copy_output_frame and set it TRUE when + when downstream didn't request GstVideoMeta API, the caps are raw + and the internal allocator is the VA-API one. + https://bugzilla.gnome.org/show_bug.cgi?id=785054 + +2018-02-15 19:28:33 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + plugins: store the first downstream allocator if available + The allocator will be required if we need to allocate a buffer + to store the frame with the expected strides. + https://bugzilla.gnome.org/show_bug.cgi?id=785054 + +2018-02-20 02:25:13 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideobufferpool.c: + * gst/vaapi/gstvaapivideobufferpool.h: + vaapibufferpool: add gst_vaapi_video_buffer_pool_copy_buffer() + This function will inform the element if it shall copy the generated + buffer by the pool to a system allocated buffer before pushing it + to downstream. + https://bugzilla.gnome.org/show_bug.cgi?id=785054 + +2018-02-15 19:22:08 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapibufferpool: don't change config when forcing video meta + VA-API based buffer might need a video meta because of different + strides. But when donwstream doesn't support video meta we need to + force the usage of video meta. + Before we changed the buffer pool configuration, but actually this + is a hack and we cannot rely on that for downstream. + This patch add a check fo raw video caps and allocator is VA-API, + then the option is enabled without changing the pool configuration. + In this case the element is responsible to copy the frame to a + simple buffer with the expected strides. + https://bugzilla.gnome.org/show_bug.cgi?id=785054 + +2018-02-20 09:15:05 -0600 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: set discont flag at vpp deinterlacing + When deinterlacing with VPP the discont flag was not forwarded to + the new created buffer. This patch sets the discont flag if input + buffer has it. + +2018-02-20 02:14:37 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideobufferpool.h: + vaapibufferpool: remove wrong gcc annotation + +2018-02-15 14:55:42 -0600 Matteo Valdina + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapifeienc_h264.c: + * gst-libs/gst/vaapi/gstvaapifeipak_h264.c: + * gst-libs/gst/vaapi/gstvaapiutils_h26x_priv.h: + libs: encoder: h264,h265: extend max periodic keyframe. + Increased max values of periodic key frame for h26x codecs. + This allow more fine tunning of encoder that in certian scenario + want higher periodic key frame. + For example: it doesn't want a key frame each 10 seconds but + each 120 seconds. + https://bugzilla.gnome.org/show_bug.cgi?id=786320 + +2018-02-15 19:44:35 +0000 Tim-Philipp Müller + + * configure.ac: + * meson.build: + Back to development + +=== release 1.13.1 === + +2018-02-15 17:39:16 +0000 Tim-Philipp Müller + + * Makefile.am: + * NEWS: + * configure.ac: + * gstreamer-vaapi.doap: + * meson.build: + Release 1.13.1 + +2018-02-15 18:15:33 +0000 Tim-Philipp Müller + + * gst/vaapi/Makefile.am: + vaapi: dist new header + +2018-02-12 17:53:58 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapi.c: + vaapi: register vaapisink as marginal on wayland + vaapsink, when used with the Intel VA-API driver, tries to display + surfaces with format NV12, which are handled correctly by + Weston. Nonetheless, COGL cannot display YUV surfaces, making fail + pipelines on mutter. + This shall be solved either by COGL or by making the driver to paint + RGB surfaces. In the meanwhile, let's just demote vaapisink as + marginal when the Wayland environment is detected, no matter if it is + Weston. + https://bugzilla.gnome.org/show_bug.cgi?id=775698 + +2018-02-12 19:00:36 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + plugins: update mesa's vendor string in whitelist + Mesa has updated its VA-API Gallium driver vendor string: + https://cgit.freedesktop.org/mesa/mesa/commit/?id=5db29d62ce1fefa3f2ee6e4a4688576fde4bde4a + This patch tries to cover both, the old and the new one. + https://bugzilla.gnome.org/show_bug.cgi?id=793386 + +2018-02-08 19:22:17 +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-07 09:13:26 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: handle vaapi allocator in allocation query + In propose_allocation() if the numer of allocation params is zero, the + system's allocator is added first, and lastly the native VA-API + allocator. + In decide_allocation(), the allocations params in query are travered, + looking for a native VA-API allocator. If it is found, it is reused as + src pad allocator. Otherwise, a new allocator is instantiated and + appended in the query. + https://bugzilla.gnome.org/show_bug.cgi?id=789476 + +2018-02-07 09:06:46 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.h: + vaapivideomemory: remove unused macro + GST_VAAPI_VIDEO_ALLOCATOR_NAME was added in commit 5b11b8332 but it + was never used, since the native VA-API allocator name has been + GST_VAAPI_VIDEO_MEMORY_NAME. + This patch removes GST_VAAPI_VIDEO_ALLOCATOR_NAME macro. + https://bugzilla.gnome.org/show_bug.cgi?id=789476 + +2018-02-02 08:54:00 +0000 VaL Doroshchuk + + * gst/vaapi/gstvaapisink.c: + vaapisink: don't mask button events for foreign windows + Don't subscribe to button press events when using a foreing window, + because the user created window would trap those events, preveting the + show of frames. + https://bugzilla.gnome.org/show_bug.cgi?id=791615 + +2018-02-05 08:51:56 +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:38:37 +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-30 12:56:49 +0000 Philippe Normand + + * gst/vaapi/gstvaapi.c: + vaapi: add NULL-sentinel to kernel_names + The array needs to be NULL-terminated according to the + gst_plugin_add_dependency() documentation. + +2018-01-18 18:53:29 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostprocutil.c: + vaapipostproc: remove spurious code + This assignation is dead code, since gst_video_info_from_caps() set + to 1 by default. + https://bugzilla.gnome.org/show_bug.cgi?id=790149 + +2018-01-18 18:51:57 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostprocutil.c: + vaapipostproc: if no p-a-r in out caps define a range + Instead of copying the pixel-aspect-ratio from the sink caps, define + an open range for the src caps pixel-aspect-ratio. Later it will be + defined. + https://bugzilla.gnome.org/show_bug.cgi?id=790149 + +2018-01-18 13:10:59 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapisink.c: + vaapisink: check for display's color-balance properties + Check for display's color-balance properties, available by the VA-API + driver, before setting them. + Also logs an info message of those unavailable properties. + https://bugzilla.gnome.org/show_bug.cgi?id=792638 + +2018-01-17 17:30:50 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: re-using buffer pool breaks renegotiation + at propose_allocation() we should not reuse the proposed buffer, + because it could break renegotiation. + https://bugzilla.gnome.org/show_bug.cgi?id=792620 + +2018-01-17 17:26:24 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: use g_clear_object() to unref sinkpad_buffer_pool + https://bugzilla.gnome.org/show_bug.cgi?id=792620 + +2018-01-17 12:42:12 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/meson.build: + build: meson: add missing GstGL dependency + +2018-01-17 12:41:54 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiutils_egl.c: + libs: utils: egl: add missing guards for GstGL + +2018-01-11 11:48:02 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: remove dmabuf-import hack + Remove the hack to check if an upstream element has enabled the + property io-mode enabled as dmabuf-import. + https://bugzilla.gnome.org/show_bug.cgi?id=792034 + +2017-12-01 15:04:35 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidisplay_egl.c: + * gst-libs/gst/vaapi/gstvaapiutils_egl.c: + * gst-libs/gst/vaapi/gstvaapiutils_egl.h: + libs: egl: utils: use eglGetPlatformDisplay() + eglGetDisplay() is currently broken in Mesa for Wayland. Also using + eglGetDisplay() is rather fragile, and it is recommended to use + eglGetPlatformDisplay() when possible. + In order to do that, this patch uses the helper in GstGL. If + gstreamer-vaapi is not compiled with GstGL support, eglGetDisplay() + will be used. + https://bugzilla.gnome.org/show_bug.cgi?id=790493 + +2017-12-08 14:46:02 +0100 Michael Tretter + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: lock ensure_filter with postproc_lock + gst_vaapipostproc_ensure_filter might free the allowed_srcpad_caps + and allowed_sinkpad_caps. This can race with copying these caps in + gst_vaapipostproc_transform_caps and lead to segfaults. + The gst_vaapipostproc_transform_caps function already locks + postproc_lock before copying the caps. Make sure that calls to + gst_vaapipostproc_ensure_filter also acquire this lock. + https://bugzilla.gnome.org/show_bug.cgi?id=791404 + +2018-01-10 17:10:28 +0100 Víctor Manuel Jáquez Leal + + * tests/test-filter.c: + tests: test-filter: fix dereference before null check + Null-checking op_info suggests that it may be null, but it has already + been dereferenced on all paths leading to the check. + There may be a null pointer dereference, or else the comparison + against null is unnecessary. + +2018-01-10 17:06:53 +0100 Víctor Manuel Jáquez Leal + + * tests/y4mreader.c: + tests: y4mreader: fix string state checkup + str cannot be null in that moment, but it may be the end of string. + +2018-01-10 16:59:56 +0100 Víctor Manuel Jáquez Leal + + * tests/y4mreader.c: + tests: y4mreader: use int for fgetc + Assigning the return value of fgetc to char truncates its value. + It will not be possible to distinguish between EOF and a valid + character. + +2018-01-10 16:48:07 +0100 Víctor Manuel Jáquez Leal + + * tests/y4mreader.c: + tests: y4mreader: fix incompatible cast + Passed pointer in parse_int() are unsigned int (32 bits, unsigned) but + they are dereferenced as a wider long (64 bits, signed). This may lead + to memory corruption. + +2017-12-19 16:01:10 +0000 Tim-Philipp Müller + + * meson.build: + meson: fix fallback for gstreamer-gl-1.0, it's now in -base + +2017-12-14 14:53:27 +1100 Matthew Waters + + * common: + Automatic update of common submodule + From e8c7a71 to 3fa2c9e + +2017-12-06 16:11:46 -0500 Nicolas Dufresne + + * gst/vaapi/gstvaapivideocontext.c: + videoconvert: gst_element_post_message() is transfer full on msg + For this reson we need not to unref the message, even if it failed. + +2017-12-06 16:11:25 -0500 Nicolas Dufresne + + * gst/vaapi/gstvaapivideocontext.c: + Revert "vaapivideocontext: possible memleak when no bus attached" + This reverts commit 0438a3e62660e64ed390b6bb83bfb560b91664aa. + +2017-12-01 23:03:32 +0100 Víctor Manuel Jáquez Leal + + * tests/elements/test-vaapicontext.c: + test: vaapicontext: process have-context bus message + +2017-11-29 18:29:45 +0100 Víctor Manuel Jáquez Leal + + * tests/elements/test-vaapicontext.c: + test: vaapicontext: app context is not persistent + +2017-11-29 11:02:03 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapivideocontext.c: + * gst/vaapi/gstvaapivideocontext.h: + vaapivideocontext: only vaapisink process app context + gst.vaapi.app.Display context is made for applications that will + provide the VA display and the native display to used by the + pipeline, when are using vaapisink as overlay. There are no use + case for encoders, decoders, neither for the postprocessor. + In the case of the vaapisink, it shall query for gst.vaapi.Display + upstream first, and then, if there is no reply, + gst.vaapi.app.Display context will be posted in the bus for the + application. If the application replies, a GstVaapiDisplay object + is instantiated given the context info, otherwise a + GstVaapiDisplay is created with the normal algorithm to guess the + graphics platform. Either way, the instantiated GstVaapiDisplay + is propagated among the pipeline and the have-message bus message. + Also only vaapisink will process the gst.vaapi.app.Display, if + and only if, it doesn't have a display already set. This is + caused because if vaapisink is in a bin (playsink, for example) + the need-context is posted twice, leading to an error state. + https://bugzilla.gnome.org/show_bug.cgi?id=790999 + +2017-12-01 20:21:54 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideocontext.c: + vaapivideocontext: log the name of GstVaapiDisplay + https://bugzilla.gnome.org/show_bug.cgi?id=790999 + +2017-11-30 14:24:43 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideocontext.c: + vaapivideocontext: possible memleak when no bus attached + https://bugzilla.gnome.org/show_bug.cgi?id=790999 + +2017-11-27 13:04:24 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.h: + libs: window: wayland: remove unused header include + Remove wayland-client.h include since there is no exposed symbols from + it. + +2017-11-27 12:18:56 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h264,h265: guard rate control's macroblock + macroblock parameter appear on VA-API 1.0.0. It should be guarded. + +2017-11-27 20:17:55 +1100 Matthew Waters + + * common: + Automatic update of common submodule + From 3f4aa96 to e8c7a71 + +2016-07-29 14:58:49 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + libs: encoder: h264: Add Hierarchical-B encode + Frames are encoded as different layers. Frame in a particular + layer will use pictures in lower or same layer as references. + Which means decoder can drop the frames in upper layer but still + decode lower layer frames. + B-frames, except the one in top most layer, are reference frames. + All the base layer frames are I or P. + eg: with 3 temporal layers + T3: B1 B3 B5 B7 + T2: B2 B6 + T1: I0 P4 P8 + T1, T2, T3: Temporal Layers + P1...Pn: P-Frames: + B1...Bn: B-frames: + T1: I0->P4 , P4->P8 etc.. + T2: I0--> B2 <-- P4 + T3: I0--> B1 <-- B2, B2 --> B3 <-- P4 + Signed-off-by: Sreerenj Balachandran + https://bugzilla.gnome.org/show_bug.cgi?id=788918 + +2016-07-28 18:33:23 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + libs: encoder: h264: Add Hierarchical-P encode + Frames are encoded as different layers. A frame in a particular + layer will use pictures in lower or same layer as references. + Which means decoder can drop the frames in upper layer but still + decode lower layer frames. + eg: with 3 temporal layers + T3: P1 P3 P5 P7 + T2: P2 P6 + T1: P0 P4 P8 + T1, T2, T3: Temporal Layers + P1...pn: P-Frames: + P0->P1 , P0->P2, P2->P3, P0->P4......repeat + Signed-off-by: Sreerenj Balachandran + https://bugzilla.gnome.org/show_bug.cgi?id=788918 + +2016-07-28 16:51:28 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + libs: encoder: h264: Fix frame_num generation + The frame_num generation was not correctly implemented. + According to h264 spec, frame_num should get incremented + for each frame if previous frame is a referece frame. + For eg: IPBPB sequece should have the frame numbers 0,1,2,2,3 + Signed-off-by: Sreerenj Balachandran + https://bugzilla.gnome.org/show_bug.cgi?id=788918 + +2016-07-28 15:53:48 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + libs: encoder: h264: Add new property "prediction-type" + Adds new property "prediction-type" to select different reference + picture selection modes like hierarchical-p, hierarchical-b etc. + Signed-off-by: Sreerenj Balachandran + https://bugzilla.gnome.org/show_bug.cgi?id=788918 + +2016-07-28 15:12:05 +0300 XuGuangxin + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_objects.h: + libs: encoder: h264: Add machinery for implementing hierarchical-prediction + Adds some basic building blocks to ease the implementation + of hierarchical prediction modes. + -- add an utility method to find temporal level of each frame + -- define max_ref_frame count based on temporal level count + -- add temporal_level_div[] for finding temporal level each frame + to be encoded. + -- find ip_period based on temporal level count + Signed-off-by: Sreerenj Balachandran + https://bugzilla.gnome.org/show_bug.cgi?id=788918 + +2016-07-28 14:17:53 +0300 XuGuangxin + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + libs: encoder: h264: Add property "temporal-levels" + Adds new property "temporal-levels" to select the number of + temporal levels to be included in the encoded stream. + Signed-off-by: Sreerenj Balachandran + https://bugzilla.gnome.org/show_bug.cgi?id=788918 + +2016-07-27 16:41:01 +0300 XuGuangxin + + * gst-libs/gst/vaapi/gstvaapiencoder_objects.h: + libs: encoder: objects: Add a reference flag + We can have p-frame as non-ref and also b-frame as ref + which are not supported yet. Reference flag + is the first machinery needed for more advanced + reference picture selection modes. + Signed-off-by: Sreerenj Balachandran + https://bugzilla.gnome.org/show_bug.cgi?id=788918 + +2017-11-02 13:21:34 +0100 Daniel van Vugt + + * gst-libs/gst/vaapi/gstvaapisurface_egl.c: + libs: surface: egl: add comment + Add a warning comment when using old intel-vaapi-drivers (>1.8.4), + where the creation of surfaces from GEM fd may fail. + https://bugzilla.gnome.org/show_bug.cgi?id=773453 + +2017-10-10 13:38:21 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay_egl.c: + * gst-libs/gst/vaapi/gstvaapidisplay_egl.h: + * gst-libs/gst/vaapi/gstvaapitexture_egl.c: + libs: display: egl: add gst_vaapi_display_egl_set_current_display() + Adds a new function that changes the internal EGL display to the + current one (eglGetCurrentDisplay()) and sets the current context + too (eglGetCurrentContext()). + This new function is called by gst_vaapi_texture_egl_create() updating + the GstVaapiDisplayEGL with the current EGL display. + https://bugzilla.gnome.org/show_bug.cgi?id=773453 + +2017-10-09 16:02:11 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapitexture_egl.c: + libs: texture: egl: update EGL display and context + It is required to use the context of the calling thread when wrapping + a foreign texture. According the documentation of + GstVideoGLTextureUploadMeta: + "The caller of gst_video_gl_texture_upload_meta_upload() must + have OpenGL set up and call this from a thread where it is valid + to upload something to an OpenGL texture." + This patch updates the EGL display and context in GstVaapiDisplay + instance to the one used by te renderer that uploads the texture. + Original-patch-by: Daniel van Vugt + https://bugzilla.gnome.org/show_bug.cgi?id=773453 + +2017-10-10 19:53:04 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: centralize assignation of GL objects + Add plugin_set_gst_gl() where the GstGL objects are assigned. + https://bugzilla.gnome.org/show_bug.cgi?id=773453 + +2017-10-10 19:13:35 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: set GL objects if ensured + Only set the GL display and GL other context if they are ensured. + https://bugzilla.gnome.org/show_bug.cgi?id=773453 + +2017-10-10 17:14:15 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: set GL objects if context is handled + Only set the GL display and GL other context if they are extracted + correctly from the gstreamer's context. + https://bugzilla.gnome.org/show_bug.cgi?id=773453 + +2017-10-10 19:57:45 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: fix memory leak when GL context is created + When the GL display and context are created inside an VAAPI element + the created GL context is leaked. + https://bugzilla.gnome.org/show_bug.cgi?id=773453 + +2017-10-10 14:01:59 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay_egl.c: + libs: display: egl: free leaked memory + The EGL VAAPI display forgot to release the egl display, context and + proxied VAAPI display. + https://bugzilla.gnome.org/show_bug.cgi?id=773453 + +2017-10-05 19:25:08 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapitexture_egl.c: + libs: texture: egl: code style + https://bugzilla.gnome.org/show_bug.cgi?id=773453 + +2017-10-04 13:51:23 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapisurface_egl.c: + libs: surface: egl: error message if no extension + Instead of silently fail to export the image if there is not available + the EGL_MESA_drm_image, log an error message. Also a code refactoring + was done. + https://bugzilla.gnome.org/show_bug.cgi?id=773453 + +2017-10-31 13:10:50 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: direct rendering on memory:VASurface + As buffers negotiated with memory:VASurface caps feature can also be + mapped, they can also be configured to use VA derived images, in other + words "direct rendering". + Also, because of the changes in dmabuf allocator as default allocator, + the code for configuring the direct rendering was not clear. + This patch cleans up the code and enables direct rendering when the + environment variable GST_VAAPI_ENABLE_DIRECT_RENDERING is defined, + even then the memory:VASurface cap feature is negotiated. + https://bugzilla.gnome.org/show_bug.cgi?id=786054 + +2017-10-04 11:54:31 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginutil.c: + plugins: only dmabuf on srcpad if downstream + Set if source pad can handle dmabuf only if the GstGL context comes + from downstream. + It is possible to know that at two moments: + 1\ In the case of GstGLTextureUpload caps feature is negotiated and + downstream pool reports back gst.gl.GstGLContext. + 2\ When GstGLContext is found as GstContext from dowstream. + https://bugzilla.gnome.org/show_bug.cgi?id=788503 + +2017-10-04 11:52:32 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideocontext.c: + vaapivideocontext: add inline documentation + Document function gst_vaapi_find_gl_local_context(). + https://bugzilla.gnome.org/show_bug.cgi?id=788503 + +2017-10-04 11:50:25 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapivideocontext.c: + * gst/vaapi/gstvaapivideocontext.h: + vaapivideocontext: return the direction of gl context + In function gst_vaapi_find_gl_context() add a direction parameter to + return back the direction where the GstGL context was found. + This is going to be useful when checking if downstream can import + dmabuf-based buffers. + https://bugzilla.gnome.org/show_bug.cgi?id=788503 + +2017-10-04 08:30:51 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + plugins: add gst_vaapi_plugin_base_set_srcpad_can_dmabuf() + This patch refactors the code by adding the function + vaapi_plugin_base_set_srcpad_can_dmabuf(), it determines if the passed + GstGLContext can handle dmabuf-based buffers. + The function is exposed publicly since it is intended to be used later + at GstVaapiDisplay instantiation. + https://bugzilla.gnome.org/show_bug.cgi?id=788503 + +2017-10-20 12:37:15 +0200 Hyunjun Ko + + * gst/vaapi/gstvaapiencode.c: + vaapiencode: allow to set property on runtime + Tis patch, allows some properties that we want to be set on + runtime. (eg. bitrate) + Note that all properties are under control by num_codedbuf_queued. + https://bugzilla.gnome.org/show_bug.cgi?id=786321 + +2017-09-15 15:38:18 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: allow to set bitrate on runtime + In case of streaming, controlling bitrate dynamically for encoder might be + important to manage quality of the streaming. + This patch is to support such a scenario. + https://bugzilla.gnome.org/show_bug.cgi?id=786321 + +2017-10-10 11:35:24 +0300 Sebastian Dröge + + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapi.h: + * gst/vaapi/gstvaapidecodebin.c: + vaapidecodebin: Register element if no VPP support is available too + VPP support is only needed for advanced deinterlacing, which is not + enabled by default either. Error out if it is selected but VPP is not + supported, and otherwise just work without VPP support. + https://bugzilla.gnome.org/show_bug.cgi?id=788758 + +2017-10-16 11:57:16 +0200 Thibault Saunier + + * gst/vaapi/gstvaapipluginutil.c: + Avoid infinite loop when vaapi_create_display fails + Which might be the case when using, for example, xvfb. + +2017-10-02 18:53:21 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiutils.c: + libs: utils: log warn if display fail + gstreamer-vaapi initializes the display by trial-and-error, thus + logging an error message if the display initialisation fails the user + may be weary of the error message in the screen, if using VA-API 1.0 + This commit set the VA error log handler to GStreamer warning level + while calling vaInitialize() and set it to error after that. + https://bugzilla.gnome.org/show_bug.cgi?id=783169 + +2017-09-29 20:05:22 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + plugins: try to create test display in order + When creating the test display for querying capabilites, it try in + certain order: DRM, Wayland and finally X11. GLX nor EGL are tried + since they are either composited with X11 or Wayland. + The reason for this is to reduce the posibility of failure that could + blacklist the plugin. + https://bugzilla.gnome.org/show_bug.cgi?id=782212 + +2017-09-29 15:07:47 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + libs: display: delay getting screen resolution + Instead of extracting the screen resolution at GstVaapiDisplay + creation, this patch delay it until the screen size is requested for + first time. + https://bugzilla.gnome.org/show_bug.cgi?id=782212 + +2017-09-28 18:58:17 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay_egl.c: + libs: display: egl: avoid two vaDisplay instantiates + GstVaapiDisplayEGL is a wrapper of another GstVaapiDisplay, either X11 + or Wayland. Nonetheless it created another vaDisplay for it, instead + of using the wrapped one. + This patch enables the reuse of the wrapped vaDisplay avoiding + instantiating two. + https://bugzilla.gnome.org/show_bug.cgi?id=782212 + +2017-09-28 17:45:00 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + libs: display: remove display_type from display info + Since it's no required to pass the display type in the display info, + the structure member is removed. + https://bugzilla.gnome.org/show_bug.cgi?id=782212 + +2017-09-28 17:35:01 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + libs: display: remove display_type member + It is not used any more since GstVaapiDisplay was ported as a + GstObject-based. This information is part of the class information. + https://bugzilla.gnome.org/show_bug.cgi?id=782212 + +2017-09-28 16:12:23 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + libs: display: remove parent member + Parent was a crumb left from display cache. + https://bugzilla.gnome.org/show_bug.cgi?id=782212 + +2017-10-03 13:06:33 +0200 Sebastian Dröge + + * gst/vaapi/gstvaapi.c: + vaapi: Also register vaapipostproc without VPP support + It can still do simple deinterlacing then. + +2017-10-03 10:51:06 +0200 Sebastian Dröge + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: Allow running without VPP support + We returned FALSE from ::start() if VPP support is not available, but it + is only really needed for complex filters and during transform we check + for that. For simple deinterlacing it is not needed. + +2017-09-27 18:35:20 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: use scoped variable for return value + Instead of reusing a parameter variable for the return value of + gst_vaapipostproc_transform_caps(), this patch uses the function + scoped pointer. Thus, the code is cleaner. + https://bugzilla.gnome.org/show_bug.cgi?id=785706 + +2017-09-27 18:32:03 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: removed unused parameter + Removed caps parameter from gst_vaapipostproc_transform_caps_impl() + helper function since the it is not used. + https://bugzilla.gnome.org/show_bug.cgi?id=785706 + +2017-09-27 13:32:34 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: use scoped variable for return value + Instead of reusing a parameter variable for the return value of + gst_vaapipostproc_fixate_caps(), this patch uses the function scoped + pointer. Thus, the code is cleaner. + https://bugzilla.gnome.org/show_bug.cgi?id=785706 + +2017-09-27 11:27:40 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.h: + plugins: memory:DMABuf only handles planar formats + When glimagesink negotiates the caps feature memory:DMABuf the + exported dmabufs buffers with NV12 format are not well rendered, thus + setting only planar. + https://bugzilla.gnome.org/show_bug.cgi?id=788229 + +2017-09-25 17:04:12 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode.c: + vaapiencode: flush pending frames before set format + Flush pending frames, if any, in the internal encorder, before setting + the new negotiated format. + https://bugzilla.gnome.org/show_bug.cgi?id=786173 + +2017-09-25 15:50:19 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: drain pending frames before set format + Drain pending frames, if any, in the internal decoder before setting + the new negotiated format. + https://bugzilla.gnome.org/show_bug.cgi?id=786173 + +2017-09-22 19:35:04 +0200 Víctor Manuel Jáquez Leal + + * tests/test-display.c: + tests: display: use GObject getter + Instead of using the gst_vaapi_display_get_property(), this patch + replaces it with g_object_get_property() to dump the available VA + display properties. + https://bugzilla.gnome.org/show_bug.cgi?id=788058 + +2017-09-22 19:25:20 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapisink.c: + vaapisink: use GObject setter and getter + Instead of using gst_vaapi_display_set_property() or + gst_vaapi_display_get_property(), this patch set replace it usage + with g_object_set() or g_object_get(). + Also the internal helper cb_set_value() is removed since it is not + used anymore. + https://bugzilla.gnome.org/show_bug.cgi?id=788058 + +2017-09-22 18:59:49 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + libs: display: initialize value if they are not yet + This is a difference between the GObject API and the GstVaapi one: the + GValue passed to get a property value, in GObject has to be + initialized with g_value_init(), but in GstVaapi is has not. + In order to overcome this mismatch, this patch call g_value_init() + internally only in the passed one is not already initialized. + https://bugzilla.gnome.org/show_bug.cgi?id=788058 + +2017-09-22 17:04:17 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + libs: display: optimize properties setters and getters + Shuffled some code to avoid to find the properties descriptor in the + array twice, adding the internal functions _set_property() and + _get_property(). + https://bugzilla.gnome.org/show_bug.cgi?id=788058 + +2017-09-22 16:29:02 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + libs: display: install properties in class + Install the properties in the class as a normal GObject. Implement + set_property() and get_property() vmethods. + https://bugzilla.gnome.org/show_bug.cgi?id=788058 + +2017-09-22 15:16:34 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + libs: display: remove gst_vaapi_display_properties_init() + Remove gst_vaapi_display_properties_init() since it can be unrolled in + gst_vaapi_display_class_init() + https://bugzilla.gnome.org/show_bug.cgi?id=788058 + +2017-09-22 15:12:05 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + libs: display: remove libgstvaapi_init_once() + It is not required since it can be unrolled in + gst_vaapi_display_class_init() + https://bugzilla.gnome.org/show_bug.cgi?id=788058 + +2017-09-22 17:50:15 +0200 Víctor Manuel Jáquez Leal + + * tests/test-display.c: + tests: test-display: remove display cache tests + Since commit ec3e10f6, display cache was removed. This patch removes + this leftovers in the display test. + +2017-09-18 14:29:55 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + libs: decoder: h264/h265: decode codec data only if opened + Fixes regression introduced by commit 2eb2b26a. + There is a use case when the decoder set the src caps and immediatly + tries to process the media codec_data, this happens before decoder is + even opened, thus priv->parser is not instantiated yet. + https://bugzilla.gnome.org/show_bug.cgi?id=787818 + +2017-09-18 19:11:45 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + libs: encoder: change mbbrc from uint to enum + Instead of handling the macroblock bitrate control as a integer, this + patch changes it as a enum, which is more self documented in the + GStreamer elements. + https://bugzilla.gnome.org/show_bug.cgi?id=787855 + +2017-09-18 13:55:49 +1000 Jan Schmidt + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + Fix a typo in the prop string for compliance-mode + +2017-09-15 18:31:49 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: don't unref properties + This patch fixes a regression introduced in commit 148f867c, since the + props variable is set to object's member variable + encoder->properties. And it is set in the instance initialization, + thus it will not be leaked. + https://bugzilla.gnome.org/show_bug.cgi?id=787733 + +2017-09-15 15:14:47 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst/vaapi/gstvaapiencode.c: + vaapiencode/libs: encoder: fix leaks of properties + https://bugzilla.gnome.org/show_bug.cgi?id=786321 + +2017-08-24 21:51:22 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + libs: decoder: at update_caps() decode codec_data + When updating the caps in decoder, if the caps has codec_data (avC + format), it has to be parsed to update the state of the decoder. + https://bugzilla.gnome.org/show_bug.cgi?id=786173 + +2017-09-13 15:44:32 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapicontext.c: + libs: context: fix wrong counter of the array of attributes + The counter value passed to vaCreateConfig is always +1. + This is a regression caused by commit e42ec3ad. + The present patch fixes wrong counting of the array of attributes. + https://bugzilla.gnome.org/show_bug.cgi?id=787613 + +2017-09-13 12:23:42 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.h: + libs: encoder: h265: support I/P/B QP setting seperatedly + Creates 2 properties, qp-ip and qp-ib for setting different QP for P/B + frames + and set slice_qp_delta for each frame according to the value provided. + https://bugzilla.gnome.org/show_bug.cgi?id=785923 + +2017-09-13 12:22:07 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + libs: encoder: h264: support I/P/B QP setting seperatedly + Creates 2 properties, qp-ip and qp-ib for setting different QP for P/B + frames + and set slice_qp_delta for each frame according to the value provided. + In addition, remove the limitation of (<= 4) when setting + slice_qp_delta. + https://bugzilla.gnome.org/show_bug.cgi?id=785923 + +2017-09-13 12:15:57 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h264/h265: keep min_qp as is unless it's over init_qp + Creates new variable for QP for I frame and keep it at configuration and + use this for pic_init_qp and slice_qp_delta setting. + Since changing min qp doesn't make sense, keep min qp as is. + https://bugzilla.gnome.org/show_bug.cgi?id=785923 + +2017-09-13 12:09:45 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.h: + libs: encoder: h265: Add mbbrc property + This property supports Macroblock level Bitrate Control as the + following (same as h264 encoder): + 0: auto + 1: on + 2: off + https://bugzilla.gnome.org/show_bug.cgi?id=785917 + +2017-09-13 12:02:53 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + libs: encoder: h264: Add mbbrc property + This property supports Macroblock level Bitrate Control as the + following: + 0: auto + 1: on + 2: off + https://bugzilla.gnome.org/show_bug.cgi?id=785917 + +2017-09-13 11:39:09 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: add multi reference support + This is doing the same as h264 encoder as the following: + Using num_ref_frames provided and the result of the Query + VAConfigAttribEncMaxRefFrames, it determines the size of reference list + and perform encoding with multi reference frames as the following: + 1\ The num_ref_frames is being considered as the number of + reference picture list0 + 2\ Encoder adds 1 reference frame more to the reference picture list1 + internally if b-frame encoding. + 3\ If num_ref_frames is bigger than the number of refrence frames + supported in the driver, it will be lowered. + Also this patch includes: + - Set num_negative_pics and num_positive_pics according to the number of + refs. + - Set delta_poc according to the number of refs. + - Increase max_dec_pic_buffering according to the number of refs + - Change max_num_reorder_pics according to num of bframes + https://bugzilla.gnome.org/show_bug.cgi?id=783804 + +2017-09-13 11:37:33 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.h: + libs: encoder: h265: add refs property + Users can provide the number of reference frame by this property, + which is exaclty same as h264. + The value of the property will be considered as the number of + reference picture list0 and will add 1 reference frame more to the + reference picture list1 internally if b-frame encoding. + If the value provided is bigger than the number of refrence frames + supported in the driver, it will be lowered. + The maximum value is aligned to the value of the driver supported now. + https://bugzilla.gnome.org/show_bug.cgi?id=783804 + +2017-09-13 11:17:26 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h264/5: determine num_ref_idx_active_override_flag according to reference list + Follows the specification as below: + 7.4.7.1 in Rec. ITU-T H.265 v4 (12/2016) + num_ref_idx_active_override_flag equal to 1 specifies that the syntax + element num_ref_idx_l0_active_minus1 is present for P and B slices and + that the syntax element num_ref_idx_l1_active_minus1 is present for B + slices. + num_ref_idx_active_override_flag equal to 0 specifies that the syntax + elements num_ref_idx_l0_active_minus1 and num_ref_idx_l1_active_minus1 + are not present. + https://bugzilla.gnome.org/show_bug.cgi?id=783804 + +2017-09-13 11:06:20 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: keep idr_period equal to keyframe period + Remove FIXME code, which makes previous assignation spurious. + This also means to make idr_period equal to keyframe period, + which is same as h264 encoder. + https://bugzilla.gnome.org/show_bug.cgi?id=783804 + +2017-09-06 14:03:25 -0400 Nicolas Dufresne + + * gst/vaapi/gstvaapipluginbase.c: + Request minimum buffer even if need_pool is FALSE + When tee is used, it will not request a pool, but still it wants to + know how many buffers are required. + https://bugzilla.gnome.org/show_bug.cgi?id=730758 + +2017-09-05 10:58:57 -0700 U. Artie Eoff + + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + libs: encoder: h264_fei: VA-API 1.0 compat + Use VA_ENC_PACKED_HEADER_H264_SEI compat macro for VA-API 1.0 + compatibility. + https://bugzilla.gnome.org/show_bug.cgi?id=787322 + Signed-off-by: U. Artie Eoff + +2017-09-01 13:48:01 -0700 Sreerenj Balachandran + + * gst/vaapi/gstvaapisink.c: + vaapisink: Fix rendering in drm display + Make sure vaapisink create a va surface backed buffer pool and all + required attributes get assigned correctly for drm display type. + This is needed to make the below pipeline working: + gst-launch-1.0 filesrc location= raw_video.mov ! videoparse format=uyvy + width=320 height=240 framerate=30/1 ! vaapisink display=drm + https://bugzilla.gnome.org/show_bug.cgi?id=786954 + +2017-08-09 18:46:09 -0700 Sreerenj Balachandran + + * tests/Makefile.am: + * tests/test-fei-enc-in.c: + * tests/test-fei-enc-out.c: + FEI: Add test applications to showcase fei use case + test-fei-enc-out: A simple fei encoding application to output mv, mbcode and distortion + eg: + ./test-fei-enc-out -i sample_320x240.nv12 -w 320 -h 240 -o out.264 -v mv.out -d out.dist -m out.mbcode -e 1 + test-fei-enc-in: A simple fei encoding application for testing input fei buffers + eg: + ./test-fei-enc-in -c h264 -o out.264 -e 4 -q 1 sample_i420.y4m + Fixme: Running test-fei-enc-in in PAK mode with mv and mbcode input buffers + from saved files is still not working + People contributed: + Wang, Yi + Leilei + Zhong, Xiaoxia + xiaominc + Li, Jing B + https://bugzilla.gnome.org/show_bug.cgi?id=785712 + https://bugzilla.gnome.org/show_bug.cgi?id=784667 + +2017-08-09 18:36:13 -0700 Sreerenj Balachandran + + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapiencode_h264_fei.c: + * gst/vaapi/gstvaapiencode_h264_fei.h: + FEI: plugin: Add vaapih264feienc element + A new FEI based encoder element for h264 is added: vaapih264feienc + FEI is a an extension to VA-API which is providing low level + advanced control over different stages of encoding. + Extending vaapih264enc with fei support is possible, but it will + make the code too much complicated and will be difficult + to debug. So adding the new encoder element, but keeping + the rank as 0 , vaapih264enc will stay as the primary + encoder for normal use cases. + The vaaih264feienc is mainly useful for customers who want to play + with MotionVectors and Macroblock Predictions. Also user can + do one stage of encoding(eg: only the Motion Vector Calculation) + in software and offload trasformation/entroy-coding etc to + Hardware (which is what PAK module is doing) using FEI element. + vaapih264feienc can work in different modes using fei-mode properoty + eg: gst-launch-1.0 videotestsrc ! vaapih264feienc fei-mode=ENC+PAK ! filesink location=sample.264 + Important Note: ENC only mode won't produce any encoded data which is expected. + But ENC alwys requires the output of PAK in order to do the inter-prediction + over reconstructed frames. + Similary PAK mode alway requires MV and MBCode as input, so unless there is an + upstream element providing those buffers, PAK only won't work as expected. + In a nutshell, ENC_PAK and the ENC+PAK modes are the only options we can verify + with vaapih264feienc. But ideally, EN+PAK mode verification is enough to make sure + that ENC and PAK are working as expected since ENC+PAK mode always invoke ENC and PAK + separately in vaapih264feienc. + People contributed: + Wang, Yi + Leilei + Zhong, Xiaoxia + xiaominc + Li, Jing B + https://bugzilla.gnome.org/show_bug.cgi?id=785712 + https://bugzilla.gnome.org/show_bug.cgi?id=784667 + Signed-off-by: Sreerenj Balachandran + +2017-08-09 18:32:13 -0700 Yi A Wang + + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode.h: + FEI: plugin: Add virtual methods to base encode + Two new virtual methods are added to gstvaapiencode. + load_control_data(): load the FEI input buffers set by the upstream elements + save_stats_to_meta(): save the FEI output buffers to Meta for downnstream elements + https://bugzilla.gnome.org/show_bug.cgi?id=785712 + https://bugzilla.gnome.org/show_bug.cgi?id=784667 + Signed-off-by: Sreerenj Balachandran + +2017-08-09 18:26:57 -0700 Yi A Wang + + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapifeivideometa.c: + * gst/vaapi/gstvaapifeivideometa.h: + FEI: plugin: Add fei specific video meta + GstVaapiFeiVideoMeta holds the below fei codec objects: + GstVaapiEncFeiMbCode + GstVaapiEncFeiMv + GstVaapiEncFeiMvPredictor + GstVaapiEncFeiMbControl + GstVaapiEncFeiQp + GstVaapiEncFeiDistortion + https://bugzilla.gnome.org/show_bug.cgi?id=785712 + https://bugzilla.gnome.org/show_bug.cgi?id=784667 + Signed-off-by: Sreerenj Balachandran + +2017-08-09 18:19:06 -0700 Sreerenj Balachandran + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_fei.h: + * gst-libs/gst/vaapi/gstvaapifeienc_h264.c: + * gst-libs/gst/vaapi/gstvaapifeienc_h264.h: + * gst-libs/gst/vaapi/gstvaapifeipak_h264.c: + * gst-libs/gst/vaapi/gstvaapifeipak_h264.h: + FEI: libs: Add FEI encoder + Adding FEI encoder to core lib. + The code is splitted into three session: + 1: gstvaapiencoder_h264_fei.{h,c} + This is the replica of gstvaapiencoder_h264.{c,h} but with FEI. + All the modes ENC, PAK and ENC_PAK are running based + the code in these files. + 2: gstvaapifeienc_h264.{h,c} + Abstract implementation intended for ENC (only VME) operation. + 3: gstvaapifeipak_h264.{h,c} + Abstrct implementation intended for PAK (only the PAK module) + Right now ENC_PAK, ENC and PAK are running based on code + in gstvaapiencoder_h264_fei.{h,c}. The abstract implementations + in gstvaapifeienc_h264.{h,c} and gstvaapifeipak_h264.{h,c} are + needed if user request for ENC+PAK mode operation. + ENC+PAK: Here we need to invoke two sequence of + vaBeginPicture/vaRenderPicutre/vaEndPicture for each frame, + first for the ENC only and the second for PAK only. + Each mode associated with separate context ,but same pool of surfaces are + shared between the modes. + This is more useful once we have custom BRC algorithms. + Other Contributors: + Wang, Yi + Leilei + Zhong, Xiaoxia + xiaominc + Li, Jing B + https://bugzilla.gnome.org/show_bug.cgi?id=785712 + https://bugzilla.gnome.org/show_bug.cgi?id=784667 + +2017-08-09 17:54:27 -0700 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_objects.c: + * gst-libs/gst/vaapi/gstvaapiencoder_objects.h: + FEI: libs: Add fei codec objects to GstVaapiEncPicture + All the codec objects(vaapi buffers) supposed to be + submited in vaRenderPicutre are associated with a GstVaapiEncPicture + for each frame, follow the same design for FEI too. + https://bugzilla.gnome.org/show_bug.cgi?id=785712 + https://bugzilla.gnome.org/show_bug.cgi?id=784667 + +2017-08-09 16:05:13 -0700 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapicodedbufferproxy.c: + * gst-libs/gst/vaapi/gstvaapicodedbufferproxy.h: + * gst-libs/gst/vaapi/gstvaapicodedbufferproxy_priv.h: + FEI: libs: Add fei codec objects in codedbufferproxy + MbCode, MV and Distortion buffers (fei codec objects) + can be treated as output of different fei modes based user request. + For eg: MbCode and MV are the output of ENC only. MbCode, MV and Dist + can be dumped as output in ENC_PAK mode for analysis purpose. + So treating them as a part of CodedBufferProxy too. + Here we avoided Qp, MbControl and MvPredictor codec objects since + there is no practical use case of treating them as "output buffers". + Other contributors: + Zhong, Xiaoxia + xiaominc + Leilei + Li, Jing B + https://bugzilla.gnome.org/show_bug.cgi?id=785712 + https://bugzilla.gnome.org/show_bug.cgi?id=784667 + +2017-08-09 15:49:21 -0700 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy_priv.h: + FEI: libs: Add fei codec objects to surface proxy + Add fei codec objects to surface proxy since handling the + fei buffers(codec objects here) external to gstvaapisurfaceproxy + will make the code complicated. Especially considering the behavior + of encoder where the input frame order from upstream and output + frame order to the downstream are not sequential. + Other contributors: + Zhong, Xiaoxia + xiaominc + Leilei + Li, Jing B + https://bugzilla.gnome.org/show_bug.cgi?id=785712 + https://bugzilla.gnome.org/show_bug.cgi?id=784667 + +2017-08-09 15:35:10 -0700 Sreerenj Balachandran + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapifei_objects.c: + * gst-libs/gst/vaapi/gstvaapifei_objects.h: + * gst-libs/gst/vaapi/gstvaapifei_objects_priv.h: + FEI: Add codec objects for fei usecase + There are 6 new va buffer types, each defined as a specific codec object. + Borrowed the code from gstvaapicodecobject , but made a clear separation + to avoid any possible mess-up. Because unlike the other gstvaaicodecobjects, + feicodecobjects can be shared between elements and also can be accessed + from different thread. + Unlike the other fei codecs object, VAEncMiscParameterTypeFEIFrameControl + object is not shared between elements.So we utilize the already + existing gst_vaapi_enc_misc_param_new(), but still keeping the code + in gstvaapfei_objects_priv.h in order to have a better + code readability. + Fixme: + -- Probably we need _locked_map() and _unlocked_map() + -- Context can be associated with PreEnc(not just Enoder) + once we have the proper support inplace, but for now we don't have + PreEnc support, so should be safe enough to use GstVaapiEncoder. + https://bugzilla.gnome.org/show_bug.cgi?id=785712 + https://bugzilla.gnome.org/show_bug.cgi?id=784667 + +2017-08-09 14:22:12 -0700 Sreerenj Balachandran + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapifeiutils_h264.c: + * gst-libs/gst/vaapi/gstvaapifeiutils_h264.h: + FEI: libs: add H264 fei specific utility functions + Added enum/flag type definitions for a number of FEI + input and output parameters. + Original author of the patch: Wang, Yi + https://bugzilla.gnome.org/show_bug.cgi?id=785712 + https://bugzilla.gnome.org/show_bug.cgi?id=784667 + Signed-off-by: Wang, Yi + Signed-off-by: Sreerenj Balachandran + +2017-08-09 14:10:16 -0700 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + FEI: libs: Add virtual method for secondary context creation. + Add a new vitrual method ensure_secondary_context to the + base encoder which is only required for the FEI entrypoint, that too + only when user configures the ENC+PAK mode. ENC+PAK mode is not something + supported directly by libva or driver, but this can be enabled + from the middleware. + Original Author of this idea: Leilei Shang + Signed-off-by: Leilei Shang + Signed-off-by: xiaominc + Signed-off-by: Sreerenj Balachandran + https://bugzilla.gnome.org/show_bug.cgi?id=785712 + https://bugzilla.gnome.org/show_bug.cgi?id=784667 + +2017-08-09 14:05:03 -0700 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + FEI: libs: make sure the default context creation works as expected. + Current code always guess the entrypoint during init phase in case + if there is no entrypoint already configured in GstVaapiContextInfo. + Make sure FEI Entrypoint is not messing up with this logic. + https://bugzilla.gnome.org/show_bug.cgi?id=785712 + https://bugzilla.gnome.org/show_bug.cgi?id=784667 + +2017-08-09 13:45:40 -0700 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapiencoder.c: + FEI: libs: Add FEI functional mode configuration + FEI Entrypoint can work in either one of the 3 different modes: + VA_FEI_FUNCTION_ENC, VA_FEI_FUNCTION_PAK or VA_FEI_FUNCTION_ENC_PAK. + Add infrastructure in gstvaapicontext and gstvaapiencoder for this + functioal mode configuration. + https://bugzilla.gnome.org/show_bug.cgi?id=785712 + https://bugzilla.gnome.org/show_bug.cgi?id=784667 + +2017-08-09 13:02:24 -0700 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + FEI: libs: Add FEI Entrypoint mapping + Define the new mapping GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_FEI + for VAEntrypointFEI. + https://bugzilla.gnome.org/show_bug.cgi?id=785712 + https://bugzilla.gnome.org/show_bug.cgi?id=784667 + +2017-08-09 12:58:29 -0700 Sreerenj Balachandran + + * configure.ac: + FEI: Add support for FEI conditional build + FEI(Flexible Encoding Infrastructure) is an extension + to VA API. Define USE_H264_FEI_ENCODER based on + fei header file and required structures availability. + https://bugzilla.gnome.org/show_bug.cgi?id=785712 + https://bugzilla.gnome.org/show_bug.cgi?id=784667 + +2017-08-28 17:34:50 -0700 Orestis Floros + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: force add h264 SVC profiles in caps + When vaapih264dec's base-only profile is set to TRUE, fake SVC profile + support in caps. + https://bugzilla.gnome.org/show_bug.cgi?id=732266 + Signed-off-by: Sreerenj Balachandran + +2017-08-28 17:32:57 -0700 Orestis Floros + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + libs: decoder: h264: decode SVC base layer only + Drops non-base NALs when the base-only property is set to TRUE. + This modifies the behavior for MVC streams with base-only too: All the + non-base units are dropped before they are decoded instead of dropping + the non-base frames. + The relevant part from the H264 spec is: + > Decoders that conform to one or more of the profiles specified in + Annex A rather than the profiles specified in Annexes G or H shall + ignore (remove from the bitstream and discard) the contents of all NAL + units with nal_unit_type equal to 14, 15, or 20. + To eliminate side effects from the offending units: + - PPS's with a broken seq_parameter_set_id (referring to dropped subset + SPS's) are ignored. + - The NAL parsing is skipped and their flags are set to + GST_VAAPI_DECODER_UNIT_FLAG_SKIP. + - Prefix units are not stored in prev_pi. Otherwise, parse_slice() would + use them even if they are flagged to be skipped. Subset SPS's and slice + extension units are not stored there either. + https://bugzilla.gnome.org/show_bug.cgi?id=732266 + Signed-off-by: Sreerenj Balachandran + +2017-08-28 17:28:04 -0700 Orestis Floros + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + libs: decoder: h264: check nalu validity in parser info finalize + https://bugzilla.gnome.org/show_bug.cgi?id=732266 + Signed-off-by: Sreerenj Balachandran + +2017-08-28 19:20:42 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + libs: encoder: remove unused cast macro + Remove internal macro to cast structure that are already declared + in the header. + +2017-08-28 19:09:07 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.h: + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.h: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.h: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.h: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.h: + Revert "libs: encoders: remove unused cast macros" + This reverts commit fd7d38f7d26b11e592638092b4073b5c1764f255. + +2017-08-28 18:32:32 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.h: + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.h: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.h: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.h: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.h: + libs: encoders: remove unused cast macros + They are only used inside the code, where another macro is defined. + Thus these exported macros have no use. + +2017-08-24 20:26:11 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + libs: decoder: h264: improve code-style + https://bugzilla.gnome.org/show_bug.cgi?id=786173 + +2017-08-25 16:22:59 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapicompat.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + libs: encoder: h264: handle deprecated enum + In VA-API 1.0 the enum VAEncPackedHeaderH264_SEI is deprecated, and + instead VAEncPackedHeaderRawData should be used. + This patch creates a compatibility symbol, + VA_ENC_PACKED_HEADER_H264_SEI, to expose the used enum according the + VA-API version. + https://bugzilla.gnome.org/show_bug.cgi?id=784398 + +2017-08-25 16:07:34 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiutils.c: + libs: guard deprecated symbols + In VA-API 1.0 the H.264 baseline profile is deprecated. This patch + guards the H.264 baseline usage. Consider this commit as a + continuation of commit e0e0a474 + https://bugzilla.gnome.org/show_bug.cgi?id=784398 + +2017-08-17 12:54:47 +0200 Víctor Manuel Jáquez Leal + + * configure.ac: + * meson.build: + * meson_options.txt: + Revert "build: check for libva-2.0" + This reverts commit 8f2eb70803099d4b533ecc10fc259041d8714210. + https://bugzilla.gnome.org/show_bug.cgi?id=784398 + +2017-08-17 12:44:40 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapicompat.h: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: macro to get a renamed value in VA-API 1.0 + In VA-API 1.0 the union bits in VAEncMiscParameterBufferROI has + renamed one member from roi_value_is_qp_delat to + roi_value_is_qp_delta, which is the correct name. + In order to keep back compatibility a macro has added to access this + union member. + https://bugzilla.gnome.org/show_bug.cgi?id=784398 + +2017-08-22 11:37:28 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.h: + * gst/vaapi/gstvaapipluginutil.c: + plugins: include main gstgl header + Instead including particular gstgl header files in a header file + that doesn't export a gstgl symbol, the main gstgl header file is + included in gstvaapipluginutil.c where the symbols are used. + https://bugzilla.gnome.org/show_bug.cgi?id=786597 + +2017-08-18 18:00:24 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + libs: encoder: h264: fix enum namespace + +2017-08-17 12:26:12 +0100 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 48a5d85 to 3f4aa96 + +2017-08-17 11:03:35 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + libs: encoder: h264: remove spurious assignation + Coverity scan bug: + An assigned value that is never used may represent unnecessary + computation, an incorrect algorithm, or possibly the need for cleanup + or refactoring. + ip_period is assigned first to be rewritter inmediatly after. The + first assignation is spurious. + +2017-08-15 17:36:51 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: fix mismatch of the return type + https://bugzilla.gnome.org/show_bug.cgi?id=786307 + +2017-08-10 13:34:21 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidecoder_unit.h: + * gst-libs/gst/vaapi/gstvaapiminiobject.h: + * gst-libs/gst/vaapi/gstvaapiutils.h: + * gst-libs/gst/vaapi/gstvaapiutils_glx.h: + * gst-libs/gst/vaapi/gstvaapiutils_h264_priv.h: + * gst-libs/gst/vaapi/gstvaapiutils_h265_priv.h: + * gst-libs/gst/vaapi/gstvaapiutils_mpeg2_priv.h: + * gst-libs/gst/vaapi/gstvaapiutils_x11.h: + * gst-libs/gst/vaapi/libgstvaapi_priv_check.h: + * gst-libs/gst/vaapi/meson.build: + libs: remove unused header + Since libgstvaapi is not distributed, there is no need to check for + private header inclusion. Thus removing it. + https://bugzilla.gnome.org/show_bug.cgi?id=786119 + +2017-08-10 13:27:11 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiutils_h264.h: + * gst-libs/gst/vaapi/gstvaapiutils_h264_priv.h: + * gst-libs/gst/vaapi/gstvaapiutils_h265.h: + * gst-libs/gst/vaapi/gstvaapiutils_h265_priv.h: + * gst-libs/gst/vaapi/gstvaapiutils_mpeg2.h: + * gst-libs/gst/vaapi/gstvaapiutils_mpeg2_priv.h: + libs: utils: move gstvaapisurface.h to private headers + Since the utils don't expose API defined in gstvaapisource.h, it is + moved to their private headers where they are used. + https://bugzilla.gnome.org/show_bug.cgi?id=786119 + +2017-08-10 13:26:12 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiutils_h264.c: + * gst-libs/gst/vaapi/gstvaapiutils_h264.h: + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + * gst-libs/gst/vaapi/gstvaapiutils_h265.h: + * gst-libs/gst/vaapi/gstvaapiutils_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiutils_mpeg2.h: + libs: utils: remove va.h include in header + And include gstvaapicompat.h in the C files, since the VA-API is not + exposed in the headers. + https://bugzilla.gnome.org/show_bug.cgi?id=786119 + +2017-08-10 13:24:06 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + libs: encoder: remove va.h include + Since it is already managed by gstvaapicompat.h + https://bugzilla.gnome.org/show_bug.cgi?id=786119 + +2017-08-10 13:11:04 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapicodec_objects.h: + * gst-libs/gst/vaapi/gstvaapicompat.h: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * meson.build: + build: consolidate the VA sub API includes + Include all VA sub APIs headers in a single point (gstvaapicompat.h), + since they are all already included in va.h after VA-API 0.38. + https://bugzilla.gnome.org/show_bug.cgi?id=786119 + +2017-08-10 13:09:27 +0200 Víctor Manuel Jáquez Leal + + * configure.ac: + * meson.build: + build: check for va_vpp.h + Thus, in config.h the macro HAVE_VA_VA_VPP_H is defined. This will + allow us to handle the inclusion of the header better. + https://bugzilla.gnome.org/show_bug.cgi?id=786119 + +2017-08-11 20:22:41 +0100 Tim-Philipp Müller + + * meson.build: + meson: don't export symbols by default + Only plugin entry points should be exported. + +2017-08-09 19:06:59 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + libs: decoder: h265: remove spurious code + Coverity scan: + Logically dead code: The indicated dead code may have performed some + action; that action will never occur. + By using pointer arithmetic is impossible to get NULL. + +2017-08-08 18:52:37 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapicontext.c: + libs: context: use attribs index instead pointers + Coverity scan bug: + Out-of-bounds write. This could cause an immediate crash or incorrect + computations. + Coverity basically found that it is possible to assign more than 4 + attribs in the array. + In my opinion this was produced because code pattern used pointer + arithmetic, which is not readable nor maintainable. + This patch refactors config_create() to use an array index rather than + pointer arithmetic. Also a run-time check for index size was added. + +2017-08-08 17:38:51 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode_h264.c: + vaapiencode: h264: remove spurious code + Coverity scan bug: + An unsigned value can never be negative, so this test will always + evaluate the same way. + As len is guint32, there is no need to check it if it is equal or + bigger than zero. + +2017-08-08 17:34:12 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: initialize variable + Coverity scan bug: + The variable will contain an arbitrary value left from earlier + computations. + Variable base_only is fetched from base-only property, and it may be + not assigned. It needs to be initialized. + +2017-08-08 17:29:54 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + libs: windows: wayland: fail if cannot remove last frame + Converity scan bug: + If the function returns an error value, the error value may be + mistaken for a normal value. + If g_atomic_pointer_compare_and_exchange() fails because the frame is + not the last one, the function fails. Thus, logging an info message. + +2017-08-08 17:21:52 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + libs: utils: glx: check return value + Coverity scan bug: + If the function returns an error value, the error value may be + mistaken for a normal value. + Function sscanf returns the number of assignations done. Validate this + return value with the number of expected variables to match. + +2017-08-08 17:12:06 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiobject.c: + libs: vaapi: object: remove unrequired NULL check + Coverity scan bug: + Dereference after null check: Either the check against null is + unnecessary, or there may be a null pointer dereference. + Variable klass has been validated as non-NULL several time before in + gst_vaapi_object_new() function, so there is no need to check it + again. + +2017-08-08 17:06:17 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: remove spurious assignation + Coverity scan bug: + An assigned value that is never used may represent unnecessary + computation, an incorrect algorithm, or possibly the need for cleanup + or refactoring. + ip_period is assigned first to be rewritter inmediatly after. The + first assignation is spurious. + +2017-08-08 16:50:39 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + libs: encoder: h264: fix copy & paste error + Coverity scan bug: + The copied code will not have its intended effect. + This is a bug from commit cdaf15b2, where the intention is to + initialize RefPicList1 while setting RefPicList0. + +2017-08-08 16:33:44 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: fix possible integer overflow + Coverity scan bug: + Unintentional integer overflow. The expression's value may not be what + the programmer intended, because the expression is evaluated using a + narrow (i.e. few bits) integer type. + Cast operator to guint64 before computation to avoid narrowing. + merge with 3c5a6add + +2017-08-08 16:12:13 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + libs: decoder: mpeg4: fail if return value is not OK + Coverity scan bug: + An assigned value that is never used may represent unnecessary + computation, an incorrect algorithm, or possibly the need for cleanup + or refactoring. + In the return value of decode_slice() or + gst_mpeg4_parse_video_packet_header() are not success, thus fail + decode_packet() function. + +2017-08-08 15:49:27 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + libs: decoder: h265: check for null + Coverity scan bug: + Dereference after null check: Either the check against null is + unnecessary, or there may be a null pointer dereference. + While looking for hte lowest poc, according to rest of the code, the + picture in the dbp (decoded picture buffer) might be NULL, thus we + could check for a NULL picture before assigned as found. + Also, split a comma operator because it is considered as a bad + practice because it possible side effects. + +2017-08-08 15:38:16 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + libs: decoder: h265: untaint loop control variable + Coverity scan bug: + Scalars (for example, integers) are not properly + bounds-checked (sanitized) before being used as array or pointer + indexes, loop boundaries, or function arguments are considered as + tainted. + In this case, num_nals were not checked before used as loop control. + +2017-08-08 13:46:56 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + libs: decoder: h264: remove unrequired NULL check + Coverity scan bug: + Dereference after null check: Either the check against null is + unnecessary, or there may be a null pointer dereference. + In the original commit for fill_picture_gaps() (commit 5abd2b90) the + prev_picture could be NULL, that's why the code did a null check. But, + since commit 52adebe7, the previous reference frames are tracked, thus + there is no need to check null anymore. + +2017-08-03 23:17:44 +0300 orestisf + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: fix gst_caps_new_simple call + https://bugzilla.gnome.org/show_bug.cgi?id=732265 + +2017-07-25 22:25:10 +0300 orestisf + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: force add h264 MVC profiles in caps + When vaapih264dec's base-only profile is set to TRUE, fake MVC profile + support in caps. + https://bugzilla.gnome.org/show_bug.cgi?id=732265 + +2017-07-25 22:54:30 +0300 orestisf + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + libs: decoder: h264: decode MVC base view only + If processed SPS has mvc profile and the configuration is set to + base-only, the frame is drop. + https://bugzilla.gnome.org/show_bug.cgi?id=732265 + +2017-07-25 22:06:56 +0300 orestisf + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode_props.c: + vaapidecode: set h264 base-only to decoder + Set the base-only value when property is set and the internal + decoder is already instantiated or when the internal decoder + is created. + https://bugzilla.gnome.org/show_bug.cgi?id=732265 + +2017-07-25 22:03:34 +0300 orestisf + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.h: + libs: decoder: h264: add setter for base-only mode + https://bugzilla.gnome.org/show_bug.cgi?id=732265 + +2017-07-25 22:01:37 +0300 orestisf + + * gst/vaapi/gstvaapidecode_props.c: + * gst/vaapi/gstvaapidecode_props.h: + vaapidecode_props: h264: add base-only property + https://bugzilla.gnome.org/show_bug.cgi?id=732265 + +2017-08-01 11:11:55 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + libs: encoder: h264: missing property enum documentation + +2017-08-02 14:54:53 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + libs: encoder: h264: add multi reference support + Using num_ref_frames provided and the result of the Query + VAConfigAttribEncMaxRefFrames, it determines the size of reference list + and perform encoding with multi reference frames as the following: + 1\ The num_ref_frames is being considered as the number of + reference picture list0 + 2\ Encoder adds 1 reference frame more to the reference picture list1 + internally if b-frame encoding. + 3\ If num_ref_frames is bigger than the number of refrence frames + supported in the driver, it will be lowered. + https://bugzilla.gnome.org/show_bug.cgi?id=783803 + +2017-08-02 14:53:34 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + libs: encoder: h264: add refs property + Users can provide the number of reference frame by this property. + The value of the property will be considered as the number of + reference picture list0 and will add 1 reference frame more to the + reference picture list1 internally if b-frame encoding. + If the value provided is bigger than the number of refrence frames + supported in the driver, it will be lowered. + https://bugzilla.gnome.org/show_bug.cgi?id=783803 + +2017-07-28 15:27:20 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + libs: encoder: implements gst_vaapi_encoder_ensure_max_num_ref_frames + This function will query VAConfigAttribEncMaxRefFrames to get the + maximum number of reference frames supported in the driver. + This will be used for h264/h265 encoding. + https://bugzilla.gnome.org/show_bug.cgi?id=783803 + +2017-08-01 18:38:40 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode_h265.c: + vaapiencode: h265: compare an unsigned int if not zero + An unsigned value can never be negative, so this test (greater than + zero) will always evaluate the same way. Thus change it to just if + it's not zero. + +2017-08-01 18:10:50 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: check gst_gl_ensure_element_data() return value + Refactor gst_vaapi_plugin_base_create_gl_context() in order to check + the return value of gst_gl_ensure_element_data(). The result is a code + bit cleaner. + +2017-08-01 17:59:38 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + plugins: avoid dead code detection + By using #elif macro, the static code analysis would stop to detect + these lines as dead code. Also it is inforced the mutually exclusive + environments. + +2017-08-01 17:39:04 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapivideobufferpool: don't shift by negative since it's undefined + The function g_bit_nth_lsf() may return -1 if the request bit position + is not avaible. Thus, this patch check if the return value is not -1 + in order to continue. + +2017-08-01 17:29:40 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapisink.c: + vaapisink: fix memory leak + +2017-08-01 17:23:48 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostprocutil.c: + vaapipostproc: fix memory leaks + +2017-07-27 10:54:00 +0000 Tomas Rataj + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + libs: display: when appending formats change pointers to indexes + Thus, it fixes an invalid read when YV12 or I420 are not supported by + the driver. + https://bugzilla.gnome.org/show_bug.cgi?id=785085 + +2017-07-19 12:02:40 -0700 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + libs: encoder: h264: Add uncompliant mode reducing coded buffer size + Added a new property "compliance-mode", which default is the normal + strict compliant mode. + The second mode, "restrict-buf-alloc", is to limit the coded buffer + allocation size to improve performance in some specific Intel + platforms (there is asignificant performance improvement in parallel + encodings). Under this new mode, we use the MinCR field in A.3.1 for + pre-calculating the coded-buffer size. + https://bugzilla.gnome.org/show_bug.cgi?id=784590 + +2017-07-05 17:13:44 -0700 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiutils_h264.c: + * gst-libs/gst/vaapi/gstvaapiutils_h264_priv.h: + libs: utils_h264: Extend LevelLimit table with MinCR field + Add MinCR(Minimum Compression Ratio) field to GstVaapiH264LevelLimits + based on Annex A.3 + https://bugzilla.gnome.org/show_bug.cgi?id=784590 + +2017-07-11 17:29:13 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiutils.c: + libs: utils: libva 1.0 changed the logging + The logging mechanism in libva has changed it's functions + signatures. This patch updates that for libva versions >= 1.0 + https://bugzilla.gnome.org/show_bug.cgi?id=784398 + +2017-07-11 17:27:32 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + libs: decoder: h264: libva 1.0 deprecated baseline + libva 1.0 deprecated H.264 baseline profile and FMO support + (commit b4f332b3). + https://bugzilla.gnome.org/show_bug.cgi?id=784398 + +2017-07-26 20:03:35 +0200 Víctor Manuel Jáquez Leal + + * configure.ac: + * meson.build: + * meson_options.txt: + build: check for libva-2.0 + Check for libva-2.0 since libva's developers decided to increase the + library's version number. + https://bugzilla.gnome.org/show_bug.cgi?id=784398 + +2017-07-11 16:55:26 +0200 Víctor Manuel Jáquez Leal + + * configure.ac: + * meson.build: + build: blacklist only libva 0.99.0 + Intel's MSDK uses libva 0.99.0, meanwhile open source libva bumped + its API version to 1.0.0. Thus we have to blacklist only the MSDK's + libva (0.99.0) + https://bugzilla.gnome.org/show_bug.cgi?id=784398 + +2017-07-26 20:30:37 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/meson.build: + build: meson: remove gstvaapidisplaycache.c + This is a missing bit of commit ec3e10f6 + +2017-07-26 09:53:10 -0700 U. Artie Eoff + + * configure.ac: + configure: do not break configure if gtk+-3.0 devel missing + Fix PKG_CHECK_MODULES rule for with_gtk=check condition to + set USE_GTK=0 if gtk+-3.0 is not available. + Since commit 85856c29a70d6de4aea5b708e04e9eb418190623 + Author: Hyunjun Ko + Date: Wed Jul 5 15:59:43 2017 +0900 + tests: elements: add testsuite of vaapi context + ...configure fails if gtk+-3.0 development files are missing. + The "with_gtk" option defaults to "check" in configure.ac + which implies that if it is not explicitly requested then + configure will only enable it if it's available on the system. + However, the PKG_CHECK_MODULES rule that get's activated on + "check" condition did not provide default when gtk+-3.0 devel + packages are not found on the system. Thus, it resulted in + configure failure. + Signed-off-by: U. Artie Eoff + https://bugzilla.gnome.org/show_bug.cgi?id=785452 + +2017-07-05 15:59:43 +0900 Hyunjun Ko + + * configure.ac: + * tests/elements/Makefile.am: + * tests/elements/test-vaapicontext.c: + tests: elements: add testsuite of vaapi context + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=766704 + +2017-07-05 15:32:43 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapisink.c: + vaapisink: fail if surface display is different + Replacing GstVaapiDisplay during rendering might be hiding problems + at some cases, even though it's safe currently since we use cache + of GstVaapidisplay. + Play safe by failing if this happens. + https://bugzilla.gnome.org/show_bug.cgi?id=766704 + +2017-07-05 15:31:55 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapivideocontext.c: + * gst/vaapi/gstvaapivideocontext.h: + videocontext: support "gst.vaapi.app.Display" context + Through "gst.vaapi.app.Display" context, users can set their own VADisplay + and native display of their backend. + Attributes: + - display : pointer of VADisplay + - x11-display : pointer of X11 display (Display *), if they're using. + This patch creates GstVaapidisplayX11 if information provided through + "gst.vaapi.app.Display" + https://bugzilla.gnome.org/show_bug.cgi?id=766704 + +2017-07-05 14:33:38 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.h: + libs: display: x11: add gst_vaapi_display_x11_new_with_va_display() + Implements new API function so that users could create GstVaapiDisplay + with their own VADisplay within a native display as backend. + https://bugzilla.gnome.org/show_bug.cgi?id=766704 + +2017-07-05 14:32:35 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + libs: display: pass display info when foreign display + When creating a GstVaapiDisplay using a foreign VADisplay, and render + with that display, it also requires native display of the backend. + https://bugzilla.gnome.org/show_bug.cgi?id=766704 + +2017-06-26 21:18:25 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplaycache.c: + * gst-libs/gst/vaapi/gstvaapidisplaycache.h: + libs: display: remove cache + Remove a bunch of code that handles the VADisplay cache, since the + context sharing should be doing this correctly. + https://bugzilla.gnome.org/show_bug.cgi?id=747946 + +2017-07-13 10:56:18 +0900 Hyunjun Ko + + * tests/elements/Makefile.am: + * tests/elements/test-vaapipostproc.c: + tests: elements: add test for vaapipostproc + https://bugzilla.gnome.org/show_bug.cgi?id=754885 + +2017-07-12 18:25:15 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapipostproc.c: + postproc: reconfigure when width or height changes + https://bugzilla.gnome.org/show_bug.cgi?id=754885 + +2017-07-17 18:53:57 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + libs: encoder: vp9: array terminated in zeros + There is a crash when setting ref-pic-mode since the #GEnumValue + array is not terminated with a structured with all memvers being + zero. + https://bugzilla.gnome.org/show_bug.cgi?id=785032 + +2017-07-13 16:43:34 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode_h264.c: + vaapiencode: h264: add plugin documentation + Comment how the profile is set and other parameters. + +2017-05-26 15:19:00 +0000 Matt Staples + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + libs: decoder: h264: push frames as soon as possible + Push frames downstream as soon as possible instead of waiting until + they are ejected from the DPB. + This patch makes the decoder not comply with the H.264 specification, + but it is required for some video cameras. + https://bugzilla.gnome.org/show_bug.cgi?id=762509 + Signed-off-by: Víctor Manuel Jáquez Leal + +2017-07-10 19:27:57 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode_props.c: + vaapidecode_props: h264: set low-latency in decoder + Set the low-latency property if the H264 decoder is already + instantiated, thus you could change the behavior in run-time. + https://bugzilla.gnome.org/show_bug.cgi?id=783588 + +2017-07-06 20:00:15 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: set h264 low latency to decoder + https://bugzilla.gnome.org/show_bug.cgi?id=783588 + +2017-06-14 18:30:53 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.h: + libs: decoder: h264: add getter/setter for low latency mode + https://bugzilla.gnome.org/show_bug.cgi?id=783588 + +2017-06-14 18:31:18 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode_props.c: + * gst/vaapi/gstvaapidecode_props.h: + vaapidecode_props: h264: add low latency property + Adding support for private data. + https://bugzilla.gnome.org/show_bug.cgi?id=783588 + +2017-06-14 18:23:34 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode_props.c: + * gst/vaapi/gstvaapidecode_props.h: + * gst/vaapi/meson.build: + vaapidecode_props: add skeleton for h264 decoder properties + https://bugzilla.gnome.org/show_bug.cgi?id=783588 + +2017-06-14 17:07:30 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: properties callback in decoders map + https://bugzilla.gnome.org/show_bug.cgi?id=783588 + +2017-07-07 12:01:59 +0100 Tim-Philipp Müller + + * meson.build: + meson: find python3 via python3 module + https://bugzilla.gnome.org/show_bug.cgi?id=783198 + +2017-06-09 14:47:40 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + libs: encoder: h264: submit sps in case of IDR picture + If the picture is IDR, also submit a SPS header. + This means when frame number reaches to keyframe-period or an force + key unit event arrives, we insert SPS/PPS again. + https://bugzilla.gnome.org/show_bug.cgi?id=776712 + +2017-06-09 14:47:16 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + libs: encoder: h264: set the frame as IDR if forced key unit + GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME() is a flag usually used to manage + the `frame-lost` event in the case of streaming, such as RTP. + In case of this event, it is needed to start new GOP rather than just + produce an I-frame. + https://bugzilla.gnome.org/show_bug.cgi?id=776712 + +2017-04-05 14:48:46 -0700 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + libs: encoder: h264: insert AU delimiter + Insert an AUD as the first NAL of each encoded frame. + Some applications require Access Unit Delimiter for decoding the + stream. + The AU delimeter insertion is done only when the aud parameter is + TRUE (by default is disabled). The reason of this it is because this + header is only available from Intel Gen9 and the VA intel driver + should be 1.8 or superior. Otherwise, the output will be corrupted. + https://bugzilla.gnome.org/show_bug.cgi?id=776712 + Signed-off-by: Victor Jaquez + +2017-06-29 12:50:26 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + libs: encoder: h264: initialize all elements of view_ids + Currently when num_views is changed by multiview-mode on sink caps, it produces + wrong MVC encoded stream since the array view_ids is not set properly according + to changed num_views. + So this patch initializes all of the array sequentially to handle this case. + Side effect is not going to happen by this patch since this array is being + handled by num_views. + https://bugzilla.gnome.org/show_bug.cgi?id=784321 + +2017-06-27 14:30:54 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + Revert "encoder: h264: Use high profile by default" + This reverts commit 4aec5bdd7207fc0e45813ef14c9c0ad5174a8f75. + https://bugzilla.gnome.org/show_bug.cgi?id=757941 + +2017-06-27 16:03:37 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + libs: encoder: h264: set profile via capsfilter + Until now, the encoder ignored the profile in src caps and chose one + according with the given parameters. But the encoder must honor the + profile specifed in src caps. + This patch do that, and if the encoder needs to choose the profile, + it will do it by following these rules: + 1\ If given parameters are not compatible with given profile, the + encoder will bail out with an error. + 2\ The encoder will choose the higher profile indicated in the + src caps. + https://bugzilla.gnome.org/show_bug.cgi?id=757941 + +2017-06-27 13:14:31 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapiencode_h264.c: + vaapiencode: h264: set profile to src caps + So far vaapi encoder does not set profile to src caps. This patch makes it + setting profile to src caps, which is determined by itself. + In addition, if encoder chose different profile, which is not negotiated with + downstream, we should set compatible profile to make negotiation working. + https://bugzilla.gnome.org/show_bug.cgi?id=757941 + +2017-06-22 09:56:49 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h264.h: + vaapiencode: h264: verify if requested profile is supported + Check if the requested profile in source caps, is supported by the + VA driver. If it is not, an info log message is send saying that + another (compatible?) profile will be used. + https://bugzilla.gnome.org/show_bug.cgi?id=757941 + +2017-06-21 21:49:27 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode_h264.c: + vaapiencode: h264: improve set_config() vmethod + First check if downstream requests ANY caps. If so, byte-stream is + used and the profile will be choose by the encoder. If dowstream + requests EMPTY caps, the negotiation will fail. + Lately, byte-stream and profile are looked in the allowed caps. + https://bugzilla.gnome.org/show_bug.cgi?id=757941 + +2017-06-21 19:30:55 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode_h264.c: + vaapiencode: h264: check for avc in set_config() + The check for avc stream format was done in the vaapi encoder's + vmethod get_caps(), but that is wrong since it has to be check + when encoder set_format(). + https://bugzilla.gnome.org/show_bug.cgi?id=757941 + +2017-06-29 12:49:24 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapipostprocutil.c: + vaapipostproc: set multivew-mode flags to src caps + vaapipostproc didn't negotiate the proper multiview caps losing + downstream information. + This patch enables the playing of MVC encoded stream by setting + the proper multiview mode/flags and views to src caps, according + to sink caps. + https://bugzilla.gnome.org/show_bug.cgi?id=784320 + +2016-11-22 15:52:47 +0000 Julien Isorce + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: add support for DMABuf caps feature + https://bugzilla.gnome.org/show_bug.cgi?id=755072 + Signed-off-by: Julien Isorce + +2017-06-01 19:42:20 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: add support for DMABuf caps feature + https://bugzilla.gnome.org/show_bug.cgi?id=755072 + Original-patch-by: Julien Isorce + +2017-06-23 12:12:12 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + vaapipluginbase: force dmabuf allocator if DMABuf caps feature + Instantiate all dmabuf allocator for src pad buffer pool if the + src caps ask for memory:DMABuf feature. + https://bugzilla.gnome.org/show_bug.cgi?id=755072 + +2016-11-22 23:26:05 +0000 Julien Isorce + + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + vaapipluginutil: add support for DMABuf caps feature + https://bugzilla.gnome.org/show_bug.cgi?id=755072 + Signed-off-by: Julien Isorce + Signed-off-by: Victor Jaquez + vaapipluginutil: add support for DMABuf caps feature + +2017-06-01 19:13:52 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + vaapipluginbase: dmabuf memory map trial for raw caps + Only push dmabuf-based buffers with raw caps if gst_memory_map() + succeeds. Otherwise, use the the vaapi surfaces allocator. + https://bugzilla.gnome.org/show_bug.cgi?id=755072 + https://bugzilla.gnome.org/show_bug.cgi?id=774649 + Original-patch-by: Julien Isorce + +2016-06-08 19:11:15 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + vaapivideomemory: add gst_vaapi_dmabuf_can_map() + This new method checks the specified allocator can create GstMemory that can + be mapped. + https://bugzilla.gnome.org/show_bug.cgi?id=755072 + +2017-06-23 17:33:03 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapivideobufferpool: fix regression with video metas + There is another regression with 7a206923 when setting the video + info for the video meta, it should be the one from the image's + allocator rather from the allocation caps. + Test pipeline: + gst-launch-1.0 filesrc location=bug766184.flv ! decodebin \ + ! tee ! videoconvert ! videoscale \ + ! video/x-raw, width=1920, height=1080 ! xvimagesink + +2017-06-23 14:38:10 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapivideobufferpool.c: + plugins: update buffer size with the one reported by allocator + There is a regression in 7a206923, since the buffer pool ditches all + the buffers generated by them because the pool config size is + different of the buffer's size. + Test pipeline: + gst-launch-1.0 filesrc location=big_buck_bunny_1080p_h264.mov \ + ! qtdemux ! vaapih264dec ! vaapipostproc ! xvimagesink \ + --gst-debug=GST_PERFORMANCE:5 + The allocator may update the buffer size according to the VA surface + properties. In order to do this, the video info is modified when the + allocator is created, which reports through the allocation info the + updated size, and set it to the pool config. + +2017-06-14 21:40:33 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + libs: decoder: h264: initialize active_sps/pps in reset + Since commits in https://bugzilla.gnome.org/show_bug.cgi?id=781142 landed, + they introduced regression in seek. + Formerly, once seek is done, decoder drops P-frames until I-frame arrives. + But since the commits landed, it doesn't drop P-frame and does try to + decode it continuously because active_sps is still alive. See ensure_sps function. + But there are prev_frames and prev_ref_frames reset already, then it + causes assertion. + So it's necessary to reset active_sps/pps also in reset method. + https://bugzilla.gnome.org/show_bug.cgi?id=783726 + +2017-06-15 13:24:56 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + libs: encoder: fix compilation with old versions of libva + There are some symbols that are not used when compiling with old + version of libva and those generates a compilation error. + Original-patch-by: Matt Staples + +2017-06-09 14:02:20 -0700 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: Fix the quality level clamping + Change the hard-coded range of quality-level from {1-8} to {1-7}, + since it is the range Intel Open source driver supports. + Also perform the range clamping only if the user provided + quality-level is greater than the max-range suppored by the driver, + because there could be non-intel drivers giving lower value than + the hard-coded max value 7. + https://bugzilla.gnome.org/show_bug.cgi?id=783567 + +2017-04-06 19:35:27 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + libs: encoder: log out the name of the profile + Instead of printing a number, it is more readable to log out, in + case of error, the name of the failing profile. + +2017-05-31 12:36:17 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + libs: encoder: h264: changes raw number of profile to macro name of its + Changes raw number of profile to macro name of its to improve readability. + https://bugzilla.gnome.org/show_bug.cgi?id=757941 + +2017-06-09 17:00:40 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapivideobufferpool: remove allocation_vinfo private attribute + There is no need to keep this attribute internally since it is + already managed by the allocator. + https://bugzilla.gnome.org/show_bug.cgi?id=783599 + +2017-06-09 15:02:08 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapivideobufferpool: refactor set_config() + Refactor the set_config() virtual method considering a cleaner + approach to allocator instanciation, if it it not set or if it is + not valid for the pool. + https://bugzilla.gnome.org/show_bug.cgi?id=783599 + +2017-06-09 13:05:36 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapivideobufferpool.c: + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + plugins: distinguish allocation and negotiation caps + The vaapi video decoders might have different allocation caps from + the negotiation caps, thus the GstVideoMeta shall use the negotiation + caps, not the allocation caps. + This was done before reusing gst_allocator_get_vaapi_video_info(), + storing there the negotiation caps if they differ from the allocation + ones, but this strategy felt short when the allocator had to be reset + in the vaapi buffer pool, since we need both. + This patch adds gst_allocator_set_vaapi_negotiated_video_info() and + gst_allocator_get_vaapi_negotiated_video_info() to store the + negotiated video info in the allocator, and distinguish it from + the allocation video info. + https://bugzilla.gnome.org/show_bug.cgi?id=783599 + +2017-06-08 19:32:35 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + vaapivideomemory: rename qdata quarks and ids + Also the parameter names were renamed to reflect their origin + and purpose. + https://bugzilla.gnome.org/show_bug.cgi?id=783599 + +2017-06-08 16:05:49 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapivideobufferpool: rename local variables + Renamed local video info structure names in set_config() vitual + method. The purpose of their renaming is to clarify the origin + of those structures, whether come from passed caps parameter + (new_allocation_vinfo) or from the configured allocator + (allocator_vinfo). + https://bugzilla.gnome.org/show_bug.cgi?id=783599 + +2017-06-08 15:49:05 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapivideobufferpool: rename video info structures + Renamed private GstVideoInfo structure video_info to allocation_vinfo + and alloc_info to negotiated_vinfo. + The purpose of these renaming is to clarify the origin and purpose of + these private variables: + video_info (now allocation_vinfo) comes from the bufferpool + configuration. It describes the physical video resolution to be + allocated by the allocator, which may be different from the + negotiated one. + alloc_info (now vmeta_vinfo) comes from the negotiated caps in + the pipeline. It represents how the frame is going to be mapped + using the video meta. + In Intel's VA-API backend, the allocation_vinfo resolution is + bigger than the negotiated_info. + https://bugzilla.gnome.org/show_bug.cgi?id=783599 + +2017-06-08 12:51:50 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: set framerate if bigger than 0/1 + Just set the framerate parameter if the framerate numerator and + denominator are bigger than zero. + Otherwise, in Intel Gen6 driver, a warning is raised disabling the + bitrate control. + Original-patch-by: Hyunjun Ko + https://bugzilla.gnome.org/show_bug.cgi?id=783532 + +2017-06-07 12:32:53 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: bitrate target percentage calculation + If the rate control is set to Constant Bit Rate (CBR) the target + percentage is 100%, otherwise is 70% + +2017-06-07 12:25:24 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + libs: encoder: h264,h265,mpeg2,vp8,vp9: refactor ratecontrol param + Centralize the common configuration for the Rate Control parameter, + thus can be overloaded per each specific encoder. + +2017-06-07 11:10:49 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + libs: encoder: h264,h265,mpeg2,vp8,vp9: refactor framerate param + Since the framerate VA parameter is calculated equally among all the + encoders, it is better to handle it in the base encoder class. + +2016-08-09 15:53:47 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.h: + libs: encoder: vp9: Adds CBR and VBR Encoding support + https://bugzilla.gnome.org/show_bug.cgi?id=766832 + Signed-off-by: Hyunjun Ko + Signed-off-by: Víctor Manuel Jáquez Leal + +2017-06-01 12:12:26 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + libs: encoder: vp8: Adds VBR Encoding support + https://bugzilla.gnome.org/show_bug.cgi?id=778732 + +2017-06-01 12:11:12 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: Adds VBR Encoding support + Enables Variable BitRate mode, which does set FrameRate and RateControl + parameters. + https://bugzilla.gnome.org/show_bug.cgi?id=778732 + +2017-06-02 13:50:05 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: Describes more detail about the bitrate property + https://bugzilla.gnome.org/show_bug.cgi?id=778732 + +2017-06-05 20:44:22 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: add rate control parameter + https://bugzilla.gnome.org/show_bug.cgi?id=783449 + +2017-06-05 20:33:27 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + libs: encoder: h264,h265,mpeg2: add framerate parameter + https://bugzilla.gnome.org/show_bug.cgi?id=783449 + +2017-06-05 20:30:07 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + libs: encoder: vp8,h264,h265,mpeg2: set misc param once + Instead of recalculating the miscellaneous buffer parameters for + every buffer, it is only done once, when the encoder is configured. + And for every buffer, the same structures are just copied. + https://bugzilla.gnome.org/show_bug.cgi?id=783449 + +2017-06-05 17:31:10 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + libs: encoder: vp8,h264,h265,mpeg2: refactor misc parameters + This is patch pretends to decouple the assignation of the values + in the parameter structures and the VA buffer's parameters setting. + It may lead to some issues since HRD, framerate or controlrate may + not be handled by the specific encoder, but they are set in + the VA buffer's parameters. + I leave as it because this patch is just a transitional patch. + https://bugzilla.gnome.org/show_bug.cgi?id=783449 + +2017-06-05 16:34:12 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + libs: encoder: vp8: fix frame rate calculation + According to the VA documentation: + The framerate is specified as a number of frames per second, + as a fraction. The denominator of the fraction is given in + the top half (the high two bytes) of the framerate field, and + the numerator is given in the bottom half (the low two bytes). + For example, if framerate is set to (100 << 16 | 750), this is + 750 / 100, hence 7.5fps. + If the denominator is zero (the high two bytes are both zero) + then it takes the value one instead, so the framerate is just + the integer in the low 2 bytes. + This patch fixes the the framerate calculation in vp8 encoder + according to this. + https://bugzilla.gnome.org/show_bug.cgi?id=783449 + +2017-06-02 19:46:52 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + libs: encoder: vp8: refactor FrameRate parameter + Move frame-rate parameter from ensure_misc_params() to + ensure_contro_rate_param() since it only has meaning when the + control rate is either VBR or CBR. + https://bugzilla.gnome.org/show_bug.cgi?id=783449 + +2017-06-02 19:33:36 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + libs: encoder: h264,h265,mpeg2,vp8: refactor HDR + Move the Hypothetical Reference Decoder (HRD) parameter, from + ensure_misc_params() to ensure_control_rate_params(), since it + only shall be defined when the control rate is either VBR or CBR. + https://bugzilla.gnome.org/show_bug.cgi?id=783449 + +2017-06-02 17:21:25 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + libs: encoder: h264,vp8,mpeg2: refactor control rate + Instead of filling the control rate param in ensure_misc_params(), + this patch refactor it out, as a first step to merge the same code + for all the encoders. + https://bugzilla.gnome.org/show_bug.cgi?id=783449 + +2017-06-02 16:28:30 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + libs: encoder: h264, h265, mpeg2: remove assert + Remove spurious asserts for misc parameters. If they cannot be + allocated, FALSE is already returned. + +2017-06-05 18:19:05 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + libs: encoder: use VA quality level structure + Instead of using a proxy to story the buffer quality level, the + encoder now uses the native VA structure, which is copied to the + dynamically allocated VAEncMiscParameterBuffer. + This approach is computationally less expensive. + +2017-05-26 11:10:34 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + libs: standardize the FIXME comment + This is a trivial patch that makes homogeneous the FIXME tag in + comments. + For more info about these comment style: + http://wiki.c2.com/?FixmeComment + +2017-05-22 17:20:45 +0200 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + libs: encoder: vp8: set quality level regardless of rate control mode + https://bugzilla.gnome.org/show_bug.cgi?id=782957 + +2017-05-15 18:38:29 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + libs: encoder: check for maximum number of slices + Right now, H264 and HEVC can set as a property the number of slices to + process. But each driver can set a maximum number of slices, depending + on the supported profile & entry point. + This patch verifies the current num_slices to process against the maximum + permitted by the driver and the media size. + https://bugzilla.gnome.org/show_bug.cgi?id=780955 + +2017-05-15 18:36:21 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiutils_h26x_priv.h: + libs: utils: mark functions as internals + The functions in this header are internal to the library. + +2017-05-15 18:35:40 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapicontext.h: + libs: context: add missing documentation + Document the region-of-interest configuration variables. + +2017-05-12 18:46:50 +0200 Víctor Manuel Jáquez Leal + + * tests/elements/test-vaapisink.c: + tests: elements: vaapisink: handle nav events + The test app can now handle navigation events to rotate the + display. + +2017-05-12 18:17:55 +0200 Víctor Manuel Jáquez Leal + + * tests/elements/test-vaapisink.c: + tests: elements: clean up vaapisink test + - Use gst_element_send_event() instead of gst_pad_push_event() + - don't zero App structure + - check for pipeline parsing error + - only get vaapisink for property set + +2017-05-12 13:08:30 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapisink.c: + vaapisink: keep handle_events flag except that if user want to set + When state of vaapisink is changed from PLAYING to NULL, the handle_events + flag is set to FALSE, and never recovered, and then event thread is never + going to run. + So we should allow to set the flag only when users try it. + https://bugzilla.gnome.org/show_bug.cgi?id=782543 + +2017-05-12 13:06:24 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + libs: window: x11: fix src rect info when using vpp + Since we started using VPP in VaapiWindowX11, we need to care about + the case that src rect and window's size are different. + So, once VPP has converted to other format, we should honor the + size of the VPP's surface as source rect. Otherwise, it is cropped + according the previous size of the source rect. + https://bugzilla.gnome.org/show_bug.cgi?id=782542 + +2017-04-28 15:20:01 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + plugins: remove par from caps negotiation + https://bugzilla.gnome.org/show_bug.cgi?id=781759 + +2017-03-30 17:57:42 +0900 Hyunjun Ko + + * tests/elements/Makefile.am: + * tests/elements/test-roi.c: + tests: elements: add an example for ROI + This implements a pipleint to recognize difference between ROI and non-ROI. + See comments in this code in detail. + https://bugzilla.gnome.org/show_bug.cgi?id=768248 + Signed-off-by: Víctor Manuel Jáquez Leal + +2017-03-30 17:54:20 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode_h264.c: + vaapiencode: handle custom event GstVaapiEncoderRegionOfInterest + Handles new custom event GstVaapiEncoderRegionOfInterest + to enable/disable a ROI region. + Writes a way to use new event to document. + https://bugzilla.gnome.org/show_bug.cgi?id=768248 + Signed-off-by: Víctor Manuel Jáquez Leal + +2017-02-23 18:53:18 +0900 Hyunjun Ko + + * tests/simple-encoder.c: + tests: simple-encoder: add an option to set ROI + $ simple-encoder -r inputfile.y4m + And you'll got an output file in H264 with two regions of interest. + https://bugzilla.gnome.org/show_bug.cgi?id=768248 + Signed-off-by: Víctor Manuel Jáquez Leal + +2017-02-23 18:52:48 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + libs: encoder: h264: set ROI params during encoding + Set ROI params during encoding each frame, which are set via + gst_vaapi_encoder_add_roi () + https://bugzilla.gnome.org/show_bug.cgi?id=768248 + Signed-off-by: Víctor Manuel Jáquez Leal + +2017-03-28 17:41:37 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + libs: encoder: add api gst_vaapi_encoder_add/del_roi + Implements and exposes new api gst_vaapi_encoder_add/del_roi to set ROI regions. + https://bugzilla.gnome.org/show_bug.cgi?id=768248 + +2017-02-23 17:57:07 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder/context: query region of interest support + Queries if the driver supports "Region of Interest" (ROI) during the config + creation. + This attribute conveys whether the driver supports region-of-interest (ROI) + encoding, based on user provided ROI rectangles. The attribute value is + partitioned into fields as defined in the VAConfigAttribValEncROI union. + If ROI encoding is supported, the ROI information is passed to the driver + using VAEncMiscParameterTypeROI. + https://bugzilla.gnome.org/show_bug.cgi?id=768248 + Signed-off-by: Víctor Manuel Jáquez Leal + +2017-05-12 11:11:48 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_objects.h: + libs: encoder: fix a comment + +2017-05-11 12:23:28 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: guard quality level configuration + The quality level appeared in VA-API 0.36. So let's guard its + usage. + +2017-04-19 13:04:44 -0700 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_objects.h: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + encoders: add quality level tuning + This patch adds the handling of VAEncMiscParameterTypeQualityLevel, + in gstreamer-vaapi encoders: + The encoding quality could be set through this structure, if the + implementation supports multiple quality levels. The quality level set + through this structure is persistent over the entire coded sequence, or + until a new structure is being sent. The quality level range can be queried + through the VAConfigAttribEncQualityRange attribute. A lower value means + higher quality, and a value of 1 represents the highest quality. The quality + level setting is used as a trade-off between quality and speed/power + consumption, with higher quality corresponds to lower speed and higher power + consumption. + The quality level is set by the element's parameter "quality-level" with a + hard-coded range of 1 to 8. + Later, when the encoder is configured in run time, just before start + processing, the quality level is scaled to the codec range. If + VAConfigAttribEncQualityRange is not available in the used VA backend, then + the quality level is set to zero, which means "disabled". + All the available codecs now process this parameter if it is available. + https://bugzilla.gnome.org/show_bug.cgi?id=778733 + Signed-off-by: Víctor Manuel Jáquez Leal + +2017-05-04 18:59:31 +0300 Sebastian Dröge + + * configure.ac: + * meson.build: + Back to development + +=== release 1.12.0 === + +2017-05-04 15:46:03 +0300 Sebastian Dröge + + * ChangeLog: + * NEWS: + * configure.ac: + * gstreamer-vaapi.doap: + * meson.build: + Release 1.12.0 + +2017-05-04 11:49:33 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecodebin.c: + Revert "vaapidecodebin: fix element's classification" + This reverts commit 8cbe03599a4f27c2001380e2ec150c4f4267a9cf. + +2017-04-27 22:55:27 -0700 Scott D Phillips + + * configure.ac: + * meson.build: + build: Require libva < 0.99.0 + libva >= 0.99.0 is not currently supported by gstreamer-vaapi, so + fail to configure instead of failing late in the build. + This libva is bundled in msdk[1] and it is ahead in time with + respect the official and open source libva[2]. GStreamer-VAAPI + only supports the latter for now. + 1. https://software.intel.com/en-us/media-sdk/download + 2. https://github.com/01org/libva/ + https://bugzilla.gnome.org/show_bug.cgi?id=781866 + +2017-05-02 14:08:54 +0200 Victor Toso + + * gst/vaapi/gstvaapidecodebin.c: + vaapidecodebin: fix element's classification + This bin should have similar classification as decodebin which is + "Generic/Bin/Decoder" otherwise it will appear wrongly as video + decoder. + Signed-off-by: Victor Toso + https://bugzilla.gnome.org/show_bug.cgi?id=782063 + +=== release 1.11.91 === + +2017-04-27 17:49:52 +0300 Sebastian Dröge + + * ChangeLog: + * NEWS: + * configure.ac: + * gstreamer-vaapi.doap: + * meson.build: + Release 1.11.91 + +2017-04-27 13:08:56 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + Revert "plugins: reject pixel-aspect-ratio with value 0/1" + This reverts commit c0be7b1890ea8da915a81ae82bc9f504aee7cc26. + +2017-04-27 12:43:54 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + plugins: reject pixel-aspect-ratio with value 0/1 + Do not negotiate a pixel-aspect-ratio of 0/1. + https://bugzilla.gnome.org/show_bug.cgi?id=781759 + +2017-04-26 15:48:01 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostprocutil.c: + * gst/vaapi/gstvaapisink.c: + plugins: handle pixel-aspect-ratio with value 0/1 + When downstream negotiates a pixel-aspect-ratio of 0/1, the + calculations for resizing and formatting in vaapipostproc and + vaapisink, respectively, failed, and thus the pipeline. + This patch handles this situation by converting p-a-r of 0/1 to + 1/1. This is how other sinks, such as glimagesink, work. + https://bugzilla.gnome.org/show_bug.cgi?id=781759 + +2017-04-27 14:42:55 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapivideobufferpool: fix leak of created allocator + Since it's created by itself, it should be unref-counted + after gst_buffer_pool_config_set_allocator call. Afterwards, + this allocator will be ref-counted again when assigning to priv->allocator. + https://bugzilla.gnome.org/show_bug.cgi?id=781577 + +2017-04-21 19:07:18 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapivideobufferpool: create or reconfig allocator + Sometimes a video decoder could set different buffer pool + configurations, because their frame size changes. In this case we + did not reconfigure the allocator. + This patch enables this use case, creating a new allocator inside + the VAAPI buffer pool if the caps changed, if it is not dmabuf-based. + If so, it is just reconfigured, since it doesn't have a surface pool. + https://bugzilla.gnome.org/show_bug.cgi?id=781577 + +2017-04-25 12:58:44 +0200 Víctor Manuel Jáquez Leal + + * tests/elements/Makefile.am: + test: elements: fix compilation flags + This issue was spotten on bug #766704 + Original-patch-by: Hyunjun Ko + +2017-04-25 16:23:08 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + libs: windows: wayland: fix leak if failure of sync + Sometimes gst_vaapi_window_wayland_sync returns FALSE when poll returns EBUSY + during destruction. + In this case, if GstVaapiWindow is using vpp, leak of vpp surface happens. + This surface is not attached to anything at this moment, so we should release + it manually. + https://bugzilla.gnome.org/show_bug.cgi?id=781695 + +2017-04-24 20:30:30 +0100 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 60aeef6 to 48a5d85 + +2017-04-21 15:30:09 +0200 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + libs: window: wayland: mark frames as done + When the frame listener callbacks 'done', the number of pending + frames are decreased. Nonetheless, there might be occasions where + the buffer listener callbacks 'release', without calling previously + frame's 'done'. This leads to problem with + gst_vaapi_window_wayland_sync() operation. + This patch marks as done those frames which were callbacked, but if + the buffer callbacks 'release' and associated frame is not marked + as 'done' it is so, thus the number of pending frames keeps correct. + https://bugzilla.gnome.org/show_bug.cgi?id=780442 + Signed-off-by: Víctor Manuel Jáquez Leal + +2017-04-21 14:07:44 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + libs: window: wayland: don't sync at destroy() + Don't call gst_vaapi_window_wayland_sync() when destroying the + wayland window instance, since it might lead to a lock at + gst_poll_wait() when more than one instances of vaapisink are + rendering in the same pipeline, this is because they share the + same window. + Since now all the frames are freed we don't need to freed the + private last_frame, since its address is invalid now. + https://bugzilla.gnome.org/show_bug.cgi?id=780442 + Signed-off-by: Hyunjun Ko + +2017-04-19 10:37:19 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + libs: window: wayland: null buffer at destroy() + Fix leakage of the last wl buffer. + VAAPI wayland sink needs to send a null buffer while destruction, + it assures that all the wl buffers are released. Otherwise, the last + buffer's callback might be not called, which leads to leak of + GstVaapiDisplay. + This was inspired by gstwaylandsink. + https://bugzilla.gnome.org/show_bug.cgi?id=774029 + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-10-30 10:43:49 +0900 Jagyum Koo + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + libs: window: wayland: rt event queue at destroy() + The proxy object of wl_buffer for the last frame remains in the + wl_map. Even though we call wl_buffer_destroy() in + frame_release_callback(), the proxy object remains without being + removed, since proxy object is deleted when wayland server sees the + delete request and sends 'delete_id' event. + We need to call roundtrip before destroying event_queue so that the + proxy object is removed. Otherwise, it would be mess up as receiving + 'delete_id' event from previous play, when playing in the next + va/wayland window with the same wl_display connection. + https://bugzilla.gnome.org/show_bug.cgi?id=773689 + Signed-off-by: Víctor Manuel Jáquez Leal + +2017-04-20 20:30:52 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + libs: window: wayland: cancel read at poll message + Always call wl_display_cancel_read() when an errno is set, but + different to EAGAIN or EINTR. + https://bugzilla.gnome.org/show_bug.cgi?id=780442 + +2017-04-21 18:05:48 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapidecodebin.c: + * gst/vaapi/gstvaapidecodebin.h: + vaapidecodebin: skips configuration once it's done + Skips configuration of creation of vpp/capsfilter and link them once it's done. + Otherwise, it always fails when it's trying to re-start playback. + https://bugzilla.gnome.org/show_bug.cgi?id=781573 + +2017-04-20 18:44:41 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostprocutil.c: + vaapipostproc: fixes for memory leaks + The use of gst_vaapi_value_set_format() and gst_structure_*_value() + requires to clear the used GValue to avoid a memory leak. + +2016-12-08 18:51:54 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + plugins: enable direct rendering with envvar + Direct rendering (use vaDeriveImage rather than vaPutImage) has better + performance in some Intel platforms (Haswell, for example) but in others + (Skylake) is the opposite. + In order to have some control, the patch enables the direct rendering + through the environment variable GST_VAAPI_ENABLE_DIRECT_RENDERING. + Also it seems to generating some problems with gallium/radeon backend. + See bug #779642. + https://bugzilla.gnome.org/show_bug.cgi?id=775848 + +2017-04-08 02:05:21 +1000 Jan Schmidt + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: Don't renegotiate on every flush + If caps don't actually change, don't update the + decoder and don't set the do_renego flag forcing + downstream renegotiation + https://bugzilla.gnome.org/show_bug.cgi?id=781142 + +2017-04-08 01:21:23 +1000 Jan Schmidt + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264 decoder: Implement reset() for faster flush + Implement a custom reset() function for faster flushes + that just clear the reference pictures but don't reallocate + the DPB or clear out SPS/PPS + https://bugzilla.gnome.org/show_bug.cgi?id=781142 + +2017-04-05 17:24:20 +1000 Jan Schmidt + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + * gst/vaapi/gstvaapidecode.c: + Implement decoder reset on flush, rather than recreating + Clear decoders out on a flush but keep the same instance, + rather than completely recreating them. That avoids + unecessarily freeing and recreating surface pools + and contexts, which can be quite expensive + https://bugzilla.gnome.org/show_bug.cgi?id=781142 + +2017-04-11 18:50:35 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiwindow.c: + libs: window: don't add an unused function + The macro GST_VAAPI_OBJECT_DEFINE_CLASS_WITH_CODE only defines + a function that is never used, thus when compiling we might see + this warning (clang): + gstvaapiwindow.c:147:1: warning: unused function 'gst_vaapi_window_class' [-Wunused-function] + GST_VAAPI_OBJECT_DEFINE_CLASS_WITH_CODE (GstVaapiWindow, + ^ + https://bugzilla.gnome.org/show_bug.cgi?id=759533 + +2017-04-11 18:22:00 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow_priv.h: + libs: window: remove surface_format member + Since we always convert to NV12, there is no need to keep a + variable for that. Let us hard code it. + https://bugzilla.gnome.org/show_bug.cgi?id=759533 + +2017-04-10 17:23:26 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11_priv.h: + libs: window: x11/wayland: use new api for conversion + Since gst_vaapi_window_vpp_convert_internal is created, + GstVaapiWindowX11/Wayland can use it for conversion. + Note that once it chooses to use vpp, it's going to use vpp + until the session is finished. + https://bugzilla.gnome.org/show_bug.cgi?id=759533 + +2017-04-10 11:41:29 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow_priv.h: + libs: window: add gst_vaapi_window_vpp_convert_internal() + If a backend doesn't support specific format, we can use vpp for conversion + and make it playing. + This api is originated from GstVaapiWindowWayland and moved to GstVaapiWindow, + so that GstVaapiWindowX11 could use it. + https://bugzilla.gnome.org/show_bug.cgi?id=759533 + +2017-04-03 16:45:36 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11_priv.h: + libs: window: x11/wayland: chaining up to GstVaapiWindow + Currently, GstVaapiWindowX11/Wayland are not descendants of GstVaapiWindow. + This patch chains them up to GstVaapiWindow to handle common members in GstVaapiWindow. + https://bugzilla.gnome.org/show_bug.cgi?id=759533 + +2017-04-05 11:19:15 -0700 Scott D Phillips + + * gst/vaapi/gstvaapipluginutil.c: + plugins: Fix usage of GST_GL_HAVE_WINDOW_* defines + When these definitions are false, they are undef in the + preprocessor, not a defined value of 0. When they are unset the + compile fails with: + 'GST_GL_HAVE_WINDOW_WAYLAND' undeclared (first use in this function) + https://bugzilla.gnome.org/show_bug.cgi?id=780948 + +2017-04-10 23:51:06 +0100 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 39ac2f5 to 60aeef6 + +=== release 1.11.90 === + +2017-04-07 16:36:21 +0300 Sebastian Dröge + + * ChangeLog: + * NEWS: + * configure.ac: + * gstreamer-vaapi.doap: + * meson.build: + Release 1.11.90 + +2017-04-03 14:52:41 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode_h265.c: + vaapiencode: h265: add main-10 in caps template + This patch adds h265's main-10 profile in encoder src caps template. + https://bugzilla.gnome.org/show_bug.cgi?id=771291 + +2017-04-03 15:34:51 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: chroma and luma with format + If the profile is main-10 the bit_depth_luma_minus8, in the sequence + parameter buffer, shall be the color format bit depth minus 8, 10-8 + which is 2. Also for bit_depth_chroma_minus8. + This patch gets the negotiated sink caps format and queries its + luma's depth and uses that value to fill the mentioned parameters. + https://bugzilla.gnome.org/show_bug.cgi?id=771291 + +2017-03-29 19:20:26 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: admit YUV420_10BPP as valid chroma + Accepts as supported the GST_VAAPI_CHROMA_TYPE_YUV420_10BPP chroma + type. + https://bugzilla.gnome.org/show_bug.cgi?id=771291 + +2017-03-29 19:16:50 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: ensures profile given format + Set the VA profile as GST_VAAPI_PROFILE_H265_MAIN10 if the + configured color format is P010_10LE. + Otherwise, keep GST_VAAPI_PROFILE_H265_MAIN + https://bugzilla.gnome.org/show_bug.cgi?id=771291 + +2017-04-06 17:21:21 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encode: merge all possible surface formats + When the function gst_vaapi_encoder_get_surface_formats() was added + it was under the assumption that any VA profile of the specific codec + supported the same format colors. But it is not, for example the + profiles that support 10bit formats. + In other words, different VA profiles of a same codec may support + different color formats in their upload surfaces. + In order to expose all the possible color formats, if no profile is + specified via source caps, or if the encoder doesn't have yet a + context, all the possible VA profiles for the specific codec are + iterated and their color formats are merged. + https://bugzilla.gnome.org/show_bug.cgi?id=771291 + +2017-04-06 16:28:12 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode.h: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h265.c: + vaapiencode: add get_profile() vmethod + This new virtual method, get_profile(), if implemented by specific + encoders, will return the VA profile potentially determined by the + source caps. + Also it is implemented by h264 and h265 encoders, which are the main + users of this vmethod. + https://bugzilla.gnome.org/show_bug.cgi?id=771291 + +2017-04-06 12:49:24 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst/vaapi/gstvaapiencode.c: + libs: encoder: pass profile to get_surface_formats() + In order to get the supported surface formats within a specific + profile this patch adds the GstVaapiProfile as property to + gst_vaapi_encoder_get_surface_formats(). + Currently the extracted formats are only those related with the + default profile of the element's codec. + https://bugzilla.gnome.org/show_bug.cgi?id=771291 + +2017-04-06 12:28:51 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: dummy context for get_surface_formats() + Instead of creating (if it doesn't exist, yet) the encoder's context + the method gst_vaapi_encoder_get_surface_formats() now it creates + dummy contexts, unless the encoder has it already created. + The purpose of this is to avoid setting a encoder's context with a + wrong profile. + https://bugzilla.gnome.org/show_bug.cgi?id=771291 + +2017-04-04 14:39:59 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: refactor init_context_info() + In order to generate vaapi contexts iterative, the function + init_context_info() is refactored to pass, as parameters the + GstVaapiContextInfo and the GstVaapiProfile. + https://bugzilla.gnome.org/show_bug.cgi?id=771291 + +2017-04-04 14:21:43 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + libs: encoder: initialize chroma_type + Instead of initialize the chroma_type with a undefined value, which + will be converted to GST_VAAPI_CHROMA_TYPE_YUV420 by GstVaapiContext, + this patch queries the VA config, given the received + GstVaapiContextInfo's parameters, and gets the first response. + In order to get the GstVaapiChromaType value, also it was needed to + add a new utility function: to_GstVaapiChromaType(), which, given a + VA_RT_FORMAT_* will return the associated GstVaapiChromaType. + https://bugzilla.gnome.org/show_bug.cgi?id=771291 + +2017-03-31 11:21:21 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode.c: + vaapiencode: enhance logs of negotiated caps + https://bugzilla.gnome.org/show_bug.cgi?id=771291 + +2017-04-05 11:15:41 -0700 Scott D Phillips + + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + libs: encoder: vp9: Fix initialization of ref_list + gcc 7.0.1 gives a memset-elt-size warning in gst_vaapi_encoder_vp9_init: + 'memset' used with length equal to number of elements without + multiplication by element size [-Werror=memset-elt-size] + https://bugzilla.gnome.org/show_bug.cgi?id=780947 + +2017-03-31 14:12:43 -0700 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: Fix Backward ReferencePicture flag setting + This is a regression introduced by e829b62 which + override the reference flags and caused issues with + latest intel-vaapi-driver. + +2017-03-29 13:22:47 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: fix code style + Trivial patch to remove a double ';' as end of instruction. + +2017-03-28 10:53:20 -0700 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: Fix B frame encoding artifacts + The current implementation is updating the POC values only + in Slice parameter Buffer.But we are not filling the + picture order count and reference flags in VAPictureH264 + while populating VA Picture/Slice structures.The latest + intel-vaapi-driver is directly accessing the above fields + from VAPicutreH264 provided as RefPicLists, which resulted + some wrong maths and prediction errors in driver. + https://bugzilla.gnome.org/show_bug.cgi?id=780620 + +2017-03-21 16:13:56 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: remove unused macro definition + Since the h265 encoder doesn't use GValueArray, there is no need to + disable the Glib deprecation warnings, thus removing the macro + definition. + +2017-03-20 16:45:01 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + plugins: when debug disabled, default category is NULL + As in gstreamer-vaapi a common base class is used, the specific + default category is passed to the base-plugin initializator, thus + the log messages are categorized with the used plugin. + Nonetheless, when the gst-debug is disabled in compilation time, + it is needed to pass NULL to the base-plugin initializator. This + patch does that. + https://bugzilla.gnome.org/show_bug.cgi?id=780302 + +2017-03-17 17:14:01 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiutils_h26x.c: + * gst-libs/gst/vaapi/gstvaapiutils_h26x_priv.h: + libs: h26x: adds gst_vaapi_utils_h26x_write_nal_unit() + Implements gst_vaapi_utils_h26x_write_nal_unit(), which writes NAL + unit length and data to a bitwriter. + Note that this helper function applies EPB (Emulation Prevention + Bytes), since otherwise produced codec_data might be broken when + decoder/parser considering EPB, starts parsing. + See sections 7.3 and 7.4 of the H264 and H264 specifications, which + describes the emulation_prevention_three_byte. + https://bugzilla.gnome.org/show_bug.cgi?id=778750 + Signed-off-by: Víctor Manuel Jáquez Leal + +2017-03-17 16:49:41 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiutils_h26x.c: + * gst-libs/gst/vaapi/gstvaapiutils_h26x_priv.h: + * gst-libs/gst/vaapi/meson.build: + libs: utils: h26x: create vaapiutils_h26x + Since there is duplicated code in h264/265 encoder, we could + refactor it to avoid duplicated code. + https://bugzilla.gnome.org/show_bug.cgi?id=778750 + Signed-off-by: Víctor Manuel Jáquez Leal + +2017-03-17 16:32:36 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h264/5: fix wrong return value + https://bugzilla.gnome.org/show_bug.cgi?id=778750 + +2017-03-13 17:29:59 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h265.c: + docs: h264/h265: put parser to the example pipeline + https://bugzilla.gnome.org/show_bug.cgi?id=778749 + +2017-03-13 16:20:59 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: fix reserved length of bits + Fix reserved length of bits for bit_depth_luma_minus8 and bit_depth_chroma_minus8 + https://bugzilla.gnome.org/show_bug.cgi?id=778749 + +2017-03-12 18:59:42 +0100 Thomas Petazzoni + + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + * tests/test-display.c: + O_CLOEXEC needs _GNU_SOURCE defined + From man open(2): + The O_CLOEXEC, O_DIRECTORY, and O_NOFOLLOW flags are not specified + in POSIX.1-2001, but are specified in POSIX.1-2008. Since glibc + 2.12, one can obtain their definitions by defining either + _POSIX_C_SOURCE with a value greater than or equal to 200809L or + _XOPEN_SOURCE with a value greater than or equal to 700. In glibc + 2.11 and earlier, one obtains the definitions by defining + _GNU_SOURCE. + And indeed, with the uClibc C library, O_CLOEXEC is not exposed if + _GNU_SOURCE is not defined. Therefore, this commit fixes the build of + gstreamer-vaapi with the uClibc C library. + Signed-off-by: Thomas Petazzoni + https://bugzilla.gnome.org/show_bug.cgi?id=779953 + +2017-03-14 16:07:08 +0100 Víctor Manuel Jáquez Leal + + * README: + README: fix "Sources" section + Update the URL where the release source tarballs can be downloaded. + +2017-03-12 21:39:53 +0100 Thomas Petazzoni + + * README: + README: fix "Reporting bugs" section + The "Reporting bugs" section gives + https://bugzilla.gnome.org/enter_bug.cgi?product=gstreamer-vaapi as the + link to report a bug, but this link says "Sorry, entering a bug into the + product gstreamer-vaapi has been disabled.". + This commit fixes the URL to point to the proper location, and also + removes the following paragraph that is no longer correct. + Signed-off-by: Thomas Petazzoni + https://bugzilla.gnome.org/show_bug.cgi?id=779954 + +2017-03-03 19:55:00 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + plugins: retry to create the VA display + Particularly in GNOME Wayland, the negotiated or created GL context + defines a GLX environment, but VAAPI fails to create a GLX VA + display because there is no a DRI2 connection. + This patch retries to create the VA display if VA cannot create one + with the GL context parameters. Now using the old list of display + types. + This should also work in the case of systems with two GPU, when the + non-VAAPI has the graphics environment, and the VAAPI-enabled one + shall work headless. + https://bugzilla.gnome.org/show_bug.cgi?id=772838 + +2016-10-19 15:33:41 +0100 Julien Isorce + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: texture upload if driver supports GL + Removes GstVideoGLTextureUploadMeta caps feature if the driver + doesn't support opengl. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=772838 + +2016-10-25 17:48:47 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: texture upload if driver supports GL + When the allowed source pad caps are generated, the GLTextureUpload caps are + only inserted if the driver support OpenGL. + https://bugzilla.gnome.org/show_bug.cgi?id=772838 + +2017-02-22 15:02:01 -0800 Sreerenj Balachandran + + * configure.ac: + configure: Add missing compiler flags + The AC_CHECK_HEADERS macro was failing to locate some headers, in + particular the va_enc_* headers due to missing compiler flags. + https://bugzilla.gnome.org/show_bug.cgi?id=779101 + Signed-off-by: Víctor Manuel Jáquez Leal + +2017-03-01 14:48:46 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + libs: window: wayland: handle more VAStatus to use vpp + Since the commit landed https://github.com/01org/intel-vaapi-driver/pull/55, + we should consider more returned VAStatus to use vpp. + https://bugzilla.gnome.org/show_bug.cgi?id=779400 + +2017-02-23 15:16:06 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: ensure profile when context initialization + We can't be sure that encoder's profile is assgined already or not + at context initialization. + https://bugzilla.gnome.org/show_bug.cgi?id=779120 + +2017-02-23 15:13:59 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: set rate control info only when query succeed + Currently, it set rate control information even when query fails. + In addition, it doesn't update any more since the flag + got_rate_control_mask is set to TRUE. + https://bugzilla.gnome.org/show_bug.cgi?id=779120 + +2017-02-24 16:00:23 +0200 Sebastian Dröge + + * meson.build: + meson: Update version + +2017-02-24 15:38:22 +0200 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.11.2 === + +2017-02-24 15:10:21 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * configure.ac: + * gstreamer-vaapi.doap: + Release 1.11.2 + +2017-02-16 18:37:59 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode.c: + vaapiencode: merge tags for downstream's info + Add encoder and codec name and the bitrate into the output for + informational purposes. Some muxers or application use it as + media metadata. + https://bugzilla.gnome.org/show_bug.cgi?id=778781 + +2017-02-17 01:27:52 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: caps can change at any time + The encoder should be able to change its caps even it is already + processing a stream. + This is suppose to happen after a flush so the codedbuf_queue should + be empty. + https://bugzilla.gnome.org/show_bug.cgi?id=775490 + +2017-02-17 01:19:00 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: encoder: h265: bail if nal unit type fails + Bail out if the NAL unit type is not recognized. + https://bugzilla.gnome.org/show_bug.cgi?id=778782 + +2017-02-16 18:11:50 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + libs: decoder: h264,h265 avoid uninitialized variable + Configuring GCC to verify possible usage of uninitialized variables, + shows that found_index might be used without previous assignation. + This patch assigns a initial value to found_index, also avoid a + branching when returning the result value. + https://bugzilla.gnome.org/show_bug.cgi?id=778782 + +2017-02-13 16:39:41 -0800 Scott D Phillips + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecodebin.c: + build: rename USE_HEVC_DECODER to USE_H265_DECODER + Rename to be consistent with H.264 and also H.265 encoder. The + meson build assumed this was already consistently named, and so + previously was not able to actually build the H.265 decoder. + https://bugzilla.gnome.org/show_bug.cgi?id=778576 + +2017-02-15 19:14:59 +0000 Tim-Philipp Müller + + * meson.build: + meson: gstreamer-codecparsers is a required dep + Just like in configure.ac. + +2017-02-15 00:26:21 +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-10 09:51:38 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + libs: encoder: vp8: add CBR encoding mode + This patch enables the Constant BitRate encoding mode in VP8 encoder. + Basically it adds the configuration parameters required by libva to + CBR enconding. + Original-Patch-By: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=749950 + +2017-02-09 12:39:19 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + libs: encoder: vp8: fix bitrate calculation + Base encoder's unit of bitrate is in Kbps. We should honor it so + we use the value of bitrate in VA, in which is expressed in bps. + https://bugzilla.gnome.org/show_bug.cgi?id=749950 + +2017-02-09 12:49:44 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: fix build when gcc + In commit a8e482f9 we added a function without parameters, but gcc + doesn't like that. + +2017-02-06 15:46:20 -0800 Scott D Phillips + + * gst-libs/gst/base/meson.build: + * gst-libs/gst/meson.build: + * gst-libs/gst/vaapi/meson.build: + * gst-libs/meson.build: + * gst/meson.build: + * gst/vaapi/meson.build: + * meson.build: + * meson_options.txt: + vaapi: add meson build + https://bugzilla.gnome.org/show_bug.cgi?id=778250 + +2017-02-08 10:17:40 -0800 Scott D Phillips + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapiversion.h.in: + make: remove gstvaapiversion.h generation + https://bugzilla.gnome.org/show_bug.cgi?id=778250 + +2016-10-19 15:47:41 +0100 Julien Isorce + + * gst/vaapi/gstvaapipluginbase.c: + plugins: use linear storage if not the same device + When dmabuf is negotiated downstream and decoding and rendering are + not done on the same device, the layout has to be linear in order for + the memory to be shared accross devices, since each device has its + own way to do tiling. + Right now this code is rather just a to-do comment, since we are not + fetching the device ids. + https://bugzilla.gnome.org/show_bug.cgi?id=755072 + +2017-02-08 14:17:05 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiutils.c: + libs: utils: add HEVC profiles representation + https://bugzilla.gnome.org/show_bug.cgi?id=778318 + +2017-02-07 16:17:39 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + libs: decoder: h264: reduce frame number of gaps + Reduce frame num gaps so that we don't have to create unnecessary + dummy pictures, just throw them away. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=777506 + +2016-10-16 01:04:09 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: don't GLTextureUpload if dmabuf + Do not add the meta:GstVideoGLTextureUploadMeta feature if the render + element can handle dmabuf-based buffers, avoiding its negotiation. + +2016-10-19 16:21:21 +0100 Julien Isorce + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: make pool to export decoder's surface + Use new -base API gst_video_decoder_allocate_output_frame_full() to + pass the current proxy/surface to the pool. + The pool will will export thins given surface instead of exporting a + brand new surface that will never be filled in with meaningfull data. + https://bugzilla.gnome.org/show_bug.cgi?id=755072 + +2017-02-03 17:06:29 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: decoder can negotiate dmabuf downstream + +2016-10-19 16:07:07 +0100 Julien Isorce + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapivideobufferpool: override acquire_buffer() + Overriding the vmethod acquire_buffer() it is possible to attach the + right GstMemory to the current acquired buffer. + As a matter of fact, this acquired buffer may contain any instantiated + GstFdmemory, since this buffer have been popped out from the buffer + pool, which is a FIFO queue. So there is no garantee that this buffer + matches with the current processed surface. Evenmore, the VA driver + might not use a FIFO queue. Therefore, it is no way to guess on the + ordering. + In short, acquire_buffer on the VA driver and on the buffer pool return + none matching data, we have to manually attach the right GstFdMemory to + the acquired GstBuffer. The right GstMemory is the one associated with + the current surface. + https://bugzilla.gnome.org/show_bug.cgi?id=755072 + +2016-10-19 16:05:04 +0100 Julien Isorce + + * gst/vaapi/gstvaapivideobufferpool.c: + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: export surface if it is provided + gst_vaapi_dmabuf_memory_new() always exports a surface. Previously, it + had to create that surface. Now it can also export an already provided + surface. It is useful to export decoder's surfaces (from VA context). + https://bugzilla.gnome.org/show_bug.cgi?id=755072 + +2016-10-19 15:55:27 +0100 Julien Isorce + + * gst/vaapi/gstvaapivideobufferpool.h: + vaapivideobufferpool: add GstVaapiVideoBufferPoolAcquireParams + Useful to let the pool know the current surface proxy when calling + gst_buffer_pool_alloc_buffer() / gst_buffer_pool_acquire_buffer() + https://bugzilla.gnome.org/show_bug.cgi?id=755072 + +2016-10-19 15:09:34 +0100 Julien Isorce + + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + libs: surface: add gst_vaapi_surface_{set,peek}_buffer_proxy() + These functions are useful when a dmabuf-based memory is instantiated in + order to relate the generated buffer @proxy with the processed @surface. + https://bugzilla.gnome.org/show_bug.cgi?id=755072 + +2016-10-19 15:07:31 +0100 Julien Isorce + + * gst-libs/gst/vaapi/gstvaapibufferproxy.c: + * gst-libs/gst/vaapi/gstvaapibufferproxy.h: + * gst-libs/gst/vaapi/gstvaapibufferproxy_priv.h: + libs: bufferproxy: gst_vaapi_buffer_proxy_{set,peek}_mem() + This patch adds a GstMemory as a variable member of the buffer proxy, + because we will need to associate the buffer proxy with the memory + which exposes it. Later, we will know which memory, in the video buffer + pool, is attached to the processed surface. + https://bugzilla.gnome.org/show_bug.cgi?id=755072 + +2016-10-19 15:33:41 +0100 Julien Isorce + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: don't GLTextureUpload if dmabuf + Do not add the meta:GstVideoGLTextureUploadMeta feature if the render + element can handle dmabuf-based buffers, avoiding its negotiation. + Similar as "vaapidecode: do not add meta:GstVideoGLTextureUploadMeta + feature if can dmabuf" + https://bugzilla.gnome.org/show_bug.cgi?id=755072 + +2016-12-16 14:12:30 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: enable DMAbuf allocator to downstream + If the negotiated caps are raw caps and downstream supports the + EGL_EXT_image_dma_buf_import extension, then the created allocator + is the DMAbuf, configured to downstream. + At this moment, the only element which can push dmabuf-based buffers + to downstream, is vaapipostproc. + +2016-06-02 22:13:51 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + plugins: check if negotiate dmabuf with downstream + In order to enable, in the future, dmabuf-based buffers, the vaapi base + plugin needs to check if downstream can import dmabuf buffers. + This patch checks if downstream can handle dmabuf, by introspecting the + shared GL context. If the GL context is EGL/GLES2 and have the extension + EGL_EXT_image_dma_buf_import, then dmabuf can be negotiated. + Original-patch-by: Julien Isorce + +2016-10-19 15:37:04 +0100 Julien Isorce + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: release proxy's data if downstream + The surface created for downstream is going to be filled by VAAPI + elements. So, the driver needs write access on that surface. + This patch releases the derived image held by the proxy, thus the + surface is unmarked as busy. + This is how it has to be done as discussed on libva mailing list. + https://bugzilla.gnome.org/show_bug.cgi?id=755072 + +2016-10-19 15:01:04 +0100 Julien Isorce + + * gst-libs/gst/vaapi/gstvaapibufferproxy.c: + * gst-libs/gst/vaapi/gstvaapibufferproxy.h: + libs: bufferproxy: add gst_vaapi_buffer_proxy_release_data() + Adds an API to request the user's data release in the buffer proxy. + https://bugzilla.gnome.org/show_bug.cgi?id=755072 + +2016-10-19 15:27:03 +0100 Julien Isorce + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + vaapivideomemory: add direction to dmabuf allocator + Add GstPadDirection param to gst_vaapi_dmabuf_allocator_new(), thus + we later could do different thing when the allocated memory is for + upstream or dowstream, as required by VA-API. + https://bugzilla.gnome.org/show_bug.cgi?id=755072 + +2016-12-15 15:59:30 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiutils_core.c: + libs: utils: return NULL if failed to get surface formats + Thus, when generating the allowed caps, the element will throw a + warning and it will use its caps template. + This behavior might be a bug in the VA driver. + https://bugzilla.gnome.org/show_bug.cgi?id=775490 + +2015-11-26 18:21:08 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + Revert "vaapidisplay: mark X11 display as compatible with EGL" + This reverts commit 200b1baabc066f8a4102f82f539655d588200ec9. + +2017-02-01 14:32:45 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: set GST_VAAPI_POSTPROC_FLAG_SIZE according to src caps + A value of width/height property should be set to out caps, + if negotiation had been going properly. + So we can use srcpad_info when making decision of scaling. + https://bugzilla.gnome.org/show_bug.cgi?id=778010 + +2017-01-27 12:10:54 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + plugins: handle GL params through context query + If the element instantiated the GL display and context, they should + handle them too through the context query. + https://bugzilla.gnome.org/show_bug.cgi?id=777409 + +2017-01-26 12:02:56 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + * gst/vaapi/gstvaapipluginutil.c: + plugins: create a GL context on certain conditions + If a GstVaapiDisplay is not found in the GStreamer context sharing, + then VAAPI elements look for a local GstGLContext in gst context + sharing mechanism ('gst.gl.local.context'). + If this GstGLContext not found either then, only the VAAPI decoders + and the VAAPI post-processor, will try to instantiate a new + GstGLContext. + If a valid GstGLContext is received, then a new GstVaapiDisplay will + be instantiated with the platform, API and windowing specified by the + instantiated GstGLContext. + Original-Patch-By: Matt Fischer + https://bugzilla.gnome.org/show_bug.cgi?id=777409 + +2016-08-02 15:48:25 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideocontext.c: + vaapivideocontext: context type can be rejected + Instead of calling g_return_val_if_fail() to check the context type, we + should use a normal conditional, since it is possible that other context types + can arrive and try to be assigned. Otherwise a critical log message is + printed. + This happens when we use playbin3 with vaapipostproc as video-filter. + https://bugzilla.gnome.org/show_bug.cgi?id=777409 + +2017-01-20 19:57:52 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostprocutil.c: + vaapipostproc: use sink caps par if not requested + Use the sink caps pixel-aspect-ratio to fixate the src caps, if it + is not already set. + https://bugzilla.gnome.org/show_bug.cgi?id=777395 + +2017-01-20 19:00:24 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostprocutil.c: + vaapipostproc: set interlace mode + if the vaapipostproc is configured to not do deinterlacing, the + interlace-mode in the src caps should be the same as the input caps. + https://bugzilla.gnome.org/show_bug.cgi?id=777395 + +2017-01-20 16:10:32 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapisink.c: + vaapisink: fix gcc compiler warning + warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement] + +2017-01-12 19:54:41 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapisink.c: + vaapisink: don't use member variable outside lock + Thus a race condition segfault is avoided. + Original-patch-by: Matt Staples + https://bugzilla.gnome.org/show_bug.cgi?id=777146 + +2017-01-18 17:20:21 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipostproc.c: + plugins: avoid log flood when activating pool + Every time a new buffer is allocated, the pool is activated. This + doesn't impact in performance since gst_buffer_pool_set_active() + checks the current state of the pool. Nonetheless it logs out a + message if the state is the same, and it floods the logging subsystem + if it is enabled. + To avoid this log flooding first the pool state is checked before + changing it. + +2017-01-13 21:26:15 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + vaapidecode: update internal decoder sink caps + When a new sink caps arrive the internal decoder state is updated + and, if it is, request a downstream renegotiation. + Previously, when new caps arrived the whole decoder where destroyed + and recreated. Now, if the caps are compatible or has the same codec, + the internal decoder is kept, but a downstream renegotiation is + requested. + https://bugzilla.gnome.org/show_bug.cgi?id=776979 + +2017-01-12 16:33:13 +0200 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.11.1 === + +2017-01-12 16:27:12 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * configure.ac: + * gstreamer-vaapi.doap: + Release 1.11.1 + +2017-01-12 12:49:55 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiutils.c: + vaapi: bump ifdef to API 0.40.0 for log redirect + vaSetInfoCallback() is not released yet. It is going to appear in + VA-API 0.40.0 + +2017-01-12 13:45:29 +0200 Sebastian Dröge + + * gst-libs/gst/vaapi/gstvaapiutils.c: + vaapiutils: Fix compilation with latest and previous libva releases + vaSetInfoCallback() was defined after 0.39.4 / 1.7.3, so check for + 0.39.5 instead. + +2017-01-11 16:04:24 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + libs: display: redirect logging at initialize + Redirect libva's logs to GStreamer logging mechanism. This is + particularly useful when VA is initialized, because it always logs + out the drivers details. + In order to achieve this a new helper function was added as a wrapper + for the vaInitialize() function. + https://bugzilla.gnome.org/show_bug.cgi?id=777115 + +2017-01-10 15:15:31 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapipluginbase.c: + plugins: provide at least two buffers in sink pool + Adds two buffers as the default value of minimum buffer. + This would be used when creating and proposing vaapi bufferpool for + sink pad, hence the upstream element will keep, at least, these two + buffers. + https://bugzilla.gnome.org/show_bug.cgi?id=775203 + Signed-off-by: Víctor Manuel Jáquez Leal + +2017-01-10 13:49:27 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + libs: decoder: h264: don't update cloned attributes + If the frame is a cloned picture, its PTS comes from its parent + picture. In addition, the base decoder doesn't set a valid PTS to + the frame corresponding to the cloned picture. + https://bugzilla.gnome.org/show_bug.cgi?id=774254 + +2017-01-09 19:25:24 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: check for display + This patch fixes the check of display, rather than check for the + meta, which it is known it exists. + +2017-01-09 16:23:56 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + vaapivideomemory: rename dmabuf allocator parameters + Rename the parameters 'vip' and 'flags' to 'alloc_info' and + 'surface_alloc_flags' respectively. The purpose of this change is + to auto-document those parameters. + Also, aligned to this patch, the local 'alloc_info' variable was + renamed as 'surface_info', because it stores the possible surface's + video info, not the allocate one. + +2017-01-09 16:18:32 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + vaapivideomemory: rename vip to alloc_info parameter + In order to auto-document the code, this patch renames the 'vip' + parameter in the functions related to gst_vaapi_video_allocator_new () + to 'alloc_info', since it declares the allocation video info from + the vaapi buffer pool. + +2017-01-09 16:08:17 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: use GST_VIDEO_INFO_FORMAT_STRING() + Use the existing local macro GST_VIDEO_INFO_FORMAT_STRING() to get + the video format string. + +2017-01-09 12:51:11 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: unroll gst_vaapi_surface_new_with_format() + gst_vaapi_surface_new_with_format() is a wrapper for + gst_vaapi_surface_new_full (). In this case, the former is simpler + than the first. This patch changes that. + +2017-01-04 19:23:06 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: notify if src pad caps changed + If src pad caps have changed, it needs to notify it downstream. In + addition, do not set passthrough if they have changed. + Otherwise, transform sometimes starts processing before caps change. + The passthrough value will be set in fixate later in this case. + https://bugzilla.gnome.org/show_bug.cgi?id=775204 + +2016-12-14 15:51:01 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecodebin.c: + vaapidecodebin: capsfilter to optimize negotiation + Add a capsfilter forcing the caps + "video/x-raw(memory:VASurface), format=(string)NV12" between the + queue and the vaapipostproc so no renegotiation is required. + https://bugzilla.gnome.org/show_bug.cgi?id=776175 + +2016-12-21 17:38:07 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: fail surface/image configuration + To detect and handle errors during allocator_configure_surface_info() + and allocator_conigure_image_info(). + https://bugzilla.gnome.org/show_bug.cgi?id=776084 + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-12-21 17:50:41 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapisink.c: + vaapisink: ensures raw caps at start() + Calls gst_vaapi_plugin_base_get_allowed_raw_caps() at start() to avoid + race conditions at get_caps(), especially with multiple src elements. + https://bugzilla.gnome.org/show_bug.cgi?id=776303 + +2016-12-09 14:51:52 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapisurface_drm.c: + libs: surface: fix error handling code style + +2016-12-09 16:14:14 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: add gst_video_info_update_from_surface() + With this function is possible to refactor and remove duplicated code + between dmabuf configuration and direct rendering/uploading + configuration. + +2016-12-09 15:51:32 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: no log object at initialization + When an instance of GstVaapiVideoAllocator fails at initializing, the + log message should not include the allocator's object, because it is + going to be unrefed. + +2016-12-09 17:56:02 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: lock stream when setting caps + +2016-12-09 17:42:42 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + Revert "vaapidecode: implement negotiate() vmethod" + This reverts commit 3285121181295c544480fc6ba756845b16285d30. + videodecode's negotiate() vmethod is also called when events arrive, + but this would mean that the proper configuration of sink pad might + not be complete, thus we should not update the src pad. + Let's keep the old non-vmethod negotitate(). + +2016-12-07 16:52:35 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapi.c: + Revert "encoders: demote to RANK_NONE since not fit for autoplugging yet" + This reverts commit f182b8be2ba05965e6d31a4d380d6563b9b53a77. + +2016-12-01 18:57:10 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode.h: + vaapiencode: get surface formats in get_caps() + Query for the supported surface formats in config at get_caps() vmethod. + https://bugzilla.gnome.org/show_bug.cgi?id=769266 + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-12-07 11:26:37 +0100 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + libs: encoder: add gst_vaapi_encoder_get_surface_formats() + This method will return the valid surface formats in the current + config. If the are no VAConfig it is created with the information + available. + https://bugzilla.gnome.org/show_bug.cgi?id=769266 + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-12-07 11:10:42 +0100 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + libs: encoder: split set_context_info() + Split set_context_info() adding init_context_info() which only + initialises the GstVaapiContextInfo structure inside GstVaapiEncoder + required for VAConfig. + https://bugzilla.gnome.org/show_bug.cgi?id=769266 + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-12-02 09:30:52 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapicontext.c: + libs: context: skip VAContext if no frame size + If GstVaapiContextInfo has just initial information, without frame's + width and height, skip the creation of the VAContext, just keep the + VAConfig. + https://bugzilla.gnome.org/show_bug.cgi?id=769266 + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-12-02 09:28:07 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapicontext.c: + libs: context: split context_create() + Split the funcion context_create() into context_create() and + config_create(). + Decoupling VAConfig and VAContext during context creation, we could + query the VAConfig for the supported surface's formats without creating + a VAContext. + https://bugzilla.gnome.org/show_bug.cgi?id=769266 + +2016-12-06 17:33:42 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + libs: drm: find render node in hybrid system + Originally the drm backend only tried to open the first render node + found. But in hybrid system this first render node might not support + VA-API (propietary Nvidia driver, for example). + This patch tries all the available nodes until a finding one with a + VA-API supported driver. + https://bugzilla.gnome.org/show_bug.cgi?id=774811 + Original-patch-by: Stirling Westrup and + Reza Razavi + +2016-11-14 17:45:55 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: refactor code for readability + Added the inlined function allocator_configure_pools() moving out code + from gst_vaapi_video_allocator_new() to make clear that it is a + post-initalization of the object. + +2016-11-14 17:40:37 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: log error if not VA image + Log an error message if the test image for surface downloading + cannot be allocated or mapped. + +2016-11-14 17:33:41 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: remove unused macros + These macros are not used. Let us remove them. + +2016-11-11 19:45:45 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + vaapivideomemory: rename video for allocation_info + Since video_info stores the GstVideoInfo of the allocation caps, + it is clear if we rename it as allocation_info, to distinguish it + later from negotiation_info. + +2016-10-19 15:27:03 +0100 Julien Isorce + + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + vaapivideomemory: add real GstVaapiDmaBufAllocator + Instead of defining GstVaapiDmaBufAllocator as a hackish decorator of + GstDmaBufAllocator, now, since the expose of the GstDmaBufAllocator's + GType, GstVaapiDmaBufAllocator is a full feature GstAllocator inherited + from GstDmaBufAllocator. + https://bugzilla.gnome.org/show_bug.cgi?id=755072 + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-10-19 15:30:09 +0100 Julien Isorce + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: errors in gst_vaapi_dmabuf_allocator_new() + Add a helper function to initialize the gst_debug_vaapivideomemory, + to use it either by the GstVaapiVideoAllocatorClass or + GstVaapiDmabufAllocator (which is a decorator of GstDmaBufAllocator). + Later, log possible errors when calling gst_vaapi_dmabuf_allocator_new () + https://bugzilla.gnome.org/show_bug.cgi?id=755072 + +2016-11-29 15:14:32 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapiencode.c: + vaapiencode: release internal encoder at stop() + As the internal encoder is created at start(), let's release it at + stop() vmethod, to be consistent. + gst_vaapiencode_destroy() is called since it also resets the input and + output states, which is something that the base class does internally + after calling stop() vmethod. + https://bugzilla.gnome.org/show_bug.cgi?id=769266 + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-12-03 08:20:56 +0100 Edward Hervey + + * common: + Automatic update of common submodule + From f49c55e to 39ac2f5 + +2016-11-29 14:59:02 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapiencode.c: + vaapiencode: call ensure_encoder() at start() + Currently, specific encoder is created during set_format(). This might + lead to race condition when creating profiles with multiple encoders. + This patch moves ensure_encoder() call to start() vmethod to ensure + avoiding the race condition. + https://bugzilla.gnome.org/show_bug.cgi?id=773546 + +2016-11-21 19:29:22 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecodebin.c: + vaapidecodebin: bring back dynamic configuration + In commit ca0c3fd6 we remove the dynamic configuration if the bin + because we assumed that the bin will be always static as it is + registered. + Nonetheless we were wrong, because it is possible to request, with a + property, to avoid the use of the post-processor. + Since we want to add a way to disable the post-processor through + environment variables, this remove feature is required again. + If the environment variable GST_VAAPI_DISABLE_VPP is defined the + postprocessor inside of the vaapidecodebin is disabled, then + vaapidecodebin is an alias of the old vaapidecode. + https://bugzilla.gnome.org/show_bug.cgi?id=775041 + +2016-11-21 18:25:18 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: implement negotiate() vmethod + Instead of decorating the negotiate() method, let us override it, + so the stream is locked while called. + https://bugzilla.gnome.org/show_bug.cgi?id=775040 + +2016-11-26 11:27:26 +0000 Tim-Philipp Müller + + * .gitmodules: + common: use https protocol for common submodule + https://bugzilla.gnome.org/show_bug.cgi?id=775110 + +2016-11-24 21:17:54 +0100 Dominique Leuenberger + + * gst-libs/gst/vaapi/Makefile.am: + build: add LIBVA_WAYLAND_CFLAGS to libgstvaapiegl + In case libva-wayland has its headers not installed in default + locations (like /usr/include), the build fails to include "wayland-client.h": + CC libgstvaapi_egl_la-gstvaapiutils_egl.lo + In file included from gstvaapidisplay_wayland.h:27:0, + from gstvaapidisplay_egl.c:35: + /usr/include/va/va_wayland.h:31:28: fatal error: wayland-client.h: No such file or directory + #include + As we already passed VA_CLAGS, /usr/include/va/va_wayland.h could be found, but it is + our fault not to instruct the system that we ALSO care for va_wayland. We correctly query + for libva-wayland.pc in configure and use this in other places as well. It is thus only + correct and consequent, to do it also at this spot. + https://bugzilla.gnome.org/show_bug.cgi?id=773946 + +2015-10-28 12:55:18 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideocontext.c: + vaapivideocontext: log a message if no bus + Raise a warning if there is no bus when the element tries to post a + message. + +2015-10-28 12:57:14 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapisink.c: + vaapisink: create display at open() + Instead of creating the VA display before setting the bus to the + element, it is created when the element is opened. + Basically, this commit is a revert of + 5e5d62cac79754ba60057fc2516135aad8d7de35 + That was done when the GStreamer's context sharing was not mature + enough as now. There is no reason to keep this hack. + +2016-11-04 18:04:36 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: don't add video crop meta + Since the differentiation of negotiation caps and allocation caps, + there is no need to add a video crop meta with the negotiation caps. + Hence, removing it. + https://bugzilla.gnome.org/show_bug.cgi?id=773948 + +2015-03-19 21:20:26 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideobuffer.c: + * gst/vaapi/gstvaapivideometa.c: + * gst/vaapi/gstvaapivideometa.h: + remove the video converter from vaapi buffer meta + Since all the video converter were deprecated in gstreamer-1.2, we don't need + to handle them anymore in the vaapi's buffer meta. + This patch removes its usage and the buffer meta's API for that. + https://bugzilla.gnome.org/show_bug.cgi?id=745728 + +2016-11-21 18:28:18 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: destroy source pad allocator and pool + First, deactivate source pad pool when the out caps change, and if so, + destroy texture map, the source pad allocator and pool only if the + new caps are different from the ones already set. + +2016-11-21 19:17:07 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: don't destroy sink pad allocator + Don't destroy sink pad allocator at _set_caps() because it will be done at + ensure_sinkpad_buffer_pool() if it is required. + +2016-11-21 18:27:00 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: first validate the out caps + When calling _set_caps() first validate the out caps before doing + anything else. + +2016-11-21 18:42:02 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: negotiate after destroying allocator + This is related with bug 758907 when no vaapipostproc is used (no + vaapidecodebin). In order to negotiate downstream we need to destroy + the source pad allocator, otherwise the same allocated buffers are + used, failing the mapping. + +2016-11-21 16:35:34 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: remove GST_VAAPI_TYPE_VIDEO_INFO + Remove redundant GST_VAAPI_TYPE_VIDEO_INFO, since it is a duplicate of + GST_TYPE_VIDEO_INFO created before gstreamer 1.6, where the boxed type + was created. + https://bugzilla.gnome.org/show_bug.cgi?id=774782 + +2016-11-21 12:51:25 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: update the src pad allocator video info + Update the size, stride and offset of the source pad allocator video + info, so the pool could set the correct GstVideoMeta + https://bugzilla.gnome.org/show_bug.cgi?id=774782 + +2016-11-21 12:36:27 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: add missing documentation + https://bugzilla.gnome.org/show_bug.cgi?id=774782 + +2016-11-21 12:29:26 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: use early return without goto + https://bugzilla.gnome.org/show_bug.cgi?id=774782 + +2016-11-21 11:25:21 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + plugins: add allocator to allocation query + This patch adds the created allocator to the allocation query either + in decide_allocation() and propose_allocation() vmehtods. + With it, there's no need to set the modified allocator's size in the + pool configuration. + https://bugzilla.gnome.org/show_bug.cgi?id=774782 + +2016-10-19 15:15:01 +0100 Julien Isorce + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapivideobufferpool: set correct buffer size + We should set the correct buffer size when we are configuring the pool, + otherwise the buffer will be discarded when it returns to the pool. + Indeed when the ref-count of a buffer reaches zero, its pool will queue + it back (and ref it) if, and only if, the buffer size matches the + configured buffer size on the pool. + This issue can be debugged with GST_DEBUG=*PERF*:6, see gstbufferpool.c + https://bugzilla.gnome.org/show_bug.cgi?id=774782 + +2016-11-10 13:26:31 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: check for memory allocator + When calling gst_vaapi_video_memory_copy() the allocator of the memory + to copy should be allocated by the vaapi allocator. + This patch does this verification. + +2016-11-10 13:25:30 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: code style fixes + A cosmetic commit for enhance readability of the casts and method + preconditions. + +2016-11-09 19:49:22 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: unroll gst_vaapi_video_allocator_free() + Instead of having a gst_vaapi_video_memory_free() that is only going to + be called by gst_vaapi_video_allocator_free(), let's just remove the first + and merged into the second. + +2016-11-09 19:29:12 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: avoid virtual methods casting + Use the expected virtual method signatures for readability. + +2016-11-09 18:58:20 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: remove unimplemented methods + Remove unimplemented method for allocator mem_share() and mem_is_span(). + +2016-11-09 18:54:47 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: fail if frame map can't get plane + If map() vmethod in GstVideMeta cannot get the plane data, return false, + thus the caller will not try to read invalid memory. + https://bugzilla.gnome.org/show_bug.cgi?id=774213 + +2016-11-09 18:39:06 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + vaapivideomemory: lock map and unmap operations + In order to avoid race condition when two threads call map/unmap the same + VA surface, this patch mutex these operations. + https://bugzilla.gnome.org/show_bug.cgi?id=774213 + +2016-11-09 17:37:06 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: refactor vaapi memory unmapping + There were duplicated code in gst_video_meta_unmap_vaapi_memory() and + gst_vaapi_video_memory_unmap() when unmapping. + This patch refactors both methods adding the common function + unmap_vaapi_memory(). This also ensures, if direct rendering is enabled, it + is correctly reset. + Additionally, only when mapping flag has the WRITE bit, it set the image as + current, which was done in gst_video_meta_map_vaapi_memory() but no in + gst_vaapi_video_memory_map(). + In order to make this, the mapping flags were required, so instead of + overloading mem_unmap() virtual function, mem_unmap_full() is overloaded. + https://bugzilla.gnome.org/show_bug.cgi?id=774213 + +2016-11-09 13:54:23 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: refactor vaapi memory mapping + There were duplicated code in gst_video_meta_map_vaapi_memory() and + gst_vaapi_video_memory_map() when doing the READ and WRITE mapping. + This patch refactors both methods adding the common function + map_vaapi_memory(). + Additionally, only when flag has the READ bit it calls + ensure_images_is_current(), which was done in + gst_video_meta_map_vaapi_memory() but no in + gst_vaapi_video_memory_map(). + https://bugzilla.gnome.org/show_bug.cgi?id=772151 + +2016-10-27 18:22:18 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: unref allowed_sinkpad_caps at close() + The variable member allowed_sinkpad_caps is constructed querying the + current VA display. Bearing that in mind, the variable shall be freed + when the VA display changes or is removed. + This patch moves the freeing of allowed_sinkpad_caps to close(), when + the VA display is freed. + +2016-11-11 11:40:09 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapisink.c: + vaapisink: finish event thread at stop() + The thread that handles window's events should be finished during + pipeline's shutdown, otherwise it will remain alive during pipeline + re-activation, leading to unexpected problems. + This patch fixes failures of intensive_state_change scenario of + gst-validate + https://bugzilla.gnome.org/show_bug.cgi?id=774241 + +2016-11-08 09:35:00 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: enhance debug message + "gst_pad_push" is not a good description of the event. + +2016-11-08 10:05:32 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapipostproc.c: + postproc: honor gst_pad_push() return value + Returning GST_FLOW_ERROR always when gst_pad_push fails might lead to + deadlock during seek. + This patch returns the same error of gst_pad_push() and log out the + return value. + https://bugzilla.gnome.org/show_bug.cgi?id=774030 + +2016-11-04 16:26:18 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: guard GST_VAAPI_MAKE_GLTEXUPLOAD_CAPS + In commit 6d11a00 were introduced a regression when gstreamer-vaapi is + compiled with out EGL/GLX support: it shall not support + GST_VAAPI_MAKE_GLTEXUPLOAD_CAPS. + This patch guards the inclusion of GST_VAAPI_MAKE_GLTEXUPLOAD_CAPS in the + allowed src caps for vaapedecode if EGL/GLX. + +2016-11-04 12:55:23 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: increment map counter only if succeeded + Previously the frame map counter increased independently if the map succeeded + or not. This leaded to critical messages and crashes if the frame was unable + to be mapped, but the counter increased. + This patch increases the map counter only if the map operation occurred. + https://bugzilla.gnome.org/show_bug.cgi?id=773939 + +2016-11-03 17:30:46 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: set negotiation caps in src allocator + When the allocator is created, it stores the allocation caps. But sometimes + the "allocation caps" may be different from the "negotiation caps". + In this case, the allocator should store the negotiation caps since they + are the ones used for frame mapping with GstVideoMeta. + When vaapispostproc is used, this is not a problem since the element is assume + to resize. But when using a vaapi decoder only, with a software renderer, it + fails in this case. + https://bugzilla.gnome.org/show_bug.cgi?id=773323 + +2016-07-19 16:40:10 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + vaapidecode: generate source pad caps + Just as vaapipostproc, VA decoder's context can be queried to get the possible + raw formats, so, the src caps can negotiate the exact caps that the context + supports. + +2016-02-25 18:57:30 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + libs: decoder: add _get_surface_formats() + This function exposes the available formats of the surfaces in the the current + context to the plugins. + +2016-02-18 19:32:58 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + libs: context: ensure context formats + This patch ensures to get the formats, as filter does, available in the + decoder / encoder context. + The context fills up the array as soon it is created, otherwise the pipeline + could get stalled (perhaps this is a bug in my HSW backend). + https://bugzilla.gnome.org/show_bug.cgi?id=752958 + +2016-02-18 19:20:10 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapiutils_core.c: + * gst-libs/gst/vaapi/gstvaapiutils_core.h: + libs: move get_surface_formats to utils_core + The query of all the supported formats for a VA config were only used by the + postprocessor (vaapifilter). But, in order to enable the vaapidecoder to + negotiate a suitable raw format with downstream, we need to query these + formats against the decoder's config. + This patch is the first step: moves the code in filter's ensure_image() to a + generic gst_vaapi_get_surface_formats() in vaapiutils_core, so it can be + shared later by the decoder. + https://bugzilla.gnome.org/show_bug.cgi?id=752958 + +2016-07-19 18:56:15 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: remove set_sinkpad_dmabuf_allocator() + Since when the sink pad allocator is created, it is decided if the required + one is vaapi allocator or dmabuf allocator, there is no need to force its set + again. + +2016-10-27 11:25:55 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: ensure display when getting raw caps + When running gst-discoverer-1.0, in certain media, vaapipostroc is stopped + meanwhile it is transforming caps. The problem is that stop() calls + gst_vaapi_plugin_base_close(), which nullifies the element's va display, but + the va display is used in tranform_caps() when it is extracting the possible + format conversions. This display disappearing generates warning messages. + This patch holds a local reference of va display at ensure_allowed_raw_caps() + hence it doesn't go away meanwhile it is used, even if the + gst_vaapi_plugin_base_close() is called in other thread. + https://bugzilla.gnome.org/show_bug.cgi?id=773593 + +2016-11-03 12:54:23 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h265.c: + plugins: fix code style for errors + +2016-10-19 19:04:20 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapibufferproxy.c: + * gst-libs/gst/vaapi/gstvaapicodedbuffer.c: + * gst-libs/gst/vaapi/gstvaapicodedbufferproxy.c: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext_overlay.c: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_dpb.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplaycache.c: + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimagepool.c: + * gst-libs/gst/vaapi/gstvaapiparser_frame.c: + * gst-libs/gst/vaapi/gstvaapipixmap.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils_egl.c: + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + libs: fix code style for errors + +2016-11-03 09:31:17 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapivideocontext.c: + plugins: update GstGL deprecated symbol + GST_GL_TYPE_CONTEXT was deprecated. Now it is GST_TYPE_GL_CONTEXT. + +2016-10-21 11:48:54 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: direct render when raw video + Enable the direct rendering with linear surfaces if the negotiated src caps + are video/x-raw without features. + Pass also the caps, since they are needed to know the requested caps features. + +2016-10-24 20:09:59 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: move src allocator error to instantiator + Just as we did in ensure_sinkpad_allocator(), let's move the error message + into the ensure_srcpad_allocator() from the caller, + gst_vaapi_plugin_base_decide_allocation() + +2016-10-20 19:37:01 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: enable direct upload if raw video + Enable the direct upload with linear surfaces if the negotiated sink caps are + video/x-raw without features. + +2016-10-21 11:21:04 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + pluginutil: add gst_caps_is_video_raw() + +2016-10-24 19:25:27 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: receive caps in ensure_sinkpad_allocator() + Instead of receiving the GstVideoInfo structure as parameter, get the original + GstCaps from ensure_sinkpad_buffer_pool(), in this way we could decide better + which allocator instantiate. + +2016-10-20 19:31:58 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: destroy derived image at unmap + If the allocator was configured to use direct upload or rendering, the + generated derived image created at mapping needs to be destroyed after + unmapping, because, in order to process the surface, it should not be marked + as "busy" by the driver. + +2016-10-21 11:57:55 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: enhance logs for direct modes + Print, conditionally, only the enabled direct mode. + +2016-10-20 17:02:49 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + vaapivideomemory: add direct upload flag + Adds the direct-upload flag in the GstVaapiVideoAllocator and + GstVaapiVideoMemory. + It still doesn't apply any functional change. + +2016-10-20 16:49:22 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + vaapivideomemory: set direct rendering at run-time + The way to experiment with the direct rendering is through and internal + compiler pre-processor flag. + The current change set enables a way to specified at run-time, as a flag + passed to the allocator at instanciation time. + +2016-10-20 18:09:59 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: log in perf category when copy + Log in performance category when the derive image handling fails, falling back + to memory copy. + +2016-10-20 16:31:21 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: error log is derive image fails + Instead of a silently failure of the derive image, this patch log an error + message according to the failure. + +2016-10-20 12:52:18 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: store surface alloc flags in qdata + For sake of consistency, we should add the requested surface allocation flags + to the object's qdata structure. + +2016-10-20 12:22:06 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: category init when object define + Move the Gstreamer debug category initialize to the GObject definition. + +2016-11-03 08:31:16 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapitexturemap.c: + libs: vaapitexturemap: trivial code-style fix + +2016-11-02 20:01:09 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay_egl.c: + libs: display: egl: avoid recreate native display + Instead of passing the native descriptor of the display, just pass the received + GstVaapiDisplay and reuse it. + +2016-11-02 15:38:52 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: log the GstVaapiDisplay name + Now that GstVaapiDisplay is descendant of GstObject, it has a human-friendly + name. Log it instead of the memory address. + +2016-11-02 18:37:00 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapiwindow_egl.c: + libs: window: egl: pass native va display + When creating a GstVaapiWindowEGL, it also creates native window by its own + native display. It should pass the native display, either X11 or Wayland. + https://bugzilla.gnome.org/show_bug.cgi?id=768266 + +2016-10-13 12:53:17 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapidebug.h: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.h: + * gst-libs/gst/vaapi/gstvaapidisplay_drm_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_egl.c: + * gst-libs/gst/vaapi/gstvaapidisplay_egl.h: + * gst-libs/gst/vaapi/gstvaapidisplay_egl_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.c: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.h: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h: + * gst-libs/gst/vaapi/gstvaapitexture_egl.c: + * gst-libs/gst/vaapi/gstvaapiutils_egl.c: + * gst-libs/gst/vaapi/gstvaapiutils_egl.h: + * gst/vaapi/gstvaapivideocontext.c: + libs: display: GstVaapiDisplay as GstObject descendant + This patch is to change the inheritance of GstVaapiDisplay to GstObject, + instead of GstVaapiMiniObject. In this way we can use all the available + infrastructure for GObject/GstObject such as GstTracer, GIR, etc. + In addition, a new debug category for GstVaapiDisplay is created to make it + easier to trace debug messages. It is named "vaapidisplay" and it transverse + all the VA display backends (DRM, GLX, EGL, Wayland, ...) + This patch is a step forward to expose GstVaapiDisplay for users in a future + library. + https://bugzilla.gnome.org/show_bug.cgi?id=768266 + Signed-off-by: Víctor Manuel Jáquez Leal + +=== release 1.11.0 === + +2016-11-01 18:54:54 +0200 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.10.0 === + +2016-11-01 18:19:32 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * configure.ac: + * gstreamer-vaapi.doap: + Release 1.10.0 + +2016-10-27 17:13:48 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecodebin.c: + vaapidecodebin: resurrect disable-vpp property + https://bugzilla.gnome.org/show_bug.cgi?id=773589 + +2016-10-27 16:32:23 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecodebin.c: + vaapidecodebin: name the internal queue + https://bugzilla.gnome.org/show_bug.cgi?id=773589 + +2016-10-27 16:27:45 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecodebin.c: + * gst/vaapi/gstvaapidecodebin.h: + vaapidecodebin: remove unused variables + Since vaapipostproc is only registered if the driver supports it, all the + support for dynamic loading were removed. Though some leftovers remained. + https://bugzilla.gnome.org/show_bug.cgi?id=773589 + +2016-10-27 12:53:54 +0200 Víctor Manuel Jáquez Leal + + * docs/plugins/Makefile.am: + * docs/plugins/gstreamer-vaapi-plugins-docs.xml.in: + * docs/plugins/running.xml: + docs: document environment variables + https://bugzilla.gnome.org/show_bug.cgi?id=773544 + +2016-10-27 12:31:49 +0200 Víctor Manuel Jáquez Leal + + * docs/plugins/gstreamer-vaapi-plugins-docs.xml.in: + * docs/plugins/gstreamer-vaapi-plugins-sections.txt: + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecodebin.c: + * gst/vaapi/gstvaapidecodedoc.c: + docs: replace vaapidecode with each codec + In the spirit of the codec split, this patch removes the documentation of + vaapidecode and adds a page per each possible decoder. + Nonetheless, only those available in the compilation system are going to be + instrospected, because the rest are not registered. + +2016-10-27 11:06:06 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapivideobuffer.c: + * gst/vaapi/gstvaapivideometa.c: + docs: add missing long descriptions + +2016-10-25 14:32:44 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: use GST_*_OBJECT when possible + Since we can have several vaapipostproc operating in a pipeline, it is useful + to know which one is generating the logging message. + https://bugzilla.gnome.org/show_bug.cgi?id=773497 + +2016-07-19 17:00:23 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + vaapidecode: rename member to allowed_sinkpad_caps + vaapidecode has a member named allowed_caps, but this name is not enough + explicit. This patch renames allowed_caps to allowed_sinkpad_caps. + No functional changes were included. + https://bugzilla.gnome.org/show_bug.cgi?id=773497 + +2016-10-20 18:12:04 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h265.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideometa.c: + * gst/vaapi/gstvaapivideometa_texture.c: + plugins: fix code style for errors + https://bugzilla.gnome.org/show_bug.cgi?id=773497 + +2016-10-20 17:01:57 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: comment style + https://bugzilla.gnome.org/show_bug.cgi?id=773497 + +2016-10-20 11:19:50 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + vaapivideomemory: rename input parameter + In order to clarify the use of flag as input parameter, it is renamed to + surface_alloc_flag, since it is used when creating a VA surface with certain + properties. + https://bugzilla.gnome.org/show_bug.cgi?id=773497 + +2016-10-25 19:22:03 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: rename element description + So encoders and decoders have similar descriptions. + https://bugzilla.gnome.org/show_bug.cgi?id=773497 + +2016-08-02 11:32:19 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h265.c: + vaapiencode: h264, h265: rename codec name + So encoder and decoders have the same codec name. + https://bugzilla.gnome.org/show_bug.cgi?id=773497 + +2016-07-29 15:17:33 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: simplify code + Merge two lines of variable declarations. + https://bugzilla.gnome.org/show_bug.cgi?id=773497 + +2016-10-07 18:46:22 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapipixmap_priv.h: + * gst-libs/gst/vaapi/gstvaapitexture_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow_priv.h: + libs: minor correction for logical consistency + GstVaapiDecode is a descendant of GstVaapiMiniObject, so, thought we should + use its methods, even though it doesn't change functionality. + GstVaapiPixmap, GstVaapiTexture and GstVaapiWindow are descendant of + GstVaapiObject, hence its methods shall be used. + https://bugzilla.gnome.org/show_bug.cgi?id=772554 + +2016-10-19 15:39:54 +0100 Julien Isorce + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: add explanation about the call 'dup (dmabuf_fd)' + In short GstFdMemory is configured to call close when using + GstDmabufMemory. + https://bugzilla.gnome.org/show_bug.cgi?id=755072 + +2016-09-02 16:42:45 +0200 Víctor Manuel Jáquez Leal + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + build: clean up the dlopen usage + +2016-10-08 14:33:59 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + encoder: h264,h265: fix regression in offset count + In commit dc35dafa a bug was introduced because I assumed that + GST_CLOCK_TIME_NONE is zero when is -1. This patch fixes that mistake. + https://bugzilla.gnome.org/show_bug.cgi?id=772259 + +2016-10-18 17:02:59 +0200 Víctor Manuel Jáquez Leal + + * README: + docs: update README + +2016-09-27 17:29:25 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay_egl.c: + libs: display: egl: remove unused header include + The header gmodule.h is not used since the library dynamic loading for EGL + display was removed. + https://bugzilla.gnome.org/show_bug.cgi?id=772599 + +=== release 1.9.90 === + +2016-09-30 13:05:20 +0300 Sebastian Dröge + + * ChangeLog: + * NEWS: + * common: + * configure.ac: + * gstreamer-vaapi.doap: + Release 1.9.90 + +2016-03-04 16:35:11 +0900 Vineeth TM + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecodebin.c: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h265.c: + * gst/vaapi/gstvaapiencode_jpeg.c: + * gst/vaapi/gstvaapiencode_mpeg2.c: + * gst/vaapi/gstvaapiencode_vp8.c: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + vaapi: use new gst_element_class_add_static_pad_template() + https://bugzilla.gnome.org/show_bug.cgi?id=763083 + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-09-22 16:34:48 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapipluginbase.c: + plugins: reset textures at negotiation/shutdown + When caps reconfiguration is called, the new downstream frame size might be + different. Thus, if the downstream caps change,the display's texture map is + reset. + In addition, during pipeline shutdown, textures in texture map have to be + released, since each one have a reference to the GstVaapiDisplay object, which + is a dangerous circular reference. + https://bugzilla.gnome.org/show_bug.cgi?id=769293 + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-09-22 16:34:38 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_egl.c: + * gst-libs/gst/vaapi/gstvaapidisplay_egl_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.c: + * gst-libs/gst/vaapi/gstvaapidisplay_glx_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst/vaapi/gstvaapivideometa_texture.c: + libs: display{egl,glx}: cache GstVaapiTextures + instances when created and reuse + This patch improves performance when glimagesink uploads a GL texture. + It caches the GStVaapiTexture instances in GstVaapiDisplay{GLX,EGL}, using an + instance of GstVaapiTextureMap, so our internal texture structure can be found + by matching the GL texture id for each frame upload process, avoiding the + internal texture structure creation and its following destruction. + https://bugzilla.gnome.org/show_bug.cgi?id=769293 + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-09-22 16:33:06 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapitexturemap.c: + * gst-libs/gst/vaapi/gstvaapitexturemap.h: + libs: vaapitexturemap: implement GstVaapiTextureMap + Implement GstVaapiTextureMap object, which caches VAAPI textures, so them can be + reused. Internally it is a hash table. + Note that it is GstObject based rather than GstVaapiObject, as part of the future + converstion to GstObject of most of the code. + https://bugzilla.gnome.org/show_bug.cgi?id=769293 + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-09-21 09:55:53 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + encoder: vp8: Increase the allocation size for coded buffer + We are not getting enough compression for some streams and + encoded frame end up with more size than allocated. + Assuming a compression ratio of 4, which should be good enough + for holding the frames. + https://bugzilla.gnome.org/show_bug.cgi?id=771528 + +2016-09-21 09:52:21 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + encoder: vp9: Fix refresh frame flag setting + While doing the mode-1 referece picture selection, + the circular buffer logic was not correctly setting the + refresh frame flags as per VP9 spec. + Make sure refresh_flag[0] get updated correclty after + each cycle of GST_VP9_REF_FRAMES. + https://bugzilla.gnome.org/show_bug.cgi?id=771507 + +2016-09-14 18:42:09 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + vaapidecode: codec_data minimal size is 7 + When the format of a H.264 stream is AVC3, the SPS and PPS are inside the + stream, not in the codec_data, so the size of codec_data might be 7. + This patch reduces the minimal size of the codec_data buffer from 8 to 7. + https://bugzilla.gnome.org/show_bug.cgi?id=771441 + +2016-09-14 16:29:01 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: reset decoder hard when set_format() + set_format() is called by upstream when the stream capabilites has changed. + Before, if the new stream is compatible with the old one the VA decoder was + not destroyed. Nonetheless, with this behavoir, the VA decoder ignores + when the upstreamer parsers gets more details of the stream, such as the + framerate. Hence, when the src caps are negotiates, the further sink caps + updates are ignored. + This patch forces the VA decoder destroying and recreation when set_format() + is called. + https://bugzilla.gnome.org/show_bug.cgi?id=770921 + +2016-09-14 11:31:39 +0200 Sebastian Dröge + + * configure.ac: + configure: Depend on gstreamer 1.9.2.1 + +2016-09-09 12:03:37 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + Revert "vaapivideomemory: load VA Image when mapping to write" + This reverts commit c67edea4aba35f16d9e97c78a0b49ad1b590b112. + +2016-09-10 20:52:21 +1000 Jan Schmidt + + * common: + Automatic update of common submodule + From b18d820 to f980fd9 + +2016-09-10 09:58:25 +1000 Jan Schmidt + + * common: + Automatic update of common submodule + From f49c55e to b18d820 + +2016-09-08 16:16:09 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapipluginbase.c: + plugins: set allocator's image size to sinkpad bufferpool + Otherwise the buffer is always ditched by the bufferpool, losing performance. + https://bugzilla.gnome.org/show_bug.cgi?id=771035 + +2016-09-07 17:34:08 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapisurface.c: + libs: surface: ensure composite overlay is not bigger + Ensure the composition overlay rectangle (subtitles) is not bigger than + the surface where it is going to be composited and rendered. + https://bugzilla.gnome.org/show_bug.cgi?id=766978 + +2016-09-07 17:51:23 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: load VA Image when mapping to write + When calling gst_video_frame_map() with GST_MAP_WRITE flag, it doesn't call + ensure_image_is_current(), which means it doesn't guarentee VAImage is valid + in this case. + https://bugzilla.gnome.org/show_bug.cgi?id=766978 + +2016-09-06 12:27:45 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: merge vc1 and wmv3 elements + This patch merges vaapivc1dec and vaapiwmv3dec into a single + vaapivc1dec. Also, removed the WMVA format, since it is not + supported by libva. + https://bugzilla.gnome.org/show_bug.cgi?id=734093 + +2016-09-06 11:19:05 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + decoder: vc1: fails only on advanced profile + In commit 2eb4394 the frame coding mode was verified for progressive + regardless the profile. But the FCM is only valid in the advanced + profile. This patch checks for the advanced profile before verifying FCM for + progressive. + https://bugzilla.gnome.org/show_bug.cgi?id=769250 + +2016-09-01 12:39:15 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapi.c: + vaapi: DISPLAY envvar as dependency + In a multiple video cards system, a X11 environment may have different VA + capabilities. This patch tracks the DISPLAY environment variable to + invalidates the GStreamer features cache. Also tracks WAYLAND_DISPLAY. + https://bugzilla.gnome.org/show_bug.cgi?id=770357 + +2016-08-26 14:55:17 -0700 Scott D Phillips + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + decoder: vc1: Fail only on actual interlaced frames + In the earlier patch: + f31d9f3 decoder: vc1: Print error on interlaced content + Decoding would error out if the interlace flag was set in the + sequence bdu. This isn't quite right because a video can have this + flag set and yet not have any interlaced pictures. + Here instead we error out when either parsing a field bdu or + decoding a frame bdu which has fcm set to anything other than + progressive. + Signed-off-by: Scott D Phillips + https://bugzilla.gnome.org/show_bug.cgi?id=769250 + +2016-09-01 12:34:48 +0300 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.9.2 === + +2016-09-01 12:34:38 +0300 Sebastian Dröge + + * ChangeLog: + * NEWS: + * configure.ac: + * gstreamer-vaapi.doap: + Release 1.9.2 + +2016-08-16 11:58:38 +0300 Scott D Phillips + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + decoder: vc1: Print error on interlaced content + Interlaced video is as yet unsupported in the vc1 element. Print + an error to make that more obvious. + https://bugzilla.gnome.org/show_bug.cgi?id=769250 + +2016-08-10 13:29:45 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: fix C90 mixed declarations and code + Commit 4259d1a introduced this compilation error. This patch fixes it. + +2016-07-21 17:38:40 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + encoder: h264,h265,mpeg2,vp8: use gst_util_uint64_scale() for bitrate + Use gst_util_uint64_scale() to calculate bitrate instead of normal arithmetic + to avoid overflows, underflows and loss of precision. + https://bugzilla.gnome.org/show_bug.cgi?id=768458 + +2016-07-05 20:07:15 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + vaapiencode: h264,h265: validate fps numerator + Validate that fps numerator is non-zero so it can be used to calculate + the duration of the B frame. + Also it gst_util_uint64_scale() is used instead of normal arithmetic in + order to aviod overflows, underflows and loss of precision. + https://bugzilla.gnome.org/show_bug.cgi?id=768458 + +2016-08-06 12:54:17 +0100 Tim-Philipp Müller + + * gst/vaapi/gstvaapi.c: + encoders: demote to RANK_NONE since not fit for autoplugging yet + Encoders claim to support a whole bunch of input formats but then + just error out if the format is not actually supported, even if + there's a converter in front. This means they're not fit for + autoplugging in encodebin or camerabin yet and therefore should + not have a rank. People can still use them in custom pipelines. + https://bugzilla.gnome.org/show_bug.cgi?id=769266 + +2016-07-19 19:24:08 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: check dmabuf-import for sink pad allocator + Check earlier if upstream video source has activated the dmabuf-import + io-mode (hack to disappear soon), thus we can avoid the re-assignation of a + new allocator. + +2016-07-19 20:02:54 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: reset allocators if video info changed + If the frame size or format, change, the allocators are reset, so a new ones + can be created with the new video info. + +2016-07-19 19:27:27 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: remove sink pad allocator if caps change + If the negotiated sinkpad caps change, destroy the assignated allocator, + because it is not valid anymore. + +2016-07-19 20:01:05 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + pluginutil: const params to gst_video_info_changed() + Since they are not modified, we should mark them as const. + +2016-07-29 15:13:29 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + gstvaapivideomemory: allocator's image size getter + Add the method gst_allocator_get_vaapi_image_size() for the + GstVaapiVideoAllocator, which gets the size of the allocated images with the + current video info. + This method replaces the direct call to the allocator's image info when the + pool is configured. + +2016-07-29 18:06:30 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapipluginbase.c: + plugins: update buffer pool size with new allocator's image size + Depends on media, video size is sometimes updated with new allocator. + It leads to dismatch between bufferpool's set size and real allocated buffer size. + In this case, it causes every buffer is freed during release in bufferpool, + which should be reused. This affects performance. + https://bugzilla.gnome.org/show_bug.cgi?id=769248 + +2016-07-27 19:49:59 +0200 Víctor Manuel Jáquez Leal + + * configure.ac: + configure: remove gmodule-2.0 EGL dependency + Since commit 27429ce, EGL support doesn't depend on dynamic loading libraries, + thus the dependency to gmodule-2.0 is not mandatory anymore. + +2016-07-27 10:09:38 -0700 Scott D Phillips + + * configure.ac: + configure: Fix non-fatal PKG_CHECK_MODULES invocations + Some invocations of PKG_CHECK_MODULES were intended to be non-fatal if + the package is missing, but action-if-not-found was given as an empty + string which still causes the default action to run, which halts + execution. + Signed-off-by: Scott D Phillips + https://bugzilla.gnome.org/show_bug.cgi?id=769237 + +2016-07-13 18:34:57 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay_egl.c: + libs: egl: remove dynamic library loading code + Since the upstream of gstreamer-vaapi, the library is not a public shared + object anymore. But the EGL support depended on this dynamic library, so the + EGL support was broken. + This patch removes the dynamic library loading code and instantiates the + EGL display using either X11 or Wayland if available. + https://bugzilla.gnome.org/show_bug.cgi?id=767203 + +2016-07-12 23:47:41 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + vaapidecode: register only the available decoders + In order to register only the available decoders, this patch queries the + created test VA display, which uses the currently used back-end (X11, Wayland, + DRM, …) on the used display device. + https://bugzilla.gnome.org/show_bug.cgi?id=724352 + +2016-06-28 11:43:15 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + vaapi: register only the available encoders + In order to register only the available encoders, this patch queries the + created test VA display, which uses the currently used back-end (X11, + Wayland, DRM, …) on the used display device. + https://bugzilla.gnome.org/show_bug.cgi?id=724352 + +2016-06-07 16:28:07 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecodebin.c: + vaapidecode: split all the codecs + Split the vaapidecode to all the supported codecs with the format + vaapi{codec}dec. + vaapidecode is stil registered as a GObject type, but not as a + GStreamer feature, so it can be used internally by vaapidecodebin without + changing its code too much. + https://bugzilla.gnome.org/show_bug.cgi?id=734093 + +2016-07-12 22:19:37 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecodebin.c: + vaapidecodebin: simplify the code + Since the elements dependant of the VA video processor are now only registered + if it is available, vaapidecodebin code can be simplified a lot, removing all + the code required to check if the VA video processor was available. + https://bugzilla.gnome.org/show_bug.cgi?id=768899 + +2016-07-12 17:54:26 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: delay the GstVaapiDisplay instantiating + Delay the GstVaapiDisplay instantiating until when changing the state from + READY to PAUSE. In this way the element has more chances to find an already + created GstVaapiDisplay, or a GL context, in the pipeline. + https://bugzilla.gnome.org/show_bug.cgi?id=766206 + +2016-07-12 17:49:50 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + pluginutil: set GLX display type + The function gst_vaapi_create_display_from_gl_context() cretes a + GstVaapiDisplay given a GstGLContext. But it didn't created a GLX VA display + when the GL platform was GLX, but a plain X11 VA display. + This patch fixes that, by querying the GL platform earlier. + https://bugzilla.gnome.org/show_bug.cgi?id=766206 + +2016-06-02 19:57:08 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapivideocontext.c: + * gst/vaapi/gstvaapivideocontext.h: + plugins: add gst_vaapi_plugin_base_find_gl_context() + Using the GstContext mechanism, it is possible to find if the pipeline + shares a GstGLContext, even if we are not to negotiating GLTextureUpload + meta. This is interesting because we could negotiate system memory caps + feature, but enable DMABuf if the GstGLContext is EGL with some extensions. + https://bugzilla.gnome.org/show_bug.cgi?id=766206 + +2016-06-28 17:14:06 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + plugins: remove gst_vaapi_plugin_base_driver_is_whitelisted() + Since nobody is calling gst_vaapi_plugin_base_driver_is_whitelisted(), + it is deleted. + +2016-07-12 18:24:10 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.h: + plugins: remove common change_state() vmethod + Remove the common change_state() vmethod for all the plugins, since no one is + using it. + +2016-07-12 20:38:07 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: remove change_state() vmethod + Since the driver checkup is done at registering, there is no need to do it + when changing the element state from NULL to READY. This patch remove this + vmethod from vaapidecode. + +2016-07-12 20:29:12 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapi.c: + vaapi: register vaapipostproc only if supported + Query the GstVaapiDisplay to know if the driver supports video + postprocessing. If does, then register vaapipostproc and vaapidecodebin + elements. + This patch will simplify the design of vaapidecodebin. + https://bugzilla.gnome.org/show_bug.cgi?id=724352 + +2016-06-29 12:36:26 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapi.c: + vaapi: don't register if VA driver is unsupported + Using the test VA display, the driver name is queried, and if it is not + white-listed, the plugin rejects to register any element. + https://bugzilla.gnome.org/show_bug.cgi?id=724352 + +2016-06-28 17:14:06 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + plugins: add gst_vaapi_driver_is_whitelisted() + Move some of the logic in gst_vaapi_plugin_base_driver_is_whitelisted() to a + new function gst_vaapi_driver_is_whitelisted(), in this way, it can be used + when registering the plugin's feature set with the test VA display. + https://bugzilla.gnome.org/show_bug.cgi?id=724352 + +2016-07-12 19:56:02 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapi.c: + vaapi: instantiate a VA display when registering + This patch tries to instantiate a GstVaapiDisplay when registering the plugin + features, if it fails, no gstreamer-vaapi element is registering. + The purpose of this patch is to avoid a situation where the user has + gstreamer-vaapi installed but their VA-API setup is not functional, which may + lead to unexpected behavior. + https://bugzilla.gnome.org/show_bug.cgi?id=724352 + +2016-06-28 11:33:18 +0200 Víctor Manuel Jáquez Leal + + * configure.ac: + * gst/vaapi/gstvaapi.c: + vaapi: declare external dependencies + There are two main external dependencies that define the feature set of this + plugin: a) the kernel and b) the VA driver + This patch tracks both dependencies, if any of them change, GStreamer will + re-inspect the plugin. + The kernel is tracked through the device files /dev/dri/card* + The VA driver is tracked through the files VA_DRIVERS_PATH/*_drv_video.so, + where VA_DRIVERS_PATH is the one defined in libva package configuration. Also, + the environment variables LIBVA_DRIVERS_PATH and LIBVA_DRIVER_NAME are tracked + since they modify the driver lookup. + Additionally, the environment variable GST_VAAPI_ALL_DRIVERS is tracked too. + https://bugzilla.gnome.org/show_bug.cgi?id=724352 + +2016-07-19 16:02:27 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: remove unneeded initializations + GObject's memory is set to zero, so there is no need to initialize to zero or + NULL it's class variables. + +2016-07-19 18:28:28 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.h: + plugins: remove undefined macros + +2016-07-19 17:43:28 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapisurface_drm.c: + Revert "gstvaapisurface_drm: release image when done" + This reverts commit 1dbcc8a0e199f2da6a0ab8e949f13341916128a3 and commit + 372a03a9e38acbf435eb80bf31d9a9844069e504. + While the dmabuf handle is exported, the derive image must exist, otherwise + the image's VA buffer is invalid, thus the dmabuf handle is never released, + leading into a file descriptors leak. + +2016-07-21 17:38:17 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + encoder: h265: fix code-style + +2016-07-22 16:55:59 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: update filters at color balance + This is a fix for a regression of previous commit, which updates the filters + only when the property is set, because it is also required to update the + filter when the color balance interface change its values. + +2016-07-22 12:10:23 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + vaapipostproc: make it enable/disable pass-through mode + In case that sink caps and src caps are same, and no filtering parameter set, + pass-through mode is enabled. + If new filtering parameter is set during playback, it makes it reconfiguring, + so that pass-through mode is changed + In addition, updating filter is performed during reconfiguration, if needed. + https://bugzilla.gnome.org/show_bug.cgi?id=751876 + +2016-07-22 11:51:26 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapifilter.h: + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: checking and updating filter parameter only when it's set + This patch is to avoid checking filter value at every frame. + https://bugzilla.gnome.org/show_bug.cgi?id=751876 + +2016-07-21 11:24:31 +0300 Allen Zhang + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + decoder: h265: handle the SEI NAL units included in codec_data + The prefix/suffix SEI nal units can appear in codec_data too + which weren't handled before. Parse these SEI headers to + fix the segfault. + https://bugzilla.gnome.org/show_bug.cgi?id=768544 + +2016-07-15 16:32:26 +0200 Víctor Manuel Jáquez Leal + + * docs/plugins/Makefile.am: + build: doc: do not redefine MAINTAINERCLEANFILES + MAINTAINERCLEANFILES is defined in gtk-doc-plugins.mak, thus instead of + overload it, the files should be added. + +2016-07-15 14:41:27 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: Fix MVC encode while enabling dct8x8 + Pack the transform_8x8_mode_flag and other necessary rbsp data + in packed_pps header for MVC encode. + https://bugzilla.gnome.org/show_bug.cgi?id=768647 + +2016-07-12 23:58:55 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapisink.c: + vaapisink: demote a debug message to trace + Reduces noise when debugging. + +2016-07-13 17:21:01 +0900 Jagyum Koo + + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + wayland: Error check before using cached wl_display + A planar(or some other) buffer allocation may fail on the driver, then + the wayland connection becomes invalid, not able to send request or + receive any event. So we need to set up a new wayland connection if + there's an error detected on the cached wl_display. + https://bugzilla.gnome.org/show_bug.cgi?id=768761 + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-07-11 21:15:57 +0200 Stefan Sauer + + * common: + Automatic update of common submodule + From ac2f647 to f49c55e + +2016-07-05 18:23:22 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode.c: + vaapiencode: demote a log to trace level + Removes noise when debugging. + +2016-07-06 11:17:23 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapiencode.c: + vaapiencode: implement flush() vmethod + In order to handle correctly seek and other operations, vaapiencode should + flush all the remaining data from the encoder without pushing it downstream. + This patch implements the flush() vmethod, only after of pausing the + source pad task, and restarting it again after the flush stop. + https://bugzilla.gnome.org/show_bug.cgi?id=767176 + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-07-11 08:43:04 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + decoder: vc1: flush dpb only if opened + Flush the decode picture buffer, if and only if, the decoder is + started. Otherwise the dpb structure might be NULL. + https://bugzilla.gnome.org/show_bug.cgi?id=742922 + +2016-07-01 14:42:20 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + vaapidecode: drop non-keyframe in reverse playback + To avoid surface-exhausted situation during reverse playback, + drop frames except for key frame. + Also, to avoid the corruption of the parser state, flush() vmethod + doesn't destroy the VA decoder when playing in reverse. + https://bugzilla.gnome.org/show_bug.cgi?id=742922 + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-07-10 19:33:14 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: unref output frame earlier + The queue in GstVaapiDecode adds an extra reference to the frames. This patch + unref that extra reference earlier making the code simpler to follow. + https://bugzilla.gnome.org/show_bug.cgi?id=768652 + +2016-07-10 19:01:17 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: remove gst_vaapidecode_internal_flush() + As gst_vaapidecode_finish() is the only callee of + gst_vaapidecode_internal_flush(), it is better to inline it. + https://bugzilla.gnome.org/show_bug.cgi?id=768652 + +2016-07-10 18:18:57 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: flush output adapter at drain() + Calling drain() vmethod means "decode any data it can at this point, but that + more data may arrive after". Hence, vaapidecode should check if there is data + in the output adapter and process them, without destroying the decoded picture + buffer (dpb). + Since this operation is done by gst_vaapidecode_internal_flush(), the operation + was refactored into a new function gst_vaapidecode_flush_output_adapter(). + https://bugzilla.gnome.org/show_bug.cgi?id=768652 + +2016-07-10 13:46:25 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: call purge at flush() + Calling flush() vmethod means "to flush all remaining data from the decoder + without pushing it downstream". + Nonetheless flush() is calling gst_vaapidecode_internal_flush(), which calls + gst_video_decoder_have_frame() if there is still something in the input + adapter, which may push buffers to downstream by calling handle_frame(). + This patch changes this behavior by calling gst_vaapidecode_purge() rather + than gst_vaapidecode_internal_flush(), which does what we want: flushes the VA + decoder and releases all the rest of decoded frames. + https://bugzilla.gnome.org/show_bug.cgi?id=768652 + +2016-07-06 18:38:37 +0200 Víctor Manuel Jáquez Leal + + * tests/elements/Makefile.am: + * tests/elements/test-vaapisink.c: + test: elements: remove spurious linkage + Element tests only need to link against gstreamer libraries. + +2016-07-06 14:41:21 +0300 Sebastian Dröge + + * configure.ac: + configure: Require GLib >= 2.40 like everywhere else + +2016-07-06 13:51:21 +0300 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.9.1 === + +2016-07-06 13:48:07 +0300 Sebastian Dröge + + * ChangeLog: + * NEWS: + * common: + * configure.ac: + * gstreamer-vaapi.doap: + Release 1.9.1 + +2016-07-05 20:59:49 +0200 Víctor Manuel Jáquez Leal + + * tests/elements/test-vaapisink.c: + tests: elements: rotate orientation event + +2016-07-01 16:01:54 +0900 Hyunjun Ko + + * configure.ac: + * tests/Makefile.am: + * tests/elements/Makefile.am: + * tests/elements/test-vaapisink.c: + tests: elements: Add testsuite for vaapisink + https://bugzilla.gnome.org/show_bug.cgi?id=765798 + +2016-07-01 16:00:46 +0900 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapitypes.h: + * gst-libs/gst/vaapi/gstvaapivalue.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + vaapisink: add support for GST_TAG_IMAGE_ORIENTATION + https://bugzilla.gnome.org/show_bug.cgi?id=765798 + +2016-06-29 13:57:02 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: return caps template if no display + This patch is a fix for my bad review of commit 6d73ca8d. The element should + be able to return the available raw caps handled by the VA display, but that + only should happen when there a VA display. If there's none, the element + should use the caps template. + https://bugzilla.gnome.org/show_bug.cgi?id=768161 + +2016-06-29 16:42:18 +1000 Matthew Waters + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: don't require a vaapi display for all caps queries + This delays the requirement of having a GstVaapiDisplay until later + https://bugzilla.gnome.org/show_bug.cgi?id=768161 + +2016-06-28 15:48:39 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiutils.c: + utils: report VP9 profiles + Add VP9Profile0-3 name mapping. + +2016-06-28 14:05:51 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapi.c: + vaapi: nest includes under USE_ENCODER macro + This is a missed changeset from commit 1c05c53, since also header includes + should be nested. + +2016-06-28 11:54:33 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapi.c: + vaapi: nest encoders under USE_ENCODER macro + Though USE_{JPEG,VP8,VP9,H265}_ENCODER macros definition depend on USE_ENCODER + macro, it is clearer to nest them, showing explicitly the dependency relation. + +2016-06-24 12:05:24 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideocontext.c: + vaapivideocontext: check if query context is NULL + Under certain conditions the element might receive a positive context query + but without a context instance. This situation will lead to a segmentation + fault when traversing the context list in the pipeline. + https://bugzilla.gnome.org/show_bug.cgi?id=767946 + +2016-06-20 13:22:36 -0700 Scott D Phillips + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/glibcompat.h: + * gst-libs/gst/vaapi/sysdeps.h: + remove unused glibcompat.h + glibcompat.h is no longer doing anything. Remove it. + Signed-off-by: Scott D Phillips + https://bugzilla.gnome.org/show_bug.cgi?id=767886 + +2016-06-22 14:28:44 -0700 Scott D Phillips + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: Use high profile by default + Change defaults for max-bframes, cabac, and dct8x8 to be enabled + by default. This will cause the default profile to be high instead + of baseline. In most situations this is the right decision, and + the profile can still be lowered in the case of caps restrictions. + Signed-off-by: Scott D Phillips + https://bugzilla.gnome.org/show_bug.cgi?id=757941 + +2016-06-22 12:15:29 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecodebin.c: + vaapidecodebin: element warning if missing element + Raise an element warning if a required element is not available, thus the + pipeline will post a warning message and the application will be informed. + +2016-06-22 15:11:56 +0300 Hyunjun Ko + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + decoder: h265: fix to release all dpb pictures + Without this, all dpb pictures are not released during flush, + because we used the global dpb_count variable for checking the + dpb fullness which get decremented in dpb_remove_index() + routine during each loop iteration. + https://bugzilla.gnome.org/show_bug.cgi?id=767934 + +2016-06-21 11:48:54 -0400 Nicolas Dufresne + + * common: + Automatic update of common submodule + From ac2f647 to f363b32 + +2016-06-20 19:53:26 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipostproc.c: + vaapi: fix minor leaks + https://bugzilla.gnome.org/show_bug.cgi?id=767868 + +2016-06-17 17:00:03 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapi.c: + vaapi: remove an already included header + gst/gst.h is already included in gstcompat.h + +2016-06-17 16:53:26 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecodebin.c: + vaapidecodebin: add vp9 in sink pad template + +2016-06-15 20:19:27 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapisink.c: + vaapisink: return caps template if no display + If vaapisink received a caps query before getting a VA display, it returned + only the surfaces related caps. This behavior broke the autovideosink + negotiation. + This patch returns the pad's template caps if no VA display, otherwise the + caps are crafted as before. + https://bugzilla.gnome.org/show_bug.cgi?id=767699 + +2016-06-15 11:25:23 -0700 Scott D Phillips + + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + decoder: vp9: Update comment about context resets + Clarify that vaapi context resets are never needed for vp9, but + that ensure_context() needs called when the size increases so that + new surfaces can be allocated. + Signed-off-by: Scott D Phillips + https://bugzilla.gnome.org/show_bug.cgi?id=767474 + +2016-05-17 15:34:23 -0700 Scott D Phillips + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + gstvaapicontext: control reset_on_resize with option + Signed-off-by: Scott D Phillips + https://bugzilla.gnome.org/show_bug.cgi?id=767474 + +2016-06-14 09:45:22 -0700 Scott D Phillips + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapivideobufferpool: add video meta to config when needed + In cases where we know the video meta must be present, add it to + the pool configuration. + Signed-off-by: Scott D Phillips + https://bugzilla.gnome.org/show_bug.cgi?id=766184 + +2016-06-13 10:48:41 -0700 Scott D Phillips + + * gst/vaapi/gstvaapipluginbase.c: + plugins: retry pool config + if gst_buffer_pool_set_config returns FALSE, check the modified + config and retry set_config if the config is still acceptable. + Signed-off-by: Scott D Phillips + https://bugzilla.gnome.org/show_bug.cgi?id=766184 + +2016-06-08 18:42:43 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.h: + vaapivideomemory: internal attributes to methods + Mark as internal the functions used by VA-API dmabuf allocator. + +2016-06-02 15:41:22 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: remove precondition for decide_allocation() + There's no need to check for the display in the plugin object when + decide_allocation() vmethod is called, because the display will created or + re-created along the method execution. + +2016-06-08 18:44:34 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: avoid possible memory leaks + Get the pool config just before use it, to avoid a memory leak if the + allocator cannot be instantiated. Similarly, return FALSE if the configuration + cannot be set, avoid keep a not used allocator in the pool. + +2016-05-31 11:52:57 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: use GstParentBufferMeta + Instead of using the VASurface proxy's notify, which is internal gstvaapi API, + use the GStreamer's GstParentBufferMeta. + https://bugzilla.gnome.org/show_bug.cgi?id=765435 + +2016-05-31 08:26:33 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: cache VASurfaces from dmabufs + This patch avoids the creation of a VASurface each time a new input buffer is + processed, caching them in the input buffer itself. + https://bugzilla.gnome.org/show_bug.cgi?id=765435 + +2016-05-30 23:55:43 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapisurface_drm.c: + * gst-libs/gst/vaapi/gstvaapisurface_drm.h: + * gst/vaapi/gstvaapipluginbase.c: + libs: change gst_vaapi_surface_new_with_dma_buf_handle() + Instead of passing the data already in GstVideoInfo, let's just pass the + GstVideoInfo structure. + https://bugzilla.gnome.org/show_bug.cgi?id=765435 + +2016-05-25 12:31:15 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + plugins: use an unique allocator per pad + Instead of instantiating an allocator per vaapivideobufferpool, only one + allocator is instantiated per element's pad and shared among future pools. + If the pad's caps changes, the allocator is reset. + https://bugzilla.gnome.org/show_bug.cgi?id=765435 + +2016-05-25 10:58:01 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapivideobufferpool.c: + * gst/vaapi/gstvaapivideobufferpool.h: + vaapivideobufferpool: share options flag with pluginbase + Originally, vaapivideobufferpool has a set of boolean variables for the + buffer configuration options. + This pach changes these boolean variables for a single bitwise, just as + it is used in pluginbase. Hence, the internal enum was moved to + vaapivideobufferpool header. + https://bugzilla.gnome.org/show_bug.cgi?id=765435 + +2016-05-10 15:57:06 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: add gst_vaapi_plugin_base_create_pool() + This patch refactors the code in pluginbase in order to centralize the buffer + pool instantiation. As the buffer pool config may have different options, these + are gathered using a bitwise flag. + https://bugzilla.gnome.org/show_bug.cgi?id=765435 + +2016-05-20 18:46:14 +0200 Víctor Manuel Jáquez Leal + + pluginbase negotiates allocator with bufferpool + Originally vaapivideobufferpool instantiates its own allocator regardless the + received configuration, and it relies in custom configuration options to + choose which kind of allocator instantiate. + This patch transfers the responsibility of the allocator instantiate to + vaapipluginbase and pass it to the vaapivideobufferpool through its + configuration. + * gst/vaapi/gstvaapipluginbase.c + + set_dmabuf_allocator(): inserts a dmabuf allocator in the bufferpool + + ensure_sinkpad_buffer_pool(): set a normal vaapi video allocator in + bufferpool configuration + + gst_vaapi_plugin_base_propose_allocation(): call set_dmabuf_allocator() if + needed. + + gst_vaapi_plugin_base_decide_allocation(): set a normal vaapi video + allocator in bufferpool configuration + * gst/vaapi/gstvaapivideobufferpool.c + + gst_vaapi_video_buffer_pool_set_config(): instead of instantiate the + allocator, process the received one through its configuration. + * gst/vaapi/gstvaapivideobufferpool.h: removed + GST_BUFFER_POOL_OPTION_DMABUF_MEMORY since it is not used anymore. + * gst/vaapi/gstvaapivideomemory.c + + gst_vaapi_is_dmabuf_allocator(): new helper function to identify a dmabuf + allocator with the vaapi qdata. + https://bugzilla.gnome.org/show_bug.cgi?id=765435 + +2016-05-20 14:39:23 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapivideobufferpool: keep only current video info + Instead of keeping old and new GstVideoInfo video structure, we only keep one, + the current one, the negotiated. The old one is not needed at all. + https://bugzilla.gnome.org/show_bug.cgi?id=765435 + +2016-05-23 15:38:07 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapivideomemory.c: + pluginutil: add gst_video_info_force_nv12_if_encoded() + This lines repeat a couple times in the code, so it would be better to put it + a helper function. + https://bugzilla.gnome.org/show_bug.cgi?id=765435 + +2016-05-20 14:15:53 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapivideobufferpool.c: + pluginutil: add gst_video_info_changed() helper + This function is shared among different elements, so let factorized it. + https://bugzilla.gnome.org/show_bug.cgi?id=765435 + +2016-06-08 10:14:16 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapipostprocutil.c: + vaapipostproc: Add colorimetry attributes to src caps + https://bugzilla.gnome.org/show_bug.cgi?id=766596 + +2016-06-08 10:17:46 +0900 Hyunjun Ko + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: remove chroma-site and colorimetry from src caps + https://bugzilla.gnome.org/show_bug.cgi?id=766596 + +2016-06-07 14:19:50 -0700 Scott D Phillips + + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + vaapipostproc: add postproc_lock to protect data members + Add a mutex to postproc to protect concurrent access to data members. + Previously set_caps() could release the allowed_srcpad_caps while + transform_caps was in the middle of using it. + Signed-off-by: Scott D Phillips + https://bugzilla.gnome.org/show_bug.cgi?id=766940 + +2016-05-30 11:30:40 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.h: + encoder: vp9: Add simple algorithms for reference picture selection + Added two modes(as properties) for reference picture selection: + ref-mode-0: AltRef and GoldRef pointing to the recent keyframe + and LastRef is pointing to the previous frame. + ref-mode-1: Previous frame (n) as LastRef , n-1 th frame as GoldRef + and n-2 th frame as AltRef + https://bugzilla.gnome.org/show_bug.cgi?id=766048 + +2016-05-30 11:25:52 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + encoder: vp9: Define Max frame width and height + https://bugzilla.gnome.org/show_bug.cgi?id=766048 + +2016-05-30 11:25:03 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.h: + encoder: vp9: Add more propertis for tuning encode quality + Added three tuning properties: + 1: filter_level + 2: sharpness_level + 3: luma ac quant-table index + https://bugzilla.gnome.org/show_bug.cgi?id=766048 + +2016-05-30 11:24:14 +0300 Sreerenj Balachandran + + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapiencode_vp9.c: + * gst/vaapi/gstvaapiencode_vp9.h: + Add vp9 encode element to "vaapi" plugin + https://bugzilla.gnome.org/show_bug.cgi?id=766048 + +2016-05-30 11:23:12 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp9.h: + Add vp9 encoder support in libgstvaapi + https://bugzilla.gnome.org/show_bug.cgi?id=766048 + +2016-05-30 11:22:35 +0300 Sreerenj Balachandran + + * configure.ac: + build: Add check for VP9 encode API support in libva + https://bugzilla.gnome.org/show_bug.cgi?id=766048 + +2016-05-26 11:42:32 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapisurface_drm.c: + gstvaapisurface_drm: fix internal documentation + +2016-05-26 11:41:25 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapisurface_drm.c: + gstvaapisurface_drm: fix code-style + +2016-05-25 12:28:48 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: remove unused header + Remove the include of gst/allocators/allocators.h since it is not used. + +2016-05-25 10:36:33 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideobufferpool.h: + vaapivideobufferpool: remove GL_TEXTURE_UPLOAD_META + Since gstreamer-vaapi is coupled with gstreamer releases, there is no need to + keep compatibility definition. + This patch removes the definition of + GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META since it is in + gst-plugins-base version 1.2.2 + +2016-05-23 22:49:11 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: add gst_vaapi_buffer_pool_caps_is_equal() + This is a helper function to improve the readability of + ensure_sinkpad_buffer_pool(). It makes clearer when the buffer pool needs to be + re-instantiated. + +2016-05-24 16:29:33 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: deactivate buffer pool before unref + This buffer pool may still be processing buffers when a caps renegotiation is + done. This one-liner patch deactivates the pool to drain it before it + de-allocation. + +2016-05-24 16:22:24 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: no sinkpad bufferpool when decoder + Right now, the decoders create a buffer pool for their sink pad which is not + used at all, because the decoders have never proposed it to upstream. + This patch avoids the buffer pool instantiating when the element inherits from + the GstVideoDecoder class. + +2016-05-24 13:39:25 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: avoid to get/set pool config twice + This patch is a bit of optimization, since the bufferpool configuration is get + when the pool is created. Hence, we only need to request it when the pool from + the allocation query is reused. + +2016-05-13 13:14:23 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: destroy pool earlier if non-vaapi + If the offered pool in decide_allocation() vmethod doesn't have the + VAAPI_VIDEO_META option, it is destroyed immediatly and the pointer cleared, + so it could be created later. + +2016-05-23 22:30:04 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapivideobufferpool: split caps validation + When validating the caps from bufferpool config, this patch distinguishes the + error from no caps received (NULL) from the invalid caps (cannot be converted + into GstVideoInfo structure). + +2016-05-23 22:21:15 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginbase.c: + plugins: check for caps in query earlier + Check for caps as soon gst_query_parse_allocation() returns. + +2016-05-23 23:13:55 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + plugins: remove unused variables + This variables stopped to be used since commit 001a5c63, which removed the + gstvaapiuploader. + +2016-05-23 18:47:46 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: fix potential memleak from commit 9159328 + If gst_video_info_from_caps() fails it is required to unref the instantiated + pool. + +2016-05-23 18:04:47 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: handle if gst_video_info_from_caps() fails + Return FALSE is the received caps cannot be transformed into a GstVideoInfo + structure. + +2016-05-23 17:55:35 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: handle if gst_video_info_from_caps() fails + Let's play safe and return error if, somehow, the received caps are wrong. + +2016-05-23 17:47:36 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: relate errors to instance + Use GST_{ERROR,WARNING}_OBJECT instead of GST_{ERROR,WARNING}, thus the logs + will show the name of the vaapipluginbase instance that failed. + Also, the code-style is fixed, where some error labels need to be surrounded + by braces. + +2016-05-20 21:01:02 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapisink.c: + plugins: use GstVideoInfo accessors + Instead of access to GstVideInfo members directly, use their accessors + macros. This patch makes more resistance to future changes in GStreamer core. + +2016-05-20 19:33:39 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapisurface_drm.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipostproc.c: + * tests/simple-encoder.c: + remove spurious gst_video_info_init() + gst_video_info_set_format() and gst_video_info_from_caps() call, internally, + gst_video_info_init(), hence it is not required to call it before them. This + patch removes these spurious calls. + +2016-05-20 19:15:11 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + vaapipluginbase: code-style: rename goto label + The error labels have error_ prefix, but this one. + +2016-05-19 16:34:50 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: use allocator custom alloc flag + Instead of a dummy alloc() vmethod, the allocator instance set the flag + GST_ALLOCATOR_FLAG_CUSTOM_ALLOC, which is used by the framework to avoid call + gst_allocator_alloc() on the allocator. + +2016-05-06 13:17:47 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapivideobufferpool: relate errors to instance + Use GST_ERROR_OBJECT instead of GST_ERROR, thus the logs will show the name of + the vaapivideobufferpool instance that failed. + +2016-05-10 16:14:48 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: remove gst_vaapi_plugin_base_set_pool_config() + This function helper make sense for GStreamer 1.2, but it is not helpful for + greater version since the validation is already done in the API implementation. + Thus, it is removed. + +2016-05-18 17:05:03 +0300 Sreerenj Balachandran + + * gst/vaapi/gstvaapipluginbase.c: + gstvaapipluginbase: Fix typo in doc + +2016-05-13 11:45:20 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder : h264: Disable b-frame encode in low-power mode + This is a workaround since vaapi-intel-driver doesn't have + support for B-frame encode when utilizing low-power-enc + hardware block. + Fixme :We should query the VAConfigAttribEncMaxRefFrames + instead of blindly disabling b-frame support and set b/p frame count, + buffer pool size etc based on the query result. + https://bugzilla.gnome.org/show_bug.cgi?id=766050 + +2016-05-13 11:44:57 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + encoder: h264 : Use "tune=low-power" for enabling lowpower encode + Remove the duplicate property "low-power-enc" and use the + tune property for enabling low power encoding mode. + https://bugzilla.gnome.org/show_bug.cgi?id=766050 + +2016-05-11 12:06:38 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + gstvaapiencoder:Use internal api to dervie configured VAEntrypoint + https://bugzilla.gnome.org/show_bug.cgi?id=766050 + +2016-05-11 12:05:36 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + encoder: h264: Add support of low power/high performance encoding mode + Added a new property "low-power-enc" for enabling low power + encoding mode. Certain encoding tools may not be available + with the VAEntrypointEncSliceLP. + https://bugzilla.gnome.org/show_bug.cgi?id=766050 + +2016-05-11 12:04:46 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapitypes.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapivalue.c: + Add mapping for Macroblock level rate control (VA_RC_MB) + +2016-05-11 12:03:08 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + gstvaapidisplay: Add VAEntrypointEncSliceLP support + https://bugzilla.gnome.org/show_bug.cgi?id=766050 + +2016-05-11 11:59:59 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + gstvaapiprofile : Add VAEntrypointEncSliceLP definitions + This is for implementations that supports low_power/high_performance + variant for slice level encode. + https://bugzilla.gnome.org/show_bug.cgi?id=766050 + +2016-05-05 18:23:10 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostprocutil.c: + vaapipostproc: negotiate frame size fixation + Refactor _fixate_frame_size(). Now, instead of fixating the frame size only + using the sink caps, also it use the next capsfilter. + This code is a shameless copy of gst_video_scale_fixate_caps() from + https://cgit.freedesktop.org/gstreamer/gst-plugins-base/tree/gst/videoscale/gstvideoscale.c?id=1.8.1#n634 + https://bugzilla.gnome.org/show_bug.cgi?id=758548 + +2016-05-06 10:50:10 +0200 Scott D Phillips + + * gst/vaapi/gstvaapipostprocutil.c: + vaapipostproc: don't use GstVideoInfo for src caps + Instead of using gst_video_info_to_caps () to generated the fixed src caps, + this patch enables the first step for caps negotiation with a possible + following caps filter. + _get_preferred_caps() will traverse the possible src caps looking for the one + wit the preferred feature and the preferred color format. Then the color + format, the frame size and the frame rate are fixated. + https://bugzilla.gnome.org/show_bug.cgi?id=758548 + +2016-05-05 15:32:36 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostprocutil.c: + * gst/vaapi/gstvaapipostprocutil.h: + vaapipostproc: move gst_vaapipostproc_fixate_srccaps() + Move gst_vaapipostproc_fixate_srccaps() to gstvaapiposptprocutil. + No functional changes. + https://bugzilla.gnome.org/show_bug.cgi?id=758548 + +2016-05-05 15:19:02 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: simplify code + Change a convoluted snippet to find the preferred color format in the peer + caps. + https://bugzilla.gnome.org/show_bug.cgi?id=758548 + +2016-05-05 15:16:02 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: use othercaps for preferred caps + Instead of the allowed_srcpad_caps variable, this patch uses the othercaps + from fixate_caps() vmethod to find the preferred caps feature and color + format. + https://bugzilla.gnome.org/show_bug.cgi?id=758548 + +2016-05-05 13:46:11 +0200 Scott D Phillips + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: add fixate_caps() vmethod + Instead of fixating the srcpad caps in transform_caps() vmethod, this patch + implements the fixate_caps() vmethod and moves code around. + https://bugzilla.gnome.org/show_bug.cgi?id=758548 + +2016-05-05 12:07:59 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostprocutil.c: + * gst/vaapi/gstvaapipostprocutil.h: + vaapipostproc: set early properties restrictions + When running transform_caps() vmethod, returning the srcpad caps, the caps are + early restricted to the element properties set: width, height, format and + force keep aspect. + A new file was added gstvaapipostprocutil.{c,h} where the utilities functions + are stored. + https://bugzilla.gnome.org/show_bug.cgi?id=758548 + +2016-04-25 13:45:04 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: log the caps transformation + https://bugzilla.gnome.org/show_bug.cgi?id=758548 + +2016-04-27 21:20:32 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: no GLTextureUpload in sinkpad + As the vaapipostproc does not process frames with the VideoGLTextureUpload + meta, the feature is removed from the sink pad template. + https://bugzilla.gnome.org/show_bug.cgi?id=765931 + +2015-09-28 08:49:39 +0100 Julien Isorce + + * gst/vaapi/gstvaapivideobufferpool.c: + vaapibufferpool: do not create texture upload meta if dmabuf + https://bugzilla.gnome.org/show_bug.cgi?id=755072 + +2016-05-06 12:16:26 +0200 Víctor Manuel Jáquez Leal + + * git.mk: + build: update git.mk + +2016-04-29 13:11:48 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.h: + plugin: fix macro processor check + Instead of #ifdef it should be used #if becasuse USE_GST_GL_HELPERS is always + defined in config.h, but it would be 0 or 1 depending on the configure output. + https://bugzilla.gnome.org/show_bug.cgi?id=765702 + +2016-04-29 12:53:06 +0200 Víctor Manuel Jáquez Leal + + * tests/test-display.c: + tests: display: guard possible unused variables + https://bugzilla.gnome.org/show_bug.cgi?id=765702 + +2016-04-29 12:48:44 +0200 Víctor Manuel Jáquez Leal + + * tests/codec.c: + * tests/decoder.c: + * tests/image.c: + * tests/output.c: + * tests/simple-decoder.c: + * tests/test-decode.c: + * tests/test-display.c: + * tests/test-filter.c: + * tests/test-h264.c: + * tests/test-jpeg.c: + * tests/test-mpeg2.c: + * tests/test-mpeg4.c: + * tests/test-subpicture-data.c: + * tests/test-subpicture.c: + * tests/test-surfaces.c: + * tests/test-textures.c: + * tests/test-vc1.c: + * tests/test-windows.c: + tests: inforce gstreamer code-style + +2016-04-27 17:10:26 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + encoder: h265: Enable cu_qp_delta_enabled_flag for CBR + It seems driver requires enablement of cu_qp_delta_enabled_flag + for modifying QP values to controll the CBR mode bitrate. + https://bugzilla.gnome.org/show_bug.cgi?id=749852 + +2016-04-27 17:06:09 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + encoder: h265: Add CBR Encoding support + https://bugzilla.gnome.org/show_bug.cgi?id=749852 + +2015-11-27 05:09:10 +0000 Julien Isorce + + * gst-libs/gst/vaapi/gstvaapisurface.c: + gstvaapisurface: explicitely clear TILING flag if dmabuf + https://bugzilla.gnome.org/show_bug.cgi?id=755072 + +2015-10-04 23:44:16 +0100 Julien Isorce + + * gst-libs/gst/vaapi/gstvaapisurface_drm.c: + gstvaapisurface_drm: release image when done + Otherwise intel-vaapi-driver will fail to process the exported surface because + it will find it is currently derived, so considered as busy. + https://bugzilla.gnome.org/show_bug.cgi?id=755072 + +2015-09-26 06:25:12 +0100 Julien Isorce + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: already have a surface proxy if dmabuf + https://bugzilla.gnome.org/show_bug.cgi?id=755072 + +2016-03-11 08:58:51 +0000 Julien Isorce + + * gst/vaapi/gstvaapipostproc.c: + various gst-indent + +2016-04-21 15:14:47 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + vaapidecode: search driver in whitelist + If the backend driver vendor string is not in a white-list, and the + environment variable GST_VAAPI_ALL_DRIVERS is not set either, the decoder will + change it state from NULL to READY, hence the auto-plug mechanism will look + for another decoder. + This patch assumes the GstContext has already being shared along the pipeline + and the element has a valid GstVaapiDisplay instance. + https://bugzilla.gnome.org/show_bug.cgi?id=764673 + +2016-04-21 12:57:30 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + plugins: rework set_context() vmethod definition + In bug 757598 was added the set_context() vmethod chain up in + GstVaapiPluginBase. But it is buggy, since the parent_class address is + assigned to the last element which called gst_vaapi_plugin_base_class_init(). + No error has shown up since none of the element's base classes redefined + set_context() vmethod from GstElement, so always the correct function was + called. Still this code is wrong and this patch make it right. + Since set_context() is the same code, a macro is used to implement that code + in all the gst-vaapi elements. + https://bugzilla.gnome.org/show_bug.cgi?id=765368 + +2016-04-15 17:57:25 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: resize if negotiated and allocation caps are different + Since commit 859a2b2, in vaapidecode, allocation query can be different from + the negotiated caps. + When connecting the vaapidecoder to the vaapipostprocessor, the last one will + resize the frame to the negotiated, if and only if, some other parameter is + activated to avoid the passthrough. If it is not, the surface won't be mapped + into a image. If not, the image won't be resized and the output buffer would be + mapped. + This patch will break the passthrough if the allocation query is different + from the negotiation caps, forcing the resizing. + https://bugzilla.gnome.org/show_bug.cgi?id=765095 + +2016-04-05 13:09:37 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: improve code readability + No functional changes. + +2016-04-05 13:37:40 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: move GstCapsFeatures near to its use + Move the handling of the GstCapsFeatures just after it is used, in order to + avoid handling its memory. + +2016-04-05 13:07:14 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: caps negotiation checks + Check that GLUploadTexture is not negotatiated if gstreamer-vaapi is not + compiled with GL support. + +2016-03-10 16:43:16 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + * gst/vaapi/gstvaapipostproc.c: + plugins: remove param in gst_vaapi_plugin_base_decide_allocation() + +2016-03-10 16:42:04 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: bail early if not caps in decide_allocation() + +2016-03-29 14:17:54 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapipostproc.c: + plugin: use allowed caps filter from element + Instead of using the srcpad template caps for filtering the peer caps, the + function gst_vaapi_find_preferred_caps_feature(), now receives a new parameter + for the element's allowed caps. + With this modification, the vaapipostproc element simplifies a bit its code. + https://bugzilla.gnome.org/show_bug.cgi?id=765223 + +2016-04-18 17:28:51 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapipostproc.c: + plugin: remove function parameter + The native format parameter in gst_vaapi_find_preferred_caps_feature() can be + saved if the out format is used for both: in and out. Thus the code is more + readable. + https://bugzilla.gnome.org/show_bug.cgi?id=765223 + +2016-04-18 17:17:58 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: warns if driver will do color conversions + If the downstream feature is system memory, the surface has to be mapped, + hence a warning message is logged saying that the driver has to do color + conversions. This might be troublesome because not all the color conversion + combinations are supported by the VA-API drivers, and there is not a reliable + way to know them before hand. + https://bugzilla.gnome.org/show_bug.cgi?id=765223 + +2016-03-29 13:28:27 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + plugin: honour negotiated format + Instead of setting the requested format by the caller, the function + gst_vaapi_find_preferred_caps_feature() now returns, in the output parameter, + the negotiated format. + A new helper function was added: gst_vaapi_find_preferred_format(), which, + given the format list from the negotiated caps, will choose the best one, if + possible, given the native format. + https://bugzilla.gnome.org/show_bug.cgi?id=765223 + +2016-03-28 19:26:02 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + plugin: simplify caps feature selection + This patch simplifies the function gst_vaapi_find_preferred_caps_feature(). + Instead of intersecting custom caps to find the preferred feature, the peer + caps are traversed in order to find the preferred feature, according to an + ordered feature priority list. + In the case of GLTextureUploadMeta, the colour format is computed using + GstVideoInfo of the selected fixed caps. + https://bugzilla.gnome.org/show_bug.cgi?id=765223 + +2016-03-31 16:39:08 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: use macros for GstVideoInfo + Instead of accessing directly to the members of the structure, use the macros. + +2016-04-14 17:02:23 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: refactor is_display_resolution_changed() + Make the comparisons more readable and simple. + https://bugzilla.gnome.org/show_bug.cgi?id=764316 + +2016-04-14 16:43:07 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + vaapidecode: keep only display_{width,height} + Instead of keeping the structure GstVideoInfo when we are using its width and + height, we only keep these two guints. + https://bugzilla.gnome.org/show_bug.cgi?id=764316 + +2016-04-14 16:31:34 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: decoded_info is valid at src caps update + As decoded_info is assured to be valid when gst_vaapidecode_update_src_caps() + is called, then we don't need to verify or replace it with the sinkpad info + (reference state). + https://bugzilla.gnome.org/show_bug.cgi?id=764316 + +2016-04-14 16:22:25 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: always a valid format in decoded_info + Always set a valid format in decoded_info class variable. + https://bugzilla.gnome.org/show_bug.cgi?id=764316 + +2016-03-25 15:31:28 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: code style fixes + No functional changes. + https://bugzilla.gnome.org/show_bug.cgi?id=764316 + +2016-04-14 16:10:02 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: init {decoded,display}_info at open() + It is required to initialize {decoded,display}_info variables when the decoder + is open, not only at instance initialization. + https://bugzilla.gnome.org/show_bug.cgi?id=764316 + +2016-03-28 15:30:28 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + vaapidecode: remove spurious class variables + active, do_pool_renego and do_outstate_renego class variables were used to + indicate when negotiate downstream once, but now that each time a new surface + resolution is pop out a renegotation verified, these variable are not required + anymore. + https://bugzilla.gnome.org/show_bug.cgi?id=764316 + +2016-04-14 15:46:32 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + * gst/vaapi/gstvaapipostproc.c: + remove custom allocation query + When resolving bug 753914, a custom allocation query was added, overlapping + the responsibilities of GstVideoDecoder. + But with the merge of the patches from bug 764421 this overlapping was not + required anymore. This patch restores this situation setting the + allocation_caps in the GstVideoCodecState when needed. + https://bugzilla.gnome.org/show_bug.cgi?id=764316 + +2016-04-14 10:04:47 +0100 Julien Isorce + + * common: + Automatic update of common submodule + From 6f2d209 to ac2f647 + +2016-04-13 15:44:20 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecodebin.c: + * gst/vaapi/gstvaapipostproc.c: + plugins: disable GL_TEXTURE_UPLOAD if no EGL/GLX + The plugins should not expose the feature meta:GstVideoGLTextureUploadMeta in + their caps templates if they were not compiled either with GLX or EGL support. + +2016-04-13 20:33:32 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + plugins: fix compilation when EGL/GLX is disabled + The compiler might complain of gst_vaapi_create_display_from_handle() being + unused if both EGL and GLX are disabled. This patch avoid that compilation + error. + +2016-04-13 14:09:00 +0200 Michael Olbrich + + * gst-libs/gst/vaapi/gstvaapicodedbufferpool.c: + libs: fix deleting a GstVaapiCodedBufferPool object + Call gst_vaapi_video_pool_finalize() in coded_buffer_pool_finalize(). + Otherwise it is not called when the pool is destroyed and all objects + referenced by the GstVaapiVideoPool are never released. + https://bugzilla.gnome.org/show_bug.cgi?id=764993 + +2016-04-07 18:03:42 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapisurface.c: + surface: destroy derived image + If gst_vaapi_image_new_with_image() fails, the created derived image should be + destroyed, otherwise the surface cannot be processed because is being used. + https://bugzilla.gnome.org/show_bug.cgi?id=764607 + +2016-03-18 20:00:52 -0300 Thiago Santos + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: add stop function + Clear any status on the current stream: + stored frames, caps and decoder configuration + https://bugzilla.gnome.org/show_bug.cgi?id=763460 + +2016-04-01 14:00:28 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + decoder: vp9: Align with the ABI changes in vp9 codecparser + The subsampling_x, subsampling_y, bit_depth, color_space and color_range + fileds are moved from GstVp9FrameHdr to the global GstVp9Parser structure. + These fields are only present in keyframe or intra-only frame, no need to + duplicate them for inter-frames. + https://bugzilla.gnome.org/show_bug.cgi?id=764082 + +2016-04-01 13:59:59 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + decoder: vp9 : Add 10bit decoding support (Profile2) + https://bugzilla.gnome.org/show_bug.cgi?id=764082 + +2016-04-01 13:57:45 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + gstvaapiporfile: Add more VP9 profile definitions + https://bugzilla.gnome.org/show_bug.cgi?id=764082 + +2016-02-03 20:34:49 +0100 Víctor Manuel Jáquez Leal + + * Makefile.am: + * configure.ac: + build: possibility to disable tests + The configuration option --disable-examples will disable the compilation of + the sample apps in tests/ directory. + +2016-03-29 14:25:55 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h265.c: + * gst/vaapi/gstvaapiencode_jpeg.c: + * gst/vaapi/gstvaapiencode_mpeg2.c: + * gst/vaapi/gstvaapiencode_vp8.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapisink.c: + unify caps template for VAAPI encoders and decoders + There is no difference in VAAPI surface caps between encoders and decoders. + Thus, the patch makes a simplification by removing encoders specific caps and + shares the same definition of VAAPI surfaces caps for all the elements. + +2016-03-10 17:42:55 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: move gst_vaapidecode_negotiate() code + With it we can remove a function declaration, making the code a bit + more readable. + https://bugzilla.gnome.org/show_bug.cgi?id=764316 + +2016-03-29 13:50:00 +0200 Víctor Manuel Jáquez Leal + + * docs/plugins/gstreamer-vaapi-plugins-docs.xml.in: + * docs/plugins/gstreamer-vaapi-plugins-sections.txt: + * gst/vaapi/gstvaapidecode.c: + docs: generate vaapijpegdec documentation + https://bugzilla.gnome.org/show_bug.cgi?id=764314 + +2016-03-30 14:37:21 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + decoder: h265: Fix offset calculation when there is more than one vps/sps/pps present in codec_data + The array_completeness, reserved bit and num_nal_units fields + in HEVCDecoderConfigurationRecord will be present for each VPS/SPS/PPS array list, + but not for each occurance of similar headers. + https://bugzilla.gnome.org/show_bug.cgi?id=764274 + +2016-03-29 15:34:38 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/video-format.c: + video-format: Keep the HW order preference while mapping to GstVideoFormats + +2016-03-29 15:02:46 +0300 Sreerenj Balachandran + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapivideomemory.c: + gst/vaapi: keep precedence for NV12 over I420 + Use NV12 as default "assumption" format all over. + NV12 is the default high priority format used my most of the + vaapi-drivers. + +2016-03-29 14:34:37 +0300 Sreerenj Balachandran + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: Use video format derived from decoded surface as default src pad format + Use the surface format derived from first decoded surface + to negotiate the downstream video format capabilities. + https://bugzilla.gnome.org/show_bug.cgi?id=759181 + +2016-03-29 14:34:00 +0300 Scott D Phillips + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/video-format.c: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapisink.c: + Add P010 video format support + The P010 video format is the native format used by the vaapi intel driver + for HEVCMain10 decode . Add support for planes and images of this video format. + https://bugzilla.gnome.org/show_bug.cgi?id=759181 + +2016-03-27 09:11:00 +0000 Stephen + + * gst-libs/gst/vaapi/gstvaapiutils_x11.c: + libs: x11: allows 30-bit colour depth + The colour depth is clamped to 24 when it is not equal {15,16,24,32}. But this + fails with the NVIDIA binary driver as it doesn't advertise a TrueColor visual + with a depth of 24 (only 30 and 32). Allowing the depth to be 30, lets everything + work as expected. + https://bugzilla.gnome.org/show_bug.cgi?id=764256 + +2016-03-28 13:13:56 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideometa_texture.c: + gltextureupload: use an array for texture type + Instead of using a single value for the texture type, use an array with 4 + elements, just as the GstVideoGLTextureUploadMeta, avoiding a buffer + overflow. + https://bugzilla.gnome.org/show_bug.cgi?id=764231 + +2016-03-24 15:09:43 +0200 Sreerenj Balachandran + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginbase.c: + vaapidecode: Fix decide_allocation handling + Set the already configured pool in decide_allocation query + in cases where pool renegotiation is not required. + https://bugzilla.gnome.org/show_bug.cgi?id=753914 + +2016-03-24 15:09:15 +0200 Sreerenj Balachandran + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: Derive and save the decoded surface format + After the decoding of first frame, try to extract the exact + decoded surface format using vaDeriveImage and keep this + as the format in decoded_info. + https://bugzilla.gnome.org/show_bug.cgi?id=753914 + +2016-03-24 15:08:50 +0200 Sreerenj Balachandran + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + * gst/vaapi/gstvaapipostproc.c: + Make vaapidecode to advertise the cropped values in srcpad, but negotiate pool only if needed + -- Maintaing decoded surface resoluton and actual display resoultion separately + -- Before pushing every frames downstream, check for the requirement of pool negoation and + output_state negotiation: This is needed to avoid multiple issuses with cropping, + multi-resoluton video handling, more complex multi resolution decode scenarios for vp9decode, + possible wrong behaviour from upstream element to report uncropped values etc. Due to these reasons, + We can't just reliably use the resolution change notification from libgstvaapi for pool renegotiation too. + This is slight overhead, but safe enough. Optimization could be possible though. + https://bugzilla.gnome.org/show_bug.cgi?id=753914 + +2016-03-24 15:08:27 +0200 Sreerenj Balachandran + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: Delay the output format setting until we have a decoded surface + This will help to consoidate the out caps negotiation to a single place, + which will make the code simpler, allows to get the exact decoded format + if needed and the selected chroma type too. + https://bugzilla.gnome.org/show_bug.cgi?id=753914 + +2016-03-24 13:36:24 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.h: + vaapidecode: GST_VAAPIDECODE macro is a cast + This patch is the continuation of commit 1e1d3b1d because the function + gst_vaapidecode_get_type() got undefined since then. + Now, the macro GST_VAAPIDECODE is a simple cast to the GstVaapiDecode + structure. The rest of the GObject handling macros were deleted too. + +2016-03-24 13:34:18 +0200 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.8.0 === + +2016-03-24 13:11:05 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * configure.ac: + * gstreamer-vaapi.doap: + Release 1.8.0 + +=== release 1.7.91 === + +2016-03-15 12:39:20 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * configure.ac: + * gstreamer-vaapi.doap: + Release 1.7.91 + +2016-03-11 17:44:07 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + decoder: h265: Fix offset calculation in codec_data parsing + https://bugzilla.gnome.org/show_bug.cgi?id=762922 + +2016-03-09 20:26:31 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecodebin.c: + vaapidecodebin: don't handle jpeg decoding + As JPEG decoder has been split and demoted, it cannot be handled by + vaapidecodebin + Added a fixme comment regarding the future removal of vaapidecode. + https://bugzilla.gnome.org/show_bug.cgi?id=734093 + +2016-03-09 20:25:08 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: split out jpeg decoder + Split, as a different element, the JPEG decoder. + https://bugzilla.gnome.org/show_bug.cgi?id=734093 + +2016-03-09 18:41:49 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + vaapidecode: register decoder with internal GType + Don't expose the the vaapidecode GType, instead expose a function + which will register element. + This is the first step to split the decoder by codecs. + https://bugzilla.gnome.org/show_bug.cgi?id=734093 + +2016-03-10 12:47:49 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: remove unused function declaration + There is no need to pre-declare gst_vaapidecode_update_sink_caps(). And fixed + code-style of the other pre-declared functions. + +2016-03-09 18:58:13 +0100 Víctor Manuel Jáquez Leal + + * docs/plugins/Makefile.am: + build: git ignore gtkdoc generated files + +2016-03-09 18:55:39 +0100 Víctor Manuel Jáquez Leal + + * m4/Makefile.am: + build: handle git ignore in m4 directory + +2016-03-04 20:17:54 -0300 Thiago Santos + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + vaapidecoder_h265: plug leak of h265 parsing info + If something goes wrong while parsing, the info object is + being leaked + https://bugzilla.gnome.org/show_bug.cgi?id=763121 + +2016-03-04 20:17:20 -0300 Thiago Santos + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + vaapidecoder_h264: plug leak of h264 parsing info + If something goes wrong while parsing, the info object is + being leaked + https://bugzilla.gnome.org/show_bug.cgi?id=763121 + +2016-03-09 11:03:28 +0900 Vineeth TM + + * gst/vaapi/gstvaapipluginutil.c: + plugins: fix gstgl and vaapi memory leaks + 1\ Unref gl_display and gl_window as soon they are not needed. + 2\ Remove an unneeded display type check, since is handled by + gst_vaapi_created_display_from_handle() + 3\ Unref vaapi's display if the display cannot be bind to a GL API. + Modified-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=763354 + +2016-03-09 14:13:24 +0900 Vineeth TM + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + vaapidisplay: Fix uninitialized value error for VA attribute + https://bugzilla.gnome.org/show_bug.cgi?id=763362 + +2016-03-08 10:47:56 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapiencode.c: + plugins: proxy information from downstream caps + Propagate to upstream the downstream information, such as fps, par, etc. + This will fix several "getcaps" critical warnings in gst-validate. + https://bugzilla.gnome.org/show_bug.cgi?id=763300 + +2016-03-04 10:51:42 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + decoder: vp9: Assign values for profile and bit_depth from frame header + bit_depth field has added only in VA-API 0.39.0, added version check. + +2016-03-04 09:12:13 +0200 Sebastian Dröge + + * Makefile.am: + build: Dist gstreamer-vaapi.doap and configure.ac/autogen.sh + https://bugzilla.gnome.org/show_bug.cgi?id=763067 + +=== release 1.7.90 === + +2016-03-01 19:23:51 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * configure.ac: + * gstreamer-vaapi.doap: + Release 1.7.90 + +2016-03-01 16:14:47 +0200 Sebastian Dröge + + * configure.ac: + configure: Use AG_GST_SET_PACKAGE_RELEASE_DATETIME_WITH_NANO to set release date + +2016-03-01 11:35:49 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: intersect with filter in getcaps() + In commit 6034734d I forgot to add the caps filter intersection in the + getcaps() vmethod generating a regression when a capsfilter is set in the + pipeline. + This commit adds the caps filter intersection. + +2016-02-29 11:55:27 +0200 Lim Siew Hoon + + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c: + Add memset to initialize value for VAEncSliceParameterBufferJPEG + https://bugzilla.gnome.org/show_bug.cgi?id=762850 + +2016-02-26 12:42:46 +0200 Sebastian Dröge + + * common: + Automatic update of common submodule + From b64f03f to 6f2d209 + +2016-02-24 12:36:33 +0100 Víctor Manuel Jáquez Leal + + * Makefile.am: + * configure.ac: + * m4/Makefile.am: + build: add m4 directory + Instead of rely on the automatic creation of m4 directory by aclocal, we + already control it. Later we could create our own m4 scripts in order to + unclutter configure.ac + https://bugzilla.gnome.org/show_bug.cgi?id=762528 + +2016-02-23 10:55:02 +0200 Scott D Phillips + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + decoder: hevc: Fill dependent slice segment headers while parsing + Copy the data into the dependent slice segment header from the + corresponding independent slice segment header during parsing. + Previously the reference to the "previous" independent header was + held through the parsing phase and then dereferenced during the + decoding phase. This caused all dependent headers to be populated + with the data of the AU's last independent header instead of the + proper corresponding header. + https://bugzilla.gnome.org/show_bug.cgi?id=762352 + Changes since v1: + - Reworded commit message + +2016-02-17 13:43:48 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: use video decoder getcaps() + The usage of getcaps() vmethod is preferred than to handle manually the sink's + caps query. + In order to avoid function declarations, this patch moves the class_init() + method to the end of the file. + +2016-02-17 12:51:45 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: remove deprecated code + Since we are only supporting current GStreamer version, since 1.3 + gst_buffer_pool_config_add_option() checks if the option to add is + already set. There is no need to do it ourselves. + +2016-02-19 19:03:44 -0300 Thiago Santos + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + vaapidecoder_h265: fix parsing of NALU aligned data + Don't assume the whole buffer is a single NAL, instead look for the + next start code in case there are multiple NALs per buffer. + https://bugzilla.gnome.org/show_bug.cgi?id=762328 + +2016-02-19 11:10:25 -0300 Thiago Santos + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + vaapidecoder_h264: fix parsing of NALU aligned data + Don't assume the whole buffer is a single NAL, instead look for the + next start code in case there are multiple NALs per buffer. + https://bugzilla.gnome.org/show_bug.cgi?id=762328 + +2016-02-18 10:13:53 +0900 Vineeth TM + + * gst/vaapi/gstvaapisink.c: + vaapisink: Fix event,pad,structure memory leaks + https://bugzilla.gnome.org/show_bug.cgi?id=762229 + +2016-02-17 15:40:54 +0200 Lim Siew Hoon + + * gst/vaapi/gstvaapipluginbase.c: + Add icamerasrc as dmabuf capable peer element + icamerasrc is another gstreamer plugin using to capture RAW + frames from camera device. It is based on libcamhal library. + There are some properties available to control icamera behavior. + Signed-off-by: Lim Siew Hoon + Tested & Reviewed: Zhu Haiyang + https://bugzilla.gnome.org/show_bug.cgi?id=759481 + Fixme: This is the similar workaround we done for v4l2src. + The workaround will be removed once we fix #755072 + +2016-02-17 17:15:28 +0900 Vineeth TM + + * gst/vaapi/gstvaapipluginbase.c: + vaapipluginbase: Fix structure memory leak + config structure is not being freed in all cases + https://bugzilla.gnome.org/show_bug.cgi?id=762172 + +2016-02-17 17:20:08 +0900 Vineeth TM + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: Fix videocodec state memory leak + When state is not NULL and either width/height of video info is 0, then state leaks + https://bugzilla.gnome.org/show_bug.cgi?id=762173 + +2016-02-16 15:44:48 +0000 Tim-Philipp Müller + + * gst/vaapi/gstvaapisink.c: + vaapisink: post message for application for unhandled keyboard/mouse events + Makes (most) keyboard shortcuts work in gst-play-1.0 when + the video window has focus. + +2016-02-16 08:48:43 +0900 Vineeth TM + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: Fix capsfeature memory leak + https://bugzilla.gnome.org/show_bug.cgi?id=762116 + +2016-02-16 08:15:40 +0900 Vineeth TM + + * gst/vaapi/gstvaapisink.c: + vaapisink: Fix capsfeature memory leak + caps feature allocated is not being freeing in some cases + https://bugzilla.gnome.org/show_bug.cgi?id=762111 + +2016-02-16 15:09:01 +0200 Sebastian Dröge + + * configure.ac: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst/vaapi/gstvaapidecodebin.c: + * gst/vaapi/gstvaapipluginutil.c: + vaapi: Fix various compiler warnings and disable -Wredundant-decls for now + +2016-02-16 14:36:39 +0200 Sebastian Dröge + + * configure.ac: + configure: Fix setting of extra compiler warning flags + +2016-02-15 18:00:49 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapibufferproxy.c: + libs: fix build error + gst_vaapi_buffer_proxy_{acquire_handle,release_handle,finalize,class} + functions are used only when libva's API version is greater than 0.36.0 + This patch guards those functions completely rather than just their + content. The patch is a continuation of commit 38f8fea4 + Original-patch-by: Vineeth TM + https://bugzilla.gnome.org/show_bug.cgi?id=762055 + +2016-02-15 10:01:54 +0900 Vineeth TM + + * tests/simple-encoder.c: + tests: simple-encoder: fix build error + argument mismatch of gsize with 'long unsigned int' + https://bugzilla.gnome.org/show_bug.cgi?id=762055 + +2016-02-04 10:16:00 +0200 Sreerenj Balachandran + + * gst/vaapi/gstvaapisink.c: + vaapisink: Fix wrong caps advertising + The get_caps() should only report the supported formats. + https://bugzilla.gnome.org/show_bug.cgi?id=761147 + +2016-02-05 18:11:29 -0300 Thiago Santos + + * common: + Automatic update of common submodule + From e97c9bb to b64f03f + +2016-02-03 19:07:40 +0100 Víctor Manuel Jáquez Leal + + * docs/plugins/gstreamer-vaapi-plugins-docs.xml.in: + * docs/plugins/gstreamer-vaapi-plugins-sections.txt: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h265.c: + * gst/vaapi/gstvaapiencode_jpeg.c: + * gst/vaapi/gstvaapiencode_mpeg2.c: + * gst/vaapi/gstvaapiencode_vp8.c: + rename encoders to vaapi{codec}enc + Trying to comply with GStreamer's element names, this patch renames the + encoders using the name format vaapi{codec}enc. + In this way, the plugin documentation is linked correctly. + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-02-03 18:42:36 +0100 Víctor Manuel Jáquez Leal + + * configure.ac: + Use new AG_GST_ARG_ENABLE_EXTRA_CHECKS #define + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-02-03 18:02:21 +0100 Víctor Manuel Jáquez Leal + + * configure.ac: + build: remove vp9 parser check + Since the VP9 parser was added in gst-plugins-bad 1.7.1 we can remove safely + the check of the parser, as we did for the others. + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-02-03 17:06:48 +0100 Víctor Manuel Jáquez Leal + + * common: + * configure.ac: + Back to development + Signed-off-by: Víctor Manuel Jáquez Leal + +=== release 1.6.0 === + +2016-02-03 16:53:41 +0100 Víctor Manuel Jáquez Leal + + * configure.ac: + Release 1.6.0 + +2016-02-03 16:45:18 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + libs: fix compiler warnings + After setting the release flags, the compiler warns about a couple + initialized variables. + Also marked a couple of set variables as unused, because they are only + used for assertion. + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-29 20:41:27 +0100 Víctor Manuel Jáquez Leal + + * docs/plugins/gstreamer-vaapi-plugins-docs.xml.in: + * docs/plugins/gstreamer-vaapi-plugins-sections.txt: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecodebin.c: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h265.c: + * gst/vaapi/gstvaapiencode_jpeg.c: + * gst/vaapi/gstvaapiencode_mpeg2.c: + * gst/vaapi/gstvaapiencode_vp8.c: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + docs: update plugin documentation + Update all the documentation of elements of the vaapi plugin. + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-29 15:39:09 +0100 Víctor Manuel Jáquez Leal + + * Makefile.am: + * configure.ac: + * docs/Makefile.am: + * docs/plugins/Makefile.am: + * docs/plugins/gstreamer-vaapi-plugins-docs.xml.in: + * docs/plugins/gstreamer-vaapi-plugins.types: + * docs/reference/Makefile.am: + * docs/reference/plugins/Makefile.am: + * docs/reference/plugins/plugins-sections.txt: + * docs/reference/plugins/plugins.types: + * docs/version.entities.in: + resurrect gtk-doc machinery + Our auto-generated documentation has been a bit neglected. This patch replaces + the 'normal' gtk-doc with the one used in GStreamer, which is adapted for + plugins, elements and libraries. + This patch also re-enables documentation generation. + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-28 19:35:24 +0100 Víctor Manuel Jáquez Leal + + * ChangeLog: + * Makefile.am: + * autogen.sh: + * configure.ac: + use gst-common submodule + This is 'the' big change in gstreamer-vaapi autoconf. Now it uses the official + GStreamer common submodule. + The documentation generation has been disable temporarily since it needs a + major rework, which will be done in the following commit. + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-25 16:06:03 +0100 Víctor Manuel Jáquez Leal + + * .gitmodules: + * common: + add gst-common submodule + Pointing to branch 1.6 + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-28 13:28:30 +0100 Víctor Manuel Jáquez Leal + + * gstreamer-vaapi.doap: + add doap descriptor + DOAP (Description of a Project) is an RDF Schema and XML vocabulary to + describe software projects, in particular free and open source software. + The description is used in GStreamer as in many other open source projects. + This patch adds the doap description of this project. + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-02-03 11:50:13 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_dpb.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + * gst-libs/gst/vaapi/gstvaapidecoder_unit.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiparser_frame.c: + * gst-libs/gst/vaapi/gstvaapipixmap.c: + * gst-libs/gst/vaapi/gstvaapipixmap_x11.c: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + libs: humongous code style fix + As part of the upstreaming process of gstreamer-vaapi into the GStreamer + umbrella, we need to comply with the project's code style. This meant to + change a lot of code. + It was decided to use a single massive patch to update the code style. + I would like to apologize with the original developers of this code because of + the history breakage. + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-02-03 11:04:15 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + * gst-libs/gst/vaapi/gstvaapidisplay_egl.c: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst/vaapi/gstvaapivideomemory.c: + libs: small refactors to enhance the code style + As gst-indent generated ugly code in these cases, this patch changes the used + idiomatic into other one. + No functional changes were introduced. + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-02-02 17:59:57 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapicodec_objects.c: + * gst-libs/gst/vaapi/gstvaapicodedbufferpool.c: + * gst-libs/gst/vaapi/gstvaapicodedbufferproxy.c: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_objects.c: + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapiimagepool.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + * gst-libs/gst/vaapi/gstvaapiutils_egl.c: + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + * gst-libs/gst/vaapi/gstvaapiutils_x11.c: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow_egl.c: + libs: small code style fixes + This a set of small code style fixes detected as-is by gst-indent. + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-02-02 17:50:19 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapicodedbufferpool.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapiimagepool.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + * gst-libs/gst/vaapi/gstvaapitexture_egl.c: + * gst-libs/gst/vaapi/gstvaapitexture_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_drm.c: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + libs: trivial comment style fixes + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-02-02 17:31:02 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapicodedbuffer.c: + * gst-libs/gst/vaapi/gstvaapiwindow_egl.c: + libs: avoid gst-indent mess up + Guard pieces of code to avoid gst-ident to mess up the following code. + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-02-03 12:17:59 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecodebin.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapivideomemory.c: + plugins: fix code style + Minor code style changes by executing gst-indent in gst/vaapi directory. + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-02-01 13:22:10 +0000 Tim-Philipp Müller + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + Fix some more compiler warning + Two (false) compiler warnings about variables potentially + being used uninitialized, and one about a variable being + set but not used. + https://bugzilla.gnome.org/show_bug.cgi?id=759192 + +2016-02-01 13:02:13 +0000 Tim-Philipp Müller + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipostproc.c: + * tests/simple-encoder.c: + * tests/test-filter.c: + vaapi: fix 'ISO C90 forbids mixed declarations and code' compiler warnings + Declare variables at the beginning of a code block, which + is how it's done in GStreamer. + https://bugzilla.gnome.org/show_bug.cgi?id=759192 + +2016-01-28 14:21:04 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + decoder: vp9: Fix crop rectangle setting + Align with software vp9dec behaviour: Add crop rectangle + only if display_width/display_height is less than the + frame_hdr->width/frame_hdr->height + +2016-01-27 08:56:45 +0200 Sreerenj Balachandran + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: Fix renegotiation for resolution change + Always renegotiate the pool if the immediate frame which going + to be pushed has a different un-cropped resolution than the already + configured one. + +2016-01-29 15:51:49 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.h: + plugins: use the same pre-processor macro + In gstvaapipluginbase.c we are using the macro USE_GST_GL_HELPERS to guard the + code related with GstGL. Nonetheless, in gstvaapipluginbase.h we are using + HAVE_GST_GL_GL_H macro in order to include the GstGLContext's header. + We should use only one to be homogeneous. This patch sets USE_GST_GL_HELPERS + in the header file. + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-29 18:06:29 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + decoder: update a deprecated function + Somehow this didn't show up earlier, but gst_adapter_prev_timestamp() got + deprecated since GStreamer 1.0. + This patch replace it with gst_adapter_prev_pts() + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-29 13:13:56 +0100 Víctor Manuel Jáquez Leal + + * configure.ac: + build: honor configure's cache + The user might enable --config-cache when calling configure script. If so, our + configuration variables will not be correctly calculated. + This patch extracts the value of our variables either from the cache or from + the operation result. + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-28 19:12:13 +0100 Víctor Manuel Jáquez Leal + + * configure.ac: + build: use common version variables + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-28 19:01:43 +0100 Víctor Manuel Jáquez Leal + + * configure.ac: + build: hard-code an unneeded macro + That macro is required for EGL's dynamic module loading, but since + gstreamer-vaapi doesn't creates dynamic modules, it is not required anymore. + That code in gst-libs/gst/vaapi/gstvaapidisplay_egl.c should be removed. + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-28 17:14:51 +0100 Víctor Manuel Jáquez Leal + + * configure.ac: + build: refactorization of dependency tracking + This patch tries to avoid branching in configure.ac using a more functional + approach in macros usage. + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-29 12:34:30 +0100 Víctor Manuel Jáquez Leal + + * configure.ac: + build: check for OpenGL either GLX or EGL are requested + Refactor some code in configure.ac to centralize $enable_opengl definition. + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-28 16:55:44 +0100 Víctor Manuel Jáquez Leal + + * configure.ac: + build: indent and add square braces + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-28 16:50:39 +0100 Víctor Manuel Jáquez Leal + + * configure.ac: + build: upgrade autotools version dependency + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-29 11:14:34 +0100 Víctor Manuel Jáquez Leal + + * configure.ac: + build: enhance string comparisons + Add a 'x' as a prefix in string comparisons to watch out for edge cases where + the string is empty or undefined. + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-28 14:29:16 +0100 Víctor Manuel Jáquez Leal + + * configure.ac: + build: remove unused variables + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-27 19:00:51 +0100 Víctor Manuel Jáquez Leal + + * configure.ac: + build: remove check for old version of gstreamer + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-27 17:55:02 +0100 Víctor Manuel Jáquez Leal + + * configure.ac: + build: remove GStreamer's parsers checks + This patch removes almost all the parsers check since they are already in place, + with the exception of the VP9 parser, since it was merged in Gstreamer 1.7. + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-29 12:11:17 +0100 Víctor Manuel Jáquez Leal + + * configure.ac: + * gst/vaapi/Makefile.am: + build: add gstreamer-pbutils dependency + This dependency was added in gstvaapidecodebin with the call + gst_missing_element_message_new(). + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-27 17:53:59 +0100 Víctor Manuel Jáquez Leal + + * configure.ac: + build: fix variable declaration + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-27 17:47:32 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/Makefile.am: + build: fix when HEVC decoder is disabled + This a very pathological situation: when we have a HEVC encoder but not a HEVC + decoder. + The encoder needs functions that are only available when the decoder is + enabled. + This patch moves the utils functions into the generic sources, such as the + rest of the utils. + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-27 17:20:31 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/Makefile.am: + build: remove unused EGL specific sources + These Makefile variables are not used at all. + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-27 17:19:32 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/Makefile.am: + build: remove check for GStreamer 1.2 + Since we are working for current stable GStreamer 1.6 + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-26 11:49:40 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiparse.h: + Remove more video parser crufts + This header is not used anymore since it declares parsers that are + already in GStreamer 1.6 + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-25 12:43:15 +0000 Tim-Philipp Müller + + * configure.ac: + * docs/reference/Makefile.am: + * docs/reference/libs/Makefile.am: + * docs/reference/libs/libs-docs.xml.in: + * docs/reference/libs/libs-overrides.txt: + * docs/reference/libs/libs-sections.txt: + docs: remove library documentation which is non-public now + https://bugzilla.gnome.org/show_bug.cgi?id=759192 + +2016-01-25 12:40:49 +0000 Tim-Philipp Müller + + * Makefile.am: + * configure.ac: + * debian.upstream/Makefile.am: + * debian.upstream/changelog.in: + * debian.upstream/compat: + * debian.upstream/control.in: + * debian.upstream/copyright: + * debian.upstream/gstreamer-vaapi-doc.install.in: + * debian.upstream/gstreamer-vaapi.install.in: + * debian.upstream/rules: + Remove debian.upstream packaging + https://bugzilla.gnome.org/show_bug.cgi?id=759192 + +2016-01-22 19:27:13 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst/vaapi/gstcompat.h: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapisink.c: + Remove old gst version guards + As gstreamer-vaapi now only supports from GStreamer 1.6, this patch removes + all the old GStreamer version guards. + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-22 19:23:43 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiparse.c: + Remove video parser crufts + We forgot to remove gstvaapiparse.c when we removed all the videoparser + machinery. + Signed-off-by: Víctor Manuel Jáquez Leal + +2015-12-09 19:52:33 +0100 Víctor Manuel Jáquez Leal + + * docs/reference/libs/Makefile.am: + * docs/reference/plugins/Makefile.am: + * gst-libs/gst/vaapi/Makefile.am: + * gst/vaapi/Makefile.am: + * tests/Makefile.am: + libs: remove versioning + Since we don't install libraries anymore, it makes no sense to keep + versioning them according to the gstreamer's version. + Signed-off-by: Víctor Manuel Jáquez Leal + +2015-12-09 16:59:16 +0100 Víctor Manuel Jáquez Leal + + * configure.ac: + * debian.upstream/Makefile.am: + * debian.upstream/control.in: + * debian.upstream/libgstvaapi-dev.install.in: + * debian.upstream/libgstvaapi-drm.install.in: + * debian.upstream/libgstvaapi-glx.install.in: + * debian.upstream/libgstvaapi-wayland.install.in: + * debian.upstream/libgstvaapi-x11.install.in: + * debian.upstream/libgstvaapi.install.in: + * gst-libs/gst/vaapi/Makefile.am: + * tests/Makefile.am: + libs: make libraries no installables + Signed-off-by: Víctor Manuel Jáquez Leal + +2015-12-09 15:37:39 +0100 Víctor Manuel Jáquez Leal + + * debian.upstream/libgstvaapi-dev.install.in: + * gst-libs/gst/vaapi/Makefile.am: + Do not install libgstvaapi headers + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-19 10:40:54 +0200 Sreerenj Balachandran + + * Makefile.am: + * configure.ac: + * patches/Makefile.am: + * patches/videoparsers/0001-plugins-compile-the-built-in-video-parsers-as-vaapip.patch: + * patches/videoparsers/0002-h264parse-fix-build-with-older-GStreamer-1.x-stacks.patch: + * patches/videoparsers/0003-h264parse-default-to-byte-stream-nalu-format-Annex-B.patch: + * patches/videoparsers/0004-h264parse-Disable-3D-video-support-for-GStreamer-1.5.patch: + * patches/videoparsers/0005-videoparsers-h264-Disable-passthorugh-mode-enabling.patch: + * patches/videoparsers/0006-h265parse-include-gstvaapiparse.h.patch: + * patches/videoparsers/0007-h265parse-fix-build-with-GStreamer-1.5.patch: + * patches/videoparsers/Makefile.am: + * patches/videoparsers/series.frag: + Remove videoparser patches + +2015-12-09 15:18:11 +0100 Víctor Manuel Jáquez Leal + + * Makefile.am: + * configure.ac: + * debian.upstream/libgstvaapi-dev.install.in: + * pkgconfig/Makefile.am: + * pkgconfig/gstreamer-vaapi-drm.pc.in: + * pkgconfig/gstreamer-vaapi-glx.pc.in: + * pkgconfig/gstreamer-vaapi-wayland.pc.in: + * pkgconfig/gstreamer-vaapi-x11.pc.in: + * pkgconfig/gstreamer-vaapi.pc.in: + Remove pkg-config files + Signed-off-by: Víctor Manuel Jáquez Leal + +2015-12-09 13:24:30 +0100 Víctor Manuel Jáquez Leal + + * .gitmodules: + * Makefile.am: + * configure.ac: + * ext/Makefile.am: + * ext/codecparsers: + * gst-libs/gst/Makefile.am: + * gst-libs/gst/codecparsers/Makefile.am: + * gst-libs/gst/vaapi/Makefile.am: + * gst/vaapi/Makefile.am: + Remove codecparsers submodule + Signed-off-by: Víctor Manuel Jáquez Leal + +2015-12-08 00:36:36 +0200 Sreerenj Balachandran + + * .gitmodules: + * autogen.sh: + * configure.ac: + * debian.upstream/libgstvaapi.install.in: + * ext/Makefile.am: + * ext/libvpx/Makefile.am: + * ext/libvpx/gstlibvpx.c: + * ext/libvpx/gstlibvpx.h: + * ext/libvpx/libgstcodecparsers_vpx.vers: + * ext/libvpx/sources.frag: + * ext/libvpx/upstream: + * gst-libs/gst/codecparsers/Makefile.am: + * gst-libs/gst/codecparsers/gstvaapilibvpx.c: + Remove libvpx submodule + We will be using upstream codecparsers always. + No more internal libvpx ! + +2015-12-09 14:12:22 +0100 Víctor Manuel Jáquez Leal + + * configure.ac: + build: fix check for GstJpegParser + Right now the local JPEG parser is always compiled because the check for the + upstreamed version is broken: it looks for an non existent symbol: + GstJpegImage. + This patch changes that check for< GstJpegFrameHdr. + Signed-off-by: Víctor Manuel Jáquez Leal + +2015-10-28 09:56:46 +0100 Michael Olbrich + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + wayland: free the frame in frame_release_callback() + This basically reverts 62c3888b76afc69f714a020957e8c5dd9d98f561 (wayland: + decouple wl_buffer from frame). + Otherwise the frame may be overwritten while it is still used by the + compositer: + The frame done callback (frame_done_callback()) is called, when the + compositor is done processing the frame and hands it to the hardware. + The buffer release callback (frame_release_callback()) is called when the + buffer memory is no longer used. + This can be quite some time later: E.g. if weston (with the DRM backend) + puts the buffer on a hardware plane, then then buffer release callback is + called when the kernel is done with the buffer. This is usually when the + next frame is shown, so most likely after the frame done callback for the + next frame! + Since 70eff01d36a2870cbf06ffb91c2a941e8cb6b804 "wayland: sync() when + destroy()" the mentioned possible leak should no longer be a problem, so + reverting this change should cause no leaking buffers. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=758848 + Signed-off-by: Víctor Manuel Jáquez Leal + +2016-01-14 17:36:24 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: check ANY caps at transform_caps() + When transforming downstream caps we should check for ANY caps from peer pad, + otherwise we get a segmentation fault. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=759893 + +2016-01-13 19:17:02 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapisink.c: + vaapisink: ignore frame if its upload failed + When gst_vaapi_plugin_base_get_input_buffer() fail to copy the input buffer + into a VAAPI buffer, the return value is GST_FLOW_NOT_SUPPORTED, and it was + ignored by the vaapisink, leading to a segmentation fault. + This patch ignores the frame that generated the GST_FLOW_NOT_SUPPORTED + returned by gst_vaapi_plugin_base_get_input_buffer(), avoiding the + segmentation fault, but doing and effort to continue rendering. This is + the same behavior of ximagesink. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=759332 + +2015-12-09 18:24:50 +0200 Joel Holdsworth + + * configure.ac: + build: Don't ignore GST_PLUGIN_PATH_1_0 even if the directory doesn't exist yet + https://bugzilla.gnome.org/show_bug.cgi?id=759184 + +2015-12-08 16:14:11 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + * gst-libs/gst/vaapi/gstvaapiutils_h265_priv.h: + Add 10 HEVC 10 bit decoding support + Only supporting vaapidecode ! vaapisink combination for now. + Missing dependencies: + 1: No support for P010 video format in GStreamer + 2: No support for P010 vaGetImage()/vaPutimage() in vaapi-intel-driver + 3: As a result of 1&2 , we have no support for Vaapi Video memory mapping + through GstVideoMeta. + Right now we only set chroma format (YUV420 with more than 8 bits per channel) + for surface pool and keeping GST_VIDEO_FORMAT as ENCODED. The underlying format + of the surfaces is implementation (driver) defined, which is P010. + +2001-01-01 04:59:28 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.h: + gstvaapisurfacepool: Add new API to create surface pool based on chroma type + This new API gst_vaapi_surface_pool_new_with_chroma_type() is for + creating a new GstVaapiVideoPool of GstVaapiSurfaces with the specified + chroam type and dimensions. The underlying format of the surfaces is + implementation (driver) defined. + +2015-12-07 19:06:28 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + Add definitions for YUV420 with more than 8 bits per channel + +2015-12-07 17:26:24 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + gstvaapiporfile: Fix string representation of HEVCMain10 profile + +2015-12-07 16:17:11 +0200 Sreerenj Balachandran + + * configure.ac: + Bump version for development + +=== release 0.7.0 === + +2015-12-07 12:52:10 +0200 Sreerenj Balachandran + + * configure.ac: + 0.7.0 + +2015-12-07 12:49:05 +0200 Sreerenj Balachandran + + * NEWS: + NEWS: Updates + +2015-12-07 12:47:04 +0200 Sreerenj Balachandran + + * AUTHORS: + AUTHORS: Update + +2015-12-07 12:39:23 +0200 Sreerenj Balachandran + + * README: + README: Update + +2015-11-26 10:34:12 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapitexture_glx.c: + texture: detect GL version and use the proper API + When receiving the texture from the application or the video sink, we must + know it size and border. To query the texture the API has changed according to + the OpenGL version used in the GL context of the application/vsink. + This patch checks the current context API type and queries the texture + according to this detected API. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=753099 + +2015-11-26 10:19:32 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapitexture_glx.c: + texture: check for expected target and format + gst_vaapi_texture_glx_new_wrapped() only handles a GL_TEXTURE_2D target and + formats GL_RGBA or GL_BGRA. + This patch adds a debugging verification of those values. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=753099 + +2015-11-26 10:26:10 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + * gst-libs/gst/vaapi/gstvaapiutils_glx.h: + libs: add gl3_bind_texture_2d() + Since OpenGL3.1 removed the fixed pipelines[1] enabling 2D textures is not + needed. In particular, the Intel's Mesa implementation complains if it is + called. + This patch add a new binding function for 2D textures, without enabling + gl3_bind_texture_2d()[2]. + 1. https://www.opengl.org/wiki/Fixed_Function_Pipeline + 2. https://www.opengl.org/wiki/Common_Mistakes#OOP_and_hidden_binding + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=753099 + +2015-11-26 10:14:45 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + * gst-libs/gst/vaapi/gstvaapiutils_glx.h: + libs: add gl_get_current_api() + In order to know which OpenGL API use, we must detect the API type of current + context. This patch adds the function gl_get_current_api() which returns the + OpenGL API type. + This function is an adaptation of gst_gl_context_get_current_gl_api() from + GstGL. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=753099 + +2015-11-27 12:29:11 +0200 Sreerenj Balachandran + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + build: Add gmodule dependency for libgstvaapi_egl + https://bugzilla.gnome.org/show_bug.cgi?id=756259 + +2015-11-27 14:24:55 +0200 Sreerenj Balachandran + + * patches/videoparsers/0005-videoparsers-h264-Disable-passthorugh-mode-enabling.patch: + * patches/videoparsers/0006-h265parse-include-gstvaapiparse.h.patch: + * patches/videoparsers/0007-h265parse-fix-build-with-GStreamer-1.5.patch: + * patches/videoparsers/series.frag: + patches/videoparsers: h264: Disable passthorugh mode enabling + This is a quick fix for regression introduced by the upstream + commit e8908f5aeef952566f6bccde743c7735d3f8c6ef in h264 videoparser. + The patch is disabling the passthrough mode, otherwise it will + break multi-layer mvc stream parsing. + https://bugzilla.gnome.org/show_bug.cgi?id=758656 + +2015-11-25 15:12:53 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/Makefile.am: + * patches/videoparsers/Makefile.am: + * patches/videoparsers/series.frag: + build: add gsth265parse patches conditionally + As gsth265parse was added in GStreamer 1.4, and gstreamer-vaapi still support + GStreamer 1.2, the patching of gsth265parse must be conditional to the target + GStreamer version. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=755525 + +2015-11-25 15:11:28 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/Makefile.am: + build: declare correctly parse lib built files + This is a continuation of commit fc8a0d12 + When declaring BUILT_SOURCES, those files should not be distributed. This + patch avoids the distribution of the generated source code. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=755525 + +2015-11-24 17:14:20 +0200 Sreerenj Balachandran + + * ext/libvpx/sources.frag: + build: libvpx: Add missing source file + +2015-11-23 17:21:23 +0200 Sreerenj Balachandran + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: Correctly detect the caps change + This is a quick fix for regression introuduced by the + commit 757833230bc73b8e3b4e31649e4618ba802bea51 + With out this, the gst_vaapipostproc_create() will + never get invoked. + https://bugzilla.gnome.org/show_bug.cgi?id=758543 + +2015-11-18 20:48:30 +0100 Víctor Manuel Jáquez Leal + + * ext/libvpx/Makefile.am: + * ext/libvpx/sources.frag: + build: libvpx: update the sources lists + `make dist` broke since commit f06798 (libvpx: Update the submodule to + libvpx-1.4.0) because the sources.frag does not contain all the module + sources. + This patch updates thoroughly the sources. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=755525 + +2015-11-16 17:49:01 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: don't set caps change at first set + When the source caps change, the filter is destroyed and recreated. + Nonetheless, this happens every time the vaapipostproc starts, since the caps + change detection algorithm does not take in consideration when the caps are + set by first time. + This patch intents to be an optimization, to avoid a useless filter + destroy-creation cycle when the sources caps are set for first time. + The new helper function video_info_update() is a refactorization to avoid + duplicated code. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=758007 + +2015-11-12 16:13:25 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: params video_info_changed() callers + The signature is video_info_changed(old_vip, new_vip). Nonetheless the callers + swapped the the order. This didn't raise problems since the comparison of both + structures were not affected by its semantics. + But still it would be better to fix this to keep the coherence of the code. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=758007 + +2015-09-24 10:35:44 +0000 Víctor Manuel Jáquez Leal + + * gst/vaapi/Makefile.am: + build: declare real built files + When runnig the `make dist` target from a clean tree, it fails because + if could not find the copied files from codecparsers submodule. + They weren't copied because they weren't declared as built sources. + This patch removes the stamp mechanism and use the actual file list to copy + as the built sources. Also it fixes the duplication of the parser files. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=755525 + +2015-11-17 19:37:07 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + decoder: vp9: Fix last/golden/altref frame index setting + Always fill VADecPictureParameterBufferVP9 last/golden/altref indices + based on what ever reference frame indices encoded in frame header. + +2015-08-25 16:01:51 +0000 Víctor Manuel Jáquez Leal + + * debian.upstream/rules: + debian: remove custom parallel compilation + In order to build a debian package with upstream source, the user should + do + ./autogen.sh + cp -a debian.upstream debian + debuild -eDEB_BUILD_OPTIONS="parallel=8" -us -uc -b + The environment variable DEB_BUILD_OPTIONS="parallel=8" is the canonical + way to make a parallel build (-j8 in this case). + This commit removes the script in debian/rules that detects the number of + cpus, requested by the environment variable DEBIAN_BUILD_NCPUS, which is not + official in debian. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=754087 + +2015-11-16 18:22:55 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + decoder: vp9: Fix PTS calculation of cloned frames + +2015-11-16 18:22:33 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + decoder: vp9: Avoid unnecessary show_frame flag checking while doing picture output + We always set GST_VAAPI_PICTURE_FLAG_SKIPPED for DECODE_ONLY frames and the + gstvaapidecoder base calss is reponsible for handling those frames later on. + No need for explicit verification of frame header's show_frame in order to + do picture outputing. + +2015-11-16 18:22:14 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + decoder: vp9: Fix ref picture update while doing repeat frame + Don't try to do frame decoding and reference picture update + while receiving a vp9 frame having show_existing_frame flag + set as TRUE. + +2015-11-16 18:21:56 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + decoder: vp9: Add repeat-frame display handling + If vp9 frame header come up with show_existing_frame flag set, + we should duplicate the existing decoded frame as current frame to + be displayed. + +2015-11-12 11:07:38 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecodebin.c: + vaapidecodebin: add me as element co-author + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=757957 + +2015-11-12 12:47:01 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecodebin.c: + vaapidecodebin: try to get display from decoder + Rather than create a dummy display, if none has propagated as a context, we + should try to get the one from vaapidecode. + As the bin is already in READY state, the vaapidecode should be also in that + state. That means that the contexts have been negotiated, and it should have + already a display. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=757957 + +2015-11-11 19:04:25 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecodebin.c: + * gst/vaapi/gstvaapidecodebin.h: + vaapidecodebin: add postprocessor dynamically + The former approach to left the bin unfinished has some problems: the context + cannot be shared because the vaapidecode is unlinked in many cases, leading to + creating a VADisplay twice. + Initially the bin is fully functional, constructed as + (-----------------------------------) + | vaapidecodebin | + | (-------------) (-------) | + |<--| vaapidecode |--->| queue |--->| + | (-------------) (-------) | + (-----------------------------------) + When the context is shared and the VADisplay has VPP capabilities, before + changing to READY state, the bin is reconfigured dynamically, adding the + vaapipostproc element afeter the queue: + (--------------------------------------------------------) + | vaapidecodebin | + | (-------------) (-------) (---------------) | + |<--| vaapidecode |--->| queue |--->| vaapipostproc |--->| + | (-------------) (-------) (---------------) | + (--------------------------------------------------------) + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=757957 + +2015-11-11 16:33:24 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecodebin.c: + vaapidecodebin: delay the bin configuration + Delay the bin configuration until changing to READY state. This is because we + should add the vaapipostproc element until the vaapidecode has emitted the + HAVE_CONTEXT message, so de gst_bin_add() could set the context set to + vaapipostproc. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=757957 + +2015-11-13 19:39:56 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + decoder: vp9: Add crop rectangle support. + Set crop rectange if: + There is display_width and display_height which is different from actual width/height + or + The changed resolution is less than the actual configured dimension of surfaces + +2015-11-13 19:23:05 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + decoder: vp9: Fix the context and surface pool reset for multi resolution video + Unlike other decoders, vp9 decoder doesn't need to reset the + whole context and surfaces for each resolution change. Context + reset only needed if resolution of any frame is greater than + what actullay configured. There are streams where a bigger + resolution set in ivf header or webm header but actual resolution + of all frames are less. Also it is possible to have inter-prediction + between these multi resolution frames. + +2015-11-13 18:58:33 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + decoder: vp9: Fill the VADecPictureParameterBufferVP9 width/height from frame header + Always fill width/height of VADecPictureParameterBufferVP9 from frame header. + Preliminary fix for supproting multi resolution video decode. + +2015-11-13 18:51:27 +0200 Sreerenj Balachandran + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: Add comments for corner case fixes and fix couple of indentations. + +2015-11-13 18:41:53 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + decoder: vp9: Set lossless flag from frame header + +2015-11-13 18:40:52 +0200 Sreerenj Balachandran + + * ext/codecparsers: + codecparsers: Update to gst-vaapi-branch d9f25 + d9f2527: codecparsers: vp9: Set lossless flag in frame header + +2015-11-11 19:16:16 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + libs: vp9: remove unused symbols + clang complains about a couple variables and one label which were not + used. This patch removes them. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=757958 + +2015-11-10 19:00:22 +0200 Sreerenj Balachandran + + * ext/codecparsers: + codecparsers: Update to gst-vaapi-branch da251bb + da251bb: codecparsers: vp9: Optimize the memory allocation + f5759f4: codecparsers: vp9: Fix the wrong memcpy of probability arrays + +2015-11-05 12:58:52 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + plugin: guard pointers to pad query functions + Since gstreamer 1.4 is not required to have pad query functions if the query + vmethods are used. + This patch guards out the pad query functions for gstreamer < 1.4 + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=757629 + +2015-11-05 12:39:55 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapiencode.c: + vaapiencode: use pad query vmethods + GstVideoEncoder, the base class of vaapiencode, added support for pad queries + as virtual methods since gstreamer 1.4. This patch enables those vmethods, + while keeps support for previous versions of gstreamer. + This patch is relevant since GstVideoEncoder takes care of other queries that + we are currently ignoring. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=757629 + +2015-10-28 13:01:04 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: return pad's template caps if no display + A caps query can occur before the element has a display. In that case, the + element can return its pad's template. But when the element already has a + display, and the caps probe fails, the element shall return an empty caps, so + the auto-plug could try with another decoder. + If the element has a display and the caps probe works, then the computed caps + should be returned. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=757598 + +2015-10-28 12:59:02 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapisink.c: + plugins: don't create display at caps query + Caps query can happen before the element has a bus. The display creation should + be should occur on the context negotiation, when the bus is already configured. + Then at caps query no display should be created. + Instead of force the display creation, we graciously fail the allowed_caps() + creation. + This change only applies for vaapidecode and vaapisink. The vaapipostroc, as a + basetransform descendant, seems to be not affected by this, nor the encoders. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=757598 + +2015-11-04 21:38:42 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + plugins: fix context query handling + The current context query handling design is flawed: the function + gst_vaapi_reply_to_query() returns FALSE either if the query is not a + GST_CONTEXT_QUERY of if the query could not be handled correctly. But the + pad query function should handle differently each case. + This patch changes the gst_vaapi_reply_to_query() for + gst_vaapi_handle_context_query() and changes it usage in all the vaapi plugins + to match the correct context query handling. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=757598 + +2015-11-04 20:37:05 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + plugin: don't lose previous context at query + When processing the GST_CONTEXT_QUERY we should not lose the previous + context in the query, we should only add our display structure. + This patch copies the old context, if it is there, and stamp our display on + it. Otherwise, a new context is created. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=757598 + +2015-11-04 20:29:03 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideocontext.c: + * gst/vaapi/gstvaapivideocontext.h: + vaapivideocontext: add gst_vaapi_video_context_set_display() + This function set the display to an already created context. This function is + going to be used later. + Also, gst_vaapi_video_context_new_with_display() now uses this function. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=757598 + +2015-10-30 12:27:16 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapivideocontext.c: + * gst/vaapi/gstvaapivideocontext.h: + plugins: check if display is set in sync + Since the context messages are sync'ed, the display assignation happens in the + same thread, hence we can know if the display was found or not as soon we call + for it. + In order to take advantage of it, gst_vaapi_video_context_prepare() receives, + as a new parameter, the address of the plugin's display, and reports back if + the display was found and set. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=757598 + +2015-10-30 12:33:48 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapivideocontext.c: + plugins: set display through context + Instead of setting the display to the plugin directly after its creation, do + it through the gstreamer's context mechanism, avoiding double assignations. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=757598 + +2015-11-02 18:20:07 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideocontext.c: + vaapivideocontext: rename context structure + The context structure is named "display" which is too generic. The contrary + happens, for example, with GstGL, what uses the same name as the context, and + its logs make more sense. + This patch renames the context structure with the same name as the + context, thus GST_PTR_FORMAT can pretty print it. + https://bugzilla.gnome.org/show_bug.cgi?id=757598 + +2015-11-04 19:02:34 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideocontext.c: + vaapivideocontext: refactor gst_vaapi_video_context_prepare() + First, refactorized run_context_query() into _gst_context_run_query(), adding + a new parameter: the pad direction, in order to simplify the code. + Second, added a new helper function: _gst_context_query(), which is a generic + context query function. It isolates the operation of running the query and + sets the context if found, also it enhances the logs. + _gst_context_query() is similar to the one used in GstGL. Perhaps, in the + future this helper function will be merged into the core libraries of + GStreamer. + Finally, gst_vaapi_video_context_prepare() was rewritten to use + _gst_context_query(). + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=757598 + +2015-10-30 11:18:47 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideocontext.c: + vaapivideocontext: refactor context category debug + Refactor the extraction GST_CAT_CONTEXT logging using a only once + initializator, so we could get the debug category from different code + paths, safely. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=757598 + +2015-10-23 11:17:01 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideocontext.c: + gstvaapivideocontext: fix indentation + gst-indent does not handle correctly some expression like function + declaration with attributes, breaking the following expressions. + This patch makes gst-indent to ignore the attributed function + declartion so the followed function definition is not mangled, such + as happened in commit b4154a + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=757598 + +2015-11-02 16:48:27 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugin: chain up set_context() vmethod + Since Gstreamer 1.7, set_context() vmethod needs to be chained up with + the parent class in order to broadcast all its contexts when the element + is added into a bin: + http://cgit.freedesktop.org/gstreamer/gstreamer/commit/?id=d5ded1588920c4471eefe055d09095d9e5e989b5 + There is no need to guard the call, because before GStreamer 1.7, the + set_context() vmethod was NULL in the element class, hence the conditional + call make it safe. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=757598 + +2015-11-06 10:20:34 +0100 Víctor Manuel Jáquez Leal + + * tests/simple-encoder.c: + tests: simple-encoder: remove dead code + The caps creation for codec state configuration is not used. Let's remove it. + Signed-off-by: Víctor Manuel Jáquez Leal + +2015-11-02 19:05:07 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecodebin.c: + vaapidecodebin: fix a leaked display instance + The display returned by gst_vaapi_video_context_get_display() increments the + references. Thus, we have to unref the returned display. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=757595 + +2015-11-04 16:50:44 +0100 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay_glx.h: + * gst-libs/gst/vaapi/gstvaapiutils_glx.h: + libs: remove unneeded headers + Since gstvaapidisplay_glx.h do not expose gl.h/glx.h structures, it is not + required to include them in the header. It is not also required to include + them in gstvaapidisplay_glx.c, since gstvaapiutils_glx.h includes them and + exposes their structures (e.g. GLXPixmap). + Nonetheless, glext.h neither glxext.h are required to include, they are + already included conditionally by gl.h and glx.h, respectively. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=757577 + +2015-11-06 19:18:54 +0200 Sreerenj Balachandran + + * ext/codecparsers: + codecparsers: Update to gst-vaapi-branch 0ea6792 + 0ea6792: codecparsers: vp9: Add header comments + 347ffc7: codecparsers: vp9: Use g_slice_free() for releasing memory allocated from the slice allocator + +2015-11-06 15:19:38 +0200 Sreerenj Balachandran + + * gst/vaapi/gstvaapidecode.c: + VP9: plugins: Add VP9 decoder + +2015-11-06 15:12:51 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vp9.h: + VP9: libgstvaapi: Add VP9 decoder + +2015-11-06 14:57:00 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + VP9: gstvaapiprofile: Add profile definitions + +2015-11-06 14:39:22 +0200 Sreerenj Balachandran + + * configure.ac: + VP9: build: Check availability of vp9 decoder APIs + +2015-11-06 14:24:08 +0200 Sreerenj Balachandran + + * configure.ac: + * ext/Makefile.am: + * gst-libs/gst/codecparsers/Makefile.am: + VP9: Allow building vp9 codecparser internally + +2015-11-06 12:38:46 +0200 Sreerenj Balachandran + + * ext/codecparsers: + codecparsers: Update to gst-vaapi-branch commit ac5dc1a + ac5dc1a: codecparsers: vp9: Add vp9 codec parser + e7d9217: codecparser: h264: initialize parsing structures + 403d400: codecparser: h265: initialize parsing structures + +2015-11-04 15:37:34 +0100 Víctor Manuel Jáquez Leal + + * configure.ac: + configure.ac: don't use an undefined variable + If the environment lacks of gstreamer development packages, this error will + be reported to the user: "gstreamer- was not found" + This is because we are using an undefined variable in the printed message. The + fix simple changes the variable for the hard-coded string "1.0". + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=757283 + +2015-10-16 15:55:40 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: relax guards for memory:VASurface capsfeature + Though caps features are supported since GStreamer 1.2, there are some + issues with the features caps negotiation in that version. Nonetheless, + those issues are fixed in GStreamer 1.4. So, the memoy:VASurface caps + feature negotiation is relaxed for GStreamer 1.4. + The guard is the same as in vaapisink's caps template. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=756686 + +2015-10-15 18:18:36 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: decide allocation doesn't update srccaps + The received caps query will bring the already negotiated caps, so they are + not expected to change. + This patch removes this verification which is dead code path. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=756686 + +2015-10-14 20:30:30 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + vaapidecode: use caps to check the features + Instead of calling gst_vaapi_find_preferred_caps_feature(), which is + expensive, we check the caps from the allocation query, to check the + negotiated feature. + In order to do this verification a new utility function has been implemented: + gst_vaapi_caps_feature_contains(). + As this new function shared its logic with gst_caps_has_vaapi_surface(), both + have been refactorized. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=756686 + +2015-10-14 20:22:43 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: set format before decide allocation + There is a regression from commit 3d8e5e. It was expected the buffer pool + allocation occur before the caps negotiation, but it is not. + This patch fixes this regression: the caps negotiation is done regardless the + allocation query from downstream. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=756686 + +2015-10-16 20:21:50 +0800 Lim Siew Hoon + + * configure.ac: + build: check for patch and fix yasm check + Add configure checking for GNU patch tools and fixed configure + checking YASM to correct sequence. + Signed-off-by: Lim Siew Hoon + https://bugzilla.gnome.org/show_bug.cgi?id=756690 + +2015-10-15 19:20:21 +0300 Sreerenj Balachandran + + * ext/libvpx/Makefile.am: + build: Remove disable-md5 option for libvpx build + The configure option --disable-md5 was provided in libvpx-1.3.0 which + has been removed in 1.4.0. + +2015-10-15 19:00:26 +0300 Sreerenj Balachandran + + * ext/libvpx/upstream: + libvpx: Update the submodule to libvpx-1.4.0 + libvpx git commit: c74bf6d889992c3cabe017ec353ca85c323107cd + +2015-10-15 10:59:08 +0300 Sreerenj Balachandran + + * configure.ac: + configure: mark support for GStreamer 1.2 as obsolete. + Support for GStreamer 1.2 is obsolete. i.e. it is no longer supported. + Our goal is to support the last two stable versions of GStreamer which + are 1.4 and 1.6 at the moment. + We still keep the 1.2 specific codes until the next gstreamer-vaapi-0.7 + release and will get rid of those in 0.8. + +2015-10-12 14:13:03 +0300 Sreerenj Balachandran + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: Fix buffer copy assertion + Don't try to copy the NULL buffer-codec_data. + +2015-09-28 14:57:33 +0200 Víctor Manuel Jáquez Leal + + * configure.ac: + build: allow builds against GStreamer 1.7.x + Signed-off-by: Víctor Manuel Jáquez Leal + +2015-09-23 16:02:46 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstcompat.h: + gstcompat: add gst_buffer_copy_deep() if gst < 1.5 + gst_buffer_copy_deep() was added in GStreamer 1.5. If want to use it we should + add an implementation if gstreamer-vaapi is linked to previous versions. + Signed-off-by: Víctor Manuel Jáquez Leal + +2015-09-23 12:13:41 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: simplify copy of GstVideoCodecState + Signed-off-by: Víctor Manuel Jáquez Leal + +2015-09-14 19:21:08 +0200 Víctor Manuel Jáquez Leal + + * patches/videoparsers/0006-h265parse-fix-build-with-GStreamer-1.5.patch: + * patches/videoparsers/series.frag: + patches/videoparsers: h265parser: more API fences + Add more API fences according with its version and refresh the patch. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=754845 + +2015-09-14 19:19:56 +0200 Víctor Manuel Jáquez Leal + + * patches/videoparsers/0005-h265parse-include-gstvaapiparse.h.patch: + * patches/videoparsers/series.frag: + patches/videoparsers: h265parser: rename patch keeping number + Refresh the patch and rename it in order to keep the patch number. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=754845 + +2015-09-14 19:18:33 +0200 Víctor Manuel Jáquez Leal + + * patches/videoparsers/0002-h264parse-fix-build-with-older-GStreamer-1.x-stacks.patch: + patches/videoparsers: h264parser: more API fences and refresh + Add more API fences according with its version and refresh the patch. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=754845 + +2015-09-14 19:16:51 +0200 Víctor Manuel Jáquez Leal + + * patches/videoparsers/0004-h264parse-Disable-3D-video-support-for-GStreamer-1.5.patch: + * patches/videoparsers/series.frag: + patches/videoparsers: h264parser: fix description and refresh + Fix a typo in the patch description and refresh it in order to avoid the + creation of .orig files and break the distcheck target. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=754845 + +2015-09-14 19:15:18 +0200 Víctor Manuel Jáquez Leal + + * patches/videoparsers/0001-plugins-compile-the-built-in-video-parsers-as-vaapip.patch: + * patches/videoparsers/0003-h264parse-default-to-byte-stream-nalu-format-Annex-B.patch: + patches/videoparsers: h264parser: refresh patches + In order to avoid the creation of .orig files and break the distcheck target. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=754845 + +2015-09-15 16:53:31 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/Makefile.am: + build: link libgstvaapi_parse against codec parser + GST_CODEC_PARSER_* variables are defined if builtin codec parsers are disabled + when running configure. + Right now, libgstcodecparsers links only to libgstvaapi, but libgstvaapi_parse + need it if builtin codec parsers are disabled. + This patch adds GST_CODEC_PARSER_* variables to libgstvaapi_parse + compilation. If builtin codec parsers are enable, this variable is null, so it + should work using libgstvaapi, as normal. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=754845 + +2015-09-11 16:35:30 +0200 Víctor Manuel Jáquez Leal + + * configure.ac: + build: verify for H264 MVC and H265 SPS + Currently the H264 and H265 parsers look for MVC and SPS respectively, and + the required symbols for those were added in GStreamer 1.5 + If we try to compile in GStreamer < 1.4, without enabling the builtin codec + parsers, the compilation fails, because the lack of those symbols. + This patch verifies if the installed H264 and H265 parsers have those symbols. If + they do not, the specific built in codec parsers are enabled and used. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=754845 + +2015-09-11 16:49:16 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: initialize PPS's slice_group_id + When the GstVaapiParserInfoH264 is allocated, the memory is not initialized, + so it contains random data. + When gst_h264_parser_parse_pps() fails, the PPS structure keeps slice_group_id + pointer uninitialized, leading to a segmentation fault when the memory is + freed. + This patch prevents this by initializing the slice_group_id before the PPS + parsing. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=754845 + +2015-09-15 11:01:29 +0300 Mark Nauwelaerts + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: proper numerator and denominator for forced latency framerate + https://bugzilla.gnome.org/show_bug.cgi?id=755040 + +2015-09-11 20:51:42 +0300 Sreerenj Balachandran + + * ext/codecparsers: + codecparsers: Update to gst-vaapi-branch commit f9e284b + dae1a84: h264parse/h265parse: Fix negotiation crash + 45a9f8a: codecparsers: h265 : Fix default scaling list values + 28eaaf5: codecparsers: h265: Fix the selection of Active Ref Pic Set + Signed-off-by: Sreerenj Balachandran + +2015-09-04 22:19:55 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + decoder: hevc: Don't flush dpb for EOS/EOB nal + Explicit flushing of dpb for EOS and EOB nal decoding is wrong, + the dpb_add() itself will handle the flusing(if needed) of dpb + for end of sequence and end of bitstream. + https://bugzilla.gnome.org/show_bug.cgi?id=754010 + +2015-09-04 22:11:10 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + decoder: hevc: Fix the dpb_add() based on C.5.2.3 + Follow the spec as it is in C.5.2.3, add the decoded frame to dpb + just after the PicLatencyCnt setting of existing dpb frames. + https://bugzilla.gnome.org/show_bug.cgi?id=754010 + +2015-09-04 22:02:55 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + decoder: hevc: Fix the picture addition in dpb() based on spec H265 v3 (04/2015) + This fix is based on the V3 vesion of spec which was missing in older versions. + When the current picture has PicOutputFlag equal to 1, for each picture in the + DPB that is marked as "needed for output" and follows the current picture in output order, + the associated variable PicLatencyCount is set equal to PicLatencyCount + 1 (C.5.2.3). + https://bugzilla.gnome.org/show_bug.cgi?id=754010 + +2015-09-04 22:00:36 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + decoder: h265: Fix indentation + +2015-06-13 01:39:31 +1000 Jan Schmidt + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginutil.c: + multiview: initial attempt at stereo/multiview support + Add support for marking caps and buffers for multiview or + stereoscopic output. + https://bugzilla.gnome.org/show_bug.cgi?id=750835 + +2015-08-28 17:12:12 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + decoder: hevc: remove unused functions + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=754250 + +2015-08-31 13:11:54 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: remove (another) unused variable + Signed-off-by: Víctor Manuel Jáquez Leal + +2015-08-28 17:10:40 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: remove unused variable + Thus silence the compilation warnings. + +2015-08-28 16:06:08 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: compilation fix + gst_vaapi_decoder_state_changed() returns void. This patch fixes the + compilation where the toolchain uses restrictive flags as clang. + Signed-off-by: Víctor Manuel Jáquez Leal + +2015-08-29 00:27:05 +0300 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: renegotiate if caps are not equal + The use of gst_caps_is_always_compatible() for this optimization may lead to + false positives. It is better to stick to gst_caps_is_strictly_equal() to know + if it is required a re-negotiation. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=750835 + +2015-08-29 00:18:57 +0300 Sreerenj Balachandran + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + vaapidecode: Rework the re-negotiation code to handle multi resoultion videos + Delaying the pool re-negotiation untill we push all decoded (and queued) + frames downstream. Otherwise for the multi-resolution videos, the + GstVideoVideoMemory will be having wrong resolution and which leads + to nasty behaviours, especially when using software renderers. + sample media file: RAP_B_Bossen_1.bin + case explained: + The first SPS Nal will report resoultion of 448x256 and having crop rectangles to + get the final resoultion 416x240. + Starting from 25 th frame, the resolution will change to 416x240. But parser + elements won't report this since the effective croped resolution is same in + both cases. Here the core libgstvaapi will detect this through it's internal + parsing and do all context/pool destory/reset stuffs. Also it will notify this + change to plugins in advance. But if the plugin try to do re-negotiaion of pool + immediately, this will not sync with the resolution of already decoded and queued + frames and which will lead to failure in gst_video_frame_map() in downstream(if we use the + software renderer). So we have to delay the pool renegotiation in vaapidecode, + untill we push all decoded frames downstream. + https://bugzilla.gnome.org/show_bug.cgi?id=753914 + +2015-08-28 23:43:47 +0300 Sreerenj Balachandran + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: Always keep a copy of input codec state + Currently we are sharing the input GstVideoCodecState with + GstVaapiDecoder(gst-libs/gst/vaapi) by just doing ref and unref for + each caps change. This is troublesome in many cases, for eg: if + resoultion changes with in a singe stream. Because, when ever there + is a resolution change, GstVideoDecoder will first change the Codec_state->caps + fields with new resolution, but since we are using the same codecstate (ref) + in gstvaapidecode.c, the caps check for input caps change will always fail. + https://bugzilla.gnome.org/show_bug.cgi?id=753914 + +2015-08-26 07:25:03 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + decoder: hevc: Fix the scaling list scan order + The default scan order of scaling lists are up-right-diagonal + as per hevc specification. Use the newly implemented + uprightdiagonal_to_raster conversion codecparser APIs to + get the the scaling_list values in raster order, which is + what the VA intel driver requires. + +2015-08-26 07:20:09 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + decoder: hevc: sync with the codecparser changes + The Tile Scanning Conversion process (spec 6-3 and 6-4) is implemented + in codecparsers now. Remove the duplication from gstvaapidecoder_h265 + +2015-08-26 07:04:22 +0300 Sreerenj Balachandran + + * patches/videoparsers/0002-h264parse-fix-build-with-older-GStreamer-1.x-stacks.patch: + patches/Videoparsers: update patch to fix build with older GStreamer 1.2 stacks + +2015-08-26 06:57:36 +0300 Sreerenj Balachandran + + * ext/codecparsers: + codecparsers: Update to gst-vaapi-branch commit 69550f1 + c207c6d: codecparsers: h265: Fix tile row and column parsing + 47074c5: codecparsers: h265: Add APIs for up-right-diagonal/raster scan conversion + cd28b18: codecparsers: h265: Fix the range of delta_chroma_log2_weight_denom + 1746bbe: videoparsers: Use gst_base_parse_merge_tags() + 2f0932b: h264parse: Clear SPS info after processing + f57d6b0: videoparsers: enable accept-template flag + +2015-08-25 15:38:42 +0000 Víctor Manuel Jáquez Leal + + * debian.upstream/control.in: + debian: add yasm as build dependency + As the compilation of libvpx (for vp8 parser) is enabled by default, + yasm is required by default too. + Signed-off-by: Víctor Manuel Jáquez Leal + +2015-08-14 19:21:04 +0800 Lim Siew Hoon + + * debian.upstream/rules: + debian: remove --with-gstreamer-api option + It is no longer valid in gstreamer-vaapi. + Signed-off-by: Lim Siew Hoon + [removed unused GST_API_VERSION variable] + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=753618 + +2015-08-24 19:22:14 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + wayland: rename is_cancelled to sync_failed + Since commit 065a18a3, the semantics of the variable is_cancelled did not make + sense. This commit renames this variable to sync_failed. + +2015-08-13 15:12:44 -0400 Olivier Crete + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + wayland: Don't return GST_FLOW_ERROR on flushing + Setting the sink to flushing causes gst_vaapi_window_wayland_sync() to + return FALSE which makes gst_vaapi_window_wayland_render() return + FALSE which ends up posting an ERROR message in + gst_vaapisink_show_frame_unlocked(). Solution is to just return TRUE + in the EBUSY case. + https://bugzilla.gnome.org/show_bug.cgi?id=753598 + +2015-08-06 12:28:51 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapi.c: + Revert "Marking rank of vaapidecodebin as GST_RANK_MARGINAL for now." + This reverts commit 3ccb198b513dc6ad287fe44117d03bec4d6a966a. + +2015-07-06 20:22:57 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecodebin.c: + vaapidecodebin: check for postproc instance + If the VPP's deinterlace-method is set, first we should check if the postproc + is already instanced to set it. Otherwise we just store it until the VPP is + added into the bin. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=749554 + +2015-08-06 18:48:13 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecodebin.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + vaapidecodebin: ensure VPP before going to READY + There are sometimes that the VA-API display context is not shared among the + pipeline, but it is important to know it before going to READY state (when the + pipeline is already linked). + One instance of this case is this: + gst-launch-1.0 filesrc location=media ! decodebin ! vaapipostproc ! vaapisink + This patch adds a new function in gstvaapipluginutil called + gst_vaapi_create_test_display(). Its purpose is to create a disposable VA-API + display, which only will be used for verify if the VAEntrypointVideoProc is + available by the hardware. Afterwards, it should be unrefed. + If the vaapidecodebin is going to READY state, and the element still doesn't + know if VPP is available, the last resort is to create a new instance of the + VA-API display and test for it. + https://bugzilla.gnome.org/show_bug.cgi?id=749554 + +2015-08-06 12:39:52 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecodebin.c: + vaapidecodebin: post an error message if fails + If the construction of the bin fails, post an error message in the bus. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=749554 + +2015-08-06 12:36:07 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecodebin.c: + * gst/vaapi/gstvaapidecodebin.h: + vaapidecodebin: has_vpp as a tri-state variable + has_vpp can be UNKNOWN while the context message hasn't being received. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=749554 + +2015-08-03 16:33:02 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + gstvaapivideomemory: native format with no derived image + If USE_NATIVE_FORMATS is defined we bail out before configuring the surface + info based on the derived image configuration. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=744042 + +2015-07-23 20:07:59 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/video-format.c: + * gst-libs/gst/vaapi/video-format.h: + * gst/vaapi/gstvaapivideomemory.c: + surface pool config based on video info + First added the function gst_vaapi_video_format_get_best_native(), which + returns the best native format that matches a particular chroma type: + YUV 4:2:0 -> NV12, YUV 4:2:2 -> YUY2, YUV 4:0:0 -> Y800 + RGB32 chroma and encoded format map to NV12 too. + That format is used to configure, initially, the surface's pool for the + allocator. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=744042 + +2015-07-23 16:03:43 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + gstvaapivideomemory: refactor gst_vaapi_video_allocator_new() + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=744042 + +2015-06-19 15:51:07 +0200 Victor Jaquez + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + gstvaapiencoder: validate chroma according to the VA's RT format + Before, only YUV420 color space where supported. With this patch, the + encoder is queried to know the supported formats and admits YUV422 + color space if its available. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=744042 + +2015-08-13 05:07:52 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + decoder: hevc: Add calculation of WpOffsetHalfRangeC + This is necessary for finding ChromaOffsetL0/ChromaOffsetL1 + prediction weight table values with out using any hard coding. + Fixme: We don't have parser API for sps_range_extension, so + assumed zero value for high_precision_offsets_enabled_flag. + Signed-off-by: Sreerenj Balachandran + +2015-08-13 04:09:44 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + decoder: hevc: Fix ChromaOffsetL0/ChromaOffsetL1 calculation + Based on ITU-T rec H265(4/2015): 7-56 + This was a wrong equation in rec H265 (4/2013): 7-44... + Signed-off-by: Sreerenj Balachandran + +2015-08-13 04:08:03 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + decoder: hevc: Fix default value assignment of pred_weight_table + +2015-08-13 03:48:43 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + decoder: hevc: Fix the value assigning for delta_chroma_log2_weight_denom + Assign only if ChromaArrayType != 0.. + Signed-off-by: Sreerenj Balachandran + +2015-08-13 03:06:32 +0300 Sreerenj Balachandran + + * ext/codecparsers: + codecparsers: Update to gst-vaapi-branch commit 1c70432 + 8e98b41: codecparsers: h265: Fix the range of delta_chroma_log2_weight_denom + 839c5bc: codecparsers: h265: Fix the parsing of ref_pic_lists_modification + Signed-off-by: Sreerenj Balachandran + +2015-08-11 08:09:10 +0300 Sreerenj Balachandran + + * ext/codecparsers: + codecparsers: Update to gst-vaapi-branch commit c18b8ad + 8a03e67: videoparsers: h265: Avoid skipping of EOS and EOB nals + a033083: videoparsers: h265: Fix the frame start detection code + Signed-off-by: Sreerenj Balachandran + +2015-08-10 05:50:50 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + decoder: hevc: Add SEI parsing + Signed-off-by: Sreerenj Balachandran + +2015-08-07 08:43:44 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + decoder: hevc: Workaround to recognize wrongly encoded main profile streams + HACK: This is a work-around to identify some main profile streams having wrong profile_idc. + There are some wrongly encoded main profile streams(eg: ENTP_C_LG_3.bin) which doesn't + have any of the profile_idc values mentioned in Annex-A, instead general_profile_idc + has been set as zero and having general_profile_compatibility_flag[general_profile_idc] + is TRUE. Assuming them as MAIN profile for now. + https://bugzilla.gnome.org/show_bug.cgi?id=753226 + Signed-off-by: Sreerenj Balachandran + +2015-08-07 08:41:57 +0300 Sreerenj Balachandran + + * patches/videoparsers/0002-h264parse-fix-build-with-older-GStreamer-1.x-stacks.patch: + patches/videoparsers: Fix the wrong source file path + This is something wrongly typed in commit 6d7b631 + +2015-08-07 08:34:55 +0300 Sreerenj Balachandran + + * ext/codecparsers: + codecparsers: Update to gst-vaapi-branch commit b8d8be4 + ee7e81b: h264parse: Don't discard first AU delimiter + 3690fb9: h264parse: Add more NAL types for debugging output + 108d368: h265parse: Avoid checking for Non Mandatory VPS NAL + ace61048: h265parse: expose compatible profiles to downstream + Signed-off-by: Sreerenj Balachandran + +2015-08-06 13:07:53 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapivideocontext.c: + * gst/vaapi/gstvaapivideocontext.h: + gstvaapivideocontext: remove unused parameter + gst_vaapi_video_context_prepare() received an unused parameter. This patch + removes it and the structure passed by the caller. + This a left over of "Removal of gstreamer-1.0 support" (commit 8b36e25f). + Signed-off-by: Víctor Manuel Jáquez Leal + +2015-08-06 04:01:24 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + decoder: hevc: Fix decoding of stream when it has temporal sublayers + We are calculating the dpb size based on max_dec_pic_buffering. + But if there are more than one temporal sublayers, we are supposed + to use the max_dec_pic_buffering[max_sub_layers_minus] for dpb + size calculation (Assuming HighestTid as max_sub_layers_minus). + Sample streams: TSCL_A_VIDYO_5.bin, TSCL_B_VIDYO_4.bin + https://bugzilla.gnome.org/show_bug.cgi?id=753226 + Signed-off-by: Sreerenj Balachandran + +2015-08-05 14:11:12 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecodebin.c: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h265.c: + * gst/vaapi/gstvaapiencode_jpeg.c: + * gst/vaapi/gstvaapiencode_mpeg2.c: + * gst/vaapi/gstvaapiencode_vp8.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + refactor vaapi caps strings for pad templates + Refactor the main vaapi caps strings into three macros: + GST_VAAPI_MAKE_SURFACE_CAPS, GST_VAAPI_MAKE_ENC_SURFACE_CAPS and + GST_VAAPI_MAKE_GLTEXUPLOAD_CAPS. + Those are in gstvaapipluginutil.h so all the elements could use them, instead + of re-declaring them every time. + No functional changes. + Signed-off-by: Víctor Manuel Jáquez Leal + +2015-08-05 14:15:07 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + gstvaapipostproc: fix code style + Signed-off-by: Víctor Manuel Jáquez Leal + +2015-08-05 05:23:20 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + decoder: hevc: Fix the decoding of dependent slice segment + Decoding process for reference picture list construction needs to be + invoked only for P and B slice and the value for slice_type of dependent slice + segment should be taken from the previous independent slice segment header + of the same pic. + https://bugzilla.gnome.org/show_bug.cgi?id=753226 + Signed-off-by: Sreerenj Balachandran + +2015-06-22 17:38:41 +0200 Victor Jaquez + + * gst/vaapi/gstvaapipluginbase.c: + plugins: reduce the noise of warnings + Those messagse should be attached to the object, also the lack of + caps is not an error, in particular in the case of JPEG encoding. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=744042 + +2015-06-23 17:49:51 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapicontext.c: + gstvaapicontext: fix the JPEG encoder attribs value + When we query for the VAConfigAttribEncJPEG, we get a value which packs the + VAConfigAttribValEncJPEG structure, but we did not assign it. This patch + assigns the returned value to the attribute. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=744042 + +2015-06-18 17:37:46 +0200 Victor Jaquez + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + gstvaapiencoder: framerate 0/1 is valid too + Framerate 0/1 is valid, and it is particularly useful for picture + encoding, such as jpeg. This patch makes the encoder to admit that + framerate. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=744042 + +2015-07-03 09:35:16 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostroc: GLTextureUploadMeta in sink template + Advertise GLTextureUploadMeta in sink caps template. + https://bugzilla.gnome.org/show_bug.cgi?id=752130 + +2015-07-23 13:11:40 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiuploader.c: + * gst/vaapi/gstvaapiuploader.h: + remove gstvaapiuploader + Working on bug #744042 I realized that the gstvaapiuploader is practically not + used. + This patch removes the gstvaapiuploader and add the method + gst_vaapi_plugin_base_get_allowed_raw_caps () that returns the raw caps that + the system can handle, which is used by vaapisink and vaapipostproc. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=752777 + +2015-07-27 18:49:13 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: don't lost GLTextureUpload on seek + When seeking, the decoder is reset, but the buffer pool is not + re-negotiated, but in reset_full() the code forgets if the negotiated buffer + pool has the GLTextureUpload meta. + The decoder knows that GLTextureUpload meta was negotiated in + decide_allocation(), but this method is not called when seeking. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=752929 + +2015-07-21 18:45:56 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + plugins: don't use gst_pad_get_allowed_caps() + gst_pad_get_allowed_caps() query the pad and the peer pad. In the case + decoders, that is OK, but in the case of the postproc might lead loops, + since the gst_base_transform_query_caps() forwards the query upstream + and forth. + Instead of gst_pad_get_allowed_caps() we only query the peer with + gst_pad_peer_query_caps() using the pad's template as filter. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=752558 + +2015-07-22 12:40:19 +0300 Sreerenj Balachandran + + * README: + README: updates + +2015-07-22 09:45:26 +0300 Sreerenj Balachandran + + * patches/videoparsers/0004-h264parse-Disable-3D-video-support-for-GStremaer-1.5.patch: + * patches/videoparsers/series.frag: + patches/videoparsers: h264parse: Disable 3D video support for GStremaer < 1.5 + All API/ABI changes for S3D/MVC are added in 1.5, backporting + them to older verison is not recommended. + Signed-off-by: Sreerenj Balachandran + +2015-07-22 09:41:34 +0300 Sreerenj Balachandran + + * patches/videoparsers/0002-h264parse-fix-build-with-older-GStreamer-1.x-stacks.patch: + patches/Videoparsers: update patch to fix build with older GStreamer 1.2 stacks + +2015-07-22 09:38:42 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + decoder: jpeg: Align with new API/ABI changes in codecparser + Signed-off-by: Sreerenj Balachandran + +2015-07-22 09:31:02 +0300 Sreerenj Balachandran + + * ext/codecparsers: + codecparsers: Update to gst-vaapi-branch commit 800bdb2 + ed13220: mpegvideometa: add meta transform function + 18d5efd: codecparsers: jpeg: add some padding to ScanHdr struct + 7a51722: codecparsers: jpeg: fix docs for table parsing functions + 06b8ded: codecparsers: jpeg: fix validity checking of data parsed + 387a39d: codecparsers: jpeg: fix up API + db9d6a9: codecparsers: jpeg: tweak API a little + bb6951e: codecparsers: jpeg: hide gst_jpeg_scan_for_marker_code() + f33c30c: codecparsers: jpeg: fix and optimize scan for next marker code + 4658c30: codecparsers: jpeg: fix calculation of segment size + 759bcb9: codecparsers: jpeg: fix default Huffman tables generation + b4811ee: codecparsers: jpeg: add JPEG bitstream parser + 9422464: h264parse: fix typo in log message + 9e793a0: h264parse: Move PAR calcs, and use them for stereoscopic half-aspect + 77704ce: nalutils: trivial patch to check if + 8bb9249: codecparsers: mpeg4: actually return full number of bits of resync marker + 7862f95: Revert "codecparsers: remove ignored increment of return" + 54017b1: h264parse: Add support for passing stereoscopic/multiview info + 8667ee4: h264parse: Don't switch to passthrough on set_caps() + Signed-off-by: Sreerenj Balachandran + +2015-06-29 14:27:56 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: track previous reference frames. + Improve closure of gaps in frame_num by strictly following and trying + to fill them with previous reference frames. So, they are now tracked + thus avoiding insertion of dummy ("greenish") frames. + +2015-06-29 13:16:09 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: fix integration of second field into the DPB. + If the new picture to be added to the DPB is not a first field, then + it shall be the second field of the previous picture that was added + before. + This removes the need for dpb_find_picture() now that we track the + immediately preceding decoded picture, in decode order. + +2015-07-06 14:38:26 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: fix closure of "other-field" gap. + When a dummy "other-field" is inserted, it is assumed to inherit the + reference flags from the first field, and the sliding window decoded + reference picture marking process is also executed so that corrupted + frames are moved out as early as possible. + While doing so, we also try to output frames that now contain a single + valid field picture, prior to inserting any other picture into the DPB. + Note: this may be superfluous currently based on the fact that dpb_add() + combines the two most recent pairable fields, but this process would be + further simplified later on. + +2015-06-24 13:58:17 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: track corrupted frames. + Mark the picture as "corrupted" if it is reconstructed from corrupted + references or if those references are fake, e.g. resulting from lost + frames. + This is useful for notifying the upper layer, or downstream elements, + that the decoded frame may contain artefacts. + https://bugzilla.gnome.org/show_bug.cgi?id=703921 + +2015-06-24 13:48:46 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + * gst/vaapi/gstvaapidecode.c: + decoder: add initial infrastructure for marking corrupted output. + Add initial infrastructure in core codec library and vaapidecode to mark + corrupted frames as such. A corrupted frame is such a frame that was + reconstructed from invalid references for instance. + https://bugzilla.gnome.org/show_bug.cgi?id=751434 + Signed-off-by: Gwenole Beauchesne + +2015-07-15 18:18:49 +0300 Sreerenj Balachandran + + * configure.ac: + Bump version for development + +=== release 0.6.0 === + +2015-07-15 15:49:38 +0300 Sreerenj Balachandran + + * configure.ac: + 0.6.0 + +2015-07-15 15:49:19 +0300 Sreerenj Balachandran + + * NEWS: + NEWS: updates + +2015-07-14 19:39:20 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + vaapidecoder: no wmv profiles gstreamer 1.4/1.2 + This patch fix the auto-plugging problem in gstreamer 1.2 and gstreamer 1.4 + Right now there is not a primary ranked parser for vc1 and the demuxers + delivers caps without specifying the profile. This situation is not an issue + for avdec_vc1 but for vaapidecode it is, which refuses to negotiate without a + explicit profile defined in the negotiated caps. + Nonetheless, in gstreamer 1.5 it seems not to be a problem since the + negotiation admits caps subsets try outs. + This patch solves the issue ignoring the profile negotiation in the caps. For + gstreamer < 1.5 the profile string is not handled, so the auto-plugging get + done without the vc1 parser, such as happens in gstreamer 1.5. + Signed-off-by: Víctor Manuel Jáquez Leal + +2015-07-07 20:57:20 +0300 Sreerenj Balachandran + + * gst/vaapi/gstvaapi.c: + Marking rank of vaapidecodebin as GST_RANK_MARGINAL for now. + Unfortunately vaapidecodebin element is not seems to be stable + enough for autoplugging ahead of vaapidecode. + Lowering the rank for now (cosidering the immediate 0.6 release). + See this: https://bugzilla.gnome.org/show_bug.cgi?id=749554 + Signed-off-by: Sreerenj Balachandran + +2015-07-07 13:32:18 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/Makefile.am: + build: Add missing CFLAGS to Makefile.am + +2015-07-03 15:07:02 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapifilter.c: + gstvaapifilter: Only register STE property if it supported by corresponding VA library + Fix the regression introduced in commit eb465fb. + VAProcFilterSkinToneEnhancement is avaialbe from VA >= 0.36. + Signed-off-by: Sreerenj Balachandran + +2015-07-02 17:49:25 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: no format convert on GL tex upload meta + When GL texture upload meta is negotiated, vaapipostproc shall not modify the + color format of the buffer. + https://bugzilla.gnome.org/show_bug.cgi?id=748184 + +2015-07-03 12:42:09 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapifilter.c: + gstvaapifilter: Add guard for VAProcFilterSkinToneEnhancement + VAProcFilterSkinToneEnhancement is avaialbe from VA >= 0.36. + Signed-off-by: Sreerenj Balachandran + +2015-07-02 21:57:38 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + encoder:h265: Fix the check for packed-header support + Use VA_ENC_PACKED_HEADER_* definition for checking. + Signed-off-by: Sreerenj Balachandran + +2015-07-02 21:37:56 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder:h264: Fix the check for packed-header support + Use VA_ENC_PACKED_HEADER_* definition for checking. + Signed-off-by: Sreerenj Balachandran + +2015-07-02 21:00:14 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: submit SEI buffering_period() and picture_timing() messages for CBR mode + One buffering_period() SEI message shall be present in every IDR access unit + when NalHrdBpPresentFlag is inferred to be equal to 1. This is the case when we + use a non-CQP mode, e.g. CBR. In other words, when + nal_hrd_parameters_present_flag is set to 1. + One picture_timing() SEI messages shall be present in every access unit + if CpbDpbDelaysPresentFlag is equal to 1 or pic_struct_present_flag is equal to 1 + https://bugzilla.gnome.org/show_bug.cgi?id=722734 + https://bugzilla.gnome.org/show_bug.cgi?id=751831 + Signed-off-by: Sreerenj Balachandran + +2015-07-01 14:16:50 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecodebin.c: + vaapidecodebin: notify if vpp is disabled + When the system is aware that VPP is not available by the VA driver, + it would be useful to notify to the user that the disable-vpp property + has changed. + https://bugzilla.gnome.org/show_bug.cgi?id=749554 + +2015-07-01 14:17:17 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecodebin.c: + * gst/vaapi/gstvaapidecodebin.h: + vaapidecodebin: enable vpp if it is available + Instead of creating and adding VPP into the bin at setup, we wait until + we are sure the VA driver supports it. We know that when the VA video + context is received by the bin. Afterwards, it is decided to instanciate + and link the VPP or not. + This is more efficient and safer than waiting the VPP to fail and then + disable it. + https://bugzilla.gnome.org/show_bug.cgi?id=749554 + +2015-07-02 12:29:32 +0300 Sreerenj Balachandran + + * tests/test-display.c: + * tests/test-windows.c: + tests: Fix compilation while enabling egl as the only renderer in build + Include missing header files gstvaapidisplay_egl.h and gstvaapiwindow_egl.h. + +2015-07-02 10:45:50 +0300 Sreerenj Balachandran + + * configure.ac: + configure: fix the build while enabling egl as the only renderer + +2015-07-02 10:25:25 +0300 Sreerenj Balachandran + + * configure.ac: + libs: Bump library major version + +2015-06-30 09:44:18 +0300 Sreerenj Balachandran + + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapidecodebin.c: + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode_jpeg.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapivideobufferpool.c: + * gst/vaapi/gstvaapivideocontext.c: + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideometa.c: + gst/vaapi: Switch to upstreram like indentation. + gst-indent for all gst/vaapi/*.c source files + +2015-06-30 09:35:37 +0300 Sreerenj Balachandran + + * gst/vaapi/gstvaapidecodebin.c: + * gst/vaapi/gstvaapidecodebin.h: + vaapidecodebin: Add property to disable VPP + Adding a new propery "disable-vpp", enabling it will prevent + the insertion of vaapipostproc child element. + This is helpful in debugging, specifically to narrow-down the + vaapidecodebin/vaapipostproc related negotiation issues. + No support for run-time disabling for now. + https://bugzilla.gnome.org/show_bug.cgi?id=745901 + +2015-06-29 13:35:59 +0300 Sreerenj Balachandran + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: Fix wrong selection of passthrough mode. + The Current code path is falling back to passthorugh mode if there is no + vpp property set by the user explictily. But we should not use the + passthrough mode if the negotiated src pad caps have a differnt color space + format than sink pad caps (Even though the user didn't set the format property + explicitly). + https://bugzilla.gnome.org/show_bug.cgi?id=748184 + Signed-off-by: Sreerenj Balachandran + +2015-06-29 13:20:28 +0300 Sreerenj Balachandran + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: prevent advanced-deinterlacing of non-native video formats. + This is a workaround to deal with the va-intel-driver for non-native + formats while doing advanced deinterlacing. The format of reference surfaces must + be same as the format used by the driver internally for motion adaptive + deinterlacing and motion compensated deinterlacing. + A permanent solution could be to do the color space conversion internally + for reference surfaces. + https://bugzilla.gnome.org/show_bug.cgi?id=730925 + Signed-off-by: Sreerenj Balachandran + +2015-06-29 13:06:30 +0300 Simon Farnsworth + + * gst/vaapi/gstvaapisink.c: + Work around ABBA deadlock between vaapisink and vaapipostproc + vaapisink takes the display lock, then does a gst_buffer_replace which can + take the lock on the gst_vaapi_video_pool. + vaapipostproc asks the gst_vaapi_video_pool for a new surface. This takes + the lock on the gst_vaapi_video_pool; if you're unlucky, there are no free + surfaces, which means that gst_vaapi_surface_create is + called. gst_vaapi_surface_create takes the display lock. + If vaapisink and vaapipostproc are in different threads, and this happens, + you get a deadlock. vaapisink holds the display lock, and wants the + gst_vaapi_video_pool lock. vaapipostproc holds the gst_vaapi_video_pool lock + and wants the display lock. + Work around this by releasing the display lock in vaapisink around the + gst_buffer_replace. + https://bugzilla.gnome.org/show_bug.cgi?id=738249 + Signed-off-by: Simon Farnsworth + Signed-off-by: Sreerenj Balachandran + +2015-04-29 16:34:07 +0200 Jacobo Aragunde Pérez + + * gst/vaapi/gstvaapidecodebin.c: + * gst/vaapi/gstvaapidecodebin.h: + vaapidecodebin: expose deinterlace-method property from inner vaapipostproc + https://bugzilla.gnome.org/show_bug.cgi?id=745901 + +2015-05-19 11:24:10 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: log negotiated caps + +2015-05-18 14:30:22 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: remove useless debug message + +2015-02-12 12:31:57 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: log negotiated src/sink caps + +2015-05-07 15:57:26 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapisink.c: + vaapisink: error handling if rendering fails + This patch enhance the code path when an error is found when rendering a + buffer. + If the video meta doesn't contain a surface proxy or a surface, a warning + message is printed. + If the rendering backend fails, a error message is posted in the bus. + https://bugzilla.gnome.org/show_bug.cgi?id=749382 + +2015-06-18 14:55:12 +0300 Sreerenj Balachandran + + * gst/vaapi/gstvaapisink.c: + vaapisink: Fix the conditional pad template creation. + +2015-06-18 13:19:26 +0300 Sreerenj Balachandran + + * tests/Makefile.am: + build: Don't build simple-encoder test program if there is no VA Encoding support + This will fix the build error against older VA-APIs <= 0.32 + +2015-06-18 12:20:37 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapibufferproxy.c: + * gst-libs/gst/vaapi/gstvaapicompat.h: + Fix build error for older VA-API versions + Provide guards for VA_SURFACE_ATTRIB_MEM_TYPE_KERNEL_DRM and + VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME which are only availble from + VA >= 0.36. + +2015-06-17 14:20:37 +0300 Sreerenj Balachandran + + * gst/vaapi/gstvaapisink.c: + vaapisink: Fix the capsfeature advertisement in padtemplate + This fixes the regression introduced in 64acc74. + If a pad supports multiple set of capsfeatures, it needs to add + multiple equal structures with different feature sets to the caps. + Because caps structures with the same name but with a non-equal + set of caps features are not compatible. + Without this patch, playbin will autoplug xvimagesink instead of vaapisink. + https://bugzilla.gnome.org/show_bug.cgi?id=750095 + +2015-06-17 12:41:28 +0300 Adrian Cox + + * gst/vaapi/gstvaapisink.c: + vaapisink: Expose the overlay capability for compatibility with dvbsuboverlay. + https://bugzilla.gnome.org/show_bug.cgi?id=750095 + Signed-off-by: Sreerenj Balachandran + Signed-off-by: Gwenole Beauchesne + +2015-06-17 09:53:29 +0300 Olivier Crete + + * gst/vaapi/gstvaapipluginbase.c: + vaapipluginbase: Override downstream allocation reply if no pool + If the downstream replied without a pool, then override it. + https://bugzilla.gnome.org/show_bug.cgi?id=748559 + +2015-06-09 15:15:31 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + vaapipostproc: add color balance interface + https://bugzilla.gnome.org/show_bug.cgi?id=720376 + +2015-05-22 18:13:25 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapifilter.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + vaapipostproc: add skin tone enhancement + Added the 'skin-tone-enhancement' property to vaapostproc. + https://bugzilla.gnome.org/show_bug.cgi?id=744088 + +2015-05-20 18:02:37 +0200 Víctor Manuel Jáquez Leal + + * docs/reference/libs/libs-docs.xml.in: + doc: add VA-API reference in freedesktop + +2015-06-04 19:03:44 +0200 Víctor Manuel Jáquez Leal + + * patches/videoparsers/0001-plugins-compile-the-built-in-video-parsers-as-vaapip.patch: + * patches/videoparsers/0002-h264parse-fix-build-with-older-GStreamer-1.x-stacks.patch: + * patches/videoparsers/0003-h264parse-default-to-byte-stream-nalu-format-Annex-B.patch: + patches/videoparsers: rebase all the h264parse patches + In order to avoid the creation of .orig files and break the distcheck target + +2015-06-04 18:29:15 +0200 Víctor Manuel Jáquez Leal + + * ext/libvpx/Makefile.am: + build: don't build in parallel libvpx + This fixes the distcheck -j XX target. + +2015-06-02 08:52:53 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c: + encoder: jpeg: Fix the packed header generation + This is a work-around to satisfy the va-intel-driver. + Normalize the quality factor and scale QM values (only for packed header + generation) similar to what VA-Intel driver is doing . Otherwise the + generated packed headers will be wrong, since the driver itself is + scaling the QM values using the normalized quality factor. + https://bugzilla.gnome.org/show_bug.cgi?id=748335 + Signed-off-by: Sreerenj Balachandran + +2015-06-02 11:46:00 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: fix uninitialized variables in avcC mode. + Fix uninitialized variables when decoding SPS and PPS NAL units from + "codec-data" buffers. This is particularly important when seeking ops + are involved, and the new persistent states are used more often. + https://bugzilla.gnome.org/show_bug.cgi?id=750094 + +2015-06-01 18:39:18 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: remove unneeded casting + And a code-style fix + +2015-05-21 19:38:33 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: calculate decoding latency + This is a naïve approach to the calculation of the VA-API decoding latency. It + takes into consideration when the frame-rate has some insane value. + https://bugzilla.gnome.org/show_bug.cgi?id=740419 + +2015-05-21 23:16:14 +1000 Jan Schmidt + + * configure.ac: + configure: Compiling against libgstgl requires libgstvideo + Fix detection of the GstGL helper headers in uninstalled + builds. + +2015-05-28 10:52:48 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + encoder: hevc: Fix the size over-flow for encoded buffer. + The approximation of 6 times compression ratio migh not + work in all cases. Especially when enabling I frames. + Provide large enough size for coded-buffer creation. + +2015-05-28 10:43:20 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + encoder: vp8: Fix the size over-flow for encoded buffer. + The approximation of 4 times compression ratio will not + work in all cases. Especially when enabling I frames. + Provide large enough size for coded-buffer creation. + +2015-05-28 05:43:49 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + encoder: hevc: fix bug in multi slice encoding. + This is a work-around for satisfying the VA-Intel driver. + The driver only support slices begin from CTU row start address. + Multi-Slice encoding also requires a fix in va-intel-driver: + http://lists.freedesktop.org/archives/libva/2015-May/003351.html + https://bugzilla.gnome.org/show_bug.cgi?id=749854 + Signed-off-by: Sreerenj Balachandran + +2015-03-12 22:57:22 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: add initial support for loss of pictures. + Implement decoding process for gaps in frame_num (8.5.2). This + also somewhat supports unintentional loss of pictures. + https://bugzilla.gnome.org/show_bug.cgi?id=745048 + https://bugzilla.gnome.org/show_bug.cgi?id=703921 + Original-patch-by: Wind Yuan + [fixed derivation of POC, ensured clone is valid for reference, + actually fixed detection of gaps in FrameNum by PrevRefFrameNum] + Signed-off-by: Gwenole Beauchesne + +2015-05-22 11:42:52 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: add support for missing first field. + Try to identify missing first fields too, thus disregarding any + intermediate gaps in frames. We also assume that we keep the same + field sequence, i.e. if previous frames were in top-field-first + (TFF) order, then so are subsequent frames. + Note that insertion of dummy first fields need to operate in two + steps: (i) create the original first field that the current field + will inherit from, and (ii) submit that field into the DPB prior + to initializing the current (other) field POC values but after any + reference flag was set. i.e. copy reference flags from the child + (other field) to the parent (first field). + https://bugzilla.gnome.org/show_bug.cgi?id=745048 + +2015-05-07 14:00:58 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: add support for missing second field. + Interlaced H.264 video frames always have two fields to decode and + display. However, in some cases, e.g. packet loss, one of the field + can be missing. This perturbs the reference picture marking process, + whereby the number of references available in DPB no longer matches + the expected value. + This patch adds initial support for missing field within a decoded + frame. The current strategy taken is to find out the nearest field, + by POC value, and with the same parity. + https://bugzilla.gnome.org/show_bug.cgi?id=745048 + +2015-05-22 17:06:11 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: improve tracking of "top-field-first" flag. + Try to maintain a "top-field-first" (TFF) flag, even if the H.264 standard + does not mandate it. This will be useful for tracking missing fields, and + also for more correct _split_fields() implementation for frames in the DPB. + +2015-05-05 11:56:11 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: skip all pictures prior the first I-frame. + Don't try to decode pictures until the first I-frame is received within + the currently active sequence. There is no point is decoding and then + displaying frames with artifacts. + +2015-05-12 15:36:10 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: fix processing of EOSEQ NAL. + Fix decoding of end_of_seq() NAL unit so that to not submit the current + picture for decoding again. This is pretty vintage code that dates back + before the existing of the whole decoder units machinery. + One issue that could be arising if that code was kept is that we could + have submitted a picture, and subsequently a GstVideoCodec frame, twice. + Once without the decode_only flag set, and once with that flag set. The + end result is that the GstVideoDecoder would release the codec frame + twice, thus releasing stale data. + In short, the piece of code that is removed by this patch is for once + completely obsolete for a while, and secondly error-prone in corner + cases. + +2013-02-28 15:26:36 +0800 Wind Yuan + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + decoder: add utility function to clone picture objects. + https://bugzilla.gnome.org/show_bug.cgi?id=703921 + Signed-off-by: Wind Yuan + [added cosmetic changes, fixed propagation of "one-field" flag to + children, fixed per-codec clone modes (h264)] + Signed-off-by: Gwenole Beauchesne + +2015-05-27 23:49:18 +0300 Alban Browaeys + + * gst/vaapi/Makefile.am: + build: don't compile HEVC encoder if not supported + Fix: + (gst-plugin-scanner:16681): GStreamer-WARNING **: Failed to load plugin '/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstvaapi.so': /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstvaapi.so: undefined symbol: gst_vaapi_encoder_h265_get_default_properties + https://bugzilla.gnome.org/show_bug.cgi?id=749954 + Signed-off-by: Alban Browaeys + Signed-off-by: Sreerenj Balachandran + +2015-05-27 23:43:16 +0300 Alban Browaeys + + * gst-libs/gst/vaapi/gstvaapicompat.h: + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + HEVC: decode: add missing va_dec_hevc header + Signed-off-by: Alban Browaeys + Signed-off-by: Sreerenj Balachandran + https://bugzilla.gnome.org/show_bug.cgi?id=749953 + +2015-05-26 13:28:32 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: fix PTS cache for GOP start. + If the GOP temporal sequence number (TSN) is interpolated from a valid + PTS, then we need to compensate that PTS corresponding to the start of + GOP with the next picture to be decoded, which shall be an I-frame, + based on its sequence number. + https://bugzilla.gnome.org/show_bug.cgi?id=748676 + +2015-05-27 10:49:56 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: avoid crash when seeking with debug logs + Move down the debug message when the state of the decoder is verified + so the slice header is not NULL. + +2014-12-17 00:41:10 +1100 Jan Schmidt + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: Avoid crashes and warnings on re-opened decoder after a seek + Reset state and add some checks for safe state to avoid a crash and + a warning after the decoder is destroyed/recreated during a seek. + +2015-05-26 10:21:59 +0300 Sreerenj Balachandran + + * patches/videoparsers/0003-h264parse-default-to-byte-stream-nalu-format-Annex-B.patch: + * patches/videoparsers/series.frag: + patches/videoparsers: Rebase the patch on top of gst-vaapi-branch commit 20ee952 + Signed-off-by: Sreerenj Balachandran + +2015-05-26 10:03:20 +0300 Sreerenj Balachandran + + * ext/codecparsers: + codecparsers: Update to gst-vaapi-branch commit 20ee952 + b7dded3: h264parse: don't consider unknown stream-format as avc + 5110ad9: h264parse: fix up handling of input caps corner cases + e51db3e: h264parse: Remove dead code + 3d739d0: codecparser: h265: Fix the number of tile rows/columns parsing + 8482957: h265parse: Fix profile, tier and level setting in caps + 4649acb: h265parse: Fix the memory freeing of stored VPS nals + f2beeb7: h265parse: Fix source caps to report cropped dimensions + 6886a31: h264parse: Fix profile and level setting in caps + 5286c1a: h264parse: Consider SEI NALU as "HEADER" packets + eb97854: videoparsers: h264: bit-exact sync with upstream, minor changes here and there + 53074fc: build: Upgrade GStreamer dependency to 1.0 + Signed-off-by: Sreerenj Balachandran + +2015-05-26 06:01:10 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + HEVC: decode: Replace clip3 implementation with glib CLAMP macro + Signed-off-by: Sreerenj Balachandran + +2015-05-26 05:33:33 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + HEVC: decode: Update Cropping Rectangle + Signed-off-by: Sreerenj Balachandran + +2015-05-25 11:58:20 +0300 Sreerenj Balachandran + + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapiencode_h265.c: + * gst/vaapi/gstvaapiencode_h265.h: + HEVC_Encode: Add HEVC(h265) Encoder plugin + https://bugzilla.gnome.org/show_bug.cgi?id=748874 + Signed-off-by: Sreerenj Balachandran + +2015-05-25 11:38:34 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h265.h: + HEVC_Encode: Add HEVC(h265) encoder to core libgstvaapi + https://bugzilla.gnome.org/show_bug.cgi?id=748874 + Signed-off-by: Sreerenj Balachandran + +2015-05-25 11:26:14 +0300 Sreerenj Balachandran + + * configure.ac: + HEVC_Encode: build: Check availability of VA APIs for H265 encoding. + Signed-off-by: Sreerenj Balachandran + https://bugzilla.gnome.org/show_bug.cgi?id=748874 + +2015-05-25 10:58:52 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + * gst-libs/gst/vaapi/gstvaapiutils_h265.h: + gstvaapiutils_h265: Add H265 Tier specific utility functions + -- New API: gst_vaapi_utils_h265_get_tier_from_string() + -- New API: gst_vaapi_utils_h265_get_tier_string() + https://bugzilla.gnome.org/show_bug.cgi?id=748874 + Signed-off-by: Sreerenj Balachandran + +2015-05-19 10:57:42 +0200 Víctor Manuel Jáquez Leal + + * docs/reference/plugins/Makefile.am: + doc: conditional linking for scanner + Add x11 library only if it is enabled. + https://bugzilla.gnome.org/show_bug.cgi?id=749018 + +2015-05-19 10:37:13 +0200 Víctor Manuel Jáquez Leal + + * docs/reference/plugins/plugins.types: + doc: fix scanner compilation warning + https://bugzilla.gnome.org/show_bug.cgi?id=749018 + +2015-05-06 16:19:23 +0200 Víctor Manuel Jáquez Leal + + * docs/reference/libs/libs-docs.xml.in: + * docs/reference/libs/libs-sections.txt: + doc: update sections and symbols + https://bugzilla.gnome.org/show_bug.cgi?id=749018 + +2015-05-13 10:38:24 +0200 Víctor Manuel Jáquez Leal + + * .gitignore: + * Makefile.am: + * debian.upstream/Makefile.am: + * docs/Makefile.am: + * docs/reference/Makefile.am: + * docs/reference/libs/Makefile.am: + * docs/reference/plugins/Makefile.am: + * ext/Makefile.am: + * ext/libvpx/Makefile.am: + * git.mk: + * gst-libs/Makefile.am: + * gst-libs/gst/Makefile.am: + * gst-libs/gst/base/Makefile.am: + * gst-libs/gst/codecparsers/Makefile.am: + * gst-libs/gst/vaapi/Makefile.am: + * gst/Makefile.am: + * gst/vaapi/Makefile.am: + * patches/Makefile.am: + * patches/videoparsers/Makefile.am: + * pkgconfig/Makefile.am: + * tests/Makefile.am: + build: use git.mk + This patch handles dinamically the gitignore files with git.mk[1]. + Removed the automake variable MAINTAINERCLANFILES in most of the + Makefile.am files since now it is handled by the top one. + 1. https://github.com/behdad/git.mk/blob/master/git.mk + https://bugzilla.gnome.org/show_bug.cgi?id=749321 + +2015-05-07 11:28:15 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + wayland: sync() when destroy() + Before pushing a the new frame, the render() method calls sync() to flush the + pending frames. Nonetheless, the last pushed frame never gets rendered, leading + to a memory leak too. + This patch calls sync() in the destroy() to flush the pending frames before + destroying the window. + Also a is_cancelled flag is added. This flag tells to not flush the event + queue again since the method failed previously or were cancelled by the user. + https://bugzilla.gnome.org/show_bug.cgi?id=749078 + +2015-05-07 15:55:40 +0200 Michael Olbrich + + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + * gst/vaapi/gstvaapisink.c: + vaapisink: implement unlock/unlock_stop for wayland + Otherwise wl_display_dispatch_queue() might prevent the pipeline from + shutting down. This can happen e.g. if the wayland compositor exits while + the pipeline is running. + Changes: + * renamed unlock()/unlock_stop() to unblock()/unblock_cancel() in gstvaapiwindow + * splitted the patch removing wl_display_dispatch_queue() + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=747492 + https://bugzilla.gnome.org/show_bug.cgi?id=749078 + +2015-05-07 12:33:34 +0200 Víctor Manuel Jáquez Leal + + * configure.ac: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + wayland: wl_display_dispatch_queue() can block forever. + wl_display_dispatch_queue() might prevent the pipeline from shutting + down. This can happen e.g. if the wayland compositor exits while the + pipeline is running. + This patch replaces it with these steps: + - With wl_display_prepare_read() all threads announce their intention + to read. + - wl_display_read_events() is thread save. On threads reads, the other + wait for it to finish. + - With wl_display_dispatch_queue_pending() each thread dispatches its + own events. + wl_display_dispatch_queue_pending() was defined since wayland 1.0.2 + Original-patch-by: Michael Olbrich + * stripped out the unlock() unlock_stop() logic + * stripped out the poll handling + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=749078 + https://bugzilla.gnome.org/show_bug.cgi?id=747492 + +2015-05-07 18:30:33 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + wayland: rename frame for last_frame + Since frame in the private data means the last frame sent, it would + semantically better use last_frame. + Also, this patch makes use of g_atomic_pointer_{compare_and_exchange, set}() + functions. + https://bugzilla.gnome.org/show_bug.cgi?id=749078 + +2015-05-07 11:18:12 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + wayland: use a counter as sync flag + Wayland window has a pointer to the last pushed frame and use it to set the + flag for stopping the queue dispatch loop. This may lead to memory leaks, + since we are not keeping track of all the queued frames structures. + This patch removes the last pushed frame pointer and change the binary flag + for an atomic counter, keeping track of number of queued frames and use it for + the queue dispatch loop. + https://bugzilla.gnome.org/show_bug.cgi?id=749078 + +2015-05-07 10:36:17 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + wayland: decouple wl_buffer from frame + This patch takes out the wayland's buffer from the the frame structure. The + buffer is queued to wayland and destroyed in the "release" callback. The + frame is freed in the surface's "done" callback. + In this way a buffer may be leaked but not the whole frame structure. + - surface 'done' callback is used to throttle the rendering operation and to + unallocate the frame, but not the buffer. + - buffer 'release' callback is used to destroy wl_buffer. + Original-patch-by: Zhao Halley + * code rebase + * kept the the event_queue for buffer's proxy + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=749078 + +2015-05-14 16:22:36 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapisink.c: + vaapisink: fix indentation + +2015-05-13 11:54:01 +0200 Víctor Manuel Jáquez Leal + + * debian.upstream/Makefile.am: + * ext/libvpx/Makefile.am: + * gst-libs/gst/vaapi/Makefile.am: + * gst/vaapi/Makefile.am: + * tests/Makefile.am: + build: fix make distcheck + This patch fixes several issues found when running the `make distcheck` + target: + - In commit c561b8da, the update of gstcompat.h in Makefile.am was + forgotten. + - In commit c5756a91 add the simple_encoder_source_h in EXTRA_DIST was + forgotten. + - vpx.build.stamp is not generated at all, only vpx.configure.stamp. + - The make target distcleancheck failed because some autogenerated files + were not handled with the DISTCLEANFILES variable. + Note: `make distcheck -jXX` is not currently supported. + +2015-05-13 13:28:17 +0200 Víctor Manuel Jáquez Leal + + * patches/videoparsers/0001-plugins-compile-the-built-in-video-parsers-as-vaapip.patch: + * patches/videoparsers/0002-h264parse-fix-build-with-older-GStreamer-1.x-stacks.patch: + * patches/videoparsers/0004-h264parse-default-to-byte-stream-nalu-format-Annex-B.patch: + h264parse: update patches with upstream + These patches didn't applied cleanly, breaking the `make distcleancheck` + target. Re-sync'ed the patches against the current git's submodule. + +2015-05-12 16:04:33 +0200 Gwenole Beauchesne + + * tests/simple-encoder.c: + tests: simple-encoder: fix build warnings on 64-bit platforms. + Add a cosmetic change to replace VAAPI buffer with VA buffer and most + importantly fix warnings spitted out during build on 64-bit platforms. + ../../tests/simple-encoder.c:211:5: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘gssize’ [-Wformat=] + g_warning ("Invalid VAAPI buffer size (%d)", size); + ^ + ../../tests/simple-encoder.c:217:5: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘gssize’ [-Wformat=] + g_warning ("Failed to create output buffer of size %d", size); + ^ + +2015-05-08 15:54:09 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapivideocontext.h: + plugins: remove gstreamer-0.10 crumbs + GstVideoContext was used in gstreamer-0.10, which is not supported anymore. + Still, its definition was still in the code. This patch removes it. + https://bugzilla.gnome.org/show_bug.cgi?id=749113 + +2015-05-05 13:08:25 +0200 Víctor Manuel Jáquez Leal + + * tests/Makefile.am: + * tests/simple-encoder.c: + * tests/y4mreader.c: + * tests/y4mreader.h: + tests: add simple-encoder program + This patch adds a simple-encoder test program that uses libgstvaapi for video + encoding to elementary (raw) streams. Input stream is raw YUV in the Y4M + format. That can be from a regular file or standard input when the input + filename is "-". + Usage: simple-encoder [options]* + Options: + --output|-o output file name + --codec|-c codec to use for video encoding + --bitrate|-b desired bitrate (kbps) + By default, and as an initial patch, the encoded stream shall conform to the + minimally supported profile. That is "Constrained Baseline Profile" for H.264 + and "Simple Profile" for MPEG-2. Though, those are the defaults to be + generated by libgstvaapi. + You can find Y4M sample files here http://samples.mplayerhq.hu/yuv4mpeg2/ + Original-patch-by: Changzhi Wei + * general code clean-up + * removed the yuv reader thread + * re-wrote the y4m file parser + * updated used API fixed some wrong usage + * fixed a lot of memory leaks + * added the bitrate setting + * keep fps' numerator and denominator + * simplified the thread control + * removed custom logging and use glib + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=719528 + +2015-05-05 13:02:19 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder.h: + libs: trivial documentation fix + GST_VAAPI_ENCODER_STATUS_NO_SURFACE and GST_VAAPI_ENCODER_STATUS_NO_BUFFER + are not errors, so they do not have the ERROR namespace. + This patch fixes this typo in documentation. + +2015-02-15 15:01:03 +0000 Simon Farnsworth + + * gst-libs/gst/vaapi/gstvaapiwindow_priv.h: + window: Correct prototype to match implementation + On s390x, guintptr and GstVaapiID are not compatible types. The + implementation of gst_vaapi_window_new_internal() and all its callers + seem to assume that its third argument is a GstVaapiID, while the + header gives it guintptr type. + https://bugzilla.gnome.org/show_bug.cgi?id=744559 + +2015-05-04 14:24:43 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecodebin.c: + vaapidecode: add guards for disabled codecs. + Fix link when building plugin elements without HEVC support. e.g. don't + try to call into gst_vaapi_decoder_h265_set_alignment() if there is no + support HEVC enabled in libgstvaapi. + Also, drop disabled codecs from static template caps. Add the missing + HEVC static template caps into vaapidecodebin too. + +2015-04-30 13:29:48 +0200 Víctor Manuel Jáquez Leal + + * configure.ac: + * gst-libs/gst/vaapi/glibcompat.h: + build: upgrade glib dependency to 2.32 + Since bug #745728 was fixed the oldest supported version of GStreamer is + 1.2. That GStreamer release requires glib 2.32, so we can upgrade our + requirement too. + This patch changes the required version of glib in configure.ac and removes + the hacks in glibcompat.h + https://bugzilla.gnome.org/show_bug.cgi?id=748698 + +2015-04-30 13:21:08 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: check if the pool config is already set + In commit 97b768, a regression for GStreamer 1.2 was introduced: + GStreamer 1.2 doesn't check, in gst_buffer_pool_set_config() if the + config option is already set. This patch adds an inline function to + first verify if the option is not in the pool config berfore add it. + +2015-04-29 12:39:50 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: tune up a couple of log messages + In order to reduce the noise, the query type log was downgrade from INFO to + DEBUG, and the shared display address log message is assigned to the object. + +2015-04-29 12:27:43 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: check gst_buffer_pool_set_config() + Check the return value of gst_buffer_pool_set_config(). If it fails an error + message is posted in the bus. + +2015-04-29 12:24:52 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: more specific log message + Be more specific in the log message about the reason of creating a new pool. + +2015-04-29 12:22:29 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: delete unused variable + need_pool is a boolean variable extracted from the allocation query, but it is + not used afterwards. + +2015-04-27 19:21:12 -0400 Olivier Crete + + * gst/vaapi/gstvaapipluginbase.c: + vaapipluginbase: Update the pool if there was no pool in the downstream reply + Fix regression introduced by bd866479, the query after decide_allocation() + always needs a pool in the first slot. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=748559 + +2015-04-27 20:50:19 -0400 Olivier Crete + + * gst/vaapi/gstvaapivideobufferpool.c: + videopool: Free members before chaining up finalize + The finalize function in GObject frees the object memory, so + everything else needs to have been freed before. + https://bugzilla.gnome.org/show_bug.cgi?id=748563 + +2015-04-27 20:31:50 -0400 Olivier Crete + + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + wayland: don't leak the registry proxy + Release the registry proxy when closing the display. + https://bugzilla.gnome.org/show_bug.cgi?id=748564 + +2015-04-21 17:17:06 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + wayland: refactor _sync() method and rename callback + This patch only intends to improve readability: in the method + gst_vaapi_window_wayland_sync() the if/do instructions are squashed into a + single while loop. + Also renames the frame_redraw_callback() callback into frame_done_callback(), + which is a bit more aligned to Wayland API. + +2015-02-03 16:52:06 +0100 Michael Olbrich + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + wayland: free frame in buffer release callback + The Wayland compositor may still use the buffer when the frame done + callback is called. + This patch destroys the frame (which contains the buffer) until the + release callback is called. The draw termination callback only controls + the display queue dispatching. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=747492 + +2015-04-21 10:00:36 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: refactor gst_vaapidecode_internal_flush() + This a cosmetic refactor: gst_vaapidecode_internal_flush() removes its only + label; gst_vaapidecode_finish() is more readable and gst_vaapidecode_purge() + shares the same error message of gst_vaapidecode_internal_flush() when flush + fails. + +2015-04-20 13:27:27 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: refactor gst_vaapidecode_destroy() + Add the method gst_vaapidecode_purge(). This method releases the + flushed frames from the decoder. + This new method add more readablity to gst_vaapidecode_destroy() + +2015-04-16 12:53:18 -0400 Olivier Crete + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst/vaapi/gstvaapidecode.c: + vaapidecode: Tell the base class about released frames on close + The base class needs to be informed about frames that were still queued + in the decoder on release, otherwise they are leaked. + https://bugzilla.gnome.org/show_bug.cgi?id=747999 + +2015-04-19 11:19:03 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: reduce logging noise + When a frame is rejected by downstream, the message is logged twice. This + patch removes one of those logging messages. + Also, the reject of a frame doesn't mean an alarming error. This patch demotes + the log message from error to info. + +2015-04-16 20:18:13 -0400 Olivier Crete + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: Use the GstVideoDecoder error reporting function + This way, the decoder won't stop on the first decoding error, + in most cases it can recover after some glitchiness. + https://bugzilla.gnome.org/show_bug.cgi?id=744620 + +2015-04-17 19:10:35 +0000 Olivier Crete + + * gst/vaapi/gstvaapipluginbase.c: + vaapipluginbase: The allocation query can return without a pool + It is possible to return the min/max/size without actually providing + a pool. This way the source knows how many buffers downstream needs. + https://bugzilla.gnome.org/show_bug.cgi?id=748076 + +2015-04-17 16:45:22 +0300 Sreerenj Balachandran + + * ext/Makefile.am: + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapiparse.c: + * gst/vaapi/gstvaapiparse.h: + * patches/videoparsers/0001-h265parse-include-gstvaapiparse.h.patch: + * patches/videoparsers/series.frag: + plugins: Add h265 videoparser element "vaapiparse_h265" + This is a mirror of h265parse element in upstream gst-plugins-bad. + There could be additional patches but all should go to upstream. + This is for making development faster. + Note: vaapiparse_h265 will get build only for GStreamer version >= 1.4 + +2015-04-17 15:44:04 +0300 Sreerenj Balachandran + + * ext/codecparsers: + codecparsers: Update to gst-vaapi-branch commit 43a0368 + 45f1c28: codecparser: h265: Fix nal unit size checking + f25987b: codecparser: h265: Calculate crop rectangle dimensions + 639573a: codecparser: h265: Fix parsing multiple SEI messages in a single SEI Nal + 4c8ec41: Add h265 videoparser plugin source files + +2015-04-17 10:10:10 +0200 Gwenole Beauchesne + + * autogen.sh: + autogen: drop videoutils submodule. + +2015-04-17 10:36:25 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + decoder: hevc: cosmetics. + Mostly coding style updates. Avoid integer signess inconsistencies. + Optimize dpb_find_lowest_poc() to align with original h264's decoder. + +2015-04-16 14:13:59 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + decoder: hevc: Add Support for tiled video decoding + Based up on the value of uniform_spacing_flag in Picture Parameter Set, + the tile column width and tile row height should be calculated. + Equations: 6-1, 6-2 + Tiled video Descriptions: 7.3.2.3, 7.4.3.3 + +2015-04-16 14:13:21 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + decoder: hevc: Fix decoding when there are RASL pictures present. + -- Set NoRaslOutputFlag based on EOS and EOB Nal units + -- Fix PicOutputFlag setting for RASL picture + -- Fix prev_poc_lsb/prev_poc_msb calculation + -- Drop the RASL frames if NoRaslOutputFlag is TRUE for the associated IRAP picture + -- Fixed couple of crashes and added cosmetics + +2015-04-14 10:54:54 +0100 Martin Sherburn + + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + display: drm: fix race condition setting device type + There is a race condition where g_drm_device_type can be left set to + DRM_DEVICE_RENDERNODES when it shouldn't. + If thread 1 comes in and falls into the last else statement setting up both + RENDERNODES and LEGACY types. And begins to process the first type (RENDERNODES), + it sets g_drm_device_type = RENDERNODES. + Now when thread 2 comes in and sees g_drm_device_type is RENDERNODES, it queues + up that type to be tried but then encounters the lock and has to wait until the + first thread finishes. Once the lock is acquired it will then proceed to ONLY try + RENDERNODES and fail it. But it doesn't try LEGACY. And from then on, all future + attempts will only try RENDERNODES. + So to avoid this situation I have simply moved the acquisition of the lock higher + up in the attached patch. + https://bugzilla.gnome.org/show_bug.cgi?id=747914 + +2015-04-15 15:26:12 -0400 Olivier Crete + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: Don't create filter on caps query + The problem with this is that creating the filter causes the display to + be selected, and the caps query happens while linking the element. So, + if the downstream or upstream element is using a specific display + object, it won't be propagated correctly to the postproc as it already + has a display at this point. + https://bugzilla.gnome.org/show_bug.cgi?id=747945 + +2015-04-15 15:20:17 -0400 Olivier Crete + + * gst-libs/gst/vaapi/gstvaapivideopool.c: + videopool: Release lock while allocating new object + The video pool can be accessed with the display lock held, for example, + when releasing a buffer from inside vaapisink_render, but allocating + a new object can may also take the display lock. Which means a possible + deadlock. + https://bugzilla.gnome.org/show_bug.cgi?id=747944 + +2015-04-15 17:26:43 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapisink.c: + vaapisink: use GstVideoSink vmethod show_frame() + vaapisink inherits from GstVideoSink, in order to use its functionality (such + as ::show-preroll-frame property), we should use its vmethod show_frame(), + rather than call ourselves render() and preroll(). + +2015-04-15 18:16:47 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + vaapisink: add 'handoff' signal + This patch adds the signal ::handoff and the property signal-handoffs. If the + property is set TRUE, the signal ::handoff is emitted just after the buffer is + rendered. + Based on Zhao Halley + https://bugzilla.gnome.org/show_bug.cgi?id=747905 + +2015-04-14 10:17:16 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + HEVC: silence the compiler + Fixed a couple of clang complains. + +2015-02-02 16:42:43 +0100 Michael Olbrich + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + wayland: destroy vpp buffer pool on resize + Otherwise the old buffers with the old size are used. + https://bugzilla.gnome.org/show_bug.cgi?id=747491 + +2015-04-14 10:08:47 +0200 Víctor Manuel Jáquez Leal + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + build: don't compile HEVC if not supported + HEVC decoding was added recently libva-1.5. + This patch avoids HEVC decoding support in libgstvaapi if it is not available + in the installed libva. + https://bugzilla.gnome.org/show_bug.cgi?id=747831 + +2015-04-13 16:04:59 +0300 Sreerenj Balachandran + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: Update Author name in plugin metadata + +2015-04-13 15:43:30 +0300 Sreerenj Balachandran + + * gst/vaapi/gstvaapidecode.c: + plugins: Add HEVC decoder + Signed-off-by: Sreerenj Balachandran + +2015-04-13 15:41:45 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidecoder_h265.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h265.h: + HEVC: Add HEVC(h265) decoder to core libgstvaapi + Signed-off-by: Sreerenj Balachandran + +2015-04-13 14:53:46 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiutils_h265.c: + * gst-libs/gst/vaapi/gstvaapiutils_h265.h: + * gst-libs/gst/vaapi/gstvaapiutils_h265_priv.h: + HEVC: Add codec utility methods to core libgstvaapi + Signed-off-by: Sreerenj Balachandran + +2015-04-13 14:52:53 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + HEVC: gstvaapiprofile: Add profile definitions + Signed-off-by: Sreerenj Balachandran + +2015-04-13 14:52:14 +0300 Sreerenj Balachandran + + * configure.ac: + HEVC: build: Check availability of h265 decoder APIs + Signed-off-by: Sreerenj Balachandran + +2015-04-13 14:51:51 +0300 Sreerenj Balachandran + + * configure.ac: + * ext/Makefile.am: + * gst-libs/gst/codecparsers/Makefile.am: + HEVC: Allow to build h265 codecparser internally + Signed-off-by: Sreerenj Balachandran + +2015-04-08 18:05:20 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapibufferproxy.c: + * gst-libs/gst/vaapi/gstvaapibufferproxy_priv.h: + * gst-libs/gst/vaapi/gstvaapisurface.c: + guard buffer export API if not available + The support for buffer exports in VA-API was added in version 0.36. These + interfaces are for interop with EGL, OpenCL, etc. + GStreamer-VAAPI uses it for a dmabuf memory allocator. Though, gstreamer-vaapi + has to support VA-API versions ranging from 0.30.4, which doesn't support it. + This patch guards all the buffer exports handling (and dmabuf allocator) if + the detected VA-API version is below 0.36. + https://bugzilla.gnome.org/show_bug.cgi?id=746405 + +2015-04-13 11:29:35 +0300 Sreerenj Balachandran + + * ext/codecparsers: + codecparsers: Update to gst-vaapi-branch commit 9bc72b0 + 767bf22: codecparsers: h265: add helpers to convert quantization matrices + 71c8e93: codecparser: h265: skip byte alignment bits while parsing slice header + 3bf0355: codecparsre: h265: Fix the NumDeltaPocs calculation + 10e2087: codecparser: h265: Fix the NumPocTotalCurr calculatio + 2d753b8: codecparser: h265: Fix nal size calculation for EOS and EOB + +2014-12-11 12:02:38 +0100 Michael Olbrich + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: unref video codec frame twice + We get one reference when the frame is passed to decode_handle_frame() + and create another one in gst_vaapi_decoder_push_frame(). + Usually the frame is handled in gst_vaapidecode_push_decoded_frame(). + Here the frame is always released twice: + gst_video_decoder_finish_frame() + gst_video_codec_frame_unref() or + gst_video_decoder_drop_frame() + gst_video_codec_frame_unref(). + In gst_vaapidecode_reset_full() both references to the frame must be + released as well. + Signed-off-by: Víctor Manuel Jáquez Leal + https://bugzilla.gnome.org/show_bug.cgi?id=743226 + +2015-04-08 18:20:34 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay_glx.c: + libs: remove unused variables + clang reports these unused variables. Let's get rid of them. + This patch is a missing part of commit c82e5173 + https://bugzilla.gnome.org/show_bug.cgi?id=747312 + +2015-04-03 20:38:07 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + decoder: mpeg4: remove an spurious comparison + The member size in GstMpeg4Packet is gsize which is unsigned, which cannot be + less than zero. Hence this pre-condition test is a no-op. This patch removes + that code. + https://bugzilla.gnome.org/show_bug.cgi?id=747312 + +2015-04-03 20:33:44 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: casts slice_param->slice_type + slice_type in slice_param is defined as (char *), but it is compared against a + signed integer. clang complains about this comparison. + This patch casts the variable. + https://bugzilla.gnome.org/show_bug.cgi?id=747312 + +2015-04-03 20:31:47 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_objects.h: + encoder: avoid GstVaapiCodedBuffer redefinition + The symbol GstVaapiCodedBuffer is already defined in + gst-libs/gst/vaapi/gstvaapicodedbuffer.h which is loaded, at the end, by + gstvaapiencoder_objects.h. Clang complains about the symbol re-definition. + This patch removes that redefinition. + https://bugzilla.gnome.org/show_bug.cgi?id=747312 + +2015-04-03 20:28:22 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidisplay_egl.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + libs: remove unused variables + clang reports these unused variables. Let's get rid of them. + https://bugzilla.gnome.org/show_bug.cgi?id=747312 + +2015-04-03 20:27:24 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + encoder: mpeg2: use fabsf() instead of abs() + The member value in frame_rate_tab is float, the result of the abs() function + should be float too. But abs() only manages integers. + This patch replaces abs() with fabsf() to handle correctly the possible floats + values. + https://bugzilla.gnome.org/show_bug.cgi?id=747312 + +2015-04-03 20:02:29 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + decoder: cast GST_VAAPI_DECODER_STATUS_DROP_FRAME + Since GST_VAAPI_DECODER_STATUS_DROP_FRAME is not part of the enum + GstVaapiDecoderStatus, we need to cast it to avoid compiler complains. + https://bugzilla.gnome.org/show_bug.cgi?id=747312 + +2015-04-04 00:40:29 +0300 Sreerenj Balachandran + + * README: + Update README + +2015-04-04 00:06:56 +0300 Sreerenj Balachandran + + * .gitmodules: + * README: + Changing source code download links from https://gitorious to https://github + -- gitmodules: Change gstreamer-codecparsers submodule source download link + -- README: Change the gstreamer-vaapi webpage link + +2015-04-03 23:30:24 +0300 Sreerenj Balachandran + + * ext/codecparsers: + codecparsers: update to gst-vaapi-branch commit 1f792e4 + 87f4a7e: bytereader: add gst_byte_reader_peek_sub_reader() and _get_sub_reader() + 7d8ba7a: bytereader: use unchecked inline variant for get_remaining in more places + 2528ea6: bytereader: add gst_byte_reader_masked_scan_uint32_peek + 2b92a67: h264parse: reset the parser information when caps changes + 05eee86: codecparsers: Indent file + e27a38b: codecparsers: Add READ_UE_MAX macro + 2036471: Constify some static arrays everywhere + +2015-04-03 17:45:08 +0300 Sreerenj Balachandran + + * gst/vaapi/gstvaapivideoconverter_glx.c: + * gst/vaapi/gstvaapivideoconverter_x11.c: + Remove the gstvaapivideoconverter_*.c source files missed in commit 51b1e4a + +2015-04-03 17:09:08 +0300 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecodebin.c: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_jpeg.c: + * gst/vaapi/gstvaapiencode_mpeg2.c: + * gst/vaapi/gstvaapiencode_vp8.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapivideobuffer.c: + * gst/vaapi/gstvaapivideobufferpool.c: + * gst/vaapi/gstvaapivideocontext.c: + * gst/vaapi/gstvaapivideocontext.h: + * gst/vaapi/gstvaapivideoconverter_glx.h: + * gst/vaapi/gstvaapivideoconverter_x11.h: + * gst/vaapi/gstvaapivideomemory.h: + * gst/vaapi/gstvaapivideometa_texture.c: + Removal of gstreamer-1.0 support + The support for GStreamer 1.0 has been obsoleted in 0.5.10 release. + GStreamer 1.2 is the a minimal requirement for building the gstreamer-vaapi. + This patch removes all the pre-processor conditional code compilation guarded + for gstreamer-1.0. + Thus, all the video converters were removed too. + https://bugzilla.gnome.org/show_bug.cgi?id=745728 + Signed-off-by: Gwenole Beauchesne + Signed-off-by: Sreerenj Balachandran + +2015-04-03 17:08:30 +0300 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstcompat.h: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/sysdeps.h: + * gst/vaapi/gstcompat.h: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecodebin.c: + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_jpeg.c: + * gst/vaapi/gstvaapiencode_mpeg2.c: + * gst/vaapi/gstvaapiencode_vp8.c: + * gst/vaapi/gstvaapiparse.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiuploader.c: + * gst/vaapi/gstvaapivideobuffer.c: + * gst/vaapi/gstvaapivideobufferpool.c: + * gst/vaapi/gstvaapivideocontext.c: + * gst/vaapi/gstvaapivideoconverter_glx.c: + * gst/vaapi/gstvaapivideoconverter_x11.c: + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideometa.c: + * gst/vaapi/gstvaapivideometa_texture.c: + * tests/codec.c: + update and move gstcompat.h + The purpose of gstcompat.h is to couple the API differences among + gstreamer-1.0 and gstreamer-0.10. Since gstreamer-0.10 is obsolete, the code + in this compatibility layer shall be removed. + Nevertheless, the gstcompat.h header should be kept, if new incompatibilites + appear in the future, but it shall live in gst/vaapi, not in gst-libs. + This patch removes the crumbs defined gstcompat.h and moves it to gst/vaapi. + In order to avoid layer violations, gstcompat.h includes sysdeps.h and all + the includes in gst/vaapi of sysdeps.h are replaced with gstcompat.h + https://bugzilla.gnome.org/show_bug.cgi?id=745728 + Signed-off-by: Gwenole Beauchesne + Signed-off-by: Sreerenj Balachandran + +2015-04-03 17:05:45 +0300 Víctor Manuel Jáquez Leal + + * configure.ac: + * gst/vaapi/Makefile.am: + autotools: remove gstreamer-1.0 support + This patch only removes the support of gstreamer-1.0 in the autotools + scripts. No other files are touched. + In the automake file all the converters were deprecated. + https://bugzilla.gnome.org/show_bug.cgi?id=745728 + Signed-off-by: Gwenole Beauchesne + Signed-off-by: Sreerenj Balachandran + +2015-04-03 17:03:38 +0300 Sreerenj Balachandran + + * .gitmodules: + * ext/Makefile.am: + * ext/videoutils: + Remove the gstreamer-videoutils submodule + +2015-04-03 17:01:45 +0300 Víctor Manuel Jáquez Leal + + * configure.ac: + * gst-libs/gst/Makefile.am: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/video/Makefile.am: + * gst/vaapi/Makefile.am: + * tests/Makefile.am: + Remove libgstvaapi-videoutils.so + This library was intended to add the base classes for video decoders which + where not included in gstreamer-0.10. + Since the support of gstreamer-0.10 is deprecated those classes are not + required, thus the whole library is removed. + https://bugzilla.gnome.org/show_bug.cgi?id=745728 + https://bugzilla.gnome.org/show_bug.cgi?id=732666 + Signed-off-by: Gwenole Beauchesne + +2015-04-03 16:55:43 +0300 Víctor Manuel Jáquez Leal + + * configure.ac: + * gst-libs/gst/vaapi/gstvaapicontext_overlay.c: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * tests/test-subpicture.c: + Remove HAVE_GST_VIDEO_OVERLAY_HWCAPS macro + This macro guarded the use of HAVE_GST_VIDEO_OVERLAY_HWCAPS, which was not + defined before gstreamer 0.10.35. Since the support of gstreamer-0.10 is + deprecated these guards are not required. + https://bugzilla.gnome.org/show_bug.cgi?id=745728 + https://bugzilla.gnome.org/show_bug.cgi?id=732666 + Signed-off-by: Gwenole Beauchesne + +2015-04-03 16:55:27 +0300 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstcompat.h: + * gst-libs/gst/vaapi/gstvaapicontext_overlay.c: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/video-format.c: + * gst-libs/gst/vaapi/video-format.h: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecodebin.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapidownload.h: + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_jpeg.c: + * gst/vaapi/gstvaapiencode_mpeg2.c: + * gst/vaapi/gstvaapiencode_vp8.c: + * gst/vaapi/gstvaapiparse.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiupload.c: + * gst/vaapi/gstvaapiupload.h: + * gst/vaapi/gstvaapiuploader.c: + * gst/vaapi/gstvaapivideobuffer.c: + * gst/vaapi/gstvaapivideoconverter_glx.c: + * gst/vaapi/gstvaapivideoconverter_x11.c: + * gst/vaapi/gstvaapivideometa.c: + * gst/vaapi/gstvaapivideometa.h: + * tests/test-filter.c: + * tests/test-subpicture.c: + Removal of gstreamer-0.10 support + This patch removes all the pre-processor conditional code compilation guarded + for gstreamer-0.10. + https://bugzilla.gnome.org/show_bug.cgi?id=745728 + https://bugzilla.gnome.org/show_bug.cgi?id=732666 + Signed-off-by: Gwenole Beauchesne + +2015-04-03 16:54:54 +0300 Víctor Manuel Jáquez Leal + + * configure.ac: + * debian.upstream/control.in: + * gst-libs/gst/video/Makefile.am: + * gst/vaapi/Makefile.am: + autotools: remove gstreamer-0.10 support + This patch only removes the support of gstreamer-0.10 in the autotools + scripts. No other files are touched. + The configuration parameter --gstreamer-api was deleted since now it is always + auto-detected. + The verification of vmethod query in GstBaseSinkClass was removed since it was + added in gstreamer 0.10.35. The same case for GstVideoOverlayComposition and + its format flags. + The precious variable GST_PLUGIN_PATH was removed, while GST_PLUGIN_PATH_1_0 + remained. + The automake files were changed accordingly. + Removed, in debian/control, the vaapiupload and vaapidownload descriptions. + https://bugzilla.gnome.org/show_bug.cgi?id=732666 + https://bugzilla.gnome.org/show_bug.cgi?id=745728 + Signed-off-by: Gwenole Beauchesne + +2015-03-16 23:38:18 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: add drain() vmethod + In GStremer v1.6 a new vmethod drain() was added in GstVideoDecoder + class. This patch implements this new method. + https://bugzilla.gnome.org/show_bug.cgi?id=742922 + Signed-off-by: Víctor Manuel Jáquez Leal + Signed-off-by: Sreerenj Balachandran + +2015-03-16 23:37:29 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: remove vmethod reset() + Since in bug #745728 the support for GStreamer 1.0 is going to be dropped, + this patch removes the method reset() which was deprecated in GStreamer 1.2. + https://bugzilla.gnome.org/show_bug.cgi?id=742922 + Signed-off-by: Víctor Manuel Jáquez Leal + Signed-off-by: Sreerenj Balachandran + +2015-03-16 23:36:33 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: handle flush() vmethod + Since GStreamer 1.2 the vmethod reset() in GstVideoDecoderClass was deprecated + and flush() was added. + This patch set the vmethod flush() if the installed GStreamer version is 1.2 or + superior. Otherwise, reset() is set. + v2: 1) In order to avoid symbol collision, the old method gst_vaapidecode_flush() + was renamed to gst_vaapidecode_internal_flush(). + 2) The new vmethod flush() always do a hard full reset. + v3: 1) Call gst_vaapidecode_internal_flush() first in flush() vmethod, in order to + gather all collected data with gst_video_decoder_have_frame() + https://bugzilla.gnome.org/show_bug.cgi?id=742922 + Signed-off-by: Víctor Manuel Jáquez Leal + Signed-off-by: Sreerenj Balachandran + +2015-03-16 23:10:53 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: call the correct query function + In commit 2f8c115 (vaapidecode: use the query virtual methods in 1.4) + a bug was introduced: when calling the parent's query function of the + src pad, the one of the sink pad is called instead. This patch fixes + this issue. + https://bugzilla.gnome.org/show_bug.cgi?id=746248 + +2015-03-15 00:36:45 +0200 Sreerenj Balachandran + + * .gitmodules: + gitmodules: Use https:// url instead of git:// for submodules. + Gitorious is failing to clone repositories over git:// url. + +2015-03-14 22:12:19 +0200 Julien Isorce + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + vaapidisplay: mark X11 display as compatible with EGL + GST_GL_WINDOW=x11 GST_GL_API=gles2 GST_GL_PLATFORM=egl + gst-launch-1.0 ... ! vaapidecode ! glimagesink + https://bugzilla.gnome.org/show_bug.cgi?id=745902 + Signed-off-by: Víctor Manuel Jáquez Leal + +2015-03-06 15:20:01 +0200 Olivier Crete + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: Don't crash if a buffer outlives the decoder + Sometimes, for example, when switching video streams but keeping + the same sink, the surface will be released after the decoder is + stopped and replaced. This caused a crash because the release + callback was called on an invalid pointer. + The patch adding an additional reference to the decoder object in the buffer. + https://bugzilla.gnome.org/show_bug.cgi?id=745189 + Signed-off-by: Olivier Crete + Signed-off-by: Sreerenj Balachandran + +2015-03-06 14:31:21 +0200 Sreerenj Balachandran + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: clean-ups (indentation, drop unused variables) + +2015-03-06 14:09:22 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: use the query virtual methods in 1.4 + GstVideoDecoder, the base class of vaapidecode, added support for + pad queries as virtual methods. This patch enables the use of that + support, while keeping support for lower versions of gstreamer. + This patch is important because GstVideoDecoder takes care of other + queries that might be important in the pipeline managing. + v2: 1) rebase to current master + 2) fix indentation with gst-indent + 3) simplify the patch layout + 4) fix the context query + 5) initialise the filter to NULL + 6) improve the query log message for gst-1.2 + https://bugzilla.gnome.org/show_bug.cgi?id=744406 + +2015-03-06 12:16:17 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + vaapipostproc: always activate buffer pool + The vaapipostproc has a proxy flag to know if the the buffer pool is + already active. But this fails in some situations where it is needed + to renegotiate the buffer pool. + This patch removes that flag so the renegotiation is done whenever is + required. + https://bugzilla.gnome.org/show_bug.cgi?id=745535 + +2015-03-02 17:04:20 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + vaapisink: fix minor memory leak in debug mode. + The gst_video_colorimetry_to_string() function returns a newly created + string that represents the GstVideoColorimetry value. So, that needs + to be released after usage, in e.g. GST_DEBUG(). + +2015-03-03 12:37:41 +0200 Sreerenj Balachandran + + * gst/vaapi/gstvaapidecodebin.h: + vaapidecodebin: Avoid usage of "__" prefix in macro names + Avoiding "__" prefix usage in Header File Guards as per + C standard recommendation. + +2015-03-03 12:31:11 +0200 Sreerenj Balachandran + + * gst/vaapi/gstvaapi.c: + plugins: Disable vaapidecodebin for GStreamer < 1.4 + There are autoplugging issues in GStreamer-1.2. + Lets disable vaapidecodebin untill we get some workarounds for this. + +2015-03-02 15:19:40 +0200 Sreerenj Balachandran + + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapidecodebin.c: + * gst/vaapi/gstvaapidecodebin.h: + plugins: Add a vaapidecodebin element + Add a "vaapidecodebin" element to vaapi plugins. + Child Elements: "vaapidecode ! queue ! vaapipostproc" + The Reasons for implementing a new bin element: + -- Help to Autoplug Hardware Accelerated Video Postprocessing element in playbin + with out any dependency to upstream gstreamer. + This is to overcome the *unacceptable* delay in upstream gstreamer to get new + features in. Eg: https://bugzilla.gnome.org/show_bug.cgi?id=687182. + Also customers using older gstreamer versions (1.2 and 1.4) will get the + benefit of autoplugging, hardware accelerated deinterlacing support etc. + -- Help to maintain a single thread implementation in vaapidecode. + This will result a dead-lock free vaapidecode in most of the cases. + More details here: https://bugzilla.gnome.org/show_bug.cgi?id=742605 + https://bugzilla.gnome.org/show_bug.cgi?id=745216 + +2015-03-02 14:59:16 +0200 Sreerenj Balachandran + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: re-indent (gst-indent) gstvaapidecode.c + +2015-03-02 14:46:38 +0200 Simon Farnsworth + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + vaapidecode: Switch back to Single thread implementation + Because the decoder uses the thread from handle_frame() to decode a frame, + the src pad task creates an unsolveable AB-BA deadlock between + handle_frame() waiting for a free surface and decode_loop() pushing + decoded frames out. + Instead, have handle_frame() take responsibility for pushing surfaces, + and remove the deadlock completely. If you need a separate thread + downstream, you can insert a queue between vaapidecode and its downstream + to get one. + Another justification for the single thread implementation is, + there are two many point of locking in gstreamer-vaapi's current + implementation which can lead to deadlocks. + https://bugzilla.gnome.org/show_bug.cgi?id=742605 + Signed-off-by: Simon Farnsworth + Signed-off-by: Víctor Manuel Jáquez Leal + Signed-off-by: Sreerenj Balachandran + +2015-03-02 13:28:41 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginbase.c: + plugins: fix detection of upstream v4l2src element. + Improve check for upstream element that requires DMABUF buffer pool, + e.g. v4l2src element. In particular, make sure to traverse through + any additional capsfilter for instance. + Note: the traversal to the top-most upstream element could be made + more generic, but we are insofar only interested in supporting pipes + similar to v4l2src or v4l2src ! capsfilter, e.g. with an explicit + specification for a desired video camera format, or resolution. + +2015-03-02 11:12:53 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideomemory.c: + plugins: fix allocation of DMABUF memory. + The dmabuf allocator would close the DMABUF handle passed in the init + function gst_dmabuf_allocator_alloc(). So, we need to dup() it so that + to avoid a double close, ultimately in the underlying driver that owns + the DMABUF handle. + +2015-02-26 12:28:02 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: keep src caps and output state in sync + vaapidecode keeps an output state that use the format + GST_VIDEO_FORMAT_ENCODED, while it crafts a different src caps + for a correct negotiation. + I don't see the rational behind this decoupling, it looks like + unnecessary complexity. This patch simplify this logic keeping + in sync the output state and the src caps. + This patch improves the readability of the function + gst_vaapidecode_update_src_caps() and simplify its logic. Also, + the patch validates if the buffer pool has the configuration for + the GL texture upload meta, in order to set the caps feature + meta:GLTextureUpload. Otherwise, the I420 format is set back. + https://bugzilla.gnome.org/show_bug.cgi?id=744618 + Signed-off-by: Víctor Manuel Jáquez Leal + Signed-off-by: Sreerenj Balachandran + +2015-02-26 12:26:54 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: upload meta only if feature and allocation + When vaapidecode finishes the decoding of a frame and pushes it, + if, in the decide_allocation() method, it is determined if the + next element supports the GL texture upload meta feature, the + decoder adds the buffer's meta. + Nonetheless, in the same spirit of the commit 71d3ce4d, the + determination if the next element supports the GL texture upload + meta needs to check both the preferred caps feature *and* if the + allocation query request the API type. + This patch, first removes the unused variable need_pool, and + determines the attribute has_texture_upload_meta using the + preferred caps feature *and* the allocation query. + Also, the feature passed to GstVaapPluginBase is not longer + determined by has_texture_upload_meta, but by the computed + preferred one. + https://bugzilla.gnome.org/show_bug.cgi?id=744618 + Signed-off-by: Víctor Manuel Jáquez Leal + Signed-off-by: Sreerenj Balachandran + +2015-02-26 12:24:55 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + vaapidecode: delayed src caps negotiation + Currently the src caps are set immediately after the sink caps are set, but in + that moment the pipeline might not fully constructed and the video sink has + not negotiated its supported caps and features. As a consequence, in many cases + of playback, the least optimized caps feature is forced. This is partially the + responsible of bug #744039. + Also, vaapidecode doesn't attend the reconfigure events from downstream, + which is a problem too, since the video sink can be changed with different + caps features. + This patch delays the src caps, setting them until the first frame arrives to + the decoder, assuming until that very moment the whole pipeline is already + negotiated. Particularly, it checks if the src pad needs to be reconfigured, + as a consequence of a reconfiguration event from downstream. + A key part of this patch is the new GstVaapiCapsFeature + GST_VAAPI_CAPS_FEATURE_NOT_NEGOTIATED, which is returned when the src pad + doesn't have a peer yet. Also, for a better report of the caps allowed + through the src pad and its peer, this patch uses gst_pad_get_allowed_caps() + instead of gst_pad_peer_query_caps() when looking for the preferred feature. + v3: move the input_state unref to close(), since videodecoder resets at + some events such as navigation. + v4: a) the state_changed() callback replaces the input_state if the media + changed, so this case is also handled. + b) since the parameter ref_state in gst_vaapidecode_update_src_caps() is + always the input_state, the parameter were removed. + c) there were a lot of repeated code handling the input_state, so I + refactored it with the function gst_vaapi_decode_input_state_replace(). + https://bugzilla.gnome.org/show_bug.cgi?id=744618 + Signed-off-by: Víctor Manuel Jáquez Leal + Signed-off-by: Sreerenj Balachandran + +2015-02-24 17:14:33 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + encoder: h264: add support for more than 2 views + Add support for H.264 MVC Multiview High profile encoding with + more than 2 views. All views within the same accesss unit are + provided in increasing order of view order index (VOIdx). + Upto 10 view are supported for now. + A new property "view-ids" has been provided for the plugins to + set the view ids (which is an array of guint values) to be used + for mvc encoding. + https://bugzilla.gnome.org/show_bug.cgi?id=732453 + +2015-02-23 16:55:36 +0100 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginbase.c: + plugins: upload meta only if feature and allocation + Working on bug #743687, I realized that vaapidecode always adds to its buffer + pool the config option GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META if + the decide_allocation()'s query has GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE. + Nevertheless, there are occasions where the query has the API type, but the + last negotiated caps don't have the feature meta:GstVideoGLTextureUploadMeta. + Under this contradiction, vaapidecode adds the GLTextureUploadMeta API to its + buffer pool configuration, and adds its buffer's meta to each output buffer, + even if the negotiated caps feature is memory:SystemMemory with I420 color + format. + This kind of output buffers chokes ClutterAutoVideosSink, since it uses a map + that relates caps <-> GL upload method. If it receives a buffer with color + format I420, it assumes that it doesn't have a texture upload meta, because + only those with RGB color format has it. Our buffers, with I420 format, say + that they have the upload meta too. In that case the mapped method is a dummy + one which does nothing. I reported this issue in bug #744039 (the patch, + obviously, was rejected). + This patch workarounds the problem: the buffer pool's configuration option + GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META is set if and only if the + query has the GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE *and* the negotiated + caps feature is meta:GstVideoGLTextureUploadMeta. + I have tested these patches with gst-master (1.5), gst-1.4 and gst-1.2 and + in all they seem to work correctly. + https://bugzilla.gnome.org/show_bug.cgi?id=744618 + [adapted to fit current EGL changes] + Signed-off-by: Gwenole Beauchesne + +2015-02-20 15:13:03 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapitexture.h: + * gst-libs/gst/vaapi/gstvaapitexture_glx.c: + * gst-libs/gst/vaapi/gstvaapitexture_priv.h: + * gst/vaapi/gstvaapivideometa_texture.c: + plugins: add support for GstVideoGLTextureOrientation. + Add support for GstVideoGLTextureOrientation modes. In particular, + add orientation flags to the GstVaapiTexture wrapper and the GLX + implementations. Default mode is that texture memory is laid out + with top lines first, left row first. Flags indicate whether the + X or Y axis need to be inverted. + +2015-02-09 21:09:07 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapivideometa_texture.c: + plugins: add support for BGRA textures. + Some frameworks (EFL) expect BGRA textures for storage. However, + adding support for that broadly into GStreamer framework implies + two kinds of hacks: (i) libgstgl helpers currently do not support + BGRA textures correctly, (ii) we need to better parse downstream + suggested caps and intersect them with what the VA plugin elements + can offer to them for GL texturing. + +2015-01-23 09:31:57 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginutil.c: + plugins: fix support for Wayland/EGL running alongside X11. + When multiple display servers are available, the glimagesink element + (from GStreamer 1.4) may not be able to derive a global display in + Wayland. Rather, a "window"-specific display is created. In this case, + the GstGLDisplay handle available through GstGLContext is invalid. + So, try to improve heuristics for display server characterisation in + those particular situations. + +2015-02-20 15:29:17 +0100 Gwenole Beauchesne + + * configure.ac: + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapivideobufferpool.c: + * gst/vaapi/gstvaapivideometa_texture.c: + plugins: add initial support for EGL. + Add initial support for EGL through GstVideoGLTextureUploadMeta. + Fix gst_vaapi_ensure_display() to allocate a GstVaapiDisplay off the + downstream supplied GstGLContext configuration, i.e. use its native + display handle to create a GstVaapiDisplay of type X11 or Wayland ; + and use the desired OpenGL API to allocate the GstVaapiDisplayEGL + wrapper. + https://bugzilla.gnome.org/show_bug.cgi?id=741079 + +2014-12-09 11:46:58 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideometa_texture.c: + plugins: track video texture size changes. + Sync video texture sizes to GstVideoGLTextureUploadMeta private date, + i.e. GstVaapiVideoMetaTexture, on a regular basis. In particular, we + now update the texture size from the GstVideoMeta, if any, or reset + to some defaults otherwise. + +2014-12-03 15:45:52 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + * gst/vaapi/gstvaapipluginutil.c: + plugins: ensure VA display matches GL context expectations. + If a GstGLContext is supplied by the downstream element, then make + sure that the VA plugin element gets a compatible display to what + is requested by the GL context. e.g. re-allocate a VA/GLX display + when a GLX context is provided by the downstream element. + +2014-12-03 14:14:30 +0100 Gwenole Beauchesne + + * configure.ac: + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + plugins: record downstream GstGLContext. + Record GL context supplied by downstream elements. This can be useful, + and further needed, to enforce run-time check that the GL context is + compatible for use by libgstvaapi. e.g. check that we don't create a + VA/GLX display for EGL/X11 contexts. + https://bugzilla.gnome.org/show_bug.cgi?id=725643 + Original-path-by: Matthew Waters + +2014-12-01 14:52:39 +0100 Gwenole Beauchesne + + * tests/Makefile.am: + * tests/output.c: + egl: update tests. + Add initial support for EGL to tests. The new EGL backend can be selected + through the --egl command line option. The OpenGL|ES version can further + be selected with the --gles-version command line option, where the default + of 0 means "desktop" OpenGL. + +2015-01-27 16:21:04 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidisplay_egl.c: + * gst-libs/gst/vaapi/gstvaapiutils_egl.c: + * gst-libs/gst/vaapi/gstvaapiutils_egl.h: + * gst-libs/gst/vaapi/gstvaapiwindow_egl.c: + * gst-libs/gst/vaapi/gstvaapiwindow_egl.h: + egl: add windowing support. + This provides for some basic EGL window abstraction. + +2015-01-24 08:29:57 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidisplay_egl.c: + * gst-libs/gst/vaapi/gstvaapitexture_egl.c: + * gst-libs/gst/vaapi/gstvaapitexture_egl.h: + egl: add texture abstraction. + Add GstVaapiTextureEGL abstraction that can create its own GL texture, + or import a foreign allocated one, while still allowing updates from a + VA surface. + +2014-12-09 18:14:56 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapisurface_egl.c: + * gst-libs/gst/vaapi/gstvaapisurface_egl.h: + egl: allow for EGLImage imports into VA Surfaces. + Add helpers to import EGLImage objects into VA surfaces. There are + two operational modes: (i) gst_vaapi_surface_new_from_egl_image(), + which allows for implicit conversion from EGLImage to a VA surface + in native video format, and (ii) gst_vaapi_surface_new_with_egl_image(), + which exactly wraps the source EGLImage, typically in RGBA format + with linear storage. + Note: in case of (i), the EGLImage can be disposed right after the + VA surface creation call, unlike in (ii) where the user shall ensure + that the EGLImage is live until the associated VA surface is no longer + needed. + https://bugzilla.gnome.org/show_bug.cgi?id=743847 + +2015-02-20 15:27:53 +0100 Gwenole Beauchesne + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/egl_compat.h: + * gst-libs/gst/vaapi/egl_vtable.h: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_egl.c: + * gst-libs/gst/vaapi/gstvaapidisplay_egl.h: + * gst-libs/gst/vaapi/gstvaapidisplay_egl_priv.h: + * gst-libs/gst/vaapi/gstvaapiutils_egl.c: + * gst-libs/gst/vaapi/gstvaapiutils_egl.h: + * gst-libs/gst/vaapi/ogl_compat.h: + Add initial support for EGL. + Add initial support for EGL to libgstvaapi core library. The target + display server and the desired OpenGL API can be programmatically + selected at run-time. + A comprehensive set of EGL utilities are provided to support those + dynamic selection needs, but also most importantly to ensure that + the GL command stream is executed from within a single thread. + https://bugzilla.gnome.org/show_bug.cgi?id=743846 + +2015-01-30 21:38:07 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapivalue.c: + libs: initialize GValues in a thread-safe manner. + +2015-01-30 21:35:10 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapivalue.c: + libs: re-indent all GValue related source code. + +2015-01-22 22:45:24 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: partially revert 0777f35. + Reset the VA decoder after updating the base plugin caps, and most + importantly, after GstVideoDecoder negotiation. The reason behind + this is that the negotiation could trigger a last decide_allocation() + where we could actually derive a new GstVaapiDisplay to use from the + downstream element. e.g. GLX backend. + +2015-02-19 13:37:09 +0200 Sreerenj Balachandran + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: Caps query should return the list of all supported caps. + Query caps filtering should be always done on top of allowed caps instead + of existing fixed caps on a particular pad. + This fixes the mvc stream decoding when there is a base view(high profile) + and non-base view(stereo-high profile). + +2015-02-18 13:36:16 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: intersect filter from query caps + According to documentation[1] when receiving a GST_QUERY_CAPS + the return value should be all formats that this elements supports, + taking into account limitations of peer elements further downstream + or upstream, sorted by order of preference, highest preference first. + This patch add those limitations intersecting with the received + filter in the query. Also takes into account the already negotiated + caps. Also adds the processing of the query on the SRC pad. + 1. http://gstreamer.freedesktop.org/data/doc/gstreamer/head/pwg/html/section-nego-getcaps.html + https://bugzilla.gnome.org/show_bug.cgi?id=744406 + +2015-02-18 11:46:11 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapibufferproxy.c: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c: + * gst/vaapi/gstvaapivideomemory.c: + Fix compiler warnings + This patch fixes some warnings that gcc 4.9 reports. + https://bugzilla.gnome.org/show_bug.cgi?id=744411 + +2015-02-18 11:22:21 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: Use GST_DEBUG_FUNCPTR for gst_vaapidecode_query() + Hence the function name is shown in the gst-inspect-1.0 information + rather than the memory address. + https://bugzilla.gnome.org/show_bug.cgi?id=744330 + +2015-02-18 11:21:35 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: log flow error name + https://bugzilla.gnome.org/show_bug.cgi?id=744387 + +2015-02-18 11:20:42 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + VC1: decoder: Ignore VC1 user BDU's + Don't return error if the processed BDU is a user one, just ignore them. + https://bugzilla.gnome.org/show_bug.cgi?id=741237 + Signed-off-by: Sreerenj Balachandran + +2015-02-18 11:19:26 +0200 Olivier Crete + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginbase.c: + vaapidecode: Emit error GstMessage when returning a GST_FLOW_ERROR + This is required in GStreamer, elements should never return + GST_FLOW_ERROR without posting an ERROR message on the bus. + https://bugzilla.gnome.org/show_bug.cgi?id=744620 + +2015-02-13 13:45:32 +0200 Sreerenj Balachandran + + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapiencode_vp8.c: + * gst/vaapi/gstvaapiencode_vp8.h: + plugins: Add VP8 Encoder + +2015-02-13 13:42:04 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapiencoder_vp8.h: + Add VP8 Encoder to core libgstvaapi. + +2015-02-13 13:40:19 +0200 Sreerenj Balachandran + + * configure.ac: + configure: Add Check for VP8 Encoding API + +2015-02-10 11:40:16 +0200 Lim Siew Hoon + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + decoder: vc1: Rounding control handling for VC1 simple and Main profile + Added rounding control handling for VC1 simple and Main profile + based on VC1 standard spec: section 8.3.7 + https://bugzilla.gnome.org/show_bug.cgi?id=743958 + Signed-off-by: Lim Siew Hoon + Signed-off-by: Sreerenj Balachandran + +2015-02-06 12:10:51 +0200 Sreerenj Balachandran + + * gst/vaapi/Makefile.am: + build: fix make dist when certain conditionals not met. + Fix typo which was preventing the inclusion of jpeg encoder + source files from make dist (when there is no jpeg encoder + API support in libva). + +2015-02-05 13:08:53 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c: + encoder: jpeg: Fix the sampling factor calculation for ENCODED format. + If the incoming raw video format is GST_VIDEO_FORMAT_ENCODED, + use native YUV420 format (which is i420) as default. + +2015-02-05 12:13:38 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + encoder: Only support YUV420 native format as input for now + Practically we should be able to support more formats, for eg: + JPEG Encoder can support YUV422, RGBA and all. + But this is causing more issues which need proper fix here and there. + +2015-02-04 18:34:59 +0200 Olivier Crete + + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * gst/vaapi/gstvaapidecode.c: + vaapidecode: Check the condition after taking the lock + Otherwise the condition could become true before the lock + is taken and the g_cond_signal() could be called + before the g_cond_wait(), so the g_cond_wait() is never + awoken. + https://bugzilla.gnome.org/show_bug.cgi?id=740645 + +2015-02-04 11:18:29 +0200 Sreerenj Balachandran + + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapiencode_jpeg.c: + * gst/vaapi/gstvaapiencode_jpeg.h: + plugins: Add JPEG encoder element + +2015-02-04 11:17:58 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapicontext.c: + gstvaapicontext: Add VAConfigAttribValEncJPEG to the attribute list using for VAConfig creation. + +2015-02-04 11:17:27 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapicontext.c: + gstvaapicontext: Don't use the unsupported Ratecontrol attributes for vaCreateConfig + Don't add the VAConfigAttribRateControl to the attribute list using + for the vaCreateConfig if it is not supported by the driver. + +2015-02-04 11:17:06 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + gstvaapiencoder: Use hardcoded packed_raw_data flag for JPEG Encoding + +2015-02-04 11:16:37 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + gstvaapiencoder: Fix crash when handling rate control mask + Having a ratecontrol_mask equal to zero is not a bug, but the driver + might not be supporting any kind of rate control mechanisms. + Eg: JPEG Encoding + +2015-02-04 11:16:05 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapiencoder_jpeg.h: + encoder: Add JPEG Encoder + +2015-02-04 11:15:38 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_objects.c: + * gst-libs/gst/vaapi/gstvaapiencoder_objects.h: + encoder_objects: Add QuantizationMatrix and JPEGHuffmanTable + +2015-02-04 11:15:00 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + Encode: Add support for Picture level Entrypoint + This is useful for JPEG encoding which is utilizing picture level + entrypoint instead of slice level entrypoint like h264,mpeg2 etc. + +2015-02-04 11:14:15 +0200 Sreerenj Balachandran + + * configure.ac: + configure: Add Check for JPEG encoding API + +2015-02-03 13:08:53 +0200 Sreerenj Balachandran + + * AUTHORS: + AUTHORS: Updates + +2015-02-03 13:08:01 +0200 Sreerenj Balachandran + + * configure.ac: + Bump version for development. + +=== release 0.5.10 === + +2015-02-03 10:00:42 +0200 Sreerenj Balachandran + + * configure.ac: + 0.5.10 + +2015-02-03 10:00:23 +0200 Sreerenj Balachandran + + * NEWS: + NEWS: Updates + +2015-02-02 11:43:58 +0200 Sreerenj Balachandran + + * gst/vaapi/gstvaapivideometa_texture.c: + Fix compilation error if there is no GL/gl.h header file installed + +2015-01-28 18:09:40 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideomemory.h: + plugins: drop leftover declaration. + GstVaapiVideoMemory quark is not needed any more, and the actual + implementation was already removed bfore the merge. i.e. this is + an oversight for a hunk that was not meant to be pushed. + +2015-01-26 18:30:47 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapivideobufferpool.c: + * gst/vaapi/gstvaapivideobufferpool.h: + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + plugins: add support for dma_buf exports (v4l2src). + Allow v4l2src element to connected to vaapipostproc or vaapisink when + "io-mode" is set to "dmabuf-import". In practice, this is a more likely + operational mode with uvcvideo. Supporting v4lsrc with "io-mode" set + to "dmabuf" could work, but with more demanding driver or kernel reqs. + Note: with GStreamer 1.4, v4l2src (gst-plugins-good) needs to be built + with --without-libv4l2. + https://bugzilla.gnome.org/show_bug.cgi?id=743635 + +2014-01-23 05:00:09 -0500 Wind Yuan + + * configure.ac: + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapipluginbase.c: + plugins: add support for dma_buf imports. + Allow imports of v4l2 buffers into VA surfaces for further operation + with vaapi plugins, e.g. vaapipostproc or vaapiencode_* elements. + https://bugzilla.gnome.org/show_bug.cgi?id=735362 + [fixed memory leaks, ported to new dma_buf infrastructure, cleanups] + Signed-off-by: Gwenole Beauchesne + +2014-09-15 15:27:50 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurface_drm.c: + * gst-libs/gst/vaapi/gstvaapisurface_drm.h: + surface: add support for GEM buffer imports. + Add support for GEM buffer imports. This is useful for VA/EGL interop + with legacy Mesa implementations, or when it is desired or required to + support outbound textures for instance. + https://bugzilla.gnome.org/show_bug.cgi?id=736718 + +2014-09-15 15:25:09 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurface_drm.c: + * gst-libs/gst/vaapi/gstvaapisurface_drm.h: + surface: add support for dma_buf imports. + Add new gst_vaapi_surface_new_with_dma_buf_handle() helper function + to allow for creating VA surfaces from a foreign DRM PRIME fd. The + resulting VA surface owns the supplied buffer handle. + https://bugzilla.gnome.org/show_bug.cgi?id=735362 + +2015-01-27 11:19:58 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapisurface_priv.h: + surface: add initial support for foreign buffer imports. + Add gst_vaapi_surface_new_from_buffer_proxy() helper function to + create a VA surface from an external buffer provided throug the + new GstVaapiBufferProxy object. + +2014-09-15 13:47:53 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapibufferproxy.c: + * gst-libs/gst/vaapi/gstvaapibufferproxy.h: + * gst-libs/gst/vaapi/gstvaapisurface_drm.c: + * gst-libs/gst/vaapi/gstvaapisurface_drm.h: + surface: add support for GEM buffer exports. + Add support for GEM buffer exports. This will only work with VA drivers + based off libdrm, e.g. the Intel HD Graphics VA driver. This is needed + to support interop with EGL and the "Desktop" GL specification. Indeed, + the EXT_image_dma_buf_import extension is not going to be supported in + Desktop GL, due to the lack of support for GL_TEXTURE_EXTERNAL_OES targets + there. + This is useful for implementing VA/EGL interop with legacy Mesa stacks, + in Desktop OpenGL context. + https://bugzilla.gnome.org/show_bug.cgi?id=736717 + +2014-09-15 11:48:05 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapibufferproxy.c: + * gst-libs/gst/vaapi/gstvaapibufferproxy.h: + * gst-libs/gst/vaapi/gstvaapisurface_drm.c: + * gst-libs/gst/vaapi/gstvaapisurface_drm.h: + surface: add support for dma_buf exports. + Use the new VA buffer export APIs to allow for a VA surface to be + exposed as a plain PRIME fd. This is in view to simplifying interop + with EGL or OpenCL for instance. + https://bugzilla.gnome.org/show_bug.cgi?id=735364 + +2014-09-15 10:58:51 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapibufferproxy.c: + * gst-libs/gst/vaapi/gstvaapibufferproxy.h: + * gst-libs/gst/vaapi/gstvaapibufferproxy_priv.h: + Add abstraction for exported VA buffers. + The VA buffer export APIs work for a particular lifetime starting from + vaAcquireBufferHandle() and ending with vaReleaseBufferHandle(). As such, + it could be much more convenient to support implicit releases by simply + having a refcount reaching zero. + https://bugzilla.gnome.org/show_bug.cgi?id=736721 + +2015-01-28 18:25:09 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/Makefile.am: + Add missing header file to Makefile + Add gstvaapitexture_glx.h to Makefile.am + +2015-01-27 11:44:12 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.h: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapiuploader.c: + * gst/vaapi/gstvaapivideobufferpool.c: + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + * tests/test-surfaces.c: + videopool: add optional flags for surface pool allocation. + Reword surface pool allocation helpers so that to allow for a simple + form, e.g. gst_vaapi_surface_pool_new(format, width, height); and a + somewhat more elaborated/flexible form with optional allocation flags + and precise GstVideoInfo specification. + This is an API/ABI change, and SONAME version needs to be bumped. + +2015-01-26 23:21:56 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiimagepool.c: + * gst-libs/gst/vaapi/gstvaapiimagepool.h: + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.h: + * gst-libs/gst/vaapi/gstvaapivideopool.c: + * gst-libs/gst/vaapi/gstvaapivideopool.h: + * gst-libs/gst/vaapi/gstvaapivideopool_priv.h: + videopool: re-indent all GstVaapiVideoPool related source code. + +2014-12-10 20:13:21 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + window: add toplevel display indirection for visualid and colormap. + Add GstVaapiDisplay::get_{visual_id,colormap}() helpers to help determine + the best suitable window visual id and colormap. This is an indirection in + view to supporting EGL and custom/generic replacements. + +2014-12-10 19:58:10 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11_priv.h: + window: add toplevel API to determine the colormap. + Add GstVaapiWindowClass::get_colormap() hook to help determine the + currently active colormap bound to the supplied window, or actually + create it if it does not already exist yet. + +2014-12-10 19:36:12 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiutils_x11.c: + * gst-libs/gst/vaapi/gstvaapiutils_x11.h: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11_priv.h: + window: add toplevel API to determine a visual id. + Add GstVaapiWindowClass::get_visual_id() function hook to help find + the best suitable visual id for the supplied window. While doing so, + also simplify the process by which an X11 window is created with a + desired Visual, i.e. now use a visual id instead of a Visual object. + +2014-12-10 18:12:24 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.c: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_drm.c: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + window: add generic helper to create windows. + Add a new generic helper function gst_vaapi_window_new() to create + a window without having the caller to check for the display type + himself. i.e. internally, there is now a GstVaapiDisplayClass hook + to create windows, and the actual backend implementation fills it in. + Add new generic helper functions gst_vaapi_texture_new_wrapped() + This is a simplification in view to supporting EGL. + +2014-12-03 11:39:24 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst/vaapi/gstvaapivideometa_texture.c: + display: add utility function to check for OpenGL rendering. + Add gst_vaapi_display_has_opengl() helper function to help determining + whether the display can support OpenGL context to be bound to it, i.e. + if the class is of type GST_VAAPI_DISPLAY_TYPE_GLX. + +2014-12-10 18:02:55 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + * gst-libs/gst/vaapi/gstvaapidisplay_drm_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.c: + * gst-libs/gst/vaapi/gstvaapidisplay_glx_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapivideobuffer.c: + * gst/vaapi/gstvaapivideometa_texture.c: + display: refine the meaning of display type. + Make gst_vaapi_display_get_display_type() return the actual VA display + type. Conversely, add a gst_vaapi_display_get_class_type() function to + return the type of the GstVaapiDisplay instance. The former is used to + identify the display server onto which the application is running, and + the latter to identify the original object class. + +2014-12-02 11:23:29 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + display: cosmetics (helper macros, new internal API names). + Add more helper macros to the top-level GstVaapiDisplay interfaces. + Rename a few others used internally for improved consistency. + +2014-12-01 17:08:29 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapiobject_priv.h: + * gst-libs/gst/vaapi/gstvaapipixmap_x11.c: + * gst-libs/gst/vaapi/gstvaapitexture_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + display: record native display object. + Record the underlying native display instance into the toplevel + GstVaapiDisplay object. This is useful for fast lookups to the + underlying native display, e.g. for creating an EGL display. + +2014-12-01 16:54:32 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplaycache.c: + * gst-libs/gst/vaapi/gstvaapidisplaycache.h: + display: use a recursive mutex for the display cache. + Use a recursive mutex for the display cache so that a 3rdparty display + object could be initialized during the initialization of the parent + display. + +2014-12-04 14:36:35 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay_glx.c: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapitexture.h: + * gst-libs/gst/vaapi/gstvaapitexture_glx.c: + * gst-libs/gst/vaapi/gstvaapitexture_priv.h: + texture: add generic helper to create textures. + Add new generic helper functions gst_vaapi_texture_new_wrapped() + and gst_vaapi_texture_new() to create a texture without having + the caller to uselessly check for the display type himself. i.e. + internally, there is now a GstVaapiDisplayClass hook to create + textures, and the actual backend implementation fills it in. + This is a simplification in view to supporting EGL. + +2014-10-23 17:44:23 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapitexture.h: + * gst-libs/gst/vaapi/gstvaapitexture_glx.c: + * gst-libs/gst/vaapi/gstvaapitexture_glx.h: + * gst-libs/gst/vaapi/gstvaapitexture_priv.h: + * gst/vaapi/gstvaapivideoconverter_glx.c: + * gst/vaapi/gstvaapivideometa_texture.c: + * tests/test-textures.c: + texture: move to core libgstvaapi base library. + GstVaapiTexture is a generic abstraction that could be moved to the + core libgstvaapi library. While doing this, no extra dependency needs + to be added. This means that a GstVaapitextureClass is now available + for any specific code that needs to be added, e.g. creation of the + underlying GL texture objects, or backend dependent ways to upload + a surface to the texture object. + Generic OpenGL data types (GLuint, GLenum) are also replaced with a + plain guint. + https://bugzilla.gnome.org/show_bug.cgi?id=736715 + +2014-10-23 13:11:54 +0200 Gwenole Beauchesne + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapicompat.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.c: + * gst-libs/gst/vaapi/gstvaapitexture.c: + texture: drop support for VA/GLX interfaces. + The VA/GLX interfaces are obsolete. They used to exist for XvBA, and + ease of use, but they had other caveats to deal with. It's now better + to move on to legacy mode, whereby VA/GLX interop is two be provided + through (i) X11 Pixmap, and (ii) other modern means of buffer sharing. + https://bugzilla.gnome.org/show_bug.cgi?id=736711 + +2014-10-23 11:56:31 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapitexture.h: + * gst/vaapi/gstvaapivideoconverter_glx.c: + * gst/vaapi/gstvaapivideometa_texture.c: + * tests/test-textures.c: + texture: add support for cropping rectangle during transfer. + The gst_vaapi_texture_put_surface() function is missing a crop_rect + argument that would be used during transfer for cropping the source + surface to the desired dimensions. + Note: from a user point-of-view, he should create the GstVaapiTexture + object with the cropped size. That's the default behaviour in software + decoding pipelines that we need to cope with. + This is an API/ABI change, and SONAME version needs to be bumped. + https://bugzilla.gnome.org/show_bug.cgi?id=736712 + +2014-10-23 11:22:10 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapitexture.h: + texture: re-indent all GstVaapiTexture related source code. + +2015-01-27 11:16:34 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + surface: add more fine-grained allocation helper. + Add new gst_vaapi_surface_new_full() helper function that allocates + VA surface from a GstVideoInfo template in argument. Additional flags + may include ways to + - allocate linear storage (GST_VAAPI_SURFACE_ALLOC_FLAG_LINEAR_STORAGE) ; + - allocate with fixed strides (GST_VAPI_SURFACE_ALLOC_FLAG_FIXED_STRIDES) ; + - allocate with fixed offsets (GST_VAAPI_SURFACE_ALLOC_FLAG_FIXED_OFFSETS). + +2014-09-15 14:57:57 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapisurface_priv.h: + surface: re-indent all GstVaapiSurface related source code. + +2015-01-23 16:44:34 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + surfaceproxy: add helper to create a wrapped surface object. + Add new gst_vaapi_surface_proxy_new() helper to wrap a surface into + a proxy. The main use case for that is to convey additional information + at the proxy level that would not be suitable to the plain surface. + +2015-01-23 16:37:06 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy_priv.h: + surfaceproxy: re-indent all GstVaapiSurfaceProxy related source code. + +2015-01-27 18:02:56 +0100 Gwenole Beauchesne + + * configure.ac: + libs: bump library major version. + +2014-12-04 14:36:35 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapitypes.h: + libs: re-introduce a GST_VAAPI_ID_INVALID value. + Re-introduce a GST_VAAPI_ID_INVALID value that represents + a non-zero and invalid id. This is useful to have a value + that is still invalid for cases where zero could actually + be a valid value. + +2014-12-02 16:51:20 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiminiobject.c: + * gst-libs/gst/vaapi/gstvaapiminiobject.h: + libs: expose GstVaapiMiniObject APIs to all backends. + Make it possible to have all libgstvaapi backends (libs) access to a + common GstVaapiMiniObject API and implementation. This is a minor step + towards full exposure when needed, but restrict it to libgstvaapi at + this time. + +2014-12-02 14:15:49 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiminiobject.c: + * gst-libs/gst/vaapi/gstvaapiminiobject.h: + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapiobject.h: + * gst-libs/gst/vaapi/gstvaapiobject_priv.h: + libs: re-indent all GstVaapiObject related source code. + Re-indent and provide additional minor cosmetical changes to the + GstVaapiMiniObject and GstVaapiObject source files. + +2015-01-27 16:25:21 +0200 Simon Farnsworth + + * gst/vaapi/gstvaapipluginutil.c: + pluginutil: Fix clearing of subtitle overlay + dvbsuboverlay signals no subtitles present by not setting + GstVideoOverlayCompositionMeta on a buffer. + Detect this, and remove subtitles whenever we have no overlay composition to + hand. + Signed-off-by: Simon Farnsworth + +2015-01-27 16:06:02 +0200 Michael Olbrich + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: clear state on stop + Otherwise restarting may fail because the state of vaapipluginbase and + vaapipostproc don't match. e.g. gst_vaapipostproc_set_caps() will skip + initailization and not call gst_vaapi_plugin_base_set_caps() + +2015-01-27 14:50:12 +0200 Michael Olbrich + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: don't print an error message for GST_FLOW_FLUSHING + +2015-01-27 12:38:45 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + gstvaapiencoder: Fix the negotiation issue with _ENCODED format handling + Don't error out for the video format GST_VIDEO_FORMAT_ENCODED with in gstvaapiencoder, + since the vaaapi context creation (gstvaapicontext.c) can still use the + default chroma type which is YUV420. + https://bugzilla.gnome.org/show_bug.cgi?id=743567 + https://bugzilla.gnome.org/show_bug.cgi?id=743035 + +2015-01-21 18:31:22 +0200 Sreerenj Balachandran + + * patches/videoparsers/0003-h264parse-add-initial-support-for-MVC-NAL-units.patch: + * patches/videoparsers/series.frag: + h264parse: drop patches merged upstream. + 0003-h264parse-add-initial-support-for-MVC-NAL-units.patch + +2015-01-21 18:26:12 +0200 Sreerenj Balachandran + + * ext/codecparsers: + codecparsers: update to gst-vaapi-branch commit d3b5c1b + 8194cac: h264parse: parse SPS subset + 64b7f52: h264parse: expose stereo-high profile + 774360a: h264parse: add initial support for MVC NAL units + 258478f: h264parser: fix stack smashing + +2015-01-19 11:30:12 +0200 Sreerenj Balachandran + + * gst/vaapi/gstvaapivideometa_texture.c: + Fix compilation error if there is no GL/gl.h header file installed + +2015-01-15 16:23:24 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: commit updated srcpad caps to base plugin. + Make sure that the GstVaapiPluginBase instance receives the new src + pad caps whenever they get updated from within the GstVaapiDecoder + decode routines. + This also ensures that downstream elements receive correctly sized + SW decoded buffers if needed. + https://bugs.tizen.org/jira/browse/TC-114 + +2015-01-15 16:19:59 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: always reset decoder on ::set_format(). + Split GstVideoDecoder::set_format() handler to first update the sink + pad caps and reset the active VA decoder instance based on those, and + then update the src pad caps whenever possible, e.g. when the caps + specify a valid video resolution. + +2015-01-15 16:14:13 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: don't crash when trying to allocate 0x0 images. + In some occasions, a buffer pool is created for pre-initialization + purposes regardless of whether a valid image size is available or + not. However, during actual decode stage, the vaapidecode element + is expected to update the srcpad caps with the new dimensions, thus + also triggering a reset of the underlying bufferpool. + +2015-01-15 00:00:16 +0200 Sreerenj Balachandran + + * ext/codecparsers: + codecparsers: update to gst-vaapi-branch commit 191cb2f + 347605a: h264parse: expose compatible profiles to downstream + d1ea97e: h264parse: Fix periodic SPS/PPS sending work after a seek + 24a3126: Revert "h264parse: expose compatible profiles to downstream" + 8661740: h264parse: expose compatible profiles to downstream + 8b7ef3f: codecparsers: fix some compiler warnings + +2014-11-27 12:11:03 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: Fix the period between I/P frames + If the key-frame period is set as one, then ip_period shuld be zero + https://bugzilla.gnome.org/show_bug.cgi?id=734992 + +2014-11-27 11:21:03 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: Provide intra_idr_period value for VAEncSequenceParameterBufferH264 + https://bugzilla.gnome.org/show_bug.cgi?id=734993 + +2014-11-27 11:14:50 +0200 Sreerenj Balachandran + + * gst/vaapi/gstvaapisink.c: + vaapisink: Protect the X11 API invokations with proper locking + https://bugzilla.gnome.org/show_bug.cgi?id=739808 + +2014-11-27 11:13:20 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: fix pixel-aspect-ratio in encoded stream. + Really report sample aspect ratio (SAR) as present, and make it match + what we have obtained from the user as pixel-aspect-ratio (PAR). i.e. + really make sure VUI parameter aspect_ratio_info_present_flag is set + to TRUE and that the indication from aspect_ratio_idc is Extended_SAR. + This is a leftover from git commit a12662f. + https://bugzilla.gnome.org/show_bug.cgi?id=740360 + +2014-11-25 11:46:12 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + decoder: mpeg4: fix uninitialized variables. + Fix gst_vaapi_decoder_mpeg4_parse() to initialize the packet type to + GST_MPEG4_USER_DATA so that a parse error would result in skipping + that packet. Also fix gst_vaapi_decoder_mpeg4_decode_codec_data() to + initialize status to GST_VAAPI_DECODER_STATUS_SUCCESS. + +2014-11-25 11:41:49 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: fix profile limits. + Fix ensure_profile_limits() to lower profile to the desired limits, + only if the latter are actually known and the profile needed to be + changed to fit. + +2014-11-24 15:14:37 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: fix out caps for GLMemory. + If the best downstream capsfeature turns out to be GLMemory, then make + sure to propagate RGBA video format in caps to that element. This fixes + the following pipeline: ... ! vaapipostproc ! glimagesink. + +2014-11-24 14:25:33 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: fix check for compatible src pad capsfilters. + When an explicit output video format is selected, from an src pad + capsfilter, make sure that the downstream element actually supports + that format. In particular, fix crash with the following pipelines: + ... ! vaapipostproc ! video/x-raw,format=XXX ! xvimagesink ; where + XXX is a format not supported by xvimagesink. + While doing so, also reduce the set of src pad filter caps to the + actual set of allowed src pad caps. + +2014-11-24 14:10:11 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + * gst/vaapi/gstvaapiuploader.c: + * gst/vaapi/gstvaapiuploader.h: + plugins: re-indent all video processing related source code. + +2014-11-24 13:20:33 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideomemory.c: + plugins: further fixes to the new "current" storage tracker. + The ensure_surface() and ensure_image() functions shall only relate + to the underlying backing store. The actual current flags are to be + updated only through ensure_{surface,image}_is_current() or very other + particular cases in GstMemory hooks. + +2014-11-21 15:43:35 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideomemory.c: + plugins: fix "current" video memory flags. + If the surface proxy is updated into the GstVaapiVideoMemory, then + it is assumed it is the most current representation of the current + video frame. Likewise, make a few more arrangements to have the + "current " flags set more consistently. + +2014-11-21 15:23:13 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + * gst/vaapi/gstvaapivideometa.c: + plugins: ensure VA surface is current prior to using it. + When interacting with SW elements, the buffers and underlying video + memory could be mapped as read/write. However, we need to use those + buffers again as plain VA surfaces, we have to make sure the VA image + is thus committed back to VA surface memory. + This fixes pipelines involving avdec_* and vaapi{postproc,sink}. + +2013-07-12 06:34:15 -0400 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideomemory.c: + plugins: enable memory maps for read & write. + Hence vaapisink can display buffers decoded by gst-libav, or HW decoded + buffers can be further processed in-place, e.g. with a textoverlay. + https://bugzilla.gnome.org/show_bug.cgi?id=704078 + [ported to current git master branch, amended commit message] + Signed-off-by: Gwenole Beauchesne + +2014-11-18 14:57:02 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapipostproc.c: + plugins: preserve framerate when updating src caps video format. + In the current implementation, gst_video_info_set_format() would reset + the whole GstVideoInfo structure first, prior to setting video format + and size. So, coleteral information like framerate or pixel-aspect- + ratio are lost. + Provide and use a unique gst_video_info_change_format() for overcome + this issue, i.e. only have it change the format and video size, and + copy over the rest of the fields. + https://bugzilla.gnome.org/show_bug.cgi?id=734665 + +2014-11-18 14:07:57 +0200 Sreerenj Balachandran + + * gst/vaapi/gstvaapi.c: + vaapidecode: increase the rank to GST_RANK_PRIMARY + 1 + This is for helping decodebin to autoplug the vaapidecode element. + Decodebin is selecting decoder elements only based on rank and caps. + Without overriding the autoplug-* signals there is no way to autoplug + HW decoders inside decodebin. An easier soulution is to raise the + rank of vaapidecode, so that it gets selected first. + https://bugzilla.gnome.org/show_bug.cgi?id=739332 + +2014-11-12 07:46:53 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst/vaapi/gstvaapidecode.c: + vaapidecode: only expose supported profiles when needed. + JPEG and VP8 codecs do not really support the concept of "profile". So, + don't try to expose any set that wouldn't be supported by jpegparse, or + ivfparse for instance. + https://bugzilla.gnome.org/show_bug.cgi?id=739713 + https://bugzilla.gnome.org/show_bug.cgi?id=739714 + +2014-11-13 15:13:24 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + decoder: h264: add initial support for repeat-first-field (RFF) flag. + Use the SEI pic_timing() message to track and propagate down the repeat + first field (RFF) flag. This is only initial support as there is one + other condition that could induce the RFF flag, which is not handled + yet. + +2014-11-13 15:05:19 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: fix picture ordering count type 0 with previous MMCO5. + Fix the decoding process for picture order count type 0 when the previous + picture had a memory_management_control_operation = 5. In particular, fix + the actual variable type for prev_pic_structure to hold the full bits of + the picture structure. + In practice, this used to work though, due to the underlying type used to + express a gboolean. + +2014-11-13 15:00:21 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: fix detection of top-field-first (TFF) flag. + Use the SEI pic_timing() message to track the pic_struct variable when + present, or infer it from the regular slice header flags field_pic_flag + and bottom_field_flag. This fixes temporal sequence ordering when the + output pictures are to be displayed. + https://bugzilla.gnome.org/show_bug.cgi?id=739291 + +2014-11-14 09:54:02 +0100 Gwenole Beauchesne + + * ext/codecparsers: + codecparsers: update to gst-vaapi-branch commit 3d05d9f. + 1241840 h264: fix derivation of MaxPicNum variable + 3bd718e h264: fix GstH264ParserResult documentation typo + b021609 h264parse: set the HEADER flag on buffers containing SPS or PPS + b08e4be h264parse: don't unnecesarily set src_caps + +2014-11-03 19:20:43 +0200 Sreerenj Balachandran + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: Add string representation of VPP functions to ElementFactoy Klass + Added the same Klass specifications used in other upstream + video postprocessing elements like videoconvert, videoscale, + videobalance and deinterlace. + An example use case is for this is to help the playsink + to autoplug the hardware accelerated deinterlacer. + +2014-11-03 19:19:20 +0200 Sreerenj Balachandran + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: Tweak the output video format setting to enable the autoplugging + This is a workaround until auto-plugging is fixed when + format=ENCODED + memory:VASurface caps feature are provided. + Use the downstream negotiated video format as the output video format + if the user didn't ask for the colorspace conversion explicitly. + Usecase: This will help to connect elements like videoscale, videorate etc + to vaapipostproc. + https://bugzilla.gnome.org/show_bug.cgi?id=739443 + +2014-10-29 17:30:30 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + vaapipostproc: allow user defined scaling mode. + Add new "scale-method" property to expose the scaling mode to use during + video processing. Note that this is only a hint, and the actual behaviour + may differ from implementation (VA driver) to implementation. + +2014-10-29 16:57:12 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapifilter.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + filter: add initial support for high quality scaling. + Add support for video scaling options in VPP pipelines. Only the + DEFAULT mode is bound to exist. Others might be folded into that + mode. + +2014-10-29 16:35:46 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapifilter.h: + filter: re-indent all GstVaapiFilter related source code. + +2014-10-29 15:45:50 +0100 Gwenole Beauchesne + + * ext/codecparsers: + codecparsers: update to gst-vaapi-branch commit f9d3bde. + 2218b02 h264parse: expose parsed profile and level to downstream + 3dbfab4 h264parse: return flushing if we get chained while being set to READY + d40fa8b h264: fix frame packing SEI parsing + 32d40be h264: Use proper bit_reader api while parsing buffering_period SEI + b3e022e h264: initialize some fields of pic_timing structure + a70661d vc1: fix expected level in sequence-layer parsing unit test + 6cee88d vc1: fix level values for simple/main profile + 356c189 vc1: add unit test for sequence-layer parsing + ab9f641 vc1: take care of endianness when parsing sequence-layer + 8dc8e35 mpeg4: fix vlc table used for sprite trajectory + +2014-10-29 15:46:47 +0200 Sreerenj Balachandran + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: Expose the supported profiles as caps to upstream + This will allows the playbin to fallback to Software Decoder + if the Hardware Decoder does not support a particular profile. + https://bugzilla.gnome.org/show_bug.cgi?id=730997 + +2014-10-29 15:46:12 +0200 Sreerenj Balachandran + + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode.h: + * gst/vaapi/gstvaapiencode_h264.c: + encode: Attach the codec-data to out caps only based on negotiated caps + Attach the codec_data to out_caps only if downstream needed. + For eg: h264 encoder doesn't need to stuff codec_data to the + src caps if the negotiated caps has a stream format of byte-stream. + https://bugzilla.gnome.org/show_bug.cgi?id=734902 + +2014-10-29 15:45:44 +0200 Sreerenj Balachandran + + * configure.ac: + configure: echoing installation prefix path + +2014-09-24 10:14:24 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + display: add support for DRM Render-Nodes. + Add support for DRM Render-Nodes. This is a new feature that appeared + in kernel 3.12 for experimentation purposes, but was later declared + stable enough in kernel 3.15 for getting enabled by default. + This allows headless usages without authentication at all, i.e. usages + through plain ssh connections is possible. + +2014-09-24 13:44:43 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + vaapisink: clean-ups (indentation, drop unused variables). + +2014-09-24 13:39:55 +0200 Gwenole Beauchesne + + * configure.ac: + * gst/vaapi/gstvaapisink.c: + vaapisink: fix GstNavigation "key-press" / "key-release" events. + Fix arguments to XkbKeycodeToKeysym() for converting an X11 keycode + to a KeySym. In particular, there is no such Window argument. Also + make sure to check for, and use, the correct header + where that new function is defined. Otherwise, default to the older + XKeycodeToKeysym() function. + +2014-09-24 13:23:17 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + vaapisink: fix GstNavigation "mouse-move" event. + Really use the motion event coordinates to propagate the "mouse-move" + event to upper layer, instead of those from a button event. Those are + technically the same though. + +2014-09-16 14:25:40 +0300 Sreerenj Balachandran + + * gst/vaapi/gstvaapisink.c: + vaapisink: implement the GstNavigation interface + This is useful for things like DVD menus, where key/mouse events + would need to be forwarded from the upstream sink element. + https://bugzilla.gnome.org/show_bug.cgi?id=711479 + +2014-03-13 18:38:33 +0000 Simon Farnsworth + + * gst/vaapi/gstvaapipluginbase.c: + vaapipostproc: fix deinterlacing from non VA memory buffers. + When we copy a buffer because we're moving it into VA-API memory, we + need to copy flags. Otherwise, interlaced YUV buffers from a capture + source (e.g. V4L2) don't get flagged as interlaced. + https://bugzilla.gnome.org/show_bug.cgi?id=726270 + Signed-off-by: Simon Farnsworth + [reversed order of gst_buffer_copy_into() flags to match <1.0 code] + Signed-off-by: Gwenole Beauchesne + +2014-08-22 15:22:32 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: add support for GLTextureUploadMeta output. + This allows for vaapipostproc to be chained to the glimagesink element + for instance. + https://bugzilla.gnome.org/show_bug.cgi?id=735231 + +2014-08-22 15:22:32 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: add support for "download" capability. + Allow implicit conversions to raw video formats, while still keeping + VA surfaces underneath. This allows for chaining the vaapipostproc + element to a software-only element that takes care of maps/unmaps. + e.g. xvimagesink. + https://bugzilla.gnome.org/show_bug.cgi?id=720174 + +2014-08-22 18:10:54 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + vaapipostproc: use pooled vaapi video meta. + Use pooled GstVaapiVideoMeta information, i.e. always allocate that on + video buffer allocation. Also optimize copy of additional metadata info + into the resulting video buffer: only copy the video cropping info and + the source surface proxy. + https://bugzilla.gnome.org/show_bug.cgi?id=720311 + Signed-off-by: Sreerenj Balachandran + [fixed proxy leak, fixed double free on error, optimized meta copy] + Signed-off-by: Gwenole Beauchesne + +2014-08-22 15:17:29 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: fix passthrough mode. + If no explicit output surface format is supplied try to keep the one + supplied through the sink pad caps. This avoids a useless copy, even + if things are kept in GPU memory. + This is a performance regression from git commit dfa70b9. + +2014-07-05 21:00:34 +0300 Sreerenj Balachandran + + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + vaapipostproc: fix output buffer to have a GstVaapiVideoMemory. + https://bugzilla.gnome.org/show_bug.cgi?id=720311 + [used new infrastructure through base decide_allocation() impl] + Signed-off-by: Gwenole Beauchesne + +2014-08-22 11:13:36 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: enable advanced deinterlacing with same format. + If only advanced deinterlacing is requested, i.e. deinterlacing is + the only active algorithm to apply with source and output surface + formats being the same, then make sure to enable VPP processing. + Otherwise, allow fallback to bob-deinterlacing with simple rendering + flags alteration. + +2014-08-21 15:04:20 +0300 Sreerenj Balachandran + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: avoid NULL pointer unref if GstVaapiImage creation failed. + https://bugzilla.gnome.org/show_bug.cgi?id=735156 + +2014-08-22 13:25:03 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginutil.c: + plugins: fix memory leaks. + +2014-08-21 14:10:36 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + plugins: factor out decide_allocation() hook. + Add a default decide_allocation() hook to GstVaapiPluginBase. The caps + feature argument can be used to force a bufferpool with a specific kind + of memory. + +2014-08-21 11:12:39 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideobufferpool.c: + * gst/vaapi/gstvaapivideobufferpool.h: + * gst/vaapi/gstvaapivideomemory.c: + plugins: allow bufferpool to not allocate vaapi video meta. + Add GST_VAAPI_VIDEO_BUFFER_POOL_ACQUIRE_FLAG_NO_ALLOC params flag that + can be used to disable early allocations of vaapi video metas on buffers, + thus delagating that to the bufferpool user. + +2014-08-21 10:45:31 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideobuffer.c: + * gst/vaapi/gstvaapivideobuffer.h: + * gst/vaapi/gstvaapivideobufferpool.c: + * gst/vaapi/gstvaapivideobufferpool.h: + * gst/vaapi/gstvaapivideocontext.c: + * gst/vaapi/gstvaapivideocontext.h: + * gst/vaapi/gstvaapivideoconverter_glx.c: + * gst/vaapi/gstvaapivideoconverter_glx.h: + * gst/vaapi/gstvaapivideoconverter_x11.c: + * gst/vaapi/gstvaapivideoconverter_x11.h: + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + * gst/vaapi/gstvaapivideometa.c: + * gst/vaapi/gstvaapivideometa.h: + * gst/vaapi/gstvaapivideometa_texture.c: + * gst/vaapi/gstvaapivideometa_texture.h: + plugins: re-indent all GstVaapiVideo* related source code. + +2014-08-22 15:12:46 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + surfaceproxy: fix copy to propagate view_id. + Fix gst_vaapi_surface_proxy_copy() to copy the view-id element, thus + fixing random frames skipped when vaapipostproc element is used in + passthrough mode. In that mode, GstMemory is copied, thus including + the underlying GstVaapiVideoMeta and associated GstVaapiSurfaceProxy. + +2014-08-20 16:38:45 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: fix detection of output surface format changes. + Default to I420 format for output surfaces so that to match the usual + GStreamer pipelines. Though, internally, we could still opt for NV12 + surface formats, i.e. default format=ENCODED is a hint for that, thus + delegating the decision to the VA driver. + +2014-08-20 10:59:53 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: fix construction of allowed sink pad caps. + Fix construction of the set of caps allowed on the sink pad to filter + out unsupported raw video caps with GStreamer >= 1.2. + +2014-08-20 10:37:02 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + vaapipostproc: improve heuristics for detecting native VA surfaces. + Use the new gst_caps_has_vaapi_surface() helper function to detect + whether the sink pad caps contain native VA surfaces, or not, i.e. + no raw video caps. + Also rename is_raw_yuv to get_va_surfaces to make the variable more + explicit as we just want a way to differentiate raw video caps from + VA surfaces actually. + +2014-08-12 18:33:25 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: disable discontinuity detection code. + The "discontinuity" tracking code, whereby lost frames are tentatively + detected, is inoperant if the sink pad buffer timestamps are not right + to begin with. + This is a temporary workaround until the following bug is fixed: + https://bugzilla.gnome.org/show_bug.cgi?id=734386 + +2014-08-07 14:57:26 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: fix heuristic for detecting discontinuity. + In order to make the discontinuity detection code useful, we need to + detect the lost frames in the history as early as the previous frame. + This is because some VA implementations only support one reference + frame for advanced deinterlacing. + In practice, turn the condition for detecting new frame that is beyond + the previous frame from field_duration*2 to field_duration*3, i.e. + nothing received for the past frame and a half because of possible + rounding errors when calculating the field-duration either in this + element (vaapipostproc), or from the upstream element (parser element). + This is a regression introduced with commit faefd62. + https://bugzilla.gnome.org/show_bug.cgi?id=734135 + +2014-08-20 11:43:08 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + plugins: fix detection of raw video caps. + Use the new gst_caps_has_vaapi_surface() helper function to better + detect raw video caps, and in particular those from RGB colorspace. + https://bugzilla.gnome.org/show_bug.cgi?id=734665 + +2014-08-20 11:30:41 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + plugins: add helper for detecting VA surfaces in caps. + Introduce new gst_caps_has_vaapi_surface() helper function to detect + whether the supplied caps has VA surfaces. With GStreamer >= 1.2, this + implies a check for memory:VASurface caps features, and format=ENCODED + for earlier versions of GStreamer. + +2014-08-12 13:01:57 +0300 Sebastian Dröge + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: start the decoder task again after finishing + This allows the element to accept data again after draining without + a hard reset or caps change happening in between. + https://bugzilla.gnome.org/show_bug.cgi?id=734616 + +2014-08-12 13:00:03 +0300 Sebastian Dröge + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: unlock condition variables before shutting down the element + Otherwise threads might wait for them, causing the shutdown of the element + to deadlock on the streaming thread. + https://bugzilla.gnome.org/show_bug.cgi?id=734616 + +2014-08-11 17:15:24 +0300 Sebastian Dröge + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: reset decoder_finish variable after stopping the decoder thread + Otherwise the element is not usable again after draining/EOS. + https://bugzilla.gnome.org/show_bug.cgi?id=734616 + +2014-08-11 17:14:53 +0300 Sebastian Dröge + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: don't try flushing the decoder instance if we didn't create one yet + This otherwise results in unnecessary error messages. + https://bugzilla.gnome.org/show_bug.cgi?id=734616 + +2014-08-01 06:32:32 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst/vaapi/Makefile.am: + build: fix with --no-undefined linker flags. + https://bugzilla.gnome.org/show_bug.cgi?id=729352 + +2014-01-23 15:44:09 +0000 Changzhi Wei + + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + vaapisink: add support for GstColorBalance interface. + https://bugzilla.gnome.org/show_bug.cgi?id=722390 + [fixed channel names, simplified range factor, fixed memory leak] + Signed-off-by: Gwenole Beauchesne + +2014-01-23 15:23:00 +0000 Changzhi Wei + + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + vaapisink: add support for colorbalance adjustment. + https://bugzilla.gnome.org/show_bug.cgi?id=722390 + [fixed and simplified tracking of colorbalance value changes] + Signed-off-by: Gwenole Beauchesne + +2014-07-31 13:18:21 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + vaapisink: improve installation of properties. + Simplify the creation and installation process of properties, by first + accumulating them into a g_properties[] array, and next calling into + g_object_class_install_properties(). + Also add missing docs and flags to some properties. + +2014-07-31 10:48:15 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + vaapisink: code clean-ups. + Move code around in a more logical way. Introduce GST_VAAPISINK_CAST() + helper macro and use it wherever we know the object is a GstBaseSink or + any base class. Drop explicit initializers for values that have defaults + set to zero. + +2014-07-31 10:37:57 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + vaapisink: re-indent all GstVaapiSink related source code. + +2014-07-30 17:27:50 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + vaapisink: introduce separate backends. + Introduce new backends vtable so that to have clean separation between + display dependent code and common base code. That's a "soft" separation, + we don't really need dedicated objects. + https://bugzilla.gnome.org/show_bug.cgi?id=722248 + +2014-07-30 16:47:20 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + vaapisink: drop unused "synchronous" mode. + Support for X11 "synchronous" mode was never implemented, and was only + to be useful for debugging. Drop that altogether, that's not going to + be useful in practice. + https://bugzilla.gnome.org/show_bug.cgi?id=733985 + +2014-07-30 17:32:29 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + vaapisink: drop unused variables. + Drop obsolete, and now unused, video_buffer_pool and video_buffer_size + variables. They got merged into the GstVaapiPluginBase object. + +2014-07-30 16:35:32 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + vaapisink: drop GLX rendering and fancy effects. + Rendering with GLX in vaapisink is kind of useless nowadays, including + OpenGL related fancy effects. Plain VA/GLX interfaces are also getting + deprecated in favor of EGL, or more direct buffer sharing with actual + GL textures. + Should testing of interop with GLX be needed, one could still be using + the modern cluttersink or glimagesink elements. + https://bugzilla.gnome.org/show_bug.cgi?id=733984 + +2013-11-05 14:01:11 +0100 Holger Kaelberer + + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + vaapisink: listen to window size changes on X11. + Allow dynamic changes to the window, e.g. performed by the user, and + make sure to refresh its contents, while preserving aspect ratio. + In practice, Expose and ConfigureNotify events are tracked in X11 + display mode by default. This occurs in a separte event thread, and + this is similar to what xvimagesink does. Any of those events will + trigger a reconfiguration of the window "soft" size, subsequently + the render-rect when necessary, and finally _expose() the result. + The default of handle_events=true can be changed programatically via + gst_x_overlay_handle_events(). + Thanks to Fabrice Bellet for rebasing the patch. + https://bugzilla.gnome.org/show_bug.cgi?id=711478 + [dropped XInitThreads(), cleaned up the code a little] + Signed-off-by: Gwenole Beauchesne + +2014-07-29 15:47:46 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: decode and output all pending frames on normal EOS. + The gst_vaapidecode_decode_loop() function is called within a separate + task to fetch and output all frames that were decoded so far. So, if + the decoder_loop_status is forcibly set to EOS when _finish() is called, + then we are bound to exist the task without submitting the pending + frames. + If the downstream element error'ed out, then the gst_pad_push() would + propagate up an error and so we will get it right for cutting off + _finish() early in that case. + This is a regression from 6003596. + https://bugzilla.gnome.org/show_bug.cgi?id=733897 + +2014-07-29 13:24:52 +0200 Gwenole Beauchesne + + * configure.ac: + Bump version for development. + +2014-07-29 10:31:58 +0200 Gwenole Beauchesne + + * AUTHORS: + AUTHORS: updates. + +2014-07-29 10:31:15 +0200 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2014-07-29 16:22:01 +1000 Matthew Waters + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: properly return from decode loop on downstream errors. + Fixes a hang/race on shutdown where _decode_loop() had already completed + its execution and _finish() was waiting on a GCond for decode_loop() + to complete. Also fixes the possible race where _finish() is called + but _decode_loop() endlessly returns before signalling completion + iff the decoder instance returns GST_FLOW_OK. + Found with: ... ! vaapidecode ! {glimagesink,cluttersink} + https://bugzilla.gnome.org/show_bug.cgi?id=733897 + [factored out GST_VIDEO_DECODER_STREAM_UNLOCK() call] + Signed-off-by: Gwenole Beauchesne + +2014-07-28 18:45:49 +0200 Gwenole Beauchesne + + * NEWS: + * configure.ac: + 0.5.9. + +2014-07-28 18:31:09 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + vaapisink: fix GstVideoOverlay::expose() implementation. + Now that we always track the currently active video buffer, it is + not necessary to automatically increase its reference since this is + implicitly performed in ::show_frame() through the get_input_buffer() + helper from GstVaapiPluginBase class. + This is a regression from a26df80. + +2014-07-28 18:00:19 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginutil.c: + vaapidecode: simplify bufferpool configuration. + Rework the logics behind the configuration of an adequate bufferpool, + especially when OpenGL meta or additional capsfeatures are needed. + Besides, for GStreamer >= 1.4, the first capsfeatures that gets matched, + and that is not system memory, is now selected by default. + +2014-07-28 16:43:47 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: fix auto-plugging of vaapisink element. + Make sure to propagate memory:VASurface capsfeature to srcpad caps + only for GStreamer >= 1.5 as the plug-in elements in GStreamer 1.4 + core currently miss additional patches available in 1.5-git (1.6). + This is a temporary workaround. + +2014-07-28 15:54:46 +0300 Sreerenj Balachandran + + * configure.ac: + configure: allow builds against GStreamer git (1.5.x). + https://bugzilla.gnome.org/show_bug.cgi?id=733688 + +2014-07-28 14:20:33 +0200 Gwenole Beauchesne + + * configure.ac: + configure: fix build with GStreamer 1.4.0 release. + +2014-03-04 19:40:59 +0100 Gwenole Beauchesne + + * configure.ac: + * debian.upstream/Makefile.am: + * debian.upstream/control.in: + debian: fix packaging for new naming scheme. + +2014-07-28 11:52:06 +0200 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2014-07-28 11:39:11 +0200 Gwenole Beauchesne + + * configure.ac: + configure: mark support for GStreamer < 1.2 as deprecated. + Supporting anything thing below GStreamer 1.2 is asking for trouble + for keeping up with the required facilities to make efficient pipelines. + Users are invited to upgrade to the very latest GStreamer 1.2.x release, + at the minimum. + +2014-07-28 11:35:24 +0200 Gwenole Beauchesne + + * configure.ac: + configure: mark support for GStreamer 0.10 as obsolete. + Support for GStreamer 0.10 is obsolete. i.e. it is no longer supported + and may actually be removed altogether for a future release. There is + no real point to maintain a build for such an ancient GStreamer version + that is not even supported upstream. + +2014-07-28 10:25:26 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + vaapisink: allow a specific view component to be displayed. + If a multiview stream is decoded, multiple view components are submitted + as is downstream. It is the responsibility of the sink element to display + the required view components. By default, always select the frame buffer + that matches the view-id of the very first frame to be displayed. + However, introduce a "view-id" property to allow the selection of a + specific view component of interest to display. + +2014-07-28 10:09:34 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + vaapisink: always keep the last displayed buffer around. + Always record the VA surface that is currently being rendered, no matter + the fact we are using texturedblit or overlay. That's because in some + occasions, we need to refresh or resize the displayed contents based on + new events. e.g. user-resized window. + Besides, it's simpler to track the last video buffer in GstVaapiSink than + through the base sink "last-sample". + +2014-07-25 11:13:29 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapisink.c: + vaapisink: add support for "display-name" property. + Add a "display-name" property to vaapisink so that the end user could + select the desired output. Keep "display-name" in-line with the existing + "display" (GstVaapiDisplayXXX type). + So, for X11 or GLX, the "display-name" is the usual display name as we + know for XOpenDisplay(); for Wayland, the "display-name" is the name used + for wl_display_connect(); and for DRM, the "display-name" is actually the + DRI device name. + https://bugzilla.gnome.org/show_bug.cgi?id=722247 + +2014-07-25 17:29:40 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + window: make gst_vaapi_window_reconfigure() thread-safe. + Ensure the X11 implementation for GstVaapiWindow::get_geometry() is + thread-safe by default, so that upper layer users don't need to handle + that explicitly. + +2013-07-29 09:28:28 +0200 Holger Kaelberer + + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + window: allow for updating size from current geometry. + Add gst_vaapi_window_reconfigure() interface to force an update of + the GstVaapiWindow "soft" size, based on the current geometry of the + underlying native window. + This can be useful for instance to synchronize the window size when + the user changed it. + Thanks to Fabrice Bellet for rebasing the patch. + [changed interface to gst_vaapi_window_reconfigure()] + Signed-off-by: Gwenole Beauchesne + +2014-07-25 16:53:41 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_drm.c: + * gst-libs/gst/vaapi/gstvaapiwindow_drm.h: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.h: + * gst-libs/gst/vaapi/gstvaapiwindow_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11_priv.h: + window: re-indent all GstVaapiWindow related source code. + +2014-07-25 11:24:39 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + display: add interface to retrieve the display name. + Add gst_vaapi_display_get_display_name() helper function to determine + the name associated with the underlying native display. Note that for + raw DRM backends, the display name is actually the device path. + +2014-07-25 10:55:53 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + display: fix comparison of X11 display names. + Make sure to not only compare display host names, but also the actual + display number. The screen number does not need to be checked at this + time. + +2014-07-25 15:52:06 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapivideobufferpool.c: + vaapidecode: add support for VideoAlignment bufferpool option. + Always add VideoAlignment bufferpool option if the downstream element + expects its own pool to be used but does not offer it through a proper + propose_allocation() implementation for instance, and that the ALLOCATION + query does not expose the availability of the Video Meta API. + This fixes propagation of video buffer stride information to Firefox. + +2014-07-25 15:44:58 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: always prefer native VA surface formats. + Make sure to always prefer native internal formats for the VA surfaces + that get allocated. Also disable "direct-rendering" mode in this case. + This is needed so that to make sure that anything that gets out of the + decoder, or anything that gets into the encoder, is in native format + for the hardware, and thus the driver doesn't need to perform implicit + conversions in there. Interop with SW elements is still available with + fast implementations of VA imaging APIs. + +2014-07-24 11:58:29 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: disallow memory shares across buffers, use a copy. + Forbid shares of GstMemory instances, and rather make copy of it. This + effectively copies the GstMemory structure and enclosed metadata, but + this does not copy the VA surface contents itself. It should though. + This fixes preroll and makes sure to not download garbage for the first + frame when a SW rendering sink is used. + +2014-07-24 06:46:22 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + vaapivideomemory: use an image pool to cache objects. + Use an image pool to hold VA images to be used for downloads/uploads + of contents for the associated surface. + This is an optmization for size. So, instead of creating as many VA + images as there are buffers (then VA surfaces) allocated, we only + maintain a minimal set of live VA images, thus preserving memory + resources. + +2014-07-24 00:14:04 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: forbid R/W mappings if non direct-rendering mode. + Disable read-write mappings if "direct-rendering" is not supported. + Since the ordering of read and write operations is not specified, + this would require to always download the VA surface on _map(), then + commit the temporary VA image back to the VA surface on _unmap(). + Some SW decoding plug-in elements still use R/W mappings though. + https://bugzilla.gnome.org/show_bug.cgi?id=733242 + +2014-07-23 23:49:53 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: minor code clean-ups. + Fix error messages introduced in the previous commit for the _map() + imaplementation. Also use the new get_image_data() helper function + to determine the base pixels data buffer from a GstVaapiImage when + updating the video info structure from it. + +2014-07-23 18:54:13 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + vaapivideomemory: add support for raw pixels mappings. + Allow raw pixels of the whole frame to be mapped read-only. i.e. in + cases where the buffer pool is allocated without VideoMeta API, thus + individual planes cannot be mapped. + This is initial support for Firefox >= 30. + https://bugzilla.gnome.org/show_bug.cgi?id=731886 + +2014-07-03 18:41:11 +0300 Sreerenj Balachandran + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: fix determination of the surface pool format. + While creating the vaapi video allocator, make sure the associated + surface pool has correct format instead of defaulting to NV12 video + format even though there is no direct rendering support. + https://bugzilla.gnome.org/show_bug.cgi?id=732691 + +2014-07-23 18:01:21 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideomemory.c: + vaapivideomemory: fix association of surface to proxy. + Make sure to always update the VA surface pointer whenever the proxy + changes. This used to only work when the VA surface is written to, in + interop with SW element ("upload" feature), and this now fixes cases + when the VA surface is needed for reading, in interop with SW element + ("download" feature). + +2014-07-23 10:23:06 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapivideomemory.c: + plugins: expose I420 format for interop with SW elements. + Always expose I420 format by default when the VA surface could be + mapped for interoperability with non harware accelerated elements. + However, the default behaviour remains the auto-plugging of vaapi + elements, down to the sink. + Side effect: "direct-rendering" mode is also disabled most of the + times as plain memcpy() from uncached speculative write combining + memory is not going to be efficient enough. + +2014-07-22 18:54:29 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapivideomemory.c: + plugins: allow download capability to vaapidecode element. + Fix support for VA surface download capability in vaapidecode element + for GStreamer >= 1.2. This is a fix to supporting libva-vdpau-driver, + but also the libva-intel-driver while performing hardware accelerated + conversions from the native VA surface format (NV12) to the desired + output VA image format. + For instance, this fixes pipelines involving vaapidecode ! xvimagesink. + https://bugzilla.gnome.org/show_bug.cgi?id=733243 + +2014-07-17 01:51:36 +0200 Fabrice Bellet + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + decoder: mpeg4: fix picture decoder return value for skipped frames. + The picture decoder should return GST_VAAPI_DECODER_STATUS_DROP_FRAME + when a frame should be skipped, so the stream processing is not stalled. + https://bugzilla.gnome.org/show_bug.cgi?id=733324 + +2014-07-04 15:13:32 +1000 Jan Schmidt + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + decoder: mpeg2: respect any input PTS provided for a frame. + The timestamp generator in gstvaapidecoder_mpeg2.c always interpolated + frame timestamps within a GOP, even when it's been fed input PTS for + every frame. + That leads to incorrect output timestamps in some situations - for example + live playback where input timestamps have been scaled based on arrival time + from the network and don't exactly match the framerate. + https://bugzilla.gnome.org/show_bug.cgi?id=732719 + +2014-01-22 08:20:59 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiobject.c: + GstVaapiObject: make gst_vaapi_object_new() more robust. + Forbid GstVaapiObject to be created without an associated klass spec. + It is mandatory that the subclass implements an adequate .finalize() + hook, so it shall provide a valid GstVaapiObjectClass. + https://bugzilla.gnome.org/show_bug.cgi?id=722757 + [made non-NULL klass argument to gst_vaapi_object_new() a requirement] + Signed-off-by: Gwenole Beauchesne + +2014-01-21 15:43:57 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiobject.c: + GstVaapiObject: initialize the derived object data with init() hook. + Call the subclass .init() function in gst_vaapi_object_new(), if + needed. The default behaviour is to zero initialize the subclass + object data, then the .init() function can be used to initialize + fields to non-default values, e.g. VA object ids to VA_INVALID_ID. + Also fix the gst_vaapi_object_new() description, which was merely + copied from GstVaapiMiniObject. + https://bugzilla.gnome.org/show_bug.cgi?id=722757 + [changed to always zero initialize the subclass] + Signed-off-by: Gwenole Beauchesne + +2014-06-13 21:45:04 +0100 Lionel Landwerlin + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: make decoder work with playbin + When playbin/decodebin builds the pipeline, it puts decoders and sinks + into different bins and forwards the queries from bins to bins. So in + the initials steps the pipeline is built iteratively by playbin and + looks like this : + [filesrc] + [filesrc] -> [typefind] + [filesrc] -> [typefind] -> [demuxer] + [filesrc] -> [typefind] -> [demuxer] -> [decoder] + At this point the decoder is asked for its SRC caps and it will make a + choice based on what gst_pad_peer_query_caps() returns. The problem is + that the caps returns at that point includes caps features like ANY, + essentially because playbin can plug in additional elements like + videoscale, videoconv or deinterlace. + This patch adds a another call to + gst_vaapi_find_preferred_caps_feature() when the decoder decides its + allocation, to make sure we asks the downstream elements when the + entire pipeline has been built. + https://bugzilla.gnome.org/show_bug.cgi?id=731645 + +2014-06-27 11:57:11 +0100 Simon Farnsworth + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: don't let tmp_rect go out of scope. + A compiler change showed me that tmp_rect went out of scope before + it was used. Move it to the beginning of the function instead. + https://bugzilla.gnome.org/show_bug.cgi?id=726363 + Signed-off-by: Simon Farnsworth + [added guards for GStreamer 0.10 builds] + Signed-off-by: Gwenole Beauchesne + +2014-07-03 22:44:40 +0200 Gwenole Beauchesne + + * AUTHORS: + AUTHORS: updates. + +2014-07-03 22:34:35 +0200 Gwenole Beauchesne + + * README: + README: updates. + Drop references to deprecated plugins (vaapiupload, vaapidownload), + mention that support for GStreamer 0.10 is deprecated, make overview + more descriptive in certain aspects. + +2014-07-03 22:21:39 +0200 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2014-07-03 19:42:02 +0200 Gwenole Beauchesne + + * README: + * configure.ac: + build: mention that support for GStreamer 0.10 is deprecated. + +2014-07-03 17:17:00 +0200 Gwenole Beauchesne + + * configure.ac: + * gst/vaapi/gstvaapidecode.c: + build: fix for GStreamer 0.10. + +2014-07-03 18:01:09 +0200 Gwenole Beauchesne + + * patches/videoparsers/0002-h264parse-fix-build-with-GStreamer-1.2.patch: + * patches/videoparsers/0002-h264parse-fix-build-with-older-GStreamer-1.x-stacks.patch: + * patches/videoparsers/series.frag: + build: fix for GStreamer 1.0.x. + +2014-07-03 13:48:48 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: detect incorrectly paired fields in frames. + When a DPB flush is required, e.g. at a natural and of stream or issued + explicitly through an IDR, try to detect any frame left in the DPB that + is interlaced but does not contain two decoded fields. In that case, mark + the picture as having a single field only. + This avoids a hang while decoding tv_cut.mkv. + +2014-07-03 11:13:33 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: simplify the DPB output process. + Simplify the dpb_output() function to exclusively rely on the frame store + buffer to output, since this is now always provided. Besides, also fix + cases where split fields would not be displayed. + This is a regression from f48b1e0. + +2014-07-01 17:20:44 +0200 Gwenole Beauchesne + + * patches/videoparsers/0003-h264parse-fix-and-optimize-NAL-collection-function.patch: + * patches/videoparsers/0005-h264parse-introduce-new-state-tracking-variables.patch: + * patches/videoparsers/0006-h264parse-improve-conditions-for-skipping-NAL-units.patch: + * patches/videoparsers/0007-h264parse-fix-collection-of-access-units-to-preserve.patch: + * patches/videoparsers/series.frag: + h264parse: drop patches merged upstream. + 0003-h264parse-fix-and-optimize-NAL-collection-function.patch + 0005-h264parse-introduce-new-state-tracking-variables.patch + 0006-h264parse-improve-conditions-for-skipping-NAL-units.patch + 0007-h264parse-fix-collection-of-access-units-to-preserve.patch + +2014-07-01 17:18:08 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: fix memory leak in PPS. + Cope with latest changes from codecparsers/h264. It is now required + to explicitly clear the GstH264PPS structure as it could contain + additional allocations (slice_group_ids). + +2014-07-01 17:13:56 +0200 Gwenole Beauchesne + + * ext/codecparsers: + codecparsers: update to gst-vaapi-branch commit 2d53b69. + c4ace00 h264parse: fix collection of access units to preserve config headers + 0f9f7c9 h264parse: improve conditions for skipping NAL units + 9ffb25c h264parse: introduce new state tracking variables + 64955d3 h264parse: fix and optimize NAL collection function + 13cd2a3 h264: clarifications and documentation fixes + 53e7dd1 h264: fix identification of EOSEQ and EOS NALs + 18f0de0 h264: fix memory leak in GstH264PPS + fdcb54c h264: fix typo in GstH264VUIParams description + fd4dae9 vp8: move up built-in range decoder private data + +2014-06-30 19:01:35 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy_priv.h: + decoder: propagate MVC metadata ("view-id", head of multiview set). + Add new GstVaapiSurfaceProxy flag FFB, which means "first frame in + bundle", and really expresses the first view component of a multi + view coded frame. e.g. in H.264 MVC, the surface proxy has flag FFB + set if VOIdx = 0. + Likewise, new API is exposed to retrieve the associated "view-id". + +2014-06-30 18:46:45 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + decoder: propagate "one-field" flags. + Allow decoders to set the "one-field" attribute when the decoded frame + genuinely has a single field, or if the second field was mis-decoded but + we still want to display the first field. + +2014-06-30 18:34:45 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + decoder: output decoded frames only once. + Make sure to output the decoded picture, and push the associated + GstVideoCodecFrame, only once. The frame fully represents what needs + to be output, included for interlaced streams. Otherwise, the base + GstVideoDecoder class would release the frame twice. + Anyway, the general process is to output decoded frames only when + they are complete. By complete, we mean a full frame was decoded or + both fields of a frame were decoded. + +2014-06-30 16:12:52 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: decode current picture earlier. + Slightly optimize decoding process by submitting the current VA surface + for decoding earlier to the hardware, and perform the reference picture + marking process and DPB update process afterwards. + This is a minor optimization to let the video decode engine kick in work + earlier, thus improving parallel resources utilization. + +2014-06-30 16:09:17 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: fix output of second field when first field is not in DPB. + Fix decoding of interlaced streams where a first field (e.g. B-slice) + was immediately output and the current decoded field is to be paired + with that former frame, which is no longer in DPB. + https://bugzilla.gnome.org/show_bug.cgi?id=701340 + +2014-06-30 11:06:29 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: slightly optimize the process to detect new pictures. + Optimize the process to detect new pictures or start of new access + units by checking if the previous NAL unit was the end of a picture, + or the end of the previous access unit. + +2014-06-13 15:42:53 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: handle access unit ("au") optimization. + Optimize parsing when buffers are supplied with access unit alignment. + This helps determining faster when the end of an access unit is reached. + +2014-06-28 07:25:35 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: fix tracking of DPB size changes. + Add support for MVC streams with multiple SPS and subset SPS headers + emitted regularly, e.g. at around every I-frame. Track the maximum + number of views in ensure_context() and really reset the DPB size to + the expected value, always. i.e. even if it decreased. dpb_reset() + only cares of ensuring the DPB allocation. + +2014-06-27 20:44:24 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: fix the DPB compaction process. + Fix the compaction process when the DPB is cleared for a specific + view, i.e. fix the process of filling in the holes resulting from + removing frame buffers matching the current picture. + +2014-06-27 16:38:03 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: generate new SPS only when codec config changed. + It is not necessary to periodically send SPS or subset SPS headers. + This is up to the upper layer (e.g. transport layer) to decide on + if/how to periodically submit those. For now, only generate new SPS + or subset SPS headers when the codec config changed. + Note: the upper layer could readily determine the config headers + (SPS/PPS) through the gst_vaapi_encoder_h264_get_codec_data() function. + https://bugzilla.gnome.org/show_bug.cgi?id=732083 + Signed-off-by: Gwenole Beauchesne + +2014-06-27 18:43:27 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: track encoder config changes. + Track and report when encoder configuration changed. For now, this covers + resolution, profile/level and bitrate changes. + +2014-06-27 13:15:13 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: add pixel-aspect-ratio to VUI parameters. + Report sample aspect ratio (SAR) as present, and make it match what + we have obtained from the user as pixel-aspect-ratio (PAR). i.e. the + VUI parameter aspect_ratio_info_present_flag now defaults to TRUE. + +2014-06-27 00:49:34 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: fix number of anchor and non-anchor reference pictures. + Set the value of num_anchor_refs_l0, num_anchor_refs_l1, num_non_anchor_refs_l0, + and num_non_anchor_refs_l1 to zero since the inter-view prediction is not yet + supported. + +2014-06-27 10:37:38 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: fix timing_info_present_flag value in subset SPS. + When the seq_parameter_set_data() syntax structure is present in a subset + sequence parameter set and vui_parameters_present_flag is equal to 1, then + timing_info_present_flag shall be equal to 0 (H.7.4.2.1.1). + +2014-06-26 14:39:52 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: add cpbBrNalFactor values for MVC profiles. + +2014-06-26 14:51:32 +0200 Gwenole Beauchesne + + * patches/videoparsers/0003-h264parse-add-initial-support-for-MVC-NAL-units.patch: + h264parse: fix detection of access unit boundaries for MVC. + The gst_h264_parse_collect_nal() function is a misnomer. In reality, + this function is used to determine access unit boundaries, i.e. that + is the key function for alignment=au output format generation. + +2014-06-26 14:49:53 +0200 Gwenole Beauchesne + + * patches/videoparsers/0007-h264parse-fix-collection-of-access-units-to-preserve.patch: + * patches/videoparsers/series.frag: + h264parse: fix collection of access units to preserve config headers. + Always use a GstAdapter when collecting access units (alignment="au") + in either byte-stream or avcC format. This is required to properly + preserve config headers like SPS and PPS when invalid or broken NAL + units are subsequently parsed. + More precisely, this fixes scenario like: + + where we used to reset the output frame buffer when an invalid or + broken NAL is parsed, i.e. SPS and PPS NAL units were lost, thus + preventing the next slice unit to be decoded, should this also + represent any valid data. + https://bugzilla.gnome.org/show_bug.cgi?id=732203 + +2014-06-26 14:48:08 +0200 Gwenole Beauchesne + + * patches/videoparsers/0003-h264parse-add-initial-support-for-MVC-NAL-units.patch: + * patches/videoparsers/0006-h264parse-improve-conditions-for-skipping-NAL-units.patch: + * patches/videoparsers/series.frag: + h264parse: improve conditions for skipping NAL units. + Carefully track cases when skipping broken or invalid NAL units is + necessary. In particular, always allow NAL units to be processed + and let that gst_h264_parse_process_nal() function decide on whether + the current NAL needs to be dropped or not. + This fixes parsing of streams with SEI NAL buffering_period() message + inserted between SPS and PPS, or SPS-Ext NAL following a traditional + SPS NAL unit, among other cases too. + Practical examples from the H.264 AVC conformance suite include + alphaconformanceG, CVSE2_Sony_B, CVSE3_Sony_H, CVSEFDFT3_Sony_E + when parsing in stream-format=byte-stream,alignment=au mode. + https://bugzilla.gnome.org/show_bug.cgi?id=732203 + +2014-06-26 14:45:34 +0200 Gwenole Beauchesne + + * patches/videoparsers/0003-h264parse-add-initial-support-for-MVC-NAL-units.patch: + * patches/videoparsers/0005-h264parse-introduce-new-state-tracking-variables.patch: + * patches/videoparsers/series.frag: + h264parse: introduce new state tracking variables. + Improve parser state tracking by introducing new flags reflecting + it: "got-sps", "got-pps" and "got-slice". This is an addition for + robustness purposes. + Older have_sps and have_pps variables are kept because they have + a different meaning. i.e. they are used for deciding on when to + submit updated caps or not, and rather mean "have new SPS/PPS to + be submitted?" + +2014-06-26 14:39:30 +0200 Gwenole Beauchesne + + * patches/videoparsers/0004-h264parse-default-to-byte-stream-nalu-format-Annex-B.patch: + * patches/videoparsers/series.frag: + h264parse: default to byte-stream/nalu format (Annex B). + Always default to stream-format=byte-stream,alignment=nalu if avcC + format was not detected. This is the natural stream format specified + in the standard (Annex.B): a series of NAL units prefixed with the + usual start code. + https://bugzilla.gnome.org/show_bug.cgi?id=732167 + +2014-06-26 14:37:58 +0200 Gwenole Beauchesne + + * patches/videoparsers/0003-h264parse-fix-and-optimize-NAL-collection-function.patch: + * patches/videoparsers/series.frag: + h264parse: fix and optimize NAL collection function. + Use gst_h264_parser_identify_nalu_unchecked() to identify the next + NAL unit. We don't want to parse the full NAL unit, but only the + header bytes and possibly the first RBSP byte for identifying the + first_mb_in_slice syntax element. + Also fix check for failure when returning from that function. The + only success condition for that is GST_H264_PARSER_OK, so use it. + https://bugzilla.gnome.org/show_bug.cgi?id=732154 + +2014-06-26 11:39:38 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: fix NAL unit types in packed headers. + Submit Prefix NAL headers (nal_unit_type = 14) before every packed + slice header (nal_unit_type = 1 or 5) only for the base view. In non + base views, a Coded Slice Extension NAL header (nal_unit_type = 20) + is required, with an appropriate nal_unit_header_mvc_extension() in + the NAL header bytes. + https://bugzilla.gnome.org/show_bug.cgi?id=732083 + +2014-06-25 22:05:52 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: add missing field in packed Subset SPS header. + Write the missing num_level_values_signalled_minus1 syntax element + into the packed header for subset sequence parameter set. + https://bugzilla.gnome.org/show_bug.cgi?id=732083 + +2014-06-25 22:26:32 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: fix marking of non-reference picture into DPB. + Fix search for a picture in the DPB that has a lower POC value than + the current picture. The dpb_find_lowest_poc() function will return + a picture with the lowest POC in DPB and that is marked as "needed + for output", but an additional check against the actual POC value + of the current picture is needed. + This is a regression from 1c46990. + https://bugzilla.gnome.org/show_bug.cgi?id=732130 + +2014-06-19 17:08:47 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: fix DPB clear when no decoding actually started. + Fix dpb_clear() to clear previous frame buffers only if they actually + exist to begin with. If the decoder bailed out early, e.g. when it + does not support a specific profile, that array of previous frames + might not be allocated beforehand. + +2014-02-06 08:30:10 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.h: + * gst/vaapi/gstvaapidecode.c: + decoder: h264: add support for NALU "alignment" optimization. + We can avoid scanning for start codes again if the bitstream is fed + in NALU chunks. Currently, we always scan for start codes, and keep + track of remaining bits in a GstAdapter, even if, in practice, we + are likely receiving one GstBuffer per NAL unit. i.e. h264parse with + "nal" alignment. + https://bugzilla.gnome.org/show_bug.cgi?id=723284 + [use gst_adapter_available_fast() to determine the top buffer size] + Signed-off-by: Gwenole Beauchesne + +2014-06-18 18:53:51 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: fix caps to report interlace-mode accordingly. + The `vaapipostproc' element could never determine if the H.264 stream + was interlaced, and thus always assumed it to be progressive. Fix the + H.264 decoder to report interlace-mode accordingly, thus allowing the + vaapipostproc element to automatically enable deinterlacing. + +2014-06-19 13:35:23 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: don't crash with dynamic framerate (0/1). + Avoid reaching an assert if dynamic framerates (0/1) are used. One + way to solve this problem is to just stick field_duration to zero. + However, this means that, in presence of interlaced streams, the + very first field will never be displayed if precise presentation + timestamps are honoured. + https://bugzilla.gnome.org/show_bug.cgi?id=729604 + +2014-02-07 12:27:50 +0000 Simon Farnsworth + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: create filter surface pool if it does not exist yet. + ensure_srcpad_buffer_pool() tries to avoid unnecessarily deleting and + recreating filter_pool. Unfortunately, this also meant it didn't create + it if it did not exist. + Fix it to always create the buffer pool if it does not exist. + https://bugzilla.gnome.org/show_bug.cgi?id=723834 + Signed-off-by: Simon Farnsworth + +2013-12-12 10:01:13 +0800 Zhao, Halley + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: reset deinterlacer state when there is a discontinuity. + Reset deinterlacer state, i.e. past reference frames used for advanced + deinterlacing, when there is some discontinuity detected in the course + of processing source buffers. + This fixes support for advanced deinterlacing when a seek occurred. + https://bugzilla.gnome.org/show_bug.cgi?id=720375 + [fixed type of pts_diff variable, fetch previous buffer PTS from the + history buffer, reduce heuristic for detecting discontinuity] + Signed-off-by: Gwenole Beauchesne + +2014-06-18 16:16:34 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: add support for crop regions in VPP mode. + Apply video cropping regions stored in GstVideoCropMeta, or in older + GstVaapiSurfaceProxy representation, to VPP pipelines. In non-VPP modes, + the crop meta are already propagated to the output buffers. + https://bugzilla.gnome.org/show_bug.cgi?id=720730 + +2014-03-14 17:49:40 +0000 Simon Farnsworth + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: make deinterlace-mode behave as expected. + deinterlace-mode didn't behave in the way you'd expect if you have + past experience of the deinterlace element. There were two bugs: + 1. "auto" mode wouldn't deinterlace "interleaved" buffers, only "mixed". + 2. "force" mode wouldn't deinterlace "mixed" buffers flagged as progressive. + Fix these up, and add assertions and error messages to detect cases that + aren't handled. + https://bugzilla.gnome.org/show_bug.cgi?id=726361 + Signed-off-by: Simon Farnsworth + Signed-off-by: Gwenole Beauchesne + +2014-01-15 16:36:29 +0000 Matthieu Bouron + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: do not discard video info props when the format changed. + gst_video_info_set_format() does not preserve video info properties. In + order to keep important information in the caps such as interlace mode, + framerate, pixel aspect ratio, ... we need to manually copy back those + properties after setting the new video format. + https://bugzilla.gnome.org/show_bug.cgi?id=722276 + +2014-02-23 01:43:39 +1100 Matthew Waters + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: plug a memory leak. + It can happen that there is a pool provided that does not advertise + the vappivideometa. We should unref that pool before using our own. + Discovered with vaapidecode ! {glimagesink,cluttersink} + https://bugzilla.gnome.org/show_bug.cgi?id=724957 + [fixed compilation by adding the missing semi-colon] + Signed-off-by: Gwenole Beauchesne + +2014-06-18 13:47:36 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: parse source data until a frame is obtained. + Parse any pending data until a complete frame is obtained. This is a + memory optimization to avoid expansion of video packets stuffed into + the GstAdapter, and a fix to EOS condition to detect there is actually + pending data that needs to be decoded, and subsequently output. + https://bugzilla.gnome.org/show_bug.cgi?id=731831 + +2014-06-05 15:32:29 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: fix multiple slices support in packed headers mode. + Handle packedi slice headers and packed raw data on a per-slice basis, + which is necessary for multi slice encoding. + +2014-06-05 15:30:38 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_objects.c: + * gst-libs/gst/vaapi/gstvaapiencoder_objects.h: + encoder: add infrastructure for per-slice handling of packed headers. + The packed slice header and packed raw data need to be paired with + the submission of VAEncSliceHeaderParameterBuffer. So handle them + on a per-slice basis insted of a per-picture basis. + [removed useless initializer] + Signed-off-by: Gwenole Beauchesne + +2014-03-07 17:40:34 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + vaapisink: fix initialization with "drm" display type. + Force early initializatin of the GstVaapiDisplay so that to make sure + that the sink element display object is presented first to upstream + elements, as it will be correctly featuring the requested display type + by the user. + Otherwise, we might end up in situations where a VA/X11 display is + initialized in vaapidecode, then we try VA/DRM display in vaapisink + (as requested by the "display" property), but this would cause a failure + because we cannot acquire a DRM display that was previously acquired + through another backend (e.g. VA/X11). + +2014-03-07 17:38:14 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginbase.c: + plugins: fix initialization with foreign context. + When a new display is settled through GstElement::set_context() (>= 1.2), + or GstVideoContext::set_context() (<= 1.0), then we shall also update the + associated display type. + +2014-04-28 17:44:03 +0200 Gwenole Beauchesne + + * Makefile.am: + * configure.ac: + * ext/Makefile.am: + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapiparse.c: + * gst/vaapi/gstvaapiparse.h: + * patches/Makefile.am: + * patches/videoparsers/0001-plugins-compile-the-built-in-video-parsers-as-vaapip.patch: + * patches/videoparsers/0002-h264parse-fix-build-with-GStreamer-1.2.patch: + * patches/videoparsers/0003-h264parse-add-initial-support-for-MVC-NAL-units.patch: + * patches/videoparsers/Makefile.am: + * patches/videoparsers/series.frag: + plugins: add built-in video parsers as "vaapiparse" element. + The built-in video parsers elements are built into a single DSO named + libgstvaapi_parse.so. The various video parsers could be accessed as + vaapiparse_CODEC. + For now, this only includes a modified version of h264parse so that to + support H.264 MVC encoded streams. + +2014-06-13 11:36:56 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: cope with new gst_h264_quant_matrix_*() interfaces. + New gst_h264_quant_matrix_*_get_raster_from_zigzag() were renamed + from gst_h264_video_quant_matrix_*_get_raster_from_zigzag(). + +2014-06-13 11:34:07 +0200 Gwenole Beauchesne + + * ext/codecparsers: + codecparsers: update to gst-vaapi-branch commit d6325ac. + 7d8d045 h264parse: use new gst_h264_video_calculate_framerate() + d2f965a h264parse: set field_pic_flag when parsing a slice header + 24c15b8 Import h264parse + a9283e5 bytereader: Use concistant derefence method + a8252c6 bytereader: Use pointer instead of index access + b1bebfc Import GstBitReader and GstByteReader + 2f58788 h264: recognize SVC NAL units + 4335da5 h264: fix SPS copy code for MVC + cf9b6dc h264: fix quantization matrix conversion routine names + b11ce2a h264: add gst_h264_video_calculate_framerate() + 126dc6f add C++ guards for MPEG-4 and VP8 parsers + +2014-06-10 18:30:21 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: factor out DPB pruning for MVC. + Factor out the removal process of unused inter-view only reference + pictures from the DPB, prior to the possible insertion of the current + picture. + Ideally, the compiler could still opt for generating two loops. But + at least, the code is now clearer for maintenance. + +2014-06-10 17:42:58 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: clean-ups. + Fix GST_VAAPI_PICTURE_IS_{INTER_VIEW,ANCHOR}() definitions to use + the base GST_VAAPI_PICTURE_FLAG_IS_SET() macro. + +2014-06-10 16:07:51 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: improve pruning of unused MVC inter-view frames. + Improve process for the removal of pictures from DPB before possible + insertion of the current picture (C.4.4) for H.264 MVC inter-view only + reference components. In particular, handle cases where picture to be + inserted is not the last one of the access unit and if it was already + output and is no longer marked as used for reference, including for + decoding next view components within the same access unit. + +2014-06-03 17:36:38 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: improve DPB bumping process for MVC. + While invoking the DPB bumping process in presence of many views, + it could be necessary to output previous pictures that are ready, + in a whole. i.e. emitting all view components from the very first + view order index zero to the very last one in its original access + unit; and not starting from the view order index of the picture + that caused the DPB bumping process to be invoked. + As a reminder, the maximum number of frames in DPB for MultiView + High profile with more than 2 views is not necessarily a multiple + of the number of views. + This fixes decoding of MVCNV-4.264. + +2014-06-06 17:56:06 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: fix inter-view references array growth. + Let the utility layer handle dynamic growth of the inter-view pictures + array. By definition, setting a new size to the array will effectively + grow the array, but would also fill in the newly created elements with + empty entries (NULL), thus also increasing the reported length, which + is not correct. + +2014-06-03 17:36:38 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: reduce ReferenceFrames entries to the essential set. + When decoding Multiview High profile streams with a large number of + views, it is not possible to make the VAPictureParameterBufferH264. + ReferenceFrames[] array hold the complete DPB, with all possibly + active pictures to be used for inter-view prediction in the current + access unit. + So reduce the scope of the ReferenceFrames[] array to only include + the set of reference pictures that are going to be used for decoding + the current picture. Basically, this is a union of all RefPicListX[] + array, for all slices constituting the decoded picture. + +2014-06-04 19:10:44 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: fix MVC inter-view prediction process. + The inter-view reference components and inter-view only reference + components that are included in the reference picture lists shall + be considered as not being marked as "used for short-term reference" + or "used for long-term reference". This means that reference flags + should all be removed from VAPictureH264.flags. + This fixes decoding of MVCNV-2.264. + +2014-06-04 19:03:18 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: fix detection of profile changes for MVC. + If the VA driver exposes ad-hoc H.264 MVC profiles, then we have to + be careful to detect profiles changes and not reset the underlying + VA context erroneously. In MVC situations, we could indeed get a + profile_idc change for every SPS that gets activated, alternatively + (base-view -> non-base view -> base-view, etc.). + An improved fix would be to characterize the exact profile to use + once and for all when SPS NAL units are parsed. This would also + allow for fallbacks to a base-view decoding only mode. + +2014-06-03 14:30:39 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: drop extraneous definitions. + Re-use definitions from the codecparser headers instead of duplicating + them here again. That covers NALU definitions and slice types. + +2014-04-01 11:26:04 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: remove unnecessary calcualtion of max_pic_order_cnt. + https://bugzilla.gnome.org/show_bug.cgi?id=727418 + +2014-04-01 14:23:56 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: don't allow CABAC with Extended profile. + The H.264 specification does not support CABAC entropy coding for the + Extended profile. + https://bugzilla.gnome.org/show_bug.cgi?id=727418 + +2014-05-07 00:12:39 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: use packed headers mode for MVC encoding. + Exclusively use VA drivers that support raw packed headers for encoding. + i.e. simply submit packed headers Subset SPS and Prefix NAL units. This + provides for better compatibility accross the various VA drivers and HW + generations since no particular API is needed beyond what readily exists. + +2014-05-07 00:09:45 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: add support for packed slice headers. + https://bugzilla.gnome.org/show_bug.cgi?id=722905 + +2014-05-07 00:09:19 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: store subset sps to generate the codec-data + Store the SubsetSPS nal unit which we need for MVC specific + codec_data generation. + +2014-05-07 00:08:33 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: fix MVC pipeline hang while encoding with B-frames. + Since we are encoding each view independently from each other, we + need a higher number of pre-allocated surfaces to be used as the + reconstructed frames. For Stereo High profile encoding, this means + to effectively double the number of frames to be stored in the DPB. + +2014-02-17 15:51:43 +0800 Li Xiaowei + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + * gst-libs/gst/vaapi/gstvaapiutils_h264.c: + * gst/vaapi/gstvaapiencode_h264.c: + encoder: h264: add initial support for H.264 Stereo High profile. + Add initial support for Subset SPS, Prefix NAL and Slice Extension NAL + for non-base-view streams encoding, and the usual SPS, PPS and Slice + NALs for base-view encoding. + The H.264 Stereo High profile encoding mode will be turned on when the + "num-views" parameter is set to 2. The source (raw) YUV frames will be + considered as Left/Right view, alternatively. + Each of the two views has its own frames reordering pool and reference + frames list management system. Inter-view references are not supported + yet, so the views are encoded independently from each other. + Signed-off-by: Li Xiaowei + [limited to Stereo High profile per the definition of MAX_NUM_VIEWS] + Signed-off-by: Gwenole Beauchesne + +2014-02-17 11:10:26 +0800 Li Xiaowei + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: wrap pools for refs and frames reordering. + Create structures to maintain the reference frames list (RefPool) and + frames reordering (ReorderPool) logic. + This is a prerequisite for H.264 MVC support. + Signed-off-by: Li Xiaowei + +2014-02-14 15:33:15 +0800 Li Xiaowei + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: add provisional support for subset SPS headers. + Add provisions to write subset SPS headers to the bitstream in view + to supporting the H.264 MVC specification. + This assumes the libva "staging" branch is in use. + Signed-off-by: Li Xiaowei + +2013-12-18 13:47:32 +0800 Li Xiaowei + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiutils.c: + utils: add H.264 MVC profiles. + Add "MultiView High" and "Stereo High" definitions. + Signed-off-by: Li Xiaowei + [require VA-API >= 0.35.2 for MVC profiles] + Signed-off-by: Gwenole Beauchesne + +2014-06-02 16:25:03 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiutils.c: + utils: only enable VP8 profiles for newer VA-API versions. + VP8 decoding API appeared in VA-API >= 0.35.0. So, disable mappings + involving VP8 codec on earlier versions of the API. + +2014-05-22 10:04:46 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: compute view ids only once per slice. + Optimize lookups of view ids / view order indices by caching the result + of the calculatiosn right into the GstVaapiParserInfoH264 struct. This + terribly simplifies is_new_access_unit() and find_first_field() functions. + +2014-05-21 17:57:00 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: add support for MVC interlaced streams. + Fix support for MVC Stereo High profile streams with interlaced frames. + Also improve the detection logic of the first field. + +2014-05-20 18:08:15 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: add MVC profiles compatibility logic. + Add safe fallbacks for MVC profiles: + - all MultiView High profile streams with 2 views at most can be decoded + with a Stereo High profile compliant decoder ; + - all Stereo High profile streams with only progressive views can be + decoded with a MultiView High profile compliant decoder ; + - all drivers that support slice-level decoding could normally support + MVC profiles when the DPB holds at most 16 frames. + +2014-05-02 14:58:45 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + decoder: h264: add initial support for MVC. + https://bugzilla.gnome.org/show_bug.cgi?id=721772 + +2014-05-01 19:16:09 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: dynamically allocate the DPB. + Dynamically allocate the Decoded Picture Buffer (DPB) and add provisions + for supporting the MVC allocation requirements. + +2014-05-01 19:33:40 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: fix detection of access unit boundaries. + In order to have a stricter conforming implementation, we need to carefully + detect access unit boundaries. Additional operations could be necessary to + perform at those boundaries. + +2013-03-13 11:44:38 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: detect the first VCL NAL unit of a picture for MVC. + Detect the first VCL NAL unit of a picture for MVC, based on the + view_id as per H.7.4.1.2.4. Note that we only need to detect new + view components. + Signed-off-by: Gwenole Beauchesne + +2013-10-31 19:32:55 +0800 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: properly handle Prefix NAL units. + Always cache the previous NAL unit so that we could check whether + there is a Prefix NAL unit immediately preceding the current slice + or IDR NAL unit. In that case, the NAL unit metadata is copied into + the current NAL unit. Otherwise, some default values are inferred, + tentatively. e.g. view_id shall be set to 0 and inter_view_flag to 1. + [infer default values for slice if previous NAL was not a Prefix] + Signed-off-by: Gwenole Beauchesne + +2013-02-28 15:59:55 +0800 Xiaowei Li + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: add support for MVC base views. + Allow decoding for base views of MVC encoded streams. For now, just skip + the slice extension and prefix NAL units, and skip non-base view frames. + Signed-off-by: Xiaowei Li + [fixed memory leak, improved check for MVC NAL units] + Signed-off-by: Gwenole Beauchesne + +2014-05-04 14:49:28 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: simplify storage of decoded picture into DPB. + Factor out process by which the decoded picture with the lowest POC + is found, and possibly output. Likewise, the storage and marking of + a reference decoded, or non-reference decoded picture, into the DPB + could also be simplified as they mostly share the same operations. + +2014-05-02 22:40:16 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: minor clean-ups. + Make init_picture_ref_lists() more consistent with other functions + related to the reference marking process by supplying the current + picture as argument. + +2014-05-20 11:36:40 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + display: add utility function to query VA driver name. + Add gst_vaapi_display_get_vendor_string() helper function to query + the underlying VA driver name. The display object owns the resulting + string, so it shall not be deallocated. + That function is thread-safe. It could be used for debugging purposes, + for instance. + +2014-03-07 14:50:14 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplaycache.c: + * gst-libs/gst/vaapi/gstvaapidisplaycache.h: + display: make cache maintenance really MT-safe. + Make sure to initialize one GstVaapiDisplay at a time, even in threaded + environments. This makes sure the display cache is also consistent + during the whole display creation process. In the former implementation, + there were risks that display cache got updated in another thread. + +2014-05-03 15:56:51 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicontext.c: + context: allow dynamic growth of VA surfaces pool. + Add support for dynamic growth of the VA surfaces pool. For decoding, + this implies the recreation of the underlying VA context, as per the + requirement from VA-API. Besides, only increases are supported, not + shrinks. + +2014-05-03 15:47:53 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicontext.c: + context: reset VA context if VA surfaces set changed. + It is a requirement from VA-API specification that the VA context got + from vaCreateContext(), for decoding purposes, binds the supplied set + of VA surfaces. This means that if the set of VA surfaces is to be + changed for the current decode session, then the VA context needs to + be recreated with the new set of VA surfaces. + +2014-05-12 19:23:04 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: fix assignment of LongTermFrameIdx. + Complement fix committed as e95a42e. + The H.264 AVC standard has to say: if the field is part of a reference + frame or a complementary reference field pair, and the other field of + the same reference frame or complementary reference field pair is also + marked as "used for long-term reference", the reference frame or + complementary reference field pair is also marked as "used for long-term + reference" and assigned LongTermFrameIdx equal to long_term_frame_idx. + This fixes decoding of MR9_BT_B in strict mode. + https://bugs.freedesktop.org/show_bug.cgi?id=64624 + https://bugzilla.gnome.org/show_bug.cgi?id=724518 + +2014-05-10 06:23:29 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + decoder: h264: properly support grayscale formats. + Request the correct chroma format for decoding grayscale streams. + i.e. make lookups of the VA chroma format more generic, thus possibly + supporting more formats in the future. + This means that, if a VA driver doesn't support grayscale formats, + it is now going to fail. We cannot safely assume that maybe grayscale + was implemented on top of some YUV 4:2:0 with the chroma components + all set to 0x80. + +2014-02-06 11:14:09 +0000 Simon Farnsworth + + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapifilter.h: + * tests/test-filter.c: + build: fix source file modes. + A few source files are marked executable in error - fix them + https://bugzilla.gnome.org/show_bug.cgi?id=723748 + Signed-off-by: Simon Farnsworth + +2014-04-29 13:22:47 +0300 Sreerenj Balachandran + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidecoder_vp8.c: + * gst/vaapi/gstvaapidecode.c: + build: fix conditional compilation of VP8 decoder. + https://bugzilla.gnome.org/show_bug.cgi?id=729170 + [added check for VASliceParameterBufferBase fields] + Signed-off-by: Gwenole Beauchesne + +2014-04-27 08:55:24 +0200 Gwenole Beauchesne + + * gst-libs/gst/codecparsers/Makefile.am: + build: fix make dist for codecparsers. + +2014-04-28 09:42:13 +0200 Gwenole Beauchesne + + * ext/codecparsers: + codecparsers: update to gst-vaapi-branch commit eaa3f7e. + h264: fix parsing of slice groups for map type = 2 + +2014-04-26 22:35:49 +0200 Gwenole Beauchesne + + * ext/codecparsers: + codecparsers: update to gst-vaapi branch commit f44edfc. + h264: fix derivation of default scaling lists + +2013-05-24 19:00:54 +0800 Cong Zhong + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: fix long-term reference picture marking process. + Fix reference picture marking process with memory_management_control_op + set to 3 and 6, i.e. assign LongTermFrameIdx to a short-term reference + picture, or the current picture. + This fixes decoding of FRExt_MMCO4_Sony_B. + https://bugs.freedesktop.org/show_bug.cgi?id=64624 + https://bugzilla.gnome.org/show_bug.cgi?id=724518 + [squashed, edited to use GST_VAAPI_PICTURE_IS_COMPLETE() macro] + Signed-off-by: Gwenole Beauchesne + +2014-04-26 20:21:46 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: fix initialization of RefPicLists for multiple slices. + The initialization of reference picture lists (8.2.4.2) applies to all + slices. So, the RefPicList0/1 lists need to be constructed prior to + each slice submission to the HW decoder. + This fixes decoding of video sequences where frames are encoded with + multiple slices of different types, e.g. 4 slices in this order I, P, + I, and P. More precisely, CABAST3_Sony_E and CABASTBR3_Sony_B. + https://bugzilla.gnome.org/show_bug.cgi?id=724518 + +2013-06-04 15:01:46 +0800 Zhong Cong + + * ext/codecparsers: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: skip SPS extension and auxiliary slice NALs. + When NAL units of type 13 (SPS extension) or type 19 (auxiliary slice) + are present in a video, decoders shall perform the (optional) decoding + process specified for these NAL units or shall ignore them (7.4.1). + Implement option 2 (skip) for now, as alpha composition is not + supported yet during the decoding process. + This fixes decoding of the primary coded video in alphaconformanceG. + https://bugzilla.gnome.org/show_bug.cgi?id=703928 + https://bugzilla.gnome.org/show_bug.cgi?id=728869 + https://bugzilla.gnome.org/show_bug.cgi?id=724518 + [skip NAL units earlier, i.e. at parsing time] + Signed-off-by: Gwenole Beauchesne + +2013-03-07 11:32:20 +0800 Li Xiaowei + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: fix slice data bit offset with MVC NAL units. + When MVC slice NAL units (coded slice extension and prefix NAL) are + present, the number of NAL header bytes is 3, not 1 as usual. + Signed-off-by: Li Xiaowei + Signed-off-by: Gwenole Beauchesne + +2014-04-25 19:11:03 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: fix activation of picture and sequence parameters. + At the time the first VCL NAL unit of a primary coded picture is found, + and if that NAL unit was parsed to be an SPS or PPS, then the entries + in the parser may have been overriden. This means that, when the picture + is to be decoded, slice_hdr->pps could point to an invalid (the next) + PPS entry. + So, one way to solve this problem is to not use the parser PPS and + SPS info but rather maintain our own activation chain in the decoder. + https://bugzilla.gnome.org/show_bug.cgi?id=724519 + https://bugzilla.gnome.org/show_bug.cgi?id=724518 + +2014-04-25 16:24:01 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: retain SEI messages until the end of frame. + Retain the SEI messages that were parsed from the access unit until we + have completely decoded the current frame. This is done so that we can + peek at that data whenever necessary during decoding. e.g. for exposing + 3D stereoscopic information at a later stage. + +2014-04-25 14:23:11 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: add support for grayscale encoded clips. + Fix support for grayscale encoded video clips, and possibly others if + the underlying driver supports the non-YUV 4:2:0 formats. i.e. defer + the decision that a surface with the desired chroma format is not + supported to the actual VA driver implementation. + https://bugzilla.gnome.org/show_bug.cgi?id=728144 + +2014-04-25 14:16:24 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vp8.c: + decoder: default to YUV 4:2:0 VA surfaces. + Cope with context changes to support non-YUV 4:2:0 VA surfaces. Still, + make sure all codecs use YUV 4:2:0 output format for now, by default. + +2014-04-25 13:57:02 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + decoder: re-indent GstVaapiDecoder base object. + +2014-04-25 13:47:53 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + encoder: derive chroma type from video format. + Cope with previous VA context change to derive the correct surface chroma + type from the input video format. + +2014-04-25 13:45:31 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + context: add support for non-YUV 4:2:0 formats. + Don't force allocation of VA surfaces in YUV 4:2:0 format. Rather, allow + for the upper layer to specify the desired chroma type. If the chroma + type field is not set (or yields zero), then YUV 4:2:0 format is used + by default. + +2014-04-22 19:53:50 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_vp8.c: + vp8: fix per-segment deblocking filter level in relative mode. + Fix possible bug when a per-segment deblocking filter level value + needs to be set in non-absolute mode, i.e. when the loop filter update + value is negative in delta mode. + Also clamp the resulting filter level value to 0..63 range. + +2014-04-22 17:25:15 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_vp8.c: + vp8: fix check for disabling the loop filter (again). + Improve condition to disable the loop filter. The previous heuristic + used to check all filter levels, for all segments. It turns out that + only the base filter_level value defined in the frame header needs + to be checked. + This fixes 00-comprehensive-013. + +2014-04-21 18:02:21 +0200 Gwenole Beauchesne + + * gst-libs/gst/codecparsers/Makefile.am: + * gst/vaapi/Makefile.am: + build: fix make dist with certain conditionals not met. + Fix generation of source tarballs when certain conditionals are not + met. e.g. always include all buildable codecparsers sources in the + distribution tarball, fix plug-in element sources set to include X11 + and encoder bits. + +2014-04-21 17:34:59 +0200 Gwenole Beauchesne + + * ext/Makefile.am: + build: add missing files for GStreamer 0.10. + Add missing GstVideoEncoder implementation files to fix build with ancient + GStreamer 0.10 stack. + https://bugzilla.gnome.org/show_bug.cgi?id=723964 + +2014-04-19 10:17:20 +0200 Gwenole Beauchesne + + * ext/Makefile.am: + build: add missing files for VP8 bitstream parser. + Fix make dist for building the VP8 bitstream parser. + +2014-04-21 17:49:38 +0200 Gwenole Beauchesne + + * configure.ac: + * ext/libvpx/Makefile.am: + * gst-libs/gst/codecparsers/Makefile.am: + vp8: allow compilation without the built-in libvpx. + The built-in libvpx serves multiple purposes, among which the most + important ones could be: track the most up-to-date, and optimized, + range decoder; allow for future hybrid implementations (non-VLD); + and have a completely independent range decoder implementation. + +2014-04-21 17:28:27 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_vp8.c: + vp8: propagate PTS from demux frame. + gst_adapter_prev_pts() is forbidden within libgstvaapi. Besides, the demuxer + or parser would already have determined the PTS from a previous stage. + +2014-04-19 07:49:30 +0200 Gwenole Beauchesne + + * Makefile.am: + * debian.upstream/libgstvaapi.install.in: + * ext/libvpx/Makefile.am: + * ext/libvpx/sources.frag: + * gst-libs/gst/codecparsers/Makefile.am: + vp8: fix compilation with built-in libvpx. + Apply correct patch from fd.o #722760 to fix several issues: update the + license terms to LGPLv2.1+, fix dependencies to built-in libvpx and fix + make dist. + +2014-02-13 21:17:23 +0100 Gwenole Beauchesne + + * .gitmodules: + * autogen.sh: + * configure.ac: + * ext/Makefile.am: + * ext/libvpx/Makefile.am: + * ext/libvpx/gstlibvpx.c: + * ext/libvpx/gstlibvpx.h: + * ext/libvpx/libgstcodecparsers_vpx.vers: + * ext/libvpx/sources.frag: + * ext/libvpx/upstream: + * gst-libs/gst/codecparsers/Makefile.am: + * gst-libs/gst/codecparsers/gstvaapilibvpx.c: + vp8: use range decoder from libvpx. + Add libvpx submodule that tracks the upstream version 1.3.0. This is + needed to build a libgstcodecparsers_vpx.so library with all symbols + placed into the GSTREAMER namespace. + +2014-04-04 19:17:17 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_vp8.c: + vp8: fix check for disabling the loop filter. + +2013-12-27 07:18:24 +0800 Zhao, Halley + + * configure.ac: + * ext/Makefile.am: + * gst-libs/gst/codecparsers/Makefile.am: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapicodec_objects.c: + * gst-libs/gst/vaapi/gstvaapicodec_objects.h: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + * gst-libs/gst/vaapi/gstvaapidecoder_vp8.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vp8.h: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + * gst/vaapi/gstvaapidecode.c: + Add initial VP8 decoder. + https://bugzilla.gnome.org/show_bug.cgi?id=722761 + [complete overhaul, fixed support for resolution changes] + Signed-off-by: Gwenole Beauchesne + +2014-03-21 15:15:37 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: cope with new gst_h264_parser_parse_sei() interface. + The gst_h264_parse_parse_sei() function now returns an array of SEI + messages, instead of a single SEI message. Reason: it is allowed to + have several SEI messages packed into a single SEI NAL unit, instead + of multiple NAL units. + +2014-04-18 19:36:16 +0200 Gwenole Beauchesne + + * ext/codecparsers: + codecparsers: update to gst-vaapi-branch commit a454f86. + b2eb5f6 vp8: rename dboolhuff symbols + b74a881 vp8: add GStreamer native utilities + 2940ac6 add VP8 bitstream parser + +2014-04-18 19:16:56 +0200 Gwenole Beauchesne + + * ext/codecparsers: + codecparsers: update to gst-vaapi-branch commit d459bc5. + d459bc5 h264: set framerate even for interlaced videos + c78b82c h264: add support for Recovery Point SEI message + 7693bac h264: add support for Frame Packing Arrangement SEI message + 31fafa7 h264: add support for Stereo Video Information SEI message + 8b113a6 h264: parse seq_parameter_set_mvc_extension() + 040f9b8 h264: parse MVC syntax elements + cc18ef3 h264: add nal_reader_skip_long() helper + 7e76a48 h264: fix slice_header() parsing for MVC + caf46d8 h264: add gst_h264_parse_nalu_header() helper + f75074e h264: add gst_h264_parse_sps_data() helper + 798c397 h264: clean-up gst_h264_parser_parse_sei_message() + 4e36737 h264: fix skipping of unsupported SEI messages + 5300766 h264: fix SEI buffering_period() parsing + +2014-03-21 15:09:14 +0100 Gwenole Beauchesne + + * ext/codecparsers: + * gst-libs/gst/codecparsers/Makefile.am: + codecparsers: update to gst-vaapi-branch commit 8fadf40. + 8fadf40 h264: Fix multiple SEI messages in one SEI RBSP parsing. + 644825f h265: remove trailling 0x00 bytes as the spec doesn't allow them + 95f9f0f h264: remove trailling 0x00 bytes as the spec doesn't allow them + 766007b h265: Initialize pointer correctly that is never assigned but freed in error cases + 8ec5816 h265: Fix segfault when parsing HRD parameter + 5b1730f h265: Fix segfault when parsing VPS + 983b7f7 h265: prevent to overrun chroma_weight_l0_flag + 7ba641d h265: Fix debug output + d9f9f9b h264: not all startcodes should have 3-byte 0 prefix + +2014-02-04 18:35:28 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: fix robustness patch for bytestream format. + Fix parser and decoder state to sync at the right locations. This is + because we could reset the parser state, while the decoder state was + not copied yet, e.g. when parsing several NAL units from multiple frames + whereas the current frame was not decoded yet. + This is a regression brought in by commit 6fe5496. + +2014-02-18 06:56:51 +0100 Gwenole Beauchesne + + * configure.ac: + * pkgconfig/Makefile.am: + * pkgconfig/gstreamer-vaapi-drm.pc.in: + * pkgconfig/gstreamer-vaapi-glx.pc.in: + * pkgconfig/gstreamer-vaapi-wayland.pc.in: + * pkgconfig/gstreamer-vaapi-x11.pc.in: + build: fix pkgconfig file names (again). + It turns out it is more convenient to have only pkgconfig files named + after the installed GStreamer API version (1.0) instead of using all + possible subsequent names from that (1.0, 1.2, 1.4). i.e. they conflict + altogether anyway, so align pkgconfig file names to that. + +2014-02-07 09:43:51 +0100 Gwenole Beauchesne + + * debian.upstream/libgstvaapi-dev.install.in: + * gst-libs/gst/vaapi/Makefile.am: + * pkgconfig/gstreamer-vaapi.pc.in: + build: fix packaging for GStreamer 1.2. + Fix gstreamer-vaapi includedir for GStreamer 1.2 setups. i.e. use + the pkgconfig version (1.0) instead of the intended API version (1.2). + libgstvaapi1.0-dev and libgstvaapi1.2-dev packages will now conflict, + as would core GStreamer 1.0 and GStreamer 1.2 dev packages anyway. + +2014-01-24 11:27:30 +0100 Gwenole Beauchesne + + * configure.ac: + Bump version for development. + +2014-01-24 10:55:39 +0100 Gwenole Beauchesne + + * debian.upstream/control.in: + debian: fix trailing whitespace in description. + +2014-01-23 23:24:55 +0100 Gwenole Beauchesne + + * debian.upstream/control.in: + * debian.upstream/copyright: + debian: fix package description. + Try to improve package description for the compiled plug-in elements + available in there. e.g. only display vaapidownload and vaapiupload + for GStreamer 0.10 builds, display vaapiencode_* elements when VA + encoding is enabled, etc. + Also increase the copyright notice date. + +2014-01-23 22:47:19 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + build: fix warnings on 64-bit platforms. + +2014-01-23 22:44:09 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapiutils.c: + build: fix for older versions of VA-API (< 0.34.0). + Fix build with older versions of VA-API (< 0.34.0), or versions without + good enough headers for encoding support for instance. + +2014-01-23 19:36:14 +0100 Gwenole Beauchesne + + * NEWS: + * configure.ac: + 0.5.8. + +2014-01-23 19:32:28 +0100 Gwenole Beauchesne + + * README: + README: updates. + VA-API up to 0.34.0 is actually supported. Mention new video encoding + support. Update copyright years, list of supported Intel HD Graphics + hardware. + +2014-01-23 19:18:13 +0100 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2014-01-20 14:16:56 +0100 Gwenole Beauchesne + + * tests/test-filter.c: + tests: test-filter: fix "deinterlace" option parse. + Default to GST_VAAPI_DEINTERLACE_METHOD_NONE if no "deinterlace" option + string was provided, i.e. if it remained set to NULL. + +2014-01-23 18:41:24 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiutils_core.c: + * gst-libs/gst/vaapi/gstvaapiutils_core.h: + libs: factor out usages of vaGetConfigAttributes(). + Add gst_vaapi_get_config_attribute() helper function that takes a + GstVaapiDisplay and the rest of the arguments with VA types. The aim + is to have thread-safe VA helpers by default. + +2014-01-23 17:41:02 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + * gst-libs/gst/vaapi/gstvaapiutils_glx.h: + * gst-libs/gst/vaapi/gstvaapiutils_h264.c: + * gst-libs/gst/vaapi/gstvaapiutils_h264.h: + * gst-libs/gst/vaapi/gstvaapiutils_h264_priv.h: + * gst-libs/gst/vaapi/gstvaapiutils_mpeg2.h: + * gst-libs/gst/vaapi/gstvaapiutils_mpeg2_priv.h: + * gst-libs/gst/vaapi/gstvaapiutils_x11.c: + * gst-libs/gst/vaapi/gstvaapiutils_x11.h: + libs: re-indent all source code related to VA utilities. + +2014-01-23 17:06:08 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/libgstvaapi_priv_check.h: + libs: add missing file (libgstvaapi_priv_check.h). + +2014-01-23 15:13:06 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + encoder: notify the encoder of the submitted packed headers. + Make sure to configure the encoder with the set of packed headers we + intend to generate and submit. i.e. make selection of packed headers + to submit more robust. + +2014-01-23 15:10:11 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + encoder: fix and factor out check for supported rate-control modes. + Cache the first compatible GstVaapiProfile found if the encoder is not + configured yet. Next, factor out the code to check for the supported + rate-control modes by moving out vaGetConfigAttributes() to a separate + function, while also making sure that the attribute type is actually + supported by the encoder. + Also fix the default set of supported rate control modes to not the + "none" variant. It's totally useless to expose it at this point. + +2014-01-23 14:01:33 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapiencoder.c: + context: move rate-control mode to encoder specific config. + Move usage-specific config out of the common GstVaapiContextInfo. + Create a specialized config for encoding and move rate-control mode + to there. + +2014-01-23 13:30:41 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.c: + context: introduce concept of usage. + Introduce GstVaapiContextUsage so that to explicitly determine the + usage of a VA context. This is useful in view to simplifying the + creation of VA context for VPP too. + +2014-01-23 11:44:12 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicontext.c: + context: fix get_attribute() value result. + Unknown attributes, or attributes that are not supported for the given + profile/entrypoint pair have a return value of VA_ATTRIB_NOT_SUPPORTED. + So, return failure in this case. + +2014-01-23 10:59:20 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapicontext_overlay.c: + * gst-libs/gst/vaapi/gstvaapicontext_overlay.h: + * gst-libs/gst/vaapi/gstvaapisurface.c: + context: move overlay composition to separate files. + Move GstVideoOverlayComposition handling to separate source files. + This helps keeing GstVaapiContext core implementation to the bare + minimal, i.e. simpy helpers to create a VA context and handle pool + of associated VA surfaces. + +2014-01-23 09:41:07 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.c: + context: clean-ups. Strip down APIs. + Improve documentation and debug messages. Clean-up APIs, i.e. strip + them down to the minimal set of interfaces. They are private, so no + need expose getters for instance. + +2014-01-23 09:27:38 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + context: re-indent all GstVaapiContext related source code. + +2014-01-23 10:20:40 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidecoder_unit.h: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplaycache.h: + * gst-libs/gst/vaapi/gstvaapiminiobject.h: + * gst-libs/gst/vaapi/gstvaapiobject_priv.h: + * gst-libs/gst/vaapi/gstvaapipixmap_priv.h: + * gst-libs/gst/vaapi/gstvaapiutils.h: + * gst-libs/gst/vaapi/gstvaapiutils_glx.h: + * gst-libs/gst/vaapi/gstvaapiutils_h264_priv.h: + * gst-libs/gst/vaapi/gstvaapiutils_mpeg2_priv.h: + * gst-libs/gst/vaapi/gstvaapiutils_x11.h: + * gst-libs/gst/vaapi/gstvaapiwindow_priv.h: + libs: check that private headers remain private. + Make sure that libgstvaapi private headers remain internally used to + build libgstvaapi libraries only. All header dependencies were reviewed + and checks for IN_LIBGSTVAAPI definition were added accordingly. + Also rename GST_VAAPI_CORE definition to IN_LIBGSTVAAPI_CORE to keep + consistency. + +2014-01-22 19:04:58 +0100 Gwenole Beauchesne + + * configure.ac: + Bump library major version. + Bump the library major version due to API/ABI changes that occurred in + the imaging API. In particular, GstVaapiDisplay interfaces no longer + expose any GstCaps but provide GArray based ones e.g. to determine the + set of supported decode/encode profiles. + +2014-01-22 18:54:14 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/glibcompat.h: + * gst-libs/gst/vaapi/gstvaapicodec_objects.c: + * gst-libs/gst/vaapi/gstvaapicodec_objects.h: + * gst-libs/gst/vaapi/gstvaapicodedbufferpool.c: + * gst-libs/gst/vaapi/gstvaapicodedbufferpool.h: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.h: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2_priv.h: + * gst-libs/gst/vaapi/gstvaapiencoder_objects.c: + * gst-libs/gst/vaapi/gstvaapiencoder_objects.h: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapipixmap_x11.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapitypes.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils_h264.c: + * gst-libs/gst/vaapi/gstvaapiutils_h264.h: + * gst-libs/gst/vaapi/gstvaapiutils_h264_priv.h: + * gst-libs/gst/vaapi/gstvaapiutils_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiutils_mpeg2.h: + * gst-libs/gst/vaapi/gstvaapiutils_mpeg2_priv.h: + * gst-libs/gst/vaapi/gstvaapivalue.c: + * gst-libs/gst/vaapi/gstvaapivalue.h: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode.h: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h264.h: + * gst/vaapi/gstvaapiencode_mpeg2.c: + * gst/vaapi/gstvaapiencode_mpeg2.h: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + * gst/vaapi/gstvaapivideometa_texture.c: + * tests/simple-decoder.c: + legal: update copyright notice dates. + +2014-01-22 18:49:20 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.h: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2_priv.h: + * gst-libs/gst/vaapi/gstvaapiencoder_objects.c: + * gst-libs/gst/vaapi/gstvaapiencoder_objects.h: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode.h: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h264.h: + * gst/vaapi/gstvaapiencode_mpeg2.c: + * gst/vaapi/gstvaapiencode_mpeg2.h: + legal: add per-file authorship information. + +2014-01-22 18:11:26 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + decoder: fix video codec frame number in standalone mode. + Set a valid GstVideoCodecFrame.system_frame_number when decoding a + stream in standalone mode. While we are at it, improve the debugging + messages to also include that frame number. + +2014-01-17 16:56:53 +0800 Wind Yuan + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + decoder: fix crash on invalid pointer for GST_DEBUG(). + When decoding failed, or that the frame was dropped, the associated + surface proxy is not guaranteed to be present. Thus, the GST_DEBUG() + message needs to check whether the proxy is actually present or not. + https://bugzilla.gnome.org/show_bug.cgi?id=722403 + [fixed gst_vaapi_surface_proxy_get_surface_id() to return VA_INVALID_ID] + Signed-off-by: Gwenole Beauchesne + +2014-01-22 17:07:24 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: disable NAL HRD parameters for now. + Don't emit NAL HRD parameters for now in the SPS headers because the + SEI buffering_period() and picture_timing() messages are not handled + yet. Some additional changes are necessary to get it right. + https://bugzilla.gnome.org/show_bug.cgi?id=722734 + +2014-01-21 19:04:41 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + * gst-libs/gst/vaapi/gstvaapiutils_h264.c: + * gst-libs/gst/vaapi/gstvaapiutils_h264_priv.h: + encoder: h264: fix default CPB buffer size. + Fix default CPB buffer size to something more reasonable (1500 ms) + and that still fits the level limits. This is a non configurable + property for now. The initial CPB removal delay is also fixed to + 750 ms. + https://bugzilla.gnome.org/show_bug.cgi?id=722087 + +2014-01-22 14:43:24 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: fix bitrate encoding for HRD conformance. + Round down the calculated, or supplied, bitrate (kbps) into a multiple + of the HRD bitrate scale factor. Use a bitrate scale factor of 64 so + that to have less losses in precision. Likewise, don't round up because + that could be a strict constraint imposed by the user. + +2014-01-22 11:25:13 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: fix level lookup constraints wrt. bitrate. + Fix the level calculation involving bitrate limits. Since we are + targetting NAL HRD conformance, the check against MaxBR from the + Table A-1 limits shall involve cpbBrNalFactor depending on the + active profile. + +2014-01-21 18:01:20 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: submit sequence parameter only once. + Submit sequence parameter buffers only once, or when the bitstream + was reconfigured in a way that requires such. Always submit packed + sequence parameter buffers at I-frame period, if the VA driver needs + those. + https://bugzilla.gnome.org/show_bug.cgi?id=722737 + +2014-01-21 18:35:17 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + encoder: h264: only submit packed headers when required. + Make sure to submit the packed headers only if the underlying VA driver + requires those. Currently, only handle packed sequence and picture + headers. + https://bugzilla.gnome.org/show_bug.cgi?id=722737 + +2014-01-21 17:35:24 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: fix ip_period value in sequence parameter. + The VAEncSequenceParameterBuffer.ip_period value reprents the distance + between the I-frame and the next P-frame. So, this also accounts for + any additional B-frame in the middle of it. + This fixes rate control heuristics for certain VA drivers. + https://bugzilla.gnome.org/show_bug.cgi?id=722735 + +2014-01-21 17:04:40 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: fix level when bitrate is automatically computed. + Fix level characterisation when the bitrate is automatically computed + from the active coding tools. i.e. ensure the bitrate once the profile + is completely characterized but before the level calculation process. + +2014-01-21 16:05:22 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: clean-ups. + Document and rename a few functions here and there. Drop code that + caps num_bframes variable in reset_properties() since they shall + have been checked beforehand, during properties initialization. + +2014-01-21 15:28:34 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: clean-up bitwriter related utilities. + Clean-up GstBitWriter related utility functions and simplify notations. + While we are at it, also make bitstream writing more robust should an + overflow occur. We could later optimize for writing headers capped to + their maximum possible size by using the _unchecked() helper variants. + +2014-01-21 15:23:01 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_priv.h: + encoder: h264: completely remove private headers. + Drop private header since it was originally used to expose internals + to the plugin element. The proper interface is now the properties API, + thus rendering private headers totally obsolete. + +2014-01-15 15:54:32 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: fix PPS header packing with profile < high. + Fix PPS header packing when profile is below High since 8x8 transform + mode and scaling lists are High Profile features. + +2014-01-15 15:46:19 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: always emit VUI parameters for framerate. + Always emit VUI parameters for timing_info, which includes framerate + information. + +2014-01-15 15:10:48 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: really fix frame cropping rectangle calculation. + Make frame cropping rectangle calculation future proof, i.e. exactly + follow the specification (7-18) to (7-21), and subsampling definitions + from Table 6-1. + https://bugzilla.gnome.org/show_bug.cgi?id=722089 + https://bugzilla.gnome.org/show_bug.cgi?id=722238 + +2014-01-15 12:09:14 +0100 Holger Kaelberer + + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + vaapisink: set csc render flags from sinkpad caps. + This maps GstVideoColorimetry information in vaapisink's sinkpad caps + to GST_VAAPI_COLOR_STANDARD_* flags, if per-buffer information was not + available. + https://bugzilla.gnome.org/show_bug.cgi?id=722255 + [factored out code, added SMPTE240M, handle per-buffer flags] + Signed-off-by: Gwenole Beauchesne + +2012-03-28 15:05:26 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst/vaapi/gstvaapipostproc.c: + surface: rework render flags. + Pack render flags per category and provide more flags into the color + standard category. In particular, cover for SMPTE-240M. + +2013-12-13 04:14:41 +0800 Zhao, Halley + + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + vaapipostproc: add support for colorbalance filters. + Add support for hue, saturation, brightness and constrat adjustments. + Also fix cap info local copy to match the really expected cap subtype + of interest. + https://bugzilla.gnome.org/show_bug.cgi?id=720376 + Signed-off-by: Gwenole Beauchesne + +2013-12-12 08:38:12 +0800 Zhao, Halley + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: fix support for "sharpen" filter. + Fix copy/paste error when submitting the "sharpen" value to the + GstVaapiFilter instance. + https://bugzilla.gnome.org/show_bug.cgi?id=720375 + Signed-off-by: Gwenole Beauchesne + +2013-12-20 12:05:42 +0000 Lionel Landwerlin + + * configure.ac: + * pkgconfig/gstreamer-vaapi-drm.pc.in: + * pkgconfig/gstreamer-vaapi-glx.pc.in: + * pkgconfig/gstreamer-vaapi-wayland.pc.in: + * pkgconfig/gstreamer-vaapi-x11.pc.in: + * pkgconfig/gstreamer-vaapi.pc.in: + pkgconfig: plugin dir should use PKG version not API version. + Fix the pluginsdir and includedir variables in the generated pkgconfig + (.pc) files. The location needs to be built with the PKG version in + mind instead of the API version. + While we are at it, also fix the PKG version for GStreamer >= 1.3. + https://bugzilla.gnome.org/show_bug.cgi?id=720820 + [additional fixes for includedir and pkg requirements] + Signed-off-by: Gwenole Beauchesne + +2014-01-15 10:05:45 +0100 Holger Kaelberer + + * gst/vaapi/gstvaapisink.c: + vaapisink: fix display initialization in GstVideoOverlay implementation. + When gst_vaapisink_video_overlay_set_window_handle() is called early, + before the pipeline has been set to PLAYING, the display has not yet + been initialized and _PLUGIN_BASE_DISPLAY_TYPE() is not yet + up-to-date. For this reason the foreign XID is not attached. + Now _ensure_display() is called earlier. + https://bugzilla.gnome.org/show_bug.cgi?id=722244 + Signed-off-by: Gwenole Beauchesne + +2013-10-09 13:47:54 +0300 Sreerenj Balachandran + + * gst/vaapi/gstvaapisink.c: + vaapisink: expose the raw video formats in static caps template. + Expose all raw video formats in the static caps template since the + vaapisink is supporting raw data. We will get the exact set of formats + supported by the driver dynamically through the _get_caps() routine. + https://bugzilla.gnome.org/show_bug.cgi?id=703271 + https://bugzilla.gnome.org/show_bug.cgi?id=720737 + Signed-off-by: Gwenole Beauchesne + +2013-12-11 18:08:26 +0000 Matthieu Bouron + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: query downstream caps features like GLTextureUploadMeta. + Fix vaapidecode to correctly report caps features downstream, when + a custom pipeline is built manually. + https://bugzilla.gnome.org/show_bug.cgi?id=719372 + Signed-off-by: Gwenole Beauchesne + +2013-12-17 15:27:10 +0000 Matthieu Bouron + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: add system memory caps to template caps. + Since vaapidecode provides buffer that can be mapped as regular memory, + those caps should be added to the template caps. That only applies to + GStreamer >= 1.2. + https://bugzilla.gnome.org/show_bug.cgi?id=720608 + Signed-off-by: Gwenole Beauchesne + +2013-12-17 10:26:03 +0800 Wind Yuan + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: fix hang on SIGINT. + vaapidecode hangs when pipeline is stopped without any EOS, e.g. when + +C is pressed, thus causing the srcpad task to keep running and + locked. This fixes a deadlock on state change from PAUSED to READY. + https://bugzilla.gnome.org/show_bug.cgi?id=720584 + Signed-off-by: Gwenole Beauchesne + +2013-12-17 04:23:42 -0500 Wind Yuan + + * gst/vaapi/gstvaapiencode.c: + vaapiencode: fix possible hang on SIGINT. + vaapiencode might hang when the pipeline is stopped without any EOS, + e.g. when +C is pressed, thus causing the srcpad task to keep + running and locked. This fixes a possible deadlock on state change + from PAUSED to READY. + https://bugzilla.gnome.org/show_bug.cgi?id=720584 + Signed-off-by: Gwenole Beauchesne + +2014-01-14 16:33:04 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapiencode.c: + vaapiencode: fix typo in error message. + Fix incomplete error message in gst_vaapiencode_push_frame(). + +2014-01-14 19:08:36 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + plugins: add helpers to create video caps with features. + Add gst_vaapi_video_format_new_template_caps_with_features() helper + function to add the supplied caps feature string on GStreamer >= 1.2. + Add gst_vaapi_find_preferred_caps_feature() helper function to discover + the "best" caps feature to use for the supplied pad. In practice, we + will always favor memory:VASurface first, then meta:GLTextureUploadMeta, + and finally the system memory caps. + https://bugzilla.gnome.org/show_bug.cgi?id=719372 + +2014-01-09 11:54:11 +0000 Matthieu Bouron + + * gst/vaapi/gstvaapivideometa_texture.c: + plugins: don't apply overlay composition in GLTextureUpload function. + The GLTextureUpload function is not in charge of doing the overlay + composition if any. + https://bugzilla.gnome.org/show_bug.cgi?id=721859 + Signed-off-by: Gwenole Beauchesne + +2014-01-14 13:47:52 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_objects.c: + encoder: re-order submission of VA objects. + Change the submission order of VA objects so that to make that process + more logical. i.e. submit sequence parameter first, if any; next the + packed headers associated to sequece, picture or slices; and finally + the actual picture and associated slices. + +2014-01-14 12:01:11 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_objects.c: + * gst-libs/gst/vaapi/gstvaapiencoder_objects.h: + encoder: clean-up objects. + Various clean-ups to improve consistency and readability: rename some + variables, drop unused macro definitions, drop initialization of vars + that are zero-initialized from the base class, drop un-necessary casts, + allocate GPtrArrays with a destroy function. + +2014-01-13 13:41:35 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: fix frame cropping rectangle calculation. + Fix frame cropping rectangle calculation to handle horizontal resolutions + that don't match a multiple of 16 pixels, but also the vertical resolution + that was incorrectly computed for progressive sequences too. + https://bugzilla.gnome.org/show_bug.cgi?id=722089 + +2014-01-13 11:49:14 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: improve automatic bitrate calculation. + For non "Constant-QP" modes, we could provide more reasonable heuristics + for the target bitrate. In general, 48 bits per macroblock with all the + useful coding tools enable looks safe enough. Then, this rate is raised + by +10% to +15% for each coding tool that is disabled. + https://bugzilla.gnome.org/show_bug.cgi?id=719699 + +2014-01-13 11:11:25 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: support "high-compression" tuning option. + Add support for "high-compression" tuning option. First, determine the + largest supported profile by the hardware. Next, check any target limit + set by the user. Then, enable each individual coding tool based on the + resulting profile_idc value to use. + https://bugzilla.gnome.org/show_bug.cgi?id=719696 + +2014-01-12 22:24:04 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_priv.h: + * gst-libs/gst/vaapi/gstvaapiutils_h264.c: + * gst-libs/gst/vaapi/gstvaapiutils_h264.h: + * gst/vaapi/gstvaapiencode_h264.c: + encoder: h264: allow target decoder constraints. + Allow user to precise the largest profile to use for encoding due + to target decoder constraints. For instance, if CABAC entropy coding + mode is requested by "constrained-baseline" profile only is desired, + then an error is returned during codec configuration. + Also make sure that the suitable profile we derived actually matches + what the HW can cope with. + https://bugzilla.gnome.org/show_bug.cgi?id=719694 + +2014-01-12 22:14:11 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + encoder: h264: refine size of coded buffer. + Refine the heuristic to determine the maximum size of a coded buffer + to account for the exact number of slices. set_context_info() is the + last step during codec reconfiguration, no additional change is done + afterwards, so re-using the num_slices field here is fine. + https://bugzilla.gnome.org/show_bug.cgi?id=719953 + +2013-12-13 17:36:08 +0800 Wind Yuan + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_priv.h: + encoder: h264: expose more coding tools. + Add new H.264 coding tools to improve compression: + - "cabac": enable CABAC entropy coding (default: FALSE); + - "dct8x8": enable spatial transform 8x8 (default: FALSE). + https://bugzilla.gnome.org/show_bug.cgi?id=719693 + Signed-off-by: Gwenole Beauchesne + +2014-01-10 18:18:25 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_priv.h: + encoder: h264: derive profile and level from active coding tools. + Automatically derive the minimum profile and level to be used for + encoding, based on the activated coding tools. The encoder will + be trying to generate a bitstream that has the best chances to be + decoded on most platforms by default. + Also change the default profile to "constrained-baseline" so that + to ensure maximum compatibility when the stream is decoded. + https://bugzilla.gnome.org/show_bug.cgi?id=719691 + +2014-01-10 17:02:44 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_priv.h: + encoder: h264: fix hardware profile lookup. + Fix lookup for a suitable HW profile, as to be used by the underlying + hardware, based on heuristics that lead to characterize the SW profile, + i.e. the one used by the SW level encoding logic. + Also fix constraint_set0_flag (A.2.1) and constraint_set1_flag (A.2.2) + as they should respectively match the baseline and main profile. + https://bugzilla.gnome.org/show_bug.cgi?id=719827 + +2014-01-10 14:46:15 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_priv.h: + encoder: h264: support only the byte-stream format. + The libgstvaapi core encoders are meant to support raw bitstreams only. + Henceforth, we are always producing a stream in "byte-stream" format. + However, the "codec-data" buffer which holds SPS and PPS headers is + always available. The "lengthSizeMinusOne" field is always set to 3 + so that in-place "byte-stream" format to "avc" format conversion could + be performed. + +2014-01-10 14:05:40 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_priv.h: + * gst/vaapi/gstvaapiencode_h264.c: + encoder: h264: clean-ups. + Various clean-ups to improve consistency and readability: rename some + variables, drop unused macro definitions, drop initialization of vars + that are zero-initialized from the base class, drop un-necessary casts. + +2014-01-13 17:11:15 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + encoder: mpeg2: fix hardware profile lookup. + Fix lookup for a suitable HW profile, as to be used by the underlying + hardware, based on heuristics that lead to characterize the SW profile, + i.e. the one used by the SW level encoding logic. + +2014-01-13 16:56:04 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2_priv.h: + encoder: mpeg2: derive profile and level from active coding tools. + Automatically derive the minimum profile and level to be used for + encoding, based on the activated coding tools. Improve lookup for + the best suitable level with the new MPEG-2 helper functions. + Also change the default profile to "simple" so that to ensure maximum + compatibility when the stream is decoded. + https://bugzilla.gnome.org/show_bug.cgi?id=719703 + +2014-01-13 14:41:15 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.h: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2_priv.h: + encoder: mpeg2: clean-ups. + Various clean-ups to improve consistency and readability: drop unused + macro definitions, drop initialization of vars that are zero-initialized + from the base class, drop un-necessary casts. + +2014-01-13 10:48:25 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + encoder: add tuning options API. + Add encoder "tune" option to override the default behaviour that is to + favor maximum decoder compatibility at the expense of lower compression + ratios. + Expected tuning options to be developed are: + - "high-compression": improve compression, target best-in-class decoders; + - "low-latency": tune for low-latency decoding; + - "low-power": tune for encoding in low power / resources conditions. + +2014-01-12 23:17:14 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + encoder: fix bitrate units to match kbps. + Bitrate is expressed in kilobits per second (kbps). So, this exactly + means in multiple of 1000 bits, not 1024 bits. + https://bugzilla.gnome.org/show_bug.cgi?id=722086 + +2014-01-12 21:57:20 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_objects.c: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + encoder: clean-ups. + Drop obsolete and unused macros. Add a few doc comments. Slightly + improve indentation of a few leftovers. + +2014-01-12 18:52:14 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + * gst-libs/gst/vaapi/gstvaapivalue.c: + * gst-libs/gst/vaapi/gstvaapivalue.h: + encoder: filter out the supported set of rate-control properties. + Only expose the exact static set of supported rate-control properties + to the upper layer. For instance, if the GstVaapiEncoderXXX class does + only support CQP rate control, then only add it the the exposed enum + type. + Add helper macros and functions to build a GType for an enum subset. + +2014-01-10 13:23:48 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_priv.h: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.h: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2_priv.h: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + encoder: add keyframe period API. + Add gst_vaapi_encoder_set_keyframe_period() interface to allow the + user control the maximum distance between two keyframes. This new + property can only be set prior to gst_vaapi_encoder_set_codec_state(). + A value of zero for "keyframe-period" gets it re-evaluated to the + actual framerate during encoder reconfiguration. + +2014-01-10 12:01:51 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + encoder: improve codec reconfiguration. + Improve codec reconfiguration to be performed only through a single + function. That is, remove the _set_context_info() hook as subclass + should not alter the parent GstVaapiContextInfo itself. Besides, the + VA context is constructed only at the final stages of reconfigure(). + +2014-01-10 11:30:25 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicodedbufferpool.c: + * gst-libs/gst/vaapi/gstvaapicodedbufferpool.h: + * gst-libs/gst/vaapi/gstvaapiencoder.c: + encoder: fix possible memory leak of coded buffer pools. + Fix gst_vaapi_encoder_reconfigure_internal() to re-/allocate the coded + buffer pool only if the coded buffer size actually changed. + +2014-01-10 10:54:22 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode.h: + encoder: add video codec-state API. + Add interface to communicate the encoder resolution and related info + like framerate, interlaced vs. progressive, etc. This new interface + supersedes gst_vaapi_encoder_set_format() and doesn't use any GstCaps + but rather use GstVideoCodecState. + Note that gst_vaapi_encoder_set_codec_state() is also a synchronization + point for codec config. This means that the encoder is reconfigured + there to match the latest properties. + +2014-01-13 17:18:42 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapiencode.c: + vaapiencode: don't crash on NULL encoder on _finish(). + Don't try to destroy an encoder, in GstVideoEncoder::finish() handler, + if it was not created in the first place. Return "not-negotiated" error + since this means we did not even reach GstVideoEncoder::set_format(), + where the encoder could have been created. + This fixes a crash when the vaapiencode_* plug-in elements get deallocated + and that we failed to negotiate either pad. + https://bugzilla.gnome.org/show_bug.cgi?id=719704 + +2014-01-09 18:20:24 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode.h: + * gst/vaapi/gstvaapiencode_h264.c: + vaapiencode: use more GstVaapiPluginBase facilities. + Avoid duplication of pad references or query functions since they are + provided through the GstVaapiPluginBase object. + +2014-01-09 18:10:35 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode.h: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h264.h: + * gst/vaapi/gstvaapiencode_mpeg2.c: + vaapiencode: fix negotiation process of output caps. + The specified caps in gst_video_encoder_set_output_state() function + arguments should not contain any resolution, pixel-aspect-ratio, + framerate, codec-data et al. Those rather should be set through the + returned GstVideoCodecState. This means that output caps creation + could be delayed until before gst_video_encoder_finish_frame() is + called. + This greatly simplifies the GstVideoEncoder::set_format() callback + by the way. + +2014-01-08 18:56:23 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapiencode.c: + vaapiencode: make GstVaapiEncode an abstract type. + Make base GstVaapiEncode class an abstract type so that we cannot + create an instance from it without going through any of the codec + specific derived class. + +2014-01-09 10:09:38 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode.h: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_mpeg2.c: + vaapiencode: rename a few member functions. + Rename a few member functions to make them more consistent: + - alloc_encoder(): now reduced to allocate the encoder object only; + - alloc_buffer(): allocate buffer from srcpad, and copy bitstream. + +2014-01-08 18:36:46 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode.h: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h264.h: + * gst/vaapi/gstvaapiencode_mpeg2.c: + vaapiencode: update for new properties API. + Update MPEG-2 and H.264 encode elements to cope with the new core + libgstvaapi properties API. i.e. all configurable properties are now + directly handled at the GstVaapiEncoder level. + Besides, this also makes sure to not use or modify the GstVaapiEncoder + private definitions directly. Private data need to remain private. + https://bugzilla.gnome.org/show_bug.cgi?id=719529 + +2014-01-06 17:46:40 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.h: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + encoder: add properties API. + Add interface to communicate configurable properties to the encoder. + This covers both the common ones (rate-control, bitrate), and the + codec specific properties. + https://bugzilla.gnome.org/show_bug.cgi?id=719529 + +2014-01-06 18:01:33 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_priv.h: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2_priv.h: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_mpeg2.c: + encoder: add bitrate API. + Add gst_vaapi_encoder_set_bitrate() interface to allow the user control + the bitrate for encoding. Currently, changing this parameter is only + valid before the first frame is encoded. Should the value be modified + afterwards, then GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED is + returned. + https://bugzilla.gnome.org/show_bug.cgi?id=719529 + +2014-01-06 15:10:36 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2_priv.h: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + * gst-libs/gst/vaapi/gstvaapitypes.h: + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode.h: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_mpeg2.c: + encoder: add rate control API. + Add gst_vaapi_encoder_set_rate_control() interface to request a new + rate control mode for encoding. Changing the rate control mode is + only valid prior to encoding the very first frame. Afterwards, an + error ("operation-failed") is issued. + https://bugzilla.gnome.org/show_bug.cgi?id=719529 + +2014-01-03 16:57:25 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_mpeg2.c: + vaapiencode: fix indentation. + +2014-01-03 16:57:09 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_priv.h: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_objects.c: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + * gst/vaapi/gstvaapiencode.h: + encoder: fix indentation. + +2014-01-13 16:20:06 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiutils_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiutils_mpeg2.h: + * gst-libs/gst/vaapi/gstvaapiutils_mpeg2_priv.h: + utils: add new MPEG-2 helper functions. + Add various helper functions to convert profile, level, chroma formats + from gstreamer-vaapi world and the MPEG-2 specification world. + +2014-01-10 19:49:52 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiutils_h264.c: + utils: h264: don't use fatal asserts. + Replace g_assert() with a g_debug() so that to not make the program + abort when an unsupported value is supplied. + +2014-01-10 19:37:44 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiutils_h264.c: + * gst-libs/gst/vaapi/gstvaapiutils_h264.h: + utils: h264: add helpers for profile and level string mappings. + Add profile and level helper functions to convert to/from strings. + +2014-01-10 18:27:20 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiutils_h264.c: + * gst-libs/gst/vaapi/gstvaapiutils_h264.h: + * gst-libs/gst/vaapi/gstvaapiutils_h264_priv.h: + utils: h264: expose levels in public header. + Instal header but only expose the + H.264 levels in there. The additional helper functions are meant + to be private for now. + +2014-01-09 09:27:40 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicodec_objects.c: + * gst-libs/gst/vaapi/gstvaapicodec_objects.h: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + codec: add helper macros to maintain object refcount. + Add gst_vaapi_mini_object_{ref,unref,replace}() helper macros so that + to avoid explicit casts to GstVaapiMiniObject in all caller sites. + +2014-01-09 09:30:49 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + codec: re-indent decoder objects. + +2014-01-09 09:10:21 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicodec_objects.c: + * gst-libs/gst/vaapi/gstvaapicodec_objects.h: + codec: re-indent base codec objects. + +2014-01-03 12:49:05 +0000 Matthieu Bouron + + * gst/vaapi/gstvaapipluginbase.c: + plugins: do not free debug category in finalize method. + Fixes a crash when multiple vaapidecode elements are finalized since + the debug category is created once in the class init method. + This is a regression from git commit 7e58d60. + https://bugzilla.gnome.org/show_bug.cgi?id=721390 + Signed-off-by: Gwenole Beauchesne + +2014-01-02 11:35:30 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/glibcompat.h: + * tests/simple-decoder.c: + tests: simple-decoder: don't use deprecated g_thread_create(). + Use g_thread_try_new() instead of the deprecated g_thread_create() + function. Provide compatibility glue for any GLib version < 2.31.2. + +2014-01-02 11:17:28 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapipixmap_x11.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst/vaapi/gstvaapiencode.c: + Fix printf()-like formats. + Fix formts for various GST_DEBUG et al. invocations. More precisely, + make size_t arguments use the %zu format specifier accordingly; force + XID formats to be a 32-bit unsigned integer; and fix the format used + for gst_vaapi_create_surface_with_format() error cases since we have + been using strings nowadays. + +2013-12-21 07:38:14 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/video-format.c: + * gst-libs/gst/vaapi/video-format.h: + utils: format: drop unused helper functions. + The following helper functions are no longer used, thus are removed: + - gst_vaapi_video_format_from_structure() + - gst_vaapi_video_format_from_caps() + - gst_vaapi_video_format_to_caps() + +2013-12-21 07:29:50 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/video-format.c: + * gst-libs/gst/vaapi/video-format.h: + utils: re-indent GstVideoFormat related helpers. + +2013-12-21 08:27:30 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidownload.c: + download: use GstVideoInfo facilities to build output caps. + Use standard GstVideoInfo related functions to build the output caps, + thus directly preserving additional fields as needed, instead of + manually copying them over through gst_vaapi_append_surface_caps(). + Also ensure that the input caps are fixated first. + +2013-12-21 10:41:22 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapiuploader.c: + plugins: factor out construction of template caps. + Add new helper functions to build video template caps. + - gst_vaapi_video_format_new_template_caps(): + create GstCaps with size, frame rate and PAR to full range + - gst_vaapi_video_format_new_template_caps_from_list(): + try to create a "simplified" list from the supplied formats + +2013-12-21 06:41:34 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapipostproc.c: + plugins: factor out construction of GValue from GstVideoFormat. + Add new helper functions to build GValues from GstVideoFormat: + - gst_vaapi_value_set_format(): + build a GValue from the supplied video format + - gst_vaapi_value_set_format_list(): + build a GValue list from the supplied array of video formats + +2013-12-21 06:22:30 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapivideocontext.c: + * gst/vaapi/gstvaapivideocontext.h: + plugins: re-indent common and video context creation utils. + +2013-12-20 15:31:14 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst/vaapi/gstvaapidecode.c: + * tests/test-display.c: + display: don't use GstCaps for decode or encode profiles list. + Replace gst_vaapi_display_get_{decode,encode}_caps() APIs with more + more convenient APIs that return an array of GstVaapiProfile instead + of GstCaps: gst_vaapi_display_get_{decode,encode}_profiles(). + +2013-12-20 15:15:05 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapiuploader.c: + * tests/test-display.c: + display: don't use GstCaps for image or subpicture formats list. + Replace gst_vaapi_display_get_{image,subpicture}_caps() APIs, that + returned GstCaps, with more convenient APIs that return an array of + GstVideoFormat: gst_vaapi_display_get_{image,subpicture}_formats(). + +2013-12-20 14:01:45 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + display: allocate queried resources on-demand. + Allocate the set of decoders or encoders on-demand, when they are + queried. Likewise for VA display attributes, image and subpicture + formats. + +2013-12-20 13:27:07 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.h: + * gst-libs/gst/vaapi/gstvaapidisplay_drm_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.c: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.h: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplaycache.c: + * gst-libs/gst/vaapi/gstvaapidisplaycache.h: + display: re-indent all GstVaapiDisplay related source code. + +2013-12-20 16:04:19 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + utils: add helper functions to get codec or profile name. + +2013-12-20 17:08:23 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + * gst/vaapi/gstvaapiuploader.c: + plugins: fix permissions for certain files. + Drop the execute bit for gstvaapiuploader.c and gstvaapipostproc.[ch] + files. + +2013-12-12 17:01:29 +0000 Matthieu Bouron + + * gst/vaapi/gstvaapivideometa_texture.c: + plugins: implement GLTextureUploadMeta user data copy. + Makes the copies of a buffer reference their own GLTextureUploadMeta + user data and prevent the original buffer accessing already freed + memory if its copies has been released and freed. + https://bugzilla.gnome.org/show_bug.cgi?id=720336 + [Propagate the original meta texture to the copy too] + Signed-off-by: Gwenole Beauchesne + +2013-12-17 18:52:23 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode.h: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + plugins: factor out support for raw YUV buffers on sink pads. + Factor out propose_allocation() hooks, creation of video buffer pool + for the sink pad, conversion from raw YUV buffers to VA surface backed + buffers. Update vaapidecode, vaapiencode and vaapipostproc to cope + with the new GstVaapiPluginBase abilities. + +2013-12-17 18:46:07 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstcompat.h: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiupload.c: + plugins: factor out pad caps. + +2013-12-13 16:03:08 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiupload.c: + plugins: factor out video context sharing code. + +2013-12-13 13:24:24 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiupload.c: + plugins: factor out GstImplementsInterface. + +2013-12-13 12:00:35 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginutil.c: + plugins: check type of display obtained from neighbours. + Fix display creation code to check that any display obtained from a + neighbour actually has the type we expect. Note: if display type is + set to "any", we can then accept any VA display type. + +2013-12-13 11:52:47 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + * gst/vaapi/gstvaapiupload.c: + plugins: factor out display creation process. + Move common VA display creation code to GstVaapiPluginBase, with the + default display type remaining "any". Also add a "display-changed" + hook so that subclasses could perform additional tasks when/if the + VA display changed, due to a new display type request for instance. + All plug-ins are updated to cope with the new internal APIs. + +2013-12-13 10:24:26 +0100 Gwenole Beauchesne + + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapidownload.h: + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode.h: + * gst/vaapi/gstvaapipluginbase.c: + * gst/vaapi/gstvaapipluginbase.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + * gst/vaapi/gstvaapiupload.c: + * gst/vaapi/gstvaapiupload.h: + plugins: add new base object, store display in there. + Introduce a new GstVaapiPluginBase object that will contain all common + data structures and perform all common tasks. First step is to have a + single place to hold VA displays. + While we are at it, also make sure to store and subsequently release + the appropriate debug category for the subclasses. + +2013-12-11 14:04:27 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiobject.h: + * gst-libs/gst/vaapi/gstvaapiobject_priv.h: + * gst/vaapi/gstvaapivideometa_texture.c: + * gst/vaapi/gstvaapivideometa_texture.h: + plugins: fix GLTextureUploadMeta to work with different texture ids. + The GLTextureUploadMeta implementation assumed that for each upload() + sequence, the supplied texture id is always the same as the one that + was previously cached into the underlying GstVaapiTexture. Cope with + any texture id change the expense to recreate the underlying VA/GLX + resources. + https://bugzilla.gnome.org/show_bug.cgi?id=719643 + +2013-12-11 13:25:51 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapivideobufferpool.c: + * gst/vaapi/gstvaapivideometa_texture.c: + plugins: allow builds without GLX enabled for GStreamer 1.2. + Don't try to build GLTextureUploadMeta related code if GLX is not + enabled during GStreamer >= 1.2 builds. + +2013-11-20 17:20:07 +0000 Matthieu Bouron + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapivideobufferpool.c: + * gst/vaapi/gstvaapivideobufferpool.h: + * gst/vaapi/gstvaapivideometa_texture.c: + * gst/vaapi/gstvaapivideometa_texture.h: + plugins: request GLTextureUpload meta on buffers in the buffer pool. + Requesting the GLTextureUpload meta on buffers in the bufferpool + prevents such metas from being de-allocated when buffers are released + in the sink. + This is particulary useful in terms of performance when using the + GLTextureUploadMeta API since the GstVaapiTexture associated with + the target texture is stored in the meta. + https://bugzilla.gnome.org/show_bug.cgi?id=712558 + Signed-off-by: Gwenole Beauchesne + +2013-12-11 10:51:03 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideometa_texture.c: + plugins: robustify GstVideoGLTextureUploadMeta implementation. + Make GstVideoGLTextureUploadMeta::upload() implementation more robust + when the GstVaapiTexture associated with the supplied texture id could + not be created. + +2013-12-10 16:14:27 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: improve robustness when packets are missing. + Improve robustness when some expected packets where not received yet + or that were not correctly decoded. For example, don't try to decode + a picture if there was no valid frame headers parsed so far. + https://bugs.freedesktop.org/show_bug.cgi?id=57902 + +2013-12-10 14:20:55 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: fix decoding of BA3_SVA_C.264. + Conformance test Base_Ext_Main_profiles/BA3_SVA_C.264 complys with + extended profile specifications. However, the SPS header has the + constraint_set1_flag syntax element set to 1. This means that, if + a Main profile compliant decoder is available, then it should be + able to decode this stream. + This changes makes it possible to fall-back from Extended profile + to Main profile if constraint_set1_flag is set to 1. + https://bugzilla.gnome.org/show_bug.cgi?id=720190 + +2013-12-10 11:13:01 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiprofile.h: + * gst-libs/gst/vaapi/gstvaapiutils_h264.c: + utils: h264: add more profiles. + Add extended profile (A.2.3), high 4:2:2 profile (A.2.6), high 4:2:2 + profiles (A.2.7, A.2.10), scalable profiles (G.10.1.1, G.10.1.2) and + multiview profiles (H.10.1.1, H.10.1.2). + Document "Constrained Baseline" and "High 10" profiles. + +2013-12-10 15:21:51 +0100 Gwenole Beauchesne + + * ext/codecparsers: + codecparsers: update to gst-vaapi-branch commit e7d0e18. + e7d0e18 h264: complete set of NAL unit types + +2013-12-06 15:08:26 +0800 Wind Yuan + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + decoder: h264: add support for constrained baseline profile. + Recognize streams marked as conforming to the "Constrained Baseline + Profile". If VA driver supports that as is, fine. Otherwise, fallback + to baseline, main or high profile. + Constrained Baseline Profile conveys coding tools that are common + to baseline profile and main profile. + https://bugzilla.gnome.org/show_bug.cgi?id=719947 + [Added fallbacks to main and high profiles] + Signed-off-by: Gwenole Beauchesne + +2013-12-09 12:46:45 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + decoder: h264: fix decoding of scaling lists. + The GStreamer codecparser layer now parses the scaling lists in zigzag + scan order, as expected, so that to match the original bitstream layout + and specification. However, further convert the scaling lists into + raster scan order to fit the existing practice in most VA drivers. + https://bugzilla.gnome.org/show_bug.cgi?id=706406 + +2013-12-09 12:07:28 +0100 Gwenole Beauchesne + + * ext/codecparsers: + codecparsers: update to gst-vaapi-branch commit 177c73b. + a7e3255 add H.265 (HEVC) bitstream parser + 177c73b h264: fix picture level scaling lists derivation (rule B) + 14733f1 h264: fix parsing of VCL HRD parameters + 59a0b47 h264: store quantization matrices in zig-zag order + ffb6e26 h264: add helpers to convert quantization matrices + c78a504 mpeg2: also initialize debug category in parse_sequence_header() + 719d1b0 mpeg2: turn internal consistency check into a g_assert() + 5241d8e all: remove some unused functions + 18eb312 all: fix for GST_DISABLE_GST_DEBUG + 963c04a all: make warnings more meaningful + +2013-12-06 19:05:52 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiutils_h264.c: + * gst-libs/gst/vaapi/gstvaapiutils_h264.h: + utils: add helpers for H.264 levels. + - gst_vaapi_utils_h264_get_level(): + Returns GstVaapiLevelH264 from H.264 level_idc value + - gst_vaapi_utils_h264_get_level_idc(): + Returns H.264 level_idc value from GstVaapiLevelH264 + - gst_vaapi_utils_h264_get_level_limits(): + Returns level limits as specified in Table A-1 of the H.264 standard + - gst_vaapi_utils_h264_get_level_limits_table(): + Returns the Table A-1 specification + +2013-12-06 17:34:52 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + * gst-libs/gst/vaapi/gstvaapiutils_h264.c: + utils: add new H.264 profiles. + Add "Constrained Baseline Profile" and "High 10 Profile" definitions + and helper functiions. + +2013-12-06 17:21:52 +0100 Gwenole Beauchesne + + utils: add new H.264 helper functions. + * Profiles: + - gst_vaapi_utils_h264_get_profile(): + Returns GstVaapiProfile from H.264 profile_idc value + - gst_vaapi_utils_h264_get_profile_idc(): + Returns H.264 profile_idc value from GstVaapiProfile + * Chroma formats: + - gst_vaapi_utils_h264_get_chroma_type(): + Returns GstVaapiChromaType from H.264 chroma_format_idc value + - gst_vaapi_utils_h264_get_chroma_format_idc(): + Returns H.264 chroma_format_idc value from GstVaapiChromaType + +2013-12-03 11:05:17 +0000 Matthieu Bouron + + * gst-libs/gst/base/Makefile.am: + * gst-libs/gst/vaapi/Makefile.am: + Fix missing files in distribution tarball. + https://bugzilla.gnome.org/show_bug.cgi?id=719776 + [Additional fixes and clean-ups] + Signed-off-by: Gwenole Beauchesne + +2013-12-05 18:13:54 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + encoder: fix computation of max coded buffer size (again). + The previous fix was only valid to express the maximum size of the + macroblock layer, i.e. without any headers. Now, also account for + the slice headers and top picture header, but also any other header + we might stuff into the VA coded buffer, e.g. sequence headers. + +2013-12-04 19:10:13 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + encoder: fix computation of max coded buffer size. + Fix coded buffer size for each codec. A generic issue was that the + number of macroblocks was incorrectly computed. The second issue was + specific to MPEG-2 were the max number of bits per macroblock, and + as defined by the standard, was incorrectly mapped to the (lower) + H.264 requirement. i.e. 4608 bits vs. 3200 bits limit. + +2013-12-04 18:48:35 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + encoder: simplify VA context initialization process. + Change get_context_info() into a set_context_info() function that + initializes common defaults into the base class, thus allowing the + subclasses to specialize the context info further on. + The set_context_info() hook is also the location where additional + context specific data could be initialized. At this point, we are + guaranteed to have valid video resolution size and framerate. i.e. + gst_vaapi_encoder_set_format() was called beforehand. + +2013-11-26 14:38:23 +0800 Wind Yuan + + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + encoder: fix mpeg2 compilation error. + https://bugzilla.gnome.org/show_bug.cgi?id=719746 + Signed-off-by: Gwenole Beauchesne + +2013-12-04 17:55:18 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + * gst/vaapi/gstvaapiencode.c: + encoder: clean-ups and document public APIs. + Clean public APIs up so that to better align with the decoder APIs. + Most importantly, gst_vaapi_encoder_get_buffer() is changed to only + return the VA coded buffer proxy. Also provide useful documentation + for the public APIs. + +2013-12-04 17:05:17 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + encoder: avoid extra allocations of GstVaapiEncoderSyncPic objects. + Kill GstVaapiEncoderSyncPic objects that are internally and temporarily + allocated. Rather, associate a GstVaapiEncPicture to a coded buffer + through GstVaapiCodedBufferProxy user-data facility. + Besides, use a GAsyncQueue to maintain a thread-safe queue object of + coded buffers. + Partial fix for the following report: + https://bugzilla.gnome.org/show_bug.cgi?id=719530 + +2013-12-03 17:04:43 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst/vaapi/gstvaapiencode.c: + encoder: refactor status codes. + Drop obsolete or unused status codes. Align some status codes with the + decoder counterparts. + +2013-12-04 11:54:40 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_priv.h: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2_priv.h: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + encoder: fix subclassing process. + Fix the GstVaapiEncoderClass parent class type. Make sure to validate + subclass hooks as early as possible, i.e. in gst_vaapi_encoder_init(), + thus avoiding useless run-time checks. Also simplify the subclass + initialization process to be less error prone. + +2013-12-03 16:11:46 +0100 Gwenole Beauchesne + + encoder: rework GstVaapiCodedBuffer and related proxy. + Refactor the GstVaapiCodedBuffer APIs so that to more clearly separate + public and private interfaces. Besides, the map/unmap APIs should not + be exposed as is but appropriate accessors should be provided instead. + * GstVaapiCodedBuffer: VA coded buffer abstraction + - gst_vaapi_coded_buffer_get_size(): get coded buffer size. + - gst_vaapi_coded_buffer_copy_into(): copy coded buffer into GstBuffer + * GstVaapiCodedBufferPool: pool of VA coded buffer objects + - gst_vaapi_coded_buffer_pool_new(): create a pool of coded buffers of + the specified max size, and bound to the supplied encoder + * GstVaapiCodedBufferProxy: pool-allocated VA coded buffer object proxy + - gst_vaapi_coded_buffer_proxy_new_from_pool(): create coded buf from pool + - gst_vaapi_coded_buffer_proxy_get_buffer(): get underlying coded buffer + - gst_vaapi_coded_buffer_proxy_get_buffer_size(): get coded buffer size + Rationale: more optimized transfer functions might be provided in the + future, thus rendering the map/unmap mechanism obsolete or sub-optimal. + https://bugzilla.gnome.org/show_bug.cgi?id=719775 + +2013-11-29 14:02:52 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + plugins: fix reference leaks of VA display objects. + Fix GstElement::set_context() implementation for all plug-in elements + to avoid leaking an extra reference to the VA display, thus preventing + correct cleanup of VA resources in GStreamer 1.2 builds. + +2013-11-29 13:56:12 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapivideocontext.c: + plugins: simplify gst_vaapi_ensure_display(). + Return earlier if the creation of a VA display failed. Likewise, simplify + gst_vaapi_video_context_propagate() now that we are guaranteed to have a + valid VA display. + +2013-11-28 19:08:28 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideomemory.c: + plugins: fix memory leaks through GstVideoMeta maps. + When GstVideoMeta maps were used, the supporting functions incorrectly + used gst_buffer_get_memory() instead of gst_buffer_peek_memory(), thus + always increasing the associated GstMemory reference count and giving + zero chance to actually release that, and subsequently the VA display. + +2013-11-28 14:15:44 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_mpeg2.c: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiuploader.c: + plugins: use G_PARAM_STATIC_STRINGS. + This avoids a few string copies during initialization. + +2013-11-28 17:28:11 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideometa.c: + plugins: simplify VA video meta to only reference surface proxies. + Simplify GstVaapiVideoMeta to only hold a surface proxy, which is + now allocated from a surface pool. This also means that the local + reference to the VA surface is also gone, as it could be extracted + from the associated surface proxy. + +2013-11-28 16:51:37 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideobuffer.c: + * gst/vaapi/gstvaapivideobuffer.h: + * gst/vaapi/gstvaapivideometa.c: + * gst/vaapi/gstvaapivideometa.h: + plugins: drop obsolete functions. + Drop the following functions that are not longer used: + - gst_vaapi_video_buffer_new_with_surface() + - gst_vaapi_video_meta_new_with_surface() + - gst_vaapi_video_meta_set_surface() + - gst_vaapi_video_meta_set_surface_from_pool() + +2013-11-28 16:37:31 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideometa.c: + plugins: allow VA video meta to be allocated from surface proxy pools. + Fix gst_vaapi_video_meta_new_from_pool() to allocate VA surface proxies + from surface pools instead of plain VA surfaces. This is to simplify + allocations now that surface proxies are created from a surface pool. + +2013-11-28 17:25:05 +0100 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy_priv.h: + surfaceproxy: add copy function. + Add gst_vaapi_surface_proxy_copy() function that creates a new surface + proxy with the same information from the parent proxy, except that the + user-defined destroy notify function is not copied over. + The underlying VA surface is pushed back to the video pool only when + the last reference to the parent surface proxy is released. + +2013-11-28 15:56:53 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiencoder_objects.c: + * gst-libs/gst/vaapi/gstvaapiencoder_objects.h: + * gst/vaapi/gstvaapiencode.c: + vaapiencode: optimize _handle_frame() to avoid extra allocation. + Optimize gst_vaapiencode_handle_frame() to avoid extra memory allocation, + and in particular the GstVaapiEncObjUserData object. i.e. directly use + the VA surface proxy from the source buffer. This also makes the user + data attached to the GstVideoCodecFrame more consistent between both + the decoder and encoder plug-in elements. + +2013-11-28 15:14:43 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapiencode.c: + vaapiencode: fix memory leaks in _push_frame() on error. + Simplify gst_vaapiencode_push_frame(), while also removing the call + to gst_video_encoder_negotiate() since this is implicit in _finish() + if caps changed. Also fixed memory leaks that occured on error. + +2013-11-28 13:57:54 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode.h: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h264.h: + * gst/vaapi/gstvaapiencode_mpeg2.c: + vaapiencode: additional clean-ups. + Constify pointers wherever possible. Drop unused variables, and use + consistent variable names. Fix gst_vaapiencode_h264_allocate_buffer() + to correctly report errors, especially when in-place conversion from + bytestream to avcC format failed. + +2013-11-28 13:26:40 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode.h: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h264.h: + * gst/vaapi/gstvaapiencode_mpeg2.c: + * gst/vaapi/gstvaapiencode_mpeg2.h: + vaapiencode: move common properties to base class. + Move "rate-control" mode and "bitrate" properties to the GstVaapiEncode + base class. The actual range of supported rate control modes is currently + implemented as a plug-in element hook. This ought to be determined from + the GstVaapiEncoder object instead, i.e. from libgstvaapi. + +2013-11-28 10:54:36 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_mpeg2.c: + vaapiencode: fix plugin description and debug name. + Align the plug-in debug category to its actual name. i.e. enable debug + logs through vaapiencode_ where is mpeg2, h264, etc. Fix + the plug-in element description to make it more consistent with other + VA-API plug-ins. + +2013-11-27 16:27:31 +0100 Gwenole Beauchesne + + * configure.ac: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/video/Makefile.am: + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode.h: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_mpeg2.c: + vaapiencode: add initial support for GStreamer 0.10. + +2013-11-27 16:25:59 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstcompat.h: + libs: add more GstBuffer compat glue for GStreamer 0.10. + Add gst_buffer_new_allocate() and gst_buffer_fill() implementations. + Fix gst_buffer_new_wrapped_full() implementation to handle the destroy + notify function. + +2013-11-27 15:56:51 +0100 Gwenole Beauchesne + + * configure.ac: + * gst-libs/gst/video/Makefile.am: + libs: always use built-in videoutils for GStreamer 0.10. + GStreamer 0.10.36 is the latest and ultimate version to be released + from the GStreamer 0.10 branch. i.e. no further releases are to be + made. So, we can safely enable the built-in videoutils replacement + now that they are in sync with the 0.10 branch. + +2013-11-27 15:47:38 +0100 Gwenole Beauchesne + + * ext/videoutils: + videoutils: update to master commit d4a15a5. + d4a15a5 video: fix compiler warning in header with C++11 / clang-3.1 + 86096cc videodecoder: minor cosmetic changes to align a bit more with master + b4b8b52 videodecoder: allow parse function to not use all data on adapter + 2145495 videodecoder: warn if frame list gets long + 36c3753 videodecoder: Also use the object lock to protect the output_state + 518c93d videodecoder: fix seeking again + 185fb63 video: Correct usage of the base class stream lock + 170e944 videodecoder: Expose _negotiate function + +2013-11-26 12:06:07 +0000 Matthieu Bouron + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + * tests/Makefile.am: + Fix build with GStreamer >= 1.3. + http://bugzilla.gnome.org/show_bug.cgi?id=715183 + Signed-off-by: Gwenole Beauchesne + +2013-11-26 17:56:59 +0100 Gwenole Beauchesne + + * configure.ac: + configure: disable encoders with GStreamer 0.10. + Don't try to build video encoders for GStreamer 0.10. Support code is + not there yet, and probably will never for such an ancient version. + +2013-11-26 17:26:44 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapiencode.c: + vaapiencode: fix error handling while allocating output buffers. + Fix default GstVideoEncoder::allocate_buffer() implementation to properly + unmap the coded buffer prior to returning an error. + +2013-11-26 17:11:22 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapiencode.c: + vaapiencode: fix error handling in _finish() hook. + Fix GstVideoEncoder::finish() implementation to really return possible + errors instead of GST_FLOW_OK. That is, fix check for timeout status. + +2013-11-26 16:34:14 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode.h: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h264.h: + * gst/vaapi/gstvaapiencode_mpeg2.c: + * gst/vaapi/gstvaapiencode_mpeg2.h: + vaapiencode: minor clean-ups. + Add a GST_VAAPIENCODE_CAST() helper to avoid run-time checks against + the GObject type system. We are guaranteed to only deal with the same + plug-in element object. + +2013-11-26 15:31:03 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_mpeg2.c: + vaapiencode: fix support for raw YUV sink buffers. + Allow vaapiencode plug-in elements to encode from raw YUV buffers. + The most efficient way to do so is to let the vaapiencode elements + allocate a buffer pool, and subsequently buffers from it. This means + that upstream elements are expected to honour downstream pools. + If upstream elements insist on providing their own allocated buffers + to the vaapiencode elements, then it possibly would be more efficient + to insert a vaapipostproc element before the vaapiencode element. + This is because vaapipostproc currently has better support than other + elements for "foreign" raw YUV buffers. + +2013-11-26 15:12:59 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapiencode.c: + vaapiencode: fix support for GStreamer 1.2. + +2013-11-07 17:42:21 +0800 Wind Yuan + + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_mpeg2.c: + vaapiencode: initial port to GStreamer 1.2. + Signed-off-by: Gwenole Beauchesne + +2013-11-20 16:21:32 +0800 XuGuangxin + + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapiencode_mpeg2.c: + * gst/vaapi/gstvaapiencode_mpeg2.h: + plugins: add mpeg2 encoder element. + Add GstVaapiEncodeMPEG2 element object. The actual plug-in element + is called "vaapiencode_mpeg2". + Valid properties: + - rate-control: rate control mode (default: cqp - constant QP) + - bitrate: desired bitrate in kbps (default: auto-calculated) + - key-period: maximal distance between two key frames (default: 30) + - max-bframes: number of B-frames between I and P (default: 2) + - quantizer: constant quantizer (default: 8) + Signed-off-by: Gwenole Beauchesne + +2013-07-29 16:02:56 +0800 Wind Yuan + + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapiencode_h264.c: + * gst/vaapi/gstvaapiencode_h264.h: + plugins: add h264 encoder element. + Add GstVaapiEncodeH264 element object. The actual plug-in element + is called "vaapiencode_h264". + Valid properties: + - rate-control: rate control mode (default: none) + - bitrate: desired bitrate in kbps (default: auto-calculated) + - key-period: maximal distance between two key frames (default: 30) + - num-slices: number of slices per frame (default: 1) + - max-bframes: number of B-frames between I and P (default: 0) + - min-qp: minimal quantizer (default: 1) + - init-qp: initial quantizer (default: 26) + Signed-off-by: Gwenole Beauchesne + +2013-07-29 13:44:48 +0800 Wind Yuan + + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapiencode.c: + * gst/vaapi/gstvaapiencode.h: + plugins: add base encoder element. + vaapiencode element is based on GstVideoEncoder APIs. + Signed-off-by: Gwenole Beauchesne + +2013-11-20 16:20:15 +0800 XuGuangxin + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.h: + * gst-libs/gst/vaapi/gstvaapiencoder_mpeg2_priv.h: + encoder: add mpeg2 encoder. + Add initial support for MPEG-2 encoding. I/P/B frames are supported. + Signed-off-by: Gwenole Beauchesne + +2013-07-29 15:46:11 +0800 Wind Yuan + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.c: + * gst-libs/gst/vaapi/gstvaapiencoder_h264.h: + * gst-libs/gst/vaapi/gstvaapiencoder_h264_priv.h: + encoder: add h264 encoder. + Signed-off-by: Gwenole Beauchesne + +2013-07-29 13:34:06 +0800 Wind Yuan + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiencoder.c: + * gst-libs/gst/vaapi/gstvaapiencoder.h: + * gst-libs/gst/vaapi/gstvaapiencoder_objects.c: + * gst-libs/gst/vaapi/gstvaapiencoder_objects.h: + * gst-libs/gst/vaapi/gstvaapiencoder_priv.h: + Add initial infrastructure for video encoding. + Add initial API for video encoding: only basic interfaces and small + encoder objects are implemented so far. + Signed-off-by: Gwenole Beauchesne + +2013-07-29 15:41:23 +0800 Wind Yuan + + * configure.ac: + * gst-libs/gst/Makefile.am: + * gst-libs/gst/base/Makefile.am: + * gst-libs/gst/base/gstbitwriter.c: + * gst-libs/gst/base/gstbitwriter.h: + * gst-libs/gst/vaapi/Makefile.am: + libs: add generic bitstream writer. + GstBitWriter provides a bit writer that can write any number of bits + to a pre-allocated memory buffer. Helper functions are also provided + to write any number of bits from 8, 16, 32 and 64 bit variables. + Signed-off-by: Gwenole Beauchesne + +2013-07-12 22:07:59 +0800 Wind Yuan + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + libs: add support for rate-control to GstVaapiContext. + Extend GstVaapiContextInfo structure to hold the desired rate control + mode for encoding purposes. For decoding purposes, this field is not + used and it is initialized to GST_VAAPI_RATECONTROL_NONE. + Signed-off-by: Gwenole Beauchesne + +2013-07-12 21:33:32 +0800 Wind Yuan + + * gst-libs/gst/vaapi/gstvaapitypes.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + * gst-libs/gst/vaapi/gstvaapivalue.c: + * gst-libs/gst/vaapi/gstvaapivalue.h: + libs: add rate-control attributes. + Add GstVaapiRateControl types and GType values in view to supporting + rate controls for encoding. This is meant to be used for instance in + GstVaapiContext. + Signed-off-by: Gwenole Beauchesne + +2013-11-22 11:56:51 +0100 Gwenole Beauchesne + + * configure.ac: + Bump version for development. + +2013-11-22 11:28:09 +0100 Gwenole Beauchesne + + * gst/vaapi/Makefile.am: + build: fix for Wayland headers not in standard include dirs. + Fix build when Wayland headers don't live in plain system include dirs + like /usr/include but rather in /usr/include/wayland for instance. + Original patch written by Dominique Leuenberger + https://bugzilla.gnome.org/show_bug.cgi?id=712282 + +2013-11-14 10:58:37 +0000 Ross Burton + + * gst-libs/gst/vaapi/Makefile.am: + build: link libgstvaapi-wayland against videoutils. + This library is using symbols that don't exist in GStreamer 0.10 so + it needs to link to built-in implementation (libgstvaapi-videoutils). + https://bugzilla.gnome.org/show_bug.cgi?id=712282 + Signed-off-by: Ross Burton + Signed-off-by: Gwenole Beauchesne + +2013-11-22 11:15:57 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst/vaapi/gstvaapipostproc.c: + vaapostproc: fix memory leaks. + Destroy VPP output surface pool on exit. Also avoid a possible crash + in double-free situation caused by insufficiently reference counted + array of formats returned during initialization. + +2013-11-22 10:19:06 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + vaapipostproc: fix and optimize advanced deinterlacing mode. + Fix advanced deinterlacing modes with VPP to track only up to 2 past + reference buffers. This used to be 3 past reference buffers but this + doesn't fit with the existing decode pipeline that only has 4 extra + scratch surfaces. + Also optimize references tracking to be only enabled when needed, i.e. + when advanced deinterlacing mode is used. This means that we don't + need to track past references for basic bob or weave deinterlacing. + +2013-11-22 10:04:45 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: fix "mixed" mode deinterlacing. + In "mixed" interlaced streams, the buffer contains additional flags that + specify whether the frame contained herein is interlaced or not. This means + that we can alternatively get progressive or interlaced frames. Make sure + to disable deinterlacing at the VPP level when the source buffer is no longer + interlaced. + +2013-11-22 09:49:30 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: fix memory leaks with advanced deinterlacing. + Fix memory leaks with advanced deinterlacing, i.e. when we keep track + of past buffers. Completely reset the deinterlace state, thus destroying + any buffer currently held, on _start(), _stop() and _destroy(). + +2013-11-22 06:59:51 +0100 Gwenole Beauchesne + + * README: + README: updates. + - GStreamer 1.2 APIs are supported ; + - Video Processing (VA/VPP) features. + +2013-11-22 06:45:22 +0100 Gwenole Beauchesne + + * README: + README: update for GStreamer >= 1.0.x and VPP features. + +2013-11-22 06:37:12 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/glibcompat.h: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.h: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.h: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.h: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.h: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.h: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.h: + * gst-libs/gst/vaapi/gstvaapidisplay_drm_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.c: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.h: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.h: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplaycache.c: + * gst-libs/gst/vaapi/gstvaapidisplaycache.h: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst-libs/gst/vaapi/gstvaapiimagepool.c: + * gst-libs/gst/vaapi/gstvaapiimagepool.h: + * gst-libs/gst/vaapi/gstvaapiminiobject.h: + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapiobject.h: + * gst-libs/gst/vaapi/gstvaapiobject_priv.h: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapisurface_priv.h: + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy_priv.h: + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapitexture.h: + * gst-libs/gst/vaapi/gstvaapitypes.h: + * gst-libs/gst/vaapi/gstvaapiutils_x11.c: + * gst-libs/gst/vaapi/gstvaapiutils_x11.h: + * gst-libs/gst/vaapi/gstvaapivalue.c: + * gst-libs/gst/vaapi/gstvaapivalue.h: + * gst-libs/gst/vaapi/gstvaapivideopool.c: + * gst-libs/gst/vaapi/gstvaapivideopool.h: + * gst-libs/gst/vaapi/gstvaapivideopool_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_drm.c: + * gst-libs/gst/vaapi/gstvaapiwindow_drm.h: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.h: + * gst-libs/gst/vaapi/gstvaapiwindow_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11_priv.h: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapidecode.h: + * gst/vaapi/gstvaapidownload.h: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapipostproc.h: + * gst/vaapi/gstvaapisink.h: + * gst/vaapi/gstvaapivideoconverter_glx.h: + * tests/image.c: + * tests/image.h: + * tests/output.h: + * tests/test-display.c: + * tests/test-jpeg.c: + * tests/test-jpeg.h: + * tests/test-mpeg4.c: + * tests/test-mpeg4.h: + * tests/test-surfaces.c: + * tests/test-windows.c: + legal: update copyright notice dates. + +2013-11-22 05:57:18 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/glibcompat.h: + * gst-libs/gst/vaapi/gstcompat.h: + * gst-libs/gst/vaapi/gstvaapicodec_objects.c: + * gst-libs/gst/vaapi/gstvaapicodec_objects.h: + * gst-libs/gst/vaapi/gstvaapicompat.h: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapidebug.h: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_dpb.c: + * gst-libs/gst/vaapi/gstvaapidecoder_dpb.h: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.h: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.h: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.h: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.h: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * gst-libs/gst/vaapi/gstvaapidecoder_unit.c: + * gst-libs/gst/vaapi/gstvaapidecoder_unit.h: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.h: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.h: + * gst-libs/gst/vaapi/gstvaapidisplay_drm_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.c: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.h: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplaycache.c: + * gst-libs/gst/vaapi/gstvaapidisplaycache.h: + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapifilter.h: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst-libs/gst/vaapi/gstvaapiimage_priv.h: + * gst-libs/gst/vaapi/gstvaapiimagepool.c: + * gst-libs/gst/vaapi/gstvaapiimagepool.h: + * gst-libs/gst/vaapi/gstvaapiminiobject.c: + * gst-libs/gst/vaapi/gstvaapiminiobject.h: + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapiobject.h: + * gst-libs/gst/vaapi/gstvaapiobject_priv.h: + * gst-libs/gst/vaapi/gstvaapiparser_frame.c: + * gst-libs/gst/vaapi/gstvaapiparser_frame.h: + * gst-libs/gst/vaapi/gstvaapipixmap.c: + * gst-libs/gst/vaapi/gstvaapipixmap.h: + * gst-libs/gst/vaapi/gstvaapipixmap_priv.h: + * gst-libs/gst/vaapi/gstvaapipixmap_x11.c: + * gst-libs/gst/vaapi/gstvaapipixmap_x11.h: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.h: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapisurface_priv.h: + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy_priv.h: + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapitexture.h: + * gst-libs/gst/vaapi/gstvaapitypes.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + * gst-libs/gst/vaapi/gstvaapiutils_glx.h: + * gst-libs/gst/vaapi/gstvaapiutils_x11.c: + * gst-libs/gst/vaapi/gstvaapiutils_x11.h: + * gst-libs/gst/vaapi/gstvaapivalue.c: + * gst-libs/gst/vaapi/gstvaapivalue.h: + * gst-libs/gst/vaapi/gstvaapivideopool.c: + * gst-libs/gst/vaapi/gstvaapivideopool.h: + * gst-libs/gst/vaapi/gstvaapivideopool_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_drm.c: + * gst-libs/gst/vaapi/gstvaapiwindow_drm.h: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.h: + * gst-libs/gst/vaapi/gstvaapiwindow_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11_priv.h: + * gst-libs/gst/vaapi/gstvaapiworkarounds.h: + * gst-libs/gst/vaapi/sysdeps.h: + * gst-libs/gst/vaapi/video-format.c: + * gst-libs/gst/vaapi/video-format.h: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapidownload.h: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + * gst/vaapi/gstvaapiupload.c: + * gst/vaapi/gstvaapiupload.h: + * gst/vaapi/gstvaapiuploader.c: + * gst/vaapi/gstvaapiuploader.h: + * gst/vaapi/gstvaapivideobuffer.c: + * gst/vaapi/gstvaapivideobuffer.h: + * gst/vaapi/gstvaapivideobufferpool.c: + * gst/vaapi/gstvaapivideobufferpool.h: + * gst/vaapi/gstvaapivideocontext.c: + * gst/vaapi/gstvaapivideocontext.h: + * gst/vaapi/gstvaapivideoconverter_glx.c: + * gst/vaapi/gstvaapivideoconverter_glx.h: + * gst/vaapi/gstvaapivideoconverter_x11.c: + * gst/vaapi/gstvaapivideoconverter_x11.h: + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + * gst/vaapi/gstvaapivideometa.c: + * gst/vaapi/gstvaapivideometa.h: + * gst/vaapi/gstvaapivideometa_texture.c: + * gst/vaapi/gstvaapivideometa_texture.h: + * tests/codec.c: + * tests/codec.h: + * tests/decoder.c: + * tests/decoder.h: + * tests/image.c: + * tests/image.h: + * tests/output.c: + * tests/output.h: + * tests/simple-decoder.c: + * tests/test-decode.c: + * tests/test-decode.h: + * tests/test-display.c: + * tests/test-filter.c: + * tests/test-h264.c: + * tests/test-h264.h: + * tests/test-jpeg.c: + * tests/test-jpeg.h: + * tests/test-mpeg2.c: + * tests/test-mpeg2.h: + * tests/test-mpeg4.c: + * tests/test-mpeg4.h: + * tests/test-surfaces.c: + * tests/test-textures.c: + * tests/test-vc1.c: + * tests/test-vc1.h: + * tests/test-windows.c: + legal: add per-file authorship information. + Credit original authors on a per-file basis as we cannot expect people + to know all country-specific rules, or bother browsing through the git + history. + +2013-11-21 23:52:43 +0100 Gwenole Beauchesne + + * NEWS: + * configure.ac: + 0.5.7. + +2013-11-21 23:51:59 +0100 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2013-11-21 23:17:59 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.h: + decoder: don't include obsolete headers. + The header was removed from the public + set of APIs. So, don't make public headers (gstvaapidecoder.h) depend + on private files. + +2013-11-18 16:20:43 +0100 Gwenole Beauchesne + + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: add initial support for GStreamer 1.2. + Port vaapipostproc element to GStreamer 1.2. Support is quite minimal + right now so that to cope with auto-plugging issues/regressions. e.g. + this happens when the correct set of expected caps are being exposed. + This means that, currently, the proposed caps are not fully accurate. + +2013-11-01 10:22:17 +0800 Halley Zhao + + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + vaapipostproc: add support for denoise and sharpen filters. + Signed-off-by: Gwenole Beauchesne + +2013-11-21 19:52:56 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + vaapipostproc: add support for advanced deinterlacing. + Add initial support for advanced deinterlacing. The history buffer + size is arbitrarily set to 3 references for now. + +2013-11-21 22:32:03 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: fix deinterlacing with VPP. + Fix basic deinterlacing flags provided to gst_vaapi_set_deinterlacing() + for the first field. Render flags were supplied instead of the actual + deinterlacing flags (deint_flags). + +2013-11-21 15:08:55 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: fix transform caps. + Fix GstBaseTransform::transform_caps() implementation to always return + the complete set of allowed sink pad caps (unfixated) even if the src + pad caps we are getting are fixated. Rationale: there are just so many + possible combinations, and it was wrong to provide a unique set anyway. + As a side effect, this greatly simplifies the ability to derive src pad + caps from fixated sink pad caps. + +2013-11-01 10:31:13 +0800 Halley Zhao + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapifilter.h: + filter: add helper to specify references for deinterlacing. + Add gst_vaapi_fitler_set_deinterlacing_references() API to submit the + list of surfaces used for forward or backward reference in advanced + deinterlacing mode, e.g. Motion-Adaptive, Motion-Compensated. + The list of surfaces used as deinterlacing references shall be live + until the next call to gst_vaapi_filter_process(). + Signed-off-by: Gwenole Beauchesne + +2013-11-21 18:44:46 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapifilter.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst/vaapi/gstvaapipostproc.c: + * tests/test-filter.c: + filter: fix semantics of deinterlacing flags. + Fix deinterlacing flags to make more sense. The TFF (top-field-first) + flag is meant to specify the organization of reference frames used in + advanced deinterlacing modes. Introduce the more explicit flag TOPFIELD + to specify that the top-field of the supplied input surface is to be + used for deinterlacing. Conversely, if not set, this means that the + bottom field of the supplied input surface will be used instead. + +2013-11-21 17:20:28 +0100 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapifilter.h: + filter: add helpers to check for supported/active operation. + Add a couple of helper functions: + - gst_vaapi_filter_has_operation(): checks whether the VA driver + advertises support for the supplied operation ; + - gst_vaapi_filter_use_operation(): checks whether the supplied + operation was already enabled to its non-default value. + +2013-11-20 15:10:17 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + libs: fix GstVaapiSurfaceProxy destroy notify call site. + The user-defined destroy notify function is meant to be called only when + the surface proxy was fully released, i.e. once it actually released the + VA surface back to the underlying pool. + +2013-08-29 13:44:22 +0800 XuGuangxin + + * gst-libs/gst/vaapi/gstvaapivideopool.c: + * gst-libs/gst/vaapi/gstvaapivideopool_priv.h: + libs: make GstVaapiVideoPool thread-safe. + https://bugzilla.gnome.org/show_bug.cgi?id=707108 + Signed-off-by: Gwenole Beauchesne + +2013-08-29 14:04:06 +0800 XuGuangxin + + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + libs: robustify decoder objects and surface proxy initialization. + Fix GstVaapiPicture, GstVaapiSlice and GstVaapiSurfaceProxy initialization + sequences to have the expected default values set beforehand in case of an + error raising up further during creation. i.e. make it possible to cleanly + destroy those partially initialized objects. + https://bugzilla.gnome.org/show_bug.cgi?id=707108 + Signed-off-by: Gwenole Beauchesne + +2013-11-21 11:01:41 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: fix decoder flush. + There are situations where gst_video_decoder_flush() is called, and + this subsequently produces a gst_video_decoder_reset() that kills the + currently active GstVideoCodecFrame. This means that it no longer + exists by the time we reach GstVideoDecoder::finish() callback, thus + possibly resulting in a crash if we assumed spare data was still + available for decode (current_frame_size > 0). + Try to honour GstVideoDecoder::reset() behaviour from GStreamer 1.0 + that means a flush, thus performing the actual operations there like + calling gst_video_decoder_have_frame() if pending data is available. + +2013-11-20 19:21:05 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + vaapidecode: fix dead-locks with decoder task. + Review all interactions between the main video decoder stream thread + and the decode task to derive a correct sequence of operations for + decoding. Also avoid extra atomic operations that become implicit under + the GstVideoDecoder stream lock. + +2013-08-29 14:12:10 +0800 XuGuangxin + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: fix hard reset for seek cases. + Fix hard reset for seek cases by flushing the GstVaapiDecoder queue + and completely purge any decoded output frame that may come out from + it. At this stage, the GstVaapiDecoder shall be in a complete clean + state to start decoding over new buffers. + Signed-off-by: Gwenole Beauchesne + +2013-08-29 14:12:10 +0800 XuGuangxin + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + vaapidecode: drop decode timeout, always wait for a free surface. + vaapidecode used to wait up to one second past the expected time of + presentation for the last decoded frame. This is not realistic in + practice when it comes to video pause/resume. Changed behaviour to + unconditionnally wait for a free VA surface prior to continuing the + decoding. The decode task will continue pushing the output frames to + the downstream element while also reporting errors at the same time + to the main thread. + https://bugzilla.gnome.org/show_bug.cgi?id=707108 + Signed-off-by: Gwenole Beauchesne + +2013-11-20 10:56:28 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: fix srcpad caps for GStreamer 1.2. + The srcpad caps exposed for GStreamer 1.2 were missing any useful info + like framerate, pixel-aspect-ratio, interlace-mode et al. Not to mention + that it relied on possibly un-initialized data. Fix srcpad caps to be + initialized from a sanitized copy of GstVideoDecoder output state caps. + Note: the correct way to expose the srcpad caps triggers an additional + issue in core GStreamer auto-plugging capabilities as the correct caps + to be exposed should be format=ENCODED with memory:VASurface caps feature + at the minimum. In some situations, we could determine the underlying + VA surface format, but this is not always possible. e.g. cases where it + is not allowed to expose the underlying VA surface data, or when the + VA driver implementation cannot actually provide such information. + +2013-11-20 10:45:23 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapisink.c: + plugins: streamline VA formats exposed in caps to a realistic set. + Currently, the decoder only supports YUV 4:2:0 output. So, expose the + output formats for GStreamer 1.2 in caps to a realistic subset. This + means NV12, I420 or YV12 but also ENCODED if we cannot determine the + underlying VA surface format, or if it is actually not allowed to get + access to the surface contents. + +2013-11-20 10:37:36 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapisink.c: + plugins: expose the expected format for GstVideoGLTextureUploadMeta. + Fix vaapidecode srcpad caps to only expose RGBA video format for the + meta:GstVideoGLTextureUploadMeta feature. That's only what is supported + so far. Besides, drop this meta from the vaapisink sinkpad caps since + we really don't support that for rendering. + https://bugzilla.gnome.org/show_bug.cgi?id=711828 + +2013-11-18 18:25:21 +0100 Gwenole Beauchesne + + * configure.ac: + configure: automatically detect GStreamer API version. + Automatically detect GStreamer API version. The --with-gstreamer-api + configure option now defaults to "autodetect" and configure then tries + to derive the GStreamer API version from the highest version based on + what pkg-config --modversion would report. + https://bugzilla.gnome.org/show_bug.cgi?id=711657 + +2013-11-01 13:43:11 +0800 Wind Yuan + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: fix support for raw YUV data upload on GStreamer 1.0. + Fix raw YUV data uploaded as in the following pipeline: + $ gst-launch-1.0 filesrc video.yuv ! videoparse ! vaapipostproc ! vaapisink + The main reason why it failed was that the videoparse element simply + allocates GstBuffer with raw data chunk'ed off the sink pad without + any prior knowledge of the actual frame info. i.e. it basically just + calls gst_adapter_take_buffer(). + We could avoid the extra copy performed in vaapipostproc if the videoparse + element was aware of the downstream pool and bothers copying line by + line, for each plane. This means that, for a single frame per buffer, + the optimizatin will be to allocate the video buffer downstream, map + it, and copy each line that is coming through until we need to fills + in the successive planes. + Still, optimized raw YUV uploads already worked with the following: + $ gst-launch-1.0 videotestsrc ! vaapipostproc ! vaapisink + https://bugzilla.gnome.org/show_bug.cgi?id=711250 + [clean-ups, fixed error cases to unmap and unref outbuf] + Signed-off-by: Gwenole Beauchesne + +2013-11-16 07:02:24 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: try to downgrade deinterlace-method when needed. + If the currently selected deinterlacing method is not supported by the + underlying hardware, then try to downgrade the method to a supported one. + At the minimum, basic bob-deinterlacing shall always be supported. + +2013-11-15 19:04:07 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: add initial support for deinterlacing with VPP. + Allow basic bob-deinterlacing to work when VPP is enabled. Currently, + this only covers bob-deinterlacing when the output pixel format is + explicitly set. + +2013-11-15 17:14:04 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: fix build on 64-bit platforms with GStreamer 0.10. + The size argument for GstBaseTransform::transform_size() hook is a + guint in GStreamer 0.10 APIs but a gsize in GStreamer >= 1.0.X APIs. + +2013-10-18 18:08:25 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + vaapipostproc: add initial support for scaling. + Add initial support for basic scaling with size specified through the + "width" and "height" properties. If either user-provided dimension is + zero and "force-aspect-ratio" is set to true (the default), then the + other dimension is scaled to preserve the aspect ratio. + +2013-10-18 18:08:25 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + vaapipostproc: add initial support for color conversion. + If VPP is available, we always try to implicitly convert the source + buffer to the "native" surface format for the underlying accelerator. + This means that no optimization is performed yet to propagate raw YUV + buffers to the downstream element as is, if VPP is available. i.e. it + will always cause a color conversion. + +2013-10-16 11:23:03 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: fix bug when user disabled deinterlacing. + Fix pipeline error / hang when the user disabled deinterlacing through + the deinterlace-mode=disabled property setting. + +2013-10-16 11:20:50 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + vaapipostproc: factor out operations to be applied into flags. + Even if we only support deinterlacing for now, use flags to specify + which filters are to be applied to each frame we receive in transform(). + This is preparatory work for integrating new filters. + +2013-10-04 15:37:24 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + vaapipostproc: add support for raw YUV video source buffers. + Allow video processing from raw YUV buffers coming from the sink pad, + while still producing a VA surface for the downstream elements. + +2013-10-04 16:00:56 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: add support for "mixed" interlace mode. + Add support for "mixed" interlace-mode, whereby the video frame buffer + shall be deinterlaced only if its flags mention that's actually an + interlaced frame buffer. + +2013-10-03 19:04:07 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstcompat.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + * gst/vaapi/gstvaapivideobuffer.c: + * gst/vaapi/gstvaapivideobuffer.h: + vaapipostproc: rework plug-in element. + Rewrite the vaapipostproc plug-in element so that it derives from + GstBaseTransform, thus simplifying the caps negotiation process. + +2013-10-09 17:25:10 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideobufferpool.c: + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + plugins: fix and optimize check for buffer pool allocator params. + Reset the buffer pool allocator only if the config caps changed in a + sensible way: format or resolution change. i.e. don't bother with + other caps like colorimetry et al. as this doesn't affect the way to + allocate VA surfaces or images. + +2013-10-09 10:33:55 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideomemory.c: + plugins: enable memory maps for read & write with direct-rendering. + Enable read and write mappings only if direct-rendering is supported. + Otherwise, this means that we may need to download data from the VA + surface first for correctness, even if the VA surface doesn't need to + be read at all. i.e. sometimes, READWRITE mappings are meant for + surfaces that are written to first, and read afterwards for further + processing. + https://bugzilla.gnome.org/show_bug.cgi?id=704078 + +2013-10-09 10:06:40 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideomemory.c: + plugins: fix check for direct-rendering support. + Fix check for direct-rendering if the creation of VA surfaces with + an explicit pixel format is not support, e.g. VA-API < 0.34.0, and + that we tried to allocate a VA surface based on the corresponding + chroma type. i.e. in that particular case, we have to make sure that + the derived image has actually the expected format. + +2013-10-09 09:47:18 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideobufferpool.c: + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + plugins: fix buffer pool reset_buffer() to reset memory resources. + Fix GstVaapiVideoBufferPool::reset_buffer() to reset the underlying + memory resources, and more particularly the VA surface proxy. Most + importantly, the GstVaapiVideoMeta is retained. Cached surface in + memory are released, thus triggering a new allocation the next time + we need to map the buffer. + +2013-10-09 09:33:56 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + plugins: fix GstVaapiVideoMemory to allocate VA surface proxies. + Make sure GstVaapiVideoMemory allocates VA surface proxies from a + pool stored in the parent VA memory allocator. + This fixes the following scenario: + - VA video buffer 1 is allocated from a buffer pool + - Another video buffer is created, and inherits info from buffer 1 + - Buffer 1 is released, thus pushing it back to the buffer pool + - New buffer alloc request comes it, this yields buffer 1 back + - At this stage, buffers 1 and 2 still share the same underlying VA + surface, but buffer 2 was already submitted downstream for further + processing, thus conflicting with additional processing we were + about to perform on buffer 1. + Maybe the core GstBufferPool implementation should have been fixed + instead to actually make sure that the returned GstBuffer memory we + found from the pool is writable? + +2013-10-04 19:34:32 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapiuploader.c: + plugins: create a proxy for GstVaapiUploader allocated buffers. + Always make sure to allocate a VA surface proxy for GstVaapiUploader + allocated buffers, i.e. make gst_vaapi_uploader_get_buffer() allocate + a proxy surface. + This fixes cases where we want to retain the underlying surface longer, + instead of releasing it back to the surface pool right away. + +2013-10-04 19:30:36 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapipostproc.c: + plugins: add helper function to disable deinterlacing in caps. + Add gst_caps_set_interlaced() helper function that would reset the + interlace-mode field to "progressive" for GStreamer >= 1.0, or the + interlaced field to "false" for GStreamer 0.10. + +2013-10-01 18:26:39 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapifilter.c: + filter: fix memory leak of VPP operations. + Fix ensure_operations() to release the VPP operations array if non + NULL, prior to returning to the caller. The former function was also + renamed to a more meaningful get_operations() since the caller owns + the returned array that needs to be released. + +2013-09-04 13:53:25 +0800 Zhao Halley + + * gst-libs/gst/vaapi/gstvaapifilter.c: + filter: fix first-time operation lookup. + Fix first-time operation lookup through find_operation() if the set + of supported operations was not initially determined through the + gst_vaapi_filter_get_operations() helper function. + Signed-off-by: Gwenole Beauchesne + +2013-09-04 13:53:25 +0800 Zhao Halley + + * gst-libs/gst/vaapi/gstvaapifilter.c: + filter: fix colorbalance related subtypes. + Fix intiialization of GstVaapiFilterOpData for colorbalance related + operations. In particular, fill in the va_subtype field accordingly. + Signed-off-by: Gwenole Beauchesne + +2013-09-30 17:08:12 +0200 Víctor Manuel Jáquez Leal + + * gst-libs/gst/vaapi/gstvaapifilter.c: + filter: fix VA-API 0.34.0 symbol guards. + VASurfaceAttrib and VAProcFilterParameterBufferType are symbols + that need to be guarded for libva 0.34 and 0.33, respectively. + https://bugzilla.gnome.org/show_bug.cgi?id=709102 + Signed-off-by: Gwenole Beauchesne + +2013-10-01 17:57:11 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapisink.c: + plugins: hanle the context query in any pad. + Also this patch simplifies the code, since now the query is common for the + decoder and the sink. + https://bugzilla.gnome.org/show_bug.cgi?id=709200 + +2013-10-01 12:09:44 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapivideocontext.c: + plugins: query upstream element for a GstContext. + Fix gst_vaapi_video_context_prepare() to also query upstream elements + for a valid GstContext. Improve comments regarding the steps used to + lookup or build that context, thus conforming to the GstContext API + recommendations. + https://bugzilla.gnome.org/show_bug.cgi?id=709112 + Signed-off-by: Gwenole Beauchesne + +2013-09-26 15:21:24 +0200 Gwenole Beauchesne + + * configure.ac: + * debian.upstream/control.in: + Fix detection and packaging of GStreamer 1.2.x builds. + The GStreamer 1.2.x packages sticked to the naming convention for 1.0.x + packages, i.e. -1.0 suffix. However, for gstreamer-vaapi packaging + purposes, update the versioning to -1.2 suffix instead. + +2013-07-15 13:41:00 +0200 Víctor Manuel Jáquez Leal + + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapivideometa_texture.c: + * gst/vaapi/gstvaapivideometa_texture.h: + plugins: add support for GstVideoGLTextureUploadMeta. + If the allocation meta GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE is + requested, and more specifically under a GLX configuration, then add + the GstVideoGLTextureUploadMeta to the output buffer. + https://bugzilla.gnome.org/show_bug.cgi?id=703236 + Signed-off-by: Gwenole Beauchesne + +2013-07-04 11:03:52 +0300 Sreerenj Balachandran + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapivideomemory.h: + plugins: add support for GstCaps features. + Move VA video buffer memory from "video/x-surface,type=vaapi" format, + as expressed in caps, to the more standard use of caps features. i.e. + add "memory:VASurface" feature attribute to the associated caps. + https://bugzilla.gnome.org/show_bug.cgi?id=703271 + Signed-off-by: Gwenole Beauchesne + +2013-07-12 12:58:57 -0400 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapisink.c: + plugins: improve ::query() debugging messages. + Fix gst_vaapidecode_query() to correctly display the query type name, + instead of randomly displaying that we shared the underlying display. + Also add debug info for the GstVaapiSink::query() handler, i.e. the + supplied query type name actually. + Signed-off-by: Gwenole Beauchesne + +2013-07-12 12:58:57 -0400 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapisink.c: + plugins: add support for GstContext API. + Add support for the new GstContext API from GStreamer 1.2.x. + - implement the GstElement::set_context() hook ; + - reply to the `context' query from downstream elements. + https://bugzilla.gnome.org/show_bug.cgi?id=703235 + Signed-off-by: Gwenole Beauchesne + +2013-05-22 12:07:52 -0400 Víctor Manuel Jáquez Leal + + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapivideocontext.c: + * gst/vaapi/gstvaapivideocontext.h: + plugins: add compat layer for GstVideoContext. + Add thin compatibility layer for the deprecated GstVideoContext API. + For GStreamer API >= 1.2, this involves the following two functions: + - gst_vaapi_video_context_prepare(): queries if a context is already + set in the pipeline ; + - gst_vaapi_video_context_propagate(): propagates the newly-created + context to the rest of the pipeline. + https://bugzilla.gnome.org/show_bug.cgi?id=703235 + Signed-off-by: Gwenole Beauchesne + +2013-05-21 12:42:39 -0400 Víctor Manuel Jáquez Leal + + * configure.ac: + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapivideobuffer.c: + plugins: initial port to GStreamer 1.2. + Port vaapidecode and vaapisink plugins to GStreamer API >= 1.2. This + is rather minimalistic so that to test the basic functionality. + Disable vaapipostproc plugin for now as further polishing is needed. + Also disable GstVideoContext interface support since this API is now + gone in 1.2.x. This is preparatory work for GstContext support. + https://bugzilla.gnome.org/show_bug.cgi?id=703235 + Signed-off-by: Gwenole Beauchesne + +2013-09-24 16:21:11 +0200 Gwenole Beauchesne + + * tests/simple-decoder.c: + tests: simple-decoder: fix for non-X11 backends. + Don't try to create pixmaps if we have not requested that feature. This + fixes execution for non-X11 backends, and most specifically DRM video + output mode. + +2013-09-24 16:22:59 +0200 Gwenole Beauchesne + + * ext/codecparsers: + codecparsers: update to gst-vaapi-branch commit b33bd32. + b33bd32 jpeg: fix and optimize scan for next marker code + +2013-09-23 19:14:56 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + jpeg: fix calculation of MCU count. + Fix calculation of MCU count for image sizes that are not a multiple + of 8 pixels in either dimension, but also for non-common sampling + factors like 4:2:2 in non-interleaved mode. + +2013-09-23 16:49:41 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + jpeg: add support for multiscan images. + Add support for images with multiple scans per frame. The Huffman table + can be updated before SOS, and thus possibly requiring multiple uploads + of Huffman tables to the VA driver. So, the latter must be able to cope + with multiple VA buffers of type 'huffman-table' and with the correct + sequential order. + +2013-09-23 11:41:52 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + jpeg: improve robustness when packets are missing. + Improve robustness when some expected packets where not received yet + or that were not correctly decoded. For example, don't try to decode + a picture if there was no valid frame headers. + +2013-09-20 16:46:43 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + jpeg: minor clean-ups. + Improve debugging and error messages. Rename a few variables to fit the + existing naming conventions. Change some fatal asserts to non-fatal + error codes. + +2013-09-20 10:12:08 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + jpeg: rework and optimize parser. + Split the input buffer data into decoder units that represent a JPEG + segment. Handle scan decoder unit specifically so that it can include + both the scan header (SOS) but also any other ECS or RSTi segment. + That way, we parse the input buffer stream only once at the gst-vaapi + level instead of (i) in gst_vaapi_decoder_jpeg_parse() to split the + stream into frames SOI .. EOI and (ii) in decode_buffer() to further + determine segment boundaries and decode them. + In practice, this is a +15 to +25% performance improvement. + +2013-09-17 14:29:54 +0800 Junfeng Xu + + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + jpeg: handle comment segments. + Fix decode_buffer() function to gracefully skip comment (COM) segments. + This fixes decoding of streams generated by certain cameras, e.g. like + the Logitech Pro C920. + https://bugzilla.gnome.org/show_bug.cgi?id=708208 + Signed-off-by: Junfeng Xu + +2013-09-18 17:59:44 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + jpeg: fix determination of image bounds. + Look for the exact image bounds characterised by the and + markers. Use the gst_jpeg_parse() codec parser utility function to + optimize the lookup for the next marker segment. + https://bugzilla.gnome.org/show_bug.cgi?id=707447 + +2013-09-10 15:46:09 +0800 Junfeng Xu + + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + jpeg: fix calculation of offset to next marker segment. + Fix calculation of the offset to the next marker segment since the + correction of the codecparser part to match the API specification. + i.e. the GstJpegMarkerSegment.size field represents the size in bytes + of the segment minus any marker prefix. + https://bugzilla.gnome.org/show_bug.cgi?id=707447 + Signed-off-by: Junfeng Xu + +2013-09-20 18:30:18 +0200 Gwenole Beauchesne + + * ext/codecparsers: + codecparsers: update to gst-vaapi-branch commit 23c7dde. + 23c7dde jpeg: fix calculation of segment size + +2013-08-31 16:00:05 +0200 Gwenole Beauchesne + + * configure.ac: + Bump version for development. + +2013-08-31 15:47:33 +0200 Gwenole Beauchesne + + * NEWS: + * configure.ac: + 0.5.6. + +2013-08-31 15:46:25 +0200 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2013-08-15 17:59:37 +0800 Wind Yuan + + * configure.ac: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + configure: fix detection of VA/JPEG decoding API. + Fix detection of VA/JPEG decoding API with non-standard libva packages. + More precisely, some packages were shipping with a header that + did not include . + https://bugzilla.gnome.org/show_bug.cgi?id=706055 + Signed-off-by: Gwenole Beauchesne + +2013-04-18 19:49:42 +0800 Zhao Halley + + * gst/vaapi/gstvaapisink.c: + vaapisink: ensure the uploader is setup for upstream allocated buffers. + In GStreamer 0.10 builds, make sure that the GstVaapiUploader helper + is setup in case upstream elements allocate buffers themselves without + honouring our GstVaapiSink::bufer_alloc() hook. + In particular, this fixes support for OGG video streams with WebKit. + https://bugzilla.gnome.org/show_bug.cgi?id=703934 + Signed-off-by: Gwenole Beauchesne + +2013-08-29 19:07:34 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + vaapisink: simplify get_render_buffer() for GStreamer 0.10 builds. + Implement and use gst_vaapisink_get_render_buffer() for GStreamer 0.10 + builds as well. + +2013-08-29 18:34:57 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + vaapisink: handle raw buffers not created from VA video buffer pool. + Handle raw video buffers that were not created from a VA video buffer + pool. Use the generic GstVideo API to copy buffers in GStreamer 1.0.x + builds instead of the GstVaapiUploader. + https://bugs.freedesktop.org/show_bug.cgi?id=55818 + +2013-08-29 19:33:02 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: remove extraneous size information from allowed caps. + Fix _getcaps() implementation to not report codecs with size information + filled in the returned caps. That's totally useless nowadays. Ideally, + this is a hint to insert a video parser element, thus allowing future + optimizations, but this is not a strict requirement for gstreamer-vaapi, + which is able to parse the elementary bitstreams itself. + https://bugzilla.gnome.org/show_bug.cgi?id=704734 + +2013-07-30 14:05:39 +0800 Guangxin.Xu + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + vaapidecode: submit the last frame from output adapter to decoder. + If there is no frame delimiter at the end of the stream, e.g. no + end-of-stream or end-of-sequence marker, and that the current frame + was fully parsed correctly, then assume that last frame is complete + and submit it to the decoder. + https://bugzilla.gnome.org/show_bug.cgi?id=705123 + Signed-off-by: Guangxin.Xu + Signed-off-by: Gwenole Beauchesne + +2013-08-29 11:55:05 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + vaapidecode: push all decoded frames from within the task. + Make sure to push all decoded frames from the task so that the unlying + VA surfaces could all be rendered from the same thread. + +2013-08-27 18:24:12 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + wayland: render the raw surface if VPP failed. + As a last resort, if video processing capabilities (VPP) are not available, + or they did not produce anything conclusive enough, then try to fallback to + the original rendering code path whereby the whole VA surface is rendered + as is, no matter of video cropping or deinterlacing requests. + Note: under those conditions, the visual outcome won't be correct but at + least, something gets displayed instead of bailing out. + +2013-08-27 18:20:08 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + wayland: add supporting for video processing. + Try to use VA/VPP processing capabilities to handle video cropping and + additional rendering flags that may not be directly supported by the + underlying hardware when exposing a suitable Wayland buffer for the + supplied VA surface. e.g. deinterlacing, different color primaries than + BT.601, etc. + +2013-08-27 16:26:22 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + wayland: add new frame redraw infrastructure. + Update the frame redraw infrastructure with a new FrameState stucture + holds all the necessary information used to display the next pending + surface. + While we are at it, delay the sync operation down to when it is actually + needed. That way, we keep performing additional tasks meanwhile. + +2013-08-27 18:06:10 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapifilter.h: + filter: allow specification of render target regions. + Add support for rendering the source surface to a particular region within + the supplied target surface. The default background color is black. + +2013-08-26 17:14:33 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideobuffer.c: + decode: fix creation of GLX video buffers for GStreamer 0.10. + Fix creation of GstVaapiVideoBuffer objects (i) to have that type for real; + and (ii) to correctly extract the GstSurfaceConverter from the video buffer + object meta. + This fixes support for cluttersink with GStreamer 0.10 builds. + +2013-08-26 16:15:49 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: disable video cropping as picture_display_extension() is missing. + Disable video cropping in MPEG-2 codec because it is partially implemented + and actually because nobody implements it that way, and the standard spec + does not specify the display process either anyway. + Most notably, there are two possible use cases for sequence_display_extension() + horizontal_display_size & vertical_display_size: (i) guesstimating the + pixel-aspect-ratio, or (ii) implement some kind of span & scan process + in conjunction with picture_display_extension() information. + https://bugzilla.gnome.org/show_bug.cgi?id=704848 + +2013-08-16 16:58:58 +0100 Simon Farnsworth + + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + vaapisink: allow scaling to ignore aspect ratio. + Other GStreamer sinks, like xvimagesink, have a force-aspect-ratio property, + which allows you to say that you don't want the sink to respect aspect + ratio. Add the same property to vaapisink. + http://lists.freedesktop.org/archives/libva/2012-September/001298.html + Signed-off-by: Simon Farnsworth + +2013-05-14 15:19:04 +0800 Wind Yuan + + * gst/vaapi/gstvaapisink.c: + vaapisink: fix memory leak of GstVaapiUploader instance. + Make sure gst_vaapisink_ensure_uploader() checks for the existence + of a former GstVaapiUploader instance prior to forcibly creating a + new one. + https://bugzilla.gnome.org/show_bug.cgi?id=703980 + +2013-07-31 16:49:20 +0800 Guangxin.Xu + + * gst/vaapi/gstvaapisink.c: + vaapisink: fix get_caps() implementation for GStreamer 1.0. + Fix GstBaseSink::get_caps() implementation for GStreamer 1.0.X builds + by honouring the filter caps argument. More precisely, this fixes the + following pipeline: gst-launch-1.0 videotestsrc ! vaapisink + https://bugzilla.gnome.org/show_bug.cgi?id=705192 + Signed-off-by: Guangxin.Xu + Signed-off-by: Gwenole Beauchesne + +2013-08-26 11:31:06 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + mpeg4: fix double definition of GstVaapiDecoderMpeg4Class. + This fixes the following issue: + CC libgstvaapi_0.10_la-gstvaapidecoder_mpeg4.lo + gstvaapidecoder_mpeg4.c:113: error: redefinition of typedef + 'GstVaapiDecoderMpeg4Class' + gstvaapidecoder_mpeg4.c:44: note: previous declaration of + 'GstVaapiDecoderMpeg4Class' was here + make[5]: *** [libgstvaapi_0.10_la-gstvaapidecoder_mpeg4.lo] Error 1 + make[5]: Leaving directory + `/builddir/build/BUILD/gstreamer-vaapi-0.5.5.1/gst-libs/gst/vaapi' + https://bugzilla.gnome.org/show_bug.cgi?id=705148 + +2013-07-30 15:59:40 +0200 Gwenole Beauchesne + + * tests/test-filter.c: + tests: filter: add support for deinterlacing. + Add --deinterlace option to enable deinterlacing through explicit VA/VPP + deinterlacing filter. However, if --deinterlace option is not set but the + --deinterlace-flags option is set with "top-field-first", then the very + basic bob deinterlacing filter is set through VA/VPP proc pipeline flags. + +2013-07-17 17:29:41 +0800 Zhao Halley + + * tests/test-filter.c: + tests: filter: add support for denoising and sharpening. + Add --denoise option to enable noise reduction with the level specified + as the option value (float). Likewise, add --sharpen option to enable + sharpening. + Signed-off-by: Gwenole Beauchesne + +2013-07-24 14:31:34 +0200 Gwenole Beauchesne + + * tests/test-filter.c: + tests: filter: add support for frame cropping. + Add support for frame cropping through the --crop-rect|-c argument. + The format used is either 'x' , with origin at (0,0) ; + or full specification with '('? ',' ')'? 'x' . + +2013-07-23 18:00:26 +0200 Gwenole Beauchesne + + * tests/test-filter.c: + tests: filter: dump supported operations and formats. + +2013-07-08 16:54:55 +0800 Zhao Halley + + * tests/Makefile.am: + * tests/test-filter.c: + tests: add initial test for video processing. + Add minimal test case for video processing: scaling and color format + conversion. + Signed-off-by: Gwenole Beauchesne + +2013-07-29 09:23:50 +0800 Zhao Halley + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapifilter.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + filter: add initial support for deinterlacing. + Add basic deinterlacing support, i.e. bob-deinterlacing whereby only + the selected field from the input surface is kept for the target surface. + Setting gst_vaapi_filter_set_deinterlacing() method argument to + GST_VAAPI_DEINTERLACE_METHOD_NONE means to disable deinterlacing. + Also move GstVaapiDeinterlaceMethod definition from vaapipostproc plug-in + to libgstvaapi core library. + Signed-off-by: Gwenole Beauchesne + +2013-07-17 17:40:41 +0800 Zhao Halley + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapifilter.h: + filter: add support for color balance adjustment. + Add ProcAmp (color balance) adjustments for hue, saturation, brightness + and contrast. The respective range for each filter shall be the same as + for the VA display attributes. + Signed-off-by: Gwenole Beauchesne + +2013-07-17 17:37:16 +0800 Zhao Halley + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapifilter.h: + filter: add support for sharpening. + Sharpening is configured with a float value. The supported range is + -1.0 .. 1.0 with 0.0 being the default, and that means no sharpening + operation at all. + Signed-off-by: Gwenole Beauchesne + +2013-07-17 17:29:41 +0800 Zhao Halley + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapifilter.h: + filter: add support for denoising. + Noise reduction is configured with a float value. The supported range + is 0.0 .. 1.0 with 0.0 being the default, and that means no denoise + operation at all. + Signed-off-by: Gwenole Beauchesne + +2013-07-24 14:22:28 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapifilter.h: + filter: add support for frame cropping. + Frame cropping is defined with a GstVaapiRectangle value. The default + behaviour is to treat the source surface as a whole + +2013-07-25 13:55:15 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapifilter.c: + filter: add helper functions. + Add helper functions to ensure an operation VA buffer is allocated to + the right size; that filter caps get parsed and assigned to the right + operation too; and that float parameters are correctly scaled to fit + the reported range from the VA driver. + +2013-07-23 15:52:45 +0200 Gwenole Beauchesne + + * configure.ac: + * docs/reference/libs/libs-docs.xml.in: + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapifilter.c: + * gst-libs/gst/vaapi/gstvaapifilter.h: + Add initial infrastructure for video processing. + Add initial API for video processing: only scaling and color format + conversion operations are supported. + +2013-07-24 11:53:38 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/video-format.c: + * gst-libs/gst/vaapi/video-format.h: + libs: add gst_vaapi_video_format_from_string() helper. + Add gst_vaapi_video_format_from_string() helper function to convert from + a video format string representation to a suitable GstVideoFormat. This + is just an alias to gst_video_format_from_string() for GStreamer 1.0.x + builds, and a proper iteration over all GstVideoFormat string representations + otherwise for earlier GStreamer 0.10.x builds. + +2013-07-24 11:37:23 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/video-format.c: + * gst-libs/gst/vaapi/video-format.h: + libs: add gst_vaapi_video_format_from_va_fourcc() helper. + Add gst_vaapi_video_format_from_va_fourcc() helper that converts from a + VA fourcc value to a suitable GstVideoFormat. + +2013-07-24 11:41:05 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapivalue.c: + * gst-libs/gst/vaapi/gstvaapivalue.h: + libs: add type definitions for GstVaapiPoint and GstVaapiRectangle. + Add helper functions to describe GstVaapiPoint and GstVaapiRectangle + structures as a standard GType. This could be useful to have them + described as a GValue later on. + +2013-07-26 13:57:35 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-docs.xml.in: + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapidisplaycache.h: + libs: drop some public APIs. + Don't expose GstVaapiContext APIs and make them totally private to + libgstvaapi core library. That API would also tend to disappear in + a future revision. Likewise, don't expose GstVaapiDisplayCache API + but keep symbols visible so that the various render backends could + share a common display cache implementation in libgstvaapi. + Try to clean-up the documentation from any stale entry too. + +2013-08-23 18:35:42 +0200 Gwenole Beauchesne + + * tests/image.c: + * tests/image.h: + tests: image: allow creation of images with interleaved patterns. + Add image_generate_full() function to create interleaved color rectangles. + If flags is zero, the whole frame is generated with a unique pattern. If + flags is non-zero, then each field is handled individually. + +2013-08-23 16:25:39 +0200 Gwenole Beauchesne + + * tests/image.c: + tests: image: fix conversion from RGB to YUV. + Fix RGB to YUV conversion to preserve full data range. + +2013-07-26 13:12:28 +0200 Gwenole Beauchesne + + * tests/image.c: + tests: image: try to upload images through vaDeriveImage() too. + On some platforms, vaPutImage() would fail even if it does not involve + color format conversion or scaling, whereas copying raw pixels through + vaDeriveImage() could work instead. + +2013-07-26 10:05:06 +0200 Gwenole Beauchesne + + * tests/image.c: + tests: image: add support for packed YUV formats. + Add support for packed YUV 4:2:2 formats, i.e. YUY2 and UYVY. + +2013-07-25 18:10:40 +0200 Gwenole Beauchesne + + * tests/image.c: + tests: image: fix generation of I420/YV12 images. + U/V planes were reversed, thus producing invalid images. + +2013-07-24 13:55:04 +0200 Gwenole Beauchesne + + * tests/image.c: + tests: image: fix string representation for GstVideoFormat. + +2013-07-26 12:57:19 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst-libs/gst/vaapi/gstvaapiimage_priv.h: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + image: clean image API up. + Don't expose functions that reference a GstVaapiImageRaw, those are + meant to be internal only for implementing subpictures sync. Also add + a few private definitions to avoid functions calls for retrieving + image size and format information. + +2013-07-26 11:43:49 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + image: add gst_vaapi_image_copy() helper. + Add gst_vaapi_image_copy() helper function to copy images of same format + and size. + +2013-07-22 14:53:51 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideoconverter_x11.c: + plugins: handle video cropping in X11 pixmap converter. + Use GstVideoCropMeta in GStreamer 1.0 or any other render rectangle + we could decode from the stream. + +2013-07-22 11:58:33 +0200 Gwenole Beauchesne + + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapivideobuffer.c: + * gst/vaapi/gstvaapivideoconverter_glx.c: + * gst/vaapi/gstvaapivideoconverter_x11.c: + * gst/vaapi/gstvaapivideoconverter_x11.h: + plugins: add support for "x11-pixmap" video converter type. + Install a new video converter that supports X11 pixmap targets for X11 + backends only, or make the GLX converter creation function chain up to + the X11 converter whenever requested. + +2013-07-22 09:36:08 +0200 Gwenole Beauchesne + + * tests/simple-decoder.c: + tests: simple-decoder: add support for pixmap API. + Add support for the new render-to-pixmap API. Avoid flickering on + platforms supporting video overlay by keeping up to 2 intermediate + pixmaps. + +2013-07-22 09:12:21 +0200 Gwenole Beauchesne + + * tests/simple-decoder.c: + tests: simple-decoder: add support for video cropping. + Handle video cropping information attached to a VA surface proxy. + +2013-07-22 09:03:30 +0200 Gwenole Beauchesne + + * tests/output.c: + * tests/output.h: + * tests/test-decode.c: + tests: add support for render-to-pixmap. + Add --pixmap option to test-decode so that to allow copies of VA + surface to an intermediate pixmap and rendering from that pixmap. + Only X11 backends are supported for now. + +2013-07-22 09:00:38 +0200 Gwenole Beauchesne + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11_priv.h: + x11: implement pixmap rendering with RENDER extension. + Use hardware accelerated XRenderComposite() function, from the RENDER + extension, to blit a pixmap to screen. Besides, this can also support + cropping and scaling. + +2013-07-19 15:05:34 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-docs.xml.in: + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h: + * gst-libs/gst/vaapi/gstvaapipixmap_x11.c: + * gst-libs/gst/vaapi/gstvaapipixmap_x11.h: + x11: implement pixmap API. + Implement the new render-to-pixmap API. The only supported pixmap format + that will work is xRGB, with native byte ordering. Others might work but + they were not tested. + +2013-07-22 10:10:40 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiutils_x11.c: + * gst-libs/gst/vaapi/gstvaapiutils_x11.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + x11: update x11_get_geometry() helper function with depth output. + Allow x11_get_geometry() utility function to also return the depth + assigned to the X drawable. + +2013-07-22 10:00:21 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-docs.xml.in: + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapipixmap.c: + * gst-libs/gst/vaapi/gstvaapipixmap.h: + * gst-libs/gst/vaapi/gstvaapipixmap_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_priv.h: + Add initial Pixmap API. + Add API to transfer VA urfaces to native pixmaps. Also add an API to + render a native pixmap, for completeness. In general, rendering to + pixmap would only be useful to certain VA drivers and use cases on + X11 display servers. e.g. GLX_EXT_texture_from_pixmap (TFP) handled + in an upper layer. + +2013-07-22 15:15:48 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/video-format.c: + * gst-libs/gst/vaapi/video-format.h: + libs: add and expose gst_vaapi_video_format_to_string() helper. + This is just a wrapper over gst_video_format_to_string() for older + GStreamer 0.10 builds. + +2013-07-18 02:54:54 -0300 Emilio López + + * gst/vaapi/gstvaapipluginutil.c: + plugins: fix display type comparison in gst_vaapi_create_display(). + After the code got moved to create the gst_vaapi_create_display() helper, + this comparison was not updated to dereference the newly-created + pointer, so the code was comparing the pointer itself to the type, and + therefore failing to retrieve the VA display. + This fixes the following error (and gets gst-vaapi decoding again): + ERROR vaapidecode gstvaapidecode.c:807:gst_vaapidecode_ensure_allowed_caps: failed to retrieve VA display + https://bugzilla.gnome.org/show_bug.cgi?id=704410 + Signed-off-by: Emilio López + +2013-07-17 11:07:39 +0200 Gwenole Beauchesne + + * configure.ac: + Bump version for development. + +2013-07-15 17:49:31 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: don't output dummy pictures. + Mark dummy pictures as output already so that we don't try to submit + them to the upper layer since this is purely internal / temporary + picture for helping the decoder. + +2013-07-15 17:43:34 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + decoder: dispose GstVideoCodecFrame earlier. + Once the picture was output, it is no longer necessary to keep an extra + reference to the underlying GstVideoCodecFrame. So, we can release it + earlier, and maybe subsequently release the associate surface proxy + earlier. + +2013-07-15 14:47:01 +0200 Gwenole Beauchesne + + * NEWS: + * configure.ac: + 0.5.5. + +2013-07-15 14:42:33 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + * gst-libs/gst/vaapi/video-format.c: + * gst-libs/gst/vaapi/video-format.h: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapiuploader.c: + * tests/image.c: + * tests/test-display.c: + Fix new video format API. + Fix new internal video format API, based on GstVideoFormat, to not + clobber with system symbols. So replace the gst_video_format_* prefix + with gst_vaapi_video_format_ prefix, even if the format type remains + GstVideoFormat. + +2013-07-15 14:05:45 +0200 Gwenole Beauchesne + + * configure.ac: + Bump library major version. + Bump the library major version due to API/ABI changes that occurred in + the imaging API. In particular, GstVaapiImageFormat type was replaced + with the standard GstVideoFormat type. All dependent APIs were updated + to match this change. + +2013-07-15 13:44:43 +0200 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2013-06-11 15:11:34 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + decoder: fix memory leak when processing interlaced pictures. + Fix memory leak when processing interlaced pictures and that occurs + because the first field, represented as a GstVideoCodecFrame, never + gets released. i.e. when the picture is completed, this is generally + the case when the second field is successfully decoded, we need to + propagate the GstVideoCodecFrame of the first field to the original + GstVideoDecoder so that it could reclaim memory. + Otherwise, we keep accumulating the first fields into GstVideoDecoder + private frames list until the end-of-stream is reached. The frames + are eventually released there, but too late, i.e. too much memory + may have been consumed. + https://bugzilla.gnome.org/show_bug.cgi?id=701257 + +2013-07-15 11:58:31 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginutil.c: + plugins: simlpify gst_vaapi_create_display() helper. + Simplify gst_vaapi_create_display() helper as gst_vaapi_display_XXX_new() + performs the necessary validation checks for the underlying VA display + prior to returning to the caller. So, if an error occurred, then NULL is + really returned in that case. + +2013-05-24 05:04:01 -0400 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + plugins: add gst_vaapi_create_display() helper. + https://bugzilla.gnome.org/show_bug.cgi?id=703235 + Signed-off-by: Gwenole Beauchesne + +2013-07-12 17:47:07 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideobufferpool.c: + plugins: don't reallocate pool allocator for the same caps. + If the video buffer pool config doesn't have new caps, then it's not + necessary to reinstantiate the allocator. That could be a costly + operation as we could do some extra heavy checking in there. + +2013-07-12 17:14:49 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideomemory.c: + plugins: fix ref counting of GstVaapiVideoMemory allocator. + Fix reference counting issue whereby gst_memory_init() does not hold + an extra reference to the GstAllocator. So, there could be situations + where the last instance of GstVaapiVideoAllocator gets released before + a dangling GstVaapiVideoMemory object, thus possibly leading to a crash. + +2013-07-12 15:15:07 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapiuploader.c: + vaapiupload: use implicit color conversion to NV12. + Always perform conversion of sources buffers to NV12 since this is + the way we tested for this capability in ensure_allowed_caps(). This + also saves memory bandwidth for further rendering. However, this may + not preserve quality since the YUV buffers are down-sampled to 4:2:0. + +2013-07-12 15:01:01 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapivideopool.c: + pool: fix deallocation of video pools. + The queue of free objects to used was deallocated with g_queue_free_full(). + However, this convenience function shall only be used if the original queue + was allocated with g_queue_new(). This caused memory corruption, eventually + leading to a crash. + The correct solution is to pair the g_queue_init() with the corresponding + g_queue_clear(), while iterating over all free objects to deallocate them. + +2013-03-13 17:44:52 +0800 Wind Yuan + + * gst/vaapi/gstvaapidownload.c: + vaapidownload: fix src caps format error. + This fixes direct linking of vaapidownload element to xvimagesink with + VA drivers supporting vaGetImage() from the native VA surface format to + a different VA image format. i.e. color conversion during download. + http://bugzilla.gnome.org/show_bug.cgi?id=703937 + Signed-off-by: Gwenole Beauchesne + +2013-07-11 18:26:37 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidownload.c: + vaapidownload: fix debug string for image formats. + The image is now expressed as a standard GstVideoFormat, which is not + a FOURCC but rather a regular enum value. + This is a regression introduced in commit 09397fa. + +2013-04-24 10:39:03 +0800 Wind Yuan + + * gst-libs/gst/vaapi/gstvaapiimage.c: + image: add support for raw YUY2/UYVY image copies. + Implement raw image copies for YUY2 format. Add support for UYVY format + too, with the same copy function as for YUY2. Even though components + ordering differs, copying line strides is essentially the same. + https://bugzilla.gnome.org/show_bug.cgi?id=703939 + https://bugzilla.gnome.org/show_bug.cgi?id=703940 + Signed-off-by: Gwenole Beauchesne + +2013-07-10 15:15:11 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapiuploader.c: + plugins: clean-up video uploader helper. + Fix gst_vaapi_uploader_get_buffer() to not assign caps since they + were already negotiated beforehand, and they are not used from the + buffer in upstream elements. + Clean-up gst_vaapi_uploader_ensure_caps() to use the new image caps + represented as a GstVideoInfo. + +2013-07-10 15:03:43 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapiuploader.c: + plugins: use GstVideoInfo in video uploader helper. + +2013-07-10 10:34:24 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideomemory.c: + plugins: allow creation of VA surfaces with explicit pixel format. + Adapt GstVaapiVideoMemory allocator to support creation of VA surfaces + with an explicit pixel format. This allows for direct rendering to + VA surface memory from a software decoder. + +2013-07-10 14:20:30 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + surface: fix surface pool creation with an explicit pixel format. + Fix creation of surface pool objects to honour explicit pixel format + specification. If this operation is not supported, then fallback to + the older interface with chroma format. + +2013-07-10 13:58:55 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurface.c: + surface: try to determine the underlying VA surface format. + If a VA surface was allocated with the chroma-format interface, try to + determine the underlying pixel format on gst_vaapi_surface_get_format(), + or return GST_VIDEO_FORMAT_ENCODED if this is not a supported operation. + +2013-07-09 19:08:37 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapisurface_priv.h: + surface: allow creation with explicit pixel format. + Make it possible to create VA surfaces with a specific pixel format. + This is a new capability brought in by VA-API >= 0.34.0. If that + capability is not built-in (e.g. using VA-API < 0.34.0), then + gst_vaapi_surface_new_with_format() will return NULL. + +2013-07-10 09:48:40 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/video-format.c: + * gst-libs/gst/vaapi/video-format.h: + surface: add helper function to get chroma type from GstVideoFormat. + Add gst_video_format_get_chroma_type() helper function to determine + the GstVaapiChromaType from a standard GStreamer video format. It is + possible to reconstruct that from GstVideoFormatInfo but it is much + simpler (and faster?) to use the local GstVideoFormatMap table. + +2013-07-09 19:13:39 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + surface: add new chroma formats. + Add new chroma formats available with VA-API >= 0.34.0. In particular, + this includes "RGB" chroma formats, and more YUV subsampled formats. + Also add a new from_GstVaapiChromaType() helper function to convert + libgstvaapi chroma type to VA chroma format. + +2013-07-10 13:32:15 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiimagepool.c: + pool: fix image pool to check for the video format to use. + Make gst_vaapi_image_pool_new() succeed, and thus returning a valid + image pool object, only if the underlying VA display does support the + requested VA image format. + +2013-07-10 13:07:37 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapiimagepool.c: + * gst-libs/gst/vaapi/gstvaapiimagepool.h: + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.h: + * gst-libs/gst/vaapi/gstvaapivideopool.h: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapiuploader.c: + * tests/Makefile.am: + * tests/test-surfaces.c: + Use GstVideoInfo for video pools. + Get rid of GstCaps to create surface/image pool, and use GstVideoInfo + structures instead. Those are smaller, and allows for streamlining + libgstvaapi more. + +2013-07-09 18:03:36 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/video-format.c: + Add more video formats. + Add new video format mappings to VA image formats: + - YUV: packed YUV (YUY2, UYVY), grayscale (Y800) ; + - RGB: 32-bit RGB without alpha channel (XRGB, XBGR, RGBX, BGRX). + +2013-07-10 15:52:20 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiimage.c: + image: fix debug message with video format. + Fix debug message string with image format expressed with GstVideoFormat + instead of the obsolete format that turned out to be a fourcc. + This is a regression from git commit e61c5fc. + +2013-07-09 15:28:31 +0200 Gwenole Beauchesne + + * tests/image.c: + * tests/image.h: + * tests/test-display.c: + * tests/test-textures.c: + * tests/test-windows.c: + tests: port to new video format API. + +2013-07-09 15:44:35 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapiuploader.c: + * gst/vaapi/gstvaapivideomemory.c: + plugins: port to new video format API. + +2013-07-09 16:26:11 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiimage.c: + libs: use GstVideoInfo wherever possible. + In particular, use gst_video_info_from_caps() helper function in VA image + for implementating gst_vaapi_image_get_buffer() [vaapidownload] and + gst_vaapi_image_update_from_buffer() [subpictures] in GStreamer 0.10 builds. + +2013-07-09 16:38:05 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-docs.xml.in: + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiimageformat.c: + * gst-libs/gst/vaapi/gstvaapiimageformat.h: + libs: drop GstVaapiImageFormat helpers. + Drop GstVaapiImageFormat helpers since everything was moved to the new + GstVideoFormat based API. Don't bother with backwards compatibility and + just bump the library major version afterwards. + +2013-07-09 14:03:01 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst-libs/gst/vaapi/gstvaapiimagepool.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + libs: port to new video format API. + +2013-07-09 15:29:59 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-docs.xml.in: + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/video-format.c: + * gst-libs/gst/vaapi/video-format.h: + Add new video format API. + Leverage GstVideoFormat utilities from core GStreamer to provide an + adaptation layer to VA image formats. + +2013-07-09 11:13:59 +0200 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2013-07-08 18:32:00 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + vaapisink: fix creation of GLX texture. + Fix creation of GLX texture, to not depend on the GstCaps video size that + could be wrong, especially in presence of frame cropping. So, use the size + from the source VA surfaces. + An optimization could be to reduce the texture size to the actual visible + size on screen. i.e. scale down the texture size to match the screen dimensions, + while preserving the VA surface aspect ratio. However, some VA drivers don't + honour that. + +2013-02-18 16:28:27 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: add support for video cropping. + If the stream has a sequence_display_extenion, then attach the + display_horizontal/display_vertical dimension as the cropping + rectangle width/height to the GstVaapiPicture. + Signed-off-by: Gwenole Beauchesne + +2013-02-18 15:05:37 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + vc1: add support for video cropping. + If the Advanced profile has display_extension fields, then set the display + width/height dimension as cropping rectangle to the GstVaapiPicture. + Signed-off-by: Gwenole Beauchesne + +2013-02-15 18:50:26 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: add support for video cropping. + If the encoded stream has the frame_cropping_flag set, then associate + the cropping rectangle to GstVaapiPicture. + Signed-off-by: Gwenole Beauchesne + +2013-07-08 17:01:21 +0200 Gwenole Beauchesne + + * tests/decoder.c: + * tests/decoder.h: + * tests/test-decode.c: + * tests/test-subpicture.c: + tests: add basic support for video cropping. + Change generic decoder of sample I-frame to return a GstVaapiSurfaceProxy + instead of a plain GstVaapiSurface. This means that we can now retrieve + the frame cropping rectangle from the surface proxy, along with additional + information if ever needed. + +2013-07-08 14:50:42 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapivideometa.c: + plugins: add support for video cropping. + Add support for GstVideoCropMeta in GStreamer >= 1.0.x builds and gst-vaapi + specific meta information to hold video cropping details. Make the sink + support video cropping in X11 and GLX modes. + +2013-02-15 18:24:24 +0200 Sreerenj Balachandran + + * gst/vaapi/gstvaapivideometa.c: + * gst/vaapi/gstvaapivideometa.h: + plugins: add helper functions to set the render rectangle. + Some video clips may have a clipping region that needs to propogate to + the renderer. These helper functions make it possible to attach that + clipping region, as a GstVaapiRectangle, the the video meta associated + with the buffer. + Signed-off-by: Sreerenj Balachandran + signed-off-by: Gwenole Beauchesne + +2013-07-08 14:47:24 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy_priv.h: + surfaceproxy: allow for NULL cropping rectangle. + Make it possible associate an empty cropping rectangle to the surface + proxy, thus resetting any cropping rectangle that was previously set. + This allows for returning plain NULL when no cropping rectangle was + initially set up to the surface proxy, or if it was reset to defaults. + +2013-07-08 11:41:59 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurfaceproxy_priv.h: + surfaceproxy: clean-up helper macros. + Always use the GST_VAAPI_SURFACE_PROXY() helper macro to cast from a + proxy macro argument to a GstVaapiSurfaceProxy pointer. + +2013-07-08 11:43:27 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface_priv.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + surface: add simple surface info accessors as helper macros. + Add helper macros to retrieve the VA surface information like size + (width, height) or chroma type. This is a micro-optimization to avoid + useless function calls and NULL pointer re-checks in internal routines. + +2013-02-15 18:42:12 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy_priv.h: + decoder: add support for video cropping. + Add gst_vaapi_picture_set_crop_rect() helper function to copy the video + cropping information from raw bitstreams to each picture being decoded. + Also add helper function to surface proxy to propagate that information + outside of libgstvaapi. e.g. plug-in elements or standalone applications. + Signed-off-by: Sreerenj Balachandran + Signed-off-by: Gwenole Beauchesne + +2013-07-08 17:30:30 +0200 Gwenole Beauchesne + + * ext/codecparsers: + codecparsers: update to gst-vaapi-branch commit f90de0a. + f90de0a h264: fix calculation of the frame cropping rectangle + 535515c h264: parse the cropping rectangle separately + +2013-07-05 19:03:41 +0200 Gwenole Beauchesne + + * ext/codecparsers: + codecparsers: update to gst-vaapi-branch commit 0f68a71. + 0f68a71 mpeg2: fix video packet header size checks + +2013-06-07 20:08:43 +0800 Zhong Cong + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: reset quantization matrices on new sequence headers. + The MPEG-2 standard specifies (6.3.7) that all quantisation matrices + shall be reset to their default values when a Sequence_Header() is + decoded. + Signed-off-by: Gwenole Beauchesne + +2013-07-05 15:49:34 +0200 Gwenole Beauchesne + + * configure.ac: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: cope with latest codecparser changes. + Fix build with newer MPEG-2 codecparser where GstMpegVideoPacket are + used in individual header parsers. Also use the new slice parsing API. + +2013-07-05 17:51:26 +0200 Gwenole Beauchesne + + * ext/codecparsers: + codecparsers: update to gst-vaapi-branch commit dddd182. + dddd182 mpeg2: add slice header parsing API + 94e6228 mpeg2: add sequence scalable extension parsing API + 531134f mpeg2: add new API that takes GstMpegVideoPacket arguments + 4b135d3 h264: fix the return value type for the SEI palyload parsing methods + +2013-06-27 12:25:44 +0300 Sreerenj Balachandran + + * gst/vaapi/gstvaapisink.c: + vaapisink: expose the raw video formats in static caps template. + Expose all raw video formats in the static caps template since the + vaapisink is supporting raw data. We will get the exact set of formats + supported by the driver dynamically through the _get_caps() routine. + This also fixes an inconsistency wrt. GStreamer 0.10 builds. + https://bugzilla.gnome.org/show_bug.cgi?id=702178 + Signed-off-by: Gwenole Beauchesne + +2013-06-27 13:53:46 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + vaapisink: add "use-glx" property for OpenGL rendering. + Now that VA/GLX capable buffers are generated by default on X11, thus + depending on a VA/GLX display, we stil want to use vaPutSurface() for + rendering since it is faster. + Anyway, OpenGL rendering in vaapisink was only meant for testing and + enabling "fancy" effects to play with. This has no real value. So, + disable OpenGL rendering by default. + +2013-06-06 05:36:03 -0400 Víctor Manuel Jáquez Leal + + * gst/vaapi/gstvaapipluginutil.c: + plugins: try to allocate a GLX display first over an X11 one. + If the gstreamer-vaapi plug-in elements are built with GLX support, then + try to allocate a GstVaapiDisplayGLX first before resorting to a VA/X11 + display next. + https://bugzilla.gnome.org/show_bug.cgi?id=701742 + +2013-04-25 17:07:13 +0100 Lionel Landwerlin + + * configure.ac: + configure: use GST_PLUGIN_PATH_1_0 instead of GST_PLUGIN_PATH for Gst 1.0. + jhbuild sets $GST_PLUGIN_PATH_1_0 which overrides $GST_PLUGIN_PATH. + https://bugzilla.gnome.org/show_bug.cgi?id=698858 + Signed-off-by: Gwenole Beauchesne + +2013-04-27 15:15:49 +0800 Wind Yuan + + * gst-libs/gst/vaapi/gstvaapiimage.c: + image: fix wrong check for rect bounds in copy_image(). + +2013-06-14 13:41:14 +0200 Gwenole Beauchesne + + * configure.ac: + Bump version for development. + +2013-06-14 11:47:50 +0200 Gwenole Beauchesne + + * NEWS: + * configure.ac: + 0.5.4. + +2013-06-14 11:43:46 +0200 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2013-06-14 11:39:54 +0200 Gwenole Beauchesne + + * configure.ac: + * gst-libs/gst/codecparsers/Makefile.am: + configure: always build the MPEG-4 parser. + Always build the MPEG-4 parser for now as there are also core fixes + included in the parser that cannot be tested for with API checks. + +2013-06-14 11:32:36 +0200 Gwenole Beauchesne + + * configure.ac: + configure: add --enable-builtin-codecparsers [default="yes"] option. + Add flag to have all codecparsers built-in, thus ensuring that the + resulting binaries have all the necessary bug fixes and this is what + the QA has been testing anyway. + Of course, for a completely up-to-date Linux distribution, you could + also opt for --disable-builtin-codecparsers and use the system ones. + Though, some core fixes could be missing, and those cannot be tested + for with API checks. + +2013-06-14 11:14:23 +0200 Gwenole Beauchesne + + * ext/codecparsers: + codecparsers: update to gst-vaapi-branch commit 843ce3e. + 843ce3e jpeg: fix default Huffman tables generation. + 8655187 mpeg2: fix the pixel-aspect-ratio calculation + 21099dc mpeg2: actually store video bitrate values + dd02087 mpeg2: fix picture packet extension size check + 25948e9 mpeg2: increase min size for picture coding ext + f1f5a40 ensure the debug category is properly initialized + +2013-06-12 14:16:17 +0100 Gwenole Beauchesne + + * debian.upstream/Makefile.am: + debian: fix list of generated files for .deb packaging. + +2013-06-12 13:48:26 +0100 Gwenole Beauchesne + + * configure.ac: + * debian.upstream/Makefile.am: + * debian.upstream/control.in: + debian: fix libgstvaapi -dev package name. + Fix libgstvaapi -dev package name so that to allow installation of both + GStreamer 0.10 and 1.0.x based packages. + +2013-06-05 17:42:00 +0200 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2013-05-31 11:09:40 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + wayland: fix memory leak of display resources. + +2013-06-04 07:14:22 +0800 Zhao Halley + + * gst/vaapi/gstvaapisink.c: + vaapisink: fix build without VA/GLX support. + +2013-06-05 11:01:51 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + plugins: allow buffer mappings to GstVaapiSurfaceProxy. + Allow plain gst_buffer_map() interface to work with gstreamer-vaapi + video buffers, i.e. expose the underlying GstVaapiSurfaceProxy to the + caller. This is the only sensible enough thing to do in this mode as + the underlying surface pixels need to be extracted through an explicit + call to the gst_video_frame_map() function instead. + A possible use-case of this is to implement a "handoff" signal handler + to fakesink or identity element for further processing. + +2013-06-03 10:22:44 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideomemory.c: + plugins: silence check for direct-rendering mode in video memory. + Fix gst_vaapi_video_allocator_new() to silently check for direct-rendering + mode support, and not trigger fatal-criticals if either test surface or + image could not be created. Typical case: pixel format mismatch, e.g. NV12 + supported by most hardware vs. I420 supported by most software decoders. + +2013-06-03 10:06:29 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideomemory.c: + plugins: improve video memory flags safety checks. + On map, ensure we have GST_MAP_WRITE flags since this is only what we + support for now. Likewise, on unmap, make sure that the VA image is + unmapped for either read or write, while still committing it to the + VA surface if write was requested. + +2013-05-30 18:17:07 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurface.c: + surface: fix memory leak through unreleased parent context. + Break the circular references between GstVaapiContext and its children + GstVaapiSurfaces. Since the VA surfaces held an extra reference to the + context, which holds a reference to its VA surfaces, then none of those + were released. + How does this impact support for subpictures? + The only situation when the parent context needs to disappear is when + it is replaced with another one because of a resolution change in the + video stream for instance, or a normal destroy. In this case, it does + not really matter to apply subpictures to the peer surfaces since they + are either gone, or those that are left in the pipe can probably bear + a reinstantiation of the subpictures for it. + So, parent_context is set to NULL when the parent context is destroyed, + other VA surfaces can still get subpictures attached to them, individually + not as a whole. i.e. subpictures for surface S1 will be created from + active composition buffers and associated to S1, subpictures for S2 will + be created from the next active composition buffers, etc. We don't try + to cache the subpictures in those cases (pending surfaces until EOS + is reached, or pending surfaces until new surfaces matching new VA context + get to be used instead). + +2013-05-27 14:01:48 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + vaapisink: fix one-time initialization when display property is set. + Fix gst_vaapisink_ensure_display() to perform one-time initialization + tasks even if the `display' property was explicitly set. + +2013-05-27 15:59:08 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + window: fix GLX window initialization. + Make sure to create the GLX context once the window object has completed + its creation. Since gl_resize() relies on the newly created window size, + then we cannot simply overload the GstVaapiWindowClass::create() hook. + So, we just call into gst_vaapi_window_glx_ensure_context() once the + window object is created in the gst_vaapi_window_glx_new*() functions. + +2013-05-27 17:18:40 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + * gst-libs/gst/vaapi/gstvaapidisplay_drm_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h: + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapiwindow_drm.c: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + display: validate display types. + +2013-05-27 16:13:33 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + display: drop internal NAME_PREFIX, store the real display name. + Always store a valid display name/device path, instead of adding a + particular prefix. i.e. make it simply a strdup(), or "" if it was + initially NULL. + +2013-05-27 13:17:31 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.c: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplaycache.c: + * gst-libs/gst/vaapi/gstvaapidisplaycache.h: + display: make it possible to lookup the display cache by type. + Make it possible to add extra an extra filter to most of display cache + lookup functions so that the GstVaapiDisplay instance can really match + a compatible and existing display by type, instead of relying on extra + string tags (e.g. "X11:" prefix, etc.). + +2013-05-24 16:19:23 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + display: cope with new display cache API. + +2013-05-24 16:12:01 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplaycache.c: + * gst-libs/gst/vaapi/gstvaapidisplaycache.h: + display: rework display cache API. + Simplify display cache API, while making it more flexible. We can now create + custom lookup functions with gst_vaapi_display_cache_lookup_custom(). + +2013-05-24 15:05:45 +0200 Gwenole Beauchesne + + * tests/test-display.c: + tests: improve check for display cache. + Improve check for display cache infrastructure. In particular, for X11 and + GLX backends, we need to make sure that we can create a GstVaapiDisplayX11 + from another GstVaapiDisplayGLX, i.e. underlying X11 and VA displays can be + shared. Besides, allocating a GstVaapiDisplayGLX while a GstVaapiDisplayX11 + already exists will have to generate different VA displays. + +2013-05-15 10:33:16 +0800 Zhao Halley + + * gst/vaapi/gstvaapiuploader.c: + uploader: fix memory leak in GStreamer 0.10 builds. + In GStreamer 0.10 builds, gst_vaapi_uploader_get_buffer() was used + but it exhibited a memory leak because the surface generated for the + GstVaapiVideoMeta totally lost its parent video pool. So, it was not + possible to release that surface back to the parent pool when the meta + gets released, and the memory consumption kept growing. + Signed-off-by: Gwenole Beauchesne + +2013-05-23 18:56:43 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideometa.c: + plugins: fix gst_vaapi_video_meta_new_from_pool(). + Since GST_VAAPI_IS_xxx_VIDEO_POOL() was only testing for NULL and not + the underlying object type, the gst_vaapi_video_meta_new_from_pool() + was hereby totally broken. Fixed this regression by using the newly + provided gst_vaapi_video_pool_get_object_type() function. + +2013-05-23 18:22:50 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapiuploader.c: + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideometa.c: + plugins: cope with GST_VAAPI_IS_xxx() macros removal. + +2013-05-23 18:19:24 +0200 Gwenole Beauchesne + + * tests/decoder.c: + tests: cope with GST_VAAPI_IS_xxx() macros removal. + +2013-05-23 18:45:23 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapiimagepool.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + * gst-libs/gst/vaapi/gstvaapivideopool.c: + * gst-libs/gst/vaapi/gstvaapivideopool.h: + * gst-libs/gst/vaapi/gstvaapivideopool_priv.h: + libs: add query for GstVaapiVideoPool object types. + Add API to identify the underlying GstVaapiVideoPool object type. + +2013-05-23 18:15:48 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.h: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.h: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst-libs/gst/vaapi/gstvaapiimagepool.c: + * gst-libs/gst/vaapi/gstvaapiimagepool.h: + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapiobject.h: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.h: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy_priv.h: + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapivideopool.c: + * gst-libs/gst/vaapi/gstvaapivideopool.h: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_drm.h: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.h: + libs: drop GST_VAAPI_IS_xxx() helper macros. + Drop obsolete GST_VAAPI_IS_xxx() helper macros since we are no longer + deriving from GObject and so those were only checking for whether the + argument was NULL or not. This is now irrelevant, and even confusing + to some extent, because we no longer have type checking. + Note: this incurs more type checking (review) but the libgstvaapi is + rather small, so this is manageable. + +2013-05-07 18:52:28 +0200 Gwenole Beauchesne + + * configure.ac: + Bump library major version. + The whole libgstvaapi libraries got a major refresh to get rid of GObject. + This is a fundamental change that requires a new SONAME. More changes are + underway to streamline the core libraries. + So far, the net result is a reduction of .text size (code) by 32KB, i.e. -10%. + On one particular test (sintel HD trailer), the total number of executed + instruction was reduced by 8%. + +2013-05-07 18:37:24 +0200 Gwenole Beauchesne + + * docs/reference/libs/Makefile.am: + * docs/reference/libs/libs-docs.xml.in: + * docs/reference/libs/libs-sections.txt: + * docs/reference/libs/libs.core.types: + * docs/reference/libs/libs.glx.types: + * docs/reference/libs/libs.x11.types: + docs: cope with removed APIs. + Some APIs are dead because they are no longer based on GObject. + +2013-05-06 14:43:38 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiupload.c: + * gst/vaapi/gstvaapiuploader.c: + * gst/vaapi/gstvaapivideobufferpool.c: + * gst/vaapi/gstvaapivideoconverter_glx.c: + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideometa.c: + plugins: cope with new GstVaapiMiniObject objects. + +2013-05-07 11:45:10 +0200 Gwenole Beauchesne + + * tests/decoder.c: + * tests/image.c: + * tests/output.c: + * tests/simple-decoder.c: + * tests/test-decode.c: + * tests/test-display.c: + * tests/test-subpicture.c: + * tests/test-surfaces.c: + * tests/test-textures.c: + * tests/test-windows.c: + tests: cope with new GstVaapiMiniObject objects. + +2013-05-07 15:38:51 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + display: fix set_synchronous() to lock display. + +2013-05-03 19:02:23 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiimagepool.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + videopool: simplify creation of video objects pool. + +2013-05-07 18:17:10 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapitypes.h: + libs: simplify GstVaapiID definitions. + Make GstVaapiID a gsize instead of guessing an underlying integer large + enough to hold all bits of a pointer. Also drop GST_VAAPI_ID_NONE since + this is plain zero and that it is no longer passed as varargs. + +2013-05-02 16:11:53 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapi_priv.h: + * gst-libs/gst/vaapi/gstvaapiparamspecs.c: + * gst-libs/gst/vaapi/gstvaapiparamspecs.h: + * gst-libs/gst/vaapi/gstvaapivalue.c: + * gst-libs/gst/vaapi/gstvaapivalue.h: + libs: drop obsolete function helpers and objects. + Drop obsolete GstVaapiID related function helpers for passing them as + GValues. + +2013-05-07 11:39:34 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.h: + * gst-libs/gst/vaapi/gstvaapidisplay_drm_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.c: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.h: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h: + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapivideopool.c: + libs: use GstVaapiMiniObject for display objects. + +2013-05-06 14:07:17 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicodec_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.h: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.h: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.h: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.h: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.h: + libs: use GstVaapiMiniObject for video decoders. + Port GstVaapiDecoder and GstVaapiDecoder{MPEG2,MPEG4,JPEG,H264,VC1} to + GstVaapiMiniObject. Add gst_vaapi_decoder_set_codec_state_changed_func() + helper function to let the user add a callback to a function triggered + whenever the codec state (e.g. caps) changes. + +2013-05-03 11:01:12 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapiimagepool.c: + * gst-libs/gst/vaapi/gstvaapiimagepool.h: + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapivideopool.c: + * gst-libs/gst/vaapi/gstvaapivideopool.h: + * gst-libs/gst/vaapi/gstvaapivideopool_priv.h: + libs: use GstVaapiMiniObject for video object pools. + Port GstVaapiVideoPool, GstVaapiSurfacePool and GstVaapiImagePool to + GstVaapiMiniObject. Drop gst_vaapi_video_pool_get_caps() since it was + no longer used for a long time. Make object allocators static, i.e. + local to the shared library. + +2013-04-30 17:22:00 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapitexture.h: + libs: use GstVaapiObject for texture objects. + +2013-04-30 17:20:14 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_drm.c: + * gst-libs/gst/vaapi/gstvaapiwindow_drm.h: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.h: + * gst-libs/gst/vaapi/gstvaapiwindow_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11_priv.h: + libs: use GstVaapiObject for window objects. + +2013-04-30 17:22:15 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.h: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapivideopool.c: + libs: use GstVaapiObject for VA objects. + +2013-04-30 17:20:46 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapiobject.h: + * gst-libs/gst/vaapi/gstvaapiobject_priv.h: + Port GstVaapiObject to GstVaapiMiniObject. + +2013-04-30 10:28:30 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicodec_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_dpb.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiminiobject.c: + * gst-libs/gst/vaapi/gstvaapiminiobject.h: + libs: refine GstVaapiMiniObject. + Drop support for user-defined data since this capability was not used + so far and GstVaapiMiniObject represents the smallest reference counted + object type. Add missing GST_VAAPI_MINI_OBJECT_CLASS() helper macro. + Besides, since GstVaapiMiniObject is a libgstvaapi internal object, it + is also possible to further simplify the layout of the object. i.e. merge + GstVaapiMiniObjectBase into GstVaapiMiniObject. + +2013-05-07 16:43:51 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + decoder: update picture size from the bitstream. + Propagate the picture size from the bitstream to the GstVaapiDecoder, + and subsequent user who installed a signal on notify::caps. This fixes + decoding of TS streams when the demuxer failed to extract the required + information. + +2013-04-25 14:16:01 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + decoder: fix raw decoding mode. + Fix gst_vaapi_decoder_get_surface() to actually transfer ownership of the + surface proxy to the caller. + +2013-04-25 13:56:18 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * gst/vaapi/gstvaapidecode.c: + decoder: add gst_vaapi_decoder_get_frame_with_timeout(). + Add gst_vaapi_decoder_get_frame_with_timeout() helper function that will + wait for a frame to be decoded, until the specified timeout in microseconds, + prior to returning to the caller. + This is a fix to performance regression from 851cc0, whereby the vaapidecode + loop executed on the srcpad task was called to often, thus starving all CPU + resources. + +2013-04-19 14:38:59 +0200 Gwenole Beauchesne + + * configure.ac: + Bump version for development. + +2013-04-18 19:09:45 +0200 Gwenole Beauchesne + + * NEWS: + * configure.ac: + 0.5.3. + +2013-04-18 19:08:39 +0200 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2013-04-18 15:55:26 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: rework heuristics to detect decode timeout. + Rework heuristics to detect when downstream element ran into errors, + and thus failing to release any VA surface in due time for the current + frame to get decoded. In particular, recalibrate the render time base + when the first frame gets submitted downstream, or when there is no + timestamp that could be inferred. + +2013-04-18 15:50:02 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstcompat.h: + * gst/vaapi/gstvaapidecode.c: + vaapidecode: rework GstVideoDecoder::handle_frame() with a task. + Rework GstVideoDecoder::handle_frame() to decode the current frame, + while possibly waiting for a free surface, and separately submit all + decoded frames from a task. This makes it possible to pop and render + decoded frames as soon as possible. + +2013-04-18 10:06:15 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiupload.c: + plugins: use gst_object_unref() wherever applicable. + Use gst_object_unref() wherever applicable, e.g. objects derived from + GstElement, GstVideoPool, etc. + +2013-04-17 14:21:16 +0200 Gwenole Beauchesne + + * docs/reference/plugins/plugins-docs.xml.in: + * docs/reference/plugins/plugins-sections.txt: + * docs/reference/plugins/plugins.types: + docs: drop obsolete plug-ins. + Drop documentation for obsolete plug-ins, even for GStreamer 0.10. + i.e. vaapiupload and vaapidownload are no longer the recommended + plug-ins to use. + +2013-04-17 13:17:26 +0200 Gwenole Beauchesne + + * debian.upstream/rules: + debian: fix build of GStreamer 0.10 packages. + Fix build of Debian packages to scan the actual GStreamer API version + from the generated changelog file. + +2013-04-17 10:58:04 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: minor clean-ups. + Use g_clear_object() wherever appropriate and remove dead-code. + +2013-04-17 10:53:03 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: fix reference counting buf for passthrough mode. + Fix reference counting bug for passthrough mode, whereby the input buffer + was propagated as is downstream through gst_pad_push() without increasing + its reference count before. The was a problem when gst_pad_push() returns + an error and we further decrease the reference count of the input buffer. + +2013-04-17 10:18:45 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstcompat.h: + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: port to GStreamer 1.0. + Add support for interlaced streams with GStreamer 1.0 too. Basically, + this enables vaapipostproc, though it is not auto-plugged yet. We also + make sure to reply to CAPS queries, and happily handle CAPS events. + +2013-04-17 10:14:55 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + decoder: fix GstVideoCodecFrame flags for interlaced contents. + Fix support for interlaced contents with GStreamer 0.10. In particular, + propagate GstVaapiSurfaceProxy frame flags to GstVideoCodecFrame flags + correctly. + This is a regression from commit 87e5717. + +2013-04-16 13:23:41 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * gst-libs/gst/vaapi/gstvaapiparser_frame.c: + * gst-libs/gst/vaapi/gstvaapiparser_frame.h: + decoder: rename GstVaapiDecoderFrame to GstVaapiParserFrame. + Rename GstVaapiDecoderFrame to GstVaapiParserFrame because this data + structure was only useful to parsing and a proper GstvaapiDecoderFrame + instance will be created instead. + +2013-04-16 19:09:30 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + decoder: export presentation timestamp for raw decoding mode. + Fix regression from 0.4-branch whereby GstVaapiSurfaceProxy no longer + held any information about the expected presentation timestamp, frame + duration or additional flags like interlaced or top-field-first. + +2013-04-16 18:56:24 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + decoder: use new GstVaapiSurfaceProxy utility functions. + Use new GstVaapiSurfaceProxy internal helper functions to propagate the + necessary GstVideoCodecFrame flags to vaapidecode (GStreamer 0.10). + Also make GstVaapiDecoder push_frame() operate similarly to drop_frame(). + i.e. increase the GstVideoCodecFrame reference count in push_frame rather + than gst_vaapi_picture_output(). + +2013-04-16 18:35:48 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy_priv.h: + surfaceproxy: add more attributes for raw decoding modes. + Add more attributes for raw decoding modes, i.e. directly through the + libgstvaapi helper library. In particular, add presentation timestamp, + duration and a couple of flags (interlaced, TFF, RFF, one-field). + +2013-04-16 13:48:00 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + * gst/vaapi/gstvaapidecode.c: + * tests/simple-decoder.c: + surfaceproxy: drop user-data support from GstVaapiSurfaceProxy. + Drop user-data support from GstVaapiSurfaceProxy. Rather make it explicit + to call some user-provided function when the surface proxy is released. + +2013-04-15 12:52:51 +0400 Víctor Manuel Jáquez Leal + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + build: link libgstvaapi-glx-1.0.so against libdl. + Ensure libgstvaapi-glx*.so builds against libdl since dlsym() is used + to resolve glXGetProcAddress() from GLX libraries. This fix builds on + Fedora 17. + https://bugzilla.gnome.org/show_bug.cgi?id=698046 + Signed-off-by: Gwenole Beauchesne + +2013-04-15 14:22:57 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + decoder: fix gst_vaapi_decoder_get_codec_state(). + Fix previous commit whereby gst_vaapi_decoder_get_codec_state() was + supposed to make GstVaapiDecoder own the return GstVideoCodecState + object. Only comment was updated, not the actual code. + +2013-04-15 13:58:58 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst/vaapi/gstvaapidecode.c: + decoder: make gst_vaapi_decoder_get_codec_state() return the original state. + Make gst_vaapi_decoder_get_codec_state() return the original codec state, + i.e. make the GstVaapiDecoder object own the return state so that callers + that want an extra reference to it would just gst_video_codec_state_ref() + it before usage. This aligns the behaviour with what we had before with + gst_vaapi_decoder_get_caps(). + This is an ABI incompatible change, library major version was bumped from + previous release (0.5.2). + +2013-04-15 13:52:19 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideobufferpool.h: + * gst/vaapi/gstvaapivideoconverter_glx.h: + plugins: mark a few more functions as internal. + Mark the following functions are internal, i.e. private to the vaapi plug-in: + - gst_vaapi_video_buffer_pool_get_type() + - gst_vaapi_video_converter_glx_get_type() + - gst_vaapi_video_converter_glx_new() + +2013-04-15 13:48:43 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideobuffer.c: + plugins: implement GstSurfaceMeta API. + Implement GstSurfaceMeta API for GStreamer 1.0.x. Even though this is + an unstable/deprecated API, this makes it possible to support Clutter + sink with minimal changes. Tested against clutter-gst 1.9.92. + +2013-04-12 17:12:43 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + vaapisink: optimize GstVideoOverlayInterface::expose(). + When render-mode is "overlay", then it is not really useful to peek into + the GstBaseSink::last_buffer, since we have our own video_buffer already + recorded and maintained into GstVaapiSink. + +2013-04-12 17:05:06 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + vaapisink: fix memory leak of GstSample objects. + Fix memory leak of GstSample objects in GstVideoOverlayInterface::expose(). + This also fixes extra unreferencing of the underlying GstBuffer in the common + path afterwards (for both 0.10 or 1.0). + +2013-04-12 13:44:52 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstcompat.h: + * gst/vaapi/gstvaapi.c: + plugins: fix description for gst-inspect. + Fix the name of the plug-in element reported to gst-inspect-1.0. i.e. we + need an explicit definition for GStreamer >= 1.0 because the GST_PLUGIN_DEFINE + incorrectly uses #name for creating the plug-in name, instead of using macro + expansion (and let further expansion of macros) through e.g. G_STRINGIFY(). + +2013-04-11 09:24:44 +0200 Gwenole Beauchesne + + * README: + README: updates. + Update build requirements for GStreamer 1.0.x support. Add section for + ways to report bugs. + +2013-04-10 16:54:01 +0200 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2013-04-10 15:31:41 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst/vaapi/Makefile.am: + Fix make dist to include all source files, in any case. + Fix make dist to allow build for either GStreamer 0.10 or 1.0. i.e. make + sure to include all source files in either case while generating source + tarballs. + +2013-04-10 15:21:57 +0200 Gwenole Beauchesne + + * configure.ac: + Bump library major version. + Bump library major version, while preserving a major version of 0 for + GStreamer 1.0 based libraries, and a major version of 2 for GStreamer + 0.10 based librarieS. + +2013-04-10 14:37:42 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + plugins: implement direct-rendering mode for raw YUV buffer uploads. + Allow direct-rendering (writes) into target VA surfaces. + +2013-04-09 16:02:06 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideobufferpool.c: + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + plugins: implement uploads from raw YUV buffers for GStreamer 1.0. + Implement GstVideoMeta::{,un}map() to support raw YUV buffer upload when + the last component is unmapped. Downloads are not supported yet. The aim + was to first support SW decoding + HW accelerated rendering (vaapisink). + e.g. for Wayland. + +2013-04-03 11:10:41 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: submit all decoded frames before decoding a new one. + Make sure to purge all pending frames that were already decoded prior + to decoding a new one. This helps release VA surfaces as early as + possible. + +2013-04-02 16:12:16 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: reply to CAPS queries. + Handle GST_QUERY_CAPS, which is the GStreamer 1.0 mechanism to retrieve + the set of allowed caps, i.e. it works similar to GstPad::get_caps(). + This fixes fallback to SW decoding if no HW decoder is available. + +2013-03-20 11:26:38 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + decoder: fix unpaired GstBuffer map/unmaps. + This possibly fixes a few memory leaks along the way. + +2013-03-20 14:40:57 +0100 Gwenole Beauchesne + + * configure.ac: + * gst-libs/gst/vaapi/gstcompat.h: + * gst-libs/gst/vaapi/gstvaapiimageformat.c: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + * gst/vaapi/gstvaapiuploader.c: + * tests/codec.c: + Allow build against either GStreamer API (0.10 or 1.0). + Introduce a new configure option --with-gstreamer-api that determines + the desired GStreamer API to use. By default, GStreamer 1.0 is selected. + Also integrate more compatibility glue into gstcompat.h and plugins. + +2012-11-08 16:41:22 +0200 Sreerenj Balachandran + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + plugins: use new video buffer pools. + Use new GstVaapiVideoBufferPool to maintain video buffers. Implement + GstBaseSink::propose_allocation() to expose that pool to upstream + elements; and also implement GstVideoDecoder::decide_allocation() to + actually use that pool (from downstream), if any, or create one. + Signed-off-by: Gwenole Beauchesne + +2012-11-08 16:41:22 +0200 Sreerenj Balachandran + + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapivideobufferpool.c: + * gst/vaapi/gstvaapivideobufferpool.h: + * gst/vaapi/gstvaapivideomemory.c: + * gst/vaapi/gstvaapivideomemory.h: + plugins: add GstVaapiVideoMemory and GstVaapiVideoBufferPool objects. + Add initial support for GstVaapiVideoMemory backed buffer pool. The memory + object currently holds a reference to GstVaapiVideoMeta. + Signed-off-by: Gwenole Beauchesne + +2013-04-04 17:36:45 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideometa.c: + * gst/vaapi/gstvaapivideometa.h: + plugins: allow copies of GstVaapiVideoMeta objects. + Make it possible to copy GstVaapiVideoMeta objects, unless they contain VA + objects created from GstVaapiVideoPool. This is mostly useful to clone a + GstVaapiVideoMeta object containing a VA surface proxy so that to alter its + rendering flags. + +2013-04-04 16:16:31 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideometa.c: + plugins: make it possible to clear VA objects from GstVaapiVideoMeta. + Fix GstVaapiVideoMeta to allow VA objects to be destroyed when they are + reset to NULL. i.e. make gst_vaapi_video_meta_set_{image,surface}() and + gst_vaapi_video_meta_set_surface_proxy() actually clear VA objects when + argument is NULL. + +2012-09-03 14:00:25 +0300 Sreerenj Balachandran + + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiupload.c: + * gst/vaapi/gstvaapiuploader.c: + * gst/vaapi/gstvaapivideobuffer.c: + * gst/vaapi/gstvaapivideoconverter_glx.c: + * gst/vaapi/gstvaapivideometa.c: + * gst/vaapi/gstvaapivideometa.h: + plugins: initial port to GStreamer 1.0. + Port vaapidecode and vaapisink plugins to GStreamer API >= 1.0. This + is rather minimalistic so that to test the basic functionality. + Disable vaapiupload, vaapidownload and vaapipostproc plugins. The latter + needs polishing wrt. to GStreamer 1.x functionality and the former are + totally phased out in favor of GstVaapiVideoMemory map/unmap facilities, + which are yet to be implemented. + Signed-off-by: Gwenole Beauchesne + +2013-03-21 10:12:09 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstcompat.h: + * tests/codec.c: + * tests/decoder.c: + * tests/simple-decoder.c: + * tests/test-subpicture.c: + tests: add support for GStreamer 1.0. + +2012-09-04 15:12:18 +0300 Sreerenj Balachandran + + * configure.ac: + * gst-libs/gst/vaapi/gstcompat.h: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimageformat.c: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + Add initial support for GStreamer 1.0. + This integrates support for GStreamer API >= 1.0 only in the libgstvaapi + core decoding library. The changes are kept rather minimal here so that + the library retains as little dependency as possible on core GStreamer + functionality. + Signed-off-by: Gwenole Beauchesne + +2013-04-03 15:58:57 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + vaapisink: improve check for raw YUV format mode. + Improve check for raw YUV format modes by avoiding checks against strings + ("video/x-raw-yuv") for each new GstBuffer allocation. In the usual case, + GstBaseSink::set_caps() is called first and if VA surface format mode is + used, then GstBaseSink::buffer_alloc() is not called. If the latter is + called before set_caps(), then we just make a full check. This one is + pretty rare though, e.g. it usually happens once for custom pipelines. + +2013-04-03 15:06:46 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginutil.c: + plugins: don't fail if there is no overlay composition to apply. + Fix gst_vaapi_apply_composition() to not fail if no overlay composition + was found. i.e. return success (TRUE). This was harmless though extra + debug messages are not nice. + This is a regression introduced by commit 95b8659. + +2013-04-03 14:59:33 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + vaapidecode: expose the exact set of supported HW decoders. + Don't return static caps that don't mean anything for the underlying codecs + that are actually supported for decoding. i.e. always allocate a VA display + and retrieve the exact set of HW decoders available. That VA display may be + re-used later on during negotiation through GstVideoContext "prepare-context". + This fixes fallback to SW decoding if no HW decoder is available. + +2013-04-03 13:08:55 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + decoder: drop obsolete functions. + Drop the following functions that are now obsolete: + - gst_vaapi_context_get_surface() + - gst_vaapi_context_put_surface() + - gst_vaapi_context_find_surface_by_id() + - gst_vaapi_surface_proxy_new() + - gst_vaapi_surface_proxy_get_context() + - gst_vaapi_surface_proxy_set_context() + - gst_vaapi_surface_proxy_set_surface() + This is an API change. + +2013-04-03 13:14:59 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + decoder: delegate surface size check to VA context reset. + Now that the surface pool is reference counted in the surface proxy wrapper, + we can safely ignore surface size checks in gst_vaapi_decoder_ensure_context(). + Besides, this check is already performed in gst_vaapi_context_reset_full(). + +2013-04-03 11:37:44 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + decoder: simplify acquisition/release of spare surface. + Introduce gst_vaapi_surface_proxy_new_from_pool() to allocate a new surface + proxy from the context surface pool. This change also makes sure to retain + the parent surface pool in the proxy. + Besides, it was also totally useless to attach/detach parent context to + VA surface each time we acquire/release it. Since the whole context owns + all associated VA surfaces, we can mark this as such only once and for all. + +2013-03-29 10:39:37 +0100 Gwenole Beauchesne + + * configure.ac: + Bump version for development. + +2013-03-28 10:18:51 +0100 Gwenole Beauchesne + + * NEWS: + * configure.ac: + 0.5.2. + +2013-03-28 10:15:53 +0100 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2013-03-26 18:57:00 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapisink.c: + plugins: fix usage of gst_vaapi_reply_to_query(). + Make gst_vaapi_reply_to_query() first check whether the query argument + is actually a video-context query, i.e. with type GST_QUERY_TYPE_CUSTOM. + Then, make sure vaapisink propagates the query to the parent class if + it is not a video-context query. + +2013-03-26 18:45:53 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapivideobuffer.c: + * gst/vaapi/gstvaapivideobuffer.h: + plugins: streamline video buffers. + Add new gst_vaapi_video_buffer_new() helper function that allocates a video + buffer from a GstVaapiVideoMeta. Also remove obsolete and useless function + gst_vaapi_video_buffer_get_meta(). + +2013-03-26 10:31:10 +0100 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/Makefile.am: + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiupload.c: + * gst/vaapi/gstvaapiuploader.c: + * gst/vaapi/gstvaapivideobuffer.h: + * gst/vaapi/gstvaapivideoconverter_glx.c: + * gst/vaapi/gstvaapivideometa.c: + * gst/vaapi/gstvaapivideometa.h: + plugins: integrate GstVaapiVideoMeta from libgstvaapi. + Move GstVaapiVideoMeta from core libgstvaapi decoding library to the + actual plugin elements. That's only useful there. Also inline reference + counting code from GstVaapiMiniObject. + +2013-03-21 17:17:53 +0100 Gwenole Beauchesne + + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapipluginbuffer.c: + * gst/vaapi/gstvaapipluginbuffer.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapiupload.c: + * gst/vaapi/gstvaapiuploader.c: + * gst/vaapi/gstvaapivideobuffer.c: + * gst/vaapi/gstvaapivideobuffer.h: + plugins: drop gstvaapipluginbuffer.[ch] helper files. + Move all gst_vaapi_video_buffer_new*() helpers from gstvaapipluginbuffer.[ch] + to gstvaapivideobuffer.[ch], and drop the obsolete files. + +2013-03-21 17:06:43 +0100 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * docs/reference/libs/libs.core.types: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapivideobuffer.h: + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapidownload.h: + * gst/vaapi/gstvaapipluginbuffer.c: + * gst/vaapi/gstvaapipostproc.h: + * gst/vaapi/gstvaapivideobuffer.c: + * gst/vaapi/gstvaapivideobuffer.h: + * gst/vaapi/gstvaapivideoconverter_glx.h: + plugins: integrate GstVaapiVideoBuffer from libgstvaapi. + Move GstVaapiVideoBuffer from core libgstvaapi decoding library to the + actual plugin elements. That's only useful there. + +2013-03-21 16:32:43 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapivideoconverter_glx.c: + plugins: use common helper function to apply compositions. + Use common gst_vaapi_apply_composition() helper function to apply compositions + attached to a buffer in vaapisink or GstVaapiVideoConverterGLX. + +2013-03-21 16:09:42 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapivideoconverter_glx.c: + * gst-libs/gst/vaapi/gstvaapivideoconverter_glx.h: + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapipluginbuffer.c: + * gst/vaapi/gstvaapivideoconverter_glx.c: + * gst/vaapi/gstvaapivideoconverter_glx.h: + plugins: integrate GstVaapiVideoConverterGLX from libgstvaapi. + Make sure libgstvaapi core decoding library doesn't include un-needed + dependencies. So, move out GstVaapiVideoConverterGLX to plugins instead. + Besides, even if the vaapisink element is not used, we are bound to have + a correctly populated GstSurfaceBuffer from vaapidecode. + Also clean-up the file along the way. + +2013-03-21 13:32:15 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + vc1: fix use of possibly uninitialized variable. + In decode_codec_data(), force initialization of format to zero so that + we can catch up cases where codec-data has neither "format" nor "wmvversion" + fields, thus making it possible to gracefully fail in this case. + +2013-03-21 13:43:46 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + jpeg: propagate buffer data as a const guchar * pointer (cosmetics). + +2013-03-21 14:36:40 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + decoder: sanitize codec-data decoding. + Add a new GstVaapiDecoder::decode_codec_data() hook to actually decode + codec-data in the decoder sub-class. Provide a common shared helper + function to do the actual work and delegating further to the sub-class. + +2013-03-21 13:41:28 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + * gst-libs/gst/vaapi/gstvaapidecoder_unit.c: + * gst-libs/gst/vaapi/gstvaapidecoder_unit.h: + decoder: get rid of GstVaapiDecoderUnit::buffer field. + Drop GstVaapiDecoderUnit buffer field (GstBuffer) since it's totally + useless nowadays as creating sub-buffers doesn't bring any value. It + actually means more memory allocations. We can't do without that in + JPEG and MPEG-4:2 decoders. + +2013-03-21 13:28:05 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + decoder: sanitize uses of codec frame input buffer (cosmetics). + Alias GST_VAAPI_DECODER_CODEC_FRAME(decoder)->input_buffer to a simple + "buffer" variable. + +2013-03-20 17:34:38 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + vaapisink: add helper function to apply a composition buffer. + Simplify application of a composition buffer to a GstVaapiSurface, and + all its peers, until that function is eventually promoted to libgstvaapi. + +2013-03-20 13:42:15 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + vaapisink: fix support for raw YUV buffers. + If the raw YUV buffer was created from vaapisink, through the buffer_alloc() + hook, then it will have a valid GstVaapiVideoMeta object attached to it. + However, we previously assumed in that case that it was a "native" VA buffer, + thus not calling into GstVaapiUploader::process(). + +2013-03-20 18:41:40 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstcompat.h: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiupload.c: + plugins: use modern GstElement metadata information. + Use gst_element_class_set_static_metadata() from GStreamer 1.0, which + basically is the same as gst_element_class_set_details_simple() in + GStreamer 0.10 context. + +2013-03-20 18:04:39 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiupload.c: + plugins: move up interfaces (cosmetics). + Move GstImplementsInterface and GstVideoContext support functions up + so that to keep a clear separation between the plugin element and its + interface hooks. + +2013-03-20 12:57:18 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiuploader.c: + plugins: upgrade to newer APIs (GstVideoInfo based helpers). + Use GstVideoInfo and gst_video_info_from_caps() helper wherever possible. + Also use the newly added gst_vaapi_image_format_from_structure() helper + in GstVaapiUploader::ensure_allowed_caps(). + +2013-03-20 14:02:48 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginbuffer.c: + plugins: fix creation of video buffer from another source buffer. + gst_vaapi_video_buffer_new_from_buffer() needs to reference the source + buffer video meta since it would be unreference'd from the get_buffer() + helper function. For other cases, we still use (steal) the newly created + video meta. + +2013-03-20 11:57:03 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginbuffer.c: + * gst/vaapi/gstvaapipluginutil.c: + plugins: include "sysdeps.h" header instead of "config.h". + +2013-03-20 18:33:23 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstcompat.h: + * tests/codec.c: + tests: modernize GstTypeFind functions. + Use the GstTypeFind hooks from GStreamer 1.0. They look safer and + exactly correspond to the expected behaviour. + +2013-03-20 11:57:57 +0100 Gwenole Beauchesne + + * tests/image.c: + * tests/image.h: + * tests/test-decode.c: + * tests/test-display.c: + * tests/test-h264.c: + * tests/test-h264.h: + * tests/test-jpeg.c: + * tests/test-jpeg.h: + * tests/test-mpeg2.c: + * tests/test-mpeg2.h: + * tests/test-mpeg4.c: + * tests/test-mpeg4.h: + * tests/test-textures.c: + * tests/test-vc1.c: + * tests/test-vc1.h: + * tests/test-windows.c: + tests: fix license templates. + +2013-03-20 11:53:59 +0100 Gwenole Beauchesne + + * tests/test-display.c: + tests: use gst_vaapi_image_format_from_structure() in test-display. + Use gst_vaapi_image_format_from_structure() helper in test-display and + then extract a VAImageFormat from it instead of relying on GstCaps for + YUV and RGB formats. + +2013-03-20 11:50:15 +0100 Gwenole Beauchesne + + * tests/codec.c: + * tests/decoder.c: + * tests/output.c: + * tests/test-decode.c: + * tests/test-display.c: + * tests/test-subpicture.c: + * tests/test-textures.c: + * tests/test-windows.c: + tests: include "sysdeps.h" header instead of "config.h". + +2013-03-20 18:25:05 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstcompat.h: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + subpicture: use gst_video_overlay_rectangle_get_pixels_unscaled_raw(). + Use newer gst_video_overlay_rectangle_get_pixels_unscaled_raw() helper + function with GStreamer 0.10 compatible semantics, or that tries to + approach the current meaning. Basically, this is also just about moving + the helper to gstcompat.h. + +2013-03-20 11:10:31 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiimageformat.c: + * gst-libs/gst/vaapi/gstvaapiimageformat.h: + image: add gst_vaapi_image_format_from_structure() helper. + Add helper function to convert video formats from a GstStructure to a + plain GstVaapiImageFormat. + +2013-03-20 18:12:18 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstcompat.h: + * gst-libs/gst/vaapi/sysdeps.h: + sysdeps: split out GStreamer API compatibility glue to "gstcompat.h". + +2013-03-20 11:56:15 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/sysdeps.h: + sysdeps: add more standard includes by default. + +2013-03-20 14:43:46 +0100 Gwenole Beauchesne + + * configure.ac: + configure: improve GStreamer API version checks. + +2013-03-20 11:44:10 +0100 Gwenole Beauchesne + + * configure.ac: + * debian.upstream/Makefile.am: + * debian.upstream/changelog.in: + * debian.upstream/control.in: + * debian.upstream/gstreamer-vaapi-doc.install.in: + * debian.upstream/libgstvaapi-dev.install.in: + * debian.upstream/libgstvaapi-drm.install.in: + * debian.upstream/libgstvaapi-glx.install.in: + * debian.upstream/libgstvaapi-wayland.install.in: + * debian.upstream/libgstvaapi-x11.install.in: + * debian.upstream/libgstvaapi.install.in: + * docs/reference/libs/Makefile.am: + * docs/reference/libs/libs-docs.xml.in: + * docs/reference/plugins/Makefile.am: + * docs/reference/plugins/plugins-docs.xml.in: + * gst-libs/gst/vaapi/Makefile.am: + * gst/vaapi/Makefile.am: + * pkgconfig/Makefile.am: + * pkgconfig/gstreamer-vaapi-drm.pc.in: + * pkgconfig/gstreamer-vaapi-glx.pc.in: + * pkgconfig/gstreamer-vaapi-wayland.pc.in: + * pkgconfig/gstreamer-vaapi-x11.pc.in: + * pkgconfig/gstreamer-vaapi.pc.in: + * tests/Makefile.am: + configure: rename GST_MAJORMINOR to GST_API_VERSION. + +2013-03-20 11:28:06 +0100 Gwenole Beauchesne + + * configure.ac: + configure: improve check for H.264 codecparser. + +2013-02-26 00:38:24 +0100 Holger Kaelberer + + * gst/vaapi/gstvaapiuploader.c: + vaapiupload: fix illegal write in ensure_image(). + Fix ensure_image() to only zero-initialize the first line of each plane. + Properly initializing each plane to their full vertical resolution would + require to actually compute it based on the image format. + In particular, for NV12 images, the UV plane has half vertical resolution + vs. the Y plane. So using the full image height to initialize the UV plane + will obviously lead to a buffer overflow. Likewise for other YUV format. + Since ensure_image() is only a helper function to initialize something, + and not necessarily the whole thing, it is fine to initializ the first + line only. Besides, the target surface is not rendered either. + Signed-off-by: Gwenole Beauchesne + +2013-02-17 16:28:47 +0800 Xiang, Haihao + + * gst-libs/gst/codecparsers/Makefile.am: + * gst-libs/gst/video/Makefile.am: + build: fix compiling of local GstVideoDecoder and codecparsers. + Generated source files were missing a dependency on the complete set of + generated header files. e.g. gstvideodecoder.c requires gstvideoutils.h + to build and almost every codec parser source depends on parserutils.h. + https://bugs.freedesktop.org/show_bug.cgi?id=59575 + Signed-off-by: Xiang, Haihao + Signed-off-by: Gwenole Beauchesne + +2013-02-08 11:56:54 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: set {luma,chroma}_log2_weight_denom to 0 if no pred_weight_table(). + Force luma_log2_weight_denom and chroma_log2_weight_denom to zero if + there is no pred_weight_table() that was parsed. + This is a workaround for the VA intel-driver on Ivy Bridge. + +2013-02-07 15:42:55 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: use new profile definitions from codecparsers. + +2013-02-07 15:29:44 +0100 Gwenole Beauchesne + + * ext/codecparsers: + codecparsers: update to gst-vaapi-branch commit 500bc02. + 500bc02 h264: add profile enums + +2013-02-06 15:27:18 +0100 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2013-02-06 15:21:27 +0100 Gwenole Beauchesne + + * ext/codecparsers: + codecparsers: update to gst-vaapi-branch commit 31b1c57. + 8957fb7 mpeg2: add helpers to convert quantization matrices + 07c4034 mpeg2: store quantization matrices in zigzag scan order + +2013-01-31 11:32:24 +0100 Gwenole Beauchesne + + * tests/simple-decoder.c: + tests: simple-decoder: fix build on older platforms. + Make simple-decoder build and execute correctly on older platforms, + and more precisely older versions of glib. + +2013-01-31 11:30:12 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/glibcompat.h: + glibcompat: add replacement for g_async_queue_timeout_pop(). + g_async_queue_timeout_pop() appeared in glib 2.31.18. Implement it as + g_async_queue_timed_pop() with a GTimeVal as the final time to wait for + new data to arrive in the queue. + +2013-01-31 11:25:18 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/glibcompat.h: + glibcompat: add replacement for g_cond_wait(). + +2013-01-30 18:38:38 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: fix decoding of 4K videos. + Account for slice_vertical_position_extension when vertical_size > 2800. + +2013-01-30 18:54:13 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: fix decoding of sequence_end(). + There shall be only one place to call decode_current_picture(), and this + is in the end_frame() hook. The EOS unit is processed after end_frame() + so this means we cannot have a valid picture to decode/output at this + point. + +2013-01-30 15:10:06 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: improve robustness when packets are missing. + Improve robustness when some expected packets where not received yet + or that were not correctly decoded. For example, don't try to decode + a picture if there was no valid sequence or picture headers. + +2013-01-30 18:58:01 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + decoder: handle decode-only frames in raw API mode. + Fix gst_vaapi_decoder_get_surface() to only return frames with a valid + surface proxy, i.e. with a valid VA surface. This means that any frame + marked as decode-only is simply skipped. + +2013-01-30 16:33:48 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + decoder: allow frames to be dropped. + If the decoder was not able to decode a frame because insufficient + information was available, e.g. missing sequence or picture header, + then allow the frame to be gracefully dropped without generating + any error. + It is also possible that a frame is not meant to be displayed but + only used as a reference, so dropping that frame is also a valid + operation since GstVideoDecoder base class has extra references to + that GstVideoCodecFrame that needs to be released. + +2013-01-30 16:26:07 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: handle decode-only frames. + Decode-only frames may not have a valid surface proxy. So, simply discard + them gracefully, i.e. don't create meta data information. GstVideoDecoder + base class will properly handle this case and won't try to push any buffer + to downstream elements. + +2013-01-24 00:49:17 +0200 Sreerenj Balachandran + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: add support for post-seek semantics reset. + Implement GstVideoDecoder::reset() as a destruction of the VA decoder + and the creation of a new VA decoder. + Signed-off-by: Gwenole Beauchesne + +2013-01-30 09:38:07 +0100 Gwenole Beauchesne + + * configure.ac: + Bump version for development. + +2013-01-30 09:37:38 +0100 Gwenole Beauchesne + + * NEWS: + * configure.ac: + 0.5.1. + +2013-01-24 00:48:26 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: implement GstVaapiDecoder::flush() as a DPB flush. + +2013-01-24 17:34:43 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_frame.h: + decoder: fix documentation for GstVaapiDecoderFrame. + Drop superfluous reference to prev_slice member. + +2013-01-29 16:18:13 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + decoder: assume current frame is complete at end-of-stream. + Assume we got a complete frame when the end-of-stream is reached and that + the current codec frame contains at least one slice data unit. + +2013-01-29 14:14:45 +0100 Gwenole Beauchesne + + * NEWS: + * README: + * debian.upstream/copyright: + * gst-libs/gst/vaapi/gstvaapicodec_objects.c: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_dpb.c: + * gst-libs/gst/vaapi/gstvaapidecoder_dpb.h: + * gst-libs/gst/vaapi/gstvaapidecoder_frame.c: + * gst-libs/gst/vaapi/gstvaapidecoder_frame.h: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * gst-libs/gst/vaapi/gstvaapidecoder_unit.c: + * gst-libs/gst/vaapi/gstvaapidecoder_unit.h: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapiminiobject.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.h: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer.h: + * gst-libs/gst/vaapi/gstvaapivideoconverter_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + * gst-libs/gst/vaapi/sysdeps.h: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapipluginbuffer.c: + * gst/vaapi/gstvaapipluginbuffer.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiupload.c: + * gst/vaapi/gstvaapiuploader.c: + * tests/output.c: + * tests/test-decode.c: + * tests/test-subpicture.c: + legal: fix year for some copyright notices (2013). + +2013-01-29 14:03:27 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.h: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.h: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.h: + * gst-libs/gst/vaapi/gstvaapiimageformat.c: + * gst-libs/gst/vaapi/gstvaapiimageformat.h: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.h: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapisurface_priv.h: + * gst-libs/gst/vaapi/gstvaapiutils_x11.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer.h: + * gst-libs/gst/vaapi/gstvaapivideoconverter_glx.c: + * gst-libs/gst/vaapi/gstvaapivideoconverter_glx.h: + * gst/vaapi/gstvaapidecode.h: + * gst/vaapi/gstvaapisink.h: + * tests/test-subpicture.c: + legal: fix year for some copyright notices (2012). + +2013-01-29 14:00:04 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicompat.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h: + * gst-libs/gst/vaapi/gstvaapiimagepool.c: + * gst-libs/gst/vaapi/gstvaapiimagepool.h: + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapiobject.h: + * gst-libs/gst/vaapi/gstvaapiobject_priv.h: + * gst-libs/gst/vaapi/gstvaapiparamspecs.c: + * gst-libs/gst/vaapi/gstvaapiparamspecs.h: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.h: + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapitexture.h: + * gst-libs/gst/vaapi/gstvaapitypes.h: + * gst-libs/gst/vaapi/gstvaapiutils_glx.h: + * gst-libs/gst/vaapi/gstvaapiutils_x11.h: + * gst-libs/gst/vaapi/gstvaapivalue.c: + * gst-libs/gst/vaapi/gstvaapivalue.h: + * gst-libs/gst/vaapi/gstvaapivideopool.c: + * gst-libs/gst/vaapi/gstvaapivideopool.h: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.h: + * tests/test-display.c: + * tests/test-surfaces.c: + * tests/test-windows.c: + legal: add Intel copyright on modified files. + +2013-01-29 13:37:41 +0100 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2013-01-28 18:09:09 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + wayland: use a local event queue to avoid lock contention. + This improves performance when rendering several surfaces from within + the same process. e.g. a tee of vaapidecode'd buffers to vaapisink. + +2013-01-28 17:28:58 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + wayland: fix thread-safe issues. + The Wayland API is not fully thread-safe and client applications shall + perform locking themselves on key functions. Besides, make sure to + release the lock if the _render() function fails. + +2013-01-28 16:37:28 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + wayland: really wait until the pending redraw completed. + Introduce gst_vaapi_window_wayland_sync() helper function to wait for + the completion of the redraw request. Use it in _render() function to + actually block until the previous draw request is completed. + +2013-01-23 10:10:35 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + wayland: fix frame_redraw callback. + The redraw callback needs to be attached to the surface prior to the + commit. Otherwise, the callback notifies the next surface repaint, + which is not the desired behaviour. i.e. we want to be notified for + the surface we have just filled. + Another isse was the redraw_pending was reset before the actual completion + of the frame redraw callback function, thus causing concurrency issues. + e.g. the callback could have been called again, but with a NULL buffer. + +2013-01-28 14:45:28 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + wayland: fix display sharing. + When the Wayland display is shared, we still have to create our own local + shell and compositor objects, since they are not propagated from the cache. + Likewise, we also need to determine the display size or vaapisink would + fail to account for the display aspect ratio, and will try to create a 0x0 + window. + +2013-01-24 17:38:53 +0100 Gwenole Beauchesne + + * ext/codecparsers: + codecparsers: update to gst-vaapi-branch commit 21a098e. + 21a098e vc1: fix bitplanes decoding (DIFF6 or NORM6) [residual] + f8c836a vc1: fix bitplanes decoding (DIFF6 or NORM6) + +2013-01-23 16:38:24 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + vc1: handle frames with multiple slices. + +2013-01-23 17:01:34 +0100 Gwenole Beauchesne + + * ext/codecparsers: + codecparsers: update to gst-vaapi-branch commit 3fba492. + 3fba492 vc1: add API to parse slice headers + +2013-01-23 11:11:25 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + vc1: handle CLOSED_ENTRY. + When CLOSED_ENTRY == 0, and if the B pictures that follow an entry-point + lack a reference anchor picture, these B pictures shall be discarded. + https://bugs.freedesktop.org/show_bug.cgi?id=59505 + +2013-01-23 10:25:52 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + vc1: cope with latest codecparser changes. + Fix build with newer VC-1 codecparser where dqsbedge was renamed to + dqbedge, and now represents either DQSBEDGE or DQDBEDGE depending on + the actual value of DQPROFILE. + +2013-01-23 10:24:04 +0100 Gwenole Beauchesne + + * ext/codecparsers: + codecparsers: update to gst-vaapi-branch commit 3d2c67c. + 3d2c67c vc1: simplify GstVC1VopDquant structure + +2013-01-22 10:51:40 +0100 Gwenole Beauchesne + + * ext/codecparsers: + codecparsers: update to gst-vaapi-branch commit 5d33da8. + 5d33da8 vc1: fix bitplanes decoding + 562bdc4 vc1: fix VOPDQUANT parser for DQUANT == 2 + 0b13d2b vc1: fix calculation of ALTPQUANT + ba88e63 vc1: fix parser for DQPROFILE in VOPDQUANT + +2013-01-22 15:47:09 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + vc1: fix size of encapsulated BDU. + Fix size of encapsulated BDUs since GstVC1BDU.size actually represents + the size of the BDU data, starting from offset, i.e. after any start + code is parsed. + This fixes a buffer overflow during the unescaping process. + +2013-01-11 17:08:00 +0800 Wind Yuan + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + vc1: fix decoding of WMV3 videos in AVI format. + The AVI demuxer (avidemux) does not set a proper "format" attribute + to the generated caps. So, try to recover the video codec format from + the "wmvversion" property instead. + Signed-off-by: Gwenole Beauchesne + +2013-01-22 13:28:13 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + vc1: review and report errors accordingly. + Use GST_ERROR() to report real errors instead of hiding them into + GST_DEBUG(). + +2013-01-22 13:50:39 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + vc1: don't create GstBuffers for all decoder units. + Don't create temporary GstBuffers for all decoder units, even if they + are lightweight "sub-buffers", since it is not really necessary to keep + the buffer data around. + +2013-01-22 16:03:18 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + vc1: implement flush() hook. + Make it a simple DPB flush. + +2013-01-22 13:44:32 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + vc1: implement {start,end}_frame() hooks. + Implement GstVaapiDecoder.start_frame() and end_frame() semantics so + that to create new VA context earlier and submit VA pictures to the + HW for decoding as soon as possible. i.e. don't wait for the next + frame to start decoding the previous one. + +2013-01-22 09:30:04 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + vc1: fix next POC for new sequence layers. + Fix next POC when a new sequence layer is reached. At this point, we + need to reset any previous reference picture, i.e. non B-frame. + +2012-08-02 17:15:26 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + vc1: port to common GstVaapiDpb interface. + Use GstVaapiDpb interface instead of maintaining our own prev and next + picture pointers. While doing so, try to derive a sensible POC value. + Signed-off-by: Gwenole Beauchesne + +2013-01-15 17:10:56 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + vc1: fix decode_sequence_end() to return success, not EOS. + +2013-01-18 17:00:18 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + decoder: simplify gst_vaapi_decoder_get_surface(). + Avoid extraenous branches, i.e. immediately return with success once we + have a decoded frame available. + +2013-01-18 16:56:15 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + decoder: optimize and clean decode_step() up. + Avoid usage of goto. Simplify decode_step() process to first accumulate all + pending buffers into the GstAdapter, and then parse and decode units from + that input adapter. Stop the process once a frame is fully decoded or an + error occurred. + +2013-01-18 14:46:23 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + display: move "vaapi" debug init to libgstvaapi_init_once(). + +2013-01-18 14:17:34 +0100 Gwenole Beauchesne + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapiversion.h.in: + display: dump gstreamer-vaapi version for debugging purposes. + +2013-01-18 14:30:48 +0100 Gwenole Beauchesne + + * tests/Makefile.am: + tests: simple-decoder: fix build with built-in videoutils. + Fix build with built-in videoutils, i.e. when system GStreamer installation + does not know about GstVideoDecoder API. + +2013-01-18 10:35:44 +0100 Gwenole Beauchesne + + * tests/simple-decoder.c: + tests: simple-decoder: flush decoded frames at EOS. + Flush the remaining decoded frames when an end-of-stream is reached. + +2013-01-18 10:25:14 +0100 Gwenole Beauchesne + + * tests/simple-decoder.c: + tests: simple-decoder: drop use of GstVaapiVideoMeta. + Don't use GstVaapiVideoMeta since that object is not guaranteed to live + in libgstvaapi forever. Rather, that'd move to plugin elements at some + point. + +2013-01-16 13:53:43 +0100 Gwenole Beauchesne + + * tests/simple-decoder.c: + tests: simple-decoder: add benchmark mode. + Add --benchmark option to enable benchmark mode where rendering is not + synchronized with presentation timestamps of the decoded surfaces. + +2013-01-16 13:29:06 +0100 Gwenole Beauchesne + + * tests/Makefile.am: + * tests/simple-decoder.c: + tests: simple-decoder: honour framerate from the bitstream. + Try to honour the framerate from the bitstream, or cap the playback to + 60 fps by default. + +2013-01-15 18:49:28 +0100 Gwenole Beauchesne + + * tests/simple-decoder.c: + tests: simple-decoder: set window size to the surface dimensions. + Set the window size to the decoded surface dimensions, if the user has + not requested the application to run in full-screen mode. Besides, no + effort is made to preserve aspect ratio or to center the video within + the mapped window. + +2013-01-15 17:33:18 +0100 Gwenole Beauchesne + + * tests/Makefile.am: + * tests/simple-decoder.c: + tests: add simple decoder application. + Add simple decoder application to show off decoding capabilities from + raw bitstreams, for debugging or performance evaluation purposes. + +2013-01-15 17:30:57 +0100 Gwenole Beauchesne + + * tests/Makefile.am: + * tests/codec.c: + * tests/codec.h: + tests: add codec helper utils. + Add helper functions to determine the codec type from a specific file + or utility functions to convert from codec type to GstCaps or from + codec name to codec type. + +2013-01-15 17:47:13 +0100 Gwenole Beauchesne + + * tests/output.c: + tests: allow fullscreen mode. + Add new --fullscreen|-f option to create new windows in fullscreen mode. + +2013-01-17 18:35:58 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: implement GstVaapiDecoder::flush() as a DPB flush. + +2013-01-17 18:07:03 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: handle end-of-stream NALU. + Handle NAL unit to actually flush any pending picture + from the DPB. + +2013-01-17 18:22:49 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: handle EOS events. + Flush all decoded frames to downstream when EOS is received. This is + performed by implementing GstVideoDecoder::finish() hook. + +2013-01-17 18:19:14 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: split gvd_handle_frame() into decode/push frames. + Split GstVideoDecoder::handle_frame() implementation into two functions: + (i) one for decoding the provided GstVideoCodecFrame and (ii) another one + for purging all decoded frames and submit them downstream. + +2013-01-17 18:33:32 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + decoder: add GstVaapiDecoder::flush() hook. + +2013-01-15 17:21:50 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + decoder: fix check for end-of-stream in raw API mode. + Make sure to immediately return GST_VAAPI_DECODER_STATUS_END_OF_STREAM + if the end-of-stream was already reached at the previous iteration. + +2013-01-15 16:55:29 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + decoder: make decode_step() return once the frame is decoded. + Make sure we always have a free surface left to use for decoding the + current frame. This means that decode_step() has to return once a frame + gets decoded. If the current adapter contains more buffers with valid + frames, they will get parsed and decoded on subsequent iterations. + +2013-01-17 15:47:17 +0100 Gwenole Beauchesne + + * ext/codecparsers: + codecparsers: update to gst-vaapi-branch commit b47983a. + 8840c2d h264: zero-initialize SPS VUI parameters + +2013-01-15 09:21:36 +0100 Gwenole Beauchesne + + * configure.ac: + Bump version for development. + +2013-01-15 09:21:08 +0100 Gwenole Beauchesne + + * NEWS: + * configure.ac: + 0.5.0. + +2013-01-14 11:48:58 +0100 Gwenole Beauchesne + + * docs/reference/libs/libs-docs.xml.in: + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + docs: expose new interfaces. + +2013-01-14 12:58:20 +0100 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2013-01-14 10:58:49 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_dpb.c: + dpb: cosmetics (clean-ups). + +2013-01-14 10:46:25 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_dpb.c: + * gst-libs/gst/vaapi/gstvaapidecoder_dpb.h: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + dpb: port to GstVaapiMiniObject. + +2013-01-14 10:21:53 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_dpb.c: + * gst-libs/gst/vaapi/gstvaapidecoder_dpb.h: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + dpb: drop GstVaapiDpb2 interface, keep only one class. + Keep only one DPB interface and rename gst_vaapi_dpb2_get_references() + to gst_vaapi_dpb_get_neighbours() so that to retrieve pictures in DPB + around the specified picture POC. + +2012-08-02 15:56:54 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_dpb.c: + * gst-libs/gst/vaapi/gstvaapidecoder_dpb.h: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + dpb: rename GstVaapiDpbMpeg2 to GstVaapiDpb2. + Move GstVaapiDpbMpeg2 API to a more generic version that could also be + useful to other decoders that require 2 reference pictures, e.g. VC-1. + Signed-off-by: Gwenole Beauchesne + +2013-01-11 16:04:30 +0100 Gwenole Beauchesne + + * configure.ac: + Bump version for pre-release. + +2013-01-11 15:57:09 +0100 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2012-07-20 12:36:33 +0200 Holger Kaelberer + + * configure.ac: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/sysdeps.h: + * tests/test-subpicture.c: + overlay: fix build without advanced GstVideoOverlayFormatFlags. + Check for global-alpha support in GstVideoOverlayComposition API. + Signed-off-by: Gwenole Beauchesne + +2013-01-04 10:19:56 +0100 Gwenole Beauchesne + + * tests/test-subpicture.c: + tests: add support for global-alpha subpictures. + Add --global-alpha option to test-subpicture. + +2013-01-10 13:09:28 +0100 Gwenole Beauchesne + + * tests/Makefile.am: + * tests/test-subpicture.c: + tests: use GstVideoOverlayComposition API for subpicture test. + +2013-01-10 11:26:17 +0100 Gwenole Beauchesne + + * tests/Makefile.am: + * tests/test-subpicture.c: + tests: use common decoder helpers for subpicture test. + Use common decoder helpers for subpicture test, thus allowing to decode + sample images in an alternate format. + +2013-01-10 11:22:38 +0100 Gwenole Beauchesne + + * tests/Makefile.am: + * tests/decoder.c: + * tests/decoder.h: + * tests/test-decode.c: + tests: add decoder helpers. + +2013-01-11 15:19:45 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicontext.c: + overlay: fix ordering of composition layers. + Make sure to maintain the association order of composition layers when + GstVideoOverlayRectangle objects are kept around (cached). + +2012-05-15 10:24:08 +0200 Holger Kaelberer + + * gst-libs/gst/vaapi/gstvaapicontext.c: + overlay: fix support for global-alpha. + Fix support for global-alpha subpictures. The previous changes brought + the ability to check for GstVideoOverlayRectangle changes by comparing + the underlying pixel buffer pointers. If sequence number and pixel data + did not change, then this is an indication that only the global-alpha + value changed. Now, try to update the underlying VA subpicture global-alpha + value. + Signed-off-by: Gwenole Beauchesne + +2013-01-11 11:53:05 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicontext.c: + overlay: detect render-rect changes. + Don't re-upload VA subpicture if only the render rectangle changed. + Rather deassociate the subpicture and re-associate it with the new + render rectangle. + +2013-01-11 11:12:26 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicontext.c: + overlay: fix check for pixels buffer change. + A GstVideoOverlayRectangle is created whenever the underlying pixels data + change. However, when global-alpha is supported, it is possible to re-use + the same GstVideoOverlayRectangle but with a change to the global-alpha + value. This process causes a change of sequence number, so we can no longer + check for that. + Still, if sequence numbers did not change, then there was no change in + global-alpha either. So, we need a way to compare the underlying GstBuffer + pointers. There is no API to retrieve the original pixels buffer from + a GstVideoOverlayRectangle. So, we use the following heuristics: + 1. Use gst_video_overlay_rectangle_get_pixels_unscaled_argb() with the same + format flags from which the GstVideoOverlayRectangle was created. This + will work if there was no prior consumer of the GstVideoOverlayRectangle + with alternate (non-"native") format flags. + 2. In overlay_rectangle_has_changed_pixels(), we have to use the same + gst_video_overlay_rectangle_get_pixels_unscaled_argb() function but + with flags that match the subpicture. This is needed to cope with + platforms that don't support global-alpha in HW, so the gst-video + layer takes care of that and fixes this up with a possibly new + GstBuffer, and hence pixels data (or) in-place by caching the current + global-alpha value applied. So we have to determine the rectangle + was previously used, based on what previous flags were used to + retrieve the ARGB pixels buffer. + +2013-01-10 18:42:37 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicontext.c: + overlay: optimize cache at the GstVideoOverlayRectangle level. + We previously assumed that an overlay composition changed if the number + of overlay rectangles in there actually changed, or that the rectangle + was updated, and thus its seqnum was also updated. + Now, we can cope with cases where the GstVideoOverlayComposition grew + by one or a few more overlay rectangles, and the initial overlay rectangles + are kept as is. + +2013-01-10 13:41:39 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicontext.c: + overlay: simplify caching of GstVideoOverlayComposition objects. + Create the GPtrArray once in the _init() function and destroy it only + in the _finalize() function. Then use overlay_clear() to remove all + subpicture associations for intermediate updates, don't recreate the + GPtrArray. + Make GstVaapiOverlayRectangle a reference counted object. Also make + sure that overlay_rectangle_new() actually creates and associates the + VA subpicture. + +2012-05-15 10:24:08 +0200 Holger Kaelberer + + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + overlay: add support for global-alpha. + Handle global-alpha from GstVideoOverlayComposition API. Likewise, + the same code path could also work for premultiplied-alpha but this + was not tested. + Signed-off-by: Gwenole Beauchesne + +2012-05-15 10:24:08 +0200 Holger Kaelberer + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.h: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * tests/image.c: + * tests/test-subpicture.c: + subpicture: add support for global-alpha. + Add the necessary helpers in GstVaapiDisplay to determine whether subpictures + with global alpha are supported or not. Also add accessors in GstVaapiSubpicture + to address this feature. + Signed-off-by: Gwenole Beauchesne + +2013-01-04 09:41:25 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisubpicture.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + subpicture: add premultiplied-alpha and global-alpha feature flags. + Add premultiplied-alpha and global-alpha feature flags, along with converters + between VA-API and gstreamer-vaapi definitions. Another round of helpers is + also necessary for GstVideoOverlayComposition API. + +2013-01-03 18:02:49 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + display: allow image/subpicture formats with additional flags. + Introduce new GstVaapiFormatInfo to store the actual GstVaapiImageFormat + and any additional flags needed. Currently, all flags are set to zero. + +2013-01-11 13:34:45 +0100 Gwenole Beauchesne + + * gst-libs/gst/codecparsers/Makefile.am: + * gst-libs/gst/video/Makefile.am: + * tests/Makefile.am: + libs: fix build of submodule wrappers. + Make sure to build codecparsers/ and videoutils/ sources against the + newly generated headers when out-of-source builds are used. + +2013-01-11 14:11:39 +0100 Gwenole Beauchesne + + * configure.ac: + configure: fix checks for packages installed in non-standard roots. + +2013-01-10 10:12:25 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiminiobject.c: + decoder: fix mini object implementation on 64-bit systems. + Use GPOINTER_TO_SIZE() instead of GPOINTER_TO_UINT() while manipulating + pointers. The latter is meant to be 32-bit only, not uintptr_t like size. + Only a gsize can hold all bits of a pointer. + Thanks to Ouping Zhang for spotting this error. + +2013-01-09 16:05:39 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: optimize scan for the end of the frame. + Heuristic: if the second start-code is available, check whether that + one marks the start of a new frame because e.g. this is a sequence + or picture header. This doesn't save much, since we already cache the + results. + +2013-01-09 13:44:18 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: optimize scan for start codes. + Accelerate scan for start codes by skipping up to 3 bytes per iteration. + A start code prefix is defined by the following bytes: 00 00 01. Thus, + for any group of 3 bytes (xx yy zz), we have the following possible cases: + 1. If zz != 1, this cannot be a start code, then skip 3 bytes; + 2. If yy != 0, this cannot be a start code, then skip 2 bytes; + 3. If xx != 0 or zz != 1, this cannot be a start code, then skip 1 byte; + 4. xx == 00, yy == 00, zz == 1, we have match! + This algorithm requires to peek bytes from the adapter. This increases the + amount of bytes copied to a temporary buffer, but this process is much faster + than scanning for all the bytes and using shift/masks. So, overall, this is + a win. + +2013-01-08 16:41:44 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: drop useless gst_adapter_peek(). + Drop useless gst_adapter_peek() since the returned buffer was not used + and this could incur superfluous memcpy(). + +2013-01-07 16:07:38 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: cosmetics: move parse_slice() down. + +2013-01-07 15:24:51 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: avoid too many allocations of parser info objects. + Move parsing back to decoding step, but keep functions separate for now. + This is needed for future optimizations that may introduce some meta data + for parsed info attached to codec frames. + +2013-01-07 14:04:22 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_unit.c: + * gst-libs/gst/vaapi/gstvaapidecoder_unit.h: + decoder: decoder units are no longer dynamically allocated objects. + +2013-01-07 13:59:07 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_frame.c: + * gst-libs/gst/vaapi/gstvaapidecoder_frame.h: + decoder: optimize pre-allocation of decoder units. + Optimize pre-allocation of decoder units, thus avoiding un-necessary + memory reallocations. The heuristic used is that we could have around + one slice unit per macroblock line. + +2013-01-07 13:41:59 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_frame.c: + * gst-libs/gst/vaapi/gstvaapidecoder_frame.h: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * gst-libs/gst/vaapi/gstvaapidecoder_unit.c: + decoder: use an array of units instead of a single-linked list. + Use a GArray to hold decoder units in a frame, instead of a single-linked + list. This makes 'append' calls faster, but not that much. At least, this + makes things clearer. + +2013-01-07 11:13:07 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + * gst-libs/gst/vaapi/gstvaapidecoder_unit.c: + * gst-libs/gst/vaapi/gstvaapidecoder_unit.h: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + decoder: refactor decoder unit API. + Allocate decoder unit earlier in the main parse() function and don't + delegate this task to derived classes. The ultimate purpose is to get + rid of dynamic allocation of decoder units. + +2013-01-07 10:48:27 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: introduce parser info instead of MPEG-2 specific decoder unit. + Use a new GstVaapiParserInfoMpeg2 data structure instead of deriving + from GstVaapiDecoderUnit for MPEG-2 specific parser information. + +2013-01-07 10:22:54 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: introduce parser info instead of H.264 specific decoder unit. + Use a new GstVaapiParserInfoH264 data structure instead of deriving + from GstVaapiDecoderUnit for H.264 specific parser information. + +2013-01-05 12:33:06 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: set default values for some header fields. + The SPS, PPS and slice headers are not fully zero-initialized in the + codecparsers/ library. Rather, the standard upstream behaviour is to + initialize only certain syntax elements with some inferred values if + they are not present in the bitstream. + At the gstreamer-vaapi decoder level, we need to further initialize + certain syntax elements with some sensible default values so that to + not complicate VA drivers that just pass those verbatim to the HW, + and also avoid an memset() of the whole decoder unit. + Signed-off-by: Sreerenj Balachandran + Signed-off-by: Gwenole Beauchesne + +2013-01-06 19:05:49 +0100 Gwenole Beauchesne + + * ext/codecparsers: + codecparsers: update to gst-vaapi-rebased commit b47983a. + b47983a h264: add inferred value for slice_beta_offset_div2 + +2013-01-05 17:55:47 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapipluginbuffer.c: + * gst/vaapi/gstvaapipluginbuffer.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiupload.c: + * gst/vaapi/gstvaapiuploader.c: + plugins: cope with new GstVaapiVideoMeta API. + Update plugin elements with the new GstVaapiVideoMeta API. + This also fixes support for subpictures/overlay because GstVideoDecoder + generates a sub-buffer from the GstVaapiVideoBuffer. So, that sub-buffer + is marked as read-only. However, when comes in the textoverlay element + for example, it checks whether the input buffer is writable. Since that + buffer read-only, then a new GstBuffer is created. Since gst_buffer_copy() + does not preserve the parent field, the generated buffer in textoverlay + is not exploitable because we lost all VA specific information. + Now, with GstVaapiVideoMeta information attached to a standard GstBuffer, + all information are preserved through gst_buffer_copy() since the latter + does copy metadata (qdata in this case). + +2013-01-05 17:37:13 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer.h: + * gst-libs/gst/vaapi/gstvaapivideobuffer_glx.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer_glx.h: + * gst-libs/gst/vaapi/gstvaapivideobuffer_priv.h: + * gst-libs/gst/vaapi/gstvaapivideoconverter_glx.c: + videobuffer: wrap video meta into a surface buffer. + Make GstVaapiVideoBuffer a simple wrapper for video meta. This buffer is + no longer necessary but for compatibility with GStreamer 0.10 APIs or users + expecting a GstSurfaceBuffer like Clutter. + +2013-01-05 08:31:24 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapivideometa.c: + * gst-libs/gst/vaapi/gstvaapivideometa.h: + videobuffer: add video meta information. + Add new GstVaapiVideoMeta object that holds all information needed to + convey gst-vaapi specific data as a GstBuffer. + +2013-01-03 13:10:33 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: fix calculation of the time-out value. + Fix calculation of the time-out value for cases where no VA surface is + available for decoding. In this case, we need to wait until downstream + sink consumed at least one surface. The time-out was miscalculated as + it was always set to + one second, which is not suitable + for streams with larger gaps. + +2013-01-03 13:05:47 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + decoder: always use the calculated presentation timestamp. + Use PTS value computed by the decoder, which could also be derived from + the GstVideoCodecFrame PTS. This makes it possible to fix up the PTS if + the original one was miscomputed or only represented a DTS instead. + +2013-01-02 17:33:15 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: don't create sub-buffer for slice data. + +2013-01-03 11:16:44 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + decoder: create new context when encoded resolution changes. + Create a new VA context if the encoded surface size changes because we + need to keep the underlying surface pool until the last one was released. + Otherwise, either of the following cases could have happened: (i) release + a VA surface to an inexistent pool, or (ii) release VA surface to an + existing surface pool, but with different size. + +2013-01-02 17:23:53 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: don't create sub-buffer for slice data. + Avoid creating a GstBuffer for slice data. Rather, directly use the codec + frame input buffer data. This is possible because the codec frame is valid + until end_frame() where we submit the VA buffers for decoding. Anyway, the + slice data buffer is copied into the VA buffer when it is created. + +2013-01-02 14:45:50 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: minor clean-ups. + Drop explicit initialization of most fields that are implicitly set to + zero. Remove some useless checks for NULL pointers. + +2013-01-02 14:18:31 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: optimize scan for the second start code. + Optimize scan for the second start code, on the next parse() call so that + to avoid scanning again earlier bytes where we didn't find any start code. + +2013-01-02 14:10:20 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: use sequence_display_extension() to compute PAR. + Also compute pixel-aspect-ratio from sequence_display_extension(), + should it exist in the bitstream. + +2013-01-02 14:02:29 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: handle sequence_display_extension(). + +2012-12-27 15:18:55 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: implement {start,end}_frame() hooks. + Implement GstVaapiDecoder.start_frame() and end_frame() semantics so + that to create new VA context earlier and submit VA pictures to the + HW for decoding as soon as possible. i.e. don't wait for the next + frame to start decoding the previous one. + +2012-12-27 14:54:29 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: parse slice() header earlier. + Parse slice() header and first macroblock position earlier in _parse() + function instead of waiting for the _decode() stage. This doesn't change + anything but readability. + +2012-12-27 14:41:04 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: add codec specific decoder unit. + Introduce new GstVaapiDecoderUnitMpeg2 object, which holds the standard + GstMpegVideoPacket and additional parsed header info. Besides, we now + parse as early as in the _parse() function so that to avoid un-necessary + creation of sub-buffers in _decode() for video packets that are not slices. + +2012-12-27 18:52:43 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_frame.c: + * gst-libs/gst/vaapi/gstvaapidecoder_frame.h: + * gst-libs/gst/vaapi/gstvaapidecoder_unit.h: + decoder: introduce lists of units to decode before/after frame. + Theory of operations: all units marked as "slice" are moved to the "units" + list. Since this list only contains slice data units, the prev_slice pointer + was removed. Besides, we now maintain two extra lists of units to be decoded + before or after slice data units. + In particular, all units in the "pre_units" list will be decoded before + GstVaapiDecoder::start_frame() is called and units in the "post_units" + list will be decoded after GstVaapiDecoder::end_frame() is called. + +2013-01-02 16:06:18 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicodec_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + decoder: drop useless checks for codec objects. + Codec objects are used internally only and they are bound to be created + with a valid GstVaapiDecoder object. + +2012-12-27 10:35:45 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: use GST_ERROR to print error messages. + +2012-12-27 09:55:14 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: avoid double release of frame on error. + Don't call gst_video_decoder_drop_frame() if gst_video_decoder_finish_frame() + was already called before and it returned an error. In that case, we were + releasing the frame again, thus leading to a "double-free" condition. + +2012-12-21 14:29:01 +0100 Gwenole Beauchesne + + * .gitmodules: + * autogen.sh: + * configure.ac: + * ext/Makefile.am: + * ext/videoutils: + * gst-libs/gst/Makefile.am: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/video/Makefile.am: + * gst/vaapi/Makefile.am: + Add videoutils submodule for GstVideoDecoder APIs. + +2012-12-18 16:36:01 +0100 Gwenole Beauchesne + + * configure.ac: + configure: check for GstVideoDecoder API. + GstVideoDecoder API is part of an unreleased GStreamer 0.10 stack. In particular, + this is only available in git 0.10 branch or GStreamer >= 1.0 stack. Interested + parties may either use upstream git 0.10 branch or backport the necessary support + for GstVideoDecoder API, thus including helper tools like GstVideoCodecFrame et al. + +2012-12-18 16:21:31 +0100 Gwenole Beauchesne + + * docs/reference/libs/libs.core.types: + docs: remove obsolete gst_vaapi_surface_proxy_get_type(). + GstVaapiSurfaceProxy is no longer based on the GType system. + +2012-12-18 16:17:22 +0100 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + docs: fix entries for GstVaapiSurfaceProxy. + +2012-12-18 15:29:58 +0100 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2012-12-18 15:15:52 +0100 Gwenole Beauchesne + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + Bump library major version. + Increase library major so that to cope with API/ABI incompatible changes + since 0.4.x series and avoid user issues. + +2012-12-13 16:02:52 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + surfaceproxy: minor clean-ups. + +2012-12-13 15:51:24 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + surfaceproxy: drop accessors to obsolete attributes. + Make GstVaapiSurfaceProxy only a thin wrapper around a VA context and a + VA surface. i.e. drop any other attribute like timestamp, duration, + interlaced or top-field-first. + +2012-12-13 15:34:10 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * gst/vaapi/gstvaapidecode.c: + decoder: maintain decoded frames as GstVideoCodecFrame objects. + Maintain decoded surfaces as GstVideoCodecFrame objects instead of + GstVaapiSurfaceProxy objects. The latter will tend to be reduced to + the strict minimum: a context and a surface. + +2012-12-13 14:30:18 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: output all decoded frames as soon as possible. + Make sure to push all decoded frames downstream as soon as possible. + This makes sure we don't need to wait for a new frame to be ready to + be decoded before receiving new decoded frames. + This also separates the decode process and the output process. The latter + could be moved to a specific GstTask later on. + +2012-12-13 14:27:18 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + decoder: add gst_vaapi_decoder_get_frame() API. + Add new gst_vaapi_decoder_get_frame() function meant to be used with + gst_vaapi_decoder_decode(). The purpose is to return the next decoded + frame as a GstVideoCodecFrame and the associated GstVaapiSurfaceProxy + as the user-data object. + +2012-12-13 15:47:27 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: use GstBuffer flags for TFF. + Determine whether the buffer represents the top-field only by checking for + the GST_VIDEO_BUFFER_TFF flag instead of relying on the GstVaapiSurfaceProxy + flag. Also trust "interlaced" caps to determine whether the input frame + is interleaved or not. + +2012-12-13 13:27:33 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: handle video sub-buffers. + Intermediate elements may produce a sub-buffer from a valid GstVaapiVideoBuffer + for non raw YUV cases. Make sure vaapipostproc now understands those buffers. + +2012-12-18 14:57:36 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: optimize initialization process of decoder units. + Decoder units were zero-initialized, including the SPS/PPS/slice headers. + The latter don't require zero-initialization since the codecparsers/ lib + will do so for key variables already. This is not a great value per se but + at least it makes it possible to check whether the default initialization + decisions made in the codecparsers/ lib were right or not. + This can be reverted if this exposes too many issues. + +2012-12-13 11:48:06 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: minor clean-ups. + Drop explicit initialization of most fields that are implicitly set to + zero. Drop helper macros for casting to GstVaapiPictureH264 or + GstVaapiFrameStore. Also remove some useless checks for NULL pointers. + +2012-12-07 17:45:03 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: drop GstVaapiSliceH264 object. + Use standard GstVaapiSlice object from now on since we already have + parsed and recorded the slice headers (GstH264SliceHdr decode units). + +2012-12-13 10:47:25 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: detect new pictures from decode-units. + Update is_new_picture() to cope with GstVaapiDecoderUnitH264, instead + of assuming frame boundaries when first_mb_in_slice is zero. + +2012-12-13 10:21:46 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: implement {start,end}_frame() hooks. + Implement GstVaapiDecoder.start_frame() and end_frame() semantics so + that to create new VA context earlier and submit VA pictures to the + HW for decoding as soon as possible. i.e. don't wait for the next + frame to start decoding the previous one. + +2012-12-12 18:33:52 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: optimize scan for the second start code. + Optimize scan for the second start code, on the next parse() call so that + to avoid scanning again earlier bytes where we didn't find any start code. + +2012-12-06 17:25:01 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: add codec specific decoder unit. + Introduce new GstVaapiDecoderUnitH264 object, which holds the standard + NAL unit header (GstH264NalUnit) and additional parsed header info. + Besides, we now parse headers as early as in the _parse() function so + that to avoid un-necessary creation of sub-buffers in _decode() for + NAL units that are not slices. + This is a performance win by ~+1.1% only. + +2012-12-04 11:01:42 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + vaapisink: handle sub video-buffers. + Intermediate elements may produce a sub-buffer from a valid GstVaapiVideoBuffer + for non raw YUV cases. Make sure vaapisink now understands those buffers. + +2012-12-12 15:22:32 +0100 Sreerenj Balachandran + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: use gst_vaapi_decoder_get_codec_state(). + Directly use the GstVideoCodecState associated with the VA decoder + instead of parsing caps again. + Signed-off-by: Sreerenj Balachandran + Signed-off-by: Gwenole Beauchesne + +2012-12-04 14:53:15 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: use more standard helpers. + Use g_clear_object() [glib >= 2.28] and gst_caps_replace() helper functions + in more places. + +2012-12-04 14:45:29 +0100 Sreerenj Balachandran + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + vaapidecode: move to GstVideoDecoder base class. + Make vaapidecode derive from the standard GstVideoDecoder base element + class. This simplifies the code to the strict minimum for the decoder + element and makes it easier to port to GStreamer 1.x API. + Signed-off-by: Sreerenj Balachandran + Signed-off-by: Gwenole Beauchesne + +2012-12-06 14:02:25 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + jpeg: initial port to new GstVaapiDecoder API + +2012-12-06 14:02:21 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + vc1: initial port to new GstVaapiDecoder API + +2012-12-06 14:02:17 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: initial port to new GstVaapiDecoder API + +2012-12-17 09:47:20 -0800 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + mpeg4: initial port to new GstVaapiDecoder API + +2012-12-06 14:01:46 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: initial port to new GstVaapiDecoder API. + +2012-12-12 15:09:21 +0100 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + decoder: use GstVideoCodecState. + Use standard GstVideoCodecState throughout GstVaapiDecoder and expose + it with a new gst_vaapi_decoder_get_codec_state() function. This makes + it possible to drop picture size (width, height) information, framerate + (fps_n, fps_d) information, pixel aspect ratio (par_n, par_d) information, + and interlace mode (is_interlaced field). + This is a new API with backwards compatibility maintained. In particular, + gst_vaapi_decoder_get_caps() is still available. + Signed-off-by: Sreerenj Balachandran + Signed-off-by: Gwenole Beauchesne + +2012-12-12 13:44:07 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * tests/test-decode.c: + * tests/test-subpicture.c: + decoder: update gst_vaapi_decoder_get_surface() semantics. + Align gst_vaapi_decoder_get_surface() semantics with the rest of the + API. That is, return a GstVaapiDecoderStatus and the decoded surface + as a handle to GstVaapiSurfaceProxy in parameter. + This is an API/ABI change. + +2012-12-07 16:40:44 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + decoder: use standard helper functions. + Use g_clear_object(), gst_buffer_replace() and gst_caps_replace() + whenever necessary. + +2012-11-29 15:06:00 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + decoder: expose new parse/decode API. + Introduce new decoding process whereby a GstVideoCodecFrame is created + first. Next, input stream buffers are accumulated into a GstAdapter, + that is then passed to the _parse() function. The GstVaapiDecoder object + accumulates all parsed units and when a complete frame or field is + detected, that GstVideoCodecFrame is passed to the _decode() function. + Ultimately, the caller receives a GstVaapiSurfaceProxy if decoding + process was successful. + +2012-12-13 10:20:35 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + decoder: add {start,end}_frame() hooks. + The start_frame() hook is called prior to traversing all decode-units + for decoding. The unit argument represents the first slice in the frame. + Some codecs (e.g. H.264) need to wait for the first slice in order to + determine the actual VA context parameters. + +2012-12-06 13:57:42 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + decoder: add new GstVaapiDecoder API. + Split decoding process into two steps: (i) parse incoming bitstreams + into simple decoder-units until the frame or field is complete; and + (ii) decode the whole frame or field at once. + This is an ABI change. + +2012-12-05 10:51:41 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidecoder_frame.c: + * gst-libs/gst/vaapi/gstvaapidecoder_frame.h: + decoder: add new "decoder-frame" object. + Introduce a new GstVaapiDecoderFrame that is just a list of decoder units + (GstVaapiDecoderUnit objects) that constitute a frame. This object is just + an extension to GstVideoCodecFrame for VA decoder purposes. It is available + as the user-data member element. + This is a libgstvaapi internal object. + +2012-12-06 09:44:01 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidecoder_unit.c: + * gst-libs/gst/vaapi/gstvaapidecoder_unit.h: + decoder: add new "decoder-unit" object. + Introduce GstVaapiDecoderUnit which represents a fragment of the source + stream to be decoded. For instance, a decode-unit will be a NAL unit for + H.264 streams, an EBDU for VC-1 streams, and a video packet for MPEG-2 + streams. + This is a libgstvaapi internal object. + +2012-12-03 14:09:01 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + Port GstVaapiFrameStore to GstVaapiMiniObject. + +2012-12-03 11:19:08 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicodec_objects.c: + * gst-libs/gst/vaapi/gstvaapicodec_objects.h: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + Port codec objects to GstVaapiMiniObject. + +2012-12-03 13:46:28 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginbuffer.c: + * tests/test-decode.c: + * tests/test-subpicture.c: + surfaceproxy: port to GstVaapiMiniObject. + GstVaapiSurfaceProxy does not use any particular functionality from + GObject. Actually, it only needs a basic object type with reference + counting. + This is an API and ABI change. + +2012-11-30 17:25:07 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiminiobject.c: + * gst-libs/gst/vaapi/gstvaapiminiobject.h: + Add GstVaapiMiniObject. + Introduce a new reference counted object that is very lightweight and + also provides flags and user-data functionalities. Initialization and + finalization times are reduced by up to a factor 5x vs GstMiniObject + from GStreamer 0.10 stack. + This is a libgstvaapi internal object. + +2012-12-17 02:51:17 -0800 Gwenole Beauchesne + + * tests/Makefile.am: + * tests/test-decode.c: + * tests/test-mpeg4.c: + * tests/test-mpeg4.h: + tests: add test for MPEG-4:2 decoding. + +2012-12-17 04:42:29 -0800 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: initialize VA context before allocating the first slice. + Fix decode_slice() to ensure a VA context exists prior to creating a + new GstVaapiSliceH264, which invokes vaCreateBuffer() with some VA + context ID. i.e. the latter was not initialized, thus causing failures + on Cedar Trail for example. + +2012-12-05 09:15:32 +0800 Zhao Halley + + * configure.ac: + configure: install plugin elements in GST_PLUGIN_PATH, if set. + If GST_PLUGIN_PATH environment variable exists and points to a valid + directory, then use it as the system installation path for gst-vaapi + plugin elements. + Signed-off-by: Gwenole Beauchesne + +2012-12-17 14:27:56 +0100 Gwenole Beauchesne + + * configure.ac: + configure: downgrade glib required version to 2.28. + +2012-12-17 09:41:24 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/glibcompat.h: + * gst/vaapi/gstvaapi.c: + libs: fix compatibility with glib 2.28. + Always prefer non deprecated APIs by default and provide compatibility + glue for older glib versions when necessary. + +2012-12-17 10:10:55 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplaycache.c: + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + libs: use glib >= 2.32 semantics for mutexes. + Use glib >= 2.32 semantics for GMutex and GRecMutex wrt. initialization + and termination. Basically, the new mutex objects can be used as static + mutex objects from the deprecated APIs, e.g. GStaticMutex and GStaticRecMutex. + +2012-12-17 04:15:53 -0800 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + libs: only export gst_vaapi_*() symbols. + This fixes symbol clashes between the gst-vaapi built-in codecparsers/ + library and the system-provided one, mainly used by videoparses/. Now, + only symbols with the gst_vaapi_* prefix will be exported, if they are + not marked as "hidden" to libgstvaapi. + +2012-11-20 18:21:41 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapiuploader.c: + vaapiupload: reset direct-rendering to zero when changing caps. + Make sure to reset direct-rendering flag to zero when caps are changed, + and only derive it to one when the next checks succeed. + +2012-11-20 14:42:24 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapiupload.c: + vaapiupload: fix sink caps to report the supported set of YUV caps. + Try to allocate the GstVaapiUploader helper object prior to listing the + supported image formats. Otherwise, only a single generic caps is output + with no particular pixel format referenced in there. + +2012-11-20 14:32:40 +0100 Zhao Halley + + * gst/vaapi/gstvaapiupload.c: + * gst/vaapi/gstvaapiupload.h: + vaapiupload: use new GstVaapiUploader helper. + Use GstVaapiUploader helper that automatically handles direct rendering + mode, thus making the "direct-rendering" property obsolete and hence it + is now removed. + The "direct-rendering" level 2, i.e. exposing VA surface buffers, was never + really well supported and it could actually trigger degraded performance. + Signed-off-by: Gwenole Beauchesne + +2012-11-20 15:50:56 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiuploader.c: + * gst/vaapi/gstvaapiuploader.h: + vaapisink: compute and expose the supported set of YUV caps. + Make vaapisink expose only the set of supported caps for raw YUV buffers. + Add gst_vaapi_uploader_get_caps() helper function to determine the set + of supported YUV caps as source (for images). This function actually + tries to zero and upload each image to a 64x64 test surface. Of course, + this relies on VA drivers to not claim success if vaPutImage() is not + correctly supported. + +2012-11-20 14:28:55 +0100 Gwenole Beauchesne + + * NEWS: + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + * gst/vaapi/gstvaapiuploader.c: + * gst/vaapi/gstvaapiuploader.h: + vaapisink: add support for raw YUV buffers. + Add new GstVaapiUploader helper to upload raw YUV buffers to VA surfaces. + It is up to the caller to negotiate source caps (for images) and output + caps (for surfaces). gst_vaapi_uploader_has_direct_rendering() is available + to help decide between the creation of a GstVaapiVideoBuffer or a regular + GstBuffer on sink pads. + Signed-off-by: Zhao Halley + Signed-off-by: Gwenole Beauchesne + +2012-11-20 14:36:29 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiimage.c: + image: fix GstVaapiImage map and unmap. + Fix gst_vaapi_image_map() to return TRUE and the GstVaapiImageRaw + structure correctly filled in if the image was already mapped. + Likewise, make gst_vaapi_image_unmap() return TRUE if the image + was already unmapped. + +2012-10-30 13:15:45 +0800 Wind Yuan + + * NEWS: + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + videobuffer: fix memory leak for surface and image. + Fix reference leak of surface and image in GstVaapiVideoBuffer wrapper, + thus resulting on actual memory leak of GstVaapiImage when using them + for downloads/uploads from VA surfaces and more specifically surfaces + when the pipeline is shutdown. i.e. vaTerminate() was never called + because the resources were not unreferenced, and thus not deallocated + in the end. + Signed-off-by: Gwenole Beauchesne + +2012-11-19 10:04:52 +0100 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2012-11-16 18:00:10 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: fix picture size in macroblocks. + The picture size signalled by sps->{width,height} is the actual size with + cropping applied, not the original size derived from pic_width_in_mbs_minus1 + and pic_height_in_map_units_minus1. VA driver expects that original size, + uncropped. + There is another issue pending: frame cropping information needs to be + taken care of. + +2012-11-16 16:18:52 +0100 Gwenole Beauchesne + + * gst-libs/gst/codecparsers/Makefile.am: + codecparsers: always build parserutils first. + Fix commit 18245b4 so that to link and build parserutils.[ch] first. + This is needed since that's the common dependency for actual codec + parsers (gstvc1parser.c for instance). + +2012-11-15 17:50:45 +0100 Gwenole Beauchesne + + * gst-libs/gst/codecparsers/Makefile.am: + codecparsers: always build the VC-1 parser library. + ... this is useful to make sure pixel-aspect-ratio and framerate + information are correctly parsed since we have no means to detect + that at configure time. + +2012-11-08 11:40:47 +0200 Sreerenj Balachandran + + * configure.ac: + * gst-libs/gst/codecparsers/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: fix PAR calculation from commit bd11bae. + Invoke gst_mpeg_video_finalise_mpeg2_sequence_header() to get the + correct PAR values. While doing so, require a newer version of the + bitstream parser library. + Note: it may be necessary to also parse the Sequence_Display_Extension() + header. + Signed-off-by: Sreerenj Balachandran + Signed-off-by: Gwenole Beauchesne + +2012-11-15 15:00:43 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + Fix build with the GNU gold linker. + In particular, fix libgstvaapi-glx DSO dependencies to include libgstbase + and libgstvideo libs, e.g. for gst_video_buffer_get_overlay_composition(). + +2012-11-02 18:18:37 +0000 Rob Bradford + + * configure.ac: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + wayland: port to 1.0 version of the protocol. + This patch updates to relect the 1.0 version of the protocol. The main + changes are the switch to wl_registry for global object notifications + and the way that the event queue and file descriptor is processed. + Signed-off-by: Gwenole Beauchesne + +2012-11-14 19:22:13 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: fix incorrect integration of previous commit (4d31e1e). + git am got confused somehow, though the end result doesn't change at + all since we require both SPS and PPS to be parsed prior to decoding + the first slice. + +2012-11-14 18:40:47 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: start decoding slices after first SPS/PPS activation. + Only start decoding slices when at least one SPS and PPS got activated. + This fixes cases when a source represents a substream of another stream + and no SPS and PPS was inserted before the first slice of the generated + substream. + +2012-11-14 14:25:34 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: fix VAPictureParameterBufferH264.ReferenceFrames[] construction. + ... for interlaced streams. The short_ref[] and long_ref[] arrays may + contain up to 32 fields but VA ReferenceFrames[] array expects up to + 16 reference frames, thus including both fields. + +2012-11-14 10:27:12 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: fix interlaced stream decoding with MMCO. + Fix decoding of interlaced streams when adaptive_ref_pic_marking_mode_flag + is equal to 1, i.e. when memory management control operations are used. In + particular, when field_pic_flag is set to 0, the new reference flags shall + be applied to both fields. + +2012-11-13 17:14:39 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: add initial support for interlaced streams. + Decoded frames are only output when they are complete, i.e. when both + fields are decoded. This also means that the "interlaced" caps is not + propagated to vaapipostproc or vaapisink elements. Another limitation + is that interlaced bitstreams with MMCO are unlikely to work. + +2012-11-13 16:35:30 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: split remove_reference_at() into finer units. + Split remove_reference_at() into a function that actually removes the + specified entry from the short-term or long-term reference picture array, + and a function that sets reference flags to the desired value, possibly + zero. The latters marks the picture as "unused for reference". + +2012-10-23 14:04:22 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + decoder: fix gst_vaapi_picture_new_field() object type. + Fix gst_vaapi_picture_new_field() to preserve the original picture type. + e.g. gst_vaapi_picture_new_field() with a GstVaapiPictureH264 argument + shall generate a GstVaapiPictureH264 object. + +2012-11-13 14:04:31 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: add picture structure for reference picture marking process. + Introduce new `structure' field to the H.264 specific picture structure + so that to simplify the reference picture marking process. That local + picture structure is derived from the original picture structure, as + defined by the syntax elements field_pic_flag and bottom_field_flag. + +2012-11-02 15:14:58 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: introduce new frame store structure. + The frame store represents a Decoded Picture Buffer entry, which can + hold up to two fields. So far, the frame store is only used to hold + full frames. + +2012-11-13 10:10:31 +0100 Gwenole Beauchesne + + * ext/codecparsers: + codecparsers: update to gst-vaapi-rebased commit 73d6aab. + 73d6aab h264: fix rbsp_more_data() implementation + 25d04cf h264: fix error code for invalid size parsed in SPS + 84798e5 fix FSF address + +2012-10-31 16:37:14 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: minor clean-ups. + Move DPB flush up if the current picture to decode is an IDR. Besides, + don't bother to check for IDR pictures in dpb_add() function since an + explicit DPB flush was already performed in this case. + +2012-10-31 14:24:09 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: simplify reference picture marking process. + ... to build the short_ref[] and long_ref[] lists from the DPB, instead + of maintaining them separately. This avoids refs/unrefs while making it + possible to generate the list based on the actual picture structure. + This also ensures that the list of generated ReferenceFrames[] actually + matches what reference frames are available in the DPB. i.e. short_ref[] + and long_ref[] entries are implied from the DPB, so there is no risk of + having "dangling" references. + +2012-10-31 11:52:03 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: introduce per-field POC in GstVaapiPictureH264. + Use the POC member available in the GstVaapiPicture base class and + get rid of the dependency on the local VAPictureH264 TopFieldOrderCnt + and BottomFieldOrderCnt. Rather, use a simple field_poc[] array + initialized to INT_MAX, so that to simplify picture POC calculation + for non frame pictures. + +2012-10-31 11:45:14 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: introduce GST_VAAPI_PICTURE_{SHORT,LONG}_TERM_REFERENCE flags. + Further get rid of GstVaapiPictureH264-local VAPictureH264.flags for + reference bits, thus simplifying the reference picture marking process + to only track a single set of reference flags. Also introduce a new + long_term_frame_idx member. + +2012-10-31 11:33:40 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: introduce GST_VAAPI_PICTURE_FLAG_IDR flag. + +2012-10-31 10:56:15 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: fill in GstVaapiPicture structure. + ... and get rid of local VAPictureH264.flags fields in GstVaapiPictureH264. + +2012-10-31 11:07:48 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: add vaapi_fill_picture() helper. + Add vaapi_fill_picture() helper function to convert GstVaapiPictureH264 + to VAPictureH264 structure. This is preparatory work to get rid of the + local VAPictureH264 member in GstVaapiPictureH264. + +2012-10-26 16:12:05 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: fix activation order of picture and sequence parameters. + Delay ensure_context() until we actually need a VA context for allocating + new VA surfaces, and then GstVaapiPictures, but also when a real activation + of a new picture parameter set occurs, thus also implying an activation + of the related sequence parameter set. + The most important thing was to drop the global pps and sps pointers since + they may not have matched the currently activated picture parameter or + sequence parameter sets at the specified decode point. + Anoter positive side-effect is that this cleans up all occurrences of + decode_current_picture() to only keep those useful in decode_picture(), + before a new picture is allocated, or in decode_sequence_end() when + an end-of-stream or end-of-sequence condition occurred. + +2012-10-26 13:17:43 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: fix scaling list generation. + ... aka fix regression from efaab79. In particular, ScalingList8x8[] + array was partially copied to the VAIQMatrixBufferH264. While we are + at it, also improve bounds checking and avoid copying 8x8 scaling + lists if transform_8x8_mode_flag is set to 0. + +2012-10-24 18:23:09 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: fix detection of picture boundaries. + Strictly follow the standard (7.4.1.2.4) to detect the first VCL NAL + unit of a primary coded picture. + +2012-10-23 14:50:14 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: optimize handling of scaling lists. + Don't copy scaling lists twice to an intermediate state. Rather, directly + use the scaling lists from GstH264PPS since they would match those provided + by SPS header, if necessary. i.e. if PPS-specific scaling lists are not + available in the bitstream. + +2012-10-23 10:33:50 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: simplify code when MMCO is 5. + Remove exit_picture() and exit_picture_poc() since PicOrderCnt(CurrPic) + is now updated accordingly to the standard. Besides, MMCO = 5 specific + operations are moved up to exec_ref_pic_marking_adaptive_mmco_5(). + +2012-10-22 11:52:13 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: fix MMCO-based reference picture marking process. + Fix adaptive memory control decoded reference picture marking process + implementation for operations 2 to 6, thus also fixing support for + long-term reference pictures. + +2012-10-22 10:50:29 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: move MMCO handlers out of the loop (cosmetics). + This change only splits each individual MMCO handler into several functions + dedicated for each operation. This is needed to perform further work later + on. + +2012-10-17 15:49:23 +0200 Gwenole Beauchesne + + * Makefile.am: + debian: fix make dist for packaging. + bzip2 tarballs are now used, so update the deb.upstream dependencies + to include dist-bzip2 instead of plain old dist, and use the correct + tar extract options to handle that format. + +2012-10-17 15:42:17 +0200 Gwenole Beauchesne + + * configure.ac: + configure: generate bzip2 tarballs in ustar format by default. + +2012-10-17 15:38:14 +0200 Gwenole Beauchesne + + * configure.ac: + configure: bump glib required version to 2.31.2. + Use new Thread API. In particular, g_mutex_init() and g_cond_init() + rather than g_mutex_new() and g_cond_new() respectively. + +2012-10-04 17:39:53 +0100 Rob Bradford + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + vaapidecode: adopt non-deprecrated glib locking primitive pattern. + The use of heap allocated GMutex/GCond is deprecated. Instead place them + inside the structure they are locking. + These changes switch to use g_mutex_init/g_cond_init rather than the heap + allocation functions. + Because we cannot test for a NULL pointer for the GMutex/GCond we must + initialise inside the GObject _init function and clear inside the _finalize + which is guaranteed to only be called once and after the object is no longer + in use. + +2012-10-17 14:52:35 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: fix compiler warnings. + Don't care of the return value for gst_vaapi_decoder_put_buffer() + during destruction of the element. Don't print out (uninitialised) + error code when allocation of video buffer failed. + +2012-10-16 16:52:04 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: add flag to compile with strict DPB ordering mode. + Allow build with strict DPB ordering mode whereby evicted entries + are replaced by the next entries, in order instead of optimizing + it away with the last entry in the DPB. + This is only useful for debugging purpose, against a reference SW + decoder for example. + +2012-10-16 16:46:17 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: drop extra code covered by built-in codecparsers. + GstH264SliceHdr.n_emulation_prevention_bytes is bound to exist now that + a newer version of codecparsers/ are used if the system provided one is + now recent enough to have those required extensions. + +2012-10-16 16:43:43 +0200 Gwenole Beauchesne + + * gst-libs/gst/codecparsers/Makefile.am: + codecparsers: fix generation of symlinks. + Try to improve dependencies while generating symlinks to externally + maintained copy of codecparsers (derived from upstream git master + tree). + +2012-10-11 15:04:12 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + vc1: use framerate information from bitstream parser. + +2012-09-27 18:05:46 +0100 Simon Farnsworth + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + vc1: use pixel-aspect-ratio from bitstream parser. + Signed-off-by: Simon Farnsworth + Signed-off-by: Gwenole Beauchesne + +2012-09-27 18:05:46 +0100 Simon Farnsworth + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: use pixel-aspec-ratio information from bitstream parser. + Signed-off-by: Simon Farnsworth + Signed-off-by: Gwenole Beauchesne + +2012-10-11 13:49:14 +0200 Gwenole Beauchesne + + * configure.ac: + * gst-libs/gst/codecparsers/Makefile.am: + codecparsers: h264: use submodule sources. + Use newer sources from the codecparsers/ submodule for + - GstH264SliceHdr.n_emulation_prevention_bytes: EPBs; + - GstH264VUIParams.{par_n,par_d}: pixel-aspect-ratio. + +2012-10-11 13:23:02 +0200 Gwenole Beauchesne + + * .gitignore: + * configure.ac: + * gst-libs/gst/codecparsers/Makefile.am: + * gst-libs/gst/codecparsers/gstjpegparser.c: + * gst-libs/gst/codecparsers/gstjpegparser.h: + * gst-libs/gst/vaapi/Makefile.am: + codecparsers: jpeg: use submodule sources. + +2012-10-11 10:03:14 +0200 Gwenole Beauchesne + + * .gitmodules: + * Makefile.am: + * autogen.sh: + * configure.ac: + * ext/Makefile.am: + * ext/codecparsers: + Add codecparsers submodule. + +2012-10-11 14:17:12 +0200 Gwenole Beauchesne + + * .gitignore: + .gitignore: updates. + +2012-10-11 13:40:37 +0200 Gwenole Beauchesne + + * autogen.sh: + autogen: fix check for gtkdocize and autoreconf. + If gtkdocize or autoreconf programs were not found, then the autogen.sh + script would fail to report that correctly because test -z was not passed + any argument (empty string "" in this case). + +2012-09-27 18:05:46 +0100 Simon Farnsworth + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: use pixel-aspect-ratio from SPS header. + Propagate pixel-aspect-ratio determined by the GStreamer codecparser + from the sequence headers. + Signed-off-by: Simon Farnsworth + Signed-off-by: Gwenole Beauchesne + +2012-10-10 10:35:20 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: add decode_nalu() helper function. + Split decode_buffer() into the core infrastructure that determines + the NAL units contained in the adapter and the actual function that + decodes the NAL unit. + +2012-10-10 10:31:39 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: fix end-of-stream conditions (flush). + Decode pending data in the adapter prior to processing the actual + code for end-of-stream. + +2012-10-10 09:45:03 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: add decode_packet() helper function. + Split decode_buffer() into the core infrastructure that determines + the packets contained in the adapter and the actual function that + decodes the packet data. + +2012-10-09 15:34:18 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: fix end-of-stream conditions (flush). + Decode pending data in the adapter prior to processing the actual + code for end-of-stream. Initial code from Feng Yuan. + +2012-10-09 15:40:49 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: fix memory leak of empty packets. + Fix memory leakage of empty packets, i.e. packets that only contain + the start code prefix. In particular, free empty user-data packets. + Besides, the codec parser will already fail gracefully if the packet + to parse does not have the minimum required size. So, we can also + completely drop the block of code that used to handle packets of size 4 + (including the start code). + +2012-10-09 15:01:38 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: fix return value for "no-data" conditions. + Fix return value when the second scan for start code fails. This means + there is not enough data to determine the full extents of the current + packet and the function shall return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA + in this case, instead of GST_VAAPI_DECODER_STATUS_SUCCESS. + +2012-10-09 14:48:00 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + decoder: refine semantics of gst_vaapi_decoder_put_buffer(). + Improve the semantics for gst_vaapi_decoder_put_buffer() when an empty + buffer is passed on. An empty buffer is a buffer with a NULL data pointer + or with a size equals to zero. In this case, that buffer is simply + skipped and the function returns TRUE. A NULL buffer argument still + marks the end-of-stream. + +2012-10-09 14:40:00 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + decoder: drop unused functions. + +2012-08-26 22:29:04 -0400 Wind Yuan + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: flush buffers when receiving EOS. + Signed-off-by: Gwenole Beauchesne + +2012-10-05 13:36:27 +0200 Gwenole Beauchesne + + * debian.upstream/Makefile.am: + debian: fix make dist for packaging. + +2012-10-05 12:06:27 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay_wayland_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + wayland: cosmetics (remove tabs). + +2012-10-04 17:39:52 +0100 Rob Bradford + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + wayland: add support for windowed mode. + Rather than always making the surface fullscreen instead implement the + set_fullscreen vfunc on GstVaapiWindow and then set the shell surface + fullscreen on not depending on that. + Reviewed-by: Joe Konno + Signed-off-by: Gwenole Beauchesne + +2012-10-01 09:21:03 +0200 Gwenole Beauchesne + + * configure.ac: + Bump version for development. + +2012-09-28 17:54:03 +0200 Gwenole Beauchesne + + * README: + * configure.ac: + Fix and document build dependencies better. + +2012-09-28 17:41:42 +0200 Gwenole Beauchesne + + * debian.upstream/control.in: + debian: fix GStreamer build dependencies. + +2012-09-28 17:39:43 +0200 Gwenole Beauchesne + + * configure.ac: + * debian.upstream/control.in: + debian: fix Wayland build dependencies. + +2012-09-28 17:38:17 +0200 Gwenole Beauchesne + + * debian.upstream/control.in: + debian: fix conditional build of packages. + Make it still possible to build package even if one of the build dependencies + for a specific video backend is not available. + +2012-09-27 11:08:58 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + * gst-libs/gst/vaapi/gstvaapiutils_glx.h: + utils: drop unused GLX helpers. + Remove helpers for GL_ARB_fragment_program and GL_ARB_multitexture + extensions since they are not used throughout gstreamer-vaapi. + +2012-09-27 11:04:24 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiutils_glx.h: + utils: fix build with version >= 85. + Mesa recently updated the header version to Khronos version 85. + This caused the PFNGLMULTITEXCOORD2FPROC definition to be moved out of the + GL_VERSION_1_3_DEPRECATED block. However, since also defines + GL_VERSION_1_3 to 1, the definitions in are then not enabled, + thus leaving PFNGLMULTITEXCOORD2FPROC undefined as well. + Provide a PFNGLMULTITEXCOORD2FPROC replacement as an interim solution for + newer versions of the header. + +2012-09-26 16:33:16 +0200 Gwenole Beauchesne + + * configure.ac: + configure: update VA-API version requirements. + VA/DRM and VA/Wayland API are now promoted to VA-API 0.33.0 (libva 1.1.0). + +2012-09-21 16:43:38 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: review and report errors accordingly. + Use GST_ERROR() to report real errors instead of hiding them into + GST_DEBUG(). + +2012-09-20 17:58:21 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: exclusively use GstAdapter, drop sub-buffer hack. + Maintaining the sub-buffer is rather suboptimal especially since we + were also maintaining a GstAdapter. Now, we only use the GstAdapter + thus requiring minor extra parsing when receiving avcC buffers. + +2012-09-20 16:18:27 +0200 Gwenole Beauchesne + + * README: + README: updates. + +2012-09-20 16:02:39 +0200 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2012-09-20 14:38:15 +0200 Gwenole Beauchesne + + * debian.upstream/gstreamer-vaapi.install.in: + debian: fix packaging on recent Ubuntu platforms. + Use explicit GStreamer plugins path. + +2012-09-17 17:55:43 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-docs.xml.in: + * docs/reference/libs/libs.core.types: + docs: fix build for make dist. + +2012-09-14 10:30:35 -0400 Kristian Høgsberg + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + wayland: set opaque region for YUV surface. + This allows the compositor to optimize redraws and cull away changes + obscured by the video surface. + Signed-off-by: Gwenole Beauchesne + +2012-09-14 17:30:19 +0200 Gwenole Beauchesne + + * configure.ac: + configure: fix check for libva-glx and libva-drm. + +2012-09-12 13:42:49 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/glibcompat.h: + glibcompat: add replacement for g_cond_wait_until(). + +2012-09-12 13:41:47 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiupload.c: + plugins: include "sysdeps.h" instead of "config.h". + +2012-09-12 10:40:06 +0200 Gwenole Beauchesne + + * gst-libs/gst/codecparsers/gstjpegparser.c: + codecparsers: jpeg: add missing includes. + +2012-09-11 17:03:33 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst/vaapi/gstvaapidecode.c: + vaapidecode: don't reset decoder if codec type is the same. + Reset, i.e. destroy then create, the decoder in _setcaps() handler only + if the underlying codec type actually changed. This makes it possible + to be more tolerant with certain MPEG-2 streams that get parsed to + form caps that are compatible with the previous state but minor changes + to "codec-data". + +2012-09-11 16:41:32 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: simplify codec lookup from caps. + Add new gst_vaapi_codec_from_caps() helper to determine codec type from + the specified caps. Don't globally expose this function since this is + really trivial and only used in the vaapidecode element. + +2012-09-11 15:54:20 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + vaapidecode: improve "no free surface" conditions. + Previously, vaapidecode would wait up to one second until a free surface + is available, or it aborts decoding. Now, vaapidecode waits until the + last decoded surface was to be presented, plus one second. Besides, end + times are now expressed relative to the monotonic clock. + +2012-09-11 10:59:33 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst/vaapi/gstvaapidecode.c: + decoder: propagate buffer duration downstream. + +2012-09-11 10:59:10 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + surfaceproxy: add "duration" property. + +2012-09-10 18:26:51 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + decoder: cope with new GstVaapiContextInfo based API. + Update decoders to report the maximum number of reference frames to use. + +2012-09-10 18:17:10 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicontext.c: + context: JPEG codec does not need any reference frame. + +2012-09-10 18:15:02 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + context: allow number of reference frames to be set. + Make it possible to specify the maximum number of references to use within + a single VA context. This helps reducing GPU memory allocations to the useful + number of references to be used. + +2012-09-07 16:41:16 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: fix deinterlace-{mode,method} types definition. + +2012-09-07 16:15:40 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + mpeg4: fix debug info for unsupported profile. + +2012-09-07 16:14:11 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.c: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimagepool.c: + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + * gst-libs/gst/vaapi/gstvaapivalue.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer_glx.c: + * gst-libs/gst/vaapi/gstvaapivideoconverter_glx.c: + * gst-libs/gst/vaapi/gstvaapivideopool.c: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow_drm.c: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + libs: fix build in strict ISO C mode. + +2012-09-07 16:11:12 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiupload.c: + plugins: fix build in strict ISO C mode. + +2012-09-07 15:31:09 +0200 Gwenole Beauchesne + + * pkgconfig/gstreamer-vaapi-glx.pc.in: + * pkgconfig/gstreamer-vaapi-x11.pc.in: + * pkgconfig/gstreamer-vaapi.pc.in: + pkgconfig: fix dependencies and slightly improve description. + Drop @LIBVA_EXTRA_{CFLAGS,LIBS}@ substitutions and slightly improve + descriptions with clearer renderer names. + +2012-09-04 13:54:19 +0200 Philip Lorenz + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: acquire lock only if the mutex exists. + When playback stops the GstVaapiDecode object is reset into a clean + state. However, surfaces may still be referenced by library users and + unreferencing them after the reset triggers an access to an unset mutex. + Signed-off-by: Gwenole Beauchesne + +2012-09-07 11:58:53 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + decoder: drop extraneous return for void function. + +2012-09-07 11:57:59 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiimage.c: + image: don't use (void *) pointer arithmetic. + +2012-09-04 13:40:04 +0200 Philip Lorenz + + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapiimageformat.c: + * gst-libs/gst/vaapi/gstvaapiimageformat.h: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapitypes.h: + * gst/vaapi/gstvaapipostproc.h: + Do not forward declare enums. + Forward declaring enums is not allowed by the C standard and aborts + compilation if the header file is included in a C++ project. + Signed-off-by: Gwenole Beauchesne + +2012-09-07 11:44:44 +0200 Gwenole Beauchesne + + * configure.ac: + configure: fix check for VA/DRM API. + +2012-09-04 11:53:18 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + vaapisink: fix calculation of window size. + If either dimension is out-of-bounds, then scale window to fit the + display size, even if the output is to be rotated. Use the standard + gst_video_sink_center_rect() function to center and scale the window + wrt. the outer (display) bounds. + +2012-08-28 02:45:22 -0400 Wind Yuan + + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + vaapisink: add video rotation support. + Signed-off-by: Gwenole Beauchesne + +2012-09-06 11:47:40 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginutil.h: + pluginutils: add G_PRIMITIVE_SWAP() helper macro. + This macro helps swapping variables while maintaining the correct underlying + and primitive type. + +2012-09-06 11:51:41 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + display: fix display aspect ratio when display is rotated. + +2012-09-06 11:50:21 +0200 Gwenole Beauchesne + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h: + display: fix physical display size when display is rotated. + +2012-08-30 16:27:56 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapivalue.c: + display: fix GstVaapiRotation enumeration of values. + +2012-08-29 13:18:05 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-docs.xml.in: + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapivideosink.c: + * gst-libs/gst/vaapi/gstvaapivideosink.h: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiupload.c: + vaapisink: drop obsolete GstVaapiVideoSink interface. + This interface was deprecated since 0.3.x series when the GstVideoContext + interface was added to the main GStreamer APIs. + +2012-08-27 18:34:27 +0300 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + vaapisink: automatically detect overlay rendering mode. + Retain the VA surface until another surface is to be displayed only + if VA display rendering mode is determined to be "overlay" mode. + +2012-08-24 16:30:33 +0300 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + vaapisink: retain VA surface until another one is displayed. + Keep VA surface proxy associated with the surface that is currently + being displayed. This makes sure that surface is not released back + to the pool of surfaces free to use for decoding. This is necessary + with VA driver implementations that support rendering to an overlay + pipe. Otherwise, there could be cases where we are decoding into a + surface that is being displayed, hence some flickering. + +2012-08-24 14:54:16 +0300 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.h: + vaapisink: fix build with older toolchains. + Don't re-declare GstVaapiTexture if USE_GLX mode is set. + +2012-08-29 10:13:58 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + display: partially revert 8ebe4d6. + Don't try to fix up the initial values, this could make things worse. + Simply assume the driver does not support the capability in this case. + +2012-08-28 16:08:34 +0200 Gwenole Beauchesne + + * tests/test-display.c: + tests: dump VA display properties. + +2012-08-28 18:11:32 +0300 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + display: fix validation process of properties during discovery. + Some VA drivers (e.g. EMGD) can have completely random values for initial + display attributes. So, try to improve the discovery process to check the + initial display attribute values actually fall within valid bounds. If not, + try to reset those to some sensible values like the default value reported + through vaQueryDisplayAttributes(). + +2012-08-28 13:59:50 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + display: add color balance properties. + Add support for hue, saturation, brightness and contrast attributes. + +2012-08-28 14:05:16 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + display: initialize default attribute values. + Ensure the display attribute is actually supported by trying to retrieve + its current value during GstVaapiDisplay creation. + +2012-08-28 11:09:56 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + display: raise "notify" for property changes. + +2012-08-28 10:55:59 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + display: expose display attributes as GObject properties. + Expose VA display "render-mode" and "rotation" attributes as standard + GObject properties. + +2012-08-28 16:24:15 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + display: install properties in batch. + Use g_object_class_install_properties() to install GstVaapiDisplay properties. + It is useful to maintain properties as GParamSpec so that to be able to raise + "notify" signals by id instead of by name in the future. + +2012-08-27 19:00:37 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + display: fix gst_vaapi_display_has_property(). + Append the "render-mode" and "rotation" properties, should they be supported + by the underlying VA driver. + +2012-08-22 02:18:11 -0400 Wind Yuan + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapitypes.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + * gst-libs/gst/vaapi/gstvaapivalue.c: + * gst-libs/gst/vaapi/gstvaapivalue.h: + display: add support for rotation modes. + Signed-off-by: Gwenole Beauchesne + +2012-08-27 18:11:37 +0300 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapitypes.h: + * gst-libs/gst/vaapi/gstvaapivalue.c: + * gst-libs/gst/vaapi/gstvaapivalue.h: + display: add support for rendering modes. + A rendering mode can be "overlay" or "texture"'ed blit. + The former mode implies that a VA surface used for rendering can't be + re-used right away for decoding, so the sink shall make provisions to + retain the associated surface proxy until the next surface is to be + displayed. + The latter mode implies that the VA surface is implicitly copied to an + intermediate backing store, or back buffer of a frame buffer, so the + associated surface proxy can be disposed right away. + +2012-08-27 17:02:49 +0300 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + display: add initial support for display attributes. + The VA display attributes are mapped to properties so that to maintain the + GStreamer terminology. Properties are to be identified by name, but internal + functions are available to lookup the property by the actual VA display + attribute type. + +2012-08-24 11:36:16 +0300 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + jpeg: fix end-of-image (EOI) handler. + decode_current_picture() was converted to return a gboolean instead + of a GstVaapiDecoderStatus, so we were not getting out of the decode + loop as expected, or could cause an error instead. + Signed-off-by: Gwenole Beauchesne + +2012-08-24 18:41:47 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: include start code into VA slice data buffer. + Integrate the start code prefix in the slice data buffer that is submitted + to the hardware. VA-API specifies that slice_data_offset is the offset to + the first byte of slice data. And, for MPEG-2, slice() data begins with + the slice_start_code. Some VA driver implementations (EMGD) expect this. + +2012-06-28 01:08:03 +0900 Javier Jardón + + * autogen.sh: + autogen: fix configure script generation when srcdir != builddir. + This patch allows for regenerating the configure script from a build + directory that is not the actual source directory. + Signed-off-by: Gwenole Beauchesne + +2012-06-28 00:22:03 +0900 Javier Jardón + + * configure.ac: + configure: use new libtool syntax. + This now requires libtool >= 2.2 to regenerate the configure script. + Signed-off-by: Gwenole Beauchesne + +2012-08-08 12:50:41 +0900 Javier Jardón + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + decoder: use g_object_notify_by_pspec(). + Use g_object_notify_by_pspec() instead of g_object_notify() so that to + avoid a property name lookup. i.e. this makes notifications faster to + the `vaapidecode' element. + Signed-off-by: Gwenole Beauchesne + +2012-08-06 19:21:03 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + wayland: handle de-interlacing flags. + VA/Wayland API was updated to allow flags for bob deinterlacing. + More elaborated filters will require a complete VA/VPP pipeline. + +2012-08-02 18:27:48 +0200 Gwenole Beauchesne + + * gst-libs/gst/codecparsers/gstjpegparser.c: + jpeg: fix default quantization tables. + Two elements in the luminance quantization table were wrong. So, + gst_jpeg_get_default_quantization_tables() now reconstructs tables + in zig-zag order from the standard ones (Tables K.1 and K.2). + +2012-08-02 15:17:57 +0200 Gwenole Beauchesne + + * gst-libs/gst/codecparsers/gstjpegparser.c: + jpeg: compute default Huffman tables. + ... instead of having them pre-calculated. This saves around 1.5 KB + of data in the DSO but requires gst_jpeg_get_default_huffman_tables() + to do more work. Though, the client application may have to call that + function at most once, only. + +2012-08-01 18:30:27 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + display: drop VAProfileNone entries from debug messages. + +2012-07-31 18:24:14 +0800 Yan Yin + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + display: query for supported display attributes. + Signed-off-by: Gwenole Beauchesne + +2012-07-31 18:22:48 +0800 Yan Yin + + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + utils: add string_of_VADisplayAttributeType() helper. + Signed-off-by: Gwenole Beauchesne + +2012-08-01 15:46:35 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + vaapisink: handle VA/DRM API. + This is not useful in practice but for raw performance evaluation when + the sink is invoked with display=drm sync=false. fakesink could also be + used though. + +2012-08-01 15:46:19 +0200 Gwenole Beauchesne + + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapipluginutil.c: + plugins: add support for headless pipelines. + +2012-08-01 15:44:49 +0200 Gwenole Beauchesne + + * tests/Makefile.am: + * tests/output.c: + * tests/test-display.c: + * tests/test-windows.c: + tests: add support for headless decoding. + +2012-08-01 15:44:02 +0200 Gwenole Beauchesne + + * NEWS: + * configure.ac: + * debian.upstream/Makefile.am: + * debian.upstream/control.in: + * debian.upstream/libgstvaapi-drm.install.in: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.c: + * gst-libs/gst/vaapi/gstvaapidisplay_drm.h: + * gst-libs/gst/vaapi/gstvaapidisplay_drm_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow_drm.c: + * gst-libs/gst/vaapi/gstvaapiwindow_drm.h: + * pkgconfig/Makefile.am: + * pkgconfig/gstreamer-vaapi-drm.pc.in: + Add initial support for VA/DRM. + +2012-07-31 17:58:43 +0200 Gwenole Beauchesne + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + Fix build without X11 (again). + Don't try to build libgstvaapi-x11.so.* if X11 was disabled. Also shuffle + files list wrt. x11, glx and wayland backends. + +2012-07-31 11:51:57 +0200 Gwenole Beauchesne + + * configure.ac: + * gst-libs/gst/vaapi/gstvaapicodec_objects.h: + * gst-libs/gst/vaapi/gstvaapicompat.h: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + jpeg: update to the latest VA-API changes (0.32.1+). + +2012-07-27 14:27:05 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland_priv.h: + * gst/vaapi/gstvaapisink.c: + wayland: implement display ::get_size*() hooks. + +2012-07-27 10:45:41 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginutil.c: + plugins: prefer X11 rendering over GLX. + Prefer X11 display over GLX so that "vaapisink" uses X11, i.e. vaPutSurface(), + for rendering instead of texturing. + +2012-07-26 09:28:51 -0400 Kristian Høgsberg + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + wayland: use scale fullscreen method. + This makes the compositor scale the surface to fit and preserves aspect + ratio. + Signed-off-by: Gwenole Beauchesne + +2012-07-26 09:27:47 -0400 Kristian Høgsberg + + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + wayland: respond to ping/pong protocol so we're not deemed unresponsive. + Signed-off-by: Gwenole Beauchesne + +2012-07-25 10:39:04 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + wayland: fix double disconnect of display. + +2012-07-24 19:58:55 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + wayland: mangle display name for cache lookups. + +2012-07-24 15:43:44 +0200 Gwenole Beauchesne + + * configure.ac: + * debian.upstream/Makefile.am: + * debian.upstream/control.in: + * debian.upstream/libgstvaapi-wayland.install.in: + * pkgconfig/Makefile.am: + * pkgconfig/gstreamer-vaapi-wayland.pc.in: + wayland: add packaging files. + +2012-07-24 15:07:48 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapisink.c: + * pkgconfig/Makefile.am: + Fix build without X11. + +2012-07-24 09:45:25 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapisink.c: + plugins: add support for Wayland. + +2012-07-23 12:56:33 +0200 Gwenole Beauchesne + + * tests/Makefile.am: + * tests/output.c: + * tests/test-display.c: + * tests/test-windows.c: + tests: add support for Wayland. + +2012-07-19 10:27:23 +0200 Sreerenj Balachandran + + * NEWS: + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.c: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland.h: + * gst-libs/gst/vaapi/gstvaapidisplay_wayland_priv.h: + * gst-libs/gst/vaapi/gstvaapiobject_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.c: + * gst-libs/gst/vaapi/gstvaapiwindow_wayland.h: + Add initial support for VA/Wayland. + Signed-off-by: Gwenole Beauchesne + +2012-07-25 15:11:51 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginbuffer.c: + plugins: fix creation of video buffer from surface proxy. + Fix a regression introduced with commit 8ef490a. + +2012-07-25 14:51:28 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginbuffer.c: + * gst/vaapi/gstvaapipluginutil.c: + plugins: use new display types more. + In particular, simplify gst_vaapi_reply_to_query() with display types. + Likewise for creating new video buffers. + +2012-07-25 10:02:29 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiupload.c: + plugins: fix display type selection and propagation. + If vaapisink is in the GStreamer pipeline, then we shall allocate a + unique GstVaapiDisplay and propagate it upstream. i.e. subsequent + queries from vaapidecode shall get a valid answer from vaapisink. + +2012-07-25 11:37:26 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + display: fix destruction of mutex. + +2012-07-25 09:16:02 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.c: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplaycache.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapisink.c: + display: add display types. + Move display types from gstvaapipluginutil.* to gstvaapidisplay.* so that + we could simplify characterization of a GstVaapiDisplay. Also rename "auto" + type to "any", and add a "display-type" attribute. + +2012-07-24 19:43:40 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + display: use prefixed display names for cache lookups. + This improves display name comparisons by always allocating a valid display + name. This also helps to disambiguate lookups by name in the global display + cache, should a new backend be implemented. + +2012-07-24 16:14:51 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginutil.h: + plugins: declare helper functions as internal. + +2012-07-24 14:31:25 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer.h: + * gst-libs/gst/vaapi/gstvaapivideobuffer_glx.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer_glx.h: + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapipluginbuffer.c: + * gst/vaapi/gstvaapipluginbuffer.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapiupload.c: + videobuffer: drop deprecated functions. + Move video buffer creation routines to plugin elements. That exclusively + uses *_typed_new*() variants. + +2012-07-24 14:09:09 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapivideobuffer.h: + * gst-libs/gst/vaapi/gstvaapivideobuffer_glx.h: + videobuffer: mark video buffer creation routines as deprecated. + The vdeo buffer creation routines shall actually be internal to gstreamer-vaapi + plugin elements. So deprecate any explicit creation routines that are not the + new *_typed_new*() variants. + +2012-07-24 13:52:06 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer_glx.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer_priv.h: + videobuffer: factor out base and GLX implementations. + Introduce new typed constructors internal to gstreamer-vaapi plugin elements. + This avoids duplication of code, and makes it possible to further implement + generic video buffer creation routines that automatically map to base or GLX + variants. + +2012-07-24 10:58:32 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + utils: fix gl_create_context() with parent context set. + If GLX window was created from a foreign Display, then that same Display shall + be used for subsequent glXMakeCurrent(). This means that gl_create_context() + will now use the same Display that the parent, if available. + This fixes cluttersink with the Intel GenX VA driver. + +2012-07-23 18:37:38 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiupload.c: + pluginutils: improve automatic display type selection. + +2012-07-23 18:01:26 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + pluginutils: cosmetics (indentation fixes). + +2012-07-23 17:54:58 +0200 Gwenole Beauchesne + + * configure.ac: + configure: simplify video outputs summary. + +2012-07-23 17:49:08 +0200 Gwenole Beauchesne + + * configure.ac: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + configure: drop check for --enable-vaapisink-glx. + vaapisink is now built with support for multiple display types, whenever + they are enabled. The new "display" attribute is used to select a particular + renderer. + +2012-07-23 16:15:38 +0200 Gwenole Beauchesne + + * configure.ac: + * gst-libs/gst/vaapi/gstvaapicompat.h: + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapiupload.c: + * tests/test-display.c: + configure: drop check for --enable-vaapi-glx. + This flag is obsolete. It was meant to explicitly enable/disable VA/GLX API + support, or fallback to TFP+FBO if this API is not found. Now, we check for + the VA/GLX API by default if --enable-glx is set. If this API is not found, + we now default to use TFP+FBO. + Note: TFP+FBO, i.e. using vaPutSurface() is now also a deprecated usage and + will be removed in the future. If GLX rendering is requested, then the VA/GLX + API shall be used as it covers most usages. e.g. AMD driver can't render to + an X pixmap yet. + +2012-07-23 15:20:23 +0200 Gwenole Beauchesne + + * tests/output.c: + tests: allow GLX output, if available and selected. + +2012-07-23 15:17:03 +0200 Gwenole Beauchesne + + * tests/Makefile.am: + * tests/output.c: + * tests/output.h: + * tests/test-decode.c: + * tests/test-subpicture.c: + * tests/test-surfaces.c: + tests: use common display and window creation routines. + Add new --output option to select the renderer. Use --list-outputs to + print a list of supported renderers. + +2012-07-23 14:15:42 +0200 Gwenole Beauchesne + + * tests/Makefile.am: + tests: move encoded bitstreams to libutils.la. + +2012-07-23 14:11:16 +0200 Gwenole Beauchesne + + * tests/Makefile.am: + tests: build convenience library for common utilities. + +2012-07-20 16:37:01 +0200 Gwenole Beauchesne + + * tests/Makefile.am: + * tests/test-display.c: + tests: simplify build with various display options. + +2012-07-23 13:28:42 +0200 Gwenole Beauchesne + + * configure.ac: + configure: improve checks for X11. + +2012-07-20 15:57:26 +0200 Gwenole Beauchesne + + * tests/Makefile.am: + configure: fix previous commit for GLX deps. + +2012-07-20 14:44:27 +0200 Gwenole Beauchesne + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + configure: improve checks for GLX. + +2012-07-20 11:45:15 +0200 Gwenole Beauchesne + + * configure.ac: + * gst-libs/gst/vaapi/gstvaapicompat.h: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.h: + * gst-libs/gst/vaapi/gstvaapiutils.h: + Drop support for obsolete VA-API versions < 0.30.4. + +2012-07-20 11:16:27 +0200 Gwenole Beauchesne + + * configure.ac: + * gst-libs/gst/Makefile.am: + * gst-libs/gst/gstutils_version.h.in: + * gst/vaapi/gstvaapisink.c: + vaapisink: drop checks for new APIs used by default. + GStreamer -base plugins >= 0.10.31 are now required, so the checks for + new APIs like GstXOverlay::set_window_handle() and ::set_render_rectangle() + are no longer necessary. + +2012-07-20 14:05:23 +0200 Gwenole Beauchesne + + * configure.ac: + configure: cosmetics and some minor changes. + - Better grouping of feature checks + - Sort list of config files to generate + +2012-07-19 17:55:00 +0200 Gwenole Beauchesne + + * configure.ac: + * gst-libs/gst/vaapi/gstvaapicodec_objects.h: + * gst-libs/gst/vaapi/gstvaapidecoder_dpb.h: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * gst-libs/gst/vaapi/gstvaapisurface_priv.h: + * gst-libs/gst/vaapi/gstvaapiutils.h: + * gst-libs/gst/vaapi/gstvaapiutils_glx.h: + * gst-libs/gst/vaapi/gstvaapiutils_x11.h: + Use standard G_GNUC_INTERNAL keyword instead of attribute_hidden. + +2012-07-19 17:41:25 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiutils_tsb.c: + * gst-libs/gst/vaapi/gstvaapiutils_tsb.h: + Drop obsolete GstVaapiTSB. + It has been replaced with a GstAdapter and gst_adapter_prev_pts(). + +2012-07-19 17:27:06 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + docs: add missing entries for the JPEG decoder. + +2012-07-19 17:16:28 +0200 Gwenole Beauchesne + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapidecode.c: + * tests/test-decode.c: + * tests/test-subpicture.c: + Drop all references to USE_CODEC_PARSERS. + +2012-07-19 17:00:36 +0200 Gwenole Beauchesne + + * NEWS: + * configure.ac: + * docs/reference/libs/libs-sections.txt: + * docs/reference/libs/libs.core.types: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.h: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + * tests/test-decode.c: + * tests/test-subpicture.c: + Drop FFmpeg-based decoders. + GStreamer codecparsers-based decoders are the only supported decoders now. + Though, FFmpeg decoders are still available in gstreamer-vaapi 0.3.x series. + +2012-07-01 05:55:05 +0900 Javier Jardón + + * configure.ac: + * debian.upstream/control.in: + configure: bump glib required version to 2.28. + Signed-off-by: Gwenole Beauchesne + +2012-06-29 08:45:47 +0900 Javier Jardón + + * gst/vaapi/gstvaapidecode.h: + * gst/vaapi/gstvaapidownload.h: + * gst/vaapi/gstvaapipostproc.h: + * gst/vaapi/gstvaapisink.h: + * gst/vaapi/gstvaapiupload.h: + plugins: declare _get_type() functions as const. + Declaring a function as const enables better optimization of calls to + the function. + Signed-off-by: Gwenole Beauchesne + +2012-07-01 05:50:17 +0900 Javier Jardón + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiupload.c: + plugins: use g_clear_object() wherever applicable. + Signed-off-by: Gwenole Beauchesne + +2012-06-29 15:19:51 +0900 Javier Jardón + + * gst-libs/gst/vaapi/gstvaapicodec_objects.h: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_dpb.h: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.h: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.h: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.h: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.h: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.h: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.h: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.h: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst-libs/gst/vaapi/gstvaapiimagepool.h: + * gst-libs/gst/vaapi/gstvaapiobject.h: + * gst-libs/gst/vaapi/gstvaapiparamspecs.h: + * gst-libs/gst/vaapi/gstvaapisubpicture.h: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapisurfacepool.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + * gst-libs/gst/vaapi/gstvaapitexture.h: + * gst-libs/gst/vaapi/gstvaapivalue.h: + * gst-libs/gst/vaapi/gstvaapivideobuffer.h: + * gst-libs/gst/vaapi/gstvaapivideobuffer_glx.h: + * gst-libs/gst/vaapi/gstvaapivideoconverter_glx.h: + * gst-libs/gst/vaapi/gstvaapivideopool.h: + * gst-libs/gst/vaapi/gstvaapivideosink.h: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.h: + libs: declare _get_type() functions as const. + Declaring a function as const enables better optimization of calls + to the function. + Signed-off-by: Gwenole Beauchesne + +2012-07-01 05:34:15 +0900 Javier Jardón + + * gst-libs/gst/vaapi/glibcompat.h: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + * gst-libs/gst/vaapi/gstvaapivideoconverter_glx.c: + * gst-libs/gst/vaapi/gstvaapivideopool.c: + libs: use g_clear_object() wherever applicable. + This is a preferred thread-safe version. Also add an inline version of + g_clear_object() if compiling with glib < 2.28. + Signed-off-by: Gwenole Beauchesne + +2012-07-01 06:02:22 +0900 Javier Jardón + + * .gitignore: + * configure.ac: + * docs/reference/libs/Makefile.am: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapimarshal.list: + * gst-libs/gst/vaapi/gstvaapiobject.c: + libs: use generic g_cclosure_marshal_VOID__VOID(). + Signed-off-by: Gwenole Beauchesne + +2012-07-19 14:29:33 +0200 Gwenole Beauchesne + + * configure.ac: + * gst-libs/gst/vaapi/glibcompat.h: + glibcompat: drop explicit check for g_list_free_full(). + +2012-07-19 13:58:31 +0200 Gwenole Beauchesne + + * configure.ac: + Bump version for development. + +2012-07-19 13:57:05 +0200 Gwenole Beauchesne + + * gst-libs/gst/codecparsers/Makefile.am: + jpeg: fix make dist. + +2012-06-28 00:39:10 +0900 Javier Jardón + + * autogen.sh: + * configure.ac: + * docs/Makefile.am: + configure: fix build without gtk-doc support. + Also do not generate tamplate files as all the documentation is inline. + Drop un-needed code in autogen.sh as well. + Signed-off-by: Gwenole Beauchesne + +2012-06-28 00:27:31 +0900 Javier Jardón + + * Makefile.am: + * autogen.sh: + * configure.ac: + configure: put m4 macros and autogenerated files into m4/ directory. + Signed-off-by: Gwenole Beauchesne + +2012-06-28 00:20:12 +0900 Javier Jardón + + * configure.ac: + configure: drop deprecated autoconf macros. + Bump autoconf required version to 2.58, needed for AS_HELP_STRING macro. + Signed-off-by: Gwenole Beauchesne + +2012-06-28 00:04:19 +0900 Javier Jardón + + * configure.ac: + configure: don't use AC_SUBST for some variables. + PKG_CHECK_MODULES already does this for us. + Signed-off-by: Gwenole Beauchesne + +2012-07-19 11:43:03 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapiupload.c: + plugins: add support for GstImplementsInterface. + +2012-07-01 02:58:36 +0900 Javier Jardón + + * configure.ac: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiupload.c: + plugins: use G_DEFINE_TYPE_* instead of deprecated GST_BOILERPLATE_*. + Signed-off-by: Gwenole Beauchesne + +2012-07-01 03:57:13 +0900 Javier Jardón + + * configure.ac: + * gst/vaapi/gstvaapisink.c: + plugins: do not use deprecated GStreamer -base symbols. + Bump GStreamer plugins -base required version to 0.10.31, needed for + gst_x_overlay_got_window_handle(). + Signed-off-by: Gwenole Beauchesne + +2012-07-01 03:57:13 +0900 Javier Jardón + + * configure.ac: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiupload.c: + plugins: do not use deprecated core GStreamer symbols. + Bump GStreamer required version to 0.10.14, needed for + gst_element_class_set_details_simple(). + Signed-off-by: Gwenole Beauchesne + +2012-07-19 10:54:33 +0200 Gwenole Beauchesne + + * tests/test-decode.c: + tests: fix build without JPEG decoder support. + +2012-07-17 13:44:45 +0200 Gwenole Beauchesne + + * tests/Makefile.am: + * tests/test-decode.c: + * tests/test-jpeg.c: + * tests/test-jpeg.h: + tests: add test for JPEG decoding. + +2012-07-17 13:43:32 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + jpeg: update to match latest parser API. + +2012-07-16 17:35:19 +0200 Gwenole Beauchesne + + * gst-libs/gst/codecparsers/gstjpegparser.c: + * gst-libs/gst/codecparsers/gstjpegparser.h: + codecparsers: jpeg: tweak parser API. + ... to allow for more consistent parsing API among various codec parsers. + In particular, drop use of GList. + +2012-07-16 16:24:04 +0200 Gwenole Beauchesne + + * configure.ac: + jpeg: fix configure check for VA/JPEG decoding API. + +2012-06-26 15:18:53 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + jpeg: fix build with VA-API < 0.32.0. + +2012-06-26 15:04:58 +0200 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2012-06-26 15:02:44 +0200 Gwenole Beauchesne + + * configure.ac: + Bump version for development. + +2012-06-26 14:46:40 +0200 Gwenole Beauchesne + + * NEWS: + * configure.ac: + 0.3.7. + +2012-06-26 13:34:39 +0200 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2012-06-25 16:07:55 +0800 Yan Yin + + * gst/vaapi/gstvaapipluginutil.c: + vaapiplugin: fix build when compiling without GLX. + Signed-off-by: Gwenole Beauchesne + +2012-06-26 11:03:25 +0200 Gwenole Beauchesne + + * configure.ac: + configure: disable FFmpeg-based decoders. + FFmpeg decoders are still available through the --enable-ffmpeg option + but are no longer maintained. + +2012-06-25 17:25:44 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + Fix build with recent GStreamer stack. + +2012-06-25 17:10:49 +0200 Gwenole Beauchesne + + * configure.ac: + * gst-libs/gst/vaapi/gstvaapicompat.h: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + jpeg: update to current VA/JPEG decoding API. + +2012-06-21 16:06:47 +0200 Gwenole Beauchesne + + * gst-libs/gst/codecparsers/gstjpegparser.c: + * gst-libs/gst/codecparsers/gstjpegparser.h: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + codecparsers: jpeg: track valid quantization and Huffman tables. + Add valid flag to GstJpegQuantTable and GstJpegHuffmanTable so that + to determine whether a table actually changed since the last user + synchronization point. That way, this makes it possible for some + hardware accelerated decoding solution to upload only those tables + that changed. + +2012-06-05 10:10:22 +0800 Wind Yuan + + * gst-libs/gst/codecparsers/gstjpegparser.c: + codecparsers: jpeg: use U_READ_UINT*() wherever possible. + Use GstByteReader *_unchecked() variants as much as possible. + Signed-off-by: Gwenole Beauchesne + +2012-06-04 16:20:13 +0800 Wind Yuan + + * gst-libs/gst/codecparsers/gstjpegparser.c: + * gst-libs/gst/codecparsers/gstjpegparser.h: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + jpeg: add new GstJpegHuffmanTables structure. + Add new GstJpegHuffmanTables helper structure to hold all possible + AC/DC Huffman tables available to all components. + Signed-off-by: Gwenole Beauchesne + +2012-06-04 15:52:19 +0800 Wind Yuan + + * gst-libs/gst/codecparsers/gstjpegparser.c: + * gst-libs/gst/codecparsers/gstjpegparser.h: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + jpeg: make gst_jpeg_parse() support multiple scans. + gst_jpeg_parse() now gathers all scans available in the supplied + buffer. A scan comprises of the scan header and any entropy-coded + segments or restart marker following it. The size and offset to + the associated data (ECS + RST segments) are append to a new + GstJpegScanOffsetSize structure. + Signed-off-by: Gwenole Beauchesne + +2012-04-19 23:50:14 +0800 Wind Yuan + + * gst-libs/gst/codecparsers/gstjpegparser.c: + * gst-libs/gst/codecparsers/gstjpegparser.h: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + jpeg: update to match latest parser API. + Signed-off-by: Gwenole Beauchesne + +2012-04-13 01:58:39 -0400 Gwenole Beauchesne + + * gst-libs/gst/codecparsers/gstjpegparser.h: + jpeg: simplify and optimize parser API. + +2012-04-18 22:30:45 -0400 Wind Yuan + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + mpeg: fix picture used to determine backward_reference_vop_coding_type. + Complete fix brought by bf9f77b1afb0829b97e2d502057aec973c5fd7f5 + but Gwenole did not apply all the bits. + Signed-off-by: Gwenole Beauchesne + +2012-04-27 04:13:00 -0400 Wind Yuan + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + mpeg4: map Simple_Scalable profile to Advanced_Simple profile. + Signed-off-by: Gwenole Beauchesne + +2012-04-27 04:10:17 -0400 Wind Yuan + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + mpeg4: handle skipped frames (vop_hdr->coded = 0). + Gracefully skip non VOP coded frames. + Signed-off-by: Gwenole Beauchesne + +2012-04-26 04:00:41 -0400 Wind Yuan + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + mpeg4: fix timestamp issues on too fast playback. + Improve generation of presentation timestamps to be less sensitive + to input stream errors. In practise, GOP is also a synchronization + point for PTS calculation. + Signed-off-by: Gwenole Beauchesne + +2012-04-16 10:02:29 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicodec_objects.c: + Fix build without JPEG decoder. + +2012-04-12 11:48:24 +0200 Wind Yuan + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + mpeg4: fix VOP coding type of backward reference pictures. + Signed-off-by: Gwenole Beauchesne + +2012-04-11 23:02:45 -0400 Wind Yuan + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + mpeg4: fix handling of temporal reference distances. + TRD and TRB fields are not large enough to hold the difference of PTS + expressed with nanosecond resolution. So, compute them from the original + VOP info. + Signed-off-by: Gwenole Beauchesne + +2012-04-12 11:00:22 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_dpb.c: + dpb: mpeg2: cosmetics. + Define MAX_MPEG2_REFERENCES to 2 and avoid magic numbers all around. + +2012-02-10 00:21:04 +0800 Wind Yuan + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapicodec_objects.c: + * gst-libs/gst/vaapi/gstvaapicodec_objects.h: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_jpeg.h: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + * gst/vaapi/gstvaapidecode.c: + Add initial JPEG decoder. + Signed-off-by: Gwenole Beauchesne + +2012-02-10 00:21:04 +0800 Wind Yuan + + * configure.ac: + * gst-libs/gst/Makefile.am: + * gst-libs/gst/codecparsers/Makefile.am: + * gst-libs/gst/codecparsers/gstjpegparser.c: + * gst-libs/gst/codecparsers/gstjpegparser.h: + * gst-libs/gst/vaapi/Makefile.am: + codecparsers: add JPEG parser. + Signed-off-by: Gwenole Beauchesne + +2012-04-10 13:29:10 +0200 Wind Yuan + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: fix VA display type. + Fix typo whereby plain VADisplay type was used instead of the GstVaapiDisplay + wrapper. + Signed-off-by: Gwenole Beauchesne + +2012-04-10 14:28:31 +0200 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: fix includes when compiling for a single API. + +2012-04-02 18:42:12 +0200 Gwenole Beauchesne + + * NEWS: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: fix calculation of macroblock_offset. + Fix decoding of streams with extra slice() information before the first + macroblock(). e.g. this fixes sony-ct3.bs from conformance test. + +2012-04-02 18:09:21 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: fix interpolation of GOP TSN from new PTS. + New GOP TSN base could be mis-calculated. In particular, this fixes + decoding of uruseiyatsura.vob from . + +2012-04-02 16:07:58 +0200 Gwenole Beauchesne + + * NEWS: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + mpeg2: fix decoding of high profile streams. + Allow MPEG-2 High profile streams only if the HW supports that profile + or no High profile specific bits are used, and thus Main profile could + be used instead. i.e. chroma_format is 4:2:0, intra_dc_precision is not + set to 11 and no sequence_scalable_extension() was parsed. + +2012-04-02 14:51:06 +0200 Gwenole Beauchesne + + * NEWS: + * gst/vaapi/gstvaapidecode.c: + vaapidecode: report unsupported codec profiles. + Try to gracefully abort when the HW does not support the requested + profile. There is no fallback unless profiles are correctly parsed + and matched through caps beforehand. + +2012-02-07 15:23:22 +0100 Holger Kaelberer + + * NEWS: + * gst/vaapi/gstvaapisink.c: + vaapisink: don't resize a 'foreign' X-window. + Don't forcibly resize foreign X windows. The user is responsible for + their size and vaapisink shall not change this. + Signed-off-by: Gwenole Beauchesne + +2012-02-07 15:21:05 +0100 Holger Kaelberer + + * NEWS: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + vaapisink: recalculate render rect only if caps are negotiated. + Fix gst_vaapisink_xoverlay_set_window_handle() when it is called before + caps got negotiated. Besides, when a foreign window is provided by the + user, so should the render rect. + Signed-off-by: Gwenole Beauchesne + +2012-04-02 13:07:34 +0200 Gwenole Beauchesne + + * configure.ac: + Bump version for development. + +2012-04-02 10:07:33 +0200 Gwenole Beauchesne + + * configure.ac: + 0.3.6. + +2012-04-02 12:52:54 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-docs.xml.in: + * docs/reference/libs/libs-sections.txt: + * docs/reference/plugins/plugins-docs.xml.in: + * docs/reference/plugins/plugins-sections.txt: + * docs/reference/plugins/plugins.types: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapivideoconverter_glx.c: + * gst/vaapi/gstvaapipostproc.c: + Fix a few documentation issues. + +2012-04-02 10:05:57 +0200 Gwenole Beauchesne + + * NEWS: + * README: + Update introduction and changelog. + +2012-04-02 11:29:53 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_dpb.c: + * gst-libs/gst/vaapi/gstvaapidecoder_dpb.h: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: allocate dummy picture for first field based I-frame. + In P-pictures, prediction shall be made from the two most recently + decoded reference fields. However, when the first I-frame is a field, + the next field of the current picture could be a P-picture but only a + single field was decoded so far. In this case, create a dummy picture + with POC = -1 that will be used as reference. + Some VA drivers would error out if P-pictures don't have a forward + reference picture. This is true in general but not in this very specific + initial case. + +2012-04-02 10:43:30 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: fix simple to main profile fallback. + Allow fallback from simple to main profile when the HW decoder does + not support the former profile and that no sequence_header_extension() + is available to point out this. + +2012-03-30 03:04:40 -0400 Wind Yuan + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + mpeg4: improve error checking while decoding packets. + decode_picture() could return an error when an MPEG-4 profile is not + supported for example. In this case, the underlying VA context is not + allocated and no other proper action can be taken. Likewise on exit + from decode_slice(). + Signed-off-by: Gwenole Beauchesne + +2012-03-30 17:03:28 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_dpb.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + decoder: use POC to maintain the DPB. + Introduce a POC field in GstVaapiPicture so that to store simpler sequential + numbers. A signed 32-bit integer should be enough for 1 year of continuous + video streaming at 60 Hz. + Use this new POC value to maintain the DPB, instead of 64-bit timestamps. + This also aligns with H.264 that will be migrated to GstVaapiDpb infrastructure. + +2012-03-30 16:23:33 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: rework generation of presentation timestamps. + Always prefer PTS from the demuxer layer for GOP times. If this is invalid, + i.e. demuxer could not determine the PTS or the generated PTS is lower than + max PTS from past pictures, then try to fix it up based on the duration of + a frame. + For picture PTS, simply use the GOP PTS formerly computed then use TSN to + reconstruct a current time. Also now handle wrapped TSN correctly. + +2012-03-30 17:07:39 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: ignore empty user-data packets. + Fix tcela-8.bits conformance test. + +2012-03-29 11:13:20 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: review and report errors accordingly. + Use GST_ERROR() to report real errors instead of hiding them into + GST_DEBUG(). + +2012-03-28 19:15:47 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: fix invalid interlaced frame in progressive sequence. + Some streams, badly constructed, could have signaled an interlaced + frame while the sequence was meant to be progressive. Warn and force + frame to be progressive in this case. + +2012-03-28 16:08:29 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + mpeg2: add support for interlaced streams. + Pictures are submitted to the HW for rendering only when both fields + are decoded or current picture is a full frame. + +2012-03-28 14:36:30 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidecoder_dpb.c: + * gst-libs/gst/vaapi/gstvaapidecoder_dpb.h: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: add new decoded picture buffer infrastructure. + Decoded pictures are now maintained into DPB, similarly to H.264. + The same mechanism could be re-used for VC-1 and MPEG-4:2 codecs. + +2012-03-28 17:50:28 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + decoder: add first-field flag to picture. + Add first-field (FF) flag to GstVaapiPicture, thus not requiring is_first_field + member in each decoder. Rather, when a GstVaapiPicture is created, it is considered + as the first field. Any subsequent allocated field will become the second field. + +2012-03-28 16:05:58 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicodec_objects.c: + * gst-libs/gst/vaapi/gstvaapicodec_objects.h: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + decoder: allow pictures to be cloned for field decoding. + Add gst_vaapi_picture_new_field() function that clones a picture, while + preserving the parent picture surface. i.e. the surface proxy reference + count is increased and other fields copied as is. Besides, the picture + is reset into a "non-output" mode. + +2012-03-28 16:07:44 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + decoder: rework picture field flags. + Add top-field-first (TFF) and interlaced flags to GstVaapiPicture so they + could be propagated to the surface proxy when it is pushed for rendering. + Besides, top and bottom fields are now expressed with picture structure flags + from GstVaapiSurfaceRenderFlags. + +2012-03-28 14:28:26 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + decoder: add OUTPUT flag to pictures. + Allow pictures to be marked as output gst_vaapi_picture_output(). + +2012-03-28 14:24:40 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + decoder: fix semantics of SKIPPED pictures. + If GstVaapiPicture has flag SKIPPED set, this means gst_vaapi_picture_output() + will not push the underlying surface for rendering. Besides, VC-1 skipped P-frame + has nothing to do with rendering. This only means that the currently decoded + picture is just a copy of its reference picture. + +2012-03-28 15:16:17 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + * gst/vaapi/gstvaapipostproc.c: + vaapipostproc: get "interlaced" attribute from surface proxy. + Add new "interlaced" attribute to GstVaapiSurfaceProxy. Use this in + vaapipostproc so that to handles cases where bitstream is interlaced + but almost only frame pictures are generated. In this case, we should + not be alternating between top/bottom fields. + +2012-03-26 14:37:24 +0200 Gwenole Beauchesne + + * README: + * debian.upstream/control.in: + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapipostproc.c: + * gst/vaapi/gstvaapipostproc.h: + vaapipostproc: add new element for video postprocessing. + Add vaapipostproc element for video postprocessing. So far, only basic + bob deinterlacing is implemented. Interlaced mode is automatically + detected based on sink caps ("interlaced" field). + +2012-03-26 12:01:36 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer.h: + * gst-libs/gst/vaapi/gstvaapivideoconverter_glx.c: + * gst/vaapi/gstvaapisink.c: + videobuffer: add surface render flags. + Allow rendering flags, as a combination of GstVaapiSurfaceRenderFlags, + to be set to the video buffer. In particular, this is mostly useful for + basic deinterlacing. + +2012-03-23 17:13:58 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicompat.h: + compat: add compatibility glue with VA-API 0.34+ (WIP). + +2012-03-23 17:11:18 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: skip all Filler Data NALs. + +2012-03-22 03:28:22 -0400 Wind Yuan + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + mpeg4: check for decoder status prior to decoding packet. + Make sure there is a VA surface free prior to decoding the current frame. + Signed-off-by: Gwenole Beauchesne + +2012-03-15 04:58:04 -0400 Wind Yuan + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + decode: delay NEWSEGMENT event if vaapidecode element was not linked. + Rationale: playbin2 links all elements at run-time. Once vaapidecode + is created and a NEWSEGMENT event arrives, downstream element may not + be ready yet. So, delay this event until next element is chained in, + otherwise basesink could output "Received buffer without a new-segment. + Assuming timestamps start from 0". + Signed-off-by: Gwenole Beauchesne + +2012-03-13 20:33:41 -0400 Wind Yuan + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: fix GOP timestamps when incorrect data is received. + Some streams have incorrect GOP timestamps, or nothing set at all. + i.e. GOP time is 00:00:00 for all GOPs. Try to recover in this case + from demuxer timestamps, which are monotonic. + Signed-off-by: Gwenole Beauchesne + +2012-03-13 02:03:31 -0400 Wind Yuan + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: don't decode anything before the first sequence_header(). + Skip all pictures prior to the first sequence_header(). Besides, + skip all picture_data() if there was no prior picture_header(). + Signed-off-by: Gwenole Beauchesne + +2012-02-07 15:57:14 +0100 Holger Kaelberer + + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + ffmpeg: add support for interlaced streams. + Evaluate interlaced stream properties. + Signed-off-by: Gwenole Beauchesne + +2012-02-07 15:54:15 +0100 Holger Kaelberer + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: propagate interlaced and TFF properties downstream. + Propagate "interlaced" caps downstream and set "tff" buffer flag + appropriately to output buffers for interlaced pictures. + Signed-off-by: Gwenole Beauchesne + +2012-02-07 15:54:15 +0100 Holger Kaelberer + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + decoder: maintain caps for interlaced streams. + Extend GstVaapiDecoder base object to maintain caps with "interlaced" + property. + Signed-off-by: Gwenole Beauchesne + +2012-02-07 15:54:15 +0100 Holger Kaelberer + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + surfaceproxy: add TFF property. + Add TFF (top-field-first) property to GstVaapiSurfaceProxy. + Signed-off-by: Gwenole Beauchesne + +2012-03-16 14:21:36 +0100 Gwenole Beauchesne + + * AUTHORS: + AUTHORS: update to match current authors. + +2012-02-28 11:58:21 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: fix is_first_field calculation. + Reset is_first_field for frame pictures. Factor out locations where + the flag is updated. + +2012-02-24 12:56:48 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: catch incorrect picture_structure from bitstreams. + Assume "frame" picture structure if the syntax element was zero or if + progressive_frame is set. + +2012-02-24 12:53:30 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: fix slice_vertical_position calculation (again). + VA-API expects slice_vertical_position as the initial position from the + bitstream. i.e. the direct slice() information. VA drivers will be fixed + accordingly. + +2012-03-02 15:03:57 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + Revert "vaapidecode: fix another pad template ref leak" (Holger Kaelberer) + This reverts commit 2f127d6af473afd647a2c88f75faafd1cd718437. + For gst_element_class_get_pad_template(), no unreferencing is necessary + according to the GStreamer documentation. + +2012-03-02 13:41:16 +0100 Gwenole Beauchesne + + * configure.ac: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: fix slice_data_bit_offset calculation. + Unlike what VA-API documentation defines, the slice_data_bit_offset + represents the offset to the first macroblock in the slice data, minus + any emulation prevention bytes in the slice_header(). + This fix copes with binary-only VA drivers that won't be fixed any + time soon. Besides, this aligns with the current FFmpeg behaviour + that was based on those proprietary drivers implementing the API + incorrectly. + +2012-02-21 02:11:20 -0500 Wind Yuan + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: skip all Access Unit (AU) NALs. + Signed-off-by: Gwenole Beauchesne + +2012-02-29 03:08:46 -0500 Wind Yuan + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: fix modification process of reference picture lists. + Construction of RefPicList0/1 could be off by one element. + Signed-off-by: Gwenole Beauchesne + +2012-02-12 11:21:52 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: fix size calculation from sequence_extension(). + Original values from sequence_header() are 12-bit and the remaining + 2 most significant bits are coming from sequence_extension(). + Signed-off-by: Gwenole Beauchesne + +2012-02-23 16:39:14 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: fix slice_vertical_position calculation. + Make sure to adjust slice_vertical_position if picture structure + is a top or bottom field. + +2012-02-23 16:23:27 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + decoder: add picture structure flags. + +2012-02-23 14:42:38 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: fix decoding at end-of-sequence. + +2012-02-23 14:17:34 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: fix slice_horizontal_position calculation. + +2012-02-23 16:14:02 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: drop useless mb_y and mb_height members. + +2012-02-23 11:19:48 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: fix decoding of multiple slices with same slice_vertical_position. + 6.3.15 says that "some slices may have the same slice_vertical_position, + since slices may start and finish anywhere". So, we can't submit the current + picture to the HW right away since subsequent slices would be missing. + +2012-02-15 14:08:44 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiimage.c: + image: fix source stride in picture copy. + +2012-02-13 10:10:35 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + decoder: fix double buffer free with some VA drivers. + vaRenderPicture() implicitly disposes VA buffers. Some VA drivers would + push the VA buffer object into a list of free buffers to be re-used. However, + reference pictures (and data) that was kept would explicitly release the VA + buffer object later on, thus possibly destroying a valid (re-used) object. + Besides, some other VA drivers don't support correctly the vaRenderPicture() + semantics for VA buffers disposal and would leak memory if there is no explicit + vaDestroyBuffer(). The temporary workaround is to explcitily destroy VA buffers + right after vaRenderPicture(). All VA drivers need to be aligned. + +2012-02-08 18:08:49 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: complete any current picture decoder before SPS / PPS change. + This ensures the VA context is clear when the encoded resolution + changes. i.e. make sure older picture is decoded with the older + VA context before it changes. + +2012-02-08 18:07:14 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: create VA context earlier when SPS is parsed. + +2012-02-08 17:57:29 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: don't allocate too big data structures on stack. + +2012-02-07 11:07:15 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/glibcompat.h: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplaycache.c: + glib: map deprecated API to glib >= 2.32 equivalents. + GStaticMutex and GStaticRecMutex are now replaced with GMutex and + GRecMutex, which no longer require any prior call to g_thread_init(). + +2012-02-07 10:01:01 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiutils.h: + * gst-libs/gst/vaapi/gstvaapiutils_glx.h: + * gst-libs/gst/vaapi/gstvaapiutils_x11.h: + glib: fix includes. + +2012-02-07 10:05:53 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicodec_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + cosmetics: fix warnings (drop unused variables). + +2012-02-06 16:11:38 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: fix another pad template ref leak. + +2012-02-06 15:54:09 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + mpeg2: fix crash when there is no free surface to decode into. + +2012-01-31 16:38:58 +0800 Zhao Halley + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + display: skip profiles which have no entrypoints. + Signed-off-by: Gwenole Beauchesne + +2012-02-05 18:28:51 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapiupload.c: + vaapiupload: use g_object_unref() for GstVaapiImage. + +2012-02-05 18:24:08 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiupload.c: + plugins: fix pad template ref leaks. + +2012-02-02 09:23:15 +0100 Gwenole Beauchesne + + * configure.ac: + Bump version for development. + +2012-02-01 23:34:09 +0100 Gwenole Beauchesne + + * NEWS: + * configure.ac: + 0.3.4. + +2012-02-01 23:32:47 +0100 Gwenole Beauchesne + + * README: + README: updates. + Mention codecparsers-based decoders, FFmpeg is now optional. Update + list of support HW. + +2012-02-01 23:28:23 +0100 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2012-01-31 11:34:17 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + decoder: allocate proxy surface earlier. + This simplifies gst_vaapi_picture_output() to only update the presentation + timestamp and submit the proxy to the decoder for output. + +2012-01-31 11:26:37 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + decoder: fix memory leak of VA objects on exit. + On sequence end, if the last decoded picture is not output for rendering, + then the proxy surface is not created. In this case, the original surface + must be released explicitly to the context. + +2012-01-31 10:47:36 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: use GstAdapter to track input sequence. + This fixes possible memory leaks and improves performance by removing + some extra copies. + +2012-01-30 18:25:03 +0100 Gwenole Beauchesne + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/glibcompat.h: + * gst-libs/gst/vaapi/sysdeps.h: + Add glib compatibility glue for older versions. + +2012-01-30 18:12:59 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapicodec_objects.c: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplaycache.c: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimageformat.c: + * gst-libs/gst/vaapi/gstvaapiimagepool.c: + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapiparamspecs.c: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + * gst-libs/gst/vaapi/gstvaapiutils_x11.c: + * gst-libs/gst/vaapi/gstvaapivalue.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer_glx.c: + * gst-libs/gst/vaapi/gstvaapivideoconverter_glx.c: + * gst-libs/gst/vaapi/gstvaapivideopool.c: + * gst-libs/gst/vaapi/gstvaapivideosink.c: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst-libs/gst/vaapi/sysdeps.h: + Add header for system-dependent definitions. + +2012-01-30 10:15:32 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicodec_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + decoder: optimize slice data buffers initialization. + VA drivers may have a faster means to transfer user buffers to GPU + buffers than using memcpy(). In particular, on Intel Gen graphics, we + can use pwrite(). This provides for faster upload of bitstream and can + help higher bitrates. + vaapi_create_buffer() helper function was also updated to allow for + un-mapped buffers and pre-initialized data for buffers. + +2012-01-27 17:28:50 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: simplify RefPicList reconstruction. + +2012-01-27 16:08:03 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: flush DPB when the end of the sequence is reached. + +2012-01-24 15:38:14 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: handle Decoded Picture Buffer (DPB). + +2012-01-24 09:20:25 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: fix pred_weight_table() reconstruction. + Only the explicit pred_weight_table(), possibly with the inferred default + values, shall be required. e.g. don't fill in the table if weighted_pred_flag + is not set for P/SP slices. + +2012-01-23 15:03:07 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: execute reference picture marking process (MMCO). + +2012-01-23 15:20:51 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: fix presentation timestamps. + +2012-01-18 13:38:34 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: execute reference picture marking process (sliding window). + +2012-01-17 10:42:49 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: handle avcC format for decoding buffers. + +2011-11-25 14:37:00 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + h264: handle codec-data. + Signed-off-by: Gwenole Beauchesne + +2011-08-12 17:43:55 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.c: + * gst-libs/gst/vaapi/gstvaapidecoder_h264.h: + * gst/vaapi/gstvaapidecode.c: + * tests/test-decode.c: + Add initial H.264 decoder. + +2012-01-26 15:28:42 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + decoder: retain proxy surface until the GstVaapiPicture is destroyed. + Keep a valid reference to the proxy in GstVaapiPicture so that frames + marked as "used for reference" could be kept during the lifetime of the + picture. i.e. don't release them too soon as they could be re-used right + away. + +2012-01-26 15:19:14 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + decoder: properly reference count pictures. + This fixes cases where a GstVaapiPicture would be destroyed whereas + there is still a valid instance of it in either prev, current or + next picture. + +2012-01-26 14:54:31 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + decoder: simplify output of decoded frames. + Drop obsolete gst_vaapi_decoder_push_surface() that was no longer used. + Change gst_vaapi_decoder_push_surface_proxy() semantics to assume PTS + is already set correctly and reference count increased, if necessary. + +2012-01-26 09:48:11 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapicodec_objects.c: + * gst-libs/gst/vaapi/gstvaapicodec_objects.h: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.c: + * gst-libs/gst/vaapi/gstvaapidecoder_objects.h: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + decoder: rework the internal VA objects API. + The new API simplifies a lot reference counting and makes it more + flexible for future additions/changes. The GstVaapiCodecInfo is + also gone. Rather, new helper macros are provided to allocate + picture, slice and quantization matrix parameter buffers. + +2012-01-24 10:21:45 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + decoder: allow slices to be attached to pictures later. + +2011-11-21 18:39:49 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + decoder: add ref_count to GstVaapiPicture. + +2012-01-23 11:48:42 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + vaapisink: cap window size to the maximum display size. + +2012-01-18 10:23:41 +0100 Zhao Halley + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiworkarounds.h: + profile: match video/x-h263 as H.263 Baseline profile. + HACK: qtdemux does not report profiles for H.263. So, assume plain + "video/x-h263" is H.263 Baseline profile. + Signed-off-by: Gwenole Beauchesne + +2012-01-18 10:22:58 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapiworkarounds.h: + display: report H.263 Baseline profile. + HACK: expose GST_VAAPI_PROFILE_H263_BASELINE for decoding if MPEG-4:2 Simple + profile (VAProfileMPEG4Simple) is supported. + +2012-01-24 10:06:37 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiworkarounds.h: + Add template for workarounds. + +2012-01-18 10:47:56 +0100 Gwenole Beauchesne + + * tests/test-decode.c: + tests: error out if FFmpeg|codecparsers are not supported. + +2012-01-18 10:42:38 +0100 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapisurface_priv.h: + surface: don't expose gst_vaapi_surface_get_parent_context(). + gst_vaapi_surface_get_parent_context() was not meant to be exposed globally. + It's just an internal helper function. However, it's still possible to get + the parent context through the "parent-context" property. + +2012-01-16 14:19:00 +0100 Gwenole Beauchesne + + * tests/Makefile.am: + * tests/test-subpicture.c: + tests: fix build without FFmpeg. + +2012-01-16 14:09:57 +0100 Gwenole Beauchesne + + * configure.ac: + Bump version for development. + +2012-01-16 11:05:31 +0100 Gwenole Beauchesne + + * NEWS: + * configure.ac: + 0.3.3. + +2012-01-16 11:03:51 +0100 Gwenole Beauchesne + + * README: + * debian.upstream/copyright: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.c: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapidownload.h: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapiupload.c: + * gst/vaapi/gstvaapiupload.h: + * tests/test-decode.c: + legal: fix year for some copyright notices. + +2012-01-16 10:42:55 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.c: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst-libs/gst/vaapi/gstvaapiimageformat.c: + * gst-libs/gst/vaapi/gstvaapiimageformat.h: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.h: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + * gst-libs/gst/vaapi/gstvaapiutils_x11.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer.h: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst/vaapi/gstvaapidownload.h: + * gst/vaapi/gstvaapisink.h: + * gst/vaapi/gstvaapiupload.h: + * tests/test-decode.c: + legal: add Intel copyright on modified files. + +2012-01-16 10:41:10 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapi_priv.h: + * gst-libs/gst/vaapi/gstvaapicompat.h: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapidebug.h: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.h: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.c: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst-libs/gst/vaapi/gstvaapiimageformat.c: + * gst-libs/gst/vaapi/gstvaapiimageformat.h: + * gst-libs/gst/vaapi/gstvaapiimagepool.c: + * gst-libs/gst/vaapi/gstvaapiimagepool.h: + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapiobject.h: + * gst-libs/gst/vaapi/gstvaapiobject_priv.h: + * gst-libs/gst/vaapi/gstvaapiparamspecs.c: + * gst-libs/gst/vaapi/gstvaapiparamspecs.h: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.h: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapitexture.h: + * gst-libs/gst/vaapi/gstvaapitypes.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + * gst-libs/gst/vaapi/gstvaapiutils_glx.h: + * gst-libs/gst/vaapi/gstvaapiutils_x11.c: + * gst-libs/gst/vaapi/gstvaapiutils_x11.h: + * gst-libs/gst/vaapi/gstvaapivalue.c: + * gst-libs/gst/vaapi/gstvaapivalue.h: + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer.h: + * gst-libs/gst/vaapi/gstvaapivideopool.c: + * gst-libs/gst/vaapi/gstvaapivideopool.h: + * gst-libs/gst/vaapi/gstvaapivideosink.c: + * gst-libs/gst/vaapi/gstvaapivideosink.h: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.h: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapidownload.h: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + * gst/vaapi/gstvaapiupload.c: + * gst/vaapi/gstvaapiupload.h: + * tests/image.c: + * tests/image.h: + * tests/test-decode.c: + * tests/test-decode.h: + * tests/test-display.c: + * tests/test-h264.c: + * tests/test-h264.h: + * tests/test-mpeg2.c: + * tests/test-mpeg2.h: + * tests/test-surfaces.c: + * tests/test-textures.c: + * tests/test-vc1.c: + * tests/test-vc1.h: + * tests/test-windows.c: + legal: fix copyright notices to include "Copyright" term. + +2011-12-09 16:44:03 +0800 Zhao Halley + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.h: + mpeg4: replace GstVaapiTSB with GstAdapter (gst-plugins-base >= 0.10.24). + Signed-off-by: Gwenole Beauchesne + +2011-12-09 16:28:11 +0800 Zhao Halley + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.h: + * gst/vaapi/gstvaapidecode.c: + Add initial MPEG-4 decoder. + Signed-off-by: Gwenole Beauchesne + +2011-11-18 15:41:40 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.h: + vc1: replace GstVaapiTSB with GstAdapter (gst-plugins-base >= 0.10.24). + Signed-off-by: Gwenole Beauchesne + +2011-10-07 11:50:20 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + vc1: fix codec-data decoding for WMV3 format. + +2011-10-07 11:12:33 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + vc1: fix presentation timestamps. + +2011-10-06 15:59:22 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + vc1: fix MV mode packing. + +2011-10-05 16:41:57 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + vc1: handle codec-data. + +2011-10-05 15:56:36 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + vc1: handle encapsulated bitstreams. + +2011-10-04 17:51:51 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + vc1: fix bitplanes decoding. + +2011-10-04 14:15:55 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + vc1: fix BFRACTION reconstruction. + +2011-09-30 17:16:23 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + vc1: fix framerate calculation. + +2011-09-30 13:40:11 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.c: + * gst-libs/gst/vaapi/gstvaapidecoder_vc1.h: + * gst/vaapi/gstvaapidecode.c: + * tests/test-decode.c: + Add initial VC-1 decoder. + +2012-01-09 17:37:34 +0100 Zhao Halley + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: fix first field detection. + Signed-off-by: Gwenole Beauchesne + +2012-01-06 16:44:09 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: fix quantisation matrix construction. + +2011-11-18 15:06:07 +0200 Sreerenj Balachandran + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.h: + mpeg2: replace GstVaapiTSB API with GstAdapter (gst-plugins-base >= 0.10.24). + Signed-off-by: Gwenole Beauchesne + +2011-09-14 18:11:57 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: fix packets spanning over two buffers. + +2011-09-12 18:20:00 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: ignore system start codes (PES headers). + +2011-09-12 18:02:53 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + mpeg2: handle closed_gop. + +2011-08-05 11:55:11 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c: + * gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.h: + * gst/vaapi/gstvaapidecode.c: + * tests/test-decode.c: + Add initial MPEG-2 decoder. + +2011-08-12 10:21:19 +0200 Gwenole Beauchesne + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapidecode.c: + * tests/test-decode.c: + Allow conditional build of GStreamer/FFmpeg bitstream parsers. + +2011-08-05 11:53:50 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + Add VA decoder helpers. + +2011-08-05 11:52:43 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.h: + decoder: add new error codes. + GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE: for unsupported profile + GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT: for unsupported chroma format + +2011-09-12 13:00:59 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiutils_tsb.c: + * gst-libs/gst/vaapi/gstvaapiutils_tsb.h: + Add timestamp buffer store helper utils. + +2011-08-04 17:29:41 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + Add VA buffer helpers. + +2012-01-13 15:03:38 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + utils: slight improvements to gl_bind_texture(). + +2012-01-13 14:13:55 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + utils: pretty-print output of gl_get_error_string(). + +2012-01-13 14:03:29 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + utils: rewrite gl_perspective() as per OpenGL FAQ 9.085. + +2012-01-13 12:09:07 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiutils.c: + utils: simplify string of VAProfile/VAEntrypoint. + +2012-01-13 11:46:55 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + utils: drop string_of_FOURCC() in favor of standard GST_FOURCC_* helpers. + +2012-01-12 17:18:47 +0100 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2012-01-12 15:34:59 +0100 Gwenole Beauchesne + + * tests/test-decode.c: + tests: check for shared VA displays (display cache). + +2012-01-12 15:30:04 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + display: always free VA display cache if it is empty. + +2012-01-12 15:03:04 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.c: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + display: use VA display cache for X11 and GLX winsys. + +2012-01-12 12:46:34 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplaycache.c: + * gst-libs/gst/vaapi/gstvaapidisplaycache.h: + display: implement a VA display cache. + +2012-01-11 14:13:06 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginutil.c: + vaapiplugin: fix gst_vaapi_ensure_display() to use system defaults. + This ensures the display name provided to gst_vaapi_display_*_new() + maps to the system defaults, instead of forcing "" that could be different + from the current DISPLAY name. + +2011-08-26 15:44:25 -0400 Nicolas Dufresne + + * gst/vaapi/gstvaapiupload.c: + vaapiupload: only set caps on newly created buffers. + Signed-off-by: Gwenole Beauchesne + +2012-01-11 14:11:30 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + vaapisink: ensure VA display in GstBaseSink::start() hook. + This ensures a VA display is ready by the time upstream elements request + for it. + +2011-08-26 15:44:46 -0400 Nicolas Dufresne + + * gst/vaapi/gstvaapisink.c: + vaapisink: don't leak GL texture. + Signed-off-by: Gwenole Beauchesne + +2012-01-09 16:51:35 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + vaapisink: fix calculation of render region. + +2012-01-09 11:23:39 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + vaapisink: automatically fit video to window. + +2012-01-09 10:37:30 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + vaapisink: implement GstXOverlay::set_render_rectangle(). + +2012-01-09 11:04:21 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiwindow.c: + window: always check geometry when the window is mapped. + +2012-01-06 17:51:59 +0100 Zhao Halley + + * gst-libs/gst/vaapi/gstvaapiutils.c: + Add missing profiles from VA-API 0.32.0. + Signed-off-by: Gwenole Beauchesne + +2012-01-06 16:48:15 +0100 Gwenole Beauchesne + + * .gitignore: + .gitignore: add test-subpicture. + +2012-01-06 11:23:21 +0100 Gwenole Beauchesne + + * configure.ac: + Bump version for development. + +2012-01-06 11:20:48 +0100 Gwenole Beauchesne + + * NEWS: + * configure.ac: + 0.3.2. + +2012-01-06 11:18:55 +0100 Gwenole Beauchesne + + * tests/Makefile.am: + tests: fix make dist (ship with test-subpicture-data.h). + +2012-01-05 17:35:12 +0100 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2012-01-05 17:09:35 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + decoder: fix possible leak of VA surfaces. + Under some circumstances, we could have leaked a surface, thus not + releasing it to the pool of available surfaces in the VA context. + The strategy is now to use a proxy earlier and automatically ref/unref + whenever necessary. In particular, during the lifetime needed for FFmpeg. + +2012-01-05 16:59:57 +0100 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + surfaceproxy: add helper to retrieve the VA surface ID. + +2012-01-05 16:44:44 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + surfaceproxy: simplify destruction. + Also make sure to always make sure to release the surface back to the + pool of surfaces in the associated VA context, if any. + +2012-01-05 16:26:49 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapidecode.c: + vaapidecode: fix deinitialization order. + +2012-01-05 14:50:26 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapicontext.c: + context: avoid self reference loops with surfaces. + +2012-01-05 11:23:01 +0100 Gwenole Beauchesne + + * debian.upstream/control.in: + debian: update control.in description for new plugins. + +2012-01-05 11:01:56 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapiupload.c: + vaapiupload: use new gst_vaapi_append_surface_caps() helper. + This also fixes extra structures, beyond the one at index 0, to hold + the right additional values. + +2012-01-05 10:55:34 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapiupload.c: + vaapiupload: fix sink (YUV) caps to not report type and opengl fields. + +2012-01-05 10:50:59 +0100 Gwenole Beauchesne + + * README: + * docs/reference/plugins/plugins-docs.xml.in: + * docs/reference/plugins/plugins-sections.txt: + * docs/reference/plugins/plugins.types: + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapidownload.c: + * gst/vaapi/gstvaapidownload.h: + vaapidownload: add new plugin to download pixels from VA surfaces. + +2012-01-05 11:00:39 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + vaapipluingutils: add helper to append surface caps to YUV caps. + +2012-01-05 10:29:48 +0100 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + image: add helpers to extract pixels to user buffers. + +2012-01-04 11:34:34 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiimage.c: + image: simplify initialization of raw images from video buffers. + +2012-01-04 11:29:11 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiimage.c: + image: fix update from NV12 buffers. + +2012-01-03 18:16:35 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapiupload.c: + vaapiupload: fix memory leak in _init() function. + +2012-01-03 14:34:09 +0100 Gwenole Beauchesne + + * NEWS: + * README: + * debian.upstream/control.in: + * docs/reference/plugins/plugins-docs.xml.in: + * docs/reference/plugins/plugins-sections.txt: + * docs/reference/plugins/plugins.types: + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapiupload.c: + * gst/vaapi/gstvaapiupload.h: + Rename vaapiconvert element to vaapiupload. + +2012-01-03 13:54:03 +0100 Gwenole Beauchesne + + * configure.ac: + Bump version for development. + +2012-01-03 13:42:12 +0100 Gwenole Beauchesne + + * NEWS: + * configure.ac: + 0.3.1. + +2011-12-14 15:22:24 +0100 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2011-12-14 14:40:37 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapivideoconverter_glx.c: + * gst/vaapi/gstvaapisink.c: + surface: apply composition to the parent context, if requested. + +2011-12-14 14:35:13 +0100 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + context: make it possible to apply composition globally. + +2011-12-14 14:13:58 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurface.c: + surface: fix associate subpicture to not report deassociation errors. + +2011-12-14 13:46:26 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurface.c: + surface: fix typo in debug message. + +2011-12-14 13:16:21 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.h: + * gst-libs/gst/vaapi/gstvaapisurface.c: + subpicture: add helper to create subpicture from GstVideoOverlayRectangle. + +2011-12-13 16:53:15 +0100 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapisurface_priv.h: + surface: record parent context. + +2011-12-13 15:59:02 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiutils_x11.c: + * gst-libs/gst/vaapi/gstvaapivideoconverter_glx.c: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapisink.c: + Fix warnings. + +2011-12-13 15:51:58 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapivideoconverter_glx.c: + * gst/vaapi/gstvaapisink.c: + Rename gst_vaapi_surface_update_composition() to gst_vaapi_surface_set_subpictures_from_composition(). + +2011-12-13 13:40:55 +0100 Gwenole Beauchesne + + * configure.ac: + configure: check for GstVideoOverlayComposition. + +2011-12-12 18:42:44 +0100 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2011-11-25 15:00:25 -0500 Nicolas Dufresne + + * gst-libs/gst/vaapi/gstvaapivideoconverter_glx.c: + converter: add support for GstVideoOverlayComposition planes. + Signed-off-by: Gwenole Beauchesne + +2011-11-23 16:45:46 -0300 Thibault Saunier + + * gst/vaapi/gstvaapisink.c: + vaapisink: handle GstVideoOverlayComposition planes. + Signed-off-by: Gwenole Beauchesne + +2011-12-12 18:27:14 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurface.c: + surface: use unscaled overlay rectangle for blending. + +2011-12-12 18:37:13 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurface.c: + surface: fix VA image leak when an error occurred. + +2011-11-25 14:59:56 -0500 Nicolas Dufresne + + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + surface: add helper to handle GstVideoOverlayComposition. + This helper resets the subpictures to reflect the current composition + layers provided with the buffers. + Signed-off-by: Gwenole Beauchesne + +2011-12-12 18:13:19 +0100 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiimageformat.c: + * gst-libs/gst/vaapi/gstvaapiimageformat.h: + * gst/vaapi/gstvaapiconvert.c: + image: add gst_vaapi_image_format_from_video() helper. + +2011-12-12 16:34:07 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + image: allow updates from GstVaapiImageRaw. + +2011-12-12 14:34:03 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst/vaapi/gstvaapiconvert.c: + * tests/test-subpicture.c: + image: allow partial updates. + +2011-12-12 15:31:52 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + subpicture: fix doc for gst_vaapi_subpicture_set_image(). + +2011-12-12 13:39:20 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + display: fix has_image_format() to check against subpicture formats. + +2011-10-17 18:43:15 +0200 Gwenole Beauchesne + + * tests/test-subpicture.c: + tests: fix subpicture test. + +2011-10-14 13:00:12 -0300 Thibault Saunier + + * tests/Makefile.am: + * tests/test-subpicture-data.c: + * tests/test-subpicture-data.h: + * tests/test-subpicture.c: + tests: add test for subpictures. + Signed-off-by: Gwenole Beauchesne + +2011-11-25 12:28:04 -0500 Nicolas Dufresne + + * gst/vaapi/gstvaapiconvert.c: + * gst/vaapi/gstvaapidecode.c: + Add missing video context queries. + Signed-off-by: Gwenole Beauchesne + +2011-12-12 13:22:07 +0100 Gwenole Beauchesne + + * configure.ac: + Bump version for development. + +2011-12-12 10:04:32 +0100 Gwenole Beauchesne + + * gst-libs/gst/video/Makefile.am: + * gst-libs/gst/video/gstbasevideocodec.c: + * gst-libs/gst/video/gstbasevideocodec.h: + * gst-libs/gst/video/gstbasevideodecoder.c: + * gst-libs/gst/video/gstbasevideodecoder.h: + * gst-libs/gst/video/gstbasevideoutils.c: + * gst-libs/gst/video/gstbasevideoutils.h: + Drop unused copy of GstBaseVideoDecoder. + +2011-12-09 11:46:45 +0100 Gwenole Beauchesne + + * NEWS: + * configure.ac: + 0.3.0. + +2011-12-09 11:38:43 +0100 Gwenole Beauchesne + + * README: + README: update dependencies. + +2011-12-09 11:38:34 +0100 Gwenole Beauchesne + + * NEWS: + NEWS: updates. + +2011-12-09 11:20:04 +0100 Gwenole Beauchesne + + * configure.ac: + configure: check for GstBaseSink 'query' vfunc. + +2011-12-09 10:45:20 +0100 Gwenole Beauchesne + + * gst/vaapi/Makefile.am: + vaapiplugin: include local build dir to CFLAGS for generated files. + +2011-12-09 10:44:52 +0100 Gwenole Beauchesne + + * autogen.sh: + autogen: don't configure if NO_CONFIGURE variable is set. + +2011-12-08 11:54:59 +0100 Sreerenj Balachandran + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + vaapidecode: return sink caps template if decoder is in NULL state. + Otherwise, the decoder would always create its own X display instead + of probing it from the downstream element, which is not reliable. + e.g. DISPLAY is not :0 or when running on Wayland. + Signed-off-by: Gwenole Beauchesne + +2011-12-08 15:44:09 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapiconvert.c: + * gst/vaapi/gstvaapidecode.c: + vaapiplugin: properly set surface type to "vaapi" in caps. + +2011-12-08 15:16:14 +0100 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + decoder: drop unused headers. + +2011-11-04 19:47:25 -0400 Nicolas Dufresne + + * gst/vaapi/gstvaapiconvert.c: + * gst/vaapi/gstvaapidecode.c: + vaapiplugin: properly set opengl support in caps. + Signed-off-by: Gwenole Beauchesne + +2011-11-04 20:07:52 -0400 Nicolas Dufresne + + * gst/vaapi/gstvaapiconvert.c: + * gst/vaapi/gstvaapidecode.c: + vaapiplugin: allocate GLX buffers when supported. + Signed-off-by: Gwenole Beauchesne + +2011-11-04 19:47:09 -0400 Nicolas Dufresne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer_glx.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer_glx.h: + * gst-libs/gst/vaapi/gstvaapivideobuffer_priv.h: + * gst-libs/gst/vaapi/gstvaapivideoconverter_glx.c: + * gst-libs/gst/vaapi/gstvaapivideoconverter_glx.h: + videobuffer: add GLX buffer support. + Signed-off-by: Gwenole Beauchesne + +2011-10-06 16:06:15 -0400 Nicolas Dufresne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer.h: + Port to GstSurfaceBuffer interface. + Signed-off-by: Gwenole Beauchesne + +2011-10-06 16:04:37 -0400 Nicolas Dufresne + + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapisink.c: + Don't use downstream buffer allocation. + With the new video/x-surface abstraction, we can't rely on having a VA + specific sink downstream. Also, there was no particular reason to do that. + Signed-off-by: Gwenole Beauchesne + +2011-11-04 17:16:23 -0400 Nicolas Dufresne + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst/vaapi/gstvaapiconvert.c: + * gst/vaapi/gstvaapisink.c: + * tests/Makefile.am: + * tests/test-surfaces.c: + Change caps to use new video/x-surface generic type. + Signed-off-by: Gwenole Beauchesne + +2011-11-04 16:50:15 -0400 Nicolas Dufresne + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiutils_gst.c: + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapiconvert.c: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapipluginutil.c: + * gst/vaapi/gstvaapipluginutil.h: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + Port to GstVideoContext interface. + This new interface allows for upstream and downstream display sharing + that works in both static and dynamic pipelines. + Signed-off-by: Gwenole Beauchesne + +2011-12-08 14:57:36 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + vaapisink: use GST_ERROR to print error messages. + +2011-12-08 13:30:51 +0100 Gwenole Beauchesne + + * gst/vaapi/Makefile.am: + vaapiplugin: link against VA/GLX when enabled. + +2011-12-07 19:09:55 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapiconvert.c: + * gst/vaapi/gstvaapisink.c: + Add Intel copyright information. + +2011-12-07 19:04:09 +0100 Gwenole Beauchesne + + * gst/vaapi/gstvaapisink.c: + vaapisink: allow compatibility with gst-plugins-base < 0.10.31. + +2011-12-07 18:40:35 +0100 Gwenole Beauchesne + + * .gitignore: + * configure.ac: + * gst-libs/gst/Makefile.am: + * gst-libs/gst/gstutils_version.h.in: + Add new GStreamer version check utilities. + +2011-07-28 11:14:49 +0300 Sreerenj Balachandran + + * gst/vaapi/gstvaapisink.c: + vaapisink: replace the deprecated xoverlay API with the new one. + Signed-off-by: Gwenole Beauchesne + +2011-12-07 17:31:09 +0100 Gwenole Beauchesne + + * configure.ac: + configure: allow for pre-releases. + +2011-10-13 17:08:13 -0400 Nicolas Dufresne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + display: destroy display on creation failure. + This allows element to detect that the display creation has actually + failed. + Signed-off-by: Gwenole Beauchesne + +2011-10-13 17:07:35 -0400 Nicolas Dufresne + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + display: don't crash when config is empty. + Signed-off-by: Gwenole Beauchesne + +2011-12-07 14:42:14 +0100 Gwenole Beauchesne + + * README: + * debian.upstream/copyright: + doc: mention Collabora copyrights. + +2011-12-07 14:40:20 +0100 Gwenole Beauchesne + + * .gitignore: + .gitignore: refine for generated docs. + +2011-09-14 15:12:41 -0400 Nicolas Dufresne + + * configure.ac: + * docs/reference/plugins/Makefile.am: + * gst/Makefile.am: + * gst/vaapi/Makefile.am: + * gst/vaapi/gstvaapi.c: + * gst/vaapi/gstvaapiconvert.c: + * gst/vaapi/gstvaapiconvert.h: + * gst/vaapi/gstvaapidecode.c: + * gst/vaapi/gstvaapidecode.h: + * gst/vaapi/gstvaapisink.c: + * gst/vaapi/gstvaapisink.h: + * gst/vaapiconvert/Makefile.am: + * gst/vaapidecode/Makefile.am: + Group all plugins into the same bundle + Signed-off-by: Gwenole Beauchesne + +2011-07-21 14:31:30 +0200 Gwenole Beauchesne + + * configure.ac: + Bump version for development. + +2011-12-07 14:17:32 +0100 Gwenole Beauchesne + + * configure.ac: + * debian.upstream/control.in: + debian: build against upstream libva packages. + +2011-12-07 13:52:17 +0100 Gwenole Beauchesne + + * docs/reference/libs/Makefile.am: + * docs/reference/plugins/Makefile.am: + * tests/Makefile.am: + Fix build on Ubuntu 11.10 (Oneric). + +2011-12-07 13:14:28 +0100 Gwenole Beauchesne + + * NEWS: + 0.2.7. + +2011-09-12 16:20:16 -0400 Nicolas Dufresne + + * .gitignore: + Adding ignore file + Signed-off-by: Gwenole Beauchesne + +2011-10-24 16:18:16 -0400 Nicolas Dufresne + + * gst/vaapiconvert/gstvaapiconvert.c: + * gst/vaapidecode/gstvaapidecode.c: + * gst/vaapisink/gstvaapisink.c: + Update license in plugin definition + Signed-off-by: Gwenole Beauchesne + +2011-10-12 14:00:50 +0200 Gwenole Beauchesne + + * NEWS: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + decoder: fix use of invalid data at the end-of-stream. + +2011-10-19 14:47:31 +0200 Gwenole Beauchesne + + * gst/vaapiconvert/gstvaapiconvert.c: + vaapiconvert: fix some warnings. + +2011-10-19 14:43:56 +0200 Gwenole Beauchesne + + * configure.ac: + * debian.upstream/changelog.in: + * debian.upstream/control.in: + * debian.upstream/copyright: + * gst/vaapiconvert/gstvaapiconvert.c: + * gst/vaapidecode/gstvaapidecode.c: + * gst/vaapisink/gstvaapisink.c: + Update with my current e-mail address. + +2011-10-19 14:39:21 +0200 Gwenole Beauchesne + + * NEWS: + * README: + Splitted-Desktop systems relicensed plugins and tests to LGPL v2.1+. + +2011-10-18 09:18:20 +0200 warly + + * tests/image.c: + * tests/image.h: + * tests/test-decode.c: + * tests/test-decode.h: + * tests/test-display.c: + * tests/test-h264.c: + * tests/test-h264.h: + * tests/test-mpeg2.c: + * tests/test-mpeg2.h: + * tests/test-surfaces.c: + * tests/test-textures.c: + * tests/test-vc1.c: + * tests/test-vc1.h: + * tests/test-windows.c: + switch tests licence to LGPL v2.1+ + +2011-10-18 09:06:52 +0200 warly + + * COPYING: + * README: + * debian.upstream/copyright: + * gst/vaapiconvert/gstvaapiconvert.c: + * gst/vaapiconvert/gstvaapiconvert.h: + * gst/vaapidecode/gstvaapidecode.c: + * gst/vaapidecode/gstvaapidecode.h: + * gst/vaapisink/gstvaapisink.c: + * gst/vaapisink/gstvaapisink.h: + move plugins to LGPL v2.1+ + +2011-09-14 13:07:18 +0200 Gwenole Beauchesne + + * gst/vaapidecode/gstvaapidecode.c: + vaapidecode: fix sink caps to not expose size information. + This fixes this particular issue: + GStreamer-WARNING **: pad vaapidecode0:sink returned caps which are not + a real subset of its template caps + +2011-09-14 11:34:05 +0200 Gwenole Beauchesne + + * NEWS: + * gst/vaapidecode/gstvaapidecode.c: + vaapidecode: fix decoding of MPEG-2 PS files. + +2011-09-12 13:00:04 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/Makefile.am: + Cosmetics (sort source files). + +2011-09-08 14:50:24 +0200 Gwenole Beauchesne + + * gst/vaapiconvert/gstvaapiconvert.c: + * gst/vaapiconvert/gstvaapiconvert.h: + vaapiconvert: fix direct-rendering caps detection. + +2011-09-08 14:40:08 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapiimage.c: + Fix gst_vaapi_image_new_with_image(). + +2011-09-08 13:09:17 +0200 Gwenole Beauchesne + + * gst/vaapiconvert/gstvaapiconvert.c: + vaapiconvert: warn when surface failed to be updated with image. + +2011-09-06 18:34:33 +0200 Gwenole Beauchesne + + * gst/vaapiconvert/gstvaapiconvert.c: + vaapiconvert: fix autodetection for vaDeriveImage() support. + +2011-09-06 17:47:10 +0200 Gwenole Beauchesne + + * gst/vaapiconvert/gstvaapiconvert.c: + vaapiconvert: fix memory leak (VA surface image). + +2011-09-05 16:20:20 +0200 Gwenole Beauchesne + + * NEWS: + * gst/vaapiconvert/gstvaapiconvert.c: + vaapiconvert: fix direct-rendering mode. + +2011-09-06 16:49:43 +0200 Gwenole Beauchesne + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer.h: + Add gst_vaapi_video_buffer_new_from_buffer(). + Add helper function to bind a foreign buffer into a GstVaapiVideoBuffer. + Any image, surface or surface proxy will be inherited from the source buffer + if it is a GstVaapiVideoBuffer. + +2011-09-05 17:23:05 +0200 Gwenole Beauchesne + + * gst/vaapiconvert/gstvaapiconvert.c: + vaapiconvert: protect access to direct_rendering. + +2011-09-05 16:18:14 +0200 Gwenole Beauchesne + + * gst/vaapiconvert/gstvaapiconvert.c: + vaapiconvert: use gst_vaapi_display_lookup_downstream() helper to get a VA display. + +2011-08-01 14:15:39 +0200 Gwenole Beauchesne + + * NEWS: + * README: + * debian.upstream/copyright: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst/vaapidecode/gstvaapidecode.c: + * gst/vaapidecode/gstvaapidecode.h: + Add Intel copyright information. + +2011-07-22 15:59:00 +0200 Gwenole Beauchesne + + * NEWS: + Updates. + +2011-07-22 15:55:47 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + Fix build with newer FFmpeg versions. + +2011-07-22 15:39:51 +0200 Gwenole Beauchesne + + * gst/vaapidecode/gstvaapidecode.c: + * gst/vaapidecode/gstvaapidecode.h: + Fix decoding of MPEG-2 TS files. + +2011-07-22 15:34:48 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + Report caps update only once per video resolution change. + +2011-07-22 15:33:13 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapisurface.h: + Add canonical form (type name) of VA surface caps. + +2011-07-22 15:42:16 +0200 Gwenole Beauchesne + + * configure.ac: + Bump version for development. + +2011-07-19 17:38:40 +0200 Gwenole Beauchesne + + * configure.ac: + Use pretty build output with automake >= 1.11. + +2011-07-15 16:08:08 +0200 Gwenole Beauchesne + + * gst/vaapiconvert/Makefile.am: + * gst/vaapidecode/Makefile.am: + * gst/vaapisink/Makefile.am: + * tests/Makefile.am: + Fix build with libva headers not in a standard include dir. + +2011-06-14 15:59:08 +0200 Gwenole Beauchesne + + * configure.ac: + 0.2.6. + +2011-06-14 13:52:56 +0200 Gwenole Beauchesne + + * gst-libs/gst/vaapi/gstvaapi_priv.h: + * gst-libs/gst/vaapi/gstvaapicompat.h: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapidebug.h: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.h: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.c: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst-libs/gst/vaapi/gstvaapiimageformat.c: + * gst-libs/gst/vaapi/gstvaapiimageformat.h: + * gst-libs/gst/vaapi/gstvaapiimagepool.c: + * gst-libs/gst/vaapi/gstvaapiimagepool.h: + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapiobject.h: + * gst-libs/gst/vaapi/gstvaapiobject_priv.h: + * gst-libs/gst/vaapi/gstvaapiparamspecs.c: + * gst-libs/gst/vaapi/gstvaapiparamspecs.h: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.h: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapitexture.h: + * gst-libs/gst/vaapi/gstvaapitypes.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + * gst-libs/gst/vaapi/gstvaapiutils_glx.h: + * gst-libs/gst/vaapi/gstvaapiutils_gst.c: + * gst-libs/gst/vaapi/gstvaapiutils_gst.h: + * gst-libs/gst/vaapi/gstvaapiutils_x11.c: + * gst-libs/gst/vaapi/gstvaapiutils_x11.h: + * gst-libs/gst/vaapi/gstvaapivalue.c: + * gst-libs/gst/vaapi/gstvaapivalue.h: + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer.h: + * gst-libs/gst/vaapi/gstvaapivideopool.c: + * gst-libs/gst/vaapi/gstvaapivideopool.h: + * gst-libs/gst/vaapi/gstvaapivideosink.c: + * gst-libs/gst/vaapi/gstvaapivideosink.h: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.h: + * gst/vaapiconvert/gstvaapiconvert.c: + * gst/vaapiconvert/gstvaapiconvert.h: + * gst/vaapidecode/gstvaapidecode.c: + * gst/vaapidecode/gstvaapidecode.h: + * gst/vaapisink/gstvaapisink.c: + * gst/vaapisink/gstvaapisink.h: + * tests/image.c: + * tests/image.h: + * tests/test-decode.c: + * tests/test-decode.h: + * tests/test-display.c: + * tests/test-h264.c: + * tests/test-h264.h: + * tests/test-mpeg2.c: + * tests/test-mpeg2.h: + * tests/test-surfaces.c: + * tests/test-textures.c: + * tests/test-vc1.c: + * tests/test-vc1.h: + * tests/test-windows.c: + Update copyright notice. + +2011-06-14 13:51:41 +0200 Gwenole Beauchesne + + * NEWS: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + * gst-libs/gst/vaapi/gstvaapiutils_x11.c: + * gst-libs/gst/vaapi/gstvaapivalue.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + * gst-libs/gst/vaapi/gstvaapivideopool.c: + * gst-libs/gst/vaapi/gstvaapivideosink.c: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + Fix licensing terms. + +2010-07-20 11:23:16 +0000 gb + + * NEWS: + 0.2.5. + +2010-07-20 11:21:37 +0000 gb + + * debian.upstream/copyright: + Fix license terms... + +2010-07-01 13:19:29 +0000 gb + + * gst/vaapisink/gstvaapisink.c: + Render pretty background only in use-reflection=true mode. + +2010-07-01 11:43:22 +0000 gb + + * NEWS: + Updates. + +2010-07-01 11:41:23 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + Drop the GLX 1.3 requirement. + +2010-07-01 11:38:28 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + * gst-libs/gst/vaapi/gstvaapiutils_glx.h: + Call the GLX/Pixmap related functions through the vtable. + +2010-07-01 11:11:18 +0000 gb + + * NEWS: + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + Drop dependency on libavformat. + +2010-06-22 15:15:46 +0000 gb + + * gst-libs/gst/video/gstbasevideodecoder.c: + * gst-libs/gst/video/gstbasevideodecoder.h: + Add gst_base_video_decoder_update_src_caps(). Don't forcibly set "interlaced" field if upstream elements did not have any. + +2010-06-22 14:06:25 +0000 gb + + * gst-libs/gst/video/gstbasevideodecoder.c: + * gst-libs/gst/video/gstbasevideoutils.c: + * gst-libs/gst/video/gstbasevideoutils.h: + Drop superfluous functions. + +2010-06-22 13:57:33 +0000 gb + + * gst-libs/gst/video/gstbasevideodecoder.c: + Really drop any dependency on libgstvideo. i.e. inline the helpers. + +2010-06-22 13:48:30 +0000 gb + + * gst-libs/gst/video/gstbasevideodecoder.c: + Further drop dependency on libgstvideo. + +2010-06-22 12:57:06 +0000 gb + + * gst-libs/gst/video/Makefile.am: + * gst-libs/gst/video/gstbasevideocodec.c: + * gst-libs/gst/video/gstbasevideocodec.h: + * gst-libs/gst/video/gstbasevideodecoder.c: + * gst-libs/gst/video/gstbasevideodecoder.h: + * gst-libs/gst/video/gstbasevideoutils.c: + * gst-libs/gst/video/gstbasevideoutils.h: + Add GstBaseVideoDecoder from gst-plugins-bad git. + +2010-06-15 12:36:16 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + Fix GLX version check. + +2010-06-14 14:46:41 +0000 gb + + * NEWS: + * configure.ac: + Bump version for development. + +2010-06-14 14:14:42 +0000 gb + + * NEWS: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + Fix decoding of some H.264 streams. e.g. Ice Age 2 trailer. + +2010-06-14 12:58:22 +0000 gb + + * NEWS: + Update changelog. + +2010-06-14 09:20:37 +0000 gb + + * gst-libs/gst/vaapi/gstvaapicompat.h: + Fix build with older VA-API 0.29-sds. + +2010-05-18 11:22:54 +0000 gb + + * gst/vaapisink/gstvaapisink.c: + * gst/vaapisink/gstvaapisink.h: + Fix upscaling in foreign window (Totem). + +2010-05-17 12:32:34 +0000 gb + + * gst/vaapisink/gstvaapisink.c: + Soft validate caps since we only care about video/x-vaapi-surface as input. _setcaps() will check for other fields. + +2010-05-17 08:55:51 +0000 gb + + * NEWS: + * gst/vaapisink/gstvaapisink.c: + Fix video rendering rect within an embedder window (Totem). + +2010-05-17 08:28:28 +0000 gb + + * NEWS: + * gst/vaapisink/gstvaapisink.c: + Disable GLX rendering when vaapisink uses a foreign X window. + +2010-05-17 08:24:42 +0000 gb + + * gst/vaapisink/gstvaapisink.c: + Simplify GLX rendering code. + +2010-05-17 07:32:10 +0000 gb + + * configure.ac: + Bump version for development. + +2010-05-16 21:44:17 +0000 gb + + * NEWS: + 0.2.3. + +2010-05-16 21:35:14 +0000 gb + + * gst/vaapidecode/gstvaapidecode.c: + Wait for at most one second for a VA surface to become available. + +2010-05-16 21:18:37 +0000 gb + + * README: + * configure.ac: + Build-Requires: gstreamer0.10 >= 0.10.10 for gst_caps_merge(). + +2010-05-16 21:17:49 +0000 gb + + * NEWS: + * README: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + Fix decoder caps to report codec aliases. + +2010-05-16 21:04:32 +0000 gb + + * NEWS: + * gst/vaapidecode/gstvaapidecode.c: + * gst/vaapidecode/gstvaapidecode.h: + Fix VC-1 decoding through the playbin2 pipeline. + +2010-05-15 15:33:20 +0000 gb + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + Regularly update and expose decoder caps. + +2010-05-15 09:43:28 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + Add mechanism to reinsert buffer leftovers into the queue. + +2010-05-15 06:59:54 +0000 gb + + * NEWS: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + Fix memory leak of encoded buffers. + +2010-05-15 05:36:15 +0000 gb + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + Check for out-of-free-surfaces condition. + +2010-05-15 04:35:00 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder.h: + Change GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN value to something more generic (-1). + +2010-05-15 04:25:32 +0000 gb + + * gst/vaapisink/gstvaapisink.c: + Improve debug info for gst_vaapisink_ensure_render_rect(). + +2010-05-14 05:02:05 +0000 gb + + * configure.ac: + Bump version for development. + +2010-05-13 21:52:22 +0000 gb + + * NEWS: + 0.2.2. + +2010-05-13 21:39:58 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + Improve previous fix. + +2010-05-13 21:27:43 +0000 gb + + * NEWS: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + Fix a crash in the FFmpeg decoder on close. + +2010-05-13 16:41:55 +0000 gb + + * README: + Sort platforms by name. + +2010-05-13 09:40:52 +0000 gb + + * NEWS: + * configure.ac: + Bump version for development. + +2010-05-13 09:38:47 +0000 gb + + * gst/vaapisink/gstvaapisink.c: + Add debug info for _show_frame(). + +2010-05-13 07:19:46 +0000 gb + + * Makefile.am: + Nuke older build dir. + +2010-05-13 07:19:21 +0000 gb + + * debian.upstream/control.in: + Fix packaging deps. + +2010-05-13 06:12:37 +0000 gb + + * NEWS: + Cosmetics. + +2010-05-13 06:11:42 +0000 gb + + * NEWS: + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + Fix OpenGL texture internal format (Clutter). + +2010-05-13 04:40:40 +0000 gb + + * NEWS: + Respin release. + +2010-05-13 04:27:44 +0000 gb + + * gst/vaapisink/gstvaapisink.c: + Debug video & display PARs. + +2010-05-13 04:22:31 +0000 gb + + * gst/vaapisink/gstvaapisink.c: + Use XGetGeometry() to retrieve the window size. + +2010-05-12 19:40:30 +0000 gb + + * gst/vaapisink/gstvaapisink.c: + Move code around. + +2010-05-12 19:35:45 +0000 gb + + * gst/vaapisink/gstvaapisink.c: + Ensure VA display is created prior to initializing the window from a specific XID. Also move code down. + +2010-05-12 19:18:04 +0000 gb + + * README: + Drop obsolete comment. + +2010-05-12 19:14:59 +0000 gb + + * NEWS: + 0.2.1. + +2010-05-12 19:14:35 +0000 gb + + * gst/vaapidecode/gstvaapidecode.c: + Fix GstVaapiDisplay refcounting in vaapidecode. + +2010-05-12 14:10:38 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiutils_gst.c: + Fix comment. + +2010-05-12 12:58:53 +0000 gb + + * gst/vaapisink/gstvaapisink.c: + * gst/vaapisink/gstvaapisink.h: + Fix render rect when the foreign window size changes. + +2010-05-12 11:43:50 +0000 gb + + * NEWS: + * configure.ac: + * gst/vaapisink/Makefile.am: + * gst/vaapisink/gstvaapisink.c: + Add GstXOverlay interface to vaapisink (e.g. for Totem). + +2010-05-12 10:51:21 +0000 gb + + * README: + Update deps to match configure.ac versions. + +2010-05-12 09:34:37 +0000 gb + + * gst/vaapiconvert/gstvaapiconvert.c: + * gst/vaapidecode/gstvaapidecode.c: + * gst/vaapisink/gstvaapisink.c: + Cosmetics. + +2010-05-12 09:22:49 +0000 gb + + * NEWS: + * gst/vaapidecode/Makefile.am: + * gst/vaapidecode/gstvaapidecode.c: + * gst/vaapidecode/gstvaapidecode.h: + Fix vaapidecode to expose the HW supported caps only. + +2010-05-12 08:32:34 +0000 gb + + * gst/vaapidecode/gstvaapidecode.c: + Initialize decoder earlier. + +2010-05-12 08:02:45 +0000 gb + + * NEWS: + * README: + * gst/vaapidecode/gstvaapidecode.c: + Fix integration within the playbin2 pipeline. + +2010-05-12 08:02:19 +0000 gb + + * docs/reference/libs/Makefile.am: + Exclude gstvaapiutils_gst.h from docs for now. + +2010-05-12 08:00:09 +0000 gb + + * gst/vaapiconvert/gstvaapiconvert.c: + * gst/vaapidecode/gstvaapidecode.c: + * gst/vaapisink/gstvaapisink.c: + Raise VA-API plugins ranks. + +2010-05-12 07:57:55 +0000 gb + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiutils_gst.c: + * gst-libs/gst/vaapi/gstvaapiutils_gst.h: + Add gst_vaapi_display_lookup_downstream() helper. + +2010-05-11 16:23:17 +0000 gb + + * gst/vaapidecode/gstvaapidecode.c: + Use fixed caps on the src pad, they are not meant to change from video/x-vaapi-surface. + +2010-05-11 16:19:30 +0000 gb + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer.h: + * gst/vaapisink/gstvaapisink.c: + Expose VA display through GstVaapiVideoBuffer. + +2010-05-11 16:09:49 +0000 gb + + * gst/vaapidecode/gstvaapidecode.c: + Simplify gst_vaapidecode_set_caps() and fix memory leak. + +2010-05-11 12:06:59 +0000 gb + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapivideopool.c: + * gst-libs/gst/vaapi/gstvaapivideopool.h: + Expose video pool display. + +2010-05-11 12:03:13 +0000 gb + + * gst-libs/gst/vaapi/gstvaapivideosink.c: + Stop iteration if there is no more element to examine. + +2010-05-10 09:32:47 +0000 gb + + * gst/vaapiconvert/gstvaapiconvert.c: + * gst/vaapidecode/gstvaapidecode.c: + * gst/vaapisink/gstvaapisink.c: + Improve plugin details. + +2010-05-07 06:35:31 +0000 gb + + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst/vaapiconvert/gstvaapiconvert.c: + * gst/vaapidecode/gstvaapidecode.c: + * gst/vaapisink/gstvaapisink.c: + Factor out VA surface caps. + +2010-05-05 15:36:25 +0000 gb + + * gst/vaapidecode/gstvaapidecode.c: + Add gst_vaapidecode_ensure_display() helper for set-caps. + +2010-05-05 12:57:59 +0000 gb + + * configure.ac: + Bump version for development. + +2010-05-05 12:29:28 +0000 gb + + * NEWS: + Really make it 0.2.0. + +2010-05-05 12:28:59 +0000 gb + + * README: + More docs. + +2010-05-05 11:48:31 +0000 gb + + * docs/reference/libs/Makefile.am: + Don't exclude GstVaapiParamSpecs. + +2010-05-05 11:44:06 +0000 gb + + * docs/reference/libs/Makefile.am: + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + Fix docs. + +2010-05-05 06:06:02 +0000 gb + + * gst/vaapiconvert/gstvaapiconvert.c: + * gst/vaapidecode/gstvaapidecode.c: + * gst/vaapisink/gstvaapisink.c: + Lower plugins rank for now since playbin2 auto-plugging is not working properly. User applications will have to create their own pipeline or with some hacks around playbin2. + +2010-05-04 15:03:47 +0000 gb + + * gst-libs/gst/vaapi/Makefile.am: + Really link all helper libraries with libtool -no-undefined. + +2010-05-04 15:02:29 +0000 gb + + * gst-libs/gst/vaapi/Makefile.am: + Link helper libraries with libtool -no-undefined. + +2010-05-04 14:59:27 +0000 gb + + * configure.ac: + * debian.upstream/gstreamer-vaapi.install.in: + * gst/vaapiconvert/Makefile.am: + * gst/vaapidecode/Makefile.am: + * gst/vaapisink/Makefile.am: + Don't build plugins with SONAME. Make them plain *.so. + +2010-05-04 08:59:27 +0000 gb + + * README: + Improve documentation for release. + +2010-05-03 22:50:56 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + Fix build with older VA-API 0.29. + +2010-05-03 22:43:01 +0000 gb + + * NEWS: + 0.2.0. + +2010-05-03 22:42:46 +0000 gb + + * tests/Makefile.am: + Fix make dist. + +2010-05-03 22:36:34 +0000 gb + + * docs/reference/libs/Makefile.am: + * docs/reference/libs/libs-docs.xml.in: + * docs/reference/libs/libs-sections.txt: + * docs/reference/libs/libs.core.types: + * docs/reference/plugins/Makefile.am: + * docs/reference/plugins/plugins-docs.xml.in: + * docs/reference/plugins/plugins-sections.txt: + * docs/reference/plugins/plugins.types: + Add missing docs. + +2010-05-03 22:34:53 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + Fix doc. + +2010-05-03 22:28:02 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.h: + * gst/vaapidecode/gstvaapidecode.c: + * tests/test-decode.c: + Rename gst_vaapi_decoder_ffmpeg_new_from_caps() to plain gst_vaapi_decoder_ffmpeg_new(). + +2010-05-03 22:02:41 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + Extract framerate information from caps. + +2010-05-03 21:49:35 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + Move caps initialization to parent class. + +2010-05-03 21:25:46 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + Simplify. + +2010-05-03 21:25:26 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + Fix doc. + +2010-05-03 21:14:01 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + More simplifications. + +2010-05-03 20:55:17 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * tests/test-decode.c: + Simplify GstVaapiDecoder API. + +2010-05-03 20:40:27 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder.h: + Drop obsolete defs. + +2010-05-03 20:34:57 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder.h: + Drop obsolete decls. + +2010-05-03 17:36:01 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst/vaapidecode/gstvaapidecode.c: + Add more aliases for MPEG-4 decoding. + +2010-05-03 17:04:00 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + Use avctx->coded_{width,height} info to create the VA context. + +2010-05-03 16:54:23 +0000 gb + + * tests/test-decode.c: + * tests/test-decode.h: + Use gst_vaapi_decoder_ffmpeg_new_from_caps(). + +2010-05-03 16:41:13 +0000 gb + + * tests/test-decode.c: + * tests/test-decode.h: + * tests/test-h264.c: + * tests/test-h264.h: + * tests/test-mpeg2.c: + * tests/test-mpeg2.h: + * tests/test-vc1.c: + * tests/test-vc1.h: + Simplify tests info. + +2010-05-03 16:17:51 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + Try to improve heuristics to use an AVCodecContextParser. + +2010-05-03 15:35:22 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + Fix VC-1 decoding, it does not require any specific parser. + +2010-05-03 15:34:22 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + Fix VC-1 detection with older gstreamer libs (no "fourcc" field, but a "format" one). + +2010-05-03 15:29:18 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + Use size information from the demuxer, whenever available. i.e. fix WMV3 decoding. + +2010-05-03 15:11:32 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.h: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * gst/vaapidecode/gstvaapidecode.c: + * gst/vaapidecode/gstvaapidecode.h: + Add gst_vaapi_decoder_ffmpeg_new_from_caps() helper. + +2010-05-03 14:53:18 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + Improve WMV3 detection yet further. + +2010-05-03 13:44:41 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + Fix detection of plain old WMV3 contents. + +2010-05-03 12:25:07 +0000 gb + + * tests/test-vc1.c: + Add End-of-Sequence start code. + +2010-05-03 11:44:23 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst/vaapidecode/gstvaapidecode.c: + Fix VC-1 detection. + +2010-05-03 08:51:28 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + Fix build with older gstreamer libs where gst_buffer_unref() is not a plain function. + +2010-05-03 08:34:57 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + Drop obsolete (and wrong) code. + +2010-05-03 08:33:23 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + Cosmetics (spelling). + +2010-05-03 08:32:46 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + Try to fix timestamps (step 1). Looks OK on H55. + +2010-05-03 07:10:04 +0000 gb + + * debian.upstream/Makefile.am: + Ship with COPYING.LIB. + +2010-05-03 07:07:27 +0000 gb + + * COPYING.LIB: + * NEWS: + * README: + * gst-libs/gst/vaapi/gstvaapi_priv.h: + * gst-libs/gst/vaapi/gstvaapicompat.h: + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + * gst-libs/gst/vaapi/gstvaapidebug.h: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.h: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.c: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst-libs/gst/vaapi/gstvaapiimageformat.c: + * gst-libs/gst/vaapi/gstvaapiimageformat.h: + * gst-libs/gst/vaapi/gstvaapiimagepool.c: + * gst-libs/gst/vaapi/gstvaapiimagepool.h: + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapiobject.h: + * gst-libs/gst/vaapi/gstvaapiobject_priv.h: + * gst-libs/gst/vaapi/gstvaapiparamspecs.c: + * gst-libs/gst/vaapi/gstvaapiparamspecs.h: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + * gst-libs/gst/vaapi/gstvaapisubpicture.h: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapisurfacepool.h: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + * gst-libs/gst/vaapi/gstvaapitexture.h: + * gst-libs/gst/vaapi/gstvaapitypes.h: + * gst-libs/gst/vaapi/gstvaapiutils.h: + * gst-libs/gst/vaapi/gstvaapiutils_glx.h: + * gst-libs/gst/vaapi/gstvaapiutils_x11.h: + * gst-libs/gst/vaapi/gstvaapivalue.h: + * gst-libs/gst/vaapi/gstvaapivideobuffer.h: + * gst-libs/gst/vaapi/gstvaapivideopool.h: + * gst-libs/gst/vaapi/gstvaapivideosink.h: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.h: + Relicense gst-libs/ code to LGPL v2.1+. + +2010-05-03 06:49:43 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + Drop extraneous comma. + +2010-05-03 06:49:19 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + Drop variant=itu field to help codec detection. + +2010-04-30 15:50:19 +0000 gb + + * gst/vaapidecode/gstvaapidecode.c: + Decode as many surfaces as possible in gst_vaapidecode_step(). + +2010-04-30 15:37:28 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * gst/vaapidecode/gstvaapidecode.c: + * gst/vaapidecode/gstvaapidecode.h: + * tests/test-decode.c: + Drop excessive threading that over-complicates synchronisation. MPEG-2 & H.264 videos now play but there are other problems (timestamps). + +2010-04-30 13:13:50 +0000 gb + + * configure.ac: + 0.2.0. + +2010-04-30 12:04:12 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + Move VA context reset to AVCodecContext.get_context() as the surface sizes can change. + +2010-04-30 09:52:29 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + Fix gst_vaapi_display_has_{decoder,encoder}() to check for the entrypoint too. + +2010-04-30 09:48:41 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + Add GST_VAAPI_ENTRYPOINT_SLICE_ENCODE. + +2010-04-30 08:18:07 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + Document H.264 / AVC1 format case better. + +2010-04-29 23:09:07 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + Fix H.264 decoding with AVC1 format bitstreams. + +2010-04-29 22:00:37 +0000 gb + + * gst/vaapidecode/gstvaapidecode.c: + Complete initialization of the GstVaapiVideoBuffer. Some frames start to show up. + +2010-04-29 21:59:14 +0000 gb + + * gst/vaapisink/gstvaapisink.c: + Add missing GstBaseSink::buffer_alloc() override. i.e. make sure to allocate a GstVaapiVideoBuffer instead of a plain GstBuffer from the peer pad. + +2010-04-29 21:56:10 +0000 gb + + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer.h: + Export gst_vaapi_video_buffer_new(). + +2010-04-29 21:12:30 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + Fix gst_vaapi_profile_get_caps() to include the "profile" field. + +2010-04-29 17:56:42 +0000 gb + + * configure.ac: + Fix comment. + +2010-04-29 17:55:58 +0000 gb + + * NEWS: + * configure.ac: + * gst/Makefile.am: + * gst/vaapidecode/Makefile.am: + * gst/vaapidecode/gstvaapidecode.c: + * gst/vaapidecode/gstvaapidecode.h: + Add FFmpeg/VAAPI decoder for the new `vaapidecode' element. + +2010-04-29 17:51:57 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + Add gst_vaapi_decoder_pause(). + +2010-04-29 17:11:32 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + Use a GstTask with start/stop semantics for the decoder thread. + +2010-04-29 16:08:46 +0000 gb + + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + Drop extraneous var. + +2010-04-29 15:45:44 +0000 gb + + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer.h: + Add support for GstVaapiSurfaceProxy to GstVaapiVideoBuffer. + +2010-04-29 14:58:45 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + Fix gst_vaapi_decoder_get_surface() status. + +2010-04-29 14:28:43 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + Try to set correct timestamps to the decoded surface proxy. + +2010-04-29 12:52:27 +0000 gb + + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + * tests/test-decode.c: + Add timestamps to GstVaapiSurfaceProxy. + +2010-04-29 09:43:40 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + Fix GstVaapiDecoder::destroy(): GASyncQueue is not a GObject, likewise for GstBuffer. + +2010-04-29 09:40:38 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + Fix destructor, av_parser_close() does destroy the struct already, unliker avcodec_close()... + +2010-04-29 09:35:54 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + Prefer profile from codec-data if any was found there. + +2010-04-29 09:34:54 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + Improve heuristics to find the best profile. Use the highest one if no explicit match on "profile" field. + +2010-04-28 23:09:52 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + Make sure gst_vaapi_decoder_get_surface() gets unblocked on error. + +2010-04-28 22:30:50 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + Fix VC-1 codec initialization, it really needs an extradata buffer. + +2010-04-28 22:16:10 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + Split decoder creation with actual resources allocation and codec setup (probe). This fixes a memory leak (avctx, pctx) on destroy and most interestingly makes it possible to detect unsupported codecs. + +2010-04-28 21:58:58 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + Move gst_vaapi_decoder_ffmpeg_create() call to object constructor. + +2010-04-28 21:50:44 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.h: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * tests/test-decode.c: + Add "codec-data" property for additional codec data. e.g. VC-1 sequence headers for elementary streams. + +2010-04-28 21:20:19 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + Cosmetics (weird indentation). + +2010-04-28 21:15:55 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + Cosmetics (extraneous variable, debug message). + +2010-04-28 09:07:45 +0000 gb + + * configure.ac: + Fix check for VA-API enabled FFmpeg. + +2010-04-27 15:26:19 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + - Add PTS and framerate information. - Simplify parsing with an AVCodeParserContext. + +2010-04-27 11:59:23 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + Add more error codes. Fix documentation. + +2010-04-26 13:30:27 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + Fix gst_vaapi_profile_get_codec(). Improve gst_vaapi_profile_from_caps() for H.264 & caps with "codec-data". + +2010-04-26 11:44:32 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + * tests/test-decode.c: + Handle user end-of-streams. Add gst_vaapi_decoder_{start,stop}() helpers. + +2010-04-26 11:36:12 +0000 gb + + * tests/test-vc1.c: + Drop useless End-of-Sequence marker. + +2010-04-26 08:53:18 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + Flush stream only if avcodec_decode_video() read something. Otherwise, we might still have to seek into the stream. i.e. keep the data longer. + +2010-04-26 08:40:27 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + Use a recursive mutex so that a single thread can lock several times. This fixes decoding of MPEG-2 and H.264 because those created a GstVaapiContext later through avcodec_decode_video() that was a protected call. + +2010-04-26 08:15:58 +0000 gb + + * tests/test-h264.c: + * tests/test-vc1.c: + Regenerate correct clips. + +2010-04-23 16:11:55 +0000 gb + + * tests/Makefile.am: + * tests/test-decode.c: + * tests/test-h264.c: + * tests/test-h264.h: + * tests/test-mpeg2.c: + * tests/test-mpeg2.h: + * tests/test-vc1.c: + * tests/test-vc1.h: + Add decoder demos. Use -c (mpeg2|h264|vc1) to select the codec. + XXX: only VC-1 decoding works at this time because of awful + bugs left in GstVaapiDecoderFfmpeg et al. + +2010-04-23 16:05:58 +0000 gb + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidecoder.c: + * gst-libs/gst/vaapi/gstvaapidecoder.h: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c: + * gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.h: + * gst-libs/gst/vaapi/gstvaapidecoder_priv.h: + Add initial (multithreaded) decoder based on FFmpeg. + There are tons of bugs left: + - Decoder API not nice enough with error conditions + - FFmpeg parser is sometimes broken + - Packets queue can be lost + +2010-04-23 16:00:50 +0000 gb + + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.c: + * gst-libs/gst/vaapi/gstvaapisurfaceproxy.h: + Add surface proxy that holds a reference to the parent surface and that returns the surface to that context on destruction. + +2010-04-23 15:59:31 +0000 gb + + * gst-libs/gst/vaapi/gstvaapicontext.c: + * gst-libs/gst/vaapi/gstvaapicontext.h: + Add VA context abstraction. + +2010-04-23 10:58:19 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiprofile.h: + Fix VA profiles definitions for gst_vaapi_profile_get_codec() to work. + +2010-04-21 15:03:31 +0000 gb + + * gst-libs/gst/vaapi/gstvaapivideopool.c: + * gst-libs/gst/vaapi/gstvaapivideopool.h: + Add a means to cap the number of objects allocated in the pool. + +2010-04-21 15:02:23 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + Add VA entrypoint abstraction. + +2010-04-20 13:36:04 +0000 gb + + * docs/reference/libs/libs-docs.xml.in: + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapiprofile.c: + * gst-libs/gst/vaapi/gstvaapiprofile.h: + * tests/test-display.c: + Add VA profile abstraction. + +2010-04-20 07:51:23 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + Fix OpenGL rendering on G45 systems. + +2010-04-16 13:47:30 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + Fix gl_create_context() to find a GLXFBConfig compatible with the parent GL context. + +2010-04-02 11:27:23 +0000 gb + + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + * gst-libs/gst/vaapi/gstvaapiutils_glx.h: + Fix TFP logic and simplify the FBO model. i.e. it's not necessary to create another texture (and storage) for the TFP, simply a new texture name. + +2010-04-01 16:11:54 +0000 gb + + * gst-libs/gst/vaapi/gstvaapitexture.c: + Fix get-out conditions. + +2010-04-01 15:38:59 +0000 gb + + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + The shared GL context in GstVaapiTexture is only useful for cases where TFP+FBO are used, thus avoiding the need fully preserve the states and call into glGet*() functions that need synchronization. + +2010-04-01 13:55:19 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiutils_glx.h: + Shorter structs. + +2010-04-01 13:41:24 +0000 gb + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.c: + * gst-libs/gst/vaapi/gstvaapidisplay_glx_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h: + * gst-libs/gst/vaapi/gstvaapiobject_priv.h: + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * tests/test-windows.c: + Make more helpers internal, thus reducing .text size further. Add gst_vaapi_display_x11_get_screen() helper along the way. + +2010-04-01 09:47:59 +0000 gb + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapi_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.c: + * gst-libs/gst/vaapi/gstvaapidisplay_priv.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + Move GST_VAAPI_DISPLAY_VADISPLAY() and GST_VAAPI_DISPLAY_{LOCK,UNLOCK}() to gstvaapidisplay_priv.h. + +2010-03-31 15:25:19 +0000 gb + + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + * gst-libs/gst/vaapi/gstvaapiutils_glx.h: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + Improve handling of GL contexts. + +2010-03-30 16:41:21 +0000 gb + + * configure.ac: + Simplify summary. + +2010-03-30 13:33:12 +0000 gb + + * configure.ac: + Bump version for development. + +2010-03-30 13:29:34 +0000 gb + + * configure.ac: + * debian.upstream/Makefile.am: + * debian.upstream/control.in: + Rename -dev package to libgstvaapi-dev. + +2010-03-30 13:17:12 +0000 gb + + * NEWS: + * README: + Updates. + +2010-03-30 13:05:31 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiutils.c: + Fix build with VA-API < 0.30. + +2010-03-30 13:01:34 +0000 gb + + * configure.ac: + * gst-libs/gst/vaapi/gstvaapicompat.h: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.c: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.h: + * gst-libs/gst/vaapi/gstvaapitexture.c: + * tests/test-display.c: + Enable build without VA/GLX extensions. i.e. fallback to TFP + FBO. + +2010-03-30 12:59:15 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + * gst-libs/gst/vaapi/gstvaapiutils_glx.h: + Add TFP and FBO helpers. + +2010-03-30 12:55:27 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + Cosmetics. Make vaapi_check_status() use GST_DEBUG() for error messages. + +2010-03-30 08:13:34 +0000 gb + + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + Use a shorter function name. + +2010-03-30 08:11:50 +0000 gb + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + Add gst_vaapi_surface_query_status() wrapper. + +2010-03-30 07:50:11 +0000 gb + + * docs/reference/plugins/Makefile.am: + Fix leftover during migration. + +2010-03-30 07:46:47 +0000 gb + + * Makefile.am: + * configure.ac: + * docs/reference/plugins/Makefile.am: + * gst/Makefile.am: + * gst/vaapiconvert/Makefile.am: + * gst/vaapiconvert/gstvaapiconvert.c: + * gst/vaapiconvert/gstvaapiconvert.h: + * gst/vaapisink/Makefile.am: + * gst/vaapisink/gstvaapisink.c: + * gst/vaapisink/gstvaapisink.h: + Rename to gst/ as sys/ was too vague. + +2010-03-30 07:39:16 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.h: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + Try to not reference VA-API types directly. + +2010-03-29 16:24:37 +0000 gb + + * sys/vaapisink/gstvaapisink.c: + Fix reflection code to preserve aspect ratio. + +2010-03-29 16:17:38 +0000 gb + + * sys/vaapisink/gstvaapisink.c: + * sys/vaapisink/gstvaapisink.h: + Fix fullscreen mode. + +2010-03-29 15:59:44 +0000 gb + + * sys/vaapisink/gstvaapisink.c: + * sys/vaapisink/gstvaapisink.h: + Add OpenGL reflection effect ("use-reflection"). + +2010-03-29 15:51:54 +0000 gb + + * configure.ac: + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + Use a projection suitable for rotation around the Y axis. + +2010-03-29 15:03:30 +0000 gb + + * configure.ac: + * sys/vaapisink/Makefile.am: + * sys/vaapisink/gstvaapisink.c: + * sys/vaapisink/gstvaapisink.h: + Don't build vaapisink/gl by default. However, if this is enabled, use the GL renderer by default. + +2010-03-29 14:50:52 +0000 gb + + * configure.ac: + * debian.upstream/Makefile.am: + * debian.upstream/control.in: + * debian.upstream/libgstvaapi-glx.install.in: + Add libgstvaapi-glx-0 package. + +2010-03-29 14:47:49 +0000 gb + + * pkgconfig/Makefile.am: + Really fix make distclean. + +2010-03-29 14:43:22 +0000 gb + + * docs/reference/libs/Makefile.am: + Fix make dist. + +2010-03-29 14:42:57 +0000 gb + + * pkgconfig/Makefile.am: + Fix make distclean. + +2010-03-29 14:40:26 +0000 gb + + * tests/Makefile.am: + Fix make dist. + +2010-03-29 14:31:17 +0000 gb + + * docs/reference/libs/Makefile.am: + * docs/reference/libs/libs.core.types: + * docs/reference/libs/libs.glx.types: + * docs/reference/libs/libs.x11.types: + Fix doc build. + +2010-03-29 14:21:51 +0000 gb + + * sys/vaapisink/gstvaapisink.h: + Fix build without GLX. + +2010-03-29 14:13:55 +0000 gb + + * NEWS: + 0.1.2. + +2010-03-29 14:13:26 +0000 gb + + * sys/vaapisink/Makefile.am: + * sys/vaapisink/gstvaapisink.c: + * sys/vaapisink/gstvaapisink.h: + Add VA/GLX support to vaapisink. + +2010-03-29 13:40:27 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + * gst-libs/gst/vaapi/gstvaapiutils_glx.h: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + Add glXSwapBuffers() workaround for NVIDIA. + +2010-03-29 13:27:16 +0000 gb + + * tests/Makefile.am: + * tests/test-textures.c: + Improve VA/GLX textures test. + +2010-03-29 12:51:38 +0000 gb + + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + * gst-libs/gst/vaapi/gstvaapiutils_glx.h: + Fix texture rendering. + +2010-03-29 11:25:20 +0000 gb + + * docs/reference/libs/libs-docs.xml.in: + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapitexture.c: + Fix documentation. + +2010-03-29 10:40:26 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.h: + Add gst_vaapi_window_glx_put_texture() helper. + +2010-03-29 09:09:30 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + Fix typos. + +2010-03-26 17:00:45 +0000 gb + + * tests/image.c: + * tests/image.h: + * tests/test-windows.c: + Move code around. + +2010-03-26 16:52:07 +0000 gb + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapitexture.c: + * gst-libs/gst/vaapi/gstvaapitexture.h: + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + * gst-libs/gst/vaapi/gstvaapiutils_glx.h: + Add initial VA/GLX texture abstraction though the API is not good enough yet. + +2010-03-26 15:22:00 +0000 gb + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapiobject.h: + Add gst_vaapi_object_{,un}lock_display() helpers. + +2010-03-26 15:16:01 +0000 gb + + * tests/Makefile.am: + * tests/image.c: + * tests/image.h: + * tests/test-windows.c: + Factor out image utilities. + +2010-03-26 11:54:43 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + MT-Safe: lock display. + +2010-03-26 11:50:31 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + Make sure window resize completed prior to resizing the GL viewport. + +2010-03-26 11:39:20 +0000 gb + + * gst-libs/gst/vaapi/Makefile.am: + gstvaapicompat.h is a private header, don't install it. + +2010-03-26 11:35:20 +0000 gb + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + Add gst_vaapi_display_{sync,flush}() helpers. + +2010-03-26 11:30:54 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * sys/vaapisink/gstvaapisink.c: + * sys/vaapisink/gstvaapisink.h: + Add "synchronous" mode. + +2010-03-26 11:02:12 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + Only add _display suffix to open & close members because they could be #define to some arbitrary value. lock/unlock are safe names. + +2010-03-26 10:09:23 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + Restore GLX context only if there is one. + +2010-03-26 09:41:12 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + * gst-libs/gst/vaapi/gstvaapiutils_glx.h: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.h: + Add gst_vaapi_window_glx_make_current(). Handle X11 window size changes and reset the GL viewport. + +2010-03-26 08:35:24 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiwindow.c: + Check GstVaapiWindow::render() is available prior to calling it. + +2010-03-26 08:10:23 +0000 gb + + * tests/Makefile.am: + * tests/test-display.c: + * tests/test-textures.c: + Add VA/GLX display tests. + +2010-03-26 08:00:32 +0000 gb + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + Fix compile flags. + +2010-03-25 17:39:06 +0000 gb + + * docs/reference/libs/Makefile.am: + * docs/reference/libs/libs-docs.xml.in: + * docs/reference/libs/libs-sections.txt: + * docs/reference/libs/libs.types: + Add missing API documentation. + +2010-03-25 17:28:49 +0000 gb + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.c: + * gst-libs/gst/vaapi/gstvaapidisplay_glx.h: + * gst-libs/gst/vaapi/gstvaapiutils_glx.c: + * gst-libs/gst/vaapi/gstvaapiutils_glx.h: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.c: + * gst-libs/gst/vaapi/gstvaapiwindow_glx.h: + * pkgconfig/Makefile.am: + * pkgconfig/gstreamer-vaapi-glx.pc.in: + * tests/Makefile.am: + * tests/test-textures.c: + Add initial VA/GLX support. + +2010-03-25 17:21:56 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + Add missing includes (for vaapi_check_status()). + +2010-03-25 17:21:13 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidebug.h: + Only enable GST_DEBUG() if DEBUG is defined. Drop old D(bug()) stuff. + +2010-03-25 17:18:36 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.h: + Add gst_vaapi_window_x11_is_foreign_xid() helper. + +2010-03-25 17:18:06 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiutils_x11.c: + * gst-libs/gst/vaapi/gstvaapiutils_x11.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.h: + Allow derived classes to specify custom Visual and Colormap. + +2010-03-25 13:54:06 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiutils_x11.c: + * gst-libs/gst/vaapi/gstvaapiutils_x11.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + Allow window creation with a specific visual (e.g. for GLX support). + +2010-03-25 13:21:19 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiimage.c: + Fix return value on error (though it's the same in the end). + +2010-03-25 12:39:54 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + Simplify initialization of VADisplay. + +2010-03-25 10:04:39 +0000 gb + + * configure.ac: + Move __attribute__((visibility("hidden"))) check down. + +2010-03-25 09:49:17 +0000 gb + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.h: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * tests/test-surfaces.c: + Restore the gst_vaapi_{surface,image,subpicture}_get_id() interfaces. + +2010-03-25 09:39:17 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + Use the parent display object, no need to maintain another one. + In the end, libgstvaapi-x11 reduced by 1 KB in .text vs. 0.1.1. + +2010-03-25 09:37:40 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiobject_priv.h: + Add more internal helpers. + +2010-03-24 17:40:19 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiobject_priv.h: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + Rename to GST_VAAPI_OBJECT_DISPLAY(). + +2010-03-24 17:38:23 +0000 gb + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapiparamspecs.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapitypes.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + All GstVaapiID are initialized to GST_VAAPI_ID_NONE by default. Besides, all GstVaapiObject derived class shall initialize "id" to a valid value. + +2010-03-24 17:22:18 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + Make GstVaapiWindow* derive from GstVaapiObject. + +2010-03-24 16:37:35 +0000 gb + + * configure.ac: + Factor out use gstreamer-vaapi (PACKAGE name). + +2010-03-24 16:35:36 +0000 gb + + * configure.ac: + Improve versioning summary. + +2010-03-24 16:27:36 +0000 gb + + * gst-libs/gst/vaapi/Makefile.am: + gstvaapicompat.h is now a private header (not installed). + +2010-03-24 16:25:56 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimageformat.c: + * gst-libs/gst/vaapi/gstvaapiimageformat.h: + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + Include gstvaapicompat.h in source files only, not headers. + +2010-03-24 16:21:20 +0000 gb + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + * sys/vaapiconvert/Makefile.am: + * sys/vaapisink/Makefile.am: + * tests/Makefile.am: + Drop tedious LIBVA_EXTRA_{CFLAGS,LIBS} definitions in Makefile.am. Override CFLAGS & LIBS instead. + +2010-03-24 16:17:49 +0000 gb + + * NEWS: + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapicompat.h: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.h: + * gst-libs/gst/vaapi/gstvaapiimageformat.h: + * gst-libs/gst/vaapi/gstvaapiparamspecs.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + * pkgconfig/gstreamer-vaapi-x11.pc.in: + * pkgconfig/gstreamer-vaapi.pc.in: + * sys/vaapiconvert/Makefile.am: + * sys/vaapisink/Makefile.am: + * tests/Makefile.am: + Add compatibility with the original VA-API 0.29. + +2010-03-24 15:18:33 +0000 gb + + * gst-libs/gst/vaapi/gstvaapivalue.h: + Add missing file (gstvaapivalue.h). + +2010-03-24 15:12:56 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + Fix g_warning() invocation. + +2010-03-24 15:11:26 +0000 gb + + * gst-libs/gst/vaapi/gstvaapisurface.c: + Deassociate subpictures while destroying the surface. + +2010-03-24 14:57:33 +0000 gb + + * gst-libs/gst/vaapi/gstvaapisurface.c: + Fix destruction order of subpictures. They should be destroyed first. + +2010-03-24 14:46:33 +0000 gb + + * NEWS: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimageformat.c: + * gst-libs/gst/vaapi/gstvaapiimageformat.h: + * tests/test-windows.c: + Add support for AYUV format. + +2010-03-24 14:36:39 +0000 gb + + * tests/test-windows.c: + Simplify upload process and fallback to subpictures. + +2010-03-24 13:44:01 +0000 gb + + * docs/reference/libs/libs-docs.xml.in: + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapiparamspecs.c: + Fix documentation. + +2010-03-24 13:37:38 +0000 gb + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapiparamspecs.c: + * gst-libs/gst/vaapi/gstvaapitypes.h: + * gst-libs/gst/vaapi/gstvaapivalue.c: + Move GValue specific stuff to a dedicated file. + +2010-03-24 13:22:25 +0000 gb + + * tests/test-surfaces.c: + Cosmetics (lowercase for consistency). + +2010-03-24 13:21:54 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiobject.c: + Cosmetics (vertical alignment). + +2010-03-24 13:20:34 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiobject.c: + Fix return value on error. + +2010-03-24 13:19:58 +0000 gb + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapiobject.h: + * gst-libs/gst/vaapi/gstvaapiobject_priv.h: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.h: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * tests/test-surfaces.c: + Move "id" down to the GstVaapiObject base. + +2010-03-24 12:59:22 +0000 gb + + * gst-libs/gst/vaapi/gstvaapitypes.c: + Cosmetics (drop extraneous empty line). + +2010-03-24 12:57:54 +0000 gb + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiparamspecs.c: + * gst-libs/gst/vaapi/gstvaapiparamspecs.h: + Add GParamSpecs for GstVaapiID. + +2010-03-24 12:54:52 +0000 gb + + * docs/reference/libs/libs.types: + Drop gst_vaapi_id_get_type(). + +2010-03-24 12:38:40 +0000 gb + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapitypes.h: + Add GST_VAAPI_ID_FORMAT() and GST_VAAPI_ID_ARGS() helpers. + +2010-03-24 09:52:43 +0000 gb + + * docs/reference/libs/libs-sections.txt: + * docs/reference/libs/libs.types: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapitypes.c: + * gst-libs/gst/vaapi/gstvaapitypes.h: + Add GstVaapiID abstraction. + +2010-03-24 09:22:00 +0000 gb + + * docs/reference/libs/libs.types: + Sort types. + +2010-03-24 08:35:27 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + Drop useless include (). + +2010-03-24 08:34:11 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiobject_priv.h: + Optimize GST_VAAPI_OBJECT_GET_DISPLAY to avoid a run-time check. + +2010-03-24 08:32:12 +0000 gb + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapiobject.h: + * gst-libs/gst/vaapi/gstvaapiobject_priv.h: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + Move private definitions and accessors to gstvaapiobject_priv.h. + +2010-03-24 08:16:32 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimageformat.c: + * gst-libs/gst/vaapi/gstvaapiimagepool.c: + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + * gst-libs/gst/vaapi/gstvaapivideopool.c: + * gst-libs/gst/vaapi/gstvaapivideosink.c: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + Fix short descriptions. + +2010-03-23 18:45:09 +0000 gb + + * Makefile.am: + * configure.ac: + * debian.upstream/Makefile.am: + * debian.upstream/changelog.in: + * debian.upstream/compat: + * debian.upstream/control.in: + * debian.upstream/copyright: + * debian.upstream/gstreamer-vaapi-doc.install.in: + * debian.upstream/gstreamer-vaapi.install.in: + * debian.upstream/libgstvaapi-dev.install.in: + * debian.upstream/libgstvaapi-x11.install.in: + * debian.upstream/libgstvaapi.install.in: + * debian.upstream/rules: + Generate upstream packages through make deb.upstream. + +2010-03-23 17:40:03 +0000 gb + + * configure.ac: + Bump version for development. + +2010-03-23 17:29:47 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiutils_x11.c: + Use a black background for new windows. + +2010-03-23 17:18:35 +0000 gb + + * NEWS: + 0.1.1. + +2010-03-23 17:12:40 +0000 gb + + * configure.ac: + * docs/reference/libs/libs.types: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapimarshal.list: + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapiobject.h: + * tests/test-surfaces.c: + Add "destroy" signal. + +2010-03-23 16:25:20 +0000 gb + + * docs/reference/libs/libs-docs.xml.in: + Improve gst-plugins-vaapi Library reference template. + +2010-03-23 16:21:28 +0000 gb + + * docs/reference/libs/libs-docs.xml.in: + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst-libs/gst/vaapi/gstvaapiobject.c: + * gst-libs/gst/vaapi/gstvaapiobject.h: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.h: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + Make GstVaapi{Surface,Image,Subpicture} derive from a GstVaapiObject. + +2010-03-23 16:11:21 +0000 gb + + * sys/vaapisink/gstvaapisink.c: + Fix return value. + +2010-03-23 15:34:51 +0000 gb + + * sys/vaapisink/gstvaapisink.c: + Make sure VA display is valid when created with an explicit "display" name. + +2010-03-23 15:28:50 +0000 gb + + * sys/vaapisink/gstvaapisink.c: + Use plain "display" property for the X11 display name. + +2010-03-23 15:22:47 +0000 gb + + * sys/vaapiconvert/gstvaapiconvert.c: + * sys/vaapisink/gstvaapisink.c: + Document vaapiconvert & vaapisink plugins. + +2010-03-23 14:19:21 +0000 gb + + * configure.ac: + * docs/reference/Makefile.am: + * docs/reference/plugins/Makefile.am: + * docs/reference/plugins/plugins-docs.xml.in: + * docs/reference/plugins/plugins-overrides.txt: + * docs/reference/plugins/plugins-sections.txt: + * docs/reference/plugins/plugins.types: + Add plugins documentation template. + +2010-03-23 14:06:42 +0000 gb + + * sys/vaapisink/gstvaapisink.c: + * sys/vaapisink/gstvaapisink.h: + Don't export gst_vaapisink_get_display(). + +2010-03-23 13:32:36 +0000 gb + + * configure.ac: + * docs/reference/libs/libs-docs.xml.in: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + Drop introspection annotations since they require gtk-doc >= 1.12. + +2010-03-23 10:51:35 +0000 gb + + * gst-libs/gst/vaapi/gstvaapisurface.c: + Add note about the fact that the surface holds an extra reference to the subpicture. + +2010-03-23 10:49:33 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + Improve debugging messages. + +2010-03-23 10:48:58 +0000 gb + + * tests/test-windows.c: + Unref subpicture earlier as the surface is supposed to hold a reference to it. + +2010-03-23 10:36:20 +0000 gb + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * tests/test-windows.c: + Add gst_vaapi_surface_{,de}associate_subpicture() API. + +2010-03-23 08:13:37 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + Wait for MapNotify or UnmapNotify events on foreign windows too. + +2010-03-23 07:42:05 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + Check whether the foreign XID is mapped at binding time. + +2010-03-23 07:34:15 +0000 gb + + * sys/vaapisink/gstvaapisink.c: + Add missing includes. + +2010-03-23 07:31:04 +0000 gb + + * configure.ac: + * debian/Makefile.am: + * debian/control.in: + * debian/gstreamer-vaapi-doc.install.in: + * debian/rules: + Add -doc package. + +2010-03-23 06:41:29 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + Fix warnings (drop extraneous var). + +2010-03-23 06:40:27 +0000 gb + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.h: + Add GST_VAAPI_WINDOW_XWINDOW() helper macro. + +2010-03-22 16:59:29 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiwindow.c: + Shorten condition. + +2010-03-22 16:57:20 +0000 gb + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_priv.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + Try to improve switch to fullscreen mode. + +2010-03-22 16:01:34 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiutils_x11.c: + * gst-libs/gst/vaapi/gstvaapiutils_x11.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + Improve display locking and rework X event wait functions. + +2010-03-22 13:06:41 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow_priv.h: + Move _GstVaapiWindowPrivate declaration to gstvaapiwindow_priv.h. + +2010-03-22 13:05:05 +0000 gb + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow_priv.h: + Add private API to set window size & fullscreen modes without triggering any notification or virtual functions. This is useful for derived class to fix up sizes whenever appropriate. + +2010-03-22 12:47:13 +0000 gb + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + Add gst_vaapi_window_get_fullscreen() helper and "fullscreen" property. + +2010-03-22 12:39:02 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + Add gst_vaapi_window_get_display() to base. + +2010-03-22 12:16:47 +0000 gb + + * docs/reference/libs/libs-docs.xml.in: + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapitypes.h: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * sys/vaapisink/gstvaapisink.c: + * sys/vaapisink/gstvaapisink.h: + Add GstVaapiPoint & GstVaapiRectangle data structures. + +2010-03-22 12:05:11 +0000 gb + + * NEWS: + 0.1.1. + +2010-03-22 12:03:26 +0000 gb + + * NEWS: + * sys/vaapisink/gstvaapisink.c: + * sys/vaapisink/gstvaapisink.h: + Allow `vaapisink` to render videos in fullscreen mode. + +2010-03-22 10:51:49 +0000 gb + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + Add gst_vaapi_window_set_fullscreen() API. + +2010-03-22 10:03:24 +0000 gb + + * sys/vaapisink/gstvaapisink.c: + Size window so that to respect the video and pixel aspect ratio. + +2010-03-22 09:32:01 +0000 gb + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * tests/test-display.c: + Add gst_vaapi_display_get_pixel_aspect_ratio(). + +2010-03-22 08:45:03 +0000 gb + + * docs/reference/libs/libs-sections.txt: + Updates. + +2010-03-22 08:44:38 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * tests/test-display.c: + Add display size accessors. + +2010-03-22 08:03:12 +0000 gb + + * configure.ac: + * debian/control.in: + Build-Requires: gstreamer-plugins-base >= 0.10.16. + +2010-03-21 08:45:09 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.h: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst-libs/gst/vaapi/gstvaapiimagepool.h: + * gst-libs/gst/vaapi/gstvaapisubpicture.h: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapisurfacepool.h: + * gst-libs/gst/vaapi/gstvaapivideobuffer.h: + * gst-libs/gst/vaapi/gstvaapivideopool.h: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.h: + Fix documentation of *Class'es. + +2010-03-21 08:38:17 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + Move GstVaapiSurfaceRenderFlags conversion to get_PutSurface_flags_from_GstVaapiSurfaceRenderFlags(). + +2010-03-21 08:22:46 +0000 gb + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + Move GstVaapiSurfaceRenderFlags to gstvaapisurface.h since this will also be useful for e.g. a gstvaapitexture.h. + +2010-03-21 08:12:52 +0000 gb + + * docs/reference/libs/libs-sections.txt: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * sys/vaapisink/gstvaapisink.c: + * tests/test-windows.c: + Rename gst_vaapi_window_put_surface_full() to plain gst_vaapi_window_put_surface(). + +2010-03-19 17:15:16 +0000 gb + + * docs/reference/libs/Makefile.am: + Fix make dist for --enable-gtk-doc builds. + +2010-03-19 17:13:59 +0000 gb + + * autogen.sh: + Improve autogen.sh. + +2010-03-19 17:11:20 +0000 gb + + * Makefile.am: + * autogen.sh: + Generate gtk-doc.make from gtkdocize. + +2010-03-19 17:04:51 +0000 gb + + * Makefile.am: + * NEWS: + * configure.ac: + * docs/Makefile.am: + * docs/reference/Makefile.am: + * docs/reference/libs/Makefile.am: + * docs/reference/libs/libs-docs.xml.in: + * docs/reference/libs/libs-overrides.txt: + * docs/reference/libs/libs-sections.txt: + * docs/reference/libs/libs.types: + Document public API for libgstvaapi-*.so.*. + +2010-03-19 16:41:52 +0000 gb + + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer.h: + Document GstVaapiVideoBuffer. + +2010-03-19 16:08:48 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiimagepool.c: + * gst-libs/gst/vaapi/gstvaapiimagepool.h: + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.h: + * gst-libs/gst/vaapi/gstvaapivideopool.c: + * gst-libs/gst/vaapi/gstvaapivideopool.h: + Document surface & image pools. Drop obsolete gst_vaapi_video_pool_new() function. + +2010-03-19 15:45:21 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.h: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst-libs/gst/vaapi/gstvaapiimageformat.c: + * gst-libs/gst/vaapi/gstvaapiimageformat.h: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.h: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + * gst-libs/gst/vaapi/gstvaapivideosink.c: + * gst-libs/gst/vaapi/gstvaapivideosink.h: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.h: + Add tedious documentation. + +2010-03-19 10:42:11 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + Beautify append_formats(). + +2010-03-19 10:38:45 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + Simplify GstVaapiDisplay (use GArray). + +2010-03-19 08:42:51 +0000 gb + + * NEWS: + * sys/vaapiconvert/gstvaapiconvert.c: + * sys/vaapiconvert/gstvaapiconvert.h: + Factor out direct-rendering infrastructure. + +2010-03-18 16:18:17 +0000 gb + + * sys/vaapiconvert/gstvaapiconvert.c: + * sys/vaapiconvert/gstvaapiconvert.h: + Allow user to specify inout-buffers & derive-image optimizations. + +2010-03-18 15:58:28 +0000 gb + + * sys/vaapiconvert/gstvaapiconvert.c: + Reduce number of debug messaged printed out. + +2010-03-18 15:53:50 +0000 gb + + * sys/vaapiconvert/gstvaapiconvert.c: + * sys/vaapiconvert/gstvaapiconvert.h: + Add vaDeriveImage() optimization. + +2010-03-18 15:52:20 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiimage.c: + Fix gst_vaapi_image_create() from a foreign VA image. + +2010-03-18 15:28:59 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + Add gst_vaapi_surface_derive_image() API. + +2010-03-18 13:49:50 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + Make it possible to bin an X11 window to GstVaapiWindowX11 with plain g_object_new() and "xid" property. i.e. get foreign window size in gst_vaapi_window_x11_create(). + +2010-03-18 13:08:17 +0000 gb + + * tests/test-windows.c: + Try YV12 & I420 image formats too. + +2010-03-18 12:59:55 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiimage.c: + Split map/unmap functions into internal functions that don't check preconditions. + +2010-03-18 12:56:53 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiimage.c: + Improve gst_vaapi_image_new() sanity checks. + +2010-03-18 12:52:58 +0000 gb + + * tests/test-windows.c: + Fix typo. + +2010-03-18 08:45:57 +0000 gb + + * sys/vaapiconvert/gstvaapiconvert.c: + Check if our inout buffer is still alive or default to a separate output buffer. + +2010-03-18 08:16:59 +0000 gb + + * sys/vaapiconvert/gstvaapiconvert.c: + * sys/vaapiconvert/gstvaapiconvert.h: + Factor out buffers negotiation and optimization checks. + +2010-03-18 08:02:25 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiutils_x11.c: + * gst-libs/gst/vaapi/gstvaapiutils_x11.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * sys/vaapiconvert/gstvaapiconvert.h: + Use gtypes. + +2010-03-17 10:43:02 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiimage.c: + Optimize gst_vaapi_image_is_linear() and simplify gst_vaapi_image_update_from_buffer(). + +2010-03-17 07:59:31 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + Add VA display locking utilities. + +2010-03-17 07:20:19 +0000 gb + + * sys/vaapisink/gstvaapisink.c: + Initialize the X window in a ::set_caps() handler. Also fix build with GStreamer < 0.10.25. i.e. use preroll/render hooks. + +2010-03-17 07:17:17 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * tests/test-windows.c: + Don't show window by default during creation. + +2010-03-17 06:49:27 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + Fix gst_vaapi_window_x11_destroy(). + +2010-03-16 17:57:57 +0000 gb + + * sys/vaapiconvert/gstvaapiconvert.c: + * sys/vaapiconvert/gstvaapiconvert.h: + Alias sink & src pad buffers whenever possible. + +2010-03-16 17:57:23 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + Extend GstVaapiImage API with *_get_image(), *_is_linear(), *_get_data_size(). + +2010-03-16 17:10:02 +0000 gb + + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer.h: + Make GstVaapiVideoBuffer handle two pools. i.e. both image & surface at the same time. + +2010-03-16 14:37:47 +0000 gb + + * sys/vaapiconvert/gstvaapiconvert.c: + Fix image & surface size cache. + +2010-03-16 14:12:40 +0000 gb + + * configure.ac: + Move gstreamer-vaapi package versioning to the top. + +2010-03-16 14:11:46 +0000 gb + + * configure.ac: + Bump version for development. + +2010-03-16 14:07:53 +0000 gb + + * configure.ac: + Cosmetics (shorten lines). + +2010-03-16 13:58:43 +0000 gb + + * NEWS: + * README: + Update docs. + +2010-03-16 13:53:54 +0000 gb + + * debian/Makefile.am: + * debian/changelog.in: + * debian/compat: + * debian/control.in: + * debian/copyright: + * debian/gstreamer-vaapi.install.in: + * debian/libgstvaapi-dev.install.in: + * debian/libgstvaapi-x11.install.in: + * debian/libgstvaapi.install.in: + * debian/rules: + Add debian packaging. + +2010-03-16 13:53:09 +0000 gb + + * Makefile.am: + * configure.ac: + Add debian packaging. + +2010-03-16 10:13:36 +0000 gb + + * pkgconfig/Makefile.am: + Silence GNU make extensions warning. + +2010-03-16 09:59:03 +0000 gb + + * configure.ac: + Add AM_PROG_CC_C_O, thus fixing this warning: tests/Makefile.am:16: compiling `test-display.c' with per-target flags requires `AM_PROG_CC_C_O' in `configure.ac' + +2010-03-16 09:57:25 +0000 gb + + * Makefile.am: + * configure.ac: + * pkgconfig/Makefile.am: + * pkgconfig/gstreamer-vaapi-x11.pc.in: + * pkgconfig/gstreamer-vaapi.pc.in: + Add pkgconfig files. + +2010-03-16 09:39:07 +0000 gb + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + * sys/vaapisink/Makefile.am: + * tests/Makefile.am: + Split X11 support to libgstvaapi-x11-*.so.* + +2010-03-16 09:21:15 +0000 gb + + * gst-libs/gst/vaapi/Makefile.am: + Don't install private headers. + +2010-03-16 09:18:57 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidebug.h: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + Fix header guards. + +2010-03-16 09:17:41 +0000 gb + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidebug.h: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimagepool.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + * gst-libs/gst/vaapi/gstvaapivideopool.c: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + Rename vaapi_debug.h to gstvaapidebug.h. + +2010-03-16 09:15:48 +0000 gb + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapiutils.c: + * gst-libs/gst/vaapi/gstvaapiutils.h: + * gst-libs/gst/vaapi/vaapi_debug.h: + Move vaapi_utils.* to gstvaapiutils.* + +2010-03-16 09:13:16 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiutils_x11.h: + Cosmetics (remove an extra line). + +2010-03-16 09:12:47 +0000 gb + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiutils_x11.c: + * gst-libs/gst/vaapi/gstvaapiutils_x11.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + Move X11 utilties to gstvaapiutils_x11.[ch]. + +2010-03-16 09:03:10 +0000 gb + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapivideosink.c: + * gst-libs/gst/vaapi/gstvaapivideosink.h: + * sys/vaapiconvert/gstvaapiconvert.c: + * sys/vaapisink/gstvaapisink.c: + Rename GstVaapiSinkBase to GstVaapiVideoSink. + +2010-03-16 08:49:16 +0000 gb + + * configure.ac: + * tests/Makefile.am: + * tests/examples/Makefile.am: + * tests/examples/generic/Makefile.am: + * tests/test-display.c: + * tests/test-surfaces.c: + * tests/test-windows.c: + Move tests to top-level tests/ directory. + +2010-03-16 08:43:16 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * sys/vaapiconvert/gstvaapiconvert.c: + * sys/vaapiconvert/gstvaapiconvert.h: + Handle I420 formats internally in GstVaapiImage. + +2010-03-15 17:44:35 +0000 gb + + * sys/vaapiconvert/gstvaapiconvert.c: + * sys/vaapiconvert/gstvaapiconvert.h: + Implement I420 (resp. YV12) with YV12 (resp. I420) if the driver does not. + +2010-03-15 17:43:29 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiimage.c: + Implement I420 and YV12 if the underlying implementation does not. + +2010-03-15 17:10:56 +0000 gb + + * sys/vaapiconvert/Makefile.am: + * sys/vaapiconvert/gstvaapiconvert.c: + * sys/vaapiconvert/gstvaapiconvert.h: + Add initial vaapiconvert plugin. + +2010-03-15 17:09:12 +0000 gb + + * sys/vaapisink/gstvaapisink.c: + * sys/vaapisink/gstvaapisink.h: + Display frames. + +2010-03-15 16:57:37 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + Factor out. + +2010-03-15 16:57:01 +0000 gb + + * tests/examples/generic/test-windows.c: + Generate R/G/B rects. + +2010-03-15 16:13:51 +0000 gb + + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + Add gst_vaapi_surface_sync(). + +2010-03-15 16:13:37 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiimage.c: + Cosmetics (reverse args order). + +2010-03-15 15:55:20 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst-libs/gst/vaapi/gstvaapisurface.c: + Cosmetics. + +2010-03-15 15:12:27 +0000 gb + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiwindow.c: + * gst-libs/gst/vaapi/gstvaapiwindow.h: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.c: + * gst-libs/gst/vaapi/gstvaapiwindow_x11.h: + * tests/examples/generic/Makefile.am: + * tests/examples/generic/test-windows.c: + Add VA/X11 window abstraction. + +2010-03-15 14:57:57 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.h: + Add VA and X11 display accessors. + +2010-03-15 14:57:30 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiimage.c: + Fix preconditions. + +2010-03-15 13:32:37 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + Cosmetics. + +2010-03-15 11:49:03 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + Add gst_vaapi_{get,put}_image() API. + +2010-03-15 10:27:10 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + Add gst_vaapi_image_update_from_buffer() helper. + +2010-03-12 23:53:48 +0000 gb + + * sys/vaapisink/Makefile.am: + * sys/vaapisink/gstvaapisink.c: + * sys/vaapisink/gstvaapisink.h: + Implement GstVaapiSinkBase interface and integrate with GST_DEBUG better. + +2010-03-12 23:50:09 +0000 gb + + * tests/examples/generic/Makefile.am: + * tests/examples/generic/test-surfaces.c: + Add surface tests. + +2010-03-12 23:48:50 +0000 gb + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapivideobuffer.c: + * gst-libs/gst/vaapi/gstvaapivideobuffer.h: + Add basic GstVaapiVideoBuffer. + +2010-03-12 23:47:47 +0000 gb + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiimagepool.c: + * gst-libs/gst/vaapi/gstvaapiimagepool.h: + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.h: + * gst-libs/gst/vaapi/gstvaapivideopool.c: + * gst-libs/gst/vaapi/gstvaapivideopool.h: + Add GstVaapiImagePool and factor out GstVaapiSurfacePool from a base GstVaapiVideoPool. + +2010-03-12 22:32:35 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiimageformat.c: + Simplify format conversion code. + +2010-03-12 22:28:01 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiimageformat.c: + * gst-libs/gst/vaapi/gstvaapiimageformat.h: + Add gst_vaapi_image_format_from_caps() helper. + +2010-03-12 17:45:18 +0000 gb + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapisurfacepool.c: + * gst-libs/gst/vaapi/gstvaapisurfacepool.h: + Add VA surface pool (lazy allocator). + +2010-03-12 17:39:11 +0000 gb + + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + Add gst_vaapi_surface_get_size() helper. + +2010-03-12 10:52:08 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiimageformat.c: + Avoid use of GstStaticCaps since older gstreamer versions (0.10.22) write to it. + +2010-03-11 15:35:43 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + Reset display-name if the user provided his own X11 display. + +2010-03-11 15:21:43 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.h: + * tests/examples/generic/test-display.c: + Add gst_vaapi_display_x11_new_with_display() API. + +2010-03-11 15:04:18 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay_x11.h: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst-libs/gst/vaapi/gstvaapisubpicture.h: + * gst-libs/gst/vaapi/gstvaapisurface.h: + Fix *_GET_CLASS() definitions... + +2010-03-11 15:01:00 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.h: + * tests/examples/generic/test-display.c: + API change: gst_vaapi_display_x11_new() now takes an X11 display name. + +2010-03-11 13:58:32 +0000 gb + + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + Use GstVaapiChromaType abstraction. + +2010-03-11 12:30:12 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + New refcounting policy. All getters return a reference, not a copy. So the user shall reference the object itself, should he wish so. + +2010-03-11 12:14:10 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiimageformat.c: + Don't warn on failure, just return an appropriate error or value. + +2010-03-11 12:11:36 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapiimageformat.c: + * gst-libs/gst/vaapi/gstvaapiimageformat.h: + Filter out any format that is not supported by the library (libgstvaapi). Also sort the formats by HW preference. + +2010-03-11 10:50:27 +0000 gb + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapisinkbase.c: + * gst-libs/gst/vaapi/gstvaapisinkbase.h: + Add helper interface that all VA-API sinks must implement. e.g. vaapisink. + +2010-03-10 13:13:51 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/vaapi_debug.h: + Use GST_DEBUG. + +2010-03-10 13:10:59 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + Fix GstVaapiImage and GstVaapiSubpicture initialization. + +2010-03-10 13:02:45 +0000 gb + + * gst-libs/gst/vaapi/gstvaapisurface.c: + Fix GstVaapiSurface initialization, override constructed() method, not constructor(). GObject C is awful... + +2010-03-10 12:25:38 +0000 gb + + * tests/examples/generic/test-display.c: + Dump caps. + +2010-03-10 12:25:19 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + Fix GstVaapiDisplay initialization. + +2010-03-10 10:43:31 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + Get VA image & subpicture formats as GstCaps. + +2010-03-10 10:41:12 +0000 gb + + * gst-libs/gst/vaapi/gstvaapiimageformat.c: + * gst-libs/gst/vaapi/gstvaapiimageformat.h: + Add helper to convert from GstVaapiImageFormat to GstCaps. + +2010-03-09 12:00:32 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapisurface.c: + Cosmetics (drop unused variables). + +2010-03-05 17:11:52 +0000 gb + + * configure.ac: + * sys/vaapiconvert/Makefile.am: + * sys/vaapiconvert/gstvaapiconvert.c: + * sys/vaapiconvert/gstvaapiconvert.h: + * sys/vaapisink/Makefile.am: + * sys/vaapisink/gstvaapisink.c: + * sys/vaapisink/gstvaapisink.h: + Add boilerplate for vaapiconvert and vaapisink elements. + +2010-03-05 15:29:04 +0000 gb + + * configure.ac: + * sys/Makefile.am: + * sys/vaapiconvert/Makefile.am: + Add vaapiconvert element hierarchy. + +2010-03-05 15:26:36 +0000 gb + + * sys/vaapisink/Makefile.am: + Rename to vaapisink. + +2010-03-05 10:07:22 +0000 gb + + * gst-libs/gst/vaapi/gstvaapisurface.c: + Shorter code (and more correct). + +2010-03-05 10:04:55 +0000 gb + + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + Add helper to get GstVaapiDisplay from a surface. + +2010-03-05 08:52:20 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + Fix subpicture formats list length. + +2010-03-04 17:41:34 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + Add utilities to check whether a VA-API driver supports specific image or subpicture format. Likewise for VA profile. + +2010-03-04 17:40:47 +0000 gb + + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.h: + Cosmetics (more checks, includes). + +2010-03-04 17:39:58 +0000 gb + + * gst-libs/gst/vaapi/gstvaapisubpicture.c: + * gst-libs/gst/vaapi/gstvaapisubpicture.h: + Really add VA subpicture abstraction. + +2010-03-04 17:39:01 +0000 gb + + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapiimage.c: + * gst-libs/gst/vaapi/gstvaapiimage.h: + * gst-libs/gst/vaapi/gstvaapiimageformat.c: + * gst-libs/gst/vaapi/gstvaapiimageformat.h: + * gst-libs/gst/vaapi/gstvaapisurface.c: + * gst-libs/gst/vaapi/gstvaapisurface.h: + Add VA surface, image, subpicture abstractions. Ported over from Gnash. + +2010-01-25 16:15:01 +0000 gb + + * configure.ac: + * gst-libs/gst/vaapi/Makefile.am: + * gst-libs/gst/vaapi/gstvaapidisplay.c: + * gst-libs/gst/vaapi/gstvaapidisplay.h: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.c: + * gst-libs/gst/vaapi/gstvaapidisplay_x11.h: + * gst-libs/gst/vaapi/vaapi_debug.h: + * gst-libs/gst/vaapi/vaapi_utils.c: + * gst-libs/gst/vaapi/vaapi_utils.h: + * tests/examples/generic/Makefile.am: + * tests/examples/generic/test-display.c: + Add initial VA display abstraction. + +2010-01-25 15:04:10 +0000 gb + + * Makefile.am: + * configure.ac: + * tests/Makefile.am: + * tests/examples/Makefile.am: + * tests/examples/generic/Makefile.am: + Add tests infrastructure. + +2010-01-25 14:59:37 +0000 gb + + * configure.ac: + Clean up VA-API checks. + +2010-01-25 13:49:55 +0000 gb + + * configure.ac: + Check for __attribute__((visibility("hidden"))). + diff --git a/NEWS b/NEWS new file mode 100644 index 0000000000..0e581c39b8 --- /dev/null +++ b/NEWS @@ -0,0 +1,299 @@ +GStreamer 1.20 Release Notes + +GStreamer 1.20 has not been released yet. It is scheduled for release +around October/November 2021. + +1.19.x is the unstable development version that is being developed in +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 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. + +See https://gstreamer.freedesktop.org/releases/1.20/ for the latest +version of this document. + +Last updated: Wednesday 22 September 2021, 18:00 UTC (log) + +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 many new features, bug +fixes and other improvements. + +Highlights + +- this section will be completed in due course + +Major new features and changes + +Noteworthy new features and API + +- this section will be filled in in due course + +New elements + +- this section will be filled in in due course + +New element features and additions + +- this section will be filled in in due course + +Plugin and library moves + +- this section will be filled in in due course + +- There were no plugin moves or library moves in this cycle. + +Plugin removals + +The following elements or plugins have been removed: + +- this section will be filled in in due course + +Miscellaneous API additions + +- this section will be filled in in due course + +Miscellaneous performance, latency and memory optimisations + +- this section will be filled in in due course + +Miscellaneous other changes and enhancements + +- this section will be filled in in due course + +Tracing framework and debugging improvements + +- this section will be filled in in due course + +Tools + +- this section will be filled in in due course + +GStreamer RTSP server + +- this section will be filled in in due course + +GStreamer VAAPI + +- this section will be filled in in due course + +GStreamer OMX + +- this section will be filled in in due course + +GStreamer Editing Services and NLE + +- this section will be filled in in due course + +GStreamer validate + +- this section will be filled in in due course + +GStreamer Python Bindings + +- this section will be filled in in due course + +GStreamer C# Bindings + +- 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 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. + +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 + 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 + +- this section will be filled in in due course + +gst-build + +- this section will be filled in in due course + +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. + +General improvements + +- this section will be filled in in due course + +macOS / iOS + +- this section will be filled in in due course + +Windows + +- this section will be filled in in due course + +Windows MSI installer + +- this section will be filled in in due course + +Linux + +- this section will be filled in in due course + +Android + +- this section will be filled in in due course + +Platform-specific changes and improvements + +Android + +- this section will be filled in in due course + +macOS and iOS + +- this section will be filled in in due course + +Windows + +- this section will be filled in in due course + +Linux + +- this section will be filled in in due course + +Documentation improvements + +- this section will be filled in in due course + +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 + +- 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 + +- 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.20 branch + +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.20.x bug-fix releases will be made from +the git 1.20 branch, which will be a stable branch. + +1.20.0 + +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 main branch. + +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. + +------------------------------------------------------------------------ + +These release notes have been prepared by Tim-Philipp Müller with +contributions from … + +License: CC BY-SA 4.0 diff --git a/README b/README new file mode 100644 index 0000000000..5cc959c132 --- /dev/null +++ b/README @@ -0,0 +1,133 @@ + + gstreamer-vaapi + VA-API support to GStreamer + + Copyright (C) 2010-2011 Splitted-Desktop Systems + Copyright (C) 2011-2020 Intel Corporation + Copyright (C) 2011 Collabora Ltd. + Copyright (C) 2015-2020 Igalia, S.L. + + +License +------- + +gstreamer-vaapi helper libraries and plugin elements are available +under the terms of the GNU Lesser General Public License v2.1+ + + +Overview +-------- + +gstreamer-vaapi consists in a collection of VA-API based plugins for +GStreamer and helper libraries. + + * `vaapidec' is used to decode JPEG, MPEG-2, MPEG-4:2, H.264 + AVC, H.264 MVC, VP8, VP9, VC-1, WMV3, HEVC videos to VA surfaces, + depending on the actual value of and the underlying + hardware capabilities. This plugin is also able to implicitly + download the decoded surface to raw YUV buffers. + + * `vaapienc' is used to encode into MPEG-2, H.264 AVC, H.264 + MVC, JPEG, VP8, VP9, HEVC videos, depending on the actual value of + (mpeg2, h264, etc.) and the hardware capabilities. By + default, raw format bitstreams are generated, so the result may be + piped to a muxer, e.g. qtmux for MP4 containers. + + * `vaapipostproc' is used to filter VA surfaces, for e.g. scaling, + deinterlacing (bob, motion-adaptive, motion-compensated), noise + reduction or sharpening. This plugin is also used to upload raw + YUV pixels into VA surfaces. + + * `vaapisink' is used to render VA surfaces to an X11 or Wayland + display. This plugin also features a "headless" mode (DRM) more + suited to remote transcode scenarios, with faster throughput. + + * `vaapioverlay` is a accelerated compositor that blends or + composite different video streams. + + +Features +-------- + + * VA-API support from 0.39 + * JPEG, MPEG-2, MPEG-4, H.264 AVC, H.264 MVC, VP8, VC-1, HEVC and + VP9 ad-hoc decoders + * MPEG-2, H.264 AVC,H.264 MVC, JPEG, VP8, VP9 and HEVC ad-hoc + encoders + * OpenGL rendering through VA/GLX or GLX texture-from-pixmap + FBO + * Support for EGL backend + * Support for the Wayland display server + * Support for headless decode pipelines with VA/DRM + * Support for major HW video decoding solutions on Linux (AMD, + Intel, NVIDIA) + * Support for HW video encoding on Intel HD Graphics hardware + * Support for VA Video Processing APIs (VA/VPP) + - Scaling and color conversion + - Image enhancement filters: Sharpening, Noise Reductio, Color + Balance, Skin-Tone-Enhancement + - Advanced deinterlacing: Motion-Adaptive, Motion-Compensated + + +Requirements +------------ + +Hardware requirements + + * Hardware supported by i965 driver or iHD, such as + - Intel Ironlake, Sandybridge, Ivybridge, Haswell, Broadwell, + Skylake, etc. (HD Graphics) + - Intel BayTrail, Braswell + - Intel Poulsbo (US15W) + - Intel Medfield or Cedar Trail + * Hardware supported by AMD Radeonsi driver, such as the list below + - AMD Carrizo, Bristol Ridge, Raven Ridge, Picasso, Renoir + - AMD Tonga, Fiji, Polaris XX, Vega XX, Navi 1X + * Other hardware supported by Mesa VA gallium state-tracker + + +Usage +----- + + VA elements are automatically plugged into GStreamer pipelines. So, + using playbin should work as is. + However, here are a few alternate pipelines that could be manually + constructed. + + * Play an H.264 video with an MP4 container in fullscreen mode + $ gst-launch-1.0 -v filesrc location=/path/to/video.mp4 ! \ + qtdemux ! vaapidecodebin ! vaapisink fullscreen=true + + * Play a raw MPEG-2 interlaced stream + $ gst-launch-1.0 -v filesrc location=/path/to/mpeg2.bits ! \ + mpegvideoparse ! vaapimpeg2dec ! vaapipostproc ! vaapisink + + * Convert from one pixel format to another, while also downscaling + $ gst-launch-1.0 -v filesrc location=/path/to/raw_video.yuv ! \ + videoparse format=yuy2 width=1280 height=720 ! \ + vaapipostproc format=nv12 height=480 ! vaapisink + + * Encode a 1080p stream in raw I420 format into H.264 + $ gst-launch-1.0 -v filesrc location=/path/to/raw_video.yuv ! \ + videoparse format=i420 width=1920 height=1080 framerate=30/1 ! \ + vaapih264enc rate-control=cbr tune=high-compression ! \ + qtmux ! filesink location=/path/to/encoded_video.mp4 + + +Sources +------- + + gstreamer-vaapi is Open Source software, so updates to this + framework are really easy to get. + + Stable source code releases can be found at: + + + GitLab repository for work-in-progress changes is available at: + + + +Reporting Bugs +-------------- + + Bugs can be reported in the GStreamer's GitLab system at: + diff --git a/RELEASE b/RELEASE new file mode 100644 index 0000000000..89a24e6fa7 --- /dev/null +++ b/RELEASE @@ -0,0 +1,96 @@ +This is GStreamer gstreamer-vaapi 1.19.2. + +GStreamer 1.19 is the development branch leading up to the next major +stable version which will be 1.20. + +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 will one day be found at: + + https://gstreamer.freedesktop.org/releases/1.20/ + +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. + + - 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 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://gitlab.freedesktop.org/gstreamer/ + +==== Homepage ==== + +The project's website is https://gstreamer.freedesktop.org/ + +==== Support and Bugs ==== + +We have recently moved from GNOME Bugzilla to GitLab on freedesktop.org +for bug reports and feature requests: + + 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). + +There is also a #gstreamer IRC channel on the Freenode IRC network. + +==== Developers ==== + +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: + + https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel diff --git a/docs/gst_plugins_cache.json b/docs/gst_plugins_cache.json new file mode 100644 index 0000000000..8dc00b2a81 --- /dev/null +++ b/docs/gst_plugins_cache.json @@ -0,0 +1,2018 @@ +{ + "vaapi": { + "description": "VA-API based elements", + "elements": { + "vaapidecodebin": { + "author": "Sreerenj Balachandran , Victor Jaquez ", + "description": "A VA-API based bin with a decoder and a postprocessor", + "hierarchy": [ + "GstVaapiDecodeBin", + "GstBin", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "interfaces": [ + "GstChildProxy" + ], + "klass": "Codec/Decoder/Video/Hardware", + "long-name": "VA-API Decode Bin", + "pad-templates": { + "sink": { + "caps": "video/mpeg:\n mpegversion: 2\n systemstream: false\nvideo/mpeg:\n mpegversion: 4\nvideo/x-divx:\nvideo/x-xvid:\nvideo/x-h263:\nvideo/x-h264:\nvideo/x-h265:\nvideo/x-wmv:\nvideo/x-vp8:\nvideo/x-vp9:\n", + "direction": "sink", + "presence": "always" + }, + "src": { + "caps": "video/x-raw(memory:VASurface):\n format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: progressive\n\nvideo/x-raw(meta:GstVideoGLTextureUploadMeta):\n format: { RGBA, BGRA }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: progressive\nvideo/x-raw:\n format: { AYUV64, ARGB64, GBRA_12LE, GBRA_12BE, Y412_LE, Y412_BE, A444_10LE, GBRA_10LE, A444_10BE, GBRA_10BE, A422_10LE, A422_10BE, A420_10LE, A420_10BE, RGB10A2_LE, BGR10A2_LE, Y410, GBRA, ABGR, VUYA, BGRA, AYUV, ARGB, RGBA, A420, Y444_16LE, Y444_16BE, v216, P016_LE, P016_BE, Y444_12LE, GBR_12LE, Y444_12BE, GBR_12BE, I422_12LE, I422_12BE, Y212_LE, Y212_BE, I420_12LE, I420_12BE, P012_LE, P012_BE, Y444_10LE, GBR_10LE, Y444_10BE, GBR_10BE, r210, I422_10LE, I422_10BE, NV16_10LE32, Y210, v210, UYVP, I420_10LE, I420_10BE, P010_10LE, NV12_10LE32, NV12_10LE40, P010_10BE, Y444, GBR, NV24, xBGR, BGRx, xRGB, RGBx, BGR, IYU2, v308, RGB, Y42B, NV61, NV16, VYUY, UYVY, YVYU, YUY2, I420, YV12, NV21, NV12, NV12_64Z32, Y41B, IYU1, YVU9, YUV9, RGB16, BGR16, RGB15, BGR15, RGB8P, GRAY16_LE, GRAY16_BE, GRAY10_LE32, GRAY8 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: progressive\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "deinterlace-method": { + "blurb": "Deinterlace method to use", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "none (0)", + "mutable": "null", + "readable": true, + "type": "GstVaapiDeinterlaceMethod", + "writable": true + }, + "disable-vpp": { + "blurb": "Disable Video Post Processing (No support for run time disabling)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "max-size-buffers": { + "blurb": "Max. number of buffers in the queue (0=disable)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "1", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "max-size-bytes": { + "blurb": "Max. amount of data in the queue (bytes, 0=disable)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "max-size-time": { + "blurb": "Max. amount of data in the queue (in ns, 0=disable)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "18446744073709551615", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint64", + "writable": true + } + }, + "rank": "primary + 2" + }, + "vaapih264dec": { + "author": "Gwenole Beauchesne , Halley Zhao , Sreerenj Balachandran , Wind Yuan ", + "description": "A VA-API based H264 video decoder", + "hierarchy": [ + "GstVaapiDecode_h264", + "GstVideoDecoder", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Decoder/Video/Hardware", + "long-name": "VA-API H264 decoder", + "pad-templates": { + "sink": { + "caps": "video/x-h264:\n", + "direction": "sink", + "presence": "always" + }, + "src": { + "caps": "video/x-raw(memory:VASurface):\n format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(meta:GstVideoGLTextureUploadMeta):\n format: { RGBA, BGRA }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(memory:DMABuf):\n format: { I420, YV12, RGBA }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "base-only": { + "blurb": "Drop any NAL unit not defined in Annex.A", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "low-latency": { + "blurb": "When enabled, frames will be pushed as soon as they are available. It might violate the H.264 spec.", + "conditionally-available": false, + "construct": true, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + } + }, + "rank": "primary" + }, + "vaapih264enc": { + "author": "Wind Yuan ", + "description": "A VA-API based H264 video encoder", + "hierarchy": [ + "GstVaapiEncodeH264", + "GstVaapiEncode", + "GstVideoEncoder", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "interfaces": [ + "GstPreset" + ], + "klass": "Codec/Encoder/Video/Hardware", + "long-name": "VA-API H264 encoder", + "pad-templates": { + "sink": { + "caps": "video/x-raw:\n format: { NV12, YV12, I420 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: progressive\n\nvideo/x-raw(memory:VASurface):\n format: { NV12, YV12, I420 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: progressive\n", + "direction": "sink", + "presence": "always" + }, + "src": { + "caps": "video/x-h264:\n stream-format: { (string)avc, (string)byte-stream }\n alignment: au\n profile: { (string)constrained-baseline, (string)baseline, (string)main, (string)high, (string)multiview-high, (string)stereo-high }\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "bitrate": { + "blurb": "The desired bitrate expressed in kbps (0: auto-calculate)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "2048000", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "cabac": { + "blurb": "Enable CABAC entropy coding mode", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "compliance-mode": { + "blurb": "Tune Encode quality/performance by relaxing specification compliance restrictions", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "strict (0)", + "mutable": "null", + "readable": true, + "type": "GstVaapiEncoderH264ComplianceMode", + "writable": true + }, + "cpb-length": { + "blurb": "Length of the CPB buffer in milliseconds", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "1500", + "max": "10000", + "min": "1", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "dct8x8": { + "blurb": "Enable adaptive use of 8x8 transforms in I-frames", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "default-roi-delta-qp": { + "blurb": "The default delta-qp to apply to each Region of Interest(lower value means higher-quality, higher value means lower-quality)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "-10", + "max": "10", + "min": "-10", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true + }, + "init-qp": { + "blurb": "Initial quantizer value", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "26", + "max": "51", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "keyframe-period": { + "blurb": "Maximal distance between two keyframes (0: auto-calculate)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "30", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "max-bframes": { + "blurb": "Number of B-frames between I and P", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "10", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "max-qp": { + "blurb": "Maximum quantizer value", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "51", + "max": "51", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "mbbrc": { + "blurb": "Macroblock level Bitrate Control", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "auto (0)", + "mutable": "null", + "readable": true, + "type": "GstVaapiEncoderMbbrc", + "writable": true + }, + "min-qp": { + "blurb": "Minimum quantizer value", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "1", + "max": "51", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "num-slices": { + "blurb": "Number of slices per frame", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "1", + "max": "200", + "min": "1", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "num-views": { + "blurb": "Number of Views for MVC encoding", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "1", + "max": "10", + "min": "1", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "prediction-type": { + "blurb": "Reference Picture Selection Modes", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "default (0)", + "mutable": "null", + "readable": true, + "type": "GstVaapiEncoderH264PredictionType", + "writable": true + }, + "qp-ib": { + "blurb": "Difference of QP between I and B frame (available only on CQP)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "51", + "min": "-51", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true + }, + "qp-ip": { + "blurb": "Difference of QP between I and P frame (available only on CQP)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "51", + "min": "-51", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true + }, + "quality-factor": { + "blurb": "quality factor for ICQ/QVBR bitrate control mode(low value means higher-quality, higher value means lower-quality)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "26", + "max": "51", + "min": "1", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "quality-level": { + "blurb": "Encoding Quality Level (lower value means higher-quality/slow-encode, higher value means lower-quality/fast-encode)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "4", + "max": "7", + "min": "1", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "rate-control": { + "blurb": "Rate control mode", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "cqp (1)", + "mutable": "null", + "readable": true, + "type": "GstVaapiRateControlH264", + "writable": true + }, + "refs": { + "blurb": "Number of reference frames", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "1", + "max": "8", + "min": "1", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "target-percentage": { + "blurb": "The desired target percentage of bitrate for variable rate controls.", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "70", + "max": "100", + "min": "1", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "temporal-levels": { + "blurb": "Number of temporal levels in the encoded stream ", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "1", + "max": "4", + "min": "1", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "trellis": { + "blurb": "The Trellis Quantization Method of Encoder", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "tune": { + "blurb": "Encoder tuning option", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "none (0)", + "mutable": "null", + "readable": true, + "type": "GstVaapiEncoderTuneH264", + "writable": true + }, + "view-ids": { + "blurb": "Set of View Ids used for MVC encoding", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GstValueArray", + "writable": true + } + }, + "rank": "primary" + }, + "vaapih265dec": { + "author": "Gwenole Beauchesne , Halley Zhao , Sreerenj Balachandran , Wind Yuan ", + "description": "A VA-API based H265 video decoder", + "hierarchy": [ + "GstVaapiDecode_h265", + "GstVideoDecoder", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Decoder/Video/Hardware", + "long-name": "VA-API H265 decoder", + "pad-templates": { + "sink": { + "caps": "video/x-h265:\n", + "direction": "sink", + "presence": "always" + }, + "src": { + "caps": "video/x-raw(memory:VASurface):\n format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(meta:GstVideoGLTextureUploadMeta):\n format: { RGBA, BGRA }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(memory:DMABuf):\n format: { I420, YV12, RGBA }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "primary" + }, + "vaapih265enc": { + "author": "Sreerenj Balachandran ", + "description": "A VA-API based H265 video encoder", + "hierarchy": [ + "GstVaapiEncodeH265", + "GstVaapiEncode", + "GstVideoEncoder", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "interfaces": [ + "GstPreset" + ], + "klass": "Codec/Encoder/Video/Hardware", + "long-name": "VA-API H265 encoder", + "pad-templates": { + "sink": { + "caps": "video/x-raw:\n format: { NV12, YV12, I420 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: progressive\n\nvideo/x-raw(memory:VASurface):\n format: { NV12, YV12, I420 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: progressive\n", + "direction": "sink", + "presence": "always" + }, + "src": { + "caps": "video/x-h265:\n stream-format: { (string)hvc1, (string)byte-stream }\n alignment: au\n profile: { (string)main, (string)main-10, (string)main-444, (string)main-444-10 }\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "bitrate": { + "blurb": "The desired bitrate expressed in kbps (0: auto-calculate)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "2048000", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "cpb-length": { + "blurb": "Length of the CPB buffer in milliseconds", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "1500", + "max": "10000", + "min": "1", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "default-roi-delta-qp": { + "blurb": "The default delta-qp to apply to each Region of Interest(lower value means higher-quality, higher value means lower-quality)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "-10", + "max": "10", + "min": "-10", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true + }, + "init-qp": { + "blurb": "Initial quantizer value", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "26", + "max": "51", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "keyframe-period": { + "blurb": "Maximal distance between two keyframes (0: auto-calculate)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "30", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "low-delay-b": { + "blurb": "Transforms P frames into predictive B frames. Enable it when P frames are not supported.", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "max-bframes": { + "blurb": "Number of B-frames between I and P", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "10", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "max-qp": { + "blurb": "Maximum quantizer value", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "51", + "max": "51", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "mbbrc": { + "blurb": "Macroblock level Bitrate Control", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "auto (0)", + "mutable": "null", + "readable": true, + "type": "GstVaapiEncoderMbbrc", + "writable": true + }, + "min-qp": { + "blurb": "Minimum quantizer value", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "1", + "max": "51", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "num-slices": { + "blurb": "Number of slices per frame", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "1", + "max": "200", + "min": "1", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "num-tile-cols": { + "blurb": "the number of columns for tile encoding", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "1", + "max": "20", + "min": "1", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "num-tile-rows": { + "blurb": "the number of rows for tile encoding", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "1", + "max": "22", + "min": "1", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "qp-ib": { + "blurb": "Difference of QP between I and B frame (available only on CQP)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "51", + "min": "-51", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true + }, + "qp-ip": { + "blurb": "Difference of QP between I and P frame (available only on CQP)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "51", + "min": "-51", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true + }, + "quality-factor": { + "blurb": "quality factor for ICQ/QBVR bitrate control mode (lower value means higher quality, higher value means lower quality)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "26", + "max": "51", + "min": "1", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "quality-level": { + "blurb": "Encoding Quality Level (lower value means higher-quality/slow-encode, higher value means lower-quality/fast-encode)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "4", + "max": "7", + "min": "1", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "rate-control": { + "blurb": "Rate control mode", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "cqp (1)", + "mutable": "null", + "readable": true, + "type": "GstVaapiRateControlH265", + "writable": true + }, + "refs": { + "blurb": "Number of reference frames", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "1", + "max": "3", + "min": "1", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "target-percentage": { + "blurb": "The desired target percentage of bitrate for variable rate controls.", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "70", + "max": "100", + "min": "1", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "trellis": { + "blurb": "The Trellis Quantization Method of Encoder", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "tune": { + "blurb": "Encoder tuning option", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "none (0)", + "mutable": "null", + "readable": true, + "type": "GstVaapiEncoderTuneH265", + "writable": true + } + }, + "rank": "primary" + }, + "vaapijpegdec": { + "author": "Gwenole Beauchesne , Halley Zhao , Sreerenj Balachandran , Wind Yuan ", + "description": "A VA-API based JPEG video decoder", + "hierarchy": [ + "GstVaapiDecode_jpeg", + "GstVideoDecoder", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Decoder/Video/Hardware", + "long-name": "VA-API JPEG decoder", + "pad-templates": { + "sink": { + "caps": "image/jpeg:\n", + "direction": "sink", + "presence": "always" + }, + "src": { + "caps": "video/x-raw(memory:VASurface):\n format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(meta:GstVideoGLTextureUploadMeta):\n format: { RGBA, BGRA }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(memory:DMABuf):\n format: { I420, YV12, RGBA }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "marginal" + }, + "vaapimpeg2dec": { + "author": "Gwenole Beauchesne , Halley Zhao , Sreerenj Balachandran , Wind Yuan ", + "description": "A VA-API based MPEG2 video decoder", + "hierarchy": [ + "GstVaapiDecode_mpeg2", + "GstVideoDecoder", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Decoder/Video/Hardware", + "long-name": "VA-API MPEG2 decoder", + "pad-templates": { + "sink": { + "caps": "video/mpeg:\n mpegversion: 2\n systemstream: false\n", + "direction": "sink", + "presence": "always" + }, + "src": { + "caps": "video/x-raw(memory:VASurface):\n format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(meta:GstVideoGLTextureUploadMeta):\n format: { RGBA, BGRA }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(memory:DMABuf):\n format: { I420, YV12, RGBA }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "primary" + }, + "vaapimpeg2enc": { + "author": "Guangxin Xu ", + "description": "A VA-API based MPEG-2 video encoder", + "hierarchy": [ + "GstVaapiEncodeMpeg2", + "GstVaapiEncode", + "GstVideoEncoder", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "interfaces": [ + "GstPreset" + ], + "klass": "Codec/Encoder/Video/Hardware", + "long-name": "VA-API MPEG-2 encoder", + "pad-templates": { + "sink": { + "caps": "video/x-raw:\n format: { NV12, YV12, I420 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: progressive\n\nvideo/x-raw(memory:VASurface):\n format: { NV12, YV12, I420 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: progressive\n", + "direction": "sink", + "presence": "always" + }, + "src": { + "caps": "video/mpeg:\n mpegversion: 2\n systemstream: false\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "bitrate": { + "blurb": "The desired bitrate expressed in kbps (0: auto-calculate)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "2048000", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "default-roi-delta-qp": { + "blurb": "The default delta-qp to apply to each Region of Interest(lower value means higher-quality, higher value means lower-quality)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "-10", + "max": "10", + "min": "-10", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true + }, + "keyframe-period": { + "blurb": "Maximal distance between two keyframes (0: auto-calculate)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "30", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "max-bframes": { + "blurb": "Number of B-frames between I and P", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "16", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "min-force-key-unit-interval": { + "blurb": "Minimum interval between force-keyunit requests in nanoseconds", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "18446744073709551615", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint64", + "writable": true + }, + "qos": { + "blurb": "Handle Quality-of-Service events from downstream", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "quality-level": { + "blurb": "Encoding Quality Level (lower value means higher-quality/slow-encode, higher value means lower-quality/fast-encode)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "4", + "max": "7", + "min": "1", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "quantizer": { + "blurb": "Constant quantizer (if rate-control mode is CQP)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "8", + "max": "62", + "min": "2", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "rate-control": { + "blurb": "Rate control mode", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "cqp (1)", + "mutable": "null", + "readable": true, + "type": "GstVaapiRateControlMPEG2", + "writable": true + }, + "target-percentage": { + "blurb": "The desired target percentage of bitrate for variable rate controls.", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "70", + "max": "100", + "min": "1", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "trellis": { + "blurb": "The Trellis Quantization Method of Encoder", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "tune": { + "blurb": "Encoder tuning option", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "none (0)", + "mutable": "null", + "readable": true, + "type": "GstVaapiEncoderTuneMPEG2", + "writable": true + } + }, + "rank": "primary" + }, + "vaapipostproc": { + "author": "Gwenole Beauchesne ", + "description": "A VA-API video postprocessing filter", + "hierarchy": [ + "GstVaapiPostproc", + "GstBaseTransform", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "interfaces": [ + "GstColorBalance" + ], + "klass": "Filter/Converter/Effect/Video/Scaler/Deinterlace/Hardware", + "long-name": "VA-API video postprocessing", + "pad-templates": { + "sink": { + "caps": "video/x-raw(memory:VASurface):\n format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: { (string)progressive, (string)interleaved, (string)mixed }\nvideo/x-raw:\n format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: { (string)progressive, (string)interleaved, (string)mixed }\n", + "direction": "sink", + "presence": "always" + }, + "src": { + "caps": "video/x-raw(memory:VASurface):\n format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: progressive\n\nvideo/x-raw(meta:GstVideoGLTextureUploadMeta):\n format: { RGBA, BGRA }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: { (string)progressive, (string)interleaved, (string)mixed }\n\nvideo/x-raw(memory:DMABuf):\n format: { I420, YV12, RGBA }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "brightness": { + "blurb": "The color brightness value", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "1", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gfloat", + "writable": true + }, + "contrast": { + "blurb": "The color contrast value", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "1", + "max": "2", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gfloat", + "writable": true + }, + "crop-bottom": { + "blurb": "Pixels to crop at bottom", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "2147483647", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "crop-left": { + "blurb": "Pixels to crop at left", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "2147483647", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "crop-right": { + "blurb": "Pixels to crop at right", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "2147483647", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "crop-top": { + "blurb": "Pixels to crop at top", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "2147483647", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "deinterlace-method": { + "blurb": "Deinterlace method to use", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "bob (1)", + "mutable": "null", + "readable": true, + "type": "GstVaapiDeinterlaceMethod", + "writable": true + }, + "deinterlace-mode": { + "blurb": "Deinterlace mode to use", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "auto (0)", + "mutable": "null", + "readable": true, + "type": "GstVaapiDeinterlaceMode", + "writable": true + }, + "denoise": { + "blurb": "The level of denoising to apply", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gfloat", + "writable": true + }, + "force-aspect-ratio": { + "blurb": "When enabled, scaling will respect original aspect ratio", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "format": { + "blurb": "The forced output pixel format", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "encoded (1)", + "mutable": "null", + "readable": true, + "type": "GstVideoFormat", + "writable": true + }, + "hdr-tone-map": { + "blurb": "Apply HDR tone mapping algorithm", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "auto (0)", + "mutable": "null", + "readable": true, + "type": "GstVaapiHDRToneMap", + "writable": true + }, + "height": { + "blurb": "Forced output height", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "2147483647", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "hue": { + "blurb": "The color hue value", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "180", + "min": "-180", + "mutable": "null", + "readable": true, + "type": "gfloat", + "writable": true + }, + "saturation": { + "blurb": "The color saturation value", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "1", + "max": "2", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gfloat", + "writable": true + }, + "scale-method": { + "blurb": "Scaling method to use", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "default (0)", + "mutable": "null", + "readable": true, + "type": "GstVaapiScaleMethod", + "writable": true + }, + "sharpen": { + "blurb": "The level of sharpening/blurring to apply", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "1", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gfloat", + "writable": true + }, + "skin-tone-enhancement": { + "blurb": "Apply the skin tone enhancement algorithm", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "skin-tone-enhancement-level": { + "blurb": "Apply the skin tone enhancement algorithm with specified level", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "3", + "max": "9", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "video-direction": { + "blurb": "Video direction: rotation and flipping", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "identity (0)", + "mutable": "null", + "readable": true, + "type": "GstVideoOrientationMethod", + "writable": true + }, + "width": { + "blurb": "Forced output width", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "2147483647", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + } + }, + "rank": "primary" + }, + "vaapisink": { + "author": "Gwenole Beauchesne ", + "description": "A VA-API based videosink", + "hierarchy": [ + "GstVaapiSink", + "GstVideoSink", + "GstBaseSink", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "interfaces": [ + "GstVideoOverlay", + "GstColorBalance", + "GstNavigation" + ], + "klass": "Sink/Video", + "long-name": "VA-API sink", + "pad-templates": { + "sink": { + "caps": "video/x-raw(memory:VASurface):\n format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(memory:VASurface, meta:GstVideoOverlayComposition):\n format: { ENCODED, NV12, I420, YV12, P010_10LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(meta:GstVideoOverlayComposition):\n format: { AYUV64, ARGB64, GBRA_12LE, GBRA_12BE, Y412_LE, Y412_BE, A444_10LE, GBRA_10LE, A444_10BE, GBRA_10BE, A422_10LE, A422_10BE, A420_10LE, A420_10BE, RGB10A2_LE, BGR10A2_LE, Y410, GBRA, ABGR, VUYA, BGRA, AYUV, ARGB, RGBA, A420, Y444_16LE, Y444_16BE, v216, P016_LE, P016_BE, Y444_12LE, GBR_12LE, Y444_12BE, GBR_12BE, I422_12LE, I422_12BE, Y212_LE, Y212_BE, I420_12LE, I420_12BE, P012_LE, P012_BE, Y444_10LE, GBR_10LE, Y444_10BE, GBR_10BE, r210, I422_10LE, I422_10BE, NV16_10LE32, Y210, v210, UYVP, I420_10LE, I420_10BE, P010_10LE, NV12_10LE32, NV12_10LE40, P010_10BE, Y444, GBR, NV24, xBGR, BGRx, xRGB, RGBx, BGR, IYU2, v308, RGB, Y42B, NV61, NV16, VYUY, UYVY, YVYU, YUY2, I420, YV12, NV21, NV12, NV12_64Z32, Y41B, IYU1, YVU9, YUV9, RGB16, BGR16, RGB15, BGR15, RGB8P, GRAY16_LE, GRAY16_BE, GRAY10_LE32, GRAY8 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: { AYUV64, ARGB64, GBRA_12LE, GBRA_12BE, Y412_LE, Y412_BE, A444_10LE, GBRA_10LE, A444_10BE, GBRA_10BE, A422_10LE, A422_10BE, A420_10LE, A420_10BE, RGB10A2_LE, BGR10A2_LE, Y410, GBRA, ABGR, VUYA, BGRA, AYUV, ARGB, RGBA, A420, Y444_16LE, Y444_16BE, v216, P016_LE, P016_BE, Y444_12LE, GBR_12LE, Y444_12BE, GBR_12BE, I422_12LE, I422_12BE, Y212_LE, Y212_BE, I420_12LE, I420_12BE, P012_LE, P012_BE, Y444_10LE, GBR_10LE, Y444_10BE, GBR_10BE, r210, I422_10LE, I422_10BE, NV16_10LE32, Y210, v210, UYVP, I420_10LE, I420_10BE, P010_10LE, NV12_10LE32, NV12_10LE40, P010_10BE, Y444, GBR, NV24, xBGR, BGRx, xRGB, RGBx, BGR, IYU2, v308, RGB, Y42B, NV61, NV16, VYUY, UYVY, YVYU, YUY2, I420, YV12, NV21, NV12, NV12_64Z32, Y41B, IYU1, YVU9, YUV9, RGB16, BGR16, RGB15, BGR15, RGB8P, GRAY16_LE, GRAY16_BE, GRAY10_LE32, GRAY8 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "sink", + "presence": "always" + } + }, + "properties": { + "brightness": { + "blurb": "The display brightness value", + "conditionally-available": false, + "construct": true, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "1", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gfloat", + "writable": true + }, + "contrast": { + "blurb": "The display contrast value", + "conditionally-available": false, + "construct": true, + "construct-only": false, + "controllable": false, + "default": "1", + "max": "2", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gfloat", + "writable": true + }, + "display": { + "blurb": "display type to use", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "any (0)", + "mutable": "null", + "readable": true, + "type": "GstVaapiDisplayType", + "writable": true + }, + "display-name": { + "blurb": "display name to use", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", + "writable": true + }, + "force-aspect-ratio": { + "blurb": "When enabled, scaling will respect original aspect ratio", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "fullscreen": { + "blurb": "Requests window in fullscreen state", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "hue": { + "blurb": "The display hue value", + "conditionally-available": false, + "construct": true, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "180", + "min": "-180", + "mutable": "null", + "readable": true, + "type": "gfloat", + "writable": true + }, + "rotation": { + "blurb": "The display rotation mode", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0 (0)", + "mutable": "null", + "readable": true, + "type": "GstVaapiRotation", + "writable": true + }, + "saturation": { + "blurb": "The display saturation value", + "conditionally-available": false, + "construct": true, + "construct-only": false, + "controllable": false, + "default": "1", + "max": "2", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gfloat", + "writable": true + }, + "signal-handoffs": { + "blurb": "Send a signal after rendering the buffer", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "view-id": { + "blurb": "ID of the view component of interest to display", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "-1", + "max": "2147483647", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true + } + }, + "rank": "marginal", + "signals": { + "handoff": { + "args": [ + { + "name": "arg0", + "type": "GstBuffer" + } + ], + "return-type": "void", + "when": "last" + } + } + }, + "vaapivc1dec": { + "author": "Gwenole Beauchesne , Halley Zhao , Sreerenj Balachandran , Wind Yuan ", + "description": "A VA-API based VC1 video decoder", + "hierarchy": [ + "GstVaapiDecode_vc1", + "GstVideoDecoder", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Decoder/Video/Hardware", + "long-name": "VA-API VC1 decoder", + "pad-templates": { + "sink": { + "caps": "video/x-wmv:\n wmvversion: 3\n format: { WMV3, WVC1 }\n", + "direction": "sink", + "presence": "always" + }, + "src": { + "caps": "video/x-raw(memory:VASurface):\n format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(meta:GstVideoGLTextureUploadMeta):\n format: { RGBA, BGRA }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(memory:DMABuf):\n format: { I420, YV12, RGBA }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "primary" + } + }, + "filename": "gstvaapi", + "license": "LGPL", + "other-types": { + "GstVaapiDeinterlaceMethod": { + "kind": "enum", + "values": [ + { + "desc": "Disable deinterlacing", + "name": "none", + "value": "0" + }, + { + "desc": "Bob deinterlacing", + "name": "bob", + "value": "1" + }, + { + "desc": "Weave deinterlacing", + "name": "weave", + "value": "2" + }, + { + "desc": "Motion adaptive deinterlacing", + "name": "motion-adaptive", + "value": "3" + }, + { + "desc": "Motion compensated deinterlacing", + "name": "motion-compensated", + "value": "4" + } + ] + }, + "GstVaapiDeinterlaceMode": { + "kind": "enum", + "values": [ + { + "desc": "Auto detection", + "name": "auto", + "value": "0" + }, + { + "desc": "Force deinterlacing", + "name": "interlaced", + "value": "1" + }, + { + "desc": "Never deinterlace", + "name": "disabled", + "value": "2" + } + ] + }, + "GstVaapiDisplayType": { + "kind": "enum", + "values": [ + { + "desc": "Auto detection", + "name": "any", + "value": "0" + }, + { + "desc": "VA/X11 display", + "name": "x11", + "value": "1" + }, + { + "desc": "VA/GLX display", + "name": "glx", + "value": "2" + }, + { + "desc": "VA/EGL display", + "name": "egl", + "value": "5" + }, + { + "desc": "VA/Wayland display", + "name": "wayland", + "value": "3" + }, + { + "desc": "VA/DRM display", + "name": "drm", + "value": "4" + } + ] + }, + "GstVaapiEncode": { + "hierarchy": [ + "GstVaapiEncode", + "GstVideoEncoder", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "interfaces": [ + "GstPreset" + ], + "kind": "object" + }, + "GstVaapiEncoderH264ComplianceMode": { + "kind": "enum", + "values": [ + { + "desc": "Strict compliance to the H264 Specification ", + "name": "strict", + "value": "0" + }, + { + "desc": "Restrict the allocation size of coded-buffer", + "name": "restrict-buf-alloc", + "value": "1" + } + ] + }, + "GstVaapiEncoderH264PredictionType": { + "kind": "enum", + "values": [ + { + "desc": "Default encode, prev/next frame as ref ", + "name": "default", + "value": "0" + }, + { + "desc": "Hierarchical P frame encode", + "name": "hierarchical-p", + "value": "1" + }, + { + "desc": "Hierarchical B frame encode", + "name": "hierarchical-b", + "value": "2" + } + ] + }, + "GstVaapiEncoderMbbrc": { + "kind": "enum", + "values": [ + { + "desc": "Auto", + "name": "auto", + "value": "0" + }, + { + "desc": "On", + "name": "on", + "value": "1" + }, + { + "desc": "Off", + "name": "off", + "value": "2" + } + ] + }, + "GstVaapiEncoderTuneH264": { + "kind": "enum", + "values": [ + { + "desc": "None", + "name": "none", + "value": "0" + }, + { + "desc": "High compression", + "name": "high-compression", + "value": "1" + }, + { + "desc": "Low power mode", + "name": "low-power", + "value": "3" + } + ] + }, + "GstVaapiEncoderTuneH265": { + "kind": "enum", + "values": [ + { + "desc": "None", + "name": "none", + "value": "0" + }, + { + "desc": "Low power mode", + "name": "low-power", + "value": "3" + } + ] + }, + "GstVaapiEncoderTuneMPEG2": { + "kind": "enum", + "values": [ + { + "desc": "None", + "name": "none", + "value": "0" + } + ] + }, + "GstVaapiHDRToneMap": { + "kind": "enum", + "values": [ + { + "desc": "Auto detection", + "name": "auto", + "value": "0" + }, + { + "desc": "Disable HDR tone mapping", + "name": "disabled", + "value": "1" + } + ] + }, + "GstVaapiRateControlH264": { + "kind": "enum", + "values": [ + { + "desc": "Constant QP", + "name": "cqp", + "value": "1" + }, + { + "desc": "Constant bitrate", + "name": "cbr", + "value": "2" + }, + { + "desc": "Variable bitrate", + "name": "vbr", + "value": "4" + }, + { + "desc": "Variable bitrate - Constrained", + "name": "vbr_constrained", + "value": "5" + }, + { + "desc": "Constant QP - Intelligent", + "name": "icq", + "value": "7" + }, + { + "desc": "Variable bitrate - Quality defined", + "name": "qvbr", + "value": "8" + } + ] + }, + "GstVaapiRateControlH265": { + "kind": "enum", + "values": [ + { + "desc": "Constant QP", + "name": "cqp", + "value": "1" + }, + { + "desc": "Constant bitrate", + "name": "cbr", + "value": "2" + }, + { + "desc": "Variable bitrate", + "name": "vbr", + "value": "4" + }, + { + "desc": "Constant QP - Intelligent", + "name": "icq", + "value": "7" + }, + { + "desc": "Variable bitrate - Quality defined", + "name": "qvbr", + "value": "8" + } + ] + }, + "GstVaapiRateControlMPEG2": { + "kind": "enum", + "values": [ + { + "desc": "Constant QP", + "name": "cqp", + "value": "1" + }, + { + "desc": "Constant bitrate", + "name": "cbr", + "value": "2" + } + ] + }, + "GstVaapiRotation": { + "kind": "enum", + "values": [ + { + "desc": "Unrotated mode", + "name": "0", + "value": "0" + }, + { + "desc": "Rotated by 90°, clockwise", + "name": "90", + "value": "90" + }, + { + "desc": "Rotated by 180°, clockwise", + "name": "180", + "value": "180" + }, + { + "desc": "Rotated by 270°, clockwise", + "name": "270", + "value": "270" + }, + { + "desc": "Rotated by image-orientating tag°", + "name": "Automatic", + "value": "360" + } + ] + }, + "GstVaapiScaleMethod": { + "kind": "enum", + "values": [ + { + "desc": "Default scaling mode", + "name": "default", + "value": "0" + }, + { + "desc": "Fast scaling mode", + "name": "fast", + "value": "1" + }, + { + "desc": "High quality scaling mode", + "name": "hq", + "value": "2" + } + ] + } + }, + "package": "gstreamer-vaapi", + "source": "gstreamer-vaapi", + "tracers": {}, + "url": "https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi/issues" + } +} \ No newline at end of file diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000000..dcdf204c7d --- /dev/null +++ b/docs/index.md @@ -0,0 +1,34 @@ +--- +short-description: GStreamer plugins from gstreamer-vaapi +... + +# VAAPI Plugin + +## Environment variables + +GStreamer-VAAPI inspects a few of environment variables to define it +usage. + +**GST_VAAPI_ALL_DRIVERS.** + +This environment variable can be set, independently of its value, to +disable the drivers white list. By default only intel and mesa va +drivers are loaded if they are available. The rest are ignored. With +this environment variable defined, all the available va drivers are +loaded, even if they are deprecated. + +**LIBVA_DRIVER_NAME.** + +This environment variable can be set with the drivers name to load. For +example, intel's driver is `i915`, meanwhile mesa is `gallium`. + +**LIBVA_DRIVERS_PATH.** + +This environment variable can be set to a colon-separated list of paths +(or a semicolon-separated list on Windows). libva will scan these paths +for va drivers. + +**GST_VAAPI_DRM_DEVICE.** +This environment variable can be set to a specified DRM device when DRM +display is used, it is ignored when other types of displays are used. +By default /dev/dri/renderD128 is used for DRM display. diff --git a/docs/meson.build b/docs/meson.build new file mode 100644 index 0000000000..c6fe4a50d9 --- /dev/null +++ b/docs/meson.build @@ -0,0 +1,74 @@ +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 it 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 + 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('vaapi-plugins-doc-cache', + command: [plugins_cache_generator, plugins_cache, '@OUTPUT@', '@INPUT@'], + input: plugins, + output: 'gst_plugins_cache.json', + build_always_stale: true, + ) +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_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 + +build_hotdoc = true +hotdoc = import('hotdoc') +if not hotdoc.has_extensions(required_hotdoc_extensions) + if get_option('doc').enabled() + error('Documentation enabled but gi-extension missing') + endif + + message('@0@ extensions not found, not building documentation'.format(required_hotdoc_extensions)) + subdir_done() +endif + +message('Plugins: @0@'.format(plugins)) +libs_doc = [] +plugins_doc = [hotdoc.generate_doc('vaapi', + project_version: api_version, + sitemap: 'sitemap.txt', + index: 'index.md', + gst_index: 'index.md', + gst_smart_index: true, + gst_c_sources: ['../gst/*/*.[ch]',], + gst_cache_file: plugins_cache, + gst_plugin_name: 'vaapi', + dependencies: [gstbase_dep, gstvideo_dep, gstallocators_dep, gstpbutils_dep, + libva_dep, gstlibvaapi_dep, gstgl_dep, libm] + plugins, +)] diff --git a/docs/sitemap.txt b/docs/sitemap.txt new file mode 100644 index 0000000000..058a2713a4 --- /dev/null +++ b/docs/sitemap.txt @@ -0,0 +1 @@ +gst-index diff --git a/gst-libs/gst/meson.build b/gst-libs/gst/meson.build new file mode 100644 index 0000000000..a8719a14c0 --- /dev/null +++ b/gst-libs/gst/meson.build @@ -0,0 +1 @@ +subdir('vaapi') diff --git a/gst-libs/gst/vaapi/egl_compat.h b/gst-libs/gst/vaapi/egl_compat.h new file mode 100644 index 0000000000..c417211678 --- /dev/null +++ b/gst-libs/gst/vaapi/egl_compat.h @@ -0,0 +1,39 @@ +/* + * egl_compat.h - EGL compatiliby layer + * + * Copyright (C) 2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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 + */ + +#ifndef EGL_COMPAT_H +#define EGL_COMPAT_H + +#include +#include +#include "ogl_compat.h" + +#ifndef GL_OES_EGL_image +#define GL_OES_EGL_image 1 +typedef void *GLeglImageOES; +typedef void (*PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)(GLenum target, + GLeglImageOES image); +typedef void (*PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC)(GLenum target, + GLeglImageOES image); +#endif /* GL_OES_EGL_image */ + +#endif /* EGL_COMPAT_H */ diff --git a/gst-libs/gst/vaapi/egl_vtable.h b/gst-libs/gst/vaapi/egl_vtable.h new file mode 100644 index 0000000000..53b3acc9fd --- /dev/null +++ b/gst-libs/gst/vaapi/egl_vtable.h @@ -0,0 +1,806 @@ +/* + * egl_vtable.h - EGL function definitions + * + * Copyright (C) 2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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 + */ + +/* ------------------------------------------------------------------------- */ +// Generate strings + +#define GL_PROTO_GEN_STRING(x) \ + GL_PROTO_GEN_STRING_I(x) +#define GL_PROTO_GEN_STRING_I(x) \ + #x + +/* ------------------------------------------------------------------------- */ +// Concatenate arguments + +#define GL_PROTO_GEN_CONCAT(a1, a2) \ + GL_PROTO_GEN_CONCAT2_I(a1, a2) +#define GL_PROTO_GEN_CONCAT2(a1, a2) \ + GL_PROTO_GEN_CONCAT2_I(a1, a2) +#define GL_PROTO_GEN_CONCAT2_I(a1, a2) \ + a1 ## a2 + +#define GL_PROTO_GEN_CONCAT3(a1, a2, a3) \ + GL_PROTO_GEN_CONCAT3_I(a1, a2, a3) +#define GL_PROTO_GEN_CONCAT3_I(a1, a2, a3) \ + a1 ## a2 ## a3 + +#define GL_PROTO_GEN_CONCAT4(a1, a2, a3, a4) \ + GL_PROTO_GEN_CONCAT4_I(a1, a2, a3, a4) +#define GL_PROTO_GEN_CONCAT4_I(a1, a2, a3, a4) \ + a1 ## a2 ## a3 ## a4 + +#define GL_PROTO_GEN_CONCAT5(a1, a2, a3, a4, a5) \ + GL_PROTO_GEN_CONCAT5_I(a1, a2, a3, a4, a5) +#define GL_PROTO_GEN_CONCAT5_I(a1, a2, a3, a4, a5) \ + a1 ## a2 ## a3 ## a4 ## a5 + +/* ------------------------------------------------------------------------- */ +// Default macros + +#ifndef EGL_PROTO_BEGIN +#define EGL_PROTO_BEGIN(NAME, TYPE, EXTENSION) +#endif +#ifndef EGL_PROTO_ARG_LIST +#define EGL_PROTO_ARG_LIST(...) GL_PROTO_ARG_LIST(__VA_ARGS__) +#endif +#ifndef EGL_PROTO_ARG +#define EGL_PROTO_ARG(NAME, TYPE) GL_PROTO_ARG(NAME, TYPE) +#endif +#ifndef EGL_PROTO_INVOKE +#define EGL_PROTO_INVOKE(NAME, TYPE, ARGS) +#endif +#ifndef EGL_PROTO_END +#define EGL_PROTO_END() +#endif +#ifndef EGL_DEFINE_EXTENSION +#define EGL_DEFINE_EXTENSION(EXTENSION) +#endif + +#ifndef GL_PROTO_BEGIN +#define GL_PROTO_BEGIN(NAME, TYPE, EXTENSION) +#endif +#ifndef GL_PROTO_ARG_LIST +#define GL_PROTO_ARG_LIST(...) +#endif +#ifndef GL_PROTO_ARG +#define GL_PROTO_ARG(NAME, TYPE) +#endif +#ifndef GL_PROTO_INVOKE +#define GL_PROTO_INVOKE(NAME, TYPE, ARGS) +#endif +#ifndef GL_PROTO_END +#define GL_PROTO_END() +#endif +#ifndef GL_DEFINE_EXTENSION +#define GL_DEFINE_EXTENSION(EXTENSION) +#endif + +/* NOTE: this is auto-generated code -- do not edit! */ + +EGL_PROTO_BEGIN(CreateImageKHR, EGLImageKHR, KHR_image_base) +EGL_PROTO_ARG_LIST( +EGL_PROTO_ARG(dpy, EGLDisplay), +EGL_PROTO_ARG(ctx, EGLContext), +EGL_PROTO_ARG(target, EGLenum), +EGL_PROTO_ARG(buffer, EGLClientBuffer), +EGL_PROTO_ARG(attrib_list, const EGLint *)) +EGL_PROTO_INVOKE(CreateImageKHR, EGLImageKHR, (dpy, ctx, target, buffer, attrib_list)) +EGL_PROTO_END() + +EGL_PROTO_BEGIN(DestroyImageKHR, EGLImageKHR, KHR_image_base) +EGL_PROTO_ARG_LIST( +EGL_PROTO_ARG(dpy, EGLDisplay), +EGL_PROTO_ARG(image, EGLImageKHR)) +EGL_PROTO_INVOKE(DestroyImageKHR, EGLImageKHR, (dpy, image)) +EGL_PROTO_END() + +EGL_PROTO_BEGIN(CreateDRMImageMESA, EGLImageKHR, MESA_drm_image) +EGL_PROTO_ARG_LIST( +EGL_PROTO_ARG(dpy, EGLDisplay), +EGL_PROTO_ARG(attrib_list, const EGLint *)) +EGL_PROTO_INVOKE(CreateDRMImageMESA, EGLImageKHR, (dpy, attrib_list)) +EGL_PROTO_END() + +EGL_PROTO_BEGIN(ExportDRMImageMESA, EGLImageKHR, MESA_drm_image) +EGL_PROTO_ARG_LIST( +EGL_PROTO_ARG(dpy, EGLDisplay), +EGL_PROTO_ARG(image, EGLImageKHR), +EGL_PROTO_ARG(name, EGLint *), +EGL_PROTO_ARG(handle, EGLint *), +EGL_PROTO_ARG(stride, EGLint *)) +EGL_PROTO_INVOKE(ExportDRMImageMESA, EGLImageKHR, (dpy, image, name, handle, stride)) +EGL_PROTO_END() + +EGL_PROTO_BEGIN(ExportDMABUFImageMESA, EGLBoolean, MESA_image_dma_buf_export) +EGL_PROTO_ARG_LIST( +EGL_PROTO_ARG(dpy, EGLDisplay), +EGL_PROTO_ARG(image, EGLImageKHR), +EGL_PROTO_ARG(fds, int *), +EGL_PROTO_ARG(strides, EGLint *), +EGL_PROTO_ARG(offsets, EGLint *)) +EGL_PROTO_INVOKE(ExportDMABUFImageMESA, EGLBoolean, (dpy, image, fds, strides, offsets)) +EGL_PROTO_END() + +EGL_PROTO_BEGIN(ExportDMABUFImageQueryMESA, EGLBoolean, MESA_image_dma_buf_export) +EGL_PROTO_ARG_LIST( +EGL_PROTO_ARG(dpy, EGLDisplay), +EGL_PROTO_ARG(image, EGLImageKHR), +EGL_PROTO_ARG(fourcc, int *), +EGL_PROTO_ARG(num_planes, int *), +EGL_PROTO_ARG(modifiers, EGLuint64KHR *)) +EGL_PROTO_INVOKE(ExportDMABUFImageQueryMESA, EGLBoolean, (dpy, image, fourcc, num_planes, modifiers)) +EGL_PROTO_END() + +EGL_DEFINE_EXTENSION(EXT_image_dma_buf_import) +EGL_DEFINE_EXTENSION(KHR_create_context) +EGL_DEFINE_EXTENSION(KHR_gl_texture_2D_image) +EGL_DEFINE_EXTENSION(KHR_image_base) +EGL_DEFINE_EXTENSION(KHR_surfaceless_context) +EGL_DEFINE_EXTENSION(MESA_configless_context) +EGL_DEFINE_EXTENSION(MESA_drm_image) +EGL_DEFINE_EXTENSION(MESA_image_dma_buf_export) + +GL_PROTO_BEGIN(GetError, GLenum, CORE_1_0) +GL_PROTO_ARG_LIST() +GL_PROTO_INVOKE(GetError, GLenum, ()) +GL_PROTO_END() + +GL_PROTO_BEGIN(GetString, const GLubyte *, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(name, GLenum)) +GL_PROTO_INVOKE(GetString, const GLubyte *, (name)) +GL_PROTO_END() + +GL_PROTO_BEGIN(GetIntegerv, void, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(pname, GLenum), +GL_PROTO_ARG(params, GLint *)) +GL_PROTO_INVOKE(GetIntegerv, void, (pname, params)) +GL_PROTO_END() + +GL_PROTO_BEGIN(Enable, void, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(cap, GLenum)) +GL_PROTO_INVOKE(Enable, void, (cap)) +GL_PROTO_END() + +GL_PROTO_BEGIN(Disable, void, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(cap, GLenum)) +GL_PROTO_INVOKE(Disable, void, (cap)) +GL_PROTO_END() + +GL_PROTO_BEGIN(IsEnabled, GLboolean, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(cap, GLenum)) +GL_PROTO_INVOKE(IsEnabled, GLboolean, (cap)) +GL_PROTO_END() + +GL_PROTO_BEGIN(Finish, void, CORE_1_0) +GL_PROTO_ARG_LIST() +GL_PROTO_INVOKE(Finish, void, ()) +GL_PROTO_END() + +GL_PROTO_BEGIN(Flush, void, CORE_1_0) +GL_PROTO_ARG_LIST() +GL_PROTO_INVOKE(Flush, void, ()) +GL_PROTO_END() + +GL_PROTO_BEGIN(Begin, void, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(mode, GLenum)) +GL_PROTO_INVOKE(Begin, void, (mode)) +GL_PROTO_END() + +GL_PROTO_BEGIN(End, void, CORE_1_0) +GL_PROTO_ARG_LIST() +GL_PROTO_INVOKE(End, void, ()) +GL_PROTO_END() + +GL_PROTO_BEGIN(Color4f, void, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(red, GLfloat), +GL_PROTO_ARG(green, GLfloat), +GL_PROTO_ARG(blue, GLfloat), +GL_PROTO_ARG(alpha, GLfloat)) +GL_PROTO_INVOKE(Color4f, void, (red, green, blue, alpha)) +GL_PROTO_END() + +GL_PROTO_BEGIN(Clear, void, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(mask, GLbitfield)) +GL_PROTO_INVOKE(Clear, void, (mask)) +GL_PROTO_END() + +GL_PROTO_BEGIN(ClearColor, void, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(red, GLclampf), +GL_PROTO_ARG(green, GLclampf), +GL_PROTO_ARG(blue, GLclampf), +GL_PROTO_ARG(alpha, GLclampf)) +GL_PROTO_INVOKE(ClearColor, void, (red, green, blue, alpha)) +GL_PROTO_END() + +GL_PROTO_BEGIN(PushMatrix, void, CORE_1_0) +GL_PROTO_ARG_LIST() +GL_PROTO_INVOKE(PushMatrix, void, ()) +GL_PROTO_END() + +GL_PROTO_BEGIN(PopMatrix, void, CORE_1_0) +GL_PROTO_ARG_LIST() +GL_PROTO_INVOKE(PopMatrix, void, ()) +GL_PROTO_END() + +GL_PROTO_BEGIN(LoadIdentity, void, CORE_1_0) +GL_PROTO_ARG_LIST() +GL_PROTO_INVOKE(LoadIdentity, void, ()) +GL_PROTO_END() + +GL_PROTO_BEGIN(MatrixMode, void, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(mode, GLenum)) +GL_PROTO_INVOKE(MatrixMode, void, (mode)) +GL_PROTO_END() + +GL_PROTO_BEGIN(PushAttrib, void, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(mask, GLbitfield)) +GL_PROTO_INVOKE(PushAttrib, void, (mask)) +GL_PROTO_END() + +GL_PROTO_BEGIN(PopAttrib, void, CORE_1_0) +GL_PROTO_ARG_LIST() +GL_PROTO_INVOKE(PopAttrib, void, ()) +GL_PROTO_END() + +GL_PROTO_BEGIN(Viewport, void, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(x, GLint), +GL_PROTO_ARG(y, GLint), +GL_PROTO_ARG(width, GLsizei), +GL_PROTO_ARG(height, GLsizei)) +GL_PROTO_INVOKE(Viewport, void, (x, y, width, height)) +GL_PROTO_END() + +GL_PROTO_BEGIN(Frustum, void, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(left, GLdouble), +GL_PROTO_ARG(right, GLdouble), +GL_PROTO_ARG(bottom, GLdouble), +GL_PROTO_ARG(top, GLdouble), +GL_PROTO_ARG(zNear, GLdouble), +GL_PROTO_ARG(zFar, GLdouble)) +GL_PROTO_INVOKE(Frustum, void, (left, right, bottom, top, zNear, zFar)) +GL_PROTO_END() + +GL_PROTO_BEGIN(Scalef, void, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(x, GLfloat), +GL_PROTO_ARG(y, GLfloat), +GL_PROTO_ARG(z, GLfloat)) +GL_PROTO_INVOKE(Scalef, void, (x, y, z)) +GL_PROTO_END() + +GL_PROTO_BEGIN(Translatef, void, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(x, GLfloat), +GL_PROTO_ARG(y, GLfloat), +GL_PROTO_ARG(z, GLfloat)) +GL_PROTO_INVOKE(Translatef, void, (x, y, z)) +GL_PROTO_END() + +GL_PROTO_BEGIN(EnableClientState, void, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(array, GLenum)) +GL_PROTO_INVOKE(EnableClientState, void, (array)) +GL_PROTO_END() + +GL_PROTO_BEGIN(DisableClientState, void, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(array, GLenum)) +GL_PROTO_INVOKE(DisableClientState, void, (array)) +GL_PROTO_END() + +GL_PROTO_BEGIN(TexCoordPointer, void, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(size, GLint), +GL_PROTO_ARG(type, GLenum), +GL_PROTO_ARG(stride, GLsizei), +GL_PROTO_ARG(pointer, const GLvoid *)) +GL_PROTO_INVOKE(TexCoordPointer, void, (size, type, stride, pointer)) +GL_PROTO_END() + +GL_PROTO_BEGIN(VertexPointer, void, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(size, GLint), +GL_PROTO_ARG(type, GLenum), +GL_PROTO_ARG(stride, GLsizei), +GL_PROTO_ARG(pointer, const GLvoid *)) +GL_PROTO_INVOKE(VertexPointer, void, (size, type, stride, pointer)) +GL_PROTO_END() + +GL_PROTO_BEGIN(EnableVertexAttribArray, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(index, GLuint)) +GL_PROTO_INVOKE(EnableVertexAttribArray, void, (index)) +GL_PROTO_END() + +GL_PROTO_BEGIN(DisableVertexAttribArray, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(index, GLuint)) +GL_PROTO_INVOKE(DisableVertexAttribArray, void, (index)) +GL_PROTO_END() + +GL_PROTO_BEGIN(GetVertexAttribPointerv, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(index, GLuint), +GL_PROTO_ARG(pname, GLenum), +GL_PROTO_ARG(pointer, GLvoid **)) +GL_PROTO_INVOKE(GetVertexAttribPointerv, void, (index, pname, pointer)) +GL_PROTO_END() + +GL_PROTO_BEGIN(VertexAttribPointer, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(index, GLuint), +GL_PROTO_ARG(size, GLint), +GL_PROTO_ARG(type, GLenum), +GL_PROTO_ARG(normalized, GLboolean), +GL_PROTO_ARG(stride, GLsizei), +GL_PROTO_ARG(pointer, const GLvoid *)) +GL_PROTO_INVOKE(VertexAttribPointer, void, (index, size, type, normalized, stride, pointer)) +GL_PROTO_END() + +GL_PROTO_BEGIN(DrawArrays, void, CORE_1_1) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(mode, GLenum), +GL_PROTO_ARG(first, GLint), +GL_PROTO_ARG(count, GLsizei)) +GL_PROTO_INVOKE(DrawArrays, void, (mode, first, count)) +GL_PROTO_END() + +GL_PROTO_BEGIN(GenTextures, void, CORE_1_1) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(n, GLsizei), +GL_PROTO_ARG(textures, GLuint *)) +GL_PROTO_INVOKE(GenTextures, void, (n, textures)) +GL_PROTO_END() + +GL_PROTO_BEGIN(DeleteTextures, void, CORE_1_1) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(n, GLsizei), +GL_PROTO_ARG(textures, const GLuint *)) +GL_PROTO_INVOKE(DeleteTextures, void, (n, textures)) +GL_PROTO_END() + +GL_PROTO_BEGIN(BindTexture, void, CORE_1_1) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(target, GLenum), +GL_PROTO_ARG(texture, GLuint)) +GL_PROTO_INVOKE(BindTexture, void, (target, texture)) +GL_PROTO_END() + +GL_PROTO_BEGIN(ActiveTexture, void, CORE_1_3) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(texture, GLenum)) +GL_PROTO_INVOKE(ActiveTexture, void, (texture)) +GL_PROTO_END() + +GL_PROTO_BEGIN(GetTexLevelParameteriv, void, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(target, GLenum), +GL_PROTO_ARG(level, GLint), +GL_PROTO_ARG(pname, GLenum), +GL_PROTO_ARG(params, GLint *)) +GL_PROTO_INVOKE(GetTexLevelParameteriv, void, (target, level, pname, params)) +GL_PROTO_END() + +GL_PROTO_BEGIN(TexParameterf, void, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(target, GLenum), +GL_PROTO_ARG(pname, GLenum), +GL_PROTO_ARG(param, GLfloat)) +GL_PROTO_INVOKE(TexParameterf, void, (target, pname, param)) +GL_PROTO_END() + +GL_PROTO_BEGIN(TexParameterfv, void, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(target, GLenum), +GL_PROTO_ARG(pname, GLenum), +GL_PROTO_ARG(params, const GLfloat *)) +GL_PROTO_INVOKE(TexParameterfv, void, (target, pname, params)) +GL_PROTO_END() + +GL_PROTO_BEGIN(TexParameteri, void, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(target, GLenum), +GL_PROTO_ARG(pname, GLenum), +GL_PROTO_ARG(param, GLint)) +GL_PROTO_INVOKE(TexParameteri, void, (target, pname, param)) +GL_PROTO_END() + +GL_PROTO_BEGIN(TexParameteriv, void, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(target, GLenum), +GL_PROTO_ARG(pname, GLenum), +GL_PROTO_ARG(params, const GLint *)) +GL_PROTO_INVOKE(TexParameteriv, void, (target, pname, params)) +GL_PROTO_END() + +GL_PROTO_BEGIN(TexImage2D, void, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(target, GLenum), +GL_PROTO_ARG(level, GLint), +GL_PROTO_ARG(internalformat, GLint), +GL_PROTO_ARG(width, GLsizei), +GL_PROTO_ARG(height, GLsizei), +GL_PROTO_ARG(border, GLint), +GL_PROTO_ARG(format, GLenum), +GL_PROTO_ARG(type, GLenum), +GL_PROTO_ARG(pixels, const GLvoid *)) +GL_PROTO_INVOKE(TexImage2D, void, (target, level, internalformat, width, height, border, format, type, pixels)) +GL_PROTO_END() + +GL_PROTO_BEGIN(TexSubImage2D, void, CORE_1_1) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(target, GLenum), +GL_PROTO_ARG(level, GLint), +GL_PROTO_ARG(xoffset, GLint), +GL_PROTO_ARG(yoffset, GLint), +GL_PROTO_ARG(width, GLsizei), +GL_PROTO_ARG(height, GLsizei), +GL_PROTO_ARG(format, GLenum), +GL_PROTO_ARG(type, GLenum), +GL_PROTO_ARG(UNUSED, GLuint), +GL_PROTO_ARG(pixels, const GLvoid *)) +GL_PROTO_INVOKE(TexSubImage2D, void, (target, level, xoffset, yoffset, width, height, format, type, UNUSED, pixels)) +GL_PROTO_END() + +GL_PROTO_BEGIN(PixelStoref, void, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(pname, GLenum), +GL_PROTO_ARG(param, GLfloat)) +GL_PROTO_INVOKE(PixelStoref, void, (pname, param)) +GL_PROTO_END() + +GL_PROTO_BEGIN(PixelStorei, void, CORE_1_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(pname, GLenum), +GL_PROTO_ARG(param, GLint)) +GL_PROTO_INVOKE(PixelStorei, void, (pname, param)) +GL_PROTO_END() + +GL_PROTO_BEGIN(CreateShader, GLuint, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(type, GLenum)) +GL_PROTO_INVOKE(CreateShader, GLuint, (type)) +GL_PROTO_END() + +GL_PROTO_BEGIN(DeleteShader, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(program, GLuint)) +GL_PROTO_INVOKE(DeleteShader, void, (program)) +GL_PROTO_END() + +GL_PROTO_BEGIN(ShaderSource, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(shader, GLuint), +GL_PROTO_ARG(count, GLsizei), +GL_PROTO_ARG(string, const GLchar * const *), +GL_PROTO_ARG(length, const GLint *)) +GL_PROTO_INVOKE(ShaderSource, void, (shader, count, string, length)) +GL_PROTO_END() + +GL_PROTO_BEGIN(CompileShader, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(shader, GLuint)) +GL_PROTO_INVOKE(CompileShader, void, (shader)) +GL_PROTO_END() + +GL_PROTO_BEGIN(GetShaderiv, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(shader, GLuint), +GL_PROTO_ARG(pname, GLenum), +GL_PROTO_ARG(params, GLint *)) +GL_PROTO_INVOKE(GetShaderiv, void, (shader, pname, params)) +GL_PROTO_END() + +GL_PROTO_BEGIN(GetShaderInfoLog, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(shader, GLuint), +GL_PROTO_ARG(bufSize, GLsizei), +GL_PROTO_ARG(length, GLsizei *), +GL_PROTO_ARG(infoLog, GLchar *)) +GL_PROTO_INVOKE(GetShaderInfoLog, void, (shader, bufSize, length, infoLog)) +GL_PROTO_END() + +GL_PROTO_BEGIN(CreateProgram, GLuint, CORE_2_0) +GL_PROTO_ARG_LIST() +GL_PROTO_INVOKE(CreateProgram, GLuint, ()) +GL_PROTO_END() + +GL_PROTO_BEGIN(DeleteProgram, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(program, GLuint)) +GL_PROTO_INVOKE(DeleteProgram, void, (program)) +GL_PROTO_END() + +GL_PROTO_BEGIN(AttachShader, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(program, GLuint), +GL_PROTO_ARG(shader, GLuint)) +GL_PROTO_INVOKE(AttachShader, void, (program, shader)) +GL_PROTO_END() + +GL_PROTO_BEGIN(LinkProgram, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(program, GLuint)) +GL_PROTO_INVOKE(LinkProgram, void, (program)) +GL_PROTO_END() + +GL_PROTO_BEGIN(UseProgram, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(program, GLuint)) +GL_PROTO_INVOKE(UseProgram, void, (program)) +GL_PROTO_END() + +GL_PROTO_BEGIN(GetProgramiv, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(program, GLuint), +GL_PROTO_ARG(pname, GLenum), +GL_PROTO_ARG(params, GLint *)) +GL_PROTO_INVOKE(GetProgramiv, void, (program, pname, params)) +GL_PROTO_END() + +GL_PROTO_BEGIN(GetProgramInfoLog, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(program, GLuint), +GL_PROTO_ARG(bufSize, GLsizei), +GL_PROTO_ARG(length, GLsizei *), +GL_PROTO_ARG(infoLog, GLchar *)) +GL_PROTO_INVOKE(GetProgramInfoLog, void, (program, bufSize, length, infoLog)) +GL_PROTO_END() + +GL_PROTO_BEGIN(BindAttribLocation, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(program, GLuint), +GL_PROTO_ARG(index, GLuint), +GL_PROTO_ARG(name, const GLchar *)) +GL_PROTO_INVOKE(BindAttribLocation, void, (program, index, name)) +GL_PROTO_END() + +GL_PROTO_BEGIN(GetUniformLocation, GLint, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(program, GLuint), +GL_PROTO_ARG(name, const GLchar *)) +GL_PROTO_INVOKE(GetUniformLocation, GLint, (program, name)) +GL_PROTO_END() + +GL_PROTO_BEGIN(Uniform1f, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(location, GLint), +GL_PROTO_ARG(v0, GLfloat)) +GL_PROTO_INVOKE(Uniform1f, void, (location, v0)) +GL_PROTO_END() + +GL_PROTO_BEGIN(Uniform1fv, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(location, GLint), +GL_PROTO_ARG(count, GLsizei), +GL_PROTO_ARG(value, const GLfloat *)) +GL_PROTO_INVOKE(Uniform1fv, void, (location, count, value)) +GL_PROTO_END() + +GL_PROTO_BEGIN(Uniform1i, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(location, GLint), +GL_PROTO_ARG(v0, GLint)) +GL_PROTO_INVOKE(Uniform1i, void, (location, v0)) +GL_PROTO_END() + +GL_PROTO_BEGIN(Uniform1iv, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(location, GLint), +GL_PROTO_ARG(count, GLsizei), +GL_PROTO_ARG(value, const GLint *)) +GL_PROTO_INVOKE(Uniform1iv, void, (location, count, value)) +GL_PROTO_END() + +GL_PROTO_BEGIN(Uniform2f, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(location, GLint), +GL_PROTO_ARG(v0, GLfloat), +GL_PROTO_ARG(v1, GLfloat)) +GL_PROTO_INVOKE(Uniform2f, void, (location, v0, v1)) +GL_PROTO_END() + +GL_PROTO_BEGIN(Uniform2fv, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(location, GLint), +GL_PROTO_ARG(count, GLsizei), +GL_PROTO_ARG(value, const GLfloat *)) +GL_PROTO_INVOKE(Uniform2fv, void, (location, count, value)) +GL_PROTO_END() + +GL_PROTO_BEGIN(Uniform2i, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(location, GLint), +GL_PROTO_ARG(v0, GLint), +GL_PROTO_ARG(v1, GLint)) +GL_PROTO_INVOKE(Uniform2i, void, (location, v0, v1)) +GL_PROTO_END() + +GL_PROTO_BEGIN(Uniform2iv, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(location, GLint), +GL_PROTO_ARG(count, GLsizei), +GL_PROTO_ARG(value, const GLint *)) +GL_PROTO_INVOKE(Uniform2iv, void, (location, count, value)) +GL_PROTO_END() + +GL_PROTO_BEGIN(Uniform3f, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(location, GLint), +GL_PROTO_ARG(v0, GLfloat), +GL_PROTO_ARG(v1, GLfloat), +GL_PROTO_ARG(v2, GLfloat)) +GL_PROTO_INVOKE(Uniform3f, void, (location, v0, v1, v2)) +GL_PROTO_END() + +GL_PROTO_BEGIN(Uniform3fv, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(location, GLint), +GL_PROTO_ARG(count, GLsizei), +GL_PROTO_ARG(value, const GLfloat *)) +GL_PROTO_INVOKE(Uniform3fv, void, (location, count, value)) +GL_PROTO_END() + +GL_PROTO_BEGIN(Uniform3i, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(location, GLint), +GL_PROTO_ARG(v0, GLint), +GL_PROTO_ARG(v1, GLint), +GL_PROTO_ARG(v2, GLint)) +GL_PROTO_INVOKE(Uniform3i, void, (location, v0, v1, v2)) +GL_PROTO_END() + +GL_PROTO_BEGIN(Uniform3iv, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(location, GLint), +GL_PROTO_ARG(count, GLsizei), +GL_PROTO_ARG(value, const GLint *)) +GL_PROTO_INVOKE(Uniform3iv, void, (location, count, value)) +GL_PROTO_END() + +GL_PROTO_BEGIN(Uniform4f, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(location, GLint), +GL_PROTO_ARG(v0, GLfloat), +GL_PROTO_ARG(v1, GLfloat), +GL_PROTO_ARG(v2, GLfloat), +GL_PROTO_ARG(v3, GLfloat)) +GL_PROTO_INVOKE(Uniform4f, void, (location, v0, v1, v2, v3)) +GL_PROTO_END() + +GL_PROTO_BEGIN(Uniform4fv, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(location, GLint), +GL_PROTO_ARG(count, GLsizei), +GL_PROTO_ARG(value, const GLfloat *)) +GL_PROTO_INVOKE(Uniform4fv, void, (location, count, value)) +GL_PROTO_END() + +GL_PROTO_BEGIN(Uniform4i, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(location, GLint), +GL_PROTO_ARG(v0, GLint), +GL_PROTO_ARG(v1, GLint), +GL_PROTO_ARG(v2, GLint), +GL_PROTO_ARG(v3, GLint)) +GL_PROTO_INVOKE(Uniform4i, void, (location, v0, v1, v2, v3)) +GL_PROTO_END() + +GL_PROTO_BEGIN(Uniform4iv, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(location, GLint), +GL_PROTO_ARG(count, GLsizei), +GL_PROTO_ARG(value, const GLint *)) +GL_PROTO_INVOKE(Uniform4iv, void, (location, count, value)) +GL_PROTO_END() + +GL_PROTO_BEGIN(UniformMatrix2fv, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(location, GLint), +GL_PROTO_ARG(count, GLsizei), +GL_PROTO_ARG(transpose, GLboolean), +GL_PROTO_ARG(value, const GLfloat *)) +GL_PROTO_INVOKE(UniformMatrix2fv, void, (location, count, transpose, value)) +GL_PROTO_END() + +GL_PROTO_BEGIN(UniformMatrix3fv, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(location, GLint), +GL_PROTO_ARG(count, GLsizei), +GL_PROTO_ARG(transpose, GLboolean), +GL_PROTO_ARG(value, const GLfloat *)) +GL_PROTO_INVOKE(UniformMatrix3fv, void, (location, count, transpose, value)) +GL_PROTO_END() + +GL_PROTO_BEGIN(UniformMatrix4fv, void, CORE_2_0) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(location, GLint), +GL_PROTO_ARG(count, GLsizei), +GL_PROTO_ARG(transpose, GLboolean), +GL_PROTO_ARG(value, const GLfloat *)) +GL_PROTO_INVOKE(UniformMatrix4fv, void, (location, count, transpose, value)) +GL_PROTO_END() + +GL_PROTO_BEGIN(EGLImageTargetTexture2DOES, void, OES_EGL_image) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(target, GLenum), +GL_PROTO_ARG(image, void *)) +GL_PROTO_INVOKE(EGLImageTargetTexture2DOES, void, (target, image)) +GL_PROTO_END() + +GL_PROTO_BEGIN(EGLImageTargetRenderbufferStorageOES, void, OES_EGL_image) +GL_PROTO_ARG_LIST( +GL_PROTO_ARG(target, GLenum), +GL_PROTO_ARG(image, void *)) +GL_PROTO_INVOKE(EGLImageTargetRenderbufferStorageOES, void, (target, image)) +GL_PROTO_END() + +GL_DEFINE_EXTENSION(CORE_1_0) +GL_DEFINE_EXTENSION(CORE_1_1) +GL_DEFINE_EXTENSION(CORE_1_3) +GL_DEFINE_EXTENSION(CORE_2_0) +GL_DEFINE_EXTENSION(OES_EGL_image) + +#undef EGL_PROTO_BEGIN +#undef EGL_PROTO_BEGIN_I +#undef EGL_PROTO_ARG_LIST +#undef EGL_PROTO_ARG +#undef EGL_PROTO_INVOKE +#undef EGL_PROTO_INVOKE_I +#undef EGL_PROTO_END +#undef EGL_DEFINE_EXTENSION +#undef EGL_DEFINE_EXTENSION_I + +#undef GL_PROTO_BEGIN +#undef GL_PROTO_BEGIN_I +#undef GL_PROTO_ARG_LIST +#undef GL_PROTO_ARG +#undef GL_PROTO_INVOKE +#undef GL_PROTO_INVOKE_I +#undef GL_PROTO_END +#undef GL_DEFINE_EXTENSION +#undef GL_DEFINE_EXTENSION_I + +#undef GL_PROTO_GEN_CONCAT5 +#undef GL_PROTO_GEN_CONCAT5_I +#undef GL_PROTO_GEN_CONCAT4 +#undef GL_PROTO_GEN_CONCAT4_I +#undef GL_PROTO_GEN_CONCAT3 +#undef GL_PROTO_GEN_CONCAT3_I +#undef GL_PROTO_GEN_CONCAT2 +#undef GL_PROTO_GEN_CONCAT2_I +#undef GL_PROTO_GEN_CONCAT +#undef GL_PROTO_GEN_STRING +#undef GL_PROTO_GEN_STRING_I diff --git a/gst-libs/gst/vaapi/gstvaapiblend.c b/gst-libs/gst/vaapi/gstvaapiblend.c new file mode 100644 index 0000000000..07a1ab6ed8 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiblend.c @@ -0,0 +1,326 @@ +/* + * gstvaapiblend.c - Video processing blend + * + * Copyright (C) 2019 Intel Corporation + * Author: U. Artie Eoff + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include "gstvaapicompat.h" +#include "gstvaapiblend.h" +#include "gstvaapiutils.h" +#include "gstvaapivalue.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapisurface_priv.h" + +struct _GstVaapiBlend +{ + GstObject parent_instance; + + GstVaapiDisplay *display; + + VAConfigID va_config; + VAContextID va_context; + + guint32 flags; +}; + +typedef struct _GstVaapiBlendClass GstVaapiBlendClass; +struct _GstVaapiBlendClass +{ + GstObjectClass parent_class; +}; + +GST_DEBUG_CATEGORY_STATIC (gst_debug_vaapi_blend); +#ifndef GST_DISABLE_GST_DEBUG +#define GST_CAT_DEFAULT gst_debug_vaapi_blend +#else +#define GST_CAT_DEFAULT NULL +#endif + +G_DEFINE_TYPE_WITH_CODE (GstVaapiBlend, gst_vaapi_blend, GST_TYPE_OBJECT, + GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi_blend, "vaapiblend", 0, + "VA-API Blend")); + +enum +{ + PROP_DISPLAY = 1, +}; + +static void +gst_vaapi_blend_set_property (GObject * object, guint property_id, + const GValue * value, GParamSpec * pspec) +{ + GstVaapiBlend *const blend = GST_VAAPI_BLEND (object); + + switch (property_id) { + case PROP_DISPLAY:{ + GstVaapiDisplay *display = g_value_get_object (value);; + if (display) { + if (GST_VAAPI_DISPLAY_HAS_VPP (display)) { + blend->display = gst_object_ref (display); + } else { + GST_WARNING_OBJECT (blend, "GstVaapiDisplay doesn't support VPP"); + } + } + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +gst_vaapi_blend_get_property (GObject * object, guint property_id, + GValue * value, GParamSpec * pspec) +{ + GstVaapiBlend *const blend = GST_VAAPI_BLEND (object); + + switch (property_id) { + case PROP_DISPLAY: + g_value_set_object (value, blend->display); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +gst_vaapi_blend_finalize (GObject * object) +{ + GstVaapiBlend *const blend = GST_VAAPI_BLEND (object); + + if (!blend->display) + goto bail; + + GST_VAAPI_DISPLAY_LOCK (blend->display); + + if (blend->va_context != VA_INVALID_ID) { + vaDestroyContext (GST_VAAPI_DISPLAY_VADISPLAY (blend->display), + blend->va_context); + blend->va_context = VA_INVALID_ID; + } + + if (blend->va_config != VA_INVALID_ID) { + vaDestroyConfig (GST_VAAPI_DISPLAY_VADISPLAY (blend->display), + blend->va_config); + blend->va_config = VA_INVALID_ID; + } + + GST_VAAPI_DISPLAY_UNLOCK (blend->display); + + gst_vaapi_display_replace (&blend->display, NULL); + +bail: + G_OBJECT_CLASS (gst_vaapi_blend_parent_class)->finalize (object); +} + +static void +gst_vaapi_blend_class_init (GstVaapiBlendClass * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = gst_vaapi_blend_set_property; + object_class->get_property = gst_vaapi_blend_get_property; + object_class->finalize = gst_vaapi_blend_finalize; + + g_object_class_install_property (object_class, PROP_DISPLAY, + g_param_spec_object ("display", "Gst VA-API Display", + "The VA-API display object to use", GST_TYPE_VAAPI_DISPLAY, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME)); +} + +static void +gst_vaapi_blend_init (GstVaapiBlend * blend) +{ + blend->display = NULL; + blend->va_config = VA_INVALID_ID; + blend->va_context = VA_INVALID_ID; + blend->flags = 0; +} + +static gboolean +gst_vaapi_blend_initialize (GstVaapiBlend * blend) +{ + VAStatus status; + VAProcPipelineCaps pipeline_caps = { 0, }; + + if (!blend->display) + return FALSE; + + status = vaCreateConfig (GST_VAAPI_DISPLAY_VADISPLAY (blend->display), + VAProfileNone, VAEntrypointVideoProc, NULL, 0, &blend->va_config); + if (!vaapi_check_status (status, "vaCreateConfig() [VPP]")) + return FALSE; + + status = vaCreateContext (GST_VAAPI_DISPLAY_VADISPLAY (blend->display), + blend->va_config, 0, 0, 0, NULL, 0, &blend->va_context); + if (!vaapi_check_status (status, "vaCreateContext() [VPP]")) + return FALSE; + +#if VA_CHECK_VERSION(1,1,0) + status = + vaQueryVideoProcPipelineCaps (GST_VAAPI_DISPLAY_VADISPLAY + (blend->display), blend->va_context, NULL, 0, &pipeline_caps); + if (vaapi_check_status (status, "vaQueryVideoProcPipelineCaps()")) + blend->flags = pipeline_caps.blend_flags; + + if (!(blend->flags & VA_BLEND_GLOBAL_ALPHA)) { + GST_WARNING_OBJECT (blend, "VPP does not support global alpha blending"); + return FALSE; + } +#else + return FALSE; +#endif + + return TRUE; +} + +GstVaapiBlend * +gst_vaapi_blend_new (GstVaapiDisplay * display) +{ + GstVaapiBlend *blend = g_object_new (GST_TYPE_VAAPI_BLEND, + "display", display, NULL); + + if (!gst_vaapi_blend_initialize (blend)) { + gst_object_unref (blend); + blend = NULL; + } + + return blend; +} + +void +gst_vaapi_blend_replace (GstVaapiBlend ** old_blend_ptr, + GstVaapiBlend * new_blend) +{ + g_return_if_fail (old_blend_ptr != NULL); + + gst_object_replace ((GstObject **) old_blend_ptr, GST_OBJECT (new_blend)); +} + +static gboolean +gst_vaapi_blend_process_unlocked (GstVaapiBlend * blend, + GstVaapiSurface * output, GstVaapiBlendSurfaceNextFunc next, + gpointer user_data) +{ + VAStatus va_status; + VADisplay va_display; + GstVaapiBlendSurface *current; + + va_display = GST_VAAPI_DISPLAY_VADISPLAY (blend->display); + + va_status = vaBeginPicture (va_display, blend->va_context, + GST_VAAPI_SURFACE_ID (output)); + if (!vaapi_check_status (va_status, "vaBeginPicture()")) + return FALSE; + + current = next (user_data); + for (; current; current = next (user_data)) { + VAProcPipelineParameterBuffer *param = NULL; + VABufferID id = VA_INVALID_ID; + VARectangle src_rect = { 0, }; + VARectangle dst_rect = { 0, }; +#if VA_CHECK_VERSION(1,1,0) + VABlendState blend_state; +#endif + + if (!current->surface) + return FALSE; + + /* Build surface region (source) */ + src_rect.width = GST_VAAPI_SURFACE_WIDTH (current->surface); + src_rect.height = GST_VAAPI_SURFACE_HEIGHT (current->surface); + if (current->crop) { + if ((current->crop->x + current->crop->width > src_rect.width) || + (current->crop->y + current->crop->height > src_rect.height)) + return FALSE; + src_rect.x = current->crop->x; + src_rect.y = current->crop->y; + src_rect.width = current->crop->width; + src_rect.height = current->crop->height; + } + + /* Build output region (target) */ + dst_rect.x = current->target.x; + dst_rect.y = current->target.y; + dst_rect.width = current->target.width; + dst_rect.height = current->target.height; + + if (!vaapi_create_buffer (va_display, blend->va_context, + VAProcPipelineParameterBufferType, sizeof (*param), NULL, &id, + (gpointer *) & param)) + return FALSE; + + memset (param, 0, sizeof (*param)); + + param->surface = GST_VAAPI_SURFACE_ID (current->surface); + param->surface_region = &src_rect; + param->output_region = &dst_rect; + param->output_background_color = 0xff000000; + +#if VA_CHECK_VERSION(1,1,0) + blend_state.flags = VA_BLEND_GLOBAL_ALPHA; + blend_state.global_alpha = current->alpha; + param->blend_state = &blend_state; +#endif + + vaapi_unmap_buffer (va_display, id, NULL); + + va_status = vaRenderPicture (va_display, blend->va_context, &id, 1); + vaapi_destroy_buffer (va_display, &id); + if (!vaapi_check_status (va_status, "vaRenderPicture()")) + return FALSE; + } + + va_status = vaEndPicture (va_display, blend->va_context); + if (!vaapi_check_status (va_status, "vaEndPicture()")) + return FALSE; + + return TRUE; +} + +/** + * gst_vaapi_blend_process: + * @blend: a #GstVaapiBlend instance. + * @output: a #GstVaapiSurface to be composed. + * @next: a function to fetch the next #GstVaapiBlendSurface to + * process. + * @data: state storage for @next. + * + * This function will process all the input surfaces defined through + * #GstVaapiBlendSurface and will blend them onto the @output surface. + * + * Returns: %TRUE if the blend process succeed; otherwise %FALSE. + **/ +gboolean +gst_vaapi_blend_process (GstVaapiBlend * blend, GstVaapiSurface * output, + GstVaapiBlendSurfaceNextFunc next, gpointer user_data) +{ + gboolean result; + + g_return_val_if_fail (blend != NULL, FALSE); + g_return_val_if_fail (output != NULL, FALSE); + g_return_val_if_fail (next != NULL, FALSE); + + GST_VAAPI_DISPLAY_LOCK (blend->display); + result = gst_vaapi_blend_process_unlocked (blend, output, next, user_data); + GST_VAAPI_DISPLAY_UNLOCK (blend->display); + + return result; +} diff --git a/gst-libs/gst/vaapi/gstvaapiblend.h b/gst-libs/gst/vaapi/gstvaapiblend.h new file mode 100644 index 0000000000..8c94128394 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiblend.h @@ -0,0 +1,68 @@ +/* + * gstvaapiblend.h - Video processing blend + * + * Copyright (C) 2019 Intel Corporation + * Author: U. Artie Eoff + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_BLEND_H +#define GST_VAAPI_BLEND_H + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_BLEND \ + (gst_vaapi_blend_get_type ()) +#define GST_VAAPI_BLEND(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_BLEND, GstVaapiBlend)) +#define GST_IS_VAAPI_BLEND(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_BLEND)) + +typedef struct _GstVaapiBlend GstVaapiBlend; +typedef struct _GstVaapiBlendSurface GstVaapiBlendSurface; + +struct _GstVaapiBlendSurface +{ + GstVaapiSurface const *surface; + const GstVaapiRectangle *crop; + GstVaapiRectangle target; + gdouble alpha; +}; + +typedef GstVaapiBlendSurface* (*GstVaapiBlendSurfaceNextFunc)(gpointer data); + +GstVaapiBlend * +gst_vaapi_blend_new (GstVaapiDisplay * display); + +void +gst_vaapi_blend_replace (GstVaapiBlend ** old_blend_ptr, + GstVaapiBlend * new_blend); + +gboolean +gst_vaapi_blend_process (GstVaapiBlend * blend, GstVaapiSurface * output, + GstVaapiBlendSurfaceNextFunc next, gpointer user_data); + +GType +gst_vaapi_blend_get_type (void) G_GNUC_CONST; + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiBlend, gst_object_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_FILTER_H */ diff --git a/gst-libs/gst/vaapi/gstvaapibufferproxy.c b/gst-libs/gst/vaapi/gstvaapibufferproxy.c new file mode 100644 index 0000000000..71547eea26 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapibufferproxy.c @@ -0,0 +1,297 @@ +/* + * gstvaapibufferproxy.c - Buffer proxy abstraction + * + * Copyright (C) 2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include "gstvaapicompat.h" +#include "gstvaapibufferproxy.h" +#include "gstvaapibufferproxy_priv.h" +#include "gstvaapisurface_priv.h" +#include "gstvaapiutils.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +static gboolean +gst_vaapi_buffer_proxy_acquire_handle (GstVaapiBufferProxy * proxy) +{ + GstVaapiDisplay *display; + const guint mem_type = proxy->va_info.mem_type; + VAStatus va_status; + + if (proxy->va_info.handle) + return TRUE; + + if (!proxy->surface || proxy->va_buf == VA_INVALID_ID) + return FALSE; + + display = GST_VAAPI_SURFACE_DISPLAY (GST_VAAPI_SURFACE (proxy->surface)); + + GST_VAAPI_DISPLAY_LOCK (display); + va_status = vaAcquireBufferHandle (GST_VAAPI_DISPLAY_VADISPLAY (display), + proxy->va_buf, &proxy->va_info); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!vaapi_check_status (va_status, "vaAcquireBufferHandle()")) + return FALSE; + if (proxy->va_info.mem_type != mem_type) + return FALSE; + return TRUE; +} + +static gboolean +gst_vaapi_buffer_proxy_release_handle (GstVaapiBufferProxy * proxy) +{ + GstVaapiDisplay *display; + VAStatus va_status; + + if (!proxy->va_info.handle) + return TRUE; + + if (!proxy->surface || proxy->va_buf == VA_INVALID_ID) + return FALSE; + + display = GST_VAAPI_SURFACE_DISPLAY (GST_VAAPI_SURFACE (proxy->surface)); + + GST_VAAPI_DISPLAY_LOCK (display); + va_status = vaReleaseBufferHandle (GST_VAAPI_DISPLAY_VADISPLAY (display), + proxy->va_buf); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!vaapi_check_status (va_status, "vaReleaseBufferHandle()")) + return FALSE; + return TRUE; +} + +static void +gst_vaapi_buffer_proxy_finalize (GstVaapiBufferProxy * proxy) +{ + gst_vaapi_buffer_proxy_release_handle (proxy); + + /* Notify the user function that the object is now destroyed */ + if (proxy->destroy_func) + proxy->destroy_func (proxy->destroy_data); + + proxy->surface = NULL; +} + +static inline const GstVaapiMiniObjectClass * +gst_vaapi_buffer_proxy_class (void) +{ + static const GstVaapiMiniObjectClass GstVaapiBufferProxyClass = { + sizeof (GstVaapiBufferProxy), + (GDestroyNotify) gst_vaapi_buffer_proxy_finalize + }; + return &GstVaapiBufferProxyClass; +} + +GstVaapiBufferProxy * +gst_vaapi_buffer_proxy_new (guintptr handle, guint type, gsize size, + GDestroyNotify destroy_func, gpointer user_data) +{ + GstVaapiBufferProxy *proxy; + + g_return_val_if_fail (handle != 0, NULL); + g_return_val_if_fail (size > 0, NULL); + + proxy = (GstVaapiBufferProxy *) + gst_vaapi_mini_object_new (gst_vaapi_buffer_proxy_class ()); + if (!proxy) + return NULL; + + proxy->surface = NULL; + proxy->destroy_func = destroy_func; + proxy->destroy_data = user_data; + proxy->type = type; + proxy->va_buf = VA_INVALID_ID; + proxy->va_info.handle = handle; + proxy->va_info.type = VAImageBufferType; + proxy->va_info.mem_type = from_GstVaapiBufferMemoryType (proxy->type); + proxy->va_info.mem_size = size; + if (!proxy->va_info.mem_type) + goto error_unsupported_mem_type; + return proxy; + + /* ERRORS */ +error_unsupported_mem_type: + { + GST_ERROR ("unsupported buffer type (%d)", proxy->type); + gst_vaapi_buffer_proxy_unref (proxy); + return NULL; + } +} + +GstVaapiBufferProxy * +gst_vaapi_buffer_proxy_new_from_surface (GstMiniObject * surface, + VABufferID buf_id, guint type, GDestroyNotify destroy_func, gpointer data) +{ + GstVaapiBufferProxy *proxy; + + g_return_val_if_fail (surface != NULL, NULL); + + proxy = (GstVaapiBufferProxy *) + gst_vaapi_mini_object_new (gst_vaapi_buffer_proxy_class ()); + if (!proxy) + return NULL; + + proxy->surface = surface; + proxy->destroy_func = destroy_func; + proxy->destroy_data = data; + proxy->type = type; + proxy->va_buf = buf_id; + memset (&proxy->va_info, 0, sizeof (proxy->va_info)); + proxy->va_info.mem_type = from_GstVaapiBufferMemoryType (proxy->type); + if (!proxy->va_info.mem_type) + goto error_unsupported_mem_type; + if (!gst_vaapi_buffer_proxy_acquire_handle (proxy)) + goto error_acquire_handle; + return proxy; + + /* ERRORS */ +error_unsupported_mem_type: + { + GST_ERROR ("unsupported buffer type (%d)", proxy->type); + gst_vaapi_buffer_proxy_unref (proxy); + return NULL; + } +error_acquire_handle: + { + GST_ERROR ("failed to acquire the underlying VA buffer handle"); + gst_vaapi_buffer_proxy_unref (proxy); + return NULL; + } +} + +/** + * gst_vaapi_buffer_proxy_ref: + * @proxy: a #GstVaapiBufferProxy + * + * Atomically increases the reference count of the given @proxy by one. + * + * Returns: The same @proxy argument + */ +GstVaapiBufferProxy * +gst_vaapi_buffer_proxy_ref (GstVaapiBufferProxy * proxy) +{ + g_return_val_if_fail (proxy != NULL, NULL); + + return (GstVaapiBufferProxy *) + gst_vaapi_mini_object_ref (GST_VAAPI_MINI_OBJECT (proxy)); +} + +/** + * gst_vaapi_buffer_proxy_unref: + * @proxy: a #GstVaapiBufferProxy + * + * Atomically decreases the reference count of the @proxy by one. If + * the reference count reaches zero, the object will be free'd. + */ +void +gst_vaapi_buffer_proxy_unref (GstVaapiBufferProxy * proxy) +{ + g_return_if_fail (proxy != NULL); + + gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (proxy)); +} + +/** + * gst_vaapi_buffer_proxy_replace: + * @old_proxy_ptr: a pointer to a #GstVaapiBufferProxy + * @new_proxy: a #GstVaapiBufferProxy + * + * Atomically replaces the proxy object held in @old_proxy_ptr with + * @new_proxy. This means that @old_proxy_ptr shall reference a valid + * object. However, @new_proxy can be NULL. + */ +void +gst_vaapi_buffer_proxy_replace (GstVaapiBufferProxy ** old_proxy_ptr, + GstVaapiBufferProxy * new_proxy) +{ + g_return_if_fail (old_proxy_ptr != NULL); + + gst_vaapi_mini_object_replace ((GstVaapiMiniObject **) (old_proxy_ptr), + GST_VAAPI_MINI_OBJECT (new_proxy)); +} + +/** + * gst_vaapi_buffer_proxy_get_type: + * @proxy: a #GstVaapiBufferProxy + * + * Returns the underlying VA buffer memory type. + * + * Return value: the buffer memory type + */ +guint +gst_vaapi_buffer_proxy_get_type (GstVaapiBufferProxy * proxy) +{ + g_return_val_if_fail (proxy != NULL, 0); + + return GST_VAAPI_BUFFER_PROXY_TYPE (proxy); +} + +/** + * gst_vaapi_buffer_proxy_get_handle: + * @proxy: a #GstVaapiBufferProxy + * + * Returns the underlying VA buffer handle stored in the @proxy. + * + * Return value: the buffer handle + */ +guintptr +gst_vaapi_buffer_proxy_get_handle (GstVaapiBufferProxy * proxy) +{ + g_return_val_if_fail (proxy != NULL, 0); + + return GST_VAAPI_BUFFER_PROXY_HANDLE (proxy); +} + +/** + * gst_vaapi_buffer_proxy_get_size: + * @proxy: a #GstVaapiBufferProxy + * + * Returns the underlying VA buffer memory size in bytes. + * + * Return value: the buffer size in bytes + */ +gsize +gst_vaapi_buffer_proxy_get_size (GstVaapiBufferProxy * proxy) +{ + g_return_val_if_fail (proxy != NULL, 0); + + return GST_VAAPI_BUFFER_PROXY_SIZE (proxy); +} + +/** + * gst_vaapi_buffer_proxy_release_data: + * @proxy: a #GstVaapiBufferProxy + * + * Notifies the user to destroy the user's data, though the @proxy is + * not going to be destroyed. + **/ +void +gst_vaapi_buffer_proxy_release_data (GstVaapiBufferProxy * proxy) +{ + g_return_if_fail (proxy != NULL); + + if (proxy->destroy_func) { + proxy->destroy_func (proxy->destroy_data); + proxy->destroy_func = NULL; + proxy->destroy_data = NULL; + } +} diff --git a/gst-libs/gst/vaapi/gstvaapibufferproxy.h b/gst-libs/gst/vaapi/gstvaapibufferproxy.h new file mode 100644 index 0000000000..4b1cebec24 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapibufferproxy.h @@ -0,0 +1,106 @@ +/* + * gstvaapibufferproxy.h - Buffer proxy abstraction + * + * Copyright (C) 2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_BUFFER_PROXY_H +#define GST_VAAPI_BUFFER_PROXY_H + +G_BEGIN_DECLS + +#define GST_VAAPI_BUFFER_PROXY(obj) \ + ((GstVaapiBufferProxy *)(obj)) + +/** + * GST_VAAPI_BUFFER_PROXY_TYPE: + * @buf: a #GstVaapiBufferProxy + * + * Macro that evaluates to the type of the underlying VA buffer @buf + */ +#define GST_VAAPI_BUFFER_PROXY_TYPE(buf) \ + gst_vaapi_buffer_proxy_get_type (GST_VAAPI_BUFFER_PROXY (buf)) + +/** + * GST_VAAPI_BUFFER_PROXY_HANDLE: + * @buf: a #GstVaapiBufferProxy + * + * Macro that evaluates to the handle of the underlying VA buffer @buf + */ +#define GST_VAAPI_BUFFER_PROXY_HANDLE(buf) \ + gst_vaapi_buffer_proxy_get_handle (GST_VAAPI_BUFFER_PROXY (buf)) + +/** + * GST_VAAPI_BUFFER_PROXY_SIZE: + * @buf: a #GstVaapiBufferProxy + * + * Macro that evaluates to the size of the underlying VA buffer @buf + */ +#define GST_VAAPI_BUFFER_PROXY_SIZE(buf) \ + gst_vaapi_buffer_proxy_get_size (GST_VAAPI_BUFFER_PROXY (buf)) + +typedef struct _GstVaapiBufferProxy GstVaapiBufferProxy; + +/** + * GstVaapiBufferMemoryType: + * @GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF: DRM PRIME buffer memory type (old version). + * @GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF2: DRM PRIME buffer memory type. + * @GST_VAAPI_BUFFER_MEMORY_TYPE_GEM_BUF: Kernel DRM buffer memory type. + * @GST_VAAPI_BUFFER_MEMORY_TYPE_V4L2: V4L2 buffer memory type. + * @GST_VAAPI_BUFFER_MEMORY_TYPE_USER_PTR: User pointer memory type. + * + * Set of underlying VA buffer memory types. + */ +typedef enum { + GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF = 1, + GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF2, + GST_VAAPI_BUFFER_MEMORY_TYPE_GEM_BUF, + GST_VAAPI_BUFFER_MEMORY_TYPE_V4L2, + GST_VAAPI_BUFFER_MEMORY_TYPE_USER_PTR, +} GstVaapiBufferMemoryType; + +GstVaapiBufferProxy * +gst_vaapi_buffer_proxy_new (guintptr handle, guint type, gsize size, + GDestroyNotify destroy_func, gpointer user_data); + +GstVaapiBufferProxy * +gst_vaapi_buffer_proxy_ref (GstVaapiBufferProxy * proxy); + +void +gst_vaapi_buffer_proxy_unref (GstVaapiBufferProxy * proxy); + +void +gst_vaapi_buffer_proxy_replace (GstVaapiBufferProxy ** old_proxy_ptr, + GstVaapiBufferProxy * new_proxy); + +guint +gst_vaapi_buffer_proxy_get_type (GstVaapiBufferProxy * proxy); + +guintptr +gst_vaapi_buffer_proxy_get_handle (GstVaapiBufferProxy * proxy); + +gsize +gst_vaapi_buffer_proxy_get_size (GstVaapiBufferProxy * proxy); + +void +gst_vaapi_buffer_proxy_release_data (GstVaapiBufferProxy * proxy); + +G_END_DECLS + +#endif /* GST_VAAPI_BUFFER_PROXY_H */ diff --git a/gst-libs/gst/vaapi/gstvaapibufferproxy_priv.h b/gst-libs/gst/vaapi/gstvaapibufferproxy_priv.h new file mode 100644 index 0000000000..445201deac --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapibufferproxy_priv.h @@ -0,0 +1,88 @@ +/* + * gstvaapibufferproxy_priv.h - Buffer proxy abstraction (private definitions) + * + * Copyright (C) 2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_BUFFER_PROXY_PRIV_H +#define GST_VAAPI_BUFFER_PROXY_PRIV_H + +#include "gstvaapibufferproxy.h" +#include "gstvaapiminiobject.h" + +G_BEGIN_DECLS + +/** + * GST_VAAPI_BUFFER_PROXY_TYPE: + * @buf: a #GstVaapiBufferProxy + * + * Macro that evaluates to the type of the underlying VA buffer @buf + */ +#undef GST_VAAPI_BUFFER_PROXY_TYPE +#define GST_VAAPI_BUFFER_PROXY_TYPE(buf) \ + (GST_VAAPI_BUFFER_PROXY (buf)->type) + +/** + * GST_VAAPI_BUFFER_PROXY_HANDLE: + * @buf: a #GstVaapiBufferProxy + * + * Macro that evaluates to the handle of the underlying VA buffer @buf + */ +#undef GST_VAAPI_BUFFER_PROXY_HANDLE +#define GST_VAAPI_BUFFER_PROXY_HANDLE(buf) \ + (GST_VAAPI_BUFFER_PROXY (buf)->va_info.handle) + +/** + * GST_VAAPI_BUFFER_PROXY_SIZE: + * @buf: a #GstVaapiBufferProxy + * + * Macro that evaluates to the size of the underlying VA buffer @buf + */ +#undef GST_VAAPI_BUFFER_PROXY_SIZE +#define GST_VAAPI_BUFFER_PROXY_SIZE(buf) \ + (GST_VAAPI_BUFFER_PROXY (buf)->va_info.mem_size) + +struct _GstVaapiBufferProxy { + /*< private >*/ + GstVaapiMiniObject parent_instance; + GstMiniObject *surface; + + GDestroyNotify destroy_func; + gpointer destroy_data; + guint type; + VABufferID va_buf; + VABufferInfo va_info; +}; + +G_GNUC_INTERNAL +GstVaapiBufferProxy * +gst_vaapi_buffer_proxy_new_from_surface (GstMiniObject * surface, + VABufferID buf_id, guint type, GDestroyNotify destroy_func, gpointer data); + +G_GNUC_INTERNAL +guint +from_GstVaapiBufferMemoryType (guint type); + +G_GNUC_INTERNAL +guint +to_GstVaapiBufferMemoryType (guint va_type); + +G_END_DECLS + +#endif /* GST_VAAPI_BUFFER_PROXY_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapicodec_objects.c b/gst-libs/gst/vaapi/gstvaapicodec_objects.c new file mode 100644 index 0000000000..1bdd93b24e --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapicodec_objects.c @@ -0,0 +1,255 @@ +/* + * gstvaapicodec_objects.c - VA codec objects abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include +#include "gstvaapicodec_objects.h" +#include "gstvaapidecoder_priv.h" +#include "gstvaapicompat.h" +#include "gstvaapiutils.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +/* ------------------------------------------------------------------------- */ +/* --- Base Codec Object --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_CODEC_OBJECT_GET_CLASS(object) \ + gst_vaapi_codec_object_get_class(object) + +const GstVaapiCodecObjectClass * +gst_vaapi_codec_object_get_class (GstVaapiCodecObject * object) +{ + return (const GstVaapiCodecObjectClass *) + GST_VAAPI_MINI_OBJECT_GET_CLASS (object); +} + +static gboolean +gst_vaapi_codec_object_create (GstVaapiCodecObject * object, + const GstVaapiCodecObjectConstructorArgs * args) +{ + const GstVaapiCodecObjectClass *klass; + + g_return_val_if_fail (args->param_size > 0, FALSE); + + if (GST_VAAPI_MINI_OBJECT_FLAG_IS_SET (object, + GST_VAAPI_CODEC_OBJECT_FLAG_CONSTRUCTED)) + return TRUE; + + klass = GST_VAAPI_CODEC_OBJECT_GET_CLASS (object); + if (!klass->create || !klass->create (object, args)) + return FALSE; + + GST_VAAPI_MINI_OBJECT_FLAG_SET (object, + GST_VAAPI_CODEC_OBJECT_FLAG_CONSTRUCTED); + return TRUE; +} + +GstVaapiCodecObject * +gst_vaapi_codec_object_new_with_param_num (const GstVaapiCodecObjectClass * + object_class, GstVaapiCodecBase * codec, gconstpointer param, + guint param_size, guint param_num, gconstpointer data, + guint data_size, guint flags) +{ + GstVaapiCodecObject *obj; + GstVaapiCodecObjectConstructorArgs args; + + obj = (GstVaapiCodecObject *) + gst_vaapi_mini_object_new0 (GST_VAAPI_MINI_OBJECT_CLASS (object_class)); + if (!obj) + return NULL; + + obj = GST_VAAPI_CODEC_OBJECT (obj); + obj->codec = codec; + + args.param = param; + args.param_size = param_size; + args.param_num = param_num; + args.data = data; + args.data_size = data_size; + args.flags = flags; + + if (gst_vaapi_codec_object_create (obj, &args)) + return obj; + + gst_vaapi_codec_object_unref (obj); + return NULL; +} + +GstVaapiCodecObject * +gst_vaapi_codec_object_new (const GstVaapiCodecObjectClass * object_class, + GstVaapiCodecBase * codec, gconstpointer param, guint param_size, + gconstpointer data, guint data_size, guint flags) +{ + return gst_vaapi_codec_object_new_with_param_num (object_class, codec, param, + param_size, 1, data, data_size, flags); +} + +#define GET_DECODER(obj) GST_VAAPI_DECODER_CAST((obj)->parent_instance.codec) +#define GET_VA_DISPLAY(obj) GET_DECODER(obj)->va_display +#define GET_VA_CONTEXT(obj) GET_DECODER(obj)->va_context + +/* ------------------------------------------------------------------------- */ +/* --- Inverse Quantization Matrices --- */ +/* ------------------------------------------------------------------------- */ + +GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiIqMatrix, gst_vaapi_iq_matrix); + +void +gst_vaapi_iq_matrix_destroy (GstVaapiIqMatrix * iq_matrix) +{ + vaapi_destroy_buffer (GET_VA_DISPLAY (iq_matrix), &iq_matrix->param_id); + iq_matrix->param = NULL; +} + +gboolean +gst_vaapi_iq_matrix_create (GstVaapiIqMatrix * iq_matrix, + const GstVaapiCodecObjectConstructorArgs * args) +{ + iq_matrix->param_id = VA_INVALID_ID; + return vaapi_create_buffer (GET_VA_DISPLAY (iq_matrix), + GET_VA_CONTEXT (iq_matrix), VAIQMatrixBufferType, + args->param_size, args->param, &iq_matrix->param_id, &iq_matrix->param); +} + +GstVaapiIqMatrix * +gst_vaapi_iq_matrix_new (GstVaapiDecoder * decoder, + gconstpointer param, guint param_size) +{ + GstVaapiCodecObject *object; + + object = gst_vaapi_codec_object_new (&GstVaapiIqMatrixClass, + GST_VAAPI_CODEC_BASE (decoder), param, param_size, NULL, 0, 0); + if (!object) + return NULL; + return GST_VAAPI_IQ_MATRIX_CAST (object); +} + +/* ------------------------------------------------------------------------- */ +/* --- VC-1 Bit Planes --- */ +/* ------------------------------------------------------------------------- */ + +GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiBitPlane, gst_vaapi_bitplane); + +void +gst_vaapi_bitplane_destroy (GstVaapiBitPlane * bitplane) +{ + vaapi_destroy_buffer (GET_VA_DISPLAY (bitplane), &bitplane->data_id); + bitplane->data = NULL; +} + +gboolean +gst_vaapi_bitplane_create (GstVaapiBitPlane * bitplane, + const GstVaapiCodecObjectConstructorArgs * args) +{ + bitplane->data_id = VA_INVALID_ID; + return vaapi_create_buffer (GET_VA_DISPLAY (bitplane), + GET_VA_CONTEXT (bitplane), VABitPlaneBufferType, args->param_size, + args->param, &bitplane->data_id, (void **) &bitplane->data); +} + + +GstVaapiBitPlane * +gst_vaapi_bitplane_new (GstVaapiDecoder * decoder, guint8 * data, + guint data_size) +{ + GstVaapiCodecObject *object; + + object = gst_vaapi_codec_object_new (&GstVaapiBitPlaneClass, + GST_VAAPI_CODEC_BASE (decoder), data, data_size, NULL, 0, 0); + if (!object) + return NULL; + return GST_VAAPI_BITPLANE_CAST (object); +} + +/* ------------------------------------------------------------------------- */ +/* --- JPEG Huffman Tables --- */ +/* ------------------------------------------------------------------------- */ + +GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiHuffmanTable, gst_vaapi_huffman_table); + +void +gst_vaapi_huffman_table_destroy (GstVaapiHuffmanTable * huf_table) +{ + vaapi_destroy_buffer (GET_VA_DISPLAY (huf_table), &huf_table->param_id); + huf_table->param = NULL; +} + +gboolean +gst_vaapi_huffman_table_create (GstVaapiHuffmanTable * huf_table, + const GstVaapiCodecObjectConstructorArgs * args) +{ + huf_table->param_id = VA_INVALID_ID; + return vaapi_create_buffer (GET_VA_DISPLAY (huf_table), + GET_VA_CONTEXT (huf_table), VAHuffmanTableBufferType, args->param_size, + args->param, &huf_table->param_id, (void **) &huf_table->param); +} + +GstVaapiHuffmanTable * +gst_vaapi_huffman_table_new (GstVaapiDecoder * decoder, + guint8 * data, guint data_size) +{ + GstVaapiCodecObject *object; + + object = gst_vaapi_codec_object_new (&GstVaapiHuffmanTableClass, + GST_VAAPI_CODEC_BASE (decoder), data, data_size, NULL, 0, 0); + if (!object) + return NULL; + return GST_VAAPI_HUFFMAN_TABLE_CAST (object); +} + +GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiProbabilityTable, + gst_vaapi_probability_table); + +void +gst_vaapi_probability_table_destroy (GstVaapiProbabilityTable * prob_table) +{ + vaapi_destroy_buffer (GET_VA_DISPLAY (prob_table), &prob_table->param_id); + prob_table->param = NULL; +} + +gboolean +gst_vaapi_probability_table_create (GstVaapiProbabilityTable * prob_table, + const GstVaapiCodecObjectConstructorArgs * args) +{ + prob_table->param_id = VA_INVALID_ID; + return vaapi_create_buffer (GET_VA_DISPLAY (prob_table), + GET_VA_CONTEXT (prob_table), + VAProbabilityBufferType, + args->param_size, args->param, &prob_table->param_id, &prob_table->param); +} + +GstVaapiProbabilityTable * +gst_vaapi_probability_table_new (GstVaapiDecoder * decoder, + gconstpointer param, guint param_size) +{ + GstVaapiCodecObject *object; + + object = gst_vaapi_codec_object_new (&GstVaapiProbabilityTableClass, + GST_VAAPI_CODEC_BASE (decoder), param, param_size, NULL, 0, 0); + if (!object) + return NULL; + return GST_VAAPI_PROBABILITY_TABLE_CAST (object); +} diff --git a/gst-libs/gst/vaapi/gstvaapicodec_objects.h b/gst-libs/gst/vaapi/gstvaapicodec_objects.h new file mode 100644 index 0000000000..ab30dab7d5 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapicodec_objects.h @@ -0,0 +1,275 @@ +/* + * gstvaapicodec_objects.h - VA codec objects abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_CODEC_COMMON_H +#define GST_VAAPI_CODEC_COMMON_H + +#include +#include + +G_BEGIN_DECLS + +typedef gpointer GstVaapiCodecBase; +typedef struct _GstVaapiCodecObject GstVaapiCodecObject; +typedef struct _GstVaapiCodecObjectClass GstVaapiCodecObjectClass; +typedef struct _GstVaapiIqMatrix GstVaapiIqMatrix; +typedef struct _GstVaapiBitPlane GstVaapiBitPlane; +typedef struct _GstVaapiHuffmanTable GstVaapiHuffmanTable; +typedef struct _GstVaapiProbabilityTable GstVaapiProbabilityTable; + +/* ------------------------------------------------------------------------- */ +/* --- Base Codec Object --- */ +/* ------------------------------------------------------------------------- */ + +/* XXX: remove when a common base class for decoder and encoder is available */ +#define GST_VAAPI_CODEC_BASE(obj) \ + ((GstVaapiCodecBase *) (obj)) + +#define GST_VAAPI_CODEC_OBJECT(obj) \ + ((GstVaapiCodecObject *) (obj)) + +enum +{ + GST_VAAPI_CODEC_OBJECT_FLAG_CONSTRUCTED = (1 << 0), + GST_VAAPI_CODEC_OBJECT_FLAG_LAST = (1 << 1) +}; + +typedef struct +{ + gconstpointer param; + guint param_size; + guint param_num; + gconstpointer data; + guint data_size; + guint flags; +} GstVaapiCodecObjectConstructorArgs; + +typedef gboolean +(*GstVaapiCodecObjectCreateFunc)(GstVaapiCodecObject * object, + const GstVaapiCodecObjectConstructorArgs * args); + +typedef GDestroyNotify GstVaapiCodecObjectDestroyFunc; + +/** + * GstVaapiCodecObject: + * + * A #GstVaapiMiniObject holding the base codec object data + */ +struct _GstVaapiCodecObject +{ + /*< private >*/ + GstVaapiMiniObject parent_instance; + GstVaapiCodecBase *codec; +}; + +/** + * GstVaapiCodecObjectClass: + * + * The #GstVaapiCodecObject base class. + */ +struct _GstVaapiCodecObjectClass +{ + /*< private >*/ + GstVaapiMiniObjectClass parent_class; + + GstVaapiCodecObjectCreateFunc create; +}; + +G_GNUC_INTERNAL +const GstVaapiCodecObjectClass * +gst_vaapi_codec_object_get_class (GstVaapiCodecObject * object) G_GNUC_CONST; + +G_GNUC_INTERNAL +GstVaapiCodecObject * +gst_vaapi_codec_object_new (const GstVaapiCodecObjectClass * object_class, + GstVaapiCodecBase * codec, gconstpointer param, guint param_size, + gconstpointer data, guint data_size, guint flags); + +G_GNUC_INTERNAL +GstVaapiCodecObject * +gst_vaapi_codec_object_new_with_param_num (const GstVaapiCodecObjectClass * + object_class, GstVaapiCodecBase * codec, gconstpointer param, + guint param_size, guint param_num, gconstpointer data, + guint data_size, guint flags); + +#define gst_vaapi_codec_object_ref(object) \ + ((gpointer) gst_vaapi_mini_object_ref (GST_VAAPI_MINI_OBJECT (object))) + +#define gst_vaapi_codec_object_unref(object) \ + gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (object)) + +#define gst_vaapi_codec_object_replace(old_object_ptr, new_object) \ + gst_vaapi_mini_object_replace ((GstVaapiMiniObject **) (old_object_ptr), \ + GST_VAAPI_MINI_OBJECT (new_object)) + +/* ------------------------------------------------------------------------- */ +/* --- Inverse Quantization Matrices --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_IQ_MATRIX_CAST(obj) \ + ((GstVaapiIqMatrix *) (obj)) + +/** + * GstVaapiIqMatrix: + * + * A #GstVaapiCodecObject holding an inverse quantization matrix parameter. + */ +struct _GstVaapiIqMatrix +{ + /*< private >*/ + GstVaapiCodecObject parent_instance; + VABufferID param_id; + + /*< public >*/ + gpointer param; +}; + +G_GNUC_INTERNAL +GstVaapiIqMatrix * +gst_vaapi_iq_matrix_new (GstVaapiDecoder * decoder, gconstpointer param, + guint param_size); + +/* ------------------------------------------------------------------------- */ +/* --- VC-1 Bit Planes --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_BITPLANE_CAST(obj) \ + ((GstVaapiBitPlane *) (obj)) + +/** + * GstVaapiBitPlane: + * + * A #GstVaapiCodecObject holding a VC-1 bit plane parameter. + */ +struct _GstVaapiBitPlane +{ + /*< private >*/ + GstVaapiCodecObject parent_instance; + VABufferID data_id; + + /*< public >*/ + guint8 *data; +}; + +G_GNUC_INTERNAL +GstVaapiBitPlane * +gst_vaapi_bitplane_new (GstVaapiDecoder * decoder, guint8 * data, + guint data_size); + +/* ------------------------------------------------------------------------- */ +/* --- JPEG Huffman Tables --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_HUFFMAN_TABLE_CAST(obj) \ + ((GstVaapiHuffmanTable *) (obj)) + +/** + * GstVaapiHuffmanTable: + * + * A #GstVaapiCodecObject holding huffman table. + */ +struct _GstVaapiHuffmanTable +{ + /*< private >*/ + GstVaapiCodecObject parent_instance; + VABufferID param_id; + + /*< public >*/ + gpointer param; +}; + +G_GNUC_INTERNAL +GstVaapiHuffmanTable * +gst_vaapi_huffman_table_new (GstVaapiDecoder * decoder, guint8 * data, + guint data_size); + +/* ------------------------------------------------------------------------- */ +/* --- Probability (Update) Table --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_PROBABILITY_TABLE_CAST(obj) \ + ((GstVaapiProbabilityTable *)(obj)) + +/** + * GstVaapiProbabilityTable: + * + * A #GstVaapiCodecObject holding an Probability (Update) Table for RAC decoding + */ +struct _GstVaapiProbabilityTable +{ + /*< private > */ + GstVaapiCodecObject parent_instance; + VABufferID param_id; + + /*< public > */ + gpointer param; +}; + +G_GNUC_INTERNAL +GstVaapiProbabilityTable * +gst_vaapi_probability_table_new (GstVaapiDecoder * decoder, + gconstpointer param, guint param_size); + +/* ------------------------------------------------------------------------- */ +/* --- Helpers to create codec-dependent objects --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_CODEC_DEFINE_TYPE(type, prefix) \ +G_GNUC_INTERNAL \ +void \ +G_PASTE (prefix, _destroy) (type *); \ + \ +G_GNUC_INTERNAL \ +gboolean \ +G_PASTE (prefix, _create) (type *, \ + const GstVaapiCodecObjectConstructorArgs * args); \ + \ +static const GstVaapiCodecObjectClass G_PASTE (type, Class) = { \ + .parent_class = { \ + .size = sizeof (type), \ + .finalize = (GstVaapiCodecObjectDestroyFunc) \ + G_PASTE (prefix, _destroy) \ + }, \ + .create = (GstVaapiCodecObjectCreateFunc) \ + G_PASTE (prefix, _create), \ +} + +#define GST_VAAPI_IQ_MATRIX_NEW(codec, decoder) \ + gst_vaapi_iq_matrix_new (GST_VAAPI_DECODER_CAST (decoder), \ + NULL, sizeof (G_PASTE (VAIQMatrixBuffer, codec))) + +#define GST_VAAPI_BITPLANE_NEW(decoder, size) \ + gst_vaapi_bitplane_new (GST_VAAPI_DECODER_CAST (decoder), NULL, size) + +#define GST_VAAPI_HUFFMAN_TABLE_NEW(codec, decoder) \ + gst_vaapi_huffman_table_new (GST_VAAPI_DECODER_CAST (decoder), \ + NULL, sizeof (G_PASTE (VAHuffmanTableBuffer, codec))) + +#define GST_VAAPI_PROBABILITY_TABLE_NEW(codec, decoder) \ + gst_vaapi_probability_table_new (GST_VAAPI_DECODER_CAST (decoder), \ + NULL, sizeof (G_PASTE (VAProbabilityDataBuffer, codec))) + +G_END_DECLS + +#endif /* GST_VAAPI_CODEC_OBJECTS_H */ diff --git a/gst-libs/gst/vaapi/gstvaapicodedbuffer.c b/gst-libs/gst/vaapi/gstvaapicodedbuffer.c new file mode 100644 index 0000000000..5d5f3a2ea4 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapicodedbuffer.c @@ -0,0 +1,251 @@ +/* + * gstvaapicodedbuffer.c - VA coded buffer abstraction + * + * Copyright (C) 2013 Intel Corporation + * Author: Wind Yuan + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include "gstvaapicodedbuffer.h" +#include "gstvaapicodedbuffer_priv.h" +#include "gstvaapiencoder_priv.h" +#include "gstvaapiutils.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +static gboolean +coded_buffer_create (GstVaapiCodedBuffer * buf, guint buf_size, + GstVaapiContext * context) +{ + GstVaapiDisplay *const display = GST_VAAPI_CODED_BUFFER_DISPLAY (buf); + VABufferID buf_id; + gboolean success; + + GST_VAAPI_DISPLAY_LOCK (display); + success = vaapi_create_buffer (GST_VAAPI_DISPLAY_VADISPLAY (display), + GST_VAAPI_CONTEXT_ID (context), VAEncCodedBufferType, buf_size, + NULL, &buf_id, NULL); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!success) + return FALSE; + + GST_DEBUG ("coded buffer %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (buf_id)); + GST_VAAPI_CODED_BUFFER_ID (buf) = buf_id; + return TRUE; +} + +static void +coded_buffer_free (GstVaapiCodedBuffer * buf) +{ + GstVaapiDisplay *const display = GST_VAAPI_CODED_BUFFER_DISPLAY (buf); + VABufferID buf_id; + + buf_id = GST_VAAPI_CODED_BUFFER_ID (buf); + GST_DEBUG ("coded buffer %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (buf_id)); + + if (buf_id != VA_INVALID_ID) { + GST_VAAPI_DISPLAY_LOCK (display); + vaapi_destroy_buffer (GST_VAAPI_DISPLAY_VADISPLAY (display), &buf_id); + GST_VAAPI_DISPLAY_UNLOCK (display); + GST_VAAPI_CODED_BUFFER_ID (buf) = VA_INVALID_ID; + } + + gst_vaapi_display_replace (&GST_VAAPI_CODED_BUFFER_DISPLAY (buf), NULL); + + g_slice_free1 (sizeof (GstVaapiCodedBuffer), buf); +} + +static gboolean +coded_buffer_map (GstVaapiCodedBuffer * buf) +{ + GstVaapiDisplay *const display = GST_VAAPI_CODED_BUFFER_DISPLAY (buf); + + if (buf->segment_list) + return TRUE; + + GST_VAAPI_DISPLAY_LOCK (display); + buf->segment_list = + vaapi_map_buffer (GST_VAAPI_DISPLAY_VADISPLAY (display), + GST_VAAPI_CODED_BUFFER_ID (buf)); + GST_VAAPI_DISPLAY_UNLOCK (display); + return buf->segment_list != NULL; +} + +static void +coded_buffer_unmap (GstVaapiCodedBuffer * buf) +{ + GstVaapiDisplay *const display = GST_VAAPI_CODED_BUFFER_DISPLAY (buf); + + if (!buf->segment_list) + return; + + GST_VAAPI_DISPLAY_LOCK (display); + vaapi_unmap_buffer (GST_VAAPI_DISPLAY_VADISPLAY (display), + GST_VAAPI_CODED_BUFFER_ID (buf), (void **) &buf->segment_list); + GST_VAAPI_DISPLAY_UNLOCK (display); +} + +GST_DEFINE_MINI_OBJECT_TYPE (GstVaapiCodedBuffer, gst_vaapi_coded_buffer); + +/* + * gst_vaapi_coded_buffer_new: + * @context: the parent #GstVaapiContext object + * @buf_size: the buffer size in bytes + * + * Creates a new VA coded buffer bound to the supplied @context. + * + * Return value: the newly allocated #GstVaapiCodedBuffer object, or + * %NULL if an error occurred + */ +GstVaapiCodedBuffer * +gst_vaapi_coded_buffer_new (GstVaapiContext * context, guint buf_size) +{ + GstVaapiCodedBuffer *buf; + GstVaapiDisplay *display; + + g_return_val_if_fail (context != NULL, NULL); + g_return_val_if_fail (buf_size > 0, NULL); + + display = GST_VAAPI_CONTEXT_DISPLAY (context); + g_return_val_if_fail (display != NULL, NULL); + + buf = g_slice_new (GstVaapiCodedBuffer); + if (!buf) + return NULL; + + gst_mini_object_init (GST_MINI_OBJECT_CAST (buf), 0, + GST_TYPE_VAAPI_CODED_BUFFER, NULL, NULL, + (GstMiniObjectFreeFunction) coded_buffer_free); + + GST_VAAPI_CODED_BUFFER_DISPLAY (buf) = gst_object_ref (display); + GST_VAAPI_CODED_BUFFER_ID (buf) = VA_INVALID_ID; + buf->segment_list = NULL; + + if (!coded_buffer_create (buf, buf_size, context)) + goto error; + return buf; + + /* ERRORS */ +error: + { + gst_vaapi_coded_buffer_unref (buf); + return NULL; + } +} + +/* + * gst_vaapi_coded_buffer_map: + * @buf: a #GstVaapiCodedBuffer + * @data: pointer to the mapped buffer data (VACodedBufferSegment) + * + * Maps the VA coded buffer and returns the data pointer into @data. + * + * Return value: %TRUE if successful, %FALSE otherwise + */ +gboolean +gst_vaapi_coded_buffer_map (GstVaapiCodedBuffer * buf, + VACodedBufferSegment ** out_segment_list_ptr) +{ + g_return_val_if_fail (buf != NULL, FALSE); + g_return_val_if_fail (out_segment_list_ptr != NULL, FALSE); + + if (!coded_buffer_map (buf)) + return FALSE; + + *out_segment_list_ptr = buf->segment_list; + return TRUE; +} + +/* + * gst_vaapi_coded_buffer_unmap: + * @buf: a #GstVaapiCodedBuffer + * + * Unamps the VA coded buffer. + */ +void +gst_vaapi_coded_buffer_unmap (GstVaapiCodedBuffer * buf) +{ + g_return_if_fail (buf != NULL); + + coded_buffer_unmap (buf); +} + +/** + * gst_vaapi_coded_buffer_get_size: + * @buf: a #GstVaapiCodedBuffer + * + * Returns the VA coded buffer size in bytes. That represents the + * exact buffer size, as filled in so far, not the size of the + * allocated buffer. + * + * Return value: the size of the VA coded buffer, or -1 on error + */ +gssize +gst_vaapi_coded_buffer_get_size (GstVaapiCodedBuffer * buf) +{ + VACodedBufferSegment *segment; + gssize size; + + g_return_val_if_fail (buf != NULL, -1); + + if (!coded_buffer_map (buf)) + return -1; + + size = 0; + for (segment = buf->segment_list; segment != NULL; segment = segment->next) + size += segment->size; + + coded_buffer_unmap (buf); + return size; +} + +/** + * gst_vaapi_coded_buffer_copy_into: + * @dest: the destination #GstBuffer + * @src: the source #GstVaapiCodedBuffer + * + * Copies the coded buffer data from @src into the regular buffer @dest. + * + * Return value: %TRUE if successful, %FALSE otherwise + */ +gboolean +gst_vaapi_coded_buffer_copy_into (GstBuffer * dest, GstVaapiCodedBuffer * src) +{ + VACodedBufferSegment *segment; + goffset offset; + gsize size; + + g_return_val_if_fail (src != NULL, FALSE); + g_return_val_if_fail (dest != NULL, FALSE); + + if (!coded_buffer_map (src)) + return FALSE; + + offset = 0; + for (segment = src->segment_list; segment != NULL; segment = segment->next) { + size = gst_buffer_fill (dest, offset, segment->buf, segment->size); + if (size != segment->size) + break; + offset += segment->size; + } + + coded_buffer_unmap (src); + return segment == NULL; +} diff --git a/gst-libs/gst/vaapi/gstvaapicodedbuffer.h b/gst-libs/gst/vaapi/gstvaapicodedbuffer.h new file mode 100644 index 0000000000..bee4cc4f5b --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapicodedbuffer.h @@ -0,0 +1,73 @@ +/* + * gstvaapicodedbuffer.h - VA coded buffer abstraction + * + * Copyright (C) 2013 Intel Corporation + * Author: Wind Yuan + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_CODED_BUFFER_H +#define GST_VAAPI_CODED_BUFFER_H + +G_BEGIN_DECLS + +#define GST_VAAPI_CODED_BUFFER(obj) \ + ((GstVaapiCodedBuffer *)(obj)) + +/** + * GST_VAAPI_CODED_BUFFER_SIZE: + * @buf: a #GstVaapiCodedBuffer + * + * Macro that evaluates to the size of the underlying VA coded buffer @buf + */ +#define GST_VAAPI_CODED_BUFFER_SIZE(buf) \ + gst_vaapi_coded_buffer_get_size (GST_VAAPI_CODED_BUFFER(buf)) + +typedef struct _GstVaapiCodedBuffer GstVaapiCodedBuffer; +typedef struct _GstVaapiCodedBufferProxy GstVaapiCodedBufferProxy; +typedef struct _GstVaapiCodedBufferPool GstVaapiCodedBufferPool; + +#define GST_TYPE_VAAPI_CODED_BUFFER (gst_vaapi_coded_buffer_get_type ()) + +GType +gst_vaapi_coded_buffer_get_type (void) G_GNUC_CONST; + +/** + * gst_vaapi_coded_buffer_unref: (skip) + * @buf: (transfer full): a #GstVaapiCodedBuffer. + * + * Decreases the refcount of @buf. If the refcount reaches 0, the + * @buf will be freed. + */ +static inline void +gst_vaapi_coded_buffer_unref (GstVaapiCodedBuffer * buf) +{ + gst_mini_object_unref (GST_MINI_OBJECT_CAST (buf)); +} + +gssize +gst_vaapi_coded_buffer_get_size (GstVaapiCodedBuffer * buf); + +gboolean +gst_vaapi_coded_buffer_copy_into (GstBuffer * dest, GstVaapiCodedBuffer * src); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiCodedBuffer, gst_vaapi_coded_buffer_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_CODED_BUFFER_H */ diff --git a/gst-libs/gst/vaapi/gstvaapicodedbuffer_priv.h b/gst-libs/gst/vaapi/gstvaapicodedbuffer_priv.h new file mode 100644 index 0000000000..b872b9c8a0 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapicodedbuffer_priv.h @@ -0,0 +1,84 @@ +/* + * gstvaapicodedbuffer_priv.h - VA coded buffer abstraction (private defs) + * + * Copyright (C) 2013 Intel Corporation + * Author: Wind Yuan + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_CODED_BUFFER_PRIV_H +#define GST_VAAPI_CODED_BUFFER_PRIV_H + +#include +#include "gstvaapicodedbuffer.h" + +G_BEGIN_DECLS + +#define GST_VAAPI_CODED_BUFFER_CAST(obj) \ + ((GstVaapiCodedBuffer *)(obj)) + +/** + * GstVaapiCodedBuffer: + * + * A VA coded buffer object wrapper. + */ +struct _GstVaapiCodedBuffer +{ + /*< private >*/ + GstMiniObject mini_object; + GstVaapiDisplay *display; + GstVaapiID object_id; + + /*< public >*/ + VACodedBufferSegment *segment_list; +}; + +/** + * GST_VAAPI_CODED_BUFFER_DISPLAY: + * @buf: a #GstVaapiCodedBuffer + * + * Macro that evaluates to the #GstVaapiDisplay of @buf + */ +#undef GST_VAAPI_CODED_BUFFER_DISPLAY +#define GST_VAAPI_CODED_BUFFER_DISPLAY(buf) (GST_VAAPI_CODED_BUFFER (buf)->display) + +/** + * GST_VAAPI_CODED_BUFFER_ID: + * @buf: a #GstVaapiCodedBuffer + * + * Macro that evaluates to the object ID of @buf + */ +#undef GST_VAAPI_CODED_BUFFER_ID +#define GST_VAAPI_CODED_BUFFER_ID(buf) (GST_VAAPI_CODED_BUFFER (buf)->object_id) + +G_GNUC_INTERNAL +GstVaapiCodedBuffer * +gst_vaapi_coded_buffer_new (GstVaapiContext * context, guint buf_size); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_coded_buffer_map (GstVaapiCodedBuffer * buf, + VACodedBufferSegment ** out_segment_list_ptr); + +G_GNUC_INTERNAL +void +gst_vaapi_coded_buffer_unmap (GstVaapiCodedBuffer * buf); + +G_END_DECLS + +#endif /* GST_VAAPI_CODED_BUFFER_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapicodedbufferpool.c b/gst-libs/gst/vaapi/gstvaapicodedbufferpool.c new file mode 100644 index 0000000000..3262a946b0 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapicodedbufferpool.c @@ -0,0 +1,132 @@ +/* + * gstvaapicodedbufferpool.c - VA coded buffer pool + * + * Copyright (C) 2013-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include "gstvaapicodedbufferpool.h" +#include "gstvaapicodedbuffer_priv.h" +#include "gstvaapivideopool_priv.h" +#include "gstvaapiencoder_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +/** + * GstVaapiCodedBufferPool: + * + * A pool of lazily allocated #GstVaapiCodedBuffer objects. + */ +struct _GstVaapiCodedBufferPool +{ + /*< private > */ + GstVaapiVideoPool parent_instance; + + GstVaapiContext *context; + gsize buf_size; +}; + +static void +coded_buffer_pool_init (GstVaapiCodedBufferPool * pool, + GstVaapiContext * context, gsize buf_size) +{ + pool->context = gst_vaapi_context_ref (context); + pool->buf_size = buf_size; +} + +static void +coded_buffer_pool_finalize (GstVaapiCodedBufferPool * pool) +{ + gst_vaapi_video_pool_finalize (GST_VAAPI_VIDEO_POOL (pool)); + gst_vaapi_context_unref (pool->context); + pool->context = NULL; +} + +static gpointer +coded_buffer_pool_alloc_object (GstVaapiVideoPool * base_pool) +{ + GstVaapiCodedBufferPool *const pool = GST_VAAPI_CODED_BUFFER_POOL (base_pool); + + return gst_vaapi_coded_buffer_new (pool->context, pool->buf_size); +} + +static inline const GstVaapiMiniObjectClass * +gst_vaapi_coded_buffer_pool_class (void) +{ + static const GstVaapiVideoPoolClass GstVaapiCodedBufferPoolClass = { + {sizeof (GstVaapiCodedBufferPool), + (GDestroyNotify) coded_buffer_pool_finalize} + , + .alloc_object = coded_buffer_pool_alloc_object + }; + return GST_VAAPI_MINI_OBJECT_CLASS (&GstVaapiCodedBufferPoolClass); +} + +/** + * gst_vaapi_coded_buffer_pool_new: + * @encoder: a #GstVaapiEncoder + * @buf_size: the max size of #GstVaapiCodedBuffer objects, in bytes + * + * Creates a new #GstVaapiVideoPool of #GstVaapiCodedBuffer objects + * with the supplied maximum size in bytes, and bound to the specified + * @encoder object. + * + * Return value: the newly allocated #GstVaapiVideoPool + */ +GstVaapiVideoPool * +gst_vaapi_coded_buffer_pool_new (GstVaapiEncoder * encoder, gsize buf_size) +{ + GstVaapiVideoPool *pool; + GstVaapiContext *context; + + g_return_val_if_fail (encoder != NULL, NULL); + g_return_val_if_fail (buf_size > 0, NULL); + + context = GST_VAAPI_ENCODER_CONTEXT (encoder); + g_return_val_if_fail (context != NULL, NULL); + + pool = (GstVaapiVideoPool *) + gst_vaapi_mini_object_new (gst_vaapi_coded_buffer_pool_class ()); + if (!pool) + return NULL; + + gst_vaapi_video_pool_init (pool, GST_VAAPI_CONTEXT_DISPLAY (context), + GST_VAAPI_VIDEO_POOL_OBJECT_TYPE_CODED_BUFFER); + coded_buffer_pool_init (GST_VAAPI_CODED_BUFFER_POOL (pool), + context, buf_size); + return pool; +} + +/** + * gst_vaapi_coded_buffer_pool_get_buffer_size: + * @pool: a #GstVaapiCodedBufferPool + * + * Determines the maximum size of each #GstVaapiCodedBuffer held in + * the @pool. + * + * Return value: size of a #GstVaapiCodedBuffer in @pool + */ +gsize +gst_vaapi_coded_buffer_pool_get_buffer_size (GstVaapiCodedBufferPool * pool) +{ + g_return_val_if_fail (pool != NULL, 0); + + return pool->buf_size; +} diff --git a/gst-libs/gst/vaapi/gstvaapicodedbufferpool.h b/gst-libs/gst/vaapi/gstvaapicodedbufferpool.h new file mode 100644 index 0000000000..c8b9e1ba10 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapicodedbufferpool.h @@ -0,0 +1,45 @@ +/* + * gstvaapicodedbufferpool.h - VA coded buffer pool + * + * Copyright (C) 2013-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_CODED_BUFFER_POOL_H +#define GST_VAAPI_CODED_BUFFER_POOL_H + +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_CODED_BUFFER_POOL(obj) \ + ((GstVaapiCodedBufferPool *)(obj)) + +struct _GstVaapiEncoder; + +GstVaapiVideoPool * +gst_vaapi_coded_buffer_pool_new (struct _GstVaapiEncoder * encoder, + gsize buf_size); + +gsize +gst_vaapi_coded_buffer_pool_get_buffer_size (GstVaapiCodedBufferPool * pool); + +G_END_DECLS + +#endif /* GST_VAAPI_CODED_BUFFER_POOL_H */ diff --git a/gst-libs/gst/vaapi/gstvaapicodedbufferproxy.c b/gst-libs/gst/vaapi/gstvaapicodedbufferproxy.c new file mode 100644 index 0000000000..ececae9c3e --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapicodedbufferproxy.c @@ -0,0 +1,256 @@ +/* + * gstvaapicodedbufferproxy.c - VA coded buffer proxy + * + * Copyright (C) 2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include "gstvaapicodedbufferproxy.h" +#include "gstvaapicodedbufferproxy_priv.h" +#include "gstvaapivideopool_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +static void +coded_buffer_proxy_set_user_data (GstVaapiCodedBufferProxy * proxy, + gpointer user_data, GDestroyNotify destroy_func) +{ + if (proxy->user_data_destroy) + proxy->user_data_destroy (proxy->user_data); + + proxy->user_data = user_data; + proxy->user_data_destroy = destroy_func; +} + +static void +coded_buffer_proxy_finalize (GstVaapiCodedBufferProxy * proxy) +{ + if (proxy->buffer) { + if (proxy->pool) + gst_vaapi_video_pool_put_object (proxy->pool, proxy->buffer); + gst_vaapi_coded_buffer_unref (proxy->buffer); + proxy->buffer = NULL; + } + gst_vaapi_video_pool_replace (&proxy->pool, NULL); + coded_buffer_proxy_set_user_data (proxy, NULL, NULL); + + /* Notify the user function that the object is now destroyed */ + if (proxy->destroy_func) + proxy->destroy_func (proxy->destroy_data); +} + +static inline const GstVaapiMiniObjectClass * +gst_vaapi_coded_buffer_proxy_class (void) +{ + static const GstVaapiMiniObjectClass GstVaapiCodedBufferProxyClass = { + sizeof (GstVaapiCodedBufferProxy), + (GDestroyNotify) coded_buffer_proxy_finalize + }; + return &GstVaapiCodedBufferProxyClass; +} + +/** + * gst_vaapi_coded_buffer_proxy_new_from_pool: + * @pool: a #GstVaapiCodedBufferPool + * + * Allocates a new coded buffer from the supplied @pool and creates + * the wrapped coded buffer proxy object from it. When the last + * reference to the proxy object is released, then the underlying VA + * coded buffer is pushed back to its parent pool. + * + * Returns: The same newly allocated @proxy object, or %NULL on error + */ +GstVaapiCodedBufferProxy * +gst_vaapi_coded_buffer_proxy_new_from_pool (GstVaapiCodedBufferPool * pool) +{ + GstVaapiCodedBufferProxy *proxy; + + g_return_val_if_fail (pool != NULL, NULL); + g_return_val_if_fail (GST_VAAPI_VIDEO_POOL (pool)->object_type == + GST_VAAPI_VIDEO_POOL_OBJECT_TYPE_CODED_BUFFER, NULL); + + proxy = (GstVaapiCodedBufferProxy *) + gst_vaapi_mini_object_new (gst_vaapi_coded_buffer_proxy_class ()); + if (!proxy) + return NULL; + + proxy->destroy_func = NULL; + proxy->user_data_destroy = NULL; + proxy->pool = gst_vaapi_video_pool_ref (GST_VAAPI_VIDEO_POOL (pool)); + proxy->buffer = gst_vaapi_video_pool_get_object (proxy->pool); + if (!proxy->buffer) + goto error; + gst_mini_object_ref (GST_MINI_OBJECT_CAST (proxy->buffer)); + return proxy; + + /* ERRORS */ +error: + { + gst_vaapi_coded_buffer_proxy_unref (proxy); + return NULL; + } +} + +/** + * gst_vaapi_coded_buffer_proxy_ref: + * @proxy: a #GstVaapiCodedBufferProxy + * + * Atomically increases the reference count of the given @proxy by one. + * + * Returns: The same @proxy argument + */ +GstVaapiCodedBufferProxy * +gst_vaapi_coded_buffer_proxy_ref (GstVaapiCodedBufferProxy * proxy) +{ + g_return_val_if_fail (proxy != NULL, NULL); + + return GST_VAAPI_CODED_BUFFER_PROXY (gst_vaapi_mini_object_ref + (GST_VAAPI_MINI_OBJECT (proxy))); +} + +/** + * gst_vaapi_coded_buffer_proxy_unref: + * @proxy: a #GstVaapiCodedBufferProxy + * + * Atomically decreases the reference count of the @proxy by one. If + * the reference count reaches zero, the object will be free'd. + */ +void +gst_vaapi_coded_buffer_proxy_unref (GstVaapiCodedBufferProxy * proxy) +{ + g_return_if_fail (proxy != NULL); + + gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (proxy)); +} + +/** + * gst_vaapi_coded_buffer_proxy_replace: + * @old_proxy_ptr: a pointer to a #GstVaapiCodedBufferProxy + * @new_proxy: a #GstVaapiCodedBufferProxy + * + * Atomically replaces the proxy object held in @old_proxy_ptr with + * @new_proxy. This means that @old_proxy_ptr shall reference a valid + * object. However, @new_proxy can be NULL. + */ +void +gst_vaapi_coded_buffer_proxy_replace (GstVaapiCodedBufferProxy ** old_proxy_ptr, + GstVaapiCodedBufferProxy * new_proxy) +{ + g_return_if_fail (old_proxy_ptr != NULL); + + gst_vaapi_mini_object_replace ((GstVaapiMiniObject **) old_proxy_ptr, + GST_VAAPI_MINI_OBJECT (new_proxy)); +} + +/** + * gst_vaapi_coded_buffer_proxy_get_buffer: + * @proxy: a #GstVaapiCodedBufferProxy + * + * Returns the #GstVaapiCodedBuffer stored in the @proxy. + * + * Return value: the #GstVaapiCodedBuffer, or %NULL if an error occurred + */ +GstVaapiCodedBuffer * +gst_vaapi_coded_buffer_proxy_get_buffer (GstVaapiCodedBufferProxy * proxy) +{ + g_return_val_if_fail (proxy != NULL, NULL); + + return GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (proxy); +} + +/** + * gst_vaapi_coded_buffer_proxy_get_buffer_size: + * @proxy: a #GstVaapiCodedBufferProxy + * + * Returns the size of the underlying #GstVaapiCodedBuffer object + * stored in the @proxy. + * + * Return value: the underlying #GstVaapiCodedBuffer size, or -1 if an + * error occurred + */ +gssize +gst_vaapi_coded_buffer_proxy_get_buffer_size (GstVaapiCodedBufferProxy * proxy) +{ + g_return_val_if_fail (proxy != NULL, -1); + + return GST_VAAPI_CODED_BUFFER_PROXY_BUFFER_SIZE (proxy); +} + +/** + * gst_vaapi_coded_buffer_proxy_set_destroy_notify: + * @proxy: a @GstVaapiCodedBufferProxy + * @destroy_func: a #GDestroyNotify function + * @user_data: some extra data to pass to the @destroy_func function + * + * Sets @destroy_func as the function to call when the coded buffer + * @proxy was released. At this point, the proxy object is considered + * released, i.e. the underlying data storage is no longer valid and + * the callback function shall not expect anything from that. + */ +void +gst_vaapi_coded_buffer_proxy_set_destroy_notify (GstVaapiCodedBufferProxy * + proxy, GDestroyNotify destroy_func, gpointer user_data) +{ + g_return_if_fail (proxy != NULL); + + proxy->destroy_func = destroy_func; + proxy->destroy_data = user_data; +} + +/** + * gst_vaapi_coded_buffer_proxy_get_user_data: + * @proxy: a #GstVaapiCodedBufferProxy + * + * Gets private data previously set on the VA coded buffer proxy + * object through the gst_vaapi_coded_buffer_proxy_set_user_data() + * function. + * + * Return value: the previously set user-data + */ +gpointer +gst_vaapi_coded_buffer_proxy_get_user_data (GstVaapiCodedBufferProxy * proxy) +{ + g_return_val_if_fail (proxy != NULL, NULL); + + return proxy->user_data; +} + +/** + * gst_vaapi_coded_buffer_proxy_set_user_data: + * @proxy: a #GstVaapiCodedBufferProxy + * @user_data: user-defined data + * @destroy_func: a #GDestroyNotify + * + * Sets @user_data on the VA coded buffer proxy object and the + * #GDestroyNotify function that will be called when the coded buffer + * proxy object is released. + * + * If a @user_data was previously set, then the previously set + * @destroy_func function, if any, will be called before the + * @user_data is replaced. + */ +void +gst_vaapi_coded_buffer_proxy_set_user_data (GstVaapiCodedBufferProxy * proxy, + gpointer user_data, GDestroyNotify destroy_func) +{ + g_return_if_fail (proxy != NULL); + + coded_buffer_proxy_set_user_data (proxy, user_data, destroy_func); +} diff --git a/gst-libs/gst/vaapi/gstvaapicodedbufferproxy.h b/gst-libs/gst/vaapi/gstvaapicodedbufferproxy.h new file mode 100644 index 0000000000..4968c63075 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapicodedbufferproxy.h @@ -0,0 +1,82 @@ +/* + * gstvaapicodedbufferproxy_priv.h - VA coded buffer proxy + * + * Copyright (C) 2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_CODED_BUFFER_PROXY_H +#define GST_VAAPI_CODED_BUFFER_PROXY_H + +#include +#include + +G_BEGIN_DECLS + +/** + * GST_VAAPI_CODED_BUFFER_PROXY_BUFFER: + * @proxy: a #GstVaapiCodedBufferProxy + * + * Macro that evaluated to the underlying #GstVaapiCodedBuffer of @proxy. + */ +#define GST_VAAPI_CODED_BUFFER_PROXY_BUFFER(proxy) \ + gst_vaapi_coded_buffer_proxy_get_buffer(proxy) + +/** + * GST_VAAPI_CODED_BUFFER_PROXY_BUFFER_SIZE: + * @proxy: a #GstVaapiCodedBufferProxy + * + * Macro that evaluated to the underlying #GstVaapiCodedBuffer size of + * @proxy. + */ +#define GST_VAAPI_CODED_BUFFER_PROXY_BUFFER_SIZE(proxy) \ + gst_vaapi_coded_buffer_proxy_get_buffer_size(proxy) + +GstVaapiCodedBufferProxy * +gst_vaapi_coded_buffer_proxy_new_from_pool (GstVaapiCodedBufferPool * pool); + +GstVaapiCodedBufferProxy * +gst_vaapi_coded_buffer_proxy_ref (GstVaapiCodedBufferProxy * proxy); + +void +gst_vaapi_coded_buffer_proxy_unref (GstVaapiCodedBufferProxy * proxy); + +void +gst_vaapi_coded_buffer_proxy_replace (GstVaapiCodedBufferProxy ** old_proxy_ptr, + GstVaapiCodedBufferProxy * new_proxy); + +GstVaapiCodedBuffer * +gst_vaapi_coded_buffer_proxy_get_buffer (GstVaapiCodedBufferProxy * proxy); + +gssize +gst_vaapi_coded_buffer_proxy_get_buffer_size (GstVaapiCodedBufferProxy * proxy); + +void +gst_vaapi_coded_buffer_proxy_set_destroy_notify (GstVaapiCodedBufferProxy * + proxy, GDestroyNotify destroy_func, gpointer user_data); + +gpointer +gst_vaapi_coded_buffer_proxy_get_user_data (GstVaapiCodedBufferProxy * proxy); + +void +gst_vaapi_coded_buffer_proxy_set_user_data (GstVaapiCodedBufferProxy * proxy, + gpointer user_data, GDestroyNotify destroy_func); + +G_END_DECLS + +#endif /* GST_VAAPI_CODED_BUFFER_PROXY_H */ diff --git a/gst-libs/gst/vaapi/gstvaapicodedbufferproxy_priv.h b/gst-libs/gst/vaapi/gstvaapicodedbufferproxy_priv.h new file mode 100644 index 0000000000..6feb8f9c82 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapicodedbufferproxy_priv.h @@ -0,0 +1,70 @@ +/* + * gstvaapicodedbufferproxy_priv.h - VA coded buffer proxy (private defs) + * + * Copyright (C) 2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_CODED_BUFFER_PROXY_PRIV_H +#define GST_VAAPI_CODED_BUFFER_PROXY_PRIV_H + +#include "gstvaapicodedbuffer_priv.h" +#include "gstvaapiminiobject.h" + +G_BEGIN_DECLS + +#define GST_VAAPI_CODED_BUFFER_PROXY(proxy) \ + ((GstVaapiCodedBufferProxy *)(proxy)) + +struct _GstVaapiCodedBufferProxy +{ + /*< private >*/ + GstVaapiMiniObject parent_instance; + + GstVaapiVideoPool *pool; + GstVaapiCodedBuffer *buffer; + GDestroyNotify destroy_func; + gpointer destroy_data; + GDestroyNotify user_data_destroy; + gpointer user_data; +}; + +/** + * GST_VAAPI_CODED_BUFFER_PROXY_BUFFER: + * @proxy: a #GstVaapiCodedBufferProxy + * + * Macro that evaluated to the underlying #GstVaapiCodedBuffer of @proxy. + */ +#undef GST_VAAPI_CODED_BUFFER_PROXY_BUFFER +#define GST_VAAPI_CODED_BUFFER_PROXY_BUFFER(proxy) \ + GST_VAAPI_CODED_BUFFER_PROXY(proxy)->buffer + +/** + * GST_VAAPI_CODED_BUFFER_PROXY_BUFFER_SIZE: + * @proxy: a #GstVaapiCodedBufferProxy + * + * Macro that evaluated to the underlying #GstVaapiCodedBuffer size of + * @proxy. + */ +#undef GST_VAAPI_CODED_BUFFER_PROXY_BUFFER_SIZE +#define GST_VAAPI_CODED_BUFFER_PROXY_BUFFER_SIZE(proxy) \ + GST_VAAPI_CODED_BUFFER_SIZE(GST_VAAPI_CODED_BUFFER_PROXY_BUFFER(proxy)) + +G_END_DECLS + +#endif /* GST_VAAPI_CODED_BUFFER_PROXY_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapicompat.h b/gst-libs/gst/vaapi/gstvaapicompat.h new file mode 100644 index 0000000000..f75a9eaec1 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapicompat.h @@ -0,0 +1,41 @@ +/* + * gstvapicompat.h - VA-API compatibility glue + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_COMPAT_H +#define GST_VAAPI_COMPAT_H + +#include + +#if VA_CHECK_VERSION(1,0,0) +#define VA_ROI_RC_QP_DELTA_SUPPORT(x) x->bits.roi_rc_qp_delta_support +#define VA_ENC_PACKED_HEADER_H264_SEI VAEncPackedHeaderRawData +#else +#define VA_ROI_RC_QP_DELTA_SUPPORT(x) x->bits.roi_rc_qp_delat_support +#define VA_ENC_PACKED_HEADER_H264_SEI VAEncPackedHeaderH264_SEI +#endif + +#include +#include + +#endif /* GST_VAAPI_COMPAT_H */ diff --git a/gst-libs/gst/vaapi/gstvaapicontext.c b/gst-libs/gst/vaapi/gstvaapicontext.c new file mode 100644 index 0000000000..88cd1105f3 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapicontext.c @@ -0,0 +1,788 @@ +/* + * gstvaapicontext.c - VA context abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapicontext + * @short_description: VA context abstraction + */ + +#include "sysdeps.h" +#include "gstvaapicompat.h" +#include "gstvaapicontext.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapisurface_priv.h" +#include "gstvaapisurfacepool.h" +#include "gstvaapisurfaceproxy.h" +#include "gstvaapivideopool_priv.h" +#include "gstvaapiutils.h" + +/* Define default VA surface chroma format to YUV 4:2:0 */ +#define DEFAULT_CHROMA_TYPE (GST_VAAPI_CHROMA_TYPE_YUV420) + +/* Number of scratch surfaces beyond those used as reference */ +#define SCRATCH_SURFACES_COUNT (4) + +/* Debug category for GstVaapiContext */ +GST_DEBUG_CATEGORY (gst_debug_vaapi_context); +#define GST_CAT_DEFAULT gst_debug_vaapi_context + +static void +_init_vaapi_context_debug (void) +{ +#ifndef GST_DISABLE_GST_DEBUG + static gsize _init = 0; + + if (g_once_init_enter (&_init)) { + GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi_context, "vaapicontext", 0, + "VA-API context"); + g_once_init_leave (&_init, 1); + } +#endif +} + +static inline gboolean +_context_is_broken_jpeg_decoder (GstVaapiContext * context) +{ + GstVaapiDisplay *const display = GST_VAAPI_CONTEXT_DISPLAY (context); + + return (context->info.profile == GST_VAAPI_PROFILE_JPEG_BASELINE + && context->info.entrypoint == GST_VAAPI_ENTRYPOINT_VLD + && gst_vaapi_display_has_driver_quirks (display, + GST_VAAPI_DRIVER_QUIRK_JPEG_DEC_BROKEN_FORMATS)); +} + +static gboolean +ensure_attributes (GstVaapiContext * context) +{ + if (G_LIKELY (context->attribs)) + return TRUE; + + context->attribs = + gst_vaapi_config_surface_attributes_get (GST_VAAPI_CONTEXT_DISPLAY + (context), context->va_config); + + if (!context->attribs) + return FALSE; + + if (_context_is_broken_jpeg_decoder (context)) { + GstVideoFormat fmt = GST_VIDEO_FORMAT_NV12; + g_array_prepend_val (context->attribs->formats, fmt); + + context->attribs->mem_types &= ~VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME; + } + return TRUE; +} + +/* XXX(victor): verify the preferred video format concords with the + * chroma type; otherwise it is changed for the (very arbritrary) + * preferred format from the requested context chroma type, in the + * context attributes */ +static void +ensure_preferred_format (GstVaapiContext * context) +{ + const GstVaapiContextInfo *const cip = &context->info; + GArray *formats; + guint i; + + if (context->preferred_format != GST_VIDEO_FORMAT_UNKNOWN) + return; + + if (_context_is_broken_jpeg_decoder (context)) + return; + + if (!ensure_attributes (context) || !context->attribs->formats) + return; + + formats = context->attribs->formats; + for (i = 0; i < formats->len; i++) { + GstVideoFormat format = g_array_index (formats, GstVideoFormat, i); + if (format == gst_vaapi_video_format_from_chroma (cip->chroma_type)) { + context->preferred_format = format; + break; + } + } + + return; +} + +static inline gboolean +context_get_attribute (GstVaapiContext * context, VAConfigAttribType type, + guint * out_value_ptr) +{ + return gst_vaapi_get_config_attribute (GST_VAAPI_CONTEXT_DISPLAY (context), + context->va_profile, context->va_entrypoint, type, out_value_ptr); +} + +static void +context_destroy_surfaces (GstVaapiContext * context) +{ + if (context->surfaces) { + g_ptr_array_unref (context->surfaces); + context->surfaces = NULL; + } + + context->preferred_format = GST_VIDEO_FORMAT_UNKNOWN; + + gst_vaapi_video_pool_replace (&context->surfaces_pool, NULL); +} + +static void +context_destroy (GstVaapiContext * context) +{ + GstVaapiDisplay *const display = GST_VAAPI_CONTEXT_DISPLAY (context); + VAContextID context_id; + VAStatus status; + + context_id = GST_VAAPI_CONTEXT_ID (context); + GST_DEBUG ("context 0x%08x / config 0x%08x", context_id, context->va_config); + + if (context_id != VA_INVALID_ID) { + GST_VAAPI_DISPLAY_LOCK (display); + status = vaDestroyContext (GST_VAAPI_DISPLAY_VADISPLAY (display), + context_id); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!vaapi_check_status (status, "vaDestroyContext()")) + GST_WARNING ("failed to destroy context 0x%08x", context_id); + GST_VAAPI_CONTEXT_ID (context) = VA_INVALID_ID; + } + + if (context->va_config != VA_INVALID_ID) { + GST_VAAPI_DISPLAY_LOCK (display); + status = vaDestroyConfig (GST_VAAPI_DISPLAY_VADISPLAY (display), + context->va_config); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!vaapi_check_status (status, "vaDestroyConfig()")) + GST_WARNING ("failed to destroy config 0x%08x", context->va_config); + context->va_config = VA_INVALID_ID; + } + + if (context->attribs) { + gst_vaapi_config_surface_attributes_free (context->attribs); + context->attribs = NULL; + } +} + +static gboolean +context_ensure_surfaces (GstVaapiContext * context) +{ + GstVaapiDisplay *display = GST_VAAPI_CONTEXT_DISPLAY (context); + const GstVaapiContextInfo *const cip = &context->info; + const guint num_surfaces = cip->ref_frames + SCRATCH_SURFACES_COUNT; + GstVaapiSurface *surface; + GstVideoFormat format; + guint i, capacity; + + ensure_preferred_format (context); + format = context->preferred_format; + for (i = context->surfaces->len; i < num_surfaces; i++) { + if (format != GST_VIDEO_FORMAT_UNKNOWN) { + surface = gst_vaapi_surface_new_with_format (display, format, cip->width, + cip->height, 0); + } else { + surface = gst_vaapi_surface_new (display, cip->chroma_type, cip->width, + cip->height); + } + if (!surface) + return FALSE; + g_ptr_array_add (context->surfaces, surface); + if (!gst_vaapi_video_pool_add_object (context->surfaces_pool, surface)) + return FALSE; + } + + capacity = cip->usage == GST_VAAPI_CONTEXT_USAGE_DECODE ? 0 : num_surfaces; + gst_vaapi_video_pool_set_capacity (context->surfaces_pool, capacity); + return TRUE; +} + +static gboolean +context_create_surfaces (GstVaapiContext * context) +{ + const GstVaapiContextInfo *const cip = &context->info; + GstVaapiDisplay *const display = GST_VAAPI_CONTEXT_DISPLAY (context); + guint num_surfaces; + + num_surfaces = cip->ref_frames + SCRATCH_SURFACES_COUNT; + if (!context->surfaces) { + context->surfaces = g_ptr_array_new_full (num_surfaces, + (GDestroyNotify) gst_mini_object_unref); + if (!context->surfaces) + return FALSE; + } + + if (!context->surfaces_pool) { + context->surfaces_pool = + gst_vaapi_surface_pool_new_with_chroma_type (display, cip->chroma_type, + cip->width, cip->height, 0); + + if (!context->surfaces_pool) + return FALSE; + } + return context_ensure_surfaces (context); +} + +static gboolean +context_create (GstVaapiContext * context) +{ + const GstVaapiContextInfo *const cip = &context->info; + GstVaapiDisplay *const display = GST_VAAPI_CONTEXT_DISPLAY (context); + VAContextID context_id; + VASurfaceID surface_id; + VASurfaceID *surfaces_data = NULL; + VAStatus status; + GArray *surfaces = NULL; + gboolean success = FALSE; + guint i; + gint num_surfaces = 0; + + if (!context->surfaces && !context_create_surfaces (context)) + goto cleanup; + + /* Create VA surfaces list for vaCreateContext() */ + surfaces = g_array_sized_new (FALSE, + FALSE, sizeof (VASurfaceID), context->surfaces->len); + if (!surfaces) + goto cleanup; + + for (i = 0; i < context->surfaces->len; i++) { + GstVaapiSurface *const surface = g_ptr_array_index (context->surfaces, i); + if (!surface) + goto cleanup; + surface_id = GST_VAAPI_SURFACE_ID (surface); + g_array_append_val (surfaces, surface_id); + } + + g_assert (surfaces->len == context->surfaces->len); + + /* vaCreateContext() doesn't really need an array of VASurfaceIDs (see + * https://lists.01.org/pipermail/intel-vaapi-media/2017-July/000052.html and + * https://github.com/intel/libva/issues/251); pass a dummy list of valid + * (non-null) IDs until the signature gets updated. */ + if (cip->usage != GST_VAAPI_CONTEXT_USAGE_DECODE) { + surfaces_data = (VASurfaceID *) surfaces->data; + num_surfaces = surfaces->len; + } + + GST_VAAPI_DISPLAY_LOCK (display); + status = vaCreateContext (GST_VAAPI_DISPLAY_VADISPLAY (display), + context->va_config, cip->width, cip->height, VA_PROGRESSIVE, + surfaces_data, num_surfaces, &context_id); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!vaapi_check_status (status, "vaCreateContext()")) + goto cleanup; + + GST_VAAPI_CONTEXT_ID (context) = context_id; + success = TRUE; + +cleanup: + if (surfaces) + g_array_unref (surfaces); + return success; +} + +static gboolean +config_create (GstVaapiContext * context) +{ + const GstVaapiContextInfo *const cip = &context->info; + GstVaapiDisplay *const display = GST_VAAPI_CONTEXT_DISPLAY (context); + VAConfigAttrib attribs[7], *attrib; + VAStatus status; + guint value, va_chroma_format, attrib_index; + + /* Reset profile and entrypoint */ + if (cip->profile == GST_VAAPI_PROFILE_UNKNOWN + || cip->entrypoint == GST_VAAPI_ENTRYPOINT_INVALID) + goto cleanup; + context->va_profile = gst_vaapi_profile_get_va_profile (cip->profile); + context->va_entrypoint = + gst_vaapi_entrypoint_get_va_entrypoint (cip->entrypoint); + + attrib_index = 0; + attrib = &attribs[attrib_index]; + g_assert (attrib_index < G_N_ELEMENTS (attribs)); + + /* Validate VA surface format */ + va_chroma_format = from_GstVaapiChromaType (cip->chroma_type); + if (!va_chroma_format) + goto cleanup; + attrib->type = VAConfigAttribRTFormat; + if (!context_get_attribute (context, attrib->type, &value)) + goto cleanup; + if (!(value & va_chroma_format)) { + GST_ERROR ("unsupported chroma format (%s)", + string_of_va_chroma_format (va_chroma_format)); + goto cleanup; + } + attrib->value = va_chroma_format; + attrib = &attribs[++attrib_index]; + g_assert (attrib_index < G_N_ELEMENTS (attribs)); + + switch (cip->usage) { +#if USE_ENCODERS + case GST_VAAPI_CONTEXT_USAGE_ENCODE: + { + const GstVaapiConfigInfoEncoder *const config = &cip->config.encoder; + guint va_rate_control; + + /* Rate control */ + va_rate_control = from_GstVaapiRateControl (config->rc_mode); + if (va_rate_control != VA_RC_NONE) { + attrib->type = VAConfigAttribRateControl; + if (!context_get_attribute (context, attrib->type, &value)) + goto cleanup; + + if ((value & va_rate_control) != va_rate_control) { + GST_ERROR ("unsupported %s rate control", + string_of_VARateControl (va_rate_control)); + goto cleanup; + } + attrib->value = va_rate_control; + attrib = &attribs[++attrib_index]; + g_assert (attrib_index < G_N_ELEMENTS (attribs)); + } + /* Packed headers */ + if (config->packed_headers) { + attrib->type = VAConfigAttribEncPackedHeaders; + if (!context_get_attribute (context, attrib->type, &value)) + goto cleanup; + + if ((value & config->packed_headers) != config->packed_headers) { + GST_ERROR ("unsupported packed headers 0x%08x", + config->packed_headers & ~(value & config->packed_headers)); + goto cleanup; + } + attrib->value = config->packed_headers; + attrib = &attribs[++attrib_index]; + g_assert (attrib_index < G_N_ELEMENTS (attribs)); + } + if (cip->profile == GST_VAAPI_PROFILE_JPEG_BASELINE) { + attrib->type = VAConfigAttribEncJPEG; + if (!context_get_attribute (context, attrib->type, &value)) + goto cleanup; + attrib->value = value; + attrib = &attribs[++attrib_index]; + g_assert (attrib_index < G_N_ELEMENTS (attribs)); + } +#if VA_CHECK_VERSION(0,39,1) + if (config->roi_capability) { + VAConfigAttribValEncROI *roi_config; + + attrib->type = VAConfigAttribEncROI; + if (!context_get_attribute (context, attrib->type, &value)) + goto cleanup; + roi_config = (VAConfigAttribValEncROI *) & value; + if (roi_config->bits.num_roi_regions != config->roi_num_supported) { + GST_ERROR ("Mismatched ROI support: number of regions supported: %d", + roi_config->bits.num_roi_regions); + goto cleanup; + } + if (config->rc_mode != GST_VAAPI_RATECONTROL_CQP + && VA_ROI_RC_QP_DELTA_SUPPORT (roi_config) == 0) { + GST_ERROR ("Mismatched ROI support: ROI delta QP: %d", + VA_ROI_RC_QP_DELTA_SUPPORT (roi_config)); + goto cleanup; + } + attrib->value = value; + attrib = &attribs[++attrib_index]; + g_assert (attrib_index < G_N_ELEMENTS (attribs)); + } +#endif + break; + } +#endif + default: + break; + } + + GST_VAAPI_DISPLAY_LOCK (display); + status = vaCreateConfig (GST_VAAPI_DISPLAY_VADISPLAY (display), + context->va_profile, context->va_entrypoint, attribs, attrib_index, + &context->va_config); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!vaapi_check_status (status, "vaCreateConfig()")) + goto cleanup; + + return TRUE; +cleanup: + GST_WARNING ("Failed to create vaConfig"); + return FALSE; +} + +/** Updates config for encoding. Returns %TRUE if config changed */ +static gboolean +context_update_config_encoder (GstVaapiContext * context, + const GstVaapiConfigInfoEncoder * new_config) +{ + GstVaapiConfigInfoEncoder *const config = &context->info.config.encoder; + gboolean config_changed = FALSE; + + g_assert (context->info.usage == GST_VAAPI_CONTEXT_USAGE_ENCODE); + + if (config->rc_mode != new_config->rc_mode) { + config->rc_mode = new_config->rc_mode; + config_changed = TRUE; + } + + if (config->packed_headers != new_config->packed_headers) { + config->packed_headers = new_config->packed_headers; + config_changed = TRUE; + } + + if (config->roi_capability != new_config->roi_capability || + config->roi_num_supported != new_config->roi_num_supported) { + config->roi_capability = new_config->roi_capability; + config->roi_num_supported = new_config->roi_num_supported; + config_changed = TRUE; + } + + return config_changed; +} + +static inline void +gst_vaapi_context_init (GstVaapiContext * context, + const GstVaapiContextInfo * new_cip) +{ + GstVaapiContextInfo *const cip = &context->info; + + *cip = *new_cip; + if (!cip->chroma_type) + cip->chroma_type = DEFAULT_CHROMA_TYPE; + + context->va_config = VA_INVALID_ID; + context->reset_on_resize = TRUE; + + context->attribs = NULL; + context->preferred_format = GST_VIDEO_FORMAT_UNKNOWN; +} + +/** + * gst_vaapi_context_new: + * @display: a #GstVaapiDisplay + * @cip: a pointer to the #GstVaapiContextInfo + * + * Creates a new #GstVaapiContext with the configuration specified by + * @cip, thus including profile, entry-point, encoded size and maximum + * number of reference frames reported by the bitstream. + * + * Return value: the newly allocated #GstVaapiContext object + */ +GstVaapiContext * +gst_vaapi_context_new (GstVaapiDisplay * display, + const GstVaapiContextInfo * cip) +{ + GstVaapiContext *context; + + g_return_val_if_fail (display, NULL); + + _init_vaapi_context_debug (); + + if (cip->profile == GST_VAAPI_PROFILE_UNKNOWN + || cip->entrypoint == GST_VAAPI_ENTRYPOINT_INVALID) + return NULL; + + context = g_slice_new (GstVaapiContext); + if (!context) + return NULL; + + GST_VAAPI_CONTEXT_DISPLAY (context) = gst_object_ref (display); + GST_VAAPI_CONTEXT_ID (context) = VA_INVALID_ID; + g_atomic_int_set (&context->ref_count, 1); + context->surfaces = NULL; + context->surfaces_pool = NULL; + + gst_vaapi_context_init (context, cip); + + if (!config_create (context)) + goto error; + + /* this means we don't want to create a VAcontext */ + if (cip->width == 0 && cip->height == 0) + goto done; + + /* this is not valid */ + if (cip->width == 0 || cip->height == 0) + goto error; + + if (!context_create (context)) + goto error; + +done: + GST_DEBUG ("context 0x%08" G_GSIZE_MODIFIER "x / config 0x%08x", + GST_VAAPI_CONTEXT_ID (context), context->va_config); + return context; + + /* ERRORS */ +error: + { + gst_vaapi_context_unref (context); + return NULL; + } +} + +/** + * gst_vaapi_context_reset: + * @context: a #GstVaapiContext + * @new_cip: a pointer to the new #GstVaapiContextInfo details + * + * Resets @context to the configuration specified by @new_cip, thus + * including profile, entry-point, encoded size and maximum number of + * reference frames reported by the bitstream. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_context_reset (GstVaapiContext * context, + const GstVaapiContextInfo * new_cip) +{ + GstVaapiContextInfo *const cip = &context->info; + gboolean reset_surfaces = FALSE, reset_config = FALSE; + gboolean grow_surfaces = FALSE; + GstVaapiChromaType chroma_type; + + if (new_cip->profile == GST_VAAPI_PROFILE_UNKNOWN + || new_cip->entrypoint == GST_VAAPI_ENTRYPOINT_INVALID) + return FALSE; + + chroma_type = new_cip->chroma_type ? new_cip->chroma_type : + DEFAULT_CHROMA_TYPE; + if (cip->chroma_type != chroma_type) { + cip->chroma_type = chroma_type; + reset_surfaces = TRUE; + } + + if (cip->width != new_cip->width || cip->height != new_cip->height) { + cip->width = new_cip->width; + cip->height = new_cip->height; + reset_surfaces = TRUE; + } + + if (cip->profile != new_cip->profile || + cip->entrypoint != new_cip->entrypoint) { + cip->profile = new_cip->profile; + cip->entrypoint = new_cip->entrypoint; + reset_config = TRUE; + } + + if (cip->ref_frames < new_cip->ref_frames) { + cip->ref_frames = new_cip->ref_frames; + grow_surfaces = TRUE; + } + + if (cip->usage != new_cip->usage) { + cip->usage = new_cip->usage; + reset_config = TRUE; + memcpy (&cip->config, &new_cip->config, sizeof (cip->config)); + } else if (new_cip->usage == GST_VAAPI_CONTEXT_USAGE_ENCODE) { + if (context_update_config_encoder (context, &new_cip->config.encoder)) + reset_config = TRUE; + } else if (new_cip->usage == GST_VAAPI_CONTEXT_USAGE_DECODE) { + if ((reset_surfaces && context->reset_on_resize) || grow_surfaces) + reset_config = TRUE; + } + + if (reset_surfaces) + context_destroy_surfaces (context); + if (reset_config) + context_destroy (context); + + if (reset_config && !(config_create (context) && context_create (context))) + return FALSE; + if (reset_surfaces && !context_create_surfaces (context)) + return FALSE; + else if (grow_surfaces && !context_ensure_surfaces (context)) + return FALSE; + return TRUE; +} + +/** + * gst_vaapi_context_get_id: + * @context: a #GstVaapiContext + * + * Returns the underlying VAContextID of the @context. + * + * Return value: the underlying VA context id + */ +GstVaapiID +gst_vaapi_context_get_id (GstVaapiContext * context) +{ + g_return_val_if_fail (context != NULL, VA_INVALID_ID); + + return GST_VAAPI_CONTEXT_ID (context); +} + +/** + * gst_vaapi_context_get_surface_proxy: + * @context: a #GstVaapiContext + * + * Acquires a free surface, wrapped into a #GstVaapiSurfaceProxy. The + * returned surface will be automatically released when the proxy is + * destroyed. So, it is enough to call gst_vaapi_surface_proxy_unref() + * after usage. + * + * This function returns %NULL if there is no free surface available + * in the pool. The surfaces are pre-allocated during context creation + * though. + * + * Return value: a free surface, or %NULL if none is available + */ +GstVaapiSurfaceProxy * +gst_vaapi_context_get_surface_proxy (GstVaapiContext * context) +{ + g_return_val_if_fail (context != NULL, NULL); + + return + gst_vaapi_surface_proxy_new_from_pool (GST_VAAPI_SURFACE_POOL + (context->surfaces_pool)); +} + +/** + * gst_vaapi_context_get_surface_count: + * @context: a #GstVaapiContext + * + * Retrieves the number of free surfaces left in the pool. + * + * Return value: the number of free surfaces available in the pool + */ +guint +gst_vaapi_context_get_surface_count (GstVaapiContext * context) +{ + g_return_val_if_fail (context != NULL, 0); + + if (gst_vaapi_video_pool_get_capacity (context->surfaces_pool) == 0) + return G_MAXUINT; + return gst_vaapi_video_pool_get_size (context->surfaces_pool); +} + +/** + * gst_vaapi_context_reset_on_resize: + * @context: a #GstVaapiContext + * @reset_on_resize: Should the context be reset on size change + * + * Sets whether the underlying context should be reset when a size change + * happens. The proper setting for this is codec dependent. + */ +void +gst_vaapi_context_reset_on_resize (GstVaapiContext * context, + gboolean reset_on_resize) +{ + g_return_if_fail (context != NULL); + + context->reset_on_resize = reset_on_resize; +} + +/** + * gst_vaapi_context_get_surface_formats: + * @context: a #GstVaapiContext + * + * Determines the set of supported formats by the surfaces associated + * to @context. The caller owns an extra reference of the resulting + * array of #GstVideoFormat elements, so it shall be released with + * g_array_unref after usage. + * + * Return value: (transfer full): the set of target formats supported + * by the surfaces in @context. + */ +GArray * +gst_vaapi_context_get_surface_formats (GstVaapiContext * context) +{ + g_return_val_if_fail (context, NULL); + + if (!ensure_attributes (context)) + return NULL; + + if (context->attribs->formats) + return g_array_ref (context->attribs->formats); + return NULL; +} + +/** + * gst_vaapi_context_get_surface_attributes: + * @context: a #GstVaapiContext + * @out_attribs: an allocated #GstVaapiConfigSurfaceAttributes + * + * Copy context's surface restrictions to @out_attribs, EXCEPT the + * color formats. Use gst_vaapi_context_get_surface_formats() to get + * them. + * + * Returns: %TRUE if the attributes were extracted and copied; %FALSE, + * otherwise + **/ +gboolean +gst_vaapi_context_get_surface_attributes (GstVaapiContext * context, + GstVaapiConfigSurfaceAttributes * out_attribs) +{ + g_return_val_if_fail (context, FALSE); + + if (!ensure_attributes (context)) + return FALSE; + + if (out_attribs) { + out_attribs->min_width = context->attribs->min_width; + out_attribs->min_height = context->attribs->min_height; + out_attribs->max_width = context->attribs->max_width; + out_attribs->max_height = context->attribs->max_height; + out_attribs->mem_types = context->attribs->mem_types; + out_attribs->formats = NULL; + } + + return TRUE; +} + +/** + * gst_vaapi_context_ref: + * @context: a #GstVaapiContext + * + * Atomically increases the reference count of the given @context by one. + * + * Returns: The same @context argument + */ +GstVaapiContext * +gst_vaapi_context_ref (GstVaapiContext * context) +{ + g_return_val_if_fail (context != NULL, NULL); + + g_atomic_int_inc (&context->ref_count); + + return context; +} + +/** + * gst_vaapi_context_unref: + * @context: a #GstVaapiContext + * + * Atomically decreases the reference count of the @context by one. If + * the reference count reaches zero, the object will be free'd. + */ +void +gst_vaapi_context_unref (GstVaapiContext * context) +{ + g_return_if_fail (context != NULL); + g_return_if_fail (context->ref_count > 0); + + if (g_atomic_int_dec_and_test (&context->ref_count)) { + context_destroy (context); + context_destroy_surfaces (context); + gst_vaapi_display_replace (&context->display, NULL); + g_slice_free (GstVaapiContext, context); + } +} diff --git a/gst-libs/gst/vaapi/gstvaapicontext.h b/gst-libs/gst/vaapi/gstvaapicontext.h new file mode 100644 index 0000000000..7117722b4f --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapicontext.h @@ -0,0 +1,170 @@ +/* + * gstvaapicontext.h - VA context abstraction (private) + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_CONTEXT_H +#define GST_VAAPI_CONTEXT_H + +#include "gstvaapiprofile.h" +#include "gstvaapidisplay.h" +#include "gstvaapisurface.h" +#include "gstvaapiutils_core.h" +#include "gstvaapivideopool.h" + +G_BEGIN_DECLS + +#define GST_VAAPI_CONTEXT(obj) \ + ((GstVaapiContext *) (obj)) + +typedef struct _GstVaapiConfigInfoEncoder GstVaapiConfigInfoEncoder; +typedef struct _GstVaapiContextInfo GstVaapiContextInfo; +typedef struct _GstVaapiContext GstVaapiContext; + +/** + * GstVaapiContextUsage: + * @GST_VAAPI_CONTEXT_MODE_DECODE: context used for decoding. + * @GST_VAAPI_CONTEXT_MODE_ENCODE: context used for encoding. + * @GST_VAAPI_CONTEXT_MODE_VPP: context used for video processing. + * + * The set of supported VA context usages. + */ +typedef enum { + GST_VAAPI_CONTEXT_USAGE_DECODE = 1, + GST_VAAPI_CONTEXT_USAGE_ENCODE, + GST_VAAPI_CONTEXT_USAGE_VPP, +} GstVaapiContextUsage; + +/** + * GstVaapiConfigInfoEncoder: + * @rc_mode: rate-control mode (#GstVaapiRateControl). + * @packed_headers: notify encoder that packed headers are submitted (mask). + * @roi_capability: if encoder supports regions-of-interest. + * @roi_num_supported: The number of regions-of-interest supported. + * + * Extra configuration for encoding. + */ +struct _GstVaapiConfigInfoEncoder +{ + GstVaapiRateControl rc_mode; + guint packed_headers; + gboolean roi_capability; + guint roi_num_supported; +}; + +/** + * GstVaapiContextInfo: + * + * Structure holding VA context info like encoded size, decoder + * profile and entry-point to use, and maximum number of reference + * frames reported by the bitstream. + */ +struct _GstVaapiContextInfo +{ + GstVaapiContextUsage usage; + GstVaapiProfile profile; + GstVaapiEntrypoint entrypoint; + GstVaapiChromaType chroma_type; + guint width; + guint height; + guint ref_frames; + union _GstVaapiConfigInfo { + GstVaapiConfigInfoEncoder encoder; + } config; +}; + +/** + * GstVaapiContext: + * + * A VA context wrapper. + */ +struct _GstVaapiContext +{ + /*< private >*/ + gint ref_count; + GstVaapiDisplay *display; + GstVaapiID object_id; + + /*< public >*/ + GstVaapiContextInfo info; + VAProfile va_profile; + VAEntrypoint va_entrypoint; + VAConfigID va_config; + GPtrArray *surfaces; + GstVaapiVideoPool *surfaces_pool; + gboolean reset_on_resize; + GstVaapiConfigSurfaceAttributes *attribs; + GstVideoFormat preferred_format; +}; + +#define GST_VAAPI_CONTEXT_ID(context) (((GstVaapiContext *)(context))->object_id) +#define GST_VAAPI_CONTEXT_DISPLAY(context) (((GstVaapiContext *)(context))->display) + +G_GNUC_INTERNAL +GstVaapiContext * +gst_vaapi_context_new (GstVaapiDisplay * display, + const GstVaapiContextInfo * cip); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_context_reset (GstVaapiContext * context, + const GstVaapiContextInfo * new_cip); + +G_GNUC_INTERNAL +GstVaapiID +gst_vaapi_context_get_id (GstVaapiContext * context); + +G_GNUC_INTERNAL +GstVaapiSurfaceProxy * +gst_vaapi_context_get_surface_proxy (GstVaapiContext * context); + +G_GNUC_INTERNAL +guint +gst_vaapi_context_get_surface_count (GstVaapiContext * context); + +G_GNUC_INTERNAL +void +gst_vaapi_context_reset_on_resize (GstVaapiContext * context, + gboolean reset_on_resize); + +G_GNUC_INTERNAL +GArray * +gst_vaapi_context_get_surface_formats (GstVaapiContext * context); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_context_get_surface_attributes (GstVaapiContext * context, + GstVaapiConfigSurfaceAttributes * out_attribs); + +G_GNUC_INTERNAL +GstVaapiContext * +gst_vaapi_context_ref (GstVaapiContext * context); + +G_GNUC_INTERNAL +void +gst_vaapi_context_unref (GstVaapiContext * context); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiContext, gst_vaapi_context_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_CONTEXT_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidebug.h b/gst-libs/gst/vaapi/gstvaapidebug.h new file mode 100644 index 0000000000..88ea3123ca --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidebug.h @@ -0,0 +1,38 @@ +/* + * gstvaapidebug.h - VA-API debugging utilities + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DEBUG_H +#define GST_VAAPI_DEBUG_H + +#include + +#if DEBUG +GST_DEBUG_CATEGORY_EXTERN(gst_debug_vaapi); +#define GST_CAT_DEFAULT gst_debug_vaapi +#endif + +#if DEBUG_VAAPI_DISPLAY +GST_DEBUG_CATEGORY_EXTERN(gst_debug_vaapi_display); +#define GST_CAT_DEFAULT gst_debug_vaapi_display +#endif + +#endif /* GST_VAAPI_DEBUG_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidecoder.c b/gst-libs/gst/vaapi/gstvaapidecoder.c new file mode 100644 index 0000000000..ed702310ba --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder.c @@ -0,0 +1,1213 @@ +/* + * gstvaapidecoder.c - VA decoder abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapidecoder + * @short_description: VA decoder abstraction + */ + +#include "sysdeps.h" +#include "gstvaapicompat.h" +#include "gstvaapidecoder.h" +#include "gstvaapidecoder_priv.h" +#include "gstvaapiparser_frame.h" +#include "gstvaapisurfaceproxy_priv.h" +#include "gstvaapiutils.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +enum +{ + PROP_DISPLAY = 1, + PROP_CAPS, + N_PROPERTIES +}; +static GParamSpec *g_properties[N_PROPERTIES] = { NULL, }; + +G_DEFINE_TYPE (GstVaapiDecoder, gst_vaapi_decoder, GST_TYPE_OBJECT); + +static void drop_frame (GstVaapiDecoder * decoder, GstVideoCodecFrame * frame); + +static void +parser_state_reset (GstVaapiParserState * ps) +{ + + if (ps->input_adapter) + gst_adapter_clear (ps->input_adapter); + if (ps->output_adapter) + gst_adapter_clear (ps->output_adapter); + ps->current_adapter = NULL; + + if (ps->next_unit_pending) { + gst_vaapi_decoder_unit_clear (&ps->next_unit); + ps->next_unit_pending = FALSE; + } + + ps->current_frame_number = 0; + ps->input_offset1 = ps->input_offset2 = 0; + ps->at_eos = FALSE; +} + +static void +parser_state_finalize (GstVaapiParserState * ps) +{ + if (ps->input_adapter) { + gst_adapter_clear (ps->input_adapter); + g_object_unref (ps->input_adapter); + ps->input_adapter = NULL; + } + + if (ps->output_adapter) { + gst_adapter_clear (ps->output_adapter); + g_object_unref (ps->output_adapter); + ps->output_adapter = NULL; + } + + if (ps->next_unit_pending) { + gst_vaapi_decoder_unit_clear (&ps->next_unit); + ps->next_unit_pending = FALSE; + } +} + +static gboolean +parser_state_init (GstVaapiParserState * ps) +{ + memset (ps, 0, sizeof (*ps)); + + ps->input_adapter = gst_adapter_new (); + if (!ps->input_adapter) + return FALSE; + + ps->output_adapter = gst_adapter_new (); + if (!ps->output_adapter) + return FALSE; + return TRUE; +} + +static void +parser_state_prepare (GstVaapiParserState * ps, GstAdapter * adapter) +{ + /* XXX: check we really have a continuity from the previous call */ + if (ps->current_adapter != adapter) + goto reset; + return; + +reset: + ps->current_adapter = adapter; + ps->input_offset1 = -1; + ps->input_offset2 = -1; +} + +static gboolean +push_buffer (GstVaapiDecoder * decoder, GstBuffer * buffer) +{ + if (!buffer) { + buffer = gst_buffer_new (); + if (!buffer) + return FALSE; + GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_EOS); + } + + GST_DEBUG ("queue encoded data buffer %p (%zu bytes)", + buffer, gst_buffer_get_size (buffer)); + + g_async_queue_push (decoder->buffers, buffer); + return TRUE; +} + +static GstBuffer * +pop_buffer (GstVaapiDecoder * decoder) +{ + GstBuffer *buffer; + + buffer = g_async_queue_try_pop (decoder->buffers); + if (!buffer) + return NULL; + + GST_DEBUG ("dequeue buffer %p for decoding (%zu bytes)", + buffer, gst_buffer_get_size (buffer)); + + return buffer; +} + +static GstVaapiDecoderStatus +do_parse (GstVaapiDecoder * decoder, + GstVideoCodecFrame * base_frame, GstAdapter * adapter, gboolean at_eos, + guint * got_unit_size_ptr, gboolean * got_frame_ptr) +{ + GstVaapiParserState *const ps = &decoder->parser_state; + GstVaapiParserFrame *frame; + GstVaapiDecoderUnit *unit; + GstVaapiDecoderStatus status; + + *got_unit_size_ptr = 0; + *got_frame_ptr = FALSE; + + frame = gst_video_codec_frame_get_user_data (base_frame); + if (!frame) { + GstVideoCodecState *const codec_state = decoder->codec_state; + frame = gst_vaapi_parser_frame_new (codec_state->info.width, + codec_state->info.height); + if (!frame) + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + gst_video_codec_frame_set_user_data (base_frame, + frame, (GDestroyNotify) gst_vaapi_mini_object_unref); + } + + parser_state_prepare (ps, adapter); + + unit = &ps->next_unit; + if (ps->next_unit_pending) { + ps->next_unit_pending = FALSE; + goto got_unit; + } + gst_vaapi_decoder_unit_init (unit); + + ps->current_frame = base_frame; + status = GST_VAAPI_DECODER_GET_CLASS (decoder)->parse (decoder, + adapter, at_eos, unit); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) { + if (at_eos && frame->units->len > 0 && + status == GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA) { + /* XXX: assume the frame is complete at */ + *got_frame_ptr = TRUE; + return GST_VAAPI_DECODER_STATUS_SUCCESS; + } + return status; + } + + if (GST_VAAPI_DECODER_UNIT_IS_FRAME_START (unit) && frame->units->len > 0) { + ps->next_unit_pending = TRUE; + *got_frame_ptr = TRUE; + return GST_VAAPI_DECODER_STATUS_SUCCESS; + } + +got_unit: + gst_vaapi_parser_frame_append_unit (frame, unit); + *got_unit_size_ptr = unit->size; + *got_frame_ptr = GST_VAAPI_DECODER_UNIT_IS_FRAME_END (unit); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +do_decode_units (GstVaapiDecoder * decoder, GArray * units) +{ + GstVaapiDecoderClass *const klass = GST_VAAPI_DECODER_GET_CLASS (decoder); + GstVaapiDecoderStatus status; + guint i; + + for (i = 0; i < units->len; i++) { + GstVaapiDecoderUnit *const unit = + &g_array_index (units, GstVaapiDecoderUnit, i); + if (GST_VAAPI_DECODER_UNIT_IS_SKIPPED (unit)) + continue; + status = klass->decode (decoder, unit); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +do_decode_1 (GstVaapiDecoder * decoder, GstVaapiParserFrame * frame) +{ + GstVaapiDecoderClass *const klass = GST_VAAPI_DECODER_GET_CLASS (decoder); + GstVaapiDecoderStatus status; + + if (frame->pre_units->len > 0) { + status = do_decode_units (decoder, frame->pre_units); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + } + + if (frame->units->len > 0) { + if (klass->start_frame) { + GstVaapiDecoderUnit *const unit = + &g_array_index (frame->units, GstVaapiDecoderUnit, 0); + status = klass->start_frame (decoder, unit); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + } + + status = do_decode_units (decoder, frame->units); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + if (klass->end_frame) { + status = klass->end_frame (decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + } + } + + if (frame->post_units->len > 0) { + status = do_decode_units (decoder, frame->post_units); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + } + + /* Drop frame if there is no slice data unit in there */ + if (G_UNLIKELY (frame->units->len == 0)) + return (GstVaapiDecoderStatus) GST_VAAPI_DECODER_STATUS_DROP_FRAME; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static inline GstVaapiDecoderStatus +do_decode (GstVaapiDecoder * decoder, GstVideoCodecFrame * base_frame) +{ + GstVaapiParserState *const ps = &decoder->parser_state; + GstVaapiParserFrame *const frame = base_frame->user_data; + GstVaapiDecoderStatus status; + + ps->current_frame = base_frame; + + gst_vaapi_parser_frame_ref (frame); + status = do_decode_1 (decoder, frame); + gst_vaapi_parser_frame_unref (frame); + + switch ((guint) status) { + case GST_VAAPI_DECODER_STATUS_DROP_FRAME: + drop_frame (decoder, base_frame); + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + break; + } + return status; +} + +static GstVaapiDecoderStatus +decode_step (GstVaapiDecoder * decoder) +{ + GstVaapiParserState *const ps = &decoder->parser_state; + GstVaapiDecoderStatus status; + GstBuffer *buffer; + gboolean got_frame; + guint got_unit_size, input_size; + + /* Fill adapter with all buffers we have in the queue */ + for (;;) { + buffer = pop_buffer (decoder); + if (!buffer) + break; + + ps->at_eos = GST_BUFFER_IS_EOS (buffer); + if (!ps->at_eos) + gst_adapter_push (ps->input_adapter, buffer); + } + + /* Parse and decode all decode units */ + input_size = gst_adapter_available (ps->input_adapter); + if (input_size == 0) { + if (ps->at_eos) + return GST_VAAPI_DECODER_STATUS_END_OF_STREAM; + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + } + + do { + if (!ps->current_frame) { + ps->current_frame = g_slice_new0 (GstVideoCodecFrame); + if (!ps->current_frame) + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + ps->current_frame->ref_count = 1; + ps->current_frame->system_frame_number = ps->current_frame_number++; + } + + status = do_parse (decoder, ps->current_frame, ps->input_adapter, + ps->at_eos, &got_unit_size, &got_frame); + GST_DEBUG ("parse frame (status = %d)", status); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) { + if (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA && ps->at_eos) + status = GST_VAAPI_DECODER_STATUS_END_OF_STREAM; + break; + } + + if (got_unit_size > 0) { + buffer = gst_adapter_take_buffer (ps->input_adapter, got_unit_size); + input_size -= got_unit_size; + + if (gst_adapter_available (ps->output_adapter) == 0) { + ps->current_frame->pts = gst_adapter_prev_pts (ps->input_adapter, NULL); + } + gst_adapter_push (ps->output_adapter, buffer); + } + + if (got_frame) { + ps->current_frame->input_buffer = + gst_adapter_take_buffer (ps->output_adapter, + gst_adapter_available (ps->output_adapter)); + + status = do_decode (decoder, ps->current_frame); + GST_DEBUG ("decode frame (status = %d)", status); + + gst_video_codec_frame_unref (ps->current_frame); + ps->current_frame = NULL; + break; + } + } while (input_size > 0); + return status; +} + +static void +drop_frame (GstVaapiDecoder * decoder, GstVideoCodecFrame * frame) +{ + GST_DEBUG ("drop frame %d", frame->system_frame_number); + + /* no surface proxy */ + gst_video_codec_frame_set_user_data (frame, NULL, NULL); + + frame->pts = GST_CLOCK_TIME_NONE; + GST_VIDEO_CODEC_FRAME_FLAG_SET (frame, + GST_VIDEO_CODEC_FRAME_FLAG_DECODE_ONLY); + + g_async_queue_push (decoder->frames, gst_video_codec_frame_ref (frame)); +} + +static inline void +push_frame (GstVaapiDecoder * decoder, GstVideoCodecFrame * frame) +{ + GstVaapiSurfaceProxy *const proxy = frame->user_data; + + GST_DEBUG ("push frame %d (surface 0x%08x)", frame->system_frame_number, + (guint32) GST_VAAPI_SURFACE_PROXY_SURFACE_ID (proxy)); + + g_async_queue_push (decoder->frames, gst_video_codec_frame_ref (frame)); +} + +static inline GstVideoCodecFrame * +pop_frame (GstVaapiDecoder * decoder, guint64 timeout) +{ + GstVideoCodecFrame *frame; + GstVaapiSurfaceProxy *proxy; + + if (G_LIKELY (timeout > 0)) + frame = g_async_queue_timeout_pop (decoder->frames, timeout); + else + frame = g_async_queue_try_pop (decoder->frames); + if (!frame) + return NULL; + + proxy = frame->user_data; + GST_DEBUG ("pop frame %d (surface 0x%08x)", frame->system_frame_number, + (proxy ? (guint32) GST_VAAPI_SURFACE_PROXY_SURFACE_ID (proxy) : + VA_INVALID_ID)); + + return frame; +} + +static gboolean +set_caps (GstVaapiDecoder * decoder, const GstCaps * caps) +{ + GstVideoCodecState *const codec_state = decoder->codec_state; + GstStructure *const structure = gst_caps_get_structure (caps, 0); + const GValue *v_codec_data; + + decoder->codec = gst_vaapi_get_codec_from_caps (caps); + if (!decoder->codec) + return FALSE; + + if (!gst_video_info_from_caps (&codec_state->info, caps)) + return FALSE; + + if (codec_state->caps) + gst_caps_unref (codec_state->caps); + codec_state->caps = gst_caps_copy (caps); + + v_codec_data = gst_structure_get_value (structure, "codec_data"); + if (v_codec_data) + gst_buffer_replace (&codec_state->codec_data, + gst_value_get_buffer (v_codec_data)); + return TRUE; +} + +static inline GstCaps * +get_caps (GstVaapiDecoder * decoder) +{ + return GST_VAAPI_DECODER_CODEC_STATE (decoder)->caps; +} + +static void +notify_codec_state_changed (GstVaapiDecoder * decoder) +{ + if (decoder->codec_state_changed_func) + decoder->codec_state_changed_func (decoder, decoder->codec_state, + decoder->codec_state_changed_data); +} + +static void +gst_vaapi_decoder_finalize (GObject * object) +{ + GstVaapiDecoder *const decoder = GST_VAAPI_DECODER (object); + + gst_video_codec_state_unref (decoder->codec_state); + decoder->codec_state = NULL; + + parser_state_finalize (&decoder->parser_state); + + if (decoder->buffers) { + g_async_queue_unref (decoder->buffers); + decoder->buffers = NULL; + } + + if (decoder->frames) { + g_async_queue_unref (decoder->frames); + decoder->frames = NULL; + } + + if (decoder->context) { + gst_vaapi_context_unref (decoder->context); + decoder->context = NULL; + } + decoder->va_context = VA_INVALID_ID; + + gst_vaapi_display_replace (&decoder->display, NULL); + decoder->va_display = NULL; + + G_OBJECT_CLASS (gst_vaapi_decoder_parent_class)->finalize (object); +} + +static void +gst_vaapi_decoder_set_property (GObject * object, guint property_id, + const GValue * value, GParamSpec * pspec) +{ + GstVaapiDecoder *const decoder = GST_VAAPI_DECODER (object); + + switch (property_id) { + case PROP_DISPLAY: + g_assert (decoder->display == NULL); + decoder->display = g_value_dup_object (value); + g_assert (decoder->display != NULL); + decoder->va_display = GST_VAAPI_DISPLAY_VADISPLAY (decoder->display); + break; + case PROP_CAPS:{ + GstCaps *caps = g_value_get_boxed (value); + if (!set_caps (decoder, caps)) { + GST_WARNING_OBJECT (decoder, "failed to set caps %" GST_PTR_FORMAT, + caps); + } + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +gst_vaapi_decoder_get_property (GObject * object, guint property_id, + GValue * value, GParamSpec * pspec) +{ + GstVaapiDecoder *const decoder = GST_VAAPI_DECODER (object); + + switch (property_id) { + case PROP_DISPLAY: + g_value_set_object (value, decoder->display); + break; + case PROP_CAPS: + g_value_set_boxed (value, gst_caps_ref (get_caps (decoder))); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +gst_vaapi_decoder_class_init (GstVaapiDecoderClass * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = gst_vaapi_decoder_set_property; + object_class->get_property = gst_vaapi_decoder_get_property; + object_class->finalize = gst_vaapi_decoder_finalize; + + /** + * GstVaapiDecoder:display: + * + * #GstVaapiDisplay to be used. + */ + g_properties[PROP_DISPLAY] = + g_param_spec_object ("display", "Gst VA-API Display", + "The VA-API display object to use", GST_TYPE_VAAPI_DISPLAY, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME); + + /** + * GstCaps:caps: + * + * #GstCaps the caps describing the media to process. + */ + g_properties[PROP_CAPS] = + g_param_spec_boxed ("caps", "Caps", + "The caps describing the media to process", GST_TYPE_CAPS, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME); + + g_object_class_install_properties (object_class, N_PROPERTIES, g_properties); +} + +static void +gst_vaapi_decoder_init (GstVaapiDecoder * decoder) +{ + GstVideoCodecState *codec_state; + + parser_state_init (&decoder->parser_state); + + codec_state = g_slice_new0 (GstVideoCodecState); + codec_state->ref_count = 1; + gst_video_info_init (&codec_state->info); + + decoder->va_context = VA_INVALID_ID; + decoder->codec_state = codec_state; + decoder->buffers = g_async_queue_new_full ((GDestroyNotify) gst_buffer_unref); + decoder->frames = g_async_queue_new_full ((GDestroyNotify) + gst_video_codec_frame_unref); +} + +/** + * gst_vaapi_decoder_replace: + * @old_decoder_ptr: a pointer to a #GstVaapiDecoder + * @new_decoder: a #GstVaapiDecoder + * + * Atomically replaces the decoder decoder held in @old_decoder_ptr + * with @new_decoder. This means that @old_decoder_ptr shall reference + * a valid decoder. However, @new_decoder can be NULL. + */ +void +gst_vaapi_decoder_replace (GstVaapiDecoder ** old_decoder_ptr, + GstVaapiDecoder * new_decoder) +{ + gst_object_replace ((GstObject **) old_decoder_ptr, GST_OBJECT (new_decoder)); +} + +/** + * gst_vaapi_decoder_get_user_data: + * @decoder: a #GstVaapiDecoder + * + * Retrieves the user-defined data associated with the @decoder, if any. + * + * Return value: the user-defined data associated with the @decoder + */ +gpointer +gst_vaapi_decoder_get_user_data (GstVaapiDecoder * decoder) +{ + g_return_val_if_fail (decoder != NULL, NULL); + + return decoder->user_data; +} + +/** + * gst_vaapi_decoder_set_user_data: + * @decoder: a #GstVaapiDecoder + * @user_data: the pointer to user-defined data + * + * Associates user-defined @user_data to the @decoder. Retrieve the + * attached value with gst_vaapi_decoder_get_user_data() function. + */ +void +gst_vaapi_decoder_set_user_data (GstVaapiDecoder * decoder, gpointer user_data) +{ + g_return_if_fail (decoder != NULL); + + decoder->user_data = user_data; +} + +/** + * gst_vaapi_decoder_get_codec: + * @decoder: a #GstVaapiDecoder + * + * Retrieves the @decoder codec type. + * + * Return value: the #GstVaapiCodec type for @decoder + */ +GstVaapiCodec +gst_vaapi_decoder_get_codec (GstVaapiDecoder * decoder) +{ + g_return_val_if_fail (decoder != NULL, (GstVaapiCodec) 0); + + return decoder->codec; +} + +/** + * gst_vaapi_decoder_get_codec_state: + * @decoder: a #GstVaapiDecoder + * + * Retrieves the @decoder codec state. The decoder owns the returned + * #GstVideoCodecState structure, so use gst_video_codec_state_ref() + * whenever necessary. + * + * Return value: the #GstVideoCodecState object for @decoder + */ +GstVideoCodecState * +gst_vaapi_decoder_get_codec_state (GstVaapiDecoder * decoder) +{ + g_return_val_if_fail (decoder != NULL, NULL); + + return GST_VAAPI_DECODER_CODEC_STATE (decoder); +} + +/** + * gst_vaapi_decoder_set_codec_state_changed_func: + * @decoder: a #GstVaapiDecoder + * @func: the function to call when codec state changed + * @user_data: a pointer to user-defined data + * + * Sets @func as the function to call whenever the @decoder codec + * state changes. + */ +void +gst_vaapi_decoder_set_codec_state_changed_func (GstVaapiDecoder * decoder, + GstVaapiDecoderStateChangedFunc func, gpointer user_data) +{ + g_return_if_fail (decoder != NULL); + + decoder->codec_state_changed_func = func; + decoder->codec_state_changed_data = user_data; +} + +/** + * gst_vaapi_decoder_get_caps: + * @decoder: a #GstVaapiDecoder + * + * Retrieves the @decoder caps. The decoder owns the returned caps, so + * use gst_caps_ref() whenever necessary. + * + * Returns: (transfer none): the @decoder caps + */ +GstCaps * +gst_vaapi_decoder_get_caps (GstVaapiDecoder * decoder) +{ + return get_caps (decoder); +} + +/** + * gst_vaapi_decoder_put_buffer: + * @decoder: a #GstVaapiDecoder + * @buf: a #GstBuffer + * + * Queues a #GstBuffer to the HW decoder. The decoder holds a + * reference to @buf. + * + * Caller can notify an End-Of-Stream with @buf set to %NULL. However, + * if an empty buffer is passed, i.e. a buffer with %NULL data pointer + * or size equals to zero, then the function ignores this buffer and + * returns %TRUE. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_decoder_put_buffer (GstVaapiDecoder * decoder, GstBuffer * buf) +{ + g_return_val_if_fail (decoder != NULL, FALSE); + + if (buf) { + if (gst_buffer_get_size (buf) == 0) + return TRUE; + buf = gst_buffer_ref (buf); + } + return push_buffer (decoder, buf); +} + +/** + * gst_vaapi_decoder_get_surface: + * @decoder: a #GstVaapiDecoder + * @out_proxy_ptr: the next decoded surface as a #GstVaapiSurfaceProxy + * + * Flushes encoded buffers to the decoder and returns a decoded + * surface, if any. + * + * On successful return, *@out_proxy_ptr contains the decoded surface + * as a #GstVaapiSurfaceProxy. The caller owns this object, so + * gst_vaapi_surface_proxy_unref() shall be called after usage. + * + * Return value: a #GstVaapiDecoderStatus + */ +GstVaapiDecoderStatus +gst_vaapi_decoder_get_surface (GstVaapiDecoder * decoder, + GstVaapiSurfaceProxy ** out_proxy_ptr) +{ + GstVideoCodecFrame *frame; + GstVaapiDecoderStatus status; + + g_return_val_if_fail (decoder != NULL, + GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER); + g_return_val_if_fail (out_proxy_ptr != NULL, + GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER); + + do { + frame = pop_frame (decoder, 0); + while (frame) { + if (!GST_VIDEO_CODEC_FRAME_IS_DECODE_ONLY (frame)) { + GstVaapiSurfaceProxy *const proxy = frame->user_data; + proxy->timestamp = frame->pts; + proxy->duration = frame->duration; + *out_proxy_ptr = gst_vaapi_surface_proxy_ref (proxy); + gst_video_codec_frame_unref (frame); + return GST_VAAPI_DECODER_STATUS_SUCCESS; + } + gst_video_codec_frame_unref (frame); + frame = pop_frame (decoder, 0); + } + status = decode_step (decoder); + } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS); + + *out_proxy_ptr = NULL; + return status; +} + +/** + * gst_vaapi_decoder_get_frame: + * @decoder: a #GstVaapiDecoder + * @out_frame_ptr: the next decoded frame as a #GstVideoCodecFrame + * + * On successful return, *@out_frame_ptr contains the next decoded + * frame available as a #GstVideoCodecFrame. The caller owns this + * object, so gst_video_codec_frame_unref() shall be called after + * usage. Otherwise, @GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA is + * returned if no decoded frame is available. + * + * The actual surface is available as a #GstVaapiSurfaceProxy attached + * to the user-data anchor of the output frame. Ownership of the proxy + * is transferred to the frame. + * + * This is equivalent to gst_vaapi_decoder_get_frame_with_timeout() + * with a timeout value of zero. + * + * Return value: a #GstVaapiDecoderStatus + */ +GstVaapiDecoderStatus +gst_vaapi_decoder_get_frame (GstVaapiDecoder * decoder, + GstVideoCodecFrame ** out_frame_ptr) +{ + return gst_vaapi_decoder_get_frame_with_timeout (decoder, out_frame_ptr, 0); +} + +/** + * gst_vaapi_decoder_get_frame_with_timeout: + * @decoder: a #GstVaapiDecoder + * @out_frame_ptr: the next decoded frame as a #GstVideoCodecFrame + * @timeout: the number of microseconds to wait for the frame, at most + * + * On successful return, *@out_frame_ptr contains the next decoded + * frame available as a #GstVideoCodecFrame. The caller owns this + * object, so gst_video_codec_frame_unref() shall be called after + * usage. Otherwise, @GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA is + * returned if no decoded frame is available. + * + * The actual surface is available as a #GstVaapiSurfaceProxy attached + * to the user-data anchor of the output frame. Ownership of the proxy + * is transferred to the frame. + * + * Return value: a #GstVaapiDecoderStatus + */ +GstVaapiDecoderStatus +gst_vaapi_decoder_get_frame_with_timeout (GstVaapiDecoder * decoder, + GstVideoCodecFrame ** out_frame_ptr, guint64 timeout) +{ + GstVideoCodecFrame *out_frame; + + g_return_val_if_fail (decoder != NULL, + GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER); + g_return_val_if_fail (out_frame_ptr != NULL, + GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER); + + out_frame = pop_frame (decoder, timeout); + if (!out_frame) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + + *out_frame_ptr = out_frame; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +void +gst_vaapi_decoder_set_picture_size (GstVaapiDecoder * decoder, + guint width, guint height) +{ + GstVideoCodecState *const codec_state = decoder->codec_state; + gboolean size_changed = FALSE; + + if (codec_state->info.width != width) { + GST_DEBUG ("picture width changed to %d", width); + codec_state->info.width = width; + gst_caps_set_simple (codec_state->caps, "width", G_TYPE_INT, width, NULL); + size_changed = TRUE; + } + + if (codec_state->info.height != height) { + GST_DEBUG ("picture height changed to %d", height); + codec_state->info.height = height; + gst_caps_set_simple (codec_state->caps, "height", G_TYPE_INT, height, NULL); + size_changed = TRUE; + } + + if (size_changed) + notify_codec_state_changed (decoder); +} + +void +gst_vaapi_decoder_set_framerate (GstVaapiDecoder * decoder, + guint fps_n, guint fps_d) +{ + GstVideoCodecState *const codec_state = decoder->codec_state; + + if (!fps_n || !fps_d) + return; + + if (codec_state->info.fps_n != fps_n || codec_state->info.fps_d != fps_d) { + GST_DEBUG ("framerate changed to %u/%u", fps_n, fps_d); + codec_state->info.fps_n = fps_n; + codec_state->info.fps_d = fps_d; + gst_caps_set_simple (codec_state->caps, + "framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL); + notify_codec_state_changed (decoder); + } +} + +void +gst_vaapi_decoder_set_pixel_aspect_ratio (GstVaapiDecoder * decoder, + guint par_n, guint par_d) +{ + GstVideoCodecState *const codec_state = decoder->codec_state; + + if (!par_n || !par_d) + return; + + if (codec_state->info.par_n != par_n || codec_state->info.par_d != par_d) { + GST_DEBUG ("pixel-aspect-ratio changed to %u/%u", par_n, par_d); + codec_state->info.par_n = par_n; + codec_state->info.par_d = par_d; + gst_caps_set_simple (codec_state->caps, + "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d, NULL); + notify_codec_state_changed (decoder); + } +} + +static const gchar * +gst_interlace_mode_to_string (GstVideoInterlaceMode mode) +{ + switch (mode) { + case GST_VIDEO_INTERLACE_MODE_PROGRESSIVE: + return "progressive"; + case GST_VIDEO_INTERLACE_MODE_INTERLEAVED: + return "interleaved"; + case GST_VIDEO_INTERLACE_MODE_MIXED: + return "mixed"; + default: + return ""; + } +} + +void +gst_vaapi_decoder_set_interlace_mode (GstVaapiDecoder * decoder, + GstVideoInterlaceMode mode) +{ + GstVideoCodecState *const codec_state = decoder->codec_state; + + if (codec_state->info.interlace_mode != mode) { + GST_DEBUG ("interlace mode changed to %s", + gst_interlace_mode_to_string (mode)); + codec_state->info.interlace_mode = mode; + gst_caps_set_simple (codec_state->caps, "interlaced", + G_TYPE_BOOLEAN, mode != GST_VIDEO_INTERLACE_MODE_PROGRESSIVE, NULL); + notify_codec_state_changed (decoder); + } +} + +void +gst_vaapi_decoder_set_interlaced (GstVaapiDecoder * decoder, + gboolean interlaced) +{ + gst_vaapi_decoder_set_interlace_mode (decoder, + (interlaced ? + GST_VIDEO_INTERLACE_MODE_INTERLEAVED : + GST_VIDEO_INTERLACE_MODE_PROGRESSIVE)); +} + +void +gst_vaapi_decoder_set_multiview_mode (GstVaapiDecoder * decoder, + gint views, GstVideoMultiviewMode mv_mode, GstVideoMultiviewFlags mv_flags) +{ + GstVideoCodecState *const codec_state = decoder->codec_state; + GstVideoInfo *info = &codec_state->info; + + if (GST_VIDEO_INFO_VIEWS (info) != views || + GST_VIDEO_INFO_MULTIVIEW_MODE (info) != mv_mode || + GST_VIDEO_INFO_MULTIVIEW_FLAGS (info) != mv_flags) { + const gchar *mv_mode_str = + gst_video_multiview_mode_to_caps_string (mv_mode); + + GST_DEBUG ("Multiview mode changed to %s flags 0x%x views %d", + mv_mode_str, mv_flags, views); + GST_VIDEO_INFO_MULTIVIEW_MODE (info) = mv_mode; + GST_VIDEO_INFO_MULTIVIEW_FLAGS (info) = mv_flags; + GST_VIDEO_INFO_VIEWS (info) = views; + + gst_caps_set_simple (codec_state->caps, "multiview-mode", + G_TYPE_STRING, mv_mode_str, + "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mv_flags, + GST_FLAG_SET_MASK_EXACT, "views", G_TYPE_INT, views, NULL); + + notify_codec_state_changed (decoder); + } +} + +gboolean +gst_vaapi_decoder_ensure_context (GstVaapiDecoder * decoder, + GstVaapiContextInfo * cip) +{ + gst_vaapi_decoder_set_picture_size (decoder, cip->width, cip->height); + + cip->usage = GST_VAAPI_CONTEXT_USAGE_DECODE; + if (decoder->context) { + if (!gst_vaapi_context_reset (decoder->context, cip)) + return FALSE; + } else { + decoder->context = gst_vaapi_context_new (decoder->display, cip); + if (!decoder->context) + return FALSE; + } + decoder->va_context = gst_vaapi_context_get_id (decoder->context); + return TRUE; +} + +void +gst_vaapi_decoder_push_frame (GstVaapiDecoder * decoder, + GstVideoCodecFrame * frame) +{ + push_frame (decoder, frame); +} + +GstVaapiDecoderStatus +gst_vaapi_decoder_parse (GstVaapiDecoder * decoder, + GstVideoCodecFrame * base_frame, GstAdapter * adapter, gboolean at_eos, + guint * got_unit_size_ptr, gboolean * got_frame_ptr) +{ + g_return_val_if_fail (decoder != NULL, + GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER); + g_return_val_if_fail (base_frame != NULL, + GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER); + g_return_val_if_fail (adapter != NULL, + GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER); + g_return_val_if_fail (got_unit_size_ptr != NULL, + GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER); + g_return_val_if_fail (got_frame_ptr != NULL, + GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER); + + return do_parse (decoder, base_frame, adapter, at_eos, + got_unit_size_ptr, got_frame_ptr); +} + +GstVaapiDecoderStatus +gst_vaapi_decoder_decode (GstVaapiDecoder * decoder, GstVideoCodecFrame * frame) +{ + g_return_val_if_fail (decoder != NULL, + GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER); + g_return_val_if_fail (frame != NULL, + GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER); + g_return_val_if_fail (frame->user_data != NULL, + GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER); + + return do_decode (decoder, frame); +} + +/* This function really marks the end of input, + * so that the decoder will drain out any pending + * frames on calls to gst_vaapi_decoder_get_frame_with_timeout() */ +GstVaapiDecoderStatus +gst_vaapi_decoder_flush (GstVaapiDecoder * decoder) +{ + GstVaapiDecoderClass *klass; + + g_return_val_if_fail (decoder != NULL, + GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER); + + klass = GST_VAAPI_DECODER_GET_CLASS (decoder); + + if (klass->flush) + return klass->flush (decoder); + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +/* Reset the decoder instance to a clean state, + * clearing any pending decode state, without + * reallocating the entire decoder */ +GstVaapiDecoderStatus +gst_vaapi_decoder_reset (GstVaapiDecoder * decoder) +{ + GstVaapiDecoderClass *klass; + GstVaapiDecoderStatus ret = GST_VAAPI_DECODER_STATUS_SUCCESS; + + g_return_val_if_fail (decoder != NULL, + GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER); + + klass = GST_VAAPI_DECODER_GET_CLASS (decoder); + + GST_DEBUG ("Resetting decoder"); + + if (klass->reset) { + ret = klass->reset (decoder); + } else { + GST_WARNING_OBJECT (decoder, "missing reset() implementation"); + } + + if (ret != GST_VAAPI_DECODER_STATUS_SUCCESS) + return ret; + + /* Clear any buffers and frame in the queues */ + { + GstVideoCodecFrame *frame; + GstBuffer *buffer; + + while ((frame = g_async_queue_try_pop (decoder->frames)) != NULL) + gst_video_codec_frame_unref (frame); + + while ((buffer = g_async_queue_try_pop (decoder->buffers)) != NULL) + gst_buffer_unref (buffer); + } + + parser_state_reset (&decoder->parser_state); + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +GstVaapiDecoderStatus +gst_vaapi_decoder_decode_codec_data (GstVaapiDecoder * decoder) +{ + GstVaapiDecoderClass *const klass = GST_VAAPI_DECODER_GET_CLASS (decoder); + GstBuffer *const codec_data = GST_VAAPI_DECODER_CODEC_DATA (decoder); + GstVaapiDecoderStatus status; + GstMapInfo map_info; + const guchar *buf; + guint buf_size; + + if (!codec_data) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + /* FIXME: add a meaningful error code? */ + if (!klass->decode_codec_data) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + if (!gst_buffer_map (codec_data, &map_info, GST_MAP_READ)) { + GST_ERROR ("failed to map buffer"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + buf = map_info.data; + buf_size = map_info.size; + if (G_LIKELY (buf && buf_size > 0)) + status = klass->decode_codec_data (decoder, buf, buf_size); + else + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + gst_buffer_unmap (codec_data, &map_info); + return status; +} + +/** + * gst_vaapi_decoder_update_caps: + * @decoder: a #GstVaapiDecoder + * @caps: a #GstCaps + * + * If @caps is compatible with the current caps, or they have the same + * codec, the caps are updated internally. + * + * This method will not call codec_state_changed() callback, since + * this function is intended to run sync and during the set_format() + * vmethod. + * + * Returns: %TRUE if the caps were updated internally. + **/ +gboolean +gst_vaapi_decoder_update_caps (GstVaapiDecoder * decoder, GstCaps * caps) +{ + GstCaps *decoder_caps; + GstVaapiCodec codec; + + g_return_val_if_fail (decoder != NULL, FALSE); + g_return_val_if_fail (caps != NULL, FALSE); + + decoder_caps = get_caps (decoder); + if (!decoder_caps) + return FALSE; + + if (gst_caps_is_always_compatible (caps, decoder_caps)) + return set_caps (decoder, caps); + + codec = gst_vaapi_get_codec_from_caps (caps); + if (codec == 0) + return FALSE; + if (codec == decoder->codec) { + if (set_caps (decoder, caps)) { + return + gst_vaapi_decoder_decode_codec_data (decoder) == + GST_VAAPI_DECODER_STATUS_SUCCESS; + } + } + + return FALSE; +} + +/** + * gst_vaapi_decoder_get_surface_attributres: + * @decoder: a #GstVaapiDecoder instances + * @min_width (out): the minimal surface width + * @min_height (out): the minimal surface height + * @max_width (out): the maximal surface width + * @max_height (out): the maximal surface height + * + * Fetches the valid surface's attributes for the current context. + * + * Returns: a #GArray of valid formats we get or %NULL if failed. + **/ +GArray * +gst_vaapi_decoder_get_surface_attributes (GstVaapiDecoder * decoder, + gint * min_width, gint * min_height, gint * max_width, gint * max_height, + guint * mem_types) +{ + gboolean ret; + GstVaapiConfigSurfaceAttributes attribs = { 0, }; + + g_return_val_if_fail (decoder != NULL, FALSE); + + if (!decoder->context) + return NULL; + + ret = gst_vaapi_context_get_surface_attributes (decoder->context, &attribs); + if (ret) + attribs.formats = gst_vaapi_context_get_surface_formats (decoder->context); + + if (!attribs.formats) + return NULL; + if (attribs.formats->len == 0) { + g_array_unref (attribs.formats); + return NULL; + } + + if (min_width) + *min_width = attribs.min_width; + if (min_height) + *min_height = attribs.min_height; + if (max_width) + *max_width = attribs.max_width; + if (max_height) + *max_height = attribs.max_height; + if (mem_types) + *mem_types = attribs.mem_types; + return attribs.formats; +} diff --git a/gst-libs/gst/vaapi/gstvaapidecoder.h b/gst-libs/gst/vaapi/gstvaapidecoder.h new file mode 100644 index 0000000000..2c55e2e1fb --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder.h @@ -0,0 +1,148 @@ +/* + * gstvaapidecoder.h - VA decoder abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODER_H +#define GST_VAAPI_DECODER_H + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_DECODER \ + (gst_vaapi_decoder_get_type ()) +#define GST_VAAPI_DECODER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DECODER, GstVaapiDecoder)) +#define GST_VAAPI_IS_DECODER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_DECODER)) + +typedef struct _GstVaapiDecoder GstVaapiDecoder; +typedef void (*GstVaapiDecoderStateChangedFunc) (GstVaapiDecoder * decoder, + const GstVideoCodecState * codec_state, gpointer user_data); + +/** + * GstVaapiDecoderStatus: + * @GST_VAAPI_DECODER_STATUS_SUCCESS: Success. + * @GST_VAAPI_DECODER_STATUS_END_OF_STREAM: End-Of-Stream. + * @GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED: No memory left. + * @GST_VAAPI_DECODER_STATUS_ERROR_INIT_FAILED: Decoder initialization failure. + * @GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC: Unsupported codec. + * @GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA: Not enough input data to decode. + * @GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE: No surface left to hold the decoded picture. + * @GST_VAAPI_DECODER_STATUS_ERROR_INVALID_SURFACE: Invalid surface. + * @GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER: Invalid or unsupported bitstream data. + * @GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE: Unsupported codec profile. + * @GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT: Unsupported chroma format. + * @GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER: Unsupported parameter. + * @GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN: Unknown error. + * + * Decoder status for gst_vaapi_decoder_get_surface(). + */ +typedef enum { + GST_VAAPI_DECODER_STATUS_SUCCESS = 0, + GST_VAAPI_DECODER_STATUS_END_OF_STREAM, + GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED, + GST_VAAPI_DECODER_STATUS_ERROR_INIT_FAILED, + GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC, + GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA, + GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE, + GST_VAAPI_DECODER_STATUS_ERROR_INVALID_SURFACE, + GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER, + GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE, + GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT, + GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER, + GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN = -1 +} GstVaapiDecoderStatus; + +GType +gst_vaapi_decoder_get_type (void) G_GNUC_CONST; + +void +gst_vaapi_decoder_replace (GstVaapiDecoder ** old_decoder_ptr, + GstVaapiDecoder * new_decoder); + +gpointer +gst_vaapi_decoder_get_user_data (GstVaapiDecoder * decoder); + +void +gst_vaapi_decoder_set_user_data (GstVaapiDecoder * decoder, gpointer user_data); + +GstVaapiCodec +gst_vaapi_decoder_get_codec (GstVaapiDecoder * decoder); + +GstVideoCodecState * +gst_vaapi_decoder_get_codec_state (GstVaapiDecoder * decoder); + +void +gst_vaapi_decoder_set_codec_state_changed_func (GstVaapiDecoder * decoder, + GstVaapiDecoderStateChangedFunc func, gpointer user_data); + +GstCaps * +gst_vaapi_decoder_get_caps (GstVaapiDecoder * decoder); + +gboolean +gst_vaapi_decoder_put_buffer (GstVaapiDecoder * decoder, GstBuffer * buf); + +GstVaapiDecoderStatus +gst_vaapi_decoder_get_surface (GstVaapiDecoder * decoder, + GstVaapiSurfaceProxy ** out_proxy_ptr); + +GstVaapiDecoderStatus +gst_vaapi_decoder_get_frame (GstVaapiDecoder * decoder, + GstVideoCodecFrame ** out_frame_ptr); + +GstVaapiDecoderStatus +gst_vaapi_decoder_get_frame_with_timeout (GstVaapiDecoder * decoder, + GstVideoCodecFrame ** out_frame_ptr, guint64 timeout); + +GstVaapiDecoderStatus +gst_vaapi_decoder_parse (GstVaapiDecoder * decoder, + GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos, + guint * got_unit_size_ptr, gboolean * got_frame_ptr); + +GstVaapiDecoderStatus +gst_vaapi_decoder_decode (GstVaapiDecoder * decoder, + GstVideoCodecFrame * frame); + +GstVaapiDecoderStatus +gst_vaapi_decoder_flush (GstVaapiDecoder * decoder); + +GstVaapiDecoderStatus +gst_vaapi_decoder_reset (GstVaapiDecoder * decoder); + +gboolean +gst_vaapi_decoder_update_caps (GstVaapiDecoder * decoder, GstCaps * caps); + +GArray * +gst_vaapi_decoder_get_surface_attributes (GstVaapiDecoder * decoder, + gint * min_width, gint * min_height, gint * max_width, gint * max_height, + guint * mem_types); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDecoder, gst_object_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_DECODER_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_av1.c b/gst-libs/gst/vaapi/gstvaapidecoder_av1.c new file mode 100644 index 0000000000..eff62e635d --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_av1.c @@ -0,0 +1,1288 @@ +/* + * gstvaapidecoder_av1.c - AV1 decoder + * + * Copyright (C) 2019-2020 Intel Corporation + * Author: Junyan He + * + * 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:gstvaapidecoder_av1 + * @short_description: AV1 decoder + */ + +#include "sysdeps.h" +#include +#include "gstvaapidecoder_av1.h" +#include "gstvaapidecoder_objects.h" +#include "gstvaapidecoder_priv.h" +#include "gstvaapidisplay_priv.h" + +#include "gstvaapicompat.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +#define GST_VAAPI_DECODER_AV1_CAST(decoder) ((GstVaapiDecoderAV1 *)(decoder)) + +typedef struct _GstVaapiDecoderAV1Private GstVaapiDecoderAV1Private; +typedef struct _GstVaapiDecoderAV1Class GstVaapiDecoderAV1Class; +typedef struct _GstVaapiPictureAV1 GstVaapiPictureAV1; + +struct _GstVaapiDecoderAV1Private +{ + GstVaapiProfile profile; + guint width; + guint height; + gboolean reset_context; + GstVaapiPictureAV1 *current_picture; + gboolean annex_b; + GstAV1Parser *parser; + GstAV1SequenceHeaderOBU *seq_header; + GstVaapiPictureAV1 *ref_frames[GST_AV1_NUM_REF_FRAMES]; +}; + +/** + * GstVaapiDecoderAV1: + * + * A decoder based on AV1. + */ +struct _GstVaapiDecoderAV1 +{ + /*< private > */ + GstVaapiDecoder parent_instance; + GstVaapiDecoderAV1Private priv; +}; + +/** + * GstVaapiDecoderAV1Class: + * + * A decoder class based on AV1. + */ +struct _GstVaapiDecoderAV1Class +{ + /*< private > */ + GstVaapiDecoderClass parent_class; +}; + +G_DEFINE_TYPE (GstVaapiDecoderAV1, gst_vaapi_decoder_av1, + GST_TYPE_VAAPI_DECODER); + +/* ------------------------------------------------------------------------- */ +/* --- AV1 Parser Info --- */ +/* ------------------------------------------------------------------------- */ +typedef struct _GstVaapiParserInfoAV1 GstVaapiParserInfoAV1; +struct _GstVaapiParserInfoAV1 +{ + GstVaapiMiniObject parent_instance; + GstAV1OBU obu; + union + { + GstAV1SequenceHeaderOBU seq_header; + GstAV1MetadataOBU metadata; + GstAV1FrameHeaderOBU frame_header; + GstAV1TileListOBU tile_list; + GstAV1TileGroupOBU tile_group; + GstAV1FrameOBU frame; + }; + /* The offset between input data and real OBU data */ + gint data_offset; +}; + +static void +parser_info_av1_finalize (GstVaapiParserInfoAV1 * pi) +{ +} + +static inline const GstVaapiMiniObjectClass * +parser_info_av1_class (void) +{ + static const GstVaapiMiniObjectClass GstVaapiParserInfoAV1Class = { + .size = sizeof (GstVaapiParserInfoAV1), + .finalize = (GDestroyNotify) parser_info_av1_finalize + }; + return &GstVaapiParserInfoAV1Class; +} + +static inline GstVaapiParserInfoAV1 * +parser_info_av1_new (GstAV1OBU * obu) +{ + GstVaapiParserInfoAV1 *pi = (GstVaapiParserInfoAV1 *) + gst_vaapi_mini_object_new (parser_info_av1_class ()); + + if (pi) + pi->obu = *obu; + + return pi; +} + +/* ------------------------------------------------------------------------- */ +/* --- AV1 Picture --- */ +/* ------------------------------------------------------------------------- */ +struct _GstVaapiPictureAV1 +{ + GstVaapiPicture base; + /* When apply_grain enabled, recon proxy is different from the display + proxy, otherwise the same. */ + GstVaapiSurfaceProxy *recon_proxy; + GstAV1FrameHeaderOBU frame_header; + gboolean cloned; +}; + +GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiPictureAV1, gst_vaapi_picture_av1); + +void +gst_vaapi_picture_av1_destroy (GstVaapiPictureAV1 * picture) +{ + if (picture->recon_proxy) { + gst_vaapi_surface_proxy_unref (picture->recon_proxy); + picture->recon_proxy = NULL; + } + gst_vaapi_picture_destroy (GST_VAAPI_PICTURE (picture)); +} + +gboolean +gst_vaapi_picture_av1_create (GstVaapiPictureAV1 * picture, + const GstVaapiCodecObjectConstructorArgs * args) +{ + if (!gst_vaapi_picture_create (GST_VAAPI_PICTURE (picture), args)) + return FALSE; + + picture->recon_proxy = gst_vaapi_surface_proxy_ref (picture->base.proxy); + g_assert (GST_VAAPI_SURFACE_PROXY_SURFACE_ID (picture->recon_proxy) == + picture->base.surface_id); + + return TRUE; +} + +static inline GstVaapiPictureAV1 * +gst_vaapi_picture_av1_new (GstVaapiDecoderAV1 * decoder) +{ + GstVaapiPictureAV1 *picture; + + picture = (GstVaapiPictureAV1 *) + gst_vaapi_codec_object_new (&GstVaapiPictureAV1Class, + GST_VAAPI_CODEC_BASE (decoder), NULL, + sizeof (VADecPictureParameterBufferAV1), NULL, 0, 0); + + if (picture) + picture->cloned = FALSE; + + return picture; +} + +static const gchar * +av1_obu_name (GstAV1OBUType type) +{ + switch (type) { + case GST_AV1_OBU_SEQUENCE_HEADER: + return "sequence header"; + case GST_AV1_OBU_TEMPORAL_DELIMITER: + return "temporal delimiter"; + case GST_AV1_OBU_FRAME_HEADER: + return "frame header"; + case GST_AV1_OBU_TILE_GROUP: + return "tile group"; + case GST_AV1_OBU_METADATA: + return "metadata"; + case GST_AV1_OBU_FRAME: + return "frame"; + case GST_AV1_OBU_REDUNDANT_FRAME_HEADER: + return "redundant frame header"; + case GST_AV1_OBU_TILE_LIST: + return "tile list"; + case GST_AV1_OBU_PADDING: + return "padding"; + default: + return "unknown"; + } + + return NULL; +} + +static GstVaapiChromaType +av1_get_chroma_type (GstVaapiProfile profile, + GstAV1SequenceHeaderOBU * seq_header) +{ + /* 6.4.1: + seq_profile Bit depth Monochrome support Chroma subsampling + 0 8 or 10 Yes YUV 4:2:0 + 1 8 or 10 No YUV 4:4:4 + 2 8 or 10 Yes YUV 4:2:2 + 2 12 Yes YUV 4:2:0,YUV 4:2:2,YUV 4:4:4 + */ + + /* TODO: consider Monochrome case. Just return 4:2:0 for Monochrome now. */ + switch (profile) { + case GST_VAAPI_PROFILE_AV1_0: + if (seq_header->bit_depth == 8) { + return GST_VAAPI_CHROMA_TYPE_YUV420; + } else if (seq_header->bit_depth == 10) { + return GST_VAAPI_CHROMA_TYPE_YUV420_10BPP; + } + break; + case GST_VAAPI_PROFILE_AV1_1: + if (seq_header->bit_depth == 8) { + return GST_VAAPI_CHROMA_TYPE_YUV444; + } else if (seq_header->bit_depth == 10) { + return GST_VAAPI_CHROMA_TYPE_YUV444_10BPP; + } + break; + default: + break; + } + + GST_WARNING ("can not decide chrome type."); + return 0; +} + +static GstVaapiProfile +av1_get_profile (guint profile_idc) +{ + GstVaapiProfile profile; + + switch (profile_idc) { + case GST_AV1_PROFILE_0: + profile = GST_VAAPI_PROFILE_AV1_0; + break; + case GST_AV1_PROFILE_1: + profile = GST_VAAPI_PROFILE_AV1_1; + break; + default: + GST_INFO ("unsupported av1 profile_idc value %d", profile_idc); + profile = GST_VAAPI_PROFILE_UNKNOWN; + break; + } + return profile; +} + +static GstVaapiDecoderStatus +av1_decode_seqeunce (GstVaapiDecoderAV1 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderAV1Private *const priv = &decoder->priv; + GstVaapiProfile profile; + GstVaapiParserInfoAV1 *const pi = unit->parsed_info; + + profile = av1_get_profile (pi->seq_header.seq_profile); + if (profile == GST_VAAPI_PROFILE_UNKNOWN) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + + if (!gst_vaapi_display_has_decoder (GST_VAAPI_DECODER_DISPLAY (decoder), + profile, GST_VAAPI_ENTRYPOINT_VLD)) { + GST_WARNING ("not supported av1 profile %s", + gst_vaapi_profile_get_va_name (profile)); + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + } + + if (profile != priv->profile) { + GST_DEBUG ("new av1 profile %s", gst_vaapi_profile_get_va_name (profile)); + /* We delay the context creation to when we know the frame resolution */ + priv->reset_context = TRUE; + priv->profile = profile; + } + + /* update the sequence */ + if (priv->seq_header) + g_slice_free (GstAV1SequenceHeaderOBU, priv->seq_header); + priv->seq_header = g_slice_dup (GstAV1SequenceHeaderOBU, &pi->seq_header); + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +av1_decoder_ensure_context (GstVaapiDecoderAV1 * decoder) +{ + GstVaapiDecoderAV1Private *const priv = &decoder->priv; + GstVaapiContextInfo info; + + if (priv->reset_context) { + if (priv->current_picture) + gst_vaapi_picture_replace (&priv->current_picture, NULL); + + info.profile = priv->profile; + info.entrypoint = GST_VAAPI_ENTRYPOINT_VLD; + info.width = priv->width; + info.height = priv->height; + info.chroma_type = av1_get_chroma_type (info.profile, priv->seq_header); + if (!info.chroma_type) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT; + + info.ref_frames = GST_AV1_NUM_REF_FRAMES + 2; + + priv->reset_context = FALSE; + if (!gst_vaapi_decoder_ensure_context (GST_VAAPI_DECODER (decoder), &info)) { + GST_WARNING ("can not make av1 decoder context with profile %s," + " width %d, height %d", gst_vaapi_profile_get_va_name (info.profile), + info.width, info.height); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + } + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static void +av1_fill_segment_info (VADecPictureParameterBufferAV1 * pic_param, + GstAV1FrameHeaderOBU * frame_header) +{ + guint i, j; + uint8_t feature_mask; + +#define COPY_SEG_FIELD(FP, FS) \ + pic_param->seg_info.segment_info_fields.bits.FP = \ + (frame_header)->segmentation_params.FS + + COPY_SEG_FIELD (enabled, segmentation_enabled); + COPY_SEG_FIELD (update_map, segmentation_update_map); + COPY_SEG_FIELD (temporal_update, segmentation_temporal_update); + COPY_SEG_FIELD (update_data, segmentation_update_data); + for (i = 0; i < GST_AV1_MAX_SEGMENTS; i++) + for (j = 0; j < GST_AV1_SEG_LVL_MAX; j++) + pic_param->seg_info.feature_data[i][j] = + frame_header->segmentation_params.feature_data[i][j]; + + for (i = 0; i < GST_AV1_MAX_SEGMENTS; i++) { + feature_mask = 0; + for (j = 0; j < GST_AV1_SEG_LVL_MAX; j++) { + if (frame_header->segmentation_params.feature_enabled[i][j]) + feature_mask |= 1 << j; + } + pic_param->seg_info.feature_mask[i] = feature_mask; + } +#undef COPY_SEG_FIELD +} + +static void +av1_fill_film_grain_info (VADecPictureParameterBufferAV1 * pic_param, + GstAV1FrameHeaderOBU * frame_header) +{ + guint i; + + if (!frame_header->film_grain_params.apply_grain) { + memset (&pic_param->film_grain_info, 0, sizeof (VAFilmGrainStructAV1)); + return; + } +#define COPY_FILM_GRAIN_FIELD(FP) \ + pic_param->SUB_FIELD.FP = (frame_header)->film_grain_params.FP +#define SUB_FIELD film_grain_info.film_grain_info_fields.bits + + COPY_FILM_GRAIN_FIELD (apply_grain); + COPY_FILM_GRAIN_FIELD (chroma_scaling_from_luma); + COPY_FILM_GRAIN_FIELD (grain_scaling_minus_8); + COPY_FILM_GRAIN_FIELD (ar_coeff_lag); + COPY_FILM_GRAIN_FIELD (ar_coeff_shift_minus_6); + COPY_FILM_GRAIN_FIELD (grain_scale_shift); + COPY_FILM_GRAIN_FIELD (overlap_flag); + COPY_FILM_GRAIN_FIELD (clip_to_restricted_range); +#undef SUB_FIELD + + pic_param->film_grain_info.grain_seed = + frame_header->film_grain_params.grain_seed; + + pic_param->film_grain_info.num_y_points = + frame_header->film_grain_params.num_y_points; + for (i = 0; i < frame_header->film_grain_params.num_y_points; i++) { + pic_param->film_grain_info.point_y_value[i] = + frame_header->film_grain_params.point_y_value[i]; + pic_param->film_grain_info.point_y_scaling[i] = + frame_header->film_grain_params.point_y_scaling[i]; + } + + pic_param->film_grain_info.num_cb_points = + frame_header->film_grain_params.num_cb_points; + for (i = 0; i < frame_header->film_grain_params.num_cb_points; i++) { + pic_param->film_grain_info.point_cb_value[i] = + frame_header->film_grain_params.point_cb_value[i]; + pic_param->film_grain_info.point_cb_scaling[i] = + frame_header->film_grain_params.point_cb_scaling[i]; + } + + pic_param->film_grain_info.num_cr_points = + frame_header->film_grain_params.num_cr_points; + for (i = 0; i < frame_header->film_grain_params.num_cr_points; i++) { + pic_param->film_grain_info.point_cr_value[i] = + frame_header->film_grain_params.point_cr_value[i]; + pic_param->film_grain_info.point_cr_scaling[i] = + frame_header->film_grain_params.point_cr_scaling[i]; + } + + + if (pic_param->film_grain_info.num_y_points) { + for (i = 0; i < 24; i++) { + pic_param->film_grain_info.ar_coeffs_y[i] = + frame_header->film_grain_params.ar_coeffs_y_plus_128[i] - 128; + } + } + if (frame_header->film_grain_params.chroma_scaling_from_luma + || pic_param->film_grain_info.num_cb_points) { + for (i = 0; i < GST_AV1_MAX_NUM_POS_LUMA; i++) { + pic_param->film_grain_info.ar_coeffs_cb[i] = + frame_header->film_grain_params.ar_coeffs_cb_plus_128[i] - 128; + } + } + if (frame_header->film_grain_params.chroma_scaling_from_luma + || pic_param->film_grain_info.num_cr_points) { + for (i = 0; i < GST_AV1_MAX_NUM_POS_LUMA; i++) { + pic_param->film_grain_info.ar_coeffs_cr[i] = + frame_header->film_grain_params.ar_coeffs_cr_plus_128[i] - 128; + } + } +#define SUB_FIELD film_grain_info + COPY_FILM_GRAIN_FIELD (cb_mult); + COPY_FILM_GRAIN_FIELD (cb_luma_mult); + COPY_FILM_GRAIN_FIELD (cb_offset); + COPY_FILM_GRAIN_FIELD (cr_mult); + COPY_FILM_GRAIN_FIELD (cr_luma_mult); + COPY_FILM_GRAIN_FIELD (cr_offset); +#undef SUB_FIELD +#undef COPY_FILM_GRAIN_FIELD +} + +static void +av1_fill_loop_filter_info (VADecPictureParameterBufferAV1 * pic_param, + GstAV1FrameHeaderOBU * frame_header) +{ + guint i; + + pic_param->superres_scale_denominator = frame_header->superres_denom; + pic_param->interp_filter = frame_header->interpolation_filter; + pic_param->filter_level[0] = + frame_header->loop_filter_params.loop_filter_level[0]; + pic_param->filter_level[1] = + frame_header->loop_filter_params.loop_filter_level[1]; + pic_param->filter_level_u = + frame_header->loop_filter_params.loop_filter_level[2]; + pic_param->filter_level_v = + frame_header->loop_filter_params.loop_filter_level[3]; + pic_param->loop_filter_info_fields.bits.sharpness_level = + frame_header->loop_filter_params.loop_filter_sharpness; + pic_param->loop_filter_info_fields.bits.mode_ref_delta_enabled = + frame_header->loop_filter_params.loop_filter_delta_enabled; + pic_param->loop_filter_info_fields.bits.mode_ref_delta_update = + frame_header->loop_filter_params.loop_filter_delta_update; + + for (i = 0; i < GST_AV1_TOTAL_REFS_PER_FRAME; i++) + pic_param->ref_deltas[i] = + frame_header->loop_filter_params.loop_filter_ref_deltas[i]; + for (i = 0; i < 2; i++) + pic_param->mode_deltas[i] = + frame_header->loop_filter_params.loop_filter_mode_deltas[i]; + + pic_param->mode_control_fields.bits.delta_lf_present_flag = + frame_header->loop_filter_params.delta_lf_present; + pic_param->mode_control_fields.bits.log2_delta_lf_res = + frame_header->loop_filter_params.delta_lf_res; + pic_param->mode_control_fields.bits.delta_lf_multi = + frame_header->loop_filter_params.delta_lf_multi; +} + +static void +av1_fill_quantization_info (VADecPictureParameterBufferAV1 * pic_param, + GstAV1FrameHeaderOBU * frame_header) +{ + pic_param->base_qindex = frame_header->quantization_params.base_q_idx; + pic_param->y_dc_delta_q = frame_header->quantization_params.delta_q_y_dc; + pic_param->u_dc_delta_q = frame_header->quantization_params.delta_q_u_dc; + pic_param->u_ac_delta_q = frame_header->quantization_params.delta_q_u_ac; + pic_param->v_dc_delta_q = frame_header->quantization_params.delta_q_v_dc; + pic_param->v_ac_delta_q = frame_header->quantization_params.delta_q_v_ac; + + pic_param->qmatrix_fields.bits.using_qmatrix = + frame_header->quantization_params.using_qmatrix; + if (pic_param->qmatrix_fields.bits.using_qmatrix) { + pic_param->qmatrix_fields.bits.qm_y = + frame_header->quantization_params.qm_y; + pic_param->qmatrix_fields.bits.qm_u = + frame_header->quantization_params.qm_u; + pic_param->qmatrix_fields.bits.qm_v = + frame_header->quantization_params.qm_v; + } else { + pic_param->qmatrix_fields.bits.qm_y = 0; + pic_param->qmatrix_fields.bits.qm_u = 0; + pic_param->qmatrix_fields.bits.qm_v = 0; + } + + pic_param->mode_control_fields.bits.delta_q_present_flag = + frame_header->quantization_params.delta_q_present; + pic_param->mode_control_fields.bits.log2_delta_q_res = + frame_header->quantization_params.delta_q_res; +} + +static void +av1_fill_cdef_info (VADecPictureParameterBufferAV1 * pic_param, + GstAV1FrameHeaderOBU * frame_header, guint8 num_planes) +{ + guint8 sec_strength; + guint i; + + pic_param->cdef_damping_minus_3 = frame_header->cdef_params.cdef_damping - 3; + pic_param->cdef_bits = frame_header->cdef_params.cdef_bits; + for (i = 0; i < GST_AV1_CDEF_MAX; i++) { + sec_strength = frame_header->cdef_params.cdef_y_sec_strength[i]; + g_assert (sec_strength <= 4); + /* may need to minus 1 in order to merge with primary value. */ + if (sec_strength == 4) + sec_strength--; + + pic_param->cdef_y_strengths[i] = + ((frame_header->cdef_params.cdef_y_pri_strength[i] & 0xf) << 2) | + (sec_strength & 0x03); + } + if (num_planes > 1) { + for (i = 0; i < GST_AV1_CDEF_MAX; i++) { + sec_strength = frame_header->cdef_params.cdef_uv_sec_strength[i]; + g_assert (sec_strength <= 4); + /* may need to minus 1 in order to merge with primary value. */ + if (sec_strength == 4) + sec_strength--; + + pic_param->cdef_uv_strengths[i] = + ((frame_header->cdef_params.cdef_uv_pri_strength[i] & 0xf) << 2) | + (sec_strength & 0x03); + } + } else { + for (i = 0; i < GST_AV1_CDEF_MAX; i++) { + pic_param->cdef_uv_strengths[i] = 0; + } + } +} + +static void +av1_fill_loop_restoration_info (VADecPictureParameterBufferAV1 * pic_param, + GstAV1FrameHeaderOBU * frame_header) +{ + pic_param->loop_restoration_fields.bits.yframe_restoration_type = + frame_header->loop_restoration_params.frame_restoration_type[0]; + pic_param->loop_restoration_fields.bits.cbframe_restoration_type = + frame_header->loop_restoration_params.frame_restoration_type[1]; + pic_param->loop_restoration_fields.bits.crframe_restoration_type = + frame_header->loop_restoration_params.frame_restoration_type[2]; + pic_param->loop_restoration_fields.bits.lr_unit_shift = + frame_header->loop_restoration_params.lr_unit_shift; + pic_param->loop_restoration_fields.bits.lr_uv_shift = + frame_header->loop_restoration_params.lr_uv_shift; +} + +static void +av1_fill_global_motion_info (VADecPictureParameterBufferAV1 * pic_param, + GstAV1FrameHeaderOBU * frame_header) +{ + guint i, j; + + for (i = 0; i < 7; i++) { + pic_param->wm[i].wmtype = + frame_header->global_motion_params.gm_type[GST_AV1_REF_LAST_FRAME + i]; + + for (j = 0; j < 6; j++) + pic_param->wm[i].wmmat[j] = + frame_header->global_motion_params.gm_params + [GST_AV1_REF_LAST_FRAME + i][j]; + + pic_param->wm[i].wmmat[6] = 0; + pic_param->wm[i].wmmat[7] = 0; + + pic_param->wm[i].invalid = + frame_header->global_motion_params.invalid[GST_AV1_REF_LAST_FRAME + i]; + } +} + +static gboolean +av1_fill_picture_frame_header (GstVaapiDecoderAV1 * decoder, + GstVaapiPictureAV1 * picture, GstAV1FrameHeaderOBU * frame_header) +{ + GstVaapiDecoderAV1Private *priv = &decoder->priv; + VADecPictureParameterBufferAV1 *pic_param = + GST_VAAPI_PICTURE (picture)->param; + GstAV1SequenceHeaderOBU *seq_header = priv->seq_header; + guint i; + + pic_param->profile = seq_header->seq_profile; + pic_param->order_hint_bits_minus_1 = seq_header->order_hint_bits_minus_1; + + if (seq_header->bit_depth == 8) + pic_param->bit_depth_idx = 0; + else if (seq_header->bit_depth == 10) + pic_param->bit_depth_idx = 1; + else if (seq_header->bit_depth == 12) + pic_param->bit_depth_idx = 2; + else + g_assert (0); + + pic_param->matrix_coefficients = seq_header->color_config.matrix_coefficients; + +#define COPY_SEQ_FIELD(FP, FS) \ + pic_param->seq_info_fields.fields.FP = (seq_header)->FS + + COPY_SEQ_FIELD (still_picture, still_picture); + COPY_SEQ_FIELD (use_128x128_superblock, use_128x128_superblock); + COPY_SEQ_FIELD (enable_filter_intra, enable_filter_intra); + COPY_SEQ_FIELD (enable_intra_edge_filter, enable_intra_edge_filter); + COPY_SEQ_FIELD (enable_interintra_compound, enable_interintra_compound); + COPY_SEQ_FIELD (enable_masked_compound, enable_masked_compound); + COPY_SEQ_FIELD (enable_dual_filter, enable_dual_filter); + COPY_SEQ_FIELD (enable_order_hint, enable_order_hint); + COPY_SEQ_FIELD (enable_jnt_comp, enable_jnt_comp); + COPY_SEQ_FIELD (enable_cdef, enable_cdef); + COPY_SEQ_FIELD (mono_chrome, color_config.mono_chrome); + COPY_SEQ_FIELD (color_range, color_config.color_range); + COPY_SEQ_FIELD (subsampling_x, color_config.subsampling_x); + COPY_SEQ_FIELD (subsampling_y, color_config.subsampling_y); + COPY_SEQ_FIELD (film_grain_params_present, film_grain_params_present); +#undef COPY_SEQ_FIELD + + if (frame_header->film_grain_params.apply_grain) { + g_assert (GST_VAAPI_SURFACE_PROXY_SURFACE_ID (picture->recon_proxy) != + GST_VAAPI_PICTURE (picture)->surface_id); + pic_param->current_frame = + GST_VAAPI_SURFACE_PROXY_SURFACE_ID (picture->recon_proxy); + pic_param->current_display_picture = + GST_VAAPI_PICTURE (picture)->surface_id; + } else { + pic_param->current_frame = GST_VAAPI_PICTURE (picture)->surface_id; + pic_param->current_display_picture = + GST_VAAPI_PICTURE (picture)->surface_id; + } + + pic_param->frame_width_minus1 = frame_header->upscaled_width - 1; + pic_param->frame_height_minus1 = frame_header->frame_height - 1; + + for (i = 0; i < GST_AV1_NUM_REF_FRAMES; i++) { + if (priv->ref_frames[i]) + pic_param->ref_frame_map[i] = + GST_VAAPI_SURFACE_PROXY_SURFACE_ID (priv->ref_frames[i]->recon_proxy); + else + pic_param->ref_frame_map[i] = VA_INVALID_SURFACE; + } + for (i = 0; i < GST_AV1_REFS_PER_FRAME; i++) { + pic_param->ref_frame_idx[i] = frame_header->ref_frame_idx[i]; + } + pic_param->primary_ref_frame = frame_header->primary_ref_frame; + pic_param->order_hint = frame_header->order_hint; + + av1_fill_segment_info (pic_param, frame_header); + av1_fill_film_grain_info (pic_param, frame_header); + + pic_param->tile_cols = frame_header->tile_info.tile_cols; + pic_param->tile_rows = frame_header->tile_info.tile_rows; + for (i = 0; i < 63; i++) { + pic_param->width_in_sbs_minus_1[i] = + frame_header->tile_info.width_in_sbs_minus_1[i]; + pic_param->height_in_sbs_minus_1[i] = + frame_header->tile_info.height_in_sbs_minus_1[i]; + } + + pic_param->context_update_tile_id = + frame_header->tile_info.context_update_tile_id; + +#define COPY_PIC_FIELD(FIELD) \ + pic_param->pic_info_fields.bits.FIELD = (frame_header)->FIELD + + COPY_PIC_FIELD (frame_type); + COPY_PIC_FIELD (show_frame); + COPY_PIC_FIELD (showable_frame); + COPY_PIC_FIELD (error_resilient_mode); + COPY_PIC_FIELD (disable_cdf_update); + COPY_PIC_FIELD (allow_screen_content_tools); + COPY_PIC_FIELD (force_integer_mv); + COPY_PIC_FIELD (allow_intrabc); + COPY_PIC_FIELD (use_superres); + COPY_PIC_FIELD (allow_high_precision_mv); + COPY_PIC_FIELD (is_motion_mode_switchable); + COPY_PIC_FIELD (use_ref_frame_mvs); + COPY_PIC_FIELD (disable_frame_end_update_cdf); + pic_param->pic_info_fields.bits.uniform_tile_spacing_flag = + frame_header->tile_info.uniform_tile_spacing_flag; + COPY_PIC_FIELD (allow_warped_motion); +#undef COPY_PIC_FIELD + + av1_fill_loop_filter_info (pic_param, frame_header); + av1_fill_quantization_info (pic_param, frame_header); + + pic_param->mode_control_fields.bits.tx_mode = frame_header->tx_mode; + pic_param->mode_control_fields.bits.reference_select = + frame_header->reference_select; + pic_param->mode_control_fields.bits.reduced_tx_set_used = + frame_header->reduced_tx_set; + pic_param->mode_control_fields.bits.skip_mode_present = + frame_header->skip_mode_present; + + av1_fill_cdef_info (pic_param, frame_header, seq_header->num_planes); + av1_fill_loop_restoration_info (pic_param, frame_header); + av1_fill_global_motion_info (pic_param, frame_header); + + return TRUE; +} + +static GstVaapiDecoderStatus +av1_decode_frame_header (GstVaapiDecoderAV1 * decoder, + GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderAV1Private *const priv = &decoder->priv; + GstVaapiParserInfoAV1 *const pi = unit->parsed_info; + GstAV1FrameHeaderOBU *frame_header = NULL; + GstVaapiDecoderStatus ret = GST_VAAPI_DECODER_STATUS_SUCCESS; + GstVaapiPictureAV1 *picture = NULL; + + if (pi->obu.obu_type == GST_AV1_OBU_FRAME_HEADER) { + frame_header = &pi->frame_header; + } else { + g_assert (pi->obu.obu_type == GST_AV1_OBU_FRAME); + frame_header = &pi->frame.frame_header; + } + + if (frame_header->show_existing_frame) { + GstVaapiPictureAV1 *to_show_picture = NULL; + + to_show_picture = priv->ref_frames[frame_header->frame_to_show_map_idx]; + if (to_show_picture == NULL) { + GST_ERROR ("frame_to_show_map_idx point to a invalid picture"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + if (gst_av1_parser_reference_frame_loading (priv->parser, + &to_show_picture->frame_header) != GST_AV1_PARSER_OK) { + GST_ERROR ("load frame to show ref frame failed"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + picture = (GstVaapiPictureAV1 *) + gst_vaapi_picture_new_clone (GST_VAAPI_PICTURE_CAST (to_show_picture)); + if (!picture) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE; + gst_vaapi_surface_proxy_replace (&picture->recon_proxy, + to_show_picture->recon_proxy); + picture->cloned = TRUE; + GST_VAAPI_PICTURE_FLAG_UNSET (picture, GST_VAAPI_PICTURE_FLAG_SKIPPED); + + picture->frame_header = to_show_picture->frame_header; + /* only update references if the frame_to_show_map_idx is a KEY FRAME */ + if (picture->frame_header.frame_type == GST_AV1_KEY_FRAME) { + picture->frame_header = to_show_picture->frame_header; + g_assert (picture->frame_header.refresh_frame_flags == + ((1 << GST_AV1_NUM_REF_FRAMES) - 1)); + } else { + /* Just set to no update ref */ + picture->frame_header.refresh_frame_flags = 0; + } + } else { + /* Resolution changed */ + if (priv->width != priv->seq_header->max_frame_width_minus_1 + 1 || + priv->height != priv->seq_header->max_frame_height_minus_1 + 1) { + priv->reset_context = TRUE; + priv->width = priv->seq_header->max_frame_width_minus_1 + 1; + priv->height = priv->seq_header->max_frame_height_minus_1 + 1; + GST_INFO ("change the resolution to %dx%d", priv->width, priv->height); + } + + ret = av1_decoder_ensure_context (decoder); + if (ret != GST_VAAPI_DECODER_STATUS_SUCCESS) + return ret; + + picture = gst_vaapi_picture_av1_new (decoder); + if (!picture) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE; + + if (frame_header->upscaled_width != priv->width || + frame_header->frame_height != priv->height) { + GstVaapiRectangle crop_rect; + + if (frame_header->upscaled_width > priv->width) { + GST_WARNING ("Frame width is %d, bigger than sequence max width %d", + frame_header->upscaled_width, priv->width); + gst_vaapi_codec_object_unref (picture); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + if (frame_header->frame_height > priv->height) { + GST_WARNING ("Frame height is %d, bigger than sequence max height %d", + frame_header->frame_height, priv->height); + gst_vaapi_codec_object_unref (picture); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + crop_rect.x = 0; + crop_rect.y = 0; + crop_rect.width = frame_header->upscaled_width; + crop_rect.height = frame_header->frame_height; + gst_vaapi_picture_set_crop_rect (GST_VAAPI_PICTURE (picture), &crop_rect); + } + + if (frame_header->film_grain_params.apply_grain) { + GstVaapiSurfaceProxy *recon_proxy = gst_vaapi_context_get_surface_proxy + (GST_VAAPI_DECODER (decoder)->context); + if (!recon_proxy) { + gst_vaapi_codec_object_unref (picture); + return GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE; + } + gst_vaapi_surface_proxy_replace (&picture->recon_proxy, recon_proxy); + } + + picture->frame_header = *frame_header; + + /* this frame will not show this time */ + if (!frame_header->show_frame) + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_SKIPPED); + + GST_VAAPI_PICTURE (picture)->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME; + GST_VAAPI_PICTURE (picture)->type = + frame_header->frame_is_intra ? GST_VAAPI_PICTURE_TYPE_I : + GST_VAAPI_PICTURE_TYPE_P; + + if (!av1_fill_picture_frame_header (decoder, picture, frame_header)) { + gst_vaapi_codec_object_unref (picture); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + } + + gst_vaapi_picture_replace (&priv->current_picture, picture); + gst_vaapi_picture_unref (picture); + + return ret; +} + +static GstVaapiDecoderStatus +av1_decode_tile_data (GstVaapiDecoderAV1 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderAV1Private *const priv = &decoder->priv; + GstVaapiPictureAV1 *picture = priv->current_picture; + GstVaapiParserInfoAV1 *const pi = unit->parsed_info; + GstAV1TileGroupOBU *tile_group = &pi->tile_group; + guint32 i; + GstVaapiSlice *slice; + GstBuffer *const buffer = + GST_VAAPI_DECODER_CODEC_FRAME (decoder)->input_buffer; + GstMapInfo map_info; + + if (!picture) { + GST_WARNING ("Decode the tile date without a picture"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) { + GST_ERROR ("failed to map buffer"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + slice = GST_VAAPI_SLICE_NEW_N_PARAMS (AV1, decoder, + map_info.data + pi->data_offset + unit->offset, pi->obu.obu_size, + (tile_group->tg_end - tile_group->tg_start + 1)); + gst_buffer_unmap (buffer, &map_info); + if (!slice) { + GST_ERROR ("failed to allocate slice"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + for (i = 0; i < tile_group->tg_end - tile_group->tg_start + 1; i++) { + VASliceParameterBufferAV1 *const slice_param = + slice->param + i * sizeof (VASliceParameterBufferAV1); + + slice_param->slice_data_size = + tile_group->entry[tile_group->tg_start + i].tile_size; + slice_param->slice_data_offset = + tile_group->entry[tile_group->tg_start + i].tile_offset; + slice_param->tile_row = + tile_group->entry[tile_group->tg_start + i].tile_row; + slice_param->tile_column = + tile_group->entry[tile_group->tg_start + i].tile_col; + slice_param->slice_data_flag = 0; + } + + gst_vaapi_picture_add_slice (GST_VAAPI_PICTURE_CAST (picture), slice); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +av1_decode_unit (GstVaapiDecoderAV1 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderStatus ret = GST_VAAPI_DECODER_STATUS_SUCCESS; + GstVaapiParserInfoAV1 *const pi = unit->parsed_info; + + GST_DEBUG ("begin to decode the unit of %s", av1_obu_name (pi->obu.obu_type)); + + switch (pi->obu.obu_type) { + case GST_AV1_OBU_SEQUENCE_HEADER: + ret = av1_decode_seqeunce (decoder, unit); + break; + case GST_AV1_OBU_FRAME_HEADER: + ret = av1_decode_frame_header (decoder, unit); + break; + case GST_AV1_OBU_FRAME: + ret = av1_decode_frame_header (decoder, unit); + if (ret != GST_VAAPI_DECODER_STATUS_SUCCESS) + break; + /* fall through */ + case GST_AV1_OBU_TILE_GROUP: + ret = av1_decode_tile_data (decoder, unit); + break; + case GST_AV1_OBU_METADATA: + case GST_AV1_OBU_REDUNDANT_FRAME_HEADER: + case GST_AV1_OBU_PADDING: + /* Not handled */ + ret = GST_VAAPI_DECODER_STATUS_SUCCESS; + break; + default: + GST_WARNING ("can not handle obu type %s", + av1_obu_name (pi->obu.obu_type)); + ret = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + return ret; +} + +static GstVaapiDecoderStatus +av1_decode_current_picture (GstVaapiDecoderAV1 * decoder) +{ + GstVaapiDecoderAV1Private *priv = &decoder->priv; + GstVaapiPictureAV1 *const picture = + (GstVaapiPictureAV1 *) priv->current_picture; + + g_assert (picture); + + if (!gst_vaapi_picture_decode_with_surface_id (GST_VAAPI_PICTURE (picture), + GST_VAAPI_SURFACE_PROXY_SURFACE_ID (picture->recon_proxy))) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +av1_decoder_update_state (GstVaapiDecoderAV1 * decoder, + GstVaapiPictureAV1 * picture) +{ + GstVaapiDecoderAV1Private *priv = &decoder->priv; + GstAV1ParserResult ret; + guint i; + + /* This is a show_existing_frame case, only update key frame */ + if (picture->cloned && picture->frame_header.frame_type != GST_AV1_KEY_FRAME) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + ret = gst_av1_parser_reference_frame_update (priv->parser, + &picture->frame_header); + if (ret != GST_AV1_PARSER_OK) { + GST_ERROR ("failed to update the reference."); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + for (i = 0; i < GST_AV1_NUM_REF_FRAMES; i++) { + if ((picture->frame_header.refresh_frame_flags >> i) & 1) { + GST_LOG ("reference frame %p to ref slot:%d", picture, i); + gst_vaapi_picture_replace (&priv->ref_frames[i], picture); + } + } + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static void +av1_decoder_reset (GstVaapiDecoderAV1 * decoder) +{ + GstVaapiDecoderAV1Private *priv = &decoder->priv; + guint i; + + priv->profile = GST_VAAPI_PROFILE_UNKNOWN; + priv->width = 0; + priv->height = 0; + priv->annex_b = FALSE; + priv->reset_context = FALSE; + + if (priv->current_picture) + gst_vaapi_picture_replace (&priv->current_picture, NULL); + + if (priv->seq_header) { + g_slice_free (GstAV1SequenceHeaderOBU, priv->seq_header); + priv->seq_header = NULL; + } + + for (i = 0; i < GST_AV1_NUM_REF_FRAMES; i++) + gst_vaapi_picture_replace (&priv->ref_frames[i], NULL); +} + +static gboolean +av1_is_picture_end (GstVaapiParserInfoAV1 * pi) +{ + GstAV1TileGroupOBU *tile_group = NULL; + + if (pi->obu.obu_type == GST_AV1_OBU_FRAME) { + tile_group = &pi->frame.tile_group; + } else if (pi->obu.obu_type == GST_AV1_OBU_TILE_GROUP) { + tile_group = &pi->tile_group; + } + g_assert (tile_group); + + if (tile_group->tg_end == tile_group->num_tiles - 1) + return TRUE; + + return FALSE; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_av1_reset (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderAV1 *const decoder = GST_VAAPI_DECODER_AV1 (base_decoder); + GstVaapiDecoderAV1Private *priv = &decoder->priv; + + av1_decoder_reset (decoder); + gst_av1_parser_reset (priv->parser, FALSE); + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_av1_parse (GstVaapiDecoder * base_decoder, + GstAdapter * adapter, gboolean at_eos, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderAV1 *const decoder = GST_VAAPI_DECODER_AV1 (base_decoder); + GstVaapiDecoderAV1Private *const priv = &decoder->priv; + GstVaapiParserInfoAV1 *pi; + GstAV1Parser *parser = priv->parser; + guchar *buf; + guint buf_size, flags; + GstAV1OBU obu; + GstAV1ParserResult av1_ret; + GstVaapiDecoderStatus ret = GST_VAAPI_DECODER_STATUS_SUCCESS; + guint32 consumed; + + buf_size = gst_adapter_available (adapter); + if (!buf_size) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + + /* no need to do unmap here */ + buf = (guchar *) gst_adapter_map (adapter, buf_size); + if (!buf) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + + av1_ret = + gst_av1_parser_identify_one_obu (parser, buf, buf_size, &obu, &consumed); + if (av1_ret == GST_AV1_PARSER_DROP) { + GST_LOG ("just discard a %s obu with size %d, consumed %d", + av1_obu_name (obu.obu_type), obu.obu_size, consumed); + gst_adapter_flush (adapter, consumed); + return GST_VAAPI_DECODER_STATUS_SUCCESS; + } else if (av1_ret == GST_AV1_PARSER_NO_MORE_DATA) { + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + } else if (av1_ret == GST_AV1_PARSER_BITSTREAM_ERROR) { + GST_WARNING_OBJECT (decoder, "parse error, an invalid bitstream"); + gst_adapter_flush (adapter, consumed); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } else if (av1_ret != GST_AV1_PARSER_OK) { + GST_WARNING_OBJECT (decoder, "parse error, unknown error"); + gst_adapter_flush (adapter, consumed); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + GST_DEBUG ("get one %s obu with size %d, consumed %d", + av1_obu_name (obu.obu_type), obu.obu_size, consumed); + + pi = parser_info_av1_new (&obu); + if (!pi) { + gst_adapter_flush (adapter, consumed); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + gst_vaapi_decoder_unit_set_parsed_info (unit, pi, + (GDestroyNotify) gst_vaapi_mini_object_unref); + + flags = 0; + av1_ret = GST_AV1_PARSER_OK; + switch (pi->obu.obu_type) { + case GST_AV1_OBU_TEMPORAL_DELIMITER: + av1_ret = gst_av1_parser_parse_temporal_delimiter_obu (parser, &pi->obu); + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP; + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START; + break; + case GST_AV1_OBU_SEQUENCE_HEADER: + av1_ret = gst_av1_parser_parse_sequence_header_obu (parser, &pi->obu, + &pi->seq_header); + break; + case GST_AV1_OBU_REDUNDANT_FRAME_HEADER: + av1_ret = gst_av1_parser_parse_frame_header_obu (parser, &pi->obu, + &pi->frame_header); + break; + case GST_AV1_OBU_FRAME_HEADER: + av1_ret = gst_av1_parser_parse_frame_header_obu (parser, &pi->obu, + &pi->frame_header); + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START; + if (pi->frame_header.show_existing_frame) { + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END; + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE; + } + break; + case GST_AV1_OBU_FRAME: + av1_ret = gst_av1_parser_parse_frame_obu (parser, &obu, &pi->frame); + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START; + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE; + pi->data_offset = obu.data - buf; + if (av1_is_picture_end (pi)) + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END; + break; + case GST_AV1_OBU_METADATA: + av1_ret = gst_av1_parser_parse_metadata_obu (parser, &obu, &pi->metadata); + break; + case GST_AV1_OBU_TILE_GROUP: + av1_ret = gst_av1_parser_parse_tile_group_obu (parser, &obu, + &pi->tile_group); + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE; + pi->data_offset = obu.data - buf; + if (av1_is_picture_end (pi)) + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END; + break; + case GST_AV1_OBU_TILE_LIST: + av1_ret = + gst_av1_parser_parse_tile_list_obu (parser, &obu, &pi->tile_list); + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE; + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END; + break; + case GST_AV1_OBU_PADDING: + break; + default: + GST_WARNING_OBJECT (decoder, "an unrecognized obu type %d", obu.obu_type); + av1_ret = GST_AV1_PARSER_BITSTREAM_ERROR; + break; + } + + if (av1_ret != GST_AV1_PARSER_OK) { + /* Should not get NO_MORE_DATA, the obu size is already known */ + GST_WARNING_OBJECT (decoder, "parse %s obu error", + av1_obu_name (pi->obu.obu_type)); + gst_adapter_flush (adapter, consumed); + gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (pi)); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + unit->size = consumed; + unit->offset = pi->obu.data - buf; + GST_VAAPI_DECODER_UNIT_FLAG_SET (unit, flags); + + return ret; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_av1_decode (GstVaapiDecoder * base_decoder, + GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderAV1 *const decoder = GST_VAAPI_DECODER_AV1 (base_decoder); + GstVaapiDecoderStatus status; + + status = av1_decode_unit (decoder, unit); + + return status; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_av1_start_frame (GstVaapiDecoder * base_decoder, + GstVaapiDecoderUnit * base_unit) +{ + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_av1_end_frame (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderAV1 *const decoder = GST_VAAPI_DECODER_AV1 (base_decoder); + GstVaapiDecoderStatus status = GST_VAAPI_DECODER_STATUS_SUCCESS; + GstVaapiDecoderAV1Private *priv = &decoder->priv; + + if (!priv->current_picture->cloned) + status = av1_decode_current_picture (decoder); + + /* update state anyway */ + av1_decoder_update_state (decoder, priv->current_picture); + + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + goto out; + + if (!gst_vaapi_picture_output (GST_VAAPI_PICTURE (priv->current_picture))) + status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + +out: + gst_vaapi_picture_replace (&priv->current_picture, NULL); + return status; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_av1_flush (GstVaapiDecoder * base_decoder) +{ + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static void +gst_vaapi_decoder_av1_finalize (GObject * object) +{ + GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (object); + GstVaapiDecoderAV1 *const decoder = GST_VAAPI_DECODER_AV1 (base_decoder); + GstVaapiDecoderAV1Private *priv = &decoder->priv; + + av1_decoder_reset (decoder); + if (decoder->priv.parser) + gst_av1_parser_free (decoder->priv.parser); + priv->parser = NULL; + + G_OBJECT_CLASS (gst_vaapi_decoder_av1_parent_class)->finalize (object); +} + +static void +gst_vaapi_decoder_av1_class_init (GstVaapiDecoderAV1Class * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstVaapiDecoderClass *const decoder_class = GST_VAAPI_DECODER_CLASS (klass); + + object_class->finalize = gst_vaapi_decoder_av1_finalize; + + decoder_class->reset = gst_vaapi_decoder_av1_reset; + decoder_class->parse = gst_vaapi_decoder_av1_parse; + decoder_class->decode = gst_vaapi_decoder_av1_decode; + decoder_class->start_frame = gst_vaapi_decoder_av1_start_frame; + decoder_class->end_frame = gst_vaapi_decoder_av1_end_frame; + decoder_class->flush = gst_vaapi_decoder_av1_flush; +} + +static void +gst_vaapi_decoder_av1_init (GstVaapiDecoderAV1 * decoder) +{ + guint i; + GstVaapiDecoderAV1Private *priv = &decoder->priv; + + priv->profile = GST_VAAPI_PROFILE_UNKNOWN; + priv->width = 0; + priv->height = 0; + priv->annex_b = FALSE; + priv->reset_context = FALSE; + priv->current_picture = NULL; + priv->seq_header = NULL; + + for (i = 0; i < GST_AV1_NUM_REF_FRAMES; i++) + priv->ref_frames[i] = NULL; + + priv->parser = gst_av1_parser_new (); +} + +/** + * gst_vaapi_decoder_av1_new: + * @display: a #GstVaapiDisplay + * @caps: a #GstCaps holding codec information + * + * Creates a new #GstVaapiDecoder for AV1 decoding. The @caps can + * hold extra information like codec-data and pictured coded size. + * + * Return value: the newly allocated #GstVaapiDecoder object + */ +GstVaapiDecoder * +gst_vaapi_decoder_av1_new (GstVaapiDisplay * display, GstCaps * caps) +{ + return g_object_new (GST_TYPE_VAAPI_DECODER_AV1, "display", display, + "caps", caps, NULL); +} diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_av1.h b/gst-libs/gst/vaapi/gstvaapidecoder_av1.h new file mode 100644 index 0000000000..8604093edf --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_av1.h @@ -0,0 +1,47 @@ +/* + * gstvaapidecoder_av1.h - AV1 decoder + * + * Copyright (C) 2019-2020 Intel Corporation + * Author: Junyan He + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODER_AV1_H +#define GST_VAAPI_DECODER_AV1_H + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_DECODER_AV1 \ + (gst_vaapi_decoder_av1_get_type ()) +#define GST_VAAPI_DECODER_AV1(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DECODER_AV1, GstVaapiDecoderAV1)) +#define GST_VAAPI_IS_DECODER_AV1(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_DECODER_AV1)) + +typedef struct _GstVaapiDecoderAV1 GstVaapiDecoderAV1; + +GType +gst_vaapi_decoder_av1_get_type (void) G_GNUC_CONST; + +GstVaapiDecoder * +gst_vaapi_decoder_av1_new (GstVaapiDisplay * display, GstCaps * caps); + +G_END_DECLS + +#endif /* GST_VAAPI_DECODER_AV1_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_dpb.c b/gst-libs/gst/vaapi/gstvaapidecoder_dpb.c new file mode 100644 index 0000000000..7825c9dc61 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_dpb.c @@ -0,0 +1,421 @@ +/* + * gstvaapidecoder_dpb.c - Decoded Picture Buffer + * + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include "gstvaapidecoder_dpb.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +#define GST_VAAPI_DPB_CLASS(klass) \ + ((GstVaapiDpbClass *)(klass)) + +#define GST_VAAPI_DPB_GET_CLASS(obj) \ + GST_VAAPI_DPB_CLASS(GST_VAAPI_MINI_OBJECT_GET_CLASS(obj)) + +/** + * GstVaapiDpb: + * + * A decoded picture buffer (DPB) object. + */ +struct _GstVaapiDpb +{ + /*< private > */ + GstVaapiMiniObject parent_instance; + + /*< protected > */ + GstVaapiPicture **pictures; + guint num_pictures; + guint max_pictures; +}; + +/** + * GstVaapiDpbClass: + * + * The #GstVaapiDpb base class. + */ +struct _GstVaapiDpbClass +{ + /*< private > */ + GstVaapiMiniObjectClass parent_class; + + /*< protected > */ + void (*flush) (GstVaapiDpb * dpb); + gboolean (*add) (GstVaapiDpb * dpb, GstVaapiPicture * picture); + void (*get_neighbours) (GstVaapiDpb * dpb, GstVaapiPicture * picture, + GstVaapiPicture ** prev_picture_ptr, GstVaapiPicture ** next_picture_ptr); +}; + +static const GstVaapiMiniObjectClass *gst_vaapi_dpb_class (void); + +static const GstVaapiMiniObjectClass *gst_vaapi_dpb2_class (void); + +/* ------------------------------------------------------------------------- */ +/* --- Common utilities --- */ +/* ------------------------------------------------------------------------- */ + +static inline GstVaapiDpb * +dpb_new (guint max_pictures) +{ + GstVaapiDpb *dpb; + + g_return_val_if_fail (max_pictures > 0, NULL); + + dpb = + (GstVaapiDpb *) gst_vaapi_mini_object_new (max_pictures == + 2 ? gst_vaapi_dpb2_class () : gst_vaapi_dpb_class ()); + if (!dpb) + return NULL; + + dpb->num_pictures = 0; + dpb->max_pictures = max_pictures; + + dpb->pictures = g_new0 (GstVaapiPicture *, max_pictures); + if (!dpb->pictures) + goto error; + return dpb; + + /* ERRORS */ +error: + { + gst_vaapi_dpb_unref (dpb); + return NULL; + } +} + +static gint +dpb_get_oldest (GstVaapiDpb * dpb, gboolean output) +{ + gint i, lowest_pts_index; + + for (i = 0; i < dpb->num_pictures; i++) { + if ((GST_VAAPI_PICTURE_IS_OUTPUT (dpb->pictures[i]) ^ output) == 0) + break; + } + if (i == dpb->num_pictures) + return -1; + + lowest_pts_index = i++; + for (; i < dpb->num_pictures; i++) { + GstVaapiPicture *const picture = dpb->pictures[i]; + if ((GST_VAAPI_PICTURE_IS_OUTPUT (picture) ^ output) != 0) + continue; + if (picture->poc < dpb->pictures[lowest_pts_index]->poc) + lowest_pts_index = i; + } + return lowest_pts_index; +} + +static void +dpb_remove_index (GstVaapiDpb * dpb, guint index) +{ + GstVaapiPicture **const pictures = dpb->pictures; + guint num_pictures = --dpb->num_pictures; + + if (index != num_pictures) + gst_vaapi_picture_replace (&pictures[index], pictures[num_pictures]); + gst_vaapi_picture_replace (&pictures[num_pictures], NULL); +} + +static inline gboolean +dpb_output (GstVaapiDpb * dpb, GstVaapiPicture * picture) +{ + return gst_vaapi_picture_output (picture); +} + +static gboolean +dpb_bump (GstVaapiDpb * dpb) +{ + gint index; + gboolean success; + + index = dpb_get_oldest (dpb, FALSE); + if (index < 0) + return FALSE; + + success = dpb_output (dpb, dpb->pictures[index]); + if (!GST_VAAPI_PICTURE_IS_REFERENCE (dpb->pictures[index])) + dpb_remove_index (dpb, index); + return success; +} + +static void +dpb_clear (GstVaapiDpb * dpb) +{ + guint i; + + for (i = 0; i < dpb->num_pictures; i++) + gst_vaapi_picture_replace (&dpb->pictures[i], NULL); + dpb->num_pictures = 0; +} + +static void +dpb_flush (GstVaapiDpb * dpb) +{ + while (dpb_bump (dpb)); + dpb_clear (dpb); +} + +/* ------------------------------------------------------------------------- */ +/* --- Generic implementation --- */ +/* ------------------------------------------------------------------------- */ + +static gboolean +dpb_add (GstVaapiDpb * dpb, GstVaapiPicture * picture) +{ + guint i; + + // Remove all unused pictures + i = 0; + while (i < dpb->num_pictures) { + GstVaapiPicture *const picture = dpb->pictures[i]; + if (GST_VAAPI_PICTURE_IS_OUTPUT (picture) && + !GST_VAAPI_PICTURE_IS_REFERENCE (picture)) + dpb_remove_index (dpb, i); + else + i++; + } + + // Store reference decoded picture into the DPB + if (GST_VAAPI_PICTURE_IS_REFERENCE (picture)) { + while (dpb->num_pictures == dpb->max_pictures) { + if (!dpb_bump (dpb)) + return FALSE; + } + } + // Store non-reference decoded picture into the DPB + else { + if (GST_VAAPI_PICTURE_IS_SKIPPED (picture)) + return TRUE; + while (dpb->num_pictures == dpb->max_pictures) { + for (i = 0; i < dpb->num_pictures; i++) { + if (!GST_VAAPI_PICTURE_IS_OUTPUT (picture) && + dpb->pictures[i]->poc < picture->poc) + break; + } + if (i == dpb->num_pictures) + return dpb_output (dpb, picture); + if (!dpb_bump (dpb)) + return FALSE; + } + } + gst_vaapi_picture_replace (&dpb->pictures[dpb->num_pictures++], picture); + return TRUE; +} + +static void +dpb_get_neighbours (GstVaapiDpb * dpb, GstVaapiPicture * picture, + GstVaapiPicture ** prev_picture_ptr, GstVaapiPicture ** next_picture_ptr) +{ + GstVaapiPicture *prev_picture = NULL; + GstVaapiPicture *next_picture = NULL; + guint i; + + /* Find the first picture with POC > specified picture POC */ + for (i = 0; i < dpb->num_pictures; i++) { + GstVaapiPicture *const ref_picture = dpb->pictures[i]; + if (ref_picture->poc == picture->poc) { + if (i > 0) + prev_picture = dpb->pictures[i - 1]; + if (i + 1 < dpb->num_pictures) + next_picture = dpb->pictures[i + 1]; + break; + } else if (ref_picture->poc > picture->poc) { + next_picture = ref_picture; + if (i > 0) + prev_picture = dpb->pictures[i - 1]; + break; + } + } + + g_assert (next_picture ? next_picture->poc > picture->poc : TRUE); + g_assert (prev_picture ? prev_picture->poc < picture->poc : TRUE); + + if (prev_picture_ptr) + *prev_picture_ptr = prev_picture; + if (next_picture_ptr) + *next_picture_ptr = next_picture; +} + +/* ------------------------------------------------------------------------- */ +/* --- Optimized implementation for 2 reference pictures --- */ +/* ------------------------------------------------------------------------- */ + +static gboolean +dpb2_add (GstVaapiDpb * dpb, GstVaapiPicture * picture) +{ + GstVaapiPicture *ref_picture; + gint index = -1; + + g_return_val_if_fail (GST_VAAPI_IS_DPB (dpb), FALSE); + g_return_val_if_fail (dpb->max_pictures == 2, FALSE); + + /* + * Purpose: only store reference decoded pictures into the DPB + * + * This means: + * - non-reference decoded pictures are output immediately + * - ... thus causing older reference pictures to be output, if not already + * - the oldest reference picture is replaced with the new reference picture + */ + if (G_LIKELY (dpb->num_pictures == 2)) { + index = (dpb->pictures[0]->poc > dpb->pictures[1]->poc); + ref_picture = dpb->pictures[index]; + if (!GST_VAAPI_PICTURE_IS_OUTPUT (ref_picture)) { + if (!dpb_output (dpb, ref_picture)) + return FALSE; + } + } + + if (!GST_VAAPI_PICTURE_IS_REFERENCE (picture)) + return dpb_output (dpb, picture); + + if (index < 0) + index = dpb->num_pictures++; + gst_vaapi_picture_replace (&dpb->pictures[index], picture); + return TRUE; +} + +static void +dpb2_get_neighbours (GstVaapiDpb * dpb, GstVaapiPicture * picture, + GstVaapiPicture ** prev_picture_ptr, GstVaapiPicture ** next_picture_ptr) +{ + GstVaapiPicture *ref_picture, *ref_pictures[2]; + GstVaapiPicture **picture_ptr; + guint i, index; + + g_return_if_fail (GST_VAAPI_IS_DPB (dpb)); + g_return_if_fail (dpb->max_pictures == 2); + g_return_if_fail (GST_VAAPI_IS_PICTURE (picture)); + + ref_pictures[0] = NULL; + ref_pictures[1] = NULL; + for (i = 0; i < dpb->num_pictures; i++) { + ref_picture = dpb->pictures[i]; + index = ref_picture->poc > picture->poc; + picture_ptr = &ref_pictures[index]; + if (!*picture_ptr || ((*picture_ptr)->poc > ref_picture->poc) == index) + *picture_ptr = ref_picture; + } + + if (prev_picture_ptr) + *prev_picture_ptr = ref_pictures[0]; + if (next_picture_ptr) + *next_picture_ptr = ref_pictures[1]; +} + +/* ------------------------------------------------------------------------- */ +/* --- Interface --- */ +/* ------------------------------------------------------------------------- */ + +static void +gst_vaapi_dpb_finalize (GstVaapiDpb * dpb) +{ + dpb_clear (dpb); + g_free (dpb->pictures); +} + +static const GstVaapiMiniObjectClass * +gst_vaapi_dpb_class (void) +{ + static const GstVaapiDpbClass GstVaapiDpbClass = { + {sizeof (GstVaapiDpb), + (GDestroyNotify) gst_vaapi_dpb_finalize} + , + + dpb_flush, + dpb_add, + dpb_get_neighbours + }; + return &GstVaapiDpbClass.parent_class; +} + +static const GstVaapiMiniObjectClass * +gst_vaapi_dpb2_class (void) +{ + static const GstVaapiDpbClass GstVaapiDpb2Class = { + {sizeof (GstVaapiDpb), + (GDestroyNotify) gst_vaapi_dpb_finalize} + , + + dpb_flush, + dpb2_add, + dpb2_get_neighbours + }; + return &GstVaapiDpb2Class.parent_class; +} + +GstVaapiDpb * +gst_vaapi_dpb_new (guint max_pictures) +{ + return dpb_new (max_pictures); +} + +void +gst_vaapi_dpb_flush (GstVaapiDpb * dpb) +{ + const GstVaapiDpbClass *klass; + + g_return_if_fail (GST_VAAPI_IS_DPB (dpb)); + + klass = GST_VAAPI_DPB_GET_CLASS (dpb); + if (G_UNLIKELY (!klass || !klass->add)) + return; + klass->flush (dpb); +} + +gboolean +gst_vaapi_dpb_add (GstVaapiDpb * dpb, GstVaapiPicture * picture) +{ + const GstVaapiDpbClass *klass; + + g_return_val_if_fail (GST_VAAPI_IS_DPB (dpb), FALSE); + g_return_val_if_fail (GST_VAAPI_IS_PICTURE (picture), FALSE); + + klass = GST_VAAPI_DPB_GET_CLASS (dpb); + if (G_UNLIKELY (!klass || !klass->add)) + return FALSE; + return klass->add (dpb, picture); +} + +guint +gst_vaapi_dpb_size (GstVaapiDpb * dpb) +{ + g_return_val_if_fail (GST_VAAPI_IS_DPB (dpb), 0); + + return dpb->num_pictures; +} + +void +gst_vaapi_dpb_get_neighbours (GstVaapiDpb * dpb, GstVaapiPicture * picture, + GstVaapiPicture ** prev_picture_ptr, GstVaapiPicture ** next_picture_ptr) +{ + const GstVaapiDpbClass *klass; + + g_return_if_fail (GST_VAAPI_IS_DPB (dpb)); + g_return_if_fail (GST_VAAPI_IS_PICTURE (picture)); + + klass = GST_VAAPI_DPB_GET_CLASS (dpb); + if (G_UNLIKELY (!klass || !klass->get_neighbours)) + return; + klass->get_neighbours (dpb, picture, prev_picture_ptr, next_picture_ptr); +} diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_dpb.h b/gst-libs/gst/vaapi/gstvaapidecoder_dpb.h new file mode 100644 index 0000000000..fa52d41591 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_dpb.h @@ -0,0 +1,80 @@ +/* + * gstvaapidecoder_dpb.h - Decoded Picture Buffer + * + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODER_DPB_H +#define GST_VAAPI_DECODER_DPB_H + +#include + +G_BEGIN_DECLS + +typedef struct _GstVaapiDpb GstVaapiDpb; +typedef struct _GstVaapiDpbClass GstVaapiDpbClass; + +/* ------------------------------------------------------------------------- */ +/* --- Decoded Picture Buffer --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_DPB(obj) \ + ((GstVaapiDpb *)(obj)) + +#define GST_VAAPI_IS_DPB(obj) \ + (GST_VAAPI_DPB(obj) != NULL) + +G_GNUC_INTERNAL +GstVaapiDpb * +gst_vaapi_dpb_new(guint max_pictures); + +G_GNUC_INTERNAL +void +gst_vaapi_dpb_flush(GstVaapiDpb *dpb); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_dpb_add(GstVaapiDpb *dpb, GstVaapiPicture *picture); + +G_GNUC_INTERNAL +guint +gst_vaapi_dpb_size(GstVaapiDpb *dpb); + +G_GNUC_INTERNAL +void +gst_vaapi_dpb_get_neighbours( + GstVaapiDpb *dpb, + GstVaapiPicture *picture, + GstVaapiPicture **prev_picture_ptr, + GstVaapiPicture **next_picture_ptr +); + +#define gst_vaapi_dpb_ref(dpb) \ + gst_vaapi_mini_object_ref(GST_VAAPI_MINI_OBJECT(dpb)) + +#define gst_vaapi_dpb_unref(dpb) \ + gst_vaapi_mini_object_unref(GST_VAAPI_MINI_OBJECT(dpb)) + +#define gst_vaapi_dpb_replace(old_dpb_ptr, new_dpb) \ + gst_vaapi_mini_object_replace((GstVaapiMiniObject **)(old_dpb_ptr), \ + (GstVaapiMiniObject *)(new_dpb)) + +G_END_DECLS + +#endif /* GST_VAAPI_DECODER_DPB */ diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_h264.c b/gst-libs/gst/vaapi/gstvaapidecoder_h264.c new file mode 100644 index 0000000000..01b1797eb4 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_h264.c @@ -0,0 +1,5018 @@ +/* + * gstvaapidecoder_h264.c - H.264 decoder + * + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapidecoder_h264 + * @short_description: H.264 decoder + */ + +#include "sysdeps.h" +#include +#include +#include "gstvaapidecoder_h264.h" +#include "gstvaapidecoder_objects.h" +#include "gstvaapidecoder_priv.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapiutils_h264_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +/* Defined to 1 if strict ordering of DPB is needed. Only useful for debug */ +#define USE_STRICT_DPB_ORDERING 0 + +typedef struct _GstVaapiDecoderH264Private GstVaapiDecoderH264Private; +typedef struct _GstVaapiDecoderH264Class GstVaapiDecoderH264Class; +typedef struct _GstVaapiFrameStore GstVaapiFrameStore; +typedef struct _GstVaapiFrameStoreClass GstVaapiFrameStoreClass; +typedef struct _GstVaapiParserInfoH264 GstVaapiParserInfoH264; +typedef struct _GstVaapiPictureH264 GstVaapiPictureH264; +typedef struct _GstVaapiStereo3DInfo GstVaapiStereo3DInfo; + +// Used for field_poc[] +#define TOP_FIELD 0 +#define BOTTOM_FIELD 1 + +/* ------------------------------------------------------------------------- */ +/* --- H.264 Parser Info --- */ +/* ------------------------------------------------------------------------- */ + +/* + * Extended decoder unit flags: + * + * @GST_VAAPI_DECODER_UNIT_AU_START: marks the start of an access unit. + * @GST_VAAPI_DECODER_UNIT_AU_END: marks the end of an access unit. + */ +enum +{ + /* This flag does not strictly follow the definitions (7.4.1.2.3) + for detecting the start of an access unit as we are only + interested in knowing if the current slice is the first one or + the last one in the current access unit */ + GST_VAAPI_DECODER_UNIT_FLAG_AU_START = + (GST_VAAPI_DECODER_UNIT_FLAG_LAST << 0), + GST_VAAPI_DECODER_UNIT_FLAG_AU_END = (GST_VAAPI_DECODER_UNIT_FLAG_LAST << 1), + + GST_VAAPI_DECODER_UNIT_FLAGS_AU = (GST_VAAPI_DECODER_UNIT_FLAG_AU_START | + GST_VAAPI_DECODER_UNIT_FLAG_AU_END), +}; + +#define GST_VAAPI_PARSER_INFO_H264(obj) \ + ((GstVaapiParserInfoH264 *)(obj)) + +struct _GstVaapiParserInfoH264 +{ + GstVaapiMiniObject parent_instance; + GstH264NalUnit nalu; + union + { + GstH264SPS sps; + GstH264PPS pps; + GArray *sei; + GstH264SliceHdr slice_hdr; + } data; + guint state; + guint flags; // Same as decoder unit flags (persistent) + guint view_id; // View ID of slice + guint voc; // View order index (VOIdx) of slice +}; + +static void +gst_vaapi_parser_info_h264_finalize (GstVaapiParserInfoH264 * pi) +{ + if (!pi->nalu.valid) + return; + + switch (pi->nalu.type) { + case GST_H264_NAL_SPS: + case GST_H264_NAL_SUBSET_SPS: + gst_h264_sps_clear (&pi->data.sps); + break; + case GST_H264_NAL_PPS: + gst_h264_pps_clear (&pi->data.pps); + break; + case GST_H264_NAL_SEI: + if (pi->data.sei) { + g_array_unref (pi->data.sei); + pi->data.sei = NULL; + } + break; + } +} + +static inline const GstVaapiMiniObjectClass * +gst_vaapi_parser_info_h264_class (void) +{ + static const GstVaapiMiniObjectClass GstVaapiParserInfoH264Class = { + .size = sizeof (GstVaapiParserInfoH264), + .finalize = (GDestroyNotify) gst_vaapi_parser_info_h264_finalize + }; + return &GstVaapiParserInfoH264Class; +} + +static inline GstVaapiParserInfoH264 * +gst_vaapi_parser_info_h264_new (void) +{ + return (GstVaapiParserInfoH264 *) + gst_vaapi_mini_object_new (gst_vaapi_parser_info_h264_class ()); +} + +#define gst_vaapi_parser_info_h264_ref(pi) \ + gst_vaapi_mini_object_ref(GST_VAAPI_MINI_OBJECT(pi)) + +#define gst_vaapi_parser_info_h264_unref(pi) \ + gst_vaapi_mini_object_unref(GST_VAAPI_MINI_OBJECT(pi)) + +#define gst_vaapi_parser_info_h264_replace(old_pi_ptr, new_pi) \ + gst_vaapi_mini_object_replace((GstVaapiMiniObject **)(old_pi_ptr), \ + (GstVaapiMiniObject *)(new_pi)) + +/* ------------------------------------------------------------------------- */ +/* --- H.264 Pictures --- */ +/* ------------------------------------------------------------------------- */ + +/* + * Extended picture flags: + * + * @GST_VAAPI_PICTURE_FLAG_IDR: flag that specifies an IDR picture + * @GST_VAAPI_PICTURE_FLAG_INTER_VIEW: flag that indicates the picture + * may be used for inter-view prediction + * @GST_VAAPI_PICTURE_FLAG_ANCHOR: flag that specifies an anchor picture, + * i.e. a picture that is decoded with only inter-view prediction, + * and not inter prediction + * @GST_VAAPI_PICTURE_FLAG_AU_START: flag that marks the start of an + * access unit (AU) + * @GST_VAAPI_PICTURE_FLAG_AU_END: flag that marks the end of an + * access unit (AU) + * @GST_VAAPI_PICTURE_FLAG_GHOST: flag that specifies a "non-existing" + * picture, without any viable GstVideoCodecFrame associated to it. + * i.e. a dummy picture with some valid contents + * @GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE: flag that specifies + * "used for short-term reference" + * @GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE: flag that specifies + * "used for long-term reference" + * @GST_VAAPI_PICTURE_FLAGS_REFERENCE: mask covering any kind of + * reference picture (short-term reference or long-term reference) + */ +enum +{ + GST_VAAPI_PICTURE_FLAG_IDR = (GST_VAAPI_PICTURE_FLAG_LAST << 0), + GST_VAAPI_PICTURE_FLAG_REFERENCE2 = (GST_VAAPI_PICTURE_FLAG_LAST << 1), + GST_VAAPI_PICTURE_FLAG_INTER_VIEW = (GST_VAAPI_PICTURE_FLAG_LAST << 2), + GST_VAAPI_PICTURE_FLAG_ANCHOR = (GST_VAAPI_PICTURE_FLAG_LAST << 3), + GST_VAAPI_PICTURE_FLAG_AU_START = (GST_VAAPI_PICTURE_FLAG_LAST << 4), + GST_VAAPI_PICTURE_FLAG_AU_END = (GST_VAAPI_PICTURE_FLAG_LAST << 5), + GST_VAAPI_PICTURE_FLAG_GHOST = (GST_VAAPI_PICTURE_FLAG_LAST << 6), + + GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE = + (GST_VAAPI_PICTURE_FLAG_REFERENCE), + GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE = + (GST_VAAPI_PICTURE_FLAG_REFERENCE | GST_VAAPI_PICTURE_FLAG_REFERENCE2), + GST_VAAPI_PICTURE_FLAGS_REFERENCE = + (GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE | + GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE), +}; + +#define GST_VAAPI_PICTURE_IS_IDR(picture) \ + (GST_VAAPI_PICTURE_FLAG_IS_SET(picture, GST_VAAPI_PICTURE_FLAG_IDR)) + +#define GST_VAAPI_PICTURE_IS_SHORT_TERM_REFERENCE(picture) \ + ((GST_VAAPI_PICTURE_FLAGS(picture) & \ + GST_VAAPI_PICTURE_FLAGS_REFERENCE) == \ + GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE) + +#define GST_VAAPI_PICTURE_IS_LONG_TERM_REFERENCE(picture) \ + ((GST_VAAPI_PICTURE_FLAGS(picture) & \ + GST_VAAPI_PICTURE_FLAGS_REFERENCE) == \ + GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE) + +#define GST_VAAPI_PICTURE_IS_INTER_VIEW(picture) \ + (GST_VAAPI_PICTURE_FLAG_IS_SET(picture, GST_VAAPI_PICTURE_FLAG_INTER_VIEW)) + +#define GST_VAAPI_PICTURE_IS_ANCHOR(picture) \ + (GST_VAAPI_PICTURE_FLAG_IS_SET(picture, GST_VAAPI_PICTURE_FLAG_ANCHOR)) + +#define GST_VAAPI_PICTURE_H264(picture) \ + ((GstVaapiPictureH264 *)(picture)) + +struct _GstVaapiPictureH264 +{ + GstVaapiPicture base; + GstH264SliceHdr *last_slice_hdr; + guint structure; + gint32 field_poc[2]; + gint32 frame_num; // Original frame_num from slice_header() + gint32 frame_num_wrap; // Temporary for ref pic marking: FrameNumWrap + gint32 long_term_frame_idx; // Temporary for ref pic marking: LongTermFrameIdx + gint32 pic_num; // Temporary for ref pic marking: PicNum + gint32 long_term_pic_num; // Temporary for ref pic marking: LongTermPicNum + GstVaapiPictureH264 *other_field; // Temporary for ref pic marking: other field in the same frame store + guint output_flag:1; + guint output_needed:1; +}; + +GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiPictureH264, gst_vaapi_picture_h264); + +void +gst_vaapi_picture_h264_destroy (GstVaapiPictureH264 * picture) +{ + gst_vaapi_picture_destroy (GST_VAAPI_PICTURE (picture)); +} + +gboolean +gst_vaapi_picture_h264_create (GstVaapiPictureH264 * picture, + const GstVaapiCodecObjectConstructorArgs * args) +{ + if (!gst_vaapi_picture_create (GST_VAAPI_PICTURE (picture), args)) + return FALSE; + + picture->structure = picture->base.structure; + picture->field_poc[0] = G_MAXINT32; + picture->field_poc[1] = G_MAXINT32; + picture->output_needed = FALSE; + return TRUE; +} + +static inline GstVaapiPictureH264 * +gst_vaapi_picture_h264_new (GstVaapiDecoderH264 * decoder) +{ + return (GstVaapiPictureH264 *) + gst_vaapi_codec_object_new (&GstVaapiPictureH264Class, + GST_VAAPI_CODEC_BASE (decoder), NULL, + sizeof (VAPictureParameterBufferH264), NULL, 0, 0); +} + +static inline void +gst_vaapi_picture_h264_set_reference (GstVaapiPictureH264 * picture, + guint reference_flags, gboolean other_field) +{ + if (!picture) + return; + GST_VAAPI_PICTURE_FLAG_UNSET (picture, GST_VAAPI_PICTURE_FLAGS_REFERENCE); + GST_VAAPI_PICTURE_FLAG_SET (picture, reference_flags); + + if (!other_field || !(picture = picture->other_field)) + return; + GST_VAAPI_PICTURE_FLAG_UNSET (picture, GST_VAAPI_PICTURE_FLAGS_REFERENCE); + GST_VAAPI_PICTURE_FLAG_SET (picture, reference_flags); +} + +static inline GstVaapiPictureH264 * +gst_vaapi_picture_h264_new_field (GstVaapiPictureH264 * picture) +{ + g_return_val_if_fail (picture, NULL); + + return (GstVaapiPictureH264 *) gst_vaapi_picture_new_field (&picture->base); +} + +static inline GstVaapiPictureH264 * +gst_vaapi_picture_h264_new_clone (GstVaapiPictureH264 * picture) +{ + g_return_val_if_fail (picture, NULL); + + return (GstVaapiPictureH264 *) gst_vaapi_picture_new_clone (&picture->base); +} + +/* ------------------------------------------------------------------------- */ +/* --- Frame Buffers (DPB) --- */ +/* ------------------------------------------------------------------------- */ + +struct _GstVaapiFrameStore +{ + /*< private > */ + GstVaapiMiniObject parent_instance; + + guint view_id; + guint structure; + GstVaapiPictureH264 *buffers[2]; + guint num_buffers; + guint output_needed; + guint output_called; +}; + +static void +gst_vaapi_frame_store_finalize (gpointer object) +{ + GstVaapiFrameStore *const fs = object; + guint i; + + for (i = 0; i < fs->num_buffers; i++) + gst_vaapi_picture_replace (&fs->buffers[i], NULL); +} + +static GstVaapiFrameStore * +gst_vaapi_frame_store_new (GstVaapiPictureH264 * picture) +{ + GstVaapiFrameStore *fs; + + static const GstVaapiMiniObjectClass GstVaapiFrameStoreClass = { + sizeof (GstVaapiFrameStore), + gst_vaapi_frame_store_finalize + }; + + fs = (GstVaapiFrameStore *) + gst_vaapi_mini_object_new (&GstVaapiFrameStoreClass); + if (!fs) + return NULL; + + fs->view_id = picture->base.view_id; + fs->structure = picture->structure; + fs->buffers[0] = gst_vaapi_picture_ref (picture); + fs->buffers[1] = NULL; + fs->num_buffers = 1; + fs->output_needed = 0; + fs->output_called = 0; + + if (picture->output_flag) { + picture->output_needed = TRUE; + fs->output_needed++; + } + return fs; +} + +static gboolean +gst_vaapi_frame_store_add (GstVaapiFrameStore * fs, + GstVaapiPictureH264 * picture) +{ + guint field; + + g_return_val_if_fail (fs->num_buffers == 1, FALSE); + g_return_val_if_fail (!GST_VAAPI_PICTURE_IS_FRAME (picture), FALSE); + g_return_val_if_fail (!GST_VAAPI_PICTURE_IS_FIRST_FIELD (picture), FALSE); + + gst_vaapi_picture_replace (&fs->buffers[fs->num_buffers++], picture); + if (picture->output_flag) { + picture->output_needed = TRUE; + fs->output_needed++; + } + + fs->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME; + + field = picture->structure == GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD ? + TOP_FIELD : BOTTOM_FIELD; + + if (fs->buffers[0]->field_poc[field] != G_MAXINT32) + return FALSE; + fs->buffers[0]->field_poc[field] = picture->field_poc[field]; + + if (picture->field_poc[!field] != G_MAXINT32) + return FALSE; + picture->field_poc[!field] = fs->buffers[0]->field_poc[!field]; + + return TRUE; +} + +static gboolean +gst_vaapi_frame_store_split_fields (GstVaapiFrameStore * fs, gboolean tff) +{ + GstVaapiPictureH264 *const first_field = fs->buffers[0]; + GstVaapiPictureH264 *second_field; + + g_return_val_if_fail (fs->num_buffers == 1, FALSE); + + first_field->base.structure = tff ? + GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD : + GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD; + GST_VAAPI_PICTURE_FLAG_SET (first_field, GST_VAAPI_PICTURE_FLAG_INTERLACED); + + second_field = gst_vaapi_picture_h264_new_field (first_field); + if (!second_field) + return FALSE; + gst_vaapi_picture_h264_set_reference (second_field, + GST_VAAPI_PICTURE_FLAGS (first_field) & GST_VAAPI_PICTURE_FLAGS_REFERENCE, + FALSE); + gst_vaapi_picture_replace (&fs->buffers[fs->num_buffers++], second_field); + gst_vaapi_picture_unref (second_field); + + second_field->frame_num = first_field->frame_num; + second_field->field_poc[0] = first_field->field_poc[0]; + second_field->field_poc[1] = first_field->field_poc[1]; + second_field->output_flag = first_field->output_flag; + if (second_field->output_flag) { + second_field->output_needed = TRUE; + fs->output_needed++; + } + return TRUE; +} + +static inline gboolean +gst_vaapi_frame_store_has_frame (GstVaapiFrameStore * fs) +{ + return fs->structure == GST_VAAPI_PICTURE_STRUCTURE_FRAME; +} + +static inline gboolean +gst_vaapi_frame_store_is_complete (GstVaapiFrameStore * fs) +{ + return gst_vaapi_frame_store_has_frame (fs) || + GST_VAAPI_PICTURE_IS_ONEFIELD (fs->buffers[0]); +} + +static inline gboolean +gst_vaapi_frame_store_has_reference (GstVaapiFrameStore * fs) +{ + guint i; + + for (i = 0; i < fs->num_buffers; i++) { + if (GST_VAAPI_PICTURE_IS_REFERENCE (fs->buffers[i])) + return TRUE; + } + return FALSE; +} + +static gboolean +gst_vaapi_frame_store_has_inter_view (GstVaapiFrameStore * fs) +{ + guint i; + + for (i = 0; i < fs->num_buffers; i++) { + if (GST_VAAPI_PICTURE_IS_INTER_VIEW (fs->buffers[i])) + return TRUE; + } + return FALSE; +} + +#define gst_vaapi_frame_store_ref(fs) \ + gst_vaapi_mini_object_ref(GST_VAAPI_MINI_OBJECT(fs)) + +#define gst_vaapi_frame_store_unref(fs) \ + gst_vaapi_mini_object_unref(GST_VAAPI_MINI_OBJECT(fs)) + +#define gst_vaapi_frame_store_replace(old_fs_p, new_fs) \ + gst_vaapi_mini_object_replace((GstVaapiMiniObject **)(old_fs_p), \ + (GstVaapiMiniObject *)(new_fs)) + +/* ------------------------------------------------------------------------- */ +/* --- H.264 3D Info --- */ +/* ------------------------------------------------------------------------- */ +/** + * GstVaapiStereo3DInfo: + * @mode: the #GstVideoMultiviewMode. + * @flags: the #GstVideoMultiviewFlags. + * @id: the id number. + * @repetition_period: 0 means once, 1 means always, >1 compare with poc. + */ +struct _GstVaapiStereo3DInfo +{ + GstVideoMultiviewMode mode; + GstVideoMultiviewFlags flags; + guint id; + guint repetition_period; +}; + +/* ------------------------------------------------------------------------- */ +/* --- H.264 Decoder --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_DECODER_H264_CAST(decoder) \ + ((GstVaapiDecoderH264 *)(decoder)) + +typedef enum +{ + GST_H264_VIDEO_STATE_GOT_SPS = 1 << 0, + GST_H264_VIDEO_STATE_GOT_PPS = 1 << 1, + GST_H264_VIDEO_STATE_GOT_SLICE = 1 << 2, + GST_H264_VIDEO_STATE_GOT_I_FRAME = 1 << 3, // persistent across SPS + GST_H264_VIDEO_STATE_GOT_P_SLICE = 1 << 4, // predictive (all non-intra) + + GST_H264_VIDEO_STATE_VALID_PICTURE_HEADERS = (GST_H264_VIDEO_STATE_GOT_SPS | + GST_H264_VIDEO_STATE_GOT_PPS), + GST_H264_VIDEO_STATE_VALID_PICTURE = + (GST_H264_VIDEO_STATE_VALID_PICTURE_HEADERS | + GST_H264_VIDEO_STATE_GOT_SLICE) +} GstH264VideoState; + +struct _GstVaapiDecoderH264Private +{ + GstH264NalParser *parser; + guint parser_state; + guint decoder_state; + GstVaapiStreamAlignH264 stream_alignment; + GstVaapiPictureH264 *current_picture; + GstVaapiParserInfoH264 *sps[GST_H264_MAX_SPS_COUNT]; + GstVaapiParserInfoH264 *active_sps; + GstVaapiParserInfoH264 *pps[GST_H264_MAX_PPS_COUNT]; + GstVaapiParserInfoH264 *active_pps; + GstVaapiParserInfoH264 *prev_pi; + GstVaapiParserInfoH264 *prev_slice_pi; + GstVaapiFrameStore **prev_ref_frames; + GstVaapiFrameStore **prev_frames; + guint prev_frames_alloc; + GstVaapiFrameStore **dpb; + guint dpb_count; + guint dpb_size; + guint dpb_size_max; + guint max_views; + GstVaapiProfile profile; + GstVaapiEntrypoint entrypoint; + GstVaapiChromaType chroma_type; + GPtrArray *inter_views; + GstVaapiPictureH264 *short_ref[32]; + guint short_ref_count; + GstVaapiPictureH264 *long_ref[32]; + guint long_ref_count; + GstVaapiPictureH264 *RefPicList0[32]; + guint RefPicList0_count; + GstVaapiPictureH264 *RefPicList1[32]; + guint RefPicList1_count; + guint nal_length_size; + guint mb_width; + guint mb_height; + guint pic_structure; // pic_struct (from SEI pic_timing() or inferred) + gint32 field_poc[2]; // 0:TopFieldOrderCnt / 1:BottomFieldOrderCnt + gint32 poc_msb; // PicOrderCntMsb + gint32 poc_lsb; // pic_order_cnt_lsb (from slice_header()) + gint32 prev_poc_msb; // prevPicOrderCntMsb + gint32 prev_poc_lsb; // prevPicOrderCntLsb + gint32 frame_num_offset; // FrameNumOffset + gint32 frame_num; // frame_num (from slice_header()) + gint32 prev_frame_num; // prevFrameNum + gint32 prev_ref_frame_num; // prevRefFrameNum + gboolean prev_pic_has_mmco5; // prevMmco5Pic + gboolean prev_pic_reference; // previous picture is a reference + guint prev_pic_structure; // previous picture structure + guint is_opened:1; + guint is_avcC:1; + guint has_context:1; + guint progressive_sequence:1; + guint top_field_first:1; + + gboolean force_low_latency; + gboolean base_only; + + GstVaapiStereo3DInfo stereo_info; +}; + +/** + * GstVaapiDecoderH264: + * + * A decoder based on H264. + */ +struct _GstVaapiDecoderH264 +{ + /*< private > */ + GstVaapiDecoder parent_instance; + GstVaapiDecoderH264Private priv; +}; + +/** + * GstVaapiDecoderH264Class: + * + * A decoder class based on H264. + */ +struct _GstVaapiDecoderH264Class +{ + /*< private > */ + GstVaapiDecoderClass parent_class; +}; + +G_DEFINE_TYPE (GstVaapiDecoderH264, gst_vaapi_decoder_h264, + GST_TYPE_VAAPI_DECODER); + +static gboolean +exec_ref_pic_marking (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture); + +static gboolean +exec_ref_pic_marking_sliding_window (GstVaapiDecoderH264 * decoder); + +static gboolean +is_inter_view_reference_for_next_pictures (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture); + +static inline gboolean +is_inter_view_reference_for_next_frames (GstVaapiDecoderH264 * decoder, + GstVaapiFrameStore * fs) +{ + return is_inter_view_reference_for_next_pictures (decoder, fs->buffers[0]); +} + +/* Determines if the supplied profile is one of the MVC set */ +static gboolean +is_mvc_profile (GstH264Profile profile) +{ + return profile == GST_H264_PROFILE_MULTIVIEW_HIGH || + profile == GST_H264_PROFILE_STEREO_HIGH; +} + +/* Determines the view_id from the supplied NAL unit */ +static inline guint +get_view_id (GstH264NalUnit * nalu) +{ + return GST_H264_IS_MVC_NALU (nalu) ? nalu->extension.mvc.view_id : 0; +} + +/* Determines the view order index (VOIdx) from the supplied view_id */ +static gint +get_view_order_index (GstH264SPS * sps, guint16 view_id) +{ + GstH264SPSExtMVC *mvc; + gint i; + + if (!sps || sps->extension_type != GST_H264_NAL_EXTENSION_MVC) + return 0; + + mvc = &sps->extension.mvc; + for (i = 0; i <= mvc->num_views_minus1; i++) { + if (mvc->view[i].view_id == view_id) + return i; + } + GST_ERROR ("failed to find VOIdx from view_id (%d)", view_id); + return -1; +} + +/* Determines NumViews */ +static guint +get_num_views (GstH264SPS * sps) +{ + return 1 + (sps->extension_type == GST_H264_NAL_EXTENSION_MVC ? + sps->extension.mvc.num_views_minus1 : 0); +} + +/* Get number of reference frames to use */ +static guint +get_max_dec_frame_buffering (GstH264SPS * sps) +{ + guint num_views, max_dpb_frames; + guint max_dec_frame_buffering, PicSizeMbs; + GstVaapiLevelH264 level; + const GstVaapiH264LevelLimits *level_limits; + + /* Table A-1 - Level limits */ + if (G_UNLIKELY (sps->level_idc == 11 && sps->constraint_set3_flag)) + level = GST_VAAPI_LEVEL_H264_L1b; + else + level = gst_vaapi_utils_h264_get_level (sps->level_idc); + level_limits = gst_vaapi_utils_h264_get_level_limits (level); + if (G_UNLIKELY (!level_limits)) { + GST_FIXME ("unsupported level_idc value (%d)", sps->level_idc); + max_dec_frame_buffering = 16; + } else { + PicSizeMbs = ((sps->pic_width_in_mbs_minus1 + 1) * + (sps->pic_height_in_map_units_minus1 + 1) * + (sps->frame_mbs_only_flag ? 1 : 2)); + max_dec_frame_buffering = level_limits->MaxDpbMbs / PicSizeMbs; + } + if (is_mvc_profile (sps->profile_idc)) + max_dec_frame_buffering <<= 1; + + /* VUI parameters */ + if (sps->vui_parameters_present_flag) { + GstH264VUIParams *const vui_params = &sps->vui_parameters; + if (vui_params->bitstream_restriction_flag) + max_dec_frame_buffering = vui_params->max_dec_frame_buffering; + else { + switch (sps->profile_idc) { + case 44: // CAVLC 4:4:4 Intra profile + case GST_H264_PROFILE_SCALABLE_HIGH: + case GST_H264_PROFILE_HIGH: + case GST_H264_PROFILE_HIGH10: + case GST_H264_PROFILE_HIGH_422: + case GST_H264_PROFILE_HIGH_444: + if (sps->constraint_set3_flag) + max_dec_frame_buffering = 0; + break; + } + } + } + + num_views = get_num_views (sps); + max_dpb_frames = 16 * (num_views > 1 ? g_bit_storage (num_views - 1) : 1); + if (max_dec_frame_buffering > max_dpb_frames) + max_dec_frame_buffering = max_dpb_frames; + else if (max_dec_frame_buffering < sps->num_ref_frames) + max_dec_frame_buffering = sps->num_ref_frames; + return MAX (1, max_dec_frame_buffering); +} + +static void +array_remove_index_fast (void *array, guint * array_length_ptr, guint index) +{ + gpointer *const entries = array; + guint num_entries = *array_length_ptr; + + g_return_if_fail (index < num_entries); + + if (index != --num_entries) + entries[index] = entries[num_entries]; + entries[num_entries] = NULL; + *array_length_ptr = num_entries; +} + +#if 1 +static inline void +array_remove_index (void *array, guint * array_length_ptr, guint index) +{ + array_remove_index_fast (array, array_length_ptr, index); +} +#else +static void +array_remove_index (void *array, guint * array_length_ptr, guint index) +{ + gpointer *const entries = array; + const guint num_entries = *array_length_ptr - 1; + guint i; + + g_return_if_fail (index <= num_entries); + + for (i = index; i < num_entries; i++) + entries[i] = entries[i + 1]; + entries[num_entries] = NULL; + *array_length_ptr = num_entries; +} +#endif + +#define ARRAY_REMOVE_INDEX(array, index) \ + array_remove_index(array, &array##_count, index) + +static void +dpb_remove_index (GstVaapiDecoderH264 * decoder, guint index) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + guint i, num_frames = --priv->dpb_count; + + if (USE_STRICT_DPB_ORDERING) { + for (i = index; i < num_frames; i++) + gst_vaapi_frame_store_replace (&priv->dpb[i], priv->dpb[i + 1]); + } else if (index != num_frames) + gst_vaapi_frame_store_replace (&priv->dpb[index], priv->dpb[num_frames]); + gst_vaapi_frame_store_replace (&priv->dpb[num_frames], NULL); +} + +static gboolean +dpb_output (GstVaapiDecoderH264 * decoder, GstVaapiFrameStore * fs) +{ + GstVaapiPictureH264 *picture = NULL; + guint i; + + g_return_val_if_fail (fs != NULL, FALSE); + + fs->output_called++; + if (!gst_vaapi_frame_store_is_complete (fs)) + return TRUE; + + for (i = 0; i < fs->num_buffers; i++) { + GstVaapiPictureH264 *const pic = fs->buffers[i]; + if (pic == NULL) + return FALSE; + pic->output_needed = FALSE; + if (!GST_VAAPI_PICTURE_FLAG_IS_SET (pic, GST_VAAPI_PICTURE_FLAG_GHOST)) + picture = pic; + } + + fs->output_needed = 0; + fs->output_called = 0; + if (!picture) + return TRUE; + return gst_vaapi_picture_output (GST_VAAPI_PICTURE_CAST (picture)); +} + +static inline void +dpb_evict (GstVaapiDecoderH264 * decoder, GstVaapiPictureH264 * picture, + guint i) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiFrameStore *const fs = priv->dpb[i]; + + if (!fs->output_needed && !gst_vaapi_frame_store_has_reference (fs)) + dpb_remove_index (decoder, i); +} + +/* Finds the picture with the nearest previous POC and same structure */ +static gint +dpb_find_nearest_prev_poc (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture, guint picture_structure, + GstVaapiPictureH264 ** found_picture_ptr) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiPictureH264 *found_picture = NULL; + guint i, j, found_index = -1; + + g_return_val_if_fail (picture != NULL, -1); + + if (!picture_structure) + picture_structure = picture->base.structure; + + for (i = 0; i < priv->dpb_count; i++) { + GstVaapiFrameStore *const fs = priv->dpb[i]; + if (picture->base.view_id != fs->view_id) + continue; + for (j = 0; j < fs->num_buffers; j++) { + GstVaapiPictureH264 *const pic = fs->buffers[j]; + if (pic->base.structure != picture_structure) + continue; + if (pic->base.poc >= picture->base.poc) + continue; + if (!found_picture || found_picture->base.poc < pic->base.poc) + found_picture = pic, found_index = i; + } + } + + if (found_picture_ptr) + *found_picture_ptr = found_picture; + return found_index; +} + +/* Finds the picture with the lowest POC that needs to be output */ +static gint +dpb_find_lowest_poc_for_output (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture, GstVaapiPictureH264 ** found_picture_ptr, + gboolean * can_be_output) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiPictureH264 *found_picture = NULL; + guint i, j, found_index = -1, found_poc = -1; + gboolean is_first = TRUE; + gint last_output_poc = -1; + + for (i = 0; i < priv->dpb_count; i++) { + GstVaapiFrameStore *const fs = priv->dpb[i]; + if (!fs->output_needed) { + /* find the maximum poc of any previously output frames that are + * still held in the DPB. */ + if (can_be_output != NULL) { + for (j = 0; j < fs->num_buffers; j++) { + if (is_first || fs->buffers[j]->base.poc > last_output_poc) { + is_first = FALSE; + last_output_poc = fs->buffers[j]->base.poc; + } + } + } + continue; + } + if (picture && picture->base.view_id != fs->view_id) + continue; + for (j = 0; j < fs->num_buffers; j++) { + GstVaapiPictureH264 *const pic = fs->buffers[j]; + if (!pic->output_needed) + continue; + if (!found_picture || found_picture->base.poc > pic->base.poc || + (found_picture->base.poc == pic->base.poc && + found_picture->base.voc > pic->base.voc)) + found_picture = pic, found_index = i, found_poc = pic->base.poc; + } + } + + if (can_be_output != NULL) { + /* found_picture can be output if it's the first frame in the DPB, + * or if there's no gap between it and the most recently output + * frame. */ + *can_be_output = FALSE; + if (found_picture && + gst_vaapi_frame_store_is_complete (priv->dpb[found_index])) { + if (is_first) { + *can_be_output = TRUE; + } else if (((int) (found_poc)) > ((int) (last_output_poc))) { + *can_be_output = (found_poc - last_output_poc) <= 2; + } else { + /* A frame with a higher poc has already been sent. No choice + * now but to drop this frame */ + GST_WARNING ("dropping out-of-sequence frame"); + priv->dpb[found_index]->output_needed = FALSE; + } + } + } + + if (found_picture_ptr) + *found_picture_ptr = found_picture; + return found_index; +} + +/* Finds the picture with the lowest POC that needs to be output */ +static gint +dpb_find_lowest_poc (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture, GstVaapiPictureH264 ** found_picture_ptr) +{ + return dpb_find_lowest_poc_for_output (decoder, picture, found_picture_ptr, + NULL); +} + + +/* Finds the picture with the lowest VOC that needs to be output */ +static gint +dpb_find_lowest_voc (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture, GstVaapiPictureH264 ** found_picture_ptr) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiPictureH264 *found_picture = NULL; + guint i, j, found_index = -1; + + for (i = 0; i < priv->dpb_count; i++) { + GstVaapiFrameStore *const fs = priv->dpb[i]; + if (!fs->output_needed || fs->view_id == picture->base.view_id) + continue; + for (j = 0; j < fs->num_buffers; j++) { + GstVaapiPictureH264 *const pic = fs->buffers[j]; + if (!pic->output_needed || pic->base.poc != picture->base.poc) + continue; + if (!found_picture || found_picture->base.voc > pic->base.voc) + found_picture = pic, found_index = i; + } + } + + if (found_picture_ptr) + *found_picture_ptr = found_picture; + return found_index; +} + +static gboolean +dpb_output_other_views (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture, guint voc) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiPictureH264 *found_picture; + gint found_index; + gboolean success; + + if (priv->max_views == 1) + return TRUE; + + /* Emit all other view components that were in the same access + unit than the picture we have just found */ + found_picture = picture; + for (;;) { + found_index = dpb_find_lowest_voc (decoder, found_picture, &found_picture); + if (found_index < 0 || found_picture->base.voc >= voc) + break; + success = dpb_output (decoder, priv->dpb[found_index]); + dpb_evict (decoder, found_picture, found_index); + if (!success) + return FALSE; + } + return TRUE; +} + +static gboolean +dpb_bump (GstVaapiDecoderH264 * decoder, GstVaapiPictureH264 * picture) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiPictureH264 *found_picture; + gint found_index; + gboolean success; + + found_index = dpb_find_lowest_poc (decoder, picture, &found_picture); + if (found_index < 0) + return FALSE; + + gst_vaapi_picture_ref (found_picture); + + if (picture && picture->base.poc != found_picture->base.poc) + dpb_output_other_views (decoder, found_picture, found_picture->base.voc); + + success = dpb_output (decoder, priv->dpb[found_index]); + + dpb_evict (decoder, found_picture, found_index); + if (priv->max_views == 1) + goto done; + + if (picture && picture->base.poc != found_picture->base.poc) + dpb_output_other_views (decoder, found_picture, G_MAXUINT32); + +done: + gst_vaapi_picture_unref (found_picture); + return success; +} + +static void +dpb_output_ready_frames (GstVaapiDecoderH264 * decoder) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + gboolean can_output = FALSE; + gint found_index; + + while (TRUE) { + found_index = dpb_find_lowest_poc_for_output (decoder, + priv->current_picture, NULL, &can_output); + if (found_index < 0 || !can_output) + break; + dpb_output (decoder, priv->dpb[found_index]); + } +} + +static void +dpb_clear (GstVaapiDecoderH264 * decoder, GstVaapiPictureH264 * picture) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + guint i, n; + + for (i = 0; i < priv->dpb_count; i++) { + if (picture && picture->base.view_id != priv->dpb[i]->view_id) + continue; + gst_vaapi_frame_store_replace (&priv->dpb[i], NULL); + } + + /* Compact the resulting DPB, i.e. remove holes */ + for (i = 0, n = 0; i < priv->dpb_count; i++) { + if (priv->dpb[i]) { + if (i != n) { + priv->dpb[n] = priv->dpb[i]; + priv->dpb[i] = NULL; + } + n++; + } + } + priv->dpb_count = n; + + /* Clear previous frame buffers only if this is a "flush-all" operation, + or if the picture is the first one in the access unit */ + if (priv->prev_frames && (!picture || + GST_VAAPI_PICTURE_FLAG_IS_SET (picture, + GST_VAAPI_PICTURE_FLAG_AU_START))) { + for (i = 0; i < priv->max_views; i++) + gst_vaapi_frame_store_replace (&priv->prev_frames[i], NULL); + } + + /* Clear previous reference frame buffers only if this is a "flush-all" + operation, or if the picture is part of an IDR NAL */ + if (priv->prev_ref_frames && (!picture || + GST_VAAPI_PICTURE_FLAG_IS_SET (picture, + GST_VAAPI_PICTURE_FLAG_IDR))) { + for (i = 0; i < priv->max_views; i++) + gst_vaapi_frame_store_replace (&priv->prev_ref_frames[i], NULL); + } +} + +static void +dpb_flush (GstVaapiDecoderH264 * decoder, GstVaapiPictureH264 * picture) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + guint i; + + /* Detect broken frames and mark them as having a single field if + needed */ + for (i = 0; i < priv->dpb_count; i++) { + GstVaapiFrameStore *const fs = priv->dpb[i]; + if (!fs->output_needed || gst_vaapi_frame_store_is_complete (fs)) + continue; + GST_VAAPI_PICTURE_FLAG_SET (fs->buffers[0], + GST_VAAPI_PICTURE_FLAG_ONEFIELD); + } + + /* Output any frame remaining in DPB */ + while (dpb_bump (decoder, picture)); + dpb_clear (decoder, picture); +} + +static void +dpb_prune_mvc (GstVaapiDecoderH264 * decoder, GstVaapiPictureH264 * picture) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + const gboolean is_last_picture = /* in the access unit */ + GST_VAAPI_PICTURE_FLAG_IS_SET (picture, GST_VAAPI_PICTURE_FLAG_AU_END); + guint i; + + // Remove all unused inter-view only reference components of the current AU + i = 0; + while (i < priv->dpb_count) { + GstVaapiFrameStore *const fs = priv->dpb[i]; + if (fs->view_id != picture->base.view_id && + !fs->output_needed && !gst_vaapi_frame_store_has_reference (fs) && + (is_last_picture || + !is_inter_view_reference_for_next_frames (decoder, fs))) + dpb_remove_index (decoder, i); + else + i++; + } +} + +static gboolean +dpb_add (GstVaapiDecoderH264 * decoder, GstVaapiPictureH264 * picture) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiFrameStore *fs; + guint i; + + if (priv->max_views > 1) + dpb_prune_mvc (decoder, picture); + + // Remove all unused pictures + if (!GST_VAAPI_PICTURE_IS_IDR (picture)) { + i = 0; + while (i < priv->dpb_count) { + GstVaapiFrameStore *const fs = priv->dpb[i]; + if (fs->view_id == picture->base.view_id && + !fs->output_needed && !gst_vaapi_frame_store_has_reference (fs)) + dpb_remove_index (decoder, i); + else + i++; + } + } + // Check if picture is the second field and the first field is still in DPB + if (GST_VAAPI_PICTURE_IS_INTERLACED (picture) && + !GST_VAAPI_PICTURE_IS_FIRST_FIELD (picture)) { + fs = priv->prev_frames[picture->base.voc]; + if (!fs || &fs->buffers[0]->base != picture->base.parent_picture) + return FALSE; + if (!gst_vaapi_frame_store_add (fs, picture)) + return FALSE; + + if (fs->output_called) + return dpb_output (decoder, fs); + return TRUE; + } + // Try to output the previous frame again if it was not submitted yet + // e.g. delayed while waiting for the next field, or a field gap was closed + fs = priv->prev_frames[picture->base.voc]; + if (fs && fs->output_called) + dpb_output (decoder, fs); + + // Create new frame store, and split fields if necessary + fs = gst_vaapi_frame_store_new (picture); + if (!fs) + return FALSE; + gst_vaapi_frame_store_replace (&priv->prev_frames[picture->base.voc], fs); + gst_vaapi_frame_store_unref (fs); + + if (!priv->progressive_sequence && gst_vaapi_frame_store_has_frame (fs)) { + if (!gst_vaapi_frame_store_split_fields (fs, priv->top_field_first)) + return FALSE; + } + // C.4.5.1 - Storage and marking of a reference decoded picture into the DPB + if (GST_VAAPI_PICTURE_IS_REFERENCE (picture)) { + while (priv->dpb_count == priv->dpb_size) { + if (!dpb_bump (decoder, picture)) + return FALSE; + } + gst_vaapi_frame_store_replace (&priv->prev_ref_frames[picture->base.voc], + fs); + } + // C.4.5.2 - Storage and marking of a non-reference decoded picture into the DPB + else { + const gboolean StoreInterViewOnlyRefFlag = + !GST_VAAPI_PICTURE_FLAG_IS_SET (picture, + GST_VAAPI_PICTURE_FLAG_AU_END) && + GST_VAAPI_PICTURE_FLAG_IS_SET (picture, + GST_VAAPI_PICTURE_FLAG_INTER_VIEW); + if (!picture->output_flag && !StoreInterViewOnlyRefFlag) + return TRUE; + while (priv->dpb_count == priv->dpb_size) { + GstVaapiPictureH264 *found_picture; + if (!StoreInterViewOnlyRefFlag) { + if (dpb_find_lowest_poc (decoder, picture, &found_picture) < 0 || + found_picture->base.poc > picture->base.poc) + return dpb_output (decoder, fs); + } + if (!dpb_bump (decoder, picture)) + return FALSE; + } + } + gst_vaapi_frame_store_replace (&priv->dpb[priv->dpb_count++], fs); + return TRUE; +} + +static gboolean +dpb_reset (GstVaapiDecoderH264 * decoder, guint dpb_size) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + + if (dpb_size > priv->dpb_size_max) { + priv->dpb = g_try_realloc_n (priv->dpb, dpb_size, sizeof (*priv->dpb)); + if (!priv->dpb) + return FALSE; + memset (&priv->dpb[priv->dpb_size_max], 0, + (dpb_size - priv->dpb_size_max) * sizeof (*priv->dpb)); + priv->dpb_size_max = dpb_size; + } + priv->dpb_size = dpb_size; + + GST_DEBUG ("DPB size %u", priv->dpb_size); + return TRUE; +} + +static void +unref_inter_view (GstVaapiPictureH264 * picture) +{ + if (!picture) + return; + GST_VAAPI_PICTURE_FLAG_UNSET (picture, GST_VAAPI_PICTURE_FLAG_INTER_VIEW); + gst_vaapi_picture_unref (picture); +} + +/* Resets MVC resources */ +static gboolean +mvc_reset (GstVaapiDecoderH264 * decoder) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + guint i; + + // Resize array of inter-view references + if (!priv->inter_views) { + priv->inter_views = g_ptr_array_new_full (priv->max_views, + (GDestroyNotify) unref_inter_view); + if (!priv->inter_views) + return FALSE; + } + // Resize array of previous frame buffers + for (i = priv->max_views; i < priv->prev_frames_alloc; i++) { + gst_vaapi_frame_store_replace (&priv->prev_ref_frames[i], NULL); + gst_vaapi_frame_store_replace (&priv->prev_frames[i], NULL); + } + + priv->prev_ref_frames = g_try_realloc_n (priv->prev_ref_frames, + priv->max_views, sizeof (*priv->prev_ref_frames)); + if (!priv->prev_ref_frames) + goto error_allocate; + + priv->prev_frames = g_try_realloc_n (priv->prev_frames, priv->max_views, + sizeof (*priv->prev_frames)); + if (!priv->prev_frames) + goto error_allocate; + + for (i = priv->prev_frames_alloc; i < priv->max_views; i++) { + priv->prev_ref_frames[i] = NULL; + priv->prev_frames[i] = NULL; + } + priv->prev_frames_alloc = priv->max_views; + return TRUE; + + /* ERRORS */ +error_allocate: + { + g_free (priv->prev_ref_frames); + priv->prev_ref_frames = NULL; + g_free (priv->prev_frames); + priv->prev_frames = NULL; + priv->prev_frames_alloc = 0; + return FALSE; + } +} + +static GstVaapiDecoderStatus +get_status (GstH264ParserResult result) +{ + GstVaapiDecoderStatus status; + + switch (result) { + case GST_H264_PARSER_OK: + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + break; + case GST_H264_PARSER_NO_NAL_END: + status = GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + break; + case GST_H264_PARSER_ERROR: + status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + break; + default: + status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + break; + } + return status; +} + +static void +gst_vaapi_decoder_h264_close (GstVaapiDecoderH264 * decoder) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + + gst_vaapi_picture_replace (&priv->current_picture, NULL); + gst_vaapi_parser_info_h264_replace (&priv->prev_slice_pi, NULL); + gst_vaapi_parser_info_h264_replace (&priv->prev_pi, NULL); + + dpb_clear (decoder, NULL); + + if (priv->inter_views) { + g_ptr_array_unref (priv->inter_views); + priv->inter_views = NULL; + } + + if (priv->parser) { + gst_h264_nal_parser_free (priv->parser); + priv->parser = NULL; + } +} + +static gboolean +gst_vaapi_decoder_h264_open (GstVaapiDecoderH264 * decoder) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + + gst_vaapi_decoder_h264_close (decoder); + + priv->parser = gst_h264_nal_parser_new (); + if (!priv->parser) + return FALSE; + return TRUE; +} + +static void +gst_vaapi_decoder_h264_destroy (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderH264 *const decoder = + GST_VAAPI_DECODER_H264_CAST (base_decoder); + GstVaapiDecoderH264Private *const priv = &decoder->priv; + guint i; + + gst_vaapi_decoder_h264_close (decoder); + priv->is_opened = FALSE; + + g_clear_pointer (&priv->dpb, g_free); + priv->dpb_size_max = priv->dpb_size = 0; + + g_clear_pointer (&priv->prev_ref_frames, g_free); + g_clear_pointer (&priv->prev_frames, g_free); + priv->prev_frames_alloc = 0; + + for (i = 0; i < G_N_ELEMENTS (priv->pps); i++) + gst_vaapi_parser_info_h264_replace (&priv->pps[i], NULL); + gst_vaapi_parser_info_h264_replace (&priv->active_pps, NULL); + + for (i = 0; i < G_N_ELEMENTS (priv->sps); i++) + gst_vaapi_parser_info_h264_replace (&priv->sps[i], NULL); + gst_vaapi_parser_info_h264_replace (&priv->active_sps, NULL); +} + +static gboolean +gst_vaapi_decoder_h264_create (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderH264 *const decoder = + GST_VAAPI_DECODER_H264_CAST (base_decoder); + GstVaapiDecoderH264Private *const priv = &decoder->priv; + + priv->profile = GST_VAAPI_PROFILE_UNKNOWN; + priv->entrypoint = GST_VAAPI_ENTRYPOINT_VLD; + priv->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420; + priv->prev_pic_structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME; + priv->progressive_sequence = TRUE; + priv->top_field_first = FALSE; + priv->stereo_info.mode = GST_VIDEO_MULTIVIEW_MODE_MONO; + priv->stereo_info.flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE; + return TRUE; +} + +/* Limited reset can just needs to get the decoder + * ready to process fresh data after a flush. + * Preserves the existing DPB allocation and any SPS/PPS */ +static GstVaapiDecoderStatus +gst_vaapi_decoder_h264_reset (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderH264 *const decoder = + GST_VAAPI_DECODER_H264_CAST (base_decoder); + GstVaapiDecoderH264Private *const priv = &decoder->priv; + + gst_vaapi_decoder_h264_close (decoder); + priv->is_opened = FALSE; + + priv->dpb_size = 0; + + g_clear_pointer (&priv->prev_ref_frames, g_free); + g_clear_pointer (&priv->prev_frames, g_free); + priv->prev_frames_alloc = 0; + gst_vaapi_parser_info_h264_replace (&priv->active_pps, NULL); + gst_vaapi_parser_info_h264_replace (&priv->active_sps, NULL); + + priv->profile = GST_VAAPI_PROFILE_UNKNOWN; + priv->entrypoint = GST_VAAPI_ENTRYPOINT_VLD; + priv->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420; + priv->prev_pic_structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME; + priv->progressive_sequence = TRUE; + priv->top_field_first = FALSE; + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +/* Activates the supplied PPS */ +static GstH264PPS * +ensure_pps (GstVaapiDecoderH264 * decoder, GstH264PPS * pps) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiParserInfoH264 *const pi = priv->pps[pps->id]; + + gst_vaapi_parser_info_h264_replace (&priv->active_pps, pi); + return pi ? &pi->data.pps : NULL; +} + +/* Returns the active PPS */ +static inline GstH264PPS * +get_pps (GstVaapiDecoderH264 * decoder) +{ + GstVaapiParserInfoH264 *const pi = decoder->priv.active_pps; + + return pi ? &pi->data.pps : NULL; +} + +/* Activate the supplied SPS */ +static GstH264SPS * +ensure_sps (GstVaapiDecoderH264 * decoder, GstH264SPS * sps) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiParserInfoH264 *const pi = priv->sps[sps->id]; + + /* Propagate "got I-frame" state to the next SPS unit if the + current sequence was not ended */ + if (pi && priv->active_sps) + pi->state |= (priv->active_sps->state & GST_H264_VIDEO_STATE_GOT_I_FRAME); + + gst_vaapi_parser_info_h264_replace (&priv->active_sps, pi); + return pi ? &pi->data.sps : NULL; +} + +/* Returns the active SPS */ +static inline GstH264SPS * +get_sps (GstVaapiDecoderH264 * decoder) +{ + GstVaapiParserInfoH264 *const pi = decoder->priv.active_sps; + + return pi ? &pi->data.sps : NULL; +} + +static void +fill_profiles (GstVaapiProfile profiles[16], guint * n_profiles_ptr, + GstVaapiProfile profile) +{ + guint n_profiles = *n_profiles_ptr; + + profiles[n_profiles++] = profile; + switch (profile) { + case GST_VAAPI_PROFILE_H264_MAIN: + profiles[n_profiles++] = GST_VAAPI_PROFILE_H264_HIGH; + break; + default: + break; + } + *n_profiles_ptr = n_profiles; +} + +/* Fills in compatible profiles for MVC decoding */ +static void +fill_profiles_mvc (GstVaapiDecoderH264 * decoder, GstVaapiProfile profiles[16], + guint * n_profiles_ptr, guint dpb_size) +{ + const gchar *const vendor_string = + gst_vaapi_display_get_vendor_string (GST_VAAPI_DECODER_DISPLAY (decoder)); + + gboolean add_high_profile = FALSE; + struct map + { + const gchar *str; + guint str_len; + }; + const struct map *m; + + // Drivers that support slice level decoding + if (vendor_string && dpb_size <= 16) { + static const struct map drv_names[] = { + {"Intel i965 driver", 17}, + {NULL, 0} + }; + for (m = drv_names; m->str != NULL && !add_high_profile; m++) { + if (g_ascii_strncasecmp (vendor_string, m->str, m->str_len) == 0) + add_high_profile = TRUE; + } + } + + if (add_high_profile) + fill_profiles (profiles, n_profiles_ptr, GST_VAAPI_PROFILE_H264_HIGH); +} + +static GstVaapiProfile +get_profile (GstVaapiDecoderH264 * decoder, GstH264SPS * sps, guint dpb_size) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiDisplay *const display = GST_VAAPI_DECODER_DISPLAY (decoder); + GstVaapiProfile profile, profiles[4]; + guint i, n_profiles = 0; + + profile = gst_vaapi_utils_h264_get_profile (sps->profile_idc); + if (!profile) + return GST_VAAPI_PROFILE_UNKNOWN; + + fill_profiles (profiles, &n_profiles, profile); + switch (profile) { + case GST_VAAPI_PROFILE_H264_BASELINE: + GST_INFO ("Baseline stream to be processed as Constrained-Baseline or " + "Main"); + fill_profiles (profiles, &n_profiles, + GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE); + fill_profiles (profiles, &n_profiles, GST_VAAPI_PROFILE_H264_MAIN); + break; + case GST_VAAPI_PROFILE_H264_EXTENDED: + if (sps->constraint_set1_flag) { // A.2.2 (main profile) + fill_profiles (profiles, &n_profiles, GST_VAAPI_PROFILE_H264_MAIN); + } + break; + case GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH: + if (priv->max_views == 2) { + fill_profiles (profiles, &n_profiles, + GST_VAAPI_PROFILE_H264_STEREO_HIGH); + } + fill_profiles_mvc (decoder, profiles, &n_profiles, dpb_size); + break; + case GST_VAAPI_PROFILE_H264_STEREO_HIGH: + if (sps->frame_mbs_only_flag) { + fill_profiles (profiles, &n_profiles, + GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH); + } + fill_profiles_mvc (decoder, profiles, &n_profiles, dpb_size); + break; + default: + break; + } + + /* If the preferred profile (profiles[0]) matches one that we already + found, then just return it now instead of searching for it again */ + if (profiles[0] == priv->profile) + return priv->profile; + + for (i = 0; i < n_profiles; i++) { + if (gst_vaapi_display_has_decoder (display, profiles[i], priv->entrypoint)) + return profiles[i]; + } + return GST_VAAPI_PROFILE_UNKNOWN; +} + +static GstVaapiDecoderStatus +ensure_context (GstVaapiDecoderH264 * decoder, GstH264SPS * sps) +{ + GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER_CAST (decoder); + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiContextInfo info; + GstVaapiProfile profile; + GstVaapiChromaType chroma_type; + gboolean reset_context = FALSE; + guint mb_width, mb_height, dpb_size, num_views; + + num_views = get_num_views (sps); + if (priv->max_views < num_views) { + priv->max_views = num_views; + reset_context = TRUE; + GST_DEBUG ("maximum number of views changed to %u", num_views); + } + + dpb_size = get_max_dec_frame_buffering (sps); + if (priv->dpb_size < dpb_size) { + GST_DEBUG ("DPB size increased"); + reset_context = TRUE; + } + + profile = get_profile (decoder, sps, dpb_size); + if (!profile) { + GST_ERROR ("unsupported profile_idc %u", sps->profile_idc); + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + } + + if (!priv->profile || (priv->profile != profile && priv->max_views == 1)) { + GST_DEBUG ("profile changed to %x", profile); + reset_context = TRUE; + priv->profile = profile; + } + + if (reset_context) { + switch (num_views) { + case 1: + /* Frame-packed mode details should be used if we got */ + if (priv->stereo_info.mode != GST_VIDEO_MULTIVIEW_MODE_NONE) { + gst_vaapi_decoder_set_multiview_mode (base_decoder, + 2, priv->stereo_info.mode, priv->stereo_info.flags); + } else { + gst_vaapi_decoder_set_multiview_mode (base_decoder, + num_views, GST_VIDEO_MULTIVIEW_MODE_NONE, + GST_VIDEO_MULTIVIEW_FLAGS_NONE); + } + break; + case 2: /* Assume stereo */ + if (profile == GST_VAAPI_PROFILE_H264_STEREO_HIGH) { + GST_DEBUG ("Stereo profile - frame-by-frame output, %d views", + num_views); + gst_vaapi_decoder_set_multiview_mode (base_decoder, num_views, + GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME, + GST_VIDEO_MULTIVIEW_FLAGS_NONE); + break; + } + /* non-stereo 2 views. Fall through */ + default: + GST_DEBUG ("Multiview profile - frame-by-frame output, %d views", + num_views); + gst_vaapi_decoder_set_multiview_mode (base_decoder, num_views, + GST_VIDEO_MULTIVIEW_MODE_MULTIVIEW_FRAME_BY_FRAME, + GST_VIDEO_MULTIVIEW_FLAGS_NONE); + break; + } + } + + chroma_type = gst_vaapi_utils_h264_get_chroma_type (sps->chroma_format_idc); + if (!chroma_type) { + GST_ERROR ("unsupported chroma_format_idc %u", sps->chroma_format_idc); + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT; + } + + if (priv->chroma_type != chroma_type) { + GST_DEBUG ("chroma format changed"); + reset_context = TRUE; + priv->chroma_type = chroma_type; + } + + mb_width = sps->pic_width_in_mbs_minus1 + 1; + mb_height = + (sps->pic_height_in_map_units_minus1 + 1) << !sps->frame_mbs_only_flag; + if (priv->mb_width != mb_width || priv->mb_height != mb_height) { + GST_DEBUG ("size changed"); + reset_context = TRUE; + priv->mb_width = mb_width; + priv->mb_height = mb_height; + } + + if (priv->progressive_sequence != sps->frame_mbs_only_flag) { + GST_DEBUG ("interlacing-mode changed"); + priv->progressive_sequence = sps->frame_mbs_only_flag; + gst_vaapi_decoder_set_interlaced (base_decoder, + !priv->progressive_sequence); + priv->top_field_first = FALSE; + } + + gst_vaapi_decoder_set_pixel_aspect_ratio (base_decoder, + sps->vui_parameters.par_n, sps->vui_parameters.par_d); + + if (!reset_context && priv->has_context) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + /* XXX: fix surface size when cropping is implemented */ + info.profile = priv->profile; + info.entrypoint = priv->entrypoint; + info.chroma_type = priv->chroma_type; + info.width = sps->width; + info.height = sps->height; + info.ref_frames = dpb_size; + + if (!gst_vaapi_decoder_ensure_context (GST_VAAPI_DECODER (decoder), &info)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + priv->has_context = TRUE; + + /* Reset DPB */ + if (!dpb_reset (decoder, dpb_size)) + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + + /* Reset MVC data */ + if (!mvc_reset (decoder)) + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static void +fill_iq_matrix_4x4 (VAIQMatrixBufferH264 * iq_matrix, const GstH264PPS * pps, + const GstH264SPS * sps) +{ + guint i; + + /* There are always 6 4x4 scaling lists */ + g_assert (G_N_ELEMENTS (iq_matrix->ScalingList4x4) == 6); + g_assert (G_N_ELEMENTS (iq_matrix->ScalingList4x4[0]) == 16); + + for (i = 0; i < G_N_ELEMENTS (iq_matrix->ScalingList4x4); i++) + gst_h264_quant_matrix_4x4_get_raster_from_zigzag (iq_matrix->ScalingList4x4 + [i], pps->scaling_lists_4x4[i]); +} + +static void +fill_iq_matrix_8x8 (VAIQMatrixBufferH264 * iq_matrix, const GstH264PPS * pps, + const GstH264SPS * sps) +{ + guint i, n; + + /* If chroma_format_idc != 3, there are up to 2 8x8 scaling lists */ + if (!pps->transform_8x8_mode_flag) + return; + + g_assert (G_N_ELEMENTS (iq_matrix->ScalingList8x8) >= 2); + g_assert (G_N_ELEMENTS (iq_matrix->ScalingList8x8[0]) == 64); + + n = (sps->chroma_format_idc != 3) ? 2 : 6; + for (i = 0; i < n; i++) { + gst_h264_quant_matrix_8x8_get_raster_from_zigzag (iq_matrix->ScalingList8x8 + [i], pps->scaling_lists_8x8[i]); + } +} + +static GstVaapiDecoderStatus +ensure_quant_matrix (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture) +{ + GstVaapiPicture *const base_picture = &picture->base; + GstH264PPS *const pps = get_pps (decoder); + GstH264SPS *const sps = get_sps (decoder); + VAIQMatrixBufferH264 *iq_matrix; + + base_picture->iq_matrix = GST_VAAPI_IQ_MATRIX_NEW (H264, decoder); + if (!base_picture->iq_matrix) { + GST_ERROR ("failed to allocate IQ matrix"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + iq_matrix = base_picture->iq_matrix->param; + + /* XXX: we can only support 4:2:0 or 4:2:2 since ScalingLists8x8[] + is not large enough to hold lists for 4:4:4 */ + if (sps->chroma_format_idc == 3) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT; + + fill_iq_matrix_4x4 (iq_matrix, pps, sps); + fill_iq_matrix_8x8 (iq_matrix, pps, sps); + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static inline gboolean +is_valid_state (guint state, guint ref_state) +{ + return (state & ref_state) == ref_state; +} + +static GstVaapiDecoderStatus +decode_current_picture (GstVaapiDecoderH264 * decoder) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiParserInfoH264 *const sps_pi = decoder->priv.active_sps; + GstVaapiPictureH264 *const picture = priv->current_picture; + + if (!is_valid_state (priv->decoder_state, GST_H264_VIDEO_STATE_VALID_PICTURE)) + goto drop_frame; + + priv->decoder_state |= sps_pi->state; + if (!(priv->decoder_state & GST_H264_VIDEO_STATE_GOT_I_FRAME)) { + if (priv->decoder_state & GST_H264_VIDEO_STATE_GOT_P_SLICE) + goto drop_frame; + sps_pi->state |= GST_H264_VIDEO_STATE_GOT_I_FRAME; + } + + priv->decoder_state = 0; + priv->pic_structure = GST_H264_SEI_PIC_STRUCT_FRAME; + + if (!picture) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + if (!gst_vaapi_picture_decode (GST_VAAPI_PICTURE_CAST (picture))) + goto error; + if (!exec_ref_pic_marking (decoder, picture)) + goto error; + if (!dpb_add (decoder, picture)) + goto error; + + if (priv->force_low_latency) + dpb_output_ready_frames (decoder); + gst_vaapi_picture_replace (&priv->current_picture, NULL); + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + /* ERRORS */ +error: + { + /* XXX: fix for cases where first field failed to be decoded */ + gst_vaapi_picture_replace (&priv->current_picture, NULL); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + +drop_frame: + { + priv->decoder_state = 0; + priv->pic_structure = GST_H264_SEI_PIC_STRUCT_FRAME; + return (GstVaapiDecoderStatus) GST_VAAPI_DECODER_STATUS_DROP_FRAME; + } +} + +static GstVaapiDecoderStatus +parse_sps (GstVaapiDecoderH264 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiParserInfoH264 *const pi = unit->parsed_info; + GstH264SPS *const sps = &pi->data.sps; + GstH264ParserResult result; + + GST_DEBUG ("parse SPS"); + + priv->parser_state = 0; + + /* Variables that don't have inferred values per the H.264 + standard but that should get a default value anyway */ + sps->log2_max_pic_order_cnt_lsb_minus4 = 0; + + result = gst_h264_parser_parse_sps (priv->parser, &pi->nalu, sps); + if (result != GST_H264_PARSER_OK) + return get_status (result); + + priv->parser_state |= GST_H264_VIDEO_STATE_GOT_SPS; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +parse_subset_sps (GstVaapiDecoderH264 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiParserInfoH264 *const pi = unit->parsed_info; + GstH264SPS *const sps = &pi->data.sps; + GstH264ParserResult result; + + GST_DEBUG ("parse subset SPS"); + + /* Variables that don't have inferred values per the H.264 + standard but that should get a default value anyway */ + sps->log2_max_pic_order_cnt_lsb_minus4 = 0; + + result = gst_h264_parser_parse_subset_sps (priv->parser, &pi->nalu, sps); + if (result != GST_H264_PARSER_OK) + return get_status (result); + + priv->parser_state |= GST_H264_VIDEO_STATE_GOT_SPS; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +parse_pps (GstVaapiDecoderH264 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiParserInfoH264 *const pi = unit->parsed_info; + GstH264PPS *const pps = &pi->data.pps; + GstH264ParserResult result; + + GST_DEBUG ("parse PPS"); + + /* Variables that don't have inferred values per the H.264 + standard but that should get a default value anyway */ + pps->slice_group_map_type = 0; + pps->slice_group_change_rate_minus1 = 0; + pps->slice_group_id = NULL; + + result = gst_h264_parser_parse_pps (priv->parser, &pi->nalu, pps); + + /* PPS's sps id might be an ignored subset sps in SVC streams */ + if (priv->base_only && result == GST_H264_PARSER_BROKEN_LINK) { + pi->nalu.valid = FALSE; + return GST_VAAPI_DECODER_STATUS_SUCCESS; + } + + priv->parser_state &= GST_H264_VIDEO_STATE_GOT_SPS; + + if (result != GST_H264_PARSER_OK) + return get_status (result); + + priv->parser_state |= GST_H264_VIDEO_STATE_GOT_PPS; + + if (pps->num_slice_groups_minus1 > 0) { + GST_FIXME ("FMO is not supported"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +parse_sei (GstVaapiDecoderH264 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiParserInfoH264 *const pi = unit->parsed_info; + GArray **const sei_ptr = &pi->data.sei; + GstH264ParserResult result; + + GST_DEBUG ("parse SEI"); + + result = gst_h264_parser_parse_sei (priv->parser, &pi->nalu, sei_ptr); + if (result != GST_H264_PARSER_OK) { + GST_WARNING ("failed to parse SEI messages"); + return get_status (result); + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +parse_slice (GstVaapiDecoderH264 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiParserInfoH264 *const pi = unit->parsed_info; + GstH264SliceHdr *const slice_hdr = &pi->data.slice_hdr; + GstH264NalUnit *const nalu = &pi->nalu; + GstH264SPS *sps; + GstH264ParserResult result; + + GST_DEBUG ("parse slice"); + + priv->parser_state &= (GST_H264_VIDEO_STATE_GOT_SPS | + GST_H264_VIDEO_STATE_GOT_PPS); + + /* Propagate Prefix NAL unit info, if necessary */ + switch (nalu->type) { + case GST_H264_NAL_SLICE: + case GST_H264_NAL_SLICE_IDR:{ + GstVaapiParserInfoH264 *const prev_pi = priv->prev_pi; + if (prev_pi && prev_pi->nalu.type == GST_H264_NAL_PREFIX_UNIT) { + /* MVC sequences shall have a Prefix NAL unit immediately + preceding this NAL unit */ + pi->nalu.extension_type = prev_pi->nalu.extension_type; + pi->nalu.extension = prev_pi->nalu.extension; + } else { + /* In the very unlikely case there is no Prefix NAL unit + immediately preceding this NAL unit, try to infer some + defaults (H.7.4.1.1) */ + GstH264NalUnitExtensionMVC *const mvc = &pi->nalu.extension.mvc; + mvc->non_idr_flag = !(nalu->type == GST_H264_NAL_SLICE_IDR); + nalu->idr_pic_flag = !mvc->non_idr_flag; + mvc->priority_id = 0; + mvc->view_id = 0; + mvc->temporal_id = 0; + mvc->anchor_pic_flag = 0; + mvc->inter_view_flag = 1; + } + break; + } + } + + /* Variables that don't have inferred values per the H.264 + standard but that should get a default value anyway */ + slice_hdr->cabac_init_idc = 0; + slice_hdr->direct_spatial_mv_pred_flag = 0; + + result = gst_h264_parser_parse_slice_hdr (priv->parser, &pi->nalu, + slice_hdr, TRUE, TRUE); + if (result != GST_H264_PARSER_OK) + return get_status (result); + + sps = slice_hdr->pps->sequence; + + /* Update MVC data */ + pi->view_id = get_view_id (&pi->nalu); + pi->voc = get_view_order_index (sps, pi->view_id); + + priv->parser_state |= GST_H264_VIDEO_STATE_GOT_SLICE; + if (!GST_H264_IS_I_SLICE (slice_hdr)) + priv->parser_state |= GST_H264_VIDEO_STATE_GOT_P_SLICE; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_sps (GstVaapiDecoderH264 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiParserInfoH264 *const pi = unit->parsed_info; + GstH264SPS *const sps = &pi->data.sps; + + GST_DEBUG ("decode SPS"); + + gst_vaapi_parser_info_h264_replace (&priv->sps[sps->id], pi); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_subset_sps (GstVaapiDecoderH264 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiParserInfoH264 *const pi = unit->parsed_info; + GstH264SPS *const sps = &pi->data.sps; + + GST_DEBUG ("decode subset SPS"); + + gst_vaapi_parser_info_h264_replace (&priv->sps[sps->id], pi); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_pps (GstVaapiDecoderH264 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiParserInfoH264 *const pi = unit->parsed_info; + GstH264PPS *const pps = &pi->data.pps; + + GST_DEBUG ("decode PPS"); + + gst_vaapi_parser_info_h264_replace (&priv->pps[pps->id], pi); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static gboolean +decode_sei_frame_packing (GstVaapiDecoderH264 * decoder, + const GstH264FramePacking * frame_packing) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVideoMultiviewMode saved_mode = priv->stereo_info.mode; + GstVideoMultiviewFlags saved_flags = priv->stereo_info.flags; + gboolean left = TRUE; + gboolean frame_revert = FALSE; + + /* Only IDs from 0->255 and 512->2^31-1 are valid. Ignore others */ + if ((frame_packing->frame_packing_id >= 256 && + frame_packing->frame_packing_id < 512) || + (frame_packing->frame_packing_id >= (1U << 31))) + return FALSE; + + if (frame_packing->frame_packing_cancel_flag) { + if (priv->stereo_info.id == frame_packing->frame_packing_id) + priv->stereo_info = (GstVaapiStereo3DInfo) { + GST_VIDEO_MULTIVIEW_MODE_MONO, GST_VIDEO_MULTIVIEW_FLAGS_NONE, 256, 0}; + return TRUE; + } + + if (frame_packing->frame_packing_repetition_period != 1) { + GST_WARNING ("SEI: repetition_period != 1 is not unsupported"); + return FALSE; + } + + if (frame_packing->frame_packing_type > GST_H264_FRAME_PACKING_NONE) { + GST_WARNING ("SEI: unsupported frame_packing_type %d", + frame_packing->frame_packing_type); + return FALSE; + } + + if (frame_packing->content_interpretation_type >= 3) { + GST_WARNING ("SEI: unsupported content_interpretation_type %d", + frame_packing->frame_packing_type); + return FALSE; + } + + /* TODO: frame frame0/1_grid_position_x/y are ignored now. */ + + priv->stereo_info = (GstVaapiStereo3DInfo) { + GST_VIDEO_MULTIVIEW_MODE_MONO, GST_VIDEO_MULTIVIEW_FLAGS_NONE, 256, 0}; + + switch (frame_packing->frame_packing_type) { + case GST_H264_FRAME_PACKING_CHECKERBOARD_INTERLEAVING: + priv->stereo_info.mode = GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD; + break; + case GST_H264_FRAME_PACKING_COLUMN_INTERLEAVING: + priv->stereo_info.mode = GST_VIDEO_MULTIVIEW_MODE_COLUMN_INTERLEAVED; + break; + case GST_H264_FRAME_PACKING_ROW_INTERLEAVING: + priv->stereo_info.mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED; + break; + case GST_H264_FRAME_PACKING_SIDE_BY_SIDE: + if (frame_packing->quincunx_sampling_flag) { + priv->stereo_info.mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE_QUINCUNX; + } else { + priv->stereo_info.mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE; + } + break; + case GST_H264_FRMAE_PACKING_TOP_BOTTOM: + priv->stereo_info.mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM; + break; + case GST_H264_FRAME_PACKING_TEMPORAL_INTERLEAVING: + priv->stereo_info.mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME; + break; + default: + priv->stereo_info.mode = GST_VIDEO_MULTIVIEW_MODE_MONO; + break; + } + + /* Spec does not describe multi-IDs case, we just keep one valid */ + priv->stereo_info.id = frame_packing->frame_packing_id; + priv->stereo_info.repetition_period = + frame_packing->frame_packing_repetition_period; + + if (frame_packing->content_interpretation_type == 2) + frame_revert = TRUE; + + if (frame_packing->frame_packing_type == + GST_H264_FRAME_PACKING_TEMPORAL_INTERLEAVING) { + if (frame_packing->current_frame_is_frame0_flag) { + left = TRUE; + } else { + left = FALSE; + } + + if (frame_revert) + left = !left; + } + + if (!left) + priv->stereo_info.flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST; + + if (frame_packing->frame_packing_type == GST_H264_FRAME_PACKING_SIDE_BY_SIDE + && frame_packing->spatial_flipping_flag) { + if (frame_packing->frame0_flipped_flag != + ((priv->stereo_info.flags & + GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST) != 0)) { + priv->stereo_info.flags |= GST_VIDEO_MULTIVIEW_FLAGS_LEFT_FLOPPED; + } else { + priv->stereo_info.flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_FLOPPED; + } + } + if (frame_packing->frame_packing_type == GST_H264_FRMAE_PACKING_TOP_BOTTOM + && frame_packing->spatial_flipping_flag != + ((priv->stereo_info.flags & + GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST) != 0)) { + if (frame_packing->frame0_flipped_flag) { + priv->stereo_info.flags |= GST_VIDEO_MULTIVIEW_FLAGS_LEFT_FLIPPED; + } else { + priv->stereo_info.flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_FLIPPED; + } + } + + if (saved_mode != priv->stereo_info.mode + || saved_flags != priv->stereo_info.flags) { + gst_vaapi_decoder_set_multiview_mode (GST_VAAPI_DECODER_CAST (decoder), + 2, priv->stereo_info.mode, priv->stereo_info.flags); + } + + return TRUE; +} + +static GstVaapiDecoderStatus +decode_sei (GstVaapiDecoderH264 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiParserInfoH264 *const pi = unit->parsed_info; + guint i; + + GST_DEBUG ("decode SEI messages"); + + for (i = 0; i < pi->data.sei->len; i++) { + const GstH264SEIMessage *const sei = + &g_array_index (pi->data.sei, GstH264SEIMessage, i); + + switch (sei->payloadType) { + case GST_H264_SEI_PIC_TIMING:{ + const GstH264PicTiming *const pic_timing = &sei->payload.pic_timing; + if (pic_timing->pic_struct_present_flag) + priv->pic_structure = pic_timing->pic_struct; + break; + } + case GST_H264_SEI_FRAME_PACKING: + decode_sei_frame_packing (decoder, &sei->payload.frame_packing); + break; + default: + break; + } + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_sequence_end (GstVaapiDecoderH264 * decoder) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiParserInfoH264 *const sps_pi = decoder->priv.active_sps; + + GST_DEBUG ("decode sequence-end"); + + /* Sequence ended, don't try to propagate "got I-frame" state + beyond this point */ + if (sps_pi) + sps_pi->state &= ~GST_H264_VIDEO_STATE_GOT_I_FRAME; + + dpb_flush (decoder, NULL); + + /* Reset defaults, should there be a new sequence available next */ + priv->max_views = 1; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +/* 8.2.1.1 - Decoding process for picture order count type 0 */ +static void +init_picture_poc_0 (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture, GstH264SliceHdr * slice_hdr) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstH264SPS *const sps = get_sps (decoder); + const gint32 MaxPicOrderCntLsb = + 1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4); + gint32 temp_poc; + + GST_DEBUG ("decode picture order count type 0"); + + if (GST_VAAPI_PICTURE_IS_IDR (picture)) { + priv->prev_poc_msb = 0; + priv->prev_poc_lsb = 0; + } else if (priv->prev_pic_has_mmco5) { + priv->prev_poc_msb = 0; + priv->prev_poc_lsb = + (priv->prev_pic_structure == GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD ? + 0 : priv->field_poc[TOP_FIELD]); + } else { + priv->prev_poc_msb = priv->poc_msb; + priv->prev_poc_lsb = priv->poc_lsb; + } + + // (8-3) + priv->poc_lsb = slice_hdr->pic_order_cnt_lsb; + if (priv->poc_lsb < priv->prev_poc_lsb && + (priv->prev_poc_lsb - priv->poc_lsb) >= (MaxPicOrderCntLsb / 2)) + priv->poc_msb = priv->prev_poc_msb + MaxPicOrderCntLsb; + else if (priv->poc_lsb > priv->prev_poc_lsb && + (priv->poc_lsb - priv->prev_poc_lsb) > (MaxPicOrderCntLsb / 2)) + priv->poc_msb = priv->prev_poc_msb - MaxPicOrderCntLsb; + else + priv->poc_msb = priv->prev_poc_msb; + + temp_poc = priv->poc_msb + priv->poc_lsb; + switch (picture->structure) { + case GST_VAAPI_PICTURE_STRUCTURE_FRAME: + // (8-4, 8-5) + priv->field_poc[TOP_FIELD] = temp_poc; + priv->field_poc[BOTTOM_FIELD] = temp_poc + + slice_hdr->delta_pic_order_cnt_bottom; + break; + case GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD: + // (8-4) + priv->field_poc[TOP_FIELD] = temp_poc; + break; + case GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD: + // (8-5) + priv->field_poc[BOTTOM_FIELD] = temp_poc; + break; + } +} + +/* 8.2.1.2 - Decoding process for picture order count type 1 */ +static void +init_picture_poc_1 (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture, GstH264SliceHdr * slice_hdr) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstH264SPS *const sps = get_sps (decoder); + const gint32 MaxFrameNum = 1 << (sps->log2_max_frame_num_minus4 + 4); + gint32 prev_frame_num_offset, abs_frame_num, expected_poc; + guint i; + + GST_DEBUG ("decode picture order count type 1"); + + if (priv->prev_pic_has_mmco5) + prev_frame_num_offset = 0; + else + prev_frame_num_offset = priv->frame_num_offset; + + // (8-6) + if (GST_VAAPI_PICTURE_IS_IDR (picture)) + priv->frame_num_offset = 0; + else if (priv->prev_frame_num > priv->frame_num) + priv->frame_num_offset = prev_frame_num_offset + MaxFrameNum; + else + priv->frame_num_offset = prev_frame_num_offset; + + // (8-7) + if (sps->num_ref_frames_in_pic_order_cnt_cycle != 0) + abs_frame_num = priv->frame_num_offset + priv->frame_num; + else + abs_frame_num = 0; + if (!GST_VAAPI_PICTURE_IS_REFERENCE (picture) && abs_frame_num > 0) + abs_frame_num = abs_frame_num - 1; + + if (abs_frame_num > 0) { + gint32 expected_delta_per_poc_cycle; + gint32 poc_cycle_cnt, frame_num_in_poc_cycle; + + expected_delta_per_poc_cycle = 0; + for (i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; i++) + expected_delta_per_poc_cycle += sps->offset_for_ref_frame[i]; + + // (8-8) + poc_cycle_cnt = (abs_frame_num - 1) / + sps->num_ref_frames_in_pic_order_cnt_cycle; + frame_num_in_poc_cycle = (abs_frame_num - 1) % + sps->num_ref_frames_in_pic_order_cnt_cycle; + + // (8-9) + expected_poc = poc_cycle_cnt * expected_delta_per_poc_cycle; + for (i = 0; i <= frame_num_in_poc_cycle; i++) + expected_poc += sps->offset_for_ref_frame[i]; + } else + expected_poc = 0; + if (!GST_VAAPI_PICTURE_IS_REFERENCE (picture)) + expected_poc += sps->offset_for_non_ref_pic; + + // (8-10) + switch (picture->structure) { + case GST_VAAPI_PICTURE_STRUCTURE_FRAME: + priv->field_poc[TOP_FIELD] = expected_poc + + slice_hdr->delta_pic_order_cnt[0]; + priv->field_poc[BOTTOM_FIELD] = priv->field_poc[TOP_FIELD] + + sps->offset_for_top_to_bottom_field + + slice_hdr->delta_pic_order_cnt[1]; + break; + case GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD: + priv->field_poc[TOP_FIELD] = expected_poc + + slice_hdr->delta_pic_order_cnt[0]; + break; + case GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD: + priv->field_poc[BOTTOM_FIELD] = expected_poc + + sps->offset_for_top_to_bottom_field + + slice_hdr->delta_pic_order_cnt[0]; + break; + } +} + +/* 8.2.1.3 - Decoding process for picture order count type 2 */ +static void +init_picture_poc_2 (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture, GstH264SliceHdr * slice_hdr) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstH264SPS *const sps = get_sps (decoder); + const gint32 MaxFrameNum = 1 << (sps->log2_max_frame_num_minus4 + 4); + gint32 prev_frame_num_offset, temp_poc; + + GST_DEBUG ("decode picture order count type 2"); + + if (priv->prev_pic_has_mmco5) + prev_frame_num_offset = 0; + else + prev_frame_num_offset = priv->frame_num_offset; + + // (8-11) + if (GST_VAAPI_PICTURE_IS_IDR (picture)) + priv->frame_num_offset = 0; + else if (priv->prev_frame_num > priv->frame_num) + priv->frame_num_offset = prev_frame_num_offset + MaxFrameNum; + else + priv->frame_num_offset = prev_frame_num_offset; + + // (8-12) + if (GST_VAAPI_PICTURE_IS_IDR (picture)) + temp_poc = 0; + else if (!GST_VAAPI_PICTURE_IS_REFERENCE (picture)) + temp_poc = 2 * (priv->frame_num_offset + priv->frame_num) - 1; + else + temp_poc = 2 * (priv->frame_num_offset + priv->frame_num); + + // (8-13) + if (picture->structure != GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD) + priv->field_poc[TOP_FIELD] = temp_poc; + if (picture->structure != GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD) + priv->field_poc[BOTTOM_FIELD] = temp_poc; +} + +/* 8.2.1 - Decoding process for picture order count */ +static void +init_picture_poc (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture, GstH264SliceHdr * slice_hdr) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstH264SPS *const sps = get_sps (decoder); + + switch (sps->pic_order_cnt_type) { + case 0: + init_picture_poc_0 (decoder, picture, slice_hdr); + break; + case 1: + init_picture_poc_1 (decoder, picture, slice_hdr); + break; + case 2: + init_picture_poc_2 (decoder, picture, slice_hdr); + break; + } + + if (picture->structure != GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD) + picture->field_poc[TOP_FIELD] = priv->field_poc[TOP_FIELD]; + if (picture->structure != GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD) + picture->field_poc[BOTTOM_FIELD] = priv->field_poc[BOTTOM_FIELD]; + picture->base.poc = MIN (picture->field_poc[0], picture->field_poc[1]); +} + +static int +compare_picture_pic_num_dec (const void *a, const void *b) +{ + const GstVaapiPictureH264 *const picA = *(GstVaapiPictureH264 **) a; + const GstVaapiPictureH264 *const picB = *(GstVaapiPictureH264 **) b; + + return picB->pic_num - picA->pic_num; +} + +static int +compare_picture_long_term_pic_num_inc (const void *a, const void *b) +{ + const GstVaapiPictureH264 *const picA = *(GstVaapiPictureH264 **) a; + const GstVaapiPictureH264 *const picB = *(GstVaapiPictureH264 **) b; + + return picA->long_term_pic_num - picB->long_term_pic_num; +} + +static int +compare_picture_poc_dec (const void *a, const void *b) +{ + const GstVaapiPictureH264 *const picA = *(GstVaapiPictureH264 **) a; + const GstVaapiPictureH264 *const picB = *(GstVaapiPictureH264 **) b; + + return picB->base.poc - picA->base.poc; +} + +static int +compare_picture_poc_inc (const void *a, const void *b) +{ + const GstVaapiPictureH264 *const picA = *(GstVaapiPictureH264 **) a; + const GstVaapiPictureH264 *const picB = *(GstVaapiPictureH264 **) b; + + return picA->base.poc - picB->base.poc; +} + +static int +compare_picture_frame_num_wrap_dec (const void *a, const void *b) +{ + const GstVaapiPictureH264 *const picA = *(GstVaapiPictureH264 **) a; + const GstVaapiPictureH264 *const picB = *(GstVaapiPictureH264 **) b; + + return picB->frame_num_wrap - picA->frame_num_wrap; +} + +static int +compare_picture_long_term_frame_idx_inc (const void *a, const void *b) +{ + const GstVaapiPictureH264 *const picA = *(GstVaapiPictureH264 **) a; + const GstVaapiPictureH264 *const picB = *(GstVaapiPictureH264 **) b; + + return picA->long_term_frame_idx - picB->long_term_frame_idx; +} + +/* 8.2.4.1 - Decoding process for picture numbers */ +static void +init_picture_refs_pic_num (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture, GstH264SliceHdr * slice_hdr) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstH264SPS *const sps = get_sps (decoder); + const gint32 MaxFrameNum = 1 << (sps->log2_max_frame_num_minus4 + 4); + guint i; + + GST_DEBUG ("decode picture numbers"); + + for (i = 0; i < priv->short_ref_count; i++) { + GstVaapiPictureH264 *const pic = priv->short_ref[i]; + + // (H.8.2) + if (pic->base.view_id != picture->base.view_id) + continue; + + // (8-27) + if (pic->frame_num > priv->frame_num) + pic->frame_num_wrap = pic->frame_num - MaxFrameNum; + else + pic->frame_num_wrap = pic->frame_num; + + // (8-28, 8-30, 8-31) + if (GST_VAAPI_PICTURE_IS_FRAME (picture)) + pic->pic_num = pic->frame_num_wrap; + else { + if (pic->structure == picture->structure) + pic->pic_num = 2 * pic->frame_num_wrap + 1; + else + pic->pic_num = 2 * pic->frame_num_wrap; + } + } + + for (i = 0; i < priv->long_ref_count; i++) { + GstVaapiPictureH264 *const pic = priv->long_ref[i]; + + // (H.8.2) + if (pic->base.view_id != picture->base.view_id) + continue; + + // (8-29, 8-32, 8-33) + if (GST_VAAPI_PICTURE_IS_FRAME (picture)) + pic->long_term_pic_num = pic->long_term_frame_idx; + else { + if (pic->structure == picture->structure) + pic->long_term_pic_num = 2 * pic->long_term_frame_idx + 1; + else + pic->long_term_pic_num = 2 * pic->long_term_frame_idx; + } + } +} + +#define SORT_REF_LIST(list, n, compare_func) \ + qsort(list, n, sizeof(*(list)), compare_picture_##compare_func) + +static void +init_picture_refs_fields_1 (guint picture_structure, + GstVaapiPictureH264 * RefPicList[32], + guint * RefPicList_count, + GstVaapiPictureH264 * ref_list[32], guint ref_list_count) +{ + guint i, j, n; + + i = 0; + j = 0; + n = *RefPicList_count; + do { + g_assert (n < 32); + for (; i < ref_list_count; i++) { + if (ref_list[i]->structure == picture_structure) { + RefPicList[n++] = ref_list[i++]; + break; + } + } + for (; j < ref_list_count; j++) { + if (ref_list[j]->structure != picture_structure) { + RefPicList[n++] = ref_list[j++]; + break; + } + } + } while (i < ref_list_count || j < ref_list_count); + *RefPicList_count = n; +} + +static inline void +init_picture_refs_fields (GstVaapiPictureH264 * picture, + GstVaapiPictureH264 * RefPicList[32], + guint * RefPicList_count, + GstVaapiPictureH264 * short_ref[32], + guint short_ref_count, + GstVaapiPictureH264 * long_ref[32], guint long_ref_count) +{ + guint n = 0; + + /* 8.2.4.2.5 - reference picture lists in fields */ + init_picture_refs_fields_1 (picture->structure, RefPicList, &n, + short_ref, short_ref_count); + init_picture_refs_fields_1 (picture->structure, RefPicList, &n, + long_ref, long_ref_count); + *RefPicList_count = n; +} + +/* Finds the inter-view reference picture with the supplied view id */ +static GstVaapiPictureH264 * +find_inter_view_reference (GstVaapiDecoderH264 * decoder, guint16 view_id) +{ + GPtrArray *const inter_views = decoder->priv.inter_views; + guint i; + + for (i = 0; i < inter_views->len; i++) { + GstVaapiPictureH264 *const picture = g_ptr_array_index (inter_views, i); + if (picture->base.view_id == view_id) + return picture; + } + + GST_WARNING ("failed to find inter-view reference picture for view_id: %d", + view_id); + return NULL; +} + +/* Checks whether the view id exists in the supplied list of view ids */ +static gboolean +find_view_id (guint16 view_id, const guint16 * view_ids, guint num_view_ids) +{ + guint i; + + for (i = 0; i < num_view_ids; i++) { + if (view_ids[i] == view_id) + return TRUE; + } + return FALSE; +} + +static gboolean +find_view_id_in_view (guint16 view_id, const GstH264SPSExtMVCView * view, + gboolean is_anchor) +{ + if (is_anchor) + return (find_view_id (view_id, view->anchor_ref_l0, + view->num_anchor_refs_l0) || + find_view_id (view_id, view->anchor_ref_l1, view->num_anchor_refs_l1)); + + return (find_view_id (view_id, view->non_anchor_ref_l0, + view->num_non_anchor_refs_l0) || + find_view_id (view_id, view->non_anchor_ref_l1, + view->num_non_anchor_refs_l1)); +} + +/* Checks whether the inter-view reference picture with the supplied + view id is used for decoding the current view component picture */ +static gboolean +is_inter_view_reference_for_picture (GstVaapiDecoderH264 * decoder, + guint16 view_id, GstVaapiPictureH264 * picture) +{ + const GstH264SPS *const sps = get_sps (decoder); + gboolean is_anchor; + + if (!GST_VAAPI_PICTURE_IS_MVC (picture) || + sps->extension_type != GST_H264_NAL_EXTENSION_MVC) + return FALSE; + + is_anchor = GST_VAAPI_PICTURE_IS_ANCHOR (picture); + return find_view_id_in_view (view_id, + &sps->extension.mvc.view[picture->base.voc], is_anchor); +} + +/* Checks whether the supplied inter-view reference picture is used + for decoding the next view component pictures */ +static gboolean +is_inter_view_reference_for_next_pictures (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture) +{ + const GstH264SPS *const sps = get_sps (decoder); + gboolean is_anchor; + guint i, num_views; + + if (!GST_VAAPI_PICTURE_IS_MVC (picture) || + sps->extension_type != GST_H264_NAL_EXTENSION_MVC) + return FALSE; + + is_anchor = GST_VAAPI_PICTURE_IS_ANCHOR (picture); + num_views = sps->extension.mvc.num_views_minus1 + 1; + for (i = picture->base.voc + 1; i < num_views; i++) { + const GstH264SPSExtMVCView *const view = &sps->extension.mvc.view[i]; + if (find_view_id_in_view (picture->base.view_id, view, is_anchor)) + return TRUE; + } + return FALSE; +} + +/* H.8.2.1 - Initialization process for inter-view prediction references */ +static gboolean +init_picture_refs_mvc_1 (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 ** ref_list, guint * ref_list_count_ptr, guint num_refs, + const guint16 * view_ids, guint num_view_ids) +{ + guint j, n; + + n = *ref_list_count_ptr; + for (j = 0; j < num_view_ids && n < num_refs; j++) { + GstVaapiPictureH264 *pic; + + if (!(pic = find_inter_view_reference (decoder, view_ids[j]))) + return FALSE; + + ref_list[n++] = pic; + } + + *ref_list_count_ptr = n; + + return TRUE; +} + +static inline gboolean +init_picture_refs_mvc (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture, GstH264SliceHdr * slice_hdr, guint list) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + const GstH264SPS *const sps = get_sps (decoder); + const GstH264SPSExtMVCView *view; + gboolean ret = TRUE; + + GST_DEBUG ("initialize reference picture list for inter-view prediction"); + + if (sps->extension_type != GST_H264_NAL_EXTENSION_MVC) + return TRUE; + view = &sps->extension.mvc.view[picture->base.voc]; + +#define INVOKE_INIT_PICTURE_REFS_MVC(ref_list, view_list) do { \ + ret = init_picture_refs_mvc_1(decoder, \ + priv->RefPicList##ref_list, \ + &priv->RefPicList##ref_list##_count, \ + slice_hdr->num_ref_idx_l##ref_list##_active_minus1 + 1, \ + view->view_list##_l##ref_list, \ + view->num_##view_list##s_l##ref_list); \ + } while (0) + + if (list == 0) { + if (GST_VAAPI_PICTURE_IS_ANCHOR (picture)) + INVOKE_INIT_PICTURE_REFS_MVC (0, anchor_ref); + else + INVOKE_INIT_PICTURE_REFS_MVC (0, non_anchor_ref); + } else { + if (GST_VAAPI_PICTURE_IS_ANCHOR (picture)) + INVOKE_INIT_PICTURE_REFS_MVC (1, anchor_ref); + else + INVOKE_INIT_PICTURE_REFS_MVC (1, non_anchor_ref); + } + + return ret; + +#undef INVOKE_INIT_PICTURE_REFS_MVC +} + +static gboolean +init_picture_refs_p_slice (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture, GstH264SliceHdr * slice_hdr) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiPictureH264 **ref_list; + guint i; + gboolean ret = TRUE; + + GST_DEBUG ("decode reference picture list for P and SP slices"); + + if (GST_VAAPI_PICTURE_IS_FRAME (picture)) { + /* 8.2.4.2.1 - P and SP slices in frames */ + if (priv->short_ref_count > 0) { + ref_list = priv->RefPicList0; + for (i = 0; i < priv->short_ref_count; i++) + ref_list[i] = priv->short_ref[i]; + SORT_REF_LIST (ref_list, i, pic_num_dec); + priv->RefPicList0_count += i; + } + + if (priv->long_ref_count > 0) { + ref_list = &priv->RefPicList0[priv->RefPicList0_count]; + for (i = 0; i < priv->long_ref_count; i++) + ref_list[i] = priv->long_ref[i]; + SORT_REF_LIST (ref_list, i, long_term_pic_num_inc); + priv->RefPicList0_count += i; + } + } else { + /* 8.2.4.2.2 - P and SP slices in fields */ + GstVaapiPictureH264 *short_ref[32]; + guint short_ref_count = 0; + GstVaapiPictureH264 *long_ref[32]; + guint long_ref_count = 0; + + if (priv->short_ref_count > 0) { + for (i = 0; i < priv->short_ref_count; i++) + short_ref[i] = priv->short_ref[i]; + SORT_REF_LIST (short_ref, i, frame_num_wrap_dec); + short_ref_count = i; + } + + if (priv->long_ref_count > 0) { + for (i = 0; i < priv->long_ref_count; i++) + long_ref[i] = priv->long_ref[i]; + SORT_REF_LIST (long_ref, i, long_term_frame_idx_inc); + long_ref_count = i; + } + + init_picture_refs_fields (picture, + priv->RefPicList0, &priv->RefPicList0_count, + short_ref, short_ref_count, long_ref, long_ref_count); + } + + if (GST_VAAPI_PICTURE_IS_MVC (picture)) { + /* RefPicList0 */ + ret = init_picture_refs_mvc (decoder, picture, slice_hdr, 0); + } + + return ret; +} + +static gboolean +init_picture_refs_b_slice (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture, GstH264SliceHdr * slice_hdr) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiPictureH264 **ref_list; + guint i, n; + gboolean ret = TRUE; + + GST_DEBUG ("decode reference picture list for B slices"); + + if (GST_VAAPI_PICTURE_IS_FRAME (picture)) { + /* 8.2.4.2.3 - B slices in frames */ + + /* RefPicList0 */ + if (priv->short_ref_count > 0) { + // 1. Short-term references + ref_list = priv->RefPicList0; + for (n = 0, i = 0; i < priv->short_ref_count; i++) { + if (priv->short_ref[i]->base.poc < picture->base.poc) + ref_list[n++] = priv->short_ref[i]; + } + SORT_REF_LIST (ref_list, n, poc_dec); + priv->RefPicList0_count += n; + + ref_list = &priv->RefPicList0[priv->RefPicList0_count]; + for (n = 0, i = 0; i < priv->short_ref_count; i++) { + if (priv->short_ref[i]->base.poc >= picture->base.poc) + ref_list[n++] = priv->short_ref[i]; + } + SORT_REF_LIST (ref_list, n, poc_inc); + priv->RefPicList0_count += n; + } + + if (priv->long_ref_count > 0) { + // 2. Long-term references + ref_list = &priv->RefPicList0[priv->RefPicList0_count]; + for (n = 0, i = 0; i < priv->long_ref_count; i++) + ref_list[n++] = priv->long_ref[i]; + SORT_REF_LIST (ref_list, n, long_term_pic_num_inc); + priv->RefPicList0_count += n; + } + + /* RefPicList1 */ + if (priv->short_ref_count > 0) { + // 1. Short-term references + ref_list = priv->RefPicList1; + for (n = 0, i = 0; i < priv->short_ref_count; i++) { + if (priv->short_ref[i]->base.poc > picture->base.poc) + ref_list[n++] = priv->short_ref[i]; + } + SORT_REF_LIST (ref_list, n, poc_inc); + priv->RefPicList1_count += n; + + ref_list = &priv->RefPicList1[priv->RefPicList1_count]; + for (n = 0, i = 0; i < priv->short_ref_count; i++) { + if (priv->short_ref[i]->base.poc <= picture->base.poc) + ref_list[n++] = priv->short_ref[i]; + } + SORT_REF_LIST (ref_list, n, poc_dec); + priv->RefPicList1_count += n; + } + + if (priv->long_ref_count > 0) { + // 2. Long-term references + ref_list = &priv->RefPicList1[priv->RefPicList1_count]; + for (n = 0, i = 0; i < priv->long_ref_count; i++) + ref_list[n++] = priv->long_ref[i]; + SORT_REF_LIST (ref_list, n, long_term_pic_num_inc); + priv->RefPicList1_count += n; + } + } else { + /* 8.2.4.2.4 - B slices in fields */ + GstVaapiPictureH264 *short_ref0[32]; + guint short_ref0_count = 0; + GstVaapiPictureH264 *short_ref1[32]; + guint short_ref1_count = 0; + GstVaapiPictureH264 *long_ref[32]; + guint long_ref_count = 0; + + /* refFrameList0ShortTerm */ + if (priv->short_ref_count > 0) { + ref_list = short_ref0; + for (n = 0, i = 0; i < priv->short_ref_count; i++) { + if (priv->short_ref[i]->base.poc <= picture->base.poc) + ref_list[n++] = priv->short_ref[i]; + } + SORT_REF_LIST (ref_list, n, poc_dec); + short_ref0_count += n; + + ref_list = &short_ref0[short_ref0_count]; + for (n = 0, i = 0; i < priv->short_ref_count; i++) { + if (priv->short_ref[i]->base.poc > picture->base.poc) + ref_list[n++] = priv->short_ref[i]; + } + SORT_REF_LIST (ref_list, n, poc_inc); + short_ref0_count += n; + } + + /* refFrameList1ShortTerm */ + if (priv->short_ref_count > 0) { + ref_list = short_ref1; + for (n = 0, i = 0; i < priv->short_ref_count; i++) { + if (priv->short_ref[i]->base.poc > picture->base.poc) + ref_list[n++] = priv->short_ref[i]; + } + SORT_REF_LIST (ref_list, n, poc_inc); + short_ref1_count += n; + + ref_list = &short_ref1[short_ref1_count]; + for (n = 0, i = 0; i < priv->short_ref_count; i++) { + if (priv->short_ref[i]->base.poc <= picture->base.poc) + ref_list[n++] = priv->short_ref[i]; + } + SORT_REF_LIST (ref_list, n, poc_dec); + short_ref1_count += n; + } + + /* refFrameListLongTerm */ + if (priv->long_ref_count > 0) { + for (i = 0; i < priv->long_ref_count; i++) + long_ref[i] = priv->long_ref[i]; + SORT_REF_LIST (long_ref, i, long_term_frame_idx_inc); + long_ref_count = i; + } + + init_picture_refs_fields (picture, + priv->RefPicList0, &priv->RefPicList0_count, + short_ref0, short_ref0_count, long_ref, long_ref_count); + + init_picture_refs_fields (picture, + priv->RefPicList1, &priv->RefPicList1_count, + short_ref1, short_ref1_count, long_ref, long_ref_count); + } + + /* Check whether RefPicList1 is identical to RefPicList0, then + swap if necessary */ + if (priv->RefPicList1_count > 1 && + priv->RefPicList1_count == priv->RefPicList0_count && + memcmp (priv->RefPicList0, priv->RefPicList1, + priv->RefPicList0_count * sizeof (priv->RefPicList0[0])) == 0) { + GstVaapiPictureH264 *const tmp = priv->RefPicList1[0]; + priv->RefPicList1[0] = priv->RefPicList1[1]; + priv->RefPicList1[1] = tmp; + } + + if (GST_VAAPI_PICTURE_IS_MVC (picture)) { + /* RefPicList0 */ + ret = init_picture_refs_mvc (decoder, picture, slice_hdr, 0); + + /* RefPicList1 */ + ret = init_picture_refs_mvc (decoder, picture, slice_hdr, 1); + } + + return ret; +} + +#undef SORT_REF_LIST + +static gint +find_short_term_reference (GstVaapiDecoderH264 * decoder, gint32 pic_num) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + guint i; + + for (i = 0; i < priv->short_ref_count; i++) { + if (priv->short_ref[i]->pic_num == pic_num) + return i; + } + GST_ERROR ("found no short-term reference picture with PicNum = %d", pic_num); + return -1; +} + +static gint +find_long_term_reference (GstVaapiDecoderH264 * decoder, + gint32 long_term_pic_num) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + guint i; + + for (i = 0; i < priv->long_ref_count; i++) { + if (priv->long_ref[i]->long_term_pic_num == long_term_pic_num) + return i; + } + GST_ERROR ("found no long-term reference picture with LongTermPicNum = %d", + long_term_pic_num); + return -1; +} + +static gboolean +exec_picture_refs_modification_1 (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture, GstH264SliceHdr * slice_hdr, guint list) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstH264SPS *const sps = get_sps (decoder); + GstH264RefPicListModification *ref_pic_list_modification; + guint num_ref_pic_list_modifications; + GstVaapiPictureH264 **ref_list; + guint *ref_list_count_ptr, ref_list_idx = 0; + const guint16 *view_ids = NULL; + guint i, j, n, num_refs, num_view_ids = 0; + gint found_ref_idx; + gint32 MaxPicNum, CurrPicNum, picNumPred, picViewIdxPred; + gboolean ret = TRUE; + + GST_DEBUG ("modification process of reference picture list %u", list); + + if (list == 0) { + ref_pic_list_modification = slice_hdr->ref_pic_list_modification_l0; + num_ref_pic_list_modifications = slice_hdr->n_ref_pic_list_modification_l0; + ref_list = priv->RefPicList0; + ref_list_count_ptr = &priv->RefPicList0_count; + num_refs = slice_hdr->num_ref_idx_l0_active_minus1 + 1; + + if (GST_VAAPI_PICTURE_IS_MVC (picture) && + sps->extension_type == GST_H264_NAL_EXTENSION_MVC) { + const GstH264SPSExtMVCView *const view = + &sps->extension.mvc.view[picture->base.voc]; + if (GST_VAAPI_PICTURE_IS_ANCHOR (picture)) { + view_ids = view->anchor_ref_l0; + num_view_ids = view->num_anchor_refs_l0; + } else { + view_ids = view->non_anchor_ref_l0; + num_view_ids = view->num_non_anchor_refs_l0; + } + } + } else { + ref_pic_list_modification = slice_hdr->ref_pic_list_modification_l1; + num_ref_pic_list_modifications = slice_hdr->n_ref_pic_list_modification_l1; + ref_list = priv->RefPicList1; + ref_list_count_ptr = &priv->RefPicList1_count; + num_refs = slice_hdr->num_ref_idx_l1_active_minus1 + 1; + + if (GST_VAAPI_PICTURE_IS_MVC (picture) && + sps->extension_type == GST_H264_NAL_EXTENSION_MVC) { + const GstH264SPSExtMVCView *const view = + &sps->extension.mvc.view[picture->base.voc]; + if (GST_VAAPI_PICTURE_IS_ANCHOR (picture)) { + view_ids = view->anchor_ref_l1; + num_view_ids = view->num_anchor_refs_l1; + } else { + view_ids = view->non_anchor_ref_l1; + num_view_ids = view->num_non_anchor_refs_l1; + } + } + } + + if (!GST_VAAPI_PICTURE_IS_FRAME (picture)) { + MaxPicNum = 1 << (sps->log2_max_frame_num_minus4 + 5); // 2 * MaxFrameNum + CurrPicNum = 2 * slice_hdr->frame_num + 1; // 2 * frame_num + 1 + } else { + MaxPicNum = 1 << (sps->log2_max_frame_num_minus4 + 4); // MaxFrameNum + CurrPicNum = slice_hdr->frame_num; // frame_num + } + + picNumPred = CurrPicNum; + picViewIdxPred = -1; + + for (i = 0; i < num_ref_pic_list_modifications; i++) { + GstH264RefPicListModification *const l = &ref_pic_list_modification[i]; + if (l->modification_of_pic_nums_idc == 3) + break; + + /* 8.2.4.3.1 - Short-term reference pictures */ + if (l->modification_of_pic_nums_idc == 0 + || l->modification_of_pic_nums_idc == 1) { + gint32 abs_diff_pic_num = l->value.abs_diff_pic_num_minus1 + 1; + gint32 picNum, picNumNoWrap; + + // (8-34) + if (l->modification_of_pic_nums_idc == 0) { + picNumNoWrap = picNumPred - abs_diff_pic_num; + if (picNumNoWrap < 0) + picNumNoWrap += MaxPicNum; + } + // (8-35) + else { + picNumNoWrap = picNumPred + abs_diff_pic_num; + if (picNumNoWrap >= MaxPicNum) + picNumNoWrap -= MaxPicNum; + } + picNumPred = picNumNoWrap; + + // (8-36) + picNum = picNumNoWrap; + if (picNum > CurrPicNum) + picNum -= MaxPicNum; + + // (8-37) + for (j = num_refs; j > ref_list_idx; j--) + ref_list[j] = ref_list[j - 1]; + found_ref_idx = find_short_term_reference (decoder, picNum); + ref_list[ref_list_idx++] = + found_ref_idx >= 0 ? priv->short_ref[found_ref_idx] : NULL; + n = ref_list_idx; + for (j = ref_list_idx; j <= num_refs; j++) { + gint32 PicNumF; + if (!ref_list[j]) + continue; + PicNumF = + GST_VAAPI_PICTURE_IS_SHORT_TERM_REFERENCE (ref_list[j]) ? + ref_list[j]->pic_num : MaxPicNum; + if (PicNumF != picNum || + ref_list[j]->base.view_id != picture->base.view_id) + ref_list[n++] = ref_list[j]; + } + } + + /* 8.2.4.3.2 - Long-term reference pictures */ + else if (l->modification_of_pic_nums_idc == 2) { + + for (j = num_refs; j > ref_list_idx; j--) + ref_list[j] = ref_list[j - 1]; + found_ref_idx = + find_long_term_reference (decoder, l->value.long_term_pic_num); + ref_list[ref_list_idx++] = + found_ref_idx >= 0 ? priv->long_ref[found_ref_idx] : NULL; + n = ref_list_idx; + for (j = ref_list_idx; j <= num_refs; j++) { + gint32 LongTermPicNumF; + if (!ref_list[j]) + continue; + LongTermPicNumF = + GST_VAAPI_PICTURE_IS_LONG_TERM_REFERENCE (ref_list[j]) ? + ref_list[j]->long_term_pic_num : INT_MAX; + if (LongTermPicNumF != l->value.long_term_pic_num || + ref_list[j]->base.view_id != picture->base.view_id) + ref_list[n++] = ref_list[j]; + } + } + + /* H.8.2.2.3 - Inter-view prediction reference pictures */ + else if ((GST_VAAPI_PICTURE_IS_MVC (picture) && + sps->extension_type == GST_H264_NAL_EXTENSION_MVC) && + (l->modification_of_pic_nums_idc == 4 || + l->modification_of_pic_nums_idc == 5)) { + gint32 abs_diff_view_idx = l->value.abs_diff_view_idx_minus1 + 1; + gint32 picViewIdx, targetViewId; + + // (H-6) + if (l->modification_of_pic_nums_idc == 4) { + picViewIdx = picViewIdxPred - abs_diff_view_idx; + if (picViewIdx < 0) + picViewIdx += num_view_ids; + } + // (H-7) + else { + picViewIdx = picViewIdxPred + abs_diff_view_idx; + if (picViewIdx >= num_view_ids) + picViewIdx -= num_view_ids; + } + picViewIdxPred = picViewIdx; + + // (H-8, H-9) + targetViewId = view_ids[picViewIdx]; + + // (H-10) + for (j = num_refs; j > ref_list_idx; j--) + ref_list[j] = ref_list[j - 1]; + ref_list[ref_list_idx++] = + find_inter_view_reference (decoder, targetViewId); + n = ref_list_idx; + for (j = ref_list_idx; j <= num_refs; j++) { + if (!ref_list[j]) + continue; + if (ref_list[j]->base.view_id != targetViewId || + ref_list[j]->base.poc != picture->base.poc) + ref_list[n++] = ref_list[j]; + } + } + } + + for (i = 0; i < num_refs; i++) { + if (!ref_list[i]) { + ret = FALSE; + GST_ERROR ("list %u entry %u is empty", list, i); + } + } + + *ref_list_count_ptr = num_refs; + + return ret; +} + +/* 8.2.4.3 - Modification process for reference picture lists */ +static gboolean +exec_picture_refs_modification (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture, GstH264SliceHdr * slice_hdr) +{ + gboolean ret = TRUE; + + GST_DEBUG ("execute ref_pic_list_modification()"); + + /* RefPicList0 */ + if (!GST_H264_IS_I_SLICE (slice_hdr) && !GST_H264_IS_SI_SLICE (slice_hdr) && + slice_hdr->ref_pic_list_modification_flag_l0) + ret = exec_picture_refs_modification_1 (decoder, picture, slice_hdr, 0); + + /* RefPicList1 */ + if (GST_H264_IS_B_SLICE (slice_hdr) && + slice_hdr->ref_pic_list_modification_flag_l1) + ret = exec_picture_refs_modification_1 (decoder, picture, slice_hdr, 1); + + return ret; +} + +static gboolean +check_picture_ref_corruption (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * RefPicList[32], guint RefPicList_count) +{ + const guint corrupted_flags = + GST_VAAPI_PICTURE_FLAG_CORRUPTED | GST_VAAPI_PICTURE_FLAG_GHOST; + guint i; + + for (i = 0; i < RefPicList_count; i++) { + GstVaapiPictureH264 *const picture = RefPicList[i]; + if (picture && (GST_VAAPI_PICTURE_FLAGS (picture) & corrupted_flags)) + return TRUE; + } + return FALSE; +} + +static void +mark_picture_refs (GstVaapiDecoderH264 * decoder, GstVaapiPictureH264 * picture) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + + if (GST_VAAPI_PICTURE_IS_CORRUPTED (picture)) + return; + + if (check_picture_ref_corruption (decoder, + priv->RefPicList0, priv->RefPicList0_count) || + check_picture_ref_corruption (decoder, + priv->RefPicList1, priv->RefPicList1_count)) + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_CORRUPTED); +} + +static void +init_picture_ref_lists (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + guint i, j, short_ref_count, long_ref_count; + + short_ref_count = 0; + long_ref_count = 0; + if (GST_VAAPI_PICTURE_IS_FRAME (picture)) { + for (i = 0; i < priv->dpb_count; i++) { + GstVaapiFrameStore *const fs = priv->dpb[i]; + GstVaapiPictureH264 *pic; + if (!gst_vaapi_frame_store_has_frame (fs)) + continue; + pic = fs->buffers[0]; + if (pic->base.view_id != picture->base.view_id) + continue; + if (GST_VAAPI_PICTURE_IS_SHORT_TERM_REFERENCE (pic)) + priv->short_ref[short_ref_count++] = pic; + else if (GST_VAAPI_PICTURE_IS_LONG_TERM_REFERENCE (pic)) + priv->long_ref[long_ref_count++] = pic; + pic->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME; + pic->other_field = fs->buffers[1]; + } + } else { + for (i = 0; i < priv->dpb_count; i++) { + GstVaapiFrameStore *const fs = priv->dpb[i]; + for (j = 0; j < fs->num_buffers; j++) { + GstVaapiPictureH264 *const pic = fs->buffers[j]; + if (pic->base.view_id != picture->base.view_id) + continue; + if (GST_VAAPI_PICTURE_IS_SHORT_TERM_REFERENCE (pic)) + priv->short_ref[short_ref_count++] = pic; + else if (GST_VAAPI_PICTURE_IS_LONG_TERM_REFERENCE (pic)) + priv->long_ref[long_ref_count++] = pic; + pic->structure = pic->base.structure; + pic->other_field = fs->buffers[j ^ 1]; + } + } + } + + for (i = short_ref_count; i < priv->short_ref_count; i++) + priv->short_ref[i] = NULL; + priv->short_ref_count = short_ref_count; + + for (i = long_ref_count; i < priv->long_ref_count; i++) + priv->long_ref[i] = NULL; + priv->long_ref_count = long_ref_count; +} + +static gboolean +init_picture_refs (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture, GstH264SliceHdr * slice_hdr) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + guint i, num_refs; + gboolean ret = TRUE; + + init_picture_ref_lists (decoder, picture); + init_picture_refs_pic_num (decoder, picture, slice_hdr); + + priv->RefPicList0_count = 0; + priv->RefPicList1_count = 0; + + switch (slice_hdr->type % 5) { + case GST_H264_P_SLICE: + case GST_H264_SP_SLICE: + ret = init_picture_refs_p_slice (decoder, picture, slice_hdr); + break; + case GST_H264_B_SLICE: + ret = init_picture_refs_b_slice (decoder, picture, slice_hdr); + break; + default: + break; + } + + switch (slice_hdr->type % 5) { + case GST_H264_B_SLICE: + num_refs = 1 + slice_hdr->num_ref_idx_l1_active_minus1; + for (i = priv->RefPicList1_count; i < num_refs; i++) + priv->RefPicList1[i] = NULL; + priv->RefPicList1_count = num_refs; + + // fall-through + case GST_H264_P_SLICE: + case GST_H264_SP_SLICE: + num_refs = 1 + slice_hdr->num_ref_idx_l0_active_minus1; + for (i = priv->RefPicList0_count; i < num_refs; i++) + priv->RefPicList0[i] = NULL; + priv->RefPicList0_count = num_refs; + break; + default: + break; + } + + ret = ret && exec_picture_refs_modification (decoder, picture, slice_hdr); + + mark_picture_refs (decoder, picture); + + return ret; +} + +static GstVaapiPictureH264 * +fill_picture_other_field_gap (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * f0) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiPictureH264 *prev_picture, *f1; + gint prev_frame_index; + guint picture_structure; + + picture_structure = f0->base.structure; + switch (picture_structure) { + case GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD: + picture_structure = GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD; + break; + case GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD: + picture_structure = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD; + break; + default: + g_assert (0 && "unexpected picture structure"); + return NULL; + } + GST_VAAPI_PICTURE_FLAG_SET (f0, GST_VAAPI_PICTURE_FLAG_ONEFIELD); + + prev_frame_index = dpb_find_nearest_prev_poc (decoder, f0, + picture_structure, &prev_picture); + if (prev_frame_index < 0) + goto error_find_field; + + f1 = gst_vaapi_picture_h264_new_field (f0); + if (!f1) + goto error_allocate_field; + + gst_vaapi_surface_proxy_replace (&f1->base.proxy, prev_picture->base.proxy); + f1->base.surface = GST_VAAPI_SURFACE_PROXY_SURFACE (f1->base.proxy); + f1->base.surface_id = GST_VAAPI_SURFACE_PROXY_SURFACE_ID (f1->base.proxy); + f1->base.poc++; + f1->structure = f1->base.structure; + + /* XXX: clone other H.264 picture specific flags */ + GST_VAAPI_PICTURE_FLAG_SET (f1, + (GST_VAAPI_PICTURE_FLAG_SKIPPED | GST_VAAPI_PICTURE_FLAG_GHOST)); + + gst_vaapi_picture_h264_set_reference (f1, 0, FALSE); + gst_vaapi_picture_replace (&priv->current_picture, f1); + gst_vaapi_picture_unref (f1); + + init_picture_ref_lists (decoder, f1); + init_picture_refs_pic_num (decoder, f1, NULL); + if (!exec_ref_pic_marking_sliding_window (decoder)) + goto error_exec_ref_pic_marking; + if (!dpb_add (decoder, f1)) + goto error_append_field; + return f1; + + /* ERRORS */ +error_find_field: + { + GST_ERROR ("failed to find field with POC nearest to %d", f0->base.poc); + return NULL; + } +error_allocate_field: + { + GST_ERROR ("failed to allocate missing field for previous frame store"); + return NULL; + } +error_exec_ref_pic_marking: + { + GST_ERROR ("failed to execute reference picture marking process"); + return NULL; + } +error_append_field: + { + GST_ERROR ("failed to add missing field into previous frame store"); + return NULL; + } +} + +static gboolean +fill_picture_gaps (GstVaapiDecoderH264 * decoder, GstVaapiPictureH264 * picture, + GstH264SliceHdr * slice_hdr) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstH264SPS *const sps = get_sps (decoder); + const gint32 MaxFrameNum = 1 << (sps->log2_max_frame_num_minus4 + 4); + gint32 prev_frame_num; + GstVaapiFrameStore *prev_frame; + GstVaapiPicture *base_picture; + GstVaapiPictureH264 *lost_picture, *prev_picture; + GstH264SliceHdr lost_slice_hdr; + gboolean success = FALSE; + + if (priv->prev_ref_frame_num == priv->frame_num) + return TRUE; + if ((priv->prev_ref_frame_num + 1) % MaxFrameNum == priv->frame_num) + return TRUE; + if (priv->dpb_count == 0) + return TRUE; + + prev_frame = priv->prev_ref_frames[picture->base.voc]; + g_assert (prev_frame != NULL && prev_frame->buffers[0] != NULL); + prev_picture = gst_vaapi_picture_ref (prev_frame->buffers[0]); + gst_vaapi_picture_ref (picture); + + lost_slice_hdr = *slice_hdr; + lost_slice_hdr.field_pic_flag = 0; + if (sps->pic_order_cnt_type == 1) { + lost_slice_hdr.delta_pic_order_cnt[0] = 0; + lost_slice_hdr.delta_pic_order_cnt[1] = 0; + } + lost_slice_hdr.dec_ref_pic_marking.adaptive_ref_pic_marking_mode_flag = 0; + + /* XXX: this process is incorrect for MVC */ + /* Reduce frame num gaps so we don't have to create unnecessary + * dummy pictures */ + prev_frame_num = priv->prev_ref_frame_num; + if (prev_frame_num > slice_hdr->frame_num) + prev_frame_num -= MaxFrameNum; + + if ((slice_hdr->frame_num - prev_frame_num) - 1 > sps->num_ref_frames) { + prev_frame_num = (slice_hdr->frame_num - sps->num_ref_frames) - 1; + + if (prev_frame_num < 0) + prev_frame_num += MaxFrameNum; + } + priv->frame_num = prev_frame_num; + + for (;;) { + priv->prev_ref_frame_num = priv->frame_num; + priv->frame_num = (priv->prev_ref_frame_num + 1) % MaxFrameNum; + if (priv->frame_num == slice_hdr->frame_num) + break; + + /* Create new picture */ + lost_picture = gst_vaapi_picture_h264_new_clone (prev_picture); + if (!lost_picture) + goto error_allocate_picture; + + base_picture = &lost_picture->base; + base_picture->type = GST_VAAPI_PICTURE_TYPE_NONE; + base_picture->pts = GST_CLOCK_TIME_NONE; + base_picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME; + lost_picture->frame_num = priv->frame_num; + lost_picture->frame_num_wrap = priv->frame_num; + lost_picture->structure = base_picture->structure; + + GST_VAAPI_PICTURE_FLAG_SET (lost_picture, + (GST_VAAPI_PICTURE_FLAG_SKIPPED | + GST_VAAPI_PICTURE_FLAG_GHOST | + GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE)); + + if (sps->pic_order_cnt_type != 0) + init_picture_poc (decoder, lost_picture, &lost_slice_hdr); + else { + base_picture->poc = prev_picture->base.poc + 2; + if (prev_picture->field_poc[0] != G_MAXINT32) + lost_picture->field_poc[0] = prev_picture->field_poc[0] + 2; + if (prev_picture->field_poc[1] != G_MAXINT32) + lost_picture->field_poc[1] = prev_picture->field_poc[1] + 2; + } + + gst_vaapi_picture_replace (&prev_picture, lost_picture); + gst_vaapi_picture_replace (&priv->current_picture, lost_picture); + gst_vaapi_picture_unref (lost_picture); + + init_picture_ref_lists (decoder, lost_picture); + init_picture_refs_pic_num (decoder, lost_picture, &lost_slice_hdr); + if (!exec_ref_pic_marking_sliding_window (decoder)) + goto error_exec_ref_pic_marking; + if (!dpb_add (decoder, lost_picture)) + goto error_dpb_add; + gst_vaapi_picture_replace (&priv->current_picture, NULL); + } + success = TRUE; + +cleanup: + priv->frame_num = slice_hdr->frame_num; + priv->prev_ref_frame_num = (priv->frame_num + MaxFrameNum - 1) % MaxFrameNum; + gst_vaapi_picture_replace (&prev_picture, NULL); + gst_vaapi_picture_replace (&priv->current_picture, picture); + gst_vaapi_picture_unref (picture); + return success; + + /* ERRORS */ +error_allocate_picture: + { + GST_ERROR ("failed to allocate lost picture"); + goto cleanup; + } +error_exec_ref_pic_marking: + { + GST_ERROR ("failed to execute reference picture marking process"); + goto cleanup; + } +error_dpb_add: + { + GST_ERROR ("failed to store lost picture into the DPB"); + goto cleanup; + } +} + +static gboolean +init_picture (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture, GstVaapiParserInfoH264 * pi) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiPicture *const base_picture = &picture->base; + GstH264SliceHdr *const slice_hdr = &pi->data.slice_hdr; + + if (priv->prev_pic_reference) + priv->prev_ref_frame_num = priv->frame_num; + priv->prev_frame_num = priv->frame_num; + priv->frame_num = slice_hdr->frame_num; + picture->frame_num = priv->frame_num; + picture->frame_num_wrap = priv->frame_num; + picture->output_flag = TRUE; /* XXX: conformant to Annex A only */ + + /* If it's a cloned picture, it has some assignments from parent + * picture already. In addition, base decoder doesn't set valid pts + * to the frame corresponding to cloned picture. + */ + if (G_LIKELY (!base_picture->parent_picture)) { + base_picture->pts = GST_VAAPI_DECODER_CODEC_FRAME (decoder)->pts; + base_picture->type = GST_VAAPI_PICTURE_TYPE_NONE; + base_picture->view_id = pi->view_id; + base_picture->voc = pi->voc; + } + + /* Initialize extensions */ + switch (pi->nalu.extension_type) { + case GST_H264_NAL_EXTENSION_MVC:{ + GstH264NalUnitExtensionMVC *const mvc = &pi->nalu.extension.mvc; + + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_MVC); + if (mvc->inter_view_flag) + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_INTER_VIEW); + if (mvc->anchor_pic_flag) + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_ANCHOR); + break; + } + } + + /* Reset decoder state for IDR pictures */ + if (pi->nalu.idr_pic_flag) { + GST_DEBUG (""); + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_IDR); + dpb_flush (decoder, picture); + } else if (!fill_picture_gaps (decoder, picture, slice_hdr)) + return FALSE; + + /* Initialize picture structure */ + if (slice_hdr->field_pic_flag) { + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_INTERLACED); + priv->pic_structure = slice_hdr->bottom_field_flag ? + GST_H264_SEI_PIC_STRUCT_BOTTOM_FIELD : + GST_H264_SEI_PIC_STRUCT_TOP_FIELD; + } + + base_picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME; + switch (priv->pic_structure) { + case GST_H264_SEI_PIC_STRUCT_TOP_FIELD: + base_picture->structure = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD; + if (GST_VAAPI_PICTURE_IS_FIRST_FIELD (picture)) + priv->top_field_first = TRUE; + break; + case GST_H264_SEI_PIC_STRUCT_BOTTOM_FIELD: + base_picture->structure = GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD; + break; + case GST_H264_SEI_PIC_STRUCT_TOP_BOTTOM_TOP: + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_RFF); + // fall-through + case GST_H264_SEI_PIC_STRUCT_TOP_BOTTOM: + if (GST_VAAPI_PICTURE_IS_FIRST_FIELD (picture)) + priv->top_field_first = TRUE; + break; + case GST_H264_SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM: + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_RFF); + break; + case GST_H264_SEI_PIC_STRUCT_FRAME: + if (!priv->progressive_sequence && priv->dpb_count == 0) + priv->top_field_first = TRUE; + break; + } + picture->structure = base_picture->structure; + if (priv->top_field_first) + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_TFF); + + /* Initialize reference flags */ + if (pi->nalu.ref_idc) { + GstH264DecRefPicMarking *const dec_ref_pic_marking = + &slice_hdr->dec_ref_pic_marking; + + if (GST_VAAPI_PICTURE_IS_IDR (picture) && + dec_ref_pic_marking->long_term_reference_flag) + GST_VAAPI_PICTURE_FLAG_SET (picture, + GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE); + else + GST_VAAPI_PICTURE_FLAG_SET (picture, + GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE); + } + + init_picture_poc (decoder, picture, slice_hdr); + return TRUE; +} + +/* 8.2.5.3 - Sliding window decoded reference picture marking process */ +static gboolean +exec_ref_pic_marking_sliding_window (GstVaapiDecoderH264 * decoder) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstH264SPS *const sps = get_sps (decoder); + GstVaapiPictureH264 *ref_picture; + guint i, m, max_num_ref_frames; + + GST_DEBUG ("reference picture marking process (sliding window)"); + + if (!GST_VAAPI_PICTURE_IS_FIRST_FIELD (priv->current_picture)) + return TRUE; + + max_num_ref_frames = sps->num_ref_frames; + if (max_num_ref_frames == 0) + max_num_ref_frames = 1; + if (!GST_VAAPI_PICTURE_IS_FRAME (priv->current_picture)) + max_num_ref_frames <<= 1; + + if (priv->short_ref_count + priv->long_ref_count < max_num_ref_frames) + return TRUE; + if (priv->short_ref_count < 1) + return FALSE; + + for (m = 0, i = 1; i < priv->short_ref_count; i++) { + GstVaapiPictureH264 *const picture = priv->short_ref[i]; + if (picture->frame_num_wrap < priv->short_ref[m]->frame_num_wrap) + m = i; + } + + ref_picture = priv->short_ref[m]; + gst_vaapi_picture_h264_set_reference (ref_picture, 0, TRUE); + ARRAY_REMOVE_INDEX (priv->short_ref, m); + + /* Both fields need to be marked as "unused for reference", so + remove the other field from the short_ref[] list as well */ + if (!GST_VAAPI_PICTURE_IS_FRAME (priv->current_picture) + && ref_picture->other_field) { + for (i = 0; i < priv->short_ref_count; i++) { + if (priv->short_ref[i] == ref_picture->other_field) { + ARRAY_REMOVE_INDEX (priv->short_ref, i); + break; + } + } + } + return TRUE; +} + +static inline gint32 +get_picNumX (GstVaapiPictureH264 * picture, + GstH264RefPicMarking * ref_pic_marking) +{ + gint32 pic_num; + + if (GST_VAAPI_PICTURE_IS_FRAME (picture)) + pic_num = picture->frame_num_wrap; + else + pic_num = 2 * picture->frame_num_wrap + 1; + pic_num -= ref_pic_marking->difference_of_pic_nums_minus1 + 1; + return pic_num; +} + +/* 8.2.5.4.1. Mark short-term reference picture as "unused for reference" */ +static void +exec_ref_pic_marking_adaptive_mmco_1 (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture, GstH264RefPicMarking * ref_pic_marking) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + gint32 i, picNumX; + + picNumX = get_picNumX (picture, ref_pic_marking); + i = find_short_term_reference (decoder, picNumX); + if (i < 0) + return; + + gst_vaapi_picture_h264_set_reference (priv->short_ref[i], 0, + GST_VAAPI_PICTURE_IS_FRAME (picture)); + ARRAY_REMOVE_INDEX (priv->short_ref, i); +} + +/* 8.2.5.4.2. Mark long-term reference picture as "unused for reference" */ +static void +exec_ref_pic_marking_adaptive_mmco_2 (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture, GstH264RefPicMarking * ref_pic_marking) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + gint32 i; + + i = find_long_term_reference (decoder, ref_pic_marking->long_term_pic_num); + if (i < 0) + return; + + gst_vaapi_picture_h264_set_reference (priv->long_ref[i], 0, + GST_VAAPI_PICTURE_IS_FRAME (picture)); + ARRAY_REMOVE_INDEX (priv->long_ref, i); +} + +/* 8.2.5.4.3. Assign LongTermFrameIdx to a short-term reference picture */ +static void +exec_ref_pic_marking_adaptive_mmco_3 (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture, GstH264RefPicMarking * ref_pic_marking) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiPictureH264 *ref_picture, *other_field; + gint32 i, picNumX; + + for (i = 0; i < priv->long_ref_count; i++) { + if (priv->long_ref[i]->long_term_frame_idx == + ref_pic_marking->long_term_frame_idx) + break; + } + if (i != priv->long_ref_count) { + gst_vaapi_picture_h264_set_reference (priv->long_ref[i], 0, TRUE); + ARRAY_REMOVE_INDEX (priv->long_ref, i); + } + + picNumX = get_picNumX (picture, ref_pic_marking); + i = find_short_term_reference (decoder, picNumX); + if (i < 0) + return; + + ref_picture = priv->short_ref[i]; + ARRAY_REMOVE_INDEX (priv->short_ref, i); + priv->long_ref[priv->long_ref_count++] = ref_picture; + + ref_picture->long_term_frame_idx = ref_pic_marking->long_term_frame_idx; + gst_vaapi_picture_h264_set_reference (ref_picture, + GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE, + GST_VAAPI_PICTURE_IS_COMPLETE (picture)); + + /* Assign LongTermFrameIdx to the other field if it was also + marked as "used for long-term reference */ + other_field = ref_picture->other_field; + if (other_field && GST_VAAPI_PICTURE_IS_LONG_TERM_REFERENCE (other_field)) + other_field->long_term_frame_idx = ref_pic_marking->long_term_frame_idx; +} + +/* 8.2.5.4.4. Mark pictures with LongTermFramIdx > max_long_term_frame_idx + * as "unused for reference" */ +static void +exec_ref_pic_marking_adaptive_mmco_4 (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture, GstH264RefPicMarking * ref_pic_marking) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + gint32 i, long_term_frame_idx; + + long_term_frame_idx = ref_pic_marking->max_long_term_frame_idx_plus1 - 1; + + for (i = 0; i < priv->long_ref_count; i++) { + if (priv->long_ref[i]->long_term_frame_idx <= long_term_frame_idx) + continue; + gst_vaapi_picture_h264_set_reference (priv->long_ref[i], 0, FALSE); + ARRAY_REMOVE_INDEX (priv->long_ref, i); + i--; + } +} + +/* 8.2.5.4.5. Mark all reference pictures as "unused for reference" */ +static void +exec_ref_pic_marking_adaptive_mmco_5 (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture, GstH264RefPicMarking * ref_pic_marking) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + + dpb_flush (decoder, picture); + + priv->prev_pic_has_mmco5 = TRUE; + + /* The picture shall be inferred to have had frame_num equal to 0 (7.4.3) */ + priv->frame_num = 0; + priv->frame_num_offset = 0; + picture->frame_num = 0; + + /* Update TopFieldOrderCnt and BottomFieldOrderCnt (8.2.1) */ + if (picture->structure != GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD) + picture->field_poc[TOP_FIELD] -= picture->base.poc; + if (picture->structure != GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD) + picture->field_poc[BOTTOM_FIELD] -= picture->base.poc; + picture->base.poc = 0; +} + +/* 8.2.5.4.6. Assign a long-term frame index to the current picture */ +static void +exec_ref_pic_marking_adaptive_mmco_6 (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture, GstH264RefPicMarking * ref_pic_marking) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiPictureH264 *other_field; + guint i; + + for (i = 0; i < priv->long_ref_count; i++) { + if (priv->long_ref[i]->long_term_frame_idx == + ref_pic_marking->long_term_frame_idx) + break; + } + if (i != priv->long_ref_count) { + gst_vaapi_picture_h264_set_reference (priv->long_ref[i], 0, TRUE); + ARRAY_REMOVE_INDEX (priv->long_ref, i); + } + + picture->long_term_frame_idx = ref_pic_marking->long_term_frame_idx; + gst_vaapi_picture_h264_set_reference (picture, + GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE, + GST_VAAPI_PICTURE_IS_COMPLETE (picture)); + + /* Assign LongTermFrameIdx to the other field if it was also + marked as "used for long-term reference */ + other_field = GST_VAAPI_PICTURE_H264 (picture->base.parent_picture); + if (other_field && GST_VAAPI_PICTURE_IS_LONG_TERM_REFERENCE (other_field)) + other_field->long_term_frame_idx = ref_pic_marking->long_term_frame_idx; +} + +/* 8.2.5.4. Adaptive memory control decoded reference picture marking process */ +static gboolean +exec_ref_pic_marking_adaptive (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture, + GstH264DecRefPicMarking * dec_ref_pic_marking) +{ + guint i; + + typedef void (*exec_ref_pic_marking_adaptive_mmco_func) (GstVaapiDecoderH264 * + decoder, GstVaapiPictureH264 * picture, + GstH264RefPicMarking * ref_pic_marking); + + static const exec_ref_pic_marking_adaptive_mmco_func mmco_funcs[] = { + NULL, + exec_ref_pic_marking_adaptive_mmco_1, + exec_ref_pic_marking_adaptive_mmco_2, + exec_ref_pic_marking_adaptive_mmco_3, + exec_ref_pic_marking_adaptive_mmco_4, + exec_ref_pic_marking_adaptive_mmco_5, + exec_ref_pic_marking_adaptive_mmco_6, + }; + + GST_DEBUG ("reference picture marking process (adaptive memory control)"); + + for (i = 0; i < dec_ref_pic_marking->n_ref_pic_marking; i++) { + GstH264RefPicMarking *const ref_pic_marking = + &dec_ref_pic_marking->ref_pic_marking[i]; + + const guint mmco = ref_pic_marking->memory_management_control_operation; + if (mmco < G_N_ELEMENTS (mmco_funcs) && mmco_funcs[mmco]) + mmco_funcs[mmco] (decoder, picture, ref_pic_marking); + else { + GST_ERROR ("unhandled MMCO %u", mmco); + return FALSE; + } + } + return TRUE; +} + +/* 8.2.5 - Execute reference picture marking process */ +static gboolean +exec_ref_pic_marking (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + + priv->prev_pic_reference = GST_VAAPI_PICTURE_IS_REFERENCE (picture); + priv->prev_pic_has_mmco5 = FALSE; + priv->prev_pic_structure = picture->structure; + + if (GST_VAAPI_PICTURE_IS_INTER_VIEW (picture)) + g_ptr_array_add (priv->inter_views, gst_vaapi_picture_ref (picture)); + + if (!priv->prev_pic_reference) + return TRUE; + + if (!GST_VAAPI_PICTURE_IS_IDR (picture)) { + GstH264DecRefPicMarking *const dec_ref_pic_marking = + &picture->last_slice_hdr->dec_ref_pic_marking; + if (dec_ref_pic_marking->adaptive_ref_pic_marking_mode_flag) { + if (!exec_ref_pic_marking_adaptive (decoder, picture, + dec_ref_pic_marking)) + return FALSE; + } else { + if (!exec_ref_pic_marking_sliding_window (decoder)) + return FALSE; + } + } + return TRUE; +} + +static void +vaapi_init_picture (VAPictureH264 * pic) +{ + pic->picture_id = VA_INVALID_ID; + pic->frame_idx = 0; + pic->flags = VA_PICTURE_H264_INVALID; + pic->TopFieldOrderCnt = 0; + pic->BottomFieldOrderCnt = 0; +} + +static void +vaapi_fill_picture (VAPictureH264 * pic, GstVaapiPictureH264 * picture, + guint picture_structure) +{ + if (!picture_structure) + picture_structure = picture->structure; + + pic->picture_id = picture->base.surface_id; + pic->flags = 0; + + if (GST_VAAPI_PICTURE_IS_LONG_TERM_REFERENCE (picture)) { + pic->flags |= VA_PICTURE_H264_LONG_TERM_REFERENCE; + pic->frame_idx = picture->long_term_frame_idx; + } else { + if (GST_VAAPI_PICTURE_IS_SHORT_TERM_REFERENCE (picture)) + pic->flags |= VA_PICTURE_H264_SHORT_TERM_REFERENCE; + pic->frame_idx = picture->frame_num; + } + + switch (picture_structure) { + case GST_VAAPI_PICTURE_STRUCTURE_FRAME: + pic->TopFieldOrderCnt = picture->field_poc[TOP_FIELD]; + pic->BottomFieldOrderCnt = picture->field_poc[BOTTOM_FIELD]; + break; + case GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD: + pic->flags |= VA_PICTURE_H264_TOP_FIELD; + pic->TopFieldOrderCnt = picture->field_poc[TOP_FIELD]; + pic->BottomFieldOrderCnt = 0; + break; + case GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD: + pic->flags |= VA_PICTURE_H264_BOTTOM_FIELD; + pic->BottomFieldOrderCnt = picture->field_poc[BOTTOM_FIELD]; + pic->TopFieldOrderCnt = 0; + break; + } +} + +static void +vaapi_fill_picture_for_RefPicListX (VAPictureH264 * pic, + GstVaapiPictureH264 * picture) +{ + vaapi_fill_picture (pic, picture, 0); + + /* H.8.4 - MVC inter prediction and inter-view prediction process */ + if (GST_VAAPI_PICTURE_IS_INTER_VIEW (picture)) { + /* The inter-view reference components and inter-view only + reference components that are included in the reference + picture lists are considered as not being marked as "used for + short-term reference" or "used for long-term reference" */ + pic->flags &= ~(VA_PICTURE_H264_SHORT_TERM_REFERENCE | + VA_PICTURE_H264_LONG_TERM_REFERENCE); + } +} + +static gboolean +fill_picture (GstVaapiDecoderH264 * decoder, GstVaapiPictureH264 * picture) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiPicture *const base_picture = &picture->base; + GstH264PPS *const pps = get_pps (decoder); + GstH264SPS *const sps = get_sps (decoder); + VAPictureParameterBufferH264 *const pic_param = base_picture->param; + guint i, n; + + /* Fill in VAPictureParameterBufferH264 */ + vaapi_fill_picture (&pic_param->CurrPic, picture, 0); + + for (i = 0, n = 0; i < priv->dpb_count; i++) { + GstVaapiFrameStore *const fs = priv->dpb[i]; + if ((gst_vaapi_frame_store_has_reference (fs) && + fs->view_id == picture->base.view_id) || + (gst_vaapi_frame_store_has_inter_view (fs) && + is_inter_view_reference_for_picture (decoder, fs->view_id, + picture))) + vaapi_fill_picture (&pic_param->ReferenceFrames[n++], fs->buffers[0], + fs->structure); + if (n >= G_N_ELEMENTS (pic_param->ReferenceFrames)) + break; + } + for (; n < G_N_ELEMENTS (pic_param->ReferenceFrames); n++) + vaapi_init_picture (&pic_param->ReferenceFrames[n]); + +#define COPY_FIELD(s, f) \ + pic_param->f = (s)->f + +#define COPY_BFM(a, s, f) \ + pic_param->a.bits.f = (s)->f + + pic_param->picture_width_in_mbs_minus1 = priv->mb_width - 1; + pic_param->picture_height_in_mbs_minus1 = priv->mb_height - 1; + pic_param->frame_num = priv->frame_num; + + COPY_FIELD (sps, bit_depth_luma_minus8); + COPY_FIELD (sps, bit_depth_chroma_minus8); + COPY_FIELD (sps, num_ref_frames); + if (pic_param->num_ref_frames == 0) + pic_param->num_ref_frames = priv->dpb_size; + +#if !VA_CHECK_VERSION(1,0,0) + /* Deprecate H.264 baseline profile and FMO support */ + COPY_FIELD (pps, num_slice_groups_minus1); + COPY_FIELD (pps, slice_group_map_type); + COPY_FIELD (pps, slice_group_change_rate_minus1); +#endif + COPY_FIELD (pps, pic_init_qp_minus26); + COPY_FIELD (pps, pic_init_qs_minus26); + COPY_FIELD (pps, chroma_qp_index_offset); + COPY_FIELD (pps, second_chroma_qp_index_offset); + + pic_param->seq_fields.value = 0; /* reset all bits */ + pic_param->seq_fields.bits.residual_colour_transform_flag = + sps->separate_colour_plane_flag; + pic_param->seq_fields.bits.MinLumaBiPredSize8x8 = sps->level_idc >= 31; /* A.3.3.2 */ + + COPY_BFM (seq_fields, sps, chroma_format_idc); + COPY_BFM (seq_fields, sps, gaps_in_frame_num_value_allowed_flag); + COPY_BFM (seq_fields, sps, frame_mbs_only_flag); + COPY_BFM (seq_fields, sps, mb_adaptive_frame_field_flag); + COPY_BFM (seq_fields, sps, direct_8x8_inference_flag); + COPY_BFM (seq_fields, sps, log2_max_frame_num_minus4); + COPY_BFM (seq_fields, sps, pic_order_cnt_type); + COPY_BFM (seq_fields, sps, log2_max_pic_order_cnt_lsb_minus4); + COPY_BFM (seq_fields, sps, delta_pic_order_always_zero_flag); + + pic_param->pic_fields.value = 0; /* reset all bits */ + pic_param->pic_fields.bits.field_pic_flag = + GST_VAAPI_PICTURE_IS_INTERLACED (picture); + pic_param->pic_fields.bits.reference_pic_flag = + GST_VAAPI_PICTURE_IS_REFERENCE (picture); + + COPY_BFM (pic_fields, pps, entropy_coding_mode_flag); + COPY_BFM (pic_fields, pps, weighted_pred_flag); + COPY_BFM (pic_fields, pps, weighted_bipred_idc); + COPY_BFM (pic_fields, pps, transform_8x8_mode_flag); + COPY_BFM (pic_fields, pps, constrained_intra_pred_flag); + COPY_BFM (pic_fields, pps, pic_order_present_flag); + COPY_BFM (pic_fields, pps, deblocking_filter_control_present_flag); + COPY_BFM (pic_fields, pps, redundant_pic_cnt_present_flag); + return TRUE; +} + +/* Detection of the first VCL NAL unit of a primary coded picture (7.4.1.2.4) */ +static gboolean +is_new_picture (GstVaapiParserInfoH264 * pi, GstVaapiParserInfoH264 * prev_pi) +{ + GstH264SliceHdr *const slice_hdr = &pi->data.slice_hdr; + GstH264PPS *const pps = slice_hdr->pps; + GstH264SPS *const sps = pps->sequence; + GstH264SliceHdr *prev_slice_hdr; + + if (!prev_pi) + return TRUE; + prev_slice_hdr = &prev_pi->data.slice_hdr; + +#define CHECK_EXPR(expr, field_name) do { \ + if (!(expr)) { \ + GST_DEBUG(field_name " differs in value"); \ + return TRUE; \ + } \ + } while (0) + +#define CHECK_VALUE(new_slice_hdr, old_slice_hdr, field) \ + CHECK_EXPR(((new_slice_hdr)->field == (old_slice_hdr)->field), #field) + + /* view_id differs in value and VOIdx of current slice_hdr is less + than the VOIdx of the prev_slice_hdr */ + CHECK_VALUE (pi, prev_pi, view_id); + + /* frame_num differs in value, regardless of inferred values to 0 */ + CHECK_VALUE (slice_hdr, prev_slice_hdr, frame_num); + + /* pic_parameter_set_id differs in value */ + CHECK_VALUE (slice_hdr, prev_slice_hdr, pps); + + /* field_pic_flag differs in value */ + CHECK_VALUE (slice_hdr, prev_slice_hdr, field_pic_flag); + + /* bottom_field_flag is present in both and differs in value */ + if (slice_hdr->field_pic_flag && prev_slice_hdr->field_pic_flag) + CHECK_VALUE (slice_hdr, prev_slice_hdr, bottom_field_flag); + + /* nal_ref_idc differs in value with one of the nal_ref_idc values is 0 */ + CHECK_EXPR ((pi->nalu.ref_idc != 0) == + (prev_pi->nalu.ref_idc != 0), "nal_ref_idc"); + + /* POC type is 0 for both and either pic_order_cnt_lsb differs in + value or delta_pic_order_cnt_bottom differs in value */ + if (sps->pic_order_cnt_type == 0) { + CHECK_VALUE (slice_hdr, prev_slice_hdr, pic_order_cnt_lsb); + if (pps->pic_order_present_flag && !slice_hdr->field_pic_flag) + CHECK_VALUE (slice_hdr, prev_slice_hdr, delta_pic_order_cnt_bottom); + } + + /* POC type is 1 for both and either delta_pic_order_cnt[0] + differs in value or delta_pic_order_cnt[1] differs in value */ + else if (sps->pic_order_cnt_type == 1) { + CHECK_VALUE (slice_hdr, prev_slice_hdr, delta_pic_order_cnt[0]); + CHECK_VALUE (slice_hdr, prev_slice_hdr, delta_pic_order_cnt[1]); + } + + /* IdrPicFlag differs in value */ + CHECK_VALUE (&pi->nalu, &prev_pi->nalu, idr_pic_flag); + + /* IdrPicFlag is equal to 1 for both and idr_pic_id differs in value */ + if (pi->nalu.idr_pic_flag) + CHECK_VALUE (slice_hdr, prev_slice_hdr, idr_pic_id); + +#undef CHECK_EXPR +#undef CHECK_VALUE + return FALSE; +} + +/* Detection of a new access unit, assuming we are already in presence + of a new picture */ +static inline gboolean +is_new_access_unit (GstVaapiParserInfoH264 * pi, + GstVaapiParserInfoH264 * prev_pi) +{ + if (!prev_pi || prev_pi->view_id == pi->view_id) + return TRUE; + return pi->voc < prev_pi->voc; +} + +/* Determines whether the supplied picture has the same field parity + than a picture specified through the other slice header */ +static inline gboolean +same_field_parity (GstVaapiPictureH264 * field, GstH264SliceHdr * slice_hdr) +{ + g_return_val_if_fail (GST_VAAPI_PICTURE_IS_INTERLACED (field), FALSE); + + return ((field->base.structure == GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD) ^ + slice_hdr->bottom_field_flag) == 0; +} + +/* Finds the first field picture corresponding to the supplied picture */ +static GstVaapiPictureH264 * +find_first_field (GstVaapiDecoderH264 * decoder, GstVaapiParserInfoH264 * pi) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstH264SliceHdr *const slice_hdr = &pi->data.slice_hdr; + GstVaapiFrameStore *fs; + GstVaapiPictureH264 *f0, *f1; + + fs = priv->prev_frames[pi->voc]; + if (!fs) + return NULL; + + f0 = fs->buffers[0]; + if (!slice_hdr->field_pic_flag) { + if (!gst_vaapi_frame_store_has_frame (fs)) + fill_picture_other_field_gap (decoder, f0); + return NULL; + } + + /* At this point, the current frame is known to be interlaced */ + if (gst_vaapi_frame_store_has_frame (fs)) { + return NULL; + } + + /* At this point, the previous frame is interlaced and contains a + single field */ + if (f0->frame_num == slice_hdr->frame_num) { + f1 = f0; + if (same_field_parity (f0, slice_hdr)) { + fill_picture_other_field_gap (decoder, f0); + f1 = NULL; + } + return f1; + } + + fill_picture_other_field_gap (decoder, f0); + return NULL; +} + +static GstVaapiDecoderStatus +decode_picture (GstVaapiDecoderH264 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiParserInfoH264 *const pi = unit->parsed_info; + GstH264SliceHdr *const slice_hdr = &pi->data.slice_hdr; + GstH264PPS *const pps = ensure_pps (decoder, slice_hdr->pps); + GstH264SPS *const sps = ensure_sps (decoder, slice_hdr->pps->sequence); + GstVaapiPictureH264 *picture, *first_field; + GstVaapiDecoderStatus status; + + if (!(pps && sps)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + + status = ensure_context (decoder, sps); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + priv->decoder_state = 0; + + first_field = find_first_field (decoder, pi); + if (first_field) { + /* Re-use current picture where the first field was decoded */ + picture = gst_vaapi_picture_h264_new_field (first_field); + if (!picture) { + GST_ERROR ("failed to allocate field picture"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + } else { + /* Create new picture */ + picture = gst_vaapi_picture_h264_new (decoder); + if (!picture) { + GST_ERROR ("failed to allocate picture"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + } + gst_vaapi_picture_replace (&priv->current_picture, picture); + gst_vaapi_picture_unref (picture); + + /* Clear inter-view references list if this is the primary coded + picture of the current access unit */ + if (pi->flags & GST_VAAPI_DECODER_UNIT_FLAG_AU_START) + g_ptr_array_set_size (priv->inter_views, 0); + + /* Update cropping rectangle */ + if (sps->frame_cropping_flag) { + GstVaapiRectangle crop_rect; + crop_rect.x = sps->crop_rect_x; + crop_rect.y = sps->crop_rect_y; + crop_rect.width = sps->crop_rect_width; + crop_rect.height = sps->crop_rect_height; + gst_vaapi_picture_set_crop_rect (&picture->base, &crop_rect); + } + + status = ensure_quant_matrix (decoder, picture); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) { + GST_ERROR ("failed to reset quantizer matrix"); + return status; + } + + if (!init_picture (decoder, picture, pi)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + if (!fill_picture (decoder, picture)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + + priv->decoder_state = pi->state; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static inline guint +get_slice_data_bit_offset (GstH264SliceHdr * slice_hdr, guint nal_header_bytes) +{ + guint epb_count; + + epb_count = slice_hdr->n_emulation_prevention_bytes; + return 8 * nal_header_bytes + slice_hdr->header_size - epb_count * 8; +} + +static gboolean +fill_pred_weight_table (GstVaapiDecoderH264 * decoder, + GstVaapiSlice * slice, GstH264SliceHdr * slice_hdr) +{ + VASliceParameterBufferH264 *const slice_param = slice->param; + GstH264PPS *const pps = get_pps (decoder); + GstH264SPS *const sps = get_sps (decoder); + GstH264PredWeightTable *const w = &slice_hdr->pred_weight_table; + guint num_weight_tables = 0; + gint i, j; + + if (pps->weighted_pred_flag && + (GST_H264_IS_P_SLICE (slice_hdr) || GST_H264_IS_SP_SLICE (slice_hdr))) + num_weight_tables = 1; + else if (pps->weighted_bipred_idc == 1 && GST_H264_IS_B_SLICE (slice_hdr)) + num_weight_tables = 2; + else + num_weight_tables = 0; + + slice_param->luma_log2_weight_denom = 0; + slice_param->chroma_log2_weight_denom = 0; + slice_param->luma_weight_l0_flag = 0; + slice_param->chroma_weight_l0_flag = 0; + slice_param->luma_weight_l1_flag = 0; + slice_param->chroma_weight_l1_flag = 0; + + if (num_weight_tables < 1) + return TRUE; + + slice_param->luma_log2_weight_denom = w->luma_log2_weight_denom; + slice_param->chroma_log2_weight_denom = w->chroma_log2_weight_denom; + + slice_param->luma_weight_l0_flag = 1; + for (i = 0; i <= slice_param->num_ref_idx_l0_active_minus1; i++) { + slice_param->luma_weight_l0[i] = w->luma_weight_l0[i]; + slice_param->luma_offset_l0[i] = w->luma_offset_l0[i]; + } + + slice_param->chroma_weight_l0_flag = sps->chroma_array_type != 0; + if (slice_param->chroma_weight_l0_flag) { + for (i = 0; i <= slice_param->num_ref_idx_l0_active_minus1; i++) { + for (j = 0; j < 2; j++) { + slice_param->chroma_weight_l0[i][j] = w->chroma_weight_l0[i][j]; + slice_param->chroma_offset_l0[i][j] = w->chroma_offset_l0[i][j]; + } + } + } + + if (num_weight_tables < 2) + return TRUE; + + slice_param->luma_weight_l1_flag = 1; + for (i = 0; i <= slice_param->num_ref_idx_l1_active_minus1; i++) { + slice_param->luma_weight_l1[i] = w->luma_weight_l1[i]; + slice_param->luma_offset_l1[i] = w->luma_offset_l1[i]; + } + + slice_param->chroma_weight_l1_flag = sps->chroma_array_type != 0; + if (slice_param->chroma_weight_l1_flag) { + for (i = 0; i <= slice_param->num_ref_idx_l1_active_minus1; i++) { + for (j = 0; j < 2; j++) { + slice_param->chroma_weight_l1[i][j] = w->chroma_weight_l1[i][j]; + slice_param->chroma_offset_l1[i][j] = w->chroma_offset_l1[i][j]; + } + } + } + return TRUE; +} + +static gboolean +fill_RefPicList (GstVaapiDecoderH264 * decoder, + GstVaapiSlice * slice, GstH264SliceHdr * slice_hdr) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + VASliceParameterBufferH264 *const slice_param = slice->param; + guint i, num_ref_lists = 0; + + slice_param->num_ref_idx_l0_active_minus1 = 0; + slice_param->num_ref_idx_l1_active_minus1 = 0; + + /* ensure empty list by default */ + vaapi_init_picture (&slice_param->RefPicList0[0]); + vaapi_init_picture (&slice_param->RefPicList1[0]); + + if (GST_H264_IS_B_SLICE (slice_hdr)) + num_ref_lists = 2; + else if (GST_H264_IS_I_SLICE (slice_hdr)) + num_ref_lists = 0; + else + num_ref_lists = 1; + + if (num_ref_lists < 1) + return TRUE; + + slice_param->num_ref_idx_l0_active_minus1 = + slice_hdr->num_ref_idx_l0_active_minus1; + + for (i = 0; i < priv->RefPicList0_count && priv->RefPicList0[i]; i++) + vaapi_fill_picture_for_RefPicListX (&slice_param->RefPicList0[i], + priv->RefPicList0[i]); + if (i < 32) + vaapi_init_picture (&slice_param->RefPicList0[i]); + + if (num_ref_lists < 2) + return TRUE; + + slice_param->num_ref_idx_l1_active_minus1 = + slice_hdr->num_ref_idx_l1_active_minus1; + + for (i = 0; i < priv->RefPicList1_count && priv->RefPicList1[i]; i++) + vaapi_fill_picture_for_RefPicListX (&slice_param->RefPicList1[i], + priv->RefPicList1[i]); + if (i < 32) + vaapi_init_picture (&slice_param->RefPicList1[i]); + + return TRUE; +} + +static gboolean +fill_slice (GstVaapiDecoderH264 * decoder, + GstVaapiSlice * slice, GstVaapiParserInfoH264 * pi) +{ + VASliceParameterBufferH264 *const slice_param = slice->param; + GstH264SliceHdr *const slice_hdr = &pi->data.slice_hdr; + + /* Fill in VASliceParameterBufferH264 */ + slice_param->slice_data_bit_offset = + get_slice_data_bit_offset (slice_hdr, pi->nalu.header_bytes); + slice_param->first_mb_in_slice = slice_hdr->first_mb_in_slice; + slice_param->slice_type = slice_hdr->type % 5; + slice_param->direct_spatial_mv_pred_flag = + slice_hdr->direct_spatial_mv_pred_flag; + slice_param->cabac_init_idc = slice_hdr->cabac_init_idc; + slice_param->slice_qp_delta = slice_hdr->slice_qp_delta; + slice_param->disable_deblocking_filter_idc = + slice_hdr->disable_deblocking_filter_idc; + slice_param->slice_alpha_c0_offset_div2 = + slice_hdr->slice_alpha_c0_offset_div2; + slice_param->slice_beta_offset_div2 = slice_hdr->slice_beta_offset_div2; + + if (!fill_RefPicList (decoder, slice, slice_hdr)) + return FALSE; + if (!fill_pred_weight_table (decoder, slice, slice_hdr)) + return FALSE; + return TRUE; +} + +static GstVaapiDecoderStatus +decode_slice (GstVaapiDecoderH264 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiParserInfoH264 *const pi = unit->parsed_info; + GstVaapiPictureH264 *const picture = priv->current_picture; + GstH264SliceHdr *const slice_hdr = &pi->data.slice_hdr; + GstVaapiSlice *slice; + GstBuffer *const buffer = + GST_VAAPI_DECODER_CODEC_FRAME (decoder)->input_buffer; + GstMapInfo map_info; + + GST_DEBUG ("slice (%u bytes)", pi->nalu.size); + + if (!is_valid_state (pi->state, GST_H264_VIDEO_STATE_VALID_PICTURE_HEADERS)) { + GST_WARNING ("failed to receive enough headers to decode slice"); + return GST_VAAPI_DECODER_STATUS_SUCCESS; + } + + if (!ensure_pps (decoder, slice_hdr->pps)) { + GST_ERROR ("failed to activate PPS"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + if (!ensure_sps (decoder, slice_hdr->pps->sequence)) { + GST_ERROR ("failed to activate SPS"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) { + GST_ERROR ("failed to map buffer"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + /* Check wether this is the first/last slice in the current access unit */ + if (pi->flags & GST_VAAPI_DECODER_UNIT_FLAG_AU_START) + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_AU_START); + if (pi->flags & GST_VAAPI_DECODER_UNIT_FLAG_AU_END) + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_AU_END); + + slice = GST_VAAPI_SLICE_NEW (H264, decoder, + (map_info.data + unit->offset + pi->nalu.offset), pi->nalu.size); + gst_buffer_unmap (buffer, &map_info); + if (!slice) { + GST_ERROR ("failed to allocate slice"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + if (!init_picture_refs (decoder, picture, slice_hdr)) { + gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (slice)); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + if (!fill_slice (decoder, slice, pi)) { + gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (slice)); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + gst_vaapi_picture_add_slice (GST_VAAPI_PICTURE_CAST (picture), slice); + picture->last_slice_hdr = slice_hdr; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static inline gint +scan_for_start_code (GstAdapter * adapter, guint ofs, guint size, guint32 * scp) +{ + if (size == 0) + return -1; + + return (gint) gst_adapter_masked_scan_uint32_peek (adapter, + 0xffffff00, 0x00000100, ofs, size, scp); +} + +static GstVaapiDecoderStatus +decode_unit (GstVaapiDecoderH264 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiParserInfoH264 *const pi = unit->parsed_info; + GstVaapiDecoderStatus status; + + priv->decoder_state |= pi->state; + switch (pi->nalu.type) { + case GST_H264_NAL_SPS: + status = decode_sps (decoder, unit); + break; + case GST_H264_NAL_SUBSET_SPS: + status = decode_subset_sps (decoder, unit); + break; + case GST_H264_NAL_PPS: + status = decode_pps (decoder, unit); + break; + case GST_H264_NAL_SLICE_EXT: + case GST_H264_NAL_SLICE_IDR: + /* fall-through. IDR specifics are handled in init_picture() */ + case GST_H264_NAL_SLICE: + status = decode_slice (decoder, unit); + break; + case GST_H264_NAL_SEQ_END: + case GST_H264_NAL_STREAM_END: + status = decode_sequence_end (decoder); + break; + case GST_H264_NAL_SEI: + status = decode_sei (decoder, unit); + break; + case GST_H264_NAL_SLICE_DPA: + case GST_H264_NAL_SLICE_DPB: + case GST_H264_NAL_SLICE_DPC: + case GST_H264_NAL_AU_DELIMITER: + case GST_H264_NAL_FILLER_DATA: + case GST_H264_NAL_SPS_EXT: + case GST_H264_NAL_PREFIX_UNIT: + case GST_H264_NAL_DEPTH_SPS: + case GST_H264_NAL_SLICE_AUX: + case GST_H264_NAL_SLICE_DEPTH: + GST_DEBUG ("unsupported NAL unit type %d, just skip", pi->nalu.type); + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + break; + default: + GST_WARNING ("unknown NAL unit type id %d, skip", pi->nalu.type); + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + break; + } + return status; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_h264_decode_codec_data (GstVaapiDecoder * base_decoder, + const guchar * buf, guint buf_size) +{ + GstVaapiDecoderH264 *const decoder = + GST_VAAPI_DECODER_H264_CAST (base_decoder); + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiDecoderStatus status; + GstVaapiDecoderUnit unit; + GstVaapiParserInfoH264 *pi = NULL; + GstH264ParserResult result; + guint i, ofs, num_sps, num_pps; + + if (!priv->is_opened) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + unit.parsed_info = NULL; + + if (buf_size < 7) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + + if (buf[0] != 1) { + GST_ERROR ("failed to decode codec-data, not in avcC format"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + priv->nal_length_size = (buf[4] & 0x03) + 1; + + num_sps = buf[5] & 0x1f; + ofs = 6; + + for (i = 0; i < num_sps; i++) { + pi = gst_vaapi_parser_info_h264_new (); + if (!pi) + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + unit.parsed_info = pi; + + result = gst_h264_parser_identify_nalu_avc (priv->parser, + buf, ofs, buf_size, 2, &pi->nalu); + if (result != GST_H264_PARSER_OK) { + status = get_status (result); + goto cleanup; + } + + status = parse_sps (decoder, &unit); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + goto cleanup; + ofs = pi->nalu.offset + pi->nalu.size; + + pi->state = priv->parser_state; + pi->flags = 0; + + status = decode_sps (decoder, &unit); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + goto cleanup; + gst_vaapi_parser_info_h264_replace (&pi, NULL); + } + + num_pps = buf[ofs]; + ofs++; + + for (i = 0; i < num_pps; i++) { + pi = gst_vaapi_parser_info_h264_new (); + if (!pi) + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + unit.parsed_info = pi; + + result = gst_h264_parser_identify_nalu_avc (priv->parser, + buf, ofs, buf_size, 2, &pi->nalu); + if (result != GST_H264_PARSER_OK) { + status = get_status (result); + goto cleanup; + } + + status = parse_pps (decoder, &unit); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + goto cleanup; + ofs = pi->nalu.offset + pi->nalu.size; + + pi->state = priv->parser_state; + pi->flags = 0; + + status = decode_pps (decoder, &unit); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + goto cleanup; + gst_vaapi_parser_info_h264_replace (&pi, NULL); + } + + priv->is_avcC = TRUE; + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + +cleanup: + { + gst_vaapi_parser_info_h264_replace (&pi, NULL); + return status; + } +} + +static GstVaapiDecoderStatus +ensure_decoder (GstVaapiDecoderH264 * decoder) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiDecoderStatus status; + + if (!priv->is_opened) { + priv->is_opened = gst_vaapi_decoder_h264_open (decoder); + if (!priv->is_opened) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC; + + status = + gst_vaapi_decoder_decode_codec_data (GST_VAAPI_DECODER_CAST (decoder)); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_h264_parse (GstVaapiDecoder * base_decoder, + GstAdapter * adapter, gboolean at_eos, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH264 *const decoder = + GST_VAAPI_DECODER_H264_CAST (base_decoder); + GstVaapiDecoderH264Private *const priv = &decoder->priv; + GstVaapiParserState *const ps = GST_VAAPI_PARSER_STATE (base_decoder); + GstVaapiParserInfoH264 *pi; + GstVaapiDecoderStatus status; + GstH264ParserResult result; + guchar *buf; + guint i, size, buf_size, nalu_size, flags; + guint32 start_code; + gint ofs, ofs2; + gboolean at_au_end = FALSE; + + status = ensure_decoder (decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + switch (priv->stream_alignment) { + case GST_VAAPI_STREAM_ALIGN_H264_NALU: + case GST_VAAPI_STREAM_ALIGN_H264_AU: + size = gst_adapter_available_fast (adapter); + break; + default: + size = gst_adapter_available (adapter); + break; + } + + if (priv->is_avcC) { + if (size < priv->nal_length_size) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + + buf = (guchar *) & start_code; + g_assert (priv->nal_length_size <= sizeof (start_code)); + gst_adapter_copy (adapter, buf, 0, priv->nal_length_size); + + nalu_size = 0; + for (i = 0; i < priv->nal_length_size; i++) + nalu_size = (nalu_size << 8) | buf[i]; + + buf_size = priv->nal_length_size + nalu_size; + if (size < buf_size) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + else if (priv->stream_alignment == GST_VAAPI_STREAM_ALIGN_H264_AU) + at_au_end = (buf_size == size); + } else { + if (size < 4) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + + if (priv->stream_alignment == GST_VAAPI_STREAM_ALIGN_H264_NALU) { + buf_size = size; + ofs = scan_for_start_code (adapter, 4, size - 4, NULL); + if (ofs > 0) + buf_size = ofs; + } else { + ofs = scan_for_start_code (adapter, 0, size, NULL); + if (ofs < 0) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + + if (ofs > 0) { + gst_adapter_flush (adapter, ofs); + size -= ofs; + } + + ofs2 = ps->input_offset2 - ofs - 4; + if (ofs2 < 4) + ofs2 = 4; + + ofs = G_UNLIKELY (size < ofs2 + 4) ? -1 : + scan_for_start_code (adapter, ofs2, size - ofs2, NULL); + if (ofs < 0) { + // Assume the whole NAL unit is present if end-of-stream + // or stream buffers aligned on access unit boundaries + if (priv->stream_alignment == GST_VAAPI_STREAM_ALIGN_H264_AU) + at_au_end = TRUE; + else if (!at_eos) { + ps->input_offset2 = size; + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + } + ofs = size; + } + buf_size = ofs; + } + } + ps->input_offset2 = 0; + + buf = (guchar *) gst_adapter_map (adapter, buf_size); + if (!buf) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + + unit->size = buf_size; + + pi = gst_vaapi_parser_info_h264_new (); + if (!pi) + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + + gst_vaapi_decoder_unit_set_parsed_info (unit, + pi, (GDestroyNotify) gst_vaapi_mini_object_unref); + + if (priv->is_avcC) + result = gst_h264_parser_identify_nalu_avc (priv->parser, + buf, 0, buf_size, priv->nal_length_size, &pi->nalu); + else + result = gst_h264_parser_identify_nalu_unchecked (priv->parser, + buf, 0, buf_size, &pi->nalu); + status = get_status (result); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + goto exit; + + if (priv->base_only && (pi->nalu.type == GST_H264_NAL_PREFIX_UNIT + || pi->nalu.type == GST_H264_NAL_SUBSET_SPS + || pi->nalu.type == GST_H264_NAL_SLICE_EXT)) { + GST_VAAPI_DECODER_UNIT_FLAG_SET (unit, GST_VAAPI_DECODER_UNIT_FLAG_SKIP); + pi->nalu.valid = FALSE; + return GST_VAAPI_DECODER_STATUS_SUCCESS; + } + switch (pi->nalu.type) { + case GST_H264_NAL_SPS: + status = parse_sps (decoder, unit); + break; + case GST_H264_NAL_SUBSET_SPS: + status = parse_subset_sps (decoder, unit); + break; + case GST_H264_NAL_PPS: + status = parse_pps (decoder, unit); + break; + case GST_H264_NAL_SEI: + status = parse_sei (decoder, unit); + break; + case GST_H264_NAL_SLICE_EXT: + if (!GST_H264_IS_MVC_NALU (&pi->nalu)) { + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + break; + } + /* fall-through */ + case GST_H264_NAL_SLICE_IDR: + case GST_H264_NAL_SLICE: + status = parse_slice (decoder, unit); + break; + default: + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + break; + } + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + goto exit; + + flags = 0; + if (at_au_end) { + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END | + GST_VAAPI_DECODER_UNIT_FLAG_AU_END; + } + switch (pi->nalu.type) { + case GST_H264_NAL_AU_DELIMITER: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_AU_START; + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START; + /* fall-through */ + case GST_H264_NAL_FILLER_DATA: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP; + break; + case GST_H264_NAL_STREAM_END: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_STREAM_END; + /* fall-through */ + case GST_H264_NAL_SEQ_END: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END; + flags |= GST_VAAPI_DECODER_UNIT_FLAG_AU_END; + break; + case GST_H264_NAL_SPS: + case GST_H264_NAL_SUBSET_SPS: + case GST_H264_NAL_PPS: + case GST_H264_NAL_SEI: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_AU_START; + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START; + break; + case GST_H264_NAL_SLICE_EXT: + if (!GST_H264_IS_MVC_NALU (&pi->nalu)) { + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP; + break; + } + /* fall-through */ + case GST_H264_NAL_SLICE_IDR: + case GST_H264_NAL_SLICE: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE; + if (priv->prev_pi && + (priv->prev_pi->flags & GST_VAAPI_DECODER_UNIT_FLAG_AU_END)) { + flags |= GST_VAAPI_DECODER_UNIT_FLAG_AU_START | + GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START; + } else if (is_new_picture (pi, priv->prev_slice_pi)) { + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START; + if (is_new_access_unit (pi, priv->prev_slice_pi)) + flags |= GST_VAAPI_DECODER_UNIT_FLAG_AU_START; + } + gst_vaapi_parser_info_h264_replace (&priv->prev_slice_pi, pi); + break; + case GST_H264_NAL_SPS_EXT: + case GST_H264_NAL_SLICE_AUX: + /* skip SPS extension and auxiliary slice for now */ + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP; + break; + case GST_H264_NAL_PREFIX_UNIT: + /* skip Prefix NAL units for now */ + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP | + GST_VAAPI_DECODER_UNIT_FLAG_AU_START | + GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START; + break; + default: + if (pi->nalu.type >= 14 && pi->nalu.type <= 18) + flags |= GST_VAAPI_DECODER_UNIT_FLAG_AU_START | + GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START; + break; + } + if ((flags & GST_VAAPI_DECODER_UNIT_FLAGS_AU) && priv->prev_slice_pi) + priv->prev_slice_pi->flags |= GST_VAAPI_DECODER_UNIT_FLAG_AU_END; + GST_VAAPI_DECODER_UNIT_FLAG_SET (unit, flags); + + pi->nalu.data = NULL; + pi->state = priv->parser_state; + pi->flags = flags; + gst_vaapi_parser_info_h264_replace (&priv->prev_pi, pi); + return GST_VAAPI_DECODER_STATUS_SUCCESS; + +exit: + { + gst_adapter_flush (adapter, unit->size); + gst_vaapi_parser_info_h264_unref (pi); + return status; + } +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_h264_decode (GstVaapiDecoder * base_decoder, + GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH264 *const decoder = + GST_VAAPI_DECODER_H264_CAST (base_decoder); + GstVaapiDecoderStatus status; + + status = ensure_decoder (decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + return decode_unit (decoder, unit); +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_h264_start_frame (GstVaapiDecoder * base_decoder, + GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH264 *const decoder = + GST_VAAPI_DECODER_H264_CAST (base_decoder); + + return decode_picture (decoder, unit); +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_h264_end_frame (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderH264 *const decoder = + GST_VAAPI_DECODER_H264_CAST (base_decoder); + + return decode_current_picture (decoder); +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_h264_flush (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderH264 *const decoder = + GST_VAAPI_DECODER_H264_CAST (base_decoder); + + dpb_flush (decoder, NULL); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static void +gst_vaapi_decoder_h264_finalize (GObject * object) +{ + GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (object); + + gst_vaapi_decoder_h264_destroy (base_decoder); + G_OBJECT_CLASS (gst_vaapi_decoder_h264_parent_class)->finalize (object); +} + +static void +gst_vaapi_decoder_h264_class_init (GstVaapiDecoderH264Class * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstVaapiDecoderClass *const decoder_class = GST_VAAPI_DECODER_CLASS (klass); + + decoder_class->reset = gst_vaapi_decoder_h264_reset; + decoder_class->parse = gst_vaapi_decoder_h264_parse; + decoder_class->decode = gst_vaapi_decoder_h264_decode; + decoder_class->start_frame = gst_vaapi_decoder_h264_start_frame; + decoder_class->end_frame = gst_vaapi_decoder_h264_end_frame; + decoder_class->flush = gst_vaapi_decoder_h264_flush; + decoder_class->decode_codec_data = gst_vaapi_decoder_h264_decode_codec_data; + + object_class->finalize = gst_vaapi_decoder_h264_finalize; +} + +static void +gst_vaapi_decoder_h264_init (GstVaapiDecoderH264 * decoder) +{ + GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (decoder); + + gst_vaapi_decoder_h264_create (base_decoder); +} + +/** + * gst_vaapi_decoder_h264_set_alignment: + * @decoder: a #GstVaapiDecoderH264 + * @alignment: the #GstVaapiStreamAlignH264 + * + * Specifies how stream buffers are aligned / fed, i.e. the boundaries + * of each buffer that is supplied to the decoder. This could be no + * specific alignment, NAL unit boundaries, or access unit boundaries. + */ +void +gst_vaapi_decoder_h264_set_alignment (GstVaapiDecoderH264 * decoder, + GstVaapiStreamAlignH264 alignment) +{ + g_return_if_fail (decoder != NULL); + + decoder->priv.stream_alignment = alignment; +} + +/** + * gst_vaapi_decoder_h264_set_base_only: + * @decoder: a #GstVaapiDecoderH264 + * @base_only: %TRUE to force decoding the base view only + * + * if @base_only is %TRUE only the base view of MVC or SVC encoded streams + * is decoded. + * + **/ +void +gst_vaapi_decoder_h264_set_base_only (GstVaapiDecoderH264 * decoder, + gboolean base_only) +{ + g_return_if_fail (decoder != NULL); + + decoder->priv.base_only = base_only; +} + +/** + * gst_vaapi_decoder_h264_set_low_latency: + * @decoder: a #GstVaapiDecoderH264 + * @force_low_latency: %TRUE if force low latency + * + * if @force_low_latency is %TRUE the decoded frames are pushed soon + * as possible, instead of to wait until decoded picture buffer (DPB) + * release them. + * + * This violate the H.264 specification but it is useful for some live + * sources. + **/ +void +gst_vaapi_decoder_h264_set_low_latency (GstVaapiDecoderH264 * decoder, + gboolean force_low_latency) +{ + g_return_if_fail (decoder != NULL); + + decoder->priv.force_low_latency = force_low_latency; +} + +/** + * gst_vaapi_decoder_h264_get_low_latency: + * @decoder: a #GstVaapiDecoderH264 + * + * Returns: %TRUE if the low latency mode is enabled; otherwise + * %FALSE. + **/ +gboolean +gst_vaapi_decoder_h264_get_low_latency (GstVaapiDecoderH264 * decoder) +{ + g_return_val_if_fail (decoder != NULL, FALSE); + + return decoder->priv.force_low_latency; +} + +/** + * gst_vaapi_decoder_h264_new: + * @display: a #GstVaapiDisplay + * @caps: a #GstCaps holding codec information + * + * Creates a new #GstVaapiDecoder for MPEG-2 decoding. The @caps can + * hold extra information like codec-data and pictured coded size. + * + * Return value: the newly allocated #GstVaapiDecoder object + */ +GstVaapiDecoder * +gst_vaapi_decoder_h264_new (GstVaapiDisplay * display, GstCaps * caps) +{ + return g_object_new (GST_TYPE_VAAPI_DECODER_H264, "display", display, + "caps", caps, NULL); +} diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_h264.h b/gst-libs/gst/vaapi/gstvaapidecoder_h264.h new file mode 100644 index 0000000000..fd3f6c4bd0 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_h264.h @@ -0,0 +1,80 @@ +/* + * gstvaapidecoder_h264.h - H.264 decoder + * + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODER_H264_H +#define GST_VAAPI_DECODER_H264_H + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_DECODER_H264 \ + (gst_vaapi_decoder_h264_get_type ()) +#define GST_VAAPI_DECODER_H264(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DECODER_H264, GstVaapiDecoderH264)) +#define GST_VAAPI_IS_DECODER_H264(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_DECODER_H264)) + +typedef struct _GstVaapiDecoderH264 GstVaapiDecoderH264; + +/** + * GstVaapiStreamAlignH264: + * @GST_VAAPI_STREAM_ALIGN_H264_NONE: Generic H.264 stream buffers + * @GST_VAAPI_STREAM_ALIGN_H264_NALU: H.264 stream buffers aligned NAL + * unit boundaries + * @GST_VAAPI_STREAM_ALIGN_H264_AU: H.264 stream buffers aligned on + * access unit boundaries + * + * Set of possible buffer alignments for H.264 streams. + */ +typedef enum { + GST_VAAPI_STREAM_ALIGN_H264_NONE, + GST_VAAPI_STREAM_ALIGN_H264_NALU, + GST_VAAPI_STREAM_ALIGN_H264_AU +} GstVaapiStreamAlignH264; + +GType +gst_vaapi_decoder_h264_get_type (void) G_GNUC_CONST; + +GstVaapiDecoder * +gst_vaapi_decoder_h264_new (GstVaapiDisplay *display, GstCaps *caps); + +void +gst_vaapi_decoder_h264_set_alignment(GstVaapiDecoderH264 *decoder, + GstVaapiStreamAlignH264 alignment); + +gboolean +gst_vaapi_decoder_h264_get_low_latency(GstVaapiDecoderH264 * decoder); + +void +gst_vaapi_decoder_h264_set_low_latency(GstVaapiDecoderH264 * decoder, + gboolean force_low_latency); + +void +gst_vaapi_decoder_h264_set_base_only(GstVaapiDecoderH264 * decoder, + gboolean base_only); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDecoderH264, gst_object_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_DECODER_H264_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_h265.c b/gst-libs/gst/vaapi/gstvaapidecoder_h265.c new file mode 100644 index 0000000000..ad2588857b --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_h265.c @@ -0,0 +1,3408 @@ +/* + * gstvaapidecoder_h265.c - H.265 decoder + * + * Copyright (C) 2015 Intel Corporation + * Author: Sreerenj Balachandran + * + * 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:gstvaapidecoder_h265 + * @short_description: H.265 decoder + */ + +#include "sysdeps.h" +#include +#include +#include +#include "gstvaapicompat.h" +#include "gstvaapidecoder_h265.h" +#include "gstvaapidecoder_objects.h" +#include "gstvaapidecoder_priv.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapiutils_h265_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +/* Defined to 1 if strict ordering of DPB is needed. Only useful for debug */ +#define USE_STRICT_DPB_ORDERING 0 + +typedef struct _GstVaapiDecoderH265Private GstVaapiDecoderH265Private; +typedef struct _GstVaapiDecoderH265Class GstVaapiDecoderH265Class; +typedef struct _GstVaapiFrameStore GstVaapiFrameStore; +typedef struct _GstVaapiFrameStoreClass GstVaapiFrameStoreClass; +typedef struct _GstVaapiParserInfoH265 GstVaapiParserInfoH265; +typedef struct _GstVaapiPictureH265 GstVaapiPictureH265; + +static gboolean nal_is_slice (guint8 nal_type); + +/* ------------------------------------------------------------------------- */ +/* --- H.265 Parser Info --- */ +/* ------------------------------------------------------------------------- */ + +/* + * Extended decoder unit flags: + * + * @GST_VAAPI_DECODER_UNIT_AU_START: marks the start of an access unit. + * @GST_VAAPI_DECODER_UNIT_AU_END: marks the end of an access unit. + */ +enum +{ + GST_VAAPI_DECODER_UNIT_FLAG_AU_START = + (GST_VAAPI_DECODER_UNIT_FLAG_LAST << 0), + GST_VAAPI_DECODER_UNIT_FLAG_AU_END = (GST_VAAPI_DECODER_UNIT_FLAG_LAST << 1), + + GST_VAAPI_DECODER_UNIT_FLAGS_AU = (GST_VAAPI_DECODER_UNIT_FLAG_AU_START | + GST_VAAPI_DECODER_UNIT_FLAG_AU_END), +}; + +#define GST_VAAPI_PARSER_INFO_H265(obj) \ + ((GstVaapiParserInfoH265 *)(obj)) + +struct _GstVaapiParserInfoH265 +{ + GstVaapiMiniObject parent_instance; + GstH265NalUnit nalu; + union + { + GstH265VPS vps; + GstH265SPS sps; + GstH265PPS pps; + GArray *sei; + GstH265SliceHdr slice_hdr; + } data; + guint state; + guint flags; // Same as decoder unit flags (persistent) +}; + +static void +gst_vaapi_parser_info_h265_finalize (GstVaapiParserInfoH265 * pi) +{ + if (nal_is_slice (pi->nalu.type)) + gst_h265_slice_hdr_free (&pi->data.slice_hdr); + else { + switch (pi->nalu.type) { + case GST_H265_NAL_VPS: + case GST_H265_NAL_SPS: + case GST_H265_NAL_PPS: + break; + case GST_H265_NAL_PREFIX_SEI: + case GST_H265_NAL_SUFFIX_SEI: + if (pi->data.sei) { + g_array_unref (pi->data.sei); + pi->data.sei = NULL; + } + break; + } + } +} + +static inline const GstVaapiMiniObjectClass * +gst_vaapi_parser_info_h265_class (void) +{ + static const GstVaapiMiniObjectClass GstVaapiParserInfoH265Class = { + .size = sizeof (GstVaapiParserInfoH265), + .finalize = (GDestroyNotify) gst_vaapi_parser_info_h265_finalize + }; + return &GstVaapiParserInfoH265Class; +} + +static inline GstVaapiParserInfoH265 * +gst_vaapi_parser_info_h265_new (void) +{ + return (GstVaapiParserInfoH265 *) + gst_vaapi_mini_object_new (gst_vaapi_parser_info_h265_class ()); +} + +#define gst_vaapi_parser_info_h265_ref(pi) \ + gst_vaapi_mini_object_ref(GST_VAAPI_MINI_OBJECT(pi)) + +#define gst_vaapi_parser_info_h265_unref(pi) \ + gst_vaapi_mini_object_unref(GST_VAAPI_MINI_OBJECT(pi)) + +#define gst_vaapi_parser_info_h265_replace(old_pi_ptr, new_pi) \ + gst_vaapi_mini_object_replace((GstVaapiMiniObject **)(old_pi_ptr), \ + (GstVaapiMiniObject *)(new_pi)) + +/* ------------------------------------------------------------------------- */ +/* --- H.265 Pictures --- */ +/* ------------------------------------------------------------------------- */ + +/* + * Extended picture flags: + * + * @GST_VAAPI_PICTURE_FLAG_IDR: flag that specifies an IDR picture + * @GST_VAAPI_PICTURE_FLAG_AU_START: flag that marks the start of an + * access unit (AU) + * @GST_VAAPI_PICTURE_FLAG_AU_END: flag that marks the end of an + * access unit (AU) + * @GST_VAAPI_PICTURE_FLAG_RPS_ST_CURR_BEFORE: flag indicate the inclusion + * of picture in RefPicSetStCurrBefore reference list + * @GST_VAAPI_PICTURE_FLAG_RPS_ST_CURR_AFTER: flag indicate the inclusion + * of picture in RefPictSetStCurrAfter reference list + * @GST_VAAPI_PICTURE_FLAG_RPS_ST_FOLL: flag indicate the inclusion + * of picture in RefPicSetStFoll reference list + * @GST_VAAPI_PICTURE_FLAG_RPS_LT_CURR: flag indicate the inclusion + * of picture in RefPicSetLtCurr reference list + * @GST_VAAPI_PICTURE_FLAG_RPS_LT_FOLL: flag indicate the inclusion + * of picture in RefPicSetLtFoll reference list + * @GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE: flag that specifies + * "used for short-term reference" + * @GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE: flag that specifies + * "used for long-term reference" + * @GST_VAAPI_PICTURE_FLAGS_REFERENCE: mask covering any kind of + * reference picture (short-term reference or long-term reference) + */ +enum +{ + GST_VAAPI_PICTURE_FLAG_IDR = (GST_VAAPI_PICTURE_FLAG_LAST << 0), + GST_VAAPI_PICTURE_FLAG_REFERENCE2 = (GST_VAAPI_PICTURE_FLAG_LAST << 1), + GST_VAAPI_PICTURE_FLAG_AU_START = (GST_VAAPI_PICTURE_FLAG_LAST << 4), + GST_VAAPI_PICTURE_FLAG_AU_END = (GST_VAAPI_PICTURE_FLAG_LAST << 5), + GST_VAAPI_PICTURE_FLAG_RPS_ST_CURR_BEFORE = + (GST_VAAPI_PICTURE_FLAG_LAST << 6), + GST_VAAPI_PICTURE_FLAG_RPS_ST_CURR_AFTER = (GST_VAAPI_PICTURE_FLAG_LAST << 7), + GST_VAAPI_PICTURE_FLAG_RPS_ST_FOLL = (GST_VAAPI_PICTURE_FLAG_LAST << 8), + GST_VAAPI_PICTURE_FLAG_RPS_LT_CURR = (GST_VAAPI_PICTURE_FLAG_LAST << 9), + GST_VAAPI_PICTURE_FLAG_RPS_LT_FOLL = (GST_VAAPI_PICTURE_FLAG_LAST << 10), + + GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE = + (GST_VAAPI_PICTURE_FLAG_REFERENCE), + GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE = + (GST_VAAPI_PICTURE_FLAG_REFERENCE | GST_VAAPI_PICTURE_FLAG_REFERENCE2), + GST_VAAPI_PICTURE_FLAGS_REFERENCE = + (GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE | + GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE), + + GST_VAAPI_PICTURE_FLAGS_RPS_ST = + (GST_VAAPI_PICTURE_FLAG_RPS_ST_CURR_BEFORE | + GST_VAAPI_PICTURE_FLAG_RPS_ST_CURR_AFTER | + GST_VAAPI_PICTURE_FLAG_RPS_ST_FOLL), + GST_VAAPI_PICTURE_FLAGS_RPS_LT = + (GST_VAAPI_PICTURE_FLAG_RPS_LT_CURR | GST_VAAPI_PICTURE_FLAG_RPS_LT_FOLL), +}; + +#define GST_VAAPI_PICTURE_IS_IDR(picture) \ + (GST_VAAPI_PICTURE_FLAG_IS_SET(picture, GST_VAAPI_PICTURE_FLAG_IDR)) + +#define GST_VAAPI_PICTURE_IS_SHORT_TERM_REFERENCE(picture) \ + ((GST_VAAPI_PICTURE_FLAGS(picture) & \ + GST_VAAPI_PICTURE_FLAGS_REFERENCE) == \ + GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE) + +#define GST_VAAPI_PICTURE_IS_LONG_TERM_REFERENCE(picture) \ + ((GST_VAAPI_PICTURE_FLAGS(picture) & \ + GST_VAAPI_PICTURE_FLAGS_REFERENCE) == \ + GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE) + +#define GST_VAAPI_PICTURE_H265(picture) \ + ((GstVaapiPictureH265 *)(picture)) + +struct _GstVaapiPictureH265 +{ + GstVaapiPicture base; + GstH265SliceHdr *last_slice_hdr; + guint structure; + gint32 poc; // PicOrderCntVal (8.3.1) + gint32 poc_lsb; // slice_pic_order_cnt_lsb + guint32 pic_latency_cnt; // PicLatencyCount + guint output_flag:1; + guint output_needed:1; + guint NoRaslOutputFlag:1; + guint NoOutputOfPriorPicsFlag:1; + guint RapPicFlag:1; // nalu type between 16 and 21 + guint IntraPicFlag:1; // Intra pic (only Intra slices) +}; + +GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiPictureH265, gst_vaapi_picture_h265); + +void +gst_vaapi_picture_h265_destroy (GstVaapiPictureH265 * picture) +{ + gst_vaapi_picture_destroy (GST_VAAPI_PICTURE (picture)); +} + +gboolean +gst_vaapi_picture_h265_create (GstVaapiPictureH265 * picture, + const GstVaapiCodecObjectConstructorArgs * args) +{ + if (!gst_vaapi_picture_create (GST_VAAPI_PICTURE (picture), args)) + return FALSE; + + picture->structure = picture->base.structure; + picture->poc = G_MAXINT32; + picture->output_needed = FALSE; + return TRUE; +} + +static inline void +gst_vaapi_picture_h265_set_reference (GstVaapiPictureH265 * picture, + guint reference_flags) +{ + if (!picture) + return; + GST_VAAPI_PICTURE_FLAG_UNSET (picture, + GST_VAAPI_PICTURE_FLAGS_RPS_ST | GST_VAAPI_PICTURE_FLAGS_RPS_LT); + GST_VAAPI_PICTURE_FLAG_UNSET (picture, GST_VAAPI_PICTURE_FLAGS_REFERENCE); + GST_VAAPI_PICTURE_FLAG_SET (picture, reference_flags); +} + +/* ------------------------------------------------------------------------- */ +/* --- Frame Buffers (DPB) --- */ +/* ------------------------------------------------------------------------- */ + +struct _GstVaapiFrameStore +{ + /*< private > */ + GstVaapiMiniObject parent_instance; + + GstVaapiPictureH265 *buffer; +}; + +static void +gst_vaapi_frame_store_finalize (gpointer object) +{ + GstVaapiFrameStore *const fs = object; + + gst_vaapi_picture_replace (&fs->buffer, NULL); +} + +static GstVaapiFrameStore * +gst_vaapi_frame_store_new (GstVaapiPictureH265 * picture) +{ + GstVaapiFrameStore *fs; + + static const GstVaapiMiniObjectClass GstVaapiFrameStoreClass = { + sizeof (GstVaapiFrameStore), + gst_vaapi_frame_store_finalize + }; + + fs = (GstVaapiFrameStore *) + gst_vaapi_mini_object_new (&GstVaapiFrameStoreClass); + if (!fs) + return NULL; + + fs->buffer = gst_vaapi_picture_ref (picture); + + return fs; +} + +static inline gboolean +gst_vaapi_frame_store_has_reference (GstVaapiFrameStore * fs) +{ + if (GST_VAAPI_PICTURE_IS_REFERENCE (fs->buffer)) + return TRUE; + return FALSE; +} + +#define gst_vaapi_frame_store_ref(fs) \ + gst_vaapi_mini_object_ref(GST_VAAPI_MINI_OBJECT(fs)) + +#define gst_vaapi_frame_store_unref(fs) \ + gst_vaapi_mini_object_unref(GST_VAAPI_MINI_OBJECT(fs)) + +#define gst_vaapi_frame_store_replace(old_fs_p, new_fs) \ + gst_vaapi_mini_object_replace((GstVaapiMiniObject **)(old_fs_p), \ + (GstVaapiMiniObject *)(new_fs)) + +/* ------------------------------------------------------------------------- */ +/* --- H.265 Decoder --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_DECODER_H265_CAST(decoder) \ + ((GstVaapiDecoderH265 *)(decoder)) + +typedef enum +{ + GST_H265_VIDEO_STATE_GOT_VPS = 1 << 0, + GST_H265_VIDEO_STATE_GOT_SPS = 1 << 1, + GST_H265_VIDEO_STATE_GOT_PPS = 1 << 2, + GST_H265_VIDEO_STATE_GOT_SLICE = 1 << 3, + GST_H265_VIDEO_STATE_GOT_I_FRAME = 1 << 4, /* persistent across SPS */ + GST_H265_VIDEO_STATE_GOT_P_SLICE = 1 << 5, /* predictive (all non-intra) */ + + GST_H265_VIDEO_STATE_VALID_PICTURE_HEADERS = + (GST_H265_VIDEO_STATE_GOT_SPS | GST_H265_VIDEO_STATE_GOT_PPS), + GST_H265_VIDEO_STATE_VALID_PICTURE = + (GST_H265_VIDEO_STATE_VALID_PICTURE_HEADERS | + GST_H265_VIDEO_STATE_GOT_SLICE) +} GstH265VideoState; + +struct _GstVaapiDecoderH265Private +{ + GstH265Parser *parser; + guint parser_state; + guint decoder_state; + GstVaapiStreamAlignH265 stream_alignment; + GstVaapiPictureH265 *current_picture; + GstVaapiParserInfoH265 *vps[GST_H265_MAX_VPS_COUNT]; + GstVaapiParserInfoH265 *active_vps; + GstVaapiParserInfoH265 *sps[GST_H265_MAX_SPS_COUNT]; + GstVaapiParserInfoH265 *active_sps; + GstVaapiParserInfoH265 *pps[GST_H265_MAX_PPS_COUNT]; + GstVaapiParserInfoH265 *active_pps; + GstVaapiParserInfoH265 *prev_pi; + GstVaapiParserInfoH265 *prev_slice_pi; + GstVaapiParserInfoH265 *prev_independent_slice_pi; + GstVaapiFrameStore **dpb; + guint dpb_count; + guint dpb_size; + guint dpb_size_max; + GstVaapiProfile profile; + GstVaapiEntrypoint entrypoint; + GstVaapiChromaType chroma_type; + + GstVaapiPictureH265 *RefPicSetStCurrBefore[16]; + GstVaapiPictureH265 *RefPicSetStCurrAfter[16]; + GstVaapiPictureH265 *RefPicSetStFoll[16]; + GstVaapiPictureH265 *RefPicSetLtCurr[16]; + GstVaapiPictureH265 *RefPicSetLtFoll[16]; + + GstVaapiPictureH265 *RefPicList0[16]; + guint RefPicList0_count; + GstVaapiPictureH265 *RefPicList1[16]; + guint RefPicList1_count; + + guint32 SpsMaxLatencyPictures; + gint32 WpOffsetHalfRangeC; + + guint nal_length_size; + + guint pic_width_in_luma_samples; //sps->pic_width_in_luma_samples + guint pic_height_in_luma_samples; //sps->pic_height_in_luma_samples + guint pic_structure; // pic_struct (from SEI pic_timing() or inferred) + gint32 poc; // PicOrderCntVal + gint32 poc_msb; // PicOrderCntMsb + gint32 poc_lsb; // pic_order_cnt_lsb (from slice_header()) + gint32 prev_poc_msb; // prevPicOrderCntMsb + gint32 prev_poc_lsb; // prevPicOrderCntLsb + gint32 prev_tid0pic_poc_lsb; + gint32 prev_tid0pic_poc_msb; + gint32 PocStCurrBefore[16]; + gint32 PocStCurrAfter[16]; + gint32 PocStFoll[16]; + gint32 PocLtCurr[16]; + gint32 PocLtFoll[16]; + guint NumPocStCurrBefore; + guint NumPocStCurrAfter; + guint NumPocStFoll; + guint NumPocLtCurr; + guint NumPocLtFoll; + guint NumPocTotalCurr; + guint is_opened:1; + guint is_hvcC:1; + guint has_context:1; + guint progressive_sequence:1; + guint new_bitstream:1; + guint prev_nal_is_eos:1; /*previous nal type is EOS */ + guint associated_irap_NoRaslOutputFlag:1; +}; + +/** + * GstVaapiDecoderH265: + * + * A decoder based on H265. + */ +struct _GstVaapiDecoderH265 +{ + /*< private > */ + GstVaapiDecoder parent_instance; + GstVaapiDecoderH265Private priv; +}; + +/** + * GstVaapiDecoderH265Class: + * + * A decoder class based on H265. + */ +struct _GstVaapiDecoderH265Class +{ + /*< private > */ + GstVaapiDecoderClass parent_class; +}; + +G_DEFINE_TYPE (GstVaapiDecoderH265, gst_vaapi_decoder_h265, + GST_TYPE_VAAPI_DECODER); + +#define RSV_VCL_N10 10 +#define RSV_VCL_N12 12 +#define RSV_VCL_N14 14 + +static gboolean +nal_is_idr (guint8 nal_type) +{ + if ((nal_type == GST_H265_NAL_SLICE_IDR_W_RADL) || + (nal_type == GST_H265_NAL_SLICE_IDR_N_LP)) + return TRUE; + return FALSE; +} + +static gboolean +nal_is_irap (guint8 nal_type) +{ + if ((nal_type >= GST_H265_NAL_SLICE_BLA_W_LP) && + (nal_type <= RESERVED_IRAP_NAL_TYPE_MAX)) + return TRUE; + return FALSE; +} + +static gboolean +nal_is_bla (guint8 nal_type) +{ + if ((nal_type >= GST_H265_NAL_SLICE_BLA_W_LP) && + (nal_type <= GST_H265_NAL_SLICE_BLA_N_LP)) + return TRUE; + return FALSE; +} + +static gboolean +nal_is_cra (guint8 nal_type) +{ + if (nal_type == GST_H265_NAL_SLICE_CRA_NUT) + return TRUE; + return FALSE; +} + +static gboolean +nal_is_radl (guint8 nal_type) +{ + if ((nal_type >= GST_H265_NAL_SLICE_RADL_N) && + (nal_type <= GST_H265_NAL_SLICE_RADL_R)) + return TRUE; + return FALSE; +} + +static gboolean +nal_is_rasl (guint8 nal_type) +{ + if ((nal_type >= GST_H265_NAL_SLICE_RASL_N) && + (nal_type <= GST_H265_NAL_SLICE_RASL_R)) + return TRUE; + return FALSE; +} + +static gboolean +nal_is_slice (guint8 nal_type) +{ + if ((nal_type >= GST_H265_NAL_SLICE_TRAIL_N) && + (nal_type <= GST_H265_NAL_SLICE_CRA_NUT)) + return TRUE; + return FALSE; +} + +static gboolean +nal_is_ref (guint8 nal_type) +{ + gboolean ret = FALSE; + switch (nal_type) { + case GST_H265_NAL_SLICE_TRAIL_N: + case GST_H265_NAL_SLICE_TSA_N: + case GST_H265_NAL_SLICE_STSA_N: + case GST_H265_NAL_SLICE_RADL_N: + case GST_H265_NAL_SLICE_RASL_N: + case RSV_VCL_N10: + case RSV_VCL_N12: + case RSV_VCL_N14: + ret = FALSE; + break; + default: + ret = TRUE; + break; + } + return ret; +} + +static gboolean +is_range_extension_profile (GstVaapiProfile profile) +{ + if (profile == GST_VAAPI_PROFILE_H265_MAIN_422_10 + || profile == GST_VAAPI_PROFILE_H265_MAIN_444 + || profile == GST_VAAPI_PROFILE_H265_MAIN_444_10 + || profile == GST_VAAPI_PROFILE_H265_MAIN12 + || profile == GST_VAAPI_PROFILE_H265_MAIN_444_12 + || profile == GST_VAAPI_PROFILE_H265_MAIN_422_12) + return TRUE; + return FALSE; +} + +static gboolean +is_scc_profile (GstVaapiProfile profile) +{ +#if VA_CHECK_VERSION(1,2,0) + if (profile == GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN + || profile == GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_10 + || profile == GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444 +#if VA_CHECK_VERSION(1,8,0) + || profile == GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444_10 +#endif + ) + return TRUE; +#endif + return FALSE; +} + +static inline GstVaapiPictureH265 * +gst_vaapi_picture_h265_new (GstVaapiDecoderH265 * decoder) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + if (is_range_extension_profile (priv->profile) + || is_scc_profile (priv->profile)) { +#if VA_CHECK_VERSION(1,2,0) + return (GstVaapiPictureH265 *) + gst_vaapi_codec_object_new (&GstVaapiPictureH265Class, + GST_VAAPI_CODEC_BASE (decoder), NULL, + sizeof (VAPictureParameterBufferHEVCExtension), NULL, 0, 0); +#endif + return NULL; + } else { + return (GstVaapiPictureH265 *) + gst_vaapi_codec_object_new (&GstVaapiPictureH265Class, + GST_VAAPI_CODEC_BASE (decoder), NULL, + sizeof (VAPictureParameterBufferHEVC), NULL, 0, 0); + } +} + +/* Activates the supplied PPS */ +static GstH265PPS * +ensure_pps (GstVaapiDecoderH265 * decoder, GstH265PPS * pps) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiParserInfoH265 *const pi = priv->pps[pps->id]; + + gst_vaapi_parser_info_h265_replace (&priv->active_pps, pi); + return pi ? &pi->data.pps : NULL; +} + +/* Returns the active PPS */ +static inline GstH265PPS * +get_pps (GstVaapiDecoderH265 * decoder) +{ + GstVaapiParserInfoH265 *const pi = decoder->priv.active_pps; + + return pi ? &pi->data.pps : NULL; +} + +/* Activate the supplied SPS */ +static GstH265SPS * +ensure_sps (GstVaapiDecoderH265 * decoder, GstH265SPS * sps) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiParserInfoH265 *const pi = priv->sps[sps->id]; + + /* Propagate "got I-frame" state to the next SPS unit if the current + * sequence was not ended */ + if (pi && priv->active_sps) + pi->state |= (priv->active_sps->state & GST_H265_VIDEO_STATE_GOT_I_FRAME); + + gst_vaapi_parser_info_h265_replace (&priv->active_sps, pi); + return pi ? &pi->data.sps : NULL; +} + +/* Returns the active SPS */ +static inline GstH265SPS * +get_sps (GstVaapiDecoderH265 * decoder) +{ + GstVaapiParserInfoH265 *const pi = decoder->priv.active_sps; + + return pi ? &pi->data.sps : NULL; +} + +/* VPS nal is not necessary to decode the base layers, so this is not + * needed at the moment. But in future we need this, especially when + * dealing with MVC and scalable layer decoding. + * See https://bugzilla.gnome.org/show_bug.cgi?id=754250 + */ +#if 0 +/* Activate the supplied VPS */ +static GstH265VPS * +ensure_vps (GstVaapiDecoderH265 * decoder, GstH265VPS * vps) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiParserInfoH265 *const pi = priv->vps[vps->id]; + + gst_vaapi_parser_info_h265_replace (&priv->active_vps, pi); + return pi ? &pi->data.vps : NULL; +} + +/* Returns the active VPS */ +static inline GstH265VPS * +get_vps (GstVaapiDecoderH265 * decoder) +{ + GstVaapiParserInfoH265 *const pi = decoder->priv.active_vps; + return pi ? &pi->data.vps : NULL; +} +#endif + +/* Get number of reference frames to use */ +static guint +get_max_dec_frame_buffering (GstH265SPS * sps) +{ + G_GNUC_UNUSED guint max_dec_frame_buffering; /* FIXME */ + GstVaapiLevelH265 level; + const GstVaapiH265LevelLimits *level_limits; + + level = gst_vaapi_utils_h265_get_level (sps->profile_tier_level.level_idc); + level_limits = gst_vaapi_utils_h265_get_level_limits (level); + if (G_UNLIKELY (!level_limits)) { + GST_FIXME ("unsupported level_idc value (%d)", + sps->profile_tier_level.level_idc); + max_dec_frame_buffering = 16; + } + + /* FIXME: Add limit check based on Annex A */ + + /* Assuming HighestTid as sps_max_sub_layers_minus1 */ + return MAX (1, + (sps->max_dec_pic_buffering_minus1[sps->max_sub_layers_minus1] + 1)); +} + +static void +dpb_remove_all (GstVaapiDecoderH265 * decoder) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + + while (priv->dpb_count > 0) + gst_vaapi_frame_store_replace (&priv->dpb[--priv->dpb_count], NULL); +} + +static void +dpb_remove_index (GstVaapiDecoderH265 * decoder, gint index) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + guint i, num_frames = --priv->dpb_count; + + if (USE_STRICT_DPB_ORDERING) { + for (i = index; i < num_frames; i++) + gst_vaapi_frame_store_replace (&priv->dpb[i], priv->dpb[i + 1]); + } else if (index != num_frames) + gst_vaapi_frame_store_replace (&priv->dpb[index], priv->dpb[num_frames]); + gst_vaapi_frame_store_replace (&priv->dpb[num_frames], NULL); +} + +static gboolean +dpb_output (GstVaapiDecoderH265 * decoder, GstVaapiFrameStore * fs) +{ + GstVaapiPictureH265 *picture; + + g_return_val_if_fail (fs != NULL, FALSE); + + picture = fs->buffer; + if (!picture) + return FALSE; + + picture->output_needed = FALSE; + return gst_vaapi_picture_output (GST_VAAPI_PICTURE_CAST (picture)); +} + +/* Get the dpb picture having the specifed poc or poc_lsb */ +static GstVaapiPictureH265 * +dpb_get_picture (GstVaapiDecoderH265 * decoder, gint poc, gboolean match_lsb) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + guint i; + + for (i = 0; i < priv->dpb_count; i++) { + GstVaapiPictureH265 *const picture = priv->dpb[i]->buffer; + + if (picture && GST_VAAPI_PICTURE_FLAG_IS_SET (picture, + GST_VAAPI_PICTURE_FLAGS_REFERENCE)) { + if (match_lsb) { + if (picture->poc_lsb == poc) + return picture; + } else { + if (picture->poc == poc) + return picture; + } + } + } + return NULL; +} + +/* Get the dpb picture having the specifed poc and shor/long ref flags */ +static GstVaapiPictureH265 * +dpb_get_ref_picture (GstVaapiDecoderH265 * decoder, gint poc, gboolean is_short) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + guint i; + + for (i = 0; i < priv->dpb_count; i++) { + GstVaapiPictureH265 *const picture = priv->dpb[i]->buffer; + + if (picture && picture->poc == poc) { + if (is_short && GST_VAAPI_PICTURE_IS_SHORT_TERM_REFERENCE (picture)) + return picture; + else if (GST_VAAPI_PICTURE_IS_LONG_TERM_REFERENCE (picture)) + return picture; + } + } + + return NULL; +} + +/* Finds the picture with the lowest POC that needs to be output */ +static gint +dpb_find_lowest_poc (GstVaapiDecoderH265 * decoder, + GstVaapiPictureH265 ** found_picture_ptr) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiPictureH265 *found_picture = NULL; + guint i, found_index = -1; + + for (i = 0; i < priv->dpb_count; i++) { + GstVaapiPictureH265 *const picture = priv->dpb[i]->buffer; + if (picture && !picture->output_needed) + continue; + if (picture && (!found_picture || found_picture->poc > picture->poc)) { + found_picture = picture; + found_index = i; + } + } + + if (found_picture_ptr) + *found_picture_ptr = found_picture; + return found_index; +} + +static gboolean +dpb_bump (GstVaapiDecoderH265 * decoder, GstVaapiPictureH265 * picture) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiPictureH265 *found_picture; + gint found_index; + gboolean success; + + found_index = dpb_find_lowest_poc (decoder, &found_picture); + if (found_index < 0) + return FALSE; + + success = dpb_output (decoder, priv->dpb[found_index]); + + if (!gst_vaapi_frame_store_has_reference (priv->dpb[found_index])) + dpb_remove_index (decoder, found_index); + + return success; +} + +static void +dpb_clear (GstVaapiDecoderH265 * decoder, gboolean hard_flush) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiPictureH265 *pic; + guint i; + + if (hard_flush) { + dpb_remove_all (decoder); + } else { + /* Remove unused pictures from DPB */ + i = 0; + while (i < priv->dpb_count) { + GstVaapiFrameStore *const fs = priv->dpb[i]; + pic = fs->buffer; + if (!pic->output_needed && !gst_vaapi_frame_store_has_reference (fs)) + dpb_remove_index (decoder, i); + else + i++; + } + } +} + +static void +dpb_flush (GstVaapiDecoderH265 * decoder) +{ + /* Output any frame remaining in DPB */ + while (dpb_bump (decoder, NULL)); + dpb_clear (decoder, TRUE); +} + +static gint +dpb_get_num_need_output (GstVaapiDecoderH265 * decoder) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + guint i = 0, n_output_needed = 0; + + while (i < priv->dpb_count) { + GstVaapiFrameStore *const fs = priv->dpb[i]; + if (fs->buffer->output_needed) + n_output_needed++; + i++; + } + + return n_output_needed; +} + +static gboolean +check_latency_cnt (GstVaapiDecoderH265 * decoder) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiPictureH265 *tmp_pic; + guint i = 0; + + while (i < priv->dpb_count) { + GstVaapiFrameStore *const fs = priv->dpb[i]; + tmp_pic = fs->buffer; + if (tmp_pic->output_needed) { + if (tmp_pic->pic_latency_cnt >= priv->SpsMaxLatencyPictures) + return TRUE; + } + i++; + } + + return FALSE; +} + +static gboolean +dpb_add (GstVaapiDecoderH265 * decoder, GstVaapiPictureH265 * picture) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstH265SPS *const sps = get_sps (decoder); + GstVaapiFrameStore *fs; + GstVaapiPictureH265 *tmp_pic; + guint i = 0; + + /* C.5.2.3 */ + if (picture->output_flag) { + while (i < priv->dpb_count) { + GstVaapiFrameStore *const fs = priv->dpb[i]; + tmp_pic = fs->buffer; + if (tmp_pic->output_needed) + tmp_pic->pic_latency_cnt += 1; + i++; + } + } + + /* Create new frame store */ + fs = gst_vaapi_frame_store_new (picture); + if (!fs) + return FALSE; + gst_vaapi_frame_store_replace (&priv->dpb[priv->dpb_count++], fs); + gst_vaapi_frame_store_unref (fs); + + if (picture->output_flag) { + picture->output_needed = 1; + picture->pic_latency_cnt = 0; + } else + picture->output_needed = 0; + + /* set pic as short_term_ref */ + gst_vaapi_picture_h265_set_reference (picture, + GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE); + + /* C.5.2.4 "Bumping" process */ + while ((dpb_get_num_need_output (decoder) > + sps->max_num_reorder_pics[sps->max_sub_layers_minus1]) + || (sps->max_latency_increase_plus1[sps->max_sub_layers_minus1] + && check_latency_cnt (decoder))) + dpb_bump (decoder, picture); + + return TRUE; +} + + +/* C.5.2.2 */ +static gboolean +dpb_init (GstVaapiDecoderH265 * decoder, GstVaapiPictureH265 * picture, + GstVaapiParserInfoH265 * pi) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstH265SliceHdr *const slice_hdr = &pi->data.slice_hdr; + GstH265SPS *const sps = get_sps (decoder); + + if (nal_is_irap (pi->nalu.type) + && picture->NoRaslOutputFlag && !priv->new_bitstream) { + + if (pi->nalu.type == GST_H265_NAL_SLICE_CRA_NUT) + picture->NoOutputOfPriorPicsFlag = 1; + else + picture->NoOutputOfPriorPicsFlag = + slice_hdr->no_output_of_prior_pics_flag; + + if (picture->NoOutputOfPriorPicsFlag) + dpb_clear (decoder, TRUE); + else { + dpb_clear (decoder, FALSE); + while (dpb_bump (decoder, NULL)); + } + } else { + dpb_clear (decoder, FALSE); + while ((dpb_get_num_need_output (decoder) > + sps->max_num_reorder_pics[sps->max_sub_layers_minus1]) + || (sps->max_latency_increase_plus1[sps->max_sub_layers_minus1] + && check_latency_cnt (decoder)) + || (priv->dpb_count >= + (sps->max_dec_pic_buffering_minus1[sps->max_sub_layers_minus1] + + 1))) { + dpb_bump (decoder, picture); + } + } + + return TRUE; +} + +static gboolean +dpb_reset (GstVaapiDecoderH265 * decoder, guint dpb_size) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + + if (dpb_size > priv->dpb_size_max) { + priv->dpb = g_try_realloc_n (priv->dpb, dpb_size, sizeof (*priv->dpb)); + if (!priv->dpb) + return FALSE; + memset (&priv->dpb[priv->dpb_size_max], 0, + (dpb_size - priv->dpb_size_max) * sizeof (*priv->dpb)); + priv->dpb_size_max = dpb_size; + } + priv->dpb_size = dpb_size; + GST_DEBUG ("DPB size %u", priv->dpb_size); + return TRUE; +} + +static GstVaapiDecoderStatus +get_status (GstH265ParserResult result) +{ + GstVaapiDecoderStatus status; + + switch (result) { + case GST_H265_PARSER_OK: + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + break; + case GST_H265_PARSER_NO_NAL_END: + status = GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + break; + case GST_H265_PARSER_ERROR: + status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + break; + default: + status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + break; + } + return status; +} + +static void +gst_vaapi_decoder_h265_close (GstVaapiDecoderH265 * decoder) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + + gst_vaapi_picture_replace (&priv->current_picture, NULL); + gst_vaapi_parser_info_h265_replace (&priv->prev_slice_pi, NULL); + gst_vaapi_parser_info_h265_replace (&priv->prev_independent_slice_pi, NULL); + gst_vaapi_parser_info_h265_replace (&priv->prev_pi, NULL); + + dpb_clear (decoder, TRUE); + + if (priv->parser) { + gst_h265_parser_free (priv->parser); + priv->parser = NULL; + } + + priv->is_opened = FALSE; +} + +static gboolean +gst_vaapi_decoder_h265_open (GstVaapiDecoderH265 * decoder) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + + gst_vaapi_decoder_h265_close (decoder); + priv->parser = gst_h265_parser_new (); + if (!priv->parser) + return FALSE; + return TRUE; +} + +static void +gst_vaapi_decoder_h265_destroy (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderH265 *const decoder = + GST_VAAPI_DECODER_H265_CAST (base_decoder); + GstVaapiDecoderH265Private *const priv = &decoder->priv; + guint i; + + gst_vaapi_decoder_h265_close (decoder); + g_clear_pointer (&priv->dpb, g_free); + priv->dpb_count = priv->dpb_size_max = priv->dpb_size = 0; + + for (i = 0; i < G_N_ELEMENTS (priv->pps); i++) + gst_vaapi_parser_info_h265_replace (&priv->pps[i], NULL); + gst_vaapi_parser_info_h265_replace (&priv->active_pps, NULL); + for (i = 0; i < G_N_ELEMENTS (priv->sps); i++) + gst_vaapi_parser_info_h265_replace (&priv->sps[i], NULL); + gst_vaapi_parser_info_h265_replace (&priv->active_sps, NULL); + for (i = 0; i < G_N_ELEMENTS (priv->vps); i++) + gst_vaapi_parser_info_h265_replace (&priv->vps[i], NULL); + gst_vaapi_parser_info_h265_replace (&priv->active_vps, NULL); +} + +static gboolean +gst_vaapi_decoder_h265_create (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderH265 *const decoder = + GST_VAAPI_DECODER_H265_CAST (base_decoder); + GstVaapiDecoderH265Private *const priv = &decoder->priv; + + priv->profile = GST_VAAPI_PROFILE_UNKNOWN; + priv->entrypoint = GST_VAAPI_ENTRYPOINT_VLD; + priv->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420; + priv->progressive_sequence = TRUE; + priv->new_bitstream = TRUE; + priv->prev_nal_is_eos = FALSE; + return TRUE; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_h265_reset (GstVaapiDecoder * base_decoder) +{ + gst_vaapi_decoder_h265_destroy (base_decoder); + gst_vaapi_decoder_h265_create (base_decoder); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static void +fill_profiles (GstVaapiProfile profiles[16], guint * n_profiles_ptr, + GstVaapiProfile profile) +{ + guint n_profiles = *n_profiles_ptr; + + profiles[n_profiles++] = profile; + switch (profile) { + case GST_VAAPI_PROFILE_H265_MAIN: + profiles[n_profiles++] = GST_VAAPI_PROFILE_H265_MAIN10; + break; + case GST_VAAPI_PROFILE_H265_MAIN_STILL_PICTURE: + profiles[n_profiles++] = GST_VAAPI_PROFILE_H265_MAIN; + profiles[n_profiles++] = GST_VAAPI_PROFILE_H265_MAIN10; + break; + default: + break; + } + *n_profiles_ptr = n_profiles; +} + +static GstVaapiProfile +get_profile (GstVaapiDecoderH265 * decoder, GstH265SPS * sps, guint dpb_size) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiDisplay *const display = GST_VAAPI_DECODER_DISPLAY (decoder); + GstVaapiProfile profile, profiles[3]; + guint i, n_profiles = 0; + + profile = gst_vaapi_utils_h265_get_profile (sps); + if (!profile) { + /* HACK: This is a work-around to identify some main profile streams having wrong profile_idc. + * There are some wrongly encoded main profile streams(eg: ENTP_C_LG_3.bin) which doesn't + * have any of the profile_idc values mentioned in Annex-A, instead general_profile_idc + * has been set as zero and having general_profile_compatibility_flag[general_profile_idc] + * is TRUE. Assuming them as MAIN profile for now */ + if (sps->profile_tier_level.profile_space == 0 && + sps->profile_tier_level.profile_idc == 0 && + sps->profile_tier_level.profile_compatibility_flag[0] == 1) { + GST_WARNING ("Wrong profile_idc, blindly setting it as main profile !!"); + profile = GST_VAAPI_PROFILE_H265_MAIN; + } else + return GST_VAAPI_PROFILE_UNKNOWN; + } + + fill_profiles (profiles, &n_profiles, profile); + switch (profile) { + case GST_VAAPI_PROFILE_H265_MAIN10: + if (sps->profile_tier_level.profile_compatibility_flag[1]) { // A.2.3.2 (main profile) + fill_profiles (profiles, &n_profiles, GST_VAAPI_PROFILE_H265_MAIN); + } + break; + default: + break; + } + + /* If the preferred profile (profiles[0]) matches one that we already + found, then just return it now instead of searching for it again */ + if (profiles[0] == priv->profile) + return priv->profile; + for (i = 0; i < n_profiles; i++) { + if (gst_vaapi_display_has_decoder (display, profiles[i], priv->entrypoint)) + return profiles[i]; + } + return GST_VAAPI_PROFILE_UNKNOWN; +} + +static GstVaapiDecoderStatus +ensure_context (GstVaapiDecoderH265 * decoder, GstH265SPS * sps) +{ + GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER_CAST (decoder); + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiContextInfo info; + GstVaapiProfile profile; + GstVaapiChromaType chroma_type; + gboolean reset_context = FALSE; + guint dpb_size; + + dpb_size = get_max_dec_frame_buffering (sps); + if (priv->dpb_size < dpb_size) { + GST_DEBUG ("DPB size increased"); + reset_context = TRUE; + } + + profile = get_profile (decoder, sps, dpb_size); + if (!profile) { + GST_ERROR ("unsupported profile_idc %u", + sps->profile_tier_level.profile_idc); + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + } + + if (!priv->profile || (priv->profile != profile)) { + GST_DEBUG ("profile changed"); + reset_context = TRUE; + priv->profile = profile; + } + + chroma_type = + gst_vaapi_utils_h265_get_chroma_type (sps->chroma_format_idc, + sps->bit_depth_luma_minus8 + 8, sps->bit_depth_chroma_minus8 + 8); + if (!chroma_type) { + GST_ERROR ("unsupported chroma_format_idc %u", sps->chroma_format_idc); + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT; + } + + if (priv->chroma_type != chroma_type) { + GST_DEBUG ("chroma format changed"); + reset_context = TRUE; + priv->chroma_type = chroma_type; + } + + if (priv->pic_width_in_luma_samples != sps->pic_width_in_luma_samples || + priv->pic_height_in_luma_samples != sps->pic_height_in_luma_samples) { + GST_DEBUG ("size changed"); + reset_context = TRUE; + priv->pic_width_in_luma_samples = sps->pic_width_in_luma_samples; + priv->pic_height_in_luma_samples = sps->pic_height_in_luma_samples; + } + + priv->progressive_sequence = 1; /* FIXME */ + gst_vaapi_decoder_set_interlaced (base_decoder, !priv->progressive_sequence); + gst_vaapi_decoder_set_pixel_aspect_ratio (base_decoder, + sps->vui_params.par_n, sps->vui_params.par_d); + if (!reset_context && priv->has_context) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + /* XXX: fix surface size when cropping is implemented */ + info.profile = priv->profile; + info.entrypoint = priv->entrypoint; + info.chroma_type = priv->chroma_type; + info.width = sps->width; + info.height = sps->height; + info.ref_frames = dpb_size; + + if (!gst_vaapi_decoder_ensure_context (GST_VAAPI_DECODER (decoder), &info)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + priv->has_context = TRUE; + + /* Reset DPB */ + if (!dpb_reset (decoder, dpb_size)) + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static void +fill_iq_matrix_4x4 (VAIQMatrixBufferHEVC * iq_matrix, + GstH265ScalingList * scaling_list) +{ + guint i; + + g_assert (G_N_ELEMENTS (iq_matrix->ScalingList4x4) == 6); + g_assert (G_N_ELEMENTS (iq_matrix->ScalingList4x4[0]) == 16); + for (i = 0; i < G_N_ELEMENTS (iq_matrix->ScalingList4x4); i++) { + gst_h265_quant_matrix_4x4_get_raster_from_uprightdiagonal + (iq_matrix->ScalingList4x4[i], scaling_list->scaling_lists_4x4[i]); + } +} + +static void +fill_iq_matrix_8x8 (VAIQMatrixBufferHEVC * iq_matrix, + GstH265ScalingList * scaling_list) +{ + guint i; + + g_assert (G_N_ELEMENTS (iq_matrix->ScalingList8x8) == 6); + g_assert (G_N_ELEMENTS (iq_matrix->ScalingList8x8[0]) == 64); + for (i = 0; i < G_N_ELEMENTS (iq_matrix->ScalingList8x8); i++) { + gst_h265_quant_matrix_8x8_get_raster_from_uprightdiagonal + (iq_matrix->ScalingList8x8[i], scaling_list->scaling_lists_8x8[i]); + } +} + +static void +fill_iq_matrix_16x16 (VAIQMatrixBufferHEVC * iq_matrix, + GstH265ScalingList * scaling_list) +{ + guint i; + + g_assert (G_N_ELEMENTS (iq_matrix->ScalingList16x16) == 6); + g_assert (G_N_ELEMENTS (iq_matrix->ScalingList16x16[0]) == 64); + for (i = 0; i < G_N_ELEMENTS (iq_matrix->ScalingList16x16); i++) { + gst_h265_quant_matrix_16x16_get_raster_from_uprightdiagonal + (iq_matrix->ScalingList16x16[i], scaling_list->scaling_lists_16x16[i]); + } +} + +static void +fill_iq_matrix_32x32 (VAIQMatrixBufferHEVC * iq_matrix, + GstH265ScalingList * scaling_list) +{ + guint i; + + g_assert (G_N_ELEMENTS (iq_matrix->ScalingList32x32) == 2); + g_assert (G_N_ELEMENTS (iq_matrix->ScalingList32x32[0]) == 64); + for (i = 0; i < G_N_ELEMENTS (iq_matrix->ScalingList32x32); i++) { + gst_h265_quant_matrix_32x32_get_raster_from_uprightdiagonal + (iq_matrix->ScalingList32x32[i], scaling_list->scaling_lists_32x32[i]); + } +} + +static void +fill_iq_matrix_dc_16x16 (VAIQMatrixBufferHEVC * iq_matrix, + GstH265ScalingList * scaling_list) +{ + guint i; + + for (i = 0; i < 6; i++) + iq_matrix->ScalingListDC16x16[i] = + scaling_list->scaling_list_dc_coef_minus8_16x16[i] + 8; +} + +static void +fill_iq_matrix_dc_32x32 (VAIQMatrixBufferHEVC * iq_matrix, + GstH265ScalingList * scaling_list) +{ + guint i; + + for (i = 0; i < 2; i++) + iq_matrix->ScalingListDC32x32[i] = + scaling_list->scaling_list_dc_coef_minus8_32x32[i] + 8; +} + +static GstVaapiDecoderStatus +ensure_quant_matrix (GstVaapiDecoderH265 * decoder, + GstVaapiPictureH265 * picture) +{ + GstVaapiPicture *const base_picture = &picture->base; + GstH265PPS *const pps = get_pps (decoder); + GstH265SPS *const sps = get_sps (decoder); + GstH265ScalingList *scaling_list = NULL; + VAIQMatrixBufferHEVC *iq_matrix; + + if (pps && + (pps->scaling_list_data_present_flag || + (sps->scaling_list_enabled_flag + && !sps->scaling_list_data_present_flag))) + scaling_list = &pps->scaling_list; + else if (sps && sps->scaling_list_enabled_flag + && sps->scaling_list_data_present_flag) + scaling_list = &sps->scaling_list; + else + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + base_picture->iq_matrix = GST_VAAPI_IQ_MATRIX_NEW (HEVC, decoder); + if (!base_picture->iq_matrix) { + GST_ERROR ("failed to allocate IQ matrix"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + iq_matrix = base_picture->iq_matrix->param; + + fill_iq_matrix_4x4 (iq_matrix, scaling_list); + fill_iq_matrix_8x8 (iq_matrix, scaling_list); + fill_iq_matrix_16x16 (iq_matrix, scaling_list); + fill_iq_matrix_32x32 (iq_matrix, scaling_list); + fill_iq_matrix_dc_16x16 (iq_matrix, scaling_list); + fill_iq_matrix_dc_32x32 (iq_matrix, scaling_list); + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static inline gboolean +is_valid_state (guint state, guint ref_state) +{ + return (state & ref_state) == ref_state; +} + +static GstVaapiDecoderStatus +decode_current_picture (GstVaapiDecoderH265 * decoder) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiParserInfoH265 *const sps_pi = decoder->priv.active_sps; + GstVaapiPictureH265 *const picture = priv->current_picture; + + if (!is_valid_state (priv->decoder_state, GST_H265_VIDEO_STATE_VALID_PICTURE)) { + goto drop_frame; + } + + priv->decoder_state |= sps_pi->state; + if (!(priv->decoder_state & GST_H265_VIDEO_STATE_GOT_I_FRAME)) { + const GstH265PPS *pps = get_pps (decoder); + /* 7.4.3.3.3: the picture is an IRAP picture, nuh_layer_id is equal to 0, + and pps_curr_pic_ref_enabled_flag is equal to 0, slice_type shall be + equal to 2(I Slice). + And F.8.3.4: Decoding process for reference picture lists construction + is invoked at the beginning of the decoding process for each P or B + slice. + so if pps_curr_pic_ref_enabled_flag is set, which means the picture can + ref to itself, the IRAP picture may be set to P/B slice, in order to + generate the ref lists. If the slice_type is I, no ref list will be + constructed and no MV data for that slice according to the syntax. + That kind of CVS may start with P/B slice, but in fact it is a intra + frame. */ + if (priv->decoder_state & GST_H265_VIDEO_STATE_GOT_P_SLICE && + !pps->pps_scc_extension_params.pps_curr_pic_ref_enabled_flag) + goto drop_frame; + sps_pi->state |= GST_H265_VIDEO_STATE_GOT_I_FRAME; + } + + priv->decoder_state = 0; + /* FIXME: Use SEI header values */ + priv->pic_structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME; + + if (!picture) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + if (!gst_vaapi_picture_decode (GST_VAAPI_PICTURE_CAST (picture))) + goto error; + + if (!dpb_add (decoder, picture)) + goto error; + + gst_vaapi_picture_replace (&priv->current_picture, NULL); + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + /* ERRORS */ +error: + { + gst_vaapi_picture_replace (&priv->current_picture, NULL); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } +drop_frame: + { + priv->decoder_state = 0; + priv->pic_structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME; + return (GstVaapiDecoderStatus) GST_VAAPI_DECODER_STATUS_DROP_FRAME; + } +} + +static GstVaapiDecoderStatus +parse_vps (GstVaapiDecoderH265 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiParserInfoH265 *const pi = unit->parsed_info; + GstH265VPS *const vps = &pi->data.vps; + GstH265ParserResult result; + + GST_DEBUG ("parse VPS"); + priv->parser_state = 0; + + memset (vps, 0, sizeof (GstH265VPS)); + + result = gst_h265_parser_parse_vps (priv->parser, &pi->nalu, vps); + if (result != GST_H265_PARSER_OK) + return get_status (result); + + priv->parser_state |= GST_H265_VIDEO_STATE_GOT_VPS; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +parse_sps (GstVaapiDecoderH265 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiParserInfoH265 *const pi = unit->parsed_info; + GstH265SPS *const sps = &pi->data.sps; + GstH265ParserResult result; + + GST_DEBUG ("parse SPS"); + priv->parser_state = 0; + + memset (sps, 0, sizeof (GstH265SPS)); + + result = gst_h265_parser_parse_sps (priv->parser, &pi->nalu, sps, TRUE); + if (result != GST_H265_PARSER_OK) + return get_status (result); + + priv->parser_state |= GST_H265_VIDEO_STATE_GOT_SPS; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +parse_pps (GstVaapiDecoderH265 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiParserInfoH265 *const pi = unit->parsed_info; + GstH265PPS *const pps = &pi->data.pps; + GstH265ParserResult result; + guint col_width[19], row_height[21]; + + GST_DEBUG ("parse PPS"); + priv->parser_state &= GST_H265_VIDEO_STATE_GOT_SPS; + + memset (col_width, 0, sizeof (col_width)); + memset (row_height, 0, sizeof (row_height)); + + memset (pps, 0, sizeof (GstH265PPS)); + + result = gst_h265_parser_parse_pps (priv->parser, &pi->nalu, pps); + if (result != GST_H265_PARSER_OK) + return get_status (result); + + priv->parser_state |= GST_H265_VIDEO_STATE_GOT_PPS; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +parse_sei (GstVaapiDecoderH265 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiParserInfoH265 *const pi = unit->parsed_info; + GArray **const sei_ptr = &pi->data.sei; + GstH265ParserResult result; + + GST_DEBUG ("parse SEI"); + + result = gst_h265_parser_parse_sei (priv->parser, &pi->nalu, sei_ptr); + if (result != GST_H265_PARSER_OK) { + GST_WARNING ("failed to parse SEI messages"); + return get_status (result); + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +parse_slice (GstVaapiDecoderH265 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiParserInfoH265 *const pi = unit->parsed_info; + GstH265SliceHdr *const slice_hdr = &pi->data.slice_hdr; + GstH265ParserResult result; + + GST_DEBUG ("parse slice"); + priv->parser_state &= (GST_H265_VIDEO_STATE_GOT_SPS | + GST_H265_VIDEO_STATE_GOT_PPS); + + slice_hdr->short_term_ref_pic_set_idx = 0; + + memset (slice_hdr, 0, sizeof (GstH265SliceHdr)); + + result = gst_h265_parser_parse_slice_hdr (priv->parser, &pi->nalu, slice_hdr); + if (result != GST_H265_PARSER_OK) + return get_status (result); + + priv->parser_state |= GST_H265_VIDEO_STATE_GOT_SLICE; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_vps (GstVaapiDecoderH265 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiParserInfoH265 *const pi = unit->parsed_info; + GstH265VPS *const vps = &pi->data.vps; + + GST_DEBUG ("decode VPS"); + + gst_vaapi_parser_info_h265_replace (&priv->vps[vps->id], pi); + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_sps (GstVaapiDecoderH265 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiParserInfoH265 *const pi = unit->parsed_info; + GstH265SPS *const sps = &pi->data.sps; + guint high_precision_offsets_enabled_flag = 0, bitdepthC = 0; + + GST_DEBUG ("decode SPS"); + + if (sps->max_latency_increase_plus1[sps->max_sub_layers_minus1]) + priv->SpsMaxLatencyPictures = + sps->max_num_reorder_pics[sps->max_sub_layers_minus1] + + sps->max_latency_increase_plus1[sps->max_sub_layers_minus1] - 1; + + /* Calculate WpOffsetHalfRangeC: (7-34) + * FIXME: We don't have parser API for sps_range_extension, so + * assuming high_precision_offsets_enabled_flag as zero */ + bitdepthC = sps->bit_depth_chroma_minus8 + 8; + priv->WpOffsetHalfRangeC = + 1 << (high_precision_offsets_enabled_flag ? (bitdepthC - 1) : 7); + + gst_vaapi_parser_info_h265_replace (&priv->sps[sps->id], pi); + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_pps (GstVaapiDecoderH265 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiParserInfoH265 *const pi = unit->parsed_info; + GstH265PPS *const pps = &pi->data.pps; + + GST_DEBUG ("decode PPS"); + + gst_vaapi_parser_info_h265_replace (&priv->pps[pps->id], pi); + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_sei (GstVaapiDecoderH265 * decoder, GstVaapiDecoderUnit * unit) +{ + + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiParserInfoH265 *const pi = unit->parsed_info; + guint i; + + GST_DEBUG ("decode SEI messages"); + + for (i = 0; i < pi->data.sei->len; i++) { + const GstH265SEIMessage *const sei = + &g_array_index (pi->data.sei, GstH265SEIMessage, i); + + switch (sei->payloadType) { + case GST_H265_SEI_PIC_TIMING:{ + const GstH265PicTiming *const pic_timing = &sei->payload.pic_timing; + priv->pic_structure = pic_timing->pic_struct; + break; + } + default: + break; + } + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_sequence_end (GstVaapiDecoderH265 * decoder) +{ + GstVaapiDecoderStatus status; + GstVaapiParserInfoH265 *const sps_pi = decoder->priv.active_sps; + + GST_DEBUG ("decode sequence-end"); + + /* Sequence ended, don't try to propagate "got I-frame" state beyond + * this point */ + if (sps_pi) + sps_pi->state &= ~GST_H265_VIDEO_STATE_GOT_I_FRAME; + + status = decode_current_picture (decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +/* 8.3.1 - Decoding process for picture order count */ +static void +init_picture_poc (GstVaapiDecoderH265 * decoder, + GstVaapiPictureH265 * picture, GstVaapiParserInfoH265 * pi) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstH265SliceHdr *const slice_hdr = &pi->data.slice_hdr; + GstH265SPS *const sps = get_sps (decoder); + const gint32 MaxPicOrderCntLsb = + 1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4); + guint8 nal_type = pi->nalu.type; + guint8 temporal_id = pi->nalu.temporal_id_plus1 - 1; + + GST_DEBUG ("decode PicOrderCntVal"); + + priv->prev_poc_lsb = priv->poc_lsb; + priv->prev_poc_msb = priv->poc_msb; + + if (!(nal_is_irap (nal_type) && picture->NoRaslOutputFlag)) { + priv->prev_poc_lsb = priv->prev_tid0pic_poc_lsb; + priv->prev_poc_msb = priv->prev_tid0pic_poc_msb; + } + + /* Finding PicOrderCntMsb */ + if (nal_is_irap (nal_type) && picture->NoRaslOutputFlag) + priv->poc_msb = 0; + else { + /* (8-1) */ + if ((slice_hdr->pic_order_cnt_lsb < priv->prev_poc_lsb) && + ((priv->prev_poc_lsb - slice_hdr->pic_order_cnt_lsb) >= + (MaxPicOrderCntLsb / 2))) + priv->poc_msb = priv->prev_poc_msb + MaxPicOrderCntLsb; + + else if ((slice_hdr->pic_order_cnt_lsb > priv->prev_poc_lsb) && + ((slice_hdr->pic_order_cnt_lsb - priv->prev_poc_lsb) > + (MaxPicOrderCntLsb / 2))) + priv->poc_msb = priv->prev_poc_msb - MaxPicOrderCntLsb; + + else + priv->poc_msb = priv->prev_poc_msb; + } + + /* (8-2) */ + priv->poc = picture->poc = priv->poc_msb + slice_hdr->pic_order_cnt_lsb; + priv->poc_lsb = picture->poc_lsb = slice_hdr->pic_order_cnt_lsb; + + if (nal_is_idr (nal_type)) { + picture->poc = 0; + picture->poc_lsb = 0; + priv->poc_lsb = 0; + priv->poc_msb = 0; + priv->prev_poc_lsb = 0; + priv->prev_poc_msb = 0; + priv->prev_tid0pic_poc_lsb = 0; + priv->prev_tid0pic_poc_msb = 0; + } + + picture->base.poc = picture->poc; + GST_DEBUG ("PicOrderCntVal %d", picture->base.poc); + + if (!temporal_id && !nal_is_rasl (nal_type) && + !nal_is_radl (nal_type) && nal_is_ref (nal_type)) { + priv->prev_tid0pic_poc_lsb = slice_hdr->pic_order_cnt_lsb; + priv->prev_tid0pic_poc_msb = priv->poc_msb; + } +} + +static void +init_picture_refs (GstVaapiDecoderH265 * decoder, + GstVaapiPictureH265 * picture, GstH265SliceHdr * slice_hdr) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + guint32 NumRpsCurrTempList0 = 0, NumRpsCurrTempList1 = 0; + GstVaapiPictureH265 *RefPicListTemp0[16] = { NULL, }; + GstVaapiPictureH265 *RefPicListTemp1[16] = { NULL, }; + guint i, rIdx = 0; + guint num_ref_idx_l0_active_minus1 = 0; + guint num_ref_idx_l1_active_minus1 = 0; + GstH265RefPicListModification *ref_pic_list_modification; + GstH265PPS *const pps = get_pps (decoder); + guint type; + + memset (priv->RefPicList0, 0, sizeof (GstVaapiPictureH265 *) * 16); + memset (priv->RefPicList1, 0, sizeof (GstVaapiPictureH265 *) * 16); + priv->RefPicList0_count = priv->RefPicList1_count = 0; + + num_ref_idx_l0_active_minus1 = slice_hdr->num_ref_idx_l0_active_minus1; + num_ref_idx_l1_active_minus1 = slice_hdr->num_ref_idx_l1_active_minus1; + ref_pic_list_modification = &slice_hdr->ref_pic_list_modification; + type = slice_hdr->type; + + /* decoding process for reference picture list construction needs to be + * invoked only for P and B slice */ + if (type == GST_H265_I_SLICE) + return; + + NumRpsCurrTempList0 = + MAX ((num_ref_idx_l0_active_minus1 + 1), priv->NumPocTotalCurr); + NumRpsCurrTempList1 = + MAX ((num_ref_idx_l1_active_minus1 + 1), priv->NumPocTotalCurr); + + /* (8-8) */ + while (rIdx < NumRpsCurrTempList0) { + for (i = 0; i < priv->NumPocStCurrBefore && rIdx < NumRpsCurrTempList0; + rIdx++, i++) + RefPicListTemp0[rIdx] = priv->RefPicSetStCurrBefore[i]; + for (i = 0; i < priv->NumPocStCurrAfter && rIdx < NumRpsCurrTempList0; + rIdx++, i++) + RefPicListTemp0[rIdx] = priv->RefPicSetStCurrAfter[i]; + for (i = 0; i < priv->NumPocLtCurr && rIdx < NumRpsCurrTempList0; + rIdx++, i++) + RefPicListTemp0[rIdx] = priv->RefPicSetLtCurr[i]; + if (pps->pps_scc_extension_params.pps_curr_pic_ref_enabled_flag) + RefPicListTemp0[rIdx++] = picture; + } + + /* construct RefPicList0 (8-9) */ + for (rIdx = 0; rIdx <= num_ref_idx_l0_active_minus1; rIdx++) + priv->RefPicList0[rIdx] = + ref_pic_list_modification->ref_pic_list_modification_flag_l0 ? + RefPicListTemp0[ref_pic_list_modification->list_entry_l0[rIdx]] : + RefPicListTemp0[rIdx]; + if (pps->pps_scc_extension_params.pps_curr_pic_ref_enabled_flag + && !ref_pic_list_modification->ref_pic_list_modification_flag_l0 + && (NumRpsCurrTempList0 > num_ref_idx_l0_active_minus1 + 1)) + priv->RefPicList0[num_ref_idx_l0_active_minus1] = picture; + priv->RefPicList0_count = rIdx; + + if (type == GST_H265_B_SLICE) { + rIdx = 0; + + /* (8-10) */ + while (rIdx < NumRpsCurrTempList1) { + for (i = 0; i < priv->NumPocStCurrAfter && rIdx < NumRpsCurrTempList1; + rIdx++, i++) + RefPicListTemp1[rIdx] = priv->RefPicSetStCurrAfter[i]; + for (i = 0; i < priv->NumPocStCurrBefore && rIdx < NumRpsCurrTempList1; + rIdx++, i++) + RefPicListTemp1[rIdx] = priv->RefPicSetStCurrBefore[i]; + for (i = 0; i < priv->NumPocLtCurr && rIdx < NumRpsCurrTempList1; + rIdx++, i++) + RefPicListTemp1[rIdx] = priv->RefPicSetLtCurr[i]; + if (pps->pps_scc_extension_params.pps_curr_pic_ref_enabled_flag) + RefPicListTemp1[rIdx++] = picture; + } + + /* construct RefPicList1 (8-10) */ + for (rIdx = 0; rIdx <= num_ref_idx_l1_active_minus1; rIdx++) + priv->RefPicList1[rIdx] = + ref_pic_list_modification->ref_pic_list_modification_flag_l1 ? + RefPicListTemp1[ref_pic_list_modification->list_entry_l1 + [rIdx]] : RefPicListTemp1[rIdx]; + priv->RefPicList1_count = rIdx; + } +} + +static gboolean +init_picture (GstVaapiDecoderH265 * decoder, + GstVaapiPictureH265 * picture, GstVaapiParserInfoH265 * pi) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiPicture *const base_picture = &picture->base; + GstH265SliceHdr *const slice_hdr = &pi->data.slice_hdr; + + base_picture->pts = GST_VAAPI_DECODER_CODEC_FRAME (decoder)->pts; + base_picture->type = GST_VAAPI_PICTURE_TYPE_NONE; + + if (nal_is_idr (pi->nalu.type)) { + GST_DEBUG (""); + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_IDR); + } + + if (pi->nalu.type >= GST_H265_NAL_SLICE_BLA_W_LP && + pi->nalu.type <= GST_H265_NAL_SLICE_CRA_NUT) + picture->RapPicFlag = TRUE; + + /* FIXME: Use SEI header values */ + base_picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME; + picture->structure = base_picture->structure; + + /*NoRaslOutputFlag ==1 if the current picture is + 1) an IDR picture + 2) a BLA picture + 3) a CRA picture that is the first access unit in the bitstream + 4) first picture that follows an end of sequence NAL unit in decoding order + 5) has HandleCraAsBlaFlag == 1 (set by external means, so not considering ) + */ + if (nal_is_idr (pi->nalu.type) || nal_is_bla (pi->nalu.type) || + (nal_is_cra (pi->nalu.type) && priv->new_bitstream) + || priv->prev_nal_is_eos) { + picture->NoRaslOutputFlag = 1; + } + + if (nal_is_irap (pi->nalu.type)) { + picture->IntraPicFlag = TRUE; + priv->associated_irap_NoRaslOutputFlag = picture->NoRaslOutputFlag; + } + + if (nal_is_rasl (pi->nalu.type) && priv->associated_irap_NoRaslOutputFlag) + picture->output_flag = FALSE; + else + picture->output_flag = slice_hdr->pic_output_flag; + + init_picture_poc (decoder, picture, pi); + + return TRUE; +} + +static void +vaapi_init_picture (VAPictureHEVC * pic) +{ + pic->picture_id = VA_INVALID_SURFACE; + pic->pic_order_cnt = 0; + pic->flags = VA_PICTURE_HEVC_INVALID; +} + +static void +vaapi_fill_picture (VAPictureHEVC * pic, GstVaapiPictureH265 * picture, + guint picture_structure) +{ + + if (!picture_structure) + picture_structure = picture->structure; + + pic->picture_id = picture->base.surface_id; + pic->pic_order_cnt = picture->poc; + pic->flags = 0; + + /* Set the VAPictureHEVC flags */ + if (GST_VAAPI_PICTURE_IS_LONG_TERM_REFERENCE (picture)) + pic->flags |= VA_PICTURE_HEVC_LONG_TERM_REFERENCE; + + if (GST_VAAPI_PICTURE_FLAG_IS_SET (picture, + GST_VAAPI_PICTURE_FLAG_RPS_ST_CURR_BEFORE)) + pic->flags |= VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE; + + else if (GST_VAAPI_PICTURE_FLAG_IS_SET (picture, + GST_VAAPI_PICTURE_FLAG_RPS_ST_CURR_AFTER)) + pic->flags |= VA_PICTURE_HEVC_RPS_ST_CURR_AFTER; + + else if (GST_VAAPI_PICTURE_FLAG_IS_SET (picture, + GST_VAAPI_PICTURE_FLAG_RPS_LT_CURR)) + pic->flags |= VA_PICTURE_HEVC_RPS_LT_CURR; + + switch (picture_structure) { + case GST_VAAPI_PICTURE_STRUCTURE_FRAME: + break; + case GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD: + pic->flags |= VA_PICTURE_HEVC_FIELD_PIC; + break; + case GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD: + pic->flags |= VA_PICTURE_HEVC_FIELD_PIC; + pic->flags |= VA_PICTURE_HEVC_BOTTOM_FIELD; + break; + default: + break; + } +} + +static guint +get_index_for_RefPicListX (VAPictureHEVC * ReferenceFrames, + GstVaapiPictureH265 * pic) +{ + gint i; + + for (i = 0; i < 15; i++) { + if ((ReferenceFrames[i].picture_id != VA_INVALID_ID) && pic) { + if ((ReferenceFrames[i].pic_order_cnt == pic->poc) && + (ReferenceFrames[i].picture_id == pic->base.surface_id)) { + return i; + } + } + } + return 0xff; +} + +static gboolean +fill_picture (GstVaapiDecoderH265 * decoder, GstVaapiPictureH265 * picture) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiPicture *const base_picture = &picture->base; + GstH265PPS *const pps = get_pps (decoder); + GstH265SPS *const sps = get_sps (decoder); + VAPictureParameterBufferHEVC *pic_param = base_picture->param; + guint i, n; + +#if VA_CHECK_VERSION(1,2,0) + VAPictureParameterBufferHEVCRext *pic_rext_param = NULL; + VAPictureParameterBufferHEVCScc *pic_scc_param = NULL; + if (is_range_extension_profile (priv->profile)) { + VAPictureParameterBufferHEVCExtension *param = base_picture->param; + pic_param = ¶m->base; + pic_rext_param = ¶m->rext; + } + if (is_scc_profile (priv->profile)) { + VAPictureParameterBufferHEVCExtension *param = base_picture->param; + pic_param = ¶m->base; + pic_rext_param = ¶m->rext; + pic_scc_param = ¶m->scc; + } +#endif + + pic_param->pic_fields.value = 0; + pic_param->slice_parsing_fields.value = 0; + + /* Fill in VAPictureHEVC */ + vaapi_fill_picture (&pic_param->CurrPic, picture, 0); + /* Fill in ReferenceFrames */ + for (i = 0, n = 0; i < priv->dpb_count; i++) { + GstVaapiFrameStore *const fs = priv->dpb[i]; + if ((gst_vaapi_frame_store_has_reference (fs))) + vaapi_fill_picture (&pic_param->ReferenceFrames[n++], fs->buffer, + fs->buffer->structure); + if (n >= G_N_ELEMENTS (pic_param->ReferenceFrames)) + break; + } + /* 7.4.3.3.3, the current decoded picture is marked as "used for + long-term reference", no matter TwoVersionsOfCurrDecPicFlag */ + if (pps->pps_scc_extension_params.pps_curr_pic_ref_enabled_flag + && n < G_N_ELEMENTS (pic_param->ReferenceFrames) - 1) { + gst_vaapi_picture_h265_set_reference (picture, + GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE); + vaapi_fill_picture (&pic_param->ReferenceFrames[n++], picture, + picture->structure); + gst_vaapi_picture_h265_set_reference (picture, 0); + } + + for (; n < G_N_ELEMENTS (pic_param->ReferenceFrames); n++) + vaapi_init_picture (&pic_param->ReferenceFrames[n]); + + +#define COPY_FIELD(s, f) \ + pic_param->f = (s)->f +#define COPY_BFM(a, s, f) \ + pic_param->a.bits.f = (s)->f + + COPY_FIELD (sps, pic_width_in_luma_samples); + COPY_FIELD (sps, pic_height_in_luma_samples); + COPY_BFM (pic_fields, sps, chroma_format_idc); + COPY_BFM (pic_fields, sps, separate_colour_plane_flag); + COPY_BFM (pic_fields, sps, pcm_enabled_flag); + COPY_BFM (pic_fields, sps, scaling_list_enabled_flag); + COPY_BFM (pic_fields, pps, transform_skip_enabled_flag); + COPY_BFM (pic_fields, sps, amp_enabled_flag); + COPY_BFM (pic_fields, sps, strong_intra_smoothing_enabled_flag); + COPY_BFM (pic_fields, pps, sign_data_hiding_enabled_flag); + COPY_BFM (pic_fields, pps, constrained_intra_pred_flag); + COPY_BFM (pic_fields, pps, cu_qp_delta_enabled_flag); + COPY_BFM (pic_fields, pps, weighted_pred_flag); + COPY_BFM (pic_fields, pps, weighted_bipred_flag); + COPY_BFM (pic_fields, pps, transquant_bypass_enabled_flag); + COPY_BFM (pic_fields, pps, tiles_enabled_flag); + COPY_BFM (pic_fields, pps, entropy_coding_sync_enabled_flag); + pic_param->pic_fields.bits.pps_loop_filter_across_slices_enabled_flag = + pps->loop_filter_across_slices_enabled_flag; + COPY_BFM (pic_fields, pps, loop_filter_across_tiles_enabled_flag); + COPY_BFM (pic_fields, sps, pcm_loop_filter_disabled_flag); + /* Fix: Assign value based on sps_max_num_reorder_pics */ + pic_param->pic_fields.bits.NoPicReorderingFlag = 0; + /* Fix: Enable if picture has no B slices */ + pic_param->pic_fields.bits.NoBiPredFlag = 0; + + pic_param->sps_max_dec_pic_buffering_minus1 = + sps->max_dec_pic_buffering_minus1[0]; + COPY_FIELD (sps, bit_depth_luma_minus8); + COPY_FIELD (sps, bit_depth_chroma_minus8); + COPY_FIELD (sps, pcm_sample_bit_depth_luma_minus1); + COPY_FIELD (sps, pcm_sample_bit_depth_chroma_minus1); + COPY_FIELD (sps, log2_min_luma_coding_block_size_minus3); + COPY_FIELD (sps, log2_diff_max_min_luma_coding_block_size); + COPY_FIELD (sps, log2_min_transform_block_size_minus2); + COPY_FIELD (sps, log2_diff_max_min_transform_block_size); + COPY_FIELD (sps, log2_min_pcm_luma_coding_block_size_minus3); + COPY_FIELD (sps, log2_diff_max_min_pcm_luma_coding_block_size); + COPY_FIELD (sps, max_transform_hierarchy_depth_intra); + COPY_FIELD (sps, max_transform_hierarchy_depth_inter); + COPY_FIELD (pps, init_qp_minus26); + COPY_FIELD (pps, diff_cu_qp_delta_depth); + pic_param->pps_cb_qp_offset = pps->cb_qp_offset; + pic_param->pps_cr_qp_offset = pps->cr_qp_offset; + COPY_FIELD (pps, log2_parallel_merge_level_minus2); + COPY_FIELD (pps, num_tile_columns_minus1); + COPY_FIELD (pps, num_tile_rows_minus1); + for (i = 0; i <= pps->num_tile_columns_minus1; i++) + pic_param->column_width_minus1[i] = pps->column_width_minus1[i]; + for (; i < 19; i++) + pic_param->column_width_minus1[i] = 0; + for (i = 0; i <= pps->num_tile_rows_minus1; i++) + pic_param->row_height_minus1[i] = pps->row_height_minus1[i]; + for (; i < 21; i++) + pic_param->row_height_minus1[i] = 0; + + COPY_BFM (slice_parsing_fields, pps, lists_modification_present_flag); + COPY_BFM (slice_parsing_fields, sps, long_term_ref_pics_present_flag); + pic_param->slice_parsing_fields.bits.sps_temporal_mvp_enabled_flag = + sps->temporal_mvp_enabled_flag; + COPY_BFM (slice_parsing_fields, pps, cabac_init_present_flag); + COPY_BFM (slice_parsing_fields, pps, output_flag_present_flag); + COPY_BFM (slice_parsing_fields, pps, dependent_slice_segments_enabled_flag); + pic_param->slice_parsing_fields.bits. + pps_slice_chroma_qp_offsets_present_flag = + pps->slice_chroma_qp_offsets_present_flag; + COPY_BFM (slice_parsing_fields, sps, sample_adaptive_offset_enabled_flag); + COPY_BFM (slice_parsing_fields, pps, deblocking_filter_override_enabled_flag); + pic_param->slice_parsing_fields.bits.pps_disable_deblocking_filter_flag = + pps->deblocking_filter_disabled_flag; + COPY_BFM (slice_parsing_fields, pps, + slice_segment_header_extension_present_flag); + pic_param->slice_parsing_fields.bits.RapPicFlag = picture->RapPicFlag; + pic_param->slice_parsing_fields.bits.IdrPicFlag = + GST_VAAPI_PICTURE_FLAG_IS_SET (picture, GST_VAAPI_PICTURE_FLAG_IDR); + pic_param->slice_parsing_fields.bits.IntraPicFlag = picture->IntraPicFlag; + + COPY_FIELD (sps, log2_max_pic_order_cnt_lsb_minus4); + COPY_FIELD (sps, num_short_term_ref_pic_sets); + pic_param->num_long_term_ref_pic_sps = sps->num_long_term_ref_pics_sps; + COPY_FIELD (pps, num_ref_idx_l0_default_active_minus1); + COPY_FIELD (pps, num_ref_idx_l1_default_active_minus1); + pic_param->pps_beta_offset_div2 = pps->beta_offset_div2; + pic_param->pps_tc_offset_div2 = pps->tc_offset_div2; + COPY_FIELD (pps, num_extra_slice_header_bits); + + /* FIXME: Set correct value as mentioned in va_dec_hevc.h */ + pic_param->st_rps_bits = 0; + +#if VA_CHECK_VERSION(1,2,0) + if (pic_rext_param) { + pic_rext_param->range_extension_pic_fields.value = 0; + +#define COPY_REXT_FIELD(s, f) \ + pic_rext_param->f = s.f +#define COPY_REXT_BFM(a, s, f) \ + pic_rext_param->a.bits.f = s.f + + COPY_REXT_BFM (range_extension_pic_fields, sps->sps_extnsion_params, + transform_skip_rotation_enabled_flag); + COPY_REXT_BFM (range_extension_pic_fields, sps->sps_extnsion_params, + transform_skip_context_enabled_flag); + COPY_REXT_BFM (range_extension_pic_fields, sps->sps_extnsion_params, + implicit_rdpcm_enabled_flag); + COPY_REXT_BFM (range_extension_pic_fields, sps->sps_extnsion_params, + explicit_rdpcm_enabled_flag); + COPY_REXT_BFM (range_extension_pic_fields, sps->sps_extnsion_params, + extended_precision_processing_flag); + COPY_REXT_BFM (range_extension_pic_fields, sps->sps_extnsion_params, + intra_smoothing_disabled_flag); + COPY_REXT_BFM (range_extension_pic_fields, sps->sps_extnsion_params, + high_precision_offsets_enabled_flag); + COPY_REXT_BFM (range_extension_pic_fields, sps->sps_extnsion_params, + persistent_rice_adaptation_enabled_flag); + COPY_REXT_BFM (range_extension_pic_fields, sps->sps_extnsion_params, + cabac_bypass_alignment_enabled_flag); + + COPY_REXT_BFM (range_extension_pic_fields, pps->pps_extension_params, + cross_component_prediction_enabled_flag); + COPY_REXT_BFM (range_extension_pic_fields, pps->pps_extension_params, + chroma_qp_offset_list_enabled_flag); + + COPY_REXT_FIELD (pps->pps_extension_params, diff_cu_chroma_qp_offset_depth); + COPY_REXT_FIELD (pps->pps_extension_params, + chroma_qp_offset_list_len_minus1); + COPY_REXT_FIELD (pps->pps_extension_params, log2_sao_offset_scale_luma); + COPY_REXT_FIELD (pps->pps_extension_params, log2_sao_offset_scale_chroma); + COPY_REXT_FIELD (pps->pps_extension_params, + log2_max_transform_skip_block_size_minus2); + + memcpy (pic_rext_param->cb_qp_offset_list, + pps->pps_extension_params.cb_qp_offset_list, + sizeof (pic_rext_param->cb_qp_offset_list)); + memcpy (pic_rext_param->cr_qp_offset_list, + pps->pps_extension_params.cr_qp_offset_list, + sizeof (pic_rext_param->cr_qp_offset_list)); + } + + if (pic_scc_param) { +#define COPY_SCC_FIELD(s, f) \ + pic_scc_param->f = s->f +#define COPY_SCC_BFM(a, s, f) \ + pic_scc_param->a.bits.f = s->f + + const GstH265PPSSccExtensionParams *pps_scc = + &pps->pps_scc_extension_params; + const GstH265SPSSccExtensionParams *sps_scc = + &sps->sps_scc_extension_params; + guint32 num_comps; + + pic_scc_param->screen_content_pic_fields.value = 0; + + COPY_SCC_BFM (screen_content_pic_fields, pps_scc, + pps_curr_pic_ref_enabled_flag); + COPY_SCC_BFM (screen_content_pic_fields, sps_scc, + palette_mode_enabled_flag); + COPY_SCC_BFM (screen_content_pic_fields, sps_scc, + motion_vector_resolution_control_idc); + COPY_SCC_BFM (screen_content_pic_fields, sps_scc, + intra_boundary_filtering_disabled_flag); + COPY_SCC_BFM (screen_content_pic_fields, pps_scc, + residual_adaptive_colour_transform_enabled_flag); + COPY_SCC_BFM (screen_content_pic_fields, pps_scc, + pps_slice_act_qp_offsets_present_flag); + + COPY_SCC_FIELD (sps_scc, palette_max_size); + COPY_SCC_FIELD (sps_scc, delta_palette_max_predictor_size); + COPY_SCC_FIELD (pps_scc, pps_act_y_qp_offset_plus5); + COPY_SCC_FIELD (pps_scc, pps_act_cb_qp_offset_plus5); + COPY_SCC_FIELD (pps_scc, pps_act_cr_qp_offset_plus3); + + /* firstly use the pps, then sps */ + num_comps = sps->chroma_format_idc ? 3 : 1; + + if (pps_scc->pps_palette_predictor_initializers_present_flag) { + pic_scc_param->predictor_palette_size = + pps_scc->pps_num_palette_predictor_initializer; + for (n = 0; n < num_comps; n++) + for (i = 0; i < pps_scc->pps_num_palette_predictor_initializer; i++) + pic_scc_param->predictor_palette_entries[n][i] = + (uint16_t) pps_scc->pps_palette_predictor_initializer[n][i]; + } else if (sps_scc->sps_palette_predictor_initializers_present_flag) { + pic_scc_param->predictor_palette_size = + sps_scc->sps_num_palette_predictor_initializer_minus1 + 1; + for (n = 0; n < num_comps; n++) + for (i = 0; + i < sps_scc->sps_num_palette_predictor_initializer_minus1 + 1; i++) + pic_scc_param->predictor_palette_entries[n][i] = + (uint16_t) sps_scc->sps_palette_predictor_initializer[n][i]; + } + } +#endif + return TRUE; +} + +/* Detection of the first VCL NAL unit of a coded picture (7.4.2.4.5 ) */ +static gboolean +is_new_picture (GstVaapiParserInfoH265 * pi, GstVaapiParserInfoH265 * prev_pi) +{ + GstH265SliceHdr *const slice_hdr = &pi->data.slice_hdr; + + if (!prev_pi) + return TRUE; + + if (slice_hdr->first_slice_segment_in_pic_flag) + return TRUE; + + return FALSE; +} + +/* Detection of a new access unit, assuming we are already in presence + of a new picture */ +static inline gboolean +is_new_access_unit (GstVaapiParserInfoH265 * pi, + GstVaapiParserInfoH265 * prev_pi) +{ + if (!prev_pi) + return TRUE; + + return FALSE; +} + +static gboolean +has_entry_in_rps (GstVaapiPictureH265 * dpb_pic, + GstVaapiPictureH265 ** rps_list, guint rps_list_length) +{ + guint i; + + if (!dpb_pic || !rps_list || !rps_list_length) + return FALSE; + + for (i = 0; i < rps_list_length; i++) { + if (rps_list[i] && rps_list[i]->poc == dpb_pic->poc) + return TRUE; + } + return FALSE; +} + +/* the derivation process for the RPS and the picture marking */ +static void +derive_and_mark_rps (GstVaapiDecoderH265 * decoder, + GstVaapiPictureH265 * picture, GstVaapiParserInfoH265 * pi, + gint32 * CurrDeltaPocMsbPresentFlag, gint32 * FollDeltaPocMsbPresentFlag) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiPictureH265 *dpb_pic = NULL; + guint i; + + memset (priv->RefPicSetLtCurr, 0, sizeof (GstVaapiPictureH265 *) * 16); + memset (priv->RefPicSetLtFoll, 0, sizeof (GstVaapiPictureH265 *) * 16); + memset (priv->RefPicSetStCurrBefore, 0, sizeof (GstVaapiPictureH265 *) * 16); + memset (priv->RefPicSetStCurrAfter, 0, sizeof (GstVaapiPictureH265 *) * 16); + memset (priv->RefPicSetStFoll, 0, sizeof (GstVaapiPictureH265 *) * 16); + + /* (8-6) */ + for (i = 0; i < priv->NumPocLtCurr; i++) { + if (!CurrDeltaPocMsbPresentFlag[i]) { + dpb_pic = dpb_get_picture (decoder, priv->PocLtCurr[i], TRUE); + if (dpb_pic) + priv->RefPicSetLtCurr[i] = dpb_pic; + else + priv->RefPicSetLtCurr[i] = NULL; + } else { + dpb_pic = dpb_get_picture (decoder, priv->PocLtCurr[i], FALSE); + if (dpb_pic) + priv->RefPicSetLtCurr[i] = dpb_pic; + else + priv->RefPicSetLtCurr[i] = NULL; + } + } + for (; i < 16; i++) + priv->RefPicSetLtCurr[i] = NULL; + + for (i = 0; i < priv->NumPocLtFoll; i++) { + if (!FollDeltaPocMsbPresentFlag[i]) { + dpb_pic = dpb_get_picture (decoder, priv->PocLtFoll[i], TRUE); + if (dpb_pic) + priv->RefPicSetLtFoll[i] = dpb_pic; + else + priv->RefPicSetLtFoll[i] = NULL; + } else { + dpb_pic = dpb_get_picture (decoder, priv->PocLtFoll[i], FALSE); + if (dpb_pic) + priv->RefPicSetLtFoll[i] = dpb_pic; + else + priv->RefPicSetLtFoll[i] = NULL; + } + } + for (; i < 16; i++) + priv->RefPicSetLtFoll[i] = NULL; + + /* Mark all ref pics in RefPicSetLtCurr and RefPicSetLtFol as long_term_refs */ + for (i = 0; i < priv->NumPocLtCurr; i++) { + if (priv->RefPicSetLtCurr[i]) + gst_vaapi_picture_h265_set_reference (priv->RefPicSetLtCurr[i], + GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE | + GST_VAAPI_PICTURE_FLAG_RPS_LT_CURR); + } + for (i = 0; i < priv->NumPocLtFoll; i++) { + if (priv->RefPicSetLtFoll[i]) + gst_vaapi_picture_h265_set_reference (priv->RefPicSetLtFoll[i], + GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE | + GST_VAAPI_PICTURE_FLAG_RPS_LT_FOLL); + } + + /* (8-7) */ + for (i = 0; i < priv->NumPocStCurrBefore; i++) { + dpb_pic = dpb_get_ref_picture (decoder, priv->PocStCurrBefore[i], TRUE); + if (dpb_pic) { + gst_vaapi_picture_h265_set_reference (dpb_pic, + GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE | + GST_VAAPI_PICTURE_FLAG_RPS_ST_CURR_BEFORE); + priv->RefPicSetStCurrBefore[i] = dpb_pic; + } else + priv->RefPicSetStCurrBefore[i] = NULL; + } + for (; i < 16; i++) + priv->RefPicSetStCurrBefore[i] = NULL; + + for (i = 0; i < priv->NumPocStCurrAfter; i++) { + dpb_pic = dpb_get_ref_picture (decoder, priv->PocStCurrAfter[i], TRUE); + if (dpb_pic) { + gst_vaapi_picture_h265_set_reference (dpb_pic, + GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE | + GST_VAAPI_PICTURE_FLAG_RPS_ST_CURR_AFTER); + priv->RefPicSetStCurrAfter[i] = dpb_pic; + } else + priv->RefPicSetStCurrAfter[i] = NULL; + } + for (; i < 16; i++) + priv->RefPicSetStCurrAfter[i] = NULL; + + for (i = 0; i < priv->NumPocStFoll; i++) { + dpb_pic = dpb_get_ref_picture (decoder, priv->PocStFoll[i], TRUE); + if (dpb_pic) { + gst_vaapi_picture_h265_set_reference (dpb_pic, + GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE | + GST_VAAPI_PICTURE_FLAG_RPS_ST_FOLL); + priv->RefPicSetStFoll[i] = dpb_pic; + } else + priv->RefPicSetStFoll[i] = NULL; + } + for (; i < 16; i++) + priv->RefPicSetStFoll[i] = NULL; + + /* Mark all dpb pics not beloging to RefPicSet*[] as unused for ref */ + for (i = 0; i < priv->dpb_count; i++) { + dpb_pic = priv->dpb[i]->buffer; + if (dpb_pic && + !has_entry_in_rps (dpb_pic, priv->RefPicSetLtCurr, priv->NumPocLtCurr) + && !has_entry_in_rps (dpb_pic, priv->RefPicSetLtFoll, + priv->NumPocLtFoll) + && !has_entry_in_rps (dpb_pic, priv->RefPicSetStCurrAfter, + priv->NumPocStCurrAfter) + && !has_entry_in_rps (dpb_pic, priv->RefPicSetStCurrBefore, + priv->NumPocStCurrBefore) + && !has_entry_in_rps (dpb_pic, priv->RefPicSetStFoll, + priv->NumPocStFoll)) + gst_vaapi_picture_h265_set_reference (dpb_pic, 0); + } + +} + +/* Decoding process for reference picture set (8.3.2) */ +static gboolean +decode_ref_pic_set (GstVaapiDecoderH265 * decoder, + GstVaapiPictureH265 * picture, GstVaapiParserInfoH265 * pi) +{ + guint i, j, k; + gint32 CurrDeltaPocMsbPresentFlag[16] = { 0, }; + gint32 FollDeltaPocMsbPresentFlag[16] = { 0, }; + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstH265SliceHdr *const slice_hdr = &pi->data.slice_hdr; + GstH265SPS *const sps = get_sps (decoder); + GstH265PPS *const pps = get_pps (decoder); + const gint32 MaxPicOrderCntLsb = + 1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4); + + /* if it is an irap pic, set all ref pics in dpb as unused for ref */ + if (nal_is_irap (pi->nalu.type) && picture->NoRaslOutputFlag) { + for (i = 0; i < priv->dpb_count; i++) { + GstVaapiFrameStore *const fs = priv->dpb[i]; + gst_vaapi_picture_h265_set_reference (fs->buffer, 0); + } + } + + /* Reset everything for IDR */ + if (nal_is_idr (pi->nalu.type)) { + memset (priv->PocStCurrBefore, 0, sizeof (guint) * 16); + memset (priv->PocStCurrAfter, 0, sizeof (guint) * 16); + memset (priv->PocStFoll, 0, sizeof (guint) * 16); + memset (priv->PocLtCurr, 0, sizeof (guint) * 16); + memset (priv->PocLtFoll, 0, sizeof (guint) * 16); + priv->NumPocStCurrBefore = priv->NumPocStCurrAfter = priv->NumPocStFoll = 0; + priv->NumPocLtCurr = priv->NumPocLtFoll = 0; + priv->NumPocTotalCurr = 0; + } else { + GstH265ShortTermRefPicSet *stRefPic = NULL; + gint32 num_lt_pics, pocLt; + gint32 PocLsbLt[16] = { 0, }; + gint32 UsedByCurrPicLt[16] = { 0, }; + gint32 DeltaPocMsbCycleLt[16] = { 0, }; + gint numtotalcurr = 0; + + /* this is based on CurrRpsIdx described in spec */ + if (!slice_hdr->short_term_ref_pic_set_sps_flag) + stRefPic = &slice_hdr->short_term_ref_pic_sets; + else if (sps->num_short_term_ref_pic_sets) + stRefPic = + &sps->short_term_ref_pic_set[slice_hdr->short_term_ref_pic_set_idx]; + + g_assert (stRefPic != NULL); + + for (i = 0, j = 0, k = 0; i < stRefPic->NumNegativePics; i++) { + if (stRefPic->UsedByCurrPicS0[i]) { + priv->PocStCurrBefore[j++] = picture->poc + stRefPic->DeltaPocS0[i]; + numtotalcurr++; + } else + priv->PocStFoll[k++] = picture->poc + stRefPic->DeltaPocS0[i]; + } + priv->NumPocStCurrBefore = j; + for (i = 0, j = 0; i < stRefPic->NumPositivePics; i++) { + if (stRefPic->UsedByCurrPicS1[i]) { + priv->PocStCurrAfter[j++] = picture->poc + stRefPic->DeltaPocS1[i]; + numtotalcurr++; + } else + priv->PocStFoll[k++] = picture->poc + stRefPic->DeltaPocS1[i]; + } + priv->NumPocStCurrAfter = j; + priv->NumPocStFoll = k; + num_lt_pics = slice_hdr->num_long_term_sps + slice_hdr->num_long_term_pics; + /* The variables PocLsbLt[i] and UsedByCurrPicLt[i] are derived as follows: */ + for (i = 0; i < num_lt_pics; i++) { + if (i < slice_hdr->num_long_term_sps) { + PocLsbLt[i] = sps->lt_ref_pic_poc_lsb_sps[slice_hdr->lt_idx_sps[i]]; + UsedByCurrPicLt[i] = + sps->used_by_curr_pic_lt_sps_flag[slice_hdr->lt_idx_sps[i]]; + } else { + PocLsbLt[i] = slice_hdr->poc_lsb_lt[i]; + UsedByCurrPicLt[i] = slice_hdr->used_by_curr_pic_lt_flag[i]; + } + if (UsedByCurrPicLt[i]) + numtotalcurr++; + } + + if (pps->pps_scc_extension_params.pps_curr_pic_ref_enabled_flag) + numtotalcurr++; + priv->NumPocTotalCurr = numtotalcurr; + + /* The variable DeltaPocMsbCycleLt[i] is derived as follows: (7-38) */ + for (i = 0; i < num_lt_pics; i++) { + if (i == 0 || i == slice_hdr->num_long_term_sps) + DeltaPocMsbCycleLt[i] = slice_hdr->delta_poc_msb_cycle_lt[i]; + else + DeltaPocMsbCycleLt[i] = + slice_hdr->delta_poc_msb_cycle_lt[i] + DeltaPocMsbCycleLt[i - 1]; + } + + /* (8-5) */ + for (i = 0, j = 0, k = 0; i < num_lt_pics; i++) { + pocLt = PocLsbLt[i]; + if (slice_hdr->delta_poc_msb_present_flag[i]) + pocLt += + picture->poc - DeltaPocMsbCycleLt[i] * MaxPicOrderCntLsb - + slice_hdr->pic_order_cnt_lsb; + if (UsedByCurrPicLt[i]) { + priv->PocLtCurr[j] = pocLt; + CurrDeltaPocMsbPresentFlag[j++] = + slice_hdr->delta_poc_msb_present_flag[i]; + } else { + priv->PocLtFoll[k] = pocLt; + FollDeltaPocMsbPresentFlag[k++] = + slice_hdr->delta_poc_msb_present_flag[i]; + } + } + priv->NumPocLtCurr = j; + priv->NumPocLtFoll = k; + + } + + /* the derivation process for the RPS and the picture marking */ + derive_and_mark_rps (decoder, picture, pi, CurrDeltaPocMsbPresentFlag, + FollDeltaPocMsbPresentFlag); + + return TRUE; +} + +static GstVaapiDecoderStatus +decode_picture (GstVaapiDecoderH265 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiParserInfoH265 *pi = unit->parsed_info; + GstH265SliceHdr *const slice_hdr = &pi->data.slice_hdr; + GstH265PPS *const pps = ensure_pps (decoder, slice_hdr->pps); + GstH265SPS *const sps = ensure_sps (decoder, slice_hdr->pps->sps); + GstVaapiPictureH265 *picture; + GstVaapiDecoderStatus status; + + if (!(pps && sps)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + + status = ensure_context (decoder, sps); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + priv->decoder_state = 0; + + /* Create new picture */ + picture = gst_vaapi_picture_h265_new (decoder); + if (!picture) { + GST_ERROR ("failed to allocate picture"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + gst_vaapi_picture_replace (&priv->current_picture, picture); + gst_vaapi_picture_unref (picture); + + /* Update cropping rectangle */ + if (sps->conformance_window_flag) { + GstVaapiRectangle crop_rect; + crop_rect.x = sps->crop_rect_x; + crop_rect.y = sps->crop_rect_y; + crop_rect.width = sps->crop_rect_width; + crop_rect.height = sps->crop_rect_height; + gst_vaapi_picture_set_crop_rect (&picture->base, &crop_rect); + } + + status = ensure_quant_matrix (decoder, picture); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) { + GST_ERROR ("failed to reset quantizer matrix"); + return status; + } + + if (!init_picture (decoder, picture, pi)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + + /* Drop all RASL pictures having NoRaslOutputFlag is TRUE for the + * associated IRAP picture */ + if (nal_is_rasl (pi->nalu.type) && priv->associated_irap_NoRaslOutputFlag) { + gst_vaapi_picture_replace (&priv->current_picture, NULL); + return (GstVaapiDecoderStatus) GST_VAAPI_DECODER_STATUS_DROP_FRAME; + } + + if (!decode_ref_pic_set (decoder, picture, pi)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + + if (!dpb_init (decoder, picture, pi)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + + if (!fill_picture (decoder, picture)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + + priv->decoder_state = pi->state; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static inline guint +get_slice_data_byte_offset (GstH265SliceHdr * slice_hdr, guint nal_header_bytes) +{ + guint epb_count; + + epb_count = slice_hdr->n_emulation_prevention_bytes; + return nal_header_bytes + (slice_hdr->header_size + 7) / 8 - epb_count; +} + +static gboolean +fill_pred_weight_table (GstVaapiDecoderH265 * decoder, + GstVaapiSlice * slice, GstH265SliceHdr * slice_hdr) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + VASliceParameterBufferHEVC *slice_param = slice->param; + GstH265PPS *const pps = get_pps (decoder); + GstH265SPS *const sps = get_sps (decoder); + GstH265PredWeightTable *const w = &slice_hdr->pred_weight_table; + gint chroma_weight, chroma_log2_weight_denom; + gint i, j; + +#if VA_CHECK_VERSION(1,2,0) + VASliceParameterBufferHEVCRext *slice_rext_param = NULL; + if (is_range_extension_profile (priv->profile)) { + VASliceParameterBufferHEVCExtension *param = slice->param; + slice_param = ¶m->base; + slice_rext_param = ¶m->rext; + } +#endif + + slice_param->luma_log2_weight_denom = 0; + slice_param->delta_chroma_log2_weight_denom = 0; + + if ((pps->weighted_pred_flag && GST_H265_IS_P_SLICE (slice_hdr)) || + (pps->weighted_bipred_flag && GST_H265_IS_B_SLICE (slice_hdr))) { + + /* FIXME: This should be done in parser apis */ + memset (slice_param->delta_luma_weight_l0, 0, + sizeof (slice_param->delta_luma_weight_l0)); + memset (slice_param->luma_offset_l0, 0, + sizeof (slice_param->luma_offset_l0)); + memset (slice_param->delta_luma_weight_l1, 0, + sizeof (slice_param->delta_luma_weight_l1)); + memset (slice_param->luma_offset_l1, 0, + sizeof (slice_param->luma_offset_l1)); + memset (slice_param->delta_chroma_weight_l0, 0, + sizeof (slice_param->delta_chroma_weight_l0)); + memset (slice_param->ChromaOffsetL0, 0, + sizeof (slice_param->ChromaOffsetL0)); + memset (slice_param->delta_chroma_weight_l1, 0, + sizeof (slice_param->delta_chroma_weight_l1)); + memset (slice_param->ChromaOffsetL1, 0, + sizeof (slice_param->ChromaOffsetL1)); + +#if VA_CHECK_VERSION(1,2,0) + if (slice_rext_param) { + memset (slice_rext_param->luma_offset_l0, 0, + sizeof (slice_rext_param->luma_offset_l0)); + memset (slice_rext_param->luma_offset_l1, 0, + sizeof (slice_rext_param->luma_offset_l1)); + memset (slice_rext_param->ChromaOffsetL0, 0, + sizeof (slice_rext_param->ChromaOffsetL0)); + memset (slice_rext_param->ChromaOffsetL1, 0, + sizeof (slice_rext_param->ChromaOffsetL1)); + } +#endif + + slice_param->luma_log2_weight_denom = w->luma_log2_weight_denom; + if (sps->chroma_array_type != 0) + slice_param->delta_chroma_log2_weight_denom = + w->delta_chroma_log2_weight_denom; + + chroma_log2_weight_denom = + slice_param->luma_log2_weight_denom + + slice_param->delta_chroma_log2_weight_denom; + + for (i = 0; i <= slice_param->num_ref_idx_l0_active_minus1; i++) { + if (slice_hdr->pred_weight_table.luma_weight_l0_flag[i]) { + slice_param->delta_luma_weight_l0[i] = w->delta_luma_weight_l0[i]; + slice_param->luma_offset_l0[i] = w->luma_offset_l0[i]; +#if VA_CHECK_VERSION(1,2,0) + if (slice_rext_param) + slice_rext_param->luma_offset_l0[i] = w->luma_offset_l0[i]; +#endif + } + if (slice_hdr->pred_weight_table.chroma_weight_l0_flag[i]) { + for (j = 0; j < 2; j++) { + slice_param->delta_chroma_weight_l0[i][j] = + w->delta_chroma_weight_l0[i][j]; + /* Find ChromaWeightL0 */ + chroma_weight = + (1 << chroma_log2_weight_denom) + w->delta_chroma_weight_l0[i][j]; + /* 7-56 */ + slice_param->ChromaOffsetL0[i][j] = CLAMP ( + (priv->WpOffsetHalfRangeC + w->delta_chroma_offset_l0[i][j] - + ((priv->WpOffsetHalfRangeC * + chroma_weight) >> chroma_log2_weight_denom)), + -priv->WpOffsetHalfRangeC, priv->WpOffsetHalfRangeC - 1); +#if VA_CHECK_VERSION(1,2,0) + if (slice_rext_param) + slice_rext_param->ChromaOffsetL0[i][j] = CLAMP ( + (priv->WpOffsetHalfRangeC + w->delta_chroma_offset_l0[i][j] - + ((priv->WpOffsetHalfRangeC * + chroma_weight) >> chroma_log2_weight_denom)), + -priv->WpOffsetHalfRangeC, priv->WpOffsetHalfRangeC - 1); +#endif + } + } + } + + if (GST_H265_IS_B_SLICE (slice_hdr)) { + for (i = 0; i <= slice_param->num_ref_idx_l1_active_minus1; i++) { + if (slice_hdr->pred_weight_table.luma_weight_l1_flag[i]) { + slice_param->delta_luma_weight_l1[i] = w->delta_luma_weight_l1[i]; + slice_param->luma_offset_l1[i] = w->luma_offset_l1[i]; +#if VA_CHECK_VERSION(1,2,0) + if (slice_rext_param) + slice_rext_param->luma_offset_l1[i] = w->luma_offset_l1[i]; +#endif + } + if (slice_hdr->pred_weight_table.chroma_weight_l1_flag[i]) { + for (j = 0; j < 2; j++) { + slice_param->delta_chroma_weight_l1[i][j] = + w->delta_chroma_weight_l1[i][j]; + /* Find ChromaWeightL1 */ + chroma_weight = + (1 << chroma_log2_weight_denom) + + w->delta_chroma_weight_l1[i][j]; + /* 7-56 */ + slice_param->ChromaOffsetL1[i][j] = + CLAMP ((priv->WpOffsetHalfRangeC + + w->delta_chroma_offset_l1[i][j] - + ((priv->WpOffsetHalfRangeC * + chroma_weight) >> chroma_log2_weight_denom)), + -priv->WpOffsetHalfRangeC, priv->WpOffsetHalfRangeC - 1); +#if VA_CHECK_VERSION(1,2,0) + if (slice_rext_param) + slice_rext_param->ChromaOffsetL1[i][j] = + CLAMP ((priv->WpOffsetHalfRangeC + + w->delta_chroma_offset_l1[i][j] - + ((priv->WpOffsetHalfRangeC * + chroma_weight) >> chroma_log2_weight_denom)), + -priv->WpOffsetHalfRangeC, priv->WpOffsetHalfRangeC - 1); +#endif + } + } + } + } + } + return TRUE; +} + +static gboolean +fill_RefPicList (GstVaapiDecoderH265 * decoder, + GstVaapiPictureH265 * picture, GstVaapiSlice * slice, + GstH265SliceHdr * slice_hdr) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + VASliceParameterBufferHEVC *const slice_param = slice->param; + GstVaapiPicture *const base_picture = &picture->base; + VAPictureParameterBufferHEVC *const pic_param = base_picture->param; + guint i, num_ref_lists = 0, j; + + slice_param->num_ref_idx_l0_active_minus1 = 0; + slice_param->num_ref_idx_l1_active_minus1 = 0; + for (j = 0; j < 2; j++) + for (i = 0; i < 15; i++) + slice_param->RefPicList[j][i] = 0xFF; + + if (GST_H265_IS_B_SLICE (slice_hdr)) + num_ref_lists = 2; + else if (GST_H265_IS_I_SLICE (slice_hdr)) + num_ref_lists = 0; + else + num_ref_lists = 1; + + if (num_ref_lists < 1) + return TRUE; + + slice_param->num_ref_idx_l0_active_minus1 = + slice_hdr->num_ref_idx_l0_active_minus1; + slice_param->num_ref_idx_l1_active_minus1 = + slice_hdr->num_ref_idx_l1_active_minus1; + + for (i = 0; i < priv->RefPicList0_count; i++) + slice_param->RefPicList[0][i] = + get_index_for_RefPicListX (pic_param->ReferenceFrames, + priv->RefPicList0[i]); + for (; i < 15; i++) + slice_param->RefPicList[0][i] = 0xFF; + + if (num_ref_lists < 2) + return TRUE; + + for (i = 0; i < priv->RefPicList1_count; i++) + slice_param->RefPicList[1][i] = + get_index_for_RefPicListX (pic_param->ReferenceFrames, + priv->RefPicList1[i]); + for (; i < 15; i++) + slice_param->RefPicList[1][i] = 0xFF; + + return TRUE; +} + +static gboolean +fill_slice (GstVaapiDecoderH265 * decoder, + GstVaapiPictureH265 * picture, GstVaapiSlice * slice, + GstVaapiParserInfoH265 * pi, GstVaapiDecoderUnit * unit) +{ + GstH265SliceHdr *slice_hdr = &pi->data.slice_hdr; + VASliceParameterBufferHEVC *slice_param = slice->param; + +#if VA_CHECK_VERSION(1,2,0) + GstVaapiDecoderH265Private *const priv = &decoder->priv; + VASliceParameterBufferHEVCRext *slice_rext_param = NULL; + if (is_range_extension_profile (priv->profile) + || is_scc_profile (priv->profile)) { + VASliceParameterBufferHEVCExtension *param = slice->param; + slice_param = ¶m->base; + slice_rext_param = ¶m->rext; + } +#endif + + /* Fill in VASliceParameterBufferH265 */ + slice_param->LongSliceFlags.value = 0; + slice_param->slice_data_byte_offset = + get_slice_data_byte_offset (slice_hdr, pi->nalu.header_bytes); + + slice_param->slice_segment_address = slice_hdr->segment_address; + +#define COPY_LFF(f) \ + slice_param->LongSliceFlags.fields.f = (slice_hdr)->f + + if (GST_VAAPI_PICTURE_FLAG_IS_SET (picture, GST_VAAPI_PICTURE_FLAG_AU_END)) + slice_param->LongSliceFlags.fields.LastSliceOfPic = 1; + else + slice_param->LongSliceFlags.fields.LastSliceOfPic = 0; + + COPY_LFF (dependent_slice_segment_flag); + + COPY_LFF (mvd_l1_zero_flag); + COPY_LFF (cabac_init_flag); + COPY_LFF (collocated_from_l0_flag); + slice_param->LongSliceFlags.fields.color_plane_id = + slice_hdr->colour_plane_id; + slice_param->LongSliceFlags.fields.slice_type = slice_hdr->type; + slice_param->LongSliceFlags.fields.slice_sao_luma_flag = + slice_hdr->sao_luma_flag; + slice_param->LongSliceFlags.fields.slice_sao_chroma_flag = + slice_hdr->sao_chroma_flag; + slice_param->LongSliceFlags.fields.slice_temporal_mvp_enabled_flag = + slice_hdr->temporal_mvp_enabled_flag; + slice_param->LongSliceFlags.fields.slice_deblocking_filter_disabled_flag = + slice_hdr->deblocking_filter_disabled_flag; + slice_param->LongSliceFlags.fields. + slice_loop_filter_across_slices_enabled_flag = + slice_hdr->loop_filter_across_slices_enabled_flag; + + if (!slice_hdr->temporal_mvp_enabled_flag) + slice_param->collocated_ref_idx = 0xFF; + else + slice_param->collocated_ref_idx = slice_hdr->collocated_ref_idx; + + slice_param->num_ref_idx_l0_active_minus1 = + slice_hdr->num_ref_idx_l0_active_minus1; + slice_param->num_ref_idx_l1_active_minus1 = + slice_hdr->num_ref_idx_l1_active_minus1; + slice_param->slice_qp_delta = slice_hdr->qp_delta; + slice_param->slice_cb_qp_offset = slice_hdr->cb_qp_offset; + slice_param->slice_cr_qp_offset = slice_hdr->cr_qp_offset; + slice_param->slice_beta_offset_div2 = slice_hdr->beta_offset_div2; + slice_param->slice_tc_offset_div2 = slice_hdr->tc_offset_div2; + slice_param->five_minus_max_num_merge_cand = + slice_hdr->five_minus_max_num_merge_cand; + +#if VA_CHECK_VERSION(1,2,0) + if (slice_rext_param) { + slice_rext_param->slice_ext_flags.bits.cu_chroma_qp_offset_enabled_flag = + slice_hdr->cu_chroma_qp_offset_enabled_flag; + slice_rext_param->slice_ext_flags.bits.use_integer_mv_flag = + slice_hdr->use_integer_mv_flag; + + slice_rext_param->slice_act_y_qp_offset = slice_hdr->slice_act_y_qp_offset; + slice_rext_param->slice_act_cb_qp_offset = + slice_hdr->slice_act_cb_qp_offset; + slice_rext_param->slice_act_cr_qp_offset = + slice_hdr->slice_act_cr_qp_offset; + } +#endif + + if (!fill_RefPicList (decoder, picture, slice, slice_hdr)) + return FALSE; + + if (!fill_pred_weight_table (decoder, slice, slice_hdr)) + return FALSE; + + return TRUE; +} + +static GstVaapiDecoderStatus +decode_slice (GstVaapiDecoderH265 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiParserInfoH265 *const pi = unit->parsed_info; + GstVaapiPictureH265 *const picture = priv->current_picture; + GstH265SliceHdr *const slice_hdr = &pi->data.slice_hdr; + GstVaapiSlice *slice = NULL; + GstBuffer *const buffer = + GST_VAAPI_DECODER_CODEC_FRAME (decoder)->input_buffer; + GstMapInfo map_info; + + GST_DEBUG ("slice (%u bytes)", pi->nalu.size); + if (!is_valid_state (pi->state, GST_H265_VIDEO_STATE_VALID_PICTURE_HEADERS)) { + GST_WARNING ("failed to receive enough headers to decode slice"); + return GST_VAAPI_DECODER_STATUS_SUCCESS; + } + + if (!ensure_pps (decoder, slice_hdr->pps)) { + GST_ERROR ("failed to activate PPS"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + if (!ensure_sps (decoder, slice_hdr->pps->sps)) { + GST_ERROR ("failed to activate SPS"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) { + GST_ERROR ("failed to map buffer"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + /* Check wether this is the first/last slice in the current access unit */ + if (pi->flags & GST_VAAPI_DECODER_UNIT_FLAG_AU_START) + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_AU_START); + + if (pi->flags & GST_VAAPI_DECODER_UNIT_FLAG_AU_END) + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_AU_END); + + if (is_range_extension_profile (priv->profile) + || is_scc_profile (priv->profile)) { +#if VA_CHECK_VERSION(1,2,0) + slice = GST_VAAPI_SLICE_NEW (HEVCExtension, decoder, + (map_info.data + unit->offset + pi->nalu.offset), pi->nalu.size); +#endif + } else { + slice = GST_VAAPI_SLICE_NEW (HEVC, decoder, + (map_info.data + unit->offset + pi->nalu.offset), pi->nalu.size); + } + gst_buffer_unmap (buffer, &map_info); + if (!slice) { + GST_ERROR ("failed to allocate slice"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + init_picture_refs (decoder, picture, slice_hdr); + + if (!fill_slice (decoder, picture, slice, pi, unit)) { + gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (slice)); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + gst_vaapi_picture_add_slice (GST_VAAPI_PICTURE_CAST (picture), slice); + picture->last_slice_hdr = slice_hdr; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static inline gint +scan_for_start_code (GstAdapter * adapter, guint ofs, guint size, guint32 * scp) +{ + if (size == 0) + return -1; + + return (gint) gst_adapter_masked_scan_uint32_peek (adapter, + 0xffffff00, 0x00000100, ofs, size, scp); +} + +static GstVaapiDecoderStatus +decode_unit (GstVaapiDecoderH265 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiParserInfoH265 *const pi = unit->parsed_info; + GstVaapiDecoderStatus status; + priv->decoder_state |= pi->state; + switch (pi->nalu.type) { + case GST_H265_NAL_VPS: + status = decode_vps (decoder, unit); + break; + case GST_H265_NAL_SPS: + status = decode_sps (decoder, unit); + break; + case GST_H265_NAL_PPS: + status = decode_pps (decoder, unit); + break; + case GST_H265_NAL_SLICE_TRAIL_N: + case GST_H265_NAL_SLICE_TRAIL_R: + case GST_H265_NAL_SLICE_TSA_N: + case GST_H265_NAL_SLICE_TSA_R: + case GST_H265_NAL_SLICE_STSA_N: + case GST_H265_NAL_SLICE_STSA_R: + case GST_H265_NAL_SLICE_RADL_N: + case GST_H265_NAL_SLICE_RADL_R: + case GST_H265_NAL_SLICE_RASL_N: + case GST_H265_NAL_SLICE_RASL_R: + case GST_H265_NAL_SLICE_BLA_W_LP: + case GST_H265_NAL_SLICE_BLA_W_RADL: + case GST_H265_NAL_SLICE_BLA_N_LP: + case GST_H265_NAL_SLICE_IDR_W_RADL: + case GST_H265_NAL_SLICE_IDR_N_LP: + case GST_H265_NAL_SLICE_CRA_NUT: + /* slice decoding will get started only after completing all the + initialization routines for each picture which is hanlding in + start_frame() call back, so the new_bitstream and prev_nal_is_eos + flags will have effects starting from the next frame onwards */ + priv->new_bitstream = FALSE; + priv->prev_nal_is_eos = FALSE; + status = decode_slice (decoder, unit); + break; + case GST_H265_NAL_EOB: + priv->new_bitstream = TRUE; + GST_DEBUG + ("Next AU(if there is any) will be the begining of new bitstream"); + status = decode_sequence_end (decoder); + break; + case GST_H265_NAL_EOS: + priv->prev_nal_is_eos = TRUE; + status = decode_sequence_end (decoder); + break; + case GST_H265_NAL_SUFFIX_SEI: + case GST_H265_NAL_PREFIX_SEI: + status = decode_sei (decoder, unit); + break; + default: + GST_WARNING ("unsupported NAL unit type %d", pi->nalu.type); + status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + break; + } + return status; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_h265_decode_codec_data (GstVaapiDecoder * + base_decoder, const guchar * buf, guint buf_size) +{ + GstVaapiDecoderH265 *const decoder = + GST_VAAPI_DECODER_H265_CAST (base_decoder); + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiDecoderStatus status; + GstVaapiDecoderUnit unit; + GstVaapiParserInfoH265 *pi = NULL; + GstH265ParserResult result; + guint num_nal_arrays, num_nals; + guint i, j, ofs; + + if (!priv->is_opened) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + unit.parsed_info = NULL; + if (buf_size < 23) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + if (buf[0] != 1) { + GST_ERROR ("failed to decode codec-data, not in hvcC format"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + priv->nal_length_size = (buf[21] & 0x03) + 1; + GST_DEBUG ("nal length size %u", priv->nal_length_size); + num_nal_arrays = buf[22]; + ofs = 23; + for (i = 0; i < num_nal_arrays; i++) { + if (ofs + 1 > buf_size) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + num_nals = GST_READ_UINT16_BE (buf + ofs + 1); + /* the max number of nals is GST_H265_MAX_PPS_COUNT (64) */ + if (num_nals > 64) + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + ofs += 3; + + for (j = 0; j < num_nals; j++) { + pi = gst_vaapi_parser_info_h265_new (); + if (!pi) + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + unit.parsed_info = pi; + result = gst_h265_parser_identify_nalu_hevc (priv->parser, + buf, ofs, buf_size, 2, &pi->nalu); + if (result != GST_H265_PARSER_OK) { + status = get_status (result); + goto cleanup; + } + + pi->state = priv->parser_state; + pi->flags = 0; + + switch (pi->nalu.type) { + case GST_H265_NAL_VPS: + status = parse_vps (decoder, &unit); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + goto cleanup; + status = decode_vps (decoder, &unit); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + goto cleanup; + break; + case GST_H265_NAL_SPS: + status = parse_sps (decoder, &unit); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + goto cleanup; + status = decode_sps (decoder, &unit); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + goto cleanup; + break; + case GST_H265_NAL_PPS: + status = parse_pps (decoder, &unit); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + goto cleanup; + status = decode_pps (decoder, &unit); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + goto cleanup; + break; + case GST_H265_NAL_SUFFIX_SEI: + case GST_H265_NAL_PREFIX_SEI: + status = parse_sei (decoder, &unit); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + goto cleanup; + status = decode_sei (decoder, &unit); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + goto cleanup; + break; + + } + ofs = pi->nalu.offset + pi->nalu.size; + gst_vaapi_parser_info_h265_replace (&pi, NULL); + } + } + + priv->is_hvcC = TRUE; + status = GST_VAAPI_DECODER_STATUS_SUCCESS; +cleanup: + gst_vaapi_parser_info_h265_replace (&pi, NULL); + return status; +} + +static GstVaapiDecoderStatus +ensure_decoder (GstVaapiDecoderH265 * decoder) +{ + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiDecoderStatus status; + + if (!priv->is_opened) { + priv->is_opened = gst_vaapi_decoder_h265_open (decoder); + if (!priv->is_opened) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC; + status = + gst_vaapi_decoder_decode_codec_data (GST_VAAPI_DECODER_CAST (decoder)); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static void +populate_dependent_slice_hdr (GstVaapiParserInfoH265 * pi, + GstVaapiParserInfoH265 * indep_pi) +{ + GstH265SliceHdr *slice_hdr = &pi->data.slice_hdr; + GstH265SliceHdr *indep_slice_hdr = &indep_pi->data.slice_hdr; + + memcpy (&slice_hdr->type, &indep_slice_hdr->type, + offsetof (GstH265SliceHdr, num_entry_point_offsets) - + offsetof (GstH265SliceHdr, type)); +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_h265_parse (GstVaapiDecoder * base_decoder, + GstAdapter * adapter, gboolean at_eos, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH265 *const decoder = + GST_VAAPI_DECODER_H265_CAST (base_decoder); + GstVaapiDecoderH265Private *const priv = &decoder->priv; + GstVaapiParserState *const ps = GST_VAAPI_PARSER_STATE (base_decoder); + GstVaapiParserInfoH265 *pi; + GstVaapiDecoderStatus status; + GstH265ParserResult result; + guchar *buf; + guint i, size, buf_size, nalu_size, flags; + guint32 start_code; + gint ofs, ofs2; + gboolean at_au_end = FALSE; + + status = ensure_decoder (decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + switch (priv->stream_alignment) { + case GST_VAAPI_STREAM_ALIGN_H265_NALU: + case GST_VAAPI_STREAM_ALIGN_H265_AU: + size = gst_adapter_available_fast (adapter); + break; + default: + size = gst_adapter_available (adapter); + break; + } + + if (priv->is_hvcC) { + if (size < priv->nal_length_size) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + buf = (guchar *) & start_code; + g_assert (priv->nal_length_size <= sizeof (start_code)); + gst_adapter_copy (adapter, buf, 0, priv->nal_length_size); + nalu_size = 0; + for (i = 0; i < priv->nal_length_size; i++) + nalu_size = (nalu_size << 8) | buf[i]; + buf_size = priv->nal_length_size + nalu_size; + if (size < buf_size) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + else if (priv->stream_alignment == GST_VAAPI_STREAM_ALIGN_H265_AU) + at_au_end = (buf_size == size); + } else { + if (size < 4) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + if (priv->stream_alignment == GST_VAAPI_STREAM_ALIGN_H265_NALU) { + buf_size = size; + ofs = scan_for_start_code (adapter, 4, size - 4, NULL); + if (ofs > 0) + buf_size = ofs; + } else { + ofs = scan_for_start_code (adapter, 0, size, NULL); + if (ofs < 0) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + if (ofs > 0) { + gst_adapter_flush (adapter, ofs); + size -= ofs; + } + + ofs2 = ps->input_offset2 - ofs - 4; + if (ofs2 < 4) + ofs2 = 4; + ofs = G_UNLIKELY (size < ofs2 + 4) ? -1 : + scan_for_start_code (adapter, ofs2, size - ofs2, NULL); + if (ofs < 0) { + // Assume the whole NAL unit is present if end-of-stream + // or stream buffers aligned on access unit boundaries + if (priv->stream_alignment == GST_VAAPI_STREAM_ALIGN_H265_AU) + at_au_end = TRUE; + else if (!at_eos) { + ps->input_offset2 = size; + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + } + ofs = size; + } + buf_size = ofs; + } + } + ps->input_offset2 = 0; + buf = (guchar *) gst_adapter_map (adapter, buf_size); + if (!buf) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + unit->size = buf_size; + pi = gst_vaapi_parser_info_h265_new (); + if (!pi) + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + gst_vaapi_decoder_unit_set_parsed_info (unit, + pi, (GDestroyNotify) gst_vaapi_mini_object_unref); + if (priv->is_hvcC) + result = gst_h265_parser_identify_nalu_hevc (priv->parser, + buf, 0, buf_size, priv->nal_length_size, &pi->nalu); + else + result = gst_h265_parser_identify_nalu_unchecked (priv->parser, + buf, 0, buf_size, &pi->nalu); + status = get_status (result); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + goto exit; + switch (pi->nalu.type) { + case GST_H265_NAL_VPS: + status = parse_vps (decoder, unit); + break; + case GST_H265_NAL_SPS: + status = parse_sps (decoder, unit); + break; + case GST_H265_NAL_PPS: + status = parse_pps (decoder, unit); + break; + case GST_H265_NAL_PREFIX_SEI: + case GST_H265_NAL_SUFFIX_SEI: + status = parse_sei (decoder, unit); + break; + case GST_H265_NAL_SLICE_TRAIL_N: + case GST_H265_NAL_SLICE_TRAIL_R: + case GST_H265_NAL_SLICE_TSA_N: + case GST_H265_NAL_SLICE_TSA_R: + case GST_H265_NAL_SLICE_STSA_N: + case GST_H265_NAL_SLICE_STSA_R: + case GST_H265_NAL_SLICE_RADL_N: + case GST_H265_NAL_SLICE_RADL_R: + case GST_H265_NAL_SLICE_RASL_N: + case GST_H265_NAL_SLICE_RASL_R: + case GST_H265_NAL_SLICE_BLA_W_LP: + case GST_H265_NAL_SLICE_BLA_W_RADL: + case GST_H265_NAL_SLICE_BLA_N_LP: + case GST_H265_NAL_SLICE_IDR_W_RADL: + case GST_H265_NAL_SLICE_IDR_N_LP: + case GST_H265_NAL_SLICE_CRA_NUT: + status = parse_slice (decoder, unit); + break; + default: + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + break; + } + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + goto exit; + flags = 0; + if (at_au_end) { + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END | + GST_VAAPI_DECODER_UNIT_FLAG_AU_END; + } + + switch (pi->nalu.type) { + case GST_H265_NAL_AUD: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_AU_START; + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START; + /* fall-through */ + case GST_H265_NAL_FD: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP; + break; + case GST_H265_NAL_EOB: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_STREAM_END; + /* fall-through */ + case GST_H265_NAL_SUFFIX_SEI: + case GST_H265_NAL_EOS: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END; + flags |= GST_VAAPI_DECODER_UNIT_FLAG_AU_END; + break; + case GST_H265_NAL_VPS: + case GST_H265_NAL_SPS: + case GST_H265_NAL_PPS: + case GST_H265_NAL_PREFIX_SEI: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_AU_START; + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START; + break; + case GST_H265_NAL_SLICE_TRAIL_N: + case GST_H265_NAL_SLICE_TRAIL_R: + case GST_H265_NAL_SLICE_TSA_N: + case GST_H265_NAL_SLICE_TSA_R: + case GST_H265_NAL_SLICE_STSA_N: + case GST_H265_NAL_SLICE_STSA_R: + case GST_H265_NAL_SLICE_RADL_N: + case GST_H265_NAL_SLICE_RADL_R: + case GST_H265_NAL_SLICE_RASL_N: + case GST_H265_NAL_SLICE_RASL_R: + case GST_H265_NAL_SLICE_BLA_W_LP: + case GST_H265_NAL_SLICE_BLA_W_RADL: + case GST_H265_NAL_SLICE_BLA_N_LP: + case GST_H265_NAL_SLICE_IDR_W_RADL: + case GST_H265_NAL_SLICE_IDR_N_LP: + case GST_H265_NAL_SLICE_CRA_NUT: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE; + if (priv->prev_pi && + (priv->prev_pi->flags & GST_VAAPI_DECODER_UNIT_FLAG_AU_END)) { + flags |= GST_VAAPI_DECODER_UNIT_FLAG_AU_START | + GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START; + } else if (is_new_picture (pi, priv->prev_slice_pi)) { + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START; + if (is_new_access_unit (pi, priv->prev_slice_pi)) + flags |= GST_VAAPI_DECODER_UNIT_FLAG_AU_START; + } + gst_vaapi_parser_info_h265_replace (&priv->prev_slice_pi, pi); + if (!pi->data.slice_hdr.dependent_slice_segment_flag) + gst_vaapi_parser_info_h265_replace (&priv->prev_independent_slice_pi, + pi); + else + populate_dependent_slice_hdr (pi, priv->prev_independent_slice_pi); + if (!GST_H265_IS_I_SLICE (&pi->data.slice_hdr)) + priv->parser_state |= GST_H265_VIDEO_STATE_GOT_P_SLICE; + break; + default: + /* Fix */ + break; + } + if ((flags & GST_VAAPI_DECODER_UNIT_FLAGS_AU) && priv->prev_slice_pi) + priv->prev_slice_pi->flags |= GST_VAAPI_DECODER_UNIT_FLAG_AU_END; + GST_VAAPI_DECODER_UNIT_FLAG_SET (unit, flags); + pi->nalu.data = NULL; + pi->state = priv->parser_state; + pi->flags = flags; + gst_vaapi_parser_info_h265_replace (&priv->prev_pi, pi); + return GST_VAAPI_DECODER_STATUS_SUCCESS; + +exit: + gst_adapter_flush (adapter, unit->size); + gst_vaapi_parser_info_h265_unref (pi); + return status; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_h265_decode (GstVaapiDecoder * base_decoder, + GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH265 *const decoder = + GST_VAAPI_DECODER_H265_CAST (base_decoder); + GstVaapiDecoderStatus status; + + status = ensure_decoder (decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + return decode_unit (decoder, unit); +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_h265_start_frame (GstVaapiDecoder * base_decoder, + GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderH265 *const decoder = + GST_VAAPI_DECODER_H265_CAST (base_decoder); + + return decode_picture (decoder, unit); +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_h265_end_frame (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderH265 *const decoder = + GST_VAAPI_DECODER_H265_CAST (base_decoder); + + return decode_current_picture (decoder); +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_h265_flush (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderH265 *const decoder = + GST_VAAPI_DECODER_H265_CAST (base_decoder); + + dpb_flush (decoder); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static void +gst_vaapi_decoder_h265_finalize (GObject * object) +{ + GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (object); + + gst_vaapi_decoder_h265_destroy (base_decoder); + G_OBJECT_CLASS (gst_vaapi_decoder_h265_parent_class)->finalize (object); +} + +static void +gst_vaapi_decoder_h265_class_init (GstVaapiDecoderH265Class * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstVaapiDecoderClass *const decoder_class = GST_VAAPI_DECODER_CLASS (klass); + + object_class->finalize = gst_vaapi_decoder_h265_finalize; + + decoder_class->reset = gst_vaapi_decoder_h265_reset; + decoder_class->parse = gst_vaapi_decoder_h265_parse; + decoder_class->decode = gst_vaapi_decoder_h265_decode; + decoder_class->start_frame = gst_vaapi_decoder_h265_start_frame; + decoder_class->end_frame = gst_vaapi_decoder_h265_end_frame; + decoder_class->flush = gst_vaapi_decoder_h265_flush; + decoder_class->decode_codec_data = gst_vaapi_decoder_h265_decode_codec_data; +} + +static void +gst_vaapi_decoder_h265_init (GstVaapiDecoderH265 * decoder) +{ + GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (decoder); + + gst_vaapi_decoder_h265_create (base_decoder); +} + +/** + * gst_vaapi_decoder_h265_set_alignment: + * @decoder: a #GstVaapiDecoderH265 + * @alignment: the #GstVaapiStreamAlignH265 + * + * Specifies how stream buffers are aligned / fed, i.e. the boundaries + * of each buffer that is supplied to the decoder. This could be no + * specific alignment, NAL unit boundaries, or access unit boundaries. + */ +void +gst_vaapi_decoder_h265_set_alignment (GstVaapiDecoderH265 * decoder, + GstVaapiStreamAlignH265 alignment) +{ + g_return_if_fail (decoder != NULL); + decoder->priv.stream_alignment = alignment; +} + +/** + * gst_vaapi_decoder_h265_new: + * @display: a #GstVaapiDisplay + * @caps: a #GstCaps holding codec information + * + * Creates a new #GstVaapiDecoder for MPEG-2 decoding. The @caps can + * hold extra information like codec-data and pictured coded size. + * + * Return value: the newly allocated #GstVaapiDecoder object + */ +GstVaapiDecoder * +gst_vaapi_decoder_h265_new (GstVaapiDisplay * display, GstCaps * caps) +{ + return g_object_new (GST_TYPE_VAAPI_DECODER_H265, "display", display, + "caps", caps, NULL); +} diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_h265.h b/gst-libs/gst/vaapi/gstvaapidecoder_h265.h new file mode 100644 index 0000000000..0b5d0922e3 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_h265.h @@ -0,0 +1,70 @@ +/* + * gstvaapidecoder_h265.h - H.265 decoder + * + * Copyright (C) 2015 Intel Corporation + * Author: Sreerenj Balachandran + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODER_H265_H +#define GST_VAAPI_DECODER_H265_H + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_DECODER_H265 \ + (gst_vaapi_decoder_h265_get_type ()) +#define GST_VAAPI_DECODER_H265(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DECODER_H265, GstVaapiDecoderH265)) +#define GST_VAAPI_IS_DECODER_H265(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_DECODER_H265)) + +typedef struct _GstVaapiDecoderH265 GstVaapiDecoderH265; + +/** + * GstVaapiStreamAlignH265: + * @GST_VAAPI_STREAM_ALIGN_H265_NONE: Generic H.265 stream buffers + * @GST_VAAPI_STREAM_ALIGN_H265_NALU: H.265 stream buffers aligned NAL + * unit boundaries + * @GST_VAAPI_STREAM_ALIGN_H265_AU: H.265 stream buffers aligned on + * access unit boundaries + * + * Set of possible buffer alignments for H.265 streams. + */ +typedef enum { + GST_VAAPI_STREAM_ALIGN_H265_NONE, + GST_VAAPI_STREAM_ALIGN_H265_NALU, + GST_VAAPI_STREAM_ALIGN_H265_AU +} GstVaapiStreamAlignH265; + +GType +gst_vaapi_decoder_h265_get_type (void) G_GNUC_CONST; + +GstVaapiDecoder * +gst_vaapi_decoder_h265_new (GstVaapiDisplay *display, GstCaps *caps); + +void +gst_vaapi_decoder_h265_set_alignment (GstVaapiDecoderH265 *decoder, + GstVaapiStreamAlignH265 alignment); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDecoderH265, gst_object_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_DECODER_H265_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c b/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c new file mode 100644 index 0000000000..3122f7beeb --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c @@ -0,0 +1,964 @@ +/* + * gstvaapidecoder_jpeg.c - JPEG decoder + * + * Copyright (C) 2011-2013 Intel Corporation + * Author: Wind Yuan + * Author: Gwenole Beauchesne + * + * 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:gstvaapidecoder_jpeg + * @short_description: JPEG decoder + */ + +#include "sysdeps.h" +#include +#include "gstvaapicompat.h" +#include "gstvaapidecoder_jpeg.h" +#include "gstvaapidecoder_objects.h" +#include "gstvaapidecoder_priv.h" +#include "gstvaapidisplay_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +#define GST_VAAPI_DECODER_JPEG_CAST(decoder) \ + ((GstVaapiDecoderJpeg *)(decoder)) + +typedef struct _GstVaapiDecoderJpegPrivate GstVaapiDecoderJpegPrivate; +typedef struct _GstVaapiDecoderJpegClass GstVaapiDecoderJpegClass; + +typedef enum +{ + GST_JPEG_VIDEO_STATE_GOT_SOI = 1 << 0, + GST_JPEG_VIDEO_STATE_GOT_SOF = 1 << 1, + GST_JPEG_VIDEO_STATE_GOT_SOS = 1 << 2, + GST_JPEG_VIDEO_STATE_GOT_HUF_TABLE = 1 << 3, + GST_JPEG_VIDEO_STATE_GOT_IQ_TABLE = 1 << 4, + + GST_JPEG_VIDEO_STATE_VALID_PICTURE = (GST_JPEG_VIDEO_STATE_GOT_SOI | + GST_JPEG_VIDEO_STATE_GOT_SOF | GST_JPEG_VIDEO_STATE_GOT_SOS), +} GstJpegVideoState; + +struct _GstVaapiDecoderJpegPrivate +{ + GstVaapiProfile profile; + guint width; + guint height; + GstVaapiPicture *current_picture; + GstJpegFrameHdr frame_hdr; + GstJpegHuffmanTables huf_tables; + GstJpegQuantTables quant_tables; + guint mcu_restart; + guint parser_state; + guint decoder_state; + guint is_opened:1; + guint profile_changed:1; + guint size_changed:1; +}; + +/** + * GstVaapiDecoderJpeg: + * + * A decoder based on Jpeg. + */ +struct _GstVaapiDecoderJpeg +{ + /*< private > */ + GstVaapiDecoder parent_instance; + GstVaapiDecoderJpegPrivate priv; +}; + +/** + * GstVaapiDecoderJpegClass: + * + * A decoder class based on Jpeg. + */ +struct _GstVaapiDecoderJpegClass +{ + /*< private > */ + GstVaapiDecoderClass parent_class; +}; + +G_DEFINE_TYPE (GstVaapiDecoderJpeg, gst_vaapi_decoder_jpeg, + GST_TYPE_VAAPI_DECODER); + +static inline void +unit_set_marker_code (GstVaapiDecoderUnit * unit, GstJpegMarker marker) +{ + unit->parsed_info = GSIZE_TO_POINTER (marker); +} + +static inline GstJpegMarker +unit_get_marker_code (GstVaapiDecoderUnit * unit) +{ + return GPOINTER_TO_SIZE (unit->parsed_info); +} + +static void +gst_vaapi_decoder_jpeg_close (GstVaapiDecoderJpeg * decoder) +{ + GstVaapiDecoderJpegPrivate *const priv = &decoder->priv; + + gst_vaapi_picture_replace (&priv->current_picture, NULL); + + /* Reset all */ + priv->profile = GST_VAAPI_PROFILE_JPEG_BASELINE; + priv->width = 0; + priv->height = 0; + priv->is_opened = FALSE; + priv->profile_changed = TRUE; + priv->size_changed = TRUE; +} + +static gboolean +gst_vaapi_decoder_jpeg_open (GstVaapiDecoderJpeg * decoder) +{ + GstVaapiDecoderJpegPrivate *const priv = &decoder->priv; + + gst_vaapi_decoder_jpeg_close (decoder); + + priv->parser_state = 0; + priv->decoder_state = 0; + return TRUE; +} + +static void +gst_vaapi_decoder_jpeg_destroy (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderJpeg *const decoder = + GST_VAAPI_DECODER_JPEG_CAST (base_decoder); + + gst_vaapi_decoder_jpeg_close (decoder); +} + +static gboolean +gst_vaapi_decoder_jpeg_create (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderJpeg *const decoder = + GST_VAAPI_DECODER_JPEG_CAST (base_decoder); + GstVaapiDecoderJpegPrivate *const priv = &decoder->priv; + + priv->profile = GST_VAAPI_PROFILE_JPEG_BASELINE; + priv->profile_changed = TRUE; + priv->size_changed = TRUE; + return TRUE; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_jpeg_reset (GstVaapiDecoder * base_decoder) +{ + gst_vaapi_decoder_jpeg_destroy (base_decoder); + gst_vaapi_decoder_jpeg_create (base_decoder); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static gboolean +get_chroma_type (GstJpegFrameHdr * frame_hdr, GstVaapiChromaType * chroma_type) +{ + int h0 = frame_hdr->components[0].horizontal_factor; + int h1 = frame_hdr->components[1].horizontal_factor; + int h2 = frame_hdr->components[2].horizontal_factor; + int v0 = frame_hdr->components[0].vertical_factor; + int v1 = frame_hdr->components[1].vertical_factor; + int v2 = frame_hdr->components[2].vertical_factor; + + if (frame_hdr->num_components == 1) { + *chroma_type = GST_VAAPI_CHROMA_TYPE_YUV400; + return TRUE; + } + + if (h1 != h2 || v1 != v2) + return FALSE; + + if (h0 == h1) { + if (v0 == v1) + *chroma_type = GST_VAAPI_CHROMA_TYPE_YUV444; + else if (v0 == 2 * v1) + *chroma_type = GST_VAAPI_CHROMA_TYPE_YUV422; + else + return FALSE; + } else if (h0 == 2 * h1) { + if (v0 == v1) + *chroma_type = GST_VAAPI_CHROMA_TYPE_YUV422; + else if (v0 == 2 * v1) + *chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420; + else + return FALSE; + } else if (h0 == 4 * h1) { + if (v0 == v1) + *chroma_type = GST_VAAPI_CHROMA_TYPE_YUV411; + else + return FALSE; + } else + return FALSE; + + return TRUE; +} + +static GstVaapiDecoderStatus +ensure_context (GstVaapiDecoderJpeg * decoder) +{ + GstVaapiDecoderJpegPrivate *const priv = &decoder->priv; + GstJpegFrameHdr *const frame_hdr = &priv->frame_hdr; + GstVaapiChromaType chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420; + GstVaapiProfile profiles[2]; + GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD; + guint i, n_profiles = 0; + gboolean reset_context = FALSE; + + if (priv->profile_changed) { + GST_DEBUG ("profile changed"); + priv->profile_changed = FALSE; + reset_context = TRUE; + + profiles[n_profiles++] = priv->profile; + //if (priv->profile == GST_VAAPI_PROFILE_JPEG_EXTENDED) + // profiles[n_profiles++] = GST_VAAPI_PROFILE_JPEG_BASELINE; + + for (i = 0; i < n_profiles; i++) { + if (gst_vaapi_display_has_decoder (GST_VAAPI_DECODER_DISPLAY (decoder), + profiles[i], entrypoint)) + break; + } + if (i == n_profiles) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + priv->profile = profiles[i]; + } + + if (priv->size_changed) { + GST_DEBUG ("size changed"); + priv->size_changed = FALSE; + reset_context = TRUE; + } + + if (reset_context) { + GstVaapiContextInfo info; + + info.profile = priv->profile; + info.entrypoint = entrypoint; + info.width = priv->width; + info.height = priv->height; + info.ref_frames = 2; + if (!get_chroma_type (frame_hdr, &chroma_type)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT; + info.chroma_type = chroma_type; + + reset_context = + gst_vaapi_decoder_ensure_context (GST_VAAPI_DECODER (decoder), &info); + if (!reset_context) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static inline gboolean +is_valid_state (guint state, guint ref_state) +{ + return (state & ref_state) == ref_state; +} + +#define VALID_STATE(TYPE, STATE) \ + is_valid_state(priv->G_PASTE(TYPE,_state), \ + G_PASTE(GST_JPEG_VIDEO_STATE_,STATE)) + +static GstVaapiDecoderStatus +decode_current_picture (GstVaapiDecoderJpeg * decoder) +{ + GstVaapiDecoderJpegPrivate *const priv = &decoder->priv; + GstVaapiPicture *const picture = priv->current_picture; + + if (!VALID_STATE (decoder, VALID_PICTURE)) + goto drop_frame; + priv->decoder_state = 0; + + if (!picture) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + if (!gst_vaapi_picture_decode (picture)) + goto error; + if (!gst_vaapi_picture_output (picture)) + goto error; + gst_vaapi_picture_replace (&priv->current_picture, NULL); + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + /* ERRORS */ +error: + { + gst_vaapi_picture_replace (&priv->current_picture, NULL); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + +drop_frame: + { + priv->decoder_state = 0; + return (GstVaapiDecoderStatus) GST_VAAPI_DECODER_STATUS_DROP_FRAME; + } +} + +static gboolean +fill_picture (GstVaapiDecoderJpeg * decoder, + GstVaapiPicture * picture, GstJpegFrameHdr * frame_hdr) +{ + VAPictureParameterBufferJPEGBaseline *const pic_param = picture->param; + guint i; + + memset (pic_param, 0, sizeof (VAPictureParameterBufferJPEGBaseline)); + pic_param->picture_width = frame_hdr->width; + pic_param->picture_height = frame_hdr->height; + + pic_param->num_components = frame_hdr->num_components; + if (frame_hdr->num_components > 4) + return FALSE; + for (i = 0; i < pic_param->num_components; i++) { + pic_param->components[i].component_id = frame_hdr->components[i].identifier; + pic_param->components[i].h_sampling_factor = + frame_hdr->components[i].horizontal_factor; + pic_param->components[i].v_sampling_factor = + frame_hdr->components[i].vertical_factor; + pic_param->components[i].quantiser_table_selector = + frame_hdr->components[i].quant_table_selector; + } + return TRUE; +} + +static GstVaapiDecoderStatus +fill_quantization_table (GstVaapiDecoderJpeg * decoder, + GstVaapiPicture * picture) +{ + GstVaapiDecoderJpegPrivate *const priv = &decoder->priv; + VAIQMatrixBufferJPEGBaseline *iq_matrix; + guint i, j, num_tables; + + if (!VALID_STATE (decoder, GOT_IQ_TABLE)) + gst_jpeg_get_default_quantization_tables (&priv->quant_tables); + + picture->iq_matrix = GST_VAAPI_IQ_MATRIX_NEW (JPEGBaseline, decoder); + if (!picture->iq_matrix) { + GST_ERROR ("failed to allocate quantiser table"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + iq_matrix = picture->iq_matrix->param; + + num_tables = MIN (G_N_ELEMENTS (iq_matrix->quantiser_table), + GST_JPEG_MAX_QUANT_ELEMENTS); + + for (i = 0; i < num_tables; i++) { + GstJpegQuantTable *const quant_table = &priv->quant_tables.quant_tables[i]; + + iq_matrix->load_quantiser_table[i] = quant_table->valid; + if (!iq_matrix->load_quantiser_table[i]) + continue; + + if (quant_table->quant_precision != 0) { + // Only Baseline profile is supported, thus 8-bit Qk values + GST_ERROR ("unsupported quantization table element precision"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT; + } + + for (j = 0; j < GST_JPEG_MAX_QUANT_ELEMENTS; j++) + iq_matrix->quantiser_table[i][j] = quant_table->quant_table[j]; + iq_matrix->load_quantiser_table[i] = 1; + quant_table->valid = FALSE; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static gboolean +huffman_tables_updated (const GstJpegHuffmanTables * huf_tables) +{ + guint i; + + for (i = 0; i < G_N_ELEMENTS (huf_tables->dc_tables); i++) + if (huf_tables->dc_tables[i].valid) + return TRUE; + for (i = 0; i < G_N_ELEMENTS (huf_tables->ac_tables); i++) + if (huf_tables->ac_tables[i].valid) + return TRUE; + return FALSE; +} + +static void +huffman_tables_reset (GstJpegHuffmanTables * huf_tables) +{ + guint i; + + for (i = 0; i < G_N_ELEMENTS (huf_tables->dc_tables); i++) + huf_tables->dc_tables[i].valid = FALSE; + for (i = 0; i < G_N_ELEMENTS (huf_tables->ac_tables); i++) + huf_tables->ac_tables[i].valid = FALSE; +} + +static void +fill_huffman_table (GstVaapiHuffmanTable * huf_table, + const GstJpegHuffmanTables * huf_tables) +{ + VAHuffmanTableBufferJPEGBaseline *const huffman_table = huf_table->param; + guint i, num_tables; + + num_tables = MIN (G_N_ELEMENTS (huffman_table->huffman_table), + GST_JPEG_MAX_SCAN_COMPONENTS); + + for (i = 0; i < num_tables; i++) { + huffman_table->load_huffman_table[i] = + huf_tables->dc_tables[i].valid && huf_tables->ac_tables[i].valid; + if (!huffman_table->load_huffman_table[i]) + continue; + + memcpy (huffman_table->huffman_table[i].num_dc_codes, + huf_tables->dc_tables[i].huf_bits, + sizeof (huffman_table->huffman_table[i].num_dc_codes)); + memcpy (huffman_table->huffman_table[i].dc_values, + huf_tables->dc_tables[i].huf_values, + sizeof (huffman_table->huffman_table[i].dc_values)); + memcpy (huffman_table->huffman_table[i].num_ac_codes, + huf_tables->ac_tables[i].huf_bits, + sizeof (huffman_table->huffman_table[i].num_ac_codes)); + memcpy (huffman_table->huffman_table[i].ac_values, + huf_tables->ac_tables[i].huf_values, + sizeof (huffman_table->huffman_table[i].ac_values)); + memset (huffman_table->huffman_table[i].pad, + 0, sizeof (huffman_table->huffman_table[i].pad)); + } +} + +static void +get_max_sampling_factors (const GstJpegFrameHdr * frame_hdr, + guint * h_max_ptr, guint * v_max_ptr) +{ + guint h_max = frame_hdr->components[0].horizontal_factor; + guint v_max = frame_hdr->components[0].vertical_factor; + guint i; + + for (i = 1; i < frame_hdr->num_components; i++) { + const GstJpegFrameComponent *const fcp = &frame_hdr->components[i]; + if (h_max < fcp->horizontal_factor) + h_max = fcp->horizontal_factor; + if (v_max < fcp->vertical_factor) + v_max = fcp->vertical_factor; + } + + if (h_max_ptr) + *h_max_ptr = h_max; + if (v_max_ptr) + *v_max_ptr = v_max; +} + +static const GstJpegFrameComponent * +get_component (const GstJpegFrameHdr * frame_hdr, guint selector) +{ + guint i; + + for (i = 0; i < frame_hdr->num_components; i++) { + const GstJpegFrameComponent *const fcp = &frame_hdr->components[i]; + if (fcp->identifier == selector) + return fcp; + } + return NULL; +} + +static GstVaapiDecoderStatus +decode_picture (GstVaapiDecoderJpeg * decoder, GstJpegSegment * seg) +{ + GstVaapiDecoderJpegPrivate *const priv = &decoder->priv; + GstJpegFrameHdr *const frame_hdr = &priv->frame_hdr; + + if (!VALID_STATE (decoder, GOT_SOI)) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + switch (seg->marker) { + case GST_JPEG_MARKER_SOF_MIN: + priv->profile = GST_VAAPI_PROFILE_JPEG_BASELINE; + break; + default: + GST_ERROR ("unsupported profile %d", seg->marker); + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + } + + memset (frame_hdr, 0, sizeof (*frame_hdr)); + if (!gst_jpeg_segment_parse_frame_header (seg, frame_hdr)) { + GST_ERROR ("failed to parse image"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + if (priv->height != frame_hdr->height || priv->width != frame_hdr->width) + priv->size_changed = TRUE; + + priv->height = frame_hdr->height; + priv->width = frame_hdr->width; + + priv->decoder_state |= GST_JPEG_VIDEO_STATE_GOT_SOF; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_huffman_table (GstVaapiDecoderJpeg * decoder, GstJpegSegment * seg) +{ + GstVaapiDecoderJpegPrivate *const priv = &decoder->priv; + + if (!VALID_STATE (decoder, GOT_SOI)) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + if (!gst_jpeg_segment_parse_huffman_table (seg, &priv->huf_tables)) { + GST_ERROR ("failed to parse Huffman table"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + priv->decoder_state |= GST_JPEG_VIDEO_STATE_GOT_HUF_TABLE; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_quant_table (GstVaapiDecoderJpeg * decoder, GstJpegSegment * seg) +{ + GstVaapiDecoderJpegPrivate *const priv = &decoder->priv; + + if (!VALID_STATE (decoder, GOT_SOI)) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + if (!gst_jpeg_segment_parse_quantization_table (seg, &priv->quant_tables)) { + GST_ERROR ("failed to parse quantization table"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + priv->decoder_state |= GST_JPEG_VIDEO_STATE_GOT_IQ_TABLE; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_restart_interval (GstVaapiDecoderJpeg * decoder, GstJpegSegment * seg) +{ + GstVaapiDecoderJpegPrivate *const priv = &decoder->priv; + + if (!VALID_STATE (decoder, GOT_SOI)) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + if (!gst_jpeg_segment_parse_restart_interval (seg, &priv->mcu_restart)) { + GST_ERROR ("failed to parse restart interval"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_scan (GstVaapiDecoderJpeg * decoder, GstJpegSegment * seg) +{ + GstVaapiDecoderJpegPrivate *const priv = &decoder->priv; + GstVaapiPicture *const picture = priv->current_picture; + GstVaapiSlice *slice; + VASliceParameterBufferJPEGBaseline *slice_param; + GstJpegScanHdr scan_hdr; + guint scan_hdr_size, scan_data_size; + guint i, h_max, v_max, mcu_width, mcu_height; + + if (!VALID_STATE (decoder, GOT_SOF)) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + scan_hdr_size = (seg->data[seg->offset] << 8) | seg->data[seg->offset + 1]; + scan_data_size = seg->size - scan_hdr_size; + + memset (&scan_hdr, 0, sizeof (scan_hdr)); + if (!gst_jpeg_segment_parse_scan_header (seg, &scan_hdr)) { + GST_ERROR ("failed to parse scan header"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + slice = GST_VAAPI_SLICE_NEW (JPEGBaseline, decoder, + seg->data + seg->offset + scan_hdr_size, scan_data_size); + if (!slice) { + GST_ERROR ("failed to allocate slice"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + gst_vaapi_picture_add_slice (picture, slice); + + if (!VALID_STATE (decoder, GOT_HUF_TABLE)) + gst_jpeg_get_default_huffman_tables (&priv->huf_tables); + + // Update VA Huffman table if it changed for this scan + if (huffman_tables_updated (&priv->huf_tables)) { + slice->huf_table = GST_VAAPI_HUFFMAN_TABLE_NEW (JPEGBaseline, decoder); + if (!slice->huf_table) { + GST_ERROR ("failed to allocate Huffman tables"); + huffman_tables_reset (&priv->huf_tables); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + fill_huffman_table (slice->huf_table, &priv->huf_tables); + huffman_tables_reset (&priv->huf_tables); + } + + slice_param = slice->param; + slice_param->num_components = scan_hdr.num_components; + for (i = 0; i < scan_hdr.num_components; i++) { + slice_param->components[i].component_selector = + scan_hdr.components[i].component_selector; + slice_param->components[i].dc_table_selector = + scan_hdr.components[i].dc_selector; + slice_param->components[i].ac_table_selector = + scan_hdr.components[i].ac_selector; + } + slice_param->restart_interval = priv->mcu_restart; + slice_param->slice_horizontal_position = 0; + slice_param->slice_vertical_position = 0; + + get_max_sampling_factors (&priv->frame_hdr, &h_max, &v_max); + mcu_width = 8 * h_max; + mcu_height = 8 * v_max; + + if (scan_hdr.num_components == 1) { // Non-interleaved + const guint Csj = slice_param->components[0].component_selector; + const GstJpegFrameComponent *const fcp = + get_component (&priv->frame_hdr, Csj); + + if (!fcp || fcp->horizontal_factor == 0 || fcp->vertical_factor == 0) { + GST_ERROR ("failed to validate image component %u", Csj); + return GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER; + } + mcu_width /= fcp->horizontal_factor; + mcu_height /= fcp->vertical_factor; + } + slice_param->num_mcus = + ((priv->frame_hdr.width + mcu_width - 1) / mcu_width) * + ((priv->frame_hdr.height + mcu_height - 1) / mcu_height); + + priv->decoder_state |= GST_JPEG_VIDEO_STATE_GOT_SOS; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_segment (GstVaapiDecoderJpeg * decoder, GstJpegSegment * seg) +{ + GstVaapiDecoderJpegPrivate *const priv = &decoder->priv; + GstVaapiDecoderStatus status; + + // Decode segment + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + switch (seg->marker) { + case GST_JPEG_MARKER_SOI: + priv->mcu_restart = 0; + priv->decoder_state |= GST_JPEG_VIDEO_STATE_GOT_SOI; + break; + case GST_JPEG_MARKER_EOI: + priv->decoder_state = 0; + break; + case GST_JPEG_MARKER_DAC: + GST_ERROR ("unsupported arithmetic coding mode"); + status = GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + break; + case GST_JPEG_MARKER_DHT: + status = decode_huffman_table (decoder, seg); + break; + case GST_JPEG_MARKER_DQT: + status = decode_quant_table (decoder, seg); + break; + case GST_JPEG_MARKER_DRI: + status = decode_restart_interval (decoder, seg); + break; + case GST_JPEG_MARKER_SOS: + status = decode_scan (decoder, seg); + break; + default: + // SOFn segments + if (seg->marker >= GST_JPEG_MARKER_SOF_MIN && + seg->marker <= GST_JPEG_MARKER_SOF_MAX) + status = decode_picture (decoder, seg); + break; + } + return status; +} + +static GstVaapiDecoderStatus +ensure_decoder (GstVaapiDecoderJpeg * decoder) +{ + GstVaapiDecoderJpegPrivate *const priv = &decoder->priv; + + if (!priv->is_opened) { + priv->is_opened = gst_vaapi_decoder_jpeg_open (decoder); + if (!priv->is_opened) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static gboolean +is_scan_complete (GstJpegMarker marker) +{ + // Scan is assumed to be complete when the new segment is not RSTi + return marker < GST_JPEG_MARKER_RST_MIN || marker > GST_JPEG_MARKER_RST_MAX; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_jpeg_parse (GstVaapiDecoder * base_decoder, + GstAdapter * adapter, gboolean at_eos, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderJpeg *const decoder = + GST_VAAPI_DECODER_JPEG_CAST (base_decoder); + GstVaapiDecoderJpegPrivate *const priv = &decoder->priv; + GstVaapiParserState *const ps = GST_VAAPI_PARSER_STATE (base_decoder); + GstVaapiDecoderStatus status; + GstJpegMarker marker; + GstJpegSegment seg; + const guchar *buf; + guint buf_size, flags; + gint ofs1, ofs2; + + status = ensure_decoder (decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + /* Expect at least 2 bytes for the marker */ + buf_size = gst_adapter_available (adapter); + if (buf_size < 2) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + + buf = gst_adapter_map (adapter, buf_size); + if (!buf) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + + ofs1 = ps->input_offset1 - 2; + if (ofs1 < 0) + ofs1 = 0; + + for (;;) { + // Skip any garbage until we reach SOI, if needed + if (!gst_jpeg_parse (&seg, buf, buf_size, ofs1)) { + gst_adapter_unmap (adapter); + ps->input_offset1 = buf_size; + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + } + ofs1 = seg.offset; + + marker = seg.marker; + if (!VALID_STATE (parser, GOT_SOI) && marker != GST_JPEG_MARKER_SOI) + continue; + if (marker == GST_JPEG_MARKER_SOS) { + ofs2 = ps->input_offset2 - 2; + if (ofs2 < ofs1 + seg.size) + ofs2 = ofs1 + seg.size; + + // Parse the whole scan + ECSs, including RSTi + for (;;) { + if (!gst_jpeg_parse (&seg, buf, buf_size, ofs2)) { + gst_adapter_unmap (adapter); + ps->input_offset1 = ofs1; + ps->input_offset2 = buf_size; + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + } + + if (is_scan_complete (seg.marker)) + break; + ofs2 = seg.offset + seg.size; + } + ofs2 = seg.offset - 2; + } else { + // Check that the whole segment is actually available (in buffer) + ofs2 = ofs1 + seg.size; + if (ofs2 > buf_size) { + gst_adapter_unmap (adapter); + ps->input_offset1 = ofs1; + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + } + } + break; + } + gst_adapter_unmap (adapter); + + unit->size = ofs2 - ofs1; + unit_set_marker_code (unit, marker); + gst_adapter_flush (adapter, ofs1); + ps->input_offset1 = 2; + ps->input_offset2 = 2; + + flags = 0; + switch (marker) { + case GST_JPEG_MARKER_SOI: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START; + priv->parser_state |= GST_JPEG_VIDEO_STATE_GOT_SOI; + break; + case GST_JPEG_MARKER_EOI: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END; + priv->parser_state = 0; + break; + case GST_JPEG_MARKER_SOS: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE; + priv->parser_state |= GST_JPEG_VIDEO_STATE_GOT_SOS; + break; + case GST_JPEG_MARKER_DAC: + case GST_JPEG_MARKER_DHT: + case GST_JPEG_MARKER_DQT: + if (priv->parser_state & GST_JPEG_VIDEO_STATE_GOT_SOF) + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE; + break; + case GST_JPEG_MARKER_DRI: + if (priv->parser_state & GST_JPEG_VIDEO_STATE_GOT_SOS) + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE; + break; + case GST_JPEG_MARKER_DNL: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE; + break; + case GST_JPEG_MARKER_COM: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP; + break; + default: + /* SOFn segments */ + if (marker >= GST_JPEG_MARKER_SOF_MIN && + marker <= GST_JPEG_MARKER_SOF_MAX) + priv->parser_state |= GST_JPEG_VIDEO_STATE_GOT_SOF; + + /* Application segments */ + else if (marker >= GST_JPEG_MARKER_APP_MIN && + marker <= GST_JPEG_MARKER_APP_MAX) + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP; + + /* Reserved */ + else if (marker >= 0x02 && marker <= 0xbf) + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP; + break; + } + GST_VAAPI_DECODER_UNIT_FLAG_SET (unit, flags); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_jpeg_decode (GstVaapiDecoder * base_decoder, + GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderJpeg *const decoder = + GST_VAAPI_DECODER_JPEG_CAST (base_decoder); + GstVaapiDecoderStatus status; + GstJpegSegment seg; + GstBuffer *const buffer = + GST_VAAPI_DECODER_CODEC_FRAME (decoder)->input_buffer; + GstMapInfo map_info; + + status = ensure_decoder (decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) { + GST_ERROR ("failed to map buffer"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + seg.marker = unit_get_marker_code (unit); + seg.data = map_info.data; + seg.offset = unit->offset; + seg.size = unit->size; + + status = decode_segment (decoder, &seg); + gst_buffer_unmap (buffer, &map_info); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_jpeg_start_frame (GstVaapiDecoder * base_decoder, + GstVaapiDecoderUnit * base_unit) +{ + GstVaapiDecoderJpeg *const decoder = + GST_VAAPI_DECODER_JPEG_CAST (base_decoder); + GstVaapiDecoderJpegPrivate *const priv = &decoder->priv; + GstVaapiPicture *picture; + GstVaapiDecoderStatus status; + + if (!VALID_STATE (decoder, GOT_SOF)) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + status = ensure_context (decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) { + GST_ERROR ("failed to reset context"); + return status; + } + + picture = GST_VAAPI_PICTURE_NEW (JPEGBaseline, decoder); + if (!picture) { + GST_ERROR ("failed to allocate picture"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + gst_vaapi_picture_replace (&priv->current_picture, picture); + gst_vaapi_picture_unref (picture); + + if (!fill_picture (decoder, picture, &priv->frame_hdr)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + + status = fill_quantization_table (decoder, picture); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + /* Update presentation time */ + picture->pts = GST_VAAPI_DECODER_CODEC_FRAME (decoder)->pts; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_jpeg_end_frame (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderJpeg *const decoder = + GST_VAAPI_DECODER_JPEG_CAST (base_decoder); + + return decode_current_picture (decoder); +} + +static void +gst_vaapi_decoder_jpeg_finalize (GObject * object) +{ + GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (object); + + gst_vaapi_decoder_jpeg_destroy (base_decoder); + G_OBJECT_CLASS (gst_vaapi_decoder_jpeg_parent_class)->finalize (object); +} + +static void +gst_vaapi_decoder_jpeg_class_init (GstVaapiDecoderJpegClass * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstVaapiDecoderClass *const decoder_class = GST_VAAPI_DECODER_CLASS (klass); + + object_class->finalize = gst_vaapi_decoder_jpeg_finalize; + + decoder_class->reset = gst_vaapi_decoder_jpeg_reset; + decoder_class->parse = gst_vaapi_decoder_jpeg_parse; + decoder_class->decode = gst_vaapi_decoder_jpeg_decode; + decoder_class->start_frame = gst_vaapi_decoder_jpeg_start_frame; + decoder_class->end_frame = gst_vaapi_decoder_jpeg_end_frame; +} + +static void +gst_vaapi_decoder_jpeg_init (GstVaapiDecoderJpeg * decoder) +{ + GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (decoder); + + gst_vaapi_decoder_jpeg_create (base_decoder); +} + +/** + * gst_vaapi_decoder_jpeg_new: + * @display: a #GstVaapiDisplay + * @caps: a #GstCaps holding codec information + * + * Creates a new #GstVaapiDecoder for JPEG decoding. The @caps can + * hold extra information like codec-data and pictured coded size. + * + * Return value: the newly allocated #GstVaapiDecoder object + */ +GstVaapiDecoder * +gst_vaapi_decoder_jpeg_new (GstVaapiDisplay * display, GstCaps * caps) +{ + return g_object_new (GST_TYPE_VAAPI_DECODER_JPEG, "display", display, + "caps", caps, NULL); +} diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.h b/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.h new file mode 100644 index 0000000000..5c1b4afc12 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.h @@ -0,0 +1,51 @@ +/* + * gstvaapidecoder_jpeg.h - JPEG decoder + * + * Copyright (C) 2011-2013 Intel Corporation + * Author: Wind Yuan + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODER_JPEG_H +#define GST_VAAPI_DECODER_JPEG_H + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_DECODER_JPEG \ + (gst_vaapi_decoder_jpeg_get_type ()) +#define GST_VAAPI_DECODER_JPEG(decoder) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DECODER_JPEG, GstVaapiDecoderJpeg)) +#define GST_VAAPI_IS_DECODER_JPEG(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_DECODER_JPEG)) + +typedef struct _GstVaapiDecoderJpeg GstVaapiDecoderJpeg; + +GType +gst_vaapi_decoder_jpeg_get_type (void) G_GNUC_CONST; + +GstVaapiDecoder * +gst_vaapi_decoder_jpeg_new (GstVaapiDisplay *display, GstCaps *caps); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDecoderJpeg, gst_object_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_DECODER_JPEG_H */ + diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c b/gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c new file mode 100644 index 0000000000..3855aa06f9 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c @@ -0,0 +1,1624 @@ +/* + * gstvaapidecoder_mpeg2.c - MPEG-2 decoder + * + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapidecoder_mpeg2 + * @short_description: MPEG-2 decoder + */ + +#include "sysdeps.h" +#include +#include +#include "gstvaapidecoder_mpeg2.h" +#include "gstvaapidecoder_objects.h" +#include "gstvaapidecoder_dpb.h" +#include "gstvaapidecoder_priv.h" +#include "gstvaapidisplay_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +/* ------------------------------------------------------------------------- */ +/* --- PTS Generator --- */ +/* ------------------------------------------------------------------------- */ + +typedef struct _PTSGenerator PTSGenerator; +struct _PTSGenerator +{ + GstClockTime gop_pts; // Current GOP PTS + GstClockTime max_pts; // Max picture PTS + guint gop_tsn; // Absolute GOP TSN + guint max_tsn; // Max picture TSN, relative to last GOP TSN + guint ovl_tsn; // How many times TSN overflowed since GOP + guint lst_tsn; // Last picture TSN + guint fps_n; + guint fps_d; +}; + +static void +pts_init (PTSGenerator * tsg) +{ + tsg->gop_pts = GST_CLOCK_TIME_NONE; + tsg->max_pts = GST_CLOCK_TIME_NONE; + tsg->gop_tsn = 0; + tsg->max_tsn = 0; + tsg->ovl_tsn = 0; + tsg->lst_tsn = 0; + tsg->fps_n = 0; + tsg->fps_d = 0; +} + +static inline GstClockTime +pts_get_duration (PTSGenerator * tsg, guint num_frames) +{ + return gst_util_uint64_scale (num_frames, + GST_SECOND * tsg->fps_d, tsg->fps_n); +} + +static inline guint +pts_get_poc (PTSGenerator * tsg) +{ + return tsg->gop_tsn + tsg->ovl_tsn * 1024 + tsg->lst_tsn; +} + +static void +pts_set_framerate (PTSGenerator * tsg, guint fps_n, guint fps_d) +{ + tsg->fps_n = fps_n; + tsg->fps_d = fps_d; +} + +static void +pts_sync (PTSGenerator * tsg, GstClockTime gop_pts) +{ + guint gop_tsn; + + if (!GST_CLOCK_TIME_IS_VALID (gop_pts) || + (GST_CLOCK_TIME_IS_VALID (tsg->max_pts) && tsg->max_pts >= gop_pts)) { + /* Invalid GOP PTS, interpolate from the last known picture PTS */ + if (GST_CLOCK_TIME_IS_VALID (tsg->max_pts)) { + gop_pts = tsg->max_pts + pts_get_duration (tsg, 1); + gop_tsn = tsg->gop_tsn + tsg->ovl_tsn * 1024 + tsg->max_tsn + 1; + } else { + gop_pts = 0; + gop_tsn = 0; + } + } else { + /* Interpolate GOP TSN from this valid PTS */ + if (GST_CLOCK_TIME_IS_VALID (tsg->gop_pts)) + gop_tsn = + tsg->gop_tsn + gst_util_uint64_scale (gop_pts - tsg->gop_pts + + pts_get_duration (tsg, 1) - 1, tsg->fps_n, GST_SECOND * tsg->fps_d); + else + gop_tsn = 0; + } + + tsg->gop_pts = gop_pts; + tsg->gop_tsn = gop_tsn; + tsg->max_tsn = 0; + tsg->ovl_tsn = 0; + tsg->lst_tsn = 0; +} + +static GstClockTime +pts_eval (PTSGenerator * tsg, GstClockTime pic_pts, guint pic_tsn) +{ + GstClockTime pts; + + if (!GST_CLOCK_TIME_IS_VALID (tsg->gop_pts)) + tsg->gop_pts = pts_get_duration (tsg, pic_tsn); + + pts = pic_pts; + if (!GST_CLOCK_TIME_IS_VALID (pts)) + pts = tsg->gop_pts + pts_get_duration (tsg, tsg->ovl_tsn * 1024 + pic_tsn); + else if (pts == tsg->gop_pts) { + /* The picture following the GOP header shall be an I-frame. + So we can compensate for the GOP start time from here */ + tsg->gop_pts -= pts_get_duration (tsg, pic_tsn); + } + + if (!GST_CLOCK_TIME_IS_VALID (tsg->max_pts) || tsg->max_pts < pts) + tsg->max_pts = pts; + + if (tsg->max_tsn < pic_tsn) + tsg->max_tsn = pic_tsn; + else if (tsg->max_tsn == 1023 && pic_tsn < tsg->lst_tsn) { /* TSN wrapped */ + tsg->max_tsn = pic_tsn; + tsg->ovl_tsn++; + } + tsg->lst_tsn = pic_tsn; + + return pts; +} + +/* ------------------------------------------------------------------------- */ +/* --- MPEG-2 Parser Info --- */ +/* ------------------------------------------------------------------------- */ + +typedef struct _GstVaapiParserInfoMpeg2 GstVaapiParserInfoMpeg2; +struct _GstVaapiParserInfoMpeg2 +{ + GstVaapiMiniObject parent_instance; + GstMpegVideoPacket packet; + guint8 extension_type; /* for Extension packets */ + union + { + GstMpegVideoSequenceHdr seq_hdr; + GstMpegVideoSequenceExt seq_ext; + GstMpegVideoSequenceDisplayExt seq_display_ext; + GstMpegVideoSequenceScalableExt seq_scalable_ext; + GstMpegVideoGop gop; + GstMpegVideoQuantMatrixExt quant_matrix; + GstMpegVideoPictureHdr pic_hdr; + GstMpegVideoPictureExt pic_ext; + GstMpegVideoSliceHdr slice_hdr; + } data; +}; + +static inline const GstVaapiMiniObjectClass * +gst_vaapi_parser_info_mpeg2_class (void) +{ + static const GstVaapiMiniObjectClass GstVaapiParserInfoMpeg2Class = { + sizeof (GstVaapiParserInfoMpeg2), + NULL + }; + return &GstVaapiParserInfoMpeg2Class; +} + +static inline GstVaapiParserInfoMpeg2 * +gst_vaapi_parser_info_mpeg2_new (void) +{ + return (GstVaapiParserInfoMpeg2 *) + gst_vaapi_mini_object_new (gst_vaapi_parser_info_mpeg2_class ()); +} + +static inline GstVaapiParserInfoMpeg2 * +gst_vaapi_parser_info_mpeg2_ensure (GstVaapiParserInfoMpeg2 ** pi_ptr) +{ + GstVaapiParserInfoMpeg2 *pi = *pi_ptr; + + if (G_LIKELY (pi != NULL)) + return pi; + + *pi_ptr = pi = gst_vaapi_parser_info_mpeg2_new (); + return pi; +} + +#define gst_vaapi_parser_info_mpeg2_ref(pi) \ + gst_vaapi_mini_object_ref(GST_VAAPI_MINI_OBJECT(pi)) + +#define gst_vaapi_parser_info_mpeg2_unref(pi) \ + gst_vaapi_mini_object_unref(GST_VAAPI_MINI_OBJECT(pi)) + +#define gst_vaapi_parser_info_mpeg2_replace(old_pi_ptr, new_pi) \ + gst_vaapi_mini_object_replace((GstVaapiMiniObject **)(old_pi_ptr), \ + (GstVaapiMiniObject *)(new_pi)) + +/* ------------------------------------------------------------------------- */ +/* --- MPEG-2 Decoder --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_DECODER_MPEG2_CAST(decoder) \ + ((GstVaapiDecoderMpeg2 *)(decoder)) + +typedef struct _GstVaapiDecoderMpeg2Private GstVaapiDecoderMpeg2Private; +typedef struct _GstVaapiDecoderMpeg2Class GstVaapiDecoderMpeg2Class; + +typedef enum +{ + GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR = 1 << 0, + GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT = 1 << 1, + GST_MPEG_VIDEO_STATE_GOT_PIC_HDR = 1 << 2, + GST_MPEG_VIDEO_STATE_GOT_PIC_EXT = 1 << 3, + GST_MPEG_VIDEO_STATE_GOT_SLICE = 1 << 4, + + GST_MPEG_VIDEO_STATE_VALID_SEQ_HEADERS = (GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR | + GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT), + GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS = (GST_MPEG_VIDEO_STATE_GOT_PIC_HDR | + GST_MPEG_VIDEO_STATE_GOT_PIC_EXT), + GST_MPEG_VIDEO_STATE_VALID_PICTURE = (GST_MPEG_VIDEO_STATE_VALID_SEQ_HEADERS | + GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS | GST_MPEG_VIDEO_STATE_GOT_SLICE) +} GstMpegVideoState; + +struct _GstVaapiDecoderMpeg2Private +{ + GstVaapiProfile profile; + GstVaapiProfile hw_profile; + guint width; + guint height; + guint fps_n; + guint fps_d; + guint state; + GstVaapiRectangle crop_rect; + GstVaapiParserInfoMpeg2 *seq_hdr; + GstVaapiParserInfoMpeg2 *seq_ext; + GstVaapiParserInfoMpeg2 *seq_display_ext; + GstVaapiParserInfoMpeg2 *seq_scalable_ext; + GstVaapiParserInfoMpeg2 *gop; + GstVaapiParserInfoMpeg2 *pic_hdr; + GstVaapiParserInfoMpeg2 *pic_ext; + GstVaapiParserInfoMpeg2 *pic_display_ext; + GstVaapiParserInfoMpeg2 *quant_matrix; + GstVaapiParserInfoMpeg2 *slice_hdr; + GstVaapiPicture *current_picture; + GstVaapiDpb *dpb; + PTSGenerator tsg; + guint is_opened:1; + guint size_changed:1; + guint profile_changed:1; + guint quant_matrix_changed:1; + guint progressive_sequence:1; + guint closed_gop:1; + guint broken_link:1; +}; + +/** + * GstVaapiDecoderMpeg2: + * + * A decoder based on Mpeg2. + */ +struct _GstVaapiDecoderMpeg2 +{ + /*< private > */ + GstVaapiDecoder parent_instance; + GstVaapiDecoderMpeg2Private priv; +}; + +/** + * GstVaapiDecoderMpeg2Class: + * + * A decoder class based on Mpeg2. + */ +struct _GstVaapiDecoderMpeg2Class +{ + /*< private > */ + GstVaapiDecoderClass parent_class; +}; + +G_DEFINE_TYPE (GstVaapiDecoderMpeg2, gst_vaapi_decoder_mpeg2, + GST_TYPE_VAAPI_DECODER); + +static void +gst_vaapi_decoder_mpeg2_close (GstVaapiDecoderMpeg2 * decoder) +{ + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + + gst_vaapi_picture_replace (&priv->current_picture, NULL); + + gst_vaapi_parser_info_mpeg2_replace (&priv->seq_hdr, NULL); + gst_vaapi_parser_info_mpeg2_replace (&priv->seq_ext, NULL); + gst_vaapi_parser_info_mpeg2_replace (&priv->seq_display_ext, NULL); + gst_vaapi_parser_info_mpeg2_replace (&priv->seq_scalable_ext, NULL); + gst_vaapi_parser_info_mpeg2_replace (&priv->gop, NULL); + gst_vaapi_parser_info_mpeg2_replace (&priv->pic_hdr, NULL); + gst_vaapi_parser_info_mpeg2_replace (&priv->pic_ext, NULL); + gst_vaapi_parser_info_mpeg2_replace (&priv->pic_display_ext, NULL); + gst_vaapi_parser_info_mpeg2_replace (&priv->quant_matrix, NULL); + gst_vaapi_parser_info_mpeg2_replace (&priv->slice_hdr, NULL); + + priv->state = 0; + + gst_vaapi_dpb_replace (&priv->dpb, NULL); + + priv->is_opened = FALSE; +} + +static gboolean +gst_vaapi_decoder_mpeg2_open (GstVaapiDecoderMpeg2 * decoder) +{ + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + + gst_vaapi_decoder_mpeg2_close (decoder); + + priv->dpb = gst_vaapi_dpb_new (2); + if (!priv->dpb) + return FALSE; + + pts_init (&priv->tsg); + return TRUE; +} + +static void +gst_vaapi_decoder_mpeg2_destroy (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderMpeg2 *const decoder = + GST_VAAPI_DECODER_MPEG2_CAST (base_decoder); + + gst_vaapi_decoder_mpeg2_close (decoder); +} + +static gboolean +gst_vaapi_decoder_mpeg2_create (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderMpeg2 *const decoder = + GST_VAAPI_DECODER_MPEG2_CAST (base_decoder); + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + + priv->hw_profile = GST_VAAPI_PROFILE_UNKNOWN; + priv->profile = GST_VAAPI_PROFILE_MPEG2_SIMPLE; + priv->profile_changed = TRUE; /* Allow fallbacks to work */ + return TRUE; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_mpeg2_reset (GstVaapiDecoder * base_decoder) +{ + gst_vaapi_decoder_mpeg2_destroy (base_decoder); + gst_vaapi_decoder_mpeg2_create (base_decoder); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static inline void +copy_quant_matrix (guint8 dst[64], const guint8 src[64]) +{ + memcpy (dst, src, 64); +} + +static const char * +get_profile_str (GstVaapiProfile profile) +{ + const char *str; + + switch (profile) { + case GST_VAAPI_PROFILE_MPEG2_SIMPLE: + str = "simple"; + break; + case GST_VAAPI_PROFILE_MPEG2_MAIN: + str = "main"; + break; + case GST_VAAPI_PROFILE_MPEG2_HIGH: + str = "high"; + break; + default: + str = ""; + break; + } + return str; +} + +static GstVaapiProfile +get_profile (GstVaapiDecoderMpeg2 * decoder, GstVaapiEntrypoint entrypoint) +{ + GstVaapiDisplay *const va_display = GST_VAAPI_DECODER_DISPLAY (decoder); + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + GstVaapiProfile profile = priv->profile; + + do { + /* Return immediately if the exact same profile was found */ + if (gst_vaapi_display_has_decoder (va_display, profile, entrypoint)) + break; + + /* Otherwise, try to map to a higher profile */ + switch (profile) { + case GST_VAAPI_PROFILE_MPEG2_SIMPLE: + profile = GST_VAAPI_PROFILE_MPEG2_MAIN; + break; + case GST_VAAPI_PROFILE_MPEG2_MAIN: + profile = GST_VAAPI_PROFILE_MPEG2_HIGH; + break; + case GST_VAAPI_PROFILE_MPEG2_HIGH: + // Try to map to main profile if no high profile specific bits used + if (priv->profile == profile && + !priv->seq_scalable_ext && + (priv->seq_ext && priv->seq_ext->data.seq_ext.chroma_format == 1)) { + profile = GST_VAAPI_PROFILE_MPEG2_MAIN; + break; + } + // fall-through + default: + profile = GST_VAAPI_PROFILE_UNKNOWN; + break; + } + } while (profile != GST_VAAPI_PROFILE_UNKNOWN); + + if (profile != priv->profile) + GST_INFO ("forced %s profile to %s profile", + get_profile_str (priv->profile), get_profile_str (profile)); + return profile; +} + +static GstVaapiDecoderStatus +ensure_context (GstVaapiDecoderMpeg2 * decoder) +{ + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD; + gboolean reset_context = FALSE; + + if (priv->profile_changed) { + GST_DEBUG ("profile changed"); + priv->profile_changed = FALSE; + reset_context = TRUE; + + priv->hw_profile = get_profile (decoder, entrypoint); + if (priv->hw_profile == GST_VAAPI_PROFILE_UNKNOWN) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + } + + if (priv->size_changed) { + GST_DEBUG ("size changed"); + priv->size_changed = FALSE; + reset_context = TRUE; + } + + if (reset_context) { + GstVaapiContextInfo info; + + info.profile = priv->hw_profile; + info.entrypoint = entrypoint; + info.chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420; + info.width = priv->width; + info.height = priv->height; + info.ref_frames = 2; + reset_context = + gst_vaapi_decoder_ensure_context (GST_VAAPI_DECODER_CAST (decoder), + &info); + if (!reset_context) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +ensure_quant_matrix (GstVaapiDecoderMpeg2 * decoder, GstVaapiPicture * picture) +{ + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + GstMpegVideoSequenceHdr *const seq_hdr = &priv->seq_hdr->data.seq_hdr; + VAIQMatrixBufferMPEG2 *iq_matrix; + guint8 *intra_quant_matrix = NULL; + guint8 *non_intra_quant_matrix = NULL; + guint8 *chroma_intra_quant_matrix = NULL; + guint8 *chroma_non_intra_quant_matrix = NULL; + + if (!priv->quant_matrix_changed) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + priv->quant_matrix_changed = FALSE; + + picture->iq_matrix = GST_VAAPI_IQ_MATRIX_NEW (MPEG2, decoder); + if (!picture->iq_matrix) { + GST_ERROR ("failed to allocate IQ matrix"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + iq_matrix = picture->iq_matrix->param; + + intra_quant_matrix = seq_hdr->intra_quantizer_matrix; + non_intra_quant_matrix = seq_hdr->non_intra_quantizer_matrix; + + if (priv->quant_matrix) { + GstMpegVideoQuantMatrixExt *const quant_matrix = + &priv->quant_matrix->data.quant_matrix; + if (quant_matrix->load_intra_quantiser_matrix) + intra_quant_matrix = quant_matrix->intra_quantiser_matrix; + if (quant_matrix->load_non_intra_quantiser_matrix) + non_intra_quant_matrix = quant_matrix->non_intra_quantiser_matrix; + if (quant_matrix->load_chroma_intra_quantiser_matrix) + chroma_intra_quant_matrix = quant_matrix->chroma_intra_quantiser_matrix; + if (quant_matrix->load_chroma_non_intra_quantiser_matrix) + chroma_non_intra_quant_matrix = + quant_matrix->chroma_non_intra_quantiser_matrix; + } + + iq_matrix->load_intra_quantiser_matrix = intra_quant_matrix != NULL; + if (intra_quant_matrix) + copy_quant_matrix (iq_matrix->intra_quantiser_matrix, intra_quant_matrix); + + iq_matrix->load_non_intra_quantiser_matrix = non_intra_quant_matrix != NULL; + if (non_intra_quant_matrix) + copy_quant_matrix (iq_matrix->non_intra_quantiser_matrix, + non_intra_quant_matrix); + + iq_matrix->load_chroma_intra_quantiser_matrix = + chroma_intra_quant_matrix != NULL; + if (chroma_intra_quant_matrix) + copy_quant_matrix (iq_matrix->chroma_intra_quantiser_matrix, + chroma_intra_quant_matrix); + + iq_matrix->load_chroma_non_intra_quantiser_matrix = + chroma_non_intra_quant_matrix != NULL; + if (chroma_non_intra_quant_matrix) + copy_quant_matrix (iq_matrix->chroma_non_intra_quantiser_matrix, + chroma_non_intra_quant_matrix); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static inline gboolean +is_valid_state (GstVaapiDecoderMpeg2 * decoder, guint state) +{ + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + + return (priv->state & state) == state; +} + +static GstVaapiDecoderStatus +decode_current_picture (GstVaapiDecoderMpeg2 * decoder) +{ + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + GstVaapiPicture *const picture = priv->current_picture; + + if (!is_valid_state (decoder, GST_MPEG_VIDEO_STATE_VALID_PICTURE)) + goto drop_frame; + priv->state &= GST_MPEG_VIDEO_STATE_VALID_SEQ_HEADERS; + + if (!picture) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + if (!gst_vaapi_picture_decode (picture)) + goto error; + if (GST_VAAPI_PICTURE_IS_COMPLETE (picture)) { + if (!gst_vaapi_dpb_add (priv->dpb, picture)) + goto error; + gst_vaapi_picture_replace (&priv->current_picture, NULL); + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + /* ERRORS */ +error: + { + /* XXX: fix for cases where first field failed to be decoded */ + gst_vaapi_picture_replace (&priv->current_picture, NULL); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + +drop_frame: + { + priv->state &= GST_MPEG_VIDEO_STATE_VALID_SEQ_HEADERS; + return (GstVaapiDecoderStatus) GST_VAAPI_DECODER_STATUS_DROP_FRAME; + } +} + +static GstVaapiDecoderStatus +parse_sequence (GstVaapiDecoderMpeg2 * decoder, + GstVaapiDecoderUnit * unit, const GstMpegVideoPacket * packet) +{ + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + GstMpegVideoSequenceHdr *seq_hdr; + + priv->state = 0; + + if (!gst_vaapi_parser_info_mpeg2_ensure (&priv->seq_hdr)) { + GST_ERROR ("failed to allocate parser info for sequence header"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + seq_hdr = &priv->seq_hdr->data.seq_hdr; + + if (!gst_mpeg_video_packet_parse_sequence_header (packet, seq_hdr)) { + GST_ERROR ("failed to parse sequence header"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + gst_vaapi_decoder_unit_set_parsed_info (unit, seq_hdr, NULL); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_sequence (GstVaapiDecoderMpeg2 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER_CAST (decoder); + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + GstMpegVideoSequenceHdr *const seq_hdr = unit->parsed_info; + + gst_vaapi_parser_info_mpeg2_replace (&priv->seq_ext, NULL); + gst_vaapi_parser_info_mpeg2_replace (&priv->seq_display_ext, NULL); + gst_vaapi_parser_info_mpeg2_replace (&priv->seq_scalable_ext, NULL); + gst_vaapi_parser_info_mpeg2_replace (&priv->quant_matrix, NULL); + gst_vaapi_parser_info_mpeg2_replace (&priv->pic_display_ext, NULL); + + priv->fps_n = seq_hdr->fps_n; + priv->fps_d = seq_hdr->fps_d; + pts_set_framerate (&priv->tsg, priv->fps_n, priv->fps_d); + gst_vaapi_decoder_set_framerate (base_decoder, priv->fps_n, priv->fps_d); + + priv->width = seq_hdr->width; + priv->height = seq_hdr->height; + priv->size_changed = TRUE; + priv->quant_matrix_changed = TRUE; + priv->progressive_sequence = TRUE; + + priv->state |= GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +parse_sequence_ext (GstVaapiDecoderMpeg2 * decoder, + GstVaapiDecoderUnit * unit, const GstMpegVideoPacket * packet) +{ + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + GstMpegVideoSequenceExt *seq_ext; + + priv->state &= GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR; + + if (!gst_vaapi_parser_info_mpeg2_ensure (&priv->seq_ext)) { + GST_ERROR ("failed to allocate parser info for sequence extension"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + seq_ext = &priv->seq_ext->data.seq_ext; + + if (!gst_mpeg_video_packet_parse_sequence_extension (packet, seq_ext)) { + GST_ERROR ("failed to parse sequence-extension"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + gst_vaapi_decoder_unit_set_parsed_info (unit, seq_ext, NULL); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_sequence_ext (GstVaapiDecoderMpeg2 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER_CAST (decoder); + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + GstMpegVideoSequenceExt *const seq_ext = unit->parsed_info; + GstVaapiProfile profile; + guint width, height; + + if (!is_valid_state (decoder, GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR)) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + priv->progressive_sequence = seq_ext->progressive; + gst_vaapi_decoder_set_interlaced (base_decoder, !priv->progressive_sequence); + + width = (priv->width & 0x0fff) | ((guint32) seq_ext->horiz_size_ext << 12); + height = (priv->height & 0x0fff) | ((guint32) seq_ext->vert_size_ext << 12); + GST_DEBUG ("video resolution %ux%u", width, height); + + if (seq_ext->fps_n_ext && seq_ext->fps_d_ext) { + priv->fps_n *= seq_ext->fps_n_ext + 1; + priv->fps_d *= seq_ext->fps_d_ext + 1; + pts_set_framerate (&priv->tsg, priv->fps_n, priv->fps_d); + gst_vaapi_decoder_set_framerate (base_decoder, priv->fps_n, priv->fps_d); + } + + if (priv->width != width) { + priv->width = width; + priv->size_changed = TRUE; + } + + if (priv->height != height) { + priv->height = height; + priv->size_changed = TRUE; + } + + switch (seq_ext->profile) { + case GST_MPEG_VIDEO_PROFILE_SIMPLE: + profile = GST_VAAPI_PROFILE_MPEG2_SIMPLE; + break; + case GST_MPEG_VIDEO_PROFILE_MAIN: + profile = GST_VAAPI_PROFILE_MPEG2_MAIN; + break; + case GST_MPEG_VIDEO_PROFILE_HIGH: + profile = GST_VAAPI_PROFILE_MPEG2_HIGH; + break; + default: + GST_ERROR ("unsupported profile %d", seq_ext->profile); + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + } + if (priv->profile != profile) { + priv->profile = profile; + priv->profile_changed = TRUE; + } + + priv->state |= GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +parse_sequence_display_ext (GstVaapiDecoderMpeg2 * decoder, + GstVaapiDecoderUnit * unit, const GstMpegVideoPacket * packet) +{ + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + GstMpegVideoSequenceDisplayExt *seq_display_ext; + + if (!gst_vaapi_parser_info_mpeg2_ensure (&priv->seq_display_ext)) { + GST_ERROR ("failed to allocate parser info for sequence display extension"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + seq_display_ext = &priv->seq_display_ext->data.seq_display_ext; + + if (!gst_mpeg_video_packet_parse_sequence_display_extension (packet, + seq_display_ext)) { + GST_ERROR ("failed to parse sequence-display-extension"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + gst_vaapi_decoder_unit_set_parsed_info (unit, seq_display_ext, NULL); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_sequence_display_ext (GstVaapiDecoderMpeg2 * decoder, + GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + GstMpegVideoSequenceDisplayExt *seq_display_ext; + + seq_display_ext = priv->seq_display_ext ? + &priv->seq_display_ext->data.seq_display_ext : NULL; + + /* Update cropping rectangle */ + if (seq_display_ext) { + GstVaapiRectangle *const crop_rect = &priv->crop_rect; + crop_rect->x = 0; + crop_rect->y = 0; + crop_rect->width = seq_display_ext->display_horizontal_size; + crop_rect->height = seq_display_ext->display_vertical_size; + } + + /* XXX: handle color primaries */ + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +parse_sequence_scalable_ext (GstVaapiDecoderMpeg2 * decoder, + GstVaapiDecoderUnit * unit, const GstMpegVideoPacket * packet) +{ + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + GstMpegVideoSequenceScalableExt *seq_scalable_ext; + + if (!gst_vaapi_parser_info_mpeg2_ensure (&priv->seq_scalable_ext)) { + GST_ERROR + ("failed to allocate parser info for sequence scalable extension"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + seq_scalable_ext = &priv->seq_scalable_ext->data.seq_scalable_ext; + + if (!gst_mpeg_video_packet_parse_sequence_scalable_extension (packet, + seq_scalable_ext)) { + GST_ERROR ("failed to parse sequence-scalable-extension"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + gst_vaapi_decoder_unit_set_parsed_info (unit, seq_scalable_ext, NULL); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_sequence_scalable_ext (GstVaapiDecoderMpeg2 * decoder, + GstVaapiDecoderUnit * unit) +{ + /* XXX: unsupported header -- ignore */ + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_sequence_end (GstVaapiDecoderMpeg2 * decoder) +{ + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + + if (priv->dpb) + gst_vaapi_dpb_flush (priv->dpb); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +parse_quant_matrix_ext (GstVaapiDecoderMpeg2 * decoder, + GstVaapiDecoderUnit * unit, const GstMpegVideoPacket * packet) +{ + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + GstMpegVideoQuantMatrixExt *quant_matrix; + + if (!gst_vaapi_parser_info_mpeg2_ensure (&priv->quant_matrix)) { + GST_ERROR ("failed to allocate parser info for quantization matrix"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + quant_matrix = &priv->quant_matrix->data.quant_matrix; + + if (!gst_mpeg_video_packet_parse_quant_matrix_extension (packet, + quant_matrix)) { + GST_ERROR ("failed to parse quant-matrix-extension"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + gst_vaapi_decoder_unit_set_parsed_info (unit, quant_matrix, NULL); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_quant_matrix_ext (GstVaapiDecoderMpeg2 * decoder, + GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + + priv->quant_matrix_changed = TRUE; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +parse_gop (GstVaapiDecoderMpeg2 * decoder, + GstVaapiDecoderUnit * unit, const GstMpegVideoPacket * packet) +{ + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + GstMpegVideoGop *gop; + + if (!gst_vaapi_parser_info_mpeg2_ensure (&priv->gop)) { + GST_ERROR ("failed to allocate parser info for GOP"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + gop = &priv->gop->data.gop; + + if (!gst_mpeg_video_packet_parse_gop (packet, gop)) { + GST_ERROR ("failed to parse GOP"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + gst_vaapi_decoder_unit_set_parsed_info (unit, gop, NULL); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_gop (GstVaapiDecoderMpeg2 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + GstMpegVideoGop *const gop = unit->parsed_info; + + priv->closed_gop = gop->closed_gop; + priv->broken_link = gop->broken_link; + + GST_DEBUG ("GOP %02u:%02u:%02u:%02u (closed_gop %d, broken_link %d)", + gop->hour, gop->minute, gop->second, gop->frame, + priv->closed_gop, priv->broken_link); + + pts_sync (&priv->tsg, GST_VAAPI_DECODER_CODEC_FRAME (decoder)->pts); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +parse_picture (GstVaapiDecoderMpeg2 * decoder, + GstVaapiDecoderUnit * unit, const GstMpegVideoPacket * packet) +{ + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + GstMpegVideoPictureHdr *pic_hdr; + + priv->state &= (GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR | + GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT); + + if (!gst_vaapi_parser_info_mpeg2_ensure (&priv->pic_hdr)) { + GST_ERROR ("failed to allocate parser info for picture header"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + pic_hdr = &priv->pic_hdr->data.pic_hdr; + + if (!gst_mpeg_video_packet_parse_picture_header (packet, pic_hdr)) { + GST_ERROR ("failed to parse picture header"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + gst_vaapi_decoder_unit_set_parsed_info (unit, pic_hdr, NULL); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_picture (GstVaapiDecoderMpeg2 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + + if (!is_valid_state (decoder, GST_MPEG_VIDEO_STATE_VALID_SEQ_HEADERS)) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + gst_vaapi_parser_info_mpeg2_replace (&priv->pic_ext, NULL); + + priv->state |= GST_MPEG_VIDEO_STATE_GOT_PIC_HDR; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +parse_picture_ext (GstVaapiDecoderMpeg2 * decoder, + GstVaapiDecoderUnit * unit, const GstMpegVideoPacket * packet) +{ + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + GstMpegVideoPictureExt *pic_ext; + + priv->state &= (GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR | + GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT | GST_MPEG_VIDEO_STATE_GOT_PIC_HDR); + + if (!gst_vaapi_parser_info_mpeg2_ensure (&priv->pic_ext)) { + GST_ERROR ("failed to allocate parser info for picture extension"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + pic_ext = &priv->pic_ext->data.pic_ext; + + if (!gst_mpeg_video_packet_parse_picture_extension (packet, pic_ext)) { + GST_ERROR ("failed to parse picture-extension"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + gst_vaapi_decoder_unit_set_parsed_info (unit, pic_ext, NULL); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_picture_ext (GstVaapiDecoderMpeg2 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + GstMpegVideoPictureExt *const pic_ext = unit->parsed_info; + + if (!is_valid_state (decoder, GST_MPEG_VIDEO_STATE_GOT_PIC_HDR)) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + if (priv->progressive_sequence && !pic_ext->progressive_frame) { + GST_WARNING ("invalid interlaced frame in progressive sequence, fixing"); + pic_ext->progressive_frame = 1; + } + + if (pic_ext->picture_structure == 0 || + (pic_ext->progressive_frame && + pic_ext->picture_structure != + GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME)) { + GST_WARNING ("invalid picture_structure %d, replacing with \"frame\"", + pic_ext->picture_structure); + pic_ext->picture_structure = GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME; + } + + priv->state |= GST_MPEG_VIDEO_STATE_GOT_PIC_EXT; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static inline guint32 +pack_f_code (guint8 f_code[2][2]) +{ + return (((guint32) f_code[0][0] << 12) | + ((guint32) f_code[0][1] << 8) | + ((guint32) f_code[1][0] << 4) | (f_code[1][1])); +} + +static GstVaapiDecoderStatus +init_picture (GstVaapiDecoderMpeg2 * decoder, GstVaapiPicture * picture) +{ + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + GstMpegVideoPictureHdr *const pic_hdr = &priv->pic_hdr->data.pic_hdr; + GstMpegVideoPictureExt *const pic_ext = &priv->pic_ext->data.pic_ext; + + switch (pic_hdr->pic_type) { + case GST_MPEG_VIDEO_PICTURE_TYPE_I: + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_REFERENCE); + picture->type = GST_VAAPI_PICTURE_TYPE_I; + break; + case GST_MPEG_VIDEO_PICTURE_TYPE_P: + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_REFERENCE); + picture->type = GST_VAAPI_PICTURE_TYPE_P; + break; + case GST_MPEG_VIDEO_PICTURE_TYPE_B: + picture->type = GST_VAAPI_PICTURE_TYPE_B; + break; + default: + GST_ERROR ("unsupported picture type %d", pic_hdr->pic_type); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + if (!priv->progressive_sequence && !pic_ext->progressive_frame) { + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_INTERLACED); + if (pic_ext->top_field_first) + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_TFF); + } + + switch (pic_ext->picture_structure) { + case GST_MPEG_VIDEO_PICTURE_STRUCTURE_TOP_FIELD: + picture->structure = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD; + break; + case GST_MPEG_VIDEO_PICTURE_STRUCTURE_BOTTOM_FIELD: + picture->structure = GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD; + break; + case GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME: + picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME; + break; + } + + /* Allocate dummy picture for first field based I-frame */ + if (picture->type == GST_VAAPI_PICTURE_TYPE_I && + !GST_VAAPI_PICTURE_IS_FRAME (picture) && + gst_vaapi_dpb_size (priv->dpb) == 0) { + GstVaapiPicture *dummy_picture; + gboolean success; + + dummy_picture = GST_VAAPI_PICTURE_NEW (MPEG2, decoder); + if (!dummy_picture) { + GST_ERROR ("failed to allocate dummy picture"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + dummy_picture->type = GST_VAAPI_PICTURE_TYPE_I; + dummy_picture->pts = GST_CLOCK_TIME_NONE; + dummy_picture->poc = -1; + dummy_picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME; + + GST_VAAPI_PICTURE_FLAG_SET (dummy_picture, + (GST_VAAPI_PICTURE_FLAG_SKIPPED | + GST_VAAPI_PICTURE_FLAG_OUTPUT | GST_VAAPI_PICTURE_FLAG_REFERENCE) + ); + + success = gst_vaapi_dpb_add (priv->dpb, dummy_picture); + gst_vaapi_picture_unref (dummy_picture); + if (!success) { + GST_ERROR ("failed to add dummy picture into DPB"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + GST_INFO ("allocated dummy picture for first field based I-frame"); + } + + /* Update presentation time */ + picture->pts = pts_eval (&priv->tsg, + GST_VAAPI_DECODER_CODEC_FRAME (decoder)->pts, pic_hdr->tsn); + picture->poc = pts_get_poc (&priv->tsg); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static void +fill_picture (GstVaapiDecoderMpeg2 * decoder, GstVaapiPicture * picture) +{ + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + VAPictureParameterBufferMPEG2 *const pic_param = picture->param; + GstMpegVideoPictureHdr *const pic_hdr = &priv->pic_hdr->data.pic_hdr; + GstMpegVideoPictureExt *const pic_ext = &priv->pic_ext->data.pic_ext; + GstVaapiPicture *prev_picture, *next_picture; + + /* Fill in VAPictureParameterBufferMPEG2 */ + pic_param->horizontal_size = priv->width; + pic_param->vertical_size = priv->height; + pic_param->forward_reference_picture = VA_INVALID_ID; + pic_param->backward_reference_picture = VA_INVALID_ID; + pic_param->picture_coding_type = pic_hdr->pic_type; + pic_param->f_code = pack_f_code (pic_ext->f_code); + +#define COPY_FIELD(a, b, f) \ + pic_param->a.b.f = pic_ext->f + pic_param->picture_coding_extension.value = 0; + pic_param->picture_coding_extension.bits.is_first_field = + GST_VAAPI_PICTURE_IS_FIRST_FIELD (picture); + COPY_FIELD (picture_coding_extension, bits, intra_dc_precision); + COPY_FIELD (picture_coding_extension, bits, picture_structure); + COPY_FIELD (picture_coding_extension, bits, top_field_first); + COPY_FIELD (picture_coding_extension, bits, frame_pred_frame_dct); + COPY_FIELD (picture_coding_extension, bits, concealment_motion_vectors); + COPY_FIELD (picture_coding_extension, bits, q_scale_type); + COPY_FIELD (picture_coding_extension, bits, intra_vlc_format); + COPY_FIELD (picture_coding_extension, bits, alternate_scan); + COPY_FIELD (picture_coding_extension, bits, repeat_first_field); + COPY_FIELD (picture_coding_extension, bits, progressive_frame); + + gst_vaapi_dpb_get_neighbours (priv->dpb, picture, + &prev_picture, &next_picture); + + switch (pic_hdr->pic_type) { + case GST_MPEG_VIDEO_PICTURE_TYPE_B: + if (next_picture) + pic_param->backward_reference_picture = next_picture->surface_id; + if (prev_picture) + pic_param->forward_reference_picture = prev_picture->surface_id; + else if (!priv->closed_gop) + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_SKIPPED); + break; + case GST_MPEG_VIDEO_PICTURE_TYPE_P: + if (prev_picture) + pic_param->forward_reference_picture = prev_picture->surface_id; + break; + } +} + +static GstVaapiDecoderStatus +parse_slice (GstVaapiDecoderMpeg2 * decoder, + GstVaapiDecoderUnit * unit, const GstMpegVideoPacket * packet) +{ + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + GstMpegVideoSliceHdr *slice_hdr; + GstMpegVideoSequenceHdr *seq_hdr; + GstMpegVideoSequenceScalableExt *seq_scalable_ext; + + priv->state &= (GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR | + GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT | + GST_MPEG_VIDEO_STATE_GOT_PIC_HDR | GST_MPEG_VIDEO_STATE_GOT_PIC_EXT); + + if (!is_valid_state (decoder, GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS)) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + if (!gst_vaapi_parser_info_mpeg2_ensure (&priv->slice_hdr)) { + GST_ERROR ("failed to allocate parser info for slice header"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + slice_hdr = &priv->slice_hdr->data.slice_hdr; + seq_hdr = &priv->seq_hdr->data.seq_hdr; + seq_scalable_ext = priv->seq_scalable_ext ? + &priv->seq_scalable_ext->data.seq_scalable_ext : NULL; + + if (!gst_mpeg_video_packet_parse_slice_header (packet, slice_hdr, + seq_hdr, seq_scalable_ext)) { + GST_ERROR ("failed to parse slice header"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + gst_vaapi_decoder_unit_set_parsed_info (unit, slice_hdr, NULL); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_slice (GstVaapiDecoderMpeg2 * decoder, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + GstVaapiPicture *const picture = priv->current_picture; + GstVaapiSlice *slice; + VASliceParameterBufferMPEG2 *slice_param; + GstMpegVideoSliceHdr *const slice_hdr = unit->parsed_info; + GstBuffer *const buffer = + GST_VAAPI_DECODER_CODEC_FRAME (decoder)->input_buffer; + GstMapInfo map_info; + + if (!is_valid_state (decoder, GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS)) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) { + GST_ERROR ("failed to map buffer"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + GST_DEBUG ("slice %d (%u bytes)", slice_hdr->mb_row, unit->size); + + slice = GST_VAAPI_SLICE_NEW (MPEG2, decoder, + (map_info.data + unit->offset), unit->size); + gst_buffer_unmap (buffer, &map_info); + if (!slice) { + GST_ERROR ("failed to allocate slice"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + gst_vaapi_picture_add_slice (picture, slice); + + /* Fill in VASliceParameterBufferMPEG2 */ + slice_param = slice->param; + slice_param->macroblock_offset = slice_hdr->header_size + 32; + slice_param->slice_horizontal_position = slice_hdr->mb_column; + slice_param->slice_vertical_position = slice_hdr->mb_row; + slice_param->quantiser_scale_code = slice_hdr->quantiser_scale_code; + slice_param->intra_slice_flag = slice_hdr->intra_slice; + + priv->state |= GST_MPEG_VIDEO_STATE_GOT_SLICE; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static inline gint +scan_for_start_code (const guchar * buf, guint buf_size, + GstMpegVideoPacketTypeCode * type_ptr) +{ + guint i = 0; + + while (i <= (buf_size - 4)) { + if (buf[i + 2] > 1) + i += 3; + else if (buf[i + 1]) + i += 2; + else if (buf[i] || buf[i + 2] != 1) + i++; + else + break; + } + + if (i <= (buf_size - 4)) { + if (type_ptr) + *type_ptr = buf[i + 3]; + return i; + } + return -1; +} + +static GstVaapiDecoderStatus +parse_unit (GstVaapiDecoderMpeg2 * decoder, GstVaapiDecoderUnit * unit, + GstMpegVideoPacket * packet) +{ + GstMpegVideoPacketTypeCode type; + GstMpegVideoPacketExtensionCode ext_type; + GstVaapiDecoderStatus status; + + type = packet->type; + switch (type) { + case GST_MPEG_VIDEO_PACKET_PICTURE: + status = parse_picture (decoder, unit, packet); + break; + case GST_MPEG_VIDEO_PACKET_SEQUENCE: + status = parse_sequence (decoder, unit, packet); + break; + case GST_MPEG_VIDEO_PACKET_EXTENSION: + ext_type = packet->data[4] >> 4; + switch (ext_type) { + case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE: + status = parse_sequence_ext (decoder, unit, packet); + break; + case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY: + status = parse_sequence_display_ext (decoder, unit, packet); + break; + case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_SCALABLE: + status = parse_sequence_scalable_ext (decoder, unit, packet); + break; + case GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX: + status = parse_quant_matrix_ext (decoder, unit, packet); + break; + case GST_MPEG_VIDEO_PACKET_EXT_PICTURE: + status = parse_picture_ext (decoder, unit, packet); + break; + default: + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + break; + } + break; + case GST_MPEG_VIDEO_PACKET_GOP: + status = parse_gop (decoder, unit, packet); + break; + default: + if (type >= GST_MPEG_VIDEO_PACKET_SLICE_MIN && + type <= GST_MPEG_VIDEO_PACKET_SLICE_MAX) { + status = parse_slice (decoder, unit, packet); + break; + } + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + break; + } + return status; +} + +static GstVaapiDecoderStatus +decode_unit (GstVaapiDecoderMpeg2 * decoder, GstVaapiDecoderUnit * unit, + GstMpegVideoPacket * packet) +{ + GstMpegVideoPacketTypeCode type; + GstMpegVideoPacketExtensionCode ext_type; + GstVaapiDecoderStatus status; + + type = packet->type; + switch (type) { + case GST_MPEG_VIDEO_PACKET_PICTURE: + status = decode_picture (decoder, unit); + break; + case GST_MPEG_VIDEO_PACKET_SEQUENCE: + status = decode_sequence (decoder, unit); + break; + case GST_MPEG_VIDEO_PACKET_EXTENSION: + ext_type = packet->data[4] >> 4; + switch (ext_type) { + case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE: + status = decode_sequence_ext (decoder, unit); + break; + case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY: + status = decode_sequence_display_ext (decoder, unit); + break; + case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_SCALABLE: + status = decode_sequence_scalable_ext (decoder, unit); + break; + case GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX: + status = decode_quant_matrix_ext (decoder, unit); + break; + case GST_MPEG_VIDEO_PACKET_EXT_PICTURE: + status = decode_picture_ext (decoder, unit); + break; + default: + // Ignore unknown start-code extensions + GST_WARNING ("unsupported packet extension type 0x%02x", ext_type); + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + break; + } + break; + case GST_MPEG_VIDEO_PACKET_SEQUENCE_END: + status = decode_sequence_end (decoder); + break; + case GST_MPEG_VIDEO_PACKET_GOP: + status = decode_gop (decoder, unit); + break; + default: + if (type >= GST_MPEG_VIDEO_PACKET_SLICE_MIN && + type <= GST_MPEG_VIDEO_PACKET_SLICE_MAX) { + status = decode_slice (decoder, unit); + break; + } + GST_WARNING ("unsupported packet type 0x%02x", type); + status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + break; + } + return status; +} + +static GstVaapiDecoderStatus +ensure_decoder (GstVaapiDecoderMpeg2 * decoder) +{ + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + + if (!priv->is_opened) { + priv->is_opened = gst_vaapi_decoder_mpeg2_open (decoder); + if (!priv->is_opened) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_mpeg2_parse (GstVaapiDecoder * base_decoder, + GstAdapter * adapter, gboolean at_eos, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderMpeg2 *const decoder = + GST_VAAPI_DECODER_MPEG2_CAST (base_decoder); + GstVaapiParserState *const ps = GST_VAAPI_PARSER_STATE (base_decoder); + GstVaapiDecoderStatus status; + GstMpegVideoPacketTypeCode type, type2 = GST_MPEG_VIDEO_PACKET_NONE; + const guchar *buf; + guint buf_size, flags; + gint ofs, ofs1, ofs2; + + status = ensure_decoder (decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + buf_size = gst_adapter_available (adapter); + if (buf_size < 4) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + + buf = gst_adapter_map (adapter, buf_size); + if (!buf) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + + ofs = scan_for_start_code (buf, buf_size, &type); + if (ofs < 0) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + ofs1 = ofs; + + ofs2 = ps->input_offset2 - 4; + if (ofs2 < ofs1 + 4) + ofs2 = ofs1 + 4; + + ofs = G_UNLIKELY (buf_size < ofs2 + 4) ? -1 : + scan_for_start_code (&buf[ofs2], buf_size - ofs2, &type2); + if (ofs < 0) { + // Assume the whole packet is present if end-of-stream + if (!at_eos) { + ps->input_offset2 = buf_size; + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + } + ofs = buf_size - ofs2; + } + ofs2 += ofs; + + unit->size = ofs2 - ofs1; + gst_adapter_flush (adapter, ofs1); + ps->input_offset2 = 4; + + /* Check for start of new picture */ + flags = 0; + switch (type) { + case GST_MPEG_VIDEO_PACKET_SEQUENCE_END: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END; + flags |= GST_VAAPI_DECODER_UNIT_FLAG_STREAM_END; + break; + case GST_MPEG_VIDEO_PACKET_USER_DATA: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP; + /* fall-through */ + case GST_MPEG_VIDEO_PACKET_SEQUENCE: + case GST_MPEG_VIDEO_PACKET_GOP: + case GST_MPEG_VIDEO_PACKET_PICTURE: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START; + break; + case GST_MPEG_VIDEO_PACKET_EXTENSION: + if (G_UNLIKELY (unit->size < 5)) + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + break; + default: + if (type >= GST_MPEG_VIDEO_PACKET_SLICE_MIN && + type <= GST_MPEG_VIDEO_PACKET_SLICE_MAX) { + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE; + switch (type2) { + case GST_MPEG_VIDEO_PACKET_USER_DATA: + case GST_MPEG_VIDEO_PACKET_SEQUENCE: + case GST_MPEG_VIDEO_PACKET_GOP: + case GST_MPEG_VIDEO_PACKET_PICTURE: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END; + break; + default: + break; + } + } + // Ignore system start codes (PES headers) + else if (type >= 0xb9 && type <= 0xff) + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP; + break; + } + GST_VAAPI_DECODER_UNIT_FLAG_SET (unit, flags); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_mpeg2_decode (GstVaapiDecoder * base_decoder, + GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderMpeg2 *const decoder = + GST_VAAPI_DECODER_MPEG2_CAST (base_decoder); + GstVaapiDecoderStatus status; + GstMpegVideoPacket packet; + GstBuffer *const buffer = + GST_VAAPI_DECODER_CODEC_FRAME (decoder)->input_buffer; + GstMapInfo map_info; + + status = ensure_decoder (decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) { + GST_ERROR ("failed to map buffer"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + packet.data = map_info.data + unit->offset; + packet.size = unit->size; + packet.type = packet.data[3]; + packet.offset = 4; + + status = parse_unit (decoder, unit, &packet); + gst_buffer_unmap (buffer, &map_info); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + return decode_unit (decoder, unit, &packet); +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_mpeg2_start_frame (GstVaapiDecoder * base_decoder, + GstVaapiDecoderUnit * base_unit) +{ + GstVaapiDecoderMpeg2 *const decoder = + GST_VAAPI_DECODER_MPEG2_CAST (base_decoder); + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + GstMpegVideoSequenceHdr *seq_hdr; + GstMpegVideoSequenceExt *seq_ext; + GstMpegVideoSequenceDisplayExt *seq_display_ext; + GstVaapiPicture *picture; + GstVaapiDecoderStatus status; + + if (!is_valid_state (decoder, GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS)) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + priv->state &= ~GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS; + + seq_hdr = &priv->seq_hdr->data.seq_hdr; + seq_ext = priv->seq_ext ? &priv->seq_ext->data.seq_ext : NULL; + seq_display_ext = priv->seq_display_ext ? + &priv->seq_display_ext->data.seq_display_ext : NULL; + if (gst_mpeg_video_finalise_mpeg2_sequence_header (seq_hdr, seq_ext, + seq_display_ext)) + gst_vaapi_decoder_set_pixel_aspect_ratio (base_decoder, + seq_hdr->par_w, seq_hdr->par_h); + + status = ensure_context (decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) { + GST_ERROR ("failed to reset context"); + return status; + } + + if (priv->current_picture) { + /* Re-use current picture where the first field was decoded */ + picture = gst_vaapi_picture_new_field (priv->current_picture); + if (!picture) { + GST_ERROR ("failed to allocate field picture"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + } else { + /* Create new picture */ + picture = GST_VAAPI_PICTURE_NEW (MPEG2, decoder); + if (!picture) { + GST_ERROR ("failed to allocate picture"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + } + gst_vaapi_picture_replace (&priv->current_picture, picture); + gst_vaapi_picture_unref (picture); + + /* Update cropping rectangle */ + /* XXX: handle picture_display_extension() */ + if (seq_display_ext && priv->pic_display_ext) { + GstVaapiRectangle *const crop_rect = &priv->crop_rect; + if (crop_rect->x + crop_rect->width <= priv->width && + crop_rect->y + crop_rect->height <= priv->height) + gst_vaapi_picture_set_crop_rect (picture, crop_rect); + } + + status = ensure_quant_matrix (decoder, picture); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) { + GST_ERROR ("failed to reset quantizer matrix"); + return status; + } + + status = init_picture (decoder, picture); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + fill_picture (decoder, picture); + + priv->state |= GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_mpeg2_end_frame (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderMpeg2 *const decoder = + GST_VAAPI_DECODER_MPEG2_CAST (base_decoder); + + return decode_current_picture (decoder); +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_mpeg2_flush (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderMpeg2 *const decoder = + GST_VAAPI_DECODER_MPEG2_CAST (base_decoder); + GstVaapiDecoderMpeg2Private *const priv = &decoder->priv; + + if (priv->dpb) + gst_vaapi_dpb_flush (priv->dpb); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static void +gst_vaapi_decoder_mpeg2_finalize (GObject * object) +{ + GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (object); + + gst_vaapi_decoder_mpeg2_destroy (base_decoder); + G_OBJECT_CLASS (gst_vaapi_decoder_mpeg2_parent_class)->finalize (object); +} + +static void +gst_vaapi_decoder_mpeg2_class_init (GstVaapiDecoderMpeg2Class * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstVaapiDecoderClass *const decoder_class = GST_VAAPI_DECODER_CLASS (klass); + + object_class->finalize = gst_vaapi_decoder_mpeg2_finalize; + + decoder_class->reset = gst_vaapi_decoder_mpeg2_reset; + decoder_class->parse = gst_vaapi_decoder_mpeg2_parse; + decoder_class->decode = gst_vaapi_decoder_mpeg2_decode; + decoder_class->start_frame = gst_vaapi_decoder_mpeg2_start_frame; + decoder_class->end_frame = gst_vaapi_decoder_mpeg2_end_frame; + decoder_class->flush = gst_vaapi_decoder_mpeg2_flush; +} + +static void +gst_vaapi_decoder_mpeg2_init (GstVaapiDecoderMpeg2 * decoder) +{ + GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (decoder); + + gst_vaapi_decoder_mpeg2_create (base_decoder); +} + +/** + * gst_vaapi_decoder_mpeg2_new: + * @display: a #GstVaapiDisplay + * @caps: a #GstCaps holding codec information + * + * Creates a new #GstVaapiDecoder for MPEG-2 decoding. The @caps can + * hold extra information like codec-data and pictured coded size. + * + * Return value: the newly allocated #GstVaapiDecoder object + */ +GstVaapiDecoder * +gst_vaapi_decoder_mpeg2_new (GstVaapiDisplay * display, GstCaps * caps) +{ + return g_object_new (GST_TYPE_VAAPI_DECODER_MPEG2, "display", display, + "caps", caps, NULL); +} diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.h b/gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.h new file mode 100644 index 0000000000..765a80cac7 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.h @@ -0,0 +1,50 @@ +/* + * gstvaapidecoder_mpeg2.h - MPEG-2 decoder + * + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODER_MPEG2_H +#define GST_VAAPI_DECODER_MPEG2_H + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_DECODER_MPEG2 \ + (gst_vaapi_decoder_mpeg2_get_type ()) +#define GST_VAAPI_DECODER_MPEG2(decoder) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DECODER_MPEG2, GstVaapiDecoderMpeg2)) +#define GST_VAAPI_IS_DECODER_MPEG2(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_DECODER_MPEG2)) + +typedef struct _GstVaapiDecoderMpeg2 GstVaapiDecoderMpeg2; + +GType +gst_vaapi_decoder_mpeg2_get_type (void) G_GNUC_CONST; + +GstVaapiDecoder * +gst_vaapi_decoder_mpeg2_new (GstVaapiDisplay *display, GstCaps *caps); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDecoderMpeg2, gst_object_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_DECODER_MPEG2_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c b/gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c new file mode 100644 index 0000000000..8ecdb324fd --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c @@ -0,0 +1,1215 @@ +/* + * gstvaapidecoder_mpeg4.c - MPEG-4 decoder + * + * Copyright (C) 2011-2013 Intel Corporation + * Author: Halley Zhao + * + * 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:gstvaapidecoder_mpeg4 + * @short_description: MPEG-4 decoder, include h263/divx/xvid support + */ + +#include "sysdeps.h" +#include +#include +#include "gstvaapidecoder_mpeg4.h" +#include "gstvaapidecoder_objects.h" +#include "gstvaapidecoder_priv.h" +#include "gstvaapidisplay_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +#define GST_VAAPI_DECODER_MPEG4_CAST(decoder) \ + ((GstVaapiDecoderMpeg4 *)(decoder)) + +typedef struct _GstVaapiDecoderMpeg4Private GstVaapiDecoderMpeg4Private; +typedef struct _GstVaapiDecoderMpeg4Class GstVaapiDecoderMpeg4Class; + +struct _GstVaapiDecoderMpeg4Private +{ + GstVaapiProfile profile; + guint level; + guint width; + guint height; + guint fps_n; + guint fps_d; + guint coding_type; + GstMpeg4VisualObjectSequence vos_hdr; + GstMpeg4VisualObject vo_hdr; + GstMpeg4VideoSignalType signal_type; + GstMpeg4VideoObjectLayer vol_hdr; + GstMpeg4VideoObjectPlane vop_hdr; + GstMpeg4VideoPlaneShortHdr svh_hdr; + GstMpeg4VideoPacketHdr packet_hdr; + GstMpeg4SpriteTrajectory sprite_trajectory; + VAIQMatrixBufferMPEG4 iq_matrix; + GstVaapiPicture *curr_picture; + // forward reference pic + GstVaapiPicture *next_picture; + // backward reference pic + GstVaapiPicture *prev_picture; + GstClockTime seq_pts; + GstClockTime gop_pts; + GstClockTime pts_diff; + GstClockTime max_pts; + // anchor sync time base for any picture type, + // it is time base of backward reference frame + GstClockTime last_sync_time; + // time base for recent I/P/S frame, + // it is time base of forward reference frame for B frame + GstClockTime sync_time; + + /* last non-b-frame time by resolution */ + GstClockTime last_non_b_scale_time; + GstClockTime non_b_scale_time; + GstClockTime trb; + GstClockTime trd; + // temporal_reference of previous frame of svh + guint8 prev_t_ref; + guint is_opened:1; + guint is_first_field:1; + guint size_changed:1; + guint profile_changed:1; + guint progressive_sequence:1; + guint closed_gop:1; + guint broken_link:1; + guint calculate_pts_diff:1; + guint is_svh:1; +}; + +/** + * GstVaapiDecoderMpeg4: + * + * A decoder based on Mpeg4. + */ +struct _GstVaapiDecoderMpeg4 +{ + /*< private > */ + GstVaapiDecoder parent_instance; + GstVaapiDecoderMpeg4Private priv; +}; + +/** + * GstVaapiDecoderMpeg4Class: + * + * A decoder class based on Mpeg4. + */ +struct _GstVaapiDecoderMpeg4Class +{ + /*< private > */ + GstVaapiDecoderClass parent_class; +}; + +G_DEFINE_TYPE (GstVaapiDecoderMpeg4, gst_vaapi_decoder_mpeg4, + GST_TYPE_VAAPI_DECODER); + +static void +gst_vaapi_decoder_mpeg4_close (GstVaapiDecoderMpeg4 * decoder) +{ + GstVaapiDecoderMpeg4Private *const priv = &decoder->priv; + + gst_vaapi_picture_replace (&priv->curr_picture, NULL); + gst_vaapi_picture_replace (&priv->next_picture, NULL); + gst_vaapi_picture_replace (&priv->prev_picture, NULL); +} + +static gboolean +gst_vaapi_decoder_mpeg4_open (GstVaapiDecoderMpeg4 * decoder) +{ + GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (decoder); + GstVaapiDecoderMpeg4Private *const priv = &decoder->priv; + GstCaps *caps = NULL; + GstStructure *structure = NULL; + + gst_vaapi_decoder_mpeg4_close (decoder); + + priv->is_svh = 0; + caps = gst_vaapi_decoder_get_caps (base_decoder); + if (caps) { + structure = gst_caps_get_structure (caps, 0); + if (structure) { + if (gst_structure_has_name (structure, "video/x-h263")) { + priv->is_svh = 1; + priv->profile = GST_VAAPI_PROFILE_MPEG4_SIMPLE; + priv->prev_t_ref = -1; + } + } + } + return TRUE; +} + +static void +gst_vaapi_decoder_mpeg4_destroy (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderMpeg4 *const decoder = + GST_VAAPI_DECODER_MPEG4_CAST (base_decoder); + + gst_vaapi_decoder_mpeg4_close (decoder); +} + +static gboolean +gst_vaapi_decoder_mpeg4_create (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderMpeg4 *const decoder = + GST_VAAPI_DECODER_MPEG4_CAST (base_decoder); + GstVaapiDecoderMpeg4Private *const priv = &decoder->priv; + + priv->profile = GST_VAAPI_PROFILE_MPEG4_SIMPLE; + priv->seq_pts = GST_CLOCK_TIME_NONE; + priv->gop_pts = GST_CLOCK_TIME_NONE; + priv->max_pts = GST_CLOCK_TIME_NONE; + priv->calculate_pts_diff = TRUE; + priv->size_changed = TRUE; + priv->profile_changed = TRUE; + return TRUE; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_mpeg4_reset (GstVaapiDecoder * base_decoder) +{ + gst_vaapi_decoder_mpeg4_destroy (base_decoder); + gst_vaapi_decoder_mpeg4_create (base_decoder); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static inline void +copy_quant_matrix (guint8 dst[64], const guint8 src[64]) +{ + memcpy (dst, src, 64); +} + +static GstVaapiDecoderStatus +ensure_context (GstVaapiDecoderMpeg4 * decoder) +{ + GstVaapiDecoderMpeg4Private *const priv = &decoder->priv; + GstVaapiProfile profiles[2]; + GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD; + guint i, n_profiles = 0; + gboolean reset_context = FALSE; + + if (priv->profile_changed) { + GST_DEBUG ("profile changed"); + priv->profile_changed = FALSE; + reset_context = TRUE; + + profiles[n_profiles++] = priv->profile; + if (priv->profile == GST_VAAPI_PROFILE_MPEG4_SIMPLE) + profiles[n_profiles++] = GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE; + + for (i = 0; i < n_profiles; i++) { + if (gst_vaapi_display_has_decoder (GST_VAAPI_DECODER_DISPLAY (decoder), + profiles[i], entrypoint)) + break; + } + if (i == n_profiles) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + priv->profile = profiles[i]; + } + + if (priv->size_changed) { + GST_DEBUG ("size changed"); + priv->size_changed = FALSE; + reset_context = TRUE; + } + + if (reset_context) { + GstVaapiContextInfo info; + + info.profile = priv->profile; + info.entrypoint = entrypoint; + info.chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420; + info.width = priv->width; + info.height = priv->height; + info.ref_frames = 2; + reset_context = + gst_vaapi_decoder_ensure_context (GST_VAAPI_DECODER (decoder), &info); + if (!reset_context) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +ensure_quant_matrix (GstVaapiDecoderMpeg4 * decoder, GstVaapiPicture * picture) +{ + GstVaapiDecoderMpeg4Private *const priv = &decoder->priv; + VAIQMatrixBufferMPEG4 *iq_matrix; + + if (!priv->vol_hdr.load_intra_quant_mat + && !priv->vol_hdr.load_non_intra_quant_mat) { + return GST_VAAPI_DECODER_STATUS_SUCCESS; + } + + picture->iq_matrix = GST_VAAPI_IQ_MATRIX_NEW (MPEG4, decoder); + if (!picture->iq_matrix) { + GST_DEBUG ("failed to allocate IQ matrix"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + iq_matrix = picture->iq_matrix->param; + + if (priv->vol_hdr.load_intra_quant_mat) { + iq_matrix->load_intra_quant_mat = 1; + copy_quant_matrix (iq_matrix->intra_quant_mat, + priv->vol_hdr.intra_quant_mat); + } else + iq_matrix->load_intra_quant_mat = 0; + + if (priv->vol_hdr.load_non_intra_quant_mat) { + iq_matrix->load_non_intra_quant_mat = 1; + copy_quant_matrix (iq_matrix->non_intra_quant_mat, + priv->vol_hdr.non_intra_quant_mat); + } else + iq_matrix->load_non_intra_quant_mat = 0; + + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static inline GstVaapiDecoderStatus +render_picture (GstVaapiDecoderMpeg4 * decoder, GstVaapiPicture * picture) +{ + if (!gst_vaapi_picture_output (picture)) + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +/* decode_picture() start to decode a frame/picture + * decode_current_picture() finishe decoding a frame/picture + * (commit buffer to driver for decoding) + */ +static GstVaapiDecoderStatus +decode_current_picture (GstVaapiDecoderMpeg4 * decoder) +{ + GstVaapiDecoderMpeg4Private *const priv = &decoder->priv; + GstVaapiPicture *const picture = priv->curr_picture; + GstVaapiDecoderStatus status = GST_VAAPI_DECODER_STATUS_SUCCESS; + + if (picture) { + if (!gst_vaapi_picture_decode (picture)) + status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + if (!GST_VAAPI_PICTURE_IS_REFERENCE (picture)) { + if ((priv->prev_picture && priv->next_picture) || + (priv->closed_gop && priv->next_picture)) + status = render_picture (decoder, picture); + } + gst_vaapi_picture_replace (&priv->curr_picture, NULL); + } + return status; +} + +static GstVaapiDecoderStatus +decode_sequence (GstVaapiDecoderMpeg4 * decoder, const guint8 * buf, + guint buf_size) +{ + GstVaapiDecoderMpeg4Private *const priv = &decoder->priv; + GstMpeg4VisualObjectSequence *const vos_hdr = &priv->vos_hdr; + GstVaapiProfile profile; + + if (gst_mpeg4_parse_visual_object_sequence (vos_hdr, buf, + buf_size) != GST_MPEG4_PARSER_OK) { + GST_DEBUG ("failed to parse sequence header"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + priv->level = vos_hdr->level; + switch (vos_hdr->profile) { + case GST_MPEG4_PROFILE_SIMPLE: + profile = GST_VAAPI_PROFILE_MPEG4_SIMPLE; + break; + case GST_MPEG4_PROFILE_ADVANCED_SIMPLE: + case GST_MPEG4_PROFILE_SIMPLE_SCALABLE: /* shared profile with ADVANCED_SIMPLE */ + profile = GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE; + break; + default: + GST_DEBUG ("unsupported profile %d", vos_hdr->profile); + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + } + if (priv->profile != profile) { + priv->profile = profile; + priv->profile_changed = TRUE; + } + priv->seq_pts = GST_VAAPI_DECODER_CODEC_FRAME (decoder)->pts; + priv->size_changed = TRUE; + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_sequence_end (GstVaapiDecoderMpeg4 * decoder) +{ + GstVaapiDecoderMpeg4Private *const priv = &decoder->priv; + GstVaapiDecoderStatus status; + + if (priv->curr_picture) { + status = decode_current_picture (decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + status = render_picture (decoder, priv->curr_picture); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + } + + if (priv->next_picture) { + status = render_picture (decoder, priv->next_picture); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + } + return GST_VAAPI_DECODER_STATUS_END_OF_STREAM; +} + +static GstVaapiDecoderStatus +decode_visual_object (GstVaapiDecoderMpeg4 * decoder, const guint8 * buf, + guint buf_size) +{ + GstVaapiDecoderMpeg4Private *const priv = &decoder->priv; + GstMpeg4VisualObject *vo_hdr = &priv->vo_hdr; + GstMpeg4VideoSignalType *signal_type = &priv->signal_type; + + if (gst_mpeg4_parse_visual_object (vo_hdr, signal_type, buf, + buf_size) != GST_MPEG4_PARSER_OK) { + GST_DEBUG ("failed to parse visual object"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + /* XXX: video_signal_type isn't used for decoding */ + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_video_object_layer (GstVaapiDecoderMpeg4 * decoder, const guint8 * buf, + guint buf_size) +{ + GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (decoder); + GstVaapiDecoderMpeg4Private *const priv = &decoder->priv; + GstMpeg4VisualObject *vo_hdr = &priv->vo_hdr; + GstMpeg4VideoObjectLayer *vol_hdr = &priv->vol_hdr; + + if (gst_mpeg4_parse_video_object_layer (vol_hdr, vo_hdr, buf, + buf_size) != GST_MPEG4_PARSER_OK) { + GST_DEBUG ("failed to parse video object layer"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + priv->width = vol_hdr->width; + priv->height = vol_hdr->height; + + priv->progressive_sequence = !vol_hdr->interlaced; + + if (vol_hdr->fixed_vop_rate) { + priv->fps_n = vol_hdr->vop_time_increment_resolution; + priv->fps_d = vol_hdr->fixed_vop_time_increment; + gst_vaapi_decoder_set_framerate (base_decoder, priv->fps_n, priv->fps_d); + } + + gst_vaapi_decoder_set_pixel_aspect_ratio (base_decoder, + priv->vol_hdr.par_width, priv->vol_hdr.par_height); + gst_vaapi_decoder_set_picture_size (base_decoder, priv->width, priv->height); + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_gop (GstVaapiDecoderMpeg4 * decoder, const guint8 * buf, guint buf_size) +{ + GstVaapiDecoderMpeg4Private *const priv = &decoder->priv; + GstMpeg4GroupOfVOP gop; + GstClockTime gop_time; + + if (buf_size > 4) { + if (gst_mpeg4_parse_group_of_vop (&gop, buf, + buf_size) != GST_MPEG4_PARSER_OK) { + GST_DEBUG ("failed to parse GOP"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + } else { + gop.closed = 1; + gop.broken_link = 0; + gop.hours = 0; + gop.minutes = 0; + gop.seconds = 0; + } + + priv->closed_gop = gop.closed; + priv->broken_link = gop.broken_link; + + GST_DEBUG ("GOP %02u:%02u:%02u (closed_gop %d, broken_link %d)", + gop.hours, gop.minutes, gop.seconds, priv->closed_gop, priv->broken_link); + + gop_time = gop.hours * 3600 + gop.minutes * 60 + gop.seconds; + priv->last_sync_time = gop_time; + priv->sync_time = gop_time; + + if (priv->gop_pts != GST_CLOCK_TIME_NONE) + priv->pts_diff += gop_time * GST_SECOND - priv->gop_pts; + priv->gop_pts = gop_time * GST_SECOND; + priv->calculate_pts_diff = TRUE; + priv->is_first_field = TRUE; + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static void +calculate_pts_diff (GstVaapiDecoderMpeg4 * decoder, + GstMpeg4VideoObjectLayer * vol_hdr, GstMpeg4VideoObjectPlane * vop_hdr) +{ + GstVaapiDecoderMpeg4Private *const priv = &decoder->priv; + GstClockTime frame_timestamp; + + frame_timestamp = GST_VAAPI_DECODER_CODEC_FRAME (decoder)->pts; + if (frame_timestamp && frame_timestamp != GST_CLOCK_TIME_NONE) { + /* Buffer with timestamp */ + if (priv->max_pts != GST_CLOCK_TIME_NONE && frame_timestamp < priv->max_pts) { + frame_timestamp = priv->max_pts + + gst_util_uint64_scale ((vol_hdr->fixed_vop_rate ? + vol_hdr->fixed_vop_time_increment : 1), + GST_SECOND, vol_hdr->vop_time_increment_resolution); + } + } else { + /* Buffer without timestamp set */ + if (priv->max_pts == GST_CLOCK_TIME_NONE) /* first buffer */ + frame_timestamp = 0; + else { + GstClockTime tmp_pts; + tmp_pts = priv->pts_diff + priv->gop_pts + + vop_hdr->modulo_time_base * GST_SECOND + + gst_util_uint64_scale (vop_hdr->time_increment, + GST_SECOND, vol_hdr->vop_time_increment_resolution); + if (tmp_pts > priv->max_pts) + frame_timestamp = tmp_pts; + else + frame_timestamp = priv->max_pts + + gst_util_uint64_scale ((vol_hdr->fixed_vop_rate ? + vol_hdr->fixed_vop_time_increment : 1), + GST_SECOND, vol_hdr->vop_time_increment_resolution); + } + } + + priv->pts_diff = frame_timestamp - + (priv->gop_pts + vop_hdr->modulo_time_base * GST_SECOND + + gst_util_uint64_scale (vop_hdr->time_increment, GST_SECOND, + vol_hdr->vop_time_increment_resolution)); +} + +static GstVaapiDecoderStatus +decode_picture (GstVaapiDecoderMpeg4 * decoder, const guint8 * buf, + guint buf_size) +{ + GstMpeg4ParseResult parser_result = GST_MPEG4_PARSER_OK; + GstVaapiDecoderMpeg4Private *const priv = &decoder->priv; + GstMpeg4VideoObjectPlane *const vop_hdr = &priv->vop_hdr; + GstMpeg4VideoObjectLayer *const vol_hdr = &priv->vol_hdr; + GstMpeg4SpriteTrajectory *const sprite_trajectory = &priv->sprite_trajectory; + GstVaapiPicture *picture; + GstVaapiDecoderStatus status; + GstClockTime pts; + + // context depends on priv->width and priv->height, so we move parse_vop a little earlier + if (priv->is_svh) { + parser_result = + gst_mpeg4_parse_video_plane_short_header (&priv->svh_hdr, buf, + buf_size); + + } else { + parser_result = + gst_mpeg4_parse_video_object_plane (vop_hdr, sprite_trajectory, vol_hdr, + buf, buf_size); + /* Need to skip this frame if VOP was not coded */ + if (GST_MPEG4_PARSER_OK == parser_result && !vop_hdr->coded) + return (GstVaapiDecoderStatus) GST_VAAPI_DECODER_STATUS_DROP_FRAME; + } + + if (parser_result != GST_MPEG4_PARSER_OK) { + GST_DEBUG ("failed to parse picture header"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + if (priv->is_svh) { + priv->width = priv->svh_hdr.vop_width; + priv->height = priv->svh_hdr.vop_height; + } else { + if (!vop_hdr->width && !vop_hdr->height) { + vop_hdr->width = vol_hdr->width; + vop_hdr->height = vol_hdr->height; + } + priv->width = vop_hdr->width; + priv->height = vop_hdr->height; + } + + status = ensure_context (decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) { + GST_DEBUG ("failed to reset context"); + return status; + } + + if (priv->curr_picture) { + status = decode_current_picture (decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + } + + priv->curr_picture = GST_VAAPI_PICTURE_NEW (MPEG4, decoder); + if (!priv->curr_picture) { + GST_DEBUG ("failed to allocate picture"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + picture = priv->curr_picture; + + status = ensure_quant_matrix (decoder, picture); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) { + GST_DEBUG ("failed to reset quantizer matrix"); + return status; + } + + /* 7.6.7 Temporal prediction structure + * forward reference frame B B B B B B backward reference frame + * | | + * nearest I/P/S in the past with vop_coded ==1 | + * nearest I/P/S in the future with any vop_coded + * FIXME: it said that B frame shouldn't use backward reference frame + * when backward reference frame coded is 0 + */ + if (priv->is_svh) { + priv->coding_type = priv->svh_hdr.picture_coding_type; + } else { + priv->coding_type = priv->vop_hdr.coding_type; + } + switch (priv->coding_type) { + case GST_MPEG4_I_VOP: + picture->type = GST_VAAPI_PICTURE_TYPE_I; + if (priv->is_svh || vop_hdr->coded) + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_REFERENCE); + break; + case GST_MPEG4_P_VOP: + picture->type = GST_VAAPI_PICTURE_TYPE_P; + if (priv->is_svh || vop_hdr->coded) + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_REFERENCE); + break; + case GST_MPEG4_B_VOP: + picture->type = GST_VAAPI_PICTURE_TYPE_B; + break; + case GST_MPEG4_S_VOP: + picture->type = GST_VAAPI_PICTURE_TYPE_S; + // see 3.175 reference VOP + if (vop_hdr->coded) + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_REFERENCE); + break; + default: + GST_DEBUG ("unsupported picture type %d", priv->coding_type); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + if (!priv->is_svh && !vop_hdr->coded) { + status = render_picture (decoder, priv->prev_picture); + return status; + } + + if (priv->is_svh) { + guint temp_ref = priv->svh_hdr.temporal_reference; + guint delta_ref; + + if (temp_ref < priv->prev_t_ref) { + temp_ref += 256; + } + delta_ref = temp_ref - priv->prev_t_ref; + + pts = priv->sync_time; + // see temporal_reference definition in spec, 30000/1001Hz + pts += gst_util_uint64_scale (delta_ref, GST_SECOND * 1001, 30000); + priv->sync_time = pts; + priv->prev_t_ref = priv->svh_hdr.temporal_reference; + } else { + /* Update priv->pts_diff */ + if (priv->calculate_pts_diff) { + calculate_pts_diff (decoder, vol_hdr, vop_hdr); + priv->calculate_pts_diff = FALSE; + } + + /* Update presentation time, 6.3.5 */ + if (vop_hdr->coding_type != GST_MPEG4_B_VOP) { + // increment basing on decoding order + priv->last_sync_time = priv->sync_time; + priv->sync_time = priv->last_sync_time + vop_hdr->modulo_time_base; + pts = priv->sync_time * GST_SECOND; + pts += + gst_util_uint64_scale (vop_hdr->time_increment, GST_SECOND, + vol_hdr->vop_time_increment_resolution); + priv->last_non_b_scale_time = priv->non_b_scale_time; + priv->non_b_scale_time = + priv->sync_time * vol_hdr->vop_time_increment_resolution + + vop_hdr->time_increment; + priv->trd = priv->non_b_scale_time - priv->last_non_b_scale_time; + } else { + // increment basing on display oder + pts = (priv->last_sync_time + vop_hdr->modulo_time_base) * GST_SECOND; + pts += + gst_util_uint64_scale (vop_hdr->time_increment, GST_SECOND, + vol_hdr->vop_time_increment_resolution); + priv->trb = + (priv->last_sync_time + + vop_hdr->modulo_time_base) * vol_hdr->vop_time_increment_resolution + + vop_hdr->time_increment - priv->last_non_b_scale_time; + } + } + picture->pts = pts + priv->pts_diff; + if (priv->max_pts == GST_CLOCK_TIME_NONE || priv->max_pts < picture->pts) + priv->max_pts = picture->pts; + + /* Update reference pictures */ + /* XXX: consider priv->vol_hdr.low_delay, consider packed video frames for DivX/XviD */ + if (GST_VAAPI_PICTURE_IS_REFERENCE (picture)) { + if (priv->next_picture) + status = render_picture (decoder, priv->next_picture); + gst_vaapi_picture_replace (&priv->prev_picture, priv->next_picture); + gst_vaapi_picture_replace (&priv->next_picture, picture); + } + return status; +} + +static inline guint +get_vop_coding_type (GstVaapiPicture * picture) +{ + return picture->type - GST_VAAPI_PICTURE_TYPE_I; +} + +static gboolean +fill_picture (GstVaapiDecoderMpeg4 * decoder, GstVaapiPicture * picture) +{ + GstVaapiDecoderMpeg4Private *const priv = &decoder->priv; + VAPictureParameterBufferMPEG4 *const pic_param = picture->param; + GstMpeg4VideoObjectPlane *const vop_hdr = &priv->vop_hdr; + + /* Fill in VAPictureParameterBufferMPEG4 */ + pic_param->forward_reference_picture = VA_INVALID_ID; + pic_param->backward_reference_picture = VA_INVALID_ID; + + pic_param->vol_fields.value = 0; + pic_param->vop_fields.value = 0; + if (priv->is_svh) { + // vol_hdr Parameters + pic_param->vol_fields.bits.short_video_header = 1; + // does the following vol_hdr parameters matter for short video header? + pic_param->vol_fields.bits.chroma_format = 1; // I420, see table 6-15. + pic_param->vol_fields.bits.interlaced = 0; + pic_param->vol_fields.bits.obmc_disable = 1; + pic_param->vol_fields.bits.sprite_enable = 0; + pic_param->vol_fields.bits.sprite_warping_accuracy = 0; + pic_param->vol_fields.bits.quant_type = 0; //method 1; $7.4.4 + pic_param->vol_fields.bits.quarter_sample = 0; + pic_param->vol_fields.bits.data_partitioned = 0; + pic_param->vol_fields.bits.reversible_vlc = 0; + pic_param->vol_fields.bits.resync_marker_disable = 1; + pic_param->no_of_sprite_warping_points = 0; + pic_param->quant_precision = 5; + // VOP parameters + pic_param->vop_width = priv->svh_hdr.vop_width; + pic_param->vop_height = priv->svh_hdr.vop_height; + pic_param->vop_fields.bits.vop_coding_type = + priv->svh_hdr.picture_coding_type; + pic_param->vop_time_increment_resolution = + priv->vol_hdr.vop_time_increment_resolution; + + pic_param->num_gobs_in_vop = priv->svh_hdr.num_gobs_in_vop; + pic_param->num_macroblocks_in_gob = priv->svh_hdr.num_macroblocks_in_gob; + } else { + int i; + + // VOL parameters + pic_param->vol_fields.bits.short_video_header = 0; + pic_param->vol_fields.bits.chroma_format = priv->vol_hdr.chroma_format; + pic_param->vol_fields.bits.interlaced = priv->vol_hdr.interlaced; + pic_param->vol_fields.bits.obmc_disable = priv->vol_hdr.obmc_disable; + pic_param->vol_fields.bits.sprite_enable = priv->vol_hdr.sprite_enable; + pic_param->vol_fields.bits.sprite_warping_accuracy = + priv->vol_hdr.sprite_warping_accuracy; + pic_param->vol_fields.bits.quant_type = priv->vol_hdr.quant_type; + pic_param->vol_fields.bits.quarter_sample = priv->vol_hdr.quarter_sample; + pic_param->vol_fields.bits.data_partitioned = + priv->vol_hdr.data_partitioned; + pic_param->vol_fields.bits.reversible_vlc = priv->vol_hdr.reversible_vlc; + pic_param->vol_fields.bits.resync_marker_disable = + priv->vol_hdr.resync_marker_disable; + pic_param->no_of_sprite_warping_points = + priv->vol_hdr.no_of_sprite_warping_points; + + for (i = 0; i < 3 && i < priv->vol_hdr.no_of_sprite_warping_points; i++) { + pic_param->sprite_trajectory_du[i] = + priv->sprite_trajectory.vop_ref_points[i]; + pic_param->sprite_trajectory_dv[i] = + priv->sprite_trajectory.sprite_ref_points[i]; + } + pic_param->quant_precision = priv->vol_hdr.quant_precision; + + // VOP parameters + pic_param->vop_width = vop_hdr->width; + pic_param->vop_height = vop_hdr->height; + pic_param->vop_fields.bits.vop_coding_type = vop_hdr->coding_type; + pic_param->vop_fields.bits.vop_rounding_type = vop_hdr->rounding_type; + pic_param->vop_fields.bits.intra_dc_vlc_thr = vop_hdr->intra_dc_vlc_thr; + pic_param->vop_fields.bits.top_field_first = vop_hdr->top_field_first; + pic_param->vop_fields.bits.alternate_vertical_scan_flag = + vop_hdr->alternate_vertical_scan_flag; + + pic_param->vop_fcode_forward = vop_hdr->fcode_forward; + pic_param->vop_fcode_backward = vop_hdr->fcode_backward; + pic_param->vop_time_increment_resolution = + priv->vol_hdr.vop_time_increment_resolution; + } + + pic_param->TRB = 0; + pic_param->TRD = 0; + switch (priv->coding_type) { + case GST_MPEG4_B_VOP: + pic_param->TRB = priv->trb; + pic_param->backward_reference_picture = priv->next_picture->surface_id; + pic_param->vop_fields.bits.backward_reference_vop_coding_type = + get_vop_coding_type (priv->next_picture); + // fall-through + case GST_MPEG4_P_VOP: + pic_param->TRD = priv->trd; + if (priv->prev_picture) + pic_param->forward_reference_picture = priv->prev_picture->surface_id; + break; + } + + if (priv->vol_hdr.interlaced) { + priv->is_first_field ^= 1; + } + return TRUE; +} + +static GstVaapiDecoderStatus +decode_slice (GstVaapiDecoderMpeg4 * decoder, + const guint8 * buf, guint buf_size, gboolean has_packet_header) +{ + GstVaapiDecoderMpeg4Private *const priv = &decoder->priv; + GstVaapiPicture *const picture = priv->curr_picture; + GstVaapiSlice *slice; + VASliceParameterBufferMPEG4 *slice_param; + + GST_DEBUG ("decoder silce: %p, %u bytes)", buf, buf_size); + + // has_packet_header is ture for the 2+ slice + if (!has_packet_header && !fill_picture (decoder, picture)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + + slice = GST_VAAPI_SLICE_NEW (MPEG4, decoder, buf, buf_size); + if (!slice) { + GST_DEBUG ("failed to allocate slice"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + gst_vaapi_picture_add_slice (picture, slice); + + /* Fill in VASliceParameterBufferMPEG4 */ + slice_param = slice->param; + if (priv->is_svh) { + slice_param->macroblock_offset = (priv->svh_hdr.size) % 8; + slice_param->macroblock_number = 0; + // the header of first gob_layer is empty (gob_header_empty=1), use vop_quant + slice_param->quant_scale = priv->svh_hdr.vop_quant; + } else { + if (has_packet_header) { + slice_param->macroblock_offset = priv->packet_hdr.size % 8; + slice_param->macroblock_number = priv->packet_hdr.macroblock_number; + slice_param->quant_scale = priv->packet_hdr.quant_scale; + } else { + slice_param->macroblock_offset = priv->vop_hdr.size % 8; + slice_param->macroblock_number = 0; + slice_param->quant_scale = priv->vop_hdr.quant; + } + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_packet (GstVaapiDecoderMpeg4 * decoder, GstMpeg4Packet packet) +{ + GstVaapiDecoderMpeg4Private *const priv = &decoder->priv; + GstMpeg4Packet *tos = &packet; + GstVaapiDecoderStatus status; + + // packet.size is the size from current marker to the next. + if (tos->type == GST_MPEG4_VISUAL_OBJ_SEQ_START) { + status = + decode_sequence (decoder, packet.data + packet.offset, packet.size); + } else if (tos->type == GST_MPEG4_VISUAL_OBJ_SEQ_END) { + status = decode_sequence_end (decoder); + } else if (tos->type == GST_MPEG4_VISUAL_OBJ) { + status = + decode_visual_object (decoder, packet.data + packet.offset, + packet.size); + } else if (tos->type >= GST_MPEG4_VIDEO_OBJ_FIRST + && tos->type <= GST_MPEG4_VIDEO_OBJ_LAST) { + GST_WARNING + ("unexpected marker: (GST_MPEG4_VIDEO_OBJ_FIRST, GST_MPEG4_VIDEO_OBJ_LAST)"); + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + } else if (tos->type >= GST_MPEG4_VIDEO_LAYER_FIRST + && tos->type <= GST_MPEG4_VIDEO_LAYER_LAST) { + status = + decode_video_object_layer (decoder, packet.data + packet.offset, + packet.size); + } else if (tos->type == GST_MPEG4_GROUP_OF_VOP) { + status = decode_gop (decoder, packet.data + packet.offset, packet.size); + } else if (tos->type == GST_MPEG4_VIDEO_OBJ_PLANE) { + GstMpeg4Packet video_packet; + const guint8 *_data; + gint _data_size; + + status = decode_picture (decoder, packet.data + packet.offset, packet.size); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + /* decode slice + * A resync marker shall only be located immediately before a macroblock + * (or video packet header if exists) and aligned with a byte + * either start_code or resync_marker are scaned/measured by byte, + * while the header itself are parsed/measured in bit + * it means: resync_marker(video_packet_header) start from byte boundary, + * while MB doesn't start from byte boundary -- it is what 'macroblock_offset' + * in slice refer to + */ + _data = packet.data + packet.offset + priv->vop_hdr.size / 8; + _data_size = packet.size - (priv->vop_hdr.size / 8); + + if (priv->vol_hdr.resync_marker_disable) { + status = decode_slice (decoder, _data, _data_size, FALSE); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + } else { + GstMpeg4ParseResult ret = GST_MPEG4_PARSER_OK; + gboolean first_slice = TRUE; + + // next start_code is required to determine the end of last slice + _data_size += 4; + + while (_data_size > 0) { + // we can skip user data here + ret = + gst_mpeg4_parse (&video_packet, TRUE, &priv->vop_hdr, _data, 0, + _data_size); + if (ret != GST_MPEG4_PARSER_OK) { + break; + } + + if (first_slice) { + status = decode_slice (decoder, _data, video_packet.size, FALSE); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + first_slice = FALSE; + } else { + _data += video_packet.offset; + _data_size -= video_packet.offset; + + ret = + gst_mpeg4_parse_video_packet_header (&priv->packet_hdr, + &priv->vol_hdr, &priv->vop_hdr, &priv->sprite_trajectory, _data, + _data_size); + if (ret != GST_MPEG4_PARSER_OK) + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + status = + decode_slice (decoder, _data + priv->packet_hdr.size / 8, + video_packet.size - priv->packet_hdr.size / 8, TRUE); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + } + + _data += video_packet.size; + _data_size -= video_packet.size; + } + } + status = decode_current_picture (decoder); + } else if (tos->type == GST_MPEG4_USER_DATA + || tos->type == GST_MPEG4_VIDEO_SESSION_ERR + || tos->type == GST_MPEG4_FBA + || tos->type == GST_MPEG4_FBA_PLAN + || tos->type == GST_MPEG4_MESH + || tos->type == GST_MPEG4_MESH_PLAN + || tos->type == GST_MPEG4_STILL_TEXTURE_OBJ + || tos->type == GST_MPEG4_TEXTURE_SPATIAL + || tos->type == GST_MPEG4_TEXTURE_SNR_LAYER + || tos->type == GST_MPEG4_TEXTURE_TILE + || tos->type == GST_MPEG4_SHAPE_LAYER + || tos->type == GST_MPEG4_STUFFING + || tos->type == GST_MPEG4_SYSTEM_FIRST + || tos->type == GST_MPEG4_SYSTEM_LAST) { + GST_WARNING ("Ignore marker: %x\n", tos->type); + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + } else { + GST_ERROR ("unsupported start code %x\n", tos->type); + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + } + + return status; +} + +static GstVaapiDecoderStatus +decode_buffer (GstVaapiDecoderMpeg4 * decoder, const guchar * buf, + guint buf_size) +{ + GstVaapiDecoderMpeg4Private *const priv = &decoder->priv; + GstVaapiDecoderStatus status; + GstMpeg4Packet packet; + guint ofs; + + if (priv->is_svh) { + status = decode_picture (decoder, buf, buf_size); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + ofs = priv->svh_hdr.size / 8; + status = decode_slice (decoder, buf + ofs, buf_size - ofs, FALSE); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + } else { + packet.data = buf; + packet.offset = 0; + packet.size = buf_size; + packet.type = (GstMpeg4StartCode) packet.data[0]; + + status = decode_packet (decoder, packet); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_mpeg4_decode_codec_data (GstVaapiDecoder * base_decoder, + const guchar * _buf, guint _buf_size) +{ + GstVaapiDecoderMpeg4 *const decoder = + GST_VAAPI_DECODER_MPEG4_CAST (base_decoder); + GstVaapiDecoderStatus status = GST_VAAPI_DECODER_STATUS_SUCCESS; + GstMpeg4ParseResult result = GST_MPEG4_PARSER_OK; + GstMpeg4Packet packet; + guchar *buf; + guint pos, buf_size; + + // add additional 0x000001b2 to enclose the last header + buf_size = _buf_size + 4; + buf = malloc (buf_size); + memcpy (buf, _buf, buf_size); + buf[buf_size - 4] = 0; + buf[buf_size - 3] = 0; + buf[buf_size - 2] = 1; + buf[buf_size - 1] = 0xb2; + + pos = 0; + + while (result == GST_MPEG4_PARSER_OK && pos < buf_size) { + result = gst_mpeg4_parse (&packet, FALSE, NULL, buf, pos, buf_size); + if (result != GST_MPEG4_PARSER_OK) { + break; + } + status = decode_packet (decoder, packet); + if (GST_VAAPI_DECODER_STATUS_SUCCESS == status) { + pos = packet.offset + packet.size; + } else { + GST_WARNING ("decode mp4 packet failed when decoding codec data\n"); + break; + } + } + free (buf); + return status; +} + +static GstVaapiDecoderStatus +ensure_decoder (GstVaapiDecoderMpeg4 * decoder) +{ + GstVaapiDecoderMpeg4Private *const priv = &decoder->priv; + GstVaapiDecoderStatus status; + + if (!priv->is_opened) { + priv->is_opened = gst_vaapi_decoder_mpeg4_open (decoder); + if (!priv->is_opened) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC; + + status = + gst_vaapi_decoder_decode_codec_data (GST_VAAPI_DECODER_CAST (decoder)); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_mpeg4_parse (GstVaapiDecoder * base_decoder, + GstAdapter * adapter, gboolean at_eos, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderMpeg4 *const decoder = + GST_VAAPI_DECODER_MPEG4_CAST (base_decoder); + GstVaapiDecoderMpeg4Private *const priv = &decoder->priv; + GstVaapiDecoderStatus status; + GstMpeg4Packet packet; + GstMpeg4ParseResult result; + const guchar *buf; + guint size, buf_size, flags = 0; + + status = ensure_decoder (decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + size = gst_adapter_available (adapter); + buf = gst_adapter_map (adapter, size); + if (!buf) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + + packet.type = GST_MPEG4_USER_DATA; + if (priv->is_svh) + result = gst_h263_parse (&packet, buf, 0, size); + else + result = gst_mpeg4_parse (&packet, FALSE, NULL, buf, 0, size); + if (result == GST_MPEG4_PARSER_NO_PACKET_END && at_eos) + packet.size = size - packet.offset; + else if (result == GST_MPEG4_PARSER_ERROR) + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + else if (result != GST_MPEG4_PARSER_OK) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + + buf_size = packet.size; + gst_adapter_flush (adapter, packet.offset); + unit->size = buf_size; + + /* Check for start of new picture */ + switch (packet.type) { + case GST_MPEG4_VIDEO_SESSION_ERR: + case GST_MPEG4_FBA: + case GST_MPEG4_FBA_PLAN: + case GST_MPEG4_MESH: + case GST_MPEG4_MESH_PLAN: + case GST_MPEG4_STILL_TEXTURE_OBJ: + case GST_MPEG4_TEXTURE_SPATIAL: + case GST_MPEG4_TEXTURE_SNR_LAYER: + case GST_MPEG4_TEXTURE_TILE: + case GST_MPEG4_SHAPE_LAYER: + case GST_MPEG4_STUFFING: + gst_adapter_flush (adapter, packet.size); + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + case GST_MPEG4_USER_DATA: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP; + break; + case GST_MPEG4_VISUAL_OBJ_SEQ_END: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END; + flags |= GST_VAAPI_DECODER_UNIT_FLAG_STREAM_END; + break; + case GST_MPEG4_VIDEO_OBJ_PLANE: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE; + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END; + /* fall-through */ + case GST_MPEG4_VISUAL_OBJ_SEQ_START: + case GST_MPEG4_VISUAL_OBJ: + case GST_MPEG4_GROUP_OF_VOP: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START; + break; + default: + if (packet.type >= GST_MPEG4_VIDEO_OBJ_FIRST && + packet.type <= GST_MPEG4_VIDEO_OBJ_LAST) { + gst_adapter_flush (adapter, packet.size); + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + } + if (packet.type >= GST_MPEG4_VIDEO_LAYER_FIRST && + packet.type <= GST_MPEG4_VIDEO_LAYER_LAST) { + break; + } + if (packet.type >= GST_MPEG4_SYSTEM_FIRST && + packet.type <= GST_MPEG4_SYSTEM_LAST) { + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP; + break; + } + GST_WARNING ("unsupported start code (0x%02x)", packet.type); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + GST_VAAPI_DECODER_UNIT_FLAG_SET (unit, flags); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_mpeg4_decode (GstVaapiDecoder * base_decoder, + GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderMpeg4 *const decoder = + GST_VAAPI_DECODER_MPEG4_CAST (base_decoder); + GstVaapiDecoderStatus status; + GstBuffer *const buffer = + GST_VAAPI_DECODER_CODEC_FRAME (decoder)->input_buffer; + GstMapInfo map_info; + + status = ensure_decoder (decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) { + GST_ERROR ("failed to map buffer"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + status = decode_buffer (decoder, map_info.data + unit->offset, unit->size); + gst_buffer_unmap (buffer, &map_info); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static void +gst_vaapi_decoder_mpeg4_finalize (GObject * object) +{ + GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (object); + + gst_vaapi_decoder_mpeg4_destroy (base_decoder); + G_OBJECT_CLASS (gst_vaapi_decoder_mpeg4_parent_class)->finalize (object); +} + +static void +gst_vaapi_decoder_mpeg4_class_init (GstVaapiDecoderMpeg4Class * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstVaapiDecoderClass *const decoder_class = GST_VAAPI_DECODER_CLASS (klass); + + object_class->finalize = gst_vaapi_decoder_mpeg4_finalize; + + decoder_class->reset = gst_vaapi_decoder_mpeg4_reset; + decoder_class->parse = gst_vaapi_decoder_mpeg4_parse; + decoder_class->decode = gst_vaapi_decoder_mpeg4_decode; + decoder_class->decode_codec_data = gst_vaapi_decoder_mpeg4_decode_codec_data; +} + +static void +gst_vaapi_decoder_mpeg4_init (GstVaapiDecoderMpeg4 * decoder) +{ + GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (decoder); + + gst_vaapi_decoder_mpeg4_create (base_decoder); +} + +/** + * gst_vaapi_decoder_mpeg4_new: + * @display: a #GstVaapiDisplay + * @caps: a #GstCaps holding codec information + * + * Creates a new #GstVaapiDecoder for MPEG-2 decoding. The @caps can + * hold extra information like codec-data and pictured coded size. + * + * Return value: the newly allocated #GstVaapiDecoder object + */ +GstVaapiDecoder * +gst_vaapi_decoder_mpeg4_new (GstVaapiDisplay * display, GstCaps * caps) +{ + return g_object_new (GST_TYPE_VAAPI_DECODER_MPEG4, "display", display, + "caps", caps, NULL); +} diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.h b/gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.h new file mode 100644 index 0000000000..2efd164e0f --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.h @@ -0,0 +1,49 @@ +/* + * gstvaapidecoder_mpeg4.h - MPEG-4 decoder + * + * Copyright (C) 2011-2013 Intel Corporation + * Author: Halley Zhao + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODER_MPEG4_H +#define GST_VAAPI_DECODER_MPEG4_H + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_DECODER_MPEG4 \ + (gst_vaapi_decoder_mpeg4_get_type ()) +#define GST_VAAPI_DECODER_MPEG4(decoder) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DECODER_MPEG4, GstVaapiDecoderMpeg4)) +#define GST_VAAPI_IS_DECODER_MPEG4(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_DECODER_MPEG4)) + +typedef struct _GstVaapiDecoderMpeg4 GstVaapiDecoderMpeg4; + +GType +gst_vaapi_decoder_mpeg4_get_type (void) G_GNUC_CONST; + +GstVaapiDecoder * +gst_vaapi_decoder_mpeg4_new (GstVaapiDisplay *display, GstCaps *caps); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDecoderMpeg4, gst_object_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_DECODER_MPEG4_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_objects.c b/gst-libs/gst/vaapi/gstvaapidecoder_objects.c new file mode 100644 index 0000000000..159625f8c2 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_objects.c @@ -0,0 +1,507 @@ +/* + * gstvaapidecoder_objects.c - VA decoder objects helpers + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include +#include "gstvaapidecoder_objects.h" +#include "gstvaapidecoder_priv.h" +#include "gstvaapisurfaceproxy_priv.h" +#include "gstvaapicompat.h" +#include "gstvaapiutils.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +#define GET_DECODER(obj) GST_VAAPI_DECODER_CAST((obj)->parent_instance.codec) +#define GET_CONTEXT(obj) GET_DECODER(obj)->context +#define GET_VA_DISPLAY(obj) GET_DECODER(obj)->va_display +#define GET_VA_CONTEXT(obj) GET_DECODER(obj)->va_context + +static inline void +gst_video_codec_frame_clear (GstVideoCodecFrame ** frame_ptr) +{ + if (!*frame_ptr) + return; + gst_video_codec_frame_unref (*frame_ptr); + *frame_ptr = NULL; +} + +/* ------------------------------------------------------------------------- */ +/* --- Pictures --- */ +/* ------------------------------------------------------------------------- */ + +GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiPicture, gst_vaapi_picture); + +enum +{ + GST_VAAPI_CREATE_PICTURE_FLAG_CLONE = 1 << 0, + GST_VAAPI_CREATE_PICTURE_FLAG_FIELD = 1 << 1, +}; + +void +gst_vaapi_picture_destroy (GstVaapiPicture * picture) +{ + if (picture->slices) { + g_ptr_array_unref (picture->slices); + picture->slices = NULL; + } + + gst_vaapi_codec_object_replace (&picture->iq_matrix, NULL); + gst_vaapi_codec_object_replace (&picture->huf_table, NULL); + gst_vaapi_codec_object_replace (&picture->bitplane, NULL); + gst_vaapi_codec_object_replace (&picture->prob_table, NULL); + + if (picture->proxy) { + gst_vaapi_surface_proxy_unref (picture->proxy); + picture->proxy = NULL; + } + picture->surface_id = VA_INVALID_ID; + picture->surface = NULL; + + vaapi_destroy_buffer (GET_VA_DISPLAY (picture), &picture->param_id); + picture->param = NULL; + + gst_video_codec_frame_clear (&picture->frame); + gst_vaapi_picture_replace (&picture->parent_picture, NULL); +} + +gboolean +gst_vaapi_picture_create (GstVaapiPicture * picture, + const GstVaapiCodecObjectConstructorArgs * args) +{ + gboolean success; + + picture->param_id = VA_INVALID_ID; + + if (args->flags & GST_VAAPI_CREATE_PICTURE_FLAG_CLONE) { + GstVaapiPicture *const parent_picture = GST_VAAPI_PICTURE (args->data); + + picture->parent_picture = gst_vaapi_picture_ref (parent_picture); + + picture->proxy = gst_vaapi_surface_proxy_ref (parent_picture->proxy); + picture->type = parent_picture->type; + picture->pts = parent_picture->pts; + picture->poc = parent_picture->poc; + picture->voc = parent_picture->voc; + picture->view_id = parent_picture->view_id; + + // Copy all picture flags but "output" + GST_VAAPI_PICTURE_FLAG_SET (picture, + GST_VAAPI_PICTURE_FLAGS (parent_picture) & + (GST_VAAPI_PICTURE_FLAG_SKIPPED | + GST_VAAPI_PICTURE_FLAG_REFERENCE | + GST_VAAPI_PICTURE_FLAG_INTERLACED | + GST_VAAPI_PICTURE_FLAG_FF | GST_VAAPI_PICTURE_FLAG_TFF | + GST_VAAPI_PICTURE_FLAG_ONEFIELD | + GST_VAAPI_PICTURE_FLAG_RFF | GST_VAAPI_PICTURE_FLAG_MVC)); + + // Propagate "corrupted" flag while not presuming that the second + // field is itself corrupted if the first one was marked as such + if (GST_VAAPI_PICTURE_IS_CORRUPTED (parent_picture) && + !(args->flags & GST_VAAPI_CREATE_PICTURE_FLAG_FIELD)) + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_CORRUPTED); + + picture->structure = parent_picture->structure; + if ((args->flags & GST_VAAPI_CREATE_PICTURE_FLAG_FIELD) && + GST_VAAPI_PICTURE_IS_INTERLACED (picture)) { + switch (picture->structure) { + case GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD: + picture->structure = GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD; + break; + case GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD: + picture->structure = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD; + break; + } + GST_VAAPI_PICTURE_FLAG_UNSET (picture, GST_VAAPI_PICTURE_FLAG_FF); + } + + if (parent_picture->has_crop_rect) { + picture->has_crop_rect = TRUE; + picture->crop_rect = parent_picture->crop_rect; + } + } else { + picture->type = GST_VAAPI_PICTURE_TYPE_NONE; + picture->pts = GST_CLOCK_TIME_NONE; + + picture->proxy = + gst_vaapi_context_get_surface_proxy (GET_CONTEXT (picture)); + if (!picture->proxy) + return FALSE; + + picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME; + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_FF); + } + picture->surface = GST_VAAPI_SURFACE_PROXY_SURFACE (picture->proxy); + picture->surface_id = GST_VAAPI_SURFACE_PROXY_SURFACE_ID (picture->proxy); + + success = vaapi_create_buffer (GET_VA_DISPLAY (picture), + GET_VA_CONTEXT (picture), VAPictureParameterBufferType, + args->param_size, args->param, &picture->param_id, &picture->param); + if (!success) + return FALSE; + picture->param_size = args->param_size; + + picture->slices = g_ptr_array_new_with_free_func ((GDestroyNotify) + gst_vaapi_mini_object_unref); + if (!picture->slices) + return FALSE; + + picture->frame = + gst_video_codec_frame_ref (GST_VAAPI_DECODER_CODEC_FRAME (GET_DECODER + (picture))); + return TRUE; +} + +GstVaapiPicture * +gst_vaapi_picture_new (GstVaapiDecoder * decoder, + gconstpointer param, guint param_size) +{ + GstVaapiCodecObject *object; + + object = gst_vaapi_codec_object_new (&GstVaapiPictureClass, + GST_VAAPI_CODEC_BASE (decoder), param, param_size, NULL, 0, 0); + if (!object) + return NULL; + return GST_VAAPI_PICTURE_CAST (object); +} + +GstVaapiPicture * +gst_vaapi_picture_new_field (GstVaapiPicture * picture) +{ + GstVaapiDecoder *const decoder = GET_DECODER (picture); + GstVaapiCodecObject *object; + + object = gst_vaapi_codec_object_new (gst_vaapi_codec_object_get_class + (&picture->parent_instance), GST_VAAPI_CODEC_BASE (decoder), NULL, + picture->param_size, picture, 0, + (GST_VAAPI_CREATE_PICTURE_FLAG_CLONE | + GST_VAAPI_CREATE_PICTURE_FLAG_FIELD)); + if (!object) + return NULL; + return GST_VAAPI_PICTURE_CAST (object); +} + +GstVaapiPicture * +gst_vaapi_picture_new_clone (GstVaapiPicture * picture) +{ + GstVaapiDecoder *const decoder = GET_DECODER (picture); + GstVaapiCodecObject *object; + + object = gst_vaapi_codec_object_new (gst_vaapi_codec_object_get_class + (&picture->parent_instance), GST_VAAPI_CODEC_BASE (decoder), NULL, + picture->param_size, picture, 0, GST_VAAPI_CREATE_PICTURE_FLAG_CLONE); + if (!object) + return NULL; + return GST_VAAPI_PICTURE_CAST (object); +} + +void +gst_vaapi_picture_add_slice (GstVaapiPicture * picture, GstVaapiSlice * slice) +{ + g_return_if_fail (GST_VAAPI_IS_PICTURE (picture)); + g_return_if_fail (GST_VAAPI_IS_SLICE (slice)); + + g_ptr_array_add (picture->slices, slice); +} + +static gboolean +do_decode (VADisplay dpy, VAContextID ctx, VABufferID * buf_id, void **buf_ptr) +{ + VAStatus status; + + vaapi_unmap_buffer (dpy, *buf_id, buf_ptr); + + status = vaRenderPicture (dpy, ctx, buf_id, 1); + if (!vaapi_check_status (status, "vaRenderPicture()")) + return FALSE; + + /* XXX: vaRenderPicture() is meant to destroy the VA buffer implicitly */ + vaapi_destroy_buffer (dpy, buf_id); + return TRUE; +} + +gboolean +gst_vaapi_picture_decode_with_surface_id (GstVaapiPicture * picture, + VASurfaceID surface_id) +{ + GstVaapiIqMatrix *iq_matrix; + GstVaapiBitPlane *bitplane; + GstVaapiHuffmanTable *huf_table; + GstVaapiProbabilityTable *prob_table; + VADisplay va_display; + VAContextID va_context; + VAStatus status; + guint i; + + g_return_val_if_fail (GST_VAAPI_IS_PICTURE (picture), FALSE); + g_return_val_if_fail (surface_id != VA_INVALID_SURFACE, FALSE); + + va_display = GET_VA_DISPLAY (picture); + va_context = GET_VA_CONTEXT (picture); + + GST_DEBUG ("decode picture 0x%08x", surface_id); + + status = vaBeginPicture (va_display, va_context, surface_id); + if (!vaapi_check_status (status, "vaBeginPicture()")) + return FALSE; + + if (!do_decode (va_display, va_context, &picture->param_id, &picture->param)) + return FALSE; + + iq_matrix = picture->iq_matrix; + if (iq_matrix && !do_decode (va_display, va_context, + &iq_matrix->param_id, &iq_matrix->param)) + return FALSE; + + bitplane = picture->bitplane; + if (bitplane && !do_decode (va_display, va_context, + &bitplane->data_id, (void **) &bitplane->data)) + return FALSE; + + huf_table = picture->huf_table; + if (huf_table && !do_decode (va_display, va_context, + &huf_table->param_id, (void **) &huf_table->param)) + return FALSE; + + prob_table = picture->prob_table; + if (prob_table && !do_decode (va_display, va_context, + &prob_table->param_id, (void **) &prob_table->param)) + return FALSE; + + for (i = 0; i < picture->slices->len; i++) { + GstVaapiSlice *const slice = g_ptr_array_index (picture->slices, i); + VABufferID va_buffers[2]; + + huf_table = slice->huf_table; + if (huf_table && !do_decode (va_display, va_context, + &huf_table->param_id, (void **) &huf_table->param)) + return FALSE; + + vaapi_unmap_buffer (va_display, slice->param_id, NULL); + va_buffers[0] = slice->param_id; + va_buffers[1] = slice->data_id; + + status = vaRenderPicture (va_display, va_context, va_buffers, 2); + if (!vaapi_check_status (status, "vaRenderPicture()")) + return FALSE; + } + + status = vaEndPicture (va_display, va_context); + + for (i = 0; i < picture->slices->len; i++) { + GstVaapiSlice *const slice = g_ptr_array_index (picture->slices, i); + + vaapi_destroy_buffer (va_display, &slice->param_id); + vaapi_destroy_buffer (va_display, &slice->data_id); + } + + if (!vaapi_check_status (status, "vaEndPicture()")) + return FALSE; + return TRUE; +} + +gboolean +gst_vaapi_picture_decode (GstVaapiPicture * picture) +{ + g_return_val_if_fail (GST_VAAPI_IS_PICTURE (picture), FALSE); + + return gst_vaapi_picture_decode_with_surface_id (picture, + picture->surface_id); +} + +/* Mark picture as output for internal purposes only. Don't push frame out */ +static void +do_output_internal (GstVaapiPicture * picture) +{ + if (GST_VAAPI_PICTURE_IS_OUTPUT (picture)) + return; + + gst_video_codec_frame_clear (&picture->frame); + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_OUTPUT); +} + +static gboolean +do_output (GstVaapiPicture * picture) +{ + GstVideoCodecFrame *const out_frame = picture->frame; + GstVaapiSurfaceProxy *proxy; + guint flags = 0; + + if (GST_VAAPI_PICTURE_IS_OUTPUT (picture)) + return TRUE; + + if (!picture->proxy) + return FALSE; + + proxy = gst_vaapi_surface_proxy_ref (picture->proxy); + + if (picture->has_crop_rect) + gst_vaapi_surface_proxy_set_crop_rect (proxy, &picture->crop_rect); + + gst_video_codec_frame_set_user_data (out_frame, + proxy, (GDestroyNotify) gst_vaapi_mini_object_unref); + + out_frame->pts = picture->pts; + + if (GST_VAAPI_PICTURE_IS_SKIPPED (picture)) + GST_VIDEO_CODEC_FRAME_FLAG_SET (out_frame, + GST_VIDEO_CODEC_FRAME_FLAG_DECODE_ONLY); + + if (GST_VAAPI_PICTURE_IS_CORRUPTED (picture)) + flags |= GST_VAAPI_SURFACE_PROXY_FLAG_CORRUPTED; + + if (GST_VAAPI_PICTURE_IS_MVC (picture)) { + if (picture->voc == 0) + flags |= GST_VAAPI_SURFACE_PROXY_FLAG_FFB; + GST_VAAPI_SURFACE_PROXY_VIEW_ID (proxy) = picture->view_id; + } + + if (GST_VAAPI_PICTURE_IS_INTERLACED (picture)) { + flags |= GST_VAAPI_SURFACE_PROXY_FLAG_INTERLACED; + if (GST_VAAPI_PICTURE_IS_TFF (picture)) + flags |= GST_VAAPI_SURFACE_PROXY_FLAG_TFF; + if (GST_VAAPI_PICTURE_IS_RFF (picture)) + flags |= GST_VAAPI_SURFACE_PROXY_FLAG_RFF; + if (GST_VAAPI_PICTURE_IS_ONEFIELD (picture)) + flags |= GST_VAAPI_SURFACE_PROXY_FLAG_ONEFIELD; + } + GST_VAAPI_SURFACE_PROXY_FLAG_SET (proxy, flags); + + gst_vaapi_decoder_push_frame (GET_DECODER (picture), out_frame); + gst_video_codec_frame_clear (&picture->frame); + + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_OUTPUT); + return TRUE; +} + +gboolean +gst_vaapi_picture_output (GstVaapiPicture * picture) +{ + g_return_val_if_fail (GST_VAAPI_IS_PICTURE (picture), FALSE); + + if (G_UNLIKELY (picture->parent_picture)) { + /* Emit the first field to GstVideoDecoder so that to release + the underlying GstVideoCodecFrame. However, mark this + picture as skipped so that to not display it */ + GstVaapiPicture *const parent_picture = picture->parent_picture; + do { + if (!GST_VAAPI_PICTURE_IS_INTERLACED (parent_picture)) + break; + if (!GST_VAAPI_PICTURE_IS_FIRST_FIELD (parent_picture)) + break; + if (parent_picture->frame == picture->frame) + do_output_internal (parent_picture); + else { + GST_VAAPI_PICTURE_FLAG_SET (parent_picture, + GST_VAAPI_PICTURE_FLAG_SKIPPED); + if (!do_output (parent_picture)) + return FALSE; + } + } while (0); + } + return do_output (picture); +} + +void +gst_vaapi_picture_set_crop_rect (GstVaapiPicture * picture, + const GstVaapiRectangle * crop_rect) +{ + g_return_if_fail (GST_VAAPI_IS_PICTURE (picture)); + + picture->has_crop_rect = crop_rect != NULL; + if (picture->has_crop_rect) + picture->crop_rect = *crop_rect; +} + +/* ------------------------------------------------------------------------- */ +/* --- Slices --- */ +/* ------------------------------------------------------------------------- */ + +GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiSlice, gst_vaapi_slice); + +void +gst_vaapi_slice_destroy (GstVaapiSlice * slice) +{ + VADisplay const va_display = GET_VA_DISPLAY (slice); + + gst_vaapi_codec_object_replace (&slice->huf_table, NULL); + + vaapi_destroy_buffer (va_display, &slice->data_id); + vaapi_destroy_buffer (va_display, &slice->param_id); + slice->param = NULL; +} + +gboolean +gst_vaapi_slice_create (GstVaapiSlice * slice, + const GstVaapiCodecObjectConstructorArgs * args) +{ + VASliceParameterBufferBase *slice_param; + gboolean success; + + slice->param_id = VA_INVALID_ID; + slice->data_id = VA_INVALID_ID; + + success = vaapi_create_buffer (GET_VA_DISPLAY (slice), GET_VA_CONTEXT (slice), + VASliceDataBufferType, args->data_size, args->data, &slice->data_id, + NULL); + if (!success) + return FALSE; + + g_assert (args->param_num >= 1); + success = vaapi_create_n_elements_buffer (GET_VA_DISPLAY (slice), + GET_VA_CONTEXT (slice), VASliceParameterBufferType, args->param_size, + args->param, &slice->param_id, &slice->param, args->param_num); + if (!success) + return FALSE; + + slice_param = slice->param; + slice_param->slice_data_size = args->data_size; + slice_param->slice_data_offset = 0; + slice_param->slice_data_flag = VA_SLICE_DATA_FLAG_ALL; + return TRUE; +} + +GstVaapiSlice * +gst_vaapi_slice_new (GstVaapiDecoder * decoder, + gconstpointer param, guint param_size, const guchar * data, guint data_size) +{ + GstVaapiCodecObject *object; + + object = gst_vaapi_codec_object_new (&GstVaapiSliceClass, + GST_VAAPI_CODEC_BASE (decoder), param, param_size, data, data_size, 0); + return GST_VAAPI_SLICE_CAST (object); +} + +GstVaapiSlice * +gst_vaapi_slice_new_n_params (GstVaapiDecoder * decoder, + gconstpointer param, guint param_size, guint param_num, const guchar * data, + guint data_size) +{ + GstVaapiCodecObject *object; + + object = gst_vaapi_codec_object_new_with_param_num (&GstVaapiSliceClass, + GST_VAAPI_CODEC_BASE (decoder), param, param_size, param_num, data, + data_size, 0); + return GST_VAAPI_SLICE_CAST (object); +} diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_objects.h b/gst-libs/gst/vaapi/gstvaapidecoder_objects.h new file mode 100644 index 0000000000..cc301d17e4 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_objects.h @@ -0,0 +1,294 @@ +/* + * gstvaapidecoder_objects.h - VA decoder objects + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODER_OBJECTS_H +#define GST_VAAPI_DECODER_OBJECTS_H + +#include + +G_BEGIN_DECLS + +typedef struct _GstVaapiPicture GstVaapiPicture; +typedef struct _GstVaapiSlice GstVaapiSlice; + +/* ------------------------------------------------------------------------- */ +/* --- Pictures --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_PICTURE_CAST(obj) \ + ((GstVaapiPicture *) (obj)) + +#define GST_VAAPI_PICTURE(obj) \ + GST_VAAPI_PICTURE_CAST (obj) + +#define GST_VAAPI_IS_PICTURE(obj) \ + (GST_VAAPI_PICTURE (obj) != NULL) + +typedef enum +{ + GST_VAAPI_PICTURE_TYPE_NONE = 0, // Undefined + GST_VAAPI_PICTURE_TYPE_I, // Intra + GST_VAAPI_PICTURE_TYPE_P, // Predicted + GST_VAAPI_PICTURE_TYPE_B, // Bi-directional predicted + GST_VAAPI_PICTURE_TYPE_S, // S(GMC)-VOP (MPEG-4) + GST_VAAPI_PICTURE_TYPE_SI, // Switching Intra + GST_VAAPI_PICTURE_TYPE_SP, // Switching Predicted + GST_VAAPI_PICTURE_TYPE_BI, // BI type (VC-1) +} GstVaapiPictureType; + +/** + * GstVaapiPictureFlags: + * @GST_VAAPI_PICTURE_FLAG_SKIPPED: skipped frame + * @GST_VAAPI_PICTURE_FLAG_REFERENCE: reference frame + * @GST_VAAPI_PICTURE_FLAG_OUTPUT: frame was output + * @GST_VAAPI_PICTURE_FLAG_INTERLACED: interlaced frame + * @GST_VAAPI_PICTURE_FLAG_FF: first-field + * @GST_VAAPI_PICTURE_FLAG_TFF: top-field-first + * @GST_VAAPI_PICTURE_FLAG_ONEFIELD: only one field is valid + * @GST_VAAPI_PICTURE_FLAG_MVC: multiview component + * @GST_VAAPI_PICTURE_FLAG_RFF: repeat-first-field + * @GST_VAAPI_PICTURE_FLAG_CORRUPTED: picture was reconstructed from + * corrupted references + * @GST_VAAPI_PICTURE_FLAG_LAST: first flag that can be used by subclasses + * + * Enum values used for #GstVaapiPicture flags. + */ +typedef enum +{ + GST_VAAPI_PICTURE_FLAG_SKIPPED = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 0), + GST_VAAPI_PICTURE_FLAG_REFERENCE = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 1), + GST_VAAPI_PICTURE_FLAG_OUTPUT = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 2), + GST_VAAPI_PICTURE_FLAG_INTERLACED = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 3), + GST_VAAPI_PICTURE_FLAG_FF = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 4), + GST_VAAPI_PICTURE_FLAG_TFF = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 5), + GST_VAAPI_PICTURE_FLAG_ONEFIELD = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 6), + GST_VAAPI_PICTURE_FLAG_MVC = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 7), + GST_VAAPI_PICTURE_FLAG_RFF = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 8), + GST_VAAPI_PICTURE_FLAG_CORRUPTED = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 9), + GST_VAAPI_PICTURE_FLAG_LAST = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 10), +} GstVaapiPictureFlags; + +#define GST_VAAPI_PICTURE_FLAGS GST_VAAPI_MINI_OBJECT_FLAGS +#define GST_VAAPI_PICTURE_FLAG_IS_SET GST_VAAPI_MINI_OBJECT_FLAG_IS_SET +#define GST_VAAPI_PICTURE_FLAG_SET GST_VAAPI_MINI_OBJECT_FLAG_SET +#define GST_VAAPI_PICTURE_FLAG_UNSET GST_VAAPI_MINI_OBJECT_FLAG_UNSET + +#define GST_VAAPI_PICTURE_IS_SKIPPED(picture) \ + GST_VAAPI_PICTURE_FLAG_IS_SET (picture, GST_VAAPI_PICTURE_FLAG_SKIPPED) + +#define GST_VAAPI_PICTURE_IS_REFERENCE(picture) \ + GST_VAAPI_PICTURE_FLAG_IS_SET (picture, GST_VAAPI_PICTURE_FLAG_REFERENCE) + +#define GST_VAAPI_PICTURE_IS_OUTPUT(picture) \ + GST_VAAPI_PICTURE_FLAG_IS_SET (picture, GST_VAAPI_PICTURE_FLAG_OUTPUT) + +#define GST_VAAPI_PICTURE_IS_INTERLACED(picture) \ + GST_VAAPI_PICTURE_FLAG_IS_SET (picture, GST_VAAPI_PICTURE_FLAG_INTERLACED) + +#define GST_VAAPI_PICTURE_IS_FIRST_FIELD(picture) \ + GST_VAAPI_PICTURE_FLAG_IS_SET (picture, GST_VAAPI_PICTURE_FLAG_FF) + +#define GST_VAAPI_PICTURE_IS_TFF(picture) \ + GST_VAAPI_PICTURE_FLAG_IS_SET (picture, GST_VAAPI_PICTURE_FLAG_TFF) + +#define GST_VAAPI_PICTURE_IS_RFF(picture) \ + GST_VAAPI_PICTURE_FLAG_IS_SET (picture, GST_VAAPI_PICTURE_FLAG_RFF) + +#define GST_VAAPI_PICTURE_IS_ONEFIELD(picture) \ + GST_VAAPI_PICTURE_FLAG_IS_SET (picture, GST_VAAPI_PICTURE_FLAG_ONEFIELD) + +#define GST_VAAPI_PICTURE_IS_FRAME(picture) \ + (GST_VAAPI_PICTURE (picture)->structure == GST_VAAPI_PICTURE_STRUCTURE_FRAME) + +#define GST_VAAPI_PICTURE_IS_COMPLETE(picture) \ + (GST_VAAPI_PICTURE_IS_FRAME (picture) || \ + GST_VAAPI_PICTURE_IS_ONEFIELD (picture) || \ + !GST_VAAPI_PICTURE_IS_FIRST_FIELD (picture)) + +#define GST_VAAPI_PICTURE_IS_MVC(picture) \ + (GST_VAAPI_PICTURE_FLAG_IS_SET (picture, GST_VAAPI_PICTURE_FLAG_MVC)) + +#define GST_VAAPI_PICTURE_IS_CORRUPTED(picture) \ + (GST_VAAPI_PICTURE_FLAG_IS_SET (picture, GST_VAAPI_PICTURE_FLAG_CORRUPTED)) + +/** + * GstVaapiPicture: + * + * A #GstVaapiCodecObject holding a picture parameter. + */ +struct _GstVaapiPicture +{ + /*< private >*/ + GstVaapiCodecObject parent_instance; + GstVaapiPicture *parent_picture; + GstVideoCodecFrame *frame; + GstVaapiSurface *surface; + GstVaapiSurfaceProxy *proxy; + VABufferID param_id; + guint param_size; + + /*< public >*/ + GstVaapiPictureType type; + VASurfaceID surface_id; + gpointer param; + GPtrArray *slices; + GstVaapiIqMatrix *iq_matrix; + GstVaapiHuffmanTable *huf_table; + GstVaapiBitPlane *bitplane; + GstVaapiProbabilityTable *prob_table; + GstClockTime pts; + gint32 poc; + guint16 voc; + guint16 view_id; + guint structure; + GstVaapiRectangle crop_rect; + guint has_crop_rect:1; +}; + +G_GNUC_INTERNAL +void +gst_vaapi_picture_destroy (GstVaapiPicture * picture); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_picture_create (GstVaapiPicture * picture, + const GstVaapiCodecObjectConstructorArgs * args); + +G_GNUC_INTERNAL +GstVaapiPicture * +gst_vaapi_picture_new (GstVaapiDecoder * decoder, + gconstpointer param, guint param_size); + +G_GNUC_INTERNAL +GstVaapiPicture * +gst_vaapi_picture_new_field (GstVaapiPicture * picture); + +G_GNUC_INTERNAL +GstVaapiPicture * +gst_vaapi_picture_new_clone (GstVaapiPicture * picture); + +G_GNUC_INTERNAL +void +gst_vaapi_picture_add_slice (GstVaapiPicture * picture, GstVaapiSlice * slice); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_picture_decode (GstVaapiPicture * picture); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_picture_decode_with_surface_id (GstVaapiPicture * picture, + VASurfaceID surface_id); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_picture_output (GstVaapiPicture * picture); + +G_GNUC_INTERNAL +void +gst_vaapi_picture_set_crop_rect (GstVaapiPicture * picture, + const GstVaapiRectangle * crop_rect); + +#define gst_vaapi_picture_ref(picture) \ + gst_vaapi_codec_object_ref (picture) + +#define gst_vaapi_picture_unref(picture) \ + gst_vaapi_codec_object_unref (picture) + +#define gst_vaapi_picture_replace(old_picture_ptr, new_picture) \ + gst_vaapi_codec_object_replace (old_picture_ptr, new_picture) + +/* ------------------------------------------------------------------------- */ +/* --- Slices --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_SLICE_CAST(obj) \ + ((GstVaapiSlice *) (obj)) + +#define GST_VAAPI_SLICE(obj) \ + GST_VAAPI_SLICE_CAST (obj) + +#define GST_VAAPI_IS_SLICE(obj) \ + (GST_VAAPI_SLICE (obj) != NULL) + +/** + * GstVaapiSlice: + * + * A #GstVaapiCodecObject holding a slice parameter. + */ +struct _GstVaapiSlice +{ + /*< private >*/ + GstVaapiCodecObject parent_instance; + + /*< public >*/ + VABufferID param_id; + VABufferID data_id; + gpointer param; + + /* Per-slice overrides */ + GstVaapiHuffmanTable *huf_table; +}; + +G_GNUC_INTERNAL +void +gst_vaapi_slice_destroy (GstVaapiSlice * slice); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_slice_create (GstVaapiSlice * slice, + const GstVaapiCodecObjectConstructorArgs * args); + +G_GNUC_INTERNAL +GstVaapiSlice * +gst_vaapi_slice_new (GstVaapiDecoder * decoder, gconstpointer param, + guint param_size, const guchar * data, guint data_size); + +G_GNUC_INTERNAL +GstVaapiSlice * +gst_vaapi_slice_new_n_params (GstVaapiDecoder * decoder, + gconstpointer param, guint param_size, guint param_num, const guchar * data, + guint data_size); + +/* ------------------------------------------------------------------------- */ +/* --- Helpers to create codec-dependent objects --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_PICTURE_NEW(codec, decoder) \ + gst_vaapi_picture_new (GST_VAAPI_DECODER_CAST (decoder), \ + NULL, sizeof (G_PASTE (VAPictureParameterBuffer, codec))) + +#define GST_VAAPI_SLICE_NEW(codec, decoder, buf, buf_size) \ + gst_vaapi_slice_new (GST_VAAPI_DECODER_CAST (decoder), \ + NULL, sizeof (G_PASTE (VASliceParameterBuffer, codec)), \ + buf, buf_size) + +#define GST_VAAPI_SLICE_NEW_N_PARAMS(codec, decoder, buf, buf_size, n) \ + gst_vaapi_slice_new_n_params (GST_VAAPI_DECODER_CAST (decoder), \ + NULL, sizeof (G_PASTE (VASliceParameterBuffer, codec)), n, \ + buf, buf_size) + +G_END_DECLS + +#endif /* GST_VAAPI_DECODER_OBJECTS_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_priv.h b/gst-libs/gst/vaapi/gstvaapidecoder_priv.h new file mode 100644 index 0000000000..10b8d2cf77 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_priv.h @@ -0,0 +1,275 @@ +/* + * gstvaapidecoder_priv.h - VA decoder abstraction (private definitions) + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODER_PRIV_H +#define GST_VAAPI_DECODER_PRIV_H + +#include "sysdeps.h" +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_DECODER_CAST(decoder) \ + ((GstVaapiDecoder *)(decoder)) + +#define GST_VAAPI_DECODER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPI_DECODER, GstVaapiDecoderClass)) + +#define GST_VAAPI_IS_DECODER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPI_DECODER)) + +#define GST_VAAPI_DECODER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_DECODER, GstVaapiDecoderClass)) + +typedef struct _GstVaapiDecoderClass GstVaapiDecoderClass; + +/** + * GST_VAAPI_PARSER_STATE: + * @decoder: a #GstVaapiDecoder + * + * Macro that evaluates to the #GstVaapiParserState of @decoder. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_PARSER_STATE +#define GST_VAAPI_PARSER_STATE(decoder) \ + (&GST_VAAPI_DECODER_CAST(decoder)->parser_state) + +/** + * GST_VAAPI_DECODER_DISPLAY: + * @decoder: a #GstVaapiDecoder + * + * Macro that evaluates to the #GstVaapiDisplay of @decoder. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_DECODER_DISPLAY +#define GST_VAAPI_DECODER_DISPLAY(decoder) \ + GST_VAAPI_DECODER_CAST(decoder)->display + +/** + * GST_VAAPI_DECODER_CONTEXT: + * @decoder: a #GstVaapiDecoder + * + * Macro that evaluates to the #GstVaapiContext of @decoder. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_DECODER_CONTEXT +#define GST_VAAPI_DECODER_CONTEXT(decoder) \ + GST_VAAPI_DECODER_CAST(decoder)->context + +/** + * GST_VAAPI_DECODER_CODEC: + * @decoder: a #GstVaapiDecoder + * + * Macro that evaluates to the #GstVaapiCodec of @decoder. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_DECODER_CODEC +#define GST_VAAPI_DECODER_CODEC(decoder) \ + GST_VAAPI_DECODER_CAST(decoder)->codec + +/** + * GST_VAAPI_DECODER_CODEC_STATE: + * @decoder: a #GstVaapiDecoder + * + * Macro that evaluates to the #GstVideoCodecState holding codec state + * for @decoder. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_DECODER_CODEC_STATE +#define GST_VAAPI_DECODER_CODEC_STATE(decoder) \ + GST_VAAPI_DECODER_CAST(decoder)->codec_state + +/** + * GST_VAAPI_DECODER_CODEC_DATA: + * @decoder: a #GstVaapiDecoder + * + * Macro that evaluates to the #GstBuffer holding optional codec data + * for @decoder. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_DECODER_CODEC_DATA +#define GST_VAAPI_DECODER_CODEC_DATA(decoder) \ + GST_VAAPI_DECODER_CODEC_STATE(decoder)->codec_data + +/** + * GST_VAAPI_DECODER_CODEC_FRAME: + * @decoder: a #GstVaapiDecoder + * + * Macro that evaluates to the #GstVideoCodecFrame holding decoder + * units for the current frame. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_DECODER_CODEC_FRAME +#define GST_VAAPI_DECODER_CODEC_FRAME(decoder) \ + GST_VAAPI_PARSER_STATE(decoder)->current_frame + +/** + * GST_VAAPI_DECODER_WIDTH: + * @decoder: a #GstVaapiDecoder + * + * Macro that evaluates to the coded width of the picture + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_DECODER_WIDTH +#define GST_VAAPI_DECODER_WIDTH(decoder) \ + GST_VAAPI_DECODER_CODEC_STATE(decoder)->info.width + +/** + * GST_VAAPI_DECODER_HEIGHT: + * @decoder: a #GstVaapiDecoder + * + * Macro that evaluates to the coded height of the picture + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_DECODER_HEIGHT +#define GST_VAAPI_DECODER_HEIGHT(decoder) \ + GST_VAAPI_DECODER_CODEC_STATE(decoder)->info.height + +/* End-of-Stream buffer */ +#define GST_BUFFER_FLAG_EOS (GST_BUFFER_FLAG_LAST + 0) + +#define GST_BUFFER_IS_EOS(buffer) \ + GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_EOS) + +#define GST_VAAPI_DECODER_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_DECODER, \ + GstVaapiDecoderPrivate)) + +typedef enum { + GST_VAAPI_DECODER_STATUS_DROP_FRAME = -2 +} GstVaapiDecoderStatusPrivate; + +typedef struct _GstVaapiParserState GstVaapiParserState; +struct _GstVaapiParserState +{ + GstVideoCodecFrame *current_frame; + guint32 current_frame_number; + GstAdapter *current_adapter; + GstAdapter *input_adapter; + gint input_offset1; + gint input_offset2; + GstAdapter *output_adapter; + GstVaapiDecoderUnit next_unit; + guint next_unit_pending:1; + guint at_eos:1; +}; + +/** + * GstVaapiDecoder: + * + * A VA decoder base instance. + */ +struct _GstVaapiDecoder +{ + /*< private >*/ + GstObject parent_instance; + + gpointer user_data; + GstVaapiDisplay *display; + VADisplay va_display; + GstVaapiContext *context; + VAContextID va_context; + GstVaapiCodec codec; + GstVideoCodecState *codec_state; + GAsyncQueue *buffers; + GAsyncQueue *frames; + GstVaapiParserState parser_state; + GstVaapiDecoderStateChangedFunc codec_state_changed_func; + gpointer codec_state_changed_data; +}; + +/** + * GstVaapiDecoderClass: + * + * A VA decoder base class. + */ +struct _GstVaapiDecoderClass +{ + /*< private >*/ + GstObjectClass parent_class; + + GstVaapiDecoderStatus (*parse) (GstVaapiDecoder * decoder, + GstAdapter * adapter, gboolean at_eos, + struct _GstVaapiDecoderUnit * unit); + GstVaapiDecoderStatus (*decode) (GstVaapiDecoder * decoder, + struct _GstVaapiDecoderUnit * unit); + GstVaapiDecoderStatus (*start_frame) (GstVaapiDecoder * decoder, + struct _GstVaapiDecoderUnit * unit); + GstVaapiDecoderStatus (*end_frame) (GstVaapiDecoder * decoder); + GstVaapiDecoderStatus (*flush) (GstVaapiDecoder * decoder); + GstVaapiDecoderStatus (*reset) (GstVaapiDecoder * decoder); + GstVaapiDecoderStatus (*decode_codec_data) (GstVaapiDecoder * decoder, + const guchar * buf, guint buf_size); +}; + +G_GNUC_INTERNAL +void +gst_vaapi_decoder_set_picture_size (GstVaapiDecoder * decoder, + guint width, guint height); + +G_GNUC_INTERNAL +void +gst_vaapi_decoder_set_framerate (GstVaapiDecoder * decoder, + guint fps_n, guint fps_d); + +G_GNUC_INTERNAL +void +gst_vaapi_decoder_set_pixel_aspect_ratio (GstVaapiDecoder * decoder, + guint par_n, guint par_d); + +G_GNUC_INTERNAL +void +gst_vaapi_decoder_set_interlace_mode (GstVaapiDecoder * decoder, + GstVideoInterlaceMode mode); + +G_GNUC_INTERNAL +void +gst_vaapi_decoder_set_interlaced (GstVaapiDecoder * decoder, + gboolean interlaced); + +G_GNUC_INTERNAL +void +gst_vaapi_decoder_set_multiview_mode (GstVaapiDecoder * decoder, + gint views, GstVideoMultiviewMode mv_mode, GstVideoMultiviewFlags mv_flags); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_decoder_ensure_context (GstVaapiDecoder * decoder, + GstVaapiContextInfo * cip); + +G_GNUC_INTERNAL +void +gst_vaapi_decoder_push_frame (GstVaapiDecoder * decoder, + GstVideoCodecFrame * frame); + +G_GNUC_INTERNAL +GstVaapiDecoderStatus +gst_vaapi_decoder_decode_codec_data (GstVaapiDecoder * decoder); + +G_END_DECLS + +#endif /* GST_VAAPI_DECODER_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_unit.c b/gst-libs/gst/vaapi/gstvaapidecoder_unit.c new file mode 100644 index 0000000000..fd08a83e31 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_unit.c @@ -0,0 +1,89 @@ +/* + * gstvaapidecoder_unit.c - VA decoder units + * + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapidecoder_unit + * @short_description: Decoder unit + */ + +#include "sysdeps.h" +#include "gstvaapidecoder_unit.h" + +/** + * gst_vaapi_decoder_unit_init: + * @unit: a #GstVaapiDecoderUnit + * + * Initializes internal resources bound to the supplied decoder @unit. + * + * @note This is an internal function used to implement lightweight + * sub-classes. + */ +void +gst_vaapi_decoder_unit_init (GstVaapiDecoderUnit * unit) +{ + unit->flags = 0; + unit->size = 0; + unit->offset = 0; + + unit->parsed_info = NULL; + unit->parsed_info_destroy_notify = NULL; +} + +/** + * gst_vaapi_decoder_unit_clear: + * @unit: a #GstVaapiDecoderUnit + * + * Deallocates any internal resources bound to the supplied decoder + * @unit. + * + * @note This is an internal function used to implement lightweight + * sub-classes. + */ +void +gst_vaapi_decoder_unit_clear (GstVaapiDecoderUnit * unit) +{ + gst_vaapi_decoder_unit_set_parsed_info (unit, NULL, NULL); +} + +/** + * gst_vaapi_decoder_unit_set_parsed_info: + * @unit: a #GstVaapiDecoderUnit + * @parsed_info: parser info + * @destroy_notify: (closure parsed_info): a #GDestroyNotify + * + * Sets @parsed_info on the object and the #GDestroyNotify that will be + * called when the data is freed. + * + * If some @parsed_info was previously set, then the former @destroy_notify + * function will be called before the @parsed_info is replaced. + */ +void +gst_vaapi_decoder_unit_set_parsed_info (GstVaapiDecoderUnit * unit, + gpointer parsed_info, GDestroyNotify destroy_notify) +{ + g_return_if_fail (GST_VAAPI_IS_DECODER_UNIT (unit)); + + if (unit->parsed_info && unit->parsed_info_destroy_notify) + unit->parsed_info_destroy_notify (unit->parsed_info); + unit->parsed_info = parsed_info; + unit->parsed_info_destroy_notify = destroy_notify; +} diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_unit.h b/gst-libs/gst/vaapi/gstvaapidecoder_unit.h new file mode 100644 index 0000000000..7ee77a05cf --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_unit.h @@ -0,0 +1,189 @@ +/* + * gstvaapidecoder_unit.h - VA decoder units + * + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODER_UNIT_H +#define GST_VAAPI_DECODER_UNIT_H + +G_BEGIN_DECLS + +typedef struct _GstVaapiDecoderUnit GstVaapiDecoderUnit; + +#define GST_VAAPI_DECODER_UNIT(unit) \ + ((GstVaapiDecoderUnit *)(unit)) + +#define GST_VAAPI_IS_DECODER_UNIT(unit) \ + (GST_VAAPI_DECODER_UNIT(unit) != NULL) + +/** + * GstVaapiDecoderUnitFlags: + * @GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START: marks the start of a frame. + * @GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END: marks the end of a frame. + * @GST_VAAPI_DECODER_UNIT_FLAG_STREAM_END: marks the end of a stream. + * @GST_VAAPI_DECODER_UNIT_FLAG_SLICE: the unit contains slice data. + * @GST_VAAPI_DECODER_UNIT_FLAG_SKIP: marks the unit as unused/skipped. + * + * Flags for #GstVaapiDecoderUnit. + */ +typedef enum { + GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START = (1 << 0), + GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END = (1 << 1), + GST_VAAPI_DECODER_UNIT_FLAG_STREAM_END = (1 << 2), + GST_VAAPI_DECODER_UNIT_FLAG_SLICE = (1 << 3), + GST_VAAPI_DECODER_UNIT_FLAG_SKIP = (1 << 4), + GST_VAAPI_DECODER_UNIT_FLAG_LAST = (1 << 5) +} GstVaapiDecoderUnitFlags; + +/** + * GST_VAAPI_DECODER_UNIT_FLAGS: + * @unit: a #GstVaapiDecoderUnit + * + * The entire set of flags for the @unit + */ +#define GST_VAAPI_DECODER_UNIT_FLAGS(unit) \ + ((unit)->flags) + +/** + * GST_VAAPI_DECODER_UNIT_FLAG_IS_SET: + * @unit: a #GstVaapiDecoderUnit + * @flag: a flag to check for + * + * Checks whether the given @flag is set + */ +#define GST_VAAPI_DECODER_UNIT_FLAG_IS_SET(unit, flag) \ + ((GST_VAAPI_DECODER_UNIT_FLAGS(unit) & (flag)) != 0) + +/** + * GST_VAAPI_DECODER_UNIT_FLAG_SET: + * @unit: a #GstVaapiDecoderUnit + * @flags: flags to set + * + * This macro sets the given bits + */ +#define GST_VAAPI_DECODER_UNIT_FLAG_SET(unit, flags) \ + (GST_VAAPI_DECODER_UNIT_FLAGS(unit) |= (flags)) + +/** + * GST_VAAPI_DECODER_UNIT_FLAG_UNSET: + * @unit: a #GstVaapiDecoderUnit + * @flags: flags to unset + * + * This macro unsets the given bits. + */ +#define GST_VAAPI_DECODER_UNIT_FLAG_UNSET(unit, flags) \ + (GST_VAAPI_DECODER_UNIT_FLAGS(unit) &= ~(flags)) + +/** + * GST_VAAPI_DECODER_UNIT_IS_FRAME_START: + * @unit: a #GstVaapiDecoderUnit + * + * Tests if the decoder unit marks the start of a frame. + * + * The start of a frame is codec dependent but it may include any new + * sequence header. + */ +#define GST_VAAPI_DECODER_UNIT_IS_FRAME_START(unit) \ + (GST_VAAPI_DECODER_UNIT_FLAG_IS_SET(unit, \ + GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START)) + +/** + * GST_VAAPI_DECODER_UNIT_IS_FRAME_END: + * @unit: a #GstVaapiDecoderUnit + * + * Tests if the decoder unit marks the end of a frame. + * + * The end of a frame is codec dependent but it is usually represented + * by the last bitstream chunk that holds valid slice data. + */ +#define GST_VAAPI_DECODER_UNIT_IS_FRAME_END(unit) \ + (GST_VAAPI_DECODER_UNIT_FLAG_IS_SET(unit, \ + GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END)) + +/** + * GST_VAAPI_DECODER_UNIT_IS_STREAM_END: + * @unit: a #GstVaapiDecoderUnit + * + * Tests if the decoder unit marks the end of the stream. + */ +#define GST_VAAPI_DECODER_UNIT_IS_STREAM_END(unit) \ + (GST_VAAPI_DECODER_UNIT_FLAG_IS_SET(unit, \ + GST_VAAPI_DECODER_UNIT_FLAG_STREAM_END)) + +/** + * GST_VAAPI_DECODER_UNIT_IS_SLICE: + * @unit: a #GstVaapiDecoderUnit + * + * Tests if the decoder unit contains slice data. + */ +#define GST_VAAPI_DECODER_UNIT_IS_SLICE(unit) \ + (GST_VAAPI_DECODER_UNIT_FLAG_IS_SET(unit, \ + GST_VAAPI_DECODER_UNIT_FLAG_SLICE)) + +/** + * GST_VAAPI_DECODER_UNIT_IS_SKIPPED: + * @unit: a #GstVaapiDecoderUnit + * + * Tests if the decoder unit is not needed for decoding an can be skipped. + * i.e. #GstVaapiDecoder sub-classes won't see this chunk of bitstream + * data. + */ +#define GST_VAAPI_DECODER_UNIT_IS_SKIPPED(unit) \ + (GST_VAAPI_DECODER_UNIT_FLAG_IS_SET(unit, \ + GST_VAAPI_DECODER_UNIT_FLAG_SKIP)) + +/** + * GstVaapiDecoderUnit: + * @size: size in bytes of this bitstream unit + * @offset: relative offset in bytes to bitstream unit within the + * associated #GstVideoCodecFrame input_buffer + * @parsed_info: parser-specific data (this is codec specific) + * @parsed_info_destroy_notify: function used to release @parsed_info data + * + * A chunk of bitstream data that was parsed. + */ +struct _GstVaapiDecoderUnit { + guint flags; + guint size; + guint offset; + gpointer parsed_info; + GDestroyNotify parsed_info_destroy_notify; +}; + +G_GNUC_INTERNAL +void +gst_vaapi_decoder_unit_init(GstVaapiDecoderUnit *unit); + +G_GNUC_INTERNAL +void +gst_vaapi_decoder_unit_clear(GstVaapiDecoderUnit *unit); + +G_GNUC_INTERNAL +GstVaapiDecoderUnit * +gst_vaapi_decoder_unit_new(void); + +G_GNUC_INTERNAL +void +gst_vaapi_decoder_unit_set_parsed_info(GstVaapiDecoderUnit *unit, + gpointer parsed_info, GDestroyNotify destroy_notify); + +G_END_DECLS + +#endif /* GST_VAAPI_DECODER_UNIT_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_vc1.c b/gst-libs/gst/vaapi/gstvaapidecoder_vc1.c new file mode 100644 index 0000000000..d8dcbce6fa --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_vc1.c @@ -0,0 +1,1484 @@ +/* + * gstvaapidecoder_vc1.c - VC-1 decoder + * + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapidecoder_vc1 + * @short_description: VC-1 decoder + */ + +#include "sysdeps.h" +#include +#include "gstvaapidecoder_vc1.h" +#include "gstvaapidecoder_objects.h" +#include "gstvaapidecoder_dpb.h" +#include "gstvaapidecoder_unit.h" +#include "gstvaapidecoder_priv.h" +#include "gstvaapidisplay_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +#define GST_VAAPI_DECODER_VC1_CAST(decoder) \ + ((GstVaapiDecoderVC1 *)(decoder)) + +typedef struct _GstVaapiDecoderVC1Private GstVaapiDecoderVC1Private; +typedef struct _GstVaapiDecoderVC1Class GstVaapiDecoderVC1Class; + +/** + * GstVaapiDecoderVC1: + * + * A decoder based on VC1. + */ +struct _GstVaapiDecoderVC1Private +{ + GstVaapiProfile profile; + guint width; + guint height; + GstVC1SeqHdr seq_hdr; + GstVC1EntryPointHdr entrypoint_hdr; + GstVC1FrameHdr frame_hdr; + GstVC1BitPlanes *bitplanes; + GstVaapiPicture *current_picture; + GstVaapiPicture *last_non_b_picture; + GstVaapiDpb *dpb; + gint32 next_poc; + guint8 *rbdu_buffer; + guint8 rndctrl; + guint rbdu_buffer_size; + guint is_opened:1; + guint has_codec_data:1; + guint has_entrypoint:1; + guint size_changed:1; + guint profile_changed:1; + guint closed_entry:1; + guint broken_link:1; +}; + +/** + * GstVaapiDecoderVC1: + * + * A decoder based on VC1. + */ +struct _GstVaapiDecoderVC1 +{ + /*< private > */ + GstVaapiDecoder parent_instance; + GstVaapiDecoderVC1Private priv; +}; + +/** + * GstVaapiDecoderVC1Class: + * + * A decoder class based on VC1. + */ +struct _GstVaapiDecoderVC1Class +{ + /*< private > */ + GstVaapiDecoderClass parent_class; +}; + +G_DEFINE_TYPE (GstVaapiDecoderVC1, gst_vaapi_decoder_vc1, + GST_TYPE_VAAPI_DECODER); + +static GstVaapiDecoderStatus +get_status (GstVC1ParserResult result) +{ + GstVaapiDecoderStatus status; + + switch (result) { + case GST_VC1_PARSER_OK: + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + break; + case GST_VC1_PARSER_NO_BDU_END: + status = GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + break; + case GST_VC1_PARSER_ERROR: + status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + break; + default: + status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + break; + } + return status; +} + +static void +gst_vaapi_decoder_vc1_close (GstVaapiDecoderVC1 * decoder) +{ + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + + gst_vaapi_picture_replace (&priv->last_non_b_picture, NULL); + gst_vaapi_picture_replace (&priv->current_picture, NULL); + gst_vaapi_dpb_replace (&priv->dpb, NULL); + + if (priv->bitplanes) { + gst_vc1_bitplanes_free (priv->bitplanes); + priv->bitplanes = NULL; + } + priv->is_opened = FALSE; +} + +static gboolean +gst_vaapi_decoder_vc1_open (GstVaapiDecoderVC1 * decoder) +{ + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + + gst_vaapi_decoder_vc1_close (decoder); + + priv->dpb = gst_vaapi_dpb_new (2); + if (!priv->dpb) + return FALSE; + + priv->bitplanes = gst_vc1_bitplanes_new (); + if (!priv->bitplanes) + return FALSE; + + memset (&priv->seq_hdr, 0, sizeof (GstVC1SeqHdr)); + memset (&priv->entrypoint_hdr, 0, sizeof (GstVC1EntryPointHdr)); + memset (&priv->frame_hdr, 0, sizeof (GstVC1FrameHdr)); + + return TRUE; +} + +static void +gst_vaapi_decoder_vc1_destroy (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderVC1 *const decoder = GST_VAAPI_DECODER_VC1_CAST (base_decoder); + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + + gst_vaapi_decoder_vc1_close (decoder); + + if (priv->rbdu_buffer) { + g_clear_pointer (&priv->rbdu_buffer, g_free); + priv->rbdu_buffer_size = 0; + } +} + +static gboolean +gst_vaapi_decoder_vc1_create (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderVC1 *const decoder = GST_VAAPI_DECODER_VC1_CAST (base_decoder); + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + + priv->has_codec_data = priv->has_entrypoint = + priv->size_changed = priv->profile_changed = + priv->closed_entry = priv->broken_link = FALSE; + + priv->profile = GST_VAAPI_PROFILE_UNKNOWN; + priv->rndctrl = 0; + priv->width = priv->height = 0; + return TRUE; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_vc1_reset (GstVaapiDecoder * base_decoder) +{ + gst_vaapi_decoder_vc1_destroy (base_decoder); + gst_vaapi_decoder_vc1_create (base_decoder); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +ensure_context (GstVaapiDecoderVC1 * decoder) +{ + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + GstVaapiProfile profiles[2]; + GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD; + guint i, n_profiles = 0; + gboolean reset_context = FALSE; + + if (priv->profile_changed) { + GST_DEBUG ("profile changed"); + priv->profile_changed = FALSE; + reset_context = TRUE; + + profiles[n_profiles++] = priv->profile; + if (priv->profile == GST_VAAPI_PROFILE_VC1_SIMPLE) + profiles[n_profiles++] = GST_VAAPI_PROFILE_VC1_MAIN; + + for (i = 0; i < n_profiles; i++) { + if (gst_vaapi_display_has_decoder (GST_VAAPI_DECODER_DISPLAY (decoder), + profiles[i], entrypoint)) + break; + } + if (i == n_profiles) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + priv->profile = profiles[i]; + } + + if (priv->size_changed) { + GST_DEBUG ("size changed"); + priv->size_changed = FALSE; + reset_context = TRUE; + } + + if (reset_context) { + GstVaapiContextInfo info; + + info.profile = priv->profile; + info.entrypoint = entrypoint; + info.chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420; + info.width = priv->width; + info.height = priv->height; + info.ref_frames = 2; + reset_context = + gst_vaapi_decoder_ensure_context (GST_VAAPI_DECODER (decoder), &info); + if (!reset_context) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_current_picture (GstVaapiDecoderVC1 * decoder) +{ + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + GstVaapiPicture *const picture = priv->current_picture; + + if (!picture) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + if (!gst_vaapi_picture_decode (picture)) + goto error; + if (GST_VAAPI_PICTURE_IS_COMPLETE (picture)) { + if (!gst_vaapi_dpb_add (priv->dpb, picture)) + goto error; + gst_vaapi_picture_replace (&priv->current_picture, NULL); + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + /* ERRORS */ +error: + { + /* XXX: fix for cases where first field failed to be decoded */ + gst_vaapi_picture_replace (&priv->current_picture, NULL); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } +} + +static GstVaapiDecoderStatus +decode_sequence (GstVaapiDecoderVC1 * decoder, GstVC1BDU * rbdu, + GstVC1BDU * ebdu) +{ + GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (decoder); + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + GstVC1SeqHdr *const seq_hdr = &priv->seq_hdr; + GstVC1AdvancedSeqHdr *const adv_hdr = &seq_hdr->advanced; + GstVC1SeqStructC *const structc = &seq_hdr->struct_c; + GstVC1ParserResult result; + GstVaapiProfile profile; + guint width, height, fps_n, fps_d, par_n, par_d; + + result = gst_vc1_parse_sequence_header (rbdu->data + rbdu->offset, + rbdu->size, seq_hdr); + if (result != GST_VC1_PARSER_OK) { + GST_ERROR ("failed to parse sequence layer"); + return get_status (result); + } + + priv->has_entrypoint = FALSE; + + /* Reset POC */ + if (priv->last_non_b_picture) { + if (priv->last_non_b_picture->poc == priv->next_poc) + priv->next_poc++; + gst_vaapi_picture_replace (&priv->last_non_b_picture, NULL); + } + + /* Validate profile */ + switch (seq_hdr->profile) { + case GST_VC1_PROFILE_SIMPLE: + case GST_VC1_PROFILE_MAIN: + case GST_VC1_PROFILE_ADVANCED: + break; + default: + GST_ERROR ("unsupported profile %d", seq_hdr->profile); + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + } + + fps_n = 0; + fps_d = 0; + par_n = 0; + par_d = 0; + switch (seq_hdr->profile) { + case GST_VC1_PROFILE_SIMPLE: + case GST_VC1_PROFILE_MAIN: + if (structc->wmvp) { + fps_n = structc->framerate; + fps_d = 1; + } + break; + case GST_VC1_PROFILE_ADVANCED: + fps_n = adv_hdr->fps_n; + fps_d = adv_hdr->fps_d; + par_n = adv_hdr->par_n; + par_d = adv_hdr->par_d; + break; + default: + g_assert (0 && "XXX: we already validated the profile above"); + break; + } + + if (fps_n && fps_d) + gst_vaapi_decoder_set_framerate (base_decoder, fps_n, fps_d); + + if (par_n > 0 && par_d > 0) + gst_vaapi_decoder_set_pixel_aspect_ratio (base_decoder, par_n, par_d); + + width = 0; + height = 0; + switch (seq_hdr->profile) { + case GST_VC1_PROFILE_SIMPLE: + case GST_VC1_PROFILE_MAIN: + width = seq_hdr->struct_c.coded_width; + height = seq_hdr->struct_c.coded_height; + break; + case GST_VC1_PROFILE_ADVANCED: + width = seq_hdr->advanced.max_coded_width; + height = seq_hdr->advanced.max_coded_height; + break; + default: + g_assert (0 && "XXX: we already validated the profile above"); + break; + } + + if (priv->width != width) { + priv->width = width; + priv->size_changed = TRUE; + } + + if (priv->height != height) { + priv->height = height; + priv->size_changed = TRUE; + } + + profile = GST_VAAPI_PROFILE_UNKNOWN; + switch (seq_hdr->profile) { + case GST_VC1_PROFILE_SIMPLE: + profile = GST_VAAPI_PROFILE_VC1_SIMPLE; + break; + case GST_VC1_PROFILE_MAIN: + profile = GST_VAAPI_PROFILE_VC1_MAIN; + break; + case GST_VC1_PROFILE_ADVANCED: + profile = GST_VAAPI_PROFILE_VC1_ADVANCED; + break; + default: + g_assert (0 && "XXX: we already validated the profile above"); + break; + } + if (priv->profile != profile) { + priv->profile = profile; + priv->profile_changed = TRUE; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_sequence_end (GstVaapiDecoderVC1 * decoder) +{ + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + GstVaapiDecoderStatus status; + + status = decode_current_picture (decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + gst_vaapi_dpb_flush (priv->dpb); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_entry_point (GstVaapiDecoderVC1 * decoder, GstVC1BDU * rbdu, + GstVC1BDU * ebdu) +{ + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + GstVC1SeqHdr *const seq_hdr = &priv->seq_hdr; + GstVC1EntryPointHdr *const entrypoint_hdr = &priv->entrypoint_hdr; + GstVC1ParserResult result; + + result = gst_vc1_parse_entry_point_header (rbdu->data + rbdu->offset, + rbdu->size, entrypoint_hdr, seq_hdr); + if (result != GST_VC1_PARSER_OK) { + GST_ERROR ("failed to parse entrypoint layer"); + return get_status (result); + } + + if (entrypoint_hdr->coded_size_flag) { + priv->width = entrypoint_hdr->coded_width; + priv->height = entrypoint_hdr->coded_height; + priv->size_changed = TRUE; + } + + priv->has_entrypoint = TRUE; + priv->closed_entry = entrypoint_hdr->closed_entry; + priv->broken_link = entrypoint_hdr->broken_link; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +/* Reconstruct bitstream PTYPE (7.1.1.4, index into Table-35) */ +static guint +get_PTYPE (guint ptype) +{ + switch (ptype) { + case GST_VC1_PICTURE_TYPE_I: + return 0; + case GST_VC1_PICTURE_TYPE_P: + return 1; + case GST_VC1_PICTURE_TYPE_B: + return 2; + case GST_VC1_PICTURE_TYPE_BI: + return 3; + } + return 4; /* skipped P-frame */ +} + +/* Reconstruct bitstream BFRACTION (7.1.1.14, index into Table-40) */ +static guint +get_BFRACTION (guint bfraction) +{ + guint i; + + static const struct + { + guint16 index; + guint16 value; + } + bfraction_map[] = { + { + 0, GST_VC1_BFRACTION_BASIS / 2}, { + 1, GST_VC1_BFRACTION_BASIS / 3}, { + 2, (GST_VC1_BFRACTION_BASIS * 2) / 3}, { + 3, GST_VC1_BFRACTION_BASIS / 4}, { + 4, (GST_VC1_BFRACTION_BASIS * 3) / 4}, { + 5, GST_VC1_BFRACTION_BASIS / 5}, { + 6, (GST_VC1_BFRACTION_BASIS * 2) / 5}, { + 7, (GST_VC1_BFRACTION_BASIS * 3) / 5}, { + 8, (GST_VC1_BFRACTION_BASIS * 4) / 5}, { + 9, GST_VC1_BFRACTION_BASIS / 6}, { + 10, (GST_VC1_BFRACTION_BASIS * 5) / 6}, { + 11, GST_VC1_BFRACTION_BASIS / 7}, { + 12, (GST_VC1_BFRACTION_BASIS * 2) / 7}, { + 13, (GST_VC1_BFRACTION_BASIS * 3) / 7}, { + 14, (GST_VC1_BFRACTION_BASIS * 4) / 7}, { + 15, (GST_VC1_BFRACTION_BASIS * 5) / 7}, { + 16, (GST_VC1_BFRACTION_BASIS * 6) / 7}, { + 17, GST_VC1_BFRACTION_BASIS / 8}, { + 18, (GST_VC1_BFRACTION_BASIS * 3) / 8}, { + 19, (GST_VC1_BFRACTION_BASIS * 5) / 8}, { + 20, (GST_VC1_BFRACTION_BASIS * 7) / 8}, { + 21, GST_VC1_BFRACTION_RESERVED}, { + 22, GST_VC1_BFRACTION_PTYPE_BI} + }; + + if (!bfraction) + return 0; + + for (i = 0; i < G_N_ELEMENTS (bfraction_map); i++) { + if (bfraction_map[i].value == bfraction) + return bfraction_map[i].index; + } + return 21; /* RESERVED */ +} + +/* Translate GStreamer MV modes to VA-API */ +static guint +get_VAMvModeVC1 (guint mvmode) +{ + switch (mvmode) { + case GST_VC1_MVMODE_1MV_HPEL_BILINEAR: + return VAMvMode1MvHalfPelBilinear; + case GST_VC1_MVMODE_1MV: + return VAMvMode1Mv; + case GST_VC1_MVMODE_1MV_HPEL: + return VAMvMode1MvHalfPel; + case GST_VC1_MVMODE_MIXED_MV: + return VAMvModeMixedMv; + case GST_VC1_MVMODE_INTENSITY_COMP: + return VAMvModeIntensityCompensation; + } + return 0; +} + +/* Reconstruct bitstream MVMODE (7.1.1.32) */ +static guint +get_MVMODE (GstVC1FrameHdr * frame_hdr) +{ + guint mvmode; + + if (frame_hdr->profile == GST_VC1_PROFILE_ADVANCED) + mvmode = frame_hdr->pic.advanced.mvmode; + else + mvmode = frame_hdr->pic.simple.mvmode; + + if (frame_hdr->ptype == GST_VC1_PICTURE_TYPE_P || + frame_hdr->ptype == GST_VC1_PICTURE_TYPE_B) + return get_VAMvModeVC1 (mvmode); + return 0; +} + +/* Reconstruct bitstream MVMODE2 (7.1.1.33) */ +static guint +get_MVMODE2 (GstVC1FrameHdr * frame_hdr) +{ + guint mvmode, mvmode2; + + if (frame_hdr->profile == GST_VC1_PROFILE_ADVANCED) { + mvmode = frame_hdr->pic.advanced.mvmode; + mvmode2 = frame_hdr->pic.advanced.mvmode2; + } else { + mvmode = frame_hdr->pic.simple.mvmode; + mvmode2 = frame_hdr->pic.simple.mvmode2; + } + + if (frame_hdr->ptype == GST_VC1_PICTURE_TYPE_P && + mvmode == GST_VC1_MVMODE_INTENSITY_COMP) + return get_VAMvModeVC1 (mvmode2); + return 0; +} + +static inline int +has_MVTYPEMB_bitplane (GstVaapiDecoderVC1 * decoder) +{ + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + GstVC1SeqHdr *const seq_hdr = &priv->seq_hdr; + GstVC1FrameHdr *const frame_hdr = &priv->frame_hdr; + guint mvmode, mvmode2; + + if (seq_hdr->profile == GST_VC1_PROFILE_ADVANCED) { + GstVC1PicAdvanced *const pic = &frame_hdr->pic.advanced; + if (pic->mvtypemb) + return 0; + mvmode = pic->mvmode; + mvmode2 = pic->mvmode2; + } else { + GstVC1PicSimpleMain *const pic = &frame_hdr->pic.simple; + if (pic->mvtypemb) + return 0; + mvmode = pic->mvmode; + mvmode2 = pic->mvmode2; + } + return (frame_hdr->ptype == GST_VC1_PICTURE_TYPE_P && + (mvmode == GST_VC1_MVMODE_MIXED_MV || + (mvmode == GST_VC1_MVMODE_INTENSITY_COMP && + mvmode2 == GST_VC1_MVMODE_MIXED_MV))); +} + +static inline int +has_SKIPMB_bitplane (GstVaapiDecoderVC1 * decoder) +{ + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + GstVC1SeqHdr *const seq_hdr = &priv->seq_hdr; + GstVC1FrameHdr *const frame_hdr = &priv->frame_hdr; + + if (seq_hdr->profile == GST_VC1_PROFILE_ADVANCED) { + GstVC1PicAdvanced *const pic = &frame_hdr->pic.advanced; + if (pic->skipmb) + return 0; + } else { + GstVC1PicSimpleMain *const pic = &frame_hdr->pic.simple; + if (pic->skipmb) + return 0; + } + return (frame_hdr->ptype == GST_VC1_PICTURE_TYPE_P || + frame_hdr->ptype == GST_VC1_PICTURE_TYPE_B); +} + +static inline int +has_DIRECTMB_bitplane (GstVaapiDecoderVC1 * decoder) +{ + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + GstVC1SeqHdr *const seq_hdr = &priv->seq_hdr; + GstVC1FrameHdr *const frame_hdr = &priv->frame_hdr; + + if (seq_hdr->profile == GST_VC1_PROFILE_ADVANCED) { + GstVC1PicAdvanced *const pic = &frame_hdr->pic.advanced; + if (pic->directmb) + return 0; + } else { + GstVC1PicSimpleMain *const pic = &frame_hdr->pic.simple; + if (pic->directmb) + return 0; + } + return frame_hdr->ptype == GST_VC1_PICTURE_TYPE_B; +} + +static inline int +has_ACPRED_bitplane (GstVaapiDecoderVC1 * decoder) +{ + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + GstVC1SeqHdr *const seq_hdr = &priv->seq_hdr; + GstVC1FrameHdr *const frame_hdr = &priv->frame_hdr; + GstVC1PicAdvanced *const pic = &frame_hdr->pic.advanced; + + if (seq_hdr->profile != GST_VC1_PROFILE_ADVANCED) + return 0; + if (pic->acpred) + return 0; + return (frame_hdr->ptype == GST_VC1_PICTURE_TYPE_I || + frame_hdr->ptype == GST_VC1_PICTURE_TYPE_BI); +} + +static inline int +has_OVERFLAGS_bitplane (GstVaapiDecoderVC1 * decoder) +{ + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + GstVC1SeqHdr *const seq_hdr = &priv->seq_hdr; + GstVC1EntryPointHdr *const entrypoint_hdr = &priv->entrypoint_hdr; + GstVC1FrameHdr *const frame_hdr = &priv->frame_hdr; + GstVC1PicAdvanced *const pic = &frame_hdr->pic.advanced; + + if (seq_hdr->profile != GST_VC1_PROFILE_ADVANCED) + return 0; + if (pic->overflags) + return 0; + return ((frame_hdr->ptype == GST_VC1_PICTURE_TYPE_I || + frame_hdr->ptype == GST_VC1_PICTURE_TYPE_BI) && + (entrypoint_hdr->overlap && frame_hdr->pquant <= 8) && + pic->condover == GST_VC1_CONDOVER_SELECT); +} + +static inline void +pack_bitplanes (GstVaapiBitPlane * bitplane, guint n, + const guint8 * bitplanes[3], guint x, guint y, guint stride) +{ + const guint dst_index = n / 2; + const guint src_index = y * stride + x; + guint8 v = 0; + + if (bitplanes[0]) + v |= bitplanes[0][src_index]; + if (bitplanes[1]) + v |= bitplanes[1][src_index] << 1; + if (bitplanes[2]) + v |= bitplanes[2][src_index] << 2; + bitplane->data[dst_index] = (bitplane->data[dst_index] << 4) | v; +} + +static gboolean +fill_picture_structc (GstVaapiDecoderVC1 * decoder, GstVaapiPicture * picture) +{ + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + VAPictureParameterBufferVC1 *const pic_param = picture->param; + GstVC1SeqStructC *const structc = &priv->seq_hdr.struct_c; + GstVC1FrameHdr *const frame_hdr = &priv->frame_hdr; + GstVC1PicSimpleMain *const pic = &frame_hdr->pic.simple; + + /* Fill in VAPictureParameterBufferVC1 (simple/main profile bits) */ + pic_param->sequence_fields.bits.finterpflag = structc->finterpflag; + pic_param->sequence_fields.bits.multires = structc->multires; + pic_param->sequence_fields.bits.overlap = structc->overlap; + pic_param->sequence_fields.bits.syncmarker = structc->syncmarker; + pic_param->sequence_fields.bits.rangered = structc->rangered; + pic_param->sequence_fields.bits.max_b_frames = structc->maxbframes; + pic_param->conditional_overlap_flag = 0; /* advanced profile only */ + pic_param->fast_uvmc_flag = structc->fastuvmc; + pic_param->b_picture_fraction = get_BFRACTION (pic->bfraction); + pic_param->cbp_table = pic->cbptab; + pic_param->mb_mode_table = 0; /* XXX: interlaced frame */ + pic_param->range_reduction_frame = pic->rangeredfrm; + pic_param->post_processing = 0; /* advanced profile only */ + pic_param->picture_resolution_index = pic->respic; + pic_param->luma_scale = pic->lumscale; + pic_param->luma_shift = pic->lumshift; + pic_param->raw_coding.flags.mv_type_mb = pic->mvtypemb; + pic_param->raw_coding.flags.direct_mb = pic->directmb; + pic_param->raw_coding.flags.skip_mb = pic->skipmb; + pic_param->bitplane_present.flags.bp_mv_type_mb = + has_MVTYPEMB_bitplane (decoder); + pic_param->bitplane_present.flags.bp_direct_mb = + has_DIRECTMB_bitplane (decoder); + pic_param->bitplane_present.flags.bp_skip_mb = has_SKIPMB_bitplane (decoder); + pic_param->mv_fields.bits.mv_table = pic->mvtab; + pic_param->mv_fields.bits.extended_mv_flag = structc->extended_mv; + pic_param->mv_fields.bits.extended_mv_range = pic->mvrange; + pic_param->transform_fields.bits.variable_sized_transform_flag = + structc->vstransform; + pic_param->transform_fields.bits.mb_level_transform_type_flag = pic->ttmbf; + pic_param->transform_fields.bits.frame_level_transform_type = pic->ttfrm; + pic_param->transform_fields.bits.transform_ac_codingset_idx2 = + pic->transacfrm2; + + /* Refer to 8.3.7 Rounding control for Simple and Main Profile */ + if (frame_hdr->ptype == GST_VC1_PICTURE_TYPE_I || + frame_hdr->ptype == GST_VC1_PICTURE_TYPE_BI) + priv->rndctrl = 1; + else if (frame_hdr->ptype == GST_VC1_PICTURE_TYPE_P) + priv->rndctrl ^= 1; + + pic_param->rounding_control = priv->rndctrl; + + return TRUE; +} + +static gboolean +fill_picture_advanced (GstVaapiDecoderVC1 * decoder, GstVaapiPicture * picture) +{ + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + VAPictureParameterBufferVC1 *const pic_param = picture->param; + GstVC1AdvancedSeqHdr *const adv_hdr = &priv->seq_hdr.advanced; + GstVC1EntryPointHdr *const entrypoint_hdr = &priv->entrypoint_hdr; + GstVC1FrameHdr *const frame_hdr = &priv->frame_hdr; + GstVC1PicAdvanced *const pic = &frame_hdr->pic.advanced; + + if (!priv->has_entrypoint) + return FALSE; + + /* Fill in VAPictureParameterBufferVC1 (advanced profile bits) */ + pic_param->sequence_fields.bits.pulldown = adv_hdr->pulldown; + pic_param->sequence_fields.bits.interlace = adv_hdr->interlace; + pic_param->sequence_fields.bits.tfcntrflag = adv_hdr->tfcntrflag; + pic_param->sequence_fields.bits.finterpflag = adv_hdr->finterpflag; + pic_param->sequence_fields.bits.psf = adv_hdr->psf; + pic_param->sequence_fields.bits.overlap = entrypoint_hdr->overlap; + pic_param->entrypoint_fields.bits.broken_link = entrypoint_hdr->broken_link; + pic_param->entrypoint_fields.bits.closed_entry = entrypoint_hdr->closed_entry; + pic_param->entrypoint_fields.bits.panscan_flag = entrypoint_hdr->panscan_flag; + pic_param->entrypoint_fields.bits.loopfilter = entrypoint_hdr->loopfilter; + pic_param->conditional_overlap_flag = pic->condover; + pic_param->fast_uvmc_flag = entrypoint_hdr->fastuvmc; + pic_param->range_mapping_fields.bits.luma_flag = + entrypoint_hdr->range_mapy_flag; + pic_param->range_mapping_fields.bits.luma = entrypoint_hdr->range_mapy; + pic_param->range_mapping_fields.bits.chroma_flag = + entrypoint_hdr->range_mapuv_flag; + pic_param->range_mapping_fields.bits.chroma = entrypoint_hdr->range_mapuv; + pic_param->b_picture_fraction = get_BFRACTION (pic->bfraction); + pic_param->cbp_table = pic->cbptab; + pic_param->mb_mode_table = 0; /* XXX: interlaced frame */ + pic_param->range_reduction_frame = 0; /* simple/main profile only */ + pic_param->rounding_control = pic->rndctrl; + pic_param->post_processing = pic->postproc; + pic_param->picture_resolution_index = 0; /* simple/main profile only */ + pic_param->luma_scale = pic->lumscale; + pic_param->luma_shift = pic->lumshift; + pic_param->picture_fields.bits.frame_coding_mode = pic->fcm; + pic_param->picture_fields.bits.top_field_first = pic->tff; + pic_param->picture_fields.bits.is_first_field = pic->fcm == 0; /* XXX: interlaced frame */ + pic_param->picture_fields.bits.intensity_compensation = + pic->mvmode == GST_VC1_MVMODE_INTENSITY_COMP; + pic_param->raw_coding.flags.mv_type_mb = pic->mvtypemb; + pic_param->raw_coding.flags.direct_mb = pic->directmb; + pic_param->raw_coding.flags.skip_mb = pic->skipmb; + pic_param->raw_coding.flags.ac_pred = pic->acpred; + pic_param->raw_coding.flags.overflags = pic->overflags; + pic_param->bitplane_present.flags.bp_mv_type_mb = + has_MVTYPEMB_bitplane (decoder); + pic_param->bitplane_present.flags.bp_direct_mb = + has_DIRECTMB_bitplane (decoder); + pic_param->bitplane_present.flags.bp_skip_mb = has_SKIPMB_bitplane (decoder); + pic_param->bitplane_present.flags.bp_ac_pred = has_ACPRED_bitplane (decoder); + pic_param->bitplane_present.flags.bp_overflags = + has_OVERFLAGS_bitplane (decoder); + pic_param->reference_fields.bits.reference_distance_flag = + entrypoint_hdr->refdist_flag; + pic_param->mv_fields.bits.mv_table = pic->mvtab; + pic_param->mv_fields.bits.extended_mv_flag = entrypoint_hdr->extended_mv; + pic_param->mv_fields.bits.extended_mv_range = pic->mvrange; + pic_param->mv_fields.bits.extended_dmv_flag = entrypoint_hdr->extended_dmv; + pic_param->pic_quantizer_fields.bits.dquant = entrypoint_hdr->dquant; + pic_param->pic_quantizer_fields.bits.quantizer = entrypoint_hdr->quantizer; + pic_param->transform_fields.bits.variable_sized_transform_flag = + entrypoint_hdr->vstransform; + pic_param->transform_fields.bits.mb_level_transform_type_flag = pic->ttmbf; + pic_param->transform_fields.bits.frame_level_transform_type = pic->ttfrm; + pic_param->transform_fields.bits.transform_ac_codingset_idx2 = + pic->transacfrm2; + return TRUE; +} + +static gboolean +fill_picture (GstVaapiDecoderVC1 * decoder, GstVaapiPicture * picture) +{ + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + VAPictureParameterBufferVC1 *const pic_param = picture->param; + GstVC1SeqHdr *const seq_hdr = &priv->seq_hdr; + GstVC1FrameHdr *const frame_hdr = &priv->frame_hdr; + GstVC1VopDquant *const vopdquant = &frame_hdr->vopdquant; + GstVaapiPicture *prev_picture, *next_picture; + + /* Fill in VAPictureParameterBufferVC1 (common fields) */ + pic_param->forward_reference_picture = VA_INVALID_ID; + pic_param->backward_reference_picture = VA_INVALID_ID; + pic_param->inloop_decoded_picture = VA_INVALID_ID; + pic_param->sequence_fields.value = 0; + pic_param->sequence_fields.bits.profile = seq_hdr->profile; + pic_param->coded_width = priv->width; + pic_param->coded_height = priv->height; + pic_param->entrypoint_fields.value = 0; + pic_param->range_mapping_fields.value = 0; + pic_param->picture_fields.value = 0; + pic_param->picture_fields.bits.picture_type = get_PTYPE (frame_hdr->ptype); + pic_param->raw_coding.value = 0; + pic_param->bitplane_present.value = 0; + pic_param->reference_fields.value = 0; + pic_param->mv_fields.value = 0; + pic_param->mv_fields.bits.mv_mode = get_MVMODE (frame_hdr); + pic_param->mv_fields.bits.mv_mode2 = get_MVMODE2 (frame_hdr); + pic_param->pic_quantizer_fields.value = 0; + pic_param->pic_quantizer_fields.bits.half_qp = frame_hdr->halfqp; + pic_param->pic_quantizer_fields.bits.pic_quantizer_scale = frame_hdr->pquant; + pic_param->pic_quantizer_fields.bits.pic_quantizer_type = + frame_hdr->pquantizer; + pic_param->pic_quantizer_fields.bits.dq_frame = vopdquant->dquantfrm; + pic_param->pic_quantizer_fields.bits.dq_profile = vopdquant->dqprofile; + pic_param->pic_quantizer_fields.bits.dq_sb_edge = + vopdquant->dqprofile == + GST_VC1_DQPROFILE_SINGLE_EDGE ? vopdquant->dqbedge : 0; + pic_param->pic_quantizer_fields.bits.dq_db_edge = + vopdquant->dqprofile == + GST_VC1_DQPROFILE_DOUBLE_EDGES ? vopdquant->dqbedge : 0; + pic_param->pic_quantizer_fields.bits.dq_binary_level = vopdquant->dqbilevel; + pic_param->pic_quantizer_fields.bits.alt_pic_quantizer = vopdquant->altpquant; + pic_param->transform_fields.value = 0; + pic_param->transform_fields.bits.transform_ac_codingset_idx1 = + frame_hdr->transacfrm; + pic_param->transform_fields.bits.intra_transform_dc_table = + frame_hdr->transdctab; + + if (seq_hdr->profile == GST_VC1_PROFILE_ADVANCED) { + if (!fill_picture_advanced (decoder, picture)) + return FALSE; + } else { + if (!fill_picture_structc (decoder, picture)) + return FALSE; + } + + gst_vaapi_dpb_get_neighbours (priv->dpb, picture, + &prev_picture, &next_picture); + + switch (picture->type) { + case GST_VAAPI_PICTURE_TYPE_B: + if (next_picture) + pic_param->backward_reference_picture = next_picture->surface_id; + if (prev_picture) + pic_param->forward_reference_picture = prev_picture->surface_id; + else if (!priv->closed_entry) + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_SKIPPED); + break; + case GST_VAAPI_PICTURE_TYPE_P: + if (prev_picture) + pic_param->forward_reference_picture = prev_picture->surface_id; + break; + default: + break; + } + + if (pic_param->bitplane_present.value) { + const guint8 *bitplanes[3]; + guint x, y, n; + + switch (picture->type) { + case GST_VAAPI_PICTURE_TYPE_P: + bitplanes[0] = pic_param->bitplane_present.flags.bp_direct_mb ? + priv->bitplanes->directmb : NULL; + bitplanes[1] = pic_param->bitplane_present.flags.bp_skip_mb ? + priv->bitplanes->skipmb : NULL; + bitplanes[2] = pic_param->bitplane_present.flags.bp_mv_type_mb ? + priv->bitplanes->mvtypemb : NULL; + break; + case GST_VAAPI_PICTURE_TYPE_B: + bitplanes[0] = pic_param->bitplane_present.flags.bp_direct_mb ? + priv->bitplanes->directmb : NULL; + bitplanes[1] = pic_param->bitplane_present.flags.bp_skip_mb ? + priv->bitplanes->skipmb : NULL; + bitplanes[2] = NULL; /* XXX: interlaced frame (FORWARD plane) */ + break; + case GST_VAAPI_PICTURE_TYPE_BI: + case GST_VAAPI_PICTURE_TYPE_I: + bitplanes[0] = NULL; /* XXX: interlaced frame (FIELDTX plane) */ + bitplanes[1] = pic_param->bitplane_present.flags.bp_ac_pred ? + priv->bitplanes->acpred : NULL; + bitplanes[2] = pic_param->bitplane_present.flags.bp_overflags ? + priv->bitplanes->overflags : NULL; + break; + default: + bitplanes[0] = NULL; + bitplanes[1] = NULL; + bitplanes[2] = NULL; + break; + } + + picture->bitplane = GST_VAAPI_BITPLANE_NEW (decoder, + (seq_hdr->mb_width * seq_hdr->mb_height + 1) / 2); + if (!picture->bitplane) + return FALSE; + + n = 0; + for (y = 0; y < seq_hdr->mb_height; y++) + for (x = 0; x < seq_hdr->mb_width; x++, n++) + pack_bitplanes (picture->bitplane, n, bitplanes, x, y, + seq_hdr->mb_stride); + if (n & 1) /* move last nibble to the high order */ + picture->bitplane->data[n / 2] <<= 4; + } + return TRUE; +} + +static GstVaapiDecoderStatus +decode_slice_chunk (GstVaapiDecoderVC1 * decoder, GstVC1BDU * ebdu, + guint slice_addr, guint header_size) +{ + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + GstVaapiPicture *const picture = priv->current_picture; + GstVaapiSlice *slice; + VASliceParameterBufferVC1 *slice_param; + + slice = GST_VAAPI_SLICE_NEW (VC1, decoder, + ebdu->data + ebdu->sc_offset, + ebdu->size + ebdu->offset - ebdu->sc_offset); + if (!slice) { + GST_ERROR ("failed to allocate slice"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + gst_vaapi_picture_add_slice (picture, slice); + + /* Fill in VASliceParameterBufferVC1 */ + slice_param = slice->param; + slice_param->macroblock_offset = 8 * (ebdu->offset - ebdu->sc_offset) + + header_size; + slice_param->slice_vertical_position = slice_addr; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_frame (GstVaapiDecoderVC1 * decoder, GstVC1BDU * rbdu, GstVC1BDU * ebdu) +{ + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + GstVC1FrameHdr *const frame_hdr = &priv->frame_hdr; + GstVC1ParserResult result; + GstVaapiPicture *const picture = priv->current_picture; + + memset (frame_hdr, 0, sizeof (*frame_hdr)); + result = gst_vc1_parse_frame_header (rbdu->data + rbdu->offset, + rbdu->size, frame_hdr, &priv->seq_hdr, priv->bitplanes); + if (result != GST_VC1_PARSER_OK) { + GST_ERROR ("failed to parse frame layer"); + return get_status (result); + } + + /* @FIXME: intel-driver cannot handle interlaced frames */ + if (priv->profile == GST_VAAPI_PROFILE_VC1_ADVANCED + && frame_hdr->pic.advanced.fcm != GST_VC1_FRAME_PROGRESSIVE) { + GST_ERROR ("interlaced video not supported"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + } + + switch (frame_hdr->ptype) { + case GST_VC1_PICTURE_TYPE_I: + picture->type = GST_VAAPI_PICTURE_TYPE_I; + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_REFERENCE); + break; + case GST_VC1_PICTURE_TYPE_SKIPPED: + case GST_VC1_PICTURE_TYPE_P: + picture->type = GST_VAAPI_PICTURE_TYPE_P; + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_REFERENCE); + break; + case GST_VC1_PICTURE_TYPE_B: + picture->type = GST_VAAPI_PICTURE_TYPE_B; + break; + case GST_VC1_PICTURE_TYPE_BI: + picture->type = GST_VAAPI_PICTURE_TYPE_BI; + break; + default: + GST_ERROR ("unsupported picture type %d", frame_hdr->ptype); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + /* Update presentation time */ + if (GST_VAAPI_PICTURE_IS_REFERENCE (picture)) { + picture->poc = priv->last_non_b_picture ? + (priv->last_non_b_picture->poc + 1) : priv->next_poc; + priv->next_poc = picture->poc + 1; + gst_vaapi_picture_replace (&priv->last_non_b_picture, picture); + } else if (!priv->last_non_b_picture) + picture->poc = priv->next_poc++; + else { /* B or BI */ + picture->poc = priv->last_non_b_picture->poc++; + priv->next_poc = priv->last_non_b_picture->poc + 1; + } + picture->pts = GST_VAAPI_DECODER_CODEC_FRAME (decoder)->pts; + + if (!fill_picture (decoder, picture)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + return decode_slice_chunk (decoder, ebdu, 0, frame_hdr->header_size); +} + +static GstVaapiDecoderStatus +decode_slice (GstVaapiDecoderVC1 * decoder, GstVC1BDU * rbdu, GstVC1BDU * ebdu) +{ + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + GstVC1SliceHdr slice_hdr; + GstVC1ParserResult result; + + memset (&slice_hdr, 0, sizeof (slice_hdr)); + result = gst_vc1_parse_slice_header (rbdu->data + rbdu->offset, + rbdu->size, &slice_hdr, &priv->seq_hdr); + if (result != GST_VC1_PARSER_OK) { + GST_ERROR ("failed to parse slice layer"); + return get_status (result); + } + return decode_slice_chunk (decoder, ebdu, slice_hdr.slice_addr, + slice_hdr.header_size); +} + +static gboolean +decode_rbdu (GstVaapiDecoderVC1 * decoder, GstVC1BDU * rbdu, GstVC1BDU * ebdu) +{ + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + guint8 *rbdu_buffer; + guint i, j, rbdu_buffer_size; + + /* BDU are encapsulated in advanced profile mode only */ + if (priv->profile != GST_VAAPI_PROFILE_VC1_ADVANCED) { + memcpy (rbdu, ebdu, sizeof (*rbdu)); + return TRUE; + } + + /* Reallocate unescaped bitstream buffer */ + rbdu_buffer = priv->rbdu_buffer; + if (!rbdu_buffer || ebdu->size > priv->rbdu_buffer_size) { + rbdu_buffer = g_realloc (priv->rbdu_buffer, ebdu->size); + if (!rbdu_buffer) + return FALSE; + priv->rbdu_buffer = rbdu_buffer; + priv->rbdu_buffer_size = ebdu->size; + } + + /* Unescape bitstream buffer */ + if (ebdu->size < 4) { + memcpy (rbdu_buffer, ebdu->data + ebdu->offset, ebdu->size); + rbdu_buffer_size = ebdu->size; + } else { + guint8 *const bdu_buffer = ebdu->data + ebdu->offset; + for (i = 0, j = 0; i < ebdu->size; i++) { + if (i >= 2 && i < ebdu->size - 1 && + bdu_buffer[i - 1] == 0x00 && + bdu_buffer[i - 2] == 0x00 && + bdu_buffer[i] == 0x03 && bdu_buffer[i + 1] <= 0x03) + i++; + rbdu_buffer[j++] = bdu_buffer[i]; + } + rbdu_buffer_size = j; + } + + /* Reconstruct RBDU */ + rbdu->type = ebdu->type; + rbdu->size = rbdu_buffer_size; + rbdu->sc_offset = 0; + rbdu->offset = 0; + rbdu->data = rbdu_buffer; + return TRUE; +} + +static GstVaapiDecoderStatus +decode_ebdu (GstVaapiDecoderVC1 * decoder, GstVC1BDU * ebdu) +{ + GstVaapiDecoderStatus status; + GstVC1BDU rbdu; + + if (!decode_rbdu (decoder, &rbdu, ebdu)) + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + + switch (ebdu->type) { + case GST_VC1_SEQUENCE: + status = decode_sequence (decoder, &rbdu, ebdu); + break; + case GST_VC1_ENTRYPOINT: + status = decode_entry_point (decoder, &rbdu, ebdu); + break; + case GST_VC1_FRAME: + status = decode_frame (decoder, &rbdu, ebdu); + break; + case GST_VC1_SLICE: + status = decode_slice (decoder, &rbdu, ebdu); + break; + case GST_VC1_END_OF_SEQ: + status = decode_sequence_end (decoder); + break; + case GST_VC1_FIELD_USER: + case GST_VC1_FRAME_USER: + case GST_VC1_ENTRY_POINT_USER: + case GST_VC1_SEQUENCE_USER: + /* Let's just ignore them */ + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + break; + default: + GST_WARNING ("unsupported BDU type %d", ebdu->type); + status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + break; + } + return status; +} + +static GstVaapiDecoderStatus +decode_buffer (GstVaapiDecoderVC1 * decoder, guchar * buf, guint buf_size) +{ + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + GstVC1BDU ebdu; + + if (priv->has_codec_data) { + ebdu.type = GST_VC1_FRAME; + ebdu.sc_offset = 0; + ebdu.offset = 0; + } else { + ebdu.type = buf[3]; + ebdu.sc_offset = 0; + ebdu.offset = 4; + } + ebdu.data = buf; + ebdu.size = buf_size - ebdu.offset; + return decode_ebdu (decoder, &ebdu); +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_vc1_decode_codec_data (GstVaapiDecoder * base_decoder, + const guchar * buf, guint buf_size) +{ + GstVaapiDecoderVC1 *const decoder = GST_VAAPI_DECODER_VC1_CAST (base_decoder); + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + GstVC1SeqHdr *const seq_hdr = &priv->seq_hdr; + GstVaapiDecoderStatus status; + GstVC1ParserResult result; + GstVC1BDU ebdu; + GstCaps *caps; + GstStructure *structure; + guint ofs; + gint width, height; + guint32 format; + gint version; + const gchar *s; + + priv->has_codec_data = TRUE; + + width = GST_VAAPI_DECODER_WIDTH (decoder); + height = GST_VAAPI_DECODER_HEIGHT (decoder); + if (!width || !height) { + GST_ERROR ("failed to parse size from codec-data"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + caps = GST_VAAPI_DECODER_CODEC_STATE (decoder)->caps; + structure = gst_caps_get_structure (caps, 0); + s = gst_structure_get_string (structure, "format"); + if (s && strlen (s) == 4) { + format = GST_MAKE_FOURCC (s[0], s[1], s[2], s[3]); + } else { + /* Try to determine format from "wmvversion" property */ + if (gst_structure_get_int (structure, "wmvversion", &version)) + format = (version >= 1 && version <= 3) ? + GST_MAKE_FOURCC ('W', 'M', 'V', ('0' + version)) : 0; + else + format = 0; + } + if (!format) { + GST_ERROR ("failed to parse profile from codec-data"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC; + } + + /* WMV3 -- expecting sequence header */ + if (format == GST_MAKE_FOURCC ('W', 'M', 'V', '3')) { + seq_hdr->struct_c.coded_width = width; + seq_hdr->struct_c.coded_height = height; + ebdu.type = GST_VC1_SEQUENCE; + ebdu.size = buf_size; + ebdu.sc_offset = 0; + ebdu.offset = 0; + ebdu.data = (guint8 *) buf; + return decode_ebdu (decoder, &ebdu); + } + + /* WVC1 -- expecting bitstream data units */ + if (format != GST_MAKE_FOURCC ('W', 'V', 'C', '1')) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + seq_hdr->advanced.max_coded_width = width; + seq_hdr->advanced.max_coded_height = height; + + ofs = 0; + do { + result = gst_vc1_identify_next_bdu (buf + ofs, buf_size - ofs, &ebdu); + + switch (result) { + case GST_VC1_PARSER_NO_BDU_END: + /* Assume the EBDU is complete within codec-data bounds */ + ebdu.size = buf_size - ofs - ebdu.offset; + // fall-through + case GST_VC1_PARSER_OK: + status = decode_ebdu (decoder, &ebdu); + ofs += ebdu.offset + ebdu.size; + break; + default: + status = get_status (result); + break; + } + } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS && ofs < buf_size); + return status; +} + +static GstVaapiDecoderStatus +ensure_decoder (GstVaapiDecoderVC1 * decoder) +{ + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + GstVaapiDecoderStatus status; + + if (!priv->is_opened) { + priv->is_opened = gst_vaapi_decoder_vc1_open (decoder); + if (!priv->is_opened) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC; + + status = + gst_vaapi_decoder_decode_codec_data (GST_VAAPI_DECODER_CAST (decoder)); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static inline gint +scan_for_start_code (GstAdapter * adapter, guint ofs, guint size, guint32 * scp) +{ + return (gint) gst_adapter_masked_scan_uint32_peek (adapter, + 0xffffff00, 0x00000100, ofs, size, scp); +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_vc1_parse (GstVaapiDecoder * base_decoder, + GstAdapter * adapter, gboolean at_eos, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderVC1 *const decoder = GST_VAAPI_DECODER_VC1_CAST (base_decoder); + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + GstVaapiDecoderStatus status; + guint8 bdu_type; + guint size, buf_size, flags = 0; + gint ofs; + + status = ensure_decoder (decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + size = gst_adapter_available (adapter); + + if (priv->has_codec_data) { + // Assume demuxer sends out plain frames + if (size < 1) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + buf_size = size; + bdu_type = GST_VC1_FRAME; + } else { + if (size < 4) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + + ofs = scan_for_start_code (adapter, 0, size, NULL); + if (ofs < 0) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + gst_adapter_flush (adapter, ofs); + size -= ofs; + + ofs = G_UNLIKELY (size < 8) ? -1 : + scan_for_start_code (adapter, 4, size - 4, NULL); + if (ofs < 0) { + // Assume the whole packet is present if end-of-stream + if (!at_eos) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + ofs = size; + } + buf_size = ofs; + gst_adapter_copy (adapter, &bdu_type, 3, 1); + } + + unit->size = buf_size; + + /* Check for new picture layer */ + switch (bdu_type) { + case GST_VC1_END_OF_SEQ: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END; + flags |= GST_VAAPI_DECODER_UNIT_FLAG_STREAM_END; + break; + case GST_VC1_SEQUENCE: + case GST_VC1_ENTRYPOINT: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START; + break; + case GST_VC1_FRAME: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START; + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE; + break; + case GST_VC1_SLICE: + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE; + break; + case GST_VC1_FIELD: + /* @FIXME: intel-driver cannot handle interlaced frames */ + GST_ERROR ("interlaced video not supported"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + } + GST_VAAPI_DECODER_UNIT_FLAG_SET (unit, flags); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_vc1_decode (GstVaapiDecoder * base_decoder, + GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderVC1 *const decoder = GST_VAAPI_DECODER_VC1_CAST (base_decoder); + GstVaapiDecoderStatus status; + GstBuffer *const buffer = + GST_VAAPI_DECODER_CODEC_FRAME (decoder)->input_buffer; + GstMapInfo map_info; + + status = ensure_decoder (decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) { + GST_ERROR ("failed to map buffer"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + status = decode_buffer (decoder, map_info.data + unit->offset, unit->size); + gst_buffer_unmap (buffer, &map_info); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_vc1_start_frame (GstVaapiDecoder * base_decoder, + GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderVC1 *const decoder = GST_VAAPI_DECODER_VC1_CAST (base_decoder); + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + GstVaapiDecoderStatus status; + GstVaapiPicture *picture; + + status = ensure_context (decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) { + GST_ERROR ("failed to reset context"); + return status; + } + status = ensure_decoder (decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + picture = GST_VAAPI_PICTURE_NEW (VC1, decoder); + if (!picture) { + GST_ERROR ("failed to allocate picture"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + gst_vaapi_picture_replace (&priv->current_picture, picture); + gst_vaapi_picture_unref (picture); + + /* Update cropping rectangle */ + do { + GstVC1AdvancedSeqHdr *adv_hdr; + GstVaapiRectangle crop_rect; + + if (priv->profile != GST_VAAPI_PROFILE_VC1_ADVANCED) + break; + + adv_hdr = &priv->seq_hdr.advanced; + if (!adv_hdr->display_ext) + break; + + crop_rect.x = 0; + crop_rect.y = 0; + crop_rect.width = adv_hdr->disp_horiz_size; + crop_rect.height = adv_hdr->disp_vert_size; + if (crop_rect.width <= priv->width && crop_rect.height <= priv->height) + gst_vaapi_picture_set_crop_rect (picture, &crop_rect); + } while (0); + + if (!gst_vc1_bitplanes_ensure_size (priv->bitplanes, &priv->seq_hdr)) { + GST_ERROR ("failed to allocate bitplanes"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_vc1_end_frame (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderVC1 *const decoder = GST_VAAPI_DECODER_VC1_CAST (base_decoder); + + return decode_current_picture (decoder); +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_vc1_flush (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderVC1 *const decoder = GST_VAAPI_DECODER_VC1_CAST (base_decoder); + GstVaapiDecoderVC1Private *const priv = &decoder->priv; + + if (priv->is_opened) + gst_vaapi_dpb_flush (priv->dpb); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static void +gst_vaapi_decoder_vc1_finalize (GObject * object) +{ + GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (object); + + gst_vaapi_decoder_vc1_destroy (base_decoder); + G_OBJECT_CLASS (gst_vaapi_decoder_vc1_parent_class)->finalize (object); +} + +static void +gst_vaapi_decoder_vc1_class_init (GstVaapiDecoderVC1Class * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstVaapiDecoderClass *const decoder_class = GST_VAAPI_DECODER_CLASS (klass); + + object_class->finalize = gst_vaapi_decoder_vc1_finalize; + + decoder_class->reset = gst_vaapi_decoder_vc1_reset; + decoder_class->parse = gst_vaapi_decoder_vc1_parse; + decoder_class->decode = gst_vaapi_decoder_vc1_decode; + decoder_class->start_frame = gst_vaapi_decoder_vc1_start_frame; + decoder_class->end_frame = gst_vaapi_decoder_vc1_end_frame; + decoder_class->flush = gst_vaapi_decoder_vc1_flush; + + decoder_class->decode_codec_data = gst_vaapi_decoder_vc1_decode_codec_data; +} + +static void +gst_vaapi_decoder_vc1_init (GstVaapiDecoderVC1 * decoder) +{ + GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (decoder); + + gst_vaapi_decoder_vc1_create (base_decoder); +} + +/** + * gst_vaapi_decoder_vc1_new: + * @display: a #GstVaapiDisplay + * @caps: a #GstCaps holding codec information + * + * Creates a new #GstVaapiDecoder for VC-1 decoding. The @caps can + * hold extra information like codec-data and pictured coded size. + * + * Return value: the newly allocated #GstVaapiDecoder object + */ +GstVaapiDecoder * +gst_vaapi_decoder_vc1_new (GstVaapiDisplay * display, GstCaps * caps) +{ + return g_object_new (GST_TYPE_VAAPI_DECODER_VC1, "display", display, + "caps", caps, NULL); +} diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_vc1.h b/gst-libs/gst/vaapi/gstvaapidecoder_vc1.h new file mode 100644 index 0000000000..034681f608 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_vc1.h @@ -0,0 +1,49 @@ +/* + * gstvaapidecoder_vc1.h - VC-1 decoder + * + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODER_VC1_H +#define GST_VAAPI_DECODER_VC1_H + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_DECODER_VC1 \ + (gst_vaapi_decoder_vc1_get_type ()) +#define GST_VAAPI_DECODER_VC1(decoder) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DECODER_VC1, GstVaapiDecoderVC1)) +#define GST_VAAPI_IS_DECODER_VC1(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_DECODER_VC1)) + +typedef struct _GstVaapiDecoderVC1 GstVaapiDecoderVC1; + +GType +gst_vaapi_decoder_vc1_get_type (void) G_GNUC_CONST; + +GstVaapiDecoder * +gst_vaapi_decoder_vc1_new (GstVaapiDisplay *display, GstCaps *caps); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDecoderVC1, gst_object_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_DECODER_VC1_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_vp8.c b/gst-libs/gst/vaapi/gstvaapidecoder_vp8.c new file mode 100644 index 0000000000..b61a0a9261 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_vp8.c @@ -0,0 +1,677 @@ +/* + * gstvaapidecoder_vp8.c - VP8 decoder + * + * Copyright (C) 2013-2014 Intel Corporation + * Author: Halley Zhao + * Author: Gwenole Beauchesne + * + * 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:gstvaapidecoder_vp8 + * @short_description: VP8 decoder + */ + +#include "sysdeps.h" +#include +#include "gstvaapidecoder_vp8.h" +#include "gstvaapidecoder_objects.h" +#include "gstvaapidecoder_priv.h" +#include "gstvaapidisplay_priv.h" + +#include "gstvaapicompat.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +#define GST_VAAPI_DECODER_VP8_CAST(decoder) \ + ((GstVaapiDecoderVp8 *)(decoder)) + +typedef struct _GstVaapiDecoderVp8Private GstVaapiDecoderVp8Private; +typedef struct _GstVaapiDecoderVp8Class GstVaapiDecoderVp8Class; + +struct _GstVaapiDecoderVp8Private +{ + GstVaapiProfile profile; + guint width; + guint height; + GstVp8Parser parser; + GstVp8FrameHdr frame_hdr; + GstVaapiPicture *last_picture; + GstVaapiPicture *golden_ref_picture; + GstVaapiPicture *alt_ref_picture; + GstVaapiPicture *current_picture; + guint size_changed:1; +}; + +/** + * GstVaapiDecoderVp8: + * + * A decoder based on Vp8. + */ +struct _GstVaapiDecoderVp8 +{ + /*< private > */ + GstVaapiDecoder parent_instance; + + GstVaapiDecoderVp8Private priv; +}; + +/** + * GstVaapiDecoderVp8Class: + * + * A decoder class based on Vp8. + */ +struct _GstVaapiDecoderVp8Class +{ + /*< private > */ + GstVaapiDecoderClass parent_class; +}; + +G_DEFINE_TYPE (GstVaapiDecoderVp8, gst_vaapi_decoder_vp8, + GST_TYPE_VAAPI_DECODER); + +static GstVaapiDecoderStatus +get_status (GstVp8ParserResult result) +{ + GstVaapiDecoderStatus status; + + switch (result) { + case GST_VP8_PARSER_OK: + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + break; + case GST_VP8_PARSER_ERROR: + status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + break; + default: + status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + break; + } + return status; +} + +static void +gst_vaapi_decoder_vp8_close (GstVaapiDecoderVp8 * decoder) +{ + GstVaapiDecoderVp8Private *const priv = &decoder->priv; + + gst_vaapi_picture_replace (&priv->last_picture, NULL); + gst_vaapi_picture_replace (&priv->golden_ref_picture, NULL); + gst_vaapi_picture_replace (&priv->alt_ref_picture, NULL); + gst_vaapi_picture_replace (&priv->current_picture, NULL); +} + +static gboolean +gst_vaapi_decoder_vp8_open (GstVaapiDecoderVp8 * decoder) +{ + GstVaapiDecoderVp8Private *const priv = &decoder->priv; + + gst_vaapi_decoder_vp8_close (decoder); + gst_vp8_parser_init (&priv->parser); + return TRUE; +} + +static void +gst_vaapi_decoder_vp8_destroy (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderVp8 *const decoder = GST_VAAPI_DECODER_VP8_CAST (base_decoder); + + gst_vaapi_decoder_vp8_close (decoder); +} + +static gboolean +gst_vaapi_decoder_vp8_create (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderVp8 *const decoder = GST_VAAPI_DECODER_VP8_CAST (base_decoder); + GstVaapiDecoderVp8Private *const priv = &decoder->priv; + + if (!gst_vaapi_decoder_vp8_open (decoder)) + return FALSE; + + priv->profile = GST_VAAPI_PROFILE_UNKNOWN; + return TRUE; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_vp8_reset (GstVaapiDecoder * base_decoder) +{ + gst_vaapi_decoder_vp8_destroy (base_decoder); + if (gst_vaapi_decoder_vp8_create (base_decoder)) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; +} + +static GstVaapiDecoderStatus +ensure_context (GstVaapiDecoderVp8 * decoder) +{ + GstVaapiDecoderVp8Private *const priv = &decoder->priv; + const GstVaapiProfile profile = GST_VAAPI_PROFILE_VP8; + const GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD; + gboolean reset_context = FALSE; + + if (priv->profile != profile) { + if (!gst_vaapi_display_has_decoder (GST_VAAPI_DECODER_DISPLAY (decoder), + profile, entrypoint)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + + priv->profile = profile; + reset_context = TRUE; + } + + if (priv->size_changed) { + GST_DEBUG ("size changed"); + priv->size_changed = FALSE; + reset_context = TRUE; + } + + if (reset_context) { + GstVaapiContextInfo info; + + info.profile = priv->profile; + info.entrypoint = entrypoint; + info.chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420; + info.width = priv->width; + info.height = priv->height; + info.ref_frames = 3; + reset_context = + gst_vaapi_decoder_ensure_context (GST_VAAPI_DECODER (decoder), &info); + + if (!reset_context) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +ensure_quant_matrix (GstVaapiDecoderVp8 * decoder, GstVaapiPicture * picture) +{ + GstVaapiDecoderVp8Private *const priv = &decoder->priv; + GstVp8FrameHdr *const frame_hdr = &priv->frame_hdr; + GstVp8Segmentation *const seg = &priv->parser.segmentation; + VAIQMatrixBufferVP8 *iq_matrix; + const gint8 QI_MAX = 127; + gint8 qi, qi_base; + gint i; + + picture->iq_matrix = GST_VAAPI_IQ_MATRIX_NEW (VP8, decoder); + if (!picture->iq_matrix) { + GST_ERROR ("failed to allocate IQ matrix"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + iq_matrix = picture->iq_matrix->param; + + /* Fill in VAIQMatrixBufferVP8 */ + for (i = 0; i < 4; i++) { + if (seg->segmentation_enabled) { + qi_base = seg->quantizer_update_value[i]; + if (!seg->segment_feature_mode) // 0 means delta update + qi_base += frame_hdr->quant_indices.y_ac_qi; + } else + qi_base = frame_hdr->quant_indices.y_ac_qi; + + qi = qi_base; + iq_matrix->quantization_index[i][0] = CLAMP (qi, 0, QI_MAX); + qi = qi_base + frame_hdr->quant_indices.y_dc_delta; + iq_matrix->quantization_index[i][1] = CLAMP (qi, 0, QI_MAX); + qi = qi_base + frame_hdr->quant_indices.y2_dc_delta; + iq_matrix->quantization_index[i][2] = CLAMP (qi, 0, QI_MAX); + qi = qi_base + frame_hdr->quant_indices.y2_ac_delta; + iq_matrix->quantization_index[i][3] = CLAMP (qi, 0, QI_MAX); + qi = qi_base + frame_hdr->quant_indices.uv_dc_delta; + iq_matrix->quantization_index[i][4] = CLAMP (qi, 0, QI_MAX); + qi = qi_base + frame_hdr->quant_indices.uv_ac_delta; + iq_matrix->quantization_index[i][5] = CLAMP (qi, 0, QI_MAX); + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +ensure_probability_table (GstVaapiDecoderVp8 * decoder, + GstVaapiPicture * picture) +{ + GstVaapiDecoderVp8Private *const priv = &decoder->priv; + GstVp8FrameHdr *const frame_hdr = &priv->frame_hdr; + VAProbabilityDataBufferVP8 *prob_table; + + picture->prob_table = GST_VAAPI_PROBABILITY_TABLE_NEW (VP8, decoder); + if (!picture->prob_table) { + GST_ERROR ("failed to allocate probality table"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + prob_table = picture->prob_table->param; + + /* Fill in VAProbabilityDataBufferVP8 */ + memcpy (prob_table->dct_coeff_probs, frame_hdr->token_probs.prob, + sizeof (frame_hdr->token_probs.prob)); + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static void +init_picture (GstVaapiDecoderVp8 * decoder, GstVaapiPicture * picture) +{ + GstVaapiDecoderVp8Private *const priv = &decoder->priv; + GstVp8FrameHdr *const frame_hdr = &priv->frame_hdr; + + picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME; + picture->type = frame_hdr->key_frame ? GST_VAAPI_PICTURE_TYPE_I : + GST_VAAPI_PICTURE_TYPE_P; + picture->pts = GST_VAAPI_DECODER_CODEC_FRAME (decoder)->pts; + + if (!frame_hdr->show_frame) + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_SKIPPED); +} + +static gboolean +fill_picture (GstVaapiDecoderVp8 * decoder, GstVaapiPicture * picture) +{ + GstVaapiDecoderVp8Private *const priv = &decoder->priv; + VAPictureParameterBufferVP8 *const pic_param = picture->param; + GstVp8Parser *const parser = &priv->parser; + GstVp8FrameHdr *const frame_hdr = &priv->frame_hdr; + GstVp8Segmentation *const seg = &parser->segmentation; + gint i; + + /* Fill in VAPictureParameterBufferVP8 */ + pic_param->frame_width = priv->width; + pic_param->frame_height = priv->height; + + pic_param->last_ref_frame = VA_INVALID_SURFACE; + pic_param->golden_ref_frame = VA_INVALID_SURFACE; + pic_param->alt_ref_frame = VA_INVALID_SURFACE; + if (!frame_hdr->key_frame) { + if (priv->last_picture) + pic_param->last_ref_frame = priv->last_picture->surface_id; + if (priv->golden_ref_picture) + pic_param->golden_ref_frame = priv->golden_ref_picture->surface_id; + if (priv->alt_ref_picture) + pic_param->alt_ref_frame = priv->alt_ref_picture->surface_id; + } + pic_param->out_of_loop_frame = VA_INVALID_SURFACE; // not used currently + + pic_param->pic_fields.value = 0; + pic_param->pic_fields.bits.key_frame = !frame_hdr->key_frame; + pic_param->pic_fields.bits.version = frame_hdr->version; + pic_param->pic_fields.bits.segmentation_enabled = seg->segmentation_enabled; + pic_param->pic_fields.bits.update_mb_segmentation_map = + seg->update_mb_segmentation_map; + pic_param->pic_fields.bits.update_segment_feature_data = + seg->update_segment_feature_data; + pic_param->pic_fields.bits.filter_type = frame_hdr->filter_type; + pic_param->pic_fields.bits.sharpness_level = frame_hdr->sharpness_level; + pic_param->pic_fields.bits.loop_filter_adj_enable = + parser->mb_lf_adjust.loop_filter_adj_enable; + pic_param->pic_fields.bits.mode_ref_lf_delta_update = + parser->mb_lf_adjust.mode_ref_lf_delta_update; + pic_param->pic_fields.bits.sign_bias_golden = frame_hdr->sign_bias_golden; + pic_param->pic_fields.bits.sign_bias_alternate = + frame_hdr->sign_bias_alternate; + pic_param->pic_fields.bits.mb_no_coeff_skip = frame_hdr->mb_no_skip_coeff; + + for (i = 0; i < 3; i++) + pic_param->mb_segment_tree_probs[i] = seg->segment_prob[i]; + + for (i = 0; i < 4; i++) { + gint8 level; + if (seg->segmentation_enabled) { + level = seg->lf_update_value[i]; + if (!seg->segment_feature_mode) // 0 means delta update + level += frame_hdr->loop_filter_level; + } else + level = frame_hdr->loop_filter_level; + pic_param->loop_filter_level[i] = CLAMP (level, 0, 63); + + pic_param->loop_filter_deltas_ref_frame[i] = + parser->mb_lf_adjust.ref_frame_delta[i]; + pic_param->loop_filter_deltas_mode[i] = + parser->mb_lf_adjust.mb_mode_delta[i]; + } + + /* In decoding, the only loop filter settings that matter are those + in the frame header (9.1) */ + pic_param->pic_fields.bits.loop_filter_disable = + frame_hdr->loop_filter_level == 0; + + pic_param->prob_skip_false = frame_hdr->prob_skip_false; + pic_param->prob_intra = frame_hdr->prob_intra; + pic_param->prob_last = frame_hdr->prob_last; + pic_param->prob_gf = frame_hdr->prob_gf; + + memcpy (pic_param->y_mode_probs, frame_hdr->mode_probs.y_prob, + sizeof (frame_hdr->mode_probs.y_prob)); + memcpy (pic_param->uv_mode_probs, frame_hdr->mode_probs.uv_prob, + sizeof (frame_hdr->mode_probs.uv_prob)); + memcpy (pic_param->mv_probs, frame_hdr->mv_probs.prob, + sizeof (frame_hdr->mv_probs)); + + pic_param->bool_coder_ctx.range = frame_hdr->rd_range; + pic_param->bool_coder_ctx.value = frame_hdr->rd_value; + pic_param->bool_coder_ctx.count = frame_hdr->rd_count; + + return TRUE; +} + +static gboolean +fill_slice (GstVaapiDecoderVp8 * decoder, GstVaapiSlice * slice) +{ + GstVaapiDecoderVp8Private *const priv = &decoder->priv; + VASliceParameterBufferVP8 *const slice_param = slice->param; + GstVp8FrameHdr *const frame_hdr = &priv->frame_hdr; + gint i; + + /* Fill in VASliceParameterBufferVP8 */ + slice_param->slice_data_offset = frame_hdr->data_chunk_size; + slice_param->macroblock_offset = frame_hdr->header_size; + slice_param->num_of_partitions = + (1 << frame_hdr->log2_nbr_of_dct_partitions) + 1; + + slice_param->partition_size[0] = + frame_hdr->first_part_size - ((slice_param->macroblock_offset + 7) >> 3); + for (i = 1; i < slice_param->num_of_partitions; i++) + slice_param->partition_size[i] = frame_hdr->partition_size[i - 1]; + for (; i < G_N_ELEMENTS (slice_param->partition_size); i++) + slice_param->partition_size[i] = 0; + + return TRUE; +} + +static GstVaapiDecoderStatus +decode_slice (GstVaapiDecoderVp8 * decoder, GstVaapiPicture * picture, + const guchar * buf, guint buf_size) +{ + GstVaapiSlice *slice; + + slice = GST_VAAPI_SLICE_NEW (VP8, decoder, buf, buf_size); + if (!slice) { + GST_ERROR ("failed to allocate slice"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + if (!fill_slice (decoder, slice)) { + gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (slice)); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + gst_vaapi_picture_add_slice (GST_VAAPI_PICTURE_CAST (picture), slice); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_picture (GstVaapiDecoderVp8 * decoder, const guchar * buf, + guint buf_size) +{ + GstVaapiDecoderVp8Private *const priv = &decoder->priv; + GstVaapiPicture *picture; + GstVaapiDecoderStatus status; + + status = ensure_context (decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + /* Create new picture */ + picture = GST_VAAPI_PICTURE_NEW (VP8, decoder); + if (!picture) { + GST_ERROR ("failed to allocate picture"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + gst_vaapi_picture_replace (&priv->current_picture, picture); + gst_vaapi_picture_unref (picture); + + status = ensure_quant_matrix (decoder, picture); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + status = ensure_probability_table (decoder, picture); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + init_picture (decoder, picture); + if (!fill_picture (decoder, picture)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + + return decode_slice (decoder, picture, buf, buf_size); +} + +static void +update_ref_frames (GstVaapiDecoderVp8 * decoder) +{ + GstVaapiDecoderVp8Private *const priv = &decoder->priv; + GstVaapiPicture *picture = priv->current_picture; + GstVp8FrameHdr *const frame_hdr = &priv->frame_hdr; + + // update picture reference + if (frame_hdr->key_frame) { + gst_vaapi_picture_replace (&priv->golden_ref_picture, picture); + gst_vaapi_picture_replace (&priv->alt_ref_picture, picture); + } else { + // process refresh_alternate_frame/copy_buffer_to_alternate first + if (frame_hdr->refresh_alternate_frame) { + gst_vaapi_picture_replace (&priv->alt_ref_picture, picture); + } else { + switch (frame_hdr->copy_buffer_to_alternate) { + case 0: + // do nothing + break; + case 1: + gst_vaapi_picture_replace (&priv->alt_ref_picture, + priv->last_picture); + break; + case 2: + gst_vaapi_picture_replace (&priv->alt_ref_picture, + priv->golden_ref_picture); + break; + default: + GST_WARNING + ("WARNING: VP8 decoder: unrecognized copy_buffer_to_alternate"); + } + } + + if (frame_hdr->refresh_golden_frame) { + gst_vaapi_picture_replace (&priv->golden_ref_picture, picture); + } else { + switch (frame_hdr->copy_buffer_to_golden) { + case 0: + // do nothing + break; + case 1: + gst_vaapi_picture_replace (&priv->golden_ref_picture, + priv->last_picture); + break; + case 2: + gst_vaapi_picture_replace (&priv->golden_ref_picture, + priv->alt_ref_picture); + break; + default: + GST_WARNING + ("WARNING: VP8 decoder: unrecognized copy_buffer_to_golden"); + } + } + } + if (frame_hdr->key_frame || frame_hdr->refresh_last) + gst_vaapi_picture_replace (&priv->last_picture, picture); +} + +static GstVaapiDecoderStatus +decode_current_picture (GstVaapiDecoderVp8 * decoder) +{ + GstVaapiDecoderVp8Private *const priv = &decoder->priv; + GstVaapiPicture *const picture = priv->current_picture; + + if (!picture) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + update_ref_frames (decoder); + if (!gst_vaapi_picture_decode (picture)) + goto error; + if (!gst_vaapi_picture_output (picture)) + goto error; + gst_vaapi_picture_replace (&priv->current_picture, NULL); + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + /* ERRORS */ +error: + { + /* XXX: fix for cases where first field failed to be decoded */ + gst_vaapi_picture_replace (&priv->current_picture, NULL); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } +} + +static GstVaapiDecoderStatus +parse_frame_header (GstVaapiDecoderVp8 * decoder, const guchar * buf, + guint buf_size, GstVp8FrameHdr * frame_hdr) +{ + GstVaapiDecoderVp8Private *const priv = &decoder->priv; + GstVp8ParserResult result; + + memset (frame_hdr, 0, sizeof (*frame_hdr)); + result = gst_vp8_parser_parse_frame_header (&priv->parser, frame_hdr, + buf, buf_size); + if (result != GST_VP8_PARSER_OK) + return get_status (result); + + if (frame_hdr->key_frame && + (frame_hdr->width != priv->width || frame_hdr->height != priv->height)) { + priv->width = frame_hdr->width; + priv->height = frame_hdr->height; + priv->size_changed = TRUE; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_vp8_parse (GstVaapiDecoder * base_decoder, + GstAdapter * adapter, gboolean at_eos, GstVaapiDecoderUnit * unit) +{ + guint flags = 0; + + unit->size = gst_adapter_available (adapter); + + /* The whole frame is available */ + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START; + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE; + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END; + GST_VAAPI_DECODER_UNIT_FLAG_SET (unit, flags); + return GST_VAAPI_DECODER_STATUS_SUCCESS; + +} + +static GstVaapiDecoderStatus +decode_buffer (GstVaapiDecoderVp8 * decoder, const guchar * buf, guint buf_size) +{ + GstVaapiDecoderVp8Private *const priv = &decoder->priv; + GstVaapiDecoderStatus status; + + status = parse_frame_header (decoder, buf, buf_size, &priv->frame_hdr); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + return decode_picture (decoder, buf, buf_size); +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_vp8_decode (GstVaapiDecoder * base_decoder, + GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderVp8 *const decoder = GST_VAAPI_DECODER_VP8_CAST (base_decoder); + GstVaapiDecoderStatus status; + GstBuffer *const buffer = + GST_VAAPI_DECODER_CODEC_FRAME (decoder)->input_buffer; + GstMapInfo map_info; + + if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) { + GST_ERROR ("failed to map buffer"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + status = decode_buffer (decoder, map_info.data + unit->offset, unit->size); + gst_buffer_unmap (buffer, &map_info); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_vp8_start_frame (GstVaapiDecoder * base_decoder, + GstVaapiDecoderUnit * base_unit) +{ + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_vp8_end_frame (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderVp8 *const decoder = GST_VAAPI_DECODER_VP8_CAST (base_decoder); + + return decode_current_picture (decoder); +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_vp8_flush (GstVaapiDecoder * base_decoder) +{ + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static void +gst_vaapi_decoder_vp8_finalize (GObject * object) +{ + GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (object); + + gst_vaapi_decoder_vp8_destroy (base_decoder); + G_OBJECT_CLASS (gst_vaapi_decoder_vp8_parent_class)->finalize (object); +} + +static void +gst_vaapi_decoder_vp8_class_init (GstVaapiDecoderVp8Class * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstVaapiDecoderClass *const decoder_class = GST_VAAPI_DECODER_CLASS (klass); + + object_class->finalize = gst_vaapi_decoder_vp8_finalize; + + decoder_class->reset = gst_vaapi_decoder_vp8_reset; + decoder_class->parse = gst_vaapi_decoder_vp8_parse; + decoder_class->decode = gst_vaapi_decoder_vp8_decode; + decoder_class->start_frame = gst_vaapi_decoder_vp8_start_frame; + decoder_class->end_frame = gst_vaapi_decoder_vp8_end_frame; + decoder_class->flush = gst_vaapi_decoder_vp8_flush; +} + +static void +gst_vaapi_decoder_vp8_init (GstVaapiDecoderVp8 * decoder) +{ + GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (decoder); + + gst_vaapi_decoder_vp8_create (base_decoder); +} + +/** + * gst_vaapi_decoder_vp8_new: + * @display: a #GstVaapiDisplay + * @caps: a #GstCaps holding codec information + * + * Creates a new #GstVaapiDecoder for VP8 decoding. The @caps can + * hold extra information like codec-data and pictured coded size. + * + * Return value: the newly allocated #GstVaapiDecoder object + */ +GstVaapiDecoder * +gst_vaapi_decoder_vp8_new (GstVaapiDisplay * display, GstCaps * caps) +{ + return g_object_new (GST_TYPE_VAAPI_DECODER_VP8, "display", display, + "caps", caps, NULL); +} diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_vp8.h b/gst-libs/gst/vaapi/gstvaapidecoder_vp8.h new file mode 100644 index 0000000000..9ba26470f0 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_vp8.h @@ -0,0 +1,50 @@ +/* + * gstvaapidecoder_vp8.h - VP8 decoder + * + * Copyright (C) 2013-2014 Intel Corporation + * Author: Halley Zhao + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODER_VP8_H +#define GST_VAAPI_DECODER_VP8_H + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_DECODER_VP8 \ + (gst_vaapi_decoder_vp8_get_type ()) +#define GST_VAAPI_DECODER_VP8(decoder) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DECODER_VP8, GstVaapiDecoderVp8)) +#define GST_VAAPI_IS_DECODER_VP8(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_DECODER_VP8)) + +typedef struct _GstVaapiDecoderVp8 GstVaapiDecoderVp8; + +GType +gst_vaapi_decoder_vp8_get_type (void) G_GNUC_CONST; + +GstVaapiDecoder * +gst_vaapi_decoder_vp8_new (GstVaapiDisplay * display, GstCaps * caps); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDecoderVp8, gst_object_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_DECODER_VP8_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_vp9.c b/gst-libs/gst/vaapi/gstvaapidecoder_vp9.c new file mode 100644 index 0000000000..3862cc26c2 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_vp9.c @@ -0,0 +1,833 @@ +/* + * gstvaapidecoder_vp9.c - VP9 decoder + * + * Copyright (C) 2014-2015 Intel Corporation + * Author: Sreerenj Balachandran + * + * 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:gstvaapidecoder_vp9 + * @short_description: VP9 decoder + */ + +#include "sysdeps.h" +#include +#include "gstvaapidecoder_vp9.h" +#include "gstvaapidecoder_objects.h" +#include "gstvaapidecoder_priv.h" +#include "gstvaapidisplay_priv.h" + +#include "gstvaapicompat.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +#define GST_VAAPI_DECODER_VP9_CAST(decoder) \ + ((GstVaapiDecoderVp9 *)(decoder)) + +typedef struct _GstVaapiDecoderVp9Private GstVaapiDecoderVp9Private; +typedef struct _GstVaapiDecoderVp9Class GstVaapiDecoderVp9Class; + +struct _GstVaapiDecoderVp9Private +{ + GstVaapiProfile profile; + guint width; + guint height; + GstVp9Parser *parser; + GstVp9FrameHdr frame_hdr; + GstVaapiPicture *current_picture; + GstVaapiPicture *ref_frames[GST_VP9_REF_FRAMES]; /* reference frames in ref_slots[max_ref] */ + + guint num_frames; /* number of frames in a super frame */ + guint frame_sizes[8]; /* size of frames in a super frame */ + guint frame_cnt; /* frame count variable for super frame */ + guint total_idx_size; /* super frame index size (full block size) */ + guint had_superframe_hdr:1; /* indicate the presense of super frame */ + + guint size_changed:1; +}; + +/** + * GstVaapiDecoderVp9: + * + * A decoder based on Vp9. + */ +struct _GstVaapiDecoderVp9 +{ + /*< private > */ + GstVaapiDecoder parent_instance; + + GstVaapiDecoderVp9Private priv; +}; + +/** + * GstVaapiDecoderVp9Class: + * + * A decoder class based on Vp9. + */ +struct _GstVaapiDecoderVp9Class +{ + /*< private > */ + GstVaapiDecoderClass parent_class; +}; + +G_DEFINE_TYPE (GstVaapiDecoderVp9, gst_vaapi_decoder_vp9, + GST_TYPE_VAAPI_DECODER); + +static GstVaapiDecoderStatus +get_status (GstVp9ParserResult result) +{ + GstVaapiDecoderStatus status; + + switch (result) { + case GST_VP9_PARSER_OK: + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + break; + case GST_VP9_PARSER_ERROR: + status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + break; + default: + status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + break; + } + return status; +} + +static void +gst_vaapi_decoder_vp9_close (GstVaapiDecoderVp9 * decoder) +{ + GstVaapiDecoderVp9Private *const priv = &decoder->priv; + guint i; + + for (i = 0; i < GST_VP9_REF_FRAMES; i++) + gst_vaapi_picture_replace (&priv->ref_frames[i], NULL); + + g_clear_pointer (&priv->parser, gst_vp9_parser_free); +} + +static gboolean +gst_vaapi_decoder_vp9_open (GstVaapiDecoderVp9 * decoder) +{ + GstVaapiDecoderVp9Private *const priv = &decoder->priv; + + gst_vaapi_decoder_vp9_close (decoder); + priv->parser = gst_vp9_parser_new (); + return TRUE; +} + +static void +gst_vaapi_decoder_vp9_destroy (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderVp9 *const decoder = GST_VAAPI_DECODER_VP9_CAST (base_decoder); + + gst_vaapi_decoder_vp9_close (decoder); +} + +static gboolean +gst_vaapi_decoder_vp9_create (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderVp9 *const decoder = GST_VAAPI_DECODER_VP9_CAST (base_decoder); + GstVaapiDecoderVp9Private *const priv = &decoder->priv; + + if (!gst_vaapi_decoder_vp9_open (decoder)) + return FALSE; + + priv->profile = GST_VAAPI_PROFILE_UNKNOWN; + return TRUE; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_vp9_reset (GstVaapiDecoder * base_decoder) +{ + gst_vaapi_decoder_vp9_destroy (base_decoder); + if (gst_vaapi_decoder_vp9_create (base_decoder)) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; +} + +/* Returns GstVaapiProfile from VP9 frame_hdr profile value */ +static GstVaapiProfile +get_profile (guint profile_idc) +{ + GstVaapiProfile profile; + + switch (profile_idc) { + case GST_VP9_PROFILE_0: + profile = GST_VAAPI_PROFILE_VP9_0; + break; + case GST_VP9_PROFILE_1: + profile = GST_VAAPI_PROFILE_VP9_1; + break; + case GST_VP9_PROFILE_2: + profile = GST_VAAPI_PROFILE_VP9_2; + break; + case GST_VP9_PROFILE_3: + profile = GST_VAAPI_PROFILE_VP9_3; + break; + default: + GST_DEBUG ("unsupported profile_idc value"); + profile = GST_VAAPI_PROFILE_UNKNOWN; + break; + } + return profile; +} + +static gboolean +get_chroma_type (GstVp9FrameHdr * frame_hdr, GstVp9Parser * parser, + GstVaapiContextInfo * info) +{ + switch (frame_hdr->profile) { + case GST_VP9_PROFILE_0: + info->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420; + break; + case GST_VP9_PROFILE_1: + if (parser->subsampling_x == 1 && parser->subsampling_y == 0) + info->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV422; + else if (parser->subsampling_x == 0 && parser->subsampling_y == 0) + info->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV444; + else + return FALSE; + break; + case GST_VP9_PROFILE_2: + if (parser->bit_depth == 10) + info->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420_10BPP; + else + info->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420_12BPP; + break; + case GST_VP9_PROFILE_3: + if (parser->subsampling_x == 1 && parser->subsampling_y == 0) { + if (parser->bit_depth == 10) + info->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV422_10BPP; + else + info->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV422_12BPP; + } else if (parser->subsampling_x == 0 && parser->subsampling_y == 0) { + if (parser->bit_depth == 10) + info->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV444_10BPP; + else + info->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV444_12BPP; + } else + return FALSE; + break; + default: + return FALSE; + break; + } + return TRUE; +} + +static GstVaapiDecoderStatus +ensure_context (GstVaapiDecoderVp9 * decoder) +{ + GstVaapiDecoderVp9Private *const priv = &decoder->priv; + GstVp9FrameHdr *frame_hdr = &priv->frame_hdr; + GstVp9Parser *parser = priv->parser; + GstVaapiProfile profile; + const GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD; + gboolean reset_context = FALSE; + + profile = get_profile (frame_hdr->profile); + + if (priv->profile != profile) { + if (!gst_vaapi_display_has_decoder (GST_VAAPI_DECODER_DISPLAY (decoder), + profile, entrypoint)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + + priv->profile = profile; + reset_context = TRUE; + } + + if (priv->size_changed) { + GST_DEBUG ("size changed"); + priv->size_changed = FALSE; + reset_context = TRUE; + } + + if (reset_context) { + GstVaapiContextInfo info; + + info.profile = priv->profile; + info.entrypoint = entrypoint; + info.width = priv->width; + info.height = priv->height; + info.ref_frames = 8; + if (!get_chroma_type (frame_hdr, parser, &info)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT; + + reset_context = + gst_vaapi_decoder_ensure_context (GST_VAAPI_DECODER (decoder), &info); + + if (!reset_context) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + + gst_vaapi_context_reset_on_resize (GST_VAAPI_DECODER_CONTEXT (decoder), + FALSE); + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static void +init_picture (GstVaapiDecoderVp9 * decoder, GstVaapiPicture * picture) +{ + GstVaapiDecoderVp9Private *const priv = &decoder->priv; + GstVp9FrameHdr *const frame_hdr = &priv->frame_hdr; + + picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME; + picture->type = + (frame_hdr->frame_type == + GST_VP9_KEY_FRAME) ? GST_VAAPI_PICTURE_TYPE_I : GST_VAAPI_PICTURE_TYPE_P; + picture->pts = GST_VAAPI_DECODER_CODEC_FRAME (decoder)->pts; + + if (!frame_hdr->show_frame) + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_SKIPPED); +} + +static void +vaapi_fill_ref_frames (GstVaapiDecoderVp9 * decoder, GstVaapiPicture * picture, + GstVp9FrameHdr * frame_hdr, VADecPictureParameterBufferVP9 * pic_param) +{ + GstVaapiDecoderVp9Private *const priv = &decoder->priv; + guint i; + + if (frame_hdr->frame_type != GST_VP9_KEY_FRAME) { + pic_param->pic_fields.bits.last_ref_frame = + frame_hdr->ref_frame_indices[GST_VP9_REF_FRAME_LAST - 1]; + pic_param->pic_fields.bits.last_ref_frame_sign_bias = + frame_hdr->ref_frame_sign_bias[GST_VP9_REF_FRAME_LAST - 1]; + pic_param->pic_fields.bits.golden_ref_frame = + frame_hdr->ref_frame_indices[GST_VP9_REF_FRAME_GOLDEN - 1]; + pic_param->pic_fields.bits.golden_ref_frame_sign_bias = + frame_hdr->ref_frame_sign_bias[GST_VP9_REF_FRAME_GOLDEN - 1]; + pic_param->pic_fields.bits.alt_ref_frame = + frame_hdr->ref_frame_indices[GST_VP9_REF_FRAME_ALTREF - 1]; + pic_param->pic_fields.bits.alt_ref_frame_sign_bias = + frame_hdr->ref_frame_sign_bias[GST_VP9_REF_FRAME_ALTREF - 1]; + } + + for (i = 0; i < G_N_ELEMENTS (priv->ref_frames); i++) { + pic_param->reference_frames[i] = priv->ref_frames[i] ? + priv->ref_frames[i]->surface_id : VA_INVALID_SURFACE; + } +} + +static gboolean +fill_picture (GstVaapiDecoderVp9 * decoder, GstVaapiPicture * picture) +{ + GstVaapiDecoderVp9Private *priv = &decoder->priv; + VADecPictureParameterBufferVP9 *pic_param = picture->param; + GstVp9Parser *parser = priv->parser; + GstVp9FrameHdr *frame_hdr = &priv->frame_hdr; + + /* Fill in VAPictureParameterBufferVP9 */ + pic_param->frame_width = frame_hdr->width; + pic_param->frame_height = frame_hdr->height; + + /* Fill in ReferenceFrames */ + vaapi_fill_ref_frames (decoder, picture, frame_hdr, pic_param); + +#define COPY_FIELD(s, f) \ + pic_param->f = (s)->f +#define COPY_BFM(a, s, f) \ + pic_param->a.bits.f = (s)->f + + COPY_BFM (pic_fields, parser, subsampling_x); + COPY_BFM (pic_fields, parser, subsampling_y); + COPY_BFM (pic_fields, frame_hdr, frame_type); + COPY_BFM (pic_fields, frame_hdr, show_frame); + COPY_BFM (pic_fields, frame_hdr, error_resilient_mode); + COPY_BFM (pic_fields, frame_hdr, intra_only); + COPY_BFM (pic_fields, frame_hdr, allow_high_precision_mv); + COPY_BFM (pic_fields, frame_hdr, mcomp_filter_type); + COPY_BFM (pic_fields, frame_hdr, frame_parallel_decoding_mode); + COPY_BFM (pic_fields, frame_hdr, reset_frame_context); + COPY_BFM (pic_fields, frame_hdr, refresh_frame_context); + COPY_BFM (pic_fields, frame_hdr, frame_context_idx); + COPY_BFM (pic_fields, frame_hdr, lossless_flag); + + pic_param->pic_fields.bits.segmentation_enabled = + frame_hdr->segmentation.enabled; + pic_param->pic_fields.bits.segmentation_temporal_update = + frame_hdr->segmentation.temporal_update; + pic_param->pic_fields.bits.segmentation_update_map = + frame_hdr->segmentation.update_map; + + COPY_FIELD (&frame_hdr->loopfilter, filter_level); + COPY_FIELD (&frame_hdr->loopfilter, sharpness_level); + COPY_FIELD (frame_hdr, log2_tile_rows); + COPY_FIELD (frame_hdr, log2_tile_columns); + COPY_FIELD (frame_hdr, frame_header_length_in_bytes); + COPY_FIELD (frame_hdr, first_partition_size); + COPY_FIELD (frame_hdr, profile); +#if VA_CHECK_VERSION (0, 39, 0) + COPY_FIELD (parser, bit_depth); +#endif + + g_assert (G_N_ELEMENTS (pic_param->mb_segment_tree_probs) == + G_N_ELEMENTS (parser->mb_segment_tree_probs)); + g_assert (G_N_ELEMENTS (pic_param->segment_pred_probs) == + G_N_ELEMENTS (parser->segment_pred_probs)); + + memcpy (pic_param->mb_segment_tree_probs, parser->mb_segment_tree_probs, + sizeof (parser->mb_segment_tree_probs)); + + if (frame_hdr->segmentation.temporal_update) { + memcpy (pic_param->segment_pred_probs, parser->segment_pred_probs, + sizeof (parser->segment_pred_probs)); + } else { + memset (pic_param->segment_pred_probs, 255, + sizeof (pic_param->segment_pred_probs)); + } + + return TRUE; +} + +static gboolean +fill_slice (GstVaapiDecoderVp9 * decoder, GstVaapiSlice * slice) +{ + GstVaapiDecoderVp9Private *const priv = &decoder->priv; + GstVp9Parser *parser = priv->parser; + VASliceParameterBufferVP9 *const slice_param = slice->param; + guint i; + +#define COPY_SEG_FIELD(s, f) \ + seg_param->f = (s)->f + + /* Fill in VASliceParameterBufferVP9 */ + for (i = 0; i < GST_VP9_MAX_SEGMENTS; i++) { + VASegmentParameterVP9 *seg_param = &slice_param->seg_param[i]; + GstVp9Segmentation *seg = &parser->segmentation[i]; + + memcpy (seg_param->filter_level, seg->filter_level, + sizeof (seg->filter_level)); + COPY_SEG_FIELD (seg, luma_ac_quant_scale); + COPY_SEG_FIELD (seg, luma_dc_quant_scale); + COPY_SEG_FIELD (seg, chroma_ac_quant_scale); + COPY_SEG_FIELD (seg, chroma_dc_quant_scale); + + seg_param->segment_flags.fields.segment_reference_skipped = + seg->reference_skip; + seg_param->segment_flags.fields.segment_reference_enabled = + seg->reference_frame_enabled; + seg_param->segment_flags.fields.segment_reference = seg->reference_frame; + + } + /* Fixme: When segmentation is disabled, only seg_param[0] has valid values, + * all other entries should be populated with 0 ? */ + + return TRUE; +} + +static GstVaapiDecoderStatus +decode_slice (GstVaapiDecoderVp9 * decoder, GstVaapiPicture * picture, + const guchar * buf, guint buf_size) +{ + GstVaapiSlice *slice; + + slice = GST_VAAPI_SLICE_NEW (VP9, decoder, buf, buf_size); + if (!slice) { + GST_ERROR ("failed to allocate slice"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + if (!fill_slice (decoder, slice)) { + gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (slice)); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + gst_vaapi_picture_add_slice (GST_VAAPI_PICTURE_CAST (picture), slice); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static void +update_ref_frames (GstVaapiDecoderVp9 * decoder) +{ + GstVaapiDecoderVp9Private *const priv = &decoder->priv; + GstVaapiPicture *picture = priv->current_picture; + GstVp9FrameHdr *const frame_hdr = &priv->frame_hdr; + guint8 refresh_frame_flags, mask, i = 0; + + if (frame_hdr->frame_type == GST_VP9_KEY_FRAME) + refresh_frame_flags = (1 << GST_VP9_REF_FRAMES) - 1; + else + refresh_frame_flags = frame_hdr->refresh_frame_flags; + + for (mask = refresh_frame_flags; mask; mask >>= 1, ++i) { + if (mask & 1) + gst_vaapi_picture_replace (&priv->ref_frames[i], picture); + } +} + +#ifdef GST_VAAPI_PICTURE_NEW +#undef GST_VAAPI_PICTURE_NEW +#endif + +#define GST_VAAPI_PICTURE_NEW(codec, decoder) \ + gst_vaapi_picture_new (GST_VAAPI_DECODER_CAST (decoder), \ + NULL, sizeof (G_PASTE (VADecPictureParameterBuffer, codec))) + +static GstVaapiDecoderStatus +decode_picture (GstVaapiDecoderVp9 * decoder, const guchar * buf, + guint buf_size) +{ + GstVaapiDecoderVp9Private *const priv = &decoder->priv; + GstVp9FrameHdr *frame_hdr = &priv->frame_hdr; + GstVaapiPicture *picture; + GstVaapiDecoderStatus status; + guint crop_width = 0, crop_height = 0; + gboolean is_clone_pic = FALSE; + + status = ensure_context (decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + /* if show_exising_frame flag is true, we just need to return + * the existing frame in ref frame array, so creating a clone + * of already decoded frame */ + if (frame_hdr->show_existing_frame) { + GstVaapiPicture *existing_frame = + priv->ref_frames[frame_hdr->frame_to_show]; + + if (!existing_frame) { + GST_ERROR ("Failed to get the existing frame from dpb"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + picture = gst_vaapi_picture_new_clone (existing_frame); + if (!picture) { + GST_ERROR ("Failed to create clone picture"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + is_clone_pic = TRUE; + + /* for cloned picture we should always unset the skip flag since + * the previously decoded frame might be decode-only but repeat-frame + * should make it ready for display */ + GST_VAAPI_PICTURE_FLAG_UNSET (picture, GST_VAAPI_PICTURE_FLAG_SKIPPED); + + /* reset picture pts with whatever set in VideoCodecFrame */ + picture->pts = GST_VAAPI_DECODER_CODEC_FRAME (decoder)->pts; + } else { + /* Create new picture */ + picture = GST_VAAPI_PICTURE_NEW (VP9, decoder); + if (!picture) { + GST_ERROR ("failed to allocate picture"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + } + gst_vaapi_picture_replace (&priv->current_picture, picture); + gst_vaapi_picture_unref (picture); + + if (is_clone_pic) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + if (priv->width > frame_hdr->width || priv->height > frame_hdr->height) { + crop_width = frame_hdr->width; + crop_height = frame_hdr->height; + } + if (crop_width || crop_height) { + GstVaapiRectangle crop_rect; + crop_rect.x = 0; + crop_rect.y = 0; + crop_rect.width = crop_width; + crop_rect.height = crop_height; + gst_vaapi_picture_set_crop_rect (picture, &crop_rect); + } + + init_picture (decoder, picture); + if (!fill_picture (decoder, picture)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + + return decode_slice (decoder, picture, buf, buf_size); +} + + +static GstVaapiDecoderStatus +decode_current_picture (GstVaapiDecoderVp9 * decoder) +{ + GstVaapiDecoderVp9Private *const priv = &decoder->priv; + GstVaapiPicture *const picture = priv->current_picture; + GstVp9FrameHdr *const frame_hdr = &priv->frame_hdr; + + if (!picture) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + if (frame_hdr->show_existing_frame) + goto ret; + + if (!gst_vaapi_picture_decode (picture)) + goto error; + + update_ref_frames (decoder); + +ret: + if (!gst_vaapi_picture_output (picture)) + goto error; + + gst_vaapi_picture_replace (&priv->current_picture, NULL); + + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + /* ERRORS */ +error: + { + /* XXX: fix for cases where first field failed to be decoded */ + gst_vaapi_picture_replace (&priv->current_picture, NULL); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } +} + +static gboolean +parse_super_frame (const guchar * data, guint data_size, + guint * frame_sizes, guint * frame_count, guint * total_idx_size) +{ + guint8 marker; + guint32 num_frames = 1, frame_size_length, total_index_size; + guint i, j; + + if (data_size <= 0) + return FALSE; + + marker = data[data_size - 1]; + + if ((marker & 0xe0) == 0xc0) { + + GST_DEBUG ("Got VP9-Super Frame, size %d", data_size); + + num_frames = (marker & 0x7) + 1; + frame_size_length = ((marker >> 3) & 0x3) + 1; + total_index_size = 2 + num_frames * frame_size_length; + + if ((data_size >= total_index_size) + && (data[data_size - total_index_size] == marker)) { + const guint8 *x = &data[data_size - total_index_size + 1]; + + for (i = 0; i < num_frames; i++) { + guint32 cur_frame_size = 0; + + for (j = 0; j < frame_size_length; j++) + cur_frame_size |= (*x++) << (j * 8); + + frame_sizes[i] = cur_frame_size; + } + + *frame_count = num_frames; + *total_idx_size = total_index_size; + } else { + GST_ERROR ("Failed to parse Super-frame"); + return FALSE; + } + } else { + *frame_count = num_frames; + frame_sizes[0] = data_size; + *total_idx_size = 0; + } + + return TRUE; +} + +static GstVaapiDecoderStatus +parse_frame_header (GstVaapiDecoderVp9 * decoder, const guchar * buf, + guint buf_size, GstVp9FrameHdr * frame_hdr) +{ + GstVaapiDecoderVp9Private *const priv = &decoder->priv; + GstVp9ParserResult result; + guint width, height; + + result = gst_vp9_parser_parse_frame_header (priv->parser, frame_hdr, + buf, buf_size); + if (result != GST_VP9_PARSER_OK) + return get_status (result); + + /* Unlike other decoders, vp9 decoder doesn't need to reset the + * whole context and surfaces for each resolution change. Calling + * ensure_context() again is only needed if the resolution of any frame + * is greater than what was previously configured, so that new, larger + * surfaces can be allocated. There are streams where a bigger + * resolution set in ivf header or webm header but actual resolution + * of all frames are less. Also it is possible to have inter-prediction + * between these multi resolution frames */ + width = GST_VAAPI_DECODER_WIDTH (decoder); + height = GST_VAAPI_DECODER_HEIGHT (decoder); + if (priv->width < width || priv->height < height) { + priv->width = GST_VAAPI_DECODER_WIDTH (decoder); + priv->height = GST_VAAPI_DECODER_HEIGHT (decoder); + priv->size_changed = TRUE; + } + if ((frame_hdr->width > priv->width || frame_hdr->height > priv->height)) { + priv->width = frame_hdr->width; + priv->height = frame_hdr->height; + priv->size_changed = TRUE; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_vp9_parse (GstVaapiDecoder * base_decoder, + GstAdapter * adapter, gboolean at_eos, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderVp9 *const decoder = GST_VAAPI_DECODER_VP9_CAST (base_decoder); + GstVaapiDecoderVp9Private *const priv = &decoder->priv; + guchar *buf; + guint buf_size, flags = 0; + + buf_size = gst_adapter_available (adapter); + if (!buf_size) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + buf = (guchar *) gst_adapter_map (adapter, buf_size); + if (!buf) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + + if (!priv->had_superframe_hdr) { + if (!parse_super_frame (buf, buf_size, priv->frame_sizes, &priv->num_frames, + &priv->total_idx_size)) + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + + if (priv->num_frames > 1) + priv->had_superframe_hdr = TRUE; + } + + unit->size = priv->frame_sizes[priv->frame_cnt++]; + + if (priv->frame_cnt == priv->num_frames) { + priv->num_frames = 0; + priv->frame_cnt = 0; + priv->had_superframe_hdr = FALSE; + unit->size += priv->total_idx_size; + } + + /* The whole frame is available */ + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START; + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE; + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END; + + GST_VAAPI_DECODER_UNIT_FLAG_SET (unit, flags); + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_buffer (GstVaapiDecoderVp9 * decoder, const guchar * buf, guint buf_size) +{ + GstVaapiDecoderVp9Private *const priv = &decoder->priv; + GstVaapiDecoderStatus status; + guint size = buf_size; + + if (priv->total_idx_size && !priv->had_superframe_hdr) { + size -= priv->total_idx_size; + priv->total_idx_size = 0; + } + + status = parse_frame_header (decoder, buf, size, &priv->frame_hdr); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + return decode_picture (decoder, buf, size); +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_vp9_decode (GstVaapiDecoder * base_decoder, + GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderVp9 *const decoder = GST_VAAPI_DECODER_VP9_CAST (base_decoder); + GstVaapiDecoderStatus status; + GstBuffer *const buffer = + GST_VAAPI_DECODER_CODEC_FRAME (decoder)->input_buffer; + GstMapInfo map_info; + + if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) { + GST_ERROR ("failed to map buffer"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + status = decode_buffer (decoder, map_info.data + unit->offset, unit->size); + gst_buffer_unmap (buffer, &map_info); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_vp9_start_frame (GstVaapiDecoder * base_decoder, + GstVaapiDecoderUnit * base_unit) +{ + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_vp9_end_frame (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderVp9 *const decoder = GST_VAAPI_DECODER_VP9_CAST (base_decoder); + + return decode_current_picture (decoder); +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_vp9_flush (GstVaapiDecoder * base_decoder) +{ + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static void +gst_vaapi_decoder_vp9_finalize (GObject * object) +{ + GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (object); + + gst_vaapi_decoder_vp9_destroy (base_decoder); + G_OBJECT_CLASS (gst_vaapi_decoder_vp9_parent_class)->finalize (object); +} + +static void +gst_vaapi_decoder_vp9_class_init (GstVaapiDecoderVp9Class * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstVaapiDecoderClass *const decoder_class = GST_VAAPI_DECODER_CLASS (klass); + + object_class->finalize = gst_vaapi_decoder_vp9_finalize; + + decoder_class->reset = gst_vaapi_decoder_vp9_reset; + decoder_class->parse = gst_vaapi_decoder_vp9_parse; + decoder_class->decode = gst_vaapi_decoder_vp9_decode; + decoder_class->start_frame = gst_vaapi_decoder_vp9_start_frame; + decoder_class->end_frame = gst_vaapi_decoder_vp9_end_frame; + decoder_class->flush = gst_vaapi_decoder_vp9_flush; +} + +static void +gst_vaapi_decoder_vp9_init (GstVaapiDecoderVp9 * decoder) +{ + GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (decoder); + + gst_vaapi_decoder_vp9_create (base_decoder); +} + +/** + * gst_vaapi_decoder_vp9_new: + * @display: a #GstVaapiDisplay + * @caps: a #GstCaps holding codec information + * + * Creates a new #GstVaapiDecoder for VP9 decoding. The @caps can + * hold extra information like codec-data and pictured coded size. + * + * Return value: the newly allocated #GstVaapiDecoder object + */ +GstVaapiDecoder * +gst_vaapi_decoder_vp9_new (GstVaapiDisplay * display, GstCaps * caps) +{ + return g_object_new (GST_TYPE_VAAPI_DECODER_VP9, "display", display, + "caps", caps, NULL); +} diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_vp9.h b/gst-libs/gst/vaapi/gstvaapidecoder_vp9.h new file mode 100644 index 0000000000..f00ce739d2 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_vp9.h @@ -0,0 +1,49 @@ +/* + * gstvaapidecoder_vp9.h - VP9 decoder + * + * Copyright (C) 2015-2016 Intel Corporation + * Author: Sreerenj Balachandran + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODER_VP9_H +#define GST_VAAPI_DECODER_VP9_H + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_DECODER_VP9 \ + (gst_vaapi_decoder_vp9_get_type ()) +#define GST_VAAPI_DECODER_VP9(decoder) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DECODER_VP9, GstVaapiDecoderVp9)) +#define GST_VAAPI_IS_DECODER_VP9(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_DECODER_VP9)) + +typedef struct _GstVaapiDecoderVp9 GstVaapiDecoderVp9; + +GType +gst_vaapi_decoder_vp9_get_type (void) G_GNUC_CONST; + +GstVaapiDecoder * +gst_vaapi_decoder_vp9_new (GstVaapiDisplay * display, GstCaps * caps); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDecoderVp9, gst_object_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_DECODER_VP9_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidisplay.c b/gst-libs/gst/vaapi/gstvaapidisplay.c new file mode 100644 index 0000000000..878761af83 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay.c @@ -0,0 +1,2185 @@ +/* + * gstvaapidisplay.c - VA display abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapidisplay + * @short_description: VA display abstraction + */ + +#include "sysdeps.h" +#include "gstvaapiutils.h" +#include "gstvaapivalue.h" +#include "gstvaapidisplay.h" +#include "gstvaapitexturemap.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapiworkarounds.h" + +/* Debug category for all vaapi libs */ +GST_DEBUG_CATEGORY (gst_debug_vaapi); + +/* Debug category for VaapiDisplay */ +GST_DEBUG_CATEGORY (gst_debug_vaapi_display); +#define GST_CAT_DEFAULT gst_debug_vaapi_display + +#define _do_init \ + G_ADD_PRIVATE (GstVaapiDisplay); \ + GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi_display, \ + "vaapidisplay", 0, "VA-API Display"); \ + GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi, "vaapi", 0, "VA-API helper"); + +G_DEFINE_TYPE_WITH_CODE (GstVaapiDisplay, gst_vaapi_display, GST_TYPE_OBJECT, + _do_init); + +typedef struct _GstVaapiProfileConfig GstVaapiProfileConfig; +struct _GstVaapiProfileConfig +{ + GstVaapiProfile profile; + guint32 entrypoints; /* bits map of GstVaapiEntrypoint */ +}; + +typedef struct _GstVaapiProperty GstVaapiProperty; +struct _GstVaapiProperty +{ + const gchar *name; + VADisplayAttribute attribute; + gint old_value; +}; + +typedef struct _GstVaapiFormatInfo GstVaapiFormatInfo; +struct _GstVaapiFormatInfo +{ + GstVideoFormat format; + guint flags; +}; + +#define DEFAULT_RENDER_MODE GST_VAAPI_RENDER_MODE_TEXTURE +#define DEFAULT_ROTATION GST_VAAPI_ROTATION_0 + +#define ENTRY_POINT_FLAG(entry) (1U << G_PASTE(GST_VAAPI_ENTRYPOINT_, entry)) + +enum +{ + PROP_RENDER_MODE = 1, + PROP_ROTATION, + PROP_HUE, + PROP_SATURATION, + PROP_BRIGHTNESS, + PROP_CONTRAST, + PROP_VA_DISPLAY, + + N_PROPERTIES +}; + +static GParamSpec *g_properties[N_PROPERTIES] = { NULL, }; + +static gboolean +get_attribute (GstVaapiDisplay * display, VADisplayAttribType type, + gint * value); + +static gboolean +set_attribute (GstVaapiDisplay * display, VADisplayAttribType type, gint value); + +static gboolean +get_color_balance (GstVaapiDisplay * display, guint prop_id, gfloat * v); + +static gboolean +set_color_balance (GstVaapiDisplay * display, guint prop_id, gfloat v); + +/* GstVaapiDisplayType enumerations */ +GType +gst_vaapi_display_type_get_type (void) +{ + static GType g_type = 0; + + static const GEnumValue display_types[] = { + {GST_VAAPI_DISPLAY_TYPE_ANY, + "Auto detection", "any"}, +#if USE_X11 + {GST_VAAPI_DISPLAY_TYPE_X11, + "VA/X11 display", "x11"}, +#endif +#if USE_GLX + {GST_VAAPI_DISPLAY_TYPE_GLX, + "VA/GLX display", "glx"}, +#endif +#if USE_EGL + {GST_VAAPI_DISPLAY_TYPE_EGL, + "VA/EGL display", "egl"}, +#endif +#if USE_WAYLAND + {GST_VAAPI_DISPLAY_TYPE_WAYLAND, + "VA/Wayland display", "wayland"}, +#endif +#if USE_DRM + {GST_VAAPI_DISPLAY_TYPE_DRM, + "VA/DRM display", "drm"}, +#endif + {0, NULL, NULL}, + }; + + if (!g_type) + g_type = g_enum_register_static ("GstVaapiDisplayType", display_types); + return g_type; +} + +/** + * gst_vaapi_display_type_is_compatible: + * @type1: the #GstVaapiDisplayType to test + * @type2: the reference #GstVaapiDisplayType + * + * Compares whether #GstVaapiDisplay @type1 is compatible with @type2. + * That is, if @type2 is in "any" category, or derived from @type1. + * + * Returns: %TRUE if @type1 is compatible with @type2, %FALSE otherwise. + */ +gboolean +gst_vaapi_display_type_is_compatible (GstVaapiDisplayType type1, + GstVaapiDisplayType type2) +{ + if (type1 == type2) + return TRUE; + + switch (type1) { + case GST_VAAPI_DISPLAY_TYPE_GLX: + if (type2 == GST_VAAPI_DISPLAY_TYPE_X11) + return TRUE; + break; + default: + break; + } + return type2 == GST_VAAPI_DISPLAY_TYPE_ANY; +} + +/* Append GstVideoFormat to formats array */ +static inline void +append_format (GArray * formats, GstVideoFormat format, guint flags) +{ + GstVaapiFormatInfo fi; + + fi.format = format; + fi.flags = flags; + g_array_append_val (formats, fi); +} + +/* Append VAImageFormats to formats array */ +static void +append_formats (GArray * formats, const VAImageFormat * va_formats, + guint * flags, guint n) +{ + GstVideoFormat format; + int YV12_idx = -1; + int I420_idx = -1; + const GstVaapiFormatInfo *fip; + guint i; + + for (i = 0; i < n; i++) { + const VAImageFormat *const va_format = &va_formats[i]; + + format = gst_vaapi_video_format_from_va_format (va_format); + if (format == GST_VIDEO_FORMAT_UNKNOWN) { + GST_DEBUG ("unsupported format %" GST_FOURCC_FORMAT, + GST_FOURCC_ARGS (va_format->fourcc)); + continue; + } + append_format (formats, format, flags ? flags[i] : 0); + + switch (format) { + case GST_VIDEO_FORMAT_YV12: + YV12_idx = formats->len - 1; + break; + case GST_VIDEO_FORMAT_I420: + I420_idx = formats->len - 1; + break; + default: + break; + } + } + + /* Append I420 (resp. YV12) format if YV12 (resp. I420) is not + supported by the underlying driver */ + if ((YV12_idx != -1) && (I420_idx == -1)) { + fip = &g_array_index (formats, GstVaapiFormatInfo, YV12_idx); + append_format (formats, GST_VIDEO_FORMAT_I420, fip->flags); + } else if ((I420_idx != -1) && (YV12_idx == -1)) { + fip = &g_array_index (formats, GstVaapiFormatInfo, I420_idx); + append_format (formats, GST_VIDEO_FORMAT_YV12, fip->flags); + } +} + +/* Sort image formats. Prefer YUV formats first */ +static gint +compare_yuv_formats (gconstpointer a, gconstpointer b) +{ + const GstVideoFormat fmt1 = ((GstVaapiFormatInfo *) a)->format; + const GstVideoFormat fmt2 = ((GstVaapiFormatInfo *) b)->format; + + const gboolean is_fmt1_yuv = gst_vaapi_video_format_is_yuv (fmt1); + const gboolean is_fmt2_yuv = gst_vaapi_video_format_is_yuv (fmt2); + + if (is_fmt1_yuv != is_fmt2_yuv) + return is_fmt1_yuv ? -1 : 1; + + return ((gint) gst_vaapi_video_format_get_score (fmt1) - + (gint) gst_vaapi_video_format_get_score (fmt2)); +} + +/* Sort subpicture formats. Prefer RGB formats first */ +static gint +compare_rgb_formats (gconstpointer a, gconstpointer b) +{ + const GstVideoFormat fmt1 = ((GstVaapiFormatInfo *) a)->format; + const GstVideoFormat fmt2 = ((GstVaapiFormatInfo *) b)->format; + + const gboolean is_fmt1_rgb = gst_vaapi_video_format_is_rgb (fmt1); + const gboolean is_fmt2_rgb = gst_vaapi_video_format_is_rgb (fmt2); + + if (is_fmt1_rgb != is_fmt2_rgb) + return is_fmt1_rgb ? -1 : 1; + + return ((gint) gst_vaapi_video_format_get_score (fmt1) - + (gint) gst_vaapi_video_format_get_score (fmt2)); +} + +/* Check if configs array contains profile at entrypoint */ +static inline gboolean +find_config (GPtrArray * configs, GstVaapiProfile profile, + GstVaapiEntrypoint entrypoint) +{ + GstVaapiProfileConfig *config; + guint i; + + if (!configs) + return FALSE; + + for (i = 0; i < configs->len; i++) { + config = g_ptr_array_index (configs, i); + if (config->profile == profile + && (config->entrypoints & (1U << entrypoint))) + return TRUE; + } + return FALSE; +} + +/* HACK: append H.263 Baseline profile if MPEG-4:2 Simple profile is supported */ +static void +append_h263_config (GArray * configs, GPtrArray * decoders) +{ + GstVaapiProfileConfig *config, tmp_config; + GstVaapiProfileConfig *mpeg4_simple_config = NULL; + GstVaapiProfileConfig *h263_baseline_config = NULL; + guint i; + + if (!WORKAROUND_H263_BASELINE_DECODE_PROFILE) + return; + + if (!decoders) + return; + + for (i = 0; i < decoders->len; i++) { + config = g_ptr_array_index (decoders, i); + if (config->profile == GST_VAAPI_PROFILE_MPEG4_SIMPLE) + mpeg4_simple_config = config; + else if (config->profile == GST_VAAPI_PROFILE_H263_BASELINE) + h263_baseline_config = config; + } + + if (mpeg4_simple_config && !h263_baseline_config) { + tmp_config = *mpeg4_simple_config; + tmp_config.profile = GST_VAAPI_PROFILE_H263_BASELINE; + tmp_config.entrypoints = ENTRY_POINT_FLAG (VLD); + g_array_append_val (configs, tmp_config); + g_ptr_array_add (decoders, &g_array_index (configs, + GstVaapiProfileConfig, configs->len - 1)); + } +} + +/* Sort profiles. Group per codec */ +static gint +compare_profiles (gconstpointer a, gconstpointer b) +{ + const GstVaapiProfileConfig *const config1 = (GstVaapiProfileConfig *) a; + const GstVaapiProfileConfig *const config2 = (GstVaapiProfileConfig *) b; + + g_assert (config1->profile != config2->profile); + return config1->profile - config2->profile; +} + +/* Convert configs array to profiles as GstCaps */ +static GArray * +get_profiles (GPtrArray * configs, GstVaapiCodec codec) +{ + GstVaapiProfileConfig *config; + GArray *out_profiles; + guint i; + + if (!configs) + return NULL; + + out_profiles = g_array_new (FALSE, FALSE, sizeof (GstVaapiProfile)); + if (!out_profiles) + return NULL; + + for (i = 0; i < configs->len; i++) { + config = g_ptr_array_index (configs, i); + if (!codec || (codec == gst_vaapi_profile_get_codec (config->profile))) + g_array_append_val (out_profiles, config->profile); + } + return out_profiles; +} + +/* Find format info */ +static const GstVaapiFormatInfo * +find_format_info (GArray * formats, GstVideoFormat format) +{ + const GstVaapiFormatInfo *fip; + guint i; + + for (i = 0; i < formats->len; i++) { + fip = &g_array_index (formats, GstVaapiFormatInfo, i); + if (fip->format == format) + return fip; + } + return NULL; +} + +/* Check if formats array contains format */ +static inline gboolean +find_format (GArray * formats, GstVideoFormat format) +{ + return find_format_info (formats, format) != NULL; +} + +/* Convert formats array to GstCaps */ +static GArray * +get_formats (GArray * formats) +{ + const GstVaapiFormatInfo *fip; + GArray *out_formats; + guint i; + + out_formats = g_array_new (FALSE, FALSE, sizeof (GstVideoFormat)); + if (!out_formats) + return NULL; + + for (i = 0; i < formats->len; i++) { + fip = &g_array_index (formats, GstVaapiFormatInfo, i); + g_array_append_val (out_formats, fip->format); + } + return out_formats; +} + +/* Find display attribute */ +static const GstVaapiProperty * +find_property (GArray * properties, const gchar * name) +{ + GstVaapiProperty *prop; + guint i; + + if (!name) + return NULL; + + for (i = 0; i < properties->len; i++) { + prop = &g_array_index (properties, GstVaapiProperty, i); + if (strcmp (prop->name, name) == 0) + return prop; + } + return NULL; +} + +#if 0 +static const GstVaapiProperty * +find_property_by_type (GArray * properties, VADisplayAttribType type) +{ + GstVaapiProperty *prop; + guint i; + + for (i = 0; i < properties->len; i++) { + prop = &g_array_index (properties, GstVaapiProperty, i); + if (prop->attribute.type == type) + return prop; + } + return NULL; +} +#endif + +static inline const GstVaapiProperty * +find_property_by_pspec (GstVaapiDisplay * display, GParamSpec * pspec) +{ + GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display); + + return find_property (priv->properties, pspec->name); +} + +static guint +find_property_id (const gchar * name) +{ + typedef struct + { + const gchar *name; + guint id; + } property_map; + + static const property_map g_property_map[] = { + {GST_VAAPI_DISPLAY_PROP_RENDER_MODE, PROP_RENDER_MODE}, + {GST_VAAPI_DISPLAY_PROP_ROTATION, PROP_ROTATION}, + {GST_VAAPI_DISPLAY_PROP_HUE, PROP_HUE}, + {GST_VAAPI_DISPLAY_PROP_SATURATION, PROP_SATURATION}, + {GST_VAAPI_DISPLAY_PROP_BRIGHTNESS, PROP_BRIGHTNESS}, + {GST_VAAPI_DISPLAY_PROP_CONTRAST, PROP_CONTRAST}, + {NULL,} + }; + + const property_map *m; + for (m = g_property_map; m->name != NULL; m++) { + if (strcmp (m->name, name) == 0) + return m->id; + } + return 0; +} + +/* Initialize VA profiles (decoders, encoders) */ +static gboolean +ensure_profiles (GstVaapiDisplay * display) +{ + GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display); + VAProfile *profiles = NULL; + VAEntrypoint *entrypoints = NULL; + gint i, j, n, num_entrypoints; + VAStatus status; + gboolean success = FALSE; + + GST_VAAPI_DISPLAY_LOCK (display); + + if (priv->has_profiles) { + GST_VAAPI_DISPLAY_UNLOCK (display); + return TRUE; + } + + priv->codecs = g_array_new (FALSE, FALSE, sizeof (GstVaapiProfileConfig)); + if (!priv->codecs) + goto cleanup; + + priv->decoders = g_ptr_array_new (); + if (!priv->decoders) + goto cleanup; + priv->encoders = g_ptr_array_new (); + if (!priv->encoders) + goto cleanup; + priv->has_profiles = TRUE; + + /* VA profiles */ + profiles = g_new (VAProfile, vaMaxNumProfiles (priv->display)); + if (!profiles) + goto cleanup; + entrypoints = g_new (VAEntrypoint, vaMaxNumEntrypoints (priv->display)); + if (!entrypoints) + goto cleanup; + + n = 0; + status = vaQueryConfigProfiles (priv->display, profiles, &n); + if (!vaapi_check_status (status, "vaQueryConfigProfiles()")) + goto cleanup; + + GST_DEBUG ("%d profiles", n); + for (i = 0; i < n; i++) { + if (profiles[i] == VAProfileNone) + continue; + GST_DEBUG (" %s", string_of_VAProfile (profiles[i])); + } + + for (i = 0; i < n; i++) { + GstVaapiProfileConfig config = { 0, }; + + config.profile = gst_vaapi_profile (profiles[i]); + if (!config.profile) + continue; + + status = vaQueryConfigEntrypoints (priv->display, + profiles[i], entrypoints, &num_entrypoints); + if (!vaapi_check_status (status, "vaQueryConfigEntrypoints()")) + continue; + + for (j = 0; j < num_entrypoints; j++) + config.entrypoints |= (1U << gst_vaapi_entrypoint (entrypoints[j])); + + priv->codecs = g_array_append_val (priv->codecs, config); + } + + for (i = 0; i < priv->codecs->len; i++) { + GstVaapiProfileConfig *cfg; + + cfg = &g_array_index (priv->codecs, GstVaapiProfileConfig, i); + + if ((cfg->entrypoints & ENTRY_POINT_FLAG (VLD)) + || (cfg->entrypoints & ENTRY_POINT_FLAG (IDCT)) + || (cfg->entrypoints & ENTRY_POINT_FLAG (MOCO))) + g_ptr_array_add (priv->decoders, cfg); + if ((cfg->entrypoints & ENTRY_POINT_FLAG (SLICE_ENCODE)) + || (cfg->entrypoints & ENTRY_POINT_FLAG (PICTURE_ENCODE)) + || (cfg->entrypoints & ENTRY_POINT_FLAG (SLICE_ENCODE_LP))) + g_ptr_array_add (priv->encoders, cfg); + } + + append_h263_config (priv->codecs, priv->decoders); + + g_ptr_array_sort (priv->decoders, compare_profiles); + g_ptr_array_sort (priv->encoders, compare_profiles); + + /* Video processing API */ + status = vaQueryConfigEntrypoints (priv->display, VAProfileNone, + entrypoints, &num_entrypoints); + if (vaapi_check_status (status, "vaQueryEntrypoints() [VAProfileNone]")) { + for (j = 0; j < num_entrypoints; j++) { + if (entrypoints[j] == VAEntrypointVideoProc) + priv->has_vpp = TRUE; + } + } + success = TRUE; + +cleanup: + g_free (profiles); + g_free (entrypoints); + GST_VAAPI_DISPLAY_UNLOCK (display); + return success; +} + +/* Initialize VA display attributes */ +static gboolean +ensure_properties (GstVaapiDisplay * display) +{ + GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display); + VADisplayAttribute *display_attrs = NULL; + VAStatus status; + gint i, n; + gboolean success = FALSE; + + if (priv->properties) + return TRUE; + + priv->properties = g_array_new (FALSE, FALSE, sizeof (GstVaapiProperty)); + if (!priv->properties) + goto cleanup; + + /* VA display attributes */ + display_attrs = + g_new (VADisplayAttribute, vaMaxNumDisplayAttributes (priv->display)); + if (!display_attrs) + goto cleanup; + + n = 0; + status = vaQueryDisplayAttributes (priv->display, display_attrs, &n); + if (!vaapi_check_status (status, "vaQueryDisplayAttributes()")) + goto cleanup; + + GST_DEBUG ("%d display attributes", n); + for (i = 0; i < n; i++) { + VADisplayAttribute *const attr = &display_attrs[i]; + GstVaapiProperty prop; + gint value; + + GST_DEBUG (" %s", string_of_VADisplayAttributeType (attr->type)); + + switch (attr->type) { + case VADisplayAttribRenderMode: + prop.name = GST_VAAPI_DISPLAY_PROP_RENDER_MODE; + break; + case VADisplayAttribRotation: + prop.name = GST_VAAPI_DISPLAY_PROP_ROTATION; + break; + case VADisplayAttribHue: + prop.name = GST_VAAPI_DISPLAY_PROP_HUE; + break; + case VADisplayAttribSaturation: + prop.name = GST_VAAPI_DISPLAY_PROP_SATURATION; + break; + case VADisplayAttribBrightness: + prop.name = GST_VAAPI_DISPLAY_PROP_BRIGHTNESS; + break; + case VADisplayAttribContrast: + prop.name = GST_VAAPI_DISPLAY_PROP_CONTRAST; + break; + default: + prop.name = NULL; + break; + } + if (!prop.name) + continue; + + /* Assume the attribute is really supported if we can get the + * actual and current value */ + if (!get_attribute (display, attr->type, &value)) + continue; + + /* Some drivers (e.g. EMGD) have completely random initial + * values */ + if (value < attr->min_value || value > attr->max_value) + continue; + + prop.attribute = *attr; + prop.old_value = value; + g_array_append_val (priv->properties, prop); + } + success = TRUE; + +cleanup: + g_free (display_attrs); + return success; +} + +/* Initialize VA image formats */ +static gboolean +ensure_image_formats (GstVaapiDisplay * display) +{ + GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display); + VAImageFormat *formats = NULL; + VAStatus status; + gint i, n, max_images; + gboolean success = FALSE; + + GST_VAAPI_DISPLAY_LOCK (display); + if (priv->image_formats) { + GST_VAAPI_DISPLAY_UNLOCK (display); + return TRUE; + } + + priv->image_formats = g_array_new (FALSE, FALSE, sizeof (GstVaapiFormatInfo)); + if (!priv->image_formats) + goto cleanup; + + /* VA image formats */ + max_images = vaMaxNumImageFormats (priv->display); + formats = g_new (VAImageFormat, max_images); + if (!formats) + goto cleanup; + + n = 0; + status = vaQueryImageFormats (priv->display, formats, &n); + if (!vaapi_check_status (status, "vaQueryImageFormats()")) + goto cleanup; + + /* XXX(victor): Force RGBA in i965 display formats. + * + * This is required for GLTextureUploadMeta since it only negotiates + * RGBA, nevertheless i965 driver only reports RGBx breaking back + * compatibility. + * + * Side effects are not expected since it worked before commit + * 32bf6f1e */ + if (gst_vaapi_display_has_driver_quirks (display, + GST_VAAPI_DRIVER_QUIRK_MISSING_RGBA_IMAGE_FORMAT)) { + formats = g_renew (VAImageFormat, formats, max_images + 1); + + formats[n].fourcc = VA_FOURCC_RGBA; + formats[n].byte_order = VA_LSB_FIRST; + formats[n].bits_per_pixel = 32; + formats[n].depth = 32; + formats[n].red_mask = 0x000000ff; + formats[n].green_mask = 0x0000ff00; + formats[n].blue_mask = 0x00ff0000; + formats[n].alpha_mask = 0xff000000; + n++; + } + + GST_DEBUG ("%d image formats", n); + for (i = 0; i < n; i++) + GST_DEBUG (" %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (formats[i].fourcc)); + + if (!gst_vaapi_video_format_create_map (formats, n)) { + GST_ERROR ("fail to create map between gst video format and vaImageFormat"); + goto cleanup; + } + + append_formats (priv->image_formats, formats, NULL, n); + g_array_sort (priv->image_formats, compare_yuv_formats); + success = TRUE; + +cleanup: + g_free (formats); + GST_VAAPI_DISPLAY_UNLOCK (display); + return success; +} + +/* Initialize VA subpicture formats */ +static gboolean +ensure_subpicture_formats (GstVaapiDisplay * display) +{ + GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display); + VAImageFormat *formats = NULL; + unsigned int *flags = NULL; + VAStatus status; + guint i, n; + gboolean success = FALSE; + + GST_VAAPI_DISPLAY_LOCK (display); + if (priv->subpicture_formats) { + GST_VAAPI_DISPLAY_UNLOCK (display); + return TRUE; + } + + priv->subpicture_formats = + g_array_new (FALSE, FALSE, sizeof (GstVaapiFormatInfo)); + if (!priv->subpicture_formats) + goto cleanup; + + /* VA subpicture formats */ + n = vaMaxNumSubpictureFormats (priv->display); + formats = g_new (VAImageFormat, n); + if (!formats) + goto cleanup; + flags = g_new (guint, n); + if (!flags) + goto cleanup; + + n = 0; + status = vaQuerySubpictureFormats (priv->display, formats, flags, &n); + if (!vaapi_check_status (status, "vaQuerySubpictureFormats()")) + goto cleanup; + + GST_DEBUG ("%d subpicture formats", n); + for (i = 0; i < n; i++) { + GST_DEBUG (" %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (formats[i].fourcc)); + flags[i] = to_GstVaapiSubpictureFlags (flags[i]); + } + + append_formats (priv->subpicture_formats, formats, flags, n); + g_array_sort (priv->subpicture_formats, compare_rgb_formats); + success = TRUE; + +cleanup: + g_free (formats); + g_free (flags); + GST_VAAPI_DISPLAY_UNLOCK (display); + return success; +} + +/* Ensures the VA driver vendor string was copied */ +static gboolean +ensure_vendor_string (GstVaapiDisplay * display) +{ + GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display); + const gchar *vendor_string; + + GST_VAAPI_DISPLAY_LOCK (display); + if (!priv->vendor_string) { + vendor_string = vaQueryVendorString (priv->display); + if (vendor_string) + priv->vendor_string = g_strdup (vendor_string); + GST_INFO_OBJECT (display, "vendor: %s", priv->vendor_string); + } + GST_VAAPI_DISPLAY_UNLOCK (display); + return priv->vendor_string != NULL; +} + +static void +set_driver_quirks (GstVaapiDisplay * display) +{ + GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display); + guint i; + + /* *INDENT-OFF* */ + static const struct + { + const char *match_string; + guint quirks; + } vaapi_driver_quirks_table[] = { + /* @XXX(victor): is this string enough to identify it */ + { "AMD", GST_VAAPI_DRIVER_QUIRK_NO_CHECK_SURFACE_PUT_IMAGE }, + { "i965", GST_VAAPI_DRIVER_QUIRK_NO_CHECK_VPP_COLOR_STD }, + { "i965", GST_VAAPI_DRIVER_QUIRK_MISSING_RGBA_IMAGE_FORMAT }, + { "iHD", GST_VAAPI_DRIVER_QUIRK_JPEG_ENC_SHIFT_VALUE_BY_50 }, + { "iHD", GST_VAAPI_DRIVER_QUIRK_HEVC_ENC_SLICE_NOT_SPAN_TILE }, + { "i965", GST_VAAPI_DRIVER_QUIRK_JPEG_DEC_BROKEN_FORMATS }, + }; + /* *INDENT-ON* */ + + if (!ensure_vendor_string (display)) + return; + + for (i = 0; i < G_N_ELEMENTS (vaapi_driver_quirks_table); i++) { + const char *match_str = vaapi_driver_quirks_table[i].match_string; + if (g_strstr_len (priv->vendor_string, strlen (priv->vendor_string), + match_str) != NULL) { + priv->driver_quirks |= vaapi_driver_quirks_table[i].quirks; + } + } + + GST_INFO_OBJECT (display, "Matched driver string \"%s\", setting quirks " + "(%#x)", priv->vendor_string, priv->driver_quirks); +} + +static void +gst_vaapi_display_calculate_pixel_aspect_ratio (GstVaapiDisplay * display) +{ + GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display); + gdouble ratio, delta; + gint i, j, index, windex; + + static const gint par[][2] = { + {1, 1}, /* regular screen */ + {16, 15}, /* PAL TV */ + {11, 10}, /* 525 line Rec.601 video */ + {54, 59}, /* 625 line Rec.601 video */ + {64, 45}, /* 1280x1024 on 16:9 display */ + {5, 3}, /* 1280x1024 on 4:3 display */ + {4, 3} /* 800x600 on 16:9 display */ + }; + + /* First, calculate the "real" ratio based on the X values; + * which is the "physical" w/h divided by the w/h in pixels of the + * display */ + if (!priv->width || !priv->height || !priv->width_mm || !priv->height_mm) + ratio = 1.0; + else + ratio = (gdouble) (priv->width_mm * priv->height) / + (priv->height_mm * priv->width); + GST_DEBUG ("calculated pixel aspect ratio: %f", ratio); + + /* Now, find the one from par[][2] with the lowest delta to the real one */ +#define DELTA(idx, w) (ABS(ratio - ((gdouble)par[idx][w] / par[idx][!(w)]))) + delta = DELTA (0, 0); + index = 0; + windex = 0; + + for (i = 1; i < G_N_ELEMENTS (par); i++) { + for (j = 0; j < 2; j++) { + const gdouble this_delta = DELTA (i, j); + if (this_delta < delta) { + index = i; + windex = j; + delta = this_delta; + } + } + } +#undef DELTA + + priv->par_n = par[index][windex]; + priv->par_d = par[index][windex ^ 1]; +} + +static void +gst_vaapi_display_ensure_screen_resolution (GstVaapiDisplay * display) +{ + GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display); + const GstVaapiDisplayClass *const klass = + GST_VAAPI_DISPLAY_GET_CLASS (display); + + if (priv->got_scrres) + return; + + if (klass->get_size) + klass->get_size (display, &priv->width, &priv->height); + if (klass->get_size_mm) + klass->get_size_mm (display, &priv->width_mm, &priv->height_mm); + + gst_vaapi_display_calculate_pixel_aspect_ratio (display); + priv->got_scrres = TRUE; +} + +static void +gst_vaapi_display_destroy (GstVaapiDisplay * display) +{ + GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display); + GstVaapiDisplayClass *klass = GST_VAAPI_DISPLAY_GET_CLASS (display); + + g_clear_pointer (&priv->decoders, g_ptr_array_unref); + g_clear_pointer (&priv->encoders, g_ptr_array_unref); + g_clear_pointer (&priv->codecs, g_array_unref); + g_clear_pointer (&priv->image_formats, g_array_unref); + g_clear_pointer (&priv->subpicture_formats, g_array_unref); + g_clear_pointer (&priv->properties, g_array_unref); + + if (priv->display) { + if (!priv->parent) + vaTerminate (priv->display); + priv->display = NULL; + } + + if (klass->close_display) + klass->close_display (display); + + g_clear_pointer (&priv->display_name, g_free); + g_clear_pointer (&priv->vendor_string, g_free); + + gst_vaapi_display_replace (&priv->parent, NULL); +} + +static gboolean +gst_vaapi_display_create (GstVaapiDisplay * display, + GstVaapiDisplayInitType init_type, gpointer data) +{ + GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display); + const GstVaapiDisplayClass *const klass = + GST_VAAPI_DISPLAY_GET_CLASS (display); + GstVaapiDisplayInfo info = { + .display = display, + }; + + switch (init_type) { + case GST_VAAPI_DISPLAY_INIT_FROM_VA_DISPLAY:{ + GstVaapiDisplayInfo *p_info = data; + + info.va_display = p_info->va_display; + priv->display = p_info->va_display; + priv->use_foreign_display = TRUE; + + if (!klass->bind_display) + break; + + data = p_info->native_display; + goto bind_display; + } + case GST_VAAPI_DISPLAY_INIT_FROM_DISPLAY_NAME: + if (klass->open_display && !klass->open_display (display, data)) + return FALSE; + goto create_display; + case GST_VAAPI_DISPLAY_INIT_FROM_NATIVE_DISPLAY: + bind_display: + if (klass->bind_display && !klass->bind_display (display, data)) + return FALSE; + // fall-through + create_display: + if (!klass->get_display || !klass->get_display (display, &info)) + return FALSE; + priv->display = info.va_display; + priv->native_display = info.native_display; + break; + } + if (!priv->display) + return FALSE; + + if (!priv->parent) { + if (!vaapi_initialize (priv->display)) + return FALSE; + } + + GST_INFO_OBJECT (display, "new display addr=%p", display); + g_free (priv->display_name); + priv->display_name = g_strdup (info.display_name); + + set_driver_quirks (display); + + if (!ensure_image_formats (display)) { + gst_vaapi_display_destroy (display); + return FALSE; + } + + return TRUE; +} + +static void +gst_vaapi_display_lock_default (GstVaapiDisplay * display) +{ + GstVaapiDisplayPrivate *priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display); + + if (priv->parent) + priv = GST_VAAPI_DISPLAY_GET_PRIVATE (priv->parent); + g_rec_mutex_lock (&priv->mutex); +} + +static void +gst_vaapi_display_unlock_default (GstVaapiDisplay * display) +{ + GstVaapiDisplayPrivate *priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display); + + if (priv->parent) + priv = GST_VAAPI_DISPLAY_GET_PRIVATE (priv->parent); + g_rec_mutex_unlock (&priv->mutex); +} + +static void +gst_vaapi_display_init (GstVaapiDisplay * display) +{ + GstVaapiDisplayPrivate *const priv = + gst_vaapi_display_get_instance_private (display); + + display->priv = priv; + priv->par_n = 1; + priv->par_d = 1; + + g_rec_mutex_init (&priv->mutex); +} + +static gboolean +_set_property (GstVaapiDisplay * display, const GstVaapiProperty * prop, + const GValue * value) +{ + switch (prop->attribute.type) { + case VADisplayAttribRenderMode:{ + GstVaapiRenderMode mode; + if (!G_VALUE_HOLDS (value, GST_VAAPI_TYPE_RENDER_MODE)) + return FALSE; + mode = g_value_get_enum (value); + return gst_vaapi_display_set_render_mode (display, mode); + } + case VADisplayAttribRotation:{ + GstVaapiRotation rotation; + if (!G_VALUE_HOLDS (value, GST_VAAPI_TYPE_ROTATION)) + return FALSE; + rotation = g_value_get_enum (value); + return gst_vaapi_display_set_rotation (display, rotation); + } + case VADisplayAttribHue: + case VADisplayAttribSaturation: + case VADisplayAttribBrightness: + case VADisplayAttribContrast:{ + gfloat v; + if (!G_VALUE_HOLDS (value, G_TYPE_FLOAT)) + return FALSE; + v = g_value_get_float (value); + return set_color_balance (display, find_property_id (prop->name), v); + } + default: + break; + } + + GST_WARNING ("unsupported property '%s'", prop->name); + return FALSE; +} + +static void +gst_vaapi_display_set_property (GObject * object, guint property_id, + const GValue * value, GParamSpec * pspec) +{ + GstVaapiDisplay *display = GST_VAAPI_DISPLAY (object); + const GstVaapiProperty *prop; + + if (!ensure_properties (display)) + return; + + prop = find_property_by_pspec (display, pspec); + if (!prop) { + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + return; + } + + _set_property (display, prop, value); +} + +static gboolean +_get_property (GstVaapiDisplay * display, const GstVaapiProperty * prop, + GValue * value) +{ + switch (prop->attribute.type) { + case VADisplayAttribRenderMode:{ + GstVaapiRenderMode mode; + if (!gst_vaapi_display_get_render_mode (display, &mode)) + return FALSE; + if (!G_IS_VALUE (value)) + g_value_init (value, GST_VAAPI_TYPE_RENDER_MODE); + g_value_set_enum (value, mode); + break; + } + case VADisplayAttribRotation:{ + GstVaapiRotation rotation; + rotation = gst_vaapi_display_get_rotation (display); + if (!G_IS_VALUE (value)) + g_value_init (value, GST_VAAPI_TYPE_ROTATION); + g_value_set_enum (value, rotation); + break; + } + case VADisplayAttribHue: + case VADisplayAttribSaturation: + case VADisplayAttribBrightness: + case VADisplayAttribContrast:{ + gfloat val; + if (!get_color_balance (display, find_property_id (prop->name), &val)) + return FALSE; + if (!G_IS_VALUE (value)) + g_value_init (value, G_TYPE_FLOAT); + g_value_set_float (value, val); + break; + } + default: + GST_WARNING ("unsupported property '%s'", prop->name); + return FALSE; + } + return TRUE; +} + +static void +gst_vaapi_display_get_property (GObject * object, guint property_id, + GValue * value, GParamSpec * pspec) +{ + GstVaapiDisplay *display = GST_VAAPI_DISPLAY (object); + const GstVaapiProperty *prop; + + if (property_id == PROP_VA_DISPLAY) { + g_value_set_pointer (value, gst_vaapi_display_get_display (display)); + return; + } + + if (!ensure_properties (display)) + return; + + prop = find_property_by_pspec (display, pspec); + if (!prop) { + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + return; + } + + _get_property (display, prop, value); +} + +static void +gst_vaapi_display_finalize (GObject * object) +{ + GstVaapiDisplay *const display = GST_VAAPI_DISPLAY (object); + GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display); + + gst_vaapi_display_destroy (display); + g_rec_mutex_clear (&priv->mutex); + + G_OBJECT_CLASS (gst_vaapi_display_parent_class)->finalize (object); +} + +void +gst_vaapi_display_class_init (GstVaapiDisplayClass * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gst_vaapi_display_finalize; + object_class->set_property = gst_vaapi_display_set_property; + object_class->get_property = gst_vaapi_display_get_property; + + klass->lock = gst_vaapi_display_lock_default; + klass->unlock = gst_vaapi_display_unlock_default; + + /** + * GstVaapiDisplay:render-mode: + * + * The VA display rendering mode, expressed as a #GstVaapiRenderMode. + */ + g_properties[PROP_RENDER_MODE] = + g_param_spec_enum (GST_VAAPI_DISPLAY_PROP_RENDER_MODE, + "render mode", + "The display rendering mode", + GST_VAAPI_TYPE_RENDER_MODE, DEFAULT_RENDER_MODE, G_PARAM_READWRITE); + + /** + * GstVaapiDisplay:rotation: + * + * The VA display rotation mode, expressed as a #GstVaapiRotation. + */ + g_properties[PROP_ROTATION] = + g_param_spec_enum (GST_VAAPI_DISPLAY_PROP_ROTATION, + "rotation", + "The display rotation mode", + GST_VAAPI_TYPE_ROTATION, DEFAULT_ROTATION, G_PARAM_READWRITE); + + /** + * GstVaapiDisplay:hue: + * + * The VA display hue, expressed as a float value. Range is -180.0 + * to 180.0. Default value is 0.0 and represents no modification. + */ + g_properties[PROP_HUE] = + g_param_spec_float (GST_VAAPI_DISPLAY_PROP_HUE, + "hue", "The display hue value", -180.0, 180.0, 0.0, G_PARAM_READWRITE); + + /** + * GstVaapiDisplay:saturation: + * + * The VA display saturation, expressed as a float value. Range is + * 0.0 to 2.0. Default value is 1.0 and represents no modification. + */ + g_properties[PROP_SATURATION] = + g_param_spec_float (GST_VAAPI_DISPLAY_PROP_SATURATION, + "saturation", + "The display saturation value", 0.0, 2.0, 1.0, G_PARAM_READWRITE); + + /** + * GstVaapiDisplay:brightness: + * + * The VA display brightness, expressed as a float value. Range is + * -1.0 to 1.0. Default value is 0.0 and represents no modification. + */ + g_properties[PROP_BRIGHTNESS] = + g_param_spec_float (GST_VAAPI_DISPLAY_PROP_BRIGHTNESS, + "brightness", + "The display brightness value", -1.0, 1.0, 0.0, G_PARAM_READWRITE); + + /** + * GstVaapiDisplay:contrast: + * + * The VA display contrast, expressed as a float value. Range is 0.0 + * to 2.0. Default value is 1.0 and represents no modification. + */ + g_properties[PROP_CONTRAST] = + g_param_spec_float (GST_VAAPI_DISPLAY_PROP_CONTRAST, + "contrast", + "The display contrast value", 0.0, 2.0, 1.0, G_PARAM_READWRITE); + + /** + * GstVaapiDisplay:va-display: + * + * The VA display handle, expressed as a #VADisplay. + */ + g_properties[PROP_VA_DISPLAY] = + g_param_spec_pointer ("va-display", "VADisplay", + "VA Display handler", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, N_PROPERTIES, g_properties); + gst_type_mark_as_plugin_api (gst_vaapi_display_type_get_type (), 0); +} + +/** + * gst_vaapi_display_config: + * @display: instance of #GstVaapiDisplay + * @init_type: type of initialization #GstVaapiDisplayInitType + * @init_value: a pointer to the structure with the initialization + * parameters + * + * Binds @display to the VA layer; otherwise it is just an empty + * structure. + * + * Returns: the configured @display if it was configured correctly; + * otherwise unrefs @display and returns %NULL. + **/ +GstVaapiDisplay * +gst_vaapi_display_config (GstVaapiDisplay * display, + GstVaapiDisplayInitType init_type, gpointer init_value) +{ + g_return_val_if_fail (display && GST_VAAPI_IS_DISPLAY (display), NULL); + + if (!gst_vaapi_display_create (display, init_type, init_value)) + goto error; + return display; + + /* ERRORS */ +error: + { + gst_object_unref (display); + return NULL; + } +} + +/** + * gst_vaapi_display_new_with_display: + * @va_display: a #VADisplay + * + * Creates a new #GstVaapiDisplay, using @va_display as the VA + * display. + * + * Return value: the newly created #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_display_new_with_display (VADisplay va_display) +{ + GstVaapiDisplayInfo info = { + .va_display = va_display, + }; + + return gst_vaapi_display_config (g_object_new (GST_TYPE_VAAPI_DISPLAY, NULL), + GST_VAAPI_DISPLAY_INIT_FROM_VA_DISPLAY, &info); +} + +/** + * gst_vaapi_display_replace: + * @old_display_ptr: a pointer to a #GstVaapiDisplay + * @new_display: a #GstVaapiDisplay + * + * Atomically replaces the display display held in @old_display_ptr + * with @new_display. This means that @old_display_ptr shall reference + * a valid display. However, @new_display can be NULL. + */ +void +gst_vaapi_display_replace (GstVaapiDisplay ** old_display_ptr, + GstVaapiDisplay * new_display) +{ + gst_object_replace ((GstObject **) old_display_ptr, + (GstObject *) new_display); +} + +/** + * gst_vaapi_display_lock: + * @display: a #GstVaapiDisplay + * + * Locks @display. If @display is already locked by another thread, + * the current thread will block until @display is unlocked by the + * other thread. + */ +void +gst_vaapi_display_lock (GstVaapiDisplay * display) +{ + GstVaapiDisplayClass *klass; + + g_return_if_fail (display != NULL); + + klass = GST_VAAPI_DISPLAY_GET_CLASS (display); + if (klass->lock) + klass->lock (display); +} + +/** + * gst_vaapi_display_unlock: + * @display: a #GstVaapiDisplay + * + * Unlocks @display. If another thread is blocked in a + * gst_vaapi_display_lock() call for @display, it will be woken and + * can lock @display itself. + */ +void +gst_vaapi_display_unlock (GstVaapiDisplay * display) +{ + GstVaapiDisplayClass *klass; + + g_return_if_fail (display != NULL); + + klass = GST_VAAPI_DISPLAY_GET_CLASS (display); + if (klass->unlock) + klass->unlock (display); +} + +/** + * gst_vaapi_display_sync: + * @display: a #GstVaapiDisplay + * + * Flushes any requests queued for the windowing system and waits until + * all requests have been handled. This is often used for making sure + * that the display is synchronized with the current state of the program. + * + * This is most useful for X11. On windowing systems where requests are + * handled synchronously, this function will do nothing. + */ +void +gst_vaapi_display_sync (GstVaapiDisplay * display) +{ + GstVaapiDisplayClass *klass; + + g_return_if_fail (display != NULL); + + klass = GST_VAAPI_DISPLAY_GET_CLASS (display); + if (klass->sync) + klass->sync (display); + else if (klass->flush) + klass->flush (display); +} + +/** + * gst_vaapi_display_flush: + * @display: a #GstVaapiDisplay + * + * Flushes any requests queued for the windowing system. + * + * This is most useful for X11. On windowing systems where requests + * are handled synchronously, this function will do nothing. + */ +void +gst_vaapi_display_flush (GstVaapiDisplay * display) +{ + GstVaapiDisplayClass *klass; + + g_return_if_fail (display != NULL); + + klass = GST_VAAPI_DISPLAY_GET_CLASS (display); + if (klass->flush) + klass->flush (display); +} + +/** + * gst_vaapi_display_get_class_type: + * @display: a #GstVaapiDisplay + * + * Returns the #GstVaapiDisplayType of @display. This is the type of + * the object, thus the associated class, not the type of the VA + * display. + * + * Return value: the #GstVaapiDisplayType + */ +GstVaapiDisplayType +gst_vaapi_display_get_class_type (GstVaapiDisplay * display) +{ + g_return_val_if_fail (display != NULL, GST_VAAPI_DISPLAY_TYPE_ANY); + + return GST_VAAPI_DISPLAY_GET_CLASS_TYPE (display); +} + +/** + * gst_vaapi_display_get_display_type: + * @display: a #GstVaapiDisplay + * + * Returns the #GstVaapiDisplayType of the VA display bound to + * @display. This is not the type of the @display object. + * + * Return value: the #GstVaapiDisplayType + */ +GstVaapiDisplayType +gst_vaapi_display_get_display_type (GstVaapiDisplay * display) +{ + g_return_val_if_fail (display != NULL, GST_VAAPI_DISPLAY_TYPE_ANY); + + return GST_VAAPI_DISPLAY_VADISPLAY_TYPE (display); +} + +/** + * gst_vaapi_display_get_display_type: + * @display: a #GstVaapiDisplay + * + * Returns the @display name. + * + * Return value: the display name + */ +const gchar * +gst_vaapi_display_get_display_name (GstVaapiDisplay * display) +{ + g_return_val_if_fail (display != NULL, NULL); + + return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->display_name; +} + +/** + * gst_vaapi_display_get_display: + * @display: a #GstVaapiDisplay + * + * Returns the #VADisplay bound to @display. + * + * Return value: the #VADisplay + */ +VADisplay +gst_vaapi_display_get_display (GstVaapiDisplay * display) +{ + g_return_val_if_fail (display != NULL, NULL); + + return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->display; +} + +/** + * gst_vaapi_display_get_width: + * @display: a #GstVaapiDisplay + * + * Retrieves the width of a #GstVaapiDisplay. + * + * Return value: the width of the @display, in pixels + */ +guint +gst_vaapi_display_get_width (GstVaapiDisplay * display) +{ + g_return_val_if_fail (display != NULL, 0); + + gst_vaapi_display_ensure_screen_resolution (display); + + return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->width; +} + +/** + * gst_vaapi_display_get_height: + * @display: a #GstVaapiDisplay + * + * Retrieves the height of a #GstVaapiDisplay + * + * Return value: the height of the @display, in pixels + */ +guint +gst_vaapi_display_get_height (GstVaapiDisplay * display) +{ + g_return_val_if_fail (display != NULL, 0); + + gst_vaapi_display_ensure_screen_resolution (display); + + return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->height; +} + +/** + * gst_vaapi_display_get_size: + * @display: a #GstVaapiDisplay + * @pwidth: return location for the width, or %NULL + * @pheight: return location for the height, or %NULL + * + * Retrieves the dimensions of a #GstVaapiDisplay. + */ +void +gst_vaapi_display_get_size (GstVaapiDisplay * display, guint * pwidth, + guint * pheight) +{ + g_return_if_fail (GST_VAAPI_DISPLAY (display)); + + gst_vaapi_display_ensure_screen_resolution (display); + + if (pwidth) + *pwidth = GST_VAAPI_DISPLAY_GET_PRIVATE (display)->width; + + if (pheight) + *pheight = GST_VAAPI_DISPLAY_GET_PRIVATE (display)->height; +} + +/** + * gst_vaapi_display_get_pixel_aspect_ratio: + * @display: a #GstVaapiDisplay + * @par_n: return location for the numerator of pixel aspect ratio, or %NULL + * @par_d: return location for the denominator of pixel aspect ratio, or %NULL + * + * Retrieves the pixel aspect ratio of a #GstVaapiDisplay. + */ +void +gst_vaapi_display_get_pixel_aspect_ratio (GstVaapiDisplay * display, + guint * par_n, guint * par_d) +{ + g_return_if_fail (display != NULL); + + gst_vaapi_display_ensure_screen_resolution (display); + + if (par_n) + *par_n = GST_VAAPI_DISPLAY_GET_PRIVATE (display)->par_n; + + if (par_d) + *par_d = GST_VAAPI_DISPLAY_GET_PRIVATE (display)->par_d; +} + +/** + * gst_vaapi_display_has_video_processing: + * @display: a #GstVaapiDisplay + * + * Checks whether the underlying VA driver implementation supports + * video processing (VPP) acceleration. + * + * Returns: %TRUE if some VPP features are available + */ +gboolean +gst_vaapi_display_has_video_processing (GstVaapiDisplay * display) +{ + g_return_val_if_fail (display != NULL, FALSE); + + if (!ensure_profiles (display)) + return FALSE; + return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->has_vpp; +} + +/** + * gst_vaapi_display_get_decode_profiles: + * @display: a #GstVaapiDisplay + * + * Gets the supported profiles for decoding. The caller owns an extra + * reference to the resulting array of #GstVaapiProfile elements, so + * it shall be released with g_array_unref() after usage. + * + * Return value: a newly allocated #GArray, or %NULL if error or if + * decoding is not supported at all + */ +GArray * +gst_vaapi_display_get_decode_profiles (GstVaapiDisplay * display) +{ + g_return_val_if_fail (display != NULL, NULL); + + if (!ensure_profiles (display)) + return NULL; + return get_profiles (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->decoders, 0); +} + +/** + * gst_vaapi_display_has_decoder: + * @display: a #GstVaapiDisplay + * @profile: a #VAProfile + * @entrypoint: a #GstVaaiEntrypoint + * + * Returns whether VA @display supports @profile for decoding at the + * specified @entrypoint. + * + * Return value: %TRUE if VA @display supports @profile for decoding. + */ +gboolean +gst_vaapi_display_has_decoder (GstVaapiDisplay * display, + GstVaapiProfile profile, GstVaapiEntrypoint entrypoint) +{ + g_return_val_if_fail (display != NULL, FALSE); + + if (!ensure_profiles (display)) + return FALSE; + return find_config (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->decoders, + profile, entrypoint); +} + +/** + * gst_vaapi_display_get_encode_profiles: + * @display: a #GstVaapiDisplay + * + * Gets the supported profiles for encoding. The caller owns an extra + * reference to the resulting array of #GstVaapiProfile elements, so + * it shall be released with g_array_unref() after usage. + * + * Return value: a newly allocated #GArray, or %NULL if error or if + * encoding is not supported at all + */ +GArray * +gst_vaapi_display_get_encode_profiles (GstVaapiDisplay * display) +{ + g_return_val_if_fail (display != NULL, NULL); + + if (!ensure_profiles (display)) + return NULL; + return get_profiles (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->encoders, 0); +} + +/** + * gst_vaapi_display_get_encode_profiles_by_codec: + * @display: a #GstVaapiDisplay + * @codec: a #GstVaapiCodec + * + * Gets the supported profiles which belongs to @codec for encoding. + * The caller owns an extra reference to the resulting array of + * #GstVaapiProfile elements, so it shall be released with g_array_unref() + * after usage. + * + * Return value: a newly allocated #GArray, or %NULL if error or if + * no encoding profile is found specified by the @codec. + */ +GArray * +gst_vaapi_display_get_encode_profiles_by_codec (GstVaapiDisplay * display, + GstVaapiCodec codec) +{ + g_return_val_if_fail (display != NULL, NULL); + + if (!ensure_profiles (display)) + return NULL; + return get_profiles (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->encoders, + codec); +} + +/** + * gst_vaapi_display_has_encoder: + * @display: a #GstVaapiDisplay + * @profile: a #VAProfile + * @entrypoint: a #GstVaapiEntrypoint + * + * Returns whether VA @display supports @profile for encoding at the + * specified @entrypoint. + * + * Return value: %TRUE if VA @display supports @profile for encoding. + */ +gboolean +gst_vaapi_display_has_encoder (GstVaapiDisplay * display, + GstVaapiProfile profile, GstVaapiEntrypoint entrypoint) +{ + g_return_val_if_fail (display != NULL, FALSE); + + if (!ensure_profiles (display)) + return FALSE; + return find_config (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->encoders, + profile, entrypoint); +} + +/** + * gst_vaapi_display_get_image_formats: + * @display: a #GstVaapiDisplay + * + * Gets the supported image formats for gst_vaapi_surface_get_image() + * or gst_vaapi_surface_put_image(). + * + * Note that this method does not necessarily map image formats + * returned by vaQueryImageFormats(). The set of capabilities can be + * stripped down, if gstreamer-vaapi does not support the format, or + * expanded to cover compatible formats not exposed by the underlying + * driver. e.g. I420 can be supported even if the driver only exposes + * YV12. + * + * Note: the caller owns an extra reference to the resulting array of + * #GstVideoFormat elements, so it shall be released with + * g_array_unref() after usage. + * + * Return value: a newly allocated #GArray, or %NULL on error or if + * the set is empty + */ +GArray * +gst_vaapi_display_get_image_formats (GstVaapiDisplay * display) +{ + g_return_val_if_fail (display != NULL, NULL); + + if (!ensure_image_formats (display)) + return NULL; + return get_formats (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->image_formats); +} + +/** + * gst_vaapi_display_has_image_format: + * @display: a #GstVaapiDisplay + * @format: a #GstVideoFormat + * + * Returns whether VA @display supports @format image format. + * + * Return value: %TRUE if VA @display supports @format image format + */ +gboolean +gst_vaapi_display_has_image_format (GstVaapiDisplay * display, + GstVideoFormat format) +{ + GstVaapiDisplayPrivate *priv; + + g_return_val_if_fail (display != NULL, FALSE); + g_return_val_if_fail (format, FALSE); + + priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display); + + if (!ensure_image_formats (display)) + return FALSE; + if (find_format (priv->image_formats, format)) + return TRUE; + + /* XXX: try subpicture formats since some drivers could report a + * set of VA image formats that is not a superset of the set of VA + * subpicture formats + */ + if (!ensure_subpicture_formats (display)) + return FALSE; + return find_format (priv->subpicture_formats, format); +} + +/** + * gst_vaapi_display_get_subpicture_formats: + * @display: a #GstVaapiDisplay + * + * Gets the supported subpicture formats. + * + * Note that this method does not necessarily map subpicture formats + * returned by vaQuerySubpictureFormats(). The set of capabilities can + * be stripped down if gstreamer-vaapi does not support the + * format. e.g. this is the case for paletted formats like IA44. + * + * Note: the caller owns an extra reference to the resulting array of + * #GstVideoFormat elements, so it shall be released with + * g_array_unref() after usage. + * + * Return value: a newly allocated #GArray, or %NULL on error of if + * the set is empty + */ +GArray * +gst_vaapi_display_get_subpicture_formats (GstVaapiDisplay * display) +{ + g_return_val_if_fail (display != NULL, NULL); + + if (!ensure_subpicture_formats (display)) + return NULL; + return + get_formats (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->subpicture_formats); +} + +/** + * gst_vaapi_display_has_subpicture_format: + * @display: a #GstVaapiDisplay + * @format: a #GstVideoFormat + * @flags_ptr: pointer to #GstVaapiSubpictureFlags, or zero + * + * Returns whether VA @display supports @format subpicture format with + * the supplied @flags. + * + * Return value: %TRUE if VA @display supports @format subpicture format + */ +gboolean +gst_vaapi_display_has_subpicture_format (GstVaapiDisplay * display, + GstVideoFormat format, guint * flags_ptr) +{ + GstVaapiDisplayPrivate *priv; + const GstVaapiFormatInfo *fip; + + g_return_val_if_fail (display != NULL, FALSE); + g_return_val_if_fail (format, FALSE); + + priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display); + + if (!ensure_subpicture_formats (display)) + return FALSE; + + fip = find_format_info (priv->subpicture_formats, format); + if (!fip) + return FALSE; + + if (flags_ptr) + *flags_ptr = fip->flags; + return TRUE; +} + +/** + * gst_vaapi_display_has_property: + * @display: a #GstVaapiDisplay + * @name: the property name to check + * + * Returns whether VA @display supports the requested property. The + * check is performed against the property @name. So, the client + * application may perform this check only once and cache this + * information. + * + * Return value: %TRUE if VA @display supports property @name + */ +gboolean +gst_vaapi_display_has_property (GstVaapiDisplay * display, const gchar * name) +{ + g_return_val_if_fail (display != NULL, FALSE); + g_return_val_if_fail (name, FALSE); + + if (!ensure_properties (display)) + return FALSE; + return find_property (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->properties, + name) != NULL; +} + +static gboolean +get_attribute (GstVaapiDisplay * display, VADisplayAttribType type, + gint * value) +{ + GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display); + VADisplayAttribute attr = { 0, }; + VAStatus status; + + attr.type = type; + attr.flags = VA_DISPLAY_ATTRIB_GETTABLE; + status = vaGetDisplayAttributes (priv->display, &attr, 1); + if (!vaapi_check_status (status, "vaGetDisplayAttributes()")) + return FALSE; + *value = attr.value; + return TRUE; +} + +static gboolean +set_attribute (GstVaapiDisplay * display, VADisplayAttribType type, gint value) +{ + GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display); + VADisplayAttribute attr = { 0, }; + VAStatus status; + + attr.type = type; + attr.value = value; + attr.flags = VA_DISPLAY_ATTRIB_SETTABLE; + status = vaSetDisplayAttributes (priv->display, &attr, 1); + if (!vaapi_check_status (status, "vaSetDisplayAttributes()")) + return FALSE; + return TRUE; +} + +static gboolean +get_render_mode_VADisplayAttribRenderMode (GstVaapiDisplay * display, + GstVaapiRenderMode * pmode) +{ + gint modes, devices; + + if (!get_attribute (display, VADisplayAttribRenderDevice, &devices)) + return FALSE; + if (!devices) + return FALSE; + if (!get_attribute (display, VADisplayAttribRenderMode, &modes)) + return FALSE; + + /* Favor "overlay" mode since it is the most restrictive one */ + if (modes & (VA_RENDER_MODE_LOCAL_OVERLAY | VA_RENDER_MODE_EXTERNAL_OVERLAY)) + *pmode = GST_VAAPI_RENDER_MODE_OVERLAY; + else + *pmode = GST_VAAPI_RENDER_MODE_TEXTURE; + return TRUE; +} + +static gboolean +get_render_mode_default (GstVaapiDisplay * display, GstVaapiRenderMode * pmode) +{ + switch (GST_VAAPI_DISPLAY_VADISPLAY_TYPE (display)) { +#if USE_WAYLAND + case GST_VAAPI_DISPLAY_TYPE_WAYLAND: + /* wl_buffer mapped from VA surface through vaGetSurfaceBufferWl() */ + *pmode = GST_VAAPI_RENDER_MODE_OVERLAY; + break; +#endif +#if USE_DRM + case GST_VAAPI_DISPLAY_TYPE_DRM: + /* vaGetSurfaceBufferDRM() returns the underlying DRM buffer handle */ + *pmode = GST_VAAPI_RENDER_MODE_OVERLAY; + break; +#endif + default: + /* This includes VA/X11 and VA/GLX modes */ + *pmode = DEFAULT_RENDER_MODE; + break; + } + return TRUE; +} + +/** + * gst_vaapi_display_get_render_mode: + * @display: a #GstVaapiDisplay + * @pmode: return location for the VA @display rendering mode + * + * Returns the current VA @display rendering mode. + * + * Return value: %TRUE if VA @display rendering mode could be determined + */ +gboolean +gst_vaapi_display_get_render_mode (GstVaapiDisplay * display, + GstVaapiRenderMode * pmode) +{ + g_return_val_if_fail (display != NULL, FALSE); + + /* Try with render-mode attribute */ + if (get_render_mode_VADisplayAttribRenderMode (display, pmode)) + return TRUE; + + /* Default: determine from the display type */ + return get_render_mode_default (display, pmode); +} + +/** + * gst_vaapi_display_set_render_mode: + * @display: a #GstVaapiDisplay + * @mode: the #GstVaapiRenderMode to set + * + * Sets the VA @display rendering mode to the supplied @mode. This + * function returns %FALSE if the rendering mode could not be set, + * e.g. run-time switching rendering mode is not supported. + * + * Return value: %TRUE if VA @display rendering @mode could be changed + * to the requested value + */ +gboolean +gst_vaapi_display_set_render_mode (GstVaapiDisplay * display, + GstVaapiRenderMode mode) +{ + gint modes, devices; + + g_return_val_if_fail (display != NULL, FALSE); + + if (!get_attribute (display, VADisplayAttribRenderDevice, &devices)) + return FALSE; + + modes = 0; + switch (mode) { + case GST_VAAPI_RENDER_MODE_OVERLAY: + if (devices & VA_RENDER_DEVICE_LOCAL) + modes |= VA_RENDER_MODE_LOCAL_OVERLAY; + if (devices & VA_RENDER_DEVICE_EXTERNAL) + modes |= VA_RENDER_MODE_EXTERNAL_OVERLAY; + break; + case GST_VAAPI_RENDER_MODE_TEXTURE: + if (devices & VA_RENDER_DEVICE_LOCAL) + modes |= VA_RENDER_MODE_LOCAL_GPU; + if (devices & VA_RENDER_DEVICE_EXTERNAL) + modes |= VA_RENDER_MODE_EXTERNAL_GPU; + break; + } + if (!modes) + return FALSE; + if (!set_attribute (display, VADisplayAttribRenderMode, modes)) + return FALSE; + return TRUE; +} + +/** + * gst_vaapi_display_get_rotation: + * @display: a #GstVaapiDisplay + * + * Returns the current VA @display rotation angle. If the VA driver + * does not support "rotation" display attribute, then the display is + * assumed to be un-rotated. + * + * Return value: the current #GstVaapiRotation value + */ +GstVaapiRotation +gst_vaapi_display_get_rotation (GstVaapiDisplay * display) +{ + gint value; + + g_return_val_if_fail (display != NULL, DEFAULT_ROTATION); + + if (!get_attribute (display, VADisplayAttribRotation, &value)) + value = VA_ROTATION_NONE; + return to_GstVaapiRotation (value); +} + +/** + * gst_vaapi_display_set_rotation: + * @display: a #GstVaapiDisplay + * @rotation: the #GstVaapiRotation value to set + * + * Sets the VA @display rotation angle to the supplied @rotation + * value. This function returns %FALSE if the rotation angle could not + * be set, e.g. the VA driver does not allow to change the display + * rotation angle. + * + * Return value: %TRUE if VA @display rotation angle could be changed + * to the requested value + */ +gboolean +gst_vaapi_display_set_rotation (GstVaapiDisplay * display, + GstVaapiRotation rotation) +{ + guint value; + + g_return_val_if_fail (display != NULL, FALSE); + + value = from_GstVaapiRotation (rotation); + if (!set_attribute (display, VADisplayAttribRotation, value)) + return FALSE; + return TRUE; +} + +/* Get color balance attributes */ +static gboolean +get_color_balance (GstVaapiDisplay * display, guint prop_id, gfloat * v) +{ + GParamSpecFloat *const pspec = G_PARAM_SPEC_FLOAT (g_properties[prop_id]); + const GstVaapiProperty *prop; + const VADisplayAttribute *attr; + gfloat out_value; + gint value; + + if (!ensure_properties (display)) + return FALSE; + + if (!pspec) + return FALSE; + + prop = find_property_by_pspec (display, &pspec->parent_instance); + if (!prop) + return FALSE; + attr = &prop->attribute; + + if (!get_attribute (display, attr->type, &value)) + return FALSE; + + /* Scale wrt. the medium ("default") value */ + out_value = pspec->default_value; + if (value > attr->value) + out_value += ((gfloat) (value - attr->value) / + (attr->max_value - attr->value) * + (pspec->maximum - pspec->default_value)); + else if (value < attr->value) + out_value -= ((gfloat) (attr->value - value) / + (attr->value - attr->min_value) * + (pspec->default_value - pspec->minimum)); + *v = out_value; + return TRUE; +} + +/* Set color balance attribute */ +static gboolean +set_color_balance (GstVaapiDisplay * display, guint prop_id, gfloat v) +{ + GParamSpecFloat *const pspec = G_PARAM_SPEC_FLOAT (g_properties[prop_id]); + const GstVaapiProperty *prop; + const VADisplayAttribute *attr; + gint value; + + if (!ensure_properties (display)) + return FALSE; + + if (!pspec) + return FALSE; + + prop = find_property_by_pspec (display, &pspec->parent_instance); + if (!prop) + return FALSE; + attr = &prop->attribute; + + /* Scale wrt. the medium ("default") value */ + value = attr->value; + if (v > pspec->default_value) + value += ((v - pspec->default_value) / + (pspec->maximum - pspec->default_value) * + (attr->max_value - attr->value)); + else if (v < pspec->default_value) + value -= ((pspec->default_value - v) / + (pspec->default_value - pspec->minimum) * + (attr->value - attr->min_value)); + if (!set_attribute (display, attr->type, value)) + return FALSE; + return TRUE; +} + +/** + * gst_vaapi_display_get_vendor_string: + * @display: a #GstVaapiDisplay + * + * Returns the VA driver vendor string attached to the supplied VA @display. + * The @display owns the vendor string, do *not* de-allocate it. + * + * This function is thread safe. + * + * Return value: the current #GstVaapiRotation value + */ +const gchar * +gst_vaapi_display_get_vendor_string (GstVaapiDisplay * display) +{ + g_return_val_if_fail (display != NULL, NULL); + + if (!ensure_vendor_string (display)) + return NULL; + return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->vendor_string; +} + +/** + * gst_vaapi_display_has_opengl: + * @display: a #GstVaapiDisplay + * + * Returns wether the @display that was created does support OpenGL + * context to be attached. + * + * This function is thread safe. + * + * Return value: %TRUE if the @display supports OpenGL context, %FALSE + * otherwise + */ +gboolean +gst_vaapi_display_has_opengl (GstVaapiDisplay * display) +{ + GstVaapiDisplayClass *klass; + + g_return_val_if_fail (display != NULL, FALSE); + + klass = GST_VAAPI_DISPLAY_GET_CLASS (display); + return (klass->display_type == GST_VAAPI_DISPLAY_TYPE_GLX || + klass->display_type == GST_VAAPI_DISPLAY_TYPE_EGL); +} + +/** + * gst_vaapi_display_reset_texture_map: + * @display: a #GstVaapiDisplay + * + * Reset the internal #GstVaapiTextureMap if available. + * + * This function is thread safe. + */ +void +gst_vaapi_display_reset_texture_map (GstVaapiDisplay * display) +{ + GstVaapiDisplayClass *klass; + GstVaapiTextureMap *map; + + g_return_if_fail (display != NULL); + + if (!gst_vaapi_display_has_opengl (display)) + return; + klass = GST_VAAPI_DISPLAY_GET_CLASS (display); + if (!klass->get_texture_map) + return; + if ((map = klass->get_texture_map (display))) + gst_vaapi_texture_map_reset (map); +} + +/** + * gst_vaapi_display_get_driver_quirks: + * @display: a #GstVaapiDisplay + * @quirks: the #GstVaapiDriverQuirks bitwise to check + * + * Returns: %TRUE if @quirks are set in @display's driver + **/ +gboolean +gst_vaapi_display_has_driver_quirks (GstVaapiDisplay * display, guint quirks) +{ + g_return_val_if_fail (display != NULL, FALSE); + + return (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->driver_quirks & quirks); +} diff --git a/gst-libs/gst/vaapi/gstvaapidisplay.h b/gst-libs/gst/vaapi/gstvaapidisplay.h new file mode 100644 index 0000000000..2ca9bd31f4 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay.h @@ -0,0 +1,293 @@ +/* + * gstvaapidisplay.h - VA display abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DISPLAY_H +#define GST_VAAPI_DISPLAY_H + +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_DISPLAY (gst_vaapi_display_get_type ()) +#define GST_VAAPI_DISPLAY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DISPLAY, GstVaapiDisplay)) +#define GST_VAAPI_IS_DISPLAY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_DISPLAY)) + +/** + * GST_VAAPI_DISPLAY_GET_CLASS_TYPE: + * @display: a #GstVaapiDisplay + * + * Returns the #display class type + */ +#define GST_VAAPI_DISPLAY_GET_CLASS_TYPE(display) \ + gst_vaapi_display_get_class_type (GST_VAAPI_DISPLAY (display)) + +/** + * GST_VAAPI_DISPLAY_VADISPLAY_TYPE: + * @display: a #GstVaapiDisplay + * + * Returns the underlying VADisplay @display type. + */ +#define GST_VAAPI_DISPLAY_VADISPLAY_TYPE(display) \ + gst_vaapi_display_get_display_type (GST_VAAPI_DISPLAY (display)) + +/** + * GST_VAAPI_DISPLAY_VADISPLAY: + * @display_: a #GstVaapiDisplay + * + * Macro that evaluates to the #VADisplay of @display. + */ +#define GST_VAAPI_DISPLAY_VADISPLAY(display) \ + gst_vaapi_display_get_display (GST_VAAPI_DISPLAY (display)) + +/** + * GST_VAAPI_DISPLAY_LOCK: + * @display: a #GstVaapiDisplay + * + * Locks @display + */ +#define GST_VAAPI_DISPLAY_LOCK(display) \ + gst_vaapi_display_lock (GST_VAAPI_DISPLAY (display)) + +/** + * GST_VAAPI_DISPLAY_UNLOCK: + * @display: a #GstVaapiDisplay + * + * Unlocks @display + */ +#define GST_VAAPI_DISPLAY_UNLOCK(display) \ + gst_vaapi_display_unlock (GST_VAAPI_DISPLAY (display)) + +typedef struct _GstVaapiDisplayInfo GstVaapiDisplayInfo; +typedef struct _GstVaapiDisplay GstVaapiDisplay; + +/** + * GstVaapiDriverQuirks: + * @GST_VAAPI_DRIVER_QUIRK_NO_CHECK_SURFACE_PUT_IMAGE: if driver + * crashes when try to put an image in a reused surface. + * https://gitlab.freedesktop.org/mesa/mesa/merge_requests/2016 + * @GST_VAAPI_DRIVER_QUIRK_NO_CHECK_VPP_COLOR_STD: if driver does not + * properly report supported vpp color standards. + * @GST_VAAPI_DRIVER_QUIRK_MISSING_RGBA_IMAGE_FORMAT: i965 driver doesn't + * report to support ARGB format, but if it's forced to create a RGBA + * surface, it works. Driver issue: + * https://github.com/intel/intel-vaapi-driver/issues/500 + * @GST_VAAPI_DRIVER_QUIRK_JPEG_ENC_SHIFT_VALUE_BY_50: if the driver shifts + * the value by 50 when calculating quantization from quality level + * @GST_VAAPI_DRIVER_QUIRK_HEVC_ENC_SLICE_NOT_SPAN_TILE: The requirement + * that one slice should not span tiles when tile is enabled. + * @GST_VAAPI_DRIVER_QUIRK_JPEG_DEC_BROKEN_FORMATS: i965 driver does not + * report all the handled formats for JPEG decoding. + */ +typedef enum +{ + GST_VAAPI_DRIVER_QUIRK_NO_CHECK_SURFACE_PUT_IMAGE = (1U << 0), + GST_VAAPI_DRIVER_QUIRK_NO_CHECK_VPP_COLOR_STD = (1U << 1), + GST_VAAPI_DRIVER_QUIRK_MISSING_RGBA_IMAGE_FORMAT = (1U << 3), + GST_VAAPI_DRIVER_QUIRK_JPEG_ENC_SHIFT_VALUE_BY_50 = (1U << 4), + GST_VAAPI_DRIVER_QUIRK_HEVC_ENC_SLICE_NOT_SPAN_TILE = (1U << 5), + GST_VAAPI_DRIVER_QUIRK_JPEG_DEC_BROKEN_FORMATS = (1U << 6), +} GstVaapiDriverQuirks; + +/** + * GstVaapiDisplayType: + * @GST_VAAPI_DISPLAY_TYPE_ANY: Automatic detection of the display type. + * @GST_VAAPI_DISPLAY_TYPE_X11: VA/X11 display. + * @GST_VAAPI_DISPLAY_TYPE_GLX: VA/GLX display. + * @GST_VAAPI_DISPLAY_TYPE_WAYLAND: VA/Wayland display. + * @GST_VAAPI_DISPLAY_TYPE_DRM: VA/DRM display. + * @GST_VAAPI_DISPLAY_TYPE_EGL: VA/EGL display. + */ +typedef enum +{ + GST_VAAPI_DISPLAY_TYPE_ANY = 0, + GST_VAAPI_DISPLAY_TYPE_X11, + GST_VAAPI_DISPLAY_TYPE_GLX, + GST_VAAPI_DISPLAY_TYPE_WAYLAND, + GST_VAAPI_DISPLAY_TYPE_DRM, + GST_VAAPI_DISPLAY_TYPE_EGL, +} GstVaapiDisplayType; + +#define GST_VAAPI_TYPE_DISPLAY_TYPE \ + (gst_vaapi_display_type_get_type()) + +GType +gst_vaapi_display_type_get_type (void) G_GNUC_CONST; + +GType +gst_vaapi_display_get_type (void) G_GNUC_CONST; + +gboolean +gst_vaapi_display_type_is_compatible (GstVaapiDisplayType type1, + GstVaapiDisplayType type2); + +/** + * GstVaapiDisplayInfo: + * + * Generic class to retrieve VA display info + */ +struct _GstVaapiDisplayInfo +{ + GstVaapiDisplay *display; + gchar *display_name; + VADisplay va_display; + gpointer native_display; +}; + +/** + * GstVaapiDisplayProperties: + * @GST_VAAPI_DISPLAY_PROP_RENDER_MODE: rendering mode (#GstVaapiRenderMode). + * @GST_VAAPI_DISPLAY_PROP_ROTATION: rotation angle (#GstVaapiRotation). + * @GST_VAAPI_DISPLAY_PROP_HUE: hue (float: [-180 ; 180], default: 0). + * @GST_VAAPI_DISPLAY_PROP_SATURATION: saturation (float: [0 ; 2], default: 1). + * @GST_VAAPI_DISPLAY_PROP_BRIGHTNESS: brightness (float: [-1 ; 1], default: 0). + * @GST_VAAPI_DISPLAY_PROP_CONTRAST: contrast (float: [0 ; 2], default: 1). + */ +#define GST_VAAPI_DISPLAY_PROP_RENDER_MODE "render-mode" +#define GST_VAAPI_DISPLAY_PROP_ROTATION "rotation" +#define GST_VAAPI_DISPLAY_PROP_HUE "hue" +#define GST_VAAPI_DISPLAY_PROP_SATURATION "saturation" +#define GST_VAAPI_DISPLAY_PROP_BRIGHTNESS "brightness" +#define GST_VAAPI_DISPLAY_PROP_CONTRAST "contrast" + +GstVaapiDisplay * +gst_vaapi_display_new_with_display (VADisplay va_display); + +void +gst_vaapi_display_replace (GstVaapiDisplay ** old_display_ptr, + GstVaapiDisplay * new_display); + +void +gst_vaapi_display_lock (GstVaapiDisplay * display); + +void +gst_vaapi_display_unlock (GstVaapiDisplay * display); + +void +gst_vaapi_display_sync (GstVaapiDisplay * display); + +void +gst_vaapi_display_flush (GstVaapiDisplay * display); + +GstVaapiDisplayType +gst_vaapi_display_get_class_type (GstVaapiDisplay * display); + +GstVaapiDisplayType +gst_vaapi_display_get_display_type (GstVaapiDisplay * display); + +const gchar * +gst_vaapi_display_get_display_name (GstVaapiDisplay * display); + +VADisplay +gst_vaapi_display_get_display (GstVaapiDisplay * display); + +guint +gst_vaapi_display_get_width (GstVaapiDisplay * display); + +guint +gst_vaapi_display_get_height (GstVaapiDisplay * display); + +void +gst_vaapi_display_get_size (GstVaapiDisplay * display, guint * pwidth, + guint * pheight); + +void +gst_vaapi_display_get_pixel_aspect_ratio (GstVaapiDisplay * display, + guint * par_n, guint * par_d); + +gboolean +gst_vaapi_display_has_video_processing (GstVaapiDisplay * display); + +GArray * +gst_vaapi_display_get_decode_profiles (GstVaapiDisplay * display); + +gboolean +gst_vaapi_display_has_decoder (GstVaapiDisplay * display, + GstVaapiProfile profile, GstVaapiEntrypoint entrypoint); + +GArray * +gst_vaapi_display_get_encode_profiles (GstVaapiDisplay * display); + +GArray * +gst_vaapi_display_get_encode_profiles_by_codec (GstVaapiDisplay * display, + GstVaapiCodec codec); + +gboolean +gst_vaapi_display_has_encoder (GstVaapiDisplay * display, + GstVaapiProfile profile, GstVaapiEntrypoint entrypoint); + +GArray * +gst_vaapi_display_get_image_formats (GstVaapiDisplay * display); + +gboolean +gst_vaapi_display_has_image_format (GstVaapiDisplay * display, + GstVideoFormat format); + +GArray * +gst_vaapi_display_get_subpicture_formats (GstVaapiDisplay * display); + +gboolean +gst_vaapi_display_has_subpicture_format (GstVaapiDisplay * display, + GstVideoFormat format, guint * flags_ptr); + +gboolean +gst_vaapi_display_has_property (GstVaapiDisplay * display, const gchar * name); + +gboolean +gst_vaapi_display_get_render_mode (GstVaapiDisplay * display, + GstVaapiRenderMode * pmode); + +gboolean +gst_vaapi_display_set_render_mode (GstVaapiDisplay * display, + GstVaapiRenderMode mode); + +GstVaapiRotation +gst_vaapi_display_get_rotation (GstVaapiDisplay * display); + +gboolean +gst_vaapi_display_set_rotation (GstVaapiDisplay * display, + GstVaapiRotation rotation); + +const gchar * +gst_vaapi_display_get_vendor_string (GstVaapiDisplay * display); + +gboolean +gst_vaapi_display_has_opengl (GstVaapiDisplay * display); + +void +gst_vaapi_display_reset_texture_map (GstVaapiDisplay * display); + +gboolean +gst_vaapi_display_has_driver_quirks (GstVaapiDisplay * display, guint quirks); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDisplay, gst_object_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_DISPLAY_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_drm.c b/gst-libs/gst/vaapi/gstvaapidisplay_drm.c new file mode 100644 index 0000000000..1fc376a520 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_drm.c @@ -0,0 +1,470 @@ +/* + * gstvaapidisplay_drm.c - VA/DRM display abstraction + * + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapidisplay_drm + * @short_description: VA/DRM display abstraction + */ + +#define _GNU_SOURCE +#include "sysdeps.h" +#include +#include +#include +#include +#include +#include "gstvaapiutils.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapidisplay_drm.h" +#include "gstvaapidisplay_drm_priv.h" +#include "gstvaapiwindow_drm.h" + +#define DEBUG_VAAPI_DISPLAY 1 +#include "gstvaapidebug.h" + +#ifndef MAXPATHLEN +#if defined(PATH_MAX) +#define MAXPATHLEN PATH_MAX +#elif defined(_PC_PATH_MAX) +#define MAXPATHLEN sysconf(_PC_PATH_MAX) +#else +#define MAXPATHLEN 2048 +#endif +#endif + +G_DEFINE_TYPE_WITH_PRIVATE (GstVaapiDisplayDRM, gst_vaapi_display_drm, + GST_TYPE_VAAPI_DISPLAY); + +typedef enum +{ + DRM_DEVICE_LEGACY = 1, + DRM_DEVICE_RENDERNODES, +} DRMDeviceType; + +static DRMDeviceType g_drm_device_type; +static GMutex g_drm_device_type_lock; +static const gchar *allowed_subsystems[] = { "pci", "platform", NULL }; + +static gboolean +supports_vaapi (int fd) +{ + gboolean ret; + VADisplay va_dpy; + + va_dpy = vaGetDisplayDRM (fd); + if (!va_dpy) + return FALSE; + + ret = vaapi_initialize (va_dpy); + vaTerminate (va_dpy); + return ret; +} + +/* Get default device path. Actually, the first match in the DRM subsystem */ +static const gchar * +get_default_device_path (GstVaapiDisplay * display) +{ + GstVaapiDisplayDRMPrivate *const priv = + GST_VAAPI_DISPLAY_DRM_PRIVATE (display); + const gchar *syspath, *devpath; + struct udev *udev = NULL; + struct udev_device *device, *parent; + struct udev_enumerate *e = NULL; + struct udev_list_entry *l; + gint i; + int fd; + + if (!priv->device_path_default) { + udev = udev_new (); + if (!udev) + goto end; + + e = udev_enumerate_new (udev); + if (!e) + goto end; + + udev_enumerate_add_match_subsystem (e, "drm"); + switch (g_drm_device_type) { + case DRM_DEVICE_LEGACY: + udev_enumerate_add_match_sysname (e, "card[0-9]*"); + break; + case DRM_DEVICE_RENDERNODES: + udev_enumerate_add_match_sysname (e, "renderD[0-9]*"); + break; + default: + GST_ERROR ("unknown drm device type (%d)", g_drm_device_type); + goto end; + } + udev_enumerate_scan_devices (e); + udev_list_entry_foreach (l, udev_enumerate_get_list_entry (e)) { + syspath = udev_list_entry_get_name (l); + device = udev_device_new_from_syspath (udev, syspath); + parent = udev_device_get_parent (device); + + for (i = 0; allowed_subsystems[i] != NULL; i++) + if (g_strcmp0 (udev_device_get_subsystem (parent), + allowed_subsystems[i]) == 0) + break; + + if (allowed_subsystems[i] == NULL) { + udev_device_unref (device); + continue; + } + + devpath = udev_device_get_devnode (device); + fd = open (devpath, O_RDWR | O_CLOEXEC); + if (fd < 0) { + udev_device_unref (device); + continue; + } + + if (supports_vaapi (fd)) + priv->device_path_default = g_strdup (devpath); + close (fd); + udev_device_unref (device); + if (priv->device_path_default) + break; + } + + end: + if (e) + udev_enumerate_unref (e); + if (udev) + udev_unref (udev); + } + return priv->device_path_default; +} + +/* Reconstruct a device path without our prefix */ +static const gchar * +get_device_path (GstVaapiDisplay * display) +{ + GstVaapiDisplayDRMPrivate *const priv = + GST_VAAPI_DISPLAY_DRM_PRIVATE (display); + const gchar *device_path = priv->device_path; + + if (!device_path || *device_path == '\0') + return NULL; + return device_path; +} + +/* Mangle device path with our prefix */ +static gboolean +set_device_path (GstVaapiDisplay * display, const gchar * device_path) +{ + GstVaapiDisplayDRMPrivate *const priv = + GST_VAAPI_DISPLAY_DRM_PRIVATE (display); + + g_free (priv->device_path); + priv->device_path = NULL; + + if (!device_path) { + device_path = get_default_device_path (display); + if (!device_path) + return FALSE; + } + priv->device_path = g_strdup (device_path); + return priv->device_path != NULL; +} + +/* Set device path from file descriptor */ +static gboolean +set_device_path_from_fd (GstVaapiDisplay * display, gint drm_device) +{ + GstVaapiDisplayDRMPrivate *const priv = + GST_VAAPI_DISPLAY_DRM_PRIVATE (display); + gboolean success = FALSE; + gchar fd_name[MAXPATHLEN]; + GError *error = NULL; + + g_free (priv->device_path); + priv->device_path = NULL; + + if (drm_device < 0) + goto end; + + sprintf (fd_name, "/proc/%d/fd/%d", getpid (), drm_device); + priv->device_path = g_file_read_link (fd_name, &error); + + if (error) { + g_error_free (error); + goto end; + } + + if (g_str_has_prefix (priv->device_path, "/dev/dri/card") || + g_str_has_prefix (priv->device_path, "/dev/dri/renderD")) + success = TRUE; + else { + g_free (priv->device_path); + priv->device_path = NULL; + } + +end: + return success; +} + +static gboolean +gst_vaapi_display_drm_bind_display (GstVaapiDisplay * display, + gpointer native_display) +{ + GstVaapiDisplayDRMPrivate *const priv = + GST_VAAPI_DISPLAY_DRM_PRIVATE (display); + + priv->drm_device = GPOINTER_TO_INT (native_display); + priv->use_foreign_display = TRUE; + + if (!set_device_path_from_fd (display, priv->drm_device)) + return FALSE; + return TRUE; +} + +static gboolean +gst_vaapi_display_drm_open_display (GstVaapiDisplay * display, + const gchar * name) +{ + GstVaapiDisplayDRMPrivate *const priv = + GST_VAAPI_DISPLAY_DRM_PRIVATE (display); + + if (!set_device_path (display, name)) + return FALSE; + + priv->drm_device = open (get_device_path (display), O_RDWR | O_CLOEXEC); + if (priv->drm_device < 0) + return FALSE; + priv->use_foreign_display = FALSE; + + return TRUE; +} + +static void +gst_vaapi_display_drm_close_display (GstVaapiDisplay * display) +{ + GstVaapiDisplayDRMPrivate *const priv = + GST_VAAPI_DISPLAY_DRM_PRIVATE (display); + + if (priv->drm_device >= 0) { + if (!priv->use_foreign_display) + close (priv->drm_device); + priv->drm_device = -1; + } + + g_clear_pointer (&priv->device_path, g_free); + g_clear_pointer (&priv->device_path_default, g_free); +} + +static gboolean +gst_vaapi_display_drm_get_display_info (GstVaapiDisplay * display, + GstVaapiDisplayInfo * info) +{ + GstVaapiDisplayDRMPrivate *const priv = + GST_VAAPI_DISPLAY_DRM_PRIVATE (display); + + info->native_display = GINT_TO_POINTER (priv->drm_device); + info->display_name = priv->device_path; + if (!info->va_display) { + info->va_display = vaGetDisplayDRM (priv->drm_device); + if (!info->va_display) + return FALSE; + } + return TRUE; +} + +static GstVaapiWindow * +gst_vaapi_display_drm_create_window (GstVaapiDisplay * display, GstVaapiID id, + guint width, guint height) +{ + return id != GST_VAAPI_ID_INVALID ? + NULL : gst_vaapi_window_drm_new (display, width, height); +} + +static void +gst_vaapi_display_drm_init (GstVaapiDisplayDRM * display) +{ + GstVaapiDisplayDRMPrivate *const priv = + gst_vaapi_display_drm_get_instance_private (display); + + display->priv = priv; + priv->drm_device = -1; +} + +static void +gst_vaapi_display_drm_class_init (GstVaapiDisplayDRMClass * klass) +{ + GstVaapiDisplayClass *const dpy_class = GST_VAAPI_DISPLAY_CLASS (klass); + + dpy_class->display_type = GST_VAAPI_DISPLAY_TYPE_DRM; + dpy_class->bind_display = gst_vaapi_display_drm_bind_display; + dpy_class->open_display = gst_vaapi_display_drm_open_display; + dpy_class->close_display = gst_vaapi_display_drm_close_display; + dpy_class->get_display = gst_vaapi_display_drm_get_display_info; + dpy_class->create_window = gst_vaapi_display_drm_create_window; +} + +/** + * gst_vaapi_display_drm_new: + * @device_path: the DRM device path + * + * Opens an DRM file descriptor using @device_path and returns a newly + * allocated #GstVaapiDisplay object. The DRM display will be cloed + * when the reference count of the object reaches zero. + * + * If @device_path is NULL, the DRM device path will be automatically + * determined as the first positive match in the list of available DRM + * devices. + * + * Return value: a newly allocated #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_display_drm_new (const gchar * device_path) +{ + GstVaapiDisplay *display; + guint types[3], i, num_types = 0; + gpointer device_paths[3]; + + g_mutex_lock (&g_drm_device_type_lock); + if (device_path) { + device_paths[num_types] = (gpointer) device_path; + types[num_types++] = 0; + } else if (g_drm_device_type) { + device_paths[num_types] = (gpointer) device_path; + types[num_types++] = g_drm_device_type; + } else { + const gchar *user_choice = g_getenv ("GST_VAAPI_DRM_DEVICE"); + + if (user_choice) { + device_paths[num_types] = (gpointer) user_choice; + types[num_types++] = 0; + } else { + device_paths[num_types] = (gpointer) device_path; + types[num_types++] = DRM_DEVICE_RENDERNODES; + device_paths[num_types] = (gpointer) device_path; + types[num_types++] = DRM_DEVICE_LEGACY; + } + } + + for (i = 0; i < num_types; i++) { + g_drm_device_type = types[i]; + display = g_object_new (GST_TYPE_VAAPI_DISPLAY_DRM, NULL); + display = gst_vaapi_display_config (display, + GST_VAAPI_DISPLAY_INIT_FROM_DISPLAY_NAME, device_paths[i]); + if (display || device_path) + break; + } + g_mutex_unlock (&g_drm_device_type_lock); + return display; +} + +/** + * gst_vaapi_display_drm_new_with_device: + * @device: an open DRM device (file descriptor) + * + * Creates a #GstVaapiDisplay based on the open DRM @device. The + * caller still owns the device file descriptor and must call close() + * when all #GstVaapiDisplay references are released. Doing so too + * early can yield undefined behaviour. + * + * Return value: a newly allocated #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_display_drm_new_with_device (gint device) +{ + GstVaapiDisplay *display; + + g_return_val_if_fail (device >= 0, NULL); + + display = g_object_new (GST_TYPE_VAAPI_DISPLAY_DRM, NULL); + return gst_vaapi_display_config (display, + GST_VAAPI_DISPLAY_INIT_FROM_NATIVE_DISPLAY, GINT_TO_POINTER (device)); +} + +/** + * gst_vaapi_display_drm_new_with_va_display: + * @va_display: a VADisplay #va_display + * @fd: an open DRM device (file descriptor) #fd + * + * Creates a #GstVaapiDisplay based on the VADisplay @va_display and + * the open DRM device @fd. + * The caller still owns the device file descriptor and must call close() + * when all #GstVaapiDisplay references are released. + * + * Return value: a newly allocated #GstVaapiDisplay object + */ + +GstVaapiDisplay * +gst_vaapi_display_drm_new_with_va_display (VADisplay va_display, gint fd) +{ + GstVaapiDisplay *display; + GstVaapiDisplayInfo info = { + .va_display = va_display, + .native_display = GINT_TO_POINTER (fd), + }; + + g_return_val_if_fail (fd >= 0, NULL); + + display = g_object_new (GST_TYPE_VAAPI_DISPLAY_DRM, NULL); + if (!gst_vaapi_display_config (display, + GST_VAAPI_DISPLAY_INIT_FROM_VA_DISPLAY, &info)) { + gst_object_unref (display); + return NULL; + } + + return display; +} + +/** + * gst_vaapi_display_drm_get_device: + * @display: a #GstVaapiDisplayDRM + * + * Returns the underlying DRM device file descriptor that was created + * by gst_vaapi_display_drm_new() or that was bound from + * gst_vaapi_display_drm_new_with_device(). + * + * Return value: the DRM file descriptor attached to @display + */ +gint +gst_vaapi_display_drm_get_device (GstVaapiDisplayDRM * display) +{ + g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_DRM (display), -1); + + return GST_VAAPI_DISPLAY_DRM_DEVICE (display); +} + +/** + * gst_vaapi_display_drm_get_device_path: + * @display: a #GstVaapiDisplayDRM + * + * Returns the underlying DRM device path name was created by + * gst_vaapi_display_drm_new() or that was bound from + * gst_vaapi_display_drm_new_with_device(). + * + * Note: the #GstVaapiDisplayDRM object owns the resulting string, so + * it shall not be deallocated. + * + * Return value: the DRM device path name attached to @display + */ +const gchar * +gst_vaapi_display_drm_get_device_path (GstVaapiDisplayDRM * display) +{ + g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_DRM (display), NULL); + + return get_device_path (GST_VAAPI_DISPLAY_CAST (display)); +} diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_drm.h b/gst-libs/gst/vaapi/gstvaapidisplay_drm.h new file mode 100644 index 0000000000..199c6eae7d --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_drm.h @@ -0,0 +1,59 @@ +/* + * gstvaapidisplay_drm.h - VA/DRM display abstraction + * + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DISPLAY_DRM_H +#define GST_VAAPI_DISPLAY_DRM_H + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_DISPLAY_DRM (gst_vaapi_display_drm_get_type ()) +#define GST_VAAPI_DISPLAY_DRM(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DISPLAY_DRM, GstVaapiDisplayDRM)) + +typedef struct _GstVaapiDisplayDRM GstVaapiDisplayDRM; + +GstVaapiDisplay * +gst_vaapi_display_drm_new (const gchar * device_path); + +GstVaapiDisplay * +gst_vaapi_display_drm_new_with_device (gint device); + +GstVaapiDisplay * +gst_vaapi_display_drm_new_with_va_display (VADisplay va_display, gint fd); + +gint +gst_vaapi_display_drm_get_device (GstVaapiDisplayDRM * display); + +const gchar * +gst_vaapi_display_drm_get_device_path (GstVaapiDisplayDRM * + display); + +GType +gst_vaapi_display_drm_get_type (void) G_GNUC_CONST; + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDisplayDRM, gst_object_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_DISPLAY_DRM_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_drm_priv.h b/gst-libs/gst/vaapi/gstvaapidisplay_drm_priv.h new file mode 100644 index 0000000000..ef3d2559bd --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_drm_priv.h @@ -0,0 +1,90 @@ +/* + * gstvaapidisplay_drm_priv.h - Internal VA/DRM interface + * + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DISPLAY_DRM_PRIV_H +#define GST_VAAPI_DISPLAY_DRM_PRIV_H + +#include +#include "gstvaapidisplay_priv.h" + +G_BEGIN_DECLS + +#define GST_VAAPI_IS_DISPLAY_DRM(display) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((display), GST_TYPE_VAAPI_DISPLAY_DRM)) + +#define GST_VAAPI_DISPLAY_DRM_CAST(display) \ + ((GstVaapiDisplayDRM *)(display)) + +#define GST_VAAPI_DISPLAY_DRM_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_DISPLAY_DRM, GstVaapiDisplayDRMClass)) + +#define GST_VAAPI_DISPLAY_DRM_PRIVATE(display) \ + (GST_VAAPI_DISPLAY_DRM_CAST(display)->priv) + +typedef struct _GstVaapiDisplayDRMPrivate GstVaapiDisplayDRMPrivate; +typedef struct _GstVaapiDisplayDRMClass GstVaapiDisplayDRMClass; + +/** + * GST_VAAPI_DISPLAY_DRM_DEVICE: + * @display: a #GstVaapiDisplay + * + * Macro that evaluates to the underlying DRM file descriptor of @display + */ +#undef GST_VAAPI_DISPLAY_DRM_DEVICE +#define GST_VAAPI_DISPLAY_DRM_DEVICE(display) \ + GST_VAAPI_DISPLAY_DRM_PRIVATE(display)->drm_device + +struct _GstVaapiDisplayDRMPrivate +{ + gchar *device_path_default; + gchar *device_path; + gint drm_device; + guint use_foreign_display:1; // Foreign native_display? +}; + +/** + * GstVaapiDisplayDRM: + * + * VA/DRM display wrapper. + */ +struct _GstVaapiDisplayDRM +{ + /*< private >*/ + GstVaapiDisplay parent_instance; + + GstVaapiDisplayDRMPrivate *priv; +}; + +/** + * GstVaapiDisplayDRMClass: + * + * VA/DRM display wrapper clas. + */ +struct _GstVaapiDisplayDRMClass +{ + /*< private >*/ + GstVaapiDisplayClass parent_class; +}; + +G_END_DECLS + +#endif /* GST_VAAPI_DISPLAY_DRM_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_egl.c b/gst-libs/gst/vaapi/gstvaapidisplay_egl.c new file mode 100644 index 0000000000..fcffecdbcb --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_egl.c @@ -0,0 +1,471 @@ +/* + * gstvaapidisplay_egl.c - VA/EGL display abstraction + * + * Copyright (C) 2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include "gstvaapidisplay_egl.h" +#include "gstvaapidisplay_egl_priv.h" +#include "gstvaapiwindow.h" +#include "gstvaapiwindow_egl.h" +#include "gstvaapiwindow_priv.h" +#include "gstvaapitexture_egl.h" + +#if USE_X11 +#include "gstvaapidisplay_x11.h" +#endif +#if USE_WAYLAND +#include "gstvaapidisplay_wayland.h" +#endif + +#define DEBUG_VAAPI_DISPLAY 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE (GstVaapiDisplayEGL, gst_vaapi_display_egl, + GST_TYPE_VAAPI_DISPLAY); + +/* ------------------------------------------------------------------------- */ +/* --- EGL backend implementation --- */ +/* ------------------------------------------------------------------------- */ + +typedef struct +{ + gpointer display; + guint display_type; + guint gles_version; + gpointer gl_display; +} InitParams; + +static gboolean +reset_context (GstVaapiDisplayEGL * display, EGLContext gl_context) +{ + EglConfig *config; + EglContext *ctx; + + egl_object_replace (&display->egl_context, NULL); + + if (gl_context != EGL_NO_CONTEXT) + ctx = egl_context_new_wrapped (display->egl_display, gl_context); + else { + config = egl_config_new (display->egl_display, display->gles_version, + GST_VIDEO_FORMAT_RGB); + if (!config) + return FALSE; + + ctx = egl_context_new (display->egl_display, config, NULL); + egl_object_unref (config); + } + if (!ctx) + return FALSE; + + egl_object_replace (&display->egl_context, ctx); + egl_object_unref (ctx); + return TRUE; +} + +static inline gboolean +ensure_context (GstVaapiDisplayEGL * display) +{ + return display->egl_context || reset_context (display, EGL_NO_CONTEXT); +} + +static inline gboolean +ensure_context_is_wrapped (GstVaapiDisplayEGL * display, EGLContext gl_context) +{ + return (display->egl_context && + display->egl_context->base.handle.p == gl_context) || + reset_context (display, gl_context); +} + +static gboolean +gst_vaapi_display_egl_bind_display (GstVaapiDisplay * base_display, + gpointer native_params) +{ + GstVaapiDisplay *native_vaapi_display; + GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display); + EglDisplay *egl_display; + EGLDisplay *native_egl_display; + guint gl_platform = EGL_PLATFORM_UNKNOWN; + const InitParams *params = (InitParams *) native_params; + GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display); + + native_vaapi_display = params->display; + native_egl_display = params->gl_display; + + if (!native_vaapi_display) { +#if USE_X11 + if (params->display_type == GST_VAAPI_DISPLAY_TYPE_ANY + || params->display_type == GST_VAAPI_DISPLAY_TYPE_X11 + || params->display_type == GST_VAAPI_DISPLAY_TYPE_EGL) + native_vaapi_display = gst_vaapi_display_x11_new (NULL); +#endif +#if USE_WAYLAND + if (!native_vaapi_display) + native_vaapi_display = gst_vaapi_display_wayland_new (NULL); +#endif + } else { + /* thus it could be assigned to parent */ + gst_object_ref (native_vaapi_display); + } + if (!native_vaapi_display) + return FALSE; + + gst_vaapi_display_replace (&display->display, native_vaapi_display); + priv->parent = native_vaapi_display; + + switch (GST_VAAPI_DISPLAY_GET_CLASS_TYPE (display->display)) { + case GST_VAAPI_DISPLAY_TYPE_X11: + gl_platform = EGL_PLATFORM_X11; + break; + case GST_VAAPI_DISPLAY_TYPE_WAYLAND: + gl_platform = EGL_PLATFORM_WAYLAND; + break; + default: + break; + } + + if (native_egl_display) { + egl_display = egl_display_new_wrapped (native_egl_display); + } else { + egl_display = egl_display_new (GST_VAAPI_DISPLAY_NATIVE (display->display), + gl_platform); + } + if (!egl_display) + return FALSE; + + egl_object_replace (&display->egl_display, egl_display); + egl_object_unref (egl_display); + display->gles_version = params->gles_version; + return TRUE; +} + +static void +gst_vaapi_display_egl_close_display (GstVaapiDisplay * base_display) +{ + GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display); + gst_vaapi_display_replace (&display->display, NULL); +} + +static void +gst_vaapi_display_egl_lock (GstVaapiDisplay * base_display) +{ + GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display); + GstVaapiDisplayClass *const klass = + GST_VAAPI_DISPLAY_GET_CLASS (display->display); + + if (klass->lock) + klass->lock (display->display); +} + +static void +gst_vaapi_display_egl_unlock (GstVaapiDisplay * base_display) +{ + GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display); + GstVaapiDisplayClass *const klass = + GST_VAAPI_DISPLAY_GET_CLASS (display->display); + + if (klass->unlock) + klass->unlock (display->display); +} + +static void +gst_vaapi_display_egl_sync (GstVaapiDisplay * base_display) +{ + GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display); + GstVaapiDisplayClass *const klass = + GST_VAAPI_DISPLAY_GET_CLASS (display->display); + + if (klass->sync) + klass->sync (display->display); + else if (klass->flush) + klass->flush (display->display); +} + +static void +gst_vaapi_display_egl_flush (GstVaapiDisplay * base_display) +{ + GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display); + GstVaapiDisplayClass *const klass = + GST_VAAPI_DISPLAY_GET_CLASS (display->display); + + if (klass->flush) + klass->flush (display->display); +} + +static gboolean +gst_vaapi_display_egl_get_display_info (GstVaapiDisplay * base_display, + GstVaapiDisplayInfo * info) +{ + GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display); + GstVaapiDisplayClass *const klass = + GST_VAAPI_DISPLAY_GET_CLASS (display->display); + + info->va_display = GST_VAAPI_DISPLAY_VADISPLAY (display->display); + + if (klass->get_display && !klass->get_display (display->display, info)) + return FALSE; + return TRUE; +} + +static void +gst_vaapi_display_egl_get_size (GstVaapiDisplay * base_display, + guint * width_ptr, guint * height_ptr) +{ + GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display); + GstVaapiDisplayClass *const klass = + GST_VAAPI_DISPLAY_GET_CLASS (display->display); + + if (klass->get_size) + klass->get_size (display->display, width_ptr, height_ptr); +} + +static void +gst_vaapi_display_egl_get_size_mm (GstVaapiDisplay * base_display, + guint * width_ptr, guint * height_ptr) +{ + GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display); + GstVaapiDisplayClass *const klass = + GST_VAAPI_DISPLAY_GET_CLASS (display->display); + + if (klass->get_size_mm) + klass->get_size_mm (display->display, width_ptr, height_ptr); +} + +static guintptr +gst_vaapi_display_egl_get_visual_id (GstVaapiDisplay * base_display, + GstVaapiWindow * window) +{ + GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display); + if (!ensure_context (display)) + return 0; + return display->egl_context->config->visual_id; +} + +static GstVaapiWindow * +gst_vaapi_display_egl_create_window (GstVaapiDisplay * display, GstVaapiID id, + guint width, guint height) +{ + if (id != GST_VAAPI_ID_INVALID) + return NULL; + return gst_vaapi_window_egl_new (display, width, height); +} + +static void +ensure_texture_map (GstVaapiDisplayEGL * display) +{ + if (!display->texture_map) + display->texture_map = gst_vaapi_texture_map_new (); +} + +static GstVaapiTexture * +gst_vaapi_display_egl_create_texture (GstVaapiDisplay * display, GstVaapiID id, + guint target, guint format, guint width, guint height) +{ + GstVaapiDisplayEGL *dpy = GST_VAAPI_DISPLAY_EGL (display); + GstVaapiTexture *texture; + + if (id == GST_VAAPI_ID_INVALID) + return gst_vaapi_texture_egl_new (display, target, format, width, height); + + ensure_texture_map (dpy); + if (!(texture = gst_vaapi_texture_map_lookup (dpy->texture_map, id))) { + if ((texture = + gst_vaapi_texture_egl_new_wrapped (display, id, target, format, + width, height))) { + gst_vaapi_texture_map_add (dpy->texture_map, texture, id); + } + } + + return texture; +} + +static GstVaapiTextureMap * +gst_vaapi_display_egl_get_texture_map (GstVaapiDisplay * display) +{ + return GST_VAAPI_DISPLAY_EGL (display)->texture_map; +} + +static void +gst_vaapi_display_egl_finalize (GObject * object) +{ + GstVaapiDisplayEGL *dpy = GST_VAAPI_DISPLAY_EGL (object); + + if (dpy->texture_map) + gst_object_unref (dpy->texture_map); + + /* HACK to avoid to call twice vaTerminate() since this and the + * proxied display share the same vaDisplay */ + GST_VAAPI_DISPLAY_VADISPLAY (object) = NULL; + + egl_object_replace (&dpy->egl_display, NULL); + egl_object_replace (&dpy->egl_context, NULL); + + gst_vaapi_display_replace (&dpy->display, NULL); + + G_OBJECT_CLASS (gst_vaapi_display_egl_parent_class)->finalize (object); +} + +static void +gst_vaapi_display_egl_init (GstVaapiDisplayEGL * display) +{ +} + +static void +gst_vaapi_display_egl_class_init (GstVaapiDisplayEGLClass * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstVaapiDisplayClass *const dpy_class = GST_VAAPI_DISPLAY_CLASS (klass); + + object_class->finalize = gst_vaapi_display_egl_finalize; + dpy_class->display_type = GST_VAAPI_DISPLAY_TYPE_EGL; + dpy_class->bind_display = gst_vaapi_display_egl_bind_display; + dpy_class->close_display = gst_vaapi_display_egl_close_display; + dpy_class->lock = gst_vaapi_display_egl_lock; + dpy_class->unlock = gst_vaapi_display_egl_unlock; + dpy_class->sync = gst_vaapi_display_egl_sync; + dpy_class->flush = gst_vaapi_display_egl_flush; + dpy_class->get_display = gst_vaapi_display_egl_get_display_info; + dpy_class->get_size = gst_vaapi_display_egl_get_size; + dpy_class->get_size_mm = gst_vaapi_display_egl_get_size_mm; + dpy_class->get_visual_id = gst_vaapi_display_egl_get_visual_id; + dpy_class->create_window = gst_vaapi_display_egl_create_window; + dpy_class->create_texture = gst_vaapi_display_egl_create_texture; + dpy_class->get_texture_map = gst_vaapi_display_egl_get_texture_map; +} + +/** + * gst_vaapi_display_egl_new: + * @display: a #GstVaapiDisplay, or %NULL to pick any one + * @gles_version: the OpenGL ES version API to use + * + * Creates a new #GstVaapiDisplay object suitable in EGL context. If + * the native @display is %NULL, then any type of display is picked, + * i.e. one that can be successfully opened. The @gles_version will + * further ensure the OpenGL ES API to use, or zero to indicate + * "desktop" OpenGL. + * + * Return value: a newly allocated #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_display_egl_new (GstVaapiDisplay * display, guint gles_version) +{ + GstVaapiDisplay *wrapper_display; + InitParams params = { + .gles_version = gles_version, + }; + + if (display) { + params.display = display; + params.display_type = GST_VAAPI_DISPLAY_VADISPLAY_TYPE (display); + } + + wrapper_display = g_object_new (GST_TYPE_VAAPI_DISPLAY_EGL, NULL); + return gst_vaapi_display_config (wrapper_display, + GST_VAAPI_DISPLAY_INIT_FROM_NATIVE_DISPLAY, ¶ms); +} + +/** + * gst_vaapi_display_egl_new_with_native_display: + * @native_display: an EGLDisplay object + * @display_type: the display type of @native_display + * @gles_version: the OpenGL ES version API to use + * + * Creates a #GstVaapiDisplay based on the native display supplied in + * as @native_display. The caller still owns the display and must call + * native display close function when all #GstVaapiDisplay references + * are released. Doing so too early can yield undefined behaviour. + * + * The @gles_version will further ensure the OpenGL ES API to use, or + * zero to indicate "desktop" OpenGL. + * + * Return value: a newly allocated #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_display_egl_new_with_native_display (gpointer native_display, + GstVaapiDisplayType display_type, guint gles_version) +{ + GstVaapiDisplay *display; + InitParams params = { + .display_type = display_type, + .gl_display = native_display, + .gles_version = gles_version, + }; + + g_return_val_if_fail (native_display != NULL, NULL); + + display = g_object_new (GST_TYPE_VAAPI_DISPLAY_EGL, NULL); + return gst_vaapi_display_config (display, + GST_VAAPI_DISPLAY_INIT_FROM_NATIVE_DISPLAY, ¶ms); +} + +EglContext * +gst_vaapi_display_egl_get_context (GstVaapiDisplayEGL * display) +{ + return ensure_context (display) ? display->egl_context : NULL; +} + +EGLDisplay +gst_vaapi_display_egl_get_gl_display (GstVaapiDisplayEGL * display) +{ + g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_EGL (display), EGL_NO_DISPLAY); + + return display->egl_display->base.handle.p; +} + +EGLContext +gst_vaapi_display_egl_get_gl_context (GstVaapiDisplayEGL * display) +{ + g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_EGL (display), EGL_NO_CONTEXT); + + return ensure_context (display) ? display->egl_context->base.handle.p : + EGL_NO_CONTEXT; +} + +gboolean +gst_vaapi_display_egl_set_gl_context (GstVaapiDisplayEGL * display, + EGLContext gl_context) +{ + g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_EGL (display), FALSE); + + return ensure_context_is_wrapped (display, gl_context); +} + +gboolean +gst_vaapi_display_egl_set_current_display (GstVaapiDisplayEGL * display) +{ + EglDisplay *egl_display; + + g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_EGL (display), FALSE); + + if (G_UNLIKELY (eglGetCurrentDisplay () == EGL_NO_DISPLAY)) + return TRUE; + if (G_LIKELY (display->egl_display->base.handle.p == eglGetCurrentDisplay ())) + return TRUE; + + egl_display = egl_display_new_wrapped (eglGetCurrentDisplay ()); + if (!egl_display) + return FALSE; + egl_object_replace (&display->egl_display, egl_display); + egl_object_unref (egl_display); + if (!gst_vaapi_display_egl_set_gl_context (display, eglGetCurrentContext ())) + return FALSE; + + return TRUE; +} diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_egl.h b/gst-libs/gst/vaapi/gstvaapidisplay_egl.h new file mode 100644 index 0000000000..07fbf83ff1 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_egl.h @@ -0,0 +1,64 @@ +/* + * gstvaapidisplay_egl.h - VA/EGL display abstraction + * + * Copyright (C) 2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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) egl later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT EGL WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DISPLAY_EGL_H +#define GST_VAAPI_DISPLAY_EGL_H + +#include +#include + +G_BEGIN_DECLS + +typedef struct _GstVaapiDisplayEGL GstVaapiDisplayEGL; + +#define GST_TYPE_VAAPI_DISPLAY_EGL (gst_vaapi_display_egl_get_type ()) +#define GST_VAAPI_DISPLAY_EGL(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DISPLAY_EGL, GstVaapiDisplayEGL)) + +GstVaapiDisplay * +gst_vaapi_display_egl_new (GstVaapiDisplay * display, guint gles_version); + +GstVaapiDisplay * +gst_vaapi_display_egl_new_with_native_display (gpointer native_display, + GstVaapiDisplayType display_type, guint gles_version); + +EGLDisplay +gst_vaapi_display_egl_get_gl_display (GstVaapiDisplayEGL * display); + +EGLContext +gst_vaapi_display_egl_get_gl_context (GstVaapiDisplayEGL * display); + +gboolean +gst_vaapi_display_egl_set_gl_context (GstVaapiDisplayEGL * display, + EGLContext gl_context); + +gboolean +gst_vaapi_display_egl_set_current_display (GstVaapiDisplayEGL * display); + +GType +gst_vaapi_display_egl_get_type (void) G_GNUC_CONST; + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDisplayEGL, gst_object_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_DISPLAY_EGL_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_egl_priv.h b/gst-libs/gst/vaapi/gstvaapidisplay_egl_priv.h new file mode 100644 index 0000000000..e99c54bdc1 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_egl_priv.h @@ -0,0 +1,105 @@ +/* + * gstvaapidisplay_egl_priv.h - Internal VA/EGL interface + * + * Copyright (C) 2014 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DISPLAY_EGL_PRIV_H +#define GST_VAAPI_DISPLAY_EGL_PRIV_H + +#include +#include +#include "gstvaapidisplay_egl.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapiutils_egl.h" + +G_BEGIN_DECLS + +#define GST_VAAPI_IS_DISPLAY_EGL(display) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((display), GST_TYPE_VAAPI_DISPLAY_EGL)) + +#define GST_VAAPI_DISPLAY_EGL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPI_DISPLAY_EGL, GstVaapiDisplayEGLClass)) + +#define GST_VAAPI_DISPLAY_EGL_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_DISPLAY_EGL, GstVaapiDisplayEGLClass)) + +#define GST_VAAPI_DISPLAY_EGL_CAST(obj) \ + ((GstVaapiDisplayEGL *)(obj)) + +/** + * GST_VAAPI_DISPLAY_EGL_DISPLAY: + * @display: a #GstVaapiDisplay + * + * Macro that evaluates to #EglDisplay wrapper for @display. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_DISPLAY_EGL_DISPLAY +#define GST_VAAPI_DISPLAY_EGL_DISPLAY(display) \ + (GST_VAAPI_DISPLAY_EGL_CAST (display)->egl_display) + +/** + * GST_VAAPI_DISPLAY_EGL_CONTEXT: + * @display: a #GstVaapiDisplay + * + * Macro that evaluates to #EglContext wrapper for @display. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_DISPLAY_EGL_CONTEXT +#define GST_VAAPI_DISPLAY_EGL_CONTEXT(display) \ + gst_vaapi_display_egl_get_context (GST_VAAPI_DISPLAY_EGL (display)) + +typedef struct _GstVaapiDisplayEGLClass GstVaapiDisplayEGLClass; + +/** + * GstVaapiDisplayEGL: + * + * VA/EGL display wrapper. + */ +struct _GstVaapiDisplayEGL +{ + /*< private >*/ + GstVaapiDisplay parent_instance; + + gpointer loader; + GstVaapiDisplay *display; + EglDisplay *egl_display; + EglContext *egl_context; + guint gles_version; + GstVaapiTextureMap *texture_map; +}; + +/** + * GstVaapiDisplayEGLClass: + * + * VA/EGL display wrapper clas. + */ +struct _GstVaapiDisplayEGLClass +{ + /*< private >*/ + GstVaapiDisplayClass parent_class; +}; + +G_GNUC_INTERNAL +EglContext * +gst_vaapi_display_egl_get_context (GstVaapiDisplayEGL * display); + +G_END_DECLS + +#endif /* GST_VAAPI_DISPLAY_EGL_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_glx.c b/gst-libs/gst/vaapi/gstvaapidisplay_glx.c new file mode 100644 index 0000000000..f75ab90f84 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_glx.c @@ -0,0 +1,159 @@ +/* + * gstvaapidisplay_glx.c - VA/GLX display abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapidisplay_glx + * @short_description: VA/GLX display abstraction + */ + +#include "sysdeps.h" +#include "gstvaapicompat.h" +#include "gstvaapiutils.h" +#include "gstvaapiutils_glx.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapidisplay_x11_priv.h" +#include "gstvaapidisplay_glx.h" +#include "gstvaapidisplay_glx_priv.h" +#include "gstvaapiwindow_glx.h" +#include "gstvaapitexture_glx.h" + +#define DEBUG_VAAPI_DISPLAY 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE (GstVaapiDisplayGLX, gst_vaapi_display_glx, + GST_TYPE_VAAPI_DISPLAY_X11); + +static GstVaapiWindow * +gst_vaapi_display_glx_create_window (GstVaapiDisplay * display, GstVaapiID id, + guint width, guint height) +{ + return id != GST_VAAPI_ID_INVALID ? + gst_vaapi_window_glx_new_with_xid (display, id) : + gst_vaapi_window_glx_new (display, width, height); +} + +static void +ensure_texture_map (GstVaapiDisplayGLX * display) +{ + if (!display->texture_map) + display->texture_map = gst_vaapi_texture_map_new (); +} + +static GstVaapiTexture * +gst_vaapi_display_glx_create_texture (GstVaapiDisplay * display, GstVaapiID id, + guint target, guint format, guint width, guint height) +{ + GstVaapiTexture *texture; + GstVaapiDisplayGLX *dpy = GST_VAAPI_DISPLAY_GLX (display); + + if (id == GST_VAAPI_ID_INVALID) + return gst_vaapi_texture_glx_new (display, target, format, width, height); + + ensure_texture_map (dpy); + if (!(texture = gst_vaapi_texture_map_lookup (dpy->texture_map, id))) { + if ((texture = + gst_vaapi_texture_glx_new_wrapped (display, id, target, format))) { + gst_vaapi_texture_map_add (dpy->texture_map, texture, id); + } + } + + return texture; +} + +static GstVaapiTextureMap * +gst_vaapi_display_glx_get_texture_map (GstVaapiDisplay * display) +{ + return GST_VAAPI_DISPLAY_GLX (display)->texture_map; +} + +static void +gst_vaapi_display_glx_finalize (GObject * object) +{ + GstVaapiDisplayGLX *dpy = GST_VAAPI_DISPLAY_GLX (object); + + if (dpy->texture_map) + gst_object_unref (dpy->texture_map); + G_OBJECT_CLASS (gst_vaapi_display_glx_parent_class)->finalize (object); +} + +static void +gst_vaapi_display_glx_init (GstVaapiDisplayGLX * display) +{ +} + +static void +gst_vaapi_display_glx_class_init (GstVaapiDisplayGLXClass * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstVaapiDisplayClass *const dpy_class = GST_VAAPI_DISPLAY_CLASS (klass); + + object_class->finalize = gst_vaapi_display_glx_finalize; + dpy_class->display_type = GST_VAAPI_DISPLAY_TYPE_GLX; + dpy_class->create_window = gst_vaapi_display_glx_create_window; + dpy_class->create_texture = gst_vaapi_display_glx_create_texture; + dpy_class->get_texture_map = gst_vaapi_display_glx_get_texture_map; +} + +/** + * gst_vaapi_display_glx_new: + * @display_name: the X11 display name + * + * Opens an X11 #Display using @display_name and returns a newly + * allocated #GstVaapiDisplay object. The X11 display will be cloed + * when the reference count of the object reaches zero. + * + * Return value: a newly allocated #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_display_glx_new (const gchar * display_name) +{ + GstVaapiDisplay *display; + + display = g_object_new (GST_TYPE_VAAPI_DISPLAY_GLX, NULL); + return gst_vaapi_display_config (display, + GST_VAAPI_DISPLAY_INIT_FROM_DISPLAY_NAME, (gpointer) display_name); +} + +/** + * gst_vaapi_display_glx_new_with_display: + * @x11_display: an X11 #Display + * + * Creates a #GstVaapiDisplay based on the X11 @x11_display + * display. The caller still owns the display and must call + * XCloseDisplay() when all #GstVaapiDisplay references are + * released. Doing so too early can yield undefined behaviour. + * + * Return value: a newly allocated #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_display_glx_new_with_display (Display * x11_display) +{ + GstVaapiDisplay *display; + + g_return_val_if_fail (x11_display != NULL, NULL); + + display = g_object_new (GST_TYPE_VAAPI_DISPLAY_GLX, NULL); + return gst_vaapi_display_config (display, + GST_VAAPI_DISPLAY_INIT_FROM_NATIVE_DISPLAY, x11_display); +} diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_glx.h b/gst-libs/gst/vaapi/gstvaapidisplay_glx.h new file mode 100644 index 0000000000..c4bdcc9ad6 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_glx.h @@ -0,0 +1,51 @@ +/* + * gstvaapidisplay_glx.h - VA/GLX display abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DISPLAY_GLX_H +#define GST_VAAPI_DISPLAY_GLX_H + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_DISPLAY_GLX (gst_vaapi_display_glx_get_type ()) +#define GST_VAAPI_DISPLAY_GLX(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DISPLAY_GLX, GstVaapiDisplayGLX)) + +typedef struct _GstVaapiDisplayGLX GstVaapiDisplayGLX; + +GstVaapiDisplay * +gst_vaapi_display_glx_new (const gchar * display_name); + +GstVaapiDisplay * +gst_vaapi_display_glx_new_with_display (Display * x11_display); + +GType +gst_vaapi_display_glx_get_type (void) G_GNUC_CONST; + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDisplayGLX, gst_object_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_DISPLAY_GLX_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_glx_priv.h b/gst-libs/gst/vaapi/gstvaapidisplay_glx_priv.h new file mode 100644 index 0000000000..a715175c04 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_glx_priv.h @@ -0,0 +1,72 @@ +/* + * gstvaapidisplay_glx_priv.h - Internal VA/GLX interface + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DISPLAY_GLX_PRIV_H +#define GST_VAAPI_DISPLAY_GLX_PRIV_H + +#include +#include +#include +#include "gstvaapidisplay_x11_priv.h" + +G_BEGIN_DECLS + +#define GST_VAAPI_IS_DISPLAY_GLX(display) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((display), GST_TYPE_VAAPI_DISPLAY_GLX)) + +#define GST_VAAPI_DISPLAY_GLX_CAST(display) \ + ((GstVaapiDisplayGLX *)(display)) + +#define GST_VAAPI_DISPLAY_GLX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPI_DISPLAY_GLX, GstVaapiDisplayGLXClass)) + +#define GST_VAAPI_DISPLAY_GLX_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_DISPLAY_GLX, GstVaapiDisplayGLXClass)) + +typedef struct _GstVaapiDisplayGLXClass GstVaapiDisplayGLXClass; + +/** + * GstVaapiDisplayGLX: + * + * VA/GLX display wrapper. + */ +struct _GstVaapiDisplayGLX +{ + /*< private >*/ + GstVaapiDisplayX11 parent_instance; + GstVaapiTextureMap *texture_map; +}; + +/** + * GstVaapiDisplayGLXClass: + * + * VA/GLX display wrapper clas. + */ +struct _GstVaapiDisplayGLXClass +{ + /*< private >*/ + GstVaapiDisplayX11Class parent_class; +}; + +G_END_DECLS + +#endif /* GST_VAAPI_DISPLAY_GLX_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_priv.h b/gst-libs/gst/vaapi/gstvaapidisplay_priv.h new file mode 100644 index 0000000000..b8cb2bdc3c --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_priv.h @@ -0,0 +1,211 @@ +/* + * gstvaapidisplay_priv.h - Base VA display (private definitions) + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DISPLAY_PRIV_H +#define GST_VAAPI_DISPLAY_PRIV_H + +#include +#include +#include +#include +#include "gstvaapiminiobject.h" + +G_BEGIN_DECLS + +#define GST_VAAPI_DISPLAY_CAST(display) \ + ((GstVaapiDisplay *)(display)) + +#define GST_VAAPI_DISPLAY_GET_PRIVATE(display) \ + (GST_VAAPI_DISPLAY_CAST (display)->priv) + +#define GST_VAAPI_DISPLAY_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPI_DISPLAY, GstVaapiDisplayClass)) + +#define GST_VAAPI_IS_DISPLAY_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPI_DISPLAY)) + +#define GST_VAAPI_DISPLAY_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_DISPLAY, GstVaapiDisplayClass)) + +typedef struct _GstVaapiDisplayPrivate GstVaapiDisplayPrivate; +typedef struct _GstVaapiDisplayClass GstVaapiDisplayClass; +typedef enum _GstVaapiDisplayInitType GstVaapiDisplayInitType; + +/** + * GST_VAAPI_DISPLAY_GET_CLASS_TYPE: + * @display: a #GstVaapiDisplay + * + * Returns the #display class type + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_DISPLAY_GET_CLASS_TYPE +#define GST_VAAPI_DISPLAY_GET_CLASS_TYPE(display) \ + (GST_VAAPI_DISPLAY_GET_CLASS (display)->display_type) + +/** + * GST_VAAPI_DISPLAY_NATIVE: + * @display: a #GstVaapiDisplay + * + * Macro that evaluates to the native display of @display. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_DISPLAY_NATIVE +#define GST_VAAPI_DISPLAY_NATIVE(display) \ + (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->native_display) + +/** + * GST_VAAPI_DISPLAY_VADISPLAY: + * @display_: a #GstVaapiDisplay + * + * Macro that evaluates to the #VADisplay of @display_. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_DISPLAY_VADISPLAY +#define GST_VAAPI_DISPLAY_VADISPLAY(display_) \ + (GST_VAAPI_DISPLAY_GET_PRIVATE (display_)->display) + +/** + * GST_VAAPI_DISPLAY_VADISPLAY_TYPE: + * @display: a #GstVaapiDisplay + * + * Returns the underlying VADisplay @display type + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_DISPLAY_VADISPLAY_TYPE +#define GST_VAAPI_DISPLAY_VADISPLAY_TYPE(display) \ + (GST_VAAPI_DISPLAY_GET_CLASS (display)->display_type) + +/** + * GST_VAAPI_DISPLAY_HAS_VPP: + * @display: a @GstVaapiDisplay + * + * Returns whether the @display supports video processing (VA/VPP) + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_DISPLAY_HAS_VPP +#define GST_VAAPI_DISPLAY_HAS_VPP(display) \ + gst_vaapi_display_has_video_processing (GST_VAAPI_DISPLAY_CAST (display)) + +struct _GstVaapiDisplayPrivate +{ + GstVaapiDisplay *parent; + GRecMutex mutex; + gchar *display_name; + VADisplay display; + gpointer native_display; + guint width; + guint height; + guint width_mm; + guint height_mm; + guint par_n; + guint par_d; + GPtrArray *decoders; /* ref element in codecs */ + GPtrArray *encoders; /* ref element in codecs */ + GArray *codecs; + GArray *image_formats; + GArray *subpicture_formats; + GArray *properties; + gchar *vendor_string; + guint use_foreign_display:1; + guint has_vpp:1; + guint has_profiles:1; + guint got_scrres:1; + guint driver_quirks; +}; + +/** + * GstVaapiDisplay: + * + * Base class for VA displays. + */ +struct _GstVaapiDisplay +{ + /*< private >*/ + GstObject parent_instance; + + GstVaapiDisplayPrivate *priv; +}; + +/** + * GstVaapiDisplayClass: + * @open_display: virtual function to open a display + * @close_display: virtual function to close a display + * @lock: (optional) virtual function to lock a display + * @unlock: (optional) virtual function to unlock a display + * @sync: (optional) virtual function to sync a display + * @flush: (optional) virtual function to flush pending requests of a display + * @get_display: virtual function to retrieve the #GstVaapiDisplayInfo + * @get_size: virtual function to retrieve the display dimensions, in pixels + * @get_size_mm: virtual function to retrieve the display dimensions, in millimeters + * @get_visual_id: (optional) virtual function to retrieve the window visual id + * @get_colormap: (optional) virtual function to retrieve the window colormap + * @create_window: (optional) virtual function to create a window + * @create_texture: (optional) virtual function to create a texture + * @get_texture_map: (optional) virtual function to get texture map + * + * Base class for VA displays. + */ +struct _GstVaapiDisplayClass +{ + /*< private >*/ + GstObjectClass parent_class; + + /*< protected >*/ + guint display_type; + + /*< public >*/ + void (*init) (GstVaapiDisplay * display); + gboolean (*bind_display) (GstVaapiDisplay * display, gpointer native_dpy); + gboolean (*open_display) (GstVaapiDisplay * display, const gchar * name); + void (*close_display) (GstVaapiDisplay * display); + void (*lock) (GstVaapiDisplay * display); + void (*unlock) (GstVaapiDisplay * display); + void (*sync) (GstVaapiDisplay * display); + void (*flush) (GstVaapiDisplay * display); + gboolean (*get_display) (GstVaapiDisplay * display, GstVaapiDisplayInfo * info); + void (*get_size) (GstVaapiDisplay * display, guint * pwidth, guint * pheight); + void (*get_size_mm) (GstVaapiDisplay * display, guint * pwidth, guint * pheight); + guintptr (*get_visual_id) (GstVaapiDisplay * display, GstVaapiWindow * window); + guintptr (*get_colormap) (GstVaapiDisplay * display, GstVaapiWindow * window); + GstVaapiWindow *(*create_window) (GstVaapiDisplay * display, GstVaapiID id, guint width, guint height); + GstVaapiTexture *(*create_texture) (GstVaapiDisplay * display, GstVaapiID id, guint target, guint format, + guint width, guint height); + GstVaapiTextureMap *(*get_texture_map) (GstVaapiDisplay * display); +}; + +/* Initialization types */ +enum _GstVaapiDisplayInitType +{ + GST_VAAPI_DISPLAY_INIT_FROM_DISPLAY_NAME = 1, + GST_VAAPI_DISPLAY_INIT_FROM_NATIVE_DISPLAY, + GST_VAAPI_DISPLAY_INIT_FROM_VA_DISPLAY +}; + +GstVaapiDisplay * +gst_vaapi_display_config (GstVaapiDisplay * display, + GstVaapiDisplayInitType init_type, gpointer init_value); + +G_END_DECLS + +#endif /* GST_VAAPI_DISPLAY_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_wayland.c b/gst-libs/gst/vaapi/gstvaapidisplay_wayland.c new file mode 100644 index 0000000000..e6e3f39460 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_wayland.c @@ -0,0 +1,457 @@ +/* + * gstvaapidisplay_wayland.c - VA/Wayland display abstraction + * + * Copyright (C) 2012-2013 Intel Corporation + * Author: Sreerenj Balachandran + * Author: Gwenole Beauchesne + * + * 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:gstvaapidisplay_wayland + * @short_description: VA/Wayland display abstraction + */ + +#include "sysdeps.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapidisplay_wayland.h" +#include "gstvaapidisplay_wayland_priv.h" +#include "gstvaapiwindow_wayland.h" + +#define DEBUG_VAAPI_DISPLAY 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE_WITH_PRIVATE (GstVaapiDisplayWayland, gst_vaapi_display_wayland, + GST_TYPE_VAAPI_DISPLAY); + +static inline const gchar * +get_default_display_name (void) +{ + static const gchar *g_display_name; + + if (!g_display_name) + g_display_name = getenv ("WAYLAND_DISPLAY"); + return g_display_name; +} + +/* Mangle display name with our prefix */ +static gboolean +set_display_name (GstVaapiDisplay * display, const gchar * display_name) +{ + GstVaapiDisplayWaylandPrivate *const priv = + GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (display); + + g_free (priv->display_name); + + if (!display_name) { + display_name = get_default_display_name (); + if (!display_name) + display_name = ""; + } + priv->display_name = g_strdup (display_name); + return priv->display_name != NULL; +} + +static void +output_handle_geometry (void *data, struct wl_output *output, + int x, int y, int physical_width, int physical_height, + int subpixel, const char *make, const char *model, int transform) +{ + GstVaapiDisplayWaylandPrivate *const priv = data; + + priv->phys_width = physical_width; + priv->phys_height = physical_height; +} + +static void +output_handle_mode (void *data, struct wl_output *wl_output, + uint32_t flags, int width, int height, int refresh) +{ + GstVaapiDisplayWaylandPrivate *const priv = data; + + if (flags & WL_OUTPUT_MODE_CURRENT) { + priv->width = width; + priv->height = height; + } +} + +static const struct wl_output_listener output_listener = { + output_handle_geometry, + output_handle_mode, +}; + +static void +handle_xdg_wm_base_ping (void *user_data, struct xdg_wm_base *xdg_wm_base, + uint32_t serial) +{ + xdg_wm_base_pong (xdg_wm_base, serial); +} + +static const struct xdg_wm_base_listener xdg_wm_base_listener = { + handle_xdg_wm_base_ping +}; + +static void +dmabuf_format (void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf, + uint32_t format) +{ +} + +static void +dmabuf_modifier (void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf, + uint32_t format, uint32_t modifier_hi, uint32_t modifier_lo) +{ + GstVaapiDisplayWaylandPrivate *const priv = data; + GstDRMFormat drm_format = { + .format = format, + .modifier = (guint64) modifier_hi << 32 | modifier_lo + }; + + if (gst_vaapi_video_format_from_drm_format (format) == + GST_VIDEO_FORMAT_UNKNOWN) { + GST_LOG ("ignoring unknown format 0x%x with modifier 0x%" G_GINT64_MODIFIER + "x", format, drm_format.modifier); + return; + } + + GST_LOG ("got format 0x%x (%s) with modifier 0x%" G_GINT64_MODIFIER "x", + format, gst_video_format_to_string (gst_vaapi_video_format_from_drm_format + (format)), drm_format.modifier); + + g_array_append_val (priv->dmabuf_formats, drm_format); +} + +static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = { + dmabuf_format, + dmabuf_modifier, +}; + + +static void +registry_handle_global (void *data, + struct wl_registry *registry, + uint32_t id, const char *interface, uint32_t version) +{ + GstVaapiDisplayWaylandPrivate *const priv = data; + + if (strcmp (interface, "wl_compositor") == 0) + priv->compositor = + wl_registry_bind (registry, id, &wl_compositor_interface, 1); + else if (strcmp (interface, "wl_subcompositor") == 0) + priv->subcompositor = + wl_registry_bind (registry, id, &wl_subcompositor_interface, 1); + else if (strcmp (interface, "wl_shell") == 0) + priv->wl_shell = wl_registry_bind (registry, id, &wl_shell_interface, 1); + else if (strcmp (interface, "xdg_wm_base") == 0) { + priv->xdg_wm_base = + wl_registry_bind (registry, id, &xdg_wm_base_interface, 1); + xdg_wm_base_add_listener (priv->xdg_wm_base, &xdg_wm_base_listener, priv); + } else if (strcmp (interface, "wl_output") == 0) { + if (!priv->output) { + priv->output = wl_registry_bind (registry, id, &wl_output_interface, 1); + wl_output_add_listener (priv->output, &output_listener, priv); + } + } else if (strcmp (interface, "zwp_linux_dmabuf_v1") == 0) { + priv->dmabuf = + wl_registry_bind (registry, id, &zwp_linux_dmabuf_v1_interface, 3); + zwp_linux_dmabuf_v1_add_listener (priv->dmabuf, &dmabuf_listener, priv); + } +} + +static const struct wl_registry_listener registry_listener = { + registry_handle_global, + NULL, +}; + +static gboolean +gst_vaapi_display_wayland_setup (GstVaapiDisplay * display) +{ + GstVaapiDisplayWaylandPrivate *const priv = + GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (display); + + wl_display_set_user_data (priv->wl_display, priv); + priv->registry = wl_display_get_registry (priv->wl_display); + wl_registry_add_listener (priv->registry, ®istry_listener, priv); + priv->event_fd = wl_display_get_fd (priv->wl_display); + wl_display_roundtrip (priv->wl_display); + + if (!priv->width || !priv->height) { + wl_display_roundtrip (priv->wl_display); + if (!priv->width || !priv->height) { + GST_ERROR ("failed to determine the display size"); + return FALSE; + } + } + + if (!priv->compositor) { + GST_ERROR ("failed to bind compositor interface"); + return FALSE; + } + + if (priv->xdg_wm_base) + return TRUE; + + if (!priv->wl_shell) { + GST_ERROR ("failed to bind wl_shell interface"); + return FALSE; + } + + return TRUE; +} + +static gboolean +gst_vaapi_display_wayland_bind_display (GstVaapiDisplay * display, + gpointer native_display) +{ + GstVaapiDisplayWaylandPrivate *const priv = + GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (display); + + priv->wl_display = native_display; + priv->use_foreign_display = TRUE; + + /* XXX: how to get socket/display name? */ + GST_WARNING ("wayland: get display name"); + set_display_name (display, NULL); + + return gst_vaapi_display_wayland_setup (display); +} + +static gboolean +gst_vaapi_display_wayland_open_display (GstVaapiDisplay * display, + const gchar * name) +{ + GstVaapiDisplayWaylandPrivate *const priv = + GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (display); + + if (!set_display_name (display, name)) + return FALSE; + + priv->wl_display = wl_display_connect (name); + if (!priv->wl_display) + return FALSE; + priv->use_foreign_display = FALSE; + + return gst_vaapi_display_wayland_setup (display); +} + +static void +gst_vaapi_display_wayland_close_display (GstVaapiDisplay * display) +{ + GstVaapiDisplayWaylandPrivate *const priv = + GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (display); + + g_clear_pointer (&priv->output, wl_output_destroy); + g_clear_pointer (&priv->wl_shell, wl_shell_destroy); + g_clear_pointer (&priv->xdg_wm_base, xdg_wm_base_destroy); + g_clear_pointer (&priv->subcompositor, wl_subcompositor_destroy); + g_clear_pointer (&priv->compositor, wl_compositor_destroy); + g_clear_pointer (&priv->registry, wl_registry_destroy); + + g_array_unref (priv->dmabuf_formats); + + if (priv->wl_display) { + if (!priv->use_foreign_display) + wl_display_disconnect (priv->wl_display); + priv->wl_display = NULL; + } + + g_clear_pointer (&priv->display_name, g_free); +} + +static gboolean +gst_vaapi_display_wayland_get_display_info (GstVaapiDisplay * display, + GstVaapiDisplayInfo * info) +{ + GstVaapiDisplayWaylandPrivate *const priv = + GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (display); + + info->native_display = priv->wl_display; + info->display_name = priv->display_name; + if (!info->va_display) { + info->va_display = vaGetDisplayWl (priv->wl_display); + if (!info->va_display) + return FALSE; + } + return TRUE; +} + +static void +gst_vaapi_display_wayland_get_size (GstVaapiDisplay * display, + guint * pwidth, guint * pheight) +{ + GstVaapiDisplayWaylandPrivate *const priv = + GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (display); + + if (!priv->output) + return; + + if (pwidth) + *pwidth = priv->width; + + if (pheight) + *pheight = priv->height; +} + +static void +gst_vaapi_display_wayland_get_size_mm (GstVaapiDisplay * display, + guint * pwidth, guint * pheight) +{ + GstVaapiDisplayWaylandPrivate *const priv = + GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (display); + + if (!priv->output) + return; + + if (pwidth) + *pwidth = priv->phys_width; + + if (pheight) + *pheight = priv->phys_height; +} + +static GstVaapiWindow * +gst_vaapi_display_wayland_create_window (GstVaapiDisplay * display, + GstVaapiID id, guint width, guint height) +{ + if (id != GST_VAAPI_ID_INVALID) + return NULL; + return gst_vaapi_window_wayland_new (display, width, height); +} + +static void +gst_vaapi_display_wayland_init (GstVaapiDisplayWayland * display) +{ + GstVaapiDisplayWaylandPrivate *const priv = + gst_vaapi_display_wayland_get_instance_private (display); + + display->priv = priv; + priv->event_fd = -1; + priv->dmabuf_formats = g_array_new (FALSE, FALSE, sizeof (GstDRMFormat)); +} + +static void +gst_vaapi_display_wayland_class_init (GstVaapiDisplayWaylandClass * klass) +{ + GstVaapiDisplayClass *const dpy_class = GST_VAAPI_DISPLAY_CLASS (klass); + + dpy_class->display_type = GST_VAAPI_DISPLAY_TYPE_WAYLAND; + + dpy_class->bind_display = gst_vaapi_display_wayland_bind_display; + dpy_class->open_display = gst_vaapi_display_wayland_open_display; + dpy_class->close_display = gst_vaapi_display_wayland_close_display; + dpy_class->get_display = gst_vaapi_display_wayland_get_display_info; + dpy_class->get_size = gst_vaapi_display_wayland_get_size; + dpy_class->get_size_mm = gst_vaapi_display_wayland_get_size_mm; + dpy_class->create_window = gst_vaapi_display_wayland_create_window; +} + +/** + * gst_vaapi_display_wayland_new: + * @display_name: the Wayland display name + * + * Opens an Wayland #wl_display using @display_name and returns a + * newly allocated #GstVaapiDisplay object. The Wayland display will + * be cloed when the reference count of the object reaches zero. + * + * Return value: a newly allocated #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_display_wayland_new (const gchar * display_name) +{ + GstVaapiDisplay *display; + + display = g_object_new (GST_TYPE_VAAPI_DISPLAY_WAYLAND, NULL); + return gst_vaapi_display_config (display, + GST_VAAPI_DISPLAY_INIT_FROM_DISPLAY_NAME, (gpointer) display_name); +} + +/** + * gst_vaapi_display_wayland_new_with_display: + * @wl_display: an Wayland #wl_display + * + * Creates a #GstVaapiDisplay based on the Wayland @wl_display + * display. The caller still owns the display and must call + * wl_display_disconnect() when all #GstVaapiDisplay references are + * released. Doing so too early can yield undefined behaviour. + * + * Return value: a newly allocated #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_display_wayland_new_with_display (struct wl_display * wl_display) +{ + GstVaapiDisplay *display; + + g_return_val_if_fail (wl_display, NULL); + + display = g_object_new (GST_TYPE_VAAPI_DISPLAY_WAYLAND, NULL); + return gst_vaapi_display_config (display, + GST_VAAPI_DISPLAY_INIT_FROM_NATIVE_DISPLAY, wl_display); +} + +/** + * gst_vaapi_display_wayland_new_with_va_display: + * @va_display: a VADisplay #va_display + * @wl_display: an Wayland #wl_display + * + * Creates a #GstVaapiDisplay based on the VADisplay @va_display and + * the Wayland @wl_display display. + * The caller still owns the display and must call + * wl_display_disconnect() when all #GstVaapiDisplay references are + * released. + * + * Return value: a newly allocated #GstVaapiDisplay object + */ + +GstVaapiDisplay * +gst_vaapi_display_wayland_new_with_va_display (VADisplay va_display, + struct wl_display * wl_display) +{ + GstVaapiDisplay *display; + GstVaapiDisplayInfo info = { + .va_display = va_display, + .native_display = wl_display, + }; + + g_return_val_if_fail (wl_display, NULL); + + display = g_object_new (GST_TYPE_VAAPI_DISPLAY_WAYLAND, NULL); + if (!gst_vaapi_display_config (display, + GST_VAAPI_DISPLAY_INIT_FROM_VA_DISPLAY, &info)) { + gst_object_unref (display); + return NULL; + } + + return display; +} + +/** + * gst_vaapi_display_wayland_get_display: + * @display: a #GstVaapiDisplayWayland + * + * Returns the underlying Wayland #wl_display that was created by + * gst_vaapi_display_wayland_new() or that was bound from + * gst_vaapi_display_wayland_new_with_display(). + * + * Return value: the Wayland #wl_display attached to @display + */ +struct wl_display * +gst_vaapi_display_wayland_get_display (GstVaapiDisplayWayland * display) +{ + g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_WAYLAND (display), NULL); + + return GST_VAAPI_DISPLAY_WL_DISPLAY (display); +} diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_wayland.h b/gst-libs/gst/vaapi/gstvaapidisplay_wayland.h new file mode 100644 index 0000000000..1f9ec30a28 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_wayland.h @@ -0,0 +1,58 @@ +/* + * gstvaapidisplay_wayland.h - VA/Wayland display abstraction + * + * Copyright (C) 2012-2013 Intel Corporation + * Author: Sreerenj Balachandran + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DISPLAY_WAYLAND_H +#define GST_VAAPI_DISPLAY_WAYLAND_H + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_DISPLAY_WAYLAND (gst_vaapi_display_wayland_get_type ()) +#define GST_VAAPI_DISPLAY_WAYLAND(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DISPLAY_WAYLAND, GstVaapiDisplayWayland)) + +typedef struct _GstVaapiDisplayWayland GstVaapiDisplayWayland; + +GstVaapiDisplay * +gst_vaapi_display_wayland_new (const gchar * display_name); + +GstVaapiDisplay * +gst_vaapi_display_wayland_new_with_display (struct wl_display * wl_display); + +GstVaapiDisplay * +gst_vaapi_display_wayland_new_with_va_display (VADisplay va_display, + struct wl_display * wl_display); + +struct wl_display * +gst_vaapi_display_wayland_get_display (GstVaapiDisplayWayland * display); + +GType +gst_vaapi_display_wayland_get_type (void) G_GNUC_CONST; + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDisplayWayland, gst_object_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_DISPLAY_WAYLAND_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_wayland_priv.h b/gst-libs/gst/vaapi/gstvaapidisplay_wayland_priv.h new file mode 100644 index 0000000000..a4e9992ed4 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_wayland_priv.h @@ -0,0 +1,114 @@ +/* + * gstvaapidisplay_wayland_priv.h - Internal VA/Wayland interface + * + * Copyright (C) 2012-2013 Intel Corporation + * Author: Sreerenj Balachandran + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DISPLAY_WAYLAND_PRIV_H +#define GST_VAAPI_DISPLAY_WAYLAND_PRIV_H + +#include "xdg-shell-client-protocol.h" +#include "linux-dmabuf-unstable-v1-client-protocol.h" + +#include +#include "gstvaapidisplay_priv.h" + +G_BEGIN_DECLS + +#define GST_VAAPI_IS_DISPLAY_WAYLAND(display) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((display), GST_TYPE_VAAPI_DISPLAY_WAYLAND)) + +#define GST_VAAPI_DISPLAY_WAYLAND_CAST(display) \ + ((GstVaapiDisplayWayland *)(display)) + +#define GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE(display) \ + (GST_VAAPI_DISPLAY_WAYLAND_CAST(display)->priv) + +#define GST_VAAPI_DISPLAY_WAYLAND_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_DISPLAY_WAYLAND, GstVaapiDisplayWaylandClass)) + +typedef struct _GstVaapiDisplayWaylandPrivate GstVaapiDisplayWaylandPrivate; +typedef struct _GstVaapiDisplayWaylandClass GstVaapiDisplayWaylandClass; + +/** + * GST_VAAPI_DISPLAY_WL_DISPLAY: + * @display: a #GstVaapiDisplay + * + * Macro that evaluates to the underlying Wayland #wl_display object + * of @display + */ +#undef GST_VAAPI_DISPLAY_WL_DISPLAY +#define GST_VAAPI_DISPLAY_WL_DISPLAY(display) \ + GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE(display)->wl_display + +typedef struct _GstDRMFormat GstDRMFormat; + +struct _GstDRMFormat { + guint format; + guint64 modifier; +}; + +struct _GstVaapiDisplayWaylandPrivate +{ + gchar *display_name; + struct wl_display *wl_display; + struct wl_compositor *compositor; + struct wl_shell *wl_shell; + struct xdg_wm_base *xdg_wm_base; + struct wl_subcompositor *subcompositor; + struct wl_output *output; + struct zwp_linux_dmabuf_v1 *dmabuf; + struct wl_registry *registry; + GArray *dmabuf_formats; + guint width; + guint height; + guint phys_width; + guint phys_height; + gint event_fd; + guint use_foreign_display:1; +}; + +/** + * GstVaapiDisplayWayland: + * + * VA/Wayland display wrapper. + */ +struct _GstVaapiDisplayWayland +{ + /*< private >*/ + GstVaapiDisplay parent_instance; + + GstVaapiDisplayWaylandPrivate *priv; +}; + +/** + * GstVaapiDisplayWaylandClass: + * + * VA/Wayland display wrapper clas. + */ +struct _GstVaapiDisplayWaylandClass +{ + /*< private >*/ + GstVaapiDisplayClass parent_class; +}; + +G_END_DECLS + +#endif /* GST_VAAPI_DISPLAY_WAYLAND_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_x11.c b/gst-libs/gst/vaapi/gstvaapidisplay_x11.c new file mode 100644 index 0000000000..1f2e1cc6d4 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_x11.c @@ -0,0 +1,545 @@ +/* + * gstvaapidisplay_x11.c - VA/X11 display abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapidisplay_x11 + * @short_description: VA/X11 display abstraction + */ + +#include "sysdeps.h" +#include "gstvaapiutils.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapidisplay_x11.h" +#include "gstvaapidisplay_x11_priv.h" +#include "gstvaapiwindow_x11.h" + +#if HAVE_XRANDR +# include +#endif + +#define DEBUG_VAAPI_DISPLAY 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE_WITH_PRIVATE (GstVaapiDisplayX11, gst_vaapi_display_x11, + GST_TYPE_VAAPI_DISPLAY); + +static inline const gchar * +get_default_display_name (void) +{ + static const gchar *g_display_name; + + if (!g_display_name) + g_display_name = getenv ("DISPLAY"); + return g_display_name; +} + +/* Reconstruct a display name without our prefix */ +static const gchar * +get_display_name (GstVaapiDisplayX11 * display) +{ + GstVaapiDisplayX11Private *const priv = display->priv; + const gchar *display_name = priv->display_name; + + if (!display_name || *display_name == '\0') + return NULL; + return display_name; +} + +/* Mangle display name with our prefix */ +static gboolean +set_display_name (GstVaapiDisplayX11 * display, const gchar * display_name) +{ + GstVaapiDisplayX11Private *const priv = display->priv; + + g_free (priv->display_name); + + if (!display_name) { + display_name = get_default_display_name (); + if (!display_name) + display_name = ""; + } + priv->display_name = g_strdup (display_name); + return priv->display_name != NULL; +} + +/* Set synchronous behavious on the underlying X11 display */ +static void +set_synchronous (GstVaapiDisplayX11 * display, gboolean synchronous) +{ + GstVaapiDisplayX11Private *const priv = display->priv; + + if (priv->synchronous != synchronous) { + priv->synchronous = synchronous; + if (priv->x11_display) { + GST_VAAPI_DISPLAY_LOCK (display); + XSynchronize (priv->x11_display, synchronous); + GST_VAAPI_DISPLAY_UNLOCK (display); + } + } +} + +/* Check for display server extensions */ +static void +check_extensions (GstVaapiDisplayX11 * display) +{ + GstVaapiDisplayX11Private *const priv = display->priv; + int evt_base, err_base; + +#if HAVE_XRANDR + priv->use_xrandr = XRRQueryExtension (priv->x11_display, + &evt_base, &err_base); +#endif +} + +static gboolean +gst_vaapi_display_x11_bind_display (GstVaapiDisplay * base_display, + gpointer native_display) +{ + GstVaapiDisplayX11 *const display = GST_VAAPI_DISPLAY_X11_CAST (base_display); + GstVaapiDisplayX11Private *const priv = display->priv; + + priv->x11_display = native_display; + priv->x11_screen = DefaultScreen (native_display); + priv->use_foreign_display = TRUE; + + check_extensions (display); + if (!set_display_name (display, XDisplayString (priv->x11_display))) + return FALSE; + return TRUE; +} + +static gboolean +gst_vaapi_display_x11_open_display (GstVaapiDisplay * base_display, + const gchar * name) +{ + GstVaapiDisplayX11 *const display = GST_VAAPI_DISPLAY_X11_CAST (base_display); + GstVaapiDisplayX11Private *const priv = display->priv; + + if (!set_display_name (display, name)) + return FALSE; + + priv->x11_display = XOpenDisplay (get_display_name (display)); + if (!priv->x11_display) + return FALSE; + priv->use_foreign_display = FALSE; + + priv->x11_screen = DefaultScreen (priv->x11_display); + + check_extensions (display); + return TRUE; +} + +static void +gst_vaapi_display_x11_close_display (GstVaapiDisplay * display) +{ + GstVaapiDisplayX11Private *const priv = + GST_VAAPI_DISPLAY_X11_PRIVATE (display); + + g_clear_pointer (&priv->pixmap_formats, g_array_unref); + + if (priv->x11_display) { + if (!priv->use_foreign_display) + XCloseDisplay (priv->x11_display); + priv->x11_display = NULL; + } + + g_clear_pointer (&priv->display_name, g_free); +} + +static void +gst_vaapi_display_x11_sync (GstVaapiDisplay * display) +{ + GstVaapiDisplayX11Private *const priv = + GST_VAAPI_DISPLAY_X11_PRIVATE (display); + + if (priv->x11_display) { + GST_VAAPI_DISPLAY_LOCK (display); + XSync (priv->x11_display, False); + GST_VAAPI_DISPLAY_UNLOCK (display); + } +} + +static void +gst_vaapi_display_x11_flush (GstVaapiDisplay * display) +{ + GstVaapiDisplayX11Private *const priv = + GST_VAAPI_DISPLAY_X11_PRIVATE (display); + + if (priv->x11_display) { + GST_VAAPI_DISPLAY_LOCK (display); + XFlush (priv->x11_display); + GST_VAAPI_DISPLAY_UNLOCK (display); + } +} + +static gboolean +gst_vaapi_display_x11_get_display_info (GstVaapiDisplay * display, + GstVaapiDisplayInfo * info) +{ + GstVaapiDisplayX11Private *const priv = + GST_VAAPI_DISPLAY_X11_PRIVATE (display); + + info->native_display = priv->x11_display; + info->display_name = priv->display_name; + if (!info->va_display) { + info->va_display = vaGetDisplay (priv->x11_display); + if (!info->va_display) + return FALSE; + } + return TRUE; +} + +static void +gst_vaapi_display_x11_get_size (GstVaapiDisplay * display, + guint * pwidth, guint * pheight) +{ + GstVaapiDisplayX11Private *const priv = + GST_VAAPI_DISPLAY_X11_PRIVATE (display); + + if (!priv->x11_display) + return; + + if (pwidth) + *pwidth = DisplayWidth (priv->x11_display, priv->x11_screen); + + if (pheight) + *pheight = DisplayHeight (priv->x11_display, priv->x11_screen); +} + +static void +gst_vaapi_display_x11_get_size_mm (GstVaapiDisplay * display, + guint * pwidth, guint * pheight) +{ + GstVaapiDisplayX11Private *const priv = + GST_VAAPI_DISPLAY_X11_PRIVATE (display); + guint width_mm, height_mm; + + if (!priv->x11_display) + return; + + width_mm = DisplayWidthMM (priv->x11_display, priv->x11_screen); + height_mm = DisplayHeightMM (priv->x11_display, priv->x11_screen); + +#if HAVE_XRANDR + /* XXX: fix up physical size if the display is rotated */ + if (priv->use_xrandr) { + XRRScreenConfiguration *xrr_config = NULL; + XRRScreenSize *xrr_sizes; + Window win; + int num_xrr_sizes, size_id, screen; + Rotation rotation; + + do { + win = DefaultRootWindow (priv->x11_display); + screen = XRRRootToScreen (priv->x11_display, win); + + xrr_config = XRRGetScreenInfo (priv->x11_display, win); + if (!xrr_config) + break; + + size_id = XRRConfigCurrentConfiguration (xrr_config, &rotation); + if (rotation == RR_Rotate_0 || rotation == RR_Rotate_180) + break; + + xrr_sizes = XRRSizes (priv->x11_display, screen, &num_xrr_sizes); + if (!xrr_sizes || size_id >= num_xrr_sizes) + break; + + width_mm = xrr_sizes[size_id].mheight; + height_mm = xrr_sizes[size_id].mwidth; + } while (0); + if (xrr_config) + XRRFreeScreenConfigInfo (xrr_config); + } +#endif + + if (pwidth) + *pwidth = width_mm; + + if (pheight) + *pheight = height_mm; +} + +static GstVaapiWindow * +gst_vaapi_display_x11_create_window (GstVaapiDisplay * display, GstVaapiID id, + guint width, guint height) +{ + return id != GST_VAAPI_ID_INVALID ? + gst_vaapi_window_x11_new_with_xid (display, id) : + gst_vaapi_window_x11_new (display, width, height); +} + +void +gst_vaapi_display_x11_class_init (GstVaapiDisplayX11Class * klass) +{ + GstVaapiDisplayClass *const dpy_class = GST_VAAPI_DISPLAY_CLASS (klass); + + dpy_class->display_type = GST_VAAPI_DISPLAY_TYPE_X11; + dpy_class->bind_display = gst_vaapi_display_x11_bind_display; + dpy_class->open_display = gst_vaapi_display_x11_open_display; + dpy_class->close_display = gst_vaapi_display_x11_close_display; + dpy_class->sync = gst_vaapi_display_x11_sync; + dpy_class->flush = gst_vaapi_display_x11_flush; + dpy_class->get_display = gst_vaapi_display_x11_get_display_info; + dpy_class->get_size = gst_vaapi_display_x11_get_size; + dpy_class->get_size_mm = gst_vaapi_display_x11_get_size_mm; + dpy_class->create_window = gst_vaapi_display_x11_create_window; +} + +static void +gst_vaapi_display_x11_init (GstVaapiDisplayX11 * display) +{ + GstVaapiDisplayX11Private *const priv = + gst_vaapi_display_x11_get_instance_private (display); + + display->priv = priv; +} + +/** + * gst_vaapi_display_x11_new: + * @display_name: the X11 display name + * + * Opens an X11 #Display using @display_name and returns a newly + * allocated #GstVaapiDisplay object. The X11 display will be cloed + * when the reference count of the object reaches zero. + * + * Return value: a newly allocated #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_display_x11_new (const gchar * display_name) +{ + GstVaapiDisplay *display; + + display = g_object_new (GST_TYPE_VAAPI_DISPLAY_X11, NULL); + return gst_vaapi_display_config (display, + GST_VAAPI_DISPLAY_INIT_FROM_DISPLAY_NAME, (gpointer) display_name); +} + +/** + * gst_vaapi_display_x11_new_with_display: + * @x11_display: an X11 #Display + * + * Creates a #GstVaapiDisplay based on the X11 @x11_display + * display. The caller still owns the display and must call + * XCloseDisplay() when all #GstVaapiDisplay references are + * released. Doing so too early can yield undefined behaviour. + * + * Return value: a newly allocated #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_display_x11_new_with_display (Display * x11_display) +{ + GstVaapiDisplay *display; + + g_return_val_if_fail (x11_display, NULL); + + display = g_object_new (GST_TYPE_VAAPI_DISPLAY_X11, NULL); + return gst_vaapi_display_config (display, + GST_VAAPI_DISPLAY_INIT_FROM_NATIVE_DISPLAY, x11_display); +} + +GstVaapiDisplay * +gst_vaapi_display_x11_new_with_va_display (VADisplay va_display, + Display * x11_display) +{ + GstVaapiDisplay *display; + GstVaapiDisplayInfo info = { + .va_display = va_display, + .native_display = x11_display, + }; + + g_return_val_if_fail (x11_display, NULL); + + display = g_object_new (GST_TYPE_VAAPI_DISPLAY_X11, NULL); + return gst_vaapi_display_config (display, + GST_VAAPI_DISPLAY_INIT_FROM_VA_DISPLAY, &info); +} + +/** + * gst_vaapi_display_x11_get_display: + * @display: a #GstVaapiDisplayX11 + * + * Returns the underlying X11 #Display that was created by + * gst_vaapi_display_x11_new() or that was bound from + * gst_vaapi_display_x11_new_with_display(). + * + * Return value: the X11 #Display attached to @display + */ +Display * +gst_vaapi_display_x11_get_display (GstVaapiDisplayX11 * display) +{ + g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_X11 (display), NULL); + + return GST_VAAPI_DISPLAY_XDISPLAY (display); +} + +/** + * gst_vaapi_display_x11_get_screen: + * @display: a #GstVaapiDisplayX11 + * + * Returns the default X11 screen that was created by + * gst_vaapi_display_x11_new() or that was bound from + * gst_vaapi_display_x11_new_with_display(). + * + * Return value: the X11 #Display attached to @display + */ +int +gst_vaapi_display_x11_get_screen (GstVaapiDisplayX11 * display) +{ + g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_X11 (display), -1); + + return GST_VAAPI_DISPLAY_XSCREEN (display); +} + +/** + * gst_vaapi_display_x11_set_synchronous: + * @display: a #GstVaapiDisplayX11 + * @synchronous: boolean value that indicates whether to enable or + * disable synchronization + * + * If @synchronous is %TRUE, gst_vaapi_display_x11_set_synchronous() + * turns on synchronous behaviour on the underlying X11 + * display. Otherwise, synchronous behaviour is disabled if + * @synchronous is %FALSE. + */ +void +gst_vaapi_display_x11_set_synchronous (GstVaapiDisplayX11 * display, + gboolean synchronous) +{ + g_return_if_fail (GST_VAAPI_IS_DISPLAY_X11 (display)); + + set_synchronous (display, synchronous); +} + +typedef struct _GstVaapiPixmapFormatX11 GstVaapiPixmapFormatX11; +struct _GstVaapiPixmapFormatX11 +{ + GstVideoFormat format; + gint depth; + gint bpp; +}; + +static GstVideoFormat +pix_fmt_to_video_format (gint depth, gint bpp) +{ + GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN; + + switch (bpp) { + case 16: + if (depth == 15) + format = GST_VIDEO_FORMAT_RGB15; + else if (depth == 16) + format = GST_VIDEO_FORMAT_RGB16; + break; + case 24: + if (depth == 24) + format = GST_VIDEO_FORMAT_RGB; + break; + case 32: + if (depth == 24 || depth == 32) + format = GST_VIDEO_FORMAT_xRGB; + break; + } + return format; +} + +static gboolean +ensure_pix_fmts (GstVaapiDisplayX11 * display) +{ + GstVaapiDisplayX11Private *const priv = + GST_VAAPI_DISPLAY_X11_PRIVATE (display); + XPixmapFormatValues *pix_fmts; + int i, n, num_pix_fmts; + + if (priv->pixmap_formats) + return TRUE; + + GST_VAAPI_DISPLAY_LOCK (display); + pix_fmts = XListPixmapFormats (GST_VAAPI_DISPLAY_XDISPLAY (display), + &num_pix_fmts); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!pix_fmts) + return FALSE; + + priv->pixmap_formats = g_array_sized_new (FALSE, FALSE, + sizeof (GstVaapiPixmapFormatX11), num_pix_fmts); + if (!priv->pixmap_formats) { + XFree (pix_fmts); + return FALSE; + } + + for (i = 0, n = 0; i < num_pix_fmts; i++) { + GstVaapiPixmapFormatX11 *const pix_fmt = + &g_array_index (priv->pixmap_formats, GstVaapiPixmapFormatX11, n); + + pix_fmt->depth = pix_fmts[i].depth; + pix_fmt->bpp = pix_fmts[i].bits_per_pixel; + pix_fmt->format = pix_fmt_to_video_format (pix_fmt->depth, pix_fmt->bpp); + if (pix_fmt->format != GST_VIDEO_FORMAT_UNKNOWN) + n++; + } + priv->pixmap_formats->len = n; + XFree (pix_fmts); + return TRUE; +} + +/* Determine the GstVideoFormat based on a supported Pixmap depth */ +GstVideoFormat +gst_vaapi_display_x11_get_pixmap_format (GstVaapiDisplayX11 * display, + guint depth) +{ + if (ensure_pix_fmts (display)) { + GstVaapiDisplayX11Private *const priv = + GST_VAAPI_DISPLAY_X11_PRIVATE (display); + guint i; + + for (i = 0; i < priv->pixmap_formats->len; i++) { + GstVaapiPixmapFormatX11 *const pix_fmt = + &g_array_index (priv->pixmap_formats, GstVaapiPixmapFormatX11, i); + if (pix_fmt->depth == depth) + return pix_fmt->format; + } + } + return GST_VIDEO_FORMAT_UNKNOWN; +} + +/* Determine the Pixmap depth based on a GstVideoFormat */ +guint +gst_vaapi_display_x11_get_pixmap_depth (GstVaapiDisplayX11 * display, + GstVideoFormat format) +{ + if (ensure_pix_fmts (display)) { + GstVaapiDisplayX11Private *const priv = + GST_VAAPI_DISPLAY_X11_PRIVATE (display); + guint i; + + for (i = 0; i < priv->pixmap_formats->len; i++) { + GstVaapiPixmapFormatX11 *const pix_fmt = + &g_array_index (priv->pixmap_formats, GstVaapiPixmapFormatX11, i); + if (pix_fmt->format == format) + return pix_fmt->depth; + } + } + return 0; +} diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_x11.h b/gst-libs/gst/vaapi/gstvaapidisplay_x11.h new file mode 100644 index 0000000000..78b6103bb2 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_x11.h @@ -0,0 +1,65 @@ +/* + * gstvaapidisplay_x11.h - VA/X11 display abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DISPLAY_X11_H +#define GST_VAAPI_DISPLAY_X11_H + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_DISPLAY_X11 (gst_vaapi_display_x11_get_type ()) +#define GST_VAAPI_DISPLAY_X11(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DISPLAY_X11, GstVaapiDisplayX11)) + +typedef struct _GstVaapiDisplayX11 GstVaapiDisplayX11; + +GstVaapiDisplay * +gst_vaapi_display_x11_new (const gchar * display_name); + +GstVaapiDisplay * +gst_vaapi_display_x11_new_with_display (Display * x11_display); + +GstVaapiDisplay * +gst_vaapi_display_x11_new_with_va_display (VADisplay va_display, Display * x11_display); + +Display * +gst_vaapi_display_x11_get_display (GstVaapiDisplayX11 * display); + +int +gst_vaapi_display_x11_get_screen (GstVaapiDisplayX11 * display); + +void +gst_vaapi_display_x11_set_synchronous (GstVaapiDisplayX11 * display, + gboolean synchronous); + +GType +gst_vaapi_display_x11_get_type (void) G_GNUC_CONST; + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDisplayX11, gst_object_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_DISPLAY_X11_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h b/gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h new file mode 100644 index 0000000000..2f2cc7afe4 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h @@ -0,0 +1,116 @@ +/* + * gstvaapidisplay_x11_priv.h - Internal VA/X11 interface + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DISPLAY_X11_PRIV_H +#define GST_VAAPI_DISPLAY_X11_PRIV_H + +#include +#include +#include "gstvaapidisplay_priv.h" + +G_BEGIN_DECLS + +#define GST_VAAPI_IS_DISPLAY_X11(display) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((display), GST_TYPE_VAAPI_DISPLAY_X11)) + +#define GST_VAAPI_DISPLAY_X11_CAST(display) \ + ((GstVaapiDisplayX11 *)(display)) + +#define GST_VAAPI_DISPLAY_X11_PRIVATE(display) \ + (GST_VAAPI_DISPLAY_X11_CAST (display)->priv) + +#define GST_VAAPI_DISPLAY_X11_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_DISPLAY_X11, GstVaapiDisplayX11Class)) + +typedef struct _GstVaapiDisplayX11Private GstVaapiDisplayX11Private; +typedef struct _GstVaapiDisplayX11Class GstVaapiDisplayX11Class; + +/** + * GST_VAAPI_DISPLAY_XDISPLAY: + * @display: a #GstVaapiDisplay + * + * Macro that evaluates to the underlying X11 #Display of @display + */ +#undef GST_VAAPI_DISPLAY_XDISPLAY +#define GST_VAAPI_DISPLAY_XDISPLAY(display) \ + GST_VAAPI_DISPLAY_X11_PRIVATE(display)->x11_display + +/** + * GST_VAAPI_DISPLAY_XSCREEN: + * @display: a #GstVaapiDisplay + * + * Macro that evaluates to the underlying X11 screen of @display + */ +#undef GST_VAAPI_DISPLAY_XSCREEN +#define GST_VAAPI_DISPLAY_XSCREEN(display) \ + GST_VAAPI_DISPLAY_X11_PRIVATE(display)->x11_screen + +struct _GstVaapiDisplayX11Private +{ + gchar *display_name; + Display *x11_display; + int x11_screen; + GArray *pixmap_formats; + guint use_foreign_display:1; // Foreign native_display? + guint use_xrandr:1; + guint synchronous:1; +}; + +/** + * GstVaapiDisplayX11: + * + * VA/X11 display wrapper. + */ +struct _GstVaapiDisplayX11 +{ + /*< private >*/ + GstVaapiDisplay parent_instance; + + GstVaapiDisplayX11Private *priv; +}; + +/** + * GstVaapiDisplayX11Class: + * + * VA/X11 display wrapper class. + */ +struct _GstVaapiDisplayX11Class +{ + /*< private >*/ + GstVaapiDisplayClass parent_class; +}; + +G_GNUC_INTERNAL +GstVideoFormat +gst_vaapi_display_x11_get_pixmap_format (GstVaapiDisplayX11 * display, + guint depth); + +G_GNUC_INTERNAL +guint +gst_vaapi_display_x11_get_pixmap_depth (GstVaapiDisplayX11 * display, + GstVideoFormat format); + +G_END_DECLS + +#endif /* GST_VAAPI_DISPLAY_X11_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiencoder.c b/gst-libs/gst/vaapi/gstvaapiencoder.c new file mode 100644 index 0000000000..8ab33ca545 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder.c @@ -0,0 +1,1873 @@ +/* + * gstvaapiencoder.c - VA encoder abstraction + * + * Copyright (C) 2013-2014 Intel Corporation + * Author: Wind Yuan + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include "gstvaapicompat.h" +#include "gstvaapiencoder.h" +#include "gstvaapiencoder_priv.h" +#include "gstvaapicontext.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapiutils.h" +#include "gstvaapiutils_core.h" +#include "gstvaapivalue.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +gboolean +gst_vaapi_encoder_ensure_param_quality_level (GstVaapiEncoder * encoder, + GstVaapiEncPicture * picture) +{ + GstVaapiEncMiscParam *misc; + + /* quality level param is not supported */ + if (GST_VAAPI_ENCODER_QUALITY_LEVEL (encoder) == 0) + return TRUE; + + misc = GST_VAAPI_ENC_QUALITY_LEVEL_MISC_PARAM_NEW (encoder); + if (!misc) + return FALSE; + memcpy (misc->data, &encoder->va_quality_level, + sizeof (encoder->va_quality_level)); + gst_vaapi_enc_picture_add_misc_param (picture, misc); + gst_vaapi_codec_object_replace (&misc, NULL); + return TRUE; +} + +gboolean +gst_vaapi_encoder_ensure_param_control_rate (GstVaapiEncoder * encoder, + GstVaapiEncPicture * picture) +{ + GstVaapiEncMiscParam *misc; + + if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CQP) + return TRUE; + + /* HRD params */ + misc = GST_VAAPI_ENC_MISC_PARAM_NEW (HRD, encoder); + if (!misc) + return FALSE; + memcpy (misc->data, &GST_VAAPI_ENCODER_VA_HRD (encoder), + sizeof (VAEncMiscParameterHRD)); + gst_vaapi_enc_picture_add_misc_param (picture, misc); + gst_vaapi_codec_object_replace (&misc, NULL); + + /* RateControl params */ + misc = GST_VAAPI_ENC_MISC_PARAM_NEW (RateControl, encoder); + if (!misc) + return FALSE; + memcpy (misc->data, &GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder), + sizeof (VAEncMiscParameterRateControl)); + gst_vaapi_enc_picture_add_misc_param (picture, misc); + gst_vaapi_codec_object_replace (&misc, NULL); + + /* FrameRate params */ + if (GST_VAAPI_ENCODER_VA_FRAME_RATE (encoder).framerate == 0) + return TRUE; + + misc = GST_VAAPI_ENC_MISC_PARAM_NEW (FrameRate, encoder); + if (!misc) + return FALSE; + memcpy (misc->data, &GST_VAAPI_ENCODER_VA_FRAME_RATE (encoder), + sizeof (VAEncMiscParameterFrameRate)); + gst_vaapi_enc_picture_add_misc_param (picture, misc); + gst_vaapi_codec_object_replace (&misc, NULL); + + return TRUE; +} + +gboolean +gst_vaapi_encoder_ensure_param_trellis (GstVaapiEncoder * encoder, + GstVaapiEncPicture * picture) +{ +#if VA_CHECK_VERSION(1,0,0) + GstVaapiEncMiscParam *misc; + VAEncMiscParameterQuantization *param; + + if (!encoder->trellis) + return TRUE; + + misc = GST_VAAPI_ENC_QUANTIZATION_MISC_PARAM_NEW (encoder); + if (!misc) + return FALSE; + if (!misc->data) + return FALSE; + + param = (VAEncMiscParameterQuantization *) misc->data; + param->quantization_flags.bits.disable_trellis = 0; + param->quantization_flags.bits.enable_trellis_I = 1; + param->quantization_flags.bits.enable_trellis_B = 1; + param->quantization_flags.bits.enable_trellis_P = 1; + + gst_vaapi_enc_picture_add_misc_param (picture, misc); + gst_vaapi_codec_object_replace (&misc, NULL); +#endif + return TRUE; +} + +gboolean +gst_vaapi_encoder_ensure_param_roi_regions (GstVaapiEncoder * encoder, + GstVaapiEncPicture * picture) +{ +#if VA_CHECK_VERSION(0,39,1) + GstVaapiContextInfo *const cip = &encoder->context_info; + const GstVaapiConfigInfoEncoder *const config = &cip->config.encoder; + VAEncMiscParameterBufferROI *roi_param; + GstVaapiEncMiscParam *misc; + VAEncROI *region_roi; + GstBuffer *input; + guint num_roi, i; + gpointer state = NULL; + + if (!config->roi_capability) + return TRUE; + + if (!picture->frame) + return FALSE; + + input = picture->frame->input_buffer; + if (!input) + return FALSE; + + num_roi = + gst_buffer_get_n_meta (input, GST_VIDEO_REGION_OF_INTEREST_META_API_TYPE); + if (num_roi == 0) + return TRUE; + num_roi = CLAMP (num_roi, 1, config->roi_num_supported); + + misc = + gst_vaapi_enc_misc_param_new (encoder, VAEncMiscParameterTypeROI, + sizeof (VAEncMiscParameterBufferROI) + num_roi * sizeof (VAEncROI)); + if (!misc) + return FALSE; + + region_roi = + (VAEncROI *) ((guint8 *) misc->param + sizeof (VAEncMiscParameterBuffer) + + sizeof (VAEncMiscParameterBufferROI)); + + roi_param = misc->data; + roi_param->num_roi = num_roi; + roi_param->roi = region_roi; + + /* roi_value in VAEncROI should be used as ROI delta QP */ + roi_param->roi_flags.bits.roi_value_is_qp_delta = 1; + roi_param->max_delta_qp = 10; + roi_param->min_delta_qp = -10; + + for (i = 0; i < num_roi; i++) { + GstVideoRegionOfInterestMeta *roi; + GstStructure *s; + + roi = (GstVideoRegionOfInterestMeta *) + gst_buffer_iterate_meta_filtered (input, &state, + GST_VIDEO_REGION_OF_INTEREST_META_API_TYPE); + if (!roi) + continue; + + /* ignore roi if overflow */ + if ((roi->x > G_MAXINT16) || (roi->y > G_MAXINT16) + || (roi->w > G_MAXUINT16) || (roi->h > G_MAXUINT16)) + continue; + + GST_LOG ("Input buffer ROI: type=%s id=%d (%d, %d) %dx%d", + g_quark_to_string (roi->roi_type), roi->id, roi->x, roi->y, roi->w, + roi->h); + + picture->has_roi = TRUE; + + region_roi[i].roi_rectangle.x = roi->x; + region_roi[i].roi_rectangle.y = roi->y; + region_roi[i].roi_rectangle.width = roi->w; + region_roi[i].roi_rectangle.height = roi->h; + + s = gst_video_region_of_interest_meta_get_param (roi, "roi/vaapi"); + if (s) { + int value = 0; + + if (!gst_structure_get_int (s, "delta-qp", &value)) + continue; + value = CLAMP (value, roi_param->min_delta_qp, roi_param->max_delta_qp); + region_roi[i].roi_value = value; + } else { + region_roi[i].roi_value = encoder->default_roi_value; + + GST_LOG ("No ROI value specified upstream, use default (%d)", + encoder->default_roi_value); + } + } + + if (picture->has_roi) + gst_vaapi_enc_picture_add_misc_param (picture, misc); + + gst_vaapi_codec_object_replace (&misc, NULL); +#endif + return TRUE; +} + +/** + * gst_vaapi_encoder_replace: + * @old_encoder_ptr: a pointer to a #GstVaapiEncoder + * @new_encoder: a #GstVaapiEncoder + * + * Atomically replaces the encoder encoder held in @old_encoder_ptr + * with @new_encoder. This means that @old_encoder_ptr shall reference + * a valid encoder. However, @new_encoder can be NULL. + */ +void +gst_vaapi_encoder_replace (GstVaapiEncoder ** old_encoder_ptr, + GstVaapiEncoder * new_encoder) +{ + gst_object_replace ((GstObject **) old_encoder_ptr, + (GstObject *) new_encoder); +} + +/* Notifies gst_vaapi_encoder_create_coded_buffer() that a new buffer is free */ +static void +_coded_buffer_proxy_released_notify (GstVaapiEncoder * encoder) +{ + g_mutex_lock (&encoder->mutex); + g_cond_signal (&encoder->codedbuf_free); + g_mutex_unlock (&encoder->mutex); +} + +/* Creates a new VA coded buffer object proxy, backed from a pool */ +static GstVaapiCodedBufferProxy * +gst_vaapi_encoder_create_coded_buffer (GstVaapiEncoder * encoder) +{ + GstVaapiCodedBufferPool *const pool = + GST_VAAPI_CODED_BUFFER_POOL (encoder->codedbuf_pool); + GstVaapiCodedBufferProxy *codedbuf_proxy; + + g_mutex_lock (&encoder->mutex); + do { + codedbuf_proxy = gst_vaapi_coded_buffer_proxy_new_from_pool (pool); + if (codedbuf_proxy) + break; + + /* Wait for a free coded buffer to become available */ + g_cond_wait (&encoder->codedbuf_free, &encoder->mutex); + codedbuf_proxy = gst_vaapi_coded_buffer_proxy_new_from_pool (pool); + } while (0); + g_mutex_unlock (&encoder->mutex); + if (!codedbuf_proxy) + return NULL; + + gst_vaapi_coded_buffer_proxy_set_destroy_notify (codedbuf_proxy, + (GDestroyNotify) _coded_buffer_proxy_released_notify, encoder); + return codedbuf_proxy; +} + +/* Notifies gst_vaapi_encoder_create_surface() that a new surface is free */ +static void +_surface_proxy_released_notify (GstVaapiEncoder * encoder) +{ + g_mutex_lock (&encoder->mutex); + g_cond_signal (&encoder->surface_free); + g_mutex_unlock (&encoder->mutex); +} + +/* Creates a new VA surface object proxy, backed from a pool and + useful to allocate reconstructed surfaces */ +GstVaapiSurfaceProxy * +gst_vaapi_encoder_create_surface (GstVaapiEncoder * encoder) +{ + GstVaapiSurfaceProxy *proxy; + + g_return_val_if_fail (encoder->context != NULL, NULL); + + g_mutex_lock (&encoder->mutex); + for (;;) { + proxy = gst_vaapi_context_get_surface_proxy (encoder->context); + if (proxy) + break; + + /* Wait for a free surface proxy to become available */ + g_cond_wait (&encoder->surface_free, &encoder->mutex); + } + g_mutex_unlock (&encoder->mutex); + + gst_vaapi_surface_proxy_set_destroy_notify (proxy, + (GDestroyNotify) _surface_proxy_released_notify, encoder); + return proxy; +} + +/* Create a coded buffer proxy where the picture is going to be + * decoded, the subclass encode vmethod is called and, if it doesn't + * fail, the coded buffer is pushed into the async queue */ +static GstVaapiEncoderStatus +gst_vaapi_encoder_encode_and_queue (GstVaapiEncoder * encoder, + GstVaapiEncPicture * picture) +{ + GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder); + GstVaapiCodedBufferProxy *codedbuf_proxy; + GstVaapiEncoderStatus status; + + codedbuf_proxy = gst_vaapi_encoder_create_coded_buffer (encoder); + if (!codedbuf_proxy) + goto error_create_coded_buffer; + + status = klass->encode (encoder, picture, codedbuf_proxy); + if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) + goto error_encode; + + gst_vaapi_coded_buffer_proxy_set_user_data (codedbuf_proxy, + picture, (GDestroyNotify) gst_vaapi_mini_object_unref); + g_async_queue_push (encoder->codedbuf_queue, codedbuf_proxy); + encoder->num_codedbuf_queued++; + + return status; + + /* ERRORS */ +error_create_coded_buffer: + { + GST_ERROR ("failed to allocate coded buffer"); + return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED; + } +error_encode: + { + GST_ERROR ("failed to encode frame (status = %d)", status); + gst_vaapi_coded_buffer_proxy_unref (codedbuf_proxy); + return status; + } +} + +/** + * gst_vaapi_encoder_put_frame: + * @encoder: a #GstVaapiEncoder + * @frame: a #GstVideoCodecFrame + * + * Queues a #GstVideoCodedFrame to the HW encoder. The encoder holds + * an extra reference to the @frame. + * + * Return value: a #GstVaapiEncoderStatus + */ +GstVaapiEncoderStatus +gst_vaapi_encoder_put_frame (GstVaapiEncoder * encoder, + GstVideoCodecFrame * frame) +{ + GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder); + GstVaapiEncoderStatus status; + GstVaapiEncPicture *picture; + + for (;;) { + picture = NULL; + status = klass->reordering (encoder, frame, &picture); + if (status == GST_VAAPI_ENCODER_STATUS_NO_SURFACE) + break; + if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) + goto error_reorder_frame; + + status = gst_vaapi_encoder_encode_and_queue (encoder, picture); + if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) + goto error_encode; + + /* Try again with any pending reordered frame now available for encoding */ + frame = NULL; + } + return GST_VAAPI_ENCODER_STATUS_SUCCESS; + + /* ERRORS */ +error_reorder_frame: + { + GST_ERROR ("failed to process reordered frames"); + return status; + } +error_encode: + { + gst_vaapi_enc_picture_unref (picture); + return status; + } +} + +/** + * gst_vaapi_encoder_get_buffer_with_timeout: + * @encoder: a #GstVaapiEncoder + * @out_codedbuf_proxy_ptr: the next coded buffer as a #GstVaapiCodedBufferProxy + * @timeout: the number of microseconds to wait for the coded buffer, at most + * + * Upon successful return, *@out_codedbuf_proxy_ptr contains the next + * coded buffer as a #GstVaapiCodedBufferProxy. The caller owns this + * object, so gst_vaapi_coded_buffer_proxy_unref() shall be called + * after usage. Otherwise, @GST_VAAPI_DECODER_STATUS_ERROR_NO_BUFFER + * is returned if no coded buffer is available so far (timeout). + * + * The parent frame is available as a #GstVideoCodecFrame attached to + * the user-data anchor of the output coded buffer. Ownership of the + * frame is transferred to the coded buffer. + * + * Return value: a #GstVaapiEncoderStatus + */ +GstVaapiEncoderStatus +gst_vaapi_encoder_get_buffer_with_timeout (GstVaapiEncoder * encoder, + GstVaapiCodedBufferProxy ** out_codedbuf_proxy_ptr, guint64 timeout) +{ + GstVaapiEncPicture *picture; + GstVaapiCodedBufferProxy *codedbuf_proxy; + + codedbuf_proxy = g_async_queue_timeout_pop (encoder->codedbuf_queue, timeout); + if (!codedbuf_proxy) + return GST_VAAPI_ENCODER_STATUS_NO_BUFFER; + + /* Wait for completion of all operations and report any error that occurred */ + picture = gst_vaapi_coded_buffer_proxy_get_user_data (codedbuf_proxy); + if (!gst_vaapi_surface_sync (picture->surface)) + goto error_invalid_buffer; + + gst_vaapi_coded_buffer_proxy_set_user_data (codedbuf_proxy, + gst_video_codec_frame_ref (picture->frame), + (GDestroyNotify) gst_video_codec_frame_unref); + + if (out_codedbuf_proxy_ptr) + *out_codedbuf_proxy_ptr = gst_vaapi_coded_buffer_proxy_ref (codedbuf_proxy); + gst_vaapi_coded_buffer_proxy_unref (codedbuf_proxy); + return GST_VAAPI_ENCODER_STATUS_SUCCESS; + + /* ERRORS */ +error_invalid_buffer: + { + GST_ERROR ("failed to encode the frame"); + gst_vaapi_coded_buffer_proxy_unref (codedbuf_proxy); + return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_SURFACE; + } +} + +static inline gboolean +_get_pending_reordered (GstVaapiEncoder * encoder, + GstVaapiEncPicture ** picture, gpointer * state) +{ + GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder); + + if (!klass->get_pending_reordered) + return FALSE; + return klass->get_pending_reordered (encoder, picture, state); +} + +/** + * gst_vaapi_encoder_flush: + * @encoder: a #GstVaapiEncoder + * + * Submits any pending (reordered) frame for encoding. + * + * Return value: a #GstVaapiEncoderStatus + */ +GstVaapiEncoderStatus +gst_vaapi_encoder_flush (GstVaapiEncoder * encoder) +{ + GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder); + GstVaapiEncPicture *picture; + GstVaapiEncoderStatus status; + gpointer iter = NULL; + + picture = NULL; + while (_get_pending_reordered (encoder, &picture, &iter)) { + if (!picture) + continue; + status = gst_vaapi_encoder_encode_and_queue (encoder, picture); + if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) + goto error_encode; + } + g_free (iter); + + return klass->flush (encoder); + + /* ERRORS */ +error_encode: + { + gst_vaapi_enc_picture_unref (picture); + return status; + } +} + +/** + * gst_vaapi_encoder_get_codec_data: + * @encoder: a #GstVaapiEncoder + * @out_codec_data_ptr: the pointer to the resulting codec-data (#GstBuffer) + * + * Returns a codec-data buffer that best represents the encoded + * bitstream. Upon successful return, and if the @out_codec_data_ptr + * contents is not NULL, then the caller function shall deallocates + * that buffer with gst_buffer_unref(). + * + * Return value: a #GstVaapiEncoderStatus + */ +GstVaapiEncoderStatus +gst_vaapi_encoder_get_codec_data (GstVaapiEncoder * encoder, + GstBuffer ** out_codec_data_ptr) +{ + GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_SUCCESS; + GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder); + + *out_codec_data_ptr = NULL; + if (!klass->get_codec_data) + return GST_VAAPI_ENCODER_STATUS_SUCCESS; + + ret = klass->get_codec_data (encoder, out_codec_data_ptr); + return ret; +} + +/* Checks video info */ +static GstVaapiEncoderStatus +check_video_info (GstVaapiEncoder * encoder, const GstVideoInfo * vip) +{ + if (!vip->width || !vip->height) + goto error_invalid_resolution; + if (vip->fps_n < 0 || vip->fps_d <= 0) + goto error_invalid_framerate; + return GST_VAAPI_ENCODER_STATUS_SUCCESS; + + /* ERRORS */ +error_invalid_resolution: + { + GST_ERROR ("invalid resolution (%dx%d)", vip->width, vip->height); + return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER; + } +error_invalid_framerate: + { + GST_ERROR ("invalid framerate (%d/%d)", vip->fps_n, vip->fps_d); + return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER; + } +} + +/* Gets a compatible profile for the active codec */ +static GstVaapiProfile +get_compatible_profile (GstVaapiEncoder * encoder) +{ + const GstVaapiEncoderClassData *const cdata = + GST_VAAPI_ENCODER_GET_CLASS (encoder)->class_data; + GstVaapiProfile profile; + GArray *profiles; + guint i; + + profiles = gst_vaapi_display_get_encode_profiles (encoder->display); + if (!profiles) + return GST_VAAPI_PROFILE_UNKNOWN; + + // Pick a profile matching the class codec + for (i = 0; i < profiles->len; i++) { + profile = g_array_index (profiles, GstVaapiProfile, i); + if (gst_vaapi_profile_get_codec (profile) == cdata->codec) + break; + } + if (i == profiles->len) + profile = GST_VAAPI_PROFILE_UNKNOWN; + + g_array_unref (profiles); + return profile; +} + +/* Gets a supported profile for the active codec */ +static GstVaapiProfile +get_profile (GstVaapiEncoder * encoder) +{ + if (!encoder->profile) + encoder->profile = get_compatible_profile (encoder); + return encoder->profile; +} + +/* Gets config attribute for the supplied profile */ +static gboolean +get_config_attribute (GstVaapiEncoder * encoder, VAConfigAttribType type, + guint * out_value_ptr) +{ + GstVaapiProfile profile; + VAProfile va_profile; + VAEntrypoint va_entrypoint; + + profile = get_profile (encoder); + if (!profile) + return FALSE; + va_profile = gst_vaapi_profile_get_va_profile (profile); + + va_entrypoint = + gst_vaapi_entrypoint_get_va_entrypoint (encoder->context_info.entrypoint); + + return gst_vaapi_get_config_attribute (encoder->display, va_profile, + va_entrypoint, type, out_value_ptr); +} + +/* Determines the set of supported packed headers */ +static guint +get_packed_headers (GstVaapiEncoder * encoder) +{ + const GstVaapiEncoderClassData *const cdata = + GST_VAAPI_ENCODER_GET_CLASS (encoder)->class_data; + guint value; + + if (encoder->got_packed_headers) + return encoder->packed_headers; + + if (!get_config_attribute (encoder, VAConfigAttribEncPackedHeaders, &value)) + value = 0; + GST_INFO ("supported packed headers: 0x%08x", value); + + encoder->got_packed_headers = TRUE; + encoder->packed_headers = cdata->packed_headers & value; + + return encoder->packed_headers; +} + +static gboolean +get_roi_capability (GstVaapiEncoder * encoder, guint * num_roi_supported) +{ +#if VA_CHECK_VERSION(0,39,1) + VAConfigAttribValEncROI *roi_config; + guint value; + + if (!get_config_attribute (encoder, VAConfigAttribEncROI, &value)) + return FALSE; + + roi_config = (VAConfigAttribValEncROI *) & value; + + if (roi_config->bits.num_roi_regions == 0) + return FALSE; + + /* Only support QP delta, and it only makes sense when rate control + * is not CQP */ + if ((GST_VAAPI_ENCODER_RATE_CONTROL (encoder) != GST_VAAPI_RATECONTROL_CQP) + && (VA_ROI_RC_QP_DELTA_SUPPORT (roi_config) == 0)) + return FALSE; + + GST_INFO ("Support for ROI - number of regions supported: %d", + roi_config->bits.num_roi_regions); + + *num_roi_supported = roi_config->bits.num_roi_regions; + return TRUE; +#else + return FALSE; +#endif +} + +static inline gboolean +is_chroma_type_supported (GstVaapiEncoder * encoder) +{ + GstVaapiContextInfo *const cip = &encoder->context_info; + const GstVideoFormat fmt = + GST_VIDEO_INFO_FORMAT (GST_VAAPI_ENCODER_VIDEO_INFO (encoder)); + guint format = 0; + + if (fmt == GST_VIDEO_FORMAT_ENCODED) + return TRUE; + + if (cip->chroma_type != GST_VAAPI_CHROMA_TYPE_YUV420 && + cip->chroma_type != GST_VAAPI_CHROMA_TYPE_YUV422 && + cip->chroma_type != GST_VAAPI_CHROMA_TYPE_YUV420_10BPP && + cip->chroma_type != GST_VAAPI_CHROMA_TYPE_YUV444 && + cip->chroma_type != GST_VAAPI_CHROMA_TYPE_YUV444_10BPP && + cip->chroma_type != GST_VAAPI_CHROMA_TYPE_YUV422_10BPP && + cip->chroma_type != GST_VAAPI_CHROMA_TYPE_YUV420_12BPP) + goto unsupported; + + if (!get_config_attribute (encoder, VAConfigAttribRTFormat, &format)) + return FALSE; + + if (!(format & from_GstVaapiChromaType (cip->chroma_type))) + goto unsupported; + + return TRUE; + + /* ERRORS */ +unsupported: + { + GST_ERROR ("The encoding format %s is not supported, " + "Please try to use vaapipostproc to convert the input format.", + gst_video_format_to_string (fmt)); + return FALSE; + } +} + +static guint +get_default_chroma_type (GstVaapiEncoder * encoder, + const GstVaapiContextInfo * cip) +{ + guint value; + + if (!gst_vaapi_get_config_attribute (encoder->display, + gst_vaapi_profile_get_va_profile (cip->profile), + gst_vaapi_entrypoint_get_va_entrypoint (cip->entrypoint), + VAConfigAttribRTFormat, &value)) + return 0; + + return to_GstVaapiChromaType (value); +} + +static void +init_context_info (GstVaapiEncoder * encoder, GstVaapiContextInfo * cip) +{ + cip->usage = GST_VAAPI_CONTEXT_USAGE_ENCODE; + cip->chroma_type = get_default_chroma_type (encoder, cip); + cip->width = 0; + cip->height = 0; + cip->ref_frames = encoder->num_ref_frames; +} + +/* Updates video context */ +static gboolean +set_context_info (GstVaapiEncoder * encoder) +{ + GstVaapiContextInfo *const cip = &encoder->context_info; + GstVaapiConfigInfoEncoder *const config = &cip->config.encoder; + const GstVideoFormat format = + GST_VIDEO_INFO_FORMAT (GST_VAAPI_ENCODER_VIDEO_INFO (encoder)); + + g_assert (cip->profile != GST_VAAPI_PROFILE_UNKNOWN); + g_assert (cip->entrypoint != GST_VAAPI_ENTRYPOINT_INVALID); + + init_context_info (encoder, cip); + cip->chroma_type = gst_vaapi_video_format_get_chroma_type (format); + cip->width = GST_VAAPI_ENCODER_WIDTH (encoder); + cip->height = GST_VAAPI_ENCODER_HEIGHT (encoder); + + if (!is_chroma_type_supported (encoder)) + goto error_unsupported_format; + + memset (config, 0, sizeof (*config)); + config->rc_mode = GST_VAAPI_ENCODER_RATE_CONTROL (encoder); + config->packed_headers = get_packed_headers (encoder); + config->roi_capability = + get_roi_capability (encoder, &config->roi_num_supported); + + return TRUE; + + /* ERRORS */ +error_unsupported_format: + { + GST_ERROR ("failed to determine chroma type for format %s", + gst_vaapi_video_format_to_string (format)); + return FALSE; + } +} + +/* Ensures the underlying VA context for encoding is created */ +static gboolean +gst_vaapi_encoder_ensure_context (GstVaapiEncoder * encoder) +{ + GstVaapiContextInfo *const cip = &encoder->context_info; + + if (!set_context_info (encoder)) + return FALSE; + + if (encoder->context) { + if (!gst_vaapi_context_reset (encoder->context, cip)) + return FALSE; + } else { + encoder->context = gst_vaapi_context_new (encoder->display, cip); + if (!encoder->context) + return FALSE; + } + encoder->va_context = gst_vaapi_context_get_id (encoder->context); + return TRUE; +} + +/* Reconfigures the encoder with the new properties */ +static GstVaapiEncoderStatus +gst_vaapi_encoder_reconfigure_internal (GstVaapiEncoder * encoder) +{ + GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder); + GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder); + GstVaapiEncoderStatus status; + GstVaapiVideoPool *pool; + guint codedbuf_size, target_percentage; + guint fps_d, fps_n; + guint quality_level_max = 0; + + fps_d = GST_VIDEO_INFO_FPS_D (vip); + fps_n = GST_VIDEO_INFO_FPS_N (vip); + + /* Generate a keyframe every second */ + if (!encoder->keyframe_period) + encoder->keyframe_period = (fps_n + fps_d - 1) / fps_d; + + /* Default frame rate parameter */ + if (fps_d > 0 && fps_n > 0) + GST_VAAPI_ENCODER_VA_FRAME_RATE (encoder).framerate = fps_d << 16 | fps_n; + + target_percentage = + (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CBR) ? + 100 : encoder->target_percentage; + + /* *INDENT-OFF* */ + /* Default values for rate control parameter */ + GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder) = (VAEncMiscParameterRateControl) { + .bits_per_second = encoder->bitrate * 1000, + .target_percentage = target_percentage, + .window_size = 500, + }; + /* *INDENT-ON* */ + + status = klass->reconfigure (encoder); + if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) + return status; + + if (!gst_vaapi_encoder_ensure_context (encoder)) + goto error_reset_context; + + if (get_config_attribute (encoder, VAConfigAttribEncQualityRange, + &quality_level_max) && quality_level_max > 0) { + GST_VAAPI_ENCODER_QUALITY_LEVEL (encoder) = + CLAMP (GST_VAAPI_ENCODER_QUALITY_LEVEL (encoder), 1, quality_level_max); + } else { + GST_VAAPI_ENCODER_QUALITY_LEVEL (encoder) = 0; + } + GST_INFO ("Quality level is fixed to %d", + GST_VAAPI_ENCODER_QUALITY_LEVEL (encoder)); + + if (encoder->trellis) { +#if VA_CHECK_VERSION(1,0,0) + guint quantization_method = 0; + if (get_config_attribute (encoder, VAConfigAttribEncQuantization, + &quantization_method) == FALSE + || !(quantization_method & VA_ENC_QUANTIZATION_TRELLIS_SUPPORTED)) { + + GST_INFO ("Trellis Quantization is not supported," + " trellis will be disabled"); + encoder->trellis = FALSE; + } +#else + GST_INFO ("The encode trellis quantization option is not supported" + " in this VAAPI version."); + encoder->trellis = FALSE; +#endif + } + + codedbuf_size = encoder->codedbuf_pool ? + gst_vaapi_coded_buffer_pool_get_buffer_size (GST_VAAPI_CODED_BUFFER_POOL + (encoder)) : 0; + if (codedbuf_size != encoder->codedbuf_size) { + pool = gst_vaapi_coded_buffer_pool_new (encoder, encoder->codedbuf_size); + if (!pool) + goto error_alloc_codedbuf_pool; + gst_vaapi_video_pool_set_capacity (pool, 5); + gst_vaapi_video_pool_replace (&encoder->codedbuf_pool, pool); + gst_vaapi_video_pool_unref (pool); + } + return GST_VAAPI_ENCODER_STATUS_SUCCESS; + + /* ERRORS */ +error_alloc_codedbuf_pool: + { + GST_ERROR ("failed to initialize coded buffer pool"); + return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED; + } +error_reset_context: + { + GST_ERROR ("failed to update VA context"); + return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED; + } +} + +/** + * gst_vaapi_encoder_set_codec_state: + * @encoder: a #GstVaapiEncoder + * @state : a #GstVideoCodecState + * + * Notifies the encoder about the source surface properties. The + * accepted set of properties is: video resolution, colorimetry, + * pixel-aspect-ratio and framerate. + * + * This function is a synchronization point for codec configuration. + * This means that, at this point, the encoder is reconfigured to + * match the new properties and any other change beyond this point has + * zero effect. + * + * Return value: a #GstVaapiEncoderStatus + */ +GstVaapiEncoderStatus +gst_vaapi_encoder_set_codec_state (GstVaapiEncoder * encoder, + GstVideoCodecState * state) +{ + GstVaapiEncoderStatus status; + + g_return_val_if_fail (encoder != NULL, + GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER); + g_return_val_if_fail (state != NULL, + GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER); + + if (!gst_video_info_is_equal (&state->info, &encoder->video_info)) { + status = check_video_info (encoder, &state->info); + if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) + return status; + encoder->video_info = state->info; + } + return gst_vaapi_encoder_reconfigure_internal (encoder); +} + +/* Determine the supported rate control modes */ +static guint +get_rate_control_mask (GstVaapiEncoder * encoder) +{ + const GstVaapiEncoderClassData *const cdata = + GST_VAAPI_ENCODER_GET_CLASS (encoder)->class_data; + guint i, value, rate_control_mask = 0; + + if (encoder->got_rate_control_mask) + return encoder->rate_control_mask; + + if (get_config_attribute (encoder, VAConfigAttribRateControl, &value)) { + for (i = 0; i < 32; i++) { + if (!(value & (1U << i))) + continue; + rate_control_mask |= 1 << to_GstVaapiRateControl (1 << i); + } + GST_INFO ("supported rate controls: 0x%08x", rate_control_mask); + + encoder->got_rate_control_mask = TRUE; + encoder->rate_control_mask = cdata->rate_control_mask & rate_control_mask; + } + + return encoder->rate_control_mask; +} + +/** + * gst_vaapi_encoder_set_rate_control: + * @encoder: a #GstVaapiEncoder + * @rate_control: the requested rate control + * + * Notifies the @encoder to use the supplied @rate_control mode. + * + * If the underlying encoder does not support that rate control mode, + * then @GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_RATE_CONTROL is + * returned. + * + * The rate control mode can only be specified before the first frame + * is to be encoded. Afterwards, any change to this parameter is + * invalid and @GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED is + * returned. + * + * Return value: a #GstVaapiEncoderStatus + */ +GstVaapiEncoderStatus +gst_vaapi_encoder_set_rate_control (GstVaapiEncoder * encoder, + GstVaapiRateControl rate_control) +{ + guint32 rate_control_mask; + + g_return_val_if_fail (encoder != NULL, + GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER); + + if (encoder->rate_control != rate_control && encoder->num_codedbuf_queued > 0) + goto error_operation_failed; + + rate_control_mask = get_rate_control_mask (encoder); + if (rate_control_mask && !(rate_control_mask & (1U << rate_control))) + goto error_unsupported_rate_control; + + encoder->rate_control = rate_control; + return GST_VAAPI_ENCODER_STATUS_SUCCESS; + + /* ERRORS */ +error_operation_failed: + { + GST_ERROR ("could not change rate control mode after encoding started"); + return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED; + } +error_unsupported_rate_control: + { + GST_ERROR ("unsupported rate control mode (%d)", rate_control); + return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_RATE_CONTROL; + } +} + +/** + * gst_vaapi_encoder_set_bitrate: + * @encoder: a #GstVaapiEncoder + * @bitrate: the requested bitrate (in kbps) + * + * Notifies the @encoder to use the supplied @bitrate value. + * + * Note: currently, the bitrate can only be specified before the first + * frame is encoded. Afterwards, any change to this parameter is + * invalid and @GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED is + * returned. + * + * Return value: a #GstVaapiEncoderStatus + */ +GstVaapiEncoderStatus +gst_vaapi_encoder_set_bitrate (GstVaapiEncoder * encoder, guint bitrate) +{ + g_return_val_if_fail (encoder != NULL, 0); + + if (encoder->bitrate != bitrate && encoder->num_codedbuf_queued > 0) { + GST_INFO ("Bitrate is changed to %d on runtime", bitrate); + encoder->bitrate = bitrate; + return gst_vaapi_encoder_reconfigure_internal (encoder); + } + + encoder->bitrate = bitrate; + return GST_VAAPI_ENCODER_STATUS_SUCCESS; +} + +GstVaapiEncoderStatus +gst_vaapi_encoder_set_target_percentage (GstVaapiEncoder * encoder, + guint target_percentage) +{ + g_return_val_if_fail (encoder != NULL, 0); + + if (encoder->target_percentage != target_percentage + && encoder->num_codedbuf_queued > 0) { + if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) != GST_VAAPI_RATECONTROL_CBR) { + GST_INFO ("Target percentage is changed to %d on runtime", + target_percentage); + encoder->target_percentage = target_percentage; + return gst_vaapi_encoder_reconfigure_internal (encoder); + } + GST_WARNING ("Target percentage is ignored for CBR rate-control"); + return GST_VAAPI_ENCODER_STATUS_SUCCESS; + } + + encoder->target_percentage = target_percentage; + return GST_VAAPI_ENCODER_STATUS_SUCCESS; +} + +/** + * gst_vaapi_encoder_set_keyframe_period: + * @encoder: a #GstVaapiEncoder + * @keyframe_period: the maximal distance between two keyframes + * + * Notifies the @encoder to use the supplied @keyframe_period value. + * + * Note: currently, the keyframe period can only be specified before + * the last call to gst_vaapi_encoder_set_codec_state(), which shall + * occur before the first frame is encoded. Afterwards, any change to + * this parameter causes gst_vaapi_encoder_set_keyframe_period() to + * return @GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED. + * + * Return value: a #GstVaapiEncoderStatus + */ +GstVaapiEncoderStatus +gst_vaapi_encoder_set_keyframe_period (GstVaapiEncoder * encoder, + guint keyframe_period) +{ + g_return_val_if_fail (encoder != NULL, 0); + + if (encoder->keyframe_period != keyframe_period + && encoder->num_codedbuf_queued > 0) + goto error_operation_failed; + + encoder->keyframe_period = keyframe_period; + return GST_VAAPI_ENCODER_STATUS_SUCCESS; + + /* ERRORS */ +error_operation_failed: + { + GST_ERROR ("could not change keyframe period after encoding started"); + return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED; + } +} + +/** + * gst_vaapi_encoder_set_tuning: + * @encoder: a #GstVaapiEncoder + * @tuning: the #GstVaapiEncoderTune option + * + * Notifies the @encoder to use the supplied @tuning option. + * + * Note: currently, the tuning option can only be specified before the + * last call to gst_vaapi_encoder_set_codec_state(), which shall occur + * before the first frame is encoded. Afterwards, any change to this + * parameter causes gst_vaapi_encoder_set_tuning() to return + * @GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED. + * + * Return value: a #GstVaapiEncoderStatus + */ +GstVaapiEncoderStatus +gst_vaapi_encoder_set_tuning (GstVaapiEncoder * encoder, + GstVaapiEncoderTune tuning) +{ + g_return_val_if_fail (encoder != NULL, 0); + + if (encoder->tune != tuning && encoder->num_codedbuf_queued > 0) + goto error_operation_failed; + + encoder->tune = tuning; + return GST_VAAPI_ENCODER_STATUS_SUCCESS; + + /* ERRORS */ +error_operation_failed: + { + GST_ERROR ("could not change tuning options after encoding started"); + return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED; + } +} + +/** + * gst_vaapi_encoder_set_quality_level: + * @encoder: a #GstVaapiEncoder + * @quality_level: the encoder quality level + * + * Notifies the @encoder to use the supplied @quality_level value. + * + * Note: currently, the quality_level can only be specified before + * the last call to gst_vaapi_encoder_set_codec_state(), which shall + * occur before the first frame is encoded. Afterwards, any change to + * this parameter causes gst_vaapi_encoder_set_quality_level() to + * return @GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED. + * + * Return value: a #GstVaapiEncoderStatus + */ +GstVaapiEncoderStatus +gst_vaapi_encoder_set_quality_level (GstVaapiEncoder * encoder, + guint quality_level) +{ + g_return_val_if_fail (encoder != NULL, 0); + + if (GST_VAAPI_ENCODER_QUALITY_LEVEL (encoder) != quality_level + && encoder->num_codedbuf_queued > 0) + goto error_operation_failed; + + GST_VAAPI_ENCODER_QUALITY_LEVEL (encoder) = quality_level; + return GST_VAAPI_ENCODER_STATUS_SUCCESS; + + /* ERRORS */ +error_operation_failed: + { + GST_ERROR ("could not change quality level after encoding started"); + return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED; + } +} + +/** + * gst_vaapi_encoder_set_trellis: + * @encoder: a #GstVaapiEncoder + * @trellis: whether to use trellis quantization + * + * Notifies the @encoder to use the supplied @trellis option. + * + * Note: currently, the tuning option can only be specified before the + * last call to gst_vaapi_encoder_set_codec_state(), which shall occur + * before the first frame is encoded. Afterwards, any change to this + * parameter causes gst_vaapi_encoder_set_tuning() to return + * @GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED. + * + * Return value: a #GstVaapiEncoderStatus + */ +GstVaapiEncoderStatus +gst_vaapi_encoder_set_trellis (GstVaapiEncoder * encoder, gboolean trellis) +{ + g_return_val_if_fail (encoder != NULL, 0); + + if (encoder->trellis != trellis && encoder->num_codedbuf_queued > 0) + goto error_operation_failed; + + encoder->trellis = trellis; + return GST_VAAPI_ENCODER_STATUS_SUCCESS; + + /* ERRORS */ +error_operation_failed: + { + GST_ERROR ("could not change trellis options after encoding started"); + return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED; + } +} + +G_DEFINE_ABSTRACT_TYPE (GstVaapiEncoder, gst_vaapi_encoder, GST_TYPE_OBJECT); + +/** + * GstVaapiEncoderProp: + * @ENCODER_PROP_DISPLAY: The display. + * @ENCODER_PROP_BITRATE: Bitrate expressed in kbps (uint). + * @ENCODER_PROP_TARGET_PERCENTAGE: Desired target percentage of + * bitrate for variable rate controls. + * @ENCODER_PROP_KEYFRAME_PERIOD: The maximal distance + * between two keyframes (uint). + * @ENCODER_PROP_DEFAULT_ROI_VALUE: The default delta qp to apply + * to each region of interest. + * @ENCODER_PROP_TRELLIS: Use trellis quantization method (gboolean). + * + * The set of configurable properties for the encoder. + */ +enum +{ + ENCODER_PROP_DISPLAY = 1, + ENCODER_PROP_BITRATE, + ENCODER_PROP_TARGET_PERCENTAGE, + ENCODER_PROP_KEYFRAME_PERIOD, + ENCODER_PROP_QUALITY_LEVEL, + ENCODER_PROP_DEFAULT_ROI_VALUE, + ENCODER_PROP_TRELLIS, + ENCODER_N_PROPERTIES +}; + +static GParamSpec *properties[ENCODER_N_PROPERTIES]; + +static void +gst_vaapi_encoder_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstVaapiEncoder *encoder = GST_VAAPI_ENCODER (object); + GstVaapiEncoderStatus status = GST_VAAPI_ENCODER_STATUS_SUCCESS; + + switch (prop_id) { + case ENCODER_PROP_DISPLAY: + g_assert (encoder->display == NULL); + encoder->display = g_value_dup_object (value); + g_assert (encoder->display != NULL); + encoder->va_display = GST_VAAPI_DISPLAY_VADISPLAY (encoder->display); + break; + case ENCODER_PROP_BITRATE: + status = gst_vaapi_encoder_set_bitrate (encoder, + g_value_get_uint (value)); + break; + case ENCODER_PROP_TARGET_PERCENTAGE: + status = + gst_vaapi_encoder_set_target_percentage (encoder, + g_value_get_uint (value)); + break; + case ENCODER_PROP_KEYFRAME_PERIOD: + status = + gst_vaapi_encoder_set_keyframe_period (encoder, + g_value_get_uint (value)); + break; + case ENCODER_PROP_QUALITY_LEVEL: + status = + gst_vaapi_encoder_set_quality_level (encoder, + g_value_get_uint (value)); + break; + case ENCODER_PROP_DEFAULT_ROI_VALUE: + encoder->default_roi_value = g_value_get_int (value); + status = GST_VAAPI_ENCODER_STATUS_SUCCESS; + break; + case ENCODER_PROP_TRELLIS: + status = + gst_vaapi_encoder_set_trellis (encoder, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + + if (status) + GST_WARNING_OBJECT (encoder, "Failed to set the property:%s, error is %d", + g_param_spec_get_name (pspec), status); +} + +static void +gst_vaapi_encoder_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstVaapiEncoder *encoder = GST_VAAPI_ENCODER (object); + + switch (prop_id) { + case ENCODER_PROP_DISPLAY: + g_value_set_object (value, encoder->display); + break; + case ENCODER_PROP_BITRATE: + g_value_set_uint (value, encoder->bitrate); + break; + case ENCODER_PROP_TARGET_PERCENTAGE: + g_value_set_uint (value, encoder->target_percentage); + break; + case ENCODER_PROP_KEYFRAME_PERIOD: + g_value_set_uint (value, encoder->keyframe_period); + break; + case ENCODER_PROP_QUALITY_LEVEL: + g_value_set_uint (value, GST_VAAPI_ENCODER_QUALITY_LEVEL (encoder)); + break; + case ENCODER_PROP_DEFAULT_ROI_VALUE: + g_value_set_int (value, encoder->default_roi_value); + break; + case ENCODER_PROP_TRELLIS: + g_value_set_boolean (value, encoder->trellis); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_encoder_init (GstVaapiEncoder * encoder) +{ + encoder->va_context = VA_INVALID_ID; + + gst_video_info_init (&encoder->video_info); + + g_mutex_init (&encoder->mutex); + g_cond_init (&encoder->surface_free); + g_cond_init (&encoder->codedbuf_free); + + encoder->codedbuf_queue = g_async_queue_new_full ((GDestroyNotify) + gst_vaapi_coded_buffer_proxy_unref); +} + +/* Base encoder cleanup (internal) */ +static void +gst_vaapi_encoder_finalize (GObject * object) +{ + GstVaapiEncoder *encoder = GST_VAAPI_ENCODER (object); + + if (encoder->context) + gst_vaapi_context_unref (encoder->context); + encoder->context = NULL; + gst_vaapi_display_replace (&encoder->display, NULL); + encoder->va_display = NULL; + + if (encoder->properties) { + g_ptr_array_unref (encoder->properties); + encoder->properties = NULL; + } + + gst_vaapi_video_pool_replace (&encoder->codedbuf_pool, NULL); + if (encoder->codedbuf_queue) { + g_async_queue_unref (encoder->codedbuf_queue); + encoder->codedbuf_queue = NULL; + } + g_cond_clear (&encoder->surface_free); + g_cond_clear (&encoder->codedbuf_free); + g_mutex_clear (&encoder->mutex); + + G_OBJECT_CLASS (gst_vaapi_encoder_parent_class)->finalize (object); +} + +static void +gst_vaapi_encoder_class_init (GstVaapiEncoderClass * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = gst_vaapi_encoder_set_property; + object_class->get_property = gst_vaapi_encoder_get_property; + object_class->finalize = gst_vaapi_encoder_finalize; + + /** + * GstVaapiDecoder:display: + * + * #GstVaapiDisplay to be used. + */ + properties[ENCODER_PROP_DISPLAY] = + g_param_spec_object ("display", "Gst VA-API Display", + "The VA-API display object to use", GST_TYPE_VAAPI_DISPLAY, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME); + + /** + * GstVaapiEncoder:bitrate: + * + * The desired bitrate, expressed in kbps. + * This is available when rate-control is CBR or VBR. + * + * CBR: This applies equally to minimum, maximum and target bitrate in the driver. + * VBR: This applies to maximum bitrate in the driver. + * Minimum bitrate will be calculated like the following in the driver. + * if (target percentage < 50) minimum bitrate = 0 + * else minimum bitrate = maximum bitrate * (2 * target percentage -100) / 100 + * Target bitrate will be calculated like the following in the driver. + * target bitrate = maximum bitrate * target percentage / 100 + */ + properties[ENCODER_PROP_BITRATE] = + g_param_spec_uint ("bitrate", + "Bitrate (kbps)", + "The desired bitrate expressed in kbps (0: auto-calculate)", + 0, 2000 * 1024, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoder:target-percentage: + * + * The desired target percentage of bitrate for variable rate controls. + */ + properties[ENCODER_PROP_TARGET_PERCENTAGE] = + g_param_spec_uint ("target-percentage", + "Target Percentage", + "The desired target percentage of bitrate for variable rate " + "controls.", 1, 100, 70, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoder:keyframe-period: + * + * The maximal distance between two keyframes. + */ + properties[ENCODER_PROP_KEYFRAME_PERIOD] = + g_param_spec_uint ("keyframe-period", + "Keyframe Period", + "Maximal distance between two keyframes (0: auto-calculate)", 0, + G_MAXUINT32, 30, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoder:quality-level: + * + * The Encoding quality level. + */ + properties[ENCODER_PROP_QUALITY_LEVEL] = + g_param_spec_uint ("quality-level", + "Quality Level", "Encoding Quality Level " + "(lower value means higher-quality/slow-encode, " + " higher value means lower-quality/fast-encode)", + 1, 7, 4, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVapiEncoder:roi-default-delta-qp + * + * Default delta-qp to apply to each Region of Interest + */ + properties[ENCODER_PROP_DEFAULT_ROI_VALUE] = + g_param_spec_int ("default-roi-delta-qp", "Default ROI delta QP", + "The default delta-qp to apply to each Region of Interest" + "(lower value means higher-quality, " + "higher value means lower-quality)", + -10, 10, -10, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoder: trellis: + * + * The trellis quantization method the encoder can use. + * Trellis is an improved quantization algorithm. + * + */ + properties[ENCODER_PROP_TRELLIS] = + g_param_spec_boolean ("trellis", + "Trellis Quantization", + "The Trellis Quantization Method of Encoder", + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + g_object_class_install_properties (object_class, ENCODER_N_PROPERTIES, + properties); +} + +static GstVaapiContext * +create_test_context_config (GstVaapiEncoder * encoder, GstVaapiProfile profile) +{ + GstVaapiContextInfo cip = { 0, }; + GstVaapiContext *ctxt; + + g_assert (profile != GST_VAAPI_PROFILE_UNKNOWN); + + cip.profile = profile; + cip.entrypoint = gst_vaapi_encoder_get_entrypoint (encoder, profile); + if (cip.entrypoint == GST_VAAPI_ENTRYPOINT_INVALID) { + GST_INFO ("can not find %s entrypoint for profile %s to create" + " text context. Ignore this profile", + GST_VAAPI_ENCODER_TUNE (encoder) == GST_VAAPI_ENCODER_TUNE_LOW_POWER ? + "the low-power" : "an available", + gst_vaapi_profile_get_va_name (profile)); + return NULL; + } + + init_context_info (encoder, &cip); + ctxt = gst_vaapi_context_new (encoder->display, &cip); + return ctxt; +} + +static gboolean +get_profile_surface_attributes (GstVaapiEncoder * encoder, + GstVaapiProfile profile, GstVaapiConfigSurfaceAttributes * attribs) +{ + GstVaapiContext *ctxt = NULL; + gboolean ret; + + g_return_val_if_fail (attribs != NULL, FALSE); + g_return_val_if_fail (profile != GST_VAAPI_PROFILE_UNKNOWN, FALSE); + + ctxt = create_test_context_config (encoder, profile); + if (!ctxt) + return FALSE; + + ret = gst_vaapi_context_get_surface_attributes (ctxt, attribs); + if (ret) { + attribs->formats = gst_vaapi_context_get_surface_formats (ctxt); + + if (!attribs->formats) + ret = FALSE; + } + + gst_vaapi_context_unref (ctxt); + return ret; +} + +static gboolean +merge_profile_surface_attributes (GstVaapiEncoder * encoder, + GstVaapiProfile profile, GstVaapiConfigSurfaceAttributes * attribs) +{ + GstVaapiConfigSurfaceAttributes attr = { 0, }; + guint i, j; + GstVideoFormat fmt, sfmt; + + if (profile == GST_VAAPI_PROFILE_UNKNOWN) + return FALSE; + + if (!get_profile_surface_attributes (encoder, profile, &attr)) + return FALSE; + + for (i = 0; i < attr.formats->len; i++) { + sfmt = g_array_index (attr.formats, GstVideoFormat, i); + for (j = 0; j < attribs->formats->len; j++) { + fmt = g_array_index (attribs->formats, GstVideoFormat, j); + if (fmt == sfmt) + break; + } + if (j >= attribs->formats->len) + g_array_append_val (attribs->formats, sfmt); + } + + g_array_unref (attr.formats); + + attribs->min_width = MIN (attribs->min_width, attr.min_width); + attribs->min_height = MIN (attribs->min_height, attr.min_height); + attribs->max_width = MAX (attribs->max_width, attr.max_width); + attribs->max_height = MAX (attribs->max_height, attr.max_height); + attribs->mem_types &= attr.mem_types; + + return TRUE; +} + +/** + * gst_vaapi_encoder_get_surface_attributres: + * @encoder: a #GstVaapiEncoder instances + * @profiles: a #GArray of #GstVaapiProfile to be test + * @min_width (out): the minimal surface width + * @min_height (out): the minimal surface height + * @max_width (out): the maximal surface width + * @max_height (out): the maximal surface height + * + * Fetches the valid surface's attributes for the specified @profiles + * + * Returns: a #GArray of valid formats we get or %NULL if failed. + **/ +GArray * +gst_vaapi_encoder_get_surface_attributes (GstVaapiEncoder * encoder, + GArray * profiles, gint * min_width, gint * min_height, + gint * max_width, gint * max_height, guint * mem_types) +{ + GstVaapiConfigSurfaceAttributes attribs = { + G_MAXINT, G_MAXINT, 1, 1, G_MAXUINT, NULL + }; + GstVaapiProfile profile; + guint i; + + attribs.formats = g_array_new (FALSE, FALSE, sizeof (GstVideoFormat)); + for (i = 0; i < profiles->len; i++) { + profile = g_array_index (profiles, GstVaapiProfile, i); + g_assert (profile != GST_VAAPI_PROFILE_UNKNOWN); + GST_LOG ("Detect input formats of profile %s", + gst_vaapi_profile_get_va_name (profile)); + + if (!merge_profile_surface_attributes (encoder, profile, &attribs)) { + GST_INFO ("Can not get surface formats for profile %s", + gst_vaapi_profile_get_va_name (profile)); + continue; + } + } + + if (attribs.formats->len == 0) { + g_array_unref (attribs.formats); + return NULL; + } + + if (min_width) + *min_width = attribs.min_width; + if (min_height) + *min_height = attribs.min_height; + if (max_width) + *max_width = attribs.max_width; + if (max_height) + *max_height = attribs.max_height; + if (mem_types) + *mem_types = attribs.mem_types; + return attribs.formats; +} + +/** + * gst_vaapi_encoder_ensure_num_slices: + * @encoder: a #GstVaapiEncoder + * @profile: a #GstVaapiProfile + * @entrypoint: a #GstVaapiEntrypoint + * @media_max_slices: the number of the slices permitted by the stream + * @num_slices: (out): the possible number of slices to process + * + * This function will clamp the @num_slices provided by the user, + * according the limit of the number of slices permitted by the stream + * and by the hardware. + * + * We need to pass the @profile and the @entrypoint, because at the + * moment the encoder base class, still doesn't have them assigned, + * and this function is meant to be called by the derived classes + * while they are configured. + * + * Returns: %TRUE if the number of slices is different than zero. + **/ +gboolean +gst_vaapi_encoder_ensure_num_slices (GstVaapiEncoder * encoder, + GstVaapiProfile profile, GstVaapiEntrypoint entrypoint, + guint media_max_slices, guint * num_slices) +{ + VAProfile va_profile; + VAEntrypoint va_entrypoint; + guint max_slices, num; + + va_profile = gst_vaapi_profile_get_va_profile (profile); + va_entrypoint = gst_vaapi_entrypoint_get_va_entrypoint (entrypoint); + + if (!gst_vaapi_get_config_attribute (encoder->display, va_profile, + va_entrypoint, VAConfigAttribEncMaxSlices, &max_slices)) { + *num_slices = 1; + return TRUE; + } + + num = *num_slices; + if (num > max_slices) + num = max_slices; + if (num > media_max_slices) + num = media_max_slices; + + if (num == 0) + return FALSE; + *num_slices = num; + return TRUE; +} + +/** + * gst_vaapi_encoder_ensure_max_num_ref_frames: + * @encoder: a #GstVaapiEncoder + * @profile: a #GstVaapiProfile + * @entrypoint: a #GstVaapiEntrypoint + * + * This function will query VAConfigAttribEncMaxRefFrames to get the + * maximum number of reference frames in the driver, + * for both the reference picture list 0 (bottom 16 bits) and + * the reference picture list 1 (top 16 bits). + * + * We need to pass the @profile and the @entrypoint, because at the + * moment the encoder base class, still doesn't have them assigned, + * and this function is meant to be called by the derived classes + * while they are configured. + * + * Returns: %TRUE if the number of reference frames is different than zero. + **/ +gboolean +gst_vaapi_encoder_ensure_max_num_ref_frames (GstVaapiEncoder * encoder, + GstVaapiProfile profile, GstVaapiEntrypoint entrypoint) +{ + VAProfile va_profile; + VAEntrypoint va_entrypoint; + guint max_ref_frames; + + va_profile = gst_vaapi_profile_get_va_profile (profile); + va_entrypoint = gst_vaapi_entrypoint_get_va_entrypoint (entrypoint); + + if (!gst_vaapi_get_config_attribute (encoder->display, va_profile, + va_entrypoint, VAConfigAttribEncMaxRefFrames, &max_ref_frames)) { + /* Set the default the number of reference frames */ + encoder->max_num_ref_frames_0 = 1; + encoder->max_num_ref_frames_1 = 0; + return TRUE; + } + + encoder->max_num_ref_frames_0 = max_ref_frames & 0xffff; + encoder->max_num_ref_frames_1 = (max_ref_frames >> 16) & 0xffff; + + return TRUE; +} + +/** + * gst_vaapi_encoder_ensure_tile_support: + * @encoder: a #GstVaapiEncoder + * @profile: a #GstVaapiProfile + * @entrypoint: a #GstVaapiEntrypoint + * + * This function will query VAConfigAttribEncTileSupport to check + * whether the encoder support tile. + * + * We need to pass the @profile and the @entrypoint, because at the + * moment the encoder base class, still doesn't have them assigned, + * and this function is meant to be called by the derived classes + * while they are configured. + * + * Returns: %TRUE if supported, %FALSE if not. + **/ +gboolean +gst_vaapi_encoder_ensure_tile_support (GstVaapiEncoder * encoder, + GstVaapiProfile profile, GstVaapiEntrypoint entrypoint) +{ + guint tile = 0; + +#if VA_CHECK_VERSION(1,0,1) + VAProfile va_profile; + VAEntrypoint va_entrypoint; + + va_profile = gst_vaapi_profile_get_va_profile (profile); + va_entrypoint = gst_vaapi_entrypoint_get_va_entrypoint (entrypoint); + + if (!gst_vaapi_get_config_attribute (encoder->display, va_profile, + va_entrypoint, VAConfigAttribEncTileSupport, &tile)) + return FALSE; +#endif + + return tile > 0; +} + +GstVaapiProfile +gst_vaapi_encoder_get_profile (GstVaapiEncoder * encoder) +{ + g_return_val_if_fail (encoder, GST_VAAPI_PROFILE_UNKNOWN); + + return encoder->profile; +} + +/* Get the entrypoint based on the tune option. */ +/** + * gst_vaapi_encoder_get_entrypoint: + * @encoder: a #GstVaapiEncoder + * @profile: a #GstVaapiProfile + * + * This function will return the valid entrypoint of the @encoder for + * @profile. If the low-power mode(tune option) is set, only LP + * entrypoints will be considered. If not, the first available entry + * point will be return. + * + * Returns: The #GstVaapiEntrypoint. + **/ +GstVaapiEntrypoint +gst_vaapi_encoder_get_entrypoint (GstVaapiEncoder * encoder, + GstVaapiProfile profile) +{ + /* XXX: The profile may not be the same with encoder->profile */ + + g_return_val_if_fail (encoder, GST_VAAPI_ENTRYPOINT_INVALID); + g_return_val_if_fail (profile != GST_VAAPI_PROFILE_UNKNOWN, + GST_VAAPI_ENTRYPOINT_INVALID); + + if (profile == GST_VAAPI_PROFILE_JPEG_BASELINE) + return GST_VAAPI_ENTRYPOINT_PICTURE_ENCODE; + + if (GST_VAAPI_ENCODER_TUNE (encoder) == GST_VAAPI_ENCODER_TUNE_LOW_POWER) { + if (gst_vaapi_display_has_encoder (GST_VAAPI_ENCODER_DISPLAY (encoder), + profile, GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP)) + return GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP; + } else { + /* If not set, choose the available one */ + if (gst_vaapi_display_has_encoder (GST_VAAPI_ENCODER_DISPLAY (encoder), + profile, GST_VAAPI_ENTRYPOINT_SLICE_ENCODE)) + return GST_VAAPI_ENTRYPOINT_SLICE_ENCODE; + + if (gst_vaapi_display_has_encoder (GST_VAAPI_ENCODER_DISPLAY (encoder), + profile, GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP)) + return GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP; + } + + return GST_VAAPI_ENTRYPOINT_INVALID; +} + +/** + * gst_vaapi_encoder_get_available_profiles: + * @encoder: a #GstVaapiEncoder + * + * Collect all supported #GstVaapiProfile of current @encoder's #GstVaapiCodec, + * and return them as a #GArray + * + * Returns: An #GArray of #GstVaapiProfile. + **/ +GArray * +gst_vaapi_encoder_get_available_profiles (GstVaapiEncoder * encoder) +{ + GstVaapiCodec codec; + GArray *all_profiles = NULL; + GArray *profiles = NULL; + GstVaapiProfile profile; + guint i; + + g_return_val_if_fail (encoder != NULL, 0); + + codec = GST_VAAPI_ENCODER_GET_CLASS (encoder)->class_data->codec; + + all_profiles = gst_vaapi_display_get_encode_profiles + (GST_VAAPI_ENCODER_DISPLAY (encoder)); + if (!all_profiles) + goto out; + + /* Add all supported profiles belong to current codec */ + profiles = g_array_new (FALSE, FALSE, sizeof (GstVaapiProfile)); + if (!profiles) + goto out; + + for (i = 0; i < all_profiles->len; i++) { + profile = g_array_index (all_profiles, GstVaapiProfile, i); + if (gst_vaapi_profile_get_codec (profile) == codec) + g_array_append_val (profiles, profile); + } + +out: + if (all_profiles) + g_array_unref (all_profiles); + if (profiles && profiles->len == 0) { + g_array_unref (profiles); + profiles = NULL; + } + + return profiles; +} + +/** Returns a GType for the #GstVaapiEncoderTune set */ +GType +gst_vaapi_encoder_tune_get_type (void) +{ + static gsize g_type = 0; + + static const GEnumValue encoder_tune_values[] = { + /* *INDENT-OFF* */ + { GST_VAAPI_ENCODER_TUNE_NONE, + "None", "none" }, + { GST_VAAPI_ENCODER_TUNE_HIGH_COMPRESSION, + "High compression", "high-compression" }, + { GST_VAAPI_ENCODER_TUNE_LOW_LATENCY, + "Low latency", "low-latency" }, + { GST_VAAPI_ENCODER_TUNE_LOW_POWER, + "Low power mode", "low-power" }, + { 0, NULL, NULL }, + /* *INDENT-ON* */ + }; + + if (g_once_init_enter (&g_type)) { + GType type = + g_enum_register_static ("GstVaapiEncoderTune", encoder_tune_values); + g_once_init_leave (&g_type, type); + } + return g_type; +} + +/** Returns a GType for the #GstVaapiEncoderMbbrc set */ +GType +gst_vaapi_encoder_mbbrc_get_type (void) +{ + static gsize g_type = 0; + + if (g_once_init_enter (&g_type)) { + static const GEnumValue encoder_mbbrc_values[] = { + {GST_VAAPI_ENCODER_MBBRC_AUTO, "Auto", "auto"}, + {GST_VAAPI_ENCODER_MBBRC_ON, "On", "on"}, + {GST_VAAPI_ENCODER_MBBRC_OFF, "Off", "off"}, + {0, NULL, NULL}, + }; + + GType type = + g_enum_register_static (g_intern_static_string ("GstVaapiEncoderMbbrc"), + encoder_mbbrc_values); + g_once_init_leave (&g_type, type); + } + return g_type; +} diff --git a/gst-libs/gst/vaapi/gstvaapiencoder.h b/gst-libs/gst/vaapi/gstvaapiencoder.h new file mode 100644 index 0000000000..6bc9887290 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder.h @@ -0,0 +1,202 @@ +/* + * gstvaapiencoder.h - VA encoder abstraction + * + * Copyright (C) 2013-2014 Intel Corporation + * Author: Wind Yuan + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_ENCODER_H +#define GST_VAAPI_ENCODER_H + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_ENCODER \ + (gst_vaapi_encoder_get_type ()) +#define GST_VAAPI_ENCODER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_ENCODER, GstVaapiEncoder)) +#define GST_VAAPI_IS_ENCODER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_ENCODER)) + +typedef struct _GstVaapiEncoder GstVaapiEncoder; + +GType +gst_vaapi_encoder_get_type (void) G_GNUC_CONST; + +/** + * GST_VAAPI_PARAM_ENCODER_EXPOSURE: (value 65536) + * + * This user defined flag is added when the internal encoder class + * wants to expose its property gparam spec to the according encode + * class. */ +#define GST_VAAPI_PARAM_ENCODER_EXPOSURE GST_PARAM_USER_SHIFT + +/** + * GstVaapiEncoderStatus: + * @GST_VAAPI_ENCODER_STATUS_SUCCESS: Success. + * @GST_VAAPI_ENCODER_STATUS_NO_SURFACE: No surface left to encode. + * @GST_VAAPI_ENCODER_STATUS_NO_BUFFER: No coded buffer left to hold + * the encoded picture. + * @GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN: Unknown error. + * @GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED: No memory left. + * @GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED: The requested + * operation failed to execute properly. e.g. invalid point in time to + * execute the operation. + * @GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_RATE_CONTROL: + * Unsupported rate control value. + * @GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE: Unsupported profile. + * @GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER: Invalid parameter. + * @GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_BUFFER: Invalid buffer. + * @GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_SURFACE: Invalid surface. + * @GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_HEADER: Invalid header. + * + * Set of #GstVaapiEncoder status codes. + */ +typedef enum +{ + GST_VAAPI_ENCODER_STATUS_SUCCESS = 0, + GST_VAAPI_ENCODER_STATUS_NO_SURFACE = 1, + GST_VAAPI_ENCODER_STATUS_NO_BUFFER = 2, + + GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN = -1, + GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED = -2, + GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED = -3, + GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_RATE_CONTROL = -4, + GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE = -5, + GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER = -100, + GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_BUFFER = -101, + GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_SURFACE = -102, + GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_HEADER = -103, +} GstVaapiEncoderStatus; + +/** + * GstVaapiEncoderTune: + * @GST_VAAPI_ENCODER_TUNE_NONE: No tuning option set. + * @GST_VAAPI_ENCODER_TUNE_HIGH_COMPRESSION: Tune for higher compression + * ratios, at the expense of lower compatibility at decoding time. + * @GST_VAAPI_ENCODER_TUNE_LOW_LATENCY: Tune for low latency decoding. + * @GST_VAAPI_ENCODER_TUNE_LOW_POWER: Tune encoder for low power / + * resources conditions. This can affect compression ratio or visual + * quality to match low power conditions. + * + * The set of tuning options for a #GstVaapiEncoder. By default, + * maximum compatibility for decoding is preferred, so the lowest + * coding tools are enabled. + */ +typedef enum { + GST_VAAPI_ENCODER_TUNE_NONE = 0, + GST_VAAPI_ENCODER_TUNE_HIGH_COMPRESSION, + GST_VAAPI_ENCODER_TUNE_LOW_LATENCY, + GST_VAAPI_ENCODER_TUNE_LOW_POWER, +} GstVaapiEncoderTune; + +/** + * GstVaapiEncoderMbbrc: + * @GST_VAAPI_ENCODER_MBBRC_AUTO: bitrate control auto + * @GST_VAAPI_ENCODER_MBBRC_ON: bitrate control on + * @GST_VAAPI_ENCODER_MBBRC_OFF: bitrate control off + * + * Values for the macroblock level bitrate control. + * + * This property values are only available for H264 and H265 (HEVC) + * encoders, when rate control is not Constant QP. + **/ +typedef enum { + GST_VAAPI_ENCODER_MBBRC_AUTO = 0, + GST_VAAPI_ENCODER_MBBRC_ON = 1, + GST_VAAPI_ENCODER_MBBRC_OFF = 2, +} GstVaapiEncoderMbbrc; + +GType +gst_vaapi_encoder_tune_get_type (void) G_GNUC_CONST; + +GType +gst_vaapi_encoder_mbbrc_get_type (void) G_GNUC_CONST; + +void +gst_vaapi_encoder_replace (GstVaapiEncoder ** old_encoder_ptr, + GstVaapiEncoder * new_encoder); + +GstVaapiEncoderStatus +gst_vaapi_encoder_get_codec_data (GstVaapiEncoder * encoder, + GstBuffer ** out_codec_data_ptr); + +GstVaapiEncoderStatus +gst_vaapi_encoder_set_codec_state (GstVaapiEncoder * encoder, + GstVideoCodecState * state); + +GstVaapiEncoderStatus +gst_vaapi_encoder_set_rate_control (GstVaapiEncoder * encoder, + GstVaapiRateControl rate_control); + +GstVaapiEncoderStatus +gst_vaapi_encoder_set_bitrate (GstVaapiEncoder * encoder, guint bitrate); + +GstVaapiEncoderStatus +gst_vaapi_encoder_set_target_percentage (GstVaapiEncoder * encoder, + guint target_percentage); + +GstVaapiEncoderStatus +gst_vaapi_encoder_put_frame (GstVaapiEncoder * encoder, + GstVideoCodecFrame * frame); + +GstVaapiEncoderStatus +gst_vaapi_encoder_set_keyframe_period (GstVaapiEncoder * encoder, + guint keyframe_period); + +GstVaapiEncoderStatus +gst_vaapi_encoder_set_tuning (GstVaapiEncoder * encoder, + GstVaapiEncoderTune tuning); + +GstVaapiEncoderStatus +gst_vaapi_encoder_set_quality_level (GstVaapiEncoder * encoder, + guint quality_level); + +GstVaapiEncoderStatus +gst_vaapi_encoder_set_trellis (GstVaapiEncoder * encoder, gboolean trellis); + +GstVaapiEncoderStatus +gst_vaapi_encoder_get_buffer_with_timeout (GstVaapiEncoder * encoder, + GstVaapiCodedBufferProxy ** out_codedbuf_proxy_ptr, guint64 timeout); + +GstVaapiEncoderStatus +gst_vaapi_encoder_flush (GstVaapiEncoder * encoder); + +GArray * +gst_vaapi_encoder_get_surface_attributes (GstVaapiEncoder * encoder, + GArray * profiles, gint * min_width, gint * min_height, + gint * max_width, gint * max_height, guint * mem_types); + +GstVaapiProfile +gst_vaapi_encoder_get_profile (GstVaapiEncoder * encoder); + +GstVaapiEntrypoint +gst_vaapi_encoder_get_entrypoint (GstVaapiEncoder * encoder, + GstVaapiProfile profile); + +GArray * +gst_vaapi_encoder_get_available_profiles (GstVaapiEncoder * encoder); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiEncoder, gst_object_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_ENCODER_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_h264.c b/gst-libs/gst/vaapi/gstvaapiencoder_h264.c new file mode 100644 index 0000000000..ad56cca2c4 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder_h264.c @@ -0,0 +1,4166 @@ +/* + * gstvaapiencoder_h264.c - H.264 encoder + * + * Copyright (C) 2012-2014 Intel Corporation + * Author: Wind Yuan + * Author: Gwenole Beauchesne + * + * 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 + */ + +#define GLIB_DISABLE_DEPRECATION_WARNINGS + +#include "sysdeps.h" +#include +#include +#include "gstvaapicompat.h" +#include "gstvaapiencoder_priv.h" +#include "gstvaapiencoder_h264.h" +#include "gstvaapiutils_h264.h" +#include "gstvaapiutils_h264_priv.h" +#include "gstvaapiutils_h26x_priv.h" +#include "gstvaapicodedbufferproxy_priv.h" +#include "gstvaapisurface.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + + +/* Define the maximum number of views supported */ +#define MAX_NUM_VIEWS 10 + +/* Define the maximum value for view-id */ +#define MAX_VIEW_ID 1023 + +/* Define default temporal levels */ +#define MIN_TEMPORAL_LEVELS 1 +#define MAX_TEMPORAL_LEVELS 4 + +/* Supported set of VA rate controls, within this implementation */ +#define SUPPORTED_RATECONTROLS \ + (GST_VAAPI_RATECONTROL_MASK (CQP) | \ + GST_VAAPI_RATECONTROL_MASK (CBR) | \ + GST_VAAPI_RATECONTROL_MASK (VBR) | \ + GST_VAAPI_RATECONTROL_MASK (VBR_CONSTRAINED) | \ + GST_VAAPI_RATECONTROL_MASK (ICQ) | \ + GST_VAAPI_RATECONTROL_MASK (QVBR)) + +/* Supported set of tuning options, within this implementation */ +#define SUPPORTED_TUNE_OPTIONS \ + (GST_VAAPI_ENCODER_TUNE_MASK (NONE) | \ + GST_VAAPI_ENCODER_TUNE_MASK (HIGH_COMPRESSION) | \ + GST_VAAPI_ENCODER_TUNE_MASK (LOW_POWER)) + +/* Supported set of VA packed headers, within this implementation */ +#define SUPPORTED_PACKED_HEADERS \ + (VA_ENC_PACKED_HEADER_SEQUENCE | \ + VA_ENC_PACKED_HEADER_PICTURE | \ + VA_ENC_PACKED_HEADER_SLICE | \ + VA_ENC_PACKED_HEADER_RAW_DATA | \ + VA_ENC_PACKED_HEADER_MISC) + +#define GST_H264_NAL_REF_IDC_NONE 0 +#define GST_H264_NAL_REF_IDC_LOW 1 +#define GST_H264_NAL_REF_IDC_MEDIUM 2 +#define GST_H264_NAL_REF_IDC_HIGH 3 + +typedef enum +{ + GST_VAAPI_ENCODER_H264_COMPLIANCE_MODE_STRICT = 0, + GST_VAAPI_ENCODER_H264_COMPLIANCE_MODE_RESTRICT_CODED_BUFFER_ALLOC = 1, +} GstVaapiEncoderH264ComplianceMode; + +static GType +gst_vaapi_encoder_h264_compliance_mode_type (void) +{ + static GType gtype = 0; + + if (gtype == 0) { + static const GEnumValue values[] = { + {GST_VAAPI_ENCODER_H264_COMPLIANCE_MODE_STRICT, + "Strict compliance to the H264 Specification ", + "strict"}, + /* The main intention is to reduce the CodedBuffer Size allocation. + * This will help to get better performance in some of the Intel + * platforms which has LLC restirictions */ + {GST_VAAPI_ENCODER_H264_COMPLIANCE_MODE_RESTRICT_CODED_BUFFER_ALLOC, + "Restrict the allocation size of coded-buffer", + "restrict-buf-alloc"}, + {0, NULL, NULL}, + }; + + gtype = + g_enum_register_static ("GstVaapiEncoderH264ComplianceMode", values); + } + return gtype; +} + +typedef enum +{ + GST_VAAPI_ENCODER_H264_PREDICTION_DEFAULT, + GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_P, + GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_B +} GstVaapiEncoderH264PredictionType; + +static GType +gst_vaapi_encoder_h264_prediction_type (void) +{ + static GType gtype = 0; + + if (gtype == 0) { + static const GEnumValue values[] = { + {GST_VAAPI_ENCODER_H264_PREDICTION_DEFAULT, + "Default encode, prev/next frame as ref ", + "default"}, + {GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_P, + "Hierarchical P frame encode", + "hierarchical-p"}, + {GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_B, + "Hierarchical B frame encode", + "hierarchical-b"}, + {0, NULL, NULL}, + }; + + gtype = + g_enum_register_static ("GstVaapiEncoderH264PredictionType", values); + } + return gtype; +} + +/* only for internal usage, values won't be equal to actual payload type */ +typedef enum +{ + GST_VAAPI_H264_SEI_UNKNOWN = 0, + GST_VAAPI_H264_SEI_BUF_PERIOD = (1 << 0), + GST_VAAPI_H264_SEI_PIC_TIMING = (1 << 1) +} GstVaapiH264SeiPayloadType; + +typedef struct +{ + GstVaapiSurfaceProxy *pic; + guint poc; + guint frame_num; + guint temporal_id; +} GstVaapiEncoderH264Ref; + +typedef enum +{ + GST_VAAPI_ENC_H264_REORD_NONE = 0, + GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES = 1, + GST_VAAPI_ENC_H264_REORD_WAIT_FRAMES = 2 +} GstVaapiEncH264ReorderState; + +typedef struct _GstVaapiH264ViewRefPool +{ + GQueue ref_list; + guint max_ref_frames; + guint max_reflist0_count; + guint max_reflist1_count; +} GstVaapiH264ViewRefPool; + +typedef struct _GstVaapiH264ViewReorderPool +{ + GQueue reorder_frame_list; + guint reorder_state; + guint frame_index; + guint frame_count; /* monotonically increasing with in every idr period */ + guint cur_frame_num; + guint cur_present_index; + gboolean prev_frame_is_ref; /* previous frame is ref or not */ +} GstVaapiH264ViewReorderPool; + +static inline gboolean +_poc_greater_than (guint poc1, guint poc2, guint max_poc) +{ + return (((poc1 - poc2) & (max_poc - 1)) < max_poc / 2); +} + +/* Get slice_type value for H.264 specification */ +static guint8 +h264_get_slice_type (GstVaapiPictureType type) +{ + switch (type) { + case GST_VAAPI_PICTURE_TYPE_I: + return GST_H264_I_SLICE; + case GST_VAAPI_PICTURE_TYPE_P: + return GST_H264_P_SLICE; + case GST_VAAPI_PICTURE_TYPE_B: + return GST_H264_B_SLICE; + default: + break; + } + return -1; +} + +/* Get log2_max_frame_num value for H.264 specification */ +static guint +h264_get_log2_max_frame_num (guint num) +{ + guint ret = 0; + + while (num) { + ++ret; + num >>= 1; + } + if (ret <= 4) + ret = 4; + else if (ret > 10) + ret = 10; + /* must be greater than 4 */ + return ret; +} + +/* Determines the cpbBrNalFactor based on the supplied profile */ +static guint +h264_get_cpb_nal_factor (GstVaapiProfile profile) +{ + guint f; + + /* Table A-2 */ + switch (profile) { + case GST_VAAPI_PROFILE_H264_HIGH: + f = 1500; + break; + case GST_VAAPI_PROFILE_H264_HIGH10: + f = 3600; + break; + case GST_VAAPI_PROFILE_H264_HIGH_422: + case GST_VAAPI_PROFILE_H264_HIGH_444: + f = 4800; + break; + case GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH: + case GST_VAAPI_PROFILE_H264_STEREO_HIGH: + f = 1500; /* H.10.2.1 (r) */ + break; + default: + f = 1200; + break; + } + return f; +} + +/* Write the NAL unit header */ +static gboolean +bs_write_nal_header (GstBitWriter * bs, guint32 nal_ref_idc, + guint32 nal_unit_type) +{ + WRITE_UINT32 (bs, 0, 1); + WRITE_UINT32 (bs, nal_ref_idc, 2); + WRITE_UINT32 (bs, nal_unit_type, 5); + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write NAL unit header"); + return FALSE; + } +} + +/* Write the MVC NAL unit header extension */ +static gboolean +bs_write_nal_header_mvc_extension (GstBitWriter * bs, + GstVaapiEncPicture * picture, guint32 view_id) +{ + guint32 svc_extension_flag = 0; + guint32 non_idr_flag = 1; + guint32 priority_id = 0; + guint32 temporal_id = 0; + guint32 anchor_pic_flag = 0; + guint32 inter_view_flag = 0; + + if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture)) + non_idr_flag = 0; + + if (picture->type == GST_VAAPI_PICTURE_TYPE_I) + anchor_pic_flag = 1; + /* svc_extension_flag == 0 for mvc stream */ + WRITE_UINT32 (bs, svc_extension_flag, 1); + + WRITE_UINT32 (bs, non_idr_flag, 1); + WRITE_UINT32 (bs, priority_id, 6); + WRITE_UINT32 (bs, view_id, 10); + WRITE_UINT32 (bs, temporal_id, 3); + WRITE_UINT32 (bs, anchor_pic_flag, 1); + WRITE_UINT32 (bs, inter_view_flag, 1); + WRITE_UINT32 (bs, 1, 1); + + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write NAL unit header"); + return FALSE; + } +} + +/* Write the NAL unit trailing bits */ +static gboolean +bs_write_trailing_bits (GstBitWriter * bs) +{ + if (!gst_bit_writer_put_bits_uint32 (bs, 1, 1)) + goto bs_error; + gst_bit_writer_align_bytes_unchecked (bs, 0); + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write NAL unit trailing bits"); + return FALSE; + } +} + +/* Write an SPS NAL unit */ +static gboolean +bs_write_sps_data (GstBitWriter * bs, + const VAEncSequenceParameterBufferH264 * seq_param, GstVaapiProfile profile, + GstVaapiRateControl rate_control, const VAEncMiscParameterHRD * hrd_params) +{ + guint8 profile_idc; + guint32 constraint_set0_flag, constraint_set1_flag; + guint32 constraint_set2_flag, constraint_set3_flag; + guint32 gaps_in_frame_num_value_allowed_flag = 0; // ?? + gboolean nal_hrd_parameters_present_flag; + + guint32 b_qpprime_y_zero_transform_bypass = 0; + guint32 residual_color_transform_flag = 0; + guint32 cbr_flag = rate_control == GST_VAAPI_RATECONTROL_CBR ? 1 : 0; + guint32 pic_height_in_map_units = + (seq_param->seq_fields.bits.frame_mbs_only_flag ? + seq_param->picture_height_in_mbs : seq_param->picture_height_in_mbs / 2); + guint32 mb_adaptive_frame_field = + !seq_param->seq_fields.bits.frame_mbs_only_flag; + guint32 i = 0; + + profile_idc = gst_vaapi_utils_h264_get_profile_idc (profile); + constraint_set0_flag = /* A.2.1 (baseline profile constraints) */ + profile == GST_VAAPI_PROFILE_H264_BASELINE || + profile == GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE; + constraint_set1_flag = /* A.2.2 (main profile constraints) */ + profile == GST_VAAPI_PROFILE_H264_MAIN || + profile == GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE; + constraint_set2_flag = 0; + constraint_set3_flag = 0; + + /* profile_idc */ + WRITE_UINT32 (bs, profile_idc, 8); + /* constraint_set0_flag */ + WRITE_UINT32 (bs, constraint_set0_flag, 1); + /* constraint_set1_flag */ + WRITE_UINT32 (bs, constraint_set1_flag, 1); + /* constraint_set2_flag */ + WRITE_UINT32 (bs, constraint_set2_flag, 1); + /* constraint_set3_flag */ + WRITE_UINT32 (bs, constraint_set3_flag, 1); + /* reserved_zero_4bits */ + WRITE_UINT32 (bs, 0, 4); + /* level_idc */ + WRITE_UINT32 (bs, seq_param->level_idc, 8); + /* seq_parameter_set_id */ + WRITE_UE (bs, seq_param->seq_parameter_set_id); + + if (profile == GST_VAAPI_PROFILE_H264_HIGH || + profile == GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH || + profile == GST_VAAPI_PROFILE_H264_STEREO_HIGH) { + /* for high profile */ + /* chroma_format_idc = 1, 4:2:0 */ + WRITE_UE (bs, seq_param->seq_fields.bits.chroma_format_idc); + if (3 == seq_param->seq_fields.bits.chroma_format_idc) { + WRITE_UINT32 (bs, residual_color_transform_flag, 1); + } + /* bit_depth_luma_minus8 */ + WRITE_UE (bs, seq_param->bit_depth_luma_minus8); + /* bit_depth_chroma_minus8 */ + WRITE_UE (bs, seq_param->bit_depth_chroma_minus8); + /* b_qpprime_y_zero_transform_bypass */ + WRITE_UINT32 (bs, b_qpprime_y_zero_transform_bypass, 1); + + /* seq_scaling_matrix_present_flag */ + g_assert (seq_param->seq_fields.bits.seq_scaling_matrix_present_flag == 0); + WRITE_UINT32 (bs, + seq_param->seq_fields.bits.seq_scaling_matrix_present_flag, 1); + +#if 0 + if (seq_param->seq_fields.bits.seq_scaling_matrix_present_flag) { + for (i = 0; + i < (seq_param->seq_fields.bits.chroma_format_idc != 3 ? 8 : 12); + i++) { + gst_bit_writer_put_bits_uint8 (bs, + seq_param->seq_fields.bits.seq_scaling_list_present_flag, 1); + if (seq_param->seq_fields.bits.seq_scaling_list_present_flag) { + g_assert (0); + /* FIXME, need write scaling list if seq_scaling_matrix_present_flag ==1 */ + } + } + } +#endif + } + + /* log2_max_frame_num_minus4 */ + WRITE_UE (bs, seq_param->seq_fields.bits.log2_max_frame_num_minus4); + /* pic_order_cnt_type */ + WRITE_UE (bs, seq_param->seq_fields.bits.pic_order_cnt_type); + + if (seq_param->seq_fields.bits.pic_order_cnt_type == 0) { + /* log2_max_pic_order_cnt_lsb_minus4 */ + WRITE_UE (bs, seq_param->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4); + } else if (seq_param->seq_fields.bits.pic_order_cnt_type == 1) { + g_assert (0 && "only POC type 0 is supported"); + WRITE_UINT32 (bs, + seq_param->seq_fields.bits.delta_pic_order_always_zero_flag, 1); + WRITE_SE (bs, seq_param->offset_for_non_ref_pic); + WRITE_SE (bs, seq_param->offset_for_top_to_bottom_field); + WRITE_UE (bs, seq_param->num_ref_frames_in_pic_order_cnt_cycle); + for (i = 0; i < seq_param->num_ref_frames_in_pic_order_cnt_cycle; i++) { + WRITE_SE (bs, seq_param->offset_for_ref_frame[i]); + } + } + + /* num_ref_frames */ + WRITE_UE (bs, seq_param->max_num_ref_frames); + /* gaps_in_frame_num_value_allowed_flag */ + WRITE_UINT32 (bs, gaps_in_frame_num_value_allowed_flag, 1); + + /* pic_width_in_mbs_minus1 */ + WRITE_UE (bs, seq_param->picture_width_in_mbs - 1); + /* pic_height_in_map_units_minus1 */ + WRITE_UE (bs, pic_height_in_map_units - 1); + /* frame_mbs_only_flag */ + WRITE_UINT32 (bs, seq_param->seq_fields.bits.frame_mbs_only_flag, 1); + + if (!seq_param->seq_fields.bits.frame_mbs_only_flag) { //ONLY mbs + g_assert (0 && "only progressive frames encoding is supported"); + WRITE_UINT32 (bs, mb_adaptive_frame_field, 1); + } + + /* direct_8x8_inference_flag */ + WRITE_UINT32 (bs, 0, 1); + /* frame_cropping_flag */ + WRITE_UINT32 (bs, seq_param->frame_cropping_flag, 1); + + if (seq_param->frame_cropping_flag) { + /* frame_crop_left_offset */ + WRITE_UE (bs, seq_param->frame_crop_left_offset); + /* frame_crop_right_offset */ + WRITE_UE (bs, seq_param->frame_crop_right_offset); + /* frame_crop_top_offset */ + WRITE_UE (bs, seq_param->frame_crop_top_offset); + /* frame_crop_bottom_offset */ + WRITE_UE (bs, seq_param->frame_crop_bottom_offset); + } + + /* vui_parameters_present_flag */ + WRITE_UINT32 (bs, seq_param->vui_parameters_present_flag, 1); + if (seq_param->vui_parameters_present_flag) { + /* aspect_ratio_info_present_flag */ + WRITE_UINT32 (bs, + seq_param->vui_fields.bits.aspect_ratio_info_present_flag, 1); + if (seq_param->vui_fields.bits.aspect_ratio_info_present_flag) { + WRITE_UINT32 (bs, seq_param->aspect_ratio_idc, 8); + if (seq_param->aspect_ratio_idc == 0xFF) { + WRITE_UINT32 (bs, seq_param->sar_width, 16); + WRITE_UINT32 (bs, seq_param->sar_height, 16); + } + } + + /* overscan_info_present_flag */ + WRITE_UINT32 (bs, 0, 1); + /* video_signal_type_present_flag */ + WRITE_UINT32 (bs, 0, 1); + /* chroma_loc_info_present_flag */ + WRITE_UINT32 (bs, 0, 1); + + /* timing_info_present_flag */ + WRITE_UINT32 (bs, seq_param->vui_fields.bits.timing_info_present_flag, 1); + if (seq_param->vui_fields.bits.timing_info_present_flag) { + WRITE_UINT32 (bs, seq_param->num_units_in_tick, 32); + WRITE_UINT32 (bs, seq_param->time_scale, 32); + WRITE_UINT32 (bs, 1, 1); /* fixed_frame_rate_flag */ + } + + /* nal_hrd_parameters_present_flag */ + nal_hrd_parameters_present_flag = seq_param->bits_per_second > 0; + WRITE_UINT32 (bs, nal_hrd_parameters_present_flag, 1); + if (nal_hrd_parameters_present_flag) { + /* hrd_parameters */ + /* cpb_cnt_minus1 */ + WRITE_UE (bs, 0); + WRITE_UINT32 (bs, SX_BITRATE - 6, 4); /* bit_rate_scale */ + WRITE_UINT32 (bs, SX_CPB_SIZE - 4, 4); /* cpb_size_scale */ + + for (i = 0; i < 1; ++i) { + /* bit_rate_value_minus1[0] */ + WRITE_UE (bs, (seq_param->bits_per_second >> SX_BITRATE) - 1); + /* cpb_size_value_minus1[0] */ + WRITE_UE (bs, (hrd_params->buffer_size >> SX_CPB_SIZE) - 1); + /* cbr_flag[0] */ + WRITE_UINT32 (bs, cbr_flag, 1); + } + /* initial_cpb_removal_delay_length_minus1 */ + WRITE_UINT32 (bs, 23, 5); + /* cpb_removal_delay_length_minus1 */ + WRITE_UINT32 (bs, 23, 5); + /* dpb_output_delay_length_minus1 */ + WRITE_UINT32 (bs, 23, 5); + /* time_offset_length */ + WRITE_UINT32 (bs, 23, 5); + } + + /* vcl_hrd_parameters_present_flag */ + WRITE_UINT32 (bs, 0, 1); + + if (nal_hrd_parameters_present_flag + || 0 /*vcl_hrd_parameters_present_flag */ ) { + /* low_delay_hrd_flag */ + WRITE_UINT32 (bs, 0, 1); + } + /* pic_struct_present_flag */ + WRITE_UINT32 (bs, 1, 1); + /* bs_restriction_flag */ + WRITE_UINT32 (bs, 0, 1); + } + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write SPS NAL unit"); + return FALSE; + } +} + +static gboolean +bs_write_sps (GstBitWriter * bs, + const VAEncSequenceParameterBufferH264 * seq_param, GstVaapiProfile profile, + GstVaapiRateControl rate_control, const VAEncMiscParameterHRD * hrd_params) +{ + if (!bs_write_sps_data (bs, seq_param, profile, rate_control, hrd_params)) + return FALSE; + + /* rbsp_trailing_bits */ + bs_write_trailing_bits (bs); + + return FALSE; +} + +static gboolean +bs_write_subset_sps (GstBitWriter * bs, + const VAEncSequenceParameterBufferH264 * seq_param, GstVaapiProfile profile, + GstVaapiRateControl rate_control, guint num_views, guint16 * view_ids, + const VAEncMiscParameterHRD * hrd_params) +{ + guint32 i, j, k; + + if (!bs_write_sps_data (bs, seq_param, profile, rate_control, hrd_params)) + return FALSE; + + if (profile == GST_VAAPI_PROFILE_H264_STEREO_HIGH || + profile == GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH) { + guint32 num_views_minus1, num_level_values_signalled_minus1; + + num_views_minus1 = num_views - 1; + g_assert (num_views_minus1 < 1024); + + /* bit equal to one */ + WRITE_UINT32 (bs, 1, 1); + + WRITE_UE (bs, num_views_minus1); + + for (i = 0; i <= num_views_minus1; i++) + WRITE_UE (bs, view_ids[i]); + + for (i = 1; i <= num_views_minus1; i++) { + guint32 num_anchor_refs_l0 = 0; + guint32 num_anchor_refs_l1 = 0; + + WRITE_UE (bs, num_anchor_refs_l0); + for (j = 0; j < num_anchor_refs_l0; j++) + WRITE_UE (bs, 0); + + WRITE_UE (bs, num_anchor_refs_l1); + for (j = 0; j < num_anchor_refs_l1; j++) + WRITE_UE (bs, 0); + } + + for (i = 1; i <= num_views_minus1; i++) { + guint32 num_non_anchor_refs_l0 = 0; + guint32 num_non_anchor_refs_l1 = 0; + + WRITE_UE (bs, num_non_anchor_refs_l0); + for (j = 0; j < num_non_anchor_refs_l0; j++) + WRITE_UE (bs, 0); + + WRITE_UE (bs, num_non_anchor_refs_l1); + for (j = 0; j < num_non_anchor_refs_l1; j++) + WRITE_UE (bs, 0); + } + + /* num level values signalled minus1 */ + num_level_values_signalled_minus1 = 0; + g_assert (num_level_values_signalled_minus1 < 64); + WRITE_UE (bs, num_level_values_signalled_minus1); + + for (i = 0; i <= num_level_values_signalled_minus1; i++) { + guint16 num_applicable_ops_minus1 = 0; + g_assert (num_applicable_ops_minus1 < 1024); + + WRITE_UINT32 (bs, seq_param->level_idc, 8); + WRITE_UE (bs, num_applicable_ops_minus1); + + for (j = 0; j <= num_applicable_ops_minus1; j++) { + guint8 temporal_id = 0; + guint16 num_target_views_minus1 = 1; + + WRITE_UINT32 (bs, temporal_id, 3); + WRITE_UE (bs, num_target_views_minus1); + + for (k = 0; k <= num_target_views_minus1; k++) + WRITE_UE (bs, k); + + WRITE_UE (bs, num_views_minus1); + } + } + + /* mvc_vui_parameters_present_flag */ + WRITE_UINT32 (bs, 0, 1); + } + + /* additional_extension2_flag */ + WRITE_UINT32 (bs, 0, 1); + + /* rbsp_trailing_bits */ + bs_write_trailing_bits (bs); + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write subset SPS NAL unit"); + return FALSE; + } + return FALSE; +} + +/* Write a PPS NAL unit */ +static gboolean +bs_write_pps (GstBitWriter * bs, + const VAEncPictureParameterBufferH264 * pic_param, GstVaapiProfile profile) +{ + guint32 num_slice_groups_minus1 = 0; + guint32 pic_init_qs_minus26 = 0; + guint32 redundant_pic_cnt_present_flag = 0; + + /* pic_parameter_set_id */ + WRITE_UE (bs, pic_param->pic_parameter_set_id); + /* seq_parameter_set_id */ + WRITE_UE (bs, pic_param->seq_parameter_set_id); + /* entropy_coding_mode_flag */ + WRITE_UINT32 (bs, pic_param->pic_fields.bits.entropy_coding_mode_flag, 1); + /* pic_order_present_flag */ + WRITE_UINT32 (bs, pic_param->pic_fields.bits.pic_order_present_flag, 1); + /* slice_groups-1 */ + WRITE_UE (bs, num_slice_groups_minus1); + + if (num_slice_groups_minus1 > 0) { + /*FIXME*/ g_assert (0 && "unsupported arbitrary slice ordering (ASO)"); + } + WRITE_UE (bs, pic_param->num_ref_idx_l0_active_minus1); + WRITE_UE (bs, pic_param->num_ref_idx_l1_active_minus1); + WRITE_UINT32 (bs, pic_param->pic_fields.bits.weighted_pred_flag, 1); + WRITE_UINT32 (bs, pic_param->pic_fields.bits.weighted_bipred_idc, 2); + /* pic_init_qp_minus26 */ + WRITE_SE (bs, pic_param->pic_init_qp - 26); + /* pic_init_qs_minus26 */ + WRITE_SE (bs, pic_init_qs_minus26); + /* chroma_qp_index_offset */ + WRITE_SE (bs, pic_param->chroma_qp_index_offset); + + WRITE_UINT32 (bs, + pic_param->pic_fields.bits.deblocking_filter_control_present_flag, 1); + WRITE_UINT32 (bs, pic_param->pic_fields.bits.constrained_intra_pred_flag, 1); + WRITE_UINT32 (bs, redundant_pic_cnt_present_flag, 1); + + /* more_rbsp_data */ + if (profile == GST_VAAPI_PROFILE_H264_HIGH + || profile == GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH + || profile == GST_VAAPI_PROFILE_H264_STEREO_HIGH) { + WRITE_UINT32 (bs, pic_param->pic_fields.bits.transform_8x8_mode_flag, 1); + WRITE_UINT32 (bs, + pic_param->pic_fields.bits.pic_scaling_matrix_present_flag, 1); + if (pic_param->pic_fields.bits.pic_scaling_matrix_present_flag) { + g_assert (0 && "unsupported scaling lists"); + /* FIXME */ + /* + for (i = 0; i < + (6+(-( (chroma_format_idc ! = 3) ? 2 : 6) * -pic_param->pic_fields.bits.transform_8x8_mode_flag)); + i++) { + gst_bit_writer_put_bits_uint8(bs, pic_param->pic_fields.bits.pic_scaling_list_present_flag, 1); + } + */ + } + WRITE_SE (bs, pic_param->second_chroma_qp_index_offset); + } + + /* rbsp_trailing_bits */ + bs_write_trailing_bits (bs); + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write PPS NAL unit"); + return FALSE; + } +} + +/* ------------------------------------------------------------------------- */ +/* --- H.264 Encoder --- */ +/* ------------------------------------------------------------------------- */ + +struct _GstVaapiEncoderH264 +{ + GstVaapiEncoder parent_instance; + + GstVaapiProfile profile; + GstVaapiLevelH264 level; + GstVaapiEntrypoint entrypoint; + guint8 profile_idc; + guint8 max_profile_idc; + guint8 hw_max_profile_idc; + guint8 level_idc; + guint32 idr_period; + guint32 ip_period; + guint32 init_qp; + guint32 min_qp; + guint32 max_qp; + guint32 qp_i; + guint32 qp_ip; + guint32 qp_ib; + guint32 num_slices; + guint32 num_bframes; + guint32 mb_width; + guint32 mb_height; + guint32 quality_factor; + gboolean use_cabac; + gboolean use_dct8x8; + guint temporal_levels; /* Number of temporal levels */ + guint temporal_level_div[MAX_TEMPORAL_LEVELS]; /* to find the temporal id */ + guint prediction_type; + guint abs_diff_pic_num_list0; + guint abs_diff_pic_num_list1; + GstClockTime cts_offset; + gboolean config_changed; + + /* frame, poc */ + guint32 max_frame_num; + guint32 log2_max_frame_num; + guint32 max_pic_order_cnt; + guint32 log2_max_pic_order_cnt; + guint32 idr_num; + guint8 pic_order_cnt_type; + guint8 delta_pic_order_always_zero_flag; + guint num_ref_frames; + + GstBuffer *sps_data; + GstBuffer *subset_sps_data; + GstBuffer *pps_data; + + guint bitrate_bits; // bitrate (bits) + guint cpb_length; // length of CPB buffer (ms) + guint cpb_length_bits; // length of CPB buffer (bits) + GstVaapiEncoderMbbrc mbbrc; // macroblock bitrate control + + /* MVC */ + gboolean is_mvc; + guint32 view_idx; /* View Order Index (VOIdx) */ + guint32 num_views; + guint16 view_ids[MAX_NUM_VIEWS]; + GstVaapiH264ViewRefPool ref_pools[MAX_NUM_VIEWS]; + GstVaapiH264ViewReorderPool reorder_pools[MAX_NUM_VIEWS]; + + gboolean use_aud; + + /* Complance mode */ + GstVaapiEncoderH264ComplianceMode compliance_mode; + guint min_cr; // Minimum Compression Ratio (A.3.1) +}; + +/* Write a SEI buffering period payload */ +static gboolean +bs_write_sei_buf_period (GstBitWriter * bs, + GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture) +{ + guint initial_cpb_removal_delay = 0; + guint initial_cpb_removal_delay_offset = 0; + guint8 initial_cpb_removal_delay_length = 24; + + /* sequence_parameter_set_id */ + WRITE_UE (bs, encoder->view_idx); + /* NalHrdBpPresentFlag == TRUE */ + /* cpb_cnt_minus1 == 0 */ + + /* decoding should start when the CPB fullness reaches half of cpb size + * initial_cpb_remvoal_delay = (((cpb_length / 2) * 90000) / 1000) */ + initial_cpb_removal_delay = encoder->cpb_length * 45; + + /* initial_cpb_remvoal_dealy */ + WRITE_UINT32 (bs, initial_cpb_removal_delay, + initial_cpb_removal_delay_length); + + /* initial_cpb_removal_delay_offset */ + WRITE_UINT32 (bs, initial_cpb_removal_delay_offset, + initial_cpb_removal_delay_length); + + /* VclHrdBpPresentFlag == FALSE */ + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write Buffering Period SEI message"); + return FALSE; + } +} + +/* Write a SEI picture timing payload */ +static gboolean +bs_write_sei_pic_timing (GstBitWriter * bs, + GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture) +{ + GstVaapiH264ViewReorderPool *reorder_pool = NULL; + guint cpb_removal_delay; + guint dpb_output_delay; + guint8 cpb_removal_delay_length = 24; + guint8 dpb_output_delay_length = 24; + guint pic_struct = 0; + guint clock_timestamp_flag = 0; + + reorder_pool = &encoder->reorder_pools[encoder->view_idx]; + if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture)) + reorder_pool->frame_count = 0; + else + reorder_pool->frame_count++; + + /* clock-tick = no_units_in_tick/time_scale (C-1) + * time_scale = FPS_N * 2 (E.2.1) + * num_units_in_tick = FPS_D (E.2.1) + * frame_duration = clock-tick * 2 + * so removal time for one frame is 2 clock-ticks. + * but adding a tolerance of one frame duration, + * which is 2 more clock-ticks */ + cpb_removal_delay = (reorder_pool->frame_count * 2 + 2); + + if (picture->type == GST_VAAPI_PICTURE_TYPE_B) + dpb_output_delay = 0; + else + dpb_output_delay = picture->poc - reorder_pool->frame_count * 2; + + /* CpbDpbDelaysPresentFlag == 1 */ + WRITE_UINT32 (bs, cpb_removal_delay, cpb_removal_delay_length); + WRITE_UINT32 (bs, dpb_output_delay, dpb_output_delay_length); + + /* pic_struct_present_flag == 1 */ + /* pic_struct */ + WRITE_UINT32 (bs, pic_struct, 4); + /* clock_timestamp_flag */ + WRITE_UINT32 (bs, clock_timestamp_flag, 1); + + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write Picture Timing SEI message"); + return FALSE; + } +} + +/* Write a Slice NAL unit */ +static gboolean +bs_write_slice (GstBitWriter * bs, + const VAEncSliceParameterBufferH264 * slice_param, + GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture) +{ + const VAEncPictureParameterBufferH264 *const pic_param = picture->param; + guint32 field_pic_flag = 0; + guint32 ref_pic_list_modification_flag_l0 = 0; + guint32 ref_pic_list_modification_flag_l1 = 0; + guint32 no_output_of_prior_pics_flag = 0; + guint32 long_term_reference_flag = 0; + guint32 adaptive_ref_pic_marking_mode_flag = 0; + + /* first_mb_in_slice */ + WRITE_UE (bs, slice_param->macroblock_address); + /* slice_type */ + WRITE_UE (bs, slice_param->slice_type); + /* pic_parameter_set_id */ + WRITE_UE (bs, slice_param->pic_parameter_set_id); + /* frame_num */ + WRITE_UINT32 (bs, picture->frame_num, encoder->log2_max_frame_num); + + /* XXX: only frames (i.e. non-interlaced) are supported for now */ + /* frame_mbs_only_flag == 0 */ + + /* idr_pic_id */ + if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture)) + WRITE_UE (bs, slice_param->idr_pic_id); + + /* XXX: only POC type 0 is supported */ + if (!encoder->pic_order_cnt_type) { + WRITE_UINT32 (bs, slice_param->pic_order_cnt_lsb, + encoder->log2_max_pic_order_cnt); + /* bottom_field_pic_order_in_frame_present_flag is FALSE */ + if (pic_param->pic_fields.bits.pic_order_present_flag && !field_pic_flag) + WRITE_SE (bs, slice_param->delta_pic_order_cnt_bottom); + } else if (encoder->pic_order_cnt_type == 1 && + !encoder->delta_pic_order_always_zero_flag) { + WRITE_SE (bs, slice_param->delta_pic_order_cnt[0]); + if (pic_param->pic_fields.bits.pic_order_present_flag && !field_pic_flag) + WRITE_SE (bs, slice_param->delta_pic_order_cnt[1]); + } + /* redundant_pic_cnt_present_flag is FALSE, no redundant coded pictures */ + + /* only works for B-frames */ + if (slice_param->slice_type == 1) + WRITE_UINT32 (bs, slice_param->direct_spatial_mv_pred_flag, 1); + + /* not supporting SP slices */ + if (slice_param->slice_type == 0 || slice_param->slice_type == 1) { + WRITE_UINT32 (bs, slice_param->num_ref_idx_active_override_flag, 1); + if (slice_param->num_ref_idx_active_override_flag) { + WRITE_UE (bs, slice_param->num_ref_idx_l0_active_minus1); + if (slice_param->slice_type == 1) + WRITE_UE (bs, slice_param->num_ref_idx_l1_active_minus1); + } + } + + if ((slice_param->slice_type != 2) && (slice_param->slice_type != 4)) { + if ((encoder->prediction_type != GST_VAAPI_ENCODER_H264_PREDICTION_DEFAULT) + && (encoder->abs_diff_pic_num_list0 > 1)) + ref_pic_list_modification_flag_l0 = 1; + + WRITE_UINT32 (bs, ref_pic_list_modification_flag_l0, 1); + + if (ref_pic_list_modification_flag_l0) { + /*modification_of_pic_num_idc */ + WRITE_UE (bs, 0); + /* abs_diff_pic_num_minus1 */ + WRITE_UE (bs, encoder->abs_diff_pic_num_list0 - 1); + /*modification_of_pic_num_idc */ + WRITE_UE (bs, 3); + } + } + + /* B-frame */ + if (slice_param->slice_type == 1) { + if ((encoder->prediction_type == + GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_B) + && (encoder->abs_diff_pic_num_list1 > 1)) + ref_pic_list_modification_flag_l1 = 1; + + WRITE_UINT32 (bs, ref_pic_list_modification_flag_l1, 1); + + if (ref_pic_list_modification_flag_l1) { + /*modification_of_pic_num_idc */ + WRITE_UE (bs, 0); + /* abs_diff_pic_num_minus1 */ + WRITE_UE (bs, encoder->abs_diff_pic_num_list1 - 1); + /*modification_of_pic_num_idc */ + WRITE_UE (bs, 3); + } + } + + /* we have: weighted_pred_flag == FALSE and */ + /* : weighted_bipred_idc == FALSE */ + if ((pic_param->pic_fields.bits.weighted_pred_flag && + (slice_param->slice_type == 0)) || + ((pic_param->pic_fields.bits.weighted_bipred_idc == 1) && + (slice_param->slice_type == 1))) { + /* XXXX: add pred_weight_table() */ + } + + /* dec_ref_pic_marking() */ + if (GST_VAAPI_ENC_PICTURE_IS_REFRENCE (picture)) { + if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture)) { + /* no_output_of_prior_pics_flag = 0 */ + WRITE_UINT32 (bs, no_output_of_prior_pics_flag, 1); + /* long_term_reference_flag = 0 */ + WRITE_UINT32 (bs, long_term_reference_flag, 1); + } else { + /* only sliding_window reference picture marking mode is supported */ + /* adpative_ref_pic_marking_mode_flag = 0 */ + WRITE_UINT32 (bs, adaptive_ref_pic_marking_mode_flag, 1); + } + } + + /* cabac_init_idc */ + if (pic_param->pic_fields.bits.entropy_coding_mode_flag && + slice_param->slice_type != 2) + WRITE_UE (bs, slice_param->cabac_init_idc); + /*slice_qp_delta */ + WRITE_SE (bs, slice_param->slice_qp_delta); + + /* XXX: only supporting I, P and B type slices */ + /* no sp_for_switch_flag and no slice_qs_delta */ + + if (pic_param->pic_fields.bits.deblocking_filter_control_present_flag) { + /* disable_deblocking_filter_idc */ + WRITE_UE (bs, slice_param->disable_deblocking_filter_idc); + if (slice_param->disable_deblocking_filter_idc != 1) { + WRITE_SE (bs, slice_param->slice_alpha_c0_offset_div2); + WRITE_SE (bs, slice_param->slice_beta_offset_div2); + } + } + + /* XXX: unsupported arbitrary slice ordering (ASO) */ + /* num_slic_groups_minus1 should be zero */ + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write Slice NAL unit"); + return FALSE; + } +} + +static inline void +_check_sps_pps_status (GstVaapiEncoderH264 * encoder, + const guint8 * nal, guint32 size) +{ + guint8 nal_type; + G_GNUC_UNUSED gsize ret; /* FIXME */ + gboolean has_subset_sps; + + g_assert (size); + + has_subset_sps = !encoder->is_mvc || (encoder->subset_sps_data != NULL); + if (encoder->sps_data && encoder->pps_data && has_subset_sps) + return; + + nal_type = nal[0] & 0x1F; + switch (nal_type) { + case GST_H264_NAL_SPS: + encoder->sps_data = gst_buffer_new_allocate (NULL, size, NULL); + ret = gst_buffer_fill (encoder->sps_data, 0, nal, size); + g_assert (ret == size); + break; + case GST_H264_NAL_SUBSET_SPS: + encoder->subset_sps_data = gst_buffer_new_allocate (NULL, size, NULL); + ret = gst_buffer_fill (encoder->subset_sps_data, 0, nal, size); + g_assert (ret == size); + break; + case GST_H264_NAL_PPS: + encoder->pps_data = gst_buffer_new_allocate (NULL, size, NULL); + ret = gst_buffer_fill (encoder->pps_data, 0, nal, size); + g_assert (ret == size); + break; + default: + break; + } +} + +/* Determines the largest supported profile by the underlying hardware */ +static gboolean +ensure_hw_profile_limits (GstVaapiEncoderH264 * encoder) +{ + GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (encoder); + GArray *profiles; + guint i, profile_idc, max_profile_idc; + + if (encoder->hw_max_profile_idc) + return TRUE; + + profiles = gst_vaapi_display_get_encode_profiles (display); + if (!profiles) + return FALSE; + + max_profile_idc = 0; + for (i = 0; i < profiles->len; i++) { + const GstVaapiProfile profile = + g_array_index (profiles, GstVaapiProfile, i); + profile_idc = gst_vaapi_utils_h264_get_profile_idc (profile); + if (!profile_idc) + continue; + if (max_profile_idc < profile_idc) + max_profile_idc = profile_idc; + } + g_array_unref (profiles); + + encoder->hw_max_profile_idc = max_profile_idc; + return TRUE; +} + +/* Derives the profile supported by the underlying hardware */ +static gboolean +ensure_hw_profile (GstVaapiEncoderH264 * encoder) +{ + GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (encoder); + GstVaapiEntrypoint entrypoint = encoder->entrypoint; + GstVaapiProfile profile, profiles[4]; + guint i, num_profiles = 0; + + profiles[num_profiles++] = encoder->profile; + switch (encoder->profile) { + case GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE: + profiles[num_profiles++] = GST_VAAPI_PROFILE_H264_BASELINE; + profiles[num_profiles++] = GST_VAAPI_PROFILE_H264_MAIN; + // fall-through + case GST_VAAPI_PROFILE_H264_MAIN: + profiles[num_profiles++] = GST_VAAPI_PROFILE_H264_HIGH; + break; + default: + break; + } + + profile = GST_VAAPI_PROFILE_UNKNOWN; + for (i = 0; i < num_profiles; i++) { + if (gst_vaapi_display_has_encoder (display, profiles[i], entrypoint)) { + profile = profiles[i]; + break; + } + } + if (profile == GST_VAAPI_PROFILE_UNKNOWN) + goto error_unsupported_profile; + + GST_VAAPI_ENCODER_CAST (encoder)->profile = profile; + return TRUE; + + /* ERRORS */ +error_unsupported_profile: + { + GST_ERROR ("unsupported HW profile %s", + gst_vaapi_profile_get_va_name (encoder->profile)); + return FALSE; + } +} + +/* Check target decoder constraints */ +static gboolean +ensure_profile_limits (GstVaapiEncoderH264 * encoder) +{ + GstVaapiProfile profile; + + if (!encoder->max_profile_idc + || encoder->profile_idc == encoder->max_profile_idc) + return TRUE; + + /* Give an error if the given parameters are invalid for requested + * profile rather than lowering profile. + */ + if (encoder->profile_idc > encoder->max_profile_idc) { + GST_WARNING ("Invalid parameter for maximum profile"); + return FALSE; + } + + profile = GST_VAAPI_PROFILE_UNKNOWN; + + if (encoder->profile_idc < encoder->max_profile_idc) { + /* Let profile be higher to fit in the maximum profile + * without changing parameters */ + if (encoder->max_profile_idc > GST_H264_PROFILE_BASELINE) + profile = GST_VAAPI_PROFILE_H264_MAIN; + + if (encoder->max_profile_idc > GST_H264_PROFILE_MAIN) + profile = GST_VAAPI_PROFILE_H264_HIGH; + + if (encoder->max_profile_idc > GST_H264_PROFILE_HIGH) { + if (encoder->num_views > 2) + profile = GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH; + else if (encoder->num_views == 2) + profile = GST_VAAPI_PROFILE_H264_STEREO_HIGH; + } + } + + if (profile) { + encoder->profile = profile; + encoder->profile_idc = encoder->max_profile_idc; + } + return TRUE; +} + +/* Derives the minimum profile from the active coding tools */ +static gboolean +ensure_profile (GstVaapiEncoderH264 * encoder) +{ + GstVaapiProfile profile; + + /* Always start from "constrained-baseline" profile for maximum + compatibility */ + profile = GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE; + + /* Main profile coding tools */ + if (encoder->num_bframes > 0 || encoder->use_cabac) + profile = GST_VAAPI_PROFILE_H264_MAIN; + + /* High profile coding tools */ + if (encoder->use_dct8x8) + profile = GST_VAAPI_PROFILE_H264_HIGH; + + /* MVC profiles coding tools */ + if (encoder->num_views == 2) + profile = GST_VAAPI_PROFILE_H264_STEREO_HIGH; + else if (encoder->num_views > 2) + profile = GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH; + + encoder->profile = profile; + encoder->profile_idc = gst_vaapi_utils_h264_get_profile_idc (profile); + return TRUE; +} + +/* Derives the level from the currently set limits */ +static gboolean +ensure_level (GstVaapiEncoderH264 * encoder) +{ + const guint cpb_factor = h264_get_cpb_nal_factor (encoder->profile); + const GstVaapiH264LevelLimits *limits_table; + guint i, num_limits, PicSizeMbs, MaxDpbMbs, MaxMBPS; + + PicSizeMbs = encoder->mb_width * encoder->mb_height; + MaxDpbMbs = PicSizeMbs * ((encoder->num_bframes) ? 2 : 1); + MaxMBPS = gst_util_uint64_scale_int_ceil (PicSizeMbs, + GST_VAAPI_ENCODER_FPS_N (encoder), GST_VAAPI_ENCODER_FPS_D (encoder)); + + limits_table = gst_vaapi_utils_h264_get_level_limits_table (&num_limits); + for (i = 0; i < num_limits; i++) { + const GstVaapiH264LevelLimits *const limits = &limits_table[i]; + if (PicSizeMbs <= limits->MaxFS && + MaxDpbMbs <= limits->MaxDpbMbs && + MaxMBPS <= limits->MaxMBPS && (!encoder->bitrate_bits + || encoder->bitrate_bits <= (limits->MaxBR * cpb_factor)) && + (!encoder->cpb_length_bits || + encoder->cpb_length_bits <= (limits->MaxCPB * cpb_factor))) + break; + } + if (i == num_limits) + goto error_unsupported_level; + + encoder->level = limits_table[i].level; + encoder->level_idc = limits_table[i].level_idc; + encoder->min_cr = limits_table[i].MinCR; + return TRUE; + + /* ERRORS */ +error_unsupported_level: + { + GST_ERROR ("failed to find a suitable level matching codec config"); + return FALSE; + } +} + +/* Enable "high-compression" tuning options */ +static gboolean +ensure_tuning_high_compression (GstVaapiEncoderH264 * encoder) +{ + guint8 profile_idc; + + if (!ensure_hw_profile_limits (encoder)) + return FALSE; + + profile_idc = encoder->hw_max_profile_idc; + if (encoder->max_profile_idc && encoder->max_profile_idc < profile_idc) + profile_idc = encoder->max_profile_idc; + + /* Tuning options to enable Main profile */ + if (profile_idc >= GST_H264_PROFILE_MAIN + && profile_idc != GST_H264_PROFILE_EXTENDED) { + encoder->use_cabac = TRUE; + if (!encoder->num_bframes) + encoder->num_bframes = 1; + } + + /* Tuning options to enable High profile */ + if (profile_idc >= GST_H264_PROFILE_HIGH) { + encoder->use_dct8x8 = TRUE; + } + return TRUE; +} + +/* Ensure tuning options */ +static gboolean +ensure_tuning (GstVaapiEncoderH264 * encoder) +{ + gboolean success; + + switch (GST_VAAPI_ENCODER_TUNE (encoder)) { + case GST_VAAPI_ENCODER_TUNE_HIGH_COMPRESSION: + success = ensure_tuning_high_compression (encoder); + break; + default: + success = TRUE; + break; + } + return success; +} + +static gboolean +is_temporal_id_max (GstVaapiEncoderH264 * encoder, guint32 temporal_id) +{ + g_assert (temporal_id < encoder->temporal_levels); + return temporal_id == encoder->temporal_levels - 1; +} + +/* Handle new GOP starts */ +static void +reset_gop_start (GstVaapiEncoderH264 * encoder) +{ + GstVaapiH264ViewReorderPool *const reorder_pool = + &encoder->reorder_pools[encoder->view_idx]; + + reorder_pool->frame_index = 1; + reorder_pool->cur_present_index = 0; + ++encoder->idr_num; +} + +/* Marks the supplied picture as a B-frame */ +static void +set_b_frame (GstVaapiEncPicture * pic, GstVaapiEncoderH264 * encoder) +{ + g_assert (pic && encoder); + g_return_if_fail (pic->type == GST_VAAPI_PICTURE_TYPE_NONE); + pic->type = GST_VAAPI_PICTURE_TYPE_B; + + if (encoder->temporal_levels > 1) { + /* while doing temporal encoding, b frames are allowded + * only in hierarchical-b mode */ + g_assert (encoder->prediction_type == + GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_B); + /* temporal_encode: set b-frame as reference frames in + * hierarchical-b encode unless they belongs to highest level */ + if (!is_temporal_id_max (encoder, pic->temporal_id)) + GST_VAAPI_PICTURE_FLAG_SET (pic, GST_VAAPI_ENC_PICTURE_FLAG_REFERENCE); + } +} + +/* Marks the supplied picture as a P-frame */ +static void +set_p_frame (GstVaapiEncPicture * pic, GstVaapiEncoderH264 * encoder) +{ + g_return_if_fail (pic->type == GST_VAAPI_PICTURE_TYPE_NONE); + pic->type = GST_VAAPI_PICTURE_TYPE_P; + + if (encoder->temporal_levels == 1) { + /* Default prediction mode */ + GST_VAAPI_PICTURE_FLAG_SET (pic, GST_VAAPI_ENC_PICTURE_FLAG_REFERENCE); + } else { + /* temporal_encode: all frames in highest level are not reference frames + * for hierarhical-p and hierarchical-b prediction mode */ + if (!is_temporal_id_max (encoder, pic->temporal_id)) + GST_VAAPI_PICTURE_FLAG_SET (pic, GST_VAAPI_ENC_PICTURE_FLAG_REFERENCE); + } +} + +/* Marks the supplied picture as an I-frame */ +static void +set_i_frame (GstVaapiEncPicture * pic, GstVaapiEncoderH264 * encoder) +{ + g_return_if_fail (pic->type == GST_VAAPI_PICTURE_TYPE_NONE); + pic->type = GST_VAAPI_PICTURE_TYPE_I; + GST_VAAPI_PICTURE_FLAG_SET (pic, GST_VAAPI_ENC_PICTURE_FLAG_REFERENCE); + + g_assert (pic->frame); + GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (pic->frame); +} + +/* Marks the supplied picture as an IDR frame */ +static void +set_idr_frame (GstVaapiEncPicture * pic, GstVaapiEncoderH264 * encoder) +{ + g_return_if_fail (pic->type == GST_VAAPI_PICTURE_TYPE_NONE); + pic->type = GST_VAAPI_PICTURE_TYPE_I; + pic->poc = 0; + GST_VAAPI_ENC_PICTURE_FLAG_SET (pic, + GST_VAAPI_ENC_PICTURE_FLAG_IDR | GST_VAAPI_ENC_PICTURE_FLAG_REFERENCE); + + g_assert (pic->frame); + GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (pic->frame); +} + +/* Marks the supplied picture a a key-frame */ +static void +set_key_frame (GstVaapiEncPicture * picture, + GstVaapiEncoderH264 * encoder, gboolean is_idr) +{ + if (is_idr) { + reset_gop_start (encoder); + set_idr_frame (picture, encoder); + } else + set_i_frame (picture, encoder); +} + +static void +set_frame_num (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture) +{ + GstVaapiH264ViewReorderPool *reorder_pool = NULL; + + reorder_pool = &encoder->reorder_pools[encoder->view_idx]; + + picture->frame_num = (reorder_pool->cur_frame_num % encoder->max_frame_num); + + if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture)) { + picture->frame_num = 0; + reorder_pool->cur_frame_num = 0; + } + + reorder_pool->prev_frame_is_ref = GST_VAAPI_ENC_PICTURE_IS_REFRENCE (picture); + + if (reorder_pool->prev_frame_is_ref) + ++reorder_pool->cur_frame_num; +} + +/* Fills in VA HRD parameters */ +static void +fill_hrd_params (GstVaapiEncoderH264 * encoder, VAEncMiscParameterHRD * hrd) +{ + if (encoder->bitrate_bits > 0) { + hrd->buffer_size = encoder->cpb_length_bits; + hrd->initial_buffer_fullness = hrd->buffer_size / 2; + } else { + hrd->buffer_size = 0; + hrd->initial_buffer_fullness = 0; + } +} + +static gboolean +add_packed_au_delimiter (GstVaapiEncoderH264 * encoder, + GstVaapiEncPicture * picture) +{ + GstVaapiEncPackedHeader *packed_aud; + GstBitWriter bs; + VAEncPackedHeaderParameterBuffer packed_header_param_buffer = { 0 }; + guint32 data_bit_size; + guint8 *data; + + gst_bit_writer_init_with_size (&bs, 128, FALSE); + WRITE_UINT32 (&bs, 0x00000001, 32); /* start code */ + bs_write_nal_header (&bs, GST_H264_NAL_REF_IDC_NONE, + GST_H264_NAL_AU_DELIMITER); + WRITE_UINT32 (&bs, picture->type - 1, 3); + if (!bs_write_trailing_bits (&bs)) + goto bs_error; + + g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0); + data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs); + data = GST_BIT_WRITER_DATA (&bs); + + packed_header_param_buffer.type = VAEncPackedHeaderRawData; + packed_header_param_buffer.bit_length = data_bit_size; + packed_header_param_buffer.has_emulation_bytes = 0; + + packed_aud = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder), + &packed_header_param_buffer, sizeof (packed_header_param_buffer), + data, (data_bit_size + 7) / 8); + g_assert (packed_aud); + + gst_vaapi_enc_picture_add_packed_header (picture, packed_aud); + gst_vaapi_codec_object_replace (&packed_aud, NULL); + + gst_bit_writer_reset (&bs); + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write AU Delimiter NAL unit"); + gst_bit_writer_reset (&bs); + return FALSE; + } +} + +/* Adds the supplied sequence header (SPS) to the list of packed + headers to pass down as-is to the encoder */ +static gboolean +add_packed_sequence_header (GstVaapiEncoderH264 * encoder, + GstVaapiEncPicture * picture, GstVaapiEncSequence * sequence) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); + GstVaapiEncPackedHeader *packed_seq; + GstBitWriter bs; + VAEncPackedHeaderParameterBuffer packed_seq_param = { 0 }; + const VAEncSequenceParameterBufferH264 *const seq_param = sequence->param; + GstVaapiProfile profile = encoder->profile; + + VAEncMiscParameterHRD hrd_params; + guint32 data_bit_size; + guint8 *data; + + fill_hrd_params (encoder, &hrd_params); + + gst_bit_writer_init_with_size (&bs, 128, FALSE); + WRITE_UINT32 (&bs, 0x00000001, 32); /* start code */ + bs_write_nal_header (&bs, GST_H264_NAL_REF_IDC_HIGH, GST_H264_NAL_SPS); + + /* Set High profile for encoding the MVC base view. Otherwise, some + traditional decoder cannot recognize MVC profile streams with + only the base view in there */ + if (profile == GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH || + profile == GST_VAAPI_PROFILE_H264_STEREO_HIGH) + profile = GST_VAAPI_PROFILE_H264_HIGH; + + bs_write_sps (&bs, seq_param, profile, base_encoder->rate_control, + &hrd_params); + + g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0); + data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs); + data = GST_BIT_WRITER_DATA (&bs); + + packed_seq_param.type = VAEncPackedHeaderSequence; + packed_seq_param.bit_length = data_bit_size; + packed_seq_param.has_emulation_bytes = 0; + + packed_seq = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder), + &packed_seq_param, sizeof (packed_seq_param), + data, (data_bit_size + 7) / 8); + g_assert (packed_seq); + + gst_vaapi_enc_picture_add_packed_header (picture, packed_seq); + gst_vaapi_codec_object_replace (&packed_seq, NULL); + + /* store sps data */ + _check_sps_pps_status (encoder, data + 4, data_bit_size / 8 - 4); + gst_bit_writer_reset (&bs); + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write SPS NAL unit"); + gst_bit_writer_reset (&bs); + return FALSE; + } +} + +static gboolean +add_packed_sequence_header_mvc (GstVaapiEncoderH264 * encoder, + GstVaapiEncPicture * picture, GstVaapiEncSequence * sequence) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); + GstVaapiEncPackedHeader *packed_seq; + GstBitWriter bs; + VAEncPackedHeaderParameterBuffer packed_header_param_buffer = { 0 }; + const VAEncSequenceParameterBufferH264 *const seq_param = sequence->param; + VAEncMiscParameterHRD hrd_params; + guint32 data_bit_size; + guint8 *data; + + fill_hrd_params (encoder, &hrd_params); + + /* non-base layer, pack one subset sps */ + gst_bit_writer_init_with_size (&bs, 128, FALSE); + WRITE_UINT32 (&bs, 0x00000001, 32); /* start code */ + bs_write_nal_header (&bs, GST_H264_NAL_REF_IDC_HIGH, GST_H264_NAL_SUBSET_SPS); + + bs_write_subset_sps (&bs, seq_param, encoder->profile, + base_encoder->rate_control, encoder->num_views, encoder->view_ids, + &hrd_params); + + g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0); + data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs); + data = GST_BIT_WRITER_DATA (&bs); + + packed_header_param_buffer.type = VAEncPackedHeaderSequence; + packed_header_param_buffer.bit_length = data_bit_size; + packed_header_param_buffer.has_emulation_bytes = 0; + + packed_seq = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder), + &packed_header_param_buffer, sizeof (packed_header_param_buffer), + data, (data_bit_size + 7) / 8); + g_assert (packed_seq); + + gst_vaapi_enc_picture_add_packed_header (picture, packed_seq); + gst_vaapi_mini_object_replace ((GstVaapiMiniObject **) & packed_seq, NULL); + + /* store subset sps data */ + _check_sps_pps_status (encoder, data + 4, data_bit_size / 8 - 4); + gst_bit_writer_reset (&bs); + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write SPS NAL unit"); + gst_bit_writer_reset (&bs); + return FALSE; + } +} + +/* Adds the supplied picture header (PPS) to the list of packed + headers to pass down as-is to the encoder */ +static gboolean +add_packed_picture_header (GstVaapiEncoderH264 * encoder, + GstVaapiEncPicture * picture) +{ + GstVaapiEncPackedHeader *packed_pic; + GstBitWriter bs; + VAEncPackedHeaderParameterBuffer packed_pic_param = { 0 }; + const VAEncPictureParameterBufferH264 *const pic_param = picture->param; + guint32 data_bit_size; + guint8 *data; + + gst_bit_writer_init_with_size (&bs, 128, FALSE); + WRITE_UINT32 (&bs, 0x00000001, 32); /* start code */ + bs_write_nal_header (&bs, GST_H264_NAL_REF_IDC_HIGH, GST_H264_NAL_PPS); + bs_write_pps (&bs, pic_param, encoder->profile); + g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0); + data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs); + data = GST_BIT_WRITER_DATA (&bs); + + packed_pic_param.type = VAEncPackedHeaderPicture; + packed_pic_param.bit_length = data_bit_size; + packed_pic_param.has_emulation_bytes = 0; + + packed_pic = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder), + &packed_pic_param, sizeof (packed_pic_param), + data, (data_bit_size + 7) / 8); + g_assert (packed_pic); + + gst_vaapi_enc_picture_add_packed_header (picture, packed_pic); + gst_vaapi_codec_object_replace (&packed_pic, NULL); + + /* store pps data */ + _check_sps_pps_status (encoder, data + 4, data_bit_size / 8 - 4); + gst_bit_writer_reset (&bs); + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write PPS NAL unit"); + gst_bit_writer_reset (&bs); + return FALSE; + } +} + +static gboolean +add_packed_sei_header (GstVaapiEncoderH264 * encoder, + GstVaapiEncPicture * picture, GstVaapiH264SeiPayloadType payloadtype) +{ + GstVaapiEncPackedHeader *packed_sei; + GstBitWriter bs, bs_buf_period, bs_pic_timing; + VAEncPackedHeaderParameterBuffer packed_sei_param = { 0 }; + guint32 data_bit_size; + guint8 buf_period_payload_size = 0, pic_timing_payload_size = 0; + guint8 *data, *buf_period_payload = NULL, *pic_timing_payload = NULL; + gboolean need_buf_period, need_pic_timing; + + gst_bit_writer_init_with_size (&bs_buf_period, 128, FALSE); + gst_bit_writer_init_with_size (&bs_pic_timing, 128, FALSE); + gst_bit_writer_init_with_size (&bs, 128, FALSE); + + need_buf_period = GST_VAAPI_H264_SEI_BUF_PERIOD & payloadtype; + need_pic_timing = GST_VAAPI_H264_SEI_PIC_TIMING & payloadtype; + + if (need_buf_period) { + /* Write a Buffering Period SEI message */ + bs_write_sei_buf_period (&bs_buf_period, encoder, picture); + /* Write byte alignment bits */ + if (GST_BIT_WRITER_BIT_SIZE (&bs_buf_period) % 8 != 0) + bs_write_trailing_bits (&bs_buf_period); + buf_period_payload_size = (GST_BIT_WRITER_BIT_SIZE (&bs_buf_period)) / 8; + buf_period_payload = GST_BIT_WRITER_DATA (&bs_buf_period); + } + + if (need_pic_timing) { + /* Write a Picture Timing SEI message */ + if (GST_VAAPI_H264_SEI_PIC_TIMING & payloadtype) + bs_write_sei_pic_timing (&bs_pic_timing, encoder, picture); + /* Write byte alignment bits */ + if (GST_BIT_WRITER_BIT_SIZE (&bs_pic_timing) % 8 != 0) + bs_write_trailing_bits (&bs_pic_timing); + pic_timing_payload_size = (GST_BIT_WRITER_BIT_SIZE (&bs_pic_timing)) / 8; + pic_timing_payload = GST_BIT_WRITER_DATA (&bs_pic_timing); + } + + /* Write the SEI message */ + WRITE_UINT32 (&bs, 0x00000001, 32); /* start code */ + bs_write_nal_header (&bs, GST_H264_NAL_REF_IDC_NONE, GST_H264_NAL_SEI); + + if (need_buf_period) { + WRITE_UINT32 (&bs, GST_H264_SEI_BUF_PERIOD, 8); + WRITE_UINT32 (&bs, buf_period_payload_size, 8); + /* Add buffering period sei message */ + gst_bit_writer_put_bytes (&bs, buf_period_payload, buf_period_payload_size); + } + + if (need_pic_timing) { + WRITE_UINT32 (&bs, GST_H264_SEI_PIC_TIMING, 8); + WRITE_UINT32 (&bs, pic_timing_payload_size, 8); + /* Add picture timing sei message */ + gst_bit_writer_put_bytes (&bs, pic_timing_payload, pic_timing_payload_size); + } + + /* rbsp_trailing_bits */ + bs_write_trailing_bits (&bs); + + g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0); + data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs); + data = GST_BIT_WRITER_DATA (&bs); + + packed_sei_param.type = VA_ENC_PACKED_HEADER_H264_SEI; + packed_sei_param.bit_length = data_bit_size; + packed_sei_param.has_emulation_bytes = 0; + + packed_sei = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder), + &packed_sei_param, sizeof (packed_sei_param), + data, (data_bit_size + 7) / 8); + g_assert (packed_sei); + + gst_vaapi_enc_picture_add_packed_header (picture, packed_sei); + gst_vaapi_codec_object_replace (&packed_sei, NULL); + + gst_bit_writer_reset (&bs_buf_period); + gst_bit_writer_reset (&bs_pic_timing); + gst_bit_writer_reset (&bs); + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write SEI NAL unit"); + gst_bit_writer_reset (&bs_buf_period); + gst_bit_writer_reset (&bs_pic_timing); + gst_bit_writer_reset (&bs); + return FALSE; + } +} + +static gboolean +get_nal_hdr_attributes (GstVaapiEncPicture * picture, + guint8 * nal_ref_idc, guint8 * nal_unit_type) +{ + switch (picture->type) { + case GST_VAAPI_PICTURE_TYPE_I: + *nal_ref_idc = GST_H264_NAL_REF_IDC_HIGH; + if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture)) + *nal_unit_type = GST_H264_NAL_SLICE_IDR; + else + *nal_unit_type = GST_H264_NAL_SLICE; + break; + case GST_VAAPI_PICTURE_TYPE_P: + if (!GST_VAAPI_ENC_PICTURE_IS_REFRENCE (picture)) + *nal_ref_idc = GST_H264_NAL_REF_IDC_NONE; + else + *nal_ref_idc = GST_H264_NAL_REF_IDC_MEDIUM; + + *nal_unit_type = GST_H264_NAL_SLICE; + break; + case GST_VAAPI_PICTURE_TYPE_B: + if (!GST_VAAPI_ENC_PICTURE_IS_REFRENCE (picture)) + *nal_ref_idc = GST_H264_NAL_REF_IDC_NONE; + else + *nal_ref_idc = GST_H264_NAL_REF_IDC_LOW; + + *nal_unit_type = GST_H264_NAL_SLICE; + break; + default: + return FALSE; + } + return TRUE; +} + +/* Adds the supplied prefix nal header to the list of packed + headers to pass down as-is to the encoder */ +static gboolean +add_packed_prefix_nal_header (GstVaapiEncoderH264 * encoder, + GstVaapiEncPicture * picture, GstVaapiEncSlice * slice) +{ + GstVaapiEncPackedHeader *packed_prefix_nal; + GstBitWriter bs; + VAEncPackedHeaderParameterBuffer packed_prefix_nal_param = { 0 }; + guint32 data_bit_size; + guint8 *data; + guint8 nal_ref_idc, nal_unit_type; + + gst_bit_writer_init_with_size (&bs, 128, FALSE); + WRITE_UINT32 (&bs, 0x00000001, 32); /* start code */ + + if (!get_nal_hdr_attributes (picture, &nal_ref_idc, &nal_unit_type)) + goto bs_error; + nal_unit_type = GST_H264_NAL_PREFIX_UNIT; + + bs_write_nal_header (&bs, nal_ref_idc, nal_unit_type); + bs_write_nal_header_mvc_extension (&bs, picture, encoder->view_idx); + g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0); + data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs); + data = GST_BIT_WRITER_DATA (&bs); + + packed_prefix_nal_param.type = VAEncPackedHeaderRawData; + packed_prefix_nal_param.bit_length = data_bit_size; + packed_prefix_nal_param.has_emulation_bytes = 0; + + packed_prefix_nal = + gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder), + &packed_prefix_nal_param, sizeof (packed_prefix_nal_param), data, + (data_bit_size + 7) / 8); + g_assert (packed_prefix_nal); + + gst_vaapi_enc_slice_add_packed_header (slice, packed_prefix_nal); + gst_vaapi_codec_object_replace (&packed_prefix_nal, NULL); + + gst_bit_writer_reset (&bs); + + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write Prefix NAL unit header"); + gst_bit_writer_reset (&bs); + return FALSE; + } +} + +/* Adds the supplied slice header to the list of packed + headers to pass down as-is to the encoder */ +static gboolean +add_packed_slice_header (GstVaapiEncoderH264 * encoder, + GstVaapiEncPicture * picture, GstVaapiEncSlice * slice) +{ + GstVaapiEncPackedHeader *packed_slice; + GstBitWriter bs; + VAEncPackedHeaderParameterBuffer packed_slice_param = { 0 }; + const VAEncSliceParameterBufferH264 *const slice_param = slice->param; + guint32 data_bit_size; + guint8 *data; + guint8 nal_ref_idc, nal_unit_type; + + gst_bit_writer_init_with_size (&bs, 128, FALSE); + WRITE_UINT32 (&bs, 0x00000001, 32); /* start code */ + + if (!get_nal_hdr_attributes (picture, &nal_ref_idc, &nal_unit_type)) + goto bs_error; + /* pack nal_unit_header_mvc_extension() for the non base view */ + if (encoder->is_mvc && encoder->view_idx) { + bs_write_nal_header (&bs, nal_ref_idc, GST_H264_NAL_SLICE_EXT); + bs_write_nal_header_mvc_extension (&bs, picture, + encoder->view_ids[encoder->view_idx]); + } else + bs_write_nal_header (&bs, nal_ref_idc, nal_unit_type); + + bs_write_slice (&bs, slice_param, encoder, picture); + data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs); + data = GST_BIT_WRITER_DATA (&bs); + + packed_slice_param.type = VAEncPackedHeaderSlice; + packed_slice_param.bit_length = data_bit_size; + packed_slice_param.has_emulation_bytes = 0; + + packed_slice = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder), + &packed_slice_param, sizeof (packed_slice_param), + data, (data_bit_size + 7) / 8); + g_assert (packed_slice); + + gst_vaapi_enc_slice_add_packed_header (slice, packed_slice); + gst_vaapi_codec_object_replace (&packed_slice, NULL); + + gst_bit_writer_reset (&bs); + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write Slice NAL unit header"); + gst_bit_writer_reset (&bs); + return FALSE; + } +} + +/* Reference picture management */ +static void +reference_pic_free (GstVaapiEncoderH264 * encoder, GstVaapiEncoderH264Ref * ref) +{ + if (!ref) + return; + if (ref->pic) + gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder), ref->pic); + g_slice_free (GstVaapiEncoderH264Ref, ref); +} + +static inline GstVaapiEncoderH264Ref * +reference_pic_create (GstVaapiEncoderH264 * encoder, + GstVaapiEncPicture * picture, GstVaapiSurfaceProxy * surface) +{ + GstVaapiEncoderH264Ref *const ref = g_slice_new0 (GstVaapiEncoderH264Ref); + + ref->pic = surface; + ref->frame_num = picture->frame_num; + ref->poc = picture->poc; + ref->temporal_id = picture->temporal_id; + return ref; +} + +static gboolean +reference_list_update (GstVaapiEncoderH264 * encoder, + GstVaapiEncPicture * picture, GstVaapiSurfaceProxy * surface) +{ + GstVaapiEncoderH264Ref *ref; + GstVaapiH264ViewRefPool *const ref_pool = + &encoder->ref_pools[encoder->view_idx]; + + if (encoder->prediction_type == GST_VAAPI_ENCODER_H264_PREDICTION_DEFAULT + && GST_VAAPI_PICTURE_TYPE_B == picture->type) { + gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder), surface); + return TRUE; + } + if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture)) { + while (!g_queue_is_empty (&ref_pool->ref_list)) + reference_pic_free (encoder, g_queue_pop_head (&ref_pool->ref_list)); + } else if (g_queue_get_length (&ref_pool->ref_list) >= + ref_pool->max_ref_frames) { + reference_pic_free (encoder, g_queue_pop_head (&ref_pool->ref_list)); + } + ref = reference_pic_create (encoder, picture, surface); + g_queue_push_tail (&ref_pool->ref_list, ref); + g_assert (g_queue_get_length (&ref_pool->ref_list) <= + ref_pool->max_ref_frames); + return TRUE; +} + +/* update reflist0 for hierarchical-p and hierarchical-b encode */ +static void +reflist0_init_hierarchical (GstVaapiEncoderH264 * encoder, + GstVaapiEncPicture * picture, GQueue * ref_list, + GstVaapiEncoderH264Ref ** reflist_0, guint * reflist_0_count) +{ + GstVaapiEncoderH264Ref *tmp = NULL; + GList *iter; + guint count = 0, i; + + iter = g_queue_peek_tail_link (ref_list); + for (; iter; iter = g_list_previous (iter)) { + tmp = (GstVaapiEncoderH264Ref *) iter->data; + + g_assert (tmp && tmp->poc != picture->poc); + + if (_poc_greater_than (picture->poc, tmp->poc, encoder->max_pic_order_cnt) + && ((picture->temporal_id && (tmp->temporal_id < picture->temporal_id)) + || (!picture->temporal_id + && (tmp->temporal_id == picture->temporal_id)))) { + reflist_0[count++] = tmp; + } + } + + g_assert (count != 0); + + /* Only need one ref frame */ + tmp = reflist_0[0]; + for (i = 1; i < count; i++) { + if (tmp->poc < reflist_0[i]->poc) + tmp = reflist_0[i]; + } + reflist_0[0] = tmp; + *reflist_0_count = 1; + encoder->abs_diff_pic_num_list0 = picture->frame_num - tmp->frame_num; +} + +/* update reflist1 for hierarchical-b encode */ +static void +reflist1_init_hierarchical_b (GstVaapiEncoderH264 * encoder, + GstVaapiEncPicture * picture, GQueue * ref_list, + GstVaapiEncoderH264Ref ** reflist_1, guint * reflist_1_count) +{ + GstVaapiEncoderH264Ref *tmp = NULL; + GList *iter; + guint count = 0, i; + + /* base layer should have only P frames */ + g_assert (picture->temporal_id != 0); + + iter = g_queue_peek_tail_link (ref_list); + for (; iter; iter = g_list_previous (iter)) { + tmp = (GstVaapiEncoderH264Ref *) iter->data; + + g_assert (tmp && tmp->poc != picture->poc); + + if (_poc_greater_than (tmp->poc, picture->poc, encoder->max_pic_order_cnt) + && (tmp->temporal_id < picture->temporal_id)) { + reflist_1[count++] = tmp; + } + } + + g_assert (count != 0); + + /* Only need one ref frame */ + tmp = reflist_1[0]; + for (i = 1; i < count; i++) { + if (tmp->poc > reflist_1[i]->poc) + tmp = reflist_1[i]; + } + reflist_1[0] = tmp; + *reflist_1_count = 1; + encoder->abs_diff_pic_num_list1 = picture->frame_num - tmp->frame_num; +} + +static gboolean +reference_list_init_hierarchical (GstVaapiEncoderH264 * encoder, + GstVaapiEncPicture * picture, + GQueue * ref_list, + GstVaapiEncoderH264Ref ** reflist_0, + guint * reflist_0_count, + GstVaapiEncoderH264Ref ** reflist_1, guint * reflist_1_count) +{ + /* reflist_0 ordering is same for hierarchical-P and hierarchical-B */ + reflist0_init_hierarchical (encoder, picture, ref_list, reflist_0, + reflist_0_count); + + if (picture->type != GST_VAAPI_PICTURE_TYPE_B) + return TRUE; + + g_assert (encoder->prediction_type == + GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_B); + + reflist1_init_hierarchical_b (encoder, picture, ref_list, + reflist_1, reflist_1_count); + + /* FIXME: Combine and optimize reflist_0_init and reflist_1_init. + * Keeping separate blocks for now to make it more + * readable and easy to debug */ + + return TRUE; +} + +static gboolean +reference_list_init (GstVaapiEncoderH264 * encoder, + GstVaapiEncPicture * picture, + GstVaapiEncoderH264Ref ** reflist_0, + guint * reflist_0_count, + GstVaapiEncoderH264Ref ** reflist_1, guint * reflist_1_count) +{ + GstVaapiEncoderH264Ref *tmp; + GstVaapiH264ViewRefPool *const ref_pool = + &encoder->ref_pools[encoder->view_idx]; + GList *iter, *list_0_start = NULL, *list_1_start = NULL; + guint count; + + *reflist_0_count = 0; + *reflist_1_count = 0; + if (picture->type == GST_VAAPI_PICTURE_TYPE_I) + return TRUE; + + /* reference picture handling for hierarchial encode */ + if (encoder->prediction_type != GST_VAAPI_ENCODER_H264_PREDICTION_DEFAULT) { + return reference_list_init_hierarchical (encoder, picture, + &ref_pool->ref_list, reflist_0, reflist_0_count, reflist_1, + reflist_1_count); + } + + iter = g_queue_peek_tail_link (&ref_pool->ref_list); + for (; iter; iter = g_list_previous (iter)) { + tmp = (GstVaapiEncoderH264Ref *) iter->data; + g_assert (tmp && tmp->poc != picture->poc); + if (_poc_greater_than (picture->poc, tmp->poc, encoder->max_pic_order_cnt)) { + list_0_start = iter; + list_1_start = g_list_next (iter); + break; + } + } + + /* order reflist_0 */ + g_assert (list_0_start); + iter = list_0_start; + count = 0; + for (; iter; iter = g_list_previous (iter)) { + reflist_0[count] = (GstVaapiEncoderH264Ref *) iter->data; + ++count; + } + *reflist_0_count = count; + + if (picture->type != GST_VAAPI_PICTURE_TYPE_B) + return TRUE; + + /* order reflist_1 */ + count = 0; + iter = list_1_start; + for (; iter; iter = g_list_next (iter)) { + reflist_1[count] = (GstVaapiEncoderH264Ref *) iter->data; + ++count; + } + *reflist_1_count = count; + return TRUE; +} + +/* Fills in VA sequence parameter buffer */ +static gboolean +fill_sequence (GstVaapiEncoderH264 * encoder, GstVaapiEncSequence * sequence) +{ + VAEncSequenceParameterBufferH264 *const seq_param = sequence->param; + GstVaapiH264ViewRefPool *const ref_pool = + &encoder->ref_pools[encoder->view_idx]; + + memset (seq_param, 0, sizeof (VAEncSequenceParameterBufferH264)); + seq_param->seq_parameter_set_id = encoder->view_idx; + seq_param->level_idc = encoder->level_idc; + seq_param->intra_period = GST_VAAPI_ENCODER_KEYFRAME_PERIOD (encoder); + seq_param->intra_idr_period = GST_VAAPI_ENCODER_KEYFRAME_PERIOD (encoder); + seq_param->ip_period = encoder->ip_period; + seq_param->bits_per_second = encoder->bitrate_bits; + + seq_param->max_num_ref_frames = ref_pool->max_ref_frames; + seq_param->picture_width_in_mbs = encoder->mb_width; + seq_param->picture_height_in_mbs = encoder->mb_height; + + /*sequence field values */ + seq_param->seq_fields.value = 0; + seq_param->seq_fields.bits.chroma_format_idc = 1; + seq_param->seq_fields.bits.frame_mbs_only_flag = 1; + seq_param->seq_fields.bits.mb_adaptive_frame_field_flag = FALSE; + seq_param->seq_fields.bits.seq_scaling_matrix_present_flag = FALSE; + /* direct_8x8_inference_flag default false */ + seq_param->seq_fields.bits.direct_8x8_inference_flag = FALSE; + g_assert (encoder->log2_max_frame_num >= 4); + seq_param->seq_fields.bits.log2_max_frame_num_minus4 = + encoder->log2_max_frame_num - 4; + /* picture order count */ + encoder->pic_order_cnt_type = seq_param->seq_fields.bits.pic_order_cnt_type = + 0; + g_assert (encoder->log2_max_pic_order_cnt >= 4); + seq_param->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4 = + encoder->log2_max_pic_order_cnt - 4; + + seq_param->bit_depth_luma_minus8 = 0; + seq_param->bit_depth_chroma_minus8 = 0; + + /* not used if pic_order_cnt_type == 0 */ + if (seq_param->seq_fields.bits.pic_order_cnt_type == 1) { + encoder->delta_pic_order_always_zero_flag = + seq_param->seq_fields.bits.delta_pic_order_always_zero_flag = TRUE; + seq_param->num_ref_frames_in_pic_order_cnt_cycle = 0; + seq_param->offset_for_non_ref_pic = 0; + seq_param->offset_for_top_to_bottom_field = 0; + memset (seq_param->offset_for_ref_frame, 0, + sizeof (seq_param->offset_for_ref_frame)); + } + + /* frame_cropping_flag */ + if ((GST_VAAPI_ENCODER_WIDTH (encoder) & 15) || + (GST_VAAPI_ENCODER_HEIGHT (encoder) & 15)) { + static const guint SubWidthC[] = { 1, 2, 2, 1 }; + static const guint SubHeightC[] = { 1, 2, 1, 1 }; + const guint CropUnitX = + SubWidthC[seq_param->seq_fields.bits.chroma_format_idc]; + const guint CropUnitY = + SubHeightC[seq_param->seq_fields.bits.chroma_format_idc] * + (2 - seq_param->seq_fields.bits.frame_mbs_only_flag); + + seq_param->frame_cropping_flag = 1; + seq_param->frame_crop_left_offset = 0; + seq_param->frame_crop_right_offset = + (16 * encoder->mb_width - + GST_VAAPI_ENCODER_WIDTH (encoder)) / CropUnitX; + seq_param->frame_crop_top_offset = 0; + seq_param->frame_crop_bottom_offset = + (16 * encoder->mb_height - + GST_VAAPI_ENCODER_HEIGHT (encoder)) / CropUnitY; + } + + /* VUI parameters are always set, at least for timing_info (framerate) */ + seq_param->vui_parameters_present_flag = TRUE; + if (seq_param->vui_parameters_present_flag) { + seq_param->vui_fields.bits.aspect_ratio_info_present_flag = TRUE; + if (seq_param->vui_fields.bits.aspect_ratio_info_present_flag) { + const GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder); + seq_param->aspect_ratio_idc = 0xff; + seq_param->sar_width = GST_VIDEO_INFO_PAR_N (vip); + seq_param->sar_height = GST_VIDEO_INFO_PAR_D (vip); + } + seq_param->vui_fields.bits.bitstream_restriction_flag = FALSE; + /* if vui_parameters_present_flag is TRUE and sps data belongs to + * subset sps, timing_info_preset_flag should be zero (H.7.4.2.1.1) */ + seq_param->vui_fields.bits.timing_info_present_flag = !encoder->view_idx; + if (seq_param->vui_fields.bits.timing_info_present_flag) { + seq_param->num_units_in_tick = GST_VAAPI_ENCODER_FPS_D (encoder); + seq_param->time_scale = GST_VAAPI_ENCODER_FPS_N (encoder) * 2; + } + } + return TRUE; +} + +/* Fills in VA picture parameter buffer */ +static gboolean +fill_picture (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture, + GstVaapiCodedBuffer * codedbuf, GstVaapiSurfaceProxy * surface) +{ + VAEncPictureParameterBufferH264 *const pic_param = picture->param; + GstVaapiH264ViewRefPool *const ref_pool = + &encoder->ref_pools[encoder->view_idx]; + GstVaapiEncoderH264Ref *ref_pic; + GList *reflist; + guint i; + + memset (pic_param, 0, sizeof (VAEncPictureParameterBufferH264)); + + /* reference list, */ + pic_param->CurrPic.picture_id = GST_VAAPI_SURFACE_PROXY_SURFACE_ID (surface); + pic_param->CurrPic.TopFieldOrderCnt = picture->poc; + i = 0; + if (picture->type != GST_VAAPI_PICTURE_TYPE_I) { + for (reflist = g_queue_peek_head_link (&ref_pool->ref_list); + reflist; reflist = g_list_next (reflist)) { + ref_pic = reflist->data; + g_assert (ref_pic && ref_pic->pic && + GST_VAAPI_SURFACE_PROXY_SURFACE_ID (ref_pic->pic) != VA_INVALID_ID); + + pic_param->ReferenceFrames[i].picture_id = + GST_VAAPI_SURFACE_PROXY_SURFACE_ID (ref_pic->pic); + pic_param->ReferenceFrames[i].TopFieldOrderCnt = ref_pic->poc; + pic_param->ReferenceFrames[i].flags |= + VA_PICTURE_H264_SHORT_TERM_REFERENCE; + pic_param->ReferenceFrames[i].frame_idx = ref_pic->frame_num; + ++i; + } + g_assert (i <= 16 && i <= ref_pool->max_ref_frames); + } + for (; i < 16; ++i) { + pic_param->ReferenceFrames[i].picture_id = VA_INVALID_ID; + } + pic_param->coded_buf = GST_VAAPI_CODED_BUFFER_ID (codedbuf); + + pic_param->pic_parameter_set_id = encoder->view_idx; + pic_param->seq_parameter_set_id = encoder->view_idx ? 1 : 0; + pic_param->last_picture = 0; /* means last encoding picture */ + pic_param->frame_num = picture->frame_num; + pic_param->pic_init_qp = encoder->qp_i; + pic_param->num_ref_idx_l0_active_minus1 = + (ref_pool->max_reflist0_count ? (ref_pool->max_reflist0_count - 1) : 0); + pic_param->num_ref_idx_l1_active_minus1 = + (ref_pool->max_reflist1_count ? (ref_pool->max_reflist1_count - 1) : 0); + pic_param->chroma_qp_index_offset = 0; + pic_param->second_chroma_qp_index_offset = 0; + + /* set picture fields */ + pic_param->pic_fields.value = 0; + pic_param->pic_fields.bits.idr_pic_flag = + GST_VAAPI_ENC_PICTURE_IS_IDR (picture); + pic_param->pic_fields.bits.reference_pic_flag = + GST_VAAPI_ENC_PICTURE_IS_REFRENCE (picture); + pic_param->pic_fields.bits.entropy_coding_mode_flag = encoder->use_cabac; + pic_param->pic_fields.bits.weighted_pred_flag = FALSE; + pic_param->pic_fields.bits.weighted_bipred_idc = 0; + pic_param->pic_fields.bits.constrained_intra_pred_flag = 0; + pic_param->pic_fields.bits.transform_8x8_mode_flag = encoder->use_dct8x8; + /* enable debloking */ + pic_param->pic_fields.bits.deblocking_filter_control_present_flag = TRUE; + pic_param->pic_fields.bits.redundant_pic_cnt_present_flag = FALSE; + /* bottom_field_pic_order_in_frame_present_flag */ + pic_param->pic_fields.bits.pic_order_present_flag = FALSE; + pic_param->pic_fields.bits.pic_scaling_matrix_present_flag = FALSE; + + return TRUE; +} + +/* Adds slice headers to picture */ +static gboolean +add_slice_headers (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture, + GstVaapiEncoderH264Ref ** reflist_0, guint reflist_0_count, + GstVaapiEncoderH264Ref ** reflist_1, guint reflist_1_count) +{ + VAEncSliceParameterBufferH264 *slice_param; + GstVaapiEncSlice *slice; + guint slice_of_mbs, slice_mod_mbs, cur_slice_mbs; + guint mb_size; + guint last_mb_index; + guint i_slice, i_ref; + + g_assert (picture); + + mb_size = encoder->mb_width * encoder->mb_height; + + g_assert (encoder->num_slices && encoder->num_slices < mb_size); + slice_of_mbs = mb_size / encoder->num_slices; + slice_mod_mbs = mb_size % encoder->num_slices; + last_mb_index = 0; + for (i_slice = 0; i_slice < encoder->num_slices; ++i_slice) { + cur_slice_mbs = slice_of_mbs; + if (slice_mod_mbs) { + ++cur_slice_mbs; + --slice_mod_mbs; + } + slice = GST_VAAPI_ENC_SLICE_NEW (H264, encoder); + g_assert (slice && slice->param_id != VA_INVALID_ID); + slice_param = slice->param; + + memset (slice_param, 0, sizeof (VAEncSliceParameterBufferH264)); + slice_param->macroblock_address = last_mb_index; + slice_param->num_macroblocks = cur_slice_mbs; + slice_param->macroblock_info = VA_INVALID_ID; + slice_param->slice_type = h264_get_slice_type (picture->type); + g_assert ((gint8) slice_param->slice_type != -1); + slice_param->pic_parameter_set_id = encoder->view_idx; + slice_param->idr_pic_id = encoder->idr_num; + slice_param->pic_order_cnt_lsb = picture->poc; + + /* not used if pic_order_cnt_type = 0 */ + slice_param->delta_pic_order_cnt_bottom = 0; + memset (slice_param->delta_pic_order_cnt, 0, + sizeof (slice_param->delta_pic_order_cnt)); + + /* only works for B frames */ + slice_param->direct_spatial_mv_pred_flag = TRUE; + /* default equal to picture parameters */ + slice_param->num_ref_idx_active_override_flag = reflist_0_count + || reflist_1_count; + if (picture->type != GST_VAAPI_PICTURE_TYPE_I && reflist_0_count > 0) + slice_param->num_ref_idx_l0_active_minus1 = reflist_0_count - 1; + else + slice_param->num_ref_idx_l0_active_minus1 = 0; + if (picture->type == GST_VAAPI_PICTURE_TYPE_B && reflist_1_count > 0) + slice_param->num_ref_idx_l1_active_minus1 = reflist_1_count - 1; + else + slice_param->num_ref_idx_l1_active_minus1 = 0; + + i_ref = 0; + if (picture->type != GST_VAAPI_PICTURE_TYPE_I) { + for (; i_ref < reflist_0_count; ++i_ref) { + slice_param->RefPicList0[i_ref].picture_id = + GST_VAAPI_SURFACE_PROXY_SURFACE_ID (reflist_0[i_ref]->pic); + slice_param->RefPicList0[i_ref].TopFieldOrderCnt = + reflist_0[i_ref]->poc; + slice_param->RefPicList0[i_ref].flags |= + VA_PICTURE_H264_SHORT_TERM_REFERENCE; + slice_param->RefPicList0[i_ref].frame_idx = reflist_0[i_ref]->frame_num; + } + } + for (; i_ref < G_N_ELEMENTS (slice_param->RefPicList0); ++i_ref) { + slice_param->RefPicList0[i_ref].picture_id = VA_INVALID_SURFACE; + slice_param->RefPicList0[i_ref].flags = VA_PICTURE_H264_INVALID; + } + + i_ref = 0; + if (picture->type == GST_VAAPI_PICTURE_TYPE_B) { + for (; i_ref < reflist_1_count; ++i_ref) { + slice_param->RefPicList1[i_ref].picture_id = + GST_VAAPI_SURFACE_PROXY_SURFACE_ID (reflist_1[i_ref]->pic); + slice_param->RefPicList1[i_ref].TopFieldOrderCnt = + reflist_1[i_ref]->poc; + slice_param->RefPicList1[i_ref].flags |= + VA_PICTURE_H264_SHORT_TERM_REFERENCE; + slice_param->RefPicList1[i_ref].frame_idx |= + reflist_1[i_ref]->frame_num; + } + } + for (; i_ref < G_N_ELEMENTS (slice_param->RefPicList1); ++i_ref) { + slice_param->RefPicList1[i_ref].picture_id = VA_INVALID_SURFACE; + slice_param->RefPicList1[i_ref].flags = VA_PICTURE_H264_INVALID; + } + + /* not used if pic_param.pic_fields.bits.weighted_pred_flag == FALSE */ + slice_param->luma_log2_weight_denom = 0; + slice_param->chroma_log2_weight_denom = 0; + slice_param->luma_weight_l0_flag = FALSE; + memset (slice_param->luma_weight_l0, 0, + sizeof (slice_param->luma_weight_l0)); + memset (slice_param->luma_offset_l0, 0, + sizeof (slice_param->luma_offset_l0)); + slice_param->chroma_weight_l0_flag = FALSE; + memset (slice_param->chroma_weight_l0, 0, + sizeof (slice_param->chroma_weight_l0)); + memset (slice_param->chroma_offset_l0, 0, + sizeof (slice_param->chroma_offset_l0)); + slice_param->luma_weight_l1_flag = FALSE; + memset (slice_param->luma_weight_l1, 0, + sizeof (slice_param->luma_weight_l1)); + memset (slice_param->luma_offset_l1, 0, + sizeof (slice_param->luma_offset_l1)); + slice_param->chroma_weight_l1_flag = FALSE; + memset (slice_param->chroma_weight_l1, 0, + sizeof (slice_param->chroma_weight_l1)); + memset (slice_param->chroma_offset_l1, 0, + sizeof (slice_param->chroma_offset_l1)); + + slice_param->cabac_init_idc = 0; + slice_param->slice_qp_delta = encoder->qp_i - encoder->init_qp; + if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CQP) { + if (picture->type == GST_VAAPI_PICTURE_TYPE_P) { + slice_param->slice_qp_delta += encoder->qp_ip; + } else if (picture->type == GST_VAAPI_PICTURE_TYPE_B) { + slice_param->slice_qp_delta += encoder->qp_ib; + } + if ((gint) encoder->init_qp + slice_param->slice_qp_delta < + (gint) encoder->min_qp) { + slice_param->slice_qp_delta = encoder->min_qp - encoder->init_qp; + } + if ((gint) encoder->init_qp + slice_param->slice_qp_delta > + (gint) encoder->max_qp) { + slice_param->slice_qp_delta = encoder->max_qp - encoder->init_qp; + } + } + slice_param->disable_deblocking_filter_idc = 0; + slice_param->slice_alpha_c0_offset_div2 = 2; + slice_param->slice_beta_offset_div2 = 2; + + /* set calculation for next slice */ + last_mb_index += cur_slice_mbs; + + /* add packed Prefix NAL unit before each Coded slice NAL in base view */ + if (encoder->is_mvc && !encoder->view_idx && + (GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) & + VA_ENC_PACKED_HEADER_RAW_DATA) + && !add_packed_prefix_nal_header (encoder, picture, slice)) + goto error_create_packed_prefix_nal_hdr; + if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) & + VA_ENC_PACKED_HEADER_SLICE) + && !add_packed_slice_header (encoder, picture, slice)) + goto error_create_packed_slice_hdr; + + gst_vaapi_enc_picture_add_slice (picture, slice); + gst_vaapi_codec_object_replace (&slice, NULL); + } + g_assert (last_mb_index == mb_size); + return TRUE; + +error_create_packed_slice_hdr: + { + GST_ERROR ("failed to create packed slice header buffer"); + gst_vaapi_codec_object_replace (&slice, NULL); + return FALSE; + } +error_create_packed_prefix_nal_hdr: + { + GST_ERROR ("failed to create packed prefix nal header buffer"); + gst_vaapi_codec_object_replace (&slice, NULL); + return FALSE; + } +} + +/* Generates and submits SPS header accordingly into the bitstream */ +static gboolean +ensure_sequence (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture) +{ + GstVaapiEncSequence *sequence = NULL; + + /* Insert an AU delimiter */ + if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) & + VA_ENC_PACKED_HEADER_RAW_DATA) && encoder->use_aud) { + if (!add_packed_au_delimiter (encoder, picture)) + goto error_create_packed_au_delimiter; + } + + /* submit an SPS header before every new I-frame, if codec config changed + * or if the picture is IDR. + */ + if ((!encoder->config_changed || picture->type != GST_VAAPI_PICTURE_TYPE_I) + && !GST_VAAPI_ENC_PICTURE_IS_IDR (picture)) + return TRUE; + + sequence = GST_VAAPI_ENC_SEQUENCE_NEW (H264, encoder); + if (!sequence || !fill_sequence (encoder, sequence)) + goto error_create_seq_param; + + /* add subset sps for non-base view and sps for base view */ + if (encoder->is_mvc && encoder->view_idx) { + if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) & + VA_ENC_PACKED_HEADER_SEQUENCE) + && !add_packed_sequence_header_mvc (encoder, picture, sequence)) + goto error_create_packed_seq_hdr; + } else { + if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) & + VA_ENC_PACKED_HEADER_SEQUENCE) + && !add_packed_sequence_header (encoder, picture, sequence)) + goto error_create_packed_seq_hdr; + } + + if (sequence) { + gst_vaapi_enc_picture_set_sequence (picture, sequence); + gst_vaapi_codec_object_replace (&sequence, NULL); + } + + if (!encoder->is_mvc || encoder->view_idx > 0) + encoder->config_changed = FALSE; + return TRUE; + + /* ERRORS */ +error_create_seq_param: + { + GST_ERROR ("failed to create sequence parameter buffer (SPS)"); + gst_vaapi_codec_object_replace (&sequence, NULL); + return FALSE; + } +error_create_packed_au_delimiter: + { + GST_ERROR ("failed to create AU delimiter"); + gst_vaapi_codec_object_replace (&sequence, NULL); + } +error_create_packed_seq_hdr: + { + GST_ERROR ("failed to create packed sequence header buffer"); + gst_vaapi_codec_object_replace (&sequence, NULL); + return FALSE; + } +} + +static gboolean +ensure_control_rate_params (GstVaapiEncoderH264 * encoder) +{ + if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CQP) + return TRUE; + +#if VA_CHECK_VERSION(1,1,0) + if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_ICQ) { + GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).ICQ_quality_factor = + encoder->quality_factor; + return TRUE; + } +#endif + + /* RateControl params */ + GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).bits_per_second = + encoder->bitrate_bits; + GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).window_size = encoder->cpb_length; + GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).initial_qp = encoder->init_qp; + GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).min_qp = encoder->min_qp; + +#if VA_CHECK_VERSION(1,1,0) + GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).max_qp = encoder->max_qp; +#endif + +#if VA_CHECK_VERSION(1,0,0) + GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).rc_flags.bits.mb_rate_control = + (guint) encoder->mbbrc; +#endif + +#if VA_CHECK_VERSION(1,3,0) + GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).quality_factor = + encoder->quality_factor; +#endif + + /* HRD params */ + fill_hrd_params (encoder, &GST_VAAPI_ENCODER_VA_HRD (encoder)); + + return TRUE; +} + +/* Generates additional control parameters */ +static gboolean +ensure_misc_params (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); + + if (!gst_vaapi_encoder_ensure_param_control_rate (base_encoder, picture)) + return FALSE; + + if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CBR || + GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_VBR) { + if (!encoder->view_idx) { + if ((GST_VAAPI_ENC_PICTURE_IS_IDR (picture)) && + (GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) & + VA_ENC_PACKED_HEADER_MISC) && + !add_packed_sei_header (encoder, picture, + GST_VAAPI_H264_SEI_BUF_PERIOD | GST_VAAPI_H264_SEI_PIC_TIMING)) + goto error_create_packed_sei_hdr; + + else if (!GST_VAAPI_ENC_PICTURE_IS_IDR (picture) && + (GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) & + VA_ENC_PACKED_HEADER_MISC) && + !add_packed_sei_header (encoder, picture, + GST_VAAPI_H264_SEI_PIC_TIMING)) + goto error_create_packed_sei_hdr; + } + } + + if (!gst_vaapi_encoder_ensure_param_trellis (base_encoder, picture)) + return FALSE; + + if (!gst_vaapi_encoder_ensure_param_roi_regions (base_encoder, picture)) + return FALSE; + + if (!gst_vaapi_encoder_ensure_param_quality_level (base_encoder, picture)) + return FALSE; + + return TRUE; + +error_create_packed_sei_hdr: + { + GST_ERROR ("failed to create packed SEI header"); + return FALSE; + } +} + +/* Generates and submits PPS header accordingly into the bitstream */ +static gboolean +ensure_picture (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture, + GstVaapiCodedBufferProxy * codedbuf_proxy, GstVaapiSurfaceProxy * surface) +{ + GstVaapiCodedBuffer *const codedbuf = + GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (codedbuf_proxy); + gboolean res = FALSE; + + res = fill_picture (encoder, picture, codedbuf, surface); + + if (!res) + return FALSE; + + if (picture->type == GST_VAAPI_PICTURE_TYPE_I && + (GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) & + VA_ENC_PACKED_HEADER_PICTURE) + && !add_packed_picture_header (encoder, picture)) { + GST_ERROR ("set picture packed header failed"); + return FALSE; + } + return TRUE; +} + +/* Generates slice headers */ +static gboolean +ensure_slices (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture) +{ + GstVaapiEncoderH264Ref *reflist_0[16]; + GstVaapiEncoderH264Ref *reflist_1[16]; + GstVaapiH264ViewRefPool *const ref_pool = + &encoder->ref_pools[encoder->view_idx]; + guint reflist_0_count = 0, reflist_1_count = 0; + + g_assert (picture); + + if (picture->type != GST_VAAPI_PICTURE_TYPE_I && + !reference_list_init (encoder, picture, + reflist_0, &reflist_0_count, reflist_1, &reflist_1_count)) { + GST_ERROR ("reference list reorder failed"); + return FALSE; + } + + g_assert (reflist_0_count + reflist_1_count <= ref_pool->max_ref_frames); + if (reflist_0_count > ref_pool->max_reflist0_count) + reflist_0_count = ref_pool->max_reflist0_count; + if (reflist_1_count > ref_pool->max_reflist1_count) + reflist_1_count = ref_pool->max_reflist1_count; + + if (!add_slice_headers (encoder, picture, + reflist_0, reflist_0_count, reflist_1, reflist_1_count)) + return FALSE; + + return TRUE; +} + +/* Normalizes bitrate (and CPB size) for HRD conformance */ +static void +ensure_bitrate_hrd (GstVaapiEncoderH264 * encoder) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); + guint bitrate, cpb_size; + + if (!base_encoder->bitrate) { + encoder->bitrate_bits = 0; + return; + } + + /* Round down bitrate. This is a hard limit mandated by the user */ + g_assert (SX_BITRATE >= 6); + bitrate = (base_encoder->bitrate * 1000) & ~((1U << SX_BITRATE) - 1); + if (bitrate != encoder->bitrate_bits) { + GST_DEBUG ("HRD bitrate: %u bits/sec", bitrate); + encoder->bitrate_bits = bitrate; + encoder->config_changed = TRUE; + } + + /* Round up CPB size. This is an HRD compliance detail */ + g_assert (SX_CPB_SIZE >= 4); + cpb_size = gst_util_uint64_scale (bitrate, encoder->cpb_length, 1000) & + ~((1U << SX_CPB_SIZE) - 1); + if (cpb_size != encoder->cpb_length_bits) { + GST_DEBUG ("HRD CPB size: %u bits", cpb_size); + encoder->cpb_length_bits = cpb_size; + encoder->config_changed = TRUE; + } +} + +/* Estimates a good enough bitrate if none was supplied */ +static void +ensure_bitrate (GstVaapiEncoderH264 * encoder) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); + + /* Default compression: 48 bits per macroblock in "high-compression" mode */ + switch (GST_VAAPI_ENCODER_RATE_CONTROL (encoder)) { + case GST_VAAPI_RATECONTROL_CBR: + case GST_VAAPI_RATECONTROL_VBR: + case GST_VAAPI_RATECONTROL_VBR_CONSTRAINED: + case GST_VAAPI_RATECONTROL_QVBR: + if (!base_encoder->bitrate) { + /* According to the literature and testing, CABAC entropy coding + mode could provide for +10% to +18% improvement in general, + thus estimating +15% here ; and using adaptive 8x8 transforms + in I-frames could bring up to +10% improvement. */ + guint bits_per_mb = 48; + guint64 factor; + + if (!encoder->use_cabac) + bits_per_mb += (bits_per_mb * 15) / 100; + if (!encoder->use_dct8x8) + bits_per_mb += (bits_per_mb * 10) / 100; + + factor = (guint64) encoder->mb_width * encoder->mb_height * bits_per_mb; + base_encoder->bitrate = + gst_util_uint64_scale (factor, GST_VAAPI_ENCODER_FPS_N (encoder), + GST_VAAPI_ENCODER_FPS_D (encoder)) / 1000; + GST_INFO ("target bitrate computed to %u kbps", base_encoder->bitrate); + } + break; + default: + base_encoder->bitrate = 0; + break; + } + ensure_bitrate_hrd (encoder); +} + +/* Constructs profile and level information based on user-defined limits */ +static GstVaapiEncoderStatus +ensure_profile_and_level (GstVaapiEncoderH264 * encoder) +{ + const GstVaapiProfile profile = encoder->profile; + const GstVaapiLevelH264 level = encoder->level; + + if (!ensure_tuning (encoder)) + GST_WARNING ("Failed to set some of the tuning option as expected! "); + + if (!ensure_profile (encoder) || !ensure_profile_limits (encoder)) + return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + + /* If set low-power encode entry point and hardware doesn't have + * support, it will fail in ensure_hw_profile() in later stage. */ + encoder->entrypoint = + gst_vaapi_encoder_get_entrypoint (GST_VAAPI_ENCODER_CAST (encoder), + encoder->profile); + if (encoder->entrypoint == GST_VAAPI_ENTRYPOINT_INVALID) { + GST_WARNING ("Cannot find valid entrypoint"); + return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + } + + /* Check HW constraints */ + if (!ensure_hw_profile_limits (encoder)) + return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + if (encoder->profile_idc > encoder->hw_max_profile_idc) + return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + + /* Ensure bitrate if not set already and derive the right level to use */ + ensure_bitrate (encoder); + if (!ensure_level (encoder)) + return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED; + + if (encoder->profile != profile || encoder->level != level) { + GST_DEBUG ("selected %s profile at level %s", + gst_vaapi_utils_h264_get_profile_string (encoder->profile), + gst_vaapi_utils_h264_get_level_string (encoder->level)); + encoder->config_changed = TRUE; + } + return GST_VAAPI_ENCODER_STATUS_SUCCESS; +} + +static void +reset_properties (GstVaapiEncoderH264 * encoder) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); + guint mb_size, i; + gboolean ret; + + if (encoder->idr_period < base_encoder->keyframe_period) + encoder->idr_period = base_encoder->keyframe_period; + + g_assert (encoder->min_qp <= encoder->max_qp); + if (encoder->min_qp > encoder->init_qp) + encoder->min_qp = encoder->init_qp; + if (encoder->max_qp < encoder->init_qp) + encoder->max_qp = encoder->init_qp; + + encoder->qp_i = encoder->init_qp; + + mb_size = encoder->mb_width * encoder->mb_height; + ret = gst_vaapi_encoder_ensure_num_slices (base_encoder, encoder->profile, + encoder->entrypoint, (mb_size + 1) / 2, &encoder->num_slices); + g_assert (ret); + + if (encoder->num_bframes > (base_encoder->keyframe_period + 1) / 2) + encoder->num_bframes = (base_encoder->keyframe_period + 1) / 2; + + gst_vaapi_encoder_ensure_max_num_ref_frames (base_encoder, encoder->profile, + encoder->entrypoint); + + if (base_encoder->max_num_ref_frames_1 < 1 && encoder->num_bframes > 0) { + GST_WARNING ("Disabling b-frame since the driver doesn't support it"); + encoder->num_bframes = 0; + + if (encoder->prediction_type == + GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_B) + encoder->prediction_type = GST_VAAPI_ENCODER_H264_PREDICTION_DEFAULT; + } + + if (encoder->num_ref_frames > base_encoder->max_num_ref_frames_0) { + GST_INFO ("Lowering the number of reference frames to %d", + base_encoder->max_num_ref_frames_0); + encoder->num_ref_frames = base_encoder->max_num_ref_frames_0; + } + + if (encoder->num_bframes > 0 && GST_VAAPI_ENCODER_FPS_N (encoder) > 0) + encoder->cts_offset = gst_util_uint64_scale (GST_SECOND, + GST_VAAPI_ENCODER_FPS_D (encoder), GST_VAAPI_ENCODER_FPS_N (encoder)); + else + encoder->cts_offset = 0; + + /* init max_frame_num, max_poc */ + encoder->log2_max_frame_num = + h264_get_log2_max_frame_num (encoder->idr_period); + g_assert (encoder->log2_max_frame_num >= 4); + encoder->max_frame_num = (1 << encoder->log2_max_frame_num); + encoder->log2_max_pic_order_cnt = encoder->log2_max_frame_num + 1; + encoder->max_pic_order_cnt = (1 << encoder->log2_max_pic_order_cnt); + encoder->idr_num = 0; + + /* If temporal scalability enabled then use hierarchical-p/b + * according to num_bframes as default prediction */ + if (encoder->temporal_levels > 1 + && encoder->prediction_type == + GST_VAAPI_ENCODER_H264_PREDICTION_DEFAULT) { + if (encoder->num_bframes > 0) + encoder->prediction_type = + GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_B; + else + encoder->prediction_type = + GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_P; + } + + if (encoder->prediction_type != GST_VAAPI_ENCODER_H264_PREDICTION_DEFAULT) { + + /* Hierarchical prediction should have a temporal level count + * greater than one and we use 4 temporal levels as default */ + if (encoder->temporal_levels <= 1) + encoder->temporal_levels = 4; + + /* this ip_period calculation is for supporting hierarchical-p + * and hierarchical-b encode */ + encoder->ip_period = 1 << (encoder->temporal_levels - 1); + + /* align the idr_period to ip_peroid to simplify encode process */ + encoder->idr_period = + GST_ROUND_UP_N (encoder->idr_period, encoder->ip_period); + + GST_VAAPI_ENCODER_KEYFRAME_PERIOD (base_encoder) = encoder->idr_period; + + /* Disable mvc-encode in hierarchical mode */ + if (encoder->num_views > 1) { + encoder->num_views = 1; + encoder->is_mvc = FALSE; + } + + /* no b-frames in Hierarchical-P */ + if (encoder->prediction_type == + GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_P) + encoder->num_bframes = 0; + + /* reset number of b-frames in Hierarchical-B */ + if (encoder->prediction_type == + GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_B) + encoder->num_bframes = (1 << (encoder->temporal_levels - 1)) - 1; + } else { + encoder->ip_period = GST_VAAPI_ENCODER_KEYFRAME_PERIOD (encoder) > 1 ? + (1 + encoder->num_bframes) : 0; + } + + for (i = 0; i < encoder->num_views; i++) { + GstVaapiH264ViewRefPool *const ref_pool = &encoder->ref_pools[i]; + GstVaapiH264ViewReorderPool *const reorder_pool = + &encoder->reorder_pools[i]; + + if (encoder->prediction_type == GST_VAAPI_ENCODER_H264_PREDICTION_DEFAULT) { + ref_pool->max_reflist0_count = encoder->num_ref_frames; + ref_pool->max_reflist1_count = encoder->num_bframes > 0; + ref_pool->max_ref_frames = ref_pool->max_reflist0_count + + ref_pool->max_reflist1_count; + } else { + guint d; + + /* This shouldn't be executed on MVC encoding */ + g_assert (i < 1); + + ref_pool->max_ref_frames = + encoder->temporal_levels * (encoder->temporal_levels) / 2 + + (encoder->num_bframes > 0); + ref_pool->max_reflist0_count = 1; + ref_pool->max_reflist1_count = encoder->num_bframes > 0; + encoder->num_ref_frames = ref_pool->max_ref_frames; + + d = encoder->ip_period; + /* temporal_level_div[] is helpful to find out the temporal level + * where each frame should belongs */ + for (i = 0; i < encoder->temporal_levels; i++) { + encoder->temporal_level_div[i] = d; + d >>= 1; + } + } + + reorder_pool->frame_index = 0; + } +} + +static GstVaapiEncoderStatus +gst_vaapi_encoder_h264_encode (GstVaapiEncoder * base_encoder, + GstVaapiEncPicture * picture, GstVaapiCodedBufferProxy * codedbuf) +{ + GstVaapiEncoderH264 *const encoder = GST_VAAPI_ENCODER_H264 (base_encoder); + GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN; + GstVaapiSurfaceProxy *reconstruct = NULL; + + reconstruct = gst_vaapi_encoder_create_surface (base_encoder); + + g_assert (GST_VAAPI_SURFACE_PROXY_SURFACE (reconstruct)); + + if (!ensure_sequence (encoder, picture)) + goto error; + if (!ensure_misc_params (encoder, picture)) + goto error; + if (!ensure_picture (encoder, picture, codedbuf, reconstruct)) + goto error; + if (!ensure_slices (encoder, picture)) + goto error; + if (!gst_vaapi_enc_picture_encode (picture)) + goto error; + + if (!reference_list_update (encoder, picture, reconstruct)) + goto error; + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; + + /* ERRORS */ +error: + { + if (reconstruct) + gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder), + reconstruct); + return ret; + } +} + +/* reorder_list sorting for hierarchical-b encode */ +static gint +sort_hierarchical_b (gconstpointer a, gconstpointer b, gpointer user_data) +{ + GstVaapiEncPicture *pic1 = (GstVaapiEncPicture *) a; + GstVaapiEncPicture *pic2 = (GstVaapiEncPicture *) b; + + if (pic1->type != GST_VAAPI_PICTURE_TYPE_B) + return 1; + if (pic2->type != GST_VAAPI_PICTURE_TYPE_B) + return -1; + if (pic1->temporal_id == pic2->temporal_id) + return pic1->poc - pic2->poc; + else + return pic1->temporal_id - pic2->temporal_id; +} + +struct _PendingIterState +{ + guint cur_view; + GstVaapiPictureType pic_type; +}; + +static gboolean +gst_vaapi_encoder_h264_get_pending_reordered (GstVaapiEncoder * base_encoder, + GstVaapiEncPicture ** picture, gpointer * state) +{ + GstVaapiEncoderH264 *const encoder = GST_VAAPI_ENCODER_H264 (base_encoder); + GstVaapiH264ViewReorderPool *reorder_pool; + GstVaapiEncPicture *pic = NULL; + struct _PendingIterState *iter; + + g_return_val_if_fail (state, FALSE); + + if (!*state) { + iter = g_new0 (struct _PendingIterState, 1); + iter->pic_type = GST_VAAPI_PICTURE_TYPE_P; + *state = iter; + } else { + iter = *state; + } + + *picture = NULL; + + if (iter->cur_view >= encoder->num_views) + return FALSE; + + reorder_pool = &encoder->reorder_pools[iter->cur_view]; + if (g_queue_is_empty (&reorder_pool->reorder_frame_list)) { + iter->cur_view++; + return TRUE; /* perhaps other views has pictures? */ + } + + if (iter->pic_type == GST_VAAPI_PICTURE_TYPE_P) { + pic = g_queue_pop_tail (&reorder_pool->reorder_frame_list); + g_assert (pic); + set_p_frame (pic, encoder); + + g_queue_foreach (&reorder_pool->reorder_frame_list, (GFunc) set_b_frame, + encoder); + /* sort the queued list of frames for hierarchical-b based on + * temporal level where each frame belongs */ + if (encoder->prediction_type == + GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_B) { + pic->temporal_id = 0; + GST_VAAPI_PICTURE_FLAG_SET (pic, GST_VAAPI_ENC_PICTURE_FLAG_REFERENCE); + + g_queue_sort (&reorder_pool->reorder_frame_list, sort_hierarchical_b, + NULL); + } + + iter->pic_type = GST_VAAPI_PICTURE_TYPE_B; + } else if (iter->pic_type == GST_VAAPI_PICTURE_TYPE_B) { + pic = g_queue_pop_head (&reorder_pool->reorder_frame_list); + g_assert (pic); + } else { + GST_WARNING ("Unhandled pending picture type"); + } + + set_frame_num (encoder, pic); + + if (GST_CLOCK_TIME_IS_VALID (pic->frame->pts)) + pic->frame->pts += encoder->cts_offset; + + *picture = pic; + return TRUE; +} + +static GstVaapiEncoderStatus +gst_vaapi_encoder_h264_flush (GstVaapiEncoder * base_encoder) +{ + GstVaapiEncoderH264 *const encoder = GST_VAAPI_ENCODER_H264 (base_encoder); + GstVaapiH264ViewReorderPool *reorder_pool; + GstVaapiEncPicture *pic; + guint i; + + for (i = 0; i < encoder->num_views; i++) { + reorder_pool = &encoder->reorder_pools[i]; + reorder_pool->frame_index = 0; + reorder_pool->cur_frame_num = 0; + reorder_pool->cur_present_index = 0; + reorder_pool->prev_frame_is_ref = FALSE; + + while (!g_queue_is_empty (&reorder_pool->reorder_frame_list)) { + pic = (GstVaapiEncPicture *) + g_queue_pop_head (&reorder_pool->reorder_frame_list); + gst_vaapi_enc_picture_unref (pic); + } + g_queue_clear (&reorder_pool->reorder_frame_list); + } + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; +} + +/* Generate "codec-data" buffer */ +static GstVaapiEncoderStatus +gst_vaapi_encoder_h264_get_codec_data (GstVaapiEncoder * base_encoder, + GstBuffer ** out_buffer_ptr) +{ + GstVaapiEncoderH264 *const encoder = GST_VAAPI_ENCODER_H264 (base_encoder); + const guint32 configuration_version = 0x01; + const guint32 nal_length_size = 4; + guint8 profile_idc, profile_comp, level_idc; + GstMapInfo sps_info, pps_info; + GstBitWriter bs; + GstBuffer *buffer; + + if (!encoder->sps_data || !encoder->pps_data) + return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_HEADER; + if (gst_buffer_get_size (encoder->sps_data) < 4) + return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_HEADER; + + if (!gst_buffer_map (encoder->sps_data, &sps_info, GST_MAP_READ)) + goto error_map_sps_buffer; + + if (!gst_buffer_map (encoder->pps_data, &pps_info, GST_MAP_READ)) + goto error_map_pps_buffer; + + /* skip sps_data[0], which is the nal_unit_type */ + profile_idc = sps_info.data[1]; + profile_comp = sps_info.data[2]; + level_idc = sps_info.data[3]; + + /* Header */ + gst_bit_writer_init_with_size (&bs, (sps_info.size + pps_info.size + 64), + FALSE); + WRITE_UINT32 (&bs, configuration_version, 8); + WRITE_UINT32 (&bs, profile_idc, 8); + WRITE_UINT32 (&bs, profile_comp, 8); + WRITE_UINT32 (&bs, level_idc, 8); + WRITE_UINT32 (&bs, 0x3f, 6); /* 111111 */ + WRITE_UINT32 (&bs, nal_length_size - 1, 2); + WRITE_UINT32 (&bs, 0x07, 3); /* 111 */ + + /* Write SPS */ + WRITE_UINT32 (&bs, 1, 5); /* SPS count = 1 */ + g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0); + /* Write Nal unit length and data of SPS */ + if (!gst_vaapi_utils_h26x_write_nal_unit (&bs, sps_info.data, sps_info.size)) + goto nal_to_byte_stream_error; + + /* Write PPS */ + WRITE_UINT32 (&bs, 1, 8); /* PPS count = 1 */ + /* Write Nal unit length and data of PPS */ + if (!gst_vaapi_utils_h26x_write_nal_unit (&bs, pps_info.data, pps_info.size)) + goto nal_to_byte_stream_error; + + gst_buffer_unmap (encoder->pps_data, &pps_info); + gst_buffer_unmap (encoder->sps_data, &sps_info); + + buffer = gst_bit_writer_reset_and_get_buffer (&bs); + if (!buffer) + goto error_alloc_buffer; + if (gst_buffer_n_memory (buffer) == 0) { + gst_buffer_unref (buffer); + goto error_alloc_buffer; + } + *out_buffer_ptr = buffer; + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; + + /* ERRORS */ +bs_error: + { + GST_ERROR ("failed to write codec-data"); + gst_buffer_unmap (encoder->sps_data, &sps_info); + gst_buffer_unmap (encoder->pps_data, &pps_info); + gst_bit_writer_reset (&bs); + return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED; + } +nal_to_byte_stream_error: + { + GST_ERROR ("failed to write nal unit"); + gst_buffer_unmap (encoder->sps_data, &sps_info); + gst_buffer_unmap (encoder->pps_data, &pps_info); + gst_bit_writer_reset (&bs); + return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED; + } +error_map_sps_buffer: + { + GST_ERROR ("failed to map SPS packed header"); + return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED; + } +error_map_pps_buffer: + { + GST_ERROR ("failed to map PPS packed header"); + gst_buffer_unmap (encoder->sps_data, &sps_info); + return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED; + } +error_alloc_buffer: + { + GST_ERROR ("failed to allocate codec-data buffer"); + gst_bit_writer_reset (&bs); + return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED; + } +} + +static guint32 +get_temporal_id (GstVaapiEncoderH264 * encoder, guint32 display_order) +{ + int l; + for (l = 0; l < encoder->temporal_levels; l++) { + if ((display_order % encoder->temporal_level_div[l]) == 0) + return l; + } + + GST_WARNING ("Couldn't find valid temporal id"); + return 0; +} + +static GstVaapiEncoderStatus +gst_vaapi_encoder_h264_reordering (GstVaapiEncoder * base_encoder, + GstVideoCodecFrame * frame, GstVaapiEncPicture ** output) +{ + GstVaapiEncoderH264 *const encoder = GST_VAAPI_ENCODER_H264 (base_encoder); + GstVaapiH264ViewReorderPool *reorder_pool = NULL; + GstVaapiEncPicture *picture; + gboolean is_idr = FALSE; + + *output = NULL; + + /* encoding views alternatively for MVC */ + if (encoder->is_mvc) { + /* FIXME: Use first-in-bundle flag on buffers to reset view idx? */ + if (frame) + encoder->view_idx = frame->system_frame_number % encoder->num_views; + else + encoder->view_idx = (encoder->view_idx + 1) % encoder->num_views; + } + reorder_pool = &encoder->reorder_pools[encoder->view_idx]; + + if (!frame) { + if (reorder_pool->reorder_state != GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES) + return GST_VAAPI_ENCODER_STATUS_NO_SURFACE; + + /* reorder_state = GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES + dump B frames from queue, sometime, there may also have P frame or I frame */ + g_assert (encoder->num_bframes > 0); + g_return_val_if_fail (!g_queue_is_empty (&reorder_pool->reorder_frame_list), + GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN); + + /* sort the queued list of frames for hierarchical-b based on + * temporal level where each frame belongs */ + if (encoder->prediction_type == + GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_B) + g_queue_sort (&reorder_pool->reorder_frame_list, sort_hierarchical_b, + NULL); + + picture = g_queue_pop_head (&reorder_pool->reorder_frame_list); + g_assert (picture); + if (g_queue_is_empty (&reorder_pool->reorder_frame_list)) { + reorder_pool->reorder_state = GST_VAAPI_ENC_H264_REORD_WAIT_FRAMES; + } + goto end; + } + + /* new frame coming */ + picture = GST_VAAPI_ENC_PICTURE_NEW (H264, encoder, frame); + if (!picture) { + GST_WARNING ("create H264 picture failed, frame timestamp:%" + GST_TIME_FORMAT, GST_TIME_ARGS (frame->pts)); + return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED; + } + ++reorder_pool->cur_present_index; + picture->poc = ((reorder_pool->cur_present_index * 2) % + encoder->max_pic_order_cnt); + + picture->temporal_id = (encoder->temporal_levels == 1) ? 1 : + get_temporal_id (encoder, reorder_pool->frame_index); + + is_idr = (reorder_pool->frame_index == 0 || + reorder_pool->frame_index >= encoder->idr_period); + + /* check key frames */ + if (is_idr || GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame) || + (reorder_pool->frame_index % + GST_VAAPI_ENCODER_KEYFRAME_PERIOD (encoder)) == 0) { + ++reorder_pool->frame_index; + + /* b frame enabled, check queue of reorder_frame_list */ + if (encoder->num_bframes + && !g_queue_is_empty (&reorder_pool->reorder_frame_list)) { + GstVaapiEncPicture *p_pic; + + p_pic = g_queue_pop_tail (&reorder_pool->reorder_frame_list); + set_p_frame (p_pic, encoder); + + /* for hierarchical-b, if idr-period reached , make sure the + * most recent queued frame get encoded as a reference + * p-frame in base-layer */ + if (encoder->prediction_type == + GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_B) { + p_pic->temporal_id = 0; + GST_VAAPI_PICTURE_FLAG_SET (p_pic, + GST_VAAPI_ENC_PICTURE_FLAG_REFERENCE); + } + /* Fix : make sure the detached head is non-ref, currently it is ref */ + + g_queue_foreach (&reorder_pool->reorder_frame_list, + (GFunc) set_b_frame, encoder); + set_key_frame (picture, encoder, + is_idr | GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame)); + g_queue_push_tail (&reorder_pool->reorder_frame_list, picture); + picture = p_pic; + reorder_pool->reorder_state = GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES; + } else { /* no b frames in queue */ + set_key_frame (picture, encoder, + is_idr | GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame)); + g_assert (g_queue_is_empty (&reorder_pool->reorder_frame_list)); + if (encoder->num_bframes) + reorder_pool->reorder_state = GST_VAAPI_ENC_H264_REORD_WAIT_FRAMES; + } + goto end; + } + + /* new p/b frames coming */ + ++reorder_pool->frame_index; + if (reorder_pool->reorder_state == GST_VAAPI_ENC_H264_REORD_WAIT_FRAMES && + g_queue_get_length (&reorder_pool->reorder_frame_list) < + encoder->num_bframes) { + g_queue_push_tail (&reorder_pool->reorder_frame_list, picture); + return GST_VAAPI_ENCODER_STATUS_NO_SURFACE; + } + + set_p_frame (picture, encoder); + + if (reorder_pool->reorder_state == GST_VAAPI_ENC_H264_REORD_WAIT_FRAMES) { + g_queue_foreach (&reorder_pool->reorder_frame_list, (GFunc) set_b_frame, + encoder); + reorder_pool->reorder_state = GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES; + g_assert (!g_queue_is_empty (&reorder_pool->reorder_frame_list)); + } + +end: + g_assert (picture); + frame = picture->frame; + if (GST_CLOCK_TIME_IS_VALID (frame->pts)) + frame->pts += encoder->cts_offset; + + /* set frame_num based on previous frame reference type */ + set_frame_num (encoder, picture); + + *output = picture; + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; +} + +static GstVaapiEncoderStatus +set_context_info (GstVaapiEncoder * base_encoder) +{ + GstVaapiEncoderH264 *const encoder = GST_VAAPI_ENCODER_H264 (base_encoder); + GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder); + const guint DEFAULT_SURFACES_COUNT = 3; + + /* Maximum sizes for common headers (in bits) */ + enum + { + MAX_SPS_HDR_SIZE = 16473, + MAX_VUI_PARAMS_SIZE = 210, + MAX_HRD_PARAMS_SIZE = 4103, + MAX_PPS_HDR_SIZE = 101, + MAX_SLICE_HDR_SIZE = 397 + 2572 + 6670 + 2402, + }; + + if (!ensure_hw_profile (encoder)) + return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + + base_encoder->num_ref_frames = (encoder->num_ref_frames + + (encoder->num_bframes > 0 ? 1 : 0) + DEFAULT_SURFACES_COUNT) + * encoder->num_views; + + /* Only YUV 4:2:0 formats are supported for now. This means that we + have a limit of 3200 bits per macroblock. */ + /* XXX: check profile and compute RawMbBits */ + base_encoder->codedbuf_size = (GST_ROUND_UP_16 (vip->width) * + GST_ROUND_UP_16 (vip->height) / 256) * 400; + + /* Account for SPS header */ + /* XXX: exclude scaling lists, MVC/SVC extensions */ + base_encoder->codedbuf_size += 4 + GST_ROUND_UP_8 (MAX_SPS_HDR_SIZE + + MAX_VUI_PARAMS_SIZE + 2 * MAX_HRD_PARAMS_SIZE) / 8; + + /* Account for PPS header */ + /* XXX: exclude slice groups, scaling lists, MVC/SVC extensions */ + base_encoder->codedbuf_size += 4 + GST_ROUND_UP_8 (MAX_PPS_HDR_SIZE) / 8; + + /* Account for slice header */ + base_encoder->codedbuf_size += encoder->num_slices * (4 + + GST_ROUND_UP_8 (MAX_SLICE_HDR_SIZE) / 8); + /* Some of the Intel Platforms(eg: APL) doesn't have LLC so + * the driver call cflush to ensure data consistency which is an + * expensive operation but we can still reduce the impact by + * limitting the pre-calculated coded_buffer size. This is not + * strictly following the h264 specification, but should be safe + * enough with intel-vaapi-driver. Our test cases showing significat + * performance improvement on APL platfrom with small coded-buffer size */ + if (encoder->compliance_mode == + GST_VAAPI_ENCODER_H264_COMPLIANCE_MODE_RESTRICT_CODED_BUFFER_ALLOC) + base_encoder->codedbuf_size /= encoder->min_cr; + + base_encoder->context_info.profile = base_encoder->profile; + base_encoder->context_info.entrypoint = encoder->entrypoint; + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; +} + +static GstVaapiEncoderStatus +gst_vaapi_encoder_h264_reconfigure (GstVaapiEncoder * base_encoder) +{ + GstVaapiEncoderH264 *const encoder = GST_VAAPI_ENCODER_H264 (base_encoder); + GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder); + GstVaapiEncoderStatus status; + guint mb_width, mb_height; + + mb_width = (GST_VAAPI_ENCODER_WIDTH (encoder) + 15) / 16; + mb_height = (GST_VAAPI_ENCODER_HEIGHT (encoder) + 15) / 16; + if (mb_width != encoder->mb_width || mb_height != encoder->mb_height) { + GST_DEBUG ("resolution: %dx%d", GST_VAAPI_ENCODER_WIDTH (encoder), + GST_VAAPI_ENCODER_HEIGHT (encoder)); + encoder->mb_width = mb_width; + encoder->mb_height = mb_height; + encoder->config_changed = TRUE; + } + + /* Take number of MVC views from input caps if provided */ + if (GST_VIDEO_INFO_MULTIVIEW_MODE (vip) == + GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME + || GST_VIDEO_INFO_MULTIVIEW_MODE (vip) == + GST_VIDEO_MULTIVIEW_MODE_MULTIVIEW_FRAME_BY_FRAME) + encoder->num_views = GST_VIDEO_INFO_VIEWS (vip); + + encoder->is_mvc = encoder->num_views > 1; + + status = ensure_profile_and_level (encoder); + if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) + return status; + + reset_properties (encoder); + ensure_control_rate_params (encoder); + return set_context_info (base_encoder); +} + +struct _GstVaapiEncoderH264Class +{ + GstVaapiEncoderClass parent_class; +}; + +G_DEFINE_TYPE (GstVaapiEncoderH264, gst_vaapi_encoder_h264, + GST_TYPE_VAAPI_ENCODER); + +static void +gst_vaapi_encoder_h264_init (GstVaapiEncoderH264 * encoder) +{ + guint32 i; + + /* Default encoding entrypoint */ + encoder->entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE; + + /* Multi-view coding information */ + encoder->is_mvc = FALSE; + encoder->num_views = 1; + encoder->view_idx = 0; + encoder->temporal_levels = MIN_TEMPORAL_LEVELS; + encoder->abs_diff_pic_num_list0 = 1; + encoder->abs_diff_pic_num_list1 = 1; + memset (encoder->view_ids, 0, sizeof (encoder->view_ids)); + + /* re-ordering list initialize */ + for (i = 0; i < MAX_NUM_VIEWS; i++) { + GstVaapiH264ViewReorderPool *const reorder_pool = + &encoder->reorder_pools[i]; + g_queue_init (&reorder_pool->reorder_frame_list); + reorder_pool->reorder_state = GST_VAAPI_ENC_H264_REORD_NONE; + reorder_pool->frame_index = 0; + reorder_pool->cur_frame_num = 0; + reorder_pool->cur_present_index = 0; + } + + /* reference list info initialize */ + for (i = 0; i < MAX_NUM_VIEWS; i++) { + GstVaapiH264ViewRefPool *const ref_pool = &encoder->ref_pools[i]; + g_queue_init (&ref_pool->ref_list); + ref_pool->max_ref_frames = 0; + ref_pool->max_reflist0_count = 1; + ref_pool->max_reflist1_count = 1; + } + + encoder->compliance_mode = GST_VAAPI_ENCODER_H264_COMPLIANCE_MODE_STRICT; + encoder->min_cr = 1; +} + +static void +gst_vaapi_encoder_h264_finalize (GObject * object) +{ + /*free private buffers */ + GstVaapiEncoderH264 *const encoder = GST_VAAPI_ENCODER_H264 (object); + GstVaapiEncPicture *pic; + GstVaapiEncoderH264Ref *ref; + guint32 i; + + gst_buffer_replace (&encoder->sps_data, NULL); + gst_buffer_replace (&encoder->subset_sps_data, NULL); + gst_buffer_replace (&encoder->pps_data, NULL); + + /* reference list info de-init */ + for (i = 0; i < MAX_NUM_VIEWS; i++) { + GstVaapiH264ViewRefPool *const ref_pool = &encoder->ref_pools[i]; + while (!g_queue_is_empty (&ref_pool->ref_list)) { + ref = (GstVaapiEncoderH264Ref *) g_queue_pop_head (&ref_pool->ref_list); + reference_pic_free (encoder, ref); + } + g_queue_clear (&ref_pool->ref_list); + } + + /* re-ordering list initialize */ + for (i = 0; i < MAX_NUM_VIEWS; i++) { + GstVaapiH264ViewReorderPool *const reorder_pool = + &encoder->reorder_pools[i]; + while (!g_queue_is_empty (&reorder_pool->reorder_frame_list)) { + pic = (GstVaapiEncPicture *) + g_queue_pop_head (&reorder_pool->reorder_frame_list); + gst_vaapi_enc_picture_unref (pic); + } + g_queue_clear (&reorder_pool->reorder_frame_list); + } + + G_OBJECT_CLASS (gst_vaapi_encoder_h264_parent_class)->finalize (object); +} + +static void +set_view_ids (GstVaapiEncoderH264 * const encoder, const GValue * value) +{ + guint i, j; + guint len = gst_value_array_get_size (value); + + if (len == 0) + goto set_default_ids; + + if (len != encoder->num_views) { + GST_WARNING ("The view number is %d, but %d view IDs are provided. Just " + "fallback to use default view IDs.", encoder->num_views, len); + goto set_default_ids; + } + + for (i = 0; i < len; i++) { + const GValue *val = gst_value_array_get_value (value, i); + encoder->view_ids[i] = g_value_get_uint (val); + } + + /* check whether duplicated ID */ + for (i = 0; i < len; i++) { + for (j = i + 1; j < len; j++) { + if (encoder->view_ids[i] == encoder->view_ids[j]) { + GST_WARNING ("The view %d and view %d have same view ID %d. Just " + "fallback to use default view IDs.", i, j, encoder->view_ids[i]); + goto set_default_ids; + } + } + } + + return; + +set_default_ids: + { + for (i = 0; i < encoder->num_views; i++) + encoder->view_ids[i] = i; + } +} + +static void +get_view_ids (GstVaapiEncoderH264 * const encoder, GValue * value) +{ + guint i; + GValue id = G_VALUE_INIT; + + g_value_reset (value); + g_value_init (&id, G_TYPE_UINT); + + for (i = 0; i < encoder->num_views; i++) { + g_value_set_uint (&id, encoder->view_ids[i]); + gst_value_array_append_value (value, &id); + } + g_value_unset (&id); +} + +/** + * @ENCODER_H264_PROP_RATECONTROL: Rate control (#GstVaapiRateControl). + * @ENCODER_H264_PROP_TUNE: The tuning options (#GstVaapiEncoderTune). + * @ENCODER_H264_PROP_MAX_BFRAMES: Number of B-frames between I + * and P (uint). + * @ENCODER_H264_PROP_INIT_QP: Initial quantizer value (uint). + * @ENCODER_H264_PROP_MIN_QP: Minimal quantizer value (uint). + * @ENCODER_H264_PROP_NUM_SLICES: Number of slices per frame (uint). + * @ENCODER_H264_PROP_CABAC: Enable CABAC entropy coding mode (bool). + * @ENCODER_H264_PROP_DCT8X8: Enable adaptive use of 8x8 + * transforms in I-frames (bool). + * @ENCODER_H264_PROP_CPB_LENGTH: Length of the CPB buffer + * in milliseconds (uint). + * @ENCODER_H264_PROP_NUM_VIEWS: Number of views per frame. + * @ENCODER_H264_PROP_VIEW_IDS: View IDs + * @ENCODER_H264_PROP_AUD: Insert AUD as first NAL per frame. + * @ENCODER_H264_PROP_COMPLIANCE_MODE: Relax Compliance restrictions + * @ENCODER_H264_PROP_NUM_REF_FRAMES: Maximum number of reference frames. + * @ENCODER_H264_PROP_MBBRC: Macroblock level Bitrate Control. + * @ENCODER_H264_PROP_QP_IP: Difference of QP between I and P frame. + * @ENCODER_H264_PROP_QP_IB: Difference of QP between I and B frame. + * @ENCODER_H264_PROP_TEMPORAL_LEVELS: Number of temporal levels + * @ENCODER_H264_PROP_PREDICTION_TYPE: Reference picture selection modes + * @ENCODER_H264_PROP_MAX_QP: Maximal quantizer value (uint). + * @ENCODER_H264_PROP_QUALITY_FACTOR: Factor for ICQ/QVBR bitrate control mode. + * + * The set of H.264 encoder specific configurable properties. + */ +enum +{ + ENCODER_H264_PROP_RATECONTROL = 1, + ENCODER_H264_PROP_TUNE, + ENCODER_H264_PROP_MAX_BFRAMES, + ENCODER_H264_PROP_INIT_QP, + ENCODER_H264_PROP_MIN_QP, + ENCODER_H264_PROP_NUM_SLICES, + ENCODER_H264_PROP_CABAC, + ENCODER_H264_PROP_DCT8X8, + ENCODER_H264_PROP_CPB_LENGTH, + ENCODER_H264_PROP_NUM_VIEWS, + ENCODER_H264_PROP_VIEW_IDS, + ENCODER_H264_PROP_AUD, + ENCODER_H264_PROP_COMPLIANCE_MODE, + ENCODER_H264_PROP_NUM_REF_FRAMES, + ENCODER_H264_PROP_MBBRC, + ENCODER_H264_PROP_QP_IP, + ENCODER_H264_PROP_QP_IB, + ENCODER_H264_PROP_TEMPORAL_LEVELS, + ENCODER_H264_PROP_PREDICTION_TYPE, + ENCODER_H264_PROP_MAX_QP, + ENCODER_H264_PROP_QUALITY_FACTOR, + ENCODER_H264_N_PROPERTIES +}; + +static GParamSpec *properties[ENCODER_H264_N_PROPERTIES]; + +static void +gst_vaapi_encoder_h264_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstVaapiEncoderH264 *const encoder = GST_VAAPI_ENCODER_H264 (object); + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object); + + if (base_encoder->num_codedbuf_queued > 0) { + GST_ERROR_OBJECT (object, + "failed to set any property after encoding started"); + return; + } + + switch (prop_id) { + case ENCODER_H264_PROP_RATECONTROL: + gst_vaapi_encoder_set_rate_control (base_encoder, + g_value_get_enum (value)); + break; + case ENCODER_H264_PROP_TUNE: + gst_vaapi_encoder_set_tuning (base_encoder, g_value_get_enum (value)); + break; + case ENCODER_H264_PROP_MAX_BFRAMES: + encoder->num_bframes = g_value_get_uint (value); + break; + case ENCODER_H264_PROP_INIT_QP: + encoder->init_qp = g_value_get_uint (value); + break; + case ENCODER_H264_PROP_MIN_QP: + encoder->min_qp = g_value_get_uint (value); + break; + case ENCODER_H264_PROP_QP_IP: + encoder->qp_ip = g_value_get_int (value); + break; + case ENCODER_H264_PROP_QP_IB: + encoder->qp_ib = g_value_get_int (value); + break; + case ENCODER_H264_PROP_NUM_SLICES: + encoder->num_slices = g_value_get_uint (value); + break; + case ENCODER_H264_PROP_CABAC: + encoder->use_cabac = g_value_get_boolean (value); + break; + case ENCODER_H264_PROP_DCT8X8: + encoder->use_dct8x8 = g_value_get_boolean (value); + break; + case ENCODER_H264_PROP_CPB_LENGTH: + encoder->cpb_length = g_value_get_uint (value); + break; + case ENCODER_H264_PROP_NUM_VIEWS: + encoder->num_views = g_value_get_uint (value); + break; + case ENCODER_H264_PROP_VIEW_IDS: + set_view_ids (encoder, value); + break; + case ENCODER_H264_PROP_AUD: + encoder->use_aud = g_value_get_boolean (value); + break; + case ENCODER_H264_PROP_COMPLIANCE_MODE: + encoder->compliance_mode = g_value_get_enum (value); + break; + case ENCODER_H264_PROP_NUM_REF_FRAMES: + encoder->num_ref_frames = g_value_get_uint (value); + break; + case ENCODER_H264_PROP_MBBRC: + encoder->mbbrc = g_value_get_enum (value); + break; + case ENCODER_H264_PROP_TEMPORAL_LEVELS: + encoder->temporal_levels = g_value_get_uint (value); + break; + case ENCODER_H264_PROP_PREDICTION_TYPE: + encoder->prediction_type = g_value_get_enum (value); + break; + case ENCODER_H264_PROP_MAX_QP: + encoder->max_qp = g_value_get_uint (value); + break; + case ENCODER_H264_PROP_QUALITY_FACTOR: + encoder->quality_factor = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gst_vaapi_encoder_h264_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstVaapiEncoderH264 *const encoder = GST_VAAPI_ENCODER_H264 (object); + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object); + + switch (prop_id) { + case ENCODER_H264_PROP_RATECONTROL: + g_value_set_enum (value, base_encoder->rate_control); + break; + case ENCODER_H264_PROP_TUNE: + g_value_set_enum (value, base_encoder->tune); + break; + case ENCODER_H264_PROP_MAX_BFRAMES: + g_value_set_uint (value, encoder->num_bframes); + break; + case ENCODER_H264_PROP_INIT_QP: + g_value_set_uint (value, encoder->init_qp); + break; + case ENCODER_H264_PROP_MIN_QP: + g_value_set_uint (value, encoder->min_qp); + break; + case ENCODER_H264_PROP_QP_IP: + g_value_set_int (value, encoder->qp_ip); + break; + case ENCODER_H264_PROP_QP_IB: + g_value_set_int (value, encoder->qp_ib); + break; + case ENCODER_H264_PROP_NUM_SLICES: + g_value_set_uint (value, encoder->num_slices); + break; + case ENCODER_H264_PROP_CABAC: + g_value_set_boolean (value, encoder->use_cabac); + break; + case ENCODER_H264_PROP_DCT8X8: + g_value_set_boolean (value, encoder->use_dct8x8); + break; + case ENCODER_H264_PROP_CPB_LENGTH: + g_value_set_uint (value, encoder->cpb_length); + break; + case ENCODER_H264_PROP_NUM_VIEWS: + g_value_set_uint (value, encoder->num_views); + break; + case ENCODER_H264_PROP_VIEW_IDS: + get_view_ids (encoder, value); + break; + case ENCODER_H264_PROP_AUD: + g_value_set_boolean (value, encoder->use_aud); + break; + case ENCODER_H264_PROP_COMPLIANCE_MODE: + g_value_set_enum (value, encoder->compliance_mode); + break; + case ENCODER_H264_PROP_NUM_REF_FRAMES: + g_value_set_uint (value, encoder->num_ref_frames); + break; + case ENCODER_H264_PROP_MBBRC: + g_value_set_enum (value, encoder->mbbrc); + break; + case ENCODER_H264_PROP_TEMPORAL_LEVELS: + g_value_set_uint (value, encoder->temporal_levels); + break; + case ENCODER_H264_PROP_PREDICTION_TYPE: + g_value_set_enum (value, encoder->prediction_type); + break; + case ENCODER_H264_PROP_MAX_QP: + g_value_set_uint (value, encoder->max_qp); + break; + case ENCODER_H264_PROP_QUALITY_FACTOR: + g_value_set_uint (value, encoder->quality_factor); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +GST_VAAPI_ENCODER_DEFINE_CLASS_DATA (H264); + +static void +gst_vaapi_encoder_h264_class_init (GstVaapiEncoderH264Class * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstVaapiEncoderClass *const encoder_class = GST_VAAPI_ENCODER_CLASS (klass); + + encoder_class->class_data = &g_class_data; + encoder_class->reconfigure = gst_vaapi_encoder_h264_reconfigure; + encoder_class->reordering = gst_vaapi_encoder_h264_reordering; + encoder_class->encode = gst_vaapi_encoder_h264_encode; + encoder_class->flush = gst_vaapi_encoder_h264_flush; + encoder_class->get_codec_data = gst_vaapi_encoder_h264_get_codec_data; + encoder_class->get_pending_reordered = + gst_vaapi_encoder_h264_get_pending_reordered; + + object_class->set_property = gst_vaapi_encoder_h264_set_property; + object_class->get_property = gst_vaapi_encoder_h264_get_property; + object_class->finalize = gst_vaapi_encoder_h264_finalize; + + /** + * GstVaapiEncoderH264:rate-control: + * + * The desired rate control mode, expressed as a #GstVaapiRateControl. + */ + properties[ENCODER_H264_PROP_RATECONTROL] = + g_param_spec_enum ("rate-control", + "Rate Control", "Rate control mode", + g_class_data.rate_control_get_type (), + g_class_data.default_rate_control, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH264:tune: + * + * The desired encoder tuning option. + */ + properties[ENCODER_H264_PROP_TUNE] = + g_param_spec_enum ("tune", + "Encoder Tuning", + "Encoder tuning option", + g_class_data.encoder_tune_get_type (), + g_class_data.default_encoder_tune, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH264:max-bframes: + * + * The number of B-frames between I and P. + */ + properties[ENCODER_H264_PROP_MAX_BFRAMES] = + g_param_spec_uint ("max-bframes", + "Max B-Frames", "Number of B-frames between I and P", 0, 10, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH264:refs: + * + * The number of reference frames. + * If B frame is encoded, it will add 1 reference frame more. + */ + properties[ENCODER_H264_PROP_NUM_REF_FRAMES] = + g_param_spec_uint ("refs", "Number of Reference Frames", + "Number of reference frames", 1, 8, 1, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH264:init-qp: + * + * The initial quantizer value. + */ + properties[ENCODER_H264_PROP_INIT_QP] = + g_param_spec_uint ("init-qp", + "Initial QP", "Initial quantizer value", 0, 51, 26, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH264:min-qp: + * + * The minimum quantizer value. + */ + properties[ENCODER_H264_PROP_MIN_QP] = + g_param_spec_uint ("min-qp", + "Minimum QP", "Minimum quantizer value", 0, 51, 1, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH264:max-qp: + * + * The maximum quantizer value. + * + * Since: 1.18 + */ + properties[ENCODER_H264_PROP_MAX_QP] = + g_param_spec_uint ("max-qp", + "Maximum QP", "Maximum quantizer value", 0, 51, 51, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH264:qp-ip: + * + * The difference of QP between I and P Frame. + * This is available only on CQP mode. + */ + properties[ENCODER_H264_PROP_QP_IP] = + g_param_spec_int ("qp-ip", + "Difference of QP between I and P frame", + "Difference of QP between I and P frame (available only on CQP)", + -51, 51, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH264:qp-ib: + * + * The difference of QP between I and B Frame. + * This is available only on CQP mode. + */ + properties[ENCODER_H264_PROP_QP_IB] = + g_param_spec_int ("qp-ib", + "Difference of QP between I and B frame", + "Difference of QP between I and B frame (available only on CQP)", + -51, 51, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH264:num-slices: + * + * The number of slices per frame. + */ + properties[ENCODER_H264_PROP_NUM_SLICES] = + g_param_spec_uint ("num-slices", + "Number of Slices", + "Number of slices per frame", + 1, 200, 1, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH264:cabac: + * + * Enable CABAC entropy coding mode for improved compression ratio, + * at the expense that the minimum target profile is Main. Default + * is CAVLC entropy coding mode. + */ + properties[ENCODER_H264_PROP_CABAC] = + g_param_spec_boolean ("cabac", + "Enable CABAC", + "Enable CABAC entropy coding mode", + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH264:dct8x8: + * + * Enable adaptive use of 8x8 transforms in I-frames. This improves + * the compression ratio by the minimum target profile is High. + * Default is to use 4x4 DCT only. + */ + properties[ENCODER_H264_PROP_DCT8X8] = + g_param_spec_boolean ("dct8x8", + "Enable 8x8 DCT", + "Enable adaptive use of 8x8 transforms in I-frames", + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH264:mbbrc: + * + * Macroblock level bitrate control. + * This is not compatible with Constant QP rate control. + */ + properties[ENCODER_H264_PROP_MBBRC] = + g_param_spec_enum ("mbbrc", + "Macroblock level Bitrate Control", + "Macroblock level Bitrate Control", + GST_VAAPI_TYPE_ENCODER_MBBRC, GST_VAAPI_ENCODER_MBBRC_AUTO, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH264:temporal-levels: + * + * Number of temporal levels in the encoded stream. + */ + properties[ENCODER_H264_PROP_TEMPORAL_LEVELS] = + g_param_spec_uint ("temporal-levels", + "temporal levels", + "Number of temporal levels in the encoded stream ", + MIN_TEMPORAL_LEVELS, MAX_TEMPORAL_LEVELS, MIN_TEMPORAL_LEVELS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH264:prediction-type: + * + * Select the referece picture selection modes + */ + properties[ENCODER_H264_PROP_PREDICTION_TYPE] = + g_param_spec_enum ("prediction-type", + "RefPic Selection", + "Reference Picture Selection Modes", + gst_vaapi_encoder_h264_prediction_type (), + GST_VAAPI_ENCODER_H264_PREDICTION_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH264:cpb-length: + * + * The size of the CPB buffer in milliseconds. + */ + properties[ENCODER_H264_PROP_CPB_LENGTH] = + g_param_spec_uint ("cpb-length", + "CPB Length", "Length of the CPB buffer in milliseconds", + 1, 10000, DEFAULT_CPB_LENGTH, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH264:num-views: + * + * The number of views for MVC encoding . + */ + properties[ENCODER_H264_PROP_NUM_VIEWS] = + g_param_spec_uint ("num-views", + "Number of Views", + "Number of Views for MVC encoding", + 1, MAX_NUM_VIEWS, 1, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH264:view-ids: + * + * The view ids for MVC encoding . + */ + properties[ENCODER_H264_PROP_VIEW_IDS] = + gst_param_spec_array ("view-ids", + "View IDs", "Set of View Ids used for MVC encoding", + g_param_spec_uint ("view-id-value", "View id value", + "view id values used for mvc encoding", 0, MAX_VIEW_ID, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS), + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH264:aud: + * + * Use AU (Access Unit) delimeter. + */ + properties[ENCODER_H264_PROP_AUD] = + g_param_spec_boolean ("aud", "AU delimiter", + "Use AU (Access Unit) delimeter", FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH264:Compliance Mode: + * + * Encode Tuning(Tweaking) with different compliance modes . + * + * + */ + properties[ENCODER_H264_PROP_COMPLIANCE_MODE] = + g_param_spec_enum ("compliance-mode", + "Spec Compliance Mode", + "Tune Encode quality/performance by relaxing specification" + " compliance restrictions", + gst_vaapi_encoder_h264_compliance_mode_type (), + GST_VAAPI_ENCODER_H264_COMPLIANCE_MODE_STRICT, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH264:quality_factor: + * + * quality factor used under ICQ/QVBR bitrate control mode. + */ + properties[ENCODER_H264_PROP_QUALITY_FACTOR] = + g_param_spec_uint ("quality-factor", + "Quality factor for ICQ/QVBR", + "quality factor for ICQ/QVBR bitrate control mode" + "(low value means higher-quality, higher value means lower-quality)", + 1, 51, 26, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + g_object_class_install_properties (object_class, ENCODER_H264_N_PROPERTIES, + properties); + + gst_type_mark_as_plugin_api (GST_VAAPI_TYPE_ENCODER_MBBRC, 0); + gst_type_mark_as_plugin_api (gst_vaapi_encoder_h264_prediction_type (), 0); + gst_type_mark_as_plugin_api (g_class_data.rate_control_get_type (), 0); + gst_type_mark_as_plugin_api (g_class_data.encoder_tune_get_type (), 0); + gst_type_mark_as_plugin_api (gst_vaapi_encoder_h264_compliance_mode_type (), + 0); +} + +/** + * gst_vaapi_encoder_h264_new: + * @display: a #GstVaapiDisplay + * + * Creates a new #GstVaapiEncoder for H.264 encoding. Note that the + * only supported output stream format is "byte-stream" format. + * + * Return value: the newly allocated #GstVaapiEncoder object + */ +GstVaapiEncoder * +gst_vaapi_encoder_h264_new (GstVaapiDisplay * display) +{ + return g_object_new (GST_TYPE_VAAPI_ENCODER_H264, "display", display, NULL); +} + +/** + * gst_vaapi_encoder_h264_set_max_profile: + * @encoder: a #GstVaapiEncoderH264 + * @profile: an H.264 #GstVaapiProfile + * + * Notifies the @encoder to use coding tools from the supplied + * @profile at most. + * + * This means that if the minimal profile derived to + * support the specified coding tools is greater than this @profile, + * then an error is returned when the @encoder is configured. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_encoder_h264_set_max_profile (GstVaapiEncoderH264 * encoder, + GstVaapiProfile profile) +{ + guint8 profile_idc; + + g_return_val_if_fail (encoder != NULL, FALSE); + g_return_val_if_fail (profile != GST_VAAPI_PROFILE_UNKNOWN, FALSE); + + if (gst_vaapi_profile_get_codec (profile) != GST_VAAPI_CODEC_H264) + return FALSE; + + profile_idc = gst_vaapi_utils_h264_get_profile_idc (profile); + if (!profile_idc) + return FALSE; + + encoder->max_profile_idc = profile_idc; + return TRUE; +} + +/** + * gst_vaapi_encoder_h264_get_profile_and_level: + * @encoder: a #GstVaapiEncoderH264 + * @out_profile_ptr: return location for the #GstVaapiProfile + * @out_level_ptr: return location for the #GstVaapiLevelH264 + * + * Queries the H.264 @encoder for the active profile and level. That + * information is only constructed and valid after the encoder is + * configured, i.e. after the gst_vaapi_encoder_set_codec_state() + * function is called. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_encoder_h264_get_profile_and_level (GstVaapiEncoderH264 * encoder, + GstVaapiProfile * out_profile_ptr, GstVaapiLevelH264 * out_level_ptr) +{ + g_return_val_if_fail (encoder != NULL, FALSE); + + if (!encoder->profile || !encoder->level) + return FALSE; + + if (out_profile_ptr) + *out_profile_ptr = encoder->profile; + if (out_level_ptr) + *out_level_ptr = encoder->level; + return TRUE; +} + +/** + * gst_vaapi_encoder_h264_supports_avc: + * @encoder: a #GstVaapiEncoderH264 + * + * Queries the H.264 @encoder if it supports the generation of avC + * stream format. + * + * Returns: %TRUE if @encoder supports avC; %FALSE otherwise + **/ +gboolean +gst_vaapi_encoder_h264_supports_avc (GstVaapiEncoderH264 * encoder) +{ + return ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) & + (VA_ENC_PACKED_HEADER_SEQUENCE | VA_ENC_PACKED_HEADER_PICTURE)) == + (VA_ENC_PACKED_HEADER_SEQUENCE | VA_ENC_PACKED_HEADER_PICTURE)); +} diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_h264.h b/gst-libs/gst/vaapi/gstvaapiencoder_h264.h new file mode 100644 index 0000000000..fc5539f8c5 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder_h264.h @@ -0,0 +1,63 @@ +/* + * gstvaapiencoder_h264.h - H.264 encoder + * + * Copyright (C) 2011-2014 Intel Corporation + * Author: Wind Yuan + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_ENCODER_H264_H +#define GST_VAAPI_ENCODER_H264_H + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_ENCODER_H264 \ + (gst_vaapi_encoder_h264_get_type ()) +#define GST_VAAPI_ENCODER_H264(encoder) \ + (G_TYPE_CHECK_INSTANCE_CAST ((encoder), GST_TYPE_VAAPI_ENCODER_H264, GstVaapiEncoderH264)) +#define GST_IS_VAAPI_ENCODER_H264(encoder) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((encoder), GST_TYPE_VAAPI_ENCODER_H264)) + +typedef struct _GstVaapiEncoderH264 GstVaapiEncoderH264; +typedef struct _GstVaapiEncoderH264Class GstVaapiEncoderH264Class; + +GType +gst_vaapi_encoder_h264_get_type (void) G_GNUC_CONST; + +GstVaapiEncoder * +gst_vaapi_encoder_h264_new (GstVaapiDisplay * display); + +gboolean +gst_vaapi_encoder_h264_set_max_profile (GstVaapiEncoderH264 * encoder, + GstVaapiProfile profile); + +gboolean +gst_vaapi_encoder_h264_get_profile_and_level (GstVaapiEncoderH264 * encoder, + GstVaapiProfile * out_profile_ptr, GstVaapiLevelH264 * out_level_ptr); + +gboolean +gst_vaapi_encoder_h264_supports_avc (GstVaapiEncoderH264 * encoder); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiEncoderH264, gst_object_unref) + +G_END_DECLS + +#endif /*GST_VAAPI_ENCODER_H264_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_h265.c b/gst-libs/gst/vaapi/gstvaapiencoder_h265.c new file mode 100644 index 0000000000..caec85f041 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder_h265.c @@ -0,0 +1,4004 @@ +/* + * gstvaapiencoder_h265.c - H.265 encoder + * + * Copyright (C) 2015 Intel Corporation + * Author: Sreerenj Balachandran + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include +#include +#include +#include "gstvaapicompat.h" +#include "gstvaapiencoder_priv.h" +#include "gstvaapiencoder_h265.h" +#include "gstvaapiutils_h265.h" +#include "gstvaapiutils_h265_priv.h" +#include "gstvaapiutils_h26x_priv.h" +#include "gstvaapicodedbufferproxy_priv.h" +#include "gstvaapisurface.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +/* Supported set of VA rate controls, within this implementation */ +#define SUPPORTED_RATECONTROLS \ + (GST_VAAPI_RATECONTROL_MASK (CQP) | \ + GST_VAAPI_RATECONTROL_MASK (CBR) | \ + GST_VAAPI_RATECONTROL_MASK (VBR) | \ + GST_VAAPI_RATECONTROL_MASK (ICQ) | \ + GST_VAAPI_RATECONTROL_MASK (QVBR)) + +/* Supported set of tuning options, within this implementation */ +#define SUPPORTED_TUNE_OPTIONS \ + (GST_VAAPI_ENCODER_TUNE_MASK (NONE) | \ + GST_VAAPI_ENCODER_TUNE_MASK (LOW_POWER)) + +/* Supported set of VA packed headers, within this implementation */ +#define SUPPORTED_PACKED_HEADERS \ + (VA_ENC_PACKED_HEADER_SEQUENCE | \ + VA_ENC_PACKED_HEADER_PICTURE | \ + VA_ENC_PACKED_HEADER_SLICE) + +typedef struct +{ + GstVaapiSurfaceProxy *pic; + guint poc; +} GstVaapiEncoderH265Ref; + +typedef enum +{ + GST_VAAPI_ENC_H265_REORD_NONE = 0, + GST_VAAPI_ENC_H265_REORD_DUMP_FRAMES = 1, + GST_VAAPI_ENC_H265_REORD_WAIT_FRAMES = 2 +} GstVaapiEncH265ReorderState; + +typedef struct _GstVaapiH265RefPool +{ + GQueue ref_list; + guint max_ref_frames; + guint max_reflist0_count; + guint max_reflist1_count; +} GstVaapiH265RefPool; + +typedef struct _GstVaapiH265ReorderPool +{ + GQueue reorder_frame_list; + guint reorder_state; + guint frame_index; + guint cur_present_index; +} GstVaapiH265ReorderPool; + +/* ------------------------------------------------------------------------- */ +/* --- H.265 Encoder --- */ +/* ------------------------------------------------------------------------- */ + +struct _GstVaapiEncoderH265 +{ + GstVaapiEncoder parent_instance; + + GstVaapiProfile profile; + GstVaapiTierH265 tier; + GstVaapiLevelH265 level; + GstVaapiEntrypoint entrypoint; + guint8 profile_idc; + GArray *allowed_profiles; + guint8 level_idc; + guint32 idr_period; + guint32 init_qp; + guint32 min_qp; + guint32 max_qp; + guint32 qp_i; + guint32 qp_ip; + guint32 qp_ib; + guint32 num_slices; + guint32 num_bframes; + guint32 ctu_width; /* CTU == Coding Tree Unit */ + guint32 ctu_height; + guint32 luma_width; + guint32 luma_height; + guint32 quality_factor; + GstClockTime cts_offset; + gboolean config_changed; + /* Always need two reference lists for inter frame */ + gboolean no_p_frame; + guint32 num_tile_cols; + guint32 num_tile_rows; + /* CTUs start address used in stream pack */ + guint32 *tile_slice_address; + /* CTUs in this slice */ + guint32 *tile_slice_ctu_num; + /* map the tile_slice_address to CTU start address in picture, + which is used by VA API. */ + guint32 *tile_slice_address_map; + + /* maximum required size of the decoded picture buffer */ + guint32 max_dec_pic_buffering; + /* maximum allowed number of pictures that can precede any picture in + * the CVS in decoding order and follow that picture in output order */ + guint32 max_num_reorder_pics; + + /* frame, poc */ + guint32 max_pic_order_cnt; + guint32 log2_max_pic_order_cnt; + guint32 idr_num; + guint num_ref_frames; + + GstBuffer *vps_data; + GstBuffer *sps_data; + GstBuffer *pps_data; + + guint bitrate_bits; // bitrate (bits) + guint cpb_length; // length of CPB buffer (ms) + guint cpb_length_bits; // length of CPB buffer (bits) + GstVaapiEncoderMbbrc mbbrc; // macroblock bitrate control + + /* Crop rectangle */ + guint conformance_window_flag:1; + guint32 conf_win_left_offset; + guint32 conf_win_right_offset; + guint32 conf_win_top_offset; + guint32 conf_win_bottom_offset; + + GstVaapiH265RefPool ref_pool; + GstVaapiH265ReorderPool reorder_pool; + guint first_slice_segment_in_pic_flag:1; + guint sps_temporal_mvp_enabled_flag:1; + guint sample_adaptive_offset_enabled_flag:1; +}; + +static inline gboolean +_poc_greater_than (guint poc1, guint poc2, guint max_poc) +{ + return (((poc1 - poc2) & (max_poc - 1)) < max_poc / 2); +} + +/* Get slice_type value for H.265 specification */ +static guint8 +h265_get_slice_type (GstVaapiPictureType type) +{ + switch (type) { + case GST_VAAPI_PICTURE_TYPE_I: + return GST_H265_I_SLICE; + case GST_VAAPI_PICTURE_TYPE_P: + return GST_H265_P_SLICE; + case GST_VAAPI_PICTURE_TYPE_B: + return GST_H265_B_SLICE; + default: + break; + } + return -1; +} + +static gboolean +h265_is_scc (GstVaapiEncoderH265 * encoder) +{ + if (encoder->profile == GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN || + encoder->profile == GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_10 || + encoder->profile == GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444 || + encoder->profile == GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444_10) + return TRUE; + + return FALSE; +} + +static gboolean +h265_is_tile_enabled (GstVaapiEncoderH265 * encoder) +{ + return encoder->num_tile_cols * encoder->num_tile_rows > 1; +} + +/* Get log2_max_pic_order_cnt value for H.265 specification */ +static guint +h265_get_log2_max_pic_order_cnt (guint num) +{ + guint ret = 0; + + while (num) { + ++ret; + num >>= 1; + } + if (ret <= 4) + ret = 4; + else if (ret > 16) + ret = 16; + /* must be greater than 4 */ + return ret; +} + +/* Write the NAL unit header */ +static gboolean +bs_write_nal_header (GstBitWriter * bs, guint32 nal_unit_type) +{ + guint8 nuh_layer_id = 0; + guint8 nuh_temporal_id_plus1 = 1; + + WRITE_UINT32 (bs, 0, 1); + WRITE_UINT32 (bs, nal_unit_type, 6); + WRITE_UINT32 (bs, nuh_layer_id, 6); + WRITE_UINT32 (bs, nuh_temporal_id_plus1, 3); + + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write NAL unit header"); + return FALSE; + } +} + +/* Write the NAL unit trailing bits */ +static gboolean +bs_write_trailing_bits (GstBitWriter * bs) +{ + if (!gst_bit_writer_put_bits_uint32 (bs, 1, 1)) + goto bs_error; + gst_bit_writer_align_bytes_unchecked (bs, 0); + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write NAL unit trailing bits"); + return FALSE; + } +} + +/* Write profile_tier_level() */ +static gboolean +bs_write_profile_tier_level (GstBitWriter * bs, + const VAEncSequenceParameterBufferHEVC * seq_param, GstVaapiProfile profile) +{ + guint i; + + /* general_profile_space */ + WRITE_UINT32 (bs, 0, 2); + /* general_tier_flag */ + WRITE_UINT32 (bs, seq_param->general_tier_flag, 1); + /* general_profile_idc */ + WRITE_UINT32 (bs, seq_param->general_profile_idc, 5); + + /* general_profile_compatibility_flag[0] */ + WRITE_UINT32 (bs, 0, 1); + /* general_profile_compatibility_flag[1] */ + if (seq_param->general_profile_idc == 1 /* Main profile */ + /* In A.3.4, NOTE: When general_profile_compatibility_flag[ 3 ] is equal + to 1, general_profile_compatibility_flag[ 1 ] and + general_profile_compatibility_flag[ 2 ] should also be equal to 1. */ + || seq_param->general_profile_idc == 3 /* Main Still Picture profile */ + ) { + WRITE_UINT32 (bs, 1, 1); + } else { + WRITE_UINT32 (bs, 0, 1); + } + /* general_profile_compatibility_flag[2] */ + if ( + /* In A.3.2, NOTE: When general_profile_compatibility_flag[ 1 ] is equal + to 1, general_profile_compatibility_flag[ 2 ] should also be equal to + 1. */ + seq_param->general_profile_idc == 1 /* Main profile */ + || seq_param->general_profile_idc == 2 /* Main 10 profile */ + /* In A.3.4, NOTE: When general_profile_compatibility_flag[ 3 ] is equal + to 1, general_profile_compatibility_flag[ 1 ] and + general_profile_compatibility_flag[ 2 ] should also be equal to 1. */ + || seq_param->general_profile_idc == 3 /* Main Still Picture profile */ + ) { + WRITE_UINT32 (bs, 1, 1); + } else { + WRITE_UINT32 (bs, 0, 1); + } + /* general_profile_compatibility_flag[3] */ + if (seq_param->general_profile_idc == 3) { + WRITE_UINT32 (bs, 1, 1); + } else { + WRITE_UINT32 (bs, 0, 1); + } + + /* general_profile_compatibility_flag[4] */ + if (seq_param->general_profile_idc == 4) { /* format range extensions profiles */ + WRITE_UINT32 (bs, 1, 1); + } else { + WRITE_UINT32 (bs, 0, 1); + } + + /* general_profile_compatibility_flag[5~8] */ + WRITE_UINT32 (bs, 0, 4); + + /* general_profile_compatibility_flag[9] */ + if (seq_param->general_profile_idc == 9) { /* screen content coding profiles */ + WRITE_UINT32 (bs, 1, 1); + } else { + WRITE_UINT32 (bs, 0, 1); + } + + /* general_profile_compatibility_flag[10~32] */ + WRITE_UINT32 (bs, 0, 22); + + /* general_progressive_source_flag */ + WRITE_UINT32 (bs, 1, 1); + /* general_interlaced_source_flag */ + WRITE_UINT32 (bs, 0, 1); + /* general_non_packed_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* general_frame_only_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + + /* additional indications specified for general_profile_idc from 4~10 */ + if (seq_param->general_profile_idc == 4) { + /* In A.3.5, Format range extensions profiles. + Just support main444, main444-10 and main422-10 profile now, may add + more profiles when needed. */ + switch (profile) { + case GST_VAAPI_PROFILE_H265_MAIN_444: + /* max_12bit_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* max_10bit_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* max_8bit_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* max_422chroma_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* max_420chroma_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* max_monochrome_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* intra_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* one_picture_only_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* lower_bit_rate_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + break; + case GST_VAAPI_PROFILE_H265_MAIN_444_10: + /* max_12bit_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* max_10bit_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* max_8bit_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* max_422chroma_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* max_420chroma_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* max_monochrome_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* intra_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* one_picture_only_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* lower_bit_rate_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + break; + case GST_VAAPI_PROFILE_H265_MAIN_422_10: + /* max_12bit_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* max_10bit_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* max_8bit_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* max_422chroma_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* max_420chroma_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* max_monochrome_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* intra_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* one_picture_only_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* lower_bit_rate_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + break; + case GST_VAAPI_PROFILE_H265_MAIN12: + /* max_12bit_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* max_10bit_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* max_8bit_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* max_422chroma_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* max_420chroma_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* max_monochrome_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* intra_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* one_picture_only_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* lower_bit_rate_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + break; + default: + GST_WARNING ("do not support the profile: %s of range extensions", + gst_vaapi_profile_get_va_name (profile)); + goto bs_error; + } + + /* general_reserved_zero_34bits */ + for (i = 0; i < 34; i++) + WRITE_UINT32 (bs, 0, 1); + } else if (seq_param->general_profile_idc == 9) { + /* In A.3.7, Screen content coding extensions profiles. */ + switch (profile) { + case GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN: + /* max_12bit_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* max_10bit_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* max_8bit_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* max_422chroma_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* max_420chroma_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* max_monochrome_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* intra_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* one_picture_only_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* lower_bit_rate_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* general_max_14bit_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + break; + case GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_10: + /* max_12bit_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* max_10bit_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* max_8bit_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* max_422chroma_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* max_420chroma_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* max_monochrome_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* intra_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* one_picture_only_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* lower_bit_rate_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* general_max_14bit_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + break; + case GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444: + /* max_12bit_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* max_10bit_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* max_8bit_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* max_422chroma_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* max_420chroma_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* max_monochrome_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* intra_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* one_picture_only_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* lower_bit_rate_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* general_max_14bit_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + break; + case GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444_10: + /* max_12bit_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* max_10bit_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* max_8bit_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* max_422chroma_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* max_420chroma_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* max_monochrome_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* intra_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* one_picture_only_constraint_flag */ + WRITE_UINT32 (bs, 0, 1); + /* lower_bit_rate_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + /* general_max_14bit_constraint_flag */ + WRITE_UINT32 (bs, 1, 1); + break; + default: + GST_WARNING ("do not support the profile: %s of screen" + " content coding extensions", + gst_vaapi_profile_get_va_name (profile)); + goto bs_error; + } + + /* general_reserved_zero_33bits */ + for (i = 0; i < 33; i++) + WRITE_UINT32 (bs, 0, 1); + } else { + /* general_reserved_zero_43bits */ + for (i = 0; i < 43; i++) + WRITE_UINT32 (bs, 0, 1); + } + + /* general_inbld_flag */ + WRITE_UINT32 (bs, 0, 1); + /* general_level_idc */ + WRITE_UINT32 (bs, seq_param->general_level_idc, 8); + + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write Profile Tier Level"); + return FALSE; + } +} + +/* Write an VPS NAL unit */ +static gboolean +bs_write_vps_data (GstBitWriter * bs, GstVaapiEncoderH265 * encoder, + GstVaapiEncPicture * picture, + const VAEncSequenceParameterBufferHEVC * seq_param, GstVaapiProfile profile) +{ + guint32 video_parameter_set_id = 0; + guint32 vps_max_layers_minus1 = 0; + guint32 vps_max_sub_layers_minus1 = 0; + guint32 vps_temporal_id_nesting_flag = 1; + guint32 vps_sub_layer_ordering_info_present_flag = 0; + guint32 vps_max_latency_increase_plus1 = 0; + guint32 vps_max_layer_id = 0; + guint32 vps_num_layer_sets_minus1 = 0; + guint32 vps_timing_info_present_flag = 0; + guint32 vps_extension_flag = 0; + guint32 vps_base_layer_internal_flag = 1; + guint32 vps_base_layer_available_flag = 1; + + /* video_parameter_set_id */ + WRITE_UINT32 (bs, video_parameter_set_id, 4); + /* vps_base_layer_internal_flag */ + WRITE_UINT32 (bs, vps_base_layer_internal_flag, 1); + /* vps_base_layer_available_flag */ + WRITE_UINT32 (bs, vps_base_layer_available_flag, 1); + /* vps_max_layers_minus1 */ + WRITE_UINT32 (bs, vps_max_layers_minus1, 6); + /* vps_max_sub_layers_minus1 */ + WRITE_UINT32 (bs, vps_max_sub_layers_minus1, 3); + /* vps_temporal_id_nesting_flag */ + WRITE_UINT32 (bs, vps_temporal_id_nesting_flag, 1); + /* vps_reserved_0xffff_16bits */ + WRITE_UINT32 (bs, 0xffff, 16); + + /* profile_tier_level */ + bs_write_profile_tier_level (bs, seq_param, profile); + + /* vps_sub_layer_ordering_info_present_flag */ + WRITE_UINT32 (bs, vps_sub_layer_ordering_info_present_flag, 1); + /* vps_max_dec_pic_buffering_minus1 */ + WRITE_UE (bs, encoder->max_dec_pic_buffering - 1); + /* vps_max_num_reorder_pics */ + WRITE_UE (bs, encoder->max_num_reorder_pics); + /* vps_max_latency_increase_plus1 */ + WRITE_UE (bs, vps_max_latency_increase_plus1); + /* vps_max_layer_id */ + WRITE_UINT32 (bs, vps_max_layer_id, 6); + /* vps_num_layer_sets_minus1 */ + WRITE_UE (bs, vps_num_layer_sets_minus1); + /* vps_timing_info_present_flag */ + WRITE_UINT32 (bs, vps_timing_info_present_flag, 1); + /* vps_extension_flag */ + WRITE_UINT32 (bs, vps_extension_flag, 1); + + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write VPS NAL unit"); + return FALSE; + } +} + +static gboolean +bs_write_vps (GstBitWriter * bs, GstVaapiEncoderH265 * encoder, + GstVaapiEncPicture * picture, + const VAEncSequenceParameterBufferHEVC * seq_param, GstVaapiProfile profile) +{ + if (!bs_write_vps_data (bs, encoder, picture, seq_param, profile)) + return FALSE; + + /* rbsp_trailing_bits */ + bs_write_trailing_bits (bs); + + return FALSE; +} + +/* Write an SPS NAL unit */ +static gboolean +bs_write_sps_data (GstBitWriter * bs, GstVaapiEncoderH265 * encoder, + GstVaapiEncPicture * picture, + const VAEncSequenceParameterBufferHEVC * seq_param, GstVaapiProfile profile, + GstVaapiRateControl rate_control, const VAEncMiscParameterHRD * hrd_params) +{ + guint32 video_parameter_set_id = 0; + guint32 max_sub_layers_minus1 = 0; + guint32 temporal_id_nesting_flag = 1; + guint32 separate_colour_plane_flag = 0; + guint32 seq_parameter_set_id = 0; + guint32 sps_sub_layer_ordering_info_present_flag = 0; + guint32 sps_max_latency_increase_plus1 = 0; + guint32 num_short_term_ref_pic_sets = 0; + guint32 long_term_ref_pics_present_flag = 0; + guint32 sps_extension_flag = 0; + guint32 nal_hrd_parameters_present_flag = 0; + guint maxNumSubLayers = 1, i; + guint32 cbr_flag = rate_control == GST_VAAPI_RATECONTROL_CBR ? 1 : 0; + + /* video_parameter_set_id */ + WRITE_UINT32 (bs, video_parameter_set_id, 4); + /* max_sub_layers_minus1 */ + WRITE_UINT32 (bs, max_sub_layers_minus1, 3); + /* temporal_id_nesting_flag */ + WRITE_UINT32 (bs, temporal_id_nesting_flag, 1); + + /* profile_tier_level */ + bs_write_profile_tier_level (bs, seq_param, profile); + + /* seq_parameter_set_id */ + WRITE_UE (bs, seq_parameter_set_id); + /* chroma_format_idc = 1, 4:2:0 */ + WRITE_UE (bs, seq_param->seq_fields.bits.chroma_format_idc); + if (seq_param->seq_fields.bits.chroma_format_idc == 3) + /* if( chroma_format_idc == 3 ) separate_colour_plane_flag */ + WRITE_UINT32 (bs, separate_colour_plane_flag, 1); + /* pic_width_in_luma_samples */ + WRITE_UE (bs, seq_param->pic_width_in_luma_samples); + /* pic_height_in_luma_samples */ + WRITE_UE (bs, seq_param->pic_height_in_luma_samples); + + /* conformance_window_flag */ + WRITE_UINT32 (bs, encoder->conformance_window_flag, 1); + if (encoder->conformance_window_flag) { + WRITE_UE (bs, encoder->conf_win_left_offset); + WRITE_UE (bs, encoder->conf_win_right_offset); + WRITE_UE (bs, encoder->conf_win_top_offset); + WRITE_UE (bs, encoder->conf_win_bottom_offset); + } + + /* bit_depth_luma_minus8 */ + WRITE_UE (bs, seq_param->seq_fields.bits.bit_depth_luma_minus8); + /* bit_depth_chroma_minus8 */ + WRITE_UE (bs, seq_param->seq_fields.bits.bit_depth_chroma_minus8); + /* log2_max_pic_order_cnt_lsb_minus4 */ + WRITE_UE (bs, encoder->log2_max_pic_order_cnt - 4); + + /* sps_sub_layer_ordering_info_present_flag */ + WRITE_UINT32 (bs, sps_sub_layer_ordering_info_present_flag, 1); + /* sps_max_dec_pic_buffering_minus1 */ + WRITE_UE (bs, encoder->max_dec_pic_buffering - 1); + /* sps_max_num_reorder_pics */ + WRITE_UE (bs, encoder->max_num_reorder_pics); + /* sps_max_latency_increase_plus1 */ + WRITE_UE (bs, sps_max_latency_increase_plus1); + + /* log2_min_luma_coding_block_size_minus3 */ + WRITE_UE (bs, seq_param->log2_min_luma_coding_block_size_minus3); + /* log2_diff_max_min_luma_coding_block_size */ + WRITE_UE (bs, seq_param->log2_diff_max_min_luma_coding_block_size); + /* log2_min_transform_block_size_minus2 */ + WRITE_UE (bs, seq_param->log2_min_transform_block_size_minus2); + /* log2_diff_max_min_transform_block_size */ + WRITE_UE (bs, seq_param->log2_diff_max_min_transform_block_size); + /* max_transform_hierarchy_depth_inter */ + WRITE_UE (bs, seq_param->max_transform_hierarchy_depth_inter); + /*max_transform_hierarchy_depth_intra */ + WRITE_UE (bs, seq_param->max_transform_hierarchy_depth_intra); + + /* scaling_list_enabled_flag */ + WRITE_UINT32 (bs, seq_param->seq_fields.bits.scaling_list_enabled_flag, 1); + /* amp_enabled_flag */ + WRITE_UINT32 (bs, seq_param->seq_fields.bits.amp_enabled_flag, 1); + /* sample_adaptive_offset_enabled_flag */ + WRITE_UINT32 (bs, + seq_param->seq_fields.bits.sample_adaptive_offset_enabled_flag, 1); + /* pcm_enabled_flag */ + WRITE_UINT32 (bs, seq_param->seq_fields.bits.pcm_enabled_flag, 1); + + /* num_short_term_ref_pic_sets */ + WRITE_UE (bs, num_short_term_ref_pic_sets); + + /* long_term_ref_pics_present_flag */ + WRITE_UINT32 (bs, long_term_ref_pics_present_flag, 1); + + /* sps_temporal_mvp_enabled_flag */ + WRITE_UINT32 (bs, seq_param->seq_fields.bits.sps_temporal_mvp_enabled_flag, + 1); + /* strong_intra_smoothing_enabled_flag */ + WRITE_UINT32 (bs, + seq_param->seq_fields.bits.strong_intra_smoothing_enabled_flag, 1); + + /* vui_parameters_present_flag */ + WRITE_UINT32 (bs, seq_param->vui_parameters_present_flag, 1); + + /*--------------- Write VUI Parameters--------------- */ + if (seq_param->vui_parameters_present_flag) { + gboolean vui_hrd_parameters_present_flag; + /* aspect_ratio_info_present_flag */ + WRITE_UINT32 (bs, + seq_param->vui_fields.bits.aspect_ratio_info_present_flag, 1); + if (seq_param->vui_fields.bits.aspect_ratio_info_present_flag) { + WRITE_UINT32 (bs, seq_param->aspect_ratio_idc, 8); + if (seq_param->aspect_ratio_idc == 0xFF) { + WRITE_UINT32 (bs, seq_param->sar_width, 16); + WRITE_UINT32 (bs, seq_param->sar_height, 16); + } + } + /* overscan_info_present_flag */ + WRITE_UINT32 (bs, 0, 1); + /* video_signal_type_present_flag */ + WRITE_UINT32 (bs, 0, 1); + /* chroma_loc_info_present_flag */ + WRITE_UINT32 (bs, 0, 1); + /* neutral_chroma_indication_flag */ + WRITE_UINT32 (bs, seq_param->vui_fields.bits.neutral_chroma_indication_flag, + 1); + /* field_seq_flag */ + WRITE_UINT32 (bs, seq_param->vui_fields.bits.field_seq_flag, 1); + /* frame_field_info_present_flag */ + WRITE_UINT32 (bs, 0, 1); + /* default_display_window_flag */ + WRITE_UINT32 (bs, 0, 1); + + /* timing_info_present_flag */ + WRITE_UINT32 (bs, seq_param->vui_fields.bits.vui_timing_info_present_flag, + 1); + if (seq_param->vui_fields.bits.vui_timing_info_present_flag) { + /* vui_num_units_in_tick */ + WRITE_UINT32 (bs, seq_param->vui_num_units_in_tick, 32); + /* vui_time_scale */ + WRITE_UINT32 (bs, seq_param->vui_time_scale, 32); + /* vui_poc_proportional_to_timing_flag */ + WRITE_UINT32 (bs, 0, 1); + + /* vui_hrd_parameters_present_flag */ + vui_hrd_parameters_present_flag = seq_param->bits_per_second > 0; + WRITE_UINT32 (bs, vui_hrd_parameters_present_flag, 1); + + if (vui_hrd_parameters_present_flag) { + nal_hrd_parameters_present_flag = 1; + /* nal_hrd_parameters_present_flag */ + WRITE_UINT32 (bs, nal_hrd_parameters_present_flag, 1); + /* vcl_hrd_parameters_present_flag */ + WRITE_UINT32 (bs, 0, 1); + + if (nal_hrd_parameters_present_flag) { + /* sub_pic_hrd_params_present_flag */ + WRITE_UINT32 (bs, 0, 1); + /* bit_rate_scale */ + WRITE_UINT32 (bs, SX_BITRATE - 6, 4); + /* cpb_size_scale */ + WRITE_UINT32 (bs, SX_CPB_SIZE - 4, 4); + /* initial_cpb_removal_delay_length_minus1 */ + WRITE_UINT32 (bs, 23, 5); + /* au_cpb_removal_delay_length_minus1 */ + WRITE_UINT32 (bs, 23, 5); + /* dpb_output_delay_length_minus1 */ + WRITE_UINT32 (bs, 23, 5); + + for (i = 0; i < maxNumSubLayers; i++) { + /* fixed_pic_rate_general_flag */ + WRITE_UINT32 (bs, 0, 1); + /* fixed_pic_rate_within_cvs_flag */ + WRITE_UINT32 (bs, 0, 1); + /* low_delay_hrd_flag */ + WRITE_UINT32 (bs, 1, 1); + /* bit_rate_value_minus1 */ + WRITE_UE (bs, (seq_param->bits_per_second >> SX_BITRATE) - 1); + /* cpb_size_value_minus1 */ + WRITE_UE (bs, (hrd_params->buffer_size >> SX_CPB_SIZE) - 1); + /* cbr_flag */ + WRITE_UINT32 (bs, cbr_flag, 1); + } + } + } + } + /* bitstream_restriction_flag */ + WRITE_UINT32 (bs, seq_param->vui_fields.bits.bitstream_restriction_flag, 1); + } + + if (h265_is_scc (encoder)) { + /* sps_extension_flag */ + WRITE_UINT32 (bs, 1, 1); + /* sps_range_extension_flag */ + WRITE_UINT32 (bs, 0, 1); + /* sps_multilayer_extension_flag */ + WRITE_UINT32 (bs, 0, 1); + /* sps_3d_extension_flag */ + WRITE_UINT32 (bs, 0, 1); + /* sps_scc_extension_flag */ + WRITE_UINT32 (bs, 1, 1); + /* sps_extension_4bits */ + WRITE_UINT32 (bs, 0, 4); + + /* sps_scc_extension() */ + /* sps_curr_pic_ref_enabled_flag */ + WRITE_UINT32 (bs, 1, 1); + /* palette_mode_enabled_flag */ + WRITE_UINT32 (bs, 1, 1); + /* palette_max_size */ + WRITE_UE (bs, 64); + /* delta_palette_max_predictor_size */ + WRITE_UE (bs, 32); + /* sps_palette_predictor_initializers_present_flag */ + WRITE_UINT32 (bs, 0, 1); + /* motion_vector_resolution_control_idc */ + WRITE_UINT32 (bs, 0, 2); + /* intra_boundary_filtering_disabled_flag */ + WRITE_UINT32 (bs, 0, 1); + } else { + /* sps_extension_flag */ + WRITE_UINT32 (bs, sps_extension_flag, 1); + } + + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write SPS NAL unit"); + return FALSE; + } +} + +static gboolean +bs_write_sps (GstBitWriter * bs, GstVaapiEncoderH265 * encoder, + GstVaapiEncPicture * picture, + const VAEncSequenceParameterBufferHEVC * seq_param, GstVaapiProfile profile, + GstVaapiRateControl rate_control, const VAEncMiscParameterHRD * hrd_params) +{ + if (!bs_write_sps_data (bs, encoder, picture, seq_param, profile, + rate_control, hrd_params)) + return FALSE; + + /* rbsp_trailing_bits */ + bs_write_trailing_bits (bs); + + return FALSE; +} + +/* Write a PPS NAL unit */ +static gboolean +bs_write_pps (GstBitWriter * bs, gboolean is_scc, + const VAEncPictureParameterBufferHEVC * pic_param) +{ + guint32 pic_parameter_set_id = 0; + guint32 seq_parameter_set_id = 0; + guint32 output_flag_present_flag = 0; + guint32 num_extra_slice_header_bits = 0; + guint32 cabac_init_present_flag = 0; + guint32 pps_slice_chroma_qp_offsets_present_flag = 0; + guint32 deblocking_filter_control_present_flag = 0; + guint32 lists_modification_present_flag = 0; + guint32 slice_segment_header_extension_present_flag = 0; + guint32 pps_extension_flag = 0; + + /* pic_parameter_set_id */ + WRITE_UE (bs, pic_parameter_set_id); + /* seq_parameter_set_id */ + WRITE_UE (bs, seq_parameter_set_id); + /* dependent_slice_segments_enabled_flag */ + WRITE_UINT32 (bs, + pic_param->pic_fields.bits.dependent_slice_segments_enabled_flag, 1); + /* output_flag_present_flag */ + WRITE_UINT32 (bs, output_flag_present_flag, 1); + /* num_extra_slice_header_bits */ + WRITE_UINT32 (bs, num_extra_slice_header_bits, 3); + /* sign_data_hiding_enabled_flag */ + WRITE_UINT32 (bs, pic_param->pic_fields.bits.sign_data_hiding_enabled_flag, + 1); + /* cabac_init_present_flag */ + WRITE_UINT32 (bs, cabac_init_present_flag, 1); + /* num_ref_idx_l0_default_active_minus1 */ + WRITE_UE (bs, pic_param->num_ref_idx_l0_default_active_minus1); + /* num_ref_idx_l1_default_active_minus1 */ + WRITE_UE (bs, pic_param->num_ref_idx_l1_default_active_minus1); + /* pic_init_qp_minus26 */ + WRITE_SE (bs, pic_param->pic_init_qp - 26); + /* constrained_intra_pred_flag */ + WRITE_UINT32 (bs, pic_param->pic_fields.bits.constrained_intra_pred_flag, 1); + /* transform_skip_enabled_flag */ + WRITE_UINT32 (bs, pic_param->pic_fields.bits.transform_skip_enabled_flag, 1); + /* cu_qp_delta_enabled_flag */ + WRITE_UINT32 (bs, pic_param->pic_fields.bits.cu_qp_delta_enabled_flag, 1); + /* diff_cu_qp_delta_depth */ + if (pic_param->pic_fields.bits.cu_qp_delta_enabled_flag) + WRITE_UE (bs, pic_param->diff_cu_qp_delta_depth); + + /* pps_cb_qp_offset */ + WRITE_SE (bs, pic_param->pps_cb_qp_offset); + /* pps_cr_qp_offset */ + WRITE_SE (bs, pic_param->pps_cr_qp_offset); + /* pps_slice_chroma_qp_offsets_present_flag */ + WRITE_UINT32 (bs, pps_slice_chroma_qp_offsets_present_flag, 1); + /* weighted_pred_flag */ + WRITE_UINT32 (bs, pic_param->pic_fields.bits.weighted_pred_flag, 1); + /* weighted_bipred_flag */ + WRITE_UINT32 (bs, pic_param->pic_fields.bits.weighted_bipred_flag, 1); + /* transquant_bypass_enabled_flag */ + WRITE_UINT32 (bs, pic_param->pic_fields.bits.transquant_bypass_enabled_flag, + 1); + /* tiles_enabled_flag */ + WRITE_UINT32 (bs, pic_param->pic_fields.bits.tiles_enabled_flag, 1); + /* entropy_coding_sync_enabled_flag */ + WRITE_UINT32 (bs, pic_param->pic_fields.bits.entropy_coding_sync_enabled_flag, + 1); + + /* tiles info */ + if (pic_param->pic_fields.bits.tiles_enabled_flag) { + WRITE_UE (bs, pic_param->num_tile_columns_minus1); + WRITE_UE (bs, pic_param->num_tile_rows_minus1); + /* uniform_spacing_flag is 1 now */ + WRITE_UINT32 (bs, 1, 1); + /* if (!uniform_spacing_flag) { + for (i = 0; i < num_tile_columns_minus1; i++) + column_width_minus1[i] + ue (v) + for (i = 0; i < num_tile_rows_minus1; i++) + row_height_minus1[i] + ue (v) + } */ + WRITE_UINT32 (bs, + pic_param->pic_fields.bits.loop_filter_across_tiles_enabled_flag, 1); + } + + /* pps_loop_filter_across_slices_enabled_flag */ + WRITE_UINT32 (bs, + pic_param->pic_fields.bits.pps_loop_filter_across_slices_enabled_flag, 1); + /* deblocking_filter_control_present_flag */ + WRITE_UINT32 (bs, deblocking_filter_control_present_flag, 1); + /* pps_scaling_list_data_present_flag */ + WRITE_UINT32 (bs, pic_param->pic_fields.bits.scaling_list_data_present_flag, + 1); + /* lists_modification_present_flag */ + WRITE_UINT32 (bs, lists_modification_present_flag, 1); + /* log2_parallel_merge_level_minus2 */ + WRITE_UE (bs, pic_param->log2_parallel_merge_level_minus2); + /* slice_segment_header_extension_present_flag */ + WRITE_UINT32 (bs, slice_segment_header_extension_present_flag, 1); + + if (is_scc) { +#if VA_CHECK_VERSION(1,8,0) + /* pps_extension_flag */ + WRITE_UINT32 (bs, 1, 1); + /* pps_range_extension_flag */ + WRITE_UINT32 (bs, 0, 1); + /* pps_multilayer_extension_flag */ + WRITE_UINT32 (bs, 0, 1); + /* pps_3d_extension_flag */ + WRITE_UINT32 (bs, 0, 1); + /* pps_scc_extension_flag */ + WRITE_UINT32 (bs, 1, 1); + /* pps_extension_4bits */ + WRITE_UINT32 (bs, 0, 4); + + /* pps_scc_extension() */ + /* pps_curr_pic_ref_enabled_flag */ + WRITE_UINT32 (bs, + pic_param->scc_fields.bits.pps_curr_pic_ref_enabled_flag, 1); + /* residual_adaptive_colour_transform_enabled_flag */ + WRITE_UINT32 (bs, 0, 1); + /* pps_palette_predictor_initializers_present_flag */ + WRITE_UINT32 (bs, 0, 1); +#else + /* SCC profile should not be selected. */ + g_assert_not_reached (); + return FALSE; +#endif + } else { + /* pps_extension_flag */ + WRITE_UINT32 (bs, pps_extension_flag, 1); + } + + /* rbsp_trailing_bits */ + bs_write_trailing_bits (bs); + + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write PPS NAL unit"); + return FALSE; + } +} + +/* Write a Slice NAL unit */ +static gboolean +bs_write_slice (GstBitWriter * bs, + const VAEncSliceParameterBufferHEVC * slice_param, + GstVaapiEncoderH265 * encoder, GstVaapiEncPicture * picture, + guint8 nal_unit_type) +{ + const VAEncPictureParameterBufferHEVC *const pic_param = picture->param; + + guint8 no_output_of_prior_pics_flag = 0; + guint8 dependent_slice_segment_flag = 0; + guint8 short_term_ref_pic_set_sps_flag = 0; + guint8 slice_deblocking_filter_disabled_flag = 0; + guint8 num_ref_idx_active_override_flag = + slice_param->slice_fields.bits.num_ref_idx_active_override_flag; + + if (h265_is_scc (encoder)) { + /* If scc, need to add the current picture itself. */ + num_ref_idx_active_override_flag = 1; + } + + /* first_slice_segment_in_pic_flag */ + WRITE_UINT32 (bs, encoder->first_slice_segment_in_pic_flag, 1); + + /* FIXME: For all IRAP pics */ + /* no_output_of_prior_pics_flag */ + if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture)) + WRITE_UINT32 (bs, no_output_of_prior_pics_flag, 1); + + /* slice_pic_parameter_set_id */ + WRITE_UE (bs, slice_param->slice_pic_parameter_set_id); + + /* slice_segment_address , bits_size = Ceil(Log2(PicSizeInCtbsY)) */ + if (!encoder->first_slice_segment_in_pic_flag) { + guint pic_size_ctb = encoder->ctu_width * encoder->ctu_height; + guint bits_size = (guint) ceil ((log2 (pic_size_ctb))); + WRITE_UINT32 (bs, slice_param->slice_segment_address, bits_size); + } + + if (!dependent_slice_segment_flag) { + /* slice_type */ + WRITE_UE (bs, slice_param->slice_type); + + if (!pic_param->pic_fields.bits.idr_pic_flag) { + /* slice_pic_order_cnt_lsb */ + WRITE_UINT32 (bs, picture->poc, encoder->log2_max_pic_order_cnt); + /* short_term_ref_pic_set_sps_flag */ + WRITE_UINT32 (bs, short_term_ref_pic_set_sps_flag, 1); + + /*---------- Write short_term_ref_pic_set(0) ----------- */ + { + guint num_positive_pics = 0, num_negative_pics = 0; + guint delta_poc_s0_minus1 = 0, delta_poc_s1_minus1 = 0; + guint used_by_curr_pic_s0_flag = 0, used_by_curr_pic_s1_flag = 0; + guint reflist_0_count = 0, reflist_1_count = 0; + gint i; + + /* Get count of ref_pic_list */ + if (picture->type == GST_VAAPI_PICTURE_TYPE_P + || picture->type == GST_VAAPI_PICTURE_TYPE_B) { + for (i = 0; i < G_N_ELEMENTS (slice_param->ref_pic_list0); ++i) { + if (slice_param->ref_pic_list0[i].picture_id == VA_INVALID_SURFACE) + break; + } + reflist_0_count = i; + + if (picture->type == GST_VAAPI_PICTURE_TYPE_B) { + for (i = 0; i < G_N_ELEMENTS (slice_param->ref_pic_list1); ++i) { + if (slice_param->ref_pic_list1[i].picture_id == + VA_INVALID_SURFACE) + break; + } + reflist_1_count = i; + } + } + + if (picture->type == GST_VAAPI_PICTURE_TYPE_P) { + delta_poc_s0_minus1 = + picture->poc - slice_param->ref_pic_list0[0].pic_order_cnt - 1; + used_by_curr_pic_s0_flag = 1; + delta_poc_s1_minus1 = 0; + used_by_curr_pic_s1_flag = 0; + } + if (picture->type == GST_VAAPI_PICTURE_TYPE_B) { + delta_poc_s0_minus1 = + picture->poc - slice_param->ref_pic_list0[0].pic_order_cnt - 1; + used_by_curr_pic_s0_flag = 1; + delta_poc_s1_minus1 = + slice_param->ref_pic_list1[0].pic_order_cnt - picture->poc - 1; + used_by_curr_pic_s1_flag = 1; + } + + num_negative_pics = reflist_0_count; + num_positive_pics = reflist_1_count; + + /* num_negative_pics */ + WRITE_UE (bs, num_negative_pics); + /* num_positive_pics */ + WRITE_UE (bs, num_positive_pics); + + for (i = 0; i < num_negative_pics; i++) { + /* delta_poc_s0_minus1 */ + if (i == 0) { + WRITE_UE (bs, delta_poc_s0_minus1); + } else { + WRITE_UE (bs, + slice_param->ref_pic_list0[i - 1].pic_order_cnt - + slice_param->ref_pic_list0[i].pic_order_cnt - 1); + } + /* used_by_curr_pic_s0_flag */ + WRITE_UINT32 (bs, used_by_curr_pic_s0_flag, 1); + } + for (i = 0; i < num_positive_pics; i++) { + /* delta_poc_s1_minus1 */ + if (i == 0) { + WRITE_UE (bs, delta_poc_s1_minus1); + } else { + WRITE_UE (bs, + slice_param->ref_pic_list1[i - 1].pic_order_cnt - + slice_param->ref_pic_list1[i].pic_order_cnt - 1); + } + /* used_by_curr_pic_s1_flag */ + WRITE_UINT32 (bs, used_by_curr_pic_s1_flag, 1); + } + } + + /* slice_temporal_mvp_enabled_flag */ + if (encoder->sps_temporal_mvp_enabled_flag) + WRITE_UINT32 (bs, + slice_param->slice_fields.bits.slice_temporal_mvp_enabled_flag, 1); + } + + if (encoder->sample_adaptive_offset_enabled_flag) { + WRITE_UINT32 (bs, slice_param->slice_fields.bits.slice_sao_luma_flag, 1); + WRITE_UINT32 (bs, slice_param->slice_fields.bits.slice_sao_chroma_flag, + 1); + } + + if (slice_param->slice_type == GST_H265_P_SLICE || + slice_param->slice_type == GST_H265_B_SLICE) { + /* num_ref_idx_active_override_flag */ + WRITE_UINT32 (bs, num_ref_idx_active_override_flag, 1); + if (num_ref_idx_active_override_flag) { + if (h265_is_scc (encoder)) { + if (picture->type == GST_VAAPI_PICTURE_TYPE_I) { + g_assert (slice_param->num_ref_idx_l0_active_minus1 == 0); + /* Let num_ref_idx_l0_active_minus1 = 0 and + NumRpsCurrTempList0 = 1 to include current picture itself */ + WRITE_UE (bs, 0); + } else { + /* For scc, need to add 1 for current picture itself when + calculating NumRpsCurrTempList0. */ + WRITE_UE (bs, slice_param->num_ref_idx_l0_active_minus1 + 1); + } + } else { + WRITE_UE (bs, slice_param->num_ref_idx_l0_active_minus1); + } + if (slice_param->slice_type == GST_H265_B_SLICE) + WRITE_UE (bs, slice_param->num_ref_idx_l1_active_minus1); + } + + /* mvd_l1_zero_flag */ + if (slice_param->slice_type == GST_H265_B_SLICE) + WRITE_UINT32 (bs, slice_param->slice_fields.bits.mvd_l1_zero_flag, 1); + + /* cabac_init_present_flag == FALSE */ + /* cabac_init_flag = FALSE */ + + /* collocated_from_l0_flag */ + if (slice_param->slice_fields.bits.slice_temporal_mvp_enabled_flag) { + if (slice_param->slice_type == GST_H265_B_SLICE) + WRITE_UINT32 (bs, + slice_param->slice_fields.bits.collocated_from_l0_flag, 1); + } + /* five_minus_max_num_merge_cand */ + WRITE_UE (bs, 5 - slice_param->max_num_merge_cand); + } + + /* slice_qp_delta */ + WRITE_SE (bs, slice_param->slice_qp_delta); + if (pic_param->pic_fields.bits.pps_loop_filter_across_slices_enabled_flag && + (slice_param->slice_fields.bits.slice_sao_luma_flag + || slice_param->slice_fields.bits.slice_sao_chroma_flag + || !slice_deblocking_filter_disabled_flag)) + WRITE_UINT32 (bs, + slice_param->slice_fields.bits. + slice_loop_filter_across_slices_enabled_flag, 1); + } + + if (pic_param->pic_fields.bits.tiles_enabled_flag + || pic_param->pic_fields.bits.entropy_coding_sync_enabled_flag) { + /* output a num_entry_point_offsets, which should be 0 here */ + WRITE_UE (bs, 0); + } + + /* byte_alignment() */ + { + /* alignment_bit_equal_to_one */ + WRITE_UINT32 (bs, 1, 1); + while (GST_BIT_WRITER_BIT_SIZE (bs) % 8 != 0) { + /* alignment_bit_equal_to_zero */ + WRITE_UINT32 (bs, 0, 1); + } + } + + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write Slice NAL unit"); + return FALSE; + } +} + +static inline void +_check_vps_sps_pps_status (GstVaapiEncoderH265 * encoder, + const guint8 * nal, guint32 size) +{ + guint8 nal_type; + G_GNUC_UNUSED gsize ret; /* FIXME */ + g_assert (size); + + if (encoder->vps_data && encoder->sps_data && encoder->pps_data) + return; + + nal_type = (nal[0] & 0x7E) >> 1; + switch (nal_type) { + case GST_H265_NAL_VPS: + encoder->vps_data = gst_buffer_new_allocate (NULL, size, NULL); + ret = gst_buffer_fill (encoder->vps_data, 0, nal, size); + g_assert (ret == size); + break; + case GST_H265_NAL_SPS: + encoder->sps_data = gst_buffer_new_allocate (NULL, size, NULL); + ret = gst_buffer_fill (encoder->sps_data, 0, nal, size); + g_assert (ret == size); + break; + case GST_H265_NAL_PPS: + encoder->pps_data = gst_buffer_new_allocate (NULL, size, NULL); + ret = gst_buffer_fill (encoder->pps_data, 0, nal, size); + g_assert (ret == size); + break; + default: + break; + } +} + +static gboolean +is_profile_allowed (GstVaapiEncoderH265 * encoder, GstVaapiProfile profile) +{ + guint i; + + if (encoder->allowed_profiles == NULL) + return TRUE; + + for (i = 0; i < encoder->allowed_profiles->len; i++) + if (profile == + g_array_index (encoder->allowed_profiles, GstVaapiProfile, i)) + return TRUE; + + return FALSE; +} + +/* Derives the profile from the active coding tools. */ +static gboolean +ensure_profile (GstVaapiEncoderH265 * encoder) +{ + GstVaapiProfile profile; + const GstVideoFormat format = + GST_VIDEO_INFO_FORMAT (GST_VAAPI_ENCODER_VIDEO_INFO (encoder)); + guint depth, chrome; + GstVaapiProfile profile_candidates[6]; + guint num, i; + + g_assert (GST_VIDEO_FORMAT_INFO_IS_YUV (gst_video_format_get_info (format))); + depth = GST_VIDEO_FORMAT_INFO_DEPTH (gst_video_format_get_info (format), 0); + chrome = gst_vaapi_utils_h265_get_chroma_format_idc + (gst_vaapi_video_format_get_chroma_type (format)); + + num = 0; + + if (chrome == 3) { + /* 4:4:4 */ + if (depth == 8) + profile_candidates[num++] = GST_VAAPI_PROFILE_H265_MAIN_444; + if (depth <= 10) + profile_candidates[num++] = GST_VAAPI_PROFILE_H265_MAIN_444_10; +#if VA_CHECK_VERSION(1,8,0) + /* Consider SCREEN_EXTENDED_MAIN_444 and SCREEN_EXTENDED_MAIN_444_10 */ + if (depth == 8) + profile_candidates[num++] = + GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444; + if (depth <= 10) + profile_candidates[num++] = + GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444_10; +#endif + } else if (chrome == 2) { + /* 4:2:2 */ + profile_candidates[num++] = GST_VAAPI_PROFILE_H265_MAIN_422_10; + } else if (chrome == 1 || chrome == 0) { + /* 4:2:0 or 4:0:0 */ + if (depth == 8) + profile_candidates[num++] = GST_VAAPI_PROFILE_H265_MAIN; + if (depth <= 10) + profile_candidates[num++] = GST_VAAPI_PROFILE_H265_MAIN10; + if (depth <= 12) + profile_candidates[num++] = GST_VAAPI_PROFILE_H265_MAIN12; + /* Always add STILL_PICTURE as a candidate for Main and Main10. */ + if (depth <= 10) + profile_candidates[num++] = GST_VAAPI_PROFILE_H265_MAIN_STILL_PICTURE; +#if VA_CHECK_VERSION(1,8,0) + /* Consider SCREEN_EXTENDED_MAIN and SCREEN_EXTENDED_MAIN_10 */ + if (depth == 8) + profile_candidates[num++] = GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN; + if (depth <= 10) + profile_candidates[num++] = + GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_10; +#endif + } + + if (num == 0) { + GST_ERROR ("Fail to find a profile for format %s.", + gst_video_format_to_string (format)); + return FALSE; + } + + profile = GST_VAAPI_PROFILE_UNKNOWN; + for (i = 0; i < num; i++) { + if (!is_profile_allowed (encoder, profile_candidates[i])) + continue; + /* If we can get valid entrypoint, hw must support this profile. */ + if (gst_vaapi_encoder_get_entrypoint (GST_VAAPI_ENCODER_CAST (encoder), + profile_candidates[i]) == GST_VAAPI_ENTRYPOINT_INVALID) + continue; + + profile = profile_candidates[i]; + break; + } + + if (profile == GST_VAAPI_PROFILE_UNKNOWN) { + GST_ERROR ("Fail to find a supported profile %sfor format %s.", + GST_VAAPI_ENCODER_TUNE (encoder) == GST_VAAPI_ENCODER_TUNE_LOW_POWER ? + "in low power mode " : "", gst_video_format_to_string (format)); + return FALSE; + } + + encoder->profile = profile; + encoder->profile_idc = gst_vaapi_utils_h265_get_profile_idc (profile); + return TRUE; +} + +/* Derives the level and tier from the currently set limits */ +static gboolean +ensure_tier_level (GstVaapiEncoderH265 * encoder) +{ + guint bitrate = GST_VAAPI_ENCODER_CAST (encoder)->bitrate; + guint i, num_limits, PicSizeInSamplesY; + guint LumaSr; + const GstVaapiH265LevelLimits *limits_table; + const GstVaapiH265LevelLimits *limits; + + PicSizeInSamplesY = encoder->luma_width * encoder->luma_height; + LumaSr = + gst_util_uint64_scale (PicSizeInSamplesY, + GST_VAAPI_ENCODER_FPS_N (encoder), GST_VAAPI_ENCODER_FPS_D (encoder)); + + limits_table = gst_vaapi_utils_h265_get_level_limits_table (&num_limits); + for (i = 0; i < num_limits; i++) { + limits = &limits_table[i]; + /* Choose level by luma picture size and luma sample rate */ + if (PicSizeInSamplesY <= limits->MaxLumaPs && LumaSr <= limits->MaxLumaSr) + break; + } + + if (i == num_limits) + goto error_unsupported_level; + + /* may need to promote the level by tile setting */ + if (h265_is_tile_enabled (encoder)) { + for (; i < num_limits; i++) { + limits = &limits_table[i]; + if (encoder->num_tile_cols <= limits->MaxTileColumns && + encoder->num_tile_rows <= limits->MaxTileRows) + break; + } + + if (i == num_limits) + goto error_promote_level; + } + + if (bitrate <= limits_table[i].MaxBRTierMain) { + encoder->tier = GST_VAAPI_TIER_H265_MAIN; + } else { + encoder->tier = GST_VAAPI_TIER_H265_HIGH; + if (bitrate > limits_table[i].MaxBRTierHigh) { + GST_INFO ("The bitrate of the stream is %d kbps, larger than" + " %s profile %s level %s tier's max bit rate %d kbps", + bitrate, + gst_vaapi_utils_h265_get_profile_string (encoder->profile), + gst_vaapi_utils_h265_get_level_string (limits_table[i].level), + gst_vaapi_utils_h265_get_tier_string (GST_VAAPI_TIER_H265_HIGH), + limits_table[i].MaxBRTierHigh); + } + } + + encoder->level = limits_table[i].level; + encoder->level_idc = limits_table[i].level_idc; + return TRUE; + + /* ERRORS */ +error_promote_level: + { + GST_ERROR ("failed to promote level for num-tile-cols is %d," + " num-tile-rows %d", encoder->num_tile_cols, encoder->num_tile_rows); + return FALSE; + } +error_unsupported_level: + { + GST_ERROR ("failed to find a suitable level matching codec config"); + return FALSE; + } +} + +/* Handle new GOP starts */ +static void +reset_gop_start (GstVaapiEncoderH265 * encoder) +{ + GstVaapiH265ReorderPool *const reorder_pool = &encoder->reorder_pool; + + reorder_pool->frame_index = 1; + reorder_pool->cur_present_index = 0; + ++encoder->idr_num; +} + +/* Marks the supplied picture as a B-frame */ +static void +set_b_frame (GstVaapiEncPicture * pic, GstVaapiEncoderH265 * encoder) +{ + g_assert (pic && encoder); + g_return_if_fail (pic->type == GST_VAAPI_PICTURE_TYPE_NONE); + pic->type = GST_VAAPI_PICTURE_TYPE_B; +} + +/* Marks the supplied picture as a P-frame */ +static void +set_p_frame (GstVaapiEncPicture * pic, GstVaapiEncoderH265 * encoder) +{ + g_return_if_fail (pic->type == GST_VAAPI_PICTURE_TYPE_NONE); + pic->type = GST_VAAPI_PICTURE_TYPE_P; +} + +/* Marks the supplied picture as an I-frame */ +static void +set_i_frame (GstVaapiEncPicture * pic, GstVaapiEncoderH265 * encoder) +{ + g_return_if_fail (pic->type == GST_VAAPI_PICTURE_TYPE_NONE); + pic->type = GST_VAAPI_PICTURE_TYPE_I; + + g_assert (pic->frame); + GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (pic->frame); +} + +/* Marks the supplied picture as an IDR frame */ +static void +set_idr_frame (GstVaapiEncPicture * pic, GstVaapiEncoderH265 * encoder) +{ + g_return_if_fail (pic->type == GST_VAAPI_PICTURE_TYPE_NONE); + pic->type = GST_VAAPI_PICTURE_TYPE_I; + pic->poc = 0; + GST_VAAPI_ENC_PICTURE_FLAG_SET (pic, GST_VAAPI_ENC_PICTURE_FLAG_IDR); + + g_assert (pic->frame); + GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (pic->frame); +} + +/* Marks the supplied picture a a key-frame */ +static void +set_key_frame (GstVaapiEncPicture * picture, + GstVaapiEncoderH265 * encoder, gboolean is_idr) +{ + if (is_idr) { + reset_gop_start (encoder); + set_idr_frame (picture, encoder); + } else + set_i_frame (picture, encoder); +} + +/* Fills in VA HRD parameters */ +static void +fill_hrd_params (GstVaapiEncoderH265 * encoder, VAEncMiscParameterHRD * hrd) +{ + if (encoder->bitrate_bits > 0) { + hrd->buffer_size = encoder->cpb_length_bits; + hrd->initial_buffer_fullness = hrd->buffer_size / 2; + } else { + hrd->buffer_size = 0; + hrd->initial_buffer_fullness = 0; + } +} + +/* Adds the supplied video parameter set header (VPS) to the list of packed + headers to pass down as-is to the encoder */ +static gboolean +add_packed_vps_header (GstVaapiEncoderH265 * encoder, + GstVaapiEncPicture * picture, GstVaapiEncSequence * sequence) +{ + GstVaapiEncPackedHeader *packed_vps; + GstBitWriter bs; + VAEncPackedHeaderParameterBuffer packed_vps_param = { 0 }; + const VAEncSequenceParameterBufferHEVC *const seq_param = sequence->param; + GstVaapiProfile profile = encoder->profile; + + guint32 data_bit_size; + guint8 *data; + + gst_bit_writer_init_with_size (&bs, 128, FALSE); + WRITE_UINT32 (&bs, 0x00000001, 32); /* start code */ + bs_write_nal_header (&bs, GST_H265_NAL_VPS); + + bs_write_vps (&bs, encoder, picture, seq_param, profile); + + g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0); + data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs); + data = GST_BIT_WRITER_DATA (&bs); + + packed_vps_param.type = VAEncPackedHeaderSequence; + packed_vps_param.bit_length = data_bit_size; + packed_vps_param.has_emulation_bytes = 0; + + packed_vps = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder), + &packed_vps_param, sizeof (packed_vps_param), + data, (data_bit_size + 7) / 8); + g_assert (packed_vps); + + gst_vaapi_enc_picture_add_packed_header (picture, packed_vps); + gst_vaapi_codec_object_replace (&packed_vps, NULL); + + /* store vps data */ + _check_vps_sps_pps_status (encoder, data + 4, data_bit_size / 8 - 4); + gst_bit_writer_reset (&bs); + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write VPS NAL unit"); + gst_bit_writer_reset (&bs); + return FALSE; + } +} + +/* Adds the supplied sequence header (SPS) to the list of packed + headers to pass down as-is to the encoder */ +static gboolean +add_packed_sequence_header (GstVaapiEncoderH265 * encoder, + GstVaapiEncPicture * picture, GstVaapiEncSequence * sequence) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); + GstVaapiEncPackedHeader *packed_seq; + GstBitWriter bs; + VAEncPackedHeaderParameterBuffer packed_seq_param = { 0 }; + const VAEncSequenceParameterBufferHEVC *const seq_param = sequence->param; + GstVaapiProfile profile = encoder->profile; + + VAEncMiscParameterHRD hrd_params; + guint32 data_bit_size; + guint8 *data; + + fill_hrd_params (encoder, &hrd_params); + + gst_bit_writer_init_with_size (&bs, 128, FALSE); + WRITE_UINT32 (&bs, 0x00000001, 32); /* start code */ + bs_write_nal_header (&bs, GST_H265_NAL_SPS); + + bs_write_sps (&bs, encoder, picture, seq_param, profile, + base_encoder->rate_control, &hrd_params); + + g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0); + data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs); + data = GST_BIT_WRITER_DATA (&bs); + + packed_seq_param.type = VAEncPackedHeaderSequence; + packed_seq_param.bit_length = data_bit_size; + packed_seq_param.has_emulation_bytes = 0; + + packed_seq = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder), + &packed_seq_param, sizeof (packed_seq_param), + data, (data_bit_size + 7) / 8); + g_assert (packed_seq); + + gst_vaapi_enc_picture_add_packed_header (picture, packed_seq); + gst_vaapi_codec_object_replace (&packed_seq, NULL); + + /* store sps data */ + _check_vps_sps_pps_status (encoder, data + 4, data_bit_size / 8 - 4); + gst_bit_writer_reset (&bs); + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write SPS NAL unit"); + gst_bit_writer_reset (&bs); + return FALSE; + } +} + +/* Adds the supplied picture header (PPS) to the list of packed + headers to pass down as-is to the encoder */ +static gboolean +add_packed_picture_header (GstVaapiEncoderH265 * encoder, + GstVaapiEncPicture * picture) +{ + GstVaapiEncPackedHeader *packed_pic; + GstBitWriter bs; + VAEncPackedHeaderParameterBuffer packed_pic_param = { 0 }; + const VAEncPictureParameterBufferHEVC *const pic_param = picture->param; + guint32 data_bit_size; + guint8 *data; + + gst_bit_writer_init_with_size (&bs, 128, FALSE); + WRITE_UINT32 (&bs, 0x00000001, 32); /* start code */ + bs_write_nal_header (&bs, GST_H265_NAL_PPS); + bs_write_pps (&bs, h265_is_scc (encoder), pic_param); + g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0); + data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs); + data = GST_BIT_WRITER_DATA (&bs); + + packed_pic_param.type = VAEncPackedHeaderPicture; + packed_pic_param.bit_length = data_bit_size; + packed_pic_param.has_emulation_bytes = 0; + + packed_pic = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder), + &packed_pic_param, sizeof (packed_pic_param), + data, (data_bit_size + 7) / 8); + g_assert (packed_pic); + + gst_vaapi_enc_picture_add_packed_header (picture, packed_pic); + gst_vaapi_codec_object_replace (&packed_pic, NULL); + + /* store pps data */ + _check_vps_sps_pps_status (encoder, data + 4, data_bit_size / 8 - 4); + gst_bit_writer_reset (&bs); + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write PPS NAL unit"); + gst_bit_writer_reset (&bs); + return FALSE; + } +} + +static gboolean +get_nal_unit_type (GstVaapiEncPicture * picture, guint8 * nal_unit_type) +{ + switch (picture->type) { + case GST_VAAPI_PICTURE_TYPE_I: + if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture)) + *nal_unit_type = GST_H265_NAL_SLICE_IDR_W_RADL; + else + *nal_unit_type = GST_H265_NAL_SLICE_TRAIL_R; + break; + case GST_VAAPI_PICTURE_TYPE_P: + *nal_unit_type = GST_H265_NAL_SLICE_TRAIL_R; + break; + case GST_VAAPI_PICTURE_TYPE_B: + *nal_unit_type = GST_H265_NAL_SLICE_TRAIL_N; + break; + default: + return FALSE; + } + return TRUE; +} + +/* Adds the supplied slice header to the list of packed + headers to pass down as-is to the encoder */ +static gboolean +add_packed_slice_header (GstVaapiEncoderH265 * encoder, + GstVaapiEncPicture * picture, GstVaapiEncSlice * slice) +{ + GstVaapiEncPackedHeader *packed_slice; + GstBitWriter bs; + VAEncPackedHeaderParameterBuffer packed_slice_param = { 0 }; + const VAEncSliceParameterBufferHEVC *const slice_param = slice->param; + guint32 data_bit_size; + guint8 *data; + guint8 nal_unit_type; + + gst_bit_writer_init_with_size (&bs, 128, FALSE); + WRITE_UINT32 (&bs, 0x00000001, 32); /* start code */ + + if (!get_nal_unit_type (picture, &nal_unit_type)) + goto bs_error; + bs_write_nal_header (&bs, nal_unit_type); + + bs_write_slice (&bs, slice_param, encoder, picture, nal_unit_type); + data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs); + data = GST_BIT_WRITER_DATA (&bs); + + packed_slice_param.type = VAEncPackedHeaderSlice; + packed_slice_param.bit_length = data_bit_size; + packed_slice_param.has_emulation_bytes = 0; + + packed_slice = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder), + &packed_slice_param, sizeof (packed_slice_param), + data, (data_bit_size + 7) / 8); + g_assert (packed_slice); + + gst_vaapi_enc_slice_add_packed_header (slice, packed_slice); + gst_vaapi_codec_object_replace (&packed_slice, NULL); + + gst_bit_writer_reset (&bs); + return TRUE; + + /* ERRORS */ +bs_error: + { + GST_WARNING ("failed to write Slice NAL unit header"); + gst_bit_writer_reset (&bs); + return FALSE; + } +} + +/* Reference picture management */ +static void +reference_pic_free (GstVaapiEncoderH265 * encoder, GstVaapiEncoderH265Ref * ref) +{ + if (!ref) + return; + if (ref->pic) + gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder), ref->pic); + g_slice_free (GstVaapiEncoderH265Ref, ref); +} + +static inline GstVaapiEncoderH265Ref * +reference_pic_create (GstVaapiEncoderH265 * encoder, + GstVaapiEncPicture * picture, GstVaapiSurfaceProxy * surface) +{ + GstVaapiEncoderH265Ref *const ref = g_slice_new0 (GstVaapiEncoderH265Ref); + + ref->pic = surface; + ref->poc = picture->poc; + return ref; +} + +static gboolean +reference_list_update (GstVaapiEncoderH265 * encoder, + GstVaapiEncPicture * picture, GstVaapiSurfaceProxy * surface) +{ + GstVaapiEncoderH265Ref *ref; + GstVaapiH265RefPool *const ref_pool = &encoder->ref_pool; + + if (GST_VAAPI_PICTURE_TYPE_B == picture->type) { + gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder), surface); + return TRUE; + } + + if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture)) { + while (!g_queue_is_empty (&ref_pool->ref_list)) + reference_pic_free (encoder, g_queue_pop_head (&ref_pool->ref_list)); + } else if (g_queue_get_length (&ref_pool->ref_list) >= + ref_pool->max_ref_frames) { + reference_pic_free (encoder, g_queue_pop_head (&ref_pool->ref_list)); + } + ref = reference_pic_create (encoder, picture, surface); + g_queue_push_tail (&ref_pool->ref_list, ref); + g_assert (g_queue_get_length (&ref_pool->ref_list) <= + ref_pool->max_ref_frames); + return TRUE; +} + +static gboolean +reference_list_init (GstVaapiEncoderH265 * encoder, + GstVaapiEncPicture * picture, + GstVaapiEncoderH265Ref ** reflist_0, + guint * reflist_0_count, + GstVaapiEncoderH265Ref ** reflist_1, guint * reflist_1_count) +{ + GstVaapiEncoderH265Ref *tmp; + GstVaapiH265RefPool *const ref_pool = &encoder->ref_pool; + GList *iter, *list_0_start = NULL, *list_1_start = NULL; + guint count; + + *reflist_0_count = 0; + *reflist_1_count = 0; + if (picture->type == GST_VAAPI_PICTURE_TYPE_I) + return TRUE; + + iter = g_queue_peek_tail_link (&ref_pool->ref_list); + for (; iter; iter = g_list_previous (iter)) { + tmp = (GstVaapiEncoderH265Ref *) iter->data; + g_assert (tmp && tmp->poc != picture->poc); + if (_poc_greater_than (picture->poc, tmp->poc, encoder->max_pic_order_cnt)) { + list_0_start = iter; + list_1_start = g_list_next (iter); + break; + } + } + + /* order reflist_0 */ + g_assert (list_0_start); + iter = list_0_start; + count = 0; + for (; iter; iter = g_list_previous (iter)) { + reflist_0[count] = (GstVaapiEncoderH265Ref *) iter->data; + ++count; + } + *reflist_0_count = count; + + if (picture->type != GST_VAAPI_PICTURE_TYPE_B) + return TRUE; + + /* order reflist_1 */ + count = 0; + iter = list_1_start; + for (; iter; iter = g_list_next (iter)) { + reflist_1[count] = (GstVaapiEncoderH265Ref *) iter->data; + ++count; + } + *reflist_1_count = count; + return TRUE; +} + +/* Fills in VA sequence parameter buffer */ +static gboolean +fill_sequence (GstVaapiEncoderH265 * encoder, GstVaapiEncSequence * sequence) +{ + VAEncSequenceParameterBufferHEVC *const seq_param = sequence->param; + const GstVideoFormat format = + GST_VIDEO_INFO_FORMAT (GST_VAAPI_ENCODER_VIDEO_INFO (encoder)); + guint bits_depth_luma_minus8 = + GST_VIDEO_FORMAT_INFO_DEPTH (gst_video_format_get_info (format), 0); + if (bits_depth_luma_minus8 < 8) + return FALSE; + bits_depth_luma_minus8 -= 8; + + memset (seq_param, 0, sizeof (VAEncSequenceParameterBufferHEVC)); + + seq_param->general_profile_idc = encoder->profile_idc; + seq_param->general_level_idc = encoder->level_idc; + seq_param->general_tier_flag = encoder->tier; + + seq_param->intra_period = GST_VAAPI_ENCODER_KEYFRAME_PERIOD (encoder); + seq_param->intra_idr_period = encoder->idr_period; + seq_param->ip_period = seq_param->intra_period > 1 ? + (1 + encoder->num_bframes) : 0; + seq_param->bits_per_second = encoder->bitrate_bits; + + seq_param->pic_width_in_luma_samples = encoder->luma_width; + seq_param->pic_height_in_luma_samples = encoder->luma_height; + + /*sequence field values */ + seq_param->seq_fields.value = 0; + seq_param->seq_fields.bits.chroma_format_idc = + gst_vaapi_utils_h265_get_chroma_format_idc + (gst_vaapi_video_format_get_chroma_type (GST_VIDEO_INFO_FORMAT + (GST_VAAPI_ENCODER_VIDEO_INFO (encoder)))); + /* the 4:4:4 chrome format */ + if (seq_param->seq_fields.bits.chroma_format_idc == 3) + seq_param->seq_fields.bits.separate_colour_plane_flag = 0; + seq_param->seq_fields.bits.separate_colour_plane_flag = 0; + seq_param->seq_fields.bits.bit_depth_luma_minus8 = bits_depth_luma_minus8; + seq_param->seq_fields.bits.bit_depth_chroma_minus8 = bits_depth_luma_minus8; + seq_param->seq_fields.bits.scaling_list_enabled_flag = FALSE; + seq_param->seq_fields.bits.strong_intra_smoothing_enabled_flag = TRUE; + seq_param->seq_fields.bits.amp_enabled_flag = TRUE; + seq_param->seq_fields.bits.sample_adaptive_offset_enabled_flag = + encoder->sample_adaptive_offset_enabled_flag = FALSE; + seq_param->seq_fields.bits.pcm_enabled_flag = FALSE; + seq_param->seq_fields.bits.pcm_loop_filter_disabled_flag = FALSE; + seq_param->seq_fields.bits.sps_temporal_mvp_enabled_flag = + encoder->sps_temporal_mvp_enabled_flag = TRUE; + + /* Based on 32x32 CTU (64x64 when using lowpower mode for hardware limitation) */ + seq_param->log2_min_luma_coding_block_size_minus3 = 0; + if (encoder->entrypoint == GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP) + seq_param->log2_diff_max_min_luma_coding_block_size = 3; + else + seq_param->log2_diff_max_min_luma_coding_block_size = 2; + seq_param->log2_min_transform_block_size_minus2 = 0; + seq_param->log2_diff_max_min_transform_block_size = 3; + /* + * Intel HW supports up to 2, we can provide a quirk for other HWs in future + * if other HW may support other values + * + * Refer to https://01.org/sites/default/files/documentation/intel-gfx-prm-osrc-kbl-vol10-hevc.pdf + */ + seq_param->max_transform_hierarchy_depth_inter = 2; + seq_param->max_transform_hierarchy_depth_intra = 2; + + seq_param->pcm_sample_bit_depth_luma_minus1 = 0; + seq_param->pcm_sample_bit_depth_chroma_minus1 = 0; + seq_param->log2_min_pcm_luma_coding_block_size_minus3 = 0; + seq_param->log2_max_pcm_luma_coding_block_size_minus3 = 0; + + /* VUI parameters are always set, at least for timing_info (framerate) */ + seq_param->vui_parameters_present_flag = TRUE; + if (seq_param->vui_parameters_present_flag) { + seq_param->vui_fields.bits.aspect_ratio_info_present_flag = TRUE; + if (seq_param->vui_fields.bits.aspect_ratio_info_present_flag) { + const GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder); + seq_param->aspect_ratio_idc = 0xff; + seq_param->sar_width = GST_VIDEO_INFO_PAR_N (vip); + seq_param->sar_height = GST_VIDEO_INFO_PAR_D (vip); + } + seq_param->vui_fields.bits.bitstream_restriction_flag = FALSE; + seq_param->vui_fields.bits.vui_timing_info_present_flag = TRUE; + if (seq_param->vui_fields.bits.vui_timing_info_present_flag) { + seq_param->vui_num_units_in_tick = GST_VAAPI_ENCODER_FPS_D (encoder); + seq_param->vui_time_scale = GST_VAAPI_ENCODER_FPS_N (encoder); + } + } + + if (h265_is_scc (encoder)) { +#if VA_CHECK_VERSION(1,8,0) + seq_param->scc_fields.bits.palette_mode_enabled_flag = 1; +#else + /* SCC profile should not be selected. */ + g_assert_not_reached (); + return FALSE; +#endif + } + + return TRUE; +} + +/* CTUs in each tile column */ +static guint32 tile_ctu_cols[GST_VAAPI_H265_MAX_COL_TILES]; +/* CTUs in each tile row */ +static guint32 tile_ctu_rows[GST_VAAPI_H265_MAX_ROW_TILES]; + +/* Fills in VA picture parameter buffer */ +static gboolean +fill_picture (GstVaapiEncoderH265 * encoder, GstVaapiEncPicture * picture, + GstVaapiCodedBuffer * codedbuf, GstVaapiSurfaceProxy * surface) +{ + VAEncPictureParameterBufferHEVC *const pic_param = picture->param; + GstVaapiH265RefPool *const ref_pool = &encoder->ref_pool; + GstVaapiEncoderH265Ref *ref_pic; + GList *reflist; + guint i; + guint8 nal_unit_type, no_output_of_prior_pics_flag = 0; + + memset (pic_param, 0, sizeof (VAEncPictureParameterBufferHEVC)); + + pic_param->decoded_curr_pic.picture_id = + GST_VAAPI_SURFACE_PROXY_SURFACE_ID (surface); + pic_param->decoded_curr_pic.pic_order_cnt = picture->poc; + pic_param->decoded_curr_pic.flags = 0; + + i = 0; + if (picture->type != GST_VAAPI_PICTURE_TYPE_I) { + for (reflist = g_queue_peek_head_link (&ref_pool->ref_list); + reflist; reflist = g_list_next (reflist)) { + ref_pic = reflist->data; + g_assert (ref_pic && ref_pic->pic && + GST_VAAPI_SURFACE_PROXY_SURFACE_ID (ref_pic->pic) != VA_INVALID_ID); + + pic_param->reference_frames[i].picture_id = + GST_VAAPI_SURFACE_PROXY_SURFACE_ID (ref_pic->pic); + pic_param->reference_frames[i].pic_order_cnt = ref_pic->poc; + ++i; + } + g_assert (i <= 15 && i <= ref_pool->max_ref_frames); + } + for (; i < 15; ++i) { + pic_param->reference_frames[i].picture_id = VA_INVALID_SURFACE; + pic_param->reference_frames[i].flags = VA_PICTURE_HEVC_INVALID; + } + pic_param->coded_buf = GST_VAAPI_CODED_BUFFER_ID (codedbuf); + + /* slice_temporal_mvp_enable_flag == FALSE */ + pic_param->collocated_ref_pic_index = 0xFF; + + pic_param->last_picture = 0; + pic_param->pic_init_qp = encoder->qp_i; + pic_param->num_ref_idx_l0_default_active_minus1 = + (ref_pool->max_reflist0_count ? (ref_pool->max_reflist0_count - 1) : 0); + pic_param->num_ref_idx_l1_default_active_minus1 = + (ref_pool->max_reflist1_count ? (ref_pool->max_reflist1_count - 1) : 0); + + if (!get_nal_unit_type (picture, &nal_unit_type)) + return FALSE; + pic_param->nal_unit_type = nal_unit_type; + + /* set picture fields */ + pic_param->pic_fields.value = 0; + pic_param->pic_fields.bits.idr_pic_flag = + GST_VAAPI_ENC_PICTURE_IS_IDR (picture); + pic_param->pic_fields.bits.coding_type = picture->type; + if (picture->type != GST_VAAPI_PICTURE_TYPE_B) + pic_param->pic_fields.bits.reference_pic_flag = TRUE; + pic_param->pic_fields.bits.sign_data_hiding_enabled_flag = FALSE; + pic_param->pic_fields.bits.transform_skip_enabled_flag = TRUE; + /* it seems driver requires enablement of cu_qp_delta_enabled_flag + * to modifiy QP values in CBR mode or low power encoding */ + if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) != GST_VAAPI_RATECONTROL_CQP + || picture->has_roi + || encoder->entrypoint == GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP) + pic_param->pic_fields.bits.cu_qp_delta_enabled_flag = 1; + + /* XXX: Intel's media-driver, when using low-power mode, requires + * that diff_cu_qp_delta_depth has to be equal to + * log2_diff_max_min_luma_coding_block_size, meaning 3. + * + * For now we assume that on only Intel's media-drivers supports + * H265 low-power */ + if ((encoder->entrypoint == GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP) && + (pic_param->pic_fields.bits.cu_qp_delta_enabled_flag)) + pic_param->diff_cu_qp_delta_depth = 3; + + pic_param->pic_fields.bits.pps_loop_filter_across_slices_enabled_flag = TRUE; + + if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture)) + no_output_of_prior_pics_flag = 1; + pic_param->pic_fields.bits.no_output_of_prior_pics_flag = + no_output_of_prior_pics_flag; + + /* Setup tile info */ + pic_param->pic_fields.bits.tiles_enabled_flag = + h265_is_tile_enabled (encoder); + if (pic_param->pic_fields.bits.tiles_enabled_flag) { + /* Always set loop filter across tiles enabled now */ + pic_param->pic_fields.bits.loop_filter_across_tiles_enabled_flag = 1; + + pic_param->num_tile_columns_minus1 = encoder->num_tile_cols - 1; + pic_param->num_tile_rows_minus1 = encoder->num_tile_rows - 1; + + /* The VA row_height_minus1 and column_width_minus1 size is 1 smaller + than the MAX_COL_TILES and MAX_ROW_TILES, which means the driver + can deduce the last tile's size based on the picture info. We need + to take care of the array size here. */ + for (i = 0; i < MIN (encoder->num_tile_cols, 19); ++i) + pic_param->column_width_minus1[i] = tile_ctu_cols[i] - 1; + for (i = 0; i < MIN (encoder->num_tile_rows, 21); ++i) + pic_param->row_height_minus1[i] = tile_ctu_rows[i] - 1; + } + + if (h265_is_scc (encoder)) { +#if VA_CHECK_VERSION(1,8,0) + pic_param->scc_fields.bits.pps_curr_pic_ref_enabled_flag = 1; +#else + /* SCC profile should not be selected. */ + g_assert_not_reached (); + return FALSE; +#endif + } + + return TRUE; +} + +static GstVaapiEncSlice * +create_and_fill_one_slice (GstVaapiEncoderH265 * encoder, + GstVaapiEncPicture * picture, + GstVaapiEncoderH265Ref ** reflist_0, guint reflist_0_count, + GstVaapiEncoderH265Ref ** reflist_1, guint reflist_1_count) +{ + VAEncSliceParameterBufferHEVC *slice_param; + GstVaapiEncSlice *slice; + guint i_ref; + + slice = GST_VAAPI_ENC_SLICE_NEW (HEVC, encoder); + g_assert (slice && slice->param_id != VA_INVALID_ID); + slice_param = slice->param; + memset (slice_param, 0, sizeof (VAEncSliceParameterBufferHEVC)); + + slice_param->slice_type = h265_get_slice_type (picture->type); + if (encoder->no_p_frame && slice_param->slice_type == GST_H265_P_SLICE) { + slice_param->slice_type = GST_H265_B_SLICE; + } else if (h265_is_scc (encoder) && + slice_param->slice_type == GST_H265_I_SLICE) { + /* In scc mode, the I frame can ref to itself and so need the L0 + reference list enabled. Just set the I frame to P_SLICE type + and leaving all reference unchanged. So all ref_pic_list0's + picture is invalid, the only ref is itself enabled by + pic_param->scc_fields.bits.pps_curr_pic_ref_enabled_flag. */ + slice_param->slice_type = GST_H265_P_SLICE; + } + + slice_param->slice_pic_parameter_set_id = 0; + + slice_param->slice_fields.bits.num_ref_idx_active_override_flag = + reflist_0_count || reflist_1_count; + if (picture->type != GST_VAAPI_PICTURE_TYPE_I && reflist_0_count > 0) + slice_param->num_ref_idx_l0_active_minus1 = reflist_0_count - 1; + else + slice_param->num_ref_idx_l0_active_minus1 = 0; + if (picture->type == GST_VAAPI_PICTURE_TYPE_B && reflist_1_count > 0) + slice_param->num_ref_idx_l1_active_minus1 = reflist_1_count - 1; + else + slice_param->num_ref_idx_l1_active_minus1 = 0; + if (picture->type == GST_VAAPI_PICTURE_TYPE_P && encoder->no_p_frame) + slice_param->num_ref_idx_l1_active_minus1 = + slice_param->num_ref_idx_l0_active_minus1; + + i_ref = 0; + if (picture->type != GST_VAAPI_PICTURE_TYPE_I) { + for (; i_ref < reflist_0_count; ++i_ref) { + slice_param->ref_pic_list0[i_ref].picture_id = + GST_VAAPI_SURFACE_PROXY_SURFACE_ID (reflist_0[i_ref]->pic); + slice_param->ref_pic_list0[i_ref].pic_order_cnt = reflist_0[i_ref]->poc; + } + } + for (; i_ref < G_N_ELEMENTS (slice_param->ref_pic_list0); ++i_ref) { + slice_param->ref_pic_list0[i_ref].picture_id = VA_INVALID_SURFACE; + slice_param->ref_pic_list0[i_ref].flags = VA_PICTURE_HEVC_INVALID; + } + + i_ref = 0; + if (picture->type == GST_VAAPI_PICTURE_TYPE_B) { + for (; i_ref < reflist_1_count; ++i_ref) { + slice_param->ref_pic_list1[i_ref].picture_id = + GST_VAAPI_SURFACE_PROXY_SURFACE_ID (reflist_1[i_ref]->pic); + slice_param->ref_pic_list1[i_ref].pic_order_cnt = reflist_1[i_ref]->poc; + } + } else if (picture->type == GST_VAAPI_PICTURE_TYPE_P && encoder->no_p_frame) { + for (; i_ref < reflist_0_count; ++i_ref) { + slice_param->ref_pic_list1[i_ref].picture_id = + GST_VAAPI_SURFACE_PROXY_SURFACE_ID (reflist_0[i_ref]->pic); + slice_param->ref_pic_list1[i_ref].pic_order_cnt = reflist_0[i_ref]->poc; + } + } + for (; i_ref < G_N_ELEMENTS (slice_param->ref_pic_list1); ++i_ref) { + slice_param->ref_pic_list1[i_ref].picture_id = VA_INVALID_SURFACE; + slice_param->ref_pic_list1[i_ref].flags = VA_PICTURE_HEVC_INVALID; + } + + slice_param->max_num_merge_cand = 5; /* MaxNumMergeCand */ + slice_param->slice_qp_delta = encoder->qp_i - encoder->init_qp; + if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CQP) { + if (picture->type == GST_VAAPI_PICTURE_TYPE_P) { + slice_param->slice_qp_delta += encoder->qp_ip; + } else if (picture->type == GST_VAAPI_PICTURE_TYPE_B) { + slice_param->slice_qp_delta += encoder->qp_ib; + } + if ((gint) encoder->init_qp + slice_param->slice_qp_delta < + (gint) encoder->min_qp) { + slice_param->slice_qp_delta = encoder->min_qp - encoder->init_qp; + } + if ((gint) encoder->init_qp + slice_param->slice_qp_delta > + (gint) encoder->max_qp) { + slice_param->slice_qp_delta = encoder->max_qp - encoder->init_qp; + } + } + + slice_param->slice_fields.bits.slice_loop_filter_across_slices_enabled_flag = + TRUE; + + return slice; +} + +/* Adds slice headers to picture */ +static gboolean +add_slice_headers (GstVaapiEncoderH265 * encoder, GstVaapiEncPicture * picture, + GstVaapiEncoderH265Ref ** reflist_0, guint reflist_0_count, + GstVaapiEncoderH265Ref ** reflist_1, guint reflist_1_count) +{ + VAEncSliceParameterBufferHEVC *slice_param; + GstVaapiEncSlice *slice; + guint slice_of_ctus, slice_mod_ctus, cur_slice_ctus; + guint ctu_size; + guint ctu_width_round_factor; + guint last_ctu_index; + guint i_slice; + + g_assert (picture); + + if (h265_is_tile_enabled (encoder)) { + for (i_slice = 0; i_slice < encoder->num_slices; ++i_slice) { + encoder->first_slice_segment_in_pic_flag = (i_slice == 0); + + slice = create_and_fill_one_slice (encoder, picture, reflist_0, + reflist_0_count, reflist_1, reflist_1_count); + slice_param = slice->param; + + slice_param->slice_segment_address = + encoder->tile_slice_address_map[encoder->tile_slice_address[i_slice]]; + slice_param->num_ctu_in_slice = encoder->tile_slice_ctu_num[i_slice]; + GST_LOG ("slice %d start tile address is %d, start address is %d," + " CTU num %d", i_slice, encoder->tile_slice_address[i_slice], + slice_param->slice_segment_address, slice_param->num_ctu_in_slice); + + if (i_slice == encoder->num_slices - 1) + slice_param->slice_fields.bits.last_slice_of_pic_flag = 1; + + if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) & + VA_ENC_PACKED_HEADER_SLICE) + && !add_packed_slice_header (encoder, picture, slice)) + goto error_create_packed_slice_hdr; + + gst_vaapi_enc_picture_add_slice (picture, slice); + gst_vaapi_codec_object_replace (&slice, NULL); + } + } else { + ctu_size = encoder->ctu_width * encoder->ctu_height; + + g_assert (encoder->num_slices && encoder->num_slices < ctu_size); + slice_of_ctus = ctu_size / encoder->num_slices; + slice_mod_ctus = ctu_size % encoder->num_slices; + last_ctu_index = 0; + + for (i_slice = 0; + i_slice < encoder->num_slices && (last_ctu_index < ctu_size); + ++i_slice) { + cur_slice_ctus = slice_of_ctus; + if (slice_mod_ctus) { + ++cur_slice_ctus; + --slice_mod_ctus; + } + + slice = create_and_fill_one_slice (encoder, picture, reflist_0, + reflist_0_count, reflist_1, reflist_1_count); + slice_param = slice->param; + + /* Work-around for satisfying the VA-Intel driver. + * The driver only support multi slice begin from row start address */ + ctu_width_round_factor = + encoder->ctu_width - (cur_slice_ctus % encoder->ctu_width); + cur_slice_ctus += ctu_width_round_factor; + if ((last_ctu_index + cur_slice_ctus) > ctu_size) + cur_slice_ctus = ctu_size - last_ctu_index; + + if (i_slice == 0) { + encoder->first_slice_segment_in_pic_flag = TRUE; + slice_param->slice_segment_address = 0; + } else { + encoder->first_slice_segment_in_pic_flag = FALSE; + slice_param->slice_segment_address = last_ctu_index; + } + slice_param->num_ctu_in_slice = cur_slice_ctus; + + /* set calculation for next slice */ + last_ctu_index += cur_slice_ctus; + + if ((i_slice == encoder->num_slices - 1) || (last_ctu_index == ctu_size)) + slice_param->slice_fields.bits.last_slice_of_pic_flag = 1; + + if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) & + VA_ENC_PACKED_HEADER_SLICE) + && !add_packed_slice_header (encoder, picture, slice)) + goto error_create_packed_slice_hdr; + + gst_vaapi_enc_picture_add_slice (picture, slice); + gst_vaapi_codec_object_replace (&slice, NULL); + } + + if (i_slice < encoder->num_slices) + GST_WARNING + ("Using less number of slices than requested, Number of slices per" + " pictures is %d", i_slice); + g_assert (last_ctu_index == ctu_size); + } + + return TRUE; + +error_create_packed_slice_hdr: + { + GST_ERROR ("failed to create packed slice header buffer"); + gst_vaapi_codec_object_replace (&slice, NULL); + return FALSE; + } +} + +/* Generates and submits SPS header accordingly into the bitstream */ +static gboolean +ensure_sequence (GstVaapiEncoderH265 * encoder, GstVaapiEncPicture * picture) +{ + GstVaapiEncSequence *sequence = NULL; + + /* submit an SPS header before every new I-frame, if codec config changed */ + if (!encoder->config_changed || picture->type != GST_VAAPI_PICTURE_TYPE_I) + return TRUE; + + sequence = GST_VAAPI_ENC_SEQUENCE_NEW (HEVC, encoder); + if (!sequence || !fill_sequence (encoder, sequence)) + goto error_create_seq_param; + + /* add packed vps and sps headers */ + if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) & + VA_ENC_PACKED_HEADER_SEQUENCE) + && !(add_packed_vps_header (encoder, picture, sequence) + && add_packed_sequence_header (encoder, picture, sequence))) { + goto error_create_packed_seq_hdr; + } + + if (sequence) { + gst_vaapi_enc_picture_set_sequence (picture, sequence); + gst_vaapi_codec_object_replace (&sequence, NULL); + } + + encoder->config_changed = FALSE; + return TRUE; + + /* ERRORS */ +error_create_seq_param: + { + GST_ERROR ("failed to create sequence parameter buffer (SPS)"); + gst_vaapi_codec_object_replace (&sequence, NULL); + return FALSE; + } +error_create_packed_seq_hdr: + { + GST_ERROR ("failed to create packed sequence header buffer"); + gst_vaapi_codec_object_replace (&sequence, NULL); + return FALSE; + } +} + +static gboolean +ensure_control_rate_params (GstVaapiEncoderH265 * encoder) +{ + if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CQP) + return TRUE; + +#if VA_CHECK_VERSION(1,1,0) + if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_ICQ) { + GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).ICQ_quality_factor = + encoder->quality_factor; + return TRUE; + } +#endif + + /* RateControl params */ + GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).bits_per_second = + encoder->bitrate_bits; + /* CPB (Coded picture buffer) length in milliseconds, which could be + * provided as a property */ + GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).window_size = encoder->cpb_length; + GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).initial_qp = encoder->init_qp; + GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).min_qp = encoder->min_qp; + +#if VA_CHECK_VERSION(1,1,0) + GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).max_qp = encoder->max_qp; +#endif + +#if VA_CHECK_VERSION(1,0,0) + GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).rc_flags.bits.mb_rate_control = + (guint) encoder->mbbrc; +#endif + +#if VA_CHECK_VERSION(1,3,0) + GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).quality_factor = + encoder->quality_factor; +#endif + + /* HRD params */ + fill_hrd_params (encoder, &GST_VAAPI_ENCODER_VA_HRD (encoder)); + + return TRUE; +} + +static gboolean +ensure_misc_params (GstVaapiEncoderH265 * encoder, GstVaapiEncPicture * picture) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); + + if (!gst_vaapi_encoder_ensure_param_control_rate (base_encoder, picture)) + return FALSE; + if (!gst_vaapi_encoder_ensure_param_roi_regions (base_encoder, picture)) + return FALSE; + if (!gst_vaapi_encoder_ensure_param_quality_level (base_encoder, picture)) + return FALSE; + return TRUE; +} + +/* Generates and submits PPS header accordingly into the bitstream */ +static gboolean +ensure_picture (GstVaapiEncoderH265 * encoder, GstVaapiEncPicture * picture, + GstVaapiCodedBufferProxy * codedbuf_proxy, GstVaapiSurfaceProxy * surface) +{ + GstVaapiCodedBuffer *const codedbuf = + GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (codedbuf_proxy); + gboolean res = FALSE; + + res = fill_picture (encoder, picture, codedbuf, surface); + + if (!res) + return FALSE; + + if (picture->type == GST_VAAPI_PICTURE_TYPE_I && + (GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) & + VA_ENC_PACKED_HEADER_PICTURE) + && !add_packed_picture_header (encoder, picture)) { + GST_ERROR ("set picture packed header failed"); + return FALSE; + } + return TRUE; +} + + +/* Generates slice headers */ +static gboolean +ensure_slices (GstVaapiEncoderH265 * encoder, GstVaapiEncPicture * picture) +{ + GstVaapiEncoderH265Ref *reflist_0[15]; + GstVaapiEncoderH265Ref *reflist_1[15]; + GstVaapiH265RefPool *const ref_pool = &encoder->ref_pool; + guint reflist_0_count = 0, reflist_1_count = 0; + + g_assert (picture); + + if (picture->type != GST_VAAPI_PICTURE_TYPE_I && + !reference_list_init (encoder, picture, + reflist_0, &reflist_0_count, reflist_1, &reflist_1_count)) { + GST_ERROR ("reference list reorder failed"); + return FALSE; + } + + g_assert (reflist_0_count + reflist_1_count <= ref_pool->max_ref_frames); + if (reflist_0_count > ref_pool->max_reflist0_count) + reflist_0_count = ref_pool->max_reflist0_count; + if (reflist_1_count > ref_pool->max_reflist1_count) + reflist_1_count = ref_pool->max_reflist1_count; + + if (!add_slice_headers (encoder, picture, + reflist_0, reflist_0_count, reflist_1, reflist_1_count)) + return FALSE; + + return TRUE; +} + +/* Normalizes bitrate (and CPB size) for HRD conformance */ +static void +ensure_bitrate_hrd (GstVaapiEncoderH265 * encoder) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); + guint bitrate, cpb_size; + + if (!base_encoder->bitrate) { + encoder->bitrate_bits = 0; + return; + } + + /* Round down bitrate. This is a hard limit mandated by the user */ + g_assert (SX_BITRATE >= 6); + bitrate = (base_encoder->bitrate * 1000) & ~((1U << SX_BITRATE) - 1); + if (bitrate != encoder->bitrate_bits) { + GST_DEBUG ("HRD bitrate: %u bits/sec", bitrate); + encoder->bitrate_bits = bitrate; + encoder->config_changed = TRUE; + } + + /* Round up CPB size. This is an HRD compliance detail */ + g_assert (SX_CPB_SIZE >= 4); + cpb_size = gst_util_uint64_scale (bitrate, encoder->cpb_length, 1000) & + ~((1U << SX_CPB_SIZE) - 1); + if (cpb_size != encoder->cpb_length_bits) { + GST_DEBUG ("HRD CPB size: %u bits", cpb_size); + encoder->cpb_length_bits = cpb_size; + encoder->config_changed = TRUE; + } +} + +/* Estimates a good enough bitrate if none was supplied */ +static void +ensure_bitrate (GstVaapiEncoderH265 * encoder) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); + + switch (GST_VAAPI_ENCODER_RATE_CONTROL (encoder)) { + case GST_VAAPI_RATECONTROL_CBR: + case GST_VAAPI_RATECONTROL_VBR: + case GST_VAAPI_RATECONTROL_QVBR: + if (!base_encoder->bitrate) { + /* FIXME: Provide better estimation */ + /* Using a 1/6 compression ratio */ + /* 12 bits per pixel for YUV420 */ + guint64 factor; + + factor = (guint64) encoder->luma_width * encoder->luma_height * 12 / 6; + base_encoder->bitrate = + gst_util_uint64_scale (factor, GST_VAAPI_ENCODER_FPS_N (encoder), + GST_VAAPI_ENCODER_FPS_D (encoder)) / 1000; + GST_INFO ("target bitrate computed to %u kbps", base_encoder->bitrate); + } + break; + default: + base_encoder->bitrate = 0; + break; + } + ensure_bitrate_hrd (encoder); +} + +/* Constructs profile, tier and level information based on user-defined limits */ +static GstVaapiEncoderStatus +ensure_profile_tier_level (GstVaapiEncoderH265 * encoder) +{ + const GstVaapiProfile profile = encoder->profile; + const GstVaapiTierH265 tier = encoder->tier; + const GstVaapiLevelH265 level = encoder->level; + + if (!ensure_profile (encoder)) + return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + + encoder->entrypoint = + gst_vaapi_encoder_get_entrypoint (GST_VAAPI_ENCODER_CAST (encoder), + encoder->profile); + g_assert (encoder->entrypoint != GST_VAAPI_ENTRYPOINT_INVALID); + + /* Ensure bitrate if not set already and derive the right level to use */ + ensure_bitrate (encoder); + + if (!ensure_tier_level (encoder)) + return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED; + + if (encoder->profile != profile || encoder->level != level + || encoder->tier != tier) { + GST_DEBUG ("selected %s profile at tier %s and level %s", + gst_vaapi_utils_h265_get_profile_string (encoder->profile), + gst_vaapi_utils_h265_get_tier_string (encoder->tier), + gst_vaapi_utils_h265_get_level_string (encoder->level)); + encoder->config_changed = TRUE; + } + return GST_VAAPI_ENCODER_STATUS_SUCCESS; +} + +static gboolean +check_ref_list (GstVaapiEncoderH265 * encoder) +{ +#if VA_CHECK_VERSION(1,9,0) + /* Some driver require both r0 and r1 list are non NULL, i.e. no p frame + in the stream. The traditional P frame can be converted to B frame with + forward dependency only. The new B frame has only forward reference in + both r0 and r1 list, which conforms to H265 spec. This can get some gain + because there are 2 MVs for each frame and can generate better motion + estimation. */ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (encoder); + guint value = 0; + VAProfile va_profile = gst_vaapi_profile_get_va_profile (encoder->profile); + VAEntrypoint va_entrypoint = + gst_vaapi_entrypoint_get_va_entrypoint (encoder->entrypoint); + + encoder->no_p_frame = FALSE; + if (gst_vaapi_get_config_attribute (base_encoder->display, va_profile, + va_entrypoint, VAConfigAttribPredictionDirection, &value)) { + gboolean double_ref_list = + ((value & VA_PREDICTION_DIRECTION_BI_NOT_EMPTY) != 0); + if (double_ref_list) { + GST_INFO ("driver does not support P frame, we need to convert P" + " frame to forward dependency B frame."); + encoder->no_p_frame = double_ref_list; + } + } + + if (encoder->no_p_frame == TRUE && base_encoder->max_num_ref_frames_1 < 1) { + GST_WARNING ("P frame should be converted to forward dependent B," + " but reference list 1 is disabled here. Should be an invalid" + " setting or a driver error."); + return FALSE; + } +#endif + + return TRUE; +} + +static GstVaapiEncoderStatus +reset_properties (GstVaapiEncoderH265 * encoder) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); + GstVaapiH265ReorderPool *reorder_pool; + GstVaapiH265RefPool *ref_pool; + guint ctu_size; + gboolean ret; + + if (encoder->idr_period < base_encoder->keyframe_period) + encoder->idr_period = base_encoder->keyframe_period; + + if (encoder->min_qp > encoder->init_qp) + encoder->min_qp = encoder->init_qp; + if (encoder->max_qp < encoder->init_qp) + encoder->max_qp = encoder->init_qp; + + encoder->qp_i = encoder->init_qp; + + ctu_size = encoder->ctu_width * encoder->ctu_height; + ret = gst_vaapi_encoder_ensure_num_slices (base_encoder, encoder->profile, + encoder->entrypoint, (ctu_size + 1) / 2, &encoder->num_slices); + g_assert (ret); + + gst_vaapi_encoder_ensure_max_num_ref_frames (base_encoder, encoder->profile, + encoder->entrypoint); + + if (!check_ref_list (encoder)) + return GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN; + + if (base_encoder->max_num_ref_frames_1 < 1 && encoder->num_bframes > 0) { + GST_WARNING ("Disabling b-frame since the driver doesn't support it"); + encoder->num_bframes = 0; + } + + if (encoder->num_ref_frames > base_encoder->max_num_ref_frames_0) { + GST_INFO ("Lowering the number of reference frames to %d", + base_encoder->max_num_ref_frames_0); + encoder->num_ref_frames = base_encoder->max_num_ref_frames_0; + } + + if (encoder->num_bframes > (base_encoder->keyframe_period + 1) / 2) + encoder->num_bframes = (base_encoder->keyframe_period + 1) / 2; + + if (encoder->num_bframes > 0 && GST_VAAPI_ENCODER_FPS_N (encoder) > 0) + encoder->cts_offset = gst_util_uint64_scale (GST_SECOND, + GST_VAAPI_ENCODER_FPS_D (encoder), GST_VAAPI_ENCODER_FPS_N (encoder)); + else + encoder->cts_offset = 0; + + /* init max_poc */ + encoder->log2_max_pic_order_cnt = + h265_get_log2_max_pic_order_cnt (encoder->idr_period); + g_assert (encoder->log2_max_pic_order_cnt >= 4); + encoder->max_pic_order_cnt = (1 << encoder->log2_max_pic_order_cnt); + encoder->idr_num = 0; + + /* Only Supporting a maximum of two reference frames */ + if (encoder->num_bframes) { + encoder->max_dec_pic_buffering = encoder->num_ref_frames + 2; + encoder->max_num_reorder_pics = 1; + } else { + encoder->max_dec_pic_buffering = encoder->num_ref_frames + 1; + encoder->max_num_reorder_pics = 0; + } + + ref_pool = &encoder->ref_pool; + ref_pool->max_reflist0_count = encoder->num_ref_frames; + ref_pool->max_reflist1_count = encoder->num_bframes > 0; + ref_pool->max_ref_frames = ref_pool->max_reflist0_count + + ref_pool->max_reflist1_count; + + reorder_pool = &encoder->reorder_pool; + reorder_pool->frame_index = 0; + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; +} + +static void +reset_tile (GstVaapiEncoderH265 * encoder) +{ + memset (tile_ctu_cols, 0, sizeof (tile_ctu_cols)); + memset (tile_ctu_rows, 0, sizeof (tile_ctu_rows)); + + if (encoder->tile_slice_address) + g_free (encoder->tile_slice_address); + encoder->tile_slice_address = NULL; + + if (encoder->tile_slice_ctu_num) + g_free (encoder->tile_slice_ctu_num); + encoder->tile_slice_ctu_num = NULL; + + if (encoder->tile_slice_address_map) + g_free (encoder->tile_slice_address_map); + encoder->tile_slice_address_map = NULL; +} + +static void +recalculate_slices_num_by_tile (GstVaapiEncoderH265 * encoder) +{ + GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (encoder); + + /* If driver has the requirement that the slice should not span tiles, + we need to increase slice number if needed. */ + if (gst_vaapi_display_has_driver_quirks (display, + GST_VAAPI_DRIVER_QUIRK_HEVC_ENC_SLICE_NOT_SPAN_TILE)) { + if (encoder->num_slices < encoder->num_tile_cols * encoder->num_tile_rows) { + /* encoder->num_slices > 1 means user set it */ + if (encoder->num_slices > 1) + GST_WARNING ("user set num-slices to %d, which is smaller than tile" + " num %d. We should make slice not span tiles, just set the" + " num-slices to tile num here.", + encoder->num_slices, + encoder->num_tile_cols * encoder->num_tile_rows); + else + GST_INFO ("set default slice num to %d, the same as the tile num.", + encoder->num_tile_cols * encoder->num_tile_rows); + encoder->num_slices = encoder->num_tile_cols * encoder->num_tile_rows; + } + } +} + +static GstVaapiEncoderStatus +calculate_slices_start_address (GstVaapiEncoderH265 * encoder) +{ + GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (encoder); + guint32 ctu_per_slice; + guint32 left_slices; + gint32 i, j, k; + + /* If driver has the requirement that the slice should not span tiles, + firstly we should scatter slices uniformly into each tile, bigger + tile gets more slices. Then we should assign CTUs within one tile + uniformly to each slice in that tile. */ + if (gst_vaapi_display_has_driver_quirks (display, + GST_VAAPI_DRIVER_QUIRK_HEVC_ENC_SLICE_NOT_SPAN_TILE)) { + guint32 *slices_per_tile = g_malloc (encoder->num_tile_cols * + encoder->num_tile_rows * sizeof (guint32)); + if (!slices_per_tile) + return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED; + + ctu_per_slice = (encoder->ctu_width * encoder->ctu_height + + encoder->num_slices - 1) / encoder->num_slices; + g_assert (ctu_per_slice > 0); + left_slices = encoder->num_slices; + + for (i = 0; i < encoder->num_tile_cols * encoder->num_tile_rows; i++) { + slices_per_tile[i] = 1; + left_slices--; + } + while (left_slices) { + /* Find the biggest CTUs/slices, and assign more. */ + gfloat largest = 0.0f; + k = -1; + for (i = 0; i < encoder->num_tile_cols * encoder->num_tile_rows; i++) { + gfloat f; + f = ((gfloat) (tile_ctu_cols[i % encoder->num_tile_cols] * + tile_ctu_rows[i / encoder->num_tile_cols])) / + (gfloat) slices_per_tile[i]; + g_assert (f >= 1.0f); + if (f > largest) { + k = i; + largest = f; + } + } + + g_assert (k >= 0); + slices_per_tile[k]++; + left_slices--; + } + + /* Assign CTUs in one tile uniformly to each slice. Note: the slice start + address is CTB address in tile scan(see spec 6.5), that is, we accumulate + all CTUs in tile0, then tile1, and tile2..., not from the picture's + perspective. */ + encoder->tile_slice_address[0] = 0; + k = 1; + for (i = 0; i < encoder->num_tile_rows; i++) { + for (j = 0; j < encoder->num_tile_cols; j++) { + guint32 s_num = slices_per_tile[i * encoder->num_tile_cols + j]; + guint32 one_tile_ctus = tile_ctu_cols[j] * tile_ctu_rows[i]; + guint32 s; + + GST_LOG ("Tile(row %d col %d), has CTU in col %d," + " CTU in row is %d, total CTU %d, assigned %d slices", i, j, + tile_ctu_cols[j], tile_ctu_rows[i], one_tile_ctus, s_num); + + g_assert (s_num > 0); + for (s = 0; s < s_num; s++) { + encoder->tile_slice_address[k] = + encoder->tile_slice_address[k - 1] + ((s + + 1) * one_tile_ctus) / s_num - (s * one_tile_ctus) / s_num; + encoder->tile_slice_ctu_num[k - 1] = + encoder->tile_slice_address[k] - encoder->tile_slice_address[k - + 1]; + k++; + } + } + } + + g_assert (k == encoder->num_slices + 1); + /* Calculate the last one */ + encoder->tile_slice_ctu_num[encoder->num_slices - 1] = + encoder->ctu_width * encoder->ctu_height - + encoder->tile_slice_address[encoder->num_slices - 1]; + + g_free (slices_per_tile); + } + /* The easy way, just assign CTUs to each slice uniformly */ + else { + ctu_per_slice = (encoder->ctu_width * encoder->ctu_height + + encoder->num_slices - 1) / encoder->num_slices; + g_assert (ctu_per_slice > 0); + + for (i = 0; i < encoder->num_slices - 1; i++) + encoder->tile_slice_ctu_num[i] = ctu_per_slice; + encoder->tile_slice_ctu_num[encoder->num_slices - 1] = + encoder->ctu_width * encoder->ctu_height - + (encoder->num_slices - 1) * ctu_per_slice; + + encoder->tile_slice_address[0] = 0; + for (i = 1; i <= encoder->num_slices; i++) + encoder->tile_slice_address[i] = encoder->tile_slice_address[i - 1] + + encoder->tile_slice_ctu_num[i - 1]; + } + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; +} + +static GstVaapiEncoderStatus +ensure_tile (GstVaapiEncoderH265 * encoder) +{ + gint32 i, j, k; + guint32 ctu_tile_width_accu[GST_VAAPI_H265_MAX_COL_TILES + 1]; + guint32 ctu_tile_height_accu[GST_VAAPI_H265_MAX_ROW_TILES + 1]; + guint32 num_slices; + GstVaapiEncoderStatus ret; + + reset_tile (encoder); + + if (!h265_is_tile_enabled (encoder)) + return GST_VAAPI_ENCODER_STATUS_SUCCESS; + + if (!gst_vaapi_encoder_ensure_tile_support (GST_VAAPI_ENCODER (encoder), + encoder->profile, encoder->entrypoint)) { + GST_ERROR ("The profile:%s, entrypoint:%d does not support tile.", + gst_vaapi_utils_h265_get_profile_string (encoder->profile), + encoder->entrypoint); + return GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN; + } + + if (encoder->num_tile_cols > + gst_vaapi_utils_h265_get_level_limits (encoder->level)->MaxTileColumns) { + GST_ERROR ("num_tile_cols:%d exceeds MaxTileColumns:%d", + encoder->num_tile_cols, + gst_vaapi_utils_h265_get_level_limits (encoder->level)->MaxTileColumns); + return GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN; + } + if (encoder->num_tile_rows > + gst_vaapi_utils_h265_get_level_limits (encoder->level)->MaxTileRows) { + GST_ERROR ("num_tile_rows:%d exceeds MaxTileRows:%d", + encoder->num_tile_rows, + gst_vaapi_utils_h265_get_level_limits (encoder->level)->MaxTileRows); + return GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN; + } + + if (encoder->ctu_width < encoder->num_tile_cols) { + GST_WARNING + ("Only %d CTUs in width, not enough to split into %d tile columns", + encoder->ctu_width, encoder->num_tile_cols); + return GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN; + } + if (encoder->ctu_height < encoder->num_tile_rows) { + GST_WARNING + ("Only %d CTUs in height, not enough to split into %d tile rows", + encoder->ctu_height, encoder->num_tile_rows); + return GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN; + } + + recalculate_slices_num_by_tile (encoder); + + /* ensure not exceed max supported slices */ + num_slices = encoder->num_slices; + gst_vaapi_encoder_ensure_num_slices (GST_VAAPI_ENCODER_CAST (encoder), + encoder->profile, encoder->entrypoint, + (encoder->ctu_width * encoder->ctu_height + 1) / 2, &num_slices); + if (num_slices != encoder->num_slices) { + GST_ERROR ("The tile setting need at least %d slices, but the max" + " slice number is just %d", encoder->num_slices, num_slices); + return GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN; + } + + encoder->tile_slice_address = + /* Add one as sentinel, hold val to calculate ctu_num */ + g_malloc ((encoder->num_slices + 1) * sizeof (guint32)); + if (!encoder->tile_slice_address) + return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED; + encoder->tile_slice_ctu_num = + g_malloc (encoder->num_slices * sizeof (guint32)); + if (!encoder->tile_slice_ctu_num) + return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED; + encoder->tile_slice_address_map = + g_malloc (encoder->ctu_width * encoder->ctu_height * sizeof (guint32)); + if (!encoder->tile_slice_address_map) + return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED; + + /* firstly uniformly separate CTUs into tiles, as the spec 6.5.1 define */ + for (i = 0; i < encoder->num_tile_cols; i++) + tile_ctu_cols[i] = + ((i + 1) * encoder->ctu_width) / encoder->num_tile_cols - + (i * encoder->ctu_width) / encoder->num_tile_cols; + for (i = 0; i < encoder->num_tile_rows; i++) + tile_ctu_rows[i] = + ((i + 1) * encoder->ctu_height) / encoder->num_tile_rows - + (i * encoder->ctu_height) / encoder->num_tile_rows; + + ret = calculate_slices_start_address (encoder); + if (ret != GST_VAAPI_ENCODER_STATUS_SUCCESS) + return ret; + + /* Build the map to specifying the conversion between a CTB address in CTB + raster scan of a picture and a CTB address in tile scan(see spec 6.5.1 + for details). */ + ctu_tile_width_accu[0] = 0; + for (i = 1; i <= encoder->num_tile_cols; i++) + ctu_tile_width_accu[i] = ctu_tile_width_accu[i - 1] + tile_ctu_cols[i - 1]; + ctu_tile_height_accu[0] = 0; + for (i = 1; i <= encoder->num_tile_rows; i++) + ctu_tile_height_accu[i] = + ctu_tile_height_accu[i - 1] + tile_ctu_rows[i - 1]; + + for (k = 0; k < encoder->ctu_width * encoder->ctu_height; k++) { + /* The ctu coordinate in the picture. */ + guint32 x = k % encoder->ctu_width; + guint32 y = k / encoder->ctu_width; + /* The ctu coordinate in the tile mode. */ + guint32 tile_x = 0; + guint32 tile_y = 0; + /* The index of the CTU in the tile mode. */ + guint32 tso = 0; + + for (i = 0; i < encoder->num_tile_cols; i++) + if (x >= ctu_tile_width_accu[i]) + tile_x = i; + g_assert (tile_x <= encoder->num_tile_cols - 1); + + for (j = 0; j < encoder->num_tile_rows; j++) + if (y >= ctu_tile_height_accu[j]) + tile_y = j; + g_assert (tile_y <= encoder->num_tile_rows - 1); + + /* add all ctus in the tiles the same line before us */ + for (i = 0; i < tile_x; i++) + tso += tile_ctu_rows[tile_y] * tile_ctu_cols[i]; + + /* add all ctus in the tiles above us */ + for (j = 0; j < tile_y; j++) + tso += encoder->ctu_width * tile_ctu_rows[j]; + + /* add the ctus inside the same tile before us */ + tso += (y - ctu_tile_height_accu[tile_y]) * tile_ctu_cols[tile_x] + + x - ctu_tile_width_accu[tile_x]; + + g_assert (tso < encoder->ctu_width * encoder->ctu_height); + + encoder->tile_slice_address_map[tso] = k; + } + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; +} + +static GstVaapiEncoderStatus +gst_vaapi_encoder_h265_encode (GstVaapiEncoder * base_encoder, + GstVaapiEncPicture * picture, GstVaapiCodedBufferProxy * codedbuf) +{ + GstVaapiEncoderH265 *const encoder = GST_VAAPI_ENCODER_H265 (base_encoder); + GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN; + GstVaapiSurfaceProxy *reconstruct = NULL; + + reconstruct = gst_vaapi_encoder_create_surface (base_encoder); + + g_assert (GST_VAAPI_SURFACE_PROXY_SURFACE (reconstruct)); + + if (!ensure_sequence (encoder, picture)) + goto error; + if (!ensure_misc_params (encoder, picture)) + goto error; + if (!ensure_picture (encoder, picture, codedbuf, reconstruct)) + goto error; + if (!ensure_slices (encoder, picture)) + goto error; + if (!gst_vaapi_enc_picture_encode (picture)) + goto error; + + if (!reference_list_update (encoder, picture, reconstruct)) + goto error; + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; + + /* ERRORS */ +error: + { + if (reconstruct) + gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder), + reconstruct); + return ret; + } +} + +struct _PendingIterState +{ + GstVaapiPictureType pic_type; +}; + +static gboolean +gst_vaapi_encoder_h265_get_pending_reordered (GstVaapiEncoder * base_encoder, + GstVaapiEncPicture ** picture, gpointer * state) +{ + GstVaapiEncoderH265 *const encoder = GST_VAAPI_ENCODER_H265 (base_encoder); + GstVaapiH265ReorderPool *reorder_pool; + GstVaapiEncPicture *pic; + struct _PendingIterState *iter; + + g_return_val_if_fail (state, FALSE); + + if (!*state) { + iter = g_new0 (struct _PendingIterState, 1); + iter->pic_type = GST_VAAPI_PICTURE_TYPE_P; + *state = iter; + } else { + iter = *state; + } + + *picture = NULL; + + reorder_pool = &encoder->reorder_pool; + if (g_queue_is_empty (&reorder_pool->reorder_frame_list)) + return FALSE; + + pic = g_queue_pop_tail (&reorder_pool->reorder_frame_list); + g_assert (pic); + if (iter->pic_type == GST_VAAPI_PICTURE_TYPE_P) { + set_p_frame (pic, encoder); + iter->pic_type = GST_VAAPI_PICTURE_TYPE_B; + } else if (iter->pic_type == GST_VAAPI_PICTURE_TYPE_B) { + set_b_frame (pic, encoder); + } else { + GST_WARNING ("Unhandled pending picture type"); + } + + if (GST_CLOCK_TIME_IS_VALID (pic->frame->pts)) + pic->frame->pts += encoder->cts_offset; + + *picture = pic; + return TRUE; +} + +static GstVaapiEncoderStatus +gst_vaapi_encoder_h265_flush (GstVaapiEncoder * base_encoder) +{ + GstVaapiEncoderH265 *const encoder = GST_VAAPI_ENCODER_H265 (base_encoder); + GstVaapiH265ReorderPool *reorder_pool; + GstVaapiEncPicture *pic; + + reorder_pool = &encoder->reorder_pool; + reorder_pool->frame_index = 0; + reorder_pool->cur_present_index = 0; + + while (!g_queue_is_empty (&reorder_pool->reorder_frame_list)) { + pic = (GstVaapiEncPicture *) + g_queue_pop_head (&reorder_pool->reorder_frame_list); + gst_vaapi_enc_picture_unref (pic); + } + g_queue_clear (&reorder_pool->reorder_frame_list); + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; +} + +/* Generate "codec-data" buffer */ +static GstVaapiEncoderStatus +gst_vaapi_encoder_h265_get_codec_data (GstVaapiEncoder * base_encoder, + GstBuffer ** out_buffer_ptr) +{ + GstVaapiEncoderH265 *const encoder = GST_VAAPI_ENCODER_H265 (base_encoder); + const guint32 configuration_version = 0x01; + const guint32 nal_length_size = 4; + GstMapInfo vps_info, sps_info, pps_info; + GstBitWriter bs; + GstBuffer *buffer; + guint min_spatial_segmentation_idc = 0; + guint num_arrays = 3; + + if (!encoder->vps_data || !encoder->sps_data || !encoder->pps_data) + return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_HEADER; + if (gst_buffer_get_size (encoder->sps_data) < 4) + return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_HEADER; + + if (!gst_buffer_map (encoder->vps_data, &vps_info, GST_MAP_READ)) + goto error_map_vps_buffer; + + if (!gst_buffer_map (encoder->sps_data, &sps_info, GST_MAP_READ)) + goto error_map_sps_buffer; + + if (!gst_buffer_map (encoder->pps_data, &pps_info, GST_MAP_READ)) + goto error_map_pps_buffer; + + /* Header */ + gst_bit_writer_init_with_size (&bs, + (vps_info.size + sps_info.size + pps_info.size + 64), FALSE); + WRITE_UINT32 (&bs, configuration_version, 8); + WRITE_UINT32 (&bs, sps_info.data[4], 8); /* profile_space | tier_flag | profile_idc */ + WRITE_UINT32 (&bs, sps_info.data[5], 32); /* profile_compatibility_flag [0-31] */ + /* progressive_source_flag | interlaced_source_flag | non_packed_constraint_flag | + * frame_only_constraint_flag | reserved_zero_bits[0-27] */ + WRITE_UINT32 (&bs, sps_info.data[9], 32); + WRITE_UINT32 (&bs, sps_info.data[13], 16); /* reserved_zero_bits [28-43] */ + WRITE_UINT32 (&bs, sps_info.data[15], 8); /* level_idc */ + WRITE_UINT32 (&bs, 0x0f, 4); /* 1111 */ + WRITE_UINT32 (&bs, min_spatial_segmentation_idc, 12); /* min_spatial_segmentation_idc */ + WRITE_UINT32 (&bs, 0x3f, 6); /* 111111 */ + WRITE_UINT32 (&bs, 0x00, 2); /* parallelismType */ + WRITE_UINT32 (&bs, 0x3f, 6); /* 111111 */ + WRITE_UINT32 (&bs, 0x01, 2); /* chroma_format_idc */ + WRITE_UINT32 (&bs, 0x1f, 5); /* 11111 */ + WRITE_UINT32 (&bs, 0x01, 3); /* bit_depth_luma_minus8 */ + WRITE_UINT32 (&bs, 0x1f, 5); /* 11111 */ + WRITE_UINT32 (&bs, 0x01, 3); /* bit_depth_chroma_minus8 */ + WRITE_UINT32 (&bs, 0x00, 16); /* avgFramerate */ + WRITE_UINT32 (&bs, 0x00, 2); /* constatnFramerate */ + WRITE_UINT32 (&bs, 0x00, 3); /* numTemporalLayers */ + WRITE_UINT32 (&bs, 0x00, 1); /* temporalIdNested */ + WRITE_UINT32 (&bs, nal_length_size - 1, 2); /* lengthSizeMinusOne */ + WRITE_UINT32 (&bs, 0x00, 8); /* numOfArrays */ + + WRITE_UINT32 (&bs, num_arrays, 8); /* numOfArrays */ + + /* Write VPS */ + WRITE_UINT32 (&bs, 0x00, 1); /* array_completeness */ + WRITE_UINT32 (&bs, 0x00, 1); /* reserved zero */ + WRITE_UINT32 (&bs, GST_H265_NAL_VPS, 6); /* Nal_unit_type */ + WRITE_UINT32 (&bs, 0x01, 16); /* numNalus, VPS count = 1 */ + g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0); + /* Write Nal unit length and data of VPS */ + if (!gst_vaapi_utils_h26x_write_nal_unit (&bs, vps_info.data, vps_info.size)) + goto nal_to_byte_stream_error; + + /* Write SPS */ + WRITE_UINT32 (&bs, 0x00, 1); /* array_completeness */ + WRITE_UINT32 (&bs, 0x00, 1); /* reserved zero */ + WRITE_UINT32 (&bs, GST_H265_NAL_SPS, 6); /* Nal_unit_type */ + WRITE_UINT32 (&bs, 0x01, 16); /* numNalus, SPS count = 1 */ + g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0); + /* Write Nal unit length and data of SPS */ + if (!gst_vaapi_utils_h26x_write_nal_unit (&bs, sps_info.data, sps_info.size)) + goto nal_to_byte_stream_error; + + /* Write PPS */ + WRITE_UINT32 (&bs, 0x00, 1); /* array_completeness */ + WRITE_UINT32 (&bs, 0x00, 1); /* reserved zero */ + WRITE_UINT32 (&bs, GST_H265_NAL_PPS, 6); /* Nal_unit_type */ + WRITE_UINT32 (&bs, 0x01, 16); /* numNalus, PPS count = 1 */ + /* Write Nal unit length and data of PPS */ + if (!gst_vaapi_utils_h26x_write_nal_unit (&bs, pps_info.data, pps_info.size)) + goto nal_to_byte_stream_error; + + gst_buffer_unmap (encoder->pps_data, &pps_info); + gst_buffer_unmap (encoder->sps_data, &sps_info); + gst_buffer_unmap (encoder->vps_data, &vps_info); + + buffer = gst_bit_writer_reset_and_get_buffer (&bs); + if (!buffer) + goto error_alloc_buffer; + if (gst_buffer_n_memory (buffer) == 0) { + gst_buffer_unref (buffer); + goto error_alloc_buffer; + } + *out_buffer_ptr = buffer; + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; + + /* ERRORS */ +bs_error: + { + GST_ERROR ("failed to write codec-data"); + gst_buffer_unmap (encoder->vps_data, &vps_info); + gst_buffer_unmap (encoder->sps_data, &sps_info); + gst_buffer_unmap (encoder->pps_data, &pps_info); + gst_bit_writer_reset (&bs); + return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED; + } +nal_to_byte_stream_error: + { + GST_ERROR ("failed to write nal unit"); + gst_buffer_unmap (encoder->vps_data, &vps_info); + gst_buffer_unmap (encoder->sps_data, &sps_info); + gst_buffer_unmap (encoder->pps_data, &pps_info); + gst_bit_writer_reset (&bs); + return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED; + } +error_map_vps_buffer: + { + GST_ERROR ("failed to map VPS packed header"); + return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED; + } +error_map_sps_buffer: + { + GST_ERROR ("failed to map SPS packed header"); + return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED; + } +error_map_pps_buffer: + { + GST_ERROR ("failed to map PPS packed header"); + gst_buffer_unmap (encoder->sps_data, &sps_info); + return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED; + } +error_alloc_buffer: + { + GST_ERROR ("failed to allocate codec-data buffer"); + gst_bit_writer_reset (&bs); + return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED; + } +} + +/* TODO */ +/* The re-ordering algorithm is similar to what we implemented for + * h264 encoder. But We could have a better algorithm for hevc encoder + * by having B-frames as reference pictures */ +static GstVaapiEncoderStatus +gst_vaapi_encoder_h265_reordering (GstVaapiEncoder * base_encoder, + GstVideoCodecFrame * frame, GstVaapiEncPicture ** output) +{ + GstVaapiEncoderH265 *const encoder = GST_VAAPI_ENCODER_H265 (base_encoder); + GstVaapiH265ReorderPool *reorder_pool = NULL; + GstVaapiEncPicture *picture; + gboolean is_idr = FALSE; + + *output = NULL; + + reorder_pool = &encoder->reorder_pool; + + if (!frame) { + if (reorder_pool->reorder_state != GST_VAAPI_ENC_H265_REORD_DUMP_FRAMES) + return GST_VAAPI_ENCODER_STATUS_NO_SURFACE; + + /* reorder_state = GST_VAAPI_ENC_H265_REORD_DUMP_FRAMES + dump B frames from queue, sometime, there may also have P frame or I frame */ + g_assert (encoder->num_bframes > 0); + g_return_val_if_fail (!g_queue_is_empty (&reorder_pool->reorder_frame_list), + GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN); + picture = g_queue_pop_head (&reorder_pool->reorder_frame_list); + g_assert (picture); + if (g_queue_is_empty (&reorder_pool->reorder_frame_list)) { + reorder_pool->reorder_state = GST_VAAPI_ENC_H265_REORD_WAIT_FRAMES; + } + goto end; + } + + /* new frame coming */ + picture = GST_VAAPI_ENC_PICTURE_NEW (HEVC, encoder, frame); + if (!picture) { + GST_WARNING ("create H265 picture failed, frame timestamp:%" + GST_TIME_FORMAT, GST_TIME_ARGS (frame->pts)); + return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED; + } + ++reorder_pool->cur_present_index; + picture->poc = ((reorder_pool->cur_present_index * 1) % + encoder->max_pic_order_cnt); + + is_idr = (reorder_pool->frame_index == 0 || + reorder_pool->frame_index >= encoder->idr_period); + + /* check key frames */ + if (is_idr || GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame) || + (reorder_pool->frame_index % + GST_VAAPI_ENCODER_KEYFRAME_PERIOD (encoder)) == 0) { + ++reorder_pool->frame_index; + + /* b frame enabled, check queue of reorder_frame_list */ + if (encoder->num_bframes + && !g_queue_is_empty (&reorder_pool->reorder_frame_list)) { + GstVaapiEncPicture *p_pic; + + p_pic = g_queue_pop_tail (&reorder_pool->reorder_frame_list); + set_p_frame (p_pic, encoder); + g_queue_foreach (&reorder_pool->reorder_frame_list, + (GFunc) set_b_frame, encoder); + set_key_frame (picture, encoder, is_idr); + g_queue_push_tail (&reorder_pool->reorder_frame_list, picture); + picture = p_pic; + reorder_pool->reorder_state = GST_VAAPI_ENC_H265_REORD_DUMP_FRAMES; + } else { /* no b frames in queue */ + set_key_frame (picture, encoder, is_idr); + g_assert (g_queue_is_empty (&reorder_pool->reorder_frame_list)); + if (encoder->num_bframes) + reorder_pool->reorder_state = GST_VAAPI_ENC_H265_REORD_WAIT_FRAMES; + } + goto end; + } + + /* new p/b frames coming */ + ++reorder_pool->frame_index; + if (reorder_pool->reorder_state == GST_VAAPI_ENC_H265_REORD_WAIT_FRAMES && + g_queue_get_length (&reorder_pool->reorder_frame_list) < + encoder->num_bframes) { + g_queue_push_tail (&reorder_pool->reorder_frame_list, picture); + return GST_VAAPI_ENCODER_STATUS_NO_SURFACE; + } + + set_p_frame (picture, encoder); + + if (reorder_pool->reorder_state == GST_VAAPI_ENC_H265_REORD_WAIT_FRAMES) { + g_queue_foreach (&reorder_pool->reorder_frame_list, (GFunc) set_b_frame, + encoder); + reorder_pool->reorder_state = GST_VAAPI_ENC_H265_REORD_DUMP_FRAMES; + g_assert (!g_queue_is_empty (&reorder_pool->reorder_frame_list)); + } + +end: + g_assert (picture); + frame = picture->frame; + if (GST_CLOCK_TIME_IS_VALID (frame->pts)) + frame->pts += encoder->cts_offset; + *output = picture; + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; +} + +static GstVaapiEncoderStatus +set_context_info (GstVaapiEncoder * base_encoder) +{ + GstVaapiEncoderH265 *const encoder = GST_VAAPI_ENCODER_H265 (base_encoder); + GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder); + const guint DEFAULT_SURFACES_COUNT = 3; + + /* FIXME: Using only a rough approximation for bitstream headers. + * Not taken into account: ScalingList, RefPicListModification, + * PredWeightTable */ + /* Maximum sizes for common headers (in bits) */ + enum + { + MAX_PROFILE_TIER_LEVEL_SIZE = 684, + MAX_VPS_HDR_SIZE = 13781, + MAX_SPS_HDR_SIZE = 615, + MAX_SHORT_TERM_REFPICSET_SIZE = 55, + MAX_VUI_PARAMS_SIZE = 267, + MAX_HRD_PARAMS_SIZE = 8196, + MAX_PPS_HDR_SIZE = 274, + MAX_SLICE_HDR_SIZE = 33660 + }; + + /* Account for VPS header */ + base_encoder->codedbuf_size += 4 + GST_ROUND_UP_8 (MAX_VPS_HDR_SIZE + + MAX_PROFILE_TIER_LEVEL_SIZE + MAX_HRD_PARAMS_SIZE) / 8; + + /* Account for SPS header */ + base_encoder->codedbuf_size += 4 + GST_ROUND_UP_8 (MAX_SPS_HDR_SIZE + + MAX_PROFILE_TIER_LEVEL_SIZE + 64 * MAX_SHORT_TERM_REFPICSET_SIZE + + MAX_VUI_PARAMS_SIZE + MAX_HRD_PARAMS_SIZE) / 8; + + /* Account for PPS header */ + base_encoder->codedbuf_size += 4 + GST_ROUND_UP_8 (MAX_PPS_HDR_SIZE) / 8; + + /* Account for slice header */ + base_encoder->codedbuf_size += encoder->num_slices * (4 + + GST_ROUND_UP_8 (MAX_SLICE_HDR_SIZE + MAX_SHORT_TERM_REFPICSET_SIZE) / 8); + + GST_VAAPI_ENCODER_CAST (encoder)->profile = encoder->profile; + + base_encoder->num_ref_frames = (encoder->num_ref_frames + + (encoder->num_bframes > 0 ? 1 : 0) + DEFAULT_SURFACES_COUNT); + + /* Only YUV 4:2:0 formats are supported for now. */ + base_encoder->codedbuf_size += GST_ROUND_UP_16 (vip->width) * + GST_ROUND_UP_16 (vip->height) * 3 / 2; + + base_encoder->context_info.profile = base_encoder->profile; + base_encoder->context_info.entrypoint = encoder->entrypoint; + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; +} + +static GstVaapiEncoderStatus +gst_vaapi_encoder_h265_reconfigure (GstVaapiEncoder * base_encoder) +{ + GstVaapiEncoderH265 *const encoder = GST_VAAPI_ENCODER_H265 (base_encoder); + GstVaapiEncoderStatus status; + guint luma_width, luma_height; + + luma_width = GST_VAAPI_ENCODER_WIDTH (encoder); + luma_height = GST_VAAPI_ENCODER_HEIGHT (encoder); + + if (luma_width != encoder->luma_width || luma_height != encoder->luma_height) { + GST_DEBUG ("resolution: %d %d", GST_VAAPI_ENCODER_WIDTH (encoder), + GST_VAAPI_ENCODER_HEIGHT (encoder)); + encoder->luma_width = GST_ROUND_UP_16 (luma_width); + encoder->luma_height = GST_ROUND_UP_16 (luma_height); + encoder->config_changed = TRUE; + /* Frame Cropping */ + if ((GST_VAAPI_ENCODER_WIDTH (encoder) & 15) || + (GST_VAAPI_ENCODER_HEIGHT (encoder) & 15)) { + /* 6.1, Table 6-1 */ + static const guint SubWidthC[] = { 1, 2, 2, 1 }; + static const guint SubHeightC[] = { 1, 2, 1, 1 }; + guint index = gst_vaapi_utils_h265_get_chroma_format_idc + (gst_vaapi_video_format_get_chroma_type (GST_VIDEO_INFO_FORMAT + (GST_VAAPI_ENCODER_VIDEO_INFO (encoder)))); + + encoder->conformance_window_flag = 1; + encoder->conf_win_left_offset = 0; + encoder->conf_win_right_offset = + (encoder->luma_width - + GST_VAAPI_ENCODER_WIDTH (encoder)) / SubWidthC[index]; + encoder->conf_win_top_offset = 0; + encoder->conf_win_bottom_offset = + (encoder->luma_height - + GST_VAAPI_ENCODER_HEIGHT (encoder)) / SubHeightC[index]; + } + } + + status = ensure_profile_tier_level (encoder); + if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) + return status; + + /* Set ctu size based on entrypoint. */ + if (encoder->entrypoint == GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP) { + encoder->ctu_width = (encoder->luma_width + 63) / 64; + encoder->ctu_height = (encoder->luma_height + 63) / 64; + } else { + encoder->ctu_width = (encoder->luma_width + 31) / 32; + encoder->ctu_height = (encoder->luma_height + 31) / 32; + } + + status = reset_properties (encoder); + if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) + return status; + + status = ensure_tile (encoder); + if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) + return status; + ensure_control_rate_params (encoder); + return set_context_info (base_encoder); +} + +static void +gst_vaapi_encoder_h265_init (GstVaapiEncoderH265 * encoder) +{ + GstVaapiH265ReorderPool *reorder_pool; + GstVaapiH265RefPool *ref_pool; + + /* Default encoding entrypoint */ + encoder->entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE; + encoder->tier = GST_VAAPI_TIER_H265_UNKNOWN; + + encoder->conformance_window_flag = 0; + encoder->num_slices = 1; + encoder->no_p_frame = FALSE; + + /* re-ordering list initialize */ + reorder_pool = &encoder->reorder_pool; + g_queue_init (&reorder_pool->reorder_frame_list); + reorder_pool->reorder_state = GST_VAAPI_ENC_H265_REORD_NONE; + reorder_pool->frame_index = 0; + reorder_pool->cur_present_index = 0; + + /* reference list info initialize */ + ref_pool = &encoder->ref_pool; + g_queue_init (&ref_pool->ref_list); + ref_pool->max_ref_frames = 0; + ref_pool->max_reflist0_count = 1; + ref_pool->max_reflist1_count = 1; + + encoder->allowed_profiles = NULL; +} + +struct _GstVaapiEncoderH265Class +{ + GstVaapiEncoderClass parent_class; +}; + +G_DEFINE_TYPE (GstVaapiEncoderH265, gst_vaapi_encoder_h265, + GST_TYPE_VAAPI_ENCODER); + +static void +gst_vaapi_encoder_h265_finalize (GObject * object) +{ + /*free private buffers */ + GstVaapiEncoderH265 *const encoder = GST_VAAPI_ENCODER_H265 (object); + GstVaapiEncPicture *pic; + GstVaapiEncoderH265Ref *ref; + GstVaapiH265RefPool *ref_pool; + GstVaapiH265ReorderPool *reorder_pool; + + gst_buffer_replace (&encoder->vps_data, NULL); + gst_buffer_replace (&encoder->sps_data, NULL); + gst_buffer_replace (&encoder->pps_data, NULL); + + /* reference list info de-init */ + ref_pool = &encoder->ref_pool; + while (!g_queue_is_empty (&ref_pool->ref_list)) { + ref = (GstVaapiEncoderH265Ref *) g_queue_pop_head (&ref_pool->ref_list); + reference_pic_free (encoder, ref); + } + g_queue_clear (&ref_pool->ref_list); + + /* re-ordering list initialize */ + reorder_pool = &encoder->reorder_pool; + while (!g_queue_is_empty (&reorder_pool->reorder_frame_list)) { + pic = (GstVaapiEncPicture *) + g_queue_pop_head (&reorder_pool->reorder_frame_list); + gst_vaapi_enc_picture_unref (pic); + } + g_queue_clear (&reorder_pool->reorder_frame_list); + + reset_tile (encoder); + + if (encoder->allowed_profiles) + g_array_unref (encoder->allowed_profiles); + + G_OBJECT_CLASS (gst_vaapi_encoder_h265_parent_class)->finalize (object); +} + +/** + * @ENCODER_H265_PROP_RATECONTROL: Rate control (#GstVaapiRateControl). + * @ENCODER_H265_PROP_TUNE: The tuning options (#GstVaapiEncoderTune). + * @ENCODER_H265_PROP_MAX_BFRAMES: Number of B-frames between I + * and P (uint). + * @ENCODER_H265_PROP_INIT_QP: Initial quantizer value (uint). + * @ENCODER_H265_PROP_MIN_QP: Minimal quantizer value (uint). + * @ENCODER_H265_PROP_NUM_SLICES: Number of slices per frame (uint). + * @ENCODER_H265_PROP_NUM_REF_FRAMES: Maximum number of reference frames. + * @ENCODER_H265_PROP_CPB_LENGTH: Length of the CPB buffer + * in milliseconds (uint). + * @ENCODER_H265_PROP_MBBRC: Macroblock level Bitrate Control. + * @ENCODER_H265_PROP_QP_IP: Difference of QP between I and P frame. + * @ENCODER_H265_PROP_QP_IB: Difference of QP between I and B frame. + * @ENCODER_H265_PROP_LOW_DELAY_B: use low delay b feature. + * @ENCODER_H265_PROP_MAX_QP: Maximal quantizer value (uint). + * + * The set of H.265 encoder specific configurable properties. + */ +enum +{ + ENCODER_H265_PROP_RATECONTROL = 1, + ENCODER_H265_PROP_TUNE, + ENCODER_H265_PROP_MAX_BFRAMES, + ENCODER_H265_PROP_INIT_QP, + ENCODER_H265_PROP_MIN_QP, + ENCODER_H265_PROP_NUM_SLICES, + ENCODER_H265_PROP_NUM_REF_FRAMES, + ENCODER_H265_PROP_CPB_LENGTH, + ENCODER_H265_PROP_MBBRC, + ENCODER_H265_PROP_QP_IP, + ENCODER_H265_PROP_QP_IB, +#ifndef GST_REMOVE_DEPRECATED + ENCODER_H265_PROP_LOW_DELAY_B, +#endif + ENCODER_H265_PROP_MAX_QP, + ENCODER_H265_PROP_QUALITY_FACTOR, + ENCODER_H265_PROP_NUM_TILE_COLS, + ENCODER_H265_PROP_NUM_TILE_ROWS, + ENCODER_H265_N_PROPERTIES +}; + +static GParamSpec *properties[ENCODER_H265_N_PROPERTIES]; + +static void +gst_vaapi_encoder_h265_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object); + GstVaapiEncoderH265 *const encoder = GST_VAAPI_ENCODER_H265 (object); + + if (base_encoder->num_codedbuf_queued > 0) { + GST_ERROR_OBJECT (object, + "failed to set any property after encoding started"); + return; + } + + switch (prop_id) { + case ENCODER_H265_PROP_RATECONTROL: + gst_vaapi_encoder_set_rate_control (base_encoder, + g_value_get_enum (value)); + break; + case ENCODER_H265_PROP_TUNE: + gst_vaapi_encoder_set_tuning (base_encoder, g_value_get_enum (value)); + break; + case ENCODER_H265_PROP_MAX_BFRAMES: + encoder->num_bframes = g_value_get_uint (value); + break; + case ENCODER_H265_PROP_INIT_QP: + encoder->init_qp = g_value_get_uint (value); + break; + case ENCODER_H265_PROP_MIN_QP: + encoder->min_qp = g_value_get_uint (value); + break; + case ENCODER_H265_PROP_QP_IP: + encoder->qp_ip = g_value_get_int (value); + break; + case ENCODER_H265_PROP_QP_IB: + encoder->qp_ib = g_value_get_int (value); + break; + case ENCODER_H265_PROP_NUM_SLICES: + encoder->num_slices = g_value_get_uint (value); + break; + case ENCODER_H265_PROP_CPB_LENGTH: + encoder->cpb_length = g_value_get_uint (value); + break; + case ENCODER_H265_PROP_NUM_REF_FRAMES: + encoder->num_ref_frames = g_value_get_uint (value); + break; + case ENCODER_H265_PROP_MBBRC: + encoder->mbbrc = g_value_get_enum (value); + break; +#ifndef GST_REMOVE_DEPRECATED + case ENCODER_H265_PROP_LOW_DELAY_B: +#if !VA_CHECK_VERSION(1,9,0) + encoder->no_p_frame = g_value_get_boolean (value); +#else + if (g_value_get_boolean (value) == TRUE) { + GST_WARNING ("Deprecate low-delay-b property. Driver now already" + " has the ability to detect whether supporting P frames. this" + " value should not be set manually and will take no effect."); + } +#endif + break; +#endif + case ENCODER_H265_PROP_MAX_QP: + encoder->max_qp = g_value_get_uint (value); + break; + case ENCODER_H265_PROP_QUALITY_FACTOR: + encoder->quality_factor = g_value_get_uint (value); + break; + case ENCODER_H265_PROP_NUM_TILE_COLS: + encoder->num_tile_cols = g_value_get_uint (value); + break; + case ENCODER_H265_PROP_NUM_TILE_ROWS: + encoder->num_tile_rows = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gst_vaapi_encoder_h265_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstVaapiEncoderH265 *const encoder = GST_VAAPI_ENCODER_H265 (object); + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object); + + switch (prop_id) { + case ENCODER_H265_PROP_RATECONTROL: + g_value_set_enum (value, base_encoder->rate_control); + break; + case ENCODER_H265_PROP_TUNE: + g_value_set_enum (value, base_encoder->tune); + break; + case ENCODER_H265_PROP_MAX_BFRAMES: + g_value_set_uint (value, encoder->num_bframes); + break; + case ENCODER_H265_PROP_INIT_QP: + g_value_set_uint (value, encoder->init_qp); + break; + case ENCODER_H265_PROP_MIN_QP: + g_value_set_uint (value, encoder->min_qp); + break; + case ENCODER_H265_PROP_QP_IP: + g_value_set_int (value, encoder->qp_ip); + break; + case ENCODER_H265_PROP_QP_IB: + g_value_set_int (value, encoder->qp_ib); + break; + case ENCODER_H265_PROP_NUM_SLICES: + g_value_set_uint (value, encoder->num_slices); + break; + case ENCODER_H265_PROP_CPB_LENGTH: + g_value_set_uint (value, encoder->cpb_length); + break; + case ENCODER_H265_PROP_NUM_REF_FRAMES: + g_value_set_uint (value, encoder->num_ref_frames); + break; + case ENCODER_H265_PROP_MBBRC: + g_value_set_enum (value, encoder->mbbrc); + break; +#ifndef GST_REMOVE_DEPRECATED + case ENCODER_H265_PROP_LOW_DELAY_B: + g_value_set_boolean (value, encoder->no_p_frame); + break; +#endif + case ENCODER_H265_PROP_MAX_QP: + g_value_set_uint (value, encoder->max_qp); + break; + case ENCODER_H265_PROP_QUALITY_FACTOR: + g_value_set_uint (value, encoder->quality_factor); + break; + case ENCODER_H265_PROP_NUM_TILE_COLS: + g_value_set_uint (value, encoder->num_tile_cols); + break; + case ENCODER_H265_PROP_NUM_TILE_ROWS: + g_value_set_uint (value, encoder->num_tile_rows); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +GST_VAAPI_ENCODER_DEFINE_CLASS_DATA (H265); + +static void +gst_vaapi_encoder_h265_class_init (GstVaapiEncoderH265Class * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstVaapiEncoderClass *const encoder_class = GST_VAAPI_ENCODER_CLASS (klass); + + encoder_class->class_data = &g_class_data; + encoder_class->reconfigure = gst_vaapi_encoder_h265_reconfigure; + encoder_class->reordering = gst_vaapi_encoder_h265_reordering; + encoder_class->encode = gst_vaapi_encoder_h265_encode; + encoder_class->flush = gst_vaapi_encoder_h265_flush; + encoder_class->get_codec_data = gst_vaapi_encoder_h265_get_codec_data; + encoder_class->get_pending_reordered = + gst_vaapi_encoder_h265_get_pending_reordered; + + object_class->set_property = gst_vaapi_encoder_h265_set_property; + object_class->get_property = gst_vaapi_encoder_h265_get_property; + object_class->finalize = gst_vaapi_encoder_h265_finalize; + + /** + * GstVaapiEncoderH265:rate-control: + * + * The desired rate control mode, expressed as a #GstVaapiRateControl. + */ + properties[ENCODER_H265_PROP_RATECONTROL] = + g_param_spec_enum ("rate-control", + "Rate Control", "Rate control mode", + g_class_data.rate_control_get_type (), + g_class_data.default_rate_control, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH265:tune: + * + * The desired encoder tuning option. + */ + properties[ENCODER_H265_PROP_TUNE] = + g_param_spec_enum ("tune", + "Encoder Tuning", + "Encoder tuning option", + g_class_data.encoder_tune_get_type (), + g_class_data.default_encoder_tune, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH265:max-bframes: + * + * The number of B-frames between I and P. + */ + properties[ENCODER_H265_PROP_MAX_BFRAMES] = + g_param_spec_uint ("max-bframes", + "Max B-Frames", "Number of B-frames between I and P", 0, 10, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH265:refs: + * + * The number of reference frames. + * If B frame is encoded, it will add 1 reference frame more. + */ + properties[ENCODER_H265_PROP_NUM_REF_FRAMES] = + g_param_spec_uint ("refs", + "Number of Reference Frames", "Number of reference frames", 1, 3, 1, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH265:init-qp: + * + * The initial quantizer value. + */ + properties[ENCODER_H265_PROP_INIT_QP] = + g_param_spec_uint ("init-qp", + "Initial QP", "Initial quantizer value", 0, 51, 26, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH265:min-qp: + * + * The minimum quantizer value. + */ + properties[ENCODER_H265_PROP_MIN_QP] = + g_param_spec_uint ("min-qp", + "Minimum QP", "Minimum quantizer value", 0, 51, 1, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH265:max-qp: + * + * The maximum quantizer value. + * + * Since: 1.18 + */ + properties[ENCODER_H265_PROP_MAX_QP] = + g_param_spec_uint ("max-qp", + "Maximum QP", "Maximum quantizer value", 0, 51, 51, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH265:qp-ip: + * + * The difference of QP between I and P Frame. + * This is available only on CQP mode. + */ + properties[ENCODER_H265_PROP_QP_IP] = + g_param_spec_int ("qp-ip", + "Difference of QP between I and P frame", + "Difference of QP between I and P frame (available only on CQP)", + -51, 51, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH265:qp-ib: + * + * The difference of QP between I and B Frame. + * This is available only on CQP mode. + */ + properties[ENCODER_H265_PROP_QP_IB] = + g_param_spec_int ("qp-ib", + "Difference of QP between I and B frame", + "Difference of QP between I and B frame (available only on CQP)", + -51, 51, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /* FIXME: there seems to be issues with multi-slice encoding */ + /** + * GstVaapiEncoderH265:num-slices: + * + * The number of slices per frame. + */ + properties[ENCODER_H265_PROP_NUM_SLICES] = + g_param_spec_uint ("num-slices", + "Number of Slices", + "Number of slices per frame", + 1, 200, 1, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH265:cpb-length: + * + * The size of the CPB buffer in milliseconds. + */ + properties[ENCODER_H265_PROP_CPB_LENGTH] = + g_param_spec_uint ("cpb-length", + "CPB Length", "Length of the CPB buffer in milliseconds", + 1, 10000, DEFAULT_CPB_LENGTH, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH265:mbbrc: + * + * Macroblock level bitrate control. + * This is not compatible with Constant QP rate control. + */ + properties[ENCODER_H265_PROP_MBBRC] = + g_param_spec_enum ("mbbrc", + "Macroblock level Bitrate Control", + "Macroblock level Bitrate Control", + GST_VAAPI_TYPE_ENCODER_MBBRC, GST_VAAPI_ENCODER_MBBRC_AUTO, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + +#ifndef GST_REMOVE_DEPRECATED + /** + * GstVaapiEncoderH265:low_delay_b: + * + * Enable low delay b frame, which will change P frame with B frame. + */ + properties[ENCODER_H265_PROP_LOW_DELAY_B] = + g_param_spec_boolean ("low-delay-b", + "Enable low delay b", + "Transforms P frames into predictive B frames." + " Enable it when P frames are not supported.", + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); +#endif + + /** + * GstVaapiEncoderH265:quality_factor: + * + * Quality factor used with ICQ/QVBR bitrate control mode. + */ + properties[ENCODER_H265_PROP_QUALITY_FACTOR] = + g_param_spec_uint ("quality-factor", + "Quality factor for ICQ/QVBR", + "quality factor for ICQ/QBVR bitrate control mode" + " (lower value means higher quality, higher value means lower quality)", + 1, 51, 26, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH265:num-tile-cols: + * + * The number of tile columns when tile encoding is enabled. + */ + properties[ENCODER_H265_PROP_NUM_TILE_COLS] = + g_param_spec_uint ("num-tile-cols", + "number of tile columns", + "the number of columns for tile encoding", 1, + GST_VAAPI_H265_MAX_COL_TILES, 1, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderH265:num-tile-rows: + * + * The number of tile rows when tile encoding is enabled. + */ + properties[ENCODER_H265_PROP_NUM_TILE_ROWS] = + g_param_spec_uint ("num-tile-rows", + "number of tile rows", + "the number of rows for tile encoding", 1, + GST_VAAPI_H265_MAX_ROW_TILES, 1, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + g_object_class_install_properties (object_class, ENCODER_H265_N_PROPERTIES, + properties); + + gst_type_mark_as_plugin_api (g_class_data.rate_control_get_type (), 0); + gst_type_mark_as_plugin_api (g_class_data.encoder_tune_get_type (), 0); +} + +/** + * gst_vaapi_encoder_h265_new: + * @display: a #GstVaapiDisplay + * + * Creates a new #GstVaapiEncoder for H.265 encoding. Note that the + * only supported output stream format is "byte-stream" format. + * + * Return value: the newly allocated #GstVaapiEncoder object + */ +GstVaapiEncoder * +gst_vaapi_encoder_h265_new (GstVaapiDisplay * display) +{ + return g_object_new (GST_TYPE_VAAPI_ENCODER_H265, "display", display, NULL); +} + +/** + * gst_vaapi_encoder_h265_set_allowed_profiles: + * @encoder: a #GstVaapiEncoderH265 + * @profiles: a #GArray of all allowed #GstVaapiProfile. + * + * Set the all allowed profiles for the encoder. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_encoder_h265_set_allowed_profiles (GstVaapiEncoderH265 * encoder, + GArray * profiles) +{ + g_return_val_if_fail (encoder != NULL, FALSE); + g_return_val_if_fail (profiles, FALSE); + + encoder->allowed_profiles = g_array_ref (profiles); + return TRUE; +} + +/** + * gst_vaapi_encoder_h265_get_profile_tier_level: + * @encoder: a #GstVaapiEncoderH265 + * @out_profile_ptr: return location for the #GstVaapiProfile + * @out_level_ptr: return location for the #GstVaapiLevelH265 + * @out_tier_ptr: return location for the #GstVaapiTierH265 + * + * Queries the H.265 @encoder for the active profile and level. That + * information is only constructed and valid after the encoder is + * configured, i.e. after the gst_vaapi_encoder_set_codec_state() + * function is called. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_encoder_h265_get_profile_tier_level (GstVaapiEncoderH265 * encoder, + GstVaapiProfile * out_profile_ptr, GstVaapiTierH265 * out_tier_ptr, + GstVaapiLevelH265 * out_level_ptr) +{ + g_return_val_if_fail (encoder != NULL, FALSE); + + if (!encoder->profile || encoder->tier == GST_VAAPI_TIER_H265_UNKNOWN + || !encoder->level) + return FALSE; + + if (out_profile_ptr) + *out_profile_ptr = encoder->profile; + if (out_level_ptr) + *out_level_ptr = encoder->level; + if (out_tier_ptr) + *out_tier_ptr = encoder->tier; + + return TRUE; +} diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_h265.h b/gst-libs/gst/vaapi/gstvaapiencoder_h265.h new file mode 100644 index 0000000000..60da074a1c --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder_h265.h @@ -0,0 +1,59 @@ +/* + * gstvaapiencoder_h265.h - H.265 encoder + * + * Copyright (C) 2015 Intel Corporation + * Author: Sreerenj Balachandran + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_ENCODER_H265_H +#define GST_VAAPI_ENCODER_H265_H + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_ENCODER_H265 \ + (gst_vaapi_encoder_h265_get_type ()) +#define GST_VAAPI_ENCODER_H265(encoder) \ + (G_TYPE_CHECK_INSTANCE_CAST ((encoder), GST_TYPE_VAAPI_ENCODER_H265, GstVaapiEncoderH265)) +#define GST_IS_VAAPI_ENCODER_H265(encoder) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((encoder), GST_TYPE_VAAPI_ENCODER_H265)) + +typedef struct _GstVaapiEncoderH265 GstVaapiEncoderH265; +typedef struct _GstVaapiEncoderH265Class GstVaapiEncoderH265Class; + +GType +gst_vaapi_encoder_h265_get_type (void) G_GNUC_CONST; + +GstVaapiEncoder * +gst_vaapi_encoder_h265_new (GstVaapiDisplay * display); + +gboolean +gst_vaapi_encoder_h265_set_allowed_profiles (GstVaapiEncoderH265 * encoder, + GArray * profiles); + +gboolean +gst_vaapi_encoder_h265_get_profile_tier_level (GstVaapiEncoderH265 * encoder, + GstVaapiProfile * out_profile_ptr, GstVaapiTierH265 *out_tier_ptr, GstVaapiLevelH265 * out_level_ptr); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiEncoderH265, gst_object_unref) + +G_END_DECLS + +#endif /*GST_VAAPI_ENCODER_H265_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c b/gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c new file mode 100644 index 0000000000..00d1597c22 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c @@ -0,0 +1,914 @@ +/* + * gstvaapiencoder_jpeg.c - JPEG encoder + * + * Copyright (C) 2015 Intel Corporation + * Author: Sreerenj Balachandran + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include +#include +#include "gstvaapicompat.h" +#include "gstvaapiencoder_priv.h" +#include "gstvaapiencoder_jpeg.h" +#include "gstvaapicodedbufferproxy_priv.h" +#include "gstvaapisurface.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +/* Define default rate control mode ("constant-qp") */ +#define DEFAULT_RATECONTROL GST_VAAPI_RATECONTROL_NONE + +/* Supported set of VA rate controls, within this implementation */ +#define SUPPORTED_RATECONTROLS \ + (GST_VAAPI_RATECONTROL_MASK (NONE)) + +/* Supported set of tuning options, within this implementation */ +#define SUPPORTED_TUNE_OPTIONS \ + (GST_VAAPI_ENCODER_TUNE_MASK (NONE)) + +/* Supported set of VA packed headers, within this implementation */ +#define SUPPORTED_PACKED_HEADERS \ + (VA_ENC_PACKED_HEADER_RAW_DATA) + +#define NUM_DC_RUN_SIZE_BITS 16 +#define NUM_AC_RUN_SIZE_BITS 16 +#define NUM_AC_CODE_WORDS_HUFFVAL 162 +#define NUM_DC_CODE_WORDS_HUFFVAL 12 + +/* ------------------------------------------------------------------------- */ +/* --- JPEG Encoder --- */ +/* ------------------------------------------------------------------------- */ + +struct _GstVaapiEncoderJpeg +{ + GstVaapiEncoder parent_instance; + GstVaapiProfile profile; + guint quality; + GstJpegQuantTables quant_tables; + GstJpegQuantTables scaled_quant_tables; + gboolean has_quant_tables; + GstJpegHuffmanTables huff_tables; + gboolean has_huff_tables; + gint cwidth[GST_VIDEO_MAX_COMPONENTS]; + gint cheight[GST_VIDEO_MAX_COMPONENTS]; + gint h_samp[GST_VIDEO_MAX_COMPONENTS]; + gint v_samp[GST_VIDEO_MAX_COMPONENTS]; + gint h_max_samp; + gint v_max_samp; + guint n_components; +}; + +/* based on upstream gst-plugins-good jpegencoder */ +static void +generate_sampling_factors (GstVaapiEncoderJpeg * encoder) +{ + GstVideoInfo *vinfo; + gint i; + + vinfo = GST_VAAPI_ENCODER_VIDEO_INFO (encoder); + + if (GST_VIDEO_INFO_FORMAT (vinfo) == GST_VIDEO_FORMAT_ENCODED) { + /* Use native I420 format */ + encoder->n_components = 3; + for (i = 0; i < encoder->n_components; ++i) { + if (i == 0) + encoder->h_samp[i] = encoder->v_samp[i] = 2; + else + encoder->h_samp[i] = encoder->v_samp[i] = 1; + GST_DEBUG ("sampling factors: %d %d", encoder->h_samp[i], + encoder->v_samp[i]); + } + return; + } + + encoder->n_components = GST_VIDEO_INFO_N_COMPONENTS (vinfo); + + encoder->h_max_samp = 0; + encoder->v_max_samp = 0; + for (i = 0; i < encoder->n_components; ++i) { + encoder->cwidth[i] = GST_VIDEO_INFO_COMP_WIDTH (vinfo, i); + encoder->cheight[i] = GST_VIDEO_INFO_COMP_HEIGHT (vinfo, i); + encoder->h_samp[i] = + GST_ROUND_UP_4 (GST_VIDEO_INFO_WIDTH (vinfo)) / encoder->cwidth[i]; + encoder->h_max_samp = MAX (encoder->h_max_samp, encoder->h_samp[i]); + encoder->v_samp[i] = + GST_ROUND_UP_4 (GST_VIDEO_INFO_HEIGHT (vinfo)) / encoder->cheight[i]; + encoder->v_max_samp = MAX (encoder->v_max_samp, encoder->v_samp[i]); + } + /* samp should only be 1, 2 or 4 */ + g_assert (encoder->h_max_samp <= 4); + g_assert (encoder->v_max_samp <= 4); + + /* now invert */ + /* maximum is invariant, as one of the components should have samp 1 */ + for (i = 0; i < encoder->n_components; ++i) { + encoder->h_samp[i] = encoder->h_max_samp / encoder->h_samp[i]; + encoder->v_samp[i] = encoder->v_max_samp / encoder->v_samp[i]; + GST_DEBUG ("sampling factors: %d %d", encoder->h_samp[i], + encoder->v_samp[i]); + } +} + +/* Derives the profile that suits best to the configuration */ +static GstVaapiEncoderStatus +ensure_profile (GstVaapiEncoderJpeg * encoder) +{ + /* Always start from "simple" profile for maximum compatibility */ + encoder->profile = GST_VAAPI_PROFILE_JPEG_BASELINE; + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; +} + +/* Derives the profile supported by the underlying hardware */ +static gboolean +ensure_hw_profile (GstVaapiEncoderJpeg * encoder) +{ + GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (encoder); + GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_PICTURE_ENCODE; + GstVaapiProfile profile, profiles[2]; + guint i, num_profiles = 0; + + profiles[num_profiles++] = encoder->profile; + + profile = GST_VAAPI_PROFILE_UNKNOWN; + for (i = 0; i < num_profiles; i++) { + if (gst_vaapi_display_has_encoder (display, profiles[i], entrypoint)) { + profile = profiles[i]; + break; + } + } + if (profile == GST_VAAPI_PROFILE_UNKNOWN) + goto error_unsupported_profile; + + GST_VAAPI_ENCODER_CAST (encoder)->profile = profile; + return TRUE; + + /* ERRORS */ +error_unsupported_profile: + { + GST_ERROR ("unsupported HW profile %s", + gst_vaapi_profile_get_va_name (encoder->profile)); + return FALSE; + } +} + +static GstVaapiEncoderStatus +set_context_info (GstVaapiEncoder * base_encoder) +{ + GstVaapiEncoderJpeg *encoder = GST_VAAPI_ENCODER_JPEG (base_encoder); + GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder); + + /* Maximum sizes for common headers (in bytes) */ + enum + { + MAX_APP_HDR_SIZE = 20, + MAX_FRAME_HDR_SIZE = 19, + MAX_QUANT_TABLE_SIZE = 138, + MAX_HUFFMAN_TABLE_SIZE = 432, + MAX_SCAN_HDR_SIZE = 14 + }; + + if (!ensure_hw_profile (encoder)) + return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + + base_encoder->num_ref_frames = 0; + + /* Only YUV 4:2:0 formats are supported for now. */ + base_encoder->codedbuf_size = GST_ROUND_UP_16 (vip->width) * + GST_ROUND_UP_16 (vip->height) * 3 / 2; + + base_encoder->codedbuf_size += MAX_APP_HDR_SIZE + MAX_FRAME_HDR_SIZE + + MAX_QUANT_TABLE_SIZE + MAX_HUFFMAN_TABLE_SIZE + MAX_SCAN_HDR_SIZE; + + base_encoder->context_info.profile = base_encoder->profile; + base_encoder->context_info.entrypoint = GST_VAAPI_ENTRYPOINT_PICTURE_ENCODE; + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; +} + +static gboolean +fill_picture (GstVaapiEncoderJpeg * encoder, + GstVaapiEncPicture * picture, + GstVaapiCodedBuffer * codedbuf, GstVaapiSurfaceProxy * surface) +{ + guint i; + VAEncPictureParameterBufferJPEG *const pic_param = picture->param; + + memset (pic_param, 0, sizeof (VAEncPictureParameterBufferJPEG)); + + pic_param->reconstructed_picture = + GST_VAAPI_SURFACE_PROXY_SURFACE_ID (surface); + pic_param->picture_width = GST_VAAPI_ENCODER_WIDTH (encoder); + pic_param->picture_height = GST_VAAPI_ENCODER_HEIGHT (encoder); + pic_param->coded_buf = GST_VAAPI_CODED_BUFFER_ID (codedbuf); + + pic_param->pic_flags.bits.profile = 0; /* Profile = Baseline */ + pic_param->pic_flags.bits.progressive = 0; /* Sequential encoding */ + pic_param->pic_flags.bits.huffman = 1; /* Uses Huffman coding */ + pic_param->pic_flags.bits.interleaved = 0; /* Input format is non interleaved (YUV) */ + pic_param->pic_flags.bits.differential = 0; /* non-Differential Encoding */ + pic_param->sample_bit_depth = 8; + pic_param->num_scan = 1; + pic_param->num_components = encoder->n_components; + pic_param->quality = encoder->quality; + for (i = 0; i < pic_param->num_components; i++) { + pic_param->component_id[i] = i + 1; + if (i != 0) + pic_param->quantiser_table_selector[i] = 1; + } + return TRUE; +} + +static gboolean +ensure_picture (GstVaapiEncoderJpeg * encoder, GstVaapiEncPicture * picture, + GstVaapiCodedBufferProxy * codedbuf_proxy, GstVaapiSurfaceProxy * surface) +{ + GstVaapiCodedBuffer *const codedbuf = + GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (codedbuf_proxy); + + if (!fill_picture (encoder, picture, codedbuf, surface)) + return FALSE; + + return TRUE; +} + +/* This is a work-around: Normalize the quality factor and scale QM + * values similar to what VA-Intel driver is doing. Otherwise the + * generated packed headers will be wrong, since the driver itself + * is scaling the QM values using the normalized quality factor */ +static void +generate_scaled_qm (GstJpegQuantTables * quant_tables, + GstJpegQuantTables * scaled_quant_tables, guint quality, guint shift) +{ + guint qt_val, nm_quality, i; + nm_quality = quality == 0 ? 1 : quality; + nm_quality = + (nm_quality < 50) ? (5000 / nm_quality) : (200 - (nm_quality * 2)); + + g_assert (quant_tables != NULL); + g_assert (scaled_quant_tables != NULL); + + for (i = 0; i < GST_JPEG_MAX_QUANT_ELEMENTS; i++) { + /* Luma QM */ + qt_val = + (quant_tables->quant_tables[0].quant_table[i] * nm_quality + + shift) / 100; + scaled_quant_tables->quant_tables[0].quant_table[i] = + CLAMP (qt_val, 1, 255); + /* Chroma QM */ + qt_val = + (quant_tables->quant_tables[1].quant_table[i] * nm_quality + + shift) / 100; + scaled_quant_tables->quant_tables[1].quant_table[i] = + CLAMP (qt_val, 1, 255); + } +} + +static gboolean +fill_quantization_table (GstVaapiEncoderJpeg * encoder, + GstVaapiEncPicture * picture) +{ + VAQMatrixBufferJPEG *q_matrix; + int i; + + g_assert (picture); + + picture->q_matrix = GST_VAAPI_ENC_Q_MATRIX_NEW (JPEG, encoder); + if (!picture->q_matrix) { + GST_ERROR ("failed to allocate quantiser table"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + q_matrix = picture->q_matrix->param; + + if (!encoder->has_quant_tables) { + GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (encoder); + guint shift = 0; + + if (gst_vaapi_display_has_driver_quirks (display, + GST_VAAPI_DRIVER_QUIRK_JPEG_ENC_SHIFT_VALUE_BY_50)) + shift = 50; + + gst_jpeg_get_default_quantization_tables (&encoder->quant_tables); + encoder->has_quant_tables = TRUE; + generate_scaled_qm (&encoder->quant_tables, &encoder->scaled_quant_tables, + encoder->quality, shift); + } + q_matrix->load_lum_quantiser_matrix = 1; + for (i = 0; i < GST_JPEG_MAX_QUANT_ELEMENTS; i++) { + q_matrix->lum_quantiser_matrix[i] = + encoder->quant_tables.quant_tables[0].quant_table[i]; + } + + q_matrix->load_chroma_quantiser_matrix = 1; + for (i = 0; i < GST_JPEG_MAX_QUANT_ELEMENTS; i++) { + q_matrix->chroma_quantiser_matrix[i] = + encoder->quant_tables.quant_tables[1].quant_table[i]; + } + + return TRUE; +} + +static gboolean +ensure_quantization_table (GstVaapiEncoderJpeg * encoder, + GstVaapiEncPicture * picture) +{ + g_assert (picture); + + if (!fill_quantization_table (encoder, picture)) + return FALSE; + + return TRUE; +} + +static gboolean +fill_huffman_table (GstVaapiEncoderJpeg * encoder, GstVaapiEncPicture * picture) +{ + VAHuffmanTableBufferJPEGBaseline *huffman_table; + guint i, num_tables; + + g_assert (picture); + + picture->huf_table = GST_VAAPI_ENC_HUFFMAN_TABLE_NEW (JPEGBaseline, encoder); + if (!picture->huf_table) { + GST_ERROR ("failed to allocate Huffman tables"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + huffman_table = picture->huf_table->param; + + num_tables = MIN (G_N_ELEMENTS (huffman_table->huffman_table), + GST_JPEG_MAX_SCAN_COMPONENTS); + + if (!encoder->has_huff_tables) { + gst_jpeg_get_default_huffman_tables (&encoder->huff_tables); + encoder->has_huff_tables = TRUE; + } + + for (i = 0; i < num_tables; i++) { + huffman_table->load_huffman_table[i] = + encoder->huff_tables.dc_tables[i].valid + && encoder->huff_tables.ac_tables[i].valid; + if (!huffman_table->load_huffman_table[i]) + continue; + + memcpy (huffman_table->huffman_table[i].num_dc_codes, + encoder->huff_tables.dc_tables[i].huf_bits, + sizeof (huffman_table->huffman_table[i].num_dc_codes)); + memcpy (huffman_table->huffman_table[i].dc_values, + encoder->huff_tables.dc_tables[i].huf_values, + sizeof (huffman_table->huffman_table[i].dc_values)); + memcpy (huffman_table->huffman_table[i].num_ac_codes, + encoder->huff_tables.ac_tables[i].huf_bits, + sizeof (huffman_table->huffman_table[i].num_ac_codes)); + memcpy (huffman_table->huffman_table[i].ac_values, + encoder->huff_tables.ac_tables[i].huf_values, + sizeof (huffman_table->huffman_table[i].ac_values)); + memset (huffman_table->huffman_table[i].pad, + 0, sizeof (huffman_table->huffman_table[i].pad)); + } + + return TRUE; +} + +static gboolean +ensure_huffman_table (GstVaapiEncoderJpeg * encoder, + GstVaapiEncPicture * picture) +{ + g_assert (picture); + + if (!fill_huffman_table (encoder, picture)) + return FALSE; + + return TRUE; +} + +static gboolean +fill_slices (GstVaapiEncoderJpeg * encoder, GstVaapiEncPicture * picture) +{ + VAEncSliceParameterBufferJPEG *slice_param; + GstVaapiEncSlice *slice; + VAEncPictureParameterBufferJPEG *const pic_param = picture->param; + + slice = GST_VAAPI_ENC_SLICE_NEW (JPEG, encoder); + g_assert (slice && slice->param_id != VA_INVALID_ID); + slice_param = slice->param; + + memset (slice_param, 0, sizeof (VAEncSliceParameterBufferJPEG)); + + slice_param->restart_interval = 0; + slice_param->num_components = pic_param->num_components; + + slice_param->components[0].component_selector = 1; + slice_param->components[0].dc_table_selector = 0; + slice_param->components[0].ac_table_selector = 0; + + slice_param->components[1].component_selector = 2; + slice_param->components[1].dc_table_selector = 1; + slice_param->components[1].ac_table_selector = 1; + + slice_param->components[2].component_selector = 3; + slice_param->components[2].dc_table_selector = 1; + slice_param->components[2].ac_table_selector = 1; + + gst_vaapi_enc_picture_add_slice (picture, slice); + gst_vaapi_codec_object_replace (&slice, NULL); + + return TRUE; +} + +static gboolean +ensure_slices (GstVaapiEncoderJpeg * encoder, GstVaapiEncPicture * picture) +{ + g_assert (picture); + + if (!fill_slices (encoder, picture)) + return FALSE; + + return TRUE; +} + +static void +generate_frame_hdr (GstJpegFrameHdr * frame_hdr, GstVaapiEncoderJpeg * encoder, + GstVaapiEncPicture * picture) +{ + VAEncPictureParameterBufferJPEG *const pic_param = picture->param; + guint i; + + memset (frame_hdr, 0, sizeof (GstJpegFrameHdr)); + frame_hdr->sample_precision = 8; + frame_hdr->width = pic_param->picture_width; + frame_hdr->height = pic_param->picture_height; + frame_hdr->num_components = pic_param->num_components; + + for (i = 0; i < frame_hdr->num_components; i++) { + frame_hdr->components[i].identifier = pic_param->component_id[i]; + frame_hdr->components[i].horizontal_factor = encoder->h_samp[i]; + frame_hdr->components[i].vertical_factor = encoder->v_samp[i]; + frame_hdr->components[i].quant_table_selector = + pic_param->quantiser_table_selector[i]; + } +} + +static void +generate_scan_hdr (GstJpegScanHdr * scan_hdr, GstVaapiEncPicture * picture) +{ + + VAEncPictureParameterBufferJPEG *const pic_param = picture->param; + + memset (scan_hdr, 0, sizeof (GstJpegScanHdr)); + scan_hdr->num_components = pic_param->num_components; + //Y Component + scan_hdr->components[0].component_selector = 1; + scan_hdr->components[0].dc_selector = 0; + scan_hdr->components[0].ac_selector = 0; + + + //U Component + scan_hdr->components[1].component_selector = 2; + scan_hdr->components[1].dc_selector = 1; + scan_hdr->components[1].ac_selector = 1; + + //V Component + scan_hdr->components[2].component_selector = 3; + scan_hdr->components[2].dc_selector = 1; + scan_hdr->components[2].ac_selector = 1; +} + +static gboolean +bs_write_jpeg_header (GstBitWriter * bs, GstVaapiEncoderJpeg * encoder, + GstVaapiEncPicture * picture) +{ + GstJpegFrameHdr frame_hdr; + GstJpegScanHdr scan_hdr; + guint i, j; + + gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8); + gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_SOI, 8); + gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8); + gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_APP_MIN, 8); + gst_bit_writer_put_bits_uint16 (bs, 16, 16); + gst_bit_writer_put_bits_uint8 (bs, 0x4A, 8); //J + gst_bit_writer_put_bits_uint8 (bs, 0x46, 8); //F + gst_bit_writer_put_bits_uint8 (bs, 0x49, 8); //I + gst_bit_writer_put_bits_uint8 (bs, 0x46, 8); //F + gst_bit_writer_put_bits_uint8 (bs, 0x00, 8); //0 + gst_bit_writer_put_bits_uint8 (bs, 1, 8); //Major Version + gst_bit_writer_put_bits_uint8 (bs, 1, 8); //Minor Version + gst_bit_writer_put_bits_uint8 (bs, 0, 8); //Density units 0:no units, 1:pixels per inch, 2: pixels per cm + gst_bit_writer_put_bits_uint16 (bs, 1, 16); //X density (pixel-aspect-ratio) + gst_bit_writer_put_bits_uint16 (bs, 1, 16); //Y density (pixel-aspect-ratio) + gst_bit_writer_put_bits_uint8 (bs, 0, 8); //Thumbnail width + gst_bit_writer_put_bits_uint8 (bs, 0, 8); //Thumbnail height + + /* Add quantization table */ + if (!encoder->has_quant_tables) { + GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (encoder); + guint shift = 0; + + if (gst_vaapi_display_has_driver_quirks (display, + GST_VAAPI_DRIVER_QUIRK_JPEG_ENC_SHIFT_VALUE_BY_50)) + shift = 50; + + gst_jpeg_get_default_quantization_tables (&encoder->quant_tables); + generate_scaled_qm (&encoder->quant_tables, &encoder->scaled_quant_tables, + encoder->quality, shift); + encoder->has_quant_tables = TRUE; + } + + gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8); + gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_DQT, 8); + gst_bit_writer_put_bits_uint16 (bs, 3 + GST_JPEG_MAX_QUANT_ELEMENTS, 16); //Lq + gst_bit_writer_put_bits_uint8 (bs, encoder->quant_tables.quant_tables[0].quant_precision, 4); //Pq + gst_bit_writer_put_bits_uint8 (bs, 0, 4); //Tq + for (i = 0; i < GST_JPEG_MAX_QUANT_ELEMENTS; i++) { + gst_bit_writer_put_bits_uint16 (bs, + encoder->scaled_quant_tables.quant_tables[0].quant_table[i], 8); + } + gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8); + gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_DQT, 8); + gst_bit_writer_put_bits_uint16 (bs, 3 + GST_JPEG_MAX_QUANT_ELEMENTS, 16); //Lq + gst_bit_writer_put_bits_uint8 (bs, encoder->quant_tables.quant_tables[1].quant_precision, 4); //Pq + gst_bit_writer_put_bits_uint8 (bs, 1, 4); //Tq + for (i = 0; i < GST_JPEG_MAX_QUANT_ELEMENTS; i++) { + gst_bit_writer_put_bits_uint16 (bs, + encoder->scaled_quant_tables.quant_tables[1].quant_table[i], 8); + } + + /*Add frame header */ + generate_frame_hdr (&frame_hdr, encoder, picture); + gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8); + gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_SOF_MIN, 8); + gst_bit_writer_put_bits_uint16 (bs, 8 + (3 * 3), 16); //lf, Size of FrameHeader in bytes without the Marker SOF + gst_bit_writer_put_bits_uint8 (bs, frame_hdr.sample_precision, 8); + gst_bit_writer_put_bits_uint16 (bs, frame_hdr.height, 16); + gst_bit_writer_put_bits_uint16 (bs, frame_hdr.width, 16); + gst_bit_writer_put_bits_uint8 (bs, frame_hdr.num_components, 8); + for (i = 0; i < frame_hdr.num_components; i++) { + gst_bit_writer_put_bits_uint8 (bs, frame_hdr.components[i].identifier, 8); + gst_bit_writer_put_bits_uint8 (bs, + frame_hdr.components[i].horizontal_factor, 4); + gst_bit_writer_put_bits_uint8 (bs, frame_hdr.components[i].vertical_factor, + 4); + gst_bit_writer_put_bits_uint8 (bs, + frame_hdr.components[i].quant_table_selector, 8); + } + + /* Add Huffman table */ + if (!encoder->has_huff_tables) { + gst_jpeg_get_default_huffman_tables (&encoder->huff_tables); + encoder->has_huff_tables = TRUE; + } + for (i = 0; i < 2; i++) { + gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8); + gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_DHT, 8); + gst_bit_writer_put_bits_uint16 (bs, 0x1F, 16); //length of table + gst_bit_writer_put_bits_uint8 (bs, 0, 4); + gst_bit_writer_put_bits_uint8 (bs, i, 4); + for (j = 0; j < NUM_DC_RUN_SIZE_BITS; j++) { + gst_bit_writer_put_bits_uint8 (bs, + encoder->huff_tables.dc_tables[i].huf_bits[j], 8); + } + + for (j = 0; j < NUM_DC_CODE_WORDS_HUFFVAL; j++) { + gst_bit_writer_put_bits_uint8 (bs, + encoder->huff_tables.dc_tables[i].huf_values[j], 8); + } + + gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8); + gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_DHT, 8); + gst_bit_writer_put_bits_uint16 (bs, 0xB5, 16); //length of table + gst_bit_writer_put_bits_uint8 (bs, 1, 4); + gst_bit_writer_put_bits_uint8 (bs, i, 4); + for (j = 0; j < NUM_AC_RUN_SIZE_BITS; j++) { + gst_bit_writer_put_bits_uint8 (bs, + encoder->huff_tables.ac_tables[i].huf_bits[j], 8); + } + + for (j = 0; j < NUM_AC_CODE_WORDS_HUFFVAL; j++) { + gst_bit_writer_put_bits_uint8 (bs, + encoder->huff_tables.ac_tables[i].huf_values[j], 8); + } + } + + /* Add ScanHeader */ + generate_scan_hdr (&scan_hdr, picture); + gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8); + gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_SOS, 8); + gst_bit_writer_put_bits_uint16 (bs, 12, 16); //Length of Scan + gst_bit_writer_put_bits_uint8 (bs, scan_hdr.num_components, 8); + + for (i = 0; i < scan_hdr.num_components; i++) { + gst_bit_writer_put_bits_uint8 (bs, + scan_hdr.components[i].component_selector, 8); + gst_bit_writer_put_bits_uint8 (bs, scan_hdr.components[i].dc_selector, 4); + gst_bit_writer_put_bits_uint8 (bs, scan_hdr.components[i].ac_selector, 4); + } + gst_bit_writer_put_bits_uint8 (bs, 0, 8); //0 for Baseline + gst_bit_writer_put_bits_uint8 (bs, 63, 8); //63 for Baseline + gst_bit_writer_put_bits_uint8 (bs, 0, 4); //0 for Baseline + gst_bit_writer_put_bits_uint8 (bs, 0, 4); //0 for Baseline + + return TRUE; +} + +static gboolean +add_packed_header (GstVaapiEncoderJpeg * encoder, GstVaapiEncPicture * picture) +{ + GstVaapiEncPackedHeader *packed_raw_data_hdr; + GstBitWriter bs; + VAEncPackedHeaderParameterBuffer packed_raw_data_hdr_param = { 0 }; + guint32 data_bit_size; + guint8 *data; + + gst_bit_writer_init_with_size (&bs, 128, FALSE); + bs_write_jpeg_header (&bs, encoder, picture); + data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs); + data = GST_BIT_WRITER_DATA (&bs); + + packed_raw_data_hdr_param.type = VAEncPackedHeaderRawData; + packed_raw_data_hdr_param.bit_length = data_bit_size; + packed_raw_data_hdr_param.has_emulation_bytes = 0; + + packed_raw_data_hdr = + gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder), + &packed_raw_data_hdr_param, sizeof (packed_raw_data_hdr_param), data, + (data_bit_size + 7) / 8); + g_assert (packed_raw_data_hdr); + + gst_vaapi_enc_picture_add_packed_header (picture, packed_raw_data_hdr); + gst_vaapi_codec_object_replace (&packed_raw_data_hdr, NULL); + + gst_bit_writer_reset (&bs); + + return TRUE; +} + +static gboolean +ensure_packed_headers (GstVaapiEncoderJpeg * encoder, + GstVaapiEncPicture * picture) +{ + g_assert (picture); + + if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) & + VA_ENC_PACKED_HEADER_RAW_DATA) + && !add_packed_header (encoder, picture)) + goto error_create_packed_hdr; + + return TRUE; + + /* ERRORS */ +error_create_packed_hdr: + { + GST_ERROR ("failed to create packed raw data header buffer"); + return FALSE; + } +} + +static GstVaapiEncoderStatus +gst_vaapi_encoder_jpeg_encode (GstVaapiEncoder * base_encoder, + GstVaapiEncPicture * picture, GstVaapiCodedBufferProxy * codedbuf) +{ + GstVaapiEncoderJpeg *const encoder = GST_VAAPI_ENCODER_JPEG (base_encoder); + GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN; + GstVaapiSurfaceProxy *reconstruct = NULL; + + reconstruct = gst_vaapi_encoder_create_surface (base_encoder); + + g_assert (GST_VAAPI_SURFACE_PROXY_SURFACE (reconstruct)); + + if (!ensure_picture (encoder, picture, codedbuf, reconstruct)) + goto error; + if (!ensure_quantization_table (encoder, picture)) + goto error; + if (!ensure_huffman_table (encoder, picture)) + goto error; + if (!ensure_slices (encoder, picture)) + goto error; + if (!ensure_packed_headers (encoder, picture)) + goto error; + if (!gst_vaapi_enc_picture_encode (picture)) + goto error; + if (reconstruct) + gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder), + reconstruct); + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; + + /* ERRORS */ +error: + { + if (reconstruct) + gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder), + reconstruct); + return ret; + } +} + +static GstVaapiEncoderStatus +gst_vaapi_encoder_jpeg_flush (GstVaapiEncoder * base_encoder) +{ + return GST_VAAPI_ENCODER_STATUS_SUCCESS; +} + +static GstVaapiEncoderStatus +gst_vaapi_encoder_jpeg_reordering (GstVaapiEncoder * base_encoder, + GstVideoCodecFrame * frame, GstVaapiEncPicture ** output) +{ + GstVaapiEncoderJpeg *const encoder = GST_VAAPI_ENCODER_JPEG (base_encoder); + GstVaapiEncPicture *picture = NULL; + GstVaapiEncoderStatus status = GST_VAAPI_ENCODER_STATUS_SUCCESS; + + if (!frame) + return GST_VAAPI_ENCODER_STATUS_NO_SURFACE; + + picture = GST_VAAPI_ENC_PICTURE_NEW (JPEG, encoder, frame); + if (!picture) { + GST_WARNING ("create JPEG picture failed, frame timestamp:%" + GST_TIME_FORMAT, GST_TIME_ARGS (frame->pts)); + return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + *output = picture; + return status; +} + +static GstVaapiEncoderStatus +gst_vaapi_encoder_jpeg_reconfigure (GstVaapiEncoder * base_encoder) +{ + GstVaapiEncoderJpeg *const encoder = GST_VAAPI_ENCODER_JPEG (base_encoder); + GstVaapiEncoderStatus status; + + status = ensure_profile (encoder); + if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) + return status; + + /* generate sampling factors (A.1.1) */ + generate_sampling_factors (encoder); + + return set_context_info (base_encoder); +} + +struct _GstVaapiEncoderJpegClass +{ + GstVaapiEncoderClass parent_class; +}; + +G_DEFINE_TYPE (GstVaapiEncoderJpeg, gst_vaapi_encoder_jpeg, + GST_TYPE_VAAPI_ENCODER); + +static void +gst_vaapi_encoder_jpeg_init (GstVaapiEncoderJpeg * encoder) +{ + encoder->has_quant_tables = FALSE; + memset (&encoder->quant_tables, 0, sizeof (encoder->quant_tables)); + memset (&encoder->scaled_quant_tables, 0, + sizeof (encoder->scaled_quant_tables)); + encoder->has_huff_tables = FALSE; + memset (&encoder->huff_tables, 0, sizeof (encoder->huff_tables)); +} + +/** + * @ENCODER_JPEG_PROP_RATECONTROL: Rate control (#GstVaapiRateControl). + * @ENCODER_JPEG_PROP_TUNE: The tuning options (#GstVaapiEncoderTune). + * @ENCODER_JPEG_PROP_QUALITY: Quality Factor value (uint). + * + * The set of JPEG encoder specific configurable properties. + */ +enum +{ + ENCODER_JPEG_PROP_RATECONTROL = 1, + ENCODER_JPEG_PROP_TUNE, + ENCODER_JPEG_PROP_QUALITY, + ENCODER_JPEG_N_PROPERTIES +}; + +static GParamSpec *properties[ENCODER_JPEG_N_PROPERTIES]; + +static void +gst_vaapi_encoder_jpeg_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object); + GstVaapiEncoderJpeg *const encoder = GST_VAAPI_ENCODER_JPEG (object); + + if (base_encoder->num_codedbuf_queued > 0) { + GST_ERROR_OBJECT (object, + "failed to set any property after encoding started"); + return; + } + + switch (prop_id) { + case ENCODER_JPEG_PROP_RATECONTROL: + gst_vaapi_encoder_set_rate_control (base_encoder, + g_value_get_enum (value)); + break; + case ENCODER_JPEG_PROP_TUNE: + gst_vaapi_encoder_set_tuning (base_encoder, g_value_get_enum (value)); + break; + case ENCODER_JPEG_PROP_QUALITY: + encoder->quality = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gst_vaapi_encoder_jpeg_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstVaapiEncoderJpeg *const encoder = GST_VAAPI_ENCODER_JPEG (object); + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object); + + switch (prop_id) { + case ENCODER_JPEG_PROP_RATECONTROL: + g_value_set_enum (value, base_encoder->rate_control); + break; + case ENCODER_JPEG_PROP_TUNE: + g_value_set_enum (value, base_encoder->tune); + break; + case ENCODER_JPEG_PROP_QUALITY: + g_value_set_uint (value, encoder->quality); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +GST_VAAPI_ENCODER_DEFINE_CLASS_DATA (JPEG); + +static void +gst_vaapi_encoder_jpeg_class_init (GstVaapiEncoderJpegClass * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstVaapiEncoderClass *const encoder_class = GST_VAAPI_ENCODER_CLASS (klass); + + encoder_class->class_data = &g_class_data; + encoder_class->reconfigure = gst_vaapi_encoder_jpeg_reconfigure; + encoder_class->reordering = gst_vaapi_encoder_jpeg_reordering; + encoder_class->encode = gst_vaapi_encoder_jpeg_encode; + encoder_class->flush = gst_vaapi_encoder_jpeg_flush; + + object_class->set_property = gst_vaapi_encoder_jpeg_set_property; + object_class->get_property = gst_vaapi_encoder_jpeg_get_property; + + properties[ENCODER_JPEG_PROP_RATECONTROL] = + g_param_spec_enum ("rate-control", + "Rate Control", "Rate control mode", + g_class_data.rate_control_get_type (), + g_class_data.default_rate_control, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + properties[ENCODER_JPEG_PROP_TUNE] = + g_param_spec_enum ("tune", + "Encoder Tuning", + "Encoder tuning option", + g_class_data.encoder_tune_get_type (), + g_class_data.default_encoder_tune, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + properties[ENCODER_JPEG_PROP_QUALITY] = + g_param_spec_uint ("quality", + "Quality factor", + "Quality factor", 0, 100, 50, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + g_object_class_install_properties (object_class, ENCODER_JPEG_N_PROPERTIES, + properties); + + gst_type_mark_as_plugin_api (g_class_data.rate_control_get_type (), 0); + gst_type_mark_as_plugin_api (g_class_data.encoder_tune_get_type (), 0); +} + +/** + * gst_vaapi_encoder_jpeg_new: + * @display: a #GstVaapiDisplay + * + * Creates a new #GstVaapiEncoder for JPEG encoding. + * + * Return value: the newly allocated #GstVaapiEncoder object + */ +GstVaapiEncoder * +gst_vaapi_encoder_jpeg_new (GstVaapiDisplay * display) +{ + return g_object_new (GST_TYPE_VAAPI_ENCODER_JPEG, "display", display, NULL); +} diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_jpeg.h b/gst-libs/gst/vaapi/gstvaapiencoder_jpeg.h new file mode 100644 index 0000000000..b3b24749f5 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder_jpeg.h @@ -0,0 +1,50 @@ +/* + * gstvaapiencoder_jpeg.h JPEGG encoder + * + * Copyright (C) 2015 Intel Corporation + * Author: Sreerenj Balachandran + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_ENCODER_JPEG_H +#define GST_VAAPI_ENCODER_JPEG_H + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_ENCODER_JPEG \ + (gst_vaapi_encoder_jpeg_get_type ()) +#define GST_VAAPI_ENCODER_JPEG(encoder) \ + (G_TYPE_CHECK_INSTANCE_CAST ((encoder), GST_TYPE_VAAPI_ENCODER_JPEG, GstVaapiEncoderJpeg)) +#define GST_IS_VAAPI_ENCODER_JPEG(encoder) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((encoder), GST_TYPE_VAAPI_ENCODER_JPEG)) + +typedef struct _GstVaapiEncoderJpeg GstVaapiEncoderJpeg; +typedef struct _GstVaapiEncoderJpegClass GstVaapiEncoderJpegClass; + +GType +gst_vaapi_encoder_jpeg_get_type (void) G_GNUC_CONST; + +GstVaapiEncoder * +gst_vaapi_encoder_jpeg_new (GstVaapiDisplay * display); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiEncoderJpeg, gst_object_unref) + +G_END_DECLS + +#endif /*GST_VAAPI_ENCODER_JPEG_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c b/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c new file mode 100644 index 0000000000..731b03e58b --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c @@ -0,0 +1,1098 @@ +/* + * gstvaapiencoder_mpeg2.c - MPEG-2 encoder + * + * Copyright (C) 2012-2014 Intel Corporation + * Author: Guangxin Xu + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include +#include "sysdeps.h" +#include +#include "gstvaapicompat.h" +#include "gstvaapiencoder_mpeg2.h" +#include "gstvaapiencoder_mpeg2_priv.h" +#include "gstvaapiutils_mpeg2_priv.h" +#include "gstvaapicodedbufferproxy_priv.h" +#include "gstvaapicontext.h" +#include "gstvaapisurface.h" +#include "gstvaapidisplay_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +/* Define default rate control mode ("constant-qp") */ +#define DEFAULT_RATECONTROL GST_VAAPI_RATECONTROL_CQP + +/* Supported set of VA rate controls, within this implementation */ +#define SUPPORTED_RATECONTROLS \ + (GST_VAAPI_RATECONTROL_MASK (CQP) | \ + GST_VAAPI_RATECONTROL_MASK (CBR)) + +/* Supported set of tuning options, within this implementation */ +#define SUPPORTED_TUNE_OPTIONS \ + (GST_VAAPI_ENCODER_TUNE_MASK (NONE)) + +/* Supported set of VA packed headers, within this implementation */ +#define SUPPORTED_PACKED_HEADERS \ + (VA_ENC_PACKED_HEADER_SEQUENCE | \ + VA_ENC_PACKED_HEADER_PICTURE) + +static gboolean +gst_bit_writer_write_sps (GstBitWriter * bitwriter, + const VAEncSequenceParameterBufferMPEG2 * seq_param); + +static gboolean +gst_bit_writer_write_pps (GstBitWriter * bitwriter, + const VAEncPictureParameterBufferMPEG2 * pic_param); + +static void clear_references (GstVaapiEncoderMpeg2 * encoder); + +static void push_reference (GstVaapiEncoderMpeg2 * encoder, + GstVaapiSurfaceProxy * ref); + +/* Derives the profile supported by the underlying hardware */ +static gboolean +ensure_hw_profile (GstVaapiEncoderMpeg2 * encoder) +{ + GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (encoder); + GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE; + GstVaapiProfile profile, profiles[2]; + guint i, num_profiles = 0; + + profiles[num_profiles++] = encoder->profile; + switch (encoder->profile) { + case GST_VAAPI_PROFILE_MPEG2_SIMPLE: + profiles[num_profiles++] = GST_VAAPI_PROFILE_MPEG2_MAIN; + break; + default: + break; + } + + profile = GST_VAAPI_PROFILE_UNKNOWN; + for (i = 0; i < num_profiles; i++) { + if (gst_vaapi_display_has_encoder (display, profiles[i], entrypoint)) { + profile = profiles[i]; + break; + } + } + if (profile == GST_VAAPI_PROFILE_UNKNOWN) + goto error_unsupported_profile; + + GST_VAAPI_ENCODER_CAST (encoder)->profile = profile; + return TRUE; + + /* ERRORS */ +error_unsupported_profile: + { + GST_ERROR ("unsupported HW profile %s", + gst_vaapi_profile_get_va_name (encoder->profile)); + return FALSE; + } +} + +/* Derives the minimum profile from the active coding tools */ +static gboolean +ensure_profile (GstVaapiEncoderMpeg2 * encoder) +{ + GstVaapiProfile profile; + + /* Always start from "simple" profile for maximum compatibility */ + profile = GST_VAAPI_PROFILE_MPEG2_SIMPLE; + + /* Main profile coding tools */ + if (encoder->ip_period > 0) + profile = GST_VAAPI_PROFILE_MPEG2_MAIN; + + encoder->profile = profile; + encoder->profile_idc = gst_vaapi_utils_mpeg2_get_profile_idc (profile); + return TRUE; +} + +/* Derives the minimum level from the current configuration */ +static gboolean +ensure_level (GstVaapiEncoderMpeg2 * encoder) +{ + const GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder); + const guint fps = (vip->fps_n + vip->fps_d - 1) / vip->fps_d; + const guint bitrate = GST_VAAPI_ENCODER_CAST (encoder)->bitrate; + const GstVaapiMPEG2LevelLimits *limits_table; + guint i, num_limits, num_samples; + + num_samples = gst_util_uint64_scale_int_ceil (vip->width * vip->height, + vip->fps_n, vip->fps_d); + + limits_table = gst_vaapi_utils_mpeg2_get_level_limits_table (&num_limits); + for (i = 0; i < num_limits; i++) { + const GstVaapiMPEG2LevelLimits *const limits = &limits_table[i]; + if (vip->width <= limits->horizontal_size_value && + vip->height <= limits->vertical_size_value && + fps <= limits->frame_rate_value && + num_samples <= limits->sample_rate && + (!bitrate || bitrate <= limits->bit_rate)) + break; + } + if (i == num_limits) + goto error_unsupported_level; + + encoder->level = limits_table[i].level; + encoder->level_idc = limits_table[i].level_idc; + return TRUE; + + /* ERRORS */ +error_unsupported_level: + { + GST_ERROR ("failed to find a suitable level matching codec config"); + return FALSE; + } +} + +/* Derives the profile and level that suits best to the configuration */ +static GstVaapiEncoderStatus +ensure_profile_and_level (GstVaapiEncoderMpeg2 * encoder) +{ + if (!ensure_profile (encoder)) + return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + + if (!ensure_level (encoder)) + return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED; + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; +} + +static gboolean +ensure_bitrate (GstVaapiEncoderMpeg2 * encoder) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); + + /* Default compression: 64 bits per macroblock */ + switch (GST_VAAPI_ENCODER_RATE_CONTROL (encoder)) { + case GST_VAAPI_RATECONTROL_CBR: + if (!base_encoder->bitrate) + base_encoder->bitrate = + gst_util_uint64_scale (GST_VAAPI_ENCODER_WIDTH (encoder) * + GST_VAAPI_ENCODER_HEIGHT (encoder), + GST_VAAPI_ENCODER_FPS_N (encoder), + GST_VAAPI_ENCODER_FPS_D (encoder)) / 4 / 1000; + break; + default: + base_encoder->bitrate = 0; + break; + } + return TRUE; +} + +static gboolean +fill_sequence (GstVaapiEncoderMpeg2 * encoder, GstVaapiEncSequence * sequence) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); + VAEncSequenceParameterBufferMPEG2 *const seq_param = sequence->param; + + memset (seq_param, 0, sizeof (VAEncSequenceParameterBufferMPEG2)); + + seq_param->intra_period = base_encoder->keyframe_period; + seq_param->ip_period = encoder->ip_period; + seq_param->picture_width = GST_VAAPI_ENCODER_WIDTH (encoder); + seq_param->picture_height = GST_VAAPI_ENCODER_HEIGHT (encoder); + + if (base_encoder->bitrate > 0) + seq_param->bits_per_second = base_encoder->bitrate * 1000; + else + seq_param->bits_per_second = 0; + + if (GST_VAAPI_ENCODER_FPS_D (encoder)) + seq_param->frame_rate = + GST_VAAPI_ENCODER_FPS_N (encoder) / GST_VAAPI_ENCODER_FPS_D (encoder); + else + seq_param->frame_rate = 0; + + seq_param->aspect_ratio_information = 1; + seq_param->vbv_buffer_size = 3; /* B = 16 * 1024 * vbv_buffer_size */ + + seq_param->sequence_extension.bits.profile_and_level_indication = + (encoder->profile_idc << 4) | encoder->level_idc; + seq_param->sequence_extension.bits.progressive_sequence = 1; /* progressive frame-pictures */ + seq_param->sequence_extension.bits.chroma_format = + gst_vaapi_utils_mpeg2_get_chroma_format_idc + (GST_VAAPI_CHROMA_TYPE_YUV420); + seq_param->sequence_extension.bits.low_delay = 0; /* FIXME */ + seq_param->sequence_extension.bits.frame_rate_extension_n = 0; /* FIXME */ + seq_param->sequence_extension.bits.frame_rate_extension_d = 0; + + seq_param->gop_header.bits.time_code = (1 << 12); /* bit12: marker_bit */ + seq_param->gop_header.bits.closed_gop = 0; + seq_param->gop_header.bits.broken_link = 0; + + return TRUE; +} + +static VAEncPictureType +get_va_enc_picture_type (GstVaapiPictureType type) +{ + switch (type) { + case GST_VAAPI_PICTURE_TYPE_I: + return VAEncPictureTypeIntra; + case GST_VAAPI_PICTURE_TYPE_P: + return VAEncPictureTypePredictive; + case GST_VAAPI_PICTURE_TYPE_B: + return VAEncPictureTypeBidirectional; + default: + return -1; + } + return -1; +} + +static gboolean +fill_picture (GstVaapiEncoderMpeg2 * encoder, + GstVaapiEncPicture * picture, + GstVaapiCodedBuffer * codedbuf, GstVaapiSurfaceProxy * surface) +{ + VAEncPictureParameterBufferMPEG2 *const pic_param = picture->param; + guint8 f_code_x, f_code_y; + + memset (pic_param, 0, sizeof (VAEncPictureParameterBufferMPEG2)); + + pic_param->reconstructed_picture = + GST_VAAPI_SURFACE_PROXY_SURFACE_ID (surface); + pic_param->coded_buf = GST_VAAPI_CODED_BUFFER_ID (codedbuf); + pic_param->picture_type = get_va_enc_picture_type (picture->type); + pic_param->temporal_reference = picture->frame_num & (1024 - 1); + pic_param->vbv_delay = 0xFFFF; + + f_code_x = 0xf; + f_code_y = 0xf; + if (pic_param->picture_type != VAEncPictureTypeIntra) { + switch (encoder->level) { + case GST_VAAPI_LEVEL_MPEG2_LOW: + f_code_x = 7; + f_code_y = 4; + break; + case GST_VAAPI_LEVEL_MPEG2_MAIN: + f_code_x = 8; + f_code_y = 5; + break; + default: /* High-1440 and High levels */ + f_code_x = 9; + f_code_y = 5; + break; + } + } + + if (pic_param->picture_type == VAEncPictureTypeIntra) { + pic_param->f_code[0][0] = 0xf; + pic_param->f_code[0][1] = 0xf; + pic_param->f_code[1][0] = 0xf; + pic_param->f_code[1][1] = 0xf; + pic_param->forward_reference_picture = VA_INVALID_SURFACE; + pic_param->backward_reference_picture = VA_INVALID_SURFACE; + } else if (pic_param->picture_type == VAEncPictureTypePredictive) { + pic_param->f_code[0][0] = f_code_x; + pic_param->f_code[0][1] = f_code_y; + pic_param->f_code[1][0] = 0xf; + pic_param->f_code[1][1] = 0xf; + pic_param->forward_reference_picture = + GST_VAAPI_SURFACE_PROXY_SURFACE_ID (encoder->forward); + pic_param->backward_reference_picture = VA_INVALID_SURFACE; + } else if (pic_param->picture_type == VAEncPictureTypeBidirectional) { + pic_param->f_code[0][0] = f_code_x; + pic_param->f_code[0][1] = f_code_y; + pic_param->f_code[1][0] = f_code_x; + pic_param->f_code[1][1] = f_code_y; + pic_param->forward_reference_picture = + GST_VAAPI_SURFACE_PROXY_SURFACE_ID (encoder->forward); + pic_param->backward_reference_picture = + GST_VAAPI_SURFACE_PROXY_SURFACE_ID (encoder->backward); + } else { + g_assert (0); + } + + pic_param->picture_coding_extension.bits.intra_dc_precision = 0; /* 8bits */ + pic_param->picture_coding_extension.bits.picture_structure = 3; /* frame picture */ + pic_param->picture_coding_extension.bits.top_field_first = 0; + pic_param->picture_coding_extension.bits.frame_pred_frame_dct = 1; /* FIXME */ + pic_param->picture_coding_extension.bits.concealment_motion_vectors = 0; + pic_param->picture_coding_extension.bits.q_scale_type = 0; + pic_param->picture_coding_extension.bits.intra_vlc_format = 0; + pic_param->picture_coding_extension.bits.alternate_scan = 0; + pic_param->picture_coding_extension.bits.repeat_first_field = 0; + pic_param->picture_coding_extension.bits.progressive_frame = 1; + pic_param->picture_coding_extension.bits.composite_display_flag = 0; + + return TRUE; +} + +static gboolean +set_sequence_packed_header (GstVaapiEncoderMpeg2 * encoder, + GstVaapiEncPicture * picture, GstVaapiEncSequence * sequence) +{ + GstVaapiEncPackedHeader *packed_seq; + GstBitWriter writer; + VAEncPackedHeaderParameterBuffer packed_header_param_buffer = { 0 }; + const VAEncSequenceParameterBufferMPEG2 *const seq_param = sequence->param; + guint32 data_bit_size; + guint8 *data; + + gst_bit_writer_init_with_size (&writer, 128, FALSE); + if (encoder->new_gop) + gst_bit_writer_write_sps (&writer, seq_param); + g_assert (GST_BIT_WRITER_BIT_SIZE (&writer) % 8 == 0); + data_bit_size = GST_BIT_WRITER_BIT_SIZE (&writer); + data = GST_BIT_WRITER_DATA (&writer); + + packed_header_param_buffer.type = VAEncPackedHeaderSequence; + packed_header_param_buffer.bit_length = data_bit_size; + packed_header_param_buffer.has_emulation_bytes = 0; + + packed_seq = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder), + &packed_header_param_buffer, sizeof (packed_header_param_buffer), + data, (data_bit_size + 7) / 8); + g_assert (packed_seq); + + gst_vaapi_enc_picture_add_packed_header (picture, packed_seq); + gst_vaapi_codec_object_replace (&packed_seq, NULL); + gst_bit_writer_reset (&writer); + + return TRUE; +} + +static gboolean +set_picture_packed_header (GstVaapiEncoderMpeg2 * encoder, + GstVaapiEncPicture * picture) +{ + GstVaapiEncPackedHeader *packed_pic; + GstBitWriter writer; + VAEncPackedHeaderParameterBuffer packed_header_param_buffer = { 0 }; + const VAEncPictureParameterBufferMPEG2 *const pic_param = picture->param; + guint32 data_bit_size; + guint8 *data; + + gst_bit_writer_init_with_size (&writer, 128, FALSE); + gst_bit_writer_write_pps (&writer, pic_param); + g_assert (GST_BIT_WRITER_BIT_SIZE (&writer) % 8 == 0); + data_bit_size = GST_BIT_WRITER_BIT_SIZE (&writer); + data = GST_BIT_WRITER_DATA (&writer); + + packed_header_param_buffer.type = VAEncPackedHeaderPicture; + packed_header_param_buffer.bit_length = data_bit_size; + packed_header_param_buffer.has_emulation_bytes = 0; + + packed_pic = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder), + &packed_header_param_buffer, sizeof (packed_header_param_buffer), + data, (data_bit_size + 7) / 8); + g_assert (packed_pic); + + gst_vaapi_enc_picture_add_packed_header (picture, packed_pic); + gst_vaapi_codec_object_replace (&packed_pic, NULL); + gst_bit_writer_reset (&writer); + + return TRUE; +} + +static gboolean +ensure_sequence (GstVaapiEncoderMpeg2 * encoder, GstVaapiEncPicture * picture) +{ + GstVaapiEncSequence *sequence; + + g_assert (picture); + sequence = GST_VAAPI_ENC_SEQUENCE_NEW (MPEG2, encoder); + g_assert (sequence); + if (!sequence) + goto error; + + if (!fill_sequence (encoder, sequence)) + goto error; + + if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) & + VA_ENC_PACKED_HEADER_SEQUENCE) + && picture->type == GST_VAAPI_PICTURE_TYPE_I + && !set_sequence_packed_header (encoder, picture, sequence)) + goto error; + gst_vaapi_enc_picture_set_sequence (picture, sequence); + gst_vaapi_codec_object_replace (&sequence, NULL); + return TRUE; + + /* ERRORS */ +error: + { + gst_vaapi_codec_object_replace (&sequence, NULL); + return FALSE; + } +} + +static gboolean +ensure_picture (GstVaapiEncoderMpeg2 * encoder, GstVaapiEncPicture * picture, + GstVaapiCodedBufferProxy * codedbuf_proxy, GstVaapiSurfaceProxy * surface) +{ + GstVaapiCodedBuffer *const codedbuf = + GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (codedbuf_proxy); + + if (!fill_picture (encoder, picture, codedbuf, surface)) + return FALSE; + + if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) & + VA_ENC_PACKED_HEADER_PICTURE) + && !set_picture_packed_header (encoder, picture)) { + GST_ERROR ("set picture packed header failed"); + return FALSE; + } + return TRUE; +} + +static gboolean +ensure_control_rate_params (GstVaapiEncoderMpeg2 * encoder) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); + + if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CQP) + return TRUE; + + /* RateControl params */ + GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).initial_qp = encoder->cqp; + + /* *INDENT-OFF* */ + /* HRD params */ + GST_VAAPI_ENCODER_VA_HRD (encoder) = (VAEncMiscParameterHRD) { + .buffer_size = base_encoder->bitrate * 1000 * 8, + .initial_buffer_fullness = base_encoder->bitrate * 1000 * 4, + }; + /* *INDENT-ON* */ + + return TRUE; +} + +static gboolean +set_misc_parameters (GstVaapiEncoderMpeg2 * encoder, + GstVaapiEncPicture * picture) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); + + if (!gst_vaapi_encoder_ensure_param_control_rate (base_encoder, picture)) + return FALSE; + if (!gst_vaapi_encoder_ensure_param_quality_level (base_encoder, picture)) + return FALSE; + return TRUE; +} + +static gboolean +fill_slices (GstVaapiEncoderMpeg2 * encoder, GstVaapiEncPicture * picture) +{ + VAEncSliceParameterBufferMPEG2 *slice_param; + GstVaapiEncSlice *slice; + guint width_in_mbs, height_in_mbs; + guint i_slice; + + g_assert (picture); + + width_in_mbs = (GST_VAAPI_ENCODER_WIDTH (encoder) + 15) / 16; + height_in_mbs = (GST_VAAPI_ENCODER_HEIGHT (encoder) + 15) / 16; + + for (i_slice = 0; i_slice < height_in_mbs; ++i_slice) { + slice = GST_VAAPI_ENC_SLICE_NEW (MPEG2, encoder); + g_assert (slice && slice->param_id != VA_INVALID_ID); + slice_param = slice->param; + + memset (slice_param, 0, sizeof (VAEncSliceParameterBufferMPEG2)); + + slice_param->macroblock_address = i_slice * width_in_mbs; + slice_param->num_macroblocks = width_in_mbs; + slice_param->is_intra_slice = (picture->type == GST_VAAPI_PICTURE_TYPE_I); + slice_param->quantiser_scale_code = encoder->cqp / 2; + + gst_vaapi_enc_picture_add_slice (picture, slice); + gst_vaapi_codec_object_replace (&slice, NULL); + } + return TRUE; +} + +static gboolean +ensure_slices (GstVaapiEncoderMpeg2 * encoder, GstVaapiEncPicture * picture) +{ + g_assert (picture); + + if (!fill_slices (encoder, picture)) + return FALSE; + + return TRUE; +} + +static GstVaapiEncoderStatus +gst_vaapi_encoder_mpeg2_encode (GstVaapiEncoder * base_encoder, + GstVaapiEncPicture * picture, GstVaapiCodedBufferProxy * codedbuf) +{ + GstVaapiEncoderMpeg2 *const encoder = + GST_VAAPI_ENCODER_MPEG2_CAST (base_encoder); + GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN; + GstVaapiSurfaceProxy *reconstruct = NULL; + + reconstruct = gst_vaapi_encoder_create_surface (base_encoder); + + g_assert (GST_VAAPI_SURFACE_PROXY_SURFACE (reconstruct)); + + if (!ensure_sequence (encoder, picture)) + goto error; + if (!ensure_picture (encoder, picture, codedbuf, reconstruct)) + goto error; + if (!set_misc_parameters (encoder, picture)) + goto error; + if (!ensure_slices (encoder, picture)) + goto error; + if (!gst_vaapi_enc_picture_encode (picture)) + goto error; + if (picture->type != GST_VAAPI_PICTURE_TYPE_B) { + if (encoder->new_gop) + clear_references (encoder); + push_reference (encoder, reconstruct); + } else if (reconstruct) + gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder), + reconstruct); + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; + + /* ERRORS */ +error: + { + if (reconstruct) + gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder), + reconstruct); + return ret; + } +} + +static GstVaapiEncoderStatus +gst_vaapi_encoder_mpeg2_flush (GstVaapiEncoder * base_encoder) +{ + GstVaapiEncoderMpeg2 *const encoder = + GST_VAAPI_ENCODER_MPEG2_CAST (base_encoder); + GstVaapiEncPicture *pic; + + while (!g_queue_is_empty (&encoder->b_frames)) { + pic = g_queue_pop_head (&encoder->b_frames); + gst_vaapi_enc_picture_unref (pic); + } + g_queue_clear (&encoder->b_frames); + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; +} + +static GstVaapiEncoderStatus +gst_vaapi_encoder_mpeg2_reordering (GstVaapiEncoder * base_encoder, + GstVideoCodecFrame * frame, GstVaapiEncPicture ** output) +{ + GstVaapiEncoderMpeg2 *const encoder = + GST_VAAPI_ENCODER_MPEG2_CAST (base_encoder); + GstVaapiEncPicture *picture = NULL; + GstVaapiEncoderStatus status = GST_VAAPI_ENCODER_STATUS_SUCCESS; + + if (!frame) { + if (g_queue_is_empty (&encoder->b_frames) && encoder->dump_frames) { + push_reference (encoder, NULL); + encoder->dump_frames = FALSE; + } + if (!encoder->dump_frames) { + return GST_VAAPI_ENCODER_STATUS_NO_SURFACE; + } + picture = g_queue_pop_head (&encoder->b_frames); + g_assert (picture); + goto end; + } + + picture = GST_VAAPI_ENC_PICTURE_NEW (MPEG2, encoder, frame); + if (!picture) { + GST_WARNING ("create MPEG2 picture failed, frame timestamp:%" + GST_TIME_FORMAT, GST_TIME_ARGS (frame->pts)); + return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + if (encoder->frame_num >= base_encoder->keyframe_period) { + encoder->frame_num = 0; + clear_references (encoder); + } + if (encoder->frame_num == 0) { + picture->type = GST_VAAPI_PICTURE_TYPE_I; + GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame); + encoder->new_gop = TRUE; + } else { + encoder->new_gop = FALSE; + if ((encoder->frame_num % (encoder->ip_period + 1)) == 0 || + encoder->frame_num == base_encoder->keyframe_period - 1) { + picture->type = GST_VAAPI_PICTURE_TYPE_P; + encoder->dump_frames = TRUE; + } else { + picture->type = GST_VAAPI_PICTURE_TYPE_B; + status = GST_VAAPI_ENCODER_STATUS_NO_SURFACE; + } + } + picture->frame_num = encoder->frame_num++; + + if (picture->type == GST_VAAPI_PICTURE_TYPE_B) { + g_queue_push_tail (&encoder->b_frames, picture); + picture = NULL; + } + +end: + *output = picture; + return status; +} + +static GstVaapiEncoderStatus +set_context_info (GstVaapiEncoder * base_encoder) +{ + GstVaapiEncoderMpeg2 *const encoder = + GST_VAAPI_ENCODER_MPEG2_CAST (base_encoder); + GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder); + + /* Maximum sizes for common headers (in bytes) */ + enum + { + MAX_SEQ_HDR_SIZE = 140, + MAX_SEQ_EXT_SIZE = 10, + MAX_GOP_SIZE = 8, + MAX_PIC_HDR_SIZE = 10, + MAX_PIC_EXT_SIZE = 11, + MAX_SLICE_HDR_SIZE = 8, + }; + + if (!ensure_hw_profile (encoder)) + return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + + base_encoder->num_ref_frames = 2; + + /* Only YUV 4:2:0 formats are supported for now. This means that we + have a limit of 4608 bits per macroblock. */ + base_encoder->codedbuf_size = (GST_ROUND_UP_16 (vip->width) * + GST_ROUND_UP_16 (vip->height) / 256) * 576; + + /* Account for Sequence, GOP, and Picture headers */ + /* XXX: exclude unused Sequence Display Extension, Sequence Scalable + Extension, Quantization Matrix Extension, Picture Display Extension, + Picture Temporal Scalable Extension, Picture Spatial Scalable + Extension */ + base_encoder->codedbuf_size += MAX_SEQ_HDR_SIZE + MAX_SEQ_EXT_SIZE + + MAX_GOP_SIZE + MAX_PIC_HDR_SIZE + MAX_PIC_EXT_SIZE; + + /* Account for Slice headers. We use one slice per line of macroblock */ + base_encoder->codedbuf_size += (GST_ROUND_UP_16 (vip->height) / 16) * + MAX_SLICE_HDR_SIZE; + + base_encoder->context_info.profile = base_encoder->profile; + base_encoder->context_info.entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE; + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; +} + +static GstVaapiEncoderStatus +gst_vaapi_encoder_mpeg2_reconfigure (GstVaapiEncoder * base_encoder) +{ + GstVaapiEncoderMpeg2 *const encoder = + GST_VAAPI_ENCODER_MPEG2_CAST (base_encoder); + GstVaapiEncoderStatus status; + + if (encoder->ip_period > base_encoder->keyframe_period) { + encoder->ip_period = base_encoder->keyframe_period - 1; + } + + status = ensure_profile_and_level (encoder); + if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) + return status; + + if (!ensure_bitrate (encoder)) + goto error; + ensure_control_rate_params (encoder); + return set_context_info (base_encoder); + + /* ERRORS */ +error: + { + return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED; + } +} + +struct _GstVaapiEncoderMpeg2Class +{ + GstVaapiEncoderClass parent_class; +}; + +G_DEFINE_TYPE (GstVaapiEncoderMpeg2, gst_vaapi_encoder_mpeg2, + GST_TYPE_VAAPI_ENCODER); + +static void +gst_vaapi_encoder_mpeg2_init (GstVaapiEncoderMpeg2 * encoder) +{ + /* re-ordering */ + g_queue_init (&encoder->b_frames); +} + +static void +clear_ref (GstVaapiEncoderMpeg2 * encoder, GstVaapiSurfaceProxy ** ref) +{ + if (*ref) { + gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder), *ref); + *ref = NULL; + } +} + +static void +clear_references (GstVaapiEncoderMpeg2 * encoder) +{ + clear_ref (encoder, &encoder->forward); + clear_ref (encoder, &encoder->backward); +} + +static void +push_reference (GstVaapiEncoderMpeg2 * encoder, GstVaapiSurfaceProxy * ref) +{ + if (encoder->backward) { + clear_ref (encoder, &encoder->forward); + encoder->forward = encoder->backward; + encoder->backward = NULL; + } + if (encoder->forward) + encoder->backward = ref; + else + encoder->forward = ref; +} + +static void +gst_vaapi_encoder_mpeg2_finalize (GObject * object) +{ + /* free private buffers */ + GstVaapiEncoderMpeg2 *const encoder = GST_VAAPI_ENCODER_MPEG2 (object); + GstVaapiEncPicture *pic; + + clear_references (encoder); + + while (!g_queue_is_empty (&encoder->b_frames)) { + pic = g_queue_pop_head (&encoder->b_frames); + gst_vaapi_enc_picture_unref (pic); + } + g_queue_clear (&encoder->b_frames); + + G_OBJECT_CLASS (gst_vaapi_encoder_mpeg2_parent_class)->finalize (object); +} + +/** + * @ENCODER_MPEG2_PROP_RATECONTROL: Rate control (#GstVaapiRateControl). + * @ENCODER_MPEG2_PROP_TUNE: The tuning options (#GstVaapiEncoderTune). + * @ENCODER_MPEG2_PROP_QUANTIZER: Constant quantizer value (uint). + * @ENCODER_MPEG2_PROP_MAX_BFRAMES: Number of B-frames between I + * and P (uint). + * + * The set of MPEG-2 encoder specific configurable properties. + */ +enum +{ + ENCODER_MPEG2_PROP_RATECONTROL = 1, + ENCODER_MPEG2_PROP_TUNE, + ENCODER_MPEG2_PROP_QUANTIZER, + ENCODER_MPEG2_PROP_MAX_BFRAMES, + ENCODER_MPEG2_N_PROPERTIES +}; + +static GParamSpec *properties[ENCODER_MPEG2_N_PROPERTIES]; + +static void +gst_vaapi_encoder_mpeg2_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object); + GstVaapiEncoderMpeg2 *const encoder = GST_VAAPI_ENCODER_MPEG2 (object); + + if (base_encoder->num_codedbuf_queued > 0) { + GST_ERROR_OBJECT (object, + "failed to set any property after encoding started"); + return; + } + + switch (prop_id) { + case ENCODER_MPEG2_PROP_RATECONTROL: + gst_vaapi_encoder_set_rate_control (base_encoder, + g_value_get_enum (value)); + break; + case ENCODER_MPEG2_PROP_TUNE: + gst_vaapi_encoder_set_tuning (base_encoder, g_value_get_enum (value)); + break; + case ENCODER_MPEG2_PROP_QUANTIZER: + encoder->cqp = g_value_get_uint (value); + break; + case ENCODER_MPEG2_PROP_MAX_BFRAMES: + encoder->ip_period = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gst_vaapi_encoder_mpeg2_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstVaapiEncoderMpeg2 *const encoder = GST_VAAPI_ENCODER_MPEG2 (object); + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object); + + switch (prop_id) { + case ENCODER_MPEG2_PROP_RATECONTROL: + g_value_set_enum (value, base_encoder->rate_control); + break; + case ENCODER_MPEG2_PROP_TUNE: + g_value_set_enum (value, base_encoder->tune); + break; + case ENCODER_MPEG2_PROP_QUANTIZER: + g_value_set_uint (value, encoder->cqp); + break; + case ENCODER_MPEG2_PROP_MAX_BFRAMES: + g_value_set_uint (value, encoder->ip_period); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +GST_VAAPI_ENCODER_DEFINE_CLASS_DATA (MPEG2); + +static void +gst_vaapi_encoder_mpeg2_class_init (GstVaapiEncoderMpeg2Class * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstVaapiEncoderClass *const encoder_class = GST_VAAPI_ENCODER_CLASS (klass); + + encoder_class->class_data = &g_class_data; + encoder_class->reconfigure = gst_vaapi_encoder_mpeg2_reconfigure; + encoder_class->reordering = gst_vaapi_encoder_mpeg2_reordering; + encoder_class->encode = gst_vaapi_encoder_mpeg2_encode; + encoder_class->flush = gst_vaapi_encoder_mpeg2_flush; + + object_class->set_property = gst_vaapi_encoder_mpeg2_set_property; + object_class->get_property = gst_vaapi_encoder_mpeg2_get_property; + object_class->finalize = gst_vaapi_encoder_mpeg2_finalize; + + /** + * GstVaapiEncoderMpeg2:rate-control: + * + * The desired rate control mode, expressed as a #GstVaapiRateControl. + */ + properties[ENCODER_MPEG2_PROP_RATECONTROL] = + g_param_spec_enum ("rate-control", + "Rate Control", "Rate control mode", + g_class_data.rate_control_get_type (), + g_class_data.default_rate_control, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderMpeg2:tune: + * + * The desired encoder tuning option. + */ + properties[ENCODER_MPEG2_PROP_TUNE] = + g_param_spec_enum ("tune", + "Encoder Tuning", + "Encoder tuning option", + g_class_data.encoder_tune_get_type (), + g_class_data.default_encoder_tune, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + properties[ENCODER_MPEG2_PROP_QUANTIZER] = + g_param_spec_uint ("quantizer", + "Constant Quantizer", + "Constant quantizer (if rate-control mode is CQP)", + 2, 62, 8, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + properties[ENCODER_MPEG2_PROP_MAX_BFRAMES] = + g_param_spec_uint ("max-bframes", "Max B-Frames", + "Number of B-frames between I and P", 0, 16, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + g_object_class_install_properties (object_class, ENCODER_MPEG2_N_PROPERTIES, + properties); + + gst_type_mark_as_plugin_api (g_class_data.rate_control_get_type (), 0); + gst_type_mark_as_plugin_api (g_class_data.encoder_tune_get_type (), 0); +} + +/** + * gst_vaapi_encoder_mpeg2_new: + * @display: a #GstVaapiDisplay + * + * Creates a new #GstVaapiEncoder for MPEG-2 encoding. + * + * Return value: the newly allocated #GstVaapiEncoder object + */ +GstVaapiEncoder * +gst_vaapi_encoder_mpeg2_new (GstVaapiDisplay * display) +{ + return g_object_new (GST_TYPE_VAAPI_ENCODER_MPEG2, "display", display, NULL); +} + +static struct +{ + int code; + float value; +} frame_rate_tab[] = { + /* *INDENT-OFF* */ + { 1, 23.976 }, + { 2, 24.0 }, + { 3, 25.0 }, + { 4, 29.97 }, + { 5, 30 }, + { 6, 50 }, + { 7, 59.94 }, + { 8, 60 } + /* *INDENT-ON* */ +}; + +static int +find_frame_rate_code (const VAEncSequenceParameterBufferMPEG2 * seq_param) +{ + unsigned int ndelta, delta = -1; + int code = 1, i; + float frame_rate_value = seq_param->frame_rate * + (seq_param->sequence_extension.bits.frame_rate_extension_d + 1) / + (seq_param->sequence_extension.bits.frame_rate_extension_n + 1); + + for (i = 0; i < G_N_ELEMENTS (frame_rate_tab); i++) { + + ndelta = fabsf (1000 * frame_rate_tab[i].value - 1000 * frame_rate_value); + if (ndelta < delta) { + code = frame_rate_tab[i].code; + delta = ndelta; + } + } + return code; +} + +static gboolean +gst_bit_writer_write_sps (GstBitWriter * bitwriter, + const VAEncSequenceParameterBufferMPEG2 * seq_param) +{ + gst_bit_writer_put_bits_uint32 (bitwriter, START_CODE_SEQ, 32); + gst_bit_writer_put_bits_uint32 (bitwriter, seq_param->picture_width, 12); + gst_bit_writer_put_bits_uint32 (bitwriter, seq_param->picture_height, 12); + gst_bit_writer_put_bits_uint32 (bitwriter, + seq_param->aspect_ratio_information, 4); + gst_bit_writer_put_bits_uint32 (bitwriter, find_frame_rate_code (seq_param), 4); /* frame_rate_code */ + gst_bit_writer_put_bits_uint32 (bitwriter, (seq_param->bits_per_second + 399) / 400, 18); /* the low 18 bits of bit_rate */ + gst_bit_writer_put_bits_uint32 (bitwriter, 1, 1); /* marker_bit */ + gst_bit_writer_put_bits_uint32 (bitwriter, seq_param->vbv_buffer_size, 10); + gst_bit_writer_put_bits_uint32 (bitwriter, 0, 1); /* constraint_parameter_flag, always 0 for MPEG-2 */ + gst_bit_writer_put_bits_uint32 (bitwriter, 0, 1); /* load_intra_quantiser_matrix */ + gst_bit_writer_put_bits_uint32 (bitwriter, 0, 1); /* load_non_intra_quantiser_matrix */ + + gst_bit_writer_align_bytes (bitwriter, 0); + + gst_bit_writer_put_bits_uint32 (bitwriter, START_CODE_EXT, 32); + gst_bit_writer_put_bits_uint32 (bitwriter, 1, 4); /* sequence_extension id */ + gst_bit_writer_put_bits_uint32 (bitwriter, + seq_param->sequence_extension.bits.profile_and_level_indication, 8); + gst_bit_writer_put_bits_uint32 (bitwriter, + seq_param->sequence_extension.bits.progressive_sequence, 1); + gst_bit_writer_put_bits_uint32 (bitwriter, + seq_param->sequence_extension.bits.chroma_format, 2); + gst_bit_writer_put_bits_uint32 (bitwriter, seq_param->picture_width >> 12, 2); + gst_bit_writer_put_bits_uint32 (bitwriter, seq_param->picture_height >> 12, + 2); + gst_bit_writer_put_bits_uint32 (bitwriter, ((seq_param->bits_per_second + 399) / 400) >> 18, 12); /* bit_rate_extension */ + gst_bit_writer_put_bits_uint32 (bitwriter, 1, 1); /* marker_bit */ + gst_bit_writer_put_bits_uint32 (bitwriter, seq_param->vbv_buffer_size >> 10, + 8); + gst_bit_writer_put_bits_uint32 (bitwriter, + seq_param->sequence_extension.bits.low_delay, 1); + gst_bit_writer_put_bits_uint32 (bitwriter, + seq_param->sequence_extension.bits.frame_rate_extension_n, 2); + gst_bit_writer_put_bits_uint32 (bitwriter, + seq_param->sequence_extension.bits.frame_rate_extension_d, 5); + + gst_bit_writer_align_bytes (bitwriter, 0); + + /* gop header */ + gst_bit_writer_put_bits_uint32 (bitwriter, START_CODE_GOP, 32); + gst_bit_writer_put_bits_uint32 (bitwriter, + seq_param->gop_header.bits.time_code, 25); + gst_bit_writer_put_bits_uint32 (bitwriter, + seq_param->gop_header.bits.closed_gop, 1); + gst_bit_writer_put_bits_uint32 (bitwriter, + seq_param->gop_header.bits.broken_link, 1); + + gst_bit_writer_align_bytes (bitwriter, 0); + + return TRUE; +} + +static gboolean +gst_bit_writer_write_pps (GstBitWriter * bitwriter, + const VAEncPictureParameterBufferMPEG2 * pic_param) +{ + gst_bit_writer_put_bits_uint32 (bitwriter, START_CODE_PICUTRE, 32); + gst_bit_writer_put_bits_uint32 (bitwriter, pic_param->temporal_reference, 10); + gst_bit_writer_put_bits_uint32 (bitwriter, + pic_param->picture_type == VAEncPictureTypeIntra ? 1 : + pic_param->picture_type == VAEncPictureTypePredictive ? 2 : 3, 3); + gst_bit_writer_put_bits_uint32 (bitwriter, pic_param->vbv_delay, 16); + + if (pic_param->picture_type == VAEncPictureTypePredictive || + pic_param->picture_type == VAEncPictureTypeBidirectional) { + gst_bit_writer_put_bits_uint32 (bitwriter, 0, 1); /* full_pel_forward_vector, always 0 for MPEG-2 */ + gst_bit_writer_put_bits_uint32 (bitwriter, 7, 3); /* forward_f_code, always 7 for MPEG-2 */ + } + + if (pic_param->picture_type == VAEncPictureTypeBidirectional) { + gst_bit_writer_put_bits_uint32 (bitwriter, 0, 1); /* full_pel_backward_vector, always 0 for MPEG-2 */ + gst_bit_writer_put_bits_uint32 (bitwriter, 7, 3); /* backward_f_code, always 7 for MPEG-2 */ + } + + gst_bit_writer_put_bits_uint32 (bitwriter, 0, 1); /* extra_bit_picture, 0 */ + + gst_bit_writer_align_bytes (bitwriter, 0); + + gst_bit_writer_put_bits_uint32 (bitwriter, START_CODE_EXT, 32); + gst_bit_writer_put_bits_uint32 (bitwriter, 8, 4); /* Picture Coding Extension ID: 8 */ + gst_bit_writer_put_bits_uint32 (bitwriter, pic_param->f_code[0][0], 4); + gst_bit_writer_put_bits_uint32 (bitwriter, pic_param->f_code[0][1], 4); + gst_bit_writer_put_bits_uint32 (bitwriter, pic_param->f_code[1][0], 4); + gst_bit_writer_put_bits_uint32 (bitwriter, pic_param->f_code[1][1], 4); + + gst_bit_writer_put_bits_uint32 (bitwriter, + pic_param->picture_coding_extension.bits.intra_dc_precision, 2); + gst_bit_writer_put_bits_uint32 (bitwriter, + pic_param->picture_coding_extension.bits.picture_structure, 2); + gst_bit_writer_put_bits_uint32 (bitwriter, + pic_param->picture_coding_extension.bits.top_field_first, 1); + gst_bit_writer_put_bits_uint32 (bitwriter, + pic_param->picture_coding_extension.bits.frame_pred_frame_dct, 1); + gst_bit_writer_put_bits_uint32 (bitwriter, + pic_param->picture_coding_extension.bits.concealment_motion_vectors, 1); + gst_bit_writer_put_bits_uint32 (bitwriter, + pic_param->picture_coding_extension.bits.q_scale_type, 1); + gst_bit_writer_put_bits_uint32 (bitwriter, + pic_param->picture_coding_extension.bits.intra_vlc_format, 1); + gst_bit_writer_put_bits_uint32 (bitwriter, + pic_param->picture_coding_extension.bits.alternate_scan, 1); + gst_bit_writer_put_bits_uint32 (bitwriter, + pic_param->picture_coding_extension.bits.repeat_first_field, 1); + gst_bit_writer_put_bits_uint32 (bitwriter, 1, 1); /* always chroma 420 */ + gst_bit_writer_put_bits_uint32 (bitwriter, + pic_param->picture_coding_extension.bits.progressive_frame, 1); + gst_bit_writer_put_bits_uint32 (bitwriter, + pic_param->picture_coding_extension.bits.composite_display_flag, 1); + + gst_bit_writer_align_bytes (bitwriter, 0); + + return TRUE; +} diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.h b/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.h new file mode 100644 index 0000000000..a4384ef6e0 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.h @@ -0,0 +1,51 @@ +/* + * gstvaapiencoder_mpeg2.h - MPEG-2 encoder + * + * Copyright (C) 2011-2014 Intel Corporation + * Author: Guangxin Xu + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_ENCODER_MPEG2_H +#define GST_VAAPI_ENCODER_MPEG2_H + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_ENCODER_MPEG2 \ + (gst_vaapi_encoder_mpeg2_get_type ()) +#define GST_VAAPI_ENCODER_MPEG2(encoder) \ + (G_TYPE_CHECK_INSTANCE_CAST ((encoder), GST_TYPE_VAAPI_ENCODER_MPEG2, GstVaapiEncoderMpeg2)) +#define GST_IS_VAAPI_ENCODER_MPEG2(encoder) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((encoder), GST_TYPE_VAAPI_ENCODER_MPEG2)) + +typedef struct _GstVaapiEncoderMpeg2 GstVaapiEncoderMpeg2; +typedef struct _GstVaapiEncoderMpeg2Class GstVaapiEncoderMpeg2Class; + +GType +gst_vaapi_encoder_mpeg2_get_type (void) G_GNUC_CONST; + +GstVaapiEncoder * +gst_vaapi_encoder_mpeg2_new (GstVaapiDisplay * display); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiEncoderMpeg2, gst_object_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_ENCODER_MPEG2_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2_priv.h b/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2_priv.h new file mode 100644 index 0000000000..cded80d40d --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2_priv.h @@ -0,0 +1,66 @@ +/* + * gstvaapiencoder_mpeg2_priv.h - MPEG-2 encoder (private definitions) + * + * Copyright (C) 2013-2014 Intel Corporation + * Author: Guangxin Xu + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_ENCODER_MPEG2_PRIV_H +#define GST_VAAPI_ENCODER_MPEG2_PRIV_H + +#include "gstvaapiencoder_priv.h" +#include "gstvaapiutils_mpeg2.h" + +G_BEGIN_DECLS + +#define GST_VAAPI_ENCODER_MPEG2_CAST(encoder) \ + ((GstVaapiEncoderMpeg2 *) (encoder)) + +#define START_CODE_PICUTRE 0x00000100 +#define START_CODE_SLICE 0x00000101 +#define START_CODE_USER 0x000001B2 +#define START_CODE_SEQ 0x000001B3 +#define START_CODE_EXT 0x000001B5 +#define START_CODE_GOP 0x000001B8 + +struct _GstVaapiEncoderMpeg2 +{ + GstVaapiEncoder parent_instance; + + GstVaapiProfile profile; + GstVaapiLevelMPEG2 level; + guint8 profile_idc; + guint8 level_idc; + guint32 cqp; /* quantizer value for CQP mode */ + guint32 ip_period; + + /* re-ordering */ + GQueue b_frames; + gboolean dump_frames; + gboolean new_gop; + + /* reference list */ + GstVaapiSurfaceProxy *forward; + GstVaapiSurfaceProxy *backward; + guint32 frame_num; /* same value picture header, but it's not mod by 1024 */ +}; + +G_END_DECLS + +#endif /* GST_VAAPI_ENCODER_MPEG2_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_objects.c b/gst-libs/gst/vaapi/gstvaapiencoder_objects.c new file mode 100644 index 0000000000..af1cf61eb3 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder_objects.c @@ -0,0 +1,583 @@ +/* + * gstvaapiencoder_objects.c - VA encoder objects abstraction + * + * Copyright (C) 2013-2014 Intel Corporation + * Author: Wind Yuan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include "gstvaapiencoder_objects.h" +#include "gstvaapiencoder_priv.h" +#include "gstvaapisurfaceproxy_priv.h" +#include "gstvaapicompat.h" +#include "gstvaapiutils.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +#define GET_ENCODER(obj) GST_VAAPI_ENCODER_CAST((obj)->parent_instance.codec) +#define GET_VA_DISPLAY(obj) GET_ENCODER(obj)->va_display +#define GET_VA_CONTEXT(obj) GET_ENCODER(obj)->va_context + +/* ------------------------------------------------------------------------- */ +/* --- Encoder Packed Header --- */ +/* ------------------------------------------------------------------------- */ + +GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiEncPackedHeader, + gst_vaapi_enc_packed_header); + +void +gst_vaapi_enc_packed_header_destroy (GstVaapiEncPackedHeader * header) +{ + vaapi_destroy_buffer (GET_VA_DISPLAY (header), &header->param_id); + vaapi_destroy_buffer (GET_VA_DISPLAY (header), &header->data_id); + header->param = NULL; + header->data = NULL; +} + +gboolean +gst_vaapi_enc_packed_header_create (GstVaapiEncPackedHeader * header, + const GstVaapiCodecObjectConstructorArgs * args) +{ + gboolean success; + + header->param_id = VA_INVALID_ID; + header->data_id = VA_INVALID_ID; + + success = vaapi_create_buffer (GET_VA_DISPLAY (header), + GET_VA_CONTEXT (header), + VAEncPackedHeaderParameterBufferType, + args->param_size, args->param, &header->param_id, &header->param); + if (!success) + return FALSE; + + if (!args->data_size) + return TRUE; + + success = vaapi_create_buffer (GET_VA_DISPLAY (header), + GET_VA_CONTEXT (header), + VAEncPackedHeaderDataBufferType, + args->data_size, args->data, &header->data_id, &header->data); + if (!success) + return FALSE; + return TRUE; +} + +GstVaapiEncPackedHeader * +gst_vaapi_enc_packed_header_new (GstVaapiEncoder * encoder, + gconstpointer param, guint param_size, gconstpointer data, guint data_size) +{ + GstVaapiCodecObject *object; + + object = gst_vaapi_codec_object_new (&GstVaapiEncPackedHeaderClass, + GST_VAAPI_CODEC_BASE (encoder), param, param_size, data, data_size, 0); + return GST_VAAPI_ENC_PACKED_HEADER (object); +} + +gboolean +gst_vaapi_enc_packed_header_set_data (GstVaapiEncPackedHeader * header, + gconstpointer data, guint data_size) +{ + gboolean success; + + vaapi_destroy_buffer (GET_VA_DISPLAY (header), &header->data_id); + header->data = NULL; + + success = vaapi_create_buffer (GET_VA_DISPLAY (header), + GET_VA_CONTEXT (header), + VAEncPackedHeaderDataBufferType, + data_size, data, &header->data_id, &header->data); + if (!success) + return FALSE; + return TRUE; +} + +/* ------------------------------------------------------------------------- */ +/* --- Encoder Sequence --- */ +/* ------------------------------------------------------------------------- */ + +GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiEncSequence, gst_vaapi_enc_sequence); + +void +gst_vaapi_enc_sequence_destroy (GstVaapiEncSequence * sequence) +{ + vaapi_destroy_buffer (GET_VA_DISPLAY (sequence), &sequence->param_id); + sequence->param = NULL; +} + +gboolean +gst_vaapi_enc_sequence_create (GstVaapiEncSequence * sequence, + const GstVaapiCodecObjectConstructorArgs * args) +{ + gboolean success; + + sequence->param_id = VA_INVALID_ID; + success = vaapi_create_buffer (GET_VA_DISPLAY (sequence), + GET_VA_CONTEXT (sequence), + VAEncSequenceParameterBufferType, + args->param_size, args->param, &sequence->param_id, &sequence->param); + if (!success) + return FALSE; + return TRUE; +} + +GstVaapiEncSequence * +gst_vaapi_enc_sequence_new (GstVaapiEncoder * encoder, + gconstpointer param, guint param_size) +{ + GstVaapiCodecObject *object; + + object = gst_vaapi_codec_object_new (&GstVaapiEncSequenceClass, + GST_VAAPI_CODEC_BASE (encoder), param, param_size, NULL, 0, 0); + return GST_VAAPI_ENC_SEQUENCE (object); +} + +/* ------------------------------------------------------------------------- */ +/* --- Encoder Slice --- */ +/* ------------------------------------------------------------------------- */ + +GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiEncSlice, gst_vaapi_enc_slice); + +void +gst_vaapi_enc_slice_destroy (GstVaapiEncSlice * slice) +{ + if (slice->packed_headers) { + g_ptr_array_unref (slice->packed_headers); + slice->packed_headers = NULL; + } + + vaapi_destroy_buffer (GET_VA_DISPLAY (slice), &slice->param_id); + slice->param = NULL; +} + +gboolean +gst_vaapi_enc_slice_create (GstVaapiEncSlice * slice, + const GstVaapiCodecObjectConstructorArgs * args) +{ + gboolean success; + + slice->param_id = VA_INVALID_ID; + success = vaapi_create_buffer (GET_VA_DISPLAY (slice), + GET_VA_CONTEXT (slice), + VAEncSliceParameterBufferType, + args->param_size, args->param, &slice->param_id, &slice->param); + if (!success) + return FALSE; + + slice->packed_headers = g_ptr_array_new_with_free_func ((GDestroyNotify) + gst_vaapi_mini_object_unref); + if (!slice->packed_headers) + return FALSE; + + return TRUE; +} + +GstVaapiEncSlice * +gst_vaapi_enc_slice_new (GstVaapiEncoder * encoder, + gconstpointer param, guint param_size) +{ + GstVaapiCodecObject *object; + + object = gst_vaapi_codec_object_new (&GstVaapiEncSliceClass, + GST_VAAPI_CODEC_BASE (encoder), param, param_size, NULL, 0, 0); + return GST_VAAPI_ENC_SLICE (object); +} + +/* ------------------------------------------------------------------------- */ +/* --- Encoder Misc Parameter Buffer --- */ +/* ------------------------------------------------------------------------- */ + +GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiEncMiscParam, gst_vaapi_enc_misc_param); + +void +gst_vaapi_enc_misc_param_destroy (GstVaapiEncMiscParam * misc) +{ + vaapi_destroy_buffer (GET_VA_DISPLAY (misc), &misc->param_id); + misc->param = NULL; + misc->data = NULL; +} + +gboolean +gst_vaapi_enc_misc_param_create (GstVaapiEncMiscParam * misc, + const GstVaapiCodecObjectConstructorArgs * args) +{ + gboolean success; + + misc->param_id = VA_INVALID_ID; + success = vaapi_create_buffer (GET_VA_DISPLAY (misc), + GET_VA_CONTEXT (misc), + VAEncMiscParameterBufferType, + args->param_size, args->param, &misc->param_id, &misc->param); + if (!success) + return FALSE; + return TRUE; +} + +GstVaapiEncMiscParam * +gst_vaapi_enc_misc_param_new (GstVaapiEncoder * encoder, + VAEncMiscParameterType type, guint data_size) +{ + GstVaapiCodecObject *object; + GstVaapiEncMiscParam *misc; + VAEncMiscParameterBuffer *va_misc; + + object = gst_vaapi_codec_object_new (&GstVaapiEncMiscParamClass, + GST_VAAPI_CODEC_BASE (encoder), + NULL, sizeof (VAEncMiscParameterBuffer) + data_size, NULL, 0, 0); + if (!object) + return NULL; + + misc = GST_VAAPI_ENC_MISC_PARAM (object); + va_misc = misc->param; + va_misc->type = type; + misc->data = va_misc->data; + return misc; +} + +/* ------------------------------------------------------------------------- */ +/* --- Quantization Matrices --- */ +/* ------------------------------------------------------------------------- */ + +GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiEncQMatrix, gst_vaapi_enc_q_matrix); + +void +gst_vaapi_enc_q_matrix_destroy (GstVaapiEncQMatrix * q_matrix) +{ + vaapi_destroy_buffer (GET_VA_DISPLAY (q_matrix), &q_matrix->param_id); + q_matrix->param = NULL; +} + +gboolean +gst_vaapi_enc_q_matrix_create (GstVaapiEncQMatrix * q_matrix, + const GstVaapiCodecObjectConstructorArgs * args) +{ + q_matrix->param_id = VA_INVALID_ID; + return vaapi_create_buffer (GET_VA_DISPLAY (q_matrix), + GET_VA_CONTEXT (q_matrix), VAQMatrixBufferType, + args->param_size, args->param, &q_matrix->param_id, &q_matrix->param); +} + +GstVaapiEncQMatrix * +gst_vaapi_enc_q_matrix_new (GstVaapiEncoder * encoder, + gconstpointer param, guint param_size) +{ + GstVaapiCodecObject *object; + + object = gst_vaapi_codec_object_new (&GstVaapiEncQMatrixClass, + GST_VAAPI_CODEC_BASE (encoder), param, param_size, NULL, 0, 0); + if (!object) + return NULL; + return GST_VAAPI_ENC_Q_MATRIX_CAST (object); +} + +/* ------------------------------------------------------------------------- */ +/* --- JPEG Huffman Tables --- */ +/* ------------------------------------------------------------------------- */ + +GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiEncHuffmanTable, + gst_vaapi_enc_huffman_table); + +void +gst_vaapi_enc_huffman_table_destroy (GstVaapiEncHuffmanTable * huf_table) +{ + vaapi_destroy_buffer (GET_VA_DISPLAY (huf_table), &huf_table->param_id); + huf_table->param = NULL; +} + +gboolean +gst_vaapi_enc_huffman_table_create (GstVaapiEncHuffmanTable * huf_table, + const GstVaapiCodecObjectConstructorArgs * args) +{ + huf_table->param_id = VA_INVALID_ID; + return vaapi_create_buffer (GET_VA_DISPLAY (huf_table), + GET_VA_CONTEXT (huf_table), VAHuffmanTableBufferType, args->param_size, + args->param, &huf_table->param_id, (void **) &huf_table->param); +} + +GstVaapiEncHuffmanTable * +gst_vaapi_enc_huffman_table_new (GstVaapiEncoder * encoder, + guint8 * data, guint data_size) +{ + GstVaapiCodecObject *object; + + object = gst_vaapi_codec_object_new (&GstVaapiEncHuffmanTableClass, + GST_VAAPI_CODEC_BASE (encoder), data, data_size, NULL, 0, 0); + if (!object) + return NULL; + return GST_VAAPI_ENC_HUFFMAN_TABLE_CAST (object); +} + +/* ------------------------------------------------------------------------- */ +/* --- Encoder Picture --- */ +/* ------------------------------------------------------------------------- */ + +GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiEncPicture, gst_vaapi_enc_picture); + +void +gst_vaapi_enc_picture_destroy (GstVaapiEncPicture * picture) +{ + if (picture->packed_headers) { + g_ptr_array_unref (picture->packed_headers); + picture->packed_headers = NULL; + } + if (picture->misc_params) { + g_ptr_array_unref (picture->misc_params); + picture->misc_params = NULL; + } + if (picture->slices) { + g_ptr_array_unref (picture->slices); + picture->slices = NULL; + } + + gst_vaapi_codec_object_replace (&picture->q_matrix, NULL); + gst_vaapi_codec_object_replace (&picture->huf_table, NULL); + + gst_vaapi_codec_object_replace (&picture->sequence, NULL); + + gst_vaapi_surface_proxy_replace (&picture->proxy, NULL); + picture->surface_id = VA_INVALID_ID; + picture->surface = NULL; + + vaapi_destroy_buffer (GET_VA_DISPLAY (picture), &picture->param_id); + picture->param = NULL; + + if (picture->frame) { + gst_video_codec_frame_unref (picture->frame); + picture->frame = NULL; + } +} + +gboolean +gst_vaapi_enc_picture_create (GstVaapiEncPicture * picture, + const GstVaapiCodecObjectConstructorArgs * args) +{ + GstVideoCodecFrame *const frame = (GstVideoCodecFrame *) args->data; + gboolean success; + + picture->proxy = gst_video_codec_frame_get_user_data (frame); + if (!gst_vaapi_surface_proxy_ref (picture->proxy)) + return FALSE; + + picture->surface = GST_VAAPI_SURFACE_PROXY_SURFACE (picture->proxy); + if (!picture->surface) + return FALSE; + + picture->surface_id = GST_VAAPI_SURFACE_ID (picture->surface); + if (picture->surface_id == VA_INVALID_ID) + return FALSE; + + picture->type = GST_VAAPI_PICTURE_TYPE_NONE; + picture->pts = GST_CLOCK_TIME_NONE; + picture->frame_num = 0; + picture->poc = 0; + + picture->param_id = VA_INVALID_ID; + picture->param_size = args->param_size; + success = vaapi_create_buffer (GET_VA_DISPLAY (picture), + GET_VA_CONTEXT (picture), + VAEncPictureParameterBufferType, + args->param_size, args->param, &picture->param_id, &picture->param); + if (!success) + return FALSE; + picture->param_size = args->param_size; + + picture->packed_headers = g_ptr_array_new_with_free_func ((GDestroyNotify) + gst_vaapi_mini_object_unref); + if (!picture->packed_headers) + return FALSE; + + picture->misc_params = g_ptr_array_new_with_free_func ((GDestroyNotify) + gst_vaapi_mini_object_unref); + if (!picture->misc_params) + return FALSE; + + picture->slices = g_ptr_array_new_with_free_func ((GDestroyNotify) + gst_vaapi_mini_object_unref); + if (!picture->slices) + return FALSE; + + picture->frame = gst_video_codec_frame_ref (frame); + return TRUE; +} + +GstVaapiEncPicture * +gst_vaapi_enc_picture_new (GstVaapiEncoder * encoder, + gconstpointer param, guint param_size, GstVideoCodecFrame * frame) +{ + GstVaapiCodecObject *object; + + g_return_val_if_fail (frame != NULL, NULL); + + object = gst_vaapi_codec_object_new (&GstVaapiEncPictureClass, + GST_VAAPI_CODEC_BASE (encoder), param, param_size, frame, 0, 0); + return GST_VAAPI_ENC_PICTURE (object); +} + +void +gst_vaapi_enc_picture_set_sequence (GstVaapiEncPicture * picture, + GstVaapiEncSequence * sequence) +{ + g_return_if_fail (picture != NULL); + g_return_if_fail (sequence != NULL); + + gst_vaapi_codec_object_replace (&picture->sequence, sequence); +} + +void +gst_vaapi_enc_picture_add_packed_header (GstVaapiEncPicture * picture, + GstVaapiEncPackedHeader * header) +{ + g_return_if_fail (picture != NULL); + g_return_if_fail (header != NULL); + + g_ptr_array_add (picture->packed_headers, + gst_vaapi_codec_object_ref (header)); +} + +void +gst_vaapi_enc_picture_add_misc_param (GstVaapiEncPicture * picture, + GstVaapiEncMiscParam * misc) +{ + g_return_if_fail (picture != NULL); + g_return_if_fail (misc != NULL); + + g_ptr_array_add (picture->misc_params, gst_vaapi_codec_object_ref (misc)); +} + +void +gst_vaapi_enc_picture_add_slice (GstVaapiEncPicture * picture, + GstVaapiEncSlice * slice) +{ + g_return_if_fail (picture != NULL); + g_return_if_fail (slice != NULL); + + g_ptr_array_add (picture->slices, gst_vaapi_codec_object_ref (slice)); +} + +void +gst_vaapi_enc_slice_add_packed_header (GstVaapiEncSlice * slice, + GstVaapiEncPackedHeader * header) +{ + g_return_if_fail (slice != NULL); + g_return_if_fail (header != NULL); + + g_ptr_array_add (slice->packed_headers, gst_vaapi_codec_object_ref (header)); +} + +static gboolean +do_encode (VADisplay dpy, VAContextID ctx, VABufferID * buf_id, void **buf_ptr) +{ + VAStatus status; + + vaapi_unmap_buffer (dpy, *buf_id, buf_ptr); + + status = vaRenderPicture (dpy, ctx, buf_id, 1); + if (!vaapi_check_status (status, "vaRenderPicture()")) + return FALSE; + + /* XXX: vaRenderPicture() is meant to destroy the VA buffer implicitly */ + vaapi_destroy_buffer (dpy, buf_id); + return TRUE; +} + +gboolean +gst_vaapi_enc_picture_encode (GstVaapiEncPicture * picture) +{ + GstVaapiEncSequence *sequence; + GstVaapiEncQMatrix *q_matrix; + GstVaapiEncHuffmanTable *huf_table; + VADisplay va_display; + VAContextID va_context; + VAStatus status; + guint i; + + g_return_val_if_fail (picture != NULL, FALSE); + g_return_val_if_fail (picture->surface_id != VA_INVALID_SURFACE, FALSE); + + va_display = GET_VA_DISPLAY (picture); + va_context = GET_VA_CONTEXT (picture); + + GST_DEBUG ("encode picture 0x%08x", picture->surface_id); + + status = vaBeginPicture (va_display, va_context, picture->surface_id); + if (!vaapi_check_status (status, "vaBeginPicture()")) + return FALSE; + + /* Submit Sequence parameter */ + sequence = picture->sequence; + if (sequence && !do_encode (va_display, va_context, + &sequence->param_id, &sequence->param)) + return FALSE; + + /* Submit Quantization matrix */ + q_matrix = picture->q_matrix; + if (q_matrix && !do_encode (va_display, va_context, + &q_matrix->param_id, &q_matrix->param)) + return FALSE; + + /* Submit huffman table */ + huf_table = picture->huf_table; + if (huf_table && !do_encode (va_display, va_context, + &huf_table->param_id, (void **) &huf_table->param)) + return FALSE; + + /* Submit Packed Headers */ + for (i = 0; i < picture->packed_headers->len; i++) { + GstVaapiEncPackedHeader *const header = + g_ptr_array_index (picture->packed_headers, i); + if (!do_encode (va_display, va_context, + &header->param_id, &header->param) || + !do_encode (va_display, va_context, &header->data_id, &header->data)) + return FALSE; + } + + /* Submit Picture parameter */ + if (!do_encode (va_display, va_context, &picture->param_id, &picture->param)) + return FALSE; + + /* Submit Misc Params */ + for (i = 0; i < picture->misc_params->len; i++) { + GstVaapiEncMiscParam *const misc = + g_ptr_array_index (picture->misc_params, i); + if (!do_encode (va_display, va_context, &misc->param_id, &misc->param)) + return FALSE; + } + + /* Submit Slice parameters */ + for (i = 0; i < picture->slices->len; i++) { + GstVaapiEncSlice *const slice = g_ptr_array_index (picture->slices, i); + guint j; + + /* Submit packed_slice_header and packed_raw_data */ + for (j = 0; j < slice->packed_headers->len; j++) { + GstVaapiEncPackedHeader *const header = + g_ptr_array_index (slice->packed_headers, j); + if (!do_encode (va_display, va_context, + &header->param_id, &header->param) || + !do_encode (va_display, va_context, &header->data_id, &header->data)) + return FALSE; + } + if (!do_encode (va_display, va_context, &slice->param_id, &slice->param)) + return FALSE; + } + + status = vaEndPicture (va_display, va_context); + if (!vaapi_check_status (status, "vaEndPicture()")) + return FALSE; + return TRUE; +} diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_objects.h b/gst-libs/gst/vaapi/gstvaapiencoder_objects.h new file mode 100644 index 0000000000..49f271dcd9 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder_objects.h @@ -0,0 +1,362 @@ +/* + * gstvaapiencoder_objects.h - VA encoder objects abstraction + * + * Copyright (C) 2013-2014 Intel Corporation + * Author: Wind Yuan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_ENCODER_OBJECTS_H +#define GST_VAAPI_ENCODER_OBJECTS_H + +#include +#include +#include + +G_BEGIN_DECLS + +typedef struct _GstVaapiEncPicture GstVaapiEncPicture; +typedef struct _GstVaapiEncSequence GstVaapiEncSequence; +typedef struct _GstVaapiEncMiscParam GstVaapiEncMiscParam; +typedef struct _GstVaapiEncSlice GstVaapiEncSlice; +typedef struct _GstVaapiEncQMatrix GstVaapiEncQMatrix; +typedef struct _GstVaapiEncHuffmanTable GstVaapiEncHuffmanTable; +typedef struct _GstVaapiEncPackedHeader GstVaapiEncPackedHeader; + +/* ------------------------------------------------------------------------- */ +/* --- Encoder Packed Header --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_ENC_PACKED_HEADER(obj) \ + ((GstVaapiEncPackedHeader *) (obj)) + +/** + * GstVaapiEncPackedHeader: + * + * A #GstVaapiCodecObject holding a packed header (param/data) for the + * encoder. + */ +struct _GstVaapiEncPackedHeader +{ + /*< private >*/ + GstVaapiCodecObject parent_instance; + + /*< public >*/ + VABufferID param_id; + gpointer param; + VABufferID data_id; + gpointer data; +}; + +G_GNUC_INTERNAL +GstVaapiEncPackedHeader * +gst_vaapi_enc_packed_header_new (GstVaapiEncoder * encoder, + gconstpointer param, guint param_size, gconstpointer data, guint data_size); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_enc_packed_header_set_data (GstVaapiEncPackedHeader * header, + gconstpointer data, guint data_size); + +/* ------------------------------------------------------------------------- */ +/* --- Encoder Sequence --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_ENC_SEQUENCE(obj) \ + ((GstVaapiEncSequence *) (obj)) + +/** + * GstVaapiEncSequence: + * + * A #GstVaapiCodecObject holding a sequence parameter for encoding. + */ +struct _GstVaapiEncSequence +{ + /*< private >*/ + GstVaapiCodecObject parent_instance; + + /*< public >*/ + VABufferID param_id; + gpointer param; +}; + +G_GNUC_INTERNAL +GstVaapiEncSequence * +gst_vaapi_enc_sequence_new (GstVaapiEncoder * encoder, + gconstpointer param, guint param_size); + +/* ------------------------------------------------------------------------- */ +/* --- Encoder Slice --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_ENC_SLICE(obj) \ + ((GstVaapiEncSlice *) (obj)) + +/** + * GstVaapiEncSlice: + * + * A #GstVaapiCodecObject holding a slice parameter used for encoding. + */ +struct _GstVaapiEncSlice +{ + /*< private >*/ + GstVaapiCodecObject parent_instance; + + /*< public >*/ + VABufferID param_id; + gpointer param; + GPtrArray *packed_headers; +}; + +G_GNUC_INTERNAL +GstVaapiEncSlice * +gst_vaapi_enc_slice_new (GstVaapiEncoder * encoder, + gconstpointer param, guint param_size); + +/* ------------------------------------------------------------------------- */ +/* --- Encoder Misc Parameter Buffer --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_ENC_MISC_PARAM(obj) \ + ((GstVaapiEncMiscParam *) (obj)) + +/** + * GstVaapiEncMiscParam: + * + * A #GstVaapiCodecObject holding a misc parameter and associated data + * used for controlling the encoder dynamically. + */ +struct _GstVaapiEncMiscParam +{ + /*< private >*/ + GstVaapiCodecObject parent_instance; + gpointer param; + + /*< public >*/ + VABufferID param_id; + gpointer data; +}; + +G_GNUC_INTERNAL +GstVaapiEncMiscParam * +gst_vaapi_enc_misc_param_new (GstVaapiEncoder * encoder, + VAEncMiscParameterType type, guint data_size); + +/* ------------------------------------------------------------------------- */ +/* --- Quantization Matrices --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_ENC_Q_MATRIX_CAST(obj) \ + ((GstVaapiEncQMatrix *) (obj)) + +/** + * GstVaapiEncQMatrix: + * + * A #GstVaapiCodecObject holding a quantization matrix parameter. + */ +struct _GstVaapiEncQMatrix +{ + /*< private >*/ + GstVaapiCodecObject parent_instance; + VABufferID param_id; + + /*< public >*/ + gpointer param; +}; + +G_GNUC_INTERNAL +GstVaapiEncQMatrix * +gst_vaapi_enc_q_matrix_new (GstVaapiEncoder * encoder, gconstpointer param, + guint param_size); + +/* ------------------------------------------------------------------------- */ +/* --- JPEG Huffman Tables --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_ENC_HUFFMAN_TABLE_CAST(obj) \ + ((GstVaapiEncHuffmanTable *) (obj)) + +/** + * GstVaapiEncHuffmanTable: + * + * A #GstVaapiCodecObject holding huffman table. + */ +struct _GstVaapiEncHuffmanTable +{ + /*< private >*/ + GstVaapiCodecObject parent_instance; + VABufferID param_id; + + /*< public >*/ + gpointer param; +}; + +G_GNUC_INTERNAL +GstVaapiEncHuffmanTable * +gst_vaapi_enc_huffman_table_new (GstVaapiEncoder * encoder, guint8 * data, + guint data_size); + +/* ------------------------------------------------------------------------- */ +/* --- Encoder Picture --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_ENC_PICTURE(obj) \ + ((GstVaapiEncPicture *) (obj)) + +typedef enum +{ + GST_VAAPI_ENC_PICTURE_FLAG_IDR = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 0), + GST_VAAPI_ENC_PICTURE_FLAG_REFERENCE = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 1), + GST_VAAPI_ENC_PICTURE_FLAG_LAST = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 2), +} GstVaapiEncPictureFlags; + +#define GST_VAAPI_ENC_PICTURE_FLAGS GST_VAAPI_MINI_OBJECT_FLAGS +#define GST_VAAPI_ENC_PICTURE_FLAG_IS_SET GST_VAAPI_MINI_OBJECT_FLAG_IS_SET +#define GST_VAAPI_ENC_PICTURE_FLAG_SET GST_VAAPI_MINI_OBJECT_FLAG_SET +#define GST_VAAPI_ENC_PICTURE_FLAG_UNSET GST_VAAPI_MINI_OBJECT_FLAG_UNSET + +#define GST_VAAPI_ENC_PICTURE_IS_IDR(picture) \ + GST_VAAPI_ENC_PICTURE_FLAG_IS_SET(picture, GST_VAAPI_ENC_PICTURE_FLAG_IDR) + +#define GST_VAAPI_ENC_PICTURE_IS_REFRENCE(picture) \ + GST_VAAPI_ENC_PICTURE_FLAG_IS_SET(picture, GST_VAAPI_ENC_PICTURE_FLAG_REFERENCE) + +/** + * GstVaapiEncPicture: + * + * A #GstVaapiCodecObject holding a picture parameter for encoding. + */ +struct _GstVaapiEncPicture +{ + /*< private >*/ + GstVaapiCodecObject parent_instance; + GstVideoCodecFrame *frame; + GstVaapiSurfaceProxy *proxy; + GstVaapiSurface *surface; + VABufferID param_id; + guint param_size; + + /* Additional data to pass down */ + GstVaapiEncSequence *sequence; + GPtrArray *packed_headers; + GPtrArray *misc_params; + + /*< public >*/ + GstVaapiPictureType type; + VASurfaceID surface_id; + gpointer param; + GPtrArray *slices; + GstVaapiEncQMatrix *q_matrix; + GstVaapiEncHuffmanTable *huf_table; + GstClockTime pts; + guint frame_num; + guint poc; + guint temporal_id; + gboolean has_roi; +}; + +G_GNUC_INTERNAL +GstVaapiEncPicture * +gst_vaapi_enc_picture_new (GstVaapiEncoder * encoder, + gconstpointer param, guint param_size, GstVideoCodecFrame * frame); + +G_GNUC_INTERNAL +void +gst_vaapi_enc_picture_set_sequence (GstVaapiEncPicture * picture, + GstVaapiEncSequence * sequence); + +G_GNUC_INTERNAL +void +gst_vaapi_enc_picture_add_packed_header (GstVaapiEncPicture * picture, + GstVaapiEncPackedHeader * header); + +G_GNUC_INTERNAL +void +gst_vaapi_enc_picture_add_misc_param (GstVaapiEncPicture * picture, + GstVaapiEncMiscParam * misc); + +G_GNUC_INTERNAL +void +gst_vaapi_enc_picture_add_slice (GstVaapiEncPicture * picture, + GstVaapiEncSlice * slice); + +G_GNUC_INTERNAL +void +gst_vaapi_enc_slice_add_packed_header (GstVaapiEncSlice *slice, + GstVaapiEncPackedHeader * header); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_enc_picture_encode (GstVaapiEncPicture * picture); + +#define gst_vaapi_enc_picture_ref(picture) \ + gst_vaapi_codec_object_ref (picture) +#define gst_vaapi_enc_picture_unref(picture) \ + gst_vaapi_codec_object_unref (picture) +#define gst_vaapi_enc_picture_replace(old_picture_ptr, new_picture) \ + gst_vaapi_codec_object_replace (old_picture_ptr, new_picture) + +/* ------------------------------------------------------------------------- */ +/* --- Helpers to create codec-dependent objects --- */ +/* ------------------------------------------------------------------------- */ + +/* GstVaapiEncSequence */ +#define GST_VAAPI_ENC_SEQUENCE_NEW(codec, encoder) \ + gst_vaapi_enc_sequence_new (GST_VAAPI_ENCODER_CAST (encoder), \ + NULL, sizeof (G_PASTE (VAEncSequenceParameterBuffer, codec))) + +/* GstVaapiEncMiscParam */ +#define GST_VAAPI_ENC_MISC_PARAM_NEW(type, encoder) \ + gst_vaapi_enc_misc_param_new (GST_VAAPI_ENCODER_CAST (encoder), \ + G_PASTE (VAEncMiscParameterType, type), \ + sizeof (G_PASTE (VAEncMiscParameter, type))) + +/* GstVaapiEncQualityLevelMiscParam */ +#define GST_VAAPI_ENC_QUALITY_LEVEL_MISC_PARAM_NEW(encoder) \ + gst_vaapi_enc_misc_param_new (GST_VAAPI_ENCODER_CAST (encoder), \ + VAEncMiscParameterTypeQualityLevel, \ + sizeof (VAEncMiscParameterBufferQualityLevel)) + +/* GstVaapiEncQuantizationMiscParam */ +#define GST_VAAPI_ENC_QUANTIZATION_MISC_PARAM_NEW(encoder) \ + gst_vaapi_enc_misc_param_new (GST_VAAPI_ENCODER_CAST (encoder), \ + VAEncMiscParameterTypeQuantization, \ + sizeof (VAEncMiscParameterQuantization)) + +/* GstVaapiEncPicture */ +#define GST_VAAPI_ENC_PICTURE_NEW(codec, encoder, frame) \ + gst_vaapi_enc_picture_new (GST_VAAPI_ENCODER_CAST (encoder), \ + NULL, sizeof (G_PASTE (VAEncPictureParameterBuffer, codec)), frame) + +/* GstVaapiEncSlice */ +#define GST_VAAPI_ENC_SLICE_NEW(codec, encoder) \ + gst_vaapi_enc_slice_new (GST_VAAPI_ENCODER_CAST (encoder), \ + NULL, sizeof(G_PASTE (VAEncSliceParameterBuffer, codec))) + +/* GstVaapiEncQuantMatrix */ +#define GST_VAAPI_ENC_Q_MATRIX_NEW(codec, encoder) \ + gst_vaapi_enc_q_matrix_new (GST_VAAPI_ENCODER_CAST (encoder), \ + NULL, sizeof (G_PASTE (VAQMatrixBuffer, codec))) + +/* GstVaapiEncHuffmanTable */ +#define GST_VAAPI_ENC_HUFFMAN_TABLE_NEW(codec, encoder) \ + gst_vaapi_enc_huffman_table_new (GST_VAAPI_ENCODER_CAST (encoder), \ + NULL, sizeof (G_PASTE (VAHuffmanTableBuffer, codec))) + +G_END_DECLS + +#endif /* GST_VAAPI_ENCODER_OBJECTS_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_priv.h b/gst-libs/gst/vaapi/gstvaapiencoder_priv.h new file mode 100644 index 0000000000..189c3791a7 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder_priv.h @@ -0,0 +1,394 @@ +/* + * gstvaapiencoder_priv.h - VA encoder abstraction (private definitions) + * + * Copyright (C) 2013-2014 Intel Corporation + * Author: Wind Yuan + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_ENCODER_PRIV_H +#define GST_VAAPI_ENCODER_PRIV_H + +#include +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_ENCODER_CAST(encoder) \ + ((GstVaapiEncoder *)(encoder)) + +#define GST_VAAPI_ENCODER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPI_ENCODER, GstVaapiEncoderClass)) + +#define GST_VAAPI_ENCODER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_ENCODER, GstVaapiEncoderClass)) + +/** + * GST_VAAPI_ENCODER_PACKED_HEADERS: + * @encoder: a #GstVaapiEncoder + * + * Macro that evaluates to the required set of VA packed headers that + * need to be submitted along with the corresponding param buffers. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_ENCODER_PACKED_HEADERS +#define GST_VAAPI_ENCODER_PACKED_HEADERS(encoder) \ + GST_VAAPI_ENCODER_CAST(encoder)->packed_headers + +/** + * GST_VAAPI_ENCODER_DISPLAY: + * @encoder: a #GstVaapiEncoder + * + * Macro that evaluates to the #GstVaapiDisplay of @encoder. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_ENCODER_DISPLAY +#define GST_VAAPI_ENCODER_DISPLAY(encoder) \ + GST_VAAPI_ENCODER_CAST(encoder)->display + +/** + * GST_VAAPI_ENCODER_CONTEXT: + * @encoder: a #GstVaapiEncoder + * + * Macro that evaluates to the #GstVaapiContext of @encoder. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_ENCODER_CONTEXT +#define GST_VAAPI_ENCODER_CONTEXT(encoder) \ + GST_VAAPI_ENCODER_CAST(encoder)->context + +/** + * GST_VAAPI_ENCODER_VIDEO_INFO: + * @encoder: a #GstVaapiEncoder + * + * Macro that evaluates to the #GstVideoInfo of @encoder. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_ENCODER_VIDEO_INFO +#define GST_VAAPI_ENCODER_VIDEO_INFO(encoder) \ + (&GST_VAAPI_ENCODER_CAST (encoder)->video_info) + +/** + * GST_VAAPI_ENCODER_WIDTH: + * @encoder: a #GstVaapiEncoder + * + * Macro that evaluates to the coded width of the picture. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_ENCODER_WIDTH +#define GST_VAAPI_ENCODER_WIDTH(encoder) \ + (GST_VAAPI_ENCODER_VIDEO_INFO (encoder)->width) + +/** + * GST_VAAPI_ENCODER_HEIGHT: + * @encoder: a #GstVaapiEncoder + * + * Macro that evaluates to the coded height of the picture. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_ENCODER_HEIGHT +#define GST_VAAPI_ENCODER_HEIGHT(encoder) \ + (GST_VAAPI_ENCODER_VIDEO_INFO (encoder)->height) + +/** + * GST_VAAPI_ENCODER_FPS_N: + * @encoder: a #GstVaapiEncoder + * + * Macro that evaluates to the coded framerate numerator. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_ENCODER_FPS_N +#define GST_VAAPI_ENCODER_FPS_N(encoder) \ + (GST_VAAPI_ENCODER_VIDEO_INFO (encoder)->fps_n) + +/** + * GST_VAAPI_ENCODER_FPS_D: + * @encoder: a #GstVaapiEncoder + * + * Macro that evaluates to the coded framerate denominator. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_ENCODER_FPS_D +#define GST_VAAPI_ENCODER_FPS_D(encoder) \ + (GST_VAAPI_ENCODER_VIDEO_INFO (encoder)->fps_d) + +/** + * GST_VAAPI_ENCODER_RATE_CONTROL: + * @encoder: a #GstVaapiEncoder + * + * Macro that evaluates to the rate control. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_ENCODER_RATE_CONTROL +#define GST_VAAPI_ENCODER_RATE_CONTROL(encoder) \ + (GST_VAAPI_ENCODER_CAST (encoder)->rate_control) + +/** + * GST_VAAPI_ENCODER_KEYFRAME_PERIOD: + * @encoder: a #GstVaapiEncoder + * + * Macro that evaluates to the keyframe period. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_ENCODER_KEYFRAME_PERIOD +#define GST_VAAPI_ENCODER_KEYFRAME_PERIOD(encoder) \ + (GST_VAAPI_ENCODER_CAST (encoder)->keyframe_period) + +/** + * GST_VAAPI_ENCODER_TUNE: + * @encoder: a #GstVaapiEncoder + * + * Macro that evaluates to the tuning option. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_ENCODER_TUNE +#define GST_VAAPI_ENCODER_TUNE(encoder) \ + (GST_VAAPI_ENCODER_CAST (encoder)->tune) + +/** + * GST_VAAPI_ENCODER_QUALITY_LEVEL: + * @encoder: a #GstVaapiEncoder + * + * Macro that evaluates to the quality level + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_ENCODER_QUALITY_LEVEL +#define GST_VAAPI_ENCODER_QUALITY_LEVEL(encoder) \ + (GST_VAAPI_ENCODER_CAST (encoder)->va_quality_level.quality_level) + +/** + * GST_VAAPI_ENCODER_VA_RATE_CONTROL: + * @encoder: a #GstVaapiEncoder + * + * Macro that evaluates to #VAEncMiscParameterRateControl + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_ENCODER_VA_RATE_CONTROL +#define GST_VAAPI_ENCODER_VA_RATE_CONTROL(encoder) \ + (GST_VAAPI_ENCODER_CAST (encoder)->va_ratecontrol) + +/** + * GST_VAAPI_ENCODER_VA_FRAME_RATE: + * @encoder: a #GstVaapiEncoder + * + * Macro that evaluates to #VAEncMiscParameterFrameRate + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_ENCODER_VA_FRAME_RATE +#define GST_VAAPI_ENCODER_VA_FRAME_RATE(encoder) \ + (GST_VAAPI_ENCODER_CAST (encoder)->va_framerate) + +/** + * GST_VAAPI_ENCODER_VA_HRD: + * @encoder: a #GstVaapiEncoder + * + * Macro that evaluates to #VAEncMiscParameterHRD + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_ENCODER_VA_HRD +#define GST_VAAPI_ENCODER_VA_HRD(encoder) \ + (GST_VAAPI_ENCODER_CAST (encoder)->va_hrd) + +/* Generate a mask for the supplied tuning option (internal) */ +#define GST_VAAPI_ENCODER_TUNE_MASK(TUNE) \ + (1U << G_PASTE (GST_VAAPI_ENCODER_TUNE_, TUNE)) + +#define GST_VAAPI_TYPE_ENCODER_TUNE \ + (gst_vaapi_encoder_tune_get_type ()) + +#define GST_VAAPI_TYPE_ENCODER_MBBRC \ + (gst_vaapi_encoder_mbbrc_get_type ()) + +typedef struct _GstVaapiEncoderClass GstVaapiEncoderClass; +typedef struct _GstVaapiEncoderClassData GstVaapiEncoderClassData; + +struct _GstVaapiEncoder +{ + /*< private >*/ + GstObject parent_instance; + + GPtrArray *properties; + GstVaapiDisplay *display; + GstVaapiContext *context; + GstVaapiContextInfo context_info; + GstVaapiEncoderTune tune; + guint packed_headers; + + VADisplay va_display; + VAContextID va_context; + GstVideoInfo video_info; + GstVaapiProfile profile; + guint num_ref_frames; + GstVaapiRateControl rate_control; + guint32 rate_control_mask; + guint bitrate; /* kbps */ + guint target_percentage; + guint keyframe_period; + + /* Maximum number of reference frames supported + * for the reference picture list 0 and list 2 */ + guint max_num_ref_frames_0; + guint max_num_ref_frames_1; + + /* parameters */ + VAEncMiscParameterBufferQualityLevel va_quality_level; + + GMutex mutex; + GCond surface_free; + GCond codedbuf_free; + guint codedbuf_size; + GstVaapiVideoPool *codedbuf_pool; + GAsyncQueue *codedbuf_queue; + guint32 num_codedbuf_queued; + + guint got_packed_headers:1; + guint got_rate_control_mask:1; + + /* miscellaneous buffer parameters */ + VAEncMiscParameterRateControl va_ratecontrol; + VAEncMiscParameterFrameRate va_framerate; + VAEncMiscParameterHRD va_hrd; + + gint8 default_roi_value; + + /* trellis quantization */ + gboolean trellis; +}; + +struct _GstVaapiEncoderClassData +{ + /*< private >*/ + GstVaapiCodec codec; + guint32 packed_headers; + + GType (*rate_control_get_type)(void); + GstVaapiRateControl default_rate_control; + guint32 rate_control_mask; + + GType (*encoder_tune_get_type)(void); + GstVaapiEncoderTune default_encoder_tune; + guint32 encoder_tune_mask; +}; + +#define GST_VAAPI_ENCODER_DEFINE_CLASS_DATA(CODEC) \ + GST_VAAPI_TYPE_DEFINE_ENUM_SUBSET_FROM_MASK( \ + G_PASTE (GstVaapiRateControl, CODEC), \ + G_PASTE (gst_vaapi_rate_control_, CODEC), \ + GST_VAAPI_TYPE_RATE_CONTROL, SUPPORTED_RATECONTROLS); \ + \ + GST_VAAPI_TYPE_DEFINE_ENUM_SUBSET_FROM_MASK( \ + G_PASTE (GstVaapiEncoderTune, CODEC), \ + G_PASTE (gst_vaapi_encoder_tune_, CODEC), \ + GST_VAAPI_TYPE_ENCODER_TUNE, SUPPORTED_TUNE_OPTIONS); \ + \ + static const GstVaapiEncoderClassData g_class_data = { \ + .codec = G_PASTE (GST_VAAPI_CODEC_, CODEC), \ + .packed_headers = SUPPORTED_PACKED_HEADERS, \ + .rate_control_get_type = \ + G_PASTE (G_PASTE (gst_vaapi_rate_control_, CODEC), _get_type), \ + .default_rate_control = DEFAULT_RATECONTROL, \ + .rate_control_mask = SUPPORTED_RATECONTROLS, \ + .encoder_tune_get_type = \ + G_PASTE (G_PASTE (gst_vaapi_encoder_tune_, CODEC), _get_type), \ + .default_encoder_tune = GST_VAAPI_ENCODER_TUNE_NONE, \ + .encoder_tune_mask = SUPPORTED_TUNE_OPTIONS, \ + } + +struct _GstVaapiEncoderClass +{ + /*< private >*/ + GstObjectClass parent_class; + + const GstVaapiEncoderClassData *class_data; + + GstVaapiEncoderStatus (*reconfigure) (GstVaapiEncoder * encoder); + GstVaapiEncoderStatus (*reordering) (GstVaapiEncoder * encoder, + GstVideoCodecFrame * in, + GstVaapiEncPicture ** out); + GstVaapiEncoderStatus (*encode) (GstVaapiEncoder * encoder, + GstVaapiEncPicture * picture, + GstVaapiCodedBufferProxy * codedbuf); + + GstVaapiEncoderStatus (*flush) (GstVaapiEncoder * encoder); + + /* get_codec_data can be NULL */ + GstVaapiEncoderStatus (*get_codec_data) (GstVaapiEncoder * encoder, + GstBuffer ** codec_data); + + /* Iterator that retrieves the pending pictures in the reordered + * list */ + gboolean (*get_pending_reordered) (GstVaapiEncoder * encoder, + GstVaapiEncPicture ** picture, + gpointer * state); +}; + +G_GNUC_INTERNAL +GstVaapiSurfaceProxy * +gst_vaapi_encoder_create_surface (GstVaapiEncoder * + encoder); + +static inline void +gst_vaapi_encoder_release_surface (GstVaapiEncoder * encoder, + GstVaapiSurfaceProxy * proxy) +{ + gst_vaapi_surface_proxy_unref (proxy); +} + +G_GNUC_INTERNAL +gboolean +gst_vaapi_encoder_ensure_param_quality_level (GstVaapiEncoder * encoder, + GstVaapiEncPicture * picture); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_encoder_ensure_param_control_rate (GstVaapiEncoder * encoder, + GstVaapiEncPicture * picture); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_encoder_ensure_param_roi_regions (GstVaapiEncoder * encoder, + GstVaapiEncPicture * picture); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_encoder_ensure_param_trellis (GstVaapiEncoder * encoder, + GstVaapiEncPicture * picture); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_encoder_ensure_num_slices (GstVaapiEncoder * encoder, + GstVaapiProfile profile, GstVaapiEntrypoint entrypoint, + guint media_max_slices, guint * num_slices); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_encoder_ensure_max_num_ref_frames (GstVaapiEncoder * encoder, + GstVaapiProfile profile, GstVaapiEntrypoint entrypoint); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_encoder_ensure_tile_support (GstVaapiEncoder * encoder, + GstVaapiProfile profile, GstVaapiEntrypoint entrypoint); + +G_END_DECLS + +#endif /* GST_VAAPI_ENCODER_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_vp8.c b/gst-libs/gst/vaapi/gstvaapiencoder_vp8.c new file mode 100644 index 0000000000..99ffa4615f --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder_vp8.c @@ -0,0 +1,701 @@ +/* + * gstvaapiencoder_vp8.c - VP8 encoder + * + * Copyright (C) 2015 Intel Corporation + * Author: Sreerenj Balachandran + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include +#include +#include "gstvaapicompat.h" +#include "gstvaapiencoder_priv.h" +#include "gstvaapiencoder_vp8.h" +#include "gstvaapicodedbufferproxy_priv.h" +#include "gstvaapisurface.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +/* Define default rate control mode ("constant-qp") */ +#define DEFAULT_RATECONTROL GST_VAAPI_RATECONTROL_CQP + +/* Supported set of VA rate controls, within this implementation */ +#define SUPPORTED_RATECONTROLS \ + (GST_VAAPI_RATECONTROL_MASK (CQP) | \ + GST_VAAPI_RATECONTROL_MASK (CBR) | \ + GST_VAAPI_RATECONTROL_MASK (VBR)) + +/* Supported set of tuning options, within this implementation */ +#define SUPPORTED_TUNE_OPTIONS \ + (GST_VAAPI_ENCODER_TUNE_MASK (NONE)) + +/* Supported set of VA packed headers, within this implementation */ +#define SUPPORTED_PACKED_HEADERS \ + (VA_ENC_PACKED_HEADER_NONE) + +#define DEFAULT_LOOP_FILTER_LEVEL 0 +#define DEFAULT_SHARPNESS_LEVEL 0 +#define DEFAULT_YAC_QI 40 + +/* ------------------------------------------------------------------------- */ +/* --- VP8 Encoder --- */ +/* ------------------------------------------------------------------------- */ + +struct _GstVaapiEncoderVP8 +{ + GstVaapiEncoder parent_instance; + GstVaapiProfile profile; + guint loop_filter_level; + guint sharpness_level; + guint yac_qi; + guint frame_num; + /* reference list */ + GstVaapiSurfaceProxy *last_ref; + GstVaapiSurfaceProxy *golden_ref; + GstVaapiSurfaceProxy *alt_ref; +}; + +/* Derives the profile that suits best to the configuration */ +static GstVaapiEncoderStatus +ensure_profile (GstVaapiEncoderVP8 * encoder) +{ + /* Always start from "simple" profile for maximum compatibility */ + encoder->profile = GST_VAAPI_PROFILE_VP8; + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; +} + +/* Derives the profile supported by the underlying hardware */ +static gboolean +ensure_hw_profile (GstVaapiEncoderVP8 * encoder) +{ + GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (encoder); + GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE; + GstVaapiProfile profile, profiles[2]; + guint i, num_profiles = 0; + + profiles[num_profiles++] = encoder->profile; + + profile = GST_VAAPI_PROFILE_UNKNOWN; + for (i = 0; i < num_profiles; i++) { + if (gst_vaapi_display_has_encoder (display, profiles[i], entrypoint)) { + profile = profiles[i]; + break; + } + } + if (profile == GST_VAAPI_PROFILE_UNKNOWN) + goto error_unsupported_profile; + + GST_VAAPI_ENCODER_CAST (encoder)->profile = profile; + return TRUE; + + /* ERRORS */ +error_unsupported_profile: + { + GST_ERROR ("unsupported HW profile %s", + gst_vaapi_profile_get_va_name (encoder->profile)); + return FALSE; + } +} + +static gboolean +ensure_bitrate (GstVaapiEncoderVP8 * encoder) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); + + /* Default compression: 64 bits per macroblock */ + switch (GST_VAAPI_ENCODER_RATE_CONTROL (encoder)) { + case GST_VAAPI_RATECONTROL_CBR: + case GST_VAAPI_RATECONTROL_VBR: + if (!base_encoder->bitrate) { + base_encoder->bitrate = + gst_util_uint64_scale (GST_VAAPI_ENCODER_WIDTH (encoder) * + GST_VAAPI_ENCODER_HEIGHT (encoder), + GST_VAAPI_ENCODER_FPS_N (encoder), + GST_VAAPI_ENCODER_FPS_D (encoder)) / (4 * 1000); + } + break; + default: + base_encoder->bitrate = 0; + break; + } + + return TRUE; +} + +static GstVaapiEncoderStatus +set_context_info (GstVaapiEncoder * base_encoder) +{ + GstVaapiEncoderVP8 *encoder = GST_VAAPI_ENCODER_VP8 (base_encoder); + GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder); + + /* Maximum sizes for common headers (in bytes) */ + enum + { + MAX_FRAME_TAG_SIZE = 10, + MAX_UPDATE_SEGMENTATION_SIZE = 13, + MAX_MB_LF_ADJUSTMENTS_SIZE = 9, + MAX_QUANT_INDICES_SIZE = 5, + MAX_TOKEN_PROB_UPDATE_SIZE = 1188, + MAX_MV_PROBE_UPDATE_SIZE = 38, + MAX_REST_OF_FRAME_HDR_SIZE = 15 + }; + + if (!ensure_hw_profile (encoder)) + return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + + base_encoder->num_ref_frames = 3; + + /* Only YUV 4:2:0 formats are supported for now. */ + /* Assumig 4 times compression ratio */ + base_encoder->codedbuf_size = GST_ROUND_UP_16 (vip->width) * + GST_ROUND_UP_16 (vip->height) * 12 / 4; + + base_encoder->codedbuf_size += + MAX_FRAME_TAG_SIZE + MAX_UPDATE_SEGMENTATION_SIZE + + MAX_MB_LF_ADJUSTMENTS_SIZE + MAX_QUANT_INDICES_SIZE + + MAX_TOKEN_PROB_UPDATE_SIZE + MAX_MV_PROBE_UPDATE_SIZE + + MAX_REST_OF_FRAME_HDR_SIZE; + + base_encoder->context_info.profile = base_encoder->profile; + base_encoder->context_info.entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE; + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; +} + +static void +clear_ref (GstVaapiEncoderVP8 * encoder, GstVaapiSurfaceProxy ** ref) +{ + if (*ref) { + gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder), *ref); + *ref = NULL; + } +} + +static void +clear_references (GstVaapiEncoderVP8 * encoder) +{ + clear_ref (encoder, &encoder->last_ref); + clear_ref (encoder, &encoder->golden_ref); + clear_ref (encoder, &encoder->alt_ref); +} + +static void +push_reference (GstVaapiEncoderVP8 * encoder, GstVaapiSurfaceProxy * ref) +{ + if (encoder->last_ref == NULL) { + encoder->golden_ref = gst_vaapi_surface_proxy_ref (ref); + encoder->alt_ref = gst_vaapi_surface_proxy_ref (ref); + } else { + clear_ref (encoder, &encoder->alt_ref); + encoder->alt_ref = encoder->golden_ref; + encoder->golden_ref = encoder->last_ref; + } + encoder->last_ref = ref; +} + +static gboolean +fill_sequence (GstVaapiEncoderVP8 * encoder, GstVaapiEncSequence * sequence) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); + VAEncSequenceParameterBufferVP8 *const seq_param = sequence->param; + + memset (seq_param, 0, sizeof (VAEncSequenceParameterBufferVP8)); + + seq_param->frame_width = GST_VAAPI_ENCODER_WIDTH (encoder); + seq_param->frame_height = GST_VAAPI_ENCODER_HEIGHT (encoder); + + if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CBR || + GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_VBR) + seq_param->bits_per_second = base_encoder->bitrate * 1000; + + seq_param->intra_period = base_encoder->keyframe_period; + + return TRUE; +} + +static gboolean +ensure_sequence (GstVaapiEncoderVP8 * encoder, GstVaapiEncPicture * picture) +{ + GstVaapiEncSequence *sequence; + + g_assert (picture); + + if (picture->type != GST_VAAPI_PICTURE_TYPE_I) + return TRUE; + + sequence = GST_VAAPI_ENC_SEQUENCE_NEW (VP8, encoder); + if (!sequence) + goto error; + + if (!fill_sequence (encoder, sequence)) + goto error; + + gst_vaapi_enc_picture_set_sequence (picture, sequence); + gst_vaapi_codec_object_replace (&sequence, NULL); + return TRUE; + + /* ERRORS */ +error: + { + gst_vaapi_codec_object_replace (&sequence, NULL); + return FALSE; + } +} + +static gboolean +ensure_control_rate_params (GstVaapiEncoderVP8 * encoder) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); + + if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CQP) + return TRUE; + + /* RateControl params */ + GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).initial_qp = encoder->yac_qi; + GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).min_qp = 1; + + /* *INDENT-OFF* */ + /* HRD params */ + GST_VAAPI_ENCODER_VA_HRD (encoder) = (VAEncMiscParameterHRD) { + .buffer_size = base_encoder->bitrate * 1000 * 2, + .initial_buffer_fullness = base_encoder->bitrate * 1000, + }; + /* *INDENT-ON* */ + + return TRUE; +} + +static gboolean +ensure_misc_params (GstVaapiEncoderVP8 * encoder, GstVaapiEncPicture * picture) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); + + if (!gst_vaapi_encoder_ensure_param_quality_level (base_encoder, picture)) + return FALSE; + + if (!gst_vaapi_encoder_ensure_param_control_rate (base_encoder, picture)) + return FALSE; + + return TRUE; +} + +static gboolean +fill_picture (GstVaapiEncoderVP8 * encoder, + GstVaapiEncPicture * picture, + GstVaapiCodedBuffer * codedbuf, GstVaapiSurfaceProxy * surface) +{ + VAEncPictureParameterBufferVP8 *const pic_param = picture->param; + int i; + + memset (pic_param, 0, sizeof (VAEncPictureParameterBufferVP8)); + + pic_param->reconstructed_frame = GST_VAAPI_SURFACE_PROXY_SURFACE_ID (surface); + pic_param->coded_buf = GST_VAAPI_CODED_BUFFER_ID (codedbuf); + + if (picture->type == GST_VAAPI_PICTURE_TYPE_P) { + pic_param->pic_flags.bits.frame_type = 1; + pic_param->ref_arf_frame = + GST_VAAPI_SURFACE_PROXY_SURFACE_ID (encoder->alt_ref); + pic_param->ref_gf_frame = + GST_VAAPI_SURFACE_PROXY_SURFACE_ID (encoder->golden_ref); + pic_param->ref_last_frame = + GST_VAAPI_SURFACE_PROXY_SURFACE_ID (encoder->last_ref); + pic_param->pic_flags.bits.refresh_last = 1; + pic_param->pic_flags.bits.refresh_golden_frame = 0; + pic_param->pic_flags.bits.copy_buffer_to_golden = 1; + pic_param->pic_flags.bits.refresh_alternate_frame = 0; + pic_param->pic_flags.bits.copy_buffer_to_alternate = 2; + } else { + pic_param->ref_last_frame = VA_INVALID_SURFACE; + pic_param->ref_gf_frame = VA_INVALID_SURFACE; + pic_param->ref_arf_frame = VA_INVALID_SURFACE; + pic_param->pic_flags.bits.refresh_last = 1; + pic_param->pic_flags.bits.refresh_golden_frame = 1; + pic_param->pic_flags.bits.refresh_alternate_frame = 1; + } + + pic_param->pic_flags.bits.show_frame = 1; + + if (encoder->loop_filter_level) { + pic_param->pic_flags.bits.version = 1; + pic_param->pic_flags.bits.loop_filter_type = 1; /* Enable simple loop filter */ + /* Disabled segmentation, so what matters is only loop_filter_level[0] */ + for (i = 0; i < 4; i++) + pic_param->loop_filter_level[i] = encoder->loop_filter_level; + } + + pic_param->sharpness_level = encoder->sharpness_level; + + /* Used for CBR */ + pic_param->clamp_qindex_low = 0; + pic_param->clamp_qindex_high = 127; + + return TRUE; +} + +static gboolean +ensure_picture (GstVaapiEncoderVP8 * encoder, GstVaapiEncPicture * picture, + GstVaapiCodedBufferProxy * codedbuf_proxy, GstVaapiSurfaceProxy * surface) +{ + GstVaapiCodedBuffer *const codedbuf = + GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (codedbuf_proxy); + + if (!fill_picture (encoder, picture, codedbuf, surface)) + return FALSE; + + return TRUE; +} + +static gboolean +fill_quantization_table (GstVaapiEncoderVP8 * encoder, + GstVaapiEncPicture * picture, GstVaapiEncQMatrix * q_matrix) +{ + VAQMatrixBufferVP8 *const qmatrix_param = q_matrix->param; + int i; + + memset (qmatrix_param, 0, sizeof (VAQMatrixBufferVP8)); + + /* DefaultYacQantVal = 8 for I frame, which is ac_qlookup[4] and + * DefaultYacQantVAl = 44 for P frame, which is ac_qllookup[40] */ + for (i = 0; i < 4; i++) { + if (encoder->yac_qi == DEFAULT_YAC_QI) { + if (picture->type == GST_VAAPI_PICTURE_TYPE_I) + qmatrix_param->quantization_index[i] = 4; + else + qmatrix_param->quantization_index[i] = 40; + } else + qmatrix_param->quantization_index[i] = encoder->yac_qi; + } + + return TRUE; +} + +static gboolean +ensure_quantization_table (GstVaapiEncoderVP8 * encoder, + GstVaapiEncPicture * picture) +{ + g_assert (picture); + + picture->q_matrix = GST_VAAPI_ENC_Q_MATRIX_NEW (VP8, encoder); + if (!picture->q_matrix) { + GST_ERROR ("failed to allocate quantiser table"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + if (!fill_quantization_table (encoder, picture, picture->q_matrix)) + return FALSE; + + return TRUE; +} + +static GstVaapiEncoderStatus +gst_vaapi_encoder_vp8_encode (GstVaapiEncoder * base_encoder, + GstVaapiEncPicture * picture, GstVaapiCodedBufferProxy * codedbuf) +{ + GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (base_encoder); + GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN; + GstVaapiSurfaceProxy *reconstruct = NULL; + + reconstruct = gst_vaapi_encoder_create_surface (base_encoder); + + g_assert (GST_VAAPI_SURFACE_PROXY_SURFACE (reconstruct)); + + if (!ensure_sequence (encoder, picture)) + goto error; + if (!ensure_misc_params (encoder, picture)) + goto error; + if (!ensure_picture (encoder, picture, codedbuf, reconstruct)) + goto error; + if (!ensure_quantization_table (encoder, picture)) + goto error; + if (!gst_vaapi_enc_picture_encode (picture)) + goto error; + if (reconstruct) { + if (picture->type == GST_VAAPI_PICTURE_TYPE_I) + clear_references (encoder); + push_reference (encoder, reconstruct); + } + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; + + /* ERRORS */ +error: + { + if (reconstruct) + gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder), + reconstruct); + return ret; + } +} + +static GstVaapiEncoderStatus +gst_vaapi_encoder_vp8_flush (GstVaapiEncoder * base_encoder) +{ + GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (base_encoder); + + encoder->frame_num = 0; + clear_references (encoder); + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; +} + +static GstVaapiEncoderStatus +gst_vaapi_encoder_vp8_reordering (GstVaapiEncoder * base_encoder, + GstVideoCodecFrame * frame, GstVaapiEncPicture ** output) +{ + GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (base_encoder); + GstVaapiEncPicture *picture = NULL; + GstVaapiEncoderStatus status = GST_VAAPI_ENCODER_STATUS_SUCCESS; + + if (!frame) + return GST_VAAPI_ENCODER_STATUS_NO_SURFACE; + + picture = GST_VAAPI_ENC_PICTURE_NEW (VP8, encoder, frame); + if (!picture) { + GST_WARNING ("create VP8 picture failed, frame timestamp:%" + GST_TIME_FORMAT, GST_TIME_ARGS (frame->pts)); + return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + if (encoder->frame_num >= base_encoder->keyframe_period) { + encoder->frame_num = 0; + clear_references (encoder); + } + if (encoder->frame_num == 0) { + picture->type = GST_VAAPI_PICTURE_TYPE_I; + GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame); + } else { + picture->type = GST_VAAPI_PICTURE_TYPE_P; + } + + encoder->frame_num++; + *output = picture; + return status; +} + +static GstVaapiEncoderStatus +gst_vaapi_encoder_vp8_reconfigure (GstVaapiEncoder * base_encoder) +{ + GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (base_encoder); + GstVaapiEncoderStatus status; + + status = ensure_profile (encoder); + if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) + return status; + + if (!ensure_bitrate (encoder)) + goto error; + + ensure_control_rate_params (encoder); + return set_context_info (base_encoder); + + /* ERRORS */ +error: + { + return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED; + } +} + +struct _GstVaapiEncoderVP8Class +{ + GstVaapiEncoderClass parent_class; +}; + +G_DEFINE_TYPE (GstVaapiEncoderVP8, gst_vaapi_encoder_vp8, + GST_TYPE_VAAPI_ENCODER); + +static void +gst_vaapi_encoder_vp8_init (GstVaapiEncoderVP8 * encoder) +{ + encoder->frame_num = 0; + encoder->last_ref = NULL; + encoder->golden_ref = NULL; + encoder->alt_ref = NULL; +} + +static void +gst_vaapi_encoder_vp8_finalize (GObject * object) +{ + GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (object); + clear_references (encoder); + G_OBJECT_CLASS (gst_vaapi_encoder_vp8_parent_class)->finalize (object); +} + +/** + * @ENCODER_VP8_PROP_RATECONTROL: Rate control (#GstVaapiRateControl). + * @ENCODER_VP8_PROP_TUNE: The tuning options (#GstVaapiEncoderTune). + * @ENCODER_VP8_PROP_LOOP_FILTER_LEVEL: Loop Filter Level(uint). + * @ENCODER_VP8_PROP_LOOP_SHARPNESS_LEVEL: Sharpness Level(uint). + * @ENCODER_VP8_PROP_YAC_Q_INDEX: Quantization table index for luma AC(uint). + * + * The set of VP8 encoder specific configurable properties. + */ +enum +{ + ENCODER_VP8_PROP_RATECONTROL = 1, + ENCODER_VP8_PROP_TUNE, + ENCODER_VP8_PROP_LOOP_FILTER_LEVEL, + ENCODER_VP8_PROP_SHARPNESS_LEVEL, + ENCODER_VP8_PROP_YAC_Q_INDEX, + ENCODER_VP8_N_PROPERTIES +}; + +static GParamSpec *properties[ENCODER_VP8_N_PROPERTIES]; + +static void +gst_vaapi_encoder_vp8_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object); + GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (object); + + if (base_encoder->num_codedbuf_queued > 0) { + GST_ERROR_OBJECT (object, + "failed to set any property after encoding started"); + return; + } + + switch (prop_id) { + case ENCODER_VP8_PROP_RATECONTROL: + gst_vaapi_encoder_set_rate_control (base_encoder, + g_value_get_enum (value)); + break; + case ENCODER_VP8_PROP_TUNE: + gst_vaapi_encoder_set_tuning (base_encoder, g_value_get_enum (value)); + break; + case ENCODER_VP8_PROP_LOOP_FILTER_LEVEL: + encoder->loop_filter_level = g_value_get_uint (value); + break; + case ENCODER_VP8_PROP_SHARPNESS_LEVEL: + encoder->sharpness_level = g_value_get_uint (value); + break; + case ENCODER_VP8_PROP_YAC_Q_INDEX: + encoder->yac_qi = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gst_vaapi_encoder_vp8_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (object); + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object); + + switch (prop_id) { + case ENCODER_VP8_PROP_RATECONTROL: + g_value_set_enum (value, base_encoder->rate_control); + break; + case ENCODER_VP8_PROP_TUNE: + g_value_set_enum (value, base_encoder->tune); + break; + case ENCODER_VP8_PROP_LOOP_FILTER_LEVEL: + g_value_set_uint (value, encoder->loop_filter_level); + break; + case ENCODER_VP8_PROP_SHARPNESS_LEVEL: + g_value_set_uint (value, encoder->sharpness_level); + break; + case ENCODER_VP8_PROP_YAC_Q_INDEX: + g_value_set_uint (value, encoder->yac_qi); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +GST_VAAPI_ENCODER_DEFINE_CLASS_DATA (VP8); + +static void +gst_vaapi_encoder_vp8_class_init (GstVaapiEncoderVP8Class * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstVaapiEncoderClass *const encoder_class = GST_VAAPI_ENCODER_CLASS (klass); + + encoder_class->class_data = &g_class_data; + encoder_class->reconfigure = gst_vaapi_encoder_vp8_reconfigure; + encoder_class->reordering = gst_vaapi_encoder_vp8_reordering; + encoder_class->encode = gst_vaapi_encoder_vp8_encode; + encoder_class->flush = gst_vaapi_encoder_vp8_flush; + + object_class->set_property = gst_vaapi_encoder_vp8_set_property; + object_class->get_property = gst_vaapi_encoder_vp8_get_property; + object_class->finalize = gst_vaapi_encoder_vp8_finalize; + + properties[ENCODER_VP8_PROP_RATECONTROL] = + g_param_spec_enum ("rate-control", + "Rate Control", "Rate control mode", + g_class_data.rate_control_get_type (), + g_class_data.default_rate_control, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + properties[ENCODER_VP8_PROP_TUNE] = + g_param_spec_enum ("tune", "Encoder Tuning", "Encoder tuning option", + g_class_data.encoder_tune_get_type (), + g_class_data.default_encoder_tune, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + properties[ENCODER_VP8_PROP_LOOP_FILTER_LEVEL] = + g_param_spec_uint ("loop-filter-level", "Loop Filter Level", + "Controls the deblocking filter strength", 0, 63, + DEFAULT_LOOP_FILTER_LEVEL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + properties[ENCODER_VP8_PROP_SHARPNESS_LEVEL] = + g_param_spec_uint ("sharpness-level", "Sharpness Level", + "Controls the deblocking filter sensitivity", 0, 7, + DEFAULT_SHARPNESS_LEVEL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + properties[ENCODER_VP8_PROP_YAC_Q_INDEX] = + g_param_spec_uint ("yac-qi", + "Luma AC Quant Table index", + "Quantization Table index for Luma AC Coefficients," + " (in default case, yac_qi=4 for key frames and yac_qi=40" + " for P frames)", + 0, 127, DEFAULT_YAC_QI, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + g_object_class_install_properties (object_class, ENCODER_VP8_N_PROPERTIES, + properties); + + gst_type_mark_as_plugin_api (g_class_data.rate_control_get_type (), 0); + gst_type_mark_as_plugin_api (g_class_data.encoder_tune_get_type (), 0); +} + +/** + * gst_vaapi_encoder_vp8_new: + * @display: a #GstVaapiDisplay + * + * Creates a new #GstVaapiEncoder for VP8 encoding. + * + * Return value: the newly allocated #GstVaapiEncoder object + */ +GstVaapiEncoder * +gst_vaapi_encoder_vp8_new (GstVaapiDisplay * display) +{ + return g_object_new (GST_TYPE_VAAPI_ENCODER_VP8, "display", display, NULL); +} diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_vp8.h b/gst-libs/gst/vaapi/gstvaapiencoder_vp8.h new file mode 100644 index 0000000000..e17c616da9 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder_vp8.h @@ -0,0 +1,49 @@ +/* + * gstvaapiencoder_vp8.h VP8G encoder + * + * Copyright (C) 2015 Intel Corporation + * Author: Sreerenj Balachandran + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_ENCODER_VP8_H +#define GST_VAAPI_ENCODER_VP8_H + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_ENCODER_VP8 \ + (gst_vaapi_encoder_vp8_get_type ()) +#define GST_VAAPI_ENCODER_VP8(encoder) \ + (G_TYPE_CHECK_INSTANCE_CAST ((encoder), GST_TYPE_VAAPI_ENCODER_VP8, GstVaapiEncoderVP8)) +#define GST_IS_VAAPI_ENCODER_VP8(encoder) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((encoder), GST_TYPE_VAAPI_ENCODER_VP8)) + +typedef struct _GstVaapiEncoderVP8 GstVaapiEncoderVP8; +typedef struct _GstVaapiEncoderVP8Class GstVaapiEncoderVP8Class; + +GType +gst_vaapi_encoder_vp8_get_type (void) G_GNUC_CONST; + +GstVaapiEncoder * +gst_vaapi_encoder_vp8_new (GstVaapiDisplay * display); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiEncoderVP8, gst_object_unref) + +G_END_DECLS +#endif /*GST_VAAPI_ENCODER_VP8_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_vp9.c b/gst-libs/gst/vaapi/gstvaapiencoder_vp9.c new file mode 100644 index 0000000000..bd47c0d644 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder_vp9.c @@ -0,0 +1,824 @@ +/* + * gstvaapiencoder_vp9.c - VP9 encoder + * + * Copyright (C) 2016 Intel Corporation + * Author: Sreerenj Balachandran + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include +#include +#include "gstvaapicompat.h" +#include "gstvaapiencoder_priv.h" +#include "gstvaapiencoder_vp9.h" +#include "gstvaapicodedbufferproxy_priv.h" +#include "gstvaapisurface.h" +#include "gstvaapiutils_vpx.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +#define MAX_TILE_WIDTH_B64 64 + +/* Define default rate control mode ("constant-qp") */ +#define DEFAULT_RATECONTROL GST_VAAPI_RATECONTROL_CQP + +/* Supported set of VA rate controls, within this implementation */ +#define SUPPORTED_RATECONTROLS \ + (GST_VAAPI_RATECONTROL_MASK (CQP) | \ + GST_VAAPI_RATECONTROL_MASK (CBR) | \ + GST_VAAPI_RATECONTROL_MASK (VBR)) + +/* Supported set of tuning options, within this implementation */ +#define SUPPORTED_TUNE_OPTIONS \ + (GST_VAAPI_ENCODER_TUNE_MASK (NONE) | \ + GST_VAAPI_ENCODER_TUNE_MASK (LOW_POWER)) + +/* Supported set of VA packed headers, within this implementation */ +#define SUPPORTED_PACKED_HEADERS \ + (VA_ENC_PACKED_HEADER_NONE) + +#define DEFAULT_LOOP_FILTER_LEVEL 10 +#define DEFAULT_SHARPNESS_LEVEL 0 +#define DEFAULT_YAC_QINDEX 60 + +#define MAX_FRAME_WIDTH 4096 +#define MAX_FRAME_HEIGHT 4096 + +/* Default CPB length (in milliseconds) */ +#define DEFAULT_CPB_LENGTH 1500 + +typedef enum +{ + GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_0 = 0, + GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_1 = 1 +} GstVaapiEnoderVP9RefPicMode; + +static GType +gst_vaapi_encoder_vp9_ref_pic_mode_type (void) +{ + static GType gtype = 0; + + if (gtype == 0) { + static const GEnumValue values[] = { + {GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_0, + "Use Keyframe(Alt & Gold) and Previousframe(Last) for prediction ", + "mode-0"}, + {GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_1, + "Use last three frames for prediction (n:Last n-1:Gold n-2:Alt)", + "mode-1"}, + {0, NULL, NULL}, + }; + + gtype = g_enum_register_static ("GstVaapiEncoderVP9RefPicMode", values); + } + return gtype; +} + + +/* ------------------------------------------------------------------------- */ +/* --- VP9 Encoder --- */ +/* ------------------------------------------------------------------------- */ + +struct _GstVaapiEncoderVP9 +{ + GstVaapiEncoder parent_instance; + GstVaapiProfile profile; + guint loop_filter_level; + guint sharpness_level; + guint yac_qi; + guint ref_pic_mode; + guint frame_num; + GstVaapiSurfaceProxy *ref_list[GST_VP9_REF_FRAMES]; /* reference list */ + guint ref_list_idx; /* next free slot in ref_list */ + GstVaapiEntrypoint entrypoint; + GArray *allowed_profiles; + + /* Bitrate contral parameters, CPB = Coded Picture Buffer */ + guint bitrate_bits; /* bitrate (bits) */ + guint cpb_length; /* length of CPB buffer (ms) */ +}; + +/* Estimates a good enough bitrate if none was supplied */ +static void +ensure_bitrate (GstVaapiEncoderVP9 * encoder) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); + guint bitrate; + + switch (GST_VAAPI_ENCODER_RATE_CONTROL (encoder)) { + case GST_VAAPI_RATECONTROL_CBR: + case GST_VAAPI_RATECONTROL_VBR: + if (!base_encoder->bitrate) { + /* FIXME: Provide better estimation */ + /* Using a 1/6 compression ratio */ + /* 12 bits per pixel fro yuv420 */ + base_encoder->bitrate = + (GST_VAAPI_ENCODER_WIDTH (encoder) * + GST_VAAPI_ENCODER_HEIGHT (encoder) * 12 / 6) * + GST_VAAPI_ENCODER_FPS_N (encoder) / + GST_VAAPI_ENCODER_FPS_D (encoder) / 1000; + GST_INFO ("target bitrate computed to %u kbps", base_encoder->bitrate); + } + + bitrate = (base_encoder->bitrate * 1000); + if (bitrate != encoder->bitrate_bits) { + GST_DEBUG ("HRD bitrate: %u bits/sec", bitrate); + encoder->bitrate_bits = bitrate; + } + + break; + default: + base_encoder->bitrate = 0; + break; + } +} + +static gboolean +is_profile_allowed (GstVaapiEncoderVP9 * encoder, GstVaapiProfile profile) +{ + guint i; + + if (encoder->allowed_profiles == NULL) + return TRUE; + + for (i = 0; i < encoder->allowed_profiles->len; i++) + if (profile == + g_array_index (encoder->allowed_profiles, GstVaapiProfile, i)) + return TRUE; + + return FALSE; +} + + /* Derives the profile that suits best to the configuration */ +static GstVaapiEncoderStatus +ensure_profile (GstVaapiEncoderVP9 * encoder) +{ + const GstVideoFormat format = + GST_VIDEO_INFO_FORMAT (GST_VAAPI_ENCODER_VIDEO_INFO (encoder)); + guint depth, chrome; + + if (!GST_VIDEO_FORMAT_INFO_IS_YUV (gst_video_format_get_info (format))) + return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + + depth = GST_VIDEO_FORMAT_INFO_DEPTH (gst_video_format_get_info (format), 0); + chrome = gst_vaapi_utils_vp9_get_chroma_format_idc + (gst_vaapi_video_format_get_chroma_type + (GST_VIDEO_INFO_FORMAT (GST_VAAPI_ENCODER_VIDEO_INFO (encoder)))); + + encoder->profile = GST_VAAPI_PROFILE_UNKNOWN; + /* + Profile Color | Depth Chroma | Subsampling + 0 | 8 bit/sample | 4:2:0 + 1 | 8 bit | 4:2:2, 4:4:4 + 2 | 10 or 12 bit | 4:2:0 + 3 | 10 or 12 bit | 4:2:2, 4:4:4 */ + if (chrome == 3 || chrome == 2) { + /* 4:4:4 and 4:2:2 */ + if (depth == 8) { + encoder->profile = GST_VAAPI_PROFILE_VP9_1; + } else if (depth == 10 || depth == 12) { + encoder->profile = GST_VAAPI_PROFILE_VP9_3; + } + } else if (chrome == 1) { + /* 4:2:0 */ + if (depth == 8) { + encoder->profile = GST_VAAPI_PROFILE_VP9_0; + } else if (depth == 10 || depth == 12) { + encoder->profile = GST_VAAPI_PROFILE_VP9_2; + } + } + + if (encoder->profile == GST_VAAPI_PROFILE_UNKNOWN) { + GST_WARNING ("Failed to decide VP9 profile"); + return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + } + + if (!is_profile_allowed (encoder, encoder->profile)) { + GST_WARNING ("Failed to find an allowed VP9 profile"); + return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + } + + /* Ensure bitrate if not set already */ + ensure_bitrate (encoder); + return GST_VAAPI_ENCODER_STATUS_SUCCESS; +} + +static GstVaapiEncoderStatus +set_context_info (GstVaapiEncoder * base_encoder) +{ + GstVaapiEncoderVP9 *encoder = GST_VAAPI_ENCODER_VP9 (base_encoder); + GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder); + const guint DEFAULT_SURFACES_COUNT = 2; + + /* FIXME: Maximum sizes for common headers (in bytes) */ + + GST_VAAPI_ENCODER_CAST (encoder)->profile = encoder->profile; + + base_encoder->num_ref_frames = 3 + DEFAULT_SURFACES_COUNT; + + /* Only YUV 4:2:0 formats are supported for now. */ + base_encoder->codedbuf_size = GST_ROUND_UP_16 (vip->width) * + GST_ROUND_UP_16 (vip->height) * 3 / 2; + + base_encoder->context_info.profile = base_encoder->profile; + base_encoder->context_info.entrypoint = encoder->entrypoint; + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; +} + +static gboolean +fill_sequence (GstVaapiEncoderVP9 * encoder, GstVaapiEncSequence * sequence) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); + VAEncSequenceParameterBufferVP9 *const seq_param = sequence->param; + + memset (seq_param, 0, sizeof (VAEncSequenceParameterBufferVP9)); + + seq_param->max_frame_width = MAX_FRAME_WIDTH; + seq_param->max_frame_height = MAX_FRAME_HEIGHT; + + /* keyframe minimum interval */ + seq_param->kf_min_dist = 1; + /* keyframe maximum interval */ + seq_param->kf_max_dist = base_encoder->keyframe_period; + seq_param->intra_period = base_encoder->keyframe_period; + seq_param->bits_per_second = encoder->bitrate_bits; + + return TRUE; +} + +static gboolean +ensure_sequence (GstVaapiEncoderVP9 * encoder, GstVaapiEncPicture * picture) +{ + GstVaapiEncSequence *sequence; + + g_assert (picture); + + if (picture->type != GST_VAAPI_PICTURE_TYPE_I) + return TRUE; + + sequence = GST_VAAPI_ENC_SEQUENCE_NEW (VP9, encoder); + if (!sequence) + goto error; + + if (!fill_sequence (encoder, sequence)) + goto error; + + gst_vaapi_enc_picture_set_sequence (picture, sequence); + gst_vaapi_codec_object_replace (&sequence, NULL); + return TRUE; + + /* ERRORS */ +error: + { + gst_vaapi_codec_object_replace (&sequence, NULL); + return FALSE; + } +} + +static gboolean +ensure_control_rate_params (GstVaapiEncoderVP9 * encoder) +{ + if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CQP) + return TRUE; + + /* RateControl params */ + GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).bits_per_second = + encoder->bitrate_bits; + GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).window_size = encoder->cpb_length; + + /* *INDENT-OFF* */ + /* HRD params */ + GST_VAAPI_ENCODER_VA_HRD (encoder) = (VAEncMiscParameterHRD) { + .buffer_size = encoder->bitrate_bits * 2, + .initial_buffer_fullness = encoder->bitrate_bits, + }; + /* *INDENT-ON* */ + + return TRUE; +} + +static gboolean +ensure_misc_params (GstVaapiEncoderVP9 * encoder, GstVaapiEncPicture * picture) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); + + if (!gst_vaapi_encoder_ensure_param_quality_level (base_encoder, picture)) + return FALSE; + if (!gst_vaapi_encoder_ensure_param_control_rate (base_encoder, picture)) + return FALSE; + return TRUE; +} + +static void +get_ref_indices (guint ref_pic_mode, guint ref_list_idx, guint * last_idx, + guint * gf_idx, guint * arf_idx, guint8 * refresh_frame_flags) +{ + if (ref_pic_mode == GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_0) { + *last_idx = ref_list_idx - 1; + *gf_idx = 1; + *arf_idx = 2; + *refresh_frame_flags = 0x01; + } else if (ref_pic_mode == GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_1) { + gint last_filled_idx = (ref_list_idx - 1) & (GST_VP9_REF_FRAMES - 1); + + *last_idx = last_filled_idx; + *gf_idx = (last_filled_idx - 1) & (GST_VP9_REF_FRAMES - 1); + *arf_idx = (last_filled_idx - 2) & (GST_VP9_REF_FRAMES - 1); + + *refresh_frame_flags = 1 << ((*last_idx + 1) % GST_VP9_REF_FRAMES); + } + + GST_LOG + ("last_ref_idx:%d gold_ref_idx:%d alt_reff_idx:%d refesh_frame_flag:%x", + *last_idx, *gf_idx, *arf_idx, *refresh_frame_flags); +} + +static gboolean +fill_picture (GstVaapiEncoderVP9 * encoder, + GstVaapiEncPicture * picture, + GstVaapiCodedBuffer * codedbuf, GstVaapiSurfaceProxy * surface) +{ + VAEncPictureParameterBufferVP9 *const pic_param = picture->param; + guint i, last_idx = 0, gf_idx = 0, arf_idx = 0; + guint8 refresh_frame_flags = 0; + gint sb_cols = 0, min_log2_tile_columns = 0; + + memset (pic_param, 0, sizeof (VAEncPictureParameterBufferVP9)); + + pic_param->reconstructed_frame = GST_VAAPI_SURFACE_PROXY_SURFACE_ID (surface); + pic_param->coded_buf = GST_VAAPI_CODED_BUFFER_ID (codedbuf); + + /* Update Reference Frame list */ + if (picture->type == GST_VAAPI_PICTURE_TYPE_I) + memset (pic_param->reference_frames, 0xFF, + sizeof (pic_param->reference_frames)); + else { + for (i = 0; i < G_N_ELEMENTS (pic_param->reference_frames); i++) { + pic_param->reference_frames[i] = + GST_VAAPI_SURFACE_PROXY_SURFACE_ID (encoder->ref_list[i]); + } + } + + /* It is possible to have dynamic scaling with gpu by providing + * src and destination resoltuion. For now we are just using + * default encoder width and height */ + pic_param->frame_width_src = GST_VAAPI_ENCODER_WIDTH (encoder); + pic_param->frame_height_src = GST_VAAPI_ENCODER_HEIGHT (encoder); + pic_param->frame_width_dst = GST_VAAPI_ENCODER_WIDTH (encoder); + pic_param->frame_height_dst = GST_VAAPI_ENCODER_HEIGHT (encoder); + + pic_param->pic_flags.bits.show_frame = 1; + + if (picture->type == GST_VAAPI_PICTURE_TYPE_P) { + pic_param->pic_flags.bits.frame_type = GST_VP9_INTER_FRAME; + + /* use three of the reference frames (last, golden and altref) + * for prediction */ + pic_param->ref_flags.bits.ref_frame_ctrl_l0 = 0x7; + + get_ref_indices (encoder->ref_pic_mode, encoder->ref_list_idx, &last_idx, + &gf_idx, &arf_idx, &refresh_frame_flags); + + pic_param->ref_flags.bits.ref_last_idx = last_idx; + pic_param->ref_flags.bits.ref_gf_idx = gf_idx; + pic_param->ref_flags.bits.ref_arf_idx = arf_idx; + pic_param->refresh_frame_flags = refresh_frame_flags; + } + + /* Maximum width of a tile in units of superblocks is MAX_TILE_WIDTH_B64(64). + * When the width is enough to partition more than MAX_TILE_WIDTH_B64(64) superblocks, + * we need multi tiles to handle it.*/ + sb_cols = (pic_param->frame_width_src + 63) / 64; + while ((MAX_TILE_WIDTH_B64 << min_log2_tile_columns) < sb_cols) + ++min_log2_tile_columns; + pic_param->log2_tile_columns = min_log2_tile_columns; + + pic_param->luma_ac_qindex = encoder->yac_qi; + pic_param->luma_dc_qindex_delta = 1; + pic_param->chroma_ac_qindex_delta = 1; + pic_param->chroma_dc_qindex_delta = 1; + pic_param->filter_level = encoder->loop_filter_level; + pic_param->sharpness_level = encoder->sharpness_level; + + return TRUE; +} + +static gboolean +ensure_picture (GstVaapiEncoderVP9 * encoder, GstVaapiEncPicture * picture, + GstVaapiCodedBufferProxy * codedbuf_proxy, GstVaapiSurfaceProxy * surface) +{ + GstVaapiCodedBuffer *const codedbuf = + GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (codedbuf_proxy); + + if (!fill_picture (encoder, picture, codedbuf, surface)) + return FALSE; + + return TRUE; +} + +static void +update_ref_list (GstVaapiEncoderVP9 * encoder, GstVaapiEncPicture * picture, + GstVaapiSurfaceProxy * ref) +{ + guint i; + + if (picture->type == GST_VAAPI_PICTURE_TYPE_I) { + for (i = 0; i < G_N_ELEMENTS (encoder->ref_list); i++) + gst_vaapi_surface_proxy_replace (&encoder->ref_list[i], ref); + gst_vaapi_surface_proxy_unref (ref); + /* set next free slot index */ + encoder->ref_list_idx = 1; + return; + } + + switch (encoder->ref_pic_mode) { + case GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_0: + gst_vaapi_surface_proxy_replace (&encoder->ref_list[0], ref); + gst_vaapi_surface_proxy_unref (ref); + break; + case GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_1: + i = encoder->ref_list_idx; + gst_vaapi_surface_proxy_replace (&encoder->ref_list[i], ref); + gst_vaapi_surface_proxy_unref (ref); + encoder->ref_list_idx = (encoder->ref_list_idx + 1) % GST_VP9_REF_FRAMES; + break; + default: + g_assert ("Code shouldn't reach here"); + break; + } +} + +static GstVaapiEncoderStatus +gst_vaapi_encoder_vp9_encode (GstVaapiEncoder * base_encoder, + GstVaapiEncPicture * picture, GstVaapiCodedBufferProxy * codedbuf) +{ + GstVaapiEncoderVP9 *const encoder = GST_VAAPI_ENCODER_VP9 (base_encoder); + GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN; + GstVaapiSurfaceProxy *reconstruct = NULL; + + reconstruct = gst_vaapi_encoder_create_surface (base_encoder); + + g_assert (GST_VAAPI_SURFACE_PROXY_SURFACE (reconstruct)); + + if (!ensure_sequence (encoder, picture)) + goto error; + if (!ensure_misc_params (encoder, picture)) + goto error; + if (!ensure_picture (encoder, picture, codedbuf, reconstruct)) + goto error; + if (!gst_vaapi_enc_picture_encode (picture)) + goto error; + + update_ref_list (encoder, picture, reconstruct); + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; + + /* ERRORS */ +error: + { + if (reconstruct) + gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder), + reconstruct); + return ret; + } +} + +static GstVaapiEncoderStatus +gst_vaapi_encoder_vp9_flush (GstVaapiEncoder * base_encoder) +{ + GstVaapiEncoderVP9 *const encoder = GST_VAAPI_ENCODER_VP9 (base_encoder); + + encoder->frame_num = 0; + + return GST_VAAPI_ENCODER_STATUS_SUCCESS; +} + +static GstVaapiEncoderStatus +gst_vaapi_encoder_vp9_reordering (GstVaapiEncoder * base_encoder, + GstVideoCodecFrame * frame, GstVaapiEncPicture ** output) +{ + GstVaapiEncoderVP9 *const encoder = GST_VAAPI_ENCODER_VP9 (base_encoder); + GstVaapiEncPicture *picture = NULL; + GstVaapiEncoderStatus status = GST_VAAPI_ENCODER_STATUS_SUCCESS; + + if (!frame) + return GST_VAAPI_ENCODER_STATUS_NO_SURFACE; + + picture = GST_VAAPI_ENC_PICTURE_NEW (VP9, encoder, frame); + if (!picture) { + GST_WARNING ("create VP9 picture failed, frame timestamp:%" + GST_TIME_FORMAT, GST_TIME_ARGS (frame->pts)); + return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + if (encoder->frame_num >= base_encoder->keyframe_period) { + encoder->frame_num = 0; + } + if (encoder->frame_num == 0) { + picture->type = GST_VAAPI_PICTURE_TYPE_I; + GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame); + } else { + picture->type = GST_VAAPI_PICTURE_TYPE_P; + } + + encoder->frame_num++; + *output = picture; + return status; +} + +static GstVaapiEncoderStatus +gst_vaapi_encoder_vp9_reconfigure (GstVaapiEncoder * base_encoder) +{ + GstVaapiEncoderVP9 *const encoder = GST_VAAPI_ENCODER_VP9 (base_encoder); + GstVaapiEncoderStatus status; + + status = ensure_profile (encoder); + if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) + return status; + + encoder->entrypoint = + gst_vaapi_encoder_get_entrypoint (base_encoder, encoder->profile); + if (encoder->entrypoint == GST_VAAPI_ENTRYPOINT_INVALID) { + GST_WARNING ("Cannot find valid profile/entrypoint pair"); + return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + } + + ensure_control_rate_params (encoder); + return set_context_info (base_encoder); +} + + +struct _GstVaapiEncoderVP9Class +{ + GstVaapiEncoderClass parent_class; +}; + +G_DEFINE_TYPE (GstVaapiEncoderVP9, gst_vaapi_encoder_vp9, + GST_TYPE_VAAPI_ENCODER); + +static void +gst_vaapi_encoder_vp9_init (GstVaapiEncoderVP9 * encoder) +{ + encoder->frame_num = 0; + encoder->loop_filter_level = DEFAULT_LOOP_FILTER_LEVEL; + encoder->sharpness_level = DEFAULT_SHARPNESS_LEVEL; + encoder->yac_qi = DEFAULT_YAC_QINDEX; + encoder->cpb_length = DEFAULT_CPB_LENGTH; + encoder->entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE; + + memset (encoder->ref_list, 0, + G_N_ELEMENTS (encoder->ref_list) * sizeof (encoder->ref_list[0])); + encoder->ref_list_idx = 0; + + encoder->allowed_profiles = NULL; +} + +static void +gst_vaapi_encoder_vp9_finalize (GObject * object) +{ + GstVaapiEncoderVP9 *const encoder = GST_VAAPI_ENCODER_VP9 (object); + + if (encoder->allowed_profiles) + g_array_unref (encoder->allowed_profiles); + + G_OBJECT_CLASS (gst_vaapi_encoder_vp9_parent_class)->finalize (object); +} + +/** + * @ENCODER_VP9_PROP_RATECONTROL: Rate control (#GstVaapiRateControl). + * @ENCODER_VP9_PROP_TUNE: The tuning options (#GstVaapiEncoderTune). + * @ENCODER_VP9_PROP_LOOP_FILTER_LEVEL: Loop Filter Level(uint). + * @ENCODER_VP9_PROP_LOOP_SHARPNESS_LEVEL: Sharpness Level(uint). + * @ENCODER_VP9_PROP_YAC_Q_INDEX: Quantization table index for luma AC + * @ENCODER_VP9_PROP_REF_PIC_MODE: Reference picute selection modes + * @ENCODER_VP9_PROP_CPB_LENGTH:Length of CPB buffer in milliseconds + * + * The set of VP9 encoder specific configurable properties. + */ +enum +{ + ENCODER_VP9_PROP_RATECONTROL = 1, + ENCODER_VP9_PROP_TUNE, + ENCODER_VP9_PROP_LOOP_FILTER_LEVEL, + ENCODER_VP9_PROP_SHARPNESS_LEVEL, + ENCODER_VP9_PROP_YAC_Q_INDEX, + ENCODER_VP9_PROP_REF_PIC_MODE, + ENCODER_VP9_PROP_CPB_LENGTH, + ENCODER_VP9_N_PROPERTIES +}; + +static GParamSpec *properties[ENCODER_VP9_N_PROPERTIES]; + +static void +gst_vaapi_encoder_vp9_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object); + GstVaapiEncoderVP9 *const encoder = GST_VAAPI_ENCODER_VP9 (object); + + if (base_encoder->num_codedbuf_queued > 0) { + GST_ERROR_OBJECT (object, + "failed to set any property after encoding started"); + return; + } + + switch (prop_id) { + case ENCODER_VP9_PROP_RATECONTROL: + gst_vaapi_encoder_set_rate_control (base_encoder, + g_value_get_enum (value)); + break; + case ENCODER_VP9_PROP_TUNE: + gst_vaapi_encoder_set_tuning (base_encoder, g_value_get_enum (value)); + break; + case ENCODER_VP9_PROP_LOOP_FILTER_LEVEL: + encoder->loop_filter_level = g_value_get_uint (value); + break; + case ENCODER_VP9_PROP_SHARPNESS_LEVEL: + encoder->sharpness_level = g_value_get_uint (value); + break; + case ENCODER_VP9_PROP_YAC_Q_INDEX: + encoder->yac_qi = g_value_get_uint (value); + break; + case ENCODER_VP9_PROP_REF_PIC_MODE: + encoder->ref_pic_mode = g_value_get_enum (value); + break; + case ENCODER_VP9_PROP_CPB_LENGTH: + encoder->cpb_length = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gst_vaapi_encoder_vp9_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstVaapiEncoderVP9 *const encoder = GST_VAAPI_ENCODER_VP9 (object); + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object); + + switch (prop_id) { + case ENCODER_VP9_PROP_RATECONTROL: + g_value_set_enum (value, base_encoder->rate_control); + break; + case ENCODER_VP9_PROP_TUNE: + g_value_set_enum (value, base_encoder->tune); + break; + case ENCODER_VP9_PROP_LOOP_FILTER_LEVEL: + g_value_set_uint (value, encoder->loop_filter_level); + break; + case ENCODER_VP9_PROP_SHARPNESS_LEVEL: + g_value_set_uint (value, encoder->sharpness_level); + break; + case ENCODER_VP9_PROP_YAC_Q_INDEX: + g_value_set_uint (value, encoder->yac_qi); + break; + case ENCODER_VP9_PROP_REF_PIC_MODE: + g_value_set_enum (value, encoder->ref_pic_mode); + break; + case ENCODER_VP9_PROP_CPB_LENGTH: + g_value_set_uint (value, encoder->cpb_length); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +GST_VAAPI_ENCODER_DEFINE_CLASS_DATA (VP9); + +static void +gst_vaapi_encoder_vp9_class_init (GstVaapiEncoderVP9Class * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstVaapiEncoderClass *const encoder_class = GST_VAAPI_ENCODER_CLASS (klass); + + encoder_class->class_data = &g_class_data; + encoder_class->reconfigure = gst_vaapi_encoder_vp9_reconfigure; + encoder_class->reordering = gst_vaapi_encoder_vp9_reordering; + encoder_class->encode = gst_vaapi_encoder_vp9_encode; + encoder_class->flush = gst_vaapi_encoder_vp9_flush; + + object_class->set_property = gst_vaapi_encoder_vp9_set_property; + object_class->get_property = gst_vaapi_encoder_vp9_get_property; + object_class->finalize = gst_vaapi_encoder_vp9_finalize; + + properties[ENCODER_VP9_PROP_RATECONTROL] = + g_param_spec_enum ("rate-control", + "Rate Control", "Rate control mode", + g_class_data.rate_control_get_type (), + g_class_data.default_rate_control, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + properties[ENCODER_VP9_PROP_TUNE] = + g_param_spec_enum ("tune", + "Encoder Tuning", + "Encoder tuning option", + g_class_data.encoder_tune_get_type (), + g_class_data.default_encoder_tune, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + properties[ENCODER_VP9_PROP_LOOP_FILTER_LEVEL] = + g_param_spec_uint ("loop-filter-level", + "Loop Filter Level", + "Controls the deblocking filter strength", + 0, 63, DEFAULT_LOOP_FILTER_LEVEL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + properties[ENCODER_VP9_PROP_SHARPNESS_LEVEL] = + g_param_spec_uint ("sharpness-level", + "Sharpness Level", + "Controls the deblocking filter sensitivity", + 0, 7, DEFAULT_SHARPNESS_LEVEL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + properties[ENCODER_VP9_PROP_YAC_Q_INDEX] = + g_param_spec_uint ("yac-qi", + "Luma AC Quant Table index", + "Quantization Table index for Luma AC Coefficients", + 0, 255, DEFAULT_YAC_QINDEX, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + properties[ENCODER_VP9_PROP_REF_PIC_MODE] = + g_param_spec_enum ("ref-pic-mode", + "RefPic Selection", + "Reference Picture Selection Modes", + gst_vaapi_encoder_vp9_ref_pic_mode_type (), + GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + /** + * GstVaapiEncoderVP9:cpb-length: + * + * The size of the Coded Picture Buffer , which means + * the window size in milliseconds. + * + */ + properties[ENCODER_VP9_PROP_CPB_LENGTH] = + g_param_spec_uint ("cpb-length", + "CPB Length", "Length of the CPB_buffer/window_size in milliseconds", + 1, 10000, DEFAULT_CPB_LENGTH, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | + GST_VAAPI_PARAM_ENCODER_EXPOSURE); + + g_object_class_install_properties (object_class, ENCODER_VP9_N_PROPERTIES, + properties); + + gst_type_mark_as_plugin_api (g_class_data.rate_control_get_type (), 0); + gst_type_mark_as_plugin_api (g_class_data.encoder_tune_get_type (), 0); +} + +/** + * gst_vaapi_encoder_vp9_new: + * @display: a #GstVaapiDisplay + * + * Creates a new #GstVaapiEncoder for VP9 encoding. + * + * Return value: the newly allocated #GstVaapiEncoder object + */ +GstVaapiEncoder * +gst_vaapi_encoder_vp9_new (GstVaapiDisplay * display) +{ + return g_object_new (GST_TYPE_VAAPI_ENCODER_VP9, "display", display, NULL); +} + +/** + * gst_vaapi_encoder_vp9_set_allowed_profiles: + * @encoder: a #GstVaapiEncoderVP9 + * @profiles: a #GArray of all allowed #GstVaapiProfile. + * + * Set the all allowed profiles for the encoder. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_encoder_vp9_set_allowed_profiles (GstVaapiEncoderVP9 * encoder, + GArray * profiles) +{ + g_return_val_if_fail (profiles != 0, FALSE); + + encoder->allowed_profiles = g_array_ref (profiles); + return TRUE; +} diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_vp9.h b/gst-libs/gst/vaapi/gstvaapiencoder_vp9.h new file mode 100644 index 0000000000..6459c01b33 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder_vp9.h @@ -0,0 +1,53 @@ +/* + * gstvaapiencoder_vp9.h VP9 encoder + * + * Copyright (C) 2016 Intel Corporation + * Author: Sreerenj Balachandran + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_ENCODER_VP9_H +#define GST_VAAPI_ENCODER_VP9_H + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_ENCODER_VP9 \ + (gst_vaapi_encoder_vp9_get_type ()) +#define GST_VAAPI_ENCODER_VP9(encoder) \ + (G_TYPE_CHECK_INSTANCE_CAST ((encoder), GST_TYPE_VAAPI_ENCODER_VP9, GstVaapiEncoderVP9)) +#define GST_IS_VAAPI_ENCODER_VP9(encoder) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((encoder), GST_TYPE_VAAPI_ENCODER_VP9)) + +typedef struct _GstVaapiEncoderVP9 GstVaapiEncoderVP9; +typedef struct _GstVaapiEncoderVP9Class GstVaapiEncoderVP9Class; + +GType +gst_vaapi_encoder_vp9_get_type (void) G_GNUC_CONST; + +GstVaapiEncoder * +gst_vaapi_encoder_vp9_new (GstVaapiDisplay * display); + +gboolean +gst_vaapi_encoder_vp9_set_allowed_profiles (GstVaapiEncoderVP9 * encoder, + GArray * profiles); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiEncoderVP9, gst_object_unref) + +G_END_DECLS +#endif /*GST_VAAPI_ENCODER_VP9_H */ diff --git a/gst-libs/gst/vaapi/gstvaapifilter.c b/gst-libs/gst/vaapi/gstvaapifilter.c new file mode 100644 index 0000000000..675c481b3f --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapifilter.c @@ -0,0 +1,2527 @@ +/* + * gstvaapifilter.c - Video processing abstraction + * + * Copyright (C) 2013-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include "gstvaapicompat.h" +#include "gstvaapifilter.h" +#include "gstvaapiutils.h" +#include "gstvaapivalue.h" +#include "gstvaapiminiobject.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapisurface_priv.h" +#include "gstvaapiutils_core.h" + +#define GST_VAAPI_FILTER_CAST(obj) \ + ((GstVaapiFilter *)(obj)) + +typedef struct _GstVaapiFilterOpData GstVaapiFilterOpData; +struct _GstVaapiFilterOpData +{ + GstVaapiFilterOp op; + GParamSpec *pspec; + gint ref_count; + guint va_type; + guint va_subtype; + gpointer va_caps; + guint va_num_caps; + guint va_cap_size; + VABufferID va_buffer; + guint va_buffer_size; + guint is_enabled:1; +}; + +struct _GstVaapiFilter +{ + /*< private > */ + GstObject parent_instance; + + GstVaapiDisplay *display; + VADisplay va_display; + VAConfigID va_config; + VAContextID va_context; + GPtrArray *operations; + GstVideoFormat format; + GstVaapiScaleMethod scale_method; + GstVideoOrientationMethod video_direction; + GstVaapiConfigSurfaceAttributes *attribs; + GArray *forward_references; + GArray *backward_references; + GstVaapiRectangle crop_rect; + GstVaapiRectangle target_rect; + guint use_crop_rect:1; + guint use_target_rect:1; + guint32 mirror_flags; + guint32 rotation_flags; + + GstVideoColorimetry input_colorimetry; + GstVideoColorimetry output_colorimetry; + +#if VA_CHECK_VERSION(1,4,0) + VAHdrMetaDataHDR10 hdr_meta; +#endif +}; + +typedef struct _GstVaapiFilterClass GstVaapiFilterClass; +struct _GstVaapiFilterClass +{ + /*< private > */ + GstObjectClass parent_class; +}; + +/* Debug category for VaapiFilter */ +GST_DEBUG_CATEGORY (gst_debug_vaapi_filter); +#define GST_CAT_DEFAULT gst_debug_vaapi_filter + +#define _do_init \ + GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi_filter, "vaapifilter", 0, \ + "VA-API Filter"); + +G_DEFINE_TYPE_WITH_CODE (GstVaapiFilter, gst_vaapi_filter, GST_TYPE_OBJECT, + _do_init); + +/* ------------------------------------------------------------------------- */ +/* --- VPP Types --- */ +/* ------------------------------------------------------------------------- */ + +static GType +gst_vaapi_scale_method_get_type (void) +{ + static gsize g_type = 0; + + static const GEnumValue enum_values[] = { + {GST_VAAPI_SCALE_METHOD_DEFAULT, + "Default scaling mode", "default"}, + {GST_VAAPI_SCALE_METHOD_FAST, + "Fast scaling mode", "fast"}, + {GST_VAAPI_SCALE_METHOD_HQ, + "High quality scaling mode", "hq"}, + {0, NULL, NULL}, + }; + + if (g_once_init_enter (&g_type)) { + const GType type = + g_enum_register_static ("GstVaapiScaleMethod", enum_values); + g_once_init_leave (&g_type, type); + + gst_type_mark_as_plugin_api (type, 0); + } + return g_type; +} + +GType +gst_vaapi_deinterlace_method_get_type (void) +{ + static gsize g_type = 0; + + static const GEnumValue enum_values[] = { + {GST_VAAPI_DEINTERLACE_METHOD_NONE, + "Disable deinterlacing", "none"}, + {GST_VAAPI_DEINTERLACE_METHOD_BOB, + "Bob deinterlacing", "bob"}, + {GST_VAAPI_DEINTERLACE_METHOD_WEAVE, + "Weave deinterlacing", "weave"}, + {GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE, + "Motion adaptive deinterlacing", "motion-adaptive"}, + {GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED, + "Motion compensated deinterlacing", "motion-compensated"}, + {0, NULL, NULL}, + }; + + if (g_once_init_enter (&g_type)) { + const GType type = + g_enum_register_static ("GstVaapiDeinterlaceMethod", enum_values); + gst_type_mark_as_plugin_api (type, 0); + g_once_init_leave (&g_type, type); + } + return g_type; +} + +GType +gst_vaapi_deinterlace_flags_get_type (void) +{ + static gsize g_type = 0; + + static const GEnumValue enum_values[] = { + {GST_VAAPI_DEINTERLACE_FLAG_TFF, + "Top-field first", "top-field-first"}, + {GST_VAAPI_DEINTERLACE_FLAG_ONEFIELD, + "One field", "one-field"}, + {GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD, + "Top field", "top-field"}, + {0, NULL, NULL} + }; + + if (g_once_init_enter (&g_type)) { + const GType type = + g_enum_register_static ("GstVaapiDeinterlaceFlags", enum_values); + gst_type_mark_as_plugin_api (type, 0); + g_once_init_leave (&g_type, type); + } + return g_type; +} + +/* ------------------------------------------------------------------------- */ +/* --- VPP Helpers --- */ +/* ------------------------------------------------------------------------- */ + +static VAProcFilterType * +vpp_get_filters_unlocked (GstVaapiFilter * filter, guint * num_filters_ptr) +{ + VAProcFilterType *filters = NULL; + guint num_filters = 0; + VAStatus va_status; + + num_filters = VAProcFilterCount; + filters = g_malloc_n (num_filters, sizeof (*filters)); + if (!filters) + goto error; + + va_status = vaQueryVideoProcFilters (filter->va_display, filter->va_context, + filters, &num_filters); + + // Try to reallocate to the expected number of filters + if (va_status == VA_STATUS_ERROR_MAX_NUM_EXCEEDED) { + VAProcFilterType *const new_filters = + g_try_realloc_n (filters, num_filters, sizeof (*new_filters)); + if (!new_filters) + goto error; + filters = new_filters; + + va_status = vaQueryVideoProcFilters (filter->va_display, + filter->va_context, filters, &num_filters); + } + if (!vaapi_check_status (va_status, "vaQueryVideoProcFilters()")) + goto error; + + *num_filters_ptr = num_filters; + return filters; + + /* ERRORS */ +error: + { + g_free (filters); + return NULL; + } +} + +static VAProcFilterType * +vpp_get_filters (GstVaapiFilter * filter, guint * num_filters_ptr) +{ + VAProcFilterType *filters; + + GST_VAAPI_DISPLAY_LOCK (filter->display); + filters = vpp_get_filters_unlocked (filter, num_filters_ptr); + GST_VAAPI_DISPLAY_UNLOCK (filter->display); + return filters; +} + +static gpointer +vpp_get_filter_caps_unlocked (GstVaapiFilter * filter, VAProcFilterType type, + guint cap_size, guint * num_caps_ptr) +{ + gpointer caps; + guint num_caps = 1; + VAStatus va_status; + + caps = g_malloc (cap_size); + if (!caps) + goto error; + + va_status = vaQueryVideoProcFilterCaps (filter->va_display, + filter->va_context, type, caps, &num_caps); + + // Try to reallocate to the expected number of filters + if (va_status == VA_STATUS_ERROR_MAX_NUM_EXCEEDED) { + gpointer const new_caps = g_try_realloc_n (caps, num_caps, cap_size); + if (!new_caps) + goto error; + caps = new_caps; + + va_status = vaQueryVideoProcFilterCaps (filter->va_display, + filter->va_context, type, caps, &num_caps); + } + if (!vaapi_check_status (va_status, "vaQueryVideoProcFilterCaps()")) + goto error; + + *num_caps_ptr = num_caps; + return caps; + + /* ERRORS */ +error: + { + g_free (caps); + return NULL; + } +} + +static gpointer +vpp_get_filter_caps (GstVaapiFilter * filter, VAProcFilterType type, + guint cap_size, guint * num_caps_ptr) +{ + gpointer caps; + + GST_VAAPI_DISPLAY_LOCK (filter->display); + caps = vpp_get_filter_caps_unlocked (filter, type, cap_size, num_caps_ptr); + GST_VAAPI_DISPLAY_UNLOCK (filter->display); + return caps; +} + +static void +vpp_get_pipeline_caps_unlocked (GstVaapiFilter * filter) +{ +#if VA_CHECK_VERSION(1,1,0) + VAProcPipelineCaps pipeline_caps = { 0, }; + + VAStatus va_status = vaQueryVideoProcPipelineCaps (filter->va_display, + filter->va_context, NULL, 0, &pipeline_caps); + + if (vaapi_check_status (va_status, "vaQueryVideoProcPipelineCaps()")) { + filter->mirror_flags = pipeline_caps.mirror_flags; + filter->rotation_flags = pipeline_caps.rotation_flags; + return; + } +#endif + + filter->mirror_flags = 0; + filter->rotation_flags = 0; +} + +static void +vpp_get_pipeline_caps (GstVaapiFilter * filter) +{ + GST_VAAPI_DISPLAY_LOCK (filter->display); + vpp_get_pipeline_caps_unlocked (filter); + GST_VAAPI_DISPLAY_UNLOCK (filter->display); +} + +/* ------------------------------------------------------------------------- */ +/* --- VPP Operations --- */ +/* ------------------------------------------------------------------------- */ + +#define DEFAULT_FORMAT GST_VIDEO_FORMAT_UNKNOWN + +#define OP_DATA_DEFAULT_VALUE(type, op_data) \ + g_value_get_##type (g_param_spec_get_default_value (op_data->pspec)) + +#define OP_RET_DEFAULT_VALUE(type, filter, op) \ + do { \ + g_return_val_if_fail (filter != NULL, FALSE); \ + return OP_DATA_DEFAULT_VALUE (type, find_operation (filter, op)); \ + } while (0) + +enum +{ + PROP_DISPLAY = 1, +}; + +enum +{ + PROP_0, + + PROP_FORMAT = GST_VAAPI_FILTER_OP_FORMAT, + PROP_CROP = GST_VAAPI_FILTER_OP_CROP, + PROP_DENOISE = GST_VAAPI_FILTER_OP_DENOISE, + PROP_SHARPEN = GST_VAAPI_FILTER_OP_SHARPEN, + PROP_HUE = GST_VAAPI_FILTER_OP_HUE, + PROP_SATURATION = GST_VAAPI_FILTER_OP_SATURATION, + PROP_BRIGHTNESS = GST_VAAPI_FILTER_OP_BRIGHTNESS, + PROP_CONTRAST = GST_VAAPI_FILTER_OP_CONTRAST, + PROP_DEINTERLACING = GST_VAAPI_FILTER_OP_DEINTERLACING, + PROP_SCALING = GST_VAAPI_FILTER_OP_SCALING, + PROP_VIDEO_DIRECTION = GST_VAAPI_FILTER_OP_VIDEO_DIRECTION, + PROP_HDR_TONE_MAP = GST_VAAPI_FILTER_OP_HDR_TONE_MAP, +#ifndef GST_REMOVE_DEPRECATED + PROP_SKINTONE = GST_VAAPI_FILTER_OP_SKINTONE, +#endif + PROP_SKINTONE_LEVEL = GST_VAAPI_FILTER_OP_SKINTONE_LEVEL, + + N_PROPERTIES +}; + +static GParamSpec *g_properties[N_PROPERTIES] = { NULL, }; + +static gsize g_properties_initialized = FALSE; + +static void +init_properties (void) +{ + /** + * GstVaapiFilter:format: + * + * The forced output pixel format, expressed as a #GstVideoFormat. + */ + g_properties[PROP_FORMAT] = g_param_spec_enum ("format", + "Format", + "The forced output pixel format", + GST_TYPE_VIDEO_FORMAT, + DEFAULT_FORMAT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * GstVaapiFilter:crop-rect: + * + * The cropping rectangle, expressed as a #GstVaapiRectangle. + */ + g_properties[PROP_CROP] = g_param_spec_boxed ("crop-rect", + "Cropping Rectangle", + "The cropping rectangle", + GST_VAAPI_TYPE_RECTANGLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * GstVaapiFilter:denoise: + * + * The level of noise reduction to apply. + */ + g_properties[PROP_DENOISE] = g_param_spec_float ("denoise", + "Denoising Level", + "The level of denoising to apply", + 0.0, 1.0, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * GstVaapiFilter:sharpen: + * + * The level of sharpening to apply for positive values, or the + * level of blurring for negative values. + */ + g_properties[PROP_SHARPEN] = g_param_spec_float ("sharpen", + "Sharpening Level", + "The level of sharpening/blurring to apply", + -1.0, 1.0, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * GstVaapiFilter:hue: + * + * The color hue, expressed as a float value. Range is -180.0 to + * 180.0. Default value is 0.0 and represents no modification. + */ + g_properties[PROP_HUE] = g_param_spec_float ("hue", + "Hue", + "The color hue value", + -180.0, 180.0, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * GstVaapiFilter:saturation: + * + * The color saturation, expressed as a float value. Range is 0.0 to + * 2.0. Default value is 1.0 and represents no modification. + */ + g_properties[PROP_SATURATION] = g_param_spec_float ("saturation", + "Saturation", + "The color saturation value", + 0.0, 2.0, 1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * GstVaapiFilter:brightness: + * + * The color brightness, expressed as a float value. Range is -1.0 + * to 1.0. Default value is 0.0 and represents no modification. + */ + g_properties[PROP_BRIGHTNESS] = g_param_spec_float ("brightness", + "Brightness", + "The color brightness value", + -1.0, 1.0, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * GstVaapiFilter:contrast: + * + * The color contrast, expressed as a float value. Range is 0.0 to + * 2.0. Default value is 1.0 and represents no modification. + */ + g_properties[PROP_CONTRAST] = g_param_spec_float ("contrast", + "Contrast", + "The color contrast value", + 0.0, 2.0, 1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * GstVaapiFilter:deinterlace-method: + * + * The deinterlacing algorithm to apply, expressed a an enum + * value. See #GstVaapiDeinterlaceMethod. + */ + g_properties[PROP_DEINTERLACING] = g_param_spec_enum ("deinterlace", + "Deinterlacing Method", + "Deinterlacing method to apply", + GST_VAAPI_TYPE_DEINTERLACE_METHOD, + GST_VAAPI_DEINTERLACE_METHOD_NONE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * GstVaapiFilter:scale-method: + * + * The scaling method to use, expressed as an enum value. See + * #GstVaapiScaleMethod. + */ + g_properties[PROP_SCALING] = g_param_spec_enum ("scale-method", + "Scaling Method", + "Scaling method to use", + GST_VAAPI_TYPE_SCALE_METHOD, + GST_VAAPI_SCALE_METHOD_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * GstVaapiFilter:video-direction: + * + * The video-direction to use, expressed as an enum value. See + * #GstVideoOrientationMethod. + */ + g_properties[PROP_VIDEO_DIRECTION] = g_param_spec_enum ("video-direction", + "Video Direction", + "Video direction: rotation and flipping", + GST_TYPE_VIDEO_ORIENTATION_METHOD, + GST_VIDEO_ORIENTATION_IDENTITY, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * GstVaapiFilter:tone-map: + * + * Apply HDR tone mapping + **/ + g_properties[PROP_HDR_TONE_MAP] = g_param_spec_boolean ("hdr-tone-map", + "HDR Tone Mapping", + "Apply HDR tone mapping", + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + +#ifndef GST_REMOVE_DEPRECATED + /** + * GstVaapiFilter:skin-tone-enhancement: + * + * Apply the skin tone enhancement algorithm. + */ + g_properties[PROP_SKINTONE] = g_param_spec_boolean ("skin-tone-enhancement", + "Skin tone enhancement", + "Apply the skin tone enhancement algorithm", + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); +#endif + + /** + * GstVaapiFilter:skin-tone-enhancement-level: + * + * Apply the skin tone enhancement algorithm with specified value. + */ + g_properties[PROP_SKINTONE_LEVEL] = + g_param_spec_uint ("skin-tone-enhancement-level", + "Skin tone enhancement level", + "Apply the skin tone enhancement algorithm with specified level", 0, 9, 3, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); +} + +static void +ensure_properties (void) +{ + if (g_once_init_enter (&g_properties_initialized)) { + init_properties (); + g_once_init_leave (&g_properties_initialized, TRUE); + } +} + +static void +op_data_free (GstVaapiFilterOpData * op_data) +{ + g_free (op_data->va_caps); + g_slice_free (GstVaapiFilterOpData, op_data); +} + +static inline gpointer +op_data_new (GstVaapiFilterOp op, GParamSpec * pspec) +{ + GstVaapiFilterOpData *op_data; + + op_data = g_slice_new0 (GstVaapiFilterOpData); + if (!op_data) + return NULL; + + op_data->op = op; + op_data->pspec = pspec; + g_atomic_int_set (&op_data->ref_count, 1); + op_data->va_buffer = VA_INVALID_ID; + + switch (op) { + case GST_VAAPI_FILTER_OP_HDR_TONE_MAP: +#if VA_CHECK_VERSION(1,4,0) + /* Only HDR10 tone mapping is supported */ + op_data->va_type = VAProcFilterHighDynamicRangeToneMapping; + op_data->va_subtype = VAProcHighDynamicRangeMetadataHDR10; + op_data->va_cap_size = sizeof (VAProcFilterCapHighDynamicRange); + op_data->va_buffer_size = + sizeof (VAProcFilterParameterBufferHDRToneMapping); + break; +#else + /* fall-through */ +#endif + case GST_VAAPI_FILTER_OP_FORMAT: + case GST_VAAPI_FILTER_OP_CROP: + case GST_VAAPI_FILTER_OP_SCALING: + case GST_VAAPI_FILTER_OP_VIDEO_DIRECTION: + op_data->va_type = VAProcFilterNone; + break; + case GST_VAAPI_FILTER_OP_DENOISE: + op_data->va_type = VAProcFilterNoiseReduction; + op_data->va_cap_size = sizeof (VAProcFilterCap); + op_data->va_buffer_size = sizeof (VAProcFilterParameterBuffer); + break; + case GST_VAAPI_FILTER_OP_SHARPEN: + op_data->va_type = VAProcFilterSharpening; + op_data->va_cap_size = sizeof (VAProcFilterCap); + op_data->va_buffer_size = sizeof (VAProcFilterParameterBuffer); + break; +#ifndef GST_REMOVE_DEPRECATED + case GST_VAAPI_FILTER_OP_SKINTONE: +#endif + case GST_VAAPI_FILTER_OP_SKINTONE_LEVEL: + op_data->va_type = VAProcFilterSkinToneEnhancement; + op_data->va_buffer_size = sizeof (VAProcFilterParameterBuffer); + break; + case GST_VAAPI_FILTER_OP_HUE: + op_data->va_subtype = VAProcColorBalanceHue; + goto op_colorbalance; + case GST_VAAPI_FILTER_OP_SATURATION: + op_data->va_subtype = VAProcColorBalanceSaturation; + goto op_colorbalance; + case GST_VAAPI_FILTER_OP_BRIGHTNESS: + op_data->va_subtype = VAProcColorBalanceBrightness; + goto op_colorbalance; + case GST_VAAPI_FILTER_OP_CONTRAST: + op_data->va_subtype = VAProcColorBalanceContrast; + op_colorbalance: + op_data->va_type = VAProcFilterColorBalance; + op_data->va_cap_size = sizeof (VAProcFilterCapColorBalance); + op_data->va_buffer_size = + sizeof (VAProcFilterParameterBufferColorBalance); + break; + case GST_VAAPI_FILTER_OP_DEINTERLACING: + op_data->va_type = VAProcFilterDeinterlacing; + op_data->va_cap_size = sizeof (VAProcFilterCapDeinterlacing); + op_data->va_buffer_size = + sizeof (VAProcFilterParameterBufferDeinterlacing); + break; + default: + g_assert (0 && "unsupported operation"); + goto error; + } + return op_data; + + /* ERRORS */ +error: + { + op_data_free (op_data); + return NULL; + } +} + +static inline gpointer +op_data_ref (gpointer data) +{ + GstVaapiFilterOpData *const op_data = data; + + g_return_val_if_fail (op_data != NULL, NULL); + + g_atomic_int_inc (&op_data->ref_count); + return op_data; +} + +static void +op_data_unref (gpointer data) +{ + GstVaapiFilterOpData *const op_data = data; + + g_return_if_fail (op_data != NULL); + g_return_if_fail (op_data->ref_count > 0); + + if (g_atomic_int_dec_and_test (&op_data->ref_count)) + op_data_free (op_data); +} + +/* Ensure capability info is set up for the VA filter we are interested in */ +static gboolean +op_data_ensure_caps (GstVaapiFilterOpData * op_data, gpointer filter_caps, + guint num_filter_caps) +{ + guchar *filter_cap = filter_caps; + guint i, va_num_caps = num_filter_caps; + + // Find the VA filter cap matching the op info sub-type + if (op_data->va_subtype) { + for (i = 0; i < num_filter_caps; i++) { + /* XXX: sub-type shall always be the first field */ + if (op_data->va_subtype == *(guint *) filter_cap) { + va_num_caps = 1; + break; + } + filter_cap += op_data->va_cap_size; + } + if (i == num_filter_caps) + return FALSE; + } + + op_data->va_caps = g_memdup2 (filter_cap, op_data->va_cap_size * va_num_caps); + if (!op_data->va_caps) + return FALSE; + + op_data->va_num_caps = va_num_caps; + return TRUE; +} + +/* Scale the filter value wrt. library spec and VA driver spec */ +static gboolean +op_data_get_value_float (GstVaapiFilterOpData * op_data, + const VAProcFilterValueRange * range, gfloat value, gfloat * out_value_ptr) +{ + GParamSpecFloat *const pspec = G_PARAM_SPEC_FLOAT (op_data->pspec); + gfloat out_value; + + g_return_val_if_fail (range != NULL, FALSE); + g_return_val_if_fail (out_value_ptr != NULL, FALSE); + + if (value < pspec->minimum || value > pspec->maximum) + return FALSE; + + // Scale wrt. the medium ("default") value + out_value = range->default_value; + if (value > pspec->default_value) + out_value += ((value - pspec->default_value) / + (pspec->maximum - pspec->default_value) * + (range->max_value - range->default_value)); + else if (value < pspec->default_value) + out_value -= ((pspec->default_value - value) / + (pspec->default_value - pspec->minimum) * + (range->default_value - range->min_value)); + + *out_value_ptr = out_value; + return TRUE; +} + +/* Get default list of operations supported by the library */ +static GPtrArray * +get_operations_default (void) +{ + GPtrArray *ops; + guint i; + + ops = g_ptr_array_new_full (N_PROPERTIES, op_data_unref); + if (!ops) + return NULL; + + ensure_properties (); + + for (i = 0; i < N_PROPERTIES; i++) { + GstVaapiFilterOpData *op_data; + GParamSpec *const pspec = g_properties[i]; + if (!pspec) + continue; + + op_data = op_data_new (i, pspec); + if (!op_data) + goto error; + g_ptr_array_add (ops, op_data); + } + return ops; + + /* ERRORS */ +error: + { + g_ptr_array_unref (ops); + return NULL; + } +} + +/* Get the ordered list of operations, based on VA/VPP queries */ +static GPtrArray * +get_operations_ordered (GstVaapiFilter * filter, GPtrArray * default_ops) +{ + GPtrArray *ops; + VAProcFilterType *filters; + gpointer filter_caps = NULL; + guint i, j, num_filters, num_filter_caps = 0; + + ops = g_ptr_array_new_full (default_ops->len, op_data_unref); + if (!ops) + return NULL; + + filters = vpp_get_filters (filter, &num_filters); + if (!filters) + goto error; + + // Append virtual ops first, i.e. those without an associated VA filter + for (i = 0; i < default_ops->len; i++) { + GstVaapiFilterOpData *const op_data = g_ptr_array_index (default_ops, i); + if (op_data->va_type == VAProcFilterNone) + g_ptr_array_add (ops, op_data_ref (op_data)); + } + + // Append ops, while preserving the VA filters ordering + for (i = 0; i < num_filters; i++) { + const VAProcFilterType va_type = filters[i]; + if (va_type == VAProcFilterNone) + continue; + + for (j = 0; j < default_ops->len; j++) { + GstVaapiFilterOpData *const op_data = g_ptr_array_index (default_ops, j); + if (op_data->va_type != va_type) + continue; + + if (op_data->va_cap_size == 0) { /* no caps, like skintone */ + g_ptr_array_add (ops, op_data_ref (op_data)); + continue; + } + + if (!filter_caps) { + filter_caps = vpp_get_filter_caps (filter, va_type, + op_data->va_cap_size, &num_filter_caps); + if (!filter_caps) + goto error; + } + if (!op_data_ensure_caps (op_data, filter_caps, num_filter_caps)) + goto error; + g_ptr_array_add (ops, op_data_ref (op_data)); + } + free (filter_caps); + filter_caps = NULL; + } + + vpp_get_pipeline_caps (filter); + + if (filter->operations) + g_ptr_array_unref (filter->operations); + filter->operations = g_ptr_array_ref (ops); + + g_free (filters); + g_ptr_array_unref (default_ops); + return ops; + + /* ERRORS */ +error: + { + g_free (filter_caps); + g_free (filters); + g_ptr_array_unref (ops); + g_ptr_array_unref (default_ops); + return NULL; + } +} + +/* Determine the set of supported VPP operations by the specific + filter, or known to this library if filter is NULL */ +static GPtrArray * +get_operations (GstVaapiFilter * filter) +{ + GPtrArray *ops; + + if (filter && filter->operations) + return g_ptr_array_ref (filter->operations); + + ops = get_operations_default (); + if (!ops) + return NULL; + return filter ? get_operations_ordered (filter, ops) : ops; +} + +/* Ensure the set of supported VPP operations is cached into the + GstVaapiFilter::operations member */ +static inline gboolean +ensure_operations (GstVaapiFilter * filter) +{ + GPtrArray *ops; + + if (!filter) + return FALSE; + + if (filter->operations) + return TRUE; + + ops = get_operations (filter); + if (!ops) + return FALSE; + + g_ptr_array_unref (ops); + return TRUE; +} + +/* Find whether the VPP operation is supported or not */ +static GstVaapiFilterOpData * +find_operation (GstVaapiFilter * filter, GstVaapiFilterOp op) +{ + guint i; + + if (!ensure_operations (filter)) + return NULL; + + for (i = 0; i < filter->operations->len; i++) { + GstVaapiFilterOpData *const op_data = + g_ptr_array_index (filter->operations, i); + if (op_data->op == op) + return op_data; + } + return NULL; +} + +/* Ensure the operation's VA buffer is allocated */ +static inline gboolean +op_ensure_n_elements_buffer (GstVaapiFilter * filter, + GstVaapiFilterOpData * op_data, gint op_num) +{ + if (G_LIKELY (op_data->va_buffer != VA_INVALID_ID)) + return TRUE; + return vaapi_create_n_elements_buffer (filter->va_display, filter->va_context, + VAProcFilterParameterBufferType, op_data->va_buffer_size, NULL, + &op_data->va_buffer, NULL, op_num); +} + +static inline gboolean +op_ensure_buffer (GstVaapiFilter * filter, GstVaapiFilterOpData * op_data) +{ + return op_ensure_n_elements_buffer (filter, op_data, 1); +} + +/* Update a generic filter (float value) */ +static gboolean +op_set_generic_unlocked (GstVaapiFilter * filter, + GstVaapiFilterOpData * op_data, gfloat value) +{ + VAProcFilterParameterBuffer *buf; + VAProcFilterCap *filter_cap; + gfloat va_value; + + if (!op_data || !op_ensure_buffer (filter, op_data)) + return FALSE; + + op_data->is_enabled = (value != OP_DATA_DEFAULT_VALUE (float, op_data)); + if (!op_data->is_enabled) + return TRUE; + + filter_cap = op_data->va_caps; + if (!op_data_get_value_float (op_data, &filter_cap->range, value, &va_value)) + return FALSE; + + buf = vaapi_map_buffer (filter->va_display, op_data->va_buffer); + if (!buf) + return FALSE; + + buf->type = op_data->va_type; + buf->value = va_value; + vaapi_unmap_buffer (filter->va_display, op_data->va_buffer, NULL); + return TRUE; +} + +static inline gboolean +op_set_generic (GstVaapiFilter * filter, GstVaapiFilterOpData * op_data, + gfloat value) +{ + gboolean success = FALSE; + + GST_VAAPI_DISPLAY_LOCK (filter->display); + success = op_set_generic_unlocked (filter, op_data, value); + GST_VAAPI_DISPLAY_UNLOCK (filter->display); + return success; +} + +/* Update the color balance filter */ +#define COLOR_BALANCE_NUM \ + GST_VAAPI_FILTER_OP_CONTRAST - GST_VAAPI_FILTER_OP_HUE + 1 + +static gboolean +op_set_color_balance_unlocked (GstVaapiFilter * filter, + GstVaapiFilterOpData * op_data, gfloat value) +{ + VAProcFilterParameterBufferColorBalance *buf; + VAProcFilterCapColorBalance *filter_cap; + gfloat va_value; + gint i; + GstVaapiFilterOpData *color_data[COLOR_BALANCE_NUM]; + GstVaapiFilterOpData *enabled_data = NULL; + gboolean ret = TRUE; + + if (!op_data) + return FALSE; + + /* collect all the Color Balance operators and find the first + * enabled one */ + for (i = 0; i < COLOR_BALANCE_NUM; i++) { + color_data[i] = find_operation (filter, GST_VAAPI_FILTER_OP_HUE + i); + if (!color_data[i]) + return FALSE; + + if (!enabled_data && color_data[i]->is_enabled) + enabled_data = color_data[i]; + } + + /* If there's no enabled operators let's enable this one. + * + * HACK: This operator will be the only one with an allocated buffer + * which will store all the color balance operators. + */ + if (!enabled_data) { + /* *INDENT-OFF* */ + if (value == OP_DATA_DEFAULT_VALUE (float, op_data)) + return TRUE; + /* *INDENT-ON* */ + + if (!op_ensure_n_elements_buffer (filter, op_data, COLOR_BALANCE_NUM)) + return FALSE; + + enabled_data = op_data; + + buf = vaapi_map_buffer (filter->va_display, enabled_data->va_buffer); + if (!buf) + return FALSE; + + /* Write all the color balance operator values in the buffer. -- + * Use the default value for all the operators except the set + * one. */ + for (i = 0; i < COLOR_BALANCE_NUM; i++) { + buf[i].type = color_data[i]->va_type; + buf[i].attrib = color_data[i]->va_subtype; + + va_value = OP_DATA_DEFAULT_VALUE (float, color_data[i]); + if (color_data[i]->op == op_data->op) { + filter_cap = color_data[i]->va_caps; + /* fail but ignore current value and set default one */ + if (!op_data_get_value_float (color_data[i], &filter_cap->range, value, + &va_value)) + ret = FALSE; + } + + buf[i].value = va_value; + } + + enabled_data->is_enabled = 1; + } else { + /* There's already one operator enabled, *in theory* with a + * buffer associated. */ + if (G_UNLIKELY (enabled_data->va_buffer == VA_INVALID_ID)) + return FALSE; + + filter_cap = op_data->va_caps; + if (!op_data_get_value_float (op_data, &filter_cap->range, value, + &va_value)) + return FALSE; + + buf = vaapi_map_buffer (filter->va_display, enabled_data->va_buffer); + if (!buf) + return FALSE; + + buf[op_data->op - GST_VAAPI_FILTER_OP_HUE].value = va_value; + } + + vaapi_unmap_buffer (filter->va_display, enabled_data->va_buffer, NULL); + + return ret; +} + +static inline gboolean +op_set_color_balance (GstVaapiFilter * filter, GstVaapiFilterOpData * op_data, + gfloat value) +{ + gboolean success = FALSE; + + GST_VAAPI_DISPLAY_LOCK (filter->display); + success = op_set_color_balance_unlocked (filter, op_data, value); + GST_VAAPI_DISPLAY_UNLOCK (filter->display); + return success; +} + +/* Update deinterlace filter */ +static gboolean +op_set_deinterlace_unlocked (GstVaapiFilter * filter, + GstVaapiFilterOpData * op_data, GstVaapiDeinterlaceMethod method, + guint flags) +{ + VAProcFilterParameterBufferDeinterlacing *buf; + const VAProcFilterCapDeinterlacing *filter_caps; + VAProcDeinterlacingType algorithm; + guint i; + + if (!op_data || !op_ensure_buffer (filter, op_data)) + return FALSE; + + op_data->is_enabled = (method != GST_VAAPI_DEINTERLACE_METHOD_NONE); + if (!op_data->is_enabled) + return TRUE; + + algorithm = from_GstVaapiDeinterlaceMethod (method); + for (i = 0, filter_caps = op_data->va_caps; i < op_data->va_num_caps; i++) { + if (filter_caps[i].type == algorithm) + break; + } + if (i == op_data->va_num_caps) + return FALSE; + + buf = vaapi_map_buffer (filter->va_display, op_data->va_buffer); + if (!buf) + return FALSE; + + buf->type = op_data->va_type; + buf->algorithm = algorithm; + buf->flags = from_GstVaapiDeinterlaceFlags (flags); + vaapi_unmap_buffer (filter->va_display, op_data->va_buffer, NULL); + return TRUE; +} + +static inline gboolean +op_set_deinterlace (GstVaapiFilter * filter, GstVaapiFilterOpData * op_data, + GstVaapiDeinterlaceMethod method, guint flags) +{ + gboolean success = FALSE; + + GST_VAAPI_DISPLAY_LOCK (filter->display); + success = op_set_deinterlace_unlocked (filter, op_data, method, flags); + GST_VAAPI_DISPLAY_UNLOCK (filter->display); + return success; +} + +/* Update skin tone enhancement level */ +static gboolean +op_set_skintone_level_unlocked (GstVaapiFilter * filter, + GstVaapiFilterOpData * op_data, guint value) +{ + VAProcFilterParameterBuffer *buf; + + if (!op_data || !op_ensure_buffer (filter, op_data)) + return FALSE; + + op_data->is_enabled = 1; + + buf = vaapi_map_buffer (filter->va_display, op_data->va_buffer); + if (!buf) + return FALSE; + buf->type = op_data->va_type; + buf->value = value; + vaapi_unmap_buffer (filter->va_display, op_data->va_buffer, NULL); + return TRUE; +} + +static inline gboolean +op_set_skintone_level (GstVaapiFilter * filter, + GstVaapiFilterOpData * op_data, guint value) +{ + gboolean success = FALSE; + + GST_VAAPI_DISPLAY_LOCK (filter->display); + success = op_set_skintone_level_unlocked (filter, op_data, value); + GST_VAAPI_DISPLAY_UNLOCK (filter->display); + return success; +} + +#ifndef GST_REMOVE_DEPRECATED +/* Update skin tone enhancement */ +static gboolean +op_set_skintone_unlocked (GstVaapiFilter * filter, + GstVaapiFilterOpData * op_data, gboolean value) +{ + if (!op_data) + return FALSE; + + if (!value) { + op_data->is_enabled = 0; + return TRUE; + } + + return op_set_skintone_level_unlocked (filter, op_data, 3); +} + +static inline gboolean +op_set_skintone (GstVaapiFilter * filter, GstVaapiFilterOpData * op_data, + gboolean enhance) +{ + gboolean success = FALSE; + + GST_VAAPI_DISPLAY_LOCK (filter->display); + success = op_set_skintone_unlocked (filter, op_data, enhance); + GST_VAAPI_DISPLAY_UNLOCK (filter->display); + return success; +} +#endif + +static gboolean +op_set_hdr_tone_map_unlocked (GstVaapiFilter * filter, + GstVaapiFilterOpData * op_data, gboolean value) +{ +#if VA_CHECK_VERSION(1,4,0) + const VAProcFilterCapHighDynamicRange *filter_caps; + guint i; + + if (!op_data) + return !value; + + if (!value) { + op_data->is_enabled = 0; + return TRUE; + } + + if (!op_ensure_buffer (filter, op_data)) + return FALSE; + + for (i = 0, filter_caps = op_data->va_caps; i < op_data->va_num_caps; i++) { + if (filter_caps[i].metadata_type == op_data->va_subtype && + (filter_caps[i].caps_flag & VA_TONE_MAPPING_HDR_TO_SDR)) + break; + } + if (i == op_data->va_num_caps) + return FALSE; + + op_data->is_enabled = 1; + + return TRUE; +#else + return !value; +#endif +} + +static inline gboolean +op_set_hdr_tone_map (GstVaapiFilter * filter, GstVaapiFilterOpData * op_data, + gboolean value) +{ + gboolean success = FALSE; + GST_VAAPI_DISPLAY_LOCK (filter->display); + success = op_set_hdr_tone_map_unlocked (filter, op_data, value); + GST_VAAPI_DISPLAY_UNLOCK (filter->display); + + return success; +} + +static gboolean +deint_refs_set (GArray * refs, GstVaapiSurface ** surfaces, guint num_surfaces) +{ + guint i; + + if (num_surfaces > 0 && !surfaces) + return FALSE; + + for (i = 0; i < num_surfaces; i++) + g_array_append_val (refs, GST_VAAPI_SURFACE_ID (surfaces[i])); + return TRUE; +} + +static void +deint_refs_clear (GArray * refs) +{ + if (refs->len > 0) + g_array_remove_range (refs, 0, refs->len); +} + +static inline void +deint_refs_clear_all (GstVaapiFilter * filter) +{ + deint_refs_clear (filter->forward_references); + deint_refs_clear (filter->backward_references); +} + +/* ------------------------------------------------------------------------- */ +/* --- Surface Attribs --- */ +/* ------------------------------------------------------------------------- */ + +static gboolean +ensure_attributes (GstVaapiFilter * filter) +{ + if (G_LIKELY (filter->attribs)) + return TRUE; + + filter->attribs = gst_vaapi_config_surface_attributes_get (filter->display, + filter->va_config); + return (filter->attribs != NULL); +} + +static inline gboolean +is_special_format (GstVideoFormat format) +{ + return format == GST_VIDEO_FORMAT_UNKNOWN || + format == GST_VIDEO_FORMAT_ENCODED; +} + +static gboolean +find_format (GstVaapiFilter * filter, GstVideoFormat format) +{ + guint i; + GArray *formats; + + formats = filter->attribs->formats; + if (is_special_format (format) || !formats) + return FALSE; + + for (i = 0; i < formats->len; i++) { + if (g_array_index (formats, GstVideoFormat, i) == format) + return TRUE; + } + return FALSE; +} + +/* ------------------------------------------------------------------------- */ +/* --- Interface --- */ +/* ------------------------------------------------------------------------- */ + +static void +gst_vaapi_filter_init (GstVaapiFilter * filter) +{ + filter->va_config = VA_INVALID_ID; + filter->va_context = VA_INVALID_ID; + filter->format = DEFAULT_FORMAT; + + filter->forward_references = + g_array_sized_new (FALSE, FALSE, sizeof (VASurfaceID), 4); + + filter->backward_references = + g_array_sized_new (FALSE, FALSE, sizeof (VASurfaceID), 4); +} + +static gboolean +gst_vaapi_filter_initialize (GstVaapiFilter * filter) +{ + VAStatus va_status; + + if (!filter->display) + return FALSE; + + va_status = vaCreateConfig (filter->va_display, VAProfileNone, + VAEntrypointVideoProc, NULL, 0, &filter->va_config); + if (!vaapi_check_status (va_status, "vaCreateConfig() [VPP]")) + return FALSE; + + va_status = vaCreateContext (filter->va_display, filter->va_config, 0, 0, 0, + NULL, 0, &filter->va_context); + if (!vaapi_check_status (va_status, "vaCreateContext() [VPP]")) + return FALSE; + + gst_video_colorimetry_from_string (&filter->input_colorimetry, NULL); + gst_video_colorimetry_from_string (&filter->output_colorimetry, NULL); + + return TRUE; +} + +static void +gst_vaapi_filter_finalize (GObject * object) +{ + GstVaapiFilter *const filter = GST_VAAPI_FILTER (object); + guint i; + + if (!filter->display) + goto bail; + + GST_VAAPI_DISPLAY_LOCK (filter->display); + if (filter->operations) { + for (i = 0; i < filter->operations->len; i++) { + GstVaapiFilterOpData *const op_data = + g_ptr_array_index (filter->operations, i); + vaapi_destroy_buffer (filter->va_display, &op_data->va_buffer); + } + g_ptr_array_unref (filter->operations); + filter->operations = NULL; + } + + if (filter->va_context != VA_INVALID_ID) { + vaDestroyContext (filter->va_display, filter->va_context); + filter->va_context = VA_INVALID_ID; + } + + if (filter->va_config != VA_INVALID_ID) { + vaDestroyConfig (filter->va_display, filter->va_config); + filter->va_config = VA_INVALID_ID; + } + GST_VAAPI_DISPLAY_UNLOCK (filter->display); + gst_vaapi_display_replace (&filter->display, NULL); + +bail: + if (filter->forward_references) { + g_array_unref (filter->forward_references); + filter->forward_references = NULL; + } + + if (filter->backward_references) { + g_array_unref (filter->backward_references); + filter->backward_references = NULL; + } + + if (filter->attribs) { + gst_vaapi_config_surface_attributes_free (filter->attribs); + filter->attribs = NULL; + } + + G_OBJECT_CLASS (gst_vaapi_filter_parent_class)->finalize (object); +} + +static void +gst_vaapi_filter_set_property (GObject * object, guint property_id, + const GValue * value, GParamSpec * pspec) +{ + GstVaapiFilter *const filter = GST_VAAPI_FILTER (object); + + switch (property_id) { + case PROP_DISPLAY:{ + GstVaapiDisplay *display = g_value_get_object (value);; + + if (display) { + if (GST_VAAPI_DISPLAY_HAS_VPP (display)) { + filter->display = gst_object_ref (display); + filter->va_display = GST_VAAPI_DISPLAY_VADISPLAY (filter->display); + } else { + GST_WARNING_OBJECT (filter, "VA display doesn't support VPP"); + } + } + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +gst_vaapi_filter_get_property (GObject * object, guint property_id, + GValue * value, GParamSpec * pspec) +{ + GstVaapiFilter *const filter = GST_VAAPI_FILTER (object); + + switch (property_id) { + case PROP_DISPLAY: + g_value_set_object (value, filter->display); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +gst_vaapi_filter_class_init (GstVaapiFilterClass * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = gst_vaapi_filter_set_property; + object_class->get_property = gst_vaapi_filter_get_property; + object_class->finalize = gst_vaapi_filter_finalize; + + /** + * GstVaapiFilter:display: + * + * #GstVaapiDisplay to be used. + */ + g_object_class_install_property (object_class, PROP_DISPLAY, + g_param_spec_object ("display", "Gst VA-API Display", + "The VA-API display object to use", GST_TYPE_VAAPI_DISPLAY, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME)); +} + +/** + * gst_vaapi_filter_new: + * @display: a #GstVaapiDisplay + * + * Creates a new #GstVaapiFilter set up to operate in "identity" + * mode. This means that no other operation than scaling is performed. + * + * Return value: the newly created #GstVaapiFilter object + */ +GstVaapiFilter * +gst_vaapi_filter_new (GstVaapiDisplay * display) +{ + GstVaapiFilter *filter; + + filter = g_object_new (GST_TYPE_VAAPI_FILTER, "display", display, NULL); + if (!gst_vaapi_filter_initialize (filter)) + goto error; + return filter; + + /* ERRORS */ +error: + { + gst_object_unref (filter); + return NULL; + } +} + +/** + * gst_vaapi_filter_replace: + * @old_filter_ptr: a pointer to a #GstVaapiFilter + * @new_filter: a #GstVaapiFilter + * + * Atomically replaces the filter held in @old_filter_ptr with + * @new_filter. This means that @old_filter_ptr shall reference a + * valid filter. However, @new_filter can be NULL. + */ +void +gst_vaapi_filter_replace (GstVaapiFilter ** old_filter_ptr, + GstVaapiFilter * new_filter) +{ + g_return_if_fail (old_filter_ptr != NULL); + + gst_object_replace ((GstObject **) old_filter_ptr, GST_OBJECT (new_filter)); +} + +/** + * gst_vaapi_filter_get_operations: + * @filter: a #GstVaapiFilter, or %NULL + * + * Determines the set of supported operations for video processing. + * The caller owns an extra reference to the resulting array of + * #GstVaapiFilterOpInfo elements, so it shall be released with + * g_ptr_array_unref() after usage. + * + * If @filter is %NULL, then this function returns the video + * processing operations supported by this library. + * + * Return value: the set of supported operations, or %NULL if an error + * occurred. + */ +GPtrArray * +gst_vaapi_filter_get_operations (GstVaapiFilter * filter) +{ + return get_operations (filter); +} + +/** + * gst_vaapi_filter_has_operation: + * @filter: a #GstVaapiFilter + * @op: a #GstVaapiFilterOp + * + * Determines whether the underlying VA driver advertises support for + * the supplied operation @op. + * + * Return value: %TRUE if the specified operation may be supported by + * the underlying hardware, %FALSE otherwise + */ +gboolean +gst_vaapi_filter_has_operation (GstVaapiFilter * filter, GstVaapiFilterOp op) +{ + g_return_val_if_fail (filter != NULL, FALSE); + + return find_operation (filter, op) != NULL; +} + +/** + * gst_vaapi_filter_use_operation: + * @filter: a #GstVaapiFilter + * @op: a #GstVaapiFilterOp + * + * Determines whether the supplied operation @op was already enabled + * through a prior call to gst_vaapi_filter_set_operation() or any + * other operation-specific function. + * + * Note: should an operation be set to its default value, this means + * that it is actually not enabled. + * + * Return value: %TRUE if the specified operation was already enabled, + * %FALSE otherwise + */ +gboolean +gst_vaapi_filter_use_operation (GstVaapiFilter * filter, GstVaapiFilterOp op) +{ + GstVaapiFilterOpData *op_data; + + g_return_val_if_fail (filter != NULL, FALSE); + + op_data = find_operation (filter, op); + if (!op_data) + return FALSE; + return op_data->is_enabled; +} + +/** + * gst_vaapi_filter_set_operation: + * @filter: a #GstVaapiFilter + * @op: a #GstVaapiFilterOp + * @value: the @op settings + * + * Enable the specified operation @op to be performed during video + * processing, i.e. in gst_vaapi_filter_process(). The @value argument + * specifies the operation settings. e.g. deinterlacing method for + * deinterlacing, denoising level for noise reduction, etc. + * + * If @value is %NULL, then this function resets the operation + * settings to their default values. + * + * Return value: %TRUE if the specified operation may be supported, + * %FALSE otherwise + */ +gboolean +gst_vaapi_filter_set_operation (GstVaapiFilter * filter, GstVaapiFilterOp op, + const GValue * value) +{ + GstVaapiFilterOpData *op_data; + + g_return_val_if_fail (filter != NULL, FALSE); + + op_data = find_operation (filter, op); + if (!op_data) + return FALSE; + + if (value && !G_VALUE_HOLDS (value, G_PARAM_SPEC_VALUE_TYPE (op_data->pspec))) + return FALSE; + + switch (op) { + case GST_VAAPI_FILTER_OP_FORMAT: + return gst_vaapi_filter_set_format (filter, value ? + g_value_get_enum (value) : DEFAULT_FORMAT); + case GST_VAAPI_FILTER_OP_CROP: + return gst_vaapi_filter_set_cropping_rectangle (filter, value ? + g_value_get_boxed (value) : NULL); + case GST_VAAPI_FILTER_OP_DENOISE: + case GST_VAAPI_FILTER_OP_SHARPEN: + return op_set_generic (filter, op_data, + (value ? g_value_get_float (value) : + OP_DATA_DEFAULT_VALUE (float, op_data))); + case GST_VAAPI_FILTER_OP_HUE: + case GST_VAAPI_FILTER_OP_SATURATION: + case GST_VAAPI_FILTER_OP_BRIGHTNESS: + case GST_VAAPI_FILTER_OP_CONTRAST: + return op_set_color_balance (filter, op_data, + (value ? g_value_get_float (value) : + OP_DATA_DEFAULT_VALUE (float, op_data))); + case GST_VAAPI_FILTER_OP_DEINTERLACING: + return op_set_deinterlace (filter, op_data, + (value ? g_value_get_enum (value) : + OP_DATA_DEFAULT_VALUE (enum, op_data)), 0); + break; + case GST_VAAPI_FILTER_OP_SCALING: + return gst_vaapi_filter_set_scaling (filter, + (value ? g_value_get_enum (value) : + OP_DATA_DEFAULT_VALUE (enum, op_data))); +#ifndef GST_REMOVE_DEPRECATED + case GST_VAAPI_FILTER_OP_SKINTONE: + return op_set_skintone (filter, op_data, + (value ? g_value_get_boolean (value) : + OP_DATA_DEFAULT_VALUE (boolean, op_data))); +#endif + case GST_VAAPI_FILTER_OP_SKINTONE_LEVEL: + return op_set_skintone_level (filter, op_data, + (value ? g_value_get_uint (value) : + OP_DATA_DEFAULT_VALUE (uint, op_data))); + case GST_VAAPI_FILTER_OP_VIDEO_DIRECTION: + return gst_vaapi_filter_set_video_direction (filter, + (value ? g_value_get_enum (value) : + OP_DATA_DEFAULT_VALUE (enum, op_data))); + case GST_VAAPI_FILTER_OP_HDR_TONE_MAP: + return op_set_hdr_tone_map (filter, op_data, + (value ? g_value_get_boolean (value) : + OP_DATA_DEFAULT_VALUE (boolean, op_data))); + default: + break; + } + return FALSE; +} + +#if VA_CHECK_VERSION(1,2,0) +static void +fill_color_standard (GstVideoColorimetry * colorimetry, + VAProcColorStandardType * type, VAProcColorProperties * properties) +{ + *type = from_GstVideoColorimetry (colorimetry); + + properties->colour_primaries = + gst_video_color_primaries_to_iso (colorimetry->primaries); + properties->transfer_characteristics = + gst_video_transfer_function_to_iso (colorimetry->transfer); + properties->matrix_coefficients = + gst_video_color_matrix_to_iso (colorimetry->matrix); + + properties->color_range = from_GstVideoColorRange (colorimetry->range); +} +#endif + +static void +gst_vaapi_filter_fill_color_standards (GstVaapiFilter * filter, + VAProcPipelineParameterBuffer * pipeline_param) +{ +#if VA_CHECK_VERSION(1,2,0) + fill_color_standard (&filter->input_colorimetry, + &pipeline_param->surface_color_standard, + &pipeline_param->input_color_properties); + + fill_color_standard (&filter->output_colorimetry, + &pipeline_param->output_color_standard, + &pipeline_param->output_color_properties); +#else + pipeline_param->surface_color_standard = VAProcColorStandardNone; + pipeline_param->output_color_standard = VAProcColorStandardNone; +#endif +} + +/** + * gst_vaapi_filter_process: + * @filter: a #GstVaapiFilter + * @src_surface: the source @GstVaapiSurface + * @dst_surface: the destination @GstVaapiSurface + * @flags: #GstVaapiSurfaceRenderFlags that apply to @src_surface + * + * Applies the operations currently defined in the @filter to + * @src_surface and return the output in @dst_surface. The order of + * operations is determined in a way that suits best the underlying + * hardware. i.e. the only guarantee held is the generated outcome, + * not any specific order of operations. + * + * Return value: a #GstVaapiFilterStatus + */ +static GstVaapiFilterStatus +gst_vaapi_filter_process_unlocked (GstVaapiFilter * filter, + GstVaapiSurface * src_surface, GstVaapiSurface * dst_surface, guint flags) +{ + VAProcPipelineParameterBuffer *pipeline_param = NULL; + VABufferID pipeline_param_buf_id = VA_INVALID_ID; + VABufferID filters[N_PROPERTIES]; + VAProcPipelineCaps pipeline_caps; + guint i, num_filters = 0; + VAStatus va_status; + VARectangle src_rect, dst_rect; + guint va_mirror = 0, va_rotation = 0; + + if (!ensure_operations (filter)) + return GST_VAAPI_FILTER_STATUS_ERROR_ALLOCATION_FAILED; + + /* Build surface region (source) */ + if (filter->use_crop_rect) { + const GstVaapiRectangle *const crop_rect = &filter->crop_rect; + + if ((crop_rect->x + crop_rect->width > + GST_VAAPI_SURFACE_WIDTH (src_surface)) || + (crop_rect->y + crop_rect->height > + GST_VAAPI_SURFACE_HEIGHT (src_surface))) + goto error; + + src_rect.x = crop_rect->x; + src_rect.y = crop_rect->y; + src_rect.width = crop_rect->width; + src_rect.height = crop_rect->height; + } else { + src_rect.x = 0; + src_rect.y = 0; + src_rect.width = GST_VAAPI_SURFACE_WIDTH (src_surface); + src_rect.height = GST_VAAPI_SURFACE_HEIGHT (src_surface); + } + + /* Build output region (target) */ + if (filter->use_target_rect) { + const GstVaapiRectangle *const target_rect = &filter->target_rect; + + if ((target_rect->x + target_rect->width > + GST_VAAPI_SURFACE_WIDTH (dst_surface)) || + (target_rect->y + target_rect->height > + GST_VAAPI_SURFACE_HEIGHT (dst_surface))) + goto error; + + dst_rect.x = target_rect->x; + dst_rect.y = target_rect->y; + dst_rect.width = target_rect->width; + dst_rect.height = target_rect->height; + } else { + dst_rect.x = 0; + dst_rect.y = 0; + dst_rect.width = GST_VAAPI_SURFACE_WIDTH (dst_surface); + dst_rect.height = GST_VAAPI_SURFACE_HEIGHT (dst_surface); + } + + for (i = 0, num_filters = 0; i < filter->operations->len; i++) { + GstVaapiFilterOpData *const op_data = + g_ptr_array_index (filter->operations, i); + if (!op_data->is_enabled) + continue; + if (op_data->va_buffer == VA_INVALID_ID) { + GST_ERROR ("invalid VA buffer for operation %s", + g_param_spec_get_name (op_data->pspec)); + goto error; + } + filters[num_filters++] = op_data->va_buffer; + } + + /* Validate pipeline caps */ + va_status = vaQueryVideoProcPipelineCaps (filter->va_display, + filter->va_context, filters, num_filters, &pipeline_caps); + if (!vaapi_check_status (va_status, "vaQueryVideoProcPipelineCaps()")) + goto error; + + if (!vaapi_create_buffer (filter->va_display, filter->va_context, + VAProcPipelineParameterBufferType, sizeof (*pipeline_param), + NULL, &pipeline_param_buf_id, (gpointer *) & pipeline_param)) + goto error; + + memset (pipeline_param, 0, sizeof (*pipeline_param)); + pipeline_param->surface = GST_VAAPI_SURFACE_ID (src_surface); + pipeline_param->surface_region = &src_rect; + + gst_vaapi_filter_fill_color_standards (filter, pipeline_param); + + pipeline_param->output_region = &dst_rect; + pipeline_param->output_background_color = 0xff000000; + pipeline_param->filter_flags = from_GstVaapiSurfaceRenderFlags (flags) | + from_GstVaapiScaleMethod (filter->scale_method); + pipeline_param->filters = filters; + pipeline_param->num_filters = num_filters; + + from_GstVideoOrientationMethod (filter->video_direction, &va_mirror, + &va_rotation); + +#if VA_CHECK_VERSION(1,1,0) + pipeline_param->mirror_state = va_mirror; + pipeline_param->rotation_state = va_rotation; +#endif + + // Reference frames for advanced deinterlacing + if (filter->forward_references->len > 0) { + pipeline_param->forward_references = (VASurfaceID *) + filter->forward_references->data; + pipeline_param->num_forward_references = + MIN (filter->forward_references->len, + pipeline_caps.num_forward_references); + } else { + pipeline_param->forward_references = NULL; + pipeline_param->num_forward_references = 0; + } + + if (filter->backward_references->len > 0) { + pipeline_param->backward_references = (VASurfaceID *) + filter->backward_references->data; + pipeline_param->num_backward_references = + MIN (filter->backward_references->len, + pipeline_caps.num_backward_references); + } else { + pipeline_param->backward_references = NULL; + pipeline_param->num_backward_references = 0; + } + + vaapi_unmap_buffer (filter->va_display, pipeline_param_buf_id, NULL); + + va_status = vaBeginPicture (filter->va_display, filter->va_context, + GST_VAAPI_SURFACE_ID (dst_surface)); + if (!vaapi_check_status (va_status, "vaBeginPicture()")) + goto error; + + va_status = vaRenderPicture (filter->va_display, filter->va_context, + &pipeline_param_buf_id, 1); + if (!vaapi_check_status (va_status, "vaRenderPicture()")) + goto error; + + va_status = vaEndPicture (filter->va_display, filter->va_context); + if (!vaapi_check_status (va_status, "vaEndPicture()")) + goto error; + + deint_refs_clear_all (filter); + vaapi_destroy_buffer (filter->va_display, &pipeline_param_buf_id); + return GST_VAAPI_FILTER_STATUS_SUCCESS; + + /* ERRORS */ +error: + { + deint_refs_clear_all (filter); + vaapi_destroy_buffer (filter->va_display, &pipeline_param_buf_id); + return GST_VAAPI_FILTER_STATUS_ERROR_OPERATION_FAILED; + } +} + +GstVaapiFilterStatus +gst_vaapi_filter_process (GstVaapiFilter * filter, + GstVaapiSurface * src_surface, GstVaapiSurface * dst_surface, guint flags) +{ + GstVaapiFilterStatus status; + + g_return_val_if_fail (filter != NULL, + GST_VAAPI_FILTER_STATUS_ERROR_INVALID_PARAMETER); + g_return_val_if_fail (src_surface != NULL, + GST_VAAPI_FILTER_STATUS_ERROR_INVALID_PARAMETER); + g_return_val_if_fail (dst_surface != NULL, + GST_VAAPI_FILTER_STATUS_ERROR_INVALID_PARAMETER); + + GST_VAAPI_DISPLAY_LOCK (filter->display); + status = gst_vaapi_filter_process_unlocked (filter, + src_surface, dst_surface, flags); + GST_VAAPI_DISPLAY_UNLOCK (filter->display); + return status; +} + +/** + * gst_vaapi_filter_get_formats: + * @filter: a #GstVaapiFilter + * + * Determines the set of supported source or target formats for video + * processing. The caller owns an extra reference to the resulting + * array of #GstVideoFormat elements, so it shall be released with + * g_array_unref() after usage. + * + * Return value: the set of supported target formats for video processing. + */ +GArray * +gst_vaapi_filter_get_formats (GstVaapiFilter * filter) +{ + g_return_val_if_fail (filter != NULL, NULL); + + if (!ensure_attributes (filter)) + return NULL; + if (filter->attribs->formats) + return g_array_ref (filter->attribs->formats); + return NULL; +} + +/** + * gst_vaapi_filter_set_format: + * @filter: a #GstVaapiFilter + * @format: the target surface format + * + * Sets the desired pixel format of the resulting video processing + * operations. + * + * If @format is #GST_VIDEO_FORMAT_UNKNOWN, the filter will assume iso + * format conversion, i.e. no color conversion at all and the target + * surface format shall match the source surface format. + * + * If @format is #GST_VIDEO_FORMAT_ENCODED, the filter will use the pixel + * format of the target surface passed to gst_vaapi_filter_process(). + * + * Return value: %TRUE if the color conversion to the specified @format + * may be supported, %FALSE otherwise. + */ +gboolean +gst_vaapi_filter_set_format (GstVaapiFilter * filter, GstVideoFormat format) +{ + g_return_val_if_fail (filter != NULL, FALSE); + + if (!ensure_attributes (filter)) + return FALSE; + + if (!is_special_format (format) && !find_format (filter, format)) + return FALSE; + + filter->format = format; + return TRUE; +} + +/** + * gst_vaapi_filter_append_caps: + * @filter: a #GstVaapiFilter + * @structure: a #GstStructure from #GstCaps + * + * Extracts the config's surface attributes, from @filter's context, + * and transforms it into a caps formats and appended them into + * @structure. + * + * Returns: %TRUE if the capabilities could be extracted and appended + * into @structure; otherwise %FALSE + **/ +gboolean +gst_vaapi_filter_append_caps (GstVaapiFilter * filter, GstStructure * structure) +{ + GstVaapiConfigSurfaceAttributes *attribs; + + g_return_val_if_fail (filter != NULL, FALSE); + g_return_val_if_fail (structure != NULL, FALSE); + + if (!ensure_attributes (filter)) + return FALSE; + + attribs = filter->attribs; + + if (attribs->min_width >= attribs->max_width || + attribs->min_height >= attribs->max_height) + return FALSE; + + gst_structure_set (structure, "width", GST_TYPE_INT_RANGE, attribs->min_width, + attribs->max_width, "height", GST_TYPE_INT_RANGE, attribs->min_height, + attribs->max_height, NULL); + + return TRUE; + +} + +/** + * gst_vaapi_filter_get_memory_types: + * @filter: a #GstVaapiFilter + * + * Gets the surface's memory types available in @filter's context. + * + * Returns: surface's memory types available in @filter context. + **/ +guint +gst_vaapi_filter_get_memory_types (GstVaapiFilter * filter) +{ + g_return_val_if_fail (filter != NULL, FALSE); + + if (!ensure_attributes (filter)) + return 0; + return filter->attribs->mem_types; +} + +/** + * gst_vaapi_filter_set_cropping_rectangle: + * @filter: a #GstVaapiFilter + * @rect: the cropping region + * + * Sets the source surface cropping rectangle to use during the video + * processing. If @rect is %NULL, the whole source surface will be used. + * + * Return value: %TRUE if the operation is supported, %FALSE otherwise. + */ +gboolean +gst_vaapi_filter_set_cropping_rectangle (GstVaapiFilter * filter, + const GstVaapiRectangle * rect) +{ + g_return_val_if_fail (filter != NULL, FALSE); + + filter->use_crop_rect = rect != NULL; + if (filter->use_crop_rect) + filter->crop_rect = *rect; + return TRUE; +} + +/** + * gst_vaapi_filter_set_target_rectangle: + * @filter: a #GstVaapiFilter + * @rect: the target render region + * + * Sets the region within the target surface where the source surface + * would be rendered. i.e. where the hardware accelerator would emit + * the outcome of video processing. If @rect is %NULL, the whole + * source surface will be used. + * + * Return value: %TRUE if the operation is supported, %FALSE otherwise. + */ +gboolean +gst_vaapi_filter_set_target_rectangle (GstVaapiFilter * filter, + const GstVaapiRectangle * rect) +{ + g_return_val_if_fail (filter != NULL, FALSE); + + filter->use_target_rect = rect != NULL; + if (filter->use_target_rect) + filter->target_rect = *rect; + return TRUE; +} + +/** + * gst_vaapi_filter_set_denoising_level: + * @filter: a #GstVaapiFilter + * @level: the level of noise reduction to apply + * + * Sets the noise reduction level to apply. If @level is 0.0f, this + * corresponds to disabling the noise reduction algorithm. + * + * Return value: %TRUE if the operation is supported, %FALSE otherwise. + */ +gboolean +gst_vaapi_filter_set_denoising_level (GstVaapiFilter * filter, gfloat level) +{ + g_return_val_if_fail (filter != NULL, FALSE); + + return op_set_generic (filter, + find_operation (filter, GST_VAAPI_FILTER_OP_DENOISE), level); +} + +/** + * gst_vaapi_filter_set_sharpening_level: + * @filter: a #GstVaapiFilter + * @level: the sharpening factor + * + * Enables noise reduction with the specified factor. + * + * Return value: %TRUE if the operation is supported, %FALSE otherwise. + */ +gboolean +gst_vaapi_filter_set_sharpening_level (GstVaapiFilter * filter, gfloat level) +{ + g_return_val_if_fail (filter != NULL, FALSE); + + return op_set_generic (filter, + find_operation (filter, GST_VAAPI_FILTER_OP_SHARPEN), level); +} + +/** + * gst_vaapi_filter_set_hue: + * @filter: a #GstVaapiFilter + * @value: the color hue value + * + * Enables color hue adjustment to the specified value. + * + * Return value: %TRUE if the operation is supported, %FALSE otherwise. + */ +gboolean +gst_vaapi_filter_set_hue (GstVaapiFilter * filter, gfloat value) +{ + g_return_val_if_fail (filter != NULL, FALSE); + + return op_set_color_balance (filter, + find_operation (filter, GST_VAAPI_FILTER_OP_HUE), value); +} + +/** + * gst_vaapi_filter_set_saturation: + * @filter: a #GstVaapiFilter + * @value: the color saturation value + * + * Enables color saturation adjustment to the specified value. + * + * Return value: %TRUE if the operation is supported, %FALSE otherwise. + */ +gboolean +gst_vaapi_filter_set_saturation (GstVaapiFilter * filter, gfloat value) +{ + g_return_val_if_fail (filter != NULL, FALSE); + + return op_set_color_balance (filter, + find_operation (filter, GST_VAAPI_FILTER_OP_SATURATION), value); +} + +/** + * gst_vaapi_filter_set_brightness: + * @filter: a #GstVaapiFilter + * @value: the color brightness value + * + * Enables color brightness adjustment to the specified value. + * + * Return value: %TRUE if the operation is supported, %FALSE otherwise. + */ +gboolean +gst_vaapi_filter_set_brightness (GstVaapiFilter * filter, gfloat value) +{ + g_return_val_if_fail (filter != NULL, FALSE); + + return op_set_color_balance (filter, + find_operation (filter, GST_VAAPI_FILTER_OP_BRIGHTNESS), value); +} + +/** + * gst_vaapi_filter_set_contrast: + * @filter: a #GstVaapiFilter + * @value: the color contrast value + * + * Enables color contrast adjustment to the specified value. + * + * Return value: %TRUE if the operation is supported, %FALSE otherwise. + */ +gboolean +gst_vaapi_filter_set_contrast (GstVaapiFilter * filter, gfloat value) +{ + g_return_val_if_fail (filter != NULL, FALSE); + + return op_set_color_balance (filter, + find_operation (filter, GST_VAAPI_FILTER_OP_CONTRAST), value); +} + +/** + * gst_vaapi_filter_set_deinterlacing: + * @filter: a #GstVaapiFilter + * @method: the deinterlacing algorithm (see #GstVaapiDeinterlaceMethod) + * @flags: the additional flags + * + * Applies deinterlacing to the video processing pipeline. If @method + * is not @GST_VAAPI_DEINTERLACE_METHOD_NONE, then @flags could + * represent the initial picture structure of the source frame. + * + * Return value: %TRUE if the operation is supported, %FALSE otherwise. + */ +gboolean +gst_vaapi_filter_set_deinterlacing (GstVaapiFilter * filter, + GstVaapiDeinterlaceMethod method, guint flags) +{ + g_return_val_if_fail (filter != NULL, FALSE); + + return op_set_deinterlace (filter, + find_operation (filter, GST_VAAPI_FILTER_OP_DEINTERLACING), method, + flags); +} + +/** + * gst_vaapi_filter_set_deinterlacing_references: + * @filter: a #GstVaapiFilter + * @forward_references: the set of #GstVaapiSurface objects used as + * forward references + * @num_forward_references: the number of elements in the + * @forward_references array + * @backward_references: the set of #GstVaapiSurface objects used as + * backward references + * @num_backward_references: the number of elements in the + * @backward_references array + * + * Specifies the list of surfaces used for forward or backward reference in + * advanced deinterlacing mode. The caller is responsible for maintaining + * the associated surfaces live until gst_vaapi_filter_process() completes. + * e.g. by holding an extra reference to the associated #GstVaapiSurfaceProxy. + * + * Temporal ordering is maintained as follows: the shorter index in + * either array is, the closest the matching surface is relatively to + * the current source surface to process. e.g. surface in + * @forward_references array index 0 represents the immediately + * preceding surface in display order, surface at index 1 is the one + * preceding surface at index 0, etc. + * + * The video processing filter will only use the recommended number of + * surfaces for backward and forward references. + * + * Note: the supplied lists of reference surfaces are not sticky. This + * means that they are only valid for the next gst_vaapi_filter_process() + * call, and thus needs to be submitted again for subsequent calls. + * + * Return value: %TRUE if the operation is supported, %FALSE otherwise. + */ +gboolean +gst_vaapi_filter_set_deinterlacing_references (GstVaapiFilter * filter, + GstVaapiSurface ** forward_references, guint num_forward_references, + GstVaapiSurface ** backward_references, guint num_backward_references) +{ + g_return_val_if_fail (filter != NULL, FALSE); + + deint_refs_clear_all (filter); + + if (!deint_refs_set (filter->forward_references, forward_references, + num_forward_references)) + return FALSE; + + if (!deint_refs_set (filter->backward_references, backward_references, + num_backward_references)) + return FALSE; + return TRUE; +} + +/** + * gst_vaapi_filter_set_scaling: + * @filter: a #GstVaapiFilter + * @method: the scaling algorithm (see #GstVaapiScaleMethod) + * + * Applies scaling algorithm to the video processing pipeline. + * + * Return value: %TRUE if the operation is supported, %FALSE otherwise. + */ +gboolean +gst_vaapi_filter_set_scaling (GstVaapiFilter * filter, + GstVaapiScaleMethod method) +{ + g_return_val_if_fail (filter != NULL, FALSE); + + filter->scale_method = method; + return TRUE; +} + +#ifndef GST_REMOVE_DEPRECATED +/** + * gst_vaapi_filter_set_skintone: + * @filter: a #GstVaapiFilter + * @enhance: %TRUE if enable the skin tone enhancement algorithm + * + * Applies the skin tone enhancement algorithm. + * + * Return value: %TRUE if the operation is supported, %FALSE + * otherwise. + **/ +gboolean +gst_vaapi_filter_set_skintone (GstVaapiFilter * filter, gboolean enhance) +{ + g_return_val_if_fail (filter != NULL, FALSE); + + return op_set_skintone (filter, + find_operation (filter, GST_VAAPI_FILTER_OP_SKINTONE), enhance); +} +#endif + +/** + * gst_vaapi_filter_set_skintone_level: + * @filter: a #GstVaapiFilter + * @value: the value if enable the skin tone enhancement algorithm + * + * Applies the skin tone enhancement algorithm with specifled value. + * + * Return value: %TRUE if the operation is supported, %FALSE + * otherwise. + **/ +gboolean +gst_vaapi_filter_set_skintone_level (GstVaapiFilter * filter, guint value) +{ + g_return_val_if_fail (filter != NULL, FALSE); + + return op_set_skintone_level (filter, + find_operation (filter, GST_VAAPI_FILTER_OP_SKINTONE_LEVEL), value); +} + +/** + * gst_vaapi_filter_set_video_direction: + * @filter: a #GstVaapiFilter + * @method: the video direction (see #GstVideoOrientationMethod) + * + * Applies mirror/rotation to the video processing pipeline. + * + * Return value: %TRUE if the operation is supported, %FALSE otherwise. + */ +gboolean +gst_vaapi_filter_set_video_direction (GstVaapiFilter * filter, + GstVideoOrientationMethod method) +{ + g_return_val_if_fail (filter != NULL, FALSE); + +#if VA_CHECK_VERSION(1,1,0) + { + guint32 va_mirror = VA_MIRROR_NONE; + guint32 va_rotation = VA_ROTATION_NONE; + + from_GstVideoOrientationMethod (method, &va_mirror, &va_rotation); + + if (va_mirror != VA_MIRROR_NONE && !(filter->mirror_flags & va_mirror)) + return FALSE; + + if (va_rotation != VA_ROTATION_NONE + && !(filter->rotation_flags & (1 << va_rotation))) + return FALSE; + } +#else + return FALSE; +#endif + + filter->video_direction = method; + return TRUE; +} + +/** + * gst_vaapi_filter_get_video_direction: + * @filter: a #GstVaapiFilter + * + * Return value: the currently applied video direction (see #GstVideoOrientationMethod) + */ +GstVideoOrientationMethod +gst_vaapi_filter_get_video_direction (GstVaapiFilter * filter) +{ + g_return_val_if_fail (filter != NULL, GST_VIDEO_ORIENTATION_IDENTITY); + return filter->video_direction; +} + +gfloat +gst_vaapi_filter_get_denoising_level_default (GstVaapiFilter * filter) +{ + OP_RET_DEFAULT_VALUE (float, filter, GST_VAAPI_FILTER_OP_DENOISE); +} + +gfloat +gst_vaapi_filter_get_sharpening_level_default (GstVaapiFilter * filter) +{ + OP_RET_DEFAULT_VALUE (float, filter, GST_VAAPI_FILTER_OP_SHARPEN); +} + +gfloat +gst_vaapi_filter_get_hue_default (GstVaapiFilter * filter) +{ + OP_RET_DEFAULT_VALUE (float, filter, GST_VAAPI_FILTER_OP_HUE); +} + +gfloat +gst_vaapi_filter_get_saturation_default (GstVaapiFilter * filter) +{ + OP_RET_DEFAULT_VALUE (float, filter, GST_VAAPI_FILTER_OP_SATURATION); +} + +gfloat +gst_vaapi_filter_get_brightness_default (GstVaapiFilter * filter) +{ + OP_RET_DEFAULT_VALUE (float, filter, GST_VAAPI_FILTER_OP_BRIGHTNESS); +} + +gfloat +gst_vaapi_filter_get_contrast_default (GstVaapiFilter * filter) +{ + OP_RET_DEFAULT_VALUE (float, filter, GST_VAAPI_FILTER_OP_CONTRAST); +} + +GstVaapiScaleMethod +gst_vaapi_filter_get_scaling_default (GstVaapiFilter * filter) +{ + OP_RET_DEFAULT_VALUE (enum, filter, GST_VAAPI_FILTER_OP_SCALING); +} + +#ifndef GST_REMOVE_DEPRECATED +gboolean +gst_vaapi_filter_get_skintone_default (GstVaapiFilter * filter) +{ + OP_RET_DEFAULT_VALUE (boolean, filter, GST_VAAPI_FILTER_OP_SKINTONE); +} +#endif + +guint +gst_vaapi_filter_get_skintone_level_default (GstVaapiFilter * filter) +{ + OP_RET_DEFAULT_VALUE (uint, filter, GST_VAAPI_FILTER_OP_SKINTONE_LEVEL); +} + +GstVideoOrientationMethod +gst_vaapi_filter_get_video_direction_default (GstVaapiFilter * filter) +{ + OP_RET_DEFAULT_VALUE (enum, filter, GST_VAAPI_FILTER_OP_VIDEO_DIRECTION); +} + +static gboolean +gst_vaapi_filter_set_colorimetry_unlocked (GstVaapiFilter * filter, + GstVideoColorimetry * input, GstVideoColorimetry * output) +{ + gchar *in_color, *out_color; + + if (input) + filter->input_colorimetry = *input; + else + gst_video_colorimetry_from_string (&filter->input_colorimetry, NULL); + + if (output) + filter->output_colorimetry = *output; + else + gst_video_colorimetry_from_string (&filter->output_colorimetry, NULL); + + in_color = gst_video_colorimetry_to_string (&filter->input_colorimetry); + GST_DEBUG_OBJECT (filter, " input colorimetry '%s'", in_color); + + out_color = gst_video_colorimetry_to_string (&filter->output_colorimetry); + GST_DEBUG_OBJECT (filter, "output colorimetry '%s'", out_color); + + if (!gst_vaapi_display_has_driver_quirks (filter->display, + GST_VAAPI_DRIVER_QUIRK_NO_CHECK_VPP_COLOR_STD)) { + VAProcPipelineCaps pipeline_caps = { 0, }; + VAProcColorStandardType type; + guint32 i; + + VAStatus va_status = vaQueryVideoProcPipelineCaps (filter->va_display, + filter->va_context, NULL, 0, &pipeline_caps); + + if (!vaapi_check_status (va_status, "vaQueryVideoProcPipelineCaps()")) + return FALSE; + + type = from_GstVideoColorimetry (&filter->input_colorimetry); + for (i = 0; i < pipeline_caps.num_input_color_standards; i++) + if (type == pipeline_caps.input_color_standards[i]) + break; + if ((i == pipeline_caps.num_input_color_standards) + && (type != VAProcColorStandardNone)) + GST_WARNING_OBJECT (filter, + "driver does not support '%s' input colorimetry." + " vpp may fail or produce unexpected results.", in_color); + + type = from_GstVideoColorimetry (&filter->output_colorimetry); + for (i = 0; i < pipeline_caps.num_output_color_standards; i++) + if (type == pipeline_caps.output_color_standards[i]) + break; + if ((i == pipeline_caps.num_output_color_standards) + && (type != VAProcColorStandardNone)) + GST_WARNING_OBJECT (filter, + "driver does not support '%s' output colorimetry." + " vpp may fail or produce unexpected results.", out_color); + } else { + GST_WARNING_OBJECT (filter, + "driver does not report the supported input/output colorimetry." + " vpp may fail or produce unexpected results."); + } + + g_free (in_color); + g_free (out_color); + + return TRUE; +} + +gboolean +gst_vaapi_filter_set_colorimetry (GstVaapiFilter * filter, + GstVideoColorimetry * input, GstVideoColorimetry * output) +{ + gboolean result; + + g_return_val_if_fail (filter != NULL, FALSE); + + GST_VAAPI_DISPLAY_LOCK (filter->display); + result = gst_vaapi_filter_set_colorimetry_unlocked (filter, input, output); + GST_VAAPI_DISPLAY_UNLOCK (filter->display); + + return result; +} + +/** + * gst_vaapi_filter_set_hdr_tone_map: + * @filter: a #GstVaapiFilter + * @value: %TRUE to enable hdr tone map algorithm + * + * Applies HDR tone mapping algorithm. + * + * Return value: %TRUE if the operation is supported, %FALSE otherwise. + */ +gboolean +gst_vaapi_filter_set_hdr_tone_map (GstVaapiFilter * filter, gboolean value) +{ + g_return_val_if_fail (filter != NULL, FALSE); + + return op_set_hdr_tone_map (filter, + find_operation (filter, GST_VAAPI_FILTER_OP_HDR_TONE_MAP), value); +} + +static gboolean +gst_vaapi_filter_set_hdr_tone_map_meta_unlocked (GstVaapiFilter * filter, + GstVideoMasteringDisplayInfo * minfo, GstVideoContentLightLevel * linfo) +{ +#if VA_CHECK_VERSION(1,4,0) + GstVaapiFilterOpData *op_data; + VAProcFilterParameterBufferHDRToneMapping *buf; + VAHdrMetaDataHDR10 *meta = &filter->hdr_meta; + + op_data = find_operation (filter, GST_VAAPI_FILTER_OP_HDR_TONE_MAP); + + if (!op_data) + return FALSE; + + meta->display_primaries_x[0] = minfo->display_primaries[1].x; + meta->display_primaries_x[1] = minfo->display_primaries[2].x; + meta->display_primaries_x[2] = minfo->display_primaries[0].x; + + meta->display_primaries_y[0] = minfo->display_primaries[1].y; + meta->display_primaries_y[1] = minfo->display_primaries[2].y; + meta->display_primaries_y[2] = minfo->display_primaries[0].y; + + meta->white_point_x = minfo->white_point.x; + meta->white_point_y = minfo->white_point.y; + + meta->max_display_mastering_luminance = + minfo->max_display_mastering_luminance; + meta->min_display_mastering_luminance = + minfo->min_display_mastering_luminance; + + meta->max_content_light_level = linfo->max_content_light_level; + meta->max_pic_average_light_level = linfo->max_frame_average_light_level; + + buf = vaapi_map_buffer (filter->va_display, op_data->va_buffer); + if (!buf) + return FALSE; + + buf->type = op_data->va_type; + buf->data.metadata_type = op_data->va_subtype; + buf->data.metadata = meta; + buf->data.metadata_size = sizeof (meta); + + vaapi_unmap_buffer (filter->va_display, op_data->va_buffer, NULL); + + return TRUE; +#else + return FALSE; +#endif +} + +/** + * gst_vaapi_filter_set_hdr_tone_map_meta: + * @filter: a #GstVaapiFilter + * @minfo: a #GstVideoMasteringDisplayInfo + * @linfo: a #GstVideoContentLightLevel + * + * Sets the input HDR meta data used for tone mapping. + * + * Return value: %TRUE if the operation is supported, %FALSE otherwise. + */ +gboolean +gst_vaapi_filter_set_hdr_tone_map_meta (GstVaapiFilter * filter, + GstVideoMasteringDisplayInfo * minfo, GstVideoContentLightLevel * linfo) +{ + gboolean status = FALSE; + + g_return_val_if_fail (filter != NULL, FALSE); + g_return_val_if_fail (minfo != NULL, FALSE); + g_return_val_if_fail (linfo != NULL, FALSE); + + GST_VAAPI_DISPLAY_LOCK (filter->display); + status = + gst_vaapi_filter_set_hdr_tone_map_meta_unlocked (filter, minfo, linfo); + GST_VAAPI_DISPLAY_UNLOCK (filter->display); + + return status; +} diff --git a/gst-libs/gst/vaapi/gstvaapifilter.h b/gst-libs/gst/vaapi/gstvaapifilter.h new file mode 100644 index 0000000000..fcc968f076 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapifilter.h @@ -0,0 +1,325 @@ +/* + * gstvaapifilter.h - Video processing abstraction + * + * Copyright (C) 2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_FILTER_H +#define GST_VAAPI_FILTER_H + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_FILTER \ + (gst_vaapi_filter_get_type ()) +#define GST_VAAPI_FILTER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_FILTER, GstVaapiFilter)) +#define GST_VAAPI_IS_FILTER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_FILTER)) + +typedef struct _GstVaapiFilter GstVaapiFilter; +typedef struct _GstVaapiFilterOpInfo GstVaapiFilterOpInfo; + +/** + * @GST_VAAPI_FILTER_OP_FORMAT: Force output pixel format (#GstVideoFormat). + * @GST_VAAPI_FILTER_OP_CROP: Crop source surface (#GstVaapiRectangle). + * @GST_VAAPI_FILTER_OP_DENOISE: Noise reduction (float). + * @GST_VAAPI_FILTER_OP_SHARPEN: Sharpening (float). + * @GST_VAAPI_FILTER_OP_HUE: Change color hue (float). + * @GST_VAAPI_FILTER_OP_SATURATION: Change saturation (float). + * @GST_VAAPI_FILTER_OP_BRIGHTNESS: Change brightness (float). + * @GST_VAAPI_FILTER_OP_CONTRAST: Change contrast (float). + * @GST_VAAPI_FILTER_OP_SCALING: Change scaling method (#GstVaapiScaleMethod). + * @GST_VAAPI_FILTER_OP_VIDEO_DIRECTION: Change video direction + * (#GstVideoOrientationMethod). + * @GST_VAAPI_FILTER_OP_HDR_TONE_MAP: HDR tone mapping (bool). + * @GST_VAAPI_FILTER_OP_SKINTONE: Skin tone enhancement (bool). + * @GST_VAAPI_FILTER_OP_SKINTONE_LEVEL: Skin tone enhancement (uint). + * + * The set of operations that could be applied to the filter. + */ +typedef enum { + GST_VAAPI_FILTER_OP_FORMAT = 1, + GST_VAAPI_FILTER_OP_CROP, + GST_VAAPI_FILTER_OP_DENOISE, + GST_VAAPI_FILTER_OP_SHARPEN, + GST_VAAPI_FILTER_OP_HUE, + GST_VAAPI_FILTER_OP_SATURATION, + GST_VAAPI_FILTER_OP_BRIGHTNESS, + GST_VAAPI_FILTER_OP_CONTRAST, + GST_VAAPI_FILTER_OP_DEINTERLACING, + GST_VAAPI_FILTER_OP_SCALING, + GST_VAAPI_FILTER_OP_VIDEO_DIRECTION, + GST_VAAPI_FILTER_OP_HDR_TONE_MAP, +#ifndef GST_REMOVE_DEPRECATED + GST_VAAPI_FILTER_OP_SKINTONE, +#endif + GST_VAAPI_FILTER_OP_SKINTONE_LEVEL, +} GstVaapiFilterOp; + +/** + * GstVaapiFilterOpInfo: + * @operation: the #GstVaapiFilterOp + * @pspec: the #GParamSpec describing the associated configurable value + * + * A #GstVaapiFilterOp descriptor. + */ +struct _GstVaapiFilterOpInfo +{ + const GstVaapiFilterOp op; + GParamSpec *const pspec; +}; + +/** + * GstVaapiFilterStatus: + * @GST_VAAPI_FILTER_STATUS_SUCCESS: Success. + * @GST_VAAPI_FILTER_STATUS_ERROR_ALLOCATION_FAILED: No memory left. + * @GST_VAAPI_FILTER_STATUS_ERROR_OPERATION_FAILED: Operation failed. + * @GST_VAAPI_FILTER_STATUS_ERROR_INVALID_PARAMETER: Invalid parameter. + * @GST_VAAPI_FILTER_STATUS_ERROR_UNSUPPORTED_OPERATION: Unsupported operation. + * @GST_VAAPI_FILTER_STATUS_ERROR_UNSUPPORTED_FORMAT: Unsupported target format. + * + * Video processing status for gst_vaapi_filter_process(). + */ +typedef enum { + GST_VAAPI_FILTER_STATUS_SUCCESS = 0, + GST_VAAPI_FILTER_STATUS_ERROR_ALLOCATION_FAILED, + GST_VAAPI_FILTER_STATUS_ERROR_OPERATION_FAILED, + GST_VAAPI_FILTER_STATUS_ERROR_INVALID_PARAMETER, + GST_VAAPI_FILTER_STATUS_ERROR_UNSUPPORTED_OPERATION, + GST_VAAPI_FILTER_STATUS_ERROR_UNSUPPORTED_FORMAT, +} GstVaapiFilterStatus; + +/** + * GstVaapiScaleMethod: + * @GST_VAAPI_SCALE_METHOD_DEFAULT: Default scaling mode. + * @GST_VAAPI_SCALE_METHOD_FAST: Fast scaling mode, at the expense of quality. + * @GST_VAAPI_SCALE_METHOD_HQ: High quality scaling mode, at the + * expense of speed. + * + * Scaling algorithms. + */ +typedef enum { + GST_VAAPI_SCALE_METHOD_DEFAULT, + GST_VAAPI_SCALE_METHOD_FAST, + GST_VAAPI_SCALE_METHOD_HQ, +} GstVaapiScaleMethod; + +/** + * GstVaapiDeinterlaceMethod: + * @GST_VAAPI_DEINTERLACE_METHOD_NONE: No deinterlacing. + * @GST_VAAPI_DEINTERLACE_METHOD_BOB: Basic bob deinterlacing algorithm. + * @GST_VAAPI_DEINTERLACE_METHOD_WEAVE: Weave deinterlacing algorithm. + * @GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE: Motion adaptive + * deinterlacing algorithm. + * @GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED: Motion compensated + * deinterlacing algorithm. + * + * Deinterlacing algorithms. + */ +typedef enum { + GST_VAAPI_DEINTERLACE_METHOD_NONE, + GST_VAAPI_DEINTERLACE_METHOD_BOB, + GST_VAAPI_DEINTERLACE_METHOD_WEAVE, + GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE, + GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED, +} GstVaapiDeinterlaceMethod; + +/** + * GstVaapiDeinterlaceFlags: + * @GST_VAAPI_DEINTERLACE_FLAG_TFF: Top-field first. If this flag is + * not set, then bottom-field first order is assumed. Note: this + * only affects the way reference frames are organized for advanced + * deinterlacing modes. + * @GST_VAAPI_DEINTERLACE_FLAG_ONEFIELD: The input frame represents a + * single field. If this flag is not set, then the whole frame holds + * two interleaved fields. + * @GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD: The top field of the input + * frame is to be used for deinterlacing. Otherwise, if this flag is + * not set, then the bottom field of the input frame will be used + * for deinterlacing. + * + * The set of gst_vaapi_filter_set_deinterlacing() flags. + */ +typedef enum { + GST_VAAPI_DEINTERLACE_FLAG_TFF = 1 << 31, + GST_VAAPI_DEINTERLACE_FLAG_ONEFIELD = 1 << 30, + GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD = 1 << 29, +} GstVaapiDeinterlaceFlags; + +#define GST_VAAPI_TYPE_SCALE_METHOD \ + gst_vaapi_scale_method_get_type() + +#define GST_VAAPI_TYPE_DEINTERLACE_METHOD \ + gst_vaapi_deinterlace_method_get_type() + +#define GST_VAAPI_TYPE_DEINTERLACE_FLAGS \ + gst_vaapi_deinterlace_flags_get_type() + +GType +gst_vaapiscale_method_get_type (void) G_GNUC_CONST; + +GType +gst_vaapi_deinterlace_method_get_type (void) G_GNUC_CONST; + +GType +gst_vaapi_deinterlace_flags_get_type (void) G_GNUC_CONST; + +GType +gst_vaapi_filter_get_type (void) G_GNUC_CONST; + +GstVaapiFilter * +gst_vaapi_filter_new (GstVaapiDisplay * display); + +void +gst_vaapi_filter_replace (GstVaapiFilter ** old_filter_ptr, + GstVaapiFilter * new_filter); + +GPtrArray * +gst_vaapi_filter_get_operations (GstVaapiFilter * filter); + +gboolean +gst_vaapi_filter_has_operation (GstVaapiFilter * filter, GstVaapiFilterOp op); + +gboolean +gst_vaapi_filter_use_operation (GstVaapiFilter * filter, GstVaapiFilterOp op); + +gboolean +gst_vaapi_filter_set_operation (GstVaapiFilter * filter, GstVaapiFilterOp op, + const GValue * value); + +GstVaapiFilterStatus +gst_vaapi_filter_process (GstVaapiFilter * filter, + GstVaapiSurface * src_surface, GstVaapiSurface * dst_surface, guint flags); + +GArray * +gst_vaapi_filter_get_formats (GstVaapiFilter * filter); + +gboolean +gst_vaapi_filter_set_format (GstVaapiFilter * filter, GstVideoFormat format); + +gboolean +gst_vaapi_filter_append_caps (GstVaapiFilter * filter, GstStructure * structure); + +guint +gst_vaapi_filter_get_memory_types (GstVaapiFilter * filter); + +gboolean +gst_vaapi_filter_set_cropping_rectangle (GstVaapiFilter * filter, + const GstVaapiRectangle * rect); + +gboolean +gst_vaapi_filter_set_target_rectangle (GstVaapiFilter * filter, + const GstVaapiRectangle * rect); + +gboolean +gst_vaapi_filter_set_denoising_level (GstVaapiFilter * filter, gfloat level); + +gboolean +gst_vaapi_filter_set_sharpening_level (GstVaapiFilter * filter, gfloat level); + +gboolean +gst_vaapi_filter_set_hue (GstVaapiFilter * filter, gfloat value); + +gboolean +gst_vaapi_filter_set_saturation (GstVaapiFilter * filter, gfloat value); + +gboolean +gst_vaapi_filter_set_brightness (GstVaapiFilter * filter, gfloat value); + +gboolean +gst_vaapi_filter_set_contrast (GstVaapiFilter * filter, gfloat value); + +gboolean +gst_vaapi_filter_set_deinterlacing (GstVaapiFilter * filter, + GstVaapiDeinterlaceMethod method, guint flags); + +gboolean +gst_vaapi_filter_set_deinterlacing_references (GstVaapiFilter * filter, + GstVaapiSurface ** forward_references, guint num_forward_references, + GstVaapiSurface ** backward_references, guint num_backward_references); + +gboolean +gst_vaapi_filter_set_scaling (GstVaapiFilter * filter, + GstVaapiScaleMethod method); + +gboolean +gst_vaapi_filter_set_video_direction (GstVaapiFilter * filter, + GstVideoOrientationMethod method); + +GstVideoOrientationMethod +gst_vaapi_filter_get_video_direction (GstVaapiFilter * filter); + +gboolean +gst_vaapi_filter_set_hdr_tone_map (GstVaapiFilter * filter, gboolean value); + +gboolean +gst_vaapi_filter_set_hdr_tone_map_meta (GstVaapiFilter * filter, + GstVideoMasteringDisplayInfo * minfo, GstVideoContentLightLevel * linfo); + +#ifndef GST_REMOVE_DEPRECATED +gboolean +gst_vaapi_filter_set_skintone (GstVaapiFilter * filter, + gboolean enhance); +#endif + +gboolean +gst_vaapi_filter_set_skintone_level (GstVaapiFilter * filter, guint value); + +gfloat +gst_vaapi_filter_get_denoising_level_default (GstVaapiFilter * filter); + +gfloat +gst_vaapi_filter_get_sharpening_level_default (GstVaapiFilter * filter); + +gfloat +gst_vaapi_filter_get_hue_default (GstVaapiFilter * filter); + +gfloat +gst_vaapi_filter_get_saturation_default (GstVaapiFilter * filter); + +gfloat +gst_vaapi_filter_get_brightness_default (GstVaapiFilter * filter); + +gfloat +gst_vaapi_filter_get_contrast_default (GstVaapiFilter * filter); + +GstVaapiScaleMethod +gst_vaapi_filter_get_scaling_default (GstVaapiFilter * filter); + +GstVideoOrientationMethod +gst_vaapi_filter_get_video_direction_default (GstVaapiFilter * filter); + +#ifndef GST_REMOVE_DEPRECATED +gboolean +gst_vaapi_filter_get_skintone_default (GstVaapiFilter * filter); +#endif + +guint +gst_vaapi_filter_get_skintone_level_default (GstVaapiFilter * filter); + +gboolean +gst_vaapi_filter_set_colorimetry (GstVaapiFilter * filter, + GstVideoColorimetry * input, GstVideoColorimetry * output); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiFilter, gst_object_unref) + +#endif /* GST_VAAPI_FILTER_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiimage.c b/gst-libs/gst/vaapi/gstvaapiimage.c new file mode 100644 index 0000000000..18389adf7b --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiimage.c @@ -0,0 +1,1072 @@ +/* + * gstvaapiimage.c - VA image abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapiimage + * @short_description: VA image abstraction + */ + +#include "sysdeps.h" +#include "gstvaapicompat.h" +#include "gstvaapiutils.h" +#include "gstvaapiimage.h" +#include "gstvaapiimage_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +#define SWAP_UINT(a, b) do { \ + guint v = a; \ + a = b; \ + b = v; \ + } while (0) + +static gboolean +_gst_vaapi_image_map (GstVaapiImage * image, GstVaapiImageRaw * raw_image); + +static gboolean _gst_vaapi_image_unmap (GstVaapiImage * image); + +static gboolean +_gst_vaapi_image_set_image (GstVaapiImage * image, const VAImage * va_image); + +/* + * VAImage wrapper + */ + +static gboolean +vaapi_image_is_linear (const VAImage * va_image) +{ + guint i, width, height, width2, height2, data_size; + + for (i = 1; i < va_image->num_planes; i++) + if (va_image->offsets[i] < va_image->offsets[i - 1]) + return FALSE; + + width = va_image->width; + height = va_image->height; + width2 = (width + 1) / 2; + height2 = (height + 1) / 2; + + switch (va_image->format.fourcc) { + case VA_FOURCC ('N', 'V', '1', '2'): + case VA_FOURCC ('Y', 'V', '1', '2'): + case VA_FOURCC ('I', '4', '2', '0'): + data_size = width * height + 2 * width2 * height2; + break; + case VA_FOURCC ('Y', 'U', 'Y', '2'): + case VA_FOURCC ('U', 'Y', 'V', 'Y'): + case VA_FOURCC ('R', 'G', '1', '6'): + data_size = 2 * width * height; + break; + case VA_FOURCC ('Y', '8', '0', '0'): + data_size = width * height; + break; + case VA_FOURCC ('A', 'Y', 'U', 'V'): + case VA_FOURCC ('A', 'R', 'G', 'B'): + case VA_FOURCC ('R', 'G', 'B', 'A'): + case VA_FOURCC ('A', 'B', 'G', 'R'): + case VA_FOURCC ('B', 'G', 'R', 'A'): + case VA_FOURCC ('X', 'R', 'G', 'B'): + case VA_FOURCC ('R', 'G', 'B', 'X'): + case VA_FOURCC ('X', 'B', 'G', 'R'): + case VA_FOURCC ('B', 'G', 'R', 'X'): + case VA_FOURCC ('Y', '2', '1', '0'): + case VA_FOURCC ('Y', '4', '1', '0'): + case VA_FOURCC ('A', 'R', '3', '0'): + case VA_FOURCC ('Y', '2', '1', '2'): + data_size = 4 * width * height; + break; + case VA_FOURCC ('P', '0', '1', '0'): + case VA_FOURCC ('P', '0', '1', '2'): + data_size = 2 * (width * height + 2 * width2 * height2); + break; + case VA_FOURCC ('R', 'G', '2', '4'): + case VA_FOURCC ('4', '4', '4', 'P'): + data_size = 3 * width * height; + break; + case VA_FOURCC ('Y', '4', '1', '2'): + data_size = 8 * width * height; + break; + default: + GST_ERROR ("FIXME: incomplete formats %" GST_FOURCC_FORMAT, + GST_FOURCC_ARGS (va_image->format.fourcc)); + data_size = G_MAXUINT; + break; + } + return va_image->data_size == data_size; +} + +static void +gst_vaapi_image_free (GstVaapiImage * image) +{ + GstVaapiDisplay *const display = GST_VAAPI_IMAGE_DISPLAY (image); + VAImageID image_id; + VAStatus status; + + _gst_vaapi_image_unmap (image); + + image_id = GST_VAAPI_IMAGE_ID (image); + GST_DEBUG ("image %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (image_id)); + + if (image_id != VA_INVALID_ID) { + GST_VAAPI_DISPLAY_LOCK (display); + status = vaDestroyImage (GST_VAAPI_DISPLAY_VADISPLAY (display), image_id); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!vaapi_check_status (status, "vaDestroyImage()")) + GST_WARNING ("failed to destroy image %" GST_VAAPI_ID_FORMAT, + GST_VAAPI_ID_ARGS (image_id)); + GST_VAAPI_IMAGE_ID (image) = VA_INVALID_ID; + } + + gst_vaapi_display_replace (&GST_VAAPI_IMAGE_DISPLAY (image), NULL); + + g_slice_free1 (sizeof (GstVaapiImage), image); +} + +static gboolean +_gst_vaapi_image_create (GstVaapiImage * image, GstVideoFormat format) +{ + GstVaapiDisplay *const display = GST_VAAPI_IMAGE_DISPLAY (image); + const VAImageFormat *va_format; + VAStatus status; + + if (!gst_vaapi_display_has_image_format (display, format)) + return FALSE; + + va_format = gst_vaapi_video_format_to_va_format (format); + if (!va_format) + return FALSE; + + GST_VAAPI_DISPLAY_LOCK (display); + status = vaCreateImage (GST_VAAPI_DISPLAY_VADISPLAY (display), + (VAImageFormat *) va_format, + image->width, image->height, &image->internal_image); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (status != VA_STATUS_SUCCESS || + image->internal_image.format.fourcc != va_format->fourcc) + return FALSE; + + image->internal_format = format; + return TRUE; +} + +static gboolean +gst_vaapi_image_create (GstVaapiImage * image, GstVideoFormat format, + guint width, guint height) +{ + const VAImageFormat *va_format; + VAImageID image_id; + + image->format = format; + image->width = width; + image->height = height; + + if (!_gst_vaapi_image_create (image, format)) { + switch (format) { + case GST_VIDEO_FORMAT_I420: + format = GST_VIDEO_FORMAT_YV12; + break; + case GST_VIDEO_FORMAT_YV12: + format = GST_VIDEO_FORMAT_I420; + break; + default: + format = 0; + break; + } + if (!format || !_gst_vaapi_image_create (image, format)) + return FALSE; + } + image->image = image->internal_image; + image_id = image->image.image_id; + + if (image->format != image->internal_format) { + switch (image->format) { + case GST_VIDEO_FORMAT_YV12: + case GST_VIDEO_FORMAT_I420: + va_format = gst_vaapi_video_format_to_va_format (image->format); + if (!va_format) + return FALSE; + image->image.format = *va_format; + SWAP_UINT (image->image.offsets[1], image->image.offsets[2]); + SWAP_UINT (image->image.pitches[1], image->image.pitches[2]); + break; + default: + break; + } + } + image->is_linear = vaapi_image_is_linear (&image->image); + + GST_DEBUG ("image %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (image_id)); + GST_VAAPI_IMAGE_ID (image) = image_id; + return TRUE; +} + +static void +gst_vaapi_image_init (GstVaapiImage * image, GstVaapiDisplay * display) +{ + /* TODO(victor): implement image copy mechanism, it's almost + * there */ + gst_mini_object_init (GST_MINI_OBJECT_CAST (image), 0, + GST_TYPE_VAAPI_IMAGE, NULL, NULL, + (GstMiniObjectFreeFunction) gst_vaapi_image_free); + + GST_VAAPI_IMAGE_DISPLAY (image) = gst_object_ref (display); + GST_VAAPI_IMAGE_ID (image) = VA_INVALID_ID; + image->internal_image.image_id = VA_INVALID_ID; + image->internal_image.buf = VA_INVALID_ID; + image->image.image_id = VA_INVALID_ID; + image->image.buf = VA_INVALID_ID; + image->image_data = NULL; + image->internal_format = image->format = GST_VIDEO_FORMAT_UNKNOWN; + image->width = image->height = 0; + image->is_linear = FALSE; +} + +GST_DEFINE_MINI_OBJECT_TYPE (GstVaapiImage, gst_vaapi_image); + +/** + * gst_vaapi_image_get_display: + * @image: a #GstVaapiImage + * + * Returns the #GstVaapiDisplay this @image is bound to. + * + * Return value: the parent #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_image_get_display (GstVaapiImage * image) +{ + g_return_val_if_fail (image != NULL, NULL); + return GST_VAAPI_IMAGE_DISPLAY (image); +} + +/** + * gst_vaapi_image_new: + * @display: a #GstVaapiDisplay + * @format: a #GstVideoFormat + * @width: the requested image width + * @height: the requested image height + * + * Creates a new #GstVaapiImage with the specified format and + * dimensions. + * + * Return value: the newly allocated #GstVaapiImage object + */ +GstVaapiImage * +gst_vaapi_image_new (GstVaapiDisplay * display, + GstVideoFormat format, guint width, guint height) +{ + GstVaapiImage *image; + + g_return_val_if_fail (width > 0, NULL); + g_return_val_if_fail (height > 0, NULL); + + GST_DEBUG ("format %s, size %ux%u", gst_vaapi_video_format_to_string (format), + width, height); + + image = g_slice_new (GstVaapiImage); + if (!image) + return NULL; + + gst_vaapi_image_init (image, display); + + if (!gst_vaapi_image_create (image, format, width, height)) + goto error; + return image; + + /* ERRORS */ +error: + { + gst_vaapi_image_unref (image); + return NULL; + } +} + +/** + * gst_vaapi_image_new_with_image: + * @display: a #GstVaapiDisplay + * @va_image: a VA image + * + * Creates a new #GstVaapiImage from a foreign VA image. The image + * format and dimensions will be extracted from @va_image. This + * function is mainly used by gst_vaapi_surface_derive_image() to bind + * a VA image to a #GstVaapiImage object. + * + * Return value: the newly allocated #GstVaapiImage object + */ +GstVaapiImage * +gst_vaapi_image_new_with_image (GstVaapiDisplay * display, VAImage * va_image) +{ + GstVaapiImage *image; + + g_return_val_if_fail (va_image, NULL); + g_return_val_if_fail (va_image->image_id != VA_INVALID_ID, NULL); + g_return_val_if_fail (va_image->buf != VA_INVALID_ID, NULL); + + GST_DEBUG ("VA image 0x%08x, format %" GST_FOURCC_FORMAT ", size %ux%u", + va_image->image_id, + GST_FOURCC_ARGS (va_image->format.fourcc), + va_image->width, va_image->height); + + image = g_slice_new (GstVaapiImage); + if (!image) + return NULL; + + gst_vaapi_image_init (image, display); + + if (!_gst_vaapi_image_set_image (image, va_image)) + goto error; + return image; + + /* ERRORS */ +error: + { + gst_vaapi_image_unref (image); + return NULL; + } +} + +/** + * gst_vaapi_image_get_id: + * @image: a #GstVaapiImage + * + * Returns the underlying VAImageID of the @image. + * + * Return value: the underlying VA image id + */ +GstVaapiID +gst_vaapi_image_get_id (GstVaapiImage * image) +{ + g_return_val_if_fail (image != NULL, VA_INVALID_ID); + + return GST_VAAPI_IMAGE_ID (image); +} + +/** + * gst_vaapi_image_get_image: + * @image: a #GstVaapiImage + * @va_image: a VA image + * + * Fills @va_image with the VA image used internally. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_image_get_image (GstVaapiImage * image, VAImage * va_image) +{ + g_return_val_if_fail (image != NULL, FALSE); + + if (va_image) + *va_image = image->image; + + return TRUE; +} + +/* + * _gst_vaapi_image_set_image: + * @image: a #GstVaapiImage + * @va_image: a VA image + * + * Initializes #GstVaapiImage with a foreign VA image. This function + * will try to "linearize" the VA image. i.e. making sure that the VA + * image offsets into the data buffer are in increasing order with the + * number of planes available in the image. + * + * This is an internal function used by gst_vaapi_image_new_with_image(). + * + * Return value: %TRUE on success + */ +gboolean +_gst_vaapi_image_set_image (GstVaapiImage * image, const VAImage * va_image) +{ + GstVideoFormat format; + VAImage alt_va_image; + const VAImageFormat *alt_va_format; + + format = gst_vaapi_video_format_from_va_format (&va_image->format); + if (format == GST_VIDEO_FORMAT_UNKNOWN) + return FALSE; + + image->internal_image = *va_image; + image->internal_format = format; + image->is_linear = vaapi_image_is_linear (va_image); + image->image = *va_image; + image->format = format; + image->width = va_image->width; + image->height = va_image->height; + + GST_VAAPI_IMAGE_ID (image) = va_image->image_id; + + /* Try to linearize image */ + if (!image->is_linear) { + switch (format) { + case GST_VIDEO_FORMAT_I420: + format = GST_VIDEO_FORMAT_YV12; + break; + case GST_VIDEO_FORMAT_YV12: + format = GST_VIDEO_FORMAT_I420; + break; + default: + format = 0; + break; + } + if (format && + (alt_va_format = gst_vaapi_video_format_to_va_format (format))) { + alt_va_image = *va_image; + alt_va_image.format = *alt_va_format; + SWAP_UINT (alt_va_image.offsets[1], alt_va_image.offsets[2]); + SWAP_UINT (alt_va_image.pitches[1], alt_va_image.pitches[2]); + if (vaapi_image_is_linear (&alt_va_image)) { + image->image = alt_va_image; + image->format = format; + image->is_linear = TRUE; + GST_DEBUG ("linearized image to %s format", + gst_vaapi_video_format_to_string (format)); + } + } + } + return TRUE; +} + +/** + * gst_vaapi_image_get_format: + * @image: a #GstVaapiImage + * + * Returns the #GstVideoFormat the @image was created with. + * + * Return value: the #GstVideoFormat + */ +GstVideoFormat +gst_vaapi_image_get_format (GstVaapiImage * image) +{ + g_return_val_if_fail (image != NULL, 0); + + return image->format; +} + +/** + * gst_vaapi_image_get_width: + * @image: a #GstVaapiImage + * + * Returns the @image width. + * + * Return value: the image width, in pixels + */ +guint +gst_vaapi_image_get_width (GstVaapiImage * image) +{ + g_return_val_if_fail (image != NULL, 0); + + return image->width; +} + +/** + * gst_vaapi_image_get_height: + * @image: a #GstVaapiImage + * + * Returns the @image height. + * + * Return value: the image height, in pixels. + */ +guint +gst_vaapi_image_get_height (GstVaapiImage * image) +{ + g_return_val_if_fail (image != NULL, 0); + + return image->height; +} + +/** + * gst_vaapi_image_get_size: + * @image: a #GstVaapiImage + * @pwidth: return location for the width, or %NULL + * @pheight: return location for the height, or %NULL + * + * Retrieves the dimensions of a #GstVaapiImage. + */ +void +gst_vaapi_image_get_size (GstVaapiImage * image, guint * pwidth, + guint * pheight) +{ + g_return_if_fail (image != NULL); + + if (pwidth) + *pwidth = image->width; + + if (pheight) + *pheight = image->height; +} + +/** + * gst_vaapi_image_is_linear: + * @image: a #GstVaapiImage + * + * Checks whether the @image has data planes allocated from a single + * buffer and offsets into that buffer are in increasing order with + * the number of planes. + * + * Return value: %TRUE if image data planes are allocated from a single buffer + */ +gboolean +gst_vaapi_image_is_linear (GstVaapiImage * image) +{ + g_return_val_if_fail (image != NULL, FALSE); + + return image->is_linear; +} + +/** + * gst_vaapi_image_is_mapped: + * @image: a #GstVaapiImage + * + * Checks whether the @image is currently mapped or not. + * + * Return value: %TRUE if the @image is mapped + */ +static inline gboolean +_gst_vaapi_image_is_mapped (GstVaapiImage * image) +{ + return image->image_data != NULL; +} + +gboolean +gst_vaapi_image_is_mapped (GstVaapiImage * image) +{ + g_return_val_if_fail (image != NULL, FALSE); + + return _gst_vaapi_image_is_mapped (image); +} + +/** + * gst_vaapi_image_map: + * @image: a #GstVaapiImage + * + * Maps the image data buffer. The actual pixels are returned by the + * gst_vaapi_image_get_plane() function. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_image_map (GstVaapiImage * image) +{ + g_return_val_if_fail (image != NULL, FALSE); + + return _gst_vaapi_image_map (image, NULL); +} + +gboolean +_gst_vaapi_image_map (GstVaapiImage * image, GstVaapiImageRaw * raw_image) +{ + GstVaapiDisplay *display; + VAStatus status; + guint i; + + if (_gst_vaapi_image_is_mapped (image)) + goto map_success; + + display = GST_VAAPI_IMAGE_DISPLAY (image); + if (!display) + return FALSE; + + GST_VAAPI_DISPLAY_LOCK (display); + status = vaMapBuffer (GST_VAAPI_DISPLAY_VADISPLAY (display), + image->image.buf, (void **) &image->image_data); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!vaapi_check_status (status, "vaMapBuffer()")) + return FALSE; + +map_success: + if (raw_image) { + const VAImage *const va_image = &image->image; + raw_image->format = image->format; + raw_image->width = va_image->width; + raw_image->height = va_image->height; + raw_image->num_planes = va_image->num_planes; + for (i = 0; i < raw_image->num_planes; i++) { + raw_image->pixels[i] = (guchar *) image->image_data + + va_image->offsets[i]; + raw_image->stride[i] = va_image->pitches[i]; + } + } + return TRUE; +} + +/** + * gst_vaapi_image_unmap: + * @image: a #GstVaapiImage + * + * Unmaps the image data buffer. Pointers to pixels returned by + * gst_vaapi_image_get_plane() are then no longer valid. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_image_unmap (GstVaapiImage * image) +{ + g_return_val_if_fail (image != NULL, FALSE); + + return _gst_vaapi_image_unmap (image); +} + +gboolean +_gst_vaapi_image_unmap (GstVaapiImage * image) +{ + GstVaapiDisplay *display; + VAStatus status; + + if (!_gst_vaapi_image_is_mapped (image)) + return TRUE; + + display = GST_VAAPI_IMAGE_DISPLAY (image); + if (!display) + return FALSE; + + GST_VAAPI_DISPLAY_LOCK (display); + status = vaUnmapBuffer (GST_VAAPI_DISPLAY_VADISPLAY (display), + image->image.buf); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!vaapi_check_status (status, "vaUnmapBuffer()")) + return FALSE; + + image->image_data = NULL; + return TRUE; +} + +/** + * gst_vaapi_image_get_plane_count: + * @image: a #GstVaapiImage + * + * Retrieves the number of planes available in the @image. The @image + * must be mapped for this function to work properly. + * + * Return value: the number of planes available in the @image + */ +guint +gst_vaapi_image_get_plane_count (GstVaapiImage * image) +{ + g_return_val_if_fail (image != NULL, 0); + g_return_val_if_fail (_gst_vaapi_image_is_mapped (image), 0); + + return image->image.num_planes; +} + +/** + * gst_vaapi_image_get_plane: + * @image: a #GstVaapiImage + * @plane: the requested plane number + * + * Retrieves the pixels data to the specified @plane. The @image must + * be mapped for this function to work properly. + * + * Return value: the pixels data of the specified @plane + */ +guchar * +gst_vaapi_image_get_plane (GstVaapiImage * image, guint plane) +{ + g_return_val_if_fail (image != NULL, NULL); + g_return_val_if_fail (_gst_vaapi_image_is_mapped (image), NULL); + g_return_val_if_fail (plane < image->image.num_planes, NULL); + + return image->image_data + image->image.offsets[plane]; +} + +/** + * gst_vaapi_image_get_pitch: + * @image: a #GstVaapiImage + * @plane: the requested plane number + * + * Retrieves the line size (stride) of the specified @plane. The + * @image must be mapped for this function to work properly. + * + * Return value: the line size (stride) of the specified plane + */ +guint +gst_vaapi_image_get_pitch (GstVaapiImage * image, guint plane) +{ + g_return_val_if_fail (image != NULL, 0); + g_return_val_if_fail (_gst_vaapi_image_is_mapped (image), 0); + g_return_val_if_fail (plane < image->image.num_planes, 0); + + return image->image.pitches[plane]; +} + +/** + * gst_vaapi_image_get_data_size: + * @image: a #GstVaapiImage + * + * Retrieves the underlying image data size. This function could be + * used to determine whether the image has a compatible layout with + * another image structure. + * + * Return value: the whole image data size of the @image + */ +guint +gst_vaapi_image_get_data_size (GstVaapiImage * image) +{ + g_return_val_if_fail (image != NULL, 0); + + return image->image.data_size; +} + +#include + +static gboolean +init_image_from_video_meta (GstVaapiImageRaw * raw_image, GstVideoMeta * vmeta) +{ + GST_FIXME ("map from GstVideoMeta + add fini_image_from_buffer()"); + return FALSE; +} + +static gboolean +init_image_from_buffer (GstVaapiImageRaw * raw_image, GstBuffer * buffer) +{ + GstVideoMeta *const vmeta = gst_buffer_get_video_meta (buffer); + + return vmeta ? init_image_from_video_meta (raw_image, vmeta) : FALSE; +} + +/* Copy N lines of an image */ +static inline void +memcpy_pic (guchar * dst, + guint dst_stride, + const guchar * src, guint src_stride, guint len, guint height) +{ + guint i; + + for (i = 0; i < height; i++) { + memcpy (dst, src, len); + dst += dst_stride; + src += src_stride; + } +} + +/* Copy NV12 images */ +static void +copy_image_NV12 (GstVaapiImageRaw * dst_image, + GstVaapiImageRaw * src_image, const GstVaapiRectangle * rect) +{ + guchar *dst, *src; + guint dst_stride, src_stride; + + /* Y plane */ + dst_stride = dst_image->stride[0]; + dst = dst_image->pixels[0] + rect->y * dst_stride + rect->x; + src_stride = src_image->stride[0]; + src = src_image->pixels[0] + rect->y * src_stride + rect->x; + memcpy_pic (dst, dst_stride, src, src_stride, rect->width, rect->height); + + /* UV plane */ + dst_stride = dst_image->stride[1]; + dst = dst_image->pixels[1] + (rect->y / 2) * dst_stride + (rect->x & -2); + src_stride = src_image->stride[1]; + src = src_image->pixels[1] + (rect->y / 2) * src_stride + (rect->x & -2); + memcpy_pic (dst, dst_stride, src, src_stride, rect->width, rect->height / 2); +} + +/* Copy YV12 images */ +static void +copy_image_YV12 (GstVaapiImageRaw * dst_image, + GstVaapiImageRaw * src_image, const GstVaapiRectangle * rect) +{ + guchar *dst, *src; + guint dst_stride, src_stride; + guint i, x, y, w, h; + + /* Y plane */ + dst_stride = dst_image->stride[0]; + dst = dst_image->pixels[0] + rect->y * dst_stride + rect->x; + src_stride = src_image->stride[0]; + src = src_image->pixels[0] + rect->y * src_stride + rect->x; + memcpy_pic (dst, dst_stride, src, src_stride, rect->width, rect->height); + + /* U/V planes */ + x = rect->x / 2; + y = rect->y / 2; + w = rect->width / 2; + h = rect->height / 2; + for (i = 1; i < dst_image->num_planes; i++) { + dst_stride = dst_image->stride[i]; + dst = dst_image->pixels[i] + y * dst_stride + x; + src_stride = src_image->stride[i]; + src = src_image->pixels[i] + y * src_stride + x; + memcpy_pic (dst, dst_stride, src, src_stride, w, h); + } +} + +/* Copy YUY2 images */ +static void +copy_image_YUY2 (GstVaapiImageRaw * dst_image, + GstVaapiImageRaw * src_image, const GstVaapiRectangle * rect) +{ + guchar *dst, *src; + guint dst_stride, src_stride; + + /* YUV 4:2:2, full vertical resolution */ + dst_stride = dst_image->stride[0]; + dst = dst_image->pixels[0] + rect->y * dst_stride + rect->x * 2; + src_stride = src_image->stride[0]; + src = src_image->pixels[0] + rect->y * src_stride + rect->x * 2; + memcpy_pic (dst, dst_stride, src, src_stride, rect->width * 2, rect->height); +} + +/* Copy RGBA images */ +static void +copy_image_RGBA (GstVaapiImageRaw * dst_image, + GstVaapiImageRaw * src_image, const GstVaapiRectangle * rect) +{ + guchar *dst, *src; + guint dst_stride, src_stride; + + dst_stride = dst_image->stride[0]; + dst = dst_image->pixels[0] + rect->y * dst_stride + rect->x; + src_stride = src_image->stride[0]; + src = src_image->pixels[0] + rect->y * src_stride + rect->x; + memcpy_pic (dst, dst_stride, src, src_stride, 4 * rect->width, rect->height); +} + +static gboolean +copy_image (GstVaapiImageRaw * dst_image, + GstVaapiImageRaw * src_image, const GstVaapiRectangle * rect) +{ + GstVaapiRectangle default_rect; + + if (dst_image->format != src_image->format || + dst_image->width != src_image->width || + dst_image->height != src_image->height) + return FALSE; + + if (rect) { + if (rect->x >= src_image->width || + rect->x + rect->width > src_image->width || + rect->y >= src_image->height || + rect->y + rect->height > src_image->height) + return FALSE; + } else { + default_rect.x = 0; + default_rect.y = 0; + default_rect.width = src_image->width; + default_rect.height = src_image->height; + rect = &default_rect; + } + + switch (dst_image->format) { + case GST_VIDEO_FORMAT_NV12: + copy_image_NV12 (dst_image, src_image, rect); + break; + case GST_VIDEO_FORMAT_YV12: + case GST_VIDEO_FORMAT_I420: + copy_image_YV12 (dst_image, src_image, rect); + break; + case GST_VIDEO_FORMAT_YUY2: + case GST_VIDEO_FORMAT_UYVY: + copy_image_YUY2 (dst_image, src_image, rect); + break; + case GST_VIDEO_FORMAT_ARGB: + case GST_VIDEO_FORMAT_RGBA: + case GST_VIDEO_FORMAT_ABGR: + case GST_VIDEO_FORMAT_BGRA: + copy_image_RGBA (dst_image, src_image, rect); + break; + default: + GST_ERROR ("unsupported image format for copy"); + return FALSE; + } + return TRUE; +} + +/** + * gst_vaapi_image_get_buffer: + * @image: a #GstVaapiImage + * @buffer: a #GstBuffer + * @rect: a #GstVaapiRectangle expressing a region, or %NULL for the + * whole image + * + * Transfers pixels data contained in the @image into the #GstBuffer. + * Both image structures shall have the same format. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_image_get_buffer (GstVaapiImage * image, + GstBuffer * buffer, GstVaapiRectangle * rect) +{ + GstVaapiImageRaw dst_image, src_image; + gboolean success; + + g_return_val_if_fail (image != NULL, FALSE); + g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE); + + if (!init_image_from_buffer (&dst_image, buffer)) + return FALSE; + if (dst_image.format != image->format) + return FALSE; + if (dst_image.width != image->width || dst_image.height != image->height) + return FALSE; + + if (!_gst_vaapi_image_map (image, &src_image)) + return FALSE; + + success = copy_image (&dst_image, &src_image, rect); + + if (!_gst_vaapi_image_unmap (image)) + return FALSE; + + return success; +} + +/** + * gst_vaapi_image_get_raw: + * @image: a #GstVaapiImage + * @dst_image: a #GstVaapiImageRaw + * @rect: a #GstVaapiRectangle expressing a region, or %NULL for the + * whole image + * + * Transfers pixels data contained in the @image into the #GstVaapiImageRaw. + * Both image structures shall have the same format. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_image_get_raw (GstVaapiImage * image, + GstVaapiImageRaw * dst_image, GstVaapiRectangle * rect) +{ + GstVaapiImageRaw src_image; + gboolean success; + + g_return_val_if_fail (image != NULL, FALSE); + + if (!_gst_vaapi_image_map (image, &src_image)) + return FALSE; + + success = copy_image (dst_image, &src_image, rect); + + if (!_gst_vaapi_image_unmap (image)) + return FALSE; + + return success; +} + +/** + * gst_vaapi_image_update_from_buffer: + * @image: a #GstVaapiImage + * @buffer: a #GstBuffer + * @rect: a #GstVaapiRectangle expressing a region, or %NULL for the + * whole image + * + * Transfers pixels data contained in the #GstBuffer into the + * @image. Both image structures shall have the same format. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_image_update_from_buffer (GstVaapiImage * image, + GstBuffer * buffer, GstVaapiRectangle * rect) +{ + GstVaapiImageRaw dst_image, src_image; + gboolean success; + + g_return_val_if_fail (image != NULL, FALSE); + g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE); + + if (!init_image_from_buffer (&src_image, buffer)) + return FALSE; + if (src_image.format != image->format) + return FALSE; + if (src_image.width != image->width || src_image.height != image->height) + return FALSE; + + if (!_gst_vaapi_image_map (image, &dst_image)) + return FALSE; + + success = copy_image (&dst_image, &src_image, rect); + + if (!_gst_vaapi_image_unmap (image)) + return FALSE; + + return success; +} + +/** + * gst_vaapi_image_update_from_raw: + * @image: a #GstVaapiImage + * @src_image: a #GstVaapiImageRaw + * @buffer: a #GstBuffer + * @rect: a #GstVaapiRectangle expressing a region, or %NULL for the + * whole image + * + * Transfers pixels data contained in the #GstVaapiImageRaw into the + * @image. Both image structures shall have the same format. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_image_update_from_raw (GstVaapiImage * image, + GstVaapiImageRaw * src_image, GstVaapiRectangle * rect) +{ + GstVaapiImageRaw dst_image; + gboolean success; + + g_return_val_if_fail (image != NULL, FALSE); + + if (!_gst_vaapi_image_map (image, &dst_image)) + return FALSE; + + success = copy_image (&dst_image, src_image, rect); + + if (!_gst_vaapi_image_unmap (image)) + return FALSE; + + return success; +} + +/** + * gst_vaapi_image_copy: + * @dst_image: the target #GstVaapiImage + * @src_image: the source #GstVaapiImage + * + * Copies pixels data from @src_image to @dst_image. Both images shall + * have the same format and size. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_image_copy (GstVaapiImage * dst_image, GstVaapiImage * src_image) +{ + GstVaapiImageRaw dst_image_raw, src_image_raw; + gboolean success = FALSE; + + g_return_val_if_fail (dst_image != NULL, FALSE); + g_return_val_if_fail (src_image != NULL, FALSE); + + if (!_gst_vaapi_image_map (dst_image, &dst_image_raw)) + goto end; + if (!_gst_vaapi_image_map (src_image, &src_image_raw)) + goto end; + + success = copy_image (&dst_image_raw, &src_image_raw, NULL); + +end: + _gst_vaapi_image_unmap (src_image); + _gst_vaapi_image_unmap (dst_image); + return success; +} diff --git a/gst-libs/gst/vaapi/gstvaapiimage.h b/gst-libs/gst/vaapi/gstvaapiimage.h new file mode 100644 index 0000000000..12ac9f49da --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiimage.h @@ -0,0 +1,174 @@ +/* + * gstvaapiimage.h - VA image abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_IMAGE_H +#define GST_VAAPI_IMAGE_H + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_IMAGE(obj) \ + ((GstVaapiImage *)(obj)) + +/** + * GST_VAAPI_IMAGE_FORMAT: + * @image: a #GstVaapiImage + * + * Macro that evaluates to the #GstVideoFormat of @image. + */ +#define GST_VAAPI_IMAGE_FORMAT(image) gst_vaapi_image_get_format(image) + +/** + * GST_VAAPI_IMAGE_WIDTH: + * @image: a #GstVaapiImage + * + * Macro that evaluates to the width of @image. + */ +#define GST_VAAPI_IMAGE_WIDTH(image) gst_vaapi_image_get_width(image) + +/** + * GST_VAAPI_IMAGE_HEIGHT: + * @image: a #GstVaapiImage + * + * Macro that evaluates to the height of @image. + */ +#define GST_VAAPI_IMAGE_HEIGHT(image) gst_vaapi_image_get_height(image) + +/** + * GST_VAAPI_IMAGE_DISPLAY: + * @image: a #GstVaapiImage + * + * Macro that evaluates to the display of @image + */ +#define GST_VAAPI_IMAGE_DISPLAY(image) gst_vaapi_image_get_display(image) + +/** + * GST_VAAPI_IMAGE_ID: + * @image: a #GstVaapiImage + * + * Macro that evaluates to the ID of @image + */ +#define GST_VAAPI_IMAGE_ID(image) gst_vaapi_image_get_id(image) + +#define GST_TYPE_VAAPI_IMAGE (gst_vaapi_image_get_type ()) + +typedef struct _GstVaapiImage GstVaapiImage; + +GType +gst_vaapi_image_get_type (void) G_GNUC_CONST; + +GstVaapiDisplay * +gst_vaapi_image_get_display (GstVaapiImage * image); + +GstVaapiImage * +gst_vaapi_image_new( + GstVaapiDisplay *display, + GstVideoFormat format, + guint width, + guint height +); + +GstVaapiImage * +gst_vaapi_image_new_with_image(GstVaapiDisplay *display, VAImage *va_image); + +/** + * gst_vaapi_image_unref: (skip) + * @image: (transfer full): a #GstVaapiImage. + * + * Decreases the refcount of the image. If the refcount reaches 0, the + * image will be freed. + */ +static inline void +gst_vaapi_image_unref (GstVaapiImage * image) +{ + gst_mini_object_unref (GST_MINI_OBJECT_CAST (image)); +} + +GstVaapiID +gst_vaapi_image_get_id(GstVaapiImage *image); + +gboolean +gst_vaapi_image_get_image(GstVaapiImage *image, VAImage *va_image); + +GstVideoFormat +gst_vaapi_image_get_format(GstVaapiImage *image); + +guint +gst_vaapi_image_get_width(GstVaapiImage *image); + +guint +gst_vaapi_image_get_height(GstVaapiImage *image); + +void +gst_vaapi_image_get_size(GstVaapiImage *image, guint *pwidth, guint *pheight); + +gboolean +gst_vaapi_image_is_linear(GstVaapiImage *image); + +gboolean +gst_vaapi_image_is_mapped(GstVaapiImage *image); + +gboolean +gst_vaapi_image_map(GstVaapiImage *image); + +gboolean +gst_vaapi_image_unmap(GstVaapiImage *image); + +guint +gst_vaapi_image_get_plane_count(GstVaapiImage *image); + +guchar * +gst_vaapi_image_get_plane(GstVaapiImage *image, guint plane); + +guint +gst_vaapi_image_get_pitch(GstVaapiImage *image, guint plane); + +guint +gst_vaapi_image_get_data_size(GstVaapiImage *image); + +gboolean +gst_vaapi_image_get_buffer( + GstVaapiImage *image, + GstBuffer *buffer, + GstVaapiRectangle *rect +); + +gboolean +gst_vaapi_image_update_from_buffer( + GstVaapiImage *image, + GstBuffer *buffer, + GstVaapiRectangle *rect +); + +gboolean +gst_vaapi_image_copy(GstVaapiImage *dst_image, GstVaapiImage *src_image); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiImage, gst_vaapi_image_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_IMAGE_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiimage_priv.h b/gst-libs/gst/vaapi/gstvaapiimage_priv.h new file mode 100644 index 0000000000..584de56d2a --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiimage_priv.h @@ -0,0 +1,139 @@ +/* + * gstvaapiimage_priv.h - VA image abstraction (private definitions) + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_IMAGE_PRIV_H +#define GST_VAAPI_IMAGE_PRIV_H + +#include + +G_BEGIN_DECLS + +typedef struct _GstVaapiImageRaw GstVaapiImageRaw; + +/** + * GstVaapiImage: + * + * A VA image wrapper + */ +struct _GstVaapiImage { + /*< private >*/ + GstMiniObject mini_object; + GstVaapiDisplay *display; + GstVaapiID object_id; + + VAImage internal_image; + VAImage image; + guchar *image_data; + GstVideoFormat internal_format; + GstVideoFormat format; + guint width; + guint height; + guint is_linear : 1; +}; + +/** + * GstVaapiImageRaw: + * + * A raw image wrapper. The caller is responsible for initializing all + * the fields with sensible values. + */ +struct _GstVaapiImageRaw { + GstVideoFormat format; + guint width; + guint height; + guint num_planes; + guchar *pixels[3]; + guint stride[3]; +}; + +/** + * GST_VAAPI_IMAGE_FORMAT: + * @image: a #GstVaapiImage + * + * Macro that evaluates to the #GstVideoFormat of @image. + */ +#undef GST_VAAPI_IMAGE_FORMAT +#define GST_VAAPI_IMAGE_FORMAT(image) \ + (GST_VAAPI_IMAGE(image)->format) + +/** + * GST_VAAPI_IMAGE_WIDTH: + * @image: a #GstVaapiImage + * + * Macro that evaluates to the width of @image. + */ +#undef GST_VAAPI_IMAGE_WIDTH +#define GST_VAAPI_IMAGE_WIDTH(image) \ + (GST_VAAPI_IMAGE(image)->width) + +/** + * GST_VAAPI_IMAGE_HEIGHT: + * @image: a #GstVaapiImage + * + * Macro that evaluates to the height of @image. + */ +#undef GST_VAAPI_IMAGE_HEIGHT +#define GST_VAAPI_IMAGE_HEIGHT(image) \ + (GST_VAAPI_IMAGE(image)->height) + +/** + * GST_VAAPI_IMAGE_DISPLAY: + * @image: a #GstVaapiImage + * + * Macro that evaluates to the @image's display + */ +#undef GST_VAAPI_IMAGE_DISPLAY +#define GST_VAAPI_IMAGE_DISPLAY(image) \ + (GST_VAAPI_IMAGE(image)->display) + +/** + * GST_VAAPI_IMAGE_ID: + * @image: a #GstVaapiImage + * + * Macro that evaluates to the @image's object ID + */ +#undef GST_VAAPI_IMAGE_ID +#define GST_VAAPI_IMAGE_ID(image) \ + (GST_VAAPI_IMAGE(image)->object_id) + + +G_GNUC_INTERNAL +gboolean +gst_vaapi_image_get_raw( + GstVaapiImage *image, + GstVaapiImageRaw *dst_image, + GstVaapiRectangle *rect +); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_image_update_from_raw( + GstVaapiImage *image, + GstVaapiImageRaw *src_image, + GstVaapiRectangle *rect +); + +G_END_DECLS + +#endif /* GST_VAAPI_IMAGE_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiimagepool.c b/gst-libs/gst/vaapi/gstvaapiimagepool.c new file mode 100644 index 0000000000..f64a367945 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiimagepool.c @@ -0,0 +1,120 @@ +/* + * gstvaapiimagepool.c - Gst VA image pool + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapiimagepool + * @short_description: VA image pool + */ + +#include "sysdeps.h" +#include "gstvaapiimagepool.h" +#include "gstvaapivideopool_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +/** + * GstVaapiImagePool: + * + * A pool of lazily allocated #GstVaapiImage objects. + */ +struct _GstVaapiImagePool +{ + /*< private > */ + GstVaapiVideoPool parent_instance; + + GstVideoFormat format; + guint width; + guint height; +}; + +static gboolean +image_pool_init (GstVaapiVideoPool * base_pool, const GstVideoInfo * vip) +{ + GstVaapiImagePool *const pool = GST_VAAPI_IMAGE_POOL (base_pool); + + pool->format = GST_VIDEO_INFO_FORMAT (vip); + pool->width = GST_VIDEO_INFO_WIDTH (vip); + pool->height = GST_VIDEO_INFO_HEIGHT (vip); + return gst_vaapi_display_has_image_format (base_pool->display, pool->format); +} + +static gpointer +gst_vaapi_image_pool_alloc_object (GstVaapiVideoPool * base_pool) +{ + GstVaapiImagePool *const pool = GST_VAAPI_IMAGE_POOL (base_pool); + + return gst_vaapi_image_new (base_pool->display, pool->format, + pool->width, pool->height); +} + +static inline const GstVaapiMiniObjectClass * +gst_vaapi_image_pool_class (void) +{ + static const GstVaapiVideoPoolClass GstVaapiImagePoolClass = { + {sizeof (GstVaapiImagePool), + (GDestroyNotify) gst_vaapi_video_pool_finalize} + , + .alloc_object = gst_vaapi_image_pool_alloc_object + }; + return GST_VAAPI_MINI_OBJECT_CLASS (&GstVaapiImagePoolClass); +} + +/** + * gst_vaapi_image_pool_new: + * @display: a #GstVaapiDisplay + * @vip: the #GstVideoInfo + * + * Creates a new #GstVaapiVideoPool of #GstVaapiImage with the + * specified format and dimensions in @vip. + * + * Return value: the newly allocated #GstVaapiVideoPool + */ +GstVaapiVideoPool * +gst_vaapi_image_pool_new (GstVaapiDisplay * display, const GstVideoInfo * vip) +{ + GstVaapiVideoPool *pool; + + g_return_val_if_fail (display != NULL, NULL); + g_return_val_if_fail (vip != NULL, NULL); + + pool = (GstVaapiVideoPool *) + gst_vaapi_mini_object_new (gst_vaapi_image_pool_class ()); + if (!pool) + return NULL; + + gst_vaapi_video_pool_init (pool, display, + GST_VAAPI_VIDEO_POOL_OBJECT_TYPE_IMAGE); + + if (!image_pool_init (pool, vip)) + goto error; + return pool; + + /* ERRORS */ +error: + { + gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (pool)); + return NULL; + } +} diff --git a/gst-libs/gst/vaapi/gstvaapiimagepool.h b/gst-libs/gst/vaapi/gstvaapiimagepool.h new file mode 100644 index 0000000000..7222bd99ae --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiimagepool.h @@ -0,0 +1,44 @@ +/* + * gstvaapiimagepool.h - Gst VA image pool + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_IMAGE_POOL_H +#define GST_VAAPI_IMAGE_POOL_H + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_IMAGE_POOL(obj) \ + ((GstVaapiImagePool *)(obj)) + +typedef struct _GstVaapiImagePool GstVaapiImagePool; + +GstVaapiVideoPool * +gst_vaapi_image_pool_new (GstVaapiDisplay * display, const GstVideoInfo * vip); + +G_END_DECLS + +#endif /* GST_VAAPI_IMAGE_POOL_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiminiobject.c b/gst-libs/gst/vaapi/gstvaapiminiobject.c new file mode 100644 index 0000000000..30586b04be --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiminiobject.c @@ -0,0 +1,201 @@ +/* + * gstvaapiminiobject.c - A lightweight reference counted object + * + * Copyright (C) 2012-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include +#include "gstvaapiminiobject.h" + +static void +gst_vaapi_mini_object_free (GstVaapiMiniObject * object) +{ + const GstVaapiMiniObjectClass *const klass = object->object_class; + + g_atomic_int_inc (&object->ref_count); + + if (klass->finalize) + klass->finalize (object); + + if (G_LIKELY (g_atomic_int_dec_and_test (&object->ref_count))) + g_slice_free1 (klass->size, object); +} + +/** + * gst_vaapi_mini_object_new: + * @object_class: (optional): The object class + * + * Creates a new #GstVaapiMiniObject. If @object_class is NULL, then the + * size of the allocated object is the same as sizeof(GstVaapiMiniObject). + * If @object_class is not NULL, typically when a sub-class is implemented, + * that pointer shall reference a statically allocated descriptor. + * + * This function does *not* zero-initialize the derived object data, + * use gst_vaapi_mini_object_new0() to fill this purpose. + * + * Returns: The newly allocated #GstVaapiMiniObject + */ +GstVaapiMiniObject * +gst_vaapi_mini_object_new (const GstVaapiMiniObjectClass * object_class) +{ + GstVaapiMiniObject *object; + + static const GstVaapiMiniObjectClass default_object_class = { + .size = sizeof (GstVaapiMiniObject), + }; + + if (G_UNLIKELY (!object_class)) + object_class = &default_object_class; + + g_return_val_if_fail (object_class->size >= sizeof (*object), NULL); + + object = g_slice_alloc (object_class->size); + if (!object) + return NULL; + + object->object_class = object_class; + g_atomic_int_set (&object->ref_count, 1); + object->flags = 0; + return object; +} + +/** + * gst_vaapi_mini_object_new0: + * @object_class: (optional): The object class + * + * Creates a new #GstVaapiMiniObject. This function is similar to + * gst_vaapi_mini_object_new() but derived object data is initialized + * to zeroes. + * + * Returns: The newly allocated #GstVaapiMiniObject + */ +GstVaapiMiniObject * +gst_vaapi_mini_object_new0 (const GstVaapiMiniObjectClass * object_class) +{ + GstVaapiMiniObject *object; + guint sub_size; + + object = gst_vaapi_mini_object_new (object_class); + if (!object) + return NULL; + + object_class = object->object_class; + + sub_size = object_class->size - sizeof (*object); + if (sub_size > 0) + memset (((guchar *) object) + sizeof (*object), 0, sub_size); + return object; +} + +/** + * gst_vaapi_mini_object_ref_internal: + * @object: a #GstVaapiMiniObject + * + * Atomically increases the reference count of the given @object by one. + * This is an internal function that does not do any run-time type check. + * + * Returns: The same @object argument + */ +static inline GstVaapiMiniObject * +gst_vaapi_mini_object_ref_internal (GstVaapiMiniObject * object) +{ + g_atomic_int_inc (&object->ref_count); + return object; +} + +/** + * gst_vaapi_mini_object_ref: + * @object: a #GstVaapiMiniObject + * + * Atomically increases the reference count of the given @object by one. + * + * Returns: The same @object argument + */ +GstVaapiMiniObject * +gst_vaapi_mini_object_ref (GstVaapiMiniObject * object) +{ + g_return_val_if_fail (object != NULL, NULL); + + return gst_vaapi_mini_object_ref_internal (object); +} + +/** + * gst_vaapi_mini_object_unref_internal: + * @object: a #GstVaapiMiniObject + * + * Atomically decreases the reference count of the @object by one. If + * the reference count reaches zero, the object will be free'd. + * + * This is an internal function that does not do any run-time type check. + */ +static inline void +gst_vaapi_mini_object_unref_internal (GstVaapiMiniObject * object) +{ + if (g_atomic_int_dec_and_test (&object->ref_count)) + gst_vaapi_mini_object_free (object); +} + +/** + * gst_vaapi_mini_object_unref: + * @object: a #GstVaapiMiniObject + * + * Atomically decreases the reference count of the @object by one. If + * the reference count reaches zero, the object will be free'd. + */ +void +gst_vaapi_mini_object_unref (GstVaapiMiniObject * object) +{ + g_return_if_fail (object != NULL); + g_return_if_fail (object->ref_count > 0); + + gst_vaapi_mini_object_unref_internal (object); +} + +/** + * gst_vaapi_mini_object_replace: + * @old_object_ptr: a pointer to a #GstVaapiMiniObject + * @new_object: a #GstVaapiMiniObject + * + * Atomically replaces the object held in @old_object_ptr with + * @new_object. This means that @old_object_ptr shall reference a + * valid object. However, @new_object can be NULL. + */ +void +gst_vaapi_mini_object_replace (GstVaapiMiniObject ** old_object_ptr, + GstVaapiMiniObject * new_object) +{ + GstVaapiMiniObject *old_object; + + g_return_if_fail (old_object_ptr != NULL); + + old_object = g_atomic_pointer_get ((gpointer *) old_object_ptr); + + if (old_object == new_object) + return; + + if (new_object) + gst_vaapi_mini_object_ref_internal (new_object); + + while (!g_atomic_pointer_compare_and_exchange ((gpointer *) old_object_ptr, + (gpointer) old_object, new_object)) + old_object = g_atomic_pointer_get ((gpointer *) old_object_ptr); + + if (old_object) + gst_vaapi_mini_object_unref_internal (old_object); +} diff --git a/gst-libs/gst/vaapi/gstvaapiminiobject.h b/gst-libs/gst/vaapi/gstvaapiminiobject.h new file mode 100644 index 0000000000..52f28636de --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiminiobject.h @@ -0,0 +1,162 @@ +/* + * gstvaapiminiobject.h - A lightweight reference counted object + * + * Copyright (C) 2012-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_MINI_OBJECT_H +#define GST_VAAPI_MINI_OBJECT_H + +#include + +G_BEGIN_DECLS + +typedef struct _GstVaapiMiniObject GstVaapiMiniObject; +typedef struct _GstVaapiMiniObjectClass GstVaapiMiniObjectClass; + +/** + * GST_VAAPI_MINI_OBJECT: + * @object: a #GstVaapiMiniObject + * + * Casts the @object to a #GstVaapiMiniObject + */ +#define GST_VAAPI_MINI_OBJECT(object) \ + ((GstVaapiMiniObject *) (object)) + +/** + * GST_VAAPI_MINI_OBJECT_PTR: + * @object_ptr: a pointer #GstVaapiMiniObject + * + * Casts the @object_ptr to a pointer to #GstVaapiMiniObject + */ +#define GST_VAAPI_MINI_OBJECT_PTR(object_ptr) \ + ((GstVaapiMiniObject **) (object_ptr)) + +/** + * GST_VAAPI_MINI_OBJECT_CLASS: + * @klass: a #GstVaapiMiniObjectClass + * + * Casts the @klass to a #GstVaapiMiniObjectClass + */ +#define GST_VAAPI_MINI_OBJECT_CLASS(klass) \ + ((GstVaapiMiniObjectClass *) (klass)) + +/** + * GST_VAAPI_MINI_OBJECT_GET_CLASS: + * @object: a #GstVaapiMiniObject + * + * Retrieves the #GstVaapiMiniObjectClass associated with the @object + */ +#define GST_VAAPI_MINI_OBJECT_GET_CLASS(object) \ + (GST_VAAPI_MINI_OBJECT (object)->object_class) + +/** + * GST_VAAPI_MINI_OBJECT_FLAGS: + * @object: a #GstVaapiMiniObject + * + * The entire set of flags for the @object + */ +#define GST_VAAPI_MINI_OBJECT_FLAGS(object) \ + (GST_VAAPI_MINI_OBJECT (object)->flags) + +/** + * GST_VAAPI_MINI_OBJECT_FLAG_IS_SET: + * @object: a #GstVaapiMiniObject + * @flag: a flag to check for + * + * Checks whether the given @flag is set + */ +#define GST_VAAPI_MINI_OBJECT_FLAG_IS_SET(object, flag) \ + ((GST_VAAPI_MINI_OBJECT_FLAGS (object) & (flag)) != 0) + +/** + * GST_VAAPI_MINI_OBJECT_FLAG_SET: + * @object: a #GstVaapiMiniObject + * @flags: flags to set + * + * This macro sets the given bits + */ +#define GST_VAAPI_MINI_OBJECT_FLAG_SET(object, flags) \ + (GST_VAAPI_MINI_OBJECT_FLAGS (object) |= (flags)) + +/** + * GST_VAAPI_MINI_OBJECT_FLAG_UNSET: + * @object: a #GstVaapiMiniObject + * @flags: flags to unset + * + * This macro unsets the given bits. + */ +#define GST_VAAPI_MINI_OBJECT_FLAG_UNSET(object, flags) \ + (GST_VAAPI_MINI_OBJECT_FLAGS (object) &= ~(flags)) + +/** + * GstVaapiMiniObject: + * @object_class: the #GstVaapiMiniObjectClass + * @ref_count: the object reference count that should be manipulated + * through gst_vaapi_mini_object_ref() et al. helpers + * @flags: set of flags that should be manipulated through + * GST_VAAPI_MINI_OBJECT_FLAG_*() functions + * + * A #GstVaapiMiniObject represents a minimal reference counted data + * structure that can hold a set of flags and user-provided data. + */ +struct _GstVaapiMiniObject +{ + /*< private >*/ + gconstpointer object_class; + gint ref_count; + guint flags; +}; + +/** + * GstVaapiMiniObjectClass: + * @size: size in bytes of the #GstVaapiMiniObject, plus any + * additional data for derived classes + * @finalize: function called to destroy data in derived classes + * + * A #GstVaapiMiniObjectClass represents the base object class that + * defines the size of the #GstVaapiMiniObject and utility function to + * dispose child objects + */ +struct _GstVaapiMiniObjectClass +{ + /*< protected >*/ + guint size; + GDestroyNotify finalize; +}; + +GstVaapiMiniObject * +gst_vaapi_mini_object_new (const GstVaapiMiniObjectClass * object_class); + +GstVaapiMiniObject * +gst_vaapi_mini_object_new0 (const GstVaapiMiniObjectClass * object_class); + +GstVaapiMiniObject * +gst_vaapi_mini_object_ref (GstVaapiMiniObject * object); + +void +gst_vaapi_mini_object_unref (GstVaapiMiniObject * object); + +void +gst_vaapi_mini_object_replace (GstVaapiMiniObject ** old_object_ptr, + GstVaapiMiniObject * new_object); + +G_END_DECLS + +#endif /* GST_VAAPI_MINI_OBJECT_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiparser_frame.c b/gst-libs/gst/vaapi/gstvaapiparser_frame.c new file mode 100644 index 0000000000..66da510bdc --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiparser_frame.c @@ -0,0 +1,150 @@ +/* + * gstvaapiparser_frame.c - VA parser frame + * + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapiparser_frame + * @short_description: VA decoder frame + */ + +#include "sysdeps.h" +#include "gstvaapiparser_frame.h" + +static inline const GstVaapiMiniObjectClass * +gst_vaapi_parser_frame_class (void) +{ + static const GstVaapiMiniObjectClass GstVaapiParserFrameClass = { + sizeof (GstVaapiParserFrame), + (GDestroyNotify) gst_vaapi_parser_frame_free + }; + return &GstVaapiParserFrameClass; +} + +static inline gboolean +alloc_units (GArray ** units_ptr, guint size) +{ + GArray *units; + + units = g_array_sized_new (FALSE, FALSE, sizeof (GstVaapiDecoderUnit), size); + *units_ptr = units; + return units != NULL; +} + +static inline void +free_units (GArray ** units_ptr) +{ + GArray *const units = *units_ptr; + guint i; + + if (units) { + for (i = 0; i < units->len; i++) { + GstVaapiDecoderUnit *const unit = + &g_array_index (units, GstVaapiDecoderUnit, i); + gst_vaapi_decoder_unit_clear (unit); + } + g_array_unref (units); + *units_ptr = NULL; + } +} + +/** + * gst_vaapi_parser_frame_new: + * @width: frame width in pixels + * @height: frame height in pixels + * + * Creates a new #GstVaapiParserFrame object. + * + * Returns: The newly allocated #GstVaapiParserFrame + */ +GstVaapiParserFrame * +gst_vaapi_parser_frame_new (guint width, guint height) +{ + GstVaapiParserFrame *frame; + guint num_slices; + + frame = (GstVaapiParserFrame *) + gst_vaapi_mini_object_new (gst_vaapi_parser_frame_class ()); + if (!frame) + return NULL; + + if (!height) + height = 1088; + num_slices = (height + 15) / 16; + + if (!alloc_units (&frame->pre_units, 16)) + goto error; + if (!alloc_units (&frame->units, num_slices)) + goto error; + if (!alloc_units (&frame->post_units, 1)) + goto error; + frame->output_offset = 0; + return frame; + + /* ERRORS */ +error: + { + gst_vaapi_parser_frame_unref (frame); + return NULL; + } +} + +/** + * gst_vaapi_parser_frame_free: + * @frame: a #GstVaapiParserFrame + * + * Deallocates any internal resources bound to the supplied decoder + * @frame. + * + * @note This is an internal function used to implement lightweight + * sub-classes. + */ +void +gst_vaapi_parser_frame_free (GstVaapiParserFrame * frame) +{ + free_units (&frame->units); + free_units (&frame->pre_units); + free_units (&frame->post_units); +} + +/** + * gst_vaapi_parser_frame_append_unit: + * @frame: a #GstVaapiParserFrame + * @unit: a #GstVaapiDecoderUnit + * + * Appends unit to the @frame. + */ +void +gst_vaapi_parser_frame_append_unit (GstVaapiParserFrame * frame, + GstVaapiDecoderUnit * unit) +{ + GArray **unit_array_ptr; + + unit->offset = frame->output_offset; + frame->output_offset += unit->size; + + if (GST_VAAPI_DECODER_UNIT_IS_SLICE (unit)) + unit_array_ptr = &frame->units; + else if (GST_VAAPI_DECODER_UNIT_IS_FRAME_END (unit)) + unit_array_ptr = &frame->post_units; + else + unit_array_ptr = &frame->pre_units; + g_array_append_val (*unit_array_ptr, *unit); +} diff --git a/gst-libs/gst/vaapi/gstvaapiparser_frame.h b/gst-libs/gst/vaapi/gstvaapiparser_frame.h new file mode 100644 index 0000000000..5d20429aab --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiparser_frame.h @@ -0,0 +1,98 @@ +/* + * gstvaapiparser_frame.h - VA parser frame + * + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_PARSER_FRAME_H +#define GST_VAAPI_PARSER_FRAME_H + +#include +#include + +G_BEGIN_DECLS + +typedef struct _GstVaapiParserFrame GstVaapiParserFrame; + +#define GST_VAAPI_PARSER_FRAME(frame) \ + ((GstVaapiParserFrame *)(frame)) + +#define GST_VAAPI_IS_PARSER_FRAME(frame) \ + (GST_VAAPI_PARSER_FRAME(frame) != NULL) + +/** + * GstVaapiParserFrame: + * @output_offset: current offset to the reconstructed #GstBuffer for + * this #GstVideoCodecFrame. This is used to initialize the decoder + * unit offset + * @units: list of #GstVaapiDecoderUnit objects (slice data) + * @pre_units: list of units to decode before GstVaapiDecoder:start_frame() + * @post_units: list of units to decode after GstVaapiDecoder:end_frame() + * + * An extension to #GstVideoCodecFrame with #GstVaapiDecoder specific + * information. Decoder frames are usually attached to codec frames as + * the user_data anchor point. + */ +struct _GstVaapiParserFrame { + /*< private >*/ + GstVaapiMiniObject parent_instance; + + guint output_offset; + GArray *units; + GArray *pre_units; + GArray *post_units; +}; + +G_GNUC_INTERNAL +GstVaapiParserFrame * +gst_vaapi_parser_frame_new(guint width, guint height); + +G_GNUC_INTERNAL +void +gst_vaapi_parser_frame_free(GstVaapiParserFrame *frame); + +G_GNUC_INTERNAL +void +gst_vaapi_parser_frame_append_unit(GstVaapiParserFrame *frame, + GstVaapiDecoderUnit *unit); + +static inline GstVaapiParserFrame * +gst_vaapi_parser_frame_ref (GstVaapiParserFrame * frame) +{ + return (GstVaapiParserFrame *) + gst_vaapi_mini_object_ref (GST_VAAPI_MINI_OBJECT (frame)); +} + +static inline void +gst_vaapi_parser_frame_unref (GstVaapiParserFrame * frame) +{ + gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (frame)); +} + +static inline void +gst_vaapi_parser_frame_replace(GstVaapiParserFrame * old_frame_p, + GstVaapiParserFrame * new_frame) +{ + gst_vaapi_mini_object_replace ((GstVaapiMiniObject **) old_frame_p, + (GstVaapiMiniObject *) new_frame); +} + +G_END_DECLS + +#endif /* GST_VAAPI_PARSER_FRAME_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiprofile.c b/gst-libs/gst/vaapi/gstvaapiprofile.c new file mode 100644 index 0000000000..35d95c8927 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiprofile.c @@ -0,0 +1,630 @@ +/* + * gstvaapiprofile.c - VA profile abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapiprofile + * @short_description: VA profile abstraction + */ + +#include "sysdeps.h" +#include +#include "gstvaapicompat.h" +#include "gstvaapiprofile.h" +#include "gstvaapiutils.h" +#include "gstvaapiworkarounds.h" + +typedef struct _GstVaapiCodecMap GstVaapiCodecMap; +typedef struct _GstVaapiProfileMap GstVaapiProfileMap; +typedef struct _GstVaapiEntrypointMap GstVaapiEntrypointMap; + +struct _GstVaapiCodecMap +{ + GstVaapiCodec codec; + const gchar *name; +}; + +struct _GstVaapiProfileMap +{ + GstVaapiProfile profile; + VAProfile va_profile; + const char *media_str; + const gchar *profile_str; +}; + +struct _GstVaapiEntrypointMap +{ + GstVaapiEntrypoint entrypoint; + VAEntrypoint va_entrypoint; +}; + +/* Codecs */ +static const GstVaapiCodecMap gst_vaapi_codecs[] = { + {GST_VAAPI_CODEC_MPEG1, "mpeg1"}, + {GST_VAAPI_CODEC_MPEG2, "mpeg2"}, + {GST_VAAPI_CODEC_MPEG4, "mpeg4"}, + {GST_VAAPI_CODEC_H263, "h263"}, + {GST_VAAPI_CODEC_H264, "h264"}, + {GST_VAAPI_CODEC_WMV3, "wmv3"}, + {GST_VAAPI_CODEC_VC1, "vc1"}, + {GST_VAAPI_CODEC_JPEG, "jpeg"}, + {GST_VAAPI_CODEC_VP8, "vp8"}, + {GST_VAAPI_CODEC_H265, "h265"}, + {GST_VAAPI_CODEC_VP9, "vp9"}, + {GST_VAAPI_CODEC_AV1, "av1"}, + {0,} +}; + +/* Profiles */ +static const GstVaapiProfileMap gst_vaapi_profiles[] = { + {GST_VAAPI_PROFILE_MPEG2_SIMPLE, VAProfileMPEG2Simple, + "video/mpeg, mpegversion=2", "simple"}, + {GST_VAAPI_PROFILE_MPEG2_MAIN, VAProfileMPEG2Main, + "video/mpeg, mpegversion=2", "main"}, + {GST_VAAPI_PROFILE_MPEG4_SIMPLE, VAProfileMPEG4Simple, + "video/mpeg, mpegversion=4", "simple"}, + {GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE, VAProfileMPEG4AdvancedSimple, + "video/mpeg, mpegversion=4", "advanced-simple"}, + {GST_VAAPI_PROFILE_MPEG4_MAIN, VAProfileMPEG4Main, + "video/mpeg, mpegversion=4", "main"}, + {GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE, VAProfileMPEG4AdvancedSimple, + "video/x-divx, divxversion=5", "advanced-simple"}, + {GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE, VAProfileMPEG4AdvancedSimple, + "video/x-xvid", "advanced-simple"}, + {GST_VAAPI_PROFILE_H263_BASELINE, VAProfileH263Baseline, + "video/x-h263, variant=itu, h263version=h263", "baseline"}, +#if !VA_CHECK_VERSION(1,0,0) + {GST_VAAPI_PROFILE_H264_BASELINE, VAProfileH264Baseline, + "video/x-h264", "baseline"}, +#endif + {GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE, + VAProfileH264ConstrainedBaseline, + "video/x-h264", "constrained-baseline"}, + {GST_VAAPI_PROFILE_H264_MAIN, VAProfileH264Main, + "video/x-h264", "main"}, + {GST_VAAPI_PROFILE_H264_HIGH, VAProfileH264High, + "video/x-h264", "high"}, + {GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH, VAProfileH264MultiviewHigh, + "video/x-h264", "multiview-high"}, + {GST_VAAPI_PROFILE_H264_STEREO_HIGH, VAProfileH264StereoHigh, + "video/x-h264", "stereo-high"}, + {GST_VAAPI_PROFILE_VC1_SIMPLE, VAProfileVC1Simple, + "video/x-wmv, wmvversion=3", "simple"}, + {GST_VAAPI_PROFILE_VC1_MAIN, VAProfileVC1Main, + "video/x-wmv, wmvversion=3", "main"}, + {GST_VAAPI_PROFILE_VC1_ADVANCED, VAProfileVC1Advanced, + "video/x-wmv, wmvversion=3, format=(string)WVC1", "advanced"}, + {GST_VAAPI_PROFILE_JPEG_BASELINE, VAProfileJPEGBaseline, + "image/jpeg", NULL}, + {GST_VAAPI_PROFILE_VP8, VAProfileVP8Version0_3, + "video/x-vp8", NULL}, + {GST_VAAPI_PROFILE_H265_MAIN, VAProfileHEVCMain, + "video/x-h265", "main"}, + {GST_VAAPI_PROFILE_H265_MAIN10, VAProfileHEVCMain10, + "video/x-h265", "main-10"}, +#if VA_CHECK_VERSION(1,2,0) + {GST_VAAPI_PROFILE_H265_MAIN_422_10, VAProfileHEVCMain422_10, + "video/x-h265", "main-422-10"}, + {GST_VAAPI_PROFILE_H265_MAIN_444, VAProfileHEVCMain444, + "video/x-h265", "main-444"}, + {GST_VAAPI_PROFILE_H265_MAIN_444_10, VAProfileHEVCMain444_10, + "video/x-h265", "main-444-10"}, + {GST_VAAPI_PROFILE_H265_MAIN12, VAProfileHEVCMain12, + "video/x-h265", "main-12"}, + {GST_VAAPI_PROFILE_H265_MAIN_444_12, VAProfileHEVCMain444_12, + "video/x-h265", "main-444-12"}, + {GST_VAAPI_PROFILE_H265_MAIN_422_12, VAProfileHEVCMain422_12, + "video/x-h265", "main-422-12"}, + {GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN, VAProfileHEVCSccMain, + "video/x-h265", "screen-extended-main"}, + {GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_10, VAProfileHEVCSccMain10, + "video/x-h265", "screen-extended-main-10"}, + {GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444, VAProfileHEVCSccMain444, + "video/x-h265", "screen-extended-main-444"}, +#endif +#if VA_CHECK_VERSION(1,8,0) + {GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444_10, + VAProfileHEVCSccMain444_10, + "video/x-h265", "screen-extended-main-444-10"}, +#endif + {GST_VAAPI_PROFILE_VP9_0, VAProfileVP9Profile0, + "video/x-vp9", "0"}, + {GST_VAAPI_PROFILE_VP9_1, VAProfileVP9Profile1, + "video/x-vp9", "1"}, + {GST_VAAPI_PROFILE_VP9_2, VAProfileVP9Profile2, + "video/x-vp9", "2"}, + {GST_VAAPI_PROFILE_VP9_3, VAProfileVP9Profile3, + "video/x-vp9", "3"}, +#if VA_CHECK_VERSION(1,8,0) + {GST_VAAPI_PROFILE_AV1_0, VAProfileAV1Profile0, + "video/x-av1", "0"}, + {GST_VAAPI_PROFILE_AV1_1, VAProfileAV1Profile1, + "video/x-av1", "1"}, +#endif + {0,} +}; + +/* Entry-points */ +static const GstVaapiEntrypointMap gst_vaapi_entrypoints[] = { + {GST_VAAPI_ENTRYPOINT_VLD, VAEntrypointVLD}, + {GST_VAAPI_ENTRYPOINT_IDCT, VAEntrypointIDCT}, + {GST_VAAPI_ENTRYPOINT_MOCO, VAEntrypointMoComp}, + {GST_VAAPI_ENTRYPOINT_SLICE_ENCODE, VAEntrypointEncSlice}, + {GST_VAAPI_ENTRYPOINT_PICTURE_ENCODE, VAEntrypointEncPicture}, +#if VA_CHECK_VERSION(0,39,1) + {GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP, VAEntrypointEncSliceLP}, +#endif + {0,} +}; + +static const GstVaapiCodecMap * +get_codecs_map (GstVaapiCodec codec) +{ + const GstVaapiCodecMap *m; + + for (m = gst_vaapi_codecs; m->codec; m++) + if (m->codec == codec) + return m; + return NULL; +} + +static const GstVaapiProfileMap * +get_profiles_map (GstVaapiProfile profile) +{ + const GstVaapiProfileMap *m; + + for (m = gst_vaapi_profiles; m->profile; m++) + if (m->profile == profile) + return m; + return NULL; +} + +static const GstVaapiEntrypointMap * +get_entrypoints_map (GstVaapiEntrypoint entrypoint) +{ + const GstVaapiEntrypointMap *m; + + for (m = gst_vaapi_entrypoints; m->entrypoint; m++) + if (m->entrypoint == entrypoint) + return m; + return NULL; +} + +/** + * gst_vaapi_codec_get_name: + * @codec: a #GstVaapiCodec + * + * Returns a string representation for the supplied @codec type. + * + * Return value: the statically allocated string representation of @codec + */ +const gchar * +gst_vaapi_codec_get_name (GstVaapiCodec codec) +{ + const GstVaapiCodecMap *const m = get_codecs_map (codec); + + return m ? m->name : NULL; +} + +/** + * gst_vaapi_profile: + * @profile: a #VAProfile + * + * Converts a VA profile into the corresponding #GstVaapiProfile. If + * the profile cannot be represented by #GstVaapiProfile, then zero is + * returned. + * + * Return value: the #GstVaapiProfile describing the @profile + */ +GstVaapiProfile +gst_vaapi_profile (VAProfile profile) +{ + const GstVaapiProfileMap *m; + + for (m = gst_vaapi_profiles; m->profile; m++) + if (m->va_profile == profile) + return m->profile; + return 0; +} + +/** + * gst_vaapi_profile_get_name: + * @profile: a #GstVaapiProfile + * + * Returns a string representation for the supplied @profile. + * + * Return value: the statically allocated string representation of @profile + */ +const gchar * +gst_vaapi_profile_get_name (GstVaapiProfile profile) +{ + const GstVaapiProfileMap *const m = get_profiles_map (profile); + + return m ? m->profile_str : NULL; +} + +/** + * gst_vaapi_profile_get_va_name: + * @profile: a #GstVaapiProfile + * + * Returns a string representation for the supplied @profile as VAProfile. + * + * Return value: the statically allocated string representation of + * @profile as VAProfile + */ +const gchar * +gst_vaapi_profile_get_va_name (GstVaapiProfile profile) +{ + const GstVaapiProfileMap *const m = get_profiles_map (profile); + + return m ? string_of_VAProfile (m->va_profile) : NULL; +} + +/** + * gst_vaapi_profile_get_media_type_name: + * @profile: a #GstVaapiProfileo + * + * Returns a string representation for the media type of the supplied + * @profile. + * + * Return value: the statically allocated string representation of + * @profile media type + */ +const gchar * +gst_vaapi_profile_get_media_type_name (GstVaapiProfile profile) +{ + const GstVaapiProfileMap *const m = get_profiles_map (profile); + + return m ? m->media_str : NULL; +} + +/** + * gst_vaapi_profile_from_codec_data: + * @codec: a #GstVaapiCodec + * @buffer: a #GstBuffer holding code data + * + * Tries to parse VA profile from @buffer data and @codec information. + * + * Return value: the #GstVaapiProfile described in @buffer + */ +static GstVaapiProfile +gst_vaapi_profile_from_codec_data_h264 (GstBuffer * buffer) +{ + /* MPEG-4 Part 15: Advanced Video Coding (AVC) file format */ + guchar buf[3]; + + if (gst_buffer_extract (buffer, 0, buf, sizeof (buf)) != sizeof (buf)) + return 0; + + if (buf[0] != 1) /* configurationVersion = 1 */ + return 0; + + switch (buf[1]) { /* AVCProfileIndication */ + case 66: + return ((buf[2] & 0x40) ? + GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE : + GST_VAAPI_PROFILE_H264_BASELINE); + case 77: + return GST_VAAPI_PROFILE_H264_MAIN; + case 100: + return GST_VAAPI_PROFILE_H264_HIGH; + case 118: + return GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH; + case 128: + return GST_VAAPI_PROFILE_H264_STEREO_HIGH; + + } + return 0; +} + +static GstVaapiProfile +gst_vaapi_profile_from_codec_data_h265 (GstBuffer * buffer) +{ + /* ISO/IEC 14496-15: HEVC file format */ + guchar buf[3]; + + if (gst_buffer_extract (buffer, 0, buf, sizeof (buf)) != sizeof (buf)) + return 0; + + if (buf[0] != 1) /* configurationVersion = 1 */ + return 0; + + if (buf[1] & 0xc0) /* general_profile_space = 0 */ + return 0; + + /* We may not recognize the exactly correct profile, which needs more + info such as depth, chroma and constraint_flag. We just return the + first one that belongs to that profile IDC. */ + switch (buf[1] & 0x1f) { /* HEVCProfileIndication */ + case 1: + return GST_VAAPI_PROFILE_H265_MAIN; + case 2: + return GST_VAAPI_PROFILE_H265_MAIN10; + case 3: + return GST_VAAPI_PROFILE_H265_MAIN_STILL_PICTURE; + case 4: + return GST_VAAPI_PROFILE_H265_MAIN_422_10; + case 9: + return GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN; + } + return 0; +} + +static GstVaapiProfile +gst_vaapi_profile_from_codec_data (GstVaapiCodec codec, GstBuffer * buffer) +{ + GstVaapiProfile profile; + + if (!codec || !buffer) + return 0; + + switch (codec) { + case GST_VAAPI_CODEC_H264: + profile = gst_vaapi_profile_from_codec_data_h264 (buffer); + break; + case GST_VAAPI_CODEC_H265: + profile = gst_vaapi_profile_from_codec_data_h265 (buffer); + break; + default: + profile = 0; + break; + } + return profile; +} + +/** + * gst_vaapi_profile_from_caps: + * @caps: a #GstCaps + * + * Converts @caps into the corresponding #GstVaapiProfile. If the + * profile cannot be represented by #GstVaapiProfile, then zero is + * returned. + * + * Return value: the #GstVaapiProfile describing the @caps + */ +GstVaapiProfile +gst_vaapi_profile_from_caps (const GstCaps * caps) +{ + const GstVaapiProfileMap *m; + GstCaps *caps_test; + GstStructure *structure; + const gchar *profile_str; + GstVaapiProfile profile, best_profile; + GstBuffer *codec_data = NULL; + const gchar *name; + gsize namelen; + + if (!caps) + return 0; + + structure = gst_caps_get_structure (caps, 0); + if (!structure) + return 0; + + name = gst_structure_get_name (structure); + namelen = strlen (name); + + profile_str = gst_structure_get_string (structure, "profile"); + if (!profile_str) { + const GValue *v_codec_data; + v_codec_data = gst_structure_get_value (structure, "codec_data"); + if (v_codec_data) + codec_data = gst_value_get_buffer (v_codec_data); + } + + profile = 0; + best_profile = 0; + for (m = gst_vaapi_profiles; !profile && m->profile; m++) { + if (strncmp (name, m->media_str, namelen) != 0) + continue; + caps_test = gst_caps_from_string (m->media_str); + if (gst_caps_is_always_compatible (caps, caps_test)) { + best_profile = m->profile; + if (profile_str && m->profile_str && + strcmp (profile_str, m->profile_str) == 0) + profile = best_profile; + } + if (!profile) { + profile = + gst_vaapi_profile_from_codec_data (gst_vaapi_profile_get_codec + (m->profile), codec_data); + if (!profile && WORKAROUND_QTDEMUX_NO_H263_PROFILES + && strncmp (name, "video/x-h263", namelen) == 0) { + /* HACK: qtdemux does not report profiles for h263 */ + profile = m->profile; + } + + /* Consider HEVC -intra profiles. Just map them to their + * non-intra profiles */ + if (!profile && profile_str + && strncmp (name, "video/x-h265", namelen) == 0 + && g_str_has_prefix (profile_str, m->profile_str) + && strncmp (profile_str + strlen (m->profile_str), "-intra", 6) == 0) { + profile = m->profile; + } + } + gst_caps_unref (caps_test); + } + return profile ? profile : best_profile; +} + +/** + * gst_vaapi_get_codec_from_caps: + * @caps: a #GstCaps + * + * Converts @caps into the corresponding #GstVaapiCodec. If we can + * not recognize the #GstVaapiCodec, then zero is returned. + * + * Return value: the #GstVaapiCodec describing the @caps + */ +GstVaapiCodec +gst_vaapi_get_codec_from_caps (const GstCaps * caps) +{ + GstStructure *structure; + const gchar *name; + gsize namelen; + const GstVaapiProfileMap *m; + GstVaapiProfile profile; + + if (!caps) + return 0; + + structure = gst_caps_get_structure (caps, 0); + if (!structure) + return 0; + + name = gst_structure_get_name (structure); + namelen = strlen (name); + + profile = GST_VAAPI_PROFILE_UNKNOWN; + for (m = gst_vaapi_profiles; m->profile; m++) { + if (strncmp (name, m->media_str, namelen) == 0) { + profile = m->profile; + break; + } + } + + if (profile == GST_VAAPI_PROFILE_UNKNOWN) + return 0; + + return gst_vaapi_profile_get_codec (profile); +} + +/** + * gst_vaapi_profile_get_va_profile: + * @profile: a #GstVaapiProfile + * + * Converts a #GstVaapiProfile into the corresponding VA profile. If + * no matching VA profile was found, -1 is returned and this error + * must be reported to be fixed. + * + * Return value: the VA profile, or -1 if none was found + */ +VAProfile +gst_vaapi_profile_get_va_profile (GstVaapiProfile profile) +{ + const GstVaapiProfileMap *const m = get_profiles_map (profile); + + return m ? m->va_profile : (VAProfile) - 1; +} + +/** + * gst_vaapi_profile_get_caps: + * @profile: a #GstVaapiProfile + * + * Converts a #GstVaapiProfile into the corresponding #GstCaps. If no + * matching caps were found, %NULL is returned. + * + * Return value: the newly allocated #GstCaps, or %NULL if none was found + */ +GstCaps * +gst_vaapi_profile_get_caps (GstVaapiProfile profile) +{ + const GstVaapiProfileMap *m; + GstCaps *out_caps, *caps; + + out_caps = gst_caps_new_empty (); + if (!out_caps) + return NULL; + + for (m = gst_vaapi_profiles; m->profile; m++) { + if (m->profile != profile) + continue; + caps = gst_caps_from_string (m->media_str); + if (!caps) + continue; + gst_caps_set_simple (caps, "profile", G_TYPE_STRING, m->profile_str, NULL); + out_caps = gst_caps_merge (out_caps, caps); + } + return out_caps; +} + +/** + * gst_vaapi_profile_get_codec: + * @profile: a #GstVaapiProfile + * + * Extracts the #GstVaapiCodec from @profile. + * + * Return value: the #GstVaapiCodec from @profile + */ +GstVaapiCodec +gst_vaapi_profile_get_codec (GstVaapiProfile profile) +{ + GstVaapiCodec codec; + + switch (profile) { + case GST_VAAPI_PROFILE_VC1_SIMPLE: + case GST_VAAPI_PROFILE_VC1_MAIN: + codec = GST_VAAPI_CODEC_WMV3; + break; + case GST_VAAPI_PROFILE_VC1_ADVANCED: + codec = GST_VAAPI_CODEC_VC1; + break; + case GST_VAAPI_PROFILE_JPEG_BASELINE: + codec = GST_VAAPI_CODEC_JPEG; + break; + default: + codec = (guint32) profile & GST_MAKE_FOURCC (0xff, 0xff, 0xff, 0); + break; + } + return codec; +} + +/** + * gst_vaapi_entrypoint: + * @entrypoint: a #VAEntrypoint + * + * Converts a VA entry-point into the corresponding #GstVaapiEntrypoint. + * If the entry-point cannot be represented by #GstVaapiEntrypoint, + * then zero is returned. + * + * Return value: the #GstVaapiEntrypoint describing the @entrypoint + */ +GstVaapiEntrypoint +gst_vaapi_entrypoint (VAEntrypoint entrypoint) +{ + const GstVaapiEntrypointMap *m; + + for (m = gst_vaapi_entrypoints; m->entrypoint; m++) + if (m->va_entrypoint == entrypoint) + return m->entrypoint; + return 0; +} + +/** + * gst_vaapi_entrypoint_get_va_entrypoint: + * @entrypoint: a #GstVaapiEntrypoint + * + * Converts a #GstVaapiEntrypoint into the corresponding VA + * entry-point. If no matching VA entry-point was found, -1 is + * returned and this error must be reported to be fixed. + * + * Return value: the VA entry-point, or -1 if none was found + */ +VAEntrypoint +gst_vaapi_entrypoint_get_va_entrypoint (GstVaapiEntrypoint entrypoint) +{ + const GstVaapiEntrypointMap *const m = get_entrypoints_map (entrypoint); + + return m ? m->va_entrypoint : (VAEntrypoint) - 1; +} diff --git a/gst-libs/gst/vaapi/gstvaapiprofile.h b/gst-libs/gst/vaapi/gstvaapiprofile.h new file mode 100644 index 0000000000..8fc98c1c59 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiprofile.h @@ -0,0 +1,271 @@ +/* + * gstvaapiprofile.h - VA profile abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_PROFILE_H +#define GST_VAAPI_PROFILE_H + +#include +#include + +G_BEGIN_DECLS + +/** + * GstVaapiCodec: + * @GST_VAAPI_CODEC_MPEG1: MPEG-1 (ISO/IEC 11172) + * @GST_VAAPI_CODEC_MPEG2: MPEG-2 (ISO/IEC 13818-2) + * @GST_VAAPI_CODEC_MPEG4: MPEG-4 Part 2 (ISO/IEC 14496-2) + * @GST_VAAPI_CODEC_H263: H.263 + * @GST_VAAPI_CODEC_H264: H.264 aka MPEG-4 Part 10 (ISO/IEC 14496-10) + * @GST_VAAPI_CODEC_WMV3: Windows Media Video 9. VC-1 Simple or Main profile (SMPTE 421M) + * @GST_VAAPI_CODEC_VC1: VC-1 Advanced profile (SMPTE 421M) + * @GST_VAAPI_CODEC_JPEG: JPEG (ITU-T 81) + * @GST_VAAPI_CODEC_H265: H.265 aka MPEG-H Part 2 (ITU-T H.265) + * @GST_VAAPI_CODEC_VP9: VP9 (libvpx) + * @GST_VAAPI_CODEC_AV1: AV1 (aom) + * + * The set of all codecs for #GstVaapiCodec. + */ +typedef enum { + GST_VAAPI_CODEC_MPEG1 = GST_MAKE_FOURCC('M','P','1',0), + GST_VAAPI_CODEC_MPEG2 = GST_MAKE_FOURCC('M','P','2',0), + GST_VAAPI_CODEC_MPEG4 = GST_MAKE_FOURCC('M','P','4',0), + GST_VAAPI_CODEC_H263 = GST_MAKE_FOURCC('2','6','3',0), + GST_VAAPI_CODEC_H264 = GST_MAKE_FOURCC('2','6','4',0), + GST_VAAPI_CODEC_WMV3 = GST_MAKE_FOURCC('W','M','V',0), + GST_VAAPI_CODEC_VC1 = GST_MAKE_FOURCC('V','C','1',0), + GST_VAAPI_CODEC_JPEG = GST_MAKE_FOURCC('J','P','G',0), + GST_VAAPI_CODEC_VP8 = GST_MAKE_FOURCC('V','P','8',0), + GST_VAAPI_CODEC_H265 = GST_MAKE_FOURCC('2','6','5',0), + GST_VAAPI_CODEC_VP9 = GST_MAKE_FOURCC('V','P','9',0), + GST_VAAPI_CODEC_AV1 = GST_MAKE_FOURCC('A','V','1',0), +} GstVaapiCodec; + +/** + * GST_VAAPI_MAKE_PROFILE: + * @codec: the #GstVaapiCodec without the GST_VAAPI_CODEC_ prefix + * @sub_id: a non-zero sub-codec id + * + * Macro that evaluates to the profile composed from @codec and + * @sub_id. + */ +#define GST_VAAPI_MAKE_PROFILE(codec, sub_id) \ + (GST_VAAPI_CODEC_##codec | GST_MAKE_FOURCC(0,0,0,sub_id)) + +/** + * GstVaapiProfile: + * @GST_VAAPI_PROFILE_UNKNOWN: + * Unknown profile, used for initializers + * @GST_VAAPI_PROFILE_MPEG1: + * MPEG-1 + * @GST_VAAPI_PROFILE_MPEG2_SIMPLE: + * MPEG-2 simple profile + * @GST_VAAPI_PROFILE_MPEG2_MAIN: + * MPEG-2 main profile + * @GST_VAAPI_PROFILE_MPEG2_HIGH: + * MPEG-2 high profile + * @GST_VAAPI_PROFILE_MPEG4_SIMPLE: + * MPEG-4 Part-2 simple profile + * @GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE: + * MPEG-4 Part-2 advanced simple profile + * @GST_VAAPI_PROFILE_MPEG4_MAIN: + * MPEG-4 Part-2 main profile + * @GST_VAAPI_PROFILE_H263_BASELINE: + * H.263 baseline profile + * @GST_VAAPI_PROFILE_H264_BASELINE: + * H.264 (MPEG-4 Part-10) baseline profile [A.2.1] + * @GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE: + * H.264 (MPEG-4 Part-10) constrained baseline profile [A.2.1.1] + * @GST_VAAPI_PROFILE_H264_MAIN: + * H.264 (MPEG-4 Part-10) main profile [A.2.2] + * @GST_VAAPI_PROFILE_H264_EXTENDED: + * H.264 (MPEG-4 Part 10) extended profile [A.2.3] + * @GST_VAAPI_PROFILE_H264_HIGH: + * H.264 (MPEG-4 Part-10) high profile [A.2.4] + * @GST_VAAPI_PROFILE_H264_HIGH10: + * H.264 (MPEG-4 Part-10) high 10 profile [A.2.5], or high 10 intra + * profile [A.2.8], depending on constraint_set3_flag + * @GST_VAAPI_PROFILE_H264_HIGH_422: + * H.264 (MPEG-4 Part-10) high 4:2:2 profile [A.2.6], or high 4:2:2 + * intra profile [A.2.9], depending on constraint_set3_flag + * @GST_VAAPI_PROFILE_H264_HIGH_444: + * H.264 (MPEG-4 Part-10) high 4:4:4 predictive profile [A.2.7], or + * high 4:4:4 intra profile [A.2.10], depending on constraint_set3_flag + * @GST_VAAPI_PROFILE_H264_SCALABLE_BASELINE: + * H.264 (MPEG-4 Part-10) scalable baseline profile [G.10.1.1] + * @GST_VAAPI_PROFILE_H264_SCALABLE_HIGH: + * H.264 (MPEG-4 Part-10) scalable high profile [G.10.1.2], or scalable + * high intra profile [G.10.1.3], depending on constraint_set3_flag + * @GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH: + * H.264 (MPEG-4 Part-10) multiview high profile [H.10.1.1] + * @GST_VAAPI_PROFILE_H264_STEREO_HIGH: + * H.264 (MPEG-4 Part-10) stereo high profile [H.10.1.2] + * @GST_VAAPI_PROFILE_VC1_SIMPLE: + * VC-1 simple profile + * @GST_VAAPI_PROFILE_VC1_MAIN: + * VC-1 main profile + * @GST_VAAPI_PROFILE_VC1_ADVANCED: + * VC-1 advanced profile + * @GST_VAAPI_PROFILE_JPEG_BASELINE: + * JPEG baseline profile + * @GST_VAAPI_PROFILE_H265_MAIN: + * H.265 main profile [A.3.2] + * @GST_VAAPI_PROFILE_H265_MAIN10: + * H.265 main 10 profile [A.3.3] + * @GST_VAAPI_PROFILE_H265_MAIN_STILL_PICTURE: + * H.265 main still picture profile [A.3.4] + * @GST_VAAPI_PROFILE_H265_MAIN_422_10: + * H.265 main still picture profile [A.3.5] + * @GST_VAAPI_PROFILE_VP9_0: + * VP9 prfile 0, bitdepth=8, 420 + * @GST_VAAPI_PROFILE_VP9_1: + * VP9 prfile 1, bitdepth=8, 422/444/440/RGB + * @GST_VAAPI_PROFILE_VP9_2: + * VP9 prfile 2, bitdepth=10/12, 420 + * @GST_VAAPI_PROFILE_VP9_3: + * VP9 prfile 3 bitdepth=10/12, 422/444/440/RGB + * @GST_VAAPI_PROFILE_AV1_0: + * AV1 prfile 0, bitdepth=8/10, 420/400 + * @GST_VAAPI_PROFILE_AV1_1: + * AV1 prfile 1 bitdepth=8/10, 444 + * + * The set of all profiles for #GstVaapiProfile. + */ +typedef enum { + GST_VAAPI_PROFILE_UNKNOWN = 0, + GST_VAAPI_PROFILE_MPEG1 = GST_VAAPI_MAKE_PROFILE(MPEG1,1), + GST_VAAPI_PROFILE_MPEG2_SIMPLE = GST_VAAPI_MAKE_PROFILE(MPEG2,1), + GST_VAAPI_PROFILE_MPEG2_MAIN = GST_VAAPI_MAKE_PROFILE(MPEG2,2), + GST_VAAPI_PROFILE_MPEG2_HIGH = GST_VAAPI_MAKE_PROFILE(MPEG2,3), + GST_VAAPI_PROFILE_MPEG4_SIMPLE = GST_VAAPI_MAKE_PROFILE(MPEG4,1), + GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE = GST_VAAPI_MAKE_PROFILE(MPEG4,2), + GST_VAAPI_PROFILE_MPEG4_MAIN = GST_VAAPI_MAKE_PROFILE(MPEG4,3), + GST_VAAPI_PROFILE_H263_BASELINE = GST_VAAPI_MAKE_PROFILE(H263,1), + GST_VAAPI_PROFILE_H264_BASELINE = GST_VAAPI_MAKE_PROFILE(H264,1), + GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE = + GST_VAAPI_MAKE_PROFILE(H264,9), + GST_VAAPI_PROFILE_H264_MAIN = GST_VAAPI_MAKE_PROFILE(H264,2), + GST_VAAPI_PROFILE_H264_EXTENDED = GST_VAAPI_MAKE_PROFILE(H264,10), + GST_VAAPI_PROFILE_H264_HIGH = GST_VAAPI_MAKE_PROFILE(H264,3), + GST_VAAPI_PROFILE_H264_HIGH10 = GST_VAAPI_MAKE_PROFILE(H264,7), + GST_VAAPI_PROFILE_H264_HIGH_422 = GST_VAAPI_MAKE_PROFILE(H264,4), + GST_VAAPI_PROFILE_H264_HIGH_444 = GST_VAAPI_MAKE_PROFILE(H264,8), + GST_VAAPI_PROFILE_H264_SCALABLE_BASELINE = + GST_VAAPI_MAKE_PROFILE(H264,5), + GST_VAAPI_PROFILE_H264_SCALABLE_HIGH = GST_VAAPI_MAKE_PROFILE(H264,6), + GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH = GST_VAAPI_MAKE_PROFILE(H264,11), + GST_VAAPI_PROFILE_H264_STEREO_HIGH = GST_VAAPI_MAKE_PROFILE(H264,15), + GST_VAAPI_PROFILE_VC1_SIMPLE = GST_VAAPI_MAKE_PROFILE(VC1,1), + GST_VAAPI_PROFILE_VC1_MAIN = GST_VAAPI_MAKE_PROFILE(VC1,2), + GST_VAAPI_PROFILE_VC1_ADVANCED = GST_VAAPI_MAKE_PROFILE(VC1,3), + GST_VAAPI_PROFILE_JPEG_BASELINE = GST_VAAPI_MAKE_PROFILE(JPEG,1), + GST_VAAPI_PROFILE_VP8 = GST_VAAPI_MAKE_PROFILE(VP8,1), + GST_VAAPI_PROFILE_H265_MAIN = GST_VAAPI_MAKE_PROFILE(H265,1), + GST_VAAPI_PROFILE_H265_MAIN10 = GST_VAAPI_MAKE_PROFILE(H265,2), + GST_VAAPI_PROFILE_H265_MAIN_STILL_PICTURE = + GST_VAAPI_MAKE_PROFILE(H265,3), + GST_VAAPI_PROFILE_H265_MAIN_422_10 = GST_VAAPI_MAKE_PROFILE(H265,4), + GST_VAAPI_PROFILE_H265_MAIN_444 = GST_VAAPI_MAKE_PROFILE(H265,5), + GST_VAAPI_PROFILE_H265_MAIN_444_10 = GST_VAAPI_MAKE_PROFILE(H265,6), + GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN = + GST_VAAPI_MAKE_PROFILE(H265,7), + GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_10 = + GST_VAAPI_MAKE_PROFILE(H265,8), + GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444 = + GST_VAAPI_MAKE_PROFILE(H265,9), + GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444_10 = + GST_VAAPI_MAKE_PROFILE(H265,10), + GST_VAAPI_PROFILE_H265_MAIN12 = GST_VAAPI_MAKE_PROFILE(H265,11), + GST_VAAPI_PROFILE_H265_MAIN_444_12 = GST_VAAPI_MAKE_PROFILE(H265,12), + GST_VAAPI_PROFILE_H265_MAIN_422_12 = GST_VAAPI_MAKE_PROFILE(H265,13), + GST_VAAPI_PROFILE_VP9_0 = GST_VAAPI_MAKE_PROFILE(VP9,1), + GST_VAAPI_PROFILE_VP9_1 = GST_VAAPI_MAKE_PROFILE(VP9,2), + GST_VAAPI_PROFILE_VP9_2 = GST_VAAPI_MAKE_PROFILE(VP9,3), + GST_VAAPI_PROFILE_VP9_3 = GST_VAAPI_MAKE_PROFILE(VP9,4), + + GST_VAAPI_PROFILE_AV1_0 = GST_VAAPI_MAKE_PROFILE(AV1,1), + GST_VAAPI_PROFILE_AV1_1 = GST_VAAPI_MAKE_PROFILE(AV1,2), +} GstVaapiProfile; + +/** + * GstVaapiEntrypoint: + * @GST_VAAPI_ENTRYPOINT_INVALID: Invalid entrypoint + * @GST_VAAPI_ENTRYPOINT_VLD: Variable Length Decoding + * @GST_VAAPI_ENTRYPOINT_IDCT: Inverse Decrete Cosine Transform + * @GST_VAAPI_ENTRYPOINT_MOCO: Motion Compensation + * @GST_VAAPI_ENTRYPOINT_SLICE_ENCODE: Encode Slice + * @GST_VAAPI_ENTRYPOINT_PICTURE_ENCODE: Encode Picture + * @GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP: Encode Slice low power/ + * high performace varient + * + * The set of all entrypoints for #GstVaapiEntrypoint + */ +typedef enum { + GST_VAAPI_ENTRYPOINT_INVALID, + GST_VAAPI_ENTRYPOINT_VLD, + GST_VAAPI_ENTRYPOINT_IDCT, + GST_VAAPI_ENTRYPOINT_MOCO, + GST_VAAPI_ENTRYPOINT_SLICE_ENCODE, + GST_VAAPI_ENTRYPOINT_PICTURE_ENCODE, + GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP, +} GstVaapiEntrypoint; + +const gchar * +gst_vaapi_codec_get_name(GstVaapiCodec codec); + +GstVaapiProfile +gst_vaapi_profile(VAProfile profile); + +GstVaapiProfile +gst_vaapi_profile_from_caps(const GstCaps *caps); + +GstVaapiCodec +gst_vaapi_get_codec_from_caps (const GstCaps *caps); + +const gchar * +gst_vaapi_profile_get_name(GstVaapiProfile profile); + +const gchar * +gst_vaapi_profile_get_va_name(GstVaapiProfile profile); + +const gchar * +gst_vaapi_profile_get_media_type_name(GstVaapiProfile profile); + +VAProfile +gst_vaapi_profile_get_va_profile(GstVaapiProfile profile); + +GstCaps * +gst_vaapi_profile_get_caps(GstVaapiProfile profile); + +GstVaapiCodec +gst_vaapi_profile_get_codec(GstVaapiProfile profile); + +GstVaapiEntrypoint +gst_vaapi_entrypoint(VAEntrypoint entrypoint); + +VAEntrypoint +gst_vaapi_entrypoint_get_va_entrypoint(GstVaapiEntrypoint entrypoint); + +G_END_DECLS + +#endif /* GST_GST_VAAPI_IMAGE_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiprofilecaps.c b/gst-libs/gst/vaapi/gstvaapiprofilecaps.c new file mode 100644 index 0000000000..0e44393513 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiprofilecaps.c @@ -0,0 +1,135 @@ +/* + * gstvaapiprofilecaps.h - VA config attributes as gstreamer capabilities + * + * Copyright (C) 2019 Igalia, S.L. + * Author: Víctor Jáquez + * + * 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:gstvaapiprofilecaps + * @short_description: VA config attributes as gstreamer capabilities + */ + +#include "sysdeps.h" +#include "gstvaapicompat.h" +#include "gstvaapicontext.h" +#include "gstvaapiprofilecaps.h" +#include "gstvaapiutils.h" + +static gboolean +init_context_info (GstVaapiDisplay * display, GstVaapiContextInfo * cip) +{ + guint value = 0; + + /* XXX: Only try a context from he first RTFormat in config. */ + if (!gst_vaapi_get_config_attribute (display, + gst_vaapi_profile_get_va_profile (cip->profile), + gst_vaapi_entrypoint_get_va_entrypoint (cip->entrypoint), + VAConfigAttribRTFormat, &value)) { + return FALSE; + } + + cip->chroma_type = to_GstVaapiChromaType (value); + return cip->chroma_type != 0; +} + +static GstVaapiContext * +create_context (GstVaapiDisplay * display, GstVaapiContextInfo * cip) +{ + if (!init_context_info (display, cip)) + return NULL; + return gst_vaapi_context_new (display, cip); +} + +static gboolean +append_caps (GstVaapiContext * context, GstStructure * structure) +{ + GstVaapiConfigSurfaceAttributes attribs = { 0, }; + + if (!gst_vaapi_context_get_surface_attributes (context, &attribs)) + return FALSE; + + if (attribs.min_width >= attribs.max_width || + attribs.min_height >= attribs.max_height) + return FALSE; + + gst_structure_set (structure, "width", GST_TYPE_INT_RANGE, attribs.min_width, + attribs.max_width, "height", GST_TYPE_INT_RANGE, attribs.min_height, + attribs.max_height, NULL); + + return TRUE; +} + +static gboolean +append_caps_with_context_info (GstVaapiDisplay * display, + GstVaapiContextInfo * cip, GstStructure * structure) +{ + GstVaapiContext *context; + gboolean ret; + + context = create_context (display, cip); + if (!context) + return FALSE; + + ret = append_caps (context, structure); + gst_vaapi_context_unref (context); + return ret; +} + +/** + * gst_vaapi_decoder_add_profile_caps: + * @display: a #GstVaapiDisplay + * @profile: a #GstVaapiProfile + * @structure: a #GstStructure + * + * Extracts the config's surface attributes, from @profile, in a + * decoder context, and transforms it into a caps formats and appended + * into @structure. + * + * Returns: %TRUE if the capabilities could be extracted and appended + * into @structure; otherwise %FALSE + **/ +gboolean +gst_vaapi_profile_caps_append_decoder (GstVaapiDisplay * display, + GstVaapiProfile profile, GstStructure * structure) +{ + GstVaapiContextInfo cip = { + GST_VAAPI_CONTEXT_USAGE_DECODE, profile, GST_VAAPI_ENTRYPOINT_VLD, 0, + }; + + g_return_val_if_fail (display != NULL, FALSE); + g_return_val_if_fail (structure != NULL, FALSE); + + return append_caps_with_context_info (display, &cip, structure); +} + +/** + * gst_vaapi_mem_type_supports: + * @va_mem_types: memory types from VA surface attributes + * @mem_type: the #GstVaapiBufferMemoryType to test + * + * Test if @va_mem_types handles @mem_type + * + * Returns: %TRUE if @mem_type is supported in @va_mem_types; + * otherwise %FALSE + **/ +gboolean +gst_vaapi_mem_type_supports (guint va_mem_types, guint mem_type) +{ + return ((va_mem_types & from_GstVaapiBufferMemoryType (mem_type)) != 0); +} diff --git a/gst-libs/gst/vaapi/gstvaapiprofilecaps.h b/gst-libs/gst/vaapi/gstvaapiprofilecaps.h new file mode 100644 index 0000000000..a33ebc92b7 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiprofilecaps.h @@ -0,0 +1,41 @@ +/* + * gstvaapiprofilecaps.h - VA config attributes as gstreamer capabilities + * + * Copyright (C) 2019 Igalia, S.L. + * Author: Víctor Jáquez + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_PROFILE_CAPS_H +#define GST_VAAPI_PROFILE_CAPS_H + +#include +#include +#include + +G_BEGIN_DECLS + +gboolean +gst_vaapi_profile_caps_append_decoder (GstVaapiDisplay * display, + GstVaapiProfile profile, GstStructure * structure); + +gboolean +gst_vaapi_mem_type_supports (guint va_mem_types, guint mem_type); + +G_END_DECLS + +#endif /* GST_VAAPI_PROFILE_CAPS_H */ diff --git a/gst-libs/gst/vaapi/gstvaapisubpicture.c b/gst-libs/gst/vaapi/gstvaapisubpicture.c new file mode 100644 index 0000000000..c2ba257b1e --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapisubpicture.c @@ -0,0 +1,376 @@ +/* + * gstvaapisubpicture.c - VA subpicture abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapisubpicture + * @short_description: VA subpicture abstraction + */ + +#include "sysdeps.h" +#include "gstvaapicompat.h" +#include "gstvaapiutils.h" +#include "gstvaapisubpicture.h" +#include "gstvaapiimage_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +/** + * GstVaapiSubpicture: + * + * A VA subpicture wrapper + */ +struct _GstVaapiSubpicture +{ + /*< private > */ + GstMiniObject mini_object; + GstVaapiDisplay *display; + GstVaapiID object_id; + + GstVaapiImage *image; + guint flags; + gfloat global_alpha; +}; + +static void +gst_vaapi_subpicture_free_image (GstVaapiSubpicture * subpicture) +{ + GstVaapiDisplay *const display = subpicture->display; + VASubpictureID subpicture_id; + VAStatus status; + + subpicture_id = subpicture->object_id; + GST_DEBUG ("subpicture %" GST_VAAPI_ID_FORMAT, + GST_VAAPI_ID_ARGS (subpicture_id)); + + if (subpicture_id != VA_INVALID_ID) { + GST_VAAPI_DISPLAY_LOCK (display); + status = vaDestroySubpicture (GST_VAAPI_DISPLAY_VADISPLAY (display), + subpicture_id); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!vaapi_check_status (status, "vaDestroySubpicture()")) + GST_WARNING ("failed to destroy subpicture %" GST_VAAPI_ID_FORMAT, + GST_VAAPI_ID_ARGS (subpicture_id)); + subpicture->object_id = VA_INVALID_ID; + } + + if (subpicture->image) + gst_mini_object_replace ((GstMiniObject **) & subpicture->image, NULL); +} + +static void +gst_vaapi_subpicture_free (GstVaapiSubpicture * subpicture) +{ + gst_vaapi_subpicture_free_image (subpicture); + gst_vaapi_display_replace (&subpicture->display, NULL); + g_slice_free1 (sizeof (GstVaapiSubpicture), subpicture); +} + +GST_DEFINE_MINI_OBJECT_TYPE (GstVaapiSubpicture, gst_vaapi_subpicture); + +static gboolean +gst_vaapi_subpicture_bind_image (GstVaapiSubpicture * subpicture, + GstVaapiImage * image) +{ + GstVaapiDisplay *const display = subpicture->display; + VASubpictureID subpicture_id; + VAStatus status; + + GST_VAAPI_DISPLAY_LOCK (display); + status = vaCreateSubpicture (GST_VAAPI_DISPLAY_VADISPLAY (display), + GST_VAAPI_IMAGE_ID (image), &subpicture_id); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!vaapi_check_status (status, "vaCreateSubpicture()")) + return FALSE; + + GST_DEBUG ("subpicture %" GST_VAAPI_ID_FORMAT, + GST_VAAPI_ID_ARGS (subpicture_id)); + subpicture->object_id = subpicture_id; + subpicture->image = + (GstVaapiImage *) gst_mini_object_ref (GST_MINI_OBJECT_CAST (image)); + return TRUE; +} + +/** + * gst_vaapi_subpicture_new: + * @image: a #GstVaapiImage + * @flags: #GstVaapiSubpictureFlags, or zero + * + * Creates a new #GstVaapiSubpicture with @image as source pixels. The + * newly created object holds a reference on @image. + * + * Return value: the newly allocated #GstVaapiSubpicture object + */ +GstVaapiSubpicture * +gst_vaapi_subpicture_new (GstVaapiImage * image, guint flags) +{ + GstVaapiSubpicture *subpicture; + GstVaapiDisplay *display; + GstVideoFormat format; + guint va_flags; + + g_return_val_if_fail (image != NULL, NULL); + + GST_DEBUG ("create from image %" GST_VAAPI_ID_FORMAT, + GST_VAAPI_ID_ARGS (GST_VAAPI_IMAGE_ID (image))); + + display = GST_VAAPI_IMAGE_DISPLAY (image); + format = GST_VAAPI_IMAGE_FORMAT (image); + if (!gst_vaapi_display_has_subpicture_format (display, format, &va_flags)) + return NULL; + if (flags & ~va_flags) + return NULL; + + subpicture = g_slice_new (GstVaapiSubpicture); + if (!subpicture) + return NULL; + + gst_mini_object_init (GST_MINI_OBJECT_CAST (subpicture), 0, + GST_TYPE_VAAPI_SUBPICTURE, NULL, NULL, + (GstMiniObjectFreeFunction) gst_vaapi_subpicture_free); + subpicture->display = gst_object_ref (display); + subpicture->object_id = VA_INVALID_ID; + subpicture->flags = flags; + subpicture->global_alpha = 1.0f; + + if (!gst_vaapi_subpicture_bind_image (subpicture, image)) + goto error; + return subpicture; + + /* ERRORS */ +error: + { + gst_vaapi_subpicture_unref (subpicture); + return NULL; + } +} + +/** + * gst_vaapi_subpicture_new_from_overlay_rectangle: + * @display: a #GstVaapiDisplay + * @rect: a #GstVideoOverlayRectangle + * + * Helper function that creates a new #GstVaapiSubpicture from a + * #GstVideoOverlayRectangle. A new #GstVaapiImage is also created + * along the way and attached to the resulting subpicture. The + * subpicture holds a unique reference to the underlying image. + * + * Return value: the newly allocated #GstVaapiSubpicture object + */ +GstVaapiSubpicture * +gst_vaapi_subpicture_new_from_overlay_rectangle (GstVaapiDisplay * display, + GstVideoOverlayRectangle * rect) +{ + GstVaapiSubpicture *subpicture; + GstVideoFormat format; + GstVaapiImage *image; + GstVaapiImageRaw raw_image; + GstBuffer *buffer; + guint8 *data; + gfloat global_alpha; + guint width, height, stride; + guint hw_flags, flags; + GstVideoMeta *vmeta; + GstMapInfo map_info; + + g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rect), NULL); + + format = GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_RGB; + + if (!gst_vaapi_display_has_subpicture_format (display, format, &hw_flags)) + return NULL; + + flags = + hw_flags & + from_GstVideoOverlayFormatFlags (gst_video_overlay_rectangle_get_flags + (rect)); + + buffer = gst_video_overlay_rectangle_get_pixels_unscaled_argb (rect, + to_GstVideoOverlayFormatFlags (flags)); + if (!buffer) + return NULL; + + vmeta = gst_buffer_get_video_meta (buffer); + if (!vmeta) + return NULL; + width = vmeta->width; + height = vmeta->height; + + if (!gst_video_meta_map (vmeta, 0, &map_info, (gpointer *) & data, + (gint *) & stride, GST_MAP_READ)) + return NULL; + + image = gst_vaapi_image_new (display, format, width, height); + if (!image) + return NULL; + + raw_image.format = format; + raw_image.width = width; + raw_image.height = height; + raw_image.num_planes = 1; + raw_image.pixels[0] = data; + raw_image.stride[0] = stride; + if (!gst_vaapi_image_update_from_raw (image, &raw_image, NULL)) { + GST_WARNING ("could not update VA image with subtitle data"); + gst_vaapi_image_unref (image); + return NULL; + } + + subpicture = gst_vaapi_subpicture_new (image, flags); + gst_vaapi_image_unref (image); + gst_video_meta_unmap (vmeta, 0, &map_info); + if (!subpicture) + return NULL; + + if (flags & GST_VAAPI_SUBPICTURE_FLAG_GLOBAL_ALPHA) { + global_alpha = gst_video_overlay_rectangle_get_global_alpha (rect); + if (!gst_vaapi_subpicture_set_global_alpha (subpicture, global_alpha)) + return NULL; + } + return subpicture; +} + +/** + * gst_vaapi_subpicture_get_id: + * @subpicture: a #GstVaapiSubpicture + * + * Returns the underlying VASubpictureID of the @subpicture. + * + * Return value: the underlying VA subpicture id + */ +GstVaapiID +gst_vaapi_subpicture_get_id (GstVaapiSubpicture * subpicture) +{ + g_return_val_if_fail (subpicture != NULL, VA_INVALID_ID); + + return subpicture->object_id; +} + +/** + * gst_vaapi_subpicture_get_flags: + * @subpicture: a #GstVaapiSubpicture + * + * Returns the @subpicture flags. + * + * Return value: the @subpicture flags + */ +guint +gst_vaapi_subpicture_get_flags (GstVaapiSubpicture * subpicture) +{ + g_return_val_if_fail (subpicture != NULL, 0); + + return subpicture->flags; +} + +/** + * gst_vaapi_subpicture_get_image: + * @subpicture: a #GstVaapiSubpicture + * + * Returns the #GstVaapiImage this @subpicture is bound to. + * + * Return value: the #GstVaapiImage this @subpicture is bound to + */ +GstVaapiImage * +gst_vaapi_subpicture_get_image (GstVaapiSubpicture * subpicture) +{ + g_return_val_if_fail (subpicture != NULL, NULL); + + return subpicture->image; +} + +/** + * gst_vaapi_subpicture_set_image: + * @subpicture: a #GstVaapiSubpicture + * @image: a #GstVaapiImage + * + * Binds a new #GstVaapiImage to the @subpicture. The reference to the + * previous image is released and a new one is acquired on @image. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_subpicture_set_image (GstVaapiSubpicture * subpicture, + GstVaapiImage * image) +{ + g_return_val_if_fail (subpicture != NULL, FALSE); + g_return_val_if_fail (image != NULL, FALSE); + + gst_vaapi_subpicture_free_image (subpicture); + return gst_vaapi_subpicture_bind_image (subpicture, image); +} + +/** + * gst_vaapi_subpicture_get_global_alpha: + * @subpicture: a #GstVaapiSubpicture + * + * Returns the value of global_alpha, set for this @subpicture. + * + * Return value: the global_alpha value of this @subpicture + */ +gfloat +gst_vaapi_subpicture_get_global_alpha (GstVaapiSubpicture * subpicture) +{ + g_return_val_if_fail (subpicture != NULL, 1.0); + + return subpicture->global_alpha; +} + +/** + * gst_vaapi_subpicture_set_global_alpha: + * @subpicture: a #GstVaapiSubpicture + * @global_alpha: value for global-alpha (range: 0.0 to 1.0, inclusive) + * + * Sets the global_alpha value of @subpicture. This function calls + * vaSetSubpictureGlobalAlpha() if the format of @subpicture, i.e. + * the current VA driver supports it. + * + * Return value: %TRUE if global_alpha could be set, %FALSE otherwise + */ +gboolean +gst_vaapi_subpicture_set_global_alpha (GstVaapiSubpicture * subpicture, + gfloat global_alpha) +{ + GstVaapiDisplay *display; + VAStatus status; + + g_return_val_if_fail (subpicture != NULL, FALSE); + + if (!(subpicture->flags & GST_VAAPI_SUBPICTURE_FLAG_GLOBAL_ALPHA)) + return FALSE; + + if (subpicture->global_alpha == global_alpha) + return TRUE; + + display = subpicture->display; + + GST_VAAPI_DISPLAY_LOCK (display); + status = vaSetSubpictureGlobalAlpha (GST_VAAPI_DISPLAY_VADISPLAY (display), + subpicture->object_id, global_alpha); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!vaapi_check_status (status, "vaSetSubpictureGlobalAlpha()")) + return FALSE; + + subpicture->global_alpha = global_alpha; + return TRUE; +} diff --git a/gst-libs/gst/vaapi/gstvaapisubpicture.h b/gst-libs/gst/vaapi/gstvaapisubpicture.h new file mode 100644 index 0000000000..d61314d586 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapisubpicture.h @@ -0,0 +1,107 @@ +/* + * gstvaapisubpicture.h - VA subpicture abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_SUBPICTURE_H +#define GST_VAAPI_SUBPICTURE_H + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_SUBPICTURE(obj) \ + ((GstVaapiSubpicture *)(obj)) + +typedef struct _GstVaapiSubpicture GstVaapiSubpicture; + +/** + * GstVaapiSubpictureFlags: + * @GST_VAAPI_SUBPICTURE_FLAG_PREMULTIPLIED_ALPHA: + * subpicture has RGB pixels with pre-multiplied alpha + * @GST_VAAPI_SUBPICTURE_FLAG_GLOBAL_ALPHA: + * subpicture needs to be blended with some global-alpha value at + * rendering time + * + * The set of all subpicture rendering flags for #GstVaapiSubpicture. + */ +typedef enum { + GST_VAAPI_SUBPICTURE_FLAG_PREMULTIPLIED_ALPHA = (1 << 0), + GST_VAAPI_SUBPICTURE_FLAG_GLOBAL_ALPHA = (1 << 1), +} GstVaapiSubpictureFlags; + +#define GST_TYPE_VAAPI_SUBPICTURE (gst_vaapi_subpicture_get_type ()) + +#define GST_VAAPI_SUBPICTURE_ID(subpicture) (gst_vaapi_subpicture_get_id (subpicture)) + +GType +gst_vaapi_subpicture_get_type (void) G_GNUC_CONST; + +/** + * gst_vaapi_subpicture_unref: (skip) + * @subpicture: (transfer full): a #GstVaapiSubpicture. + * + * Decreases the refcount of the subpicture. If the refcount reaches 0, the + * subpicture will be freed. + */ +static inline void +gst_vaapi_subpicture_unref (GstVaapiSubpicture *subpicture) +{ + gst_mini_object_unref (GST_MINI_OBJECT_CAST (subpicture)); +} + +GstVaapiSubpicture * +gst_vaapi_subpicture_new(GstVaapiImage *image, guint flags); + +GstVaapiSubpicture * +gst_vaapi_subpicture_new_from_overlay_rectangle( + GstVaapiDisplay *display, + GstVideoOverlayRectangle *rect +); + +GstVaapiID +gst_vaapi_subpicture_get_id(GstVaapiSubpicture *subpicture); + +guint +gst_vaapi_subpicture_get_flags(GstVaapiSubpicture *subpicture); + +GstVaapiImage * +gst_vaapi_subpicture_get_image(GstVaapiSubpicture *subpicture); + +gboolean +gst_vaapi_subpicture_set_image(GstVaapiSubpicture *subpicture, + GstVaapiImage *image); + +gfloat +gst_vaapi_subpicture_get_global_alpha(GstVaapiSubpicture *subpicture); + +gboolean +gst_vaapi_subpicture_set_global_alpha(GstVaapiSubpicture *subpicture, + gfloat global_alpha); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiSubpicture, gst_vaapi_subpicture_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_SUBPICTURE_H */ diff --git a/gst-libs/gst/vaapi/gstvaapisurface.c b/gst-libs/gst/vaapi/gstvaapisurface.c new file mode 100644 index 0000000000..0fdafd99f4 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapisurface.c @@ -0,0 +1,1094 @@ +/* + * gstvaapisurface.c - VA surface abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapisurface + * @short_description: VA surface abstraction + */ + +#include "sysdeps.h" +#include "gstvaapicompat.h" +#include "gstvaapiutils.h" +#include "gstvaapisurface.h" +#include "gstvaapisurface_priv.h" +#include "gstvaapicontext.h" +#include "gstvaapiimage.h" +#include "gstvaapiimage_priv.h" +#include "gstvaapibufferproxy_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +static gboolean +_gst_vaapi_surface_associate_subpicture (GstVaapiSurface * surface, + GstVaapiSubpicture * subpicture, const GstVaapiRectangle * src_rect, + const GstVaapiRectangle * dst_rect); + +static gboolean +_gst_vaapi_surface_deassociate_subpicture (GstVaapiSurface * surface, + GstVaapiSubpicture * subpicture); + +static void +destroy_subpicture_cb (gpointer subpicture, gpointer surface) +{ + _gst_vaapi_surface_deassociate_subpicture (surface, subpicture); + gst_vaapi_subpicture_unref (subpicture); +} + +static void +gst_vaapi_surface_destroy_subpictures (GstVaapiSurface * surface) +{ + if (surface->subpictures) { + g_ptr_array_foreach (surface->subpictures, destroy_subpicture_cb, surface); + g_clear_pointer (&surface->subpictures, g_ptr_array_unref); + } +} + +static void +gst_vaapi_surface_free (GstVaapiSurface * surface) +{ + GstVaapiDisplay *const display = GST_VAAPI_SURFACE_DISPLAY (surface); + VASurfaceID surface_id; + VAStatus status; + + surface_id = GST_VAAPI_SURFACE_ID (surface); + GST_DEBUG ("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (surface_id)); + + gst_vaapi_surface_destroy_subpictures (surface); + + if (surface_id != VA_INVALID_SURFACE) { + GST_VAAPI_DISPLAY_LOCK (display); + status = vaDestroySurfaces (GST_VAAPI_DISPLAY_VADISPLAY (display), + &surface_id, 1); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!vaapi_check_status (status, "vaDestroySurfaces()")) + GST_WARNING ("failed to destroy surface %" GST_VAAPI_ID_FORMAT, + GST_VAAPI_ID_ARGS (surface_id)); + GST_VAAPI_SURFACE_ID (surface) = VA_INVALID_SURFACE; + } + gst_vaapi_buffer_proxy_replace (&surface->extbuf_proxy, NULL); + gst_vaapi_display_replace (&GST_VAAPI_SURFACE_DISPLAY (surface), NULL); + + g_slice_free1 (sizeof (GstVaapiSurface), surface); +} + +static gboolean +gst_vaapi_surface_init (GstVaapiSurface * surface, + GstVaapiChromaType chroma_type, guint width, guint height) +{ + GstVaapiDisplay *const display = GST_VAAPI_SURFACE_DISPLAY (surface); + VASurfaceID surface_id; + VAStatus status; + guint va_chroma_format; + + va_chroma_format = from_GstVaapiChromaType (chroma_type); + if (!va_chroma_format) + goto error_unsupported_chroma_type; + + GST_VAAPI_DISPLAY_LOCK (display); + status = vaCreateSurfaces (GST_VAAPI_DISPLAY_VADISPLAY (display), + width, height, va_chroma_format, 1, &surface_id); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!vaapi_check_status (status, "vaCreateSurfaces()")) + return FALSE; + + GST_VAAPI_SURFACE_FORMAT (surface) = GST_VIDEO_FORMAT_UNKNOWN; + GST_VAAPI_SURFACE_CHROMA_TYPE (surface) = chroma_type; + GST_VAAPI_SURFACE_WIDTH (surface) = width; + GST_VAAPI_SURFACE_HEIGHT (surface) = height; + + GST_DEBUG ("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (surface_id)); + GST_VAAPI_SURFACE_ID (surface) = surface_id; + return TRUE; + + /* ERRORS */ +error_unsupported_chroma_type: + GST_ERROR ("unsupported chroma-type %u", chroma_type); + return FALSE; +} + +static guint +get_usage_hint (guint alloc_flags) +{ + guint usage_hints = VA_SURFACE_ATTRIB_USAGE_HINT_GENERIC; + + /* XXX(victor): So far, only media-driver uses hints for encoders + * and it doesn't test it as bitwise */ + if (alloc_flags & GST_VAAPI_SURFACE_ALLOC_FLAG_HINT_DECODER) + usage_hints = VA_SURFACE_ATTRIB_USAGE_HINT_DECODER; + else if (alloc_flags & GST_VAAPI_SURFACE_ALLOC_FLAG_HINT_ENCODER) + usage_hints = VA_SURFACE_ATTRIB_USAGE_HINT_ENCODER; + + return usage_hints; +} + +static gboolean +gst_vaapi_surface_init_full (GstVaapiSurface * surface, + const GstVideoInfo * vip, guint surface_allocation_flags) +{ + GstVaapiDisplay *const display = GST_VAAPI_SURFACE_DISPLAY (surface); + const GstVideoFormat format = GST_VIDEO_INFO_FORMAT (vip); + VASurfaceID surface_id; + VAStatus status; + guint chroma_type, va_chroma_format, i; + const VAImageFormat *va_format; + VASurfaceAttrib attribs[4], *attrib; + VASurfaceAttribExternalBuffers extbuf = { 0, }; + gboolean extbuf_needed = FALSE; + + va_format = gst_vaapi_video_format_to_va_format (format); + if (!va_format) + goto error_unsupported_format; + + chroma_type = gst_vaapi_video_format_get_chroma_type (format); + if (!chroma_type) + goto error_unsupported_format; + + va_chroma_format = from_GstVaapiChromaType (chroma_type); + if (!va_chroma_format) + goto error_unsupported_format; + + extbuf.pixel_format = va_format->fourcc; + extbuf.width = GST_VIDEO_INFO_WIDTH (vip); + extbuf.height = GST_VIDEO_INFO_HEIGHT (vip); + if (surface_allocation_flags & GST_VAAPI_SURFACE_ALLOC_FLAG_LINEAR_STORAGE) { + extbuf.flags &= ~VA_SURFACE_EXTBUF_DESC_ENABLE_TILING; + extbuf_needed = TRUE; + } + + extbuf.num_planes = GST_VIDEO_INFO_N_PLANES (vip); + if (surface_allocation_flags & (GST_VAAPI_SURFACE_ALLOC_FLAG_FIXED_STRIDES | + GST_VAAPI_SURFACE_ALLOC_FLAG_FIXED_OFFSETS)) { + for (i = 0; i < extbuf.num_planes; i++) { + if (surface_allocation_flags & GST_VAAPI_SURFACE_ALLOC_FLAG_FIXED_STRIDES) + extbuf.pitches[i] = GST_VIDEO_INFO_PLANE_STRIDE (vip, i); + if (surface_allocation_flags & GST_VAAPI_SURFACE_ALLOC_FLAG_FIXED_OFFSETS) + extbuf.offsets[i] = GST_VIDEO_INFO_PLANE_OFFSET (vip, i); + } + extbuf_needed = TRUE; + } + + attrib = attribs; + attrib->flags = VA_SURFACE_ATTRIB_SETTABLE; + attrib->type = VASurfaceAttribPixelFormat; + attrib->value.type = VAGenericValueTypeInteger; + attrib->value.value.i = va_format->fourcc; + attrib++; + + attrib->flags = VA_SURFACE_ATTRIB_SETTABLE; + attrib->type = VASurfaceAttribUsageHint; + attrib->value.type = VAGenericValueTypeInteger; + attrib->value.value.i = get_usage_hint (surface_allocation_flags); + attrib++; + + if (extbuf_needed) { + attrib->flags = VA_SURFACE_ATTRIB_SETTABLE; + attrib->type = VASurfaceAttribMemoryType; + attrib->value.type = VAGenericValueTypeInteger; + attrib->value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA; + attrib++; + + attrib->flags = VA_SURFACE_ATTRIB_SETTABLE; + attrib->type = VASurfaceAttribExternalBufferDescriptor; + attrib->value.type = VAGenericValueTypePointer; + attrib->value.value.p = &extbuf; + attrib++; + } + + GST_VAAPI_DISPLAY_LOCK (display); + status = vaCreateSurfaces (GST_VAAPI_DISPLAY_VADISPLAY (display), + va_chroma_format, extbuf.width, extbuf.height, &surface_id, 1, + attribs, attrib - attribs); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!vaapi_check_status (status, "vaCreateSurfaces()")) + return FALSE; + + GST_VAAPI_SURFACE_FORMAT (surface) = format; + GST_VAAPI_SURFACE_CHROMA_TYPE (surface) = chroma_type; + GST_VAAPI_SURFACE_WIDTH (surface) = extbuf.width; + GST_VAAPI_SURFACE_HEIGHT (surface) = extbuf.height; + + GST_DEBUG ("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (surface_id)); + GST_VAAPI_SURFACE_ID (surface) = surface_id; + return TRUE; + + /* ERRORS */ +error_unsupported_format: + GST_ERROR ("unsupported format %s", + gst_vaapi_video_format_to_string (format)); + return FALSE; +} + +static gboolean +gst_vaapi_surface_init_from_buffer_proxy (GstVaapiSurface * surface, + GstVaapiBufferProxy * proxy, const GstVideoInfo * vip) +{ + GstVaapiDisplay *const display = GST_VAAPI_SURFACE_DISPLAY (surface); + GstVideoFormat format; + VASurfaceID surface_id; + VAStatus status; + guint chroma_type, va_chroma_format; + const VAImageFormat *va_format; + VASurfaceAttrib attribs[2], *attrib; + VASurfaceAttribExternalBuffers extbuf = { 0, }; + unsigned long extbuf_handle; + guint i, width, height; + + format = GST_VIDEO_INFO_FORMAT (vip); + width = GST_VIDEO_INFO_WIDTH (vip); + height = GST_VIDEO_INFO_HEIGHT (vip); + + gst_vaapi_buffer_proxy_replace (&surface->extbuf_proxy, proxy); + + va_format = gst_vaapi_video_format_to_va_format (format); + if (!va_format) + goto error_unsupported_format; + + chroma_type = gst_vaapi_video_format_get_chroma_type (format); + if (!chroma_type) + goto error_unsupported_format; + + va_chroma_format = from_GstVaapiChromaType (chroma_type); + if (!va_chroma_format) + goto error_unsupported_format; + + extbuf_handle = GST_VAAPI_BUFFER_PROXY_HANDLE (proxy); + extbuf.pixel_format = va_format->fourcc; + extbuf.width = width; + extbuf.height = height; + extbuf.data_size = GST_VAAPI_BUFFER_PROXY_SIZE (proxy); + extbuf.num_planes = GST_VIDEO_INFO_N_PLANES (vip); + for (i = 0; i < extbuf.num_planes; i++) { + extbuf.pitches[i] = GST_VIDEO_INFO_PLANE_STRIDE (vip, i); + extbuf.offsets[i] = GST_VIDEO_INFO_PLANE_OFFSET (vip, i); + } + extbuf.buffers = (uintptr_t *) & extbuf_handle; + extbuf.num_buffers = 1; + extbuf.flags = 0; + extbuf.private_data = NULL; + + attrib = attribs; + attrib->type = VASurfaceAttribExternalBufferDescriptor; + attrib->flags = VA_SURFACE_ATTRIB_SETTABLE; + attrib->value.type = VAGenericValueTypePointer; + attrib->value.value.p = &extbuf; + attrib++; + attrib->type = VASurfaceAttribMemoryType; + attrib->flags = VA_SURFACE_ATTRIB_SETTABLE; + attrib->value.type = VAGenericValueTypeInteger; + attrib->value.value.i = + from_GstVaapiBufferMemoryType (GST_VAAPI_BUFFER_PROXY_TYPE (proxy)); + attrib++; + + GST_VAAPI_DISPLAY_LOCK (display); + status = vaCreateSurfaces (GST_VAAPI_DISPLAY_VADISPLAY (display), + va_chroma_format, width, height, &surface_id, 1, attribs, + attrib - attribs); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!vaapi_check_status (status, "vaCreateSurfaces()")) + return FALSE; + + GST_VAAPI_SURFACE_FORMAT (surface) = format; + GST_VAAPI_SURFACE_CHROMA_TYPE (surface) = chroma_type; + GST_VAAPI_SURFACE_WIDTH (surface) = width; + GST_VAAPI_SURFACE_HEIGHT (surface) = height; + + GST_DEBUG ("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (surface_id)); + GST_VAAPI_SURFACE_ID (surface) = surface_id; + return TRUE; + + /* ERRORS */ +error_unsupported_format: + GST_ERROR ("unsupported format %s", + gst_vaapi_video_format_to_string (format)); + return FALSE; +} + +GST_DEFINE_MINI_OBJECT_TYPE (GstVaapiSurface, gst_vaapi_surface); + +static GstVaapiSurface * +gst_vaapi_surface_create (GstVaapiDisplay * display) +{ + GstVaapiSurface *surface = g_slice_new (GstVaapiSurface); + if (!surface) + return NULL; + + gst_mini_object_init (GST_MINI_OBJECT_CAST (surface), 0, + GST_TYPE_VAAPI_SURFACE, NULL, NULL, + (GstMiniObjectFreeFunction) gst_vaapi_surface_free); + + GST_VAAPI_SURFACE_DISPLAY (surface) = gst_object_ref (display); + GST_VAAPI_SURFACE_ID (surface) = VA_INVALID_ID; + surface->extbuf_proxy = NULL; + surface->subpictures = NULL; + + return surface; +} + +/** + * gst_vaapi_surface_get_display: + * @surface: a #GstVaapiSurface + * + * Returns the #GstVaapiDisplay this @surface is bound to. + * + * Return value: the parent #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_surface_get_display (GstVaapiSurface * surface) +{ + g_return_val_if_fail (surface != NULL, NULL); + return GST_VAAPI_SURFACE_DISPLAY (surface); +} + +/** + * gst_vaapi_surface_new: + * @display: a #GstVaapiDisplay + * @chroma_type: the surface chroma format + * @width: the requested surface width + * @height: the requested surface height + * + * Creates a new #GstVaapiSurface with the specified chroma format and + * dimensions. + * + * NOTE: this method for creating surfaces uses deprecated VA API, + * which is still used by drivers (v.gr. i965 for jpeg decoding). + * + * Return value: the newly allocated #GstVaapiSurface object + */ +GstVaapiSurface * +gst_vaapi_surface_new (GstVaapiDisplay * display, + GstVaapiChromaType chroma_type, guint width, guint height) +{ + GstVaapiSurface *surface; + + GST_DEBUG ("size %ux%u, chroma type 0x%x", width, height, chroma_type); + + surface = gst_vaapi_surface_create (display); + if (!surface) + return NULL; + + if (!gst_vaapi_surface_init (surface, chroma_type, width, height)) + goto error; + return surface; + + /* ERRORS */ +error: + { + gst_vaapi_surface_unref (surface); + return NULL; + } +} + +/** + * gst_vaapi_surface_new_full: + * @display: a #GstVaapiDisplay + * @vip: the pointer to a #GstVideoInfo + * @surface_allocation_flags: (optional) allocation flags + * + * Creates a new #GstVaapiSurface with the specified video information + * and optional #GstVaapiSurfaceAllocFlags + * + * Return value: the newly allocated #GstVaapiSurface object, or %NULL + * if creation of VA surface with explicit pixel format is not + * supported or failed. + */ +GstVaapiSurface * +gst_vaapi_surface_new_full (GstVaapiDisplay * display, const GstVideoInfo * vip, + guint surface_allocation_flags) +{ + GstVaapiSurface *surface; + + GST_DEBUG ("size %ux%u, format %s, flags 0x%08x", GST_VIDEO_INFO_WIDTH (vip), + GST_VIDEO_INFO_HEIGHT (vip), + gst_vaapi_video_format_to_string (GST_VIDEO_INFO_FORMAT (vip)), + surface_allocation_flags); + + surface = gst_vaapi_surface_create (display); + if (!surface) + return NULL; + + if (!gst_vaapi_surface_init_full (surface, vip, surface_allocation_flags)) + goto error; + return surface; + + /* ERRORS */ +error: + { + gst_vaapi_surface_unref (surface); + return NULL; + } +} + +/** + * gst_vaapi_surface_new_with_format: + * @display: a #GstVaapiDisplay + * @format: the surface format + * @width: the requested surface width + * @height: the requested surface height + * @surface_allocation_flags: (optional) allocation flags + * + * Creates a new #GstVaapiSurface with the specified pixel format and + * dimensions. + * + * Return value: the newly allocated #GstVaapiSurface object, or %NULL + * if creation of VA surface with explicit pixel format is not + * supported or failed. + */ +GstVaapiSurface * +gst_vaapi_surface_new_with_format (GstVaapiDisplay * display, + GstVideoFormat format, guint width, guint height, + guint surface_allocation_flags) +{ + GstVideoInfo vi; + + gst_video_info_set_format (&vi, format, width, height); + return gst_vaapi_surface_new_full (display, &vi, surface_allocation_flags); +} + +/** + * gst_vaapi_surface_new_from_buffer_proxy: + * @display: a #GstVaapiDisplay + * @proxy: a #GstVaapiBufferProxy + * @info: the #GstVideoInfo structure defining the layout of the buffer + * + * Creates a new #GstVaapiSurface with the supplied VA buffer proxy + * abstraction. The underlying VA buffer memory type could be anything + * that is supported by the VA driver. + * + * The resulting #GstVaapiSurface object owns an extra reference to + * the buffer @proxy, so the caller can safely release that handle as + * early as on return of this call. + * + * Return value: the newly allocated #GstVaapiSurface object, or %NULL + * if creation of VA surface failed or is not supported + */ +GstVaapiSurface * +gst_vaapi_surface_new_from_buffer_proxy (GstVaapiDisplay * display, + GstVaapiBufferProxy * proxy, const GstVideoInfo * info) +{ + GstVaapiSurface *surface; + + g_return_val_if_fail (proxy != NULL, NULL); + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (!proxy->surface, NULL); + + surface = gst_vaapi_surface_create (display); + if (!surface) + return NULL; + + if (!gst_vaapi_surface_init_from_buffer_proxy (surface, proxy, info)) + goto error; + + proxy->surface = GST_MINI_OBJECT_CAST (surface); + return surface; + + /* ERRORS */ +error: + { + gst_vaapi_surface_unref (surface); + return NULL; + } +} + +/** + * gst_vaapi_surface_get_id: + * @surface: a #GstVaapiSurface + * + * Returns the underlying VASurfaceID of the @surface. + * + * Return value: the underlying VA surface id + */ +GstVaapiID +gst_vaapi_surface_get_id (GstVaapiSurface * surface) +{ + g_return_val_if_fail (surface != NULL, VA_INVALID_SURFACE); + + return GST_VAAPI_SURFACE_ID (surface); +} + +/** + * gst_vaapi_surface_get_chroma_type: + * @surface: a #GstVaapiSurface + * + * Returns the #GstVaapiChromaType the @surface was created with. + * + * Return value: the #GstVaapiChromaType + */ +GstVaapiChromaType +gst_vaapi_surface_get_chroma_type (GstVaapiSurface * surface) +{ + g_return_val_if_fail (surface != NULL, 0); + + return GST_VAAPI_SURFACE_CHROMA_TYPE (surface); +} + +/** + * gst_vaapi_surface_get_format: + * @surface: a #GstVaapiSurface + * + * Returns the #GstVideoFormat the @surface was created with. + * + * Return value: the #GstVideoFormat, or %GST_VIDEO_FORMAT_ENCODED if + * the surface was not created with an explicit video format, or if + * the underlying video format could not be determined + */ +GstVideoFormat +gst_vaapi_surface_get_format (GstVaapiSurface * surface) +{ + g_return_val_if_fail (surface != NULL, 0); + + /* Try to determine the underlying VA surface format */ + if (GST_VAAPI_SURFACE_FORMAT (surface) == GST_VIDEO_FORMAT_UNKNOWN) { + GstVaapiImage *const image = gst_vaapi_surface_derive_image (surface); + if (image) { + GST_VAAPI_SURFACE_FORMAT (surface) = GST_VAAPI_IMAGE_FORMAT (image); + gst_vaapi_image_unref (image); + } + if (GST_VAAPI_SURFACE_FORMAT (surface) == GST_VIDEO_FORMAT_UNKNOWN) + GST_VAAPI_SURFACE_FORMAT (surface) = GST_VIDEO_FORMAT_ENCODED; + } + return GST_VAAPI_SURFACE_FORMAT (surface); +} + +/** + * gst_vaapi_surface_get_width: + * @surface: a #GstVaapiSurface + * + * Returns the @surface width. + * + * Return value: the surface width, in pixels + */ +guint +gst_vaapi_surface_get_width (GstVaapiSurface * surface) +{ + g_return_val_if_fail (surface != NULL, 0); + + return GST_VAAPI_SURFACE_WIDTH (surface); +} + +/** + * gst_vaapi_surface_get_height: + * @surface: a #GstVaapiSurface + * + * Returns the @surface height. + * + * Return value: the surface height, in pixels. + */ +guint +gst_vaapi_surface_get_height (GstVaapiSurface * surface) +{ + g_return_val_if_fail (surface != NULL, 0); + + return GST_VAAPI_SURFACE_HEIGHT (surface); +} + +/** + * gst_vaapi_surface_get_size: + * @surface: a #GstVaapiSurface + * @width_ptr: return location for the width, or %NULL + * @height_ptr: return location for the height, or %NULL + * + * Retrieves the dimensions of a #GstVaapiSurface. + */ +void +gst_vaapi_surface_get_size (GstVaapiSurface * surface, + guint * width_ptr, guint * height_ptr) +{ + g_return_if_fail (surface != NULL); + + if (width_ptr) + *width_ptr = GST_VAAPI_SURFACE_WIDTH (surface); + + if (height_ptr) + *height_ptr = GST_VAAPI_SURFACE_HEIGHT (surface); +} + +/** + * gst_vaapi_surface_derive_image: + * @surface: a #GstVaapiSurface + * + * Derives a #GstVaapiImage from the @surface. This image buffer can + * then be mapped/unmapped for direct CPU access. This operation is + * only possible if the underlying implementation supports direct + * rendering capabilities and internal surface formats that can be + * represented with a #GstVaapiImage. + * + * When the operation is not possible, the function returns %NULL and + * the user should then fallback to using gst_vaapi_surface_get_image() + * or gst_vaapi_surface_put_image() to accomplish the same task in an + * indirect manner (additional copy). + * + * An image created with gst_vaapi_surface_derive_image() should be + * unreferenced when it's no longer needed. The image and image buffer + * data structures will be destroyed. However, the surface contents + * will remain unchanged until destroyed through the last call to + * gst_vaapi_image_unref(). + * + * Return value: the newly allocated #GstVaapiImage object, or %NULL + * on failure + */ +GstVaapiImage * +gst_vaapi_surface_derive_image (GstVaapiSurface * surface) +{ + GstVaapiDisplay *display; + VAImage va_image; + VAStatus status; + GstVaapiImage *image; + + g_return_val_if_fail (surface != NULL, NULL); + + display = GST_VAAPI_SURFACE_DISPLAY (surface); + va_image.image_id = VA_INVALID_ID; + va_image.buf = VA_INVALID_ID; + + GST_VAAPI_DISPLAY_LOCK (display); + status = vaDeriveImage (GST_VAAPI_DISPLAY_VADISPLAY (display), + GST_VAAPI_SURFACE_ID (surface), &va_image); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!vaapi_check_status (status, "vaDeriveImage()")) + return NULL; + if (va_image.image_id == VA_INVALID_ID || va_image.buf == VA_INVALID_ID) + return NULL; + + image = gst_vaapi_image_new_with_image (display, &va_image); + if (!image) + vaDestroyImage (GST_VAAPI_DISPLAY_VADISPLAY (display), va_image.image_id); + return image; +} + +/** + * gst_vaapi_surface_get_image + * @surface: a #GstVaapiSurface + * @image: a #GstVaapiImage + * + * Retrieves surface data into a #GstVaapiImage. The @image must have + * a format supported by the @surface. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_surface_get_image (GstVaapiSurface * surface, GstVaapiImage * image) +{ + GstVaapiDisplay *display; + VAImageID image_id; + VAStatus status; + guint width, height; + + g_return_val_if_fail (surface != NULL, FALSE); + g_return_val_if_fail (image != NULL, FALSE); + + display = GST_VAAPI_SURFACE_DISPLAY (surface); + if (!display) + return FALSE; + + width = GST_VAAPI_IMAGE_WIDTH (image); + height = GST_VAAPI_IMAGE_HEIGHT (image); + if (width != GST_VAAPI_SURFACE_WIDTH (surface) + || height != GST_VAAPI_SURFACE_HEIGHT (surface)) + return FALSE; + + image_id = GST_VAAPI_IMAGE_ID (image); + if (image_id == VA_INVALID_ID) + return FALSE; + + GST_VAAPI_DISPLAY_LOCK (display); + status = vaGetImage (GST_VAAPI_DISPLAY_VADISPLAY (display), + GST_VAAPI_SURFACE_ID (surface), 0, 0, width, height, image_id); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!vaapi_check_status (status, "vaGetImage()")) + return FALSE; + + return TRUE; +} + +/** + * gst_vaapi_surface_put_image: + * @surface: a #GstVaapiSurface + * @image: a #GstVaapiImage + * + * Copies data from a #GstVaapiImage into a @surface. The @image must + * have a format supported by the @surface. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_surface_put_image (GstVaapiSurface * surface, GstVaapiImage * image) +{ + GstVaapiDisplay *display; + VAImageID image_id; + VAStatus status; + guint width, height; + + g_return_val_if_fail (surface != NULL, FALSE); + g_return_val_if_fail (image != NULL, FALSE); + + display = GST_VAAPI_SURFACE_DISPLAY (surface); + if (!display) + return FALSE; + + width = GST_VAAPI_IMAGE_WIDTH (image); + height = GST_VAAPI_IMAGE_HEIGHT (image); + if (width != GST_VAAPI_SURFACE_WIDTH (surface) + || height != GST_VAAPI_SURFACE_HEIGHT (surface)) + return FALSE; + + image_id = GST_VAAPI_IMAGE_ID (image); + if (image_id == VA_INVALID_ID) + return FALSE; + + GST_VAAPI_DISPLAY_LOCK (display); + status = vaPutImage (GST_VAAPI_DISPLAY_VADISPLAY (display), + GST_VAAPI_SURFACE_ID (surface), image_id, 0, 0, width, height, 0, 0, + width, height); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!vaapi_check_status (status, "vaPutImage()")) + return FALSE; + + return TRUE; +} + +/** + * gst_vaapi_surface_associate_subpicture: + * @surface: a #GstVaapiSurface + * @subpicture: a #GstVaapiSubpicture + * @src_rect: the sub-rectangle of the source subpicture + * image to extract and process. If %NULL, the entire image will be used. + * @dst_rect: the sub-rectangle of the destination + * surface into which the image is rendered. If %NULL, the entire + * surface will be used. + * + * Associates the @subpicture with the @surface. The @src_rect + * coordinates and size are relative to the source image bound to + * @subpicture. The @dst_rect coordinates and size are relative to the + * target @surface. Note that the @surface holds an additional + * reference to the @subpicture. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_surface_associate_subpicture (GstVaapiSurface * surface, + GstVaapiSubpicture * subpicture, + const GstVaapiRectangle * src_rect, const GstVaapiRectangle * dst_rect) +{ + gboolean success; + + g_return_val_if_fail (surface != NULL, FALSE); + g_return_val_if_fail (subpicture != NULL, FALSE); + + if (!surface->subpictures) { + surface->subpictures = g_ptr_array_new (); + if (!surface->subpictures) + return FALSE; + } + + if (g_ptr_array_remove_fast (surface->subpictures, subpicture)) { + success = _gst_vaapi_surface_deassociate_subpicture (surface, subpicture); + gst_vaapi_subpicture_unref (subpicture); + if (!success) + return FALSE; + } + + success = _gst_vaapi_surface_associate_subpicture (surface, + subpicture, src_rect, dst_rect); + if (!success) + return FALSE; + + g_ptr_array_add (surface->subpictures, + gst_mini_object_ref (GST_MINI_OBJECT_CAST (subpicture))); + return TRUE; +} + +gboolean +_gst_vaapi_surface_associate_subpicture (GstVaapiSurface * surface, + GstVaapiSubpicture * subpicture, + const GstVaapiRectangle * src_rect, const GstVaapiRectangle * dst_rect) +{ + GstVaapiDisplay *display; + GstVaapiRectangle src_rect_default, dst_rect_default; + GstVaapiImage *image; + VASurfaceID surface_id; + VAStatus status; + + display = GST_VAAPI_SURFACE_DISPLAY (surface); + if (!display) + return FALSE; + + surface_id = GST_VAAPI_SURFACE_ID (surface); + if (surface_id == VA_INVALID_SURFACE) + return FALSE; + + if (!src_rect) { + image = gst_vaapi_subpicture_get_image (subpicture); + if (!image) + return FALSE; + src_rect = &src_rect_default; + src_rect_default.x = 0; + src_rect_default.y = 0; + src_rect_default.width = GST_VAAPI_IMAGE_WIDTH (image); + src_rect_default.height = GST_VAAPI_IMAGE_HEIGHT (image); + } + + if (!dst_rect) { + dst_rect = &dst_rect_default; + dst_rect_default.x = 0; + dst_rect_default.y = 0; + dst_rect_default.width = GST_VAAPI_SURFACE_WIDTH (surface); + dst_rect_default.height = GST_VAAPI_SURFACE_HEIGHT (surface); + } + + GST_VAAPI_DISPLAY_LOCK (display); + status = vaAssociateSubpicture (GST_VAAPI_DISPLAY_VADISPLAY (display), + GST_VAAPI_SUBPICTURE_ID (subpicture), &surface_id, 1, + src_rect->x, src_rect->y, src_rect->width, src_rect->height, + dst_rect->x, dst_rect->y, dst_rect->width, dst_rect->height, + from_GstVaapiSubpictureFlags (gst_vaapi_subpicture_get_flags + (subpicture))); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!vaapi_check_status (status, "vaAssociateSubpicture()")) + return FALSE; + + return TRUE; +} + +/** + * gst_vaapi_surface_deassociate_subpicture: + * @surface: a #GstVaapiSurface + * @subpicture: a #GstVaapiSubpicture + * + * Deassociates @subpicture from @surface. Other associations are kept. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_surface_deassociate_subpicture (GstVaapiSurface * surface, + GstVaapiSubpicture * subpicture) +{ + gboolean success; + + g_return_val_if_fail (surface != NULL, FALSE); + g_return_val_if_fail (subpicture != NULL, FALSE); + + if (!surface->subpictures) + return TRUE; + + /* First, check subpicture was really associated with this surface */ + if (!g_ptr_array_remove_fast (surface->subpictures, subpicture)) { + GST_DEBUG ("subpicture %" GST_VAAPI_ID_FORMAT " was not bound to " + "surface %" GST_VAAPI_ID_FORMAT, + GST_VAAPI_ID_ARGS (GST_VAAPI_SUBPICTURE_ID (subpicture)), + GST_VAAPI_ID_ARGS (GST_VAAPI_SURFACE_ID (surface))); + return TRUE; + } + + success = _gst_vaapi_surface_deassociate_subpicture (surface, subpicture); + gst_vaapi_subpicture_unref (subpicture); + return success; +} + +gboolean +_gst_vaapi_surface_deassociate_subpicture (GstVaapiSurface * surface, + GstVaapiSubpicture * subpicture) +{ + GstVaapiDisplay *display; + VASurfaceID surface_id; + VAStatus status; + + display = GST_VAAPI_SURFACE_DISPLAY (surface); + if (!display) + return FALSE; + + surface_id = GST_VAAPI_SURFACE_ID (surface); + if (surface_id == VA_INVALID_SURFACE) + return FALSE; + + GST_VAAPI_DISPLAY_LOCK (display); + status = vaDeassociateSubpicture (GST_VAAPI_DISPLAY_VADISPLAY (display), + GST_VAAPI_SUBPICTURE_ID (subpicture), &surface_id, 1); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!vaapi_check_status (status, "vaDeassociateSubpicture()")) + return FALSE; + + return TRUE; +} + +/** + * gst_vaapi_surface_sync: + * @surface: a #GstVaapiSurface + * + * Blocks until all pending operations on the @surface have been + * completed. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_surface_sync (GstVaapiSurface * surface) +{ + GstVaapiDisplay *display; + VAStatus status; + + g_return_val_if_fail (surface != NULL, FALSE); + + display = GST_VAAPI_SURFACE_DISPLAY (surface); + if (!display) + return FALSE; + + GST_VAAPI_DISPLAY_LOCK (display); + status = vaSyncSurface (GST_VAAPI_DISPLAY_VADISPLAY (display), + GST_VAAPI_SURFACE_ID (surface)); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!vaapi_check_status (status, "vaSyncSurface()")) + return FALSE; + + return TRUE; +} + +/** + * gst_vaapi_surface_query_status: + * @surface: a #GstVaapiSurface + * @pstatus: return location for the #GstVaapiSurfaceStatus + * + * Finds out any pending operations on the @surface. The + * #GstVaapiSurfaceStatus flags are returned into @pstatus. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_surface_query_status (GstVaapiSurface * surface, + GstVaapiSurfaceStatus * pstatus) +{ + GstVaapiDisplay *const display = GST_VAAPI_SURFACE_DISPLAY (surface); + VASurfaceStatus surface_status; + VAStatus status; + + g_return_val_if_fail (surface != NULL, FALSE); + + GST_VAAPI_DISPLAY_LOCK (display); + status = vaQuerySurfaceStatus (GST_VAAPI_DISPLAY_VADISPLAY (display), + GST_VAAPI_SURFACE_ID (surface), &surface_status); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!vaapi_check_status (status, "vaQuerySurfaceStatus()")) + return FALSE; + + if (pstatus) + *pstatus = to_GstVaapiSurfaceStatus (surface_status); + return TRUE; +} + +/** + * gst_vaapi_surface_set_subpictures_from_composition: + * @surface: a #GstVaapiSurface + * @compostion: a #GstVideoOverlayCompositon + * + * Helper to update the subpictures from #GstVideoOverlayCompositon. Sending + * a NULL composition will clear all the current subpictures. Note that this + * method will clear existing subpictures. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_surface_set_subpictures_from_composition (GstVaapiSurface * surface, + GstVideoOverlayComposition * composition) +{ + GstVaapiDisplay *display; + guint n, nb_rectangles; + + g_return_val_if_fail (surface != NULL, FALSE); + + display = GST_VAAPI_SURFACE_DISPLAY (surface); + if (!display) + return FALSE; + + /* Clear current subpictures */ + gst_vaapi_surface_destroy_subpictures (surface); + + if (!composition) + return TRUE; + + nb_rectangles = gst_video_overlay_composition_n_rectangles (composition); + + /* Overlay all the rectangles cantained in the overlay composition */ + for (n = 0; n < nb_rectangles; ++n) { + GstVideoOverlayRectangle *rect; + GstVaapiRectangle sub_rect; + GstVaapiSubpicture *subpicture; + + rect = gst_video_overlay_composition_get_rectangle (composition, n); + subpicture = gst_vaapi_subpicture_new_from_overlay_rectangle (display, + rect); + if (subpicture == NULL) { + GST_WARNING ("could not create subpicture for rectangle %p", rect); + return FALSE; + } + + gst_video_overlay_rectangle_get_render_rectangle (rect, + (gint *) & sub_rect.x, (gint *) & sub_rect.y, + &sub_rect.width, &sub_rect.height); + + /* ensure that the overlay is not bigger than the surface */ + sub_rect.y = MIN (sub_rect.y, GST_VAAPI_SURFACE_HEIGHT (surface)); + sub_rect.width = MIN (sub_rect.width, GST_VAAPI_SURFACE_WIDTH (surface)); + + if (!gst_vaapi_surface_associate_subpicture (surface, subpicture, + NULL, &sub_rect)) { + GST_WARNING ("could not render overlay rectangle %p", rect); + gst_vaapi_subpicture_unref (subpicture); + return FALSE; + } + gst_vaapi_subpicture_unref (subpicture); + } + return TRUE; +} + +/** + * gst_vaapi_surface_set_buffer_proxy: + * @surface: a #GstVaapiSurface + * @proxy: an external #GstVaapiBufferProxy + * + * Replaces the external buffer proxy in @surface with @proxy. + * + * This is useful when a dmabuf-based memory is instantiated in order + * to relate the generated buffer @proxy with the processed @surface. + **/ +void +gst_vaapi_surface_set_buffer_proxy (GstVaapiSurface * surface, + GstVaapiBufferProxy * proxy) +{ + gst_vaapi_buffer_proxy_replace (&surface->extbuf_proxy, proxy); +} + +/** + * gst_vaapi_surface_peek_buffer_proxy: + * @surface: a #GstVaapiSurface + * + * This is useful when a dmabuf-based memory is instantiated in order + * to relate the generated buffer @proxy with the processed @surface. + * + * Returns: (transfer none): the associated external + * #GstVaapiBufferProxy + **/ +GstVaapiBufferProxy * +gst_vaapi_surface_peek_buffer_proxy (GstVaapiSurface * surface) +{ + return surface->extbuf_proxy; +} diff --git a/gst-libs/gst/vaapi/gstvaapisurface.h b/gst-libs/gst/vaapi/gstvaapisurface.h new file mode 100644 index 0000000000..822bb1c9f4 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapisurface.h @@ -0,0 +1,288 @@ +/* + * gstvaapisurface.h - VA surface abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_SURFACE_H +#define GST_VAAPI_SURFACE_H + +#include +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +/** + * GST_VAAPI_SURFACE_CAPS_NAME: + * + * Generic caps type for VA surfaces. + */ +#define GST_VAAPI_SURFACE_CAPS_NAME "video/x-surface" + +/** + * GST_VAAPI_SURFACE_CAPS: + * + * Generic caps for VA surfaces. + */ +#define GST_VAAPI_SURFACE_CAPS \ + GST_VAAPI_SURFACE_CAPS_NAME ", " \ + "type = vaapi, " \ + "opengl = (boolean) { true, false }, " \ + "width = (int) [ 1, MAX ], " \ + "height = (int) [ 1, MAX ], " \ + "framerate = (fraction) [ 0, MAX ]" + +/** + * GstVaapiChromaType: + * @GST_VAAPI_CHROMA_TYPE_YUV420: YUV 4:2:0 chroma format + * @GST_VAAPI_CHROMA_TYPE_YUV422: YUV 4:2:2 chroma format + * @GST_VAAPI_CHROMA_TYPE_YUV444: YUV 4:4:4 chroma format + * @GST_VAAPI_CHROMA_TYPE_YUV411: YUV 4:1:1 chroma format + * @GST_VAAPI_CHROMA_TYPE_YUV400: YUV 4:0:0 chroma format (grayscale) + * @GST_VAAPI_CHROMA_TYPE_YUV420_10BPP: YUV 4:2:0 chroma format, 10 bits per channel + * @GST_VAAPI_CHROMA_TYPE_YUV422_10BPP: YUV 4:2:2 chroma format, 10 bits per channel + * @GST_VAAPI_CHROMA_TYPE_YUV444_10BPP: YUV 4:4:4 chroma format, 10 bits per channel + * @GST_VAAPI_CHROMA_TYPE_YUV420_12BPP: YUV 4:2:0 chroma format, 12 bits per channel + * @GST_VAAPI_CHROMA_TYPE_YUV422_12BPP: YUV 4:2:2 chroma format, 12 bits per channel + * @GST_VAAPI_CHROMA_TYPE_YUV444_12BPP: YUV 4:4:4 chroma format, 12 bits per channel + * @GST_VAAPI_CHROMA_TYPE_RGB16: 16-bit RGB chroma format + * @GST_VAAPI_CHROMA_TYPE_RGB32: 32-bit RGB chroma format + * @GST_VAAPI_CHROMA_TYPE_RGBP: Planar RGB, 8 bits per colour sample. + * @GST_VAAPI_CHROMA_TYPE_RGB32_10BPP: 32-bit RGB chroma format, 10 bits per colour sample + * + * The set of all chroma types for #GstVaapiSurface. + */ +typedef enum +{ + GST_VAAPI_CHROMA_TYPE_YUV420 = 1, + GST_VAAPI_CHROMA_TYPE_YUV422, + GST_VAAPI_CHROMA_TYPE_YUV444, + GST_VAAPI_CHROMA_TYPE_YUV411, + GST_VAAPI_CHROMA_TYPE_YUV400, + GST_VAAPI_CHROMA_TYPE_YUV420_10BPP, + GST_VAAPI_CHROMA_TYPE_YUV422_10BPP, + GST_VAAPI_CHROMA_TYPE_YUV444_10BPP, + GST_VAAPI_CHROMA_TYPE_YUV420_12BPP, + GST_VAAPI_CHROMA_TYPE_YUV422_12BPP, + GST_VAAPI_CHROMA_TYPE_YUV444_12BPP, + GST_VAAPI_CHROMA_TYPE_RGB16, + GST_VAAPI_CHROMA_TYPE_RGB32, + GST_VAAPI_CHROMA_TYPE_RGBP, + GST_VAAPI_CHROMA_TYPE_RGB32_10BPP, +} GstVaapiChromaType; + +/** + * GstVaapiSurfaceStatus: + * @GST_VAAPI_SURFACE_STATUS_IDLE: + * the surface is not being rendered or displayed + * @GST_VAAPI_SURFACE_STATUS_RENDERING: + * the surface is used for rendering (decoding to the surface in progress) + * @GST_VAAPI_SURFACE_STATUS_DISPLAYING: + * the surface is being displayed to screen + * @GST_VAAPI_SURFACE_STATUS_SKIPPED: + * indicates a skipped frame during encode + * + * The set of all surface status for #GstVaapiSurface. + */ +typedef enum +{ + GST_VAAPI_SURFACE_STATUS_IDLE = 1 << 0, + GST_VAAPI_SURFACE_STATUS_RENDERING = 1 << 1, + GST_VAAPI_SURFACE_STATUS_DISPLAYING = 1 << 2, + GST_VAAPI_SURFACE_STATUS_SKIPPED = 1 << 3 +} GstVaapiSurfaceStatus; + +/** + * GstVaapiSurfaceRenderFlags: + * @GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD: + * selects the top field of the surface + * @GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD: + * selects the bottom field of the surface + * @GST_VAAPI_PICTURE_STRUCTURE_FRAME: + * selects the entire surface + * @GST_VAAPI_COLOR_STANDARD_ITUR_BT_601: + * uses ITU-R BT.601 standard for color space conversion + * @GST_VAAPI_COLOR_STANDARD_ITUR_BT_709: + * uses ITU-R BT.709 standard for color space conversion + * @GST_VAAPI_COLOR_STANDARD_ITUR_BT_470M: + * uses ITU-R BT.470-2 System M standard for color space conversion + * @GST_VAAPI_COLOR_STANDARD_ITUR_BT_470BG: + * uses ITU-R BT.470-2 System B, G standard for color space conversion + * @GST_VAAPI_COLOR_STANDARD_SMPTE_170M: + * uses SMPTE-170M standard for color space conversion + * @GST_VAAPI_COLOR_STANDARD_SMPTE_240M: + * uses SMPTE-240M standard for color space conversion + * + * The set of all render flags for gst_vaapi_window_put_surface(). + */ +typedef enum +{ + /* Picture structure */ + GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD = 0x01 << 0, + GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD = 0x02 << 0, + GST_VAAPI_PICTURE_STRUCTURE_FRAME = 0x03 << 0, + GST_VAAPI_PICTURE_STRUCTURE_MASK = 0x00000003, /* 2 bits */ + + /* Color standard */ + GST_VAAPI_COLOR_STANDARD_ITUR_BT_601 = 0x01 << 2, + GST_VAAPI_COLOR_STANDARD_ITUR_BT_709 = 0x02 << 2, + GST_VAAPI_COLOR_STANDARD_ITUR_BT_470M = 0x03 << 2, + GST_VAAPI_COLOR_STANDARD_ITUR_BT_470BG = 0x04 << 2, + GST_VAAPI_COLOR_STANDARD_SMPTE_170M = 0x05 << 2, + GST_VAAPI_COLOR_STANDARD_SMPTE_240M = 0x06 << 2, + GST_VAAPI_COLOR_STANDARD_MASK = 0x0000003c, /* 4 bits */ +} GstVaapiSurfaceRenderFlags; + +/** + * GstVaapiSurfaceAllocFlags: + * @GST_VAAPI_SURFACE_ALLOC_FLAG_LINEAR_STORAGE: forces allocation + * with linear storage. Default behaviour matches native + * requirements, and thus could be tiled. + * @GST_VAAPI_SURFACE_ALLOC_FLAG_FIXED_STRIDES: force allocation with + * the supplied strides information from #GstVideoInfo + * @GST_VAAPI_SURFACE_ALLOC_FLAG_FIXED_OFFSETS: force allocation with + * the supplied offsets information from #GstVideoInfo + * @GST_VAAPI_SURFACE_ALLOC_FLAG_HINT_DECODER: Surface used by video + * decoder + * @GST_VAAPI_SURFACE_ALLOC_FLAG_HINT_ENCODER: Surface used by encoder + * + * The set of optional allocation flags for gst_vaapi_surface_new_full(). + */ +typedef enum +{ + GST_VAAPI_SURFACE_ALLOC_FLAG_LINEAR_STORAGE = 1 << 0, + GST_VAAPI_SURFACE_ALLOC_FLAG_FIXED_STRIDES = 1 << 1, + GST_VAAPI_SURFACE_ALLOC_FLAG_FIXED_OFFSETS = 1 << 2, + GST_VAAPI_SURFACE_ALLOC_FLAG_HINT_DECODER = 1 << 3, + GST_VAAPI_SURFACE_ALLOC_FLAG_HINT_ENCODER = 1 << 4, +} GstVaapiSurfaceAllocFlags; + +#define GST_VAAPI_SURFACE(obj) \ + ((GstVaapiSurface *)(obj)) + +#define GST_TYPE_VAAPI_SURFACE (gst_vaapi_surface_get_type ()) + +#define GST_VAAPI_SURFACE_ID(surface) (gst_vaapi_surface_get_id (surface)) +#define GST_VAAPI_SURFACE_DISPLAY(surface) (gst_vaapi_surface_get_display (surface)) + +typedef struct _GstVaapiSurface GstVaapiSurface; +typedef struct _GstVaapiSurfaceProxy GstVaapiSurfaceProxy; + +GType +gst_vaapi_surface_get_type (void) G_GNUC_CONST; + +/** + * gst_vaapi_surface_unref: (skip) + * @surface: (transfer full): a #GstVaapiSurface. + * + * Decreases the refcount of the surface. If the refcount reaches 0, the + * surface will be freed. + */ +static inline void +gst_vaapi_surface_unref (GstVaapiSurface * surface) +{ + gst_mini_object_unref (GST_MINI_OBJECT_CAST (surface)); +} + +GstVaapiDisplay * +gst_vaapi_surface_get_display (GstVaapiSurface * surface); + +GstVaapiSurface * +gst_vaapi_surface_new (GstVaapiDisplay * display, + GstVaapiChromaType chroma_type, guint width, guint height); + +GstVaapiSurface * +gst_vaapi_surface_new_full (GstVaapiDisplay * display, + const GstVideoInfo * vip, guint surface_allocation_flags); + +GstVaapiSurface * +gst_vaapi_surface_new_with_format (GstVaapiDisplay * display, + GstVideoFormat format, guint width, guint height, + guint surface_allocation_flags); + +GstVaapiSurface * +gst_vaapi_surface_new_from_buffer_proxy (GstVaapiDisplay * display, + GstVaapiBufferProxy * proxy, const GstVideoInfo * vip); + +GstVaapiID +gst_vaapi_surface_get_id (GstVaapiSurface * surface); + +GstVaapiChromaType +gst_vaapi_surface_get_chroma_type (GstVaapiSurface * surface); + +GstVideoFormat +gst_vaapi_surface_get_format (GstVaapiSurface * surface); + +guint +gst_vaapi_surface_get_width (GstVaapiSurface * surface); + +guint +gst_vaapi_surface_get_height (GstVaapiSurface * surface); + +void +gst_vaapi_surface_get_size (GstVaapiSurface * surface, guint * width_ptr, + guint * height_ptr); + +GstVaapiImage * +gst_vaapi_surface_derive_image (GstVaapiSurface * surface); + +gboolean +gst_vaapi_surface_get_image (GstVaapiSurface * surface, GstVaapiImage * image); + +gboolean +gst_vaapi_surface_put_image (GstVaapiSurface * surface, GstVaapiImage * image); + +gboolean +gst_vaapi_surface_associate_subpicture (GstVaapiSurface * surface, + GstVaapiSubpicture * subpicture, const GstVaapiRectangle * src_rect, + const GstVaapiRectangle * dst_rect); + +gboolean +gst_vaapi_surface_deassociate_subpicture (GstVaapiSurface * surface, + GstVaapiSubpicture * subpicture); + +gboolean +gst_vaapi_surface_sync (GstVaapiSurface * surface); + +gboolean +gst_vaapi_surface_query_status (GstVaapiSurface * surface, + GstVaapiSurfaceStatus * pstatus); + +gboolean +gst_vaapi_surface_set_subpictures_from_composition (GstVaapiSurface * surface, + GstVideoOverlayComposition * composition); + +void +gst_vaapi_surface_set_buffer_proxy (GstVaapiSurface * surface, + GstVaapiBufferProxy * proxy); + +GstVaapiBufferProxy * +gst_vaapi_surface_peek_buffer_proxy (GstVaapiSurface * surface); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiSurface, gst_vaapi_surface_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_SURFACE_H */ diff --git a/gst-libs/gst/vaapi/gstvaapisurface_drm.c b/gst-libs/gst/vaapi/gstvaapisurface_drm.c new file mode 100644 index 0000000000..833c6ac51b --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapisurface_drm.c @@ -0,0 +1,215 @@ +/* + * gstvaapisurface_drm.c - VA surface abstraction (DRM interop) + * + * Copyright (C) 2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include "gstvaapisurface_drm.h" +#include "gstvaapisurface_priv.h" +#include "gstvaapiimage_priv.h" +#include "gstvaapibufferproxy_priv.h" + +static GstVaapiBufferProxy * +gst_vaapi_surface_get_drm_buf_handle (GstVaapiSurface * surface, guint type) +{ + GstVaapiBufferProxy *proxy; + GstVaapiImage *image; + + image = gst_vaapi_surface_derive_image (surface); + if (!image) + goto error_derive_image; + + /* The proxy takes ownership if the image, even creation failure. */ + proxy = + gst_vaapi_buffer_proxy_new_from_surface (GST_MINI_OBJECT_CAST (surface), + image->internal_image.buf, type, (GDestroyNotify) gst_vaapi_image_unref, + image); + if (!proxy) + goto error_alloc_export_buffer; + return proxy; + + /* ERRORS */ +error_derive_image: + { + GST_ERROR ("failed to extract image handle from surface"); + return NULL; + } +error_alloc_export_buffer: + { + GST_ERROR ("failed to allocate export buffer proxy"); + return NULL; + } +} + +/** + * gst_vaapi_surface_peek_dma_buf_handle: + * @surface: a #GstVaapiSurface + * + * If the underlying VA driver implementation supports it, this + * function allows for returning a suitable dma_buf (DRM) buffer + * handle as a #GstVaapiBufferProxy instance. The returned buffer + * proxy does not increase the ref of underlying buffer proxy. + * + * Return value: the underlying buffer as a #GstVaapiBufferProxy + * instance. + */ +GstVaapiBufferProxy * +gst_vaapi_surface_peek_dma_buf_handle (GstVaapiSurface * surface) +{ + GstVaapiBufferProxy *buf_proxy; + + g_return_val_if_fail (surface != NULL, NULL); + + if (surface->extbuf_proxy) + return surface->extbuf_proxy; + + buf_proxy = gst_vaapi_surface_get_drm_buf_handle (surface, + GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF); + + if (buf_proxy) { + gst_vaapi_surface_set_buffer_proxy (surface, buf_proxy); + gst_vaapi_buffer_proxy_unref (buf_proxy); + } + + return buf_proxy; +} + +/** + * gst_vaapi_surface_peek_gem_buf_handle: + * @surface: a #GstVaapiSurface + * + * If the underlying VA driver implementation supports it, this + * function allows for returning a suitable GEM buffer handle as a + * #GstVaapiBufferProxy instance. The returned buffer proxy does + * not increase the ref of underlying buffer proxy. + * + * Return value: the underlying buffer as a #GstVaapiBufferProxy + * instance. + */ +GstVaapiBufferProxy * +gst_vaapi_surface_peek_gem_buf_handle (GstVaapiSurface * surface) +{ + GstVaapiBufferProxy *buf_proxy; + + g_return_val_if_fail (surface != NULL, NULL); + + if (surface->extbuf_proxy) + return surface->extbuf_proxy; + + buf_proxy = gst_vaapi_surface_get_drm_buf_handle (surface, + GST_VAAPI_BUFFER_MEMORY_TYPE_GEM_BUF); + + if (buf_proxy) { + gst_vaapi_surface_set_buffer_proxy (surface, buf_proxy); + gst_vaapi_buffer_proxy_unref (buf_proxy); + } + + return buf_proxy; +} + +static void +fill_video_info (GstVideoInfo * vip, GstVideoFormat format, guint width, + guint height, gsize offset[GST_VIDEO_MAX_PLANES], + gint stride[GST_VIDEO_MAX_PLANES]) +{ + guint i; + + gst_video_info_set_format (vip, format, width, height); + for (i = 0; i < GST_VIDEO_INFO_N_PLANES (vip); i++) { + GST_VIDEO_INFO_PLANE_OFFSET (vip, i) = offset[i]; + GST_VIDEO_INFO_PLANE_STRIDE (vip, i) = stride[i]; + } +} + +/** + * gst_vaapi_surface_new_with_dma_buf_handle: + * @display: a #GstVaapiDisplay + * @fd: the DRM PRIME file descriptor + * @size: the underlying DRM buffer size + * @format: the desired surface format + * @width: the desired surface width in pixels + * @height: the desired surface height in pixels + * @offset: the offsets to each plane + * @stride: the pitches for each plane + * + * Creates a new #GstVaapiSurface with an external DRM PRIME file + * descriptor. The newly created VA surfaces owns the supplied buffer + * handle. + * + * Return value: the newly allocated #GstVaapiSurface object, or %NULL + * if creation from DRM PRIME fd failed, or is not supported + */ +GstVaapiSurface * +gst_vaapi_surface_new_with_dma_buf_handle (GstVaapiDisplay * display, gint fd, + GstVideoInfo * vi) +{ + GstVaapiBufferProxy *proxy; + GstVaapiSurface *surface; + + proxy = gst_vaapi_buffer_proxy_new ((gintptr) fd, + GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF, GST_VIDEO_INFO_SIZE (vi), NULL, + NULL); + if (!proxy) + return NULL; + + surface = gst_vaapi_surface_new_from_buffer_proxy (display, proxy, vi); + /* Surface holds proxy's reference */ + gst_vaapi_buffer_proxy_unref (proxy); + return surface; +} + +/** + * gst_vaapi_surface_new_with_gem_buf_handle: + * @display: a #GstVaapiDisplay + * @name: the DRM GEM buffer name + * @size: the underlying DRM buffer size + * @format: the desired surface format + * @width: the desired surface width in pixels + * @height: the desired surface height in pixels + * @offset: the offsets to each plane + * @stride: the pitches for each plane + * + * Creates a new #GstVaapiSurface with an external DRM GEM buffer + * name. The newly created VA surfaces owns the supplied buffer + * handle. + * + * Return value: the newly allocated #GstVaapiSurface object, or %NULL + * if creation from GEM @name failed, or is not supported + */ +GstVaapiSurface * +gst_vaapi_surface_new_with_gem_buf_handle (GstVaapiDisplay * display, + guint32 name, guint size, GstVideoFormat format, guint width, guint height, + gsize offset[GST_VIDEO_MAX_PLANES], gint stride[GST_VIDEO_MAX_PLANES]) +{ + GstVaapiBufferProxy *proxy; + GstVaapiSurface *surface; + GstVideoInfo vi; + + proxy = gst_vaapi_buffer_proxy_new ((guintptr) name, + GST_VAAPI_BUFFER_MEMORY_TYPE_GEM_BUF, size, NULL, NULL); + if (!proxy) + return NULL; + + fill_video_info (&vi, format, width, height, offset, stride); + surface = gst_vaapi_surface_new_from_buffer_proxy (display, proxy, &vi); + /* Surface holds proxy's reference */ + gst_vaapi_buffer_proxy_unref (proxy); + return surface; +} diff --git a/gst-libs/gst/vaapi/gstvaapisurface_drm.h b/gst-libs/gst/vaapi/gstvaapisurface_drm.h new file mode 100644 index 0000000000..0bc5f846b3 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapisurface_drm.h @@ -0,0 +1,48 @@ +/* + * gstvaapisurface_drm.h - VA surface abstraction (DRM interop) + * + * Copyright (C) 2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_SURFACE_DRM_H +#define GST_VAAPI_SURFACE_DRM_H + +#include +#include + +G_BEGIN_DECLS + +GstVaapiBufferProxy * +gst_vaapi_surface_peek_dma_buf_handle (GstVaapiSurface * surface); + +GstVaapiBufferProxy * +gst_vaapi_surface_peek_gem_buf_handle (GstVaapiSurface * surface); + +GstVaapiSurface * +gst_vaapi_surface_new_with_dma_buf_handle (GstVaapiDisplay * display, gint fd, + GstVideoInfo * vi); + +GstVaapiSurface * +gst_vaapi_surface_new_with_gem_buf_handle (GstVaapiDisplay * display, + guint32 name, guint size, GstVideoFormat format, guint width, guint height, + gsize offset[GST_VIDEO_MAX_PLANES], gint stride[GST_VIDEO_MAX_PLANES]); + +G_END_DECLS + +#endif /* GST_VAAPI_SURFACE_DRM_H */ diff --git a/gst-libs/gst/vaapi/gstvaapisurface_egl.c b/gst-libs/gst/vaapi/gstvaapisurface_egl.c new file mode 100644 index 0000000000..362ac168c0 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapisurface_egl.c @@ -0,0 +1,353 @@ +/* + * gstvaapisurface_egl.c - VA surface abstraction (EGL interop) + * + * Copyright (C) 2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" + +#include "gstvaapisurface_egl.h" + +#include "gstvaapibufferproxy_priv.h" +#include "gstvaapicompat.h" +#include "gstvaapidisplay_egl_priv.h" +#include "gstvaapifilter.h" +#include "gstvaapiimage_priv.h" +#include "gstvaapisurface_drm.h" +#include "gstvaapisurface_priv.h" + +#if USE_DRM +#include +#else +#define DRM_FORMAT_MOD_LINEAR 0ULL +#define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1) +#endif + +typedef struct +{ + GstVaapiDisplayEGL *display; + EGLImageKHR image; + GstVideoFormat format; + guint width; + guint height; + guint mem_types; + GstVaapiSurface *surface; /* result */ +} CreateSurfaceWithEGLImageArgs; + +static GstVaapiSurface * +do_create_surface_with_egl_image_unlocked (GstVaapiDisplayEGL * display, + EGLImageKHR image, GstVideoFormat format, guint width, guint height, + guint mem_types) +{ + GstVaapiDisplay *const base_display = GST_VAAPI_DISPLAY_CAST (display); + EglContext *const ctx = GST_VAAPI_DISPLAY_EGL_CONTEXT (display); + EglVTable *vtable; + + if (!ctx || !(vtable = egl_context_get_vtable (ctx, FALSE))) + return NULL; + + if ((mem_types & VA_SURFACE_ATTRIB_MEM_TYPE_KERNEL_DRM) + && vtable->has_EGL_MESA_drm_image) { + gsize size, offset[GST_VIDEO_MAX_PLANES] = { 0, }; + gint name, stride[GST_VIDEO_MAX_PLANES] = { 0, }; + + /* EGL_MESA_drm_image extension */ + if (!vtable->eglExportDRMImageMESA (ctx->display->base.handle.p, image, + &name, NULL, &stride[0])) + goto error_export_image_gem_buf; + + size = height * stride[0]; + /* + * XXX: The below surface creation may fail on Intel due to: + * https://github.com/01org/intel-vaapi-driver/issues/222 + * A permanent fix for that problem will be released in intel-vaapi-driver + * version 1.8.4 and later, and also in 1.8.3-1ubuntu1. + * However if you don't have that fix then a simple workaround is to + * uncomment this line of code: + * size = GST_ROUND_UP_32 (height) * stride[0]; + */ + + return gst_vaapi_surface_new_with_gem_buf_handle (base_display, name, size, + format, width, height, offset, stride); + } + + if ((mem_types & VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME) + && vtable->has_EGL_MESA_image_dma_buf_export) { + int fourcc, num_planes, fd; + EGLint offset = 0; + EGLint stride = 0; + EGLuint64KHR modifier; + GstVideoInfo vi; + + if (!vtable->eglExportDMABUFImageQueryMESA (ctx->display->base.handle.p, + image, &fourcc, &num_planes, &modifier)) + goto error_export_dma_buf_image_query; + + /* Don't allow multi-plane dmabufs */ + if (num_planes != 1) + goto error_bad_parameters; + + /* FIXME: We don't support modifiers */ + if (modifier != DRM_FORMAT_MOD_LINEAR && modifier != DRM_FORMAT_MOD_INVALID) + goto error_bad_parameters; + + /* fix color format if needed */ + if (fourcc == GST_MAKE_FOURCC ('A', 'B', '2', '4')) + format = gst_vaapi_video_format_from_va_fourcc (VA_FOURCC_RGBA); + else if (fourcc == GST_MAKE_FOURCC ('A', 'R', '2', '4')) + format = gst_vaapi_video_format_from_va_fourcc (VA_FOURCC_BGRA); + + if (!vtable->eglExportDMABUFImageMESA (ctx->display->base.handle.p, image, + &fd, &stride, &offset)) + goto error_export_dma_buf_image; + + gst_video_info_set_format (&vi, format, width, height); + GST_VIDEO_INFO_PLANE_OFFSET (&vi, 0) = offset; + GST_VIDEO_INFO_PLANE_STRIDE (&vi, 0) = stride; + + return gst_vaapi_surface_new_with_dma_buf_handle (base_display, fd, &vi); + } +#ifndef GST_DISABLE_GST_DEBUG + { + GString *str = g_string_new (NULL); + + if (mem_types & VA_SURFACE_ATTRIB_MEM_TYPE_VA) + g_string_append (str, "VA "); + if (mem_types & VA_SURFACE_ATTRIB_MEM_TYPE_V4L2) + g_string_append (str, "V4L2 "); + if (mem_types & VA_SURFACE_ATTRIB_MEM_TYPE_USER_PTR) + g_string_append (str, "PTR "); +#if VA_CHECK_VERSION(1,1,0) + if (mem_types & VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2) + g_string_append (str, "PRIME_2 "); +#endif + + GST_ERROR ("missing EGL extensions for memory types: %s", str->str); + g_string_free (str, TRUE); + } +#endif + + return NULL; + + /* ERRORS */ +error_export_image_gem_buf: + { + GST_ERROR ("failed to export EGL image to GEM buffer"); + return NULL; + } +error_export_dma_buf_image_query: + { + GST_ERROR ("failed to query EGL image for dmabuf export"); + return NULL; + } +error_bad_parameters: + { + GST_ERROR ("multi-planed nor non-linear dmabufs are not supported"); + return NULL; + } +error_export_dma_buf_image: + { + GST_ERROR ("missing EGL_MESA_image_dma_buf_export extension"); + return NULL; + } +} + +static void +do_create_surface_with_egl_image (CreateSurfaceWithEGLImageArgs * args) +{ + GST_VAAPI_DISPLAY_LOCK (args->display); + args->surface = do_create_surface_with_egl_image_unlocked (args->display, + args->image, args->format, args->width, args->height, args->mem_types); + GST_VAAPI_DISPLAY_UNLOCK (args->display); +} + +// Creates VA surface with EGLImage buffer as backing storage (internal) +static inline GstVaapiSurface * +create_surface_with_egl_image (GstVaapiDisplayEGL * display, EGLImageKHR image, + GstVideoFormat format, guint width, guint height, guint mem_types) +{ + CreateSurfaceWithEGLImageArgs args = + { display, image, format, width, height, mem_types }; + + if (!egl_context_run (GST_VAAPI_DISPLAY_EGL_CONTEXT (display), + (EglContextRunFunc) do_create_surface_with_egl_image, &args)) + return NULL; + return args.surface; +} + +// Creates VA surface from an EGLImage buffer copy (internal) +static GstVaapiSurface * +create_surface_from_egl_image (GstVaapiDisplayEGL * display, + const GstVideoInfo * vip, EGLImageKHR image, GstVideoFormat format, + guint width, guint height, guint flags) +{ + GstVaapiDisplay *const base_display = GST_VAAPI_DISPLAY_CAST (display); + GstVaapiSurface *img_surface = NULL, *out_surface = NULL; + gboolean use_native_format = TRUE; + GstVaapiFilter *filter = NULL; + GstVaapiFilterStatus filter_status; + + img_surface = create_surface_with_egl_image (display, image, format, + width, height, 0); + if (!img_surface) + return NULL; + + if (vip) { + use_native_format = + GST_VIDEO_INFO_FORMAT (vip) == GST_VIDEO_FORMAT_ENCODED || + GST_VIDEO_INFO_FORMAT (vip) == GST_VIDEO_FORMAT_UNKNOWN; + + if (GST_VIDEO_INFO_WIDTH (vip) && GST_VIDEO_INFO_HEIGHT (vip)) { + width = GST_VIDEO_INFO_WIDTH (vip); + height = GST_VIDEO_INFO_HEIGHT (vip); + } + } + + if (use_native_format) { + out_surface = gst_vaapi_surface_new (base_display, + GST_VAAPI_CHROMA_TYPE_YUV420, width, height); + } else { + out_surface = gst_vaapi_surface_new_with_format (base_display, + GST_VIDEO_INFO_FORMAT (vip), width, height, 0); + } + if (!out_surface) + goto error_create_surface; + + filter = gst_vaapi_filter_new (base_display); + if (!filter) + goto error_create_filter; + + filter_status = gst_vaapi_filter_process (filter, + img_surface, out_surface, flags); + if (filter_status != GST_VAAPI_FILTER_STATUS_SUCCESS) + goto error_convert_surface; + + gst_vaapi_surface_unref (img_surface); + gst_object_unref (filter); + return out_surface; + + /* ERRORS */ +error_create_surface: + GST_ERROR ("failed to create output surface format:%s size:%dx%d", + gst_vaapi_video_format_to_string (vip ? GST_VIDEO_INFO_FORMAT (vip) : + GST_VIDEO_FORMAT_ENCODED), width, height); + goto error_cleanup; +error_convert_surface: + GST_ERROR ("failed to transfer EGL image to VA surface (status = %d)", + filter_status); + goto error_cleanup; +error_create_filter: + GST_ERROR ("failed to create video processing filter"); + // fall-through +error_cleanup: + gst_mini_object_replace ((GstMiniObject **) & img_surface, NULL); + gst_mini_object_replace ((GstMiniObject **) & out_surface, NULL); + gst_vaapi_filter_replace (&filter, NULL); + return NULL; +} + +/** + * gst_vaapi_surface_new_from_egl_image: + * @display: a #GstVaapiDisplay + * @vip: the desired (optional) #GstVideoInfo constraints + * @image: the EGL image to import + * @format: the EGL @image format + * @width: the EGL @image width in pixels + * @height: the EGL @image height in pixels + * @flags: postprocessing flags. See #GstVaapiSurfaceRenderFlags + * + * Creates a new #GstVaapiSurface with a copy of the EGL image + * contents. i.e. the input EGL @image can be disposed and the + * resulting VA surface would still be valid with the contents at the + * time this function was called. + * + * If @vip is %NULL, then the resulting VA surface will be created + * with the same video format and size as the original @image. If @vip + * is non-%NULL and the desired format is GST_VIDEO_FORMAT_ENCODED, + * then the resulting VA surface will have the best "native" HW + * format, usually NV12. + * + * Return value: the newly allocated #GstVaapiSurface object, or %NULL + * if creation from EGL image failed, or is not supported + */ +GstVaapiSurface * +gst_vaapi_surface_new_from_egl_image (GstVaapiDisplay * base_display, + const GstVideoInfo * vip, EGLImageKHR image, GstVideoFormat format, + guint width, guint height, guint flags) +{ + GstVaapiDisplayEGL *display; + + g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_EGL (base_display), NULL); + g_return_val_if_fail (image != EGL_NO_IMAGE_KHR, NULL); + g_return_val_if_fail (width > 0, NULL); + g_return_val_if_fail (height > 0, NULL); + + display = GST_VAAPI_DISPLAY_EGL (base_display); + if (!display || !GST_VAAPI_IS_DISPLAY_EGL (display)) + goto error_invalid_display; + return create_surface_from_egl_image (display, vip, image, format, + width, height, flags); + + /* ERRORS */ +error_invalid_display: + GST_ERROR ("invalid display (NULL or not of EGL class"); + return NULL; +} + +/** + * gst_vaapi_surface_new_with_egl_image: + * @display: a #GstVaapiDisplay + * @image: the EGL image to import + * @format: the EGL @image format + * @width: the EGL @image width in pixels + * @height: the EGL @image height in pixels + * @mem_types: the supported memory types + * + * Creates a new #GstVaapiSurface bound to an external EGL image. + * + * The caller maintains the lifetime of the EGL image object. In + * particular, the EGL image shall not be destroyed before the last + * reference to the resulting VA surface is released. + * + * Return value: the newly allocated #GstVaapiSurface object, or %NULL + * if creation from EGL image failed, or is not supported + */ +GstVaapiSurface * +gst_vaapi_surface_new_with_egl_image (GstVaapiDisplay * base_display, + EGLImageKHR image, GstVideoFormat format, guint width, guint height, + guint mem_types) +{ + GstVaapiDisplayEGL *display; + + g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_EGL (base_display), NULL); + g_return_val_if_fail (image != EGL_NO_IMAGE_KHR, NULL); + g_return_val_if_fail (width > 0, NULL); + g_return_val_if_fail (height > 0, NULL); + + display = GST_VAAPI_DISPLAY_EGL (base_display); + if (!display || !GST_VAAPI_IS_DISPLAY_EGL (display)) + goto error_invalid_display; + return create_surface_with_egl_image (display, image, format, width, height, + mem_types); + + /* ERRORS */ +error_invalid_display: + GST_ERROR ("invalid display (NULL or not of EGL class"); + return NULL; +} diff --git a/gst-libs/gst/vaapi/gstvaapisurface_egl.h b/gst-libs/gst/vaapi/gstvaapisurface_egl.h new file mode 100644 index 0000000000..71cb150aff --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapisurface_egl.h @@ -0,0 +1,44 @@ +/* + * gstvaapisurface_egl.h - VA surface abstraction (EGL interop) + * + * Copyright (C) 2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_SURFACE_EGL_H +#define GST_VAAPI_SURFACE_EGL_H + +#include +#include +#include + +G_BEGIN_DECLS + +GstVaapiSurface * +gst_vaapi_surface_new_from_egl_image (GstVaapiDisplay * display, + const GstVideoInfo * vip, EGLImageKHR image, GstVideoFormat format, + guint width, guint height, guint flags); + +GstVaapiSurface * +gst_vaapi_surface_new_with_egl_image (GstVaapiDisplay * display, + EGLImageKHR image, GstVideoFormat format, guint width, guint height, + guint mem_types); + +G_END_DECLS + +#endif /* GST_VAAPI_SURFACE_EGL_H */ diff --git a/gst-libs/gst/vaapi/gstvaapisurface_priv.h b/gst-libs/gst/vaapi/gstvaapisurface_priv.h new file mode 100644 index 0000000000..f0e8ce78fc --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapisurface_priv.h @@ -0,0 +1,124 @@ +/* + * gstvaapisurface_priv.h - VA surface abstraction (private data) + * + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_SURFACE_PRIV_H +#define GST_VAAPI_SURFACE_PRIV_H + +#include + +G_BEGIN_DECLS + +/** + * GstVaapiSurface: + * + * A VA surface wrapper. + */ +struct _GstVaapiSurface +{ + /*< private >*/ + GstMiniObject mini_object; + GstVaapiDisplay *display; + GstVaapiID object_id; + + GstVaapiBufferProxy *extbuf_proxy; + GstVideoFormat format; + guint width; + guint height; + GstVaapiChromaType chroma_type; + GPtrArray *subpictures; +}; + +/** + * GST_VAAPI_SURFACE_DISPLAY: + * @surface: a #GstVaapiSurface + * + * Macro that evaluates to the @surface's display. + * + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_SURFACE_DISPLAY +#define GST_VAAPI_SURFACE_DISPLAY(surface) \ + (GST_VAAPI_SURFACE (surface)->display) + +/** + * GST_VAAPI_SURFACE_ID: + * @surface: a #GstVaapiSurface + * + * Macro that evaluates to the @surface's ID. + * + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_SURFACE_ID +#define GST_VAAPI_SURFACE_ID(surface) \ + (GST_VAAPI_SURFACE (surface)->object_id) + +/** + * GST_VAAPI_SURFACE_CHROMA_TYPE: + * @surface: a #GstVaapiSurface + * + * Macro that evaluates to the @surface chroma type. + * + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_SURFACE_CHROMA_TYPE +#define GST_VAAPI_SURFACE_CHROMA_TYPE(surface) \ + (GST_VAAPI_SURFACE (surface)->chroma_type) + +/** + * GST_VAAPI_SURFACE_FORMAT: + * @surface: a #GstVaapiSurface + * + * Macro that evaluates to the @surface format. + * + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_SURFACE_FORMAT +#define GST_VAAPI_SURFACE_FORMAT(surface) \ + (GST_VAAPI_SURFACE (surface)->format) + +/** + * GST_VAAPI_SURFACE_WIDTH: + * @surface: a #GstVaapiSurface + * + * Macro that evaluates to the @surface width in pixels. + * + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_SURFACE_WIDTH +#define GST_VAAPI_SURFACE_WIDTH(surface) \ + (GST_VAAPI_SURFACE (surface)->width) + +/** + * GST_VAAPI_SURFACE_HEIGHT: + * @surface: a #GstVaapiSurface + * + * Macro that evaluates to the @surface height in pixels. + * + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_SURFACE_HEIGHT +#define GST_VAAPI_SURFACE_HEIGHT(surface) \ + (GST_VAAPI_SURFACE (surface)->height) + +G_END_DECLS + +#endif /* GST_VAAPI_SURFACE_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapisurfacepool.c b/gst-libs/gst/vaapi/gstvaapisurfacepool.c new file mode 100644 index 0000000000..5ad85f0e53 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapisurfacepool.c @@ -0,0 +1,212 @@ +/* + * gstvaapisurfacepool.c - Gst VA surface pool + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapisurfacepool + * @short_description: VA surface pool + */ + +#include "sysdeps.h" +#include "gstvaapisurfacepool.h" +#include "gstvaapivideopool_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +/** + * GstVaapiSurfacePool: + * + * A pool of lazily allocated #GstVaapiSurface objects. + */ +struct _GstVaapiSurfacePool +{ + /*< private > */ + GstVaapiVideoPool parent_instance; + + GstVaapiChromaType chroma_type; + GstVideoInfo video_info; + guint alloc_flags; +}; + +static gboolean +surface_pool_init (GstVaapiSurfacePool * pool, const GstVideoInfo * vip, + guint surface_allocation_flags) +{ + const GstVideoFormat format = GST_VIDEO_INFO_FORMAT (vip); + + pool->video_info = *vip; + pool->alloc_flags = surface_allocation_flags; + + if (format == GST_VIDEO_FORMAT_UNKNOWN) + return FALSE; + + if (format == GST_VIDEO_FORMAT_ENCODED) + pool->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420; + else + pool->chroma_type = gst_vaapi_video_format_get_chroma_type (format); + if (!pool->chroma_type) + return FALSE; + return TRUE; +} + +static gpointer +gst_vaapi_surface_pool_alloc_object (GstVaapiVideoPool * base_pool) +{ + GstVaapiSurfacePool *const pool = GST_VAAPI_SURFACE_POOL (base_pool); + + /* Try to allocate a surface with an explicit pixel format first */ + if (GST_VIDEO_INFO_FORMAT (&pool->video_info) != GST_VIDEO_FORMAT_ENCODED) { + GstVaapiSurface *const surface = + gst_vaapi_surface_new_full (base_pool->display, &pool->video_info, + pool->alloc_flags); + if (surface) + return surface; + } + + /* Otherwise, fallback to the original interface, based on chroma format */ + return gst_vaapi_surface_new (base_pool->display, + pool->chroma_type, GST_VIDEO_INFO_WIDTH (&pool->video_info), + GST_VIDEO_INFO_HEIGHT (&pool->video_info)); +} + +static inline const GstVaapiMiniObjectClass * +gst_vaapi_surface_pool_class (void) +{ + static const GstVaapiVideoPoolClass GstVaapiSurfacePoolClass = { + {sizeof (GstVaapiSurfacePool), + (GDestroyNotify) gst_vaapi_video_pool_finalize} + , + .alloc_object = gst_vaapi_surface_pool_alloc_object + }; + return GST_VAAPI_MINI_OBJECT_CLASS (&GstVaapiSurfacePoolClass); +} + +/** + * gst_vaapi_surface_pool_new: + * @display: a #GstVaapiDisplay + * @format: a #GstVideoFormat + * @width: the desired width, in pixels + * @height: the desired height, in pixels + * @surface_allocation_flags: (optional) allocation flags + * + * Creates a new #GstVaapiVideoPool of #GstVaapiSurface with the specified + * format and dimensions. If @format is GST_VIDEO_FORMAT_ENCODED, then + * surfaces with best "native" format would be created. Typically, this is + * NV12 format, but this is implementation (driver) defined. + * + * Return value: the newly allocated #GstVaapiVideoPool + */ +GstVaapiVideoPool * +gst_vaapi_surface_pool_new (GstVaapiDisplay * display, GstVideoFormat format, + guint width, guint height, guint surface_allocation_flags) +{ + GstVideoInfo vi; + + g_return_val_if_fail (display != NULL, NULL); + g_return_val_if_fail (width > 0, NULL); + g_return_val_if_fail (height > 0, NULL); + + gst_video_info_set_format (&vi, format, width, height); + return gst_vaapi_surface_pool_new_full (display, &vi, + surface_allocation_flags); +} + +/** + * gst_vaapi_surface_pool_new_full: + * @display: a #GstVaapiDisplay + * @vip: a #GstVideoInfo + * @surface_allocation_flags: (optional) allocation flags + * + * Creates a new #GstVaapiVideoPool of #GstVaapiSurface with the + * specified format and dimensions in @vip. + * + * Return value: the newly allocated #GstVaapiVideoPool + */ +GstVaapiVideoPool * +gst_vaapi_surface_pool_new_full (GstVaapiDisplay * display, + const GstVideoInfo * vip, guint surface_allocation_flags) +{ + GstVaapiVideoPool *pool; + + g_return_val_if_fail (display != NULL, NULL); + g_return_val_if_fail (vip != NULL, NULL); + + pool = (GstVaapiVideoPool *) + gst_vaapi_mini_object_new (gst_vaapi_surface_pool_class ()); + if (!pool) + return NULL; + + gst_vaapi_video_pool_init (pool, display, + GST_VAAPI_VIDEO_POOL_OBJECT_TYPE_SURFACE); + if (!surface_pool_init (GST_VAAPI_SURFACE_POOL (pool), vip, + surface_allocation_flags)) + goto error; + return pool; + + /* ERRORS */ +error: + { + gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (pool)); + return NULL; + } +} + +/** + * gst_vaapi_surface_pool_new_with_chroma_type: + * @display: a #GstVaapiDisplay + * @chroma_type: a #GstVaapiChromatype + * @width: the desired width, in pixels + * @height: the desired height, in pixels + * @surface_allocation_flags: (optional) allocation flags + * + * Creates a new #GstVaapiVideoPool of #GstVaapiSurface with the specified + * chroma type and dimensions. The underlying format of the surfaces is + * implementation (driver) defined. + * + * Return value: the newly allocated #GstVaapiVideoPool + */ +GstVaapiVideoPool * +gst_vaapi_surface_pool_new_with_chroma_type (GstVaapiDisplay * display, + GstVaapiChromaType chroma_type, guint width, guint height, + guint surface_allocation_flags) +{ + GstVaapiVideoPool *pool; + GstVideoInfo vi; + + g_return_val_if_fail (display != NULL, NULL); + g_return_val_if_fail (chroma_type > 0, NULL); + g_return_val_if_fail (width > 0, NULL); + g_return_val_if_fail (height > 0, NULL); + + gst_video_info_set_format (&vi, GST_VIDEO_FORMAT_ENCODED, width, height); + + pool = + gst_vaapi_surface_pool_new_full (display, &vi, surface_allocation_flags); + if (!pool) + return NULL; + + GST_VAAPI_SURFACE_POOL (pool)->chroma_type = chroma_type; + + return pool; +} diff --git a/gst-libs/gst/vaapi/gstvaapisurfacepool.h b/gst-libs/gst/vaapi/gstvaapisurfacepool.h new file mode 100644 index 0000000000..1fa7fe1b2e --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapisurfacepool.h @@ -0,0 +1,54 @@ +/* + * gstvaapisurfacepool.h - Gst VA surface pool + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_SURFACE_POOL_H +#define GST_VAAPI_SURFACE_POOL_H + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_SURFACE_POOL(obj) \ + ((GstVaapiSurfacePool *)(obj)) + +typedef struct _GstVaapiSurfacePool GstVaapiSurfacePool; + +GstVaapiVideoPool * +gst_vaapi_surface_pool_new (GstVaapiDisplay * display, GstVideoFormat format, + guint width, guint height, guint surface_allocation_flags); + +GstVaapiVideoPool * +gst_vaapi_surface_pool_new_full (GstVaapiDisplay * display, + const GstVideoInfo * vip, guint surface_allocation_flags); + +GstVaapiVideoPool * +gst_vaapi_surface_pool_new_with_chroma_type (GstVaapiDisplay * display, + GstVaapiChromaType chroma_type, guint width, guint height, + guint surface_allocation_flags); + +G_END_DECLS + +#endif /* GST_VAAPI_SURFACE_POOL_H */ diff --git a/gst-libs/gst/vaapi/gstvaapisurfaceproxy.c b/gst-libs/gst/vaapi/gstvaapisurfaceproxy.c new file mode 100644 index 0000000000..729efeb4ef --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapisurfaceproxy.c @@ -0,0 +1,407 @@ +/* + * gstvaapisurfaceproxy.c - VA surface proxy + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapisurfaceproxy + * @short_description: VA surface proxy + */ + +#include "sysdeps.h" +#include "gstvaapisurfaceproxy.h" +#include "gstvaapisurfaceproxy_priv.h" +#include "gstvaapivideopool_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +static void +gst_vaapi_surface_proxy_finalize (GstVaapiSurfaceProxy * proxy) +{ + if (proxy->surface) { + if (proxy->pool && !proxy->parent) + gst_vaapi_video_pool_put_object (proxy->pool, proxy->surface); + gst_vaapi_surface_unref (proxy->surface); + proxy->surface = NULL; + } + gst_vaapi_video_pool_replace (&proxy->pool, NULL); + gst_vaapi_surface_proxy_replace (&proxy->parent, NULL); + + /* Notify the user function that the object is now destroyed */ + if (proxy->destroy_func) + proxy->destroy_func (proxy->destroy_data); +} + +static inline const GstVaapiMiniObjectClass * +gst_vaapi_surface_proxy_class (void) +{ + static const GstVaapiMiniObjectClass GstVaapiSurfaceProxyClass = { + sizeof (GstVaapiSurfaceProxy), + (GDestroyNotify) gst_vaapi_surface_proxy_finalize + }; + return &GstVaapiSurfaceProxyClass; +} + +static void +gst_vaapi_surface_proxy_init_properties (GstVaapiSurfaceProxy * proxy) +{ + proxy->view_id = 0; + proxy->timestamp = GST_CLOCK_TIME_NONE; + proxy->duration = GST_CLOCK_TIME_NONE; + proxy->has_crop_rect = FALSE; +} + +/** + * gst_vaapi_surface_proxy_new: + * @surface: a #GstVaapiSurface + * + * Creates a new #GstVaapiSurfaceProxy with the specified + * surface. This allows for transporting additional information that + * are not to be attached to the @surface directly. + * + * Return value: the newly allocated #GstVaapiSurfaceProxy object + */ +GstVaapiSurfaceProxy * +gst_vaapi_surface_proxy_new (GstVaapiSurface * surface) +{ + GstVaapiSurfaceProxy *proxy; + + g_return_val_if_fail (surface != NULL, NULL); + + proxy = (GstVaapiSurfaceProxy *) + gst_vaapi_mini_object_new (gst_vaapi_surface_proxy_class ()); + if (!proxy) + return NULL; + + proxy->parent = NULL; + proxy->destroy_func = NULL; + proxy->pool = NULL; + proxy->surface = + (GstVaapiSurface *) gst_mini_object_ref (GST_MINI_OBJECT_CAST (surface)); + if (!proxy->surface) + goto error; + gst_vaapi_surface_proxy_init_properties (proxy); + return proxy; + + /* ERRORS */ +error: + { + gst_vaapi_surface_proxy_unref (proxy); + return NULL; + } +} + +/** + * gst_vaapi_surface_proxy_new_from_pool: + * @pool: a #GstVaapiSurfacePool + * + * Allocates a new surface from the supplied surface @pool and creates + * the wrapped surface proxy object from it. When the last reference + * to the proxy object is released, then the underlying VA surface is + * pushed back to its parent pool. + * + * Returns: The same newly allocated @proxy object, or %NULL on error + */ +GstVaapiSurfaceProxy * +gst_vaapi_surface_proxy_new_from_pool (GstVaapiSurfacePool * pool) +{ + GstVaapiSurfaceProxy *proxy; + + g_return_val_if_fail (pool != NULL, NULL); + + proxy = (GstVaapiSurfaceProxy *) + gst_vaapi_mini_object_new (gst_vaapi_surface_proxy_class ()); + if (!proxy) + return NULL; + + proxy->parent = NULL; + proxy->destroy_func = NULL; + proxy->pool = gst_vaapi_video_pool_ref (GST_VAAPI_VIDEO_POOL (pool)); + proxy->surface = gst_vaapi_video_pool_get_object (proxy->pool); + if (!proxy->surface) + goto error; + gst_mini_object_ref (GST_MINI_OBJECT_CAST (proxy->surface)); + gst_vaapi_surface_proxy_init_properties (proxy); + return proxy; + + /* ERRORS */ +error: + { + gst_vaapi_surface_proxy_unref (proxy); + return NULL; + } +} + +/** + * gst_vaapi_surface_proxy_copy: + * @proxy: the parent #GstVaapiSurfaceProxy + * + * Creates are new VA surface proxy object from the supplied parent + * @proxy object with the same initial information, e.g. timestamp, + * duration. + * + * Note: the destroy notify function is not copied into the new + * surface proxy object. + * + * Returns: The same newly allocated @proxy object, or %NULL on error + */ +GstVaapiSurfaceProxy * +gst_vaapi_surface_proxy_copy (GstVaapiSurfaceProxy * proxy) +{ + GstVaapiSurfaceProxy *copy; + + g_return_val_if_fail (proxy != NULL, NULL); + + copy = (GstVaapiSurfaceProxy *) + gst_vaapi_mini_object_new (gst_vaapi_surface_proxy_class ()); + if (!copy) + return NULL; + + GST_VAAPI_SURFACE_PROXY_FLAGS (copy) = GST_VAAPI_SURFACE_PROXY_FLAGS (proxy); + + copy->parent = gst_vaapi_surface_proxy_ref (proxy->parent ? + proxy->parent : proxy); + copy->pool = proxy->pool ? gst_vaapi_video_pool_ref (proxy->pool) : NULL; + copy->surface = (GstVaapiSurface *) + gst_mini_object_ref (GST_MINI_OBJECT_CAST (proxy->surface)); + copy->view_id = proxy->view_id; + copy->timestamp = proxy->timestamp; + copy->duration = proxy->duration; + copy->destroy_func = NULL; + copy->has_crop_rect = proxy->has_crop_rect; + if (copy->has_crop_rect) + copy->crop_rect = proxy->crop_rect; + + return copy; +} + +/** + * gst_vaapi_surface_proxy_ref: + * @proxy: a #GstVaapiSurfaceProxy + * + * Atomically increases the reference count of the given @proxy by one. + * + * Returns: The same @proxy argument + */ +GstVaapiSurfaceProxy * +gst_vaapi_surface_proxy_ref (GstVaapiSurfaceProxy * proxy) +{ + g_return_val_if_fail (proxy != NULL, NULL); + + return + GST_VAAPI_SURFACE_PROXY (gst_vaapi_mini_object_ref (GST_VAAPI_MINI_OBJECT + (proxy))); +} + +/** + * gst_vaapi_surface_proxy_unref: + * @proxy: a #GstVaapiSurfaceProxy + * + * Atomically decreases the reference count of the @proxy by one. If + * the reference count reaches zero, the object will be free'd. + */ +void +gst_vaapi_surface_proxy_unref (GstVaapiSurfaceProxy * proxy) +{ + g_return_if_fail (proxy != NULL); + + gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (proxy)); +} + +/** + * gst_vaapi_surface_proxy_replace: + * @old_proxy_ptr: a pointer to a #GstVaapiSurfaceProxy + * @new_proxy: a #GstVaapiSurfaceProxy + * + * Atomically replaces the proxy object held in @old_proxy_ptr with + * @new_proxy. This means that @old_proxy_ptr shall reference a valid + * object. However, @new_proxy can be NULL. + */ +void +gst_vaapi_surface_proxy_replace (GstVaapiSurfaceProxy ** old_proxy_ptr, + GstVaapiSurfaceProxy * new_proxy) +{ + g_return_if_fail (old_proxy_ptr != NULL); + + gst_vaapi_mini_object_replace ((GstVaapiMiniObject **) old_proxy_ptr, + GST_VAAPI_MINI_OBJECT (new_proxy)); +} + +/** + * gst_vaapi_surface_proxy_get_surface: + * @proxy: a #GstVaapiSurfaceProxy + * + * Returns the #GstVaapiSurface stored in the @proxy. + * + * Return value: the #GstVaapiSurface + */ +GstVaapiSurface * +gst_vaapi_surface_proxy_get_surface (GstVaapiSurfaceProxy * proxy) +{ + g_return_val_if_fail (proxy != NULL, NULL); + + return GST_VAAPI_SURFACE_PROXY_SURFACE (proxy); +} + +/** + * gst_vaapi_surface_proxy_get_flags: + * @proxy: a #GstVaapiSurfaceProxy + * + * Returns the #GstVaapiSurfaceProxyFlags associated with this surface + * @proxy. + * + * Return value: the set of #GstVaapiSurfaceProxyFlags + */ +guint +gst_vaapi_surface_proxy_get_flags (GstVaapiSurfaceProxy * proxy) +{ + g_return_val_if_fail (proxy != NULL, 0); + + return GST_VAAPI_SURFACE_PROXY_FLAGS (proxy); +} + +/** + * gst_vaapi_surface_proxy_get_surface_id: + * @proxy: a #GstVaapiSurfaceProxy + * + * Returns the VA surface ID stored in the @proxy. + * + * Return value: the #GstVaapiID + */ +GstVaapiID +gst_vaapi_surface_proxy_get_surface_id (GstVaapiSurfaceProxy * proxy) +{ + g_return_val_if_fail (proxy != NULL, VA_INVALID_ID); + g_return_val_if_fail (proxy->surface != NULL, VA_INVALID_ID); + + return GST_VAAPI_SURFACE_PROXY_SURFACE_ID (proxy); +} + +/** + * gst_vaapi_surface_proxy_get_view_id: + * @proxy: a #GstVaapiSurfaceProxy + * + * Returns the decoded view-id stored in the @proxy. + * + * Return value: the #GstVaapiID + */ +guintptr +gst_vaapi_surface_proxy_get_view_id (GstVaapiSurfaceProxy * proxy) +{ + g_return_val_if_fail (proxy != NULL, 0); + + return GST_VAAPI_SURFACE_PROXY_VIEW_ID (proxy); +} + +/** + * gst_vaapi_surface_proxy_get_timestamp: + * @proxy: a #GstVaapiSurfaceProxy + * + * Returns the presentation timestamp for this surface @proxy. + * + * Return value: the presentation timestamp + */ +GstClockTime +gst_vaapi_surface_proxy_get_timestamp (GstVaapiSurfaceProxy * proxy) +{ + g_return_val_if_fail (proxy != NULL, 0); + + return GST_VAAPI_SURFACE_PROXY_TIMESTAMP (proxy); +} + +/** + * gst_vaapi_surface_proxy_get_duration: + * @proxy: a #GstVaapiSurfaceProxy + * + * Returns the presentation duration for this surface @proxy. + * + * Return value: the presentation duration + */ +GstClockTime +gst_vaapi_surface_proxy_get_duration (GstVaapiSurfaceProxy * proxy) +{ + g_return_val_if_fail (proxy != NULL, 0); + + return GST_VAAPI_SURFACE_PROXY_DURATION (proxy); +} + +/** + * gst_vaapi_surface_proxy_set_destroy_notify: + * @proxy: a @GstVaapiSurfaceProxy + * @destroy_func: a #GDestroyNotify function + * @user_data: some extra data to pass to the @destroy_func function + * + * Sets @destroy_func as the function to call when the surface @proxy + * was released. At this point, the proxy object is considered + * released, i.e. the underlying data storage is no longer valid and + * the callback function shall not expect anything from that. + */ +void +gst_vaapi_surface_proxy_set_destroy_notify (GstVaapiSurfaceProxy * proxy, + GDestroyNotify destroy_func, gpointer user_data) +{ + g_return_if_fail (proxy != NULL); + + proxy->destroy_func = destroy_func; + proxy->destroy_data = user_data; +} + +/** + * gst_vaapi_surface_proxy_get_crop_rect: + * @proxy: a #GstVaapiSurfaceProxy + * + * Returns the #GstVaapiRectangle stored in the @proxy and that + * represents the cropping rectangle for the underlying surface to be + * used for rendering. + * + * If no cropping rectangle was associated with the @proxy, then this + * function returns %NULL. + * + * Return value: the #GstVaapiRectangle, or %NULL if none was + * associated with the surface proxy + */ +const GstVaapiRectangle * +gst_vaapi_surface_proxy_get_crop_rect (GstVaapiSurfaceProxy * proxy) +{ + g_return_val_if_fail (proxy != NULL, NULL); + + return GST_VAAPI_SURFACE_PROXY_CROP_RECT (proxy); +} + +/** + * gst_vaapi_surface_proxy_set_crop_rect: + * @proxy: #GstVaapiSurfaceProxy + * @crop_rect: the #GstVaapiRectangle to be stored in @proxy + * + * Associates the @crop_rect with the @proxy + */ +void +gst_vaapi_surface_proxy_set_crop_rect (GstVaapiSurfaceProxy * proxy, + const GstVaapiRectangle * crop_rect) +{ + g_return_if_fail (proxy != NULL); + + proxy->has_crop_rect = crop_rect != NULL; + if (proxy->has_crop_rect) + proxy->crop_rect = *crop_rect; +} diff --git a/gst-libs/gst/vaapi/gstvaapisurfaceproxy.h b/gst-libs/gst/vaapi/gstvaapisurfaceproxy.h new file mode 100644 index 0000000000..1dc218c45d --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapisurfaceproxy.h @@ -0,0 +1,157 @@ +/* + * gstvaapisurfaceproxy.h - VA surface proxy + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_SURFACE_PROXY_H +#define GST_VAAPI_SURFACE_PROXY_H + +#include +#include + +G_BEGIN_DECLS + +/** + * GstVaapiSurfaceProxyFlags: + * @GST_VAAPI_SURFACE_PROXY_FLAG_INTERLACED: interlaced frame + * @GST_VAAPI_SURFACE_PROXY_FLAG_TFF: top-field-first + * @GST_VAAPI_SURFACE_PROXY_FLAG_RFF: repeat-first-field + * @GST_VAAPI_SURFACE_PROXY_FLAG_ONEFIELD: only one field is available + * @GST_VAAPI_SURFACE_PROXY_FLAG_FFB: first frame in bundle, e.g. the first + * view component of a MultiView Coded (MVC) frame + * @GST_VAAPI_SURFACE_PROXY_FLAG_CORRUPTED: the underlying surface is + * corrupted somehow, e.g. reconstructed from invalid references + * @GST_VAAPI_SURFACE_PROXY_FLAG_LAST: first flag that can be used by subclasses + * + * Flags for #GstVaapiDecoderFrame. + */ +typedef enum +{ + GST_VAAPI_SURFACE_PROXY_FLAG_INTERLACED = (1 << 0), + GST_VAAPI_SURFACE_PROXY_FLAG_TFF = (1 << 1), + GST_VAAPI_SURFACE_PROXY_FLAG_RFF = (1 << 2), + GST_VAAPI_SURFACE_PROXY_FLAG_ONEFIELD = (1 << 3), + GST_VAAPI_SURFACE_PROXY_FLAG_FFB = (1 << 4), + GST_VAAPI_SURFACE_PROXY_FLAG_CORRUPTED = (1 << 5), + GST_VAAPI_SURFACE_PROXY_FLAG_LAST = (1 << 8) +} GstVaapiSurfaceProxyFlags; + +/** + * GST_VAAPI_SURFACE_PROXY_SURFACE: + * @proxy: a #GstVaapiSurfaceProxy + * + * Macro that evaluates to the #GstVaapiSurface of @proxy. + */ +#define GST_VAAPI_SURFACE_PROXY_SURFACE(proxy) \ + gst_vaapi_surface_proxy_get_surface (proxy) + +/** + * GST_VAAPI_SURFACE_PROXY_SURFACE_ID: + * @proxy: a #GstVaapiSurfaceProxy + * + * Macro that evaluates to the VA surface ID of the underlying @proxy + * surface. + */ +#define GST_VAAPI_SURFACE_PROXY_SURFACE_ID(proxy) \ + gst_vaapi_surface_proxy_get_surface_id (proxy) + +/** + * GST_VAAPI_SURFACE_PROXY_VIEW_ID: + * @proxy: a #GstVaapiSurfaceProxy + * + * Macro that evaluates to the decoded view ID of the underlying @proxy + * surface. + */ +#define GST_VAAPI_SURFACE_PROXY_VIEW_ID(proxy) \ + gst_vaapi_surface_proxy_get_view_id (proxy) + +/** + * GST_VAAPI_SURFACE_PROXY_TIMESTAMP: + * @proxy: a #GstVaapiSurfaceProxy + * + * Macro that evaluates to the presentation timestamp of the + * underlying @proxy surface. + */ +#define GST_VAAPI_SURFACE_PROXY_TIMESTAMP(proxy) \ + gst_vaapi_surface_proxy_get_timestamp (proxy) + +/** + * GST_VAAPI_SURFACE_PROXY_DURATION: + * @proxy: a #GstVaapiSurfaceProxy + * + * Macro that evaluates to the presentation duration of the + * underlying @proxy surface. + */ +#define GST_VAAPI_SURFACE_PROXY_DURATION(proxy) \ + gst_vaapi_surface_proxy_get_duration (proxy) + +GstVaapiSurfaceProxy * +gst_vaapi_surface_proxy_new (GstVaapiSurface * surface); + +GstVaapiSurfaceProxy * +gst_vaapi_surface_proxy_new_from_pool (GstVaapiSurfacePool * pool); + +GstVaapiSurfaceProxy * +gst_vaapi_surface_proxy_copy (GstVaapiSurfaceProxy * proxy); + +GstVaapiSurfaceProxy * +gst_vaapi_surface_proxy_ref (GstVaapiSurfaceProxy * proxy); + +void +gst_vaapi_surface_proxy_unref (GstVaapiSurfaceProxy * proxy); + +void +gst_vaapi_surface_proxy_replace (GstVaapiSurfaceProxy ** old_proxy_ptr, + GstVaapiSurfaceProxy * new_proxy); + +guint +gst_vaapi_surface_proxy_get_flags (GstVaapiSurfaceProxy * proxy); + +GstVaapiSurface * +gst_vaapi_surface_proxy_get_surface (GstVaapiSurfaceProxy * proxy); + +GstVaapiID +gst_vaapi_surface_proxy_get_surface_id (GstVaapiSurfaceProxy * proxy); + +guintptr +gst_vaapi_surface_proxy_get_view_id (GstVaapiSurfaceProxy * proxy); + +GstClockTime +gst_vaapi_surface_proxy_get_timestamp (GstVaapiSurfaceProxy * proxy); + +GstClockTime +gst_vaapi_surface_proxy_get_duration (GstVaapiSurfaceProxy * proxy); + +void +gst_vaapi_surface_proxy_set_destroy_notify (GstVaapiSurfaceProxy * proxy, + GDestroyNotify destroy_func, gpointer user_data); + +const GstVaapiRectangle * +gst_vaapi_surface_proxy_get_crop_rect (GstVaapiSurfaceProxy * proxy); + +void +gst_vaapi_surface_proxy_set_crop_rect (GstVaapiSurfaceProxy * proxy, + const GstVaapiRectangle * crop_rect); + +G_END_DECLS + +#endif /* GST_VAAPI_SURFACE_PROXY_H */ diff --git a/gst-libs/gst/vaapi/gstvaapisurfaceproxy_priv.h b/gst-libs/gst/vaapi/gstvaapisurfaceproxy_priv.h new file mode 100644 index 0000000000..6abe2a229d --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapisurfaceproxy_priv.h @@ -0,0 +1,133 @@ +/* + * gstvaapisurfaceproxy_priv.h - VA surface proxy (private definitions) + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_SURFACE_PROXY_PRIV_H +#define GST_VAAPI_SURFACE_PROXY_PRIV_H + +#include "gstvaapiminiobject.h" +#include "gstvaapisurfaceproxy.h" +#include "gstvaapisurface_priv.h" + +#define GST_VAAPI_SURFACE_PROXY(obj) \ + ((GstVaapiSurfaceProxy *) (obj)) + +struct _GstVaapiSurfaceProxy +{ + /*< private >*/ + GstVaapiMiniObject parent_instance; + GstVaapiSurfaceProxy *parent; + + GstVaapiVideoPool *pool; + GstVaapiSurface *surface; + guintptr view_id; + GstClockTime timestamp; + GstClockTime duration; + GDestroyNotify destroy_func; + gpointer destroy_data; + GstVaapiRectangle crop_rect; + guint has_crop_rect:1; +}; + +#define GST_VAAPI_SURFACE_PROXY_FLAGS GST_VAAPI_MINI_OBJECT_FLAGS +#define GST_VAAPI_SURFACE_PROXY_FLAG_IS_SET GST_VAAPI_MINI_OBJECT_FLAG_IS_SET +#define GST_VAAPI_SURFACE_PROXY_FLAG_SET GST_VAAPI_MINI_OBJECT_FLAG_SET +#define GST_VAAPI_SURFACE_PROXY_FLAG_UNSET GST_VAAPI_MINI_OBJECT_FLAG_UNSET + +/** + * GST_VAAPI_SURFACE_PROXY_SURFACE: + * @proxy: a #GstVaapiSurfaceProxy + * + * Macro that evaluates to the #GstVaapiSurface of @proxy. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_SURFACE_PROXY_SURFACE +#define GST_VAAPI_SURFACE_PROXY_SURFACE(proxy) \ + (GST_VAAPI_SURFACE_PROXY (proxy)->surface) + +/** + * GST_VAAPI_SURFACE_PROXY_SURFACE_ID: + * @proxy: a #GstVaapiSurfaceProxy + * + * Macro that evaluates to the VA surface ID of the underlying @proxy + * surface. + * + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_SURFACE_PROXY_SURFACE_ID +#define GST_VAAPI_SURFACE_PROXY_SURFACE_ID(proxy) \ + (GST_VAAPI_SURFACE_ID (GST_VAAPI_SURFACE_PROXY (proxy)->surface)) + +/** + * GST_VAAPI_SURFACE_PROXY_VIEW_ID: + * @proxy: a #GstVaapiSurfaceProxy + * + * Macro that evaluates to the decoded view ID of the underlying @proxy + * surface. + * + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_SURFACE_PROXY_VIEW_ID +#define GST_VAAPI_SURFACE_PROXY_VIEW_ID(proxy) \ + (GST_VAAPI_SURFACE_PROXY (proxy)->view_id) + +/** + * GST_VAAPI_SURFACE_PROXY_TIMESTAMP: + * @proxy: a #GstVaapiSurfaceProxy + * + * Macro that evaluates to the presentation timestamp of the + * underlying @proxy surface. + * + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_SURFACE_PROXY_TIMESTAMP +#define GST_VAAPI_SURFACE_PROXY_TIMESTAMP(proxy) \ + (GST_VAAPI_SURFACE_PROXY (proxy)->timestamp) + +/** + * GST_VAAPI_SURFACE_PROXY_DURATION: + * @proxy: a #GstVaapiSurfaceProxy + * + * Macro that evaluates to the presentation duration of the + * underlying @proxy surface. + * + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_SURFACE_PROXY_DURATION +#define GST_VAAPI_SURFACE_PROXY_DURATION(proxy) \ + (GST_VAAPI_SURFACE_PROXY (proxy)->duration) + +/** + * GST_VAAPI_SURFACE_PROXY_CROP_RECT: + * @proxy: a #GstVaapiSurfaceProxy + * + * Macro that evaluates to the video cropping rectangle of the underlying @proxy surface. + * + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_SURFACE_PROXY_CROP_RECT +#define GST_VAAPI_SURFACE_PROXY_CROP_RECT(proxy) \ + (GST_VAAPI_SURFACE_PROXY (proxy)->has_crop_rect ? \ + &GST_VAAPI_SURFACE_PROXY (proxy)->crop_rect : NULL) + +#endif /* GST_VAAPI_SURFACE_PROXY_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapitexture.c b/gst-libs/gst/vaapi/gstvaapitexture.c new file mode 100644 index 0000000000..9bfc87bb28 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapitexture.c @@ -0,0 +1,371 @@ +/* + * gstvaapitexture.c - VA texture abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapitexture + * @short_description: VA/GLX texture abstraction + */ + +#include "sysdeps.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapitexture.h" +#include "gstvaapitexture_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +#define GST_VAAPI_TEXTURE_ORIENTATION_FLAGS \ + (GST_VAAPI_TEXTURE_ORIENTATION_FLAG_X_INVERTED | \ + GST_VAAPI_TEXTURE_ORIENTATION_FLAG_Y_INVERTED) + +#define GST_VAAPI_TEXTURE_PRIVATE_QUARK gst_vaapi_texture_private_quark () +static GQuark +gst_vaapi_texture_private_quark (void) +{ + static gsize g_quark; + + if (g_once_init_enter (&g_quark)) { + gsize quark = (gsize) g_quark_from_static_string ("GstVaapiTexturePrivate"); + g_once_init_leave (&g_quark, quark); + } + return g_quark; +} + +gpointer +gst_vaapi_texture_get_private (GstVaapiTexture * texture) +{ + return gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (texture), + GST_VAAPI_TEXTURE_PRIVATE_QUARK); +} + +void +gst_vaapi_texture_set_private (GstVaapiTexture * texture, gpointer priv, + GDestroyNotify destroy) +{ + gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (texture), + GST_VAAPI_TEXTURE_PRIVATE_QUARK, (gpointer) priv, destroy); +} + +static void +gst_vaapi_texture_init (GstVaapiTexture * texture, GstVaapiID id, + guint target, guint format, guint width, guint height) +{ + texture->is_wrapped = id != GST_VAAPI_ID_INVALID; + GST_VAAPI_TEXTURE_ID (texture) = texture->is_wrapped ? id : 0; + texture->gl_target = target; + texture->gl_format = format; + texture->width = width; + texture->height = height; +} + +static void +gst_vaapi_texture_free (GstVaapiTexture * texture) +{ + gst_vaapi_display_replace (&GST_VAAPI_TEXTURE_DISPLAY (texture), NULL); + g_slice_free1 (sizeof (GstVaapiTexture), texture); +} + +GST_DEFINE_MINI_OBJECT_TYPE (GstVaapiTexture, gst_vaapi_texture); + +GstVaapiTexture * +gst_vaapi_texture_new_internal (GstVaapiDisplay * display, GstVaapiID id, + guint target, guint format, guint width, guint height) +{ + GstVaapiTexture *texture; + + g_return_val_if_fail (display, NULL); + g_return_val_if_fail (target != 0, NULL); + g_return_val_if_fail (format != 0, NULL); + g_return_val_if_fail (width > 0, NULL); + g_return_val_if_fail (height > 0, NULL); + + texture = g_slice_alloc (sizeof (GstVaapiTexture)); + if (!texture) + return NULL; + + gst_mini_object_init (GST_MINI_OBJECT_CAST (texture), 0, + GST_TYPE_VAAPI_TEXTURE, NULL, NULL, + (GstMiniObjectFreeFunction) gst_vaapi_texture_free); + + GST_VAAPI_TEXTURE_DISPLAY (texture) = gst_object_ref (display); + + gst_vaapi_texture_init (texture, id, target, format, width, height); + + return texture; +} + +/** + * gst_vaapi_texture_new: + * @display: a #GstVaapiDisplay + * @target: the target to which the texture is bound + * @format: the format of the pixel data + * @width: the requested width, in pixels + * @height: the requested height, in pixels + * + * Creates a texture with the specified dimensions, @target and + * @format. Note that only GL_TEXTURE_2D @target and GL_RGBA or + * GL_BGRA formats are supported at this time. + * + * The application shall maintain the live GL context itself. + * + * Return value: the newly created #GstVaapiTexture object + */ +GstVaapiTexture * +gst_vaapi_texture_new (GstVaapiDisplay * display, guint target, guint format, + guint width, guint height) +{ + GstVaapiDisplayClass *dpy_class; + + g_return_val_if_fail (display != NULL, NULL); + g_return_val_if_fail (gst_vaapi_display_has_opengl (display), NULL); + + dpy_class = GST_VAAPI_DISPLAY_GET_CLASS (display); + if (G_UNLIKELY (!dpy_class->create_texture)) + return NULL; + return dpy_class->create_texture (display, GST_VAAPI_ID_INVALID, target, + format, width, height); +} + +/** + * gst_vaapi_texture_new_wrapped: + * @display: a #GstVaapiDisplay + * @texture_id: the foreign GL texture name to use + * @target: the target to which the texture is bound + * @format: the format of the pixel data + * @width: the suggested width, in pixels + * @height: the suggested height, in pixels + * + * Creates a texture with the specified dimensions, @target and + * @format. Note that only GL_TEXTURE_2D @target and GL_RGBA or + * GL_BGRA formats are supported at this time. + * + * The size arguments @width and @height are only a suggestion. Should + * this be 0x0, then the actual size of the allocated texture storage + * would be either inherited from the original texture storage, if any + * and/or if possible, or derived from the VA surface in subsequent + * gst_vaapi_texture_put_surface() calls. + * + * The application shall maintain the live GL context itself. + * + * Return value: the newly created #GstVaapiTexture object + */ +GstVaapiTexture * +gst_vaapi_texture_new_wrapped (GstVaapiDisplay * display, guint id, + guint target, guint format, guint width, guint height) +{ + GstVaapiDisplayClass *dpy_class; + + g_return_val_if_fail (display != NULL, NULL); + g_return_val_if_fail (gst_vaapi_display_has_opengl (display), NULL); + + dpy_class = GST_VAAPI_DISPLAY_GET_CLASS (display); + if (G_UNLIKELY (!dpy_class->create_texture)) + return NULL; + return dpy_class->create_texture (display, id, target, format, width, height); +} + +/** + * gst_vaapi_texture_get_id: + * @texture: a #GstVaapiTexture + * + * Returns the underlying texture id of the @texture. + * + * Return value: the underlying texture id of the @texture + */ +guint +gst_vaapi_texture_get_id (GstVaapiTexture * texture) +{ + g_return_val_if_fail (texture != NULL, 0); + + return GST_VAAPI_TEXTURE_ID (texture); +} + +/** + * gst_vaapi_texture_get_target: + * @texture: a #GstVaapiTexture + * + * Returns the @texture target type + * + * Return value: the texture target + */ +guint +gst_vaapi_texture_get_target (GstVaapiTexture * texture) +{ + g_return_val_if_fail (texture != NULL, 0); + + return GST_VAAPI_TEXTURE_TARGET (texture); +} + +/** + * gst_vaapi_texture_get_format + * @texture: a #GstVaapiTexture + * + * Returns the @texture format + * + * Return value: the texture format + */ +guint +gst_vaapi_texture_get_format (GstVaapiTexture * texture) +{ + g_return_val_if_fail (texture != NULL, 0); + + return GST_VAAPI_TEXTURE_FORMAT (texture); +} + +/** + * gst_vaapi_texture_get_width: + * @texture: a #GstVaapiTexture + * + * Returns the @texture width. + * + * Return value: the texture width, in pixels + */ +guint +gst_vaapi_texture_get_width (GstVaapiTexture * texture) +{ + g_return_val_if_fail (texture != NULL, 0); + + return GST_VAAPI_TEXTURE_WIDTH (texture); +} + +/** + * gst_vaapi_texture_get_height: + * @texture: a #GstVaapiTexture + * + * Returns the @texture height. + * + * Return value: the texture height, in pixels. + */ +guint +gst_vaapi_texture_get_height (GstVaapiTexture * texture) +{ + g_return_val_if_fail (texture != NULL, 0); + + return GST_VAAPI_TEXTURE_HEIGHT (texture); +} + +/** + * gst_vaapi_texture_get_size: + * @texture: a #GstVaapiTexture + * @width_ptr: return location for the width, or %NULL + * @height_ptr: return location for the height, or %NULL + * + * Retrieves the dimensions of a #GstVaapiTexture. + */ +void +gst_vaapi_texture_get_size (GstVaapiTexture * texture, + guint * width_ptr, guint * height_ptr) +{ + g_return_if_fail (texture != NULL); + + if (width_ptr) + *width_ptr = GST_VAAPI_TEXTURE_WIDTH (texture); + + if (height_ptr) + *height_ptr = GST_VAAPI_TEXTURE_HEIGHT (texture); +} + +/** + * gst_vaapi_texture_get_display: + * @texture: a #GstVaapiTexture + * + * Returns the #GstVaapiDisplay this @texture is bound to. + * + * Return value: the parent #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_texture_get_display (GstVaapiTexture * texture) +{ + g_return_val_if_fail (texture != NULL, NULL); + return GST_VAAPI_TEXTURE_DISPLAY (texture); +} + +/** + * gst_vaapi_texture_get_orientation_flags: + * @texture: a #GstVaapiTexture + * + * Retrieves the texture memory layout flags, i.e. orientation. + * + * Return value: the #GstVaapiTextureOrientationFlags. + */ +guint +gst_vaapi_texture_get_orientation_flags (GstVaapiTexture * texture) +{ + g_return_val_if_fail (texture != NULL, 0); + + return GST_MINI_OBJECT_FLAGS (texture) & GST_VAAPI_TEXTURE_ORIENTATION_FLAGS; +} + +/** + * gst_vaapi_texture_set_orientation_flags: + * @texture: a #GstVaapiTexture + * @flags: a bitmask of #GstVaapiTextureOrientationFlags + * + * Reset the texture orientation flags to the supplied set of + * @flags. This completely replaces the previously installed + * flags. So, should they still be needed, then they shall be + * retrieved first with gst_vaapi_texture_get_orientation_flags(). + */ +void +gst_vaapi_texture_set_orientation_flags (GstVaapiTexture * texture, guint flags) +{ + g_return_if_fail (texture != NULL); + g_return_if_fail ((flags & ~GST_VAAPI_TEXTURE_ORIENTATION_FLAGS) == 0); + + GST_MINI_OBJECT_FLAG_UNSET (texture, GST_VAAPI_TEXTURE_ORIENTATION_FLAGS); + GST_MINI_OBJECT_FLAG_SET (texture, flags); +} + +/** + * gst_vaapi_texture_put_surface: + * @texture: a #GstVaapiTexture + * @surface: a #GstVaapiSurface + * @flags: postprocessing flags. See #GstVaapiTextureRenderFlags + * + * Renders the @surface into the @texture. The @flags specify how + * de-interlacing (if needed), color space conversion, scaling and + * other postprocessing transformations are performed. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_texture_put_surface (GstVaapiTexture * texture, + GstVaapiSurface * surface, const GstVaapiRectangle * crop_rect, guint flags) +{ + GstVaapiRectangle rect; + + g_return_val_if_fail (texture != NULL, FALSE); + g_return_val_if_fail (surface != NULL, FALSE); + + if (!texture->put_surface) + return FALSE; + + if (!crop_rect) { + rect.x = 0; + rect.y = 0; + gst_vaapi_surface_get_size (surface, &rect.width, &rect.height); + crop_rect = ▭ + } + return texture->put_surface (texture, surface, crop_rect, flags); +} diff --git a/gst-libs/gst/vaapi/gstvaapitexture.h b/gst-libs/gst/vaapi/gstvaapitexture.h new file mode 100644 index 0000000000..ef9b58637b --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapitexture.h @@ -0,0 +1,174 @@ +/* + * gstvaapitexture.h - VA texture abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_TEXTURE_H +#define GST_VAAPI_TEXTURE_H + +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TEXTURE(obj) \ + ((GstVaapiTexture *)(obj)) + +#define GST_TYPE_VAAPI_TEXTURE (gst_vaapi_texture_get_type ()) + +/** + * GST_VAAPI_TEXTURE_DISPLAY: + * @texture: a #GstVaapiTexture + * + * Macro that evaluates to the display associated with the @texture + */ +#define GST_VAAPI_TEXTURE_DISPLAY(texture) \ + gst_vaapi_texture_get_display (GST_VAAPI_TEXTURE (texture)) + +/** + * GST_VAAPI_TEXTURE_ID: + * @texture: a #GstVaapiTexture + * + * Macro that evaluates to the GL texture id associated with the @texture + */ +#define GST_VAAPI_TEXTURE_ID(texture) \ + gst_vaapi_texture_get_id (GST_VAAPI_TEXTURE (texture)) + +/** + * GST_VAAPI_TEXTURE_TARGET: + * @texture: a #GstVaapiTexture + * + * Macro that evaluates to the GL texture target associated with the @texture + */ +#define GST_VAAPI_TEXTURE_TARGET(texture) \ + gst_vaapi_texture_get_target (GST_VAAPI_TEXTURE (texture)) + +/** + * GST_VAAPI_TEXTURE_FORMAT: + * @texture: a #GstVaapiTexture + * + * Macro that evaluates to the GL texture format associated with the @texture + */ +#define GST_VAAPI_TEXTURE_FORMAT(texture) \ + gst_vaapi_texture_get_format (GST_VAAPI_TEXTURE (texture)) + +/** + * GST_VAAPI_TEXTURE_WIDTH: + * @texture: a #GstVaapiTexture + * + * Macro that evaluates to the GL texture width associated with the @texture + */ +#define GST_VAAPI_TEXTURE_WIDTH(texture) \ + gst_vaapi_texture_get_width (GST_VAAPI_TEXTURE (texture)) + +/** + * GST_VAAPI_TEXTURE_HEIGHT: + * @texture: a #GstVaapiTexture + * + * Macro that evaluates to the GL texture height associated with the @texture + */ +#define GST_VAAPI_TEXTURE_HEIGHT(texture) \ + gst_vaapi_texture_get_height (GST_VAAPI_TEXTURE (texture)) + +typedef struct _GstVaapiTexture GstVaapiTexture; + +/** + * GstVaapiTextureOrientationFlags: + * @GST_VAAPI_TEXTURE_ORIENTATION_FLAG_X_INVERTED: indicates whether + * the right row comes first in memory. + * @GST_VAAPI_TEXTURE_ORIENTATION_FLAG_Y_INVERTED: indicates whether + * the bottom line comes first in memory. + * + * Additional flags to indicate whether the texture data is organized + * in memory with the X or Y, or both, axis inverted. e.g. if only + * @GST_VAAPI_TEXTURE_ORIENTATION_FLAG_Y_INVERTED is set, this means + * that the bottom line comes first in memory, with pixels laid out + * from the left to the right. + */ +typedef enum { + GST_VAAPI_TEXTURE_ORIENTATION_FLAG_X_INVERTED = (GST_MINI_OBJECT_FLAG_LAST << 1), + GST_VAAPI_TEXTURE_ORIENTATION_FLAG_Y_INVERTED = (GST_MINI_OBJECT_FLAG_LAST << 2), +} GstVaapiTextureOrientationFlags; + +GType +gst_vaapi_texture_get_type (void) G_GNUC_CONST; + +/** + * gst_vaapi_texture_unref: (skip) + * @texture: (transfer full): a #GstVaapiTexture. + * + * Decreases the refcount of the texture. If the refcount reaches 0, the + * texture will be freed. + */ +static inline void +gst_vaapi_texture_unref (GstVaapiTexture * texture) +{ + gst_mini_object_unref (GST_MINI_OBJECT_CAST (texture)); +} + +GstVaapiTexture * +gst_vaapi_texture_new (GstVaapiDisplay * display, guint target, guint format, + guint width, guint height); + +GstVaapiTexture * +gst_vaapi_texture_new_wrapped (GstVaapiDisplay * display, guint id, + guint target, guint format, guint width, guint height); + +guint +gst_vaapi_texture_get_id (GstVaapiTexture * texture); + +GstVaapiDisplay * +gst_vaapi_texture_get_display (GstVaapiTexture * texture); + +guint +gst_vaapi_texture_get_target (GstVaapiTexture * texture); + +guint +gst_vaapi_texture_get_format (GstVaapiTexture * texture); + +guint +gst_vaapi_texture_get_width (GstVaapiTexture * texture); + +guint +gst_vaapi_texture_get_height (GstVaapiTexture * texture); + +void +gst_vaapi_texture_get_size (GstVaapiTexture * texture, guint * width_ptr, + guint * height_ptr); + +guint +gst_vaapi_texture_get_orientation_flags (GstVaapiTexture * texture); + +void +gst_vaapi_texture_set_orientation_flags (GstVaapiTexture * texture, + guint flags); + +gboolean +gst_vaapi_texture_put_surface (GstVaapiTexture * texture, + GstVaapiSurface * surface, const GstVaapiRectangle * crop_rect, + guint flags); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiTexture, gst_vaapi_texture_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_TEXTURE_H */ diff --git a/gst-libs/gst/vaapi/gstvaapitexture_egl.c b/gst-libs/gst/vaapi/gstvaapitexture_egl.c new file mode 100644 index 0000000000..49edcc883f --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapitexture_egl.c @@ -0,0 +1,379 @@ +/* + * gstvaapitexture_egl.c - VA/EGL texture abstraction + * + * Copyright (C) 2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapitexture_egl + * @short_description: VA/EGL texture abstraction + */ + +#include "sysdeps.h" +#include "gstvaapitexture.h" +#include "gstvaapitexture_egl.h" +#include "gstvaapitexture_priv.h" +#include "gstvaapicompat.h" +#include "gstvaapiutils.h" +#include "gstvaapiutils_egl.h" +#include "gstvaapidisplay_egl.h" +#include "gstvaapidisplay_egl_priv.h" +#include "gstvaapisurface_egl.h" +#include "gstvaapifilter.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +typedef struct _GstVaapiTextureEGLPrivate GstVaapiTextureEGLPrivate; + +/** + * GstVaapiTextureEGLPrivate: + * + * EGL texture specific fields. + */ +struct _GstVaapiTextureEGLPrivate +{ + /*< private > */ + GstVaapiTexture *texture; + EglContext *egl_context; + EGLImageKHR egl_image; + GstVaapiSurface *surface; + GstVaapiFilter *filter; +}; + +typedef struct +{ + GstVaapiTexture *texture; + gboolean success; /* result */ +} CreateTextureArgs; + +typedef struct +{ + GstVaapiTexture *texture; + GstVaapiSurface *surface; + const GstVaapiRectangle *crop_rect; + guint flags; + gboolean success; /* result */ +} UploadSurfaceArgs; + +static gboolean +create_objects (GstVaapiTexture * texture, GLuint texture_id) +{ + GstVaapiTextureEGLPrivate *const texture_egl = + gst_vaapi_texture_get_private (texture); + EglContext *const ctx = texture_egl->egl_context; + EglVTable *const vtable = egl_context_get_vtable (ctx, FALSE); + GLint attribs[3] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE }; + guint mem_types; + + texture_egl->filter = + gst_vaapi_filter_new (GST_VAAPI_TEXTURE_DISPLAY (texture)); + if (!texture_egl->filter) + goto error_create_filter; + + mem_types = gst_vaapi_filter_get_memory_types (texture_egl->filter); + + texture_egl->egl_image = + vtable->eglCreateImageKHR (ctx->display->base.handle.p, + ctx->base.handle.p, EGL_GL_TEXTURE_2D_KHR, + (EGLClientBuffer) GSIZE_TO_POINTER (texture_id), attribs); + if (!texture_egl->egl_image) + goto error_create_image; + + texture_egl->surface = + gst_vaapi_surface_new_with_egl_image (GST_VAAPI_TEXTURE_DISPLAY (texture), + texture_egl->egl_image, GST_VIDEO_FORMAT_RGBA, texture->width, + texture->height, mem_types); + if (!texture_egl->surface) + goto error_create_surface; + + return TRUE; + + /* ERRORS */ +error_create_image: + { + GST_ERROR ("failed to create EGL image from 2D texture %u", texture_id); + return FALSE; + } +error_create_surface: + { + GST_ERROR ("failed to create VA surface from 2D texture %u", texture_id); + return FALSE; + } +error_create_filter: + { + GST_ERROR ("failed to create VPP filter for color conversion"); + return FALSE; + } +} + +static gboolean +do_create_texture_unlocked (GstVaapiTexture * texture) +{ + GLuint texture_id; + GstVaapiTextureEGLPrivate *texture_egl = + gst_vaapi_texture_get_private (texture); + + if (texture->is_wrapped) + texture_id = GST_VAAPI_TEXTURE_ID (texture); + else { + texture_id = egl_create_texture (texture_egl->egl_context, + texture->gl_target, texture->gl_format, + texture->width, texture->height); + if (!texture_id) + return FALSE; + GST_VAAPI_TEXTURE_ID (texture) = texture_id; + } + return create_objects (texture, texture_id); +} + +static void +do_create_texture (CreateTextureArgs * args) +{ + GstVaapiTexture *const texture = args->texture; + GstVaapiTextureEGLPrivate *texture_egl = + gst_vaapi_texture_get_private (texture); + EglContextState old_cs; + + args->success = FALSE; + + GST_VAAPI_DISPLAY_LOCK (GST_VAAPI_TEXTURE_DISPLAY (texture)); + if (egl_context_set_current (texture_egl->egl_context, TRUE, &old_cs)) { + args->success = do_create_texture_unlocked (texture); + egl_context_set_current (texture_egl->egl_context, FALSE, &old_cs); + } + GST_VAAPI_DISPLAY_UNLOCK (GST_VAAPI_TEXTURE_DISPLAY (texture)); +} + +static void +destroy_objects (GstVaapiTextureEGLPrivate * texture_egl) +{ + EglContext *const ctx = texture_egl->egl_context; + EglVTable *const vtable = egl_context_get_vtable (ctx, FALSE); + + if (texture_egl->egl_image != EGL_NO_IMAGE_KHR) { + vtable->eglDestroyImageKHR (ctx->display->base.handle.p, + texture_egl->egl_image); + texture_egl->egl_image = EGL_NO_IMAGE_KHR; + } + gst_mini_object_replace ((GstMiniObject **) & texture_egl->surface, NULL); + gst_vaapi_filter_replace (&texture_egl->filter, NULL); +} + +static void +do_destroy_texture_unlocked (GstVaapiTextureEGLPrivate * texture_egl) +{ + GstVaapiTexture *const base_texture = texture_egl->texture; + const GLuint texture_id = GST_VAAPI_TEXTURE_ID (base_texture); + + destroy_objects (texture_egl); + + if (texture_id) { + if (!base_texture->is_wrapped) + egl_destroy_texture (texture_egl->egl_context, texture_id); + GST_VAAPI_TEXTURE_ID (base_texture) = 0; + } +} + +static void +do_destroy_texture (GstVaapiTextureEGLPrivate * texture_egl) +{ + EglContextState old_cs; + GstVaapiTexture *texture = texture_egl->texture; + + GST_VAAPI_DISPLAY_LOCK (GST_VAAPI_TEXTURE_DISPLAY (texture)); + if (egl_context_set_current (texture_egl->egl_context, TRUE, &old_cs)) { + do_destroy_texture_unlocked (texture_egl); + egl_context_set_current (texture_egl->egl_context, FALSE, &old_cs); + } + GST_VAAPI_DISPLAY_UNLOCK (GST_VAAPI_TEXTURE_DISPLAY (texture)); + egl_object_replace (&texture_egl->egl_context, NULL); + g_free (texture_egl); +} + +static gboolean +do_upload_surface_unlocked (GstVaapiTextureEGLPrivate * texture_egl, + GstVaapiSurface * surface, const GstVaapiRectangle * crop_rect, guint flags) +{ + GstVaapiFilterStatus status; + + if (!gst_vaapi_filter_set_cropping_rectangle (texture_egl->filter, crop_rect)) + return FALSE; + + status = gst_vaapi_filter_process (texture_egl->filter, surface, + texture_egl->surface, flags); + if (status != GST_VAAPI_FILTER_STATUS_SUCCESS) + return FALSE; + return TRUE; +} + +static void +do_upload_surface (UploadSurfaceArgs * args) +{ + GstVaapiTexture *const texture = args->texture; + GstVaapiTextureEGLPrivate *texture_egl = + gst_vaapi_texture_get_private (texture); + EglContextState old_cs; + + args->success = FALSE; + + GST_VAAPI_DISPLAY_LOCK (GST_VAAPI_TEXTURE_DISPLAY (texture)); + if (egl_context_set_current (texture_egl->egl_context, TRUE, &old_cs)) { + args->success = do_upload_surface_unlocked (texture_egl, args->surface, + args->crop_rect, args->flags); + egl_context_set_current (texture_egl->egl_context, FALSE, &old_cs); + } + GST_VAAPI_DISPLAY_UNLOCK (GST_VAAPI_TEXTURE_DISPLAY (texture)); +} + +static gboolean +gst_vaapi_texture_egl_create (GstVaapiTexture * texture) +{ + CreateTextureArgs args = { texture }; + GstVaapiDisplayEGL *display = + GST_VAAPI_DISPLAY_EGL (GST_VAAPI_TEXTURE_DISPLAY (texture)); + GstVaapiTextureEGLPrivate *texture_egl = + gst_vaapi_texture_get_private (texture); + + if (GST_VAAPI_TEXTURE (texture)->is_wrapped) { + if (!gst_vaapi_display_egl_set_current_display (display)) + return FALSE; + } + + egl_object_replace (&texture_egl->egl_context, + GST_VAAPI_DISPLAY_EGL_CONTEXT (display)); + + return egl_context_run (texture_egl->egl_context, + (EglContextRunFunc) do_create_texture, &args) && args.success; +} + +static void +gst_vaapi_texture_egl_destroy (GstVaapiTextureEGLPrivate * texture_egl) +{ + egl_context_run (texture_egl->egl_context, + (EglContextRunFunc) do_destroy_texture, texture_egl); +} + +static gboolean +gst_vaapi_texture_egl_put_surface (GstVaapiTexture * texture, + GstVaapiSurface * surface, const GstVaapiRectangle * crop_rect, guint flags) +{ + UploadSurfaceArgs args = { texture, surface, crop_rect, flags }; + GstVaapiTextureEGLPrivate *texture_egl = + gst_vaapi_texture_get_private (texture); + + return egl_context_run (texture_egl->egl_context, + (EglContextRunFunc) do_upload_surface, &args) && args.success; +} + +static GstVaapiTexture * +gst_vaapi_texture_egl_new_internal (GstVaapiTexture * texture) +{ + GstVaapiTextureEGLPrivate *texture_egl; + + texture->put_surface = gst_vaapi_texture_egl_put_surface; + + texture_egl = g_malloc0 (sizeof (GstVaapiTextureEGLPrivate)); + if (!texture_egl) { + gst_mini_object_unref (GST_MINI_OBJECT_CAST (texture)); + return NULL; + } + texture_egl->texture = texture; + gst_vaapi_texture_set_private (texture, texture_egl, + (GDestroyNotify) gst_vaapi_texture_egl_destroy); + + if (!gst_vaapi_texture_egl_create (texture)) { + gst_mini_object_unref (GST_MINI_OBJECT_CAST (texture)); + return NULL; + } + + return texture; +} + +/** + * gst_vaapi_texture_egl_new: + * @display: a #GstVaapiDisplay + * @target: the target to which the texture is bound + * @format: the format of the pixel data + * @width: the requested width, in pixels + * @height: the requested height, in pixels + * + * Creates a texture with the specified dimensions, @target and + * @format. Note that only GL_TEXTURE_2D @target and GL_RGBA or + * GL_BGRA formats are supported at this time. + * + * The application shall maintain the live EGL context itself. That + * is, gst_vaapi_window_egl_make_current() must be called beforehand, + * or any other function like eglMakeCurrent() if the context is + * managed outside of this library. + * + * Return value: the newly created #GstVaapiTexture object + */ +GstVaapiTexture * +gst_vaapi_texture_egl_new (GstVaapiDisplay * display, guint target, + guint format, guint width, guint height) +{ + GstVaapiTexture *texture; + + g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_EGL (display), NULL); + + texture = gst_vaapi_texture_new_internal (display, GST_VAAPI_ID_INVALID, + target, format, width, height); + if (!texture) + return NULL; + + return gst_vaapi_texture_egl_new_internal (texture); +} + +/** + * gst_vaapi_texture_egl_new_wrapped: + * @display: a #GstVaapiDisplay + * @texture_id: the foreign GL texture name to use + * @target: the target to which the texture is bound + * @format: the format of the pixel data + * @width: the texture width, in pixels + * @height: the texture height, in pixels + * + * Creates a texture from an existing GL texture, with the specified + * @target and @format. Note that only GL_TEXTURE_2D @target and + * GL_RGBA or GL_BGRA formats are supported at this time. + * + * The application shall maintain the live EGL context itself. That + * is, gst_vaapi_window_egl_make_current() must be called beforehand, + * or any other function like eglMakeCurrent() if the context is + * managed outside of this library. + * + * Return value: the newly created #GstVaapiTexture object + */ +GstVaapiTexture * +gst_vaapi_texture_egl_new_wrapped (GstVaapiDisplay * display, + guint texture_id, guint target, GLenum format, guint width, guint height) +{ + GstVaapiTexture *texture; + + g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_EGL (display), NULL); + g_return_val_if_fail (texture_id != GL_NONE, NULL); + + texture = gst_vaapi_texture_new_internal (display, texture_id, + target, format, width, height); + if (!texture) + return texture; + + return gst_vaapi_texture_egl_new_internal (texture); +} diff --git a/gst-libs/gst/vaapi/gstvaapitexture_egl.h b/gst-libs/gst/vaapi/gstvaapitexture_egl.h new file mode 100644 index 0000000000..848c15d6e7 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapitexture_egl.h @@ -0,0 +1,40 @@ +/* + * gstvaapitexture_egl.h - VA/EGL texture abstraction + * + * Copyright (C) 2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_TEXTURE_EGL_H +#define GST_VAAPI_TEXTURE_EGL_H + +#include + +G_BEGIN_DECLS + +GstVaapiTexture * +gst_vaapi_texture_egl_new (GstVaapiDisplay * display, guint target, + guint format, guint width, guint height); + +GstVaapiTexture * +gst_vaapi_texture_egl_new_wrapped (GstVaapiDisplay * display, guint id, + guint target, guint format, guint width, guint height); + +G_END_DECLS + +#endif /* GST_VAAPI_TEXTURE_EGL_H */ diff --git a/gst-libs/gst/vaapi/gstvaapitexture_glx.c b/gst-libs/gst/vaapi/gstvaapitexture_glx.c new file mode 100644 index 0000000000..76f450add6 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapitexture_glx.c @@ -0,0 +1,431 @@ +/* + * gstvaapitexture_glx.c - VA/GLX texture abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapitexture_glx + * @short_description: VA/GLX texture abstraction + */ + +#include "sysdeps.h" +#include "gstvaapitexture.h" +#include "gstvaapitexture_glx.h" +#include "gstvaapitexture_priv.h" +#include "gstvaapisurface_priv.h" +#include "gstvaapicompat.h" +#include "gstvaapiutils.h" +#include "gstvaapiutils_glx.h" +#include "gstvaapidisplay_glx.h" +#include "gstvaapidisplay_x11_priv.h" +#include "gstvaapidisplay_glx_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +#define GST_VAAPI_TEXTURE_GLX(texture) \ + ((GstVaapiTextureGLX *)(texture)) + +typedef struct _GstVaapiTextureGLXPrivate GstVaapiTextureGLXPrivate; + +/** + * GstVaapiTextureGLXPrivate: + * + * GLX texture specific fields. + */ +struct _GstVaapiTextureGLXPrivate +{ + /*< private > */ + GstVaapiTexture *texture; + GLContextState *gl_context; + GLPixmapObject *pixo; + GLFramebufferObject *fbo; +}; + +static gboolean +gst_vaapi_texture_glx_put_surface (GstVaapiTexture * texture, + GstVaapiSurface * surface, const GstVaapiRectangle * crop_rect, + guint flags); + +static void +destroy_objects (GstVaapiTextureGLXPrivate * texture) +{ + GLContextState old_cs; + + if (texture->gl_context) + gl_set_current_context (texture->gl_context, &old_cs); + + if (texture->fbo) { + gl_destroy_framebuffer_object (texture->fbo); + texture->fbo = NULL; + } + + if (texture->pixo) { + gl_destroy_pixmap_object (texture->pixo); + texture->pixo = NULL; + } + + if (texture->gl_context) { + gl_set_current_context (&old_cs, NULL); + gl_destroy_context (texture->gl_context); + texture->gl_context = NULL; + } +} + +static void +destroy_texture_unlocked (GstVaapiTextureGLXPrivate * texture_glx) +{ + GstVaapiTexture *texture = texture_glx->texture; + const guint texture_id = GST_VAAPI_TEXTURE_ID (texture); + + destroy_objects (texture_glx); + + if (texture_id) { + if (!texture->is_wrapped) + glDeleteTextures (1, &texture_id); + GST_VAAPI_TEXTURE_ID (texture) = 0; + } +} + +static void +gst_vaapi_texture_glx_destroy (GstVaapiTextureGLXPrivate * texture_glx) +{ + GstVaapiTexture *texture = texture_glx->texture; + + GST_VAAPI_DISPLAY_LOCK (GST_VAAPI_TEXTURE_DISPLAY (texture)); + destroy_texture_unlocked (texture_glx); + GST_VAAPI_DISPLAY_UNLOCK (GST_VAAPI_TEXTURE_DISPLAY (texture)); + + g_free (texture_glx); +} + +static gboolean +create_objects (GstVaapiTexture * texture, guint texture_id) +{ + GstVaapiTextureGLXPrivate *texture_glx = + gst_vaapi_texture_get_private (texture); + Display *const dpy = + GST_VAAPI_DISPLAY_NATIVE (GST_VAAPI_TEXTURE_DISPLAY (texture)); + GLContextState old_cs; + gboolean success = FALSE; + + gl_get_current_context (&old_cs); + + texture_glx->gl_context = + gl_create_context (dpy, DefaultScreen (dpy), &old_cs); + if (!texture_glx->gl_context + || !gl_set_current_context (texture_glx->gl_context, NULL)) + return FALSE; + + texture_glx->pixo = gl_create_pixmap_object (dpy, + texture->width, texture->height); + if (!texture_glx->pixo) { + GST_ERROR ("failed to create GLX pixmap"); + goto out_reset_context; + } + + texture_glx->fbo = gl_create_framebuffer_object (texture->gl_target, + texture_id, texture->width, texture->height); + if (!texture_glx->fbo) { + GST_ERROR ("failed to create FBO"); + goto out_reset_context; + } + success = TRUE; + +out_reset_context: + gl_set_current_context (&old_cs, NULL); + return success; +} + +static gboolean +create_texture_unlocked (GstVaapiTexture * texture) +{ + guint texture_id; + + if (texture->is_wrapped) + texture_id = GST_VAAPI_TEXTURE_ID (texture); + else { + texture_id = gl_create_texture (texture->gl_target, texture->gl_format, + texture->width, texture->height); + if (!texture_id) + return FALSE; + GST_VAAPI_TEXTURE_ID (texture) = texture_id; + } + return create_objects (texture, texture_id); +} + +static gboolean +gst_vaapi_texture_glx_create (GstVaapiTexture * texture) +{ + gboolean success; + + GST_VAAPI_DISPLAY_LOCK (GST_VAAPI_TEXTURE_DISPLAY (texture)); + success = create_texture_unlocked (texture); + GST_VAAPI_DISPLAY_UNLOCK (GST_VAAPI_TEXTURE_DISPLAY (texture)); + return success; +} + + +static GstVaapiTexture * +gst_vaapi_texture_glx_new_internal (GstVaapiTexture * texture) +{ + GstVaapiTextureGLXPrivate *texture_glx; + + texture->put_surface = gst_vaapi_texture_glx_put_surface; + + texture_glx = g_malloc0 (sizeof (GstVaapiTextureGLXPrivate)); + if (!texture_glx) { + gst_mini_object_unref (GST_MINI_OBJECT_CAST (texture)); + return NULL; + } + texture_glx->texture = texture; + gst_vaapi_texture_set_private (texture, texture_glx, + (GDestroyNotify) gst_vaapi_texture_glx_destroy); + + if (!gst_vaapi_texture_glx_create (texture)) { + gst_mini_object_unref (GST_MINI_OBJECT_CAST (texture)); + return NULL; + } + + return texture; +} + +/** + * gst_vaapi_texture_glx_new: + * @display: a #GstVaapiDisplay + * @target: the target to which the texture is bound + * @format: the format of the pixel data + * @width: the requested width, in pixels + * @height: the requested height, in pixels + * + * Creates a texture with the specified dimensions, @target and + * @format. Note that only GL_TEXTURE_2D @target and GL_RGBA or + * GL_BGRA formats are supported at this time. + * + * The application shall maintain the live GL context itself. That is, + * gst_vaapi_window_glx_make_current() must be called beforehand, or + * any other function like glXMakeCurrent() if the context is managed + * outside of this library. + * + * Return value: the newly created #GstVaapiTexture object + */ +GstVaapiTexture * +gst_vaapi_texture_glx_new (GstVaapiDisplay * display, guint target, + guint format, guint width, guint height) +{ + GstVaapiTexture *texture; + + g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_GLX (display), NULL); + + texture = gst_vaapi_texture_new_internal (display, GST_VAAPI_ID_INVALID, + target, format, width, height); + if (!texture) + return NULL; + + return gst_vaapi_texture_glx_new_internal (texture); +} + +/* Can we assume that the vsink/app context API won't change ever? */ +GstVaapiGLApi +gl_get_curent_api_once () +{ + static GstVaapiGLApi cur_api = GST_VAAPI_GL_API_NONE; + static gsize _init = 0; + + if (g_once_init_enter (&_init)) { + cur_api = gl_get_current_api (NULL, NULL); + g_once_init_leave (&_init, 1); + } + + return cur_api; +} + +/** + * gst_vaapi_texture_glx_new_wrapped: + * @display: a #GstVaapiDisplay + * @texture_id: the foreign GL texture name to use + * @target: the target to which the texture is bound + * @format: the format of the pixel data + * + * Creates a texture from an existing GL texture, with the specified + * @target and @format. Note that only GL_TEXTURE_2D @target and + * GL_RGBA or GL_BGRA formats are supported at this time. The + * dimensions will be retrieved from the @texture_id. + * + * The application shall maintain the live GL context itself. That is, + * gst_vaapi_window_glx_make_current() must be called beforehand, or + * any other function like glXMakeCurrent() if the context is managed + * outside of this library. + * + * Return value: the newly created #GstVaapiTexture object + */ +GstVaapiTexture * +gst_vaapi_texture_glx_new_wrapped (GstVaapiDisplay * display, + guint texture_id, guint target, guint format) +{ + guint width, height, border_width = 0; + GLTextureState ts = { 0, }; + gboolean success; + GstVaapiGLApi gl_api; + GstVaapiTexture *texture; + + g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_GLX (display), NULL); + g_return_val_if_fail (texture_id != GL_NONE, NULL); + g_return_val_if_fail (target == GL_TEXTURE_2D, NULL); + g_return_val_if_fail (format == GL_RGBA || format == GL_BGRA, NULL); + + gl_api = gl_get_curent_api_once (); + if (gl_api != GST_VAAPI_GL_API_OPENGL && gl_api != GST_VAAPI_GL_API_OPENGL3) + return NULL; + + /* Check texture dimensions */ + GST_VAAPI_DISPLAY_LOCK (display); + if (gl_api == GST_VAAPI_GL_API_OPENGL) + success = gl_bind_texture (&ts, target, texture_id); + else + success = gl3_bind_texture_2d (&ts, target, texture_id); + + if (success) { + if (!gl_get_texture_param (target, GL_TEXTURE_WIDTH, &width) || + !gl_get_texture_param (target, GL_TEXTURE_HEIGHT, &height)) + success = FALSE; + if (success && gl_api == GST_VAAPI_GL_API_OPENGL) + success = gl_get_texture_param (target, GL_TEXTURE_BORDER, &border_width); + gl_unbind_texture (&ts); + } + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!success) + return NULL; + + width -= 2 * border_width; + height -= 2 * border_width; + g_return_val_if_fail (width > 0, NULL); + g_return_val_if_fail (height > 0, NULL); + + texture = gst_vaapi_texture_new_internal (display, texture_id, target, + format, width, height); + if (!texture) + return NULL; + + return gst_vaapi_texture_glx_new_internal (texture); +} + +/** + * gst_vaapi_texture_put_surface: + * @texture: a #GstVaapiTexture + * @surface: a #GstVaapiSurface + * @flags: postprocessing flags. See #GstVaapiTextureRenderFlags + * + * Renders the @surface into the àtexture. The @flags specify how + * de-interlacing (if needed), color space conversion, scaling and + * other postprocessing transformations are performed. + * + * Return value: %TRUE on success + */ +static gboolean +gst_vaapi_texture_glx_put_surface_unlocked (GstVaapiTexture * texture, + GstVaapiSurface * surface, const GstVaapiRectangle * crop_rect, guint flags) +{ + GstVaapiTextureGLXPrivate *texture_glx = + gst_vaapi_texture_get_private (texture); + VAStatus status; + GLContextState old_cs; + gboolean success = FALSE; + + const GLfloat *txc, *tyc; + static const GLfloat g_texcoords[2][2] = { + {0.0f, 1.0f}, + {1.0f, 0.0f}, + }; + + status = vaPutSurface (GST_VAAPI_DISPLAY_VADISPLAY (GST_VAAPI_TEXTURE_DISPLAY + (texture)), GST_VAAPI_SURFACE_ID (surface), texture_glx->pixo->pixmap, + crop_rect->x, crop_rect->y, crop_rect->width, crop_rect->height, 0, 0, + texture->width, texture->height, NULL, 0, + from_GstVaapiSurfaceRenderFlags (flags)); + if (!vaapi_check_status (status, "vaPutSurface() [TFP]")) + return FALSE; + + if (texture_glx->gl_context && + !gl_set_current_context (texture_glx->gl_context, &old_cs)) + return FALSE; + + if (!gl_bind_framebuffer_object (texture_glx->fbo)) { + GST_ERROR ("failed to bind FBO"); + goto out_reset_context; + } + + if (!gst_vaapi_surface_sync (surface)) { + GST_ERROR ("failed to render surface to pixmap"); + goto out_unbind_fbo; + } + + if (!gl_bind_pixmap_object (texture_glx->pixo)) { + GST_ERROR ("could not bind GLX pixmap"); + goto out_unbind_fbo; + } + + flags = GST_MINI_OBJECT_FLAGS (texture); + txc = g_texcoords[! !(flags & GST_VAAPI_TEXTURE_ORIENTATION_FLAG_X_INVERTED)]; + tyc = g_texcoords[! !(flags & GST_VAAPI_TEXTURE_ORIENTATION_FLAG_Y_INVERTED)]; + + glColor4f (1.0f, 1.0f, 1.0f, 1.0f); + glBegin (GL_QUADS); + { + glTexCoord2f (txc[0], tyc[0]); + glVertex2i (0, 0); + glTexCoord2f (txc[0], tyc[1]); + glVertex2i (0, texture->height); + glTexCoord2f (txc[1], tyc[1]); + glVertex2i (texture->width, texture->height); + glTexCoord2f (txc[1], tyc[0]); + glVertex2i (texture->width, 0); + } + glEnd (); + + if (!gl_unbind_pixmap_object (texture_glx->pixo)) { + GST_ERROR ("failed to release GLX pixmap"); + goto out_unbind_fbo; + } + success = TRUE; + +out_unbind_fbo: + if (!gl_unbind_framebuffer_object (texture_glx->fbo)) + success = FALSE; +out_reset_context: + if (texture_glx->gl_context && !gl_set_current_context (&old_cs, NULL)) + success = FALSE; + return success; +} + +static gboolean +gst_vaapi_texture_glx_put_surface (GstVaapiTexture * texture, + GstVaapiSurface * surface, const GstVaapiRectangle * crop_rect, guint flags) +{ + gboolean success; + + GST_VAAPI_DISPLAY_LOCK (GST_VAAPI_TEXTURE_DISPLAY (texture)); + success = gst_vaapi_texture_glx_put_surface_unlocked (texture, surface, + crop_rect, flags); + GST_VAAPI_DISPLAY_UNLOCK (GST_VAAPI_TEXTURE_DISPLAY (texture)); + return success; +} diff --git a/gst-libs/gst/vaapi/gstvaapitexture_glx.h b/gst-libs/gst/vaapi/gstvaapitexture_glx.h new file mode 100644 index 0000000000..db8ddbb49c --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapitexture_glx.h @@ -0,0 +1,42 @@ +/* + * gstvaapitexture_glx.h - VA/GLX texture abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_TEXTURE_GLX_H +#define GST_VAAPI_TEXTURE_GLX_H + +#include + +G_BEGIN_DECLS + +GstVaapiTexture * +gst_vaapi_texture_glx_new (GstVaapiDisplay * display, guint target, + guint format, guint width, guint height); + +GstVaapiTexture * +gst_vaapi_texture_glx_new_wrapped (GstVaapiDisplay * display, guint id, + guint target, guint format); + +G_END_DECLS + +#endif /* GST_VAAPI_TEXTURE_GLX_H */ diff --git a/gst-libs/gst/vaapi/gstvaapitexture_priv.h b/gst-libs/gst/vaapi/gstvaapitexture_priv.h new file mode 100644 index 0000000000..e22df90f7e --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapitexture_priv.h @@ -0,0 +1,127 @@ +/* + * gstvaapitexture_priv.h - VA texture abstraction (private definitions) + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_TEXTURE_PRIV_H +#define GST_VAAPI_TEXTURE_PRIV_H + +G_BEGIN_DECLS + +/** + * GST_VAAPI_TEXTURE_DISPLAY: + * @texture: a #GstVaapiTexture + * + * Macro that evaluates to the @texture's display. + */ +#undef GST_VAAPI_TEXTURE_DISPLAY +#define GST_VAAPI_TEXTURE_DISPLAY(texture) \ + (GST_VAAPI_TEXTURE (texture)->display) + +/** + * GST_VAAPI_TEXTURE_ID: + * @texture: a #GstVaapiTexture + * + * Macro that evaluates to the GL texture id associated with the @texture + */ +#undef GST_VAAPI_TEXTURE_ID +#define GST_VAAPI_TEXTURE_ID(texture) \ + (GST_VAAPI_TEXTURE (texture)->object_id) + +/** + * GST_VAAPI_TEXTURE_TARGET: + * @texture: a #GstVaapiTexture + * + * Macro that evaluates to the GL texture target associated with the @texture + */ +#undef GST_VAAPI_TEXTURE_TARGET +#define GST_VAAPI_TEXTURE_TARGET(texture) \ + (GST_VAAPI_TEXTURE (texture)->gl_target) + +/** + * GST_VAAPI_TEXTURE_FORMAT: + * @texture: a #GstVaapiTexture + * + * Macro that evaluates to the GL texture format associated with the @texture + */ +#undef GST_VAAPI_TEXTURE_FORMAT +#define GST_VAAPI_TEXTURE_FORMAT(texture) \ + (GST_VAAPI_TEXTURE (texture)->gl_format) + +/** + * GST_VAAPI_TEXTURE_WIDTH: + * @texture: a #GstVaapiTexture + * + * Macro that evaluates to the GL texture width associated with the @texture + */ +#undef GST_VAAPI_TEXTURE_WIDTH +#define GST_VAAPI_TEXTURE_WIDTH(texture) \ + (GST_VAAPI_TEXTURE (texture)->width) + +/** + * GST_VAAPI_TEXTURE_HEIGHT: + * @texture: a #GstVaapiTexture + * + * Macro that evaluates to the GL texture height associated with the @texture + */ +#undef GST_VAAPI_TEXTURE_HEIGHT +#define GST_VAAPI_TEXTURE_HEIGHT(texture) \ + (GST_VAAPI_TEXTURE (texture)->height) + +/* GstVaapiTextureClass hooks */ +typedef gboolean (*GstVaapiTexturePutSurfaceFunc) (GstVaapiTexture * texture, + GstVaapiSurface * surface, const GstVaapiRectangle * crop_rect, guint flags); + +/** + * GstVaapiTexture: + * + * Base class for API-dependent textures. + */ +struct _GstVaapiTexture { + /*< private >*/ + GstMiniObject mini_object; + GstVaapiDisplay *display; + GstVaapiID object_id; + + /*< protected >*/ + GstVaapiTexturePutSurfaceFunc put_surface; + guint gl_target; + guint gl_format; + guint width; + guint height; + guint is_wrapped:1; +}; + +GstVaapiTexture * +gst_vaapi_texture_new_internal (GstVaapiDisplay * display, GstVaapiID id, + guint target, guint format, guint width, guint height); + +gpointer +gst_vaapi_texture_get_private (GstVaapiTexture * texture); + +void +gst_vaapi_texture_set_private (GstVaapiTexture * texture, gpointer priv, + GDestroyNotify destroy); + +G_END_DECLS + +#endif /* GST_VAAPI_TEXTURE_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapitexturemap.c b/gst-libs/gst/vaapi/gstvaapitexturemap.c new file mode 100644 index 0000000000..1ca7638380 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapitexturemap.c @@ -0,0 +1,165 @@ +/* + * gstvaapitexture.c - VA texture Hash map + * + * Copyright (C) 2016 Intel Corporation + * Copyright (C) 2016 Igalia S.L. + * + * 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:gstvaapitexturemap + * @short_description: VA/GLX/EGL texture hash map abstraction + */ + +#include "gstvaapitexturemap.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +/** + * GstVaapiTextureMap: + * + * Base class for API-dependent texture map. + */ +struct _GstVaapiTextureMap +{ + GstObject parent_instance; + + /*< private > */ + GHashTable *texture_map; +}; + +/** + * GstVaapiTextureMapClass: + * + * Base class for API-dependent texture map. + */ +struct _GstVaapiTextureMapClass +{ + GstObjectClass parent_class; +}; + +#define MAX_NUM_TEXTURE 10 + +G_DEFINE_TYPE (GstVaapiTextureMap, gst_vaapi_texture_map, GST_TYPE_OBJECT); + +static void +gst_vaapi_texture_map_init (GstVaapiTextureMap * map) +{ + map->texture_map = + g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, + (GDestroyNotify) gst_mini_object_unref); +} + +static void +gst_vaapi_texture_map_finalize (GObject * object) +{ + GstVaapiTextureMap *map = GST_VAAPI_TEXTURE_MAP (object); + + if (map->texture_map) { + g_hash_table_remove_all (map->texture_map); + g_hash_table_destroy (map->texture_map); + } + + G_OBJECT_CLASS (gst_vaapi_texture_map_parent_class)->finalize (object); +} + +static void +gst_vaapi_texture_map_class_init (GstVaapiTextureMapClass * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gst_vaapi_texture_map_finalize; +} + +/** + * gst_vaapi_texture_map_new: + * + * Creates a texture hash map. + * + * Return value: the newly created #GstVaapiTextureMap object + */ +GstVaapiTextureMap * +gst_vaapi_texture_map_new (void) +{ + GstVaapiTextureMap *map; + + map = g_object_new (GST_TYPE_VAAPI_TEXTURE_MAP, NULL); + return map; +} + +/** + * gst_vaapi_texture_map_add: + * @map: a #GstVaapiTextureMap instance + * @texture: a #GstVaapiTexture instance to add + * @id: the id of the GLTexture + * + * Adds @texture into the @map table. + * + * Returns: %TRUE if @texture was inserted correctly. + **/ +gboolean +gst_vaapi_texture_map_add (GstVaapiTextureMap * map, GstVaapiTexture * texture, + guint id) +{ + g_return_val_if_fail (map != NULL, FALSE); + g_return_val_if_fail (map->texture_map != NULL, FALSE); + g_return_val_if_fail (texture != NULL, FALSE); + + if (g_hash_table_size (map->texture_map) > MAX_NUM_TEXTURE) { + GST_WARNING ("Texture map is full"); + return FALSE; + } + + g_hash_table_insert (map->texture_map, GUINT_TO_POINTER (id), texture); + + return TRUE; +} + +/** + * gst_vaapi_texture_map_lookup: + * @map: a #GstVaapiTextureMap instance + * @id: the id of the GLTexture + * + * Search for the #GstVaapiTexture associated with the GLTexture @id + * in the @map. + * + * Returns: a pointer to #GstVaapiTexture if found; otherwise %NULL. + **/ +GstVaapiTexture * +gst_vaapi_texture_map_lookup (GstVaapiTextureMap * map, guint id) +{ + g_return_val_if_fail (map != NULL, NULL); + g_return_val_if_fail (map->texture_map != NULL, NULL); + + return g_hash_table_lookup (map->texture_map, GUINT_TO_POINTER (id)); +} + +/** + * gst_vaapi_texture_map_reset: + * @map: a #GstVaapiTextureMap instance + * + * Removes all the #GstVaapiTexture in the @map. + **/ +void +gst_vaapi_texture_map_reset (GstVaapiTextureMap * map) +{ + g_return_if_fail (map != NULL); + g_return_if_fail (map->texture_map != NULL); + + g_hash_table_remove_all (map->texture_map); +} diff --git a/gst-libs/gst/vaapi/gstvaapitexturemap.h b/gst-libs/gst/vaapi/gstvaapitexturemap.h new file mode 100644 index 0000000000..0e869bb446 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapitexturemap.h @@ -0,0 +1,60 @@ +/* + * gstvaapitexturemap.h - VA texture Hash map + * + * Copyright (C) 2016 Intel Corporation + * Copyright (C) 2016 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_TEXTURE_MAP_H +#define GST_VAAPI_TEXTURE_MAP_H + +#include + +G_BEGIN_DECLS + +typedef struct _GstVaapiTextureMap GstVaapiTextureMap; +typedef struct _GstVaapiTextureMapClass GstVaapiTextureMapClass; + +#define GST_TYPE_VAAPI_TEXTURE_MAP \ + (gst_vaapi_texture_map_get_type ()) +#define GST_VAAPI_TEXTURE_MAP(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_TEXTURE_MAP, GstVaapiTextureMap)) + +GstVaapiTextureMap * +gst_vaapi_texture_map_new (void); + +gboolean +gst_vaapi_texture_map_add (GstVaapiTextureMap * map, + GstVaapiTexture * texture, + guint id); + +GstVaapiTexture * +gst_vaapi_texture_map_lookup (GstVaapiTextureMap * map, + guint id); + +void +gst_vaapi_texture_map_reset (GstVaapiTextureMap * map); + +GType +gst_vaapi_texture_map_get_type (void) G_GNUC_CONST; + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiTextureMap, gst_object_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_TEXTURE_MAP_H */ diff --git a/gst-libs/gst/vaapi/gstvaapitypes.h b/gst-libs/gst/vaapi/gstvaapitypes.h new file mode 100644 index 0000000000..7bbcb4db58 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapitypes.h @@ -0,0 +1,177 @@ +/* + * gstvaapitypes.h - Basic types + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_TYPES_H +#define GST_VAAPI_TYPES_H + +#include + +G_BEGIN_DECLS + +/** + * GstVaapiID: + * + * An integer large enough to hold a generic VA id or a pointer + * wherever necessary. + */ +typedef gsize GstVaapiID; + +/** + * GST_VAAPI_ID: + * @id: an arbitrary integer value + * + * Macro that creates a #GstVaapiID from @id. + */ +#define GST_VAAPI_ID(id) ((GstVaapiID)(id)) + +/** + * GST_VAAPI_ID_INVALID: + * + * Macro that evaluates to an invalid #GstVaapiID value. + */ +#define GST_VAAPI_ID_INVALID GST_VAAPI_ID((gssize)(gint32)-1) + +/** + * GST_VAAPI_ID_FORMAT: + * + * Can be used together with #GST_VAAPI_ID_ARGS to properly output an + * integer value in a printf()-style text message. + * + * ``` C + * printf("id: %" GST_VAAPI_ID_FORMAT "\n", GST_VAAPI_ID_ARGS(id)); + * ``` + */ +#define GST_VAAPI_ID_FORMAT "p" + +/** + * GST_VAAPI_ID_ARGS: + * @id: a #GstVaapiID + * + * Can be used together with #GST_VAAPI_ID_FORMAT to properly output + * an integer value in a printf()-style text message. + */ +#define GST_VAAPI_ID_ARGS(id) GSIZE_TO_POINTER(id) + +/** + * GstVaapiPoint: + * @x: X coordinate + * @y: Y coordinate + * + * A location within a surface. + */ +typedef struct _GstVaapiPoint GstVaapiPoint; +struct _GstVaapiPoint { + guint32 x; + guint32 y; +}; + +/** + * GstVaapiRectangle: + * @x: X coordinate + * @y: Y coordinate + * @width: region width + * @height: region height + * + * A rectangle region within a surface. + */ +typedef struct _GstVaapiRectangle GstVaapiRectangle; +struct _GstVaapiRectangle { + guint32 x; + guint32 y; + guint32 width; + guint32 height; +}; + +/** + * GstVaapiRenderMode: + * @GST_VAAPI_RENDER_MODE_OVERLAY: in this mode, the VA display + * backend renders surfaces with an overlay engine. This means that + * the surface that is currently displayed shall not be re-used + * right away for decoding. i.e. it needs to be retained further, + * until the next surface is to be displayed. + * @GST_VAAPI_RENDER_MODE_TEXTURE: in this modem the VA display + * backend renders surfaces with a textured blit (GPU/3D engine). + * This means that the surface is copied to some intermediate + * backing store, or back buffer of a frame buffer, and is free to + * be re-used right away for decoding. + */ +typedef enum { + GST_VAAPI_RENDER_MODE_OVERLAY = 1, + GST_VAAPI_RENDER_MODE_TEXTURE +} GstVaapiRenderMode; + +/** + * GstVaapiRotation: + * @GST_VAAPI_ROTATION_0: the VA display is not rotated. + * @GST_VAAPI_ROTATION_90: the VA display is rotated by 90°, clockwise. + * @GST_VAAPI_ROTATION_180: the VA display is rotated by 180°, clockwise. + * @GST_VAAPI_ROTATION_270: the VA display is rotated by 270°, clockwise. + * @GST_VAAPI_ROTATION_AUTOMATIC: the VA display is rotated by image-orientating tag. + */ +typedef enum { + GST_VAAPI_ROTATION_0 = 0, + GST_VAAPI_ROTATION_90 = 90, + GST_VAAPI_ROTATION_180 = 180, + GST_VAAPI_ROTATION_270 = 270, + GST_VAAPI_ROTATION_AUTOMATIC = 360, +} GstVaapiRotation; + +/** + * GstVaapiRateControl: + * @GST_VAAPI_RATECONTROL_NONE: No rate control performed by the + * underlying driver + * @GST_VAAPI_RATECONTROL_CQP: Constant QP + * @GST_VAAPI_RATECONTROL_CBR: Constant bitrate + * @GST_VAAPI_RATECONTROL_VCM: Video conference mode + * @GST_VAAPI_RATECONTROL_VBR: Variable bitrate + * @GST_VAAPI_RATECONTROL_VBR_CONSTRAINED: Variable bitrate with peak + * rate higher than average bitrate + * @GST_VAAPI_RATECONTROL_MB: Macroblock based rate control + * @GST_VAAPI_RATECONTROL_ICQ: Intelligent Constant QP, use + * quality_factor to improve subjective quality base on motion + * @GST_VAAPI_RATECONTROL_QVBR: Quality defined VBR, use + * quality_factor to get good enough quality and save bits + * + * The set of allowed rate control values for #GstVaapiRateControl. + * Note: this is only valid for encoders. + */ +typedef enum { + GST_VAAPI_RATECONTROL_NONE = 0, + GST_VAAPI_RATECONTROL_CQP, + GST_VAAPI_RATECONTROL_CBR, + GST_VAAPI_RATECONTROL_VCM, + GST_VAAPI_RATECONTROL_VBR, + GST_VAAPI_RATECONTROL_VBR_CONSTRAINED, + GST_VAAPI_RATECONTROL_MB, + GST_VAAPI_RATECONTROL_ICQ, + GST_VAAPI_RATECONTROL_QVBR, +} GstVaapiRateControl; + +/* Define a mask for GstVaapiRateControl */ +#define GST_VAAPI_RATECONTROL_MASK(RC) \ + (1U << G_PASTE(GST_VAAPI_RATECONTROL_,RC)) + +G_END_DECLS + +#endif /* GST_VAAPI_TYPES_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiutils.c b/gst-libs/gst/vaapi/gstvaapiutils.c new file mode 100644 index 0000000000..ebec319478 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils.c @@ -0,0 +1,1030 @@ +/* + * gstvaapiutils.c - VA-API utilities + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include "gstvaapicompat.h" +#include "gstvaapiutils.h" +#include "gstvaapibufferproxy.h" +#include "gstvaapifilter.h" +#include "gstvaapisubpicture.h" +#include "gstvaapisurface.h" +#include +#include + +#define DEBUG 1 +#include "gstvaapidebug.h" + +/* string case an enum */ +#define STRCASEP(p, x) STRCASE(G_PASTE(p, x)) +#define STRCASE(x) case x: return G_STRINGIFY(x) + +/* string case a macro */ +#define STRCASEM(p, x) case G_PASTE(p, x): return G_STRINGIFY(x) + +#if VA_CHECK_VERSION (0,40,0) +static gchar * +strip_msg (const char *message) +{ + gchar *msg; + + msg = g_strdup (message); + if (!msg) + return NULL; + return g_strstrip (msg); +} + +#if VA_CHECK_VERSION (1,0,0) +static void +gst_vaapi_err (void *data, const char *message) +{ + gchar *msg; + + msg = strip_msg (message); + if (!msg) + return; + GST_ERROR ("%s", msg); + g_free (msg); +} + +static void +gst_vaapi_warning (void *data, const char *message) +{ + gchar *msg; + + msg = strip_msg (message); + if (!msg) + return; + GST_WARNING ("%s", msg); + g_free (msg); +} +#endif + +static void +gst_vaapi_log ( +#if VA_CHECK_VERSION (1,0,0) + void *data, +#endif + const char *message) +{ + gchar *msg; + + msg = strip_msg (message); + if (!msg) + return; + GST_INFO ("%s", msg); + g_free (msg); +} +#endif + +gboolean +vaapi_initialize (VADisplay dpy) +{ + gint major_version, minor_version; + VAStatus status; + +#if VA_CHECK_VERSION (1,0,0) + vaSetErrorCallback (dpy, gst_vaapi_warning, NULL); + vaSetInfoCallback (dpy, gst_vaapi_log, NULL); +#elif VA_CHECK_VERSION (0,40,0) + vaSetInfoCallback (gst_vaapi_log); +#endif + + status = vaInitialize (dpy, &major_version, &minor_version); + +#if VA_CHECK_VERSION (1,0,0) + vaSetErrorCallback (dpy, gst_vaapi_err, NULL); +#endif + + if (!vaapi_check_status (status, "vaInitialize()")) + return FALSE; + + GST_INFO ("VA-API version %d.%d", major_version, minor_version); + return TRUE; +} + +/* Check VA status for success or print out an error */ +gboolean +vaapi_check_status (VAStatus status, const gchar * msg) +{ + if (status != VA_STATUS_SUCCESS) { + GST_DEBUG ("%s: %s", msg, vaErrorStr (status)); + return FALSE; + } + return TRUE; +} + +/* Maps VA buffer */ +gpointer +vaapi_map_buffer (VADisplay dpy, VABufferID buf_id) +{ + VAStatus status; + gpointer data = NULL; + + status = vaMapBuffer (dpy, buf_id, &data); + if (!vaapi_check_status (status, "vaMapBuffer()")) + return NULL; + return data; +} + +/* Unmaps VA buffer */ +void +vaapi_unmap_buffer (VADisplay dpy, VABufferID buf_id, gpointer * pbuf) +{ + VAStatus status; + + if (pbuf) + *pbuf = NULL; + + status = vaUnmapBuffer (dpy, buf_id); + if (!vaapi_check_status (status, "vaUnmapBuffer()")) + return; +} + +/* Creates and maps VA buffer */ +gboolean +vaapi_create_buffer (VADisplay dpy, VAContextID ctx, int type, guint size, + gconstpointer buf, VABufferID * buf_id_ptr, gpointer * mapped_data) +{ + return vaapi_create_n_elements_buffer (dpy, ctx, type, size, buf, buf_id_ptr, + mapped_data, 1); +} + +gboolean +vaapi_create_n_elements_buffer (VADisplay dpy, VAContextID ctx, int type, + guint size, gconstpointer buf, VABufferID * buf_id_ptr, + gpointer * mapped_data, int num_elements) +{ + VABufferID buf_id; + VAStatus status; + gpointer data = (gpointer) buf; + + status = vaCreateBuffer (dpy, ctx, type, size, num_elements, data, &buf_id); + if (!vaapi_check_status (status, "vaCreateBuffer()")) + return FALSE; + + if (mapped_data) { + data = vaapi_map_buffer (dpy, buf_id); + if (!data) + goto error; + *mapped_data = data; + } + + *buf_id_ptr = buf_id; + return TRUE; + + /* ERRORS */ +error: + { + vaapi_destroy_buffer (dpy, &buf_id); + return FALSE; + } +} + +/* Destroy VA buffer */ +void +vaapi_destroy_buffer (VADisplay dpy, VABufferID * buf_id_ptr) +{ + if (!buf_id_ptr || *buf_id_ptr == VA_INVALID_ID) + return; + + vaDestroyBuffer (dpy, *buf_id_ptr); + *buf_id_ptr = VA_INVALID_ID; +} + +/* Return a string representation of a VAProfile */ +const gchar * +string_of_VAProfile (VAProfile profile) +{ + switch (profile) { +#define MAP(profile) \ + STRCASEP(VAProfile, profile) + MAP (MPEG2Simple); + MAP (MPEG2Main); + MAP (MPEG4Simple); + MAP (MPEG4AdvancedSimple); + MAP (MPEG4Main); + MAP (JPEGBaseline); + MAP (H263Baseline); + MAP (H264ConstrainedBaseline); +#if !VA_CHECK_VERSION(1,0,0) + MAP (H264Baseline); +#endif + MAP (H264Main); + MAP (H264High); + MAP (H264MultiviewHigh); + MAP (H264StereoHigh); +#if VA_CHECK_VERSION(1,2,0) + MAP (HEVCMain422_10); + MAP (HEVCMain444); + MAP (HEVCMain444_10); + MAP (HEVCSccMain); + MAP (HEVCSccMain10); + MAP (HEVCSccMain444); +#endif +#if VA_CHECK_VERSION(1,8,0) + MAP (HEVCSccMain444_10); +#endif + MAP (HEVCMain); + MAP (HEVCMain10); + MAP (VC1Simple); + MAP (VC1Main); + MAP (VC1Advanced); + MAP (VP8Version0_3); + MAP (VP9Profile0); + MAP (VP9Profile1); + MAP (VP9Profile2); + MAP (VP9Profile3); +#if VA_CHECK_VERSION(1,8,0) + MAP (AV1Profile0); + MAP (AV1Profile1); +#endif +#undef MAP + default: + break; + } + return ""; +} + +/* Return a string representation of a VAEntrypoint */ +const gchar * +string_of_VAEntrypoint (VAEntrypoint entrypoint) +{ + switch (entrypoint) { +#define MAP(entrypoint) \ + STRCASEP(VAEntrypoint, entrypoint) + MAP (VLD); + MAP (IZZ); + MAP (IDCT); + MAP (MoComp); + MAP (Deblocking); + MAP (EncSlice); + MAP (EncPicture); +#if VA_CHECK_VERSION(0,39,1) + MAP (EncSliceLP); +#endif + MAP (VideoProc); +#if VA_CHECK_VERSION(1,0,0) + MAP (FEI); +#endif +#undef MAP + default: + break; + } + return ""; +} + +/* Return a string representation of a VADisplayAttributeType */ +const gchar * +string_of_VADisplayAttributeType (VADisplayAttribType attribute_type) +{ + switch (attribute_type) { +#define MAP(attribute_type) \ + STRCASEP(VADisplayAttrib, attribute_type) + MAP (Brightness); + MAP (Contrast); + MAP (Hue); + MAP (Saturation); + MAP (BackgroundColor); + MAP (Rotation); + MAP (OutofLoopDeblock); + MAP (CSCMatrix); + MAP (BlendColor); + MAP (OverlayAutoPaintColorKey); + MAP (OverlayColorKey); + MAP (RenderMode); + MAP (RenderDevice); + MAP (RenderRect); +#undef MAP + default: + break; + } + return ""; +} + +/* Return a string representation of a VA chroma format */ +const gchar * +string_of_va_chroma_format (guint chroma_format) +{ + switch (chroma_format) { +#define MAP(value) \ + STRCASEM(VA_RT_FORMAT_, value) + MAP (YUV420); + MAP (YUV422); + MAP (YUV444); + MAP (YUV400); + MAP (RGB16); + MAP (RGB32); + MAP (RGBP); + MAP (YUV420_10BPP); +#if VA_CHECK_VERSION(1,2,0) + MAP (YUV422_10); + MAP (YUV444_10); + MAP (YUV420_12); + MAP (YUV422_12); + MAP (YUV444_12); + MAP (RGB32_10); +#endif +#undef MAP + default: + break; + } + return ""; +} + +const gchar * +string_of_VARateControl (guint rate_control) +{ + switch (rate_control) { + case VA_RC_NONE: + return "None"; + case VA_RC_CQP: + return "CQP"; + case VA_RC_CBR: + return "CBR"; + case VA_RC_VCM: + return "VCM"; + case VA_RC_VBR: + return "VBR"; + case VA_RC_VBR_CONSTRAINED: + return "VBR-Constrained"; +#if VA_CHECK_VERSION(0,39,1) + case VA_RC_MB: + return "MB"; +#endif +#if VA_CHECK_VERSION(1,1,0) + case VA_RC_ICQ: + return "VA_RC_ICQ"; +#endif +#if VA_CHECK_VERSION(1,3,0) + case VA_RC_QVBR: + return "VA_RC_QVBR"; +#endif + default: + break; + } + return ""; +} + +/** + * to_GstVaapiChromaType: + * @va_rt_format: the value of VAConfigAttribRTFormat + * + * Converts the VA_RT_FORMAT_* to #GstVaapiChromaType + * + * Returns: the #GstVaapiChromaType associated to @va_rt_format or + * zero. + **/ +guint +to_GstVaapiChromaType (guint va_rt_format) +{ + if (va_rt_format & VA_RT_FORMAT_YUV420) + return GST_VAAPI_CHROMA_TYPE_YUV420; + if (va_rt_format & VA_RT_FORMAT_YUV422) + return GST_VAAPI_CHROMA_TYPE_YUV422; + if (va_rt_format & VA_RT_FORMAT_YUV444) + return GST_VAAPI_CHROMA_TYPE_YUV444; + if (va_rt_format & VA_RT_FORMAT_YUV411) + return GST_VAAPI_CHROMA_TYPE_YUV411; + if (va_rt_format & VA_RT_FORMAT_YUV400) + return GST_VAAPI_CHROMA_TYPE_YUV400; + if (va_rt_format & VA_RT_FORMAT_RGB32) + return GST_VAAPI_CHROMA_TYPE_RGB32; + if (va_rt_format & VA_RT_FORMAT_RGB16) + return GST_VAAPI_CHROMA_TYPE_RGB16; + if (va_rt_format & VA_RT_FORMAT_RGBP) + return GST_VAAPI_CHROMA_TYPE_RGBP; + if (va_rt_format & VA_RT_FORMAT_YUV420_10BPP) + return GST_VAAPI_CHROMA_TYPE_YUV420_10BPP; +#if VA_CHECK_VERSION(1,2,0) + if (va_rt_format & VA_RT_FORMAT_YUV422_10) + return GST_VAAPI_CHROMA_TYPE_YUV422_10BPP; + if (va_rt_format & VA_RT_FORMAT_YUV444_10) + return GST_VAAPI_CHROMA_TYPE_YUV444_10BPP; + if (va_rt_format & VA_RT_FORMAT_YUV420_12) + return GST_VAAPI_CHROMA_TYPE_YUV420_12BPP; + if (va_rt_format & VA_RT_FORMAT_YUV422_12) + return GST_VAAPI_CHROMA_TYPE_YUV422_12BPP; + if (va_rt_format & VA_RT_FORMAT_YUV444_12) + return GST_VAAPI_CHROMA_TYPE_YUV444_12BPP; + if (va_rt_format & VA_RT_FORMAT_RGB32_10) + return GST_VAAPI_CHROMA_TYPE_RGB32_10BPP; +#endif + return 0; +} + +/** + * from_GstVaapiChromaType: + * @chroma_type: the #GstVaapiChromaType + * + * Converts #GstVaapiChromaType to a chroma format suitable for + * vaCreateSurfaces(). + */ +guint +from_GstVaapiChromaType (guint chroma_type) +{ + guint format; + + switch (chroma_type) { + case GST_VAAPI_CHROMA_TYPE_YUV420: + format = VA_RT_FORMAT_YUV420; + break; + case GST_VAAPI_CHROMA_TYPE_YUV422: + format = VA_RT_FORMAT_YUV422; + break; + case GST_VAAPI_CHROMA_TYPE_YUV444: + format = VA_RT_FORMAT_YUV444; + break; + case GST_VAAPI_CHROMA_TYPE_YUV411: + format = VA_RT_FORMAT_YUV411; + break; + case GST_VAAPI_CHROMA_TYPE_YUV400: + format = VA_RT_FORMAT_YUV400; + break; + case GST_VAAPI_CHROMA_TYPE_RGB32: + format = VA_RT_FORMAT_RGB32; + break; + case GST_VAAPI_CHROMA_TYPE_RGB16: + format = VA_RT_FORMAT_RGB16; + break; + case GST_VAAPI_CHROMA_TYPE_RGBP: + format = VA_RT_FORMAT_RGBP; + break; + case GST_VAAPI_CHROMA_TYPE_YUV420_10BPP: + format = VA_RT_FORMAT_YUV420_10BPP; + break; +#if VA_CHECK_VERSION(1,2,0) + case GST_VAAPI_CHROMA_TYPE_YUV422_10BPP: + format = VA_RT_FORMAT_YUV422_10; + break; + case GST_VAAPI_CHROMA_TYPE_YUV444_10BPP: + format = VA_RT_FORMAT_YUV444_10; + break; + case GST_VAAPI_CHROMA_TYPE_YUV420_12BPP: + format = VA_RT_FORMAT_YUV420_12; + break; + case GST_VAAPI_CHROMA_TYPE_YUV422_12BPP: + format = VA_RT_FORMAT_YUV422_12; + break; + case GST_VAAPI_CHROMA_TYPE_YUV444_12BPP: + format = VA_RT_FORMAT_YUV444_12; + break; + case GST_VAAPI_CHROMA_TYPE_RGB32_10BPP: + format = VA_RT_FORMAT_RGB32_10; + break; +#endif + default: + format = 0; + break; + } + return format; +} + +/** + * from_GstVaapiSubpictureFlags: + * @flags: the #GstVaapiSubpictureFlags + * + * Converts #GstVaapiSubpictureFlags to flags suitable for + * vaAssociateSubpicture(). + */ +guint +from_GstVaapiSubpictureFlags (guint flags) +{ + guint va_flags = 0; + + if (flags & GST_VAAPI_SUBPICTURE_FLAG_GLOBAL_ALPHA) + va_flags |= VA_SUBPICTURE_GLOBAL_ALPHA; +#ifdef VA_SUBPICTURE_PREMULTIPLIED_ALPHA + if (flags & GST_VAAPI_SUBPICTURE_FLAG_PREMULTIPLIED_ALPHA) + flags |= VA_SUBPICTURE_PREMULTIPLIED_ALPHA; +#endif + return va_flags; +} + +/** + * to_GstVaapiSubpictureFlags: + * @flags: the #GstVaapiSubpictureFlags flags to translate + * + * Converts vaQuerySubpictureFormats() @flags to #GstVaapiSubpictureFlags + * flags. + * + * Return value: the #GstVaapiSubpictureFlags flags + */ +guint +to_GstVaapiSubpictureFlags (guint va_flags) +{ + guint flags = 0; + + if (va_flags & VA_SUBPICTURE_GLOBAL_ALPHA) + flags |= GST_VAAPI_SUBPICTURE_FLAG_GLOBAL_ALPHA; +#ifdef VA_SUBPICTURE_PREMULTIPLIED_ALPHA + if (va_flags & VA_SUBPICTURE_PREMULTIPLIED_ALPHA) + flags |= GST_VAAPI_SUBPICTURE_FLAG_PREMULTIPLIED_ALPHA; +#endif + return flags; +} + +/** + * from_GstVideoOverlayFormatFlags: + * @flags: the #GstVideoOverlayFormatFlags flags to translate + * + * Converts #GstVaapiSubpictureFlags to #GstVaapiSubpictureFlags. + * + * Return value: the #GstVaapiSubpictureFlags flags + */ +guint +from_GstVideoOverlayFormatFlags (guint ovl_flags) +{ + guint flags = 0; + + if (ovl_flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA) + flags |= GST_VAAPI_SUBPICTURE_FLAG_PREMULTIPLIED_ALPHA; + if (ovl_flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA) + flags |= GST_VAAPI_SUBPICTURE_FLAG_GLOBAL_ALPHA; + return flags; +} + +/** + * to_GstVideoOverlayFormatFlags: + * @flags: the #GstVaapiSubpictureFlags flags to translate + * + * Converts #GstVaapiSubpictureFlags to #GstVideoOverlayFormatFlags. + * + * Return value: the #GstVideoOverlayFormatFlags flags + */ +guint +to_GstVideoOverlayFormatFlags (guint flags) +{ + guint ovl_flags = 0; + + if (flags & GST_VAAPI_SUBPICTURE_FLAG_PREMULTIPLIED_ALPHA) + ovl_flags |= GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA; + if (flags & GST_VAAPI_SUBPICTURE_FLAG_GLOBAL_ALPHA) + ovl_flags |= GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA; + return ovl_flags; +} + +/** + * from_GstVaapiSurfaceRenderFlags: + * @flags: the #GstVaapiSurfaceRenderFlags + * + * Converts #GstVaapiSurfaceRenderFlags to flags suitable for + * vaPutSurface(). + */ +guint +from_GstVaapiSurfaceRenderFlags (guint flags) +{ + guint va_fields, va_csc; + + /* Picture structure */ + switch (flags & GST_VAAPI_PICTURE_STRUCTURE_MASK) { + case GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD: + va_fields = VA_TOP_FIELD; + break; + case GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD: + va_fields = VA_BOTTOM_FIELD; + break; + default: + va_fields = VA_FRAME_PICTURE; + break; + } + + /* Color standard */ + switch (flags & GST_VAAPI_COLOR_STANDARD_MASK) { +#ifdef VA_SRC_BT601 + case GST_VAAPI_COLOR_STANDARD_ITUR_BT_601: + va_csc = VA_SRC_BT601; + break; +#endif +#ifdef VA_SRC_BT709 + case GST_VAAPI_COLOR_STANDARD_ITUR_BT_709: + va_csc = VA_SRC_BT709; + break; +#endif +#ifdef VA_SRC_SMPTE_240 + case GST_VAAPI_COLOR_STANDARD_SMPTE_240M: + va_csc = VA_SRC_SMPTE_240; + break; +#endif + default: + va_csc = 0; + break; + } + return va_fields | va_csc; +} + +/** + * to_GstVaapiSurfaceStatus: + * @flags: the #GstVaapiSurfaceStatus flags to translate + * + * Converts vaQuerySurfaceStatus() @flags to #GstVaapiSurfaceStatus + * flags. + * + * Return value: the #GstVaapiSurfaceStatus flags + */ +guint +to_GstVaapiSurfaceStatus (guint va_flags) +{ + guint flags; + const guint va_flags_mask = (VASurfaceReady | + VASurfaceRendering | VASurfaceDisplaying); + + /* Check for core status */ + switch (va_flags & va_flags_mask) { + case VASurfaceReady: + flags = GST_VAAPI_SURFACE_STATUS_IDLE; + break; + case VASurfaceRendering: + flags = GST_VAAPI_SURFACE_STATUS_RENDERING; + break; + case VASurfaceDisplaying: + flags = GST_VAAPI_SURFACE_STATUS_DISPLAYING; + break; + default: + flags = 0; + break; + } + + /* Check for encoder status */ + if (va_flags & VASurfaceSkipped) + flags |= GST_VAAPI_SURFACE_STATUS_SKIPPED; + return flags; +} + +/* Translate GstVaapiRotation value to VA-API rotation value */ +guint +from_GstVaapiRotation (guint value) +{ + switch (value) { + case GST_VAAPI_ROTATION_0: + return VA_ROTATION_NONE; + case GST_VAAPI_ROTATION_90: + return VA_ROTATION_90; + case GST_VAAPI_ROTATION_180: + return VA_ROTATION_180; + case GST_VAAPI_ROTATION_270: + return VA_ROTATION_270; + } + GST_ERROR ("unsupported GstVaapiRotation value %d", value); + return VA_ROTATION_NONE; +} + +/* Translate VA-API rotation value to GstVaapiRotation value */ +guint +to_GstVaapiRotation (guint value) +{ + switch (value) { + case VA_ROTATION_NONE: + return GST_VAAPI_ROTATION_0; + case VA_ROTATION_90: + return GST_VAAPI_ROTATION_90; + case VA_ROTATION_180: + return GST_VAAPI_ROTATION_180; + case VA_ROTATION_270: + return GST_VAAPI_ROTATION_270; + } + GST_ERROR ("unsupported VA-API rotation value %d", value); + return GST_VAAPI_ROTATION_0; +} + +guint +from_GstVaapiRateControl (guint value) +{ + switch (value) { + case GST_VAAPI_RATECONTROL_NONE: + return VA_RC_NONE; + case GST_VAAPI_RATECONTROL_CQP: + return VA_RC_CQP; + case GST_VAAPI_RATECONTROL_CBR: + return VA_RC_CBR; + case GST_VAAPI_RATECONTROL_VCM: + return VA_RC_VCM; + case GST_VAAPI_RATECONTROL_VBR: + return VA_RC_VBR; + case GST_VAAPI_RATECONTROL_VBR_CONSTRAINED: + return VA_RC_VBR_CONSTRAINED; +#if VA_CHECK_VERSION(0,39,1) + case GST_VAAPI_RATECONTROL_MB: + return VA_RC_MB; +#endif +#if VA_CHECK_VERSION(1,1,0) + case GST_VAAPI_RATECONTROL_ICQ: + return VA_RC_ICQ; +#endif +#if VA_CHECK_VERSION(1,3,0) + case GST_VAAPI_RATECONTROL_QVBR: + return VA_RC_QVBR; +#endif + } + GST_ERROR ("unsupported GstVaapiRateControl value %u", value); + return VA_RC_NONE; +} + +guint +to_GstVaapiRateControl (guint value) +{ + switch (value) { + case VA_RC_NONE: + return GST_VAAPI_RATECONTROL_NONE; + case VA_RC_CQP: + return GST_VAAPI_RATECONTROL_CQP; + case VA_RC_CBR: + return GST_VAAPI_RATECONTROL_CBR; + case VA_RC_VCM: + return GST_VAAPI_RATECONTROL_VCM; + case VA_RC_VBR: + return GST_VAAPI_RATECONTROL_VBR; + case VA_RC_VBR_CONSTRAINED: + return GST_VAAPI_RATECONTROL_VBR_CONSTRAINED; +#if VA_CHECK_VERSION(0,39,1) + case VA_RC_MB: + return GST_VAAPI_RATECONTROL_MB; +#endif +#if VA_CHECK_VERSION(1,1,0) + case VA_RC_ICQ: + return GST_VAAPI_RATECONTROL_ICQ; +#endif +#if VA_CHECK_VERSION(1,3,0) + case VA_RC_QVBR: + return GST_VAAPI_RATECONTROL_QVBR; +#endif + + } + GST_ERROR ("unsupported VA-API Rate Control value %u", value); + return GST_VAAPI_RATECONTROL_NONE; +} + +/* VPP: translate GstVaapiDeinterlaceMethod to VA deinterlacing algorithm */ +guint +from_GstVaapiDeinterlaceMethod (guint value) +{ + switch (value) { + case GST_VAAPI_DEINTERLACE_METHOD_NONE: + return 0; + case GST_VAAPI_DEINTERLACE_METHOD_BOB: + return VAProcDeinterlacingBob; + case GST_VAAPI_DEINTERLACE_METHOD_WEAVE: + return VAProcDeinterlacingWeave; + case GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE: + return VAProcDeinterlacingMotionAdaptive; + case GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED: + return VAProcDeinterlacingMotionCompensated; + } + GST_ERROR ("unsupported GstVaapiDeinterlaceMethod value %d", value); + return 0; +} + +/* VPP: translate GstVaapiDeinterlaceFlags into VA deinterlacing flags */ +guint +from_GstVaapiDeinterlaceFlags (guint flags) +{ + guint va_flags = 0; + + if (!(flags & GST_VAAPI_DEINTERLACE_FLAG_TFF)) + va_flags |= VA_DEINTERLACING_BOTTOM_FIELD_FIRST; + + if (flags & GST_VAAPI_DEINTERLACE_FLAG_ONEFIELD) + va_flags |= VA_DEINTERLACING_ONE_FIELD; + + if (!(flags & GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD)) + va_flags |= VA_DEINTERLACING_BOTTOM_FIELD; + return va_flags; +} + +/* VPP: translate GstVaapiScaleMethod into VA scaling flags */ +guint +from_GstVaapiScaleMethod (guint value) +{ + guint va_flags; + + switch (value) { + case GST_VAAPI_SCALE_METHOD_DEFAULT: + va_flags = VA_FILTER_SCALING_DEFAULT; + break; + case GST_VAAPI_SCALE_METHOD_FAST: + va_flags = VA_FILTER_SCALING_FAST; + break; + case GST_VAAPI_SCALE_METHOD_HQ: + va_flags = VA_FILTER_SCALING_HQ; + break; + default: + va_flags = 0; + break; + } + return va_flags; +} + +/* VPP: translate VA scaling flags into GstVaapiScale Method */ +guint +to_GstVaapiScaleMethod (guint flags) +{ + GstVaapiScaleMethod method; + + switch (flags) { + case VA_FILTER_SCALING_FAST: + method = GST_VAAPI_SCALE_METHOD_FAST; + break; + case VA_FILTER_SCALING_HQ: + method = GST_VAAPI_SCALE_METHOD_HQ; + break; + default: + method = GST_VAAPI_SCALE_METHOD_DEFAULT; + break; + } + return method; +} + +/* VPP: translate GstVideoOrientationMethod into VA mirror/rotation flags */ +void +from_GstVideoOrientationMethod (guint value, guint * va_mirror, + guint * va_rotation) +{ + *va_mirror = 0; + *va_rotation = 0; + + switch (value) { +#if VA_CHECK_VERSION(1,1,0) + case GST_VIDEO_ORIENTATION_IDENTITY: + *va_mirror = VA_MIRROR_NONE; + *va_rotation = VA_ROTATION_NONE; + break; + case GST_VIDEO_ORIENTATION_HORIZ: + *va_mirror = VA_MIRROR_HORIZONTAL; + *va_rotation = VA_ROTATION_NONE; + break; + case GST_VIDEO_ORIENTATION_VERT: + *va_mirror = VA_MIRROR_VERTICAL; + *va_rotation = VA_ROTATION_NONE; + break; + case GST_VIDEO_ORIENTATION_90R: + *va_mirror = VA_MIRROR_NONE; + *va_rotation = VA_ROTATION_90; + break; + case GST_VIDEO_ORIENTATION_180: + *va_mirror = VA_MIRROR_NONE; + *va_rotation = VA_ROTATION_180; + break; + case GST_VIDEO_ORIENTATION_90L: + *va_mirror = VA_MIRROR_NONE; + *va_rotation = VA_ROTATION_270; + break; + case GST_VIDEO_ORIENTATION_UL_LR: + *va_mirror = VA_MIRROR_HORIZONTAL; + *va_rotation = VA_ROTATION_90; + break; + case GST_VIDEO_ORIENTATION_UR_LL: + *va_mirror = VA_MIRROR_VERTICAL; + *va_rotation = VA_ROTATION_90; + break; +#endif + default: + break; + } +} + +/** + * from_GstVaapiBufferMemoryType: + * @type: a #GstVaapiBufferMemoryType + * + * Returns: the VA's memory type symbol + **/ +guint +from_GstVaapiBufferMemoryType (guint type) +{ + guint va_type; + + switch (type) { +#if VA_CHECK_VERSION(1,1,0) + case GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF2: + va_type = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2; + break; +#endif + case GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF: + va_type = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME; + break; + case GST_VAAPI_BUFFER_MEMORY_TYPE_GEM_BUF: + va_type = VA_SURFACE_ATTRIB_MEM_TYPE_KERNEL_DRM; + break; + case GST_VAAPI_BUFFER_MEMORY_TYPE_V4L2: + va_type = VA_SURFACE_ATTRIB_MEM_TYPE_V4L2; + break; + case GST_VAAPI_BUFFER_MEMORY_TYPE_USER_PTR: + va_type = VA_SURFACE_ATTRIB_MEM_TYPE_USER_PTR; + break; + default: + va_type = 0; + break; + } + return va_type; +} + +/** + * to_GstVaapiBufferMemoryType: + * @va_type: a VA's memory type symbol + * + * It will return the first "supported" memory type from @va_type bit + * flag. + * + * Returns: a #GstVaapiBufferMemoryType or 0 if unknown. + **/ +guint +to_GstVaapiBufferMemoryType (guint va_type) +{ +#if VA_CHECK_VERSION(1,1,0) + if ((va_type & VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2)) + return GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF2; +#endif + if ((va_type & VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME)) + return GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF; + if ((va_type & VA_SURFACE_ATTRIB_MEM_TYPE_KERNEL_DRM)) + return GST_VAAPI_BUFFER_MEMORY_TYPE_GEM_BUF; + if ((va_type & VA_SURFACE_ATTRIB_MEM_TYPE_V4L2)) + return GST_VAAPI_BUFFER_MEMORY_TYPE_V4L2; + if ((va_type & VA_SURFACE_ATTRIB_MEM_TYPE_USER_PTR)) + return GST_VAAPI_BUFFER_MEMORY_TYPE_USER_PTR; + return 0; +} + +/** + * from_GstVideoColorimetry: + * @colorimetry: a #GstVideoColorimetry type + * + * VPP: maps the #GstVideoColorimetry type to the VAProcColorStandardType. If + * @colorimetry is NULL or colorimetry->primaries are unknown, then returns + * VAProcColorStandardNone. If there is no 1:1 correlation, then returns + * VAProcColorStandardExplicit. Otherwise, the correlating + * VAProcColorStandardType is returned. + * + * Returns: a VAProcColorStandardType. + **/ +guint +from_GstVideoColorimetry (const GstVideoColorimetry * const colorimetry) +{ +#if VA_CHECK_VERSION(1,2,0) + if (!colorimetry + || colorimetry->primaries == GST_VIDEO_COLOR_PRIMARIES_UNKNOWN) + return VAProcColorStandardNone; + if (gst_video_colorimetry_matches (colorimetry, GST_VIDEO_COLORIMETRY_BT709)) + return VAProcColorStandardBT709; + /* NOTE: VAProcColorStandardBT2020 in VAAPI is the same as + * GST_VIDEO_COLORIMETRY_BT2020_10 in gstreamer. */ + if (gst_video_colorimetry_matches (colorimetry, + GST_VIDEO_COLORIMETRY_BT2020_10) || + gst_video_colorimetry_matches (colorimetry, GST_VIDEO_COLORIMETRY_BT2020)) + return VAProcColorStandardBT2020; + if (gst_video_colorimetry_matches (colorimetry, GST_VIDEO_COLORIMETRY_BT601)) + return VAProcColorStandardBT601; + if (gst_video_colorimetry_matches (colorimetry, + GST_VIDEO_COLORIMETRY_SMPTE240M)) + return VAProcColorStandardSMPTE240M; + + return VAProcColorStandardExplicit; +#else + return VAProcColorStandardNone; +#endif +} + +/** + * from_GstVideoColorRange: + * @value: a #GstVideoColorRange + * + * VPP: maps the #GstVideoColorRange to the VA value. + * + * Returns: the VA color range. + **/ +guint +from_GstVideoColorRange (const GstVideoColorRange value) +{ +#if VA_CHECK_VERSION(1,2,0) + switch (value) { + case GST_VIDEO_COLOR_RANGE_0_255: + return VA_SOURCE_RANGE_FULL; + case GST_VIDEO_COLOR_RANGE_16_235: + return VA_SOURCE_RANGE_REDUCED; + default: + return VA_SOURCE_RANGE_UNKNOWN; + } +#else + return 0; +#endif +} diff --git a/gst-libs/gst/vaapi/gstvaapiutils.h b/gst-libs/gst/vaapi/gstvaapiutils.h new file mode 100644 index 0000000000..315913229b --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils.h @@ -0,0 +1,178 @@ +/* + * gstvaapiutils.h - VA-API utilities + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_UTILS_H +#define GST_VAAPI_UTILS_H + +#include +#include +#include + +/** calls vaInitialize() redirecting the logging mechanism */ +G_GNUC_INTERNAL +gboolean +vaapi_initialize (VADisplay dpy); + +/** Check VA status for success or print out an error */ +G_GNUC_INTERNAL +gboolean +vaapi_check_status (VAStatus status, const gchar *msg); + +/** Maps VA buffer */ +G_GNUC_INTERNAL +gpointer +vaapi_map_buffer (VADisplay dpy, VABufferID buf_id); + +/** Unmaps VA buffer */ +G_GNUC_INTERNAL +void +vaapi_unmap_buffer (VADisplay dpy, VABufferID buf_id, void **pbuf); + +/** Creates and maps VA buffer */ +G_GNUC_INTERNAL +gboolean +vaapi_create_buffer (VADisplay dpy, VAContextID ctx, int type, guint size, + gconstpointer data, VABufferID * buf_id, gpointer * mapped_data); + +G_GNUC_INTERNAL +gboolean +vaapi_create_n_elements_buffer (VADisplay dpy, VAContextID ctx, int type, + guint size, gconstpointer data, VABufferID * buf_id, gpointer * mapped_data, + int num_elements); + +/** Destroy VA buffer */ +G_GNUC_INTERNAL +void +vaapi_destroy_buffer (VADisplay dpy, VABufferID * buf_id); + +/** Return a string representation of a VAProfile */ +G_GNUC_INTERNAL +const gchar * +string_of_VAProfile (VAProfile profile); + +/** Return a string representation of a VAEntrypoint */ +G_GNUC_INTERNAL +const gchar * +string_of_VAEntrypoint (VAEntrypoint entrypoint); + +/* Return a string representation of a VADisplayAttributeType */ +G_GNUC_INTERNAL +const gchar * +string_of_VADisplayAttributeType (VADisplayAttribType attribute_type); + +/* Return a string representation of a VA chroma format */ +G_GNUC_INTERNAL +const gchar * +string_of_va_chroma_format (guint chroma_format); + +G_GNUC_INTERNAL +const gchar * +string_of_VARateControl (guint rate_control); + +G_GNUC_INTERNAL +guint +to_GstVaapiChromaType (guint va_rt_format); + +G_GNUC_INTERNAL +guint +from_GstVaapiChromaType (guint chroma_type); + +G_GNUC_INTERNAL +guint +from_GstVaapiSubpictureFlags (guint flags); + +G_GNUC_INTERNAL +guint +to_GstVaapiSubpictureFlags (guint va_flags); + +G_GNUC_INTERNAL +guint +from_GstVideoOverlayFormatFlags (guint ovl_flags); + +G_GNUC_INTERNAL +guint +to_GstVideoOverlayFormatFlags (guint flags); + +G_GNUC_INTERNAL +guint +from_GstVaapiSurfaceRenderFlags (guint flags); + +G_GNUC_INTERNAL +guint +to_GstVaapiSurfaceStatus (guint va_flags); + +G_GNUC_INTERNAL +guint +from_GstVaapiRotation (guint value); + +G_GNUC_INTERNAL +guint +to_GstVaapiRotation (guint value); + +G_GNUC_INTERNAL +guint +from_GstVaapiRateControl (guint value); + +G_GNUC_INTERNAL +guint +to_GstVaapiRateControl (guint value); + +G_GNUC_INTERNAL +guint +from_GstVaapiDeinterlaceMethod (guint value); + +G_GNUC_INTERNAL +guint +from_GstVaapiDeinterlaceFlags (guint flags); + +G_GNUC_INTERNAL +guint +from_GstVaapiScaleMethod (guint value); + +G_GNUC_INTERNAL +guint +to_GstVaapiScaleMethod (guint flags); + +G_GNUC_INTERNAL +void +from_GstVideoOrientationMethod (guint value, guint * va_mirror, + guint * va_rotation); + +G_GNUC_INTERNAL +guint +from_GstVaapiBufferMemoryType (guint type); + +G_GNUC_INTERNAL +guint +to_GstVaapiBufferMemoryType (guint va_type); + +G_GNUC_INTERNAL +guint +from_GstVideoColorimetry (const GstVideoColorimetry *const colorimetry); + +G_GNUC_INTERNAL +guint +from_GstVideoColorRange (const GstVideoColorRange value); + +#endif /* GST_VAAPI_UTILS_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiutils_core.c b/gst-libs/gst/vaapi/gstvaapiutils_core.c new file mode 100644 index 0000000000..7c98208d42 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_core.c @@ -0,0 +1,227 @@ +/* + * gstvaapiutils_core.c - VA-API utilities (Core, MT-safe) + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include "gstvaapicompat.h" +#include "gstvaapiimage.h" +#include "gstvaapiutils.h" +#include "gstvaapiutils_core.h" +#include "gstvaapidisplay_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +/** + * gst_vaapi_get_config_attribute: + * @display: a #GstVaapiDisplay + * @profile: a VA profile + * @entrypoint: a VA entrypoint + * @type: a VA config attribute type + * @out_value_ptr: return location for the config attribute value + * + * Determines the value for the VA config attribute @type and the + * given @profile/@entrypoint pair. If @out_value_ptr is %NULL, then + * this functions acts as a way to query whether the underlying VA + * driver supports the specified attribute @type, no matter the + * returned value. + * + * Note: this function only returns success if the VA driver does + * actually know about this config attribute type and that it returned + * a valid value for it. + * + * Return value: %TRUE if the VA driver knows about the requested + * config attribute and returned a valid value, %FALSE otherwise + */ +gboolean +gst_vaapi_get_config_attribute (GstVaapiDisplay * display, VAProfile profile, + VAEntrypoint entrypoint, VAConfigAttribType type, guint * out_value_ptr) +{ + VAConfigAttrib attrib; + VAStatus status; + + g_return_val_if_fail (display != NULL, FALSE); + + GST_VAAPI_DISPLAY_LOCK (display); + attrib.type = type; + status = vaGetConfigAttributes (GST_VAAPI_DISPLAY_VADISPLAY (display), + profile, entrypoint, &attrib, 1); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!vaapi_check_status (status, "vaGetConfigAttributes()")) + return FALSE; + if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) + return FALSE; + + if (out_value_ptr) + *out_value_ptr = attrib.value; + return TRUE; +} + +static VASurfaceAttrib * +get_surface_attributes (GstVaapiDisplay * display, VAConfigID config, + guint * num_attribs) +{ + VASurfaceAttrib *surface_attribs = NULL; + guint num_surface_attribs = 0; + VAStatus va_status; + + if (config == VA_INVALID_ID) + goto error; + + GST_VAAPI_DISPLAY_LOCK (display); + va_status = vaQuerySurfaceAttributes (GST_VAAPI_DISPLAY_VADISPLAY (display), + config, NULL, &num_surface_attribs); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!vaapi_check_status (va_status, "vaQuerySurfaceAttributes()")) + goto error; + + surface_attribs = g_malloc (num_surface_attribs * sizeof (*surface_attribs)); + if (!surface_attribs) + goto error; + + GST_VAAPI_DISPLAY_LOCK (display); + va_status = vaQuerySurfaceAttributes (GST_VAAPI_DISPLAY_VADISPLAY (display), + config, surface_attribs, &num_surface_attribs); + GST_VAAPI_DISPLAY_UNLOCK (display); + if (!vaapi_check_status (va_status, "vaQuerySurfaceAttributes()")) + goto error; + + if (num_attribs) + *num_attribs = num_surface_attribs; + return surface_attribs; + + /* ERRORS */ +error: + { + if (num_attribs) + *num_attribs = -1; + if (surface_attribs) + g_free (surface_attribs); + return NULL; + } +} + +/** + * gst_vaapi_config_surface_attribures_get: + * @display: a #GstVaapiDisplay + * @config: a #VAConfigID + * + * Retrieves the possible surface attributes for the supplied config. + * + * Returns: (transfer full): returns a #GstVaapiConfigSurfaceAttributes + **/ +GstVaapiConfigSurfaceAttributes * +gst_vaapi_config_surface_attributes_get (GstVaapiDisplay * display, + VAConfigID config) +{ + VASurfaceAttrib *surface_attribs; + guint i, num_pixel_formats = 0, num_surface_attribs = 0; + GstVaapiConfigSurfaceAttributes *attribs = NULL; + + surface_attribs = + get_surface_attributes (display, config, &num_surface_attribs); + if (!surface_attribs) + return NULL; + + attribs = g_slice_new0 (GstVaapiConfigSurfaceAttributes); + if (!attribs) + goto error; + + for (i = 0; i < num_surface_attribs; i++) { + const VASurfaceAttrib *const attrib = &surface_attribs[i]; + + switch (attrib->type) { + case VASurfaceAttribPixelFormat: + if ((attrib->flags & VA_SURFACE_ATTRIB_SETTABLE)) { + GstVideoFormat fmt; + + fmt = gst_vaapi_video_format_from_va_fourcc (attrib->value.value.i); + if (fmt != GST_VIDEO_FORMAT_UNKNOWN) + num_pixel_formats++; + } + break; + case VASurfaceAttribMinWidth: + attribs->min_width = attrib->value.value.i; + break; + case VASurfaceAttribMinHeight: + attribs->min_height = attrib->value.value.i; + break; + case VASurfaceAttribMaxWidth: + attribs->max_width = attrib->value.value.i; + break; + case VASurfaceAttribMaxHeight: + attribs->max_height = attrib->value.value.i; + break; + case VASurfaceAttribMemoryType: + attribs->mem_types = attrib->value.value.i; + break; + default: + break; + } + } + + if (num_pixel_formats == 0) { + attribs->formats = NULL; + } else { + attribs->formats = g_array_sized_new (FALSE, FALSE, sizeof (GstVideoFormat), + num_pixel_formats); + + for (i = 0; i < num_surface_attribs; i++) { + const VASurfaceAttrib *const attrib = &surface_attribs[i]; + GstVideoFormat fmt; + + if (attrib->type != VASurfaceAttribPixelFormat) + continue; + if (!(attrib->flags & VA_SURFACE_ATTRIB_SETTABLE)) + continue; + + fmt = gst_vaapi_video_format_from_va_fourcc (attrib->value.value.i); + if (fmt == GST_VIDEO_FORMAT_UNKNOWN) + continue; + g_array_append_val (attribs->formats, fmt); + } + } + + g_free (surface_attribs); + return attribs; + + /* ERRORS */ +error: + { + g_free (surface_attribs); + gst_vaapi_config_surface_attributes_free (attribs); + return NULL; + } +} + +void +gst_vaapi_config_surface_attributes_free (GstVaapiConfigSurfaceAttributes * + attribs) +{ + if (!attribs) + return; + + if (attribs->formats) + g_array_unref (attribs->formats); + g_slice_free (GstVaapiConfigSurfaceAttributes, attribs); +} diff --git a/gst-libs/gst/vaapi/gstvaapiutils_core.h b/gst-libs/gst/vaapi/gstvaapiutils_core.h new file mode 100644 index 0000000000..d900567bbb --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_core.h @@ -0,0 +1,72 @@ +/* + * gstvaapiutils_core.h - VA-API utilities (Core, MT-safe) + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_UTILS_CORE_H +#define GST_VAAPI_UTILS_CORE_H + +#include + +G_BEGIN_DECLS + +typedef struct _GstVaapiConfigSurfaceAttributes GstVaapiConfigSurfaceAttributes; + + +/** + * GstVaapiConfigSurfaceAttributes: + * @min_width: Minimal width in pixels. + * @min_height: Minimal height in pixels. + * @max_width: Maximal width in pixels. + * @max_height: Maximal height in pixels. + * @mem_types: Surface memory type expressed in bit fields. + * @formats: Array of avialable GstVideoFormats of a surface in a VAConfig. + * + * Represents the possible surface attributes for the supplied config. + **/ +struct _GstVaapiConfigSurfaceAttributes +{ + gint min_width; + gint min_height; + gint max_width; + gint max_height; + guint mem_types; + GArray *formats; +}; + +/* Gets attribute value for the supplied profile/entrypoint pair (MT-safe) */ +G_GNUC_INTERNAL +gboolean +gst_vaapi_get_config_attribute (GstVaapiDisplay * display, VAProfile profile, + VAEntrypoint entrypoint, VAConfigAttribType type, guint * out_value_ptr); + +G_GNUC_INTERNAL +GstVaapiConfigSurfaceAttributes * +gst_vaapi_config_surface_attributes_get (GstVaapiDisplay * display, VAConfigID config); + +G_GNUC_INTERNAL +void +gst_vaapi_config_surface_attributes_free (GstVaapiConfigSurfaceAttributes * attribs); + +G_END_DECLS + +#endif /* GST_VAAPI_UTILS_CORE_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiutils_egl.c b/gst-libs/gst/vaapi/gstvaapiutils_egl.c new file mode 100644 index 0000000000..99ae37d291 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_egl.c @@ -0,0 +1,1485 @@ +/* + * gstvaapiutils_egl.c - EGL utilities + * + * Copyright (C) 2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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 + */ + +#include "sysdeps.h" +#include "gstvaapiutils_egl.h" +#if USE_GST_GL_HELPERS +# include +# if GST_GL_HAVE_PLATFORM_EGL +# include +# endif +#endif + +#define DEBUG 1 +#include "gstvaapidebug.h" + +typedef struct egl_message_s EglMessage; +struct egl_message_s +{ + EglObject base; + EglContextRunFunc func; + gpointer args; +}; + +static void +egl_message_finalize (EglMessage * msg) +{ +} + +/* ------------------------------------------------------------------------- */ +// Utility functions + +typedef struct gl_version_info_s GlVersionInfo; +struct gl_version_info_s +{ + guint gles_version; + guint gl_api_bit; + guint gl_api; + const gchar *gl_api_name; +}; + +static const GlVersionInfo gl_version_info[] = { + {0, EGL_OPENGL_BIT, EGL_OPENGL_API, "OpenGL"}, + {1, EGL_OPENGL_ES_BIT, EGL_OPENGL_ES_API, "OpenGL_ES"}, + {2, EGL_OPENGL_ES2_BIT, EGL_OPENGL_ES_API, "OpenGL_ES2"}, + {3, EGL_OPENGL_ES3_BIT_KHR, EGL_OPENGL_ES_API, "OpenGL_ES3"}, + {0,} +}; + +static const GlVersionInfo * +gl_version_info_lookup (guint gles_version) +{ + const GlVersionInfo *vinfo; + + for (vinfo = gl_version_info; vinfo->gl_api_bit != 0; vinfo++) { + if (vinfo->gles_version == gles_version) + return vinfo; + } + return NULL; +} + +static const GlVersionInfo * +gl_version_info_lookup_by_api (guint api) +{ + const GlVersionInfo *vinfo; + + for (vinfo = gl_version_info; vinfo->gl_api_bit != 0; vinfo++) { + if (api & vinfo->gl_api_bit) + return vinfo; + } + return NULL; +} + +static const GlVersionInfo * +gl_version_info_lookup_by_api_name (const gchar * name) +{ + const GlVersionInfo *vinfo; + + for (vinfo = gl_version_info; vinfo->gl_api_bit != 0; vinfo++) { + if (g_strcmp0 (vinfo->gl_api_name, name) == 0) + return vinfo; + } + return NULL; +} + +static gboolean +g_strv_match_string (gchar ** extensions_list, const gchar * name) +{ + if (extensions_list) { + for (; *extensions_list != NULL; extensions_list++) { + if (g_strcmp0 (*extensions_list, name) == 0) + return TRUE; + } + } + return FALSE; +} + +static gboolean +egl_find_attrib_value (const EGLint * attribs, EGLint type, EGLint * value_ptr) +{ + while (attribs[0] != EGL_NONE) { + if (attribs[0] == type) { + if (value_ptr) + *value_ptr = attribs[1]; + return TRUE; + } + attribs += 2; + } + return FALSE; +} + +/* ------------------------------------------------------------------------- */ +// Basic objects + +#define EGL_OBJECT(object) ((EglObject *)(object)) +#define EGL_OBJECT_CLASS(klass) ((EglObjectClass *)(klass)) + +#define EGL_OBJECT_DEFINE_CLASS_WITH_CODE(TN, t_n, code) \ +static void \ +G_PASTE(t_n,_finalize) (TN * object); \ + \ +static inline const EglObjectClass * \ +G_PASTE(t_n,_class) (void) \ +{ \ + static G_PASTE(TN,Class) g_class; \ + static gsize g_class_init = FALSE; \ + \ + if (g_once_init_enter (&g_class_init)) { \ + GstVaapiMiniObjectClass *const object_class = \ + GST_VAAPI_MINI_OBJECT_CLASS (&g_class); \ + code; \ + object_class->size = sizeof (TN); \ + object_class->finalize = (GDestroyNotify) \ + G_PASTE(t_n,_finalize); \ + g_once_init_leave (&g_class_init, TRUE); \ + } \ + return EGL_OBJECT_CLASS (&g_class); \ +} + +#define EGL_OBJECT_DEFINE_CLASS(TN, t_n) \ + EGL_OBJECT_DEFINE_CLASS_WITH_CODE (TN, t_n, /**/) + +static inline gpointer +egl_object_new (const EglObjectClass * klass) +{ + return gst_vaapi_mini_object_new (GST_VAAPI_MINI_OBJECT_CLASS (klass)); +} + +static inline gpointer +egl_object_new0 (const EglObjectClass * klass) +{ + return gst_vaapi_mini_object_new0 (GST_VAAPI_MINI_OBJECT_CLASS (klass)); +} + +typedef struct egl_object_class_s EglMessageClass; +typedef struct egl_object_class_s EglVTableClass; +typedef struct egl_object_class_s EglDisplayClass; +typedef struct egl_object_class_s EglConfigClass; +typedef struct egl_object_class_s EglContextClass; +typedef struct egl_object_class_s EglSurfaceClass; +typedef struct egl_object_class_s EglProgramClass; +typedef struct egl_object_class_s EglWindowClass; + +EGL_OBJECT_DEFINE_CLASS (EglMessage, egl_message); +EGL_OBJECT_DEFINE_CLASS (EglVTable, egl_vtable); +EGL_OBJECT_DEFINE_CLASS (EglDisplay, egl_display); +EGL_OBJECT_DEFINE_CLASS (EglConfig, egl_config); +EGL_OBJECT_DEFINE_CLASS (EglContext, egl_context); +EGL_OBJECT_DEFINE_CLASS (EglSurface, egl_surface); +EGL_OBJECT_DEFINE_CLASS (EglProgram, egl_program); +EGL_OBJECT_DEFINE_CLASS (EglWindow, egl_window); + +/* ------------------------------------------------------------------------- */ +// Desktop OpenGL and OpenGL|ES dispatcher (vtable) + +static GMutex gl_vtables_lock; +static EglVTable *gl_vtables[4]; + +#if (USE_GLES_VERSION_MASK & (1U << 0)) +static const gchar *gl_library_names[] = { + "libGL.la", + "libGL.so.1", + NULL +}; +#endif + +#if (USE_GLES_VERSION_MASK & (1U << 1)) +static const gchar *gles1_library_names[] = { + "libGLESv1_CM.la", + "libGLESv1_CM.so.1", + NULL +}; +#endif + +#if (USE_GLES_VERSION_MASK & (1U << 2)) +static const gchar *gles2_library_names[] = { + "libGLESv2.la", + "libGLESv2.so.2", + NULL +}; +#endif + +static const gchar **gl_library_names_group[] = { +#if (USE_GLES_VERSION_MASK & (1U << 0)) + gl_library_names, +#endif + NULL +}; + +static const gchar **gles1_library_names_group[] = { +#if (USE_GLES_VERSION_MASK & (1U << 1)) + gles1_library_names, +#endif + NULL +}; + +static const gchar **gles2_library_names_group[] = { +#if (USE_GLES_VERSION_MASK & (1U << 2)) + gles2_library_names, +#endif + NULL +}; + +static const gchar **gles3_library_names_group[] = { +#if (USE_GLES_VERSION_MASK & (1U << 3)) + gles2_library_names, +#endif + NULL +}; + +static const gchar *** +egl_vtable_get_library_names_group (guint gles_version) +{ + const gchar ***library_names_group; + + switch (gles_version) { + case 0: + library_names_group = gl_library_names_group; + break; + case 1: + library_names_group = gles1_library_names_group; + break; + case 2: + library_names_group = gles2_library_names_group; + break; + case 3: + library_names_group = gles3_library_names_group; + break; + default: + library_names_group = NULL; + break; + } + return library_names_group; +} + +static gboolean +egl_vtable_check_extension (EglVTable * vtable, EGLDisplay display, + gboolean is_egl, const gchar * group_name, guint * group_ptr) +{ + gchar ***extensions_list; + const gchar *extensions; + + g_return_val_if_fail (group_name != NULL, FALSE); + g_return_val_if_fail (group_ptr != NULL, FALSE); + + if (*group_ptr > 0) + return TRUE; + + GST_DEBUG ("check for %s extension %s", is_egl ? "EGL" : "GL", group_name); + + if (is_egl) { + if (!vtable->egl_extensions) { + extensions = eglQueryString (display, EGL_EXTENSIONS); + if (!extensions) + return FALSE; + GST_DEBUG ("EGL extensions: %s", extensions); + vtable->egl_extensions = g_strsplit (extensions, " ", 0); + } + extensions_list = &vtable->egl_extensions; + } else { + if (!vtable->gl_extensions) { + extensions = (const gchar *) vtable->glGetString (GL_EXTENSIONS); + if (!extensions) + return FALSE; + GST_DEBUG ("GL extensions: %s", extensions); + vtable->gl_extensions = g_strsplit (extensions, " ", 0); + } + extensions_list = &vtable->gl_extensions; + } + if (!g_strv_match_string (*extensions_list, group_name)) + return FALSE; + + GST_LOG (" found %s extension %s", is_egl ? "EGL" : "GL", group_name); + (*group_ptr)++; + return TRUE; +} + +static gboolean +egl_vtable_load_symbol (EglVTable * vtable, EGLDisplay display, gboolean is_egl, + const gchar * symbol_name, gpointer * symbol_ptr, + const gchar * group_name, guint * group_ptr) +{ + void (*symbol) (void); + + if (group_ptr && !*group_ptr) { + if (!egl_vtable_check_extension (vtable, display, is_egl, group_name, + group_ptr)) + return FALSE; + } + + if (is_egl) { + symbol = eglGetProcAddress (symbol_name); + } else { + if (!g_module_symbol (vtable->base.handle.p, symbol_name, + (gpointer *) & symbol)) + return FALSE; + } + if (!symbol) + return FALSE; + + GST_LOG (" found symbol %s", symbol_name); + if (symbol_ptr) + *symbol_ptr = symbol; + if (group_ptr) + (*group_ptr)++; + return TRUE; +} + +static gboolean +egl_vtable_load_egl_symbols (EglVTable * vtable, EGLDisplay display) +{ + guint n = 0; + +#define EGL_DEFINE_EXTENSION(NAME) do { \ + egl_vtable_check_extension (vtable, display, TRUE, \ + "EGL_" G_STRINGIFY (NAME), \ + &vtable->GL_PROTO_GEN_CONCAT(has_EGL_,NAME)); \ + } while (0); + +#define EGL_PROTO_BEGIN(NAME, TYPE, EXTENSION) do { \ + n += egl_vtable_load_symbol (vtable, display, TRUE, \ + G_STRINGIFY(GL_PROTO_GEN_CONCAT(egl,NAME)), \ + (gpointer *) &vtable->GL_PROTO_GEN_CONCAT(egl,NAME), \ + "EGL_" G_STRINGIFY(EXTENSION), \ + &vtable->GL_PROTO_GEN_CONCAT(has_EGL_,EXTENSION)); \ + } while (0); + +#include "egl_vtable.h" + + vtable->num_egl_symbols = n; + return TRUE; +} + +static gboolean +egl_vtable_load_gl_symbols (EglVTable * vtable, EGLDisplay display) +{ + guint n = 0; + + vtable->has_GL_CORE_1_0 = 1; + vtable->has_GL_CORE_1_1 = 1; + vtable->has_GL_CORE_1_3 = 1; + vtable->has_GL_CORE_2_0 = 1; + +#define GL_DEFINE_EXTENSION(NAME) do { \ + egl_vtable_check_extension (vtable, display, FALSE, \ + "GL_" G_STRINGIFY (NAME), \ + &vtable->GL_PROTO_GEN_CONCAT(has_GL_,NAME)); \ + } while (0); + +#define GL_PROTO_BEGIN(NAME, TYPE, EXTENSION) do { \ + n += egl_vtable_load_symbol (vtable, display, FALSE, \ + G_STRINGIFY(GL_PROTO_GEN_CONCAT(gl,NAME)), \ + (gpointer *) &vtable->GL_PROTO_GEN_CONCAT(gl,NAME), \ + "GL_" G_STRINGIFY(EXTENSION), \ + &vtable->GL_PROTO_GEN_CONCAT(has_GL_,EXTENSION)); \ + } while (0); + +#include "egl_vtable.h" + + --vtable->has_GL_CORE_1_0; + --vtable->has_GL_CORE_1_1; + --vtable->has_GL_CORE_1_3; + --vtable->has_GL_CORE_2_0; + + vtable->num_gl_symbols = n; + return TRUE; +} + +static gboolean +egl_vtable_try_load_library (EglVTable * vtable, const gchar * name) +{ + if (vtable->base.handle.p) + g_module_close (vtable->base.handle.p); + vtable->base.handle.p = g_module_open (name, + G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); + if (!vtable->base.handle.p) + return FALSE; + + GST_DEBUG ("loaded backend: %s", g_module_name (vtable->base.handle.p)); + return TRUE; +} + +static gboolean +egl_vtable_find_library (EglVTable * vtable) +{ + const gchar ***library_names_ptr = + egl_vtable_get_library_names_group (vtable->gles_version); + + if (!library_names_ptr) + return FALSE; + + for (; *library_names_ptr != NULL; library_names_ptr++) { + const gchar **library_name_ptr = *library_names_ptr; + for (; *library_name_ptr != NULL; library_name_ptr++) { + if (egl_vtable_try_load_library (vtable, *library_name_ptr)) + return TRUE; + } + } + return FALSE; +} + +static gboolean +egl_vtable_init (EglVTable * vtable, EGLDisplay display, guint gles_version) +{ + GST_DEBUG ("initialize for OpenGL|ES API version %d", gles_version); + + vtable->gles_version = gles_version; + if (!egl_vtable_find_library (vtable)) + return FALSE; + if (!egl_vtable_load_egl_symbols (vtable, display)) + return FALSE; + return TRUE; +} + +static void +egl_vtable_finalize (EglVTable * vtable) +{ + g_strfreev (vtable->egl_extensions); + g_strfreev (vtable->gl_extensions); + if (vtable->base.handle.p) + g_module_close (vtable->base.handle.p); + + if (vtable->base.is_wrapped) { + g_mutex_lock (&gl_vtables_lock); + gl_vtables[vtable->gles_version] = NULL; + g_mutex_unlock (&gl_vtables_lock); + } +} + +static EglVTable * +egl_vtable_new (EglDisplay * display, guint gles_version) +{ + EglVTable *vtable; + + g_return_val_if_fail (display != NULL, NULL); + + vtable = egl_object_new0 (egl_vtable_class ()); + if (!vtable + || !egl_vtable_init (vtable, display->base.handle.p, gles_version)) + goto error; + return vtable; + + /* ERRORS */ +error: + { + egl_object_replace (&vtable, NULL); + return NULL; + } +} + +static EglVTable * +egl_vtable_new_cached (EglDisplay * display, guint gles_version) +{ + EglVTable *vtable, **vtable_ptr; + + g_return_val_if_fail (gles_version < G_N_ELEMENTS (gl_vtables), NULL); + + vtable_ptr = &gl_vtables[gles_version]; + + g_mutex_lock (&gl_vtables_lock); + vtable = *vtable_ptr; + if (vtable) + egl_object_ref (vtable); + else { + vtable = egl_vtable_new (display, gles_version); + if (vtable) { + vtable->base.is_wrapped = TRUE; + *vtable_ptr = vtable; + } + } + g_mutex_unlock (&gl_vtables_lock); + return vtable; +} + +/* ------------------------------------------------------------------------- */ +// EGL Display + +static gboolean +egl_display_run (EglDisplay * display, EglContextRunFunc func, gpointer args) +{ + EglMessage *msg; + + if (display->gl_thread == g_thread_self ()) { + func (args); + return TRUE; + } + + msg = egl_object_new0 (egl_message_class ()); + if (!msg) + return FALSE; + + msg->base.is_valid = TRUE; + msg->func = func; + msg->args = args; + g_async_queue_push (display->gl_queue, egl_object_ref (msg)); + + g_mutex_lock (&display->mutex); + while (msg->base.is_valid) + g_cond_wait (&display->gl_thread_ready, &display->mutex); + g_mutex_unlock (&display->mutex); + egl_object_unref (msg); + return TRUE; +} + +static gpointer +egl_get_display_from_native (guintptr native_display, guint gl_platform) +{ +#if USE_GST_GL_HELPERS && GST_GL_HAVE_PLATFORM_EGL + EGLDisplay ret; + GstGLDisplayType display_type = GST_GL_DISPLAY_TYPE_ANY; + + switch (gl_platform) { + case EGL_PLATFORM_X11: + display_type = GST_GL_DISPLAY_TYPE_X11; + break; + case EGL_PLATFORM_WAYLAND: + display_type = GST_GL_DISPLAY_TYPE_WAYLAND; + break; + default: + break; + } + + ret = gst_gl_display_egl_get_from_native (display_type, native_display); + if (ret != EGL_NO_DISPLAY) + return ret; +#endif + return eglGetDisplay ((EGLNativeDisplayType) native_display); +} + +static gpointer +egl_display_thread (gpointer data) +{ + EglDisplay *const display = data; + EGLDisplay gl_display = display->base.handle.p; + EGLint major_version, minor_version; + gchar **gl_apis, **gl_api; + + g_mutex_lock (&display->mutex); + if (!display->base.is_wrapped) { + gl_display = display->base.handle.p = + egl_get_display_from_native (display->base.handle.u, + display->gl_platform); + if (!gl_display) + goto error; + if (!eglInitialize (gl_display, &major_version, &minor_version)) + goto error; + } + + display->gl_vendor_string = + g_strdup (eglQueryString (gl_display, EGL_VENDOR)); + display->gl_version_string = + g_strdup (eglQueryString (gl_display, EGL_VERSION)); + display->gl_apis_string = + g_strdup (eglQueryString (gl_display, EGL_CLIENT_APIS)); + + GST_INFO ("EGL vendor: %s", display->gl_vendor_string); + GST_INFO ("EGL version: %s", display->gl_version_string); + GST_INFO ("EGL client APIs: %s", display->gl_apis_string); + + gl_apis = g_strsplit (display->gl_apis_string, " ", 0); + if (!gl_apis) + goto error; + for (gl_api = gl_apis; *gl_api != NULL; gl_api++) { + const GlVersionInfo *const vinfo = + gl_version_info_lookup_by_api_name (*gl_api); + + if (vinfo) + display->gl_apis |= vinfo->gl_api_bit; + } + g_strfreev (gl_apis); + if (!display->gl_apis) + goto error; + + display->base.is_valid = TRUE; + display->created = TRUE; + g_cond_broadcast (&display->gl_thread_ready); + g_mutex_unlock (&display->mutex); + + while (!g_atomic_int_get (&display->gl_thread_cancel)) { + EglMessage *const msg = + g_async_queue_timeout_pop (display->gl_queue, 100000); + + if (msg) { + if (msg->base.is_valid) { + msg->func (msg->args); + msg->base.is_valid = FALSE; + g_cond_broadcast (&display->gl_thread_ready); + } + egl_object_unref (msg); + } + } + g_mutex_lock (&display->mutex); + +done: + if (gl_display != EGL_NO_DISPLAY && !display->base.is_wrapped) + eglTerminate (gl_display); + display->base.handle.p = NULL; + g_cond_broadcast (&display->gl_thread_ready); + g_mutex_unlock (&display->mutex); + return NULL; + + /* ERRORS */ +error: + { + display->created = TRUE; + display->base.is_valid = FALSE; + goto done; + } +} + +static gboolean +egl_display_init (EglDisplay * display) +{ + display->gl_queue = + g_async_queue_new_full ((GDestroyNotify) gst_vaapi_mini_object_unref); + if (!display->gl_queue) + return FALSE; + + g_mutex_init (&display->mutex); + g_cond_init (&display->gl_thread_ready); + display->gl_thread = g_thread_try_new ("OpenGL Thread", egl_display_thread, + display, NULL); + if (!display->gl_thread) + return FALSE; + + g_mutex_lock (&display->mutex); + while (!display->created) + g_cond_wait (&display->gl_thread_ready, &display->mutex); + g_mutex_unlock (&display->mutex); + return display->base.is_valid; +} + +static void +egl_display_finalize (EglDisplay * display) +{ + g_atomic_int_set (&display->gl_thread_cancel, TRUE); + g_thread_join (display->gl_thread); + g_cond_clear (&display->gl_thread_ready); + g_mutex_clear (&display->mutex); + g_async_queue_unref (display->gl_queue); + + g_free (display->gl_vendor_string); + g_free (display->gl_version_string); + g_free (display->gl_apis_string); +} + +static EglDisplay * +egl_display_new_full (gpointer handle, gboolean is_wrapped, guint platform) +{ + EglDisplay *display; + + display = egl_object_new0 (egl_display_class ()); + if (!display) + return NULL; + + display->base.handle.p = handle; + display->base.is_wrapped = is_wrapped; + display->gl_platform = platform; + if (!egl_display_init (display)) + goto error; + return display; + + /* ERRORS */ +error: + { + egl_object_unref (display); + return NULL; + } +} + +EglDisplay * +egl_display_new (gpointer native_display, guint platform) +{ + g_return_val_if_fail (native_display != NULL, NULL); + + return egl_display_new_full (native_display, FALSE, platform); +} + +EglDisplay * +egl_display_new_wrapped (EGLDisplay gl_display) +{ + g_return_val_if_fail (gl_display != EGL_NO_DISPLAY, NULL); + + return egl_display_new_full (gl_display, TRUE, EGL_PLATFORM_UNKNOWN); +} + +/* ------------------------------------------------------------------------- */ +// EGL Config + +static gboolean +egl_config_init (EglConfig * config, EglDisplay * display, + const EGLint * attribs) +{ + EGLDisplay const gl_display = display->base.handle.p; + const GlVersionInfo *vinfo; + EGLConfig gl_config; + EGLint v, gl_apis, num_configs; + + egl_object_replace (&config->display, display); + + if (!eglChooseConfig (gl_display, attribs, &gl_config, 1, &num_configs)) + return FALSE; + if (num_configs != 1) + return FALSE; + config->base.handle.p = gl_config; + + if (!eglGetConfigAttrib (gl_display, gl_config, EGL_CONFIG_ID, &v)) + return FALSE; + config->config_id = v; + + if (!eglGetConfigAttrib (gl_display, gl_config, EGL_NATIVE_VISUAL_ID, &v)) + return FALSE; + config->visual_id = v; + + if (!eglGetConfigAttrib (gl_display, gl_config, EGL_RENDERABLE_TYPE, &v)) + return FALSE; + if (!egl_find_attrib_value (attribs, EGL_RENDERABLE_TYPE, &gl_apis)) + return FALSE; + vinfo = gl_version_info_lookup_by_api (v & gl_apis); + if (!vinfo) + return FALSE; + config->gles_version = vinfo->gles_version; + config->gl_api = vinfo->gles_version > 0 ? EGL_OPENGL_ES_API : EGL_OPENGL_API; + return TRUE; +} + +static void +egl_config_finalize (EglConfig * config) +{ + egl_object_replace (&config->display, NULL); +} + +EglConfig * +egl_config_new (EglDisplay * display, guint gles_version, GstVideoFormat format) +{ + EGLint attribs[2 * 6 + 1], *attrib = attribs; + const GstVideoFormatInfo *finfo; + const GlVersionInfo *vinfo; + + g_return_val_if_fail (display != NULL, NULL); + + finfo = gst_video_format_get_info (format); + if (!finfo || !GST_VIDEO_FORMAT_INFO_IS_RGB (finfo)) + return NULL; + + vinfo = gl_version_info_lookup (gles_version); + if (!vinfo) + return NULL; + + *attrib++ = EGL_COLOR_BUFFER_TYPE; + *attrib++ = EGL_RGB_BUFFER; + *attrib++ = EGL_RED_SIZE; + *attrib++ = GST_VIDEO_FORMAT_INFO_DEPTH (finfo, GST_VIDEO_COMP_R); + *attrib++ = EGL_GREEN_SIZE; + *attrib++ = GST_VIDEO_FORMAT_INFO_DEPTH (finfo, GST_VIDEO_COMP_G); + *attrib++ = EGL_BLUE_SIZE; + *attrib++ = GST_VIDEO_FORMAT_INFO_DEPTH (finfo, GST_VIDEO_COMP_B); + *attrib++ = EGL_ALPHA_SIZE; + *attrib++ = GST_VIDEO_FORMAT_INFO_DEPTH (finfo, GST_VIDEO_COMP_A); + *attrib++ = EGL_RENDERABLE_TYPE; + *attrib++ = vinfo->gl_api_bit; + *attrib++ = EGL_NONE; + g_assert (attrib - attribs <= G_N_ELEMENTS (attribs)); + + return egl_config_new_with_attribs (display, attribs); +} + +EglConfig * +egl_config_new_with_attribs (EglDisplay * display, const EGLint * attribs) +{ + EglConfig *config; + + g_return_val_if_fail (display != NULL, NULL); + g_return_val_if_fail (attribs != NULL, NULL); + + config = egl_object_new0 (egl_config_class ()); + if (!config || !egl_config_init (config, display, attribs)) + goto error; + return config; + + /* ERRORS */ +error: + { + egl_object_replace (&config, NULL); + return NULL; + } +} + +static EglConfig * +egl_config_new_from_gl_context (EglDisplay * display, EGLContext gl_context) +{ + EGLDisplay const gl_display = display->base.handle.p; + EGLint attribs[3 * 2 + 1], *attrib = attribs; + EGLint config_id, api, v; + guint gles_version; + const GlVersionInfo *vinfo; + + if (!eglQueryContext (gl_display, gl_context, EGL_CONFIG_ID, &config_id)) + return NULL; + if (!eglQueryContext (gl_display, gl_context, EGL_CONTEXT_CLIENT_TYPE, &api)) + return NULL; + if (!eglQueryContext (gl_display, gl_context, EGL_CONTEXT_CLIENT_VERSION, &v)) + return NULL; + + if (api == EGL_OPENGL_API) + gles_version = 0; + else if (api == EGL_OPENGL_ES_API) + gles_version = v; + else { + GST_ERROR ("unsupported EGL client API (%d)", api); + return NULL; + } + + vinfo = gl_version_info_lookup (gles_version); + if (!vinfo) + return NULL; + + *attrib++ = EGL_COLOR_BUFFER_TYPE; + *attrib++ = EGL_RGB_BUFFER; + *attrib++ = EGL_CONFIG_ID; + *attrib++ = config_id; + *attrib++ = EGL_RENDERABLE_TYPE; + *attrib++ = vinfo->gl_api_bit; + *attrib++ = EGL_NONE; + g_assert (attrib - attribs <= G_N_ELEMENTS (attribs)); + + return egl_config_new_with_attribs (display, attribs); +} + +/* ------------------------------------------------------------------------- */ +// EGL Surface + +static void +egl_surface_finalize (EglSurface * surface) +{ + if (surface->base.handle.p != EGL_NO_SURFACE && !surface->base.is_wrapped) + eglDestroySurface (surface->display->base.handle.p, surface->base.handle.p); + egl_object_replace (&surface->display, NULL); +} + +static EglSurface * +egl_surface_new_wrapped (EglDisplay * display, EGLSurface gl_surface) +{ + EglSurface *surface; + + g_return_val_if_fail (display != NULL, NULL); + + surface = egl_object_new (egl_surface_class ()); + if (!surface) + return NULL; + + surface->base.is_wrapped = TRUE; + surface->base.handle.p = gl_surface; + surface->display = egl_object_ref (display); + return surface; +} + +/* ------------------------------------------------------------------------- */ +// EGL Context + +static void egl_context_state_get_current (EglContextState * cs); + +static gboolean +egl_context_state_set_current (EglContextState * new_cs, + EglContextState * old_cs); + +static gboolean +ensure_vtable (EglContext * ctx) +{ + if (!ctx->vtable) { + ctx->vtable = egl_vtable_new_cached (ctx->display, + ctx->config ? ctx->config->gles_version : 0); + if (!ctx->vtable) + return FALSE; + } + return TRUE; +} + +static gboolean +ensure_context (EglContext * ctx, EGLContext gl_parent_context) +{ + EGLDisplay *const gl_display = ctx->display->base.handle.p; + EGLContext gl_context = ctx->base.handle.p; + EGLint gles_attribs[3], *attribs = NULL; + + if (!gl_context) { + if (ctx->config->gles_version >= 2) { + attribs = gles_attribs; + attribs[0] = EGL_CONTEXT_CLIENT_VERSION; + attribs[1] = ctx->config->gles_version; + attribs[2] = EGL_NONE; + } + + gl_context = eglCreateContext (gl_display, ctx->config->base.handle.p, + gl_parent_context, attribs); + if (!gl_context) + goto error_create_context; + ctx->base.handle.p = gl_context; + } + return TRUE; + + /* ERRORS */ +error_create_context: + GST_ERROR ("failed to create EGL context"); + return FALSE; +} + +static inline gboolean +ensure_gl_is_surfaceless (EglContext * ctx) +{ + return ctx->vtable->has_EGL_KHR_surfaceless_context || + (ctx->read_surface && ctx->draw_surface); +} + +static gboolean +ensure_gl_scene (EglContext * ctx) +{ + EglVTable *vtable; + + if (!ensure_gl_is_surfaceless (ctx)) + return FALSE; + + if (ctx->base.is_valid) + return TRUE; + + vtable = egl_context_get_vtable (ctx, TRUE); + if (!vtable) + return FALSE; + + vtable->glClearColor (0.0, 0.0, 0.0, 1.0); + if (ctx->config && ctx->config->gles_version == 0) + vtable->glEnable (GL_TEXTURE_2D); + vtable->glDisable (GL_BLEND); + vtable->glDisable (GL_DEPTH_TEST); + + ctx->base.is_valid = TRUE; + return TRUE; +} + +/** + * egl_context_state_get_current: + * @cs: return location to the current #EglContextState + * + * Retrieves the current EGL context, display and surface to pack into + * the #EglContextState struct. + */ +static void +egl_context_state_get_current (EglContextState * cs) +{ + cs->display = eglGetCurrentDisplay (); + cs->context = eglGetCurrentContext (); + if (cs->context) { + cs->read_surface = eglGetCurrentSurface (EGL_READ); + cs->draw_surface = eglGetCurrentSurface (EGL_DRAW); + } else { + cs->read_surface = EGL_NO_SURFACE; + cs->draw_surface = EGL_NO_SURFACE; + } +} + +/** + * egl_context_state_set_current: + * @new_cs: the requested new #EglContextState + * @old_cs: return location to the context that was previously current + * + * Makes the @new_cs EGL context the current EGL rendering context of + * the calling thread, replacing the previously current context if + * there was one. + * + * If @old_cs is non %NULL, the previously current EGL context and + * surface are recorded. + * + * Return value: %TRUE on success + */ +static gboolean +egl_context_state_set_current (EglContextState * new_cs, + EglContextState * old_cs) +{ + /* If display is NULL, this could be that new_cs was retrieved from + egl_context_state_get_current() with none set previously. If that case, + the other fields are also NULL and we don't return an error */ + if (!new_cs->display) + return !new_cs->context && !new_cs->read_surface && !new_cs->draw_surface; + + if (old_cs) { + if (old_cs == new_cs) + return TRUE; + egl_context_state_get_current (old_cs); + if (old_cs->display == new_cs->display && + old_cs->context == new_cs->context && + old_cs->read_surface == new_cs->read_surface && + old_cs->draw_surface == new_cs->draw_surface) + return TRUE; + } + return eglMakeCurrent (new_cs->display, new_cs->draw_surface, + new_cs->read_surface, new_cs->context); +} + +static gboolean +egl_context_init (EglContext * ctx, EglDisplay * display, EglConfig * config, + EGLContext gl_parent_context) +{ + egl_object_replace (&ctx->display, display); + egl_object_replace (&ctx->config, config); + + if (config) + eglBindAPI (config->gl_api); + + if (!ensure_vtable (ctx)) + return FALSE; + if (!ensure_context (ctx, gl_parent_context)) + return FALSE; + return TRUE; +} + +static void +egl_context_finalize (EglContext * ctx) +{ + if (ctx->base.handle.p && !ctx->base.is_wrapped) + eglDestroyContext (ctx->display->base.handle.p, ctx->base.handle.p); + egl_object_replace (&ctx->read_surface, NULL); + egl_object_replace (&ctx->draw_surface, NULL); + egl_object_replace (&ctx->config, NULL); + egl_object_replace (&ctx->display, NULL); + egl_object_replace (&ctx->vtable, NULL); +} + +typedef struct +{ + EglDisplay *display; + EglConfig *config; + EGLContext gl_parent_context; + EglContext *context; /* result */ +} CreateContextArgs; + +static void +do_egl_context_new (CreateContextArgs * args) +{ + EglContext *ctx; + + ctx = egl_object_new0 (egl_context_class ()); + if (!ctx || !egl_context_init (ctx, args->display, args->config, + args->gl_parent_context)) + goto error; + args->context = ctx; + return; + + /* ERRORS */ +error: + { + egl_object_replace (&ctx, NULL); + args->context = NULL; + } +} + +EglContext * +egl_context_new (EglDisplay * display, EglConfig * config, EglContext * parent) +{ + CreateContextArgs args; + + g_return_val_if_fail (display != NULL, NULL); + g_return_val_if_fail (config != NULL, NULL); + + args.display = display; + args.config = config; + args.gl_parent_context = parent ? parent->base.handle.p : EGL_NO_CONTEXT; + if (!egl_display_run (display, (EglContextRunFunc) do_egl_context_new, &args)) + return NULL; + return args.context; +} + +EglContext * +egl_context_new_wrapped (EglDisplay * display, EGLContext gl_context) +{ + CreateContextArgs args; + EglConfig *config; + gboolean success; + + g_return_val_if_fail (display != NULL, NULL); + g_return_val_if_fail (gl_context != EGL_NO_CONTEXT, NULL); + + config = egl_config_new_from_gl_context (display, gl_context); + if (!config) + return NULL; + + args.display = display; + args.config = config; + args.gl_parent_context = gl_context; + args.context = NULL; + success = egl_display_run (display, (EglContextRunFunc) do_egl_context_new, + &args); + egl_object_unref (config); + if (!success) + return NULL; + + return args.context; +} + +EglVTable * +egl_context_get_vtable (EglContext * ctx, gboolean need_gl_symbols) +{ + g_return_val_if_fail (ctx != NULL, NULL); + g_return_val_if_fail (ctx->display->gl_thread == g_thread_self (), NULL); + + if (!ensure_vtable (ctx)) + return NULL; + + if (need_gl_symbols && !(ctx->vtable->num_gl_symbols > 0 || + egl_vtable_load_gl_symbols (ctx->vtable, + ctx->display->base.handle.p))) + return NULL; + return ctx->vtable; +} + +static void +egl_context_set_surface (EglContext * ctx, EglSurface * surface) +{ + g_return_if_fail (ctx != NULL); + g_return_if_fail (surface != NULL); + + egl_object_replace (&ctx->read_surface, surface); + egl_object_replace (&ctx->draw_surface, surface); +} + +gboolean +egl_context_set_current (EglContext * ctx, gboolean activate, + EglContextState * old_cs) +{ + EglContextState cs, *new_cs; + + g_return_val_if_fail (ctx != NULL, FALSE); + g_return_val_if_fail (ctx->display->gl_thread == g_thread_self (), FALSE); + + if (activate) { + new_cs = &cs; + new_cs->display = ctx->display->base.handle.p; + new_cs->context = ctx->base.handle.p; + new_cs->draw_surface = ctx->draw_surface ? + ctx->draw_surface->base.handle.p : EGL_NO_SURFACE; + new_cs->read_surface = ctx->read_surface ? + ctx->read_surface->base.handle.p : EGL_NO_SURFACE; + } else if (old_cs) { + new_cs = old_cs; + old_cs = NULL; + } else { + new_cs = &cs; + new_cs->display = ctx->display->base.handle.p; + new_cs->context = EGL_NO_CONTEXT; + new_cs->draw_surface = EGL_NO_SURFACE; + new_cs->read_surface = EGL_NO_SURFACE; + old_cs = NULL; + } + + if (!egl_context_state_set_current (new_cs, old_cs)) + return FALSE; + if (activate && !ensure_gl_scene (ctx)) + return FALSE; + return TRUE; +} + +gboolean +egl_context_run (EglContext * ctx, EglContextRunFunc func, gpointer args) +{ + g_return_val_if_fail (ctx != NULL, FALSE); + g_return_val_if_fail (func != NULL, FALSE); + + return egl_display_run (ctx->display, func, args); +} + +/* ------------------------------------------------------------------------- */ +// EGL Program + +static GLuint +egl_compile_shader (EglContext * ctx, GLenum type, const char *source) +{ + EglVTable *const vtable = egl_context_get_vtable (ctx, TRUE); + GLuint shader; + GLint status; + char log[BUFSIZ]; + GLsizei log_length; + + shader = vtable->glCreateShader (type); + vtable->glShaderSource (shader, 1, &source, NULL); + vtable->glCompileShader (shader); + vtable->glGetShaderiv (shader, GL_COMPILE_STATUS, &status); + if (!status) { + GST_ERROR ("failed to compile %s shader", + type == GL_FRAGMENT_SHADER ? "fragment" : + type == GL_VERTEX_SHADER ? "vertex" : ""); + + vtable->glGetShaderInfoLog (shader, sizeof (log), &log_length, log); + GST_ERROR ("info log: %s", log); + return 0; + } + return shader; +} + +static void +egl_program_finalize (EglProgram * program) +{ + EglVTable *const vtable = program->vtable; + + if (program->base.handle.u) + vtable->glDeleteProgram (program->base.handle.u); + if (program->frag_shader) + vtable->glDeleteShader (program->frag_shader); + if (program->vert_shader) + vtable->glDeleteShader (program->vert_shader); + egl_object_replace (&program->vtable, NULL); +} + +static gboolean +egl_program_init (EglProgram * program, EglContext * ctx, + const gchar * frag_shader_text, const gchar * vert_shader_text) +{ + EglVTable *const vtable = egl_context_get_vtable (ctx, TRUE); + GLuint prog_id; + char msg[BUFSIZ]; + GLsizei msglen; + GLint status; + + if (ctx->config->gles_version == 1) + goto error_unsupported_gles_version; + + program->vtable = egl_object_ref (vtable); + + program->frag_shader = + egl_compile_shader (ctx, GL_FRAGMENT_SHADER, frag_shader_text); + if (!program->frag_shader) + return FALSE; + + program->vert_shader = + egl_compile_shader (ctx, GL_VERTEX_SHADER, vert_shader_text); + if (!program->vert_shader) + return FALSE; + + prog_id = vtable->glCreateProgram (); + if (!prog_id) + return FALSE; + program->base.handle.u = prog_id; + + vtable->glAttachShader (prog_id, program->frag_shader); + vtable->glAttachShader (prog_id, program->vert_shader); + vtable->glBindAttribLocation (prog_id, 0, "position"); + vtable->glBindAttribLocation (prog_id, 1, "texcoord"); + vtable->glLinkProgram (prog_id); + + vtable->glGetProgramiv (prog_id, GL_LINK_STATUS, &status); + if (!status) + goto error_link_program; + return TRUE; + + /* ERRORS */ +error_unsupported_gles_version: + GST_ERROR ("unsupported shader with OpenGL|ES version 1"); + return FALSE; +error_link_program: + vtable->glGetProgramInfoLog (prog_id, sizeof (msg), &msglen, msg); + GST_ERROR ("failed to link program: %s", msg); + return FALSE; +} + +EglProgram * +egl_program_new (EglContext * ctx, const gchar * frag_shader_text, + const gchar * vert_shader_text) +{ + EglProgram *program; + + g_return_val_if_fail (ctx != NULL, NULL); + g_return_val_if_fail (frag_shader_text != NULL, NULL); + g_return_val_if_fail (vert_shader_text != NULL, NULL); + + program = egl_object_new0 (egl_program_class ()); + if (!program + || !egl_program_init (program, ctx, frag_shader_text, vert_shader_text)) + goto error; + return program; + + /* ERRORS */ +error: + { + egl_object_replace (&program, NULL); + return NULL; + } +} + +/* ------------------------------------------------------------------------- */ +// EGL Window + +static gboolean +egl_window_init (EglWindow * window, EglContext * ctx, gpointer native_window) +{ + EGLSurface gl_surface; + + window->context = egl_context_new (ctx->display, ctx->config, ctx); + if (!window->context) + return FALSE; + ctx = window->context; + + gl_surface = eglCreateWindowSurface (ctx->display->base.handle.p, + ctx->config->base.handle.p, (EGLNativeWindowType) native_window, NULL); + if (!gl_surface) + return FALSE; + + window->surface = egl_surface_new_wrapped (ctx->display, gl_surface); + if (!window->surface) + goto error_create_surface; + window->base.handle.p = gl_surface; + window->base.is_wrapped = FALSE; + + egl_context_set_surface (ctx, window->surface); + return TRUE; + + /* ERRORS */ +error_create_surface: + GST_ERROR ("failed to create EGL wrapper surface"); + eglDestroySurface (ctx->display->base.handle.p, gl_surface); + return FALSE; +} + +static void +egl_window_finalize (EglWindow * window) +{ + if (window->context && window->base.handle.p) + eglDestroySurface (window->context->display->base.handle.p, + window->base.handle.p); + + egl_object_replace (&window->surface, NULL); + egl_object_replace (&window->context, NULL); +} + +EglWindow * +egl_window_new (EglContext * ctx, gpointer native_window) +{ + EglWindow *window; + + g_return_val_if_fail (ctx != NULL, NULL); + g_return_val_if_fail (native_window != NULL, NULL); + + window = egl_object_new0 (egl_window_class ()); + if (!window || !egl_window_init (window, ctx, native_window)) + goto error; + return window; + + /* ERRORS */ +error: + { + egl_object_replace (&window, NULL); + return NULL; + } +} + +/* ------------------------------------------------------------------------- */ +// Misc utility functions + +void +egl_matrix_set_identity (gfloat m[16]) +{ +#define MAT(m,r,c) (m)[(c) * 4 + (r)] + MAT (m, 0, 0) = 1.0; + MAT (m, 0, 1) = 0.0; + MAT (m, 0, 2) = 0.0; + MAT (m, 0, 3) = 0.0; + MAT (m, 1, 0) = 0.0; + MAT (m, 1, 1) = 1.0; + MAT (m, 1, 2) = 0.0; + MAT (m, 1, 3) = 0.0; + MAT (m, 2, 0) = 0.0; + MAT (m, 2, 1) = 0.0; + MAT (m, 2, 2) = 1.0; + MAT (m, 2, 3) = 0.0; + MAT (m, 3, 0) = 0.0; + MAT (m, 3, 1) = 0.0; + MAT (m, 3, 2) = 0.0; + MAT (m, 3, 3) = 1.0; +#undef MAT +} + +/** + * egl_create_texture: + * @ctx: the parent #EglContext object + * @target: the target to which the texture is bound + * @format: the format of the pixel data + * @width: the requested width, in pixels + * @height: the requested height, in pixels + * + * Creates a texture with the specified dimensions and @format. The + * internal format will be automatically derived from @format. + * + * Return value: the newly created texture name + */ +guint +egl_create_texture (EglContext * ctx, guint target, guint format, + guint width, guint height) +{ + EglVTable *const vtable = egl_context_get_vtable (ctx, TRUE); + guint internal_format, texture, bytes_per_component; + + internal_format = format; + switch (format) { + case GL_LUMINANCE: + bytes_per_component = 1; + break; + case GL_LUMINANCE_ALPHA: + bytes_per_component = 2; + break; + case GL_RGBA: + case GL_BGRA_EXT: + internal_format = GL_RGBA; + bytes_per_component = 4; + break; + default: + bytes_per_component = 0; + break; + } + g_assert (bytes_per_component > 0); + + vtable->glGenTextures (1, &texture); + vtable->glBindTexture (target, texture); + + if (width > 0 && height > 0) + vtable->glTexImage2D (target, 0, internal_format, width, height, 0, + format, GL_UNSIGNED_BYTE, NULL); + + vtable->glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + vtable->glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + vtable->glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + vtable->glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + vtable->glPixelStorei (GL_UNPACK_ALIGNMENT, bytes_per_component); + + return texture; +} + +/** + * egl_destroy_texture: + * @ctx: the parent #EglContext object + * @texture: the texture name to delete + * + * Destroys the supplied @texture name. + */ +void +egl_destroy_texture (EglContext * ctx, guint texture) +{ + EglVTable *const vtable = egl_context_get_vtable (ctx, TRUE); + + vtable->glDeleteTextures (1, &texture); +} diff --git a/gst-libs/gst/vaapi/gstvaapiutils_egl.h b/gst-libs/gst/vaapi/gstvaapiutils_egl.h new file mode 100644 index 0000000000..20b553eab8 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_egl.h @@ -0,0 +1,256 @@ +/* + * gstvaapiutils_egl.h - EGL utilities + * + * Copyright (C) 2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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 + */ + +#ifndef GST_VAAPI_UTILS_EGL_H +#define GST_VAAPI_UTILS_EGL_H + +#include +#include +#include +#include "egl_compat.h" +#include "gstvaapiminiobject.h" + +typedef union egl_handle_s EglHandle; +typedef struct egl_object_s EglObject; +typedef struct egl_object_class_s EglObjectClass; +typedef struct egl_vtable_s EglVTable; +typedef struct egl_display_s EglDisplay; +typedef struct egl_config_s EglConfig; +typedef struct egl_context_state_s EglContextState; +typedef struct egl_context_s EglContext; +typedef struct egl_surface_s EglSurface; +typedef struct egl_program_s EglProgram; +typedef struct egl_window_s EglWindow; + +#define EGL_PROTO_BEGIN(NAME, TYPE, EXTENSION) \ + typedef TYPE (*GL_PROTO_GEN_CONCAT3(Egl,NAME,Proc)) +#define EGL_PROTO_END() ; +#define GL_PROTO_BEGIN(NAME, TYPE, EXTENSION) \ + typedef TYPE (*GL_PROTO_GEN_CONCAT3(Gl,NAME,Proc)) +#define GL_PROTO_ARG_LIST(...) (__VA_ARGS__) +#define GL_PROTO_ARG(NAME, TYPE) TYPE NAME +#define GL_PROTO_END() ; +#include "egl_vtable.h" + +enum { + EGL_PLATFORM_UNKNOWN, + EGL_PLATFORM_X11, + EGL_PLATFORM_WAYLAND, +}; + +union egl_handle_s +{ + gpointer p; + guintptr u; + gintptr i; +}; + +struct egl_object_s +{ + /*< private >*/ + GstVaapiMiniObject parent_instance; + + EglHandle handle; + guint is_wrapped:1; + guint is_valid:1; +}; + +struct egl_object_class_s +{ + /*< private >*/ + GstVaapiMiniObjectClass parent_class; +}; + +struct egl_vtable_s +{ + EglObject base; + + gchar **egl_extensions; + guint num_egl_symbols; + gchar **gl_extensions; + guint num_gl_symbols; + guint gles_version; + +#define EGL_PROTO_BEGIN(NAME, TYPE, EXTENSION) \ + GL_PROTO_BEGIN_I(NAME, TYPE, EXTENSION, Egl, egl) +#define GL_PROTO_BEGIN(NAME, TYPE, EXTENSION) \ + GL_PROTO_BEGIN_I(NAME, TYPE, EXTENSION, Gl, gl) +#define GL_PROTO_BEGIN_I(NAME, TYPE, EXTENSION, Prefix, prefix) \ + GL_PROTO_GEN_CONCAT3(Prefix,NAME,Proc) GL_PROTO_GEN_CONCAT(prefix,NAME); +#include "egl_vtable.h" + +#define EGL_DEFINE_EXTENSION(EXTENSION) \ + GL_DEFINE_EXTENSION_I(EXTENSION, EGL) +#define GL_DEFINE_EXTENSION(EXTENSION) \ + GL_DEFINE_EXTENSION_I(EXTENSION, GL) +#define GL_DEFINE_EXTENSION_I(EXTENSION, PREFIX) \ + guint GL_PROTO_GEN_CONCAT4(has_,PREFIX,_,EXTENSION); +#include "egl_vtable.h" +}; + +struct egl_display_s +{ + EglObject base; + + gchar *gl_vendor_string; + gchar *gl_version_string; + gchar *gl_apis_string; + guint gl_apis; /* EGL_*_BIT mask */ + guint gl_platform; + + GMutex mutex; + GThread *gl_thread; + GCond gl_thread_ready; + gboolean gl_thread_cancel; + GAsyncQueue *gl_queue; + gboolean created; +}; + +struct egl_config_s +{ + EglObject base; + + EglDisplay *display; + guint gl_api; /* EGL_*_API value */ + guint gles_version; + gint config_id; + gint visual_id; +}; + +typedef void (*EglContextRunFunc) (gpointer args); + +struct egl_context_state_s +{ + EGLDisplay display; + EGLContext context; + EGLSurface read_surface; + EGLSurface draw_surface; +}; + +struct egl_context_s +{ + EglObject base; + + EglVTable *vtable; + EglDisplay *display; + EglConfig *config; + EglSurface *read_surface; + EglSurface *draw_surface; +}; + +struct egl_surface_s +{ + EglObject base; + + EglDisplay *display; +}; + +/* Defined to the maximum number of uniforms for a shader program */ +#define EGL_MAX_UNIFORMS 16 + +struct egl_program_s +{ + EglObject base; + + EglVTable *vtable; + guint frag_shader; + guint vert_shader; + gint uniforms[EGL_MAX_UNIFORMS]; +}; + +struct egl_window_s +{ + EglObject base; + + EglContext *context; + EglSurface *surface; +}; + +#define egl_object_ref(obj) \ + ((gpointer)gst_vaapi_mini_object_ref ((GstVaapiMiniObject *)(obj))) +#define egl_object_unref(obj) \ + gst_vaapi_mini_object_unref ((GstVaapiMiniObject *)(obj)) +#define egl_object_replace(old_obj_ptr, new_obj) \ + gst_vaapi_mini_object_replace ((GstVaapiMiniObject **)(old_obj_ptr), \ + (GstVaapiMiniObject *)(new_obj)) + +G_GNUC_INTERNAL +EglDisplay * +egl_display_new (gpointer native_display, guint gl_platform); + +G_GNUC_INTERNAL +EglDisplay * +egl_display_new_wrapped (EGLDisplay gl_display); + +G_GNUC_INTERNAL +EglConfig * +egl_config_new (EglDisplay * display, guint gles_version, + GstVideoFormat format); + +G_GNUC_INTERNAL +EglConfig * +egl_config_new_with_attribs (EglDisplay * display, const EGLint * attribs); + +G_GNUC_INTERNAL +EglContext * +egl_context_new (EglDisplay * display, EglConfig * config, EglContext * parent); + +G_GNUC_INTERNAL +EglContext * +egl_context_new_wrapped (EglDisplay * display, EGLContext gl_context); + +G_GNUC_INTERNAL +EglVTable * +egl_context_get_vtable (EglContext * ctx, gboolean need_gl_symbols); + +G_GNUC_INTERNAL +gboolean +egl_context_set_current (EglContext * ctx, gboolean activate, + EglContextState * old_cs); + +G_GNUC_INTERNAL +gboolean +egl_context_run (EglContext * ctx, EglContextRunFunc func, gpointer args); + +G_GNUC_INTERNAL +EglProgram * +egl_program_new (EglContext * ctx, const gchar * frag_shader_text, + const gchar * vert_shader_text); + +G_GNUC_INTERNAL +EglWindow * +egl_window_new (EglContext * ctx, gpointer native_window); + +G_GNUC_INTERNAL +guint +egl_create_texture (EglContext * ctx, guint target, guint format, + guint width, guint height); + +G_GNUC_INTERNAL +void +egl_destroy_texture (EglContext * ctx, guint texture); + +G_GNUC_INTERNAL +void +egl_matrix_set_identity (gfloat m[16]); + +#endif /* GST_VAAPI_UTILS_EGL_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiutils_glx.c b/gst-libs/gst/vaapi/gstvaapiutils_glx.c new file mode 100644 index 0000000000..f73106c242 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_glx.c @@ -0,0 +1,1273 @@ +/* + * gstvaapiutils_glx.c - GLX utilties + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2012 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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 + */ + +#define _GNU_SOURCE 1 /* RTLD_DEFAULT */ +#include "sysdeps.h" +#include +#include +#include "gstvaapiutils_glx.h" +#include "gstvaapiutils_x11.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +/** Lookup for substring NAME in string EXT using SEP as separators */ +static gboolean +find_string (const gchar * name, const gchar * ext, const gchar * sep) +{ + const gchar *end; + int name_len, n; + + if (!name || !ext) + return FALSE; + + end = ext + strlen (ext); + name_len = strlen (name); + while (ext < end) { + n = strcspn (ext, sep); + if (n == name_len && strncmp (name, ext, n) == 0) + return TRUE; + ext += (n + 1); + } + return FALSE; +} + +/** + * gl_get_error_string: + * @error: an OpenGL error enumeration + * + * Retrieves the string representation the OpenGL @error. + * + * Return error: the static string representing the OpenGL @error + */ +const gchar * +gl_get_error_string (GLenum error) +{ + switch (error) { +#define MAP(id, str) \ + case id: return str " (" #id ")" + MAP (GL_NO_ERROR, "no error"); + MAP (GL_INVALID_ENUM, "invalid enumerant"); + MAP (GL_INVALID_VALUE, "invalid value"); + MAP (GL_INVALID_OPERATION, "invalid operation"); + MAP (GL_STACK_OVERFLOW, "stack overflow"); + MAP (GL_STACK_UNDERFLOW, "stack underflow"); + MAP (GL_OUT_OF_MEMORY, "out of memory"); +#ifdef GL_INVALID_FRAMEBUFFER_OPERATION_EXT + MAP (GL_INVALID_FRAMEBUFFER_OPERATION_EXT, + "invalid framebuffer operation"); +#endif +#undef MAP + default: + break; + }; + return ""; +} + +/** + * gl_purge_errors: + * + * Purges all OpenGL errors. This function is generally useful to + * clear up the pending errors prior to calling gl_check_error(). + */ +void +gl_purge_errors (void) +{ + while (glGetError () != GL_NO_ERROR); /* nothing */ +} + +/** + * gl_check_error: + * + * Checks whether there is any OpenGL error pending. + * + * Return value: %TRUE if an error was encountered + */ +gboolean +gl_check_error (void) +{ + GLenum error; + gboolean has_errors = FALSE; + + while ((error = glGetError ()) != GL_NO_ERROR) { + GST_DEBUG ("glError: %s caught", gl_get_error_string (error)); + has_errors = TRUE; + } + return has_errors; +} + +/** + * gl_get_param: + * @param: the parameter name + * @pval: return location for the value + * + * This function is a wrapper around glGetIntegerv() that does extra + * error checking. + * + * Return value: %TRUE on success + */ +gboolean +gl_get_param (GLenum param, guint * pval) +{ + GLint val; + + gl_purge_errors (); + glGetIntegerv (param, &val); + if (gl_check_error ()) + return FALSE; + + if (pval) + *pval = val; + return TRUE; +} + +/** + * gl_get_texture_param: + * @target: the target to which the texture is bound + * @param: the parameter name + * @pval: return location for the value + * + * This function is a wrapper around glGetTexLevelParameteriv() that + * does extra error checking. + * + * Return value: %TRUE on success + */ +gboolean +gl_get_texture_param (GLenum target, GLenum param, guint * pval) +{ + GLint val; + + gl_purge_errors (); + glGetTexLevelParameteriv (target, 0, param, &val); + if (gl_check_error ()) + return FALSE; + + if (pval) + *pval = val; + return TRUE; +} + +/** + * gl_get_texture_binding: + * @target: a texture target + * + * Determines the texture binding type for the specified target. + * + * Return value: texture binding type for @target + */ +static GLenum +gl_get_texture_binding (GLenum target) +{ + GLenum binding; + + switch (target) { + case GL_TEXTURE_1D: + binding = GL_TEXTURE_BINDING_1D; + break; + case GL_TEXTURE_2D: + binding = GL_TEXTURE_BINDING_2D; + break; + case GL_TEXTURE_3D: + binding = GL_TEXTURE_BINDING_3D; + break; + case GL_TEXTURE_RECTANGLE_ARB: + binding = GL_TEXTURE_BINDING_RECTANGLE_ARB; + break; + default: + binding = 0; + break; + } + return binding; +} + +/** + * gl_set_bgcolor: + * @color: the requested RGB color + * + * Sets background color to the RGB @color. This basically is a + * wrapper around glClearColor(). + */ +void +gl_set_bgcolor (guint32 color) +{ + glClearColor ( + ((color >> 16) & 0xff) / 255.0f, + ((color >> 8) & 0xff) / 255.0f, (color & 0xff) / 255.0f, 1.0f); +} + +/** + * gl_perspective: + * @fovy: the field of view angle, in degrees, in the y direction + * @aspect: the aspect ratio that determines the field of view in the + * x direction. The aspect ratio is the ratio of x (width) to y + * (height) + * @zNear: the distance from the viewer to the near clipping plane + * (always positive) + * @zFar: the distance from the viewer to the far clipping plane + * (always positive) + * + * Specified a viewing frustum into the world coordinate system. This + * basically is the Mesa implementation of gluPerspective(). + */ +static void +gl_perspective (GLdouble fovy, GLdouble aspect, GLdouble near_val, + GLdouble far_val) +{ + GLdouble left, right, top, bottom; + + /* Source (Q 9.085): + */ + top = tan (fovy * M_PI / 360.0) * near_val; + bottom = -top; + left = aspect * bottom; + right = aspect * top; + glFrustum (left, right, bottom, top, near_val, far_val); +} + +/** + * gl_resize: + * @width: the requested width, in pixels + * @height: the requested height, in pixels + * + * Resizes the OpenGL viewport to the specified dimensions, using an + * orthogonal projection. (0,0) represents the top-left corner of the + * window. + */ +void +gl_resize (guint width, guint height) +{ +#define FOVY 60.0f +#define ASPECT 1.0f +#define Z_NEAR 0.1f +#define Z_FAR 100.0f +#define Z_CAMERA 0.869f + + glViewport (0, 0, width, height); + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); + gl_perspective (FOVY, ASPECT, Z_NEAR, Z_FAR); + glMatrixMode (GL_MODELVIEW); + glLoadIdentity (); + + glTranslatef (-0.5f, -0.5f, -Z_CAMERA); + glScalef (1.0f / width, -1.0f / height, 1.0f / width); + glTranslatef (0.0f, -1.0f * height, 0.0f); +} + +/** + * gl_create_context: + * @dpy: an X11 #Display + * @screen: the associated screen of @dpy + * @parent: the parent #GLContextState, or %NULL if none is to be used + * + * Creates a GLX context sharing textures and displays lists with + * @parent, if not %NULL. + * + * Return value: the newly created GLX context + */ +GLContextState * +gl_create_context (Display * dpy, int screen, GLContextState * parent) +{ + GLContextState *cs; + GLXFBConfig *fbconfigs = NULL; + int fbconfig_id, val, n, n_fbconfigs; + Status status; + + static GLint fbconfig_attrs[] = { + GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_DOUBLEBUFFER, True, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_ALPHA_SIZE, 8, + None + }; + + const GLint rgba_colors[4] = { + GLX_RED_SIZE, + GLX_GREEN_SIZE, + GLX_BLUE_SIZE, + GLX_ALPHA_SIZE + }; + + cs = malloc (sizeof (*cs)); + if (!cs) + goto error; + + if (parent) { + cs->display = parent->display; + cs->window = parent->window; + screen = DefaultScreen (parent->display); + } else { + cs->display = dpy; + cs->window = None; + } + cs->visual = NULL; + cs->context = NULL; + cs->swapped_buffers = FALSE; + + if (parent && parent->context) { + status = glXQueryContext (parent->display, + parent->context, GLX_FBCONFIG_ID, &fbconfig_id); + if (status != Success) + goto error; + + if (fbconfig_id == GLX_DONT_CARE) + goto choose_fbconfig; + + fbconfigs = glXGetFBConfigs (parent->display, screen, &n_fbconfigs); + if (!fbconfigs) + goto error; + + /* Find out a 8 bit GLXFBConfig compatible with the parent context */ + for (n = 0; n < n_fbconfigs; n++) { + gboolean sizes_correct = FALSE; + int cn; + + status = glXGetFBConfigAttrib (parent->display, + fbconfigs[n], GLX_FBCONFIG_ID, &val); + if (status != Success) + goto error; + if (val != fbconfig_id) + continue; + + /* Iterate over RGBA sizes in fbconfig */ + for (cn = 0; cn < 4; cn++) { + int size = 0; + + status = glXGetFBConfigAttrib (parent->display, + fbconfigs[n], rgba_colors[cn], &size); + if (status != Success) + goto error; + + /* Last check is for alpha + * and alpha is optional */ + if (cn == 3) { + if (size == 0 || size == 8) { + sizes_correct = TRUE; + break; + } + } else if (size != 8) + break; + } + if (sizes_correct) + break; + } + if (n == n_fbconfigs) + goto error; + } else { + choose_fbconfig: + fbconfigs = glXChooseFBConfig (cs->display, + screen, fbconfig_attrs, &n_fbconfigs); + if (!fbconfigs) + goto error; + + /* Select the first one */ + n = 0; + } + + cs->visual = glXGetVisualFromFBConfig (cs->display, fbconfigs[n]); + cs->context = glXCreateNewContext (cs->display, + fbconfigs[n], GLX_RGBA_TYPE, parent ? parent->context : NULL, True); + if (!cs->context) + goto error; + +end: + if (fbconfigs) + XFree (fbconfigs); + return cs; + + /* ERRORS */ +error: + { + gl_destroy_context (cs); + cs = NULL; + goto end; + } +} + +/** + * gl_destroy_context: + * @cs: a #GLContextState + * + * Destroys the GLX context @cs + */ +void +gl_destroy_context (GLContextState * cs) +{ + if (!cs) + return; + + if (cs->visual) { + XFree (cs->visual); + cs->visual = NULL; + } + + if (cs->display && cs->context) { + if (glXGetCurrentContext () == cs->context) { + /* XXX: if buffers were never swapped, the application + will crash later with the NVIDIA driver */ + if (!cs->swapped_buffers) + gl_swap_buffers (cs); + glXMakeCurrent (cs->display, None, NULL); + } + glXDestroyContext (cs->display, cs->context); + cs->display = NULL; + cs->context = NULL; + } + free (cs); +} + +/** + * gl_get_current_context: + * @cs: return location to the current #GLContextState + * + * Retrieves the current GLX context, display and drawable packed into + * the #GLContextState struct. + */ +void +gl_get_current_context (GLContextState * cs) +{ + cs->display = glXGetCurrentDisplay (); + cs->window = glXGetCurrentDrawable (); + cs->context = glXGetCurrentContext (); +} + +/** + * gl_set_current_context: + * @new_cs: the requested new #GLContextState + * @old_cs: return location to the context that was previously current + * + * Makes the @new_cs GLX context the current GLX rendering context of + * the calling thread, replacing the previously current context if + * there was one. + * + * If @old_cs is non %NULL, the previously current GLX context and + * window are recorded. + * + * Return value: %TRUE on success + */ +gboolean +gl_set_current_context (GLContextState * new_cs, GLContextState * old_cs) +{ + /* If display is NULL, this could be that new_cs was retrieved from + gl_get_current_context() with none set previously. If that case, + the other fields are also NULL and we don't return an error */ + if (!new_cs->display) + return !new_cs->window && !new_cs->context; + + if (old_cs) { + if (old_cs == new_cs) + return TRUE; + gl_get_current_context (old_cs); + if (old_cs->display == new_cs->display && + old_cs->window == new_cs->window && old_cs->context == new_cs->context) + return TRUE; + } + return glXMakeCurrent (new_cs->display, new_cs->window, new_cs->context); +} + +/** + * gl_swap_buffers: + * @cs: a #GLContextState + * + * Promotes the contents of the back buffer of the @win window to + * become the contents of the front buffer. This simply is wrapper + * around glXSwapBuffers(). + */ +void +gl_swap_buffers (GLContextState * cs) +{ + glXSwapBuffers (cs->display, cs->window); + cs->swapped_buffers = TRUE; +} + +static inline gboolean +_init_texture_state (GLTextureState * ts, GLenum target, GLuint texture, + gboolean enabled) +{ + GLenum binding; + + ts->target = target; + + if (enabled) { + binding = gl_get_texture_binding (target); + if (!binding) + return FALSE; + if (!gl_get_param (binding, &ts->old_texture)) + return FALSE; + ts->was_enabled = TRUE; + ts->was_bound = texture == ts->old_texture; + } else { + ts->old_texture = 0; + ts->was_enabled = FALSE; + ts->was_bound = FALSE; + } + + return TRUE; +} + +static inline gboolean +_bind_enabled_texture (GLenum target, GLuint texture) +{ + gl_purge_errors (); + glBindTexture (target, texture); + if (gl_check_error ()) + return FALSE; + return TRUE; +} + +/** + * gl_bind_texture: + * @ts: a #GLTextureState + * @target: the target to which the texture is bound + * @texture: the name of a texture + * + * Binds @texture to the specified @target, while recording the + * previous state in @ts. + * + * Return value: %TRUE on success + */ +gboolean +gl_bind_texture (GLTextureState * ts, GLenum target, GLuint texture) +{ + gboolean enabled; + + enabled = (gboolean) glIsEnabled (target); + if (!_init_texture_state (ts, target, texture, enabled)) + return FALSE; + if (ts->was_bound) + return TRUE; + if (!enabled) + glEnable (target); + + return _bind_enabled_texture (target, texture); +} + +/** + * gl3_bind_texture_2d: + * @ts: a #GLTextureState + * @target: the target to which the texture is bound + * @texture: the name of a texture + * + * Binds @texture to the specified @target, while recording the + * previous state in @ts. + * + * This function is for OpenGL3 API and for targets type GL_TEXTURE_2D. + * + * Return value: %TRUE on success + */ +gboolean +gl3_bind_texture_2d (GLTextureState * ts, GLenum target, GLuint texture) +{ + if (target != GL_TEXTURE_2D) + return FALSE; + + if (!_init_texture_state (ts, target, texture, TRUE)) + return FALSE; + if (ts->was_bound) + return TRUE; + + return _bind_enabled_texture (target, texture); +} + +/** + * gl_unbind_texture: + * @ts: a #GLTextureState + * + * Rebinds the texture that was previously bound and recorded in @ts. + */ +void +gl_unbind_texture (GLTextureState * ts) +{ + if (!ts->was_bound && ts->old_texture) + glBindTexture (ts->target, ts->old_texture); + if (!ts->was_enabled) + glDisable (ts->target); +} + +/** + * gl_create_texture: + * @target: the target to which the texture is bound + * @format: the format of the pixel data + * @width: the requested width, in pixels + * @height: the requested height, in pixels + * + * Creates a texture with the specified dimensions and @format. The + * internal format will be automatically derived from @format. + * + * Return value: the newly created texture name + */ +GLuint +gl_create_texture (GLenum target, GLenum format, guint width, guint height) +{ + GLenum internal_format; + GLuint texture; + GLTextureState ts; + guint bytes_per_component; + + internal_format = format; + switch (format) { + case GL_LUMINANCE: + bytes_per_component = 1; + break; + case GL_LUMINANCE_ALPHA: + bytes_per_component = 2; + break; + case GL_RGBA: + case GL_BGRA: + internal_format = GL_RGBA; + bytes_per_component = 4; + break; + default: + bytes_per_component = 0; + break; + } + g_assert (bytes_per_component > 0); + + glGenTextures (1, &texture); + if (!gl_bind_texture (&ts, target, texture)) + return 0; + glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glPixelStorei (GL_UNPACK_ALIGNMENT, bytes_per_component); + glTexImage2D (target, + 0, internal_format, width, height, 0, format, GL_UNSIGNED_BYTE, NULL); + gl_unbind_texture (&ts); + return texture; +} + +/** + * get_proc_address: + * @name: the name of the OpenGL extension function to lookup + * + * Returns the specified OpenGL extension function + * + * Return value: the OpenGL extension matching @name, or %NULL if none + * was found + */ +typedef void (*GLFuncPtr) (void); +typedef GLFuncPtr (*GLXGetProcAddressProc) (const gchar *); + +static GLFuncPtr +get_proc_address_default (const gchar * name) +{ + return NULL; +} + +static GLXGetProcAddressProc +get_proc_address_func (void) +{ + GLXGetProcAddressProc get_proc_func; + + dlerror (); + *(void **) (&get_proc_func) = dlsym (RTLD_DEFAULT, "glXGetProcAddress"); + if (!dlerror ()) + return get_proc_func; + + *(void **) (&get_proc_func) = dlsym (RTLD_DEFAULT, "glXGetProcAddressARB"); + if (!dlerror ()) + return get_proc_func; + + return get_proc_address_default; +} + +static inline GLFuncPtr +get_proc_address (const gchar * name) +{ + static GLXGetProcAddressProc get_proc_func = NULL; + if (!get_proc_func) + get_proc_func = get_proc_address_func (); + return get_proc_func (name); +} + +/** + * gl_init_vtable: + * + * Initializes the global #GLVTable. + * + * Return value: the #GLVTable filled in with OpenGL extensions, or + * %NULL on error. + */ +static GLVTable gl_vtable_static; + +static GLVTable * +gl_init_vtable (void) +{ + GLVTable *const gl_vtable = &gl_vtable_static; + const gchar *gl_extensions = (const gchar *) glGetString (GL_EXTENSIONS); + gboolean has_extension; + + /* GLX_EXT_texture_from_pixmap */ + gl_vtable->glx_create_pixmap = (PFNGLXCREATEPIXMAPPROC) + get_proc_address ("glXCreatePixmap"); + if (!gl_vtable->glx_create_pixmap) + return NULL; + gl_vtable->glx_destroy_pixmap = (PFNGLXDESTROYPIXMAPPROC) + get_proc_address ("glXDestroyPixmap"); + if (!gl_vtable->glx_destroy_pixmap) + return NULL; + gl_vtable->glx_bind_tex_image = (PFNGLXBINDTEXIMAGEEXTPROC) + get_proc_address ("glXBindTexImageEXT"); + if (!gl_vtable->glx_bind_tex_image) + return NULL; + gl_vtable->glx_release_tex_image = (PFNGLXRELEASETEXIMAGEEXTPROC) + get_proc_address ("glXReleaseTexImageEXT"); + if (!gl_vtable->glx_release_tex_image) + return NULL; + + /* GL_ARB_framebuffer_object */ + has_extension = (find_string ("GL_ARB_framebuffer_object", gl_extensions, " ") + || find_string ("GL_EXT_framebuffer_object", gl_extensions, " ") + ); + if (has_extension) { + gl_vtable->gl_gen_framebuffers = (PFNGLGENFRAMEBUFFERSEXTPROC) + get_proc_address ("glGenFramebuffersEXT"); + if (!gl_vtable->gl_gen_framebuffers) + return NULL; + gl_vtable->gl_delete_framebuffers = (PFNGLDELETEFRAMEBUFFERSEXTPROC) + get_proc_address ("glDeleteFramebuffersEXT"); + if (!gl_vtable->gl_delete_framebuffers) + return NULL; + gl_vtable->gl_bind_framebuffer = (PFNGLBINDFRAMEBUFFEREXTPROC) + get_proc_address ("glBindFramebufferEXT"); + if (!gl_vtable->gl_bind_framebuffer) + return NULL; + gl_vtable->gl_gen_renderbuffers = (PFNGLGENRENDERBUFFERSEXTPROC) + get_proc_address ("glGenRenderbuffersEXT"); + if (!gl_vtable->gl_gen_renderbuffers) + return NULL; + gl_vtable->gl_delete_renderbuffers = (PFNGLDELETERENDERBUFFERSEXTPROC) + get_proc_address ("glDeleteRenderbuffersEXT"); + if (!gl_vtable->gl_delete_renderbuffers) + return NULL; + gl_vtable->gl_bind_renderbuffer = (PFNGLBINDRENDERBUFFEREXTPROC) + get_proc_address ("glBindRenderbufferEXT"); + if (!gl_vtable->gl_bind_renderbuffer) + return NULL; + gl_vtable->gl_renderbuffer_storage = (PFNGLRENDERBUFFERSTORAGEEXTPROC) + get_proc_address ("glRenderbufferStorageEXT"); + if (!gl_vtable->gl_renderbuffer_storage) + return NULL; + gl_vtable->gl_framebuffer_renderbuffer = + (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) + get_proc_address ("glFramebufferRenderbufferEXT"); + if (!gl_vtable->gl_framebuffer_renderbuffer) + return NULL; + gl_vtable->gl_framebuffer_texture_2d = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) + get_proc_address ("glFramebufferTexture2DEXT"); + if (!gl_vtable->gl_framebuffer_texture_2d) + return NULL; + gl_vtable->gl_check_framebuffer_status = + (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) + get_proc_address ("glCheckFramebufferStatusEXT"); + if (!gl_vtable->gl_check_framebuffer_status) + return NULL; + gl_vtable->has_framebuffer_object = TRUE; + } + return gl_vtable; +} + +/** + * gl_get_vtable: + * + * Retrieves a VTable for OpenGL extensions. + * + * Return value: VTable for OpenGL extensions + */ +GLVTable * +gl_get_vtable (void) +{ + static gsize gl_vtable_init = FALSE; + static GLVTable *gl_vtable = NULL; + + if (g_once_init_enter (&gl_vtable_init)) { + gl_vtable = gl_init_vtable (); + g_once_init_leave (&gl_vtable_init, TRUE); + } + return gl_vtable; +} + +/** + * gl_create_pixmap_object: + * @dpy: an X11 #Display + * @width: the request width, in pixels + * @height: the request height, in pixels + * + * Creates a #GLPixmapObject of the specified dimensions. This + * requires the GLX_EXT_texture_from_pixmap extension. + * + * Return value: the newly created #GLPixmapObject object + */ +GLPixmapObject * +gl_create_pixmap_object (Display * dpy, guint width, guint height) +{ + GLVTable *const gl_vtable = gl_get_vtable (); + GLPixmapObject *pixo; + GLXFBConfig *fbconfig; + int screen; + Window rootwin; + XWindowAttributes wattr; + int *attr; + int n_fbconfig_attrs; + + int fbconfig_attrs[32] = { + GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, + GLX_DOUBLEBUFFER, GL_FALSE, + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_X_RENDERABLE, GL_TRUE, + GLX_Y_INVERTED_EXT, GL_TRUE, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_ALPHA_SIZE, 8, + GL_NONE, + }; + + int pixmap_attrs[10] = { + GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, + GLX_MIPMAP_TEXTURE_EXT, GL_FALSE, + GL_NONE, + }; + + if (!gl_vtable) + return NULL; + + screen = DefaultScreen (dpy); + rootwin = RootWindow (dpy, screen); + + /* XXX: this won't work for different displays */ + if (!gl_vtable->has_texture_from_pixmap) { + const gchar *glx_extensions = glXQueryExtensionsString (dpy, screen); + if (!glx_extensions) + return NULL; + if (!find_string ("GLX_EXT_texture_from_pixmap", glx_extensions, " ")) + return NULL; + gl_vtable->has_texture_from_pixmap = TRUE; + } + + pixo = calloc (1, sizeof (*pixo)); + if (!pixo) + return NULL; + + pixo->dpy = dpy; + pixo->width = width; + pixo->height = height; + pixo->pixmap = None; + pixo->glx_pixmap = None; + pixo->is_bound = FALSE; + + XGetWindowAttributes (dpy, rootwin, &wattr); + pixo->pixmap = XCreatePixmap (dpy, rootwin, width, height, wattr.depth); + if (!pixo->pixmap) + goto error; + + /* Initialize FBConfig attributes */ + for (attr = fbconfig_attrs; *attr != GL_NONE; attr += 2); + if (wattr.depth == 32) { + *attr++ = GLX_ALPHA_SIZE; + *attr++ = 8; + *attr++ = GLX_BIND_TO_TEXTURE_RGBA_EXT; + *attr++ = GL_TRUE; + } else { + *attr++ = GLX_BIND_TO_TEXTURE_RGB_EXT; + *attr++ = GL_TRUE; + } + *attr++ = GL_NONE; + + fbconfig = glXChooseFBConfig (dpy, screen, fbconfig_attrs, &n_fbconfig_attrs); + if (!fbconfig) + goto error; + + /* Initialize GLX Pixmap attributes */ + for (attr = pixmap_attrs; *attr != GL_NONE; attr += 2); + *attr++ = GLX_TEXTURE_FORMAT_EXT; + if (wattr.depth == 32) + *attr++ = GLX_TEXTURE_FORMAT_RGBA_EXT; + else + *attr++ = GLX_TEXTURE_FORMAT_RGB_EXT; + *attr++ = GL_NONE; + + x11_trap_errors (); + pixo->glx_pixmap = gl_vtable->glx_create_pixmap (dpy, + fbconfig[0], pixo->pixmap, pixmap_attrs); + free (fbconfig); + if (x11_untrap_errors () != 0) + goto error; + + pixo->target = GL_TEXTURE_2D; + glGenTextures (1, &pixo->texture); + if (!gl_bind_texture (&pixo->old_texture, pixo->target, pixo->texture)) + goto error; + glTexParameteri (pixo->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri (pixo->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + gl_unbind_texture (&pixo->old_texture); + return pixo; + + /* ERRORS */ +error: + { + gl_destroy_pixmap_object (pixo); + return NULL; + } +} + +/** + * gl_destroy_pixmap_object: + * @pixo: a #GLPixmapObject + * + * Destroys the #GLPixmapObject object. + */ +void +gl_destroy_pixmap_object (GLPixmapObject * pixo) +{ + GLVTable *const gl_vtable = gl_get_vtable (); + + if (!pixo) + return; + + gl_unbind_pixmap_object (pixo); + + if (pixo->texture) { + glDeleteTextures (1, &pixo->texture); + pixo->texture = 0; + } + + if (pixo->glx_pixmap) { + gl_vtable->glx_destroy_pixmap (pixo->dpy, pixo->glx_pixmap); + pixo->glx_pixmap = None; + } + + if (pixo->pixmap) { + XFreePixmap (pixo->dpy, pixo->pixmap); + pixo->pixmap = None; + } + free (pixo); +} + +/** + * gl_bind_pixmap_object: + * @pixo: a #GLPixmapObject + * + * Defines a two-dimensional texture image. The texture image is taken + * from the @pixo pixmap and need not be copied. The texture target, + * format and size are derived from attributes of the @pixo pixmap. + * + * Return value: %TRUE on success + */ +gboolean +gl_bind_pixmap_object (GLPixmapObject * pixo) +{ + GLVTable *const gl_vtable = gl_get_vtable (); + + if (pixo->is_bound) + return TRUE; + + if (!gl_bind_texture (&pixo->old_texture, pixo->target, pixo->texture)) + return FALSE; + + x11_trap_errors (); + gl_vtable->glx_bind_tex_image (pixo->dpy, + pixo->glx_pixmap, GLX_FRONT_LEFT_EXT, NULL); + XSync (pixo->dpy, False); + if (x11_untrap_errors () != 0) { + GST_DEBUG ("failed to bind pixmap"); + return FALSE; + } + + pixo->is_bound = TRUE; + return TRUE; +} + +/** + * gl_unbind_pixmap_object: + * @pixo: a #GLPixmapObject + * + * Releases a color buffers that is being used as a texture. + * + * Return value: %TRUE on success + */ +gboolean +gl_unbind_pixmap_object (GLPixmapObject * pixo) +{ + GLVTable *const gl_vtable = gl_get_vtable (); + + if (!pixo->is_bound) + return TRUE; + + x11_trap_errors (); + gl_vtable->glx_release_tex_image (pixo->dpy, + pixo->glx_pixmap, GLX_FRONT_LEFT_EXT); + XSync (pixo->dpy, False); + if (x11_untrap_errors () != 0) { + GST_DEBUG ("failed to release pixmap"); + return FALSE; + } + + gl_unbind_texture (&pixo->old_texture); + + pixo->is_bound = FALSE; + return TRUE; +} + +/** + * gl_create_framebuffer_object: + * @target: the target to which the texture is bound + * @texture: the GL texture to hold the framebuffer + * @width: the requested width, in pixels + * @height: the requested height, in pixels + * + * Creates an FBO with the specified texture and size. + * + * Return value: the newly created #GLFramebufferObject, or %NULL if + * an error occurred + */ +GLFramebufferObject * +gl_create_framebuffer_object (GLenum target, + GLuint texture, guint width, guint height) +{ + GLVTable *const gl_vtable = gl_get_vtable (); + GLFramebufferObject *fbo; + GLenum status; + + if (!gl_vtable || !gl_vtable->has_framebuffer_object) + return NULL; + + /* XXX: we only support GL_TEXTURE_2D at this time */ + if (target != GL_TEXTURE_2D) + return NULL; + + fbo = calloc (1, sizeof (*fbo)); + if (!fbo) + return NULL; + + fbo->width = width; + fbo->height = height; + fbo->fbo = 0; + fbo->old_fbo = 0; + fbo->is_bound = FALSE; + + gl_get_param (GL_FRAMEBUFFER_BINDING, &fbo->old_fbo); + gl_vtable->gl_gen_framebuffers (1, &fbo->fbo); + gl_vtable->gl_bind_framebuffer (GL_FRAMEBUFFER_EXT, fbo->fbo); + gl_vtable->gl_framebuffer_texture_2d (GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, target, texture, 0); + + status = gl_vtable->gl_check_framebuffer_status (GL_DRAW_FRAMEBUFFER_EXT); + gl_vtable->gl_bind_framebuffer (GL_FRAMEBUFFER_EXT, fbo->old_fbo); + if (status != GL_FRAMEBUFFER_COMPLETE_EXT) + goto error; + return fbo; + + /* ERRORS */ +error: + { + gl_destroy_framebuffer_object (fbo); + return NULL; + } +} + +/** + * gl_destroy_framebuffer_object: + * @fbo: a #GLFramebufferObject + * + * Destroys the @fbo object. + */ +void +gl_destroy_framebuffer_object (GLFramebufferObject * fbo) +{ + GLVTable *const gl_vtable = gl_get_vtable (); + + if (!fbo) + return; + + gl_unbind_framebuffer_object (fbo); + + if (fbo->fbo) { + gl_vtable->gl_delete_framebuffers (1, &fbo->fbo); + fbo->fbo = 0; + } + free (fbo); +} + +/** + * gl_bind_framebuffer_object: + * @fbo: a #GLFramebufferObject + * + * Binds @fbo object. + * + * Return value: %TRUE on success + */ +gboolean +gl_bind_framebuffer_object (GLFramebufferObject * fbo) +{ + GLVTable *const gl_vtable = gl_get_vtable (); + const guint width = fbo->width; + const guint height = fbo->height; + + const guint attribs = (GL_VIEWPORT_BIT | + GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT); + + if (fbo->is_bound) + return TRUE; + + gl_get_param (GL_FRAMEBUFFER_BINDING, &fbo->old_fbo); + gl_vtable->gl_bind_framebuffer (GL_FRAMEBUFFER_EXT, fbo->fbo); + glPushAttrib (attribs); + glMatrixMode (GL_PROJECTION); + glPushMatrix (); + glLoadIdentity (); + glMatrixMode (GL_MODELVIEW); + glPushMatrix (); + glLoadIdentity (); + glViewport (0, 0, width, height); + glTranslatef (-1.0f, -1.0f, 0.0f); + glScalef (2.0f / width, 2.0f / height, 1.0f); + + fbo->is_bound = TRUE; + return TRUE; +} + +/** + * gl_unbind_framebuffer_object: + * @fbo: a #GLFramebufferObject + * + * Releases @fbo object. + * + * Return value: %TRUE on success + */ +gboolean +gl_unbind_framebuffer_object (GLFramebufferObject * fbo) +{ + GLVTable *const gl_vtable = gl_get_vtable (); + + if (!fbo->is_bound) + return TRUE; + + glPopAttrib (); + glMatrixMode (GL_PROJECTION); + glPopMatrix (); + glMatrixMode (GL_MODELVIEW); + glPopMatrix (); + gl_vtable->gl_bind_framebuffer (GL_FRAMEBUFFER_EXT, fbo->old_fbo); + + fbo->is_bound = FALSE; + return TRUE; +} + +/** + * gl_get_current_api: + * @major: (out): (allow-none): the GL major version + * @minor: (out): (allow-none): the GL minor version + * + * If an error occurs, @major and @minor aren't modified and + * %GST_VAAPI_GL_API_NONE is returned. + * + * This is an adaptation of gst_gl_context_get_current_gl_api() from GstGL. + * + * Returns: The version supported by the OpenGL context current in the calling + * thread or %GST_VAAPI_GL_API_NONE + */ +GstVaapiGLApi +gl_get_current_api (guint * major, guint * minor) +{ + const gchar *version; + gint maj, min, n, sret; + GstVaapiGLApi ret = (1 << 31); + + while (ret != GST_VAAPI_GL_API_NONE) { + version = (const gchar *) glGetString (GL_VERSION); + if (!version) + goto next; + + /* strlen (x.x) == 3 */ + n = strlen (version); + if (n < 3) + goto next; + + if (g_strstr_len (version, 9, "OpenGL ES")) { + /* strlen (OpenGL ES x.x) == 13 */ + if (n < 13) + goto next; + + sret = sscanf (&version[10], "%d.%d", &maj, &min); + if (sret != 2) + goto next; + + if (maj <= 0 || min < 0) + goto next; + + if (maj == 1) { + ret = GST_VAAPI_GL_API_GLES1; + break; + } else if (maj == 2 || maj == 3) { + ret = GST_VAAPI_GL_API_GLES2; + break; + } + + goto next; + } else { + sret = sscanf (version, "%d.%d", &maj, &min); + if (sret != 2) + goto next; + + if (maj <= 0 || min < 0) + goto next; + + if (maj > 3 || (maj == 3 && min > 1)) { + GLuint context_flags = 0; + + ret = GST_VAAPI_GL_API_NONE; + if (!gl_get_param (GL_CONTEXT_PROFILE_MASK, &context_flags)) + break; + + if (context_flags & GL_CONTEXT_CORE_PROFILE_BIT) + ret |= GST_VAAPI_GL_API_OPENGL3; + if (context_flags & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) + ret |= GST_VAAPI_GL_API_OPENGL; + break; + } + + ret = GST_VAAPI_GL_API_OPENGL; + break; + } + + next: + /* iterate through the apis */ + ret >>= 1; + } + + if (ret == GST_VAAPI_GL_API_NONE) + return GST_VAAPI_GL_API_NONE; + + if (major) + *major = maj; + if (minor) + *minor = min; + + return ret; +} diff --git a/gst-libs/gst/vaapi/gstvaapiutils_glx.h b/gst-libs/gst/vaapi/gstvaapiutils_glx.h new file mode 100644 index 0000000000..f5c632cc4c --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_glx.h @@ -0,0 +1,230 @@ +/* + * gstvaapiutils_glx.h - GLX utilties + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_UTILS_GLX_H +#define GST_VAAPI_UTILS_GLX_H + +#include "config.h" +#include +#include +#include + +#if GLX_GLXEXT_VERSION < 18 +typedef void (*PFNGLXBINDTEXIMAGEEXTPROC) (Display *, GLXDrawable, int, + const int *); +typedef void (*PFNGLXRELEASETEXIMAGEEXTPROC) (Display *, GLXDrawable, int); +#endif + +#if GLX_GLXEXT_VERSION < 27 +/* XXX: this is not exactly that version but this is the only means to + make sure we have the correct with those signatures */ +typedef GLXPixmap (*PFNGLXCREATEPIXMAPPROC) (Display *, GLXFBConfig, Pixmap, + const int *); +typedef void (*PFNGLXDESTROYPIXMAPPROC) (Display *, GLXPixmap); +#endif + +#ifndef GL_FRAMEBUFFER_BINDING +#define GL_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING_EXT +#endif + +G_GNUC_INTERNAL +const gchar * +gl_get_error_string (GLenum error); + +G_GNUC_INTERNAL +void +gl_purge_errors (void); + +G_GNUC_INTERNAL +gboolean +gl_check_error (void); + +G_GNUC_INTERNAL +gboolean +gl_get_param (GLenum param, guint * pval); + +G_GNUC_INTERNAL +gboolean +gl_get_texture_param (GLenum target, GLenum param, guint * pval); + +G_GNUC_INTERNAL +void +gl_set_bgcolor (guint32 color); + +G_GNUC_INTERNAL +void +gl_resize (guint width, guint height); + +typedef struct _GLContextState GLContextState; +struct _GLContextState +{ + Display *display; + Window window; + XVisualInfo *visual; + GLXContext context; + guint swapped_buffers:1; +}; + +G_GNUC_INTERNAL +GLContextState * +gl_create_context (Display * dpy, int screen, GLContextState * parent); + +G_GNUC_INTERNAL +void +gl_destroy_context (GLContextState * cs); + +G_GNUC_INTERNAL +void +gl_get_current_context (GLContextState * cs); + +G_GNUC_INTERNAL +gboolean +gl_set_current_context (GLContextState * new_cs, GLContextState * old_cs); + +G_GNUC_INTERNAL +void +gl_swap_buffers (GLContextState * cs); + +typedef struct _GLTextureState GLTextureState; +struct _GLTextureState +{ + GLenum target; + GLuint old_texture; + guint was_enabled:1; + guint was_bound:1; +}; + +G_GNUC_INTERNAL +gboolean +gl_bind_texture (GLTextureState * ts, GLenum target, GLuint texture); + +G_GNUC_INTERNAL +gboolean +gl3_bind_texture_2d (GLTextureState * ts, GLenum target, GLuint texture); + +G_GNUC_INTERNAL +void +gl_unbind_texture (GLTextureState * ts); + +G_GNUC_INTERNAL +GLuint +gl_create_texture (GLenum target, GLenum format, guint width, guint height); + +typedef struct _GLVTable GLVTable; +struct _GLVTable +{ + PFNGLXCREATEPIXMAPPROC glx_create_pixmap; + PFNGLXDESTROYPIXMAPPROC glx_destroy_pixmap; + PFNGLXBINDTEXIMAGEEXTPROC glx_bind_tex_image; + PFNGLXRELEASETEXIMAGEEXTPROC glx_release_tex_image; + PFNGLGENFRAMEBUFFERSEXTPROC gl_gen_framebuffers; + PFNGLDELETEFRAMEBUFFERSEXTPROC gl_delete_framebuffers; + PFNGLBINDFRAMEBUFFEREXTPROC gl_bind_framebuffer; + PFNGLGENRENDERBUFFERSEXTPROC gl_gen_renderbuffers; + PFNGLDELETERENDERBUFFERSEXTPROC gl_delete_renderbuffers; + PFNGLBINDRENDERBUFFEREXTPROC gl_bind_renderbuffer; + PFNGLRENDERBUFFERSTORAGEEXTPROC gl_renderbuffer_storage; + PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC gl_framebuffer_renderbuffer; + PFNGLFRAMEBUFFERTEXTURE2DEXTPROC gl_framebuffer_texture_2d; + PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC gl_check_framebuffer_status; + guint has_texture_from_pixmap:1; + guint has_framebuffer_object:1; +}; + +G_GNUC_INTERNAL +GLVTable * +gl_get_vtable (void); + +typedef struct _GLPixmapObject GLPixmapObject; +struct _GLPixmapObject +{ + Display *dpy; + GLenum target; + GLuint texture; + GLTextureState old_texture; + guint width; + guint height; + Pixmap pixmap; + GLXPixmap glx_pixmap; + guint is_bound:1; +}; + +G_GNUC_INTERNAL +GLPixmapObject * +gl_create_pixmap_object (Display * dpy, guint width, guint height); + +G_GNUC_INTERNAL +void +gl_destroy_pixmap_object (GLPixmapObject * pixo); + +G_GNUC_INTERNAL +gboolean +gl_bind_pixmap_object (GLPixmapObject * pixo); + +G_GNUC_INTERNAL +gboolean +gl_unbind_pixmap_object (GLPixmapObject * pixo); + +typedef struct _GLFramebufferObject GLFramebufferObject; +struct _GLFramebufferObject +{ + guint width; + guint height; + GLuint fbo; + GLuint old_fbo; + guint is_bound:1; +}; + +G_GNUC_INTERNAL +GLFramebufferObject * +gl_create_framebuffer_object (GLenum target, + GLuint texture, guint width, guint height); + +G_GNUC_INTERNAL +void +gl_destroy_framebuffer_object (GLFramebufferObject * fbo); + +G_GNUC_INTERNAL +gboolean +gl_bind_framebuffer_object (GLFramebufferObject * fbo); + +G_GNUC_INTERNAL +gboolean +gl_unbind_framebuffer_object (GLFramebufferObject * fbo); + +typedef enum { + GST_VAAPI_GL_API_NONE = 0, + GST_VAAPI_GL_API_OPENGL = (1 << 0), + GST_VAAPI_GL_API_OPENGL3 = (1 << 1), + GST_VAAPI_GL_API_GLES1 = (1 << 15), + GST_VAAPI_GL_API_GLES2 = (1 << 16), + + GST_VAAPI_GL_API_ANY = G_MAXUINT32 +} GstVaapiGLApi; + +G_GNUC_INTERNAL +GstVaapiGLApi +gl_get_current_api (guint * major, guint * minor); + +#endif /* GST_VAAPI_UTILS_GLX_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiutils_h264.c b/gst-libs/gst/vaapi/gstvaapiutils_h264.c new file mode 100644 index 0000000000..0d01253f21 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_h264.c @@ -0,0 +1,409 @@ +/* + * gstvaapiutils_h264.c - H.264 related utilities + * + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include +#include "gstvaapicompat.h" +#include "gstvaapiutils_h264_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +struct map +{ + guint value; + const gchar *name; +}; + +/* Profile string map */ +static const struct map gst_vaapi_h264_profile_map[] = { +/* *INDENT-OFF* */ + { GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE, "constrained-baseline" }, + { GST_VAAPI_PROFILE_H264_BASELINE, "baseline" }, + { GST_VAAPI_PROFILE_H264_MAIN, "main" }, + { GST_VAAPI_PROFILE_H264_EXTENDED, "extended" }, + { GST_VAAPI_PROFILE_H264_HIGH, "high" }, + { GST_VAAPI_PROFILE_H264_HIGH10, "high-10" }, + { GST_VAAPI_PROFILE_H264_HIGH_422, "high-4:2:2" }, + { GST_VAAPI_PROFILE_H264_HIGH_444, "high-4:4:4" }, + { GST_VAAPI_PROFILE_H264_SCALABLE_BASELINE, "scalable-baseline" }, + { GST_VAAPI_PROFILE_H264_SCALABLE_HIGH, "scalable-high" }, + { GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH, "multiview-high" }, + { GST_VAAPI_PROFILE_H264_STEREO_HIGH, "stereo-high" }, + { 0, NULL } +/* *INDENT-ON* */ +}; + +/* Level string map */ +static const struct map gst_vaapi_h264_level_map[] = { +/* *INDENT-OFF* */ + { GST_VAAPI_LEVEL_H264_L1, "1" }, + { GST_VAAPI_LEVEL_H264_L1b, "1b" }, + { GST_VAAPI_LEVEL_H264_L1_1, "1.1" }, + { GST_VAAPI_LEVEL_H264_L1_2, "1.2" }, + { GST_VAAPI_LEVEL_H264_L1_3, "1.3" }, + { GST_VAAPI_LEVEL_H264_L2, "2" }, + { GST_VAAPI_LEVEL_H264_L2_1, "2.1" }, + { GST_VAAPI_LEVEL_H264_L2_2, "2.2" }, + { GST_VAAPI_LEVEL_H264_L3, "3" }, + { GST_VAAPI_LEVEL_H264_L3_1, "3.1" }, + { GST_VAAPI_LEVEL_H264_L3_2, "3.2" }, + { GST_VAAPI_LEVEL_H264_L4, "4" }, + { GST_VAAPI_LEVEL_H264_L4_1, "4.1" }, + { GST_VAAPI_LEVEL_H264_L4_2, "4.2" }, + { GST_VAAPI_LEVEL_H264_L5, "5" }, + { GST_VAAPI_LEVEL_H264_L5_1, "5.1" }, + { GST_VAAPI_LEVEL_H264_L5_2, "5.2" }, + { GST_VAAPI_LEVEL_H264_L6, "6" }, + { GST_VAAPI_LEVEL_H264_L6_1, "6.1" }, + { GST_VAAPI_LEVEL_H264_L6_2, "6.2" }, + { 0, NULL } +/* *INDENT-ON* */ +}; + +/* Table A-1 - Level limits */ +/* *INDENT-OFF* */ +static const GstVaapiH264LevelLimits gst_vaapi_h264_level_limits[] = { + /* level idc MaxMBPS MaxFS MaxDpbMbs MaxBR MaxCPB MinCr */ + { GST_VAAPI_LEVEL_H264_L1, 10, 1485, 99, 396, 64, 175, 2 }, + { GST_VAAPI_LEVEL_H264_L1b, 11, 1485, 99, 396, 128, 350, 2 }, + { GST_VAAPI_LEVEL_H264_L1_1, 11, 3000, 396, 900, 192, 500, 2 }, + { GST_VAAPI_LEVEL_H264_L1_2, 12, 6000, 396, 2376, 384, 1000, 2 }, + { GST_VAAPI_LEVEL_H264_L1_3, 13, 11880, 396, 2376, 768, 2000, 2 }, + { GST_VAAPI_LEVEL_H264_L2, 20, 11880, 396, 2376, 2000, 2000, 2 }, + { GST_VAAPI_LEVEL_H264_L2_1, 21, 19800, 792, 4752, 4000, 4000, 2 }, + { GST_VAAPI_LEVEL_H264_L2_2, 22, 20250, 1620, 8100, 4000, 4000, 2 }, + { GST_VAAPI_LEVEL_H264_L3, 30, 40500, 1620, 8100, 10000, 10000, 2 }, + { GST_VAAPI_LEVEL_H264_L3_1, 31, 108000, 3600, 18000, 14000, 14000, 4 }, + { GST_VAAPI_LEVEL_H264_L3_2, 32, 216000, 5120, 20480, 20000, 20000, 4 }, + { GST_VAAPI_LEVEL_H264_L4, 40, 245760, 8192, 32768, 20000, 25000, 4 }, + { GST_VAAPI_LEVEL_H264_L4_1, 41, 245760, 8192, 32768, 50000, 62500, 2 }, + { GST_VAAPI_LEVEL_H264_L4_2, 42, 522240, 8704, 34816, 50000, 62500, 2 }, + { GST_VAAPI_LEVEL_H264_L5, 50, 589824, 22080, 110400, 135000, 135000, 2 }, + { GST_VAAPI_LEVEL_H264_L5_1, 51, 983040, 36864, 184320, 240000, 240000, 2 }, + { GST_VAAPI_LEVEL_H264_L5_2, 52, 2073600, 36864, 184320, 240000, 240000, 2 }, + { GST_VAAPI_LEVEL_H264_L6, 60, 4177920, 139264, 696320, 240000, 240000, 2 }, + { GST_VAAPI_LEVEL_H264_L6_1, 61, 8355840, 139264, 696320, 480000, 480000, 2 }, + { GST_VAAPI_LEVEL_H264_L6_2, 62, 16711680, 139264, 696320, 800000, 800000, 2 }, + { 0, } +}; +/* *INDENT-ON* */ + +/* Lookup value in map */ +static const struct map * +map_lookup_value (const struct map *m, guint value) +{ + g_return_val_if_fail (m != NULL, NULL); + + for (; m->name != NULL; m++) { + if (m->value == value) + return m; + } + return NULL; +} + +/* Lookup name in map */ +static const struct map * +map_lookup_name (const struct map *m, const gchar * name) +{ + g_return_val_if_fail (m != NULL, NULL); + + if (!name) + return NULL; + + for (; m->name != NULL; m++) { + if (strcmp (m->name, name) == 0) + return m; + } + return NULL; +} + +/** Returns a relative score for the supplied GstVaapiProfile */ +guint +gst_vaapi_utils_h264_get_profile_score (GstVaapiProfile profile) +{ + const struct map *const m = + map_lookup_value (gst_vaapi_h264_profile_map, profile); + + return m ? 1 + (m - gst_vaapi_h264_profile_map) : 0; +} + +/** Returns GstVaapiProfile from H.264 profile_idc value */ +GstVaapiProfile +gst_vaapi_utils_h264_get_profile (guint8 profile_idc) +{ + GstVaapiProfile profile; + + switch (profile_idc) { + case GST_H264_PROFILE_BASELINE: + profile = GST_VAAPI_PROFILE_H264_BASELINE; + break; + case GST_H264_PROFILE_MAIN: + profile = GST_VAAPI_PROFILE_H264_MAIN; + break; + case GST_H264_PROFILE_EXTENDED: + profile = GST_VAAPI_PROFILE_H264_EXTENDED; + break; + case GST_H264_PROFILE_HIGH: + profile = GST_VAAPI_PROFILE_H264_HIGH; + break; + case GST_H264_PROFILE_HIGH10: + profile = GST_VAAPI_PROFILE_H264_HIGH10; + break; + case GST_H264_PROFILE_HIGH_422: + profile = GST_VAAPI_PROFILE_H264_HIGH_422; + break; + case GST_H264_PROFILE_HIGH_444: + profile = GST_VAAPI_PROFILE_H264_HIGH_444; + break; + case GST_H264_PROFILE_SCALABLE_BASELINE: + profile = GST_VAAPI_PROFILE_H264_SCALABLE_BASELINE; + break; + case GST_H264_PROFILE_SCALABLE_HIGH: + profile = GST_VAAPI_PROFILE_H264_SCALABLE_HIGH; + break; + case GST_H264_PROFILE_MULTIVIEW_HIGH: + profile = GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH; + break; + case GST_H264_PROFILE_STEREO_HIGH: + profile = GST_VAAPI_PROFILE_H264_STEREO_HIGH; + break; + default: + GST_DEBUG ("unsupported profile_idc value"); + profile = GST_VAAPI_PROFILE_UNKNOWN; + break; + } + return profile; +} + +/** Returns H.264 profile_idc value from GstVaapiProfile */ +guint8 +gst_vaapi_utils_h264_get_profile_idc (GstVaapiProfile profile) +{ + guint8 profile_idc; + + switch (profile) { + case GST_VAAPI_PROFILE_H264_BASELINE: + case GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE: + profile_idc = GST_H264_PROFILE_BASELINE; + break; + case GST_VAAPI_PROFILE_H264_MAIN: + profile_idc = GST_H264_PROFILE_MAIN; + break; + case GST_VAAPI_PROFILE_H264_EXTENDED: + profile_idc = GST_H264_PROFILE_EXTENDED; + break; + case GST_VAAPI_PROFILE_H264_HIGH: + profile_idc = GST_H264_PROFILE_HIGH; + break; + case GST_VAAPI_PROFILE_H264_HIGH10: + profile_idc = GST_H264_PROFILE_HIGH10; + break; + case GST_VAAPI_PROFILE_H264_HIGH_422: + profile_idc = GST_H264_PROFILE_HIGH_422; + break; + case GST_VAAPI_PROFILE_H264_HIGH_444: + profile_idc = GST_H264_PROFILE_HIGH_444; + break; + case GST_VAAPI_PROFILE_H264_SCALABLE_BASELINE: + profile_idc = GST_H264_PROFILE_SCALABLE_BASELINE; + break; + case GST_VAAPI_PROFILE_H264_SCALABLE_HIGH: + profile_idc = GST_H264_PROFILE_SCALABLE_HIGH; + break; + case GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH: + profile_idc = GST_H264_PROFILE_MULTIVIEW_HIGH; + break; + case GST_VAAPI_PROFILE_H264_STEREO_HIGH: + profile_idc = GST_H264_PROFILE_STEREO_HIGH; + break; + default: + GST_DEBUG ("unsupported GstVaapiProfile value"); + profile_idc = 0; + break; + } + return profile_idc; +} + +/** Returns GstVaapiProfile from a string representation */ +GstVaapiProfile +gst_vaapi_utils_h264_get_profile_from_string (const gchar * str) +{ + const struct map *const m = map_lookup_name (gst_vaapi_h264_profile_map, str); + + return m ? (GstVaapiProfile) m->value : GST_VAAPI_PROFILE_UNKNOWN; +} + +/** Returns a string representation for the supplied H.264 profile */ +const gchar * +gst_vaapi_utils_h264_get_profile_string (GstVaapiProfile profile) +{ + const struct map *const m = + map_lookup_value (gst_vaapi_h264_profile_map, profile); + + return m ? m->name : NULL; +} + +/** Returns GstVaapiLevelH264 from H.264 level_idc value */ +GstVaapiLevelH264 +gst_vaapi_utils_h264_get_level (guint8 level_idc) +{ + const GstVaapiH264LevelLimits *llp; + + // Prefer Level 1.1 over level 1b + if (G_UNLIKELY (level_idc == 11)) + return GST_VAAPI_LEVEL_H264_L1_1; + + for (llp = gst_vaapi_h264_level_limits; llp->level != 0; llp++) { + if (llp->level_idc == level_idc) + return llp->level; + } + GST_DEBUG ("unsupported level_idc value"); + return (GstVaapiLevelH264) 0; +} + +/** Returns H.264 level_idc value from GstVaapiLevelH264 */ +guint8 +gst_vaapi_utils_h264_get_level_idc (GstVaapiLevelH264 level) +{ + const GstVaapiH264LevelLimits *const llp = + gst_vaapi_utils_h264_get_level_limits (level); + + return llp ? llp->level_idc : 0; +} + +/** Returns GstVaapiLevelH264 from a string representation */ +GstVaapiLevelH264 +gst_vaapi_utils_h264_get_level_from_string (const gchar * str) +{ + gint v, level_idc = 0; + + if (!str || !str[0]) + goto not_found; + + v = g_ascii_digit_value (str[0]); + if (v < 0) + goto not_found; + level_idc = v * 10; + + switch (str[1]) { + case '\0': + break; + case '.': + v = g_ascii_digit_value (str[2]); + if (v < 0 || str[3] != '\0') + goto not_found; + level_idc += v; + break; + case 'b': + if (level_idc == 10 && str[2] == '\0') + return GST_VAAPI_LEVEL_H264_L1b; + // fall-trough + default: + goto not_found; + } + return gst_vaapi_utils_h264_get_level (level_idc); + +not_found: + return (GstVaapiLevelH264) 0; +} + +/** Returns a string representation for the supplied H.264 level */ +const gchar * +gst_vaapi_utils_h264_get_level_string (GstVaapiLevelH264 level) +{ + if (level < GST_VAAPI_LEVEL_H264_L1 || level > GST_VAAPI_LEVEL_H264_L6_2) + return NULL; + return gst_vaapi_h264_level_map[level - GST_VAAPI_LEVEL_H264_L1].name; +} + +/** Returns level limits as specified in Table A-1 of the H.264 standard */ +const GstVaapiH264LevelLimits * +gst_vaapi_utils_h264_get_level_limits (GstVaapiLevelH264 level) +{ + if (level < GST_VAAPI_LEVEL_H264_L1 || level > GST_VAAPI_LEVEL_H264_L6_2) + return NULL; + return &gst_vaapi_h264_level_limits[level - GST_VAAPI_LEVEL_H264_L1]; +} + +/** Returns the Table A-1 specification */ +const GstVaapiH264LevelLimits * +gst_vaapi_utils_h264_get_level_limits_table (guint * out_length_ptr) +{ + if (out_length_ptr) + *out_length_ptr = G_N_ELEMENTS (gst_vaapi_h264_level_limits) - 1; + return gst_vaapi_h264_level_limits; +} + +/** Returns GstVaapiChromaType from H.264 chroma_format_idc value */ +GstVaapiChromaType +gst_vaapi_utils_h264_get_chroma_type (guint chroma_format_idc) +{ + GstVaapiChromaType chroma_type; + + switch (chroma_format_idc) { + case 0: + chroma_type = GST_VAAPI_CHROMA_TYPE_YUV400; + break; + case 1: + chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420; + break; + case 2: + chroma_type = GST_VAAPI_CHROMA_TYPE_YUV422; + break; + case 3: + chroma_type = GST_VAAPI_CHROMA_TYPE_YUV444; + break; + default: + GST_DEBUG ("unsupported chroma_format_idc value"); + chroma_type = (GstVaapiChromaType) 0; + break; + } + return chroma_type; +} + +/** Returns H.264 chroma_format_idc value from GstVaapiChromaType */ +guint +gst_vaapi_utils_h264_get_chroma_format_idc (GstVaapiChromaType chroma_type) +{ + guint chroma_format_idc; + + switch (chroma_type) { + case GST_VAAPI_CHROMA_TYPE_YUV400: + chroma_format_idc = 0; + break; + case GST_VAAPI_CHROMA_TYPE_YUV420: + chroma_format_idc = 1; + break; + case GST_VAAPI_CHROMA_TYPE_YUV422: + chroma_format_idc = 2; + break; + case GST_VAAPI_CHROMA_TYPE_YUV444: + chroma_format_idc = 3; + break; + default: + GST_DEBUG ("unsupported GstVaapiChromaType value"); + chroma_format_idc = 1; + break; + } + return chroma_format_idc; +} diff --git a/gst-libs/gst/vaapi/gstvaapiutils_h264.h b/gst-libs/gst/vaapi/gstvaapiutils_h264.h new file mode 100644 index 0000000000..38d1341957 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_h264.h @@ -0,0 +1,99 @@ +/* + * gstvaapiutils_h264.h - H.264 related utilities + * + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_UTILS_H264_H +#define GST_VAAPI_UTILS_H264_H + +#include + +G_BEGIN_DECLS + +/** + * GstVaapiLevelH264: + * @GST_VAAPI_LEVEL_H264_L1: H.264 level 1. + * @GST_VAAPI_LEVEL_H264_L1_1: H.264 level 1.1. + * @GST_VAAPI_LEVEL_H264_L1_2: H.264 level 1.2. + * @GST_VAAPI_LEVEL_H264_L1_3: H.264 level 1.3. + * @GST_VAAPI_LEVEL_H264_L2: H.264 level 2. + * @GST_VAAPI_LEVEL_H264_L2_1: H.264 level 2.1. + * @GST_VAAPI_LEVEL_H264_L2_2: H.264 level 2.2. + * @GST_VAAPI_LEVEL_H264_L3: H.264 level 3. + * @GST_VAAPI_LEVEL_H264_L3_1: H.264 level 3.1. + * @GST_VAAPI_LEVEL_H264_L3_2: H.264 level 3.2. + * @GST_VAAPI_LEVEL_H264_L4: H.264 level 4. + * @GST_VAAPI_LEVEL_H264_L4_1: H.264 level 4.1. + * @GST_VAAPI_LEVEL_H264_L4_2: H.264 level 4.2. + * @GST_VAAPI_LEVEL_H264_L5: H.264 level 5. + * @GST_VAAPI_LEVEL_H264_L5_1: H.264 level 5.1. + * @GST_VAAPI_LEVEL_H264_L5_2: H.264 level 5.2. + * @GST_VAAPI_LEVEL_H264_L6: H.264 level 6. + * @GST_VAAPI_LEVEL_H264_L6_1: H.264 level 6.1. + * @GST_VAAPI_LEVEL_H264_L6_2: H.264 level 6.2. + * + * The set of all levels for #GstVaapiLevelH264. + */ +typedef enum { + GST_VAAPI_LEVEL_H264_L1 = 1, + GST_VAAPI_LEVEL_H264_L1b, + GST_VAAPI_LEVEL_H264_L1_1, + GST_VAAPI_LEVEL_H264_L1_2, + GST_VAAPI_LEVEL_H264_L1_3, + GST_VAAPI_LEVEL_H264_L2, + GST_VAAPI_LEVEL_H264_L2_1, + GST_VAAPI_LEVEL_H264_L2_2, + GST_VAAPI_LEVEL_H264_L3, + GST_VAAPI_LEVEL_H264_L3_1, + GST_VAAPI_LEVEL_H264_L3_2, + GST_VAAPI_LEVEL_H264_L4, + GST_VAAPI_LEVEL_H264_L4_1, + GST_VAAPI_LEVEL_H264_L4_2, + GST_VAAPI_LEVEL_H264_L5, + GST_VAAPI_LEVEL_H264_L5_1, + GST_VAAPI_LEVEL_H264_L5_2, + GST_VAAPI_LEVEL_H264_L6, + GST_VAAPI_LEVEL_H264_L6_1, + GST_VAAPI_LEVEL_H264_L6_2, +} GstVaapiLevelH264; + +/* Returns a relative score for the supplied GstVaapiProfile */ +guint +gst_vaapi_utils_h264_get_profile_score (GstVaapiProfile profile); + +/* Returns GstVaapiProfile from a string representation */ +GstVaapiProfile +gst_vaapi_utils_h264_get_profile_from_string (const gchar * str); + +/* Returns a string representation for the supplied H.264 profile */ +const gchar * +gst_vaapi_utils_h264_get_profile_string (GstVaapiProfile profile); + +/* Returns GstVaapiLevelH264 from a string representation */ +GstVaapiLevelH264 +gst_vaapi_utils_h264_get_level_from_string (const gchar * str); + +/* Returns a string representation for the supplied H.264 level */ +const gchar * +gst_vaapi_utils_h264_get_level_string (GstVaapiLevelH264 level); + +G_END_DECLS + +#endif /* GST_VAAPI_UTILS_H264_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiutils_h264_priv.h b/gst-libs/gst/vaapi/gstvaapiutils_h264_priv.h new file mode 100644 index 0000000000..eb582f5ee7 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_h264_priv.h @@ -0,0 +1,97 @@ +/* + * gstvaapiutils_h264_priv.h - H.264 related utilities + * + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_UTILS_H264_PRIV_H +#define GST_VAAPI_UTILS_H264_PRIV_H + +#include "gstvaapiutils_h264.h" +#include "gstvaapisurface.h" + +G_BEGIN_DECLS + +/** + * GstVaapiH264LevelLimits: + * @level: the #GstVaapiLevelH264 + * @level_idc: the H.264 level_idc value + * @MaxMBPS: the maximum macroblock processing rate (MB/sec) + * @MaxFS: the maximum frame size (MBs) + * @MaxDpbMbs: the maxium decoded picture buffer size (MBs) + * @MaxBR: the maximum video bit rate (kbps) + * @MaxCPB: the maximum CPB size (kbits) + * @MinCR: the minimum Compression Ratio + * + * The data structure that describes the limits of an H.264 level. + */ +typedef struct { + GstVaapiLevelH264 level; + guint8 level_idc; + guint32 MaxMBPS; + guint32 MaxFS; + guint32 MaxDpbMbs; + guint32 MaxBR; + guint32 MaxCPB; + guint32 MinCR; +} GstVaapiH264LevelLimits; + +/* Returns GstVaapiProfile from H.264 profile_idc value */ +G_GNUC_INTERNAL +GstVaapiProfile +gst_vaapi_utils_h264_get_profile (guint8 profile_idc); + +/* Returns H.264 profile_idc value from GstVaapiProfile */ +G_GNUC_INTERNAL +guint8 +gst_vaapi_utils_h264_get_profile_idc (GstVaapiProfile profile); + +/* Returns GstVaapiLevelH264 from H.264 level_idc value */ +G_GNUC_INTERNAL +GstVaapiLevelH264 +gst_vaapi_utils_h264_get_level (guint8 level_idc); + +/* Returns H.264 level_idc value from GstVaapiLevelH264 */ +G_GNUC_INTERNAL +guint8 +gst_vaapi_utils_h264_get_level_idc (GstVaapiLevelH264 level); + +/* Returns level limits as specified in Table A-1 of the H.264 standard */ +G_GNUC_INTERNAL +const GstVaapiH264LevelLimits * +gst_vaapi_utils_h264_get_level_limits (GstVaapiLevelH264 level); + +/* Returns the Table A-1 specification */ +G_GNUC_INTERNAL +const GstVaapiH264LevelLimits * +gst_vaapi_utils_h264_get_level_limits_table (guint * out_length_ptr); + +/* Returns GstVaapiChromaType from H.264 chroma_format_idc value */ +G_GNUC_INTERNAL +GstVaapiChromaType +gst_vaapi_utils_h264_get_chroma_type (guint chroma_format_idc); + +/* Returns H.264 chroma_format_idc value from GstVaapiChromaType */ +G_GNUC_INTERNAL +guint +gst_vaapi_utils_h264_get_chroma_format_idc (GstVaapiChromaType chroma_type); + +G_END_DECLS + +#endif /* GST_VAAPI_UTILS_H264_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiutils_h265.c b/gst-libs/gst/vaapi/gstvaapiutils_h265.c new file mode 100644 index 0000000000..a419af8ec2 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_h265.c @@ -0,0 +1,465 @@ +/* + * gstvaapiutils_h265.c - H.265 related utilities + * + * Copyright (C) 2015 Intel Corporation + * Author: Sreerenj Balachandran + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include +#include "gstvaapicompat.h" +#include "gstvaapiutils_h265_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +struct map +{ + guint value; + const gchar *name; +}; + +/* Profile string map */ +static const struct map gst_vaapi_h265_profile_map[] = { +/* *INDENT-OFF* */ + { GST_VAAPI_PROFILE_H265_MAIN, "main" }, + { GST_VAAPI_PROFILE_H265_MAIN10, "main-10" }, + { GST_VAAPI_PROFILE_H265_MAIN_STILL_PICTURE, "main-still-picture" }, + { GST_VAAPI_PROFILE_H265_MAIN_444, "main-444" }, + { GST_VAAPI_PROFILE_H265_MAIN_444_10, "main-444-10" }, + { GST_VAAPI_PROFILE_H265_MAIN_422_10, "main-422-10" }, + { GST_VAAPI_PROFILE_H265_MAIN12, "main-12" }, + { GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN, "screen-extended-main" }, + { GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_10, "screen-extended-main-10" }, + { GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444, "screen-extended-main-444" }, + { GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444_10, "screen-extended-main-444-10"}, + { 0, NULL } +/* *INDENT-ON* */ +}; + +/* Tier string map */ +static const struct map gst_vaapi_h265_tier_map[] = { +/* *INDENT-OFF* */ + { GST_VAAPI_TIER_H265_MAIN, "main" }, + { GST_VAAPI_TIER_H265_HIGH, "high"}, + { GST_VAAPI_TIER_H265_UNKNOWN, "unknown"} +/* *INDENT-ON* */ +}; + +/* Level string map */ +static const struct map gst_vaapi_h265_level_map[] = { +/* *INDENT-OFF* */ + { GST_VAAPI_LEVEL_H265_L1, "1" }, + { GST_VAAPI_LEVEL_H265_L2, "2" }, + { GST_VAAPI_LEVEL_H265_L2_1, "2.1" }, + { GST_VAAPI_LEVEL_H265_L3, "3" }, + { GST_VAAPI_LEVEL_H265_L3_1, "3.1" }, + { GST_VAAPI_LEVEL_H265_L4, "4" }, + { GST_VAAPI_LEVEL_H265_L4_1, "4.1" }, + { GST_VAAPI_LEVEL_H265_L5, "5" }, + { GST_VAAPI_LEVEL_H265_L5_1, "5.1" }, + { GST_VAAPI_LEVEL_H265_L5_2, "5.2" }, + { GST_VAAPI_LEVEL_H265_L6, "6" }, + { GST_VAAPI_LEVEL_H265_L6_1, "6.1" }, + { GST_VAAPI_LEVEL_H265_L6_2, "6.2" }, + { 0, NULL } +/* *INDENT-ON* */ +}; + +/* Table A-1 - Level limits */ +/* *INDENT-OFF* */ +static const GstVaapiH265LevelLimits gst_vaapi_h265_level_limits[] = { + /* level idc MaxLumaPs MCPBMt MCPBHt MSlSeg MTR MTC MaxLumaSr MBRMt MBRHt MinCr*/ + { GST_VAAPI_LEVEL_H265_L1, 30, 36864, 350, 0, 16, 1, 1, 552960, 128, 0, 2}, + { GST_VAAPI_LEVEL_H265_L2, 60, 122880, 1500, 0, 16, 1, 1, 3686400, 1500, 0, 2}, + { GST_VAAPI_LEVEL_H265_L2_1, 63, 245760, 3000, 0, 20, 1, 1, 7372800, 3000, 0, 2}, + { GST_VAAPI_LEVEL_H265_L3, 90, 552960, 6000, 0, 30, 2, 2, 16588800, 6000, 0, 2}, + { GST_VAAPI_LEVEL_H265_L3_1, 93, 983040, 10000, 0, 40, 3, 3, 33177600, 10000, 0, 2}, + { GST_VAAPI_LEVEL_H265_L4, 120, 2228224, 12000, 30000, 75, 5, 5, 66846720, 12000, 30000, 4}, + { GST_VAAPI_LEVEL_H265_L4_1, 123, 2228224, 20000, 50000, 75, 5, 5, 133693440, 20000, 50000, 4}, + { GST_VAAPI_LEVEL_H265_L5, 150, 8912896, 25000, 100000, 200, 11, 10, 267386880, 25000, 100000, 6}, + { GST_VAAPI_LEVEL_H265_L5_1, 153, 8912896, 40000, 160000, 200, 11, 10, 534773760, 40000, 160000, 8}, + { GST_VAAPI_LEVEL_H265_L5_2, 156, 8912896, 60000, 240000, 200, 11, 10, 1069547520, 60000, 240000, 8}, + { GST_VAAPI_LEVEL_H265_L6, 180, 35651584, 60000, 240000, 600, 22, 20, 1069547520, 60000, 240000, 8}, + { GST_VAAPI_LEVEL_H265_L6_1, 183, 35651584, 120000, 480000, 600, 22, 20, 2139095040, 120000, 480000, 8}, + { GST_VAAPI_LEVEL_H265_L6_2, 186, 35651584, 240000, 800000, 600, 22, 20, 4278190080, 240000, 800000, 6}, + { 0, } +}; +/* *INDENT-ON* */ + +/* Lookup value in map */ +static const struct map * +map_lookup_value (const struct map *m, guint value) +{ + g_return_val_if_fail (m != NULL, NULL); + + for (; m->name != NULL; m++) { + if (m->value == value) + return m; + } + return NULL; +} + +/* Lookup name in map */ +static const struct map * +map_lookup_name (const struct map *m, const gchar * name) +{ + g_return_val_if_fail (m != NULL, NULL); + + if (!name) + return NULL; + + for (; m->name != NULL; m++) { + if (strcmp (m->name, name) == 0) + return m; + } + return NULL; +} + +/** Returns a relative score for the supplied GstVaapiProfile */ +guint +gst_vaapi_utils_h265_get_profile_score (GstVaapiProfile profile) +{ + const struct map *const m = + map_lookup_value (gst_vaapi_h265_profile_map, profile); + + return m ? 1 + (m - gst_vaapi_h265_profile_map) : 0; +} + +/** Returns GstVaapiProfile from H.265 profile_idc value */ +GstVaapiProfile +gst_vaapi_utils_h265_get_profile (GstH265SPS * sps) +{ + GstVaapiProfile vaapi_profile; + GstH265Profile profile; + + g_return_val_if_fail (sps != NULL, GST_VAAPI_PROFILE_UNKNOWN); + + profile = gst_h265_get_profile_from_sps (sps); + switch (profile) { + case GST_H265_PROFILE_MAIN: + /* Main Intra, recognize it as MAIN */ + case GST_H265_PROFILE_MAIN_INTRA: + vaapi_profile = GST_VAAPI_PROFILE_H265_MAIN; + break; + case GST_H265_PROFILE_MAIN_10: + /* Main 10 Intra, recognize it as MAIN10 */ + case GST_H265_PROFILE_MAIN_10_INTRA: + vaapi_profile = GST_VAAPI_PROFILE_H265_MAIN10; + break; + case GST_H265_PROFILE_MAIN_12: + /* Main 12 Intra, recognize it as MAIN_12 */ + case GST_H265_PROFILE_MAIN_12_INTRA: + vaapi_profile = GST_VAAPI_PROFILE_H265_MAIN12; + break; + case GST_H265_PROFILE_MAIN_STILL_PICTURE: + vaapi_profile = GST_VAAPI_PROFILE_H265_MAIN_STILL_PICTURE; + break; + case GST_H265_PROFILE_MAIN_422_10: + /* Main 422_10 Intra, recognize it as MAIN_422_10 */ + case GST_H265_PROFILE_MAIN_422_10_INTRA: + vaapi_profile = GST_VAAPI_PROFILE_H265_MAIN_422_10; + break; + case GST_H265_PROFILE_MAIN_422_12: + /* Main 422_12 Intra, recognize it as MAIN_422_12 */ + case GST_H265_PROFILE_MAIN_422_12_INTRA: + vaapi_profile = GST_VAAPI_PROFILE_H265_MAIN_422_12; + break; + case GST_H265_PROFILE_MAIN_444: + /* Main 444 Intra, recognize it as MAIN_444 */ + case GST_H265_PROFILE_MAIN_444_INTRA: + vaapi_profile = GST_VAAPI_PROFILE_H265_MAIN_444; + break; + case GST_H265_PROFILE_MAIN_444_10: + /* Main 444_10 Intra, recognize it as MAIN_444_10 */ + case GST_H265_PROFILE_MAIN_444_10_INTRA: + vaapi_profile = GST_VAAPI_PROFILE_H265_MAIN_444_10; + break; + case GST_H265_PROFILE_MAIN_444_12: + /* Main 444_12 Intra, recognize it as MAIN_444_12 */ + case GST_H265_PROFILE_MAIN_444_12_INTRA: + vaapi_profile = GST_VAAPI_PROFILE_H265_MAIN_444_12; + break; + case GST_H265_PROFILE_SCREEN_EXTENDED_MAIN: + vaapi_profile = GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN; + break; + case GST_H265_PROFILE_SCREEN_EXTENDED_MAIN_10: + vaapi_profile = GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_10; + break; + case GST_H265_PROFILE_SCREEN_EXTENDED_MAIN_444: + vaapi_profile = GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444; + break; + case GST_H265_PROFILE_SCREEN_EXTENDED_MAIN_444_10: + vaapi_profile = GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444_10; + break; + default: + GST_DEBUG ("unsupported profile_idc value"); + vaapi_profile = GST_VAAPI_PROFILE_UNKNOWN; + break; + } + return vaapi_profile; +} + +/** Returns H.265 profile_idc value from GstVaapiProfile */ +guint8 +gst_vaapi_utils_h265_get_profile_idc (GstVaapiProfile profile) +{ + guint8 profile_idc; + + switch (profile) { + case GST_VAAPI_PROFILE_H265_MAIN: + profile_idc = GST_H265_PROFILE_IDC_MAIN; + break; + case GST_VAAPI_PROFILE_H265_MAIN10: + profile_idc = GST_H265_PROFILE_IDC_MAIN_10; + break; + case GST_VAAPI_PROFILE_H265_MAIN_STILL_PICTURE: + profile_idc = GST_H265_PROFILE_IDC_MAIN_STILL_PICTURE; + break; + case GST_VAAPI_PROFILE_H265_MAIN_422_10: + /* Fall through */ + case GST_VAAPI_PROFILE_H265_MAIN_444: + /* Fall through */ + case GST_VAAPI_PROFILE_H265_MAIN_444_10: + /* Fall through */ + case GST_VAAPI_PROFILE_H265_MAIN12: + profile_idc = GST_H265_PROFILE_IDC_FORMAT_RANGE_EXTENSION; + break; + case GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN: + /* Fall through */ + case GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_10: + /* Fall through */ + case GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444: + /* Fall through */ + case GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444_10: + profile_idc = GST_H265_PROFILE_IDC_SCREEN_CONTENT_CODING; + break; + default: + GST_DEBUG ("unsupported GstVaapiProfile value"); + profile_idc = 0; + break; + } + return profile_idc; +} + +/** Returns GstVaapiProfile from a string representation */ +GstVaapiProfile +gst_vaapi_utils_h265_get_profile_from_string (const gchar * str) +{ + const struct map *const m = map_lookup_name (gst_vaapi_h265_profile_map, str); + + return m ? (GstVaapiProfile) m->value : GST_VAAPI_PROFILE_UNKNOWN; +} + +/** Returns a string representation for the supplied H.265 profile */ +const gchar * +gst_vaapi_utils_h265_get_profile_string (GstVaapiProfile profile) +{ + const struct map *const m = + map_lookup_value (gst_vaapi_h265_profile_map, profile); + + return m ? m->name : NULL; +} + +/** Returns GstVaapiLevelH265 from H.265 level_idc value */ +GstVaapiLevelH265 +gst_vaapi_utils_h265_get_level (guint8 level_idc) +{ + const GstVaapiH265LevelLimits *llp; + + for (llp = gst_vaapi_h265_level_limits; llp->level != 0; llp++) { + if (llp->level_idc == level_idc) + return llp->level; + } + GST_DEBUG ("unsupported level_idc value"); + return (GstVaapiLevelH265) 0; +} + +/** Returns H.265 level_idc value from GstVaapiLevelH265 */ +guint8 +gst_vaapi_utils_h265_get_level_idc (GstVaapiLevelH265 level) +{ + const GstVaapiH265LevelLimits *const llp = + gst_vaapi_utils_h265_get_level_limits (level); + + return llp ? llp->level_idc : 0; +} + +/** Returns GstVaapiLevelH265 from a string representation */ +GstVaapiLevelH265 +gst_vaapi_utils_h265_get_level_from_string (const gchar * str) +{ + gint v, level_idc = 0; + + if (!str || !str[0]) + goto not_found; + + v = g_ascii_digit_value (str[0]); + if (v < 0) + goto not_found; + level_idc = v * 30; + + switch (str[1]) { + case '\0': + break; + case '.': + v = g_ascii_digit_value (str[2]); + if (v < 0 || str[3] != '\0') + goto not_found; + level_idc += v; + break; + default: + goto not_found; + } + return gst_vaapi_utils_h265_get_level (level_idc); + +not_found: + return (GstVaapiLevelH265) 0; +} + +/** Returns a string representation for the supplied H.265 level */ +const gchar * +gst_vaapi_utils_h265_get_level_string (GstVaapiLevelH265 level) +{ + if (level < GST_VAAPI_LEVEL_H265_L1 || level > GST_VAAPI_LEVEL_H265_L6_2) + return NULL; + return gst_vaapi_h265_level_map[level - GST_VAAPI_LEVEL_H265_L1].name; +} + +/** Returns level limits as specified in Table A-1 of the H.265 standard */ +const GstVaapiH265LevelLimits * +gst_vaapi_utils_h265_get_level_limits (GstVaapiLevelH265 level) +{ + if (level < GST_VAAPI_LEVEL_H265_L1 || level > GST_VAAPI_LEVEL_H265_L6_2) + return NULL; + return &gst_vaapi_h265_level_limits[level - GST_VAAPI_LEVEL_H265_L1]; +} + +/** Returns the Table A-1 & A-2 specification */ +const GstVaapiH265LevelLimits * +gst_vaapi_utils_h265_get_level_limits_table (guint * out_length_ptr) +{ + if (out_length_ptr) + *out_length_ptr = G_N_ELEMENTS (gst_vaapi_h265_level_limits) - 1; + return gst_vaapi_h265_level_limits; +} + +/** Returns GstVaapiChromaType from H.265 chroma_format_idc value */ +GstVaapiChromaType +gst_vaapi_utils_h265_get_chroma_type (guint chroma_format_idc, + guint luma_bit_depth, guint chroma_bit_depth) +{ + GstVaapiChromaType chroma_type = (GstVaapiChromaType) 0; + guint depth = 0; + + if (luma_bit_depth < 8 || chroma_bit_depth < 8 || + luma_bit_depth > 16 || chroma_bit_depth > 16) { + GST_WARNING ("invalid luma_bit_depth or chroma_bit_depth value"); + return chroma_type; + } + + depth = MAX (luma_bit_depth, chroma_bit_depth); + + switch (chroma_format_idc) { + case 0: + chroma_type = GST_VAAPI_CHROMA_TYPE_YUV400; + break; + case 1: + if (depth == 8) + chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420; + else if (depth > 8 && depth <= 10) + chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420_10BPP; + else if (depth > 10 && depth <= 12) + chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420_12BPP; + break; + case 2: + if (depth == 8) + chroma_type = GST_VAAPI_CHROMA_TYPE_YUV422; + else if (depth > 8 && depth <= 10) + chroma_type = GST_VAAPI_CHROMA_TYPE_YUV422_10BPP; + else if (depth > 10 && depth <= 12) + chroma_type = GST_VAAPI_CHROMA_TYPE_YUV422_12BPP; + break; + case 3: + if (depth == 8) + chroma_type = GST_VAAPI_CHROMA_TYPE_YUV444; + else if (depth > 8 && depth <= 10) + chroma_type = GST_VAAPI_CHROMA_TYPE_YUV444_10BPP; + else if (depth > 10 && depth <= 12) + chroma_type = GST_VAAPI_CHROMA_TYPE_YUV444_12BPP; + break; + default: + break; + } + + if (chroma_type == (GstVaapiChromaType) 0) + GST_DEBUG ("unsupported chroma_format_idc value"); + + return chroma_type; +} + +/** Returns H.265 chroma_format_idc value from GstVaapiChromaType */ +guint +gst_vaapi_utils_h265_get_chroma_format_idc (GstVaapiChromaType chroma_type) +{ + guint chroma_format_idc; + + switch (chroma_type) { + case GST_VAAPI_CHROMA_TYPE_YUV400: + chroma_format_idc = 0; + break; + case GST_VAAPI_CHROMA_TYPE_YUV420: + case GST_VAAPI_CHROMA_TYPE_YUV420_10BPP: + case GST_VAAPI_CHROMA_TYPE_YUV420_12BPP: + chroma_format_idc = 1; + break; + case GST_VAAPI_CHROMA_TYPE_YUV422: + case GST_VAAPI_CHROMA_TYPE_YUV422_10BPP: + case GST_VAAPI_CHROMA_TYPE_YUV422_12BPP: + chroma_format_idc = 2; + break; + case GST_VAAPI_CHROMA_TYPE_YUV444: + case GST_VAAPI_CHROMA_TYPE_YUV444_10BPP: + case GST_VAAPI_CHROMA_TYPE_YUV444_12BPP: + chroma_format_idc = 3; + break; + default: + GST_DEBUG ("unsupported GstVaapiChromaType value"); + chroma_format_idc = 1; + break; + } + return chroma_format_idc; +} + +/** Returns GstVaapiTierH265 from a string representation */ +GstVaapiTierH265 +gst_vaapi_utils_h265_get_tier_from_string (const gchar * str) +{ + const struct map *const m = map_lookup_name (gst_vaapi_h265_tier_map, str); + + return m ? (GstVaapiTierH265) m->value : GST_VAAPI_TIER_H265_UNKNOWN; +} + +/** Returns a string representation for the supplied H.265 tier */ +const gchar * +gst_vaapi_utils_h265_get_tier_string (GstVaapiTierH265 tier) +{ + const struct map *const m = map_lookup_value (gst_vaapi_h265_tier_map, tier); + + return m ? m->name : NULL; +} diff --git a/gst-libs/gst/vaapi/gstvaapiutils_h265.h b/gst-libs/gst/vaapi/gstvaapiutils_h265.h new file mode 100644 index 0000000000..e3ac72ea2a --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_h265.h @@ -0,0 +1,123 @@ +/* + * gstvaapiutils_h265.h - H.265 related utilities + * + * Copyright (C) 2015 Intel Corporation + * Author: Sreerenj Balachandran + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_UTILS_H265_H +#define GST_VAAPI_UTILS_H265_H + +#include + +G_BEGIN_DECLS + +/** + * GST_VAAPI_H265_MAX_COL_TILES: + * + * The max tiles in column according to spec A1 + * + */ +#define GST_VAAPI_H265_MAX_COL_TILES 20 +/** + * GST_VAAPI_H265_MAX_ROW_TILES: + * + * The max tiles in row according to spec A1 + * + */ +#define GST_VAAPI_H265_MAX_ROW_TILES 22 + +/** + * GstVaapiLevelH265: + * @GST_VAAPI_LEVEL_H265_L1: H.265 level 1. + * @GST_VAAPI_LEVEL_H265_L2: H.265 level 2. + * @GST_VAAPI_LEVEL_H265_L2_1: H.265 level 2.1. + * @GST_VAAPI_LEVEL_H265_L3: H.265 level 3. + * @GST_VAAPI_LEVEL_H265_L3_1: H.265 level 3.1. + * @GST_VAAPI_LEVEL_H265_L4: H.265 level 4. + * @GST_VAAPI_LEVEL_H265_L4_1: H.265 level 4.1. + * @GST_VAAPI_LEVEL_H265_L5: H.265 level 5. + * @GST_VAAPI_LEVEL_H265_L5_1: H.265 level 5.1. + * @GST_VAAPI_LEVEL_H265_L5_2: H.265 level 5.2. + * @GST_VAAPI_LEVEL_H265_L6: H.265 level 6. + * @GST_VAAPI_LEVEL_H265_L6_1: H.265 level 6.1. + * @GST_VAAPI_LEVEL_H265_L6_2: H.265 level 6.2. + * + * The set of all levels for #GstVaapiLevelH265. + */ +typedef enum { + GST_VAAPI_LEVEL_H265_L1 = 1, + GST_VAAPI_LEVEL_H265_L2, + GST_VAAPI_LEVEL_H265_L2_1, + GST_VAAPI_LEVEL_H265_L3, + GST_VAAPI_LEVEL_H265_L3_1, + GST_VAAPI_LEVEL_H265_L4, + GST_VAAPI_LEVEL_H265_L4_1, + GST_VAAPI_LEVEL_H265_L5, + GST_VAAPI_LEVEL_H265_L5_1, + GST_VAAPI_LEVEL_H265_L5_2, + GST_VAAPI_LEVEL_H265_L6, + GST_VAAPI_LEVEL_H265_L6_1, + GST_VAAPI_LEVEL_H265_L6_2, +} GstVaapiLevelH265; + +/** + * GstVaapiTierH265: + * GST_VAAPI_TIER_H265_MAIN: H265 Tier 0 + * GST_VAAPI_TIER_H265_HIGH: H265 Tier 1 + * GST_VAAPI_TIER_H265_UNKNOWN: Unknown Tier + * + * The set of all Tier for #GstVaapiTierH265. + */ +typedef enum { + GST_VAAPI_TIER_H265_MAIN, + GST_VAAPI_TIER_H265_HIGH, + GST_VAAPI_TIER_H265_UNKNOWN = -1 +} GstVaapiTierH265; + +/* Returns a relative score for the supplied GstVaapiProfile */ +guint +gst_vaapi_utils_h265_get_profile_score (GstVaapiProfile profile); + +/* Returns GstVaapiProfile from a string representation */ +GstVaapiProfile +gst_vaapi_utils_h265_get_profile_from_string (const gchar * str); + +/* Returns a string representation for the supplied H.265 profile */ +const gchar * +gst_vaapi_utils_h265_get_profile_string (GstVaapiProfile profile); + +/* Returns GstVaapiLevelH265 from a string representation */ +GstVaapiLevelH265 +gst_vaapi_utils_h265_get_level_from_string (const gchar * str); + +/* Returns a string representation for the supplied H.265 level */ +const gchar * +gst_vaapi_utils_h265_get_level_string (GstVaapiLevelH265 level); + +/* Returns GstVaapiTierH265 from a string representation */ +GstVaapiTierH265 +gst_vaapi_utils_h265_get_tier_from_string (const gchar * str); + +/* Returns a string representation for the supplied H.265 Tier */ +const gchar * +gst_vaapi_utils_h265_get_tier_string (GstVaapiTierH265 tier); + +G_END_DECLS + +#endif /* GST_VAAPI_UTILS_H265_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiutils_h265_priv.h b/gst-libs/gst/vaapi/gstvaapiutils_h265_priv.h new file mode 100644 index 0000000000..88f7fda8c9 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_h265_priv.h @@ -0,0 +1,106 @@ +/* + * gstvaapiutils_h265_priv.h - H.265 related utilities + * + * Copyright (C) 2015 Intel Corporation + * Author: Sreerenj Balachandran + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_UTILS_H265_PRIV_H +#define GST_VAAPI_UTILS_H265_PRIV_H + +#include "gstvaapiutils_h265.h" +#include "gstvaapisurface.h" + +G_BEGIN_DECLS + +/** + * GstVaapiH265LevelLimits: + * @level: the #GstVaapiLevelH265 + * @level_idc: the H.265 level_idc value + * @MaxLumaPs: the maximum luma picture size + * @MaxCPBTierMain: the maximum CPB size for Main tier(kbits) + * @MaxCPBTierHigh: the maximum CPB size for High tier(kbits) + * @MaxSliceSegPic: the maximum slice segments per picture + * @MaxTileRows: the maximum number of Tile Rows + * @MaxTileColumns: the maximum number of Tile Columns + * @MaxLumaSr: the maximum luma sample rate (samples/sec) + * @MaxBRTierMain: the maximum video bit rate for Main Tier(kbps) + * @MaxBRTierHigh: the maximum video bit rate for High Tier(kbps) + * @MinCr: the mimimum compression ratio + * + * The data structure that describes the limits of an H.265 level. + */ +typedef struct { + GstVaapiLevelH265 level; + guint8 level_idc; + guint32 MaxLumaPs; + guint32 MaxCPBTierMain; + guint32 MaxCPBTierHigh; + guint32 MaxSliceSegPic; + guint32 MaxTileRows; + guint32 MaxTileColumns; + guint32 MaxLumaSr; + guint32 MaxBRTierMain; + guint32 MaxBRTierHigh; + guint32 MinCr; +} GstVaapiH265LevelLimits; + +/* Returns GstVaapiProfile from H.265 profile_idc value */ +G_GNUC_INTERNAL +GstVaapiProfile +gst_vaapi_utils_h265_get_profile (GstH265SPS * sps); + +/* Returns H.265 profile_idc value from GstVaapiProfile */ +G_GNUC_INTERNAL +guint8 +gst_vaapi_utils_h265_get_profile_idc (GstVaapiProfile profile); + +/* Returns GstVaapiLevelH265 from H.265 level_idc value */ +G_GNUC_INTERNAL +GstVaapiLevelH265 +gst_vaapi_utils_h265_get_level (guint8 level_idc); + +/* Returns H.265 level_idc value from GstVaapiLevelH265 */ +G_GNUC_INTERNAL +guint8 +gst_vaapi_utils_h265_get_level_idc (GstVaapiLevelH265 level); + +/* Returns level limits as specified in Table A-1 of the H.265 standard */ +G_GNUC_INTERNAL +const GstVaapiH265LevelLimits * +gst_vaapi_utils_h265_get_level_limits (GstVaapiLevelH265 level); + +/* Returns the Table A-1 specification */ +G_GNUC_INTERNAL +const GstVaapiH265LevelLimits * +gst_vaapi_utils_h265_get_level_limits_table (guint * out_length_ptr); + +/* Returns GstVaapiChromaType from H.265 chroma_format_idc value */ +G_GNUC_INTERNAL +GstVaapiChromaType +gst_vaapi_utils_h265_get_chroma_type (guint chroma_format_idc, + guint luma_bit_depth, guint chroma_bit_depth); + +/* Returns H.265 chroma_format_idc value from GstVaapiChromaType */ +G_GNUC_INTERNAL +guint +gst_vaapi_utils_h265_get_chroma_format_idc (GstVaapiChromaType chroma_type); + +G_END_DECLS + +#endif /* GST_VAAPI_UTILS_H265_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiutils_h26x.c b/gst-libs/gst/vaapi/gstvaapiutils_h26x.c new file mode 100644 index 0000000000..4a679aaa74 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_h26x.c @@ -0,0 +1,147 @@ +/* + * gstvaapiutils_h26x.c - H.26x related utilities + * + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * Copyright (C) 2017 Intel Corporation + * Author: Hyunjun Ko + * Author: Mark Thompson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gstvaapiutils_h26x_priv.h" + +/* Write an unsigned integer Exp-Golomb-coded syntax element. i.e. ue(v) */ +gboolean +bs_write_ue (GstBitWriter * bs, guint32 value) +{ + guint32 size_in_bits = 0; + guint32 tmp_value = ++value; + + while (tmp_value) { + ++size_in_bits; + tmp_value >>= 1; + } + if (size_in_bits > 1 + && !gst_bit_writer_put_bits_uint32 (bs, 0, size_in_bits - 1)) + return FALSE; + if (!gst_bit_writer_put_bits_uint32 (bs, value, size_in_bits)) + return FALSE; + return TRUE; +} + +/* Write a signed integer Exp-Golomb-coded syntax element. i.e. se(v) */ +gboolean +bs_write_se (GstBitWriter * bs, gint32 value) +{ + guint32 new_val; + + if (value <= 0) + new_val = -(value << 1); + else + new_val = (value << 1) - 1; + + if (!bs_write_ue (bs, new_val)) + return FALSE; + return TRUE; +} + +/* Copy from src to dst, applying emulation prevention bytes. + * + * This is copied from libavcodec written by Mark Thompson + * from + * http://git.videolan.org/?p=ffmpeg.git;a=commit;h=2c62fcdf5d617791a653d7957d449f75569eede0 + */ +static gboolean +gst_vaapi_utils_h26x_nal_unit_to_byte_stream (guint8 * dst, guint * dst_len, + guint8 * src, guint src_len) +{ + guint dp = 0, sp; + guint zero_run = 0; + + for (sp = 0; sp < src_len; sp++) { + if (dp >= *dst_len) + goto fail; + if (zero_run < 2) { + if (src[sp] == 0) + ++zero_run; + else + zero_run = 0; + } else { + if ((src[sp] & ~3) == 0) { + /* emulation_prevention_byte: 0x03 */ + dst[dp++] = 3; + if (dp >= *dst_len) + goto fail; + } + zero_run = src[sp] == 0; + } + dst[dp++] = src[sp]; + } + + *dst_len = dp; + return TRUE; + +fail: + *dst_len = 0; + return FALSE; +} + +/** + * gst_vaapi_utils_h26x_write_nal_unit: + * @bs: a #GstBitWriter instance + * @nal: the NAL (Network Abstraction Layer) unit to write + * @nal_size: the size, in bytes, of @nal + * + * Writes in the @bs the @nal rewritten with the "emulation prevention + * bytes" if required. + * + * Returns: TRUE if the NAL unit could be coded applying the + * "emulation prevention bytes"; otherwise FALSE. + **/ +gboolean +gst_vaapi_utils_h26x_write_nal_unit (GstBitWriter * bs, guint8 * nal, + guint nal_size) +{ + guint8 *byte_stream = NULL; + guint byte_stream_len; + + byte_stream_len = nal_size + 10; + byte_stream = g_malloc (byte_stream_len); + + if (!byte_stream) + return FALSE; + + if (!gst_vaapi_utils_h26x_nal_unit_to_byte_stream (byte_stream, + &byte_stream_len, nal, nal_size)) { + g_free (byte_stream); + return FALSE; + } + + WRITE_UINT32 (bs, byte_stream_len, 16); + gst_bit_writer_put_bytes (bs, byte_stream, byte_stream_len); + g_free (byte_stream); + + return TRUE; + +bs_error: + { + GST_ERROR ("failed to write codec-data"); + g_free (byte_stream); + return FALSE; + } +} diff --git a/gst-libs/gst/vaapi/gstvaapiutils_h26x_priv.h b/gst-libs/gst/vaapi/gstvaapiutils_h26x_priv.h new file mode 100644 index 0000000000..23749ea07c --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_h26x_priv.h @@ -0,0 +1,87 @@ +/* + * gstvaapiutils_h26x_priv.h - H.26x related utilities + * + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * Copyright (C) 2017 Intel Corporation + * Author: Hyunjun Ko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_UTILS_H26X_PRIV_H +#define GST_VAAPI_UTILS_H26X_PRIV_H + +#include + +G_BEGIN_DECLS + +/* Default CPB length (in milliseconds) */ +#define DEFAULT_CPB_LENGTH 1500 + +/* Scale factor for CPB size (HRD cpb_size_scale: min = 4) */ +#define SX_CPB_SIZE 4 + +/* Scale factor for bitrate (HRD bit_rate_scale: min = 6) */ +#define SX_BITRATE 6 + +/* Define default rate control mode ("constant-qp") */ +#define DEFAULT_RATECONTROL GST_VAAPI_RATECONTROL_CQP + +/* ------------------------------------------------------------------------- */ +/* --- H.264/265 Bitstream Writer --- */ +/* ------------------------------------------------------------------------- */ + +#define WRITE_UINT32(bs, val, nbits) \ + G_STMT_START { \ + if (!gst_bit_writer_put_bits_uint32 (bs, val, nbits)) { \ + GST_WARNING ("failed to write uint32, nbits: %d", nbits); \ + goto bs_error; \ + } \ + } G_STMT_END + +#define WRITE_UE(bs, val) \ + G_STMT_START { \ + if (!bs_write_ue (bs, val)) { \ + GST_WARNING ("failed to write ue(v)"); \ + goto bs_error; \ + } \ + } G_STMT_END + +#define WRITE_SE(bs, val) \ + G_STMT_START { \ + if (!bs_write_se (bs, val)) { \ + GST_WARNING ("failed to write se(v)"); \ + goto bs_error; \ + } \ + } G_STMT_END + +G_GNUC_INTERNAL +gboolean +bs_write_ue (GstBitWriter * bs, guint32 value); + +G_GNUC_INTERNAL +gboolean +bs_write_se (GstBitWriter * bs, gint32 value); + +/* Write nal unit, applying emulation prevention bytes */ +G_GNUC_INTERNAL +gboolean +gst_vaapi_utils_h26x_write_nal_unit (GstBitWriter * bs, guint8 * nal, guint nal_size); + +G_END_DECLS + +#endif /* GST_VAAPI_UTILS_H26X_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiutils_mpeg2.c b/gst-libs/gst/vaapi/gstvaapiutils_mpeg2.c new file mode 100644 index 0000000000..04993c8a4e --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_mpeg2.c @@ -0,0 +1,292 @@ +/* + * gstvaapiutils_mpeg2.c - MPEG-2 related utilities + * + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include +#include "gstvaapicompat.h" +#include "gstvaapiutils_mpeg2_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +struct map +{ + guint value; + const gchar *name; +}; + +/* Profile string map */ +static const struct map gst_vaapi_mpeg2_profile_map[] = { +/* *INDENT-OFF* */ + { GST_VAAPI_PROFILE_MPEG2_SIMPLE, "simple" }, + { GST_VAAPI_PROFILE_MPEG2_MAIN, "main" }, + { GST_VAAPI_PROFILE_MPEG2_HIGH, "high" }, + { 0, NULL } +/* *INDENT-ON* */ +}; + +/* Level string map */ +static const struct map gst_vaapi_mpeg2_level_map[] = { +/* *INDENT-OFF* */ + { GST_VAAPI_LEVEL_MPEG2_LOW, "low" }, + { GST_VAAPI_LEVEL_MPEG2_MAIN, "main" }, + { GST_VAAPI_LEVEL_MPEG2_HIGH_1440, "high-1440" }, + { GST_VAAPI_LEVEL_MPEG2_HIGH, "high" }, + { GST_VAAPI_LEVEL_MPEG2_HIGHP, "highP" }, + { 0, NULL } +/* *INDENT-ON* */ +}; + +/* Table 8-10 to 8-13 (up to Main profile only) */ +/* *INDENT-OFF* */ +static const GstVaapiMPEG2LevelLimits gst_vaapi_mpeg2_level_limits[] = { + /* level h_size v_size fps samples kbps vbv_size */ + { GST_VAAPI_LEVEL_MPEG2_LOW, + 0x0a, 352, 288, 30, 3041280, 4000, 475136 }, + { GST_VAAPI_LEVEL_MPEG2_MAIN, + 0x08, 720, 576, 30, 1036800, 15000, 1835008 }, + { GST_VAAPI_LEVEL_MPEG2_HIGH_1440, + 0x06, 1440, 1152, 60, 47001600, 60000, 7340032 }, + { GST_VAAPI_LEVEL_MPEG2_HIGH, + 0x04, 1920, 1152, 60, 62668800, 80000, 9781248 }, + /* Amendment 3: New level for 1080@50p/60p */ + { GST_VAAPI_LEVEL_MPEG2_HIGHP, + 0x02, 1920, 1152, 60, 125337600, 80000, 9781248 }, + { 0, } +}; +/* *INDENT-ON* */ + +/* Lookup value in map */ +static const struct map * +map_lookup_value (const struct map *m, guint value) +{ + g_return_val_if_fail (m != NULL, NULL); + + for (; m->name != NULL; m++) { + if (m->value == value) + return m; + } + return NULL; +} + +/* Lookup name in map */ +static const struct map * +map_lookup_name (const struct map *m, const gchar * name) +{ + g_return_val_if_fail (m != NULL, NULL); + + if (!name) + return NULL; + + for (; m->name != NULL; m++) { + if (strcmp (m->name, name) == 0) + return m; + } + return NULL; +} + +/** Returns a relative score for the supplied GstVaapiProfile */ +guint +gst_vaapi_utils_mpeg2_get_profile_score (GstVaapiProfile profile) +{ + const struct map *const m = + map_lookup_value (gst_vaapi_mpeg2_profile_map, profile); + + return m ? 1 + (m - gst_vaapi_mpeg2_profile_map) : 0; +} + +/** Returns GstVaapiProfile from MPEG-2 profile_idc value */ +GstVaapiProfile +gst_vaapi_utils_mpeg2_get_profile (guint8 profile_idc) +{ + GstVaapiProfile profile; + + switch (profile_idc) { + case GST_MPEG_VIDEO_PROFILE_SIMPLE: + profile = GST_VAAPI_PROFILE_MPEG2_SIMPLE; + break; + case GST_MPEG_VIDEO_PROFILE_MAIN: + profile = GST_VAAPI_PROFILE_MPEG2_MAIN; + break; + case GST_MPEG_VIDEO_PROFILE_HIGH: + profile = GST_VAAPI_PROFILE_MPEG2_HIGH; + break; + default: + GST_DEBUG ("unsupported profile_idc value"); + profile = GST_VAAPI_PROFILE_UNKNOWN; + break; + } + return profile; +} + +/** Returns MPEG-2 profile_idc value from GstVaapiProfile */ +guint8 +gst_vaapi_utils_mpeg2_get_profile_idc (GstVaapiProfile profile) +{ + guint8 profile_idc; + + switch (profile) { + case GST_VAAPI_PROFILE_MPEG2_SIMPLE: + profile_idc = GST_MPEG_VIDEO_PROFILE_SIMPLE; + break; + case GST_VAAPI_PROFILE_MPEG2_MAIN: + profile_idc = GST_MPEG_VIDEO_PROFILE_MAIN; + break; + case GST_VAAPI_PROFILE_MPEG2_HIGH: + profile_idc = GST_MPEG_VIDEO_PROFILE_HIGH; + break; + default: + GST_DEBUG ("unsupported GstVaapiProfile value"); + profile_idc = 0; + break; + } + return profile_idc; +} + +/** Returns GstVaapiProfile from a string representation */ +GstVaapiProfile +gst_vaapi_utils_mpeg2_get_profile_from_string (const gchar * str) +{ + const struct map *const m = + map_lookup_name (gst_vaapi_mpeg2_profile_map, str); + + return m ? (GstVaapiProfile) m->value : GST_VAAPI_PROFILE_UNKNOWN; +} + +/** Returns a string representation for the supplied MPEG-2 profile */ +const gchar * +gst_vaapi_utils_mpeg2_get_profile_string (GstVaapiProfile profile) +{ + const struct map *const m = + map_lookup_value (gst_vaapi_mpeg2_profile_map, profile); + + return m ? m->name : NULL; +} + +/** Returns GstVaapiLevelMPEG2 from MPEG-2 level_idc value */ +GstVaapiLevelMPEG2 +gst_vaapi_utils_mpeg2_get_level (guint8 level_idc) +{ + const GstVaapiMPEG2LevelLimits *llp; + + for (llp = gst_vaapi_mpeg2_level_limits; llp->level != 0; llp++) { + if (llp->level_idc == level_idc) + return llp->level; + } + GST_DEBUG ("unsupported level_idc value"); + return (GstVaapiLevelMPEG2) 0; +} + +/** Returns MPEG-2 level_idc value from GstVaapiLevelMPEG2 */ +guint8 +gst_vaapi_utils_mpeg2_get_level_idc (GstVaapiLevelMPEG2 level) +{ + const GstVaapiMPEG2LevelLimits *const llp = + gst_vaapi_utils_mpeg2_get_level_limits (level); + + return llp ? llp->level_idc : 0; +} + +/** Returns GstVaapiLevelMPEG2 from a string representation */ +GstVaapiLevelMPEG2 +gst_vaapi_utils_mpeg2_get_level_from_string (const gchar * str) +{ + const struct map *const m = map_lookup_name (gst_vaapi_mpeg2_level_map, str); + + return (GstVaapiLevelMPEG2) (m ? m->value : 0); +} + +/** Returns a string representation for the supplied MPEG-2 level */ +const gchar * +gst_vaapi_utils_mpeg2_get_level_string (GstVaapiLevelMPEG2 level) +{ + if (level < GST_VAAPI_LEVEL_MPEG2_LOW || level > GST_VAAPI_LEVEL_MPEG2_HIGHP) + return NULL; + return gst_vaapi_mpeg2_level_map[level - GST_VAAPI_LEVEL_MPEG2_LOW].name; +} + +/** Returns level limits as specified in Tables 8-10 to 8-13 of the + MPEG-2 standard */ +const GstVaapiMPEG2LevelLimits * +gst_vaapi_utils_mpeg2_get_level_limits (GstVaapiLevelMPEG2 level) +{ + if (level < GST_VAAPI_LEVEL_MPEG2_LOW || level > GST_VAAPI_LEVEL_MPEG2_HIGHP) + return NULL; + return &gst_vaapi_mpeg2_level_limits[level - GST_VAAPI_LEVEL_MPEG2_LOW]; +} + +/** Returns Tables 8-10 to 8-13 from the specification (up to High profile) */ +const GstVaapiMPEG2LevelLimits * +gst_vaapi_utils_mpeg2_get_level_limits_table (guint * out_length_ptr) +{ + if (out_length_ptr) + *out_length_ptr = G_N_ELEMENTS (gst_vaapi_mpeg2_level_limits) - 1; + return gst_vaapi_mpeg2_level_limits; +} + +/** Returns GstVaapiChromaType from MPEG-2 chroma_format_idc value */ +GstVaapiChromaType +gst_vaapi_utils_mpeg2_get_chroma_type (guint chroma_format_idc) +{ + GstVaapiChromaType chroma_type; + + switch (chroma_format_idc) { + case GST_MPEG_VIDEO_CHROMA_420: + chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420; + break; + case GST_MPEG_VIDEO_CHROMA_422: + chroma_type = GST_VAAPI_CHROMA_TYPE_YUV422; + break; + case GST_MPEG_VIDEO_CHROMA_444: + chroma_type = GST_VAAPI_CHROMA_TYPE_YUV444; + break; + default: + GST_DEBUG ("unsupported chroma_format_idc value"); + chroma_type = (GstVaapiChromaType) 0; + break; + } + return chroma_type; +} + +/** Returns MPEG-2 chroma_format_idc value from GstVaapiChromaType */ +guint +gst_vaapi_utils_mpeg2_get_chroma_format_idc (GstVaapiChromaType chroma_type) +{ + guint chroma_format_idc; + + switch (chroma_type) { + case GST_VAAPI_CHROMA_TYPE_YUV420: + chroma_format_idc = GST_MPEG_VIDEO_CHROMA_420; + break; + case GST_VAAPI_CHROMA_TYPE_YUV422: + chroma_format_idc = GST_MPEG_VIDEO_CHROMA_422; + break; + case GST_VAAPI_CHROMA_TYPE_YUV444: + chroma_format_idc = GST_MPEG_VIDEO_CHROMA_444; + break; + default: + GST_DEBUG ("unsupported GstVaapiChromaType value"); + chroma_format_idc = 1; + break; + } + return chroma_format_idc; +} diff --git a/gst-libs/gst/vaapi/gstvaapiutils_mpeg2.h b/gst-libs/gst/vaapi/gstvaapiutils_mpeg2.h new file mode 100644 index 0000000000..997011df53 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_mpeg2.h @@ -0,0 +1,70 @@ +/* + * gstvaapiutils_mpeg2.h - MPEG-2 related utilities + * + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_UTILS_MPEG2_H +#define GST_VAAPI_UTILS_MPEG2_H + +#include + +G_BEGIN_DECLS + +/** + * GstVaapiLevelMPEG2: + * @GST_VAAPI_LEVEL_MPEG2_LOW: Low level. + * @GST_VAAPI_LEVEL_MPEG2_MAIN: Main level. + * @GST_VAAPI_LEVEL_MPEG2_HIGH_1440: High-1440 level. + * @GST_VAAPI_LEVEL_MPEG2_HIGH: High level. + * @GST_VAAPI_LEVEL_MPEG2_HIGHP: HighP level. + * + * The set of all levels for #GstVaapiLevelMPEG2. + */ +typedef enum { + GST_VAAPI_LEVEL_MPEG2_LOW = 1, + GST_VAAPI_LEVEL_MPEG2_MAIN, + GST_VAAPI_LEVEL_MPEG2_HIGH_1440, + GST_VAAPI_LEVEL_MPEG2_HIGH, + GST_VAAPI_LEVEL_MPEG2_HIGHP, +} GstVaapiLevelMPEG2; + +/* Returns a relative score for the supplied GstVaapiProfile */ +guint +gst_vaapi_utils_mpeg2_get_profile_score (GstVaapiProfile profile); + +/* Returns GstVaapiProfile from a string representation */ +GstVaapiProfile +gst_vaapi_utils_mpeg2_get_profile_from_string (const gchar * str); + +/* Returns a string representation for the supplied MPEG-2 profile */ +const gchar * +gst_vaapi_utils_mpeg2_get_profile_string (GstVaapiProfile profile); + +/* Returns GstVaapiLevelMPEG2 from a string representation */ +GstVaapiLevelMPEG2 +gst_vaapi_utils_mpeg2_get_level_from_string (const gchar * str); + +/* Returns a string representation for the supplied MPEG-2 level */ +const gchar * +gst_vaapi_utils_mpeg2_get_level_string (GstVaapiLevelMPEG2 level); + +G_END_DECLS + +#endif /* GST_VAAPI_UTILS_MPEG2_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiutils_mpeg2_priv.h b/gst-libs/gst/vaapi/gstvaapiutils_mpeg2_priv.h new file mode 100644 index 0000000000..3ac65c5d3b --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_mpeg2_priv.h @@ -0,0 +1,97 @@ +/* + * gstvaapiutils_mpeg2_priv.h - MPEG-2 related utilities + * + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_UTILS_MPEG2_PRIV_H +#define GST_VAAPI_UTILS_MPEG2_PRIV_H + +#include "gstvaapiutils_mpeg2.h" +#include "gstvaapisurface.h" + +G_BEGIN_DECLS + +/** + * GstVaapiMPEG2LevelLimits: + * @level: the #GstVaapiLevelMPEG2 + * @level_idc: the MPEG-2 level indication value + * @horizontal_size_value: the maximum number of samples per line + * @vertical_size_value: the maximum number of lines per frame + * @frame_rate_value: the maximum number of frames per second + * @sample_rate: the maximum number of samples per second (for luminance) + * @bit_rate: the maximum bit rate (kbps) + * @vbv_buffer_size: the VBV buffer size requirements (bits) + * + * The data structure that describes the limits of an MPEG-2 level. + */ +typedef struct { + GstVaapiLevelMPEG2 level; + guint8 level_idc; + guint16 horizontal_size_value; + guint16 vertical_size_value; + guint32 frame_rate_value; + guint32 sample_rate; + guint32 bit_rate; + guint32 vbv_buffer_size; +} GstVaapiMPEG2LevelLimits; + +/* Returns GstVaapiProfile from MPEG-2 profile_idc value */ +G_GNUC_INTERNAL +GstVaapiProfile +gst_vaapi_utils_mpeg2_get_profile (guint8 profile_idc); + +/* Returns MPEG-2 profile_idc value from GstVaapiProfile */ +G_GNUC_INTERNAL +guint8 +gst_vaapi_utils_mpeg2_get_profile_idc (GstVaapiProfile profile); + +/* Returns GstVaapiLevelMPEG2 from MPEG-2 level_idc value */ +G_GNUC_INTERNAL +GstVaapiLevelMPEG2 +gst_vaapi_utils_mpeg2_get_level (guint8 level_idc); + +/* Returns MPEG-2 level_idc value from GstVaapiLevelMPEG2 */ +G_GNUC_INTERNAL +guint8 +gst_vaapi_utils_mpeg2_get_level_idc (GstVaapiLevelMPEG2 level); + +/* Returns level limits as specified in Table A-1 of the MPEG-2 standard */ +G_GNUC_INTERNAL +const GstVaapiMPEG2LevelLimits * +gst_vaapi_utils_mpeg2_get_level_limits (GstVaapiLevelMPEG2 level); + +/* Returns the Table A-1 specification */ +G_GNUC_INTERNAL +const GstVaapiMPEG2LevelLimits * +gst_vaapi_utils_mpeg2_get_level_limits_table (guint * out_length_ptr); + +/* Returns GstVaapiChromaType from MPEG-2 chroma_format_idc value */ +G_GNUC_INTERNAL +GstVaapiChromaType +gst_vaapi_utils_mpeg2_get_chroma_type (guint chroma_format_idc); + +/* Returns MPEG-2 chroma_format_idc value from GstVaapiChromaType */ +G_GNUC_INTERNAL +guint +gst_vaapi_utils_mpeg2_get_chroma_format_idc (GstVaapiChromaType chroma_type); + +G_END_DECLS + +#endif /* GST_VAAPI_UTILS_MPEG2_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiutils_vpx.c b/gst-libs/gst/vaapi/gstvaapiutils_vpx.c new file mode 100644 index 0000000000..d6bdd8161d --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_vpx.c @@ -0,0 +1,119 @@ +/* + * gstvaapiutils_vpx.c - vpx related utilities + * + * Copyright (C) 2020 Intel Corporation + * Author: He Junyan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gstvaapiutils_vpx.h" +#include "gstvaapisurface.h" + +struct map +{ + guint value; + const gchar *name; +}; + +/* Profile string map */ +static const struct map gst_vaapi_vp9_profile_map[] = { + /* *INDENT-OFF* */ + { GST_VAAPI_PROFILE_VP9_0, "0" }, + { GST_VAAPI_PROFILE_VP9_1, "1" }, + { GST_VAAPI_PROFILE_VP9_2, "2" }, + { GST_VAAPI_PROFILE_VP9_3, "3" }, + { 0, NULL } + /* *INDENT-ON* */ +}; + +/* Lookup name in map */ +static const struct map * +map_lookup_name (const struct map *m, const gchar * name) +{ + g_return_val_if_fail (m != NULL, NULL); + + if (!name) + return NULL; + + for (; m->name != NULL; m++) { + if (strcmp (m->name, name) == 0) + return m; + } + return NULL; +} + +/* Lookup value in map */ +static const struct map * +map_lookup_value (const struct map *m, guint value) +{ + g_return_val_if_fail (m != NULL, NULL); + + for (; m->name != NULL; m++) { + if (m->value == value) + return m; + } + return NULL; +} + +/** Returns GstVaapiProfile from a string representation */ +GstVaapiProfile +gst_vaapi_utils_vp9_get_profile_from_string (const gchar * str) +{ + const struct map *const m = map_lookup_name (gst_vaapi_vp9_profile_map, str); + + return m ? (GstVaapiProfile) m->value : GST_VAAPI_PROFILE_UNKNOWN; +} + +/** Returns a string representation for the supplied VP9 profile */ +const gchar * +gst_vaapi_utils_vp9_get_profile_string (GstVaapiProfile profile) +{ + const struct map *const m = + map_lookup_value (gst_vaapi_vp9_profile_map, profile); + + return m ? m->name : NULL; +} + +/** Returns VP9 chroma_format_idc value from GstVaapiChromaType */ +guint +gst_vaapi_utils_vp9_get_chroma_format_idc (guint chroma_type) +{ + guint chroma_format_idc; + + switch (chroma_type) { + case GST_VAAPI_CHROMA_TYPE_YUV400: + chroma_format_idc = 0; + break; + case GST_VAAPI_CHROMA_TYPE_YUV420: + case GST_VAAPI_CHROMA_TYPE_YUV420_10BPP: + chroma_format_idc = 1; + break; + case GST_VAAPI_CHROMA_TYPE_YUV422: + case GST_VAAPI_CHROMA_TYPE_YUV422_10BPP: + chroma_format_idc = 2; + break; + case GST_VAAPI_CHROMA_TYPE_YUV444: + case GST_VAAPI_CHROMA_TYPE_YUV444_10BPP: + chroma_format_idc = 3; + break; + default: + GST_DEBUG ("unsupported GstVaapiChromaType value"); + chroma_format_idc = 1; + break; + } + return chroma_format_idc; +} diff --git a/gst-libs/gst/vaapi/gstvaapiutils_vpx.h b/gst-libs/gst/vaapi/gstvaapiutils_vpx.h new file mode 100644 index 0000000000..acead5a529 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_vpx.h @@ -0,0 +1,43 @@ +/* + * gstvaapiutils_vpx.h - vpx related utilities + * + * Copyright (C) 2020 Intel Corporation + * Author: He Junyan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_UTILS_VPX_H +#define GST_VAAPI_UTILS_VPX_H + +#include + +G_BEGIN_DECLS + +/** Returns GstVaapiProfile from a string representation */ +GstVaapiProfile +gst_vaapi_utils_vp9_get_profile_from_string (const gchar * str); + +/** Returns a string representation for the supplied VP9 profile */ +const gchar * +gst_vaapi_utils_vp9_get_profile_string (GstVaapiProfile profile); + +guint +gst_vaapi_utils_vp9_get_chroma_format_idc (guint chroma_type); + +G_END_DECLS + +#endif /* GST_VAAPI_UTILS_VPX_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiutils_x11.c b/gst-libs/gst/vaapi/gstvaapiutils_x11.c new file mode 100644 index 0000000000..741b9b32f6 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_x11.c @@ -0,0 +1,161 @@ +/* + * gstvaapiutils_x11.c - X11 utilties + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include +#include +#include "gstvaapiutils_x11.h" + +// X error trap +static int x11_error_code = 0; +static int (*old_error_handler) (Display *, XErrorEvent *); + +static int +error_handler (Display * dpy, XErrorEvent * error) +{ + x11_error_code = error->error_code; + return 0; +} + +void +x11_trap_errors (void) +{ + x11_error_code = 0; + old_error_handler = XSetErrorHandler (error_handler); +} + +int +x11_untrap_errors (void) +{ + XSetErrorHandler (old_error_handler); + return x11_error_code; +} + +// X window management +static const int x11_event_mask = (KeyPressMask | KeyReleaseMask + | ButtonPressMask | ButtonReleaseMask | PointerMotionMask + | EnterWindowMask | ExposureMask | StructureNotifyMask); + +/** + * x11_create_window: + * @dpy: an X11 #Display + * @w: the requested width, in pixels + * @h: the requested height, in pixels + * @vid: the requested visual id + * @cmap: the requested colormap + * + * Creates a border-less window with the specified dimensions. If @vid + * is zero, the default visual for @display will be used. If @cmap is + * %None, no specific colormap will be bound to the window. Also note + * the default background color is black. + * + * Return value: the newly created X Window. + */ +Window +x11_create_window (Display * dpy, guint w, guint h, guint vid, Colormap cmap) +{ + Window rootwin, win; + int screen, depth; + XSetWindowAttributes xswa; + unsigned long xswa_mask; + XWindowAttributes wattr; + unsigned long black_pixel; + XVisualInfo visualInfo, *vi; + int num_visuals; + + screen = DefaultScreen (dpy); + rootwin = RootWindow (dpy, screen); + black_pixel = BlackPixel (dpy, screen); + + XGetWindowAttributes (dpy, rootwin, &wattr); + depth = wattr.depth; + if (depth != 15 && depth != 16 && depth != 24 && depth != 30 && depth != 32) + depth = 24; + + xswa_mask = CWBorderPixel | CWBackPixel; + xswa.border_pixel = black_pixel; + xswa.background_pixel = black_pixel; + + if (cmap) { + xswa_mask |= CWColormap; + xswa.colormap = cmap; + } + + if (vid) { + visualInfo.visualid = vid; + vi = XGetVisualInfo (dpy, VisualIDMask, &visualInfo, &num_visuals); + if (!vi || num_visuals < 1) + goto error_create_visual; + } else { + vi = &visualInfo; + XMatchVisualInfo (dpy, screen, depth, TrueColor, vi); + } + + win = XCreateWindow (dpy, rootwin, 0, 0, w, h, 0, depth, InputOutput, + vi->visual, xswa_mask, &xswa); + if (vi != &visualInfo) + XFree (vi); + if (!win) + goto error_create_window; + + XSelectInput (dpy, win, x11_event_mask); + return win; + + /* ERRORS */ +error_create_visual: + GST_ERROR ("failed to create X visual (id:%zu)", (gsize) visualInfo.visualid); + if (vi) + XFree (vi); + return None; +error_create_window: + GST_ERROR ("failed to create X window of size %ux%u", w, h); + return None; +} + +gboolean +x11_get_geometry (Display * dpy, Drawable drawable, gint * px, gint * py, + guint * pwidth, guint * pheight, guint * pdepth) +{ + Window rootwin; + int x, y; + guint width, height, border_width, depth; + + x11_trap_errors (); + XGetGeometry (dpy, drawable, &rootwin, &x, &y, &width, &height, + &border_width, &depth); + if (x11_untrap_errors ()) + return FALSE; + + if (px) + *px = x; + if (py) + *py = y; + if (pwidth) + *pwidth = width; + if (pheight) + *pheight = height; + if (pdepth) + *pdepth = depth; + return TRUE; +} diff --git a/gst-libs/gst/vaapi/gstvaapiutils_x11.h b/gst-libs/gst/vaapi/gstvaapiutils_x11.h new file mode 100644 index 0000000000..b205585b29 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_x11.h @@ -0,0 +1,49 @@ +/* + * gstvaapiutils_x11.h - X11 utilties + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_UTILS_X11_H +#define GST_VAAPI_UTILS_X11_H + +#include "config.h" +#include +#include + +G_GNUC_INTERNAL +void +x11_trap_errors (void); + +G_GNUC_INTERNAL +int +x11_untrap_errors (void); + +G_GNUC_INTERNAL +Window +x11_create_window (Display * dpy, guint w, guint h, guint vid, Colormap cmap); + +G_GNUC_INTERNAL +gboolean +x11_get_geometry (Display * dpy, Drawable drawable, gint * px, gint * py, + guint * pwidth, guint * pheight, guint * pdepth); + +#endif /* GST_VAAPI_UTILS_X11_H */ diff --git a/gst-libs/gst/vaapi/gstvaapivalue.c b/gst-libs/gst/vaapi/gstvaapivalue.c new file mode 100644 index 0000000000..62e440b63a --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapivalue.c @@ -0,0 +1,241 @@ +/* + * gstvaapivalue.c - GValue implementations specific to VA-API + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapivalue + * @short_description: GValue implementations specific to VA-API + */ + +#include "sysdeps.h" +#include +#include "gstvaapivalue.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +static gpointer +default_copy_func (gpointer data) +{ + return data; +} + +static void +default_free_func (gpointer data) +{ +} + +/* --- GstVaapiPoint --- */ + +GType +gst_vaapi_point_get_type (void) +{ + static gsize g_type = 0; + + if (g_once_init_enter (&g_type)) { + GType type = + g_boxed_type_register_static (g_intern_static_string ("GstVaapiPoint"), + default_copy_func, default_free_func); + gst_type_mark_as_plugin_api (type, 0); + g_once_init_leave (&g_type, type); + } + return g_type; +} + +/* --- GstVaapiRectangle --- */ + +GType +gst_vaapi_rectangle_get_type (void) +{ + static gsize g_type = 0; + + if (g_once_init_enter (&g_type)) { + GType type = + g_boxed_type_register_static (g_intern_static_string + ("GstVaapiRectangle"), + default_copy_func, default_free_func); + gst_type_mark_as_plugin_api (type, 0); + g_once_init_leave (&g_type, type); + } + return g_type; +} + +/* --- GstVaapiRenderMode --- */ + +GType +gst_vaapi_render_mode_get_type (void) +{ + static gsize g_type = 0; + + static const GEnumValue render_modes[] = { + {GST_VAAPI_RENDER_MODE_OVERLAY, + "Overlay render mode", "overlay"}, + {GST_VAAPI_RENDER_MODE_TEXTURE, + "Textured-blit render mode", "texture"}, + {0, NULL, NULL} + }; + + if (g_once_init_enter (&g_type)) { + GType type = g_enum_register_static ("GstVaapiRenderMode", render_modes); + gst_type_mark_as_plugin_api (type, 0); + g_once_init_leave (&g_type, type); + } + return g_type; +} + +/* --- GstVaapiRotation --- */ + +GType +gst_vaapi_rotation_get_type (void) +{ + static gsize g_type = 0; + + static const GEnumValue rotation_values[] = { + {GST_VAAPI_ROTATION_0, + "Unrotated mode", "0"}, + {GST_VAAPI_ROTATION_90, + "Rotated by 90°, clockwise", "90"}, + {GST_VAAPI_ROTATION_180, + "Rotated by 180°, clockwise", "180"}, + {GST_VAAPI_ROTATION_270, + "Rotated by 270°, clockwise", "270"}, + {GST_VAAPI_ROTATION_AUTOMATIC, + "Rotated by image-orientating tag°", "Automatic"}, + {0, NULL, NULL}, + }; + + if (g_once_init_enter (&g_type)) { + GType type = g_enum_register_static ("GstVaapiRotation", rotation_values); + gst_type_mark_as_plugin_api (type, 0); + g_once_init_leave (&g_type, type); + } + return g_type; +} + +/* --- GstVaapiRateControl --- */ + +GType +gst_vaapi_rate_control_get_type (void) +{ + static gsize g_type = 0; + + static const GEnumValue rate_control_values[] = { + {GST_VAAPI_RATECONTROL_NONE, + "None", "none"}, + {GST_VAAPI_RATECONTROL_CQP, + "Constant QP", "cqp"}, + {GST_VAAPI_RATECONTROL_CBR, + "Constant bitrate", "cbr"}, + {GST_VAAPI_RATECONTROL_VCM, + "Video conference", "vcm"}, + {GST_VAAPI_RATECONTROL_VBR, + "Variable bitrate", "vbr"}, + {GST_VAAPI_RATECONTROL_VBR_CONSTRAINED, + "Variable bitrate - Constrained", "vbr_constrained"}, + {GST_VAAPI_RATECONTROL_MB, + "Macroblock based rate control", "mb"}, + {GST_VAAPI_RATECONTROL_ICQ, + "Constant QP - Intelligent", "icq"}, + {GST_VAAPI_RATECONTROL_QVBR, + "Variable bitrate - Quality defined", "qvbr"}, + {0, NULL, NULL}, + }; + + if (g_once_init_enter (&g_type)) { + GType type = g_enum_register_static ("GstVaapiRateControl", + rate_control_values); + gst_type_mark_as_plugin_api (type, 0); + g_once_init_leave (&g_type, type); + } + return g_type; +} + +static gboolean +build_enum_subset_values_from_mask (GstVaapiEnumSubset * subset, guint32 mask) +{ + GEnumClass *enum_class; + const GEnumValue *value; + guint i, n; + + enum_class = g_type_class_ref (subset->parent_type); + if (!enum_class) + return FALSE; + + for (i = 0, n = 0; i < 32 && n < subset->num_values; i++) { + if (!(mask & (1U << i))) + continue; + value = g_enum_get_value (enum_class, i); + if (!value) + continue; + subset->values[n++] = *value; + } + g_type_class_unref (enum_class); + if (n != subset->num_values - 1) + goto error_invalid_num_values; + return TRUE; + + /* ERRORS */ +error_invalid_num_values: + { + GST_ERROR ("invalid number of static values for `%s'", subset->type_name); + return FALSE; + } +} + +GType +gst_vaapi_type_define_enum_subset_from_mask (GstVaapiEnumSubset * subset, + guint32 mask) +{ + if (g_once_init_enter (&subset->type)) { + GType type; + + build_enum_subset_values_from_mask (subset, mask); + memset (&subset->type_info, 0, sizeof (subset->type_info)); + g_enum_complete_type_info (subset->parent_type, &subset->type_info, + subset->values); + + type = g_type_register_static (G_TYPE_ENUM, subset->type_name, + &subset->type_info, 0); + g_once_init_leave (&subset->type, type); + } + return subset->type; +} + +/** + * gst_vaapi_enum_type_get_nick: + * @type: an enum #GType + * @value: the value to get its nick + * + * Returns: (tranfer none); the string associated with + * @value. Otherwise "" + **/ +const gchar * +gst_vaapi_enum_type_get_nick (GType type, gint value) +{ + gpointer const klass = g_type_class_peek (type); + GEnumValue *const e = g_enum_get_value (klass, value); + + if (e) + return e->value_nick; + return ""; +} diff --git a/gst-libs/gst/vaapi/gstvaapivalue.h b/gst-libs/gst/vaapi/gstvaapivalue.h new file mode 100644 index 0000000000..f462671504 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapivalue.h @@ -0,0 +1,166 @@ +/* + * gstvaapivalue.h - GValue implementations specific to VA-API + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_VALUE_H +#define GST_VAAPI_VALUE_H + +#include +#include + +G_BEGIN_DECLS + +/** + * GST_VAAPI_TYPE_POINT: + * + * A #GstVaapiPoint type that represents a 2D point coordinates. + * + * Return value: the GType of #GstVaapiPoint + */ +#define GST_VAAPI_TYPE_POINT gst_vaapi_point_get_type() + +/** + * GST_VAAPI_TYPE_RECTANGLE: + * + * A #GstVaapiRectangle type that represents a 2D rectangle position + * and size. + * + * Return value: the GType of #GstVaapiRectangle + */ +#define GST_VAAPI_TYPE_RECTANGLE gst_vaapi_rectangle_get_type() + +/** + * GST_VAAPI_TYPE_RENDER_MODE: + * + * A #GstVaapiRenderMode type that represents the VA display backend + * rendering mode: overlay (2D engine) or textured-blit (3D engine). + * + * Return value: the #GType of GstVaapiRenderMode + */ +#define GST_VAAPI_TYPE_RENDER_MODE gst_vaapi_render_mode_get_type() + +/** + * GST_VAAPI_TYPE_ROTATION: + * + * A type that represents the VA display rotation. + * + * Return value: the #GType of GstVaapiRotation + */ +#define GST_VAAPI_TYPE_ROTATION gst_vaapi_rotation_get_type() + +/** + * GST_VAAPI_TYPE_RATE_CONTROL: + * + * A type that represents the VA rate control. + * + * Return value: the #GType of GstVaapiRateControl + */ +#define GST_VAAPI_TYPE_RATE_CONTROL gst_vaapi_rate_control_get_type() + +GType +gst_vaapi_point_get_type(void) G_GNUC_CONST; + +GType +gst_vaapi_rectangle_get_type(void) G_GNUC_CONST; + +GType +gst_vaapi_render_mode_get_type(void) G_GNUC_CONST; + +GType +gst_vaapi_rotation_get_type(void) G_GNUC_CONST; + +GType +gst_vaapi_rate_control_get_type(void) G_GNUC_CONST; + +/** + * GST_VAAPI_POPCOUNT32: + * @x: the value from which to compute population count + * + * Computes the number of bits set in the supplied 32-bit value @x. + * + * Return value: the number of bits set in @x + */ +#define GST_VAAPI_POPCOUNT32(x) \ + GST_VAAPI_POPCOUNT32_0(x) +#define GST_VAAPI_POPCOUNT32_0(x) \ + GST_VAAPI_POPCOUNT32_1((x) - (((x) >> 1) & 0x55555555)) +#define GST_VAAPI_POPCOUNT32_1(x) \ + GST_VAAPI_POPCOUNT32_2(((x) & 0x33333333) + (((x) >> 2) & 0x33333333)) +#define GST_VAAPI_POPCOUNT32_2(x) \ + GST_VAAPI_POPCOUNT32_3((x) + ((x) >> 4)) +#define GST_VAAPI_POPCOUNT32_3(x) \ + GST_VAAPI_POPCOUNT32_4((x) & 0x0f0f0f0f) +#define GST_VAAPI_POPCOUNT32_4(x) \ + (((x) * 0x01010101) >> 24) + +/* --- GstVaapiEnumSubset --- */ + +/** + * GstVaapiEnumSubset: + * @name: name of the enum subset + * @parent_type: parent enum type + * @type: registered #GType + * @type_info: #GTypeInfo used to build the @type + * @values: pointer to a static array of #GEnumValue elements + * @num_values: number of elements in the @values array, including the + * terminator + * + * Structure that holds the required information to build a GEnum + * subset from the supplied @parent_type, i.e. a subset of its values. + */ +typedef struct { + GType parent_type; + GType type; + GTypeInfo type_info; + const gchar *type_name; + GEnumValue *values; + guint num_values; +} GstVaapiEnumSubset; + +G_GNUC_INTERNAL +GType +gst_vaapi_type_define_enum_subset_from_mask(GstVaapiEnumSubset *subset, + guint32 mask); + +#define GST_VAAPI_TYPE_DEFINE_ENUM_SUBSET_FROM_MASK(NAME, name, TYPE, MASK) \ +static GType \ +G_PASTE(name,_get_type)(void) \ +{ \ + static GEnumValue enum_values[GST_VAAPI_POPCOUNT32(MASK) + 1]; \ + static GstVaapiEnumSubset subset = { \ + .type_name = G_STRINGIFY(NAME), \ + .values = enum_values, \ + .num_values = G_N_ELEMENTS(enum_values), \ + }; \ + if (g_once_init_enter(&subset.parent_type)) \ + g_once_init_leave(&subset.parent_type, TYPE); \ + return gst_vaapi_type_define_enum_subset_from_mask(&subset, MASK); \ +} + +G_GNUC_INTERNAL +const gchar * +gst_vaapi_enum_type_get_nick (GType type, gint value); + +G_END_DECLS + +#endif /* GST_VAAPI_VALUE_H */ diff --git a/gst-libs/gst/vaapi/gstvaapivideopool.c b/gst-libs/gst/vaapi/gstvaapivideopool.c new file mode 100644 index 0000000000..8c9c10e84f --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapivideopool.c @@ -0,0 +1,423 @@ +/* + * gstvaapivideopool.c - Video object pool abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapivideopool + * @short_description: Video object pool abstraction + */ + +#include "sysdeps.h" +#include "gstvaapivideopool.h" +#include "gstvaapivideopool_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +#define GST_VAAPI_VIDEO_POOL_GET_CLASS(obj) \ + gst_vaapi_video_pool_get_class (GST_VAAPI_VIDEO_POOL (obj)) + +static inline const GstVaapiVideoPoolClass * +gst_vaapi_video_pool_get_class (GstVaapiVideoPool * pool) +{ + return GST_VAAPI_VIDEO_POOL_CLASS (GST_VAAPI_MINI_OBJECT_GET_CLASS (pool)); +} + +static inline gpointer +gst_vaapi_video_pool_alloc_object (GstVaapiVideoPool * pool) +{ + return GST_VAAPI_VIDEO_POOL_GET_CLASS (pool)->alloc_object (pool); +} + +void +gst_vaapi_video_pool_init (GstVaapiVideoPool * pool, GstVaapiDisplay * display, + GstVaapiVideoPoolObjectType object_type) +{ + pool->object_type = object_type; + pool->display = gst_object_ref (display); + pool->used_objects = NULL; + pool->used_count = 0; + pool->capacity = 0; + + g_queue_init (&pool->free_objects); + g_mutex_init (&pool->mutex); +} + +void +gst_vaapi_video_pool_finalize (GstVaapiVideoPool * pool) +{ + g_list_free_full (pool->used_objects, (GDestroyNotify) gst_mini_object_unref); + g_queue_foreach (&pool->free_objects, (GFunc) gst_mini_object_unref, NULL); + g_queue_clear (&pool->free_objects); + gst_vaapi_display_replace (&pool->display, NULL); + g_mutex_clear (&pool->mutex); +} + +/** + * gst_vaapi_video_pool_ref: + * @pool: a #GstVaapiVideoPool + * + * Atomically increases the reference count of the given @pool by one. + * + * Returns: The same @pool argument + */ +GstVaapiVideoPool * +gst_vaapi_video_pool_ref (GstVaapiVideoPool * pool) +{ + return (GstVaapiVideoPool *) + gst_vaapi_mini_object_ref (GST_VAAPI_MINI_OBJECT (pool)); +} + +/** + * gst_vaapi_video_pool_unref: + * @pool: a #GstVaapiVideoPool + * + * Atomically decreases the reference count of the @pool by one. If + * the reference count reaches zero, the pool will be free'd. + */ +void +gst_vaapi_video_pool_unref (GstVaapiVideoPool * pool) +{ + gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (pool)); +} + +/** + * gst_vaapi_video_pool_replace: + * @old_pool_ptr: a pointer to a #GstVaapiVideoPool + * @new_pool: a #GstVaapiVideoPool + * + * Atomically replaces the pool pool held in @old_pool_ptr with + * @new_pool. This means that @old_pool_ptr shall reference a valid + * pool. However, @new_pool can be NULL. + */ +void +gst_vaapi_video_pool_replace (GstVaapiVideoPool ** old_pool_ptr, + GstVaapiVideoPool * new_pool) +{ + gst_vaapi_mini_object_replace ((GstVaapiMiniObject **) (old_pool_ptr), + GST_VAAPI_MINI_OBJECT (new_pool)); +} + +/** + * gst_vaapi_video_pool_get_display: + * @pool: a #GstVaapiVideoPool + * + * Retrieves the #GstVaapiDisplay the @pool is bound to. The @pool + * owns the returned object and it shall not be unref'ed. + * + * Return value: the #GstVaapiDisplay the @pool is bound to + */ +GstVaapiDisplay * +gst_vaapi_video_pool_get_display (GstVaapiVideoPool * pool) +{ + g_return_val_if_fail (pool != NULL, NULL); + + return pool->display; +} + +/** + * gst_vaapi_video_pool_get_object_type: + * @pool: a #GstVaapiVideoPool + * + * Retrieves the type of objects the video @pool supports. + * + * Return value: the #GstVaapiVideoPoolObjectType of the underlying pool + * objects + */ +GstVaapiVideoPoolObjectType +gst_vaapi_video_pool_get_object_type (GstVaapiVideoPool * pool) +{ + g_return_val_if_fail (pool != NULL, (GstVaapiVideoPoolObjectType) 0); + + return pool->object_type; +} + +/** + * gst_vaapi_video_pool_get_object: + * @pool: a #GstVaapiVideoPool + * + * Retrieves a new object from the @pool, or allocates a new one if + * none was found. The @pool holds a reference on the returned object + * and thus shall be released through gst_vaapi_video_pool_put_object() + * when it's no longer needed. + * + * Return value: a possibly newly allocated object, or %NULL on error + */ +static gpointer +gst_vaapi_video_pool_get_object_unlocked (GstVaapiVideoPool * pool) +{ + gpointer object; + + if (pool->capacity && pool->used_count >= pool->capacity) + return NULL; + + object = g_queue_pop_head (&pool->free_objects); + if (!object) { + g_mutex_unlock (&pool->mutex); + object = gst_vaapi_video_pool_alloc_object (pool); + g_mutex_lock (&pool->mutex); + if (!object) + return NULL; + + /* Others already allocated a new one before us during we + release the mutex */ + if (pool->capacity && pool->used_count >= pool->capacity) { + gst_mini_object_unref (object); + return NULL; + } + } + + ++pool->used_count; + pool->used_objects = g_list_prepend (pool->used_objects, object); + return gst_mini_object_ref (object); +} + +gpointer +gst_vaapi_video_pool_get_object (GstVaapiVideoPool * pool) +{ + gpointer object; + + g_return_val_if_fail (pool != NULL, NULL); + + g_mutex_lock (&pool->mutex); + object = gst_vaapi_video_pool_get_object_unlocked (pool); + g_mutex_unlock (&pool->mutex); + return object; +} + +/** + * gst_vaapi_video_pool_put_object: + * @pool: a #GstVaapiVideoPool + * @object: the object to add back to the pool + * + * Pushes the @object back into the pool. The @object shall be + * obtained from the @pool through gst_vaapi_video_pool_get_object(). + * Calling this function with an arbitrary object yields undefined + * behaviour. + */ +static void +gst_vaapi_video_pool_put_object_unlocked (GstVaapiVideoPool * pool, + gpointer object) +{ + GList *elem; + + elem = g_list_find (pool->used_objects, object); + if (!elem) + return; + + gst_mini_object_unref (object); + --pool->used_count; + pool->used_objects = g_list_delete_link (pool->used_objects, elem); + g_queue_push_tail (&pool->free_objects, object); +} + +void +gst_vaapi_video_pool_put_object (GstVaapiVideoPool * pool, gpointer object) +{ + g_return_if_fail (pool != NULL); + g_return_if_fail (object != NULL); + + g_mutex_lock (&pool->mutex); + gst_vaapi_video_pool_put_object_unlocked (pool, object); + g_mutex_unlock (&pool->mutex); +} + +/** + * gst_vaapi_video_pool_add_object: + * @pool: a #GstVaapiVideoPool + * @object: the object to add to the pool + * + * Adds the @object to the pool. The pool then holds a reference on + * the @object. This operation does not change the capacity of the + * pool. + * + * Return value: %TRUE on success. + */ +static inline gboolean +gst_vaapi_video_pool_add_object_unlocked (GstVaapiVideoPool * pool, + gpointer object) +{ + g_queue_push_tail (&pool->free_objects, gst_mini_object_ref (object)); + return TRUE; +} + +gboolean +gst_vaapi_video_pool_add_object (GstVaapiVideoPool * pool, gpointer object) +{ + gboolean success; + + g_return_val_if_fail (pool != NULL, FALSE); + g_return_val_if_fail (object != NULL, FALSE); + + g_mutex_lock (&pool->mutex); + success = gst_vaapi_video_pool_add_object_unlocked (pool, object); + g_mutex_unlock (&pool->mutex); + return success; +} + +/** + * gst_vaapi_video_pool_add_objects: + * @pool: a #GstVaapiVideoPool + * @objects: a #GPtrArray of objects + * + * Adds the @objects to the pool. The pool then holds a reference on + * the @objects. This operation does not change the capacity of the + * pool and is just a wrapper around gst_vaapi_video_pool_add_object(). + * + * Return value: %TRUE on success. + */ +static gboolean +gst_vaapi_video_pool_add_objects_unlocked (GstVaapiVideoPool * pool, + GPtrArray * objects) +{ + guint i; + + for (i = 0; i < objects->len; i++) { + gpointer const object = g_ptr_array_index (objects, i); + if (!gst_vaapi_video_pool_add_object_unlocked (pool, object)) + return FALSE; + } + return TRUE; +} + +gboolean +gst_vaapi_video_pool_add_objects (GstVaapiVideoPool * pool, GPtrArray * objects) +{ + gboolean success; + + g_return_val_if_fail (pool != NULL, FALSE); + + g_mutex_lock (&pool->mutex); + success = gst_vaapi_video_pool_add_objects_unlocked (pool, objects); + g_mutex_unlock (&pool->mutex); + return success; +} + +/** + * gst_vaapi_video_pool_get_size: + * @pool: a #GstVaapiVideoPool + * + * Returns the number of free objects available in the pool. + * + * Return value: number of free objects in the pool + */ +guint +gst_vaapi_video_pool_get_size (GstVaapiVideoPool * pool) +{ + guint size; + + g_return_val_if_fail (pool != NULL, 0); + + g_mutex_lock (&pool->mutex); + size = g_queue_get_length (&pool->free_objects); + g_mutex_unlock (&pool->mutex); + return size; +} + +static gboolean +gst_vaapi_video_pool_reserve_unlocked (GstVaapiVideoPool * pool, guint n) +{ + guint i, num_allocated; + + num_allocated = g_queue_get_length (&pool->free_objects) + pool->used_count; + if (n <= num_allocated) + return TRUE; + + n = MIN (n, pool->capacity); + for (i = num_allocated; i < n; i++) { + gpointer object; + + g_mutex_unlock (&pool->mutex); + object = gst_vaapi_video_pool_alloc_object (pool); + g_mutex_lock (&pool->mutex); + if (!object) + return FALSE; + g_queue_push_tail (&pool->free_objects, object); + } + return TRUE; +} + +/** + * gst_vaapi_video_pool_reserve: + * @pool: a #GstVaapiVideoPool + * @n: the number of objects to pre-allocate + * + * Pre-allocates up to @n objects in the pool. If @n is less than or + * equal to the number of free and used objects in the pool, this call + * has no effect. Otherwise, it is a request for allocation of + * additional objects. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_video_pool_reserve (GstVaapiVideoPool * pool, guint n) +{ + gboolean success; + + g_return_val_if_fail (pool != NULL, 0); + + g_mutex_lock (&pool->mutex); + success = gst_vaapi_video_pool_reserve_unlocked (pool, n); + g_mutex_unlock (&pool->mutex); + return success; +} + +/** + * gst_vaapi_video_pool_get_capacity: + * @pool: a #GstVaapiVideoPool + * + * Returns the maximum number of objects in the pool. i.e. the maximum + * number of objects that can be returned by gst_vaapi_video_pool_get_object(). + * + * Return value: the capacity of the pool + */ +guint +gst_vaapi_video_pool_get_capacity (GstVaapiVideoPool * pool) +{ + guint capacity; + + g_return_val_if_fail (pool != NULL, 0); + + g_mutex_lock (&pool->mutex); + capacity = pool->capacity; + g_mutex_unlock (&pool->mutex); + + return capacity; +} + +/** + * gst_vaapi_video_pool_set_capacity: + * @pool: a #GstVaapiVideoPool + * @capacity: the maximal capacity of the pool + * + * Sets the maximum number of objects that can be allocated in the pool. + */ +void +gst_vaapi_video_pool_set_capacity (GstVaapiVideoPool * pool, guint capacity) +{ + g_return_if_fail (pool != NULL); + + g_mutex_lock (&pool->mutex); + pool->capacity = capacity; + g_mutex_unlock (&pool->mutex); +} diff --git a/gst-libs/gst/vaapi/gstvaapivideopool.h b/gst-libs/gst/vaapi/gstvaapivideopool.h new file mode 100644 index 0000000000..393de7b893 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapivideopool.h @@ -0,0 +1,96 @@ +/* + * gstvaapivideopool.h - Video object pool abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_VIDEO_POOL_H +#define GST_VAAPI_VIDEO_POOL_H + +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_VIDEO_POOL(obj) \ + ((GstVaapiVideoPool *)(obj)) + +typedef struct _GstVaapiVideoPool GstVaapiVideoPool; + +/** + * GstVaapiVideoPoolObjectType: + * @GST_VAAPI_VIDEO_POOL_OBJECT_TYPE_IMAGE: #GstVaapiImage objects. + * @GST_VAAPI_VIDEO_POOL_OBJECT_TYPE_SURFACE: #GstVaapiSurface objects. + * @GST_VAAPI_VIDEO_POOL_OBJECT_TYPE_CODED_BUFFER: #GstVaapiCodedBuffer objects. + * + * The set of all supported #GstVaapiVideoPool object types. + */ +typedef enum +{ + GST_VAAPI_VIDEO_POOL_OBJECT_TYPE_IMAGE = 1, + GST_VAAPI_VIDEO_POOL_OBJECT_TYPE_SURFACE, + GST_VAAPI_VIDEO_POOL_OBJECT_TYPE_CODED_BUFFER +} GstVaapiVideoPoolObjectType; + +GstVaapiVideoPool * +gst_vaapi_video_pool_ref (GstVaapiVideoPool * pool); + +void +gst_vaapi_video_pool_unref (GstVaapiVideoPool * pool); + +void +gst_vaapi_video_pool_replace (GstVaapiVideoPool ** old_pool_ptr, + GstVaapiVideoPool * new_pool); + +GstVaapiDisplay * +gst_vaapi_video_pool_get_display (GstVaapiVideoPool * pool); + +GstVaapiVideoPoolObjectType +gst_vaapi_video_pool_get_object_type (GstVaapiVideoPool * pool); + +gpointer +gst_vaapi_video_pool_get_object (GstVaapiVideoPool * pool); + +void +gst_vaapi_video_pool_put_object (GstVaapiVideoPool * pool, gpointer object); + +gboolean +gst_vaapi_video_pool_add_object (GstVaapiVideoPool * pool, gpointer object); + +gboolean +gst_vaapi_video_pool_add_objects (GstVaapiVideoPool * pool, + GPtrArray * objects); + +guint +gst_vaapi_video_pool_get_size (GstVaapiVideoPool * pool); + +gboolean +gst_vaapi_video_pool_reserve (GstVaapiVideoPool * pool, guint n); + +guint +gst_vaapi_video_pool_get_capacity (GstVaapiVideoPool * pool); + +void +gst_vaapi_video_pool_set_capacity (GstVaapiVideoPool * pool, guint capacity); + +G_END_DECLS + +#endif /* GST_VAAPI_VIDEO_POOL_H */ diff --git a/gst-libs/gst/vaapi/gstvaapivideopool_priv.h b/gst-libs/gst/vaapi/gstvaapivideopool_priv.h new file mode 100644 index 0000000000..1d5115a0d7 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapivideopool_priv.h @@ -0,0 +1,84 @@ +/* + * gstvaapivideopool_priv.h - Video object pool abstraction (private defs) + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_VIDEO_POOL_PRIV_H +#define GST_VAAPI_VIDEO_POOL_PRIV_H + +#include "gstvaapiminiobject.h" + +G_BEGIN_DECLS + +#define GST_VAAPI_VIDEO_POOL_CLASS(klass) \ + ((GstVaapiVideoPoolClass *)(klass)) +#define GST_VAAPI_IS_VIDEO_POOL_CLASS(klass) \ + ((klass) != NULL) + +typedef struct _GstVaapiVideoPoolClass GstVaapiVideoPoolClass; + +/** + * GstVaapiVideoPool: + * + * A pool of lazily allocated video objects. e.g. surfaces, images. + */ +struct _GstVaapiVideoPool +{ + /*< private >*/ + GstVaapiMiniObject parent_instance; + + guint object_type; + GstVaapiDisplay *display; + GQueue free_objects; + GList *used_objects; + guint used_count; + guint capacity; + GMutex mutex; +}; + +/** + * GstVaapiVideoPoolClass: + * @alloc_object: virtual function for allocating a video pool object + * + * A pool base class used to hold video objects. e.g. surfaces, images. + */ +struct _GstVaapiVideoPoolClass +{ + /*< private >*/ + GstVaapiMiniObjectClass parent_class; + + /*< public >*/ + gpointer (*alloc_object) (GstVaapiVideoPool * pool); +}; + +G_GNUC_INTERNAL +void +gst_vaapi_video_pool_init (GstVaapiVideoPool * pool, GstVaapiDisplay * display, + GstVaapiVideoPoolObjectType object_type); + +G_GNUC_INTERNAL +void +gst_vaapi_video_pool_finalize (GstVaapiVideoPool * pool); + +G_END_DECLS + +#endif /* GST_VAAPI_VIDEO_POOL_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiwindow.c b/gst-libs/gst/vaapi/gstvaapiwindow.c new file mode 100644 index 0000000000..7fd4502f95 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow.c @@ -0,0 +1,705 @@ +/* + * gstvaapiwindow.c - VA window abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapiwindow + * @short_description: VA window abstraction + */ + +#include "sysdeps.h" +#include "gstvaapiwindow.h" +#include "gstvaapiwindow_priv.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapisurface_priv.h" + +GST_DEBUG_CATEGORY (gst_debug_vaapi_window); +#define GST_CAT_DEFAULT gst_debug_vaapi_window + +#define _do_init \ + GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi_window, "vaapiwindow", 0, \ + "VA-API Window"); + +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstVaapiWindow, gst_vaapi_window, + GST_TYPE_OBJECT, _do_init); + +enum +{ + PROP_DISPLAY = 1, + N_PROPERTIES +}; +static GParamSpec *g_properties[N_PROPERTIES] = { NULL, }; + +static void +gst_vaapi_window_ensure_size (GstVaapiWindow * window) +{ + const GstVaapiWindowClass *const klass = GST_VAAPI_WINDOW_GET_CLASS (window); + + if (!window->check_geometry) + return; + + if (klass->get_geometry) + klass->get_geometry (window, NULL, NULL, &window->width, &window->height); + + window->check_geometry = FALSE; + window->is_fullscreen = (window->width == window->display_width && + window->height == window->display_height); +} + +static gboolean +ensure_filter (GstVaapiWindow * window) +{ + GstVaapiDisplay *const display = GST_VAAPI_WINDOW_DISPLAY (window); + + /* Ensure VPP pipeline is built */ + if (window->filter) + return TRUE; + + window->filter = gst_vaapi_filter_new (display); + if (!window->filter) + goto error_create_filter; + if (!gst_vaapi_filter_set_format (window->filter, GST_VIDEO_FORMAT_NV12)) + goto error_unsupported_format; + + return TRUE; + +error_create_filter: + { + GST_WARNING ("failed to create VPP filter. Disabling"); + window->has_vpp = FALSE; + return FALSE; + } +error_unsupported_format: + { + GST_ERROR ("unsupported render target format %s", + gst_vaapi_video_format_to_string (GST_VIDEO_FORMAT_NV12)); + window->has_vpp = FALSE; + return FALSE; + } +} + +void +gst_vaapi_window_set_vpp_format_internal (GstVaapiWindow * window, + GstVideoFormat format, guint flags) +{ + if (window->surface_pool_format == format && + window->surface_pool_flags == flags) + return; + + gst_vaapi_video_pool_replace (&window->surface_pool, NULL); + window->surface_pool_format = format; + window->surface_pool_flags = flags; +} + +static gboolean +ensure_filter_surface_pool (GstVaapiWindow * window) +{ + GstVaapiDisplay *const display = GST_VAAPI_WINDOW_DISPLAY (window); + + if (window->surface_pool) + goto ensure_filter; + + /* Ensure VA surface pool is created */ + /* XXX: optimize the surface format to use. e.g. YUY2 */ + window->surface_pool = gst_vaapi_surface_pool_new (display, + window->surface_pool_format, window->width, window->height, + window->surface_pool_flags); + if (!window->surface_pool) { + GST_WARNING ("failed to create surface pool for conversion"); + return FALSE; + } + gst_vaapi_filter_replace (&window->filter, NULL); + +ensure_filter: + return ensure_filter (window); +} + +static gboolean +gst_vaapi_window_create (GstVaapiWindow * window, guint width, guint height) +{ + gst_vaapi_display_get_size (GST_VAAPI_WINDOW_DISPLAY (window), + &window->display_width, &window->display_height); + + if (!GST_VAAPI_WINDOW_GET_CLASS (window)->create (window, &width, &height)) + return FALSE; + + if (width != window->width || height != window->height) { + GST_DEBUG ("backend resized window to %ux%u", width, height); + window->width = width; + window->height = height; + } + return TRUE; +} + +static void +gst_vaapi_window_finalize (GObject * object) +{ + GstVaapiWindow *const window = GST_VAAPI_WINDOW (object); + + gst_vaapi_video_pool_replace (&window->surface_pool, NULL); + gst_vaapi_filter_replace (&window->filter, NULL); + gst_vaapi_display_replace (&window->display, NULL); + + G_OBJECT_CLASS (gst_vaapi_window_parent_class)->finalize (object); +} + +static void +gst_vaapi_window_set_property (GObject * object, guint property_id, + const GValue * value, GParamSpec * pspec) +{ + GstVaapiWindow *const window = GST_VAAPI_WINDOW (object); + + switch (property_id) { + case PROP_DISPLAY: + g_assert (window->display == NULL); + window->display = g_value_dup_object (value); + g_assert (window->display != NULL); + window->has_vpp = GST_VAAPI_DISPLAY_HAS_VPP (window->display); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gst_vaapi_window_get_property (GObject * object, guint property_id, + GValue * value, GParamSpec * pspec) +{ + GstVaapiWindow *const window = GST_VAAPI_WINDOW (object); + + switch (property_id) { + case PROP_DISPLAY: + g_value_set_object (value, window->display); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gst_vaapi_window_class_init (GstVaapiWindowClass * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = gst_vaapi_window_set_property; + object_class->get_property = gst_vaapi_window_get_property; + object_class->finalize = gst_vaapi_window_finalize; + + /** + * GstVaapiWindow:display: + * + * #GstVaapiDisplay to be used. + */ + g_properties[PROP_DISPLAY] = + g_param_spec_object ("display", "Gst VA-API Display", + "The VA-API display object to use", GST_TYPE_VAAPI_DISPLAY, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME); + + g_object_class_install_properties (object_class, N_PROPERTIES, g_properties); +} + +static void +gst_vaapi_window_init (GstVaapiWindow * window) +{ +} + +GstVaapiWindow * +gst_vaapi_window_new_internal (GType type, GstVaapiDisplay * display, + GstVaapiID id, guint width, guint height) +{ + GstVaapiWindow *window; + + if (id != GST_VAAPI_ID_INVALID) { + g_return_val_if_fail (width == 0, NULL); + g_return_val_if_fail (height == 0, NULL); + } else { + g_return_val_if_fail (width > 0, NULL); + g_return_val_if_fail (height > 0, NULL); + } + + window = g_object_new (type, "display", display, NULL); + if (!window) + return NULL; + + window->surface_pool_format = GST_VIDEO_FORMAT_NV12; + + window->use_foreign_window = id != GST_VAAPI_ID_INVALID; + GST_VAAPI_WINDOW_ID (window) = window->use_foreign_window ? id : 0; + + GST_DEBUG_OBJECT (window, "new window with id = 0x%08" G_GSIZE_MODIFIER + "x and size %ux%u", id, width, height); + + if (!gst_vaapi_window_create (window, width, height)) + goto error; + + return window; + + /* ERRORS */ +error: + { + gst_object_unref (window); + return NULL; + } +} + +GstVaapiSurface * +gst_vaapi_window_vpp_convert_internal (GstVaapiWindow * window, + GstVaapiSurface * surface, const GstVaapiRectangle * src_rect, + const GstVaapiRectangle * dst_rect, guint flags) +{ + GstVaapiSurface *vpp_surface = NULL; + GstVaapiFilterStatus status; + + if (!window->has_vpp) + return NULL; + + if (!ensure_filter_surface_pool (window)) + return NULL; + + if (src_rect) + if (!gst_vaapi_filter_set_cropping_rectangle (window->filter, src_rect)) + return NULL; + if (dst_rect) + if (!gst_vaapi_filter_set_target_rectangle (window->filter, dst_rect)) + return NULL; + + /* Post-process the decoded source surface */ + vpp_surface = gst_vaapi_video_pool_get_object (window->surface_pool); + if (!vpp_surface) + return NULL; + + status = + gst_vaapi_filter_process (window->filter, surface, vpp_surface, flags); + if (status != GST_VAAPI_FILTER_STATUS_SUCCESS) + goto error_process_filter; + return vpp_surface; + + /* ERRORS */ +error_process_filter: + { + GST_ERROR ("failed to process surface %" GST_VAAPI_ID_FORMAT " (error %d)", + GST_VAAPI_ID_ARGS (GST_VAAPI_SURFACE_ID (surface)), status); + gst_vaapi_video_pool_put_object (window->surface_pool, vpp_surface); + return NULL; + } +} + +/** + * gst_vaapi_window_new: + * @display: a #GstVaapiDisplay + * @width: the requested window width, in pixels + * @height: the requested windo height, in pixels + * + * Creates a window with the specified @width and @height. The window + * will be attached to the @display and remains invisible to the user + * until gst_vaapi_window_show() is called. + * + * Return value: the newly allocated #GstVaapiWindow object + */ +GstVaapiWindow * +gst_vaapi_window_new (GstVaapiDisplay * display, guint width, guint height) +{ + GstVaapiDisplayClass *dpy_class; + + g_return_val_if_fail (GST_VAAPI_IS_DISPLAY (display), NULL); + + dpy_class = GST_VAAPI_DISPLAY_GET_CLASS (display); + if (G_UNLIKELY (!dpy_class->create_window)) + return NULL; + return dpy_class->create_window (display, GST_VAAPI_ID_INVALID, width, + height); +} + +/** + * gst_vaapi_window_replace: + * @old_window_ptr: a pointer to a #GstVaapiWindow + * @new_window: a #GstVaapiWindow + * + * Atomically replaces the window window held in @old_window_ptr with + * @new_window. This means that @old_window_ptr shall reference a + * valid window. However, @new_window can be NULL. + */ +void +gst_vaapi_window_replace (GstVaapiWindow ** old_window_ptr, + GstVaapiWindow * new_window) +{ + gst_object_replace ((GstObject **) old_window_ptr, GST_OBJECT (new_window)); +} + +/** + * gst_vaapi_window_get_display: + * @window: a #GstVaapiWindow + * + * Returns the #GstVaapiDisplay this @window is bound to. + * + * Return value: the parent #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_window_get_display (GstVaapiWindow * window) +{ + g_return_val_if_fail (GST_VAAPI_IS_WINDOW (window), NULL); + + return GST_VAAPI_WINDOW_DISPLAY (window); +} + +/** + * gst_vaapi_window_show: + * @window: a #GstVaapiWindow + * + * Flags a window to be displayed. Any window that is not shown will + * not appear on the screen. + */ +void +gst_vaapi_window_show (GstVaapiWindow * window) +{ + g_return_if_fail (GST_VAAPI_IS_WINDOW (window)); + + GST_VAAPI_WINDOW_GET_CLASS (window)->show (window); + window->check_geometry = TRUE; +} + +/** + * gst_vaapi_window_hide: + * @window: a #GstVaapiWindow + * + * Reverses the effects of gst_vaapi_window_show(), causing the window + * to be hidden (invisible to the user). + */ +void +gst_vaapi_window_hide (GstVaapiWindow * window) +{ + g_return_if_fail (GST_VAAPI_IS_WINDOW (window)); + + GST_VAAPI_WINDOW_GET_CLASS (window)->hide (window); +} + +/** + * gst_vaapi_window_get_fullscreen: + * @window: a #GstVaapiWindow + * + * Retrieves whether the @window is fullscreen or not + * + * Return value: %TRUE if the window is fullscreen + */ +gboolean +gst_vaapi_window_get_fullscreen (GstVaapiWindow * window) +{ + g_return_val_if_fail (GST_VAAPI_IS_WINDOW (window), FALSE); + + gst_vaapi_window_ensure_size (window); + + return window->is_fullscreen; +} + +/** + * gst_vaapi_window_set_render_rectangle: + * @window: a #GstVaapiWindow + * @x: the horizontal offset of the render area inside the window + * @y: the vertical offset of the render area inside the window + * @width: the width of the render area inside the window + * @height: the height of the render area inside the window + * + * Set information of the render area. + * + * Since: 1.18 + */ +void +gst_vaapi_window_set_render_rectangle (GstVaapiWindow * window, gint x, gint y, + gint width, gint height) +{ + const GstVaapiWindowClass *klass; + + g_return_if_fail (window != NULL); + + klass = GST_VAAPI_WINDOW_GET_CLASS (window); + + if (klass->set_render_rect) + klass->set_render_rect (window, x, y, width, height); +} + +/** + * gst_vaapi_window_set_fullscreen: + * @window: a #GstVaapiWindow + * @fullscreen: %TRUE to request window to get fullscreen + * + * Requests to place the @window in fullscreen or unfullscreen states. + */ +void +gst_vaapi_window_set_fullscreen (GstVaapiWindow * window, gboolean fullscreen) +{ + const GstVaapiWindowClass *klass; + + g_return_if_fail (GST_VAAPI_IS_WINDOW (window)); + + klass = GST_VAAPI_WINDOW_GET_CLASS (window); + + if (window->is_fullscreen != fullscreen && + klass->set_fullscreen && klass->set_fullscreen (window, fullscreen)) { + window->is_fullscreen = fullscreen; + window->check_geometry = TRUE; + } +} + +/** + * gst_vaapi_window_get_width: + * @window: a #GstVaapiWindow + * + * Retrieves the width of a #GstVaapiWindow. + * + * Return value: the width of the @window, in pixels + */ +guint +gst_vaapi_window_get_width (GstVaapiWindow * window) +{ + g_return_val_if_fail (GST_VAAPI_IS_WINDOW (window), 0); + + gst_vaapi_window_ensure_size (window); + + return window->width; +} + +/** + * gst_vaapi_window_get_height: + * @window: a #GstVaapiWindow + * + * Retrieves the height of a #GstVaapiWindow + * + * Return value: the height of the @window, in pixels + */ +guint +gst_vaapi_window_get_height (GstVaapiWindow * window) +{ + g_return_val_if_fail (GST_VAAPI_IS_WINDOW (window), 0); + + gst_vaapi_window_ensure_size (window); + + return window->height; +} + +/** + * gst_vaapi_window_get_size: + * @window: a #GstVaapiWindow + * @width_ptr: return location for the width, or %NULL + * @height_ptr: return location for the height, or %NULL + * + * Retrieves the dimensions of a #GstVaapiWindow. + */ +void +gst_vaapi_window_get_size (GstVaapiWindow * window, guint * width_ptr, + guint * height_ptr) +{ + g_return_if_fail (GST_VAAPI_IS_WINDOW (window)); + + gst_vaapi_window_ensure_size (window); + + if (width_ptr) + *width_ptr = window->width; + + if (height_ptr) + *height_ptr = window->height; +} + +/** + * gst_vaapi_window_set_width: + * @window: a #GstVaapiWindow + * @width: requested new width for the window, in pixels + * + * Resizes the @window to match the specified @width. + */ +void +gst_vaapi_window_set_width (GstVaapiWindow * window, guint width) +{ + g_return_if_fail (GST_VAAPI_IS_WINDOW (window)); + + gst_vaapi_window_set_size (window, width, window->height); +} + +/** + * gst_vaapi_window_set_height: + * @window: a #GstVaapiWindow + * @height: requested new height for the window, in pixels + * + * Resizes the @window to match the specified @height. + */ +void +gst_vaapi_window_set_height (GstVaapiWindow * window, guint height) +{ + g_return_if_fail (GST_VAAPI_IS_WINDOW (window)); + + gst_vaapi_window_set_size (window, window->width, height); +} + +/** + * gst_vaapi_window_set_size: + * @window: a #GstVaapiWindow + * @width: requested new width for the window, in pixels + * @height: requested new height for the window, in pixels + * + * Resizes the @window to match the specified @width and @height. + */ +void +gst_vaapi_window_set_size (GstVaapiWindow * window, guint width, guint height) +{ + g_return_if_fail (GST_VAAPI_IS_WINDOW (window)); + + if (width == window->width && height == window->height) + return; + + if (!GST_VAAPI_WINDOW_GET_CLASS (window)->resize (window, width, height)) + return; + + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + gst_vaapi_video_pool_replace (&window->surface_pool, NULL); + + window->width = width; + window->height = height; + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); +} + +static inline void +get_surface_rect (GstVaapiSurface * surface, GstVaapiRectangle * rect) +{ + rect->x = 0; + rect->y = 0; + rect->width = GST_VAAPI_SURFACE_WIDTH (surface); + rect->height = GST_VAAPI_SURFACE_HEIGHT (surface); +} + +static inline void +get_window_rect (GstVaapiWindow * window, GstVaapiRectangle * rect) +{ + guint width, height; + + gst_vaapi_window_get_size (window, &width, &height); + rect->x = 0; + rect->y = 0; + rect->width = width; + rect->height = height; +} + +/** + * gst_vaapi_window_put_surface: + * @window: a #GstVaapiWindow + * @surface: a #GstVaapiSurface + * @src_rect: the sub-rectangle of the source surface to + * extract and process. If %NULL, the entire surface will be used. + * @dst_rect: the sub-rectangle of the destination + * window into which the surface is rendered. If %NULL, the entire + * window will be used. + * @flags: postprocessing flags. See #GstVaapiSurfaceRenderFlags + * + * Renders the @surface region specified by @src_rect into the @window + * region specified by @dst_rect. The @flags specify how de-interlacing + * (if needed), color space conversion, scaling and other postprocessing + * transformations are performed. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_window_put_surface (GstVaapiWindow * window, + GstVaapiSurface * surface, + const GstVaapiRectangle * src_rect, + const GstVaapiRectangle * dst_rect, guint flags) +{ + const GstVaapiWindowClass *klass; + GstVaapiRectangle src_rect_default, dst_rect_default; + + g_return_val_if_fail (GST_VAAPI_IS_WINDOW (window), FALSE); + g_return_val_if_fail (surface != NULL, FALSE); + + klass = GST_VAAPI_WINDOW_GET_CLASS (window); + if (!klass->render) + return FALSE; + + if (!src_rect) { + src_rect = &src_rect_default; + get_surface_rect (surface, &src_rect_default); + } + + if (!dst_rect) { + dst_rect = &dst_rect_default; + get_window_rect (window, &dst_rect_default); + } + + return klass->render (window, surface, src_rect, dst_rect, flags); +} + +/** + * gst_vaapi_window_reconfigure: + * @window: a #GstVaapiWindow + * + * Updates internal window size from geometry of the underlying window + * implementation if necessary. + */ +void +gst_vaapi_window_reconfigure (GstVaapiWindow * window) +{ + g_return_if_fail (GST_VAAPI_IS_WINDOW (window)); + + window->check_geometry = TRUE; + gst_vaapi_window_ensure_size (window); +} + +/** + * gst_vaapi_window_unblock: + * @window: a #GstVaapiWindow + * + * Unblocks a rendering surface operation. + */ +gboolean +gst_vaapi_window_unblock (GstVaapiWindow * window) +{ + const GstVaapiWindowClass *klass; + + g_return_val_if_fail (GST_VAAPI_IS_WINDOW (window), FALSE); + + klass = GST_VAAPI_WINDOW_GET_CLASS (window); + + if (klass->unblock) + return klass->unblock (window); + + return TRUE; +} + +/** + * gst_vaapi_window_unblock_cancel: + * @window: a #GstVaapiWindow + * + * Cancels the previous unblock request. + */ +gboolean +gst_vaapi_window_unblock_cancel (GstVaapiWindow * window) +{ + const GstVaapiWindowClass *klass; + + g_return_val_if_fail (GST_VAAPI_IS_WINDOW (window), FALSE); + + klass = GST_VAAPI_WINDOW_GET_CLASS (window); + + if (klass->unblock_cancel) + return klass->unblock_cancel (window); + + return TRUE; +} diff --git a/gst-libs/gst/vaapi/gstvaapiwindow.h b/gst-libs/gst/vaapi/gstvaapiwindow.h new file mode 100644 index 0000000000..c1628f79c8 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow.h @@ -0,0 +1,110 @@ +/* + * gstvaapiwindow.h - VA window abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_WINDOW_H +#define GST_VAAPI_WINDOW_H + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_WINDOW (gst_vaapi_window_get_type ()) +#define GST_VAAPI_WINDOW(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_WINDOW, GstVaapiWindow)) +#define GST_VAAPI_IS_WINDOW(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_WINDOW)) + +typedef struct _GstVaapiWindow GstVaapiWindow; +typedef struct _GstVaapiWindowClass GstVaapiWindowClass; + +GType +gst_vaapi_window_get_type (void) G_GNUC_CONST; + +GstVaapiWindow * +gst_vaapi_window_new (GstVaapiDisplay * display, guint width, guint height); + +void +gst_vaapi_window_replace (GstVaapiWindow ** old_window_ptr, + GstVaapiWindow * new_window); + +GstVaapiDisplay * +gst_vaapi_window_get_display (GstVaapiWindow * window); + +void +gst_vaapi_window_show (GstVaapiWindow * window); + +void +gst_vaapi_window_hide (GstVaapiWindow * window); + +gboolean +gst_vaapi_window_get_fullscreen (GstVaapiWindow * window); + +void +gst_vaapi_window_set_fullscreen (GstVaapiWindow * window, gboolean fullscreen); + +guint +gst_vaapi_window_get_width (GstVaapiWindow * window); + +guint +gst_vaapi_window_get_height (GstVaapiWindow * window); + +void +gst_vaapi_window_get_size (GstVaapiWindow * window, guint * width_ptr, + guint * height_ptr); + +void +gst_vaapi_window_set_width (GstVaapiWindow * window, guint width); + +void +gst_vaapi_window_set_height (GstVaapiWindow * window, guint height); + +void +gst_vaapi_window_set_size (GstVaapiWindow * window, guint width, guint height); + +void +gst_vaapi_window_set_render_rectangle (GstVaapiWindow * window, gint x, gint y, + gint width, gint height); + +gboolean +gst_vaapi_window_put_surface (GstVaapiWindow * window, + GstVaapiSurface * surface, const GstVaapiRectangle * src_rect, + const GstVaapiRectangle * dst_rect, guint flags); + +void +gst_vaapi_window_reconfigure (GstVaapiWindow * window); + +gboolean +gst_vaapi_window_unblock (GstVaapiWindow * window); + +gboolean +gst_vaapi_window_unblock_cancel (GstVaapiWindow * window); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiWindow, gst_object_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_WINDOW_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_drm.c b/gst-libs/gst/vaapi/gstvaapiwindow_drm.c new file mode 100644 index 0000000000..54735b4db8 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow_drm.c @@ -0,0 +1,138 @@ +/* + * gstvaapiwindow_drm.c - VA/DRM window abstraction + * + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapiwindow_drm + * @short_description: VA/DRM dummy window abstraction + */ + +#include "sysdeps.h" +#include "gstvaapiwindow_drm.h" +#include "gstvaapiwindow_priv.h" +#include "gstvaapidisplay_drm_priv.h" + +GST_DEBUG_CATEGORY_EXTERN (gst_debug_vaapi_window); +#define GST_CAT_DEFAULT gst_debug_vaapi_window + +typedef struct _GstVaapiWindowDRMClass GstVaapiWindowDRMClass; + +/** + * GstVaapiWindowDRM: + * + * A dummy DRM window abstraction. + */ +struct _GstVaapiWindowDRM +{ + /*< private > */ + GstVaapiWindow parent_instance; +}; + +/** + * GstVaapiWindowDRMClass: + * + * A dummy DRM window abstraction class. + */ +struct _GstVaapiWindowDRMClass +{ + /*< private > */ + GstVaapiWindowClass parent_instance; +}; + +G_DEFINE_TYPE (GstVaapiWindowDRM, gst_vaapi_window_drm, GST_TYPE_VAAPI_WINDOW); + +static gboolean +gst_vaapi_window_drm_show (GstVaapiWindow * window) +{ + return TRUE; +} + +static gboolean +gst_vaapi_window_drm_hide (GstVaapiWindow * window) +{ + return TRUE; +} + +static gboolean +gst_vaapi_window_drm_create (GstVaapiWindow * window, + guint * width, guint * height) +{ + return TRUE; +} + +static gboolean +gst_vaapi_window_drm_resize (GstVaapiWindow * window, guint width, guint height) +{ + return TRUE; +} + +static gboolean +gst_vaapi_window_drm_render (GstVaapiWindow * window, + GstVaapiSurface * surface, + const GstVaapiRectangle * src_rect, + const GstVaapiRectangle * dst_rect, guint flags) +{ + return TRUE; +} + +static void +gst_vaapi_window_drm_class_init (GstVaapiWindowDRMClass * klass) +{ + GstVaapiWindowClass *const window_class = GST_VAAPI_WINDOW_CLASS (klass); + + window_class->create = gst_vaapi_window_drm_create; + window_class->show = gst_vaapi_window_drm_show; + window_class->hide = gst_vaapi_window_drm_hide; + window_class->resize = gst_vaapi_window_drm_resize; + window_class->render = gst_vaapi_window_drm_render; +} + +static void +gst_vaapi_window_drm_init (GstVaapiWindowDRM * window) +{ +} + +/** + * gst_vaapi_window_drm_new: + * @display: a #GstVaapiDisplay + * @width: the requested window width, in pixels (unused) + * @height: the requested windo height, in pixels (unused) + * + * Creates a dummy window. The window will be attached to the @display. + * All rendering functions will return success since VA/DRM is a + * renderless API. + * + * Note: this dummy window object is only necessary to fulfill cases + * where the client application wants to automatically determine the + * best display to use for the current system. As such, it provides + * utility functions with the same API (function arguments) to help + * implement uniform function tables. + * + * Return value: the newly allocated #GstVaapiWindow object + */ +GstVaapiWindow * +gst_vaapi_window_drm_new (GstVaapiDisplay * display, guint width, guint height) +{ + g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_DRM (display), NULL); + + return gst_vaapi_window_new_internal (GST_TYPE_VAAPI_WINDOW_DRM, display, + GST_VAAPI_ID_INVALID, width, height); +} diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_drm.h b/gst-libs/gst/vaapi/gstvaapiwindow_drm.h new file mode 100644 index 0000000000..48accb8634 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow_drm.h @@ -0,0 +1,50 @@ +/* + * gstvaapiwindow_drm.h - VA/DRM window abstraction + * + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_WINDOW_DRM_H +#define GST_VAAPI_WINDOW_DRM_H + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_WINDOW_DRM (gst_vaapi_window_drm_get_type ()) +#define GST_VAAPI_WINDOW_DRM(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_WINDOW_DRM, GstVaapiWindowDRM)) +#define GST_VAAPI_IS_WINDOW_DRM(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_WINDOW_DRM)) + +typedef struct _GstVaapiWindowDRM GstVaapiWindowDRM; + +GType +gst_vaapi_window_drm_get_type (void) G_GNUC_CONST; + +GstVaapiWindow * +gst_vaapi_window_drm_new (GstVaapiDisplay * display, guint width, guint height); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiWindowDRM, gst_object_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_WINDOW_DRM_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_egl.c b/gst-libs/gst/vaapi/gstvaapiwindow_egl.c new file mode 100644 index 0000000000..46bb2f9428 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow_egl.c @@ -0,0 +1,553 @@ +/* + * gstvaapiwindow_egl.c - VA/EGL window abstraction + * + * Copyright (C) 2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapiwindow_egl + * @short_description: VA/EGL window abstraction + */ + +#include "sysdeps.h" +#include "gstvaapiwindow_egl.h" +#include "gstvaapiwindow_priv.h" +#include "gstvaapitexture_egl.h" +#include "gstvaapitexture_priv.h" +#include "gstvaapidisplay_egl_priv.h" + +GST_DEBUG_CATEGORY_EXTERN (gst_debug_vaapi_window); +#define GST_CAT_DEFAULT gst_debug_vaapi_window + +#define GST_VAAPI_WINDOW_EGL_CAST(obj) \ + ((GstVaapiWindowEGL *)(obj)) + +#define GST_VAAPI_WINDOW_EGL_GET_PROXY(obj) \ + (GST_VAAPI_WINDOW_EGL_CAST(obj)->window) + +#define GST_VAAPI_WINDOW_EGL_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_WINDOW_EGL, GstVaapiWindowEGLClass)) + +typedef struct _GstVaapiWindowEGLClass GstVaapiWindowEGLClass; + +enum +{ + RENDER_PROGRAM_VAR_PROJ = 0, + RENDER_PROGRAM_VAR_TEX0, + RENDER_PROGRAM_VAR_TEX1, + RENDER_PROGRAM_VAR_TEX2, +}; + +struct _GstVaapiWindowEGL +{ + GstVaapiWindow parent_instance; + + GstVaapiWindow *window; + GstVaapiTexture *texture; + EglWindow *egl_window; + EglVTable *egl_vtable; + EglProgram *render_program; + gfloat render_projection[16]; +}; + +struct _GstVaapiWindowEGLClass +{ + GstVaapiWindowClass parent_class; +}; + +typedef struct +{ + GstVaapiWindowEGL *window; + guint width; + guint height; + EglContext *egl_context; + gboolean success; /* result */ +} CreateObjectsArgs; + +typedef struct +{ + GstVaapiWindowEGL *window; + guint width; + guint height; + gboolean success; /* result */ +} ResizeWindowArgs; + +typedef struct +{ + GstVaapiWindowEGL *window; + GstVaapiSurface *surface; + const GstVaapiRectangle *src_rect; + const GstVaapiRectangle *dst_rect; + guint flags; + gboolean success; /* result */ +} UploadSurfaceArgs; + +/* *IDENT-OFF* */ +static const gchar *vert_shader_text = + "#ifdef GL_ES \n" + "precision mediump float; \n" + "#endif \n" + "uniform mat4 proj; \n" + "attribute vec2 position; \n" + "attribute vec2 texcoord; \n" + "varying vec2 v_texcoord; \n" + "void main () \n" + "{ \n" + " gl_Position = proj * vec4 (position, 0.0, 1.0); \n" + " v_texcoord = texcoord; \n" + "} \n"; + +static const gchar *frag_shader_text_rgba = + "#ifdef GL_ES \n" + "precision mediump float; \n" + "#endif \n" + "uniform sampler2D tex0; \n" + "varying vec2 v_texcoord; \n" + "void main () \n" + "{ \n" + " gl_FragColor = texture2D (tex0, v_texcoord); \n" + "} \n"; +/* *IDENT-ON* */ + +G_DEFINE_TYPE (GstVaapiWindowEGL, gst_vaapi_window_egl, GST_TYPE_VAAPI_WINDOW); + +static gboolean +ensure_texture (GstVaapiWindowEGL * window, guint width, guint height) +{ + GstVaapiTexture *texture; + + if (window->texture && + GST_VAAPI_TEXTURE_WIDTH (window->texture) == width && + GST_VAAPI_TEXTURE_HEIGHT (window->texture) == height) + return TRUE; + + texture = gst_vaapi_texture_egl_new (GST_VAAPI_WINDOW_DISPLAY (window), + GL_TEXTURE_2D, GL_RGBA, width, height); + gst_mini_object_replace ((GstMiniObject **) & window->texture, + (GstMiniObject *) texture); + gst_mini_object_replace ((GstMiniObject **) & texture, NULL); + return window->texture != NULL; +} + +static gboolean +ensure_shaders (GstVaapiWindowEGL * window) +{ + EglVTable *const vtable = window->egl_vtable; + EglProgram *program; + GLuint prog_id; + + g_return_val_if_fail (window->texture != NULL, FALSE); + g_return_val_if_fail (GST_VAAPI_TEXTURE_FORMAT (window->texture) == GL_RGBA, + FALSE); + + if (window->render_program) + return TRUE; + + program = egl_program_new (window->egl_window->context, + frag_shader_text_rgba, vert_shader_text); + if (!program) + return FALSE; + + prog_id = program->base.handle.u; + + vtable->glUseProgram (prog_id); + program->uniforms[RENDER_PROGRAM_VAR_PROJ] = + vtable->glGetUniformLocation (prog_id, "proj"); + program->uniforms[RENDER_PROGRAM_VAR_TEX0] = + vtable->glGetUniformLocation (prog_id, "tex0"); + program->uniforms[RENDER_PROGRAM_VAR_TEX1] = + vtable->glGetUniformLocation (prog_id, "tex1"); + program->uniforms[RENDER_PROGRAM_VAR_TEX2] = + vtable->glGetUniformLocation (prog_id, "tex2"); + vtable->glUseProgram (0); + + egl_matrix_set_identity (window->render_projection); + + egl_object_replace (&window->render_program, program); + egl_object_replace (&program, NULL); + return TRUE; +} + +static gboolean +do_create_objects_unlocked (GstVaapiWindowEGL * window, guint width, + guint height, EglContext * egl_context) +{ + EglWindow *egl_window; + EglVTable *egl_vtable; + + egl_window = egl_window_new (egl_context, + GSIZE_TO_POINTER (GST_VAAPI_WINDOW_ID (GST_VAAPI_WINDOW_EGL_GET_PROXY + (window)))); + if (!egl_window) + return FALSE; + window->egl_window = egl_window; + + egl_vtable = egl_context_get_vtable (egl_window->context, TRUE); + if (!egl_vtable) + return FALSE; + window->egl_vtable = egl_object_ref (egl_vtable); + return TRUE; +} + +static void +do_create_objects (CreateObjectsArgs * args) +{ + GstVaapiWindowEGL *const window = args->window; + EglContextState old_cs; + + args->success = FALSE; + + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + if (egl_context_set_current (args->egl_context, TRUE, &old_cs)) { + args->success = do_create_objects_unlocked (window, args->width, + args->height, args->egl_context); + egl_context_set_current (args->egl_context, FALSE, &old_cs); + } + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); +} + +static gboolean +gst_vaapi_window_egl_create (GstVaapiWindow * window, guint * width, + guint * height) +{ + GstVaapiDisplayEGL *const display = + GST_VAAPI_DISPLAY_EGL (GST_VAAPI_WINDOW_DISPLAY (window)); + const GstVaapiDisplayClass *const native_dpy_class = + GST_VAAPI_DISPLAY_GET_CLASS (display->display); + CreateObjectsArgs args; + + g_return_val_if_fail (native_dpy_class != NULL, FALSE); + + GST_VAAPI_WINDOW_EGL_GET_PROXY (window) = + native_dpy_class->create_window (GST_VAAPI_DISPLAY (display->display), + GST_VAAPI_ID_INVALID, *width, *height); + if (!GST_VAAPI_WINDOW_EGL_GET_PROXY (window)) + return FALSE; + + gst_vaapi_window_get_size (GST_VAAPI_WINDOW_EGL_GET_PROXY (window), width, + height); + + args.window = GST_VAAPI_WINDOW_EGL_CAST (window); + args.width = *width; + args.height = *height; + args.egl_context = GST_VAAPI_DISPLAY_EGL_CONTEXT (display); + return egl_context_run (args.egl_context, + (EglContextRunFunc) do_create_objects, &args) && args.success; +} + +static void +do_destroy_objects_unlocked (GstVaapiWindowEGL * window) +{ + egl_object_replace (&window->render_program, NULL); + egl_object_replace (&window->egl_vtable, NULL); + egl_object_replace (&window->egl_window, NULL); +} + +static void +do_destroy_objects (GstVaapiWindowEGL * window) +{ + EglContext *const egl_context = + GST_VAAPI_DISPLAY_EGL_CONTEXT (GST_VAAPI_WINDOW_DISPLAY (window)); + EglContextState old_cs; + + if (!window->egl_window) + return; + + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + if (egl_context_set_current (egl_context, TRUE, &old_cs)) { + do_destroy_objects_unlocked (window); + egl_context_set_current (egl_context, FALSE, &old_cs); + } + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); +} + +static void +gst_vaapi_window_egl_finalize (GObject * object) +{ + GstVaapiWindowEGL *const window = GST_VAAPI_WINDOW_EGL (object); + + if (window->egl_window) { + egl_context_run (window->egl_window->context, + (EglContextRunFunc) do_destroy_objects, window); + } + + gst_vaapi_window_replace (&window->window, NULL); + gst_mini_object_replace ((GstMiniObject **) & window->texture, NULL); + + G_OBJECT_CLASS (gst_vaapi_window_egl_parent_class)->finalize (object); +} + +static gboolean +gst_vaapi_window_egl_show (GstVaapiWindow * window) +{ + const GstVaapiWindowClass *const klass = + GST_VAAPI_WINDOW_GET_CLASS (GST_VAAPI_WINDOW_EGL_GET_PROXY (window)); + + g_return_val_if_fail (klass->show, FALSE); + + return klass->show (GST_VAAPI_WINDOW_EGL_GET_PROXY (window)); +} + +static gboolean +gst_vaapi_window_egl_hide (GstVaapiWindow * window) +{ + const GstVaapiWindowClass *const klass = + GST_VAAPI_WINDOW_GET_CLASS (GST_VAAPI_WINDOW_EGL_GET_PROXY (window)); + + g_return_val_if_fail (klass->hide, FALSE); + + return klass->hide (GST_VAAPI_WINDOW_EGL_GET_PROXY (window)); +} + +static gboolean +gst_vaapi_window_egl_get_geometry (GstVaapiWindow * window, gint * x_ptr, + gint * y_ptr, guint * width_ptr, guint * height_ptr) +{ + const GstVaapiWindowClass *const klass = + GST_VAAPI_WINDOW_GET_CLASS (GST_VAAPI_WINDOW_EGL_GET_PROXY (window)); + + return klass->get_geometry ? + klass->get_geometry (GST_VAAPI_WINDOW_EGL_GET_PROXY (window), x_ptr, + y_ptr, width_ptr, height_ptr) : FALSE; +} + +static gboolean +gst_vaapi_window_egl_set_fullscreen (GstVaapiWindow * window, + gboolean fullscreen) +{ + const GstVaapiWindowClass *const klass = + GST_VAAPI_WINDOW_GET_CLASS (GST_VAAPI_WINDOW_EGL_GET_PROXY (window)); + + return klass->set_fullscreen ? + klass->set_fullscreen (GST_VAAPI_WINDOW_EGL_GET_PROXY (window), + fullscreen) : FALSE; +} + +static gboolean +do_resize_window_unlocked (GstVaapiWindowEGL * window, guint width, + guint height) +{ + EglVTable *const vtable = window->egl_vtable; + + vtable->glViewport (0, 0, width, height); + vtable->glClearColor (0.0f, 0.0f, 0.0f, 1.0f); + vtable->glClear (GL_COLOR_BUFFER_BIT); + return TRUE; +} + +static void +do_resize_window (ResizeWindowArgs * args) +{ + GstVaapiWindowEGL *const window = args->window; + EglContextState old_cs; + + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + if (egl_context_set_current (window->egl_window->context, TRUE, &old_cs)) { + args->success = do_resize_window_unlocked (window, args->width, + args->height); + egl_context_set_current (window->egl_window->context, FALSE, &old_cs); + } + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); +} + +static gboolean +gst_vaapi_window_egl_resize (GstVaapiWindow * window, guint width, guint height) +{ + GstVaapiWindowEGL *const win = GST_VAAPI_WINDOW_EGL_CAST (window); + const GstVaapiWindowClass *const klass = + GST_VAAPI_WINDOW_GET_CLASS (GST_VAAPI_WINDOW_EGL_GET_PROXY (window)); + ResizeWindowArgs args = { win, width, height }; + + g_return_val_if_fail (klass->resize, FALSE); + + if (!klass->resize (GST_VAAPI_WINDOW_EGL_GET_PROXY (window), width, height)) + return FALSE; + + return egl_context_run (win->egl_window->context, + (EglContextRunFunc) do_resize_window, &args) && args.success; +} + +static gboolean +do_render_texture (GstVaapiWindowEGL * window, const GstVaapiRectangle * rect) +{ + const GLuint tex_id = GST_VAAPI_TEXTURE_ID (window->texture); + EglVTable *const vtable = window->egl_vtable; + GLfloat x0, y0, x1, y1; + GLfloat texcoords[4][2]; + GLfloat positions[4][2]; + guint tex_width, tex_height; + + if (!ensure_shaders (window)) + return FALSE; + + tex_width = GST_VAAPI_TEXTURE_WIDTH (window->texture); + tex_height = GST_VAAPI_TEXTURE_HEIGHT (window->texture); + + // Source coords in VA surface + x0 = 0.0f; + y0 = 0.0f; + x1 = 1.0f; + y1 = 1.0f; + texcoords[0][0] = x0; + texcoords[0][1] = y1; + texcoords[1][0] = x1; + texcoords[1][1] = y1; + texcoords[2][0] = x1; + texcoords[2][1] = y0; + texcoords[3][0] = x0; + texcoords[3][1] = y0; + + // Target coords in EGL surface + x0 = 2.0f * ((GLfloat) rect->x / tex_width) - 1.0f; + y1 = -2.0f * ((GLfloat) rect->y / tex_height) + 1.0f; + x1 = 2.0f * ((GLfloat) (rect->x + rect->width) / tex_width) - 1.0f; + y0 = -2.0f * ((GLfloat) (rect->y + rect->height) / tex_height) + 1.0f; + positions[0][0] = x0; + positions[0][1] = y0; + positions[1][0] = x1; + positions[1][1] = y0; + positions[2][0] = x1; + positions[2][1] = y1; + positions[3][0] = x0; + positions[3][1] = y1; + + vtable->glClear (GL_COLOR_BUFFER_BIT); + + if (G_UNLIKELY (window->egl_window->context->config->gles_version == 1)) { + vtable->glBindTexture (GST_VAAPI_TEXTURE_TARGET (window->texture), tex_id); + vtable->glEnableClientState (GL_VERTEX_ARRAY); + vtable->glVertexPointer (2, GL_FLOAT, 0, positions); + vtable->glEnableClientState (GL_TEXTURE_COORD_ARRAY); + vtable->glTexCoordPointer (2, GL_FLOAT, 0, texcoords); + + vtable->glDrawArrays (GL_TRIANGLE_FAN, 0, 4); + + vtable->glDisableClientState (GL_VERTEX_ARRAY); + vtable->glDisableClientState (GL_TEXTURE_COORD_ARRAY); + } else { + EglProgram *const program = window->render_program; + + vtable->glUseProgram (program->base.handle.u); + vtable->glUniformMatrix4fv (program->uniforms[RENDER_PROGRAM_VAR_PROJ], + 1, GL_FALSE, window->render_projection); + vtable->glEnableVertexAttribArray (0); + vtable->glVertexAttribPointer (0, 2, GL_FLOAT, GL_FALSE, 0, positions); + vtable->glEnableVertexAttribArray (1); + vtable->glVertexAttribPointer (1, 2, GL_FLOAT, GL_FALSE, 0, texcoords); + + vtable->glBindTexture (GST_VAAPI_TEXTURE_TARGET (window->texture), tex_id); + vtable->glUniform1i (program->uniforms[RENDER_PROGRAM_VAR_TEX0], 0); + vtable->glDrawArrays (GL_TRIANGLE_FAN, 0, 4); + + vtable->glDisableVertexAttribArray (1); + vtable->glDisableVertexAttribArray (0); + vtable->glUseProgram (0); + } + + eglSwapBuffers (window->egl_window->context->display->base.handle.p, + window->egl_window->base.handle.p); + return TRUE; +} + +static gboolean +do_upload_surface_unlocked (GstVaapiWindowEGL * window, + GstVaapiSurface * surface, const GstVaapiRectangle * src_rect, + const GstVaapiRectangle * dst_rect, guint flags) +{ + if (!ensure_texture (window, dst_rect->width, dst_rect->height)) + return FALSE; + if (!gst_vaapi_texture_put_surface (window->texture, surface, src_rect, + flags)) + return FALSE; + if (!do_render_texture (window, dst_rect)) + return FALSE; + return TRUE; +} + +static void +do_upload_surface (UploadSurfaceArgs * args) +{ + GstVaapiWindowEGL *const window = args->window; + EglContextState old_cs; + + args->success = FALSE; + + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + if (egl_context_set_current (window->egl_window->context, TRUE, &old_cs)) { + args->success = do_upload_surface_unlocked (window, args->surface, + args->src_rect, args->dst_rect, args->flags); + egl_context_set_current (window->egl_window->context, FALSE, &old_cs); + } + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); +} + +static gboolean +gst_vaapi_window_egl_render (GstVaapiWindow * window, GstVaapiSurface * surface, + const GstVaapiRectangle * src_rect, const GstVaapiRectangle * dst_rect, + guint flags) +{ + GstVaapiWindowEGL *const win = GST_VAAPI_WINDOW_EGL_CAST (window); + UploadSurfaceArgs args = { win, surface, src_rect, dst_rect, flags }; + + return egl_context_run (win->egl_window->context, + (EglContextRunFunc) do_upload_surface, &args) && args.success; +} + +static void +gst_vaapi_window_egl_class_init (GstVaapiWindowEGLClass * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstVaapiWindowClass *const window_class = GST_VAAPI_WINDOW_CLASS (klass); + + object_class->finalize = gst_vaapi_window_egl_finalize; + + window_class->create = gst_vaapi_window_egl_create; + window_class->show = gst_vaapi_window_egl_show; + window_class->hide = gst_vaapi_window_egl_hide; + window_class->get_geometry = gst_vaapi_window_egl_get_geometry; + window_class->set_fullscreen = gst_vaapi_window_egl_set_fullscreen; + window_class->resize = gst_vaapi_window_egl_resize; + window_class->render = gst_vaapi_window_egl_render; +} + +static void +gst_vaapi_window_egl_init (GstVaapiWindowEGL * window) +{ +} + +/** + * gst_vaapi_window_egl_new: + * @display: a #GstVaapiDisplay + * @width: the requested window width, in pixels + * @height: the requested windo height, in pixels + * + * Creates a window with the specified @width and @height. The window + * will be attached to the @display and remains invisible to the user + * until gst_vaapi_window_show() is called. + * + * Return value: the newly allocated #GstVaapiWindow object + */ +GstVaapiWindow * +gst_vaapi_window_egl_new (GstVaapiDisplay * display, guint width, guint height) +{ + g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_EGL (display), NULL); + + return gst_vaapi_window_new_internal (GST_TYPE_VAAPI_WINDOW_EGL, display, + GST_VAAPI_ID_INVALID, width, height); +} diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_egl.h b/gst-libs/gst/vaapi/gstvaapiwindow_egl.h new file mode 100644 index 0000000000..ac6db5157a --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow_egl.h @@ -0,0 +1,50 @@ +/* + * gstvaapiwindow_egl.h - VA/EGL window abstraction + * + * Copyright (C) 2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_WINDOW_EGL_H +#define GST_VAAPI_WINDOW_EGL_H + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_WINDOW_EGL (gst_vaapi_window_egl_get_type ()) +#define GST_VAAPI_WINDOW_EGL(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_WINDOW_EGL, GstVaapiWindowEGL)) +#define GST_VAAPI_IS_WINDOW_EGL(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_WINDOW_EGL)) + +typedef struct _GstVaapiWindowEGL GstVaapiWindowEGL; + +GType +gst_vaapi_window_egl_get_type (void) G_GNUC_CONST; + +GstVaapiWindow * +gst_vaapi_window_egl_new (GstVaapiDisplay * display, guint width, guint height); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiWindowEGL, gst_object_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_WINDOW_EGL_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_glx.c b/gst-libs/gst/vaapi/gstvaapiwindow_glx.c new file mode 100644 index 0000000000..245235ef81 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow_glx.c @@ -0,0 +1,556 @@ +/* + * gstvaapiwindow_glx.c - VA/GLX window abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapiwindow_glx + * @short_description: VA/GLX window abstraction + */ + +#include "sysdeps.h" +#include "gstvaapiwindow_glx.h" +#include "gstvaapiwindow_x11_priv.h" +#include "gstvaapidisplay_x11.h" +#include "gstvaapidisplay_x11_priv.h" +#include "gstvaapidisplay_glx_priv.h" +#include "gstvaapiutils_x11.h" +#include "gstvaapiutils_glx.h" + +GST_DEBUG_CATEGORY_EXTERN (gst_debug_vaapi_window); +#define GST_CAT_DEFAULT gst_debug_vaapi_window + +#define GST_VAAPI_WINDOW_GLX_CAST(obj) ((GstVaapiWindowGLX *)(obj)) +#define GST_VAAPI_WINDOW_GLX_GET_PRIVATE(window) \ + gst_vaapi_window_glx_get_instance_private (GST_VAAPI_WINDOW_GLX_CAST (window)) + +#define GST_VAAPI_WINDOW_GLX_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_WINDOW_GLX, GstVaapiWindowGLXClass)) + +typedef struct _GstVaapiWindowGLXPrivate GstVaapiWindowGLXPrivate; +typedef struct _GstVaapiWindowGLXClass GstVaapiWindowGLXClass; + +struct _GstVaapiWindowGLXPrivate +{ + Colormap cmap; + GLContextState *gl_context; +}; + +/** + * GstVaapiWindowGLX: + * + * An X11 Window suitable for GLX rendering. + */ +struct _GstVaapiWindowGLX +{ + /*< private > */ + GstVaapiWindowX11 parent_instance; +}; + +/** + * GstVaapiWindowGLXClass: + * + * An X11 Window suitable for GLX rendering. + */ +struct _GstVaapiWindowGLXClass +{ + /*< private > */ + GstVaapiWindowX11Class parent_class; +}; + +G_DEFINE_TYPE_WITH_PRIVATE (GstVaapiWindowGLX, gst_vaapi_window_glx, + GST_TYPE_VAAPI_WINDOW_X11); + +/* Fill rectangle coords with capped bounds */ +static inline void +fill_rect (GstVaapiRectangle * dst_rect, + const GstVaapiRectangle * src_rect, guint width, guint height) +{ + if (src_rect) { + dst_rect->x = src_rect->x > 0 ? src_rect->x : 0; + dst_rect->y = src_rect->y > 0 ? src_rect->y : 0; + if (src_rect->x + src_rect->width < width) + dst_rect->width = src_rect->width; + else + dst_rect->width = width - dst_rect->x; + if (src_rect->y + src_rect->height < height) + dst_rect->height = src_rect->height; + else + dst_rect->height = height - dst_rect->y; + } else { + dst_rect->x = 0; + dst_rect->y = 0; + dst_rect->width = width; + dst_rect->height = height; + } +} + +static void +_gst_vaapi_window_glx_destroy_context (GstVaapiWindow * window) +{ + GstVaapiWindowGLXPrivate *const priv = + GST_VAAPI_WINDOW_GLX_GET_PRIVATE (window); + + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + if (priv->gl_context) { + gl_destroy_context (priv->gl_context); + priv->gl_context = NULL; + } + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); +} + +static gboolean +_gst_vaapi_window_glx_create_context (GstVaapiWindow * window, + GLXContext foreign_context) +{ + GstVaapiWindowGLXPrivate *const priv = + GST_VAAPI_WINDOW_GLX_GET_PRIVATE (window); + Display *const dpy = GST_VAAPI_WINDOW_NATIVE_DISPLAY (window); + GLContextState parent_cs; + + parent_cs.display = dpy; + parent_cs.window = None; + parent_cs.context = foreign_context; + + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + priv->gl_context = gl_create_context (dpy, DefaultScreen (dpy), &parent_cs); + if (!priv->gl_context) { + GST_DEBUG ("could not create GLX context"); + goto end; + } + + if (!glXIsDirect (dpy, priv->gl_context->context)) { + GST_DEBUG ("could not create a direct-rendering GLX context"); + goto out_destroy_context; + } + goto end; + +out_destroy_context: + gl_destroy_context (priv->gl_context); + priv->gl_context = NULL; +end: + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + return priv->gl_context != NULL; +} + +static gboolean +_gst_vaapi_window_glx_ensure_context (GstVaapiWindow * window, + GLXContext foreign_context) +{ + GstVaapiWindowGLXPrivate *const priv = + GST_VAAPI_WINDOW_GLX_GET_PRIVATE (window); + + if (priv->gl_context) { + if (!foreign_context || foreign_context == priv->gl_context->context) + return TRUE; + _gst_vaapi_window_glx_destroy_context (window); + } + return _gst_vaapi_window_glx_create_context (window, foreign_context); +} + +static gboolean +gst_vaapi_window_glx_ensure_context (GstVaapiWindow * window, + GLXContext foreign_context) +{ + GstVaapiWindowGLXPrivate *const priv = + GST_VAAPI_WINDOW_GLX_GET_PRIVATE (window); + GLContextState old_cs; + guint width, height; + + if (!_gst_vaapi_window_glx_ensure_context (window, foreign_context)) + return FALSE; + + priv->gl_context->window = GST_VAAPI_WINDOW_ID (window); + if (!gl_set_current_context (priv->gl_context, &old_cs)) { + GST_DEBUG ("could not make newly created GLX context current"); + return FALSE; + } + + glDisable (GL_DEPTH_TEST); + glDepthMask (GL_FALSE); + glDisable (GL_CULL_FACE); + glDrawBuffer (GL_BACK); + glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + gst_vaapi_window_get_size (window, &width, &height); + gl_resize (width, height); + + gl_set_bgcolor (0); + glClear (GL_COLOR_BUFFER_BIT); + gl_set_current_context (&old_cs, NULL); + return TRUE; +} + +static guintptr +gst_vaapi_window_glx_get_visual_id (GstVaapiWindow * window) +{ + GstVaapiWindowGLXPrivate *const priv = + GST_VAAPI_WINDOW_GLX_GET_PRIVATE (window); + + if (!_gst_vaapi_window_glx_ensure_context (window, NULL)) + return 0; + return priv->gl_context->visual->visualid; +} + +static void +gst_vaapi_window_glx_destroy_colormap (GstVaapiWindow * window) +{ + GstVaapiWindowGLXPrivate *const priv = + GST_VAAPI_WINDOW_GLX_GET_PRIVATE (window); + Display *const dpy = GST_VAAPI_WINDOW_NATIVE_DISPLAY (window); + + if (priv->cmap) { + if (!window->use_foreign_window) { + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + XFreeColormap (dpy, priv->cmap); + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + } + priv->cmap = None; + } +} + +static Colormap +gst_vaapi_window_glx_create_colormap (GstVaapiWindow * window) +{ + GstVaapiWindowGLXPrivate *const priv = + GST_VAAPI_WINDOW_GLX_GET_PRIVATE (window); + Display *const dpy = GST_VAAPI_WINDOW_NATIVE_DISPLAY (window); + XWindowAttributes wattr; + gboolean success = FALSE; + + if (!priv->cmap) { + if (!window->use_foreign_window) { + if (!_gst_vaapi_window_glx_ensure_context (window, NULL)) + return None; + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + x11_trap_errors (); + /* XXX: add a GstVaapiDisplayX11:x11-screen property? */ + priv->cmap = XCreateColormap (dpy, RootWindow (dpy, DefaultScreen (dpy)), + priv->gl_context->visual->visual, AllocNone); + success = x11_untrap_errors () == 0; + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + } else { + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + x11_trap_errors (); + XGetWindowAttributes (dpy, GST_VAAPI_WINDOW_ID (window), &wattr); + priv->cmap = wattr.colormap; + success = x11_untrap_errors () == 0; + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + } + if (!success) + return None; + } + return priv->cmap; +} + +static guintptr +gst_vaapi_window_glx_get_colormap (GstVaapiWindow * window) +{ + return GPOINTER_TO_SIZE (gst_vaapi_window_glx_create_colormap (window)); +} + +static gboolean +gst_vaapi_window_glx_resize (GstVaapiWindow * window, guint width, guint height) +{ + GstVaapiWindowGLXPrivate *const priv = + GST_VAAPI_WINDOW_GLX_GET_PRIVATE (window); + const GstVaapiWindowClass *const parent_klass = + GST_VAAPI_WINDOW_CLASS (gst_vaapi_window_glx_parent_class); + Display *const dpy = GST_VAAPI_WINDOW_NATIVE_DISPLAY (window); + GLContextState old_cs; + + if (!parent_klass->resize (window, width, height)) + return FALSE; + + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + XSync (dpy, False); /* make sure resize completed */ + if (gl_set_current_context (priv->gl_context, &old_cs)) { + gl_resize (width, height); + gl_set_current_context (&old_cs, NULL); + } + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + return TRUE; +} + +static void +gst_vaapi_window_glx_finalize (GObject * object) +{ + GstVaapiWindow *const window = GST_VAAPI_WINDOW (object); + + _gst_vaapi_window_glx_destroy_context (window); + gst_vaapi_window_glx_destroy_colormap (window); + + G_OBJECT_CLASS (gst_vaapi_window_glx_parent_class)->finalize (object); +} + +static void +gst_vaapi_window_glx_class_init (GstVaapiWindowGLXClass * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstVaapiWindowClass *const window_class = GST_VAAPI_WINDOW_CLASS (klass); + + object_class->finalize = gst_vaapi_window_glx_finalize; + + window_class->resize = gst_vaapi_window_glx_resize; + window_class->get_visual_id = gst_vaapi_window_glx_get_visual_id; + window_class->get_colormap = gst_vaapi_window_glx_get_colormap; +} + +static void +gst_vaapi_window_glx_init (GstVaapiWindowGLX * window) +{ +} + +/** + * gst_vaapi_window_glx_new: + * @display: a #GstVaapiDisplay + * @width: the requested window width, in pixels + * @height: the requested windo height, in pixels + * + * Creates a window with the specified @width and @height. The window + * will be attached to the @display and remains invisible to the user + * until gst_vaapi_window_show() is called. + * + * Return value: the newly allocated #GstVaapiWindow object + */ +GstVaapiWindow * +gst_vaapi_window_glx_new (GstVaapiDisplay * display, guint width, guint height) +{ + GstVaapiWindow *window; + + g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_GLX (display), NULL); + + window = gst_vaapi_window_new_internal (GST_TYPE_VAAPI_WINDOW_GLX, display, + GST_VAAPI_ID_INVALID, width, height); + if (!window) + return NULL; + + if (!gst_vaapi_window_glx_ensure_context (window, NULL)) + goto error; + return window; + + /* ERRORS */ +error: + { + gst_object_unref (window); + return NULL; + } +} + +/** + * gst_vaapi_window_glx_new_with_xid: + * @display: a #GstVaapiDisplay + * @xid: an X11 Window id + * + * Creates a #GstVaapiWindow using the X11 Window @xid. The caller + * still owns the window and must call XDestroyWindow() when all + * #GstVaapiWindow references are released. Doing so too early can + * yield undefined behaviour. + * + * Return value: the newly allocated #GstVaapiWindow object + */ +GstVaapiWindow * +gst_vaapi_window_glx_new_with_xid (GstVaapiDisplay * display, Window xid) +{ + GstVaapiWindow *window; + + g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_GLX (display), NULL); + g_return_val_if_fail (xid != None, NULL); + + window = gst_vaapi_window_new_internal (GST_TYPE_VAAPI_WINDOW_GLX, display, + xid, 0, 0); + if (!window) + return NULL; + + if (!gst_vaapi_window_glx_ensure_context (window, NULL)) + goto error; + return window; + + /* ERRORS */ +error: + { + gst_object_unref (window); + return NULL; + } +} + +/** + * gst_vaapi_window_glx_get_context: + * @window: a #GstVaapiWindowGLX + * + * Returns the #GLXContext bound to the @window. + * + * Return value: the #GLXContext bound to the @window + */ +GLXContext +gst_vaapi_window_glx_get_context (GstVaapiWindowGLX * window) +{ + GstVaapiWindowGLXPrivate *priv; + + g_return_val_if_fail (GST_VAAPI_IS_WINDOW_GLX (window), NULL); + + priv = GST_VAAPI_WINDOW_GLX_GET_PRIVATE (window); + return priv->gl_context->context; +} + +/** + * gst_vaapi_window_glx_set_context: + * @window: a #GstVaapiWindowGLX + * @ctx: a GLX context + * + * Binds GLX context @ctx to @window. If @ctx is non %NULL, the caller + * is responsible to making sure it has compatible visual with that of + * the underlying X window. If @ctx is %NULL, a new context is created + * and the @window owns it. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_window_glx_set_context (GstVaapiWindowGLX * window, GLXContext ctx) +{ + g_return_val_if_fail (GST_VAAPI_IS_WINDOW_GLX (window), FALSE); + + return gst_vaapi_window_glx_ensure_context (GST_VAAPI_WINDOW (window), ctx); +} + +/** + * gst_vaapi_window_glx_make_current: + * @window: a #GstVaapiWindowGLX + * + * Makes the @window GLX context the current GLX rendering context of + * the calling thread, replacing the previously current context if + * there was one. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_window_glx_make_current (GstVaapiWindowGLX * window) +{ + gboolean success; + GstVaapiWindowGLXPrivate *priv; + + g_return_val_if_fail (GST_VAAPI_IS_WINDOW_GLX (window), FALSE); + + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + priv = GST_VAAPI_WINDOW_GLX_GET_PRIVATE (window); + success = gl_set_current_context (priv->gl_context, NULL); + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + return success; +} + +/** + * gst_vaapi_window_glx_swap_buffers: + * @window: a #GstVaapiWindowGLX + * + * Promotes the contents of the back buffer of @window to become the + * contents of the front buffer of @window. This simply is wrapper + * around glXSwapBuffers(). + */ +void +gst_vaapi_window_glx_swap_buffers (GstVaapiWindowGLX * window) +{ + GstVaapiWindowGLXPrivate *priv; + + g_return_if_fail (GST_VAAPI_IS_WINDOW_GLX (window)); + + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + priv = GST_VAAPI_WINDOW_GLX_GET_PRIVATE (window); + gl_swap_buffers (priv->gl_context); + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); +} + +/** + * gst_vaapi_window_glx_put_texture: + * @window: a #GstVaapiWindowGLX + * @texture: a #GstVaapiTexture + * @src_rect: the sub-rectangle of the source texture to + * extract and process. If %NULL, the entire texture will be used. + * @dst_rect: the sub-rectangle of the destination + * window into which the texture is rendered. If %NULL, the entire + * window will be used. + * + * Renders the @texture region specified by @src_rect into the @window + * region specified by @dst_rect. + * + * NOTE: only GL_TEXTURE_2D textures are supported at this time. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_window_glx_put_texture (GstVaapiWindowGLX * window, + GstVaapiTexture * texture, + const GstVaapiRectangle * src_rect, const GstVaapiRectangle * dst_rect) +{ + GstVaapiRectangle tmp_src_rect, tmp_dst_rect; + GLTextureState ts; + GLenum tex_target; + GLuint tex_id; + guint tex_width, tex_height; + guint win_width, win_height; + + g_return_val_if_fail (GST_VAAPI_IS_WINDOW_GLX (window), FALSE); + g_return_val_if_fail (texture != NULL, FALSE); + + gst_vaapi_texture_get_size (texture, &tex_width, &tex_height); + fill_rect (&tmp_src_rect, src_rect, tex_width, tex_height); + src_rect = &tmp_src_rect; + + gst_vaapi_window_get_size (GST_VAAPI_WINDOW (window), &win_width, + &win_height); + fill_rect (&tmp_dst_rect, dst_rect, win_width, win_height); + dst_rect = &tmp_dst_rect; + + /* XXX: only GL_TEXTURE_2D textures are supported at this time */ + tex_target = gst_vaapi_texture_get_target (texture); + if (tex_target != GL_TEXTURE_2D) + return FALSE; + + tex_id = gst_vaapi_texture_get_id (texture); + if (!gl_bind_texture (&ts, tex_target, tex_id)) + return FALSE; + glColor4f (1.0f, 1.0f, 1.0f, 1.0f); + glPushMatrix (); + glTranslatef ((GLfloat) dst_rect->x, (GLfloat) dst_rect->y, 0.0f); + glBegin (GL_QUADS); + { + const float tx1 = (float) src_rect->x / tex_width; + const float tx2 = (float) (src_rect->x + src_rect->width) / tex_width; + const float ty1 = (float) src_rect->y / tex_height; + const float ty2 = (float) (src_rect->y + src_rect->height) / tex_height; + const guint w = dst_rect->width; + const guint h = dst_rect->height; + glTexCoord2f (tx1, ty1); + glVertex2i (0, 0); + glTexCoord2f (tx1, ty2); + glVertex2i (0, h); + glTexCoord2f (tx2, ty2); + glVertex2i (w, h); + glTexCoord2f (tx2, ty1); + glVertex2i (w, 0); + } + glEnd (); + glPopMatrix (); + gl_unbind_texture (&ts); + return TRUE; +} diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_glx.h b/gst-libs/gst/vaapi/gstvaapiwindow_glx.h new file mode 100644 index 0000000000..d3ff9a4772 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow_glx.h @@ -0,0 +1,75 @@ +/* + * gstvaapiwindow_glx.h - VA/GLX window abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_WINDOW_GLX_H +#define GST_VAAPI_WINDOW_GLX_H + +#include +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_WINDOW_GLX (gst_vaapi_window_glx_get_type ()) +#define GST_VAAPI_WINDOW_GLX(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_WINDOW_GLX, GstVaapiWindowGLX)) +#define GST_VAAPI_IS_WINDOW_GLX(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_WINDOW_GLX)) + +typedef struct _GstVaapiWindowGLX GstVaapiWindowGLX; + +GType +gst_vaapi_window_glx_get_type (void) G_GNUC_CONST; + +GstVaapiWindow * +gst_vaapi_window_glx_new (GstVaapiDisplay * display, guint width, guint height); + +GstVaapiWindow * +gst_vaapi_window_glx_new_with_xid (GstVaapiDisplay * display, Window xid); + +GLXContext +gst_vaapi_window_glx_get_context (GstVaapiWindowGLX * window); + +gboolean +gst_vaapi_window_glx_set_context (GstVaapiWindowGLX * window, GLXContext ctx); + +gboolean +gst_vaapi_window_glx_make_current (GstVaapiWindowGLX * window); + +void +gst_vaapi_window_glx_swap_buffers (GstVaapiWindowGLX * window); + +gboolean +gst_vaapi_window_glx_put_texture (GstVaapiWindowGLX * window, + GstVaapiTexture * texture, const GstVaapiRectangle * src_rect, + const GstVaapiRectangle * dst_rect); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiWindowGLX, gst_object_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_WINDOW_GLX_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_priv.h b/gst-libs/gst/vaapi/gstvaapiwindow_priv.h new file mode 100644 index 0000000000..168e002c0c --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow_priv.h @@ -0,0 +1,150 @@ +/* + * gstvaapiwindow_priv.h - VA window abstraction (private definitions) + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_WINDOW_PRIV_H +#define GST_VAAPI_WINDOW_PRIV_H + +#include "gstvaapidisplay.h" +#include "gstvaapifilter.h" +#include "gstvaapisurfacepool.h" + +G_BEGIN_DECLS + +#define GST_VAAPI_WINDOW_CAST(window) \ + ((GstVaapiWindow *)(window)) + +#define GST_VAAPI_WINDOW_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPI_WINDOW, GstVaapiWindowClass)) + +#define GST_VAAPI_IS_WINDOW_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPI_WINDOW)) + +#define GST_VAAPI_WINDOW_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_WINDOW, GstVaapiWindowClass)) + +#define GST_VAAPI_WINDOW_DISPLAY(window) \ + (GST_VAAPI_WINDOW_CAST (window)->display) + +#define GST_VAAPI_WINDOW_LOCK_DISPLAY(window) \ + GST_VAAPI_DISPLAY_LOCK (GST_VAAPI_WINDOW_DISPLAY (window)) + +#define GST_VAAPI_WINDOW_UNLOCK_DISPLAY(window) \ + GST_VAAPI_DISPLAY_UNLOCK (GST_VAAPI_WINDOW_DISPLAY (window)) + +#define GST_VAAPI_WINDOW_NATIVE_DISPLAY(window) \ + GST_VAAPI_DISPLAY_NATIVE (GST_VAAPI_WINDOW_DISPLAY (window)) + +#define GST_VAAPI_WINDOW_ID(window) \ + (GST_VAAPI_WINDOW_CAST (window)->native_id) + +#define GST_VAAPI_WINDOW_VADISPLAY(window) \ + GST_VAAPI_DISPLAY_VADISPLAY (GST_VAAPI_WINDOW_DISPLAY (window)) + +/** + * GstVaapiWindow: + * + * Base class for system-dependent windows. + */ +struct _GstVaapiWindow +{ + /*< private >*/ + GstObject parent_instance; + GstVaapiDisplay *display; + GstVaapiID native_id; + + /*< protected >*/ + guint width; + guint height; + guint display_width; + guint display_height; + guint use_foreign_window:1; + guint is_fullscreen:1; + guint check_geometry:1; + + /* for conversion */ + GstVideoFormat surface_pool_format; + guint surface_pool_flags; + GstVaapiVideoPool *surface_pool; + GstVaapiFilter *filter; + gboolean has_vpp; +}; + +/** + * GstVaapiWindowClass: + * @create: virtual function to create a window with width and height + * @show: virtual function to show (map) a window + * @hide: virtual function to hide (unmap) a window + * @get_geometry: virtual function to get the current window geometry + * @set_fullscreen: virtual function to change window fullscreen state + * @resize: virtual function to resize a window + * @render: virtual function to render a #GstVaapiSurface into a window + * @get_visual_id: virtual function to get the desired visual id used to + * create the window + * @get_colormap: virtual function to get the desired colormap used to + * create the window, or the currently allocated one + * @unblock: virtual function to unblock a rendering surface operation + * @unblock_cancel: virtual function to cancel the previous unblock + * request. + * + * Base class for system-dependent windows. + */ +struct _GstVaapiWindowClass +{ + /*< private >*/ + GstObjectClass parent_class; + + /*< protected >*/ + gboolean (*create) (GstVaapiWindow * window, guint * width, guint * height); + gboolean (*show) (GstVaapiWindow * window); + gboolean (*hide) (GstVaapiWindow * window); + gboolean (*get_geometry) (GstVaapiWindow * window, gint * px, gint * py, + guint * pwidth, guint * pheight); + gboolean (*set_fullscreen) (GstVaapiWindow * window, gboolean fullscreen); + gboolean (*resize) (GstVaapiWindow * window, guint width, guint height); + gboolean (*render) (GstVaapiWindow * window, GstVaapiSurface * surface, + const GstVaapiRectangle * src_rect, const GstVaapiRectangle * dst_rect, + guint flags); + guintptr (*get_visual_id) (GstVaapiWindow * window); + guintptr (*get_colormap) (GstVaapiWindow * window); + gboolean (*unblock) (GstVaapiWindow * window); + gboolean (*unblock_cancel) (GstVaapiWindow * window); + void (*set_render_rect) (GstVaapiWindow * window, gint x, gint y, gint width, gint height); +}; + +GstVaapiWindow * +gst_vaapi_window_new_internal (GType type, GstVaapiDisplay * display, + GstVaapiID handle, guint width, guint height); + +GstVaapiSurface * +gst_vaapi_window_vpp_convert_internal (GstVaapiWindow * window, + GstVaapiSurface * surface, const GstVaapiRectangle * src_rect, + const GstVaapiRectangle * dst_rect, guint flags); + +void +gst_vaapi_window_set_vpp_format_internal (GstVaapiWindow * window, + GstVideoFormat format, guint flags); + +G_END_DECLS + +#endif /* GST_VAAPI_WINDOW_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_wayland.c b/gst-libs/gst/vaapi/gstvaapiwindow_wayland.c new file mode 100644 index 0000000000..394a089bb5 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow_wayland.c @@ -0,0 +1,1092 @@ +/* + * gstvaapiwindow_wayland.c - VA/Wayland window abstraction + * + * Copyright (C) 2012-2013 Intel Corporation + * Author: Sreerenj Balachandran + * Author: Gwenole Beauchesne + * + * 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:gstvaapiwindow_wayland + * @short_description: VA/Wayland window abstraction + */ + +#include "sysdeps.h" +#include "gstvaapicompat.h" +#include "gstvaapisurface_priv.h" +#include "gstvaapiwindow_wayland.h" +#include "gstvaapiwindow_priv.h" +#include "gstvaapidisplay_wayland.h" +#include "gstvaapidisplay_wayland_priv.h" +#include "gstvaapiutils.h" +#include "gstvaapifilter.h" +#include "gstvaapisurfacepool.h" + +#include + +GST_DEBUG_CATEGORY_EXTERN (gst_debug_vaapi_window); +GST_DEBUG_CATEGORY_EXTERN (gst_debug_vaapi); +#define GST_CAT_DEFAULT gst_debug_vaapi_window + +#define GST_VAAPI_WINDOW_WAYLAND_CAST(obj) \ + ((GstVaapiWindowWayland *)(obj)) + +#define GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE(obj) \ + gst_vaapi_window_wayland_get_instance_private (GST_VAAPI_WINDOW_WAYLAND_CAST (obj)) + +#define GST_VAAPI_WINDOW_WAYLAND_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_WINDOW_WAYLAND, GstVaapiWindowWaylandClass)) + +typedef struct _GstVaapiWindowWaylandPrivate GstVaapiWindowWaylandPrivate; +typedef struct _GstVaapiWindowWaylandClass GstVaapiWindowWaylandClass; +typedef struct _FrameState FrameState; + +struct _FrameState +{ + GstVaapiWindow *window; + GstVaapiSurface *surface; + GstVaapiVideoPool *surface_pool; + struct wl_buffer *buffer; + struct wl_callback *callback; + gboolean done; +}; + +static FrameState * +frame_state_new (GstVaapiWindow * window) +{ + FrameState *frame; + + frame = g_slice_new (FrameState); + if (!frame) + return NULL; + + frame->window = window; + frame->surface = NULL; + frame->surface_pool = NULL; + frame->callback = NULL; + frame->done = FALSE; + return frame; +} + +struct _GstVaapiWindowWaylandPrivate +{ + struct xdg_surface *xdg_surface; + struct xdg_toplevel *xdg_toplevel; + struct wl_shell_surface *wl_shell_surface; + struct wl_surface *surface; + struct wl_subsurface *video_subsurface; + struct wl_event_queue *event_queue; + GList *frames; + FrameState *last_frame; + GstPoll *poll; + GstPollFD pollfd; + guint is_shown:1; + guint fullscreen_on_show:1; + guint sync_failed:1; + guint num_frames_pending; + gint configure_pending; + gboolean need_vpp; + gboolean dmabuf_broken; + GMutex opaque_mutex; + gint opaque_width, opaque_height; +}; + +/** + * GstVaapiWindowWayland: + * + * A Wayland window abstraction. + */ +struct _GstVaapiWindowWayland +{ + /*< private > */ + GstVaapiWindow parent_instance; +}; + +/** + * GstVaapiWindowWaylandClass: + * + * An Wayland Window wrapper class. + */ +struct _GstVaapiWindowWaylandClass +{ + /*< private > */ + GstVaapiWindowClass parent_class; +}; + +G_DEFINE_TYPE_WITH_PRIVATE (GstVaapiWindowWayland, gst_vaapi_window_wayland, + GST_TYPE_VAAPI_WINDOW); + +/* Object signals */ +enum +{ + SIZE_CHANGED, + N_SIGNALS +}; + +static guint signals[N_SIGNALS]; + +static void +frame_state_free (FrameState * frame) +{ + GstVaapiWindowWaylandPrivate *priv; + + if (!frame) + return; + + priv = GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (frame->window); + priv->frames = g_list_remove (priv->frames, frame); + + if (frame->surface) { + if (frame->surface_pool) + gst_vaapi_video_pool_put_object (frame->surface_pool, frame->surface); + frame->surface = NULL; + } + gst_vaapi_video_pool_replace (&frame->surface_pool, NULL); + + g_clear_pointer (&frame->callback, wl_callback_destroy); + wl_buffer_destroy (frame->buffer); + g_slice_free (FrameState, frame); +} + +static void +handle_xdg_toplevel_configure (void *data, struct xdg_toplevel *xdg_toplevel, + int32_t width, int32_t height, struct wl_array *states) +{ + GstVaapiWindow *window = GST_VAAPI_WINDOW (data); + const uint32_t *state; + + GST_DEBUG ("Got XDG-toplevel::reconfigure, [width x height] = [%d x %d]", + width, height); + + wl_array_for_each (state, states) { + switch (*state) { + case XDG_TOPLEVEL_STATE_FULLSCREEN: + case XDG_TOPLEVEL_STATE_MAXIMIZED: + case XDG_TOPLEVEL_STATE_RESIZING: + case XDG_TOPLEVEL_STATE_ACTIVATED: + break; + } + } + + if (width > 0 && height > 0) { + gst_vaapi_window_set_size (window, width, height); + g_signal_emit (window, signals[SIZE_CHANGED], 0, width, height); + } +} + +static void +handle_xdg_toplevel_close (void *data, struct xdg_toplevel *xdg_toplevel) +{ +} + +static const struct xdg_toplevel_listener xdg_toplevel_listener = { + handle_xdg_toplevel_configure, + handle_xdg_toplevel_close, +}; + +static gboolean gst_vaapi_window_wayland_sync (GstVaapiWindow * window); + +static gboolean +gst_vaapi_window_wayland_show (GstVaapiWindow * window) +{ + GstVaapiWindowWaylandPrivate *priv = + GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window); + + if (priv->xdg_surface == NULL) { + GST_FIXME ("GstVaapiWindowWayland::show() unimplemented for wl_shell"); + return TRUE; + } + + if (priv->xdg_toplevel != NULL) { + GST_DEBUG ("XDG toplevel already mapped"); + return TRUE; + } + + g_atomic_int_set (&priv->configure_pending, 1); + g_atomic_int_inc (&priv->num_frames_pending); + /* Create a toplevel window out of it */ + priv->xdg_toplevel = xdg_surface_get_toplevel (priv->xdg_surface); + g_return_val_if_fail (priv->xdg_toplevel, FALSE); + xdg_toplevel_set_title (priv->xdg_toplevel, "VA-API Wayland window"); + wl_proxy_set_queue ((struct wl_proxy *) priv->xdg_toplevel, + priv->event_queue); + + xdg_toplevel_add_listener (priv->xdg_toplevel, &xdg_toplevel_listener, + window); + + /* Commit the xdg_surface state as top-level window */ + wl_surface_commit (priv->surface); + + return gst_vaapi_window_wayland_sync (window); +} + +static gboolean +gst_vaapi_window_wayland_hide (GstVaapiWindow * window) +{ + GstVaapiWindowWaylandPrivate *priv = + GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window); + + if (priv->xdg_surface == NULL) { + GST_FIXME ("GstVaapiWindowWayland::hide() unimplemented for wl_shell"); + return TRUE; + } + + if (priv->xdg_toplevel != NULL) { + g_clear_pointer (&priv->xdg_toplevel, xdg_toplevel_destroy); + wl_surface_commit (priv->surface); + } + + return TRUE; +} + +static gboolean +gst_vaapi_window_wayland_sync (GstVaapiWindow * window) +{ + GstVaapiWindowWaylandPrivate *const priv = + GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window); + struct wl_display *const wl_display = + GST_VAAPI_WINDOW_NATIVE_DISPLAY (window); + + if (priv->sync_failed) + return FALSE; + + if (priv->pollfd.fd < 0) { + priv->pollfd.fd = wl_display_get_fd (wl_display); + gst_poll_add_fd (priv->poll, &priv->pollfd); + gst_poll_fd_ctl_read (priv->poll, &priv->pollfd, TRUE); + } + + while (g_atomic_int_get (&priv->num_frames_pending) > 0) { + while (wl_display_prepare_read_queue (wl_display, priv->event_queue) < 0) { + if (wl_display_dispatch_queue_pending (wl_display, priv->event_queue) < 0) + goto error; + } + + if (wl_display_flush (wl_display) < 0) + goto error; + + if (g_atomic_int_get (&priv->num_frames_pending) == 0) { + wl_display_cancel_read (wl_display); + return TRUE; + } + + again: + if (gst_poll_wait (priv->poll, GST_CLOCK_TIME_NONE) < 0) { + int saved_errno = errno; + if (saved_errno == EAGAIN || saved_errno == EINTR) + goto again; + wl_display_cancel_read (wl_display); + if (saved_errno == EBUSY) /* flushing */ + return FALSE; + else + goto error; + } + + if (wl_display_read_events (wl_display) < 0) + goto error; + if (wl_display_dispatch_queue_pending (wl_display, priv->event_queue) < 0) + goto error; + } + return TRUE; + + /* ERRORS */ +error: + { + priv->sync_failed = TRUE; + GST_ERROR ("Error on dispatching events: %s", g_strerror (errno)); + return FALSE; + } +} + +static void +handle_ping (void *data, struct wl_shell_surface *wl_shell_surface, + uint32_t serial) +{ + wl_shell_surface_pong (wl_shell_surface, serial); +} + +static void +handle_configure (void *data, struct wl_shell_surface *wl_shell_surface, + uint32_t edges, int32_t width, int32_t height) +{ +} + +static void +handle_popup_done (void *data, struct wl_shell_surface *wl_shell_surface) +{ +} + +static const struct wl_shell_surface_listener shell_surface_listener = { + handle_ping, + handle_configure, + handle_popup_done +}; + +static void +handle_xdg_surface_configure (void *data, struct xdg_surface *xdg_surface, + uint32_t serial) +{ + GstVaapiWindow *window = GST_VAAPI_WINDOW (data); + GstVaapiWindowWaylandPrivate *priv = + GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window); + + xdg_surface_ack_configure (xdg_surface, serial); + if (g_atomic_int_compare_and_exchange (&priv->configure_pending, 1, 0)) + g_atomic_int_dec_and_test (&priv->num_frames_pending); +} + +static const struct xdg_surface_listener xdg_surface_listener = { + handle_xdg_surface_configure, +}; + +static gboolean +gst_vaapi_window_wayland_set_fullscreen (GstVaapiWindow * window, + gboolean fullscreen) +{ + GstVaapiWindowWaylandPrivate *const priv = + GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window); + + if (window->use_foreign_window) + return TRUE; + + if (!priv->is_shown) { + priv->fullscreen_on_show = fullscreen; + return TRUE; + } + + /* XDG-shell */ + if (priv->xdg_toplevel != NULL) { + if (fullscreen) + xdg_toplevel_set_fullscreen (priv->xdg_toplevel, NULL); + else + xdg_toplevel_unset_fullscreen (priv->xdg_toplevel); + return TRUE; + } + + /* wl_shell fallback */ + if (!fullscreen) + wl_shell_surface_set_toplevel (priv->wl_shell_surface); + else { + wl_shell_surface_set_fullscreen (priv->wl_shell_surface, + WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE, 0, NULL); + } + + return TRUE; +} + +static gboolean +gst_vaapi_window_wayland_create (GstVaapiWindow * window, + guint * width, guint * height) +{ + GstVaapiWindowWaylandPrivate *const priv = + GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window); + GstVaapiDisplayWaylandPrivate *const priv_display = + GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (GST_VAAPI_WINDOW_DISPLAY (window)); + + GST_DEBUG ("create window, size %ux%u", *width, *height); + + g_return_val_if_fail (priv_display->compositor != NULL, FALSE); + g_return_val_if_fail (priv_display->xdg_wm_base || priv_display->wl_shell, + FALSE); + + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + priv->event_queue = wl_display_create_queue (priv_display->wl_display); + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + if (!priv->event_queue) + return FALSE; + + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + priv->surface = wl_compositor_create_surface (priv_display->compositor); + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + if (!priv->surface) + return FALSE; + wl_proxy_set_queue ((struct wl_proxy *) priv->surface, priv->event_queue); + + if (window->use_foreign_window) { + struct wl_surface *wl_surface; + + if (priv_display->subcompositor) { + if (GST_VAAPI_SURFACE_ID (window) == VA_INVALID_ID) { + GST_ERROR ("Invalid window"); + return FALSE; + } + + wl_surface = (struct wl_surface *) GST_VAAPI_WINDOW_ID (window); + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + priv->video_subsurface = + wl_subcompositor_get_subsurface (priv_display->subcompositor, + priv->surface, wl_surface); + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + if (!priv->video_subsurface) + return FALSE; + + wl_proxy_set_queue ((struct wl_proxy *) priv->video_subsurface, + priv->event_queue); + + wl_subsurface_set_desync (priv->video_subsurface); + } else { + GST_ERROR ("Wayland server does not support subsurfaces"); + window->use_foreign_window = FALSE; + } + /* Prefer XDG-shell over deprecated wl_shell (if available) */ + } else if (priv_display->xdg_wm_base) { + /* Create the XDG surface. We make the toplevel on VaapiWindow::show() */ + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + priv->xdg_surface = xdg_wm_base_get_xdg_surface (priv_display->xdg_wm_base, + priv->surface); + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + if (!priv->xdg_surface) + return FALSE; + wl_proxy_set_queue ((struct wl_proxy *) priv->xdg_surface, + priv->event_queue); + xdg_surface_add_listener (priv->xdg_surface, &xdg_surface_listener, window); + } else { + /* Fall back to wl_shell */ + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + priv->wl_shell_surface = wl_shell_get_shell_surface (priv_display->wl_shell, + priv->surface); + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + if (!priv->wl_shell_surface) + return FALSE; + wl_proxy_set_queue ((struct wl_proxy *) priv->wl_shell_surface, + priv->event_queue); + + wl_shell_surface_add_listener (priv->wl_shell_surface, + &shell_surface_listener, priv); + wl_shell_surface_set_toplevel (priv->wl_shell_surface); + } + + priv->poll = gst_poll_new (TRUE); + gst_poll_fd_init (&priv->pollfd); + + g_mutex_init (&priv->opaque_mutex); + + if (priv->fullscreen_on_show) + gst_vaapi_window_wayland_set_fullscreen (window, TRUE); + + priv->is_shown = TRUE; + + return TRUE; +} + +static void +gst_vaapi_window_wayland_finalize (GObject * object) +{ + GstVaapiWindow *window = GST_VAAPI_WINDOW (object); + GstVaapiWindowWaylandPrivate *const priv = + GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window); + struct wl_display *const wl_display = + GST_VAAPI_WINDOW_NATIVE_DISPLAY (window); + + /* Make sure that the last wl buffer's callback could be called */ + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + if (priv->surface) { + wl_surface_attach (priv->surface, NULL, 0, 0); + wl_surface_commit (priv->surface); + wl_display_flush (wl_display); + } + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + + gst_poll_set_flushing (priv->poll, TRUE); + + if (priv->event_queue) + wl_display_roundtrip_queue (wl_display, priv->event_queue); + + while (priv->frames) + frame_state_free ((FrameState *) priv->frames->data); + + g_clear_pointer (&priv->xdg_surface, xdg_surface_destroy); + g_clear_pointer (&priv->wl_shell_surface, wl_shell_surface_destroy); + g_clear_pointer (&priv->video_subsurface, wl_subsurface_destroy); + g_clear_pointer (&priv->surface, wl_surface_destroy); + g_clear_pointer (&priv->event_queue, wl_event_queue_destroy); + + gst_poll_free (priv->poll); + + G_OBJECT_CLASS (gst_vaapi_window_wayland_parent_class)->finalize (object); +} + +static void +gst_vaapi_window_wayland_update_opaque_region (GstVaapiWindow * window, + guint width, guint height) +{ + GstVaapiWindowWaylandPrivate *const priv = + GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window); + + g_mutex_lock (&priv->opaque_mutex); + priv->opaque_width = width; + priv->opaque_height = height; + g_mutex_unlock (&priv->opaque_mutex); +} + +static gboolean +gst_vaapi_window_wayland_resize (GstVaapiWindow * window, + guint width, guint height) +{ + if (window->use_foreign_window) + return TRUE; + + GST_DEBUG ("resize window, new size %ux%u", width, height); + + gst_vaapi_window_wayland_update_opaque_region (window, width, height); + + return TRUE; +} + +void +gst_vaapi_window_wayland_set_render_rect (GstVaapiWindow * window, gint x, + gint y, gint width, gint height) +{ + GstVaapiWindowWaylandPrivate *const priv = + GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window); + + if (priv->video_subsurface) + wl_subsurface_set_position (priv->video_subsurface, x, y); + + gst_vaapi_window_wayland_update_opaque_region (window, width, height); +} + +static inline gboolean +frame_done (FrameState * frame) +{ + GstVaapiWindowWaylandPrivate *const priv = + GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (frame->window); + + g_atomic_int_set (&frame->done, TRUE); + if (g_atomic_pointer_compare_and_exchange (&priv->last_frame, frame, NULL)) + return g_atomic_int_dec_and_test (&priv->num_frames_pending); + return FALSE; +} + +static void +frame_done_callback (void *data, struct wl_callback *callback, uint32_t time) +{ + if (!frame_done (data)) + GST_INFO ("cannot remove last frame because it didn't match or empty"); +} + +static const struct wl_callback_listener frame_callback_listener = { + frame_done_callback +}; + +static void +frame_release_callback (void *data, struct wl_buffer *wl_buffer) +{ + FrameState *const frame = data; + + if (!frame->done) + if (!frame_done (frame)) + GST_INFO ("cannot remove last frame because it didn't match or empty"); + frame_state_free (frame); +} + +static const struct wl_buffer_listener frame_buffer_listener = { + frame_release_callback +}; + +typedef enum +{ + GST_VAAPI_DMABUF_SUCCESS, + GST_VAAPI_DMABUF_BAD_FLAGS, + GST_VAAPI_DMABUF_BAD_FORMAT, + GST_VAAPI_DMABUF_BAD_MODIFIER, + GST_VAAPI_DMABUF_NOT_SUPPORTED, + GST_VAAPI_DMABUF_FLUSH, + +} GstVaapiDmabufStatus; + +#define DRM_FORMAT_MOD_INVALID 0xffffffffffffff + +static GstVaapiDmabufStatus +dmabuf_format_supported (GstVaapiDisplayWaylandPrivate * const priv_display, + guint format, guint64 modifier) +{ + GArray *formats = priv_display->dmabuf_formats; + gboolean linear = FALSE; + gint i; + + for (i = 0; i < formats->len; i++) { + GstDRMFormat fmt = g_array_index (formats, GstDRMFormat, i); + if (fmt.format == format && (fmt.modifier == modifier || + (fmt.modifier == DRM_FORMAT_MOD_INVALID && modifier == 0))) + return GST_VAAPI_DMABUF_SUCCESS; + if (fmt.format == format && (fmt.modifier == 0 || + fmt.modifier == DRM_FORMAT_MOD_INVALID)) + linear = TRUE; + } + if (linear) + return GST_VAAPI_DMABUF_BAD_MODIFIER; + else + return GST_VAAPI_DMABUF_BAD_FORMAT; +} + +GstVideoFormat +check_format (GstVaapiDisplay * const display, gint index, + GstVideoFormat expect) +{ + GstVaapiDisplayWaylandPrivate *const priv_display = + GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (display); + GArray *formats = priv_display->dmabuf_formats; + GstDRMFormat fmt = g_array_index (formats, GstDRMFormat, index); + GstVideoFormat format = gst_vaapi_video_format_from_drm_format (fmt.format); + GstVaapiSurface *surface; + + /* unkown formats should be filtered out in the display */ + g_assert (format != GST_VIDEO_FORMAT_UNKNOWN); + + if ((expect != GST_VIDEO_FORMAT_UNKNOWN) && (format != expect)) + return GST_VIDEO_FORMAT_UNKNOWN; + + surface = gst_vaapi_surface_new_with_format (display, format, 64, 64, + fmt.modifier == 0 ? GST_VAAPI_SURFACE_ALLOC_FLAG_LINEAR_STORAGE : 0); + if (!surface) + return GST_VIDEO_FORMAT_UNKNOWN; + + gst_vaapi_surface_unref (surface); + + return format; +} + +GstVideoFormat +choose_next_format (GstVaapiDisplay * const display, gint * next_index) +{ + GstVaapiDisplayWaylandPrivate *const priv_display = + GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (display); + GArray *formats = priv_display->dmabuf_formats; + GstVideoFormat format; + gint i; + + if (*next_index < 0) { + *next_index = 0; + /* try GST_VIDEO_FORMAT_RGBA first */ + for (i = 0; i < formats->len; i++) { + format = check_format (display, i, GST_VIDEO_FORMAT_RGBA); + if (format != GST_VIDEO_FORMAT_UNKNOWN) + return format; + } + } + + for (i = *next_index; i < formats->len; i++) { + format = check_format (display, i, GST_VIDEO_FORMAT_UNKNOWN); + if (format != GST_VIDEO_FORMAT_UNKNOWN) { + *next_index = i + 1; + return format; + } + } + *next_index = formats->len; + return GST_VIDEO_FORMAT_UNKNOWN; +} + +static GstVaapiDmabufStatus +dmabuf_buffer_from_surface (GstVaapiWindow * window, GstVaapiSurface * surface, + guint va_flags, struct wl_buffer **out_buffer) +{ + GstVaapiDisplay *const display = GST_VAAPI_WINDOW_DISPLAY (window); + GstVaapiDisplayWaylandPrivate *const priv_display = + GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (display); + struct zwp_linux_buffer_params_v1 *params; + struct wl_buffer *buffer = NULL; + VADRMPRIMESurfaceDescriptor desc; + VAStatus status; + GstVaapiDmabufStatus ret; + guint format, i, j, plane = 0; + + if (!priv_display->dmabuf) + return GST_VAAPI_DMABUF_NOT_SUPPORTED; + + if ((va_flags & (VA_TOP_FIELD | VA_BOTTOM_FIELD)) != VA_FRAME_PICTURE) + return GST_VAAPI_DMABUF_BAD_FLAGS; + + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + status = vaExportSurfaceHandle (GST_VAAPI_DISPLAY_VADISPLAY (display), + GST_VAAPI_SURFACE_ID (surface), VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2, + VA_EXPORT_SURFACE_SEPARATE_LAYERS | VA_EXPORT_SURFACE_READ_ONLY, &desc); + /* Try again with composed layers, in case the format is supported there */ + if (status == VA_STATUS_ERROR_INVALID_SURFACE) + status = vaExportSurfaceHandle (GST_VAAPI_DISPLAY_VADISPLAY (display), + GST_VAAPI_SURFACE_ID (surface), VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2, + VA_EXPORT_SURFACE_COMPOSED_LAYERS | VA_EXPORT_SURFACE_READ_ONLY, &desc); + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + + if (!vaapi_check_status (status, "vaExportSurfaceHandle()")) { + if (status == VA_STATUS_ERROR_UNIMPLEMENTED) + return GST_VAAPI_DMABUF_NOT_SUPPORTED; + else + return GST_VAAPI_DMABUF_BAD_FORMAT; + } + + format = gst_vaapi_drm_format_from_va_fourcc (desc.fourcc); + params = zwp_linux_dmabuf_v1_create_params (priv_display->dmabuf); + for (i = 0; i < desc.num_layers; i++) { + for (j = 0; j < desc.layers[i].num_planes; ++j) { + gint object = desc.layers[i].object_index[j]; + guint64 modifier = desc.objects[object].drm_format_modifier; + + ret = dmabuf_format_supported (priv_display, format, modifier); + if (ret != GST_VAAPI_DMABUF_SUCCESS) { + GST_DEBUG ("skipping unsupported format/modifier %s/0x%" + G_GINT64_MODIFIER "x", gst_video_format_to_string + (gst_vaapi_video_format_from_drm_format (format)), modifier); + goto out; + } + + zwp_linux_buffer_params_v1_add (params, + desc.objects[object].fd, plane, desc.layers[i].offset[j], + desc.layers[i].pitch[j], modifier >> 32, + modifier & G_GUINT64_CONSTANT (0xffffffff)); + plane++; + } + } + + buffer = zwp_linux_buffer_params_v1_create_immed (params, window->width, + window->height, format, 0); + + if (!buffer) + ret = GST_VAAPI_DMABUF_NOT_SUPPORTED; + +out: + zwp_linux_buffer_params_v1_destroy (params); + + for (i = 0; i < desc.num_objects; i++) + close (desc.objects[i].fd); + + *out_buffer = buffer; + return ret; +} + +static gboolean +buffer_from_surface (GstVaapiWindow * window, GstVaapiSurface ** surf, + const GstVaapiRectangle * src_rect, const GstVaapiRectangle * dst_rect, + guint flags, struct wl_buffer **buffer) +{ + GstVaapiDisplay *const display = GST_VAAPI_WINDOW_DISPLAY (window); + GstVaapiWindowWaylandPrivate *const priv = + GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window); + GstVaapiSurface *surface; + GstVaapiDmabufStatus ret; + guint va_flags; + VAStatus status; + gint format_index = -1; + + va_flags = from_GstVaapiSurfaceRenderFlags (flags); + +again: + surface = *surf; + if (priv->need_vpp) { + GstVaapiSurface *vpp_surface = NULL; + if (window->has_vpp) { + GST_LOG ("VPP: %s <%d, %d, %d, %d> -> %s <%d, %d, %d, %d>", + gst_video_format_to_string (gst_vaapi_surface_get_format (surface)), + src_rect->x, src_rect->y, src_rect->width, src_rect->height, + gst_video_format_to_string (window->surface_pool_format), + dst_rect->x, dst_rect->y, dst_rect->width, dst_rect->height); + vpp_surface = gst_vaapi_window_vpp_convert_internal (window, surface, + src_rect, dst_rect, flags); + } + if (G_UNLIKELY (!vpp_surface)) { + /* Not all formats are supported as destination format during VPP. + So try again with the next format if VPP fails. */ + GstVideoFormat format = choose_next_format (display, &format_index); + if ((format != GST_VIDEO_FORMAT_UNKNOWN) && window->has_vpp) { + GST_DEBUG ("VPP failed. Try again with format %s", + gst_video_format_to_string (format)); + gst_vaapi_window_set_vpp_format_internal (window, format, 0); + goto again; + } else { + GST_WARNING ("VPP failed. No supported format found."); + priv->dmabuf_broken = TRUE; + } + } else { + surface = vpp_surface; + va_flags = VA_FRAME_PICTURE; + } + } + if (!priv->dmabuf_broken) { + ret = dmabuf_buffer_from_surface (window, surface, va_flags, buffer); + switch (ret) { + case GST_VAAPI_DMABUF_SUCCESS: + goto out; + case GST_VAAPI_DMABUF_BAD_FLAGS: + /* FIXME: how should this be handed? */ + break; + case GST_VAAPI_DMABUF_BAD_FORMAT:{ + /* The Wayland server does not accept the current format or + vaExportSurfaceHandle() failed. Try again with a different format */ + GstVideoFormat format = choose_next_format (display, &format_index); + if ((format != GST_VIDEO_FORMAT_UNKNOWN) && window->has_vpp) { + GST_DEBUG ("Failed to export buffer. Try again with format %s", + gst_video_format_to_string (format)); + priv->need_vpp = TRUE; + gst_vaapi_window_set_vpp_format_internal (window, format, 0); + goto again; + } + if (window->has_vpp) + GST_WARNING ("Failed to export buffer and VPP not supported."); + else + GST_WARNING ("Failed to export buffer. No supported format found."); + priv->dmabuf_broken = TRUE; + break; + } + case GST_VAAPI_DMABUF_BAD_MODIFIER: + /* The format is supported by the Wayland server but not with the + current modifier. Try linear instead. */ + if (window->has_vpp) { + GST_DEBUG ("Modifier rejected by the server. Try linear instead."); + priv->need_vpp = TRUE; + gst_vaapi_window_set_vpp_format_internal (window, + gst_vaapi_surface_get_format (surface), + GST_VAAPI_SURFACE_ALLOC_FLAG_LINEAR_STORAGE); + goto again; + } + GST_WARNING ("Modifier rejected by the server and VPP not supported."); + priv->dmabuf_broken = TRUE; + break; + case GST_VAAPI_DMABUF_NOT_SUPPORTED: + GST_DEBUG ("DMABuf protocol not supported"); + priv->dmabuf_broken = TRUE; + break; + case GST_VAAPI_DMABUF_FLUSH: + return FALSE; + } + } + + /* DMABuf is not available or does not work. Fall back to the old API. + There is no format negotiation so stick with NV12 */ + gst_vaapi_window_set_vpp_format_internal (window, GST_VIDEO_FORMAT_NV12, 0); + + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + status = vaGetSurfaceBufferWl (GST_VAAPI_DISPLAY_VADISPLAY (display), + GST_VAAPI_SURFACE_ID (surface), + va_flags & (VA_TOP_FIELD | VA_BOTTOM_FIELD), buffer); + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + + if (window->has_vpp && !priv->need_vpp && + (status == VA_STATUS_ERROR_FLAG_NOT_SUPPORTED || + status == VA_STATUS_ERROR_UNIMPLEMENTED || + status == VA_STATUS_ERROR_INVALID_IMAGE_FORMAT)) { + priv->need_vpp = TRUE; + goto again; + } + if (!vaapi_check_status (status, "vaGetSurfaceBufferWl()")) + return FALSE; + +out: + *surf = surface; + return TRUE; +} + +static gboolean +gst_vaapi_window_wayland_render (GstVaapiWindow * window, + GstVaapiSurface * surface, + const GstVaapiRectangle * src_rect, + const GstVaapiRectangle * dst_rect, guint flags) +{ + GstVaapiWindowWaylandPrivate *const priv = + GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window); + GstVaapiDisplayWaylandPrivate *const priv_display = + GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (GST_VAAPI_WINDOW_DISPLAY (window)); + struct wl_display *const wl_display = + GST_VAAPI_WINDOW_NATIVE_DISPLAY (window); + struct wl_buffer *buffer; + FrameState *frame; + guint width, height; + gboolean ret; + + /* Skip rendering without valid window size. This can happen with a foreign + window if the render rectangle is not yet set. */ + if (window->width == 0 || window->height == 0) + return TRUE; + + /* Check that we don't need to crop source VA surface */ + gst_vaapi_surface_get_size (surface, &width, &height); + if (src_rect->x != 0 || src_rect->y != 0) + priv->need_vpp = TRUE; + if (src_rect->width != width) + priv->need_vpp = TRUE; + + /* Check that we don't render to a subregion of this window */ + if (dst_rect->x != 0 || dst_rect->y != 0) + priv->need_vpp = TRUE; + if (dst_rect->width != window->width || dst_rect->height != window->height) + priv->need_vpp = TRUE; + + /* Check that the surface has the correct size for the window */ + if (dst_rect->width != src_rect->width || + dst_rect->height != src_rect->height) + priv->need_vpp = TRUE; + + ret = buffer_from_surface (window, &surface, src_rect, dst_rect, flags, + &buffer); + if (!ret) + return FALSE; + + /* if need_vpp is set then the vpp happend */ + if (priv->need_vpp) { + width = window->width; + height = window->height; + } + + /* Wait for the previous frame to complete redraw */ + if (!gst_vaapi_window_wayland_sync (window)) { + /* Release vpp surface if exists */ + if (priv->need_vpp && window->has_vpp) + gst_vaapi_video_pool_put_object (window->surface_pool, surface); + wl_buffer_destroy (buffer); + return !priv->sync_failed; + } + + frame = frame_state_new (window); + if (!frame) + return FALSE; + g_atomic_pointer_set (&priv->last_frame, frame); + g_atomic_int_inc (&priv->num_frames_pending); + + if (priv->need_vpp && window->has_vpp) { + frame->surface = surface; + frame->surface_pool = gst_vaapi_video_pool_ref (window->surface_pool); + } + + /* XXX: attach to the specified target rectangle */ + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + wl_surface_attach (priv->surface, buffer, 0, 0); + wl_surface_damage (priv->surface, 0, 0, width, height); + + g_mutex_lock (&priv->opaque_mutex); + if (priv->opaque_width > 0) { + struct wl_region *opaque_region; + opaque_region = wl_compositor_create_region (priv_display->compositor); + wl_region_add (opaque_region, 0, 0, width, height); + wl_surface_set_opaque_region (priv->surface, opaque_region); + wl_region_destroy (opaque_region); + priv->opaque_width = 0; + priv->opaque_height = 0; + } + g_mutex_unlock (&priv->opaque_mutex); + + wl_proxy_set_queue ((struct wl_proxy *) buffer, priv->event_queue); + wl_buffer_add_listener (buffer, &frame_buffer_listener, frame); + + frame->buffer = buffer; + frame->callback = wl_surface_frame (priv->surface); + wl_callback_add_listener (frame->callback, &frame_callback_listener, frame); + priv->frames = g_list_append (priv->frames, frame); + + wl_surface_commit (priv->surface); + wl_display_flush (wl_display); + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + return TRUE; +} + +static gboolean +gst_vaapi_window_wayland_unblock (GstVaapiWindow * window) +{ + GstVaapiWindowWaylandPrivate *const priv = + GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window); + + gst_poll_set_flushing (priv->poll, TRUE); + + return TRUE; +} + +static gboolean +gst_vaapi_window_wayland_unblock_cancel (GstVaapiWindow * window) +{ + GstVaapiWindowWaylandPrivate *const priv = + GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window); + + gst_poll_set_flushing (priv->poll, FALSE); + + return TRUE; +} + +static void +gst_vaapi_window_wayland_class_init (GstVaapiWindowWaylandClass * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstVaapiWindowClass *const window_class = GST_VAAPI_WINDOW_CLASS (klass); + + object_class->finalize = gst_vaapi_window_wayland_finalize; + + window_class->create = gst_vaapi_window_wayland_create; + window_class->show = gst_vaapi_window_wayland_show; + window_class->hide = gst_vaapi_window_wayland_hide; + window_class->render = gst_vaapi_window_wayland_render; + window_class->resize = gst_vaapi_window_wayland_resize; + window_class->set_fullscreen = gst_vaapi_window_wayland_set_fullscreen; + window_class->unblock = gst_vaapi_window_wayland_unblock; + window_class->unblock_cancel = gst_vaapi_window_wayland_unblock_cancel; + window_class->set_render_rect = gst_vaapi_window_wayland_set_render_rect; + + signals[SIZE_CHANGED] = g_signal_new ("size-changed", + G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, + G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); +} + +static void +gst_vaapi_window_wayland_init (GstVaapiWindowWayland * window) +{ +} + +/** + * gst_vaapi_window_wayland_new: + * @display: a #GstVaapiDisplay + * @width: the requested window width, in pixels + * @height: the requested windo height, in pixels + * + * Creates a window with the specified @width and @height. The window + * will be attached to the @display and remains invisible to the user + * until gst_vaapi_window_show() is called. + * + * Return value (transfer full): the newly allocated #GstVaapiWindow object + */ +GstVaapiWindow * +gst_vaapi_window_wayland_new (GstVaapiDisplay * display, + guint width, guint height) +{ + g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_WAYLAND (display), NULL); + + return gst_vaapi_window_new_internal (GST_TYPE_VAAPI_WINDOW_WAYLAND, display, + GST_VAAPI_ID_INVALID, width, height); +} + +/** + * gst_vaapi_window_wayland_new_with_surface: + * @display: a #GstVaapiDisplay + * @wl_surface: a Wayland surface pointer + * + * Creates a window with the specified @wl_surface. The window + * will be attached to the @display and remains invisible to the user + * until gst_vaapi_window_show() is called. + * + * Return value (transfer full): the newly allocated #GstVaapiWindow object + * + * Since: 1.18 + */ +GstVaapiWindow * +gst_vaapi_window_wayland_new_with_surface (GstVaapiDisplay * display, + guintptr wl_surface) +{ + g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_WAYLAND (display), NULL); + g_return_val_if_fail (wl_surface, NULL); + + GST_CAT_DEBUG (gst_debug_vaapi, "new window from surface 0x%" + G_GINTPTR_MODIFIER "x", wl_surface); + + return gst_vaapi_window_new_internal (GST_TYPE_VAAPI_WINDOW_WAYLAND, display, + wl_surface, 0, 0); +} diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_wayland.h b/gst-libs/gst/vaapi/gstvaapiwindow_wayland.h new file mode 100644 index 0000000000..016f582516 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow_wayland.h @@ -0,0 +1,56 @@ +/* + * gstvaapiwindow_wayland.h - VA/Wayland window abstraction + * + * Copyright (C) 2012-2013 Intel Corporation + * Author: Sreerenj Balachandran + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_WINDOW_WAYLAND_H +#define GST_VAAPI_WINDOW_WAYLAND_H + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_WINDOW_WAYLAND (gst_vaapi_window_wayland_get_type ()) +#define GST_VAAPI_WINDOW_WAYLAND(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_WINDOW_WAYLAND, GstVaapiWindowWayland)) +#define GST_VAAPI_IS_WINDOW_WAYLAND(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_WINDOW_WAYLAND)) + +typedef struct _GstVaapiWindowWayland GstVaapiWindowWayland; + +GType +gst_vaapi_window_wayland_get_type (void) G_GNUC_CONST; + +GstVaapiWindow * +gst_vaapi_window_wayland_new (GstVaapiDisplay * display, guint width, + guint height); + +GstVaapiWindow * +gst_vaapi_window_wayland_new_with_surface (GstVaapiDisplay * display, + guintptr wl_surface); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiWindowWayland, gst_object_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_WINDOW_WAYLAND_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_x11.c b/gst-libs/gst/vaapi/gstvaapiwindow_x11.c new file mode 100644 index 0000000000..38fed7a12f --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow_x11.c @@ -0,0 +1,585 @@ +/* + * gstvaapiwindow_x11.c - VA/X11 window abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapiwindow_x11 + * @short_description: VA/X11 window abstraction + */ + +#include "sysdeps.h" +#include +#include "gstvaapicompat.h" +#include "gstvaapiwindow_x11.h" +#include "gstvaapiwindow_x11_priv.h" +#include "gstvaapidisplay_x11.h" +#include "gstvaapidisplay_x11_priv.h" +#include "gstvaapisurface_priv.h" +#include "gstvaapiutils.h" +#include "gstvaapiutils_x11.h" + +GST_DEBUG_CATEGORY_EXTERN (gst_debug_vaapi_window); +#define GST_CAT_DEFAULT gst_debug_vaapi_window + +#define GST_VAAPI_WINDOW_X11_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_WINDOW_X11, GstVaapiWindowX11Class)) + +G_DEFINE_TYPE_WITH_PRIVATE (GstVaapiWindowX11, gst_vaapi_window_x11, + GST_TYPE_VAAPI_WINDOW); + +#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */ +#define _NET_WM_STATE_ADD 1 /* add/set property */ +#define _NET_WM_STATE_TOGGLE 2 /* toggle property */ + +static void +send_wmspec_change_state (GstVaapiWindow * window, Atom state, gboolean add) +{ + GstVaapiWindowX11Private *const priv = + GST_VAAPI_WINDOW_X11_GET_PRIVATE (window); + Display *const dpy = GST_VAAPI_WINDOW_NATIVE_DISPLAY (window); + XClientMessageEvent xclient; + + memset (&xclient, 0, sizeof (xclient)); + + xclient.type = ClientMessage; + xclient.window = GST_VAAPI_WINDOW_ID (window); + xclient.message_type = priv->atom_NET_WM_STATE; + xclient.format = 32; + + xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; + xclient.data.l[1] = state; + xclient.data.l[2] = 0; + xclient.data.l[3] = 0; + xclient.data.l[4] = 0; + + XSendEvent (dpy, + DefaultRootWindow (dpy), + False, + SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *) & xclient); +} + +static void +wait_event (GstVaapiWindow * window, int type) +{ + Display *const dpy = GST_VAAPI_WINDOW_NATIVE_DISPLAY (window); + const Window xid = GST_VAAPI_WINDOW_ID (window); + XEvent e; + Bool got_event; + + for (;;) { + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + got_event = XCheckTypedWindowEvent (dpy, xid, type, &e); + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + if (got_event) + break; + g_usleep (10); + } +} + +static gboolean +timed_wait_event (GstVaapiWindow * window, int type, guint64 end_time, + XEvent * e) +{ + Display *const dpy = GST_VAAPI_WINDOW_NATIVE_DISPLAY (window); + const Window xid = GST_VAAPI_WINDOW_ID (window); + XEvent tmp_event; + guint64 now_time; + Bool got_event; + + if (!e) + e = &tmp_event; + + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + got_event = XCheckTypedWindowEvent (dpy, xid, type, e); + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + if (got_event) + return TRUE; + + do { + g_usleep (10); + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + got_event = XCheckTypedWindowEvent (dpy, xid, type, e); + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + if (got_event) + return TRUE; + now_time = g_get_real_time (); + } while (now_time < end_time); + return FALSE; +} + +static gboolean +gst_vaapi_window_x11_show (GstVaapiWindow * window) +{ + GstVaapiWindowX11Private *const priv = + GST_VAAPI_WINDOW_X11_GET_PRIVATE (window); + Display *const dpy = GST_VAAPI_WINDOW_NATIVE_DISPLAY (window); + const Window xid = GST_VAAPI_WINDOW_ID (window); + XWindowAttributes wattr; + gboolean has_errors; + + if (priv->is_mapped) + return TRUE; + + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + x11_trap_errors (); + if (window->use_foreign_window) { + XGetWindowAttributes (dpy, xid, &wattr); + if (!(wattr.your_event_mask & StructureNotifyMask)) + XSelectInput (dpy, xid, StructureNotifyMask); + } + XMapWindow (dpy, xid); + has_errors = x11_untrap_errors () != 0; + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + + if (!has_errors) { + wait_event (window, MapNotify); + if (window->use_foreign_window && + !(wattr.your_event_mask & StructureNotifyMask)) { + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + x11_trap_errors (); + XSelectInput (dpy, xid, wattr.your_event_mask); + has_errors = x11_untrap_errors () != 0; + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + } + priv->is_mapped = TRUE; + + if (priv->fullscreen_on_map) + gst_vaapi_window_set_fullscreen (window, TRUE); + } + return !has_errors; +} + +static gboolean +gst_vaapi_window_x11_hide (GstVaapiWindow * window) +{ + GstVaapiWindowX11Private *const priv = + GST_VAAPI_WINDOW_X11_GET_PRIVATE (window); + Display *const dpy = GST_VAAPI_WINDOW_NATIVE_DISPLAY (window); + const Window xid = GST_VAAPI_WINDOW_ID (window); + XWindowAttributes wattr; + gboolean has_errors; + + if (!priv->is_mapped) + return TRUE; + + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + x11_trap_errors (); + if (window->use_foreign_window) { + XGetWindowAttributes (dpy, xid, &wattr); + if (!(wattr.your_event_mask & StructureNotifyMask)) + XSelectInput (dpy, xid, StructureNotifyMask); + } + XUnmapWindow (dpy, xid); + has_errors = x11_untrap_errors () != 0; + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + + if (!has_errors) { + wait_event (window, UnmapNotify); + if (window->use_foreign_window && + !(wattr.your_event_mask & StructureNotifyMask)) { + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + x11_trap_errors (); + XSelectInput (dpy, xid, wattr.your_event_mask); + has_errors = x11_untrap_errors () != 0; + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + } + priv->is_mapped = FALSE; + } + return !has_errors; +} + +static gboolean +gst_vaapi_window_x11_create (GstVaapiWindow * window, guint * width, + guint * height) +{ + GstVaapiWindowX11Private *const priv = + GST_VAAPI_WINDOW_X11_GET_PRIVATE (window); + GstVaapiDisplay *const display = GST_VAAPI_WINDOW_DISPLAY (window); + Display *const dpy = GST_VAAPI_WINDOW_NATIVE_DISPLAY (window); + Window xid = GST_VAAPI_WINDOW_ID (window); + guint vid = 0; + Colormap cmap = None; + const GstVaapiDisplayClass *display_class; + const GstVaapiWindowClass *window_class; + XWindowAttributes wattr; + Atom wm_delete, atoms[2]; + gboolean ok; + + static const char *atom_names[2] = { + "_NET_WM_STATE", + "_NET_WM_STATE_FULLSCREEN", + }; + + if (window->use_foreign_window && xid) { + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + XGetWindowAttributes (dpy, xid, &wattr); + priv->is_mapped = wattr.map_state == IsViewable; + ok = x11_get_geometry (dpy, xid, NULL, NULL, width, height, NULL); + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + return ok; + } + + display_class = GST_VAAPI_DISPLAY_GET_CLASS (display); + if (display_class) { + if (display_class->get_visual_id) + vid = display_class->get_visual_id (display, window); + if (display_class->get_colormap) + cmap = display_class->get_colormap (display, window); + } + + window_class = GST_VAAPI_WINDOW_GET_CLASS (window); + if (window_class) { + if (window_class->get_visual_id && !vid) + vid = window_class->get_visual_id (window); + if (window_class->get_colormap && !cmap) + cmap = window_class->get_colormap (window); + } + + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + XInternAtoms (dpy, + (char **) atom_names, G_N_ELEMENTS (atom_names), False, atoms); + priv->atom_NET_WM_STATE = atoms[0]; + priv->atom_NET_WM_STATE_FULLSCREEN = atoms[1]; + + xid = x11_create_window (dpy, *width, *height, vid, cmap); + if (xid) { + /* Tell the window manager we'd like delete client messages instead of + * being killed */ + wm_delete = XInternAtom (dpy, "WM_DELETE_WINDOW", True); + if (wm_delete != None) { + (void) XSetWMProtocols (dpy, xid, &wm_delete, 1); + } + + XRaiseWindow (dpy, xid); + } + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + + GST_DEBUG ("xid %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (xid)); + GST_VAAPI_WINDOW_ID (window) = xid; + return xid != None; +} + +static void +gst_vaapi_window_x11_finalize (GObject * object) +{ + GstVaapiWindow *window = GST_VAAPI_WINDOW (object); + Display *const dpy = GST_VAAPI_WINDOW_NATIVE_DISPLAY (window); + const Window xid = GST_VAAPI_WINDOW_ID (window); + + if (xid) { + if (!window->use_foreign_window) { + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + XDestroyWindow (dpy, xid); + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + } + GST_VAAPI_WINDOW_ID (window) = None; + } + + G_OBJECT_CLASS (gst_vaapi_window_x11_parent_class)->finalize (object); +} + +static gboolean +gst_vaapi_window_x11_get_geometry (GstVaapiWindow * window, + gint * px, gint * py, guint * pwidth, guint * pheight) +{ + Display *const dpy = GST_VAAPI_WINDOW_NATIVE_DISPLAY (window); + const Window xid = GST_VAAPI_WINDOW_ID (window); + gboolean success; + + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + success = x11_get_geometry (dpy, xid, px, py, pwidth, pheight, NULL); + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + return success; +} + +static gboolean +gst_vaapi_window_x11_set_fullscreen (GstVaapiWindow * window, + gboolean fullscreen) +{ + GstVaapiWindowX11Private *const priv = + GST_VAAPI_WINDOW_X11_GET_PRIVATE (window); + Display *const dpy = GST_VAAPI_WINDOW_NATIVE_DISPLAY (window); + const Window xid = GST_VAAPI_WINDOW_ID (window); + XEvent e; + guint width, height; + gboolean has_errors; + guint64 end_time; + + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + x11_trap_errors (); + if (fullscreen) { + if (!priv->is_mapped) { + priv->fullscreen_on_map = TRUE; + + XChangeProperty (dpy, + xid, + priv->atom_NET_WM_STATE, XA_ATOM, 32, + PropModeReplace, + (unsigned char *) &priv->atom_NET_WM_STATE_FULLSCREEN, 1); + } else { + send_wmspec_change_state (window, + priv->atom_NET_WM_STATE_FULLSCREEN, TRUE); + } + } else { + if (!priv->is_mapped) { + priv->fullscreen_on_map = FALSE; + + XDeleteProperty (dpy, xid, priv->atom_NET_WM_STATE); + } else { + send_wmspec_change_state (window, + priv->atom_NET_WM_STATE_FULLSCREEN, FALSE); + } + } + XSync (dpy, False); + has_errors = x11_untrap_errors () != 0; + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + if (has_errors) + return FALSE; + + /* Try to wait for the completion of the fullscreen mode switch */ + if (!window->use_foreign_window && priv->is_mapped) { + const guint DELAY = 100000; /* 100 ms */ + end_time = DELAY + g_get_real_time (); + while (timed_wait_event (window, ConfigureNotify, end_time, &e)) { + if (fullscreen) { + gst_vaapi_display_get_size (GST_VAAPI_WINDOW_DISPLAY (window), + &width, &height); + if (e.xconfigure.width == width && e.xconfigure.height == height) + return TRUE; + } else { + gst_vaapi_window_get_size (window, &width, &height); + if (e.xconfigure.width != width || e.xconfigure.height != height) + return TRUE; + } + } + } + return FALSE; +} + +static gboolean +gst_vaapi_window_x11_resize (GstVaapiWindow * window, guint width, guint height) +{ + gboolean has_errors; + + if (!GST_VAAPI_WINDOW_ID (window)) + return FALSE; + + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + x11_trap_errors (); + XResizeWindow (GST_VAAPI_WINDOW_NATIVE_DISPLAY (window), + GST_VAAPI_WINDOW_ID (window), width, height); + has_errors = x11_untrap_errors () != 0; + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + return !has_errors; +} + +static VAStatus +gst_vaapi_window_x11_put_surface (GstVaapiWindow * window, + VASurfaceID surface_id, + const GstVaapiRectangle * src_rect, + const GstVaapiRectangle * dst_rect, guint flags) +{ + VAStatus status; + + GST_VAAPI_WINDOW_LOCK_DISPLAY (window); + status = vaPutSurface (GST_VAAPI_WINDOW_VADISPLAY (window), + surface_id, + GST_VAAPI_WINDOW_ID (window), + src_rect->x, + src_rect->y, + src_rect->width, + src_rect->height, + dst_rect->x, + dst_rect->y, + dst_rect->width, + dst_rect->height, NULL, 0, from_GstVaapiSurfaceRenderFlags (flags) + ); + + GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); + + return status; +} + +static gboolean +gst_vaapi_window_x11_render (GstVaapiWindow * window, + GstVaapiSurface * surface, + const GstVaapiRectangle * src_rect, + const GstVaapiRectangle * dst_rect, guint flags) +{ + VASurfaceID surface_id; + VAStatus status; + GstVaapiWindowX11Private *const priv = + GST_VAAPI_WINDOW_X11_GET_PRIVATE (window); + gboolean ret = FALSE; + + surface_id = GST_VAAPI_SURFACE_ID (surface); + if (surface_id == VA_INVALID_ID) + return FALSE; + + if (window->has_vpp && priv->need_vpp) + goto conversion; + + status = + gst_vaapi_window_x11_put_surface (window, surface_id, src_rect, dst_rect, + flags); + + if (status == VA_STATUS_ERROR_FLAG_NOT_SUPPORTED || + status == VA_STATUS_ERROR_UNIMPLEMENTED || + status == VA_STATUS_ERROR_INVALID_IMAGE_FORMAT) { + priv->need_vpp = TRUE; + } else { + ret = vaapi_check_status (status, "vaPutSurface()"); + } + +conversion: + if (priv->need_vpp && window->has_vpp) { + GstVaapiSurface *const vpp_surface = + gst_vaapi_window_vpp_convert_internal (window, surface, NULL, NULL, + flags); + if (G_LIKELY (vpp_surface)) { + GstVaapiRectangle vpp_src_rect; + + surface_id = GST_VAAPI_SURFACE_ID (vpp_surface); + vpp_src_rect.x = vpp_src_rect.y = 0; + vpp_src_rect.width = GST_VAAPI_SURFACE_WIDTH (vpp_surface); + vpp_src_rect.height = GST_VAAPI_SURFACE_HEIGHT (vpp_surface); + + status = + gst_vaapi_window_x11_put_surface (window, surface_id, &vpp_src_rect, + dst_rect, flags); + + ret = vaapi_check_status (status, "vaPutSurface()"); + + if (!gst_vaapi_surface_sync (vpp_surface)) { + GST_WARNING ("failed to render surface"); + ret = FALSE; + } + + gst_vaapi_video_pool_put_object (window->surface_pool, vpp_surface); + } else { + priv->need_vpp = FALSE; + } + } + + return ret; +} + +static void +gst_vaapi_window_x11_class_init (GstVaapiWindowX11Class * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstVaapiWindowClass *const window_class = GST_VAAPI_WINDOW_CLASS (klass); + + object_class->finalize = gst_vaapi_window_x11_finalize; + + window_class->create = gst_vaapi_window_x11_create; + window_class->show = gst_vaapi_window_x11_show; + window_class->hide = gst_vaapi_window_x11_hide; + window_class->get_geometry = gst_vaapi_window_x11_get_geometry; + window_class->set_fullscreen = gst_vaapi_window_x11_set_fullscreen; + window_class->resize = gst_vaapi_window_x11_resize; + window_class->render = gst_vaapi_window_x11_render; +} + +static void +gst_vaapi_window_x11_init (GstVaapiWindowX11 * window) +{ +} + +/** + * gst_vaapi_window_x11_new: + * @display: a #GstVaapiDisplay + * @width: the requested window width, in pixels + * @height: the requested windo height, in pixels + * + * Creates a window with the specified @width and @height. The window + * will be attached to the @display and remains invisible to the user + * until gst_vaapi_window_show() is called. + * + * Return value: the newly allocated #GstVaapiWindow object + */ +GstVaapiWindow * +gst_vaapi_window_x11_new (GstVaapiDisplay * display, guint width, guint height) +{ + g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_X11 (display), NULL); + + return gst_vaapi_window_new_internal (GST_TYPE_VAAPI_WINDOW_X11, display, + GST_VAAPI_ID_INVALID, width, height); +} + +/** + * gst_vaapi_window_x11_new_with_xid: + * @display: a #GstVaapiDisplay + * @xid: an X11 Window id + * + * Creates a #GstVaapiWindow using the X11 Window @xid. The caller + * still owns the window and must call XDestroyWindow() when all + * #GstVaapiWindow references are released. Doing so too early can + * yield undefined behaviour. + * + * Return value: the newly allocated #GstVaapiWindow object + */ +GstVaapiWindow * +gst_vaapi_window_x11_new_with_xid (GstVaapiDisplay * display, Window xid) +{ + g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_X11 (display), NULL); + g_return_val_if_fail (xid != None, NULL); + + return gst_vaapi_window_new_internal (GST_TYPE_VAAPI_WINDOW_X11, display, + xid, 0, 0); +} + +/** + * gst_vaapi_window_x11_get_xid: + * @window: a #GstVaapiWindowX11 + * + * Returns the underlying X11 Window that was created by + * gst_vaapi_window_x11_new() or that was bound with + * gst_vaapi_window_x11_new_with_xid(). + * + * Return value: the underlying X11 Window bound to @window. + */ +Window +gst_vaapi_window_x11_get_xid (GstVaapiWindowX11 * window) +{ + g_return_val_if_fail (GST_VAAPI_IS_WINDOW_X11 (window), None); + + return GST_VAAPI_WINDOW_ID (window); +} + +/** + * gst_vaapi_window_x11_is_foreign_xid: + * @window: a #GstVaapiWindowX11 + * + * Checks whether the @window XID was created by gst_vaapi_window_x11_new() or bound with gst_vaapi_window_x11_new_with_xid(). + * + * Return value: %TRUE if the underlying X window is owned by the + * caller (foreign window) + */ +gboolean +gst_vaapi_window_x11_is_foreign_xid (GstVaapiWindowX11 * window) +{ + g_return_val_if_fail (GST_VAAPI_IS_WINDOW_X11 (window), FALSE); + + return GST_VAAPI_WINDOW (window)->use_foreign_window; +} diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_x11.h b/gst-libs/gst/vaapi/gstvaapiwindow_x11.h new file mode 100644 index 0000000000..672e1ff9a4 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow_x11.h @@ -0,0 +1,71 @@ +/* + * gstvaapiwindow_x11.h - VA/X11 window abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_WINDOW_X11_H +#define GST_VAAPI_WINDOW_X11_H + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_WINDOW_X11 (gst_vaapi_window_x11_get_type ()) +#define GST_VAAPI_WINDOW_X11(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_WINDOW_X11, GstVaapiWindowX11)) +#define GST_VAAPI_IS_WINDOW_X11(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_WINDOW_X11)) + +/** + * GST_VAAPI_WINDOW_XWINDOW: + * @window: a #GstVaapiWindow + * + * Macro that evaluates to the underlying X11 Window of @window + */ +#define GST_VAAPI_WINDOW_XWINDOW(window) \ + gst_vaapi_window_x11_get_xid (GST_VAAPI_WINDOW_X11 (window)) + +typedef struct _GstVaapiWindowX11 GstVaapiWindowX11; + +GType +gst_vaapi_window_x11_get_type (void) G_GNUC_CONST; + +GstVaapiWindow * +gst_vaapi_window_x11_new (GstVaapiDisplay * display, guint width, guint height); + +GstVaapiWindow * +gst_vaapi_window_x11_new_with_xid (GstVaapiDisplay * display, Window xid); + +Window +gst_vaapi_window_x11_get_xid (GstVaapiWindowX11 * window); + +gboolean +gst_vaapi_window_x11_is_foreign_xid (GstVaapiWindowX11 * window); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiWindowX11, gst_object_unref) + +G_END_DECLS + +#endif /* GST_VAAPI_WINDOW_X11_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_x11_priv.h b/gst-libs/gst/vaapi/gstvaapiwindow_x11_priv.h new file mode 100644 index 0000000000..751647fe7c --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow_x11_priv.h @@ -0,0 +1,79 @@ +/* + * gstvaapiwindow_x11_priv.h - VA/X11 window abstraction (private definitions) + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_WINDOW_X11_PRIV_H +#define GST_VAAPI_WINDOW_X11_PRIV_H + +#include "gstvaapiwindow_priv.h" + +#if HAVE_XRENDER +# include +#endif + +G_BEGIN_DECLS + +#define GST_VAAPI_WINDOW_X11_CAST(obj) ((GstVaapiWindowX11 *)(obj)) +#define GST_VAAPI_WINDOW_X11_GET_PRIVATE(obj) \ + gst_vaapi_window_x11_get_instance_private (GST_VAAPI_WINDOW_X11_CAST (obj)) + +#define GST_VAAPI_WINDOW_X11_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_WINDOW_X11, GstVaapiWindowX11Class)) + +typedef struct _GstVaapiWindowX11Private GstVaapiWindowX11Private; +typedef struct _GstVaapiWindowX11Class GstVaapiWindowX11Class; + +struct _GstVaapiWindowX11Private +{ + Atom atom_NET_WM_STATE; + Atom atom_NET_WM_STATE_FULLSCREEN; + guint is_mapped:1; + guint fullscreen_on_map:1; + gboolean need_vpp; +}; + +/** + * GstVaapiWindowX11: + * + * An X11 Window wrapper. + */ +struct _GstVaapiWindowX11 +{ + /*< private >*/ + GstVaapiWindow parent_instance; +}; + +/** + * GstVaapiWindowX11Class: + * + * An X11 Window wrapper class. + */ +struct _GstVaapiWindowX11Class +{ + /*< private >*/ + GstVaapiWindowClass parent_class; +}; + +G_END_DECLS + +#endif /* GST_VAAPI_WINDOW_X11_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiworkarounds.h b/gst-libs/gst/vaapi/gstvaapiworkarounds.h new file mode 100644 index 0000000000..967ef3eb6a --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiworkarounds.h @@ -0,0 +1,42 @@ +/* + * gstvaapiworkaround.h - GStreamer/VA workarounds + * + * Copyright (C) 2011-2012 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_WORKAROUNDS_H +#define GST_VAAPI_WORKAROUNDS_H + +G_BEGIN_DECLS + +/* + * Workaround to expose H.263 Baseline decode profile for drivers that + * support MPEG-4:2 Simple profile decoding. + */ +#define WORKAROUND_H263_BASELINE_DECODE_PROFILE (1) + +/* + * Workaround for qtdemux that does not report profiles for + * video/x-h263. Assume H.263 Baseline profile in this case. + */ +#define WORKAROUND_QTDEMUX_NO_H263_PROFILES (1) + +G_END_DECLS + +#endif /* GST_VAAPI_WORKAROUNDS_H */ diff --git a/gst-libs/gst/vaapi/meson.build b/gst-libs/gst/vaapi/meson.build new file mode 100644 index 0000000000..d4353a4361 --- /dev/null +++ b/gst-libs/gst/vaapi/meson.build @@ -0,0 +1,240 @@ +gstlibvaapi_sources = [ + 'gstvaapiblend.c', + 'gstvaapibufferproxy.c', + 'gstvaapicodec_objects.c', + 'gstvaapicontext.c', + 'gstvaapidecoder.c', + 'gstvaapidecoder_dpb.c', + 'gstvaapidecoder_h264.c', + 'gstvaapidecoder_h265.c', + 'gstvaapidecoder_jpeg.c', + 'gstvaapidecoder_mpeg2.c', + 'gstvaapidecoder_mpeg4.c', + 'gstvaapidecoder_objects.c', + 'gstvaapidecoder_unit.c', + 'gstvaapidecoder_vc1.c', + 'gstvaapidecoder_vp8.c', + 'gstvaapidecoder_vp9.c', + 'gstvaapidisplay.c', + 'gstvaapifilter.c', + 'gstvaapiimage.c', + 'gstvaapiimagepool.c', + 'gstvaapiminiobject.c', + 'gstvaapiparser_frame.c', + 'gstvaapiprofile.c', + 'gstvaapiprofilecaps.c', + 'gstvaapisubpicture.c', + 'gstvaapisurface.c', + 'gstvaapisurface_drm.c', + 'gstvaapisurfacepool.c', + 'gstvaapisurfaceproxy.c', + 'gstvaapitexture.c', + 'gstvaapitexturemap.c', + 'gstvaapiutils.c', + 'gstvaapiutils_core.c', + 'gstvaapiutils_h264.c', + 'gstvaapiutils_h265.c', + 'gstvaapiutils_h26x.c', + 'gstvaapiutils_mpeg2.c', + 'gstvaapiutils_vpx.c', + 'gstvaapivalue.c', + 'gstvaapivideopool.c', + 'gstvaapiwindow.c', + 'video-format.c', +] + +gstlibvaapi_headers = [ + 'gstvaapiblend.h', + 'gstvaapibufferproxy.h', + 'gstvaapidecoder.h', + 'gstvaapidecoder_h264.h', + 'gstvaapidecoder_h265.h', + 'gstvaapidecoder_jpeg.h', + 'gstvaapidecoder_mpeg2.h', + 'gstvaapidecoder_mpeg4.h', + 'gstvaapidecoder_vc1.h', + 'gstvaapidecoder_vp8.h', + 'gstvaapidecoder_vp9.h', + 'gstvaapidisplay.h', + 'gstvaapifilter.h', + 'gstvaapiimage.h', + 'gstvaapiimagepool.h', + 'gstvaapiprofile.h', + 'gstvaapiprofilecaps.h', + 'gstvaapisubpicture.h', + 'gstvaapisurface.h', + 'gstvaapisurface_drm.h', + 'gstvaapisurfacepool.h', + 'gstvaapisurfaceproxy.h', + 'gstvaapitexture.h', + 'gstvaapitexturemap.h', + 'gstvaapitypes.h', + 'gstvaapiutils_h264.h', + 'gstvaapiutils_h265.h', + 'gstvaapiutils_mpeg2.h', + 'gstvaapiutils_vpx.h', + 'gstvaapivalue.h', + 'gstvaapivideopool.h', + 'gstvaapiwindow.h', + 'video-format.h', +] + +if USE_ENCODERS + gstlibvaapi_sources += [ + 'gstvaapicodedbuffer.c', + 'gstvaapicodedbufferpool.c', + 'gstvaapicodedbufferproxy.c', + 'gstvaapiencoder.c', + 'gstvaapiencoder_h264.c', + 'gstvaapiencoder_h265.c', + 'gstvaapiencoder_jpeg.c', + 'gstvaapiencoder_mpeg2.c', + 'gstvaapiencoder_objects.c', + 'gstvaapiencoder_vp8.c', + ] + gstlibvaapi_headers += [ + 'gstvaapicodedbuffer.h', + 'gstvaapicodedbufferpool.h', + 'gstvaapicodedbufferproxy.h', + 'gstvaapiencoder.h', + 'gstvaapiencoder_h264.h', + 'gstvaapiencoder_h265.h', + 'gstvaapiencoder_jpeg.h', + 'gstvaapiencoder_mpeg2.h', + 'gstvaapiencoder_vp8.h', + ] +endif + +if USE_VP9_ENCODER + gstlibvaapi_sources += 'gstvaapiencoder_vp9.c' + gstlibvaapi_headers += 'gstvaapiencoder_vp9.h' +endif + +if USE_AV1_DECODER + gstlibvaapi_sources += 'gstvaapidecoder_av1.c' + gstlibvaapi_headers += 'gstvaapidecoder_av1.h' +endif + +if USE_DRM + gstlibvaapi_sources += [ + 'gstvaapidisplay_drm.c', + 'gstvaapiwindow_drm.c', + ] + gstlibvaapi_headers += [ + 'gstvaapidisplay_drm.h', + 'gstvaapiwindow_drm.h', + ] +endif + +if USE_X11 + gstlibvaapi_sources += [ + 'gstvaapidisplay_x11.c', + 'gstvaapiutils_x11.c', + 'gstvaapiwindow_x11.c', + ] + gstlibvaapi_headers += [ + 'gstvaapidisplay_x11.h', + 'gstvaapiwindow_x11.h', + ] +endif + +if USE_GLX + gstlibvaapi_sources += [ + 'gstvaapidisplay_glx.c', + 'gstvaapitexture_glx.c', + 'gstvaapiutils_glx.c', + 'gstvaapiwindow_glx.c', + ] + gstlibvaapi_headers += [ + 'gstvaapidisplay_glx.h', + 'gstvaapitexture.h', + 'gstvaapitexture_glx.h', + 'gstvaapiwindow_glx.h', + ] +endif + +if USE_EGL + gstlibvaapi_sources += [ + 'gstvaapidisplay_egl.c', + 'gstvaapisurface_egl.c', + 'gstvaapitexture_egl.c', + 'gstvaapiutils_egl.c', + 'gstvaapiwindow_egl.c', + ] + gstlibvaapi_headers += [ + 'gstvaapidisplay_egl.h', + 'gstvaapisurface_egl.h', + 'gstvaapitexture_egl.h', + 'gstvaapiwindow_egl.h', + ] +endif + +if USE_WAYLAND + # The XDG shell interface needs to be generated first + wayland_protocols_basedir = wayland_protocols_dep.get_pkgconfig_variable('pkgdatadir') + xdg_shell_xml_spec = join_paths(wayland_protocols_basedir, 'stable', 'xdg-shell', 'xdg-shell.xml') + xdg_shell_header = custom_target('vaapi-xdg-shell-client-header', + command: [ wayland_scanner_bin, 'client-header', '@INPUT@', '@OUTPUT@' ], + input: xdg_shell_xml_spec, + output: 'xdg-shell-client-protocol.h') + xdg_shell_code = custom_target('vaapi-xdg-shell-client-code', + command: [ wayland_scanner_bin, 'private-code', '@INPUT@', '@OUTPUT@' ], + input: xdg_shell_xml_spec, + output: 'xdg-shell-client-protocol.c') + dmabuf_xml_spec = join_paths(wayland_protocols_basedir, 'unstable', 'linux-dmabuf', 'linux-dmabuf-unstable-v1.xml') + dmabuf_header = custom_target('vaapi-dmabuf-client-header', + command: [ wayland_scanner_bin, 'client-header', '@INPUT@', '@OUTPUT@' ], + input: dmabuf_xml_spec, + output: 'linux-dmabuf-unstable-v1-client-protocol.h') + dmabuf_code = custom_target('vaapi-dmabuf-client-code', + command: [ wayland_scanner_bin, 'private-code', '@INPUT@', '@OUTPUT@' ], + input: dmabuf_xml_spec, + output: 'linux-dmabuf-unstable-v1-client-protocol.c') + + gstlibvaapi_sources += [ + 'gstvaapidisplay_wayland.c', + 'gstvaapiwindow_wayland.c', + xdg_shell_header, + xdg_shell_code, + dmabuf_header, + dmabuf_code, + ] + gstlibvaapi_headers += [ + 'gstvaapidisplay_wayland.h', + 'gstvaapiwindow_wayland.h', + ] +endif + +gstlibvaapi_deps = [ gstbase_dep, + gstvideo_dep, + gstgl_dep, + gstglproto_dep, + gstcodecparsers_dep, + libva_dep, + libm ] +if USE_DRM + gstlibvaapi_deps += [libva_drm_dep, libdrm_dep, libudev_dep] +endif +if USE_EGL + gstlibvaapi_deps += [egl_dep, gmodule_dep, gstglegl_dep] +endif +if USE_GLX + gstlibvaapi_deps += [libva_x11_dep, x11_dep, gl_dep, libdl_dep] +endif +if USE_WAYLAND + gstlibvaapi_deps += [libva_wayland_dep, gstglwayland_dep, wayland_client_dep, wayland_protocols_dep] +endif +if USE_X11 + gstlibvaapi_deps += [libva_x11_dep, x11_dep, xrandr_dep, gstglx11_dep] +endif + +gstlibvaapi = static_library('gstlibvaapi-@0@'.format(api_version), + gstlibvaapi_sources + gstlibvaapi_headers, + c_args : gstreamer_vaapi_args + [ '-DGST_USE_UNSTABLE_API', '-DGST_VAAPI_VERSION_ID="@0@"'.format(gst_version)], + include_directories: [configinc, libsinc], + dependencies : gstlibvaapi_deps, +) + +gstlibvaapi_dep = declare_dependency(link_with: gstlibvaapi, + include_directories : [libsinc], + dependencies : gstlibvaapi_deps) diff --git a/gst-libs/gst/vaapi/ogl_compat.h b/gst-libs/gst/vaapi/ogl_compat.h new file mode 100644 index 0000000000..2fa40e743c --- /dev/null +++ b/gst-libs/gst/vaapi/ogl_compat.h @@ -0,0 +1,104 @@ +/* + * ogl_compat.h - OpenGL compatiliby layer + * + * Copyright (C) 2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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 + */ + +#ifndef OGL_COMPAT_H +#define OGL_COMPAT_H + +typedef void GLvoid; +typedef char GLchar; +typedef unsigned char GLubyte; +typedef unsigned char GLboolean; +typedef int GLint; +typedef unsigned int GLuint; +typedef int GLsizei; +typedef float GLfloat; +typedef double GLdouble; +typedef GLuint GLenum; +typedef GLuint GLbitfield; +typedef GLfloat GLclampf; + +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_VERSION 0x1F02 +#define GL_EXTENSIONS 0x1F03 +#define GL_NEAREST 0x2600 +#define GL_LINEAR 0x2601 + +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_COLOR_BUFFER_BIT 0x00004000 +#define GL_FALSE 0 +#define GL_TRUE 1 +#define GL_NONE 0 + +#define GL_BLEND 0x0BE2 +#define GL_DEPTH_TEST 0x0B71 + +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_TEXTURE_EXTERNAL_OES 0x8D65 +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 + +#define GL_UNPACK_ALIGNMENT 0x0cf5 + +#define GL_TRIANGLE_FAN 0x0006 + +#define GL_BYTE 0x1400 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_SHORT 0x1402 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_INT 0x1404 +#define GL_UNSIGNED_INT 0x1405 +#define GL_FLOAT 0x1406 + +#define GL_ALPHA 0x1906 +#define GL_RGB 0x1907 +#define GL_RGBA 0x1908 +#define GL_LUMINANCE 0x1909 +#define GL_LUMINANCE_ALPHA 0x190A + +#define GL_REPEAT 0x2901 +#define GL_CLAMP_TO_EDGE 0x812F + +#define GL_VERTEX_ARRAY 0x8074 +#define GL_TEXTURE_COORD_ARRAY 0x8078 + +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_INFO_LOG_LENGTH 0x8B84 + +#define GL_BGRA_EXT 0x80e1 +#ifndef GL_R8 +#define GL_R8 GL_R8_EXT +#endif +#ifndef GL_RG8 +#define GL_RG8 GL_RG8_EXT +#endif + +#endif /* OGL_COMPAT_H */ diff --git a/gst-libs/gst/vaapi/sysdeps.h b/gst-libs/gst/vaapi/sysdeps.h new file mode 100644 index 0000000000..5e6dafb66a --- /dev/null +++ b/gst-libs/gst/vaapi/sysdeps.h @@ -0,0 +1,36 @@ +/* + * sysdeps.h - System-dependent definitions + * + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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 SYSDEPS_H +#define SYSDEPS_H + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include + +#endif /* SYSDEPS_H */ diff --git a/gst-libs/gst/vaapi/video-format.c b/gst-libs/gst/vaapi/video-format.c new file mode 100644 index 0000000000..dad7570c2e --- /dev/null +++ b/gst-libs/gst/vaapi/video-format.c @@ -0,0 +1,685 @@ +/* + * video-format.h - Video format helpers for VA-API + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:videoformat + * @short_description: Video format helpers for VA-API + */ + +#include "sysdeps.h" +#include "gstvaapicompat.h" +#include "gstvaapisurface.h" +#include "video-format.h" + +#define DEBUG 1 +#include "gst/vaapi/gstvaapidebug.h" + +#if USE_DRM +#include +#endif + +typedef struct _GstVideoFormatMapMap +{ + GstVideoFormat format; + uint32_t drm_format; + GstVaapiChromaType chroma_type; + VAImageFormat va_format; +} GstVideoFormatMap; + +#define VA_BYTE_ORDER_NOT_CARE 0 + +#if USE_DRM +#define MAKE_DRM_FORMAT(DRM_FORMAT) G_PASTE(DRM_FORMAT_,DRM_FORMAT) +#else +#define MAKE_DRM_FORMAT(DRM_FORMAT) 0 +#endif + +#define DEF_YUV(BYTE_ORDER, FORMAT, DRM_FORMAT, FOURCC, BPP, SUB) \ + { G_PASTE(GST_VIDEO_FORMAT_,FORMAT), \ + MAKE_DRM_FORMAT(DRM_FORMAT), \ + G_PASTE(GST_VAAPI_CHROMA_TYPE_YUV,SUB), \ + { VA_FOURCC FOURCC, BYTE_ORDER, BPP, }, } + +#define DEF_RGB(BYTE_ORDER, FORMAT, DRM, FOURCC, BPP, DEPTH, R,G,B,A) \ + { G_PASTE(GST_VIDEO_FORMAT_,FORMAT), \ + MAKE_DRM_FORMAT(DRM), \ + G_PASTE(GST_VAAPI_CHROMA_TYPE_RGB,BPP), \ + { VA_FOURCC FOURCC, BYTE_ORDER, BPP, DEPTH, R, G, B, A }, } + +/* Image formats, listed in HW order preference */ +/* XXX: The new added video format must be added to + * GST_VAAPI_FORMATS_ALL in header file to make it available to all + * vaapi element's pad cap template. */ +/* *INDENT-OFF* */ +static const GstVideoFormatMap gst_vaapi_video_default_formats[] = { + /* LSB and MSB video formats definitions are unclear and ambiguous. + * + * For MSB, there is no ambiguity: same order in define, memory and + * CPU. For example, + * + * RGBA is RGBA in memory and RGBA with channel mask R:0xFF0000 + * G:0x00FF0000 B:0x0000FF00 A:0x000000FF in CPU. + * + * For LSB, CPU's perspective and memory's perspective are + * different. For example, + * + * RGBA in LSB, from CPU's perspective, it's RGBA order in memory, + * but when it is stored in memory, because CPU's little + * endianness, it will be re-ordered, with mask R:0x000000FF + * G:0x0000FF00 B:0x00FF0000 A:0xFF000000. In other words, from + * memory's perspective, RGBA LSB is equal as ABGR MSB. + * + * These definitions are mixed used all over the media system and we + * need to correct the mapping form VA video format to GStreamer + * video format in both manners, especially for RGB format. + */ + + /* YUV formats */ + DEF_YUV (VA_BYTE_ORDER_NOT_CARE, NV12, NV12, ('N', 'V', '1', '2'), 12, 420), + DEF_YUV (VA_BYTE_ORDER_NOT_CARE, YV12, YVU420, ('Y', 'V', '1', '2'), 12, 420), + DEF_YUV (VA_BYTE_ORDER_NOT_CARE, I420, YUV420, ('I', '4', '2', '0'), 12, 420), + DEF_YUV (VA_BYTE_ORDER_NOT_CARE, YUY2, YUYV, ('Y', 'U', 'Y', '2'), 16, 422), + DEF_YUV (VA_BYTE_ORDER_NOT_CARE, UYVY, UYVY, ('U', 'Y', 'V', 'Y'), 16, 422), + + DEF_YUV (VA_BYTE_ORDER_NOT_CARE, Y444, YUV444, ('4', '4', '4', 'P'), 24, 444), + DEF_YUV (VA_BYTE_ORDER_NOT_CARE, GRAY8, INVALID, ('Y', '8', '0', '0'), 8, 400), + + DEF_YUV (VA_LSB_FIRST, P010_10LE, P010, ('P', '0', '1', '0'), 24, 420_10BPP), + DEF_YUV (VA_LSB_FIRST, P012_LE, P012, ('P', '0', '1', '2'), 24, 420_12BPP), + /* AYUV is a clear defined format by doc */ + DEF_YUV (VA_LSB_FIRST, VUYA, AYUV, ('A', 'Y', 'U', 'V'), 32, 444), + + DEF_YUV (VA_BYTE_ORDER_NOT_CARE, Y210, Y210, ('Y', '2', '1', '0'), 32, 422_10BPP), + DEF_YUV (VA_BYTE_ORDER_NOT_CARE, Y410, Y410, ('Y', '4', '1', '0'), 32, 444_10BPP), + DEF_YUV (VA_BYTE_ORDER_NOT_CARE, Y212_LE, Y212, ('Y', '2', '1', '2'), 32, 422_12BPP), + DEF_YUV (VA_BYTE_ORDER_NOT_CARE, Y412_LE, Y412, ('Y', '4', '1', '2'), 32, 444_12BPP), + + /* RGB formats */ + DEF_RGB (VA_LSB_FIRST, ARGB, BGRA8888, ('A', 'R', 'G', 'B'), 32, 32, 0x0000ff00, + 0x00ff0000, 0xff000000, 0x000000ff), + DEF_RGB (VA_LSB_FIRST, ARGB, BGRA8888, ('B', 'G', 'R', 'A'), 32, 32, 0x0000ff00, + 0x00ff0000, 0xff000000, 0x000000ff), + DEF_RGB (VA_MSB_FIRST, ARGB, BGRA8888, ('A', 'R', 'G', 'B'), 32, 32, 0x00ff0000, + 0x0000ff00, 0x000000ff, 0xff000000), + + DEF_RGB (VA_LSB_FIRST, xRGB, BGRX8888, ('X', 'R', 'G', 'B'), 32, 24, 0x0000ff00, + 0x00ff0000, 0xff000000, 0x00000000), + DEF_RGB (VA_LSB_FIRST, xRGB, BGRX8888, ('B', 'G', 'R', 'X'), 32, 24, 0x0000ff00, + 0x00ff0000, 0xff000000, 0x00000000), + DEF_RGB (VA_MSB_FIRST, xRGB, BGRX8888, ('X', 'R', 'G', 'B'), 32, 24, 0x00ff0000, + 0x0000ff00, 0x000000ff, 0x00000000), + + DEF_RGB (VA_LSB_FIRST, RGBA, ABGR8888, ('R', 'G', 'B', 'A'), 32, 32, 0x000000ff, + 0x0000ff00, 0x00ff0000, 0xff000000), + DEF_RGB (VA_LSB_FIRST, RGBA, ABGR8888, ('A', 'B', 'G', 'R'), 32, 32, 0x000000ff, + 0x0000ff00, 0x00ff0000, 0xff000000), + DEF_RGB (VA_MSB_FIRST, RGBA, ABGR8888, ('R', 'G', 'B', 'A'), 32, 32, 0xff000000, + 0x00ff0000, 0x0000ff00, 0x000000ff), + + DEF_RGB (VA_LSB_FIRST, RGBx, XBGR8888, ('R', 'G', 'B', 'X'), 32, 24, 0x000000ff, + 0x0000ff00, 0x00ff0000, 0x00000000), + DEF_RGB (VA_LSB_FIRST, RGBx, XBGR8888, ('X', 'B', 'G', 'R'), 32, 24, 0x000000ff, + 0x0000ff00, 0x00ff0000, 0x00000000), + DEF_RGB (VA_MSB_FIRST, RGBx, XBGR8888, ('R', 'G', 'B', 'X'), 32, 24, 0xff000000, + 0x00ff0000, 0x0000ff00, 0x00000000), + + DEF_RGB (VA_LSB_FIRST, ABGR, RGBA8888, ('A', 'B', 'G', 'R'), 32, 32, 0xff000000, + 0x00ff0000, 0x0000ff00, 0x000000ff), + DEF_RGB (VA_LSB_FIRST, ABGR, RGBA8888, ('R', 'G', 'B', 'A'), 32, 32, 0xff000000, + 0x00ff0000, 0x0000ff00, 0x000000ff), + DEF_RGB (VA_MSB_FIRST, ABGR, RGBA8888, ('A', 'B', 'G', 'R'), 32, 32, 0x000000ff, + 0x0000ff00, 0x00ff0000, 0xff000000), + + DEF_RGB (VA_LSB_FIRST, xBGR, RGBX8888, ('X', 'B', 'G', 'R'), 32, 24, 0xff000000, + 0x00ff0000, 0x0000ff00, 0x00000000), + DEF_RGB (VA_LSB_FIRST, xBGR, RGBX8888, ('R', 'G', 'B', 'X'), 32, 24, 0xff000000, + 0x00ff0000, 0x0000ff00, 0x00000000), + DEF_RGB (VA_MSB_FIRST, xBGR, RGBX8888, ('X', 'B', 'G', 'R'), 32, 24, 0x000000ff, + 0x0000ff00, 0x00ff0000, 0x00000000), + + DEF_RGB (VA_LSB_FIRST, BGRA, ARGB8888, ('B', 'G', 'R', 'A'), 32, 32, 0x00ff0000, + 0x0000ff00, 0x000000ff, 0xff000000), + DEF_RGB (VA_LSB_FIRST, BGRA, ARGB8888, ('A', 'R', 'G', 'B'), 32, 32, 0x00ff0000, + 0x0000ff00, 0x000000ff, 0xff000000), + DEF_RGB (VA_MSB_FIRST, BGRA, ARGB8888, ('B', 'G', 'R', 'A'), 32, 32, 0x0000ff00, + 0x00ff0000, 0xff000000, 0x000000ff), + + DEF_RGB (VA_LSB_FIRST, BGRx, XRGB8888, ('B', 'G', 'R', 'X'), 32, 24, 0x00ff0000, + 0x0000ff00, 0x000000ff, 0x00000000), + DEF_RGB (VA_LSB_FIRST, BGRx, XRGB8888, ('X', 'R', 'G', 'B'), 32, 24, 0x00ff0000, + 0x0000ff00, 0x000000ff, 0x00000000), + DEF_RGB (VA_MSB_FIRST, BGRx, XRGB8888, ('B', 'G', 'R', 'X'), 32, 24, 0x0000ff00, + 0x00ff0000, 0xff000000, 0x00000000), + + DEF_RGB (VA_BYTE_ORDER_NOT_CARE, RGB16, RGB565, ('R', 'G', '1', '6'), 16, 16, + 0x0000f800, 0x000007e0, 0x0000001f, 0x00000000), + DEF_RGB (VA_BYTE_ORDER_NOT_CARE, RGB, RGB888, ('R', 'G', '2', '4'), 32, 24, + 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000), + DEF_RGB (VA_LSB_FIRST, BGR10A2_LE, ARGB2101010, ('A', 'R', '3', '0'), 32, 30, + 0x3ff00000, 0x000ffc00, 0x000003ff, 0x30000000), + {0,} +}; +/* *INDENT-ON* */ + +#undef DEF_RGB +#undef DEF_YUV + +static GArray *gst_vaapi_video_formats_map; + +static inline gboolean +va_format_is_rgb (const VAImageFormat * va_format) +{ + return va_format->depth != 0; +} + +static inline gboolean +va_format_is_yuv (const VAImageFormat * va_format) +{ + return va_format->depth == 0; +} + +static inline gboolean +va_format_is_same_rgb (const VAImageFormat * fmt1, const VAImageFormat * fmt2) +{ + return (fmt1->red_mask == fmt2->red_mask && + fmt1->green_mask == fmt2->green_mask && + fmt1->blue_mask == fmt2->blue_mask && + fmt1->alpha_mask == fmt2->alpha_mask); +} + +static inline gboolean +va_format_is_same (const VAImageFormat * fmt1, const VAImageFormat * fmt2) +{ + if (fmt1->fourcc != fmt2->fourcc) + return FALSE; + if (fmt1->byte_order != VA_BYTE_ORDER_NOT_CARE && + fmt2->byte_order != VA_BYTE_ORDER_NOT_CARE && + fmt1->byte_order != fmt2->byte_order) + return FALSE; + + return va_format_is_rgb (fmt1) ? va_format_is_same_rgb (fmt1, fmt2) : TRUE; +} + +static const GstVideoFormatMap * +get_map_in_default_by_gst_format (GstVideoFormat format) +{ + const GstVideoFormatMap *m; + for (m = gst_vaapi_video_default_formats; m->format; m++) { + if (m->format == format) + return m; + } + return NULL; +} + +static const GstVideoFormatMap * +get_map_in_default_by_va_format (const VAImageFormat * va_format) +{ + const GstVideoFormatMap *m, *n; + + n = NULL; + for (m = gst_vaapi_video_default_formats; m->format; m++) { + if (va_format_is_same (&m->va_format, va_format)) { + /* Should not map to VAImageFormat to same GstVideoFormat */ + g_assert (n == NULL); + n = m; + } + } + return n; +} + +static const GstVideoFormatMap * +get_map_by_gst_format (const GArray * formats, GstVideoFormat format) +{ + const GstVideoFormatMap *entry; + guint i; + + for (i = 0; i < formats->len; i++) { + entry = &g_array_index (formats, GstVideoFormatMap, i); + if (entry->format == format) + return entry; + } + return NULL; +} + +static const GstVideoFormatMap * +get_map_by_va_format (const VAImageFormat * va_format) +{ + const GArray *formats = gst_vaapi_video_formats_map; + const GstVideoFormatMap *entry; + guint i; + + for (i = 0; i < formats->len; i++) { + entry = &g_array_index (formats, GstVideoFormatMap, i); + if (va_format_is_same (&entry->va_format, va_format)) + return entry; + } + return NULL; +} + + +static guint +get_fmt_score_in_default (GstVideoFormat format) +{ + const GstVideoFormatMap *const m = get_map_in_default_by_gst_format (format); + + return m ? (m - &gst_vaapi_video_default_formats[0]) : G_MAXUINT; +} + +static gint +video_format_compare_by_score (gconstpointer a, gconstpointer b) +{ + const GstVideoFormatMap *m1 = (GstVideoFormatMap *) a; + const GstVideoFormatMap *m2 = (GstVideoFormatMap *) b; + + return ((gint) get_fmt_score_in_default (m1->format) - + (gint) get_fmt_score_in_default (m2->format)); +} + +/** + * gst_vaapi_video_format_to_string: + * @format: a #GstVideoFormat + * + * Returns the string representation of the @format argument. + * + * Return value: string representation of @format, or %NULL if unknown + * or unsupported. + */ +const gchar * +gst_vaapi_video_format_to_string (GstVideoFormat format) +{ + return gst_video_format_to_string (format); +} + +/** + * gst_vaapi_video_format_is_rgb: + * @format: a #GstVideoFormat + * + * Checks whether the format is an RGB format. + * + * Return value: %TRUE if @format is RGB format + */ +gboolean +gst_vaapi_video_format_is_rgb (GstVideoFormat format) +{ + const GstVideoFormatMap *const m = + get_map_by_gst_format (gst_vaapi_video_formats_map, format); + return m && va_format_is_rgb (&m->va_format); +} + +/** + * gst_vaapi_video_format_is_yuv: + * @format: a #GstVideoFormat + * + * Checks whether the format is an YUV format. + * + * Return value: %TRUE if @format is YUV format + */ +gboolean +gst_vaapi_video_format_is_yuv (GstVideoFormat format) +{ + const GstVideoFormatMap *const m = + get_map_by_gst_format (gst_vaapi_video_formats_map, format); + return m && va_format_is_yuv (&m->va_format); +} + +/** + * gst_vaapi_video_format_from_va_fourcc: + * @fourcc: a FOURCC value + * + * Converts a VA fourcc into the corresponding #GstVideoFormat. If no + * matching fourcc was found, then zero is returned. + * + * Return value: the #GstVideoFormat corresponding to the VA @fourcc + */ +GstVideoFormat +gst_vaapi_video_format_from_va_fourcc (guint32 fourcc) +{ + const GArray *map = gst_vaapi_video_formats_map; + const GstVideoFormatMap *m; + guint i; + + /* Note: VA fourcc values are now standardized and shall represent + a unique format. The associated VAImageFormat is just a hint to + determine RGBA component ordering */ + for (i = 0; i < map->len; i++) { + m = &g_array_index (map, GstVideoFormatMap, i); + if (m->va_format.fourcc == fourcc) + return m->format; + } + return GST_VIDEO_FORMAT_UNKNOWN; +} + +/** + * gst_vaapi_video_format_from_va_format: + * @va_format: a #VAImageFormat + * + * Converts a VA image format into the corresponding #GstVideoFormat. + * If the image format cannot be represented by #GstVideoFormat, + * then zero is returned. + * + * Return value: the #GstVideoFormat describing the @va_format + */ +GstVideoFormat +gst_vaapi_video_format_from_va_format (const VAImageFormat * va_format) +{ + const GstVideoFormatMap *const m = get_map_by_va_format (va_format); + return m ? m->format : GST_VIDEO_FORMAT_UNKNOWN; +} + +/** + * gst_vaapi_video_format_to_va_format: + * @format: a #GstVideoFormat + * + * Converts a #GstVideoFormat into the corresponding VA image + * format. If no matching VA image format was found, %NULL is returned + * and this error must be reported to be fixed. + * + * Return value: the VA image format, or %NULL if none was found + */ +const VAImageFormat * +gst_vaapi_video_format_to_va_format (GstVideoFormat format) +{ + const GstVideoFormatMap *const m = + get_map_by_gst_format (gst_vaapi_video_formats_map, format); + return m ? &m->va_format : NULL; +} + +/** + * gst_vaapi_video_format_get_chroma_type: + * @format: a #GstVideoFormat + * + * Converts a #GstVideoFormat into the corresponding #GstVaapiChromaType + * format. + * + * Return value: the #GstVaapiChromaType format, or zero if no match + * was found. + */ +guint +gst_vaapi_video_format_get_chroma_type (GstVideoFormat format) +{ + const GstVideoFormatMap *const m = + get_map_by_gst_format (gst_vaapi_video_formats_map, format); + return m ? m->chroma_type : 0; +} + +/** + * gst_vaapi_video_format_get_score: + * @format: a #GstVideoFormat + * + * Determines how "native" is this @format. The lower is the returned + * score, the best format this is for the underlying hardware. + * + * Return value: the @format score, or %G_MAXUINT if none was found + */ +guint +gst_vaapi_video_format_get_score (GstVideoFormat format) +{ + return get_fmt_score_in_default (format); +} + +/** + * gst_vaapi_video_format_from_chroma: + * @chroma_type: a #GstVaapiChromaType + * + * Returns the "preferred" pixel format that matches with + * @chroma_type. + * + * Returns: the preferred pixel format for @chroma_type + **/ +GstVideoFormat +gst_vaapi_video_format_from_chroma (guint chroma_type) +{ + switch (chroma_type) { + case GST_VAAPI_CHROMA_TYPE_YUV422: + return GST_VIDEO_FORMAT_YUY2; + case GST_VAAPI_CHROMA_TYPE_YUV400: + return GST_VIDEO_FORMAT_GRAY8; + case GST_VAAPI_CHROMA_TYPE_YUV420: + case GST_VAAPI_CHROMA_TYPE_RGB32: /* GstVideoGLTextureUploadMeta */ + return GST_VIDEO_FORMAT_NV12; + case GST_VAAPI_CHROMA_TYPE_YUV420_10BPP: + return GST_VIDEO_FORMAT_P010_10LE; + case GST_VAAPI_CHROMA_TYPE_YUV420_12BPP: + return GST_VIDEO_FORMAT_P012_LE; + case GST_VAAPI_CHROMA_TYPE_YUV444: + return GST_VIDEO_FORMAT_VUYA; + case GST_VAAPI_CHROMA_TYPE_YUV422_10BPP: + return GST_VIDEO_FORMAT_Y210; + case GST_VAAPI_CHROMA_TYPE_YUV444_10BPP: + return GST_VIDEO_FORMAT_Y410; + case GST_VAAPI_CHROMA_TYPE_YUV444_12BPP: + return GST_VIDEO_FORMAT_Y412_LE; + case GST_VAAPI_CHROMA_TYPE_YUV422_12BPP: + return GST_VIDEO_FORMAT_Y212_LE; + default: + return GST_VIDEO_FORMAT_UNKNOWN; + } +} + +/** + * gst_vaapi_video_format_get_best_native: + * @format: a #GstVideoFormat + * + * Returns the best "native" pixel format that matches a particular + * color-space. + * + * Returns: the #GstVideoFormat with the corresponding best native + * format for #GstVaapiSurface + **/ +GstVideoFormat +gst_vaapi_video_format_get_best_native (GstVideoFormat format) +{ + GstVaapiChromaType chroma_type; + + if (format == GST_VIDEO_FORMAT_ENCODED) + return GST_VIDEO_FORMAT_NV12; + chroma_type = gst_vaapi_video_format_get_chroma_type (format); + return gst_vaapi_video_format_from_chroma (chroma_type); +} + +/** + * gst_vaapi_video_format_get_formats_by_chroma: + * @chroma: a #GstVaapiChromaType + * + * Get all #GstVideoFormat which belong to #GstVaapiChromaType. + * + * Returns: an array of #GstVideoFormat. + **/ +GArray * +gst_vaapi_video_format_get_formats_by_chroma (guint chroma) +{ + const GstVideoFormatMap *entry; + GArray *formats; + guint i; + + formats = g_array_new (FALSE, FALSE, sizeof (GstVideoFormat)); + if (!formats) + return NULL; + + for (i = 0; i < gst_vaapi_video_formats_map->len; i++) { + entry = &g_array_index (gst_vaapi_video_formats_map, GstVideoFormatMap, i); + if (entry->chroma_type == chroma) + g_array_append_val (formats, entry->format); + } + + if (formats->len == 0) { + g_array_unref (formats); + return NULL; + } + + return formats; +} + +struct ImageFormatsData +{ + VAImageFormat *formats; + guint n; +}; + +static gpointer +video_format_create_map_once (gpointer data) +{ + const GstVideoFormatMap *src_entry, *entry; + guint i; + VAImageFormat *formats = ((struct ImageFormatsData *) data)->formats; + guint n = ((struct ImageFormatsData *) data)->n; + GArray *array = NULL; + + array = g_array_new (FALSE, TRUE, sizeof (GstVideoFormatMap)); + if (array == NULL) + return NULL; + + /* All the YUV format has no ambiguity */ + for (i = 0; i < G_N_ELEMENTS (gst_vaapi_video_default_formats); i++) { + if (va_format_is_yuv (&gst_vaapi_video_default_formats[i].va_format)) + g_array_append_val (array, gst_vaapi_video_default_formats[i]); + } + + if (formats) { + for (i = 0; i < n; i++) { + if (!va_format_is_rgb (&formats[i])) + continue; + + src_entry = get_map_in_default_by_va_format (&formats[i]); + if (src_entry) { + entry = get_map_by_gst_format (array, src_entry->format); + if (entry && !va_format_is_same (&entry->va_format, &formats[i])) { + GST_INFO ("va_format1 with fourcc %" GST_FOURCC_FORMAT + " byte order: %d, BPP: %d, depth %d, red mask 0x%4x," + " green mask 0x%4x, blue mask 0x%4x, alpha mask 0x%4x" + " conflict with va_foramt2 fourcc %" GST_FOURCC_FORMAT + " byte order: %d, BPP: %d, depth %d, red mask 0x%4x," + " green mask 0x%4x, blue mask 0x%4x, alpha mask 0x%4x." + " Both map to the same GST format: %s, which is not" + " allowed, va_format1 will be skipped", + GST_FOURCC_ARGS (entry->va_format.fourcc), + entry->va_format.byte_order, entry->va_format.bits_per_pixel, + entry->va_format.depth, entry->va_format.red_mask, + entry->va_format.green_mask, entry->va_format.blue_mask, + entry->va_format.alpha_mask, + GST_FOURCC_ARGS (formats[i].fourcc), + formats[i].byte_order, formats[i].bits_per_pixel, + formats[i].depth, formats[i].red_mask, formats[i].green_mask, + formats[i].blue_mask, formats[i].alpha_mask, + gst_video_format_to_string (entry->format)); + continue; + } + g_array_append_val (array, (*src_entry)); + } + + GST_LOG ("%s to map RGB va_format with fourcc: %" + GST_FOURCC_FORMAT + ", byte order: %d BPP: %d, depth %d, red mask %4x," + " green mask %4x, blue mask %4x, alpha mask %4x to %s gstreamer" + " video format", src_entry ? "succeed" : "failed", + GST_FOURCC_ARGS (formats[i].fourcc), formats[i].byte_order, + formats[i].bits_per_pixel, formats[i].depth, formats[i].red_mask, + formats[i].green_mask, formats[i].blue_mask, formats[i].alpha_mask, + src_entry ? gst_video_format_to_string (src_entry->format) : "any"); + } + } + + g_array_sort (array, video_format_compare_by_score); + gst_vaapi_video_formats_map = array; + return array; +} + +/** + * gst_vaapi_video_format_new_map: + * @formats: all #VAImageFormat need to map + * @n: the number of VAImageFormat + * + * Return: True if create successfully. + **/ +gboolean +gst_vaapi_video_format_create_map (VAImageFormat * formats, guint n) +{ + static GOnce once = G_ONCE_INIT; + struct ImageFormatsData data = { formats, n }; + + g_once (&once, video_format_create_map_once, &data); + + return once.retval != NULL; +} + +/** + * gst_vaapi_drm_format_from_va_fourcc: + * @fourcc: a FOURCC value + * + * Converts a VA fourcc into the corresponding DRM_FORMAT_*. If no + * matching fourcc was found, then DRM_FORMAT_INVALID is returned. + * + * Return value: the DRM_FORMAT_* corresponding to the VA @fourcc + * + * Since: 1.18 + */ +guint +gst_vaapi_drm_format_from_va_fourcc (guint32 fourcc) +{ +#if USE_DRM + const GArray *map = gst_vaapi_video_formats_map; + const GstVideoFormatMap *m; + guint i; + + /* Note: VA fourcc values are now standardized and shall represent + a unique format. The associated VAImageFormat is just a hint to + determine RGBA component ordering */ + for (i = 0; i < map->len; i++) { + m = &g_array_index (map, GstVideoFormatMap, i); + if (m->va_format.fourcc == fourcc) + return m->drm_format; + } + return DRM_FORMAT_INVALID; +#else + return 0; +#endif +} + +/** + * gst_vaapi_video_format_from_drm_format: + * @drm_format: a DRM format value + * + * Converts a DRM_FORMAT_* to the corresponding GstVideoFormat. If no + * matching fourcc was found, then DRM_FORMAT_INVALID is returned. + * + * Return value: GstVideoFormat corresponding to the @drm_format + * + * Since: 1.18 + */ +GstVideoFormat +gst_vaapi_video_format_from_drm_format (guint drm_format) +{ +#if USE_DRM + const GArray *map = gst_vaapi_video_formats_map; + const GstVideoFormatMap *m; + guint i; + + for (i = 0; i < map->len; i++) { + m = &g_array_index (map, GstVideoFormatMap, i); + if (m->drm_format == drm_format) + return m->format; + } +#endif + return GST_VIDEO_FORMAT_UNKNOWN; +} diff --git a/gst-libs/gst/vaapi/video-format.h b/gst-libs/gst/vaapi/video-format.h new file mode 100644 index 0000000000..22e14fbfd8 --- /dev/null +++ b/gst-libs/gst/vaapi/video-format.h @@ -0,0 +1,81 @@ +/* + * video-format.h - Video format helpers for VA-API + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_VIDEO_FORMAT_H +#define GST_VAAPI_VIDEO_FORMAT_H + +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_FORMATS_ALL "{ ENCODED, " \ + "NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, P012_LE, VUYA, Y210, Y410, Y212_LE, Y412_LE, " \ + "ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE " \ + "}" + +const gchar * +gst_vaapi_video_format_to_string (GstVideoFormat format); + +gboolean +gst_vaapi_video_format_is_rgb (GstVideoFormat format); + +gboolean +gst_vaapi_video_format_is_yuv (GstVideoFormat format); + +GstVideoFormat +gst_vaapi_video_format_from_va_fourcc (guint32 fourcc); + +GstVideoFormat +gst_vaapi_video_format_from_va_format (const VAImageFormat * va_format); + +const VAImageFormat * +gst_vaapi_video_format_to_va_format (GstVideoFormat format); + +guint +gst_vaapi_video_format_get_chroma_type (GstVideoFormat format); + +guint +gst_vaapi_video_format_get_score (GstVideoFormat format); + +GstVideoFormat +gst_vaapi_video_format_from_chroma (guint chroma); + +GstVideoFormat +gst_vaapi_video_format_get_best_native (GstVideoFormat format); + +GArray * +gst_vaapi_video_format_get_formats_by_chroma (guint chroma); + +gboolean +gst_vaapi_video_format_create_map (VAImageFormat * formats, guint n); + +guint +gst_vaapi_drm_format_from_va_fourcc (guint32 fourcc); + +GstVideoFormat +gst_vaapi_video_format_from_drm_format (guint drm_format); + +G_END_DECLS + +#endif /* GST_VAAPI_VIDEO_FORMAT_H */ diff --git a/gst-libs/meson.build b/gst-libs/meson.build new file mode 100644 index 0000000000..668dcbaaff --- /dev/null +++ b/gst-libs/meson.build @@ -0,0 +1 @@ +subdir('gst') diff --git a/gst/meson.build b/gst/meson.build new file mode 100644 index 0000000000..a8719a14c0 --- /dev/null +++ b/gst/meson.build @@ -0,0 +1 @@ +subdir('vaapi') diff --git a/gst/vaapi/gstcompat.h b/gst/vaapi/gstcompat.h new file mode 100644 index 0000000000..c953783fd1 --- /dev/null +++ b/gst/vaapi/gstcompat.h @@ -0,0 +1,28 @@ +/* + * gstcompat.h - Compatibility glue for GStreamer + * + * Copyright (C) 2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_COMPAT_H +#define GST_COMPAT_H + +#include "gst/vaapi/sysdeps.h" + +#endif /* GST_COMPAT_H */ diff --git a/gst/vaapi/gstvaapi.c b/gst/vaapi/gstvaapi.c new file mode 100644 index 0000000000..3532624839 --- /dev/null +++ b/gst/vaapi/gstvaapi.c @@ -0,0 +1,245 @@ +/* + * gstvaapi.c - VA-API element registration + * + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * Copyright (C) 2011 Collabora Ltd. + * Author: Nicolas Dufresne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gstcompat.h" +#include "gstvaapidecode.h" +#include "gstvaapioverlay.h" +#include "gstvaapipostproc.h" +#include "gstvaapisink.h" +#include "gstvaapidecodebin.h" + +#if USE_ENCODERS +#include "gstvaapiencode_h264.h" +#include "gstvaapiencode_mpeg2.h" +#include "gstvaapiencode_jpeg.h" +#include "gstvaapiencode_vp8.h" +#include "gstvaapiencode_h265.h" + +#if USE_VP9_ENCODER +#include "gstvaapiencode_vp9.h" +#endif +#endif + +gboolean _gst_vaapi_has_video_processing = FALSE; + +#define PLUGIN_NAME "vaapi" +#define PLUGIN_DESC "VA-API based elements" +#define PLUGIN_LICENSE "LGPL" + +static void +plugin_add_dependencies (GstPlugin * plugin) +{ + const gchar *envvars[] = { "GST_VAAPI_ALL_DRIVERS", "LIBVA_DRIVER_NAME", + "DISPLAY", "WAYLAND_DISPLAY", NULL + }; + const gchar *kernel_paths[] = { "/dev/dri", NULL }; + const gchar *kernel_names[] = { "card", "render", NULL }; + + /* features get updated upon changes in /dev/dri/card* */ + gst_plugin_add_dependency (plugin, NULL, kernel_paths, kernel_names, + GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_PREFIX); + + /* features get updated upon changes in VA environment variables */ + gst_plugin_add_dependency (plugin, envvars, NULL, NULL, + GST_PLUGIN_DEPENDENCY_FLAG_NONE); + + /* features get updated upon changes in default VA drivers + * directory */ + gst_plugin_add_dependency_simple (plugin, "LIBVA_DRIVERS_PATH", + VA_DRIVERS_PATH, "_drv_video.so", + GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_SUFFIX | + GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_DEFAULT_ONLY); +} + +static GArray * +profiles_get_codecs (GArray * profiles) +{ + guint i; + GArray *codecs; + GstVaapiProfile profile; + GstVaapiCodec codec; + + codecs = g_array_new (FALSE, FALSE, sizeof (GstVaapiCodec)); + if (!codecs) + return NULL; + + for (i = 0; i < profiles->len; i++) { + profile = g_array_index (profiles, GstVaapiProfile, i); + codec = gst_vaapi_profile_get_codec (profile); + if (gst_vaapi_codecs_has_codec (codecs, codec)) + continue; + g_array_append_val (codecs, codec); + } + + return codecs; +} + +static GArray * +display_get_decoder_codecs (GstVaapiDisplay * display) +{ + GArray *profiles, *codecs; + + profiles = gst_vaapi_display_get_decode_profiles (display); + if (!profiles) + return NULL; + + codecs = profiles_get_codecs (profiles); + g_array_unref (profiles); + return codecs; +} + +#if USE_ENCODERS +static GArray * +display_get_encoder_codecs (GstVaapiDisplay * display) +{ + GArray *profiles, *codecs; + + profiles = gst_vaapi_display_get_encode_profiles (display); + if (!profiles) + return NULL; + + codecs = profiles_get_codecs (profiles); + g_array_unref (profiles); + return codecs; +} + +typedef struct _GstVaapiEncoderMap GstVaapiEncoderMap; +struct _GstVaapiEncoderMap +{ + GstVaapiCodec codec; + guint rank; + const gchar *name; + GType (*register_type) (GstVaapiDisplay * display); +}; + +#define DEF_ENC(CODEC,codec) \ + {GST_VAAPI_CODEC_##CODEC, \ + GST_RANK_PRIMARY, \ + "vaapi" G_STRINGIFY (codec) "enc", \ + gst_vaapiencode_##codec##_register_type} + +static const GstVaapiEncoderMap vaapi_encode_map[] = { + DEF_ENC (H264, h264), + DEF_ENC (MPEG2, mpeg2), + DEF_ENC (JPEG, jpeg), + DEF_ENC (VP8, vp8), +#if USE_VP9_ENCODER + DEF_ENC (VP9, vp9), +#endif + DEF_ENC (H265, h265), +}; + +#undef DEF_ENC + +static void +gst_vaapiencode_register (GstPlugin * plugin, GstVaapiDisplay * display) +{ + guint i, j; + GArray *codecs; + GstVaapiCodec codec; + + codecs = display_get_encoder_codecs (display); + if (!codecs) + return; + + for (i = 0; i < codecs->len; i++) { + codec = g_array_index (codecs, GstVaapiCodec, i); + for (j = 0; j < G_N_ELEMENTS (vaapi_encode_map); j++) { + if (vaapi_encode_map[j].codec == codec) { + gst_element_register (plugin, vaapi_encode_map[j].name, + vaapi_encode_map[j].rank, + vaapi_encode_map[j].register_type (display)); + break; + } + } + } + + g_array_unref (codecs); +} +#endif + +static gboolean +plugin_init (GstPlugin * plugin) +{ + GstVaapiDisplay *display; + GArray *decoders; + guint rank; + + plugin_add_dependencies (plugin); + + display = gst_vaapi_create_test_display (); + if (!display) + goto error_no_display; + if (!gst_vaapi_driver_is_whitelisted (display)) + goto unsupported_driver; + + _gst_vaapi_has_video_processing = + gst_vaapi_display_has_video_processing (display); + + decoders = display_get_decoder_codecs (display); + if (decoders) { + gst_vaapidecode_register (plugin, decoders); + g_array_unref (decoders); + } + + if (_gst_vaapi_has_video_processing) + gst_vaapioverlay_register (plugin, display); + + gst_element_register (plugin, "vaapipostproc", + GST_RANK_NONE, GST_TYPE_VAAPIPOSTPROC); + + gst_element_register (plugin, "vaapidecodebin", + GST_RANK_PRIMARY + 2, GST_TYPE_VAAPI_DECODE_BIN); + + rank = GST_RANK_SECONDARY; + if (g_getenv ("WAYLAND_DISPLAY")) + rank = GST_RANK_MARGINAL; + gst_element_register (plugin, "vaapisink", rank, GST_TYPE_VAAPISINK); + +#if USE_ENCODERS + gst_vaapiencode_register (plugin, display); +#endif + + gst_object_unref (display); + + return TRUE; + + /* ERRORS: */ +error_no_display: + { + GST_WARNING ("Cannot create a VA display"); + /* Avoid blacklisting: failure to create a display could be a + * transient condition */ + return TRUE; + } +unsupported_driver: + { + gst_object_unref (display); + return TRUE; /* return TRUE to avoid get blacklisted */ + } +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, + vaapi, PLUGIN_DESC, plugin_init, + PACKAGE_VERSION, PLUGIN_LICENSE, PACKAGE, PACKAGE_BUGREPORT) diff --git a/gst/vaapi/gstvaapi.h b/gst/vaapi/gstvaapi.h new file mode 100644 index 0000000000..f5859508f1 --- /dev/null +++ b/gst/vaapi/gstvaapi.h @@ -0,0 +1,30 @@ +/* + * gstvaapi.h - VA-API element registration + * + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * Copyright (C) 2011 Collabora Ltd. + * Author: Nicolas Dufresne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef __GST_VAAPI_H__ +#define __GST_VAAPI_H__ + +G_GNUC_INTERNAL extern gboolean _gst_vaapi_has_video_processing; + +#endif /* __GST_VAAPI_H__ */ diff --git a/gst/vaapi/gstvaapidecode.c b/gst/vaapi/gstvaapidecode.c new file mode 100644 index 0000000000..10be755904 --- /dev/null +++ b/gst/vaapi/gstvaapidecode.c @@ -0,0 +1,1648 @@ +/* + * gstvaapidecode.c - VA-API video decoder + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gstcompat.h" +#include +#include + +#include "gstvaapidecode.h" +#include "gstvaapidecode_props.h" +#include "gstvaapipluginutil.h" +#include "gstvaapivideobuffer.h" +#if (USE_GLX || USE_EGL) +#include "gstvaapivideometa_texture.h" +#endif +#include "gstvaapivideobufferpool.h" +#include "gstvaapivideomemory.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#if USE_AV1_DECODER +#include +#endif + +#define GST_PLUGIN_NAME "vaapidecode" +#define GST_PLUGIN_DESC "A VA-API based video decoder" + +#define GST_VAAPI_DECODE_FLOW_PARSE_DATA GST_FLOW_CUSTOM_SUCCESS_2 + +GST_DEBUG_CATEGORY_STATIC (gst_debug_vaapidecode); +#ifndef GST_DISABLE_GST_DEBUG +#define GST_CAT_DEFAULT gst_debug_vaapidecode +#else +#define GST_CAT_DEFAULT NULL +#endif + +#define GST_VAAPI_DECODE_PARAMS_QDATA \ + g_quark_from_static_string("vaapidec-params") + +/* Default templates */ +#define GST_CAPS_CODEC(CODEC) CODEC "; " + +/* *INDENT-OFF* */ +static const char gst_vaapidecode_sink_caps_str[] = + GST_CAPS_CODEC("video/mpeg, mpegversion=2, systemstream=(boolean)false") + GST_CAPS_CODEC("video/mpeg, mpegversion=4") + GST_CAPS_CODEC("video/x-divx") + GST_CAPS_CODEC("video/x-xvid") + GST_CAPS_CODEC("video/x-h263") + GST_CAPS_CODEC("video/x-h264") + GST_CAPS_CODEC("video/x-h265") + GST_CAPS_CODEC("video/x-wmv") + GST_CAPS_CODEC("video/x-vp8") + GST_CAPS_CODEC("video/x-vp9") + GST_CAPS_CODEC("video/x-av1") + ; + +static const char gst_vaapidecode_src_caps_str[] = + GST_VAAPI_MAKE_SURFACE_CAPS "; " + GST_VIDEO_CAPS_MAKE_WITH_FEATURES(GST_CAPS_FEATURE_MEMORY_DMABUF, GST_VAAPI_FORMATS_ALL) " ;" +#if (USE_GLX || USE_EGL) + GST_VAAPI_MAKE_GLTEXUPLOAD_CAPS "; " +#endif + GST_VIDEO_CAPS_MAKE(GST_VAAPI_FORMATS_ALL); + +static GstStaticPadTemplate gst_vaapidecode_src_factory = + GST_STATIC_PAD_TEMPLATE( + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS(gst_vaapidecode_src_caps_str)); +/* *INDENT-ON* */ + +typedef struct _GstVaapiDecoderMap GstVaapiDecoderMap; +struct _GstVaapiDecoderMap +{ + guint codec; + guint rank; + const gchar *name; + const gchar *caps_str; + + void (*install_properties) (GObjectClass * klass); +}; + +static const GstVaapiDecoderMap vaapi_decode_map[] = { + {GST_VAAPI_CODEC_JPEG, GST_RANK_MARGINAL, "jpeg", "image/jpeg", NULL}, + {GST_VAAPI_CODEC_MPEG2, GST_RANK_PRIMARY, "mpeg2", + "video/mpeg, mpegversion=2, systemstream=(boolean)false", NULL}, + {GST_VAAPI_CODEC_MPEG4, GST_RANK_PRIMARY, "mpeg4", + "video/mpeg, mpegversion=4", NULL}, + {GST_VAAPI_CODEC_H263, GST_RANK_PRIMARY, "h263", "video/x-h263", NULL}, + {GST_VAAPI_CODEC_H264, GST_RANK_PRIMARY, "h264", "video/x-h264", + gst_vaapi_decode_h264_install_properties}, + {GST_VAAPI_CODEC_VC1, GST_RANK_PRIMARY, "vc1", + "video/x-wmv, wmvversion=3, format={WMV3,WVC1}", NULL}, + {GST_VAAPI_CODEC_VP8, GST_RANK_PRIMARY, "vp8", "video/x-vp8", NULL}, + {GST_VAAPI_CODEC_VP9, GST_RANK_PRIMARY, "vp9", "video/x-vp9", NULL}, + {GST_VAAPI_CODEC_H265, GST_RANK_PRIMARY, "h265", "video/x-h265", NULL}, + {GST_VAAPI_CODEC_AV1, GST_RANK_PRIMARY, "av1", "video/x-av1", NULL}, + {0 /* the rest */ , GST_RANK_PRIMARY + 1, NULL, + gst_vaapidecode_sink_caps_str, NULL}, +}; + +static GstElementClass *parent_class = NULL; +GST_VAAPI_PLUGIN_BASE_DEFINE_SET_CONTEXT (parent_class); + +static gboolean gst_vaapidecode_update_sink_caps (GstVaapiDecode * decode, + GstCaps * caps); +static gboolean gst_vaapi_decode_input_state_replace (GstVaapiDecode * decode, + const GstVideoCodecState * new_state); + +/* invoked if actual VASurface size (not the cropped values) + * changed */ +static void +gst_vaapi_decoder_state_changed (GstVaapiDecoder * decoder, + const GstVideoCodecState * codec_state, gpointer user_data) +{ + GstVaapiDecode *const decode = GST_VAAPIDECODE (user_data); + + g_assert (decode->decoder == decoder); + + if (!gst_vaapi_decode_input_state_replace (decode, codec_state)) + return; + if (!gst_vaapidecode_update_sink_caps (decode, decode->input_state->caps)) + return; +} + +static GstVideoCodecState * +copy_video_codec_state (const GstVideoCodecState * in_state) +{ + GstVideoCodecState *state; + + g_return_val_if_fail (in_state != NULL, NULL); + + state = g_slice_new0 (GstVideoCodecState); + state->ref_count = 1; + state->info = in_state->info; + state->caps = gst_caps_copy (in_state->caps); + if (in_state->codec_data) + state->codec_data = gst_buffer_copy_deep (in_state->codec_data); + + return state; +} + +static gboolean +gst_vaapi_decode_input_state_replace (GstVaapiDecode * decode, + const GstVideoCodecState * new_state) +{ + if (decode->input_state) { + if (new_state) { + const GstCaps *curcaps = decode->input_state->caps; + /* If existing caps are equal of the new state, keep the + * existing state without renegotiating. */ + if (gst_caps_is_strictly_equal (curcaps, new_state->caps)) { + GST_DEBUG ("Ignoring new caps %" GST_PTR_FORMAT + " since are equal to current ones", new_state->caps); + return FALSE; + } + } + gst_video_codec_state_unref (decode->input_state); + } + + if (new_state) + decode->input_state = copy_video_codec_state (new_state); + else + decode->input_state = NULL; + + return TRUE; +} + +static inline gboolean +gst_vaapidecode_update_sink_caps (GstVaapiDecode * decode, GstCaps * caps) +{ + GST_INFO_OBJECT (decode, "new sink caps = %" GST_PTR_FORMAT, caps); + gst_caps_replace (&decode->sinkpad_caps, caps); + return TRUE; +} + +static gboolean +gst_vaapidecode_ensure_allowed_srcpad_caps (GstVaapiDecode * decode) +{ + GstVaapiDisplay *const display = GST_VAAPI_PLUGIN_BASE_DISPLAY (decode); + GstCaps *out_caps, *raw_caps, *va_caps, *dma_caps, *gltexup_caps, *base_caps; + GArray *formats; + gint min_width, min_height, max_width, max_height; + guint mem_types; + gboolean ret = FALSE; + + if (decode->allowed_srcpad_caps) + return TRUE; + + if (!display) + return FALSE; + + if (!decode->decoder) + return FALSE; + + dma_caps = gltexup_caps = NULL; + + formats = gst_vaapi_decoder_get_surface_attributes (decode->decoder, + &min_width, &min_height, &max_width, &max_height, &mem_types); + if (!formats) + return FALSE; + + base_caps = gst_vaapi_video_format_new_template_caps_from_list (formats); + if (!base_caps) + goto bail; + gst_vaapi_caps_set_width_and_height_range (base_caps, min_width, min_height, + max_width, max_height); + + { + GArray *img_formats = gst_vaapi_display_get_image_formats (display); + GstVideoFormat decoded_format = + GST_VIDEO_INFO_FORMAT (&decode->decoded_info); + + if (!img_formats) + img_formats = g_array_ref (formats); + + if (decoded_format != GST_VIDEO_FORMAT_UNKNOWN) { + guint decoded_chroma = + gst_vaapi_video_format_get_chroma_type (decoded_format); + GArray *new_img_formats = + g_array_new (FALSE, FALSE, sizeof (GstVideoFormat)); + gint i; + + for (i = 0; i < img_formats->len; i++) { + const GstVideoFormat fmt = + g_array_index (img_formats, GstVideoFormat, i); + if (gst_vaapi_video_format_get_chroma_type (fmt) == decoded_chroma) + g_array_append_val (new_img_formats, fmt); + } + + if (new_img_formats->len == 0) { + g_clear_pointer (&new_img_formats, g_array_unref); + } else { + g_clear_pointer (&img_formats, g_array_unref); + img_formats = new_img_formats; + } + } + + raw_caps = gst_vaapi_video_format_new_template_caps_from_list (img_formats); + gst_vaapi_caps_set_width_and_height_range (raw_caps, min_width, min_height, + max_width, max_height); + g_array_unref (img_formats); + } + + va_caps = gst_caps_copy (base_caps); + gst_caps_set_features_simple (va_caps, + gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE)); + + if (gst_vaapi_mem_type_supports (mem_types, + GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF) || + gst_vaapi_mem_type_supports (mem_types, + GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF2)) { + dma_caps = gst_caps_copy (base_caps); + gst_caps_set_features_simple (dma_caps, + gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_DMABUF)); + } +#if (USE_GLX || USE_EGL) + if (!GST_VAAPI_PLUGIN_BASE_SRC_PAD_CAN_DMABUF (decode) + && gst_vaapi_display_has_opengl (GST_VAAPI_PLUGIN_BASE_DISPLAY (decode))) { + gltexup_caps = gst_caps_from_string (GST_VAAPI_MAKE_GLTEXUPLOAD_CAPS); + if (gltexup_caps) { + gst_vaapi_caps_set_width_and_height_range (base_caps, min_width, + min_height, max_width, max_height); + } + } +#endif + + out_caps = va_caps; + if (dma_caps) + gst_caps_append (out_caps, dma_caps); + if (gltexup_caps) + gst_caps_append (out_caps, gltexup_caps); + gst_caps_append (out_caps, raw_caps); + decode->allowed_srcpad_caps = out_caps; + + GST_INFO_OBJECT (decode, "allowed srcpad caps: %" GST_PTR_FORMAT, + decode->allowed_srcpad_caps); + + ret = TRUE; + +bail: + if (formats) + g_array_unref (formats); + if (base_caps) + gst_caps_unref (base_caps); + return ret; +} + +static GstCaps * +gst_vaapidecode_get_allowed_srcpad_caps (GstVaapiDecode * decode) +{ + GstPad *const srcpad = GST_VIDEO_DECODER_SRC_PAD (decode); + + if (gst_vaapidecode_ensure_allowed_srcpad_caps (decode)) + return gst_caps_ref (decode->allowed_srcpad_caps); + return gst_pad_get_pad_template_caps (srcpad); +} + +static gboolean +gst_vaapidecode_update_src_caps (GstVaapiDecode * decode) +{ + GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode); + GstPad *const srcpad = GST_VIDEO_DECODER_SRC_PAD (vdec); + GstCaps *allowed; + GstVideoCodecState *state, *ref_state; + GstVaapiCapsFeature feature; + GstCapsFeatures *features; + GstCaps *allocation_caps; + GstVideoInfo *vi; + GstVideoFormat format; + GstClockTime latency; + gint fps_d, fps_n; + guint width, height; + const gchar *format_str, *feature_str; + + if (!decode->input_state) + return FALSE; + + ref_state = decode->input_state; + + format = GST_VIDEO_INFO_FORMAT (&decode->decoded_info); + allowed = gst_vaapidecode_get_allowed_srcpad_caps (decode); + feature = gst_vaapi_find_preferred_caps_feature (srcpad, allowed, &format); + gst_caps_unref (allowed); + + if (feature == GST_VAAPI_CAPS_FEATURE_NOT_NEGOTIATED) + return FALSE; + +#if (!USE_GLX && !USE_EGL) + /* This is a very pathological situation. Should not happen. */ + if (feature == GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META) + return FALSE; +#endif + + if ((feature == GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY || + feature == GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE) + && format != GST_VIDEO_INFO_FORMAT (&decode->decoded_info)) { + GST_FIXME_OBJECT (decode, "validate if driver can convert from %s to %s", + gst_video_format_to_string (GST_VIDEO_INFO_FORMAT + (&decode->decoded_info)), gst_video_format_to_string (format)); + } + + width = decode->display_width; + height = decode->display_height; + + if (!width || !height) { + width = GST_VIDEO_INFO_WIDTH (&ref_state->info); + height = GST_VIDEO_INFO_HEIGHT (&ref_state->info); + } + + state = gst_video_decoder_set_output_state (vdec, format, width, height, + ref_state); + if (!state) + return FALSE; + + if (GST_VIDEO_INFO_WIDTH (&state->info) == 0 + || GST_VIDEO_INFO_HEIGHT (&state->info) == 0) { + gst_video_codec_state_unref (state); + return FALSE; + } + + vi = &state->info; + state->caps = gst_video_info_to_caps (vi); + + switch (feature) { + case GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META: + case GST_VAAPI_CAPS_FEATURE_DMABUF: + case GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE:{ + GstStructure *structure = gst_caps_get_structure (state->caps, 0); + if (!structure) + break; + feature_str = gst_vaapi_caps_feature_to_string (feature); + features = gst_caps_features_new (feature_str, NULL); + gst_caps_set_features (state->caps, 0, features); + break; + } + default: + break; + } + + /* Allocation query is different from pad's caps */ + allocation_caps = NULL; + if (GST_VIDEO_INFO_WIDTH (&decode->decoded_info) != width + || GST_VIDEO_INFO_HEIGHT (&decode->decoded_info) != height) { + allocation_caps = gst_caps_copy (state->caps); + format_str = gst_video_format_to_string (format); + gst_caps_set_simple (allocation_caps, + "width", G_TYPE_INT, GST_VIDEO_INFO_WIDTH (&decode->decoded_info), + "height", G_TYPE_INT, GST_VIDEO_INFO_HEIGHT (&decode->decoded_info), + "format", G_TYPE_STRING, format_str, NULL); + GST_INFO_OBJECT (decode, "new alloc caps = %" GST_PTR_FORMAT, + allocation_caps); + } + gst_caps_replace (&state->allocation_caps, allocation_caps); + if (allocation_caps) + gst_caps_unref (allocation_caps); + + GST_INFO_OBJECT (decode, "new src caps = %" GST_PTR_FORMAT, state->caps); + gst_caps_replace (&decode->srcpad_caps, state->caps); + gst_video_codec_state_unref (state); + + fps_n = GST_VIDEO_INFO_FPS_N (vi); + fps_d = GST_VIDEO_INFO_FPS_D (vi); + if (fps_n <= 0 || fps_d <= 0) { + GST_DEBUG_OBJECT (decode, "forcing 25/1 framerate for latency calculation"); + fps_n = 25; + fps_d = 1; + } + + /* For parsing/preparation purposes we'd need at least 1 frame + * latency in general, with perfectly known unit boundaries (NALU, + * AU), and up to 2 frames when we need to wait for the second frame + * start to determine the first frame is complete */ + latency = gst_util_uint64_scale (2 * GST_SECOND, fps_d, fps_n); + gst_video_decoder_set_latency (vdec, latency, latency); + + return TRUE; +} + +/* check whether the decoded surface size has changed */ +static gboolean +is_surface_resolution_changed (GstVaapiDecode * decode, + GstVaapiSurface * surface) +{ + GstVideoInfo *vinfo = &decode->decoded_info; + GstVideoFormat surface_format; + guint surface_width, surface_height; + + g_return_val_if_fail (surface != NULL, FALSE); + + gst_vaapi_surface_get_size (surface, &surface_width, &surface_height); + + if (GST_VIDEO_INFO_WIDTH (vinfo) == surface_width + && GST_VIDEO_INFO_HEIGHT (vinfo) == surface_height) + return FALSE; + + /* doing gst_vaapi_surface_get_format() only if necessary since it + * execute vaDeriveImage in the background. This will usually get + * executed only once */ + surface_format = GST_VIDEO_INFO_FORMAT (vinfo); + if (surface_format == GST_VIDEO_FORMAT_UNKNOWN) { + surface_format = gst_vaapi_surface_get_format (surface); + + /* if the VA context delivers a currently unrecognized format + * (ICM3, e.g.), we can assume one according surface chroma + * type. If fail, then use NV12 "safely" */ + if (surface_format == GST_VIDEO_FORMAT_UNKNOWN + || surface_format == GST_VIDEO_FORMAT_ENCODED) + surface_format = + gst_vaapi_video_format_from_chroma (gst_vaapi_surface_get_chroma_type + (surface)); + if (surface_format == GST_VIDEO_FORMAT_UNKNOWN) + surface_format = GST_VIDEO_FORMAT_NV12; + } + + /* reset allowed source caps since they are dependant of the decoded + * surface format */ + gst_caps_replace (&decode->allowed_srcpad_caps, NULL); + + gst_video_info_set_format (vinfo, surface_format, surface_width, + surface_height); + + return TRUE; +} + +/* check whether display resolution changed */ +static gboolean +is_display_resolution_changed (GstVaapiDecode * decode, + const GstVaapiRectangle * crop_rect) +{ + GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode); + GstVideoCodecState *state; + guint display_width, display_height; + guint negotiated_width, negotiated_height; + + display_width = GST_VIDEO_INFO_WIDTH (&decode->decoded_info); + display_height = GST_VIDEO_INFO_HEIGHT (&decode->decoded_info); + if (crop_rect) { + display_width = crop_rect->width; + display_height = crop_rect->height; + } + + state = gst_video_decoder_get_output_state (vdec); + if (G_UNLIKELY (!state)) + goto set_display_res; + + negotiated_width = GST_VIDEO_INFO_WIDTH (&state->info); + negotiated_height = GST_VIDEO_INFO_HEIGHT (&state->info); + gst_video_codec_state_unref (state); + + if ((display_width == negotiated_width && display_height == negotiated_height) + && (decode->display_width == negotiated_width + && decode->display_height == negotiated_height)) + return FALSE; + +set_display_res: + decode->display_width = display_width; + decode->display_height = display_height; + return TRUE; +} + +static gboolean +gst_vaapidecode_negotiate (GstVaapiDecode * decode) +{ + GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode); + GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (vdec); + + GST_DEBUG_OBJECT (decode, "input codec state changed: renegotiating"); + + GST_VIDEO_DECODER_STREAM_LOCK (vdec); + if (!gst_vaapidecode_update_src_caps (decode)) + goto caps_negotiation_failed; + if (!gst_vaapi_plugin_base_set_caps (plugin, NULL, decode->srcpad_caps)) + goto caps_negotiation_failed; + GST_VIDEO_DECODER_STREAM_UNLOCK (vdec); + + if (!gst_video_decoder_negotiate (vdec)) + return FALSE; + + return TRUE; + +caps_negotiation_failed: + { + GST_VIDEO_DECODER_STREAM_UNLOCK (vdec); + return FALSE; + } +} + +static gboolean +is_src_allocator_dmabuf (GstVaapiDecode * decode) +{ + GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (decode); + + if (!GST_VAAPI_PLUGIN_BASE_SRC_PAD_CAN_DMABUF (plugin)) + return FALSE; + return + gst_vaapi_is_dmabuf_allocator (GST_VAAPI_PLUGIN_BASE_SRC_PAD_ALLOCATOR + (plugin)); +} + +static GstFlowReturn +gst_vaapidecode_push_decoded_frame (GstVideoDecoder * vdec, + GstVideoCodecFrame * out_frame) +{ + GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec); + GstVaapiSurfaceProxy *proxy; + GstVaapiSurface *surface; + GstFlowReturn ret; + const GstVaapiRectangle *crop_rect; + GstVaapiVideoMeta *meta; + GstBufferPoolAcquireParams *params = NULL; + GstVaapiVideoBufferPoolAcquireParams vaapi_params = { {0,}, }; + guint flags, out_flags = 0; + gboolean alloc_renegotiate, caps_renegotiate; + + if (!GST_VIDEO_CODEC_FRAME_IS_DECODE_ONLY (out_frame)) { + proxy = gst_video_codec_frame_get_user_data (out_frame); + surface = GST_VAAPI_SURFACE_PROXY_SURFACE (proxy); + crop_rect = gst_vaapi_surface_proxy_get_crop_rect (proxy); + + /* in theory, we are not supposed to check the surface resolution + * change here since it should be advertised before from ligstvaapi. + * But there are issues with it especially for some vp9 streams where + * upstream element set un-cropped values in set_format() which make + * everything a mess. So better doing the explicit check here irrespective + * of what notification we get from upstream or libgstvaapi.Also, even if + * we received notification from libgstvaapi, the frame we are going to + * be pushed at this point might not have the notified resolution if there + * are queued frames in decoded picture buffer. */ + alloc_renegotiate = is_surface_resolution_changed (decode, surface); + caps_renegotiate = is_display_resolution_changed (decode, crop_rect); + + if (gst_pad_needs_reconfigure (GST_VIDEO_DECODER_SRC_PAD (vdec)) + || alloc_renegotiate || caps_renegotiate || decode->do_renego) { + + g_atomic_int_set (&decode->do_renego, FALSE); + if (!gst_vaapidecode_negotiate (decode)) + return GST_FLOW_ERROR; + } + + if (is_src_allocator_dmabuf (decode)) { + vaapi_params.proxy = gst_vaapi_surface_proxy_ref (proxy); + params = (GstBufferPoolAcquireParams *) & vaapi_params; + } + + ret = gst_video_decoder_allocate_output_frame_with_params (vdec, out_frame, + params); + if (params) + gst_vaapi_surface_proxy_unref (vaapi_params.proxy); + if (ret != GST_FLOW_OK) + goto error_create_buffer; + + /* if not dmabuf is negotiated set the vaapi video meta in the + * proxy */ + if (!params) { + meta = gst_buffer_get_vaapi_video_meta (out_frame->output_buffer); + if (!meta) + goto error_get_meta; + gst_vaapi_video_meta_set_surface_proxy (meta, proxy); + } + + flags = gst_vaapi_surface_proxy_get_flags (proxy); + if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_CORRUPTED) + out_flags |= GST_BUFFER_FLAG_CORRUPTED; + if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_INTERLACED) { + out_flags |= GST_VIDEO_BUFFER_FLAG_INTERLACED; + if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_TFF) + out_flags |= GST_VIDEO_BUFFER_FLAG_TFF; + if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_RFF) + out_flags |= GST_VIDEO_BUFFER_FLAG_RFF; + if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_ONEFIELD) + out_flags |= GST_VIDEO_BUFFER_FLAG_ONEFIELD; + } + GST_BUFFER_FLAG_SET (out_frame->output_buffer, out_flags); + + if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_FFB) { + GST_BUFFER_FLAG_SET (out_frame->output_buffer, + GST_VIDEO_BUFFER_FLAG_FIRST_IN_BUNDLE); + } +#if (USE_GLX || USE_EGL) + if (decode->has_texture_upload_meta) + gst_buffer_ensure_texture_upload_meta (out_frame->output_buffer); +#endif + + /* Generate a system allocated output buffer if downstream doesn't + * support GstVideoMeta */ + if (GST_VAAPI_PLUGIN_BASE_COPY_OUTPUT_FRAME (vdec)) { + GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (vdec); + GstBuffer *sys_buf, *va_buf; + + va_buf = out_frame->output_buffer; + sys_buf = + gst_buffer_new_allocate (GST_VAAPI_PLUGIN_BASE_OTHER_ALLOCATOR + (plugin), + GST_VIDEO_INFO_SIZE (GST_VAAPI_PLUGIN_BASE_SRC_PAD_INFO (plugin)), + &GST_VAAPI_PLUGIN_BASE_OTHER_ALLOCATOR_PARAMS (plugin)); + if (!sys_buf) + goto error_no_sys_buffer; + + if (!gst_vaapi_plugin_copy_va_buffer (plugin, va_buf, sys_buf)) { + gst_buffer_unref (sys_buf); + goto error_cannot_copy; + } + + gst_buffer_replace (&out_frame->output_buffer, sys_buf); + gst_buffer_unref (sys_buf); + } + } + + ret = gst_video_decoder_finish_frame (vdec, out_frame); + if (ret != GST_FLOW_OK) + goto error_commit_buffer; + return GST_FLOW_OK; + + /* ERRORS */ +error_create_buffer: + { + const GstVaapiID surface_id = + gst_vaapi_surface_get_id (GST_VAAPI_SURFACE_PROXY_SURFACE (proxy)); + + GST_ELEMENT_ERROR (vdec, STREAM, FAILED, + ("Failed to create sink buffer"), + ("video sink failed to create video buffer for proxy'ed " + "surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (surface_id))); + gst_video_decoder_drop_frame (vdec, out_frame); + return GST_FLOW_ERROR; + } +error_get_meta: + { + GST_ELEMENT_ERROR (vdec, STREAM, FAILED, + ("Failed to get vaapi video meta attached to video buffer"), + ("Failed to get vaapi video meta attached to video buffer")); + gst_video_decoder_drop_frame (vdec, out_frame); + return GST_FLOW_ERROR; + } +error_no_sys_buffer: + { + GST_ELEMENT_ERROR (vdec, STREAM, FAILED, + ("Failed to create system allocated buffer"), + ("Failed to create system allocated buffer")); + gst_video_decoder_drop_frame (vdec, out_frame); + return GST_FLOW_ERROR; + } +error_cannot_copy: + { + GST_ELEMENT_ERROR (vdec, STREAM, FAILED, + ("Failed to copy system allocated buffer"), + ("Failed to copy system allocated buffer")); + gst_video_decoder_drop_frame (vdec, out_frame); + return GST_FLOW_ERROR; + } +error_commit_buffer: + { + GST_LOG_OBJECT (decode, "downstream element rejected the frame (%s [%d])", + gst_flow_get_name (ret), ret); + return ret; + } +} + +static GstFlowReturn +gst_vaapidecode_push_all_decoded_frames (GstVaapiDecode * decode) +{ + GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode); + GstVaapiDecoderStatus status; + GstVideoCodecFrame *out_frame; + GstFlowReturn ret; + + for (;;) { + status = gst_vaapi_decoder_get_frame (decode->decoder, &out_frame); + + switch (status) { + case GST_VAAPI_DECODER_STATUS_SUCCESS: + /* GstVaapiDecode's queue adds an extra reference */ + gst_video_codec_frame_unref (out_frame); + ret = gst_vaapidecode_push_decoded_frame (vdec, out_frame); + if (ret != GST_FLOW_OK) + return ret; + break; + case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA: + return GST_FLOW_OK; + default: + GST_VIDEO_DECODER_ERROR (vdec, 1, STREAM, DECODE, ("Decoding failed"), + ("Unknown decoding error"), ret); + return ret; + } + } + g_assert_not_reached (); +} + +static GstFlowReturn +gst_vaapidecode_handle_frame (GstVideoDecoder * vdec, + GstVideoCodecFrame * frame) +{ + GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec); + GstVaapiDecoderStatus status; + + if (!decode->input_state) + goto not_negotiated; + + /* Decode current frame */ + for (;;) { + status = gst_vaapi_decoder_decode (decode->decoder, frame); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + goto error_decode; + break; + } + + /* Note that gst_vaapi_decoder_decode cannot return success without + completing the decode and pushing all decoded frames into the output + queue */ + return gst_vaapidecode_push_all_decoded_frames (decode); + + /* ERRORS */ +error_decode: + { + GstFlowReturn ret = GST_FLOW_OK; + + GST_WARNING_OBJECT (decode, "decode error %d", status); + + switch (status) { + case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC: + case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE: + case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT: + ret = GST_FLOW_NOT_SUPPORTED; + break; + default: + GST_VIDEO_DECODER_ERROR (vdec, 1, STREAM, DECODE, ("Decoding error"), + ("Decode error %d", status), ret); + GST_INFO_OBJECT (decode, "requesting upstream a key unit"); + gst_pad_push_event (GST_VIDEO_DECODER_SINK_PAD (decode), + gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE, + FALSE, 0)); + break; + } + gst_video_decoder_drop_frame (vdec, frame); + return ret; + } +not_negotiated: + { + GST_ERROR_OBJECT (decode, "not negotiated"); + gst_video_decoder_drop_frame (vdec, frame); + return GST_FLOW_NOT_NEGOTIATED; + } +} + +/* If there is something in GstVideoDecoder's output adapter, then + submit the frame for decoding */ +static inline void +gst_vaapidecode_flush_output_adapter (GstVaapiDecode * decode) +{ + if (decode->current_frame_size == 0) + return; + gst_video_decoder_have_frame (GST_VIDEO_DECODER (decode)); + decode->current_frame_size = 0; +} + +static GstFlowReturn +gst_vaapidecode_drain (GstVideoDecoder * vdec) +{ + GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec); + + if (!decode->decoder) + return GST_FLOW_NOT_NEGOTIATED; + + GST_LOG_OBJECT (decode, "drain"); + + gst_vaapidecode_flush_output_adapter (decode); + return gst_vaapidecode_push_all_decoded_frames (decode); +} + +static GstFlowReturn +gst_vaapidecode_finish (GstVideoDecoder * vdec) +{ + GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec); + GstVaapiDecoderStatus status; + GstFlowReturn ret; + + if (!decode->decoder) + return GST_FLOW_OK; + + gst_vaapidecode_flush_output_adapter (decode); + status = gst_vaapi_decoder_flush (decode->decoder); + ret = gst_vaapidecode_push_all_decoded_frames (decode); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + goto error_decoder_flush; + return ret; + + /* ERRORS: */ +error_decoder_flush: + { + GST_WARNING_OBJECT (decode, "failed to flush decoder (status %d)", status); + return GST_FLOW_ERROR; + } +} + +static gboolean +gst_vaapidecode_decide_allocation (GstVideoDecoder * vdec, GstQuery * query) +{ + GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec); + GstCaps *caps = NULL; + + gst_query_parse_allocation (query, &caps, NULL); + if (!caps) + goto error_no_caps; + + decode->has_texture_upload_meta = FALSE; + +#if (USE_GLX || USE_EGL) + decode->has_texture_upload_meta = + gst_query_find_allocation_meta (query, + GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, NULL) && + gst_vaapi_caps_feature_contains (caps, + GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META); +#endif + + return gst_vaapi_plugin_base_decide_allocation (GST_VAAPI_PLUGIN_BASE (vdec), + query); + + /* ERRORS */ +error_no_caps: + { + GST_ERROR_OBJECT (decode, "no caps specified"); + return FALSE; + } +} + +static inline gboolean +gst_vaapidecode_ensure_display (GstVaapiDecode * decode) +{ + return gst_vaapi_plugin_base_ensure_display (GST_VAAPI_PLUGIN_BASE (decode)); +} + +static gboolean +gst_vaapidecode_create (GstVaapiDecode * decode, GstCaps * caps) +{ + GstVaapiDisplay *dpy; + + if (!gst_vaapidecode_ensure_display (decode)) + return FALSE; + dpy = GST_VAAPI_PLUGIN_BASE_DISPLAY (decode); + + switch (gst_vaapi_get_codec_from_caps (caps)) { + case GST_VAAPI_CODEC_MPEG2: + decode->decoder = gst_vaapi_decoder_mpeg2_new (dpy, caps); + break; + case GST_VAAPI_CODEC_MPEG4: + case GST_VAAPI_CODEC_H263: + decode->decoder = gst_vaapi_decoder_mpeg4_new (dpy, caps); + break; + case GST_VAAPI_CODEC_H264: + decode->decoder = gst_vaapi_decoder_h264_new (dpy, caps); + + /* Set the stream buffer alignment for better optimizations */ + if (decode->decoder && caps) { + GstVaapiDecodeH264Private *priv = + gst_vaapi_decode_h264_get_instance_private (decode); + GstStructure *const structure = gst_caps_get_structure (caps, 0); + const gchar *str = NULL; + + if (!structure) + break; + + if ((str = gst_structure_get_string (structure, "alignment"))) { + GstVaapiStreamAlignH264 alignment; + if (g_strcmp0 (str, "au") == 0) + alignment = GST_VAAPI_STREAM_ALIGN_H264_AU; + else if (g_strcmp0 (str, "nal") == 0) + alignment = GST_VAAPI_STREAM_ALIGN_H264_NALU; + else + alignment = GST_VAAPI_STREAM_ALIGN_H264_NONE; + gst_vaapi_decoder_h264_set_alignment (GST_VAAPI_DECODER_H264 + (decode->decoder), alignment); + } + + if (priv) { + gst_vaapi_decoder_h264_set_low_latency (GST_VAAPI_DECODER_H264 + (decode->decoder), priv->is_low_latency); + gst_vaapi_decoder_h264_set_base_only (GST_VAAPI_DECODER_H264 + (decode->decoder), priv->base_only); + } + } + break; + case GST_VAAPI_CODEC_H265: + decode->decoder = gst_vaapi_decoder_h265_new (dpy, caps); + + /* Set the stream buffer alignment for better optimizations */ + if (decode->decoder && caps) { + GstStructure *const structure = gst_caps_get_structure (caps, 0); + const gchar *str = NULL; + + if (!structure) + break; + + if ((str = gst_structure_get_string (structure, "alignment"))) { + GstVaapiStreamAlignH265 alignment; + if (g_strcmp0 (str, "au") == 0) + alignment = GST_VAAPI_STREAM_ALIGN_H265_AU; + else if (g_strcmp0 (str, "nal") == 0) + alignment = GST_VAAPI_STREAM_ALIGN_H265_NALU; + else + alignment = GST_VAAPI_STREAM_ALIGN_H265_NONE; + gst_vaapi_decoder_h265_set_alignment (GST_VAAPI_DECODER_H265 + (decode->decoder), alignment); + } + } + break; + case GST_VAAPI_CODEC_WMV3: + case GST_VAAPI_CODEC_VC1: + decode->decoder = gst_vaapi_decoder_vc1_new (dpy, caps); + break; + case GST_VAAPI_CODEC_JPEG: + decode->decoder = gst_vaapi_decoder_jpeg_new (dpy, caps); + break; + case GST_VAAPI_CODEC_VP8: + decode->decoder = gst_vaapi_decoder_vp8_new (dpy, caps); + break; + case GST_VAAPI_CODEC_VP9: + decode->decoder = gst_vaapi_decoder_vp9_new (dpy, caps); + break; +#if USE_AV1_DECODER + case GST_VAAPI_CODEC_AV1: + decode->decoder = gst_vaapi_decoder_av1_new (dpy, caps); + break; +#endif + default: + decode->decoder = NULL; + break; + } + if (!decode->decoder) + return FALSE; + + gst_vaapi_decoder_set_codec_state_changed_func (decode->decoder, + gst_vaapi_decoder_state_changed, decode); + + return TRUE; +} + +static void +gst_vaapidecode_purge (GstVaapiDecode * decode) +{ + GstVaapiDecoderStatus status; + + if (!decode->decoder) + return; + + status = gst_vaapi_decoder_flush (decode->decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + GST_INFO_OBJECT (decode, "failed to flush decoder (status %d)", status); + + /* Purge all decoded frames as we don't need them (e.g. flush and close) + * Releasing the frames is important, otherwise the frames are not + * freed. */ + do { + GstVideoCodecFrame *frame = NULL; + + status = + gst_vaapi_decoder_get_frame_with_timeout (decode->decoder, &frame, 0); + if (frame) { + gst_video_decoder_release_frame (GST_VIDEO_DECODER (decode), frame); + gst_video_codec_frame_unref (frame); + } + } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS); +} + +static void +gst_vaapidecode_destroy (GstVaapiDecode * decode) +{ + gst_vaapidecode_purge (decode); + + gst_vaapi_decoder_replace (&decode->decoder, NULL); + /* srcpad caps are decoder's context dependant */ + gst_caps_replace (&decode->allowed_srcpad_caps, NULL); +} + +static gboolean +gst_vaapidecode_reset (GstVaapiDecode * decode, GstCaps * caps, + gboolean force_reset) +{ + /* Reset tracked frame size */ + decode->current_frame_size = 0; + + if (decode->decoder) { + if (!gst_caps_is_equal (caps, gst_vaapi_decoder_get_caps (decode->decoder))) { + if (gst_vaapi_decoder_update_caps (decode->decoder, caps)) { + g_atomic_int_set (&decode->do_renego, TRUE); + if (!force_reset) + return TRUE; + } + } + return (gst_vaapi_decoder_reset (decode->decoder) == + GST_VAAPI_DECODER_STATUS_SUCCESS); + } + + return gst_vaapidecode_create (decode, caps); +} + +static void +gst_vaapidecode_finalize (GObject * object) +{ + gst_vaapi_plugin_base_finalize (GST_VAAPI_PLUGIN_BASE (object)); + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static gboolean +gst_vaapidecode_open (GstVideoDecoder * vdec) +{ + GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec); + + if (!gst_vaapi_plugin_base_open (GST_VAAPI_PLUGIN_BASE (decode))) + return FALSE; + + decode->display_width = 0; + decode->display_height = 0; + gst_video_info_init (&decode->decoded_info); + + return TRUE; +} + +static gboolean +gst_vaapidecode_close (GstVideoDecoder * vdec) +{ + GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec); + + gst_vaapidecode_destroy (decode); + gst_caps_replace (&decode->allowed_srcpad_caps, NULL); + gst_caps_replace (&decode->allowed_sinkpad_caps, NULL); + gst_vaapi_plugin_base_close (GST_VAAPI_PLUGIN_BASE (decode)); + return TRUE; +} + +static gboolean +gst_vaapidecode_start (GstVideoDecoder * vdec) +{ + GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec); + GstVaapiDisplay *const old_display = GST_VAAPI_PLUGIN_BASE_DISPLAY (decode); + gboolean success; + + /* Let GstVideoContext ask for a proper display to its neighbours */ + /* Note: steal old display that may be allocated from get_caps() + so that to retain a reference to it, thus avoiding extra + initialization steps if we turn out to simply re-use the + existing (cached) VA display */ + GST_VAAPI_PLUGIN_BASE_DISPLAY (decode) = NULL; + success = + gst_vaapi_plugin_base_ensure_display (GST_VAAPI_PLUGIN_BASE (decode)); + if (old_display) + gst_object_unref (old_display); + + /* Disable errors on decode errors */ + gst_video_decoder_set_max_errors (vdec, -1); + + return success; +} + +static gboolean +gst_vaapidecode_stop (GstVideoDecoder * vdec) +{ + GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec); + + gst_vaapidecode_purge (decode); + gst_vaapi_decode_input_state_replace (decode, NULL); + gst_vaapi_decoder_replace (&decode->decoder, NULL); + gst_caps_replace (&decode->sinkpad_caps, NULL); + gst_caps_replace (&decode->srcpad_caps, NULL); + return TRUE; +} + +static gboolean +gst_vaapidecode_flush (GstVideoDecoder * vdec) +{ + GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec); + if (!decode->decoder) + return FALSE; + + GST_LOG_OBJECT (vdec, "flushing"); + + gst_vaapidecode_purge (decode); + + /* There could be issues if we avoid the reset() while doing + * seeking: we have to reset the internal state */ + return gst_vaapidecode_reset (decode, decode->sinkpad_caps, TRUE); +} + +static gboolean +gst_vaapidecode_set_format (GstVideoDecoder * vdec, GstVideoCodecState * state) +{ + GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (vdec); + GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec); + + if (!gst_vaapi_decode_input_state_replace (decode, state)) + return TRUE; + if (gst_vaapidecode_drain (vdec) == GST_FLOW_ERROR) + return FALSE; + if (!gst_vaapidecode_update_sink_caps (decode, state->caps)) + return FALSE; + if (!gst_vaapi_plugin_base_set_caps (plugin, decode->sinkpad_caps, NULL)) + return FALSE; + if (!gst_vaapidecode_reset (decode, decode->sinkpad_caps, FALSE)) + return FALSE; + + return TRUE; +} + +static GstFlowReturn +gst_vaapidecode_parse_frame (GstVideoDecoder * vdec, + GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos) +{ + GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec); + GstVaapiDecoderStatus status; + GstFlowReturn ret; + guint got_unit_size; + gboolean got_frame; + + status = gst_vaapi_decoder_parse (decode->decoder, frame, + adapter, at_eos, &got_unit_size, &got_frame); + + switch (status) { + case GST_VAAPI_DECODER_STATUS_SUCCESS: + if (got_unit_size > 0) { + gst_video_decoder_add_to_frame (vdec, got_unit_size); + decode->current_frame_size += got_unit_size; + } + if (got_frame) { + ret = gst_video_decoder_have_frame (vdec); + decode->current_frame_size = 0; + } else + ret = GST_VAAPI_DECODE_FLOW_PARSE_DATA; + break; + case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA: + ret = GST_VIDEO_DECODER_FLOW_NEED_DATA; + break; + case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC: + case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE: + case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT: + GST_WARNING ("parse error %d", status); + ret = GST_FLOW_NOT_SUPPORTED; + decode->current_frame_size = 0; + break; + default: + GST_WARNING ("parse error %d", status); + /* just keep parsing, the decoder should have flushed the broken unit */ + ret = GST_VAAPI_DECODE_FLOW_PARSE_DATA; + decode->current_frame_size = 0; + + GST_INFO ("requesting upstream a key unit"); + gst_pad_push_event (GST_VIDEO_DECODER_SINK_PAD (decode), + gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE, + FALSE, 0)); + break; + } + return ret; +} + +static GstFlowReturn +gst_vaapidecode_parse (GstVideoDecoder * vdec, + GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos) +{ + GstFlowReturn ret; + + do { + ret = gst_vaapidecode_parse_frame (vdec, frame, adapter, at_eos); + } while (ret == GST_VAAPI_DECODE_FLOW_PARSE_DATA); + return ret; +} + +static gboolean +is_mvc_profile (GstVaapiProfile profile) +{ + return profile == GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH + || profile == GST_VAAPI_PROFILE_H264_STEREO_HIGH; +} + +static gboolean +is_svc_profile (GstVaapiProfile profile) +{ + return profile == GST_VAAPI_PROFILE_H264_SCALABLE_BASELINE + || profile == GST_VAAPI_PROFILE_H264_SCALABLE_HIGH; +} + +static void +find_mvc_and_svc (GArray * profiles, gboolean * have_mvc, gboolean * have_svc) +{ + guint i; + + for (i = 0; i < profiles->len; i++) { + const GstVaapiProfile profile = + g_array_index (profiles, GstVaapiProfile, i); + + *have_mvc |= is_mvc_profile (profile); + *have_svc |= is_svc_profile (profile); + } +} + +static gboolean +gst_vaapidecode_ensure_allowed_sinkpad_caps (GstVaapiDecode * decode) +{ + GstCaps *caps, *allowed_sinkpad_caps; + GstPad *const sinkpad = GST_VIDEO_DECODER_SINK_PAD (decode); + GArray *profiles; + GstVaapiDisplay *const display = GST_VAAPI_PLUGIN_BASE_DISPLAY (decode); + guint i; + gboolean base_only = FALSE; + gboolean have_mvc = FALSE; + gboolean have_svc = FALSE; + + profiles = gst_vaapi_display_get_decode_profiles (display); + if (!profiles) + goto error_no_profiles; + + allowed_sinkpad_caps = gst_caps_new_empty (); + if (!allowed_sinkpad_caps) + goto error_no_memory; + + if (g_object_class_find_property (G_OBJECT_GET_CLASS (decode), "base-only")) { + g_object_get (decode, "base-only", &base_only, NULL); + } + + find_mvc_and_svc (profiles, &have_mvc, &have_svc); + + for (i = 0; i < profiles->len; i++) { + const GstVaapiProfile profile = + g_array_index (profiles, GstVaapiProfile, i); + const gchar *media_type_name; + const gchar *profile_name; + GstStructure *structure; + + media_type_name = gst_vaapi_profile_get_media_type_name (profile); + if (!media_type_name) + continue; + + caps = gst_caps_from_string (media_type_name); + if (!caps) + continue; + structure = gst_caps_get_structure (caps, 0); + if (!structure) + continue; + + profile_name = gst_vaapi_profile_get_name (profile); + if (!profile_name) + goto merge_caps; + + /* Add all according -intra profile for HEVC */ + if (profile == GST_VAAPI_PROFILE_H265_MAIN + || profile == GST_VAAPI_PROFILE_H265_MAIN10 + || profile == GST_VAAPI_PROFILE_H265_MAIN_422_10 + || profile == GST_VAAPI_PROFILE_H265_MAIN_444 + || profile == GST_VAAPI_PROFILE_H265_MAIN_444_10 + || profile == GST_VAAPI_PROFILE_H265_MAIN12 + || profile == GST_VAAPI_PROFILE_H265_MAIN_444_12 + || profile == GST_VAAPI_PROFILE_H265_MAIN_422_12) { + gchar *profiles[3], *intra_name; + + intra_name = g_strdup_printf ("%s-intra", profile_name); + + profiles[0] = (gchar *) profile_name; + profiles[1] = intra_name; + profiles[2] = NULL; + + gst_vaapi_structure_set_profiles (structure, profiles); + g_free (intra_name); + + } else if (profile == GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE) { + /* XXX: artificially adding baseline if constrained_baseline is + * available. */ + gchar *profiles[] = { (gchar *) profile_name, "baseline", NULL }; + + gst_vaapi_structure_set_profiles (structure, profiles); + } else if (profile == GST_VAAPI_PROFILE_H264_HIGH) { + gchar *profiles[11] = { (gchar *) profile_name, "progressive-high", + "constrained-high" + }; + gint i = 3; + + if (base_only && !have_mvc) { + GST_DEBUG ("base_only: force adding MVC profiles in caps"); + + profiles[i++] = "multiview-high"; + profiles[i++] = "stereo-high"; + } + + if (base_only && !have_svc) { + GST_DEBUG ("base_only: force adding SVC profiles in caps"); + + profiles[i++] = "scalable-constrained-baseline"; + profiles[i++] = "scalable-baseline"; + profiles[i++] = "scalable-high-intra"; + profiles[i++] = "scalable-constrained-high"; + profiles[i++] = "scalable-high"; + } + + profiles[i++] = NULL; + + gst_vaapi_structure_set_profiles (structure, profiles); + } else { + gst_structure_set (structure, "profile", G_TYPE_STRING, + profile_name, NULL); + } + + merge_caps: + gst_vaapi_profile_caps_append_decoder (display, profile, structure); + allowed_sinkpad_caps = gst_caps_merge (allowed_sinkpad_caps, caps); + } + + caps = gst_pad_get_pad_template_caps (sinkpad); + decode->allowed_sinkpad_caps = + gst_caps_intersect (allowed_sinkpad_caps, caps); + gst_caps_unref (caps); + gst_caps_unref (allowed_sinkpad_caps); + decode->allowed_sinkpad_caps = + gst_caps_simplify (decode->allowed_sinkpad_caps); + GST_DEBUG_OBJECT (decode, "allowed sink caps %" GST_PTR_FORMAT, + decode->allowed_sinkpad_caps); + + g_array_unref (profiles); + return TRUE; + + /* ERRORS */ +error_no_profiles: + { + GST_ERROR ("failed to retrieve VA decode profiles"); + return FALSE; + } +error_no_memory: + { + GST_ERROR ("failed to allocate allowed-caps set"); + g_array_unref (profiles); + return FALSE; + } +} + +static GstCaps * +gst_vaapidecode_sink_getcaps (GstVideoDecoder * vdec, GstCaps * filter) +{ + GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec); + GstCaps *result; + + if (decode->allowed_sinkpad_caps) + goto bail; + + /* if we haven't a display yet, return our pad's template caps */ + if (!GST_VAAPI_PLUGIN_BASE_DISPLAY (decode)) + goto bail; + + /* if the allowed caps calculation fails, return an empty caps, so + * the auto-plug can try other decoder */ + if (!gst_vaapidecode_ensure_allowed_sinkpad_caps (decode)) + return gst_caps_new_empty (); + +bail: + result = gst_video_decoder_proxy_getcaps (vdec, decode->allowed_sinkpad_caps, + filter); + + GST_DEBUG_OBJECT (decode, "Returning sink caps %" GST_PTR_FORMAT, result); + + return result; +} + +static gboolean +gst_vaapidecode_sink_query (GstVideoDecoder * vdec, GstQuery * query) +{ + gboolean ret = TRUE; + GstElement *const element = GST_ELEMENT (vdec); + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_CONTEXT:{ + ret = gst_vaapi_handle_context_query (element, query); + break; + } + default:{ + ret = GST_VIDEO_DECODER_CLASS (parent_class)->sink_query (vdec, query); + break; + } + } + + return ret; +} + +static gboolean +gst_vaapidecode_src_query (GstVideoDecoder * vdec, GstQuery * query) +{ + gboolean ret = TRUE; + GstElement *const element = GST_ELEMENT (vdec); + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_CONTEXT:{ + ret = gst_vaapi_handle_context_query (element, query); + break; + } + case GST_QUERY_CAPS:{ + GstCaps *caps, *filter = NULL; + gboolean fixed_caps; + + fixed_caps = GST_PAD_IS_FIXED_CAPS (GST_VIDEO_DECODER_SRC_PAD (vdec)); + if (!fixed_caps) { + gst_query_parse_caps (query, &filter); + caps = gst_vaapidecode_get_allowed_srcpad_caps (GST_VAAPIDECODE (vdec)); + + if (filter) { + GstCaps *tmp = caps; + caps = + gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (tmp); + } + + gst_query_set_caps_result (query, caps); + gst_caps_unref (caps); + break; + } + /* else jump to default */ + } + default:{ + ret = GST_VIDEO_DECODER_CLASS (parent_class)->src_query (vdec, query); + break; + } + } + + return ret; +} + +static gboolean +gst_vaapidecode_transform_meta (GstVideoDecoder * + vdec, GstVideoCodecFrame * frame, GstMeta * meta) +{ + const GstMetaInfo *info = meta->info; + + if (GST_VIDEO_DECODER_CLASS (parent_class)->transform_meta (vdec, frame, + meta)) + return TRUE; + + if (!g_strcmp0 (g_type_name (info->type), "GstVideoRegionOfInterestMeta")) + return TRUE; + + return FALSE; +} + +static void +gst_vaapidecode_class_init (GstVaapiDecodeClass * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstElementClass *const element_class = GST_ELEMENT_CLASS (klass); + GstVideoDecoderClass *const vdec_class = GST_VIDEO_DECODER_CLASS (klass); + GstPadTemplate *pad_template; + GstVaapiDecoderMap *map; + gchar *name, *longname, *description; + GstCaps *caps; + + GST_DEBUG_CATEGORY_INIT (gst_debug_vaapidecode, + GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC); + + parent_class = g_type_class_peek_parent (klass); + + gst_vaapi_plugin_base_class_init (GST_VAAPI_PLUGIN_BASE_CLASS (klass)); + + object_class->finalize = gst_vaapidecode_finalize; + + vdec_class->open = GST_DEBUG_FUNCPTR (gst_vaapidecode_open); + vdec_class->close = GST_DEBUG_FUNCPTR (gst_vaapidecode_close); + vdec_class->start = GST_DEBUG_FUNCPTR (gst_vaapidecode_start); + vdec_class->stop = GST_DEBUG_FUNCPTR (gst_vaapidecode_stop); + vdec_class->set_format = GST_DEBUG_FUNCPTR (gst_vaapidecode_set_format); + vdec_class->flush = GST_DEBUG_FUNCPTR (gst_vaapidecode_flush); + vdec_class->parse = GST_DEBUG_FUNCPTR (gst_vaapidecode_parse); + vdec_class->handle_frame = GST_DEBUG_FUNCPTR (gst_vaapidecode_handle_frame); + vdec_class->finish = GST_DEBUG_FUNCPTR (gst_vaapidecode_finish); + vdec_class->drain = GST_DEBUG_FUNCPTR (gst_vaapidecode_drain); + vdec_class->decide_allocation = + GST_DEBUG_FUNCPTR (gst_vaapidecode_decide_allocation); + vdec_class->src_query = GST_DEBUG_FUNCPTR (gst_vaapidecode_src_query); + vdec_class->sink_query = GST_DEBUG_FUNCPTR (gst_vaapidecode_sink_query); + vdec_class->getcaps = GST_DEBUG_FUNCPTR (gst_vaapidecode_sink_getcaps); + vdec_class->transform_meta = + GST_DEBUG_FUNCPTR (gst_vaapidecode_transform_meta); + + map = (GstVaapiDecoderMap *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass), + GST_VAAPI_DECODE_PARAMS_QDATA); + + if (map->codec) { + name = g_ascii_strup (map->name, -1); + longname = g_strdup_printf ("VA-API %s decoder", name); + description = g_strdup_printf ("A VA-API based %s video decoder", name); + g_free (name); + } else { + longname = g_strdup ("VA-API decoder"); + description = g_strdup (GST_PLUGIN_DESC); + } + + element_class->set_context = gst_vaapi_base_set_context; + gst_element_class_set_static_metadata (element_class, longname, + "Codec/Decoder/Video/Hardware", description, + "Gwenole Beauchesne , " + "Halley Zhao , " + "Sreerenj Balachandran , " + "Wind Yuan , Junyan He "); + + g_free (longname); + g_free (description); + + if (map->install_properties) + map->install_properties (object_class); + + /* sink pad */ + caps = gst_caps_from_string (map->caps_str); + pad_template = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, + caps); + gst_caps_unref (caps); + gst_element_class_add_pad_template (element_class, pad_template); + + /* src pad */ + gst_element_class_add_static_pad_template (element_class, + &gst_vaapidecode_src_factory); +} + +static void +gst_vaapidecode_init (GstVaapiDecode * decode) +{ + GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode); + + gst_vaapi_plugin_base_init (GST_VAAPI_PLUGIN_BASE (decode), GST_CAT_DEFAULT); + + gst_video_decoder_set_packetized (vdec, FALSE); +} + +gboolean +gst_vaapidecode_register (GstPlugin * plugin, GArray * decoders) +{ + gboolean ret = FALSE; + guint i, codec, rank; + gchar *type_name, *element_name; + const gchar *name; + GType type; + GTypeInfo typeinfo = { + sizeof (GstVaapiDecodeClass), + NULL, + NULL, + (GClassInitFunc) gst_vaapidecode_class_init, + NULL, + NULL, + sizeof (GstVaapiDecode), + 0, + (GInstanceInitFunc) gst_vaapidecode_init, + }; + + for (i = 0; i < G_N_ELEMENTS (vaapi_decode_map); i++) { + codec = vaapi_decode_map[i].codec; + rank = vaapi_decode_map[i].rank; + name = vaapi_decode_map[i].name; + + if (codec && !gst_vaapi_codecs_has_codec (decoders, codec)) + continue; + + if (codec) { + type_name = g_strdup_printf ("GstVaapiDecode_%s", name); + element_name = g_strdup_printf ("vaapi%sdec", name); + } else { + type_name = g_strdup ("GstVaapiDecode"); + element_name = g_strdup_printf ("vaapidecode"); + } + + type = g_type_from_name (type_name); + if (!type) { + /* create the gtype now */ + type = g_type_register_static (GST_TYPE_VIDEO_DECODER, type_name, + &typeinfo, 0); + gst_vaapi_plugin_base_init_interfaces (type); + g_type_set_qdata (type, GST_VAAPI_DECODE_PARAMS_QDATA, + (gpointer) & vaapi_decode_map[i]); + } + + /* Register GstVaapiDecode as GObject type, but not in GStreamer, so + * vaapidecodebin can use it internally, but no exposed as a plugin + * feature */ + if (codec) + ret |= gst_element_register (plugin, element_name, rank, type); + + g_free (element_name); + g_free (type_name); + } + + return ret; +} diff --git a/gst/vaapi/gstvaapidecode.h b/gst/vaapi/gstvaapidecode.h new file mode 100644 index 0000000000..77ab3ce709 --- /dev/null +++ b/gst/vaapi/gstvaapidecode.h @@ -0,0 +1,68 @@ +/* + * gstvaapidecode.h - VA-API video decoder + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPIDECODE_H +#define GST_VAAPIDECODE_H + +#include "gstvaapipluginbase.h" +#include + +G_BEGIN_DECLS + +#define GST_VAAPIDECODE(obj) ((GstVaapiDecode *)(obj)) + +typedef struct _GstVaapiDecode GstVaapiDecode; +typedef struct _GstVaapiDecodeClass GstVaapiDecodeClass; + +struct _GstVaapiDecode { + /*< private >*/ + GstVaapiPluginBase parent_instance; + + GstCaps *sinkpad_caps; + GstCaps *srcpad_caps; + GstVideoInfo decoded_info; + GstVaapiDecoder *decoder; + GstCaps *allowed_sinkpad_caps; + GstCaps *allowed_srcpad_caps; + guint current_frame_size; + guint has_texture_upload_meta : 1; + + guint display_width; + guint display_height; + + GstVideoCodecState *input_state; + + gboolean do_renego; +}; + +struct _GstVaapiDecodeClass { + /*< private >*/ + GstVaapiPluginBaseClass parent_class; +}; + +gboolean gst_vaapidecode_register (GstPlugin * plugin, GArray * decoders); + +G_END_DECLS + +#endif /* GST_VAAPIDECODE_H */ diff --git a/gst/vaapi/gstvaapidecode_props.c b/gst/vaapi/gstvaapidecode_props.c new file mode 100644 index 0000000000..dc52677674 --- /dev/null +++ b/gst/vaapi/gstvaapidecode_props.c @@ -0,0 +1,114 @@ +/* + * gstvaapidecode_props.c - VA-API decoders specific properties + * + * Copyright (C) 2017 Intel Corporation + * Author: Gwenole Beauchesne + * Author: Victor Jaquez + * + * This program 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gstvaapidecode_props.h" +#include "gstvaapidecode.h" + +#include + +enum +{ + GST_VAAPI_DECODER_H264_PROP_FORCE_LOW_LATENCY = 1, + GST_VAAPI_DECODER_H264_PROP_BASE_ONLY, +}; + +static gint h264_private_offset; + +static void +gst_vaapi_decode_h264_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstVaapiDecodeH264Private *priv; + + priv = gst_vaapi_decode_h264_get_instance_private (object); + + switch (prop_id) { + case GST_VAAPI_DECODER_H264_PROP_FORCE_LOW_LATENCY: + g_value_set_boolean (value, priv->is_low_latency); + break; + case GST_VAAPI_DECODER_H264_PROP_BASE_ONLY: + g_value_set_boolean (value, priv->base_only); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_decode_h264_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstVaapiDecodeH264Private *priv; + GstVaapiDecoderH264 *decoder; + + priv = gst_vaapi_decode_h264_get_instance_private (object); + + switch (prop_id) { + case GST_VAAPI_DECODER_H264_PROP_FORCE_LOW_LATENCY: + priv->is_low_latency = g_value_get_boolean (value); + decoder = GST_VAAPI_DECODER_H264 (GST_VAAPIDECODE (object)->decoder); + if (decoder) + gst_vaapi_decoder_h264_set_low_latency (decoder, priv->is_low_latency); + break; + case GST_VAAPI_DECODER_H264_PROP_BASE_ONLY: + priv->base_only = g_value_get_boolean (value); + decoder = GST_VAAPI_DECODER_H264 (GST_VAAPIDECODE (object)->decoder); + if (decoder) + gst_vaapi_decoder_h264_set_base_only (decoder, priv->base_only); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +void +gst_vaapi_decode_h264_install_properties (GObjectClass * klass) +{ + h264_private_offset = sizeof (GstVaapiDecodeH264Private); + g_type_class_adjust_private_offset (klass, &h264_private_offset); + + klass->get_property = gst_vaapi_decode_h264_get_property; + klass->set_property = gst_vaapi_decode_h264_set_property; + + g_object_class_install_property (klass, + GST_VAAPI_DECODER_H264_PROP_FORCE_LOW_LATENCY, + g_param_spec_boolean ("low-latency", "Force low latency mode", + "When enabled, frames will be pushed as soon as they are available. " + "It might violate the H.264 spec.", FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (klass, GST_VAAPI_DECODER_H264_PROP_BASE_ONLY, + g_param_spec_boolean ("base-only", "Decode base view only", + "Drop any NAL unit not defined in Annex.A", FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +} + +GstVaapiDecodeH264Private * +gst_vaapi_decode_h264_get_instance_private (gpointer self) +{ + if (h264_private_offset == 0) + return NULL; + return (G_STRUCT_MEMBER_P (self, h264_private_offset)); +} diff --git a/gst/vaapi/gstvaapidecode_props.h b/gst/vaapi/gstvaapidecode_props.h new file mode 100644 index 0000000000..b1f2fec600 --- /dev/null +++ b/gst/vaapi/gstvaapidecode_props.h @@ -0,0 +1,47 @@ +/* + * gstvaapidecode_props.h - VA-API decoders specific properties + * + * Copyright (C) 2017 Intel Corporation + * Author: Gwenole Beauchesne + * Author: Victor Jaquez + * + * This program 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODE_PROPS_H +#define GST_VAAPI_DECODE_PROPS_H + +#include "gstcompat.h" + +G_BEGIN_DECLS + +typedef struct _GstVaapiDecodeH264Private GstVaapiDecodeH264Private; + +struct _GstVaapiDecodeH264Private +{ + gboolean is_low_latency; + gboolean base_only; +}; + +void +gst_vaapi_decode_h264_install_properties (GObjectClass * klass); + +GstVaapiDecodeH264Private * +gst_vaapi_decode_h264_get_instance_private (gpointer self); + +G_END_DECLS + +#endif /* GST_VAAPI_DECODE_PROPS_H */ diff --git a/gst/vaapi/gstvaapidecodebin.c b/gst/vaapi/gstvaapidecodebin.c new file mode 100644 index 0000000000..7358506989 --- /dev/null +++ b/gst/vaapi/gstvaapidecodebin.c @@ -0,0 +1,444 @@ +/* + * gstvaapidecodebin.c + * + * Copyright (C) 2015 Intel Corporation + * Author: Sreerenj Balachandran + * Author: Victor Jaquez + * + * 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-vaapidecodebin + * @short_description: A VA-API based video decoder with a + * post-processor + * + * vaapidecodebin is similar vaapi{CODEC}dec, but it is composed by + * the unregistered vaapidecode, a #GstQueue, and the + * #GstVaapiPostproc, if it is available and functional in the setup. + * + * It offers the functionality of GstVaapiDecoder and the many options + * of #GstVaapiPostproc. + * + * ## Example launch line + * + * |[ + * gst-launch-1.0 filesrc location=~/big_buck_bunny.mov ! qtdemux ! h264parse ! vaapidecodebin ! vaapisink + * ]| + */ + +#include "gstcompat.h" +#include +#include +#include +#include +#include "gstvaapipluginutil.h" +#include "gstvaapidecodebin.h" +#include "gstvaapivideocontext.h" +#include "gstvaapipluginbase.h" +#include "gstvaapi.h" + +#define GST_PLUGIN_NAME "vaapidecodebin" +#define GST_PLUGIN_DESC "A VA-API based bin with a decoder and a postprocessor" + +GST_DEBUG_CATEGORY_STATIC (gst_debug_vaapi_decode_bin); +#define GST_CAT_DEFAULT gst_debug_vaapi_decode_bin + +#define DEFAULT_QUEUE_MAX_SIZE_BUFFERS 1 +#define DEFAULT_QUEUE_MAX_SIZE_BYTES 0 +#define DEFAULT_QUEUE_MAX_SIZE_TIME 0 +#define DEFAULT_DEINTERLACE_METHOD GST_VAAPI_DEINTERLACE_METHOD_BOB + +enum +{ + PROP_0, + PROP_MAX_SIZE_BUFFERS, + PROP_MAX_SIZE_BYTES, + PROP_MAX_SIZE_TIME, + PROP_DEINTERLACE_METHOD, + PROP_DISABLE_VPP, + PROP_LAST +}; + +static GParamSpec *properties[PROP_LAST]; + +/* Default templates */ +#define GST_CAPS_CODEC(CODEC) CODEC "; " +/* *INDENT-OFF* */ +static const char gst_vaapi_decode_bin_sink_caps_str[] = + GST_CAPS_CODEC("video/mpeg, mpegversion=2, systemstream=(boolean)false") + GST_CAPS_CODEC("video/mpeg, mpegversion=4") + GST_CAPS_CODEC("video/x-divx") + GST_CAPS_CODEC("video/x-xvid") + GST_CAPS_CODEC("video/x-h263") + GST_CAPS_CODEC("video/x-h264") + GST_CAPS_CODEC("video/x-h265") + GST_CAPS_CODEC("video/x-wmv") + GST_CAPS_CODEC("video/x-vp8") + GST_CAPS_CODEC("video/x-vp9") + ; +/* *INDENT-ON* */ + +/* *INDENT-OFF* */ +static const char gst_vaapi_decode_bin_src_caps_str[] = + GST_VAAPI_MAKE_SURFACE_CAPS ", " + GST_CAPS_INTERLACED_FALSE "; " +#if (USE_GLX || USE_EGL) + GST_VAAPI_MAKE_GLTEXUPLOAD_CAPS ", " + GST_CAPS_INTERLACED_FALSE "; " +#endif + GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS_ALL) ", " + GST_CAPS_INTERLACED_FALSE; +/* *INDENT-ON* */ + +static GstStaticPadTemplate gst_vaapi_decode_bin_sink_factory = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (gst_vaapi_decode_bin_sink_caps_str)); + +static GstStaticPadTemplate gst_vaapi_decode_bin_src_factory = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (gst_vaapi_decode_bin_src_caps_str)); + +G_DEFINE_TYPE (GstVaapiDecodeBin, gst_vaapi_decode_bin, GST_TYPE_BIN); + +static gboolean gst_vaapi_decode_bin_configure (GstVaapiDecodeBin * self); + +static void +post_missing_element_message (GstVaapiDecodeBin * vaapidecbin, + const gchar * missing_factory) +{ + GstMessage *msg; + + msg = gst_missing_element_message_new (GST_ELEMENT_CAST (vaapidecbin), + missing_factory); + gst_element_post_message (GST_ELEMENT_CAST (vaapidecbin), msg); + + GST_ELEMENT_WARNING (vaapidecbin, CORE, MISSING_PLUGIN, + ("Missing element '%s' - check your GStreamer installation.", + missing_factory), ("video decoding might fail")); +} + +static void +gst_vaapi_decode_bin_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstVaapiDecodeBin *vaapidecbin = GST_VAAPI_DECODE_BIN (object); + + switch (prop_id) { + case PROP_MAX_SIZE_BYTES: + vaapidecbin->max_size_bytes = g_value_get_uint (value); + g_object_set (G_OBJECT (vaapidecbin->queue), "max-size-bytes", + vaapidecbin->max_size_bytes, NULL); + break; + case PROP_MAX_SIZE_BUFFERS: + vaapidecbin->max_size_buffers = g_value_get_uint (value); + g_object_set (G_OBJECT (vaapidecbin->queue), "max-size-buffers", + vaapidecbin->max_size_buffers, NULL); + break; + case PROP_MAX_SIZE_TIME: + vaapidecbin->max_size_time = g_value_get_uint64 (value); + g_object_set (G_OBJECT (vaapidecbin->queue), "max-size-time", + vaapidecbin->max_size_time, NULL); + break; + case PROP_DEINTERLACE_METHOD: + vaapidecbin->deinterlace_method = g_value_get_enum (value); + if (vaapidecbin->postproc) + g_object_set (G_OBJECT (vaapidecbin->postproc), "deinterlace-method", + vaapidecbin->deinterlace_method, NULL); + break; + case PROP_DISABLE_VPP: + /* @TODO: Add run-time disabling support */ + vaapidecbin->disable_vpp = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_decode_bin_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstVaapiDecodeBin *vaapidecbin = GST_VAAPI_DECODE_BIN (object); + + switch (prop_id) { + case PROP_MAX_SIZE_BYTES: + g_value_set_uint (value, vaapidecbin->max_size_bytes); + break; + case PROP_MAX_SIZE_BUFFERS: + g_value_set_uint (value, vaapidecbin->max_size_buffers); + break; + case PROP_MAX_SIZE_TIME: + g_value_set_uint64 (value, vaapidecbin->max_size_time); + break; + case PROP_DEINTERLACE_METHOD: + g_value_set_enum (value, vaapidecbin->deinterlace_method); + break; + case PROP_DISABLE_VPP: + g_value_set_boolean (value, vaapidecbin->disable_vpp); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstStateChangeReturn +gst_vaapi_decode_bin_change_state (GstElement * element, + GstStateChange transition) +{ + GstVaapiDecodeBin *vaapidecbin = GST_VAAPI_DECODE_BIN (element); + GstStateChangeReturn ret; + + switch (transition) { + default: + break; + } + + ret = GST_ELEMENT_CLASS (gst_vaapi_decode_bin_parent_class)->change_state + (element, transition); + if (ret == GST_STATE_CHANGE_FAILURE) + return ret; + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + if (!gst_vaapi_decode_bin_configure (vaapidecbin)) + return GST_STATE_CHANGE_FAILURE; + break; + default: + break; + } + + return ret; +} + +static void +gst_vaapi_decode_bin_class_init (GstVaapiDecodeBinClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *element_class; + + gobject_class = G_OBJECT_CLASS (klass); + element_class = GST_ELEMENT_CLASS (klass); + + gobject_class->set_property = gst_vaapi_decode_bin_set_property; + gobject_class->get_property = gst_vaapi_decode_bin_get_property; + + element_class->change_state = gst_vaapi_decode_bin_change_state; + gst_element_class_set_static_metadata (element_class, + "VA-API Decode Bin", + "Codec/Decoder/Video/Hardware", + GST_PLUGIN_DESC, + "Sreerenj Balachandran , " + "Victor Jaquez "); + + properties[PROP_MAX_SIZE_BYTES] = g_param_spec_uint ("max-size-bytes", + "Max. size (kB)", "Max. amount of data in the queue (bytes, 0=disable)", + 0, G_MAXUINT, DEFAULT_QUEUE_MAX_SIZE_BYTES, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + properties[PROP_MAX_SIZE_BUFFERS] = g_param_spec_uint ("max-size-buffers", + "Max. size (buffers)", "Max. number of buffers in the queue (0=disable)", + 0, G_MAXUINT, DEFAULT_QUEUE_MAX_SIZE_BUFFERS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + properties[PROP_MAX_SIZE_TIME] = g_param_spec_uint64 ("max-size-time", + "Max. size (ns)", "Max. amount of data in the queue (in ns, 0=disable)", + 0, G_MAXUINT64, DEFAULT_QUEUE_MAX_SIZE_TIME, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + properties[PROP_DEINTERLACE_METHOD] = g_param_spec_enum ("deinterlace-method", + "Deinterlace method", "Deinterlace method to use", + GST_VAAPI_TYPE_DEINTERLACE_METHOD, DEFAULT_DEINTERLACE_METHOD, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + properties[PROP_DISABLE_VPP] = g_param_spec_boolean ("disable-vpp", + "Disable VPP", + "Disable Video Post Processing (No support for run time disabling)", + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (gobject_class, PROP_LAST, properties); + + gst_element_class_add_static_pad_template (element_class, + &gst_vaapi_decode_bin_sink_factory); + + gst_element_class_add_static_pad_template (element_class, + &gst_vaapi_decode_bin_src_factory); + + GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi_decode_bin, + GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC); +} + +static gboolean +gst_vaapi_decode_bin_configure (GstVaapiDecodeBin * vaapidecbin) +{ + GstElement *capsfilter; + GstCaps *caps; + GstPad *queue_srcpad, *bin_srcpad, *capsfilter_sinkpad, *vpp_srcpad; + gboolean res; + gboolean has_vpp; + + g_object_set (G_OBJECT (vaapidecbin->queue), + "max-size-bytes", vaapidecbin->max_size_bytes, + "max-size-buffers", vaapidecbin->max_size_buffers, + "max-size-time", vaapidecbin->max_size_time, NULL); + + if (vaapidecbin->disable_vpp || vaapidecbin->configured) + return TRUE; + + has_vpp = _gst_vaapi_has_video_processing; + + if (!has_vpp && (vaapidecbin->deinterlace_method == + GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE + || vaapidecbin->deinterlace_method == + GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED)) { + GST_ERROR_OBJECT (vaapidecbin, + "Don't have VPP support but advanced deinterlacing selected"); + return FALSE; + } + + GST_INFO_OBJECT (vaapidecbin, "enabling VPP"); + + /* capsfilter to force memory:VASurface */ + caps = gst_caps_from_string ("video/x-raw(memory:VASurface)"); + if (!caps) + goto error_cannot_set_caps; + capsfilter = gst_element_factory_make ("capsfilter", NULL); + g_object_set (capsfilter, "caps", caps, NULL); + gst_caps_unref (caps); + + /* create the postproc */ + vaapidecbin->postproc = gst_element_factory_make ("vaapipostproc", NULL); + if (!vaapidecbin->postproc) + goto error_vpp_missing; + g_object_set (G_OBJECT (vaapidecbin->postproc), "deinterlace-method", + vaapidecbin->deinterlace_method, NULL); + + gst_bin_add_many (GST_BIN (vaapidecbin), capsfilter, vaapidecbin->postproc, + NULL); + + if (!gst_element_link (capsfilter, vaapidecbin->postproc)) + goto error_sync_state; + + if (!gst_element_sync_state_with_parent (capsfilter)) + goto error_sync_state; + if (!gst_element_sync_state_with_parent (vaapidecbin->postproc)) + goto error_sync_state; + + /* break source ghost pad target */ + bin_srcpad = + gst_element_get_static_pad (GST_ELEMENT_CAST (vaapidecbin), "src"); + if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (bin_srcpad), NULL)) + goto error_link_pad; + + /* link decoder and queue */ + queue_srcpad = gst_element_get_static_pad (vaapidecbin->queue, "src"); + capsfilter_sinkpad = gst_element_get_static_pad (capsfilter, "sink"); + res = (gst_pad_link (queue_srcpad, capsfilter_sinkpad) == GST_PAD_LINK_OK); + gst_object_unref (capsfilter_sinkpad); + gst_object_unref (queue_srcpad); + if (!res) + goto error_link_pad; + + /* set vpp source pad as source ghost pad target */ + vpp_srcpad = gst_element_get_static_pad (vaapidecbin->postproc, "src"); + res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (bin_srcpad), vpp_srcpad); + gst_object_unref (vpp_srcpad); + if (!res) + goto error_link_pad; + + gst_object_unref (bin_srcpad); + vaapidecbin->configured = TRUE; + + return TRUE; + + /* ERRORS */ +error_cannot_set_caps: + { + GST_ELEMENT_ERROR (vaapidecbin, CORE, PAD, + ("Failed to configure caps for VA Surfaces."), (NULL)); + return FALSE; + } +error_vpp_missing: + { + post_missing_element_message (vaapidecbin, "vaapipostproc"); + return FALSE; + } +error_sync_state: + { + GST_ELEMENT_ERROR (vaapidecbin, CORE, STATE_CHANGE, + ("Failed to sync state of vaapipostproc"), (NULL)); + return FALSE; + } +error_link_pad: + { + gst_object_unref (bin_srcpad); + GST_ELEMENT_ERROR (vaapidecbin, CORE, PAD, + ("Failed to configure the vaapidecodebin."), (NULL)); + return FALSE; + } +} + +static void +gst_vaapi_decode_bin_init (GstVaapiDecodeBin * vaapidecbin) +{ + GstPad *pad, *ghostpad; + + vaapidecbin->max_size_bytes = DEFAULT_QUEUE_MAX_SIZE_BYTES; + vaapidecbin->max_size_buffers = DEFAULT_QUEUE_MAX_SIZE_BUFFERS; + vaapidecbin->max_size_time = DEFAULT_QUEUE_MAX_SIZE_TIME; + vaapidecbin->disable_vpp = (g_getenv ("GST_VAAPI_DISABLE_VPP") != NULL); + + /* create the decoder */ + vaapidecbin->decoder = + g_object_new (g_type_from_name ("GstVaapiDecode"), NULL); + g_assert (vaapidecbin->decoder); + + /* create the queue */ + vaapidecbin->queue = gst_element_factory_make ("queue", "vaapi-queue"); + if (!vaapidecbin->queue) { + gst_clear_object (&vaapidecbin->decoder); + post_missing_element_message (vaapidecbin, "queue"); + return; + } + + gst_bin_add_many (GST_BIN (vaapidecbin), vaapidecbin->decoder, + vaapidecbin->queue, NULL); + + if (!gst_element_link (vaapidecbin->decoder, vaapidecbin->queue)) { + gst_clear_object (&vaapidecbin->decoder); + gst_clear_object (&vaapidecbin->queue); + g_critical ("failed to link decoder and queue"); + return; + } + + /* create ghost pad sink */ + pad = gst_element_get_static_pad (vaapidecbin->decoder, "sink"); + ghostpad = gst_ghost_pad_new_from_template ("sink", pad, + GST_PAD_PAD_TEMPLATE (pad)); + gst_object_unref (pad); + if (!gst_element_add_pad (GST_ELEMENT (vaapidecbin), ghostpad)) + g_critical ("failed to add decoder sink pad to bin"); + + /* create ghost pad src */ + pad = gst_element_get_static_pad (GST_ELEMENT (vaapidecbin->queue), "src"); + ghostpad = gst_ghost_pad_new_from_template ("src", pad, + GST_PAD_PAD_TEMPLATE (pad)); + gst_object_unref (pad); + if (!gst_element_add_pad (GST_ELEMENT (vaapidecbin), ghostpad)) + g_critical ("failed to add queue source pad to bin"); +} diff --git a/gst/vaapi/gstvaapidecodebin.h b/gst/vaapi/gstvaapidecodebin.h new file mode 100644 index 0000000000..085a941bad --- /dev/null +++ b/gst/vaapi/gstvaapidecodebin.h @@ -0,0 +1,69 @@ +/* + * gstvaapidecodebin.h + * + * Copyright (C) 2015 Intel Corporation + * Author: Sreerenj Balachandran + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODE_BIN_H +#define GST_VAAPI_DECODE_BIN_H + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_DECODE_BIN (gst_vaapi_decode_bin_get_type ()) +#define GST_VAAPI_DECODE_BIN(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DECODE_BIN, GstVaapiDecodeBin)) +#define GST_VAAPI_DECODE_BIN_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPI_DECODE_BIN, GstVaapiDecodeBinClass)) +#define GST_IS_AUTO_DETECT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_DECODE_BIN)) +#define GST_IS_AUTO_DETECT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPI_DECODE_BIN)) +#define GST_VAAPI_DECODE_BIN_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_DECODE_BIN, GstVaapiDecodeBinClass)) + +typedef struct _GstVaapiDecodeBin { + /* < private > */ + GstBin parent; + + GstElement *decoder; + GstElement *queue; + GstElement *postproc; + + /* properties */ + guint max_size_buffers; + guint max_size_bytes; + guint64 max_size_time; + GstVaapiDeinterlaceMethod deinterlace_method; + gboolean disable_vpp; + + gboolean configured; +} GstVaapiDecodeBin; + +typedef struct _GstVaapiDecodeBinClass { + GstBinClass parent_class; + +} GstVaapiDecodeBinClass; + +GType gst_vaapi_decode_bin_get_type (void); + +G_END_DECLS + +#endif /* GST_VAAPI_DECODE_BIN_H */ diff --git a/gst/vaapi/gstvaapidecodedoc.c b/gst/vaapi/gstvaapidecodedoc.c new file mode 100644 index 0000000000..3deb2c4e0d --- /dev/null +++ b/gst/vaapi/gstvaapidecodedoc.c @@ -0,0 +1,227 @@ +/* + * gstvaapidecodedoc.c - VA-API video decoders documentation + * + * Copyright (C) 2016 Intel Corporation + * Author: Victor Jaquez + * + * 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-vaapijpegdec + * @short_description: A VA-API based JPEG image decoder + * + * vaapijpegdec decodes a JPEG image to surfaces suitable for the + * vaapisink or vaapipostproc elements using the installed + * [VA-API](https://wiki.freedesktop.org/www/Software/vaapi/) back-end. + * + * In the case of OpenGL based elements, the buffers have the + * #GstVideoGLTextureUploadMeta meta, which efficiently copies the + * content of the VA-API surface into a GL texture. + * + * Also it can deliver normal video buffers that can be rendered or + * processed by other elements, but the performance would be rather + * bad. + * + * ## Example launch line + * + * |[ + * gst-launch-1.0 filesrc location=~/image.jpeg ! jpegparse ! vaapijpegdec ! imagefreeze ! vaapisink + * ]| + */ + +/** + * SECTION:element-vaapimpeg2dec + * @short_description: A VA-API based MPEG2 video decoder + * + * vaapimpeg2dec decodes from MPEG2 bitstreams to surfaces suitable + * for the vaapisink or vaapipostproc elements using the installed + * [VA-API](https://wiki.freedesktop.org/www/Software/vaapi/) back-end. + * + * In the case of OpenGL based elements, the buffers have the + * #GstVideoGLTextureUploadMeta meta, which efficiently copies the + * content of the VA-API surface into a GL texture. + * + * Also it can deliver normal video buffers that can be rendered or + * processed by other elements, but the performance would be rather + * bad. + * + * ## Example launch line + * + * |[ + * gst-launch-1.0 filesrc location=~/sample.mpg ! mpegpsdemux ! vaapimpeg2dec ! vaapisink + * ]| + */ + +/** + * SECTION:element-vaapimpeg4dec + * @short_description: A VA-API based MPEG4 video decoder + * + * vaapimpeg4dec decodes from MPEG4 bitstreams to surfaces suitable + * for the vaapisink or vaapipostproc elements using the installed + * [VA-API](https://wiki.freedesktop.org/www/Software/vaapi/) back-end. + * + * In the case of OpenGL based elements, the buffers have the + * #GstVideoGLTextureUploadMeta meta, which efficiently copies the + * content of the VA-API surface into a GL texture. + * + * Also it can deliver normal video buffers that can be rendered or + * processed by other elements, but the performance would be rather + * bad. + * + * ## Example launch line + * + * |[ + * gst-launch-1.0 filesrc location=~/sample.mpeg4 ! mpeg4videoparse ! vaapimpeg4dec ! vaapisink + * ]| + */ + +/** + * SECTION:element-vaapih263dec + * @short_description: A VA-API based H263 video decoder + * + * vaapih263dec decodes from H263 bitstreams to surfaces suitable + * for the vaapisink or vaapipostproc elements using the installed + * [VA-API](https://wiki.freedesktop.org/www/Software/vaapi/) back-end. + * + * In the case of OpenGL based elements, the buffers have the + * #GstVideoGLTextureUploadMeta meta, which efficiently copies the + * content of the VA-API surface into a GL texture. + * + * Also it can deliver normal video buffers that can be rendered or + * processed by other elements, but the performance would be rather + * bad. + * + * ## Example launch line + * + * |[ + * gst-launch-1.0 filesrc location=~/sample.h263 ! h263parse ! vaapih263dec ! vaapisink + * ]| + */ + +/** + * SECTION:element-vaapih264dec + * @short_description: A VA-API based H264 video decoder + * + * vaapih264dec decodes from H264 bitstreams to surfaces suitable + * for the vaapisink or vaapipostproc elements using the installed + * [VA-API](https://wiki.freedesktop.org/www/Software/vaapi/) back-end. + * + * In the case of OpenGL based elements, the buffers have the + * #GstVideoGLTextureUploadMeta meta, which efficiently copies the + * content of the VA-API surface into a GL texture. + * + * Also it can deliver normal video buffers that can be rendered or + * processed by other elements, but the performance would be rather + * bad. + * + * ## Example launch line + * + * |[ + * gst-launch-1.0 filesrc location=~/big_buck_bunny.mov ! qtdemux ! h264parse ! vaapih264dec ! vaapisink + * ]| + */ + +/** + * SECTION:element-vaapih265dec + * @short_description: A VA-API based H265 video decoder + * + * vaapih265dec decodes from H265 bitstreams to surfaces suitable + * for the vaapisink or vaapipostproc elements using the installed + * [VA-API](https://wiki.freedesktop.org/www/Software/vaapi/) back-end. + * + * In the case of OpenGL based elements, the buffers have the + * #GstVideoGLTextureUploadMeta meta, which efficiently copies the + * content of the VA-API surface into a GL texture. + * + * Also it can deliver normal video buffers that can be rendered or + * processed by other elements, but the performance would be rather + * bad. + * + * ## Example launch line + * + * |[ + * gst-launch-1.0 filesrc location=./sample.bin ! h265parse ! vaapih265dec ! vaapisink + * ]| + */ + +/** + * SECTION:element-vaapivc1dec + * @short_description: A VA-API based VC1 video decoder + * + * vaapivc1dec decodes from VC1 bitstreams to surfaces suitable + * for the vaapisink or vaapipostproc elements using the installed + * [VA-API](https://wiki.freedesktop.org/www/Software/vaapi/) back-end. + * + * In the case of OpenGL based elements, the buffers have the + * #GstVideoGLTextureUploadMeta meta, which efficiently copies the + * content of the VA-API surface into a GL texture. + * + * Also it can deliver normal video buffers that can be rendered or + * processed by other elements, but the performance would be rather + * bad. + * + * ## Example launch line + * + * |[ + * gst-launch-1.0 filesrc location=~/elephants_dream.wmv ! asfdemux ! vaapivc1dec ! vaapisink + * ]| + */ + +/** + * SECTION:element-vaapivp8dec + * @short_description: A VA-API based VP8 video decoder + * + * vaapivp8dec decodes from VP8 bitstreams to surfaces suitable + * for the vaapisink or vaapipostproc elements using the installed + * [VA-API](https://wiki.freedesktop.org/www/Software/vaapi/) back-end. + * + * In the case of OpenGL based elements, the buffers have the + * #GstVideoGLTextureUploadMeta meta, which efficiently copies the + * content of the VA-API surface into a GL texture. + * + * Also it can deliver normal video buffers that can be rendered or + * processed by other elements, but the performance would be rather + * bad. + * + * ## Example launch line + * + * |[ + * gst-launch-1.0 filesrc location=./sample.webm ! matroskademux ! vaapivp8dec ! vaapisink + * ]| + */ + +/** + * SECTION:element-vaapivp9dec + * @short_description: A VA-API based VP9 video decoder + * + * vaapivp9dec decodes from VP9 bitstreams to surfaces suitable + * for the vaapisink or vaapipostproc elements using the installed + * [VA-API](https://wiki.freedesktop.org/www/Software/vaapi/) back-end. + * + * In the case of OpenGL based elements, the buffers have the + * #GstVideoGLTextureUploadMeta meta, which efficiently copies the + * content of the VA-API surface into a GL texture. + * + * Also it can deliver normal video buffers that can be rendered or + * processed by other elements, but the performance would be rather + * bad. + * + * ## Example launch line + * |[ + * gst-launch-1.0 filesrc location=./sample.vp9.webm ! ivfparse ! vaapivp9dec ! vaapisink + * ]| + */ diff --git a/gst/vaapi/gstvaapiencode.c b/gst/vaapi/gstvaapiencode.c new file mode 100644 index 0000000000..e86d55b9e1 --- /dev/null +++ b/gst/vaapi/gstvaapiencode.c @@ -0,0 +1,1044 @@ +/* + * gstvaapiencode.c - VA-API video encoder + * + * Copyright (C) 2013-2014 Intel Corporation + * Author: Wind Yuan + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gstcompat.h" +#include +#include +#include +#include "gstvaapiencode.h" +#include "gstvaapipluginutil.h" +#include "gstvaapivideometa.h" +#include "gstvaapivideomemory.h" +#include "gstvaapivideobufferpool.h" + +#define GST_PLUGIN_NAME "vaapiencode" +#define GST_PLUGIN_DESC "A VA-API based video encoder" + +#define GST_VAAPI_ENCODE_FLOW_TIMEOUT GST_FLOW_CUSTOM_SUCCESS +#define GST_VAAPI_ENCODE_FLOW_MEM_ERROR GST_FLOW_CUSTOM_ERROR +#define GST_VAAPI_ENCODE_FLOW_CONVERT_ERROR GST_FLOW_CUSTOM_ERROR_1 + +GST_DEBUG_CATEGORY_STATIC (gst_vaapiencode_debug); +#ifndef GST_DISABLE_GST_DEBUG +#define GST_CAT_DEFAULT gst_vaapiencode_debug +#else +#define GST_CAT_DEFAULT NULL +#endif + +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstVaapiEncode, + gst_vaapiencode, GST_TYPE_VIDEO_ENCODER, + GST_VAAPI_PLUGIN_BASE_INIT_INTERFACES); + +GST_VAAPI_PLUGIN_BASE_DEFINE_SET_CONTEXT (gst_vaapiencode_parent_class); + +enum +{ + PROP_0, + + PROP_BASE, +}; + +static inline gboolean +ensure_display (GstVaapiEncode * encode) +{ + return gst_vaapi_plugin_base_ensure_display (GST_VAAPI_PLUGIN_BASE (encode)); +} + +static gboolean +gst_vaapiencode_sink_query (GstVideoEncoder * encoder, GstQuery * query) +{ + gboolean ret = TRUE; + GstElement *const element = GST_ELEMENT (encoder); + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_CONTEXT: + ret = gst_vaapi_handle_context_query (element, query); + break; + default: + ret = GST_VIDEO_ENCODER_CLASS (gst_vaapiencode_parent_class)->sink_query + (encoder, query); + break; + } + + return ret; +} + +static gboolean +gst_vaapiencode_src_query (GstVideoEncoder * encoder, GstQuery * query) +{ + gboolean ret = TRUE; + GstElement *const element = GST_ELEMENT (encoder); + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_CONTEXT: + ret = gst_vaapi_handle_context_query (element, query); + break; + default: + ret = GST_VIDEO_ENCODER_CLASS (gst_vaapiencode_parent_class)->src_query + (encoder, query); + break; + } + + return ret; +} + +typedef struct +{ + guint id; + GParamSpec *pspec; + GValue value; +} PropValue; + +static void +prop_value_free (PropValue * prop_value) +{ + if (!prop_value) + return; + + if (G_VALUE_TYPE (&prop_value->value)) + g_value_unset (&prop_value->value); + + if (prop_value->pspec) { + g_param_spec_unref (prop_value->pspec); + prop_value->pspec = NULL; + } + g_slice_free (PropValue, prop_value); +} + +static PropValue * +prop_value_new_entry (guint id, GParamSpec * pspec, const GValue * value) +{ + PropValue *prop_value; + + if (!pspec) + return NULL; + + prop_value = g_slice_new0 (PropValue); + if (!prop_value) + return NULL; + + prop_value->id = id; + prop_value->pspec = g_param_spec_ref (pspec); + g_value_init (&prop_value->value, pspec->value_type); + + g_assert (g_value_type_compatible (pspec->value_type, G_VALUE_TYPE (value))); + g_value_copy (value, &prop_value->value); + + return prop_value; +} + +static inline PropValue * +prop_value_lookup_entry (GPtrArray * prop_values, guint prop_id) +{ + guint i; + PropValue *prop_value; + + if (prop_values == NULL) + return NULL; + + for (i = 0; i < prop_values->len; i++) { + prop_value = g_ptr_array_index (prop_values, i); + if (prop_value->id == prop_id) + return prop_value; + } + + return NULL; +} + +static GstFlowReturn +gst_vaapiencode_default_alloc_buffer (GstVaapiEncode * encode, + GstVaapiCodedBuffer * coded_buf, GstBuffer ** outbuf_ptr) +{ + GstBuffer *buf; + gint32 buf_size; + + g_return_val_if_fail (coded_buf != NULL, GST_FLOW_ERROR); + g_return_val_if_fail (outbuf_ptr != NULL, GST_FLOW_ERROR); + + buf_size = gst_vaapi_coded_buffer_get_size (coded_buf); + if (buf_size <= 0) + goto error_invalid_buffer; + + buf = + gst_video_encoder_allocate_output_buffer (GST_VIDEO_ENCODER_CAST (encode), + buf_size); + if (!buf) + goto error_create_buffer; + if (!gst_vaapi_coded_buffer_copy_into (buf, coded_buf)) + goto error_copy_buffer; + + *outbuf_ptr = buf; + return GST_FLOW_OK; + + /* ERRORS */ +error_invalid_buffer: + { + GST_ERROR ("invalid GstVaapiCodedBuffer size (%d bytes)", buf_size); + return GST_VAAPI_ENCODE_FLOW_MEM_ERROR; + } +error_create_buffer: + { + GST_ERROR ("failed to create output buffer of size %d", buf_size); + return GST_VAAPI_ENCODE_FLOW_MEM_ERROR; + } +error_copy_buffer: + { + GST_ERROR ("failed to copy GstVaapiCodedBuffer data"); + gst_buffer_unref (buf); + return GST_VAAPI_ENCODE_FLOW_MEM_ERROR; + } +} + +static gboolean +ensure_output_state (GstVaapiEncode * encode) +{ + GstVideoEncoder *const venc = GST_VIDEO_ENCODER_CAST (encode); + GstVaapiEncodeClass *const klass = GST_VAAPIENCODE_GET_CLASS (encode); + GstVaapiEncoderStatus status; + GstCaps *out_caps; + + if (!encode->input_state_changed) + return TRUE; + + out_caps = klass->get_caps (encode); + if (!out_caps) + return FALSE; + + if (encode->output_state) + gst_video_codec_state_unref (encode->output_state); + encode->output_state = gst_video_encoder_set_output_state (venc, out_caps, + encode->input_state); + + if (encode->need_codec_data) { + status = gst_vaapi_encoder_get_codec_data (encode->encoder, + &encode->output_state->codec_data); + if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) + return FALSE; + } + + if (!gst_video_encoder_negotiate (venc)) + return FALSE; + + encode->input_state_changed = FALSE; + return TRUE; +} + +static GstFlowReturn +gst_vaapiencode_push_frame (GstVaapiEncode * encode, gint64 timeout) +{ + GstVideoEncoder *const venc = GST_VIDEO_ENCODER_CAST (encode); + GstVaapiEncodeClass *const klass = GST_VAAPIENCODE_GET_CLASS (encode); + GstVideoCodecFrame *out_frame; + GstVaapiCodedBufferProxy *codedbuf_proxy = NULL; + GstVaapiEncoderStatus status; + GstBuffer *out_buffer; + GstFlowReturn ret; + + status = gst_vaapi_encoder_get_buffer_with_timeout (encode->encoder, + &codedbuf_proxy, timeout); + if (status == GST_VAAPI_ENCODER_STATUS_NO_BUFFER) + return GST_VAAPI_ENCODE_FLOW_TIMEOUT; + if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) + goto error_get_buffer; + + out_frame = gst_vaapi_coded_buffer_proxy_get_user_data (codedbuf_proxy); + if (!out_frame) + goto error_get_buffer; + gst_video_codec_frame_ref (out_frame); + gst_video_codec_frame_set_user_data (out_frame, NULL, NULL); + + /* Update output state */ + GST_VIDEO_ENCODER_STREAM_LOCK (encode); + if (!ensure_output_state (encode)) + goto error_output_state; + GST_VIDEO_ENCODER_STREAM_UNLOCK (encode); + + /* Allocate and copy buffer into system memory */ + out_buffer = NULL; + ret = klass->alloc_buffer (encode, + GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (codedbuf_proxy), &out_buffer); + + gst_vaapi_coded_buffer_proxy_replace (&codedbuf_proxy, NULL); + if (ret != GST_FLOW_OK) + goto error_allocate_buffer; + + gst_buffer_replace (&out_frame->output_buffer, out_buffer); + gst_buffer_unref (out_buffer); + + GST_TRACE_OBJECT (encode, "output:%" GST_TIME_FORMAT ", size:%zu", + GST_TIME_ARGS (out_frame->pts), gst_buffer_get_size (out_buffer)); + + return gst_video_encoder_finish_frame (venc, out_frame); + + /* ERRORS */ +error_get_buffer: + { + GST_ERROR ("failed to get encoded buffer (status %d)", status); + if (codedbuf_proxy) + gst_vaapi_coded_buffer_proxy_unref (codedbuf_proxy); + return GST_FLOW_ERROR; + } +error_allocate_buffer: + { + GST_ERROR ("failed to allocate encoded buffer in system memory"); + if (out_buffer) + gst_buffer_unref (out_buffer); + gst_video_codec_frame_unref (out_frame); + return ret; + } +error_output_state: + { + GST_ERROR ("failed to negotiate output state (status %d)", status); + GST_VIDEO_ENCODER_STREAM_UNLOCK (encode); + gst_video_codec_frame_unref (out_frame); + return GST_FLOW_NOT_NEGOTIATED; + } +} + +static void +gst_vaapiencode_buffer_loop (GstVaapiEncode * encode) +{ + GstFlowReturn ret; + const gint64 timeout = 50000; /* microseconds */ + + ret = gst_vaapiencode_push_frame (encode, timeout); + if (ret == GST_FLOW_OK || ret == GST_VAAPI_ENCODE_FLOW_TIMEOUT) + return; + + GST_LOG_OBJECT (encode, "pausing task, reason %s", gst_flow_get_name (ret)); + gst_pad_pause_task (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode)); +} + +static GArray * +get_profiles (GstVaapiEncode * encode) +{ + GstVaapiEncodeClass *klass = GST_VAAPIENCODE_GET_CLASS (encode); + GArray *profiles = NULL; + + if (klass->get_allowed_profiles) { + GstCaps *allowed = + gst_pad_get_allowed_caps (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode)); + GST_LOG_OBJECT (encode, + "Get allowed sink caps from downstream %" GST_PTR_FORMAT, allowed); + if (allowed && !gst_caps_is_empty (allowed) && !gst_caps_is_any (allowed)) + profiles = klass->get_allowed_profiles (encode, allowed); + + if (allowed) + gst_caps_unref (allowed); + + if (profiles) + return profiles; + } + + profiles = gst_vaapi_encoder_get_available_profiles (encode->encoder); + return profiles; +} + +static gboolean +ensure_allowed_sinkpad_caps (GstVaapiEncode * encode) +{ + GstCaps *out_caps = NULL; + GArray *formats = NULL; + gboolean ret = FALSE; + GArray *profiles = NULL; + gint min_width, min_height, max_width, max_height; + guint mem_types; + + if (encode->allowed_sinkpad_caps) + return TRUE; + if (!encode->encoder) + return TRUE; + + /* First, get all possible profiles. */ + profiles = get_profiles (encode); + if (profiles == NULL) + goto failed_get_profiles; + + /* Then get all supported formats, all these formats should be recognized + in video-format map. */ + formats = gst_vaapi_encoder_get_surface_attributes (encode->encoder, profiles, + &min_width, &min_height, &max_width, &max_height, &mem_types); + if (!formats) + goto failed_get_attributes; + + out_caps = gst_vaapi_build_caps_from_formats (formats, min_width, min_height, + max_width, max_height, mem_types); + if (!out_caps) + goto failed_create_caps; + + gst_caps_replace (&encode->allowed_sinkpad_caps, out_caps); + GST_INFO_OBJECT (encode, "Allowed sink caps %" GST_PTR_FORMAT, + encode->allowed_sinkpad_caps); + + ret = TRUE; + +bail: + if (!encode->allowed_sinkpad_caps) + encode->allowed_sinkpad_caps = gst_caps_new_empty (); + + if (profiles) + g_array_unref (profiles); + if (out_caps) + gst_caps_unref (out_caps); + if (formats) + g_array_unref (formats); + return ret; + +failed_get_attributes: + { + GST_WARNING_OBJECT (encode, "failed to get surface attributes"); + goto bail; + } +failed_create_caps: + { + GST_WARNING_OBJECT (encode, "failed to create sink caps"); + goto bail; + } +failed_get_profiles: + { + GST_WARNING_OBJECT (encode, "failed to get supported profiles"); + goto bail; + } +} + +static GstCaps * +gst_vaapiencode_get_caps (GstVideoEncoder * venc, GstCaps * filter) +{ + GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (venc); + GstCaps *result; + + ensure_allowed_sinkpad_caps (encode); + result = gst_video_encoder_proxy_getcaps (venc, encode->allowed_sinkpad_caps, + filter); + + GST_DEBUG_OBJECT (venc, "Negotiated sink caps %" GST_PTR_FORMAT, result); + return result; +} + +static gboolean +gst_vaapiencode_destroy (GstVaapiEncode * encode) +{ + if (encode->input_state) { + gst_video_codec_state_unref (encode->input_state); + encode->input_state = NULL; + } + + if (encode->output_state) { + gst_video_codec_state_unref (encode->output_state); + encode->output_state = NULL; + } + + gst_caps_replace (&encode->allowed_sinkpad_caps, NULL); + gst_vaapi_encoder_replace (&encode->encoder, NULL); + return TRUE; +} + +static void +gst_vaapiencode_purge (GstVaapiEncode * encode) +{ + GstVaapiCodedBufferProxy *codedbuf_proxy = NULL; + GstVaapiEncoderStatus status; + GstVideoCodecFrame *out_frame; + + do { + status = gst_vaapi_encoder_get_buffer_with_timeout (encode->encoder, + &codedbuf_proxy, 0); + if (status == GST_VAAPI_ENCODER_STATUS_SUCCESS) { + out_frame = gst_vaapi_coded_buffer_proxy_get_user_data (codedbuf_proxy); + if (out_frame) + gst_video_codec_frame_set_user_data (out_frame, NULL, NULL); + + gst_vaapi_coded_buffer_proxy_unref (codedbuf_proxy); + } + } while (status == GST_VAAPI_ENCODER_STATUS_SUCCESS); +} + +static gboolean +ensure_encoder (GstVaapiEncode * encode) +{ + GstVaapiEncodeClass *klass = GST_VAAPIENCODE_GET_CLASS (encode); + guint i; + + g_return_val_if_fail (klass->alloc_encoder, FALSE); + + if (encode->encoder) + return FALSE; + + encode->encoder = klass->alloc_encoder (encode, + GST_VAAPI_PLUGIN_BASE_DISPLAY (encode)); + if (!encode->encoder) + return FALSE; + + if (encode->prop_values && encode->prop_values->len) { + for (i = 0; i < encode->prop_values->len; i++) { + PropValue *const prop_value = g_ptr_array_index (encode->prop_values, i); + g_object_set_property ((GObject *) encode->encoder, + g_param_spec_get_name (prop_value->pspec), &prop_value->value); + } + /* clear alll the cache */ + g_ptr_array_unref (encode->prop_values); + encode->prop_values = NULL; + } + + return TRUE; +} + +static gboolean +gst_vaapiencode_open (GstVideoEncoder * venc) +{ + GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (venc); + GstVaapiDisplay *const old_display = GST_VAAPI_PLUGIN_BASE_DISPLAY (encode); + gboolean success; + + if (!gst_vaapi_plugin_base_open (GST_VAAPI_PLUGIN_BASE (encode))) + return FALSE; + + GST_VAAPI_PLUGIN_BASE_DISPLAY (encode) = NULL; + success = ensure_display (encode); + if (old_display) + gst_object_unref (old_display); + return success; +} + +static gboolean +gst_vaapiencode_start (GstVideoEncoder * venc) +{ + return ensure_encoder (GST_VAAPIENCODE_CAST (venc)); +} + +static gboolean +gst_vaapiencode_stop (GstVideoEncoder * venc) +{ + return gst_vaapiencode_destroy (GST_VAAPIENCODE_CAST (venc)); +} + +static gboolean +gst_vaapiencode_close (GstVideoEncoder * venc) +{ + gst_vaapi_plugin_base_close (GST_VAAPI_PLUGIN_BASE (venc)); + return TRUE; +} + +static gboolean +set_codec_state (GstVaapiEncode * encode, GstVideoCodecState * state) +{ + GstVaapiEncodeClass *const klass = GST_VAAPIENCODE_GET_CLASS (encode); + GstVaapiEncoderStatus status; + + g_return_val_if_fail (encode->encoder, FALSE); + + /* Initialize codec specific parameters */ + if (klass->set_config && !klass->set_config (encode)) + return FALSE; + + status = gst_vaapi_encoder_set_codec_state (encode->encoder, state); + if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) + return FALSE; + return TRUE; +} + +static gboolean +gst_vaapiencode_set_format (GstVideoEncoder * venc, GstVideoCodecState * state) +{ + GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (venc); + GstVaapiEncoderStatus status; + + g_return_val_if_fail (state->caps != NULL, FALSE); + + if (!set_codec_state (encode, state)) + return FALSE; + + if (!gst_vaapi_plugin_base_set_caps (GST_VAAPI_PLUGIN_BASE (encode), + state->caps, NULL)) + return FALSE; + + GST_VIDEO_ENCODER_STREAM_UNLOCK (encode); + status = gst_vaapi_encoder_flush (encode->encoder); + GST_VIDEO_ENCODER_STREAM_LOCK (encode); + if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) + return FALSE; + + gst_vaapiencode_purge (encode); + + if (encode->input_state) + gst_video_codec_state_unref (encode->input_state); + encode->input_state = gst_video_codec_state_ref (state); + encode->input_state_changed = TRUE; + + /* Store some tags */ + { + GstTagList *tags = gst_tag_list_new_empty (); + const gchar *encoder, *codec; + guint bitrate = 0; + + g_object_get (encode, "bitrate", &bitrate, NULL); + gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_NOMINAL_BITRATE, + bitrate, NULL); + + if ((encoder = + gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (encode), + GST_ELEMENT_METADATA_LONGNAME))) + gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER, encoder, + NULL); + + if ((codec = gst_vaapi_codec_get_name + (gst_vaapi_get_codec_from_caps (state->caps)))) + gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CODEC, codec, + NULL); + + gst_video_encoder_merge_tags (venc, tags, GST_TAG_MERGE_REPLACE); + gst_tag_list_unref (tags); + } + + return TRUE; +} + +static GstFlowReturn +gst_vaapiencode_handle_frame (GstVideoEncoder * venc, + GstVideoCodecFrame * frame) +{ + GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (venc); + GstPad *const srcpad = GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode); + GstVaapiEncoderStatus status; + GstVaapiVideoMeta *meta; + GstVaapiSurfaceProxy *proxy; + GstFlowReturn ret; + GstBuffer *buf; + GstTaskState task_state; + + task_state = gst_pad_get_task_state (srcpad); + if (task_state == GST_TASK_STOPPED || task_state == GST_TASK_PAUSED) + if (!gst_pad_start_task (srcpad, + (GstTaskFunction) gst_vaapiencode_buffer_loop, encode, NULL)) + goto error_task_failed; + + buf = NULL; + ret = gst_vaapi_plugin_base_get_input_buffer (GST_VAAPI_PLUGIN_BASE (encode), + frame->input_buffer, &buf); + if (ret != GST_FLOW_OK) + goto error_buffer_invalid; + + gst_buffer_replace (&frame->input_buffer, buf); + gst_buffer_unref (buf); + + meta = gst_buffer_get_vaapi_video_meta (buf); + if (!meta) + goto error_buffer_no_meta; + + proxy = gst_vaapi_video_meta_get_surface_proxy (meta); + if (!proxy) + goto error_buffer_no_surface_proxy; + + gst_video_codec_frame_set_user_data (frame, + gst_vaapi_surface_proxy_ref (proxy), + (GDestroyNotify) gst_vaapi_surface_proxy_unref); + + GST_VIDEO_ENCODER_STREAM_UNLOCK (encode); + status = gst_vaapi_encoder_put_frame (encode->encoder, frame); + GST_VIDEO_ENCODER_STREAM_LOCK (encode); + if (status < GST_VAAPI_ENCODER_STATUS_SUCCESS) + goto error_encode_frame; + + gst_video_codec_frame_unref (frame); + return GST_FLOW_OK; + + /* ERRORS */ +error_task_failed: + { + GST_ELEMENT_ERROR (venc, RESOURCE, FAILED, + ("Failed to start encoding thread."), (NULL)); + gst_video_codec_frame_unref (frame); + return GST_FLOW_ERROR; + } +error_buffer_invalid: + { + if (buf) + gst_buffer_unref (buf); + gst_video_codec_frame_unref (frame); + return ret; + } +error_buffer_no_meta: + { + GST_ERROR ("failed to get GstVaapiVideoMeta information"); + gst_video_codec_frame_unref (frame); + return GST_FLOW_ERROR; + } +error_buffer_no_surface_proxy: + { + GST_ERROR ("failed to get VA surface proxy"); + gst_video_codec_frame_unref (frame); + return GST_FLOW_ERROR; + } +error_encode_frame: + { + GST_ERROR ("failed to encode frame %d (status %d)", + frame->system_frame_number, status); + gst_video_codec_frame_unref (frame); + return GST_FLOW_ERROR; + } +} + +static GstFlowReturn +gst_vaapiencode_finish (GstVideoEncoder * venc) +{ + GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (venc); + GstVaapiEncoderStatus status; + GstFlowReturn ret = GST_FLOW_OK; + + /* Don't try to destroy encoder if none was created in the first place. + Return "not-negotiated" error since this means we did not even reach + GstVideoEncoder::set_format() state, where the encoder could have + been created */ + if (!encode->encoder) + return GST_FLOW_NOT_NEGOTIATED; + + GST_VIDEO_ENCODER_STREAM_UNLOCK (encode); + + status = gst_vaapi_encoder_flush (encode->encoder); + + gst_pad_stop_task (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode)); + + GST_VIDEO_ENCODER_STREAM_LOCK (encode); + + while (status == GST_VAAPI_ENCODER_STATUS_SUCCESS && ret == GST_FLOW_OK) + ret = gst_vaapiencode_push_frame (encode, 0); + + if (ret == GST_VAAPI_ENCODE_FLOW_TIMEOUT) + ret = GST_FLOW_OK; + return ret; +} + +static GstStateChangeReturn +gst_vaapiencode_change_state (GstElement * element, GstStateChange transition) +{ + GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (element); + GstVaapiEncoderStatus status; + + switch (transition) { + case GST_STATE_CHANGE_PAUSED_TO_READY: + gst_pad_stop_task (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode)); + + status = gst_vaapi_encoder_flush (encode->encoder); + if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) + goto flush_error; + + GST_VIDEO_ENCODER_STREAM_LOCK (encode); + gst_vaapiencode_purge (encode); + GST_VIDEO_ENCODER_STREAM_UNLOCK (encode); + break; + default: + break; + } + return + GST_ELEMENT_CLASS (gst_vaapiencode_parent_class)->change_state (element, + transition); + +flush_error: + { + GST_ERROR ("failed to flush pending encoded frames"); + return GST_STATE_CHANGE_FAILURE; + } +} + +static gboolean +gst_vaapiencode_propose_allocation (GstVideoEncoder * venc, GstQuery * query) +{ + GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (venc); + + if (!gst_vaapi_plugin_base_propose_allocation (plugin, query)) + return FALSE; + return TRUE; +} + +static gboolean +gst_vaapiencode_sink_event (GstVideoEncoder * venc, GstEvent * event) +{ + GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (venc); + GstPad *const srcpad = GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode); + gboolean ret; + + ret = GST_VIDEO_ENCODER_CLASS (gst_vaapiencode_parent_class)->sink_event + (venc, event); + if (!ret) + return FALSE; + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH_START: + gst_pad_pause_task (srcpad); + break; + case GST_EVENT_FLUSH_STOP: + ret = gst_pad_start_task (srcpad, + (GstTaskFunction) gst_vaapiencode_buffer_loop, encode, NULL); + break; + default: + break; + } + + return ret; +} + +static gboolean +gst_vaapiencode_flush (GstVideoEncoder * venc) +{ + GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (venc); + GstVaapiEncoderStatus status; + + if (!encode->encoder) + return FALSE; + + GST_LOG_OBJECT (encode, "flushing"); + + GST_VIDEO_ENCODER_STREAM_UNLOCK (encode); + status = gst_vaapi_encoder_flush (encode->encoder); + GST_VIDEO_ENCODER_STREAM_LOCK (encode); + if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) + return FALSE; + + gst_vaapiencode_purge (encode); + + gst_vaapi_encoder_replace (&encode->encoder, NULL); + if (!ensure_encoder (encode)) + return FALSE; + if (!set_codec_state (encode, encode->input_state)) + return FALSE; + + return TRUE; +} + +static void +gst_vaapiencode_finalize (GObject * object) +{ + GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (object); + + gst_vaapiencode_destroy (encode); + + if (encode->prop_values) { + g_ptr_array_unref (encode->prop_values); + encode->prop_values = NULL; + } + + gst_vaapi_plugin_base_finalize (GST_VAAPI_PLUGIN_BASE (object)); + G_OBJECT_CLASS (gst_vaapiencode_parent_class)->finalize (object); +} + +static void +gst_vaapiencode_init (GstVaapiEncode * encode) +{ + GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (encode); + + gst_vaapi_plugin_base_init (GST_VAAPI_PLUGIN_BASE (encode), GST_CAT_DEFAULT); + gst_pad_use_fixed_caps (GST_VAAPI_PLUGIN_BASE_SRC_PAD (plugin)); +} + +static void +gst_vaapiencode_class_init (GstVaapiEncodeClass * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstElementClass *const element_class = GST_ELEMENT_CLASS (klass); + GstVideoEncoderClass *const venc_class = GST_VIDEO_ENCODER_CLASS (klass); + + GST_DEBUG_CATEGORY_INIT (gst_vaapiencode_debug, + GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC); + + gst_vaapi_plugin_base_class_init (GST_VAAPI_PLUGIN_BASE_CLASS (klass)); + + object_class->finalize = gst_vaapiencode_finalize; + + element_class->set_context = gst_vaapi_base_set_context; + element_class->change_state = + GST_DEBUG_FUNCPTR (gst_vaapiencode_change_state); + + venc_class->open = GST_DEBUG_FUNCPTR (gst_vaapiencode_open); + venc_class->close = GST_DEBUG_FUNCPTR (gst_vaapiencode_close); + venc_class->start = GST_DEBUG_FUNCPTR (gst_vaapiencode_start); + venc_class->stop = GST_DEBUG_FUNCPTR (gst_vaapiencode_stop); + venc_class->set_format = GST_DEBUG_FUNCPTR (gst_vaapiencode_set_format); + venc_class->handle_frame = GST_DEBUG_FUNCPTR (gst_vaapiencode_handle_frame); + venc_class->finish = GST_DEBUG_FUNCPTR (gst_vaapiencode_finish); + venc_class->getcaps = GST_DEBUG_FUNCPTR (gst_vaapiencode_get_caps); + venc_class->propose_allocation = + GST_DEBUG_FUNCPTR (gst_vaapiencode_propose_allocation); + venc_class->flush = GST_DEBUG_FUNCPTR (gst_vaapiencode_flush); + venc_class->sink_event = GST_DEBUG_FUNCPTR (gst_vaapiencode_sink_event); + + klass->alloc_buffer = gst_vaapiencode_default_alloc_buffer; + + venc_class->src_query = GST_DEBUG_FUNCPTR (gst_vaapiencode_src_query); + venc_class->sink_query = GST_DEBUG_FUNCPTR (gst_vaapiencode_sink_query); + + gst_type_mark_as_plugin_api (GST_TYPE_VAAPIENCODE, 0); +} + +/* Only used by the drived class */ +void +gst_vaapiencode_set_property_subclass (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstVaapiEncodeClass *const encode_class = GST_VAAPIENCODE_GET_CLASS (object); + GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (object); + PropValue *prop_value; + + if (prop_id <= PROP_BASE || prop_id >= encode_class->prop_num) { + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + return; + } + + /* direct forward the property to encoder */ + if (encode->encoder) { + g_object_set_property ((GObject *) encode->encoder, + g_param_spec_get_name (pspec), value); + return; + } + + if (encode->prop_values) { + /* Delete the same prop already in cache */ + prop_value = prop_value_lookup_entry (encode->prop_values, prop_id); + if (prop_value) + g_ptr_array_remove (encode->prop_values, prop_value); + } else { + encode->prop_values = + g_ptr_array_new_with_free_func ((GDestroyNotify) prop_value_free); + } + + /* The encoder is delay created, we need to cache the property setting */ + prop_value = prop_value_new_entry (prop_id, pspec, value); + g_ptr_array_add (encode->prop_values, prop_value); +} + +/* Only used by the drived class */ +void +gst_vaapiencode_get_property_subclass (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstVaapiEncodeClass *const encode_class = GST_VAAPIENCODE_GET_CLASS (object); + GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (object); + PropValue *prop_value = NULL; + + if (prop_id <= PROP_BASE || prop_id >= encode_class->prop_num) { + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + return; + } + + /* direct forward the property to encoder */ + if (encode->encoder) { + g_object_get_property ((GObject *) encode->encoder, + g_param_spec_get_name (pspec), value); + return; + } + + if (encode->prop_values) + prop_value = prop_value_lookup_entry (encode->prop_values, prop_id); + + if (prop_value) { + /* In the cache */ + g_value_copy (&prop_value->value, value); + } else { + /* set the default value */ + g_param_value_set_default (pspec, value); + } +} + +/* Called by drived class to install all properties. The encode base class + does not have any property, all the properties of the according encoderXXX + class are installed to encodeXXX class. */ +gboolean +gst_vaapiencode_class_install_properties (GstVaapiEncodeClass * klass, + GObjectClass * encoder_class) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + guint i, n_props, installed; + GParamSpec **specs = NULL; + GParamSpec *pspec; + GParamSpec *new_spec; + GParamFlags flags; + + if (encoder_class) + specs = g_object_class_list_properties (encoder_class, &n_props); + if (!specs) + return FALSE; + + installed = 0; + for (i = 0; i < n_props; i++) { + pspec = specs[i]; + + /* Encoder do not want to expose */ + if (!(pspec->flags & GST_VAAPI_PARAM_ENCODER_EXPOSURE)) + continue; + /* Can only set on encoder init time */ + if (pspec->flags & G_PARAM_CONSTRUCT_ONLY) + continue; + + /* filter out the G_PARAM_CONSTRUCT, the encoder created later, no need + to set the init value in encode. + Also no GST_VAAPI_PARAM_ENCODER_EXPOSURE */ + flags = pspec->flags & (~(GST_VAAPI_PARAM_ENCODER_EXPOSURE | + G_PARAM_CONSTRUCT)); + + if (G_PARAM_SPEC_TYPE (pspec) == G_TYPE_PARAM_UINT) { + GParamSpecUInt *pspecuint = G_PARAM_SPEC_UINT (pspec); + new_spec = g_param_spec_uint (g_param_spec_get_name (pspec), + g_param_spec_get_nick (pspec), g_param_spec_get_blurb (pspec), + pspecuint->minimum, pspecuint->maximum, + pspecuint->default_value, flags); + } else if (G_PARAM_SPEC_TYPE (pspec) == G_TYPE_PARAM_INT) { + GParamSpecInt *pspecint = G_PARAM_SPEC_INT (pspec); + new_spec = g_param_spec_int (g_param_spec_get_name (pspec), + g_param_spec_get_nick (pspec), g_param_spec_get_blurb (pspec), + pspecint->minimum, pspecint->maximum, pspecint->default_value, flags); + } else if (G_IS_PARAM_SPEC_ENUM (pspec)) { + GParamSpecEnum *pspecenum = G_PARAM_SPEC_ENUM (pspec); + new_spec = g_param_spec_enum (g_param_spec_get_name (pspec), + g_param_spec_get_nick (pspec), + g_param_spec_get_blurb (pspec), + pspec->value_type, pspecenum->default_value, flags); + } else if (G_IS_PARAM_SPEC_BOOLEAN (pspec)) { + GParamSpecBoolean *pspecbool = G_PARAM_SPEC_BOOLEAN (pspec); + new_spec = g_param_spec_boolean (g_param_spec_get_name (pspec), + g_param_spec_get_nick (pspec), g_param_spec_get_blurb (pspec), + pspecbool->default_value, flags); + } else if (G_IS_PARAM_SPEC_FLAGS (pspec)) { + GParamSpecFlags *pspecflags = G_PARAM_SPEC_FLAGS (pspec); + new_spec = g_param_spec_flags (g_param_spec_get_name (pspec), + g_param_spec_get_nick (pspec), g_param_spec_get_blurb (pspec), + pspec->value_type, pspecflags->default_value, flags); + } else if (GST_IS_PARAM_SPEC_ARRAY_LIST (pspec)) { + GstParamSpecArray *pspecarray = GST_PARAM_SPEC_ARRAY_LIST (pspec); + new_spec = gst_param_spec_array (g_param_spec_get_name (pspec), + g_param_spec_get_nick (pspec), g_param_spec_get_blurb (pspec), + pspecarray->element_spec, flags); + } else { + GST_WARNING ("encoder's %s property has a unimplemented" + " type to expose to encode, the encode may lose the %s property", + g_param_spec_get_name (pspec), g_param_spec_get_name (pspec)); + continue; + } + + g_object_class_install_property (object_class, PROP_BASE + 1 + installed, + new_spec); + installed++; + } + + g_free (specs); + klass->prop_num = PROP_BASE + 1 + installed; + return TRUE; +} diff --git a/gst/vaapi/gstvaapiencode.h b/gst/vaapi/gstvaapiencode.h new file mode 100644 index 0000000000..9c3fc1b062 --- /dev/null +++ b/gst/vaapi/gstvaapiencode.h @@ -0,0 +1,217 @@ +/* + * gstvaapiencode.h - VA-API video encoder + * + * Copyright (C) 2013-2014 Intel Corporation + * Author: Wind Yuan + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPIENCODE_H +#define GST_VAAPIENCODE_H + +#include "gstvaapipluginbase.h" +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPIENCODE \ + (gst_vaapiencode_get_type ()) +#define GST_VAAPIENCODE_CAST(obj) \ + ((GstVaapiEncode *)(obj)) +#define GST_VAAPIENCODE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPIENCODE, GstVaapiEncode)) +#define GST_VAAPIENCODE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPIENCODE, GstVaapiEncodeClass)) +#define GST_VAAPIENCODE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPIENCODE, GstVaapiEncodeClass)) +#define GST_IS_VAAPIENCODE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPIENCODE)) +#define GST_IS_VAAPIENCODE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPIENCODE)) + +typedef struct _GstVaapiEncodeInitData GstVaapiEncodeInitData; +struct _GstVaapiEncodeInitData +{ + GstCaps *sink_caps; + GstCaps *src_caps; +}; + +/* *INDENT-OFF* */ +#define GST_VAAPI_ENCODE_STATIC_SINK_CAPS \ + GST_VAAPI_MAKE_SURFACE_CAPS ", " \ + GST_CAPS_INTERLACED_FALSE "; " \ + GST_VIDEO_CAPS_MAKE (GST_VAAPI_FORMATS_ALL) ", " \ + GST_CAPS_INTERLACED_FALSE ";" \ + GST_VIDEO_CAPS_MAKE_WITH_FEATURES( \ + GST_CAPS_FEATURE_MEMORY_DMABUF, \ + GST_VAAPI_FORMATS_ALL) "," \ + GST_CAPS_INTERLACED_FALSE +/* *INDENT-ON* */ + +#define GST_VAAPI_ENCODE_REGISTER_TYPE(NAME, CODEC, CLASS, _EXT_FMT_, FUN) \ + static GstVaapiEncodeInitData encode_init_data = { NULL, NULL }; \ + static GType encode_type = G_TYPE_INVALID; \ + static gpointer gst_vaapiencode_##NAME##_parent_class = NULL; \ + static void \ + gst_vaapiencode_##NAME##_class_init ( \ + GstVaapiEncode##CLASS##Class * klass, gpointer data); \ + static void gst_vaapiencode_##NAME##_class_intern_init (gpointer klass, \ + gpointer data) \ + { \ + gst_vaapiencode_##NAME##_parent_class = \ + g_type_class_peek_parent (klass); \ + gst_vaapiencode_##NAME##_class_init (klass, data); \ + } \ + static void \ + gst_vaapiencode_##NAME##_init (GstVaapiEncode##CLASS * encode); \ + GType \ + gst_vaapiencode_##NAME##_register_type (GstVaapiDisplay * display) \ + { \ + GstCaps *caps; \ + guint i, n; \ + GTypeInfo type_info = { \ + sizeof (GstVaapiEncodeClass), \ + NULL, \ + NULL, \ + (GClassInitFunc) gst_vaapiencode_##NAME##_class_intern_init, \ + NULL, \ + NULL, \ + sizeof (GstVaapiEncode##CLASS), \ + 0, \ + (GInstanceInitFunc) gst_vaapiencode_##NAME##_init, \ + }; \ + GArray *extra_fmts = NULL; \ + GstVideoFormat ext_video_fmts[] = _EXT_FMT_; \ + \ + GST_DEBUG_CATEGORY_INIT (gst_vaapi_##NAME##_encode_debug, \ + GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC); \ + \ + if ((n = G_N_ELEMENTS (ext_video_fmts))) { \ + extra_fmts = \ + g_array_sized_new (FALSE, FALSE, sizeof (GstVideoFormat), n); \ + for (i = 0; i < n; i++) \ + g_array_append_val (extra_fmts, ext_video_fmts[i]); \ + } \ + caps = gst_vaapi_build_template_raw_caps_by_codec (display, \ + GST_VAAPI_CONTEXT_USAGE_ENCODE, \ + GST_VAAPI_CODEC_##CODEC, extra_fmts); \ + g_clear_pointer (&extra_fmts, g_array_unref); \ + if (!caps) { \ + GST_ERROR ("failed to get sink caps for " #CODEC \ + " encode, can not register"); \ + return G_TYPE_INVALID; \ + } \ + \ + for (i = 0; i < gst_caps_get_size (caps); i++) { \ + GstStructure *structure = gst_caps_get_structure (caps, i); \ + if (!structure) \ + continue; \ + gst_structure_set (structure, "interlace-mode", G_TYPE_STRING, \ + "progressive", NULL); \ + } \ + GST_DEBUG (#CODEC" encode's sink caps %" GST_PTR_FORMAT, caps); \ + \ + /* class data will be leaked if the element never gets instantiated */ \ + GST_MINI_OBJECT_FLAG_SET (caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED); \ + encode_init_data.sink_caps = caps; \ + \ + caps = gst_vaapi_build_template_coded_caps_by_codec (display, \ + GST_VAAPI_CONTEXT_USAGE_ENCODE, \ + GST_VAAPI_CODEC_##CODEC, GST_CODEC_CAPS, \ + FUN); \ + if (!caps) { \ + GST_ERROR ("failed to get src caps for " #CODEC \ + " encode, can not register"); \ + gst_caps_unref (encode_init_data.sink_caps); \ + return G_TYPE_INVALID; \ + } \ + GST_DEBUG (#CODEC" encode's src caps %" GST_PTR_FORMAT, caps); \ + /* class data will be leaked if the element never gets instantiated */ \ + GST_MINI_OBJECT_FLAG_SET (caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED); \ + encode_init_data.src_caps = caps; \ + type_info.class_data = &encode_init_data; \ + encode_type = g_type_register_static (GST_TYPE_VAAPIENCODE, \ + "GstVaapiEncode"#CLASS, &type_info, 0); \ + \ + return encode_type; \ + } \ + \ + GType \ + gst_vaapiencode_##NAME##_get_type (void) \ + { \ + g_assert (encode_type != G_TYPE_INVALID); \ + return encode_type; \ + } + +typedef struct _GstVaapiEncode GstVaapiEncode; +typedef struct _GstVaapiEncodeClass GstVaapiEncodeClass; + +struct _GstVaapiEncode +{ + /*< private >*/ + GstVaapiPluginBase parent_instance; + + GstVaapiEncoder *encoder; + GstVideoCodecState *input_state; + gboolean input_state_changed; + /* needs to be set by the subclass implementation */ + gboolean need_codec_data; + GstVideoCodecState *output_state; + GPtrArray *prop_values; + GstCaps *allowed_sinkpad_caps; +}; + +struct _GstVaapiEncodeClass +{ + /*< private >*/ + GstVaapiPluginBaseClass parent_class; + + guint prop_num; + gboolean (*set_config) (GstVaapiEncode * encode); + GstCaps * (*get_caps) (GstVaapiEncode * encode); + GstVaapiEncoder * (*alloc_encoder) (GstVaapiEncode * encode, + GstVaapiDisplay * display); + GstFlowReturn (*alloc_buffer) (GstVaapiEncode * encode, + GstVaapiCodedBuffer * coded_buf, + GstBuffer ** outbuf_ptr); + /* Get all possible profiles based on allowed caps */ + GArray * (*get_allowed_profiles) (GstVaapiEncode * encode, + GstCaps * allowed); +}; + +GType +gst_vaapiencode_get_type (void) G_GNUC_CONST; + +G_GNUC_INTERNAL +void +gst_vaapiencode_set_property_subclass (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec); + +G_GNUC_INTERNAL +void +gst_vaapiencode_get_property_subclass (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +G_GNUC_INTERNAL +gboolean +gst_vaapiencode_class_install_properties (GstVaapiEncodeClass * klass, + GObjectClass * encoder_class); + +G_END_DECLS + +#endif /* GST_VAAPIENCODE_H */ diff --git a/gst/vaapi/gstvaapiencode_h264.c b/gst/vaapi/gstvaapiencode_h264.c new file mode 100644 index 0000000000..d58faafa15 --- /dev/null +++ b/gst/vaapi/gstvaapiencode_h264.c @@ -0,0 +1,587 @@ +/* + * gstvaapiencode_h264.c - VA-API H.264 encoder + * + * Copyright (C) 2012-2014 Intel Corporation + * Author: Wind Yuan + * Author: Gwenole Beauchesne + * + * 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-vaapih264enc + * @short_description: A VA-API based H.264 video encoder + * + * Encodes raw video streams into H.264 bitstreams. + * + * The #GstVaapiEncodeH264:rate-control property controls the type of + * encoding. In case of Constant Bitrate Encoding (CBR), the + * #GstVaapiEncodeH264:bitrate will determine the quality of the + * encoding. Alternatively, one may choose to perform Constant + * Quantizer or Variable Bitrate Encoding (VBR), in which case the + * #GstVaapiEncodeH264:bitrate is the maximum bitrate. + * + * The H264 profile that is eventually used depends on a few settings. + * If #GstVaapiEncodeH264:dct8x8 is enabled, then High profile is + * used. Otherwise, if #GstVaapiEncodeH264:cabac entropy coding is + * enabled or #GstVaapiEncodeH264:max-bframes are allowed, then Main + * Profile is in effect. The element will alway go with the maximal + * profile available in the caps negotation and otherwise Baseline + * profile applies. But in some cases (e.g. hardware platforms) a more + * restrictedprofile/level may be necessary. The recommended way to + * set a profile is to set it in the downstream caps. + * + * You can also set parameters to adjust the latency of encoding: + * #GstVaapiEncodeH264:quality-level is a number between 1-7, in the + * case of the Intel VAAPI driver, where a lower value will produce a + * higher quality output but with more latency; meanwhile a hihg + * number will produce a lower quality output with less latency. Also + * you can set #GstVaapiEncodeH264:tune, if your backend supports it, + * for low-power mode or high compression. + * + * ## Example launch line + * + * |[ + * gst-launch-1.0 -ev videotestsrc num-buffers=60 ! timeoverlay ! vaapih264enc ! h264parse ! mp4mux ! filesink location=test.mp4 + * ]| + */ + +#include "gstcompat.h" +#include +#include +#include +#include "gstvaapiencode_h264.h" +#include "gstvaapipluginutil.h" +#include "gstvaapivideomemory.h" + +#define GST_PLUGIN_NAME "vaapih264enc" +#define GST_PLUGIN_DESC "A VA-API based H264 video encoder" + +GST_DEBUG_CATEGORY_STATIC (gst_vaapi_h264_encode_debug); +#define GST_CAT_DEFAULT gst_vaapi_h264_encode_debug + +#define GST_CODEC_CAPS \ + "video/x-h264, " \ + "stream-format = (string) { avc, byte-stream }, " \ + "alignment = (string) au" + +#define EXTRA_FORMATS {} + +/* h264 encode */ +GST_VAAPI_ENCODE_REGISTER_TYPE (h264, H264, H264, EXTRA_FORMATS, + gst_vaapi_utils_h264_get_profile_string); + +static void +gst_vaapiencode_h264_init (GstVaapiEncodeH264 * encode) +{ + /* nothing to do here */ +} + +static void +gst_vaapiencode_h264_finalize (GObject * object) +{ + GstVaapiEncodeH264 *const encode = GST_VAAPIENCODE_H264_CAST (object); + + gst_caps_replace (&encode->available_caps, NULL); + G_OBJECT_CLASS (gst_vaapiencode_h264_parent_class)->finalize (object); +} + +static GArray * +gst_vaapiencode_h264_get_allowed_profiles (GstVaapiEncode * encode, + GstCaps * allowed) +{ + return gst_vaapi_encoder_get_profiles_from_caps (allowed, + gst_vaapi_utils_h264_get_profile_from_string); +} + +typedef struct +{ + GstVaapiProfile best_profile; + guint best_score; +} FindBestProfileData; + +static void +find_best_profile_value (FindBestProfileData * data, const GValue * value) +{ + const gchar *str; + GstVaapiProfile profile; + guint score; + + if (!value || !G_VALUE_HOLDS_STRING (value)) + return; + + str = g_value_get_string (value); + if (!str) + return; + profile = gst_vaapi_utils_h264_get_profile_from_string (str); + if (!profile) + return; + score = gst_vaapi_utils_h264_get_profile_score (profile); + if (score < data->best_score) + return; + data->best_profile = profile; + data->best_score = score; +} + +static GstVaapiProfile +find_best_profile (GstCaps * caps) +{ + FindBestProfileData data; + guint i, j, num_structures, num_values; + + data.best_profile = GST_VAAPI_PROFILE_UNKNOWN; + data.best_score = 0; + + num_structures = gst_caps_get_size (caps); + for (i = 0; i < num_structures; i++) { + GstStructure *const structure = gst_caps_get_structure (caps, i); + const GValue *const value = gst_structure_get_value (structure, "profile"); + + if (!value) + continue; + if (G_VALUE_HOLDS_STRING (value)) + find_best_profile_value (&data, value); + else if (GST_VALUE_HOLDS_LIST (value)) { + num_values = gst_value_list_get_size (value); + for (j = 0; j < num_values; j++) + find_best_profile_value (&data, gst_value_list_get_value (value, j)); + } + } + return data.best_profile; +} + +static GstCaps * +get_available_caps (GstVaapiEncodeH264 * encode) +{ + GstVaapiEncode *const base_encode = GST_VAAPIENCODE_CAST (encode); + GstVaapiEncoderH264 *const encoder = + GST_VAAPI_ENCODER_H264 (base_encode->encoder); + GstCaps *out_caps; + GArray *profiles; + GstVaapiProfile profile; + const gchar *profile_str; + GValue profile_v = G_VALUE_INIT; + GValue profile_list = G_VALUE_INIT; + guint i; + + if (encode->available_caps) + return encode->available_caps; + + g_value_init (&profile_list, GST_TYPE_LIST); + g_value_init (&profile_v, G_TYPE_STRING); + + profiles = + gst_vaapi_display_get_encode_profiles + (GST_VAAPI_PLUGIN_BASE_DISPLAY (encode)); + if (!profiles) + return NULL; + + for (i = 0; i < profiles->len; i++) { + profile = g_array_index (profiles, GstVaapiProfile, i); + if (gst_vaapi_profile_get_codec (profile) != GST_VAAPI_CODEC_H264) + continue; + profile_str = gst_vaapi_profile_get_name (profile); + if (!profile_str) + continue; + g_value_set_string (&profile_v, profile_str); + gst_value_list_append_value (&profile_list, &profile_v); + } + g_array_unref (profiles); + + out_caps = gst_caps_from_string (GST_CODEC_CAPS); + gst_caps_set_value (out_caps, "profile", &profile_list); + g_value_unset (&profile_list); + g_value_unset (&profile_v); + + if (!gst_vaapi_encoder_h264_supports_avc (encoder)) { + GST_INFO_OBJECT (encode, + "avc requires packed header support, outputting byte-stream"); + gst_caps_set_simple (out_caps, "stream-format", G_TYPE_STRING, + "byte-stream", NULL); + } + + encode->available_caps = out_caps; + + return encode->available_caps; +} + +static gboolean +gst_vaapiencode_h264_set_config (GstVaapiEncode * base_encode) +{ + GstVaapiEncodeH264 *const encode = GST_VAAPIENCODE_H264_CAST (base_encode); + GstVaapiEncoderH264 *const encoder = + GST_VAAPI_ENCODER_H264 (base_encode->encoder); + GstCaps *template_caps, *allowed_caps; + gboolean ret = TRUE; + + template_caps = + gst_pad_get_pad_template_caps (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode)); + allowed_caps = + gst_pad_get_allowed_caps (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode)); + + if (allowed_caps == template_caps) { + GST_INFO_OBJECT (encode, "downstream has ANY caps, outputting byte-stream"); + encode->is_avc = FALSE; + gst_caps_unref (allowed_caps); + } else if (!allowed_caps) { + GST_INFO_OBJECT (encode, + "downstream has NULL caps, outputting byte-stream"); + encode->is_avc = FALSE; + } else if (gst_caps_is_empty (allowed_caps)) { + GST_INFO_OBJECT (encode, "downstream has EMPTY caps"); + goto fail; + } else { + const char *stream_format = NULL; + GstStructure *structure; + GstVaapiProfile profile = GST_VAAPI_PROFILE_UNKNOWN; + GstCaps *available_caps; + GstCaps *profile_caps; + + available_caps = get_available_caps (encode); + if (!available_caps) + goto fail; + + if (!gst_caps_can_intersect (allowed_caps, available_caps)) { + GstCaps *tmp_caps; + + GST_INFO_OBJECT (encode, "downstream may have requested an unsupported " + "profile. Encoder will try to output a compatible one"); + + /* Let's try the best profile in the allowed caps. + * The internal encoder will fail later if it can't handle it */ + profile = find_best_profile (allowed_caps); + if (profile == GST_VAAPI_PROFILE_UNKNOWN) + goto fail; + + /* if allwed caps request baseline (which is deprecated), the + * encoder will try with constrained baseline which is + * compatible. */ + if (profile == GST_VAAPI_PROFILE_H264_BASELINE) + profile = GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE; + + tmp_caps = gst_caps_from_string (GST_CODEC_CAPS); + gst_caps_set_simple (tmp_caps, "profile", G_TYPE_STRING, + gst_vaapi_profile_get_name (profile), NULL); + if (!gst_vaapi_encoder_h264_supports_avc (encoder)) { + gst_caps_set_simple (tmp_caps, "stream-format", G_TYPE_STRING, + "byte-stream", NULL); + } + + profile_caps = gst_caps_intersect (available_caps, tmp_caps); + gst_caps_unref (tmp_caps); + if (gst_caps_is_empty (profile_caps)) { + gst_caps_unref (profile_caps); + goto fail; + } + } else { + profile_caps = gst_caps_intersect (allowed_caps, available_caps); + profile = find_best_profile (profile_caps); + } + + profile_caps = gst_caps_fixate (profile_caps); + structure = gst_caps_get_structure (profile_caps, 0); + stream_format = gst_structure_get_string (structure, "stream-format"); + encode->is_avc = (g_strcmp0 (stream_format, "avc") == 0); + + if (profile != GST_VAAPI_PROFILE_UNKNOWN) { + GST_INFO ("using %s profile as target decoder constraints", + gst_vaapi_utils_h264_get_profile_string (profile)); + ret = gst_vaapi_encoder_h264_set_max_profile (encoder, profile); + } else { + ret = FALSE; + } + + gst_caps_unref (profile_caps); + gst_caps_unref (allowed_caps); + } + gst_caps_unref (template_caps); + + base_encode->need_codec_data = encode->is_avc; + + return ret; + +fail: + { + gst_caps_unref (template_caps); + gst_caps_unref (allowed_caps); + return FALSE; + } +} + +static void +set_compatible_profile (GstVaapiEncodeH264 * encode, GstCaps * caps, + GstVaapiProfile profile, GstVaapiLevelH264 level) +{ + GstCaps *allowed_caps, *tmp_caps; + gboolean ret = FALSE; + + allowed_caps = + gst_pad_get_allowed_caps (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode)); + if (!allowed_caps || gst_caps_is_empty (allowed_caps)) { + if (allowed_caps) + gst_caps_unref (allowed_caps); + return; + } + + tmp_caps = gst_caps_from_string (GST_CODEC_CAPS); + + /* If profile doesn't exist in the allowed caps, let's find + * compatible profile in the caps. + * + * If there is one, we can set it as a compatible profile and make + * the negotiation. We consider baseline compatible with + * constrained-baseline, which is a strict subset of baseline + * profile. + */ +retry: + gst_caps_set_simple (tmp_caps, "profile", G_TYPE_STRING, + gst_vaapi_utils_h264_get_profile_string (profile), NULL); + + if (!gst_caps_can_intersect (allowed_caps, tmp_caps)) { + if (profile == GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE) { + profile = GST_VAAPI_PROFILE_H264_BASELINE; + GST_WARNING_OBJECT (GST_VAAPIENCODE_CAST (encode), "user might requested " + "baseline profile, trying constrained-baseline instead"); + goto retry; + } + } else { + gst_caps_set_simple (caps, "profile", G_TYPE_STRING, + gst_vaapi_utils_h264_get_profile_string (profile), + "level", G_TYPE_STRING, gst_vaapi_utils_h264_get_level_string (level), + NULL); + ret = TRUE; + } + + if (!ret) + GST_LOG ("There is no compatible profile in the requested caps."); + + gst_caps_unref (tmp_caps); + gst_caps_unref (allowed_caps); + return; +} + +static GstCaps * +gst_vaapiencode_h264_get_caps (GstVaapiEncode * base_encode) +{ + GstVaapiEncodeH264 *const encode = GST_VAAPIENCODE_H264_CAST (base_encode); + GstVaapiEncoderH264 *const encoder = + GST_VAAPI_ENCODER_H264 (base_encode->encoder); + GstVaapiProfile profile; + GstVaapiLevelH264 level; + GstCaps *caps; + + caps = gst_caps_from_string (GST_CODEC_CAPS); + + gst_caps_set_simple (caps, "stream-format", G_TYPE_STRING, + encode->is_avc ? "avc" : "byte-stream", NULL); + + /* Update profile determined by encoder */ + gst_vaapi_encoder_h264_get_profile_and_level (encoder, &profile, &level); + if (profile != GST_VAAPI_PROFILE_UNKNOWN) + set_compatible_profile (encode, caps, profile, level); + + GST_INFO_OBJECT (base_encode, "out caps %" GST_PTR_FORMAT, caps); + return caps; +} + +static GstVaapiEncoder * +gst_vaapiencode_h264_alloc_encoder (GstVaapiEncode * base, + GstVaapiDisplay * display) +{ + return gst_vaapi_encoder_h264_new (display); +} + +/* h264 NAL byte stream operations */ +static guint8 * +_h264_byte_stream_next_nal (guint8 * buffer, guint32 len, guint32 * nal_size) +{ + const guint8 *cur = buffer; + const guint8 *const end = buffer + len; + guint8 *nal_start = NULL; + guint32 flag = 0xFFFFFFFF; + guint32 nal_start_len = 0; + + g_assert (buffer && nal_size); + if (len < 3) { + *nal_size = len; + nal_start = (len ? buffer : NULL); + return nal_start; + } + + /*locate head postion */ + if (!buffer[0] && !buffer[1]) { + if (buffer[2] == 1) { /* 0x000001 */ + nal_start_len = 3; + } else if (!buffer[2] && len >= 4 && buffer[3] == 1) { /* 0x00000001 */ + nal_start_len = 4; + } + } + nal_start = buffer + nal_start_len; + cur = nal_start; + + /*find next nal start position */ + while (cur < end) { + flag = ((flag << 8) | ((*cur++) & 0xFF)); + if ((flag & 0x00FFFFFF) == 0x00000001) { + if (flag == 0x00000001) + *nal_size = cur - 4 - nal_start; + else + *nal_size = cur - 3 - nal_start; + break; + } + } + if (cur >= end) { + *nal_size = end - nal_start; + if (nal_start >= end) { + nal_start = NULL; + } + } + return nal_start; +} + +static inline void +_start_code_to_size (guint8 nal_start_code[4], guint32 nal_size) +{ + nal_start_code[0] = ((nal_size >> 24) & 0xFF); + nal_start_code[1] = ((nal_size >> 16) & 0xFF); + nal_start_code[2] = ((nal_size >> 8) & 0xFF); + nal_start_code[3] = (nal_size & 0xFF); +} + +static gboolean +_h264_convert_byte_stream_to_avc (GstBuffer * buf) +{ + GstMapInfo info; + guint32 nal_size; + guint8 *nal_start_code, *nal_body; + guint8 *frame_end; + + g_assert (buf); + + if (!gst_buffer_map (buf, &info, GST_MAP_READ | GST_MAP_WRITE)) + return FALSE; + + nal_start_code = info.data; + frame_end = info.data + info.size; + nal_size = 0; + + while ((frame_end > nal_start_code) && + (nal_body = _h264_byte_stream_next_nal (nal_start_code, + frame_end - nal_start_code, &nal_size)) != NULL) { + if (!nal_size) + goto error; + + g_assert (nal_body - nal_start_code == 4); + _start_code_to_size (nal_start_code, nal_size); + nal_start_code = nal_body + nal_size; + } + gst_buffer_unmap (buf, &info); + return TRUE; + + /* ERRORS */ +error: + { + gst_buffer_unmap (buf, &info); + return FALSE; + } +} + +static GstFlowReturn +gst_vaapiencode_h264_alloc_buffer (GstVaapiEncode * base_encode, + GstVaapiCodedBuffer * coded_buf, GstBuffer ** out_buffer_ptr) +{ + GstVaapiEncodeH264 *const encode = GST_VAAPIENCODE_H264_CAST (base_encode); + GstVaapiEncoderH264 *const encoder = + GST_VAAPI_ENCODER_H264 (base_encode->encoder); + GstFlowReturn ret; + + g_return_val_if_fail (encoder != NULL, GST_FLOW_ERROR); + + ret = + GST_VAAPIENCODE_CLASS (gst_vaapiencode_h264_parent_class)->alloc_buffer + (base_encode, coded_buf, out_buffer_ptr); + if (ret != GST_FLOW_OK) + return ret; + + if (!encode->is_avc) + return GST_FLOW_OK; + + /* Convert to avcC format */ + if (!_h264_convert_byte_stream_to_avc (*out_buffer_ptr)) + goto error_convert_buffer; + return GST_FLOW_OK; + + /* ERRORS */ +error_convert_buffer: + { + GST_ERROR ("failed to convert from bytestream format to avcC format"); + gst_buffer_replace (out_buffer_ptr, NULL); + return GST_FLOW_ERROR; + } +} + +static void +gst_vaapiencode_h264_class_init (GstVaapiEncodeH264Class * klass, gpointer data) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstElementClass *const element_class = GST_ELEMENT_CLASS (klass); + GstVaapiEncodeClass *const encode_class = GST_VAAPIENCODE_CLASS (klass); + GstCaps *sink_caps = ((GstVaapiEncodeInitData *) data)->sink_caps; + GstCaps *src_caps = ((GstVaapiEncodeInitData *) data)->src_caps; + GstPadTemplate *templ; + GstCaps *static_caps; + gpointer encoder_class; + + object_class->finalize = gst_vaapiencode_h264_finalize; + object_class->set_property = gst_vaapiencode_set_property_subclass; + object_class->get_property = gst_vaapiencode_get_property_subclass; + + encode_class->get_allowed_profiles = + gst_vaapiencode_h264_get_allowed_profiles; + encode_class->set_config = gst_vaapiencode_h264_set_config; + encode_class->get_caps = gst_vaapiencode_h264_get_caps; + encode_class->alloc_encoder = gst_vaapiencode_h264_alloc_encoder; + encode_class->alloc_buffer = gst_vaapiencode_h264_alloc_buffer; + + gst_element_class_set_static_metadata (element_class, + "VA-API H264 encoder", + "Codec/Encoder/Video/Hardware", + GST_PLUGIN_DESC, "Wind Yuan "); + + /* sink pad */ + g_assert (sink_caps); + static_caps = gst_caps_from_string (GST_VAAPI_ENCODE_STATIC_SINK_CAPS); + templ = + gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sink_caps); + gst_pad_template_set_documentation_caps (templ, static_caps); + gst_element_class_add_pad_template (element_class, templ); + gst_caps_unref (static_caps); + gst_caps_unref (sink_caps); + + /* src pad */ + g_assert (src_caps); + static_caps = gst_caps_from_string (GST_CODEC_CAPS); + templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps); + gst_pad_template_set_documentation_caps (templ, static_caps); + gst_element_class_add_pad_template (element_class, templ); + gst_caps_unref (static_caps); + gst_caps_unref (src_caps); + + encoder_class = g_type_class_ref (GST_TYPE_VAAPI_ENCODER_H264); + g_assert (encoder_class); + gst_vaapiencode_class_install_properties (encode_class, encoder_class); + g_type_class_unref (encoder_class); +} diff --git a/gst/vaapi/gstvaapiencode_h264.h b/gst/vaapi/gstvaapiencode_h264.h new file mode 100644 index 0000000000..f59797e22a --- /dev/null +++ b/gst/vaapi/gstvaapiencode_h264.h @@ -0,0 +1,76 @@ +/* + * gstvaapiencode_h264.h - VA-API H.264 encoder + * + * Copyright (C) 2012-2014 Intel Corporation + * Author: Wind Yuan + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPIENCODE_H264_H +#define GST_VAAPIENCODE_H264_H + +#include +#include "gstvaapiencode.h" + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPIENCODE_H264 \ + (gst_vaapiencode_h264_get_type ()) +#define GST_VAAPIENCODE_H264_CAST(obj) \ + ((GstVaapiEncodeH264 *)(obj)) +#define GST_VAAPIENCODE_H264(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPIENCODE_H264, \ + GstVaapiEncodeH264)) +#define GST_VAAPIENCODE_H264_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPIENCODE_H264, \ + GstVaapiEncodeH264Class)) +#define GST_VAAPIENCODE_H264_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPIENCODE_H264, \ + GstVaapiEncodeH264Class)) +#define GST_IS_VAAPIENCODE_H264(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPIENCODE_H264)) +#define GST_IS_VAAPIENCODE_H264_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPIENCODE_H264)) + +typedef struct _GstVaapiEncodeH264 GstVaapiEncodeH264; +typedef struct _GstVaapiEncodeH264Class GstVaapiEncodeH264Class; + +struct _GstVaapiEncodeH264 +{ + /*< private >*/ + GstVaapiEncode parent_instance; + + guint is_avc:1; /* [FALSE]=byte-stream (default); [TRUE]=avcC */ + GstCaps *available_caps; +}; + +struct _GstVaapiEncodeH264Class +{ + /*< private >*/ + GstVaapiEncodeClass parent_class; +}; + +GType +gst_vaapiencode_h264_get_type (void) G_GNUC_CONST; + +GType +gst_vaapiencode_h264_register_type (GstVaapiDisplay * display); + +G_END_DECLS + +#endif /* GST_VAAPIENCODE_H264_H */ diff --git a/gst/vaapi/gstvaapiencode_h265.c b/gst/vaapi/gstvaapiencode_h265.c new file mode 100644 index 0000000000..b0ed4138d3 --- /dev/null +++ b/gst/vaapi/gstvaapiencode_h265.c @@ -0,0 +1,404 @@ +/* + * gstvaapiencode_h265.c - VA-API H.265 encoder + * + * Copyright (C) 2015 Intel Corporation + * Author: Sreerenj Balachandran + * + * 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-vaapih265enc + * @short_description: A VA-API based HEVC video encoder + * + * Encodes raw video streams into HEVC bitstreams. + * + * ## Example launch line + * + * |[ + * gst-launch-1.0 -ev videotestsrc num-buffers=60 ! timeoverlay ! vaapih265enc ! h265parse ! matroskamux ! filesink location=test.mkv + * ]| + */ + +#include "gstcompat.h" +#include +#include +#include +#include "gstvaapiencode_h265.h" +#include "gstvaapipluginutil.h" +#include "gstvaapivideomemory.h" + +#define GST_PLUGIN_NAME "vaapih265enc" +#define GST_PLUGIN_DESC "A VA-API based H265 video encoder" + +GST_DEBUG_CATEGORY_STATIC (gst_vaapi_h265_encode_debug); +#define GST_CAT_DEFAULT gst_vaapi_h265_encode_debug + +#define GST_CODEC_CAPS \ + "video/x-h265, " \ + "stream-format = (string) { hvc1, byte-stream }, " \ + "alignment = (string) au" + +#define EXTRA_FORMATS {} + +/* h265 encode */ +GST_VAAPI_ENCODE_REGISTER_TYPE (h265, H265, H265, EXTRA_FORMATS, + gst_vaapi_utils_h265_get_profile_string); + +static void +gst_vaapiencode_h265_init (GstVaapiEncodeH265 * encode) +{ + /* nothing to do here */ +} + +static void +gst_vaapiencode_h265_finalize (GObject * object) +{ + G_OBJECT_CLASS (gst_vaapiencode_h265_parent_class)->finalize (object); +} + +static GArray * +gst_vaapiencode_h265_get_allowed_profiles (GstVaapiEncode * encode, + GstCaps * allowed) +{ + return gst_vaapi_encoder_get_profiles_from_caps (allowed, + gst_vaapi_utils_h265_get_profile_from_string); +} + +static gboolean +gst_vaapiencode_h265_set_config (GstVaapiEncode * base_encode) +{ + GstVaapiEncoderH265 *const encoder = + GST_VAAPI_ENCODER_H265 (base_encode->encoder); + GstCaps *allowed_caps = NULL; + GstCaps *template_caps = NULL; + GArray *profiles = NULL; + GArray *profiles_hw = NULL; + GArray *profiles_allowed = NULL; + GstVaapiProfile profile; + gboolean ret = TRUE; + guint i, j; + + profiles_hw = gst_vaapi_display_get_encode_profiles_by_codec + (GST_VAAPI_PLUGIN_BASE_DISPLAY (base_encode), GST_VAAPI_CODEC_H265); + if (!profiles_hw) { + ret = FALSE; + goto out; + } + + template_caps = + gst_pad_get_pad_template_caps (GST_VAAPI_PLUGIN_BASE_SRC_PAD + (base_encode)); + allowed_caps = + gst_pad_get_allowed_caps (GST_VAAPI_PLUGIN_BASE_SRC_PAD (base_encode)); + if (!allowed_caps || allowed_caps == template_caps) { + ret = gst_vaapi_encoder_h265_set_allowed_profiles (encoder, profiles_hw); + goto out; + } else if (gst_caps_is_empty (allowed_caps)) { + ret = FALSE; + goto out; + } + + profiles = gst_vaapi_encoder_get_profiles_from_caps (allowed_caps, + gst_vaapi_utils_h265_get_profile_from_string); + if (!profiles) { + ret = FALSE; + goto out; + } + + profiles_allowed = g_array_new (FALSE, FALSE, sizeof (GstVaapiProfile)); + if (!profiles_allowed) { + ret = FALSE; + goto out; + } + + for (i = 0; i < profiles->len; i++) { + profile = g_array_index (profiles, GstVaapiProfile, i); + for (j = 0; j < profiles_hw->len; j++) { + GstVaapiProfile p = g_array_index (profiles_hw, GstVaapiProfile, j); + if (p == profile) { + g_array_append_val (profiles_allowed, profile); + break; + } + } + } + if (profiles_allowed->len == 0) { + ret = FALSE; + goto out; + } + + ret = gst_vaapi_encoder_h265_set_allowed_profiles (encoder, profiles_allowed); + +out: + if (allowed_caps) + gst_caps_unref (allowed_caps); + if (template_caps) + gst_caps_unref (template_caps); + if (profiles) + g_array_unref (profiles); + if (profiles_hw) + g_array_unref (profiles_hw); + if (profiles_allowed) + g_array_unref (profiles_allowed); + + return ret; +} + +static GstCaps * +gst_vaapiencode_h265_get_caps (GstVaapiEncode * base_encode) +{ + GstVaapiEncodeH265 *const encode = GST_VAAPIENCODE_H265_CAST (base_encode); + GstVaapiEncoderH265 *const encoder = + GST_VAAPI_ENCODER_H265 (base_encode->encoder); + GstCaps *caps, *allowed_caps; + GstVaapiProfile profile = GST_VAAPI_PROFILE_UNKNOWN; + GstVaapiLevelH265 level = 0; + GstVaapiTierH265 tier = GST_VAAPI_TIER_H265_UNKNOWN; + + caps = gst_caps_from_string (GST_CODEC_CAPS); + + /* Check whether "stream-format" is hvcC mode */ + allowed_caps = + gst_pad_get_allowed_caps (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode)); + if (allowed_caps) { + const char *stream_format = NULL; + GstStructure *structure; + guint i, num_structures; + + num_structures = gst_caps_get_size (allowed_caps); + for (i = 0; !stream_format && i < num_structures; i++) { + structure = gst_caps_get_structure (allowed_caps, i); + if (!gst_structure_has_field_typed (structure, "stream-format", + G_TYPE_STRING)) + continue; + stream_format = gst_structure_get_string (structure, "stream-format"); + } + encode->is_hvc = stream_format && strcmp (stream_format, "hvc1") == 0; + gst_caps_unref (allowed_caps); + } + gst_caps_set_simple (caps, "stream-format", G_TYPE_STRING, + encode->is_hvc ? "hvc1" : "byte-stream", NULL); + + base_encode->need_codec_data = encode->is_hvc; + + gst_vaapi_encoder_h265_get_profile_tier_level (encoder, + &profile, &tier, &level); + if (profile != GST_VAAPI_PROFILE_UNKNOWN) { + gst_caps_set_simple (caps, "profile", G_TYPE_STRING, + gst_vaapi_utils_h265_get_profile_string (profile), NULL); + + if (level) { + gst_caps_set_simple (caps, "level", G_TYPE_STRING, + gst_vaapi_utils_h265_get_level_string (level), NULL); + + if (tier != GST_VAAPI_TIER_H265_UNKNOWN) + gst_caps_set_simple (caps, "tier", G_TYPE_STRING, + gst_vaapi_utils_h265_get_tier_string (tier), NULL); + } + } + + return caps; +} + +static GstVaapiEncoder * +gst_vaapiencode_h265_alloc_encoder (GstVaapiEncode * base, + GstVaapiDisplay * display) +{ + return gst_vaapi_encoder_h265_new (display); +} + +/* h265 NAL byte stream operations */ +static guint8 * +_h265_byte_stream_next_nal (guint8 * buffer, guint32 len, guint32 * nal_size) +{ + const guint8 *cur = buffer; + const guint8 *const end = buffer + len; + guint8 *nal_start = NULL; + guint32 flag = 0xFFFFFFFF; + guint32 nal_start_len = 0; + + g_assert (len != 0U && buffer && nal_size); + if (len < 3) { + *nal_size = len; + nal_start = (len ? buffer : NULL); + return nal_start; + } + + /*locate head postion */ + if (!buffer[0] && !buffer[1]) { + if (buffer[2] == 1) { /* 0x000001 */ + nal_start_len = 3; + } else if (!buffer[2] && len >= 4 && buffer[3] == 1) { /* 0x00000001 */ + nal_start_len = 4; + } + } + nal_start = buffer + nal_start_len; + cur = nal_start; + + /*find next nal start position */ + while (cur < end) { + flag = ((flag << 8) | ((*cur++) & 0xFF)); + if ((flag & 0x00FFFFFF) == 0x00000001) { + if (flag == 0x00000001) + *nal_size = cur - 4 - nal_start; + else + *nal_size = cur - 3 - nal_start; + break; + } + } + if (cur >= end) { + *nal_size = end - nal_start; + if (nal_start >= end) { + nal_start = NULL; + } + } + return nal_start; +} + +static inline void +_start_code_to_size (guint8 nal_start_code[4], guint32 nal_size) +{ + nal_start_code[0] = ((nal_size >> 24) & 0xFF); + nal_start_code[1] = ((nal_size >> 16) & 0xFF); + nal_start_code[2] = ((nal_size >> 8) & 0xFF); + nal_start_code[3] = (nal_size & 0xFF); +} + +static gboolean +_h265_convert_byte_stream_to_hvc (GstBuffer * buf) +{ + GstMapInfo info; + guint32 nal_size; + guint8 *nal_start_code, *nal_body; + guint8 *frame_end; + + g_assert (buf); + + if (!gst_buffer_map (buf, &info, GST_MAP_READ | GST_MAP_WRITE)) + return FALSE; + + nal_start_code = info.data; + frame_end = info.data + info.size; + nal_size = 0; + + while ((frame_end > nal_start_code) && + (nal_body = _h265_byte_stream_next_nal (nal_start_code, + frame_end - nal_start_code, &nal_size)) != NULL) { + if (!nal_size) + goto error; + + g_assert (nal_body - nal_start_code == 4); + _start_code_to_size (nal_start_code, nal_size); + nal_start_code = nal_body + nal_size; + } + gst_buffer_unmap (buf, &info); + return TRUE; + + /* ERRORS */ +error: + { + gst_buffer_unmap (buf, &info); + return FALSE; + } +} + +static GstFlowReturn +gst_vaapiencode_h265_alloc_buffer (GstVaapiEncode * base_encode, + GstVaapiCodedBuffer * coded_buf, GstBuffer ** out_buffer_ptr) +{ + GstVaapiEncodeH265 *const encode = GST_VAAPIENCODE_H265_CAST (base_encode); + GstVaapiEncoderH265 *const encoder = + GST_VAAPI_ENCODER_H265 (base_encode->encoder); + GstFlowReturn ret; + + g_return_val_if_fail (encoder != NULL, GST_FLOW_ERROR); + + ret = + GST_VAAPIENCODE_CLASS (gst_vaapiencode_h265_parent_class)->alloc_buffer + (base_encode, coded_buf, out_buffer_ptr); + if (ret != GST_FLOW_OK) + return ret; + + if (!encode->is_hvc) + return GST_FLOW_OK; + + /* Convert to hvcC format */ + if (!_h265_convert_byte_stream_to_hvc (*out_buffer_ptr)) + goto error_convert_buffer; + return GST_FLOW_OK; + + /* ERRORS */ +error_convert_buffer: + { + GST_ERROR ("failed to convert from bytestream format to hvcC format"); + gst_buffer_replace (out_buffer_ptr, NULL); + return GST_FLOW_ERROR; + } +} + +static void +gst_vaapiencode_h265_class_init (GstVaapiEncodeH265Class * klass, gpointer data) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstElementClass *const element_class = GST_ELEMENT_CLASS (klass); + GstVaapiEncodeClass *const encode_class = GST_VAAPIENCODE_CLASS (klass); + GstCaps *sink_caps = ((GstVaapiEncodeInitData *) data)->sink_caps; + GstCaps *src_caps = ((GstVaapiEncodeInitData *) data)->src_caps; + GstPadTemplate *templ; + GstCaps *static_caps; + gpointer encoder_class; + + object_class->finalize = gst_vaapiencode_h265_finalize; + object_class->set_property = gst_vaapiencode_set_property_subclass; + object_class->get_property = gst_vaapiencode_get_property_subclass; + + encode_class->get_allowed_profiles = + gst_vaapiencode_h265_get_allowed_profiles; + encode_class->set_config = gst_vaapiencode_h265_set_config; + encode_class->get_caps = gst_vaapiencode_h265_get_caps; + encode_class->alloc_encoder = gst_vaapiencode_h265_alloc_encoder; + encode_class->alloc_buffer = gst_vaapiencode_h265_alloc_buffer; + + gst_element_class_set_static_metadata (element_class, + "VA-API H265 encoder", + "Codec/Encoder/Video/Hardware", + GST_PLUGIN_DESC, + "Sreerenj Balachandran "); + + /* sink pad */ + g_assert (sink_caps); + static_caps = gst_caps_from_string (GST_VAAPI_ENCODE_STATIC_SINK_CAPS); + templ = + gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sink_caps); + gst_pad_template_set_documentation_caps (templ, static_caps); + gst_element_class_add_pad_template (element_class, templ); + gst_caps_unref (static_caps); + gst_caps_unref (sink_caps); + + /* src pad */ + g_assert (src_caps); + static_caps = gst_caps_from_string (GST_CODEC_CAPS); + templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps); + gst_pad_template_set_documentation_caps (templ, static_caps); + gst_element_class_add_pad_template (element_class, templ); + gst_caps_unref (static_caps); + gst_caps_unref (src_caps); + + encoder_class = g_type_class_ref (GST_TYPE_VAAPI_ENCODER_H265); + g_assert (encoder_class); + gst_vaapiencode_class_install_properties (encode_class, encoder_class); + g_type_class_unref (encoder_class); +} diff --git a/gst/vaapi/gstvaapiencode_h265.h b/gst/vaapi/gstvaapiencode_h265.h new file mode 100644 index 0000000000..4371dcfe1a --- /dev/null +++ b/gst/vaapi/gstvaapiencode_h265.h @@ -0,0 +1,73 @@ +/* + * gstvaapiencode_h265.h - VA-API H.265 encoder + * + * Copyright (C) 2015 Intel Corporation + * Author: Sreerenj Balachandran + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPIENCODE_H265_H +#define GST_VAAPIENCODE_H265_H + +#include +#include "gstvaapiencode.h" + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPIENCODE_H265 \ + (gst_vaapiencode_h265_get_type ()) +#define GST_VAAPIENCODE_H265_CAST(obj) \ + ((GstVaapiEncodeH265 *)(obj)) +#define GST_VAAPIENCODE_H265(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPIENCODE_H265, \ + GstVaapiEncodeH265)) +#define GST_VAAPIENCODE_H265_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPIENCODE_H265, \ + GstVaapiEncodeH265Class)) +#define GST_VAAPIENCODE_H265_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPIENCODE_H265, \ + GstVaapiEncodeH265Class)) +#define GST_IS_VAAPIENCODE_H265(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPIENCODE_H265)) +#define GST_IS_VAAPIENCODE_H265_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPIENCODE_H265)) + +typedef struct _GstVaapiEncodeH265 GstVaapiEncodeH265; +typedef struct _GstVaapiEncodeH265Class GstVaapiEncodeH265Class; + +struct _GstVaapiEncodeH265 +{ + /*< private >*/ + GstVaapiEncode parent_instance; + + guint is_hvc:1; /* [FALSE]=byte-stream (default); [TRUE]=hvcC */ +}; + +struct _GstVaapiEncodeH265Class +{ + /*< private >*/ + GstVaapiEncodeClass parent_class; +}; + +GType +gst_vaapiencode_h265_get_type (void) G_GNUC_CONST; +GType +gst_vaapiencode_h265_register_type (GstVaapiDisplay * display); + +G_END_DECLS + +#endif /* GST_VAAPIENCODE_H265_H */ diff --git a/gst/vaapi/gstvaapiencode_jpeg.c b/gst/vaapi/gstvaapiencode_jpeg.c new file mode 100644 index 0000000000..667a18421b --- /dev/null +++ b/gst/vaapi/gstvaapiencode_jpeg.c @@ -0,0 +1,134 @@ +/* + * gstvaapiencode_jpeg.c - VA-API JPEG encoder + * + * Copyright (C) 2015 Intel Corporation + * Author: Sreerenj Balachandran + * + * 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-vaapijpegenc + * @short_description: A VA-API based JPEG image encoder + * + * Encodes raw images into JPEG images. + * + * ## Example launch line + * + * |[ + * gst-launch-1.0 -ev videotestsrc num-buffers=1 ! timeoverlay ! vaapijpegenc ! filesink location=test.jpg + * ]| + */ + +#include "gstcompat.h" +#include +#include +#include "gstvaapiencode_jpeg.h" +#include "gstvaapipluginutil.h" +#include "gstvaapivideomemory.h" + +#define GST_PLUGIN_NAME "vaapijpegenc" +#define GST_PLUGIN_DESC "A VA-API based JPEG video encoder" + +GST_DEBUG_CATEGORY_STATIC (gst_vaapi_jpeg_encode_debug); +#define GST_CAT_DEFAULT gst_vaapi_jpeg_encode_debug + +#define GST_CODEC_CAPS \ + "image/jpeg" + +#define EXTRA_FORMATS { GST_VIDEO_FORMAT_BGRA, } + +/* jpeg encode */ +GST_VAAPI_ENCODE_REGISTER_TYPE (jpeg, JPEG, Jpeg, EXTRA_FORMATS, NULL); + +static void +gst_vaapiencode_jpeg_init (GstVaapiEncodeJpeg * encode) +{ + /* nothing to do here */ +} + +static void +gst_vaapiencode_jpeg_finalize (GObject * object) +{ + G_OBJECT_CLASS (gst_vaapiencode_jpeg_parent_class)->finalize (object); +} + +static GstCaps * +gst_vaapiencode_jpeg_get_caps (GstVaapiEncode * base_encode) +{ + GstCaps *caps; + + caps = gst_caps_from_string (GST_CODEC_CAPS); + + return caps; +} + +static GstVaapiEncoder * +gst_vaapiencode_jpeg_alloc_encoder (GstVaapiEncode * base, + GstVaapiDisplay * display) +{ + return gst_vaapi_encoder_jpeg_new (display); +} + +static void +gst_vaapiencode_jpeg_class_init (GstVaapiEncodeJpegClass * klass, gpointer data) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstElementClass *const element_class = GST_ELEMENT_CLASS (klass); + GstVaapiEncodeClass *const encode_class = GST_VAAPIENCODE_CLASS (klass); + GstCaps *sink_caps = ((GstVaapiEncodeInitData *) data)->sink_caps; + GstCaps *src_caps = ((GstVaapiEncodeInitData *) data)->src_caps; + GstPadTemplate *templ; + GstCaps *static_caps; + gpointer encoder_class; + + object_class->finalize = gst_vaapiencode_jpeg_finalize; + object_class->set_property = gst_vaapiencode_set_property_subclass; + object_class->get_property = gst_vaapiencode_get_property_subclass; + + encode_class->get_caps = gst_vaapiencode_jpeg_get_caps; + encode_class->alloc_encoder = gst_vaapiencode_jpeg_alloc_encoder; + + gst_element_class_set_static_metadata (element_class, + "VA-API JPEG encoder", + "Codec/Encoder/Image/Hardware", + GST_PLUGIN_DESC, + "Sreerenj Balachandran "); + + /* sink pad */ + g_assert (sink_caps); + static_caps = gst_caps_from_string (GST_VAAPI_ENCODE_STATIC_SINK_CAPS); + templ = + gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sink_caps); + gst_pad_template_set_documentation_caps (templ, static_caps); + gst_element_class_add_pad_template (element_class, templ); + gst_caps_unref (static_caps); + gst_caps_unref (sink_caps); + + /* src pad */ + g_assert (src_caps); + static_caps = gst_caps_from_string (GST_CODEC_CAPS); + templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps); + gst_pad_template_set_documentation_caps (templ, static_caps); + gst_element_class_add_pad_template (element_class, templ); + gst_caps_unref (static_caps); + gst_caps_unref (src_caps); + + encoder_class = g_type_class_ref (GST_TYPE_VAAPI_ENCODER_JPEG); + g_assert (encoder_class); + gst_vaapiencode_class_install_properties (encode_class, encoder_class); + g_type_class_unref (encoder_class); +} diff --git a/gst/vaapi/gstvaapiencode_jpeg.h b/gst/vaapi/gstvaapiencode_jpeg.h new file mode 100644 index 0000000000..f0bab68bfc --- /dev/null +++ b/gst/vaapi/gstvaapiencode_jpeg.h @@ -0,0 +1,72 @@ +/* + * gstvaapiencode_jpeg.h - VA-API JPEG encoder + * + * Copyright (C) 2015 Intel Corporation + * Author: Sreerenj Balachandran + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPIENCODE_JPEG_H +#define GST_VAAPIENCODE_JPEG_H + +#include +#include "gstvaapiencode.h" + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPIENCODE_JPEG \ + (gst_vaapiencode_jpeg_get_type ()) +#define GST_VAAPIENCODE_JPEG_CAST(obj) \ + ((GstVaapiEncodeJpeg *)(obj)) +#define GST_VAAPIENCODE_JPEG(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPIENCODE_JPEG, \ + GstVaapiEncodeJpeg)) +#define GST_VAAPIENCODE_JPEG_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPIENCODE_JPEG, \ + GstVaapiEncodeJpegClass)) +#define GST_VAAPIENCODE_JPEG_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPIENCODE_JPEG, \ + GstVaapiEncodeJpegClass)) +#define GST_IS_VAAPIENCODE_JPEG(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPIENCODE_JPEG)) +#define GST_IS_VAAPIENCODE_JPEG_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPIENCODE_JPEG)) + +typedef struct _GstVaapiEncodeJpeg GstVaapiEncodeJpeg; +typedef struct _GstVaapiEncodeJpegClass GstVaapiEncodeJpegClass; + +struct _GstVaapiEncodeJpeg +{ + /*< private >*/ + GstVaapiEncode parent_instance; +}; + +struct _GstVaapiEncodeJpegClass +{ + /*< private >*/ + GstVaapiEncodeClass parent_class; +}; + +GType +gst_vaapiencode_jpeg_get_type (void) G_GNUC_CONST; + +GType +gst_vaapiencode_jpeg_register_type (GstVaapiDisplay * display); + +G_END_DECLS + +#endif /* GST_VAAPIENCODE_JPEG_H */ diff --git a/gst/vaapi/gstvaapiencode_mpeg2.c b/gst/vaapi/gstvaapiencode_mpeg2.c new file mode 100644 index 0000000000..0701a102a5 --- /dev/null +++ b/gst/vaapi/gstvaapiencode_mpeg2.c @@ -0,0 +1,139 @@ +/* + * gstvaapiencode_mpeg2.c - VA-API MPEG2 encoder + * + * Copyright (C) 2012-2014 Intel Corporation + * Author: Guangxin Xu + * Author: Gwenole Beauchesne + * + * 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-vaapimpeg2enc + * @short_description: A VA-API based MPEG2 video encoder + * + * Encodes raw video streams into MPEG2 bitstreams. + * + * ## Example launch line + * + * |[ + * gst-launch-1.0 -ev videotestsrc num-buffers=60 ! timeoverlay ! vaapimpeg2enc ! matroskamux ! filesink location=test.mkv + * ]| + */ + +#include "gstcompat.h" +#include +#include +#include +#include "gstvaapiencode_mpeg2.h" +#include "gstvaapipluginutil.h" +#include "gstvaapivideomemory.h" + +#define GST_PLUGIN_NAME "vaapimpeg2enc" +#define GST_PLUGIN_DESC "A VA-API based MPEG-2 video encoder" + +GST_DEBUG_CATEGORY_STATIC (gst_vaapi_mpeg2_encode_debug); +#define GST_CAT_DEFAULT gst_vaapi_mpeg2_encode_debug + +#define GST_CODEC_CAPS \ + "video/mpeg, mpegversion = (int) 2, " \ + "systemstream = (boolean) false" + +#define EXTRA_FORMATS {} + +/* mpeg2 encode */ +GST_VAAPI_ENCODE_REGISTER_TYPE (mpeg2, MPEG2, Mpeg2, EXTRA_FORMATS, + gst_vaapi_utils_mpeg2_get_profile_string); + +static void +gst_vaapiencode_mpeg2_init (GstVaapiEncodeMpeg2 * encode) +{ + /* nothing to do here */ +} + +static void +gst_vaapiencode_mpeg2_finalize (GObject * object) +{ + G_OBJECT_CLASS (gst_vaapiencode_mpeg2_parent_class)->finalize (object); +} + +static GstCaps * +gst_vaapiencode_mpeg2_get_caps (GstVaapiEncode * base_encode) +{ + GstCaps *caps; + + caps = gst_caps_from_string (GST_CODEC_CAPS); + + /* XXX: update profile and level information */ + return caps; +} + +static GstVaapiEncoder * +gst_vaapiencode_mpeg2_alloc_encoder (GstVaapiEncode * base, + GstVaapiDisplay * display) +{ + return gst_vaapi_encoder_mpeg2_new (display); +} + +static void +gst_vaapiencode_mpeg2_class_init (GstVaapiEncodeMpeg2Class * klass, + gpointer data) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstElementClass *const element_class = GST_ELEMENT_CLASS (klass); + GstVaapiEncodeClass *const encode_class = GST_VAAPIENCODE_CLASS (klass); + GstCaps *sink_caps = ((GstVaapiEncodeInitData *) data)->sink_caps; + GstCaps *src_caps = ((GstVaapiEncodeInitData *) data)->src_caps; + GstPadTemplate *templ; + GstCaps *static_caps; + gpointer encoder_class; + + object_class->finalize = gst_vaapiencode_mpeg2_finalize; + object_class->set_property = gst_vaapiencode_set_property_subclass; + object_class->get_property = gst_vaapiencode_get_property_subclass; + + encode_class->get_caps = gst_vaapiencode_mpeg2_get_caps; + encode_class->alloc_encoder = gst_vaapiencode_mpeg2_alloc_encoder; + + gst_element_class_set_static_metadata (element_class, + "VA-API MPEG-2 encoder", + "Codec/Encoder/Video/Hardware", + GST_PLUGIN_DESC, "Guangxin Xu "); + + /* sink pad */ + g_assert (sink_caps); + static_caps = gst_caps_from_string (GST_VAAPI_ENCODE_STATIC_SINK_CAPS); + templ = + gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sink_caps); + gst_pad_template_set_documentation_caps (templ, static_caps); + gst_element_class_add_pad_template (element_class, templ); + gst_caps_unref (static_caps); + gst_caps_unref (sink_caps); + + /* src pad */ + g_assert (src_caps); + static_caps = gst_caps_from_string (GST_CODEC_CAPS); + templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps); + gst_pad_template_set_documentation_caps (templ, static_caps); + gst_element_class_add_pad_template (element_class, templ); + gst_caps_unref (static_caps); + gst_caps_unref (src_caps); + + encoder_class = g_type_class_ref (GST_TYPE_VAAPI_ENCODER_MPEG2); + g_assert (encoder_class); + gst_vaapiencode_class_install_properties (encode_class, encoder_class); + g_type_class_unref (encoder_class); +} diff --git a/gst/vaapi/gstvaapiencode_mpeg2.h b/gst/vaapi/gstvaapiencode_mpeg2.h new file mode 100644 index 0000000000..a8c765914a --- /dev/null +++ b/gst/vaapi/gstvaapiencode_mpeg2.h @@ -0,0 +1,77 @@ +/* + * gstvaapiencode_mpeg2.h - VA-API MPEG2 encoder + * + * Copyright (C) 2012-2014 Intel Corporation + * Author: Guangxin Xu + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPIENCODE_MPEG2_H +#define GST_VAAPIENCODE_MPEG2_H + +#include +#include "gstvaapiencode.h" + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPIENCODE_MPEG2 \ + (gst_vaapiencode_mpeg2_get_type ()) +#define GST_VAAPIENCODE_MPEG2_CAST(obj) \ + ((GstVaapiEncodeMpeg2 *)(obj)) +#define GST_VAAPIENCODE_MPEG2(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPIENCODE_MPEG2, \ + GstVaapiEncodeMpeg2)) +#define GST_VAAPIENCODE_MPEG2_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPIENCODE_MPEG2, \ + GstVaapiEncodeMpeg2Class)) +#define GST_VAAPIENCODE_MPEG2_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPIENCODE_MPEG2, \ + GstVaapiEncodeMpeg2Class)) +#define GST_IS_VAAPIENCODE_MPEG2(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPIENCODE_MPEG2)) +#define GST_IS_VAAPIENCODE_MPEG2_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPIENCODE_MPEG2)) + +typedef struct _GstVaapiEncodeMpeg2 GstVaapiEncodeMpeg2; +typedef struct _GstVaapiEncodeMpeg2Class GstVaapiEncodeMpeg2Class; + +struct _GstVaapiEncodeMpeg2 +{ + /*< private >*/ + GstVaapiEncode parent_instance; + + guint32 quantizer; + guint32 intra_period; + guint32 ip_period; +}; + +struct _GstVaapiEncodeMpeg2Class +{ + /*< private >*/ + GstVaapiEncodeClass parent_class; +}; + +GType +gst_vaapiencode_mpeg2_get_type (void) G_GNUC_CONST; + +GType +gst_vaapiencode_mpeg2_register_type (GstVaapiDisplay * display); + +G_END_DECLS + +#endif /* GST_VAAPIENCODE_MPEG2_H */ diff --git a/gst/vaapi/gstvaapiencode_vp8.c b/gst/vaapi/gstvaapiencode_vp8.c new file mode 100644 index 0000000000..a8f0d34134 --- /dev/null +++ b/gst/vaapi/gstvaapiencode_vp8.c @@ -0,0 +1,134 @@ +/* + * gstvaapiencode_vp8.c - VA-API VP8 encoder + * + * Copyright (C) 2015 Intel Corporation + * Author: Sreerenj Balachandran + * + * 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-vaapivp8enc + * @short_description: A VA-API based VP8 video encoder + * + * Encodes raw video streams into VP8 bitstreams. + * + * ## Example launch line + * + * |[ + * gst-launch-1.0 -ev videotestsrc num-buffers=60 ! timeoverlay ! vaapivp8enc ! matroskamux ! filesink location=test.mkv + * ]| + */ + +#include "gstcompat.h" +#include +#include +#include "gstvaapiencode_vp8.h" +#include "gstvaapipluginutil.h" +#include "gstvaapivideomemory.h" + +#define GST_PLUGIN_NAME "vaapivp8enc" +#define GST_PLUGIN_DESC "A VA-API based VP8 video encoder" + +GST_DEBUG_CATEGORY_STATIC (gst_vaapi_vp8_encode_debug); +#define GST_CAT_DEFAULT gst_vaapi_vp8_encode_debug + +#define GST_CODEC_CAPS \ + "video/x-vp8" + +#define EXTRA_FORMATS {} + +/* vp8 encode */ +GST_VAAPI_ENCODE_REGISTER_TYPE (vp8, VP8, VP8, EXTRA_FORMATS, NULL); + +static void +gst_vaapiencode_vp8_init (GstVaapiEncodeVP8 * encode) +{ + /* nothing to do here */ +} + +static void +gst_vaapiencode_vp8_finalize (GObject * object) +{ + G_OBJECT_CLASS (gst_vaapiencode_vp8_parent_class)->finalize (object); +} + +static GstCaps * +gst_vaapiencode_vp8_get_caps (GstVaapiEncode * base_encode) +{ + GstCaps *caps; + + caps = gst_caps_from_string (GST_CODEC_CAPS); + + return caps; +} + +static GstVaapiEncoder * +gst_vaapiencode_vp8_alloc_encoder (GstVaapiEncode * base, + GstVaapiDisplay * display) +{ + return gst_vaapi_encoder_vp8_new (display); +} + +static void +gst_vaapiencode_vp8_class_init (GstVaapiEncodeVP8Class * klass, gpointer data) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstElementClass *const element_class = GST_ELEMENT_CLASS (klass); + GstVaapiEncodeClass *const encode_class = GST_VAAPIENCODE_CLASS (klass); + GstCaps *sink_caps = ((GstVaapiEncodeInitData *) data)->sink_caps; + GstCaps *src_caps = ((GstVaapiEncodeInitData *) data)->src_caps; + GstPadTemplate *templ; + GstCaps *static_caps; + gpointer encoder_class; + + object_class->finalize = gst_vaapiencode_vp8_finalize; + object_class->set_property = gst_vaapiencode_set_property_subclass; + object_class->get_property = gst_vaapiencode_get_property_subclass; + + encode_class->get_caps = gst_vaapiencode_vp8_get_caps; + encode_class->alloc_encoder = gst_vaapiencode_vp8_alloc_encoder; + + gst_element_class_set_static_metadata (element_class, + "VA-API VP8 encoder", + "Codec/Encoder/Video/Hardware", + GST_PLUGIN_DESC, + "Sreerenj Balachandran "); + + /* sink pad */ + g_assert (sink_caps); + static_caps = gst_caps_from_string (GST_VAAPI_ENCODE_STATIC_SINK_CAPS); + templ = + gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sink_caps); + gst_pad_template_set_documentation_caps (templ, static_caps); + gst_element_class_add_pad_template (element_class, templ); + gst_caps_unref (static_caps); + gst_caps_unref (sink_caps); + + /* src pad */ + g_assert (src_caps); + static_caps = gst_caps_from_string (GST_CODEC_CAPS); + templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps); + gst_pad_template_set_documentation_caps (templ, static_caps); + gst_element_class_add_pad_template (element_class, templ); + gst_caps_unref (static_caps); + gst_caps_unref (src_caps); + + encoder_class = g_type_class_ref (GST_TYPE_VAAPI_ENCODER_VP8); + g_assert (encoder_class); + gst_vaapiencode_class_install_properties (encode_class, encoder_class); + g_type_class_unref (encoder_class); +} diff --git a/gst/vaapi/gstvaapiencode_vp8.h b/gst/vaapi/gstvaapiencode_vp8.h new file mode 100644 index 0000000000..1523a9dd75 --- /dev/null +++ b/gst/vaapi/gstvaapiencode_vp8.h @@ -0,0 +1,72 @@ +/* + * gstvaapiencode_vp8.h - VA-API VP8 encoder + * + * Copyright (C) 2015 Intel Corporation + * Author: Sreerenj Balachandran + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPIENCODE_VP8_H +#define GST_VAAPIENCODE_VP8_H + +#include +#include "gstvaapiencode.h" + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPIENCODE_VP8 \ + (gst_vaapiencode_vp8_get_type ()) +#define GST_VAAPIENCODE_VP8_CAST(obj) \ + ((GstVaapiEncodeVP8 *)(obj)) +#define GST_VAAPIENCODE_VP8(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPIENCODE_VP8, \ + GstVaapiEncodeVP8)) +#define GST_VAAPIENCODE_VP8_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPIENCODE_VP8, \ + GstVaapiEncodeVP8Class)) +#define GST_VAAPIENCODE_VP8_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPIENCODE_VP8, \ + GstVaapiEncodeVP8Class)) +#define GST_IS_VAAPIENCODE_VP8(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPIENCODE_VP8)) +#define GST_IS_VAAPIENCODE_VP8_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPIENCODE_VP8)) + +typedef struct _GstVaapiEncodeVP8 GstVaapiEncodeVP8; +typedef struct _GstVaapiEncodeVP8Class GstVaapiEncodeVP8Class; + +struct _GstVaapiEncodeVP8 +{ + /*< private >*/ + GstVaapiEncode parent_instance; +}; + +struct _GstVaapiEncodeVP8Class +{ + /*< private >*/ + GstVaapiEncodeClass parent_class; +}; + +GType +gst_vaapiencode_vp8_get_type (void) G_GNUC_CONST; + +GType +gst_vaapiencode_vp8_register_type (GstVaapiDisplay * display); + +G_END_DECLS + +#endif /* GST_VAAPIENCODE_VP8_H */ diff --git a/gst/vaapi/gstvaapiencode_vp9.c b/gst/vaapi/gstvaapiencode_vp9.c new file mode 100644 index 0000000000..a7cf7c278c --- /dev/null +++ b/gst/vaapi/gstvaapiencode_vp9.c @@ -0,0 +1,231 @@ +/* + * gstvaapiencode_vp9.c - VA-API VP9 encoder + * + * Copyright (C) 2016 Intel Corporation + * Author: Sreerenj Balachandran + * + * 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-vaapivp9enc + * @short_description: A VA-API based VP9 video encoder + * + * Encodes raw video streams into VP9 bitstreams. + * + * ## Example launch line + * + * |[ + * gst-launch-1.0 -ev videotestsrc num-buffers=60 ! timeoverlay ! vaapivp9enc ! matroskamux ! filesink location=test.mkv + * ]| + */ + +#include "gstcompat.h" +#include +#include +#include +#include "gstvaapiencode_vp9.h" +#include "gstvaapipluginutil.h" +#include "gstvaapivideomemory.h" + +#define GST_PLUGIN_NAME "vaapivp9enc" +#define GST_PLUGIN_DESC "A VA-API based VP9 video encoder" + +GST_DEBUG_CATEGORY_STATIC (gst_vaapi_vp9_encode_debug); +#define GST_CAT_DEFAULT gst_vaapi_vp9_encode_debug + +#define GST_CODEC_CAPS \ + "video/x-vp9" + +#define EXTRA_FORMATS {} + +/* vp9 encode */ +GST_VAAPI_ENCODE_REGISTER_TYPE (vp9, VP9, VP9, EXTRA_FORMATS, + gst_vaapi_utils_vp9_get_profile_string); + +static void +gst_vaapiencode_vp9_init (GstVaapiEncodeVP9 * encode) +{ + /* nothing to do here */ +} + +static void +gst_vaapiencode_vp9_finalize (GObject * object) +{ + G_OBJECT_CLASS (gst_vaapiencode_vp9_parent_class)->finalize (object); +} + +static GArray * +gst_vaapiencode_vp9_get_allowed_profiles (GstVaapiEncode * encode, + GstCaps * allowed) +{ + return gst_vaapi_encoder_get_profiles_from_caps (allowed, + gst_vaapi_utils_vp9_get_profile_from_string); +} + +static GstCaps * +gst_vaapiencode_vp9_get_caps (GstVaapiEncode * base_encode) +{ + GstCaps *caps; + GstVaapiProfile profile; + const gchar *profile_str; + + caps = gst_caps_from_string (GST_CODEC_CAPS); + profile = gst_vaapi_encoder_get_profile (base_encode->encoder); + profile_str = gst_vaapi_utils_vp9_get_profile_string (profile); + if (profile_str) + gst_caps_set_simple (caps, "profile", G_TYPE_STRING, profile_str, NULL); + + return caps; +} + +static GstVaapiEncoder * +gst_vaapiencode_vp9_alloc_encoder (GstVaapiEncode * base, + GstVaapiDisplay * display) +{ + return gst_vaapi_encoder_vp9_new (display); +} + +static gboolean +gst_vaapiencode_vp9_set_config (GstVaapiEncode * base_encode) +{ + GstVaapiEncoderVP9 *const encoder = + GST_VAAPI_ENCODER_VP9 (base_encode->encoder); + GstCaps *allowed_caps = NULL; + GstCaps *template_caps = NULL; + GArray *profiles = NULL; + GArray *profiles_hw = NULL; + GArray *profiles_allowed = NULL; + GstVaapiProfile profile; + gboolean ret = TRUE; + guint i, j; + + profiles_hw = gst_vaapi_display_get_encode_profiles_by_codec + (GST_VAAPI_PLUGIN_BASE_DISPLAY (base_encode), GST_VAAPI_CODEC_VP9); + if (!profiles_hw) { + ret = FALSE; + goto out; + } + + template_caps = + gst_pad_get_pad_template_caps (GST_VAAPI_PLUGIN_BASE_SRC_PAD + (base_encode)); + allowed_caps = + gst_pad_get_allowed_caps (GST_VAAPI_PLUGIN_BASE_SRC_PAD (base_encode)); + if (!allowed_caps || allowed_caps == template_caps) { + ret = gst_vaapi_encoder_vp9_set_allowed_profiles (encoder, profiles_hw); + goto out; + } else if (gst_caps_is_empty (allowed_caps)) { + ret = FALSE; + goto out; + } + + profiles = gst_vaapi_encoder_get_profiles_from_caps (allowed_caps, + gst_vaapi_utils_vp9_get_profile_from_string); + if (!profiles) { + ret = FALSE; + goto out; + } + + profiles_allowed = g_array_new (FALSE, FALSE, sizeof (GstVaapiProfile)); + if (!profiles_allowed) { + ret = FALSE; + goto out; + } + + for (i = 0; i < profiles->len; i++) { + profile = g_array_index (profiles, GstVaapiProfile, i); + for (j = 0; j < profiles_hw->len; j++) { + GstVaapiProfile p = g_array_index (profiles_hw, GstVaapiProfile, j); + if (p == profile) { + g_array_append_val (profiles_allowed, profile); + break; + } + } + } + if (profiles_allowed->len == 0) { + ret = FALSE; + goto out; + } + + ret = gst_vaapi_encoder_vp9_set_allowed_profiles (encoder, profiles_allowed); + +out: + if (allowed_caps) + gst_caps_unref (allowed_caps); + if (template_caps) + gst_caps_unref (template_caps); + if (profiles) + g_array_unref (profiles); + if (profiles_hw) + g_array_unref (profiles_hw); + if (profiles_allowed) + g_array_unref (profiles_allowed); + + return ret; +} + +static void +gst_vaapiencode_vp9_class_init (GstVaapiEncodeVP9Class * klass, gpointer data) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstElementClass *const element_class = GST_ELEMENT_CLASS (klass); + GstVaapiEncodeClass *const encode_class = GST_VAAPIENCODE_CLASS (klass); + GstCaps *sink_caps = ((GstVaapiEncodeInitData *) data)->sink_caps; + GstCaps *src_caps = ((GstVaapiEncodeInitData *) data)->src_caps; + GstPadTemplate *templ; + GstCaps *static_caps; + gpointer encoder_class; + + object_class->finalize = gst_vaapiencode_vp9_finalize; + object_class->set_property = gst_vaapiencode_set_property_subclass; + object_class->get_property = gst_vaapiencode_get_property_subclass; + + encode_class->get_allowed_profiles = gst_vaapiencode_vp9_get_allowed_profiles; + encode_class->get_caps = gst_vaapiencode_vp9_get_caps; + encode_class->alloc_encoder = gst_vaapiencode_vp9_alloc_encoder; + encode_class->set_config = gst_vaapiencode_vp9_set_config; + + gst_element_class_set_static_metadata (element_class, + "VA-API VP9 encoder", + "Codec/Encoder/Video/Hardware", + GST_PLUGIN_DESC, + "Sreerenj Balachandran "); + + /* sink pad */ + g_assert (sink_caps); + static_caps = gst_caps_from_string (GST_VAAPI_ENCODE_STATIC_SINK_CAPS); + templ = + gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sink_caps); + gst_pad_template_set_documentation_caps (templ, static_caps); + gst_element_class_add_pad_template (element_class, templ); + gst_caps_unref (static_caps); + gst_caps_unref (sink_caps); + + /* src pad */ + g_assert (src_caps); + static_caps = gst_caps_from_string (GST_CODEC_CAPS); + templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps); + gst_pad_template_set_documentation_caps (templ, static_caps); + gst_element_class_add_pad_template (element_class, templ); + gst_caps_unref (static_caps); + gst_caps_unref (src_caps); + + encoder_class = g_type_class_ref (GST_TYPE_VAAPI_ENCODER_VP9); + g_assert (encoder_class); + gst_vaapiencode_class_install_properties (encode_class, encoder_class); + g_type_class_unref (encoder_class); +} diff --git a/gst/vaapi/gstvaapiencode_vp9.h b/gst/vaapi/gstvaapiencode_vp9.h new file mode 100644 index 0000000000..8d57bda67b --- /dev/null +++ b/gst/vaapi/gstvaapiencode_vp9.h @@ -0,0 +1,72 @@ +/* + * gstvaapiencode_vp9.h - VA-API VP9 encoder + * + * Copyright (C) 2016 Intel Corporation + * Author: Sreerenj Balachandran + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPIENCODE_VP9_H +#define GST_VAAPIENCODE_VP9_H + +#include +#include "gstvaapiencode.h" + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPIENCODE_VP9 \ + (gst_vaapiencode_vp9_get_type ()) +#define GST_VAAPIENCODE_VP9_CAST(obj) \ + ((GstVaapiEncodeVP9 *)(obj)) +#define GST_VAAPIENCODE_VP9(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPIENCODE_VP9, \ + GstVaapiEncodeVP9)) +#define GST_VAAPIENCODE_VP9_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPIENCODE_VP9, \ + GstVaapiEncodeVP9Class)) +#define GST_VAAPIENCODE_VP9_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPIENCODE_VP9, \ + GstVaapiEncodeVP9Class)) +#define GST_IS_VAAPIENCODE_VP9(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPIENCODE_VP9)) +#define GST_IS_VAAPIENCODE_VP9_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPIENCODE_VP9)) + +typedef struct _GstVaapiEncodeVP9 GstVaapiEncodeVP9; +typedef struct _GstVaapiEncodeVP9Class GstVaapiEncodeVP9Class; + +struct _GstVaapiEncodeVP9 +{ + /*< private >*/ + GstVaapiEncode parent_instance; +}; + +struct _GstVaapiEncodeVP9Class +{ + /*< private >*/ + GstVaapiEncodeClass parent_class; +}; + +GType +gst_vaapiencode_vp9_get_type (void) G_GNUC_CONST; + +GType +gst_vaapiencode_vp9_register_type (GstVaapiDisplay * display); + +G_END_DECLS + +#endif /* GST_VAAPIENCODE_VP9_H */ diff --git a/gst/vaapi/gstvaapioverlay.c b/gst/vaapi/gstvaapioverlay.c new file mode 100644 index 0000000000..c70b01a103 --- /dev/null +++ b/gst/vaapi/gstvaapioverlay.c @@ -0,0 +1,686 @@ +/* + * gstvaapioverlay.c - VA-API vpp overlay + * + * Copyright (C) 2019 Intel Corporation + * Author: U. Artie Eoff + * + * This program 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA +*/ + +/** + * SECTION:element-vaapioverlay + * @title: vaapioverlay + * @short_description: a VA-API base video compositor + * + * The vaapioverlay element is similar to the base compositor element + * but uses VA-API VPP blend functions to accelerate the + * overlay/compositing. + * + * Currently this element only works with iHD driver. + * + * ## Example launch line + * + * |[ + * 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. + * ]| + */ + +#include "gstvaapioverlay.h" +#include "gstvaapipluginutil.h" +#include "gstvaapivideobufferpool.h" + +#define GST_PLUGIN_NAME "vaapioverlay" +#define GST_PLUGIN_DESC "A VA-API overlay filter" + +GST_DEBUG_CATEGORY_STATIC (gst_debug_vaapi_overlay); +#ifndef GST_DISABLE_GST_DEBUG +#define GST_CAT_DEFAULT gst_debug_vaapi_overlay +#else +#define GST_CAT_DEFAULT NULL +#endif + +/* Default templates */ +/* *INDENT-OFF* */ +static const char gst_vaapi_overlay_sink_caps_str[] = + GST_VAAPI_MAKE_SURFACE_CAPS ";" + GST_VIDEO_CAPS_MAKE (GST_VAAPI_FORMATS_ALL); +/* *INDENT-ON* */ + +/* *INDENT-OFF* */ +static const char gst_vaapi_overlay_src_caps_str[] = + GST_VAAPI_MAKE_SURFACE_CAPS ";" + GST_VIDEO_CAPS_MAKE (GST_VAAPI_FORMATS_ALL); +/* *INDENT-ON* */ + +/* *INDENT-OFF* */ +static GstStaticPadTemplate gst_vaapi_overlay_sink_factory = + GST_STATIC_PAD_TEMPLATE ("sink_%u", + GST_PAD_SINK, + GST_PAD_REQUEST, + GST_STATIC_CAPS (gst_vaapi_overlay_sink_caps_str)); +/* *INDENT-ON* */ + +/* *INDENT-OFF* */ +static GstStaticPadTemplate gst_vaapi_overlay_src_factory = + GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (gst_vaapi_overlay_src_caps_str)); +/* *INDENT-ON* */ + +G_DEFINE_TYPE (GstVaapiOverlaySinkPad, gst_vaapi_overlay_sink_pad, + GST_TYPE_VIDEO_AGGREGATOR_PAD); + +typedef struct _GstVaapiOverlaySurfaceGenerator GstVaapiOverlaySurfaceGenerator; +struct _GstVaapiOverlaySurfaceGenerator +{ + GstVaapiOverlay *overlay; + GList *current; + GstVaapiBlendSurface blend_surface; +}; + +#define DEFAULT_PAD_XPOS 0 +#define DEFAULT_PAD_YPOS 0 +#define DEFAULT_PAD_ALPHA 1.0 + +enum +{ + PROP_PAD_0, + PROP_PAD_XPOS, + PROP_PAD_YPOS, + PROP_PAD_ALPHA, +}; + +static void +gst_vaapi_overlay_sink_pad_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstVaapiOverlaySinkPad *pad = GST_VAAPI_OVERLAY_SINK_PAD (object); + + switch (prop_id) { + case PROP_PAD_XPOS: + g_value_set_int (value, pad->xpos); + break; + case PROP_PAD_YPOS: + g_value_set_int (value, pad->ypos); + break; + case PROP_PAD_ALPHA: + g_value_set_double (value, pad->alpha); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_overlay_sink_pad_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstVaapiOverlaySinkPad *pad = GST_VAAPI_OVERLAY_SINK_PAD (object); + + switch (prop_id) { + case PROP_PAD_XPOS: + pad->xpos = g_value_get_int (value); + break; + case PROP_PAD_YPOS: + pad->ypos = g_value_get_int (value); + break; + case PROP_PAD_ALPHA: + pad->alpha = g_value_get_double (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_overlay_sink_pad_finalize (GObject * object) +{ + gst_vaapi_pad_private_finalize (GST_VAAPI_OVERLAY_SINK_PAD (object)->priv); + + G_OBJECT_CLASS (gst_vaapi_overlay_sink_pad_parent_class)->finalize (object); +} + +static void +gst_vaapi_overlay_sink_pad_class_init (GstVaapiOverlaySinkPadClass * klass) +{ + GObjectClass *const gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = gst_vaapi_overlay_sink_pad_finalize; + gobject_class->set_property = gst_vaapi_overlay_sink_pad_set_property; + gobject_class->get_property = gst_vaapi_overlay_sink_pad_get_property; + + g_object_class_install_property (gobject_class, PROP_PAD_XPOS, + g_param_spec_int ("xpos", "X Position", "X Position of the picture", + G_MININT, G_MAXINT, DEFAULT_PAD_XPOS, + G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_PAD_YPOS, + g_param_spec_int ("ypos", "Y Position", "Y Position of the picture", + G_MININT, G_MAXINT, DEFAULT_PAD_YPOS, + G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_PAD_ALPHA, + g_param_spec_double ("alpha", "Alpha", "Alpha of the picture", 0.0, 1.0, + DEFAULT_PAD_ALPHA, + G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); +} + +static void +gst_vaapi_overlay_sink_pad_init (GstVaapiOverlaySinkPad * pad) +{ + pad->xpos = DEFAULT_PAD_XPOS; + pad->ypos = DEFAULT_PAD_YPOS; + pad->alpha = DEFAULT_PAD_ALPHA; + pad->priv = gst_vaapi_pad_private_new (); +} + +static void +gst_vaapi_overlay_child_proxy_init (gpointer g_iface, gpointer iface_data); + +G_DEFINE_TYPE_WITH_CODE (GstVaapiOverlay, gst_vaapi_overlay, + GST_TYPE_VIDEO_AGGREGATOR, GST_VAAPI_PLUGIN_BASE_INIT_INTERFACES + G_IMPLEMENT_INTERFACE (GST_TYPE_CHILD_PROXY, + gst_vaapi_overlay_child_proxy_init)); + +GST_VAAPI_PLUGIN_BASE_DEFINE_SET_CONTEXT (gst_vaapi_overlay_parent_class); + +static GstPad * +gst_vaapi_overlay_request_new_pad (GstElement * element, GstPadTemplate * templ, + const gchar * req_name, const GstCaps * caps) +{ + GstPad *newpad = GST_PAD (GST_ELEMENT_CLASS + (gst_vaapi_overlay_parent_class)->request_new_pad (element, templ, + req_name, caps)); + + if (!newpad) + GST_DEBUG_OBJECT (element, "could not create/add pad"); + else + gst_child_proxy_child_added (GST_CHILD_PROXY (element), G_OBJECT (newpad), + GST_OBJECT_NAME (newpad)); + + return newpad; +} + +static void +gst_vaapi_overlay_release_pad (GstElement * element, GstPad * pad) +{ + GstVaapiOverlay *const overlay = GST_VAAPI_OVERLAY (element); + + gst_child_proxy_child_removed (GST_CHILD_PROXY (overlay), G_OBJECT (pad), + GST_OBJECT_NAME (pad)); + + GST_ELEMENT_CLASS (gst_vaapi_overlay_parent_class)->release_pad (element, + pad); +} + +static inline gboolean +gst_vaapi_overlay_ensure_display (GstVaapiOverlay * overlay) +{ + return gst_vaapi_plugin_base_ensure_display (GST_VAAPI_PLUGIN_BASE (overlay)); +} + +static gboolean +gst_vaapi_overlay_sink_query (GstAggregator * agg, GstAggregatorPad * bpad, + GstQuery * query) +{ + GstVaapiOverlay *const overlay = GST_VAAPI_OVERLAY (agg); + + if (GST_QUERY_TYPE (query) == GST_QUERY_CONTEXT) { + if (gst_vaapi_handle_context_query (GST_ELEMENT (overlay), query)) { + GST_DEBUG_OBJECT (overlay, "sharing display %" GST_PTR_FORMAT, + GST_VAAPI_PLUGIN_BASE_DISPLAY (overlay)); + return TRUE; + } + } else if (GST_QUERY_TYPE (query) == GST_QUERY_ALLOCATION) { + GstCaps *caps; + + gst_query_parse_allocation (query, &caps, NULL); + + if (caps == NULL) + return FALSE; + + if (!gst_vaapi_plugin_base_pad_set_caps + (GST_VAAPI_PLUGIN_BASE (overlay), GST_PAD (bpad), caps, NULL, NULL)) + return FALSE; + } + + return GST_AGGREGATOR_CLASS (gst_vaapi_overlay_parent_class)->sink_query + (agg, bpad, query); +} + +static gboolean +gst_vaapi_overlay_src_query (GstAggregator * agg, GstQuery * query) +{ + GstVaapiOverlay *const overlay = GST_VAAPI_OVERLAY (agg); + + if (GST_QUERY_TYPE (query) == GST_QUERY_CONTEXT) { + if (gst_vaapi_handle_context_query (GST_ELEMENT (overlay), query)) { + GST_DEBUG_OBJECT (overlay, "sharing display %" GST_PTR_FORMAT, + GST_VAAPI_PLUGIN_BASE_DISPLAY (overlay)); + return TRUE; + } + } + + return GST_AGGREGATOR_CLASS (gst_vaapi_overlay_parent_class)->src_query + (agg, query); +} + +static gboolean +gst_vaapi_overlay_start (GstAggregator * agg) +{ + GstVaapiOverlay *const overlay = GST_VAAPI_OVERLAY (agg); + + if (!gst_vaapi_plugin_base_open (GST_VAAPI_PLUGIN_BASE (overlay))) + return FALSE; + + if (!gst_vaapi_overlay_ensure_display (overlay)) + return FALSE; + + overlay->blend = + gst_vaapi_blend_new (GST_VAAPI_PLUGIN_BASE_DISPLAY (overlay)); + if (!overlay->blend) + return FALSE; + + return TRUE; +} + +static gboolean +_reset_sinkpad_private (GstElement * element, GstPad * pad, gpointer user_data) +{ + gst_vaapi_pad_private_reset (GST_VAAPI_OVERLAY_SINK_PAD (pad)->priv); + + return TRUE; +} + +static gboolean +gst_vaapi_overlay_stop (GstAggregator * agg) +{ + GstVaapiOverlay *const overlay = GST_VAAPI_OVERLAY (agg); + + gst_vaapi_video_pool_replace (&overlay->blend_pool, NULL); + gst_vaapi_blend_replace (&overlay->blend, NULL); + + gst_vaapi_plugin_base_close (GST_VAAPI_PLUGIN_BASE (overlay)); + + gst_element_foreach_sink_pad (GST_ELEMENT (overlay), _reset_sinkpad_private, + NULL); + + return TRUE; +} + +static void +gst_vaapi_overlay_destroy (GstVaapiOverlay * const overlay) +{ + gst_vaapi_plugin_base_close (GST_VAAPI_PLUGIN_BASE (overlay)); + gst_element_foreach_sink_pad (GST_ELEMENT (overlay), _reset_sinkpad_private, + NULL); +} + +static void +gst_vaapi_overlay_finalize (GObject * object) +{ + GstVaapiOverlay *const overlay = GST_VAAPI_OVERLAY (object); + + gst_vaapi_overlay_destroy (overlay); + gst_vaapi_plugin_base_finalize (GST_VAAPI_PLUGIN_BASE (overlay)); + + G_OBJECT_CLASS (gst_vaapi_overlay_parent_class)->finalize (object); +} + +static gboolean +gst_vaapi_overlay_propose_allocation (GstAggregator * agg, + GstAggregatorPad * pad, GstQuery * decide_query, GstQuery * query) +{ + return gst_vaapi_plugin_base_pad_propose_allocation + (GST_VAAPI_PLUGIN_BASE (agg), GST_PAD (pad), query); +} + +static gboolean +gst_vaapi_overlay_decide_allocation (GstAggregator * agg, GstQuery * query) +{ + return gst_vaapi_plugin_base_decide_allocation + (GST_VAAPI_PLUGIN_BASE (agg), query); +} + +static GstVaapiBlendSurface * +gst_vaapi_overlay_surface_next (gpointer data) +{ + GstVaapiOverlaySurfaceGenerator *generator; + GstVideoAggregatorPad *vagg_pad; + GstVaapiOverlaySinkPad *pad; + GstVideoFrame *inframe; + GstBuffer *inbuf; + GstBuffer *buf; + GstVaapiVideoMeta *inbuf_meta; + GstVaapiBlendSurface *blend_surface; + + generator = (GstVaapiOverlaySurfaceGenerator *) data; + + /* at the end of the generator? */ + while (generator->current) { + /* get the current video aggregator sinkpad */ + vagg_pad = GST_VIDEO_AGGREGATOR_PAD (generator->current->data); + + /* increment list pointer */ + generator->current = generator->current->next; + + /* recycle the blend surface from the overlay surface generator */ + blend_surface = &generator->blend_surface; + blend_surface->surface = NULL; + + /* Current sinkpad may not be queueing buffers yet (e.g. timestamp-offset) + * or it may have reached EOS */ + if (!gst_video_aggregator_pad_has_current_buffer (vagg_pad)) + continue; + + inframe = gst_video_aggregator_pad_get_prepared_frame (vagg_pad); + buf = gst_video_aggregator_pad_get_current_buffer (vagg_pad); + pad = GST_VAAPI_OVERLAY_SINK_PAD (vagg_pad); + + if (gst_vaapi_plugin_base_pad_get_input_buffer (GST_VAAPI_PLUGIN_BASE + (generator->overlay), GST_PAD (pad), buf, &inbuf) != GST_FLOW_OK) + return blend_surface; + + inbuf_meta = gst_buffer_get_vaapi_video_meta (inbuf); + if (inbuf_meta) { + blend_surface->surface = gst_vaapi_video_meta_get_surface (inbuf_meta); + blend_surface->crop = gst_vaapi_video_meta_get_render_rect (inbuf_meta); + blend_surface->target.x = pad->xpos; + blend_surface->target.y = pad->ypos; + blend_surface->target.width = GST_VIDEO_FRAME_WIDTH (inframe); + blend_surface->target.height = GST_VIDEO_FRAME_HEIGHT (inframe); + blend_surface->alpha = pad->alpha; + } + + gst_buffer_unref (inbuf); + return blend_surface; + } + + return NULL; +} + +static GstFlowReturn +gst_vaapi_overlay_aggregate_frames (GstVideoAggregator * vagg, + GstBuffer * outbuf) +{ + GstVaapiOverlay *const overlay = GST_VAAPI_OVERLAY (vagg); + GstVaapiVideoMeta *outbuf_meta; + GstVaapiSurface *outbuf_surface; + GstVaapiSurfaceProxy *proxy; + GstVaapiOverlaySurfaceGenerator generator; + + if (!overlay->blend_pool) { + GstVaapiVideoPool *pool = + gst_vaapi_surface_pool_new_full (GST_VAAPI_PLUGIN_BASE_DISPLAY + (overlay), + GST_VAAPI_PLUGIN_BASE_SRC_PAD_INFO (overlay), 0); + if (!pool) + return GST_FLOW_ERROR; + gst_vaapi_video_pool_replace (&overlay->blend_pool, pool); + gst_vaapi_video_pool_unref (pool); + } + + outbuf_meta = gst_buffer_get_vaapi_video_meta (outbuf); + if (!outbuf_meta) + return GST_FLOW_ERROR; + + if (!gst_vaapi_video_meta_get_surface_proxy (outbuf_meta)) { + proxy = gst_vaapi_surface_proxy_new_from_pool + (GST_VAAPI_SURFACE_POOL (overlay->blend_pool)); + if (!proxy) + return GST_FLOW_ERROR; + gst_vaapi_video_meta_set_surface_proxy (outbuf_meta, proxy); + gst_vaapi_surface_proxy_unref (proxy); + } + + outbuf_surface = gst_vaapi_video_meta_get_surface (outbuf_meta); + + /* initialize the surface generator */ + generator.overlay = overlay; + generator.current = GST_ELEMENT (overlay)->sinkpads; + + if (!gst_vaapi_blend_process (overlay->blend, outbuf_surface, + gst_vaapi_overlay_surface_next, &generator)) + return GST_FLOW_ERROR; + + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_vaapi_overlay_create_output_buffer (GstVideoAggregator * vagg, + GstBuffer ** outbuf) +{ + GstVaapiOverlay *const overlay = GST_VAAPI_OVERLAY (vagg); + GstBufferPool *const pool = + GST_VAAPI_PLUGIN_BASE_SRC_PAD_BUFFER_POOL (overlay); + + g_return_val_if_fail (pool != NULL, GST_FLOW_ERROR); + + if (!gst_buffer_pool_is_active (pool) && + !gst_buffer_pool_set_active (pool, TRUE)) { + GST_ERROR_OBJECT (overlay, "failed to activate output video buffer pool"); + return GST_FLOW_ERROR; + } + + *outbuf = NULL; + if ((gst_buffer_pool_acquire_buffer (pool, outbuf, NULL) != GST_FLOW_OK) + || !*outbuf) { + GST_ERROR_OBJECT (overlay, "failed to create output video buffer"); + return GST_FLOW_ERROR; + } + + return GST_FLOW_OK; +} + +static gboolean +gst_vaapi_overlay_negotiated_src_caps (GstAggregator * agg, GstCaps * caps) +{ + if (!gst_vaapi_plugin_base_set_caps (GST_VAAPI_PLUGIN_BASE (agg), NULL, caps)) + return FALSE; + + return + GST_AGGREGATOR_CLASS (gst_vaapi_overlay_parent_class)->negotiated_src_caps + (agg, caps); +} + +static GstCaps * +gst_vaapi_overlay_fixate_src_caps (GstAggregator * agg, GstCaps * caps) +{ + GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (agg); + GList *l; + gint best_width = -1, best_height = -1; + gint best_fps_n = -1, best_fps_d = -1; + gdouble best_fps = 0.; + GstCaps *ret = NULL; + GstStructure *s; + + ret = gst_caps_make_writable (caps); + + GST_OBJECT_LOCK (vagg); + for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) { + GstVideoAggregatorPad *vaggpad = l->data; + GstVaapiOverlaySinkPad *pad = GST_VAAPI_OVERLAY_SINK_PAD (vaggpad); + gint this_width, this_height; + gint fps_n, fps_d; + gdouble cur_fps; + + fps_n = GST_VIDEO_INFO_FPS_N (&vaggpad->info); + fps_d = GST_VIDEO_INFO_FPS_D (&vaggpad->info); + + this_width = GST_VIDEO_INFO_WIDTH (&vaggpad->info) + MAX (pad->xpos, 0); + this_height = GST_VIDEO_INFO_HEIGHT (&vaggpad->info) + MAX (pad->ypos, 0); + + if (best_width < this_width) + best_width = this_width; + if (best_height < this_height) + best_height = this_height; + + if (fps_d == 0) + cur_fps = 0.0; + else + gst_util_fraction_to_double (fps_n, fps_d, &cur_fps); + + if (best_fps < cur_fps) { + best_fps = cur_fps; + best_fps_n = fps_n; + best_fps_d = fps_d; + } + } + GST_OBJECT_UNLOCK (vagg); + + if (best_fps_n <= 0 || best_fps_d <= 0 || best_fps == 0.0) { + best_fps_n = 25; + best_fps_d = 1; + best_fps = 25.0; + } + + s = gst_caps_get_structure (ret, 0); + gst_structure_fixate_field_nearest_int (s, "width", best_width); + gst_structure_fixate_field_nearest_int (s, "height", best_height); + gst_structure_fixate_field_nearest_fraction (s, "framerate", best_fps_n, + best_fps_d); + + return gst_caps_fixate (ret); +} + +static GstVaapiPadPrivate * +gst_vaapi_overlay_get_vaapi_pad_private (GstVaapiPluginBase * plugin, + GstPad * pad) +{ + if (GST_IS_VAAPI_OVERLAY_SINK_PAD (pad)) + return GST_VAAPI_OVERLAY_SINK_PAD (pad)->priv; + + g_assert (GST_VAAPI_PLUGIN_BASE_SRC_PAD (plugin) == pad); + return GST_VAAPI_PLUGIN_BASE_SRC_PAD_PRIVATE (plugin); +} + +static void +gst_vaapi_overlay_class_init (GstVaapiOverlayClass * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstElementClass *const element_class = GST_ELEMENT_CLASS (klass); + GstAggregatorClass *const agg_class = GST_AGGREGATOR_CLASS (klass); + GstVideoAggregatorClass *const vagg_class = + GST_VIDEO_AGGREGATOR_CLASS (klass); + GstVaapiPluginBaseClass *plugin_class = GST_VAAPI_PLUGIN_BASE_CLASS (klass); + + GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi_overlay, + GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC); + + gst_vaapi_plugin_base_class_init (plugin_class); + plugin_class->get_vaapi_pad_private = + GST_DEBUG_FUNCPTR (gst_vaapi_overlay_get_vaapi_pad_private); + + object_class->finalize = GST_DEBUG_FUNCPTR (gst_vaapi_overlay_finalize); + + agg_class->sink_query = GST_DEBUG_FUNCPTR (gst_vaapi_overlay_sink_query); + agg_class->src_query = GST_DEBUG_FUNCPTR (gst_vaapi_overlay_src_query); + agg_class->start = GST_DEBUG_FUNCPTR (gst_vaapi_overlay_start); + agg_class->propose_allocation = + GST_DEBUG_FUNCPTR (gst_vaapi_overlay_propose_allocation); + agg_class->fixate_src_caps = + GST_DEBUG_FUNCPTR (gst_vaapi_overlay_fixate_src_caps); + agg_class->negotiated_src_caps = + GST_DEBUG_FUNCPTR (gst_vaapi_overlay_negotiated_src_caps); + agg_class->decide_allocation = + GST_DEBUG_FUNCPTR (gst_vaapi_overlay_decide_allocation); + agg_class->stop = GST_DEBUG_FUNCPTR (gst_vaapi_overlay_stop); + + vagg_class->aggregate_frames = + GST_DEBUG_FUNCPTR (gst_vaapi_overlay_aggregate_frames); + vagg_class->create_output_buffer = + GST_DEBUG_FUNCPTR (gst_vaapi_overlay_create_output_buffer); + + element_class->request_new_pad = + GST_DEBUG_FUNCPTR (gst_vaapi_overlay_request_new_pad); + element_class->release_pad = + GST_DEBUG_FUNCPTR (gst_vaapi_overlay_release_pad); + element_class->set_context = GST_DEBUG_FUNCPTR (gst_vaapi_base_set_context); + + gst_element_class_add_static_pad_template_with_gtype (element_class, + &gst_vaapi_overlay_sink_factory, GST_TYPE_VAAPI_OVERLAY_SINK_PAD); + + gst_element_class_add_static_pad_template_with_gtype (element_class, + &gst_vaapi_overlay_src_factory, GST_TYPE_AGGREGATOR_PAD); + + gst_element_class_set_static_metadata (element_class, + "VA-API overlay", + "Filter/Editor/Video/Compositor/Hardware", + GST_PLUGIN_DESC, "U. Artie Eoff "); +} + +static void +gst_vaapi_overlay_init (GstVaapiOverlay * overlay) +{ + gst_vaapi_plugin_base_init (GST_VAAPI_PLUGIN_BASE (overlay), GST_CAT_DEFAULT); +} + +/* GstChildProxy implementation */ +static GObject * +gst_vaapi_overlay_child_proxy_get_child_by_index (GstChildProxy * child_proxy, + guint index) +{ + GstVaapiOverlay *overlay = GST_VAAPI_OVERLAY (child_proxy); + GObject *obj = NULL; + + GST_OBJECT_LOCK (overlay); + obj = g_list_nth_data (GST_ELEMENT_CAST (overlay)->sinkpads, index); + if (obj) + gst_object_ref (obj); + GST_OBJECT_UNLOCK (overlay); + + return obj; +} + +static guint +gst_vaapi_overlay_child_proxy_get_children_count (GstChildProxy * child_proxy) +{ + guint count = 0; + GstVaapiOverlay *overlay = GST_VAAPI_OVERLAY (child_proxy); + + GST_OBJECT_LOCK (overlay); + count = GST_ELEMENT_CAST (overlay)->numsinkpads; + GST_OBJECT_UNLOCK (overlay); + + return count; +} + +static void +gst_vaapi_overlay_child_proxy_init (gpointer g_iface, gpointer iface_data) +{ + GstChildProxyInterface *iface = g_iface; + + iface->get_child_by_index = gst_vaapi_overlay_child_proxy_get_child_by_index; + iface->get_children_count = gst_vaapi_overlay_child_proxy_get_children_count; +} + +gboolean +gst_vaapioverlay_register (GstPlugin * plugin, GstVaapiDisplay * display) +{ + GstVaapiBlend *blend = NULL; + + blend = gst_vaapi_blend_new (display); + if (!blend) + return FALSE; + gst_vaapi_blend_replace (&blend, NULL); + + return gst_element_register (plugin, "vaapioverlay", GST_RANK_NONE, + GST_TYPE_VAAPI_OVERLAY); +} diff --git a/gst/vaapi/gstvaapioverlay.h b/gst/vaapi/gstvaapioverlay.h new file mode 100644 index 0000000000..0357cd0fcf --- /dev/null +++ b/gst/vaapi/gstvaapioverlay.h @@ -0,0 +1,103 @@ +/* + * gstvaapioverlay.h - VA-API vpp overlay + * + * Copyright (C) 2019 Intel Corporation + * Author: U. Artie Eoff + * + * This program 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA +*/ + +#ifndef GST_VAAPI_OVERLAY_H +#define GST_VAAPI_OVERLAY_H + +#include "gstvaapipluginbase.h" +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_OVERLAY (gst_vaapi_overlay_get_type ()) +#define GST_VAAPI_OVERLAY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_OVERLAY, GstVaapiOverlay)) +#define GST_VAAPI_OVERLAY_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPI_OVERLAY, \ + GstVaapiOverlayClass)) +#define GST_IS_VAAPI_OVERLAY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_OVERLAY)) +#define GST_IS_VAAPI_OVERLAY_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPI_OVERLAY)) +#define GST_VAAPI_OVERLAY_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_OVERLAY, \ + GstVaapiOverlayClass)) + +#define GST_TYPE_VAAPI_OVERLAY_SINK_PAD (gst_vaapi_overlay_sink_pad_get_type()) +#define GST_VAAPI_OVERLAY_SINK_PAD(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_OVERLAY_SINK_PAD, \ + GstVaapiOverlaySinkPad)) +#define GST_VAAPI_OVERLAY_SINK_PAD_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPI_OVERLAY_SINK_PAD, \ + GstVaapiOverlaySinkPadClass)) +#define GST_IS_VAAPI_OVERLAY_SINK_PAD(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_OVERLAY_SINK_PAD)) +#define GST_IS_VAAPI_OVERLAY_SINK_PAD_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPI_OVERLAY_SINK_PAD)) + +typedef struct _GstVaapiOverlay GstVaapiOverlay; +typedef struct _GstVaapiOverlayClass GstVaapiOverlayClass; + +typedef struct _GstVaapiOverlaySinkPad GstVaapiOverlaySinkPad; +typedef struct _GstVaapiOverlaySinkPadClass GstVaapiOverlaySinkPadClass; + +struct _GstVaapiOverlay +{ + GstVaapiPluginBase parent_instance; + + GstVaapiBlend *blend; + GstVaapiVideoPool *blend_pool; +}; + +struct _GstVaapiOverlayClass +{ + GstVaapiPluginBaseClass parent_class; +}; + +struct _GstVaapiOverlaySinkPad +{ + GstVideoAggregatorPad parent_instance; + + gint xpos, ypos; + gdouble alpha; + + GstVaapiPadPrivate *priv; +}; + +struct _GstVaapiOverlaySinkPadClass +{ + GstVideoAggregatorPadClass parent_class; +}; + +GType +gst_vaapi_overlay_get_type (void) G_GNUC_CONST; + +GType +gst_vaapi_overlay_sink_pad_get_type (void) G_GNUC_CONST; + +gboolean +gst_vaapioverlay_register (GstPlugin * plugin, GstVaapiDisplay * display); + +G_END_DECLS + +#endif diff --git a/gst/vaapi/gstvaapipluginbase.c b/gst/vaapi/gstvaapipluginbase.c new file mode 100644 index 0000000000..a670e976e5 --- /dev/null +++ b/gst/vaapi/gstvaapipluginbase.c @@ -0,0 +1,1607 @@ +/* + * gstvaapipluginbase.c - Base GStreamer VA-API Plugin element + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gstcompat.h" +#include +#include +#include "gstvaapipluginbase.h" +#include "gstvaapipluginutil.h" +#include "gstvaapivideocontext.h" +#include "gstvaapivideometa.h" +#include "gstvaapivideobufferpool.h" +#if USE_GST_GL_HELPERS +# include +#endif + +GST_DEBUG_CATEGORY_STATIC (CAT_PERFORMANCE); +/* Default debug category is from the subclass */ +#define GST_CAT_DEFAULT (plugin->debug_category) + +#define BUFFER_POOL_SINK_MIN_BUFFERS 2 + +#define GST_VAAPI_PAD_PRIVATE(pad) \ + (GST_VAAPI_PLUGIN_BASE_GET_CLASS(plugin)->get_vaapi_pad_private(plugin, pad)) + +GstVaapiPadPrivate * +gst_vaapi_pad_private_new (void) +{ + GstVaapiPadPrivate *priv = g_new0 (GstVaapiPadPrivate, 1); + + gst_video_info_init (&priv->info); + + return priv; +} + +void +gst_vaapi_pad_private_reset (GstVaapiPadPrivate * priv) +{ + g_assert (priv); + + gst_caps_replace (&priv->caps, NULL); + gst_video_info_init (&priv->info); + + gst_clear_object (&priv->buffer_pool); + gst_clear_object (&priv->allocator); + + priv->buffer_size = 0; + priv->caps_is_raw = FALSE; + + gst_clear_object (&priv->other_allocator); +} + +void +gst_vaapi_pad_private_finalize (GstVaapiPadPrivate * priv) +{ + gst_vaapi_pad_private_reset (priv); + g_free (priv); +} + +/* GstVideoContext interface */ +static void +plugin_set_display (GstVaapiPluginBase * plugin, GstVaapiDisplay * display) +{ + const gchar *const display_name = + gst_vaapi_display_get_display_name (display); + + if (plugin->display_name && g_strcmp0 (plugin->display_name, display_name)) { + GST_DEBUG_OBJECT (plugin, "incompatible display name '%s', requested '%s'", + display_name, plugin->display_name); + gst_vaapi_display_replace (&plugin->display, NULL); + } else { + GST_INFO_OBJECT (plugin, "set display %" GST_PTR_FORMAT, display); + gst_vaapi_display_replace (&plugin->display, display); + plugin->display_type = gst_vaapi_display_get_display_type (display); + gst_vaapi_plugin_base_set_display_name (plugin, display_name); + } + gst_object_unref (display); +} + +/** + * gst_vaapi_plugin_base_set_context: + * @plugin: a #GstVaapiPluginBase instance + * @context: a #GstContext to set + * + * This is a common set_context() element's vmethod for all the + * GStreamer VA-API elements. + * + * It normally should be used through the macro + * #GST_VAAPI_PLUGIN_BASE_DEFINE_SET_CONTEXT() + **/ +void +gst_vaapi_plugin_base_set_context (GstVaapiPluginBase * plugin, + GstContext * context) +{ + GstVaapiDisplay *display = NULL; + + /* gst.vaapi.app.Display is only attended _if_ the element is + * vaapisink and it doesn't have a display set yet */ + if (gst_vaapi_video_context_get_display (context, + GST_IS_VIDEO_SINK (plugin) && !plugin->display, &display)) { + plugin_set_display (plugin, display); + } +#if USE_GST_GL_HELPERS + gst_gl_handle_set_context (GST_ELEMENT_CAST (plugin), context, + (GstGLDisplay **) & plugin->gl_display, + (GstGLContext **) & plugin->gl_other_context); +#endif +} + +void +gst_vaapi_plugin_base_init_interfaces (GType g_define_type_id) +{ +} + +static gboolean +default_has_interface (GstVaapiPluginBase * plugin, GType type) +{ + return FALSE; +} + +static void +default_display_changed (GstVaapiPluginBase * plugin) +{ +} + +static GstVaapiSurface * +_get_cached_surface (GstBuffer * buf) +{ + return gst_mini_object_get_qdata (GST_MINI_OBJECT (buf), + g_quark_from_static_string ("GstVaapiDMABufSurface")); +} + +static void +_set_cached_surface (GstBuffer * buf, GstVaapiSurface * surface) +{ + return gst_mini_object_set_qdata (GST_MINI_OBJECT (buf), + g_quark_from_static_string ("GstVaapiDMABufSurface"), surface, + (GDestroyNotify) gst_vaapi_surface_unref); +} + +static gboolean +plugin_update_sinkpad_info_from_buffer (GstVaapiPluginBase * plugin, + GstPad * sinkpad, GstBuffer * buf) +{ + GstVaapiPadPrivate *sinkpriv = GST_VAAPI_PAD_PRIVATE (sinkpad); + GstVideoInfo *const vip = &sinkpriv->info; + GstVideoMeta *vmeta; + guint i; + + vmeta = gst_buffer_get_video_meta (buf); + if (!vmeta) + return TRUE; + + if (GST_VIDEO_INFO_FORMAT (vip) != vmeta->format || + GST_VIDEO_INFO_WIDTH (vip) != vmeta->width || + GST_VIDEO_INFO_HEIGHT (vip) != vmeta->height || + GST_VIDEO_INFO_N_PLANES (vip) != vmeta->n_planes) + return FALSE; + + for (i = 0; i < GST_VIDEO_INFO_N_PLANES (vip); ++i) { + GST_VIDEO_INFO_PLANE_OFFSET (vip, i) = vmeta->offset[i]; + GST_VIDEO_INFO_PLANE_STRIDE (vip, i) = vmeta->stride[i]; + } + GST_VIDEO_INFO_SIZE (vip) = gst_buffer_get_size (buf); + return TRUE; +} + +static gboolean +is_dma_buffer (GstBuffer * buf) +{ + GstMemory *mem; + + if (gst_buffer_n_memory (buf) < 1) + return FALSE; + + mem = gst_buffer_peek_memory (buf, 0); + if (!mem || !gst_is_dmabuf_memory (mem)) + return FALSE; + return TRUE; +} + +static gboolean +plugin_bind_dma_to_vaapi_buffer (GstVaapiPluginBase * plugin, GstPad * sinkpad, + GstBuffer * inbuf, GstBuffer * outbuf) +{ + GstVaapiPadPrivate *sinkpriv = GST_VAAPI_PAD_PRIVATE (sinkpad); + GstVideoInfo *const vip = &sinkpriv->info; + GstVaapiVideoMeta *meta; + GstVaapiSurface *surface; + GstVaapiSurfaceProxy *proxy; + gint fd; + + fd = gst_dmabuf_memory_get_fd (gst_buffer_peek_memory (inbuf, 0)); + if (fd < 0) + return FALSE; + + if (!plugin_update_sinkpad_info_from_buffer (plugin, sinkpad, inbuf)) + goto error_update_sinkpad_info; + + meta = gst_buffer_get_vaapi_video_meta (outbuf); + g_return_val_if_fail (meta != NULL, FALSE); + + /* Check for a VASurface cached in the buffer */ + surface = _get_cached_surface (inbuf); + if (!surface) { + /* otherwise create one and cache it */ + surface = + gst_vaapi_surface_new_with_dma_buf_handle (plugin->display, fd, vip); + if (!surface) + goto error_create_surface; + _set_cached_surface (inbuf, surface); + } + + proxy = gst_vaapi_surface_proxy_new (surface); + if (!proxy) + goto error_create_proxy; + gst_vaapi_video_meta_set_surface_proxy (meta, proxy); + gst_vaapi_surface_proxy_unref (proxy); + gst_buffer_add_parent_buffer_meta (outbuf, inbuf); + return TRUE; + + /* ERRORS */ +error_update_sinkpad_info: + { + GST_ERROR_OBJECT (plugin, + "failed to update sink pad video info from video meta"); + return FALSE; + } +error_create_surface: + { + GST_ERROR_OBJECT (plugin, + "failed to create VA surface from dma_buf handle"); + return FALSE; + } +error_create_proxy: + { + GST_ERROR_OBJECT (plugin, + "failed to create VA surface proxy from wrapped VA surface"); + return FALSE; + } +} + +static void +plugin_reset_texture_map (GstVaapiPluginBase * plugin) +{ + if (plugin->display) + gst_vaapi_display_reset_texture_map (plugin->display); +} + +static GstVaapiPadPrivate * +default_get_vaapi_pad_private (GstVaapiPluginBase * plugin, GstPad * pad) +{ + if (plugin->sinkpad == pad) + return plugin->sinkpriv; + + g_assert (plugin->srcpad == pad); + return plugin->srcpriv; +} + +void +gst_vaapi_plugin_base_class_init (GstVaapiPluginBaseClass * klass) +{ + klass->has_interface = default_has_interface; + klass->display_changed = default_display_changed; + klass->get_vaapi_pad_private = default_get_vaapi_pad_private; +} + +void +gst_vaapi_plugin_base_init (GstVaapiPluginBase * plugin, + GstDebugCategory * debug_category) +{ + plugin->debug_category = debug_category; + plugin->display_type = GST_VAAPI_DISPLAY_TYPE_ANY; + plugin->display_type_req = GST_VAAPI_DISPLAY_TYPE_ANY; + + /* sink pad */ + plugin->sinkpad = gst_element_get_static_pad (GST_ELEMENT (plugin), "sink"); + + if (plugin->sinkpad) + plugin->sinkpriv = gst_vaapi_pad_private_new (); + + /* src pad */ + if (!(GST_OBJECT_FLAGS (plugin) & GST_ELEMENT_FLAG_SINK)) + plugin->srcpad = gst_element_get_static_pad (GST_ELEMENT (plugin), "src"); + + if (plugin->srcpad) + plugin->srcpriv = gst_vaapi_pad_private_new (); + + plugin->enable_direct_rendering = + (g_getenv ("GST_VAAPI_ENABLE_DIRECT_RENDERING") != NULL); +} + +void +gst_vaapi_plugin_base_finalize (GstVaapiPluginBase * plugin) +{ + gst_vaapi_plugin_base_close (plugin); + gst_vaapi_display_replace (&plugin->display, NULL); + g_free (plugin->display_name); + + if (plugin->sinkpriv) + gst_vaapi_pad_private_finalize (plugin->sinkpriv); + if (plugin->srcpriv) + gst_vaapi_pad_private_finalize (plugin->srcpriv); + + if (plugin->sinkpad) + gst_object_unref (plugin->sinkpad); + if (plugin->srcpad) + gst_object_unref (plugin->srcpad); +} + +/** + * gst_vaapi_plugin_base_open: + * @plugin: a #GstVaapiPluginBase + * + * Allocates any internal resources needed for correct operation from + * the subclass. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ +gboolean +gst_vaapi_plugin_base_open (GstVaapiPluginBase * plugin) +{ + gst_caps_replace (&plugin->allowed_raw_caps, NULL); + return TRUE; +} + +/** + * gst_vaapi_plugin_base_close: + * @plugin: a #GstVaapiPluginBase + * + * Deallocates all internal resources that were allocated so + * far. i.e. put the base plugin object into a clean state. + */ +void +gst_vaapi_plugin_base_close (GstVaapiPluginBase * plugin) +{ + /* Release vaapi textures first if exist, which refs display object */ + plugin_reset_texture_map (plugin); + + gst_object_replace (&plugin->gl_context, NULL); + gst_object_replace (&plugin->gl_display, NULL); + gst_object_replace (&plugin->gl_other_context, NULL); + + gst_caps_replace (&plugin->allowed_raw_caps, NULL); + + if (plugin->sinkpriv) + gst_vaapi_pad_private_reset (plugin->sinkpriv); + if (plugin->srcpriv) + gst_vaapi_pad_private_reset (plugin->srcpriv); +} + +/** + * gst_vaapi_plugin_base_has_display_type: + * @plugin: a #GstVaapiPluginBase + * @display_type_req: the desired #GstVaapiDisplayType + * + * Checks whether the @plugin elements already has a #GstVaapiDisplay + * instance compatible with type @display_type_req. + * + * Return value: %TRUE if @plugin has a compatible display, %FALSE otherwise + */ +gboolean +gst_vaapi_plugin_base_has_display_type (GstVaapiPluginBase * plugin, + GstVaapiDisplayType display_type_req) +{ + GstVaapiDisplayType display_type; + + if (!plugin->display) + return FALSE; + + display_type = plugin->display_type; + if (gst_vaapi_display_type_is_compatible (display_type, display_type_req)) + return TRUE; + + display_type = gst_vaapi_display_get_class_type (plugin->display); + if (gst_vaapi_display_type_is_compatible (display_type, display_type_req)) + return TRUE; + return FALSE; +} + +/** + * gst_vaapi_plugin_base_set_display_type: + * @plugin: a #GstVaapiPluginBase + * @display_type: the new request #GstVaapiDisplayType + * + * Requests a new display type. The change is effective at the next + * call to gst_vaapi_plugin_base_ensure_display(). + */ +void +gst_vaapi_plugin_base_set_display_type (GstVaapiPluginBase * plugin, + GstVaapiDisplayType display_type) +{ + plugin->display_type_req = display_type; +} + +/** + * gst_vaapi_plugin_base_set_display_name: + * @plugin: a #GstVaapiPluginBase + * @display_name: the new display name to match + * + * Sets the name of the display to look for. The change is effective + * at the next call to gst_vaapi_plugin_base_ensure_display(). + */ +void +gst_vaapi_plugin_base_set_display_name (GstVaapiPluginBase * plugin, + const gchar * display_name) +{ + g_free (plugin->display_name); + plugin->display_name = g_strdup (display_name); +} + +/** + * gst_vaapi_plugin_base_ensure_display: + * @plugin: a #GstVaapiPluginBase + * + * Ensures the display stored in @plugin complies with the requested + * display type constraints. + * + * Returns: %TRUE if the display was created to match the requested + * type, %FALSE otherwise. + */ +gboolean +gst_vaapi_plugin_base_ensure_display (GstVaapiPluginBase * plugin) +{ + if (gst_vaapi_plugin_base_has_display_type (plugin, plugin->display_type_req)) + return TRUE; + gst_vaapi_display_replace (&plugin->display, NULL); + + if (!gst_vaapi_ensure_display (GST_ELEMENT (plugin), + plugin->display_type_req)) + return FALSE; + plugin->display_type = gst_vaapi_display_get_display_type (plugin->display); + + GST_VAAPI_PLUGIN_BASE_GET_CLASS (plugin)->display_changed (plugin); + return TRUE; +} + +static gboolean +gst_vaapi_buffer_pool_caps_is_equal (GstBufferPool * pool, GstCaps * newcaps) +{ + GstStructure *config; + GstCaps *caps; + gboolean ret; + + caps = NULL; + ret = FALSE; + config = gst_buffer_pool_get_config (pool); + if (gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL)) + ret = gst_caps_is_equal (newcaps, caps); + gst_structure_free (config); + + return ret; +} + +static inline gboolean +reset_allocator (GstAllocator * allocator, GstVideoInfo * vinfo) +{ + const GstVideoInfo *orig_vi; + + if (!allocator) + return TRUE; + + orig_vi = gst_allocator_get_vaapi_video_info (allocator, NULL); + if (!gst_video_info_changed (orig_vi, vinfo)) + return FALSE; + + gst_object_unref (allocator); + return TRUE; +} + +static gboolean +ensure_sinkpad_allocator (GstVaapiPluginBase * plugin, GstPad * sinkpad, + GstCaps * caps, guint * size) +{ + GstVaapiPadPrivate *sinkpriv = GST_VAAPI_PAD_PRIVATE (sinkpad); + GstVideoInfo vinfo; + const GstVideoInfo *image_info; + GstVaapiImageUsageFlags usage_flag = + GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS; + + if (!gst_video_info_from_caps (&vinfo, caps)) + goto error_invalid_caps; + + if (!reset_allocator (sinkpriv->allocator, &vinfo)) + goto bail; + + /* enable direct upload if upstream requests raw video */ + if (gst_caps_is_video_raw (caps)) { + usage_flag = GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_UPLOAD; + GST_INFO_OBJECT (plugin, "enabling direct upload in sink allocator"); + } + sinkpriv->allocator = + gst_vaapi_video_allocator_new (plugin->display, &vinfo, 0, usage_flag); + +bail: + if (!sinkpriv->allocator) + goto error_create_allocator; + + image_info = gst_allocator_get_vaapi_video_info (sinkpriv->allocator, NULL); + g_assert (image_info); /* allocator ought set its image info */ + + /* update the size with the one generated by the allocator */ + *size = GST_VIDEO_INFO_SIZE (image_info); + + return TRUE; + + /* ERRORS */ +error_invalid_caps: + { + GST_ERROR_OBJECT (plugin, "invalid caps %" GST_PTR_FORMAT, caps); + return FALSE; + } +error_create_allocator: + { + GST_ERROR_OBJECT (plugin, "failed to create sink pad's allocator"); + return FALSE; + } +} + +static inline guint +get_dmabuf_surface_allocation_flags (void) +{ + /* @FIXME: fetch the real devices ids */ + /* Pair vendor/device identifies an unique physical device. */ + guint va_vendor_id = 0x00; + guint va_device_id = 0x00; + guint gl_vendor_id = 0x00; + guint gl_device_id = 0x00; + + /* Requires linear memory only if fd export is done on a different + * device than the device where the fd is imported. */ + gboolean same_physical_device = va_vendor_id == gl_vendor_id + && va_device_id == gl_device_id; + + if (same_physical_device) + return 0; + return GST_VAAPI_SURFACE_ALLOC_FLAG_LINEAR_STORAGE; +} + +static inline GstAllocator * +create_dmabuf_srcpad_allocator (GstVaapiPluginBase * plugin, + GstVideoInfo * vinfo, gboolean check_for_map) +{ + GstAllocator *allocator; + + if (!GST_IS_VIDEO_DECODER (plugin) && !GST_IS_BASE_TRANSFORM (plugin)) + return NULL; + + allocator = gst_vaapi_dmabuf_allocator_new (plugin->display, vinfo, + get_dmabuf_surface_allocation_flags (), GST_PAD_SRC); + if (!allocator || !check_for_map) + return allocator; + + /* the dmabuf allocator *must* be capable to map a buffer with raw + * caps and the there's no evidence of downstream dmabuf + * importation */ + if (!gst_vaapi_dmabuf_can_map (plugin->display, allocator)) { + GST_INFO_OBJECT (plugin, "dmabuf allocator generates unmappable buffers"); + gst_object_replace ((GstObject **) & allocator, NULL); + } + + return allocator; +} + +static gboolean +ensure_srcpad_allocator (GstVaapiPluginBase * plugin, GstPad * srcpad, + GstVideoInfo * vinfo, GstCaps * caps) +{ + GstVaapiPadPrivate *srcpriv = GST_VAAPI_PAD_PRIVATE (srcpad); + const GstVideoInfo *image_info; + + if (!reset_allocator (srcpriv->allocator, vinfo)) + goto valid_allocator; + + srcpriv->allocator = NULL; + if (caps && gst_vaapi_caps_feature_contains (caps, + GST_VAAPI_CAPS_FEATURE_DMABUF)) { + srcpriv->allocator = create_dmabuf_srcpad_allocator (plugin, vinfo, FALSE); + if (!srcpriv->allocator) + goto error_create_allocator; + } + + if (!srcpriv->allocator) { + GstVaapiImageUsageFlags usage_flag = + GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS; + + if (plugin->enable_direct_rendering) { + usage_flag = GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_RENDER; + GST_INFO_OBJECT (plugin, "enabling direct rendering in source allocator"); + } + + srcpriv->allocator = + gst_vaapi_video_allocator_new (plugin->display, vinfo, 0, usage_flag); + } + + if (!srcpriv->allocator) + goto error_create_allocator; + +valid_allocator: + image_info = gst_allocator_get_vaapi_video_info (srcpriv->allocator, NULL); + g_assert (image_info); /* both allocators ought set its image + * info */ + + /* update the size with the one generated by the allocator */ + GST_VIDEO_INFO_SIZE (vinfo) = GST_VIDEO_INFO_SIZE (image_info); + + if (GST_IS_VIDEO_DECODER (plugin)) { + /* the received caps are the "allocation caps" which may be + * different from the "negotiation caps". In this case, we should + * indicate the allocator to store the negotiation caps since they + * are the one should be used for frame mapping with GstVideoMeta */ + gboolean different_caps = srcpriv->caps && + !gst_caps_is_strictly_equal (srcpriv->caps, caps); + const GstVideoInfo *previous_negotiated = + gst_allocator_get_vaapi_negotiated_video_info (srcpriv->allocator); + + if (different_caps) { + guint i; + GstVideoInfo vi = srcpriv->info; + + /* update the planes and the size with the allocator image/surface + * info, but not the resolution */ + for (i = 0; i < GST_VIDEO_INFO_N_PLANES (image_info); i++) { + GST_VIDEO_INFO_PLANE_OFFSET (&vi, i) = + GST_VIDEO_INFO_PLANE_OFFSET (image_info, i); + GST_VIDEO_INFO_PLANE_STRIDE (&vi, i) = + GST_VIDEO_INFO_PLANE_STRIDE (image_info, i); + } + GST_VIDEO_INFO_SIZE (&vi) = GST_VIDEO_INFO_SIZE (image_info); + gst_allocator_set_vaapi_negotiated_video_info (srcpriv->allocator, &vi); + } else if (previous_negotiated) { + gst_allocator_set_vaapi_negotiated_video_info (srcpriv->allocator, NULL); + } + } + return TRUE; + + /* ERRORS */ +error_create_allocator: + { + GST_ERROR_OBJECT (plugin, "failed to create src pad's allocator"); + return FALSE; + } +} + +/** + * gst_vaapi_plugin_base_create_pool: + * @plugin: a #GstVaapiPluginBase + * @caps: the initial #GstCaps for the resulting buffer pool + * @size: the size of each buffer, not including prefix and padding + * @options: a set of #GstVaapiVideoBufferPoolOption encoded as bit-wise + * @allocator: (allow-none): the #GstAllocator to use or %NULL + * + * Create an instance of #GstVaapiVideoBufferPool + * + * Returns: (transfer full): a new allocated #GstBufferPool + **/ +static GstBufferPool * +gst_vaapi_plugin_base_create_pool (GstVaapiPluginBase * plugin, GstCaps * caps, + gsize size, guint min_buffers, guint max_buffers, guint options, + GstAllocator * allocator) +{ + GstBufferPool *pool; + GstStructure *config; + + if (!(pool = gst_vaapi_video_buffer_pool_new (plugin->display))) + goto error_create_pool; + + config = gst_buffer_pool_get_config (pool); + gst_buffer_pool_config_set_params (config, caps, size, min_buffers, + max_buffers); + gst_buffer_pool_config_add_option (config, + GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META); + if (options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META) { + gst_buffer_pool_config_add_option (config, + GST_BUFFER_POOL_OPTION_VIDEO_META); + } + if (options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT) { + gst_buffer_pool_config_add_option (config, + GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT); + } +#if (USE_GLX || USE_EGL) + if (options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD) { + gst_buffer_pool_config_add_option (config, + GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META); + } +#endif + if (allocator) + gst_buffer_pool_config_set_allocator (config, allocator, NULL); + if (!gst_buffer_pool_set_config (pool, config)) { + config = gst_buffer_pool_get_config (pool); + + if (!gst_buffer_pool_config_validate_params (config, caps, size, + min_buffers, max_buffers)) { + gst_structure_free (config); + goto error_pool_config; + } + + if (!gst_buffer_pool_set_config (pool, config)) + goto error_pool_config; + } + return pool; + + /* ERRORS */ +error_create_pool: + { + GST_ERROR_OBJECT (plugin, "failed to create buffer pool"); + return NULL; + } +error_pool_config: + { + gst_object_unref (pool); + GST_ELEMENT_ERROR (plugin, RESOURCE, SETTINGS, + ("Failed to configure the buffer pool"), + ("Configuration is most likely invalid, please report this issue.")); + return NULL; + } +} + +/** + * ensure_sinkpad_buffer_pool: + * @plugin: a #GstVaapiPluginBase + * @sinkpad: the #GstPad to use for the resulting buffer pool + * + * Makes sure the sink pad video buffer pool is created with the + * appropriate caps defined in the @sinkpad. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ +static gboolean +ensure_sinkpad_buffer_pool (GstVaapiPluginBase * plugin, GstPad * sinkpad) +{ + GstVaapiPadPrivate *sinkpriv = GST_VAAPI_PAD_PRIVATE (sinkpad); + GstCaps *caps = sinkpriv->caps; + GstBufferPool *pool; + guint size; + + /* video decoders don't use a buffer pool in the sink pad */ + if (GST_IS_VIDEO_DECODER (plugin)) + return TRUE; + + if (!gst_vaapi_plugin_base_ensure_display (plugin)) + return FALSE; + + if (sinkpriv->buffer_pool) { + if (gst_vaapi_buffer_pool_caps_is_equal (sinkpriv->buffer_pool, caps)) + return TRUE; + gst_buffer_pool_set_active (sinkpriv->buffer_pool, FALSE); + gst_clear_object (&sinkpriv->buffer_pool); + gst_clear_object (&sinkpriv->allocator); + sinkpriv->buffer_size = 0; + } + + if (!ensure_sinkpad_allocator (plugin, sinkpad, caps, &size)) + return FALSE; + + pool = + gst_vaapi_plugin_base_create_pool (plugin, caps, size, + BUFFER_POOL_SINK_MIN_BUFFERS, 0, + GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META, sinkpriv->allocator); + if (!pool) + return FALSE; + + sinkpriv->buffer_pool = pool; + sinkpriv->buffer_size = size; + return TRUE; +} + +static gboolean +_set_srcpad_caps (GstVaapiPluginBase * plugin, GstPad * srcpad, GstCaps * caps) +{ + GstVaapiPadPrivate *srcpriv = NULL; + + if (caps) { + g_assert (srcpad); + srcpriv = GST_VAAPI_PAD_PRIVATE (srcpad); + g_assert (srcpriv); + + if (caps != srcpriv->caps) { + if (!gst_video_info_from_caps (&srcpriv->info, caps)) + return FALSE; + if (srcpriv->buffer_pool + && !gst_vaapi_buffer_pool_caps_is_equal (srcpriv->buffer_pool, + caps)) { + gst_buffer_pool_set_active (srcpriv->buffer_pool, FALSE); + gst_clear_object (&srcpriv->buffer_pool); + gst_clear_object (&srcpriv->allocator); + plugin_reset_texture_map (plugin); + } + gst_caps_replace (&srcpriv->caps, caps); + } + } + + return TRUE; +} + +static gboolean +_set_sinkpad_caps (GstVaapiPluginBase * plugin, GstPad * sinkpad, + GstCaps * caps) +{ + GstVaapiPadPrivate *sinkpriv = NULL; + + if (caps) { + g_assert (sinkpad); + sinkpriv = GST_VAAPI_PAD_PRIVATE (sinkpad); + g_assert (sinkpriv); + + if (caps != sinkpriv->caps) { + if (!gst_video_info_from_caps (&sinkpriv->info, caps)) + return FALSE; + gst_caps_replace (&sinkpriv->caps, caps); + sinkpriv->caps_is_raw = !gst_caps_has_vaapi_surface (caps); + } + + if (!ensure_sinkpad_buffer_pool (plugin, sinkpad)) + return FALSE; + } + + return TRUE; +} + +/** + * gst_vaapi_plugin_base_pad_set_caps: + * @plugin: a #GstVaapiPluginBase + * @sinkpad: the sink pad to set @incaps on + * @incaps: the sink pad (input) caps + * @srcpad: the src pad to set @outcaps on + * @outcaps: the src pad (output) caps + * + * Notifies the base plugin object of the new input and output caps, + * obtained from the subclass on the requested pads. + * + * Returns: %TRUE if the update of caps was successful, %FALSE otherwise. + */ +gboolean +gst_vaapi_plugin_base_pad_set_caps (GstVaapiPluginBase * plugin, + GstPad * sinkpad, GstCaps * incaps, GstPad * srcpad, GstCaps * outcaps) +{ + return _set_sinkpad_caps (plugin, sinkpad, incaps) + && _set_srcpad_caps (plugin, srcpad, outcaps); +} + +/** + * gst_vaapi_plugin_base_set_caps: + * @plugin: a #GstVaapiPluginBase + * @incaps: the sink pad (input) caps + * @outcaps: the src pad (output) caps + * + * Notifies the base plugin object of the new input and output caps, + * obtained from the subclass, on the base plugin static pads. + * + * Returns: %TRUE if the update of caps was successful, %FALSE otherwise. + */ +gboolean +gst_vaapi_plugin_base_set_caps (GstVaapiPluginBase * plugin, GstCaps * incaps, + GstCaps * outcaps) +{ + return gst_vaapi_plugin_base_pad_set_caps (plugin, plugin->sinkpad, incaps, + plugin->srcpad, outcaps); +} + +/** + * gst_vaapi_plugin_base_pad_propose_allocation: + * @plugin: a #GstVaapiPluginBase + * @sinkpad: the sinkpad to configure the allocation query on + * @query: the allocation query to configure + * + * Proposes allocation parameters to the upstream elements on the requested + * sinkpad. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ +gboolean +gst_vaapi_plugin_base_pad_propose_allocation (GstVaapiPluginBase * plugin, + GstPad * sinkpad, GstQuery * query) +{ + GstVaapiPadPrivate *sinkpriv = GST_VAAPI_PAD_PRIVATE (sinkpad); + GstCaps *caps = NULL; + GstBufferPool *pool = NULL; + gboolean need_pool; + guint size = 0, n_allocators; + + gst_query_parse_allocation (query, &caps, &need_pool); + if (!caps) + goto error_no_caps; + + if (!ensure_sinkpad_allocator (plugin, sinkpad, caps, &size)) + return FALSE; + + if (need_pool) { + pool = gst_vaapi_plugin_base_create_pool (plugin, caps, size, + BUFFER_POOL_SINK_MIN_BUFFERS, 0, + GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META, sinkpriv->allocator); + if (!pool) + return FALSE; + } + + /* Set sinkpad allocator as the last allocation param. + * + * If there's none, set system's allocator first and VAAPI allocator + * second + */ + n_allocators = gst_query_get_n_allocation_params (query); + if (n_allocators == 0) { + GstAllocator *allocator; + + allocator = gst_allocator_find (GST_ALLOCATOR_SYSMEM); + gst_query_add_allocation_param (query, allocator, NULL); + gst_object_unref (allocator); + } + gst_query_add_allocation_param (query, sinkpriv->allocator, NULL); + + gst_query_add_allocation_pool (query, pool, size, + BUFFER_POOL_SINK_MIN_BUFFERS, 0); + if (pool) + gst_object_unref (pool); + + gst_query_add_allocation_meta (query, GST_VAAPI_VIDEO_META_API_TYPE, NULL); + gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL); + return TRUE; + + /* ERRORS */ +error_no_caps: + { + GST_INFO_OBJECT (plugin, "no caps specified"); + return FALSE; + } +} + +/** + * gst_vaapi_plugin_base_propose_allocation: + * @plugin: a #GstVaapiPluginBase + * @query: the allocation query to configure + * + * Proposes allocation parameters to the upstream elements on the base plugin + * static sinkpad. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ +gboolean +gst_vaapi_plugin_base_propose_allocation (GstVaapiPluginBase * plugin, + GstQuery * query) +{ + return gst_vaapi_plugin_base_pad_propose_allocation (plugin, plugin->sinkpad, + query); +} + +/** + * gst_vaapi_plugin_base_decide_allocation: + * @plugin: a #GstVaapiPluginBase + * @query: the allocation query to parse + * @feature: the desired #GstVaapiCapsFeature, or zero to find the + * preferred one + * + * Decides allocation parameters for the downstream elements on the base + * plugin static srcpad. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ +gboolean +gst_vaapi_plugin_base_decide_allocation (GstVaapiPluginBase * plugin, + GstQuery * query) +{ + GstVaapiPadPrivate *srcpriv = GST_VAAPI_PAD_PRIVATE (plugin->srcpad); + GstCaps *caps = NULL; + GstBufferPool *pool; + GstVideoInfo vi; + guint i, size, min, max, pool_options, num_allocators; + gint index_allocator; + gboolean update_pool = FALSE; +#if (USE_GLX || USE_EGL) + guint idx; +#endif + + gst_query_parse_allocation (query, &caps, NULL); + if (!caps) + goto error_no_caps; + + pool_options = 0; + if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) + pool_options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META; + +#if (USE_GLX || USE_EGL) + if (gst_query_find_allocation_meta (query, + GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, &idx) && + gst_vaapi_caps_feature_contains (caps, + GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META)) + pool_options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD; + +#if USE_GST_GL_HELPERS + if (!plugin->gl_context && + (pool_options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD)) { + const GstStructure *params; + GstObject *gl_context; + + gst_query_parse_nth_allocation_meta (query, idx, ¶ms); + if (params) { + if (gst_structure_get (params, "gst.gl.GstGLContext", GST_TYPE_GL_CONTEXT, + &gl_context, NULL) && gl_context) { + gst_vaapi_plugin_base_set_gl_context (plugin, gl_context); + gst_vaapi_plugin_base_set_srcpad_can_dmabuf (plugin, gl_context); + gst_object_unref (gl_context); + } + } + } +#endif +#endif + + /* Make sure the display we pass down to the buffer pool is actually + the expected one, especially when the downstream element requires + a GLX or EGL display */ + if (!gst_vaapi_plugin_base_ensure_display (plugin)) + goto error_ensure_display; + + if (!gst_video_info_from_caps (&vi, caps)) + goto error_invalid_caps; + gst_video_info_force_nv12_if_encoded (&vi); + + index_allocator = -1; + num_allocators = gst_query_get_n_allocation_params (query); + for (i = 0; i < num_allocators; i++) { + GstAllocator *allocator = NULL; + GstAllocationParams params; + + gst_query_parse_nth_allocation_param (query, i, &allocator, ¶ms); + if (!allocator) + continue; + + /* Let's keep the the first allocator if it is not VA-API. It + * might be used if it is required to copy the output frame to a + * new buffer */ + if (i == 0 + && g_strcmp0 (allocator->mem_type, GST_VAAPI_VIDEO_MEMORY_NAME) != 0) { + if (srcpriv->other_allocator) + gst_object_unref (srcpriv->other_allocator); + srcpriv->other_allocator = allocator; + srcpriv->other_allocator_params = params; + continue; + } + + if (g_strcmp0 (allocator->mem_type, GST_VAAPI_VIDEO_MEMORY_NAME) == 0) { + GST_DEBUG_OBJECT (plugin, "found vaapi allocator in query %" + GST_PTR_FORMAT, allocator); + index_allocator = i; + if (srcpriv->allocator) + gst_object_unref (srcpriv->allocator); + srcpriv->allocator = allocator; + break; + } + gst_object_unref (allocator); + } + + if (gst_query_get_n_allocation_pools (query) > 0) { + gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max); + update_pool = TRUE; + size = MAX (size, GST_VIDEO_INFO_SIZE (&vi)); + if (pool) { + /* Check whether downstream element proposed a bufferpool but did + not provide a correct propose_allocation() implementation */ + if (gst_buffer_pool_has_option (pool, + GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT)) + pool_options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT; + + /* GstVaapiVideoMeta is mandatory, and this implies VA surface memory */ + if (!gst_buffer_pool_has_option (pool, + GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META)) { + GST_INFO_OBJECT (plugin, "ignoring non-VAAPI pool: %" GST_PTR_FORMAT, + pool); + gst_clear_object (&pool); + } + } + } else { + pool = NULL; + size = GST_VIDEO_INFO_SIZE (&vi); + min = max = 0; + } + + if (!pool) { + if (!ensure_srcpad_allocator (plugin, plugin->srcpad, &vi, caps)) + goto error; + size = GST_VIDEO_INFO_SIZE (&vi); /* size might be updated by + * allocator */ + pool = gst_vaapi_plugin_base_create_pool (plugin, caps, size, min, max, + pool_options, srcpriv->allocator); + if (!pool) + goto error; + } + + if (update_pool) + gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max); + else + gst_query_add_allocation_pool (query, pool, size, min, max); + + /* allocator might be updated by ensure_srcpad_allocator() */ + if (srcpriv->allocator) { + if (index_allocator > 0) { + gst_query_set_nth_allocation_param (query, index_allocator, + srcpriv->allocator, NULL); + } else { + GST_DEBUG_OBJECT (plugin, "adding allocator in query %" GST_PTR_FORMAT, + srcpriv->allocator); + gst_query_add_allocation_param (query, srcpriv->allocator, NULL); + } + } + + gst_clear_object (&srcpriv->buffer_pool); + srcpriv->buffer_pool = pool; + + /* if downstream doesn't support GstVideoMeta, and the negotiated + * caps are raw video, and the used allocator is the VA-API one, we + * should copy the VA-API frame into a dumb buffer */ + plugin->copy_output_frame = gst_vaapi_video_buffer_pool_copy_buffer (pool); + + return TRUE; + + /* ERRORS */ +error_no_caps: + { + GST_ERROR_OBJECT (plugin, "no caps specified"); + return FALSE; + } +error_invalid_caps: + { + GST_ERROR_OBJECT (plugin, "invalid caps %" GST_PTR_FORMAT, caps); + return FALSE; + } +error_ensure_display: + { + GST_ERROR_OBJECT (plugin, "failed to ensure display of type %d", + plugin->display_type_req); + return FALSE; + } +error: + { + /* error message already sent */ + return FALSE; + } +} + +/** + * gst_vaapi_plugin_base_pad_get_input_buffer: + * @plugin: a #GstVaapiPluginBase + * @sinkpad: the sink pad to obtain input buffer on + * @inbuf: the sink pad (input) buffer + * @outbuf_ptr: the pointer to location to the VA surface backed buffer + * + * Acquires the static sink pad (input) buffer as a VA surface backed + * buffer. This is mostly useful for raw YUV buffers, as source + * buffers that are already backed as a VA surface are passed + * verbatim. + * + * Returns: #GST_FLOW_OK if the buffer could be acquired + */ +GstFlowReturn +gst_vaapi_plugin_base_pad_get_input_buffer (GstVaapiPluginBase * plugin, + GstPad * sinkpad, GstBuffer * inbuf, GstBuffer ** outbuf_ptr) +{ + GstVaapiPadPrivate *sinkpriv = GST_VAAPI_PAD_PRIVATE (sinkpad); + GstVaapiVideoMeta *meta; + GstBuffer *outbuf; + GstVideoFrame src_frame, out_frame; + gboolean success; + + g_return_val_if_fail (inbuf != NULL, GST_FLOW_ERROR); + g_return_val_if_fail (outbuf_ptr != NULL, GST_FLOW_ERROR); + + meta = gst_buffer_get_vaapi_video_meta (inbuf); + if (meta) { + *outbuf_ptr = gst_buffer_ref (inbuf); + return GST_FLOW_OK; + } + + if (!sinkpriv->caps_is_raw) + goto error_invalid_buffer; + + if (!sinkpriv->buffer_pool) + goto error_no_pool; + + if (!gst_buffer_pool_is_active (sinkpriv->buffer_pool) && + !gst_buffer_pool_set_active (sinkpriv->buffer_pool, TRUE)) + goto error_active_pool; + + outbuf = NULL; + if (gst_buffer_pool_acquire_buffer (sinkpriv->buffer_pool, + &outbuf, NULL) != GST_FLOW_OK) + goto error_create_buffer; + + if (is_dma_buffer (inbuf)) { + if (!plugin_bind_dma_to_vaapi_buffer (plugin, sinkpad, inbuf, outbuf)) + goto error_bind_dma_buffer; + goto done; + } + + if (!gst_video_frame_map (&src_frame, &sinkpriv->info, inbuf, GST_MAP_READ)) + goto error_map_src_buffer; + + if (!gst_video_frame_map (&out_frame, &sinkpriv->info, outbuf, GST_MAP_WRITE)) + goto error_map_dst_buffer; + + success = gst_video_frame_copy (&out_frame, &src_frame); + gst_video_frame_unmap (&out_frame); + gst_video_frame_unmap (&src_frame); + if (!success) + goto error_copy_buffer; + +done: + if (!gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_FLAGS | + GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_META, 0, -1)) + return GST_FLOW_ERROR; + *outbuf_ptr = outbuf; + return GST_FLOW_OK; + + /* ERRORS */ +error_no_pool: + { + GST_ELEMENT_ERROR (plugin, STREAM, FAILED, + ("no buffer pool was negotiated"), ("no buffer pool was negotiated")); + return GST_FLOW_ERROR; + } +error_active_pool: + { + GST_ELEMENT_ERROR (plugin, STREAM, FAILED, + ("failed to activate buffer pool"), ("failed to activate buffer pool")); + return GST_FLOW_ERROR; + } +error_map_dst_buffer: + { + gst_video_frame_unmap (&src_frame); + // fall-through + } +error_map_src_buffer: + { + GST_WARNING ("failed to map buffer"); + gst_buffer_unref (outbuf); + return GST_FLOW_NOT_SUPPORTED; + } + + /* ERRORS */ +error_invalid_buffer: + { + GST_ELEMENT_ERROR (plugin, STREAM, FAILED, + ("failed to validate source buffer"), + ("failed to validate source buffer")); + return GST_FLOW_ERROR; + } +error_create_buffer: + { + GST_ELEMENT_ERROR (plugin, STREAM, FAILED, ("Allocation failed"), + ("failed to create buffer")); + return GST_FLOW_ERROR; + } +error_bind_dma_buffer: + { + GST_ELEMENT_ERROR (plugin, STREAM, FAILED, ("Allocation failed"), + ("failed to bind dma_buf to VA surface buffer")); + gst_buffer_unref (outbuf); + return GST_FLOW_ERROR; + } +error_copy_buffer: + { + GST_WARNING_OBJECT (plugin, "failed to upload buffer to VA surface"); + gst_buffer_unref (outbuf); + return GST_FLOW_NOT_SUPPORTED; + } +} + +/** + * gst_vaapi_plugin_base_get_input_buffer: + * @plugin: a #GstVaapiPluginBase + * @inbuf: the sink pad (input) buffer + * @outbuf_ptr: the pointer to location to the VA surface backed buffer + * + * Acquires the static sink pad (input) buffer as a VA surface backed + * buffer. This is mostly useful for raw YUV buffers, as source + * buffers that are already backed as a VA surface are passed + * verbatim. + * + * Returns: #GST_FLOW_OK if the buffer could be acquired + */ +GstFlowReturn +gst_vaapi_plugin_base_get_input_buffer (GstVaapiPluginBase * plugin, + GstBuffer * inbuf, GstBuffer ** outbuf_ptr) +{ + return gst_vaapi_plugin_base_pad_get_input_buffer (plugin, plugin->sinkpad, + inbuf, outbuf_ptr); +} + +/** + * gst_vaapi_plugin_base_set_gl_context: + * @plugin: a #GstVaapiPluginBase + * @object: the new GL context from downstream + * + * Registers the new GL context. The change is effective at the next + * call to gst_vaapi_plugin_base_ensure_display(), where the + * underlying display object could be re-allocated to fit the GL + * context needs + */ +void +gst_vaapi_plugin_base_set_gl_context (GstVaapiPluginBase * plugin, + GstObject * object) +{ +#if USE_GST_GL_HELPERS + GstGLContext *const gl_context = GST_GL_CONTEXT (object); + GstVaapiDisplayType display_type; + + if (plugin->gl_context == object) + return; + + gst_object_replace (&plugin->gl_context, object); + + switch (gst_gl_context_get_gl_platform (gl_context)) { +#if USE_GLX + case GST_GL_PLATFORM_GLX: + display_type = GST_VAAPI_DISPLAY_TYPE_GLX; + break; +#endif + case GST_GL_PLATFORM_EGL: +#if USE_EGL + display_type = GST_VAAPI_DISPLAY_TYPE_EGL; + break; +#endif + default: + display_type = plugin->display_type; + break; + } + GST_INFO_OBJECT (plugin, "GL context: %" GST_PTR_FORMAT, plugin->gl_context); + gst_vaapi_plugin_base_set_display_type (plugin, display_type); +#endif +} + +/** + * gst_vaapi_plugin_base_create_gl_context: + * @plugin: a #GstVaapiPluginBase + * + * It queries downstream and upstream for a #GstGLDisplay and a other + * #GstGLContext. If not found, a new #GstGLDisplay and #GstGLContext + * are created, if it is possible. + * + * Returns: (transfer full) a new created #GstGLContext or %NULL + **/ +GstObject * +gst_vaapi_plugin_base_create_gl_context (GstVaapiPluginBase * plugin) +{ +#if USE_GST_GL_HELPERS + GstGLContext *gl_other_context = NULL, *gl_context = NULL; + GstGLDisplay *gl_display = NULL; + + if (!plugin->gl_display) + return NULL; + + gl_display = (GstGLDisplay *) plugin->gl_display; + if (gst_gl_display_get_handle_type (gl_display) == GST_GL_DISPLAY_TYPE_ANY) + goto no_valid_gl_display; + gl_other_context = (GstGLContext *) plugin->gl_other_context; + + GST_INFO_OBJECT (plugin, "creating a new GstGL context"); + + GST_OBJECT_LOCK (gl_display); + do { + if (gl_context) + gst_object_unref (gl_context); + gl_context = gst_gl_display_get_gl_context_for_thread (gl_display, NULL); + if (!gl_context) { + if (!gst_gl_display_create_context (gl_display, gl_other_context, + &gl_context, NULL)) + break; + } + } while (!gst_gl_display_add_context (gl_display, gl_context)); + GST_OBJECT_UNLOCK (gl_display); + + return GST_OBJECT_CAST (gl_context); + + /* ERRORS */ +no_valid_gl_display: + { + GST_INFO_OBJECT (plugin, "No valid GL display found"); + gst_object_replace (&plugin->gl_display, NULL); + gst_object_replace (&plugin->gl_other_context, NULL); + return NULL; + } +#else + return NULL; +#endif +} + +static GArray * +extract_allowed_surface_formats (GstVaapiDisplay * display, + GArray * img_formats) +{ + guint i; + GArray *out_formats; + guint surface_chroma = 0; + GstVaapiSurface *surface = NULL; + + /* let's assume all the formats are possible to download */ + if (gst_vaapi_display_has_driver_quirks (display, + GST_VAAPI_DRIVER_QUIRK_NO_CHECK_SURFACE_PUT_IMAGE)) { + out_formats = g_array_ref (img_formats); + goto bail; + } + + out_formats = + g_array_sized_new (FALSE, FALSE, sizeof (GstVideoFormat), + img_formats->len); + if (!out_formats) + return NULL; + + for (i = 0; i < img_formats->len; i++) { + const GstVideoFormat img_format = + g_array_index (img_formats, GstVideoFormat, i); + GstVaapiImage *image; + GstVideoInfo vi; + guint img_chroma; + + if (img_format == GST_VIDEO_FORMAT_UNKNOWN) + continue; + + img_chroma = gst_vaapi_video_format_get_chroma_type (img_format); + if (img_chroma != surface_chroma) { + if (surface) + gst_vaapi_surface_unref (surface); + gst_video_info_set_format (&vi, img_format, 64, 64); + surface = gst_vaapi_surface_new_full (display, &vi, 0); + if (!surface) + continue; + surface_chroma = img_chroma; + } + + image = gst_vaapi_image_new (display, img_format, 64, 64); + if (!image) + continue; + if (gst_vaapi_surface_put_image (surface, image)) + g_array_append_val (out_formats, img_format); + gst_vaapi_image_unref (image); + } + + if (surface) + gst_vaapi_surface_unref (surface); + +bail: + if (out_formats->len == 0) { + g_array_unref (out_formats); + return NULL; + } + return out_formats; +} + +static gboolean +ensure_allowed_raw_caps (GstVaapiPluginBase * plugin) +{ + GArray *formats, *out_formats; + GstVaapiDisplay *display; + GstCaps *out_caps; + gboolean ret = FALSE; + + if (plugin->allowed_raw_caps) + return TRUE; + + out_formats = NULL; + display = gst_object_ref (plugin->display); + formats = gst_vaapi_display_get_image_formats (display); + if (!formats) + goto bail; + out_formats = extract_allowed_surface_formats (display, formats); + if (!out_formats) + goto bail; + out_caps = gst_vaapi_video_format_new_template_caps_from_list (out_formats); + if (!out_caps) + goto bail; + + gst_caps_replace (&plugin->allowed_raw_caps, out_caps); + gst_caps_unref (out_caps); + ret = TRUE; + +bail: + if (formats) + g_array_unref (formats); + if (out_formats) + g_array_unref (out_formats); + gst_object_unref (display); + + return ret; +} + +/** + * gst_vaapi_plugin_base_get_allowed_sinkpad_raw_caps: + * @plugin: a #GstVaapiPluginBase + * + * Returns the raw #GstCaps allowed by the element. + * + * Returns: the allowed raw #GstCaps or %NULL + **/ +GstCaps * +gst_vaapi_plugin_base_get_allowed_sinkpad_raw_caps (GstVaapiPluginBase * plugin) +{ + if (!ensure_allowed_raw_caps (plugin)) + return NULL; + return plugin->allowed_raw_caps; +} + +/** + * gst_vaapi_plugin_base_set_srcpad_can_dmabuf: + * @plugin: a #GstVaapiPluginBase + * @object: the GL context from gst-gl + * + * This function will determine if @object supports dmabuf + * importing on the base plugin static srcpad. + * + * Please note that the context @object should come from downstream. + **/ +void +gst_vaapi_plugin_base_set_srcpad_can_dmabuf (GstVaapiPluginBase * plugin, + GstObject * object) +{ +#if USE_EGL && USE_GST_GL_HELPERS + GstVaapiPadPrivate *srcpriv = GST_VAAPI_PAD_PRIVATE (plugin->srcpad); + GstGLContext *const gl_context = GST_GL_CONTEXT (object); + + srcpriv->can_dmabuf = + (!(gst_gl_context_get_gl_api (gl_context) & GST_GL_API_GLES1) + && gst_gl_context_check_feature (gl_context, + "EGL_EXT_image_dma_buf_import")); +#endif +} + +static void +_init_performance_debug (void) +{ +#ifndef GST_DISABLE_GST_DEBUG + static gsize _init = 0; + + if (g_once_init_enter (&_init)) { + GST_DEBUG_CATEGORY_GET (CAT_PERFORMANCE, "GST_PERFORMANCE"); + g_once_init_leave (&_init, 1); + } +#endif +} + +/** + * gst_vaapi_plugin_copy_va_buffer: + * @plugin: a #GstVaapiPluginBase + * @inbuf: a #GstBuffer with VA memory type + * @outbuf: a #GstBuffer with system allocated memory + * + * Copy @inbuf to @outbuf. This if required when downstream doesn't + * support GstVideoMeta, and since VA memory may have custom strides a + * frame copy is required. + * + * Returns: %FALSE if the copy failed, otherwise %TRUE. Also returns + * %TRUE if it is not required to do the copy + **/ +gboolean +gst_vaapi_plugin_copy_va_buffer (GstVaapiPluginBase * plugin, + GstBuffer * inbuf, GstBuffer * outbuf) +{ + GstVaapiPadPrivate *srcpriv = GST_VAAPI_PAD_PRIVATE (plugin->srcpad); + GstVideoMeta *vmeta; + GstVideoFrame src_frame, dst_frame; + gboolean success; + + if (!plugin->copy_output_frame) + return TRUE; + + /* inbuf shall have video meta */ + vmeta = gst_buffer_get_video_meta (inbuf); + if (!vmeta) + return FALSE; + + _init_performance_debug (); + GST_CAT_INFO (CAT_PERFORMANCE, "copying VA buffer to system memory buffer"); + + if (!gst_video_frame_map (&src_frame, &srcpriv->info, inbuf, GST_MAP_READ)) + return FALSE; + if (!gst_video_frame_map (&dst_frame, &srcpriv->info, outbuf, GST_MAP_WRITE)) { + gst_video_frame_unmap (&src_frame); + return FALSE; + } + success = gst_video_frame_copy (&dst_frame, &src_frame); + gst_video_frame_unmap (&dst_frame); + gst_video_frame_unmap (&src_frame); + + if (success) { + gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS + | GST_BUFFER_COPY_FLAGS, 0, -1); + } + + return success; +} diff --git a/gst/vaapi/gstvaapipluginbase.h b/gst/vaapi/gstvaapipluginbase.h new file mode 100644 index 0000000000..94aa296f25 --- /dev/null +++ b/gst/vaapi/gstvaapipluginbase.h @@ -0,0 +1,317 @@ +/* + * gstvaapipluginbase.h - Base GStreamer VA-API Plugin element + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_PLUGIN_BASE_H +#define GST_VAAPI_PLUGIN_BASE_H + +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +typedef struct _GstVaapiPluginBase GstVaapiPluginBase; +typedef struct _GstVaapiPluginBaseClass GstVaapiPluginBaseClass; +typedef struct _GstVaapiPadPrivate GstVaapiPadPrivate; + +#define GST_VAAPI_PLUGIN_BASE(plugin) \ + ((GstVaapiPluginBase *)(plugin)) +#define GST_VAAPI_PLUGIN_BASE_CLASS(plugin) \ + ((GstVaapiPluginBaseClass *)(plugin)) +#define GST_VAAPI_PLUGIN_BASE_GET_CLASS(plugin) \ + GST_VAAPI_PLUGIN_BASE_CLASS(GST_ELEMENT_GET_CLASS( \ + GST_VAAPI_PLUGIN_BASE_ELEMENT(plugin))) +#define GST_VAAPI_PLUGIN_BASE_PARENT(plugin) \ + (&GST_VAAPI_PLUGIN_BASE(plugin)->parent_instance) +#define GST_VAAPI_PLUGIN_BASE_PARENT_CLASS(plugin) \ + (&GST_VAAPI_PLUGIN_BASE_CLASS(plugin)->parent_class) +#define GST_VAAPI_PLUGIN_BASE_ELEMENT(plugin) \ + (&GST_VAAPI_PLUGIN_BASE_PARENT(plugin)->element) +#define GST_VAAPI_PLUGIN_BASE_ELEMENT_CLASS(plugin) \ + (&GST_VAAPI_PLUGIN_BASE_PARENT_CLASS(plugin)->element) +#define GST_VAAPI_PLUGIN_BASE_DECODER(plugin) \ + (&GST_VAAPI_PLUGIN_BASE_PARENT(plugin)->decoder) +#define GST_VAAPI_PLUGIN_BASE_DECODER_CLASS(plugin) \ + (&GST_VAAPI_PLUGIN_BASE_PARENT_CLASS(plugin)->decoder) +#define GST_VAAPI_PLUGIN_BASE_ENCODER(plugin) \ + (&GST_VAAPI_PLUGIN_BASE_PARENT(plugin)->encoder) +#define GST_VAAPI_PLUGIN_BASE_ENCODER_CLASS(plugin) \ + (&GST_VAAPI_PLUGIN_BASE_PARENT_CLASS(plugin)->encoder) +#define GST_VAAPI_PLUGIN_BASE_TRANSFORM(plugin) \ + (&GST_VAAPI_PLUGIN_BASE_PARENT(plugin)->transform) +#define GST_VAAPI_PLUGIN_BASE_TRANSFORM_CLASS(plugin) \ + (&GST_VAAPI_PLUGIN_BASE_PARENT_CLASS(plugin)->transform) +#define GST_VAAPI_PLUGIN_BASE_SINK(plugin) \ + (&GST_VAAPI_PLUGIN_BASE_PARENT(plugin)->sink) +#define GST_VAAPI_PLUGIN_BASE_SINK_CLASS(plugin) \ + (&GST_VAAPI_PLUGIN_BASE_PARENT_CLASS(plugin)->sink) + +#define GST_VAAPI_PLUGIN_BASE_INIT_INTERFACES \ + gst_vaapi_plugin_base_init_interfaces(g_define_type_id); + +#define GST_VAAPI_PLUGIN_BASE_SINK_PAD(plugin) \ + (GST_VAAPI_PLUGIN_BASE(plugin)->sinkpad) +#define GST_VAAPI_PLUGIN_BASE_SINK_PAD_PRIVATE(plugin) \ + (GST_VAAPI_PLUGIN_BASE(plugin)->sinkpriv) +#define GST_VAAPI_PLUGIN_BASE_SINK_PAD_CAPS(plugin) \ + (GST_VAAPI_PLUGIN_BASE_SINK_PAD_PRIVATE(plugin)->caps) +#define GST_VAAPI_PLUGIN_BASE_SINK_PAD_INFO(plugin) \ + (&GST_VAAPI_PLUGIN_BASE_SINK_PAD_PRIVATE(plugin)->info) + +#define GST_VAAPI_PLUGIN_BASE_SRC_PAD(plugin) \ + (GST_VAAPI_PLUGIN_BASE(plugin)->srcpad) +#define GST_VAAPI_PLUGIN_BASE_SRC_PAD_PRIVATE(plugin) \ + (GST_VAAPI_PLUGIN_BASE(plugin)->srcpriv) +#define GST_VAAPI_PLUGIN_BASE_SRC_PAD_CAPS(plugin) \ + (GST_VAAPI_PLUGIN_BASE_SRC_PAD_PRIVATE(plugin)->caps) +#define GST_VAAPI_PLUGIN_BASE_SRC_PAD_INFO(plugin) \ + (&GST_VAAPI_PLUGIN_BASE_SRC_PAD_PRIVATE(plugin)->info) +#define GST_VAAPI_PLUGIN_BASE_SRC_PAD_CAN_DMABUF(plugin) \ + (GST_VAAPI_PLUGIN_BASE_SRC_PAD_PRIVATE(plugin)->can_dmabuf) +#define GST_VAAPI_PLUGIN_BASE_SRC_PAD_BUFFER_POOL(plugin) \ + (GST_VAAPI_PLUGIN_BASE_SRC_PAD_PRIVATE(plugin)->buffer_pool) +#define GST_VAAPI_PLUGIN_BASE_SRC_PAD_ALLOCATOR(plugin) \ + (GST_VAAPI_PLUGIN_BASE_SRC_PAD_PRIVATE(plugin)->allocator) +#define GST_VAAPI_PLUGIN_BASE_OTHER_ALLOCATOR(plugin) \ + (GST_VAAPI_PLUGIN_BASE_SRC_PAD_PRIVATE(plugin)->other_allocator) +#define GST_VAAPI_PLUGIN_BASE_OTHER_ALLOCATOR_PARAMS(plugin) \ + (GST_VAAPI_PLUGIN_BASE_SRC_PAD_PRIVATE(plugin)->other_allocator_params) + +#define GST_VAAPI_PLUGIN_BASE_COPY_OUTPUT_FRAME(plugin) \ + (GST_VAAPI_PLUGIN_BASE(plugin)->copy_output_frame) + +#define GST_VAAPI_PLUGIN_BASE_DISPLAY(plugin) \ + (GST_VAAPI_PLUGIN_BASE(plugin)->display) +#define GST_VAAPI_PLUGIN_BASE_DISPLAY_TYPE(plugin) \ + (GST_VAAPI_PLUGIN_BASE(plugin)->display_type) +#define GST_VAAPI_PLUGIN_BASE_DISPLAY_NAME(plugin) \ + (GST_VAAPI_PLUGIN_BASE(plugin)->display_name) +#define GST_VAAPI_PLUGIN_BASE_DISPLAY_REPLACE(plugin, new_display) \ + (gst_vaapi_display_replace(&GST_VAAPI_PLUGIN_BASE_DISPLAY(plugin), \ + (new_display))) + +#define GST_VAAPI_PLUGIN_BASE_DEFINE_SET_CONTEXT(parent_class) \ + static void \ + gst_vaapi_base_set_context (GstElement * element, GstContext * context) \ + { \ + GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (element); \ + \ + gst_vaapi_plugin_base_set_context (plugin, context); \ + GST_ELEMENT_CLASS (parent_class)->set_context (element, context); \ + } + +struct _GstVaapiPadPrivate +{ + GstCaps *caps; + GstVideoInfo info; + GstBufferPool *buffer_pool; + GstAllocator *allocator; + guint buffer_size; + gboolean caps_is_raw; + + gboolean can_dmabuf; + + GstAllocator *other_allocator; + GstAllocationParams other_allocator_params; +}; + +G_GNUC_INTERNAL +GstVaapiPadPrivate * +gst_vaapi_pad_private_new (void); + +G_GNUC_INTERNAL +void +gst_vaapi_pad_private_reset (GstVaapiPadPrivate * priv); + +G_GNUC_INTERNAL +void +gst_vaapi_pad_private_finalize (GstVaapiPadPrivate * priv); + +struct _GstVaapiPluginBase +{ + /*< private >*/ + union + { + GstElement element; + GstVideoDecoder decoder; + GstVideoEncoder encoder; + GstBaseTransform transform; + GstVideoSink sink; + GstVideoAggregator aggregator; + } parent_instance; + + GstDebugCategory *debug_category; + + GstPad *sinkpad; + GstPad *srcpad; + + GstVaapiPadPrivate *sinkpriv; + GstVaapiPadPrivate *srcpriv; + + GstVaapiDisplay *display; + GstVaapiDisplayType display_type; + GstVaapiDisplayType display_type_req; + gchar *display_name; + + GstObject *gl_context; + GstObject *gl_display; + GstObject *gl_other_context; + + GstCaps *allowed_raw_caps; + + gboolean enable_direct_rendering; + gboolean copy_output_frame; +}; + +struct _GstVaapiPluginBaseClass +{ + /*< private >*/ + union + { + GstElementClass element; + GstVideoDecoderClass decoder; + GstVideoEncoderClass encoder; + GstBaseTransformClass transform; + GstVideoSinkClass sink; + GstVideoAggregatorClass aggregator; + } parent_class; + + gboolean (*has_interface) (GstVaapiPluginBase * plugin, GType type); + void (*display_changed) (GstVaapiPluginBase * plugin); + GstVaapiPadPrivate * (*get_vaapi_pad_private) (GstVaapiPluginBase * plugin, GstPad * pad); +}; + +G_GNUC_INTERNAL +void +gst_vaapi_plugin_base_init_interfaces (GType type); + +G_GNUC_INTERNAL +void +gst_vaapi_plugin_base_class_init (GstVaapiPluginBaseClass * klass); + +G_GNUC_INTERNAL +void +gst_vaapi_plugin_base_init (GstVaapiPluginBase * plugin, + GstDebugCategory * debug_category); + +G_GNUC_INTERNAL +void +gst_vaapi_plugin_base_finalize (GstVaapiPluginBase * plugin); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_plugin_base_open (GstVaapiPluginBase * plugin); + +G_GNUC_INTERNAL +void +gst_vaapi_plugin_base_close (GstVaapiPluginBase * plugin); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_plugin_base_has_display_type (GstVaapiPluginBase * plugin, + GstVaapiDisplayType display_type_req); + +G_GNUC_INTERNAL +void +gst_vaapi_plugin_base_set_display_type (GstVaapiPluginBase * plugin, + GstVaapiDisplayType display_type); + +G_GNUC_INTERNAL +void +gst_vaapi_plugin_base_set_display_name (GstVaapiPluginBase * plugin, + const gchar * display_name); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_plugin_base_ensure_display (GstVaapiPluginBase * plugin); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_plugin_base_set_caps (GstVaapiPluginBase * plugin, GstCaps * incaps, + GstCaps * outcaps); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_plugin_base_pad_set_caps (GstVaapiPluginBase *plugin, + GstPad * sinkpad, GstCaps * incaps, GstPad * srcpad, GstCaps * outcaps); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_plugin_base_propose_allocation (GstVaapiPluginBase * plugin, + GstQuery * query); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_plugin_base_pad_propose_allocation (GstVaapiPluginBase * plugin, + GstPad * sinkpad, GstQuery * query); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_plugin_base_decide_allocation (GstVaapiPluginBase * plugin, + GstQuery * query); + +G_GNUC_INTERNAL +GstFlowReturn +gst_vaapi_plugin_base_get_input_buffer (GstVaapiPluginBase * plugin, + GstBuffer * inbuf, GstBuffer ** outbuf_ptr); + +G_GNUC_INTERNAL +GstFlowReturn +gst_vaapi_plugin_base_pad_get_input_buffer (GstVaapiPluginBase * plugin, + GstPad * sinkpad, GstBuffer * inbuf, GstBuffer ** outbuf_ptr); + +G_GNUC_INTERNAL +void +gst_vaapi_plugin_base_set_context (GstVaapiPluginBase * plugin, + GstContext * context); + +G_GNUC_INTERNAL +void +gst_vaapi_plugin_base_set_gl_context (GstVaapiPluginBase * plugin, + GstObject * object); + +G_GNUC_INTERNAL +GstObject * +gst_vaapi_plugin_base_create_gl_context (GstVaapiPluginBase * plugin); + +G_GNUC_INTERNAL +GstCaps * +gst_vaapi_plugin_base_get_allowed_sinkpad_raw_caps (GstVaapiPluginBase * plugin); + +G_GNUC_INTERNAL +void +gst_vaapi_plugin_base_set_srcpad_can_dmabuf (GstVaapiPluginBase * plugin, + GstObject * object); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_plugin_copy_va_buffer (GstVaapiPluginBase * plugin, + GstBuffer * inbuf, GstBuffer * outbuf); + + +G_END_DECLS + +#endif /* GST_VAAPI_PLUGIN_BASE_H */ diff --git a/gst/vaapi/gstvaapipluginutil.c b/gst/vaapi/gstvaapipluginutil.c new file mode 100644 index 0000000000..b98f305fc6 --- /dev/null +++ b/gst/vaapi/gstvaapipluginutil.c @@ -0,0 +1,1348 @@ +/* + * gstvaapipluginutil.h - VA-API plugin helpers + * + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * Copyright (C) 2011 Collabora + * Author: Nicolas Dufresne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gstcompat.h" +#include "gstvaapivideocontext.h" +#include +#include +#if USE_DRM +# include +#endif +#if USE_X11 +# include +#endif +#if USE_GLX +# include +#endif +#if USE_EGL +# include +#endif +#if USE_WAYLAND +# include +#endif +#if USE_GST_GL_HELPERS +# include +#if USE_EGL && GST_GL_HAVE_PLATFORM_EGL +# include +#endif +#endif +#include "gstvaapipluginutil.h" +#include "gstvaapipluginbase.h" + +/* Environment variable for disable driver white-list */ +#define GST_VAAPI_ALL_DRIVERS_ENV "GST_VAAPI_ALL_DRIVERS" + +typedef GstVaapiDisplay *(*GstVaapiDisplayCreateFunc) (const gchar *); +typedef GstVaapiDisplay *(*GstVaapiDisplayCreateFromHandleFunc) (gpointer); + +typedef struct +{ + const gchar *type_str; + GstVaapiDisplayType type; + GstVaapiDisplayCreateFunc create_display; + GstVaapiDisplayCreateFromHandleFunc create_display_from_handle; +} DisplayMap; + +/* *INDENT-OFF* */ +static const DisplayMap g_display_map[] = { +#if USE_WAYLAND + {"wayland", + GST_VAAPI_DISPLAY_TYPE_WAYLAND, + gst_vaapi_display_wayland_new, + (GstVaapiDisplayCreateFromHandleFunc) + gst_vaapi_display_wayland_new_with_display}, +#endif +#if USE_GLX + {"glx", + GST_VAAPI_DISPLAY_TYPE_GLX, + gst_vaapi_display_glx_new, + (GstVaapiDisplayCreateFromHandleFunc) + gst_vaapi_display_glx_new_with_display}, +#endif +#if USE_X11 + {"x11", + GST_VAAPI_DISPLAY_TYPE_X11, + gst_vaapi_display_x11_new, + (GstVaapiDisplayCreateFromHandleFunc) + gst_vaapi_display_x11_new_with_display}, +#endif +#if USE_DRM + {"drm", + GST_VAAPI_DISPLAY_TYPE_DRM, + gst_vaapi_display_drm_new}, +#endif + {NULL,} +}; +/* *INDENT-ON* */ + +static GstVaapiDisplay * +gst_vaapi_create_display (GstVaapiDisplayType display_type, + const gchar * display_name) +{ + GstVaapiDisplay *display = NULL; + const DisplayMap *m; + + for (m = g_display_map; m->type_str != NULL; m++) { + if (display_type != GST_VAAPI_DISPLAY_TYPE_ANY && display_type != m->type) + continue; + + display = m->create_display (display_name); + if (display || display_type != GST_VAAPI_DISPLAY_TYPE_ANY) + break; + } + return display; +} + +#if USE_GST_GL_HELPERS +static GstVaapiDisplay * +gst_vaapi_create_display_from_handle (GstVaapiDisplayType display_type, + gpointer handle) +{ + GstVaapiDisplay *display; + const DisplayMap *m; + + if (display_type == GST_VAAPI_DISPLAY_TYPE_ANY) + return NULL; + + for (m = g_display_map; m->type_str != NULL; m++) { + if (m->type == display_type) { + display = m->create_display_from_handle ? + m->create_display_from_handle (handle) : NULL; + return display; + } + } + return NULL; +} + +static GstVaapiDisplayType +gst_vaapi_get_display_type_from_gl (GstGLDisplayType gl_display_type, + GstGLPlatform gl_platform) +{ + switch (gl_display_type) { +#if USE_X11 + case GST_GL_DISPLAY_TYPE_X11:{ +#if USE_GLX + if (gl_platform == GST_GL_PLATFORM_GLX) + return GST_VAAPI_DISPLAY_TYPE_GLX; +#endif + return GST_VAAPI_DISPLAY_TYPE_X11; + } +#endif +#if USE_WAYLAND + case GST_GL_DISPLAY_TYPE_WAYLAND:{ + return GST_VAAPI_DISPLAY_TYPE_WAYLAND; + } +#endif +#if USE_EGL + case GST_GL_DISPLAY_TYPE_EGL:{ + return GST_VAAPI_DISPLAY_TYPE_EGL; + } +#endif +#if USE_DRM + case GST_GL_DISPLAY_TYPE_GBM:{ + return GST_VAAPI_DISPLAY_TYPE_DRM; + } +#endif + default: + /* unsupported display. Still DRM may work. */ + break; + } + + return GST_VAAPI_DISPLAY_TYPE_ANY; +} + +static GstVaapiDisplayType +gst_vaapi_get_display_type_from_gl_env (void) +{ + const gchar *const gl_window_type = g_getenv ("GST_GL_WINDOW"); + + if (!gl_window_type) { +#if USE_X11 && GST_GL_HAVE_WINDOW_X11 + return GST_VAAPI_DISPLAY_TYPE_X11; +#elif USE_WAYLAND && GST_GL_HAVE_WINDOW_WAYLAND + return GST_VAAPI_DISPLAY_TYPE_WAYLAND; +#elif USE_EGL && GST_GL_HAVE_PLATFORM_EGL + return GST_VAAPI_DISPLAY_TYPE_EGL; +#endif + } +#if USE_X11 + if (g_strcmp0 (gl_window_type, "x11") == 0) + return GST_VAAPI_DISPLAY_TYPE_X11; +#endif +#if USE_WAYLAND + if (g_strcmp0 (gl_window_type, "wayland") == 0) + return GST_VAAPI_DISPLAY_TYPE_WAYLAND; +#endif +#if USE_EGL + { + const gchar *const gl_platform_type = g_getenv ("GST_GL_PLATFORM"); + if (g_strcmp0 (gl_platform_type, "egl") == 0) + return GST_VAAPI_DISPLAY_TYPE_EGL; + } +#endif + + return GST_VAAPI_DISPLAY_TYPE_ANY; +} + +#if USE_EGL +static gint +gst_vaapi_get_gles_version_from_gl_api (GstGLAPI gl_api) +{ + switch (gl_api) { + case GST_GL_API_GLES1: + return 1; + case GST_GL_API_GLES2: + return 2; + case GST_GL_API_OPENGL: + case GST_GL_API_OPENGL3: + return 0; + default: + break; + } + return -1; +} + +static guintptr +gst_vaapi_get_egl_handle_from_gl_display (GstGLDisplay * gl_display) +{ + guintptr egl_handle = 0; + GstGLDisplayEGL *egl_display; + + egl_display = gst_gl_display_egl_from_gl_display (gl_display); + if (egl_display) { + egl_handle = gst_gl_display_get_handle (GST_GL_DISPLAY (egl_display)); + gst_object_unref (egl_display); + } + return egl_handle; +} +#endif /* USE_EGL */ + +static GstVaapiDisplay * +gst_vaapi_create_display_from_egl (GstGLDisplay * gl_display, + GstGLContext * gl_context, GstVaapiDisplayType display_type, + gpointer native_display) +{ + GstVaapiDisplay *display = NULL; +#if USE_EGL + GstGLAPI gl_api; + gint gles_version; + guintptr egl_handler; + + gl_api = gst_gl_context_get_gl_api (gl_context); + gles_version = gst_vaapi_get_gles_version_from_gl_api (gl_api); + if (gles_version == -1) + return NULL; + + egl_handler = gst_vaapi_get_egl_handle_from_gl_display (gl_display); + if (egl_handler != 0) { + gpointer native_display_egl = GSIZE_TO_POINTER (egl_handler); + display = gst_vaapi_display_egl_new_with_native_display (native_display_egl, + display_type, gles_version); + } + + if (!display) { + GstVaapiDisplay *wrapped_display; + + wrapped_display = + gst_vaapi_create_display_from_handle (display_type, native_display); + if (wrapped_display) { + display = gst_vaapi_display_egl_new (wrapped_display, gles_version); + gst_object_unref (wrapped_display); + } + } + + if (display) { + gst_vaapi_display_egl_set_gl_context (GST_VAAPI_DISPLAY_EGL (display), + GSIZE_TO_POINTER (gst_gl_context_get_gl_context (gl_context))); + } +#endif + return display; +} +#endif /* USE_GST_GL_HELPERS */ + +static GstVaapiDisplay * +gst_vaapi_create_display_from_gl_context (GstObject * gl_context_object) +{ +#if USE_GST_GL_HELPERS + GstGLContext *const gl_context = GST_GL_CONTEXT (gl_context_object); + GstGLDisplay *const gl_display = gst_gl_context_get_display (gl_context); + GstGLDisplayType gl_display_type; + GstGLPlatform gl_platform; + gpointer native_display; + GstVaapiDisplay *display = NULL; + GstVaapiDisplayType display_type; + + /* Get display type and the native hanler */ + gl_display_type = gst_gl_display_get_handle_type (gl_display); + gl_platform = gst_gl_context_get_gl_platform (gl_context); + display_type = + gst_vaapi_get_display_type_from_gl (gl_display_type, gl_platform); + + native_display = GSIZE_TO_POINTER (gst_gl_display_get_handle (gl_display)); + + if (display_type == GST_VAAPI_DISPLAY_TYPE_ANY) { + /* derive type and native_display from the active window */ + GstGLWindow *const gl_window = gst_gl_context_get_window (gl_context); + if (gl_window) + native_display = GSIZE_TO_POINTER (gst_gl_window_get_display (gl_window)); + display_type = gst_vaapi_get_display_type_from_gl_env (); + } + + if (gl_platform == GST_GL_PLATFORM_EGL) { + display = gst_vaapi_create_display_from_egl (gl_display, gl_context, + display_type, native_display); + } + + /* Non-EGL and fallback */ + if (!display) { + display = + gst_vaapi_create_display_from_handle (display_type, native_display); + } + + gst_object_unref (gl_display); + + return display; +#endif + GST_ERROR ("No GstGL support"); + return NULL; +} + +static void +gst_vaapi_find_gl_context (GstElement * element) +{ +#if USE_GST_GL_HELPERS + GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (element); + + /* if the element is vaapisink or any vaapi encoder it doesn't need + * to know a GstGLContext in order to create an appropriate + * GstVaapiDisplay. Let's them to choose their own + * GstVaapiDisplay */ + if (GST_IS_VIDEO_SINK (element) || GST_IS_VIDEO_ENCODER (element)) + return; + + if (!gst_gl_ensure_element_data (plugin, + (GstGLDisplay **) & plugin->gl_display, + (GstGLContext **) & plugin->gl_other_context)) + goto no_valid_gl_display; + + gst_vaapi_find_gl_local_context (element, &plugin->gl_context); + + if (plugin->gl_context) { + gst_vaapi_plugin_base_set_srcpad_can_dmabuf (plugin, plugin->gl_context); + } else { + GstObject *gl_context; + + gl_context = gst_vaapi_plugin_base_create_gl_context (plugin); + if (gl_context) { + gst_vaapi_plugin_base_set_gl_context (plugin, gl_context); + gst_object_unref (gl_context); + } + } + + /* ERRORS */ +no_valid_gl_display: + { + GST_INFO_OBJECT (plugin, "No valid GL display found"); + gst_object_replace (&plugin->gl_display, NULL); + gst_object_replace (&plugin->gl_other_context, NULL); + return; + } +#endif +} + +gboolean +gst_vaapi_ensure_display (GstElement * element, GstVaapiDisplayType type) +{ + GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (element); + GstVaapiDisplay *display = NULL; + + g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); + + if (gst_vaapi_video_context_prepare (element, &plugin->display)) { + /* Neighbour found and it updated the display */ + if (gst_vaapi_plugin_base_has_display_type (plugin, type)) + return TRUE; + } + + /* Query for a local GstGL context. If it's found, it will be used + * to create the VA display */ + if (!plugin->gl_context) + gst_vaapi_find_gl_context (element); + + /* If no neighboor, or application not interested, use system default */ + if (plugin->gl_context) { + display = gst_vaapi_create_display_from_gl_context (plugin->gl_context); + /* Cannot instantiate VA display based on GL context. Reset the + * requested display type to ANY to try again */ + if (!display) + gst_vaapi_plugin_base_set_display_type (plugin, + GST_VAAPI_DISPLAY_TYPE_ANY); + } + if (!display) + display = gst_vaapi_create_display (type, plugin->display_name); + if (!display) + return FALSE; + + gst_vaapi_video_context_propagate (element, display); + gst_object_unref (display); + return TRUE; +} + +gboolean +gst_vaapi_handle_context_query (GstElement * element, GstQuery * query) +{ + GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (element); + const gchar *type = NULL; + GstContext *context, *old_context; + + g_return_val_if_fail (query != NULL, FALSE); + +#if USE_GST_GL_HELPERS + if (plugin->gl_display && plugin->gl_context && plugin->gl_other_context) { + if (gst_gl_handle_context_query (element, query, + (GstGLDisplay *) plugin->gl_display, + (GstGLContext *) plugin->gl_context, + (GstGLContext *) plugin->gl_other_context)) + return TRUE; + } +#endif + + if (!plugin->display) + return FALSE; + + if (!gst_query_parse_context_type (query, &type)) + return FALSE; + + if (g_strcmp0 (type, GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME)) + return FALSE; + + gst_query_parse_context (query, &old_context); + if (old_context) { + context = gst_context_copy (old_context); + gst_vaapi_video_context_set_display (context, plugin->display); + } else { + context = gst_vaapi_video_context_new_with_display (plugin->display, FALSE); + } + + gst_query_set_context (query, context); + gst_context_unref (context); + + return TRUE; +} + +gboolean +gst_vaapi_append_surface_caps (GstCaps * out_caps, GstCaps * in_caps) +{ + GstStructure *structure; + const GValue *v_width, *v_height, *v_framerate, *v_par; + guint i, n_structures; + + structure = gst_caps_get_structure (in_caps, 0); + v_width = gst_structure_get_value (structure, "width"); + v_height = gst_structure_get_value (structure, "height"); + v_framerate = gst_structure_get_value (structure, "framerate"); + v_par = gst_structure_get_value (structure, "pixel-aspect-ratio"); + if (!v_width || !v_height) + return FALSE; + + n_structures = gst_caps_get_size (out_caps); + for (i = 0; i < n_structures; i++) { + structure = gst_caps_get_structure (out_caps, i); + gst_structure_set_value (structure, "width", v_width); + gst_structure_set_value (structure, "height", v_height); + if (v_framerate) + gst_structure_set_value (structure, "framerate", v_framerate); + if (v_par) + gst_structure_set_value (structure, "pixel-aspect-ratio", v_par); + } + return TRUE; +} + +gboolean +gst_vaapi_apply_composition (GstVaapiSurface * surface, GstBuffer * buffer) +{ + GstVideoOverlayCompositionMeta *const cmeta = + gst_buffer_get_video_overlay_composition_meta (buffer); + GstVideoOverlayComposition *composition = NULL; + + if (cmeta) + composition = cmeta->overlay; + return gst_vaapi_surface_set_subpictures_from_composition (surface, + composition); +} + +gboolean +gst_vaapi_value_set_format (GValue * value, GstVideoFormat format) +{ + const gchar *str; + + str = gst_video_format_to_string (format); + if (!str) + return FALSE; + + g_value_init (value, G_TYPE_STRING); + g_value_set_string (value, str); + return TRUE; +} + +gboolean +gst_vaapi_value_set_format_list (GValue * value, GArray * formats) +{ + GValue v_format = G_VALUE_INIT; + guint i; + + g_value_init (value, GST_TYPE_LIST); + for (i = 0; i < formats->len; i++) { + GstVideoFormat const format = g_array_index (formats, GstVideoFormat, i); + + if (!gst_vaapi_value_set_format (&v_format, format)) + continue; + gst_value_list_append_value (value, &v_format); + g_value_unset (&v_format); + } + return TRUE; +} + +static void +set_video_template_caps (GstCaps * caps) +{ + GstStructure *const structure = gst_caps_get_structure (caps, 0); + + gst_structure_set (structure, + "width", GST_TYPE_INT_RANGE, 1, G_MAXINT, + "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); +} + +GstCaps * +gst_vaapi_video_format_new_template_caps (GstVideoFormat format) +{ + GstCaps *caps; + + g_return_val_if_fail (format != GST_VIDEO_FORMAT_UNKNOWN, NULL); + + caps = gst_caps_new_empty_simple ("video/x-raw"); + if (!caps) + return NULL; + + gst_caps_set_simple (caps, + "format", G_TYPE_STRING, gst_video_format_to_string (format), NULL); + set_video_template_caps (caps); + return caps; +} + +GstCaps * +gst_vaapi_video_format_new_template_caps_from_list (GArray * formats) +{ + GValue v_formats = G_VALUE_INIT; + GstCaps *caps; + + caps = gst_caps_new_empty_simple ("video/x-raw"); + if (!caps) + return NULL; + + if (!gst_vaapi_value_set_format_list (&v_formats, formats)) { + gst_caps_unref (caps); + return NULL; + } + + gst_caps_set_value (caps, "format", &v_formats); + set_video_template_caps (caps); + g_value_unset (&v_formats); + return caps; +} + +GstCaps * +gst_vaapi_video_format_new_template_caps_with_features (GstVideoFormat format, + const gchar * features_string) +{ + GstCapsFeatures *features; + GstCaps *caps; + + caps = gst_vaapi_video_format_new_template_caps (format); + if (!caps) + return NULL; + + features = gst_caps_features_new (features_string, NULL); + if (!features) { + gst_caps_unref (caps); + return NULL; + } + gst_caps_set_features (caps, 0, features); + return caps; +} + +static GstVideoFormat +gst_vaapi_find_preferred_format (const GValue * format_list, + GstVideoFormat native_format) +{ + const GValue *frmt; + GstVideoFormat out_format; + guint i; + + /* if one format, that is the one */ + if (G_VALUE_HOLDS_STRING (format_list)) + return gst_video_format_from_string (g_value_get_string (format_list)); + + if (!GST_VALUE_HOLDS_LIST (format_list)) { + GST_ERROR ("negotiated caps do not have a valid format"); + return GST_VIDEO_FORMAT_UNKNOWN; + } + + if (native_format == GST_VIDEO_FORMAT_UNKNOWN + || native_format == GST_VIDEO_FORMAT_ENCODED) { + native_format = GST_VIDEO_FORMAT_NV12; /* default VA format */ + } + + /* search our native format in the list */ + for (i = 0; i < gst_value_list_get_size (format_list); i++) { + frmt = gst_value_list_get_value (format_list, i); + out_format = gst_video_format_from_string (g_value_get_string (frmt)); + + /* GStreamer do not handle encoded formats nicely. Try the next + * one. */ + if (out_format == GST_VIDEO_FORMAT_ENCODED) + continue; + + if (native_format == out_format) + return out_format; + } + + /* just pick the first valid format in the list */ + i = 0; + do { + frmt = gst_value_list_get_value (format_list, i++); + out_format = gst_video_format_from_string (g_value_get_string (frmt)); + } while (out_format == GST_VIDEO_FORMAT_ENCODED); + + return out_format; +} + +GstVaapiCapsFeature +gst_vaapi_find_preferred_caps_feature (GstPad * pad, GstCaps * allowed_caps, + GstVideoFormat * out_format_ptr) +{ + GstVaapiCapsFeature feature = GST_VAAPI_CAPS_FEATURE_NOT_NEGOTIATED; + guint i, j, num_structures; + GstCaps *peer_caps, *out_caps = NULL, *caps = NULL; + static const guint feature_list[] = { GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE, + GST_VAAPI_CAPS_FEATURE_DMABUF, + GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META, + GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY, + }; + + /* query with no filter */ + peer_caps = gst_pad_peer_query_caps (pad, NULL); + if (!peer_caps) + goto cleanup; + if (gst_caps_is_empty (peer_caps)) + goto cleanup; + + /* filter against our allowed caps */ + out_caps = gst_caps_intersect_full (allowed_caps, peer_caps, + GST_CAPS_INTERSECT_FIRST); + + /* default feature */ + feature = GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY; + + /* if downstream requests caps ANY, system memory is preferred */ + if (gst_caps_is_any (peer_caps)) + goto find_format; + + num_structures = gst_caps_get_size (out_caps); + for (i = 0; i < num_structures; i++) { + GstCapsFeatures *const features = gst_caps_get_features (out_caps, i); + GstStructure *const structure = gst_caps_get_structure (out_caps, i); + + /* Skip ANY features, we need an exact match for correct evaluation */ + if (gst_caps_features_is_any (features)) + continue; + + gst_caps_replace (&caps, NULL); + caps = gst_caps_new_full (gst_structure_copy (structure), NULL); + if (!caps) + continue; + gst_caps_set_features_simple (caps, gst_caps_features_copy (features)); + + for (j = 0; j < G_N_ELEMENTS (feature_list); j++) { + if (gst_vaapi_caps_feature_contains (caps, feature_list[j]) + && feature < feature_list[j]) { + feature = feature_list[j]; + break; + } + } + + /* Stop at the first match, the caps should already be sorted out + by preference order from downstream elements */ + if (feature != GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY) + break; + } + +find_format: + if (!caps) + caps = gst_caps_ref (out_caps); + + if (out_format_ptr) { + GstVideoFormat out_format; + GstStructure *structure = NULL; + const GValue *format_list; + + num_structures = gst_caps_get_size (caps); + for (i = 0; i < num_structures; i++) { + GstCapsFeatures *const features = gst_caps_get_features (caps, i); + if (gst_caps_features_contains (features, + gst_vaapi_caps_feature_to_string (feature))) { + structure = gst_caps_get_structure (caps, i); + break; + } + } + if (!structure) + goto cleanup; + format_list = gst_structure_get_value (structure, "format"); + if (!format_list) + goto cleanup; + out_format = gst_vaapi_find_preferred_format (format_list, *out_format_ptr); + if (out_format == GST_VIDEO_FORMAT_UNKNOWN) + goto cleanup; + + *out_format_ptr = out_format; + } + +cleanup: + gst_caps_replace (&caps, NULL); + gst_caps_replace (&out_caps, NULL); + gst_caps_replace (&peer_caps, NULL); + return feature; +} + +const gchar * +gst_vaapi_caps_feature_to_string (GstVaapiCapsFeature feature) +{ + const gchar *str; + + switch (feature) { + case GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY: + str = GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY; + break; + case GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META: + str = GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META; + break; + case GST_VAAPI_CAPS_FEATURE_DMABUF: + str = GST_CAPS_FEATURE_MEMORY_DMABUF; + break; + case GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE: + str = GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE; + break; + default: + str = NULL; + break; + } + return str; +} + +gboolean +gst_caps_set_interlaced (GstCaps * caps, GstVideoInfo * vip) +{ + GstVideoInterlaceMode mode; + const gchar *mode_str; + + mode = vip ? GST_VIDEO_INFO_INTERLACE_MODE (vip) : + GST_VIDEO_INTERLACE_MODE_PROGRESSIVE; + switch (mode) { + case GST_VIDEO_INTERLACE_MODE_PROGRESSIVE: + mode_str = "progressive"; + break; + case GST_VIDEO_INTERLACE_MODE_INTERLEAVED: + mode_str = "interleaved"; + break; + case GST_VIDEO_INTERLACE_MODE_MIXED: + mode_str = "mixed"; + break; + default: + GST_ERROR ("unsupported `interlace-mode' %d", mode); + return FALSE; + } + + gst_caps_set_simple (caps, "interlace-mode", G_TYPE_STRING, mode_str, NULL); + return TRUE; +} + +static gboolean +_gst_caps_has_feature (const GstCaps * caps, const gchar * feature) +{ + guint i; + + for (i = 0; i < gst_caps_get_size (caps); i++) { + GstCapsFeatures *const features = gst_caps_get_features (caps, i); + /* Skip ANY features, we need an exact match for correct evaluation */ + if (gst_caps_features_is_any (features)) + continue; + if (gst_caps_features_contains (features, feature)) + return TRUE; + } + + return FALSE; +} + +gboolean +gst_vaapi_caps_feature_contains (const GstCaps * caps, + GstVaapiCapsFeature feature) +{ + const gchar *feature_str; + + g_return_val_if_fail (caps != NULL, FALSE); + + feature_str = gst_vaapi_caps_feature_to_string (feature); + if (!feature_str) + return FALSE; + + return _gst_caps_has_feature (caps, feature_str); +} + +/* Checks whether the supplied caps contain VA surfaces */ +gboolean +gst_caps_has_vaapi_surface (GstCaps * caps) +{ + g_return_val_if_fail (caps != NULL, FALSE); + + return _gst_caps_has_feature (caps, GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE); +} + +gboolean +gst_caps_is_video_raw (GstCaps * caps) +{ + GstStructure *structure; + + g_return_val_if_fail (caps != NULL, FALSE); + + if (!gst_caps_is_fixed (caps)) + return FALSE; + if (!_gst_caps_has_feature (caps, GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY)) + return FALSE; + structure = gst_caps_get_structure (caps, 0); + return gst_structure_has_name (structure, "video/x-raw"); +} + +void +gst_video_info_change_format (GstVideoInfo * vip, GstVideoFormat format, + guint width, guint height) +{ + GstVideoInfo vi = *vip; + + gst_video_info_set_format (vip, format, width, height); + + GST_VIDEO_INFO_INTERLACE_MODE (vip) = GST_VIDEO_INFO_INTERLACE_MODE (&vi); + GST_VIDEO_FORMAT_INFO_FLAGS (vip) = GST_VIDEO_FORMAT_INFO_FLAGS (&vi); + GST_VIDEO_INFO_VIEWS (vip) = GST_VIDEO_INFO_VIEWS (&vi); + GST_VIDEO_INFO_PAR_N (vip) = GST_VIDEO_INFO_PAR_N (&vi); + GST_VIDEO_INFO_PAR_D (vip) = GST_VIDEO_INFO_PAR_D (&vi); + GST_VIDEO_INFO_FPS_N (vip) = GST_VIDEO_INFO_FPS_N (&vi); + GST_VIDEO_INFO_FPS_D (vip) = GST_VIDEO_INFO_FPS_D (&vi); + GST_VIDEO_INFO_MULTIVIEW_MODE (vip) = GST_VIDEO_INFO_MULTIVIEW_MODE (&vi); + GST_VIDEO_INFO_MULTIVIEW_FLAGS (vip) = GST_VIDEO_INFO_MULTIVIEW_FLAGS (&vi); +} + +/** + * gst_video_info_changed: + * @old: old #GstVideoInfo + * @new: new #GstVideoInfo + * + * Compares @old and @new + * + * Returns: %TRUE if @old has different format/width/height than + * @new. Otherwise, %FALSE. + **/ +gboolean +gst_video_info_changed (const GstVideoInfo * old, const GstVideoInfo * new) +{ + if (GST_VIDEO_INFO_FORMAT (old) != GST_VIDEO_INFO_FORMAT (new)) + return TRUE; + if (GST_VIDEO_INFO_WIDTH (old) != GST_VIDEO_INFO_WIDTH (new)) + return TRUE; + if (GST_VIDEO_INFO_HEIGHT (old) != GST_VIDEO_INFO_HEIGHT (new)) + return TRUE; + return FALSE; +} + +/** + * gst_video_info_force_nv12_if_encoded: + * @vinfo: a #GstVideoInfo + * + * If the format of @vinfo is %GST_VIDEO_FORMAT_ENCODED it is changed + * to %GST_VIDEO_FORMAT_NV12. + **/ +void +gst_video_info_force_nv12_if_encoded (GstVideoInfo * vinfo) +{ + if (GST_VIDEO_INFO_FORMAT (vinfo) != GST_VIDEO_FORMAT_ENCODED) + return; + gst_video_info_set_format (vinfo, GST_VIDEO_FORMAT_NV12, + GST_VIDEO_INFO_WIDTH (vinfo), GST_VIDEO_INFO_HEIGHT (vinfo)); +} + +/** + * gst_vaapi_create_test_display: + * + * Creates a temporal #GstVaapiDisplay instance, just for testing the + * supported features. + * + * Returns: a new #GstVaapiDisplay instances. Free with + * gst_object_unref () after use. Or %NULL if no VA display is + * available. + **/ +GstVaapiDisplay * +gst_vaapi_create_test_display (void) +{ + guint i; + GstVaapiDisplay *display = NULL; + const GstVaapiDisplayType test_display_map[] = { +#if USE_DRM + GST_VAAPI_DISPLAY_TYPE_DRM, +#endif +#if USE_WAYLAND + GST_VAAPI_DISPLAY_TYPE_WAYLAND, +#endif +#if USE_X11 + GST_VAAPI_DISPLAY_TYPE_X11, +#endif + }; + + for (i = 0; i < G_N_ELEMENTS (test_display_map); i++) { + display = gst_vaapi_create_display (test_display_map[i], NULL); + if (display) + break; + } + return display; +} + +/** + * gst_vaapi_driver_is_whitelisted: + * @display: a #GstVaapiDisplay + * + * Looks the VA-API driver vendors in an internal white-list. + * + * Returns: %TRUE if driver is in the white-list, otherwise %FALSE + **/ +gboolean +gst_vaapi_driver_is_whitelisted (GstVaapiDisplay * display) +{ + const gchar *vendor; + guint i; + static const gchar *whitelist[] = { + "Intel i965 driver", + "Intel iHD driver", + "Mesa Gallium driver", + NULL + }; + + g_return_val_if_fail (display, FALSE); + + if (g_getenv (GST_VAAPI_ALL_DRIVERS_ENV)) + return TRUE; + + vendor = gst_vaapi_display_get_vendor_string (display); + if (!vendor) + goto no_vendor; + + for (i = 0; whitelist[i]; i++) { + if (g_ascii_strncasecmp (vendor, whitelist[i], strlen (whitelist[i])) == 0) + return TRUE; + } + + GST_WARNING ("Unsupported VA driver: %s. Export environment variable " + GST_VAAPI_ALL_DRIVERS_ENV " to bypass", vendor); + return FALSE; + + /* ERRORS */ +no_vendor: + { + GST_WARNING ("no VA-API driver vendor description"); + return FALSE; + } +} + +/** + * gst_vaapi_codecs_has_codec: + * @codecs: a #GArray of #GstVaapiCodec + * @codec: a #GstVaapiCodec to find in @codec + * + * Search in the available @codecs for the specific @codec. + * + * Returns: %TRUE if @codec is in @codecs + **/ +gboolean +gst_vaapi_codecs_has_codec (GArray * codecs, GstVaapiCodec codec) +{ + guint i; + GstVaapiCodec c; + + g_return_val_if_fail (codec, FALSE); + + for (i = 0; i < codecs->len; i++) { + c = g_array_index (codecs, GstVaapiCodec, i); + if (c == codec) + return TRUE; + } + return FALSE; +} + +/** + * gst_vaapi_encoder_get_profiles_from_caps: + * @caps: a #GstCaps to detect + * @func: a #GstVaapiStrToProfileFunc + * + * This function will detect all profile strings in @caps and + * return the according GstVaapiProfile in array. + * + * Return: A #GArray of @GstVaapiProfile if succeed, %NULL if fail. + **/ +GArray * +gst_vaapi_encoder_get_profiles_from_caps (GstCaps * caps, + GstVaapiStrToProfileFunc func) +{ + guint i, j; + GstVaapiProfile profile; + GArray *profiles = NULL; + + if (!caps) + return NULL; + + profiles = g_array_new (FALSE, FALSE, sizeof (GstVaapiProfile)); + if (!profiles) + return NULL; + + for (i = 0; i < gst_caps_get_size (caps); i++) { + GstStructure *const structure = gst_caps_get_structure (caps, i); + const GValue *const value = gst_structure_get_value (structure, "profile"); + + if (value && G_VALUE_HOLDS_STRING (value)) { + const gchar *str = g_value_get_string (value); + if (str) { + profile = func (str); + if (profile == GST_VAAPI_PROFILE_H264_BASELINE) + profile = GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE; + if (profile != GST_VAAPI_PROFILE_UNKNOWN) + g_array_append_val (profiles, profile); + } + } else if (value && GST_VALUE_HOLDS_LIST (value)) { + const GValue *v; + const gchar *str; + for (j = 0; j < gst_value_list_get_size (value); j++) { + v = gst_value_list_get_value (value, j); + if (!v || !G_VALUE_HOLDS_STRING (v)) + continue; + + str = g_value_get_string (v); + if (str) { + profile = func (str); + if (profile != GST_VAAPI_PROFILE_UNKNOWN) + g_array_append_val (profiles, profile); + } + } + } + } + + if (profiles->len == 0) { + g_array_unref (profiles); + profiles = NULL; + } + + return profiles; +} + +void +gst_vaapi_caps_set_width_and_height_range (GstCaps * caps, gint min_width, + gint min_height, gint max_width, gint max_height) +{ + guint size, i; + GstStructure *structure; + + /* Set the width/height info to caps */ + size = gst_caps_get_size (caps); + for (i = 0; i < size; i++) { + structure = gst_caps_get_structure (caps, i); + if (!structure) + continue; + gst_structure_set (structure, "width", GST_TYPE_INT_RANGE, min_width, + max_width, "height", GST_TYPE_INT_RANGE, min_height, max_height, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); + } +} + +/** + * gst_vaapi_build_caps_from_formats: + * @formats: an array of supported #GstVideoFormat + * @min_width: the min supported width + * @min_height: the min supported height + * @max_width: the max supported width + * @max_height: the max supported height + * @mem_types: the supported VA mem types + * + * This function generates a #GstCaps based on the information such as + * formats, width and height. + * + * Return: A #GstCaps. + **/ +GstCaps * +gst_vaapi_build_caps_from_formats (GArray * formats, gint min_width, + gint min_height, gint max_width, gint max_height, guint mem_types) +{ + GstCaps *out_caps, *raw_caps, *va_caps, *dma_caps; + + dma_caps = NULL; + + raw_caps = gst_vaapi_video_format_new_template_caps_from_list (formats); + if (!raw_caps) + return NULL; + gst_vaapi_caps_set_width_and_height_range (raw_caps, min_width, min_height, + max_width, max_height); + + va_caps = gst_caps_copy (raw_caps); + gst_caps_set_features_simple (va_caps, + gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE)); + + if (gst_vaapi_mem_type_supports (mem_types, + GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF)) { + dma_caps = gst_caps_copy (raw_caps); + gst_caps_set_features_simple (dma_caps, + gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_DMABUF)); + } + + out_caps = va_caps; + if (dma_caps) + gst_caps_append (out_caps, dma_caps); + gst_caps_append (out_caps, raw_caps); + + return out_caps; +} + +/** + * gst_vaapi_build_template_raw_caps_by_codec: + * @display: a #GstVaapiDisplay + * @usage: used for encode, decode or postproc + * @codec: a #GstVaapiCodec specify the codec to detect + * @extra_fmts: a #GArray of extra #GstVideoFormat + * + * Called by vaapi elements to detect the all possible video formats belong to + * the specified codec and build the caps. Only YUV kinds of formats are detected + * because so far almost all codecs use YUV kinds of formats as input/output. + * extra_fmts can specified more formats to be included. + * + * Returns: a built #GstCaps if succeeds, or %NULL if error. + **/ +GstCaps * +gst_vaapi_build_template_raw_caps_by_codec (GstVaapiDisplay * display, + GstVaapiContextUsage usage, GstVaapiCodec codec, GArray * extra_fmts) +{ + GArray *profiles = NULL; + GArray *supported_fmts = NULL; + GstCaps *out_caps = NULL; + guint i, e; + GstVaapiProfile profile; + guint value; + guint chroma; + GstVaapiChromaType gst_chroma; + GstVaapiEntrypoint entrypoint_start, entrypoint_end; + + if (usage == GST_VAAPI_CONTEXT_USAGE_ENCODE) { + profiles = gst_vaapi_display_get_encode_profiles (display); + entrypoint_start = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE; + entrypoint_end = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP; + } else if (usage == GST_VAAPI_CONTEXT_USAGE_DECODE) { + profiles = gst_vaapi_display_get_decode_profiles (display); + entrypoint_start = GST_VAAPI_ENTRYPOINT_VLD; + entrypoint_end = GST_VAAPI_ENTRYPOINT_MOCO; + } + /* TODO: VPP */ + + if (!profiles) + goto out; + + chroma = 0; + for (i = 0; i < profiles->len; i++) { + profile = g_array_index (profiles, GstVaapiProfile, i); + if (gst_vaapi_profile_get_codec (profile) != codec) + continue; + + for (e = entrypoint_start; e <= entrypoint_end; e++) { + if (!gst_vaapi_get_config_attribute (display, + gst_vaapi_profile_get_va_profile (profile), + gst_vaapi_entrypoint_get_va_entrypoint (e), + VAConfigAttribRTFormat, &value)) + continue; + + chroma |= value; + } + } + + if (!chroma) + goto out; + + for (gst_chroma = GST_VAAPI_CHROMA_TYPE_YUV420; + gst_chroma <= GST_VAAPI_CHROMA_TYPE_YUV444_12BPP; gst_chroma++) { + GArray *fmts; + if (!(chroma & from_GstVaapiChromaType (gst_chroma))) + continue; + + fmts = gst_vaapi_video_format_get_formats_by_chroma (gst_chroma); + if (!fmts) + continue; + + /* One format can not belong to different chroma, no need to merge */ + if (supported_fmts == NULL) { + supported_fmts = fmts; + } else { + for (i = 0; i < fmts->len; i++) + g_array_append_val (supported_fmts, + g_array_index (fmts, GstVideoFormat, i)); + g_array_unref (fmts); + } + } + + if (!supported_fmts) + goto out; + + if (extra_fmts) { + for (i = 0; i < extra_fmts->len; i++) + g_array_append_val (supported_fmts, + g_array_index (extra_fmts, GstVideoFormat, i)); + } + + out_caps = gst_vaapi_build_caps_from_formats (supported_fmts, 1, 1, + G_MAXINT, G_MAXINT, + from_GstVaapiBufferMemoryType (GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF)); + +out: + if (profiles) + g_array_unref (profiles); + if (supported_fmts) + g_array_unref (supported_fmts); + + return out_caps; +} + +/** + * gst_vaapi_structure_set_profiles: + * @st: a #GstStructure + * @list: a %NULL-terminated array of strings + * + * The @list of profiles are set in @st + **/ +void +gst_vaapi_structure_set_profiles (GstStructure * st, gchar ** list) +{ + guint i; + GValue vlist = G_VALUE_INIT; + GValue value = G_VALUE_INIT; + + g_value_init (&vlist, GST_TYPE_LIST); + g_value_init (&value, G_TYPE_STRING); + + for (i = 0; list[i]; i++) { + g_value_set_string (&value, list[i]); + gst_value_list_append_value (&vlist, &value); + } + + if (i == 1) + gst_structure_set_value (st, "profile", &value); + else if (i > 1) + gst_structure_set_value (st, "profile", &vlist); + + g_value_unset (&value); + g_value_unset (&vlist); +} + +/** + * gst_vaapi_build_template_coded_caps_by_codec: + * @display: a #GstVaapiDisplay + * @usage: used for encode or decode + * @codec: a #GstVaapiCodec specify the codec to detect + * @caps_str: a string of basic caps + * + * Called by vaapi elements to detect the all possible profiles belong to the + * specified codec and build the caps based on the basic caps description. + * + * Returns: a built #GstCaps if succeeds, or %NULL if error. + **/ +GstCaps * +gst_vaapi_build_template_coded_caps_by_codec (GstVaapiDisplay * display, + GstVaapiContextUsage usage, GstVaapiCodec codec, const char *caps_str, + GstVaapiProfileToStrFunc func) +{ + GValue v_profiles = G_VALUE_INIT; + GValue v_profile = G_VALUE_INIT; + GstCaps *caps = NULL; + guint i, num; + GArray *profiles = NULL; + GstVaapiProfile profile; + const gchar *str; + + caps = gst_caps_from_string (caps_str); + if (!caps) + goto out; + + if (!func) + goto out; + + /* If no profiles, just ignore the profile field. */ + if (usage == GST_VAAPI_CONTEXT_USAGE_ENCODE) { + profiles = gst_vaapi_display_get_encode_profiles (display); + } else if (usage == GST_VAAPI_CONTEXT_USAGE_DECODE) { + profiles = gst_vaapi_display_get_decode_profiles (display); + } + if (!profiles || profiles->len == 0) + goto out; + + num = 0; + g_value_init (&v_profiles, GST_TYPE_LIST); + g_value_init (&v_profile, G_TYPE_STRING); + + for (i = 0; i < profiles->len; i++) { + profile = g_array_index (profiles, GstVaapiProfile, i); + if (gst_vaapi_profile_get_codec (profile) != codec) + continue; + + str = func (profile); + if (!str) + continue; + + g_value_set_string (&v_profile, str); + num++; + gst_value_list_append_value (&v_profiles, &v_profile); + } + + if (num == 1) { + gst_caps_set_value (caps, "profile", &v_profile); + } else if (num > 1) { + gst_caps_set_value (caps, "profile", &v_profiles); + } + +out: + g_value_unset (&v_profile); + g_value_unset (&v_profiles); + if (profiles) + g_array_unref (profiles); + + return caps; +} diff --git a/gst/vaapi/gstvaapipluginutil.h b/gst/vaapi/gstvaapipluginutil.h new file mode 100644 index 0000000000..236ccd3a0e --- /dev/null +++ b/gst/vaapi/gstvaapipluginutil.h @@ -0,0 +1,189 @@ +/* + * gstvaapipluginutil.h - VA-API plugins private helper + * + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * Copyright (C) 2011 Collabora + * Author: Nicolas Dufresne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_PLUGIN_UTIL_H +#define GST_VAAPI_PLUGIN_UTIL_H + +#include +#include +#include +#include "gstvaapivideomemory.h" + +typedef GstVaapiProfile (*GstVaapiStrToProfileFunc) (const gchar * str); +typedef const gchar * (*GstVaapiProfileToStrFunc) (GstVaapiProfile profile); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_ensure_display (GstElement * element, GstVaapiDisplayType type); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_handle_context_query (GstElement * element, GstQuery * query); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_append_surface_caps (GstCaps * out_caps, GstCaps * in_caps); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_apply_composition (GstVaapiSurface * surface, GstBuffer * buffer); + +#ifndef G_PRIMITIVE_SWAP +#define G_PRIMITIVE_SWAP(type, a, b) do { \ + const type t = a; a = b; b = t; \ + } while (0) +#endif + +/* Helpers for GValue construction for video formats */ +G_GNUC_INTERNAL +gboolean +gst_vaapi_value_set_format (GValue * value, GstVideoFormat format); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_value_set_format_list (GValue * value, GArray * formats); + +/* Helpers to build video caps */ +typedef enum +{ + GST_VAAPI_CAPS_FEATURE_NOT_NEGOTIATED, + GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY, + GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META, + GST_VAAPI_CAPS_FEATURE_DMABUF, + GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE, +} GstVaapiCapsFeature; + +G_GNUC_INTERNAL +GstCaps * +gst_vaapi_video_format_new_template_caps (GstVideoFormat format); + +G_GNUC_INTERNAL +GstCaps * +gst_vaapi_video_format_new_template_caps_from_list (GArray * formats); + +G_GNUC_INTERNAL +GstCaps * +gst_vaapi_video_format_new_template_caps_with_features (GstVideoFormat format, + const gchar * features_string); + +G_GNUC_INTERNAL +GstVaapiCapsFeature +gst_vaapi_find_preferred_caps_feature (GstPad * pad, GstCaps * allowed_caps, + GstVideoFormat * out_format_ptr); + +G_GNUC_INTERNAL +const gchar * +gst_vaapi_caps_feature_to_string (GstVaapiCapsFeature feature); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_caps_feature_contains (const GstCaps * caps, + GstVaapiCapsFeature feature); + +/* Helpers to handle interlaced contents */ +# define GST_CAPS_INTERLACED_MODES \ + "interlace-mode = (string){ progressive, interleaved, mixed }" +# define GST_CAPS_INTERLACED_FALSE \ + "interlace-mode = (string)progressive" + +#define GST_VAAPI_MAKE_SURFACE_CAPS \ + GST_VIDEO_CAPS_MAKE_WITH_FEATURES( \ + GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE, GST_VAAPI_FORMATS_ALL) + +#define GST_VAAPI_MAKE_GLTEXUPLOAD_CAPS \ + GST_VIDEO_CAPS_MAKE_WITH_FEATURES( \ + GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, "{ RGBA, BGRA }") + +#define GST_VAAPI_MAKE_DMABUF_CAPS \ + GST_VIDEO_CAPS_MAKE_WITH_FEATURES( \ + GST_CAPS_FEATURE_MEMORY_DMABUF, "{ I420, YV12, RGBA }") + +G_GNUC_INTERNAL +gboolean +gst_caps_set_interlaced (GstCaps * caps, GstVideoInfo * vip); + +G_GNUC_INTERNAL +gboolean +gst_caps_has_vaapi_surface (GstCaps * caps); + +G_GNUC_INTERNAL +gboolean +gst_caps_is_video_raw (GstCaps * caps); + +G_GNUC_INTERNAL +void +gst_video_info_change_format (GstVideoInfo * vip, GstVideoFormat format, + guint width, guint height); + +G_GNUC_INTERNAL +gboolean +gst_video_info_changed (const GstVideoInfo * old, const GstVideoInfo * new); + +G_GNUC_INTERNAL +void +gst_video_info_force_nv12_if_encoded (GstVideoInfo * vinfo); + +G_GNUC_INTERNAL +GstVaapiDisplay * +gst_vaapi_create_test_display (void); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_driver_is_whitelisted (GstVaapiDisplay * display); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_codecs_has_codec (GArray * codecs, GstVaapiCodec codec); + +G_GNUC_INTERNAL +GArray * +gst_vaapi_encoder_get_profiles_from_caps (GstCaps * caps, + GstVaapiStrToProfileFunc func); + +G_GNUC_INTERNAL +void +gst_vaapi_caps_set_width_and_height_range (GstCaps * caps, gint min_width, + gint min_height, gint max_width, gint max_height); + +G_GNUC_INTERNAL +GstCaps * +gst_vaapi_build_caps_from_formats (GArray * formats, gint min_width, + gint min_height, gint max_width, gint max_height, guint mem_type); + +G_GNUC_INTERNAL +GstCaps * +gst_vaapi_build_template_raw_caps_by_codec (GstVaapiDisplay * display, + GstVaapiContextUsage usage, GstVaapiCodec codec, GArray * extra_fmts); + +G_GNUC_INTERNAL +void +gst_vaapi_structure_set_profiles (GstStructure * st, gchar ** list); + +G_GNUC_INTERNAL +GstCaps * +gst_vaapi_build_template_coded_caps_by_codec (GstVaapiDisplay * display, + GstVaapiContextUsage usage, GstVaapiCodec codec, const char *caps_str, + GstVaapiProfileToStrFunc func); + +#endif /* GST_VAAPI_PLUGIN_UTIL_H */ diff --git a/gst/vaapi/gstvaapipostproc.c b/gst/vaapi/gstvaapipostproc.c new file mode 100644 index 0000000000..052ee4fa3c --- /dev/null +++ b/gst/vaapi/gstvaapipostproc.c @@ -0,0 +1,2802 @@ +/* + * gstvaapipostproc.c - VA-API video postprocessing + * + * Copyright (C) 2012-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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-vaapipostproc + * @short_description: A VA-API base video postprocessing filter + * + * vaapipostproc consists in various postprocessing algorithms to be + * applied to VA surfaces. + * + * ## Example launch line + * + * |[ + * gst-launch-1.0 videotestsrc ! vaapipostproc ! video/x-raw, width=1920, height=1080 ! vaapisink + * ]| + */ + +#include "gstcompat.h" +#include + +#include + +#include "gstvaapipostproc.h" +#include "gstvaapipostprocutil.h" +#include "gstvaapipluginutil.h" +#include "gstvaapivideobuffer.h" +#include "gstvaapivideobufferpool.h" +#include "gstvaapivideomemory.h" + +#define GST_PLUGIN_NAME "vaapipostproc" +#define GST_PLUGIN_DESC "A VA-API video postprocessing filter" + +GST_DEBUG_CATEGORY_STATIC (gst_debug_vaapipostproc); +#ifndef GST_DISABLE_GST_DEBUG +#define GST_CAT_DEFAULT gst_debug_vaapipostproc +#else +#define GST_CAT_DEFAULT NULL +#endif + +/* Default templates */ +/* *INDENT-OFF* */ +static const char gst_vaapipostproc_sink_caps_str[] = + GST_VAAPI_MAKE_SURFACE_CAPS ", " + GST_CAPS_INTERLACED_MODES "; " + GST_VIDEO_CAPS_MAKE (GST_VAAPI_FORMATS_ALL) ", " + GST_CAPS_INTERLACED_MODES; +/* *INDENT-ON* */ + +/* *INDENT-OFF* */ +static const char gst_vaapipostproc_src_caps_str[] = + GST_VAAPI_MAKE_SURFACE_CAPS ", " + GST_CAPS_INTERLACED_FALSE "; " +#if (USE_GLX || USE_EGL) + GST_VAAPI_MAKE_GLTEXUPLOAD_CAPS "; " +#endif + GST_VIDEO_CAPS_MAKE (GST_VAAPI_FORMATS_ALL) ", " + GST_CAPS_INTERLACED_MODES "; " + GST_VAAPI_MAKE_DMABUF_CAPS; +/* *INDENT-ON* */ + +/* *INDENT-OFF* */ +static GstStaticPadTemplate gst_vaapipostproc_sink_factory = + GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (gst_vaapipostproc_sink_caps_str)); +/* *INDENT-ON* */ + +/* *INDENT-OFF* */ +static GstStaticPadTemplate gst_vaapipostproc_src_factory = + GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (gst_vaapipostproc_src_caps_str)); +/* *INDENT-ON* */ + +static void gst_vaapipostproc_colorbalance_init (gpointer iface, gpointer data); + +G_DEFINE_TYPE_WITH_CODE (GstVaapiPostproc, gst_vaapipostproc, + GST_TYPE_BASE_TRANSFORM, GST_VAAPI_PLUGIN_BASE_INIT_INTERFACES + G_IMPLEMENT_INTERFACE (GST_TYPE_COLOR_BALANCE, + gst_vaapipostproc_colorbalance_init)); + +GST_VAAPI_PLUGIN_BASE_DEFINE_SET_CONTEXT (gst_vaapipostproc_parent_class); + +static GstVideoFormat native_formats[] = + { GST_VIDEO_FORMAT_NV12, GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_I420 }; + +enum +{ + PROP_0, + +#ifndef GST_REMOVE_DEPRECATED + PROP_FORMAT, + PROP_WIDTH, + PROP_HEIGHT, +#endif + PROP_FORCE_ASPECT_RATIO, + PROP_DEINTERLACE_MODE, + PROP_DEINTERLACE_METHOD, + PROP_DENOISE, + PROP_SHARPEN, + PROP_HUE, + PROP_SATURATION, + PROP_BRIGHTNESS, + PROP_CONTRAST, + PROP_SCALE_METHOD, + PROP_VIDEO_DIRECTION, + PROP_CROP_LEFT, + PROP_CROP_RIGHT, + PROP_CROP_TOP, + PROP_CROP_BOTTOM, + PROP_HDR_TONE_MAP, +#ifndef GST_REMOVE_DEPRECATED + PROP_SKIN_TONE_ENHANCEMENT, +#endif + PROP_SKIN_TONE_ENHANCEMENT_LEVEL, +}; + +#define GST_VAAPI_TYPE_HDR_TONE_MAP \ + gst_vaapi_hdr_tone_map_get_type() + +static GType +gst_vaapi_hdr_tone_map_get_type (void) +{ + static gsize g_type = 0; + + static const GEnumValue enum_values[] = { + {GST_VAAPI_HDR_TONE_MAP_AUTO, + "Auto detection", "auto"}, + {GST_VAAPI_HDR_TONE_MAP_DISABLED, + "Disable HDR tone mapping", "disabled"}, + {0, NULL, NULL}, + }; + + if (g_once_init_enter (&g_type)) { + const GType type = + g_enum_register_static ("GstVaapiHDRToneMap", enum_values); + g_once_init_leave (&g_type, type); + } + return g_type; +} + +#define GST_VAAPI_TYPE_DEINTERLACE_MODE \ + gst_vaapi_deinterlace_mode_get_type() + +static GType +gst_vaapi_deinterlace_mode_get_type (void) +{ + static GType deinterlace_mode_type = 0; + + static const GEnumValue mode_types[] = { + {GST_VAAPI_DEINTERLACE_MODE_AUTO, + "Auto detection", "auto"}, + {GST_VAAPI_DEINTERLACE_MODE_INTERLACED, + "Force deinterlacing", "interlaced"}, + {GST_VAAPI_DEINTERLACE_MODE_DISABLED, + "Never deinterlace", "disabled"}, + {0, NULL, NULL}, + }; + + if (!deinterlace_mode_type) { + deinterlace_mode_type = + g_enum_register_static ("GstVaapiDeinterlaceMode", mode_types); + } + return deinterlace_mode_type; +} + +static void +ds_reset (GstVaapiDeinterlaceState * ds) +{ + guint i; + + for (i = 0; i < G_N_ELEMENTS (ds->buffers); i++) + gst_buffer_replace (&ds->buffers[i], NULL); + ds->buffers_index = 0; + ds->num_surfaces = 0; + ds->deint = FALSE; + ds->tff = FALSE; +} + +static void +ds_add_buffer (GstVaapiDeinterlaceState * ds, GstBuffer * buf) +{ + gst_buffer_replace (&ds->buffers[ds->buffers_index], buf); + ds->buffers_index = (ds->buffers_index + 1) % G_N_ELEMENTS (ds->buffers); +} + +static inline GstBuffer * +ds_get_buffer (GstVaapiDeinterlaceState * ds, guint index) +{ + /* Note: the index increases towards older buffers. + i.e. buffer at index 0 means the immediately preceding buffer + in the history, buffer at index 1 means the one preceding the + surface at index 0, etc. */ + const guint n = ds->buffers_index + G_N_ELEMENTS (ds->buffers) - index - 1; + return ds->buffers[n % G_N_ELEMENTS (ds->buffers)]; +} + +static void +ds_set_surfaces (GstVaapiDeinterlaceState * ds) +{ + GstVaapiVideoMeta *meta; + guint i; + + ds->num_surfaces = 0; + for (i = 0; i < G_N_ELEMENTS (ds->buffers); i++) { + GstBuffer *const buf = ds_get_buffer (ds, i); + if (!buf) + break; + + meta = gst_buffer_get_vaapi_video_meta (buf); + ds->surfaces[ds->num_surfaces++] = gst_vaapi_video_meta_get_surface (meta); + } +} + +static GstVaapiFilterOpInfo * +find_filter_op (GPtrArray * filter_ops, GstVaapiFilterOp op) +{ + guint i; + + if (filter_ops) { + for (i = 0; i < filter_ops->len; i++) { + GstVaapiFilterOpInfo *const filter_op = g_ptr_array_index (filter_ops, i); + if (filter_op->op == op) + return filter_op; + } + } + return NULL; +} + +static inline gboolean +gst_vaapipostproc_ensure_display (GstVaapiPostproc * postproc) +{ + return + gst_vaapi_plugin_base_ensure_display (GST_VAAPI_PLUGIN_BASE (postproc)); +} + +static gboolean +gst_vaapipostproc_ensure_filter (GstVaapiPostproc * postproc) +{ + if (postproc->filter) + return TRUE; + + if (!gst_vaapipostproc_ensure_display (postproc)) + return FALSE; + + gst_caps_replace (&postproc->allowed_srcpad_caps, NULL); + gst_caps_replace (&postproc->allowed_sinkpad_caps, NULL); + + postproc->filter = + gst_vaapi_filter_new (GST_VAAPI_PLUGIN_BASE_DISPLAY (postproc)); + if (!postproc->filter) + return FALSE; + return TRUE; +} + +static gboolean +gst_vaapipostproc_ensure_filter_caps (GstVaapiPostproc * postproc) +{ + if (!gst_vaapipostproc_ensure_filter (postproc)) + return FALSE; + + if (!postproc->filter_ops) { + postproc->filter_ops = gst_vaapi_filter_get_operations (postproc->filter); + if (!postproc->filter_ops) + return FALSE; + } + + if (!postproc->filter_formats) { + postproc->filter_formats = gst_vaapi_filter_get_formats (postproc->filter); + if (!postproc->filter_formats) + return FALSE; + } + return TRUE; +} + +static gboolean +gst_vaapipostproc_create (GstVaapiPostproc * postproc) +{ + if (!gst_vaapi_plugin_base_open (GST_VAAPI_PLUGIN_BASE (postproc))) + return FALSE; + if (!gst_vaapipostproc_ensure_display (postproc)) + return FALSE; + + postproc->use_vpp = FALSE; + postproc->has_vpp = gst_vaapipostproc_ensure_filter (postproc); + return TRUE; +} + +static void +gst_vaapipostproc_destroy_filter (GstVaapiPostproc * postproc) +{ + if (postproc->filter_formats) { + g_array_unref (postproc->filter_formats); + postproc->filter_formats = NULL; + } + + if (postproc->filter_ops) { + g_ptr_array_unref (postproc->filter_ops); + postproc->filter_ops = NULL; + } + if (postproc->cb_channels) { + g_list_free_full (postproc->cb_channels, g_object_unref); + postproc->cb_channels = NULL; + } + gst_vaapi_filter_replace (&postproc->filter, NULL); + gst_vaapi_video_pool_replace (&postproc->filter_pool, NULL); +} + +static void +gst_vaapipostproc_destroy (GstVaapiPostproc * postproc) +{ + ds_reset (&postproc->deinterlace_state); + gst_vaapipostproc_destroy_filter (postproc); + + gst_caps_replace (&postproc->allowed_sinkpad_caps, NULL); + gst_caps_replace (&postproc->allowed_srcpad_caps, NULL); + gst_vaapi_plugin_base_close (GST_VAAPI_PLUGIN_BASE (postproc)); +} + +static gboolean +gst_vaapipostproc_start (GstBaseTransform * trans) +{ + GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans); + + ds_reset (&postproc->deinterlace_state); + if (!gst_vaapi_plugin_base_open (GST_VAAPI_PLUGIN_BASE (postproc))) + return FALSE; + g_mutex_lock (&postproc->postproc_lock); + gst_vaapipostproc_ensure_filter (postproc); + g_mutex_unlock (&postproc->postproc_lock); + + return TRUE; +} + +static gboolean +gst_vaapipostproc_stop (GstBaseTransform * trans) +{ + GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans); + + g_mutex_lock (&postproc->postproc_lock); + ds_reset (&postproc->deinterlace_state); + gst_vaapi_plugin_base_close (GST_VAAPI_PLUGIN_BASE (postproc)); + + postproc->field_duration = GST_CLOCK_TIME_NONE; + gst_video_info_init (&postproc->sinkpad_info); + gst_video_info_init (&postproc->srcpad_info); + gst_video_info_init (&postproc->filter_pool_info); + g_mutex_unlock (&postproc->postproc_lock); + + return TRUE; +} + +static gboolean +should_deinterlace_buffer (GstVaapiPostproc * postproc, GstBuffer * buf) +{ + if (!(postproc->flags & GST_VAAPI_POSTPROC_FLAG_DEINTERLACE) || + postproc->deinterlace_mode == GST_VAAPI_DEINTERLACE_MODE_DISABLED) + return FALSE; + + if (postproc->deinterlace_mode == GST_VAAPI_DEINTERLACE_MODE_INTERLACED) + return TRUE; + + g_assert (postproc->deinterlace_mode == GST_VAAPI_DEINTERLACE_MODE_AUTO); + + switch (GST_VIDEO_INFO_INTERLACE_MODE (&postproc->sinkpad_info)) { + case GST_VIDEO_INTERLACE_MODE_INTERLEAVED: + return TRUE; + case GST_VIDEO_INTERLACE_MODE_PROGRESSIVE: + return FALSE; + case GST_VIDEO_INTERLACE_MODE_MIXED: + if (GST_BUFFER_FLAG_IS_SET (buf, GST_VIDEO_BUFFER_FLAG_INTERLACED)) + return TRUE; + break; + default: + GST_ERROR_OBJECT (postproc, + "unhandled \"interlace-mode\", disabling deinterlacing"); + break; + } + return FALSE; +} + +static GstBuffer * +create_output_buffer (GstVaapiPostproc * postproc) +{ + GstBuffer *outbuf; + + GstBufferPool *const pool = + GST_VAAPI_PLUGIN_BASE_SRC_PAD_BUFFER_POOL (postproc); + GstFlowReturn ret; + + g_return_val_if_fail (pool != NULL, NULL); + + if (!gst_buffer_pool_is_active (pool) && + !gst_buffer_pool_set_active (pool, TRUE)) + goto error_activate_pool; + + outbuf = NULL; + ret = gst_buffer_pool_acquire_buffer (pool, &outbuf, NULL); + if (ret != GST_FLOW_OK || !outbuf) + goto error_create_buffer; + return outbuf; + + /* ERRORS */ +error_activate_pool: + { + GST_ERROR_OBJECT (postproc, "failed to activate output video buffer pool"); + return NULL; + } +error_create_buffer: + { + GST_ERROR_OBJECT (postproc, "failed to create output video buffer"); + return NULL; + } +} + +static inline GstBuffer * +create_output_dump_buffer (GstVaapiPostproc * postproc) +{ + GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (postproc); + + return + gst_buffer_new_allocate (GST_VAAPI_PLUGIN_BASE_OTHER_ALLOCATOR (plugin), + GST_VIDEO_INFO_SIZE (GST_VAAPI_PLUGIN_BASE_SRC_PAD_INFO (plugin)), + &GST_VAAPI_PLUGIN_BASE_OTHER_ALLOCATOR_PARAMS (plugin)); +} + +static void +copy_metadata (GstVaapiPostproc * postproc, GstBuffer * outbuf, + GstBuffer * inbuf) +{ + GstBaseTransformClass *bclass = GST_BASE_TRANSFORM_GET_CLASS (postproc); + GstBaseTransform *trans = GST_BASE_TRANSFORM (postproc); + + if (inbuf == outbuf) + return; + if (!bclass->copy_metadata) + return; + if (!bclass->copy_metadata (trans, inbuf, outbuf)) { + /* something failed, post a warning */ + GST_ELEMENT_WARNING (trans, STREAM, NOT_IMPLEMENTED, + ("could not copy metadata"), (NULL)); + } +} + +static gboolean +append_output_buffer_metadata (GstVaapiPostproc * postproc, GstBuffer * outbuf, + GstBuffer * inbuf, guint flags) +{ + GstVaapiVideoMeta *inbuf_meta, *outbuf_meta; + GstVaapiSurfaceProxy *proxy; + + gst_buffer_copy_into (outbuf, inbuf, flags | GST_BUFFER_COPY_FLAGS, 0, -1); + + copy_metadata (postproc, outbuf, inbuf); + + /* GstVaapiVideoMeta */ + inbuf_meta = gst_buffer_get_vaapi_video_meta (inbuf); + g_return_val_if_fail (inbuf_meta != NULL, FALSE); + proxy = gst_vaapi_video_meta_get_surface_proxy (inbuf_meta); + + outbuf_meta = gst_buffer_get_vaapi_video_meta (outbuf); + g_return_val_if_fail (outbuf_meta != NULL, FALSE); + proxy = gst_vaapi_surface_proxy_copy (proxy); + if (!proxy) + return FALSE; + + gst_vaapi_video_meta_set_surface_proxy (outbuf_meta, proxy); + gst_vaapi_surface_proxy_unref (proxy); + return TRUE; +} + +static gboolean +deint_method_is_advanced (GstVaapiDeinterlaceMethod deint_method) +{ + gboolean is_advanced; + + switch (deint_method) { + case GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE: + case GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED: + is_advanced = TRUE; + break; + default: + is_advanced = FALSE; + break; + } + return is_advanced; +} + +static GstVaapiDeinterlaceMethod +get_next_deint_method (GstVaapiDeinterlaceMethod deint_method) +{ + switch (deint_method) { + case GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED: + deint_method = GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE; + break; + default: + /* Default to basic "bob" for all others */ + deint_method = GST_VAAPI_DEINTERLACE_METHOD_BOB; + break; + } + return deint_method; +} + +static gboolean +set_best_deint_method (GstVaapiPostproc * postproc, guint flags, + GstVaapiDeinterlaceMethod * deint_method_ptr) +{ + GstVaapiDeinterlaceMethod deint_method = postproc->deinterlace_method; + gboolean success; + + for (;;) { + success = gst_vaapi_filter_set_deinterlacing (postproc->filter, + deint_method, flags); + if (success || deint_method == GST_VAAPI_DEINTERLACE_METHOD_BOB) + break; + deint_method = get_next_deint_method (deint_method); + } + *deint_method_ptr = deint_method; + return success; +} + +static gboolean +should_hdr_tone_map (GstVaapiPostproc * const postproc, const GstCaps * caps) +{ + switch (postproc->hdr_tone_map) { + case GST_VAAPI_HDR_TONE_MAP_AUTO: + { + GstVideoMasteringDisplayInfo minfo; + return gst_video_mastering_display_info_from_caps (&minfo, caps); + } + case GST_VAAPI_HDR_TONE_MAP_DISABLED: + return FALSE; + default: + GST_ERROR_OBJECT (postproc, "unhandled \"hdr-tone-map\" option"); + break; + } + return FALSE; +} + +static gboolean +configure_hdr_tone_map (GstVaapiPostproc * const postproc, const GstCaps * caps) +{ + gboolean enable; + + g_return_val_if_fail (postproc->has_vpp, FALSE); + + enable = should_hdr_tone_map (postproc, caps); + + if (!gst_vaapi_filter_set_hdr_tone_map (postproc->filter, enable)) + goto fail_configure_hdr_tone_map; + + if (enable) { + GstVideoMasteringDisplayInfo minfo; + GstVideoContentLightLevel linfo; + + gst_video_mastering_display_info_from_caps (&minfo, caps); + gst_video_content_light_level_from_caps (&linfo, caps); + + if (!gst_vaapi_filter_set_hdr_tone_map_meta (postproc->filter, &minfo, + &linfo)) + goto fail_configure_hdr_tone_map; + + postproc->flags |= GST_VAAPI_POSTPROC_FLAG_HDR_TONE_MAP; + } else { + postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_HDR_TONE_MAP); + } + + return TRUE; + +fail_configure_hdr_tone_map: + { + postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_HDR_TONE_MAP); + return FALSE; + } +} + +static gboolean +check_filter_update (GstVaapiPostproc * postproc) +{ + guint filter_flag = postproc->flags; + guint op_flag; + gint i; + + if (!postproc->has_vpp) + return FALSE; + + for (i = GST_VAAPI_FILTER_OP_DENOISE; + i <= GST_VAAPI_FILTER_OP_SKINTONE_LEVEL; i++) { + op_flag = (filter_flag >> i) & 1; + if (op_flag) + return TRUE; + } + + return FALSE; +} + +static gboolean +update_filter (GstVaapiPostproc * postproc) +{ + /* Validate filters */ + if ((postproc->flags & GST_VAAPI_POSTPROC_FLAG_FORMAT) && + !gst_vaapi_filter_set_format (postproc->filter, postproc->format)) + return FALSE; + + if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_DENOISE) { + if (!gst_vaapi_filter_set_denoising_level (postproc->filter, + postproc->denoise_level)) + return FALSE; + + if (gst_vaapi_filter_get_denoising_level_default (postproc->filter) == + postproc->denoise_level) + postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_DENOISE); + } + + if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_SHARPEN) { + if (!gst_vaapi_filter_set_sharpening_level (postproc->filter, + postproc->sharpen_level)) + return FALSE; + + if (gst_vaapi_filter_get_sharpening_level_default (postproc->filter) == + postproc->sharpen_level) + postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_SHARPEN); + } + + if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_HUE) { + if (!gst_vaapi_filter_set_hue (postproc->filter, postproc->hue)) + return FALSE; + + if (gst_vaapi_filter_get_hue_default (postproc->filter) == postproc->hue) + postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_HUE); + } + + if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_SATURATION) { + if (!gst_vaapi_filter_set_saturation (postproc->filter, + postproc->saturation)) + return FALSE; + + if (gst_vaapi_filter_get_saturation_default (postproc->filter) == + postproc->saturation) + postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_SATURATION); + } + + if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_BRIGHTNESS) { + if (!gst_vaapi_filter_set_brightness (postproc->filter, + postproc->brightness)) + return FALSE; + + if (gst_vaapi_filter_get_brightness_default (postproc->filter) == + postproc->brightness) + postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_BRIGHTNESS); + } + + if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_CONTRAST) { + if (!gst_vaapi_filter_set_contrast (postproc->filter, postproc->contrast)) + return FALSE; + + if (gst_vaapi_filter_get_contrast_default (postproc->filter) == + postproc->contrast) + postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_CONTRAST); + } + + if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_SCALE) { + if (!gst_vaapi_filter_set_scaling (postproc->filter, + postproc->scale_method)) + return FALSE; + + if (gst_vaapi_filter_get_scaling_default (postproc->filter) == + postproc->scale_method) + postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_SCALE); + } + + if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_VIDEO_DIRECTION) { + GstVideoOrientationMethod method = postproc->video_direction; + if (method == GST_VIDEO_ORIENTATION_AUTO) + method = postproc->tag_video_direction; + + if (!gst_vaapi_filter_set_video_direction (postproc->filter, method)) { + GST_ELEMENT_WARNING (postproc, LIBRARY, SETTINGS, + ("Unsupported video direction '%s' by driver.", + gst_vaapi_enum_type_get_nick + (GST_TYPE_VIDEO_ORIENTATION_METHOD, method)), + ("video direction transformation ignored")); + + /* Don't return FALSE because other filters might be set */ + } + + if (gst_vaapi_filter_get_video_direction_default (postproc->filter) == + method) + postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_VIDEO_DIRECTION); + } + + if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_CROP) + if ((postproc->crop_left | postproc->crop_right | postproc->crop_top + | postproc->crop_bottom) == 0) + postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_CROP); + + if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_SKINTONE_LEVEL) { + if (!gst_vaapi_filter_set_skintone_level (postproc->filter, + postproc->skintone_value)) + return FALSE; + + if (gst_vaapi_filter_get_skintone_level_default (postproc->filter) == + postproc->skintone_value) + postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_SKINTONE_LEVEL); + +#ifndef GST_REMOVE_DEPRECATED + /* + * When use skin tone level property, disable old skin tone property always + */ + postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_SKINTONE); +#endif + } else { +#ifndef GST_REMOVE_DEPRECATED + if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_SKINTONE) { + if (!gst_vaapi_filter_set_skintone (postproc->filter, + postproc->skintone_enhance)) + return FALSE; + + if (gst_vaapi_filter_get_skintone_default (postproc->filter) == + postproc->skintone_enhance) + postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_SKINTONE); + } +#endif + } + + return TRUE; +} + +static void +gst_vaapipostproc_set_passthrough (GstBaseTransform * trans) +{ + GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans); + gboolean filter_updated = FALSE; + + if (check_filter_update (postproc) && update_filter (postproc)) { + /* check again if changed value is default */ + filter_updated = check_filter_update (postproc); + } + + gst_base_transform_set_passthrough (trans, postproc->same_caps + && !filter_updated); +} + +static gboolean +replace_to_dumb_buffer_if_required (GstVaapiPostproc * postproc, + GstBuffer ** fieldbuf) +{ + GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (postproc); + GstBuffer *newbuf; + + if (!GST_VAAPI_PLUGIN_BASE_COPY_OUTPUT_FRAME (postproc)) + return TRUE; + + newbuf = create_output_dump_buffer (postproc); + if (!newbuf) + return FALSE; + + if (!gst_vaapi_plugin_copy_va_buffer (plugin, *fieldbuf, newbuf)) { + gst_buffer_unref (newbuf); + return FALSE; + } + + gst_buffer_replace (fieldbuf, newbuf); + gst_buffer_unref (newbuf); + + return TRUE; +} + +static gboolean +use_vpp_crop (GstVaapiPostproc * postproc) +{ + return !(postproc->forward_crop + && !(postproc->flags & GST_VAAPI_POSTPROC_FLAG_CROP)); +} + +static void +rotate_crop_meta (GstVaapiPostproc * const postproc, const GstVideoMeta * vmeta, + GstVideoCropMeta * crop) +{ + guint tmp; + + g_return_if_fail (postproc->has_vpp); + + /* The video meta is required since the caps width/height are smaller, + * which would not result in a usable GstVideoInfo for mapping the + * buffer. */ + if (!vmeta || !crop) + return; + + switch (gst_vaapi_filter_get_video_direction (postproc->filter)) { + case GST_VIDEO_ORIENTATION_HORIZ: + crop->x = vmeta->width - crop->width - crop->x; + break; + case GST_VIDEO_ORIENTATION_VERT: + crop->y = vmeta->height - crop->height - crop->y; + break; + case GST_VIDEO_ORIENTATION_90R: + tmp = crop->x; + crop->x = vmeta->height - crop->height - crop->y; + crop->y = tmp; + G_PRIMITIVE_SWAP (guint, crop->width, crop->height); + break; + case GST_VIDEO_ORIENTATION_180: + crop->x = vmeta->width - crop->width - crop->x; + crop->y = vmeta->height - crop->height - crop->y; + break; + case GST_VIDEO_ORIENTATION_90L: + tmp = crop->x; + crop->x = crop->y; + crop->y = vmeta->width - crop->width - tmp; + G_PRIMITIVE_SWAP (guint, crop->width, crop->height); + break; + case GST_VIDEO_ORIENTATION_UR_LL: + tmp = crop->x; + crop->x = vmeta->height - crop->height - crop->y; + crop->y = vmeta->width - crop->width - tmp; + G_PRIMITIVE_SWAP (guint, crop->width, crop->height); + break; + case GST_VIDEO_ORIENTATION_UL_LR: + G_PRIMITIVE_SWAP (guint, crop->x, crop->y); + G_PRIMITIVE_SWAP (guint, crop->width, crop->height); + break; + default: + break; + } +} + +static GstFlowReturn +gst_vaapipostproc_process_vpp (GstBaseTransform * trans, GstBuffer * inbuf, + GstBuffer * outbuf) +{ + GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans); + GstVaapiDeinterlaceState *const ds = &postproc->deinterlace_state; + GstVaapiVideoMeta *inbuf_meta, *outbuf_meta; + GstVaapiSurface *inbuf_surface, *outbuf_surface; + GstVaapiSurfaceProxy *proxy; + GstVaapiFilterStatus status; + GstClockTime timestamp; + GstFlowReturn ret; + GstBuffer *fieldbuf; + GstVaapiDeinterlaceMethod deint_method; + guint flags, deint_flags; + gboolean tff, deint, deint_refs, deint_changed, discont; + const GstVideoCropMeta *crop_meta; + GstVaapiRectangle *crop_rect = NULL; + GstVaapiRectangle tmp_rect; + + inbuf_meta = gst_buffer_get_vaapi_video_meta (inbuf); + if (!inbuf_meta) + goto error_invalid_buffer; + inbuf_surface = gst_vaapi_video_meta_get_surface (inbuf_meta); + + if (use_vpp_crop (postproc)) { + crop_rect = &tmp_rect; + crop_rect->x = postproc->crop_left; + crop_rect->y = postproc->crop_top; + crop_rect->width = GST_VIDEO_INFO_WIDTH (&postproc->sinkpad_info) + - (postproc->crop_left + postproc->crop_right); + crop_rect->height = GST_VIDEO_INFO_HEIGHT (&postproc->sinkpad_info) + - (postproc->crop_top + postproc->crop_bottom); + + crop_meta = gst_buffer_get_video_crop_meta (inbuf); + if (crop_meta) { + crop_rect->x += crop_meta->x; + crop_rect->y += crop_meta->y; + } + } + + if (!crop_rect) + crop_rect = (GstVaapiRectangle *) + gst_vaapi_video_meta_get_render_rect (inbuf_meta); + + timestamp = GST_BUFFER_TIMESTAMP (inbuf); + tff = GST_BUFFER_FLAG_IS_SET (inbuf, GST_VIDEO_BUFFER_FLAG_TFF); + discont = GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT); + deint = should_deinterlace_buffer (postproc, inbuf); + + /* Drop references if deinterlacing conditions changed */ + deint_changed = deint != ds->deint; + if (deint_changed || (ds->num_surfaces > 0 && tff != ds->tff)) + ds_reset (ds); + + deint_method = postproc->deinterlace_method; + deint_refs = deint_method_is_advanced (deint_method); + if (deint_refs && 0) { + GstBuffer *const prev_buf = ds_get_buffer (ds, 0); + GstClockTime prev_pts, pts = GST_BUFFER_TIMESTAMP (inbuf); + /* Reset deinterlacing state when there is a discontinuity */ + if (prev_buf && (prev_pts = GST_BUFFER_TIMESTAMP (prev_buf)) != pts) { + const GstClockTimeDiff pts_diff = GST_CLOCK_DIFF (prev_pts, pts); + if (pts_diff < 0 || (postproc->field_duration > 0 && + pts_diff >= postproc->field_duration * 3 - 1)) + ds_reset (ds); + } + } + + ds->deint = deint; + ds->tff = tff; + + flags = gst_vaapi_video_meta_get_render_flags (inbuf_meta) & + ~GST_VAAPI_PICTURE_STRUCTURE_MASK; + + /* First field */ + if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_DEINTERLACE) { + fieldbuf = create_output_buffer (postproc); + if (!fieldbuf) + goto error_create_buffer; + + outbuf_meta = gst_buffer_get_vaapi_video_meta (fieldbuf); + if (!outbuf_meta) + goto error_create_meta; + + if (!gst_vaapi_video_meta_get_surface_proxy (outbuf_meta)) { + proxy = + gst_vaapi_surface_proxy_new_from_pool (GST_VAAPI_SURFACE_POOL + (postproc->filter_pool)); + if (!proxy) + goto error_create_proxy; + gst_vaapi_video_meta_set_surface_proxy (outbuf_meta, proxy); + gst_vaapi_surface_proxy_unref (proxy); + } + + if (deint) { + deint_flags = (tff ? GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD : 0); + if (tff) + deint_flags |= GST_VAAPI_DEINTERLACE_FLAG_TFF; + if (!set_best_deint_method (postproc, deint_flags, &deint_method)) + goto error_op_deinterlace; + + if (deint_method != postproc->deinterlace_method) { + GST_DEBUG ("unsupported deinterlace-method %u. Using %u instead", + postproc->deinterlace_method, deint_method); + postproc->deinterlace_method = deint_method; + deint_refs = deint_method_is_advanced (deint_method); + } + + if (deint_refs) { + ds_set_surfaces (ds); + if (!gst_vaapi_filter_set_deinterlacing_references (postproc->filter, + ds->surfaces, ds->num_surfaces, NULL, 0)) + goto error_op_deinterlace; + } + } else if (deint_changed) { + // Reset internal filter to non-deinterlacing mode + deint_method = GST_VAAPI_DEINTERLACE_METHOD_NONE; + if (!gst_vaapi_filter_set_deinterlacing (postproc->filter, + deint_method, 0)) + goto error_op_deinterlace; + } + + outbuf_surface = gst_vaapi_video_meta_get_surface (outbuf_meta); + gst_vaapi_filter_set_cropping_rectangle (postproc->filter, crop_rect); + status = gst_vaapi_filter_process (postproc->filter, inbuf_surface, + outbuf_surface, flags); + if (status != GST_VAAPI_FILTER_STATUS_SUCCESS) + goto error_process_vpp; + + copy_metadata (postproc, fieldbuf, inbuf); + GST_BUFFER_TIMESTAMP (fieldbuf) = timestamp; + GST_BUFFER_DURATION (fieldbuf) = postproc->field_duration; + if (discont) { + GST_BUFFER_FLAG_SET (fieldbuf, GST_BUFFER_FLAG_DISCONT); + discont = FALSE; + } + + if (!replace_to_dumb_buffer_if_required (postproc, &fieldbuf)) + goto error_copy_buffer; + + ret = gst_pad_push (trans->srcpad, fieldbuf); + if (ret != GST_FLOW_OK) + goto error_push_buffer; + } + fieldbuf = NULL; + + /* Second field */ + outbuf_meta = gst_buffer_get_vaapi_video_meta (outbuf); + if (!outbuf_meta) + goto error_create_meta; + + if (!gst_vaapi_video_meta_get_surface_proxy (outbuf_meta)) { + proxy = + gst_vaapi_surface_proxy_new_from_pool (GST_VAAPI_SURFACE_POOL + (postproc->filter_pool)); + if (!proxy) + goto error_create_proxy; + gst_vaapi_video_meta_set_surface_proxy (outbuf_meta, proxy); + gst_vaapi_surface_proxy_unref (proxy); + } + + if (deint) { + deint_flags = (tff ? 0 : GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD); + if (tff) + deint_flags |= GST_VAAPI_DEINTERLACE_FLAG_TFF; + if (!gst_vaapi_filter_set_deinterlacing (postproc->filter, + deint_method, deint_flags)) + goto error_op_deinterlace; + + if (deint_refs + && !gst_vaapi_filter_set_deinterlacing_references (postproc->filter, + ds->surfaces, ds->num_surfaces, NULL, 0)) + goto error_op_deinterlace; + } else if (deint_changed + && !gst_vaapi_filter_set_deinterlacing (postproc->filter, deint_method, + 0)) + goto error_op_deinterlace; + + outbuf_surface = gst_vaapi_video_meta_get_surface (outbuf_meta); + gst_vaapi_filter_set_cropping_rectangle (postproc->filter, crop_rect); + status = gst_vaapi_filter_process (postproc->filter, inbuf_surface, + outbuf_surface, flags); + if (status != GST_VAAPI_FILTER_STATUS_SUCCESS) + goto error_process_vpp; + + if (!(postproc->flags & GST_VAAPI_POSTPROC_FLAG_DEINTERLACE)) + gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS, 0, -1); + else { + GST_BUFFER_TIMESTAMP (outbuf) = timestamp + postproc->field_duration; + GST_BUFFER_DURATION (outbuf) = postproc->field_duration; + if (discont) { + GST_BUFFER_FLAG_SET (fieldbuf, GST_BUFFER_FLAG_DISCONT); + discont = FALSE; + } + } + + copy_metadata (postproc, outbuf, inbuf); + + rotate_crop_meta (postproc, gst_buffer_get_video_meta (inbuf), + gst_buffer_get_video_crop_meta (outbuf)); + + if (deint && deint_refs) + ds_add_buffer (ds, inbuf); + postproc->use_vpp = TRUE; + return GST_FLOW_OK; + + /* ERRORS */ +error_invalid_buffer: + { + GST_ERROR_OBJECT (postproc, "failed to validate source buffer"); + return GST_FLOW_ERROR; + } +error_create_buffer: + { + GST_ERROR_OBJECT (postproc, "failed to create output buffer"); + return GST_FLOW_ERROR; + } +error_create_meta: + { + GST_ERROR_OBJECT (postproc, "failed to create new output buffer meta"); + gst_buffer_replace (&fieldbuf, NULL); + return GST_FLOW_ERROR; + } +error_create_proxy: + { + GST_ERROR_OBJECT (postproc, "failed to create surface proxy from pool"); + gst_buffer_replace (&fieldbuf, NULL); + return GST_FLOW_ERROR; + } +error_op_deinterlace: + { + GST_ERROR_OBJECT (postproc, "failed to apply deinterlacing filter"); + gst_buffer_replace (&fieldbuf, NULL); + return GST_FLOW_NOT_SUPPORTED; + } +error_process_vpp: + { + GST_ERROR_OBJECT (postproc, "failed to apply VPP filters (error %d)", + status); + gst_buffer_replace (&fieldbuf, NULL); + return GST_FLOW_ERROR; + } +error_copy_buffer: + { + GST_ERROR_OBJECT (postproc, "failed to copy field buffer to dumb buffer"); + gst_buffer_replace (&fieldbuf, NULL); + return GST_FLOW_ERROR; + } +error_push_buffer: + { + GST_DEBUG_OBJECT (postproc, "failed to push output buffer: %s", + gst_flow_get_name (ret)); + return ret; + } +} + +static GstFlowReturn +gst_vaapipostproc_process (GstBaseTransform * trans, GstBuffer * inbuf, + GstBuffer * outbuf) +{ + GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans); + GstVaapiVideoMeta *meta; + GstClockTime timestamp; + GstFlowReturn ret; + GstBuffer *fieldbuf; + guint fieldbuf_flags, outbuf_flags, flags; + gboolean tff, deint; + + meta = gst_buffer_get_vaapi_video_meta (inbuf); + if (!meta) + goto error_invalid_buffer; + + timestamp = GST_BUFFER_TIMESTAMP (inbuf); + tff = GST_BUFFER_FLAG_IS_SET (inbuf, GST_VIDEO_BUFFER_FLAG_TFF); + deint = should_deinterlace_buffer (postproc, inbuf); + + flags = gst_vaapi_video_meta_get_render_flags (meta) & + ~GST_VAAPI_PICTURE_STRUCTURE_MASK; + + /* First field */ + fieldbuf = create_output_buffer (postproc); + if (!fieldbuf) + goto error_create_buffer; + append_output_buffer_metadata (postproc, fieldbuf, inbuf, 0); + + meta = gst_buffer_get_vaapi_video_meta (fieldbuf); + fieldbuf_flags = flags; + fieldbuf_flags |= deint ? (tff ? + GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD : + GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD) : + GST_VAAPI_PICTURE_STRUCTURE_FRAME; + gst_vaapi_video_meta_set_render_flags (meta, fieldbuf_flags); + + GST_BUFFER_TIMESTAMP (fieldbuf) = timestamp; + GST_BUFFER_DURATION (fieldbuf) = postproc->field_duration; + + if (!replace_to_dumb_buffer_if_required (postproc, &fieldbuf)) + goto error_copy_buffer; + + ret = gst_pad_push (trans->srcpad, fieldbuf); + if (ret != GST_FLOW_OK) + goto error_push_buffer; + + /* Second field */ + append_output_buffer_metadata (postproc, outbuf, inbuf, 0); + + meta = gst_buffer_get_vaapi_video_meta (outbuf); + outbuf_flags = flags; + outbuf_flags |= deint ? (tff ? + GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD : + GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD) : + GST_VAAPI_PICTURE_STRUCTURE_FRAME; + gst_vaapi_video_meta_set_render_flags (meta, outbuf_flags); + + GST_BUFFER_TIMESTAMP (outbuf) = timestamp + postproc->field_duration; + GST_BUFFER_DURATION (outbuf) = postproc->field_duration; + return GST_FLOW_OK; + + /* ERRORS */ +error_invalid_buffer: + { + GST_ERROR_OBJECT (postproc, "failed to validate source buffer"); + return GST_FLOW_ERROR; + } +error_create_buffer: + { + GST_ERROR_OBJECT (postproc, "failed to create output buffer"); + return GST_FLOW_EOS; + } +error_copy_buffer: + { + GST_ERROR_OBJECT (postproc, "failed to copy field buffer to dumb buffer"); + gst_buffer_replace (&fieldbuf, NULL); + return GST_FLOW_ERROR; + } +error_push_buffer: + { + GST_DEBUG_OBJECT (postproc, "failed to push output buffer: %s", + gst_flow_get_name (ret)); + return ret; + } +} + +static GstFlowReturn +gst_vaapipostproc_passthrough (GstBaseTransform * trans, GstBuffer * inbuf, + GstBuffer * outbuf) +{ + GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans); + GstVaapiVideoMeta *meta; + + /* No video processing needed, simply copy buffer metadata */ + meta = gst_buffer_get_vaapi_video_meta (inbuf); + if (!meta) + goto error_invalid_buffer; + + append_output_buffer_metadata (postproc, outbuf, inbuf, + GST_BUFFER_COPY_TIMESTAMPS); + return GST_FLOW_OK; + + /* ERRORS */ +error_invalid_buffer: + { + GST_ERROR_OBJECT (postproc, "failed to validate source buffer"); + return GST_FLOW_ERROR; + } +} + +static gboolean +video_info_changed (GstVideoInfo * old_vip, GstVideoInfo * new_vip) +{ + if (gst_video_info_changed (old_vip, new_vip)) + return TRUE; + if (GST_VIDEO_INFO_INTERLACE_MODE (old_vip) != + GST_VIDEO_INFO_INTERLACE_MODE (new_vip)) + return TRUE; + return FALSE; +} + +static gboolean +video_info_update (GstCaps * caps, GstVideoInfo * info, + gboolean * caps_changed_ptr) +{ + GstVideoInfo vi; + + if (!gst_video_info_from_caps (&vi, caps)) + return FALSE; + + *caps_changed_ptr = FALSE; + if (video_info_changed (info, &vi)) { + *caps_changed_ptr = TRUE; + *info = vi; + } + + return TRUE; +} + +static gboolean +gst_vaapipostproc_update_sink_caps (GstVaapiPostproc * postproc, GstCaps * caps, + gboolean * caps_changed_ptr) +{ + GstVideoInfo vi; + gboolean deinterlace; + + GST_INFO_OBJECT (postproc, "new sink caps = %" GST_PTR_FORMAT, caps); + + if (!video_info_update (caps, &postproc->sinkpad_info, caps_changed_ptr)) + return FALSE; + + vi = postproc->sinkpad_info; + deinterlace = is_deinterlace_enabled (postproc, &vi); + if (deinterlace) + postproc->flags |= GST_VAAPI_POSTPROC_FLAG_DEINTERLACE; + postproc->field_duration = GST_VIDEO_INFO_FPS_N (&vi) > 0 ? + gst_util_uint64_scale (GST_SECOND, GST_VIDEO_INFO_FPS_D (&vi), + (1 + deinterlace) * GST_VIDEO_INFO_FPS_N (&vi)) : 0; + + postproc->get_va_surfaces = gst_caps_has_vaapi_surface (caps); + return TRUE; +} + +static gboolean +gst_vaapipostproc_update_src_caps (GstVaapiPostproc * postproc, GstCaps * caps, + gboolean * caps_changed_ptr) +{ + GST_INFO_OBJECT (postproc, "new src caps = %" GST_PTR_FORMAT, caps); + + if (!video_info_update (caps, &postproc->srcpad_info, caps_changed_ptr)) + return FALSE; + + if (postproc->format != GST_VIDEO_INFO_FORMAT (&postproc->sinkpad_info) && + postproc->format != DEFAULT_FORMAT) + postproc->flags |= GST_VAAPI_POSTPROC_FLAG_FORMAT; + + if (GST_VIDEO_INFO_WIDTH (&postproc->srcpad_info) != + GST_VIDEO_INFO_WIDTH (&postproc->sinkpad_info) + || GST_VIDEO_INFO_HEIGHT (&postproc->srcpad_info) != + GST_VIDEO_INFO_HEIGHT (&postproc->sinkpad_info)) + postproc->flags |= GST_VAAPI_POSTPROC_FLAG_SIZE; + + return TRUE; +} + +static gboolean +ensure_allowed_sinkpad_caps (GstVaapiPostproc * postproc) +{ + GstCaps *out_caps, *raw_caps; + guint i, num_structures; + + if (postproc->allowed_sinkpad_caps) + return TRUE; + + if (!GST_VAAPI_PLUGIN_BASE_DISPLAY (postproc)) + return FALSE; + + /* Create VA caps */ + out_caps = gst_caps_from_string (GST_VAAPI_MAKE_SURFACE_CAPS ", " + GST_CAPS_INTERLACED_MODES); + if (!out_caps) { + GST_WARNING_OBJECT (postproc, "failed to create VA sink caps"); + return FALSE; + } + + raw_caps = gst_vaapi_plugin_base_get_allowed_sinkpad_raw_caps + (GST_VAAPI_PLUGIN_BASE (postproc)); + if (!raw_caps) { + gst_caps_unref (out_caps); + GST_WARNING_OBJECT (postproc, "failed to create YUV sink caps"); + return FALSE; + } + + out_caps = gst_caps_make_writable (out_caps); + gst_caps_append (out_caps, gst_caps_copy (raw_caps)); + + num_structures = gst_caps_get_size (out_caps); + for (i = 0; i < num_structures; i++) { + GstStructure *structure; + + structure = gst_caps_get_structure (out_caps, i); + if (!structure) + continue; + + if (postproc->filter) + gst_vaapi_filter_append_caps (postproc->filter, structure); + } + + postproc->allowed_sinkpad_caps = out_caps; + + /* XXX: append VA/VPP filters */ + return TRUE; +} + +/* Fixup output caps so that to reflect the supported set of pixel formats */ +static GstCaps * +expand_allowed_srcpad_caps (GstVaapiPostproc * postproc, GstCaps * caps) +{ + GValue value = G_VALUE_INIT, v_format = G_VALUE_INIT; + guint i, num_structures; + gint gl_upload_meta_idx = -1; + + if (postproc->filter == NULL) + goto cleanup; + if (!gst_vaapipostproc_ensure_filter_caps (postproc)) + goto cleanup; + + /* Reset "format" field for each structure */ + if (!gst_vaapi_value_set_format_list (&value, postproc->filter_formats)) + goto cleanup; + if (gst_vaapi_value_set_format (&v_format, GST_VIDEO_FORMAT_ENCODED)) { + gst_value_list_prepend_value (&value, &v_format); + g_value_unset (&v_format); + } + + num_structures = gst_caps_get_size (caps); + for (i = 0; i < num_structures; i++) { + GstCapsFeatures *const features = gst_caps_get_features (caps, i); + GstStructure *structure; + + structure = gst_caps_get_structure (caps, i); + if (!structure) + continue; + + gst_vaapi_filter_append_caps (postproc->filter, structure); + + if (gst_caps_features_contains (features, + GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META)) { + gl_upload_meta_idx = i; + continue; + } + + gst_structure_set_value (structure, "format", &value); + } + g_value_unset (&value); + + if ((GST_VAAPI_PLUGIN_BASE_SRC_PAD_CAN_DMABUF (postproc) + || !gst_vaapi_display_has_opengl (GST_VAAPI_PLUGIN_BASE_DISPLAY + (postproc))) + && gl_upload_meta_idx > -1) { + gst_caps_remove_structure (caps, gl_upload_meta_idx); + } + +cleanup: + return caps; +} + +static gboolean +ensure_allowed_srcpad_caps (GstVaapiPostproc * postproc) +{ + GstCaps *out_caps; + + if (postproc->allowed_srcpad_caps) + return TRUE; + + /* Create initial caps from pad template */ + out_caps = gst_caps_from_string (gst_vaapipostproc_src_caps_str); + if (!out_caps) { + GST_ERROR_OBJECT (postproc, "failed to create VA src caps"); + return FALSE; + } + + postproc->allowed_srcpad_caps = + expand_allowed_srcpad_caps (postproc, out_caps); + return postproc->allowed_srcpad_caps != NULL; +} + +static GstCaps * +gst_vaapipostproc_transform_caps_impl (GstBaseTransform * trans, + GstPadDirection direction) +{ + GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans); + + /* Generate the sink pad caps, that could be fixated afterwards */ + if (direction == GST_PAD_SRC) { + if (!ensure_allowed_sinkpad_caps (postproc)) + return gst_caps_from_string (gst_vaapipostproc_sink_caps_str); + return gst_caps_ref (postproc->allowed_sinkpad_caps); + } + + /* Generate complete set of src pad caps */ + if (!ensure_allowed_srcpad_caps (postproc)) + return NULL; + return gst_vaapipostproc_transform_srccaps (postproc); +} + +static GstCaps * +gst_vaapipostproc_transform_caps (GstBaseTransform * trans, + GstPadDirection direction, GstCaps * caps, GstCaps * filter) +{ + GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans); + GstCaps *out_caps; + + GST_DEBUG_OBJECT (trans, + "Transforming caps %" GST_PTR_FORMAT " in direction %s", caps, + (direction == GST_PAD_SINK) ? "sink" : "src"); + + g_mutex_lock (&postproc->postproc_lock); + out_caps = gst_vaapipostproc_transform_caps_impl (trans, direction); + g_mutex_unlock (&postproc->postproc_lock); + + if (out_caps && filter) { + GstCaps *intersection; + + intersection = gst_caps_intersect_full (out_caps, filter, + GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (out_caps); + out_caps = intersection; + } + + GST_DEBUG_OBJECT (trans, "returning caps: %" GST_PTR_FORMAT, out_caps); + + return out_caps; +} + +static GstCaps * +gst_vaapipostproc_fixate_caps (GstBaseTransform * trans, + GstPadDirection direction, GstCaps * caps, GstCaps * othercaps) +{ + GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans); + GstCaps *outcaps = NULL; + gboolean same_caps, filter_updated = FALSE; + + GST_DEBUG_OBJECT (trans, "trying to fixate othercaps %" GST_PTR_FORMAT + " based on caps %" GST_PTR_FORMAT " in direction %s", othercaps, caps, + (direction == GST_PAD_SINK) ? "sink" : "src"); + + if (direction == GST_PAD_SRC) { + /* @TODO: we can do better */ + outcaps = gst_caps_fixate (othercaps); + goto done; + } + + g_mutex_lock (&postproc->postproc_lock); + postproc->has_vpp = gst_vaapipostproc_ensure_filter_caps (postproc); + if (check_filter_update (postproc) && update_filter (postproc)) { + /* check again if changed value is default */ + filter_updated = check_filter_update (postproc); + } + + outcaps = gst_vaapipostproc_fixate_srccaps (postproc, caps, othercaps); + g_mutex_unlock (&postproc->postproc_lock); + if (!outcaps) + goto done; + + /* set passthrough according to caps changes or filter changes */ + same_caps = gst_caps_is_equal (caps, outcaps); + gst_base_transform_set_passthrough (trans, same_caps && !filter_updated); + +done: + if (outcaps) + GST_DEBUG_OBJECT (trans, "fixated othercaps to %" GST_PTR_FORMAT, outcaps); + gst_caps_unref (othercaps); + + return outcaps; +} + +static gboolean +gst_vaapipostproc_transform_size (GstBaseTransform * trans, + GstPadDirection direction, GstCaps * caps, gsize size, + GstCaps * othercaps, gsize * othersize) +{ + GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans); + + if (direction == GST_PAD_SINK || postproc->get_va_surfaces) + *othersize = 0; + else + *othersize = size; + return TRUE; +} + +static gboolean +gst_vaapipostproc_transform_meta (GstBaseTransform * trans, GstBuffer * outbuf, + GstMeta * meta, GstBuffer * inbuf) +{ + GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans); + + /* don't copy GstVideoCropMeta if we are using vpp crop */ + if (meta->info->api == GST_VIDEO_CROP_META_API_TYPE + && use_vpp_crop (postproc)) + return FALSE; + + /* don't copy GstParentBufferMeta if use_vpp */ + if (meta->info->api == GST_PARENT_BUFFER_META_API_TYPE && postproc->use_vpp) + return FALSE; + + return TRUE; +} + +static GstFlowReturn +gst_vaapipostproc_transform (GstBaseTransform * trans, GstBuffer * inbuf, + GstBuffer * outbuf) +{ + GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans); + GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (postproc); + GstBuffer *buf, *sys_buf = NULL; + GstFlowReturn ret; + + ret = gst_vaapi_plugin_base_get_input_buffer (plugin, inbuf, &buf); + if (ret != GST_FLOW_OK) + return GST_FLOW_ERROR; + + if (GST_VAAPI_PLUGIN_BASE_COPY_OUTPUT_FRAME (trans)) { + GstBuffer *va_buf = create_output_buffer (postproc); + if (!va_buf) { + ret = GST_FLOW_ERROR; + goto done; + } + sys_buf = outbuf; + outbuf = va_buf; + } + + ret = GST_FLOW_NOT_SUPPORTED; + if (postproc->flags) { + /* Use VA/VPP extensions to process this frame */ + if (postproc->has_vpp) { + ret = gst_vaapipostproc_process_vpp (trans, buf, outbuf); + if (ret != GST_FLOW_NOT_SUPPORTED) + goto done; + GST_WARNING_OBJECT (postproc, "unsupported VPP filters. Disabling"); + } + + /* Only append picture structure meta data (top/bottom field) */ + if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_DEINTERLACE) { + ret = gst_vaapipostproc_process (trans, buf, outbuf); + if (ret != GST_FLOW_NOT_SUPPORTED) + goto done; + } + } + + /* Fallback: passthrough to the downstream element as is */ + ret = gst_vaapipostproc_passthrough (trans, buf, outbuf); + +done: + gst_buffer_unref (buf); + + if (sys_buf) { + if (!gst_vaapi_plugin_copy_va_buffer (plugin, outbuf, sys_buf)) + return GST_FLOW_ERROR; + + gst_buffer_unref (outbuf); + outbuf = sys_buf; + } + + return ret; +} + +static gboolean +ensure_buffer_pool (GstVaapiPostproc * postproc, GstVideoInfo * vi) +{ + GstVaapiVideoPool *pool; + + if (!vi) + return FALSE; + + gst_video_info_change_format (vi, postproc->format, + GST_VIDEO_INFO_WIDTH (vi), GST_VIDEO_INFO_HEIGHT (vi)); + + if (postproc->filter_pool + && !video_info_changed (&postproc->filter_pool_info, vi)) + return TRUE; + postproc->filter_pool_info = *vi; + + pool = + gst_vaapi_surface_pool_new_full (GST_VAAPI_PLUGIN_BASE_DISPLAY (postproc), + &postproc->filter_pool_info, 0); + if (!pool) + return FALSE; + + gst_vaapi_video_pool_replace (&postproc->filter_pool, pool); + gst_vaapi_video_pool_unref (pool); + return TRUE; +} + +static GstFlowReturn +gst_vaapipostproc_prepare_output_buffer (GstBaseTransform * trans, + GstBuffer * inbuf, GstBuffer ** outbuf_ptr) +{ + GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans); + const GstVideoMeta *video_meta; + GstVideoInfo info; + + if (gst_base_transform_is_passthrough (trans)) { + *outbuf_ptr = inbuf; + return GST_FLOW_OK; + } + + /* If we are not using vpp crop (i.e. forwarding crop meta to downstream) + * then, ensure our output buffer pool is sized and rotated for uncropped + * output */ + if (gst_buffer_get_video_crop_meta (inbuf) && !use_vpp_crop (postproc)) { + /* The video meta is required since the caps width/height are smaller, + * which would not result in a usable GstVideoInfo for mapping the + * buffer. */ + video_meta = gst_buffer_get_video_meta (inbuf); + if (!video_meta) + return GST_FLOW_ERROR; + + info = postproc->srcpad_info; + info.width = video_meta->width; + info.height = video_meta->height; + + if (postproc->has_vpp) { + /* compensate for rotation if needed */ + switch (gst_vaapi_filter_get_video_direction (postproc->filter)) { + case GST_VIDEO_ORIENTATION_90R: + case GST_VIDEO_ORIENTATION_UL_LR: + case GST_VIDEO_ORIENTATION_90L: + case GST_VIDEO_ORIENTATION_UR_LL: + G_PRIMITIVE_SWAP (guint, info.width, info.height); + default: + break; + } + } + + ensure_buffer_pool (postproc, &info); + } + + if (GST_VAAPI_PLUGIN_BASE_COPY_OUTPUT_FRAME (trans)) { + *outbuf_ptr = create_output_dump_buffer (postproc); + } else { + *outbuf_ptr = create_output_buffer (postproc); + } + + if (!*outbuf_ptr) + return GST_FLOW_ERROR; + + return GST_FLOW_OK; +} + +static gboolean +ensure_srcpad_buffer_pool (GstVaapiPostproc * postproc, GstCaps * caps) +{ + GstVideoInfo vi; + + if (!gst_video_info_from_caps (&vi, caps)) + return FALSE; + + return ensure_buffer_pool (postproc, &vi); +} + +static gboolean +is_native_video_format (GstVideoFormat format) +{ + guint i = 0; + for (i = 0; i < G_N_ELEMENTS (native_formats); i++) + if (native_formats[i] == format) + return TRUE; + return FALSE; +} + +static gboolean +gst_vaapipostproc_set_caps (GstBaseTransform * trans, GstCaps * caps, + GstCaps * out_caps) +{ + GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans); + gboolean sink_caps_changed = FALSE; + gboolean src_caps_changed = FALSE; + GstVideoInfo vinfo; + gboolean ret = FALSE; + + g_mutex_lock (&postproc->postproc_lock); + if (!gst_vaapipostproc_update_sink_caps (postproc, caps, &sink_caps_changed)) + goto done; + /* HACK: This is a workaround to deal with the va-intel-driver for non-native + * formats while doing advanced deinterlacing. The format of reference surfaces must + * be same as the format used by the driver internally for motion adaptive + * deinterlacing and motion compensated deinterlacing */ + if (!gst_video_info_from_caps (&vinfo, caps)) + goto done; + if (deint_method_is_advanced (postproc->deinterlace_method) + && !is_native_video_format (GST_VIDEO_INFO_FORMAT (&vinfo))) { + GST_WARNING_OBJECT (postproc, + "Advanced deinterlacing requires the native video formats used by the driver internally"); + goto done; + } + if (!gst_vaapipostproc_update_src_caps (postproc, out_caps, + &src_caps_changed)) + goto done; + + if (sink_caps_changed || src_caps_changed) { + gst_vaapipostproc_destroy (postproc); + if (!gst_vaapipostproc_create (postproc)) + goto done; + if (!gst_vaapi_plugin_base_set_caps (GST_VAAPI_PLUGIN_BASE (trans), + caps, out_caps)) + goto done; + } + + if (postproc->has_vpp) { + if (!gst_vaapi_filter_set_colorimetry (postproc->filter, + &GST_VIDEO_INFO_COLORIMETRY (GST_VAAPI_PLUGIN_BASE_SINK_PAD_INFO + (postproc)), + &GST_VIDEO_INFO_COLORIMETRY (GST_VAAPI_PLUGIN_BASE_SRC_PAD_INFO + (postproc)))) + goto done; + + if (!configure_hdr_tone_map (postproc, + GST_VAAPI_PLUGIN_BASE_SINK_PAD_CAPS (postproc))) + GST_WARNING_OBJECT (postproc, + "Failed to configure HDR tone mapping." + " The driver may not support it."); + } + + if (!ensure_srcpad_buffer_pool (postproc, out_caps)) + goto done; + + postproc->same_caps = gst_caps_is_equal (caps, out_caps); + + if (!src_caps_changed) { + /* set passthrough according to caps changes or filter changes */ + gst_vaapipostproc_set_passthrough (trans); + } + + ret = TRUE; + +done: + g_mutex_unlock (&postproc->postproc_lock); + + /* Updates the srcpad caps and send the caps downstream */ + if (ret && src_caps_changed) + gst_base_transform_update_src_caps (trans, out_caps); + + return ret; +} + +static gboolean +gst_vaapipostproc_query (GstBaseTransform * trans, + GstPadDirection direction, GstQuery * query) +{ + GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans); + GstElement *const element = GST_ELEMENT (trans); + + if (GST_QUERY_TYPE (query) == GST_QUERY_CONTEXT) { + if (gst_vaapi_handle_context_query (element, query)) { + GST_DEBUG_OBJECT (postproc, "sharing display %" GST_PTR_FORMAT, + GST_VAAPI_PLUGIN_BASE_DISPLAY (postproc)); + return TRUE; + } + } + + return + GST_BASE_TRANSFORM_CLASS (gst_vaapipostproc_parent_class)->query (trans, + direction, query); +} + +static gboolean +gst_vaapipostproc_propose_allocation (GstBaseTransform * trans, + GstQuery * decide_query, GstQuery * query) +{ + GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans); + GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (trans); + GstCaps *allocation_caps; + GstStructure *structure; + gint allocation_width, allocation_height; + gint negotiated_width, negotiated_height; + + /* passthrough query, we just bypass to the peer */ + if (decide_query == NULL) { + return GST_BASE_TRANSFORM_CLASS + (gst_vaapipostproc_parent_class)->propose_allocation (trans, + decide_query, query); + } + + /* advertise to upstream that we can handle crop meta */ + if (decide_query) + gst_query_add_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE, NULL); + + negotiated_width = GST_VIDEO_INFO_WIDTH (&postproc->sinkpad_info); + negotiated_height = GST_VIDEO_INFO_HEIGHT (&postproc->sinkpad_info); + + if (negotiated_width == 0 || negotiated_height == 0) + goto bail; + + allocation_caps = NULL; + gst_query_parse_allocation (query, &allocation_caps, NULL); + if (!allocation_caps) + goto bail; + + structure = gst_caps_get_structure (allocation_caps, 0); + if (!gst_structure_get_int (structure, "width", &allocation_width)) + goto bail; + if (!gst_structure_get_int (structure, "height", &allocation_height)) + goto bail; + + if (allocation_width != negotiated_width + || allocation_height != negotiated_height) { + g_mutex_lock (&postproc->postproc_lock); + postproc->flags |= GST_VAAPI_POSTPROC_FLAG_SIZE; + g_mutex_unlock (&postproc->postproc_lock); + } + +bail: + /* Let vaapidecode allocate the video buffers */ + if (postproc->get_va_surfaces) + return FALSE; + if (!gst_vaapi_plugin_base_propose_allocation (plugin, query)) + return FALSE; + return TRUE; +} + +static gboolean +gst_vaapipostproc_decide_allocation (GstBaseTransform * trans, GstQuery * query) +{ + GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans); + + g_mutex_lock (&postproc->postproc_lock); + /* Let downstream handle the crop meta if they support it */ + postproc->forward_crop = (gst_query_find_allocation_meta (query, + GST_VIDEO_CROP_META_API_TYPE, NULL) && + gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)); + GST_DEBUG_OBJECT (postproc, "use_vpp_crop=%d", use_vpp_crop (postproc)); + g_mutex_unlock (&postproc->postproc_lock); + + return gst_vaapi_plugin_base_decide_allocation (GST_VAAPI_PLUGIN_BASE (trans), + query); +} + +static void +get_scale_factor (GstVaapiPostproc * const postproc, gdouble * w_factor, + gdouble * h_factor) +{ + gdouble wd = GST_VIDEO_INFO_WIDTH (&postproc->srcpad_info); + gdouble hd = GST_VIDEO_INFO_HEIGHT (&postproc->srcpad_info); + + g_return_if_fail (postproc->has_vpp); + + switch (gst_vaapi_filter_get_video_direction (postproc->filter)) { + case GST_VIDEO_ORIENTATION_90R: + case GST_VIDEO_ORIENTATION_90L: + case GST_VIDEO_ORIENTATION_UR_LL: + case GST_VIDEO_ORIENTATION_UL_LR: + G_PRIMITIVE_SWAP (gdouble, wd, hd); + break; + default: + break; + } + + *w_factor = GST_VIDEO_INFO_WIDTH (&postproc->sinkpad_info) + - (postproc->crop_left + postproc->crop_right); + *w_factor /= wd; + + *h_factor = GST_VIDEO_INFO_HEIGHT (&postproc->sinkpad_info) + - (postproc->crop_top + postproc->crop_bottom); + *h_factor /= hd; +} + +static gboolean +gst_vaapipostproc_src_event (GstBaseTransform * trans, GstEvent * event) +{ + GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans); + gdouble new_x = 0, new_y = 0, x = 0, y = 0, w_factor = 1, h_factor = 1; + GstStructure *structure; + gboolean ret; + + GST_TRACE_OBJECT (postproc, "handling %s event", GST_EVENT_TYPE_NAME (event)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_NAVIGATION: + event = + GST_EVENT (gst_mini_object_make_writable (GST_MINI_OBJECT (event))); + + structure = (GstStructure *) gst_event_get_structure (event); + if (postproc->has_vpp + && gst_structure_get_double (structure, "pointer_x", &x) + && gst_structure_get_double (structure, "pointer_y", &y)) { + GST_DEBUG_OBJECT (postproc, "converting %fx%f", x, y); + + /* video-direction compensation */ + switch (gst_vaapi_filter_get_video_direction (postproc->filter)) { + case GST_VIDEO_ORIENTATION_90R: + new_x = y; + new_y = GST_VIDEO_INFO_WIDTH (&postproc->srcpad_info) - 1 - x; + break; + case GST_VIDEO_ORIENTATION_90L: + new_x = GST_VIDEO_INFO_HEIGHT (&postproc->srcpad_info) - 1 - y; + new_y = x; + break; + case GST_VIDEO_ORIENTATION_UR_LL: + new_x = GST_VIDEO_INFO_HEIGHT (&postproc->srcpad_info) - 1 - y; + new_y = GST_VIDEO_INFO_WIDTH (&postproc->srcpad_info) - 1 - x; + break; + case GST_VIDEO_ORIENTATION_UL_LR: + new_x = y; + new_y = x; + break; + case GST_VIDEO_ORIENTATION_180: + new_x = GST_VIDEO_INFO_WIDTH (&postproc->srcpad_info) - 1 - x; + new_y = GST_VIDEO_INFO_HEIGHT (&postproc->srcpad_info) - 1 - y; + break; + case GST_VIDEO_ORIENTATION_HORIZ: + new_x = GST_VIDEO_INFO_WIDTH (&postproc->srcpad_info) - 1 - x; + new_y = y; + break; + case GST_VIDEO_ORIENTATION_VERT: + new_x = x; + new_y = GST_VIDEO_INFO_HEIGHT (&postproc->srcpad_info) - 1 - y; + break; + default: + new_x = x; + new_y = y; + break; + } + + /* scale compensation */ + get_scale_factor (postproc, &w_factor, &h_factor); + new_x *= w_factor; + new_y *= h_factor; + + /* crop compensation */ + new_x += postproc->crop_left; + new_y += postproc->crop_top; + + GST_DEBUG_OBJECT (postproc, "to %fx%f", new_x, new_y); + gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, new_x, + "pointer_y", G_TYPE_DOUBLE, new_y, NULL); + } + break; + default: + break; + } + + ret = + GST_BASE_TRANSFORM_CLASS (gst_vaapipostproc_parent_class)->src_event + (trans, event); + + return ret; +} + +static gboolean +gst_vaapipostproc_sink_event (GstBaseTransform * trans, GstEvent * event) +{ + GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans); + GstTagList *taglist; + gchar *orientation; + gboolean ret; + gboolean do_reconf; + + GST_DEBUG_OBJECT (postproc, "handling %s event", GST_EVENT_TYPE_NAME (event)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_TAG: + gst_event_parse_tag (event, &taglist); + + if (gst_tag_list_get_string (taglist, "image-orientation", &orientation)) { + do_reconf = TRUE; + if (!g_strcmp0 ("rotate-0", orientation)) + postproc->tag_video_direction = GST_VIDEO_ORIENTATION_IDENTITY; + else if (!g_strcmp0 ("rotate-90", orientation)) + postproc->tag_video_direction = GST_VIDEO_ORIENTATION_90R; + else if (!g_strcmp0 ("rotate-180", orientation)) + postproc->tag_video_direction = GST_VIDEO_ORIENTATION_180; + else if (!g_strcmp0 ("rotate-270", orientation)) + postproc->tag_video_direction = GST_VIDEO_ORIENTATION_90L; + else if (!g_strcmp0 ("flip-rotate-0", orientation)) + postproc->tag_video_direction = GST_VIDEO_ORIENTATION_HORIZ; + else if (!g_strcmp0 ("flip-rotate-90", orientation)) + postproc->tag_video_direction = GST_VIDEO_ORIENTATION_UL_LR; + else if (!g_strcmp0 ("flip-rotate-180", orientation)) + postproc->tag_video_direction = GST_VIDEO_ORIENTATION_VERT; + else if (!g_strcmp0 ("flip-rotate-270", orientation)) + postproc->tag_video_direction = GST_VIDEO_ORIENTATION_UR_LL; + else + do_reconf = FALSE; + + g_free (orientation); + + if (do_reconf) { + postproc->flags |= GST_VAAPI_POSTPROC_FLAG_VIDEO_DIRECTION; + gst_base_transform_reconfigure_src (trans); + } + } + break; + default: + break; + } + + ret = + GST_BASE_TRANSFORM_CLASS (gst_vaapipostproc_parent_class)->sink_event + (trans, event); + + return ret; +} + +static void +gst_vaapipostproc_finalize (GObject * object) +{ + GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (object); + + gst_vaapipostproc_destroy (postproc); + + g_mutex_clear (&postproc->postproc_lock); + gst_vaapi_plugin_base_finalize (GST_VAAPI_PLUGIN_BASE (postproc)); + G_OBJECT_CLASS (gst_vaapipostproc_parent_class)->finalize (object); +} + +static void +gst_vaapipostproc_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (object); + gboolean do_reconf = FALSE; + + g_mutex_lock (&postproc->postproc_lock); + switch (prop_id) { +#ifndef GST_REMOVE_DEPRECATED + case PROP_FORMAT: + postproc->format = g_value_get_enum (value); + break; + case PROP_WIDTH: + { + guint prev_width = postproc->width; + postproc->width = g_value_get_uint (value); + do_reconf = (prev_width != postproc->width); + break; + } + case PROP_HEIGHT: + { + guint prev_height = postproc->height; + postproc->height = g_value_get_uint (value); + do_reconf = (prev_height != postproc->height); + break; + } +#endif + case PROP_FORCE_ASPECT_RATIO: + postproc->keep_aspect = g_value_get_boolean (value); + break; + case PROP_DEINTERLACE_MODE: + postproc->deinterlace_mode = g_value_get_enum (value); + break; + case PROP_DEINTERLACE_METHOD: + postproc->deinterlace_method = g_value_get_enum (value); + break; + case PROP_DENOISE: + postproc->denoise_level = g_value_get_float (value); + postproc->flags |= GST_VAAPI_POSTPROC_FLAG_DENOISE; + break; + case PROP_SHARPEN: + postproc->sharpen_level = g_value_get_float (value); + postproc->flags |= GST_VAAPI_POSTPROC_FLAG_SHARPEN; + break; + case PROP_HUE: + postproc->hue = g_value_get_float (value); + postproc->flags |= GST_VAAPI_POSTPROC_FLAG_HUE; + break; + case PROP_SATURATION: + postproc->saturation = g_value_get_float (value); + postproc->flags |= GST_VAAPI_POSTPROC_FLAG_SATURATION; + break; + case PROP_BRIGHTNESS: + postproc->brightness = g_value_get_float (value); + postproc->flags |= GST_VAAPI_POSTPROC_FLAG_BRIGHTNESS; + break; + case PROP_CONTRAST: + postproc->contrast = g_value_get_float (value); + postproc->flags |= GST_VAAPI_POSTPROC_FLAG_CONTRAST; + break; + case PROP_SCALE_METHOD: + postproc->scale_method = g_value_get_enum (value); + postproc->flags |= GST_VAAPI_POSTPROC_FLAG_SCALE; + break; + case PROP_VIDEO_DIRECTION: + postproc->video_direction = g_value_get_enum (value); + postproc->flags |= GST_VAAPI_POSTPROC_FLAG_VIDEO_DIRECTION; + break; +#ifndef GST_REMOVE_DEPRECATED + case PROP_SKIN_TONE_ENHANCEMENT: + postproc->skintone_enhance = g_value_get_boolean (value); + postproc->flags |= GST_VAAPI_POSTPROC_FLAG_SKINTONE; + break; +#endif + case PROP_SKIN_TONE_ENHANCEMENT_LEVEL: + postproc->skintone_value = g_value_get_uint (value); + postproc->flags |= GST_VAAPI_POSTPROC_FLAG_SKINTONE_LEVEL; + break; + case PROP_CROP_LEFT: + { + guint prev_crop_left = postproc->crop_left; + postproc->crop_left = g_value_get_uint (value); + postproc->flags |= GST_VAAPI_POSTPROC_FLAG_CROP; + do_reconf = (prev_crop_left != postproc->crop_left); + break; + } + case PROP_CROP_RIGHT: + { + guint prev_crop_right = postproc->crop_right; + postproc->crop_right = g_value_get_uint (value); + postproc->flags |= GST_VAAPI_POSTPROC_FLAG_CROP; + do_reconf = (prev_crop_right != postproc->crop_right); + break; + } + case PROP_CROP_TOP: + { + guint prev_crop_top = postproc->crop_top; + postproc->crop_top = g_value_get_uint (value); + postproc->flags |= GST_VAAPI_POSTPROC_FLAG_CROP; + do_reconf = (prev_crop_top != postproc->crop_top); + break; + } + case PROP_CROP_BOTTOM: + { + guint prev_crop_bottom = postproc->crop_bottom; + postproc->crop_bottom = g_value_get_uint (value); + postproc->flags |= GST_VAAPI_POSTPROC_FLAG_CROP; + do_reconf = (prev_crop_bottom != postproc->crop_bottom); + break; + } + case PROP_HDR_TONE_MAP: + postproc->hdr_tone_map = g_value_get_enum (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + g_mutex_unlock (&postproc->postproc_lock); + + if (do_reconf || check_filter_update (postproc)) + gst_base_transform_reconfigure_src (GST_BASE_TRANSFORM (postproc)); +} + +static void +gst_vaapipostproc_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (object); + + g_mutex_lock (&postproc->postproc_lock); + switch (prop_id) { +#ifndef GST_REMOVE_DEPRECATED + case PROP_FORMAT: + g_value_set_enum (value, postproc->format); + break; + case PROP_WIDTH: + g_value_set_uint (value, postproc->width); + break; + case PROP_HEIGHT: + g_value_set_uint (value, postproc->height); + break; +#endif + case PROP_FORCE_ASPECT_RATIO: + g_value_set_boolean (value, postproc->keep_aspect); + break; + case PROP_DEINTERLACE_MODE: + g_value_set_enum (value, postproc->deinterlace_mode); + break; + case PROP_DEINTERLACE_METHOD: + g_value_set_enum (value, postproc->deinterlace_method); + break; + case PROP_DENOISE: + g_value_set_float (value, postproc->denoise_level); + break; + case PROP_SHARPEN: + g_value_set_float (value, postproc->sharpen_level); + break; + case PROP_HUE: + g_value_set_float (value, postproc->hue); + break; + case PROP_SATURATION: + g_value_set_float (value, postproc->saturation); + break; + case PROP_BRIGHTNESS: + g_value_set_float (value, postproc->brightness); + break; + case PROP_CONTRAST: + g_value_set_float (value, postproc->contrast); + break; + case PROP_SCALE_METHOD: + g_value_set_enum (value, postproc->scale_method); + break; + case PROP_VIDEO_DIRECTION: + g_value_set_enum (value, postproc->video_direction); + break; +#ifndef GST_REMOVE_DEPRECATED + case PROP_SKIN_TONE_ENHANCEMENT: + g_value_set_boolean (value, postproc->skintone_enhance); + break; +#endif + case PROP_SKIN_TONE_ENHANCEMENT_LEVEL: + g_value_set_uint (value, postproc->skintone_value); + break; + case PROP_CROP_LEFT: + g_value_set_uint (value, postproc->crop_left); + break; + case PROP_CROP_RIGHT: + g_value_set_uint (value, postproc->crop_right); + break; + case PROP_CROP_TOP: + g_value_set_uint (value, postproc->crop_top); + break; + case PROP_CROP_BOTTOM: + g_value_set_uint (value, postproc->crop_bottom); + break; + case PROP_HDR_TONE_MAP: + g_value_set_enum (value, postproc->hdr_tone_map); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + g_mutex_unlock (&postproc->postproc_lock); +} + +static void +gst_vaapipostproc_class_init (GstVaapiPostprocClass * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstElementClass *const element_class = GST_ELEMENT_CLASS (klass); + GstBaseTransformClass *const trans_class = GST_BASE_TRANSFORM_CLASS (klass); + GPtrArray *filter_ops; + GstVaapiFilterOpInfo *filter_op; + + GST_DEBUG_CATEGORY_INIT (gst_debug_vaapipostproc, + GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC); + + gst_vaapi_plugin_base_class_init (GST_VAAPI_PLUGIN_BASE_CLASS (klass)); + + object_class->finalize = gst_vaapipostproc_finalize; + object_class->set_property = gst_vaapipostproc_set_property; + object_class->get_property = gst_vaapipostproc_get_property; + trans_class->start = gst_vaapipostproc_start; + trans_class->stop = gst_vaapipostproc_stop; + trans_class->fixate_caps = gst_vaapipostproc_fixate_caps; + trans_class->transform_caps = gst_vaapipostproc_transform_caps; + trans_class->transform_size = gst_vaapipostproc_transform_size; + trans_class->transform_meta = gst_vaapipostproc_transform_meta; + trans_class->transform = gst_vaapipostproc_transform; + trans_class->set_caps = gst_vaapipostproc_set_caps; + trans_class->query = gst_vaapipostproc_query; + trans_class->propose_allocation = gst_vaapipostproc_propose_allocation; + trans_class->decide_allocation = gst_vaapipostproc_decide_allocation; + trans_class->src_event = gst_vaapipostproc_src_event; + trans_class->sink_event = gst_vaapipostproc_sink_event; + + trans_class->prepare_output_buffer = gst_vaapipostproc_prepare_output_buffer; + + element_class->set_context = gst_vaapi_base_set_context; + gst_element_class_set_static_metadata (element_class, + "VA-API video postprocessing", + "Filter/Converter/Effect/Video/Scaler/Deinterlace/Hardware", + GST_PLUGIN_DESC, "Gwenole Beauchesne "); + + /* sink pad */ + gst_element_class_add_static_pad_template (element_class, + &gst_vaapipostproc_sink_factory); + + /* src pad */ + gst_element_class_add_static_pad_template (element_class, + &gst_vaapipostproc_src_factory); + + /** + * GstVaapiPostproc:hdr-tone-map: + * + * Selects whether HDR tone mapping should not be applied or if it + * should be only applied on content that has the HDR meta on the caps. + */ + g_object_class_install_property + (object_class, + PROP_HDR_TONE_MAP, + g_param_spec_enum ("hdr-tone-map", + "HDR Tone Map", + "Apply HDR tone mapping algorithm", + GST_VAAPI_TYPE_HDR_TONE_MAP, + GST_VAAPI_HDR_TONE_MAP_AUTO, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstVaapiPostproc:deinterlace-mode: + * + * This selects whether the deinterlacing should always be applied + * or if they should only be applied on content that has the + * "interlaced" flag on the caps. + */ + g_object_class_install_property + (object_class, + PROP_DEINTERLACE_MODE, + g_param_spec_enum ("deinterlace-mode", + "Deinterlace mode", + "Deinterlace mode to use", + GST_VAAPI_TYPE_DEINTERLACE_MODE, + DEFAULT_DEINTERLACE_MODE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstVaapiPostproc:deinterlace-method: + * + * This selects the deinterlacing method to apply. + */ + g_object_class_install_property + (object_class, + PROP_DEINTERLACE_METHOD, + g_param_spec_enum ("deinterlace-method", + "Deinterlace method", + "Deinterlace method to use", + GST_VAAPI_TYPE_DEINTERLACE_METHOD, + DEFAULT_DEINTERLACE_METHOD, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + + filter_ops = gst_vaapi_filter_get_operations (NULL); + if (!filter_ops) + return; + +#ifndef GST_REMOVE_DEPRECATED + /** + * GstVaapiPostproc:format: + * + * The forced output pixel format, expressed as a #GstVideoFormat. + */ + filter_op = find_filter_op (filter_ops, GST_VAAPI_FILTER_OP_FORMAT); + if (filter_op) + g_object_class_install_property (object_class, + PROP_FORMAT, filter_op->pspec); + + /** + * GstVaapiPostproc:width: + * + * The forced output width in pixels. If set to zero, the width is + * calculated from the height if aspect ration is preserved, or + * inherited from the sink caps width + */ + g_object_class_install_property + (object_class, + PROP_WIDTH, + g_param_spec_uint ("width", + "Width", + "Forced output width", + 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstVaapiPostproc:height: + * + * The forced output height in pixels. If set to zero, the height is + * calculated from the width if aspect ration is preserved, or + * inherited from the sink caps height + */ + g_object_class_install_property + (object_class, + PROP_HEIGHT, + g_param_spec_uint ("height", + "Height", + "Forced output height", + 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +#endif + + /** + * GstVaapiPostproc:crop-left: + * + * The number of pixels to crop at left. + */ + g_object_class_install_property + (object_class, + PROP_CROP_LEFT, + g_param_spec_uint ("crop-left", + "Crop Left", + "Pixels to crop at left", + 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstVaapiPostproc:crop-right: + * + * The number of pixels to crop at right. + */ + g_object_class_install_property + (object_class, + PROP_CROP_RIGHT, + g_param_spec_uint ("crop-right", + "Crop Right", + "Pixels to crop at right", + 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstVaapiPostproc:crop-top: + * + * The number of pixels to crop at top. + */ + g_object_class_install_property + (object_class, + PROP_CROP_TOP, + g_param_spec_uint ("crop-top", + "Crop Top", + "Pixels to crop at top", + 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstVaapiPostproc:crop-bottom: + * + * The number of pixels to crop at bottom. + */ + g_object_class_install_property + (object_class, + PROP_CROP_BOTTOM, + g_param_spec_uint ("crop-bottom", + "Crop Bottom", + "Pixels to crop at bottom", + 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstVaapiPostproc:force-aspect-ratio: + * + * When enabled, scaling respects video aspect ratio; when disabled, + * the video is distorted to fit the width and height properties. + */ + g_object_class_install_property + (object_class, + PROP_FORCE_ASPECT_RATIO, + g_param_spec_boolean ("force-aspect-ratio", + "Force aspect ratio", + "When enabled, scaling will respect original aspect ratio", + TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstVaapiPostproc:denoise: + * + * The level of noise reduction to apply. + */ + filter_op = find_filter_op (filter_ops, GST_VAAPI_FILTER_OP_DENOISE); + if (filter_op) + g_object_class_install_property (object_class, + PROP_DENOISE, filter_op->pspec); + + /** + * GstVaapiPostproc:sharpen: + * + * The level of sharpening to apply for positive values, or the + * level of blurring for negative values. + */ + filter_op = find_filter_op (filter_ops, GST_VAAPI_FILTER_OP_SHARPEN); + if (filter_op) + g_object_class_install_property (object_class, + PROP_SHARPEN, filter_op->pspec); + + /** + * GstVaapiPostproc:hue: + * + * The color hue, expressed as a float value. Range is -180.0 to + * 180.0. Default value is 0.0 and represents no modification. + */ + filter_op = find_filter_op (filter_ops, GST_VAAPI_FILTER_OP_HUE); + if (filter_op) + g_object_class_install_property (object_class, PROP_HUE, filter_op->pspec); + + /** + * GstVaapiPostproc:saturation: + * + * The color saturation, expressed as a float value. Range is 0.0 to + * 2.0. Default value is 1.0 and represents no modification. + */ + filter_op = find_filter_op (filter_ops, GST_VAAPI_FILTER_OP_SATURATION); + if (filter_op) + g_object_class_install_property (object_class, + PROP_SATURATION, filter_op->pspec); + + /** + * GstVaapiPostproc:brightness: + * + * The color brightness, expressed as a float value. Range is -1.0 + * to 1.0. Default value is 0.0 and represents no modification. + */ + filter_op = find_filter_op (filter_ops, GST_VAAPI_FILTER_OP_BRIGHTNESS); + if (filter_op) + g_object_class_install_property (object_class, + PROP_BRIGHTNESS, filter_op->pspec); + + /** + * GstVaapiPostproc:contrast: + * + * The color contrast, expressed as a float value. Range is 0.0 to + * 2.0. Default value is 1.0 and represents no modification. + */ + filter_op = find_filter_op (filter_ops, GST_VAAPI_FILTER_OP_CONTRAST); + if (filter_op) + g_object_class_install_property (object_class, + PROP_CONTRAST, filter_op->pspec); + + /** + * GstVaapiPostproc:scale-method: + * + * The scaling method to use, expressed as an enum value. See + * #GstVaapiScaleMethod. + */ + filter_op = find_filter_op (filter_ops, GST_VAAPI_FILTER_OP_SCALING); + if (filter_op) + g_object_class_install_property (object_class, + PROP_SCALE_METHOD, filter_op->pspec); + + /** + * GstVaapiPostproc:video-direction: + * + * The video-direction to use, expressed as an enum value. See + * #GstVideoDirection. + */ + filter_op = find_filter_op (filter_ops, GST_VAAPI_FILTER_OP_VIDEO_DIRECTION); + if (filter_op) + g_object_class_install_property (object_class, + PROP_VIDEO_DIRECTION, filter_op->pspec); + +#ifndef GST_REMOVE_DEPRECATED + /** + * GstVaapiPostproc:skin-tone-enhancement: + * + * Apply the skin tone enhancement algorithm. + */ + filter_op = find_filter_op (filter_ops, GST_VAAPI_FILTER_OP_SKINTONE); + if (filter_op) + g_object_class_install_property (object_class, + PROP_SKIN_TONE_ENHANCEMENT, filter_op->pspec); +#endif + + /** + * GstVaapiPostproc:skin-tone-enhancement-setting: + * + * Apply the skin tone enhancement algorithm with specified value. + */ + filter_op = find_filter_op (filter_ops, GST_VAAPI_FILTER_OP_SKINTONE_LEVEL); + if (filter_op) + g_object_class_install_property (object_class, + PROP_SKIN_TONE_ENHANCEMENT_LEVEL, filter_op->pspec); + + g_ptr_array_unref (filter_ops); +} + +static float * +find_value_ptr (GstVaapiPostproc * postproc, GstVaapiFilterOp op) +{ + switch (op) { + case GST_VAAPI_FILTER_OP_HUE: + return &postproc->hue; + case GST_VAAPI_FILTER_OP_SATURATION: + return &postproc->saturation; + case GST_VAAPI_FILTER_OP_BRIGHTNESS: + return &postproc->brightness; + case GST_VAAPI_FILTER_OP_CONTRAST: + return &postproc->contrast; + default: + return NULL; + } +} + +static void +cb_set_default_value (GstVaapiPostproc * postproc, GPtrArray * filter_ops, + GstVaapiFilterOp op) +{ + GstVaapiFilterOpInfo *filter_op; + GParamSpecFloat *pspec; + float *var; + + filter_op = find_filter_op (filter_ops, op); + if (!filter_op) + return; + var = find_value_ptr (postproc, op); + if (!var) + return; + pspec = G_PARAM_SPEC_FLOAT (filter_op->pspec); + *var = pspec->default_value; +} + +static void +skintone_set_default_value (GstVaapiPostproc * postproc, GPtrArray * filter_ops) +{ + GstVaapiFilterOpInfo *filter_op; + GParamSpecUInt *pspec; + + filter_op = find_filter_op (filter_ops, GST_VAAPI_FILTER_OP_SKINTONE_LEVEL); + if (!filter_op) + return; + pspec = G_PARAM_SPEC_UINT (filter_op->pspec); + postproc->skintone_value = pspec->default_value; +} + +static void +gst_vaapipostproc_init (GstVaapiPostproc * postproc) +{ + GPtrArray *filter_ops; + guint i; + + gst_vaapi_plugin_base_init (GST_VAAPI_PLUGIN_BASE (postproc), + GST_CAT_DEFAULT); + + g_mutex_init (&postproc->postproc_lock); + postproc->format = DEFAULT_FORMAT; + postproc->hdr_tone_map = GST_VAAPI_HDR_TONE_MAP_AUTO; + postproc->deinterlace_mode = DEFAULT_DEINTERLACE_MODE; + postproc->deinterlace_method = DEFAULT_DEINTERLACE_METHOD; + postproc->field_duration = GST_CLOCK_TIME_NONE; + postproc->keep_aspect = TRUE; + postproc->get_va_surfaces = TRUE; + postproc->forward_crop = FALSE; + + /* AUTO is not valid for tag_video_direction, this is just to + * ensure we setup the method as sink event tag */ + postproc->tag_video_direction = GST_VIDEO_ORIENTATION_AUTO; + + filter_ops = gst_vaapi_filter_get_operations (NULL); + if (filter_ops) { + for (i = GST_VAAPI_FILTER_OP_HUE; i <= GST_VAAPI_FILTER_OP_CONTRAST; i++) + cb_set_default_value (postproc, filter_ops, i); + + skintone_set_default_value (postproc, filter_ops); + g_ptr_array_unref (filter_ops); + } + + gst_video_info_init (&postproc->sinkpad_info); + gst_video_info_init (&postproc->srcpad_info); + gst_video_info_init (&postproc->filter_pool_info); +} + +/* ------------------------------------------------------------------------ */ +/* --- GstColorBalance interface --- */ +/* ------------------------------------------------------------------------ */ + +#define CB_CHANNEL_FACTOR 1000.0 + +typedef struct +{ + GstVaapiFilterOp op; + const gchar *name; +} ColorBalanceChannel; + +ColorBalanceChannel cb_channels[] = { + { + GST_VAAPI_FILTER_OP_HUE, "VA_FILTER_HUE"}, { + GST_VAAPI_FILTER_OP_SATURATION, "VA_FILTER_SATURATION"}, { + GST_VAAPI_FILTER_OP_BRIGHTNESS, "VA_FILTER_BRIGHTNESS"}, { + GST_VAAPI_FILTER_OP_CONTRAST, "VA_FILTER_CONTRAST"}, +}; + +static void +cb_channels_init (GstVaapiPostproc * postproc) +{ + GPtrArray *filter_ops; + GstVaapiFilterOpInfo *filter_op; + GParamSpecFloat *pspec; + GstColorBalanceChannel *channel; + guint i; + + if (postproc->cb_channels) + return; + + g_mutex_lock (&postproc->postproc_lock); + if (!gst_vaapipostproc_ensure_filter (postproc)) { + g_mutex_unlock (&postproc->postproc_lock); + return; + } + g_mutex_unlock (&postproc->postproc_lock); + + filter_ops = postproc->filter_ops ? g_ptr_array_ref (postproc->filter_ops) + : gst_vaapi_filter_get_operations (postproc->filter); + if (!filter_ops) + return; + + for (i = 0; i < G_N_ELEMENTS (cb_channels); i++) { + filter_op = find_filter_op (filter_ops, cb_channels[i].op); + if (!filter_op) + continue; + + pspec = G_PARAM_SPEC_FLOAT (filter_op->pspec); + channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL); + channel->label = g_strdup (cb_channels[i].name); + channel->min_value = pspec->minimum * CB_CHANNEL_FACTOR; + channel->max_value = pspec->maximum * CB_CHANNEL_FACTOR; + + postproc->cb_channels = g_list_prepend (postproc->cb_channels, channel); + } + + g_ptr_array_unref (filter_ops); +} + +static const GList * +gst_vaapipostproc_colorbalance_list_channels (GstColorBalance * balance) +{ + GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (balance); + + cb_channels_init (postproc); + return postproc->cb_channels; +} + +static gfloat * +cb_get_value_ptr (GstVaapiPostproc * postproc, + GstColorBalanceChannel * channel, GstVaapiPostprocFlags * flags) +{ + guint i; + gfloat *ret = NULL; + + for (i = 0; i < G_N_ELEMENTS (cb_channels); i++) { + if (g_ascii_strcasecmp (cb_channels[i].name, channel->label) == 0) + break; + } + if (i >= G_N_ELEMENTS (cb_channels)) + return NULL; + + ret = find_value_ptr (postproc, cb_channels[i].op); + if (flags) + *flags = 1 << cb_channels[i].op; + return ret; +} + +static void +gst_vaapipostproc_colorbalance_set_value (GstColorBalance * balance, + GstColorBalanceChannel * channel, gint value) +{ + GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (balance); + GstVaapiPostprocFlags flags; + gfloat new_val, *var; + + value = CLAMP (value, channel->min_value, channel->max_value); + new_val = (gfloat) value / CB_CHANNEL_FACTOR; + + var = cb_get_value_ptr (postproc, channel, &flags); + if (var) { + *var = new_val; + g_mutex_lock (&postproc->postproc_lock); + postproc->flags |= flags; + g_mutex_unlock (&postproc->postproc_lock); + gst_color_balance_value_changed (balance, channel, value); + if (check_filter_update (postproc)) + gst_base_transform_reconfigure_src (GST_BASE_TRANSFORM (postproc)); + return; + } + + GST_WARNING_OBJECT (postproc, "unknown channel %s", channel->label); +} + +static gint +gst_vaapipostproc_colorbalance_get_value (GstColorBalance * balance, + GstColorBalanceChannel * channel) +{ + GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (balance); + gfloat *var; + gint new_val; + + var = cb_get_value_ptr (postproc, channel, NULL); + if (var) { + new_val = (gint) ((*var) * CB_CHANNEL_FACTOR); + new_val = CLAMP (new_val, channel->min_value, channel->max_value); + return new_val; + } + + GST_WARNING_OBJECT (postproc, "unknown channel %s", channel->label); + return G_MININT; +} + +static GstColorBalanceType +gst_vaapipostproc_colorbalance_get_balance_type (GstColorBalance * balance) +{ + return GST_COLOR_BALANCE_HARDWARE; +} + +static void +gst_vaapipostproc_colorbalance_init (gpointer iface, gpointer data) +{ + GstColorBalanceInterface *cbface = iface; + cbface->list_channels = gst_vaapipostproc_colorbalance_list_channels; + cbface->set_value = gst_vaapipostproc_colorbalance_set_value; + cbface->get_value = gst_vaapipostproc_colorbalance_get_value; + cbface->get_balance_type = gst_vaapipostproc_colorbalance_get_balance_type; +} diff --git a/gst/vaapi/gstvaapipostproc.h b/gst/vaapi/gstvaapipostproc.h new file mode 100644 index 0000000000..9a0d52d5a9 --- /dev/null +++ b/gst/vaapi/gstvaapipostproc.h @@ -0,0 +1,230 @@ +/* + * gstvaapipostproc.h - VA-API video post processing + * + * Copyright (C) 2012-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This program 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA +*/ + +#ifndef GST_VAAPIPOSTPROC_H +#define GST_VAAPIPOSTPROC_H + +#include "gstvaapipluginbase.h" +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPIPOSTPROC \ + (gst_vaapipostproc_get_type ()) +#define GST_VAAPIPOSTPROC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPIPOSTPROC, GstVaapiPostproc)) +#define GST_VAAPIPOSTPROC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPIPOSTPROC, \ + GstVaapiPostprocClass)) +#define GST_IS_VAAPIPOSTPROC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_VAAPIPOSTPROC)) +#define GST_IS_VAAPIPOSTPROC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_VAAPIPOSTPROC)) +#define GST_VAAPIPOSTPROC_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_VAAPIPOSTPROC, \ + GstVaapiPostprocClass)) + +typedef struct _GstVaapiPostproc GstVaapiPostproc; +typedef struct _GstVaapiPostprocClass GstVaapiPostprocClass; +typedef struct _GstVaapiDeinterlaceState GstVaapiDeinterlaceState; + +/** + * GstVaapiHDRToneMap: + * @GST_VAAPI_TYPE_HDR_TONE_MAP_AUTO: Auto detect need for hdr tone map. + * @GST_VAAPI_TYPE_HDR_TONE_MAP_DISABLED: Never perform hdr tone map. + */ +typedef enum +{ + GST_VAAPI_HDR_TONE_MAP_AUTO = 0, + GST_VAAPI_HDR_TONE_MAP_DISABLED, +} GstVaapiHDRToneMap; + +/** + * GstVaapiDeinterlaceMode: + * @GST_VAAPI_DEINTERLACE_MODE_AUTO: Auto detect needs for deinterlacing. + * @GST_VAAPI_DEINTERLACE_MODE_INTERLACED: Force deinterlacing. + * @GST_VAAPI_DEINTERLACE_MODE_DISABLED: Never perform deinterlacing. + */ +typedef enum +{ + GST_VAAPI_DEINTERLACE_MODE_AUTO = 0, + GST_VAAPI_DEINTERLACE_MODE_INTERLACED, + GST_VAAPI_DEINTERLACE_MODE_DISABLED, +} GstVaapiDeinterlaceMode; + +/* + * GST_VAAPI_DEINTERLACE_MAX_REFERENCES: + * + * This represents the maximum number of VA surfaces we could keep as + * references for advanced deinterlacing. + * + * Note: if the upstream element is vaapidecode, then the maximum + * number of allowed surfaces used as references shall be less than + * the actual number of scratch surfaces used for decoding (4). + */ +#define GST_VAAPI_DEINTERLACE_MAX_REFERENCES 2 + +/** + * GstVaapiPostprocFlags: + * @GST_VAAPI_POSTPROC_FLAG_FORMAT: Pixel format conversion. + * @GST_VAAPI_POSTPROC_FLAG_DENOISE: Noise reduction. + * @GST_VAAPI_POSTPROC_FLAG_SHARPEN: Sharpening. + * @GST_VAAPI_POSTPROC_FLAG_HUE: Change color hue. + * @GST_VAAPI_POSTPROC_FLAG_SATURATION: Change saturation. + * @GST_VAAPI_POSTPROC_FLAG_BRIGHTNESS: Change brightness. + * @GST_VAAPI_POSTPROC_FLAG_CONTRAST: Change contrast. + * @GST_VAAPI_POSTPROC_FLAG_DEINTERLACE: Deinterlacing. + * @GST_VAAPI_POSTPROC_FLAG_SIZE: Video scaling. + * @GST_VAAPI_POSTPROC_FLAG_SCALE: Video scaling mode. + * @GST_VAAPI_POSTPROC_FLAG_VIDEO_DIRECTION: Video rotation and flip/mirroring. + * @GST_VAAPI_POSTPROC_FLAG_HDR_TONE_MAP: HDR tone mapping. + * @GST_VAAPI_POSTPROC_FLAG_SKINTONE: Skin tone enhancement. + * @GST_VAAPI_POSTPROC_FLAG_SKINTONE_LEVEL: Skin tone enhancement with value. + * + * The set of operations that are to be performed for each frame. + */ +typedef enum +{ + GST_VAAPI_POSTPROC_FLAG_FORMAT = 1 << GST_VAAPI_FILTER_OP_FORMAT, + GST_VAAPI_POSTPROC_FLAG_DENOISE = 1 << GST_VAAPI_FILTER_OP_DENOISE, + GST_VAAPI_POSTPROC_FLAG_SHARPEN = 1 << GST_VAAPI_FILTER_OP_SHARPEN, + GST_VAAPI_POSTPROC_FLAG_HUE = 1 << GST_VAAPI_FILTER_OP_HUE, + GST_VAAPI_POSTPROC_FLAG_SATURATION = 1 << GST_VAAPI_FILTER_OP_SATURATION, + GST_VAAPI_POSTPROC_FLAG_BRIGHTNESS = 1 << GST_VAAPI_FILTER_OP_BRIGHTNESS, + GST_VAAPI_POSTPROC_FLAG_CONTRAST = 1 << GST_VAAPI_FILTER_OP_CONTRAST, + GST_VAAPI_POSTPROC_FLAG_DEINTERLACE = 1 << GST_VAAPI_FILTER_OP_DEINTERLACING, + GST_VAAPI_POSTPROC_FLAG_SCALE = 1 << GST_VAAPI_FILTER_OP_SCALING, + GST_VAAPI_POSTPROC_FLAG_VIDEO_DIRECTION = + 1 << GST_VAAPI_FILTER_OP_VIDEO_DIRECTION, + GST_VAAPI_POSTPROC_FLAG_CROP = 1 << GST_VAAPI_FILTER_OP_CROP, + GST_VAAPI_POSTPROC_FLAG_HDR_TONE_MAP = 1 << GST_VAAPI_FILTER_OP_HDR_TONE_MAP, +#ifndef GST_REMOVE_DEPRECATED + GST_VAAPI_POSTPROC_FLAG_SKINTONE = 1 << GST_VAAPI_FILTER_OP_SKINTONE, +#endif + GST_VAAPI_POSTPROC_FLAG_SKINTONE_LEVEL = + 1 << GST_VAAPI_FILTER_OP_SKINTONE_LEVEL, + + /* Additional custom flags */ + GST_VAAPI_POSTPROC_FLAG_CUSTOM = 1 << 20, + GST_VAAPI_POSTPROC_FLAG_SIZE = GST_VAAPI_POSTPROC_FLAG_CUSTOM, +} GstVaapiPostprocFlags; + +/* + * GstVaapiDeinterlaceState: + * @buffers: history buffer, maintained as a cyclic array + * @buffers_index: next free slot in the history buffer + * @surfaces: array of surfaces used as references + * @num_surfaces: number of active surfaces in that array + * @deint: flag: previous buffers were interlaced? + * @tff: flag: previous buffers were organized as top-field-first? + * + * Context used to maintain deinterlacing state. + */ +struct _GstVaapiDeinterlaceState +{ + GstBuffer *buffers[GST_VAAPI_DEINTERLACE_MAX_REFERENCES]; + guint buffers_index; + GstVaapiSurface *surfaces[GST_VAAPI_DEINTERLACE_MAX_REFERENCES]; + guint num_surfaces; + guint deint:1; + guint tff:1; +}; + +struct _GstVaapiPostproc +{ + /*< private >*/ + GstVaapiPluginBase parent_instance; + + GMutex postproc_lock; + GstVaapiFilter *filter; + GPtrArray *filter_ops; + GstVaapiVideoPool *filter_pool; + GstVideoInfo filter_pool_info; + GArray *filter_formats; + GstVideoFormat format; /* output video format (encoded) */ + guint width; + guint height; + guint flags; + + GstCaps *allowed_sinkpad_caps; + GstVideoInfo sinkpad_info; + GstCaps *allowed_srcpad_caps; + GstVideoInfo srcpad_info; + + /* HDR Tone Mapping */ + GstVaapiHDRToneMap hdr_tone_map; + + /* Deinterlacing */ + GstVaapiDeinterlaceMode deinterlace_mode; + GstVaapiDeinterlaceMethod deinterlace_method; + GstVaapiDeinterlaceState deinterlace_state; + GstClockTime field_duration; + + /* Basic filter values */ + gfloat denoise_level; + gfloat sharpen_level; + + GstVaapiScaleMethod scale_method; + + GstVideoOrientationMethod video_direction; + GstVideoOrientationMethod tag_video_direction; + + /* Cropping */ + guint crop_left; + guint crop_right; + guint crop_top; + guint crop_bottom; + + /* Color balance filter values */ + gfloat hue; + gfloat saturation; + gfloat brightness; + gfloat contrast; + + gboolean skintone_enhance; + guint skintone_value; + gboolean forward_crop; + + guint get_va_surfaces:1; + guint has_vpp:1; + guint use_vpp:1; + guint keep_aspect:1; + + /* color balance's channel list */ + GList *cb_channels; + gboolean same_caps; +}; + +struct _GstVaapiPostprocClass +{ + /*< private >*/ + GstVaapiPluginBaseClass parent_class; +}; + +GType +gst_vaapipostproc_get_type (void) G_GNUC_CONST; + +G_END_DECLS + +#endif /* GST_VAAPIPOSTPROC_H */ diff --git a/gst/vaapi/gstvaapipostprocutil.c b/gst/vaapi/gstvaapipostprocutil.c new file mode 100644 index 0000000000..715a449e4c --- /dev/null +++ b/gst/vaapi/gstvaapipostprocutil.c @@ -0,0 +1,786 @@ +/* + * gstvaapipostprocutil.h - VA-API video post processing utilities + * + * Copyright (C) <1999> Erik Walthinsen + * Copyright (C) 2005-2012 David Schleef + * Copyright (C) 2016 Intel Corporation + * Author: Gwenole Beauchesne + * Author: Victor Jaquez + * + * This program 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include + +#include "gstvaapipostprocutil.h" +#include "gstvaapipluginutil.h" + +#define GST_CAT_DEFAULT (GST_VAAPI_PLUGIN_BASE (postproc)->debug_category) + +/* if format property is set */ +static void +_transform_format (GstVaapiPostproc * postproc, GstCapsFeatures * features, + GstStructure * structure) +{ + GValue value = G_VALUE_INIT; + + if (postproc->format == DEFAULT_FORMAT) + return; + + if (!gst_caps_features_is_equal (features, + GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY) + && !gst_caps_features_contains (features, + GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE)) + return; + + if (!gst_vaapi_value_set_format (&value, postproc->format)) + return; + + gst_structure_set_value (structure, "format", &value); + g_value_unset (&value); +} + +static void +_set_int (GValue * value, gint val) +{ + g_value_init (value, G_TYPE_INT); + g_value_set_int (value, val); +} + +static void +_set_int_range (GValue * value) +{ + g_value_init (value, GST_TYPE_INT_RANGE); + gst_value_set_int_range (value, 1, G_MAXINT); +} + +static void +_transform_frame_size (GstVaapiPostproc * postproc, GstStructure * structure) +{ + GValue width = G_VALUE_INIT; + GValue height = G_VALUE_INIT; + + if (postproc->width && postproc->height) { + _set_int (&width, postproc->width); + _set_int (&height, postproc->height); + } else if (postproc->width) { + _set_int (&width, postproc->width); + _set_int_range (&height); + } else if (postproc->height) { + _set_int_range (&width); + _set_int (&height, postproc->height); + } else { + _set_int_range (&width); + _set_int_range (&height); + } + + gst_structure_set_value (structure, "width", &width); + gst_structure_set_value (structure, "height", &height); +} + +/** + * gst_vaapipostproc_transform_srccaps: + * @postproc: a #GstVaapiPostproc instance + * + * Early apply transformation of the src pad caps according to the set + * properties. + * + * Returns: A new allocated #GstCaps + **/ +GstCaps * +gst_vaapipostproc_transform_srccaps (GstVaapiPostproc * postproc) +{ + GstCaps *out_caps; + GstStructure *structure; + GstCapsFeatures *features; + gint i, n; + + out_caps = gst_caps_new_empty (); + n = gst_caps_get_size (postproc->allowed_srcpad_caps); + + for (i = 0; i < n; i++) { + structure = gst_caps_get_structure (postproc->allowed_srcpad_caps, i); + features = gst_caps_get_features (postproc->allowed_srcpad_caps, i); + + /* make copy */ + structure = gst_structure_copy (structure); + + if (postproc->keep_aspect) + gst_structure_set (structure, "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, + 1, NULL); + + _transform_format (postproc, features, structure); + _transform_frame_size (postproc, structure); + + gst_caps_append_structure_full (out_caps, structure, + gst_caps_features_copy (features)); + } + + return out_caps; +} + +gboolean +is_deinterlace_enabled (GstVaapiPostproc * postproc, GstVideoInfo * vip) +{ + gboolean deinterlace; + + switch (postproc->deinterlace_mode) { + case GST_VAAPI_DEINTERLACE_MODE_AUTO: + deinterlace = GST_VIDEO_INFO_IS_INTERLACED (vip); + break; + case GST_VAAPI_DEINTERLACE_MODE_INTERLACED: + deinterlace = TRUE; + break; + default: + deinterlace = FALSE; + break; + } + return deinterlace; +} + +static gboolean +_fixate_frame_size (GstVaapiPostproc * postproc, GstVideoInfo * vinfo, + GstStructure * outs) +{ + const GValue *to_par; + GValue tpar = G_VALUE_INIT; + gboolean ret; + + ret = TRUE; + to_par = gst_structure_get_value (outs, "pixel-aspect-ratio"); + if (!to_par) { + g_value_init (&tpar, GST_TYPE_FRACTION_RANGE); + gst_value_set_fraction_range_full (&tpar, 1, G_MAXINT, G_MAXINT, 1); + to_par = &tpar; + } + + /* we have both PAR but they might not be fixated */ + { + gint from_w, from_h, from_par_n, from_par_d, to_par_n, to_par_d; + gint w = 0, h = 0; + gint from_dar_n, from_dar_d; + gint num, den; + + from_par_n = GST_VIDEO_INFO_PAR_N (vinfo); + from_par_d = GST_VIDEO_INFO_PAR_D (vinfo); + from_w = GST_VIDEO_INFO_WIDTH (vinfo); + from_h = GST_VIDEO_INFO_HEIGHT (vinfo); + + if (postproc->has_vpp) { + /* adjust for crop settings */ + from_w -= postproc->crop_left + postproc->crop_right; + from_h -= postproc->crop_top + postproc->crop_bottom; + + /* compensate for rotation if needed */ + switch (gst_vaapi_filter_get_video_direction (postproc->filter)) { + case GST_VIDEO_ORIENTATION_90R: + case GST_VIDEO_ORIENTATION_90L: + case GST_VIDEO_ORIENTATION_UL_LR: + case GST_VIDEO_ORIENTATION_UR_LL: + G_PRIMITIVE_SWAP (gint, from_w, from_h); + G_PRIMITIVE_SWAP (gint, from_par_n, from_par_d); + default: + break; + } + } + + gst_structure_get_int (outs, "width", &w); + gst_structure_get_int (outs, "height", &h); + + /* if both width and height are already fixed, we can't do anything + * about it anymore */ + if (w && h) { + guint n, d; + + GST_DEBUG_OBJECT (postproc, + "dimensions already set to %dx%d, not fixating", w, h); + + if (!gst_value_is_fixed (to_par)) { + if (gst_video_calculate_display_ratio (&n, &d, from_w, from_h, + from_par_n, from_par_d, w, h)) { + GST_DEBUG_OBJECT (postproc, "fixating to_par to %dx%d", n, d); + if (gst_structure_has_field (outs, "pixel-aspect-ratio")) + gst_structure_fixate_field_nearest_fraction (outs, + "pixel-aspect-ratio", n, d); + else if (n != d) + gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION, + n, d, NULL); + } + } + + goto done; + } + + /* Calculate input DAR */ + if (!gst_util_fraction_multiply (from_w, from_h, from_par_n, from_par_d, + &from_dar_n, &from_dar_d)) + goto overflow_error; + + GST_DEBUG_OBJECT (postproc, "Input DAR is %d/%d", from_dar_n, from_dar_d); + + /* If either width or height are fixed there's not much we + * can do either except choosing a height or width and PAR + * that matches the DAR as good as possible + */ + if (h) { + GstStructure *tmp; + gint set_w, set_par_n, set_par_d; + + GST_DEBUG_OBJECT (postproc, "height is fixed (%d)", h); + + /* If the PAR is fixed too, there's not much to do + * except choosing the width that is nearest to the + * width with the same DAR */ + if (gst_value_is_fixed (to_par)) { + to_par_n = gst_value_get_fraction_numerator (to_par); + to_par_d = gst_value_get_fraction_denominator (to_par); + + GST_DEBUG_OBJECT (postproc, "PAR is fixed %d/%d", to_par_n, to_par_d); + + if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, to_par_d, + to_par_n, &num, &den)) + goto overflow_error; + + w = (guint) gst_util_uint64_scale_int (h, num, den); + gst_structure_fixate_field_nearest_int (outs, "width", w); + + goto done; + } + + /* The PAR is not fixed and it's quite likely that we can set + * an arbitrary PAR. */ + + /* Check if we can keep the input width */ + tmp = gst_structure_copy (outs); + gst_structure_fixate_field_nearest_int (tmp, "width", from_w); + gst_structure_get_int (tmp, "width", &set_w); + + /* Might have failed but try to keep the DAR nonetheless by + * adjusting the PAR */ + if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, h, set_w, + &to_par_n, &to_par_d)) { + gst_structure_free (tmp); + goto overflow_error; + } + + if (!gst_structure_has_field (tmp, "pixel-aspect-ratio")) + gst_structure_set_value (tmp, "pixel-aspect-ratio", to_par); + gst_structure_fixate_field_nearest_fraction (tmp, "pixel-aspect-ratio", + to_par_n, to_par_d); + gst_structure_get_fraction (tmp, "pixel-aspect-ratio", &set_par_n, + &set_par_d); + gst_structure_free (tmp); + + /* Check if the adjusted PAR is accepted */ + if (set_par_n == to_par_n && set_par_d == to_par_d) { + if (gst_structure_has_field (outs, "pixel-aspect-ratio") || + set_par_n != set_par_d) + gst_structure_set (outs, "width", G_TYPE_INT, set_w, + "pixel-aspect-ratio", GST_TYPE_FRACTION, set_par_n, set_par_d, + NULL); + goto done; + } + + /* Otherwise scale the width to the new PAR and check if the + * adjusted with is accepted. If all that fails we can't keep + * the DAR */ + if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_par_d, + set_par_n, &num, &den)) + goto overflow_error; + + w = (guint) gst_util_uint64_scale_int (h, num, den); + gst_structure_fixate_field_nearest_int (outs, "width", w); + if (gst_structure_has_field (outs, "pixel-aspect-ratio") || + set_par_n != set_par_d) + gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION, + set_par_n, set_par_d, NULL); + + goto done; + } else if (w) { + GstStructure *tmp; + gint set_h, set_par_n, set_par_d; + + GST_DEBUG_OBJECT (postproc, "width is fixed (%d)", w); + + /* If the PAR is fixed too, there's not much to do + * except choosing the height that is nearest to the + * height with the same DAR */ + if (gst_value_is_fixed (to_par)) { + to_par_n = gst_value_get_fraction_numerator (to_par); + to_par_d = gst_value_get_fraction_denominator (to_par); + + GST_DEBUG_OBJECT (postproc, "PAR is fixed %d/%d", to_par_n, to_par_d); + + if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, to_par_d, + to_par_n, &num, &den)) + goto overflow_error; + + h = (guint) gst_util_uint64_scale_int (w, den, num); + gst_structure_fixate_field_nearest_int (outs, "height", h); + + goto done; + } + + /* The PAR is not fixed and it's quite likely that we can set + * an arbitrary PAR. */ + + /* Check if we can keep the input height */ + tmp = gst_structure_copy (outs); + gst_structure_fixate_field_nearest_int (tmp, "height", from_h); + gst_structure_get_int (tmp, "height", &set_h); + + /* Might have failed but try to keep the DAR nonetheless by + * adjusting the PAR */ + if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_h, w, + &to_par_n, &to_par_d)) { + gst_structure_free (tmp); + goto overflow_error; + } + + if (!gst_structure_has_field (tmp, "pixel-aspect-ratio")) + gst_structure_set_value (tmp, "pixel-aspect-ratio", to_par); + gst_structure_fixate_field_nearest_fraction (tmp, "pixel-aspect-ratio", + to_par_n, to_par_d); + gst_structure_get_fraction (tmp, "pixel-aspect-ratio", &set_par_n, + &set_par_d); + gst_structure_free (tmp); + + /* Check if the adjusted PAR is accepted */ + if (set_par_n == to_par_n && set_par_d == to_par_d) { + if (gst_structure_has_field (outs, "pixel-aspect-ratio") || + set_par_n != set_par_d) + gst_structure_set (outs, "height", G_TYPE_INT, set_h, + "pixel-aspect-ratio", GST_TYPE_FRACTION, set_par_n, set_par_d, + NULL); + goto done; + } + + /* Otherwise scale the height to the new PAR and check if the + * adjusted with is accepted. If all that fails we can't keep + * the DAR */ + if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_par_d, + set_par_n, &num, &den)) + goto overflow_error; + + h = (guint) gst_util_uint64_scale_int (w, den, num); + gst_structure_fixate_field_nearest_int (outs, "height", h); + if (gst_structure_has_field (outs, "pixel-aspect-ratio") || + set_par_n != set_par_d) + gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION, + set_par_n, set_par_d, NULL); + + goto done; + } else if (gst_value_is_fixed (to_par)) { + GstStructure *tmp; + gint set_h, set_w, f_h, f_w; + + to_par_n = gst_value_get_fraction_numerator (to_par); + to_par_d = gst_value_get_fraction_denominator (to_par); + + /* Calculate scale factor for the PAR change */ + if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, to_par_n, + to_par_d, &num, &den)) + goto overflow_error; + + /* Try to keep the input height (because of interlacing) */ + tmp = gst_structure_copy (outs); + gst_structure_fixate_field_nearest_int (tmp, "height", from_h); + gst_structure_get_int (tmp, "height", &set_h); + + /* This might have failed but try to scale the width + * to keep the DAR nonetheless */ + w = (guint) gst_util_uint64_scale_int (set_h, num, den); + gst_structure_fixate_field_nearest_int (tmp, "width", w); + gst_structure_get_int (tmp, "width", &set_w); + gst_structure_free (tmp); + + /* We kept the DAR and the height is nearest to the original height */ + if (set_w == w) { + gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height", + G_TYPE_INT, set_h, NULL); + goto done; + } + + f_h = set_h; + f_w = set_w; + + /* If the former failed, try to keep the input width at least */ + tmp = gst_structure_copy (outs); + gst_structure_fixate_field_nearest_int (tmp, "width", from_w); + gst_structure_get_int (tmp, "width", &set_w); + + /* This might have failed but try to scale the width + * to keep the DAR nonetheless */ + h = (guint) gst_util_uint64_scale_int (set_w, den, num); + gst_structure_fixate_field_nearest_int (tmp, "height", h); + gst_structure_get_int (tmp, "height", &set_h); + gst_structure_free (tmp); + + /* We kept the DAR and the width is nearest to the original width */ + if (set_h == h) { + gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height", + G_TYPE_INT, set_h, NULL); + goto done; + } + + /* If all this failed, keep the height that was nearest to the orignal + * height and the nearest possible width. This changes the DAR but + * there's not much else to do here. + */ + gst_structure_set (outs, "width", G_TYPE_INT, f_w, "height", G_TYPE_INT, + f_h, NULL); + goto done; + } else { + GstStructure *tmp; + gint set_h, set_w, set_par_n, set_par_d, tmp2; + + /* width, height and PAR are not fixed but passthrough is not possible */ + + /* First try to keep the height and width as good as possible + * and scale PAR */ + tmp = gst_structure_copy (outs); + gst_structure_fixate_field_nearest_int (tmp, "height", from_h); + gst_structure_get_int (tmp, "height", &set_h); + gst_structure_fixate_field_nearest_int (tmp, "width", from_w); + gst_structure_get_int (tmp, "width", &set_w); + + if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_h, set_w, + &to_par_n, &to_par_d)) { + gst_structure_free (tmp); + goto overflow_error; + } + + if (!gst_structure_has_field (tmp, "pixel-aspect-ratio")) + gst_structure_set_value (tmp, "pixel-aspect-ratio", to_par); + gst_structure_fixate_field_nearest_fraction (tmp, "pixel-aspect-ratio", + to_par_n, to_par_d); + gst_structure_get_fraction (tmp, "pixel-aspect-ratio", &set_par_n, + &set_par_d); + gst_structure_free (tmp); + + if (set_par_n == to_par_n && set_par_d == to_par_d) { + gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height", + G_TYPE_INT, set_h, NULL); + + if (gst_structure_has_field (outs, "pixel-aspect-ratio") || + set_par_n != set_par_d) + gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION, + set_par_n, set_par_d, NULL); + goto done; + } + + /* Otherwise try to scale width to keep the DAR with the set + * PAR and height */ + if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_par_d, + set_par_n, &num, &den)) + goto overflow_error; + + w = (guint) gst_util_uint64_scale_int (set_h, num, den); + tmp = gst_structure_copy (outs); + gst_structure_fixate_field_nearest_int (tmp, "width", w); + gst_structure_get_int (tmp, "width", &tmp2); + gst_structure_free (tmp); + + if (tmp2 == w) { + gst_structure_set (outs, "width", G_TYPE_INT, tmp2, "height", + G_TYPE_INT, set_h, NULL); + if (gst_structure_has_field (outs, "pixel-aspect-ratio") || + set_par_n != set_par_d) + gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION, + set_par_n, set_par_d, NULL); + goto done; + } + + /* ... or try the same with the height */ + h = (guint) gst_util_uint64_scale_int (set_w, den, num); + tmp = gst_structure_copy (outs); + gst_structure_fixate_field_nearest_int (tmp, "height", h); + gst_structure_get_int (tmp, "height", &tmp2); + gst_structure_free (tmp); + + if (tmp2 == h) { + gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height", + G_TYPE_INT, tmp2, NULL); + if (gst_structure_has_field (outs, "pixel-aspect-ratio") || + set_par_n != set_par_d) + gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION, + set_par_n, set_par_d, NULL); + goto done; + } + + /* If all fails we can't keep the DAR and take the nearest values + * for everything from the first try */ + gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height", + G_TYPE_INT, set_h, NULL); + if (gst_structure_has_field (outs, "pixel-aspect-ratio") || + set_par_n != set_par_d) + gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION, + set_par_n, set_par_d, NULL); + } + } + +done: + if (to_par == &tpar) + g_value_unset (&tpar); + + return ret; + + /* ERRORS */ +overflow_error: + { + ret = FALSE; + GST_ELEMENT_ERROR (postproc, CORE, NEGOTIATION, (NULL), + ("Error calculating the output scaled size - integer overflow")); + goto done; + } +} + +static gboolean +_fixate_frame_rate (GstVaapiPostproc * postproc, GstVideoInfo * vinfo, + GstStructure * outs) +{ + gint fps_n, fps_d; + + fps_n = GST_VIDEO_INFO_FPS_N (vinfo); + fps_d = GST_VIDEO_INFO_FPS_D (vinfo); + if (is_deinterlace_enabled (postproc, vinfo)) { + if (!gst_util_fraction_multiply (fps_n, fps_d, 2, 1, &fps_n, &fps_d)) + goto overflow_error; + } + gst_structure_set (outs, "framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL); + return TRUE; + + /* ERRORS */ +overflow_error: + { + GST_ELEMENT_ERROR (postproc, CORE, NEGOTIATION, (NULL), + ("Error calculating the output framerate - integer overflow")); + return FALSE; + } +} + +static gboolean +_set_multiview_mode (GstVaapiPostproc * postproc, GstVideoInfo * vinfo, + GstStructure * outs) +{ + const gchar *caps_str; + + caps_str = + gst_video_multiview_mode_to_caps_string (GST_VIDEO_INFO_MULTIVIEW_MODE + (vinfo)); + if (!caps_str) + return TRUE; + + gst_structure_set (outs, "multiview-mode", G_TYPE_STRING, caps_str, + "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, + GST_VIDEO_INFO_MULTIVIEW_FLAGS (vinfo), GST_FLAG_SET_MASK_EXACT, NULL); + + if (GST_VIDEO_INFO_VIEWS (vinfo) > 1) { + gst_structure_set (outs, "views", G_TYPE_INT, GST_VIDEO_INFO_VIEWS (vinfo), + NULL); + } + + return TRUE; +} + +static gboolean +_set_colorimetry (GstVaapiPostproc * postproc, GstVideoInfo * sinkinfo, + GstVideoFormat format, GstStructure * outs) +{ + GstVideoInfo vinfo; + GstVideoColorimetry colorimetry; + gchar *color; + gint width, height; + + if (!gst_structure_get_int (outs, "width", &width) + || !gst_structure_get_int (outs, "height", &height)) + return FALSE; + + /* Use the sink resolution and the src format to correctly determine the + * default src colorimetry. */ + gst_video_info_set_format (&vinfo, format, GST_VIDEO_INFO_WIDTH (sinkinfo), + GST_VIDEO_INFO_HEIGHT (sinkinfo)); + + if (GST_VIDEO_INFO_CHROMA_SITE (&vinfo) != GST_VIDEO_CHROMA_SITE_UNKNOWN) { + gst_structure_set (outs, "chroma-site", G_TYPE_STRING, + gst_video_chroma_to_string (GST_VIDEO_INFO_CHROMA_SITE (&vinfo)), NULL); + } + + /* if outs structure already specifies colorimetry, use it */ + if (gst_structure_has_field (outs, "colorimetry")) + return TRUE; + + /* make sure we set the RGB matrix for RGB formats */ + colorimetry = GST_VIDEO_INFO_COLORIMETRY (&vinfo); + if (GST_VIDEO_FORMAT_INFO_IS_RGB (vinfo.finfo) && + colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_RGB) { + GST_WARNING ("invalid matrix %d for RGB format, using RGB", + colorimetry.matrix); + colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_RGB; + } + + if ((color = gst_video_colorimetry_to_string (&colorimetry))) { + gst_structure_set (outs, "colorimetry", G_TYPE_STRING, color, NULL); + g_free (color); + } + + return TRUE; +} + +static gboolean +_set_interlace_mode (GstVaapiPostproc * postproc, GstVideoInfo * vinfo, + GstStructure * outs) +{ + const gchar *interlace_mode = NULL; + + if (is_deinterlace_enabled (postproc, vinfo)) { + interlace_mode = "progressive"; + } else { + interlace_mode = + gst_video_interlace_mode_to_string (GST_VIDEO_INFO_INTERLACE_MODE + (vinfo)); + } + + if (!interlace_mode) + return FALSE; + + gst_structure_set (outs, "interlace-mode", G_TYPE_STRING, interlace_mode, + NULL); + return TRUE; +} + +static gboolean +_set_preferred_format (GstStructure * outs, GstVideoFormat format) +{ + GValue value = G_VALUE_INIT; + + if (format == GST_VIDEO_FORMAT_UNKNOWN || format == GST_VIDEO_FORMAT_ENCODED) + return FALSE; + + if (!gst_vaapi_value_set_format (&value, format)) + return FALSE; + gst_structure_set_value (outs, "format", &value); + g_value_unset (&value); + return TRUE; +} + +static GstCaps * +_get_preferred_caps (GstVaapiPostproc * postproc, GstVideoInfo * vinfo, + GstCaps * srccaps) +{ + GstPad *srcpad; + GstVideoFormat format; + GstVaapiCapsFeature f; + const gchar *feature; + GstStructure *structure; + GstCapsFeatures *features; + GstCaps *outcaps; + gint i, n; + + format = GST_VIDEO_FORMAT_UNKNOWN; + srcpad = GST_BASE_TRANSFORM_SRC_PAD (postproc); + f = gst_vaapi_find_preferred_caps_feature (srcpad, srccaps, &format); + if (f == GST_VAAPI_CAPS_FEATURE_NOT_NEGOTIATED) + return NULL; + + feature = gst_vaapi_caps_feature_to_string (f); + if (!feature) + feature = GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY; + + n = gst_caps_get_size (srccaps); + for (i = 0; i < n; i++) { + structure = gst_caps_get_structure (srccaps, i); + features = gst_caps_get_features (srccaps, i); + + if (!gst_caps_features_is_any (features) + && gst_caps_features_contains (features, feature)) + break; + } + + if (i >= n) + goto invalid_caps; + + /* make copy */ + structure = gst_structure_copy (structure); + + if (!_set_preferred_format (structure, format)) + goto fixate_failed; + if (!_fixate_frame_size (postproc, vinfo, structure)) + goto fixate_failed; + if (!_fixate_frame_rate (postproc, vinfo, structure)) + goto fixate_failed; + _set_multiview_mode (postproc, vinfo, structure); + + if (!_set_colorimetry (postproc, vinfo, format, structure)) + goto fixate_failed; + + if (!_set_interlace_mode (postproc, vinfo, structure)) + goto interlace_mode_failed; + + outcaps = gst_caps_new_empty (); + gst_caps_append_structure_full (outcaps, structure, + gst_caps_features_copy (features)); + + /* we don't need to do format conversion if GL_TEXTURE_UPLOAD_META + * is negotiated */ + if (f == GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META) { + postproc->format = DEFAULT_FORMAT; + } else if (postproc->format != format) { + postproc->format = format; + } + + return gst_caps_fixate (outcaps); + + /* ERRORS */ +fixate_failed: + { + GST_WARNING_OBJECT (postproc, "Could not fixate src caps"); + gst_structure_free (structure); + return NULL; + } +invalid_caps: + { + GST_WARNING_OBJECT (postproc, "No valid src caps found"); + return NULL; + } +interlace_mode_failed: + { + GST_WARNING_OBJECT (postproc, "Invalid sink caps interlace mode"); + return NULL; + } +} + +/** + * gst_vaapipostproc_fixate_srccaps: + * @postproc: a #GstVaapiPostproc instance + * @sinkcaps: fixed #GstCaps from sink pad + * @srccaps: #GstCaps from src pad to fixate + * + * Given @srccaps and @sinkcaps returns a new allocated #GstCaps with + * the fixated caps for the src pad. + * + * Returns: A new allocated #GstCaps + **/ +GstCaps * +gst_vaapipostproc_fixate_srccaps (GstVaapiPostproc * postproc, + GstCaps * sinkcaps, GstCaps * srccaps) +{ + GstVideoInfo vi; + + if (!gst_video_info_from_caps (&vi, sinkcaps)) + return NULL; + return _get_preferred_caps (postproc, &vi, srccaps); +} diff --git a/gst/vaapi/gstvaapipostprocutil.h b/gst/vaapi/gstvaapipostprocutil.h new file mode 100644 index 0000000000..db5d303286 --- /dev/null +++ b/gst/vaapi/gstvaapipostprocutil.h @@ -0,0 +1,45 @@ +/* + * gstvaapipostprocutil.h - VA-API video post processing utilities + * + * Copyright (C) 2016 Intel Corporation + * Author: Gwenole Beauchesne + * Author: Victor Jaquez + * + * This program 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPIPOSTPROCUTIL_H +#define GST_VAAPIPOSTPROCUTIL_H + +#include "gstvaapipostproc.h" + +G_BEGIN_DECLS + +#define DEFAULT_FORMAT GST_VIDEO_FORMAT_ENCODED +#define DEFAULT_DEINTERLACE_MODE GST_VAAPI_DEINTERLACE_MODE_AUTO +#define DEFAULT_DEINTERLACE_METHOD GST_VAAPI_DEINTERLACE_METHOD_BOB + +GstCaps *gst_vaapipostproc_transform_srccaps (GstVaapiPostproc * postproc); + +GstCaps *gst_vaapipostproc_fixate_srccaps (GstVaapiPostproc * postproc, + GstCaps * sinkcaps, GstCaps * srccaps); + +gboolean is_deinterlace_enabled (GstVaapiPostproc * postproc, + GstVideoInfo * vip); + +G_END_DECLS + +#endif /* GST_VAAPIPOSTPROCUTIL_H */ diff --git a/gst/vaapi/gstvaapisink.c b/gst/vaapi/gstvaapisink.c new file mode 100644 index 0000000000..9b5ae9825c --- /dev/null +++ b/gst/vaapi/gstvaapisink.c @@ -0,0 +1,1992 @@ +/* + * gstvaapisink.c - VA-API video sink + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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-vaapisink + * @short_description: A VA-API based video sink + * + * vaapisink renders video frames to a drawable (X Window) on a local + * display using the Video Acceleration (VA) API. The element will + * create its own internal window and render into it. + * + * ## Example launch line + * + * |[ + * gst-launch-1.0 videotestsrc ! vaapisink + * ]| + */ + +#include "gstcompat.h" +#include +#include + +#include + +/* Supported interfaces */ +# include +# include +# include + +#include "gstvaapisink.h" +#include "gstvaapipluginutil.h" +#include "gstvaapivideometa.h" +#include "gstvaapivideobufferpool.h" +#include "gstvaapivideomemory.h" + +#define GST_PLUGIN_NAME "vaapisink" +#define GST_PLUGIN_DESC "A VA-API based videosink" + +GST_DEBUG_CATEGORY_STATIC (gst_debug_vaapisink); +#ifndef GST_DISABLE_GST_DEBUG +#define GST_CAT_DEFAULT gst_debug_vaapisink +#else +#define GST_CAT_DEFAULT NULL +#endif + +/* Default template */ +/* *INDENT-OFF* */ +static const char gst_vaapisink_sink_caps_str[] = + GST_VAAPI_MAKE_SURFACE_CAPS ";" + GST_VIDEO_CAPS_MAKE_WITH_FEATURES ( + GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE "," + GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION, + "{ ENCODED, NV12, I420, YV12, P010_10LE }") ";" + GST_VIDEO_CAPS_MAKE_WITH_FEATURES ( + GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION, + GST_VIDEO_FORMATS_ALL) ";" + GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS_ALL); +/* *INDENT-ON* */ + +static GstStaticPadTemplate gst_vaapisink_sink_factory = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (gst_vaapisink_sink_caps_str)); + +static gboolean +gst_vaapisink_has_interface (GstVaapiPluginBase * plugin, GType type) +{ + return type == GST_TYPE_VIDEO_OVERLAY || type == GST_TYPE_COLOR_BALANCE; +} + +static void +gst_vaapisink_video_overlay_iface_init (GstVideoOverlayInterface * iface); + +static void +gst_vaapisink_color_balance_iface_init (GstColorBalanceInterface * iface); + +static void +gst_vaapisink_navigation_iface_init (GstNavigationInterface * iface); + +G_DEFINE_TYPE_WITH_CODE (GstVaapiSink, + gst_vaapisink, + GST_TYPE_VIDEO_SINK, + GST_VAAPI_PLUGIN_BASE_INIT_INTERFACES + G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_OVERLAY, + gst_vaapisink_video_overlay_iface_init); + G_IMPLEMENT_INTERFACE (GST_TYPE_COLOR_BALANCE, + gst_vaapisink_color_balance_iface_init); + G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION, + gst_vaapisink_navigation_iface_init)); + +GST_VAAPI_PLUGIN_BASE_DEFINE_SET_CONTEXT (gst_vaapisink_parent_class); + +enum +{ + HANDOFF_SIGNAL, + LAST_SIGNAL +}; + +static guint gst_vaapisink_signals[LAST_SIGNAL] = { 0 }; + +enum +{ + PROP_0, + + PROP_DISPLAY_TYPE, + PROP_DISPLAY_NAME, + PROP_FULLSCREEN, + PROP_ROTATION, + PROP_FORCE_ASPECT_RATIO, + PROP_VIEW_ID, + PROP_HUE, + PROP_SATURATION, + PROP_BRIGHTNESS, + PROP_CONTRAST, + PROP_SIGNAL_HANDOFFS, + + N_PROPERTIES +}; + +#define DEFAULT_DISPLAY_TYPE GST_VAAPI_DISPLAY_TYPE_ANY +#define DEFAULT_ROTATION GST_VAAPI_ROTATION_0 +#define DEFAULT_SIGNAL_HANDOFFS FALSE + +static GParamSpec *g_properties[N_PROPERTIES] = { NULL, }; + +static void gst_vaapisink_video_overlay_expose (GstVideoOverlay * overlay); + +static gboolean gst_vaapisink_reconfigure_window (GstVaapiSink * sink); + +static void +gst_vaapisink_set_event_handling (GstVaapiSink * sink, gboolean handle_events); + +static GstFlowReturn +gst_vaapisink_show_frame (GstVideoSink * video_sink, GstBuffer * buffer); + +static gboolean +gst_vaapisink_ensure_render_rect (GstVaapiSink * sink, guint width, + guint height); + +static inline gboolean +gst_vaapisink_ensure_display (GstVaapiSink * sink) +{ + return gst_vaapi_plugin_base_ensure_display (GST_VAAPI_PLUGIN_BASE (sink)); +} + +static inline gboolean +gst_vaapisink_render_surface (GstVaapiSink * sink, GstVaapiSurface * surface, + const GstVaapiRectangle * surface_rect, guint flags) +{ + return sink->window && gst_vaapi_window_put_surface (sink->window, surface, + surface_rect, &sink->display_rect, flags); +} + +/* ------------------------------------------------------------------------ */ +/* --- DRM Backend --- */ +/* ------------------------------------------------------------------------ */ + +#if USE_DRM +#include + +static gboolean +gst_vaapisink_drm_create_window (GstVaapiSink * sink, guint width, guint height) +{ + g_return_val_if_fail (sink->window == NULL, FALSE); + + GST_ERROR ("failed to create a window for VA/DRM display"); + return FALSE; +} + +static gboolean +gst_vaapisink_drm_render_surface (GstVaapiSink * sink, + GstVaapiSurface * surface, const GstVaapiRectangle * surface_rect, + guint flags) +{ + return TRUE; +} + +static const inline GstVaapiSinkBackend * +gst_vaapisink_backend_drm (void) +{ + static const GstVaapiSinkBackend GstVaapiSinkBackendDRM = { + .create_window = gst_vaapisink_drm_create_window, + .render_surface = gst_vaapisink_drm_render_surface, + }; + return &GstVaapiSinkBackendDRM; +} +#endif + +/* ------------------------------------------------------------------------ */ +/* --- X11 Backend --- */ +/* ------------------------------------------------------------------------ */ + +#if USE_X11 +#include +#include + +#if HAVE_XKBLIB +# include +#endif + +static inline KeySym +x11_keycode_to_keysym (Display * dpy, unsigned int kc) +{ +#if HAVE_XKBLIB + return XkbKeycodeToKeysym (dpy, kc, 0, 0); +#else + return XKeycodeToKeysym (dpy, kc, 0); +#endif +} + +/* Checks whether a ConfigureNotify event is in the queue */ +typedef struct _ConfigureNotifyEventPendingArgs ConfigureNotifyEventPendingArgs; +struct _ConfigureNotifyEventPendingArgs +{ + Window window; + guint width; + guint height; + gboolean match; +}; + +static Bool +configure_notify_event_pending_cb (Display * dpy, XEvent * xev, XPointer arg) +{ + ConfigureNotifyEventPendingArgs *const args = + (ConfigureNotifyEventPendingArgs *) arg; + + if (xev->type == ConfigureNotify && + xev->xconfigure.window == args->window && + xev->xconfigure.width == args->width && + xev->xconfigure.height == args->height) + args->match = TRUE; + + /* XXX: this is a hack to traverse the whole queue because we + can't use XPeekIfEvent() since it could block */ + return False; +} + +static gboolean +configure_notify_event_pending (GstVaapiSink * sink, Window window, + guint width, guint height) +{ + GstVaapiDisplayX11 *const display = + GST_VAAPI_DISPLAY_X11 (GST_VAAPI_PLUGIN_BASE_DISPLAY (sink)); + ConfigureNotifyEventPendingArgs args; + XEvent xev; + + args.window = window; + args.width = width; + args.height = height; + args.match = FALSE; + + /* XXX: don't use XPeekIfEvent() because it might block */ + XCheckIfEvent (gst_vaapi_display_x11_get_display (display), + &xev, configure_notify_event_pending_cb, (XPointer) & args); + return args.match; +} + +static gboolean +gst_vaapisink_x11_create_window (GstVaapiSink * sink, guint width, guint height) +{ + GstVaapiDisplay *const display = GST_VAAPI_PLUGIN_BASE_DISPLAY (sink); + + g_return_val_if_fail (sink->window == NULL, FALSE); + + sink->window = gst_vaapi_window_x11_new (display, width, height); + if (!sink->window) + return FALSE; + + gst_video_overlay_got_window_handle (GST_VIDEO_OVERLAY (sink), + gst_vaapi_window_x11_get_xid (GST_VAAPI_WINDOW_X11 (sink->window))); + return TRUE; +} + +static gboolean +gst_vaapisink_x11_create_window_from_handle (GstVaapiSink * sink, + guintptr window) +{ + GstVaapiDisplay *display; + Window rootwin; + unsigned int width, height, border_width, depth; + int x, y; + XID xid = window; + + if (!gst_vaapisink_ensure_display (sink)) + return FALSE; + display = GST_VAAPI_PLUGIN_BASE_DISPLAY (sink); + + gst_vaapi_display_lock (display); + XGetGeometry (gst_vaapi_display_x11_get_display (GST_VAAPI_DISPLAY_X11 + (display)), xid, &rootwin, &x, &y, &width, &height, &border_width, + &depth); + gst_vaapi_display_unlock (display); + + if ((width != sink->window_width || height != sink->window_height) && + !configure_notify_event_pending (sink, xid, width, height)) { + if (!gst_vaapisink_ensure_render_rect (sink, width, height)) + return FALSE; + sink->window_width = width; + sink->window_height = height; + } + + if (!sink->window + || gst_vaapi_window_x11_get_xid (GST_VAAPI_WINDOW_X11 (sink->window)) != + xid) { + gst_vaapi_window_replace (&sink->window, NULL); + sink->window = gst_vaapi_window_x11_new_with_xid (display, xid); + if (!sink->window) + return FALSE; + } + + gst_vaapisink_set_event_handling (sink, sink->handle_events); + return TRUE; +} + +static gboolean +gst_vaapisink_x11_handle_events (GstVaapiSink * sink) +{ + GstVaapiDisplay *const display = GST_VAAPI_PLUGIN_BASE_DISPLAY (sink); + gboolean has_events, do_expose = FALSE; + guint pointer_x = 0, pointer_y = 0; + gboolean pointer_moved = FALSE; + XEvent e; + + if (sink->window) { + Display *const x11_dpy = + gst_vaapi_display_x11_get_display (GST_VAAPI_DISPLAY_X11 (display)); + Window x11_win = + gst_vaapi_window_x11_get_xid (GST_VAAPI_WINDOW_X11 (sink->window)); + + /* Track MousePointer interaction */ + for (;;) { + gst_vaapi_display_lock (display); + has_events = XCheckWindowEvent (x11_dpy, x11_win, PointerMotionMask, &e); + gst_vaapi_display_unlock (display); + if (!has_events) + break; + + switch (e.type) { + case MotionNotify: + pointer_x = e.xmotion.x; + pointer_y = e.xmotion.y; + pointer_moved = TRUE; + break; + default: + break; + } + } + if (pointer_moved) { + gst_vaapi_display_lock (display); + gst_navigation_send_mouse_event (GST_NAVIGATION (sink), + "mouse-move", 0, pointer_x, pointer_y); + gst_vaapi_display_unlock (display); + } + + /* Track KeyPress, KeyRelease, ButtonPress, ButtonRelease */ + for (;;) { + KeySym keysym; + const char *key_str = NULL; + gst_vaapi_display_lock (display); + has_events = XCheckWindowEvent (x11_dpy, x11_win, + KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask, + &e); + gst_vaapi_display_unlock (display); + if (!has_events) + break; + + switch (e.type) { + case ButtonPress: + gst_navigation_send_mouse_event (GST_NAVIGATION (sink), + "mouse-button-press", e.xbutton.button, e.xbutton.x, e.xbutton.y); + break; + case ButtonRelease: + gst_navigation_send_mouse_event (GST_NAVIGATION (sink), + "mouse-button-release", e.xbutton.button, e.xbutton.x, + e.xbutton.y); + break; + case KeyPress: + case KeyRelease: + gst_vaapi_display_lock (display); + keysym = x11_keycode_to_keysym (x11_dpy, e.xkey.keycode); + if (keysym != NoSymbol) { + key_str = XKeysymToString (keysym); + } else { + key_str = "unknown"; + } + gst_vaapi_display_unlock (display); + gst_navigation_send_key_event (GST_NAVIGATION (sink), + e.type == KeyPress ? "key-press" : "key-release", key_str); + break; + default: + break; + } + } + + /* Handle Expose + ConfigureNotify */ + /* Need to lock whole loop or we corrupt the XEvent queue: */ + for (;;) { + gst_vaapi_display_lock (display); + has_events = XCheckWindowEvent (x11_dpy, x11_win, + StructureNotifyMask | ExposureMask, &e); + gst_vaapi_display_unlock (display); + if (!has_events) + break; + + switch (e.type) { + case Expose: + do_expose = TRUE; + break; + case ConfigureNotify: + if (gst_vaapisink_reconfigure_window (sink)) + do_expose = TRUE; + break; + default: + break; + } + } + if (do_expose) + gst_vaapisink_video_overlay_expose (GST_VIDEO_OVERLAY (sink)); + + /* Handle Display events */ + for (;;) { + gst_vaapi_display_lock (display); + if (XPending (x11_dpy) == 0) { + gst_vaapi_display_unlock (display); + break; + } + XNextEvent (x11_dpy, &e); + gst_vaapi_display_unlock (display); + + switch (e.type) { + case ClientMessage:{ + Atom wm_delete; + + wm_delete = XInternAtom (x11_dpy, "WM_DELETE_WINDOW", False); + if (wm_delete == (Atom) e.xclient.data.l[0]) { + /* Handle window deletion by posting an error on the bus */ + GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND, + ("Output window was closed"), (NULL)); + return FALSE; + } + break; + } + default: + break; + } + } + + } + return TRUE; +} + +static gboolean +gst_vaapisink_x11_pre_start_event_thread (GstVaapiSink * sink) +{ + GstVaapiDisplayX11 *const display = + GST_VAAPI_DISPLAY_X11 (GST_VAAPI_PLUGIN_BASE_DISPLAY (sink)); + int x11_event_mask = (KeyPressMask | KeyReleaseMask | + PointerMotionMask | ExposureMask | StructureNotifyMask); + + if (!sink->foreign_window) + x11_event_mask |= ButtonPressMask | ButtonReleaseMask; + + if (sink->window) { + gst_vaapi_display_lock (GST_VAAPI_DISPLAY (display)); + XSelectInput (gst_vaapi_display_x11_get_display (display), + gst_vaapi_window_x11_get_xid (GST_VAAPI_WINDOW_X11 (sink->window)), + x11_event_mask); + gst_vaapi_display_unlock (GST_VAAPI_DISPLAY (display)); + } + return TRUE; +} + +static gboolean +gst_vaapisink_x11_pre_stop_event_thread (GstVaapiSink * sink) +{ + GstVaapiDisplayX11 *const display = + GST_VAAPI_DISPLAY_X11 (GST_VAAPI_PLUGIN_BASE_DISPLAY (sink)); + + if (sink->window) { + gst_vaapi_display_lock (GST_VAAPI_DISPLAY (display)); + XSelectInput (gst_vaapi_display_x11_get_display (display), + gst_vaapi_window_x11_get_xid (GST_VAAPI_WINDOW_X11 (sink->window)), 0); + gst_vaapi_display_unlock (GST_VAAPI_DISPLAY (display)); + } + return TRUE; +} + +static const inline GstVaapiSinkBackend * +gst_vaapisink_backend_x11 (void) +{ + static const GstVaapiSinkBackend GstVaapiSinkBackendX11 = { + .create_window = gst_vaapisink_x11_create_window, + .create_window_from_handle = gst_vaapisink_x11_create_window_from_handle, + .render_surface = gst_vaapisink_render_surface, + + .event_thread_needed = TRUE, + .handle_events = gst_vaapisink_x11_handle_events, + .pre_start_event_thread = gst_vaapisink_x11_pre_start_event_thread, + .pre_stop_event_thread = gst_vaapisink_x11_pre_stop_event_thread, + }; + return &GstVaapiSinkBackendX11; +} +#endif + +/* ------------------------------------------------------------------------ */ +/* --- Wayland Backend --- */ +/* ------------------------------------------------------------------------ */ + +#if USE_WAYLAND +#include +#include + +static void +on_window_wayland_size_changed (GstVaapiWindowWayland * window, gint width, + gint height, gpointer user_data) +{ + GstVaapiSink *sink = GST_VAAPISINK (user_data); + + GST_DEBUG ("Wayland window size changed to: %dx%d", width, height); + gst_vaapisink_reconfigure_window (sink); + gst_vaapisink_show_frame (GST_VIDEO_SINK_CAST (sink), NULL); +} + +static gboolean +gst_vaapisink_wayland_create_window (GstVaapiSink * sink, guint width, + guint height) +{ + GstVaapiDisplay *const display = GST_VAAPI_PLUGIN_BASE_DISPLAY (sink); + + g_return_val_if_fail (sink->window == NULL, FALSE); + + sink->window = gst_vaapi_window_wayland_new (display, width, height); + if (!sink->window) + return FALSE; + + g_signal_connect_object (sink->window, "size-changed", + G_CALLBACK (on_window_wayland_size_changed), sink, 0); + + return TRUE; +} + +static gboolean +gst_vaapisink_wayland_create_window_from_handle (GstVaapiSink * sink, + guintptr window) +{ + GstVaapiDisplay *display; + + if (!gst_vaapisink_ensure_display (sink)) + return FALSE; + display = GST_VAAPI_PLUGIN_BASE_DISPLAY (sink); + + if (sink->window == NULL || (guintptr) sink->window != window) { + gst_vaapi_window_replace (&sink->window, NULL); + sink->window = gst_vaapi_window_wayland_new_with_surface (display, window); + } + + return sink->window != NULL; +} + +static const inline GstVaapiSinkBackend * +gst_vaapisink_backend_wayland (void) +{ + static const GstVaapiSinkBackend GstVaapiSinkBackendWayland = { + .create_window = gst_vaapisink_wayland_create_window, + .create_window_from_handle = + gst_vaapisink_wayland_create_window_from_handle, + .render_surface = gst_vaapisink_render_surface, + }; + return &GstVaapiSinkBackendWayland; +} +#endif + +/* ------------------------------------------------------------------------ */ +/* --- GstVideoOverlay interface --- */ +/* ------------------------------------------------------------------------ */ + +static void +gst_vaapisink_video_overlay_set_window_handle (GstVideoOverlay * overlay, + guintptr window) +{ + GstVaapiSink *const sink = GST_VAAPISINK (overlay); + GstVaapiDisplayType display_type; + + if (!gst_vaapisink_ensure_display (sink)) + return; + + display_type = GST_VAAPI_PLUGIN_BASE_DISPLAY_TYPE (sink); + + /* Disable GLX rendering when vaapisink is using a foreign X + window. It's pretty much useless */ + if (display_type == GST_VAAPI_DISPLAY_TYPE_GLX) { + display_type = GST_VAAPI_DISPLAY_TYPE_X11; + gst_vaapi_plugin_base_set_display_type (GST_VAAPI_PLUGIN_BASE (sink), + display_type); + } + + sink->foreign_window = TRUE; + if (sink->backend->create_window_from_handle) + sink->backend->create_window_from_handle (sink, window); +} + +static void +gst_vaapisink_video_overlay_set_render_rectangle (GstVideoOverlay * overlay, + gint x, gint y, gint width, gint height) +{ + GstVaapiSink *const sink = GST_VAAPISINK (overlay); + GstVaapiRectangle *const display_rect = &sink->display_rect; + + display_rect->x = x; + display_rect->y = y; + display_rect->width = width; + display_rect->height = height; + + if (gst_vaapisink_ensure_render_rect (sink, width, height) && sink->window) { + gst_vaapi_window_set_render_rectangle (sink->window, x, y, width, height); + gst_vaapi_window_set_size (sink->window, width, height); + gst_vaapisink_reconfigure_window (sink); + } + + GST_DEBUG ("render rect (%d,%d):%ux%u", + display_rect->x, display_rect->y, + display_rect->width, display_rect->height); +} + +static void +gst_vaapisink_video_overlay_expose (GstVideoOverlay * overlay) +{ + GstVaapiSink *const sink = GST_VAAPISINK (overlay); + + gst_vaapisink_reconfigure_window (sink); + gst_vaapisink_show_frame (GST_VIDEO_SINK_CAST (sink), NULL); +} + +static void +gst_vaapisink_video_overlay_set_event_handling (GstVideoOverlay * overlay, + gboolean handle_events) +{ + GstVaapiSink *const sink = GST_VAAPISINK (overlay); + + sink->handle_events = handle_events; + gst_vaapisink_set_event_handling (sink, handle_events); +} + +static void +gst_vaapisink_video_overlay_iface_init (GstVideoOverlayInterface * iface) +{ + iface->set_window_handle = gst_vaapisink_video_overlay_set_window_handle; + iface->set_render_rectangle = + gst_vaapisink_video_overlay_set_render_rectangle; + iface->expose = gst_vaapisink_video_overlay_expose; + iface->handle_events = gst_vaapisink_video_overlay_set_event_handling; +} + +/* ------------------------------------------------------------------------ */ +/* --- GstColorBalance interface --- */ +/* ------------------------------------------------------------------------ */ + +enum +{ + CB_HUE = 1, + CB_SATURATION, + CB_BRIGHTNESS, + CB_CONTRAST +}; + +typedef struct +{ + guint cb_id; + const gchar *prop_name; + const gchar *channel_name; +} ColorBalanceMap; + +static const ColorBalanceMap cb_map[4] = { + {CB_HUE, GST_VAAPI_DISPLAY_PROP_HUE, "VA_HUE"}, + {CB_SATURATION, GST_VAAPI_DISPLAY_PROP_SATURATION, "VA_SATURATION"}, + {CB_BRIGHTNESS, GST_VAAPI_DISPLAY_PROP_BRIGHTNESS, "VA_BRIGHTNESS"}, + {CB_CONTRAST, GST_VAAPI_DISPLAY_PROP_CONTRAST, "VA_CONTRAST"} +}; + +static guint +cb_get_id_from_channel_name (GstVaapiSink * sink, const gchar * name) +{ + guint i; + + for (i = 0; i < G_N_ELEMENTS (sink->cb_values); i++) { + if (g_ascii_strcasecmp (cb_map[i].channel_name, name) == 0) + return cb_map[i].cb_id; + } + + GST_WARNING ("got an unknown channel %s", name); + return 0; +} + +static inline GValue * +cb_get_gvalue (GstVaapiSink * sink, guint id) +{ + g_return_val_if_fail ((guint) (id - CB_HUE) < G_N_ELEMENTS (sink->cb_values), + NULL); + + return &sink->cb_values[id - CB_HUE]; +} + +static gboolean +cb_set_value (GstVaapiSink * sink, guint id, gfloat value) +{ + GValue *const v_value = cb_get_gvalue (sink, id); + + if (!v_value) + return FALSE; + + g_value_set_float (v_value, value); + sink->cb_changed |= (1U << id); + return TRUE; +} + +static inline gfloat +cb_get_value (GstVaapiSink * sink, guint id) +{ + const GValue *const v_value = cb_get_gvalue (sink, id); + + return v_value ? g_value_get_float (v_value) : 0.0; +} + +static gboolean +cb_sync_values_from_display (GstVaapiSink * sink, GstVaapiDisplay * display) +{ + guint i; + gfloat value; + + for (i = 0; i < G_N_ELEMENTS (sink->cb_values); i++) { + const guint cb_id = CB_HUE + i; + if (!gst_vaapi_display_has_property (display, cb_map[i].prop_name)) { + GST_INFO_OBJECT (sink, "backend does not handle %s", cb_map[i].prop_name); + continue; + } + + value = 0.0; + g_object_get (display, cb_map[i].prop_name, &value, NULL); + cb_set_value (sink, cb_id, value); + } + sink->cb_changed = 0; + return TRUE; +} + +static gboolean +cb_sync_values_to_display (GstVaapiSink * sink, GstVaapiDisplay * display) +{ + guint i; + + for (i = 0; i < G_N_ELEMENTS (sink->cb_values); i++) { + const guint cb_id = CB_HUE + i; + if (!(sink->cb_changed & (1U << cb_id))) + continue; + if (!gst_vaapi_display_has_property (display, cb_map[i].prop_name)) { + GST_INFO_OBJECT (sink, "backend does not handle %s", cb_map[i].prop_name); + continue; + } + + g_object_set_property (G_OBJECT (display), cb_map[i].prop_name, + cb_get_gvalue (sink, cb_id)); + } + sink->cb_changed = 0; + return TRUE; +} + +#define CB_CHANNEL_FACTOR (1000.0) + +static void +cb_channels_init (GstVaapiSink * sink) +{ + GstVaapiDisplay *const display = GST_VAAPI_PLUGIN_BASE_DISPLAY (sink); + GstColorBalanceChannel *channel; + GParamSpecFloat *pspec; + guint i; + + for (i = 0; i < G_N_ELEMENTS (sink->cb_values); i++) { + if (!gst_vaapi_display_has_property (display, cb_map[i].prop_name)) + continue; + + pspec = G_PARAM_SPEC_FLOAT (g_properties[PROP_HUE + i]); + if (!pspec) + continue; + + channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL); + channel->label = g_strdup (cb_map[i].channel_name); + channel->min_value = pspec->minimum * CB_CHANNEL_FACTOR; + channel->max_value = pspec->maximum * CB_CHANNEL_FACTOR; + + sink->cb_channels = g_list_prepend (sink->cb_channels, channel); + } + + if (sink->cb_channels) + sink->cb_channels = g_list_reverse (sink->cb_channels); +} + +static void +cb_channels_finalize (GstVaapiSink * sink) +{ + if (sink->cb_channels) { + g_list_free_full (sink->cb_channels, g_object_unref); + sink->cb_channels = NULL; + } +} + +static const GList * +gst_vaapisink_color_balance_list_channels (GstColorBalance * cb) +{ + GstVaapiSink *const sink = GST_VAAPISINK (cb); + + if (!gst_vaapisink_ensure_display (sink)) + return NULL; + + if (!sink->cb_channels) + cb_channels_init (sink); + return sink->cb_channels; +} + +static void +gst_vaapisink_color_balance_set_value (GstColorBalance * cb, + GstColorBalanceChannel * channel, gint value) +{ + GstVaapiSink *const sink = GST_VAAPISINK (cb); + guint cb_id; + + g_return_if_fail (channel->label != NULL); + + if (!gst_vaapisink_ensure_display (sink)) + return; + + cb_id = cb_get_id_from_channel_name (sink, channel->label); + if (!cb_id) + return; + + cb_set_value (sink, cb_id, value / CB_CHANNEL_FACTOR); +} + +static gint +gst_vaapisink_color_balance_get_value (GstColorBalance * cb, + GstColorBalanceChannel * channel) +{ + GstVaapiSink *const sink = GST_VAAPISINK (cb); + guint cb_id; + + g_return_val_if_fail (channel->label != NULL, 0); + + if (!gst_vaapisink_ensure_display (sink)) + return 0; + + cb_id = cb_get_id_from_channel_name (sink, channel->label); + if (!cb_id) + return 0; + + return cb_get_value (sink, cb_id) * CB_CHANNEL_FACTOR; +} + +static GstColorBalanceType +gst_vaapisink_color_balance_get_type (GstColorBalance * cb) +{ + return GST_COLOR_BALANCE_HARDWARE; +} + +static void +gst_vaapisink_color_balance_iface_init (GstColorBalanceInterface * iface) +{ + iface->list_channels = gst_vaapisink_color_balance_list_channels; + iface->set_value = gst_vaapisink_color_balance_set_value; + iface->get_value = gst_vaapisink_color_balance_get_value; + iface->get_balance_type = gst_vaapisink_color_balance_get_type; +} + +/* ------------------------------------------------------------------------ */ +/* --- GstNavigation interface --- */ +/* ------------------------------------------------------------------------ */ + +static void +gst_vaapisink_navigation_send_event (GstNavigation * navigation, + GstStructure * structure) +{ + GstVaapiSink *const sink = GST_VAAPISINK (navigation); + GstPad *peer; + + if (!sink->window) { + gst_structure_free (structure); + return; + } + + if ((peer = gst_pad_get_peer (GST_VAAPI_PLUGIN_BASE_SINK_PAD (sink)))) { + GstEvent *event; + GstVaapiRectangle *disp_rect = &sink->display_rect; + gdouble x, y, xscale = 1.0, yscale = 1.0; + + event = gst_event_new_navigation (structure); + + /* We calculate scaling using the original video frames geometry to include + pixel aspect ratio scaling. */ + xscale = (gdouble) sink->video_width / disp_rect->width; + yscale = (gdouble) sink->video_height / disp_rect->height; + + /* Converting pointer coordinates to the non scaled geometry */ + if (gst_structure_get_double (structure, "pointer_x", &x)) { + x = MIN (x, disp_rect->x + disp_rect->width); + x = MAX (x - disp_rect->x, 0); + gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, + (gdouble) x * xscale, NULL); + } + if (gst_structure_get_double (structure, "pointer_y", &y)) { + y = MIN (y, disp_rect->y + disp_rect->height); + y = MAX (y - disp_rect->y, 0); + gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE, + (gdouble) y * yscale, NULL); + } + + if (!gst_pad_send_event (peer, gst_event_ref (event))) { + /* If upstream didn't handle the event we'll post a message with it + * for the application in case it wants to do something with it */ + gst_element_post_message (GST_ELEMENT_CAST (sink), + gst_navigation_message_new_event (GST_OBJECT_CAST (sink), event)); + } + gst_event_unref (event); + gst_object_unref (peer); + } +} + +static void +gst_vaapisink_navigation_iface_init (GstNavigationInterface * iface) +{ + iface->send_event = gst_vaapisink_navigation_send_event; +} + +/* ------------------------------------------------------------------------ */ +/* --- Common implementation --- */ +/* ------------------------------------------------------------------------ */ + +static gboolean +gst_vaapisink_reconfigure_window (GstVaapiSink * sink) +{ + guint win_width, win_height; + + gst_vaapi_window_reconfigure (sink->window); + gst_vaapi_window_get_size (sink->window, &win_width, &win_height); + if (win_width != sink->window_width || win_height != sink->window_height) { + if (!gst_vaapisink_ensure_render_rect (sink, win_width, win_height)) + return FALSE; + GST_INFO ("window was resized from %ux%u to %ux%u", + sink->window_width, sink->window_height, win_width, win_height); + sink->window_width = win_width; + sink->window_height = win_height; + return TRUE; + } + return FALSE; +} + +static gpointer +gst_vaapisink_event_thread (GstVaapiSink * sink) +{ + GST_OBJECT_LOCK (sink); + while (!g_atomic_int_get (&sink->event_thread_cancel)) { + GST_OBJECT_UNLOCK (sink); + sink->backend->handle_events (sink); + g_usleep (G_USEC_PER_SEC / 20); + GST_OBJECT_LOCK (sink); + } + GST_OBJECT_UNLOCK (sink); + return NULL; +} + +static void +gst_vaapisink_set_event_handling (GstVaapiSink * sink, gboolean handle_events) +{ + GThread *thread = NULL; + + if (!sink->backend || !sink->backend->event_thread_needed) + return; + + GST_OBJECT_LOCK (sink); + if (handle_events && !sink->event_thread) { + /* Setup our event listening thread */ + GST_DEBUG ("starting xevent thread"); + if (sink->backend->pre_start_event_thread) + sink->backend->pre_start_event_thread (sink); + + g_atomic_int_set (&sink->event_thread_cancel, FALSE); + sink->event_thread = g_thread_try_new ("vaapisink-events", + (GThreadFunc) gst_vaapisink_event_thread, sink, NULL); + } else if (!handle_events && sink->event_thread) { + GST_DEBUG ("stopping xevent thread"); + if (sink->backend->pre_stop_event_thread) + sink->backend->pre_stop_event_thread (sink); + + /* Grab thread and mark it as NULL */ + thread = sink->event_thread; + sink->event_thread = NULL; + g_atomic_int_set (&sink->event_thread_cancel, TRUE); + } + GST_OBJECT_UNLOCK (sink); + + /* Wait for our event thread to finish */ + if (thread) { + g_thread_join (thread); + GST_DEBUG ("xevent thread stopped"); + } +} + +static void +gst_vaapisink_ensure_backend (GstVaapiSink * sink) +{ + switch (GST_VAAPI_PLUGIN_BASE_DISPLAY_TYPE (sink)) { +#if USE_DRM + case GST_VAAPI_DISPLAY_TYPE_DRM: + sink->backend = gst_vaapisink_backend_drm (); + break; +#endif +#if USE_X11 + case GST_VAAPI_DISPLAY_TYPE_X11: + sink->backend = gst_vaapisink_backend_x11 (); + break; +#endif +#if USE_GLX + case GST_VAAPI_DISPLAY_TYPE_GLX: + sink->backend = gst_vaapisink_backend_x11 (); + break; +#endif +#if USE_WAYLAND + case GST_VAAPI_DISPLAY_TYPE_WAYLAND: + sink->backend = gst_vaapisink_backend_wayland (); + break; +#endif + default: + GST_ERROR ("failed to initialize GstVaapiSink backend"); + g_assert_not_reached (); + break; + } +} + +static gboolean +gst_vaapisink_ensure_render_rect (GstVaapiSink * sink, guint width, + guint height) +{ + GstVaapiRectangle *const display_rect = &sink->display_rect; + guint num, den, display_par_n, display_par_d; + gboolean success; + + /* Return success if caps are not set yet */ + if (!sink->caps) + return TRUE; + + if (!sink->keep_aspect) { + display_rect->width = width; + display_rect->height = height; + display_rect->x = 0; + display_rect->y = 0; + + GST_DEBUG ("force-aspect-ratio is false; distorting while scaling video"); + GST_DEBUG ("render rect (%d,%d):%ux%u", + display_rect->x, display_rect->y, + display_rect->width, display_rect->height); + return TRUE; + } + + GST_DEBUG ("ensure render rect within %ux%u bounds", width, height); + + gst_vaapi_display_get_pixel_aspect_ratio (GST_VAAPI_PLUGIN_BASE_DISPLAY + (sink), &display_par_n, &display_par_d); + GST_DEBUG ("display pixel-aspect-ratio %d/%d", display_par_n, display_par_d); + + success = gst_video_calculate_display_ratio (&num, &den, + sink->video_width, sink->video_height, + sink->video_par_n, sink->video_par_d, display_par_n, display_par_d); + if (!success) + return FALSE; + GST_DEBUG ("video size %dx%d, calculated ratio %d/%d", + sink->video_width, sink->video_height, num, den); + + display_rect->width = gst_util_uint64_scale_int (height, num, den); + if (display_rect->width <= width) { + GST_DEBUG ("keeping window height"); + display_rect->height = height; + } else { + GST_DEBUG ("keeping window width"); + display_rect->width = width; + display_rect->height = gst_util_uint64_scale_int (width, den, num); + } + GST_DEBUG ("scaling video to %ux%u", display_rect->width, + display_rect->height); + + g_assert (display_rect->width <= width); + g_assert (display_rect->height <= height); + + display_rect->x = (width - display_rect->width) / 2; + display_rect->y = (height - display_rect->height) / 2; + + GST_DEBUG ("render rect (%d,%d):%ux%u", + display_rect->x, display_rect->y, + display_rect->width, display_rect->height); + return TRUE; +} + +static inline gboolean +gst_vaapisink_ensure_window (GstVaapiSink * sink, guint width, guint height) +{ + return sink->window || sink->backend->create_window (sink, width, height); +} + +static void +gst_vaapisink_ensure_window_size (GstVaapiSink * sink, guint * width_ptr, + guint * height_ptr) +{ + GstVaapiDisplay *const display = GST_VAAPI_PLUGIN_BASE_DISPLAY (sink); + GstVideoRectangle src_rect, dst_rect, out_rect; + guint num, den, display_width, display_height, display_par_n, display_par_d; + gboolean success, scale; + + if (sink->foreign_window) { + *width_ptr = sink->window_width; + *height_ptr = sink->window_height; + return; + } + + gst_vaapi_display_get_size (display, &display_width, &display_height); + if (sink->fullscreen) { + *width_ptr = display_width; + *height_ptr = display_height; + return; + } + + gst_vaapi_display_get_pixel_aspect_ratio (display, + &display_par_n, &display_par_d); + + success = gst_video_calculate_display_ratio (&num, &den, + sink->video_width, sink->video_height, + sink->video_par_n, sink->video_par_d, display_par_n, display_par_d); + if (!success) { + num = sink->video_par_n; + den = sink->video_par_d; + } + + src_rect.x = 0; + src_rect.y = 0; + src_rect.w = gst_util_uint64_scale_int (sink->video_height, num, den); + src_rect.h = sink->video_height; + dst_rect.x = 0; + dst_rect.y = 0; + dst_rect.w = display_width; + dst_rect.h = display_height; + scale = (src_rect.w > dst_rect.w || src_rect.h > dst_rect.h); + gst_video_sink_center_rect (src_rect, dst_rect, &out_rect, scale); + *width_ptr = out_rect.w; + *height_ptr = out_rect.h; +} + +static inline gboolean +gst_vaapisink_ensure_colorbalance (GstVaapiSink * sink) +{ + return cb_sync_values_to_display (sink, GST_VAAPI_PLUGIN_BASE_DISPLAY (sink)); +} + + +static void +gst_vaapisink_set_rotation (GstVaapiSink * sink, GstVaapiRotation rotation, + gboolean from_tag) +{ + GST_OBJECT_LOCK (sink); + + if (from_tag) + sink->rotation_tag = rotation; + else + sink->rotation_prop = rotation; + + if (sink->rotation_prop == GST_VAAPI_ROTATION_AUTOMATIC) + sink->rotation_req = sink->rotation_tag; + else + sink->rotation_req = sink->rotation_prop; + + GST_OBJECT_UNLOCK (sink); +} + +static gboolean +gst_vaapisink_ensure_rotation (GstVaapiSink * sink, + gboolean recalc_display_rect) +{ + GstVaapiDisplay *const display = GST_VAAPI_PLUGIN_BASE_DISPLAY (sink); + gboolean success = FALSE; + + g_return_val_if_fail (display, FALSE); + + if (sink->rotation == sink->rotation_req) + return TRUE; + + if (!sink->use_rotation) { + GST_WARNING ("VA display does not support rotation"); + goto end; + } + + gst_vaapi_display_lock (display); + success = gst_vaapi_display_set_rotation (display, sink->rotation_req); + gst_vaapi_display_unlock (display); + if (!success) { + GST_ERROR ("failed to change VA display rotation mode"); + goto end; + } + + if (((sink->rotation + sink->rotation_req) % 180) == 90) { + /* Orientation changed */ + G_PRIMITIVE_SWAP (guint, sink->video_width, sink->video_height); + G_PRIMITIVE_SWAP (gint, sink->video_par_n, sink->video_par_d); + } + + if (recalc_display_rect && !sink->foreign_window) + gst_vaapisink_ensure_render_rect (sink, sink->window_width, + sink->window_height); + success = TRUE; + +end: + sink->rotation = sink->rotation_req; + return success; +} + +static const gchar * +get_display_type_name (GstVaapiDisplayType display_type) +{ + gpointer const klass = g_type_class_peek (GST_VAAPI_TYPE_DISPLAY_TYPE); + GEnumValue *const e = g_enum_get_value (klass, display_type); + + if (e) + return e->value_name; + return ""; +} + +static void +gst_vaapisink_display_changed (GstVaapiPluginBase * plugin) +{ + GstVaapiSink *const sink = GST_VAAPISINK_CAST (plugin); + GstVaapiRenderMode render_mode; + + GST_INFO ("created %s %p", get_display_type_name (plugin->display_type), + plugin->display); + + gst_vaapisink_ensure_backend (sink); + + sink->use_overlay = + gst_vaapi_display_get_render_mode (plugin->display, &render_mode) && + render_mode == GST_VAAPI_RENDER_MODE_OVERLAY; + GST_DEBUG ("use %s rendering mode", + sink->use_overlay ? "overlay" : "texture"); + + /* Keep our own colorbalance values, should we have any change pending */ + if (!sink->cb_changed) + cb_sync_values_from_display (sink, plugin->display); + + sink->use_rotation = gst_vaapi_display_has_property (plugin->display, + GST_VAAPI_DISPLAY_PROP_ROTATION); +} + +static gboolean +gst_vaapisink_start (GstBaseSink * base_sink) +{ + GstVaapiSink *const sink = GST_VAAPISINK_CAST (base_sink); + GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (base_sink); + + if (!gst_vaapisink_ensure_display (sink)) + return FALSE; + + /* Ensures possible raw caps earlier to avoid race conditions at + * get_caps() */ + if (!gst_vaapi_plugin_base_get_allowed_sinkpad_raw_caps (plugin)) + return FALSE; + + return TRUE; +} + +static gboolean +gst_vaapisink_stop (GstBaseSink * base_sink) +{ + GstVaapiSink *const sink = GST_VAAPISINK_CAST (base_sink); + + gst_vaapisink_set_event_handling (sink, FALSE); + gst_buffer_replace (&sink->video_buffer, NULL); + gst_vaapi_window_replace (&sink->window, NULL); + + gst_vaapi_plugin_base_close (GST_VAAPI_PLUGIN_BASE (sink)); + return TRUE; +} + +static GstCaps * +gst_vaapisink_get_caps_impl (GstBaseSink * base_sink) +{ + GstVaapiSink *const sink = GST_VAAPISINK_CAST (base_sink); + GstCaps *out_caps, *raw_caps, *feature_caps; + static const char surface_caps_str[] = + GST_VAAPI_MAKE_SURFACE_CAPS ";" + GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE + "," GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION, + "{ ENCODED, NV12, I420, YV12 }"); + GstCapsFeatures *features; + + if (!GST_VAAPI_PLUGIN_BASE_DISPLAY (sink)) + return gst_static_pad_template_get_caps (&gst_vaapisink_sink_factory); + + out_caps = gst_caps_from_string (surface_caps_str); + raw_caps = + gst_vaapi_plugin_base_get_allowed_sinkpad_raw_caps (GST_VAAPI_PLUGIN_BASE + (sink)); + if (!raw_caps) + return out_caps; + + out_caps = gst_caps_make_writable (out_caps); + gst_caps_append (out_caps, gst_caps_copy (raw_caps)); + + feature_caps = gst_caps_copy (raw_caps); + features = gst_caps_features_new + (GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION, NULL); + gst_caps_set_features (feature_caps, 0, features); + gst_caps_append (out_caps, feature_caps); + + return out_caps; +} + +static inline GstCaps * +gst_vaapisink_get_caps (GstBaseSink * base_sink, GstCaps * filter) +{ + GstCaps *caps, *out_caps; + + caps = gst_vaapisink_get_caps_impl (base_sink); + if (caps && filter) { + out_caps = gst_caps_intersect_full (caps, filter, GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (caps); + } else + out_caps = caps; + return out_caps; +} + +static void +update_colorimetry (GstVaapiSink * sink, GstVideoColorimetry * cinfo) +{ + if (gst_video_colorimetry_matches (cinfo, GST_VIDEO_COLORIMETRY_BT601)) + sink->color_standard = GST_VAAPI_COLOR_STANDARD_ITUR_BT_601; + else if (gst_video_colorimetry_matches (cinfo, GST_VIDEO_COLORIMETRY_BT709)) + sink->color_standard = GST_VAAPI_COLOR_STANDARD_ITUR_BT_709; + else if (gst_video_colorimetry_matches (cinfo, + GST_VIDEO_COLORIMETRY_SMPTE240M)) + sink->color_standard = GST_VAAPI_COLOR_STANDARD_SMPTE_240M; + else + sink->color_standard = 0; + +#ifndef GST_DISABLE_GST_DEBUG + { + gchar *const colorimetry_string = gst_video_colorimetry_to_string (cinfo); + GST_DEBUG ("colorimetry %s", colorimetry_string); + g_free (colorimetry_string); + } +#endif +} + +static gboolean +gst_vaapisink_set_caps (GstBaseSink * base_sink, GstCaps * caps) +{ + GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (base_sink); + GstVaapiSink *const sink = GST_VAAPISINK_CAST (base_sink); + GstVideoInfo *const vip = GST_VAAPI_PLUGIN_BASE_SINK_PAD_INFO (sink); + GstVaapiDisplay *display; + guint win_width, win_height; + + if (!gst_vaapisink_ensure_display (sink)) + return FALSE; + display = GST_VAAPI_PLUGIN_BASE_DISPLAY (sink); + + if (!gst_vaapi_plugin_base_set_caps (plugin, caps, NULL)) + return FALSE; + + sink->video_width = GST_VIDEO_INFO_WIDTH (vip); + sink->video_height = GST_VIDEO_INFO_HEIGHT (vip); + sink->video_par_n = GST_VIDEO_INFO_PAR_N (vip); + sink->video_par_d = GST_VIDEO_INFO_PAR_D (vip); + if (sink->video_par_n == 0) + sink->video_par_n = 1; + GST_DEBUG ("video pixel-aspect-ratio %d/%d", + sink->video_par_n, sink->video_par_d); + + update_colorimetry (sink, &GST_VIDEO_INFO_COLORIMETRY (vip)); + gst_caps_replace (&sink->caps, caps); + + /* Reset the rotation to the default when new caps are coming in. This + * forces re-evaluating if the rotation needs to be done */ + sink->rotation = DEFAULT_ROTATION; + gst_vaapisink_ensure_colorbalance (sink); + gst_vaapisink_ensure_rotation (sink, FALSE); + + if (GST_VAAPI_PLUGIN_BASE_DISPLAY_TYPE (sink) == GST_VAAPI_DISPLAY_TYPE_DRM) + return TRUE; + + gst_vaapisink_ensure_window_size (sink, &win_width, &win_height); + if (sink->window) { + if (!sink->foreign_window || sink->fullscreen) + gst_vaapi_window_set_size (sink->window, win_width, win_height); + } else { + gst_vaapi_display_lock (display); + gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (sink)); + gst_vaapi_display_unlock (display); + if (sink->window) + return TRUE; + if (!gst_vaapisink_ensure_window (sink, win_width, win_height)) + return FALSE; + gst_vaapi_window_set_fullscreen (sink->window, sink->fullscreen); + gst_vaapi_window_show (sink->window); + gst_vaapi_window_get_size (sink->window, &win_width, &win_height); + gst_vaapisink_set_event_handling (sink, sink->handle_events); + } + sink->window_width = win_width; + sink->window_height = win_height; + GST_DEBUG ("window size %ux%u", win_width, win_height); + + return gst_vaapisink_ensure_render_rect (sink, win_width, win_height); +} + +static GstFlowReturn +gst_vaapisink_show_frame_unlocked (GstVaapiSink * sink, GstBuffer * src_buffer) +{ + GstVaapiVideoMeta *meta; + GstVaapiSurfaceProxy *proxy; + GstVaapiSurface *surface; + GstBuffer *buffer; + GstBuffer *old_buf; + guint flags; + GstVaapiRectangle *surface_rect = NULL; + GstVaapiRectangle tmp_rect; + GstFlowReturn ret; + gint32 view_id; + GstVideoCropMeta *crop_meta; + + if (!src_buffer) { + if (sink->video_buffer) + src_buffer = sink->video_buffer; + else + return GST_FLOW_OK; + } + + crop_meta = gst_buffer_get_video_crop_meta (src_buffer); + if (crop_meta) { + surface_rect = &tmp_rect; + surface_rect->x = crop_meta->x; + surface_rect->y = crop_meta->y; + surface_rect->width = crop_meta->width; + surface_rect->height = crop_meta->height; + } + + ret = gst_vaapi_plugin_base_get_input_buffer (GST_VAAPI_PLUGIN_BASE (sink), + src_buffer, &buffer); + if (ret == GST_FLOW_NOT_SUPPORTED) + return GST_FLOW_OK; /* let's ignore the frame if it couldn't be uploaded */ + if (ret != GST_FLOW_OK) + return ret; + + meta = gst_buffer_get_vaapi_video_meta (buffer); + if (gst_vaapi_video_meta_get_display (meta) != + GST_VAAPI_PLUGIN_BASE_DISPLAY (sink)) + goto different_display; + + proxy = gst_vaapi_video_meta_get_surface_proxy (meta); + if (!proxy) + goto no_surface; + + surface = gst_vaapi_video_meta_get_surface (meta); + if (!surface) + goto no_surface; + + /* Validate view component to display */ + view_id = GST_VAAPI_SURFACE_PROXY_VIEW_ID (proxy); + if (G_UNLIKELY (sink->view_id == -1)) + sink->view_id = view_id; + else if (sink->view_id != view_id) { + ret = GST_FLOW_OK; + goto done; + } + + gst_vaapisink_ensure_colorbalance (sink); + gst_vaapisink_ensure_rotation (sink, TRUE); + + GST_TRACE_OBJECT (sink, "render surface %" GST_VAAPI_ID_FORMAT, + GST_VAAPI_ID_ARGS (gst_vaapi_surface_get_id (surface))); + + if (!surface_rect) + surface_rect = (GstVaapiRectangle *) + gst_vaapi_video_meta_get_render_rect (meta); + + if (surface_rect) + GST_DEBUG ("render rect (%d,%d), size %ux%u", + surface_rect->x, surface_rect->y, + surface_rect->width, surface_rect->height); + + flags = gst_vaapi_video_meta_get_render_flags (meta); + + /* Append default color standard obtained from caps if none was + available on a per-buffer basis */ + if (!(flags & GST_VAAPI_COLOR_STANDARD_MASK)) + flags |= sink->color_standard; + + if (!gst_vaapi_apply_composition (surface, src_buffer)) + GST_WARNING ("could not update subtitles"); + + if (!sink->backend->render_surface (sink, surface, surface_rect, flags)) + goto error; + + if (sink->signal_handoffs) + g_signal_emit (sink, gst_vaapisink_signals[HANDOFF_SIGNAL], 0, buffer); + + /* Retain VA surface until the next one is displayed */ + old_buf = sink->video_buffer; + sink->video_buffer = gst_buffer_ref (buffer); + /* Need to release the lock while releasing old buffer, otherwise a + * deadlock is possible */ + gst_vaapi_display_unlock (GST_VAAPI_PLUGIN_BASE_DISPLAY (sink)); + if (old_buf) + gst_buffer_unref (old_buf); + gst_vaapi_display_lock (GST_VAAPI_PLUGIN_BASE_DISPLAY (sink)); + + ret = GST_FLOW_OK; + +done: + gst_buffer_unref (buffer); + return ret; + + /* ERRORS */ +error: + { + GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, + ("Internal error: could not render surface"), (NULL)); + ret = GST_FLOW_ERROR; + goto done; + } + +no_surface: + { + /* No surface or surface proxy. That's very bad! */ + GST_WARNING_OBJECT (sink, "could not get surface"); + ret = GST_FLOW_ERROR; + goto done; + } + +different_display: + { + GST_WARNING_OBJECT (sink, "incoming surface has different VAAPI Display"); + ret = GST_FLOW_ERROR; + goto done; + } +} + +static GstFlowReturn +gst_vaapisink_show_frame (GstVideoSink * video_sink, GstBuffer * src_buffer) +{ + GstVaapiSink *const sink = GST_VAAPISINK_CAST (video_sink); + GstFlowReturn ret; + + /* We need at least to protect the gst_vaapi_aplpy_composition() + * call to prevent a race during subpicture destruction. + * FIXME: a less coarse grained lock could be used, though */ + gst_vaapi_display_lock (GST_VAAPI_PLUGIN_BASE_DISPLAY (sink)); + ret = gst_vaapisink_show_frame_unlocked (sink, src_buffer); + gst_vaapi_display_unlock (GST_VAAPI_PLUGIN_BASE_DISPLAY (sink)); + + return ret; +} + +static gboolean +gst_vaapisink_propose_allocation (GstBaseSink * base_sink, GstQuery * query) +{ + GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (base_sink); + + if (!gst_vaapi_plugin_base_propose_allocation (plugin, query)) + return FALSE; + + gst_query_add_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE, NULL); + gst_query_add_allocation_meta (query, + GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, NULL); + return TRUE; +} + +static gboolean +gst_vaapisink_query (GstBaseSink * base_sink, GstQuery * query) +{ + GstElement *const element = GST_ELEMENT (base_sink); + gboolean ret = FALSE; + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_CONTEXT: + ret = gst_vaapi_handle_context_query (element, query); + break; + default: + ret = GST_BASE_SINK_CLASS (gst_vaapisink_parent_class)->query (base_sink, + query); + break; + } + + return ret; +} + +static void +gst_vaapisink_destroy (GstVaapiSink * sink) +{ + cb_channels_finalize (sink); + gst_buffer_replace (&sink->video_buffer, NULL); + gst_caps_replace (&sink->caps, NULL); +} + +static void +gst_vaapisink_finalize (GObject * object) +{ + gst_vaapisink_destroy (GST_VAAPISINK_CAST (object)); + + gst_vaapi_plugin_base_finalize (GST_VAAPI_PLUGIN_BASE (object)); + G_OBJECT_CLASS (gst_vaapisink_parent_class)->finalize (object); +} + +static void +gst_vaapisink_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstVaapiSink *const sink = GST_VAAPISINK_CAST (object); + + switch (prop_id) { + case PROP_DISPLAY_TYPE: + gst_vaapi_plugin_base_set_display_type (GST_VAAPI_PLUGIN_BASE (sink), + g_value_get_enum (value)); + break; + case PROP_DISPLAY_NAME: + gst_vaapi_plugin_base_set_display_name (GST_VAAPI_PLUGIN_BASE (sink), + g_value_get_string (value)); + break; + case PROP_FULLSCREEN: + sink->fullscreen = g_value_get_boolean (value); + break; + case PROP_VIEW_ID: + sink->view_id = g_value_get_int (value); + break; + case PROP_ROTATION: + gst_vaapisink_set_rotation (sink, g_value_get_enum (value), FALSE); + break; + case PROP_FORCE_ASPECT_RATIO: + sink->keep_aspect = g_value_get_boolean (value); + break; + case PROP_SIGNAL_HANDOFFS: + sink->signal_handoffs = g_value_get_boolean (value); + break; + case PROP_HUE: + case PROP_SATURATION: + case PROP_BRIGHTNESS: + case PROP_CONTRAST: + cb_set_value (sink, (prop_id - PROP_HUE) + CB_HUE, + g_value_get_float (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_vaapisink_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstVaapiSink *const sink = GST_VAAPISINK_CAST (object); + + switch (prop_id) { + case PROP_DISPLAY_TYPE: + g_value_set_enum (value, GST_VAAPI_PLUGIN_BASE_DISPLAY_TYPE (sink)); + break; + case PROP_DISPLAY_NAME: + g_value_set_string (value, GST_VAAPI_PLUGIN_BASE_DISPLAY_NAME (sink)); + break; + case PROP_FULLSCREEN: + g_value_set_boolean (value, sink->fullscreen); + break; + case PROP_VIEW_ID: + g_value_set_int (value, sink->view_id); + break; + case PROP_ROTATION: + g_value_set_enum (value, sink->rotation); + break; + case PROP_FORCE_ASPECT_RATIO: + g_value_set_boolean (value, sink->keep_aspect); + break; + case PROP_SIGNAL_HANDOFFS: + g_value_set_boolean (value, sink->signal_handoffs); + break; + case PROP_HUE: + case PROP_SATURATION: + case PROP_BRIGHTNESS: + case PROP_CONTRAST: + g_value_set_float (value, cb_get_value (sink, + (prop_id - PROP_HUE) + CB_HUE)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +gst_vaapisink_unlock (GstBaseSink * base_sink) +{ + GstVaapiSink *const sink = GST_VAAPISINK_CAST (base_sink); + + if (sink->window) + return gst_vaapi_window_unblock (sink->window); + + return TRUE; +} + +static gboolean +gst_vaapisink_unlock_stop (GstBaseSink * base_sink) +{ + GstVaapiSink *const sink = GST_VAAPISINK_CAST (base_sink); + + if (sink->window) + return gst_vaapi_window_unblock_cancel (sink->window); + + return TRUE; +} + +static gboolean +gst_vaapisink_event (GstBaseSink * base_sink, GstEvent * event) +{ + gboolean res = TRUE; + GstTagList *taglist; + gchar *orientation; + + GstVaapiSink *const sink = GST_VAAPISINK_CAST (base_sink); + + GST_DEBUG_OBJECT (sink, "handling event %s", GST_EVENT_TYPE_NAME (event)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_TAG: + gst_event_parse_tag (event, &taglist); + + if (gst_tag_list_get_string (taglist, GST_TAG_IMAGE_ORIENTATION, + &orientation)) { + if (!g_strcmp0 ("rotate-0", orientation)) { + gst_vaapisink_set_rotation (sink, GST_VAAPI_ROTATION_0, TRUE); + } else if (!g_strcmp0 ("rotate-90", orientation)) { + gst_vaapisink_set_rotation (sink, GST_VAAPI_ROTATION_90, TRUE); + } else if (!g_strcmp0 ("rotate-180", orientation)) { + gst_vaapisink_set_rotation (sink, GST_VAAPI_ROTATION_180, TRUE); + } else if (!g_strcmp0 ("rotate-270", orientation)) { + gst_vaapisink_set_rotation (sink, GST_VAAPI_ROTATION_270, TRUE); + } + + /* Do not support for flip yet. + * It should be implemented in the near future. + * See https://bugs.freedesktop.org/show_bug.cgi?id=90654 + */ + g_free (orientation); + } + break; + default: + break; + } + + res = + GST_BASE_SINK_CLASS (gst_vaapisink_parent_class)->event (base_sink, + event); + + return res; +} + +static void +gst_vaapisink_class_init (GstVaapiSinkClass * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstElementClass *const element_class = GST_ELEMENT_CLASS (klass); + GstBaseSinkClass *const basesink_class = GST_BASE_SINK_CLASS (klass); + GstVideoSinkClass *const videosink_class = GST_VIDEO_SINK_CLASS (klass); + GstVaapiPluginBaseClass *const base_plugin_class = + GST_VAAPI_PLUGIN_BASE_CLASS (klass); + + GST_DEBUG_CATEGORY_INIT (gst_debug_vaapisink, + GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC); + + gst_vaapi_plugin_base_class_init (base_plugin_class); + base_plugin_class->has_interface = gst_vaapisink_has_interface; + base_plugin_class->display_changed = gst_vaapisink_display_changed; + + object_class->finalize = gst_vaapisink_finalize; + object_class->set_property = gst_vaapisink_set_property; + object_class->get_property = gst_vaapisink_get_property; + + basesink_class->start = gst_vaapisink_start; + basesink_class->stop = gst_vaapisink_stop; + basesink_class->get_caps = gst_vaapisink_get_caps; + basesink_class->set_caps = gst_vaapisink_set_caps; + basesink_class->query = GST_DEBUG_FUNCPTR (gst_vaapisink_query); + basesink_class->propose_allocation = gst_vaapisink_propose_allocation; + basesink_class->unlock = gst_vaapisink_unlock; + basesink_class->unlock_stop = gst_vaapisink_unlock_stop; + basesink_class->event = gst_vaapisink_event; + + videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_vaapisink_show_frame); + + element_class->set_context = gst_vaapi_base_set_context; + gst_element_class_set_static_metadata (element_class, + "VA-API sink", "Sink/Video", GST_PLUGIN_DESC, + "Gwenole Beauchesne "); + + gst_element_class_add_static_pad_template (element_class, + &gst_vaapisink_sink_factory); + + /** + * GstVaapiSink:display: + * + * The type of display to use. + */ + g_properties[PROP_DISPLAY_TYPE] = + g_param_spec_enum ("display", + "display type", + "display type to use", + GST_VAAPI_TYPE_DISPLAY_TYPE, + GST_VAAPI_DISPLAY_TYPE_ANY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * GstVaapiSink:display-name: + * + * The native display name. + */ + g_properties[PROP_DISPLAY_NAME] = + g_param_spec_string ("display-name", + "display name", + "display name to use", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * GstVaapiSink:fullscreen: + * + * Selects whether fullscreen mode is enabled or not. + */ + g_properties[PROP_FULLSCREEN] = + g_param_spec_boolean ("fullscreen", + "Fullscreen", + "Requests window in fullscreen state", + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * GstVaapiSink:rotation: + * + * The VA display rotation mode, expressed as a #GstVaapiRotation. + */ + g_properties[PROP_ROTATION] = + g_param_spec_enum (GST_VAAPI_DISPLAY_PROP_ROTATION, + "rotation", + "The display rotation mode", + GST_VAAPI_TYPE_ROTATION, + DEFAULT_ROTATION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * GstVaapiSink:force-aspect-ratio: + * + * When enabled, scaling respects video aspect ratio; when disabled, + * the video is distorted to fit the window. + */ + g_properties[PROP_FORCE_ASPECT_RATIO] = + g_param_spec_boolean ("force-aspect-ratio", + "Force aspect ratio", + "When enabled, scaling will respect original aspect ratio", + TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * GstVaapiSink:signal-handoffs: + * + * Send a signal after rendering the buffer. + */ + g_properties[PROP_SIGNAL_HANDOFFS] = + g_param_spec_boolean ("signal-handoffs", "Signal handoffs", + "Send a signal after rendering the buffer", DEFAULT_SIGNAL_HANDOFFS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * GstVaapiSink:view-id: + * + * When not set to -1, the displayed frame will always be the one + * that matches the view-id of the very first displayed frame. Any + * other number will indicate the desire to display the supplied + * view-id only. + */ + g_properties[PROP_VIEW_ID] = + g_param_spec_int ("view-id", + "View ID", + "ID of the view component of interest to display", + -1, G_MAXINT32, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * GstVaapiSink:hue: + * + * The VA display hue, expressed as a float value. Range is -180.0 + * to 180.0. Default value is 0.0 and represents no modification. + */ + g_properties[PROP_HUE] = + g_param_spec_float (GST_VAAPI_DISPLAY_PROP_HUE, + "hue", "The display hue value", -180.0, 180.0, 0.0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT); + + /** + * GstVaapiSink:saturation: + * + * The VA display saturation, expressed as a float value. Range is + * 0.0 to 2.0. Default value is 1.0 and represents no modification. + */ + g_properties[PROP_SATURATION] = + g_param_spec_float (GST_VAAPI_DISPLAY_PROP_SATURATION, + "saturation", + "The display saturation value", 0.0, 2.0, 1.0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT); + + /** + * GstVaapiSink:brightness: + * + * The VA display brightness, expressed as a float value. Range is + * -1.0 to 1.0. Default value is 0.0 and represents no modification. + */ + g_properties[PROP_BRIGHTNESS] = + g_param_spec_float (GST_VAAPI_DISPLAY_PROP_BRIGHTNESS, + "brightness", + "The display brightness value", -1.0, 1.0, 0.0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT); + + /** + * GstVaapiSink:contrast: + * + * The VA display contrast, expressed as a float value. Range is 0.0 + * to 2.0. Default value is 1.0 and represents no modification. + */ + g_properties[PROP_CONTRAST] = + g_param_spec_float (GST_VAAPI_DISPLAY_PROP_CONTRAST, + "contrast", + "The display contrast value", 0.0, 2.0, 1.0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT); + + g_object_class_install_properties (object_class, N_PROPERTIES, g_properties); + + /** + * GstVaapiSink::handoff: + * @object: the #GstVaapiSink instance + * @buffer: the buffer that was rendered + * + * This signal gets emitted after rendering the frame. + */ + gst_vaapisink_signals[HANDOFF_SIGNAL] = + g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic, + G_TYPE_NONE, 1, GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE); +} + +static void +gst_vaapisink_init (GstVaapiSink * sink) +{ + GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (sink); + guint i; + + gst_vaapi_plugin_base_init (plugin, GST_CAT_DEFAULT); + gst_vaapi_plugin_base_set_display_type (plugin, DEFAULT_DISPLAY_TYPE); + + sink->video_par_n = 1; + sink->video_par_d = 1; + sink->view_id = -1; + sink->handle_events = TRUE; + sink->rotation = DEFAULT_ROTATION; + sink->rotation_req = DEFAULT_ROTATION; + sink->rotation_tag = DEFAULT_ROTATION; + sink->keep_aspect = TRUE; + sink->signal_handoffs = DEFAULT_SIGNAL_HANDOFFS; + gst_video_info_init (&sink->video_info); + + for (i = 0; i < G_N_ELEMENTS (sink->cb_values); i++) + g_value_init (&sink->cb_values[i], G_TYPE_FLOAT); +} diff --git a/gst/vaapi/gstvaapisink.h b/gst/vaapi/gstvaapisink.h new file mode 100644 index 0000000000..525f422164 --- /dev/null +++ b/gst/vaapi/gstvaapisink.h @@ -0,0 +1,129 @@ +/* + * gstvaapisink.h - VA-API video sink + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPISINK_H +#define GST_VAAPISINK_H + +#include "gstvaapipluginbase.h" +#include +#include "gstvaapipluginutil.h" + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPISINK \ + (gst_vaapisink_get_type ()) +#define GST_VAAPISINK_CAST(obj) \ + ((GstVaapiSink *)(obj)) +#define GST_VAAPISINK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPISINK, GstVaapiSink)) +#define GST_VAAPISINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPISINK, GstVaapiSinkClass)) +#define GST_IS_VAAPISINK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPISINK)) +#define GST_IS_VAAPISINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPISINK)) +#define GST_VAAPISINK_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPISINK, GstVaapiSinkClass)) + +typedef struct _GstVaapiSink GstVaapiSink; +typedef struct _GstVaapiSinkClass GstVaapiSinkClass; +typedef struct _GstVaapiSinkBackend GstVaapiSinkBackend; + +typedef gboolean (*GstVaapiSinkCreateWindowFunc) (GstVaapiSink * sink, + guint width, guint height); +typedef gboolean (*GstVaapiSinkCreateWindowFromHandleFunc) (GstVaapiSink * sink, + guintptr window); +typedef gboolean (*GstVaapiSinkRenderSurfaceFunc) (GstVaapiSink * sink, + GstVaapiSurface * surface, const GstVaapiRectangle * surface_rect, + guint flags); +typedef gboolean (*GstVaapiSinkHandleEventsFunc) (GstVaapiSink * sink); +typedef gboolean (*GstVaapiSinkPreStartEventThreadFunc) (GstVaapiSink * sink); +typedef gboolean (*GstVaapiSinkPreStopEventThreadFunc) (GstVaapiSink * sink); + +struct _GstVaapiSinkBackend +{ + GstVaapiSinkCreateWindowFunc create_window; + GstVaapiSinkCreateWindowFromHandleFunc create_window_from_handle; + GstVaapiSinkRenderSurfaceFunc render_surface; + + /* Event threads handling */ + gboolean event_thread_needed; + GstVaapiSinkHandleEventsFunc handle_events; + GstVaapiSinkPreStartEventThreadFunc pre_start_event_thread; + GstVaapiSinkPreStopEventThreadFunc pre_stop_event_thread; +}; + +struct _GstVaapiSink +{ + /*< private >*/ + GstVaapiPluginBase parent_instance; + + const GstVaapiSinkBackend *backend; + + GstCaps *caps; + GstVaapiWindow *window; + guint window_width; + guint window_height; + GstBuffer *video_buffer; + guint video_width; + guint video_height; + gint video_par_n; + gint video_par_d; + GstVideoInfo video_info; + GstVaapiRectangle display_rect; + GstVaapiRotation rotation; + GstVaapiRotation rotation_req; + GstVaapiRotation rotation_tag; + GstVaapiRotation rotation_prop; + guint color_standard; + gint32 view_id; + GThread *event_thread; + gboolean event_thread_cancel; + + /* Color balance values */ + guint cb_changed; + GValue cb_values[4]; + GList *cb_channels; + + guint handle_events : 1; + guint foreign_window : 1; + guint fullscreen : 1; + guint use_overlay : 1; + guint use_rotation : 1; + guint keep_aspect : 1; + guint signal_handoffs : 1; +}; + +struct _GstVaapiSinkClass +{ + /*< private >*/ + GstVaapiPluginBaseClass parent_class; +}; + +GType +gst_vaapisink_get_type (void) G_GNUC_CONST; + +G_END_DECLS + +#endif /* GST_VAAPISINK_H */ diff --git a/gst/vaapi/gstvaapivideobuffer.c b/gst/vaapi/gstvaapivideobuffer.c new file mode 100644 index 0000000000..af79338b6e --- /dev/null +++ b/gst/vaapi/gstvaapivideobuffer.c @@ -0,0 +1,88 @@ +/* + * gstvaapivideobuffer.c - Gstreamer/VA video buffer + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapivideobuffer + * @short_description: VA video buffer for GStreamer + * + * This functions creates and decorates a #GstBuffer that is going to + * be used by VA base gstreamer elements. + */ + +#include "gstcompat.h" +#include "gstvaapivideobuffer.h" + +static GstBuffer * +new_vbuffer (GstVaapiVideoMeta * meta) +{ + GstBuffer *buffer; + + g_return_val_if_fail (meta != NULL, NULL); + + buffer = gst_buffer_new (); + if (buffer) + gst_buffer_set_vaapi_video_meta (buffer, meta); + gst_vaapi_video_meta_unref (meta); + return buffer; +} + +GstBuffer * +gst_vaapi_video_buffer_new (GstVaapiVideoMeta * meta) +{ + g_return_val_if_fail (meta != NULL, NULL); + + return new_vbuffer (gst_vaapi_video_meta_ref (meta)); +} + +GstBuffer * +gst_vaapi_video_buffer_new_empty (void) +{ + return gst_buffer_new (); +} + +GstBuffer * +gst_vaapi_video_buffer_new_from_pool (GstVaapiVideoPool * pool) +{ + return new_vbuffer (gst_vaapi_video_meta_new_from_pool (pool)); +} + +GstBuffer * +gst_vaapi_video_buffer_new_from_buffer (GstBuffer * buffer) +{ + GstVaapiVideoMeta *const meta = gst_buffer_get_vaapi_video_meta (buffer); + + return meta ? new_vbuffer (gst_vaapi_video_meta_ref (meta)) : NULL; +} + +GstBuffer * +gst_vaapi_video_buffer_new_with_image (GstVaapiImage * image) +{ + return new_vbuffer (gst_vaapi_video_meta_new_with_image (image)); +} + +GstBuffer * +gst_vaapi_video_buffer_new_with_surface_proxy (GstVaapiSurfaceProxy * proxy) +{ + return new_vbuffer (gst_vaapi_video_meta_new_with_surface_proxy (proxy)); +} diff --git a/gst/vaapi/gstvaapivideobuffer.h b/gst/vaapi/gstvaapivideobuffer.h new file mode 100644 index 0000000000..f751bc3e6e --- /dev/null +++ b/gst/vaapi/gstvaapivideobuffer.h @@ -0,0 +1,60 @@ +/* + * gstvaapivideobuffer.h - Gstreamer/VA video buffer + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_VIDEO_BUFFER_H +#define GST_VAAPI_VIDEO_BUFFER_H + +#include "gstvaapivideometa.h" + +G_BEGIN_DECLS + +typedef struct _GstVaapiVideoBuffer GstVaapiVideoBuffer; + +G_GNUC_INTERNAL +GstBuffer * +gst_vaapi_video_buffer_new (GstVaapiVideoMeta * meta); + +G_GNUC_INTERNAL +GstBuffer * +gst_vaapi_video_buffer_new_empty (void); + +G_GNUC_INTERNAL +GstBuffer * +gst_vaapi_video_buffer_new_from_pool (GstVaapiVideoPool * pool); + +G_GNUC_INTERNAL +GstBuffer * +gst_vaapi_video_buffer_new_from_buffer (GstBuffer * buffer); + +G_GNUC_INTERNAL +GstBuffer * +gst_vaapi_video_buffer_new_with_image (GstVaapiImage * image); + +G_GNUC_INTERNAL +GstBuffer * +gst_vaapi_video_buffer_new_with_surface_proxy (GstVaapiSurfaceProxy * proxy); + +G_END_DECLS + +#endif /* GST_VAAPI_VIDEO_BUFFER_H */ diff --git a/gst/vaapi/gstvaapivideobufferpool.c b/gst/vaapi/gstvaapivideobufferpool.c new file mode 100644 index 0000000000..d6c3ccd906 --- /dev/null +++ b/gst/vaapi/gstvaapivideobufferpool.c @@ -0,0 +1,637 @@ +/* + * gstvaapivideobufferpool.c - Gstreamer/VA video buffer pool + * + * Copyright (C) 2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gstcompat.h" +#include "gstvaapivideobufferpool.h" +#include "gstvaapivideobuffer.h" +#include "gstvaapivideomemory.h" +#include "gstvaapipluginutil.h" +#if (USE_GLX || USE_EGL) +#include "gstvaapivideometa_texture.h" +#endif + +GST_DEBUG_CATEGORY_STATIC (gst_debug_vaapivideopool); +#define GST_CAT_DEFAULT gst_debug_vaapivideopool + +enum +{ + PROP_0, + + PROP_DISPLAY, +}; + +struct _GstVaapiVideoBufferPoolPrivate +{ + GstAllocator *allocator; + GstVideoInfo vmeta_vinfo; + GstVaapiDisplay *display; + guint options; + guint use_dmabuf_memory:1; + guint forced_video_meta:1; + /* Map between surface and GstMemory, only DMA */ + GHashTable *dma_mem_map; +}; + +G_DEFINE_TYPE_WITH_PRIVATE (GstVaapiVideoBufferPool, + gst_vaapi_video_buffer_pool, GST_TYPE_BUFFER_POOL); + +static void +gst_vaapi_video_buffer_pool_finalize (GObject * object) +{ + GstVaapiVideoBufferPoolPrivate *const priv = + GST_VAAPI_VIDEO_BUFFER_POOL (object)->priv; + + gst_vaapi_display_replace (&priv->display, NULL); + gst_clear_object (&priv->allocator); + if (priv->dma_mem_map) + g_hash_table_destroy (priv->dma_mem_map); + + G_OBJECT_CLASS (gst_vaapi_video_buffer_pool_parent_class)->finalize (object); +} + +static void +gst_vaapi_video_buffer_pool_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstVaapiVideoBufferPoolPrivate *const priv = + GST_VAAPI_VIDEO_BUFFER_POOL (object)->priv; + + switch (prop_id) { + case PROP_DISPLAY: + priv->display = g_value_dup_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_video_buffer_pool_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstVaapiVideoBufferPoolPrivate *const priv = + GST_VAAPI_VIDEO_BUFFER_POOL (object)->priv; + + switch (prop_id) { + case PROP_DISPLAY: + g_value_set_pointer (value, priv->display); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +fill_video_alignment (GstVaapiVideoBufferPool * pool, GstVideoAlignment * align) +{ + GstVideoInfo *const vip = &pool->priv->vmeta_vinfo; + guint i; + gint nth_bit; + + gst_video_alignment_reset (align); + for (i = 0; i < GST_VIDEO_INFO_N_PLANES (vip); i++) { + nth_bit = g_bit_nth_lsf (GST_VIDEO_INFO_PLANE_STRIDE (vip, i), 0); + if (nth_bit >= 0) + align->stride_align[i] = (1U << nth_bit) - 1; + } +} + +static const gchar ** +gst_vaapi_video_buffer_pool_get_options (GstBufferPool * pool) +{ + static const gchar *g_options[] = { + GST_BUFFER_POOL_OPTION_VIDEO_META, + GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META, + GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META, + GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT, + NULL, + }; + + return g_options; +} + +static gboolean +gst_vaapi_video_buffer_pool_set_config (GstBufferPool * pool, + GstStructure * config) +{ + GstVaapiVideoBufferPool *const base_pool = GST_VAAPI_VIDEO_BUFFER_POOL (pool); + GstVaapiVideoBufferPoolPrivate *const priv = base_pool->priv; + GstCaps *caps; + GstVideoInfo new_allocation_vinfo; + const GstVideoInfo *allocator_vinfo; + const GstVideoInfo *negotiated_vinfo; + GstVideoAlignment align; + GstAllocator *allocator; + gboolean ret; + guint size, min_buffers, max_buffers; + guint surface_alloc_flags; + + GST_DEBUG_OBJECT (base_pool, "config %" GST_PTR_FORMAT, config); + + caps = NULL; + if (!gst_buffer_pool_config_get_params (config, &caps, &size, &min_buffers, + &max_buffers)) + goto error_invalid_config; + if (!caps) + goto error_no_caps; + if (!gst_video_info_from_caps (&new_allocation_vinfo, caps)) + goto error_invalid_caps; + + if (!gst_buffer_pool_config_has_option (config, + GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META)) + goto error_no_vaapi_video_meta_option; + + allocator = NULL; + if (!gst_buffer_pool_config_get_allocator (config, &allocator, NULL)) + goto error_invalid_allocator; + + /* it is a valid allocator? */ + if (allocator + && (g_strcmp0 (allocator->mem_type, GST_VAAPI_VIDEO_MEMORY_NAME) != 0 + && g_strcmp0 (allocator->mem_type, + GST_VAAPI_DMABUF_ALLOCATOR_NAME) != 0)) + goto error_invalid_allocator; + + /* get the allocator properties */ + if (allocator) { + priv->use_dmabuf_memory = gst_vaapi_is_dmabuf_allocator (allocator); + negotiated_vinfo = + gst_allocator_get_vaapi_negotiated_video_info (allocator); + allocator_vinfo = + gst_allocator_get_vaapi_video_info (allocator, &surface_alloc_flags); + } else { + priv->use_dmabuf_memory = FALSE; + negotiated_vinfo = NULL; + allocator_vinfo = NULL; + surface_alloc_flags = 0; + } + + /* reset or update the allocator if video resolution changed */ + if (allocator_vinfo + && gst_video_info_changed (allocator_vinfo, &new_allocation_vinfo)) { + gst_object_replace ((GstObject **) & priv->allocator, NULL); + + /* dmabuf allocator can change its parameters: no need to create a + * new one */ + if (priv->use_dmabuf_memory) { + gst_allocator_set_vaapi_video_info (allocator, &new_allocation_vinfo, + surface_alloc_flags); + } else { + allocator = NULL; + } + } + + /* create a new allocator if needed */ + if (!allocator) { + /* if no allocator set, let's create a VAAPI one */ + allocator = gst_vaapi_video_allocator_new (priv->display, + &new_allocation_vinfo, surface_alloc_flags, 0); + if (!allocator) + goto error_no_allocator; + + if (negotiated_vinfo) { + gst_allocator_set_vaapi_negotiated_video_info (allocator, + negotiated_vinfo); + } + + GST_INFO_OBJECT (base_pool, "created new allocator %" GST_PTR_FORMAT, + allocator); + gst_buffer_pool_config_set_allocator (config, allocator, NULL); + gst_object_unref (allocator); + } + + /* use the allocator and set the video info for the vmeta */ + if (allocator) { + if (priv->allocator) + gst_object_unref (priv->allocator); + if ((priv->allocator = allocator)) + gst_object_ref (allocator); + + negotiated_vinfo = + gst_allocator_get_vaapi_negotiated_video_info (priv->allocator); + allocator_vinfo = gst_allocator_get_vaapi_video_info (allocator, NULL); + priv->vmeta_vinfo = (negotiated_vinfo) ? + *negotiated_vinfo : *allocator_vinfo; + + /* last resource to set the correct buffer size */ + if (GST_VIDEO_INFO_SIZE (allocator_vinfo) != size) { + gst_buffer_pool_config_set_params (config, caps, + GST_VIDEO_INFO_SIZE (allocator_vinfo), min_buffers, max_buffers); + } + } + if (!priv->allocator) + goto error_no_allocator; + + priv->options = 0; + if (gst_buffer_pool_config_has_option (config, + GST_BUFFER_POOL_OPTION_VIDEO_META)) { + priv->options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META; + } else if (gst_caps_is_video_raw (caps) && !priv->use_dmabuf_memory) { + gint i; + + for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&new_allocation_vinfo); i++) { + if (GST_VIDEO_INFO_PLANE_OFFSET (&new_allocation_vinfo, i) != + GST_VIDEO_INFO_PLANE_OFFSET (&priv->vmeta_vinfo, i) || + GST_VIDEO_INFO_PLANE_STRIDE (&new_allocation_vinfo, i) != + GST_VIDEO_INFO_PLANE_STRIDE (&priv->vmeta_vinfo, i) || + GST_VIDEO_INFO_SIZE (&new_allocation_vinfo) != + GST_VIDEO_INFO_SIZE (&priv->vmeta_vinfo)) { + priv->options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META; + priv->forced_video_meta = TRUE; + GST_INFO_OBJECT (base_pool, "adding unrequested video meta"); + break; + } + } + } + + if (gst_buffer_pool_config_has_option (config, + GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT)) { + fill_video_alignment (GST_VAAPI_VIDEO_BUFFER_POOL (pool), &align); + gst_buffer_pool_config_set_video_alignment (config, &align); + } + + if (!priv->use_dmabuf_memory && gst_buffer_pool_config_has_option (config, + GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META)) + priv->options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD; + + ret = + GST_BUFFER_POOL_CLASS + (gst_vaapi_video_buffer_pool_parent_class)->set_config (pool, config); + return ret; + + /* ERRORS */ +error_invalid_config: + { + GST_WARNING_OBJECT (base_pool, "invalid config"); + return FALSE; + } +error_no_caps: + { + GST_WARNING_OBJECT (base_pool, "no caps in config"); + return FALSE; + } +error_invalid_caps: + { + GST_WARNING_OBJECT (base_pool, "invalid caps %" GST_PTR_FORMAT, caps); + return FALSE; + } +error_invalid_allocator: + { + GST_INFO_OBJECT (base_pool, "no allocator in config"); + return FALSE; + } +error_no_vaapi_video_meta_option: + { + GST_WARNING_OBJECT (base_pool, "no GstVaapiVideoMeta option in config"); + return FALSE; + } +error_no_allocator: + { + GST_WARNING_OBJECT (base_pool, "no allocator defined"); + return FALSE; + } +} + +static void +vaapi_buffer_pool_cache_dma_mem (GstVaapiVideoBufferPool * pool, + GstVaapiSurfaceProxy * proxy, GstMemory * mem) +{ + GstVaapiVideoBufferPoolPrivate *const priv = pool->priv; + GstVaapiSurface *surface; + + surface = GST_VAAPI_SURFACE_PROXY_SURFACE (proxy); + g_assert (surface); + g_assert (gst_vaapi_surface_peek_buffer_proxy (surface)); + + if (!priv->dma_mem_map) + priv->dma_mem_map = g_hash_table_new_full (g_direct_hash, + g_direct_equal, NULL, (GDestroyNotify) gst_memory_unref); + + if (!g_hash_table_contains (priv->dma_mem_map, surface)) { + g_hash_table_insert (priv->dma_mem_map, surface, gst_memory_ref (mem)); + } else { + g_assert (g_hash_table_lookup (priv->dma_mem_map, surface) == mem); + } +} + +static GstMemory * +vaapi_buffer_pool_lookup_dma_mem (GstVaapiVideoBufferPool * pool, + GstVaapiSurfaceProxy * proxy) +{ + GstVaapiSurface *surface; + GstVaapiVideoBufferPoolPrivate *const priv = pool->priv; + GstVaapiBufferProxy *buf_proxy; + GstMemory *mem; + + g_assert (priv->use_dmabuf_memory); + + if (!priv->dma_mem_map) + return NULL; + + surface = GST_VAAPI_SURFACE_PROXY_SURFACE (proxy); + g_assert (surface); + + buf_proxy = gst_vaapi_surface_peek_buffer_proxy (surface); + /* Have not exported yet */ + if (!buf_proxy) { + g_assert (!g_hash_table_contains (priv->dma_mem_map, surface)); + return NULL; + } + + mem = g_hash_table_lookup (priv->dma_mem_map, surface); + g_assert (mem); + + return gst_memory_ref (mem); +} + +static GstFlowReturn +gst_vaapi_video_buffer_pool_alloc_buffer (GstBufferPool * pool, + GstBuffer ** out_buffer_ptr, GstBufferPoolAcquireParams * params) +{ + GstVaapiVideoBufferPool *const base_pool = GST_VAAPI_VIDEO_BUFFER_POOL (pool); + GstVaapiVideoBufferPoolPrivate *const priv = base_pool->priv; + GstVaapiVideoBufferPoolAcquireParams *const priv_params = + (GstVaapiVideoBufferPoolAcquireParams *) params; + GstVaapiVideoMeta *meta; + GstMemory *mem; + GstBuffer *buffer; + + if (!priv->allocator) + goto error_no_allocator; + + meta = gst_vaapi_video_meta_new (priv->display); + if (!meta) + goto error_create_meta; + + buffer = gst_vaapi_video_buffer_new (meta); + + if (!buffer) + goto error_create_buffer; + + if (priv_params && priv_params->proxy) + gst_vaapi_video_meta_set_surface_proxy (meta, priv_params->proxy); + + if (priv->use_dmabuf_memory) { + mem = NULL; + if (priv_params && priv_params->proxy) { + mem = vaapi_buffer_pool_lookup_dma_mem (base_pool, priv_params->proxy); + if (!mem) { + mem = gst_vaapi_dmabuf_memory_new (priv->allocator, meta); + if (!mem) + goto error_create_memory; + + vaapi_buffer_pool_cache_dma_mem (base_pool, priv_params->proxy, mem); + } + } else { + mem = gst_vaapi_dmabuf_memory_new (priv->allocator, meta); + } + } else { + mem = gst_vaapi_video_memory_new (priv->allocator, meta); + } + if (!mem) + goto error_create_memory; + gst_vaapi_video_meta_replace (&meta, NULL); + gst_buffer_append_memory (buffer, mem); + + if (priv->options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META) { + GstVideoInfo *const vip = &priv->vmeta_vinfo; + GstVideoMeta *vmeta; + + vmeta = gst_buffer_add_video_meta_full (buffer, 0, + GST_VIDEO_INFO_FORMAT (vip), GST_VIDEO_INFO_WIDTH (vip), + GST_VIDEO_INFO_HEIGHT (vip), GST_VIDEO_INFO_N_PLANES (vip), + &GST_VIDEO_INFO_PLANE_OFFSET (vip, 0), + &GST_VIDEO_INFO_PLANE_STRIDE (vip, 0)); + + if (GST_VAAPI_IS_VIDEO_MEMORY (mem)) { + vmeta->map = gst_video_meta_map_vaapi_memory; + vmeta->unmap = gst_video_meta_unmap_vaapi_memory; + } + + GST_META_FLAG_SET (vmeta, GST_META_FLAG_POOLED); + } +#if (USE_GLX || USE_EGL) + if (priv->options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD) { + GstMeta *tex_meta = gst_buffer_add_texture_upload_meta (buffer); + if (tex_meta) + GST_META_FLAG_SET (tex_meta, GST_META_FLAG_POOLED); + } +#endif + + *out_buffer_ptr = buffer; + return GST_FLOW_OK; + + /* ERRORS */ +error_no_allocator: + { + GST_ERROR_OBJECT (base_pool, "no GstAllocator in buffer pool"); + return GST_FLOW_ERROR; + } +error_create_meta: + { + GST_ERROR_OBJECT (base_pool, "failed to allocate vaapi video meta"); + return GST_FLOW_ERROR; + } +error_create_buffer: + { + GST_ERROR_OBJECT (base_pool, "failed to create video buffer"); + gst_vaapi_video_meta_unref (meta); + return GST_FLOW_ERROR; + } +error_create_memory: + { + GST_ERROR_OBJECT (base_pool, "failed to create video memory"); + gst_buffer_unref (buffer); + gst_vaapi_video_meta_unref (meta); + return GST_FLOW_ERROR; + } +} + +static GstFlowReturn +gst_vaapi_video_buffer_pool_acquire_buffer (GstBufferPool * pool, + GstBuffer ** out_buffer_ptr, GstBufferPoolAcquireParams * params) +{ + GstVaapiVideoBufferPool *const base_pool = GST_VAAPI_VIDEO_BUFFER_POOL (pool); + GstVaapiVideoBufferPoolPrivate *const priv = base_pool->priv; + GstVaapiVideoBufferPoolAcquireParams *const priv_params = + (GstVaapiVideoBufferPoolAcquireParams *) params; + GstFlowReturn ret; + GstBuffer *buffer; + GstMemory *mem; + GstVaapiVideoMeta *meta; + GstVaapiSurface *surface; + + ret = + GST_BUFFER_POOL_CLASS + (gst_vaapi_video_buffer_pool_parent_class)->acquire_buffer (pool, &buffer, + params); + + if (!priv->use_dmabuf_memory || !params || !priv_params->proxy + || ret != GST_FLOW_OK) { + *out_buffer_ptr = buffer; + return ret; + } + + /* Some pool users, such as decode, needs to acquire a buffer for a + * specified surface (via surface proxy). If not it is a DMABuf, we + * just replace the underlying surface proxy of buffer's + * GstVaapiVideoMeta. But in DMABuf case, the thing is a little bit + * more complicated: + * + * For DMABuf, GstMemory is-a GstFdMemory, which doesn't provide a + * way to change its FD, thus once created it's bound to a + * surface. On the other side, for performace reason, when the + * buffer is released, the buffer and its memory are cached in the + * buffer pool, and at next acquire_buffer() may still reuse a + * buffer and its memory. But the pushed surface by the decoder may + * be different from the one popped by the pool, so we need to + * replace the buffer's memory with the correct one. */ + g_assert (gst_buffer_n_memory (buffer) == 1); + + /* Update the underlying surface proxy */ + meta = gst_buffer_get_vaapi_video_meta (buffer); + if (!meta) { + *out_buffer_ptr = buffer; + return GST_FLOW_ERROR; + } + gst_vaapi_video_meta_set_surface_proxy (meta, priv_params->proxy); + + mem = vaapi_buffer_pool_lookup_dma_mem (base_pool, priv_params->proxy); + if (mem) { + if (mem == gst_buffer_peek_memory (buffer, 0)) { + gst_memory_unref (mem); + *out_buffer_ptr = buffer; + return GST_FLOW_OK; + } + } else { + /* Should be an unexported surface */ + surface = GST_VAAPI_SURFACE_PROXY_SURFACE (priv_params->proxy); + g_assert (surface); + g_assert (gst_vaapi_surface_peek_buffer_proxy (surface) == NULL); + gst_vaapi_video_meta_set_surface_proxy (meta, priv_params->proxy); + mem = gst_vaapi_dmabuf_memory_new (priv->allocator, meta); + if (mem) + vaapi_buffer_pool_cache_dma_mem (base_pool, priv_params->proxy, mem); + } + + if (mem) { + gst_buffer_replace_memory (buffer, 0, mem); + gst_buffer_unset_flags (buffer, GST_BUFFER_FLAG_TAG_MEMORY); + *out_buffer_ptr = buffer; + return GST_FLOW_OK; + } else { + gst_buffer_unref (buffer); + *out_buffer_ptr = NULL; + return GST_FLOW_ERROR; + } +} + +static void +gst_vaapi_video_buffer_pool_reset_buffer (GstBufferPool * pool, + GstBuffer * buffer) +{ + GstMemory *const mem = gst_buffer_peek_memory (buffer, 0); + GstVaapiVideoMeta *meta; + + /* Release the underlying surface proxy */ + if (GST_VAAPI_IS_VIDEO_MEMORY (mem)) { + gst_vaapi_video_memory_reset_surface (GST_VAAPI_VIDEO_MEMORY_CAST (mem)); + } else if (!gst_vaapi_dmabuf_memory_holds_surface (mem)) { + /* If mem holds an internally created surface, don't reset it! + * While surface is passed, we should clear it to avoid wrong + * reference. */ + meta = gst_buffer_get_vaapi_video_meta (buffer); + g_assert (meta); + gst_vaapi_video_meta_set_surface_proxy (meta, NULL); + } + + GST_BUFFER_POOL_CLASS (gst_vaapi_video_buffer_pool_parent_class)->reset_buffer + (pool, buffer); +} + +static void +gst_vaapi_video_buffer_pool_class_init (GstVaapiVideoBufferPoolClass * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstBufferPoolClass *const pool_class = GST_BUFFER_POOL_CLASS (klass); + + GST_DEBUG_CATEGORY_INIT (gst_debug_vaapivideopool, + "vaapivideopool", 0, "VA-API video pool"); + + object_class->finalize = gst_vaapi_video_buffer_pool_finalize; + object_class->set_property = gst_vaapi_video_buffer_pool_set_property; + object_class->get_property = gst_vaapi_video_buffer_pool_get_property; + pool_class->get_options = gst_vaapi_video_buffer_pool_get_options; + pool_class->set_config = gst_vaapi_video_buffer_pool_set_config; + pool_class->alloc_buffer = gst_vaapi_video_buffer_pool_alloc_buffer; + pool_class->acquire_buffer = gst_vaapi_video_buffer_pool_acquire_buffer; + pool_class->reset_buffer = gst_vaapi_video_buffer_pool_reset_buffer; + + /** + * GstVaapiVideoBufferPool:display: + * + * The #GstVaapiDisplay this object is bound to. + */ + g_object_class_install_property + (object_class, + PROP_DISPLAY, + g_param_spec_object ("display", "Display", + "The GstVaapiDisplay to use for this video pool", + GST_TYPE_VAAPI_DISPLAY, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); +} + +static void +gst_vaapi_video_buffer_pool_init (GstVaapiVideoBufferPool * pool) +{ + pool->priv = gst_vaapi_video_buffer_pool_get_instance_private (pool); + pool->priv->dma_mem_map = NULL; +} + +GstBufferPool * +gst_vaapi_video_buffer_pool_new (GstVaapiDisplay * display) +{ + return g_object_new (GST_VAAPI_TYPE_VIDEO_BUFFER_POOL, + "display", display, NULL); +} + +/** + * gst_vaapi_video_buffer_pool_copy_buffer: + * @pool: a #GstVaapiVideoBufferPool + * + * Returns if the @pool force set of #GstVideoMeta. If so, the element + * should copy the generated buffer by the pool to a system allocated + * buffer. Otherwise, downstream could not display correctly the + * frame. + * + * Returns: %TRUE if #GstVideoMeta is forced. + **/ +gboolean +gst_vaapi_video_buffer_pool_copy_buffer (GstBufferPool * pool) +{ + GstVaapiVideoBufferPool *va_pool = (GstVaapiVideoBufferPool *) pool; + + g_return_val_if_fail (GST_VAAPI_IS_VIDEO_BUFFER_POOL (pool), FALSE); + + return va_pool->priv->forced_video_meta; +} diff --git a/gst/vaapi/gstvaapivideobufferpool.h b/gst/vaapi/gstvaapivideobufferpool.h new file mode 100644 index 0000000000..23321fc8f8 --- /dev/null +++ b/gst/vaapi/gstvaapivideobufferpool.h @@ -0,0 +1,129 @@ +/* + * gstvaapivideobufferpool.h - Gstreamer/VA video buffer pool + * + * Copyright (C) 2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_VIDEO_BUFFER_POOL_H +#define GST_VAAPI_VIDEO_BUFFER_POOL_H + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_VIDEO_BUFFER_POOL \ + (gst_vaapi_video_buffer_pool_get_type ()) +#define GST_VAAPI_VIDEO_BUFFER_POOL(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_VAAPI_TYPE_VIDEO_BUFFER_POOL, \ + GstVaapiVideoBufferPool)) +#define GST_VAAPI_VIDEO_BUFFER_POOL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_VAAPI_TYPE_VIDEO_BUFFER_POOL, \ + GstVaapiVideoBufferPoolClass)) +#define GST_VAAPI_IS_VIDEO_BUFFER_POOL(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_VAAPI_TYPE_VIDEO_BUFFER_POOL)) +#define GST_VAAPI_IS_VIDEO_BUFFER_POOL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_VAAPI_TYPE_VIDEO_BUFFER_POOL)) + +typedef struct _GstVaapiVideoBufferPoolAcquireParams GstVaapiVideoBufferPoolAcquireParams; +typedef struct _GstVaapiVideoBufferPool GstVaapiVideoBufferPool; +typedef struct _GstVaapiVideoBufferPoolClass GstVaapiVideoBufferPoolClass; +typedef struct _GstVaapiVideoBufferPoolPrivate GstVaapiVideoBufferPoolPrivate; + +/** + * GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META: + * + * An option that can be activated on bufferpool to request vaapi + * video metadata on buffers from the pool. + */ +#define GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META \ + "GstBufferPoolOptionVaapiVideoMeta" + +/** + * GstVaapiVideoBufferPoolOption: + * @GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META: + * @GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT: + * @GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD: + * + * Helper enum to handle the buffer pool options using bit operation. + **/ +typedef enum +{ + GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META = (1u << 0), + GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT = (1u << 1), + GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD = (1u << 2), +} GstVaapiVideoBufferPoolOption; + +/** + * GstVaapiVideoBufferPoolAcquireParams: + * @proxy: the #GstVaapiSurfaceProxy associated to the dmabuf-base + * memory + * + * Parameters passed to the gst_buffer_pool_acquire_buffer() function + * on a #GstVaapiVideoBufferPool, to control the allocation of the + * buffer. + * + * This is an extension of #GstBufferPoolAcquireParams + */ +struct _GstVaapiVideoBufferPoolAcquireParams +{ + GstBufferPoolAcquireParams parent_instance; + + GstVaapiSurfaceProxy *proxy; +}; + +/** + * GstVaapiVideoBufferPool: + * + * A VA video buffer pool object. + */ +struct _GstVaapiVideoBufferPool +{ + GstBufferPool parent_instance; + + /*< private >*/ + GstVaapiVideoBufferPoolPrivate *priv; +}; + +/** + * GstVaapiVideoBufferPoolClass: + * + * A VA video buffer pool class. + */ +struct _GstVaapiVideoBufferPoolClass +{ + GstBufferPoolClass parent_class; +}; + +G_GNUC_INTERNAL +GType +gst_vaapi_video_buffer_pool_get_type (void) G_GNUC_CONST; + +G_GNUC_INTERNAL +GstBufferPool * +gst_vaapi_video_buffer_pool_new (GstVaapiDisplay * display); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_video_buffer_pool_copy_buffer (GstBufferPool * pool); + +G_END_DECLS + +#endif /* GST_VAAPI_VIDEO_BUFFER_POOL_H */ diff --git a/gst/vaapi/gstvaapivideocontext.c b/gst/vaapi/gstvaapivideocontext.c new file mode 100644 index 0000000000..cc2967b833 --- /dev/null +++ b/gst/vaapi/gstvaapivideocontext.c @@ -0,0 +1,357 @@ +/* + * gstvaapivideocontext.c - GStreamer/VA video context + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * Copyright (C) 2013 Igalia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gstcompat.h" +#include "gstvaapivideocontext.h" +#if USE_GST_GL_HELPERS +# include +#endif +#if USE_X11 +#include +#endif +#if USE_WAYLAND +#include +#endif +#if USE_DRM +#include +#endif + +GST_DEBUG_CATEGORY_STATIC (GST_CAT_CONTEXT); + +static void +_init_context_debug (void) +{ +#ifndef GST_DISABLE_GST_DEBUG + static gsize _init = 0; + + if (g_once_init_enter (&_init)) { + GST_DEBUG_CATEGORY_GET (GST_CAT_CONTEXT, "GST_CONTEXT"); + g_once_init_leave (&_init, 1); + } +#endif +} + +void +gst_vaapi_video_context_set_display (GstContext * context, + GstVaapiDisplay * display) +{ + GstStructure *structure; + + g_return_if_fail (context != NULL); + + structure = gst_context_writable_structure (context); + gst_structure_set (structure, GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME, + GST_TYPE_VAAPI_DISPLAY, display, NULL); + /* The outside user may access it as a generic Gobject. */ + gst_structure_set (structure, "gst.vaapi.Display.GObject", + GST_TYPE_OBJECT, display, NULL); +} + +GstContext * +gst_vaapi_video_context_new_with_display (GstVaapiDisplay * display, + gboolean persistent) +{ + GstContext *context; + + context = gst_context_new (GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME, persistent); + gst_vaapi_video_context_set_display (context, display); + return context; +} + +gboolean +gst_vaapi_video_context_get_display (GstContext * context, gboolean app_context, + GstVaapiDisplay ** display_ptr) +{ + const GstStructure *structure; + const gchar *type; + GstVaapiDisplay *display = NULL; + + g_return_val_if_fail (GST_IS_CONTEXT (context), FALSE); + + type = gst_context_get_context_type (context); + + if (!g_strcmp0 (type, GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME)) { + structure = gst_context_get_structure (context); + return gst_structure_get (structure, GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME, + GST_TYPE_VAAPI_DISPLAY, display_ptr, NULL); + } + + if (app_context && !g_strcmp0 (type, GST_VAAPI_DISPLAY_APP_CONTEXT_TYPE_NAME)) { + VADisplay va_display = NULL; + structure = gst_context_get_structure (context); + + if (gst_structure_get (structure, "va-display", G_TYPE_POINTER, &va_display, + NULL)) { +#if USE_X11 + Display *x11_display = NULL; + if (gst_structure_get (structure, "x11-display", G_TYPE_POINTER, + &x11_display, NULL)) { + display = + gst_vaapi_display_x11_new_with_va_display (va_display, x11_display); + } +#endif +#if USE_WAYLAND + if (!display) { + struct wl_display *wl_display = NULL; + if (gst_structure_get (structure, "wl-display", G_TYPE_POINTER, + &wl_display, NULL)) { + display = + gst_vaapi_display_wayland_new_with_va_display (va_display, + wl_display); + } + } +#endif +#if USE_DRM + if (!display) { + gint fd = -1; + if (gst_structure_get (structure, "drm-device-fd", G_TYPE_INT, &fd, + NULL)) { + display = gst_vaapi_display_drm_new_with_va_display (va_display, fd); + } + } +#endif + + _init_context_debug (); + + if (!display) { + GST_CAT_WARNING (GST_CAT_CONTEXT, + "Cannot create GstVaapiDisplay if only VADisplay is provided"); + return FALSE; + } + GST_CAT_INFO (GST_CAT_CONTEXT, + "new display with context %" GST_PTR_FORMAT, display); + *display_ptr = display; + return TRUE; + } + } + + return FALSE; +} + +static gboolean +context_pad_query (const GValue * item, GValue * value, gpointer user_data) +{ + GstPad *const pad = g_value_get_object (item); + GstQuery *const query = user_data; + + if (gst_pad_peer_query (pad, query)) { + g_value_set_boolean (value, TRUE); + return FALSE; + } + + _init_context_debug (); + GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, pad, "context pad peer query failed"); + return TRUE; +} + +static gboolean +_gst_context_run_query (GstElement * element, GstQuery * query, + GstPadDirection direction) +{ + GstIteratorFoldFunction const func = context_pad_query; + GstIterator *it; + GValue res = { 0 }; + + g_value_init (&res, G_TYPE_BOOLEAN); + g_value_set_boolean (&res, FALSE); + + /* Ask neighbour */ + if (direction == GST_PAD_SRC) + it = gst_element_iterate_src_pads (element); + else + it = gst_element_iterate_sink_pads (element); + + while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC) + gst_iterator_resync (it); + gst_iterator_free (it); + + return g_value_get_boolean (&res); +} + +static gboolean +_gst_context_get_from_query (GstElement * element, GstQuery * query, + GstPadDirection direction) +{ + GstContext *ctxt; + + if (!_gst_context_run_query (element, query, direction)) + return FALSE; + + gst_query_parse_context (query, &ctxt); + if (!ctxt) + return FALSE; + + GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element, + "found context (%" GST_PTR_FORMAT ") in %s query", ctxt, + direction == GST_PAD_SRC ? "downstream" : "upstream"); + gst_element_set_context (element, ctxt); + return TRUE; +} + +static void +_gst_context_query (GstElement * element, const gchar * context_type) +{ + GstQuery *query; + GstMessage *msg; + + _init_context_debug (); + + /* 2) Query downstream with GST_QUERY_CONTEXT for the context and + check if downstream already has a context of the specific + type */ + /* 3) Query upstream with GST_QUERY_CONTEXT for the context and + check if upstream already has a context of the specific + type */ + query = gst_query_new_context (context_type); + if (_gst_context_get_from_query (element, query, GST_PAD_SRC)) + goto found; + if (_gst_context_get_from_query (element, query, GST_PAD_SINK)) + goto found; + + /* 4) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with + the required context types and afterwards check if an + usable context was set now as in 1). The message could + be handled by the parent bins of the element and the + application. */ + GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element, + "posting `need-context' message"); + msg = gst_message_new_need_context (GST_OBJECT_CAST (element), context_type); + if (!gst_element_post_message (element, msg)) + GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element, "No bus attached"); + + /* + * Whomever responds to the need-context message performs a + * GstElement::set_context() with the required context in which the + * element is required to update the display_ptr + */ + +found: + gst_query_unref (query); +} + +static gboolean +_gst_vaapi_sink_find_context (GstElement * element) +{ + GstQuery *query; + GstMessage *msg; + gboolean found; + + /* 1. Query upstream for an already created GstVaapiDisplay */ + query = gst_query_new_context (GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME); + found = _gst_context_get_from_query (element, query, GST_PAD_SINK); + gst_query_unref (query); + if (found) + return TRUE; + + /* 2. Post a GST_MESSAGE_NEED_CONTEXT message on the bus with a + * gst.vaapi.app.Display context from the application */ + msg = gst_message_new_need_context (GST_OBJECT_CAST (element), + GST_VAAPI_DISPLAY_APP_CONTEXT_TYPE_NAME); + if (!gst_element_post_message (element, msg)) { + _init_context_debug (); + GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element, "No bus attached"); + } + + return FALSE; +} + +gboolean +gst_vaapi_video_context_prepare (GstElement * element, + GstVaapiDisplay ** display_ptr) +{ + g_return_val_if_fail (element != NULL, FALSE); + g_return_val_if_fail (display_ptr != NULL, FALSE); + + /* 1) Check if the element already has a context of the specific + * type. + */ + if (*display_ptr) { + GST_LOG_OBJECT (element, "already have a display %" GST_PTR_FORMAT, + *display_ptr); + return TRUE; + } + + if (GST_IS_VIDEO_SINK (element)) { + if (!_gst_vaapi_sink_find_context (element) && *display_ptr) { + /* Propagate if display was created from application */ + gst_vaapi_video_context_propagate (element, *display_ptr); + } + } else { + _gst_context_query (element, GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME); + } + + if (*display_ptr) { + GST_LOG_OBJECT (element, "found a display %" GST_PTR_FORMAT, *display_ptr); + return TRUE; + } + + return FALSE; +} + +/* 5) Create a context by itself and post a GST_MESSAGE_HAVE_CONTEXT message + on the bus. */ +void +gst_vaapi_video_context_propagate (GstElement * element, + GstVaapiDisplay * display) +{ + GstContext *context; + GstMessage *msg; + + context = gst_vaapi_video_context_new_with_display (display, FALSE); + gst_element_set_context (element, context); + + _init_context_debug (); + GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element, + "posting `have-context' (%p) message with display %" GST_PTR_FORMAT, + context, display); + msg = gst_message_new_have_context (GST_OBJECT_CAST (element), context); + if (!gst_element_post_message (element, msg)) + GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element, "No bus attached"); +} + +/** + * gst_vaapi_find_gl_local_context: + * @element: the #GstElement where the search begins + * @gl_context_ptr: the pointer where the GstGL context is going to be + * stored + * + * Query the pipeline, downstream and upstream for a GstGL context + * + * Returns: %TRUE if found; otherwise %FALSE + **/ +gboolean +gst_vaapi_find_gl_local_context (GstElement * element, + GstObject ** gl_context_ptr) +{ +#if USE_GST_GL_HELPERS + GstGLContext **context_ptr = (GstGLContext **) gl_context_ptr; + + if (gst_gl_query_local_gl_context (element, GST_PAD_SRC, context_ptr)) + return TRUE; + if (gst_gl_query_local_gl_context (element, GST_PAD_SINK, context_ptr)) + return TRUE; +#endif + return FALSE; +} diff --git a/gst/vaapi/gstvaapivideocontext.h b/gst/vaapi/gstvaapivideocontext.h new file mode 100644 index 0000000000..8577ca452b --- /dev/null +++ b/gst/vaapi/gstvaapivideocontext.h @@ -0,0 +1,65 @@ +/* + * gstvaapivideocontext.h - GStreamer/VA video context + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * Copyright (C) 2013 Igalia + * Author: Víctor Manuel Jáquez Leal + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_VIDEO_CONTEXT_H +#define GST_VAAPI_VIDEO_CONTEXT_H + +#include + +#define GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME "gst.vaapi.Display" +#define GST_VAAPI_DISPLAY_APP_CONTEXT_TYPE_NAME "gst.vaapi.app.Display" + +G_GNUC_INTERNAL +void +gst_vaapi_video_context_set_display (GstContext * context, + GstVaapiDisplay * display); + +G_GNUC_INTERNAL +GstContext * +gst_vaapi_video_context_new_with_display (GstVaapiDisplay * display, + gboolean persistent); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_video_context_get_display (GstContext * context, gboolean app_context, + GstVaapiDisplay ** display_ptr); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_video_context_prepare (GstElement * element, + GstVaapiDisplay ** display_ptr); + +G_GNUC_INTERNAL +void +gst_vaapi_video_context_propagate (GstElement * element, + GstVaapiDisplay * display); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_find_gl_local_context (GstElement * element, + GstObject ** gl_context_ptr); + +#endif /* GST_VAAPI_VIDEO_CONTEXT_H */ diff --git a/gst/vaapi/gstvaapivideomemory.c b/gst/vaapi/gstvaapivideomemory.c new file mode 100644 index 0000000000..8c1f5887dc --- /dev/null +++ b/gst/vaapi/gstvaapivideomemory.c @@ -0,0 +1,1475 @@ +/* + * gstvaapivideomemory.c - Gstreamer/VA video memory + * + * Copyright (C) 2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gstcompat.h" +#include +#include +#include +#include +#include "gstvaapivideomemory.h" +#include "gstvaapipluginutil.h" + +GST_DEBUG_CATEGORY_STATIC (CAT_PERFORMANCE); +GST_DEBUG_CATEGORY_STATIC (gst_debug_vaapivideomemory); +#define GST_CAT_DEFAULT gst_debug_vaapivideomemory + +#ifndef GST_VIDEO_INFO_FORMAT_STRING +#define GST_VIDEO_INFO_FORMAT_STRING(vip) \ + gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (vip)) +#endif + +/* ------------------------------------------------------------------------ */ +/* --- GstVaapiVideoMemory --- */ +/* ------------------------------------------------------------------------ */ + +static void gst_vaapi_video_memory_reset_image (GstVaapiVideoMemory * mem); + +static void +_init_performance_debug (void) +{ +#ifndef GST_DISABLE_GST_DEBUG + static gsize _init = 0; + + if (g_once_init_enter (&_init)) { + GST_DEBUG_CATEGORY_GET (CAT_PERFORMANCE, "GST_PERFORMANCE"); + g_once_init_leave (&_init, 1); + } +#endif +} + +static void +_init_vaapi_video_memory_debug (void) +{ +#ifndef GST_DISABLE_GST_DEBUG + static gsize _init = 0; + + if (g_once_init_enter (&_init)) { + GST_DEBUG_CATEGORY_INIT (gst_debug_vaapivideomemory, "vaapivideomemory", 0, + "VA-API video memory allocator"); + g_once_init_leave (&_init, 1); + } +#endif +} + +static inline void +reset_image_usage (GstVaapiImageUsageFlags * flag) +{ + _init_performance_debug (); + GST_CAT_INFO (CAT_PERFORMANCE, "derive image failed, fallbacking to copy"); + *flag = GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS; +} + +static inline gboolean +use_native_formats (GstVaapiImageUsageFlags flag) +{ + return flag == GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS; +} + +static inline gboolean +use_direct_rendering (GstVaapiImageUsageFlags flag) +{ + return flag == GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_RENDER; +} + +static inline gboolean +use_direct_uploading (GstVaapiImageUsageFlags flag) +{ + return flag == GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_UPLOAD; +} + +static guchar * +get_image_data (GstVaapiImage * image) +{ + guchar *data; + VAImage va_image; + + data = gst_vaapi_image_get_plane (image, 0); + if (!data || !gst_vaapi_image_get_image (image, &va_image)) + return NULL; + + data -= va_image.offsets[0]; + return data; +} + +static GstVaapiImage * +new_image (GstVaapiDisplay * display, const GstVideoInfo * vip) +{ + if (!GST_VIDEO_INFO_WIDTH (vip) || !GST_VIDEO_INFO_HEIGHT (vip)) + return NULL; + return gst_vaapi_image_new (display, GST_VIDEO_INFO_FORMAT (vip), + GST_VIDEO_INFO_WIDTH (vip), GST_VIDEO_INFO_HEIGHT (vip)); +} + +static gboolean +ensure_image (GstVaapiVideoMemory * mem) +{ + if (!mem->image && !use_native_formats (mem->usage_flag)) { + mem->image = gst_vaapi_surface_derive_image (mem->surface); + if (!mem->image) { + reset_image_usage (&mem->usage_flag); + } else if (gst_vaapi_surface_get_format (mem->surface) != + GST_VIDEO_INFO_FORMAT (mem->image_info)) { + gst_mini_object_replace ((GstMiniObject **) & mem->image, NULL); + reset_image_usage (&mem->usage_flag); + } + } + + if (!mem->image) { + GstVaapiVideoAllocator *const allocator = + GST_VAAPI_VIDEO_ALLOCATOR_CAST (GST_MEMORY_CAST (mem)->allocator); + + mem->image = gst_vaapi_video_pool_get_object (allocator->image_pool); + if (!mem->image) + return FALSE; + } + gst_vaapi_video_meta_set_image (mem->meta, mem->image); + return TRUE; +} + +static gboolean +ensure_image_is_current (GstVaapiVideoMemory * mem) +{ + if (!use_native_formats (mem->usage_flag)) + return TRUE; + + if (!GST_VAAPI_VIDEO_MEMORY_FLAG_IS_SET (mem, + GST_VAAPI_VIDEO_MEMORY_FLAG_IMAGE_IS_CURRENT)) { + if (!gst_vaapi_surface_get_image (mem->surface, mem->image)) + return FALSE; + + GST_VAAPI_VIDEO_MEMORY_FLAG_SET (mem, + GST_VAAPI_VIDEO_MEMORY_FLAG_IMAGE_IS_CURRENT); + } + return TRUE; +} + +static GstVaapiSurfaceProxy * +new_surface_proxy (GstVaapiVideoMemory * mem) +{ + GstVaapiVideoAllocator *const allocator = + GST_VAAPI_VIDEO_ALLOCATOR_CAST (GST_MEMORY_CAST (mem)->allocator); + + return + gst_vaapi_surface_proxy_new_from_pool (GST_VAAPI_SURFACE_POOL + (allocator->surface_pool)); +} + +static gboolean +ensure_surface (GstVaapiVideoMemory * mem) +{ + if (!mem->proxy) { + gst_vaapi_surface_proxy_replace (&mem->proxy, + gst_vaapi_video_meta_get_surface_proxy (mem->meta)); + + if (!mem->proxy) { + mem->proxy = new_surface_proxy (mem); + if (!mem->proxy) + return FALSE; + gst_vaapi_video_meta_set_surface_proxy (mem->meta, mem->proxy); + } + } + mem->surface = GST_VAAPI_SURFACE_PROXY_SURFACE (mem->proxy); + return mem->surface != NULL; +} + +static gboolean +ensure_surface_is_current (GstVaapiVideoMemory * mem) +{ + if (!use_native_formats (mem->usage_flag)) + return TRUE; + + if (!GST_VAAPI_VIDEO_MEMORY_FLAG_IS_SET (mem, + GST_VAAPI_VIDEO_MEMORY_FLAG_SURFACE_IS_CURRENT)) { + if (GST_VAAPI_VIDEO_MEMORY_FLAG_IS_SET (mem, + GST_VAAPI_VIDEO_MEMORY_FLAG_IMAGE_IS_CURRENT) + && !gst_vaapi_surface_put_image (mem->surface, mem->image)) + return FALSE; + + GST_VAAPI_VIDEO_MEMORY_FLAG_SET (mem, + GST_VAAPI_VIDEO_MEMORY_FLAG_SURFACE_IS_CURRENT); + } + return TRUE; +} + +static inline gboolean +map_vaapi_memory (GstVaapiVideoMemory * mem, GstMapFlags flags) +{ + if (!ensure_surface (mem)) + goto error_no_surface; + if (!ensure_image (mem)) + goto error_no_image; + + /* Load VA image from surface only for read flag since it returns + * raw pixels */ + if ((flags & GST_MAP_READ) && !ensure_image_is_current (mem)) + goto error_no_current_image; + + if (!gst_vaapi_image_map (mem->image)) + goto error_map_image; + + /* Mark surface as dirty and expect updates from image */ + if (flags & GST_MAP_WRITE) + GST_VAAPI_VIDEO_MEMORY_FLAG_UNSET (mem, + GST_VAAPI_VIDEO_MEMORY_FLAG_SURFACE_IS_CURRENT); + + return TRUE; + +error_no_surface: + { + const GstVideoInfo *const vip = mem->surface_info; + GST_ERROR ("failed to extract VA surface of size %ux%u and format %s", + GST_VIDEO_INFO_WIDTH (vip), GST_VIDEO_INFO_HEIGHT (vip), + GST_VIDEO_INFO_FORMAT_STRING (vip)); + return FALSE; + } +error_no_image: + { + const GstVideoInfo *const vip = mem->image_info; + GST_ERROR ("failed to extract VA image of size %ux%u and format %s", + GST_VIDEO_INFO_WIDTH (vip), GST_VIDEO_INFO_HEIGHT (vip), + GST_VIDEO_INFO_FORMAT_STRING (vip)); + return FALSE; + } +error_no_current_image: + { + GST_ERROR ("failed to make image current"); + return FALSE; + } +error_map_image: + { + GST_ERROR ("failed to map image %" GST_VAAPI_ID_FORMAT, + GST_VAAPI_ID_ARGS (gst_vaapi_image_get_id (mem->image))); + return FALSE; + } +} + +static inline void +unmap_vaapi_memory (GstVaapiVideoMemory * mem, GstMapFlags flags) +{ + gst_vaapi_image_unmap (mem->image); + + if (flags & GST_MAP_WRITE) { + GST_VAAPI_VIDEO_MEMORY_FLAG_SET (mem, + GST_VAAPI_VIDEO_MEMORY_FLAG_IMAGE_IS_CURRENT); + } + + if (!use_native_formats (mem->usage_flag)) { + gst_vaapi_video_meta_set_image (mem->meta, NULL); + gst_vaapi_video_memory_reset_image (mem); + } +} + +gboolean +gst_video_meta_map_vaapi_memory (GstVideoMeta * meta, guint plane, + GstMapInfo * info, gpointer * data, gint * stride, GstMapFlags flags) +{ + gboolean ret = FALSE; + GstAllocator *allocator; + GstVaapiVideoMemory *const mem = + GST_VAAPI_VIDEO_MEMORY_CAST (gst_buffer_peek_memory (meta->buffer, 0)); + + g_return_val_if_fail (mem, FALSE); + g_return_val_if_fail (mem->meta, FALSE); + + allocator = GST_MEMORY_CAST (mem)->allocator; + g_return_val_if_fail (GST_VAAPI_IS_VIDEO_ALLOCATOR (allocator), FALSE); + + g_mutex_lock (&mem->lock); + if (mem->map_type && mem->map_type != GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_PLANAR) + goto error_incompatible_map; + + /* Map for writing */ + if (mem->map_count == 0) { + if (!map_vaapi_memory (mem, flags)) + goto out; + mem->map_type = GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_PLANAR; + } + mem->map_count++; + + *data = gst_vaapi_image_get_plane (mem->image, plane); + *stride = gst_vaapi_image_get_pitch (mem->image, plane); + info->flags = flags; + ret = (*data != NULL); + +out: + g_mutex_unlock (&mem->lock); + return ret; + + /* ERRORS */ +error_incompatible_map: + { + GST_ERROR ("incompatible map type (%d)", mem->map_type); + goto out; + } +} + +gboolean +gst_video_meta_unmap_vaapi_memory (GstVideoMeta * meta, guint plane, + GstMapInfo * info) +{ + GstAllocator *allocator; + GstVaapiVideoMemory *const mem = + GST_VAAPI_VIDEO_MEMORY_CAST (gst_buffer_peek_memory (meta->buffer, 0)); + + g_return_val_if_fail (mem, FALSE); + g_return_val_if_fail (mem->meta, FALSE); + g_return_val_if_fail (mem->surface, FALSE); + g_return_val_if_fail (mem->image, FALSE); + + allocator = GST_MEMORY_CAST (mem)->allocator; + g_return_val_if_fail (GST_VAAPI_IS_VIDEO_ALLOCATOR (allocator), FALSE); + + g_mutex_lock (&mem->lock); + if (--mem->map_count == 0) { + mem->map_type = 0; + + /* Unmap VA image used for read/writes */ + if (info->flags & GST_MAP_READWRITE) + unmap_vaapi_memory (mem, info->flags); + } + g_mutex_unlock (&mem->lock); + return TRUE; +} + +GstMemory * +gst_vaapi_video_memory_new (GstAllocator * base_allocator, + GstVaapiVideoMeta * meta) +{ + GstVaapiVideoAllocator *const allocator = + GST_VAAPI_VIDEO_ALLOCATOR_CAST (base_allocator); + const GstVideoInfo *vip; + GstVaapiVideoMemory *mem; + + g_return_val_if_fail (GST_VAAPI_IS_VIDEO_ALLOCATOR (allocator), NULL); + + mem = g_slice_new (GstVaapiVideoMemory); + if (!mem) + return NULL; + + vip = &allocator->image_info; + gst_memory_init (&mem->parent_instance, GST_MEMORY_FLAG_NO_SHARE, + base_allocator, NULL, GST_VIDEO_INFO_SIZE (vip), 0, + 0, GST_VIDEO_INFO_SIZE (vip)); + + mem->proxy = NULL; + mem->surface_info = &allocator->surface_info; + mem->surface = NULL; + mem->image_info = &allocator->image_info; + mem->image = NULL; + mem->meta = meta ? gst_vaapi_video_meta_ref (meta) : NULL; + mem->map_type = 0; + mem->map_count = 0; + mem->map_surface_id = VA_INVALID_ID; + mem->usage_flag = allocator->usage_flag; + g_mutex_init (&mem->lock); + + GST_VAAPI_VIDEO_MEMORY_FLAG_SET (mem, + GST_VAAPI_VIDEO_MEMORY_FLAG_SURFACE_IS_CURRENT); + return GST_MEMORY_CAST (mem); +} + +void +gst_vaapi_video_memory_reset_image (GstVaapiVideoMemory * mem) +{ + GstVaapiVideoAllocator *const allocator = + GST_VAAPI_VIDEO_ALLOCATOR_CAST (GST_MEMORY_CAST (mem)->allocator); + + if (!use_native_formats (mem->usage_flag)) + gst_mini_object_replace ((GstMiniObject **) & mem->image, NULL); + else if (mem->image) { + gst_vaapi_video_pool_put_object (allocator->image_pool, mem->image); + mem->image = NULL; + } + + /* Don't synchronize to surface, this shall have happened during + * unmaps */ + GST_VAAPI_VIDEO_MEMORY_FLAG_UNSET (mem, + GST_VAAPI_VIDEO_MEMORY_FLAG_IMAGE_IS_CURRENT); +} + +void +gst_vaapi_video_memory_reset_surface (GstVaapiVideoMemory * mem) +{ + mem->surface = NULL; + gst_vaapi_video_memory_reset_image (mem); + gst_vaapi_surface_proxy_replace (&mem->proxy, NULL); + if (mem->meta) + gst_vaapi_video_meta_set_surface_proxy (mem->meta, NULL); + + GST_VAAPI_VIDEO_MEMORY_FLAG_UNSET (mem, + GST_VAAPI_VIDEO_MEMORY_FLAG_SURFACE_IS_CURRENT); +} + +gboolean +gst_vaapi_video_memory_sync (GstVaapiVideoMemory * mem) +{ + g_return_val_if_fail (mem, FALSE); + + return ensure_surface_is_current (mem); +} + +static gpointer +gst_vaapi_video_memory_map (GstMemory * base_mem, gsize maxsize, guint flags) +{ + gpointer data = NULL; + GstVaapiVideoMemory *const mem = GST_VAAPI_VIDEO_MEMORY_CAST (base_mem); + + g_return_val_if_fail (mem, NULL); + g_return_val_if_fail (mem->meta, NULL); + + g_mutex_lock (&mem->lock); + if (mem->map_count == 0) { + switch (flags & (GST_MAP_READWRITE | GST_MAP_VAAPI)) { + case 0: + case GST_MAP_VAAPI: + // No flags set: return a GstVaapiSurfaceProxy + gst_vaapi_surface_proxy_replace (&mem->proxy, + gst_vaapi_video_meta_get_surface_proxy (mem->meta)); + if (!mem->proxy) + goto error_no_surface_proxy; + if (!ensure_surface_is_current (mem)) + goto error_no_current_surface; + mem->map_type = GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_SURFACE; + break; + case GST_MAP_READ: + if (!map_vaapi_memory (mem, flags)) + goto out; + mem->map_type = GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_LINEAR; + break; + default: + goto error_unsupported_map; + } + } + + switch (mem->map_type) { + case GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_SURFACE: + if (!mem->proxy) + goto error_no_surface_proxy; + + if (flags == GST_MAP_VAAPI) { + mem->map_surface_id = GST_VAAPI_SURFACE_PROXY_SURFACE_ID (mem->proxy); + if (mem->map_surface_id == VA_INVALID_ID) + goto error_no_current_surface; + + data = &mem->map_surface_id; + } else { + data = mem->proxy; + } + break; + case GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_LINEAR: + if (!mem->image) + goto error_no_image; + data = get_image_data (mem->image); + break; + default: + goto error_unsupported_map_type; + } + mem->map_count++; + +out: + g_mutex_unlock (&mem->lock); + return data; + + /* ERRORS */ +error_unsupported_map: + { + GST_ERROR ("unsupported map flags (0x%x)", flags); + goto out; + } +error_unsupported_map_type: + { + GST_ERROR ("unsupported map type (%d)", mem->map_type); + goto out; + } +error_no_surface_proxy: + { + GST_ERROR ("failed to extract GstVaapiSurfaceProxy from video meta"); + goto out; + } +error_no_current_surface: + { + GST_ERROR ("failed to make surface current"); + goto out; + } +error_no_image: + { + GST_ERROR ("failed to extract VA image from video buffer"); + goto out; + } +} + +static void +gst_vaapi_video_memory_unmap_full (GstMemory * base_mem, GstMapInfo * info) +{ + GstVaapiVideoMemory *const mem = GST_VAAPI_VIDEO_MEMORY_CAST (base_mem); + + g_mutex_lock (&mem->lock); + if (mem->map_count == 1) { + switch (mem->map_type) { + case GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_SURFACE: + mem->map_surface_id = VA_INVALID_ID; + gst_vaapi_surface_proxy_replace (&mem->proxy, NULL); + break; + case GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_LINEAR: + unmap_vaapi_memory (mem, info->flags); + break; + default: + goto error_incompatible_map; + } + mem->map_type = 0; + } + mem->map_count--; + +out: + g_mutex_unlock (&mem->lock); + return; + + /* ERRORS */ +error_incompatible_map: + { + GST_ERROR ("incompatible map type (%d)", mem->map_type); + goto out; + } +} + +static GstMemory * +gst_vaapi_video_memory_copy (GstMemory * base_mem, gssize offset, gssize size) +{ + GstVaapiVideoMemory *const mem = GST_VAAPI_VIDEO_MEMORY_CAST (base_mem); + GstVaapiVideoMeta *meta; + GstAllocator *allocator; + GstMemory *out_mem; + gsize maxsize; + + g_return_val_if_fail (mem, NULL); + g_return_val_if_fail (mem->meta, NULL); + + allocator = base_mem->allocator; + g_return_val_if_fail (GST_VAAPI_IS_VIDEO_ALLOCATOR (allocator), FALSE); + + /* XXX: this implements a soft-copy, i.e. underlying VA surfaces + are not copied */ + (void) gst_memory_get_sizes (base_mem, NULL, &maxsize); + if (offset != 0 || (size != -1 && (gsize) size != maxsize)) + goto error_unsupported; + + if (!ensure_surface_is_current (mem)) + goto error_no_current_surface; + + meta = gst_vaapi_video_meta_copy (mem->meta); + if (!meta) + goto error_allocate_memory; + + out_mem = gst_vaapi_video_memory_new (allocator, meta); + gst_vaapi_video_meta_unref (meta); + if (!out_mem) + goto error_allocate_memory; + return out_mem; + + /* ERRORS */ +error_no_current_surface: + { + GST_ERROR ("failed to make surface current"); + return NULL; + } +error_unsupported: + { + GST_ERROR ("failed to copy partial memory (unsupported operation)"); + return NULL; + } +error_allocate_memory: + { + GST_ERROR ("failed to allocate GstVaapiVideoMemory copy"); + return NULL; + } +} + +/* ------------------------------------------------------------------------ */ +/* --- GstVaapiVideoAllocator --- */ +/* ------------------------------------------------------------------------ */ + +G_DEFINE_TYPE (GstVaapiVideoAllocator, gst_vaapi_video_allocator, + GST_TYPE_ALLOCATOR); + +static void +gst_vaapi_video_allocator_free (GstAllocator * allocator, GstMemory * base_mem) +{ + GstVaapiVideoMemory *const mem = GST_VAAPI_VIDEO_MEMORY_CAST (base_mem); + + mem->surface = NULL; + gst_vaapi_video_memory_reset_image (mem); + gst_vaapi_surface_proxy_replace (&mem->proxy, NULL); + gst_vaapi_video_meta_replace (&mem->meta, NULL); + g_mutex_clear (&mem->lock); + g_slice_free (GstVaapiVideoMemory, mem); +} + +static void +gst_vaapi_video_allocator_finalize (GObject * object) +{ + GstVaapiVideoAllocator *const allocator = + GST_VAAPI_VIDEO_ALLOCATOR_CAST (object); + + gst_vaapi_video_pool_replace (&allocator->surface_pool, NULL); + gst_vaapi_video_pool_replace (&allocator->image_pool, NULL); + + G_OBJECT_CLASS (gst_vaapi_video_allocator_parent_class)->finalize (object); +} + +static void +gst_vaapi_video_allocator_class_init (GstVaapiVideoAllocatorClass * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstAllocatorClass *const allocator_class = GST_ALLOCATOR_CLASS (klass); + + _init_vaapi_video_memory_debug (); + + object_class->finalize = gst_vaapi_video_allocator_finalize; + allocator_class->free = gst_vaapi_video_allocator_free; +} + +static void +gst_vaapi_video_allocator_init (GstVaapiVideoAllocator * allocator) +{ + GstAllocator *const base_allocator = GST_ALLOCATOR_CAST (allocator); + + base_allocator->mem_type = GST_VAAPI_VIDEO_MEMORY_NAME; + base_allocator->mem_map = gst_vaapi_video_memory_map; + base_allocator->mem_unmap_full = gst_vaapi_video_memory_unmap_full; + base_allocator->mem_copy = gst_vaapi_video_memory_copy; + + GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC); +} + +static gboolean +gst_video_info_update_from_image (GstVideoInfo * vip, GstVaapiImage * image) +{ + GstVideoFormat format; + const guchar *data; + guint i, num_planes, data_size, width, height; + + /* Reset format from image */ + format = gst_vaapi_image_get_format (image); + gst_vaapi_image_get_size (image, &width, &height); + gst_video_info_set_format (vip, format, width, height); + + num_planes = gst_vaapi_image_get_plane_count (image); + g_return_val_if_fail (num_planes == GST_VIDEO_INFO_N_PLANES (vip), FALSE); + + /* Determine the base data pointer */ + data = get_image_data (image); + g_return_val_if_fail (data != NULL, FALSE); + data_size = gst_vaapi_image_get_data_size (image); + + /* Check that we don't have disjoint planes */ + for (i = 0; i < num_planes; i++) { + const guchar *const plane = gst_vaapi_image_get_plane (image, i); + if (plane - data > data_size) + return FALSE; + } + + /* Update GstVideoInfo structure */ + for (i = 0; i < num_planes; i++) { + const guchar *const plane = gst_vaapi_image_get_plane (image, i); + GST_VIDEO_INFO_PLANE_OFFSET (vip, i) = plane - data; + GST_VIDEO_INFO_PLANE_STRIDE (vip, i) = gst_vaapi_image_get_pitch (image, i); + } + GST_VIDEO_INFO_SIZE (vip) = data_size; + return TRUE; +} + +static gboolean +gst_video_info_update_from_surface (GstVideoInfo * vip, + GstVaapiSurface * surface) +{ + GstVaapiImage *image; + gboolean ret; + + ret = FALSE; + image = gst_vaapi_surface_derive_image (surface); + if (!image) + goto error_no_derive_image; + if (!gst_vaapi_image_map (image)) + goto error_cannot_map; + ret = gst_video_info_update_from_image (vip, image); + gst_vaapi_image_unmap (image); + +bail: + gst_vaapi_image_unref (image); + return ret; + + /* ERRORS */ +error_no_derive_image: + { + GST_INFO ("Cannot create a VA derived image from surface %p", surface); + return FALSE; + } +error_cannot_map: + { + GST_ERROR ("Cannot map VA derived image %p", image); + goto bail; + } +} + +#ifndef GST_DISABLE_GST_DEBUG +static const gchar * +gst_vaapi_image_usage_flags_to_string (GstVaapiImageUsageFlags usage_flag) +{ + switch (usage_flag) { + case GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS: + return "native uploading"; + case GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_RENDER: + return "direct rendering"; + case GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_UPLOAD: + return "direct uploading"; + default: + return "unknown"; + } +} +#endif + +static inline gboolean +allocator_configure_surface_try_specified_format (GstVaapiDisplay * display, + const GstVideoInfo * allocation_info, GstVaapiImageUsageFlags usage_flag, + guint surface_alloc_flag, GstVideoInfo * ret_surface_info, + GstVaapiImageUsageFlags * ret_usage_flag) +{ + GstVaapiImageUsageFlags rflag; + GstVaapiSurface *surface; + GstVideoInfo sinfo, rinfo; + + /* Try to create a surface with the given allocation info */ + surface = + gst_vaapi_surface_new_full (display, allocation_info, surface_alloc_flag); + if (!surface) + return FALSE; + + /* surface created and just native format usage was requested */ + if (use_native_formats (usage_flag)) { + rflag = GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS; + rinfo = *allocation_info; + goto out; + } + + /* Further checks whether that surface can support direct + * upload/render */ + if (gst_video_info_update_from_surface (&sinfo, surface)) { + if (GST_VIDEO_INFO_FORMAT (&sinfo) == + GST_VIDEO_INFO_FORMAT (allocation_info)) { + /* Set the correct flag */ + if (use_direct_rendering (usage_flag) + && !use_direct_uploading (usage_flag)) { + rflag = GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_RENDER; + } else if (!use_direct_rendering (usage_flag) + && use_direct_uploading (usage_flag)) { + rflag = GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_UPLOAD; + } else { + g_assert_not_reached (); + } + } else { + /* It shouldn't happen, but still it's possible. Just use + * native. */ + GST_FIXME ("Got a derive image with different format!"); + rflag = GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS; + } + + rinfo = sinfo; + goto out; + } + + /* Can not derive image or not the same format, don't use derived + images, just fallback to use native */ + rflag = GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS; + rinfo = *allocation_info; + +out: + gst_vaapi_surface_unref (surface); + + *ret_surface_info = rinfo; + *ret_usage_flag = rflag; + return TRUE; +} + +static inline gboolean +allocator_configure_surface_try_other_format (GstVaapiDisplay * display, + const GstVideoInfo * allocation_info, GstVideoInfo * ret_surface_info) +{ + GstVaapiSurface *surface; + GstVideoFormat fmt; + GstVideoInfo sinfo; + + /* Find a best native surface format if possible */ + fmt = gst_vaapi_video_format_get_best_native + (GST_VIDEO_INFO_FORMAT (allocation_info)); + if (fmt == GST_VIDEO_FORMAT_UNKNOWN + || fmt == GST_VIDEO_INFO_FORMAT (allocation_info)) + goto error_invalid_format; + + /* create a info with "best native" format */ + gst_video_info_set_format (&sinfo, fmt, + GST_VIDEO_INFO_WIDTH (allocation_info), + GST_VIDEO_INFO_HEIGHT (allocation_info)); + + /* try it */ + surface = gst_vaapi_surface_new_full (display, &sinfo, 0); + if (!surface) + goto error_no_surface; + gst_vaapi_surface_unref (surface); + + *ret_surface_info = sinfo; + return TRUE; + + /* ERRORS */ +error_invalid_format: + { + GST_ERROR ("Cannot handle format %s", + GST_VIDEO_INFO_FORMAT_STRING (allocation_info)); + return FALSE; + } +error_no_surface: + { + GST_ERROR ("Cannot create a VA Surface"); + return FALSE; + } +} + +static inline gboolean +allocator_configure_surface_info (GstVaapiDisplay * display, + GstVaapiVideoAllocator * allocator, GstVaapiImageUsageFlags req_usage_flag, + guint surface_alloc_flags) +{ + GstVaapiImageUsageFlags usage_flag; + GstVideoInfo allocation_info, surface_info; + + /* get rid of possible encoded format and assume NV12 */ + allocation_info = allocator->allocation_info; + gst_video_info_force_nv12_if_encoded (&allocation_info); + + /* Step1: Try the specified format and flag. May fallback to native if + direct upload/rendering is unavailable. */ + if (allocator_configure_surface_try_specified_format (display, + &allocation_info, req_usage_flag, surface_alloc_flags, + &surface_info, &usage_flag)) { + allocator->usage_flag = usage_flag; + allocator->surface_info = surface_info; + goto success; + } + + /* Step2: Try other surface format. Because format is different, + direct upload/rendering is unavailable, always use native */ + if (allocator_configure_surface_try_other_format (display, &allocation_info, + &surface_info)) { + allocator->usage_flag = GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS; + allocator->surface_info = surface_info; + goto success; + } + + GST_INFO_OBJECT (allocator, "Failed to configure the video format: %s" + " with usage flag: %s", + GST_VIDEO_INFO_FORMAT_STRING (&allocator->allocation_info), + gst_vaapi_image_usage_flags_to_string (req_usage_flag)); + return FALSE; + +success: + GST_DEBUG_OBJECT (allocator, "success to set the surface format %s" + " for video format %s with %s", + GST_VIDEO_INFO_FORMAT_STRING (&allocator->surface_info), + GST_VIDEO_INFO_FORMAT_STRING (&allocator->allocation_info), + gst_vaapi_image_usage_flags_to_string (allocator->usage_flag)); + return TRUE; +} + +static inline gboolean +allocator_configure_image_info (GstVaapiDisplay * display, + GstVaapiVideoAllocator * allocator) +{ + GstVaapiImage *image = NULL; + const GstVideoInfo *vinfo; + gboolean ret = FALSE; + + if (!use_native_formats (allocator->usage_flag)) { + allocator->image_info = allocator->surface_info; + return TRUE; + } + + vinfo = &allocator->allocation_info; + allocator->image_info = *vinfo; + gst_video_info_force_nv12_if_encoded (&allocator->image_info); + + image = new_image (display, &allocator->image_info); + if (!image) + goto error_no_image; + if (!gst_vaapi_image_map (image)) + goto error_cannot_map; + + gst_video_info_update_from_image (&allocator->image_info, image); + gst_vaapi_image_unmap (image); + ret = TRUE; + +bail: + if (image) + gst_vaapi_image_unref (image); + return ret; + + /* ERRORS */ +error_no_image: + { + GST_ERROR ("Cannot create VA image"); + return ret; + } +error_cannot_map: + { + GST_ERROR ("Failed to map VA image %p", image); + goto bail; + } +} + +static inline gboolean +allocator_params_init (GstVaapiVideoAllocator * allocator, + GstVaapiDisplay * display, const GstVideoInfo * alloc_info, + guint surface_alloc_flags, GstVaapiImageUsageFlags req_usage_flag) +{ + allocator->allocation_info = *alloc_info; + + if (!allocator_configure_surface_info (display, allocator, req_usage_flag, + surface_alloc_flags)) + return FALSE; + allocator->surface_pool = gst_vaapi_surface_pool_new_full (display, + &allocator->surface_info, surface_alloc_flags); + if (!allocator->surface_pool) + goto error_create_surface_pool; + + if (!allocator_configure_image_info (display, allocator)) + return FALSE; + allocator->image_pool = gst_vaapi_image_pool_new (display, + &allocator->image_info); + if (!allocator->image_pool) + goto error_create_image_pool; + + gst_allocator_set_vaapi_video_info (GST_ALLOCATOR_CAST (allocator), + &allocator->image_info, surface_alloc_flags); + + return TRUE; + + /* ERRORS */ +error_create_surface_pool: + { + GST_ERROR ("failed to allocate VA surface pool"); + return FALSE; + } +error_create_image_pool: + { + GST_ERROR ("failed to allocate VA image pool"); + return FALSE; + } +} + +GstAllocator * +gst_vaapi_video_allocator_new (GstVaapiDisplay * display, + const GstVideoInfo * alloc_info, guint surface_alloc_flags, + GstVaapiImageUsageFlags req_usage_flag) +{ + GstVaapiVideoAllocator *allocator; + + g_return_val_if_fail (display != NULL, NULL); + g_return_val_if_fail (alloc_info != NULL, NULL); + + allocator = g_object_new (GST_VAAPI_TYPE_VIDEO_ALLOCATOR, NULL); + if (!allocator) + return NULL; + + if (!allocator_params_init (allocator, display, alloc_info, + surface_alloc_flags, req_usage_flag)) { + g_object_unref (allocator); + return NULL; + } + + return GST_ALLOCATOR_CAST (allocator); +} + +/* ------------------------------------------------------------------------ */ +/* --- GstVaapiDmaBufMemory --- */ +/* ------------------------------------------------------------------------ */ + +#define GST_VAAPI_BUFFER_PROXY_QUARK gst_vaapi_buffer_proxy_quark_get () +static GQuark +gst_vaapi_buffer_proxy_quark_get (void) +{ + static gsize g_quark; + + if (g_once_init_enter (&g_quark)) { + gsize quark = (gsize) g_quark_from_static_string ("GstVaapiBufferProxy"); + g_once_init_leave (&g_quark, quark); + } + return g_quark; +} + +/* Whether @mem holds an internal VA surface proxy created at + * gst_vaapi_dmabuf_memory_new(). */ +gboolean +gst_vaapi_dmabuf_memory_holds_surface (GstMemory * mem) +{ + g_return_val_if_fail (mem != NULL, FALSE); + + return + GPOINTER_TO_INT (gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (mem), + GST_VAAPI_BUFFER_PROXY_QUARK)) == TRUE; +} + +GstMemory * +gst_vaapi_dmabuf_memory_new (GstAllocator * base_allocator, + GstVaapiVideoMeta * meta) +{ + GstMemory *mem; + GstVaapiDisplay *display; + GstVaapiSurface *surface; + GstVaapiSurfaceProxy *proxy; + GstVaapiBufferProxy *dmabuf_proxy; + gint dmabuf_fd; + const GstVideoInfo *surface_info; + guint surface_alloc_flags; + gboolean needs_surface; + GstVaapiDmaBufAllocator *const allocator = + GST_VAAPI_DMABUF_ALLOCATOR_CAST (base_allocator); + + g_return_val_if_fail (allocator != NULL, NULL); + g_return_val_if_fail (meta != NULL, NULL); + + surface_info = gst_allocator_get_vaapi_video_info (base_allocator, + &surface_alloc_flags); + if (!surface_info) + return NULL; + + display = gst_vaapi_video_meta_get_display (meta); + if (!display) + return NULL; + + proxy = gst_vaapi_video_meta_get_surface_proxy (meta); + needs_surface = (proxy == NULL); + + if (needs_surface) { + /* When exporting output VPP surfaces, or when exporting input + * surfaces to be filled/imported by an upstream element, such as + * v4l2src, we have to instantiate a VA surface to store it. */ + surface = gst_vaapi_surface_new_full (display, surface_info, + surface_alloc_flags); + if (!surface) + goto error_create_surface; + proxy = gst_vaapi_surface_proxy_new (surface); + if (!proxy) + goto error_create_surface_proxy; + /* The proxy has incremented the surface ref count. */ + gst_vaapi_surface_unref (surface); + } else { + /* When exporting existing surfaces that come from decoder's + * context. */ + surface = GST_VAAPI_SURFACE_PROXY_SURFACE (proxy); + } + + dmabuf_proxy = gst_vaapi_surface_peek_dma_buf_handle (surface); + if (!dmabuf_proxy) + goto error_create_dmabuf_proxy; + + if (needs_surface) { + gst_vaapi_video_meta_set_surface_proxy (meta, proxy); + /* meta holds the proxy's reference */ + gst_vaapi_surface_proxy_unref (proxy); + } + + /* Need dup because GstDmabufMemory creates the GstFdMemory with flag + * GST_FD_MEMORY_FLAG_NONE. So when being freed it calls close on the fd + * because GST_FD_MEMORY_FLAG_DONT_CLOSE is not set. */ + dmabuf_fd = gst_vaapi_buffer_proxy_get_handle (dmabuf_proxy); + if (dmabuf_fd < 0 || (dmabuf_fd = dup (dmabuf_fd)) < 0) + goto error_create_dmabuf_handle; + + mem = gst_dmabuf_allocator_alloc (base_allocator, dmabuf_fd, + gst_vaapi_buffer_proxy_get_size (dmabuf_proxy)); + if (!mem) + goto error_create_dmabuf_memory; + + if (needs_surface) { + /* qdata express that memory has an associated surface. */ + gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (mem), + GST_VAAPI_BUFFER_PROXY_QUARK, GINT_TO_POINTER (TRUE), NULL); + } + + /* When a VA surface is going to be filled by a VAAPI element + * (decoder or VPP), it has _not_ be marked as busy in the driver. + * Releasing the surface's derived image, held by the buffer proxy, + * the surface will be unmarked as busy. */ + if (allocator->direction == GST_PAD_SRC) + gst_vaapi_buffer_proxy_release_data (dmabuf_proxy); + + return mem; + + /* ERRORS */ +error_create_surface: + { + GST_ERROR ("failed to create VA surface (format:%s size:%ux%u)", + GST_VIDEO_INFO_FORMAT_STRING (surface_info), + GST_VIDEO_INFO_WIDTH (surface_info), + GST_VIDEO_INFO_HEIGHT (surface_info)); + return NULL; + } +error_create_surface_proxy: + { + GST_ERROR ("failed to create VA surface proxy"); + gst_vaapi_surface_unref (surface); + return NULL; + } +error_create_dmabuf_proxy: + { + GST_ERROR ("failed to export VA surface to DMABUF"); + if (surface) + gst_vaapi_surface_unref (surface); + if (proxy) + gst_vaapi_surface_proxy_unref (proxy); + return NULL; + } +error_create_dmabuf_handle: + { + GST_ERROR ("failed to duplicate DMABUF handle"); + gst_vaapi_buffer_proxy_unref (dmabuf_proxy); + return NULL; + } +error_create_dmabuf_memory: + { + GST_ERROR ("failed to create DMABUF memory"); + close (dmabuf_fd); + gst_vaapi_buffer_proxy_unref (dmabuf_proxy); + return NULL; + } +} + +/* ------------------------------------------------------------------------ */ +/* --- GstVaapiDmaBufAllocator --- */ +/* ------------------------------------------------------------------------ */ + +G_DEFINE_TYPE (GstVaapiDmaBufAllocator, + gst_vaapi_dmabuf_allocator, GST_TYPE_DMABUF_ALLOCATOR); + +static void +gst_vaapi_dmabuf_allocator_class_init (GstVaapiDmaBufAllocatorClass * klass) +{ + _init_vaapi_video_memory_debug (); +} + +static void +gst_vaapi_dmabuf_allocator_init (GstVaapiDmaBufAllocator * allocator) +{ + GstAllocator *const base_allocator = GST_ALLOCATOR_CAST (allocator); + + base_allocator->mem_type = GST_VAAPI_DMABUF_ALLOCATOR_NAME; + allocator->direction = GST_PAD_SINK; +} + +GstAllocator * +gst_vaapi_dmabuf_allocator_new (GstVaapiDisplay * display, + const GstVideoInfo * alloc_info, guint surface_alloc_flags, + GstPadDirection direction) +{ + GstVaapiDmaBufAllocator *allocator = NULL; + GstVaapiSurface *surface = NULL; + GstVideoInfo surface_info; + GstAllocator *base_allocator; + + g_return_val_if_fail (display != NULL, NULL); + g_return_val_if_fail (alloc_info != NULL, NULL); + + allocator = g_object_new (GST_VAAPI_TYPE_DMABUF_ALLOCATOR, NULL); + if (!allocator) + goto error_no_allocator; + + base_allocator = GST_ALLOCATOR_CAST (allocator); + + gst_video_info_set_format (&surface_info, GST_VIDEO_INFO_FORMAT (alloc_info), + GST_VIDEO_INFO_WIDTH (alloc_info), GST_VIDEO_INFO_HEIGHT (alloc_info)); + surface = gst_vaapi_surface_new_full (display, alloc_info, + surface_alloc_flags); + if (!surface) + goto error_no_surface; + if (!gst_video_info_update_from_surface (&surface_info, surface)) + goto fail; + gst_mini_object_replace ((GstMiniObject **) & surface, NULL); + + gst_allocator_set_vaapi_video_info (base_allocator, &surface_info, + surface_alloc_flags); + + allocator->direction = direction; + + return base_allocator; + + /* ERRORS */ +fail: + { + gst_mini_object_replace ((GstMiniObject **) & surface, NULL); + gst_object_replace ((GstObject **) & base_allocator, NULL); + return NULL; + } +error_no_allocator: + { + GST_ERROR ("failed to create a new dmabuf allocator"); + return NULL; + } +error_no_surface: + { + GST_ERROR ("failed to create a new surface"); + goto fail; + } +} + +/* ------------------------------------------------------------------------ */ +/* --- GstVaapiVideoInfo = { GstVideoInfo, flags } --- */ +/* ------------------------------------------------------------------------ */ + +#define GST_VAAPI_VIDEO_INFO_QUARK gst_vaapi_video_info_quark_get () +static GQuark +gst_vaapi_video_info_quark_get (void) +{ + static gsize g_quark; + + if (g_once_init_enter (&g_quark)) { + gsize quark = (gsize) g_quark_from_static_string ("GstVaapiVideoInfo"); + g_once_init_leave (&g_quark, quark); + } + return g_quark; +} + +#define ALLOCATION_VINFO_QUARK allocation_vinfo_quark_get () +static GQuark +allocation_vinfo_quark_get (void) +{ + static gsize g_quark; + + if (g_once_init_enter (&g_quark)) { + gsize quark = (gsize) g_quark_from_static_string ("allocation-vinfo"); + g_once_init_leave (&g_quark, quark); + } + return g_quark; +} + +#define SURFACE_ALLOC_FLAGS_QUARK surface_alloc_flags_quark_get () +static GQuark +surface_alloc_flags_quark_get (void) +{ + static gsize g_quark; + + if (g_once_init_enter (&g_quark)) { + gsize quark = (gsize) g_quark_from_static_string ("surface-alloc-flags"); + g_once_init_leave (&g_quark, quark); + } + return g_quark; +} + +#define NEGOTIATED_VINFO_QUARK negotiated_vinfo_quark_get () +static GQuark +negotiated_vinfo_quark_get (void) +{ + static gsize g_quark; + + if (g_once_init_enter (&g_quark)) { + gsize quark = (gsize) g_quark_from_static_string ("negotiated-vinfo"); + g_once_init_leave (&g_quark, quark); + } + return g_quark; +} + +/** + * gst_allocator_get_vaapi_video_info: + * @allocator: a #GstAllocator + * @out_flags_ptr: (out): the stored surface allocation flags + * + * Will get the @allocator qdata to fetch the flags and the + * allocation's #GstVideoInfo stored in it. + * + * The allocation video info, is the image video info in the case of + * the #GstVaapiVideoAllocator; and the allocation video info in the + * case of #GstVaapiDmaBufAllocator. + * + * Returns: the stored #GstVideoInfo + **/ +const GstVideoInfo * +gst_allocator_get_vaapi_video_info (GstAllocator * allocator, + guint * out_flags_ptr) +{ + const GstStructure *structure; + const GValue *value; + + g_return_val_if_fail (GST_IS_ALLOCATOR (allocator), NULL); + + structure = + g_object_get_qdata (G_OBJECT (allocator), GST_VAAPI_VIDEO_INFO_QUARK); + if (!structure) + return NULL; + + if (out_flags_ptr) { + value = gst_structure_id_get_value (structure, SURFACE_ALLOC_FLAGS_QUARK); + if (!value) + return NULL; + *out_flags_ptr = g_value_get_uint (value); + } + + value = gst_structure_id_get_value (structure, ALLOCATION_VINFO_QUARK); + if (!value) + return NULL; + return g_value_get_boxed (value); +} + +/** + * gst_allocator_set_vaapi_video_info: + * @allocator: a #GstAllocator + * @alloc_info: the allocation #GstVideoInfo to store + * @surface_alloc_flags: the flags to store + * + * Stores as GObject's qdata the @alloc_info and the + * @surface_alloc_flags in the allocator. This will "decorate" the + * allocator as a GstVaapi one. + * + * Returns: always %TRUE + **/ +gboolean +gst_allocator_set_vaapi_video_info (GstAllocator * allocator, + const GstVideoInfo * alloc_info, guint surface_alloc_flags) +{ + g_return_val_if_fail (GST_IS_ALLOCATOR (allocator), FALSE); + g_return_val_if_fail (alloc_info != NULL, FALSE); + + g_object_set_qdata_full (G_OBJECT (allocator), GST_VAAPI_VIDEO_INFO_QUARK, + gst_structure_new_id (GST_VAAPI_VIDEO_INFO_QUARK, + ALLOCATION_VINFO_QUARK, GST_TYPE_VIDEO_INFO, alloc_info, + SURFACE_ALLOC_FLAGS_QUARK, G_TYPE_UINT, surface_alloc_flags, NULL), + (GDestroyNotify) gst_structure_free); + + return TRUE; +} + +/** + * gst_allocator_set_vaapi_negotiated_video_info: + * @allocator: a #GstAllocator + * @negotiated_vinfo: the negotiated #GstVideoInfo to store. If NULL, then + * removes any previously set value. + * + * Stores as GObject's qdata the @negotiated_vinfo in the allocator + * instance. + * + * The @negotiated_vinfo is different of the @alloc_info from + * gst_allocator_set_vaapi_video_info(), and might not be set. + **/ +void +gst_allocator_set_vaapi_negotiated_video_info (GstAllocator * allocator, + const GstVideoInfo * negotiated_vinfo) +{ + g_return_if_fail (allocator && GST_IS_ALLOCATOR (allocator)); + + if (negotiated_vinfo) + g_object_set_qdata_full (G_OBJECT (allocator), NEGOTIATED_VINFO_QUARK, + gst_video_info_copy (negotiated_vinfo), + (GDestroyNotify) gst_video_info_free); + else + g_object_set_qdata (G_OBJECT (allocator), NEGOTIATED_VINFO_QUARK, NULL); +} + +/** + * gst_allocator_get_vaapi_negotiated_video_info: + * @allocator: a #GstAllocator + * + * Returns: the stored negotiation #GstVideoInfo, if it was stored + * previously. Otherwise, %NULL + **/ +GstVideoInfo * +gst_allocator_get_vaapi_negotiated_video_info (GstAllocator * allocator) +{ + g_return_val_if_fail (GST_IS_ALLOCATOR (allocator), NULL); + + return g_object_get_qdata (G_OBJECT (allocator), NEGOTIATED_VINFO_QUARK); +} + +/** + * gst_vaapi_is_dmabuf_allocator: + * @allocator: an #GstAllocator + * + * Checks if the allocator is DMABuf allocator with the GstVaapi + * decorator. + * + * Returns: %TRUE if @allocator is a DMABuf allocator type with + * GstVaapi decorator. + **/ +gboolean +gst_vaapi_is_dmabuf_allocator (GstAllocator * allocator) +{ + GstStructure *st; + + g_return_val_if_fail (GST_IS_ALLOCATOR (allocator), FALSE); + + if (g_strcmp0 (allocator->mem_type, GST_VAAPI_DMABUF_ALLOCATOR_NAME) != 0) + return FALSE; + st = g_object_get_qdata (G_OBJECT (allocator), GST_VAAPI_VIDEO_INFO_QUARK); + return (st != NULL); +} + +/** + * gst_vaapi_dmabuf_can_map: + * @display: a #GstVaapiDisplay + * @allocator: a #GstAllocator + * + * It will create a dmabuf-based buffer using @allocator, and it will + * try to map it using gst_memory_map(). + * + * Returns: %TRUE if the internal dummy buffer can be + * mapped. Otherwise %FALSE. + **/ +gboolean +gst_vaapi_dmabuf_can_map (GstVaapiDisplay * display, GstAllocator * allocator) +{ + GstVaapiVideoMeta *meta; + GstMemory *mem; + GstMapInfo info; + gboolean ret; + + g_return_val_if_fail (display != NULL, FALSE); + + ret = FALSE; + mem = NULL; + meta = NULL; + if (!gst_vaapi_is_dmabuf_allocator (allocator)) + return FALSE; + meta = gst_vaapi_video_meta_new (display); + if (!meta) + return FALSE; + mem = gst_vaapi_dmabuf_memory_new (allocator, meta); + if (!mem) + goto bail; + + if (!gst_memory_map (mem, &info, GST_MAP_READWRITE) || info.size == 0) + goto bail; + + gst_memory_unmap (mem, &info); + ret = TRUE; + +bail: + if (mem) + gst_memory_unref (mem); + if (meta) + gst_vaapi_video_meta_unref (meta); + return ret; +} diff --git a/gst/vaapi/gstvaapivideomemory.h b/gst/vaapi/gstvaapivideomemory.h new file mode 100644 index 0000000000..23d68ad7be --- /dev/null +++ b/gst/vaapi/gstvaapivideomemory.h @@ -0,0 +1,304 @@ +/* + * gstvaapivideomemory.h - Gstreamer/VA video memory + * + * Copyright (C) 2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_VIDEO_MEMORY_H +#define GST_VAAPI_VIDEO_MEMORY_H + +#include +#include +#include +#include +#include "gstvaapivideometa.h" +#include + +G_BEGIN_DECLS + +typedef struct _GstVaapiVideoMemory GstVaapiVideoMemory; +typedef struct _GstVaapiVideoAllocator GstVaapiVideoAllocator; +typedef struct _GstVaapiVideoAllocatorClass GstVaapiVideoAllocatorClass; +typedef struct _GstVaapiDmaBufAllocator GstVaapiDmaBufAllocator; +typedef struct _GstVaapiDmaBufAllocatorClass GstVaapiDmaBufAllocatorClass; + +/* ------------------------------------------------------------------------ */ +/* --- GstVaapiVideoMemory --- */ +/* ------------------------------------------------------------------------ */ + +#define GST_VAAPI_VIDEO_MEMORY_CAST(mem) \ + ((GstVaapiVideoMemory *) (mem)) + +#define GST_VAAPI_IS_VIDEO_MEMORY(mem) \ + ((mem) && (mem)->allocator && GST_VAAPI_IS_VIDEO_ALLOCATOR((mem)->allocator)) + +#define GST_VAAPI_VIDEO_MEMORY_NAME "GstVaapiVideoMemory" + +#define GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE "memory:VASurface" + +#define GST_VAAPI_VIDEO_MEMORY_FLAG_IS_SET(mem, flag) \ + GST_MEMORY_FLAG_IS_SET (mem, flag) +#define GST_VAAPI_VIDEO_MEMORY_FLAG_SET(mem, flag) \ + GST_MINI_OBJECT_FLAG_SET (mem, flag) +#define GST_VAAPI_VIDEO_MEMORY_FLAG_UNSET(mem, flag) \ + GST_MEMORY_FLAG_UNSET (mem, flag) + +/** + * GstVaapiVideoMemoryMapType: + * @GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_SURFACE: map with gst_buffer_map() + * and flags = 0x00 to return a #GstVaapiSurfaceProxy + * @GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_PLANAR: map individual plane with + * gst_video_frame_map() + * @GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_LINEAR: map with gst_buffer_map() + * and flags = GST_MAP_READ to return the raw pixels of the whole image + * + * The set of all #GstVaapiVideoMemory map types. + */ +typedef enum +{ + GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_SURFACE = 1, + GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_PLANAR, + GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_LINEAR +} GstVaapiVideoMemoryMapType; + +/** + * GstVaapiVideoMemoryFlags: + * @GST_VAAPI_VIDEO_MEMORY_FLAG_SURFACE_IS_CURRENT: The embedded + * #GstVaapiSurface has the up-to-date video frame contents. + * @GST_VAAPI_VIDEO_MEMORY_FLAG_IMAGE_IS_CURRENT: The embedded + * #GstVaapiImage has the up-to-date video frame contents. + * + * The set of extended #GstMemory flags. + */ +typedef enum +{ + GST_VAAPI_VIDEO_MEMORY_FLAG_SURFACE_IS_CURRENT = GST_MEMORY_FLAG_LAST << 0, + GST_VAAPI_VIDEO_MEMORY_FLAG_IMAGE_IS_CURRENT = GST_MEMORY_FLAG_LAST << 1, +} GstVaapiVideoMemoryFlags; + +/** + * GstVaapiImageUsageFlags: + * @GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS: will use vaCreateImage + + * va{Put,Get}Image when writing or reading onto the system memory. + * @GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_UPLOAD: will try to use + * vaDeriveImage when writing data from the system memory. + * @GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_RENDER: will try to use + * vaDeriveImage with reading data onto the system memory. + * + * Set the usage of GstVaapiImage in GstVaapiVideoMemory. + **/ +typedef enum { + GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS, + GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_UPLOAD, + GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_RENDER, +} GstVaapiImageUsageFlags; + +/** + * GstVaapiVideoMemory: + * + * A VA video memory object holder, including VA surfaces, images and + * proxies. + */ +struct _GstVaapiVideoMemory +{ + GstMemory parent_instance; + + /*< private >*/ + GstVaapiSurfaceProxy *proxy; + const GstVideoInfo *surface_info; + GstVaapiSurface *surface; + const GstVideoInfo *image_info; + GstVaapiImage *image; + GstVaapiVideoMeta *meta; + guint map_type; + gint map_count; + VASurfaceID map_surface_id; + GstVaapiImageUsageFlags usage_flag; + GMutex lock; +}; + +G_GNUC_INTERNAL +GstMemory * +gst_vaapi_video_memory_new (GstAllocator * allocator, GstVaapiVideoMeta * meta); + +G_GNUC_INTERNAL +gboolean +gst_video_meta_map_vaapi_memory (GstVideoMeta * meta, guint plane, + GstMapInfo * info, gpointer * data, gint * stride, GstMapFlags flags); + +G_GNUC_INTERNAL +gboolean +gst_video_meta_unmap_vaapi_memory (GstVideoMeta * meta, guint plane, + GstMapInfo * info); + +G_GNUC_INTERNAL +void +gst_vaapi_video_memory_reset_surface (GstVaapiVideoMemory * mem); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_video_memory_sync (GstVaapiVideoMemory * mem); + +/* ------------------------------------------------------------------------ */ +/* --- GstVaapiVideoAllocator --- */ +/* ------------------------------------------------------------------------ */ +#define GST_MAP_VAAPI (GST_MAP_FLAG_LAST << 1) + +#define GST_VAAPI_VIDEO_ALLOCATOR_CAST(allocator) \ + ((GstVaapiVideoAllocator *) (allocator)) + +#define GST_VAAPI_TYPE_VIDEO_ALLOCATOR \ + (gst_vaapi_video_allocator_get_type ()) +#define GST_VAAPI_VIDEO_ALLOCATOR(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_VAAPI_TYPE_VIDEO_ALLOCATOR, \ + GstVaapiVideoAllocator)) +#define GST_VAAPI_IS_VIDEO_ALLOCATOR(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_VAAPI_TYPE_VIDEO_ALLOCATOR)) + +/** + * GstVaapiVideoAllocator: + * + * A VA video memory allocator object. + */ +struct _GstVaapiVideoAllocator +{ + GstAllocator parent_instance; + + /*< private >*/ + GstVideoInfo allocation_info; + GstVideoInfo surface_info; + GstVaapiVideoPool *surface_pool; + GstVideoInfo image_info; + GstVaapiVideoPool *image_pool; + GstVaapiImageUsageFlags usage_flag; +}; + +/** + * GstVaapiVideoAllocatorClass: + * + * A VA video memory allocator class. + */ +struct _GstVaapiVideoAllocatorClass +{ + GstAllocatorClass parent_class; +}; + +G_GNUC_INTERNAL +GType +gst_vaapi_video_allocator_get_type (void) G_GNUC_CONST; + +G_GNUC_INTERNAL +GstAllocator * +gst_vaapi_video_allocator_new (GstVaapiDisplay * display, + const GstVideoInfo * alloc_info, guint surface_alloc_flags, + GstVaapiImageUsageFlags req_usage_flag); + +/* ------------------------------------------------------------------------ */ +/* --- GstVaapiDmaBufMemory --- */ +/* ------------------------------------------------------------------------ */ + +G_GNUC_INTERNAL +GstMemory * +gst_vaapi_dmabuf_memory_new (GstAllocator * allocator, + GstVaapiVideoMeta * meta); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_dmabuf_memory_holds_surface (GstMemory * mem); + +/* ------------------------------------------------------------------------ */ +/* --- GstVaapiDmaBufAllocator --- */ +/* ------------------------------------------------------------------------ */ + +#define GST_VAAPI_DMABUF_ALLOCATOR_CAST(allocator) \ + ((GstVaapiDmaBufAllocator *) (allocator)) + +#define GST_VAAPI_TYPE_DMABUF_ALLOCATOR \ + (gst_vaapi_dmabuf_allocator_get_type ()) +#define GST_VAAPI_DMABUF_ALLOCATOR(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_VAAPI_TYPE_DMABUF_ALLOCATOR, \ + GstVaapiDmaBufAllocator)) +#define GST_VAAPI_IS_DMABUF_ALLOCATOR(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_VAAPI_TYPE_DMABUF_ALLOCATOR)) + +#define GST_VAAPI_DMABUF_ALLOCATOR_NAME "GstVaapiDmaBufAllocator" + +/** + * GstVaapiDmaBufAllocator: + * + * A VA dmabuf memory allocator object. + */ +struct _GstVaapiDmaBufAllocator +{ + GstDmaBufAllocator parent_instance; + + /*< private >*/ + GstPadDirection direction; +}; + +/** + * GstVaapiDmaBufoAllocatorClass: + * + * A VA dmabuf memory allocator class. + */ +struct _GstVaapiDmaBufAllocatorClass +{ + GstDmaBufAllocatorClass parent_class; +}; + +G_GNUC_INTERNAL +GType +gst_vaapi_dmabuf_allocator_get_type (void) G_GNUC_CONST; + +G_GNUC_INTERNAL +GstAllocator * +gst_vaapi_dmabuf_allocator_new (GstVaapiDisplay * display, + const GstVideoInfo * alloc_info, guint surface_alloc_flags, + GstPadDirection direction); + +G_GNUC_INTERNAL +const GstVideoInfo * +gst_allocator_get_vaapi_video_info (GstAllocator * allocator, + guint * out_flags_ptr); + +G_GNUC_INTERNAL +gboolean +gst_allocator_set_vaapi_video_info (GstAllocator * allocator, + const GstVideoInfo * alloc_info, guint surface_alloc_flags); + +G_GNUC_INTERNAL +void +gst_allocator_set_vaapi_negotiated_video_info (GstAllocator * allocator, + const GstVideoInfo * negotiated_vinfo); + +G_GNUC_INTERNAL +GstVideoInfo * +gst_allocator_get_vaapi_negotiated_video_info (GstAllocator * allocator); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_is_dmabuf_allocator (GstAllocator * allocator); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_dmabuf_can_map (GstVaapiDisplay * display, GstAllocator * allocator); + +G_END_DECLS + +#endif /* GST_VAAPI_VIDEO_MEMORY_H */ diff --git a/gst/vaapi/gstvaapivideometa.c b/gst/vaapi/gstvaapivideometa.c new file mode 100644 index 0000000000..53a48dd90f --- /dev/null +++ b/gst/vaapi/gstvaapivideometa.c @@ -0,0 +1,764 @@ +/* + * gstvaapivideometa.c - Gst VA video meta + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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:gstvaapivideometa + * @short_description: VA video meta for GStreamer + * + * Describes a #GstMeta for VA-base video buffers. + */ + +#include "gstcompat.h" +#include +#include +#include "gstvaapivideometa.h" +#include "gstvaapivideomemory.h" + +#define GST_VAAPI_VIDEO_META(obj) \ + ((GstVaapiVideoMeta *) (obj)) +#define GST_VAAPI_IS_VIDEO_META(obj) \ + (GST_VAAPI_VIDEO_META (obj) != NULL) + +struct _GstVaapiVideoMeta +{ + GstBuffer *buffer; + gint ref_count; + GstVaapiDisplay *display; + GstVaapiVideoPool *image_pool; + GstVaapiImage *image; + GstVaapiSurfaceProxy *proxy; + GFunc converter; + guint render_flags; + GstVaapiRectangle render_rect; + guint has_render_rect:1; +}; + +static gboolean +ensure_surface_proxy (GstVaapiVideoMeta * meta) +{ + if (!meta->proxy) + return FALSE; + + if (meta->buffer) { + GstMemory *const mem = gst_buffer_peek_memory (meta->buffer, 0); + + if (GST_VAAPI_IS_VIDEO_MEMORY (mem)) + return gst_vaapi_video_memory_sync (GST_VAAPI_VIDEO_MEMORY_CAST (mem)); + } + return TRUE; +} + +static inline void +set_display (GstVaapiVideoMeta * meta, GstVaapiDisplay * display) +{ + gst_vaapi_display_replace (&meta->display, display); +} + +static inline void +set_image (GstVaapiVideoMeta * meta, GstVaapiImage * image) +{ + meta->image = + (GstVaapiImage *) gst_mini_object_ref (GST_MINI_OBJECT_CAST (image)); + set_display (meta, gst_vaapi_image_get_display (image)); +} + +static gboolean +set_image_from_pool (GstVaapiVideoMeta * meta, GstVaapiVideoPool * pool) +{ + GstVaapiImage *image; + + image = gst_vaapi_video_pool_get_object (pool); + if (!image) + return FALSE; + + set_image (meta, image); + meta->image_pool = gst_vaapi_video_pool_ref (pool); + return TRUE; +} + +static gboolean +set_surface_proxy (GstVaapiVideoMeta * meta, GstVaapiSurfaceProxy * proxy) +{ + GstVaapiSurface *surface; + + surface = GST_VAAPI_SURFACE_PROXY_SURFACE (proxy); + if (!surface) + return FALSE; + + meta->proxy = gst_vaapi_surface_proxy_ref (proxy); + set_display (meta, gst_vaapi_surface_get_display (surface)); + return TRUE; +} + +static gboolean +set_surface_proxy_from_pool (GstVaapiVideoMeta * meta, GstVaapiVideoPool * pool) +{ + GstVaapiSurfaceProxy *proxy; + gboolean success; + + proxy = gst_vaapi_surface_proxy_new_from_pool (GST_VAAPI_SURFACE_POOL (pool)); + if (!proxy) + return FALSE; + + success = set_surface_proxy (meta, proxy); + gst_vaapi_surface_proxy_unref (proxy); + return success; +} + +static void +gst_vaapi_video_meta_destroy_image (GstVaapiVideoMeta * meta) +{ + if (meta->image) { + if (meta->image_pool) + gst_vaapi_video_pool_put_object (meta->image_pool, meta->image); + gst_vaapi_image_unref (meta->image); + meta->image = NULL; + } + gst_vaapi_video_pool_replace (&meta->image_pool, NULL); +} + +static inline void +gst_vaapi_video_meta_destroy_proxy (GstVaapiVideoMeta * meta) +{ + gst_vaapi_surface_proxy_replace (&meta->proxy, NULL); +} + +static void +gst_vaapi_video_meta_finalize (GstVaapiVideoMeta * meta) +{ + gst_vaapi_video_meta_destroy_image (meta); + gst_vaapi_video_meta_destroy_proxy (meta); + gst_vaapi_display_replace (&meta->display, NULL); +} + +static void +gst_vaapi_video_meta_init (GstVaapiVideoMeta * meta) +{ + meta->buffer = NULL; + meta->ref_count = 1; + meta->display = NULL; + meta->image_pool = NULL; + meta->image = NULL; + meta->proxy = NULL; + meta->converter = NULL; + meta->render_flags = 0; + meta->has_render_rect = FALSE; +} + +static inline GstVaapiVideoMeta * +_gst_vaapi_video_meta_create (void) +{ + return g_slice_new (GstVaapiVideoMeta); +} + +static inline void +_gst_vaapi_video_meta_destroy (GstVaapiVideoMeta * meta) +{ + g_slice_free1 (sizeof (*meta), meta); +} + +static inline GstVaapiVideoMeta * +_gst_vaapi_video_meta_new (void) +{ + GstVaapiVideoMeta *meta; + + meta = _gst_vaapi_video_meta_create (); + if (!meta) + return NULL; + gst_vaapi_video_meta_init (meta); + return meta; +} + +static inline void +_gst_vaapi_video_meta_free (GstVaapiVideoMeta * meta) +{ + g_atomic_int_inc (&meta->ref_count); + + gst_vaapi_video_meta_finalize (meta); + + if (G_LIKELY (g_atomic_int_dec_and_test (&meta->ref_count))) + _gst_vaapi_video_meta_destroy (meta); +} + +/** + * gst_vaapi_video_meta_copy: + * @meta: a #GstVaapiVideoMeta + * + * Creates a copy of #GstVaapiVideoMeta object @meta. The original + * @meta object shall not contain any VA objects created from a + * #GstVaapiVideoPool. + * + * Return value: the newly allocated #GstVaapiVideoMeta, or %NULL on error + */ +GstVaapiVideoMeta * +gst_vaapi_video_meta_copy (GstVaapiVideoMeta * meta) +{ + GstVaapiVideoMeta *copy; + + g_return_val_if_fail (GST_VAAPI_IS_VIDEO_META (meta), NULL); + + if (meta->image_pool) + return NULL; + + copy = _gst_vaapi_video_meta_create (); + if (!copy) + return NULL; + + copy->buffer = NULL; + copy->ref_count = 1; + copy->display = gst_object_ref (meta->display); + copy->image_pool = NULL; + copy->image = meta->image ? (GstVaapiImage *) + gst_mini_object_ref (GST_MINI_OBJECT_CAST (meta->image)) : NULL; + copy->proxy = meta->proxy ? gst_vaapi_surface_proxy_copy (meta->proxy) : NULL; + copy->converter = meta->converter; + copy->render_flags = meta->render_flags; + + copy->has_render_rect = meta->has_render_rect; + if (copy->has_render_rect) + copy->render_rect = meta->render_rect; + return copy; +} + +/** + * gst_vaapi_video_meta_new: + * @display: a #GstVaapiDisplay + * + * Creates an empty #GstVaapiVideoMeta. The caller is responsible for completing + * the initialization of the meta with the gst_vaapi_video_meta_set_*() + * functions. + * + * This function shall only be called from within gstreamer-vaapi + * plugin elements. + * + * Return value: the newly allocated #GstVaapiVideoMeta, or %NULL or error + */ +GstVaapiVideoMeta * +gst_vaapi_video_meta_new (GstVaapiDisplay * display) +{ + GstVaapiVideoMeta *meta; + + g_return_val_if_fail (display != NULL, NULL); + + meta = _gst_vaapi_video_meta_new (); + if (G_UNLIKELY (!meta)) + return NULL; + + set_display (meta, display); + return meta; +} + +/** + * gst_vaapi_video_meta_new_from_pool: + * @pool: a #GstVaapiVideoPool + * + * Creates a #GstVaapiVideoMeta with a video object allocated from a @pool. + * Only #GstVaapiSurfacePool and #GstVaapiImagePool pools are supported. + * + * The meta object is destroyed through the last call to + * gst_vaapi_video_meta_unref() and the video objects are pushed back + * to their respective pools. + * + * Return value: the newly allocated #GstVaapiVideoMeta, or %NULL on error + */ +GstVaapiVideoMeta * +gst_vaapi_video_meta_new_from_pool (GstVaapiVideoPool * pool) +{ + GstVaapiVideoMeta *meta; + GstVaapiVideoPoolObjectType object_type; + + g_return_val_if_fail (pool != NULL, NULL); + + meta = _gst_vaapi_video_meta_new (); + if (G_UNLIKELY (!meta)) + return NULL; + + object_type = gst_vaapi_video_pool_get_object_type (pool); + switch (object_type) { + case GST_VAAPI_VIDEO_POOL_OBJECT_TYPE_IMAGE: + if (!set_image_from_pool (meta, pool)) + goto error; + break; + case GST_VAAPI_VIDEO_POOL_OBJECT_TYPE_SURFACE: + if (!set_surface_proxy_from_pool (meta, pool)) + goto error; + break; + default: + GST_ERROR ("unsupported video buffer pool of type %d", object_type); + goto error; + } + set_display (meta, gst_vaapi_video_pool_get_display (pool)); + return meta; + + /* ERRORS */ +error: + { + gst_vaapi_video_meta_unref (meta); + return NULL; + } +} + +/** + * gst_vaapi_video_meta_new_with_image: + * @image: a #GstVaapiImage + * + * Creates a #GstVaapiVideoMeta with the specified @image. The resulting + * meta holds an additional reference to the @image. + * + * This function shall only be called from within gstreamer-vaapi + * plugin elements. + * + * Return value: the newly allocated #GstVaapiVideoMeta, or %NULL on error + */ +GstVaapiVideoMeta * +gst_vaapi_video_meta_new_with_image (GstVaapiImage * image) +{ + GstVaapiVideoMeta *meta; + + g_return_val_if_fail (image != NULL, NULL); + + meta = _gst_vaapi_video_meta_new (); + if (G_UNLIKELY (!meta)) + return NULL; + + gst_vaapi_video_meta_set_image (meta, image); + return meta; +} + +/** + * gst_vaapi_video_meta_new_with_surface_proxy: + * @proxy: a #GstVaapiSurfaceProxy + * + * Creates a #GstVaapiVideoMeta with the specified surface @proxy. The + * resulting meta holds an additional reference to the @proxy. + * + * This function shall only be called from within gstreamer-vaapi + * plugin elements. + * + * Return value: the newly allocated #GstVaapiVideoMeta, or %NULL on error + */ +GstVaapiVideoMeta * +gst_vaapi_video_meta_new_with_surface_proxy (GstVaapiSurfaceProxy * proxy) +{ + GstVaapiVideoMeta *meta; + + g_return_val_if_fail (proxy != NULL, NULL); + + meta = _gst_vaapi_video_meta_new (); + if (G_UNLIKELY (!meta)) + return NULL; + + gst_vaapi_video_meta_set_surface_proxy (meta, proxy); + return meta; +} + +/** + * gst_vaapi_video_meta_ref: + * @meta: a #GstVaapiVideoMeta + * + * Atomically increases the reference count of the given @meta by one. + * + * Returns: The same @meta argument + */ +GstVaapiVideoMeta * +gst_vaapi_video_meta_ref (GstVaapiVideoMeta * meta) +{ + g_return_val_if_fail (meta != NULL, NULL); + + g_atomic_int_inc (&meta->ref_count); + return meta; +} + +/** + * gst_vaapi_video_meta_unref: + * @meta: a #GstVaapiVideoMeta + * + * Atomically decreases the reference count of the @meta by one. If + * the reference count reaches zero, the object will be free'd. + */ +void +gst_vaapi_video_meta_unref (GstVaapiVideoMeta * meta) +{ + g_return_if_fail (meta != NULL); + g_return_if_fail (meta->ref_count > 0); + + if (g_atomic_int_dec_and_test (&meta->ref_count)) + _gst_vaapi_video_meta_free (meta); +} + +/** + * gst_vaapi_video_meta_replace: + * @old_meta_ptr: a pointer to a #GstVaapiVideoMeta + * @new_meta: a #GstVaapiVideoMeta + * + * @new_meta. This means that @old_meta_ptr shall reference a valid + * Atomically replaces the meta object held in @old_meta_ptr with + * object. However, @new_meta can be NULL. + */ +void +gst_vaapi_video_meta_replace (GstVaapiVideoMeta ** old_meta_ptr, + GstVaapiVideoMeta * new_meta) +{ + GstVaapiVideoMeta *old_meta; + + g_return_if_fail (old_meta_ptr != NULL); + + old_meta = g_atomic_pointer_get ((gpointer *) old_meta_ptr); + + if (old_meta == new_meta) + return; + + if (new_meta) + gst_vaapi_video_meta_ref (new_meta); + + while (!g_atomic_pointer_compare_and_exchange (old_meta_ptr, old_meta, + new_meta)) + old_meta = g_atomic_pointer_get ((gpointer *) old_meta_ptr); + + if (old_meta) + gst_vaapi_video_meta_unref (old_meta); +} + +/** + * gst_vaapi_video_meta_get_display: + * @meta: a #GstVaapiVideoMeta + * + * Retrieves the #GstVaapiDisplay the @meta is bound to. The @meta + * owns the returned #GstVaapiDisplay object so the caller is + * responsible for calling g_object_ref() when needed. + * + * Return value: the #GstVaapiDisplay the @meta is bound to + */ +GstVaapiDisplay * +gst_vaapi_video_meta_get_display (GstVaapiVideoMeta * meta) +{ + g_return_val_if_fail (GST_VAAPI_IS_VIDEO_META (meta), NULL); + + return meta->display; +} + +/** + * gst_vaapi_video_meta_get_image: + * @meta: a #GstVaapiVideoMeta + * + * Retrieves the #GstVaapiImage bound to the @meta. The @meta owns + * the #GstVaapiImage so the caller is responsible for calling + * gst_mini_object_ref() when needed. + * + * Return value: the #GstVaapiImage bound to the @meta, or %NULL if + * there is none + */ +GstVaapiImage * +gst_vaapi_video_meta_get_image (GstVaapiVideoMeta * meta) +{ + g_return_val_if_fail (GST_VAAPI_IS_VIDEO_META (meta), NULL); + + return meta->image; +} + +/** + * gst_vaapi_video_meta_set_image: + * @meta: a #GstVaapiVideoMeta + * @image: a #GstVaapiImage + * + * Binds @image to the @meta. If the @meta contains another image + * previously allocated from a pool, it's pushed back to its parent + * pool and the pool is also released. + */ +void +gst_vaapi_video_meta_set_image (GstVaapiVideoMeta * meta, GstVaapiImage * image) +{ + g_return_if_fail (GST_VAAPI_IS_VIDEO_META (meta)); + + gst_vaapi_video_meta_destroy_image (meta); + + if (image) + set_image (meta, image); +} + +/** + * gst_vaapi_video_meta_set_image_from_pool + * @meta: a #GstVaapiVideoMeta + * @pool: a #GstVaapiVideoPool + * + * Binds a newly allocated video object from the @pool. The @pool + * shall be of type #GstVaapiImagePool. Previously allocated objects + * are released and returned to their parent pools, if any. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_video_meta_set_image_from_pool (GstVaapiVideoMeta * meta, + GstVaapiVideoPool * pool) +{ + g_return_val_if_fail (GST_VAAPI_IS_VIDEO_META (meta), FALSE); + g_return_val_if_fail (pool != NULL, FALSE); + g_return_val_if_fail (gst_vaapi_video_pool_get_object_type (pool) == + GST_VAAPI_VIDEO_POOL_OBJECT_TYPE_IMAGE, FALSE); + + gst_vaapi_video_meta_destroy_image (meta); + + return set_image_from_pool (meta, pool); +} + +/** + * gst_vaapi_video_meta_get_surface: + * @meta: a #GstVaapiVideoMeta + * + * Retrieves the #GstVaapiSurface bound to the @meta. The @meta + * owns the #GstVaapiSurface so the caller is responsible for calling + * gst_mini_object_ref() when needed. + * + * Return value: the #GstVaapiSurface bound to the @meta, or %NULL if + * there is none + */ +GstVaapiSurface * +gst_vaapi_video_meta_get_surface (GstVaapiVideoMeta * meta) +{ + g_return_val_if_fail (GST_VAAPI_IS_VIDEO_META (meta), NULL); + + return ensure_surface_proxy (meta) ? + GST_VAAPI_SURFACE_PROXY_SURFACE (meta->proxy) : NULL; +} + +/** + * gst_vaapi_video_meta_get_surface_proxy: + * @meta: a #GstVaapiVideoMeta + * + * Retrieves the #GstVaapiSurfaceProxy bound to the @meta. The @meta + * owns the #GstVaapiSurfaceProxy so the caller is responsible for calling + * gst_surface_proxy_ref() when needed. + * + * Return value: the #GstVaapiSurfaceProxy bound to the @meta, or + * %NULL if there is none + */ +GstVaapiSurfaceProxy * +gst_vaapi_video_meta_get_surface_proxy (GstVaapiVideoMeta * meta) +{ + g_return_val_if_fail (GST_VAAPI_IS_VIDEO_META (meta), NULL); + + return ensure_surface_proxy (meta) ? meta->proxy : NULL; +} + +/** + * gst_vaapi_video_meta_set_surface_proxy: + * @meta: a #GstVaapiVideoMeta + * @proxy: a #GstVaapiSurfaceProxy + * + * Binds surface @proxy to the @meta. If the @meta contains another + * surface previously allocated from a pool, it's pushed back to its + * parent pool and the pool is also released. + */ +void +gst_vaapi_video_meta_set_surface_proxy (GstVaapiVideoMeta * meta, + GstVaapiSurfaceProxy * proxy) +{ + const GstVaapiRectangle *crop_rect; + + g_return_if_fail (GST_VAAPI_IS_VIDEO_META (meta)); + + gst_vaapi_video_meta_destroy_proxy (meta); + + if (proxy) { + if (!set_surface_proxy (meta, proxy)) + return; + + crop_rect = gst_vaapi_surface_proxy_get_crop_rect (proxy); + if (crop_rect) + gst_vaapi_video_meta_set_render_rect (meta, crop_rect); + } +} + +/** + * gst_vaapi_video_meta_get_render_flags: + * @meta: a #GstVaapiVideoMeta + * + * Retrieves the surface render flags bound to the @meta. + * + * Return value: a combination for #GstVaapiSurfaceRenderFlags + */ +guint +gst_vaapi_video_meta_get_render_flags (GstVaapiVideoMeta * meta) +{ + g_return_val_if_fail (GST_VAAPI_IS_VIDEO_META (meta), 0); + g_return_val_if_fail (meta->proxy != NULL, 0); + + return meta->render_flags; +} + +/** + * gst_vaapi_video_meta_set_render_flags: + * @meta: a #GstVaapiVideoMeta + * @flags: a set of surface render flags + * + * Sets #GstVaapiSurfaceRenderFlags to the @meta. + */ +void +gst_vaapi_video_meta_set_render_flags (GstVaapiVideoMeta * meta, guint flags) +{ + g_return_if_fail (GST_VAAPI_IS_VIDEO_META (meta)); + g_return_if_fail (meta->proxy != NULL); + + meta->render_flags = flags; +} + +/** + * gst_vaapi_video_meta_get_render_rect: + * @meta: a #GstVaapiVideoMeta + * + * Retrieves the render rectangle bound to the @meta + * + * Return value: render rectangle associated with the video meta. + */ +const GstVaapiRectangle * +gst_vaapi_video_meta_get_render_rect (GstVaapiVideoMeta * meta) +{ + g_return_val_if_fail (GST_VAAPI_IS_VIDEO_META (meta), NULL); + + if (!meta->has_render_rect) + return NULL; + return &meta->render_rect; +} + +/** + * gst_vaapi_video_meta_set_render_rect: + * @meta: a #GstVaapiVideoMeta + * @rect: a #GstVaapiRectangle + * + * Sets the render rectangle @rect to the @meta. + */ +void +gst_vaapi_video_meta_set_render_rect (GstVaapiVideoMeta * meta, + const GstVaapiRectangle * rect) +{ + g_return_if_fail (GST_VAAPI_IS_VIDEO_META (meta)); + + meta->has_render_rect = rect != NULL; + if (meta->has_render_rect) + meta->render_rect = *rect; +} + +#define GST_VAAPI_VIDEO_META_HOLDER(meta) \ + ((GstVaapiVideoMetaHolder *) (meta)) + +typedef struct _GstVaapiVideoMetaHolder GstVaapiVideoMetaHolder; +struct _GstVaapiVideoMetaHolder +{ + GstMeta base; + GstVaapiVideoMeta *meta; +}; + +static gboolean +gst_vaapi_video_meta_holder_init (GstVaapiVideoMetaHolder * meta, + gpointer params, GstBuffer * buffer) +{ + meta->meta = NULL; + return TRUE; +} + +static void +gst_vaapi_video_meta_holder_free (GstVaapiVideoMetaHolder * meta, + GstBuffer * buffer) +{ + if (meta->meta) + gst_vaapi_video_meta_unref (meta->meta); +} + +static gboolean +gst_vaapi_video_meta_holder_transform (GstBuffer * dst_buffer, GstMeta * meta, + GstBuffer * src_buffer, GQuark type, gpointer data) +{ + GstVaapiVideoMetaHolder *const src_meta = GST_VAAPI_VIDEO_META_HOLDER (meta); + + if (GST_META_TRANSFORM_IS_COPY (type)) { + GstVaapiVideoMeta *const dst_meta = + gst_vaapi_video_meta_copy (src_meta->meta); + gst_buffer_set_vaapi_video_meta (dst_buffer, dst_meta); + gst_vaapi_video_meta_unref (dst_meta); + return TRUE; + } + return FALSE; +} + +GType +gst_vaapi_video_meta_api_get_type (void) +{ + static gsize g_type; + static const gchar *tags[] = { "memory", NULL }; + + if (g_once_init_enter (&g_type)) { + GType type = gst_meta_api_type_register ("GstVaapiVideoMetaAPI", tags); + g_once_init_leave (&g_type, type); + } + return g_type; +} + +#define GST_VAAPI_VIDEO_META_INFO gst_vaapi_video_meta_info_get () +static const GstMetaInfo * +gst_vaapi_video_meta_info_get (void) +{ + static gsize g_meta_info; + + if (g_once_init_enter (&g_meta_info)) { + gsize meta_info = + GPOINTER_TO_SIZE (gst_meta_register (GST_VAAPI_VIDEO_META_API_TYPE, + "GstVaapiVideoMeta", sizeof (GstVaapiVideoMetaHolder), + (GstMetaInitFunction) gst_vaapi_video_meta_holder_init, + (GstMetaFreeFunction) gst_vaapi_video_meta_holder_free, + (GstMetaTransformFunction) gst_vaapi_video_meta_holder_transform)); + g_once_init_leave (&g_meta_info, meta_info); + } + return GSIZE_TO_POINTER (g_meta_info); +} + +GstVaapiVideoMeta * +gst_buffer_get_vaapi_video_meta (GstBuffer * buffer) +{ + GstVaapiVideoMeta *meta; + GstMeta *m; + + g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL); + + m = gst_buffer_get_meta (buffer, GST_VAAPI_VIDEO_META_API_TYPE); + if (!m) + return NULL; + + meta = GST_VAAPI_VIDEO_META_HOLDER (m)->meta; + if (meta) + meta->buffer = buffer; + return meta; +} + +void +gst_buffer_set_vaapi_video_meta (GstBuffer * buffer, GstVaapiVideoMeta * meta) +{ + GstMeta *m; + + g_return_if_fail (GST_IS_BUFFER (buffer)); + g_return_if_fail (GST_VAAPI_IS_VIDEO_META (meta)); + + m = gst_buffer_add_meta (buffer, GST_VAAPI_VIDEO_META_INFO, NULL); + if (m) + GST_VAAPI_VIDEO_META_HOLDER (m)->meta = gst_vaapi_video_meta_ref (meta); +} diff --git a/gst/vaapi/gstvaapivideometa.h b/gst/vaapi/gstvaapivideometa.h new file mode 100644 index 0000000000..c88abfd454 --- /dev/null +++ b/gst/vaapi/gstvaapivideometa.h @@ -0,0 +1,136 @@ +/* + * gstvaapivideometa.h - Gstreamer/VA video meta + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_VIDEO_META_H +#define GST_VAAPI_VIDEO_META_H + +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +typedef struct _GstVaapiVideoMeta GstVaapiVideoMeta; + +#define GST_VAAPI_VIDEO_META_API_TYPE \ + gst_vaapi_video_meta_api_get_type () + +G_GNUC_INTERNAL +GType +gst_vaapi_video_meta_api_get_type (void) G_GNUC_CONST; + +G_GNUC_INTERNAL +GstVaapiVideoMeta * +gst_vaapi_video_meta_copy (GstVaapiVideoMeta * meta); + +G_GNUC_INTERNAL +GstVaapiVideoMeta * +gst_vaapi_video_meta_new (GstVaapiDisplay * display); + +G_GNUC_INTERNAL +GstVaapiVideoMeta * +gst_vaapi_video_meta_new_from_pool (GstVaapiVideoPool * pool); + +G_GNUC_INTERNAL +GstVaapiVideoMeta * +gst_vaapi_video_meta_new_with_image (GstVaapiImage * image); + +G_GNUC_INTERNAL +GstVaapiVideoMeta * +gst_vaapi_video_meta_new_with_surface_proxy (GstVaapiSurfaceProxy * proxy); + +G_GNUC_INTERNAL +GstVaapiVideoMeta * +gst_vaapi_video_meta_ref (GstVaapiVideoMeta * meta); + +G_GNUC_INTERNAL +void +gst_vaapi_video_meta_unref (GstVaapiVideoMeta * meta); + +G_GNUC_INTERNAL +void +gst_vaapi_video_meta_replace (GstVaapiVideoMeta ** old_meta_ptr, + GstVaapiVideoMeta * new_meta); + +G_GNUC_INTERNAL +GstVaapiDisplay * +gst_vaapi_video_meta_get_display (GstVaapiVideoMeta * meta); + +G_GNUC_INTERNAL +GstVaapiImage * +gst_vaapi_video_meta_get_image (GstVaapiVideoMeta * meta); + +G_GNUC_INTERNAL +void +gst_vaapi_video_meta_set_image (GstVaapiVideoMeta * meta, + GstVaapiImage * image); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_video_meta_set_image_from_pool (GstVaapiVideoMeta * meta, + GstVaapiVideoPool * pool); + +G_GNUC_INTERNAL +GstVaapiSurface * +gst_vaapi_video_meta_get_surface (GstVaapiVideoMeta * meta); + +G_GNUC_INTERNAL +GstVaapiSurfaceProxy * +gst_vaapi_video_meta_get_surface_proxy (GstVaapiVideoMeta * meta); + +G_GNUC_INTERNAL +void +gst_vaapi_video_meta_set_surface_proxy (GstVaapiVideoMeta * meta, + GstVaapiSurfaceProxy * proxy); + +G_GNUC_INTERNAL +guint +gst_vaapi_video_meta_get_render_flags (GstVaapiVideoMeta * meta); + +G_GNUC_INTERNAL +void +gst_vaapi_video_meta_set_render_flags (GstVaapiVideoMeta * meta, guint flags); + +G_GNUC_INTERNAL +const GstVaapiRectangle * +gst_vaapi_video_meta_get_render_rect (GstVaapiVideoMeta * meta); + +G_GNUC_INTERNAL +void +gst_vaapi_video_meta_set_render_rect (GstVaapiVideoMeta * meta, + const GstVaapiRectangle * rect); + +G_GNUC_INTERNAL +GstVaapiVideoMeta * +gst_buffer_get_vaapi_video_meta (GstBuffer * buffer); + +G_GNUC_INTERNAL +void +gst_buffer_set_vaapi_video_meta (GstBuffer * buffer, GstVaapiVideoMeta * meta); + +G_END_DECLS + +#endif /* GST_VAAPI_VIDEO_META_H */ diff --git a/gst/vaapi/gstvaapivideometa_texture.c b/gst/vaapi/gstvaapivideometa_texture.c new file mode 100644 index 0000000000..b4cf65bf7a --- /dev/null +++ b/gst/vaapi/gstvaapivideometa_texture.c @@ -0,0 +1,259 @@ +/* + * gstvaapivideometa_texture.c - GStreamer/VA video meta (GLTextureUpload) + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * Copyright (C) 2013 Igalia + * Author: Víctor Manuel Jáquez Leal + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gstcompat.h" +#include "gst/vaapi/ogl_compat.h" +#include "gstvaapivideometa.h" +#include "gstvaapivideometa_texture.h" +#include "gstvaapipluginutil.h" + +#if USE_GLX +#include +#endif + +#define DEFAULT_FORMAT GST_VIDEO_FORMAT_RGBA + +#if (USE_GLX || USE_EGL) +struct _GstVaapiVideoMetaTexture +{ + GstVaapiTexture *texture; + GstVideoGLTextureType texture_type[4]; + guint gl_format; + guint width; + guint height; +}; + +static guint +get_texture_orientation_flags (GstVideoGLTextureOrientation orientation) +{ + guint flags; + + switch (orientation) { + case GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_FLIP: + flags = GST_VAAPI_TEXTURE_ORIENTATION_FLAG_Y_INVERTED; + break; + case GST_VIDEO_GL_TEXTURE_ORIENTATION_X_FLIP_Y_NORMAL: + flags = GST_VAAPI_TEXTURE_ORIENTATION_FLAG_X_INVERTED; + break; + case GST_VIDEO_GL_TEXTURE_ORIENTATION_X_FLIP_Y_FLIP: + flags = GST_VAAPI_TEXTURE_ORIENTATION_FLAG_X_INVERTED | + GST_VAAPI_TEXTURE_ORIENTATION_FLAG_Y_INVERTED; + break; + default: + flags = 0; + break; + } + return flags; +} + +static gboolean +meta_texture_ensure_format (GstVaapiVideoMetaTexture * meta, + GstVideoFormat format) +{ + memset (meta->texture_type, 0, sizeof (meta->texture_type)); + + switch (format) { + case GST_VIDEO_FORMAT_RGBA: + meta->gl_format = GL_RGBA; + meta->texture_type[0] = GST_VIDEO_GL_TEXTURE_TYPE_RGBA; + break; + case GST_VIDEO_FORMAT_BGRA: + meta->gl_format = GL_BGRA_EXT; + /* FIXME: add GST_VIDEO_GL_TEXTURE_TYPE_BGRA extension */ + meta->texture_type[0] = GST_VIDEO_GL_TEXTURE_TYPE_RGBA; + break; + default: + goto error_unsupported_format; + } + return TRUE; + + /* ERRORS */ +error_unsupported_format: + GST_ERROR ("unsupported texture format %s", + gst_video_format_to_string (format)); + return FALSE; +} + +static gboolean +meta_texture_ensure_info_from_buffer (GstVaapiVideoMetaTexture * meta, + GstBuffer * buffer) +{ + GstVideoMeta *vmeta; + GstVideoFormat format; + + if (!buffer || !(vmeta = gst_buffer_get_video_meta (buffer))) { + format = DEFAULT_FORMAT; + meta->width = 0; + meta->height = 0; + } else { + const GstVideoFormatInfo *const fmt_info = + gst_video_format_get_info (vmeta->format); + format = (fmt_info && GST_VIDEO_FORMAT_INFO_IS_RGB (fmt_info)) ? + vmeta->format : DEFAULT_FORMAT; + meta->width = vmeta->width; + meta->height = vmeta->height; + } + return meta_texture_ensure_format (meta, format); +} + +static void +meta_texture_free (GstVaapiVideoMetaTexture * meta) +{ + if (G_UNLIKELY (!meta)) + return; + + gst_mini_object_replace ((GstMiniObject **) & meta->texture, NULL); + g_slice_free (GstVaapiVideoMetaTexture, meta); +} + +static GstVaapiVideoMetaTexture * +meta_texture_new (void) +{ + GstVaapiVideoMetaTexture *meta; + + meta = g_slice_new (GstVaapiVideoMetaTexture); + if (!meta) + return NULL; + + meta->texture = NULL; + if (!meta_texture_ensure_info_from_buffer (meta, NULL)) + goto error; + return meta; + + /* ERRORS */ +error: + { + meta_texture_free (meta); + return NULL; + } +} + +static GstVaapiVideoMetaTexture * +meta_texture_copy (GstVaapiVideoMetaTexture * meta) +{ + GstVaapiVideoMetaTexture *copy; + + copy = meta_texture_new (); + if (!copy) + return NULL; + + memcpy (copy->texture_type, meta->texture_type, sizeof (meta->texture_type)); + copy->gl_format = meta->gl_format; + copy->width = meta->width; + copy->height = meta->height; + + gst_mini_object_replace ((GstMiniObject **) & copy->texture, + (GstMiniObject *) meta->texture); + return copy; +} + +static gboolean +gst_vaapi_texture_upload (GstVideoGLTextureUploadMeta * meta, + guint texture_id[4]) +{ + GstVaapiVideoMeta *const vmeta = + gst_buffer_get_vaapi_video_meta (meta->buffer); + GstVaapiVideoMetaTexture *const meta_texture = meta->user_data; + GstVaapiSurfaceProxy *const proxy = + gst_vaapi_video_meta_get_surface_proxy (vmeta); + GstVaapiSurface *const surface = gst_vaapi_surface_proxy_get_surface (proxy); + GstVaapiDisplay *const dpy = gst_vaapi_surface_get_display (surface); + GstVaapiTexture *texture = NULL; + + if (!gst_vaapi_display_has_opengl (dpy)) + return FALSE; + + if (meta_texture->texture + /* Check whether VA display changed */ + && GST_VAAPI_TEXTURE_DISPLAY (meta_texture->texture) == dpy + /* Check whether texture id changed */ + && (gst_vaapi_texture_get_id (meta_texture->texture) == texture_id[0])) { + texture = meta_texture->texture; + } + + if (!texture) { + /* FIXME: should we assume target? */ + texture = + gst_vaapi_texture_new_wrapped (dpy, texture_id[0], + GL_TEXTURE_2D, meta_texture->gl_format, meta_texture->width, + meta_texture->height); + } + + if (meta_texture->texture != texture) { + gst_mini_object_replace ((GstMiniObject **) & meta_texture->texture, + (GstMiniObject *) texture); + } + + if (!texture) + return FALSE; + + gst_vaapi_texture_set_orientation_flags (meta_texture->texture, + get_texture_orientation_flags (meta->texture_orientation)); + + return gst_vaapi_texture_put_surface (meta_texture->texture, surface, + gst_vaapi_surface_proxy_get_crop_rect (proxy), + gst_vaapi_video_meta_get_render_flags (vmeta)); +} + +GstMeta * +gst_buffer_add_texture_upload_meta (GstBuffer * buffer) +{ + GstVaapiVideoMetaTexture *meta_texture; + + if (!buffer) + return FALSE; + + meta_texture = meta_texture_new (); + if (!meta_texture) + return FALSE; + + if (!meta_texture_ensure_info_from_buffer (meta_texture, buffer)) + goto error; + + return (GstMeta *) gst_buffer_add_video_gl_texture_upload_meta (buffer, + GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_NORMAL, 1, + meta_texture->texture_type, gst_vaapi_texture_upload, meta_texture, + (GBoxedCopyFunc) meta_texture_copy, (GBoxedFreeFunc) meta_texture_free); + + /* ERRORS */ +error: + { + meta_texture_free (meta_texture); + return NULL; + } +} + +gboolean +gst_buffer_ensure_texture_upload_meta (GstBuffer * buffer) +{ + GstVideoGLTextureUploadMeta *const meta = + gst_buffer_get_video_gl_texture_upload_meta (buffer); + + return meta ? + meta_texture_ensure_info_from_buffer (meta->user_data, buffer) : + (gst_buffer_add_texture_upload_meta (buffer) != NULL); +} +#endif diff --git a/gst/vaapi/gstvaapivideometa_texture.h b/gst/vaapi/gstvaapivideometa_texture.h new file mode 100644 index 0000000000..bf369ba897 --- /dev/null +++ b/gst/vaapi/gstvaapivideometa_texture.h @@ -0,0 +1,46 @@ +/* + * gstvaapivideometa_texture.h - GStreamer/VA video meta (GLTextureUpload) + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * Copyright (C) 2013 Igalia + * Author: Víctor Manuel Jáquez Leal + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_VIDEO_META_TEXTURE_H +#define GST_VAAPI_VIDEO_META_TEXTURE_H + +#include + +G_BEGIN_DECLS + +typedef struct _GstVaapiVideoMetaTexture GstVaapiVideoMetaTexture; + +G_GNUC_INTERNAL +GstMeta * +gst_buffer_add_texture_upload_meta (GstBuffer * buffer); + +G_GNUC_INTERNAL +gboolean +gst_buffer_ensure_texture_upload_meta (GstBuffer * buffer); + +G_END_DECLS + +#endif /* GST_VAAPI_VIDEO_META_TEXTURE_H */ diff --git a/gst/vaapi/meson.build b/gst/vaapi/meson.build new file mode 100644 index 0000000000..4265759227 --- /dev/null +++ b/gst/vaapi/meson.build @@ -0,0 +1,47 @@ +vaapi_sources = [ + 'gstvaapi.c', + 'gstvaapidecode.c', + 'gstvaapidecodedoc.c', + 'gstvaapioverlay.c', + 'gstvaapipluginbase.c', + 'gstvaapipluginutil.c', + 'gstvaapipostproc.c', + 'gstvaapipostprocutil.c', + 'gstvaapisink.c', + 'gstvaapivideobuffer.c', + 'gstvaapivideocontext.c', + 'gstvaapivideometa.c', + 'gstvaapidecodebin.c', + 'gstvaapivideobufferpool.c', + 'gstvaapivideomemory.c', + 'gstvaapivideometa_texture.c', + 'gstvaapidecode_props.c', +] + +if USE_ENCODERS + vaapi_sources += [ + 'gstvaapiencode.c', + 'gstvaapiencode_h264.c', + 'gstvaapiencode_h265.c', + 'gstvaapiencode_jpeg.c', + 'gstvaapiencode_mpeg2.c', + 'gstvaapiencode_vp8.c', + ] +endif + +if USE_VP9_ENCODER + vaapi_sources += 'gstvaapiencode_vp9.c' +endif + +gstvaapi = library('gstvaapi', + vaapi_sources, + c_args : gstreamer_vaapi_args + ['-DGST_USE_UNSTABLE_API'], + include_directories : [configinc, libsinc], + dependencies : [gstbase_dep, gstvideo_dep, gstallocators_dep, gstpbutils_dep, + libva_dep, gstlibvaapi_dep, gstgl_dep, gstglproto_dep, gstglx11_dep, gstglegl_dep, + gstglwayland_dep, libm], + install : true, + install_dir : plugins_install_dir, +) + +plugins = [gstvaapi] diff --git a/gstreamer-vaapi.doap b/gstreamer-vaapi.doap new file mode 100644 index 0000000000..8f8deb02ba --- /dev/null +++ b/gstreamer-vaapi.doap @@ -0,0 +1,341 @@ + + + GStreamer VA-API + gstreamer-vaapi + a set of VA-API based elements for GStreamer + + GStreamer VA-API is a collection of VA-API based plugin with video + processing elements for GStreamer. + + + + + C + + + + + + + + + + + + 1.19.2 + master + + 2021-09-23 + + + + + + + 1.19.1 + master + + 2021-06-01 + + + + + + + 1.18.0 + master + + 2020-09-08 + + + + + + + 1.17.90 + master + + 2020-08-20 + + + + + + + 1.17.2 + master + + 2020-07-03 + + + + + + + 1.17.1 + master + + 2020-06-19 + + + + + + + 1.16.0 + master + + 2019-04-19 + + + + + + + 1.15.90 + master + + 2019-04-11 + + + + + + + 1.15.2 + master + + 2019-02-26 + + + + + + + 1.15.1 + master + + 2019-01-17 + + + + + + + 1.14.0 + master + + 2018-03-19 + + + + + + + 1.13.91 + master + + 2018-03-13 + + + + + + + 1.13.90 + master + + 2018-03-03 + + + + + + + 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 + master + + 2017-05-04 + + + + + + + 1.11.91 + master + + 2017-04-27 + + + + + + + 1.11.90 + master + + 2017-04-07 + + + + + + + 1.11.2 + master + + 2017-02-24 + + + + + + + 1.11.1 + master + + 2017-01-12 + + + + + + + 1.10.0 + master + 2016-11-01 + + + + + + + 1.9.90 + master + 2016-09-30 + + + + + + + 1.9.2 + master + 2016-09-01 + + + + + + + 1.9.1 + master + 2016-06-06 + + + + + + + 1.8.0 + master + 2016-03-24 + + + + + + + 1.7.91 + master + 2016-03-15 + + + + + + + 1.7.90 + master + 2016-03-01 + + + + + + + 1.6.0 + master + 2016-02-14 + + + + + + + Sreerenj Balachandran + + + + + Victor Jaquez + + > + + 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 new file mode 100644 index 0000000000..d069f4089c --- /dev/null +++ b/meson.build @@ -0,0 +1,218 @@ +project('gstreamer-vaapi', 'c', + version : '1.19.2', + meson_version : '>= 0.54', + default_options : [ 'warning_level=1', + 'buildtype=debugoptimized' ]) + +gst_version = meson.project_version() +version_arr = gst_version.split('.') +gst_version_major = version_arr[0].to_int() +gst_version_minor = version_arr[1].to_int() +gst_version_micro = version_arr[2].to_int() + if version_arr.length() == 4 + gst_version_nano = version_arr[3].to_int() +else + gst_version_nano = 0 +endif + +libva_req = ['>= 0.39.0', '!= 0.99.0'] +glib_req = '>= 2.44.0' +libwayland_req = '>= 1.11.0' +libdrm_req = '>= 2.4.98' +gst_req = '>= @0@.@1@.0'.format(gst_version_major, gst_version_minor) + +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') +endif + +# Disable strict aliasing +if cc.has_argument('-fno-strict-aliasing') + add_project_arguments('-fno-strict-aliasing', language: 'c') +endif + +# Mandatory GST deps +libm = cc.find_library('m', required : false) +gst_dep = dependency('gstreamer-1.0', version : gst_req, + fallback : ['gstreamer', 'gst_dep']) +gstbase_dep = dependency('gstreamer-base-1.0', version : gst_req, + fallback : ['gstreamer', 'gst_base_dep']) +gstpbutils_dep = dependency('gstreamer-pbutils-1.0', version : gst_req, + fallback : ['gst-plugins-base', 'pbutils_dep']) +gstallocators_dep = dependency('gstreamer-allocators-1.0', version : gst_req, + fallback : ['gst-plugins-base', 'allocators_dep']) +gstvideo_dep = dependency('gstreamer-video-1.0', version : gst_req, + fallback : ['gst-plugins-base', 'video_dep']) +gstcodecparsers_dep = dependency('gstreamer-codecparsers-1.0', version : gst_req, + fallback : ['gst-plugins-bad', 'gstcodecparsers_dep']) +gstgl_dep = dependency('gstreamer-gl-1.0', version : gst_req, + fallback : ['gst-plugins-base', 'gstgl_dep'], required: false) +gstglproto_dep = dependency('', required : false) +gstglx11_dep = dependency('', required : false) +gstglwayland_dep = dependency('', required : false) +gstglegl_dep = dependency('', required : false) + +# 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 + +# Other deps +gmodule_dep = dependency('gmodule-2.0', required: false) +libva_dep = dependency('libva', version: libva_req) + +libva_drm_dep = dependency('libva-drm', version: libva_req, required: false) +libva_wayland_dep = dependency('libva-wayland', version: libva_req, required: false) +libva_x11_dep = dependency('libva-x11', version: libva_req, required: false) +libdrm_dep = dependency('libdrm', version: libdrm_req, required: false, + fallback: ['libdrm', 'ext_libdrm']) +libudev_dep = dependency('libudev', required: false) +egl_dep = dependency('egl', required: false) +gl_dep = dependency('gl', required: false) +glesv2_dep = dependency('glesv2', required: false) +gstcheck_dep = dependency('gstreamer-check-1.0', version : gst_req, + required : get_option('tests'), + fallback : ['gstreamer', 'gst_check_dep']) +libdl_dep = cc.find_library('dl', required: false) +wayland_client_dep = dependency('wayland-client', version: libwayland_req, required: false) +wayland_protocols_dep = dependency('wayland-protocols', version: '>= 1.15', required: false) +wayland_scanner_bin = find_program('wayland-scanner', required: false) +x11_dep = dependency('x11', required: false) +xrandr_dep = dependency('xrandr', required: false) + +# some of the examples can use GTK+-3 +gtk_dep = dependency('gtk+-3.0', version : '>= 3.10', required : get_option('examples')) + +GLES_VERSION_MASK = gl_dep.found() ? 1 : 0 +if glesv2_dep.found() + if (cc.has_header('GLES2/gl2.h', dependencies: glesv2_dep) and + cc.has_header('GLES2/gl2ext.h', dependencies: glesv2_dep)) + GLES_VERSION_MASK += 4 + endif + if (cc.has_header('GLES3/gl3.h', dependencies: glesv2_dep) and + cc.has_header('GLES3/gl3ext.h', dependencies: glesv2_dep) and + cc.has_header('GLES2/gl2ext.h', dependencies: glesv2_dep)) + GLES_VERSION_MASK += 8 + endif +endif + +USE_ENCODERS = get_option('with_encoders') != 'no' +USE_VP9_ENCODER = USE_ENCODERS and cc.has_header('va/va_enc_vp9.h', dependencies: libva_dep, prefix: '#include ') +USE_AV1_DECODER = cc.has_header('va/va_dec_av1.h', dependencies: libva_dep, prefix: '#include ') + +USE_DRM = libva_drm_dep.found() and libdrm_dep.found() and libudev_dep.found() and get_option('with_drm') != 'no' +USE_EGL = gmodule_dep.found() and egl_dep.found() and GLES_VERSION_MASK != 0 and get_option('with_egl') != 'no' +USE_WAYLAND = libva_wayland_dep.found() and wayland_client_dep.found() and wayland_protocols_dep.found() and wayland_scanner_bin.found() and get_option('with_wayland') != 'no' +USE_X11 = libva_x11_dep.found() and x11_dep.found() and get_option('with_x11') != 'no' +USE_GLX = gl_dep.found() and libdl_dep.found() and get_option('with_glx') != 'no' and USE_X11 + +if not (USE_DRM or USE_X11 or USE_WAYLAND) + error('No renderer API found (it is requried either DRM, X11 and/or WAYLAND)') +endif + +if gstgl_dep.found() + gstglproto_dep = dependency('gstreamer-gl-prototypes-1.0', version : gst_req, + fallback : ['gst-plugins-base', 'gstglproto_dep'], required: true) + # Behind specific checks because meson fails at optional dependencies with a + # fallback to the same subproject. On the first failure, meson will never + # check the system again even if the fallback never existed. + # Last checked with meson 0.54.3 + if USE_X11 + gstglx11_dep = dependency('gstreamer-gl-x11-1.0', version : gst_req, + fallback : ['gst-plugins-base', 'gstglx11_dep'], required: true) + endif + if USE_WAYLAND + gstglwayland_dep = dependency('gstreamer-gl-wayland-1.0', version : gst_req, + fallback : ['gst-plugins-base', 'gstglwayland_dep'], required: true) + endif + if USE_EGL + gstglegl_dep = dependency('gstreamer-gl-egl-1.0', version : gst_req, + fallback : ['gst-plugins-base', 'gstglegl_dep'], required: true) + endif +endif + +driverdir = libva_dep.get_pkgconfig_variable('driverdir') +if driverdir == '' + driverdir = join_paths(get_option('prefix'), get_option('libdir'), 'dri') +endif + +cdata = configuration_data() +cdata.set_quoted('GST_API_VERSION_S', '@0@.@1@'.format(gst_version_major, gst_version_minor)) +cdata.set_quoted('PACKAGE', 'gstreamer-vaapi') +cdata.set_quoted('VERSION', '@0@'.format(gst_version)) +cdata.set_quoted('PACKAGE_VERSION', '@0@'.format(gst_version)) +cdata.set_quoted('PACKAGE_NAME', 'GStreamer VA-API Plug-ins') +cdata.set_quoted('PACKAGE_STRING', 'GStreamer VA-API Plug-ins @0@'.format(gst_version)) +cdata.set_quoted('PACKAGE_BUGREPORT', get_option('package-origin')) +cdata.set_quoted('VA_DRIVERS_PATH', '@0@'.format(driverdir)) +cdata.set10('USE_DRM', USE_DRM) +cdata.set10('USE_EGL', USE_EGL) +cdata.set10('USE_ENCODERS', USE_ENCODERS) +cdata.set10('USE_GLX', USE_GLX) +cdata.set10('USE_VP9_ENCODER', USE_VP9_ENCODER) +cdata.set10('USE_AV1_DECODER', USE_AV1_DECODER) +cdata.set10('USE_WAYLAND', USE_WAYLAND) +cdata.set10('USE_X11', USE_X11) +cdata.set10('HAVE_XKBLIB', cc.has_header('X11/XKBlib.h', dependencies: x11_dep)) +cdata.set10('HAVE_XRANDR', xrandr_dep.found()) +cdata.set10('USE_GST_GL_HELPERS', gstgl_dep.found()) +cdata.set('USE_GLES_VERSION_MASK', GLES_VERSION_MASK) + +api_version = '1.0' +soversion = 0 +# maintaining compatibility with the previous libtool versioning +# current = minor * 100 + 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')) + +gstreamer_vaapi_args = ['-DHAVE_CONFIG_H'] +configinc = include_directories('.') +libsinc = include_directories('gst-libs') + +subdir('gst-libs') +subdir('gst') +subdir('tests') +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('gstreamer-vaapi.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 + +if gmodule_dep.version().version_compare('< 2.67.4') + cdata.set('g_memdup2(ptr,sz)', '(G_LIKELY(((guint64)(sz)) < G_MAXUINT)) ? g_memdup(ptr,sz) : (g_abort(),NULL)') +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")') diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000000..9c2b5e1644 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,15 @@ +option('with_encoders', type : 'combo', choices : ['yes', 'no', 'auto'], value : 'auto') +option('with_drm', type : 'combo', choices : ['yes', 'no', 'auto'], value : 'auto') +option('with_x11', type : 'combo', choices : ['yes', 'no', 'auto'], value : 'auto') +option('with_glx', type : 'combo', choices : ['yes', 'no', 'auto'], value : 'auto') +option('with_wayland', type : 'combo', choices : ['yes', 'no', 'auto'], value : 'auto') +option('with_egl', type : 'combo', choices : ['yes', 'no', 'auto'], value : 'auto') + +# Common feature options +option('examples', type : 'feature', value : 'auto', yield : true) +option('tests', type : 'feature', value : 'auto', yield : true) +option('doc', type : 'feature', value : 'auto', yield: true, + description: 'Enable documentation.') +option('package-origin', type : 'string', + value : 'https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi/issues', + yield : true, description : 'package origin URL to use in plugins') 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)) diff --git a/tests/check/elements/vaapioverlay.c b/tests/check/elements/vaapioverlay.c new file mode 100644 index 0000000000..b218759b1f --- /dev/null +++ b/tests/check/elements/vaapioverlay.c @@ -0,0 +1,218 @@ +/* + * vaapioverlay.c - GStreamer unit test for the vaapioverlay element + * + * Copyright (C) 2019 Intel Corporation + * Author: U. Artie Eoff + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +static GMainLoop *main_loop; +static void +message_received (GstBus * bus, GstMessage * message, GstPipeline * bin) +{ + GST_INFO ("bus message from \"%" GST_PTR_FORMAT "\": %" GST_PTR_FORMAT, + GST_MESSAGE_SRC (message), message); + + switch (message->type) { + case GST_MESSAGE_EOS: + g_main_loop_quit (main_loop); + break; + case GST_MESSAGE_WARNING:{ + GError *gerror; + gchar *debug; + + gst_message_parse_warning (message, &gerror, &debug); + gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug); + g_error_free (gerror); + g_free (debug); + break; + } + case GST_MESSAGE_ERROR:{ + GError *gerror; + gchar *debug; + + gst_message_parse_error (message, &gerror, &debug); + gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug); + g_error_free (gerror); + g_free (debug); + g_main_loop_quit (main_loop); + break; + } + default: + break; + } +} + +static GstBuffer *handoff_buffer = NULL; +static void +on_handoff (GstElement * element, GstBuffer * buffer, GstPad * pad, + gpointer data) +{ + gst_buffer_replace (&handoff_buffer, buffer); +} + +#define TEST_PATTERN_RED 4 +#define TEST_PATTERN_GREEN 5 + +GST_START_TEST (test_overlay_position) +{ + GstElement *bin, *src1, *filter1, *src2, *filter2, *overlay, *sink; + GstBus *bus; + GstPad *pad, *srcpad, *sinkpad; + GstCaps *caps; + GstVideoFrame frame; + GstVideoInfo vinfo; + + /* Check if vaapioverlay is available, since it is only available + * for iHD vaapi driver */ + overlay = gst_element_factory_make ("vaapioverlay", "overlay"); + if (!overlay) + return; + + /* build pipeline */ + bin = gst_pipeline_new ("pipeline"); + bus = gst_element_get_bus (bin); + gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH); + + src1 = gst_element_factory_make ("videotestsrc", "src1"); + g_object_set (src1, "num-buffers", 1, NULL); + g_object_set (src1, "pattern", TEST_PATTERN_GREEN, NULL); + filter1 = gst_element_factory_make ("capsfilter", "filter1"); + caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, "NV12", + "width", G_TYPE_INT, 320, "height", G_TYPE_INT, 240, NULL); + g_object_set (filter1, "caps", caps, NULL); + gst_caps_unref (caps); + + src2 = gst_element_factory_make ("videotestsrc", "src2"); + g_object_set (src2, "num-buffers", 1, NULL); + g_object_set (src2, "pattern", TEST_PATTERN_RED, NULL); + filter2 = gst_element_factory_make ("capsfilter", "filter2"); + caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, "NV12", + "width", G_TYPE_INT, 20, "height", G_TYPE_INT, 20, NULL); + g_object_set (filter2, "caps", caps, NULL); + gst_caps_unref (caps); + + sink = gst_element_factory_make ("vaapisink", "sink"); + g_object_set (sink, "display", 4, "signal-handoffs", TRUE, NULL); + g_signal_connect (sink, "handoff", G_CALLBACK (on_handoff), NULL); + + gst_bin_add_many (GST_BIN (bin), src1, filter1, src2, filter2, overlay, + sink, NULL); + gst_element_link (src1, filter1); + gst_element_link (src2, filter2); + gst_element_link (overlay, sink); + + srcpad = gst_element_get_static_pad (filter1, "src"); + sinkpad = gst_element_request_pad_simple (overlay, "sink_0"); + g_object_set (sinkpad, "xpos", 0, "ypos", 0, "alpha", 1.0, NULL); + gst_pad_link (srcpad, sinkpad); + gst_object_unref (sinkpad); + gst_object_unref (srcpad); + + srcpad = gst_element_get_static_pad (filter2, "src"); + sinkpad = gst_element_request_pad_simple (overlay, "sink_1"); + g_object_set (sinkpad, "xpos", 10, "ypos", 10, "alpha", 1.0, NULL); + gst_pad_link (srcpad, sinkpad); + gst_object_unref (sinkpad); + gst_object_unref (srcpad); + + /* setup and run the main loop */ + main_loop = g_main_loop_new (NULL, FALSE); + g_signal_connect (bus, "message::error", (GCallback) message_received, bin); + g_signal_connect (bus, "message::warning", (GCallback) message_received, bin); + g_signal_connect (bus, "message::eos", (GCallback) message_received, bin); + gst_element_set_state (bin, GST_STATE_PAUSED); + gst_element_get_state (bin, NULL, NULL, GST_CLOCK_TIME_NONE); + gst_element_set_state (bin, GST_STATE_PLAYING); + g_main_loop_run (main_loop); + + /* validate output buffer */ + fail_unless (handoff_buffer != NULL); + pad = gst_element_get_static_pad (sink, "sink"); + caps = gst_pad_get_current_caps (pad); + gst_video_info_from_caps (&vinfo, caps); + gst_caps_unref (caps); + gst_object_unref (pad); + + gst_video_frame_map (&frame, &vinfo, handoff_buffer, GST_MAP_READ); + { + guint i, j, n_planes, plane; + n_planes = GST_VIDEO_FRAME_N_PLANES (&frame); + + for (plane = 0; plane < n_planes; plane++) { + gpointer pd = GST_VIDEO_FRAME_PLANE_DATA (&frame, plane); + gint w = GST_VIDEO_FRAME_COMP_WIDTH (&frame, plane) + * GST_VIDEO_FRAME_COMP_PSTRIDE (&frame, plane); + gint h = GST_VIDEO_FRAME_COMP_HEIGHT (&frame, plane); + gint ps = GST_VIDEO_FRAME_PLANE_STRIDE (&frame, plane); + + for (j = 0; j < h; ++j) { + for (i = 0; i < w; ++i) { + guint8 actual = GST_READ_UINT8 (pd + i); + guint8 expect = 0xff; + if (plane == 0) { + if (i >= 10 && i < 30 && j >= 10 && j < 30) + expect = 0x51; + else + expect = 0x91; + } else { + if (i >= 10 && i < 30 && j >= 5 && j < 15) + expect = (i % 2) ? 0xf0 : 0x5a; + else + expect = (i % 2) ? 0x22 : 0x36; + } + fail_unless (actual == expect, + "Expected 0x%02x but got 0x%02x at (%u,%u,%u)", expect, actual, + plane, i, j); + } + pd += ps; + } + } + } + + /* cleanup */ + gst_buffer_replace (&handoff_buffer, NULL); + gst_element_set_state (bin, GST_STATE_NULL); + g_main_loop_unref (main_loop); + gst_bus_remove_signal_watch (bus); + gst_object_unref (bus); + gst_object_unref (bin); +} + +GST_END_TEST; + +static Suite * +vaapioverlay_suite (void) +{ + Suite *s = suite_create ("vaapioverlay"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_overlay_position); + + return s; +} + +GST_CHECK_MAIN (vaapioverlay); diff --git a/tests/check/elements/vaapipostproc.c b/tests/check/elements/vaapipostproc.c new file mode 100644 index 0000000000..e46304ffff --- /dev/null +++ b/tests/check/elements/vaapipostproc.c @@ -0,0 +1,393 @@ +/* + * vaapipostproc.c - GStreamer unit test for the vaapipostproc element + * + * Copyright (C) 2019 Intel Corporation + * Author: U. Artie Eoff + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +typedef struct +{ + GstElement *pipeline; + GstElement *source; + GstElement *filter; + GstElement *vpp; + GstElement *sink; +} VppTestContext; + +typedef struct +{ + gdouble x; + gdouble y; +} VppTestCoordinate; + +typedef struct +{ + VppTestCoordinate send; + VppTestCoordinate expect; +} VppTestCoordinateParams; + +GST_START_TEST (test_make) +{ + GstElement *vaapipostproc; + + vaapipostproc = gst_element_factory_make ("vaapipostproc", "vaapipostproc"); + fail_unless (vaapipostproc != NULL, "Failed to create vaapipostproc element"); + + gst_object_unref (vaapipostproc); +} + +GST_END_TEST; + +static void +vpp_test_init_context (VppTestContext * ctx) +{ + GST_INFO ("initing context"); + + ctx->pipeline = gst_pipeline_new ("pipeline"); + fail_unless (ctx->pipeline != NULL); + + ctx->source = gst_element_factory_make ("videotestsrc", "src"); + fail_unless (ctx->source != NULL, "Failed to create videotestsrc element"); + + ctx->filter = gst_element_factory_make ("capsfilter", "filter"); + fail_unless (ctx->filter != NULL, "Failed to create caps filter element"); + + ctx->vpp = gst_element_factory_make ("vaapipostproc", "vpp"); + fail_unless (ctx->vpp != NULL, "Failed to create vaapipostproc element"); + + ctx->sink = gst_element_factory_make ("fakesink", "sink"); + fail_unless (ctx->sink != NULL, "Failed to create fakesink element"); + + gst_bin_add_many (GST_BIN (ctx->pipeline), ctx->source, ctx->filter, ctx->vpp, + ctx->sink, NULL); + gst_element_link_many (ctx->source, ctx->filter, ctx->vpp, ctx->sink, NULL); +} + +static void +vpp_test_deinit_context (VppTestContext * ctx) +{ + GST_INFO ("deiniting context"); + + gst_element_set_state (ctx->pipeline, GST_STATE_NULL); + gst_object_unref (ctx->pipeline); + memset (ctx, 0x00, sizeof (VppTestContext)); +} + +static void +vpp_test_set_crop (VppTestContext * ctx, gint l, gint r, gint t, gint b) +{ + GST_LOG ("%d %d %d %0d", l, r, t, b); + g_object_set (ctx->vpp, "crop-left", l, "crop-right", r, + "crop-top", t, "crop-bottom", b, NULL); +} + +static void +vpp_test_set_orientation (VppTestContext * ctx, GstVideoOrientationMethod m) +{ + GST_LOG ("%u", m); + g_object_set (ctx->vpp, "video-direction", m, NULL); +} + +static void +vpp_test_set_dimensions (VppTestContext * ctx, gint w, gint h) +{ + GstCaps *caps = gst_caps_new_simple ("video/x-raw", + "width", G_TYPE_INT, w, "height", G_TYPE_INT, h, NULL); + GST_LOG ("%dx%d", w, h); + g_object_set (ctx->filter, "caps", caps, NULL); + gst_caps_unref (caps); +} + +static GstPadProbeReturn +cb_mouse_event (GstPad * pad, GstPadProbeInfo * info, gpointer data) +{ + VppTestCoordinate *coord = data; + gdouble x = 0, y = 0; + GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info); + + if (GST_EVENT_TYPE (event) == GST_EVENT_NAVIGATION) { + switch (gst_navigation_event_get_type (event)) { + case GST_NAVIGATION_EVENT_MOUSE_MOVE: + if (gst_navigation_event_parse_mouse_move_event (event, &x, &y)) { + coord->x = x; + coord->y = y; + } + break; + case GST_NAVIGATION_EVENT_MOUSE_BUTTON_PRESS: + case GST_NAVIGATION_EVENT_MOUSE_BUTTON_RELEASE: + if (gst_navigation_event_parse_mouse_button_event (event, NULL, &x, &y)) { + coord->x = x; + coord->y = y; + } + break; + default: + break; + } + } + + return GST_PAD_PROBE_OK; +} + +static void +vpp_test_mouse_events (VppTestContext * ctx, + const VppTestCoordinateParams * const params, const size_t nparams) +{ + GstStructure *structure; + GstEvent *event; + VppTestCoordinate probed = { 0, }; + guint i, j; + + /* probe mouse events propagated up from vaapipostproc */ + GstPad *pad = gst_element_get_static_pad (ctx->source, "src"); + gulong id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_UPSTREAM, + (GstPadProbeCallback) cb_mouse_event, &probed, NULL); + + const char *mouse_events[] = { + "mouse-move", + "mouse-button-press", + "mouse-button-release", + }; + + fail_unless (gst_element_set_state (ctx->pipeline, GST_STATE_PAUSED) + != GST_STATE_CHANGE_FAILURE); + fail_unless (gst_element_get_state (ctx->pipeline, NULL, NULL, -1) + == GST_STATE_CHANGE_SUCCESS); + + for (i = 0; i < nparams; ++i) { + for (j = 0; j < G_N_ELEMENTS (mouse_events); ++j) { + probed.x = probed.y = -1; + + GST_LOG ("sending %s event %fx%f", mouse_events[j], params[i].send.x, + params[i].send.y); + structure = gst_structure_new ("application/x-gst-navigation", "event", + G_TYPE_STRING, mouse_events[j], + "pointer_x", G_TYPE_DOUBLE, params[i].send.x, + "pointer_y", G_TYPE_DOUBLE, params[i].send.y, NULL); + event = gst_event_new_navigation (structure); + gst_element_send_event (ctx->pipeline, event); + + GST_LOG ("probed %s event %fx%f", mouse_events[j], probed.x, probed.y); + GST_LOG ("expect %s event %fx%f", mouse_events[j], params[i].expect.x, + params[i].expect.y); + + fail_unless (params[i].expect.x == probed.x); + fail_unless (params[i].expect.y == probed.y); + } + } + + gst_element_set_state (ctx->pipeline, GST_STATE_NULL); + + gst_pad_remove_probe (pad, id); + gst_object_unref (pad); +} + +static void +vpp_test_crop_mouse_events (VppTestContext * ctx, gint w, gint h, gint l, + gint r, gint t, gint b) +{ + const gdouble xmin = 0.0; + const gdouble ymin = 0.0; + const gdouble xmax = w - (l + r) - 1; + const gdouble ymax = h - (t + b) - 1; + const gdouble xctr = xmax / 2; + const gdouble yctr = ymax / 2; + const gdouble xrand = g_random_double_range (xmin, xmax); + const gdouble yrand = g_random_double_range (ymin, ymax); + + const gdouble e_xmin = xmin + l; + const gdouble e_ymin = ymin + t; + const gdouble e_xmax = xmax + l; + const gdouble e_ymax = ymax + t; + const gdouble e_xctr = xctr + l; + const gdouble e_yctr = yctr + t; + const gdouble e_xrand = xrand + l; + const gdouble e_yrand = yrand + t; + + const VppTestCoordinateParams params[] = { + {{xmin, ymin}, {e_xmin, e_ymin}}, /* left-top */ + {{xmin, yctr}, {e_xmin, e_yctr}}, /* left-center */ + {{xmin, ymax}, {e_xmin, e_ymax}}, /* left-bottom */ + + {{xmax, ymin}, {e_xmax, e_ymin}}, /* right-top */ + {{xmax, yctr}, {e_xmax, e_yctr}}, /* right-center */ + {{xmax, ymax}, {e_xmax, e_ymax}}, /* right-bottom */ + + {{xctr, ymin}, {e_xctr, e_ymin}}, /* center-top */ + {{xctr, yctr}, {e_xctr, e_yctr}}, /* center */ + {{xctr, ymax}, {e_xctr, e_ymax}}, /* center-bottom */ + + {{xrand, yrand}, {e_xrand, e_yrand}}, /* random */ + }; + + vpp_test_set_dimensions (ctx, w, h); + vpp_test_set_crop (ctx, l, r, t, b); + vpp_test_mouse_events (ctx, params, G_N_ELEMENTS (params)); +} + +GST_START_TEST (test_crop_mouse_events) +{ + VppTestContext ctx; + + vpp_test_init_context (&ctx); + + vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 0, 0, 0); + vpp_test_crop_mouse_events (&ctx, 160, 160, 1, 0, 0, 0); + vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 1, 0, 0); + vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 0, 1, 0); + vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 0, 0, 1); + vpp_test_crop_mouse_events (&ctx, 160, 160, 63, 0, 0, 0); + vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 63, 0, 0); + vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 0, 63, 0); + vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 0, 0, 63); + vpp_test_crop_mouse_events (&ctx, 160, 160, 63, 0, 0, 1); + vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 63, 1, 0); + vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 1, 63, 0); + vpp_test_crop_mouse_events (&ctx, 160, 160, 1, 0, 0, 63); + vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 0, 0, 0); + vpp_test_crop_mouse_events (&ctx, 160, 160, 32, 0, 0, 128); + vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 32, 128, 0); + vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 128, 32, 0); + vpp_test_crop_mouse_events (&ctx, 160, 160, 128, 0, 0, 32); + vpp_test_crop_mouse_events (&ctx, 160, 160, 1, 1, 1, 1); + vpp_test_crop_mouse_events (&ctx, 160, 160, 63, 63, 63, 63); + vpp_test_crop_mouse_events (&ctx, 160, 160, 64, 64, 64, 64); + + vpp_test_deinit_context (&ctx); +} + +GST_END_TEST; + +static void +vpp_test_orientation_mouse_events (VppTestContext * ctx, gint w, gint h) +{ + size_t i; + const gdouble xmin = 0.0; + const gdouble ymin = 0.0; + const gdouble xmax = w - 1; + const gdouble ymax = h - 1; + const VppTestCoordinateParams params[8][4] = { + /* (0) identity */ + { + {{xmin, ymin}, {xmin, ymin}}, + {{xmax, ymin}, {xmax, ymin}}, + {{xmin, ymax}, {xmin, ymax}}, + {{xmax, ymax}, {xmax, ymax}}, + }, + /* (1) 90 Rotation */ + { + {{ymin, xmin}, {xmin, ymax}}, + {{ymax, xmin}, {xmin, ymin}}, + {{ymin, xmax}, {xmax, ymax}}, + {{ymax, xmax}, {xmax, ymin}}, + }, + /* (2) 180 Rotation */ + { + {{xmin, ymin}, {xmax, ymax}}, + {{xmax, ymin}, {xmin, ymax}}, + {{xmin, ymax}, {xmax, ymin}}, + {{xmax, ymax}, {xmin, ymin}}, + }, + /* (3) 270 Rotation */ + { + {{ymin, xmin}, {xmax, ymin}}, + {{ymax, xmin}, {xmax, ymax}}, + {{ymin, xmax}, {xmin, ymin}}, + {{ymax, xmax}, {xmin, ymax}}, + }, + /* (4) Horizontal Flip */ + { + {{xmin, ymin}, {xmax, ymin}}, + {{xmax, ymin}, {xmin, ymin}}, + {{xmin, ymax}, {xmax, ymax}}, + {{xmax, ymax}, {xmin, ymax}}, + }, + /* (5) Vertical Flip */ + { + {{xmin, ymin}, {xmin, ymax}}, + {{xmax, ymin}, {xmax, ymax}}, + {{xmin, ymax}, {xmin, ymin}}, + {{xmax, ymax}, {xmax, ymin}}, + }, + /* (6) Vertical Flip + 90 Rotation */ + { + {{ymin, xmin}, {xmin, ymin}}, + {{ymax, xmin}, {xmin, ymax}}, + {{ymin, xmax}, {xmax, ymin}}, + {{ymax, xmax}, {xmax, ymax}}, + }, + /* (7) Horizontal Flip + 90 Rotation */ + { + {{ymin, xmin}, {xmax, ymax}}, + {{ymax, xmin}, {xmax, ymin}}, + {{ymin, xmax}, {xmin, ymax}}, + {{ymax, xmax}, {xmin, ymin}}, + }, + }; + + vpp_test_set_dimensions (ctx, w, h); + + for (i = 0; i < 8; ++i) { + vpp_test_set_orientation (ctx, i); + vpp_test_mouse_events (ctx, params[i], 4); + } +} + +GST_START_TEST (test_orientation_mouse_events) +{ + VppTestContext ctx; + + vpp_test_init_context (&ctx); + + vpp_test_orientation_mouse_events (&ctx, 160, 320); + vpp_test_orientation_mouse_events (&ctx, 161, 320); + vpp_test_orientation_mouse_events (&ctx, 160, 321); + vpp_test_orientation_mouse_events (&ctx, 161, 321); + + vpp_test_orientation_mouse_events (&ctx, 320, 160); + vpp_test_orientation_mouse_events (&ctx, 320, 161); + vpp_test_orientation_mouse_events (&ctx, 321, 160); + vpp_test_orientation_mouse_events (&ctx, 321, 161); + + vpp_test_deinit_context (&ctx); +} + +GST_END_TEST; + +static Suite * +vaapipostproc_suite (void) +{ + Suite *s = suite_create ("vaapipostproc"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_make); + tcase_add_test (tc_chain, test_crop_mouse_events); + tcase_add_test (tc_chain, test_orientation_mouse_events); + + return s; +} + +GST_CHECK_MAIN (vaapipostproc); diff --git a/tests/check/meson.build b/tests/check/meson.build new file mode 100644 index 0000000000..cedd86287f --- /dev/null +++ b/tests/check/meson.build @@ -0,0 +1,39 @@ +tests = [ + [ 'elements/vaapipostproc' ], +] + +if USE_DRM + tests += [ + [ 'elements/vaapioverlay' ] +] +endif + +test_deps = [gst_dep, gstbase_dep, gstvideo_dep, gstcheck_dep] +test_defines = [ + '-UG_DISABLE_ASSERT', + '-UG_DISABLE_CAST_CHECKS', + '-DGST_USE_UNSTABLE_API', +] + +pluginsdirs = [] +if gst_dep.type_name() == 'pkgconfig' + pluginsdirs = [gst_dep.get_pkgconfig_variable('pluginsdir')] +endif + +foreach t : tests + fname = '@0@.c'.format(t.get(0)) + test_name = t.get(0).underscorify() + extra_sources = [ ] + extra_deps = [ ] + env = environment() + env.set('CK_DEFAULT_TIMEOUT', '20') + env.set('GST_PLUGIN_SYSTEM_PATH_1_0', '') + env.set('GST_PLUGIN_PATH_1_0', [meson.build_root()] + pluginsdirs) + env.set('GST_REGISTRY', join_paths(meson.current_build_dir(), '@0@.registry'.format(test_name))) + exe = executable(test_name, fname, extra_sources, + include_directories : [configinc, libsinc], + c_args : ['-DHAVE_CONFIG_H=1' ] + test_defines, + dependencies : test_deps + extra_deps, + ) + test(test_name, exe, env: env, timeout: 3 * 60) +endforeach diff --git a/tests/examples/meson.build b/tests/examples/meson.build new file mode 100644 index 0000000000..e7b1dee58c --- /dev/null +++ b/tests/examples/meson.build @@ -0,0 +1,29 @@ +examples = [ + 'test-vaapisink', + 'test-vaapipostproc', + 'test-roi', +] + +foreach example : examples + executable(example, '@0@.c'.format(example), + c_args : gstreamer_vaapi_args, + include_directories: [configinc, libsinc], + dependencies : [gst_dep, gstvideo_dep], + install: false) +endforeach + +if USE_X11 and USE_WAYLAND +if gtk_dep.found() + executable('test-vaapicontext', 'test-vaapicontext.c', + c_args : gstreamer_vaapi_args, + include_directories: [configinc, libsinc], + dependencies : [ gst_dep, + gstvideo_dep, + libva_dep, + x11_dep, + gtk_dep, + libva_wayland_dep, + libva_x11_dep ], + install: false) +endif +endif diff --git a/tests/examples/test-roi.c b/tests/examples/test-roi.c new file mode 100644 index 0000000000..2ce614efa5 --- /dev/null +++ b/tests/examples/test-roi.c @@ -0,0 +1,261 @@ +/* + * test-roi.c - Testsuite for Region of Interest + * + * Copyright (C) 2017 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include + +typedef struct _CustomData +{ + GstElement *pipeline; + GMainLoop *loop; + gboolean roi_enabled; +} AppData; + +static void +send_eos_event (AppData * data) +{ + gst_element_send_event (data->pipeline, gst_event_new_eos ()); +} + +static void +dispatch_keystroke (AppData * app, const gchar * str) +{ + switch (g_ascii_tolower (str[0])) { + case 'r': + app->roi_enabled = !app->roi_enabled; + gst_println ("ROI %s", app->roi_enabled ? "enabled" : "disabled"); + break; + case 'q': + send_eos_event (app); + break; + default: + break; + } + + return; +} + +static void +cb_msg (GstBus * bus, GstMessage * msg, gpointer data) +{ + AppData *app = data; + GstNavigationMessageType mtype = gst_navigation_message_get_type (msg); + GstEvent *ev = NULL; + GstNavigationEventType type; + const gchar *key; + + if (mtype != GST_NAVIGATION_MESSAGE_EVENT) + return; + if (!gst_navigation_message_parse_event (msg, &ev)) + goto bail; + + type = gst_navigation_event_get_type (ev); + if (type != GST_NAVIGATION_EVENT_KEY_PRESS) + goto bail; + if (!gst_navigation_event_parse_key_event (ev, &key)) + goto bail; + + dispatch_keystroke (app, key); + +bail: + if (ev) + gst_event_unref (ev); +} + +static void +cb_msg_eos (GstBus * bus, GstMessage * msg, gpointer data) +{ + AppData *app = data; + g_main_loop_quit (app->loop); +} + + +static void +cb_msg_error (GstBus * bus, GstMessage * msg, gpointer data) +{ + AppData *app = data; + gchar *debug = NULL; + GError *err = NULL; + + gst_message_parse_error (msg, &err, &debug); + + g_print ("Error: %s\n", err->message); + g_error_free (err); + + if (debug) { + g_print ("Debug details: %s\n", debug); + g_free (debug); + } + + g_main_loop_quit (app->loop); +} + +static GstPadProbeReturn +cb_add_roi (GstPad * pad, GstPadProbeInfo * info, gpointer data) +{ + AppData *app = data; + GstVideoRegionOfInterestMeta *rmeta; + GstBuffer *buf = GST_PAD_PROBE_INFO_BUFFER (info); + GstStructure *s; + + if (!app->roi_enabled) + return GST_PAD_PROBE_OK; + + buf = gst_buffer_make_writable (buf); + if (!buf) + return GST_PAD_PROBE_OK; + + rmeta = + gst_buffer_add_video_region_of_interest_meta (buf, "test", 0, 0, 320, + 240); + if (!rmeta) + return GST_PAD_PROBE_OK; + + s = gst_structure_new ("roi/vaapi", "delta-qp", G_TYPE_INT, -10, NULL); + gst_video_region_of_interest_meta_add_param (rmeta, s); + + GST_PAD_PROBE_INFO_DATA (info) = buf; + return GST_PAD_PROBE_OK; +} + +/* Process keyboard input */ +static gboolean +handle_keyboard (GIOChannel * source, GIOCondition cond, gpointer data) +{ + AppData *app = data; + gchar *str = NULL; + + if (g_io_channel_read_line (source, &str, NULL, NULL, + NULL) != G_IO_STATUS_NORMAL) { + return TRUE; + } + + dispatch_keystroke (app, str); + + g_free (str); + return TRUE; +} + +/* + * This is an example pipeline to recognize difference between ROI and non-ROI. + * 1. Produce snow pattern with 320p + * 2. Encode and decode the raw data with 2 pipelines at same time. + * 2.1. Insert GstVideoRegionOfInterestMeta to the 2nd pipeline buffers to enable ROI. + * 3. Mix both streams in videomixer. + * 5. Output the result in one window. + * + * Note that the higher definition of original raw data, the easier we + * recognize. So you can replace videotestsrc with your + * high-definition camera or other src elements. + */ + +/* +.----------. .---. .--------. .---. .---. .---. .--------. .----------. .-----. +| videosrc |->|tee|->Q->|txtovrly|->|enc|->|dec|->|vpp|->|videobox|->|videomixer|->|vsink| +'----------' '---' '--------' '---' '---' '---' '--------' '----------' '-----' + ^ ^ + | | + | .--------. .---. .---. .---. .--------. | + '--->Q->|txtovrly|->|enc|->|dec|->|vpp|->|videobox|->' + ^ '--------' '---' '---' '---' '--------' + | + '-- Insert GstVideoRegionOfInterestMeta width roit/vaapi params on buffers +*/ + +int +main (int argc, char *argv[]) +{ + AppData data = { 0, }; + GstStateChangeReturn ret; + GstElement *el; + GstPad *pad; + GError *err = NULL; + GIOChannel *io_stdin; + GstBus *bus; + + data.roi_enabled = TRUE; + + /* Initialize GStreamer */ + gst_init (&argc, &argv); + + /* Print usage map */ + g_print ("USAGE: 'r' to enable/disable ROI && 'q' to quit\n"); + +#define SRC "videotestsrc pattern=snow ! " \ + "video/x-raw, format=NV12, width=320, framerate=5/1" +#define ENCDEC "vaapih265enc rate-control=cbr bitrate=2000 ! vaapih265dec ! " \ + "vaapipostproc ! video/x-raw, width=640" +#define TEXT "textoverlay font-desc=\"Arial Bold 48\" " + + data.pipeline = + gst_parse_launch + ("videomixer name=mix ! vaapipostproc ! vaapisink sync=false " + SRC " ! tee name=t ! queue ! " TEXT " text=\"non-ROI\" ! " ENCDEC + " ! videobox left=-640 ! mix. " + " t. ! queue name=roi ! " TEXT " text=\"ROI\" ! " ENCDEC + " ! videobox ! mix.", &err); + + if (err) { + g_printerr ("failed to parse pipeline: %s\n", err->message); + g_error_free (err); + return -1; + } + + bus = gst_pipeline_get_bus (GST_PIPELINE (data.pipeline)); + gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH); + gst_bus_enable_sync_message_emission (bus); + g_signal_connect (bus, "message::error", G_CALLBACK (cb_msg_error), &data); + g_signal_connect (bus, "message::eos", G_CALLBACK (cb_msg_eos), &data); + g_signal_connect (bus, "message::element", G_CALLBACK (cb_msg), &data); + gst_object_unref (bus); + + el = gst_bin_get_by_name (GST_BIN (data.pipeline), "roi"); + pad = gst_element_get_static_pad (el, "src"); + gst_object_unref (el); + gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, cb_add_roi, &data, NULL); + gst_object_unref (pad); + + /* Add a keyboard watch so we get notified of keystrokes */ + io_stdin = g_io_channel_unix_new (fileno (stdin)); + g_io_add_watch (io_stdin, G_IO_IN, handle_keyboard, &data); + + /* Start playing */ + ret = gst_element_set_state (data.pipeline, GST_STATE_PLAYING); + if (ret == GST_STATE_CHANGE_FAILURE) { + g_printerr ("Unable to set the pipeline to the playing state.\n"); + gst_object_unref (data.pipeline); + return -1; + } + + /* Create a GLib Main Loop and set it to run */ + data.loop = g_main_loop_new (NULL, FALSE); + g_main_loop_run (data.loop); + + /* Free resources */ + g_main_loop_unref (data.loop); + gst_element_set_state (data.pipeline, GST_STATE_NULL); + gst_object_unref (data.pipeline); + g_io_channel_unref (io_stdin); + + return 0; +} diff --git a/tests/examples/test-vaapicontext.c b/tests/examples/test-vaapicontext.c new file mode 100644 index 0000000000..98760dc585 --- /dev/null +++ b/tests/examples/test-vaapicontext.c @@ -0,0 +1,468 @@ +/* + * test-vaapicontext.c - Testsuite for VAAPI app context + * + * Copyright (C) 2017 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include +#include + +#include + +#include + +#ifdef GDK_WINDOWING_X11 +#include +#include +#include +#endif +#ifdef GDK_WINDOWING_WAYLAND +#include +#include +#endif + +static gboolean g_multisink; +static gchar *g_filepath; +static GstElement *g_vaapisink; + +static GOptionEntry g_options[] = { + {"multi", 'm', 0, G_OPTION_ARG_NONE, &g_multisink, "test multiple vaapisink", + NULL}, + {"file", 'f', 0, G_OPTION_ARG_STRING, &g_filepath, "file path to play", NULL}, + {NULL,} +}; + +typedef struct _CustomData +{ + GtkWidget *main_window; + VADisplay va_display; + GstElement *pipeline; + guintptr videoarea_handle[2]; + GstObject *gstvaapidisplay; + GtkWidget *video_widget[2]; + GstVideoOverlay *overlay[2]; +} AppData; + +static void +delete_event_cb (GtkWidget * widget, GdkEvent * event, gpointer data) +{ + AppData *app = data; + + gst_element_set_state (app->pipeline, GST_STATE_NULL); + gtk_main_quit (); +} + +static void +button_rotate_cb (GtkWidget * widget, GstElement * elem) +{ + static gint counter = 0; + const static gint tags[] = { 90, 180, 270, 0 }; + + g_object_set (elem, "rotation", tags[counter++ % G_N_ELEMENTS (tags)], NULL); +} + +static gpointer +get_native_display (AppData * app, gboolean * is_x11) +{ + GdkDisplay *gdk_display; + + gdk_display = gtk_widget_get_display (app->main_window); + +#if defined(GDK_WINDOWING_X11) + if (GDK_IS_X11_DISPLAY (gdk_display)) { + *is_x11 = TRUE; + return gdk_x11_display_get_xdisplay (gdk_display); + } else +#endif +#ifdef GDK_WINDOWING_WAYLAND + if (GDK_IS_WAYLAND_DISPLAY (gdk_display)) { + *is_x11 = FALSE; + return gdk_wayland_display_get_wl_display (gdk_display); + } else +#endif + g_error ("Running in a non supported environment"); +} + +static VADisplay +ensure_va_display (AppData * app, gpointer native_display, gboolean is_x11) +{ + if (app->va_display) + return app->va_display; + app->va_display = is_x11 ? + vaGetDisplay (native_display) : vaGetDisplayWl (native_display); + /* There's no need to call vaInitialize() since element does it + * internally */ + return app->va_display; +} + +static GstContext * +create_vaapi_app_display_context (AppData * app, gboolean new_va_display) +{ + GstContext *context; + GstStructure *s; + VADisplay va_display; + gpointer native_display = NULL; + const gchar *name = NULL; + gboolean is_x11; + + native_display = get_native_display (app, &is_x11); + + if (new_va_display) { + va_display = is_x11 ? + vaGetDisplay (native_display) : vaGetDisplayWl (native_display); + } else + va_display = ensure_va_display (app, native_display, is_x11); + + name = is_x11 ? "x11-display" : "wl-display"; + + context = gst_context_new ("gst.vaapi.app.Display", FALSE); + s = gst_context_writable_structure (context); + gst_structure_set (s, "va-display", G_TYPE_POINTER, va_display, NULL); + gst_structure_set (s, name, G_TYPE_POINTER, native_display, NULL); + + return context; +} + +static void +get_allocation (GtkWidget * widget, GtkAllocation * allocation) +{ + GdkDisplay *display = gdk_display_get_default (); + + gtk_widget_get_allocation (widget, allocation); + + /* On Wayland the whole gtk window is one surface and the video is a + * subsurface of the top-level surface. So the position must be relative + * to the top-level window not relative to the parent widget */ + if (GDK_IS_WAYLAND_DISPLAY (display)) + gtk_widget_translate_coordinates (widget, gtk_widget_get_toplevel (widget), + 0, 0, &allocation->x, &allocation->y); +} + +static GstBusSyncReply +bus_sync_handler (GstBus * bus, GstMessage * msg, gpointer data) +{ + AppData *app = data; + + switch (GST_MESSAGE_TYPE (msg)) { + case GST_MESSAGE_NEED_CONTEXT:{ + const gchar *context_type; + gboolean new_va_disp; + GstContext *context; + + gst_message_parse_context_type (msg, &context_type); + gst_println ("Got need context %s from %s", context_type, + GST_MESSAGE_SRC_NAME (msg)); + + if (g_strcmp0 (context_type, "gst.vaapi.Display") == 0) { + if (app->gstvaapidisplay) { + GstStructure *s; + + context = gst_context_new ("gst.vaapi.Display", FALSE); + s = gst_context_writable_structure (context); + gst_structure_set (s, "gst.vaapi.Display", + GST_TYPE_OBJECT, app->gstvaapidisplay, NULL); + } + break; + } + + if (g_strcmp0 (context_type, "gst.vaapi.app.Display") != 0) + break; + + /* create a new VA display *only* for the second video sink */ + new_va_disp = (g_strcmp0 (GST_MESSAGE_SRC_NAME (msg), "sink2") == 0); + + context = create_vaapi_app_display_context (app, new_va_disp); + gst_element_set_context (GST_ELEMENT (GST_MESSAGE_SRC (msg)), context); + gst_context_unref (context); + break; + } + case GST_MESSAGE_ELEMENT:{ + GstVideoOverlay *overlay; + GtkAllocation allocation; + guint i; + + if (!gst_is_video_overlay_prepare_window_handle_message (msg)) + break; + + overlay = GST_VIDEO_OVERLAY (GST_MESSAGE_SRC (msg)); + + i = (g_strcmp0 (GST_MESSAGE_SRC_NAME (msg), "sink2") == 0) ? 1 : 0; + + app->overlay[i] = overlay; + get_allocation (app->video_widget[i], &allocation); + gst_video_overlay_set_window_handle (overlay, app->videoarea_handle[i]); + gtk_widget_queue_draw_area (app->video_widget[i], 0, 0, allocation.width, + allocation.height); + + break; + } + case GST_MESSAGE_HAVE_CONTEXT:{ + const gchar *context_type; + const GstStructure *s; + GstContext *context = NULL; + const GValue *value; + + gst_message_parse_have_context (msg, &context); + if (!context) + break; + + context_type = gst_context_get_context_type (context); + gst_println ("Got have context %s from %s", context_type, + GST_MESSAGE_SRC_NAME (msg)); + + if (g_strcmp0 (context_type, "gst.vaapi.Display") != 0) + break; + s = gst_context_get_structure (context); + if (!s) + break; + value = gst_structure_get_value (s, "gst.vaapi.Display"); + if (!value) + break; + app->gstvaapidisplay = g_value_dup_object (value); + gst_println ("found display %s", GST_OBJECT_NAME (app->gstvaapidisplay)); + break; + } + case GST_MESSAGE_EOS: + gtk_main_quit (); + break; + default: + break; + } + + return GST_BUS_PASS; +} + +static void +play_cb (GtkButton * button, gpointer data) +{ + AppData *app = data; + + gst_element_set_state (app->pipeline, GST_STATE_PLAYING); +} + +static void +null_cb (GtkButton * button, gpointer data) +{ + AppData *app = data; + + gst_element_set_state (app->pipeline, GST_STATE_NULL); + app->va_display = NULL; +} + + +static void +realize_cb (GtkWidget * widget, gpointer data) +{ + AppData *app = data; + GdkWindow *window; + GdkDisplay *display; + static guint counter = 0; + + display = gdk_display_get_default (); + +#ifdef GDK_WINDOWING_WAYLAND + /* On wayland gtk_widget_get_window() only works correctly for the + * toplevel widget. Otherwise a new wayland surface is created but + * never used and the video remains invisible. */ + if (GDK_IS_WAYLAND_DISPLAY (display)) + window = gtk_widget_get_window (app->main_window); + else +#endif + window = gtk_widget_get_window (widget); + + if (!gdk_window_ensure_native (window)) + g_error ("Couldn't create native window needed for GstOverlay!"); + +#ifdef GDK_WINDOWING_X11 + if (GDK_IS_X11_DISPLAY (display)) { + app->videoarea_handle[counter++ % 2] = GDK_WINDOW_XID (window); + } else +#endif +#ifdef GDK_WINDOWING_WAYLAND + if (GDK_IS_WAYLAND_DISPLAY (display)) { + app->videoarea_handle[counter++ % 2] = + (guintptr) gdk_wayland_window_get_wl_surface (window); + } else +#endif + g_error ("Unsupported GDK backend"); +} + +static void +draw_cb (GtkWidget * widget, cairo_t * cr, gpointer data) +{ + AppData *app = data; + GtkAllocation allocation; + int i; + + i = (widget == app->video_widget[0]) ? 0 : 1; + + get_allocation (widget, &allocation); + + gst_println ("draw_cb[%d] x %d, y %d, w %d, h %d\n", i, + allocation.x, allocation.y, allocation.width, allocation.height); + + if (app->overlay[i]) { + gst_video_overlay_set_render_rectangle (app->overlay[i], allocation.x, + allocation.y, allocation.width, allocation.height); + } +} + +static GtkWidget * +create_video_box (AppData * app) +{ + GtkWidget *video_area; + + video_area = gtk_drawing_area_new (); + gtk_widget_set_size_request (video_area, 640, 480); + g_signal_connect (video_area, "realize", G_CALLBACK (realize_cb), app); + g_signal_connect (video_area, "draw", G_CALLBACK (draw_cb), app); + return video_area; +} + +static GtkWidget * +create_rotate_button (AppData * app, const gchar * name) +{ + GtkWidget *rotate; + GstElement *sink; + + sink = gst_bin_get_by_name (GST_BIN (app->pipeline), name); + if (!sink && !g_strcmp0 (name, "sink1")) + sink = g_vaapisink; + g_assert (sink); + + rotate = gtk_button_new_with_label ("Rotate"); + g_signal_connect (rotate, "clicked", G_CALLBACK (button_rotate_cb), sink); + if (sink != g_vaapisink) + gst_object_unref (sink); + + return rotate; +} + +static void +build_ui (AppData * app) +{ + GtkWidget *mainwin, *vbox, *pane, *bbox; + + mainwin = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (mainwin), "VAAPI display context test"); + gtk_window_set_resizable (GTK_WINDOW (mainwin), FALSE); + g_signal_connect (mainwin, "delete-event", G_CALLBACK (delete_event_cb), app); + app->main_window = mainwin; + + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + gtk_container_add (GTK_CONTAINER (mainwin), vbox); + + pane = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL); + gtk_box_pack_start (GTK_BOX (vbox), pane, TRUE, TRUE, 0); + + /* first video box */ + app->video_widget[0] = create_video_box (app); + gtk_paned_pack1 (GTK_PANED (pane), app->video_widget[0], TRUE, TRUE); + + /* rotate buttons */ + bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); + gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_SPREAD); + gtk_box_pack_end (GTK_BOX (vbox), bbox, TRUE, TRUE, 0); + + gtk_box_pack_start (GTK_BOX (bbox), create_rotate_button (app, "sink1"), TRUE, + TRUE, 0); + + if (g_multisink) { + /* second video box */ + app->video_widget[1] = create_video_box (app); + gtk_paned_pack2 (GTK_PANED (pane), app->video_widget[1], TRUE, TRUE); + + gtk_box_pack_start (GTK_BOX (bbox), create_rotate_button (app, "sink2"), + TRUE, TRUE, 0); + } else { + GtkWidget *button; + + button = gtk_button_new_with_label ("PLAYING"); + gtk_box_pack_start (GTK_BOX (bbox), button, TRUE, TRUE, 0); + g_signal_connect (button, "clicked", G_CALLBACK (play_cb), app); + + button = gtk_button_new_with_label ("NULL"); + gtk_box_pack_start (GTK_BOX (bbox), button, TRUE, TRUE, 0); + g_signal_connect (button, "clicked", G_CALLBACK (null_cb), app); + } + + gtk_widget_show_all (mainwin); +} + +int +main (gint argc, gchar ** argv) +{ + AppData app = { 0, }; + GstBus *bus; + GOptionContext *ctx; + GError *error = NULL; + + XInitThreads (); + + ctx = g_option_context_new ("- test options"); + if (!ctx) + return -1; + + g_option_context_add_group (ctx, gtk_get_option_group (TRUE)); + g_option_context_add_group (ctx, gst_init_get_option_group ()); + g_option_context_add_main_entries (ctx, g_options, NULL); + if (!g_option_context_parse (ctx, &argc, &argv, NULL)) + return -1; + g_option_context_free (ctx); + + if (g_multisink) { + app.pipeline = gst_parse_launch ("videotestsrc ! tee name=t ! queue ! " + "vaapisink name=sink1 t. ! queue ! vaapisink name=sink2", &error); + } else if (!g_filepath) { + app.pipeline = gst_parse_launch ("videotestsrc ! vaapih264enc ! " + "vaapidecodebin ! vaapisink name=sink1", &error); + } else { + app.pipeline = gst_element_factory_make ("playbin", NULL); + g_assert (app.pipeline); + } + + if (error) { + gst_printerrln ("failed to parse pipeline: %s", error->message); + g_error_free (error); + return -1; + } + + if (!g_multisink && g_filepath) { + g_vaapisink = gst_element_factory_make ("vaapisink", "sink1"); + g_assert (g_vaapisink); + g_object_set (app.pipeline, "uri", g_filepath, "video-sink", g_vaapisink, + NULL); + } + + build_ui (&app); + + bus = gst_element_get_bus (app.pipeline); + gst_bus_set_sync_handler (bus, bus_sync_handler, (gpointer) & app, NULL); + gst_object_unref (bus); + + gst_element_set_state (app.pipeline, GST_STATE_PLAYING); + gst_println ("Now playing…"); + + gtk_main (); + + gst_object_unref (app.pipeline); + gst_object_unref (app.gstvaapidisplay); + /* there is no need to call vaTerminate() because it is done by the + * vaapi elements */ + return 0; +} diff --git a/tests/examples/test-vaapipostproc.c b/tests/examples/test-vaapipostproc.c new file mode 100644 index 0000000000..87d1353912 --- /dev/null +++ b/tests/examples/test-vaapipostproc.c @@ -0,0 +1,157 @@ +/* + * test-vaapipostproc.c - Testsuite for VAAPI Postprocessor + * + * Copyright (C) 2017 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +typedef struct _CustomData +{ + GstElement *pipeline; + GstElement *postproc; + GMainLoop *loop; +} AppData; + +static gboolean +_check_passthrough_mode (gpointer user_data) +{ + gboolean ret; + AppData *data = (AppData *) user_data; + + ret = gst_base_transform_is_passthrough (GST_BASE_TRANSFORM (data->postproc)); + + if (ret) + gst_println ("Now this pipeline is on passthrough mode"); + else + gst_println ("Now this pipeline is NOT on passthrough mode"); + + return FALSE; +} + +static void +set_contrast (AppData * data) +{ + static gfloat value = 1.0; + + value = value == 1.0 ? 0.5 : 1.0; + g_object_set (data->postproc, "contrast", value, NULL); + gst_println ("contrast value is changed to %f", value); + + g_timeout_add (300, _check_passthrough_mode, data); +} + +static void +change_size (AppData * data) +{ + static gint i = 0; + if (i == 0) { + g_object_set (data->postproc, "width", 1280, "height", 720, NULL); + gst_println ("frame size is changed to 1280x720"); + i++; + } else { + g_object_set (data->postproc, "width", 0, "height", 0, NULL); + gst_println ("frame size is changed to default"); + i = 0; + } + + g_timeout_add (300, _check_passthrough_mode, data); +} + +/* Process keyboard input */ +static gboolean +handle_keyboard (GIOChannel * source, GIOCondition cond, AppData * data) +{ + gchar *str = NULL; + + if (g_io_channel_read_line (source, &str, NULL, NULL, + NULL) != G_IO_STATUS_NORMAL) { + return TRUE; + } + + switch (g_ascii_tolower (str[0])) { + case 's':{ + set_contrast (data); + break; + } + case 'c':{ + change_size (data); + break; + } + case 'q': + g_main_loop_quit (data->loop); + break; + default: + break; + } + + g_free (str); + + return TRUE; +} + +int +main (int argc, char *argv[]) +{ + AppData data = { 0, }; + GstStateChangeReturn ret; + GIOChannel *io_stdin; + + /* Initialize GStreamer */ + gst_init (&argc, &argv); + + /* Print usage map */ + gst_println ("USAGE: Choose one of the following options, then press enter:\n" + " 's' to set contrast\n" " 'c' to change size\n" " 'q' to quit\n"); + + data.pipeline = + gst_parse_launch + ("videotestsrc name=src ! vaapih264enc ! vaapih264dec ! vaapipostproc name=postproc ! vaapisink", + NULL); + data.postproc = gst_bin_get_by_name (GST_BIN (data.pipeline), "postproc"); + + /* Add a keyboard watch so we get notified of keystrokes */ + io_stdin = g_io_channel_unix_new (fileno (stdin)); + g_io_add_watch (io_stdin, G_IO_IN, (GIOFunc) handle_keyboard, &data); + + /* Start playing */ + ret = gst_element_set_state (data.pipeline, GST_STATE_PLAYING); + if (ret == GST_STATE_CHANGE_FAILURE) { + g_printerr ("Unable to set the pipeline to the playing state.\n"); + gst_object_unref (data.pipeline); + return -1; + } + + g_timeout_add (300, _check_passthrough_mode, &data); + + /* Create a GLib Main Loop and set it to run */ + data.loop = g_main_loop_new (NULL, FALSE); + g_main_loop_run (data.loop); + + /* Free resources */ + g_main_loop_unref (data.loop); + g_io_channel_unref (io_stdin); + gst_element_set_state (data.pipeline, GST_STATE_NULL); + + gst_object_unref (data.postproc); + gst_object_unref (data.pipeline); + + return 0; +} diff --git a/tests/examples/test-vaapisink.c b/tests/examples/test-vaapisink.c new file mode 100644 index 0000000000..41f3fc3e0b --- /dev/null +++ b/tests/examples/test-vaapisink.c @@ -0,0 +1,189 @@ +#include +#include +#include +#include + +static gboolean use_postproc; +static GOptionEntry g_options[] = { + {"postproc", 'p', 0, G_OPTION_ARG_NONE, &use_postproc, + "use vaapipostproc to rotate rather than vaapisink", NULL}, + {NULL,} +}; + +typedef struct _CustomData +{ + GstElement *pipeline; + GstElement *rotator; + GMainLoop *loop; + gboolean orient_automatic; +} AppData; + +static void +send_rotate_event (AppData * data) +{ + gboolean res = FALSE; + GstEvent *event; + static gint counter = 0; + const static gchar *tags[] = { "rotate-90", "rotate-180", "rotate-270", + "rotate-0", "flip-rotate-0", "flip-rotate-90", "flip-rotate-180", + "flip-rotate-270", + }; + + event = gst_event_new_tag (gst_tag_list_new (GST_TAG_IMAGE_ORIENTATION, + tags[counter++ % G_N_ELEMENTS (tags)], NULL)); + + /* Send the event */ + g_print ("Sending event %" GST_PTR_FORMAT ": ", event); + res = gst_element_send_event (data->pipeline, event); + g_print ("%s\n", res ? "ok" : "failed"); + +} + +static void +keyboard_cb (const gchar * key, AppData * data) +{ + switch (g_ascii_tolower (key[0])) { + case 'r': + send_rotate_event (data); + break; + case 's':{ + if (use_postproc) { + g_object_set (G_OBJECT (data->rotator), "video-direction", + GST_VIDEO_ORIENTATION_AUTO, NULL); + } else { + /* rotation=360 means auto for vaapisnk */ + g_object_set (G_OBJECT (data->rotator), "rotation", 360, NULL); + } + break; + } + case 'q': + g_main_loop_quit (data->loop); + break; + default: + break; + } +} + +static gboolean +bus_msg (GstBus * bus, GstMessage * msg, gpointer user_data) +{ + AppData *data = user_data; + + switch (GST_MESSAGE_TYPE (msg)) { + case GST_MESSAGE_ELEMENT: + { + GstNavigationMessageType mtype = gst_navigation_message_get_type (msg); + if (mtype == GST_NAVIGATION_MESSAGE_EVENT) { + GstEvent *ev = NULL; + + if (gst_navigation_message_parse_event (msg, &ev)) { + GstNavigationEventType type = gst_navigation_event_get_type (ev); + if (type == GST_NAVIGATION_EVENT_KEY_PRESS) { + const gchar *key; + + if (gst_navigation_event_parse_key_event (ev, &key)) + keyboard_cb (key, data); + } + } + if (ev) + gst_event_unref (ev); + } + break; + } + default: + break; + } + + return TRUE; +} + +/* Process keyboard input */ +static gboolean +handle_keyboard (GIOChannel * source, GIOCondition cond, AppData * data) +{ + gchar *str = NULL; + + if (g_io_channel_read_line (source, &str, NULL, NULL, + NULL) != G_IO_STATUS_NORMAL) { + return TRUE; + } + + keyboard_cb (str, data); + g_free (str); + + return TRUE; +} + +int +main (int argc, char *argv[]) +{ + AppData data; + GstStateChangeReturn ret; + GIOChannel *io_stdin; + GOptionContext *ctx; + GError *err = NULL; + guint srcid; + + /* Initialize GStreamer */ + ctx = g_option_context_new ("- test options"); + if (!ctx) + return -1; + g_option_context_add_group (ctx, gst_init_get_option_group ()); + g_option_context_add_main_entries (ctx, g_options, NULL); + if (!g_option_context_parse (ctx, &argc, &argv, NULL)) + return -1; + g_option_context_free (ctx); + + /* Print usage map */ + g_print ("USAGE: Choose one of the following options, then press enter:\n" + " 'r' to send image-orientation tag event\n" + " 's' to set orient-automatic\n" " 'Q' to quit\n"); + + if (use_postproc) { + data.pipeline = + gst_parse_launch ("videotestsrc ! vaapipostproc name=pp ! xvimagesink", + &err); + } else { + data.pipeline = + gst_parse_launch ("videotestsrc ! vaapisink name=sink", &err); + } + if (err) { + g_printerr ("failed to create pipeline: %s\n", err->message); + g_error_free (err); + return -1; + } + + if (use_postproc) + data.rotator = gst_bin_get_by_name (GST_BIN (data.pipeline), "pp"); + else + data.rotator = gst_bin_get_by_name (GST_BIN (data.pipeline), "sink"); + srcid = gst_bus_add_watch (GST_ELEMENT_BUS (data.pipeline), bus_msg, &data); + + /* Add a keyboard watch so we get notified of keystrokes */ + io_stdin = g_io_channel_unix_new (fileno (stdin)); + g_io_add_watch (io_stdin, G_IO_IN, (GIOFunc) handle_keyboard, &data); + + /* Start playing */ + ret = gst_element_set_state (data.pipeline, GST_STATE_PLAYING); + if (ret == GST_STATE_CHANGE_FAILURE) { + g_printerr ("Unable to set the pipeline to the playing state.\n"); + goto bail; + } + + /* Create a GLib Main Loop and set it to run */ + data.loop = g_main_loop_new (NULL, FALSE); + g_main_loop_run (data.loop); + + gst_element_set_state (data.pipeline, GST_STATE_NULL); + +bail: + /* Free resources */ + g_source_remove (srcid); + g_main_loop_unref (data.loop); + g_io_channel_unref (io_stdin); + + gst_object_unref (data.rotator); + gst_object_unref (data.pipeline); + + return 0; +} diff --git a/tests/internal/codec.c b/tests/internal/codec.c new file mode 100644 index 0000000000..d14981ac8e --- /dev/null +++ b/tests/internal/codec.c @@ -0,0 +1,195 @@ +/* + * codec.c - Codec utilities for the tests + * + * Copyright (C) 2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gst/vaapi/sysdeps.h" +#include +#include "codec.h" + +typedef struct +{ + const gchar *codec_str; + GstVaapiCodec codec; + const gchar *caps_str; +} CodecMap; + +static const CodecMap g_codec_map[] = { + {"h264", GST_VAAPI_CODEC_H264, + "video/x-h264"}, + {"jpeg", GST_VAAPI_CODEC_JPEG, + "image/jpeg"}, + {"mpeg2", GST_VAAPI_CODEC_MPEG2, + "video/mpeg, mpegversion=2"}, + {"mpeg4", GST_VAAPI_CODEC_MPEG4, + "video/mpeg, mpegversion=4"}, + {"wmv3", GST_VAAPI_CODEC_VC1, + "video/x-wmv, wmvversion=3"}, + {"vc1", GST_VAAPI_CODEC_VC1, + "video/x-wmv, wmvversion=3, format=(string)WVC1"}, + {NULL,} +}; + +static const CodecMap * +get_codec_map (GstVaapiCodec codec) +{ + const CodecMap *m; + + if (codec) { + for (m = g_codec_map; m->codec_str != NULL; m++) { + if (m->codec == codec) + return m; + } + } + return NULL; +} + +const gchar * +string_from_codec (GstVaapiCodec codec) +{ + const CodecMap *const m = get_codec_map (codec); + + return m ? m->codec_str : NULL; +} + +GstCaps * +caps_from_codec (GstVaapiCodec codec) +{ + const CodecMap *const m = get_codec_map (codec); + + return m ? gst_caps_from_string (m->caps_str) : NULL; +} + +GstVaapiCodec +identify_codec_from_string (const gchar * codec_str) +{ + const CodecMap *m; + + if (codec_str) { + for (m = g_codec_map; m->codec_str != NULL; m++) { + if (g_ascii_strcasecmp (m->codec_str, codec_str) == 0) + return m->codec; + } + } + return 0; +} + +typedef struct +{ + GMappedFile *file; + guint8 *data; + guint size; + guint probability; + GstCaps *caps; + GstTypeFind type_find; +} CodecIdentifier; + +static const guint8 * +codec_identifier_peek (gpointer data, gint64 offset, guint size) +{ + CodecIdentifier *const cip = data; + + if (offset >= 0 && offset + size <= cip->size) + return cip->data + offset; + if (offset < 0 && ((gint) cip->size + offset) >= 0) + return &cip->data[cip->size + offset]; + return NULL; +} + +static void +codec_identifier_suggest (gpointer data, guint probability, GstCaps * caps) +{ + CodecIdentifier *const cip = data; + + if (cip->probability < probability) { + cip->probability = probability; + gst_caps_replace (&cip->caps, caps); + } +} + +static void +codec_identifier_free (CodecIdentifier * cip) +{ + if (!cip) + return; + + if (cip->file) { + g_mapped_file_unref (cip->file); + cip->file = NULL; + } + gst_caps_replace (&cip->caps, NULL); + g_slice_free (CodecIdentifier, cip); +} + +static CodecIdentifier * +codec_identifier_new (const gchar * filename) +{ + CodecIdentifier *cip; + GstTypeFind *tfp; + + cip = g_slice_new0 (CodecIdentifier); + if (!cip) + return NULL; + + cip->file = g_mapped_file_new (filename, FALSE, NULL); + if (!cip->file) + goto error; + + cip->size = g_mapped_file_get_length (cip->file); + cip->data = (guint8 *) g_mapped_file_get_contents (cip->file); + if (!cip->data) + goto error; + + tfp = &cip->type_find; + tfp->peek = codec_identifier_peek; + tfp->suggest = codec_identifier_suggest; + tfp->data = cip; + return cip; + +error: + codec_identifier_free (cip); + return NULL; +} + +GstVaapiCodec +identify_codec (const gchar * filename) +{ + CodecIdentifier *cip; + GList *type_list, *l; + guint32 codec = 0; + + cip = codec_identifier_new (filename); + if (!cip) + return 0; + + type_list = gst_type_find_factory_get_list (); + for (l = type_list; l != NULL; l = l->next) { + GstTypeFindFactory *const factory = GST_TYPE_FIND_FACTORY (l->data); + gst_type_find_factory_call_function (factory, &cip->type_find); + } + g_list_free (type_list); + + if (cip->probability >= GST_TYPE_FIND_LIKELY) + codec = + gst_vaapi_profile_get_codec (gst_vaapi_profile_from_caps (cip->caps)); + + codec_identifier_free (cip); + return codec; +} diff --git a/tests/internal/codec.h b/tests/internal/codec.h new file mode 100644 index 0000000000..6aaf5b8fc8 --- /dev/null +++ b/tests/internal/codec.h @@ -0,0 +1,40 @@ +/* + * codec.h - Codec utilities for the tests + * + * Copyright (C) 2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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 CODEC_H +#define CODEC_H + +#include + +const gchar * +string_from_codec(GstVaapiCodec codec); + +GstCaps * +caps_from_codec(GstVaapiCodec codec); + +GstVaapiCodec +identify_codec_from_string(const gchar *codec_str); + +GstVaapiCodec +identify_codec(const gchar *filename); + +#endif /* CODEC_H */ diff --git a/tests/internal/decoder.c b/tests/internal/decoder.c new file mode 100644 index 0000000000..1dfbba2628 --- /dev/null +++ b/tests/internal/decoder.c @@ -0,0 +1,199 @@ +/* + * decoder.h - Decoder utilities for the tests + * + * Copyright (C) 2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gst/vaapi/sysdeps.h" +#include +#include +#include +#include +#include +#include "decoder.h" +#include "test-jpeg.h" +#include "test-mpeg2.h" +#include "test-mpeg4.h" +#include "test-h264.h" +#include "test-vc1.h" + +typedef void (*GetVideoInfoFunc) (VideoDecodeInfo * info); + +typedef struct _CodecDefs CodecDefs; +struct _CodecDefs +{ + const gchar *codec_str; + GetVideoInfoFunc get_video_info; +}; + +static const CodecDefs g_codec_defs[] = { +#define INIT_FUNCS(CODEC) { #CODEC, CODEC##_get_video_info } + INIT_FUNCS (jpeg), + INIT_FUNCS (mpeg2), + INIT_FUNCS (mpeg4), + INIT_FUNCS (h264), + INIT_FUNCS (vc1), +#undef INIT_FUNCS + {NULL,} +}; + +static const CodecDefs * +find_codec_defs (const gchar * codec_str) +{ + const CodecDefs *c; + for (c = g_codec_defs; c->codec_str; c++) + if (strcmp (codec_str, c->codec_str) == 0) + return c; + return NULL; +} + +static inline const CodecDefs * +get_codec_defs (GstVaapiDecoder * decoder) +{ + return gst_vaapi_decoder_get_user_data (decoder); +} + +static inline void +set_codec_defs (GstVaapiDecoder * decoder, const CodecDefs * c) +{ + gst_vaapi_decoder_set_user_data (decoder, (gpointer) c); +} + +GstVaapiDecoder * +decoder_new (GstVaapiDisplay * display, const gchar * codec_name) +{ + GstVaapiDecoder *decoder; + const CodecDefs *codec; + GstCaps *caps; + VideoDecodeInfo info; + + if (!codec_name) + codec_name = "h264"; + + codec = find_codec_defs (codec_name); + if (!codec) { + GST_ERROR ("failed to find %s codec data", codec_name); + return NULL; + } + + codec->get_video_info (&info); + caps = gst_vaapi_profile_get_caps (info.profile); + if (!caps) { + GST_ERROR ("failed to create decoder caps"); + return NULL; + } + + if (info.width > 0 && info.height > 0) + gst_caps_set_simple (caps, + "width", G_TYPE_INT, info.width, + "height", G_TYPE_INT, info.height, NULL); + + switch (gst_vaapi_profile_get_codec (info.profile)) { + case GST_VAAPI_CODEC_H264: + decoder = gst_vaapi_decoder_h264_new (display, caps); + break; + case GST_VAAPI_CODEC_JPEG: + decoder = gst_vaapi_decoder_jpeg_new (display, caps); + break; + case GST_VAAPI_CODEC_MPEG2: + decoder = gst_vaapi_decoder_mpeg2_new (display, caps); + break; + case GST_VAAPI_CODEC_MPEG4: + decoder = gst_vaapi_decoder_mpeg4_new (display, caps); + break; + case GST_VAAPI_CODEC_VC1: + decoder = gst_vaapi_decoder_vc1_new (display, caps); + break; + default: + decoder = NULL; + break; + } + gst_caps_unref (caps); + if (!decoder) { + GST_ERROR ("failed to create %s decoder", codec->codec_str); + return NULL; + } + + set_codec_defs (decoder, codec); + return decoder; +} + +gboolean +decoder_put_buffers (GstVaapiDecoder * decoder) +{ + const CodecDefs *codec; + VideoDecodeInfo info; + GstBuffer *buffer; + gboolean success; + + g_return_val_if_fail (decoder != NULL, FALSE); + + codec = get_codec_defs (decoder); + g_return_val_if_fail (codec != NULL, FALSE); + + codec->get_video_info (&info); + buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, + (guchar *) info.data, info.data_size, 0, info.data_size, NULL, NULL); + if (!buffer) { + GST_ERROR ("failed to create encoded data buffer"); + return FALSE; + } + + success = gst_vaapi_decoder_put_buffer (decoder, buffer); + gst_buffer_unref (buffer); + if (!success) { + GST_ERROR ("failed to send video data to the decoder"); + return FALSE; + } + + if (!gst_vaapi_decoder_put_buffer (decoder, NULL)) { + GST_ERROR ("failed to submit to the decoder"); + return FALSE; + } + return TRUE; +} + +GstVaapiSurfaceProxy * +decoder_get_surface (GstVaapiDecoder * decoder) +{ + GstVaapiSurfaceProxy *proxy; + GstVaapiDecoderStatus status; + + g_return_val_if_fail (decoder != NULL, NULL); + + status = gst_vaapi_decoder_get_surface (decoder, &proxy); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) { + GST_ERROR ("failed to get decoded surface (decoder status %d)", status); + return NULL; + } + return proxy; +} + +const gchar * +decoder_get_codec_name (GstVaapiDecoder * decoder) +{ + const CodecDefs *codec; + + g_return_val_if_fail (decoder != NULL, NULL); + + codec = get_codec_defs (decoder); + g_return_val_if_fail (codec != NULL, FALSE); + + return codec->codec_str; +} diff --git a/tests/internal/decoder.h b/tests/internal/decoder.h new file mode 100644 index 0000000000..68530009dd --- /dev/null +++ b/tests/internal/decoder.h @@ -0,0 +1,40 @@ +/* + * decoder.h - Decoder utilities for the tests + * + * Copyright (C) 2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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 DECODER_H +#define DECODER_H + +#include + +GstVaapiDecoder * +decoder_new(GstVaapiDisplay *display, const gchar *codec_name); + +gboolean +decoder_put_buffers(GstVaapiDecoder *decoder); + +GstVaapiSurfaceProxy * +decoder_get_surface(GstVaapiDecoder *decoder); + +const gchar * +decoder_get_codec_name(GstVaapiDecoder *decoder); + +#endif /* DECODER_H */ diff --git a/tests/internal/image.c b/tests/internal/image.c new file mode 100644 index 0000000000..ea532fb831 --- /dev/null +++ b/tests/internal/image.c @@ -0,0 +1,400 @@ +/* + * image.c - Image utilities for the tests + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "image.h" + +static gboolean +image_draw_rectangle (GstVaapiImage * image, + gint x, gint y, guint width, guint height, guint32 color, guint32 flags); + +static gboolean +image_draw_color_rectangles (GstVaapiImage * image, + guint width, guint height, const guint32 colors[4], guint32 flags) +{ + const guint w = width / 2; + const guint h = height / 2; + + if (!image_draw_rectangle (image, 0, 0, w, h, colors[0], flags)) + return FALSE; + if (!image_draw_rectangle (image, w, 0, w, h, colors[1], flags)) + return FALSE; + if (!image_draw_rectangle (image, 0, h, w, h, colors[2], flags)) + return FALSE; + if (!image_draw_rectangle (image, w, h, w, h, colors[3], flags)) + return FALSE; + return TRUE; +} + +GstVaapiImage * +image_generate (GstVaapiDisplay * display, + GstVideoFormat format, guint width, guint height) +{ + return image_generate_full (display, format, width, height, 0); +} + +GstVaapiImage * +image_generate_full (GstVaapiDisplay * display, + GstVideoFormat format, guint width, guint height, guint32 flags) +{ + GstVaapiImage *image; + + static const guint32 rgb_colors[4] = + { 0xffff0000, 0xff00ff00, 0xff0000ff, 0xff000000 }; + static const guint32 bgr_colors[4] = + { 0xff000000, 0xff0000ff, 0xff00ff00, 0xffff0000 }; + static const guint32 inv_colors[4] = + { 0xffdeadc0, 0xffdeadc0, 0xffdeadc0, 0xffdeadc0 }; + + image = gst_vaapi_image_new (display, format, width, height); + if (!image) + return NULL; + + if (flags) { + if (!image_draw_color_rectangles (image, width, height, + ((flags & GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD) ? + rgb_colors : inv_colors), + GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD)) + goto error; + + if (!image_draw_color_rectangles (image, width, height, + ((flags & GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD) ? + bgr_colors : inv_colors), + GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD)) + goto error; + } else if (!image_draw_color_rectangles (image, width, height, rgb_colors, 0)) + goto error; + return image; + +error: + gst_vaapi_image_unref (image); + return NULL; +} + +typedef void (*DrawRectFunc) (guchar * pixels[3], + guint stride[3], gint x, gint y, guint width, guint height, guint32 color); + +static void +draw_rect_ARGB (guchar * pixels[3], + guint stride[3], gint x, gint y, guint width, guint height, guint32 color) +{ + guint i, j; + + color = GUINT32_TO_BE (color); + + for (j = 0; j < height; j++) { + guint32 *p = (guint32 *) (pixels[0] + (y + j) * stride[0] + x * 4); + for (i = 0; i < width; i++) + p[i] = color; + } +} + +static void +draw_rect_BGRA (guchar * pixels[3], + guint stride[3], gint x, gint y, guint width, guint height, guint32 color) +{ + // Converts ARGB color to BGRA + color = GUINT32_SWAP_LE_BE (color); + + draw_rect_ARGB (pixels, stride, x, y, width, height, color); +} + +static void +draw_rect_RGBA (guchar * pixels[3], + guint stride[3], gint x, gint y, guint width, guint height, guint32 color) +{ + // Converts ARGB color to RGBA + color = ((color >> 24) & 0xff) | ((color & 0xffffff) << 8); + + draw_rect_ARGB (pixels, stride, x, y, width, height, color); +} + +static void +draw_rect_ABGR (guchar * pixels[3], + guint stride[3], gint x, gint y, guint width, guint height, guint32 color) +{ + // Converts ARGB color to ABGR + color = ((color & 0xff00ff00) | + ((color >> 16) & 0xff) | ((color & 0xff) << 16)); + + draw_rect_ARGB (pixels, stride, x, y, width, height, color); +} + +static void +draw_rect_NV12 ( // Y, UV planes + guchar * pixels[3], + guint stride[3], gint x, gint y, guint width, guint height, guint32 color) +{ + const guchar Y = color >> 16; + const guchar Cb = color >> 8; + const guchar Cr = color; + guchar *dst; + guint i, j; + + dst = pixels[0] + y * stride[0] + x; + for (j = 0; j < height; j++, dst += stride[0]) + for (i = 0; i < width; i++) + dst[i] = Y; + + x /= 2; + y /= 2; + width /= 2; + height /= 2; + + dst = pixels[1] + y * stride[1] + x * 2; + for (j = 0; j < height; j++, dst += stride[1]) + for (i = 0; i < width; i++) { + dst[2 * i + 0] = Cb; + dst[2 * i + 1] = Cr; + } +} + +static void +draw_rect_YV12 ( // Y, V, U planes + guchar * pixels[3], + guint stride[3], gint x, gint y, guint width, guint height, guint32 color) +{ + const guchar Y = color >> 16; + const guchar Cb = color >> 8; + const guchar Cr = color; + guchar *pY, *pU, *pV; + guint i, j; + + pY = pixels[0] + y * stride[0] + x; + for (j = 0; j < height; j++, pY += stride[0]) + for (i = 0; i < width; i++) + pY[i] = Y; + + x /= 2; + y /= 2; + width /= 2; + height /= 2; + + pV = pixels[1] + y * stride[1] + x; + pU = pixels[2] + y * stride[2] + x; + for (j = 0; j < height; j++, pU += stride[1], pV += stride[2]) + for (i = 0; i < width; i++) { + pU[i] = Cb; + pV[i] = Cr; + } +} + +static void +draw_rect_I420 ( // Y, U, V planes + guchar * pixels[3], + guint stride[3], gint x, gint y, guint width, guint height, guint32 color) +{ + guchar *new_pixels[3] = { pixels[0], pixels[2], pixels[1] }; + guint new_stride[3] = { stride[0], stride[2], stride[1] }; + + draw_rect_YV12 (new_pixels, new_stride, x, y, width, height, color); +} + +static void +draw_rect_YUV422 (guchar * pixels[3], guint stride[3], + gint x, gint y, guint width, guint height, guint32 color) +{ + guint i, j; + + width /= 2; + for (j = 0; j < height; j++) { + guint32 *const p = (guint32 *) + (pixels[0] + (y + j) * stride[0] + x * 2); + for (i = 0; i < width; i++) + p[i] = color; + } +} + +static void +draw_rect_YUY2 (guchar * pixels[3], guint stride[3], + gint x, gint y, guint width, guint height, guint32 color) +{ + const guchar Y = color >> 16; + const guchar Cb = color >> 8; + const guchar Cr = color; + + color = (Y << 24) | (Cb << 16) | (Y << 8) | Cr; + draw_rect_YUV422 (pixels, stride, x, y, width, height, GUINT32_TO_BE (color)); +} + +static void +draw_rect_UYVY (guchar * pixels[3], guint stride[3], + gint x, gint y, guint width, guint height, guint32 color) +{ + const guchar Y = color >> 16; + const guchar Cb = color >> 8; + const guchar Cr = color; + + color = (Cb << 24) | (Y << 16) | (Cr << 8) | Y; + draw_rect_YUV422 (pixels, stride, x, y, width, height, GUINT32_TO_BE (color)); +} + +static void +draw_rect_AYUV (guchar * pixels[3], + guint stride[3], gint x, gint y, guint width, guint height, guint32 color) +{ + guint i, j; + + color = color | 0xff000000; + + for (j = 0; j < height; j++) { + guint32 *p = (guint32 *) (pixels[0] + (y + j) * stride[0] + x * 4); + for (i = 0; i < width; i++) + p[i] = color; + } +} + +static inline guint32 +argb2yuv (guint32 color) +{ + const gint32 r = (color >> 16) & 0xff; + const gint32 g = (color >> 8) & 0xff; + const gint32 b = (color) & 0xff; + + const guint32 y = ((306 * r + 601 * g + 116 * b) >> 10); + const guint32 u = ((-172 * r - 339 * g + 512 * b) >> 10) + 128; + const guint32 v = ((512 * r - 428 * g - 83 * b) >> 10) + 128; + + return (y << 16) | (u << 8) | v; +} + +gboolean +image_draw_rectangle (GstVaapiImage * image, + gint x, gint y, guint width, guint height, guint32 color, guint32 flags) +{ + const GstVideoFormat image_format = gst_vaapi_image_get_format (image); + const guint image_width = gst_vaapi_image_get_width (image); + const guint image_height = gst_vaapi_image_get_height (image); + GstVaapiDisplay *display; + guchar *pixels[3]; + guint stride[3]; + DrawRectFunc draw_rect = NULL; + guint i; + + static const struct + { + GstVideoFormat format; + DrawRectFunc draw_rect; + } + map[] = { +#define _(FORMAT) { GST_VIDEO_FORMAT_##FORMAT, draw_rect_##FORMAT } + _(ARGB), + _(BGRA), + _(RGBA), _(ABGR), _(NV12), _(YV12), _(I420), _(YUY2), _(UYVY), _(AYUV), +#undef _ + { + 0,} + }; + + for (i = 0; !draw_rect && map[i].format; i++) + if (map[i].format == image_format) + draw_rect = map[i].draw_rect; + if (!draw_rect) + return FALSE; + + if (x < 0) + x = 0; + if (y < 0) + y = 0; + if (width > image_width - x) + width = image_width - x; + if (height > image_height - y) + height = image_height - y; + + display = gst_vaapi_image_get_display (image); + if (!display) + return FALSE; + + if (!gst_vaapi_image_map (image)) + return FALSE; + + for (i = 0; i < gst_vaapi_image_get_plane_count (image); i++) { + pixels[i] = gst_vaapi_image_get_plane (image, i); + stride[i] = gst_vaapi_image_get_pitch (image, i); + switch (flags) { + case GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD: + pixels[i] += stride[i]; + // fall-through + case GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD: + stride[i] *= 2; + break; + } + } + + if (flags) + y /= 2, height /= 2; + + if (gst_vaapi_video_format_is_yuv (image_format)) + color = argb2yuv (color); + + draw_rect (pixels, stride, x, y, width, height, color); + return gst_vaapi_image_unmap (image); +} + +gboolean +image_upload (GstVaapiImage * image, GstVaapiSurface * surface) +{ + GstVaapiDisplay *display; + GstVideoFormat format; + GstVaapiImage *surface_image; + GstVaapiSubpicture *subpicture; + gboolean success; + + display = gst_vaapi_surface_get_display (surface); + if (!display) + return FALSE; + + format = gst_vaapi_image_get_format (image); + if (!format) + return FALSE; + + if (gst_vaapi_surface_put_image (surface, image)) + return TRUE; + + surface_image = gst_vaapi_surface_derive_image (surface); + if (surface_image) { + success = gst_vaapi_image_copy (surface_image, image); + gst_vaapi_image_unref (surface_image); + if (success) + return TRUE; + } + + g_print ("could not upload %s image to surface\n", + gst_vaapi_video_format_to_string (format)); + + if (!gst_vaapi_display_has_subpicture_format (display, format, NULL)) + return FALSE; + + g_print ("trying as a subpicture\n"); + + subpicture = gst_vaapi_subpicture_new (image, 0); + if (!subpicture) + g_error ("could not create VA subpicture"); + + if (!gst_vaapi_surface_associate_subpicture (surface, subpicture, NULL, NULL)) + g_error ("could not associate subpicture to surface"); + + /* The surface holds a reference to the subpicture. This is safe */ + gst_vaapi_subpicture_unref (subpicture); + return TRUE; +} diff --git a/tests/internal/image.h b/tests/internal/image.h new file mode 100644 index 0000000000..6abbdb0533 --- /dev/null +++ b/tests/internal/image.h @@ -0,0 +1,51 @@ +/* + * image.h - Image utilities for the tests + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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 IMAGE_H +#define IMAGE_H + +#include +#include + +GstVaapiImage * +image_generate( + GstVaapiDisplay *display, + GstVideoFormat format, + guint width, + guint height +); + +GstVaapiImage * +image_generate_full( + GstVaapiDisplay *display, + GstVideoFormat format, + guint width, + guint height, + guint32 flags +); + +gboolean +image_upload(GstVaapiImage *image, GstVaapiSurface *surface); + +#endif /* IMAGE_H */ diff --git a/tests/internal/meson.build b/tests/internal/meson.build new file mode 100644 index 0000000000..1afd22be1c --- /dev/null +++ b/tests/internal/meson.build @@ -0,0 +1,74 @@ +libdecutils_sources = [ + 'decoder.c', + 'test-h264.c', + 'test-jpeg.c', + 'test-mpeg2.c', + 'test-mpeg4.c', + 'test-vc1.c', +] + +libdecutils_headers = [ + 'decoder.h', + 'test-h264.h', + 'test-jpeg.h', + 'test-mpeg2.h', + 'test-mpeg4.h', + 'test-vc1.h', +] + +libutils_sources = [ + 'codec.c', + 'image.c', + 'output.c', + 'test-subpicture-data.c', + 'y4mreader.c', +] + +libutils_headers = [ + 'codec.h', + 'image.h', + 'output.h', + 'test-subpicture-data.h', + 'y4mreader.h', +] + +test_examples = [ + 'simple-decoder', + 'test-decode', + 'test-display', + 'test-filter', + 'test-surfaces', + 'test-windows', + 'test-subpicture', +] + +if USE_ENCODERS + test_examples += [ 'simple-encoder' ] +endif + +if USE_GLX + test_examples += [ 'test-textures' ] +endif + +libutils = static_library('libutils', + libutils_sources + libutils_headers, + c_args : gstreamer_vaapi_args, + include_directories: [configinc, libsinc], + dependencies : gstlibvaapi_deps, + install: false) + +libdecutils = static_library('libdecutils', + libdecutils_sources + libdecutils_headers, + c_args : gstreamer_vaapi_args, + include_directories: [configinc, libsinc], + dependencies : gstlibvaapi_deps, + install: false) + +foreach example : test_examples + executable(example, '@0@.c'.format(example), + c_args : gstreamer_vaapi_args, + include_directories: [configinc, libsinc], + dependencies : [gst_dep, libva_dep, gstlibvaapi_dep], + link_with: [libutils, libdecutils], + install: false) +endforeach diff --git a/tests/internal/output.c b/tests/internal/output.c new file mode 100644 index 0000000000..2182d5ab0d --- /dev/null +++ b/tests/internal/output.c @@ -0,0 +1,227 @@ +/* + * output.c - Video output helpers + * + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gst/vaapi/sysdeps.h" +#include +#if USE_DRM +# include +# include +#endif +#if USE_X11 +# include +# include +#endif +#if USE_GLX +# include +# include +#endif +#if USE_EGL +# include +# include +#endif +#if USE_WAYLAND +# include +# include +#endif +#include "output.h" + +static const VideoOutputInfo *g_video_output; +static const VideoOutputInfo g_video_outputs[] = { + /* Video outputs are sorted in test order for automatic characterisation */ +#if USE_WAYLAND + {"wayland", + gst_vaapi_display_wayland_new, + gst_vaapi_window_wayland_new}, +#endif +#if USE_X11 + {"x11", + gst_vaapi_display_x11_new, + gst_vaapi_window_x11_new}, +#endif +#if USE_GLX + {"glx", + gst_vaapi_display_glx_new, + gst_vaapi_window_glx_new}, +#endif +#if USE_DRM + {"drm", + gst_vaapi_display_drm_new, + gst_vaapi_window_drm_new}, +#endif + {NULL,} +}; + +static gchar *g_output_name; +static gboolean g_list_outputs = FALSE; +static gboolean g_fullscreen = FALSE; + +static gboolean g_egl_mode = FALSE; +static guint g_gles_version; + +static GOptionEntry g_options[] = { + {"list-outputs", 0, + 0, + G_OPTION_ARG_NONE, &g_list_outputs, + "list video outputs", NULL}, + {"output", 'o', + 0, + G_OPTION_ARG_STRING, &g_output_name, + "video output name", NULL}, + {"fullscreen", 'f', + 0, + G_OPTION_ARG_NONE, &g_fullscreen, + "fullscreen mode", NULL}, + {"egl", 0, + 0, + G_OPTION_ARG_NONE, &g_egl_mode, + "enable EGL rendering", NULL}, + {"gles-version", 0, + 0, + G_OPTION_ARG_INT, &g_gles_version, + "OpenGL|ES version (in --egl mode)", NULL}, + {NULL,} +}; + +static void +list_outputs (void) +{ + const VideoOutputInfo *o; + + g_print ("Video outputs:"); + for (o = g_video_outputs; o->name != NULL; o++) + g_print (" %s", o->name); + g_print ("\n"); +} + +gboolean +video_output_init (int *argc, char *argv[], GOptionEntry * options) +{ + GOptionContext *ctx; + gboolean success; + + ctx = g_option_context_new ("- test options"); + if (!ctx) + return FALSE; + + g_option_context_add_group (ctx, gst_init_get_option_group ()); + g_option_context_add_main_entries (ctx, g_options, NULL); + if (options) + g_option_context_add_main_entries (ctx, options, NULL); + success = g_option_context_parse (ctx, argc, &argv, NULL); + g_option_context_free (ctx); + + if (g_list_outputs) { + list_outputs (); + exit (0); + } + return success; +} + +void +video_output_exit (void) +{ + g_free (g_output_name); + gst_deinit (); +} + +const VideoOutputInfo * +video_output_lookup (const gchar * output_name) +{ + const VideoOutputInfo *o; + + if (!output_name) + return NULL; + + for (o = g_video_outputs; o->name != NULL; o++) { + if (g_ascii_strcasecmp (o->name, output_name) == 0) + return o; + } + return NULL; +} + +GstVaapiDisplay * +video_output_create_display (const gchar * display_name) +{ + const VideoOutputInfo *o = g_video_output; + GstVaapiDisplay *egl_display, *display = NULL; + + if (!o) { + if (g_output_name) + o = video_output_lookup (g_output_name); + else { + for (o = g_video_outputs; o->name != NULL; o++) { + display = o->create_display (display_name); + if (display) { + if (gst_vaapi_display_get_display (display)) + break; + gst_object_unref (display); + display = NULL; + } + } + } + if (!o || !o->name) + return NULL; + g_print ("Using %s video output\n", o->name); + g_video_output = o; + } + + if (!display) + display = o->create_display (display_name); + + if (g_egl_mode) { +#if USE_EGL + egl_display = gst_vaapi_display_egl_new (display, g_gles_version); +#else + egl_display = NULL; + g_print ("error: unsupported EGL renderering mode\n"); +#endif + gst_object_unref (display); + if (!egl_display) + return NULL; + display = egl_display; + } + return display; +} + +GstVaapiWindow * +video_output_create_window (GstVaapiDisplay * display, guint width, + guint height) +{ + GstVaapiWindow *window; + + if (!g_video_output) + return NULL; + +#if USE_EGL + if (g_egl_mode) + window = gst_vaapi_window_egl_new (display, width, height); + else +#endif + window = g_video_output->create_window (display, width, height); + if (!window) + return NULL; + + /* Force fullscreen mode, should this be requested by the user */ + if (g_fullscreen) + gst_vaapi_window_set_fullscreen (window, TRUE); + return window; +} diff --git a/tests/internal/output.h b/tests/internal/output.h new file mode 100644 index 0000000000..69299157f5 --- /dev/null +++ b/tests/internal/output.h @@ -0,0 +1,56 @@ +/* + * output.h - Video output helpers + * + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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 OUTPUT_H +#define OUTPUT_H + +#include +#include +#include + +typedef GstVaapiDisplay *(*CreateDisplayFunc)(const gchar *display_name); +typedef GstVaapiWindow *(*CreateWindowFunc)(GstVaapiDisplay *display, + guint width, guint height); + +typedef struct _VideoOutputInfo VideoOutputInfo; +struct _VideoOutputInfo { + const gchar *name; + CreateDisplayFunc create_display; + CreateWindowFunc create_window; +}; + +gboolean +video_output_init(int *argc, char *argv[], GOptionEntry *options); + +void +video_output_exit(void); + +const VideoOutputInfo * +video_output_lookup(const gchar *output_name); + +GstVaapiDisplay * +video_output_create_display(const gchar *display_name); + +GstVaapiWindow * +video_output_create_window(GstVaapiDisplay *display, guint width, guint height); + +#endif /* OUTPUT_H */ diff --git a/tests/internal/simple-decoder.c b/tests/internal/simple-decoder.c new file mode 100644 index 0000000000..7575276729 --- /dev/null +++ b/tests/internal/simple-decoder.c @@ -0,0 +1,691 @@ +/* + * simple-decoder.c - Simple Decoder Application + * + * Copyright (C) 2013-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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 + */ + +/* + * This is a really simple decoder application that only accepts raw + * bitstreams. So, it may be needed to suggest what codec to use to + * the application. + */ + +#include "gst/vaapi/sysdeps.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "codec.h" +#include "output.h" + +static gchar *g_codec_str; +static gboolean g_benchmark; + +static GOptionEntry g_options[] = { + {"codec", 'c', + 0, + G_OPTION_ARG_STRING, &g_codec_str, + "suggested codec", NULL}, + {"benchmark", 0, + 0, + G_OPTION_ARG_NONE, &g_benchmark, + "benchmark mode", NULL}, + {NULL,} +}; + +typedef enum +{ + APP_RUNNING, + APP_GOT_EOS, + APP_GOT_ERROR, +} AppEvent; + +typedef enum +{ + APP_ERROR_NONE, + APP_ERROR_DECODER, + APP_ERROR_RENDERER, +} AppError; + +typedef struct +{ + GstVaapiSurfaceProxy *proxy; + GstClockTime pts; + GstClockTime duration; +} RenderFrame; + +typedef struct +{ + GMutex mutex; + GMappedFile *file; + gchar *file_name; + guint file_offset; + guint file_size; + guchar *file_data; + GstVaapiDisplay *display; + GstVaapiDecoder *decoder; + GThread *decoder_thread; + gboolean decoder_thread_cancel; + GAsyncQueue *decoder_queue; + GstVaapiCodec codec; + guint fps_n; + guint fps_d; + guint32 frame_duration; + guint surface_width; + guint surface_height; + GstVaapiWindow *window; + guint window_width; + guint window_height; + GThread *render_thread; + gboolean render_thread_cancel; + GCond render_ready; + RenderFrame *last_frame; + GError *error; + AppEvent event; + GCond event_cond; + GTimer *timer; + guint32 num_frames; +} App; + +static inline RenderFrame * +render_frame_new (void) +{ + return g_slice_new (RenderFrame); +} + +static void +render_frame_free (RenderFrame * rfp) +{ + if (G_UNLIKELY (!rfp)) + return; + gst_vaapi_surface_proxy_replace (&rfp->proxy, NULL); + g_slice_free (RenderFrame, rfp); +} + +static inline void +render_frame_replace (RenderFrame ** rfp_ptr, RenderFrame * new_rfp) +{ + if (*rfp_ptr) + render_frame_free (*rfp_ptr); + *rfp_ptr = new_rfp; +} + +#define APP_ERROR app_error_quark() +static GQuark +app_error_quark (void) +{ + static gsize g_quark; + + if (g_once_init_enter (&g_quark)) { + gsize quark = (gsize) g_quark_from_static_string ("AppError"); + g_once_init_leave (&g_quark, quark); + } + return g_quark; +} + +static void +app_send_error (App * app, GError * error) +{ + g_mutex_lock (&app->mutex); + app->error = error; + app->event = APP_GOT_ERROR; + g_cond_signal (&app->event_cond); + g_mutex_unlock (&app->mutex); +} + +static void +app_send_eos (App * app) +{ + g_mutex_lock (&app->mutex); + app->event = APP_GOT_EOS; + g_cond_signal (&app->event_cond); + g_mutex_unlock (&app->mutex); +} + +static const gchar * +get_decoder_status_string (GstVaapiDecoderStatus status) +{ + const gchar *str; + +#define DEFINE_STATUS(status, status_string) \ + case GST_VAAPI_DECODER_STATUS_##status: \ + str = status_string; \ + break + + switch (status) { + DEFINE_STATUS (SUCCESS, ""); + DEFINE_STATUS (END_OF_STREAM, ""); + DEFINE_STATUS (ERROR_ALLOCATION_FAILED, "allocation failed"); + DEFINE_STATUS (ERROR_INIT_FAILED, "initialization failed"); + DEFINE_STATUS (ERROR_UNSUPPORTED_CODEC, "unsupported codec"); + DEFINE_STATUS (ERROR_NO_DATA, "not enough data"); + DEFINE_STATUS (ERROR_NO_SURFACE, "no surface vailable"); + DEFINE_STATUS (ERROR_INVALID_SURFACE, "invalid surface"); + DEFINE_STATUS (ERROR_BITSTREAM_PARSER, "bitstream parser error"); + DEFINE_STATUS (ERROR_UNSUPPORTED_PROFILE, "unsupported profile"); + DEFINE_STATUS (ERROR_UNSUPPORTED_CHROMA_FORMAT, + "unsupported chroma-format"); + DEFINE_STATUS (ERROR_INVALID_PARAMETER, "invalid parameter"); + default: + str = ""; + break; + } +#undef DEFINE_STATUS + + return str; +} + +static const gchar * +get_error_string (AppError error) +{ + const gchar *str; + +#define DEFINE_ERROR(error, error_string) \ + case APP_ERROR_##error: \ + str = error_string; \ + break + + switch (error) { + DEFINE_ERROR (NONE, ""); + DEFINE_ERROR (DECODER, "decoder"); + DEFINE_ERROR (RENDERER, "renderer"); + default: + str = "unknown"; + break; + } +#undef DEFINE_ERROR + + return str; +} + +static gpointer +decoder_thread (gpointer data) +{ + App *const app = data; + GError *error = NULL; + GstVaapiDecoderStatus status; + GstVaapiSurfaceProxy *proxy; + RenderFrame *rfp; + GstBuffer *buffer; + GstClockTime pts; + gboolean got_eos = FALSE; + guint ofs; + + g_print ("Decoder thread started\n"); + +#define SEND_ERROR(...) \ + do { \ + error = g_error_new(APP_ERROR, APP_ERROR_DECODER, __VA_ARGS__); \ + goto send_error; \ + } while (0) + + pts = g_get_monotonic_time (); + ofs = 0; + while (!g_atomic_int_get (&app->decoder_thread_cancel)) { + if (G_UNLIKELY (ofs == app->file_size)) + buffer = NULL; + else { + const gsize size = MIN (4096, app->file_size - ofs); + buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, + app->file_data, app->file_size, ofs, size, NULL, NULL); + if (!buffer) + SEND_ERROR ("failed to allocate new buffer"); + ofs += size; + } + if (!gst_vaapi_decoder_put_buffer (app->decoder, buffer)) + SEND_ERROR ("failed to push buffer to decoder"); + gst_buffer_replace (&buffer, NULL); + + status = gst_vaapi_decoder_get_surface (app->decoder, &proxy); + switch (status) { + case GST_VAAPI_DECODER_STATUS_SUCCESS: + rfp = render_frame_new (); + if (!rfp) + SEND_ERROR ("failed to allocate render frame"); + rfp->proxy = proxy; + rfp->pts = pts; + rfp->duration = app->frame_duration; + pts += app->frame_duration; + g_async_queue_push (app->decoder_queue, rfp); + break; + case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA: + /* nothing to do, just continue to the next iteration */ + break; + case GST_VAAPI_DECODER_STATUS_END_OF_STREAM: + gst_vaapi_decoder_flush (app->decoder); + if (got_eos) + goto send_eos; + got_eos = TRUE; + break; + default: + SEND_ERROR ("%s", get_decoder_status_string (status)); + break; + } + } + return NULL; + +#undef SEND_ERROR + +send_eos: + app_send_eos (app); + return NULL; + +send_error: + app_send_error (app, error); + return NULL; +} + +static void +app_set_framerate (App * app, guint fps_n, guint fps_d) +{ + if (!fps_n || !fps_d) + return; + + g_mutex_lock (&app->mutex); + if (fps_n != app->fps_n || fps_d != app->fps_d) { + app->fps_n = fps_n; + app->fps_d = fps_d; + app->frame_duration = + gst_util_uint64_scale (GST_TIME_AS_USECONDS (GST_SECOND), fps_d, fps_n); + } + g_mutex_unlock (&app->mutex); +} + +static void +handle_decoder_state_changes (GstVaapiDecoder * decoder, + const GstVideoCodecState * codec_state, gpointer user_data) +{ + App *const app = user_data; + + g_assert (app->decoder == decoder); + app_set_framerate (app, codec_state->info.fps_n, codec_state->info.fps_d); +} + +static gboolean +start_decoder (App * app) +{ + GstCaps *caps; + + app->file = g_mapped_file_new (app->file_name, FALSE, NULL); + if (!app->file) + return FALSE; + + app->file_size = g_mapped_file_get_length (app->file); + app->file_data = (guint8 *) g_mapped_file_get_contents (app->file); + if (!app->file_data) + return FALSE; + + caps = caps_from_codec (app->codec); + switch (app->codec) { + case GST_VAAPI_CODEC_H264: + app->decoder = gst_vaapi_decoder_h264_new (app->display, caps); + break; + case GST_VAAPI_CODEC_JPEG: + app->decoder = gst_vaapi_decoder_jpeg_new (app->display, caps); + break; + case GST_VAAPI_CODEC_MPEG2: + app->decoder = gst_vaapi_decoder_mpeg2_new (app->display, caps); + break; + case GST_VAAPI_CODEC_MPEG4: + app->decoder = gst_vaapi_decoder_mpeg4_new (app->display, caps); + break; + case GST_VAAPI_CODEC_VC1: + app->decoder = gst_vaapi_decoder_vc1_new (app->display, caps); + break; + default: + app->decoder = NULL; + break; + } + if (!app->decoder) + return FALSE; + + gst_vaapi_decoder_set_codec_state_changed_func (app->decoder, + handle_decoder_state_changes, app); + + g_timer_start (app->timer); + + app->decoder_thread = g_thread_try_new ("Decoder Thread", decoder_thread, + app, NULL); + if (!app->decoder_thread) + return FALSE; + return TRUE; +} + +static gboolean +stop_decoder (App * app) +{ + g_timer_stop (app->timer); + + g_atomic_int_set (&app->decoder_thread_cancel, TRUE); + g_thread_join (app->decoder_thread); + g_print ("Decoder thread stopped\n"); + return TRUE; +} + +static void +ensure_window_size (App * app, GstVaapiSurface * surface) +{ + guint width, height; + + if (gst_vaapi_window_get_fullscreen (app->window)) + return; + + gst_vaapi_surface_get_size (surface, &width, &height); + if (app->surface_width == width && app->surface_height == height) + return; + app->surface_width = width; + app->surface_height = height; + + gst_vaapi_window_set_size (app->window, width, height); + gst_vaapi_window_get_size (app->window, + &app->window_width, &app->window_height); +} + +static inline void +renderer_wait_until (App * app, GstClockTime pts) +{ + g_mutex_lock (&app->mutex); + do { + } while (g_cond_wait_until (&app->render_ready, &app->mutex, pts)); + g_mutex_unlock (&app->mutex); +} + +static gboolean +renderer_process (App * app, RenderFrame * rfp) +{ + GError *error = NULL; + GstVaapiSurface *surface; + const GstVaapiRectangle *crop_rect; + +#define SEND_ERROR(...) \ + do { \ + error = g_error_new(APP_ERROR, APP_ERROR_RENDERER, __VA_ARGS__); \ + goto send_error; \ + } while (0) + + surface = gst_vaapi_surface_proxy_get_surface (rfp->proxy); + if (!surface) + SEND_ERROR ("failed to get decoded surface from render frame"); + + ensure_window_size (app, surface); + + crop_rect = gst_vaapi_surface_proxy_get_crop_rect (rfp->proxy); + + if (!gst_vaapi_surface_sync (surface)) + SEND_ERROR ("failed to sync decoded surface"); + + if (G_LIKELY (!g_benchmark)) + renderer_wait_until (app, rfp->pts); + + if (!gst_vaapi_window_put_surface (app->window, surface, + crop_rect, NULL, GST_VAAPI_PICTURE_STRUCTURE_FRAME)) + SEND_ERROR ("failed to render surface %" GST_VAAPI_ID_FORMAT, + GST_VAAPI_ID_ARGS (gst_vaapi_surface_get_id (surface))); + + app->num_frames++; + + render_frame_replace (&app->last_frame, rfp); + return TRUE; + +#undef SEND_ERROR + +send_error: + app_send_error (app, error); + return FALSE; +} + +static gpointer +renderer_thread (gpointer data) +{ + App *const app = data; + RenderFrame *rfp; + + g_print ("Render thread started\n"); + + while (!g_atomic_int_get (&app->render_thread_cancel)) { + rfp = g_async_queue_timeout_pop (app->decoder_queue, 1000000); + if (rfp && !renderer_process (app, rfp)) + break; + } + return NULL; +} + +static gboolean +flush_decoder_queue (App * app) +{ + RenderFrame *rfp; + + /* Flush pending surfaces */ + do { + rfp = g_async_queue_try_pop (app->decoder_queue); + if (!rfp) + return TRUE; + } while (renderer_process (app, rfp)); + return FALSE; +} + +static gboolean +start_renderer (App * app) +{ + app->render_thread = g_thread_try_new ("Renderer Thread", renderer_thread, + app, NULL); + if (!app->render_thread) + return FALSE; + return TRUE; +} + +static gboolean +stop_renderer (App * app) +{ + g_atomic_int_set (&app->render_thread_cancel, TRUE); + g_thread_join (app->render_thread); + + g_print ("Render thread stopped\n"); + + flush_decoder_queue (app); + render_frame_replace (&app->last_frame, NULL); + return TRUE; +} + +static void +app_free (App * app) +{ + if (!app) + return; + + if (app->file) { + g_mapped_file_unref (app->file); + app->file = NULL; + } + g_free (app->file_name); + + gst_vaapi_decoder_replace (&app->decoder, NULL); + gst_vaapi_window_replace (&app->window, NULL); + gst_vaapi_display_replace (&app->display, NULL); + + if (app->decoder_queue) { + g_async_queue_unref (app->decoder_queue); + app->decoder_queue = NULL; + } + + if (app->timer) { + g_timer_destroy (app->timer); + app->timer = NULL; + } + + g_cond_clear (&app->render_ready); + g_cond_clear (&app->event_cond); + g_mutex_clear (&app->mutex); + g_slice_free (App, app); +} + +static App * +app_new (void) +{ + App *app; + + app = g_slice_new0 (App); + if (!app) + return NULL; + + g_mutex_init (&app->mutex); + g_cond_init (&app->event_cond); + g_cond_init (&app->render_ready); + + app_set_framerate (app, 60, 1); + app->window_width = 640; + app->window_height = 480; + + app->decoder_queue = g_async_queue_new_full ( + (GDestroyNotify) render_frame_free); + if (!app->decoder_queue) + goto error; + + app->timer = g_timer_new (); + if (!app->timer) + goto error; + return app; + +error: + app_free (app); + return NULL; +} + +static gboolean +app_check_events (App * app) +{ + GError *error = NULL; + gboolean stop = FALSE; + + do { + g_mutex_lock (&app->mutex); + while (app->event == APP_RUNNING) + g_cond_wait (&app->event_cond, &app->mutex); + + switch (app->event) { + case APP_GOT_ERROR: + error = app->error; + app->error = NULL; + /* fall-through */ + case APP_GOT_EOS: + stop = TRUE; + break; + default: + break; + } + g_mutex_unlock (&app->mutex); + } while (!stop); + + if (!error) + return TRUE; + + g_message ("%s error: %s", get_error_string (error->code), error->message); + g_error_free (error); + return FALSE; +} + +static gboolean +app_run (App * app, int argc, char *argv[]) +{ + if (argc < 2) { + g_message ("no bitstream file specified"); + return FALSE; + } + app->file_name = g_strdup (argv[1]); + + if (!g_file_test (app->file_name, G_FILE_TEST_IS_REGULAR)) { + g_message ("failed to find file '%s'", app->file_name); + return FALSE; + } + + app->codec = identify_codec (app->file_name); + if (!app->codec) { + app->codec = identify_codec_from_string (g_codec_str); + if (!app->codec) { + g_message ("failed to identify codec for '%s'", app->file_name); + return FALSE; + } + } + + g_print ("Simple decoder (%s bitstream)\n", string_from_codec (app->codec)); + + app->display = video_output_create_display (NULL); + if (!app->display) { + g_message ("failed to create VA display"); + return FALSE; + } + + app->window = video_output_create_window (app->display, + app->window_width, app->window_height); + if (!app->window) { + g_message ("failed to create window"); + return FALSE; + } + + gst_vaapi_window_show (app->window); + + if (!start_decoder (app)) { + g_message ("failed to start decoder thread"); + return FALSE; + } + + if (!start_renderer (app)) { + g_message ("failed to start renderer thread"); + return FALSE; + } + + app_check_events (app); + + stop_renderer (app); + stop_decoder (app); + + g_print ("Decoded %u frames", app->num_frames); + if (g_benchmark) { + const gdouble elapsed = g_timer_elapsed (app->timer, NULL); + g_print (" in %.2f sec (%.1f fps)\n", + elapsed, (gdouble) app->num_frames / elapsed); + } + g_print ("\n"); + return TRUE; +} + +int +main (int argc, char *argv[]) +{ + App *app; + gint ret; + + if (!video_output_init (&argc, argv, g_options)) + g_error ("failed to initialize video output subsystem"); + + app = app_new (); + if (!app) + g_error ("failed to create application context"); + + ret = !app_run (app, argc, argv); + + app_free (app); + g_free (g_codec_str); + video_output_exit (); + return ret; +} diff --git a/tests/internal/simple-encoder.c b/tests/internal/simple-encoder.c new file mode 100644 index 0000000000..90b778e35b --- /dev/null +++ b/tests/internal/simple-encoder.c @@ -0,0 +1,499 @@ +/* + * simple-encoder.c - Test GstVaapiencoder + * + * Copyright (C) 2015 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gst/vaapi/sysdeps.h" +#include +#include +#include +#include + +#include "output.h" +#include "y4mreader.h" + +static guint g_bitrate = 0; +static gchar *g_codec_str; +static gchar *g_output_file_name; +static char **g_input_files = NULL; + +#define SURFACE_NUM 16 + +static GOptionEntry g_options[] = { + {"codec", 'c', 0, G_OPTION_ARG_STRING, &g_codec_str, + "codec to use for video encoding (h264/mpeg2)", NULL}, + {"bitrate", 'b', 0, G_OPTION_ARG_INT, &g_bitrate, + "desired bitrate expressed in kbps", NULL}, + {"output", 'o', 0, G_OPTION_ARG_FILENAME, &g_output_file_name, + "output file name", NULL}, + {G_OPTION_REMAINING, ' ', 0, G_OPTION_ARG_FILENAME_ARRAY, &g_input_files, + "input file name", NULL}, + {NULL} +}; + +typedef struct +{ + GstVaapiDisplay *display; + GstVaapiEncoder *encoder; + guint read_frames; + guint encoded_frames; + guint saved_frames; + Y4MReader *parser; + FILE *output_file; + guint input_stopped:1; + guint encode_failed:1; +} App; + +static inline gchar * +generate_output_filename (const gchar * ext) +{ + gchar *fn; + int i = 0; + + while (1) { + fn = g_strdup_printf ("temp%02d.%s", i, ext); + if (g_file_test (fn, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) { + i++; + g_free (fn); + } else { + break; + } + } + + return fn; +} + +static gboolean +parse_options (int *argc, char *argv[]) +{ + GOptionContext *ctx; + gboolean success; + GError *error = NULL; + + ctx = g_option_context_new (" - encoder test options"); + if (!ctx) + return FALSE; + + g_option_context_add_group (ctx, gst_init_get_option_group ()); + g_option_context_add_main_entries (ctx, g_options, NULL); + g_option_context_set_help_enabled (ctx, TRUE); + success = g_option_context_parse (ctx, argc, &argv, &error); + if (!success) { + g_printerr ("Option parsing failed: %s\n", error->message); + g_error_free (error); + goto bail; + } + + if (!g_codec_str) + g_codec_str = g_strdup ("h264"); + if (!g_output_file_name) + g_output_file_name = generate_output_filename (g_codec_str); + +bail: + g_option_context_free (ctx); + return success; +} + +static void +print_yuv_info (App * app) +{ + g_print ("\n"); + g_print ("Encode : %s\n", g_codec_str); + g_print ("Resolution : %dx%d\n", app->parser->width, app->parser->height); + g_print ("Source YUV : %s\n", g_input_files ? g_input_files[0] : "stdin"); + g_print ("Frame Rate : %0.1f fps\n", + 1.0 * app->parser->fps_n / app->parser->fps_d); + g_print ("Coded file : %s\n", g_output_file_name); + g_print ("\n"); +} + +static void +print_num_frame (App * app) +{ + g_print ("\n"); + g_print ("read frames : %d\n", app->read_frames); + g_print ("encoded frames : %d\n", app->encoded_frames); + g_print ("saved frames : %d\n", app->saved_frames); + g_print ("\n"); +} + +static GstVaapiEncoder * +encoder_new (GstVaapiDisplay * display) +{ + GstVaapiEncoder *encoder = NULL; + + if (!g_strcmp0 (g_codec_str, "mpeg2")) + encoder = gst_vaapi_encoder_mpeg2_new (display); + else if (!g_strcmp0 (g_codec_str, "h264")) + encoder = gst_vaapi_encoder_h264_new (display); + else + return NULL; + + gst_vaapi_encoder_set_bitrate (encoder, g_bitrate); + + return encoder; +} + +static inline GstVideoCodecState * +new_codec_state (gint width, gint height, gint fps_n, gint fps_d) +{ + GstVideoCodecState *state; + + state = g_slice_new0 (GstVideoCodecState); + state->ref_count = 1; + gst_video_info_set_format (&state->info, GST_VIDEO_FORMAT_ENCODED, width, + height); + + state->info.fps_n = fps_n; + state->info.fps_d = fps_d; + + return state; +} + +static gboolean +set_format (GstVaapiEncoder * encoder, gint width, gint height, gint fps_n, + gint fps_d) +{ + GstVideoCodecState *in_state; + GstVaapiEncoderStatus status; + + in_state = new_codec_state (width, height, fps_n, fps_d); + status = gst_vaapi_encoder_set_codec_state (encoder, in_state); + g_slice_free (GstVideoCodecState, in_state); + + return (status == GST_VAAPI_ENCODER_STATUS_SUCCESS); +} + +static GstBuffer * +allocate_buffer (GstVaapiCodedBuffer * vbuf) +{ + GstBuffer *buf; + gssize size; + + size = gst_vaapi_coded_buffer_get_size (vbuf); + if (size <= 0) { + g_warning ("Invalid VA buffer size (%zd)", size); + return NULL; + } + + buf = gst_buffer_new_and_alloc (size); + if (!buf) { + g_warning ("Failed to create output buffer of size %zd", size); + return NULL; + } + + if (!gst_vaapi_coded_buffer_copy_into (buf, vbuf)) { + g_warning ("Failed to copy VA buffer data"); + gst_buffer_unref (buf); + return NULL; + } + + return buf; +} + +static GstVaapiEncoderStatus +get_encoder_buffer (GstVaapiEncoder * encoder, GstBuffer ** buffer) +{ + GstVaapiCodedBufferProxy *proxy = NULL; + GstVaapiEncoderStatus status; + + status = gst_vaapi_encoder_get_buffer_with_timeout (encoder, &proxy, 50000); + if (status < GST_VAAPI_ENCODER_STATUS_SUCCESS) { + g_warning ("Failed to get a buffer from encoder: %d", status); + return status; + } else if (status > GST_VAAPI_ENCODER_STATUS_SUCCESS) { + return status; + } + + *buffer = allocate_buffer (GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (proxy)); + gst_vaapi_coded_buffer_proxy_unref (proxy); + + return status; +} + +static gboolean +outputs_to_file (GstBuffer * buffer, FILE * file) +{ + GstMapInfo info; + size_t written; + gboolean ret = FALSE; + + if (!gst_buffer_map (buffer, &info, GST_MAP_READ)) + return FALSE; + + if (info.size <= 0 || !info.data) + return FALSE; + + written = fwrite (info.data, 1, info.size, file); + if (written < info.size) { + g_warning ("write file error."); + goto bail; + } + + ret = TRUE; + +bail: + gst_buffer_unmap (buffer, &info); + return ret; +} + +static gpointer +get_buffer_thread (gpointer data) +{ + App *app = data; + + GstVaapiEncoderStatus ret; + GstBuffer *obuf; + + while (1) { + obuf = NULL; + ret = get_encoder_buffer (app->encoder, &obuf); + if (app->input_stopped && ret > GST_VAAPI_ENCODER_STATUS_SUCCESS) { + break; /* finished */ + } else if (ret > GST_VAAPI_ENCODER_STATUS_SUCCESS) { /* another chance */ + continue; + } + if (ret < GST_VAAPI_ENCODER_STATUS_SUCCESS) { /* fatal error */ + app->encode_failed = TRUE; + break; + } + + app->encoded_frames++; + g_debug ("encoded frame %d, buffer = %p", app->encoded_frames, obuf); + + if (app->output_file && outputs_to_file (obuf, app->output_file)) + app->saved_frames++; + + gst_buffer_unref (obuf); + } + + if (obuf) + gst_buffer_replace (&obuf, NULL); + + return NULL; +} + +static void +app_free (App * app) +{ + g_return_if_fail (app); + + if (app->parser) + y4m_reader_close (app->parser); + + if (app->encoder) { + gst_vaapi_encoder_flush (app->encoder); + gst_object_unref (app->encoder); + } + + if (app->display) + gst_object_unref (app->display); + + if (app->output_file) + fclose (app->output_file); + + g_slice_free (App, app); +} + +static App * +app_new (const gchar * input_fn, const gchar * output_fn) +{ + App *app = g_slice_new0 (App); + if (!app) + return NULL; + + app->parser = y4m_reader_open (input_fn); + if (!app->parser) { + g_warning ("Could not parse input stream."); + goto error; + } + + app->output_file = fopen (output_fn, "w"); + if (app->output_file == NULL) { + g_warning ("Could not open file \"%s\" for writing: %s.", output_fn, + g_strerror (errno)); + goto error; + } + + app->display = video_output_create_display (NULL); + if (!app->display) { + g_warning ("Could not create VA display."); + goto error; + } + + app->encoder = encoder_new (app->display); + if (!app->encoder) { + g_warning ("Could not create encoder."); + goto error; + } + + if (!set_format (app->encoder, app->parser->width, app->parser->height, + app->parser->fps_n, app->parser->fps_d)) { + g_warning ("Could not set format."); + goto error; + } + + return app; + +error: + app_free (app); + return NULL; +} + +static gboolean +upload_frame (GstVaapiEncoder * encoder, GstVaapiSurfaceProxy * proxy) +{ + GstVideoCodecFrame *frame; + GstVaapiEncoderStatus ret; + + frame = g_slice_new0 (GstVideoCodecFrame); + gst_video_codec_frame_set_user_data (frame, + gst_vaapi_surface_proxy_ref (proxy), + (GDestroyNotify) gst_vaapi_surface_proxy_unref); + + ret = gst_vaapi_encoder_put_frame (encoder, frame); + return (ret == GST_VAAPI_ENCODER_STATUS_SUCCESS); +} + +static gboolean +load_frame (App * app, GstVaapiImage * image) +{ + gboolean ret = FALSE; + + if (!gst_vaapi_image_map (image)) + return FALSE; + + ret = y4m_reader_load_image (app->parser, image); + + if (!gst_vaapi_image_unmap (image)) + return FALSE; + + return ret; +} + +static int +app_run (App * app) +{ + GstVaapiImage *image; + GstVaapiVideoPool *pool; + GThread *buffer_thread; + gsize id; + int ret = EXIT_FAILURE; + + image = gst_vaapi_image_new (app->display, GST_VIDEO_FORMAT_I420, + app->parser->width, app->parser->height); + + { + GstVideoInfo vi; + gst_video_info_set_format (&vi, GST_VIDEO_FORMAT_ENCODED, + app->parser->width, app->parser->height); + pool = gst_vaapi_surface_pool_new_full (app->display, &vi, 0); + } + + buffer_thread = g_thread_new ("get buffer thread", get_buffer_thread, app); + + while (1) { + GstVaapiSurfaceProxy *proxy; + GstVaapiSurface *surface; + + if (!load_frame (app, image)) + break; + + if (!gst_vaapi_image_unmap (image)) + break; + + proxy = + gst_vaapi_surface_proxy_new_from_pool (GST_VAAPI_SURFACE_POOL (pool)); + if (!proxy) { + g_warning ("Could not get surface proxy from pool."); + break; + } + surface = gst_vaapi_surface_proxy_get_surface (proxy); + if (!surface) { + g_warning ("Could not get surface from proxy."); + break; + } + + if (!gst_vaapi_surface_put_image (surface, image)) { + g_warning ("Could not update surface"); + break; + } + + if (!upload_frame (app->encoder, proxy)) { + g_warning ("put frame failed"); + break; + } + + app->read_frames++; + id = gst_vaapi_surface_get_id (surface); + g_debug ("input frame %d, surface id = %" G_GSIZE_FORMAT, app->read_frames, + id); + + gst_vaapi_surface_proxy_unref (proxy); + } + + app->input_stopped = TRUE; + + g_thread_join (buffer_thread); + + if (!app->encode_failed && feof (app->parser->fp)) + ret = EXIT_SUCCESS; + + gst_vaapi_video_pool_replace (&pool, NULL); + gst_vaapi_image_unref (image); + return ret; +} + +int +main (int argc, char *argv[]) +{ + App *app; + int ret = EXIT_FAILURE; + gchar *input_fn; + + if (!parse_options (&argc, argv)) + return EXIT_FAILURE; + + /* @TODO: iterate all the input files */ + input_fn = g_input_files ? g_input_files[0] : NULL; + if (input_fn && !g_file_test (input_fn, + G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) { + g_warning ("input file \"%s\" doesn't exist", input_fn); + goto bail; + } + + app = app_new (input_fn, g_output_file_name); + if (!app) + goto bail; + + print_yuv_info (app); + ret = app_run (app); + print_num_frame (app); + + app_free (app); + +bail: + g_free (g_codec_str); + g_free (g_output_file_name); + g_strfreev (g_input_files); + + gst_deinit (); + + return ret; +} diff --git a/tests/internal/test-decode.c b/tests/internal/test-decode.c new file mode 100644 index 0000000000..3940e716aa --- /dev/null +++ b/tests/internal/test-decode.c @@ -0,0 +1,115 @@ +/* + * test-decode.c - Test GstVaapiDecoder + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gst/vaapi/sysdeps.h" +#include +#include "decoder.h" +#include "output.h" + +/* Set to 1 to check display cache works (shared VA display) */ +#define CHECK_DISPLAY_CACHE 1 + +static inline void +pause (void) +{ + g_print ("Press any key to continue...\n"); + getchar (); +} + +static gchar *g_codec_str; + +static GOptionEntry g_options[] = { + {"codec", 'c', + 0, + G_OPTION_ARG_STRING, &g_codec_str, + "codec to test", NULL}, + {NULL,} +}; + +int +main (int argc, char *argv[]) +{ + GstVaapiDisplay *display, *display2; + GstVaapiWindow *window; + GstVaapiDecoder *decoder; + GstVaapiSurfaceProxy *proxy; + GstVaapiSurface *surface; + const GstVaapiRectangle *crop_rect; + + static const guint win_width = 640; + static const guint win_height = 480; + + if (!video_output_init (&argc, argv, g_options)) + g_error ("failed to initialize video output subsystem"); + + g_print ("Test decode\n"); + + display = video_output_create_display (NULL); + if (!display) + g_error ("could not create VA display"); + + if (CHECK_DISPLAY_CACHE) + display2 = video_output_create_display (NULL); + else + display2 = gst_object_ref (display); + if (!display2) + g_error ("could not create second VA display"); + + window = video_output_create_window (display, win_width, win_height); + if (!window) + g_error ("could not create window"); + + decoder = decoder_new (display, g_codec_str); + if (!decoder) + g_error ("could not create decoder"); + + g_print ("Decode %s sample frame\n", decoder_get_codec_name (decoder)); + + if (!decoder_put_buffers (decoder)) + g_error ("could not fill decoder with sample data"); + + proxy = decoder_get_surface (decoder); + if (!proxy) + g_error ("could not get decoded surface"); + + surface = gst_vaapi_surface_proxy_get_surface (proxy); + crop_rect = gst_vaapi_surface_proxy_get_crop_rect (proxy); + + gst_vaapi_window_show (window); + + if (!gst_vaapi_window_put_surface (window, surface, crop_rect, NULL, + GST_VAAPI_PICTURE_STRUCTURE_FRAME)) + g_error ("could not render surface"); + + pause (); + + gst_vaapi_surface_proxy_unref (proxy); + gst_object_unref (decoder); + gst_object_unref (window); + gst_object_unref (display); + gst_object_unref (display2); + g_free (g_codec_str); + video_output_exit (); + return 0; +} diff --git a/tests/internal/test-decode.h b/tests/internal/test-decode.h new file mode 100644 index 0000000000..fbe46a6dd3 --- /dev/null +++ b/tests/internal/test-decode.h @@ -0,0 +1,38 @@ +/* + * test-decode.h - Test GstVaapiDecoder + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * + * 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 TEST_DECODE_H +#define TEST_DECODE_H + +#include +#include + +typedef struct _VideoDecodeInfo VideoDecodeInfo; +struct _VideoDecodeInfo { + GstVaapiProfile profile; + guint width; + guint height; + const guchar *data; + guint data_size; +}; + +#endif /* TEST_DECODE_H */ diff --git a/tests/internal/test-display.c b/tests/internal/test-display.c new file mode 100644 index 0000000000..e9ec12604a --- /dev/null +++ b/tests/internal/test-display.c @@ -0,0 +1,426 @@ +/* + * test-display.c - Test GstVaapiDisplayX11 + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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 + */ + +#define _GNU_SOURCE +#include "gst/vaapi/sysdeps.h" +#include +#if USE_DRM +# include +# include +# include +# include +# ifndef DRM_DEVICE_PATH +# define DRM_DEVICE_PATH "/dev/dri/card0" +# endif +#endif +#if USE_X11 +# include +#endif +#if USE_GLX +# include +#endif +#if USE_WAYLAND +# include +#endif +#if USE_EGL +# include +#endif + +#ifdef HAVE_VA_VA_GLX_H +# include +#endif + +static void +print_value (const GValue * value, const gchar * name) +{ + gchar *value_string; + + value_string = g_strdup_value_contents (value); + if (!value_string) + return; + g_print (" %s: %s\n", name, value_string); + g_free (value_string); +} + +static void +print_profiles (GArray * profiles, const gchar * name) +{ + GstVaapiCodec codec; + const gchar *codec_name, *profile_name; + guint i; + + g_print ("%u %s caps\n", profiles->len, name); + + for (i = 0; i < profiles->len; i++) { + const GstVaapiProfile profile = + g_array_index (profiles, GstVaapiProfile, i); + + codec = gst_vaapi_profile_get_codec (profile); + if (!codec) + continue; + + codec_name = gst_vaapi_codec_get_name (codec); + if (!codec_name) + continue; + + profile_name = gst_vaapi_profile_get_va_name (profile); + if (!profile_name) + continue; + + g_print (" %s: %s profile\n", codec_name, profile_name); + } +} + +static void +print_format_yuv (const VAImageFormat * va_format) +{ + const guint32 fourcc = va_format->fourcc; + + g_print (" fourcc '%c%c%c%c'", + fourcc & 0xff, + (fourcc >> 8) & 0xff, (fourcc >> 16) & 0xff, (fourcc >> 24) & 0xff); +} + +static void +print_format_rgb (const VAImageFormat * va_format) +{ + g_print (" %d bits per pixel, %s endian,", + va_format->bits_per_pixel, + va_format->byte_order == VA_MSB_FIRST ? "big" : "little"); + g_print (" %s masks", va_format->alpha_mask ? "rgba" : "rgb"); + g_print (" 0x%08x 0x%08x 0x%08x", + va_format->red_mask, va_format->green_mask, va_format->blue_mask); + if (va_format->alpha_mask) + g_print (" 0x%08x", va_format->alpha_mask); +} + +static void +print_formats (GArray * formats, const gchar * name) +{ + guint i; + + g_print ("%u %s caps\n", formats->len, name); + + for (i = 0; i < formats->len; i++) { + const GstVideoFormat format = g_array_index (formats, GstVideoFormat, i); + const VAImageFormat *va_format; + + g_print (" %s:", gst_vaapi_video_format_to_string (format)); + + va_format = gst_vaapi_video_format_to_va_format (format); + if (!va_format) + g_error ("could not determine VA format"); + + if (gst_vaapi_video_format_is_yuv (format)) + print_format_yuv (va_format); + else + print_format_rgb (va_format); + g_print ("\n"); + } +} + +static void +dump_properties (GstVaapiDisplay * display) +{ + GParamSpec **properties; + guint i, n_properties; + + properties = + g_object_class_list_properties (G_OBJECT_GET_CLASS (display), + &n_properties); + + for (i = 0; i < n_properties; i++) { + const gchar *const name = g_param_spec_get_nick (properties[i]); + GValue value = G_VALUE_INIT; + + if (!gst_vaapi_display_has_property (display, name)) + continue; + + g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (properties[i])); + g_object_get_property (G_OBJECT (display), name, &value); + print_value (&value, name); + } + + g_free (properties); +} + +static void +dump_info (GstVaapiDisplay * display) +{ + GArray *profiles, *formats; + + profiles = gst_vaapi_display_get_decode_profiles (display); + if (!profiles) + g_error ("could not get VA decode profiles"); + + print_profiles (profiles, "decoders"); + g_array_unref (profiles); + + profiles = gst_vaapi_display_get_encode_profiles (display); + if (!profiles) + g_error ("could not get VA encode profiles"); + + print_profiles (profiles, "encoders"); + g_array_unref (profiles); + + formats = gst_vaapi_display_get_image_formats (display); + if (!formats) + g_error ("could not get VA image formats"); + + print_formats (formats, "image"); + g_array_unref (formats); + + formats = gst_vaapi_display_get_subpicture_formats (display); + if (!formats) + g_error ("could not get VA subpicture formats"); + + print_formats (formats, "subpicture"); + g_array_unref (formats); + + dump_properties (display); +} + +int +main (int argc, char *argv[]) +{ + GstVaapiDisplay *display; +#if USE_GLX || USE_WAYLAND + guint width, height; + guint par_n, par_d; +#endif + + gst_init (&argc, &argv); + +#if USE_DRM + g_print ("#\n"); + g_print ("# Create display with gst_vaapi_display_drm_new()\n"); + g_print ("#\n"); + { + display = gst_vaapi_display_drm_new (NULL); + if (!display) + g_error ("could not create Gst/VA display"); + + dump_info (display); + gst_object_unref (display); + } + g_print ("\n"); + + g_print ("#\n"); + g_print ("# Create display with gst_vaapi_display_drm_new_with_device()\n"); + g_print ("#\n"); + { + int drm_device; + + drm_device = open (DRM_DEVICE_PATH, O_RDWR | O_CLOEXEC); + if (drm_device < 0) + g_error ("could not open DRM device"); + + display = gst_vaapi_display_drm_new_with_device (drm_device); + if (!display) + g_error ("could not create Gst/VA display"); + + dump_info (display); + gst_object_unref (display); + close (drm_device); + } + g_print ("\n"); + + g_print ("#\n"); + g_print + ("# Create display with gst_vaapi_display_new_with_display() [vaGetDisplayDRM()]\n"); + g_print ("#\n"); + { + int drm_device; + VADisplay va_display; + + drm_device = open (DRM_DEVICE_PATH, O_RDWR | O_CLOEXEC); + if (drm_device < 0) + g_error ("could not open DRM device"); + + va_display = vaGetDisplayDRM (drm_device); + if (!va_display) + g_error ("could not create VA display"); + + display = gst_vaapi_display_new_with_display (va_display); + if (!display) + g_error ("could not create Gst/VA display"); + + dump_info (display); + gst_object_unref (display); + close (drm_device); + } + g_print ("\n"); +#endif + +#if USE_X11 + g_print ("#\n"); + g_print ("# Create display with gst_vaapi_display_x11_new()\n"); + g_print ("#\n"); + { + display = gst_vaapi_display_x11_new (NULL); + if (!display) + g_error ("could not create Gst/VA display"); + } + g_print ("\n"); + + g_print ("#\n"); + g_print ("# Create display with gst_vaapi_display_x11_new_with_display()\n"); + g_print ("#\n"); + { + Display *x11_display; + + x11_display = XOpenDisplay (NULL); + if (!x11_display) + g_error ("could not create X11 display"); + + display = gst_vaapi_display_x11_new_with_display (x11_display); + if (!display) + g_error ("could not create Gst/VA display"); + + dump_info (display); + gst_object_unref (display); + XCloseDisplay (x11_display); + } + g_print ("\n"); + + g_print ("#\n"); + g_print + ("# Create display with gst_vaapi_display_new_with_display() [vaGetDisplay()]\n"); + g_print ("#\n"); + { + Display *x11_display; + VADisplay va_display; + + x11_display = XOpenDisplay (NULL); + if (!x11_display) + g_error ("could not create X11 display"); + + va_display = vaGetDisplay (x11_display); + if (!va_display) + g_error ("could not create VA display"); + + display = gst_vaapi_display_new_with_display (va_display); + if (!display) + g_error ("could not create Gst/VA display"); + + dump_info (display); + gst_object_unref (display); + XCloseDisplay (x11_display); + } + g_print ("\n"); +#endif + +#if USE_GLX + g_print ("#\n"); + g_print ("# Create display with gst_vaapi_display_glx_new()\n"); + g_print ("#\n"); + { + display = gst_vaapi_display_glx_new (NULL); + if (!display) + g_error ("could not create Gst/VA display"); + + gst_vaapi_display_get_size (display, &width, &height); + g_print ("Display size: %ux%u\n", width, height); + + gst_vaapi_display_get_pixel_aspect_ratio (display, &par_n, &par_d); + g_print ("Pixel aspect ratio: %u/%u\n", par_n, par_d); + + dump_info (display); + gst_object_unref (display); + } + g_print ("\n"); + + g_print ("#\n"); + g_print ("# Create display with gst_vaapi_display_glx_new_with_display()\n"); + g_print ("#\n"); + { + Display *x11_display; + + x11_display = XOpenDisplay (NULL); + if (!x11_display) + g_error ("could not create X11 display"); + + display = gst_vaapi_display_glx_new_with_display (x11_display); + if (!display) + g_error ("could not create Gst/VA display"); + + dump_info (display); + gst_object_unref (display); + XCloseDisplay (x11_display); + } + g_print ("\n"); + +#ifdef HAVE_VA_VA_GLX_H + g_print ("#\n"); + g_print + ("# Create display with gst_vaapi_display_new_with_display() [vaGetDisplayGLX()]\n"); + g_print ("#\n"); + { + Display *x11_display; + VADisplay va_display; + + x11_display = XOpenDisplay (NULL); + if (!x11_display) + g_error ("could not create X11 display"); + + va_display = vaGetDisplayGLX (x11_display); + if (!va_display) + g_error ("could not create VA display"); + + display = gst_vaapi_display_new_with_display (va_display); + if (!display) + g_error ("could not create Gst/VA display"); + + dump_info (display); + gst_object_unref (display); + XCloseDisplay (x11_display); + } + g_print ("\n"); +#endif +#endif + +#if USE_WAYLAND + g_print ("#\n"); + g_print ("# Create display with gst_vaapi_display_wayland_new()\n"); + g_print ("#\n"); + { + display = gst_vaapi_display_wayland_new (NULL); + if (!display) + g_error ("could not create Gst/VA display"); + + gst_vaapi_display_get_size (display, &width, &height); + g_print ("Display size: %ux%u\n", width, height); + + gst_vaapi_display_get_pixel_aspect_ratio (display, &par_n, &par_d); + g_print ("Pixel aspect ratio: %u/%u\n", par_n, par_d); + + dump_info (display); + gst_object_unref (display); + } + g_print ("\n"); +#endif + + gst_deinit (); + return 0; +} diff --git a/tests/internal/test-filter.c b/tests/internal/test-filter.c new file mode 100644 index 0000000000..650af220e6 --- /dev/null +++ b/tests/internal/test-filter.c @@ -0,0 +1,457 @@ +/* + * test-filter.c - Test GstVaapiFilter + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2013 Intel Corporation + * Author: Halley Zhao + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gst/vaapi/sysdeps.h" +#include +#include +#include +#include "image.h" +#include "output.h" + +static gchar *g_src_format_str; +static gchar *g_crop_rect_str; +static gchar *g_denoise_str; +static gchar *g_sharpen_str; +static gchar *g_deinterlace_str; +static gchar *g_deinterlace_flags_str; + +static GOptionEntry g_options[] = { + {"src-format", 's', + 0, + G_OPTION_ARG_STRING, &g_src_format_str, + "source surface format", NULL}, + {"crop-rect", 'c', + 0, + G_OPTION_ARG_STRING, &g_crop_rect_str, + "cropping rectangle", NULL}, + {"denoise", 0, + 0, + G_OPTION_ARG_STRING, &g_denoise_str, + "set noise reduction level", NULL}, + {"sharpen", 0, + 0, + G_OPTION_ARG_STRING, &g_sharpen_str, + "set sharpening level", NULL}, + {"deinterlace", 0, + 0, + G_OPTION_ARG_STRING, &g_deinterlace_str, + "enable deinterlacing", NULL}, + {"deinterlace-flags", 0, + 0, + G_OPTION_ARG_STRING, &g_deinterlace_flags_str, + "deinterlacing flags", NULL}, + {NULL,} +}; + +#define APP_ERROR app_error_quark() +static GQuark +app_error_quark (void) +{ + static gsize g_quark; + + if (g_once_init_enter (&g_quark)) { + gsize quark = (gsize) g_quark_from_static_string ("AppError"); + g_once_init_leave (&g_quark, quark); + } + return g_quark; +} + +typedef enum +{ + APP_ERROR_NONE, + APP_ERROR_CREATE_TEST_SURFACE, +} AppError; + +static inline void +pause (void) +{ + g_print ("Press any key to continue...\n"); + getchar (); +} + +static GstVaapiSurface * +create_test_surface (GstVaapiDisplay * display, guint width, guint height, + guint flags, GError ** error_ptr) +{ + GstVideoFormat format = GST_VIDEO_FORMAT_I420; + GstVaapiSurface *surface = NULL; + GstVaapiImage *image = NULL; + GError *error = NULL; + + if (g_src_format_str) { + format = gst_video_format_from_string (g_src_format_str); + if (format == GST_VIDEO_FORMAT_UNKNOWN) + goto error_invalid_format; + } + + surface = + gst_vaapi_surface_new_with_format (display, format, width, height, 0); + if (!surface) + goto error_create_surface; + + image = image_generate_full (display, format, width, height, flags); + if (!image) + goto error_create_image; + + if (!image_upload (image, surface)) + goto error_upload_image; + + gst_vaapi_image_unref (image); + return surface; + + /* ERRORS */ +error_invalid_format: + error = g_error_new (APP_ERROR, APP_ERROR_CREATE_TEST_SURFACE, + "unknown format %s", g_src_format_str); + goto error_cleanup; +error_create_surface: + error = g_error_new (APP_ERROR, APP_ERROR_CREATE_TEST_SURFACE, + "unsupported format %s", gst_vaapi_video_format_to_string (format)); + goto error_cleanup; +error_create_image: + error = g_error_new (APP_ERROR, APP_ERROR_CREATE_TEST_SURFACE, + "unsupported %s image", gst_vaapi_video_format_to_string (format)); + goto error_cleanup; +error_upload_image: + error = g_error_new (APP_ERROR, APP_ERROR_CREATE_TEST_SURFACE, + "failed to upload %s image", gst_vaapi_video_format_to_string (format)); + goto error_cleanup; +error_cleanup: + if (image) + gst_vaapi_image_unref (image); + if (surface) + gst_vaapi_surface_unref (surface); + if (error_ptr) + *error_ptr = error; + else + g_error_free (error); + return NULL; +} + +static void +dump_operation (GstVaapiFilterOpInfo * op_info) +{ + GParamSpec *pspec; + GValue value = G_VALUE_INIT; + gchar *value_str; + + if (!op_info) + return; + + pspec = op_info->pspec; + g_print (" %s: ", g_param_spec_get_name (pspec)); + g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec)); + g_param_value_set_default (pspec, &value); + value_str = g_strdup_value_contents (&value); + g_print ("%s (default: %s)\n", G_VALUE_TYPE_NAME (&value), + value_str ? value_str : ""); + g_free (value_str); +} + +static void +dump_operations (GstVaapiFilter * filter) +{ + GPtrArray *const ops = gst_vaapi_filter_get_operations (filter); + guint i; + + if (!ops) + return; + + g_print ("%u operations\n", ops->len); + for (i = 0; i < ops->len; i++) + dump_operation (g_ptr_array_index (ops, i)); + g_ptr_array_unref (ops); +} + +static void +dump_formats (GstVaapiFilter * filter) +{ + GArray *const formats = gst_vaapi_filter_get_formats (filter); + guint i; + + if (!formats) + return; + + g_print ("%u formats\n", formats->len); + for (i = 0; i < formats->len; i++) { + GstVideoFormat format = g_array_index (formats, GstVideoFormat, i); + g_print (" %s\n", gst_vaapi_video_format_to_string (format)); + } + g_array_unref (formats); +} + +static gboolean +parse_double (const gchar * str, gdouble * out_value_ptr) +{ + gchar *endptr = NULL; + gdouble out_value; + + g_return_val_if_fail (out_value_ptr != NULL, FALSE); + + errno = 0; + out_value = g_ascii_strtod (str, &endptr); + if (!endptr || *endptr != '\0' || errno == ERANGE) + return FALSE; + + *out_value_ptr = out_value; + return TRUE; +} + +static gboolean +parse_crop_rect (const gchar * str, GstVaapiRectangle * crop_rect) +{ + if (str) { + // Format: 'x' + if (sscanf (str, "%ux%u", &crop_rect->width, &crop_rect->height) == 2) { + crop_rect->x = 0; + crop_rect->y = 0; + return TRUE; + } + // Format: '('? ',' ')'? 'x' + if (sscanf (str, "(%d,%d):%ux%u", &crop_rect->x, &crop_rect->y, + &crop_rect->width, &crop_rect->height) == 4 || + sscanf (str, "%d,%d:%ux%u", &crop_rect->x, &crop_rect->y, + &crop_rect->width, &crop_rect->height) == 4) + return TRUE; + } + return FALSE; +} + +static gboolean +parse_enum (const gchar * str, GType type, gint default_value, + gint * out_value_ptr) +{ + gint out_value = default_value; + + g_return_val_if_fail (out_value_ptr != NULL, FALSE); + + if (str) { + const GEnumValue *enum_value; + GEnumClass *const enum_class = g_type_class_ref (type); + + if (!enum_class) + return FALSE; + + enum_value = g_enum_get_value_by_nick (enum_class, str); + if (enum_value) + out_value = enum_value->value; + g_type_class_unref (enum_class); + + if (!enum_value) + return FALSE; + } + *out_value_ptr = out_value; + return TRUE; +} + +static gboolean +parse_flags (const gchar * str, GType type, guint * out_value_ptr) +{ + gchar **tokens = NULL; + gint i, value, out_value = 0; + gboolean success = FALSE; + + g_return_val_if_fail (out_value_ptr != NULL, FALSE); + + if (str) { + tokens = g_strsplit (str, ",", 32); + if (!tokens) + return FALSE; + + for (i = 0; tokens[i] != NULL; i++) { + if (!parse_enum (tokens[i], type, 0, &value)) + goto end; + out_value |= value; + } + } + *out_value_ptr = out_value; + success = TRUE; + +end: + g_strfreev (tokens); + return success; +} + +static inline gboolean +parse_deinterlace (const gchar * str, + GstVaapiDeinterlaceMethod * deinterlace_ptr) +{ + g_return_val_if_fail (deinterlace_ptr != NULL, FALSE); + + if (!str) { + *deinterlace_ptr = GST_VAAPI_DEINTERLACE_METHOD_NONE; + return TRUE; + } + return parse_enum (str, GST_VAAPI_TYPE_DEINTERLACE_METHOD, + GST_VAAPI_DEINTERLACE_METHOD_NONE, (gint *) deinterlace_ptr); +} + +static inline gboolean +parse_deinterlace_flags (const gchar * str, guint * deinterlace_flags_ptr) +{ + return parse_flags (str, GST_VAAPI_TYPE_DEINTERLACE_FLAGS, + deinterlace_flags_ptr); +} + +int +main (int argc, char *argv[]) +{ + GstVaapiDisplay *display; + GstVaapiWindow *window; + GstVaapiSurface *src_surface, *dst_surface; + GstVaapiFilter *filter = NULL; + GstVaapiFilterStatus status; + GstVaapiDeinterlaceMethod deinterlace_method; + guint deinterlace_flags = 0; + guint filter_flags = 0; + guint surface_flags = 0; + gdouble denoise_level, sharpen_level; + GError *error = NULL; + + static const guint src_width = 320; + static const guint src_height = 240; + static const guint dst_width = 480; + static const guint dst_height = 360; + static const guint win_width = 640; + static const guint win_height = 480; + + if (!video_output_init (&argc, argv, g_options)) + g_error ("failed to initialize video output subsystem"); + + if (g_denoise_str && !parse_double (g_denoise_str, &denoise_level)) + g_error ("failed to parse noise reduction level"); + + if (g_sharpen_str && !parse_double (g_sharpen_str, &sharpen_level)) + g_error ("failed to parse sharpening level"); + + if (!parse_deinterlace (g_deinterlace_str, &deinterlace_method)) + g_error ("failed to parse deinterlace method `%s'", g_deinterlace_str); + + if (!parse_deinterlace_flags (g_deinterlace_flags_str, &deinterlace_flags)) + g_error ("failed to parse deinterlace flags `%s'", g_deinterlace_flags_str); + + display = video_output_create_display (NULL); + if (!display) + g_error ("failed to create VA display"); + + window = video_output_create_window (display, win_width, win_height); + if (!window) + g_error ("failed to create window"); + + filter = gst_vaapi_filter_new (display); + if (!filter) + g_error ("failed to create video processing pipeline"); + + dump_operations (filter); + dump_formats (filter); + + if (g_crop_rect_str) { + GstVaapiRectangle crop_rect; + + if (!parse_crop_rect (g_crop_rect_str, &crop_rect)) + g_error ("failed to parse cropping rectangle"); + + printf ("Frame cropping: (%d,%d), size %ux%u\n", + crop_rect.x, crop_rect.y, crop_rect.width, crop_rect.height); + + if (!gst_vaapi_filter_set_cropping_rectangle (filter, &crop_rect)) + g_error ("failed to set cropping rectangle"); + } + + if (g_denoise_str) { + printf ("Noise reduction level: %f\n", denoise_level); + + if (!gst_vaapi_filter_set_denoising_level (filter, denoise_level)) + g_error ("failed to set denoising level"); + } + + if (g_sharpen_str) { + printf ("Sharpening level: %f\n", sharpen_level); + + if (!gst_vaapi_filter_set_sharpening_level (filter, sharpen_level)) + g_error ("failed to set sharpening level"); + } + + if (deinterlace_method != GST_VAAPI_DEINTERLACE_METHOD_NONE) { + printf ("Enable deinterlacing: %s\n", g_deinterlace_str); + + if (!gst_vaapi_filter_set_deinterlacing (filter, deinterlace_method, + deinterlace_flags)) + g_error ("failed to set deinterlacing method"); + } else if (deinterlace_flags) { + if (deinterlace_flags & GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD) + filter_flags = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD; + else + filter_flags = GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD; + } + + if (deinterlace_method != GST_VAAPI_DEINTERLACE_METHOD_NONE || + deinterlace_flags) { + if (!(deinterlace_flags & GST_VAAPI_DEINTERLACE_FLAG_ONEFIELD)) + surface_flags = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD | + GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD; + else if (deinterlace_flags & GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD) + surface_flags = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD; + else + surface_flags = GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD; + } + + src_surface = create_test_surface (display, src_width, src_height, + surface_flags, &error); + if (!src_surface) + g_error ("failed to create source VA surface: %s", error->message); + + dst_surface = gst_vaapi_surface_new (display, GST_VAAPI_CHROMA_TYPE_YUV420, + dst_width, dst_height); + if (!dst_surface) + g_error ("failed to create target VA surface"); + + status = gst_vaapi_filter_process (filter, src_surface, dst_surface, + filter_flags); + if (status != GST_VAAPI_FILTER_STATUS_SUCCESS) + g_error ("failed to process video filters"); + + gst_vaapi_window_show (window); + + if (!gst_vaapi_window_put_surface (window, dst_surface, NULL, NULL, + GST_VAAPI_PICTURE_STRUCTURE_FRAME)) + g_error ("failed to render target surface"); + + pause (); + + gst_object_unref (filter); + gst_vaapi_surface_unref (dst_surface); + gst_vaapi_surface_unref (src_surface); + gst_object_unref (window); + gst_object_unref (display); + video_output_exit (); + g_free (g_src_format_str); + g_free (g_crop_rect_str); + g_free (g_denoise_str); + g_free (g_sharpen_str); + g_free (g_deinterlace_str); + g_free (g_deinterlace_flags_str); + return 0; +} diff --git a/tests/internal/test-h264.c b/tests/internal/test-h264.c new file mode 100644 index 0000000000..d94dc42c0d --- /dev/null +++ b/tests/internal/test-h264.c @@ -0,0 +1,1051 @@ +/* + * test-h264.c - H.264 test data + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "test-h264.h" + +#define H264_CLIP_WIDTH 320 +#define H264_CLIP_HEIGHT 240 +#define H264_CLIP_DATA_SIZE 12111 + +/* Data dump of a 320x240 H.264 video clip (h264.mp4), it has a single frame */ +static const guchar h264_clip[H264_CLIP_DATA_SIZE] = { + 0x00, 0x00, 0x01, 0x67, 0x4d, 0x40, 0x0d, 0xab, 0x40, 0xa0, 0xfd, 0x80, + 0x88, 0x00, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x03, 0x00, 0xc4, 0x78, + 0xa1, 0x55, 0x00, 0x00, 0x01, 0x68, 0xee, 0x32, 0xc8, 0x00, 0x00, 0x01, + 0x65, 0x88, 0x82, 0x00, 0x45, 0xbb, 0x9d, 0x38, 0x9b, 0xe8, 0x48, 0xef, + 0xed, 0xa7, 0xd7, 0x9c, 0x19, 0x9b, 0x5a, 0xca, 0x00, 0x0d, 0x54, 0x0c, + 0xe3, 0xd5, 0xad, 0xa9, 0x5d, 0x71, 0x24, 0x83, 0xbb, 0x36, 0x4d, 0xb1, + 0xf5, 0x0f, 0xc6, 0x66, 0xb6, 0x6d, 0x1d, 0xa5, 0x45, 0xfc, 0xa0, 0x4c, + 0xbf, 0xfb, 0x2f, 0x5c, 0x1a, 0x5a, 0x3b, 0x29, 0xe0, 0x35, 0x95, 0x44, + 0x8e, 0x2f, 0x22, 0xd3, 0x3a, 0x48, 0x88, 0x7d, 0x32, 0x97, 0xff, 0xd8, + 0x54, 0x7f, 0x7f, 0x65, 0x57, 0x71, 0xaf, 0xba, 0x17, 0xe0, 0x12, 0x24, + 0xc9, 0x5b, 0xaa, 0xc7, 0xd5, 0x27, 0xc9, 0x64, 0x5d, 0x5e, 0xa0, 0xea, + 0x57, 0xd2, 0x7d, 0x55, 0x6c, 0xf2, 0x44, 0x2f, 0x4b, 0x5d, 0xbd, 0x62, + 0xb9, 0xc2, 0xfa, 0x1e, 0x8f, 0xbc, 0x57, 0x5f, 0xc1, 0x2d, 0xb3, 0x9a, + 0x0e, 0x58, 0x75, 0xf7, 0x08, 0xdf, 0x2d, 0xda, 0xc1, 0xa5, 0x55, 0x76, + 0x06, 0xaf, 0x92, 0x28, 0x43, 0xc5, 0x20, 0x16, 0x96, 0xf5, 0x79, 0x1e, + 0x88, 0x77, 0xb3, 0x4e, 0xb8, 0x4f, 0x3e, 0x51, 0x3c, 0xcf, 0xc0, 0x28, + 0xda, 0xb8, 0xa3, 0x1d, 0xed, 0x8e, 0x04, 0x74, 0x82, 0xc1, 0x5d, 0xa8, + 0x3c, 0x25, 0xd2, 0x84, 0x0b, 0x34, 0x40, 0x8b, 0x7f, 0xee, 0xae, 0xf8, + 0xde, 0x6e, 0x28, 0xf6, 0xfc, 0xfc, 0x14, 0x7e, 0x95, 0xd9, 0xd8, 0x2c, + 0x09, 0x49, 0x27, 0x64, 0x13, 0x83, 0x5c, 0x6f, 0xd4, 0x09, 0x48, 0xa8, + 0xd4, 0x1b, 0x6e, 0x4d, 0x05, 0x0a, 0xbe, 0x27, 0xff, 0xf4, 0x27, 0x04, + 0x41, 0xa0, 0x23, 0x61, 0xe6, 0x26, 0x32, 0xf4, 0xa3, 0xca, 0x97, 0xfc, + 0xeb, 0x6b, 0x45, 0x35, 0x13, 0x69, 0xd9, 0x41, 0x0f, 0xa6, 0xc0, 0xbe, + 0xd5, 0xfa, 0x28, 0xa6, 0x4f, 0x62, 0x3e, 0x1f, 0xcb, 0x98, 0x0a, 0x70, + 0x09, 0xc1, 0xe3, 0x69, 0x30, 0x20, 0xe7, 0xd5, 0x1c, 0xf0, 0x7e, 0x52, + 0x1d, 0x6a, 0xdd, 0x14, 0x58, 0x5e, 0x7a, 0x35, 0x57, 0xa1, 0xe6, 0x83, + 0x46, 0x57, 0x6e, 0x57, 0x7f, 0x72, 0x5d, 0x0c, 0x0c, 0xf4, 0x40, 0x11, + 0x8c, 0xbb, 0xdf, 0xd1, 0x54, 0xfb, 0x7d, 0xf7, 0x03, 0xb9, 0x4e, 0xa3, + 0x76, 0x4c, 0xce, 0xfb, 0x9e, 0x39, 0x02, 0xf0, 0x48, 0xb5, 0x8c, 0x36, + 0x6e, 0x93, 0x79, 0x48, 0xcc, 0x28, 0xec, 0xd7, 0xb8, 0x02, 0xe5, 0xa3, + 0x37, 0x01, 0xe1, 0x3c, 0x40, 0x8f, 0x68, 0x27, 0xbc, 0xec, 0x6b, 0x59, + 0xb9, 0xfe, 0xb8, 0x67, 0x68, 0x83, 0x99, 0x97, 0x1e, 0xcc, 0x4e, 0x23, + 0x82, 0x26, 0x93, 0x7b, 0x7a, 0x9e, 0xdc, 0x42, 0xca, 0x1b, 0x3e, 0x13, + 0x19, 0x45, 0x03, 0x40, 0xab, 0xd2, 0xda, 0x6b, 0x6c, 0x26, 0xdb, 0xe3, + 0x72, 0x06, 0x89, 0xea, 0x03, 0x95, 0xe3, 0x14, 0xe1, 0x4a, 0x16, 0x58, + 0x2d, 0x67, 0xaa, 0xbf, 0xbe, 0x37, 0x54, 0x19, 0xb1, 0x57, 0x61, 0x85, + 0x82, 0x5f, 0x63, 0x33, 0xe2, 0xf8, 0x7f, 0x4f, 0x21, 0x44, 0x8a, 0x0e, + 0x21, 0x2b, 0x12, 0x99, 0x4d, 0xd9, 0x2e, 0xea, 0x36, 0x2d, 0x45, 0xcb, + 0xe2, 0xfe, 0xdd, 0x03, 0x3b, 0x08, 0x58, 0x60, 0x1e, 0xb2, 0xfa, 0x3b, + 0x89, 0xa5, 0x03, 0xde, 0xab, 0x71, 0x32, 0x48, 0x46, 0x2c, 0xfb, 0x2b, + 0x84, 0x83, 0xc9, 0xff, 0xf6, 0xf5, 0x2f, 0xe7, 0x2f, 0x6a, 0x5d, 0x86, + 0xe2, 0x48, 0x23, 0x6d, 0x84, 0x60, 0x9b, 0xc0, 0x25, 0x1e, 0xff, 0x94, + 0xe8, 0xf4, 0xd0, 0x4e, 0x11, 0x60, 0xda, 0x20, 0xa8, 0xfd, 0xf3, 0x00, + 0x4f, 0x0e, 0x4f, 0xa2, 0xeb, 0xe1, 0xa8, 0xb3, 0x47, 0x35, 0x62, 0x83, + 0x6f, 0x08, 0x6b, 0xb8, 0x82, 0x04, 0xcc, 0x63, 0x69, 0xd7, 0xba, 0x10, + 0xd4, 0x51, 0xe6, 0xb5, 0x34, 0xe8, 0x7d, 0xaf, 0x87, 0xcf, 0x1d, 0xeb, + 0x46, 0xc1, 0xcd, 0xcb, 0xf2, 0x3b, 0x3e, 0xa0, 0x61, 0xc7, 0x68, 0x86, + 0x0b, 0x9f, 0x0b, 0x59, 0xc0, 0x79, 0x4e, 0xcc, 0x79, 0x91, 0xa0, 0xe8, + 0x80, 0x6c, 0xbd, 0x35, 0x12, 0x71, 0x2f, 0x5e, 0xa4, 0xfc, 0xe6, 0x51, + 0xe0, 0xbe, 0x41, 0x1a, 0x19, 0x60, 0xd8, 0xac, 0xcd, 0x93, 0x05, 0x70, + 0xa0, 0xda, 0x53, 0x4e, 0x5a, 0x6d, 0x9b, 0x3f, 0x28, 0x73, 0x87, 0x6f, + 0x6d, 0x41, 0x5a, 0x13, 0xd0, 0xea, 0x19, 0xb3, 0xb7, 0xf1, 0x75, 0x92, + 0xae, 0x43, 0x9d, 0xe3, 0xa7, 0x4d, 0x5a, 0x52, 0x36, 0xce, 0x6b, 0x1e, + 0x2b, 0x2e, 0xab, 0x0c, 0xd7, 0xe4, 0x1c, 0x44, 0x72, 0x9d, 0x86, 0xb6, + 0xeb, 0xe5, 0x80, 0xc4, 0x45, 0x21, 0x8b, 0xe0, 0xe0, 0x9d, 0x09, 0xfa, + 0x0b, 0x59, 0x0c, 0x2c, 0x9d, 0x97, 0x15, 0x56, 0xd0, 0x21, 0xd8, 0x90, + 0xb4, 0x89, 0xc4, 0x96, 0x76, 0xf1, 0x64, 0xa5, 0x85, 0x2a, 0x13, 0xfb, + 0xfa, 0x11, 0x1e, 0x2d, 0x63, 0xc2, 0x9a, 0x87, 0x99, 0x2c, 0x18, 0xb8, + 0xeb, 0x6a, 0x5c, 0x68, 0x26, 0x63, 0xcc, 0x1b, 0x1a, 0x5c, 0x7f, 0x0d, + 0x45, 0xcc, 0x56, 0x46, 0x92, 0xbb, 0x76, 0xf2, 0x2e, 0x52, 0x05, 0x3c, + 0xe3, 0xbb, 0x59, 0x9b, 0x89, 0x03, 0x0d, 0x48, 0xb1, 0xdc, 0x78, 0x04, + 0x03, 0x24, 0xf4, 0x62, 0xcf, 0xb1, 0xc6, 0x64, 0x05, 0xbd, 0x89, 0x94, + 0x1a, 0x8d, 0xc1, 0xbe, 0xac, 0xe0, 0xed, 0x89, 0xf3, 0x47, 0x81, 0x82, + 0xb9, 0x64, 0xcc, 0x8e, 0xc4, 0x1e, 0xa9, 0xf6, 0xde, 0x8d, 0xb7, 0x33, + 0xba, 0x5b, 0x49, 0x0d, 0x0a, 0x16, 0x96, 0x7d, 0x89, 0x82, 0xe0, 0x5a, + 0x08, 0x55, 0xbd, 0xce, 0xca, 0xc0, 0x46, 0x1a, 0x6b, 0xf9, 0x7d, 0x03, + 0xe8, 0x35, 0x69, 0x7d, 0x87, 0xc9, 0x71, 0x01, 0x7e, 0xa8, 0x3a, 0x9c, + 0xd5, 0xe2, 0x71, 0xa6, 0xc7, 0xe2, 0x2d, 0xf3, 0x6f, 0x74, 0x0f, 0x3e, + 0x03, 0x70, 0x5e, 0xec, 0x8c, 0x66, 0xf9, 0x71, 0x9a, 0xd2, 0x56, 0x57, + 0x37, 0xcd, 0x50, 0x55, 0x97, 0xea, 0x67, 0x20, 0x59, 0x06, 0x4d, 0x22, + 0xa0, 0x85, 0x90, 0xb3, 0x59, 0x15, 0x75, 0x0d, 0x70, 0xbd, 0xb5, 0x7d, + 0x72, 0xaa, 0xea, 0xfc, 0x9d, 0x08, 0x8d, 0xdf, 0x31, 0x21, 0x2d, 0xef, + 0x00, 0x24, 0x6c, 0xae, 0x82, 0x6e, 0x1a, 0x4b, 0x28, 0xa5, 0x6d, 0x98, + 0xeb, 0x50, 0x87, 0x6f, 0x1b, 0xa5, 0xba, 0x1c, 0xda, 0x59, 0xb8, 0x4c, + 0x17, 0xe3, 0xd5, 0x10, 0x46, 0x94, 0x91, 0xed, 0x0b, 0xd3, 0xfc, 0x06, + 0x81, 0x60, 0x88, 0x5f, 0x58, 0x81, 0x26, 0x54, 0xdc, 0xd5, 0x7c, 0xbe, + 0x30, 0x04, 0x17, 0x84, 0x76, 0xe8, 0xb6, 0x8a, 0xec, 0x84, 0x02, 0xcf, + 0xc7, 0xda, 0x2d, 0x2e, 0x31, 0xc2, 0x77, 0x31, 0x54, 0x32, 0xbd, 0x77, + 0xa2, 0xa5, 0x5d, 0xec, 0x1c, 0x27, 0xf6, 0xec, 0xc8, 0x3f, 0xeb, 0x1a, + 0x24, 0xcb, 0x74, 0xd0, 0xb3, 0x52, 0xa8, 0x8f, 0x4c, 0x26, 0xbf, 0x68, + 0xb2, 0x87, 0xf3, 0xa8, 0xa9, 0x4f, 0x71, 0x57, 0xc7, 0xa8, 0x34, 0x5a, + 0x01, 0x68, 0xae, 0x5c, 0xb3, 0xd8, 0x23, 0x6b, 0xea, 0x18, 0xdf, 0xa9, + 0xe5, 0xc4, 0x11, 0x49, 0x2b, 0xfa, 0xa8, 0xf3, 0x8f, 0x80, 0x47, 0xa0, + 0x19, 0xc7, 0x20, 0xef, 0xbf, 0xed, 0xe1, 0x38, 0x8b, 0x16, 0x54, 0x36, + 0x60, 0x8b, 0x04, 0x26, 0x9c, 0x6b, 0x1a, 0x95, 0x4c, 0x94, 0x6a, 0x53, + 0xcf, 0xb4, 0x4b, 0x38, 0x3a, 0x15, 0x26, 0x94, 0x10, 0x1c, 0x35, 0xe4, + 0x57, 0x80, 0x19, 0xad, 0x1f, 0x82, 0xe8, 0x47, 0xe4, 0x90, 0xa2, 0x42, + 0x30, 0x43, 0x15, 0x92, 0x2b, 0x39, 0xfb, 0x7b, 0xb3, 0xdb, 0xc7, 0x5b, + 0x79, 0x5e, 0x91, 0xba, 0x38, 0x74, 0xd6, 0x00, 0x26, 0xa5, 0x8f, 0xa4, + 0x31, 0xe6, 0x7b, 0xeb, 0x52, 0xc2, 0xe2, 0xa1, 0x6b, 0x5f, 0x17, 0xf1, + 0x15, 0xc9, 0x4b, 0x44, 0x93, 0x77, 0x28, 0xdf, 0x2a, 0xc0, 0xb5, 0x97, + 0xfc, 0xbe, 0x2e, 0x72, 0x53, 0x58, 0xf9, 0x33, 0x3a, 0xb0, 0x6e, 0xaf, + 0x0c, 0x1b, 0xcf, 0x71, 0x37, 0x6b, 0x4a, 0x9a, 0x66, 0x16, 0x90, 0x43, + 0x9b, 0x70, 0x0d, 0x8f, 0xd3, 0x04, 0x4b, 0x14, 0xf2, 0x58, 0x9f, 0x64, + 0x33, 0x21, 0xdc, 0x02, 0x8a, 0x5b, 0xd6, 0x80, 0x9c, 0x22, 0xc8, 0x39, + 0x7d, 0x2d, 0x7c, 0x09, 0x4e, 0x6a, 0x8c, 0x8d, 0x0c, 0xc4, 0xfe, 0x6f, + 0x8c, 0x50, 0xf2, 0x75, 0xc0, 0x12, 0x6f, 0xd3, 0x9d, 0x07, 0xc0, 0xe9, + 0xdf, 0x36, 0xa2, 0x6f, 0xca, 0x14, 0x5b, 0x0f, 0x5a, 0xd8, 0x35, 0x72, + 0x07, 0x08, 0x80, 0xba, 0x2f, 0x61, 0x7f, 0xb0, 0x5e, 0xbb, 0xb1, 0x47, + 0x6a, 0xbd, 0x6a, 0xe4, 0xb6, 0xa2, 0xec, 0x2e, 0x27, 0x43, 0xbc, 0xd7, + 0x2c, 0x2c, 0xf3, 0x6c, 0x12, 0x4c, 0x86, 0x5a, 0x38, 0xa4, 0x87, 0xa8, + 0xe1, 0x70, 0x17, 0x15, 0xd0, 0x2b, 0x87, 0xdb, 0x87, 0xc0, 0x85, 0x57, + 0x30, 0x31, 0x16, 0x07, 0x9b, 0x72, 0x07, 0xf5, 0x18, 0x6d, 0xd1, 0x8d, + 0x31, 0xa1, 0x25, 0x6a, 0xb4, 0xf3, 0x07, 0x5f, 0x0c, 0x99, 0x33, 0x68, + 0xbf, 0x2c, 0xa1, 0xfd, 0xde, 0x16, 0x2d, 0x4a, 0x5a, 0xa0, 0x7e, 0xe5, + 0x9b, 0x89, 0x4a, 0x8d, 0xe7, 0x18, 0x21, 0x32, 0x47, 0x3c, 0x9d, 0x48, + 0xab, 0x7d, 0xca, 0xb4, 0x63, 0xd9, 0xfd, 0x29, 0x2d, 0x4c, 0xf1, 0xf2, + 0x20, 0x0a, 0x91, 0x2e, 0x2c, 0xa1, 0x49, 0x83, 0x73, 0x15, 0xa0, 0x7d, + 0x6e, 0xae, 0x51, 0x45, 0x0d, 0x09, 0x1f, 0x8f, 0x61, 0x42, 0xbd, 0x24, + 0xcd, 0x3e, 0xe8, 0x66, 0x84, 0xc6, 0x97, 0x08, 0x7b, 0x72, 0x73, 0x7e, + 0xe7, 0x99, 0x05, 0xab, 0x63, 0xff, 0x3c, 0x44, 0xa1, 0xc0, 0x1b, 0xfc, + 0xff, 0x27, 0xe9, 0x45, 0x82, 0x75, 0x82, 0x6f, 0x9c, 0x65, 0xef, 0x67, + 0xd6, 0x00, 0xd1, 0x9f, 0x61, 0x9f, 0x38, 0xdd, 0x7f, 0x5f, 0x4d, 0x67, + 0x5b, 0x5d, 0xff, 0x98, 0x6b, 0x13, 0xe0, 0xe7, 0x69, 0xcb, 0x7f, 0x7c, + 0x11, 0x91, 0xe0, 0x05, 0xb9, 0x64, 0xd0, 0xb7, 0x91, 0xe5, 0xd4, 0x3a, + 0x47, 0x05, 0x25, 0x4f, 0x15, 0x46, 0xaf, 0x41, 0x9e, 0xc7, 0x49, 0x15, + 0x17, 0xd1, 0x9c, 0x28, 0xef, 0x80, 0xa3, 0x8b, 0x60, 0xcc, 0x60, 0xeb, + 0x96, 0x36, 0x3a, 0x23, 0x94, 0xf3, 0x6c, 0xe5, 0x3f, 0xe8, 0x8b, 0x5c, + 0x8c, 0xfe, 0x6f, 0x91, 0x65, 0x19, 0xa1, 0x4d, 0x45, 0x7b, 0x06, 0x0f, + 0x71, 0xb7, 0x9a, 0x8d, 0x8e, 0x82, 0x7b, 0x68, 0x44, 0xa4, 0xa6, 0xc3, + 0xe5, 0x67, 0x9f, 0x6c, 0xd0, 0xe4, 0xe8, 0x37, 0x08, 0x6b, 0xbb, 0xa0, + 0x3a, 0xd0, 0xa9, 0xd9, 0x04, 0xaa, 0x91, 0xac, 0x71, 0xff, 0xec, 0x7e, + 0xaf, 0xa9, 0x99, 0xa2, 0x8d, 0x91, 0x95, 0xb3, 0xd8, 0xe4, 0xf3, 0x3f, + 0xa6, 0x4b, 0x0c, 0x19, 0x23, 0xf7, 0xa7, 0xcd, 0x4c, 0x41, 0x28, 0x63, + 0x9f, 0x0b, 0x8f, 0x70, 0x70, 0xbd, 0x25, 0x16, 0x8e, 0x86, 0x8a, 0x69, + 0xe3, 0x6a, 0xd4, 0x98, 0x42, 0x56, 0x15, 0x2d, 0x3d, 0xdb, 0x17, 0x1b, + 0x23, 0x58, 0x82, 0x56, 0x11, 0x97, 0x85, 0xf2, 0x68, 0x95, 0x92, 0xd5, + 0x9e, 0x91, 0x05, 0x70, 0xc8, 0x96, 0xb2, 0x73, 0x6d, 0x1e, 0x12, 0x8c, + 0xa0, 0xe4, 0x1a, 0x84, 0x5b, 0xb4, 0x32, 0xf7, 0x9e, 0x08, 0xd0, 0x6c, + 0x42, 0xf0, 0x0b, 0xc4, 0x1f, 0xe0, 0xbb, 0x71, 0xe1, 0x2d, 0x86, 0xd7, + 0x77, 0x24, 0x43, 0x53, 0x0c, 0x88, 0x21, 0x75, 0x95, 0xd0, 0xfe, 0x10, + 0x23, 0xcd, 0xba, 0x77, 0x3d, 0x9b, 0x0f, 0xb2, 0xe2, 0xcc, 0x0f, 0x94, + 0xe0, 0x66, 0x90, 0x0e, 0xf7, 0x6a, 0x3c, 0x9f, 0xc0, 0xf6, 0x98, 0x1c, + 0x4c, 0x9f, 0x25, 0xc4, 0xeb, 0x1d, 0x91, 0x32, 0x29, 0x34, 0x2a, 0xb0, + 0x7e, 0x1c, 0x09, 0x77, 0x13, 0x83, 0xfa, 0xcf, 0x24, 0xa2, 0x5f, 0x79, + 0x78, 0x64, 0xf7, 0x45, 0x81, 0xbe, 0x6a, 0x82, 0x26, 0xfd, 0xe7, 0xc3, + 0x61, 0x41, 0x27, 0xcc, 0x99, 0x69, 0x77, 0xc8, 0xa7, 0xf3, 0x52, 0x01, + 0xa7, 0x8c, 0x0b, 0x7d, 0x86, 0x8d, 0xbb, 0x31, 0xd6, 0x67, 0xf9, 0xa7, + 0x8f, 0x76, 0xb6, 0x74, 0x26, 0x43, 0x35, 0xb8, 0x83, 0x7c, 0x16, 0x34, + 0x88, 0x0c, 0xb6, 0xec, 0xf0, 0x01, 0x8c, 0x1c, 0xe5, 0x52, 0xd4, 0xca, + 0x01, 0x2e, 0xb5, 0x87, 0xc1, 0xc1, 0x1b, 0xa3, 0x02, 0x17, 0x13, 0xd3, + 0x35, 0xe8, 0x80, 0xe1, 0xd1, 0x01, 0x9c, 0x0a, 0x62, 0x7d, 0x98, 0x7c, + 0x68, 0xa4, 0x8e, 0x3a, 0x50, 0x4b, 0x95, 0x59, 0xa3, 0x11, 0xf6, 0xa3, + 0xde, 0x92, 0x65, 0x00, 0xa0, 0xe8, 0x32, 0xf0, 0xc3, 0x77, 0x68, 0x0b, + 0xed, 0xc1, 0x69, 0xd2, 0x6e, 0xce, 0x80, 0xe4, 0x56, 0x9b, 0x15, 0xbf, + 0x3c, 0x4a, 0x38, 0x26, 0xf6, 0x6a, 0xdb, 0x62, 0x7a, 0xab, 0xb1, 0x77, + 0x75, 0x0d, 0xa7, 0xa4, 0xcf, 0x5e, 0x2d, 0xea, 0x24, 0x84, 0xbd, 0x83, + 0x8e, 0xaa, 0x91, 0xe1, 0x72, 0x5f, 0x7f, 0x26, 0x54, 0x4f, 0xab, 0xa6, + 0x50, 0x22, 0x68, 0x8c, 0xa6, 0x06, 0x67, 0x3c, 0x3e, 0x93, 0x9a, 0xc2, + 0x53, 0x15, 0x08, 0x1a, 0x3c, 0xb3, 0x3f, 0xf0, 0x83, 0xf5, 0x0d, 0x9c, + 0xe3, 0x76, 0x11, 0x45, 0x21, 0x6b, 0x65, 0x97, 0xea, 0x3c, 0xdb, 0x0d, + 0xcd, 0x6e, 0xb7, 0x26, 0x7b, 0x82, 0x63, 0x35, 0x7e, 0x76, 0xf4, 0xb8, + 0x0e, 0xe5, 0x1d, 0x95, 0x94, 0x1c, 0x60, 0xc7, 0xea, 0x9c, 0x1c, 0x73, + 0x75, 0x0e, 0x9b, 0x5f, 0x78, 0x09, 0x4f, 0x90, 0x31, 0x5c, 0xc8, 0x5b, + 0x78, 0xce, 0xb3, 0x3e, 0x31, 0x61, 0x90, 0xba, 0xe0, 0xe1, 0x57, 0x1d, + 0x71, 0x80, 0x92, 0x6b, 0x75, 0xe1, 0x34, 0x95, 0xeb, 0x88, 0xe4, 0x0b, + 0x72, 0xdc, 0x34, 0x24, 0x3b, 0x6d, 0x94, 0xc9, 0xe9, 0x8d, 0x38, 0x72, + 0x9c, 0x61, 0x6e, 0x07, 0xd7, 0x35, 0xa1, 0x74, 0xc2, 0x0c, 0x36, 0xc3, + 0x54, 0xd3, 0xe5, 0xd1, 0x08, 0x8e, 0x24, 0x77, 0xf5, 0x61, 0xcf, 0x69, + 0x9b, 0x27, 0x70, 0xe7, 0x52, 0xf6, 0xef, 0x66, 0x8f, 0x0e, 0x8b, 0xc0, + 0xf3, 0x64, 0x2a, 0xa8, 0xff, 0xcc, 0xd9, 0x61, 0x53, 0xac, 0x36, 0x23, + 0x4f, 0x3c, 0x0f, 0xe0, 0xec, 0xad, 0xc5, 0x35, 0x3f, 0x3b, 0x74, 0x26, + 0x84, 0x48, 0xd1, 0xfe, 0x72, 0x01, 0xea, 0x4d, 0x03, 0x46, 0x66, 0x5a, + 0xc4, 0x0a, 0x55, 0x43, 0x61, 0x36, 0x6a, 0xc1, 0xd2, 0x74, 0x0a, 0x8f, + 0x01, 0xb2, 0xc2, 0xaa, 0xd7, 0x2d, 0x0a, 0x0f, 0x67, 0xa1, 0x25, 0x7d, + 0x45, 0x60, 0x0f, 0x06, 0xfb, 0x8f, 0x8b, 0xe0, 0x4a, 0x8c, 0xd7, 0x19, + 0xac, 0xcc, 0x47, 0xa2, 0x7c, 0x30, 0x90, 0x94, 0x81, 0xab, 0xde, 0x38, + 0xb8, 0xc9, 0xdb, 0x63, 0x9c, 0xcb, 0xdd, 0x71, 0xde, 0x4f, 0x1e, 0x43, + 0x08, 0xe4, 0xe3, 0x83, 0x86, 0x0f, 0x34, 0xb7, 0x1e, 0x53, 0xc1, 0xde, + 0x46, 0xf1, 0x70, 0xf5, 0xd8, 0x47, 0xd2, 0x9b, 0x44, 0x88, 0x85, 0x8e, + 0x32, 0xa9, 0x0c, 0x09, 0x2f, 0xd0, 0xe4, 0x4b, 0x30, 0x3a, 0x2e, 0x65, + 0x0c, 0xff, 0xb4, 0x0d, 0xa8, 0x8f, 0x61, 0x3e, 0x7e, 0x90, 0x66, 0xbb, + 0xf6, 0xbe, 0xfd, 0x7d, 0xe4, 0xdc, 0x2c, 0x59, 0x87, 0x81, 0x60, 0x96, + 0xd7, 0x1d, 0x10, 0x02, 0x35, 0xdd, 0x16, 0x4c, 0xe9, 0x2d, 0x52, 0x45, + 0xdd, 0x3f, 0xc9, 0xff, 0x8d, 0x19, 0xad, 0x02, 0x74, 0xf1, 0x09, 0x99, + 0x94, 0x66, 0x2e, 0x8b, 0xa3, 0xdc, 0x3d, 0xf3, 0xf5, 0x85, 0xf2, 0x60, + 0x7d, 0x9d, 0xe0, 0xd3, 0x0f, 0xa4, 0x92, 0xf3, 0x55, 0xbc, 0x7b, 0x20, + 0x6b, 0xf6, 0xc4, 0xc4, 0x0f, 0x8a, 0xd7, 0x5a, 0x02, 0xb0, 0xb7, 0x78, + 0xb4, 0x9e, 0xb6, 0x93, 0x95, 0x2e, 0x76, 0x06, 0x1e, 0x34, 0x5d, 0x34, + 0x77, 0x77, 0x6d, 0x32, 0xbb, 0x46, 0xad, 0x43, 0xd7, 0x72, 0x61, 0x33, + 0x4f, 0x98, 0xe9, 0x56, 0x3a, 0x96, 0x89, 0x6e, 0x1f, 0xaf, 0x6b, 0xa0, + 0x9a, 0xe4, 0x42, 0x5a, 0xb3, 0xb8, 0x2a, 0xe1, 0x2d, 0xa6, 0x32, 0xa2, + 0x01, 0xf5, 0x3a, 0x9a, 0xbb, 0x06, 0x76, 0x0b, 0xa8, 0xac, 0x02, 0x96, + 0x0c, 0x58, 0xd3, 0x64, 0xc8, 0xe2, 0xae, 0x6c, 0xf7, 0xa7, 0x32, 0x4b, + 0x51, 0x50, 0x11, 0x90, 0xcf, 0x37, 0xed, 0xd2, 0xa0, 0xa4, 0x97, 0xb3, + 0x45, 0x1d, 0x7d, 0xf3, 0xff, 0xde, 0x9f, 0x80, 0xa9, 0x61, 0xac, 0x37, + 0x7f, 0x5d, 0xc9, 0xf6, 0xdc, 0x26, 0xd0, 0x65, 0xf2, 0xdc, 0x0c, 0x1a, + 0xcb, 0xde, 0x6b, 0x77, 0xf3, 0x08, 0xa4, 0x93, 0xab, 0x2a, 0xdf, 0x18, + 0x1a, 0xc7, 0xa6, 0xa1, 0x7e, 0x43, 0x75, 0xca, 0x88, 0xcc, 0x6f, 0xa2, + 0x85, 0x0e, 0xb0, 0xd5, 0xcd, 0x8a, 0xff, 0xc1, 0x57, 0x20, 0x66, 0xf7, + 0x19, 0x7a, 0x52, 0x5b, 0x46, 0x87, 0x5f, 0xf7, 0x77, 0xe2, 0xab, 0x4e, + 0x4a, 0xce, 0x8f, 0x3f, 0xe6, 0x9f, 0x88, 0x3a, 0x33, 0x65, 0x3c, 0x3a, + 0x41, 0xc3, 0x8e, 0xee, 0x79, 0xe7, 0x2c, 0xb0, 0x3b, 0x93, 0x82, 0xa0, + 0x1a, 0x71, 0x0e, 0xf6, 0x31, 0xc5, 0x6f, 0xc1, 0xa8, 0x32, 0x89, 0x3b, + 0x33, 0x68, 0x53, 0x81, 0x15, 0x70, 0x5e, 0x22, 0xdc, 0x99, 0xc6, 0x88, + 0xf8, 0x11, 0x06, 0x56, 0x1f, 0x80, 0x7e, 0x0b, 0x27, 0x90, 0xfc, 0x97, + 0x76, 0x61, 0xdc, 0x30, 0x5d, 0x34, 0x4e, 0x83, 0x85, 0xce, 0xe2, 0x91, + 0x4d, 0x8d, 0x92, 0x88, 0x26, 0xa0, 0xde, 0x47, 0x82, 0xd2, 0xa8, 0xa5, + 0xe7, 0x27, 0x0c, 0x45, 0x41, 0x85, 0xa1, 0x12, 0xcb, 0x3a, 0x74, 0x53, + 0x93, 0x77, 0xd0, 0x8b, 0x42, 0x8d, 0x00, 0xca, 0x44, 0x67, 0xa0, 0x6a, + 0xbd, 0xcd, 0x4a, 0x3c, 0xfe, 0x6c, 0xa1, 0x48, 0x26, 0x0d, 0x51, 0x54, + 0x59, 0xc9, 0xf9, 0x51, 0x5c, 0xd3, 0x55, 0xf0, 0x72, 0x77, 0xdb, 0x52, + 0xee, 0x0a, 0x5e, 0x8a, 0xf0, 0xbe, 0x9a, 0x37, 0xa0, 0x1b, 0x94, 0xe3, + 0x2d, 0x17, 0xc4, 0xbe, 0x9c, 0xad, 0x9c, 0xd1, 0xc6, 0xbc, 0x36, 0x5c, + 0x3b, 0xe3, 0x2e, 0x66, 0x29, 0x0c, 0x3a, 0x3d, 0xe7, 0xe3, 0xf3, 0x58, + 0x70, 0x3e, 0x59, 0xb2, 0x6c, 0x91, 0x14, 0xfe, 0x9e, 0x5e, 0x5d, 0xb2, + 0x7b, 0x46, 0x66, 0x46, 0x55, 0xe2, 0x78, 0x47, 0xeb, 0xdf, 0x2b, 0xb4, + 0xf2, 0xb2, 0x14, 0xbe, 0x64, 0x9e, 0x17, 0x16, 0x9f, 0xf5, 0x6a, 0xdd, + 0x25, 0xa1, 0x55, 0x6e, 0xb1, 0xfa, 0x09, 0xd0, 0x97, 0x7c, 0x13, 0xde, + 0x1d, 0xd4, 0x94, 0x19, 0xde, 0x8b, 0x4d, 0xe7, 0xee, 0x1f, 0xdf, 0xe5, + 0x3b, 0xdd, 0xbd, 0x13, 0x9c, 0xec, 0xcd, 0xb6, 0xb6, 0xbb, 0x3f, 0xbd, + 0x54, 0xca, 0x47, 0x5c, 0x05, 0x3c, 0x03, 0x30, 0x9d, 0x56, 0xf6, 0xc6, + 0x48, 0x6b, 0x74, 0x49, 0x58, 0xa2, 0xd8, 0x45, 0x42, 0x6f, 0xe4, 0x46, + 0x27, 0x92, 0x83, 0x78, 0x97, 0x55, 0x5b, 0x82, 0xce, 0x2a, 0x08, 0x41, + 0xb9, 0x7a, 0x66, 0x0f, 0x3c, 0x5b, 0xdf, 0x8d, 0x1d, 0x02, 0x11, 0xa4, + 0xa7, 0x0a, 0x80, 0x1e, 0xbb, 0x7a, 0xc9, 0x2f, 0xb9, 0x35, 0xc8, 0xd7, + 0x98, 0x04, 0x29, 0xaa, 0x4b, 0x88, 0x66, 0x73, 0xe4, 0x59, 0xc4, 0x3e, + 0x50, 0xad, 0xe5, 0x64, 0x54, 0xf0, 0x29, 0x38, 0xee, 0xc0, 0x00, 0xc4, + 0x22, 0x16, 0xf2, 0xc5, 0x46, 0x5c, 0xee, 0x9e, 0xf2, 0x9a, 0xe7, 0xfd, + 0x62, 0x50, 0xa2, 0xeb, 0x47, 0x56, 0x4c, 0xe4, 0x75, 0x46, 0xe4, 0xd5, + 0x25, 0xec, 0xe0, 0x35, 0x33, 0x31, 0x34, 0x1b, 0xcb, 0x72, 0x78, 0x1c, + 0x4d, 0x3a, 0x19, 0x2e, 0xc4, 0xb7, 0xa4, 0x80, 0xd2, 0x91, 0xeb, 0x2a, + 0x1d, 0xf2, 0xd1, 0xa3, 0xae, 0xac, 0x41, 0xae, 0xc2, 0x44, 0xd2, 0x3f, + 0xb4, 0x87, 0x8d, 0x69, 0x6c, 0x67, 0xd6, 0x85, 0xee, 0xd6, 0x3b, 0x03, + 0xdc, 0x58, 0x46, 0x07, 0x73, 0xb4, 0xb0, 0x3f, 0x5e, 0xc1, 0x13, 0x2c, + 0x36, 0x58, 0xd0, 0x1c, 0x34, 0x3e, 0x01, 0x88, 0xfa, 0xb1, 0x9a, 0x03, + 0x85, 0x4f, 0x4c, 0xd2, 0xac, 0xd9, 0x12, 0x09, 0xaa, 0x5f, 0x20, 0x06, + 0x1f, 0x0a, 0x44, 0x28, 0x50, 0xd1, 0x8f, 0x51, 0x8a, 0x1d, 0xfa, 0xaa, + 0x46, 0x33, 0xac, 0x0c, 0xb3, 0x10, 0xcf, 0x24, 0x4d, 0x0f, 0xcd, 0xee, + 0xd9, 0x64, 0x4a, 0x1a, 0x84, 0x0f, 0xff, 0x48, 0x8d, 0x79, 0xd4, 0x43, + 0x70, 0x1c, 0x7e, 0x7e, 0x12, 0x43, 0x51, 0x4a, 0x7e, 0x45, 0x9e, 0xa4, + 0x3c, 0x12, 0xbd, 0x95, 0xe9, 0xd6, 0xd4, 0x3f, 0xbf, 0x03, 0xae, 0x9e, + 0x24, 0x1a, 0x36, 0xbd, 0xea, 0x5d, 0x65, 0xff, 0x9f, 0x95, 0x70, 0xda, + 0xb0, 0x53, 0x6a, 0x5f, 0x64, 0x7b, 0xb6, 0x7a, 0x8d, 0xa2, 0xd4, 0x9c, + 0xb1, 0xf9, 0xe6, 0x14, 0x62, 0x3b, 0xe7, 0x5b, 0x40, 0x9d, 0xf4, 0x19, + 0xb5, 0x50, 0xc8, 0xbd, 0x76, 0xd3, 0xbc, 0x0e, 0x6d, 0x62, 0x91, 0x73, + 0x3e, 0x7f, 0xbf, 0xd0, 0xf0, 0x33, 0xf8, 0x6a, 0x9f, 0xa6, 0xad, 0xc3, + 0xa0, 0x8f, 0x45, 0x99, 0x86, 0xa7, 0x49, 0x18, 0x8a, 0xed, 0xf1, 0x7d, + 0x39, 0xf4, 0xb4, 0xf9, 0x82, 0x62, 0xd0, 0xa1, 0xb8, 0x3f, 0xe8, 0x25, + 0xf7, 0xb1, 0x59, 0xce, 0x31, 0xba, 0x1d, 0x0b, 0x1f, 0x3d, 0x6c, 0x8b, + 0xd2, 0xc5, 0x4e, 0x8e, 0xe8, 0x09, 0x9e, 0x1f, 0xf3, 0x67, 0x6f, 0x09, + 0x03, 0x9d, 0xfe, 0x57, 0x6d, 0x9b, 0xce, 0x99, 0x7b, 0x01, 0x04, 0x52, + 0xf5, 0x41, 0x7e, 0x38, 0x56, 0xb8, 0x71, 0x44, 0x43, 0x2c, 0x5e, 0x92, + 0x9d, 0x95, 0xff, 0x0b, 0xf8, 0xfa, 0x89, 0x2c, 0x58, 0xde, 0xc5, 0x4e, + 0x02, 0xe3, 0x82, 0xf7, 0xdc, 0x92, 0xa8, 0x7c, 0x39, 0x32, 0x76, 0x68, + 0x9c, 0x73, 0x75, 0x1f, 0xbc, 0x6b, 0x46, 0x33, 0x5a, 0xdb, 0x94, 0x8c, + 0x76, 0x79, 0x7e, 0x9b, 0xcc, 0x37, 0xeb, 0xed, 0xdc, 0xd5, 0xee, 0x2b, + 0x30, 0x3f, 0x7b, 0x9b, 0xac, 0x38, 0x8f, 0xf1, 0x5e, 0xec, 0xa0, 0x46, + 0x2c, 0xd1, 0x27, 0x19, 0x60, 0xec, 0xe2, 0xa7, 0x45, 0x61, 0x2d, 0xa8, + 0x7e, 0xa9, 0xf8, 0x93, 0xa4, 0x23, 0x3e, 0xd8, 0x9c, 0xcc, 0xb3, 0xee, + 0xc3, 0x1c, 0xfb, 0xbb, 0xad, 0xec, 0x73, 0x66, 0x31, 0x5d, 0x88, 0x9a, + 0xec, 0x84, 0x91, 0x1e, 0x58, 0xdd, 0xb0, 0x01, 0x46, 0x18, 0x43, 0x64, + 0xe2, 0xad, 0xac, 0x5a, 0x63, 0x4c, 0x32, 0x6b, 0xfd, 0xff, 0x66, 0x6d, + 0xb4, 0x66, 0x88, 0xec, 0xfe, 0x23, 0xaa, 0x3a, 0x2a, 0xd5, 0xff, 0xed, + 0x3a, 0x13, 0x9a, 0xae, 0x73, 0xc5, 0x62, 0x32, 0x47, 0x89, 0x19, 0x7f, + 0x2c, 0x88, 0x62, 0x34, 0xc2, 0x90, 0xa9, 0x59, 0x7c, 0x45, 0xdb, 0x98, + 0xaf, 0xf4, 0xba, 0x4e, 0x45, 0x55, 0xfc, 0x70, 0xa9, 0xfd, 0xb4, 0xa3, + 0xd9, 0xa8, 0xfb, 0xe2, 0xe6, 0xf9, 0x60, 0xc1, 0x42, 0x70, 0x3d, 0xa5, + 0x28, 0xcc, 0xd3, 0x54, 0x87, 0xda, 0x93, 0x91, 0x42, 0xa8, 0x8b, 0x62, + 0xf3, 0x4e, 0xb7, 0x86, 0xfa, 0x52, 0x19, 0x69, 0xe3, 0x6c, 0xd1, 0xc3, + 0x23, 0x82, 0xf7, 0x1d, 0xa1, 0x80, 0x92, 0xcd, 0x5e, 0x1a, 0x62, 0x3e, + 0x1b, 0x31, 0x9d, 0x0d, 0xa8, 0x25, 0x3e, 0x83, 0xae, 0x36, 0xce, 0xfd, + 0xac, 0xf7, 0x35, 0x7f, 0x74, 0xf4, 0x66, 0xa3, 0x5f, 0x00, 0xe5, 0x30, + 0xc1, 0x11, 0x70, 0x00, 0xb5, 0xd9, 0xd4, 0x6e, 0x95, 0xc4, 0xbc, 0x5b, + 0x7d, 0x62, 0x6c, 0xd5, 0xc0, 0x1e, 0x81, 0xc0, 0x61, 0x69, 0x13, 0x63, + 0xbc, 0x7f, 0x70, 0x3f, 0x3d, 0x96, 0x18, 0x39, 0xef, 0x51, 0xc6, 0xe9, + 0xcc, 0x59, 0xda, 0xc7, 0x5d, 0xb5, 0x59, 0xb0, 0xf2, 0x99, 0x5a, 0x36, + 0x21, 0x0d, 0xcc, 0x97, 0x16, 0x2b, 0x61, 0x3d, 0x0a, 0xd1, 0x6e, 0x05, + 0x86, 0x42, 0xff, 0xd8, 0xa7, 0x5c, 0x02, 0xcf, 0x90, 0x6b, 0x4e, 0xee, + 0x4e, 0xca, 0xdb, 0xd3, 0xfe, 0x7e, 0x9b, 0xe2, 0xf0, 0xa3, 0x45, 0x6d, + 0xa9, 0x92, 0xba, 0xce, 0xc6, 0x2e, 0x0a, 0xbc, 0xb2, 0x7a, 0x57, 0x07, + 0x33, 0xc2, 0xa7, 0x16, 0x25, 0x06, 0x36, 0x83, 0x35, 0x31, 0x87, 0x18, + 0x83, 0xa3, 0xc2, 0x88, 0x55, 0xcc, 0xe4, 0x84, 0x4c, 0xce, 0xb9, 0xeb, + 0xd5, 0xb2, 0xbe, 0x3d, 0x76, 0x85, 0x10, 0x07, 0x83, 0xfa, 0x1c, 0x42, + 0xbc, 0xa3, 0x4c, 0x29, 0x49, 0xe6, 0xc0, 0x30, 0x59, 0xe0, 0xc6, 0xbe, + 0xa7, 0x48, 0x4a, 0xcf, 0x0e, 0x8e, 0xb7, 0x38, 0xf2, 0xa6, 0x26, 0xd3, + 0x88, 0x06, 0x99, 0x46, 0x19, 0x65, 0x1c, 0x91, 0x8e, 0xae, 0x90, 0x78, + 0x77, 0x7f, 0xe0, 0xc2, 0x51, 0x6f, 0xb6, 0x44, 0x15, 0xf9, 0xc5, 0x8a, + 0x6c, 0x33, 0xd5, 0x90, 0x17, 0xc2, 0xca, 0x4e, 0xe1, 0x1f, 0xef, 0x02, + 0x43, 0x05, 0x3f, 0x1e, 0xb1, 0x13, 0x23, 0x1f, 0xd6, 0xc2, 0xac, 0xc4, + 0x49, 0x7a, 0x86, 0x06, 0x4b, 0xa1, 0x55, 0x6a, 0x75, 0x91, 0x4e, 0x6b, + 0x86, 0x95, 0xa7, 0xbc, 0xdc, 0x64, 0xdb, 0x81, 0xc6, 0xa5, 0x33, 0x38, + 0x98, 0xbb, 0xac, 0x03, 0xf0, 0xba, 0x49, 0xcf, 0x1c, 0xce, 0xe2, 0x3d, + 0xe5, 0x06, 0xbc, 0x5e, 0xd0, 0xf7, 0x1c, 0xbb, 0x52, 0xa1, 0x47, 0x98, + 0x12, 0xef, 0x1c, 0xb9, 0x53, 0xec, 0x67, 0x2c, 0xf0, 0x7d, 0x85, 0x9e, + 0x45, 0x87, 0x00, 0x67, 0x2f, 0xa5, 0x19, 0x9f, 0x3e, 0x20, 0x8c, 0xe9, + 0xfa, 0x8a, 0xd8, 0x02, 0x6e, 0x16, 0xc4, 0x43, 0xff, 0x08, 0x3f, 0xf3, + 0x76, 0x53, 0x95, 0x17, 0x6e, 0x74, 0xfe, 0x7e, 0x87, 0x66, 0xc9, 0xe8, + 0x8d, 0x21, 0xea, 0xd2, 0x4d, 0xc7, 0x9c, 0x5a, 0xef, 0xd5, 0xe1, 0x12, + 0x85, 0x22, 0x40, 0x3c, 0x9d, 0x89, 0x4f, 0x12, 0xb5, 0x01, 0x95, 0x0e, + 0x9b, 0xd3, 0x38, 0x5e, 0x21, 0x5a, 0x4e, 0x7e, 0xce, 0xf7, 0xa6, 0x5a, + 0x63, 0x78, 0x40, 0xba, 0x9f, 0x29, 0xf0, 0x75, 0xb6, 0x8b, 0xd9, 0x4c, + 0xab, 0xb9, 0xf4, 0xe9, 0x1f, 0x39, 0x01, 0xb3, 0xfc, 0x2c, 0xa4, 0x74, + 0xa9, 0xa9, 0x90, 0xed, 0x77, 0xd8, 0x0c, 0x6d, 0x5c, 0x7b, 0xfc, 0xbd, + 0x96, 0x96, 0xcb, 0x9b, 0x9f, 0x88, 0x86, 0x5c, 0x3c, 0x0a, 0xde, 0x28, + 0x7c, 0xf0, 0x91, 0x1c, 0x06, 0x52, 0xbe, 0xad, 0xc8, 0xef, 0xa5, 0xd3, + 0x1e, 0x29, 0xbd, 0x1d, 0xd5, 0xba, 0xf4, 0x83, 0x2d, 0x36, 0x9a, 0x8c, + 0x8d, 0x83, 0xac, 0x3f, 0xea, 0xd2, 0x2e, 0xfb, 0xf1, 0xaa, 0x7a, 0x2e, + 0xce, 0xd3, 0x90, 0x9f, 0x3c, 0x2c, 0xee, 0xed, 0xf8, 0xfc, 0x3c, 0x0e, + 0x5f, 0xd1, 0xda, 0x9c, 0x32, 0x52, 0xcd, 0x09, 0xa1, 0x53, 0x33, 0x37, + 0xe0, 0x37, 0x95, 0xb2, 0x8d, 0x03, 0x46, 0x1f, 0xb5, 0x99, 0x65, 0x54, + 0x61, 0xa2, 0xdc, 0xe9, 0x87, 0x4d, 0x41, 0xdf, 0xd1, 0xb5, 0x2c, 0x7a, + 0x46, 0x08, 0x5e, 0x0f, 0xcc, 0x80, 0x96, 0x52, 0x98, 0xa0, 0x82, 0x52, + 0x6d, 0x62, 0x6f, 0xd9, 0x48, 0xc1, 0x36, 0x0c, 0x5c, 0x7f, 0xad, 0x2c, + 0x27, 0xcf, 0x17, 0xee, 0xfa, 0xca, 0x14, 0xe7, 0x88, 0xc4, 0x20, 0xb2, + 0xa1, 0xd2, 0x66, 0xe8, 0x81, 0xce, 0x35, 0x2b, 0x30, 0x54, 0x16, 0x9e, + 0x42, 0x77, 0x16, 0x3b, 0x84, 0x77, 0x42, 0x71, 0x33, 0xf8, 0x62, 0x9e, + 0xd4, 0x1d, 0x1d, 0xf3, 0x91, 0x60, 0x97, 0xd8, 0x10, 0x29, 0xc8, 0xf9, + 0xfa, 0xca, 0x0a, 0xe9, 0x50, 0xe1, 0xcc, 0xa7, 0xe3, 0x77, 0xc2, 0x93, + 0x68, 0x50, 0x1a, 0x98, 0xd7, 0x68, 0x40, 0x80, 0x12, 0x64, 0xa7, 0x1d, + 0xb4, 0x52, 0x85, 0x7b, 0x0e, 0x85, 0x0a, 0x59, 0x6a, 0xc8, 0xe4, 0x4b, + 0xff, 0xd7, 0x0d, 0x7d, 0x9e, 0xef, 0x07, 0x2f, 0x6d, 0x46, 0x05, 0xf9, + 0x05, 0xb1, 0x97, 0x94, 0x23, 0xc5, 0x2a, 0x99, 0xcc, 0x9c, 0xc2, 0x82, + 0x97, 0xbc, 0x24, 0x9b, 0xe4, 0xf2, 0xb3, 0x12, 0x84, 0xa0, 0x2a, 0xc4, + 0x7d, 0x29, 0x4d, 0xa4, 0x97, 0xd0, 0x85, 0xa6, 0x39, 0x18, 0xd2, 0xfb, + 0xa7, 0x08, 0x53, 0x75, 0x6b, 0xbd, 0xe3, 0x98, 0x4c, 0x94, 0xdd, 0xd4, + 0x86, 0x94, 0xc2, 0x6a, 0x14, 0x23, 0xdd, 0x69, 0xae, 0x53, 0xec, 0x83, + 0x58, 0x8e, 0x87, 0x7b, 0xf1, 0xcf, 0xff, 0x34, 0xda, 0x39, 0x67, 0xba, + 0x90, 0xc5, 0xec, 0xe0, 0xb3, 0xad, 0xad, 0x3d, 0x4c, 0x8e, 0x3f, 0x08, + 0x62, 0x80, 0x5b, 0x2d, 0xf8, 0xe1, 0x67, 0x61, 0x79, 0xf5, 0xc9, 0xbe, + 0x74, 0x1b, 0x72, 0x02, 0x56, 0xc6, 0xf8, 0xd5, 0x87, 0x3a, 0x08, 0x7b, + 0x35, 0x8f, 0xdf, 0xdf, 0x87, 0x3e, 0x09, 0xf7, 0xd2, 0x74, 0xbb, 0xec, + 0x8c, 0x49, 0x0c, 0xb5, 0x3a, 0x6b, 0x33, 0x43, 0x52, 0xe2, 0x2f, 0x71, + 0x3e, 0x6f, 0x59, 0x52, 0x50, 0x8f, 0xdb, 0xa6, 0x52, 0xa7, 0x5d, 0xda, + 0x16, 0x71, 0xb2, 0x52, 0xd7, 0x3e, 0x2d, 0xf6, 0x98, 0x53, 0x0f, 0x8f, + 0xc1, 0x79, 0xd0, 0xcf, 0xe0, 0xc8, 0x22, 0x27, 0x41, 0x14, 0xe8, 0xb8, + 0xed, 0x65, 0x3c, 0xaa, 0x11, 0x72, 0x41, 0xa8, 0xd8, 0x0b, 0x35, 0x81, + 0xec, 0xa6, 0x12, 0x30, 0x23, 0x0b, 0x71, 0x7a, 0x28, 0xd9, 0x01, 0x82, + 0x35, 0xd1, 0x64, 0x6d, 0xf3, 0x63, 0x69, 0x78, 0xb4, 0x93, 0x1e, 0x05, + 0xc9, 0xb3, 0xbc, 0xb6, 0xc4, 0x5e, 0xb6, 0x2a, 0x6e, 0xec, 0x91, 0x4a, + 0x5c, 0xa2, 0x5c, 0xea, 0x2b, 0xe3, 0x33, 0x1a, 0xb3, 0x70, 0xd5, 0x39, + 0x77, 0x3e, 0xa2, 0x96, 0xd5, 0x10, 0x75, 0x8a, 0x91, 0xc6, 0xbc, 0xb6, + 0x86, 0xa6, 0x8f, 0xd3, 0x50, 0x09, 0xa3, 0x9a, 0x1f, 0xd0, 0xd7, 0xd7, + 0x23, 0xa0, 0x32, 0xd0, 0x69, 0x33, 0x2f, 0x18, 0xf2, 0x6f, 0xe2, 0xbc, + 0x2f, 0x7f, 0xf5, 0x46, 0x81, 0x2e, 0xad, 0x14, 0xc9, 0x57, 0x10, 0xa4, + 0x71, 0xa9, 0xa4, 0x05, 0x50, 0xcb, 0x93, 0xc7, 0x53, 0x84, 0x68, 0xa5, + 0x7c, 0x65, 0xc0, 0xe0, 0x37, 0xd6, 0xc3, 0xbb, 0x36, 0xef, 0x22, 0x9e, + 0x09, 0x32, 0xa5, 0xa6, 0x73, 0x61, 0xb6, 0x3c, 0x5a, 0xbe, 0x2f, 0x63, + 0x01, 0x35, 0xfe, 0xd8, 0x98, 0xd5, 0x7e, 0xfd, 0x68, 0xd8, 0x96, 0x51, + 0x6e, 0x3a, 0x17, 0x90, 0x16, 0xeb, 0x03, 0xfa, 0x0a, 0x83, 0x1a, 0xc9, + 0x48, 0x14, 0x31, 0x32, 0x07, 0x7d, 0xa8, 0xa8, 0x64, 0xd8, 0xba, 0xcf, + 0x87, 0xc5, 0x0e, 0xc3, 0x1c, 0x5b, 0xfe, 0x31, 0x98, 0xea, 0x25, 0x29, + 0x9c, 0x77, 0xf2, 0x9f, 0x5e, 0x16, 0x11, 0x6b, 0x29, 0x08, 0xab, 0xb0, + 0x57, 0xd8, 0x3d, 0x85, 0xdc, 0x3b, 0x69, 0xea, 0xd5, 0xe6, 0x90, 0xfa, + 0x95, 0x8d, 0xcc, 0x3c, 0x2d, 0x86, 0x07, 0xc6, 0x7e, 0x8d, 0xc4, 0x7a, + 0x3a, 0xcd, 0x61, 0xa4, 0x1f, 0xd9, 0x6f, 0x07, 0xa3, 0x45, 0xe8, 0x41, + 0xed, 0x51, 0x14, 0xe4, 0x3d, 0x20, 0x3b, 0x11, 0x9e, 0x93, 0xc3, 0x2e, + 0xcd, 0x29, 0x85, 0xf0, 0x61, 0x68, 0x8e, 0x19, 0xdc, 0x20, 0x0a, 0xbd, + 0xc0, 0x15, 0x90, 0x08, 0x96, 0xcf, 0x9b, 0xf3, 0xb5, 0x7b, 0xe4, 0x9a, + 0x97, 0x22, 0x93, 0x40, 0xd4, 0xde, 0x7a, 0x6e, 0x6b, 0xc4, 0x16, 0x9e, + 0x1c, 0x98, 0x9b, 0x83, 0x6e, 0x4d, 0xde, 0x11, 0x4f, 0x22, 0xed, 0x2d, + 0xe1, 0xb3, 0xfa, 0x86, 0xb0, 0xd2, 0x53, 0xd2, 0x34, 0x8a, 0x58, 0xdc, + 0x8c, 0xd9, 0x60, 0xd3, 0x46, 0x0a, 0xde, 0x48, 0xa3, 0xda, 0x5b, 0x74, + 0x3e, 0x4c, 0x51, 0xa6, 0x02, 0x20, 0xc6, 0x0d, 0xdb, 0x13, 0x42, 0xad, + 0xc6, 0x90, 0xb1, 0xe0, 0xb0, 0xac, 0xdc, 0xa7, 0x48, 0xf8, 0x2d, 0x8f, + 0xd7, 0xd9, 0x10, 0xeb, 0xd8, 0xdb, 0xf0, 0x53, 0x67, 0xa9, 0x03, 0x3e, + 0x97, 0xbf, 0xe6, 0xc3, 0xa8, 0x87, 0x3a, 0x91, 0xb8, 0xcf, 0x88, 0x5b, + 0x0d, 0x06, 0xe1, 0xe2, 0x39, 0x74, 0xc8, 0x59, 0xe0, 0x90, 0x9f, 0xc9, + 0x0a, 0x74, 0xa3, 0xb2, 0xae, 0x69, 0x79, 0xfa, 0x0d, 0xf2, 0xee, 0xde, + 0xec, 0x88, 0xbf, 0x09, 0x54, 0xd6, 0xbe, 0xbb, 0x25, 0x91, 0xe4, 0x66, + 0xd2, 0x08, 0x78, 0xda, 0x9d, 0x07, 0xc3, 0x0b, 0x3f, 0x1a, 0xd9, 0xf4, + 0xb2, 0x2d, 0x69, 0x74, 0xb1, 0x78, 0x5f, 0xc1, 0xaf, 0x7f, 0x6d, 0x17, + 0xfc, 0x2c, 0x67, 0x62, 0xce, 0xb4, 0x41, 0x6e, 0x21, 0x4b, 0x5c, 0x77, + 0xa1, 0x1f, 0xfe, 0xe6, 0x28, 0xc8, 0x52, 0xd1, 0x8e, 0x66, 0x88, 0x65, + 0x0c, 0x58, 0xec, 0x1c, 0x71, 0x4c, 0x8a, 0xc0, 0xef, 0x3e, 0x34, 0xf7, + 0x90, 0x67, 0x28, 0x16, 0x20, 0x3a, 0x2c, 0x3f, 0x51, 0x53, 0x15, 0x1c, + 0x6c, 0x75, 0x0e, 0xe1, 0xb4, 0xf3, 0x7f, 0x60, 0x3a, 0x81, 0x34, 0x82, + 0x51, 0x5e, 0x75, 0xb0, 0x5c, 0x37, 0x87, 0x2d, 0xd5, 0xc5, 0x2c, 0xab, + 0x33, 0x8a, 0x60, 0x49, 0x2c, 0xde, 0x90, 0x12, 0x11, 0x1f, 0x4b, 0x27, + 0x15, 0x92, 0xa2, 0xf1, 0x1a, 0xde, 0x35, 0x34, 0x4d, 0x52, 0xcd, 0xc0, + 0x71, 0x46, 0x7f, 0x3e, 0x21, 0x92, 0x5f, 0xc8, 0x25, 0xd4, 0x2c, 0xf4, + 0xd9, 0x38, 0xde, 0xa5, 0xae, 0x83, 0xe3, 0x50, 0x9b, 0x1b, 0xad, 0x4b, + 0xd8, 0x3f, 0x0a, 0x23, 0x40, 0x1e, 0x46, 0x7a, 0x71, 0x06, 0xac, 0x9e, + 0x06, 0xb8, 0x96, 0xef, 0x07, 0xef, 0x38, 0xe9, 0x79, 0xaa, 0x64, 0x44, + 0xa9, 0xa3, 0xc5, 0x1d, 0x5d, 0xd3, 0xa7, 0x01, 0xef, 0xf6, 0x3b, 0x15, + 0x00, 0x0c, 0xf7, 0x59, 0x4a, 0x1c, 0x12, 0x20, 0x89, 0xa8, 0x4e, 0x7b, + 0xf8, 0x9d, 0x02, 0xa6, 0x5e, 0x19, 0x7e, 0xb8, 0x5f, 0x46, 0xd9, 0xb1, + 0xbe, 0x25, 0x2c, 0x3c, 0xe7, 0x5d, 0x3b, 0x3f, 0x6f, 0x6e, 0x94, 0x83, + 0xc3, 0x8e, 0x85, 0x65, 0xff, 0xe9, 0x8e, 0x32, 0xcc, 0x68, 0x51, 0x14, + 0xbf, 0x94, 0x21, 0x3f, 0x85, 0xa8, 0x76, 0x44, 0xe6, 0xca, 0x20, 0x84, + 0xec, 0x83, 0x84, 0x64, 0xfb, 0x80, 0x01, 0x73, 0x76, 0x21, 0xd3, 0xf0, + 0x7b, 0x74, 0x5c, 0xbf, 0x71, 0xe6, 0x34, 0xff, 0x58, 0xe8, 0x6f, 0x88, + 0xa6, 0xad, 0xcf, 0x93, 0x2a, 0xc5, 0xc5, 0x23, 0x32, 0xc8, 0xec, 0xbd, + 0xf9, 0x54, 0x3d, 0xda, 0xe4, 0x81, 0x74, 0x94, 0xbf, 0x36, 0x72, 0x11, + 0xf0, 0x8a, 0x8f, 0x1b, 0x55, 0x47, 0x70, 0x7d, 0x61, 0xf0, 0x7b, 0x11, + 0x56, 0xdb, 0xbc, 0xe5, 0x72, 0xf2, 0xbd, 0x0b, 0xa0, 0x80, 0x03, 0x1a, + 0xc6, 0xe9, 0xfc, 0xcd, 0xde, 0x42, 0xae, 0x1a, 0x7d, 0x90, 0x5d, 0x21, + 0x5b, 0x3d, 0x69, 0x6f, 0x42, 0x42, 0xf2, 0x8a, 0xc8, 0xfc, 0xb9, 0xa9, + 0xdf, 0x18, 0xc4, 0x97, 0x91, 0x21, 0x28, 0xfd, 0x82, 0x8a, 0xe7, 0xac, + 0xe5, 0x5d, 0x33, 0x7b, 0x78, 0x0a, 0x48, 0x43, 0xfe, 0xfe, 0xcf, 0x09, + 0x5f, 0xed, 0x18, 0x33, 0x0c, 0xab, 0x8a, 0x5d, 0x63, 0xd5, 0x43, 0x0b, + 0xde, 0x75, 0x56, 0xef, 0x11, 0x05, 0x8c, 0xbb, 0xc0, 0x10, 0x4e, 0x85, + 0x70, 0xe1, 0x7e, 0x62, 0xb6, 0x3a, 0x84, 0x80, 0x17, 0xab, 0x38, 0x59, + 0x0b, 0xe2, 0xb1, 0x31, 0xb8, 0xb5, 0xf5, 0xad, 0xf6, 0xbf, 0x5b, 0xfb, + 0x69, 0xc8, 0xb3, 0xce, 0x65, 0xd4, 0x8e, 0x04, 0xc5, 0xc4, 0x09, 0xba, + 0x36, 0xc9, 0x90, 0xe0, 0xc2, 0x21, 0x3a, 0x94, 0x83, 0xa5, 0xd1, 0xb2, + 0xe1, 0xae, 0x6a, 0x28, 0x22, 0x59, 0x79, 0x72, 0x82, 0x42, 0x89, 0x42, + 0x9c, 0xc3, 0xdf, 0x8d, 0x15, 0x22, 0x14, 0xb3, 0xfd, 0x2a, 0x85, 0xbe, + 0xd3, 0x12, 0xa5, 0x3b, 0x0c, 0x99, 0xb2, 0xe5, 0x43, 0x8d, 0xd7, 0xc0, + 0xa1, 0xb6, 0xb2, 0xae, 0x42, 0x4a, 0xc0, 0xe5, 0x09, 0xa2, 0xf6, 0xa4, + 0xbc, 0x01, 0xee, 0x94, 0xd2, 0x0b, 0xeb, 0x28, 0x80, 0xc9, 0x7a, 0x07, + 0xd7, 0x4b, 0xee, 0x01, 0x10, 0x48, 0xcc, 0xc6, 0x03, 0x99, 0x9d, 0x67, + 0x2a, 0xbd, 0xa0, 0x6f, 0x51, 0xa4, 0x75, 0x50, 0xe1, 0x84, 0x8e, 0xda, + 0x7b, 0x5e, 0x9e, 0x78, 0x18, 0x2a, 0x6b, 0xfa, 0xef, 0x87, 0x81, 0xe9, + 0x48, 0x3f, 0x29, 0x2d, 0xfb, 0x15, 0xd2, 0x15, 0xb5, 0x5c, 0xed, 0x45, + 0x48, 0x30, 0xec, 0x00, 0x55, 0x15, 0x13, 0xc7, 0x11, 0xc4, 0x29, 0xef, + 0x0f, 0xa8, 0xa6, 0xef, 0x19, 0x41, 0xc2, 0xb6, 0x11, 0xdc, 0xe8, 0xf4, + 0xa7, 0x03, 0x80, 0x2d, 0x92, 0xad, 0x7e, 0x7e, 0x8a, 0x71, 0xa4, 0x6c, + 0x16, 0xb9, 0x84, 0xf5, 0x8d, 0x94, 0xc5, 0xd5, 0x82, 0x29, 0x42, 0x22, + 0x1f, 0x06, 0xca, 0xdd, 0xbf, 0x74, 0x0f, 0x14, 0x79, 0x26, 0x9c, 0x79, + 0x30, 0xcb, 0x01, 0x02, 0x76, 0x22, 0x4f, 0x54, 0xff, 0x49, 0xa3, 0x03, + 0x35, 0x23, 0x45, 0x91, 0xac, 0xed, 0x13, 0x31, 0xa4, 0x4e, 0x51, 0xe8, + 0x9c, 0x5b, 0xe4, 0xcf, 0x41, 0xd3, 0xa0, 0x86, 0x7f, 0x3a, 0x4d, 0xaf, + 0xa7, 0x49, 0x63, 0x47, 0x86, 0x08, 0x88, 0xcf, 0x01, 0x7a, 0xc4, 0xf5, + 0x29, 0x67, 0x8a, 0xd4, 0xdd, 0x6a, 0x6d, 0x81, 0xb8, 0x29, 0x9d, 0x7c, + 0x32, 0x4e, 0x8f, 0x0c, 0x9f, 0x8c, 0x7e, 0x76, 0xa3, 0xd4, 0x32, 0x80, + 0xd0, 0x79, 0x7d, 0x56, 0x99, 0x6d, 0x0b, 0x88, 0xfc, 0x98, 0xdb, 0xaf, + 0x13, 0xf3, 0xb2, 0x20, 0x3f, 0x19, 0xe1, 0x83, 0x70, 0xd2, 0x26, 0xd0, + 0xd2, 0xad, 0x11, 0xeb, 0x3b, 0x31, 0x03, 0x55, 0x62, 0xca, 0xb5, 0x87, + 0x31, 0x7a, 0x11, 0x4c, 0xf2, 0xc3, 0xc2, 0x1c, 0x42, 0x94, 0x7b, 0xe6, + 0x29, 0x86, 0x70, 0x8e, 0x51, 0x4a, 0xa3, 0xf2, 0xf0, 0xed, 0xa1, 0xc6, + 0x18, 0xff, 0xf2, 0xff, 0xe0, 0x07, 0x85, 0xf1, 0x93, 0x5a, 0x83, 0x1c, + 0x4c, 0xa9, 0x9b, 0xc5, 0x0c, 0xc4, 0xf0, 0xde, 0x71, 0x93, 0x78, 0xd1, + 0x3b, 0xcc, 0x5b, 0x51, 0x1f, 0xd7, 0x21, 0x12, 0x57, 0xd5, 0x2a, 0xea, + 0x64, 0x08, 0x0e, 0xf0, 0x3d, 0x42, 0xe7, 0xdf, 0xc8, 0xea, 0x42, 0x2b, + 0x41, 0x55, 0x85, 0xb8, 0x54, 0xa4, 0xc9, 0x3f, 0xce, 0xfc, 0x1a, 0xde, + 0x73, 0x08, 0xaa, 0x09, 0x25, 0x08, 0xa0, 0xdc, 0x64, 0xb7, 0xe7, 0xcc, + 0xde, 0x85, 0xa6, 0xc3, 0xe9, 0xe1, 0x43, 0x71, 0x86, 0x05, 0x55, 0x86, + 0x47, 0xf8, 0x71, 0xbd, 0xf5, 0xd7, 0x38, 0x64, 0x7f, 0x71, 0x63, 0xe1, + 0x22, 0x39, 0x99, 0xc3, 0xdf, 0x27, 0x5d, 0xdd, 0xd0, 0x57, 0x99, 0xd5, + 0x97, 0xcd, 0xd4, 0x2e, 0xc1, 0x25, 0x3d, 0x2e, 0x03, 0x0b, 0x04, 0x20, + 0x70, 0xec, 0x46, 0x6c, 0x4b, 0x55, 0x16, 0x02, 0x00, 0x71, 0xfd, 0x8a, + 0xa0, 0x1e, 0x5f, 0x41, 0xe6, 0x96, 0x58, 0xbe, 0x02, 0x73, 0x91, 0x71, + 0xb2, 0x7e, 0xc4, 0xcd, 0xce, 0xa5, 0x26, 0xee, 0xff, 0x8c, 0x9a, 0x4c, + 0xf4, 0x0a, 0x89, 0xba, 0x14, 0x6e, 0x06, 0x86, 0xb0, 0xba, 0x41, 0xdd, + 0x27, 0xf8, 0xc3, 0x46, 0x4f, 0x39, 0xac, 0x2c, 0x8a, 0x69, 0x09, 0xb7, + 0x36, 0x0f, 0xe0, 0x8d, 0x31, 0x0f, 0xc3, 0xee, 0x3a, 0x6a, 0x9e, 0x96, + 0x91, 0xf5, 0x6a, 0x12, 0x98, 0x5a, 0xc3, 0xf3, 0xb8, 0x9b, 0x07, 0xdb, + 0x8e, 0x2a, 0xb0, 0x91, 0x86, 0xb5, 0xc7, 0xe9, 0x06, 0xe1, 0x4e, 0x83, + 0x28, 0x3a, 0x0e, 0x67, 0xe5, 0x7e, 0x88, 0x2a, 0x31, 0xd2, 0xfe, 0xf6, + 0x19, 0x3d, 0x09, 0xd1, 0xef, 0x5d, 0xe1, 0x15, 0x2d, 0xb4, 0xec, 0x23, + 0xc2, 0x0c, 0x7a, 0xbf, 0xd3, 0x6f, 0xf7, 0x8a, 0x3b, 0x3a, 0x0f, 0x20, + 0xc4, 0x78, 0xbe, 0x46, 0x30, 0x0f, 0xc2, 0xd0, 0x8c, 0x23, 0xb7, 0xfa, + 0x3c, 0x19, 0x35, 0x53, 0x5f, 0xf9, 0x94, 0xf5, 0x23, 0xbe, 0xb3, 0x56, + 0x42, 0xa1, 0x27, 0xff, 0xac, 0xbf, 0x72, 0x7e, 0x89, 0xbe, 0xb9, 0x6d, + 0x2d, 0xc4, 0x3f, 0x6c, 0x7f, 0xc4, 0x7e, 0x01, 0x09, 0xc8, 0x35, 0x80, + 0x99, 0x8f, 0x1c, 0x43, 0xd3, 0xb2, 0x4a, 0xb7, 0x08, 0x06, 0x63, 0xcd, + 0x8a, 0x5e, 0x64, 0xa2, 0x93, 0xa5, 0x15, 0xa0, 0x38, 0xa0, 0xf2, 0x1c, + 0xab, 0xe1, 0x2d, 0x19, 0x30, 0xee, 0x9b, 0x87, 0x42, 0x54, 0xfb, 0xcc, + 0xfe, 0x2a, 0xcd, 0x54, 0xf5, 0xeb, 0x52, 0x6b, 0xd4, 0x1d, 0xa3, 0x7c, + 0xec, 0xf2, 0x56, 0x51, 0x54, 0xab, 0x66, 0xb0, 0x73, 0x49, 0x3e, 0xc4, + 0x89, 0xac, 0xb0, 0xc1, 0x41, 0x6f, 0x19, 0xd6, 0x41, 0xbd, 0xc2, 0xe2, + 0x1a, 0x56, 0xb3, 0x01, 0xc9, 0xdf, 0x46, 0xe7, 0xa1, 0x42, 0xfa, 0x1c, + 0x18, 0x86, 0xe2, 0x07, 0xe4, 0xfe, 0x19, 0x03, 0x7d, 0xc4, 0x51, 0x78, + 0x29, 0x68, 0x73, 0x70, 0x82, 0x98, 0x34, 0x2e, 0x41, 0x59, 0xd5, 0x20, + 0x36, 0xe3, 0xe5, 0x2c, 0xbe, 0x76, 0x23, 0x5d, 0xb1, 0xf0, 0xda, 0xee, + 0x65, 0x54, 0xd9, 0xa1, 0x77, 0x6e, 0xd8, 0x56, 0xcb, 0x6a, 0x35, 0xb5, + 0xaa, 0x97, 0x22, 0x28, 0x4d, 0x74, 0x13, 0x96, 0x59, 0x3d, 0x3a, 0xe2, + 0x26, 0xde, 0xd3, 0xc7, 0xed, 0x97, 0x98, 0xa8, 0x4a, 0x6b, 0x4b, 0xd1, + 0x52, 0xca, 0x84, 0xd6, 0x19, 0x7a, 0x6c, 0x0d, 0xb4, 0x28, 0x4f, 0xb1, + 0xa2, 0xcc, 0x07, 0x08, 0x57, 0xc9, 0x32, 0xd4, 0xe0, 0xef, 0x96, 0x9a, + 0x31, 0x1e, 0x68, 0x1d, 0x7b, 0x57, 0x26, 0x62, 0xa4, 0x26, 0xaf, 0xc7, + 0xd0, 0xab, 0xb6, 0x9e, 0x00, 0x6d, 0xfe, 0x29, 0x30, 0x53, 0xcd, 0xb8, + 0x4e, 0x30, 0x4e, 0xa5, 0xcc, 0xf6, 0xab, 0xca, 0x4d, 0x74, 0x40, 0xc2, + 0xb4, 0xfb, 0x3f, 0x75, 0x0a, 0x9d, 0x88, 0xa3, 0xb0, 0x5b, 0x4e, 0x88, + 0x50, 0x90, 0xcb, 0x5c, 0xcd, 0xc7, 0xff, 0x75, 0x97, 0xc4, 0x1b, 0xe9, + 0x03, 0x8a, 0xa7, 0x62, 0x32, 0x98, 0x60, 0x39, 0x56, 0xe5, 0x25, 0xed, + 0xba, 0x58, 0x67, 0xa3, 0xe8, 0x23, 0xd1, 0x55, 0xb3, 0xa5, 0xc0, 0xc9, + 0x75, 0x14, 0x91, 0xe6, 0x7d, 0x0e, 0xe3, 0xac, 0xc8, 0x6b, 0xa7, 0xdb, + 0x36, 0xe8, 0x44, 0x92, 0x72, 0xf2, 0x6d, 0x10, 0xeb, 0xd0, 0x7a, 0xdd, + 0x00, 0x9b, 0xf8, 0x65, 0xaa, 0xef, 0xed, 0xfb, 0x84, 0x5f, 0xfb, 0xd8, + 0xe9, 0xa8, 0x71, 0xab, 0x20, 0x98, 0x4f, 0x21, 0x7d, 0x33, 0xe2, 0xb1, + 0x3f, 0x95, 0x9c, 0x28, 0xf5, 0xd5, 0x83, 0x01, 0xe9, 0x71, 0x68, 0xa9, + 0x3d, 0x9e, 0x49, 0xfb, 0x6c, 0x83, 0x5f, 0x48, 0x9d, 0x91, 0x00, 0xab, + 0x54, 0x17, 0x11, 0x5b, 0x9d, 0x0a, 0x17, 0x8e, 0x3a, 0xbc, 0xd5, 0x33, + 0xcd, 0x2a, 0x5b, 0x14, 0x39, 0xe4, 0x30, 0x45, 0xde, 0x6e, 0xde, 0x92, + 0x7f, 0xb5, 0x91, 0x5d, 0x5b, 0xe4, 0x18, 0x17, 0x7c, 0x22, 0x1e, 0x2d, + 0x97, 0x8b, 0x6f, 0xe0, 0x54, 0x2e, 0x25, 0xbc, 0x5f, 0xef, 0x27, 0x1b, + 0x95, 0x71, 0xcc, 0x29, 0x96, 0x30, 0x82, 0xb1, 0x99, 0x98, 0x28, 0x36, + 0x5f, 0xd6, 0xf9, 0x13, 0xb3, 0x3d, 0x14, 0x91, 0x8a, 0x2f, 0xbf, 0x6e, + 0x8c, 0x57, 0xf6, 0x8e, 0x32, 0xf2, 0xd3, 0xa5, 0x1b, 0x2b, 0xba, 0xc8, + 0x0d, 0xa4, 0xd3, 0xc2, 0x16, 0x1f, 0x5f, 0xb6, 0x89, 0x77, 0xa9, 0xf3, + 0x7b, 0xb8, 0x11, 0x23, 0x41, 0xd6, 0xe0, 0x47, 0x3c, 0x94, 0xe0, 0xed, + 0xa9, 0xb1, 0x0e, 0x90, 0x38, 0xdd, 0x60, 0xcd, 0x75, 0x00, 0x36, 0x3a, + 0x42, 0xbb, 0xfd, 0xd7, 0xc6, 0x16, 0x38, 0xb4, 0xc0, 0x1d, 0xb6, 0x46, + 0x5c, 0x2f, 0x70, 0x95, 0x8d, 0x74, 0x68, 0xb2, 0xb5, 0xae, 0x73, 0x22, + 0xa1, 0xca, 0x5d, 0xd4, 0x28, 0x1a, 0xd2, 0x19, 0x1c, 0x43, 0x5e, 0x12, + 0x16, 0x15, 0xb4, 0x97, 0x64, 0x10, 0x07, 0x48, 0xf8, 0xe3, 0xfb, 0x3e, + 0xa5, 0x05, 0xcd, 0xc1, 0x29, 0xf0, 0x67, 0xb7, 0x24, 0x02, 0xac, 0x76, + 0x91, 0x64, 0x63, 0x46, 0xfb, 0xfd, 0xaa, 0x5b, 0x3f, 0xeb, 0xe0, 0xb2, + 0x5a, 0x8d, 0xde, 0xdc, 0x92, 0x0c, 0x1e, 0xfc, 0x82, 0x55, 0xc7, 0x8a, + 0xe3, 0x28, 0x57, 0xfe, 0x10, 0xe1, 0xa3, 0x5a, 0x9e, 0x67, 0x86, 0xf4, + 0xa5, 0xf5, 0xa0, 0xbd, 0xa4, 0x3c, 0xda, 0xf3, 0x83, 0x27, 0x2f, 0x55, + 0x73, 0xb6, 0x74, 0x3e, 0xd3, 0xc9, 0x84, 0x1d, 0xff, 0x61, 0x01, 0x56, + 0x30, 0x2a, 0x23, 0x57, 0xbc, 0x88, 0xa7, 0x2f, 0x6f, 0x95, 0x91, 0x4e, + 0x5b, 0x41, 0xd9, 0x95, 0x1f, 0x09, 0x95, 0x79, 0x36, 0xe3, 0x7f, 0xbd, + 0x4b, 0x09, 0x4e, 0x7f, 0x6a, 0x58, 0x6e, 0xd0, 0x60, 0xaf, 0xf1, 0x8f, + 0x4c, 0xc5, 0x5a, 0x5c, 0xb7, 0x74, 0x83, 0x3c, 0xb3, 0x7e, 0xdc, 0x76, + 0x89, 0xa5, 0xca, 0xd7, 0x75, 0x35, 0xb2, 0x4c, 0x0a, 0x67, 0x2b, 0x7a, + 0xe8, 0xac, 0x9e, 0x26, 0xa3, 0xae, 0x87, 0x66, 0x12, 0x4e, 0x74, 0xc8, + 0xd8, 0x6d, 0x89, 0x9c, 0x34, 0x63, 0x61, 0x33, 0x1b, 0x6a, 0x78, 0x7f, + 0x2f, 0xa7, 0x9b, 0xe7, 0x42, 0x0d, 0xcb, 0xc9, 0xf0, 0xa6, 0xb5, 0x38, + 0x66, 0x80, 0xca, 0x7a, 0xa9, 0xe4, 0x93, 0xe3, 0xfc, 0x7d, 0x38, 0x7d, + 0x7a, 0x2c, 0x03, 0xb4, 0x35, 0xde, 0x1b, 0x2e, 0x29, 0x24, 0x40, 0x93, + 0x6c, 0x52, 0x21, 0xd6, 0x70, 0x88, 0xfd, 0xc7, 0x5c, 0x94, 0x95, 0xc0, + 0x03, 0xce, 0x1b, 0xb3, 0x0e, 0x87, 0xac, 0xa0, 0x88, 0xcd, 0x20, 0x3d, + 0x88, 0x6f, 0xac, 0x29, 0x2e, 0xcc, 0x7d, 0xa7, 0x09, 0x16, 0xc0, 0xcc, + 0x55, 0x43, 0x19, 0xdc, 0x5e, 0xc4, 0xe5, 0x7c, 0xfb, 0x50, 0x01, 0x41, + 0xe1, 0x70, 0x84, 0x3e, 0x60, 0x88, 0x05, 0x27, 0x4b, 0x6c, 0x59, 0x9a, + 0x01, 0x50, 0xec, 0x74, 0x6a, 0x98, 0x57, 0xfe, 0xf5, 0x63, 0xc3, 0x60, + 0x55, 0x23, 0x33, 0xf9, 0x2d, 0xf0, 0x68, 0xff, 0xad, 0x61, 0xdb, 0x5e, + 0xdb, 0x0c, 0x54, 0x68, 0x8c, 0x4b, 0x64, 0x94, 0x3c, 0xa8, 0xb1, 0x31, + 0x61, 0xf3, 0xb3, 0xed, 0x8f, 0xd5, 0x07, 0x27, 0xbf, 0xa3, 0xa2, 0x42, + 0x4a, 0xa1, 0x5e, 0xc9, 0xb3, 0x9a, 0x0f, 0xbb, 0xf7, 0xc7, 0x4d, 0x0b, + 0xee, 0xbd, 0xce, 0x9e, 0x8c, 0x14, 0x7e, 0x06, 0x6e, 0x6d, 0x9b, 0xdd, + 0x22, 0xc6, 0xc2, 0x62, 0xa5, 0x45, 0xc1, 0xe1, 0x97, 0xe2, 0x50, 0x25, + 0xcc, 0x9b, 0xc4, 0x5d, 0x2d, 0x45, 0x10, 0xad, 0xa8, 0x4f, 0x27, 0xc3, + 0x1a, 0x2c, 0xef, 0x38, 0x2d, 0xa7, 0xaf, 0xe5, 0x23, 0x7a, 0x8f, 0xbf, + 0x9c, 0xd0, 0xb6, 0x31, 0x5c, 0xaa, 0xd2, 0x8c, 0xd8, 0x91, 0x00, 0xa1, + 0x8b, 0x4d, 0x3e, 0x27, 0x22, 0x6c, 0x0f, 0x64, 0x95, 0x89, 0xa6, 0x29, + 0x90, 0xf9, 0xa9, 0x24, 0x24, 0xb8, 0x71, 0x56, 0x7a, 0xc5, 0xa9, 0x26, + 0x9f, 0xf6, 0x2a, 0xa6, 0xf1, 0xca, 0x2a, 0x17, 0x14, 0x8c, 0x8d, 0xf2, + 0x44, 0x7d, 0x49, 0x4e, 0x9b, 0x4f, 0xef, 0x72, 0x7e, 0xe8, 0x0f, 0x45, + 0xb3, 0x3d, 0x61, 0xf5, 0x9d, 0x3f, 0x9a, 0xe3, 0x93, 0xdd, 0x3d, 0x02, + 0x84, 0x7d, 0xd4, 0x84, 0xa8, 0x23, 0xe9, 0x43, 0xb6, 0x66, 0xf2, 0xb7, + 0x35, 0xcf, 0xa3, 0x2f, 0xbe, 0x48, 0x0e, 0xaa, 0xfe, 0xe9, 0x7e, 0xb0, + 0x4d, 0xb3, 0x6b, 0x69, 0xdc, 0xef, 0x20, 0xec, 0xce, 0x6c, 0xad, 0x7a, + 0x20, 0x35, 0xf2, 0xfd, 0x09, 0xe1, 0xdb, 0xca, 0x2a, 0x55, 0xf7, 0x60, + 0xca, 0xf3, 0x85, 0x12, 0xe6, 0x05, 0x4f, 0xc8, 0x6e, 0x76, 0xda, 0x5f, + 0x45, 0x1e, 0xed, 0xdf, 0x57, 0x4c, 0xeb, 0x7e, 0x28, 0xf7, 0x39, 0xc4, + 0xd0, 0x10, 0x32, 0xa9, 0xcc, 0x25, 0xd9, 0x0b, 0x8c, 0x8a, 0xf6, 0x6c, + 0x84, 0xde, 0x09, 0x8c, 0xf6, 0xa4, 0x95, 0xb3, 0x65, 0x5e, 0x49, 0x36, + 0x8c, 0x51, 0x85, 0x62, 0xcc, 0xe6, 0x2a, 0x3d, 0xdc, 0x68, 0x08, 0x41, + 0x73, 0x18, 0x74, 0x10, 0xe5, 0x18, 0xfa, 0xbe, 0x2f, 0xaa, 0x98, 0x3c, + 0x7c, 0x44, 0x43, 0x3f, 0xd6, 0x27, 0xd3, 0x28, 0xf0, 0x2b, 0xeb, 0xf2, + 0x46, 0xfc, 0xf6, 0x3f, 0xc7, 0xa8, 0xc0, 0xf0, 0x17, 0xef, 0x35, 0xde, + 0x55, 0x30, 0xef, 0xf7, 0x7b, 0x57, 0xf3, 0x9f, 0x00, 0xb5, 0x49, 0x1e, + 0xc4, 0x6a, 0xea, 0x0e, 0x40, 0x95, 0x47, 0x55, 0x32, 0x4f, 0x4f, 0x24, + 0x5a, 0x10, 0xaa, 0x1f, 0x5b, 0x9b, 0xc1, 0xb3, 0xaa, 0xa3, 0x40, 0x32, + 0x56, 0x80, 0xbf, 0x38, 0xbc, 0x89, 0xad, 0xa8, 0x0e, 0x8f, 0x8e, 0x14, + 0x17, 0x5a, 0x9b, 0x25, 0x85, 0x85, 0xa7, 0x43, 0xc8, 0x19, 0x21, 0xf9, + 0xa3, 0xdc, 0xb9, 0xc8, 0x70, 0x7b, 0xc8, 0x42, 0x38, 0x50, 0xb9, 0xcf, + 0x90, 0x6e, 0x88, 0x7f, 0x5a, 0x56, 0xc8, 0xd7, 0x84, 0x7b, 0x69, 0xe1, + 0x31, 0x6d, 0xe9, 0xc7, 0x7f, 0x39, 0x78, 0x52, 0xa2, 0x0c, 0xc7, 0x3b, + 0x89, 0x05, 0x9d, 0x66, 0xc6, 0xea, 0x48, 0x75, 0xa5, 0xd6, 0x89, 0x8e, + 0x47, 0xdf, 0x81, 0x28, 0x94, 0xc7, 0x98, 0xd4, 0x1c, 0x6f, 0x95, 0xdd, + 0x20, 0x74, 0xe9, 0xde, 0xb5, 0x3b, 0x87, 0xa1, 0x1a, 0x1e, 0xee, 0xc7, + 0xbc, 0xa4, 0x12, 0x30, 0x92, 0x60, 0x9f, 0x0d, 0x4d, 0x23, 0x1f, 0xa0, + 0xea, 0x07, 0x84, 0x10, 0xb3, 0xd3, 0x2a, 0x2f, 0x27, 0xdb, 0x27, 0x76, + 0xb8, 0x43, 0xe2, 0x9a, 0xfc, 0x9b, 0x81, 0x43, 0xd2, 0xbc, 0xc2, 0xbb, + 0x40, 0xbd, 0xe8, 0x10, 0xd5, 0xca, 0xd2, 0x10, 0x5e, 0x18, 0xfe, 0x45, + 0x1d, 0xc2, 0xf9, 0x99, 0x50, 0xbe, 0x7e, 0xca, 0x1a, 0x45, 0x17, 0x99, + 0x03, 0x9d, 0x2b, 0x68, 0xb7, 0x76, 0x3e, 0x68, 0x41, 0x81, 0x6d, 0xe3, + 0x77, 0xbe, 0x4e, 0xc9, 0x41, 0xb7, 0x8a, 0xb7, 0xa7, 0x59, 0xfa, 0x04, + 0x7b, 0xde, 0xd0, 0x3f, 0x7a, 0x57, 0xa3, 0xf1, 0x9e, 0x0a, 0x66, 0x98, + 0xb0, 0xc1, 0xc2, 0xb4, 0x7a, 0x3b, 0x2f, 0x54, 0x3b, 0x66, 0xe6, 0x6b, + 0xc5, 0x2c, 0xa1, 0xb1, 0xd2, 0xee, 0xd8, 0x30, 0xf3, 0xa9, 0x2f, 0xe8, + 0xf0, 0x3e, 0xd8, 0x2b, 0x9a, 0x75, 0x58, 0x59, 0xc7, 0x3a, 0x39, 0xa1, + 0x58, 0x19, 0x87, 0x3f, 0x90, 0xe5, 0xb3, 0xb6, 0xfe, 0x39, 0x34, 0xc8, + 0x4c, 0x21, 0x7b, 0x96, 0x9e, 0x3e, 0x38, 0x48, 0x3e, 0xaa, 0x0b, 0x1b, + 0xbf, 0xa9, 0x45, 0x83, 0x8e, 0x38, 0xf3, 0x96, 0xb8, 0x24, 0x23, 0xc1, + 0xd3, 0x5c, 0x77, 0xeb, 0x6f, 0xf8, 0x16, 0xa8, 0x94, 0xbc, 0xab, 0x2a, + 0x20, 0x52, 0xec, 0x9a, 0x5c, 0xd9, 0x99, 0xb4, 0x84, 0x50, 0x90, 0xbb, + 0xf7, 0x80, 0x51, 0x61, 0x95, 0x61, 0xaa, 0x03, 0xd6, 0xd4, 0xa9, 0x73, + 0x86, 0x3b, 0xf1, 0x7e, 0xca, 0x7c, 0xfb, 0xf9, 0x33, 0xe6, 0x96, 0x66, + 0x13, 0x7a, 0x35, 0xae, 0x71, 0xcc, 0x13, 0x4b, 0x5e, 0x73, 0xbd, 0xf8, + 0xf2, 0x5e, 0x51, 0x5c, 0x50, 0x09, 0x3c, 0x59, 0xfa, 0xd0, 0xd4, 0x8e, + 0xe0, 0x21, 0xb4, 0x97, 0xa4, 0x7d, 0xeb, 0x17, 0xef, 0x4c, 0xf4, 0xd0, + 0x0b, 0xf5, 0x42, 0xaf, 0x07, 0x8e, 0xe9, 0x5f, 0x2b, 0xce, 0xb4, 0xf9, + 0x17, 0xea, 0x9e, 0x83, 0x94, 0xf5, 0x1d, 0x49, 0x91, 0x42, 0x65, 0x84, + 0x77, 0x56, 0xc0, 0x4f, 0x67, 0x37, 0xed, 0xa3, 0x18, 0x22, 0x69, 0xd7, + 0x40, 0xfb, 0x39, 0xfd, 0xc2, 0x37, 0x68, 0x98, 0x30, 0x6a, 0x33, 0xad, + 0x2f, 0xf2, 0x3d, 0x5c, 0xe0, 0x4a, 0x29, 0x38, 0xe5, 0xe0, 0x5c, 0xb3, + 0x79, 0xd5, 0x8c, 0xcd, 0x25, 0xad, 0xab, 0xd3, 0x75, 0x2f, 0x54, 0x3a, + 0xfe, 0x8e, 0x0d, 0x3f, 0xfa, 0x6e, 0xcc, 0x80, 0x26, 0x08, 0x7f, 0xa3, + 0x9e, 0xba, 0x80, 0x4c, 0x36, 0x4c, 0x4d, 0x74, 0xc0, 0x3f, 0xd1, 0xb3, + 0xad, 0xa3, 0xc8, 0xcf, 0x7a, 0x73, 0xb7, 0x09, 0x67, 0x3b, 0xf8, 0x6f, + 0x7a, 0x26, 0x57, 0x65, 0x83, 0xcf, 0x18, 0x3c, 0x86, 0x2c, 0xb4, 0xcd, + 0xe8, 0x74, 0xfa, 0x63, 0xd4, 0xb4, 0x36, 0x36, 0xd9, 0xb0, 0xeb, 0x29, + 0xe3, 0x3a, 0x7f, 0x06, 0x80, 0x29, 0x4c, 0x86, 0x94, 0x49, 0x42, 0x22, + 0x57, 0x0c, 0x4f, 0xfa, 0x08, 0xb5, 0x12, 0xbe, 0x76, 0xf5, 0x52, 0x10, + 0x47, 0x48, 0x1f, 0xbd, 0x87, 0x51, 0xd1, 0x39, 0xc8, 0x50, 0x7c, 0xfa, + 0x92, 0xe7, 0xea, 0x40, 0x55, 0xf7, 0x61, 0x9f, 0x19, 0xc2, 0x65, 0x23, + 0x6d, 0xe0, 0x41, 0xb9, 0x5b, 0xb7, 0x8c, 0x9a, 0xee, 0x50, 0x53, 0xa6, + 0xe8, 0x80, 0x14, 0x8c, 0xeb, 0x2a, 0xc1, 0x44, 0xda, 0x6d, 0x90, 0x96, + 0xb8, 0xf1, 0xc4, 0x0d, 0xf1, 0xd8, 0x8e, 0xd0, 0xb4, 0x73, 0x49, 0xe5, + 0x34, 0xab, 0x00, 0x0f, 0x0b, 0x7b, 0xc3, 0x7d, 0x53, 0x1d, 0x75, 0xef, + 0x27, 0xfb, 0xdf, 0x29, 0xfd, 0x61, 0xb3, 0x71, 0x25, 0xac, 0x62, 0x2d, + 0xaa, 0x1a, 0x2a, 0x55, 0x6e, 0x11, 0x50, 0x4b, 0x2c, 0x3d, 0xd8, 0x8d, + 0xb9, 0xcb, 0xc2, 0x21, 0x77, 0x4e, 0x40, 0x56, 0x45, 0xc1, 0x07, 0x79, + 0xdb, 0x66, 0x2f, 0x6d, 0x4d, 0xac, 0x2b, 0x2d, 0x29, 0xff, 0xa1, 0x79, + 0x10, 0x03, 0x72, 0x09, 0xe8, 0xe9, 0x31, 0xd5, 0x6f, 0x42, 0x97, 0x3e, + 0x09, 0xf0, 0x4a, 0xb5, 0xe6, 0x73, 0x94, 0xc1, 0xb4, 0x94, 0xa1, 0xd9, + 0x44, 0xe8, 0x50, 0xe2, 0x6c, 0x82, 0xea, 0x89, 0x06, 0xd6, 0x44, 0xe9, + 0x53, 0xd0, 0x5c, 0xcf, 0x0a, 0x3b, 0x89, 0x50, 0x8d, 0x1e, 0x44, 0xbd, + 0xb2, 0xb6, 0x68, 0xf4, 0xbb, 0x2d, 0x65, 0x95, 0x5c, 0xb5, 0xdc, 0xe2, + 0xb7, 0x70, 0x86, 0xfd, 0x5b, 0xcc, 0x99, 0x41, 0x5d, 0x22, 0x11, 0xa8, + 0x22, 0x8c, 0xc1, 0x73, 0x70, 0x5b, 0x31, 0x11, 0xc3, 0xdb, 0x7f, 0xca, + 0x2b, 0xcb, 0xeb, 0x7d, 0x2b, 0xd1, 0x32, 0xe6, 0xf8, 0x22, 0x22, 0x69, + 0xea, 0xb7, 0xcd, 0x25, 0x22, 0x33, 0x2f, 0x83, 0x3f, 0xb7, 0x2d, 0x22, + 0x61, 0x24, 0x01, 0xb3, 0xe9, 0xd0, 0xf6, 0x21, 0xe6, 0x2d, 0xea, 0x0e, + 0x53, 0x7a, 0x97, 0xcd, 0xcf, 0x6c, 0xe2, 0xd5, 0x8b, 0xdc, 0xe9, 0xe0, + 0xfd, 0xd0, 0xa0, 0xbf, 0xa5, 0x39, 0x7e, 0xd4, 0xdd, 0xfe, 0x1a, 0xce, + 0xb0, 0x85, 0x8e, 0xc1, 0x05, 0x36, 0xf9, 0xd3, 0x6a, 0x35, 0xab, 0x53, + 0x1d, 0xc2, 0xa0, 0xfa, 0xc2, 0x6b, 0x8b, 0x8c, 0x2d, 0x5d, 0x5f, 0xb8, + 0x18, 0x43, 0x53, 0xb9, 0x5d, 0x08, 0x07, 0xd1, 0x8f, 0xc6, 0xe9, 0xef, + 0xaf, 0x3b, 0xbb, 0x60, 0xaa, 0x28, 0xac, 0x4c, 0x03, 0x5d, 0xc8, 0x05, + 0xba, 0x82, 0x5c, 0xcb, 0xc6, 0x2a, 0x13, 0xf6, 0xfc, 0x54, 0xf3, 0xea, + 0x20, 0xce, 0xcf, 0x05, 0x00, 0xb9, 0x98, 0x0b, 0x9f, 0x96, 0xe0, 0x7b, + 0x85, 0x8e, 0x43, 0xbd, 0xf2, 0x3e, 0x17, 0x19, 0x8d, 0x23, 0x72, 0x85, + 0x93, 0xdf, 0x3a, 0x21, 0x94, 0x34, 0x32, 0x53, 0x02, 0xba, 0x34, 0xba, + 0xa5, 0x2e, 0x5c, 0x0b, 0x1e, 0x3f, 0xa9, 0x83, 0x92, 0x63, 0x0b, 0x12, + 0xc9, 0xf8, 0x35, 0xef, 0x78, 0xa0, 0xee, 0xc0, 0xbb, 0x14, 0xd4, 0x68, + 0x39, 0xa0, 0x00, 0x38, 0x77, 0x1e, 0xfc, 0x94, 0xb4, 0xd4, 0xc1, 0x98, + 0xe1, 0x43, 0x8e, 0xc6, 0xa7, 0x58, 0x33, 0x1b, 0xa3, 0x73, 0xf7, 0x4c, + 0x49, 0x9d, 0xc0, 0xb8, 0xbf, 0x30, 0x84, 0x2e, 0x5a, 0x8b, 0x6c, 0xa5, + 0xde, 0xb5, 0x6a, 0x79, 0x67, 0x54, 0xe7, 0x8c, 0x3c, 0xf3, 0x70, 0x1b, + 0x3d, 0x35, 0x23, 0x65, 0x17, 0xc9, 0x74, 0x11, 0x0b, 0xb1, 0x64, 0xc0, + 0x65, 0xa3, 0x9e, 0x5a, 0x7b, 0xa2, 0xda, 0xe1, 0xf4, 0xeb, 0xb8, 0x13, + 0x90, 0x30, 0xc1, 0x72, 0x6a, 0x2a, 0x13, 0xe3, 0x36, 0xe1, 0x05, 0x47, + 0x56, 0x42, 0xf2, 0x59, 0x44, 0x12, 0x23, 0x27, 0xe4, 0xfe, 0xae, 0x83, + 0x39, 0x0f, 0x4c, 0x85, 0x3f, 0xaf, 0x97, 0x2e, 0xae, 0x3c, 0x12, 0x0e, + 0xfd, 0x5b, 0xfd, 0x8e, 0x58, 0x58, 0x4a, 0xbd, 0x05, 0x98, 0x6b, 0x82, + 0x03, 0x02, 0x0a, 0x2d, 0x1c, 0x19, 0x0f, 0x95, 0x12, 0x5d, 0x8c, 0x1e, + 0x7b, 0x49, 0xbb, 0x83, 0xe2, 0xd2, 0x53, 0x60, 0xe1, 0xab, 0xd2, 0x8b, + 0x02, 0xeb, 0x49, 0x27, 0xd7, 0xda, 0x22, 0xd3, 0x26, 0x6f, 0x3e, 0x5b, + 0x3f, 0x33, 0xcb, 0xa8, 0x08, 0x98, 0xa6, 0xc5, 0x35, 0xc1, 0x81, 0xc1, + 0xd6, 0x28, 0xe5, 0xba, 0x50, 0xe9, 0x14, 0x1a, 0x0b, 0x0a, 0x8a, 0x9e, + 0xa3, 0xaa, 0xbc, 0x3b, 0x38, 0x5b, 0xe0, 0x1f, 0xf6, 0xb8, 0x95, 0x79, + 0xa4, 0x45, 0x5f, 0xc4, 0x63, 0x86, 0xd0, 0x15, 0xe0, 0x25, 0x6e, 0x5f, + 0x8d, 0x75, 0x25, 0x67, 0xea, 0xf3, 0x92, 0x33, 0xd1, 0x07, 0xf3, 0x43, + 0x21, 0x42, 0x40, 0x70, 0x9b, 0x8e, 0x0b, 0x41, 0x54, 0x30, 0x73, 0xd0, + 0x49, 0xe4, 0x70, 0xf6, 0xd3, 0x7d, 0x59, 0xd6, 0x1f, 0x06, 0xfc, 0x12, + 0x89, 0x9f, 0x26, 0x09, 0x34, 0xf6, 0x64, 0x56, 0x37, 0x68, 0x59, 0x33, + 0x9c, 0xa0, 0xfa, 0x65, 0x70, 0xb3, 0xe1, 0x29, 0xd1, 0x5b, 0xaf, 0xe7, + 0xa5, 0x39, 0x64, 0x38, 0x8b, 0xb1, 0xd6, 0xce, 0xa4, 0xb4, 0xb6, 0xdb, + 0x01, 0xb4, 0xf9, 0xb7, 0x1f, 0x8f, 0xcd, 0x28, 0xe6, 0x27, 0x47, 0xf2, + 0x53, 0x1d, 0xea, 0xb4, 0x53, 0xfa, 0xe0, 0x22, 0xea, 0xc5, 0xd2, 0xfc, + 0x4e, 0x45, 0xcf, 0xef, 0xaa, 0xea, 0xaf, 0x7e, 0x77, 0xe2, 0x39, 0x1c, + 0x5d, 0x9c, 0x77, 0x7b, 0x71, 0xb5, 0x11, 0xef, 0xc7, 0xf8, 0xba, 0x2b, + 0x7b, 0x15, 0xfa, 0x2d, 0xd5, 0xd8, 0xe0, 0xee, 0xbe, 0x10, 0xd6, 0xdb, + 0x47, 0xf1, 0x11, 0xcc, 0x35, 0x4c, 0x2d, 0xa8, 0x12, 0x12, 0x23, 0x78, + 0x0b, 0xd3, 0xb8, 0x90, 0x8a, 0x1d, 0xc4, 0x90, 0x4b, 0x7e, 0x35, 0xb9, + 0x9f, 0x5b, 0x68, 0x97, 0x9c, 0x09, 0xc3, 0x0d, 0x0a, 0x20, 0xd9, 0x25, + 0x07, 0xeb, 0x56, 0xb5, 0xd6, 0x93, 0x31, 0x3d, 0x71, 0x7c, 0x0f, 0x48, + 0x26, 0x32, 0x0f, 0x1b, 0x43, 0x75, 0xc2, 0xcd, 0xf6, 0xaa, 0x88, 0x38, + 0x7b, 0xe9, 0xc0, 0x98, 0x51, 0xa4, 0x06, 0x15, 0x7f, 0x11, 0x0b, 0x91, + 0xcb, 0x59, 0x92, 0x1c, 0xa1, 0x44, 0x63, 0xa4, 0x3a, 0xad, 0xd7, 0x1d, + 0x9e, 0x63, 0xfb, 0xb9, 0x7d, 0x43, 0x80, 0x79, 0xe8, 0x01, 0xba, 0x08, + 0x47, 0x78, 0x57, 0xd6, 0x0b, 0x38, 0x94, 0x64, 0xac, 0x64, 0x77, 0xdc, + 0xb8, 0xa9, 0xa5, 0xa2, 0x62, 0x70, 0x36, 0x4f, 0x39, 0xd9, 0xae, 0x2f, + 0x15, 0xd3, 0x07, 0xc4, 0x01, 0x03, 0x96, 0x5e, 0x51, 0xa7, 0x15, 0x2a, + 0x9d, 0x22, 0x74, 0xae, 0x8a, 0xd4, 0xb9, 0x91, 0xed, 0xad, 0xa7, 0x76, + 0xad, 0x38, 0x33, 0xef, 0x3c, 0xe4, 0xd0, 0x7c, 0x6e, 0x53, 0xae, 0x0c, + 0x7a, 0xdf, 0x2c, 0x18, 0xeb, 0xc4, 0x8c, 0xfe, 0xab, 0x10, 0xcd, 0xaf, + 0x8f, 0x88, 0x3f, 0xac, 0xe3, 0x20, 0xed, 0x0c, 0x62, 0x81, 0x2e, 0x12, + 0xa9, 0xa5, 0xe7, 0xd5, 0x3a, 0xef, 0x40, 0xb4, 0x91, 0x52, 0x4c, 0xfd, + 0xd5, 0xb8, 0x98, 0x19, 0xcd, 0x1b, 0xa9, 0x17, 0xe7, 0x9a, 0xda, 0x8a, + 0xb4, 0x8f, 0x1a, 0x5c, 0x78, 0xd2, 0x28, 0x7a, 0xb6, 0x66, 0xac, 0x73, + 0xd4, 0x11, 0xc0, 0x81, 0xff, 0x71, 0x57, 0x4c, 0x23, 0x90, 0x2a, 0xd8, + 0x67, 0x7a, 0x6a, 0x58, 0xb7, 0x5b, 0xbe, 0x80, 0x62, 0x17, 0x10, 0x90, + 0xc1, 0xb7, 0x2c, 0xbe, 0xbe, 0x97, 0x2e, 0x85, 0x36, 0x07, 0x8e, 0x63, + 0xfc, 0x38, 0xc5, 0x66, 0x20, 0x33, 0x2b, 0xe8, 0x25, 0x25, 0xc1, 0x11, + 0xba, 0x5b, 0x12, 0xd9, 0x06, 0x4d, 0xfc, 0x49, 0x20, 0x27, 0x6b, 0x79, + 0x92, 0x8b, 0xde, 0x22, 0x39, 0xf9, 0x2e, 0xc9, 0x1b, 0xb9, 0x97, 0x2f, + 0xc3, 0x37, 0xf5, 0xa3, 0x6b, 0xd3, 0x3b, 0x94, 0xa5, 0x56, 0xb7, 0x81, + 0x7c, 0x9d, 0x28, 0xff, 0x57, 0xe7, 0x02, 0xa1, 0xd1, 0x3a, 0x3d, 0xac, + 0x74, 0x45, 0xb3, 0xab, 0x95, 0xec, 0x68, 0x8a, 0x9c, 0xf7, 0x43, 0xa4, + 0x14, 0x0d, 0x68, 0x40, 0x5f, 0x7e, 0x25, 0x8a, 0x47, 0x3f, 0x9c, 0xaf, + 0x88, 0x0b, 0x4a, 0xc0, 0x98, 0xc2, 0x57, 0xf4, 0xde, 0x04, 0x09, 0x37, + 0x9c, 0x87, 0x83, 0xb6, 0xa5, 0xa8, 0x5e, 0xc4, 0xec, 0x2e, 0xfd, 0xc9, + 0xf3, 0x85, 0x4f, 0x7d, 0xb8, 0xba, 0x6e, 0x6d, 0xc0, 0xd2, 0x37, 0xb2, + 0xba, 0x17, 0xad, 0x29, 0xf8, 0x71, 0x74, 0x0c, 0x93, 0x1e, 0x07, 0x34, + 0xec, 0xc3, 0x5f, 0x15, 0x21, 0x49, 0x0f, 0xa7, 0x7e, 0x72, 0x79, 0x66, + 0xfd, 0x3e, 0x29, 0xce, 0x12, 0xeb, 0x57, 0x88, 0xd8, 0xcc, 0x14, 0x96, + 0x33, 0x44, 0x64, 0x6c, 0x34, 0x55, 0xb3, 0x76, 0xc9, 0xa7, 0x3f, 0x7b, + 0x16, 0x9d, 0x7e, 0x95, 0x4c, 0xfa, 0xc9, 0x46, 0x17, 0x18, 0x18, 0x78, + 0xe7, 0xfb, 0x6b, 0x86, 0xf4, 0x25, 0x3a, 0x0b, 0x4a, 0xcd, 0x1a, 0x51, + 0xde, 0xa4, 0x45, 0xdd, 0xdb, 0xc9, 0x9f, 0xa9, 0xc3, 0x58, 0xb2, 0x43, + 0x90, 0x8b, 0xc1, 0x59, 0x47, 0x1a, 0x89, 0xcb, 0x9c, 0x6d, 0x46, 0x1f, + 0x0d, 0xe9, 0xfa, 0xd8, 0xe9, 0xde, 0xdb, 0xf5, 0x22, 0x9b, 0xe3, 0xef, + 0xb4, 0x0c, 0xc7, 0x34, 0xd0, 0x2a, 0x0f, 0x0b, 0x8e, 0x11, 0x88, 0x91, + 0xb7, 0xce, 0x92, 0xf2, 0x83, 0x3c, 0xd2, 0xf8, 0x42, 0x32, 0x82, 0x48, + 0xad, 0x67, 0x44, 0x45, 0x59, 0xac, 0x57, 0xb7, 0x7e, 0x1b, 0xce, 0xca, + 0x51, 0xfb, 0x1b, 0x12, 0x39, 0xaf, 0xe4, 0xfb, 0xdb, 0xc5, 0xb7, 0xcc, + 0x4a, 0x5d, 0xc4, 0xa6, 0x95, 0xaf, 0x5b, 0x39, 0x4e, 0x47, 0xc5, 0x50, + 0x67, 0x92, 0x84, 0x62, 0xeb, 0x81, 0x77, 0x24, 0xda, 0x27, 0x64, 0xfe, + 0xe4, 0x83, 0x40, 0x33, 0xc8, 0xb1, 0xaa, 0xbb, 0xbf, 0x13, 0xc3, 0x18, + 0x9a, 0x24, 0x06, 0xbd, 0x0a, 0x07, 0xa3, 0xd6, 0xd8, 0x38, 0x32, 0x73, + 0x8d, 0x40, 0x5f, 0xc2, 0x3f, 0xeb, 0xd2, 0x0e, 0x3d, 0x6d, 0xf5, 0x72, + 0x5a, 0xa6, 0x56, 0x22, 0x41, 0xe5, 0x0c, 0xb5, 0x0c, 0xda, 0xcd, 0x46, + 0xbc, 0xd7, 0x98, 0x89, 0x5e, 0x97, 0x54, 0x4f, 0x4b, 0xc0, 0x27, 0x51, + 0x0d, 0x20, 0x3f, 0x55, 0x78, 0xdc, 0x5a, 0x79, 0x08, 0xed, 0xd3, 0xaa, + 0x9c, 0xc3, 0x7d, 0x75, 0x76, 0x81, 0xa4, 0xe0, 0xfc, 0x90, 0x6a, 0x83, + 0x37, 0x53, 0xb8, 0xb5, 0xd9, 0x7a, 0xd9, 0x7d, 0xeb, 0x50, 0x72, 0xd3, + 0x5d, 0xed, 0x22, 0xfb, 0x6e, 0x67, 0x79, 0x9c, 0xb9, 0xea, 0xac, 0xc1, + 0x6d, 0x68, 0xf5, 0x12, 0xaa, 0x54, 0x90, 0xd8, 0x7f, 0xe0, 0xf4, 0xdd, + 0x3b, 0x88, 0xe3, 0xec, 0x7f, 0x1c, 0x2b, 0x08, 0x32, 0xc6, 0x05, 0x53, + 0xae, 0xa4, 0x46, 0xa7, 0xf3, 0xe6, 0xcb, 0xe7, 0x04, 0xc1, 0x52, 0xa7, + 0xfe, 0x68, 0x55, 0xc1, 0x91, 0xb2, 0x9a, 0x3b, 0x05, 0xc6, 0xae, 0x15, + 0x89, 0xdc, 0xb2, 0x0b, 0xeb, 0x19, 0x96, 0x62, 0xe3, 0x67, 0xc5, 0xdc, + 0xf5, 0xe8, 0xbe, 0x16, 0xbe, 0xf6, 0xe4, 0x0b, 0xeb, 0x99, 0x82, 0x65, + 0x0a, 0x97, 0xf5, 0xc2, 0x19, 0x1c, 0x1e, 0xa1, 0xf1, 0x75, 0x06, 0xa7, + 0xdb, 0x97, 0x68, 0x94, 0x0b, 0xea, 0xc4, 0xda, 0x70, 0x72, 0x3e, 0x9f, + 0xfc, 0x20, 0x4e, 0x54, 0xfb, 0x18, 0x01, 0x74, 0x9a, 0x24, 0x1d, 0x20, + 0x3a, 0x25, 0xe1, 0xd8, 0xaf, 0xe3, 0x76, 0xe0, 0x47, 0x53, 0x86, 0xd9, + 0x3f, 0xc2, 0x46, 0x4a, 0x02, 0x05, 0xaf, 0xbf, 0x49, 0x12, 0x22, 0x66, + 0x81, 0xf5, 0x9d, 0xdd, 0xae, 0x7f, 0xf5, 0x99, 0x2b, 0x89, 0xa6, 0x25, + 0x30, 0xd6, 0xb3, 0x00, 0xa4, 0x62, 0xd2, 0xb3, 0x8e, 0xdd, 0xc2, 0x04, + 0x62, 0x17, 0x44, 0xa3, 0x62, 0xf7, 0x8c, 0x56, 0x00, 0x4f, 0x98, 0xfe, + 0x7a, 0xdf, 0x9d, 0x47, 0xab, 0xc9, 0xb7, 0x0e, 0x0d, 0x02, 0x54, 0x6a, + 0xab, 0xf9, 0x22, 0xb9, 0x11, 0xb3, 0xec, 0x17, 0xb9, 0xc9, 0x86, 0xf6, + 0x66, 0x97, 0x1f, 0xa9, 0x38, 0xd8, 0x66, 0x8e, 0x41, 0xd9, 0x9a, 0x35, + 0xfd, 0x19, 0x64, 0xcb, 0x1e, 0x77, 0x80, 0xd4, 0x6d, 0xea, 0x00, 0xf5, + 0x9b, 0xc9, 0x55, 0xef, 0x80, 0x14, 0x79, 0xab, 0xf5, 0x5e, 0xb0, 0x4b, + 0x73, 0x52, 0x17, 0x2a, 0xd7, 0x68, 0x79, 0x6a, 0xf1, 0xc0, 0x04, 0xce, + 0x33, 0xd2, 0x18, 0xad, 0x39, 0x4d, 0xda, 0x40, 0x49, 0xce, 0x00, 0xca, + 0x89, 0xf3, 0xbd, 0x13, 0xe5, 0x7a, 0x03, 0x99, 0xa3, 0x4b, 0x29, 0xcd, + 0x18, 0xbd, 0xc8, 0xd7, 0x30, 0xcd, 0x4f, 0x65, 0xdc, 0xca, 0xc2, 0x9f, + 0x84, 0x2d, 0x83, 0xf6, 0x69, 0x0d, 0x55, 0x08, 0x5b, 0x6c, 0x87, 0x53, + 0xda, 0x13, 0x2a, 0x34, 0xf7, 0xea, 0x13, 0xec, 0x14, 0x90, 0xe8, 0x94, + 0xdc, 0xa6, 0xcf, 0xe9, 0x9b, 0x99, 0x63, 0x48, 0xf3, 0x34, 0xac, 0xf2, + 0x78, 0x76, 0x90, 0x46, 0xd8, 0x7d, 0x2b, 0xc1, 0xd2, 0xdd, 0xf1, 0xda, + 0x23, 0xc8, 0x3c, 0xd6, 0x58, 0x2e, 0xaf, 0x2c, 0xf6, 0x8a, 0xb3, 0x93, + 0x0e, 0x4f, 0x82, 0x7e, 0x26, 0x88, 0x0b, 0x3b, 0xe4, 0xe9, 0x85, 0x2b, + 0x99, 0xca, 0xdc, 0xad, 0x84, 0x26, 0xee, 0x35, 0x6a, 0x50, 0xc4, 0xae, + 0x95, 0x30, 0x0d, 0x09, 0xef, 0xdb, 0x4b, 0x4c, 0x9b, 0x0f, 0x04, 0x0a, + 0x6e, 0xf0, 0x92, 0x43, 0x06, 0xb9, 0x73, 0x16, 0x79, 0x15, 0x3f, 0x08, + 0xcc, 0x78, 0x2b, 0x35, 0x8c, 0xa3, 0x2a, 0x6e, 0xf6, 0x5c, 0x61, 0xf3, + 0xc6, 0x4b, 0x8a, 0xbc, 0x75, 0x1f, 0x4a, 0x00, 0x4e, 0x5f, 0x9e, 0x24, + 0x03, 0x2d, 0x86, 0x26, 0xa7, 0x78, 0xb7, 0xc3, 0x6f, 0x74, 0x6d, 0x32, + 0x34, 0xcd, 0x37, 0x42, 0x56, 0x24, 0x83, 0x7f, 0xa8, 0x1b, 0x9b, 0xae, + 0x97, 0x55, 0x2d, 0xba, 0x67, 0x75, 0x67, 0xca, 0xa5, 0xd1, 0x6e, 0xd6, + 0x48, 0xaf, 0xeb, 0x71, 0xdc, 0x31, 0xfb, 0x3b, 0xe3, 0x7c, 0x64, 0x9d, + 0xe5, 0x5a, 0xe4, 0x87, 0x6e, 0xed, 0xed, 0xca, 0xb6, 0x51, 0xfd, 0x73, + 0xef, 0x7c, 0xbc, 0x15, 0x69, 0xfd, 0x9f, 0x1f, 0x0f, 0x17, 0x1a, 0x8d, + 0x73, 0x61, 0x7d, 0xf1, 0x09, 0x97, 0x06, 0xbe, 0x90, 0x38, 0xdf, 0xac, + 0xfd, 0xe2, 0x87, 0xe8, 0xc1, 0xc3, 0x9b, 0x83, 0x79, 0xa6, 0xdd, 0x6d, + 0x58, 0x4d, 0x03, 0x26, 0x99, 0x1d, 0x2e, 0x47, 0xb0, 0x20, 0x3f, 0x84, + 0xaf, 0xfa, 0xf9, 0xf1, 0x62, 0xd5, 0x80, 0xb8, 0x6e, 0x69, 0x7e, 0x53, + 0x80, 0x05, 0xc4, 0x2f, 0xba, 0xed, 0x0d, 0x75, 0xca, 0x01, 0xde, 0x6e, + 0xf0, 0xd3, 0x23, 0x9b, 0x1e, 0xae, 0x02, 0x57, 0xeb, 0x40, 0xf2, 0x55, + 0x89, 0xd7, 0x70, 0xd6, 0x45, 0xe7, 0x67, 0xd3, 0x3e, 0x21, 0xda, 0xb6, + 0xae, 0xe5, 0xe6, 0x82, 0x0c, 0x3e, 0x3e, 0xe8, 0xbe, 0x85, 0x3d, 0x79, + 0x75, 0x90, 0x9b, 0x9c, 0x01, 0x88, 0x8d, 0x5a, 0x34, 0x1d, 0x10, 0x83, + 0x85, 0x08, 0xea, 0x88, 0x51, 0x29, 0xea, 0x95, 0x40, 0x2f, 0x16, 0x90, + 0xec, 0x1b, 0xb7, 0x22, 0x81, 0xcb, 0x1b, 0x8c, 0xf5, 0xe2, 0xfd, 0xcb, + 0x1f, 0xe7, 0xb0, 0x4b, 0x4d, 0x7c, 0x7d, 0x11, 0x17, 0x20, 0x89, 0x8b, + 0x4a, 0x80, 0xa3, 0x10, 0x6f, 0x68, 0x09, 0x01, 0x68, 0x86, 0x3b, 0x2a, + 0xfb, 0x48, 0x80, 0xa0, 0xd1, 0xdb, 0x3f, 0x91, 0x44, 0x58, 0x83, 0xc6, + 0x85, 0x77, 0x6b, 0xb1, 0x35, 0x4a, 0x03, 0xa2, 0xcf, 0x2f, 0xbd, 0xcd, + 0x4b, 0xfa, 0x5a, 0x5e, 0x8f, 0x8b, 0x95, 0x62, 0xaa, 0xe7, 0x3b, 0x54, + 0xb1, 0xec, 0xd5, 0x85, 0x4f, 0xd9, 0x59, 0x56, 0xb4, 0xec, 0xc1, 0x21, + 0xc5, 0xa6, 0x35, 0x1d, 0x7b, 0x60, 0xe1, 0xb1, 0x7c, 0x8f, 0x47, 0xa1, + 0xf1, 0x13, 0x4b, 0xaf, 0x23, 0xcb, 0x5e, 0xe2, 0x74, 0x16, 0x16, 0x96, + 0x3b, 0xff, 0xbf, 0x26, 0x5f, 0x68, 0xd5, 0x64, 0xc6, 0x62, 0xaf, 0x4a, + 0xfc, 0x0f, 0x27, 0x3e, 0x96, 0x5b, 0x7c, 0xeb, 0x78, 0x81, 0x3c, 0x0a, + 0x63, 0xd5, 0x6b, 0x3c, 0xa9, 0xd4, 0x37, 0x03, 0x3b, 0x5c, 0x62, 0x7a, + 0xd5, 0x69, 0xbe, 0x44, 0x50, 0xab, 0x0a, 0x54, 0x31, 0x5c, 0x44, 0x52, + 0xfe, 0xde, 0xbb, 0x10, 0x80, 0x79, 0xb2, 0x69, 0xc5, 0x75, 0x8b, 0xba, + 0x1d, 0x4d, 0x2d, 0xfa, 0xc8, 0x0e, 0xc0, 0xaf, 0xc2, 0x31, 0xa1, 0x53, + 0xc7, 0x9f, 0x3e, 0x1f, 0x38, 0x8c, 0x1e, 0x00, 0x78, 0x76, 0xb6, 0xb5, + 0x68, 0xa4, 0x68, 0xe9, 0xba, 0xda, 0x97, 0xca, 0x16, 0xde, 0xba, 0xa1, + 0xb7, 0x17, 0x26, 0xb3, 0x4b, 0x4b, 0x4e, 0x21, 0x9c, 0xaf, 0xce, 0xf0, + 0x52, 0x41, 0x13, 0x87, 0x75, 0xc4, 0xd7, 0x34, 0x0c, 0x2d, 0xfe, 0xc1, + 0xb6, 0x60, 0x84, 0xd2, 0x57, 0xc2, 0xb2, 0x6c, 0xa6, 0x97, 0x51, 0xea, + 0x49, 0x07, 0x7d, 0xac, 0x15, 0x75, 0x71, 0x67, 0x2c, 0xdf, 0x09, 0x0c, + 0x63, 0x38, 0x6a, 0x25, 0xf3, 0x9b, 0x5d, 0x5d, 0x63, 0xe7, 0x20, 0xa3, + 0xf5, 0x6f, 0x8c, 0x77, 0x91, 0xb0, 0x6d, 0xad, 0x01, 0x1d, 0x40, 0x65, + 0xcd, 0x31, 0xbf, 0xb2, 0x0a, 0x1f, 0xf9, 0xb0, 0x34, 0x7f, 0x6a, 0xfe, + 0xca, 0x2e, 0x28, 0xc4, 0x5b, 0xdb, 0xa9, 0xd4, 0xdc, 0xe6, 0x3a, 0x0a, + 0xeb, 0xe2, 0xc5, 0xb8, 0xbe, 0xad, 0x8d, 0x7d, 0xa2, 0x5e, 0x88, 0xad, + 0xb8, 0xda, 0x41, 0x12, 0x1f, 0xc5, 0x85, 0xa1, 0x83, 0x3d, 0xc7, 0xbb, + 0x6d, 0x55, 0x63, 0xd0, 0x8b, 0x06, 0x76, 0x96, 0xf5, 0x0b, 0xd9, 0x2f, + 0x45, 0xf4, 0x9b, 0xc8, 0x18, 0xba, 0xbd, 0x30, 0xdc, 0x4d, 0x47, 0xde, + 0xbc, 0xc0, 0xc0, 0xca, 0x9f, 0xd7, 0xda, 0xcb, 0xd8, 0xdd, 0x7e, 0x98, + 0x25, 0xfd, 0x9f, 0xa4, 0x22, 0x5d, 0x4b, 0x63, 0x1b, 0xfa, 0x78, 0xdb, + 0x3d, 0x39, 0xcc, 0x26, 0x00, 0x70, 0x0e, 0xac, 0xf7, 0x30, 0xc0, 0x8c, + 0x97, 0xbe, 0x57, 0xeb, 0x1a, 0xc0, 0xfd, 0x4c, 0x81, 0x69, 0x54, 0x1b, + 0xd4, 0x8c, 0xb2, 0xe7, 0xf0, 0x5f, 0x0e, 0x46, 0x95, 0x7a, 0x2b, 0x0c, + 0x69, 0x37, 0x89, 0x45, 0x6a, 0xb2, 0x9f, 0xa8, 0x99, 0xd2, 0x6c, 0xa0, + 0x9d, 0xc0, 0x36, 0x65, 0x2f, 0x37, 0xe3, 0xc8, 0xba, 0x4f, 0xd2, 0x4c, + 0x69, 0x2e, 0x15, 0x2c, 0x92, 0x13, 0x44, 0x96, 0xa5, 0xe9, 0x90, 0x24, + 0x0a, 0x94, 0x44, 0x16, 0x6a, 0x8e, 0x4a, 0x7b, 0xf4, 0x65, 0x41, 0xd0, + 0x4e, 0xf3, 0xf2, 0x6d, 0x8e, 0xc0, 0x70, 0xdf, 0x56, 0x2f, 0x11, 0x80, + 0x03, 0x42, 0xb5, 0x9c, 0x59, 0xea, 0xe1, 0x2d, 0xc7, 0xd1, 0x29, 0x4a, + 0xce, 0x78, 0x83, 0x8f, 0x9b, 0xd4, 0x6b, 0x91, 0xd8, 0x7b, 0xd1, 0x03, + 0xc1, 0xe8, 0x84, 0xbc, 0xca, 0x64, 0xdd, 0xac, 0xdd, 0x39, 0xaf, 0x7c, + 0x5d, 0x7a, 0x5f, 0xc3, 0x8b, 0x0f, 0xd7, 0x18, 0x43, 0x4a, 0x8e, 0x3f, + 0x2f, 0x02, 0x91, 0xa2, 0xdc, 0x3e, 0x2c, 0x9c, 0x3b, 0x3c, 0xe3, 0xd4, + 0x9a, 0xb3, 0x59, 0x43, 0xd4, 0x75, 0x1c, 0x4b, 0x0b, 0xad, 0x84, 0x2d, + 0xbd, 0x05, 0x66, 0xdb, 0x0a, 0xda, 0x77, 0x75, 0x46, 0x78, 0x99, 0x44, + 0xdf, 0x12, 0x58, 0xa9, 0x3a, 0x5f, 0x04, 0x18, 0x81, 0xa2, 0x2d, 0xcf, + 0x9c, 0x35, 0x8d, 0x67, 0x73, 0x9e, 0x8d, 0xe4, 0xc9, 0x9d, 0x15, 0x80, + 0xe3, 0x36, 0xf9, 0xbd, 0xf2, 0x65, 0xb2, 0x10, 0xa9, 0xe8, 0x2a, 0x03, + 0x9d, 0x03, 0x11, 0xe5, 0xcc, 0x32, 0x12, 0xef, 0xee, 0x22, 0xa3, 0x0c, + 0x35, 0x28, 0xc0, 0x17, 0x9b, 0x43, 0x75, 0x5f, 0x2c, 0xbf, 0xeb, 0xc4, + 0xf2, 0xa0, 0x6e, 0xcb, 0x06, 0x1c, 0x5c, 0xd9, 0xe8, 0x56, 0xaf, 0xe4, + 0x2c, 0x6a, 0x8a, 0x9e, 0xea, 0x34, 0x60, 0x09, 0x94, 0xe7, 0xb2, 0x50, + 0x4b, 0xc9, 0xeb, 0xce, 0xd2, 0x7f, 0x1d, 0xc1, 0x22, 0xe1, 0x71, 0x1f, + 0xac, 0xb7, 0xb9, 0x5c, 0x8e, 0x44, 0xe9, 0x51, 0x58, 0x5c, 0x0e, 0x12, + 0x34, 0xb5, 0xab, 0xa1, 0x0d, 0xf1, 0xc6, 0x71, 0xf0, 0x51, 0x6f, 0xa8, + 0x72, 0xde, 0xad, 0x42, 0xe6, 0x39, 0x28, 0xb0, 0x66, 0xf8, 0xcb, 0x09, + 0xb2, 0x82, 0x5a, 0x02, 0x15, 0xca, 0x17, 0xa9, 0x63, 0xd8, 0xac, 0x18, + 0x49, 0xf7, 0xfa, 0x6d, 0xad, 0x3f, 0xf5, 0x2a, 0xd2, 0x1a, 0x9e, 0x4f, + 0xdc, 0xb1, 0xb5, 0x5b, 0x93, 0x59, 0x44, 0x72, 0x0c, 0xf4, 0x7e, 0xe4, + 0x62, 0x10, 0x64, 0xad, 0x2d, 0xb0, 0x2e, 0xcb, 0xf8, 0xd9, 0xbb, 0xf9, + 0xfc, 0xc5, 0xe1, 0x31, 0x6e, 0x0e, 0x8b, 0x12, 0x62, 0x25, 0x92, 0xd6, + 0xb0, 0x0d, 0x78, 0x7e, 0x03, 0x13, 0x65, 0xe0, 0xa3, 0x5d, 0x33, 0xc7, + 0x04, 0x8b, 0xe7, 0x45, 0xa8, 0x9f, 0xd1, 0x70, 0x27, 0x32, 0x6e, 0x50, + 0x48, 0x6a, 0xd3, 0x32, 0xcb, 0xca, 0xd5, 0xcd, 0xd4, 0x0a, 0x76, 0x8e, + 0x6b, 0xb1, 0x73, 0x68, 0x38, 0xf5, 0x73, 0xb2, 0x46, 0x7a, 0xb5, 0xff, + 0xea, 0x52, 0xc9, 0x5b, 0x56, 0xff, 0xf0, 0x35, 0x4b, 0xae, 0x88, 0x61, + 0x8a, 0x3c, 0xb9, 0x78, 0x1c, 0x51, 0xaa, 0x5d, 0xaf, 0xe0, 0xe7, 0x8c, + 0x03, 0x85, 0x6a, 0x1f, 0xca, 0xb9, 0x8c, 0xf4, 0x37, 0xea, 0xae, 0x54, + 0xf1, 0xb8, 0x4c, 0x94, 0x42, 0xcf, 0x2a, 0x8d, 0x13, 0xef, 0x66, 0xf8, + 0x1b, 0xbe, 0x5d, 0x9a, 0x24, 0x12, 0xb5, 0xe8, 0xe8, 0x44, 0x6b, 0x95, + 0xd6, 0xed, 0x98, 0xd8, 0x10, 0xeb, 0x19, 0xe5, 0x42, 0x01, 0xaa, 0x1c, + 0x6a, 0x62, 0xd2, 0xf0, 0xc3, 0x33, 0x4d, 0xf0, 0x3e, 0x76, 0x8d, 0xec, + 0xbb, 0xb9, 0xeb, 0x14, 0x77, 0x02, 0x39, 0xb7, 0x75, 0x21, 0x3a, 0xa5, + 0xef, 0x04, 0xb3, 0x20, 0x50, 0xaf, 0xed, 0x99, 0x0b, 0xec, 0x12, 0x6d, + 0xad, 0x9f, 0x23, 0x02, 0xc0, 0x01, 0x5a, 0xfe, 0xfc, 0xee, 0xa9, 0xc1, + 0x23, 0x51, 0x71, 0xb0, 0xe6, 0xee, 0xcc, 0xcd, 0x6a, 0x59, 0xcf, 0xad, + 0xff, 0x4b, 0x36, 0xbf, 0x2a, 0xaf, 0x56, 0xae, 0xd7, 0x35, 0x47, 0xc4, + 0x11, 0xef, 0x66, 0x18, 0xd1, 0xec, 0x2a, 0x5c, 0xca, 0xfe, 0x8f, 0x8b, + 0xa2, 0x80, 0x57, 0x42, 0xe5, 0xa5, 0xb4, 0x7a, 0x34, 0xd0, 0x1b, 0xca, + 0xb3, 0x7f, 0x2c, 0x54, 0x47, 0x50, 0xf0, 0xdd, 0xde, 0x87, 0xc0, 0x8f, + 0x3a, 0x79, 0x49, 0x50, 0xe9, 0x4a, 0xe2, 0x74, 0x08, 0x18, 0x61, 0xaa, + 0x17, 0xe4, 0x44, 0xdf, 0xeb, 0xf8, 0x2f, 0x5f, 0x06, 0x19, 0x06, 0x13, + 0xec, 0x14, 0x47, 0x04, 0x51, 0x03, 0x55, 0x62, 0x78, 0x73, 0x7d, 0xe9, + 0x15, 0xff, 0xd3, 0xb2, 0x5c, 0x54, 0x79, 0xca, 0x58, 0x10, 0x86, 0x66, + 0x4d, 0x6a, 0x73, 0x13, 0x20, 0x60, 0xd1, 0xaa, 0x54, 0xa8, 0xf3, 0x45, + 0x1c, 0x02, 0x23, 0xc6, 0x43, 0xee, 0xb4, 0xf4, 0xed, 0xa3, 0x59, 0xb7, + 0xb3, 0x4e, 0xda, 0xdf, 0x5f, 0x12, 0xed, 0xb0, 0x03, 0x93, 0xc7, 0xb7, + 0xa9, 0x52, 0xdb, 0x91, 0x39, 0x4f, 0x0d, 0x6d, 0x31, 0x08, 0xf5, 0x91, + 0x90, 0xe5, 0x11, 0xbf, 0x33, 0x4d, 0x3f, 0x7b, 0xc8, 0x46, 0xbf, 0x8f, + 0x27, 0x61, 0xc3, 0x6c, 0xea, 0xfa, 0xaf, 0xeb, 0x92, 0xd1, 0x86, 0xb4, + 0x50, 0x64, 0x6c, 0xba, 0xdf, 0x1f, 0xe9, 0xc6, 0x2f, 0xad, 0x8d, 0x95, + 0xe7, 0xfe, 0xcb, 0xbf, 0xcc, 0xba, 0xbd, 0xcc, 0x62, 0x85, 0x62, 0x7a, + 0x96, 0x85, 0x02, 0x1c, 0xc1, 0x8f, 0x4b, 0xfc, 0x4f, 0xea, 0x69, 0x8b, + 0x1c, 0x83, 0x81, 0x34, 0x15, 0x12, 0x16, 0x6f, 0x9c, 0x0e, 0xa4, 0x83, + 0xb6, 0x28, 0x2f, 0xd7, 0x6d, 0x2e, 0x98, 0x6a, 0xe7, 0x6f, 0x53, 0x83, + 0x18, 0x43, 0x75, 0x25, 0x97, 0x14, 0x15, 0x8d, 0x2f, 0x7f, 0x72, 0x1a, + 0x07, 0x42, 0x2a, 0x7a, 0xe4, 0x7e, 0xc4, 0x7a, 0x6a, 0xc9, 0x0f, 0xeb, + 0x4b, 0x60, 0x56, 0x15, 0x51, 0x23, 0x5d, 0xfa, 0x0e, 0x56, 0x06, 0x35, + 0x89, 0x89, 0x77, 0x55, 0xd3, 0xd7, 0x22, 0x2f, 0x41, 0xc5, 0x70, 0x3f, + 0x57, 0x80, 0xc6, 0xab, 0x30, 0x7e, 0xd8, 0x2b, 0xd2, 0xd2, 0xa2, 0xfc, + 0xf9, 0x32, 0x22, 0x9e, 0x63, 0x67, 0x8a, 0x55, 0xac, 0x4e, 0x66, 0x98, + 0xe6, 0x20, 0xea, 0xbd, 0x64, 0xe9, 0xd5, 0x06, 0x33, 0x33, 0xbf, 0xe2, + 0x89, 0x49, 0x91, 0x92, 0x4e, 0xf9, 0xcc, 0x23, 0xad, 0x26, 0x1a, 0xb1, + 0x01, 0x40, 0x9b, 0x3f, 0x30, 0x5c, 0x88, 0xaf, 0xce, 0x83, 0xc3, 0x45, + 0x90, 0xdc, 0xa6, 0x20, 0x3e, 0x15, 0x96, 0x25, 0xdf, 0xe1, 0xa6, 0xd6, + 0x78, 0xaf, 0xda, 0xc0, 0x0c, 0xf1, 0x21, 0x03, 0xf9, 0x7f, 0xb5, 0xfd, + 0x59, 0x20, 0x3d, 0x73, 0xad, 0xfb, 0x2b, 0x5f, 0x88, 0xbc, 0x17, 0xaf, + 0x1c, 0xaa, 0x5d, 0x17, 0x8f, 0xb7, 0x60, 0x9c, 0xc7, 0xc4, 0xe4, 0xf4, + 0xdb, 0xa9, 0x39, 0xb0, 0xd1, 0xb4, 0x6b, 0x4b, 0x20, 0xaf, 0xd5, 0xcc, + 0xd9, 0x68, 0x17, 0x4c, 0x9a, 0xd4, 0x35, 0x25, 0x17, 0x3b, 0xc3, 0x41, + 0x7b, 0x05, 0xe9, 0xe8, 0xdd, 0x02, 0x9d, 0x0f, 0x6a, 0xd7, 0xf5, 0xfa, + 0xae, 0xf2, 0x5b, 0xfe, 0xc4, 0x44, 0x62, 0xd6, 0xc4, 0x8e, 0x4b, 0x28, + 0x6a, 0x87, 0x3c, 0xe3, 0xf8, 0x01, 0xb5, 0xf9, 0x77, 0x4e, 0x07, 0x8f, + 0x40, 0x02, 0x72, 0x81, 0xa9, 0x6e, 0xa8, 0x84, 0x1f, 0xfe, 0x2e, 0x06, + 0x83, 0xb8, 0x14, 0x2b, 0xf8, 0x6e, 0x8b, 0xb2, 0xed, 0xff, 0xc5, 0x90, + 0x09, 0x86, 0xef, 0xe7, 0x64, 0xb3, 0x3f, 0x10, 0xe1, 0x47, 0xff, 0x4f, + 0xac, 0x76, 0x45, 0xa8, 0xba, 0xac, 0xab, 0x82, 0x07, 0x86, 0x8a, 0x24, + 0xf5, 0xc0, 0x01, 0x5f, 0x54, 0x8b, 0xdc, 0xbd, 0xd6, 0x28, 0x05, 0x56, + 0xfd, 0x13, 0xdf, 0x93, 0x9b, 0x68, 0x03, 0x90, 0x2c, 0x08, 0xcc, 0x0b, + 0xf9, 0x14, 0x44, 0x84, 0x79, 0x15, 0xab, 0xbc, 0x54, 0x1b, 0x76, 0xe3, + 0xfa, 0xf8, 0x32, 0xab, 0xf2, 0xcd, 0xed, 0x04, 0x15, 0x94, 0xb4, 0xb3, + 0xcc, 0x09, 0xf1, 0xb2, 0x35, 0x60, 0x0b, 0x05, 0xa1, 0x31, 0xd6, 0x6d, + 0xc6, 0x46, 0x6d, 0xe4, 0xe7, 0xbc, 0x5f, 0x3a, 0x72, 0xfd, 0x42, 0xb0, + 0x0e, 0xbb, 0xd2, 0xeb, 0x50, 0x26, 0x60, 0x38, 0xd6, 0x96, 0x1b, 0x5b, + 0x9d, 0xcc, 0xb4, 0x98, 0x9f, 0xe8, 0xf2, 0x95, 0xa3, 0x11, 0x9a, 0xcb, + 0x6d, 0x56, 0x87, 0x4b, 0x95, 0xb9, 0x41, 0xa3, 0x89, 0x2d, 0x2c, 0x29, + 0xe8, 0x29, 0x86, 0x47, 0x3e, 0x91, 0x2a, 0x59, 0x7d, 0x9c, 0x03, 0x9d, + 0x2d, 0xff, 0x05, 0x50, 0x21, 0x88, 0x12, 0x55, 0x2b, 0x25, 0x0c, 0x0c, + 0x59, 0xa9, 0x1f, 0xbd, 0x1c, 0xa0, 0xf9, 0xc2, 0x23, 0x4b, 0xaa, 0xbe, + 0x10, 0x4f, 0xf7, 0x5a, 0x25, 0x49, 0xb2, 0xc8, 0xdc, 0xf7, 0xb1, 0x45, + 0xdf, 0xbb, 0x15, 0xd9, 0x48, 0x49, 0x01, 0x27, 0xf6, 0xdc, 0x59, 0x48, + 0xb7, 0xd7, 0x5e, 0x46, 0xde, 0x2c, 0x27, 0x64, 0xf9, 0xc2, 0xc5, 0x37, + 0x21, 0x9a, 0xbf, 0x62, 0x14, 0xdd, 0x13, 0x26, 0x9f, 0x62, 0x65, 0x55, + 0xe8, 0xd7, 0x6f, 0x10, 0x5c, 0xd7, 0x19, 0x16, 0x1b, 0x87, 0xd3, 0x74, + 0xd2, 0x8a, 0x89, 0x15, 0x17, 0xd8, 0x83, 0x8f, 0x3f, 0x38, 0x98, 0x9b, + 0x25, 0x03, 0xc7, 0x7c, 0x35, 0x88, 0x53, 0x48, 0xca, 0xd6, 0x4d, 0x20, + 0x23, 0x54, 0x15, 0x51, 0xda, 0xfb, 0x7e, 0x41, 0xbc, 0x88, 0xf5, 0x53, + 0xf6, 0xe2, 0x54, 0xe6, 0xa8, 0xb1, 0x04, 0xac, 0xd1, 0xd6, 0x37, 0xd2, + 0xa9, 0x6f, 0x96, 0xc0, 0x6a, 0xb1, 0xd4, 0xcf, 0x1e, 0xda, 0xda, 0x72, + 0x43, 0xaa, 0x7b, 0x7d, 0x39, 0x19, 0x11, 0x06, 0x2a, 0x73, 0x87, 0xe6, + 0xdb, 0x8a, 0xcf, 0x66, 0xf2, 0x77, 0xc9, 0x0a, 0xe2, 0x13, 0x90, 0xd6, + 0x1b, 0xa6, 0xfb, 0xfd, 0xda, 0x63, 0x80, 0x81, 0x55, 0x7a, 0x4b, 0xea, + 0x79, 0x4d, 0xa9, 0x46, 0x2b, 0xb1, 0xa5, 0x98, 0x8d, 0x34, 0x32, 0x07, + 0xc6, 0xff, 0x98, 0x17, 0xd1, 0x55, 0x85, 0xc6, 0x8d, 0x0a, 0x3b, 0x58, + 0x1e, 0x82, 0x24, 0xa2, 0xef, 0x83, 0xed, 0xf6, 0xe2, 0x79, 0x1b, 0x2b, + 0x46, 0x7e, 0x94, 0x5b, 0xc8, 0x5a, 0x93, 0xef, 0xca, 0x76, 0xc7, 0xef, + 0x71, 0xce, 0x15, 0x33, 0x91, 0xef, 0x46, 0xa9, 0x58, 0xd8, 0x6d, 0xa9, + 0x47, 0x45, 0x35, 0xbb, 0xce, 0x96, 0xb7, 0x44, 0xd4, 0x7a, 0x90, 0xd4, + 0xcb, 0x18, 0xbc, 0x7b, 0x64, 0xf3, 0x8e, 0xf5, 0xd5, 0xf7, 0x82, 0xdb, + 0xff, 0xd6, 0x50, 0x17, 0xdf, 0x9a, 0x11, 0x75, 0x85, 0x36, 0xc8, 0x0c, + 0x44, 0xcc, 0xdc, 0x76, 0xfc, 0x9f, 0x3e, 0x84, 0x8f, 0xea, 0xc6, 0xb1, + 0xfa, 0x97, 0x75, 0x31, 0xe8, 0xc2, 0x81, 0x7b, 0x39, 0x14, 0xad, 0xdf, + 0x67, 0xf2, 0x44, 0xe0, 0xc4, 0x7a, 0x21, 0x63, 0x74, 0x73, 0x41, 0xf4, + 0xb5, 0xbd, 0x87, 0x36, 0xd0, 0x64, 0xb6, 0x8e, 0x98, 0xd2, 0x79, 0x5f, + 0x4d, 0x22, 0x8c, 0xc1, 0x41, 0x4c, 0xea, 0xb7, 0xab, 0x4b, 0x2e, 0xca, + 0x35, 0x14, 0xd3, 0x90, 0x9e, 0xd6, 0x94, 0x3e, 0x7e, 0xe4, 0x57, 0x09, + 0x22, 0x3c, 0xe6, 0xbe, 0x04, 0x95, 0x75, 0xf8, 0xe0, 0x42, 0xe9, 0xe2, + 0x5e, 0x2e, 0x2a, 0xc6, 0x48, 0x55, 0x42, 0x39, 0xc4, 0x81, 0x6a, 0xc6, + 0x19, 0xea, 0x4c, 0x63, 0x60, 0x11, 0xdf, 0xe7, 0xde, 0x4d, 0x0f, 0xec, + 0x0c, 0x8f, 0x21, 0xe7, 0x94, 0x72, 0x24, 0x4d, 0xc0, 0x44, 0x30, 0x63, + 0x18, 0x06, 0x9b, 0xb9, 0x63, 0xc2, 0x94, 0x6d, 0x78, 0xba, 0x36, 0x58, + 0xe3, 0x07, 0x0f, 0xd4, 0x16, 0xe5, 0xc7, 0x58, 0xb1, 0x5e, 0x96, 0x25, + 0x80, 0xc0, 0x0c, 0x4d, 0xf1, 0xda, 0x8b, 0xc6, 0x66, 0x56, 0x1e, 0x7c, + 0x64, 0x6b, 0x2c, 0xb2, 0x8c, 0xed, 0x07, 0xa7, 0x52, 0x70, 0xbd, 0x68, + 0xd3, 0x48, 0x18, 0x38, 0xa6, 0x60, 0x18, 0x97, 0x4a, 0xd0, 0x88, 0xed, + 0x4c, 0x99, 0xad, 0x88, 0x56, 0xec, 0x2b, 0xd7, 0xb4, 0xd6, 0xc6, 0x43, + 0x58, 0xf6, 0x9b, 0xfb, 0x28, 0xa7, 0xb4, 0xaa, 0x61, 0xc4, 0x09, 0x0b, + 0xa7, 0x51, 0x7a, 0xd3, 0x2f, 0x84, 0xeb, 0x9e, 0xc9, 0xc9, 0xac, 0x7e, + 0x80, 0x2e, 0xa6, 0x88, 0x84, 0xd2, 0x54, 0xca, 0xe6, 0xf1, 0x7c, 0x97, + 0x7c, 0x8a, 0x8a, 0x66, 0x7f, 0x00, 0x4b, 0x73, 0x3f, 0x2e, 0xfb, 0xcc, + 0xe5, 0x07, 0xe6, 0x4e, 0xa1, 0x8e, 0xfc, 0x62, 0xb7, 0xd7, 0xbe, 0xa4, + 0x4a, 0x65, 0xd7, 0xe2, 0xaa, 0x0c, 0xdd, 0x93, 0x93, 0x63, 0x56, 0x46, + 0xe5, 0xe5, 0xf5, 0x47, 0xb1, 0xe4, 0x4e, 0x60, 0x97, 0x83, 0x82, 0x23, + 0x84, 0x37, 0x20, 0xbd, 0xb5, 0x8b, 0x9d, 0x5d, 0xc8, 0xca, 0xe1, 0xa8, + 0x5a, 0xc4, 0xaa, 0xe2, 0x79, 0xda, 0x1d, 0x48, 0x60, 0x4c, 0x2e, 0x06, + 0x95, 0xb4, 0x76, 0x42, 0xa0, 0x6e, 0x52, 0x52, 0x0f, 0xf8, 0x24, 0x81, + 0x21, 0x6f, 0x67, 0x27, 0x9e, 0xe5, 0xf9, 0x9b, 0x8c, 0x82, 0x90, 0x90, + 0xdd, 0xe7, 0xd4, 0x24, 0x54, 0xa7, 0x26, 0x41, 0xd2, 0x54, 0x50, 0x6a, + 0x66, 0xf0, 0xd5, 0x68, 0xaf, 0xd1, 0xd2, 0x00, 0x66, 0xa1, 0x9e, 0x1b, + 0xab, 0xe6, 0x43, 0xa2, 0xb8, 0x05, 0x2f, 0xae, 0x9b, 0xce, 0x15, 0xa2, + 0x5b, 0xd1, 0xb5, 0x53, 0x66, 0x6e, 0xc9, 0x44, 0x7b, 0x8c, 0x5d, 0x94, + 0x63, 0x3c, 0xa5, 0xc5, 0x81, 0x48, 0xd7, 0x98, 0x6b, 0xb7, 0xce, 0xe4, + 0xd9, 0xaf, 0x1c, 0xa9, 0x76, 0x8c, 0x1b, 0x4b, 0x5c, 0x1e, 0x9c, 0x98, + 0xef, 0x74, 0x40, 0xe3, 0xf1, 0x48, 0x8c, 0x14, 0x66, 0xe4, 0x7d, 0xbd, + 0xff, 0xcf, 0xae, 0xf8, 0x36, 0x79, 0x83, 0x76, 0xe7, 0x66, 0x36, 0x12, + 0x60, 0x17, 0x2f, 0xb0, 0x2f, 0x22, 0x32, 0x4b, 0x42, 0x65, 0xed, 0x76, + 0x6e, 0x4c, 0x9d, 0xb9, 0x54, 0x9b, 0x98, 0x8b, 0x79, 0x8b, 0x0e, 0xaf, + 0x9c, 0x8c, 0xa9, 0x58, 0xaa, 0xa2, 0xde, 0x1a, 0x9b, 0x6d, 0x75, 0x0f, + 0xd2, 0xd4, 0x28, 0xdc, 0xca, 0xcd, 0x91, 0x66, 0xd0, 0xd9, 0xab, 0x3c, + 0x22, 0x55, 0x36, 0x87, 0x4f, 0x41, 0x24, 0x5c, 0xee, 0x5a, 0x54, 0x1a, + 0xe0, 0xf5, 0x2c, 0x01, 0x98, 0xa3, 0x54, 0x6e, 0x6f, 0xdc, 0x88, 0xf7, + 0x86, 0xba, 0xe2, 0x8d, 0x84, 0x95, 0x78, 0x84, 0x8c, 0xc1, 0xae, 0x8c, + 0x7f, 0xa7, 0x91, 0xbc, 0x6d, 0x3b, 0x48, 0x7a, 0x42, 0xa0, 0xc0, 0x0a, + 0xfe, 0xda, 0xbc, 0xe7, 0xa6, 0x76, 0xcb, 0xca, 0x68, 0xb0, 0xda, 0xb3, + 0x2e, 0x4c, 0x57, 0x50, 0xeb, 0xbb, 0x0a, 0x35, 0x94, 0x80, 0xab, 0xcf, + 0xa7, 0xdc, 0xab, 0x31, 0x54, 0xef, 0xe0, 0x77, 0xa5, 0x7e, 0x9e, 0x76, + 0x96, 0x62, 0x92, 0x25, 0xf1, 0xa1, 0xa5, 0x91, 0x06, 0x9e, 0x2f, 0x81, + 0xd8, 0x5f, 0x2e, 0xe4, 0xe8, 0xda, 0x9f, 0xe1, 0x62, 0xe1, 0x30, 0xd0, + 0x16, 0x02, 0xc6, 0xeb, 0x3a, 0x43, 0x4e, 0x64, 0x07, 0x77, 0xf2, 0xda, + 0x0d, 0xf5, 0xd3, 0x1c, 0x26, 0x4c, 0xcd, 0xa4, 0xb3, 0xc5, 0xd6, 0x73, + 0xb4, 0xbc, 0xc0, 0x07, 0x64, 0x98, 0xfb, 0xf6, 0x32, 0xe4, 0xe1, 0xca, + 0x74, 0x4c, 0x64, 0xad, 0x04, 0x53, 0x1b, 0x99, 0x24, 0x7b, 0x2e, 0xd7, + 0x3e, 0x07, 0xba, 0x7a, 0x08, 0x7b, 0xb1, 0xb0, 0x11, 0x3f, 0x4e, 0x66, + 0xd8, 0xa5, 0x4e, 0x72, 0x67, 0xa6, 0xbe, 0x38, 0x76, 0xcf, 0x72, 0x07, + 0x9a, 0x57, 0x2f, 0x29, 0x6d, 0x55, 0xcd, 0x69, 0xed, 0xcf, 0x59, 0x5e, + 0xd9, 0xe5, 0x29, 0x5b, 0xd0, 0x4d, 0x85, 0xea, 0x44, 0x0c, 0xac, 0x2d, + 0x76, 0x28, 0x65, 0x39, 0x2a, 0xfc, 0x9f, 0xe8, 0xd8, 0xce, 0x5c, 0x56, + 0xc0, 0x33, 0xa4, 0xcc, 0x32, 0xa6, 0x00, 0xd8, 0x9d, 0x9d, 0x0a, 0x28, + 0x27, 0x15, 0x42, 0x8e, 0xeb, 0xb0, 0xef, 0x6f, 0xb8, 0x93, 0xe2, 0xdf, + 0x6e, 0x17, 0x46, 0x67, 0x59, 0x05, 0x92, 0xad, 0x87, 0xc6, 0x06, 0x35, + 0xc8, 0x4c, 0x05, 0x1c, 0x9f, 0xf4, 0xa4, 0xa4, 0xa1, 0x8d, 0x11, 0xc7, + 0xab, 0x4b, 0x9b, 0x3a, 0x71, 0xcb, 0x2d, 0x1f, 0xec, 0x61, 0xa0, 0x66, + 0x5f, 0x3d, 0xa3, 0x95, 0x39, 0x7f, 0x98, 0x34, 0x79, 0x32, 0x15, 0x94, + 0xa0, 0x16, 0xa4, 0xf3, 0x45, 0x7b, 0x31, 0xfe, 0xf2, 0xe3, 0x65, 0x01, + 0xc1, 0xf7, 0xcd, 0xcb, 0x59, 0x52, 0xbb, 0xf6, 0xa4, 0x12, 0x22, 0x9e, + 0x5f, 0xd0, 0x50, 0x8a, 0x43, 0x62, 0xfd, 0x22, 0x21, 0xfb, 0xae, 0x08, + 0x57, 0xc7, 0x00, 0xa6, 0x48, 0x2e, 0xcb, 0x0b, 0x76, 0x08, 0xf9, 0xd4, + 0x14, 0x9a, 0xb5, 0xcd, 0xb8, 0x33, 0xc3, 0x0d, 0x2a, 0x3a, 0xf0, 0xe2, + 0x5f, 0x0e, 0x1f, 0xa1, 0x1c, 0x71, 0x38, 0x2e, 0x8e, 0x93, 0x13, 0x27, + 0xa2, 0x4a, 0xdc, 0x95, 0x1e, 0x26, 0x30, 0x5f, 0xdd, 0xc4, 0x15, 0x8e, + 0xa8, 0xfd, 0x80, 0xf4, 0x9e, 0x31, 0x80, 0xc9, 0xa0, 0xf7, 0x61, 0xb5, + 0x55, 0x40, 0xb4, 0x7f, 0xd8, 0xb2, 0x6b, 0x58, 0xba, 0x34, 0xba, 0x78, + 0xa0, 0xee, 0xa2, 0xc4, 0x73, 0x19, 0xc7, 0xdf, 0x1b, 0x46, 0x3c, 0xe0, + 0x7c, 0xb3, 0xf9, 0x7c, 0x35, 0xd5, 0xf0, 0xbf, 0x2c, 0xed, 0xa4, 0x20, + 0x95, 0x0b, 0x05, 0x7a, 0xce, 0xdc, 0x81, 0x95, 0xf3, 0x12, 0x8a, 0x7f, + 0xcb, 0xa8, 0xdc, 0x77, 0xbf, 0x8b, 0xdf, 0xf6, 0xb0, 0xce, 0xce, 0x0b, + 0xdf, 0xe9, 0xcf, 0x92, 0x02, 0x20, 0x82, 0x81, 0x9c, 0x03, 0x72, 0xe8, + 0x41, 0x6b, 0xbe, 0xb6, 0x87, 0x8b, 0xf9, 0x9e, 0x49, 0x77, 0xc5, 0xcf, + 0x73, 0x9d, 0xf6, 0x1c, 0x42, 0x7c, 0xa8, 0xbb, 0xe3, 0x24, 0x70, 0x9f, + 0xef, 0x28, 0xce, 0x45, 0x13, 0x13, 0x5f, 0xad, 0x02, 0x2a, 0xb4, 0x14, + 0x80, 0x66, 0xe1, 0x6b, 0x29, 0x72, 0x77, 0xa3, 0x04, 0x36, 0x28, 0x8d, + 0xc6, 0x39, 0xa3, 0x29, 0x59, 0xbf, 0x1e, 0x69, 0xcc, 0x8f, 0x25, 0x28, + 0xb8, 0x24, 0x7c, 0xea, 0xe9, 0x4c, 0x43, 0x6e, 0x6c, 0x7b, 0x1d, 0x41, + 0x7f, 0xd9, 0xd9, 0x59, 0x1e, 0x45, 0x76, 0xcc, 0x26, 0x6e, 0xe1, 0x80, + 0x73, 0x4d, 0x79, 0x3c, 0x5c, 0x1d, 0x78, 0xf3, 0xf9, 0x75, 0x2c, 0x9d, + 0x9d, 0x8e, 0x90, 0x23, 0xf3, 0xf9, 0xd7, 0x68, 0x14, 0xf3, 0x09, 0x2f, + 0xa1, 0x86, 0xb1, 0x9d, 0xe2, 0x3c, 0xd3, 0x16, 0xc4, 0xdf, 0x7c, 0xcf, + 0xc5, 0xf2, 0x3e, 0x67, 0x8b, 0xc8, 0x3e, 0x23, 0x17, 0xbf, 0x75, 0x1e, + 0xf3, 0x35, 0xee, 0x9f, 0x14, 0xae, 0xc1, 0x5b, 0xe7, 0x92, 0x68, 0xb8, + 0x0f, 0x95, 0x67, 0x1b, 0x55, 0xe7, 0x90, 0x6f, 0x72, 0xa0, 0x78, 0xd2, + 0x57, 0xca, 0x0a, 0x92, 0x62, 0x8d, 0x20, 0x52, 0x84, 0xb3, 0xae, 0x8e, + 0x22, 0x3d, 0x36, 0x3a, 0xfe, 0x68, 0x2d, 0x89, 0x8f, 0x51, 0x5b, 0x87, + 0x87, 0x21, 0x69, 0x1a, 0x90, 0x97, 0x9e, 0x2f, 0x91, 0xae, 0x32, 0x17, + 0x08, 0x0b, 0x3e, 0x65, 0x8a, 0xaa, 0x8e, 0xf3, 0x7b, 0x43, 0xc4, 0x2d, + 0x05, 0xac, 0x7a, 0xd9, 0x29, 0x41, 0xf8, 0x80, 0x64, 0x99, 0x98, 0xc3, + 0xb8, 0x4b, 0x4a, 0x4b, 0x48, 0x2a, 0xbd, 0x38, 0x42, 0x3a, 0xf1, 0x67, + 0x03, 0x1d, 0xd8, 0x00, 0x50, 0xc9, 0xce, 0x3a, 0x34, 0xe5, 0xac, 0x5f, + 0x36, 0x55, 0xf4, 0xf2, 0xa6, 0x09, 0x04, 0x20, 0x64, 0x56, 0xa1, 0x15, + 0x65, 0x4d, 0x07, 0x7e, 0x47, 0xf7, 0x34, 0x30, 0x3a, 0xbe, 0x49, 0xc1, + 0x75, 0xa3, 0x7d, 0xe5, 0x0e, 0xba, 0xdf, 0x81, 0xc0, 0x94, 0xf8, 0xec, + 0x1d, 0x81, 0x63, 0x48, 0x12, 0x16, 0x82, 0x12, 0x8b, 0x2a, 0xf7, 0x6e, + 0x23, 0xa4, 0x11, 0x8b, 0x70, 0xb3, 0x8a, 0xce, 0xd0, 0xdf, 0xc4, 0x6f, + 0x65, 0x01, 0xe4, 0x6e, 0x61, 0x58, 0x78, 0x2a, 0x4b, 0x9a, 0x1b, 0x65, + 0x94, 0xc4, 0xc5, 0x9d, 0x95, 0xc6, 0x12, 0x6f, 0xfc, 0x8a, 0x5e, 0x7f, + 0xc8, 0xbe, 0xa9, 0xf0, 0x65, 0xb9, 0xa7, 0xe5, 0xa9, 0x39, 0xc3, 0x7a, + 0x79, 0x05, 0x72, 0x77, 0x1f, 0xf7, 0x2b, 0x29, 0xf5, 0xb9, 0xce, 0x20, + 0x82, 0x01, 0x21, 0xa0, 0x0c, 0xd5, 0x7c, 0x7b, 0xe5, 0x9a, 0xea, 0xdb, + 0x71, 0xa6, 0xef, 0x57, 0xca, 0x0d, 0x55, 0x3e, 0x3c, 0x9e, 0xac, 0x6c, + 0x18, 0x4e, 0xe9, 0xc4, 0x67, 0x00, 0x1d, 0xc3, 0xf6, 0x88, 0x9d, 0xd5, + 0xb4, 0x1a, 0xa8, 0xde, 0xfa, 0x8c, 0xe8, 0xb5, 0x8a, 0xec, 0x6c, 0x94, + 0x62, 0x63, 0x00, 0xaf, 0x8a, 0x91, 0x4b, 0x1b, 0x01, 0x90, 0x72, 0xa5, + 0x0a, 0x03, 0x50, 0xc7, 0x0d, 0x66, 0xaf, 0xca, 0xae, 0xe5, 0x7f, 0x00, + 0x00, 0x01, 0x0a +}; + +void +h264_get_video_info (VideoDecodeInfo * info) +{ + info->profile = GST_VAAPI_PROFILE_H264_MAIN; + info->width = H264_CLIP_WIDTH; + info->height = H264_CLIP_HEIGHT; + info->data = h264_clip; + info->data_size = H264_CLIP_DATA_SIZE; +} diff --git a/tests/internal/test-h264.h b/tests/internal/test-h264.h new file mode 100644 index 0000000000..d94df4e547 --- /dev/null +++ b/tests/internal/test-h264.h @@ -0,0 +1,31 @@ +/* + * test-h264.h - H.264 test data + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * + * 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 TEST_H264_H +#define TEST_H264_H + +#include +#include "test-decode.h" + +void h264_get_video_info(VideoDecodeInfo *info); + +#endif /* TEST_H264_H */ diff --git a/tests/internal/test-jpeg.c b/tests/internal/test-jpeg.c new file mode 100644 index 0000000000..f3bd4a1410 --- /dev/null +++ b/tests/internal/test-jpeg.c @@ -0,0 +1,2082 @@ +/* + * test-jpeg.c - JPEG test data + * + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "test-jpeg.h" + +#define JPEG_CLIP_WIDTH 320 +#define JPEG_CLIP_HEIGHT 240 +#define JPEG_CLIP_DATA_SIZE 24481 + +/* Data dump of a 320x240 VC-1 video clip (jpeg.raw), it has a single frame */ +static const guchar jpeg_clip[JPEG_CLIP_DATA_SIZE] = { + 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01, + 0x01, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xff, 0xdb, 0x00, 0x43, + 0x00, 0x05, 0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04, 0x04, 0x04, 0x05, + 0x05, 0x05, 0x06, 0x07, 0x0c, 0x08, 0x07, 0x07, 0x07, 0x07, 0x0f, 0x0b, + 0x0b, 0x09, 0x0c, 0x11, 0x0f, 0x12, 0x12, 0x11, 0x0f, 0x11, 0x11, 0x13, + 0x16, 0x1c, 0x17, 0x13, 0x14, 0x1a, 0x15, 0x11, 0x11, 0x18, 0x21, 0x18, + 0x1a, 0x1d, 0x1d, 0x1f, 0x1f, 0x1f, 0x13, 0x17, 0x22, 0x24, 0x22, 0x1e, + 0x24, 0x1c, 0x1e, 0x1f, 0x1e, 0xff, 0xdb, 0x00, 0x43, 0x01, 0x05, 0x05, + 0x05, 0x07, 0x06, 0x07, 0x0e, 0x08, 0x08, 0x0e, 0x1e, 0x14, 0x11, 0x14, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0xff, 0xc0, 0x00, 0x11, 0x08, 0x00, 0xf0, 0x01, 0x40, 0x03, + 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x00, + 0x1d, 0x00, 0x00, 0x02, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x05, 0x03, 0x06, 0x07, 0x02, + 0x08, 0x01, 0x00, 0x09, 0xff, 0xc4, 0x00, 0x43, 0x10, 0x00, 0x02, 0x01, + 0x03, 0x02, 0x04, 0x04, 0x05, 0x02, 0x04, 0x03, 0x07, 0x03, 0x04, 0x03, + 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x11, 0x00, 0x21, 0x06, 0x12, 0x31, + 0x41, 0x13, 0x22, 0x51, 0x61, 0x07, 0x14, 0x32, 0x71, 0x81, 0x91, 0xa1, + 0x15, 0x23, 0x42, 0xb1, 0x52, 0xc1, 0xd1, 0x08, 0x24, 0x33, 0x62, 0xe1, + 0xf0, 0xf1, 0x16, 0x43, 0x72, 0x25, 0x26, 0x34, 0x82, 0x17, 0x53, 0x83, + 0x93, 0xff, 0xc4, 0x00, 0x19, 0x01, 0x00, 0x02, 0x03, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, + 0x00, 0x01, 0x04, 0x05, 0xff, 0xc4, 0x00, 0x2b, 0x11, 0x00, 0x02, 0x02, + 0x01, 0x04, 0x02, 0x02, 0x02, 0x01, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x02, 0x11, 0x03, 0x04, 0x12, 0x21, 0x31, 0x22, 0x41, + 0x13, 0x32, 0x05, 0x51, 0x14, 0x23, 0x42, 0x61, 0x33, 0x52, 0x91, 0xb1, + 0xc1, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, + 0x00, 0x3f, 0x00, 0xcc, 0xb8, 0xce, 0xf5, 0x70, 0x83, 0x8b, 0x2f, 0x40, + 0x79, 0xe2, 0x4b, 0x8c, 0xe8, 0x17, 0xd8, 0x48, 0xdf, 0xe9, 0xa8, 0x2d, + 0xbc, 0x52, 0xa1, 0xb3, 0x2d, 0x34, 0xa8, 0x00, 0xc1, 0xc2, 0x67, 0x6f, + 0x5f, 0xdb, 0x53, 0xf1, 0x9d, 0x08, 0x97, 0x8b, 0xef, 0x72, 0x0d, 0xc7, + 0xcf, 0xcf, 0xb7, 0x4f, 0xfd, 0xc3, 0xa4, 0x33, 0x47, 0x15, 0x0d, 0x1c, + 0xac, 0x55, 0x89, 0x70, 0x42, 0xb7, 0x4c, 0x1c, 0xf4, 0xd6, 0x13, 0x97, + 0x3f, 0xb3, 0x2d, 0x74, 0xfc, 0x6f, 0xc3, 0xe1, 0xc2, 0xbd, 0x4c, 0x8a, + 0x71, 0x82, 0x5a, 0x3c, 0x63, 0x56, 0x4b, 0x1f, 0x10, 0xf0, 0xfd, 0x7b, + 0xaa, 0x0b, 0xa5, 0x2a, 0xf3, 0x79, 0x40, 0x69, 0x00, 0x39, 0xfc, 0xeb, + 0x13, 0xf0, 0x62, 0x7e, 0x5e, 0x65, 0x00, 0xb6, 0xdb, 0x6b, 0xa1, 0x48, + 0x88, 0x4a, 0x82, 0x36, 0xf6, 0xd4, 0xb7, 0xec, 0x1d, 0x87, 0xa5, 0xae, + 0x57, 0x24, 0x8b, 0x84, 0x2a, 0x28, 0x28, 0xcd, 0x34, 0x8a, 0xb3, 0x2b, + 0x19, 0xe3, 0x91, 0x5c, 0x91, 0x83, 0xb6, 0xdd, 0x35, 0x41, 0xba, 0xd7, + 0x25, 0x35, 0xbe, 0x69, 0xb0, 0x43, 0x46, 0xa4, 0xe7, 0x3e, 0xc7, 0x59, + 0xcf, 0x0d, 0x41, 0x39, 0xba, 0x2c, 0x71, 0xd4, 0xcb, 0x1c, 0x64, 0x67, + 0x0a, 0xdb, 0x67, 0x3e, 0x9a, 0x7f, 0x7c, 0xba, 0x25, 0x45, 0x9a, 0xb2, + 0xdf, 0x24, 0x85, 0x6a, 0xb2, 0x10, 0x77, 0xe7, 0x5c, 0xf5, 0x3e, 0x9d, + 0x34, 0x8d, 0x9f, 0x17, 0x3f, 0xb2, 0x64, 0x85, 0xd3, 0x33, 0xfa, 0xd9, + 0xcd, 0x5d, 0x4b, 0xd4, 0x33, 0x12, 0xd2, 0x31, 0x6e, 0xbe, 0xa7, 0x3a, + 0x6b, 0xc3, 0x7c, 0x9f, 0xf0, 0xd9, 0xca, 0x9e, 0x6c, 0xfd, 0xf4, 0x0b, + 0xdb, 0xe6, 0x4f, 0x30, 0x4d, 0xb3, 0xd3, 0x4d, 0xf8, 0x76, 0x13, 0x1c, + 0xab, 0x24, 0x83, 0x03, 0x9f, 0x97, 0xec, 0x74, 0x68, 0x7a, 0xe8, 0xbc, + 0xd8, 0x69, 0xa9, 0xa3, 0x9c, 0x9d, 0x98, 0x95, 0x07, 0x61, 0x81, 0xbe, + 0xfd, 0x34, 0xf2, 0xa9, 0x20, 0x82, 0x21, 0x24, 0xd8, 0x8c, 0x75, 0x43, + 0x8c, 0xef, 0xdb, 0x48, 0xa8, 0x9d, 0x92, 0xea, 0xaa, 0x47, 0x2a, 0x34, + 0x60, 0x07, 0xf5, 0x20, 0x7a, 0x6a, 0xc5, 0x27, 0x87, 0x24, 0x2f, 0x05, + 0x41, 0xcc, 0x6c, 0x31, 0xd3, 0x4e, 0x42, 0x19, 0x58, 0xbe, 0xc5, 0x35, + 0x5c, 0x6b, 0x24, 0xbc, 0xde, 0x2c, 0x24, 0xb2, 0x8c, 0x90, 0x0f, 0xb6, + 0xda, 0x87, 0x83, 0x2e, 0xa2, 0x5b, 0x8c, 0x94, 0xd2, 0xc9, 0xbb, 0x6d, + 0x8c, 0x6c, 0xac, 0x31, 0xb0, 0xd3, 0xca, 0xea, 0x4e, 0x68, 0x1f, 0xc2, + 0x66, 0x78, 0xd4, 0x1f, 0x38, 0x19, 0x03, 0xd8, 0xea, 0x92, 0xb4, 0xb2, + 0xd3, 0x5f, 0x84, 0xb1, 0x1e, 0x53, 0xf5, 0x67, 0xdc, 0x77, 0xd5, 0x9a, + 0xb1, 0x3d, 0xd1, 0xda, 0x5d, 0x38, 0xc4, 0xc1, 0x1d, 0x8a, 0xa4, 0xd4, + 0xc5, 0xe2, 0xa0, 0x1d, 0x39, 0x72, 0x47, 0xb8, 0xf7, 0xd5, 0x52, 0x86, + 0xd7, 0x6e, 0x8e, 0x18, 0xea, 0xa0, 0xb9, 0x20, 0x9a, 0x51, 0x85, 0xa7, + 0x64, 0x6e, 0x6f, 0x5d, 0xfd, 0x35, 0x77, 0x85, 0xc5, 0x5d, 0x2a, 0x3b, + 0x90, 0x4b, 0x27, 0xf3, 0x36, 0xf6, 0xd6, 0x69, 0x55, 0x55, 0x24, 0xb7, + 0x29, 0x62, 0x81, 0x3f, 0x9b, 0x03, 0x98, 0x99, 0xf9, 0x80, 0x07, 0x07, + 0x18, 0xfb, 0x9c, 0x6a, 0x07, 0x81, 0x26, 0x9c, 0x18, 0xc9, 0x6a, 0x39, + 0xeb, 0xa3, 0x82, 0x86, 0x6f, 0x1a, 0x76, 0x7e, 0x54, 0x0a, 0xb8, 0xdf, + 0xed, 0xab, 0x5d, 0x3d, 0x38, 0xa1, 0x52, 0xe6, 0xa6, 0x29, 0x2e, 0x52, + 0x0c, 0x73, 0xf2, 0x73, 0x01, 0x26, 0x73, 0x80, 0x7d, 0x14, 0x6f, 0xf8, + 0xd7, 0x1c, 0x23, 0x6d, 0x82, 0x0a, 0x46, 0xa8, 0xa7, 0xa7, 0xcd, 0x5c, + 0x91, 0xff, 0x00, 0x31, 0x07, 0xd4, 0x89, 0xb6, 0xd9, 0xec, 0x31, 0xd4, + 0xf7, 0xd4, 0xf4, 0xd5, 0x4d, 0x15, 0x73, 0xd4, 0x49, 0x1a, 0xd5, 0x33, + 0x29, 0x8d, 0x40, 0x5c, 0x0f, 0xfe, 0x2a, 0xbb, 0xe3, 0xef, 0xdf, 0x03, + 0x52, 0x97, 0xa1, 0xeb, 0x0c, 0x62, 0x2b, 0x96, 0x2a, 0x98, 0xea, 0x2a, + 0x4c, 0x93, 0x4b, 0x3b, 0x2a, 0x33, 0x4c, 0x4b, 0x60, 0x06, 0x3f, 0x4f, + 0x31, 0xf5, 0x39, 0xce, 0x3b, 0x69, 0x61, 0x3e, 0x74, 0xa8, 0x8f, 0x0c, + 0x8a, 0x70, 0x37, 0xc7, 0x37, 0xdb, 0xdb, 0x53, 0xde, 0xc4, 0xbc, 0xe5, + 0xa4, 0x51, 0x0c, 0x21, 0xcf, 0x88, 0x13, 0xe9, 0x5c, 0x12, 0x06, 0x74, + 0x38, 0x65, 0x91, 0x55, 0xa2, 0x45, 0x58, 0x97, 0x60, 0x1b, 0xea, 0xfb, + 0x0f, 0x6c, 0xff, 0x00, 0xa6, 0xa0, 0xcd, 0xa0, 0xb5, 0x28, 0xd3, 0x32, + 0xac, 0x3c, 0xa5, 0xe4, 0x7c, 0x28, 0x0b, 0xe6, 0xc9, 0xd7, 0x70, 0xc6, + 0x60, 0x79, 0x21, 0x90, 0xf3, 0xf8, 0x7f, 0x4b, 0x0e, 0x80, 0xff, 0x00, + 0xde, 0xfa, 0xea, 0xb4, 0x55, 0x53, 0xd7, 0x37, 0x38, 0x0a, 0xe1, 0x41, + 0x1c, 0xbe, 0x50, 0xb9, 0xdf, 0x61, 0xa8, 0x22, 0xcc, 0x91, 0xba, 0x9d, + 0x98, 0xb9, 0x63, 0xef, 0xbe, 0xa1, 0x36, 0x8e, 0xf8, 0x5a, 0x08, 0xaa, + 0xee, 0x71, 0xa5, 0x6c, 0xf2, 0x45, 0x4e, 0x5c, 0xb4, 0x92, 0x20, 0x04, + 0xa8, 0x03, 0x3b, 0x0f, 0xbe, 0x34, 0xce, 0xb5, 0x6c, 0x86, 0xa9, 0x84, + 0x92, 0x48, 0xa8, 0xe3, 0x9c, 0x4a, 0xa3, 0x94, 0x31, 0xef, 0xb7, 0xf9, + 0xe9, 0x47, 0x0b, 0xc6, 0x2a, 0x0d, 0x42, 0x24, 0xca, 0xb2, 0x02, 0x07, + 0x23, 0x6d, 0x90, 0x3b, 0xe7, 0x4e, 0xe7, 0xa2, 0xf0, 0xe8, 0x5a, 0xa2, + 0xa4, 0x0e, 0x48, 0xce, 0xc0, 0xf5, 0x3f, 0x6d, 0x26, 0x53, 0x51, 0x97, + 0x26, 0x1c, 0xb1, 0x79, 0x1f, 0x04, 0x7c, 0x35, 0x4d, 0x40, 0x2f, 0x52, + 0x34, 0x51, 0xc8, 0xcb, 0xe1, 0x16, 0x46, 0x77, 0xc8, 0x27, 0x9b, 0x6d, + 0xbf, 0x1a, 0xb0, 0x52, 0xda, 0xcd, 0x69, 0x92, 0xae, 0xb7, 0x3e, 0x00, + 0x25, 0x82, 0xe3, 0xf7, 0xd5, 0x52, 0xdb, 0x71, 0x88, 0xcc, 0x4c, 0x50, + 0xb4, 0x2a, 0xad, 0xb4, 0x85, 0xb7, 0x1e, 0xf8, 0xd5, 0x8e, 0xa6, 0xf3, + 0x5e, 0xd6, 0x7a, 0x81, 0x4a, 0x91, 0xc8, 0xdc, 0xbc, 0x85, 0x97, 0xfa, + 0x57, 0xa1, 0x3a, 0xc1, 0x9b, 0x0e, 0x4c, 0xb2, 0xdd, 0x01, 0x19, 0x31, + 0xc9, 0x3a, 0xa1, 0x35, 0xc6, 0xf9, 0x68, 0xfe, 0x16, 0xca, 0xb4, 0xfe, + 0x13, 0xb4, 0x8d, 0xc9, 0x18, 0x39, 0x63, 0xd8, 0x12, 0x7b, 0x0c, 0x01, + 0xaa, 0x25, 0x7d, 0x52, 0xb5, 0x67, 0x8e, 0xb1, 0x85, 0x93, 0x94, 0x28, + 0x20, 0xe4, 0x80, 0x3a, 0x81, 0xa3, 0x2a, 0xa3, 0xa7, 0x2c, 0xdc, 0xa4, + 0xb7, 0x2e, 0xd9, 0xf4, 0xf6, 0xd2, 0xba, 0x88, 0xcb, 0xca, 0xbc, 0x83, + 0x7c, 0xe3, 0x5b, 0x63, 0x8f, 0x64, 0x52, 0xb0, 0x94, 0x47, 0x91, 0x99, + 0xa8, 0x7c, 0x09, 0xa1, 0xa8, 0x61, 0x04, 0xe8, 0x32, 0xbf, 0xe1, 0xce, + 0x08, 0x03, 0xdb, 0x56, 0x9a, 0x6a, 0x51, 0x53, 0x4a, 0x23, 0xa7, 0x5f, + 0xe7, 0x8f, 0xe6, 0x28, 0x27, 0x0a, 0x70, 0x37, 0xcf, 0xbe, 0x33, 0xa0, + 0xac, 0xd4, 0xf1, 0xf8, 0x54, 0xa9, 0x38, 0x60, 0xa2, 0x24, 0x0d, 0xca, + 0x33, 0xd4, 0x01, 0x9d, 0x59, 0xb8, 0xd2, 0xd3, 0x45, 0xc3, 0x95, 0x74, + 0xb0, 0xd0, 0xd7, 0x23, 0x89, 0x69, 0x23, 0x95, 0xd9, 0x58, 0x33, 0x07, + 0x61, 0xb8, 0xdb, 0xfe, 0x9d, 0x74, 0xc2, 0xf7, 0x15, 0xc6, 0xc7, 0x55, + 0x18, 0x53, 0xb8, 0x1e, 0x9e, 0xda, 0x1e, 0x3a, 0x5a, 0x58, 0xe6, 0x92, + 0x72, 0xaa, 0xae, 0xf9, 0xe6, 0x62, 0x7a, 0x92, 0x73, 0xa9, 0xa3, 0xff, + 0x00, 0x84, 0x06, 0x73, 0xe8, 0x71, 0xa1, 0xee, 0x0e, 0xb1, 0xdb, 0x65, + 0x24, 0x02, 0x4b, 0x80, 0x06, 0xa7, 0x6e, 0x80, 0xa3, 0xae, 0x5c, 0x9f, + 0x2e, 0x08, 0xf5, 0x07, 0x5f, 0x79, 0x0e, 0x71, 0xa5, 0xb4, 0x15, 0x92, + 0x52, 0x55, 0x29, 0x18, 0xe4, 0x66, 0xc3, 0x7e, 0x74, 0xff, 0x00, 0xc1, + 0x1e, 0x28, 0x65, 0x3d, 0x57, 0xa9, 0xef, 0xa7, 0x55, 0x3a, 0x0a, 0x82, + 0x28, 0x61, 0x0f, 0x42, 0xfb, 0xf3, 0x1c, 0x15, 0x0b, 0xf8, 0xd2, 0xbf, + 0xe1, 0x61, 0x79, 0x39, 0x0a, 0x1c, 0x80, 0x5c, 0xfa, 0x67, 0xb6, 0x9f, + 0xdb, 0x14, 0xa5, 0x34, 0x9c, 0x87, 0x07, 0x7d, 0x72, 0x88, 0x42, 0xfb, + 0xe9, 0x30, 0x7e, 0x4c, 0x18, 0xbe, 0x40, 0xa8, 0x69, 0x4a, 0x44, 0x63, + 0x8d, 0x41, 0x39, 0x27, 0xf1, 0xa6, 0x56, 0xda, 0x39, 0x1a, 0x60, 0x3b, + 0x91, 0x80, 0x35, 0x6d, 0xf8, 0x4d, 0x69, 0xb1, 0x5c, 0x78, 0xba, 0x2a, + 0x6e, 0x21, 0x93, 0x92, 0x8e, 0x48, 0x5f, 0xff, 0x00, 0x73, 0xc3, 0x1c, + 0xfb, 0x10, 0x0b, 0x7a, 0x75, 0xd6, 0x87, 0x3f, 0xc2, 0xca, 0xb8, 0xde, + 0x6a, 0xeb, 0x40, 0x59, 0xa0, 0x8a, 0x46, 0x11, 0x46, 0xc7, 0xcc, 0xca, + 0x0e, 0xc5, 0x4f, 0x7d, 0xb4, 0x53, 0x77, 0xe3, 0xfb, 0x2b, 0x63, 0x7d, + 0x06, 0xfc, 0x2a, 0x5e, 0x1e, 0x6b, 0x3c, 0x34, 0x17, 0xaa, 0x01, 0xe2, + 0x46, 0x00, 0xf9, 0x82, 0x4f, 0x2f, 0x41, 0xb1, 0xdf, 0x6d, 0x58, 0xef, + 0x50, 0x7c, 0x36, 0x9a, 0x9a, 0x5a, 0x19, 0xe9, 0x12, 0x71, 0xbe, 0xf1, + 0x46, 0xc5, 0x94, 0xf4, 0xc8, 0x27, 0xd3, 0xf3, 0xa5, 0x1c, 0x2d, 0x62, + 0xa4, 0x7a, 0x29, 0x4d, 0xc6, 0xbe, 0x3b, 0x7f, 0x82, 0x71, 0x22, 0x49, + 0x80, 0xd9, 0xea, 0x73, 0x9f, 0xce, 0x9e, 0xd2, 0xdd, 0x38, 0x0e, 0xd4, + 0x04, 0x00, 0xa5, 0x5b, 0x05, 0xc3, 0x49, 0xe1, 0x19, 0x33, 0xf9, 0xc6, + 0x3f, 0x4d, 0x66, 0xd3, 0xe3, 0xcd, 0x1b, 0x5b, 0x52, 0xff, 0x00, 0x23, + 0x31, 0x6e, 0x4a, 0x9a, 0x46, 0x79, 0x71, 0xf8, 0x67, 0xc3, 0x55, 0xb0, + 0x3d, 0x45, 0x97, 0x89, 0x54, 0xd4, 0xf5, 0x5a, 0x6a, 0xa5, 0x0a, 0x48, + 0xf4, 0xc8, 0xef, 0xd3, 0x48, 0x2d, 0xdc, 0x05, 0x56, 0xd5, 0xb4, 0xf6, + 0xea, 0x9a, 0x39, 0x56, 0x6a, 0x99, 0x00, 0x47, 0xe4, 0x21, 0x4a, 0xe7, + 0xb1, 0xef, 0xb6, 0xb7, 0xbb, 0x47, 0x14, 0xf0, 0x9d, 0x64, 0x89, 0x47, + 0x4d, 0x24, 0x30, 0x92, 0xdc, 0xa8, 0x92, 0x40, 0x10, 0x13, 0xe8, 0x36, + 0xc6, 0x75, 0x64, 0x9c, 0x42, 0x90, 0x88, 0xcb, 0x47, 0x12, 0x9d, 0xb7, + 0x20, 0x01, 0xae, 0x87, 0xc7, 0xb9, 0x72, 0x37, 0xe1, 0xbf, 0x67, 0xf3, + 0x9f, 0x8a, 0x2a, 0x64, 0x8f, 0x8c, 0xb8, 0x82, 0x30, 0xfc, 0xa9, 0xfc, + 0x4a, 0xa4, 0xed, 0xdc, 0xf8, 0xad, 0xa4, 0x97, 0x3a, 0xc7, 0x89, 0x92, + 0x27, 0x84, 0x32, 0x32, 0x73, 0x37, 0x9b, 0x1b, 0x9e, 0x87, 0x56, 0xdb, + 0xf5, 0xad, 0x62, 0xe2, 0xeb, 0xe5, 0x55, 0x44, 0x8c, 0xfe, 0x25, 0xc6, + 0xa5, 0x95, 0x7b, 0x00, 0x64, 0x63, 0xaa, 0x1d, 0xd6, 0x56, 0x9e, 0xbe, + 0x57, 0x41, 0xcc, 0x39, 0x88, 0x51, 0xe8, 0x35, 0x9c, 0xcd, 0x3f, 0xb3, + 0x24, 0xa3, 0x2f, 0x35, 0x6a, 0x4b, 0x08, 0x29, 0xcb, 0xdf, 0xae, 0xfa, + 0x26, 0xe0, 0xd1, 0x73, 0xaa, 0x02, 0x39, 0xb3, 0x83, 0x83, 0xfe, 0x5a, + 0x5d, 0x12, 0x4a, 0x57, 0x94, 0x61, 0x79, 0x8f, 0x73, 0xa2, 0x23, 0x49, + 0x04, 0xa2, 0x05, 0xf3, 0x3e, 0x36, 0x3f, 0xf5, 0xd4, 0x08, 0xb0, 0xf0, + 0xcc, 0x4b, 0x4c, 0x79, 0xd8, 0x6d, 0x30, 0xc0, 0x3e, 0xfa, 0x87, 0x89, + 0x68, 0xbc, 0x1b, 0x87, 0x88, 0xd1, 0xb0, 0xf1, 0x94, 0x30, 0x24, 0x75, + 0xd4, 0x31, 0x5c, 0x66, 0xf1, 0xe1, 0xa1, 0x47, 0xc4, 0x68, 0x06, 0x40, + 0x1d, 0x70, 0x37, 0xfd, 0x74, 0xc2, 0xfb, 0x4e, 0xe6, 0x18, 0xdf, 0x9d, + 0x98, 0xc5, 0x91, 0xbf, 0xf8, 0x4e, 0x08, 0x1a, 0x0c, 0x9c, 0x2a, 0x2e, + 0x5d, 0x08, 0xe0, 0x85, 0xe5, 0x90, 0xc2, 0xbb, 0x93, 0xd0, 0x68, 0x8a, + 0x75, 0x64, 0xa6, 0x32, 0x28, 0xf3, 0x83, 0x8d, 0xba, 0x1f, 0x43, 0xa1, + 0xe9, 0x25, 0x10, 0xdc, 0x12, 0x5c, 0xe0, 0x86, 0xf2, 0x9f, 0x7d, 0x3d, + 0xa6, 0xa4, 0x92, 0x76, 0x03, 0x99, 0x10, 0xb6, 0xe4, 0x1f, 0x7d, 0x54, + 0x45, 0xa0, 0x1a, 0x2a, 0x8a, 0x85, 0x98, 0x4c, 0x67, 0x22, 0x44, 0x3c, + 0xc4, 0x9d, 0xf5, 0x75, 0xa3, 0xaf, 0x59, 0xa2, 0x8d, 0xe1, 0x95, 0x24, + 0x57, 0x50, 0x7d, 0xc1, 0xf4, 0xc6, 0xab, 0xb2, 0x70, 0xed, 0xc3, 0xc4, + 0x63, 0x17, 0x86, 0xc9, 0xca, 0x49, 0x3c, 0xdd, 0xb5, 0xf6, 0xcb, 0x47, + 0x35, 0x34, 0xe9, 0x1a, 0x48, 0x4a, 0x44, 0xaf, 0xe2, 0xc6, 0xaf, 0x8d, + 0xce, 0x0e, 0x7e, 0xda, 0x6f, 0xd4, 0xd0, 0xb1, 0x6f, 0xa4, 0x59, 0x12, + 0xf7, 0x14, 0x15, 0x5e, 0x11, 0x3c, 0xc3, 0x18, 0x75, 0xec, 0x74, 0x6d, + 0x96, 0x0a, 0x58, 0xee, 0xa6, 0x48, 0x54, 0x2c, 0x75, 0x28, 0x59, 0x73, + 0xb8, 0xcf, 0x70, 0x74, 0x92, 0x8a, 0x4a, 0x0a, 0x8a, 0x59, 0x96, 0x7f, + 0x0e, 0x9e, 0xad, 0xd8, 0xb4, 0x0f, 0xfe, 0x21, 0xfe, 0x1f, 0xef, 0xfa, + 0x68, 0xae, 0x1a, 0x92, 0x49, 0xa8, 0xe5, 0x12, 0x48, 0xce, 0x12, 0x5f, + 0x26, 0xfd, 0x0f, 0xa8, 0xd2, 0x66, 0xf7, 0x0b, 0x71, 0xae, 0x03, 0x78, + 0x86, 0x9a, 0xa2, 0x9a, 0x17, 0xa5, 0xb5, 0x43, 0xfc, 0xc6, 0x89, 0xb9, + 0x14, 0x1e, 0xe7, 0x7d, 0xbf, 0xd3, 0x59, 0xc5, 0x9a, 0x92, 0x15, 0xa7, + 0x8e, 0x26, 0x86, 0x46, 0xac, 0xf1, 0x49, 0x98, 0xb6, 0xd8, 0x39, 0xdf, + 0x27, 0xb6, 0x0f, 0x6d, 0x6c, 0x54, 0x6a, 0x95, 0x02, 0x29, 0x65, 0x24, + 0xca, 0x23, 0xfa, 0x86, 0xc7, 0x39, 0xdf, 0xfb, 0x7e, 0xfa, 0xab, 0x71, + 0x8d, 0x25, 0x35, 0x3d, 0xd1, 0xe7, 0x76, 0x31, 0xc1, 0x30, 0xf1, 0x58, + 0x29, 0xfa, 0xe4, 0x1b, 0x15, 0xfc, 0xee, 0x7f, 0x1a, 0xac, 0x19, 0x29, + 0xb1, 0xd8, 0x1f, 0x20, 0xaf, 0x5c, 0x69, 0x21, 0x45, 0x3e, 0x49, 0x1c, + 0x0f, 0x0c, 0x46, 0xdb, 0x10, 0x47, 0x5c, 0x0c, 0x02, 0xc7, 0xae, 0x4f, + 0x4d, 0x75, 0x44, 0xf1, 0x07, 0x0e, 0xc0, 0xa3, 0xa3, 0x06, 0x96, 0x51, + 0x21, 0x27, 0x1f, 0xe0, 0x5f, 0xb9, 0xfe, 0xda, 0x46, 0x6a, 0x67, 0x92, + 0x59, 0x26, 0xa7, 0x79, 0x23, 0x55, 0xd8, 0x21, 0xfa, 0x98, 0x74, 0xeb, + 0x8d, 0x1d, 0x0d, 0x4c, 0x8a, 0x64, 0x91, 0x89, 0x42, 0x1b, 0x99, 0x54, + 0x11, 0xb9, 0xfc, 0x7d, 0xf5, 0xa4, 0xdf, 0x10, 0x5b, 0xcc, 0x6a, 0x79, + 0x1d, 0x97, 0x9a, 0x10, 0xac, 0x47, 0xaa, 0xef, 0xa5, 0xb4, 0xcc, 0xd2, + 0x4a, 0x22, 0x2c, 0xa8, 0xe7, 0xb4, 0x87, 0x1b, 0x7a, 0xe7, 0x4d, 0x4c, + 0xae, 0xf5, 0x45, 0x98, 0x02, 0x5c, 0x73, 0x1f, 0x4d, 0xf7, 0xd7, 0xeb, + 0x7c, 0xd1, 0x2c, 0x35, 0x08, 0xd4, 0xc7, 0x92, 0x6c, 0x2b, 0x33, 0x0e, + 0x60, 0xbb, 0xef, 0xbf, 0x6e, 0xdf, 0xa6, 0xa1, 0x05, 0xb2, 0x24, 0xb8, + 0x25, 0xc9, 0x25, 0x8f, 0x36, 0xfa, 0x82, 0xae, 0xa5, 0x29, 0x60, 0x0c, + 0x06, 0xe3, 0x1f, 0xae, 0x8d, 0xb8, 0x47, 0x1c, 0x55, 0x07, 0xc2, 0xa9, + 0x2c, 0x87, 0x3c, 0xa7, 0xaa, 0x8f, 0x63, 0xe9, 0xa4, 0xb7, 0xa6, 0x32, + 0x4e, 0x90, 0x73, 0x0c, 0x28, 0xe6, 0x38, 0xf5, 0xd4, 0x02, 0x7e, 0x28, + 0xf9, 0x4b, 0x70, 0x9a, 0x9a, 0xbd, 0xaa, 0x11, 0xbc, 0x8d, 0x91, 0x8e, + 0xc7, 0xef, 0xab, 0x62, 0x55, 0x25, 0xca, 0x89, 0x57, 0xc5, 0x63, 0x4e, + 0x76, 0x92, 0x32, 0x7a, 0x7a, 0x7e, 0x87, 0x1a, 0xa4, 0x26, 0x54, 0x95, + 0xd5, 0x9b, 0x85, 0xff, 0x00, 0xfc, 0x57, 0x1e, 0xa7, 0x4a, 0x66, 0x7c, + 0x55, 0xbd, 0x26, 0x7e, 0xa9, 0x53, 0x4f, 0x51, 0x1c, 0x4a, 0xcc, 0x6a, + 0x89, 0xdc, 0x93, 0x84, 0xe5, 0xf7, 0xd3, 0x2a, 0x74, 0x96, 0x4a, 0x69, + 0x97, 0xc4, 0x09, 0x19, 0x19, 0x24, 0xf4, 0xeb, 0xa5, 0x15, 0x33, 0x78, + 0x26, 0xbd, 0xa6, 0xe6, 0x66, 0x7c, 0x2a, 0x38, 0xfe, 0x91, 0xe9, 0xa6, + 0x7e, 0x1b, 0x25, 0xa6, 0x09, 0x26, 0x24, 0x73, 0xa0, 0x0c, 0x73, 0xd7, + 0x1f, 0xf8, 0xd1, 0x35, 0xd3, 0x1f, 0xac, 0xc7, 0xfd, 0x35, 0x21, 0x64, + 0xe9, 0x0a, 0x8c, 0x46, 0x79, 0xc0, 0xdb, 0x9b, 0xdf, 0x51, 0x59, 0xe9, + 0x7e, 0x66, 0xf5, 0x0a, 0x15, 0xca, 0x2b, 0x73, 0xb6, 0xfd, 0x86, 0x88, + 0x48, 0x8c, 0xaa, 0x4c, 0x43, 0x2b, 0xbe, 0xda, 0x71, 0xc3, 0x76, 0xe9, + 0x21, 0xfe, 0x7b, 0xaf, 0x99, 0xdb, 0x39, 0xf6, 0xd1, 0x98, 0x10, 0xe2, + 0xa5, 0x39, 0xa5, 0x2c, 0xa7, 0xa0, 0x03, 0x41, 0xd5, 0x40, 0x85, 0x9e, + 0x37, 0xce, 0x64, 0xe5, 0xc1, 0x27, 0xa1, 0x3a, 0x32, 0x5c, 0x78, 0x87, + 0x1d, 0x73, 0xa8, 0xfe, 0x5c, 0xcd, 0x59, 0xe1, 0xc8, 0xab, 0x24, 0x52, + 0x27, 0x9c, 0x1f, 0x4c, 0x63, 0x1f, 0xdb, 0x41, 0x3a, 0xf6, 0x00, 0x3d, + 0x45, 0x24, 0x94, 0xf2, 0x98, 0x88, 0xc1, 0xf5, 0xd4, 0xd3, 0xda, 0xfc, + 0x68, 0x52, 0x96, 0x45, 0x67, 0x86, 0x68, 0xc4, 0xa1, 0xb3, 0x83, 0xcd, + 0xdc, 0x7d, 0x86, 0xa6, 0xb9, 0xd3, 0xc9, 0xcf, 0x12, 0xc0, 0xbe, 0x45, + 0xc0, 0x03, 0xd1, 0x40, 0xe9, 0xa6, 0x75, 0x17, 0xa9, 0x85, 0x9e, 0x92, + 0x8d, 0x59, 0x55, 0x0b, 0xb6, 0x58, 0x0d, 0x94, 0xf4, 0x0a, 0x4f, 0xed, + 0xa4, 0x2c, 0x91, 0x95, 0x32, 0x14, 0xca, 0x5b, 0x44, 0x95, 0xf5, 0x1c, + 0xbc, 0x8e, 0xa2, 0x36, 0xc1, 0x77, 0x1d, 0x48, 0xd5, 0xba, 0x9a, 0xdb, + 0x24, 0x86, 0x2a, 0x68, 0x91, 0x9d, 0xdb, 0x08, 0x8b, 0xcb, 0xb9, 0x3e, + 0x9a, 0x8e, 0x3a, 0xe9, 0xe1, 0x26, 0x07, 0x44, 0x56, 0x2d, 0x8c, 0x95, + 0xdf, 0x4c, 0xa8, 0x3c, 0x29, 0x1a, 0x28, 0xea, 0x64, 0x78, 0xd9, 0x66, + 0x59, 0x04, 0x88, 0x3a, 0x01, 0xdb, 0xef, 0xd3, 0xf4, 0xd3, 0x3e, 0x47, + 0x77, 0x22, 0x16, 0x9b, 0x27, 0x04, 0x45, 0x2d, 0xbd, 0xda, 0x69, 0x2b, + 0xe9, 0xeb, 0x60, 0x89, 0xd9, 0xa9, 0xa3, 0xa5, 0x32, 0xe4, 0x8c, 0xee, + 0x4e, 0x40, 0x51, 0xb6, 0xa9, 0x74, 0xf4, 0xed, 0xcc, 0x55, 0xb1, 0xe5, + 0xd6, 0xf3, 0x5b, 0x61, 0x9a, 0xff, 0x00, 0x60, 0xf9, 0xee, 0x1c, 0xe3, + 0x79, 0x6a, 0x65, 0x31, 0x05, 0x96, 0x92, 0x47, 0x11, 0x07, 0x00, 0x64, + 0xae, 0x07, 0x43, 0xee, 0x73, 0x9c, 0x1d, 0xf5, 0x4b, 0xe0, 0x4b, 0x7d, + 0x96, 0x3b, 0xe4, 0x53, 0xf1, 0x0d, 0x34, 0x86, 0x28, 0x58, 0x23, 0x44, + 0x98, 0x0a, 0xc4, 0x11, 0xe6, 0x3e, 0xa3, 0xed, 0xff, 0x00, 0x4d, 0x0f, + 0xd2, 0x7e, 0x5e, 0xca, 0xa6, 0x9a, 0xbf, 0x62, 0xab, 0x4f, 0x0f, 0x57, + 0xc1, 0x43, 0x4b, 0x75, 0xaa, 0xa6, 0x78, 0xa9, 0xaa, 0x8f, 0x2d, 0x3c, + 0xa4, 0xec, 0xe0, 0x75, 0xfd, 0xf5, 0xe8, 0xcf, 0x86, 0xb7, 0x29, 0x2b, + 0xb8, 0x6e, 0x18, 0xa6, 0x6c, 0xcd, 0x4c, 0x04, 0x6d, 0xee, 0xb8, 0xf2, + 0x9f, 0xd3, 0x4c, 0xab, 0xed, 0x96, 0xdb, 0xcd, 0x84, 0x51, 0xa2, 0x45, + 0xf2, 0x92, 0xc4, 0xa6, 0x06, 0x88, 0x00, 0x14, 0x63, 0x2a, 0x57, 0x1d, + 0x34, 0x2f, 0x06, 0xd9, 0xaa, 0x2c, 0xf4, 0xf3, 0x47, 0x55, 0x22, 0x49, + 0x24, 0x8c, 0x30, 0xcb, 0xdd, 0x54, 0x60, 0x67, 0xdf, 0x1a, 0xd7, 0x8e, + 0x1b, 0x65, 0xb8, 0xd7, 0x0c, 0x7b, 0x58, 0x48, 0xe1, 0xfb, 0x79, 0xbc, + 0xcd, 0x72, 0x7a, 0x68, 0x24, 0x69, 0x54, 0x64, 0x32, 0x03, 0xca, 0xc3, + 0xb8, 0xcf, 0xaf, 0xf9, 0x68, 0xf8, 0x68, 0x69, 0x61, 0x04, 0x45, 0x4d, + 0x02, 0x02, 0x72, 0x71, 0x18, 0x19, 0x3a, 0x23, 0x7d, 0x55, 0x38, 0xeb, + 0x8b, 0xa0, 0xe1, 0xe8, 0x8c, 0x08, 0x04, 0x95, 0xae, 0xb9, 0x44, 0xcf, + 0xd2, 0x3d, 0x4e, 0x9d, 0x63, 0x5d, 0x25, 0x6c, 0x0f, 0x8e, 0x78, 0x6e, + 0xeb, 0x53, 0x23, 0xd7, 0x58, 0xaa, 0x42, 0x54, 0x4a, 0x04, 0x6f, 0x0b, + 0x72, 0x85, 0x2a, 0x06, 0xc5, 0x72, 0x30, 0x0e, 0x7b, 0xfb, 0xeb, 0x14, + 0xe3, 0x19, 0x78, 0x8a, 0x9e, 0xe5, 0xf2, 0xf7, 0xa7, 0xaa, 0x15, 0x51, + 0x6c, 0x04, 0xec, 0x58, 0x72, 0xf6, 0x03, 0x7c, 0x6a, 0xfd, 0x6e, 0xe2, + 0x7f, 0x88, 0x57, 0x27, 0x15, 0x16, 0xda, 0x69, 0x6a, 0x62, 0x0f, 0xbf, + 0xf2, 0x70, 0x9f, 0xf8, 0xd7, 0x5c, 0x6b, 0x6a, 0xe3, 0xae, 0x2e, 0xa4, + 0xa3, 0x82, 0xb6, 0xcb, 0x49, 0x4f, 0xf2, 0xef, 0xce, 0x24, 0x59, 0x57, + 0x3b, 0x8c, 0x1c, 0x8e, 0x62, 0x7d, 0xfa, 0x6a, 0xb7, 0x19, 0x9a, 0x8e, + 0x4e, 0x8f, 0x34, 0x71, 0x50, 0xf1, 0x38, 0x92, 0xec, 0xb9, 0xc0, 0x35, + 0x53, 0x2f, 0xea, 0xe7, 0x59, 0x84, 0x71, 0x73, 0x49, 0x22, 0xe7, 0x04, + 0x31, 0xdf, 0x5a, 0x5f, 0x15, 0x48, 0xe9, 0xc4, 0xd7, 0x99, 0x1a, 0x36, + 0x58, 0x23, 0xab, 0x97, 0x2c, 0x47, 0x52, 0x64, 0x3d, 0x35, 0x9f, 0x53, + 0x52, 0xd4, 0x2d, 0x1b, 0xd6, 0x3a, 0xaa, 0xc5, 0x25, 0x43, 0x04, 0xf3, + 0x79, 0xba, 0x9e, 0xda, 0xc9, 0x36, 0xab, 0x83, 0x3c, 0xfe, 0xcc, 0x85, + 0x56, 0x35, 0x04, 0x18, 0xcb, 0x39, 0xdb, 0x39, 0xfd, 0xf5, 0x24, 0x23, + 0xc3, 0x8d, 0x99, 0x8e, 0xfd, 0x0f, 0xbe, 0x88, 0x86, 0x9f, 0xc4, 0x26, + 0x42, 0x3c, 0xa8, 0x32, 0x75, 0xc3, 0x46, 0x67, 0x94, 0x3b, 0x82, 0x91, + 0x2f, 0x4d, 0xb3, 0xb6, 0x84, 0xa3, 0x9a, 0x05, 0x06, 0xba, 0x29, 0x58, + 0x75, 0x70, 0x18, 0xfd, 0xce, 0xa7, 0xbf, 0x57, 0xbc, 0xd7, 0x45, 0x46, + 0x93, 0x09, 0x0c, 0x62, 0x12, 0x40, 0xd8, 0x90, 0x49, 0xce, 0x84, 0xab, + 0x7c, 0x05, 0xf0, 0xf6, 0x03, 0x6d, 0x07, 0x2e, 0x49, 0xcf, 0xeb, 0xa5, + 0x86, 0xb8, 0x54, 0x4b, 0x3c, 0xb1, 0x4e, 0x08, 0x40, 0x4e, 0x07, 0x36, + 0x74, 0xe7, 0x87, 0xa6, 0x9a, 0xa6, 0x9d, 0x8c, 0x7b, 0xc9, 0x4e, 0x07, + 0x36, 0xfd, 0x06, 0x90, 0x40, 0xb8, 0x32, 0x30, 0xe8, 0x50, 0xff, 0x00, + 0x96, 0xaf, 0x1c, 0x07, 0x4e, 0x23, 0xb4, 0xbc, 0xb2, 0x79, 0x44, 0x8d, + 0x91, 0xb7, 0x5d, 0x1c, 0x08, 0x13, 0x41, 0x73, 0xe5, 0x0b, 0xce, 0xd8, + 0xf3, 0x6c, 0x74, 0x25, 0x45, 0xc6, 0x9d, 0x24, 0xb8, 0xcf, 0x1c, 0x73, + 0xc8, 0xd1, 0x48, 0xac, 0x44, 0x5d, 0x48, 0xd9, 0x48, 0xc7, 0xa0, 0x38, + 0xd2, 0xcb, 0x95, 0x3c, 0xd4, 0xb7, 0x59, 0x24, 0x15, 0x29, 0x35, 0x20, + 0x93, 0x9c, 0x28, 0x18, 0x3e, 0xbc, 0xb9, 0xec, 0x75, 0xfa, 0xd5, 0x5f, + 0x25, 0x0c, 0x73, 0xac, 0x30, 0xa8, 0x59, 0xf7, 0x04, 0xef, 0x91, 0xe9, + 0xa6, 0x3e, 0x43, 0x53, 0xa7, 0x63, 0x08, 0x2e, 0x10, 0x57, 0x94, 0x9a, + 0x5a, 0x42, 0x7f, 0x9b, 0xc8, 0x5f, 0xc3, 0xce, 0xfe, 0xa7, 0xfd, 0x75, + 0x6a, 0xb4, 0x52, 0xcf, 0x35, 0x72, 0x3a, 0x55, 0xf8, 0x74, 0xb1, 0x27, + 0x99, 0x00, 0xc7, 0x30, 0xed, 0x8d, 0xf6, 0xd5, 0x0a, 0x20, 0x83, 0x3c, + 0x9e, 0x54, 0x24, 0x92, 0x80, 0xec, 0x09, 0x39, 0x3a, 0xb8, 0x70, 0xf5, + 0x47, 0x3d, 0x02, 0xc5, 0xcf, 0xba, 0x80, 0x31, 0xed, 0xdb, 0x48, 0x71, + 0xe6, 0x8b, 0x94, 0xf7, 0x16, 0xd8, 0x04, 0xe0, 0xbb, 0xc2, 0x79, 0xe3, + 0x62, 0x40, 0xef, 0x81, 0xe8, 0x75, 0xf1, 0xa9, 0x1e, 0x48, 0x8c, 0x35, + 0x51, 0x2b, 0x21, 0x1f, 0x4b, 0x0c, 0x82, 0x34, 0x9a, 0xe6, 0x2e, 0x12, + 0xd9, 0x8c, 0x56, 0xfa, 0xa6, 0x86, 0x74, 0xf3, 0x01, 0xda, 0x4f, 0xf9, + 0x4f, 0xb7, 0x6d, 0x7d, 0xb1, 0x5c, 0xea, 0x2a, 0xad, 0xbe, 0x2c, 0x0e, + 0x60, 0xa8, 0x21, 0x83, 0x20, 0x3d, 0x18, 0x1c, 0x11, 0xfa, 0xea, 0x2c, + 0x39, 0x12, 0xab, 0x12, 0xa1, 0x6a, 0xc1, 0xae, 0xbc, 0x22, 0x99, 0xf1, + 0x6d, 0x93, 0x78, 0x0c, 0x09, 0x26, 0x36, 0x3e, 0x56, 0x07, 0xa8, 0x1a, + 0xac, 0xbc, 0x33, 0x51, 0xce, 0x52, 0x60, 0xd0, 0xbf, 0x39, 0x5f, 0x04, + 0x8c, 0x96, 0x00, 0xf4, 0xfb, 0x1f, 0x5d, 0x5c, 0xe8, 0xb8, 0x88, 0x21, + 0xf9, 0x6b, 0xcb, 0x2a, 0xcc, 0x84, 0xf8, 0xa0, 0x0c, 0xba, 0x8e, 0xcd, + 0x8f, 0xea, 0x07, 0xae, 0xbe, 0x71, 0x9d, 0x95, 0x6f, 0xf6, 0xea, 0x5a, + 0x9a, 0x09, 0xd7, 0xc7, 0x8b, 0x78, 0xa4, 0x4e, 0x92, 0x0f, 0x42, 0x7b, + 0x68, 0xa3, 0x36, 0xbe, 0xcc, 0xd3, 0xa7, 0xc9, 0x2c, 0x7c, 0x48, 0xa2, + 0xd6, 0xca, 0x5e, 0x4e, 0x45, 0x26, 0x08, 0x49, 0xca, 0xef, 0x9e, 0xfd, + 0x34, 0x4d, 0xe7, 0xc3, 0xa7, 0xa5, 0x58, 0x39, 0xd5, 0xe4, 0x75, 0xc9, + 0x03, 0x62, 0xbf, 0x8d, 0x09, 0x52, 0xe4, 0x43, 0x25, 0x1d, 0x50, 0x6f, + 0x1a, 0x17, 0xc4, 0x6a, 0xe3, 0x0d, 0x11, 0x07, 0x7c, 0xff, 0x00, 0xae, + 0xa0, 0xb9, 0x97, 0x79, 0x12, 0x69, 0x25, 0x67, 0x79, 0x06, 0x58, 0x9e, + 0xb9, 0xd3, 0xce, 0x92, 0xe5, 0x59, 0x02, 0xb3, 0x3c, 0x8a, 0x07, 0xd3, + 0xf4, 0x9c, 0xe8, 0x2a, 0xf4, 0x31, 0xb4, 0x8d, 0x9c, 0xef, 0x80, 0x71, + 0xe9, 0xdb, 0x47, 0x40, 0xb9, 0x46, 0x61, 0xf5, 0x76, 0xd1, 0xf6, 0xdb, + 0x1c, 0x97, 0xc9, 0x79, 0x96, 0x64, 0xa7, 0x8e, 0x22, 0x64, 0x9e, 0x46, + 0xec, 0xa0, 0xe3, 0xf5, 0x3a, 0x19, 0xc9, 0x46, 0x2e, 0x4c, 0xc9, 0xa8, + 0xe9, 0x15, 0xda, 0x0a, 0x67, 0xaa, 0x91, 0x55, 0x06, 0xed, 0xb9, 0x3e, + 0x9a, 0xb9, 0x51, 0xdb, 0x65, 0x86, 0xdc, 0xa9, 0x19, 0x08, 0xc7, 0xbe, + 0x3a, 0xe8, 0x8b, 0x6d, 0x3d, 0xb2, 0x28, 0xe6, 0x36, 0xb2, 0x1c, 0x09, + 0x44, 0x63, 0xcd, 0x92, 0xd9, 0xd5, 0xda, 0xa6, 0xca, 0xd4, 0xfc, 0x25, + 0x4a, 0xf2, 0x14, 0xf1, 0x9a, 0x56, 0xf2, 0xe7, 0x7c, 0xb6, 0xe3, 0x6f, + 0xd7, 0x59, 0x33, 0x6a, 0x16, 0x2a, 0xbf, 0x62, 0x31, 0x64, 0x58, 0xe6, + 0x9b, 0x33, 0x35, 0xa4, 0x96, 0x66, 0x82, 0x8d, 0x90, 0xb9, 0x33, 0x90, + 0x40, 0xf4, 0xcf, 0xae, 0xae, 0x37, 0xdb, 0x34, 0xaf, 0x6a, 0xf9, 0x11, + 0x16, 0x39, 0x23, 0x00, 0x7d, 0xc6, 0x35, 0x3a, 0x58, 0xea, 0x63, 0xf0, + 0x2b, 0x17, 0xfe, 0x32, 0xb8, 0x21, 0x40, 0xdc, 0x6c, 0x7b, 0xfa, 0xfb, + 0x6b, 0xb9, 0x78, 0x90, 0xd2, 0x31, 0xa7, 0xaf, 0xa7, 0x2f, 0x0c, 0x47, + 0x1e, 0x2c, 0x6b, 0xe6, 0x66, 0x1e, 0xda, 0x44, 0xf3, 0x4b, 0x23, 0x4f, + 0x13, 0xe8, 0x7f, 0xe4, 0x33, 0x47, 0x22, 0xac, 0x6e, 0xd0, 0x8e, 0x9e, + 0xc9, 0xf2, 0x74, 0x86, 0x77, 0x41, 0x95, 0x19, 0x6d, 0xb7, 0xc7, 0xae, + 0x8c, 0xa1, 0x96, 0x2f, 0x94, 0x59, 0x0b, 0x79, 0x1b, 0xa1, 0xc6, 0x98, + 0x55, 0x5f, 0x53, 0xc2, 0x47, 0x36, 0xc9, 0x96, 0x49, 0x90, 0x98, 0xd2, + 0x43, 0xca, 0x59, 0x7d, 0x4e, 0xda, 0x22, 0xc7, 0x60, 0xab, 0x9e, 0xde, + 0x93, 0x25, 0x20, 0x82, 0x09, 0x14, 0x4a, 0xbc, 0xfe, 0x52, 0xca, 0x73, + 0x83, 0x8e, 0xac, 0x36, 0x38, 0x3e, 0xc7, 0x5b, 0x74, 0xd3, 0x9c, 0xbe, + 0xc6, 0x0c, 0x49, 0xfb, 0x2a, 0x95, 0xb7, 0xba, 0x6f, 0x9c, 0x6a, 0x3a, + 0x5e, 0x71, 0x3f, 0xd2, 0x24, 0x65, 0xc2, 0x83, 0xdf, 0xef, 0xa6, 0x7c, + 0x3c, 0x87, 0xe5, 0x5e, 0x49, 0x01, 0xf1, 0x41, 0xf3, 0x16, 0x18, 0x3c, + 0xbd, 0x8e, 0x35, 0xdf, 0x11, 0xda, 0x61, 0xc1, 0x8a, 0x78, 0x44, 0xad, + 0xcf, 0x91, 0x85, 0xc1, 0x23, 0xd3, 0x3a, 0xfa, 0x9e, 0x05, 0x02, 0x88, + 0x69, 0xe5, 0xa9, 0x91, 0x7c, 0x24, 0x88, 0x09, 0x76, 0xe5, 0xee, 0x47, + 0xe0, 0xe4, 0x68, 0xb5, 0x18, 0x9d, 0xd2, 0x18, 0xe2, 0xab, 0x83, 0xa9, + 0xa6, 0x91, 0xe4, 0x25, 0x5f, 0xe9, 0xd9, 0x7d, 0xf1, 0xa6, 0x91, 0xd0, + 0xd1, 0x85, 0x5a, 0x84, 0x60, 0x8b, 0x3e, 0x25, 0x0b, 0x9c, 0x05, 0x63, + 0x8e, 0x6c, 0x67, 0xbe, 0x46, 0x92, 0x48, 0x09, 0xf2, 0x29, 0xc1, 0x03, + 0x3a, 0x7d, 0x5f, 0x6b, 0xf0, 0x69, 0xe9, 0x92, 0xbe, 0x12, 0x95, 0x31, + 0xc6, 0xac, 0x87, 0x39, 0xc0, 0x2a, 0x08, 0x3f, 0xbe, 0xb3, 0x4d, 0x52, + 0xab, 0xa1, 0x32, 0x74, 0x45, 0xc4, 0x10, 0xd3, 0xb3, 0xc3, 0x55, 0x4d, + 0x23, 0x4b, 0xcd, 0xb3, 0xf3, 0x30, 0x24, 0x37, 0x7c, 0xfe, 0x83, 0xf4, + 0xd7, 0x74, 0x12, 0x52, 0xca, 0x82, 0x29, 0x1c, 0x09, 0x06, 0x06, 0xfd, + 0x34, 0x2c, 0xce, 0xca, 0xe1, 0x0e, 0x32, 0x57, 0x25, 0xc0, 0xdd, 0xbd, + 0x33, 0xa1, 0x95, 0x17, 0xc4, 0x75, 0x63, 0xb9, 0x39, 0x07, 0x53, 0x6e, + 0xf8, 0x51, 0x1f, 0x45, 0xda, 0xc9, 0x6e, 0xa8, 0xa8, 0x12, 0xad, 0x2c, + 0x4e, 0x59, 0x50, 0x15, 0x58, 0x50, 0xb9, 0x63, 0xef, 0x8e, 0x9d, 0x33, + 0xa7, 0xb6, 0xae, 0x1f, 0xe2, 0x53, 0x22, 0x1a, 0x7b, 0x65, 0x53, 0x97, + 0xc1, 0x52, 0xd1, 0x15, 0x18, 0xf7, 0x27, 0x4f, 0x7e, 0x0f, 0x71, 0x1c, + 0x56, 0x9e, 0x12, 0xa8, 0xad, 0x8e, 0x8d, 0xdd, 0x68, 0xd9, 0x52, 0xb3, + 0xc2, 0x4e, 0x63, 0xbe, 0x79, 0x5c, 0xfe, 0x32, 0x33, 0xdb, 0xf3, 0xab, + 0xec, 0xdc, 0x61, 0x59, 0x3d, 0x96, 0x7a, 0xaa, 0x2a, 0x38, 0x9f, 0x9d, + 0x39, 0xa0, 0x2d, 0x9c, 0x0d, 0xf0, 0x79, 0x94, 0xfe, 0x4e, 0x85, 0x69, + 0xe3, 0x35, 0xcc, 0xa9, 0x95, 0xf1, 0xc2, 0xae, 0x4c, 0x17, 0x80, 0x38, + 0xaa, 0x7a, 0x4b, 0x55, 0x35, 0x0d, 0xca, 0x95, 0x95, 0x10, 0x94, 0x12, + 0x73, 0x67, 0x90, 0x0e, 0xc7, 0x6d, 0x68, 0xf0, 0xcb, 0x1c, 0xd1, 0x2c, + 0xb1, 0x38, 0x74, 0x61, 0x95, 0x20, 0xec, 0x75, 0x90, 0xd0, 0xf1, 0x7d, + 0xa9, 0x69, 0x4d, 0x15, 0x55, 0x15, 0x0b, 0xd4, 0x16, 0x69, 0x48, 0x4d, + 0x83, 0x39, 0xea, 0x48, 0xc7, 0xa9, 0xd0, 0x75, 0x9c, 0x57, 0x79, 0x85, + 0xfc, 0x6a, 0x6a, 0xd5, 0xa5, 0x45, 0x3b, 0x45, 0x1a, 0x0f, 0x0c, 0x7e, + 0x3b, 0xf6, 0xd0, 0xad, 0x7c, 0x34, 0xbe, 0x32, 0x96, 0xe4, 0x37, 0x16, + 0xad, 0x41, 0x53, 0x76, 0x6b, 0x37, 0x5b, 0xcd, 0xb6, 0x86, 0x51, 0x0d, + 0x5c, 0xfe, 0x1b, 0x1d, 0xfe, 0x82, 0xd8, 0xfd, 0x3a, 0x69, 0x1d, 0xca, + 0x8f, 0x82, 0x2b, 0xa9, 0xde, 0xef, 0x5c, 0xd4, 0x92, 0x2c, 0x6e, 0x26, + 0x7a, 0x89, 0x1f, 0xcd, 0xb7, 0x62, 0x4e, 0xe4, 0x7f, 0xcb, 0xfb, 0x6a, + 0x8b, 0x4f, 0x37, 0x13, 0xdd, 0x2a, 0x24, 0x28, 0x68, 0x9c, 0xcc, 0x7f, + 0x99, 0x2b, 0xf3, 0x2f, 0x20, 0xc6, 0xf9, 0x1f, 0xa7, 0x7d, 0x2c, 0xb9, + 0x5b, 0x28, 0x64, 0x95, 0xbf, 0x8f, 0xf1, 0x3d, 0x24, 0x4b, 0x8c, 0x98, + 0xe9, 0x50, 0xcb, 0x8f, 0xf4, 0xd1, 0x43, 0xf2, 0x73, 0xc9, 0xcc, 0x63, + 0xc0, 0x6f, 0x52, 0xdf, 0xa0, 0x8e, 0x30, 0xf8, 0x8d, 0x51, 0x24, 0x92, + 0xd2, 0xda, 0xa5, 0x11, 0x52, 0xae, 0x52, 0x24, 0x89, 0x79, 0x7c, 0x9d, + 0xbe, 0xdd, 0xb6, 0xd4, 0x7c, 0x03, 0x7d, 0xe2, 0xeb, 0xed, 0x44, 0x76, + 0x5b, 0x4d, 0x5c, 0x54, 0x28, 0x01, 0x92, 0x59, 0x79, 0x01, 0x60, 0x32, + 0x32, 0xc7, 0x3d, 0x7a, 0x8f, 0x4d, 0x65, 0x9c, 0x45, 0x76, 0xa2, 0xa4, + 0xaa, 0x96, 0x2b, 0x7b, 0x3b, 0x53, 0x87, 0x22, 0x27, 0x91, 0x40, 0x76, + 0x1d, 0xbe, 0xd9, 0xd1, 0xdc, 0x1f, 0xc5, 0xf7, 0xa5, 0x34, 0xb6, 0x4b, + 0x2d, 0x33, 0x47, 0x3c, 0xf3, 0x79, 0x8d, 0x39, 0xc4, 0xb2, 0x92, 0x73, + 0xe6, 0x6c, 0x74, 0x03, 0xdc, 0x0e, 0xa7, 0x4d, 0xc2, 0xf2, 0x39, 0xdb, + 0x17, 0x8d, 0xc9, 0xca, 0xdb, 0x28, 0x1c, 0x62, 0x3c, 0x4b, 0xb5, 0xd9, + 0x47, 0xd0, 0x2e, 0x13, 0x78, 0x8b, 0xdc, 0x8e, 0x73, 0xbe, 0x94, 0x5c, + 0x62, 0xa1, 0xa3, 0x31, 0x3c, 0x71, 0x7f, 0xbb, 0xc8, 0xbf, 0xe2, 0xe8, + 0x74, 0xc7, 0x89, 0xa1, 0xa9, 0x6e, 0x2a, 0xba, 0xf3, 0x30, 0x78, 0xcd, + 0x74, 0xe7, 0x04, 0x63, 0x6e, 0x76, 0xdb, 0xf1, 0xa5, 0x35, 0x54, 0x72, + 0x4c, 0xa2, 0x9c, 0x4a, 0xa4, 0x7d, 0x5c, 0xad, 0xb7, 0x4e, 0xc0, 0xe9, + 0xf4, 0xfd, 0x03, 0x3f, 0xb3, 0x01, 0xe4, 0xf9, 0xa2, 0xb1, 0x44, 0x79, + 0x63, 0xea, 0x7f, 0xe6, 0x3a, 0x31, 0x6d, 0x63, 0x90, 0xbc, 0x84, 0x72, + 0x85, 0xc7, 0x36, 0x0e, 0xc3, 0xf1, 0xaf, 0x94, 0xf5, 0x46, 0x89, 0x92, + 0x13, 0x44, 0xf1, 0xb1, 0x50, 0x57, 0xc4, 0xdb, 0x27, 0x44, 0x45, 0x77, + 0xa2, 0x69, 0x58, 0xd4, 0x48, 0xef, 0x57, 0x1b, 0x7f, 0xc2, 0x44, 0xf2, + 0xae, 0xff, 0x00, 0xf7, 0xbe, 0xaf, 0xc2, 0xae, 0x4c, 0x15, 0xd5, 0x95, + 0xda, 0xdb, 0x5d, 0x5c, 0x6f, 0x98, 0xe2, 0x95, 0xd3, 0x19, 0x07, 0xc3, + 0xc6, 0x47, 0xae, 0x35, 0x0d, 0x25, 0xb2, 0xba, 0xae, 0x46, 0x8a, 0x2a, + 0x66, 0x2c, 0xa4, 0x73, 0x0c, 0x7d, 0x20, 0xf4, 0x27, 0x57, 0x19, 0x2b, + 0x94, 0x4c, 0x2a, 0x15, 0x0c, 0x4e, 0xbb, 0x60, 0xff, 0x00, 0xa6, 0x99, + 0x70, 0xa5, 0x31, 0x4a, 0x0a, 0xa9, 0xd4, 0x78, 0x93, 0xcd, 0x29, 0x76, + 0xed, 0xb1, 0xd6, 0x5e, 0xdf, 0x03, 0x0a, 0xb4, 0x1c, 0x33, 0x24, 0x7c, + 0xb4, 0x2b, 0x2a, 0x3d, 0x44, 0xaa, 0x64, 0x73, 0xd0, 0x2a, 0x82, 0x32, + 0x3d, 0xfa, 0xeb, 0xbb, 0xb5, 0x49, 0xa5, 0x46, 0xa3, 0xa6, 0x99, 0xbc, + 0x15, 0xc2, 0xe0, 0x1d, 0x89, 0x03, 0x1f, 0xa6, 0xac, 0x75, 0xee, 0xf4, + 0xd5, 0xd2, 0xc9, 0x51, 0x1b, 0x20, 0x92, 0x97, 0x11, 0xb6, 0x36, 0xfa, + 0xba, 0x67, 0xf1, 0xaa, 0x95, 0x73, 0x47, 0x33, 0x15, 0x41, 0xd3, 0xbf, + 0xae, 0xb6, 0x6d, 0xa4, 0x40, 0x15, 0x12, 0x54, 0xcd, 0x1d, 0x3a, 0xe0, + 0x07, 0x38, 0xc0, 0xe8, 0x34, 0xc5, 0xe0, 0x64, 0x41, 0x1b, 0x6c, 0x54, + 0x6c, 0x3d, 0x34, 0xbe, 0xdd, 0xe2, 0x45, 0x71, 0x0e, 0x9f, 0x50, 0xdc, + 0x1d, 0x3e, 0xf0, 0xe7, 0xa8, 0x4c, 0xcc, 0xc0, 0xef, 0xbe, 0xaa, 0x3d, + 0x94, 0x28, 0x65, 0xc3, 0x6e, 0x37, 0xd3, 0x0b, 0x65, 0x63, 0xd2, 0xb2, + 0xbc, 0x6f, 0xb8, 0x6c, 0x91, 0xed, 0xaf, 0xd2, 0xd0, 0xcb, 0xe1, 0xb1, + 0x5c, 0x72, 0xaf, 0x56, 0x63, 0x80, 0x34, 0xbe, 0x17, 0x4e, 0x40, 0x7b, + 0x8c, 0xfe, 0xfa, 0x94, 0x59, 0xa6, 0x50, 0xc8, 0x92, 0xa2, 0xcc, 0x87, + 0xf9, 0x6e, 0x9c, 0xde, 0xb8, 0xd0, 0xf4, 0x94, 0xe9, 0x05, 0x75, 0x50, + 0x0a, 0x02, 0xca, 0xc2, 0x55, 0xfb, 0x91, 0x83, 0xfd, 0xbf, 0x7d, 0x07, + 0xc2, 0x12, 0x78, 0xb6, 0x7c, 0xe3, 0xfe, 0x1b, 0x60, 0x0f, 0x63, 0xa3, + 0x2b, 0x65, 0x29, 0x71, 0xa7, 0x32, 0x48, 0xb1, 0xc4, 0x62, 0x39, 0x76, + 0x3b, 0x64, 0x11, 0x81, 0xa9, 0x40, 0x47, 0xb1, 0x17, 0x18, 0x43, 0x3f, + 0xf1, 0x9a, 0x0a, 0xda, 0x2a, 0x66, 0x91, 0xd5, 0x5c, 0x4e, 0x14, 0xee, + 0xc1, 0x46, 0x41, 0xfd, 0xf5, 0x15, 0x92, 0xeb, 0x5d, 0x68, 0xa5, 0xf9, + 0xb6, 0x71, 0x2b, 0x99, 0x83, 0xcb, 0x4e, 0xe7, 0x39, 0xce, 0x70, 0x40, + 0xec, 0x71, 0xdf, 0x5f, 0xae, 0x55, 0x15, 0x17, 0xdb, 0x89, 0x96, 0xd9, + 0x28, 0x86, 0x9e, 0x89, 0x49, 0x91, 0xe4, 0x7f, 0x0c, 0xc9, 0xb6, 0x4f, + 0x2e, 0x77, 0xea, 0x31, 0xf8, 0xd0, 0x6f, 0x1a, 0xca, 0x6a, 0x24, 0x97, + 0x2e, 0xae, 0xc1, 0x06, 0x5b, 0x3c, 0xc4, 0x75, 0x27, 0xd7, 0x52, 0x93, + 0x54, 0xce, 0x8e, 0x2a, 0x9c, 0x29, 0xa3, 0x43, 0xab, 0xb3, 0x5a, 0x38, + 0xae, 0x85, 0x2b, 0x56, 0x23, 0x1c, 0xc1, 0x7c, 0xb2, 0xa7, 0xd6, 0x87, + 0xd0, 0xfa, 0x8d, 0x51, 0x78, 0xa3, 0x86, 0x2e, 0x16, 0xb8, 0xfc, 0x59, + 0x23, 0x33, 0xc4, 0x36, 0x33, 0x46, 0x3f, 0x72, 0x3b, 0x6a, 0xcd, 0xc0, + 0xb7, 0xe8, 0xa9, 0x7f, 0xfa, 0x7c, 0xbf, 0xcb, 0x5e, 0x63, 0xe1, 0x9c, + 0xec, 0x3d, 0xb5, 0x7f, 0x0c, 0x93, 0x47, 0xb8, 0x0c, 0xa7, 0xa8, 0xd2, + 0x37, 0x38, 0x3a, 0x7c, 0x99, 0xa7, 0x97, 0x26, 0x9d, 0xd7, 0xa3, 0xcf, + 0xf6, 0xe0, 0xaf, 0x1c, 0xc3, 0x38, 0xe8, 0x41, 0xfb, 0x6d, 0xa6, 0xd6, + 0x8a, 0x3a, 0x99, 0xec, 0xb5, 0x66, 0x2a, 0x81, 0x4e, 0xbb, 0x82, 0x4a, + 0x92, 0x09, 0x2d, 0xd3, 0x6f, 0xb6, 0x8e, 0xf8, 0xad, 0x45, 0x4f, 0x6f, + 0xe2, 0xaa, 0x24, 0xa3, 0x8c, 0x43, 0x1d, 0x54, 0x1c, 0xcd, 0x1a, 0x0c, + 0x2f, 0x30, 0x27, 0xcd, 0xf7, 0xd7, 0x74, 0x73, 0x46, 0x6c, 0xc9, 0x47, + 0x17, 0xf2, 0xf0, 0xdc, 0xcd, 0x8d, 0xf7, 0x3d, 0x75, 0x32, 0x4e, 0xe9, + 0x0c, 0xcd, 0x3d, 0xf0, 0x8b, 0x06, 0xb1, 0xd3, 0xc9, 0x41, 0x6f, 0xf1, + 0x50, 0xa8, 0x74, 0x97, 0x99, 0x64, 0xcf, 0x5d, 0xf3, 0xfa, 0xeb, 0x5e, + 0xe1, 0xa5, 0x3c, 0x79, 0xf1, 0x16, 0x8a, 0x9a, 0xd1, 0x0d, 0x55, 0xae, + 0x8d, 0x60, 0xe4, 0x90, 0xcd, 0x27, 0x3b, 0x04, 0x2b, 0xfc, 0xc2, 0x01, + 0xff, 0x00, 0x10, 0x3f, 0xbe, 0xb3, 0x6b, 0x5f, 0x83, 0x15, 0x39, 0x12, + 0x29, 0x2e, 0x58, 0x88, 0x80, 0xe8, 0x0f, 0xa9, 0x1a, 0x63, 0xc3, 0xb7, + 0x4e, 0x29, 0xb4, 0xde, 0x3e, 0x6a, 0x82, 0xb1, 0xe2, 0x98, 0x73, 0x24, + 0x6d, 0x1a, 0xe7, 0x00, 0xec, 0x40, 0xfc, 0x77, 0xd2, 0xf2, 0xe4, 0x86, + 0xeb, 0x92, 0xe8, 0xcb, 0x29, 0xf2, 0x8b, 0xdd, 0xd1, 0x28, 0xed, 0xb7, + 0xaa, 0x9b, 0x75, 0x2d, 0x4c, 0x6f, 0x0c, 0x32, 0xbc, 0x4a, 0x92, 0x1f, + 0x3e, 0x15, 0xb1, 0xe6, 0x1e, 0xbb, 0x68, 0xde, 0x0b, 0xe0, 0xbe, 0x17, + 0xe2, 0x0b, 0xdd, 0x7b, 0x5c, 0xe5, 0xa8, 0x89, 0xe3, 0x8b, 0xe6, 0xa1, + 0x2b, 0x22, 0x88, 0x9b, 0x0a, 0x32, 0x47, 0xe7, 0x72, 0x35, 0x44, 0xe2, + 0x5a, 0x49, 0xe4, 0xba, 0xc7, 0x70, 0x84, 0x08, 0xe6, 0x91, 0x33, 0x50, + 0x06, 0xc0, 0x38, 0xeb, 0xb7, 0xbe, 0x73, 0xf7, 0xce, 0x9e, 0xf0, 0x7c, + 0x52, 0xbd, 0xa1, 0x1e, 0x4d, 0xbc, 0x09, 0x48, 0x76, 0x0f, 0xe6, 0xf3, + 0x6f, 0x9c, 0x7a, 0x7f, 0xd3, 0x5c, 0xb8, 0xe5, 0x58, 0x5b, 0xcb, 0x1e, + 0x53, 0x33, 0xef, 0xa7, 0x67, 0xce, 0x0f, 0xf8, 0x75, 0x5d, 0xc5, 0x57, + 0xab, 0x8d, 0x5b, 0xa1, 0x78, 0x69, 0xb9, 0x9d, 0xd8, 0x37, 0xd6, 0xd9, + 0xf2, 0xa0, 0xf6, 0xc1, 0x3a, 0x9b, 0x8a, 0x6a, 0x20, 0xe1, 0xf4, 0x92, + 0x89, 0xd4, 0xad, 0x74, 0x51, 0x08, 0x84, 0x6c, 0x30, 0xf1, 0xa0, 0xfa, + 0x57, 0x1d, 0x80, 0xdf, 0x57, 0xee, 0x1b, 0xe2, 0xfa, 0x8a, 0x3b, 0x74, + 0x96, 0xfa, 0x0a, 0x95, 0xa6, 0x09, 0x2f, 0x95, 0xd9, 0x72, 0x5d, 0xb1, + 0xbe, 0x07, 0xa6, 0x4e, 0xaa, 0x3c, 0x6d, 0xc5, 0x7c, 0x41, 0x57, 0x53, + 0x2a, 0x57, 0xdb, 0xed, 0x13, 0xa0, 0xc8, 0x69, 0x85, 0x0a, 0x17, 0x91, + 0x7a, 0x0c, 0xb9, 0x05, 0x81, 0xe8, 0x76, 0x23, 0x5b, 0xf4, 0xb9, 0xf1, + 0xea, 0x9d, 0xc1, 0xb5, 0x43, 0xa1, 0x35, 0x2e, 0x8c, 0xb5, 0x65, 0xa9, + 0xaf, 0x97, 0xc4, 0xaa, 0x9d, 0xdc, 0x86, 0xca, 0xa3, 0x1c, 0x80, 0x3d, + 0x46, 0x88, 0x58, 0x23, 0x07, 0x38, 0x27, 0xee, 0x74, 0xc6, 0xe3, 0x70, + 0x8a, 0xa0, 0x08, 0x7e, 0x4a, 0x3a, 0x52, 0x3f, 0x98, 0x0a, 0x1e, 0xa3, + 0xbe, 0x83, 0xe1, 0x4b, 0x8d, 0x9e, 0xe7, 0xc4, 0xb3, 0x59, 0xa7, 0x95, + 0x48, 0x10, 0x12, 0x18, 0xb7, 0x2a, 0xb3, 0x02, 0x36, 0xfd, 0x37, 0xd6, + 0xa6, 0xdd, 0xf2, 0xc2, 0xb3, 0xf2, 0x4f, 0x43, 0x44, 0x5a, 0xb2, 0xb2, + 0x39, 0x5d, 0x62, 0x52, 0xd1, 0xac, 0x6a, 0x0f, 0xf3, 0x3f, 0xa7, 0x39, + 0xfe, 0x9f, 0x5f, 0xd3, 0xbe, 0xad, 0x22, 0xf8, 0xfc, 0x4b, 0x6c, 0xa2, + 0xb8, 0xcf, 0x6d, 0x7a, 0x3a, 0xaf, 0x07, 0xc2, 0x92, 0x45, 0x1f, 0xcb, + 0x94, 0xaf, 0x42, 0x3d, 0x0e, 0x3b, 0x63, 0xfa, 0x75, 0x35, 0x87, 0x84, + 0xc5, 0xf3, 0x88, 0x63, 0xb1, 0x59, 0x68, 0xe3, 0xa9, 0x9a, 0x37, 0x06, + 0xb8, 0x01, 0x88, 0x69, 0xc7, 0xac, 0x87, 0xb1, 0x3e, 0x9d, 0x75, 0xe8, + 0x7e, 0x1e, 0xf8, 0x79, 0x62, 0xb6, 0xf0, 0xf1, 0xb4, 0xc9, 0x09, 0x96, + 0x39, 0x7c, 0xd2, 0xa8, 0x1c, 0xab, 0xcc, 0x7a, 0xf2, 0x81, 0xd3, 0xf5, + 0xd1, 0x3d, 0x3a, 0xca, 0xa9, 0x85, 0x1c, 0x7f, 0x22, 0xb3, 0xcb, 0xf5, + 0x34, 0xfc, 0xe3, 0x07, 0x63, 0xeb, 0xa1, 0x16, 0x90, 0xac, 0x98, 0x63, + 0xbf, 0x5c, 0xe3, 0x5e, 0xac, 0x8f, 0xe1, 0x7f, 0x05, 0x2c, 0x85, 0xcd, + 0xa8, 0xb0, 0x23, 0xe9, 0x69, 0xdc, 0x81, 0xf6, 0xdf, 0x5c, 0x5d, 0x7e, + 0x16, 0x70, 0x75, 0x6d, 0x32, 0xc5, 0x15, 0xb8, 0xd1, 0xba, 0x7d, 0x32, + 0xc0, 0xe4, 0x37, 0xe7, 0x3d, 0x46, 0x97, 0x0d, 0x16, 0x48, 0xaa, 0x6e, + 0xcb, 0x8e, 0x96, 0x48, 0xc9, 0xfe, 0x09, 0xd8, 0xae, 0x37, 0x1a, 0x7b, + 0xe8, 0xa2, 0xad, 0x6a, 0x4e, 0x7a, 0x5f, 0x08, 0x4a, 0x14, 0x15, 0x67, + 0x24, 0x10, 0x18, 0x1e, 0xd8, 0x07, 0xa6, 0x94, 0xd1, 0x5c, 0xae, 0xf6, + 0x5b, 0xe5, 0x6f, 0x0b, 0x5d, 0x29, 0x62, 0x47, 0x99, 0x4c, 0x4c, 0x40, + 0xc0, 0x52, 0x08, 0xc3, 0x7b, 0x83, 0x8d, 0x7a, 0x0b, 0x82, 0xb8, 0x6a, + 0x9b, 0x84, 0xec, 0xa6, 0x86, 0x12, 0x66, 0x2f, 0x33, 0x3b, 0x38, 0x5d, + 0xdb, 0x24, 0xe3, 0x3f, 0x8c, 0x0d, 0x65, 0x9f, 0xed, 0x01, 0x62, 0x9a, + 0xae, 0xb0, 0x5f, 0xe8, 0x23, 0xfe, 0x65, 0x2a, 0xac, 0x53, 0x28, 0x19, + 0x66, 0xe6, 0x3b, 0x6d, 0xfa, 0x7e, 0xba, 0xbc, 0x9a, 0x5f, 0x15, 0x7d, + 0x93, 0x26, 0x0e, 0x0a, 0x79, 0xb3, 0xc8, 0x6a, 0xd6, 0x38, 0xdc, 0x44, + 0xec, 0xdf, 0x50, 0x1e, 0x51, 0x93, 0xad, 0x1f, 0x86, 0xb8, 0x56, 0x86, + 0x8e, 0x96, 0x5a, 0x8b, 0xad, 0x6c, 0x75, 0xf7, 0x06, 0x24, 0x53, 0x25, + 0x31, 0xe6, 0x55, 0x51, 0xd1, 0xbd, 0xf3, 0xfb, 0x67, 0x59, 0x9d, 0x82, + 0xc9, 0x5f, 0x50, 0xcd, 0x4b, 0x77, 0xb9, 0xc9, 0x46, 0x01, 0xf3, 0x43, + 0x19, 0x2c, 0xfd, 0x7e, 0x9d, 0xb6, 0x1e, 0xfd, 0x71, 0xe9, 0xad, 0x83, + 0x82, 0xeb, 0xec, 0x7c, 0x2b, 0x42, 0x20, 0xac, 0x95, 0x90, 0x22, 0x05, + 0xf1, 0xa5, 0x39, 0xe5, 0x03, 0xa0, 0x19, 0xdf, 0x03, 0x5c, 0xfd, 0x2e, + 0x9a, 0x0a, 0x4d, 0x4d, 0x70, 0x2b, 0x0e, 0x15, 0x16, 0xdb, 0x14, 0xd4, + 0xb5, 0x65, 0x65, 0x9a, 0xa2, 0x96, 0x24, 0x11, 0xc4, 0x1c, 0xe1, 0x10, + 0x05, 0xe6, 0x8c, 0x1d, 0x83, 0x0c, 0xe7, 0x27, 0x62, 0x75, 0x50, 0xbc, + 0x3c, 0x31, 0x40, 0x1a, 0xa9, 0xe3, 0x86, 0x28, 0xb2, 0xbb, 0x26, 0x02, + 0xe4, 0xee, 0x4e, 0x37, 0x3b, 0xea, 0xdd, 0xc4, 0xfc, 0x5f, 0xc3, 0xb3, + 0x55, 0xca, 0xd4, 0xa6, 0x59, 0x63, 0xa9, 0x1c, 0xa5, 0xd6, 0x12, 0xbc, + 0x8c, 0x77, 0x27, 0x27, 0xec, 0x75, 0x97, 0xfc, 0x4c, 0xbd, 0xd2, 0x57, + 0xc9, 0x45, 0x6b, 0xb5, 0xac, 0x92, 0xa1, 0x72, 0xd3, 0xc8, 0xfd, 0x5d, + 0xb3, 0x85, 0xfc, 0x60, 0xe8, 0x73, 0x60, 0x59, 0x73, 0xa8, 0x63, 0x92, + 0xa5, 0xd8, 0x39, 0x60, 0xb7, 0x70, 0xc4, 0x5c, 0x4d, 0x6b, 0xa2, 0x9e, + 0xba, 0x13, 0x41, 0x72, 0x86, 0xe1, 0x55, 0x2b, 0xe3, 0xc2, 0x81, 0x58, + 0xf8, 0x64, 0x9c, 0x2a, 0xef, 0x8d, 0xce, 0x75, 0xbd, 0x7c, 0x19, 0xf8, + 0x6f, 0x6e, 0xe1, 0xbb, 0x5b, 0x54, 0xdd, 0x12, 0x9e, 0xaa, 0xf1, 0x3a, + 0x7f, 0x3b, 0x1b, 0xf8, 0x00, 0xff, 0x00, 0x42, 0xff, 0x00, 0x99, 0xfb, + 0x6a, 0x9b, 0xf0, 0xaf, 0x86, 0xe8, 0xa8, 0xab, 0x1e, 0xbe, 0xbd, 0x44, + 0xd5, 0x2a, 0x02, 0xd3, 0x29, 0xc0, 0x45, 0x73, 0xd4, 0xe4, 0xfe, 0x9f, + 0x9d, 0x69, 0xca, 0x12, 0x95, 0xa4, 0x96, 0xa6, 0x59, 0x10, 0xca, 0x87, + 0xf9, 0x3c, 0xbb, 0x02, 0x3a, 0x01, 0xeb, 0xae, 0x9e, 0x1c, 0xf1, 0xde, + 0xe1, 0x1e, 0x90, 0xec, 0x4e, 0x8f, 0x1f, 0x71, 0x08, 0xab, 0xa8, 0xe2, + 0x6b, 0xba, 0x48, 0x42, 0xc2, 0x2b, 0xa6, 0x0b, 0xca, 0x30, 0x48, 0xe7, + 0x6e, 0xfa, 0x56, 0x68, 0xd5, 0x7c, 0xb3, 0x4e, 0x52, 0x2e, 0x6c, 0x2a, + 0x06, 0xc9, 0xfb, 0xea, 0xc1, 0xc4, 0x66, 0x25, 0xe2, 0x1b, 0x97, 0x8a, + 0x55, 0x54, 0xd6, 0x4b, 0x82, 0x4f, 0x7e, 0x73, 0xa5, 0xcd, 0x5b, 0x68, + 0x84, 0x34, 0x6f, 0x39, 0x72, 0x06, 0xea, 0x91, 0x13, 0xbf, 0xa6, 0x4e, + 0x9e, 0x80, 0xdc, 0xb7, 0xbb, 0x42, 0xd9, 0x28, 0xa4, 0x69, 0x0c, 0x18, + 0x0f, 0x01, 0xf3, 0x73, 0xc8, 0x7d, 0xfb, 0x77, 0xfd, 0x3f, 0x5d, 0x10, + 0x94, 0x74, 0xb1, 0xc7, 0x35, 0x74, 0xd4, 0x08, 0xc8, 0x8f, 0xc8, 0x85, + 0x48, 0xe6, 0x66, 0x3d, 0xcf, 0x36, 0x36, 0xf7, 0xc9, 0xd3, 0x4a, 0x29, + 0x20, 0x92, 0x9d, 0x9c, 0x7c, 0xda, 0xc5, 0xc9, 0xe5, 0x0c, 0xa3, 0xcb, + 0xb6, 0xc7, 0x19, 0xce, 0x34, 0x65, 0x0a, 0x2a, 0x70, 0x65, 0x5d, 0xa5, + 0xed, 0xf4, 0x37, 0x25, 0xad, 0x71, 0x22, 0xcd, 0x3c, 0x38, 0x92, 0x26, + 0x52, 0x30, 0x50, 0x9c, 0x15, 0x23, 0xef, 0x8c, 0x9d, 0x66, 0xcc, 0xd5, + 0xd3, 0x1a, 0x8a, 0xbb, 0xc2, 0x22, 0x75, 0x3f, 0xfb, 0x7d, 0x31, 0xe8, + 0x3f, 0xb6, 0xad, 0xd6, 0x3a, 0x8a, 0x51, 0x4d, 0x2b, 0x23, 0x72, 0xa2, + 0x2a, 0xf3, 0x85, 0x3b, 0x92, 0x37, 0xd5, 0x6a, 0x4a, 0x79, 0x67, 0xaf, + 0x58, 0x99, 0x8e, 0xc0, 0x02, 0x71, 0x8f, 0xce, 0xa1, 0xbd, 0x17, 0xb7, + 0x57, 0xab, 0xd3, 0x33, 0x47, 0x95, 0x1e, 0x6c, 0xec, 0x40, 0x18, 0xdc, + 0x69, 0x69, 0x50, 0x89, 0x21, 0xcf, 0x16, 0xd4, 0x51, 0x57, 0x33, 0x54, + 0x5a, 0xe3, 0x96, 0x9a, 0x90, 0xb7, 0x86, 0x91, 0xbb, 0xf3, 0x90, 0x40, + 0x01, 0x8e, 0x70, 0x3b, 0xe7, 0x1e, 0x9a, 0xa5, 0x5c, 0x33, 0x1a, 0x1f, + 0x50, 0x71, 0x9f, 0x6d, 0x34, 0x8e, 0xea, 0x6a, 0x03, 0x25, 0x53, 0x20, + 0x55, 0xc9, 0x18, 0x1f, 0x56, 0x7a, 0x69, 0x5d, 0x5f, 0x33, 0xc8, 0x59, + 0x17, 0x2b, 0x9e, 0x50, 0xa7, 0xbe, 0x4e, 0xb7, 0x3a, 0xa5, 0x43, 0x10, + 0x45, 0x86, 0xde, 0x64, 0x8b, 0xe6, 0x0a, 0x9e, 0x57, 0x3b, 0x9f, 0x5e, + 0xe7, 0x47, 0x5c, 0x2e, 0x73, 0xd1, 0x8f, 0x06, 0x9e, 0x34, 0x03, 0xa2, + 0x67, 0xaa, 0xfb, 0xfb, 0xe9, 0xc5, 0x24, 0x42, 0x1b, 0x4c, 0x54, 0xa5, + 0x70, 0xc1, 0x41, 0x03, 0x3d, 0xf1, 0xbe, 0xab, 0xf7, 0x57, 0x57, 0x06, + 0x1e, 0x5c, 0x31, 0x38, 0x07, 0x3d, 0x3b, 0x1d, 0x13, 0xe1, 0x10, 0x29, + 0x6e, 0x8a, 0x38, 0x42, 0xa2, 0x9e, 0x62, 0x7e, 0x7e, 0x69, 0x79, 0x5d, + 0xf1, 0xf5, 0xab, 0x0c, 0xfe, 0x31, 0xb6, 0xab, 0xa1, 0x82, 0x46, 0x00, + 0x19, 0xc6, 0xda, 0x7b, 0xc4, 0xd5, 0x14, 0x4c, 0x29, 0x61, 0xa3, 0x62, + 0xea, 0xb1, 0x00, 0x77, 0xd8, 0x10, 0x31, 0xa4, 0x72, 0xe0, 0x81, 0xeb, + 0xd7, 0x48, 0x28, 0x69, 0xc3, 0x17, 0x7a, 0xa8, 0xae, 0x94, 0x74, 0x11, + 0x95, 0x58, 0x4c, 0x86, 0x46, 0x23, 0xea, 0x27, 0x38, 0xc6, 0x7d, 0x37, + 0xd3, 0x7f, 0x88, 0x52, 0x98, 0xea, 0xad, 0x92, 0x54, 0x42, 0x66, 0xa5, + 0xf1, 0x5c, 0x4b, 0xca, 0x3a, 0x74, 0xc7, 0xe9, 0xa4, 0x1c, 0x3f, 0x02, + 0xa7, 0x10, 0x51, 0xd5, 0xce, 0x00, 0x8c, 0x2f, 0x2c, 0x67, 0xd5, 0xb2, + 0x3f, 0xeb, 0xa6, 0xff, 0x00, 0x11, 0x24, 0x35, 0x37, 0x33, 0x42, 0x8c, + 0x24, 0x8e, 0x0a, 0x6f, 0x17, 0x38, 0xc6, 0x0f, 0x36, 0xff, 0x00, 0xd8, + 0x69, 0xa9, 0x9a, 0xa2, 0x9d, 0xc6, 0x8e, 0xed, 0xd1, 0xd2, 0x55, 0xdc, + 0xeb, 0xa1, 0xf9, 0x8a, 0x9a, 0x87, 0x34, 0xab, 0x94, 0xc6, 0x59, 0x90, + 0x6f, 0x93, 0xbf, 0xb8, 0x3b, 0x76, 0x07, 0x3a, 0x86, 0xbe, 0x99, 0x60, + 0xa2, 0x8a, 0x51, 0x3a, 0x48, 0x5d, 0x1b, 0x1c, 0x9b, 0x80, 0x01, 0xd8, + 0x7e, 0x9a, 0x67, 0xf0, 0xfe, 0xe5, 0x4e, 0xb5, 0xe2, 0x09, 0x56, 0x34, + 0x9a, 0xa9, 0x42, 0x2b, 0x9f, 0xeb, 0x5c, 0x12, 0xc8, 0x7d, 0x71, 0xb6, + 0x89, 0xbe, 0x51, 0xd3, 0x43, 0xc3, 0x6f, 0x14, 0x14, 0xfe, 0x1c, 0xb5, + 0x35, 0xd2, 0x95, 0x2b, 0xf4, 0x80, 0x0f, 0xfd, 0x3f, 0x7d, 0x18, 0x70, + 0x96, 0xdc, 0x8e, 0x25, 0x66, 0xdf, 0x50, 0x94, 0xce, 0xd8, 0x3c, 0x8c, + 0xe8, 0xbc, 0xad, 0xff, 0x00, 0x31, 0x1a, 0xd2, 0xf8, 0x2a, 0xfa, 0x95, + 0x51, 0x0a, 0x3a, 0x89, 0x57, 0xc7, 0x85, 0x54, 0x33, 0x67, 0xeb, 0xf7, + 0xc6, 0xb3, 0x14, 0x12, 0x47, 0x2a, 0x4b, 0x9e, 0x56, 0x55, 0xc7, 0x4f, + 0xdf, 0x47, 0xdb, 0xe9, 0xdc, 0x89, 0x24, 0x8e, 0x69, 0x3c, 0x58, 0xc0, + 0x20, 0xe7, 0x7d, 0x23, 0x24, 0x2c, 0x76, 0xa3, 0x12, 0xcb, 0x1a, 0x63, + 0x5f, 0x8b, 0x8d, 0x2c, 0x7c, 0x65, 0x6b, 0x95, 0xc7, 0x3c, 0x26, 0x9b, + 0xc9, 0xf6, 0xe6, 0x20, 0xe9, 0xcf, 0x0e, 0xdb, 0x79, 0x28, 0xe9, 0xeb, + 0x4c, 0x69, 0x53, 0x12, 0x02, 0x15, 0x17, 0x62, 0x8d, 0xd8, 0xe4, 0x63, + 0x3d, 0x08, 0xdf, 0x3d, 0x75, 0x56, 0xe2, 0x4a, 0xa9, 0xae, 0x94, 0xb6, + 0xea, 0xa9, 0x9d, 0x9a, 0x5a, 0x34, 0x31, 0xb0, 0x27, 0x24, 0x8d, 0x59, + 0xb8, 0x3e, 0xfb, 0x4d, 0x05, 0xa4, 0xc7, 0xe2, 0x10, 0x00, 0xcf, 0xeb, + 0xac, 0xba, 0xcd, 0xff, 0x00, 0x12, 0x94, 0x7f, 0x66, 0x5c, 0xf8, 0x9c, + 0x31, 0xa4, 0xbd, 0x0b, 0xae, 0x94, 0xf5, 0x35, 0x57, 0x24, 0x9c, 0x2a, + 0xd2, 0x4a, 0xbb, 0xa2, 0xc6, 0xb8, 0x52, 0x77, 0xd8, 0x8f, 0x5e, 0xbb, + 0xea, 0xe7, 0xc0, 0x33, 0x4b, 0x5e, 0xcd, 0x6f, 0xa6, 0xa0, 0x98, 0x56, + 0x49, 0x11, 0x90, 0x2f, 0x3a, 0x9e, 0x60, 0x33, 0xcd, 0xbf, 0xdc, 0x77, + 0xd2, 0x9a, 0xea, 0xda, 0x4b, 0x8d, 0xb8, 0xd5, 0xd3, 0xef, 0x24, 0x4d, + 0xfc, 0xc0, 0x3b, 0x80, 0x0e, 0xfa, 0xe3, 0xfd, 0x9f, 0xa6, 0xa9, 0x8f, + 0x8d, 0xe3, 0x7a, 0x58, 0x64, 0x92, 0x94, 0xb3, 0x78, 0xf2, 0xe3, 0xca, + 0x85, 0x81, 0x3f, 0xe5, 0xfb, 0xe9, 0x2b, 0x4d, 0x1d, 0x42, 0x70, 0x97, + 0x4c, 0xcb, 0x8b, 0x1a, 0xcb, 0x3d, 0xac, 0x86, 0xff, 0x00, 0x59, 0x70, + 0x8e, 0xb8, 0xc9, 0xc8, 0xb1, 0x78, 0x2c, 0x47, 0x29, 0x52, 0x1e, 0x33, + 0xbe, 0xcf, 0x9e, 0xfa, 0xfb, 0xc3, 0x3c, 0x45, 0xf2, 0x97, 0x07, 0xaa, + 0xaa, 0xa7, 0x6a, 0x88, 0x79, 0x1a, 0x29, 0x23, 0x56, 0xe5, 0x3b, 0xff, + 0x00, 0x50, 0x3e, 0xda, 0xf4, 0x9d, 0xc7, 0xe1, 0x87, 0x09, 0x71, 0xc5, + 0x44, 0x57, 0x1b, 0xe5, 0xba, 0x4f, 0x1a, 0x35, 0x18, 0x96, 0x39, 0x0c, + 0x52, 0x3f, 0xff, 0x00, 0x2c, 0x75, 0x03, 0xb6, 0x7a, 0x6a, 0x7a, 0xcf, + 0x84, 0x1c, 0x0b, 0x47, 0x69, 0x31, 0x52, 0xd9, 0xe4, 0xfe, 0x5e, 0x09, + 0x26, 0xa5, 0xcf, 0x3e, 0x3f, 0xc5, 0x93, 0xbe, 0xb5, 0xc7, 0xf1, 0xca, + 0x0a, 0xa0, 0xcd, 0x0f, 0x48, 0xa3, 0xd3, 0x3c, 0xf1, 0x76, 0xe2, 0x2b, + 0xd4, 0x42, 0xa2, 0xec, 0xb6, 0xf8, 0x3f, 0x85, 0x48, 0xe9, 0x4f, 0x13, + 0xc9, 0x4f, 0xcf, 0x18, 0x20, 0x79, 0x4a, 0xbe, 0xc7, 0x9b, 0x6c, 0xed, + 0x8d, 0xf4, 0xca, 0xdf, 0x52, 0xf7, 0x38, 0x17, 0x99, 0x05, 0x4f, 0x24, + 0x79, 0x76, 0x07, 0x00, 0x1f, 0x5d, 0x6b, 0x7c, 0x75, 0xc1, 0x75, 0x1c, + 0x69, 0xc3, 0x27, 0x86, 0xed, 0x2b, 0x4b, 0x4b, 0x0c, 0x72, 0x46, 0xf9, + 0x71, 0xca, 0xaa, 0x17, 0xd9, 0x47, 0xbe, 0xa4, 0xb6, 0xfc, 0x19, 0x16, + 0xfb, 0x04, 0x74, 0x34, 0xf7, 0x58, 0xc4, 0xf8, 0xe5, 0x92, 0x4f, 0x00, + 0xe1, 0x86, 0x37, 0xfe, 0xad, 0x36, 0x1a, 0x79, 0x63, 0xfa, 0x93, 0x26, + 0x99, 0xc1, 0xd2, 0xe4, 0xf2, 0xa7, 0x19, 0x54, 0xc8, 0x95, 0x55, 0x12, + 0x42, 0x39, 0x49, 0x52, 0x83, 0x7e, 0x8b, 0xd3, 0x1a, 0x6f, 0xf0, 0x5b, + 0xe1, 0x07, 0x11, 0xf1, 0xb5, 0xca, 0x1a, 0xc3, 0x1c, 0xf6, 0xdb, 0x42, + 0x38, 0xf1, 0x2b, 0xdc, 0x63, 0x98, 0x67, 0xa4, 0x7f, 0xe2, 0x6f, 0xed, + 0xaf, 0x57, 0xf0, 0x2f, 0xc2, 0x2e, 0x18, 0xe1, 0xe0, 0x2a, 0xeb, 0x28, + 0xa9, 0xee, 0x97, 0x2e, 0x6e, 0x6f, 0x98, 0xa8, 0x8f, 0x98, 0x27, 0xb2, + 0xa9, 0xd8, 0x7d, 0xfa, 0xea, 0xf4, 0xf8, 0xa7, 0x41, 0x1c, 0x68, 0xa8, + 0x8b, 0xb0, 0x54, 0x18, 0x03, 0xf1, 0xad, 0x31, 0x80, 0xd5, 0x8b, 0x81, + 0x67, 0x06, 0x70, 0xb5, 0x9f, 0x84, 0xac, 0xd1, 0xda, 0xec, 0xb4, 0xa2, + 0x18, 0x86, 0xf2, 0x3b, 0x79, 0xa4, 0x99, 0xfb, 0xbb, 0xb7, 0x56, 0x27, + 0x4f, 0x34, 0x2a, 0x4a, 0x09, 0xeb, 0x83, 0xa9, 0x1a, 0x42, 0xcb, 0x82, + 0x34, 0xc4, 0x86, 0x25, 0x47, 0x53, 0x49, 0xc8, 0xa4, 0x8e, 0xb8, 0xce, + 0xa0, 0xa0, 0xac, 0x4a, 0x99, 0x5c, 0x67, 0x74, 0x38, 0x23, 0x5c, 0xd5, + 0x49, 0x88, 0xcf, 0xdb, 0x1a, 0x4d, 0x6b, 0x99, 0xe3, 0xba, 0x4a, 0xc4, + 0xe1, 0x1d, 0xb1, 0xfa, 0x77, 0xd5, 0xd1, 0x76, 0x3c, 0xbe, 0xb4, 0xd1, + 0xda, 0x2a, 0xa4, 0xa6, 0xe6, 0xf1, 0x92, 0x26, 0x64, 0x55, 0xea, 0xc4, + 0x02, 0x70, 0x3d, 0xcf, 0xe7, 0x59, 0x27, 0x0d, 0xdc, 0xe9, 0xaf, 0xfc, + 0x3f, 0x70, 0x14, 0x37, 0xea, 0x5b, 0x6c, 0xaf, 0x2f, 0x8d, 0x53, 0x1c, + 0xc9, 0x99, 0xe3, 0x20, 0x8c, 0x0f, 0x36, 0x01, 0xf7, 0x6d, 0xfa, 0x0d, + 0x6c, 0xaa, 0x43, 0x2e, 0x7a, 0x8d, 0x79, 0x63, 0xe3, 0x1c, 0x6f, 0x07, + 0xc4, 0xab, 0xbc, 0x64, 0x15, 0xcb, 0xab, 0xa6, 0xfb, 0x10, 0xca, 0x0f, + 0xfd, 0xfd, 0xf5, 0x8f, 0x59, 0xe3, 0x14, 0xc4, 0x67, 0x7c, 0x07, 0x3d, + 0x86, 0xae, 0xa6, 0xf1, 0xf2, 0xc6, 0x76, 0xf1, 0x5c, 0xb3, 0x25, 0x64, + 0x47, 0x21, 0x80, 0x04, 0xe7, 0x23, 0x6d, 0xfd, 0x06, 0xa6, 0x58, 0x6e, + 0xb6, 0x8b, 0x85, 0x3f, 0xf1, 0xa8, 0x12, 0xbe, 0x87, 0xc4, 0x1b, 0xcd, + 0x1f, 0x37, 0x32, 0xfb, 0x6f, 0xb6, 0x46, 0xaa, 0xdc, 0x1d, 0x7a, 0xac, + 0xb3, 0x5e, 0xa9, 0xe5, 0x49, 0x0f, 0x82, 0xf2, 0x72, 0xcc, 0xa4, 0xed, + 0xca, 0x7a, 0x9c, 0x7e, 0x9a, 0xd9, 0xb8, 0x9a, 0x4b, 0x5c, 0xf6, 0xb8, + 0xd2, 0x3a, 0x87, 0xa8, 0xe6, 0x41, 0x18, 0x43, 0x16, 0x39, 0x97, 0xa8, + 0xdf, 0x3d, 0x80, 0xd7, 0x2b, 0x0e, 0x24, 0xed, 0x27, 0xc9, 0x96, 0x00, + 0x97, 0x3e, 0x1b, 0xe1, 0x3b, 0x85, 0xbd, 0x6a, 0xa8, 0x2d, 0xa1, 0x15, + 0x9d, 0x9d, 0x0d, 0x3b, 0x91, 0x90, 0x47, 0x42, 0x0e, 0x40, 0x3e, 0xda, + 0xce, 0xab, 0xb8, 0x52, 0x25, 0xbf, 0x41, 0x55, 0x43, 0x89, 0xd2, 0x22, + 0xee, 0x61, 0x99, 0x72, 0xcb, 0xb1, 0x23, 0x3e, 0xa0, 0x6a, 0xdf, 0x6b, + 0x35, 0x34, 0xa1, 0xe9, 0xe9, 0x29, 0x66, 0x78, 0x26, 0x3c, 0xd0, 0xb4, + 0x9f, 0x48, 0x1d, 0xf7, 0xef, 0xbe, 0x35, 0xfa, 0x0a, 0x86, 0xc4, 0x93, + 0xff, 0x00, 0x0a, 0x32, 0xd6, 0x73, 0xf8, 0x11, 0xc9, 0x10, 0xc1, 0x1b, + 0xf4, 0xc7, 0x7e, 0x9a, 0xd9, 0x87, 0x0b, 0x4b, 0x73, 0x8d, 0x30, 0xc9, + 0x78, 0x2a, 0xba, 0xae, 0x59, 0x05, 0xbe, 0xaa, 0x99, 0x24, 0xab, 0x8d, + 0x1b, 0xc3, 0x90, 0x30, 0x5f, 0x10, 0x0f, 0xe9, 0xdf, 0x62, 0x71, 0xd3, + 0xed, 0xae, 0xb8, 0x8b, 0x88, 0xa9, 0x25, 0xa6, 0xf9, 0x95, 0x72, 0xf0, + 0x42, 0x07, 0x8d, 0x86, 0xc4, 0x91, 0x63, 0xa8, 0xc1, 0xed, 0x9d, 0xb4, + 0x9b, 0x88, 0xaa, 0xaf, 0x74, 0x9c, 0xa2, 0xae, 0x90, 0x46, 0x86, 0x40, + 0x1d, 0x8a, 0x6e, 0x7a, 0xec, 0x7d, 0xf6, 0xd6, 0x7b, 0xc7, 0x46, 0x94, + 0x5e, 0xb1, 0x49, 0x17, 0x20, 0x68, 0xd5, 0xa4, 0x6c, 0xec, 0xcd, 0xf6, + 0xfc, 0xe8, 0x31, 0xe9, 0xa3, 0x82, 0x4f, 0x22, 0xec, 0xb9, 0x45, 0x41, + 0x5a, 0x33, 0xfe, 0x32, 0x88, 0x0e, 0x29, 0xbb, 0xbb, 0x10, 0x8a, 0x2b, + 0x67, 0x39, 0x27, 0xa9, 0xf1, 0x0e, 0x97, 0x50, 0xbc, 0x3c, 0xe1, 0xde, + 0x15, 0x9f, 0x1b, 0x85, 0x27, 0x6d, 0x1b, 0xc5, 0x4b, 0x2d, 0x47, 0x17, + 0xde, 0x7c, 0x4f, 0xf8, 0x6b, 0x5f, 0x38, 0x07, 0xff, 0x00, 0xf4, 0x3b, + 0x6b, 0xf5, 0x05, 0x0b, 0x4a, 0xc0, 0x47, 0xf4, 0xf5, 0x63, 0x8f, 0xdb, + 0x4c, 0x7d, 0x99, 0xe7, 0xf6, 0x67, 0x75, 0x35, 0xb3, 0x4c, 0xea, 0xef, + 0x4e, 0xab, 0x10, 0xc7, 0x94, 0x36, 0xe7, 0xf3, 0x8d, 0x47, 0x25, 0xc2, + 0xae, 0xaa, 0x9b, 0x7c, 0xc4, 0x80, 0x91, 0x84, 0x63, 0x8d, 0xf4, 0x5d, + 0x72, 0x43, 0x0c, 0x4d, 0x1b, 0x46, 0xdb, 0x0c, 0x82, 0x47, 0x7d, 0x2c, + 0x89, 0x83, 0x92, 0x80, 0xf2, 0xe3, 0xaf, 0xbe, 0x95, 0x96, 0xe5, 0xd8, + 0x1b, 0xda, 0x54, 0x86, 0x9c, 0x39, 0x17, 0xf3, 0x86, 0xd8, 0xdc, 0xef, + 0xa2, 0xae, 0xeb, 0x43, 0x25, 0xd6, 0x1a, 0x6a, 0xe0, 0x48, 0x68, 0x18, + 0xa9, 0x53, 0x82, 0xa7, 0x98, 0x60, 0xff, 0x00, 0x7d, 0x15, 0xc2, 0x54, + 0xdf, 0x54, 0x84, 0x63, 0xcb, 0xb1, 0xf5, 0xd5, 0x4e, 0xfd, 0x5f, 0x3b, + 0xf1, 0x7b, 0xbb, 0xb6, 0x4c, 0x4e, 0x23, 0x5f, 0x60, 0x32, 0x31, 0xa7, + 0x41, 0xf2, 0x83, 0x8b, 0x0b, 0xbc, 0x59, 0x1a, 0x98, 0x37, 0xcb, 0xc8, + 0x25, 0x55, 0x19, 0x23, 0x9b, 0x24, 0x7e, 0x7b, 0xe8, 0x1b, 0x4a, 0xab, + 0xd5, 0xc4, 0x65, 0x1c, 0xcc, 0x18, 0x60, 0x74, 0xdb, 0x1a, 0xb5, 0xc1, + 0x50, 0x95, 0x36, 0xf8, 0xa7, 0x45, 0x1e, 0x2c, 0x43, 0x1b, 0x9e, 0xa4, + 0x6c, 0x47, 0xe7, 0x55, 0x4a, 0x80, 0x61, 0xb9, 0x4b, 0x2a, 0x46, 0xd1, + 0xa3, 0x13, 0xca, 0x06, 0xe4, 0x12, 0x7a, 0x69, 0xcb, 0xc3, 0x25, 0x16, + 0x5a, 0x89, 0x12, 0x47, 0x91, 0xf5, 0x0d, 0xf5, 0x55, 0xe2, 0x66, 0x4a, + 0x69, 0x0d, 0x44, 0x67, 0xcf, 0x9f, 0xd0, 0xe9, 0x9b, 0xd4, 0x4c, 0x82, + 0x92, 0x26, 0x86, 0x68, 0xda, 0xa1, 0x80, 0x42, 0xd1, 0xf6, 0xe8, 0x71, + 0xbf, 0x5d, 0x53, 0x78, 0xb6, 0xa1, 0xa3, 0xe2, 0x1a, 0x8a, 0x0c, 0x3a, + 0xc3, 0x4f, 0x21, 0x8c, 0xc6, 0xdd, 0x43, 0x03, 0xe6, 0xcf, 0xbe, 0x46, + 0xaf, 0x3e, 0x54, 0xfc, 0x50, 0x49, 0x86, 0x96, 0x79, 0x5b, 0xc4, 0x73, + 0x92, 0x7a, 0xeb, 0x87, 0xcf, 0x36, 0x74, 0x4b, 0x18, 0xe5, 0xa7, 0x8e, + 0x48, 0x54, 0x05, 0x2b, 0xa2, 0xf8, 0x7e, 0xdf, 0x51, 0x57, 0x5c, 0xb2, + 0x47, 0x1a, 0x48, 0x91, 0x9e, 0x66, 0x0f, 0x9c, 0x1c, 0x1e, 0x87, 0x1a, + 0x5a, 0xe8, 0xb3, 0xba, 0x41, 0xfc, 0x3e, 0x38, 0x6b, 0xe4, 0x6c, 0x3c, + 0x11, 0x16, 0x89, 0x39, 0x72, 0x09, 0x6d, 0xc1, 0x3f, 0x63, 0x83, 0xa8, + 0x6d, 0xa9, 0x1d, 0x4b, 0x9a, 0xaa, 0x89, 0x32, 0x5c, 0x31, 0xa8, 0x90, + 0x8e, 0x63, 0xd3, 0xaf, 0xf6, 0xc6, 0xac, 0x17, 0xb1, 0x59, 0x32, 0xcc, + 0x95, 0x0b, 0x0a, 0xf9, 0x08, 0x41, 0x1a, 0x72, 0xa8, 0xff, 0x00, 0x97, + 0x19, 0xd2, 0x9b, 0x3c, 0xd1, 0xc0, 0x94, 0x91, 0x14, 0x42, 0xf2, 0xc0, + 0xf0, 0x37, 0x30, 0xcf, 0x29, 0x23, 0x63, 0xa6, 0x23, 0x7e, 0x9f, 0x95, + 0x60, 0xdc, 0x2d, 0x22, 0xcb, 0x0c, 0x88, 0xcf, 0x29, 0xa9, 0x86, 0x63, + 0x24, 0x4c, 0xa4, 0xe5, 0x81, 0x1d, 0xf1, 0xf6, 0xd5, 0xba, 0x3a, 0xb8, + 0xab, 0xf8, 0x6e, 0x38, 0x48, 0x65, 0x9e, 0x4f, 0x17, 0x92, 0x10, 0x3e, + 0x97, 0x56, 0xff, 0x00, 0x3c, 0xe3, 0x3e, 0xda, 0x43, 0xc3, 0x4d, 0x10, + 0xb9, 0x1f, 0x91, 0x4c, 0xcb, 0x4e, 0x18, 0xbc, 0x8c, 0x00, 0x51, 0xb7, + 0x98, 0x31, 0x3d, 0xbb, 0x0f, 0x4d, 0xb5, 0xf2, 0x9f, 0xf9, 0xbc, 0x49, + 0x0c, 0x85, 0x84, 0x8b, 0x34, 0x26, 0xa2, 0x6c, 0x9c, 0x98, 0xf2, 0x32, + 0xc0, 0x1e, 0xfb, 0xe3, 0xf4, 0xd1, 0xa6, 0x5a, 0x85, 0x4a, 0xc8, 0x61, + 0x91, 0x7c, 0xa9, 0x22, 0x81, 0x20, 0x1f, 0x4b, 0x0e, 0x87, 0xd3, 0xef, + 0xa2, 0x62, 0x63, 0x4d, 0x2a, 0x54, 0x14, 0xe5, 0x0c, 0x4a, 0xb2, 0xe7, + 0xb6, 0x86, 0x42, 0xf2, 0x09, 0x9d, 0xfe, 0xb2, 0xdc, 0xf9, 0xf7, 0x27, + 0x4c, 0xae, 0x54, 0xc1, 0x6d, 0xf4, 0xd5, 0x87, 0xac, 0xab, 0xca, 0xdf, + 0x71, 0xd3, 0x43, 0x66, 0xcb, 0x21, 0x30, 0x14, 0xb9, 0xff, 0x00, 0x31, + 0x1e, 0x28, 0x66, 0x5c, 0x83, 0x8d, 0x98, 0x7d, 0xf4, 0x1d, 0xd1, 0x15, + 0x2c, 0xd5, 0x6a, 0xb1, 0xf3, 0x34, 0x28, 0xd2, 0x28, 0x0c, 0x40, 0x20, + 0x03, 0xb1, 0xc7, 0x51, 0xa7, 0xd1, 0x47, 0xf3, 0x02, 0xcc, 0x5d, 0xb9, + 0xd4, 0xc6, 0xeb, 0x9f, 0x42, 0x08, 0x1a, 0x89, 0x21, 0x8d, 0x2e, 0x8f, + 0x04, 0xcb, 0x98, 0xca, 0xb0, 0xfb, 0x8d, 0x4b, 0x24, 0xe3, 0xc1, 0x4b, + 0xb2, 0x99, 0x3c, 0x08, 0xe4, 0x32, 0x25, 0x24, 0x72, 0xec, 0xdc, 0xf2, + 0x16, 0xc8, 0xef, 0xb6, 0x33, 0x8d, 0x6b, 0x3f, 0x09, 0x67, 0xa2, 0xb4, + 0xf1, 0xc5, 0x80, 0xc1, 0x75, 0x49, 0x12, 0xa2, 0xa1, 0x44, 0xa8, 0xb1, + 0x91, 0xb6, 0x3a, 0x80, 0x7b, 0x7f, 0xae, 0xa9, 0x13, 0x9b, 0x5d, 0xb1, + 0x27, 0xa2, 0xaf, 0x94, 0xc0, 0xc8, 0xc7, 0xc1, 0x65, 0x21, 0x81, 0x5c, + 0xe0, 0x65, 0x7e, 0xda, 0x55, 0x45, 0x55, 0x15, 0x1d, 0xca, 0x39, 0x29, + 0xe4, 0x2b, 0x89, 0x39, 0xe1, 0x60, 0x70, 0xcb, 0x83, 0xdb, 0xdb, 0x52, + 0x16, 0x9f, 0x28, 0xe7, 0x38, 0xf2, 0x7b, 0xea, 0x4b, 0xcd, 0x6d, 0xbe, + 0xef, 0x4d, 0x45, 0x0d, 0xb6, 0x69, 0xe8, 0x66, 0x1b, 0xce, 0xb9, 0x21, + 0x0f, 0xf9, 0x68, 0x8b, 0xdf, 0x11, 0x4f, 0x47, 0x75, 0xa3, 0xa0, 0xa6, + 0xb4, 0xcd, 0x58, 0x95, 0x07, 0x0c, 0xe8, 0xdb, 0x2f, 0xa9, 0x3b, 0x1d, + 0x65, 0x3f, 0x07, 0x3e, 0x2c, 0x45, 0x7e, 0xa7, 0x92, 0xd3, 0x5c, 0x39, + 0x6e, 0x09, 0x1f, 0x2a, 0x11, 0xd2, 0x53, 0x8e, 0xb8, 0xed, 0xd3, 0x5a, + 0x65, 0x96, 0xed, 0x53, 0x25, 0xa9, 0x5a, 0xb5, 0x39, 0x6b, 0x5c, 0x9e, + 0x6c, 0x2e, 0x00, 0x1a, 0xd3, 0x43, 0x93, 0x2c, 0xf4, 0x2b, 0x04, 0x61, + 0x96, 0x24, 0xe5, 0x27, 0x73, 0xeb, 0xed, 0xa2, 0x5d, 0xd5, 0x17, 0x2d, + 0xf6, 0xd2, 0x9b, 0x5c, 0xc5, 0x61, 0x52, 0xdb, 0x93, 0xbe, 0x74, 0x75, + 0x44, 0x88, 0xf0, 0x1d, 0x1d, 0x96, 0xd9, 0x29, 0x94, 0x75, 0x07, 0x6c, + 0x68, 0x2a, 0xc9, 0xb6, 0x03, 0x27, 0x73, 0x8d, 0x41, 0x2c, 0x98, 0x5c, + 0x73, 0x76, 0xd0, 0xd3, 0x4b, 0x90, 0xbe, 0x6e, 0x9b, 0xea, 0x14, 0x1d, + 0x03, 0x79, 0x80, 0x3b, 0xfb, 0xe8, 0x95, 0x21, 0x77, 0x63, 0x8d, 0x2e, + 0xa5, 0x94, 0x39, 0x07, 0x47, 0x9f, 0x32, 0x11, 0xea, 0x35, 0x08, 0x2c, + 0xbb, 0xd4, 0x72, 0x82, 0x01, 0xfb, 0x68, 0x2a, 0x75, 0x21, 0x10, 0x8f, + 0xa8, 0xef, 0xae, 0x6e, 0x44, 0x9a, 0xd1, 0x1b, 0x74, 0xd1, 0x74, 0x91, + 0x86, 0x95, 0x41, 0xc0, 0x5e, 0xe4, 0x9c, 0x76, 0xd0, 0xc8, 0xbf, 0x56, + 0x35, 0xa2, 0xa8, 0xcc, 0x18, 0x3b, 0x91, 0xac, 0xd7, 0xe3, 0x77, 0x06, + 0xd5, 0x5f, 0x0c, 0x17, 0xdb, 0x72, 0xc6, 0x65, 0x82, 0x13, 0x1c, 0xca, + 0xcc, 0x17, 0x2a, 0x0e, 0x41, 0xcf, 0x73, 0xbf, 0x4d, 0x5a, 0x6c, 0xf7, + 0x8a, 0x09, 0xa4, 0x6a, 0x68, 0x2a, 0x01, 0x62, 0xc7, 0xcb, 0xe8, 0x7d, + 0x34, 0xf2, 0x0a, 0x98, 0xd9, 0x4c, 0x13, 0xae, 0x53, 0x3b, 0xfa, 0x1f, + 0xbe, 0xb3, 0xc5, 0xc3, 0x53, 0x8d, 0xa1, 0x52, 0x71, 0xc8, 0xb6, 0xa6, + 0x79, 0x49, 0xa9, 0xe5, 0x8d, 0xf9, 0x1e, 0x32, 0x0e, 0x31, 0x9e, 0xda, + 0xbd, 0x58, 0xab, 0x26, 0x7b, 0x4c, 0x34, 0x4a, 0x04, 0xd5, 0x0a, 0xa3, + 0x94, 0xbf, 0x51, 0xe8, 0x3e, 0xda, 0xd4, 0xef, 0x5c, 0x07, 0xc3, 0x37, + 0x69, 0x3c, 0x6f, 0x0e, 0x4a, 0x67, 0x0d, 0x9c, 0xc0, 0xc0, 0x64, 0xfd, + 0x88, 0x3a, 0x92, 0xd1, 0xc2, 0xdc, 0x37, 0x60, 0xcc, 0xf1, 0xc6, 0xd3, + 0x54, 0x0f, 0x31, 0x79, 0xbc, 0xc7, 0xf4, 0xe9, 0xac, 0x7a, 0x5d, 0x04, + 0xb1, 0xcd, 0xb6, 0xf8, 0x11, 0x0d, 0x3b, 0x83, 0xe4, 0x49, 0xc2, 0xfc, + 0x39, 0x72, 0xac, 0x8a, 0x37, 0xbb, 0xc5, 0x4c, 0xb4, 0x44, 0x15, 0x6a, + 0x67, 0x4c, 0xb3, 0x83, 0x82, 0x18, 0x10, 0x46, 0x3a, 0x68, 0x3e, 0x36, + 0xb1, 0x35, 0x92, 0xa6, 0x3a, 0xfa, 0x31, 0x31, 0xa5, 0x3b, 0x2a, 0x46, + 0x76, 0x88, 0xf4, 0xdf, 0x3f, 0x7e, 0xba, 0xb0, 0x71, 0x0d, 0xfe, 0x0a, + 0x78, 0xcc, 0xb3, 0x55, 0x88, 0x3c, 0xb9, 0x89, 0x72, 0x00, 0x3e, 0x99, + 0xc9, 0x03, 0x1f, 0xe9, 0xaa, 0x5c, 0x7f, 0x16, 0x2d, 0x36, 0x62, 0xd4, + 0xf5, 0xd7, 0x1f, 0xe2, 0x21, 0x9f, 0x99, 0x97, 0x93, 0x9d, 0x87, 0xa8, + 0xe6, 0x1e, 0x50, 0x07, 0xa0, 0x27, 0x5b, 0xd4, 0x03, 0xd8, 0x9f, 0x42, + 0xfa, 0x4e, 0x17, 0xae, 0x37, 0x75, 0xbc, 0xd7, 0xd5, 0x8a, 0xce, 0x64, + 0x23, 0xc0, 0x66, 0xce, 0x33, 0xbe, 0x73, 0xed, 0xd3, 0x54, 0x1f, 0x8a, + 0x94, 0x33, 0xc1, 0xc4, 0x9e, 0x38, 0xa4, 0x30, 0xc1, 0x34, 0x4a, 0x50, + 0x21, 0xe6, 0x24, 0x8c, 0x0d, 0xbf, 0xd3, 0x57, 0x4b, 0xc7, 0xc5, 0x4e, + 0x1b, 0xbc, 0x56, 0xc9, 0x0d, 0xb2, 0xd7, 0x74, 0xab, 0x90, 0x27, 0x24, + 0x2b, 0x4d, 0xf4, 0xc4, 0xc3, 0x6c, 0x9c, 0xed, 0x81, 0xef, 0x81, 0xaa, + 0xb9, 0x5b, 0x9d, 0x7c, 0x82, 0xbe, 0xf1, 0x0c, 0xa2, 0x9f, 0x18, 0x8e, + 0x57, 0xab, 0x40, 0x99, 0xea, 0x72, 0xc0, 0x04, 0x03, 0xdb, 0x9b, 0xf5, + 0x3a, 0xcb, 0x2c, 0x79, 0x25, 0x26, 0x9a, 0x2f, 0xf8, 0xae, 0x5d, 0x99, + 0xbf, 0x10, 0xd1, 0x49, 0x51, 0xc4, 0xf7, 0x18, 0x60, 0x4f, 0x11, 0x9e, + 0xb6, 0x5c, 0x8e, 0x9d, 0x5c, 0xef, 0xaf, 0xd7, 0x27, 0xa6, 0xb5, 0xdb, + 0x7f, 0x87, 0xc5, 0x2b, 0x7c, 0xcb, 0x6e, 0xee, 0x9d, 0xbd, 0x8e, 0xae, + 0x8b, 0x69, 0xaa, 0x9a, 0xff, 0x00, 0x51, 0x41, 0x6c, 0xa6, 0xf1, 0xee, + 0x97, 0x4a, 0xa9, 0x92, 0x05, 0xce, 0xc0, 0x73, 0x12, 0x58, 0x9f, 0xe9, + 0x03, 0x1a, 0x33, 0x8c, 0x3e, 0x03, 0xf1, 0x3d, 0x05, 0x8e, 0xba, 0xf1, + 0xf3, 0xf4, 0xf5, 0xa6, 0x91, 0x11, 0xd2, 0x08, 0x54, 0x97, 0x75, 0xc6, + 0x64, 0x3f, 0xfe, 0xbe, 0x9b, 0xe7, 0xdb, 0x57, 0x91, 0x78, 0xd9, 0x96, + 0x78, 0x9b, 0x6d, 0xa3, 0x19, 0xab, 0xa9, 0x96, 0x56, 0x26, 0x49, 0x1e, + 0x42, 0x06, 0x01, 0x63, 0x9d, 0x4b, 0x6a, 0x89, 0x5d, 0x59, 0x83, 0x79, + 0xbd, 0x31, 0xa8, 0xe7, 0xa6, 0x90, 0x30, 0x52, 0xaf, 0xcf, 0x9d, 0xd7, + 0x97, 0x7d, 0x3c, 0xb6, 0x5b, 0xda, 0x9a, 0x8f, 0xc7, 0x64, 0x09, 0x2c, + 0xa5, 0x17, 0x04, 0x67, 0x0a, 0x71, 0x81, 0xf7, 0xff, 0x00, 0xc6, 0xb1, + 0xa7, 0xb8, 0xcc, 0xe0, 0x19, 0x67, 0xb8, 0x47, 0x6d, 0x82, 0x59, 0x67, + 0x93, 0x96, 0x30, 0xa4, 0x6b, 0x3c, 0xb8, 0x39, 0x9e, 0xe9, 0x51, 0x3a, + 0x93, 0x99, 0x27, 0x66, 0x5c, 0xf6, 0x19, 0x3a, 0xd3, 0x69, 0x68, 0xd3, + 0xe6, 0x5a, 0xa2, 0xa6, 0x30, 0xe3, 0x9b, 0x11, 0xa9, 0x18, 0xc0, 0xf5, + 0xfb, 0xeb, 0x39, 0xbb, 0xd2, 0x9a, 0x6b, 0xbd, 0x44, 0x1c, 0xc4, 0xf2, + 0xc8, 0x70, 0x71, 0xef, 0xa7, 0xec, 0xa4, 0x83, 0x8a, 0xa2, 0xc1, 0xc3, + 0xb5, 0x8d, 0x08, 0x62, 0x42, 0xb8, 0x65, 0x1e, 0x56, 0x19, 0x04, 0xea, + 0xc5, 0xc2, 0xd4, 0xf0, 0xdc, 0x38, 0x80, 0x07, 0x89, 0xe9, 0xbc, 0xa7, + 0x2c, 0x06, 0x42, 0x9c, 0x8f, 0xb6, 0xda, 0xa7, 0xd2, 0x18, 0xd6, 0x8c, + 0xc6, 0xc0, 0x99, 0x41, 0x05, 0x5b, 0xdb, 0x5a, 0x0f, 0x00, 0xa5, 0x6a, + 0x8a, 0x79, 0x62, 0x85, 0xd9, 0x2a, 0x33, 0x0b, 0xbe, 0x3c, 0xb8, 0xe5, + 0xce, 0x33, 0xeb, 0xb8, 0x3a, 0x73, 0x9d, 0x2b, 0xfd, 0x06, 0x32, 0xe2, + 0xee, 0x1c, 0xb0, 0xd8, 0xfe, 0x21, 0xd0, 0x0a, 0xab, 0xbd, 0x45, 0x55, + 0x35, 0x34, 0x70, 0x4c, 0x44, 0x6a, 0x3e, 0xb2, 0xbc, 0xc5, 0x48, 0x1e, + 0xf8, 0xeb, 0xd3, 0x3a, 0xcd, 0x38, 0xa6, 0xcf, 0x4b, 0x5d, 0xc6, 0xb7, + 0xab, 0xa4, 0xf5, 0x11, 0x52, 0xc5, 0x2c, 0x8e, 0xeb, 0x19, 0x04, 0x99, + 0x25, 0x7d, 0xf9, 0x17, 0x19, 0xe9, 0x83, 0xbf, 0xdb, 0xd7, 0x56, 0xab, + 0xdd, 0xd6, 0x3b, 0xab, 0x19, 0xa2, 0x6e, 0x49, 0xa1, 0x25, 0x1c, 0x31, + 0xfa, 0x58, 0x10, 0x33, 0xf6, 0xdb, 0x55, 0x8f, 0x88, 0x15, 0xd4, 0xa6, + 0x3b, 0x5c, 0x14, 0x30, 0x39, 0xae, 0x87, 0x9d, 0xab, 0x66, 0x32, 0x65, + 0x67, 0x91, 0xfb, 0xa6, 0xdb, 0x00, 0x30, 0x3f, 0x1a, 0xcc, 0xa5, 0xf2, + 0x64, 0xe3, 0xa2, 0xd1, 0x52, 0x2f, 0xfc, 0x3e, 0x8a, 0x65, 0x48, 0xc4, + 0xb2, 0x87, 0x0a, 0xa5, 0x86, 0x00, 0x04, 0x1c, 0x6d, 0xed, 0x8d, 0x4d, + 0x69, 0xe2, 0xbb, 0xc5, 0x34, 0x4b, 0x1c, 0x12, 0xc5, 0x1a, 0xa8, 0x21, + 0x93, 0xc3, 0x18, 0x66, 0xf5, 0x3d, 0xce, 0x87, 0xe2, 0x58, 0xd9, 0x2b, + 0xa3, 0xb6, 0x42, 0xe1, 0xc5, 0x10, 0xc0, 0x23, 0x6c, 0xb9, 0xc1, 0x63, + 0xf8, 0x27, 0x1a, 0x0c, 0x4b, 0x19, 0x5e, 0x42, 0xac, 0x58, 0x7f, 0xc4, + 0x38, 0xfa, 0x4e, 0xb5, 0xf4, 0x39, 0x16, 0x7b, 0x15, 0xc6, 0xe7, 0x73, + 0xae, 0x35, 0xb5, 0x0c, 0x25, 0x00, 0x9e, 0x71, 0xd1, 0x11, 0x7d, 0x00, + 0xec, 0x75, 0x2d, 0x4c, 0x40, 0x1a, 0x98, 0xa9, 0xd5, 0xb1, 0x16, 0x64, + 0x4d, 0xf3, 0xe5, 0x27, 0xae, 0x74, 0x82, 0xd1, 0x72, 0xa9, 0xb7, 0x64, + 0x42, 0xd9, 0x89, 0x98, 0x97, 0x18, 0xea, 0x0e, 0xad, 0x36, 0xf9, 0xc5, + 0x6c, 0x2c, 0x88, 0x03, 0x10, 0x79, 0xe2, 0x5f, 0x62, 0x3a, 0x7e, 0xfa, + 0xb4, 0x6c, 0xd3, 0x83, 0x50, 0xc0, 0xb3, 0xd4, 0xc5, 0x5b, 0x01, 0xf0, + 0x96, 0x58, 0xb9, 0x26, 0xe6, 0x53, 0x82, 0xc3, 0x6e, 0xde, 0xa7, 0x18, + 0xd3, 0x7b, 0x2c, 0x71, 0x52, 0xdf, 0xed, 0xf5, 0xf1, 0x0c, 0x53, 0x73, + 0x9a, 0x1a, 0x96, 0x1f, 0xff, 0x00, 0x66, 0x3f, 0xb6, 0x30, 0x7f, 0x3a, + 0x5d, 0x65, 0x45, 0x8a, 0xa5, 0xa1, 0x9d, 0xfc, 0x0d, 0xd8, 0xb6, 0xdc, + 0xc0, 0x95, 0xdf, 0x18, 0xfb, 0x8e, 0xba, 0xea, 0xcf, 0x3a, 0xcb, 0x69, + 0xbc, 0xa5, 0x53, 0xb1, 0x95, 0x58, 0xbb, 0x39, 0x3d, 0xf9, 0x87, 0x2e, + 0x3e, 0xc7, 0x23, 0xf1, 0xa2, 0x43, 0x3d, 0x93, 0x49, 0x11, 0xa7, 0x9a, + 0x78, 0x60, 0x3e, 0x54, 0x6f, 0x5c, 0xe0, 0x69, 0x84, 0x15, 0x08, 0xd6, + 0x41, 0x4f, 0x50, 0x39, 0x8b, 0x49, 0x98, 0x37, 0xdd, 0x98, 0x03, 0xd3, + 0xf7, 0xd0, 0x15, 0x14, 0xb5, 0x0e, 0x94, 0xf7, 0x17, 0x85, 0x9a, 0x39, + 0x23, 0x0b, 0x20, 0x88, 0xe4, 0x82, 0x36, 0x39, 0xd7, 0x0e, 0xc6, 0x98, + 0x2c, 0x94, 0x75, 0x0d, 0xe4, 0x60, 0x40, 0xce, 0xe1, 0xbd, 0xff, 0x00, + 0x7d, 0x50, 0xf4, 0x7e, 0x6a, 0xa9, 0xff, 0x00, 0x85, 0x53, 0x49, 0x48, + 0x18, 0x4b, 0x04, 0xce, 0x84, 0x77, 0xc6, 0x73, 0x9f, 0xdb, 0x45, 0xb2, + 0x4b, 0x2d, 0xe2, 0x63, 0xcc, 0x59, 0xbc, 0x2e, 0x60, 0x01, 0xc6, 0x0e, + 0x3d, 0x75, 0xc9, 0x84, 0x5d, 0xe9, 0x25, 0xa8, 0x5c, 0x53, 0x55, 0x27, + 0xf5, 0x46, 0x70, 0x8c, 0xc7, 0x3e, 0x56, 0x1d, 0x8e, 0x74, 0x4d, 0x9a, + 0x41, 0x58, 0xd4, 0x8d, 0x2e, 0x56, 0xaa, 0x37, 0x30, 0xb8, 0x23, 0xa8, + 0x39, 0xe5, 0x38, 0xfd, 0xb5, 0x54, 0x49, 0x15, 0xae, 0x28, 0xa3, 0x2f, + 0xc4, 0xd3, 0x54, 0x48, 0xac, 0xf0, 0x48, 0x82, 0x52, 0x71, 0xb1, 0x63, + 0x8d, 0x89, 0xf5, 0xeb, 0xa5, 0xdc, 0xb8, 0x6f, 0x11, 0x5b, 0x0f, 0x1e, + 0x42, 0xae, 0x3a, 0x2f, 0xae, 0xad, 0x9c, 0x49, 0x56, 0xf4, 0xf6, 0xfa, + 0x3b, 0x8d, 0x1c, 0x41, 0xd3, 0xc3, 0xe4, 0x92, 0x22, 0xde, 0x5d, 0xb2, + 0x37, 0xfd, 0x35, 0x4b, 0x37, 0xba, 0xda, 0x89, 0x8a, 0x9a, 0x6a, 0x78, + 0x81, 0x18, 0xe9, 0x80, 0x07, 0xaf, 0xbf, 0x6d, 0x15, 0x18, 0x72, 0x7d, + 0xd9, 0x75, 0xf8, 0x4f, 0x7c, 0xa5, 0xb3, 0xf1, 0xc5, 0xb2, 0xbe, 0xa9, + 0x4a, 0x94, 0x94, 0x02, 0xfc, 0xd8, 0x18, 0xf7, 0xd7, 0xb7, 0xa8, 0xea, + 0xe9, 0xea, 0x29, 0xa3, 0x9a, 0x98, 0xa3, 0x41, 0x22, 0x86, 0x46, 0x43, + 0x90, 0x41, 0xe8, 0x75, 0xe0, 0x2b, 0x7c, 0x15, 0x0b, 0x02, 0x4d, 0x3d, + 0x3a, 0x87, 0xce, 0x41, 0xe5, 0xc1, 0x03, 0x5e, 0x90, 0xff, 0x00, 0x67, + 0x6e, 0x2a, 0x6b, 0x85, 0xa4, 0xd8, 0x2b, 0x80, 0x13, 0x52, 0xe5, 0xa9, + 0xb2, 0x73, 0x94, 0xcf, 0x4d, 0x32, 0x2c, 0xa8, 0x48, 0xdd, 0xe0, 0x99, + 0x55, 0xf1, 0xeb, 0xdf, 0x45, 0xbc, 0xbc, 0x89, 0x91, 0xbe, 0xfa, 0x4b, + 0x4a, 0xdc, 0xca, 0x07, 0x71, 0xa2, 0x26, 0x9f, 0x92, 0x22, 0x19, 0xbb, + 0x69, 0xa8, 0x68, 0x45, 0x44, 0xfe, 0x5e, 0xb8, 0xd2, 0xca, 0xa9, 0xfa, + 0xf9, 0xbb, 0xe9, 0x7c, 0xb5, 0x8a, 0xb2, 0x31, 0x2c, 0xaa, 0xbe, 0xa5, + 0x80, 0xc0, 0xd2, 0xea, 0xdb, 0xac, 0x14, 0xea, 0xd3, 0xb3, 0x3b, 0xc0, + 0x33, 0xe7, 0x8d, 0x4b, 0xef, 0xd7, 0xb6, 0xac, 0x83, 0xbb, 0x75, 0x63, + 0xa5, 0x49, 0x8d, 0x8f, 0x95, 0x89, 0x20, 0xea, 0xd1, 0x4a, 0xcc, 0x62, + 0x04, 0xee, 0x35, 0xe7, 0xeb, 0xd7, 0x12, 0x5c, 0xab, 0x49, 0xa9, 0x49, + 0x24, 0xa3, 0x89, 0x1f, 0xc2, 0x86, 0x15, 0xf3, 0x4b, 0x29, 0x39, 0x39, + 0xed, 0xca, 0x36, 0x1b, 0x9f, 0x5e, 0x9a, 0xdb, 0x12, 0xbd, 0xa8, 0xf8, + 0x7e, 0x0a, 0xaa, 0x85, 0x31, 0x4e, 0xd0, 0x2b, 0x14, 0x3d, 0x41, 0x2a, + 0x09, 0xce, 0x91, 0x8b, 0x3a, 0xc9, 0x26, 0x97, 0xa0, 0x20, 0xd4, 0x9d, + 0x20, 0x6b, 0xcb, 0x78, 0x77, 0x50, 0x3a, 0xe4, 0x67, 0x46, 0x51, 0x1f, + 0x19, 0x25, 0x88, 0x0c, 0x17, 0x52, 0x07, 0xdf, 0x1a, 0xa5, 0x35, 0xf2, + 0xbe, 0xe3, 0xc4, 0x51, 0x43, 0x48, 0x61, 0x9e, 0x30, 0xa7, 0xc6, 0x04, + 0x79, 0x90, 0x9d, 0xfa, 0xfd, 0xb5, 0x64, 0xa4, 0xb8, 0x2d, 0x3b, 0xc5, + 0x29, 0x39, 0x05, 0x82, 0xe7, 0xd7, 0x3a, 0xa8, 0xe5, 0x8e, 0x44, 0xf6, + 0xbe, 0x86, 0x5a, 0x92, 0x69, 0x3e, 0x80, 0xa3, 0xe1, 0x1b, 0x65, 0x4c, + 0x4b, 0x2d, 0x7f, 0x96, 0x44, 0x5e, 0x42, 0xb1, 0xca, 0x76, 0x23, 0xb8, + 0xc6, 0x30, 0x74, 0x8a, 0xe4, 0x38, 0x96, 0xc7, 0x7b, 0xa7, 0xb7, 0x5b, + 0x64, 0x96, 0xe7, 0x4b, 0x3a, 0x99, 0x14, 0x48, 0x33, 0x22, 0x28, 0x38, + 0xe5, 0x2d, 0xd8, 0x6e, 0x34, 0xcb, 0x8e, 0xea, 0x64, 0xb4, 0x66, 0x7a, + 0xdb, 0xd5, 0xb2, 0xdf, 0x04, 0x8e, 0x79, 0x92, 0x49, 0xf9, 0x5c, 0x8c, + 0xfd, 0x41, 0x71, 0x92, 0x7d, 0xbb, 0xea, 0x9b, 0x37, 0xc5, 0xce, 0x1b, + 0xa5, 0xb4, 0x34, 0x34, 0x13, 0xd6, 0xd6, 0x4c, 0xb1, 0xf2, 0xc2, 0x44, + 0x44, 0x79, 0xb1, 0xf5, 0x1e, 0xbe, 0x53, 0xe9, 0xae, 0x16, 0x3c, 0x9a, + 0x95, 0x36, 0xa1, 0x0a, 0xff, 0x00, 0x3e, 0x8c, 0xdf, 0x14, 0xa5, 0xe8, + 0xb8, 0xcd, 0xc4, 0x73, 0x50, 0x31, 0xa6, 0xb8, 0xd3, 0xc9, 0x4c, 0xdc, + 0x9c, 0xfb, 0xb6, 0x46, 0x3e, 0xfa, 0xad, 0xdf, 0xbe, 0x23, 0x59, 0xe8, + 0x22, 0x59, 0x85, 0x55, 0x2c, 0x93, 0xf3, 0xf2, 0xad, 0x3b, 0x31, 0x63, + 0x8c, 0xe3, 0x99, 0xb1, 0xd0, 0x7e, 0x7b, 0xeb, 0x22, 0x96, 0xb2, 0xf9, + 0xc6, 0x55, 0xf3, 0x09, 0x1a, 0x69, 0x51, 0x5c, 0xb9, 0x54, 0x41, 0x15, + 0x3c, 0x64, 0xf4, 0xe6, 0xc6, 0xe4, 0x9d, 0xc6, 0x0e, 0x4f, 0x6d, 0x29, + 0x96, 0x2e, 0x1c, 0xa4, 0xac, 0xe6, 0xbe, 0x5c, 0x64, 0x75, 0x89, 0x5d, + 0x65, 0xa7, 0xa3, 0x42, 0x5d, 0x88, 0x38, 0xc1, 0x6f, 0xe9, 0xff, 0x00, + 0xa7, 0x4d, 0x76, 0x71, 0xbc, 0x95, 0x52, 0xec, 0xd4, 0xb0, 0x3f, 0x6c, + 0xb6, 0x71, 0xad, 0xde, 0xcf, 0xc4, 0xb7, 0x65, 0xaa, 0xb9, 0xf1, 0x15, + 0xb6, 0x8a, 0x8a, 0x37, 0xc8, 0x86, 0x29, 0x5e, 0x50, 0xa4, 0xfd, 0x44, + 0xe4, 0x6e, 0x7a, 0x0c, 0x69, 0x7c, 0xf7, 0xbe, 0x04, 0xb4, 0xc4, 0x63, + 0xa2, 0xa9, 0x6a, 0xf9, 0x1b, 0x67, 0x10, 0xc2, 0x79, 0xa5, 0xfc, 0x9c, + 0x05, 0xfd, 0xfa, 0xea, 0xab, 0x57, 0x37, 0x0e, 0x04, 0x0d, 0x64, 0xe1, + 0xaa, 0x8a, 0x97, 0x00, 0x7f, 0x32, 0xb6, 0x76, 0x92, 0x34, 0xce, 0xd9, + 0xe5, 0x18, 0xe6, 0x39, 0x23, 0xfd, 0x34, 0xef, 0x87, 0xb8, 0x16, 0x77, + 0xa4, 0xf9, 0xaa, 0xc7, 0x8a, 0xd9, 0xce, 0xbe, 0x21, 0x62, 0x8a, 0x18, + 0x67, 0xb8, 0xe7, 0xfa, 0x74, 0xdb, 0x1d, 0x08, 0xb5, 0xd1, 0x61, 0x86, + 0xe5, 0x77, 0x7b, 0x64, 0xa2, 0x38, 0xad, 0xbc, 0x27, 0x6a, 0x68, 0xf1, + 0xcd, 0x33, 0x8f, 0x98, 0xe5, 0x3d, 0x08, 0x41, 0xfd, 0x47, 0xfe, 0x6f, + 0x53, 0xaa, 0xcd, 0xde, 0xf1, 0xc2, 0x23, 0x99, 0x5c, 0x5d, 0x2f, 0x72, + 0xa1, 0xc2, 0xd5, 0x56, 0xce, 0x4c, 0x63, 0xd9, 0x46, 0x7a, 0x7a, 0x0c, + 0x0d, 0xb4, 0xba, 0xae, 0xc1, 0x49, 0x3d, 0xda, 0x4a, 0x5a, 0x2a, 0xe1, + 0x58, 0x15, 0xb9, 0x66, 0xa9, 0x79, 0x76, 0x62, 0x33, 0xe5, 0x1d, 0xc9, + 0x1b, 0xe7, 0x1b, 0x68, 0xb8, 0xe2, 0xe1, 0x7a, 0x08, 0x42, 0xd4, 0xd5, + 0xc4, 0xd2, 0x01, 0x90, 0x24, 0xc9, 0x1c, 0xd8, 0xe9, 0x8f, 0x4f, 0x4d, + 0x1b, 0x65, 0xb4, 0x4c, 0xb7, 0xba, 0xfb, 0x4f, 0x1d, 0x56, 0xdc, 0x69, + 0x2b, 0x65, 0xa3, 0xaa, 0xa7, 0xa9, 0x99, 0x20, 0x70, 0x7c, 0xc4, 0x19, + 0x1b, 0x3f, 0x8e, 0xda, 0xd3, 0xf8, 0x67, 0xe3, 0x45, 0xd6, 0x39, 0x61, + 0x8a, 0xfb, 0x8a, 0x88, 0x73, 0xca, 0xd2, 0x20, 0x0a, 0xe4, 0x7b, 0x8e, + 0x87, 0xfb, 0xeb, 0x23, 0xbe, 0xc6, 0x0f, 0x13, 0xdc, 0x9a, 0x60, 0xc5, + 0x8d, 0x54, 0x9c, 0x80, 0x0c, 0xec, 0x1c, 0xe8, 0xfa, 0x63, 0x1b, 0xc6, + 0x09, 0x5c, 0x82, 0x30, 0x41, 0xd2, 0x6e, 0xa3, 0xb4, 0xe3, 0xe4, 0xf1, + 0x67, 0xde, 0x31, 0xa0, 0xa3, 0x8f, 0x8a, 0x6b, 0xaa, 0xed, 0xc9, 0x10, + 0xb7, 0x4c, 0xcd, 0x3d, 0x17, 0x21, 0xdb, 0x0c, 0xd9, 0xc9, 0x1d, 0xb0, + 0x0e, 0x31, 0xdb, 0x43, 0x54, 0x02, 0xd4, 0x54, 0xca, 0x18, 0x85, 0xe6, + 0x8c, 0xe3, 0xf2, 0x34, 0xc6, 0x44, 0x89, 0xa9, 0x8d, 0x3c, 0x69, 0x1b, + 0x33, 0x1f, 0x21, 0x2b, 0xba, 0x3f, 0x62, 0x3e, 0xe7, 0x63, 0xf7, 0xd0, + 0x56, 0x5a, 0x0f, 0xe2, 0x17, 0xcb, 0x75, 0xa2, 0x6a, 0xc4, 0xa7, 0x8e, + 0x79, 0x04, 0x52, 0x36, 0x39, 0xb9, 0x3c, 0xd9, 0x07, 0x1e, 0xb9, 0xc6, + 0xb3, 0x28, 0xed, 0x95, 0x02, 0x9d, 0xc4, 0xb0, 0xf0, 0x55, 0x82, 0x6b, + 0xfd, 0xfa, 0x9e, 0x85, 0x00, 0x31, 0x31, 0x1e, 0x33, 0x90, 0x71, 0x1c, + 0x7d, 0xcf, 0xf6, 0x1f, 0x9d, 0x50, 0xfe, 0x32, 0x5a, 0xa9, 0x6d, 0x5f, + 0x10, 0xaf, 0x94, 0xd4, 0x34, 0xc1, 0x29, 0x29, 0xeb, 0x4a, 0x46, 0x46, + 0xf8, 0x05, 0x43, 0x72, 0x93, 0xeb, 0xb9, 0xd7, 0xaa, 0xed, 0x16, 0x5a, + 0x5e, 0x13, 0x85, 0xe8, 0x28, 0xd8, 0x62, 0x48, 0xd9, 0xaa, 0x4f, 0xf5, + 0xc8, 0x01, 0x1e, 0x6d, 0xba, 0x36, 0x3f, 0x1a, 0xf3, 0x97, 0x19, 0xdd, + 0x29, 0xeb, 0x6d, 0x7c, 0x55, 0x0d, 0x25, 0x12, 0xb0, 0xae, 0xba, 0x1a, + 0xb8, 0xea, 0xa4, 0x39, 0x91, 0x52, 0x2e, 0x60, 0xa9, 0xf6, 0x20, 0x92, + 0x4f, 0xe3, 0x4d, 0xc9, 0xe5, 0x51, 0x06, 0x8c, 0xe2, 0x09, 0xd0, 0x37, + 0x32, 0x8d, 0xba, 0x11, 0x9d, 0x6e, 0x3c, 0x2b, 0x55, 0x40, 0x7e, 0x16, + 0xd1, 0x5b, 0xe5, 0xa3, 0x9e, 0x3a, 0xd4, 0x91, 0xea, 0x22, 0xa9, 0x59, + 0x30, 0x00, 0x6c, 0x13, 0xe5, 0xfb, 0x05, 0xdf, 0xdb, 0x59, 0x07, 0x04, + 0x59, 0xc5, 0xfb, 0x89, 0xe8, 0x6d, 0x23, 0x64, 0xa8, 0x90, 0xf3, 0x9f, + 0x45, 0x00, 0xb1, 0xfe, 0xdf, 0xdb, 0x5e, 0x9c, 0x8b, 0xe1, 0xfc, 0xf1, + 0xd1, 0x22, 0x55, 0xc9, 0x4d, 0x6f, 0xa5, 0x5a, 0x7c, 0x86, 0x73, 0x9e, + 0x45, 0x1b, 0x00, 0x07, 0xae, 0xb8, 0xda, 0xdc, 0xfa, 0x88, 0xc9, 0x43, + 0x12, 0xbf, 0xd8, 0x13, 0x52, 0xfe, 0xd3, 0x05, 0xae, 0xe1, 0xda, 0x81, + 0x0c, 0xdc, 0xd3, 0x89, 0x91, 0xdc, 0xb4, 0x8d, 0xcb, 0xe6, 0x6d, 0xf2, + 0x73, 0xf9, 0xd2, 0xdb, 0x9d, 0x0d, 0xb1, 0xa9, 0x84, 0x1e, 0x19, 0x04, + 0xe0, 0xb3, 0x03, 0xe6, 0xce, 0x3f, 0xb6, 0xac, 0x9c, 0x4b, 0x5a, 0x69, + 0x0c, 0xf0, 0xa4, 0x81, 0xe3, 0xe6, 0x60, 0xa5, 0x98, 0x2f, 0x32, 0xee, + 0x01, 0xdf, 0xf1, 0xac, 0xd2, 0x82, 0x99, 0xea, 0xeb, 0x64, 0xa3, 0xa7, + 0xac, 0x20, 0x80, 0x59, 0xf1, 0xd0, 0x0c, 0xe0, 0x8c, 0xfd, 0xce, 0x9d, + 0xa5, 0xb9, 0xa4, 0xdf, 0x65, 0x20, 0x49, 0x2d, 0x46, 0xdd, 0x5b, 0x3b, + 0x02, 0x5e, 0x19, 0xd4, 0x90, 0xc7, 0xae, 0x73, 0xd0, 0xeb, 0x93, 0x1c, + 0x7f, 0x26, 0xf4, 0x7e, 0x1a, 0x04, 0x76, 0x0f, 0xcd, 0x8f, 0x36, 0x40, + 0x23, 0xaf, 0xa6, 0xfa, 0x7d, 0xf2, 0x49, 0x6e, 0x81, 0xe3, 0x3e, 0x6e, + 0x6e, 0xad, 0xeb, 0xed, 0x9d, 0x71, 0x4f, 0x46, 0x95, 0xd0, 0xb3, 0xd3, + 0x00, 0x42, 0xec, 0xc0, 0x9e, 0x87, 0x5b, 0x5c, 0x87, 0x29, 0x95, 0x65, + 0xa4, 0x44, 0x8a, 0x58, 0x02, 0x61, 0x8f, 0x98, 0x1f, 0x5c, 0x76, 0xd3, + 0xfe, 0x1e, 0x30, 0xac, 0x54, 0xb5, 0x04, 0x12, 0x23, 0x1e, 0x1c, 0xdb, + 0xe0, 0x80, 0x7b, 0xff, 0x00, 0x6d, 0x7c, 0xb8, 0x50, 0x48, 0xb0, 0x1f, + 0x05, 0x59, 0x59, 0x71, 0xcc, 0xfd, 0x40, 0xc7, 0x5c, 0xe8, 0x5a, 0x39, + 0xdd, 0x64, 0x68, 0xe4, 0x05, 0x56, 0x4c, 0x07, 0x1d, 0x41, 0xdf, 0xd7, + 0x4d, 0xc5, 0x3b, 0x56, 0x6a, 0xd2, 0xcf, 0x91, 0x85, 0x7a, 0xad, 0x05, + 0xc3, 0xc3, 0x0c, 0x4a, 0x33, 0x07, 0xe7, 0x53, 0xb3, 0x6f, 0x9f, 0xdc, + 0x68, 0x9a, 0x98, 0x20, 0xb8, 0x55, 0x5d, 0x24, 0x85, 0x4d, 0x27, 0xcc, + 0xc7, 0x12, 0x53, 0xc6, 0x83, 0x79, 0x31, 0x8e, 0x62, 0x7f, 0xd7, 0xd8, + 0xe8, 0x6f, 0x97, 0x82, 0x96, 0x7a, 0xa4, 0xa8, 0x54, 0x94, 0xbc, 0x79, + 0x8b, 0x7c, 0xf2, 0x80, 0x71, 0x91, 0xe8, 0x74, 0x55, 0xa2, 0x17, 0x7a, + 0xba, 0x66, 0xa5, 0x1e, 0x2c, 0x49, 0x19, 0x8f, 0x9a, 0x56, 0x3e, 0x47, + 0x61, 0xb9, 0xc8, 0xec, 0x0e, 0x9b, 0x66, 0xd7, 0xc9, 0x1d, 0x96, 0xb2, + 0xa5, 0x65, 0x31, 0x46, 0xdc, 0xf1, 0x16, 0xdf, 0x27, 0x66, 0x1a, 0x6f, + 0x14, 0x74, 0xa9, 0x4c, 0xce, 0x39, 0xb9, 0xea, 0x25, 0x74, 0xf0, 0x94, + 0x67, 0x93, 0x7d, 0x8e, 0x4e, 0xf8, 0xd4, 0x14, 0xd4, 0xd3, 0x5b, 0x78, + 0x82, 0xa6, 0x9a, 0xb6, 0x9d, 0x23, 0xe6, 0x50, 0x33, 0x17, 0xd0, 0xa0, + 0xee, 0x37, 0xf7, 0xce, 0xbe, 0x56, 0xd2, 0x9b, 0x4d, 0xc9, 0x6b, 0x23, + 0x8c, 0xcb, 0x09, 0x7f, 0xa4, 0x37, 0x4e, 0xf8, 0x3e, 0x9b, 0x6a, 0x30, + 0xa2, 0x88, 0x69, 0xcc, 0x94, 0x57, 0x52, 0x7c, 0xc6, 0x35, 0x2a, 0x1d, + 0x47, 0x7e, 0xbb, 0xe9, 0x90, 0x53, 0x4f, 0x78, 0x92, 0xa2, 0x17, 0x02, + 0x0a, 0xef, 0x2c, 0x52, 0x2e, 0xde, 0x14, 0x9d, 0x41, 0xfd, 0x8e, 0xba, + 0xe2, 0x2a, 0x64, 0xf9, 0x68, 0xaf, 0x14, 0x39, 0x28, 0xdc, 0xae, 0xd9, + 0x39, 0xc0, 0x3d, 0x0f, 0xe3, 0xa6, 0x34, 0x05, 0x75, 0x4d, 0x2d, 0x4f, + 0x0e, 0x35, 0x62, 0x00, 0x67, 0x49, 0x42, 0xbb, 0x2f, 0x73, 0xeb, 0xf7, + 0xef, 0xaa, 0x0d, 0x87, 0x08, 0x45, 0x4d, 0x75, 0x4d, 0x02, 0xc6, 0x40, + 0x59, 0x85, 0x42, 0x46, 0xeb, 0x80, 0x41, 0x18, 0x7f, 0xc7, 0x43, 0xaa, + 0x4d, 0xd6, 0xa6, 0x1b, 0x87, 0x10, 0x22, 0x50, 0xa2, 0xc5, 0x12, 0xc9, + 0x9d, 0x97, 0xea, 0xc6, 0x7a, 0x6a, 0xf1, 0x72, 0x0f, 0x47, 0x53, 0x41, + 0x75, 0x2e, 0xb2, 0xbc, 0x54, 0xd1, 0x34, 0x8a, 0x06, 0xcf, 0x19, 0x18, + 0x20, 0xfd, 0x8e, 0x35, 0x47, 0xe2, 0x8a, 0x38, 0x2d, 0x97, 0xea, 0x82, + 0x8b, 0xcb, 0x4f, 0x54, 0x9e, 0x3d, 0x39, 0xce, 0x70, 0x1b, 0x7f, 0xdb, + 0xa6, 0xad, 0x19, 0x73, 0xae, 0x0b, 0x50, 0xa6, 0x6a, 0x1b, 0x5b, 0xd7, + 0xdc, 0x5f, 0xcc, 0xe7, 0x96, 0x3c, 0x8c, 0xfd, 0x8f, 0xed, 0xa7, 0x1f, + 0x04, 0xaf, 0xcf, 0x6b, 0xe3, 0xfb, 0x7a, 0x00, 0x43, 0xd6, 0x54, 0xaa, + 0x6c, 0x70, 0x00, 0x3d, 0x7f, 0xf1, 0xac, 0xb3, 0xe7, 0x95, 0x6d, 0xed, + 0x14, 0xb2, 0xb4, 0xd2, 0x48, 0xc7, 0xc4, 0x24, 0xe7, 0xec, 0x33, 0xab, + 0xef, 0xc0, 0x0a, 0x09, 0x27, 0xf8, 0x89, 0x63, 0x25, 0x39, 0xb1, 0x52, + 0xa4, 0x7b, 0x0e, 0xa7, 0xf6, 0xd1, 0xc4, 0x44, 0x4f, 0x6e, 0xb1, 0x5e, + 0x75, 0x2a, 0xa1, 0x01, 0x1b, 0x01, 0xe9, 0xeb, 0xa4, 0x7c, 0x57, 0x74, + 0xa7, 0xb5, 0xda, 0xea, 0xeb, 0x6a, 0xe6, 0x11, 0x41, 0x04, 0x4c, 0xf2, + 0x31, 0xec, 0x00, 0xd3, 0xa9, 0x4a, 0x99, 0x32, 0xbf, 0x4a, 0x2e, 0xb0, + 0x7f, 0xf6, 0xa7, 0xe2, 0x94, 0xa5, 0xb0, 0xc3, 0x60, 0x81, 0xc8, 0x9e, + 0xe0, 0xe7, 0xc4, 0x55, 0x3d, 0x23, 0x53, 0xd4, 0xfd, 0xcf, 0xf6, 0x3a, + 0x63, 0x63, 0x51, 0x94, 0x5f, 0xf8, 0xf6, 0xff, 0x00, 0xc4, 0x77, 0x4a, + 0xd6, 0x35, 0xf5, 0x30, 0xd0, 0x34, 0xdc, 0xa9, 0x0a, 0x30, 0x1c, 0xb1, + 0x6f, 0x80, 0x76, 0xdf, 0x6d, 0xb5, 0xdc, 0xbc, 0x47, 0x53, 0xf3, 0xf5, + 0x74, 0x56, 0xda, 0xc9, 0x29, 0xa8, 0x0b, 0x83, 0x1c, 0x68, 0x4a, 0xb3, + 0x63, 0x6c, 0x92, 0x31, 0x9d, 0x56, 0x6d, 0x74, 0x5e, 0x2c, 0x1e, 0x29, + 0xa8, 0x58, 0xff, 0x00, 0xa5, 0x55, 0xd4, 0x8f, 0x13, 0x1e, 0x9a, 0xfd, + 0x4b, 0x14, 0x82, 0xf9, 0x0b, 0xb4, 0x4e, 0xb0, 0x44, 0xc0, 0x49, 0x21, + 0x5e, 0xdf, 0x6d, 0x62, 0x72, 0x94, 0xd3, 0x89, 0x9d, 0xdb, 0xb4, 0x8d, + 0xe7, 0xe0, 0x15, 0x8e, 0xe5, 0xc4, 0x17, 0xef, 0x98, 0xb9, 0x09, 0x1a, + 0xd3, 0x42, 0x7c, 0x4e, 0x79, 0x06, 0x79, 0xdc, 0x74, 0x50, 0x7b, 0xff, + 0x00, 0xd3, 0x5a, 0x77, 0xc5, 0x1e, 0x2b, 0xa5, 0xa2, 0x43, 0x11, 0x9c, + 0x21, 0x07, 0x94, 0x31, 0xd8, 0x2e, 0x3a, 0x93, 0xe8, 0x06, 0xa8, 0x77, + 0xef, 0x8a, 0x74, 0x74, 0x56, 0x18, 0x6d, 0x3c, 0x27, 0x47, 0xe1, 0xd2, + 0xc3, 0x12, 0xc6, 0x27, 0x90, 0x00, 0x84, 0x8e, 0xbb, 0x77, 0xc7, 0xdf, + 0x59, 0xf5, 0x4d, 0xee, 0xbe, 0xf6, 0xe6, 0x79, 0x99, 0x6e, 0x55, 0x59, + 0x38, 0x12, 0x36, 0x51, 0x47, 0xd8, 0x6c, 0x07, 0xdf, 0x27, 0x4c, 0x86, + 0x3f, 0x8f, 0x15, 0x47, 0xb3, 0x44, 0x31, 0x54, 0x69, 0x70, 0x5f, 0x69, + 0xbe, 0x21, 0xf0, 0xd5, 0xaa, 0x1f, 0xfe, 0x9f, 0x2c, 0xd5, 0x55, 0x72, + 0x00, 0x6a, 0x3c, 0x38, 0x39, 0x8c, 0x8c, 0x47, 0x9b, 0x7e, 0xc0, 0xe4, + 0xea, 0xb1, 0xc4, 0x5c, 0x6f, 0x7c, 0xba, 0xd5, 0x43, 0x50, 0x95, 0x37, + 0x0b, 0x65, 0x3c, 0x3f, 0x42, 0xc3, 0x10, 0x0e, 0xc7, 0xb1, 0x1b, 0xfe, + 0xfa, 0x54, 0xd7, 0xfe, 0x21, 0xb3, 0x42, 0x89, 0x4d, 0x6d, 0xb5, 0xd3, + 0xc1, 0x1f, 0x2f, 0x3c, 0x49, 0x16, 0x5d, 0x8e, 0x06, 0xe7, 0xbb, 0x7a, + 0xfa, 0x7b, 0x68, 0x6a, 0xee, 0x2e, 0xbe, 0xd5, 0xce, 0xe5, 0xea, 0x68, + 0xbc, 0x73, 0x9f, 0x0d, 0xd2, 0x21, 0xcc, 0x83, 0x3f, 0xd2, 0x3a, 0x03, + 0xd3, 0x7c, 0x67, 0x43, 0x87, 0x14, 0x71, 0x7d, 0x46, 0x43, 0x02, 0xc6, + 0xb8, 0x19, 0x7c, 0xe3, 0xb5, 0x48, 0xaa, 0x97, 0x87, 0x12, 0xe1, 0x70, + 0x9f, 0xfe, 0x1d, 0x55, 0xca, 0xa5, 0xe7, 0x76, 0x63, 0xbe, 0x79, 0x00, + 0xc1, 0xf5, 0xc6, 0xfd, 0xf4, 0x2c, 0xb7, 0xba, 0x1a, 0x1b, 0xa3, 0xcd, + 0x3d, 0xaf, 0xf8, 0xbd, 0x48, 0x51, 0xe7, 0xa8, 0xfe, 0x45, 0x30, 0xf6, + 0x48, 0xb1, 0xb8, 0x1b, 0xee, 0x71, 0xf9, 0xd5, 0x7e, 0xe5, 0x76, 0xb8, + 0xd7, 0xb9, 0x5b, 0xd5, 0x55, 0x55, 0x7b, 0xf2, 0xff, 0x00, 0x2d, 0x60, + 0xf2, 0x85, 0xf7, 0x3e, 0xfa, 0xf9, 0x4d, 0x14, 0x41, 0x61, 0x47, 0x81, + 0x56, 0x49, 0x59, 0x7c, 0x3f, 0x12, 0x41, 0x9d, 0xf6, 0xc1, 0xf4, 0x1d, + 0xf1, 0xa6, 0x58, 0xed, 0xa5, 0x8a, 0xa7, 0x89, 0x6a, 0x6b, 0xe3, 0x96, + 0x28, 0xea, 0x69, 0x6c, 0x74, 0xb8, 0xc9, 0x4a, 0x38, 0xda, 0x49, 0x71, + 0xf7, 0x18, 0x03, 0xa9, 0xd8, 0x63, 0x43, 0x50, 0xd5, 0x70, 0x8d, 0xb1, + 0xa1, 0x06, 0xd5, 0x55, 0x57, 0x50, 0xc0, 0x06, 0x32, 0xaf, 0x29, 0x95, + 0x8f, 0x42, 0xc4, 0xef, 0xf8, 0x18, 0xeb, 0xed, 0xa0, 0x8c, 0x36, 0xca, + 0x59, 0x1e, 0x4a, 0xdb, 0x8d, 0xbd, 0x21, 0x58, 0x8b, 0x49, 0x1d, 0x34, + 0xad, 0x27, 0x33, 0xf4, 0xe5, 0xcf, 0x63, 0x9d, 0xf1, 0xf7, 0xd2, 0xfb, + 0x6d, 0x7d, 0x20, 0x68, 0xca, 0x51, 0x97, 0x8d, 0x18, 0x16, 0xe7, 0x8f, + 0x24, 0x8e, 0xd9, 0x3d, 0x8e, 0xa5, 0x93, 0x69, 0x6c, 0xad, 0xe3, 0x28, + 0xe8, 0xa5, 0x14, 0xbc, 0x3d, 0xc2, 0xd4, 0xd4, 0x55, 0x2d, 0xb4, 0xad, + 0x2c, 0x61, 0xcf, 0x3f, 0xa8, 0x07, 0xd3, 0x1a, 0x45, 0x57, 0x3d, 0xd6, + 0xe3, 0xe2, 0xd6, 0x5d, 0xee, 0x0f, 0x2e, 0x58, 0xf3, 0x2e, 0xfb, 0x7d, + 0x87, 0x7f, 0xb6, 0xa0, 0x9e, 0xe5, 0x33, 0xdc, 0x26, 0x9e, 0x7a, 0x76, + 0x48, 0x99, 0x88, 0x48, 0xd1, 0xbc, 0xc8, 0x99, 0xeb, 0x9e, 0xf8, 0x1f, + 0x6d, 0x17, 0x15, 0xd1, 0x45, 0x33, 0x47, 0x6b, 0xa5, 0x8e, 0x05, 0x5e, + 0xb2, 0x48, 0xb9, 0x73, 0xf6, 0xf4, 0xed, 0xeb, 0xa9, 0x64, 0xda, 0x21, + 0x99, 0xa9, 0x1e, 0xa4, 0x2d, 0x3c, 0x6f, 0x22, 0x2a, 0xe1, 0x7c, 0x98, + 0x24, 0xe7, 0x73, 0xd7, 0x5c, 0x0a, 0x7a, 0x86, 0x6c, 0x78, 0x01, 0x54, + 0x37, 0xd2, 0xdb, 0x9d, 0x37, 0x82, 0x8a, 0xb1, 0xaa, 0xda, 0xa6, 0xab, + 0xce, 0xf5, 0x21, 0x71, 0xcc, 0xdb, 0x8d, 0xb6, 0x27, 0xd3, 0x6d, 0x17, + 0x5b, 0x6f, 0x4a, 0x1a, 0x7f, 0x13, 0xe7, 0x04, 0x72, 0xe3, 0x3c, 0xaa, + 0x3a, 0x9f, 0x4c, 0xea, 0x59, 0x36, 0x9d, 0x5d, 0xe4, 0x4f, 0xfd, 0x47, + 0x72, 0xdc, 0x9c, 0x55, 0x4a, 0x08, 0xff, 0x00, 0xf7, 0x3a, 0xee, 0x38, + 0x7c, 0x53, 0xfc, 0xb7, 0xc2, 0x1d, 0xf5, 0x45, 0xe3, 0x59, 0x6b, 0x2d, + 0x9c, 0x75, 0x77, 0x31, 0x48, 0xd1, 0x78, 0xb5, 0xb2, 0xca, 0x31, 0xdf, + 0xf9, 0x87, 0xae, 0xb4, 0x1f, 0x86, 0x73, 0x58, 0xef, 0xb4, 0xb1, 0xc1, + 0x57, 0xc4, 0x0b, 0x41, 0x76, 0x79, 0x02, 0x88, 0x27, 0x4f, 0xe5, 0x48, + 0x4f, 0x75, 0x61, 0xd3, 0xdc, 0x69, 0x0e, 0x67, 0x2a, 0x5f, 0x66, 0x7e, + 0x14, 0x73, 0x0a, 0x59, 0x98, 0x48, 0x39, 0x55, 0x49, 0xe9, 0xe9, 0xa9, + 0xb8, 0xae, 0x68, 0x9e, 0xa6, 0xc9, 0xc6, 0x74, 0xd1, 0x85, 0x51, 0xe1, + 0xc7, 0x5d, 0x1a, 0x9f, 0xa6, 0x74, 0xc7, 0x98, 0xff, 0x00, 0xf2, 0x5c, + 0x1f, 0xbe, 0x75, 0x71, 0xe2, 0x2b, 0x35, 0xae, 0xc9, 0x4a, 0xe9, 0x7d, + 0xbe, 0x5b, 0xbc, 0xc4, 0x72, 0x42, 0x92, 0x12, 0xf2, 0x02, 0x73, 0xba, + 0xf6, 0x00, 0x6f, 0xa6, 0x93, 0xd0, 0xda, 0x78, 0x87, 0x83, 0xe4, 0x82, + 0xd6, 0x21, 0xac, 0xa7, 0x8a, 0x23, 0xe1, 0x98, 0xc4, 0x71, 0x22, 0xb8, + 0x1f, 0x54, 0x80, 0x2e, 0x49, 0xc6, 0x76, 0x2c, 0x7a, 0xe9, 0x39, 0x73, + 0x01, 0x1c, 0x65, 0xb7, 0xc7, 0xff, 0x00, 0xd4, 0xd6, 0xc9, 0x22, 0xa7, + 0xac, 0x68, 0x7e, 0x66, 0x00, 0x66, 0xaa, 0x40, 0x1b, 0xc1, 0x8c, 0xa8, + 0xdb, 0xdd, 0x88, 0x38, 0xc7, 0x6c, 0xeb, 0x0a, 0xab, 0x8e, 0xcb, 0x6b, + 0xac, 0x5a, 0x6a, 0xd7, 0x94, 0x5b, 0xbc, 0x72, 0x82, 0x32, 0x33, 0x23, + 0xc5, 0x92, 0x09, 0xfb, 0xe3, 0xf5, 0xd6, 0xd9, 0xf0, 0x92, 0xf1, 0x41, + 0x07, 0x06, 0x51, 0x5b, 0xae, 0x6b, 0x19, 0x58, 0xd5, 0xd6, 0x39, 0x81, + 0x00, 0x45, 0xe6, 0xda, 0x26, 0xdf, 0x63, 0xd3, 0xf6, 0xd7, 0x9c, 0x38, + 0xe2, 0x29, 0x1f, 0x8a, 0xab, 0x40, 0x93, 0x31, 0x53, 0xca, 0x51, 0x30, + 0x32, 0x00, 0xc9, 0xc7, 0xeb, 0xa9, 0x0c, 0x89, 0x26, 0x56, 0x55, 0x49, + 0x17, 0x4f, 0xf6, 0x76, 0xa9, 0xe1, 0x2b, 0x37, 0x10, 0x5c, 0xd2, 0xed, + 0x3b, 0xc1, 0x25, 0x50, 0x11, 0x5b, 0xeb, 0x25, 0x8f, 0x1c, 0x89, 0xcc, + 0x4f, 0x9b, 0xfc, 0x3c, 0xde, 0x5f, 0xd3, 0x5b, 0x7f, 0xc5, 0xea, 0x0b, + 0xc5, 0x75, 0xa2, 0x8d, 0xa1, 0x9a, 0x23, 0x43, 0x1c, 0x5c, 0xd3, 0x32, + 0xb6, 0x39, 0x98, 0xf7, 0xc0, 0xeb, 0xdb, 0xf5, 0x3a, 0xf2, 0xb5, 0xba, + 0x9d, 0x8b, 0x2b, 0x73, 0x64, 0x03, 0xe9, 0xad, 0xc3, 0xe1, 0x2f, 0x17, + 0xf3, 0x52, 0x0e, 0x12, 0xe2, 0x33, 0x2c, 0x96, 0xc9, 0xd7, 0x92, 0x9e, + 0x51, 0xd6, 0x1f, 0x40, 0x4f, 0x65, 0xfe, 0xda, 0x4e, 0x45, 0xf2, 0xc1, + 0xc2, 0xe9, 0xb0, 0x23, 0x2d, 0xde, 0x26, 0x43, 0xf1, 0x67, 0x87, 0x6e, + 0xf6, 0x8a, 0x5a, 0x4b, 0xbb, 0x40, 0xcd, 0x47, 0x55, 0xcc, 0x91, 0xcc, + 0x01, 0x00, 0x15, 0xeb, 0xf8, 0x3d, 0x8f, 0xb6, 0xb2, 0xca, 0x6a, 0xaa, + 0xba, 0x5a, 0xd4, 0x96, 0x98, 0x81, 0x39, 0x6e, 0x50, 0x18, 0x64, 0x6f, + 0xd8, 0xeb, 0xd8, 0x9f, 0x18, 0x78, 0xae, 0xd5, 0x61, 0xe1, 0x8a, 0xae, + 0x10, 0xb4, 0x53, 0xbd, 0xc9, 0xaa, 0x23, 0x30, 0xca, 0x66, 0x97, 0xc4, + 0x8a, 0x9d, 0x71, 0xdb, 0x3d, 0x4f, 0xdb, 0xa6, 0xbc, 0xad, 0x5d, 0x6f, + 0x14, 0x37, 0x6a, 0x7a, 0xb4, 0x84, 0xb4, 0x62, 0x45, 0xfa, 0x17, 0x70, + 0x33, 0xbe, 0x33, 0xd3, 0x6d, 0xb3, 0xab, 0xc1, 0x1f, 0x86, 0x3b, 0x3b, + 0x18, 0xa9, 0x70, 0x99, 0x15, 0x4a, 0xdc, 0xeb, 0xe3, 0x3f, 0x35, 0x31, + 0x65, 0x8f, 0x01, 0xe3, 0x4d, 0x82, 0x92, 0x36, 0xc8, 0x1b, 0x1f, 0xbe, + 0xa3, 0xb1, 0xdc, 0x2a, 0xec, 0xb5, 0x6e, 0x20, 0x45, 0x31, 0x33, 0xf2, + 0xba, 0x30, 0xce, 0x47, 0xb7, 0xa1, 0xd5, 0xbe, 0xed, 0x34, 0x4d, 0x0c, + 0xc2, 0xc8, 0x8f, 0x15, 0x1d, 0x75, 0x51, 0x73, 0x14, 0x92, 0x66, 0x4c, + 0x2e, 0x71, 0xcd, 0x8e, 0xb8, 0xc9, 0xfd, 0x74, 0x04, 0x96, 0x3f, 0x98, + 0x77, 0xa9, 0xf0, 0x01, 0x25, 0x4e, 0xd9, 0xc6, 0x0f, 0x63, 0xf8, 0xd1, + 0x42, 0x7b, 0xc0, 0x0e, 0xb9, 0xc1, 0x69, 0xaf, 0xb2, 0x81, 0x1d, 0x44, + 0xf2, 0xd4, 0x56, 0xb8, 0x58, 0xa9, 0x23, 0x3b, 0xbb, 0x06, 0x53, 0xe7, + 0x19, 0xfa, 0x71, 0x90, 0x3b, 0x93, 0xa4, 0x2b, 0x43, 0x27, 0x81, 0x2b, + 0x0a, 0x69, 0x72, 0xaf, 0xca, 0x06, 0x31, 0xca, 0x07, 0xb6, 0x87, 0xb8, + 0x97, 0xb7, 0x54, 0xc2, 0x82, 0x36, 0x47, 0x4c, 0x32, 0x48, 0x1b, 0xa7, + 0xb6, 0x86, 0x86, 0xf3, 0x51, 0x51, 0xf3, 0x11, 0xbd, 0x43, 0x72, 0x8d, + 0x95, 0xc0, 0xdd, 0x40, 0x3d, 0x3f, 0x52, 0x4e, 0x99, 0x6d, 0x34, 0xd0, + 0xf4, 0x1f, 0x0d, 0x10, 0x5a, 0xca, 0x66, 0x58, 0xe5, 0x91, 0xe6, 0x19, + 0x20, 0x8c, 0x12, 0xdf, 0xe1, 0xd3, 0x26, 0x06, 0x82, 0x14, 0x05, 0xea, + 0x21, 0x46, 0x56, 0x95, 0x49, 0x18, 0x0c, 0x79, 0xba, 0x63, 0xd4, 0x74, + 0xce, 0xb9, 0x17, 0x28, 0xe3, 0x6b, 0x05, 0x7c, 0x2b, 0x22, 0x8a, 0x79, + 0xd0, 0x33, 0x81, 0x9c, 0x90, 0x77, 0xc0, 0xfd, 0xf5, 0xcd, 0xd6, 0x6a, + 0xba, 0xde, 0x23, 0x9e, 0x59, 0x9e, 0x59, 0x92, 0x56, 0x56, 0x0c, 0x5b, + 0x97, 0x62, 0x7b, 0x0e, 0xcb, 0xd7, 0x6d, 0xf5, 0xad, 0x1b, 0xd7, 0x41, + 0x46, 0xe3, 0x3d, 0xc5, 0x2a, 0x6a, 0xe0, 0x5e, 0x77, 0x1c, 0xb2, 0xca, + 0x59, 0x32, 0x4e, 0x36, 0xce, 0x74, 0x44, 0xd7, 0x2a, 0x4a, 0xea, 0x54, + 0x47, 0x46, 0x8d, 0xda, 0x50, 0xae, 0x0f, 0x63, 0x82, 0x03, 0x67, 0xdb, + 0xa7, 0xe7, 0x42, 0x4d, 0x44, 0xf6, 0x8b, 0xdd, 0x54, 0x0a, 0xf9, 0x8b, + 0x67, 0x60, 0x1b, 0x2c, 0xc0, 0x8c, 0x93, 0xf6, 0xce, 0x8d, 0xad, 0xa6, + 0x48, 0xec, 0xc2, 0xe3, 0x84, 0x53, 0x59, 0xe1, 0x99, 0x90, 0x27, 0x51, + 0xb9, 0x04, 0x1f, 0x7e, 0xbf, 0xa6, 0xad, 0x8d, 0x88, 0x1c, 0x7f, 0x3d, + 0x6f, 0x86, 0x52, 0xcb, 0xe2, 0x50, 0xc3, 0x28, 0x8c, 0xf7, 0x00, 0xee, + 0x0e, 0x3d, 0xb4, 0x59, 0xb3, 0xd1, 0x54, 0x5b, 0xeb, 0x83, 0x9f, 0x0a, + 0x47, 0x0d, 0x35, 0x39, 0x4e, 0x85, 0x15, 0x73, 0xfb, 0xe4, 0x6d, 0xdb, + 0x50, 0x99, 0x69, 0xc7, 0x0b, 0xc9, 0x42, 0x81, 0x85, 0x43, 0x4c, 0x5d, + 0x49, 0x5c, 0x2b, 0x63, 0x27, 0x19, 0xfc, 0x68, 0x6a, 0x99, 0x5a, 0x0b, + 0x13, 0xb8, 0x95, 0xa3, 0x2e, 0xc5, 0x02, 0x11, 0xb9, 0xce, 0xfb, 0xfb, + 0x74, 0xd5, 0x14, 0xc0, 0xe3, 0xb9, 0xd5, 0xc5, 0x6e, 0x4b, 0x6d, 0x42, + 0xab, 0xa3, 0x60, 0x29, 0xe6, 0xdd, 0x37, 0xc6, 0x3e, 0xda, 0x8f, 0x8c, + 0x56, 0x3b, 0x8f, 0xc9, 0xdb, 0xa0, 0x58, 0xd6, 0x4a, 0x28, 0x39, 0x07, + 0x20, 0xd8, 0x9e, 0x62, 0x4f, 0xf7, 0xd4, 0x34, 0xf4, 0x6f, 0x2d, 0x39, + 0x33, 0xcb, 0x1e, 0x14, 0xf5, 0xcf, 0x51, 0xe9, 0xa6, 0x86, 0x9e, 0x81, + 0x29, 0x21, 0x34, 0xec, 0xef, 0x50, 0xc4, 0xbc, 0xac, 0x63, 0xc0, 0x51, + 0xdb, 0x07, 0xf3, 0xf9, 0xeb, 0xa8, 0x51, 0x4b, 0xa4, 0xb5, 0x4a, 0x6b, + 0x42, 0x54, 0xc6, 0x42, 0xab, 0x63, 0xa6, 0xdf, 0x73, 0xad, 0xcf, 0xfd, + 0x9c, 0x78, 0x5e, 0xe2, 0x9c, 0x71, 0x15, 0xf6, 0x68, 0xa4, 0xa5, 0xb4, + 0xd2, 0x42, 0xd2, 0x0a, 0x99, 0x94, 0xac, 0x4e, 0xdf, 0x48, 0x0a, 0xdd, + 0x3b, 0xea, 0x8c, 0x23, 0xa7, 0x0a, 0x24, 0xa7, 0x9b, 0x2f, 0xc9, 0x86, + 0x2d, 0xd3, 0x71, 0xd3, 0x1d, 0xf5, 0x74, 0xa1, 0xe2, 0xba, 0xcb, 0x85, + 0xa2, 0x92, 0xd1, 0x79, 0xb8, 0x56, 0xad, 0x14, 0x51, 0x24, 0x74, 0xd4, + 0x54, 0x31, 0x15, 0x32, 0x80, 0x4e, 0x32, 0x07, 0xdb, 0x54, 0x9d, 0x3b, + 0x15, 0x2c, 0x3c, 0xa7, 0x66, 0xf5, 0x5d, 0xf1, 0x17, 0x84, 0x23, 0x8e, + 0x68, 0x92, 0xff, 0x00, 0x4b, 0x2c, 0xe1, 0x8a, 0xb3, 0xae, 0x48, 0x03, + 0xa7, 0x5c, 0x6b, 0xcd, 0x5f, 0x10, 0x6b, 0xc7, 0x17, 0x71, 0x8d, 0x4d, + 0xe6, 0xb6, 0xae, 0xa7, 0xe4, 0xd4, 0xf8, 0x54, 0xb0, 0xa4, 0x79, 0x61, + 0x1a, 0xf4, 0x3c, 0xc7, 0xa6, 0x7a, 0x9d, 0xba, 0x9d, 0x1a, 0xd5, 0x09, + 0x6e, 0x4a, 0x8a, 0x5a, 0x6b, 0x4d, 0x22, 0x38, 0x25, 0xdc, 0xcf, 0x2f, + 0x8b, 0x3f, 0x2e, 0x46, 0x32, 0x01, 0x21, 0x49, 0x24, 0x6d, 0xd7, 0x42, + 0xd6, 0x53, 0x5e, 0x26, 0xa5, 0x7a, 0xca, 0xdb, 0x7c, 0xb1, 0x53, 0xe3, + 0x0c, 0x4c, 0x61, 0x47, 0xdc, 0x6f, 0x8c, 0x7b, 0xef, 0xa6, 0xfc, 0x96, + 0x5e, 0xd5, 0xec, 0x57, 0x15, 0x1c, 0x6e, 0x23, 0x5a, 0x48, 0x59, 0x56, + 0x32, 0x70, 0xe5, 0xcb, 0x36, 0xe7, 0x39, 0xcf, 0x41, 0xfa, 0x69, 0x84, + 0x9e, 0x1d, 0x08, 0x8e, 0x55, 0x81, 0x2a, 0xaa, 0x58, 0x79, 0xbc, 0x61, + 0xcc, 0x07, 0xb8, 0xf5, 0x3a, 0x12, 0x2a, 0x84, 0x83, 0x95, 0x22, 0x2e, + 0xc3, 0x2a, 0x63, 0x50, 0xd9, 0x18, 0xf7, 0x3d, 0xfe, 0xda, 0x6a, 0xb5, + 0x55, 0xb7, 0x26, 0x94, 0xc7, 0x4b, 0x09, 0x90, 0x10, 0xa1, 0xd9, 0xb9, + 0x79, 0x33, 0xd7, 0x1b, 0x7b, 0x01, 0xbe, 0x97, 0x63, 0x94, 0x52, 0x5c, + 0x10, 0xd4, 0xf1, 0x15, 0x74, 0xb4, 0x9f, 0x2f, 0x23, 0xc1, 0x2b, 0x10, + 0x10, 0x46, 0xb4, 0xa8, 0x7c, 0x31, 0xe8, 0xa4, 0xf4, 0x23, 0xd8, 0x7e, + 0x75, 0x02, 0xd5, 0x5c, 0x82, 0xab, 0x43, 0x4a, 0x54, 0x85, 0x11, 0x86, + 0x38, 0xe7, 0xc6, 0xfb, 0x91, 0xd0, 0x69, 0xa9, 0xb4, 0xdd, 0xa6, 0x3c, + 0x83, 0xe5, 0xa0, 0xdf, 0xeb, 0x50, 0x0b, 0x63, 0xee, 0x37, 0xfe, 0xda, + 0x51, 0x71, 0xa4, 0xab, 0xb7, 0xd4, 0x34, 0x2d, 0x56, 0x80, 0x48, 0x0e, + 0xc4, 0xe1, 0x8e, 0x0e, 0x33, 0xef, 0xa9, 0xb8, 0xbd, 0xa7, 0xc8, 0x94, + 0x3d, 0x68, 0x92, 0xbd, 0x3c, 0x55, 0x1f, 0x53, 0x09, 0x80, 0xfc, 0x68, + 0xf4, 0x64, 0xaf, 0xa9, 0x86, 0x8a, 0x3b, 0x7a, 0x7c, 0x9c, 0x32, 0x9f, + 0xe6, 0xbb, 0xf9, 0x00, 0xf5, 0x3b, 0x6f, 0xa5, 0x96, 0xe9, 0x2d, 0xd4, + 0x71, 0xbd, 0x40, 0xff, 0x00, 0x7b, 0xb8, 0x33, 0x93, 0xc9, 0x92, 0xa1, + 0x17, 0xa7, 0x5f, 0x7e, 0xa7, 0x5d, 0xd4, 0xd5, 0x5d, 0xa6, 0x6f, 0x91, + 0x79, 0x82, 0xc1, 0x27, 0xd0, 0x22, 0xd9, 0x70, 0x7a, 0x0f, 0x7e, 0xd8, + 0xd5, 0xa6, 0x53, 0x1b, 0xcd, 0x6f, 0xa1, 0x7a, 0xf6, 0x89, 0x78, 0x86, + 0x08, 0x5a, 0x43, 0xcb, 0x1c, 0x14, 0xf1, 0xb0, 0x0e, 0x07, 0x60, 0xc7, + 0x63, 0xf7, 0xd3, 0x9f, 0xfe, 0xdb, 0xa4, 0xa3, 0x4a, 0x6a, 0x88, 0xa9, + 0x58, 0x46, 0x08, 0x9a, 0x77, 0x4f, 0x1a, 0x5e, 0x7c, 0x6d, 0xd3, 0x03, + 0x3d, 0x4f, 0xa6, 0xab, 0xed, 0xc3, 0x91, 0xc3, 0x68, 0x89, 0x9a, 0xf4, + 0xb1, 0xcc, 0xe4, 0xad, 0x44, 0x0f, 0x10, 0x0f, 0x18, 0x1d, 0x40, 0x6c, + 0xe7, 0xa8, 0x1b, 0x69, 0x6a, 0xc7, 0x13, 0xd6, 0xc4, 0x94, 0x95, 0x2d, + 0x38, 0x62, 0x39, 0xde, 0x52, 0x70, 0x49, 0xdb, 0x97, 0xdf, 0xae, 0x7f, + 0x1a, 0x8c, 0x0d, 0xca, 0x5c, 0x23, 0xf5, 0x7a, 0xdb, 0xa4, 0x99, 0x12, + 0xc5, 0x43, 0x54, 0x22, 0x4d, 0xe4, 0x92, 0xa0, 0x87, 0x27, 0xdc, 0x0e, + 0xdf, 0xae, 0xbe, 0x8a, 0x17, 0x99, 0x15, 0x8b, 0xc8, 0x0e, 0x76, 0x04, + 0xe3, 0x95, 0x7e, 0xda, 0xb3, 0xf1, 0x4d, 0xae, 0xa6, 0x82, 0x9a, 0x2a, + 0xba, 0xca, 0xec, 0xf3, 0x80, 0x84, 0x41, 0x1e, 0x31, 0xb6, 0xc0, 0x00, + 0x71, 0x9c, 0x7f, 0xe7, 0x55, 0xa1, 0x08, 0x5a, 0x49, 0xa6, 0xa9, 0x96, + 0x72, 0xae, 0xdc, 0xaa, 0x07, 0x5d, 0x4a, 0x19, 0x1a, 0x6a, 0xd3, 0x23, + 0x32, 0xa5, 0x14, 0x73, 0x27, 0x2b, 0xb8, 0xc9, 0xc3, 0x02, 0x00, 0xce, + 0x7d, 0x3a, 0xeb, 0xbb, 0x3d, 0xda, 0x92, 0x9d, 0xd6, 0x69, 0x29, 0x9e, + 0x49, 0x54, 0xe4, 0x3e, 0x3c, 0xa4, 0xff, 0x00, 0x96, 0xa2, 0xb6, 0xa2, + 0xf8, 0xc9, 0xe3, 0xc7, 0x2f, 0x80, 0xc7, 0xc3, 0xe7, 0xe5, 0xcf, 0xeb, + 0xef, 0x8c, 0x68, 0xda, 0xa8, 0xa8, 0xad, 0x95, 0x58, 0xc0, 0x9e, 0x9d, + 0x9b, 0x20, 0x78, 0x7e, 0x61, 0xe9, 0x9d, 0xf6, 0x07, 0x54, 0x59, 0x35, + 0x5d, 0xee, 0x79, 0x99, 0xdd, 0x22, 0x8e, 0x25, 0x29, 0x85, 0x63, 0xb1, + 0xfc, 0x7e, 0x34, 0xbd, 0xb3, 0x57, 0x34, 0x6c, 0xae, 0x65, 0x6c, 0x81, + 0x1a, 0x83, 0x90, 0x0f, 0xb9, 0xd1, 0x97, 0x1a, 0xb7, 0xac, 0x40, 0xb1, + 0x43, 0xf2, 0x94, 0xea, 0x02, 0xf2, 0x2e, 0x09, 0x62, 0x3b, 0xe9, 0x32, + 0x99, 0x21, 0x12, 0x34, 0x52, 0x14, 0x05, 0xb1, 0x19, 0x23, 0x72, 0xde, + 0xc3, 0x50, 0x84, 0x7f, 0x10, 0xb8, 0x6b, 0x88, 0xc5, 0xfa, 0xe3, 0x79, + 0x9e, 0xd9, 0x33, 0x50, 0xcb, 0x57, 0x37, 0x85, 0x2a, 0xee, 0x39, 0x3c, + 0x56, 0x03, 0x3e, 0x9d, 0x07, 0xeb, 0xa1, 0x28, 0xac, 0xf3, 0xd2, 0xd2, + 0xbd, 0x6d, 0x43, 0x72, 0x3c, 0x60, 0x15, 0x41, 0xd5, 0x75, 0x78, 0xe3, + 0x7e, 0x27, 0xa5, 0x96, 0xef, 0x3d, 0xb7, 0xe6, 0x5c, 0xc7, 0x4b, 0x33, + 0xaf, 0x86, 0x7f, 0xc6, 0x18, 0xe4, 0x9e, 0xdd, 0x49, 0xc7, 0xb6, 0xaa, + 0x35, 0x57, 0x17, 0xaa, 0x2d, 0x00, 0x3c, 0xa8, 0x73, 0xef, 0x9d, 0xf5, + 0x9b, 0x04, 0x25, 0xb5, 0xca, 0x7d, 0xff, 0x00, 0xe1, 0xc5, 0x97, 0xd9, + 0x84, 0x47, 0x55, 0x25, 0x6d, 0x74, 0x75, 0x15, 0xb3, 0xbc, 0xc4, 0xb6, + 0x4b, 0x39, 0xe6, 0x00, 0xfa, 0x9c, 0x9d, 0xc6, 0xfa, 0xb5, 0x9e, 0x24, + 0xa7, 0xa5, 0xb3, 0xd3, 0xd9, 0xa9, 0xee, 0x0c, 0x20, 0x4c, 0xf3, 0x00, + 0xa5, 0x4b, 0x39, 0xdc, 0x9f, 0x5c, 0x7f, 0xdf, 0xde, 0x91, 0x12, 0x08, + 0x21, 0x67, 0x5f, 0xab, 0x1b, 0x6b, 0xed, 0x0a, 0x78, 0x93, 0x89, 0x64, + 0xcb, 0x04, 0x39, 0xfc, 0xe8, 0x26, 0xf9, 0x48, 0x56, 0xf2, 0xfb, 0x6f, + 0xba, 0x34, 0x96, 0xba, 0xab, 0x74, 0x52, 0x7f, 0xba, 0xcb, 0xcb, 0xe2, + 0x12, 0x30, 0x3a, 0x74, 0xc6, 0xab, 0xb7, 0x68, 0xe3, 0xa7, 0xa9, 0x54, + 0x8c, 0x89, 0x09, 0x1e, 0x66, 0x1b, 0x83, 0xed, 0x9d, 0x29, 0xaf, 0xaf, + 0xa9, 0xa6, 0x63, 0x0d, 0x31, 0x68, 0xfc, 0x4e, 0x56, 0x66, 0x56, 0xec, + 0x07, 0x4f, 0xdf, 0x52, 0x5a, 0xe7, 0x79, 0xa2, 0x78, 0x66, 0x60, 0xce, + 0x4f, 0x30, 0x63, 0xd7, 0x55, 0x54, 0x54, 0xa7, 0xb8, 0xd4, 0xfe, 0x11, + 0x58, 0x7e, 0x1f, 0xde, 0xea, 0x61, 0xa1, 0xbd, 0x5e, 0xea, 0xa9, 0xeb, + 0xa5, 0xd9, 0x69, 0x5c, 0x08, 0xe3, 0x90, 0xfa, 0x09, 0x0e, 0x72, 0x7a, + 0xed, 0xb6, 0xb7, 0xe8, 0x61, 0xe1, 0x1e, 0x07, 0xa2, 0x4a, 0x5a, 0x5a, + 0x40, 0x8e, 0xc9, 0xff, 0x00, 0x06, 0x18, 0x8c, 0x92, 0x32, 0xe3, 0xa9, + 0xf6, 0xdb, 0xae, 0xc3, 0x5e, 0x53, 0xe1, 0xb8, 0x6d, 0xf5, 0x93, 0x1a, + 0x5a, 0xe8, 0x99, 0x9e, 0x48, 0xf9, 0x29, 0x9c, 0x3f, 0x2f, 0x85, 0x36, + 0x57, 0x95, 0x89, 0xf4, 0xeb, 0xfa, 0xea, 0xdd, 0x74, 0xbc, 0xf1, 0x6f, + 0x0d, 0xd3, 0x1b, 0x55, 0xce, 0xb2, 0x3b, 0x8d, 0x1b, 0x1e, 0x69, 0x8a, + 0x8c, 0xcf, 0x32, 0x67, 0xe9, 0x62, 0x7c, 0xc5, 0x7b, 0x63, 0xa6, 0xda, + 0x09, 0x6a, 0x31, 0xc7, 0xc2, 0xbc, 0xbd, 0x0d, 0xc7, 0x38, 0xae, 0x97, + 0x27, 0xcf, 0x88, 0xb7, 0x3b, 0x75, 0xf6, 0xf7, 0x57, 0x58, 0x69, 0x44, + 0x6a, 0x1d, 0xbc, 0x1f, 0x02, 0x35, 0x50, 0x17, 0x3b, 0x1d, 0xba, 0x93, + 0xea, 0x73, 0xac, 0xca, 0xba, 0x81, 0x64, 0xad, 0x32, 0x46, 0x8c, 0xa3, + 0xb3, 0x36, 0x0b, 0x63, 0xf4, 0xd5, 0xba, 0xf4, 0xa5, 0x78, 0x4a, 0xb3, + 0x8a, 0x6d, 0x55, 0x54, 0xd1, 0x50, 0xd1, 0xf2, 0xc2, 0x20, 0x95, 0xb9, + 0x5a, 0x49, 0x5b, 0xfe, 0x5e, 0xe7, 0x19, 0x39, 0xed, 0xac, 0xee, 0xd5, + 0x7e, 0x45, 0x41, 0x1d, 0x67, 0x36, 0x32, 0xcd, 0xe2, 0x01, 0x96, 0xc9, + 0xdf, 0x41, 0x8d, 0x39, 0x2b, 0x6a, 0x85, 0xbb, 0xbe, 0x06, 0x41, 0x15, + 0x67, 0xf9, 0x79, 0x23, 0x0a, 0x08, 0xf2, 0x30, 0x3e, 0x9d, 0x06, 0x34, + 0x44, 0xf1, 0xd5, 0xd2, 0x53, 0xac, 0xeb, 0x87, 0x8f, 0x62, 0x79, 0x86, + 0x70, 0x34, 0x9f, 0x88, 0xea, 0x64, 0xa8, 0xb3, 0xd1, 0x55, 0x40, 0xad, + 0x03, 0x34, 0x87, 0xae, 0xe4, 0xe3, 0x38, 0x3a, 0x0e, 0xa7, 0x88, 0x2e, + 0x15, 0x36, 0x7a, 0x9a, 0x17, 0x3e, 0x27, 0x88, 0x98, 0x04, 0x1c, 0x15, + 0xdc, 0x69, 0x98, 0xbe, 0xa0, 0x9c, 0xf1, 0x0d, 0x6c, 0xf5, 0xfc, 0xa2, + 0x6a, 0x78, 0x51, 0xe2, 0x61, 0x1a, 0xf2, 0xb7, 0x98, 0x83, 0xed, 0x8e, + 0x83, 0x5d, 0x0b, 0x39, 0xb7, 0x52, 0x0a, 0xcb, 0x8c, 0x4b, 0xe0, 0xcb, + 0x1f, 0x89, 0x4e, 0x76, 0xfe, 0x68, 0xe6, 0x23, 0xd7, 0x6d, 0xd7, 0x40, + 0xd8, 0xa9, 0xda, 0xa8, 0xb3, 0xcf, 0x0c, 0xb2, 0x78, 0x23, 0x9c, 0x0e, + 0xc0, 0x02, 0x3a, 0xfa, 0x8d, 0x38, 0xbd, 0xdf, 0xe9, 0xae, 0xf5, 0x15, + 0x8f, 0x53, 0x48, 0xb1, 0xca, 0x89, 0x1a, 0x52, 0xa4, 0x28, 0x23, 0x48, + 0x54, 0x64, 0x9d, 0x80, 0xef, 0x9d, 0x0b, 0x1b, 0x16, 0x70, 0xe5, 0xea, + 0xa8, 0xe3, 0x01, 0x7f, 0x9a, 0xaf, 0xcc, 0xb1, 0xa0, 0xf2, 0xa2, 0x67, + 0x6f, 0xce, 0x8a, 0xbd, 0xcf, 0x34, 0xa9, 0x29, 0x41, 0xe6, 0x88, 0x22, + 0xb1, 0x07, 0x21, 0x98, 0x64, 0x93, 0x9f, 0x5d, 0xfa, 0x68, 0x5e, 0x1f, + 0xaa, 0x92, 0x92, 0xb6, 0x1a, 0x93, 0x1a, 0xb7, 0x33, 0x96, 0x90, 0x11, + 0x9f, 0x21, 0xdb, 0xfe, 0xbf, 0x8d, 0x17, 0xcf, 0x51, 0x6f, 0xaf, 0xad, + 0xa5, 0x0d, 0x84, 0x9c, 0x73, 0x00, 0x06, 0xc4, 0x7a, 0x6b, 0x5e, 0x17, + 0xc5, 0x1d, 0x0c, 0x0f, 0xc4, 0x0e, 0xa6, 0x71, 0x55, 0x08, 0xb8, 0x4c, + 0xed, 0x14, 0xed, 0x20, 0x56, 0x3d, 0x79, 0x90, 0x83, 0xab, 0x2f, 0x11, + 0xc1, 0x3b, 0xdb, 0x66, 0x96, 0x01, 0x27, 0x82, 0xaa, 0xa5, 0x14, 0x8d, + 0x89, 0x39, 0x00, 0x0f, 0xb0, 0x1f, 0xf7, 0x9d, 0x27, 0xe1, 0xca, 0x58, + 0xee, 0x54, 0xb2, 0x41, 0x24, 0x2a, 0x0f, 0x3e, 0xd2, 0x16, 0xc9, 0x4f, + 0xc6, 0x37, 0x18, 0xed, 0xab, 0x2c, 0x17, 0x1f, 0xfe, 0xcf, 0xa5, 0xb5, + 0x55, 0x4f, 0x2d, 0x3c, 0xd2, 0x86, 0x85, 0x5e, 0x55, 0x3c, 0xb8, 0x2e, + 0x00, 0xc7, 0x63, 0x91, 0x9e, 0xfd, 0x34, 0xfb, 0x34, 0xd8, 0x05, 0x1c, + 0x36, 0xf8, 0xf8, 0x6e, 0x9a, 0xe3, 0x53, 0x0b, 0xa4, 0x10, 0xa3, 0x23, + 0xc6, 0xad, 0xe6, 0x79, 0x5b, 0xa3, 0x7d, 0x8e, 0x3f, 0x1a, 0xab, 0x57, + 0x61, 0xa0, 0xa7, 0x91, 0x69, 0x5a, 0x28, 0x08, 0x28, 0x27, 0xee, 0xec, + 0x7f, 0xc4, 0x3f, 0x1a, 0x3e, 0xe8, 0x93, 0x50, 0x73, 0x5a, 0x56, 0xa1, + 0xa5, 0x32, 0xb1, 0xf0, 0xd4, 0x21, 0xfa, 0x81, 0x20, 0x6a, 0x4a, 0x09, + 0x29, 0xa5, 0xa5, 0x4a, 0x4a, 0x98, 0x2a, 0x24, 0xa9, 0x84, 0x37, 0xf2, + 0x08, 0xf2, 0x87, 0x3b, 0x02, 0x7e, 0xc7, 0x54, 0x53, 0x64, 0x34, 0x86, + 0x96, 0x8a, 0x92, 0x25, 0x8e, 0x15, 0x96, 0xac, 0x64, 0x3f, 0x8a, 0xbc, + 0xd1, 0xae, 0xe3, 0x18, 0x19, 0xd3, 0x99, 0xa9, 0x1a, 0xa6, 0x64, 0xe7, + 0x67, 0x92, 0x56, 0x40, 0x5c, 0x2a, 0xe0, 0x2e, 0x71, 0xb8, 0x00, 0xe3, + 0x1e, 0xda, 0x16, 0x8a, 0xd1, 0x5b, 0x82, 0x23, 0xa6, 0x25, 0x64, 0xf2, + 0x80, 0x1f, 0x20, 0x37, 0x5d, 0xce, 0x3a, 0xf4, 0xd8, 0xfa, 0x8d, 0x39, + 0xa1, 0x57, 0xb7, 0xd4, 0xcf, 0x6f, 0xb8, 0x49, 0x1c, 0x50, 0x48, 0x8a, + 0xf2, 0x2a, 0x37, 0x3c, 0xc7, 0xa7, 0xd2, 0xc3, 0xf7, 0x1a, 0x84, 0x21, + 0xf0, 0xe8, 0x28, 0x5a, 0x28, 0xe1, 0x57, 0xab, 0xa9, 0x23, 0x99, 0x93, + 0xa9, 0x18, 0xf5, 0x5e, 0xc3, 0xdb, 0xf4, 0xd4, 0xc6, 0xba, 0xfc, 0x94, + 0xd3, 0x2b, 0x62, 0x86, 0x0a, 0x8c, 0x16, 0x64, 0x02, 0x36, 0xe5, 0xec, + 0x32, 0x4e, 0xc3, 0xa6, 0xa1, 0xae, 0xac, 0xa5, 0x9f, 0xc2, 0x86, 0xd3, + 0x6e, 0x65, 0x98, 0xcc, 0x79, 0xa6, 0x7e, 0xac, 0x4e, 0x7c, 0xbf, 0x60, + 0x75, 0xc3, 0xfc, 0xb0, 0x0f, 0x05, 0x64, 0x4e, 0xd2, 0xb1, 0xda, 0x79, + 0xc9, 0xc0, 0x1d, 0x49, 0x41, 0x8d, 0x87, 0xbe, 0xff, 0x00, 0x6d, 0x42, + 0x06, 0x43, 0x7d, 0x96, 0x1b, 0x7c, 0x34, 0x56, 0x89, 0x33, 0x51, 0x51, + 0xe7, 0xa8, 0x91, 0xa3, 0x0c, 0xfc, 0xc7, 0x6e, 0x6c, 0x9e, 0xfe, 0xfa, + 0xee, 0x9a, 0xcb, 0x78, 0xa9, 0x55, 0x96, 0xae, 0x59, 0xa5, 0x8a, 0x12, + 0x58, 0x78, 0x8d, 0xce, 0x71, 0xdf, 0xca, 0x3a, 0x01, 0xd3, 0x3f, 0xf6, + 0x07, 0x96, 0x4a, 0x68, 0x22, 0x89, 0x6d, 0xe8, 0xaa, 0xe8, 0x7c, 0x4f, + 0x1b, 0x9b, 0x97, 0x94, 0xf5, 0xdc, 0xe3, 0xd3, 0x42, 0x52, 0x56, 0x56, + 0x55, 0x21, 0xa7, 0x8e, 0xad, 0x99, 0x64, 0x62, 0xcf, 0x32, 0x13, 0xcc, + 0xfb, 0xf4, 0x3a, 0x84, 0x0c, 0xb8, 0x5c, 0xa8, 0x29, 0xa3, 0xf9, 0x6b, + 0x4c, 0x4a, 0x24, 0x66, 0x21, 0xe4, 0x45, 0x05, 0xc7, 0xb0, 0x6f, 0x5f, + 0x7f, 0xf5, 0xd7, 0x16, 0x64, 0xba, 0xb2, 0xd4, 0xd4, 0xd2, 0x52, 0xc7, + 0x14, 0x4a, 0xc3, 0x9e, 0x57, 0x39, 0x20, 0xe3, 0xbf, 0xa9, 0xd7, 0x5f, + 0x25, 0x49, 0x41, 0x28, 0x2c, 0x7c, 0x59, 0x0a, 0x61, 0x41, 0x18, 0x20, + 0xed, 0xdf, 0x46, 0x56, 0xd5, 0xc5, 0xf2, 0x06, 0x0e, 0x52, 0xaf, 0x26, + 0x19, 0xa2, 0x41, 0x85, 0x51, 0x8e, 0xff, 0x00, 0xe2, 0x3a, 0x11, 0x88, + 0xe9, 0x2e, 0xd5, 0xe9, 0x13, 0x52, 0xc7, 0x13, 0x47, 0x33, 0xc9, 0xca, + 0xae, 0xd8, 0x5e, 0x61, 0xdf, 0x18, 0x1f, 0x4e, 0x81, 0xab, 0xa4, 0xa3, + 0x42, 0xc6, 0xa2, 0xbd, 0xa5, 0x99, 0x62, 0xe7, 0x96, 0x45, 0xcb, 0x1e, + 0x6f, 0xf0, 0x80, 0x3b, 0x60, 0xe7, 0x5c, 0x56, 0xbd, 0x24, 0x94, 0xca, + 0xa7, 0x94, 0x33, 0x1c, 0xe0, 0x1f, 0x30, 0xcf, 0xb6, 0x8c, 0xb3, 0xdd, + 0xa1, 0xa4, 0x33, 0x53, 0x45, 0x4b, 0x1c, 0x6d, 0x24, 0x65, 0x10, 0xc9, + 0x0a, 0xb3, 0x1e, 0x98, 0xcb, 0x7d, 0x86, 0xa0, 0x14, 0xe3, 0xd0, 0xb6, + 0xc7, 0x1c, 0x32, 0xe5, 0xa3, 0xa7, 0x32, 0x7f, 0x49, 0x69, 0x54, 0xe4, + 0x82, 0x3d, 0xff, 0x00, 0xb6, 0x98, 0x57, 0xd1, 0x59, 0xa3, 0xaa, 0x5a, + 0x8a, 0xda, 0xb9, 0xe4, 0x99, 0xf7, 0xf0, 0x55, 0x42, 0x82, 0x70, 0x70, + 0x07, 0xa0, 0x1a, 0x81, 0x6b, 0x40, 0xcb, 0xab, 0xc6, 0xc0, 0xae, 0x15, + 0x91, 0x76, 0x07, 0xbf, 0xe9, 0xa5, 0xeb, 0x53, 0x11, 0xaa, 0x0b, 0x31, + 0x90, 0xb6, 0x7a, 0x7f, 0x4b, 0x1f, 0x5c, 0xff, 0x00, 0x96, 0xad, 0x12, + 0xac, 0xb4, 0x70, 0xf5, 0xb2, 0x8e, 0xf5, 0x6a, 0x9e, 0x05, 0x34, 0x94, + 0x45, 0x50, 0xc9, 0x3c, 0x93, 0xe5, 0xe4, 0x75, 0x04, 0x74, 0x03, 0xd0, + 0x67, 0xef, 0x8d, 0x09, 0x53, 0x6a, 0xa3, 0xa5, 0x74, 0x9e, 0x82, 0xe6, + 0x67, 0x90, 0x02, 0xdc, 0xc0, 0x05, 0x0b, 0xbf, 0xeb, 0x9f, 0x6e, 0xdb, + 0xf5, 0xd2, 0xf9, 0xa5, 0x2d, 0x4d, 0x24, 0x91, 0x88, 0x96, 0x25, 0x6c, + 0x66, 0x3f, 0xbe, 0x8b, 0x8a, 0xe0, 0xfe, 0x04, 0x94, 0xb4, 0x8b, 0xcf, + 0xcd, 0x8c, 0x86, 0x18, 0xe5, 0x03, 0x55, 0x61, 0xc3, 0x1a, 0x5d, 0x9f, + 0x6b, 0x24, 0x9a, 0xb2, 0xa4, 0x4d, 0x59, 0x53, 0xe3, 0x15, 0x1e, 0x69, + 0x65, 0x7e, 0x8b, 0xec, 0x7d, 0x75, 0xc5, 0xe2, 0x48, 0xab, 0x63, 0xa7, + 0xa4, 0xa3, 0xa7, 0x59, 0x20, 0xa7, 0x53, 0x23, 0xca, 0xab, 0x8f, 0x10, + 0x12, 0x0e, 0xe7, 0xbf, 0x6d, 0x45, 0x77, 0x45, 0xab, 0x8c, 0x2c, 0xf2, + 0xa1, 0x91, 0xf0, 0x15, 0x00, 0xfa, 0x71, 0xa9, 0xe8, 0x84, 0x66, 0x86, + 0x48, 0x9a, 0x75, 0x8d, 0xce, 0xc5, 0xdb, 0x7e, 0x6d, 0x52, 0x65, 0xed, + 0xae, 0x85, 0x57, 0x9a, 0xfa, 0xb8, 0x5e, 0x08, 0xe2, 0x05, 0xa3, 0x93, + 0x0f, 0xca, 0xaa, 0x70, 0xa7, 0xfc, 0xfd, 0x35, 0x35, 0x4c, 0xf4, 0xb1, + 0xa7, 0xcc, 0xd4, 0x54, 0xcc, 0x95, 0x12, 0x2e, 0x70, 0xbf, 0xe2, 0xff, + 0x00, 0x2f, 0x4d, 0x0b, 0x5f, 0x3c, 0x4a, 0xea, 0x8e, 0x24, 0x6f, 0x0d, + 0xb0, 0x08, 0x07, 0x71, 0xed, 0xbf, 0xdb, 0x5c, 0x4b, 0x72, 0xa1, 0x33, + 0x47, 0x1b, 0x53, 0xaa, 0xca, 0xa0, 0x2a, 0x87, 0x1e, 0x60, 0x75, 0x2c, + 0x94, 0x49, 0xe3, 0xcd, 0x3d, 0x31, 0xf0, 0xe0, 0x54, 0x56, 0x1b, 0xb6, + 0x31, 0x9f, 0x7d, 0x09, 0x4a, 0x88, 0x19, 0x96, 0x59, 0x0c, 0x93, 0xc5, + 0xe6, 0x2c, 0xdd, 0x17, 0xd3, 0x5d, 0xcf, 0x0d, 0x74, 0xc7, 0x9a, 0x7a, + 0x94, 0xa7, 0x84, 0x9c, 0x80, 0xbf, 0x57, 0xe3, 0x40, 0x56, 0xb5, 0x32, + 0x7f, 0x22, 0x08, 0x9a, 0x56, 0xfe, 0xa9, 0x1f, 0xb9, 0xf4, 0xd5, 0xd9, + 0x03, 0x38, 0x96, 0x10, 0x9c, 0x51, 0x79, 0xce, 0x0f, 0x3d, 0xc2, 0x76, + 0x3f, 0xff, 0x00, 0xd1, 0xb4, 0x3c, 0x30, 0xab, 0xb4, 0x71, 0x80, 0x00, + 0xc8, 0x3a, 0xfd, 0xc5, 0xcc, 0xff, 0x00, 0xfa, 0xbe, 0xee, 0xb1, 0x80, + 0x49, 0xaf, 0x9c, 0x1f, 0x6f, 0xe6, 0x36, 0x8e, 0xb3, 0x52, 0xb1, 0x2b, + 0x9c, 0x9c, 0x0c, 0x13, 0xe9, 0x8e, 0xfa, 0x16, 0x70, 0x72, 0x76, 0xce, + 0xde, 0x15, 0x05, 0x52, 0x31, 0xcd, 0x81, 0x86, 0x3a, 0xfc, 0xc1, 0x29, + 0xe9, 0xf0, 0x48, 0x01, 0x77, 0x27, 0x46, 0x38, 0x5c, 0x19, 0x30, 0x79, + 0x15, 0x79, 0x8b, 0x7b, 0x7a, 0xe9, 0x69, 0x9e, 0x49, 0xa6, 0x25, 0x55, + 0x58, 0x8e, 0xfd, 0xa3, 0xfb, 0x7b, 0xfb, 0xe9, 0x51, 0x8d, 0xb1, 0x62, + 0xda, 0xe6, 0x92, 0x4f, 0xf7, 0x96, 0x6e, 0x50, 0xf8, 0x48, 0xd4, 0x8d, + 0xd8, 0x6e, 0x73, 0xa6, 0x16, 0xa6, 0x2b, 0x1a, 0x13, 0xb8, 0xf5, 0xd2, + 0xfb, 0xb3, 0x7f, 0x35, 0x23, 0xe7, 0x69, 0x02, 0x8e, 0x76, 0x63, 0xd4, + 0x93, 0xb7, 0xf6, 0x1a, 0x71, 0x41, 0x4f, 0x23, 0xd2, 0x24, 0xf1, 0xc6, + 0x4c, 0x60, 0x0e, 0x9f, 0x6d, 0x04, 0xf8, 0x74, 0x08, 0xd2, 0x9c, 0x3f, + 0x97, 0x93, 0x6c, 0x60, 0xe7, 0x4c, 0xae, 0xdc, 0x61, 0x72, 0xa4, 0xe2, + 0xda, 0x5a, 0xf5, 0x68, 0xb1, 0x35, 0xb8, 0x51, 0xb4, 0x64, 0x86, 0x19, + 0x0b, 0x80, 0xec, 0x08, 0xf5, 0xdf, 0x42, 0xd9, 0x69, 0xa5, 0x9c, 0x16, + 0x2d, 0x1c, 0x51, 0x03, 0x86, 0x79, 0x1b, 0x00, 0x1f, 0x4f, 0xbe, 0xac, + 0x77, 0x2e, 0x1f, 0xb0, 0xd2, 0x59, 0x29, 0x2f, 0x55, 0xf3, 0xc7, 0xf3, + 0x8a, 0x59, 0x0a, 0x15, 0xd9, 0xa3, 0x3e, 0x56, 0x38, 0xeb, 0xce, 0x33, + 0xb1, 0x1d, 0x0f, 0xae, 0xb9, 0xf9, 0xfe, 0x36, 0xed, 0x87, 0x08, 0xd1, + 0x4b, 0xa9, 0x5a, 0x4a, 0x9a, 0x34, 0x72, 0x64, 0x12, 0x39, 0x08, 0x55, + 0x50, 0x90, 0xcc, 0x46, 0x72, 0x31, 0xdc, 0xe4, 0xfd, 0xb7, 0xd5, 0x6e, + 0xe9, 0x6a, 0x8a, 0x86, 0x71, 0x3d, 0x43, 0xc6, 0x50, 0xe7, 0x28, 0xad, + 0xe6, 0x18, 0x3b, 0xe4, 0x76, 0xd5, 0x9a, 0xe9, 0xc5, 0xd5, 0xfc, 0x25, + 0x7b, 0xaa, 0xa4, 0xb1, 0x50, 0xd1, 0x8a, 0x6a, 0x92, 0xbe, 0x0c, 0xf3, + 0xd3, 0x7f, 0x35, 0x53, 0x1b, 0x18, 0xcb, 0x6e, 0x0e, 0xe7, 0x7d, 0x57, + 0xef, 0xcd, 0x47, 0x2a, 0xc2, 0xeb, 0x70, 0x4a, 0x8a, 0xc9, 0xc0, 0x73, + 0x18, 0x88, 0x83, 0x1b, 0x13, 0xb8, 0x66, 0x27, 0x05, 0xba, 0xe7, 0x1b, + 0x7b, 0xeb, 0x55, 0x49, 0xc5, 0x49, 0x8e, 0x64, 0x53, 0x9f, 0xe2, 0x14, + 0xa0, 0xa2, 0x08, 0xa9, 0xcb, 0x1f, 0x96, 0x42, 0x77, 0x7d, 0x03, 0x1c, + 0x46, 0x13, 0xba, 0x05, 0xe5, 0x38, 0x6f, 0x63, 0xa8, 0x2f, 0xb5, 0x75, + 0x35, 0x12, 0xc5, 0x4d, 0x24, 0xb9, 0x8a, 0x8d, 0x4c, 0x70, 0x28, 0x18, + 0xe5, 0x19, 0xcb, 0x1f, 0xbe, 0x75, 0xf6, 0xcb, 0x53, 0x4f, 0x9a, 0x95, + 0xaf, 0x8d, 0xa7, 0xfe, 0x51, 0xf0, 0xdb, 0x9b, 0x74, 0x3b, 0x60, 0xfe, + 0x3a, 0x7e, 0x75, 0x70, 0x8b, 0x5d, 0x80, 0xd0, 0x5d, 0xc2, 0xf3, 0x58, + 0xf2, 0x54, 0x3c, 0x54, 0x94, 0xf0, 0x42, 0xe4, 0x23, 0x34, 0x29, 0xcb, + 0x80, 0x31, 0xb7, 0xea, 0x33, 0x9f, 0x53, 0xa3, 0x38, 0x32, 0xde, 0xd7, + 0xab, 0xb9, 0xa5, 0x32, 0xc3, 0x02, 0x4a, 0x59, 0xa4, 0xa8, 0x99, 0xb9, + 0x42, 0x80, 0x32, 0x49, 0x6e, 0xc0, 0x01, 0x9d, 0x22, 0x9b, 0x9a, 0x03, + 0x2c, 0x7c, 0xbe, 0x2c, 0x64, 0x61, 0xb2, 0x71, 0xae, 0xed, 0xeb, 0x22, + 0x51, 0x38, 0x35, 0x02, 0x2a, 0x76, 0x50, 0x65, 0xc1, 0xce, 0x7b, 0xe0, + 0xe9, 0xff, 0x00, 0x1a, 0xf4, 0x35, 0x44, 0x6f, 0x71, 0xb9, 0x41, 0x6a, + 0x81, 0x8d, 0x21, 0x47, 0x4f, 0x10, 0xac, 0x52, 0x63, 0x3e, 0x22, 0x8e, + 0xfb, 0xef, 0xff, 0x00, 0x9d, 0x75, 0x55, 0x2f, 0xce, 0xd3, 0xdb, 0x6f, + 0x10, 0x9f, 0xe7, 0x4c, 0xc2, 0x19, 0x71, 0xdb, 0x6d, 0x57, 0xef, 0x01, + 0x2b, 0x44, 0x2b, 0x02, 0x88, 0xd1, 0x00, 0x00, 0x67, 0x60, 0x31, 0xab, + 0x7d, 0xb6, 0xc1, 0x33, 0xf0, 0x55, 0x35, 0x54, 0x15, 0x10, 0x34, 0x09, + 0x2b, 0x2e, 0x43, 0x79, 0xa3, 0x97, 0x63, 0xb8, 0xed, 0x9c, 0x9c, 0x6a, + 0xf1, 0xc5, 0x46, 0x5c, 0x7b, 0x1d, 0xa7, 0x95, 0x4a, 0x8e, 0xf8, 0x46, + 0x68, 0xad, 0xd7, 0x7a, 0xba, 0x29, 0xc1, 0x8a, 0x69, 0x64, 0x0a, 0xac, + 0x47, 0x94, 0x6f, 0xbe, 0x47, 0xa6, 0x33, 0xa6, 0x5c, 0x46, 0x69, 0xa4, + 0xe1, 0x44, 0x34, 0xd3, 0x2c, 0x81, 0x18, 0xf8, 0x43, 0x3b, 0xa3, 0x07, + 0x38, 0x20, 0xf7, 0xdb, 0x51, 0x5a, 0xad, 0x54, 0x55, 0xf7, 0xca, 0x05, + 0x59, 0x98, 0x45, 0x71, 0x82, 0x58, 0xe5, 0x27, 0xcd, 0xcb, 0x2a, 0x0f, + 0x37, 0xa6, 0xc4, 0xe8, 0x8e, 0x17, 0x84, 0x53, 0xd4, 0x49, 0x62, 0xbb, + 0x27, 0xf3, 0x28, 0x5d, 0xbc, 0x0c, 0x9d, 0x9f, 0x27, 0x61, 0x8f, 0x40, + 0x0e, 0x7f, 0x3a, 0xd2, 0x6e, 0x14, 0xdf, 0x28, 0xe6, 0x17, 0xf1, 0x0c, + 0xb5, 0xb0, 0xb7, 0x2c, 0x48, 0xe7, 0xae, 0x09, 0x6c, 0x74, 0x3d, 0x36, + 0xcf, 0x5d, 0x4d, 0x6e, 0x9e, 0xa2, 0x19, 0x62, 0x7a, 0x57, 0xa7, 0x12, + 0xab, 0x32, 0x13, 0x2e, 0xea, 0x33, 0xb8, 0x23, 0xd4, 0xed, 0xfa, 0x6a, + 0x5b, 0x85, 0x12, 0x10, 0xd5, 0x10, 0x85, 0x2f, 0x22, 0x91, 0xb7, 0xd0, + 0x33, 0x90, 0x32, 0x7d, 0xb1, 0xd3, 0x40, 0x5c, 0xe6, 0x5b, 0x6d, 0xbd, + 0xcc, 0xcc, 0x5d, 0x8a, 0x8e, 0xa3, 0x04, 0xb3, 0x0e, 0x9d, 0xff, 0x00, + 0xec, 0x1d, 0x42, 0x9a, 0x38, 0x5b, 0xcd, 0x64, 0xcd, 0x53, 0x45, 0x3d, + 0x5d, 0x05, 0x2b, 0x2b, 0x9e, 0x79, 0x9a, 0x52, 0xc4, 0x80, 0x77, 0xf0, + 0xd4, 0xec, 0x09, 0xf4, 0xd1, 0x34, 0x86, 0x2a, 0xb9, 0x44, 0x76, 0xf9, + 0x1a, 0xa0, 0xf4, 0x79, 0x64, 0x3c, 0xa4, 0xfa, 0x8e, 0xfa, 0xa2, 0xba, + 0xc0, 0x55, 0xe5, 0x91, 0xd9, 0xe5, 0x46, 0xc2, 0xa9, 0x3b, 0x0f, 0xfc, + 0x6a, 0xff, 0x00, 0xf0, 0xd6, 0x84, 0xdd, 0xd5, 0x56, 0x3a, 0xa2, 0xaf, + 0x21, 0x28, 0x60, 0x43, 0x86, 0x60, 0xa0, 0x16, 0x6c, 0xfa, 0x6a, 0x15, + 0xb9, 0x2e, 0xce, 0xe5, 0x33, 0xd1, 0xd6, 0x24, 0x63, 0xc3, 0x25, 0x18, + 0x1e, 0x45, 0xf6, 0xd3, 0xca, 0x9a, 0xab, 0x65, 0x4c, 0x82, 0xb2, 0xad, + 0xa1, 0x33, 0x3e, 0x09, 0x76, 0x18, 0x03, 0x6e, 0xde, 0x9a, 0x1a, 0xba, + 0xc6, 0xf6, 0xab, 0x84, 0x8f, 0x24, 0x0d, 0x0b, 0x83, 0x82, 0xa7, 0x32, + 0x72, 0x13, 0xd0, 0x64, 0x7a, 0xe8, 0x1a, 0x8a, 0x55, 0xaa, 0xb8, 0xf2, + 0xbd, 0x4c, 0x06, 0x38, 0xcf, 0x21, 0x91, 0xdb, 0x93, 0x1b, 0x03, 0xf4, + 0x9e, 0xdd, 0xb5, 0x06, 0x45, 0x46, 0x43, 0xca, 0xba, 0x3b, 0x65, 0x4d, + 0x2c, 0x75, 0x10, 0x49, 0x2b, 0x52, 0xf2, 0x66, 0x47, 0x91, 0x79, 0x15, + 0xcf, 0xa0, 0xfb, 0x7a, 0xe9, 0x1c, 0x72, 0x5a, 0xab, 0xae, 0x93, 0xba, + 0x54, 0xcb, 0x41, 0x16, 0x15, 0x12, 0x3c, 0x1e, 0x46, 0x41, 0xeb, 0x8f, + 0x5d, 0x73, 0x0d, 0x28, 0xab, 0xaf, 0x11, 0x52, 0xd4, 0x07, 0xa5, 0x89, + 0x72, 0xf2, 0x67, 0xcb, 0xdb, 0x23, 0xdb, 0xed, 0xa9, 0xab, 0x22, 0xa4, + 0x15, 0x5f, 0xee, 0x6f, 0xe2, 0xc6, 0x83, 0x99, 0xa4, 0xe4, 0xcf, 0x39, + 0xe9, 0xb6, 0xfd, 0x34, 0x05, 0xec, 0x3f, 0x55, 0xc0, 0x22, 0x96, 0x49, + 0xf3, 0x13, 0x72, 0xb9, 0xe5, 0x4f, 0x10, 0x6c, 0xb9, 0xe9, 0x9c, 0x64, + 0xe3, 0x5f, 0x09, 0xa0, 0x69, 0xd7, 0xc4, 0x12, 0x3c, 0x6d, 0xbb, 0x3f, + 0x26, 0x06, 0x75, 0xd5, 0x0c, 0x2a, 0xb0, 0x99, 0x0a, 0x2e, 0x7a, 0xf3, + 0xb8, 0xc9, 0x1e, 0x9a, 0x1e, 0xa6, 0xad, 0x01, 0x6c, 0xc8, 0xc4, 0x11, + 0x82, 0x54, 0x72, 0x92, 0x7d, 0xb5, 0x2c, 0x24, 0x88, 0xee, 0x09, 0x4d, + 0x15, 0x63, 0x44, 0x2a, 0x92, 0x6a, 0x79, 0x14, 0x81, 0xcb, 0xb0, 0x55, + 0x3d, 0x06, 0x7a, 0x9c, 0x6a, 0x4a, 0x6b, 0x62, 0xcc, 0xac, 0xf3, 0x7c, + 0xa1, 0x87, 0x62, 0x25, 0x73, 0xbe, 0xdd, 0x40, 0xd2, 0x72, 0x61, 0x59, + 0x39, 0xa4, 0x2c, 0xa8, 0x0e, 0x48, 0x51, 0x9d, 0x33, 0xa2, 0x96, 0x81, + 0xdb, 0xe6, 0xe0, 0x89, 0x88, 0x56, 0xe5, 0xfa, 0x82, 0x9f, 0xbe, 0xfa, + 0x96, 0x48, 0x47, 0x90, 0xca, 0xa0, 0x5e, 0x1c, 0xc3, 0x22, 0x98, 0x90, + 0xe5, 0x42, 0x0f, 0x20, 0x1f, 0xf2, 0xfe, 0xa7, 0xf5, 0xd4, 0x10, 0xab, + 0x46, 0x85, 0xd8, 0x0f, 0x31, 0xd8, 0x93, 0xa6, 0x72, 0xd5, 0x17, 0x89, + 0x56, 0x33, 0x85, 0x23, 0x38, 0x6d, 0xf1, 0x9d, 0x05, 0x51, 0x19, 0x78, + 0xb9, 0x24, 0x95, 0x37, 0x39, 0xc8, 0x19, 0x00, 0x7a, 0x7d, 0xf4, 0x36, + 0x32, 0x8e, 0x23, 0xe4, 0x2f, 0x97, 0x78, 0xbc, 0x6c, 0xf9, 0x15, 0xba, + 0x0f, 0x7f, 0xfa, 0xe8, 0x5a, 0x95, 0x8d, 0xe7, 0x0d, 0x53, 0x52, 0xc9, + 0x17, 0x49, 0x18, 0x30, 0x23, 0x3e, 0xc3, 0xbe, 0x8e, 0x8e, 0xaa, 0x8a, + 0x9c, 0x32, 0x1c, 0x29, 0xc7, 0x95, 0x89, 0xce, 0x80, 0xaa, 0xf0, 0x1a, + 0x21, 0x15, 0x35, 0x32, 0x7f, 0x88, 0x1e, 0x5c, 0x67, 0xdf, 0x3a, 0x89, + 0x83, 0x41, 0x31, 0x44, 0x21, 0x85, 0xa4, 0x86, 0x6c, 0x43, 0x8f, 0x2b, + 0x14, 0xc3, 0x63, 0xfc, 0xb5, 0x09, 0xab, 0xa4, 0x40, 0xaf, 0x83, 0x2c, + 0xa0, 0x7d, 0x4c, 0x37, 0xd0, 0x71, 0x53, 0x4d, 0x22, 0xa4, 0x50, 0xc1, + 0x34, 0xf3, 0x31, 0xc6, 0x22, 0x56, 0x60, 0xb8, 0xfc, 0x6f, 0xab, 0x5f, + 0x0b, 0xfc, 0x32, 0xe3, 0x2e, 0x24, 0x9a, 0x37, 0x86, 0xc1, 0x58, 0x60, + 0xe5, 0x00, 0xcb, 0x51, 0x88, 0x50, 0x6e, 0x33, 0xf5, 0x60, 0x9c, 0x0f, + 0x4c, 0xea, 0xec, 0x85, 0x62, 0x6b, 0xc4, 0xb2, 0x6c, 0x94, 0xa4, 0xb2, + 0x9c, 0x00, 0xfd, 0x0e, 0x3d, 0x35, 0xf2, 0xa2, 0xae, 0xaa, 0xb9, 0x07, + 0x8a, 0x90, 0xaf, 0x37, 0xd3, 0x91, 0xb6, 0x75, 0xb3, 0x56, 0x7c, 0x06, + 0x96, 0xcf, 0x2c, 0xd5, 0x95, 0xd7, 0x75, 0x34, 0x71, 0x6e, 0x9e, 0x04, + 0x21, 0x5a, 0x4f, 0xc9, 0x27, 0x97, 0xf7, 0xd5, 0x83, 0x83, 0x57, 0x86, + 0x78, 0x76, 0xa5, 0x0f, 0xf0, 0x2a, 0x22, 0x09, 0x21, 0xe6, 0x91, 0x3c, + 0x49, 0x37, 0xea, 0x43, 0x36, 0x71, 0xf6, 0xd6, 0x0c, 0xdf, 0x90, 0xc5, + 0x87, 0x26, 0xc9, 0xf0, 0x64, 0xcb, 0xac, 0xc7, 0x89, 0xd4, 0x8c, 0x9b, + 0xe1, 0xf7, 0xc2, 0x4e, 0x30, 0xe2, 0xdc, 0x55, 0x4d, 0x1c, 0x94, 0x16, + 0xdf, 0xe9, 0xa9, 0xa8, 0x04, 0x07, 0x1f, 0xf2, 0xa9, 0xc1, 0x23, 0x7e, + 0xba, 0xde, 0xf8, 0x1f, 0xe1, 0x0f, 0x06, 0x70, 0xd5, 0x10, 0x7a, 0x8a, + 0x75, 0xbb, 0x5c, 0x39, 0x73, 0x24, 0xd5, 0x03, 0x2a, 0x0e, 0x07, 0xd2, + 0x9d, 0x06, 0xfe, 0xb9, 0x3e, 0xfa, 0xb7, 0xdc, 0x78, 0xc2, 0x8e, 0x9e, + 0x8e, 0x19, 0x62, 0x41, 0x3f, 0x38, 0xda, 0x3e, 0x81, 0x75, 0xd5, 0x97, + 0x88, 0xa3, 0xba, 0xb8, 0x8e, 0x4a, 0x55, 0x87, 0x23, 0x20, 0x0d, 0xc7, + 0xeb, 0xeb, 0xab, 0x7a, 0xcd, 0x33, 0x96, 0xc8, 0xcd, 0x36, 0xcc, 0xdf, + 0xca, 0xc7, 0x3e, 0x99, 0xe7, 0x2f, 0xff, 0x00, 0x88, 0x6b, 0xab, 0x6e, + 0xf5, 0x17, 0xbb, 0xd5, 0xc2, 0x9a, 0xd3, 0x6e, 0xad, 0xac, 0x92, 0x58, + 0x9b, 0x9c, 0x3c, 0x92, 0xa1, 0x72, 0xc4, 0x85, 0xe8, 0x36, 0x23, 0xaf, + 0xae, 0x99, 0x70, 0xef, 0x03, 0xc1, 0x59, 0x5d, 0xc5, 0x31, 0x59, 0xe9, + 0x95, 0xe9, 0xe0, 0x81, 0xe9, 0xe9, 0xcc, 0xad, 0xb9, 0xc9, 0x05, 0x7e, + 0xec, 0x40, 0xeb, 0x9d, 0x69, 0x1c, 0x5b, 0x15, 0xba, 0x4a, 0xae, 0x1d, + 0x92, 0xe7, 0x33, 0x24, 0x51, 0x5b, 0x61, 0xe4, 0xe5, 0x6c, 0xb0, 0x24, + 0x1f, 0xe9, 0xf4, 0x3b, 0x6f, 0xa6, 0x1c, 0x1d, 0x4b, 0x5b, 0x6f, 0xa5, + 0xb9, 0xcf, 0x1c, 0x50, 0x47, 0x4a, 0x19, 0xa6, 0x46, 0x55, 0xda, 0x47, + 0xe5, 0x3c, 0xa7, 0x3d, 0xc0, 0xc6, 0x7e, 0xf8, 0xd3, 0xe7, 0xe1, 0x22, + 0x64, 0xc6, 0x94, 0xa9, 0x1e, 0x53, 0xbd, 0xb3, 0xc2, 0xe6, 0x85, 0xd5, + 0xe3, 0x90, 0x31, 0xf1, 0x50, 0x8f, 0x30, 0xc6, 0xdc, 0xa7, 0xdf, 0x39, + 0xfd, 0x34, 0x34, 0x4b, 0x31, 0x89, 0x62, 0x08, 0xb1, 0x21, 0x20, 0x10, + 0x06, 0xe7, 0xef, 0xa2, 0xae, 0xd3, 0x34, 0xb7, 0x09, 0x6a, 0x27, 0x72, + 0xf2, 0xca, 0xd9, 0x77, 0x3d, 0xcf, 0x7d, 0x45, 0x16, 0x19, 0x58, 0x91, + 0xb6, 0x36, 0xd1, 0xc5, 0xd1, 0x81, 0xf6, 0x03, 0x5f, 0x01, 0x77, 0x66, + 0x55, 0xc1, 0x52, 0x47, 0xdf, 0x56, 0x9e, 0x1f, 0x88, 0xa5, 0x8e, 0x33, + 0x08, 0x01, 0xca, 0xe4, 0xae, 0x92, 0x34, 0x6a, 0xd1, 0xb6, 0x7e, 0xc3, + 0x5a, 0x25, 0xa2, 0xd9, 0x1c, 0x74, 0x34, 0x50, 0xca, 0xeb, 0x1a, 0xb6, + 0x09, 0x94, 0x9c, 0x05, 0x07, 0xa9, 0xfd, 0x33, 0xaa, 0x84, 0xb9, 0x6c, + 0xa0, 0xeb, 0x35, 0xda, 0xe9, 0x07, 0x04, 0x09, 0x23, 0xb7, 0xc3, 0x1c, + 0x36, 0xe5, 0x92, 0x45, 0x9f, 0x00, 0x18, 0xe6, 0x66, 0xc2, 0xc9, 0xbf, + 0xd4, 0xdd, 0x40, 0x03, 0xa0, 0xce, 0xdd, 0xf5, 0x47, 0xaa, 0x7b, 0x95, + 0x65, 0xc9, 0xaa, 0x6b, 0x6a, 0x1a, 0x67, 0x93, 0x76, 0x9b, 0x3b, 0x9d, + 0xf3, 0xd7, 0xae, 0x72, 0x35, 0x0d, 0xd2, 0x6a, 0xba, 0x9a, 0x99, 0x16, + 0x33, 0x53, 0x1d, 0x03, 0x4a, 0x3e, 0x5e, 0x9e, 0x59, 0x08, 0xe6, 0x03, + 0xa3, 0x15, 0xf5, 0xc6, 0xbe, 0x73, 0x4d, 0x44, 0xfc, 0xa8, 0x43, 0xc4, + 0x40, 0x62, 0x31, 0xea, 0x33, 0xae, 0x7d, 0xb9, 0xab, 0x7d, 0x92, 0xdf, + 0xb1, 0xef, 0xfe, 0xab, 0xe1, 0xdb, 0x35, 0x1c, 0xd5, 0xf7, 0xdb, 0x3c, + 0x97, 0xab, 0xc8, 0x46, 0x58, 0x04, 0xa5, 0x4c, 0x4c, 0x36, 0xf3, 0x3e, + 0x73, 0xb8, 0xf4, 0x00, 0x1d, 0xf5, 0x93, 0x5d, 0x6a, 0x7f, 0x8a, 0xdc, + 0x26, 0xae, 0x11, 0x47, 0x4d, 0x23, 0x31, 0x2b, 0x14, 0x43, 0x0a, 0x83, + 0x39, 0xc0, 0xd3, 0x5e, 0x2c, 0x91, 0x66, 0xaa, 0x05, 0x0e, 0xeb, 0x93, + 0x8f, 0x63, 0xa4, 0x44, 0xaa, 0xc7, 0x14, 0x7c, 0xc0, 0x78, 0xe7, 0x90, + 0xb1, 0xe8, 0x0f, 0xa1, 0xd7, 0x46, 0x2d, 0xec, 0x49, 0x8f, 0x8c, 0x9b, + 0xec, 0xec, 0x1f, 0x15, 0x73, 0x27, 0x99, 0xb3, 0xe6, 0xcf, 0xae, 0xa2, + 0xaf, 0x44, 0x82, 0x08, 0xc8, 0x60, 0xbc, 0xc7, 0x66, 0xf7, 0xd3, 0x7a, + 0x2b, 0x44, 0xf1, 0xe0, 0xa0, 0x0b, 0x8d, 0xb0, 0x76, 0x24, 0x6b, 0x8b, + 0xe4, 0x3e, 0x15, 0x19, 0xf1, 0xd2, 0x2d, 0xfe, 0xa0, 0x17, 0xbf, 0xae, + 0xab, 0x22, 0xb4, 0x8a, 0x8f, 0x62, 0x4a, 0x47, 0x69, 0x27, 0x45, 0x69, + 0x39, 0x57, 0x1b, 0x9e, 0xde, 0xff, 0x00, 0xdb, 0x47, 0xdc, 0x2a, 0x69, + 0xa3, 0x50, 0xd4, 0xf0, 0xc6, 0x25, 0xe8, 0xdb, 0x6d, 0x9f, 0x4c, 0x69, + 0x13, 0x2b, 0xae, 0x02, 0xbb, 0x04, 0xd8, 0x92, 0x36, 0xfc, 0x68, 0xe6, + 0x81, 0x10, 0x23, 0x40, 0xc4, 0xae, 0x03, 0x12, 0xdd, 0x73, 0xdf, 0xf1, + 0xa5, 0xa4, 0x12, 0x64, 0x31, 0xc9, 0x14, 0x93, 0xe1, 0x93, 0x90, 0x92, + 0x7a, 0x74, 0xfd, 0x35, 0xe8, 0xfa, 0x0e, 0x0d, 0xb3, 0x5b, 0x3e, 0x09, + 0x48, 0x68, 0x96, 0x79, 0xeb, 0xaa, 0x04, 0x15, 0xf5, 0x12, 0x33, 0x79, + 0x49, 0x5d, 0xc8, 0x51, 0x9d, 0x80, 0x42, 0xda, 0xf3, 0xfa, 0xc2, 0x12, + 0x56, 0x2e, 0x42, 0xb8, 0x00, 0xa9, 0x03, 0xa8, 0x3b, 0xeb, 0xd0, 0xdc, + 0x0f, 0xf1, 0x04, 0x55, 0xf0, 0x5d, 0xbe, 0xd0, 0x91, 0xc4, 0xd3, 0x52, + 0xd3, 0x0a, 0x69, 0x55, 0x86, 0x4e, 0x00, 0xc0, 0x3f, 0x91, 0xa5, 0x67, + 0xda, 0xaa, 0x52, 0x74, 0x90, 0x37, 0xcd, 0x99, 0xa8, 0x13, 0xc5, 0x43, + 0x25, 0xc5, 0x1f, 0x96, 0x7a, 0x3a, 0x91, 0x32, 0xa9, 0x18, 0xf1, 0x14, + 0x9e, 0x57, 0xc0, 0xef, 0xe6, 0x03, 0xf5, 0x1a, 0x6d, 0x7f, 0x78, 0xe4, + 0xbd, 0x5a, 0xaa, 0xea, 0x52, 0x58, 0x52, 0x5a, 0x57, 0xdc, 0x1f, 0x36, + 0x7a, 0x8c, 0x8f, 0x61, 0x8d, 0x7e, 0xa5, 0xa3, 0x86, 0xa0, 0x5e, 0xad, + 0x0d, 0x21, 0x5a, 0xa8, 0x49, 0x11, 0x87, 0xd8, 0x3c, 0x6c, 0x83, 0x60, + 0x3b, 0x79, 0x94, 0x7e, 0xba, 0xe6, 0xae, 0x2a, 0x9b, 0x9d, 0x8f, 0x87, + 0x1c, 0x6f, 0x50, 0xb2, 0xc7, 0x18, 0x3f, 0xf2, 0x82, 0x57, 0xfb, 0x0d, + 0x74, 0x62, 0xd4, 0x95, 0xa3, 0xac, 0xb9, 0x42, 0xca, 0x8a, 0xb1, 0x00, + 0x96, 0x9e, 0x59, 0xe1, 0x67, 0x8e, 0x55, 0x87, 0x9b, 0x18, 0x56, 0x52, + 0x09, 0xe6, 0x23, 0xb9, 0xc9, 0xc9, 0xf5, 0xfc, 0x69, 0x1d, 0xcd, 0xa2, + 0x91, 0xe3, 0x50, 0xa2, 0x79, 0x64, 0x03, 0x2f, 0xfd, 0x38, 0xec, 0x71, + 0xdb, 0xed, 0xa7, 0xbc, 0x45, 0x22, 0x7f, 0x15, 0x91, 0x04, 0x3c, 0xe9, + 0x2c, 0x2a, 0x55, 0x13, 0x62, 0x58, 0x33, 0x63, 0x3a, 0x4d, 0x67, 0xa7, + 0x96, 0x47, 0x96, 0xb2, 0xa6, 0x3c, 0xb2, 0x36, 0xc9, 0xd3, 0x18, 0xd8, + 0xea, 0xc6, 0x51, 0x2d, 0xaa, 0xd5, 0x6d, 0xa4, 0xa9, 0xac, 0x32, 0xc5, + 0x0c, 0xf2, 0x54, 0x29, 0x4f, 0x3a, 0x6d, 0x19, 0xc7, 0x51, 0xff, 0x00, + 0x7d, 0xf4, 0xf3, 0x83, 0xea, 0xa5, 0xb0, 0x42, 0x25, 0xa4, 0x8a, 0x9a, + 0x82, 0x49, 0xa6, 0x65, 0x4a, 0x95, 0x8c, 0x39, 0x8e, 0x23, 0xec, 0x48, + 0xdc, 0x91, 0xb7, 0xb6, 0x96, 0x4c, 0x4c, 0x15, 0x12, 0x7c, 0xc3, 0x6f, + 0x29, 0x57, 0xe5, 0x4d, 0xd8, 0x92, 0x3b, 0x0d, 0x77, 0x71, 0xa9, 0x69, + 0x53, 0xe4, 0x60, 0xa6, 0x8e, 0x06, 0x95, 0x46, 0x65, 0x78, 0xc6, 0xeb, + 0xd3, 0x3e, 0xd8, 0x07, 0x19, 0xf5, 0x3a, 0x00, 0x66, 0x83, 0xab, 0x6a, + 0xea, 0xe6, 0x49, 0xab, 0x2e, 0x17, 0x96, 0xf0, 0x6a, 0x7c, 0xd1, 0x45, + 0x1b, 0x79, 0x80, 0x3b, 0x82, 0xde, 0xff, 0x00, 0x6d, 0x2d, 0x86, 0x4a, + 0x68, 0x22, 0x96, 0x78, 0xe1, 0x79, 0xcb, 0x00, 0xaa, 0xd2, 0x80, 0x47, + 0x36, 0x3b, 0x69, 0xa5, 0x45, 0xbe, 0x8a, 0x92, 0xdc, 0xf5, 0x4c, 0xaf, + 0x20, 0x50, 0xab, 0x17, 0x3a, 0xed, 0x81, 0xdc, 0x8f, 0x43, 0xdb, 0x50, + 0x53, 0x1f, 0x98, 0xa8, 0x35, 0x95, 0xe2, 0x38, 0x29, 0x97, 0xc8, 0x39, + 0x13, 0x00, 0x11, 0xd8, 0x0f, 0xc6, 0xa0, 0x6a, 0x07, 0x34, 0x90, 0x23, + 0x50, 0xc3, 0x0b, 0xf2, 0xa3, 0xc8, 0x39, 0x9f, 0x19, 0x00, 0x8f, 0x4f, + 0xfb, 0xf4, 0xd1, 0x31, 0x40, 0xb0, 0xc8, 0x20, 0xf1, 0x02, 0x43, 0x93, + 0xcc, 0x54, 0xee, 0xc3, 0x4b, 0x6b, 0xeb, 0x5a, 0x79, 0x84, 0x31, 0x07, + 0x48, 0xf9, 0x89, 0x0b, 0xcc, 0x73, 0x8f, 0xf2, 0xd4, 0xad, 0x1c, 0xd1, + 0x22, 0x91, 0x84, 0xc9, 0xca, 0x03, 0x92, 0x70, 0x46, 0x7a, 0xe7, 0x50, + 0x60, 0x65, 0x53, 0xc7, 0x0a, 0x88, 0xd2, 0x00, 0x0f, 0x31, 0x06, 0x59, + 0x18, 0x1e, 0x6f, 0x4c, 0x7a, 0x68, 0x1a, 0xaa, 0xd6, 0xe5, 0x68, 0x95, + 0x23, 0x04, 0x0c, 0x73, 0x05, 0xc8, 0xd7, 0x35, 0xd2, 0xb3, 0xc7, 0x12, + 0x31, 0xf3, 0x31, 0x00, 0x9e, 0x60, 0x77, 0xc7, 0xf7, 0xd0, 0x29, 0x04, + 0x22, 0xb2, 0x40, 0xc2, 0x52, 0x63, 0xe8, 0x5b, 0x61, 0x9d, 0x2c, 0x84, + 0x90, 0x55, 0x2a, 0x23, 0x09, 0xa7, 0x63, 0xd8, 0xaa, 0x46, 0x30, 0x75, + 0x0c, 0x73, 0xc5, 0x1c, 0x92, 0xba, 0x29, 0x54, 0x39, 0x61, 0x9f, 0x5d, + 0x14, 0x65, 0xa5, 0xa6, 0x4e, 0x6a, 0x94, 0x66, 0x69, 0x73, 0xc9, 0xe5, + 0xc6, 0x4f, 0xa0, 0xd4, 0x74, 0x34, 0x93, 0x5c, 0xaa, 0x9e, 0x38, 0x41, + 0x41, 0x18, 0x0c, 0xf1, 0xb0, 0xc1, 0x00, 0xf6, 0xd5, 0x49, 0xa4, 0xad, + 0x82, 0xe7, 0x1c, 0x6a, 0xe4, 0xcf, 0xd1, 0xd5, 0x49, 0x55, 0x12, 0x32, + 0xe5, 0xb3, 0x91, 0x8e, 0x83, 0x6d, 0x3b, 0xe1, 0xde, 0x1c, 0xbc, 0x5c, + 0xe0, 0x6a, 0xb5, 0x10, 0xd2, 0x53, 0x09, 0x39, 0x3c, 0x6a, 0x89, 0x02, + 0x26, 0x7d, 0x89, 0xdd, 0xbe, 0xc0, 0x1d, 0x3d, 0xb0, 0x70, 0xd5, 0xca, + 0xd2, 0xf4, 0xb7, 0xb6, 0xb3, 0x25, 0x4d, 0x1c, 0x45, 0x64, 0xe5, 0x91, + 0x03, 0xa4, 0x9e, 0xc4, 0x67, 0x45, 0xdf, 0xae, 0x54, 0x1c, 0x45, 0xc6, + 0x12, 0xd5, 0xc4, 0xb0, 0x5a, 0xa9, 0x9c, 0x89, 0x24, 0x49, 0x5f, 0x96, + 0x35, 0x7c, 0x00, 0xd8, 0x18, 0xeb, 0xfe, 0x9a, 0xcd, 0x93, 0x54, 0xaa, + 0xa1, 0xd9, 0xcf, 0xcb, 0xac, 0x57, 0x50, 0xe4, 0x9a, 0x5f, 0x86, 0x16, + 0xf3, 0xe1, 0x4d, 0x72, 0xba, 0x99, 0xd1, 0x94, 0xb0, 0x92, 0x05, 0xf2, + 0x6d, 0xd4, 0x02, 0x7a, 0x77, 0xed, 0xa6, 0x74, 0x1f, 0x0d, 0x78, 0x7d, + 0xee, 0x34, 0xd5, 0x74, 0xf7, 0x4b, 0x8d, 0x55, 0x34, 0x88, 0x3f, 0x92, + 0xfb, 0x3b, 0x82, 0x32, 0x14, 0x1c, 0xec, 0x0e, 0xdb, 0xe3, 0x56, 0xfe, + 0x16, 0xbf, 0x70, 0xb5, 0x25, 0xa5, 0xe9, 0x2b, 0x6a, 0xad, 0xd3, 0xc3, + 0x12, 0x2a, 0x8f, 0x02, 0x42, 0x43, 0x9e, 0xcd, 0x82, 0x3e, 0xbd, 0xce, + 0xfe, 0xc3, 0x57, 0xbb, 0x05, 0x77, 0x0a, 0x47, 0x6d, 0x94, 0xda, 0xea, + 0xe9, 0xa0, 0xf0, 0x51, 0x25, 0xa9, 0x91, 0x9b, 0x1e, 0x18, 0x60, 0x70, + 0x0b, 0x7e, 0x0e, 0xda, 0xe6, 0xfc, 0x3a, 0xb9, 0xbb, 0x79, 0x69, 0x19, + 0xbe, 0x7c, 0x8f, 0xfb, 0xcc, 0xf6, 0x86, 0xeb, 0x5d, 0xc1, 0x96, 0xd6, + 0xb2, 0xd1, 0x5a, 0x85, 0xa2, 0x16, 0x91, 0x8b, 0x18, 0xe2, 0xcb, 0x36, + 0x7f, 0xab, 0x9f, 0xd7, 0x6d, 0x36, 0xb4, 0x71, 0xdc, 0xb4, 0xb6, 0xf5, + 0x86, 0xae, 0xe3, 0x1a, 0x73, 0x1c, 0xc1, 0x2b, 0xb7, 0x9a, 0x45, 0x3d, + 0x9b, 0xdc, 0x7f, 0x96, 0x9d, 0xdf, 0x6f, 0x56, 0x2b, 0xa5, 0xba, 0xa2, + 0x95, 0x6a, 0xad, 0xd3, 0xa7, 0x86, 0x79, 0xa5, 0x9a, 0x50, 0x30, 0x7d, + 0x37, 0x1f, 0xbe, 0xb1, 0x7b, 0x8d, 0xb2, 0xed, 0x2c, 0x32, 0x7c, 0x9c, + 0x74, 0xf7, 0x5a, 0x26, 0xcb, 0x2c, 0x51, 0x37, 0x34, 0x91, 0x2e, 0x3a, + 0xff, 0x00, 0xd7, 0x57, 0x9b, 0x0e, 0x5d, 0xb4, 0xa7, 0x7f, 0xf6, 0x23, + 0x24, 0xa7, 0xea, 0x56, 0x6b, 0xd7, 0x3e, 0x2d, 0x9e, 0xa2, 0xdf, 0xe0, + 0x0a, 0xc8, 0xda, 0x26, 0x05, 0x64, 0xca, 0x87, 0x2f, 0xfa, 0xf4, 0xd5, + 0x2a, 0xed, 0x0c, 0x33, 0x54, 0x43, 0x83, 0xf2, 0xf0, 0x31, 0x1e, 0x33, + 0x67, 0x65, 0x4e, 0xbf, 0xae, 0x91, 0x70, 0xec, 0xb1, 0x41, 0xc2, 0x38, + 0x86, 0x36, 0x9e, 0x56, 0x25, 0xe3, 0x32, 0x3f, 0xd0, 0x17, 0x66, 0x5c, + 0xe3, 0x1d, 0xc6, 0xdd, 0x76, 0xd2, 0xda, 0xaa, 0x9a, 0x8b, 0xbd, 0x05, + 0x44, 0xe6, 0xb2, 0x8a, 0x0a, 0x78, 0x17, 0x95, 0x95, 0xe7, 0x0a, 0x5b, + 0xff, 0x00, 0x88, 0xfd, 0xb5, 0xcc, 0x78, 0x35, 0x19, 0x66, 0xb7, 0xc9, + 0xb4, 0x26, 0xa6, 0xfb, 0x1b, 0xde, 0x78, 0xe2, 0x82, 0x0b, 0xc8, 0x86, + 0x82, 0x88, 0x55, 0x51, 0x53, 0xa2, 0xa6, 0x0c, 0xe4, 0x07, 0x20, 0x63, + 0x9b, 0x38, 0xce, 0xfa, 0xd1, 0x3e, 0x1c, 0x71, 0xfd, 0x8a, 0xf0, 0x82, + 0xdb, 0x4d, 0x4b, 0xfc, 0x3e, 0xbf, 0x97, 0x22, 0x26, 0x3c, 0xdc, 0xe4, + 0x76, 0x56, 0xdb, 0x3a, 0xc7, 0xed, 0x2d, 0xc2, 0xd4, 0x09, 0x29, 0x96, + 0xd8, 0xd7, 0x9a, 0x9c, 0x8d, 0x84, 0xf8, 0xa7, 0x55, 0xc7, 0xa8, 0x1b, + 0x9d, 0xff, 0x00, 0xbe, 0xb4, 0xbe, 0x09, 0x3c, 0x33, 0x74, 0x86, 0x2a, + 0x9a, 0x6b, 0x5d, 0x1d, 0x2d, 0x64, 0x78, 0x25, 0x15, 0x07, 0x3a, 0x9f, + 0x5c, 0xeb, 0xa7, 0x87, 0x0c, 0x31, 0x4a, 0xe3, 0x15, 0x63, 0x21, 0x2d, + 0xa2, 0x7e, 0x28, 0x8e, 0xe5, 0xc5, 0x1c, 0x5f, 0x6e, 0xa6, 0xb5, 0xd3, + 0x93, 0x53, 0x6d, 0xb7, 0xc4, 0x31, 0x33, 0x72, 0xc6, 0x11, 0x54, 0x67, + 0x27, 0x7d, 0x89, 0x23, 0x57, 0x2e, 0x20, 0xe2, 0x0b, 0x77, 0x0f, 0x70, + 0xfd, 0x3d, 0x0c, 0xf5, 0x46, 0x09, 0x2a, 0x19, 0x11, 0xe4, 0x84, 0x11, + 0xcb, 0xd8, 0xe0, 0x7a, 0x76, 0xfb, 0x0d, 0x0d, 0x5d, 0x2d, 0x55, 0x15, + 0xae, 0x29, 0x2d, 0xf0, 0x4e, 0x9e, 0x2c, 0x71, 0x89, 0x66, 0xa7, 0x5e, + 0x69, 0x47, 0x97, 0xb0, 0xd5, 0x16, 0xe1, 0x79, 0xe1, 0x0b, 0x4d, 0xfa, + 0x14, 0xe2, 0x7b, 0xb4, 0xb5, 0xb2, 0x73, 0xf3, 0xd4, 0x52, 0xcf, 0x91, + 0x27, 0x7c, 0x0f, 0x2f, 0xbf, 0x6f, 0xdb, 0x5d, 0x79, 0x79, 0xb3, 0xa7, + 0x2f, 0x25, 0x66, 0x3d, 0x78, 0x8e, 0x4a, 0x5e, 0x21, 0xae, 0x81, 0xd5, + 0xd7, 0xc3, 0x99, 0x94, 0x12, 0x36, 0x23, 0x27, 0x1f, 0xb0, 0xd7, 0x70, + 0x03, 0xcb, 0x93, 0xdf, 0xb6, 0xb5, 0xcf, 0x8b, 0x5c, 0x05, 0x1d, 0xea, + 0x55, 0xe2, 0xce, 0x0f, 0x6a, 0x6a, 0x9a, 0x49, 0x23, 0x5f, 0x16, 0x92, + 0x39, 0x4f, 0x88, 0x08, 0x00, 0x64, 0x29, 0xea, 0x71, 0x81, 0x81, 0xbe, + 0xda, 0xad, 0xf0, 0xd7, 0xc2, 0xbe, 0x2d, 0xbc, 0xf8, 0x73, 0x4d, 0x6e, + 0x9a, 0xdb, 0x42, 0xcc, 0xb9, 0x9a, 0xa5, 0x08, 0x23, 0x7d, 0xf0, 0xbd, + 0x4e, 0xde, 0xb8, 0x1a, 0x4a, 0x95, 0xba, 0x39, 0xd2, 0xc5, 0x26, 0xf8, + 0x14, 0x70, 0x05, 0x82, 0xe1, 0xc4, 0x5c, 0x45, 0x1d, 0x2d, 0x15, 0x0c, + 0xd5, 0x29, 0x09, 0x12, 0x4d, 0xc8, 0x36, 0x54, 0xf5, 0x3f, 0x73, 0xad, + 0xd6, 0x9e, 0xd8, 0x96, 0x79, 0xde, 0xe5, 0x55, 0x49, 0x1c, 0xb2, 0x52, + 0xa7, 0x96, 0x09, 0xd7, 0x99, 0x79, 0x8f, 0x42, 0x46, 0x7e, 0xfa, 0xbb, + 0x70, 0x57, 0x08, 0xd9, 0x78, 0x2e, 0xcb, 0x15, 0x1d, 0xba, 0x27, 0x79, + 0x1c, 0x8f, 0x1a, 0xa9, 0x90, 0x19, 0x25, 0x6f, 0x56, 0xf6, 0xf6, 0xed, + 0xaa, 0xef, 0x1f, 0xde, 0x2d, 0xe2, 0xad, 0xa9, 0xe0, 0x90, 0x97, 0x4d, + 0xa5, 0x0a, 0x36, 0x2c, 0x3a, 0xfe, 0xfa, 0x1c, 0xf3, 0x96, 0x3c, 0x6e, + 0x9d, 0x36, 0x1c, 0xf1, 0xa8, 0x46, 0xd9, 0x99, 0x71, 0x6d, 0x25, 0xba, + 0xe5, 0x57, 0x25, 0x7d, 0xca, 0x95, 0x00, 0x5c, 0xb3, 0x38, 0x24, 0x01, + 0xeb, 0xb0, 0xd6, 0x7f, 0x76, 0x97, 0x87, 0xaa, 0xea, 0x45, 0x1d, 0x9e, + 0x92, 0x6e, 0x42, 0x30, 0xf3, 0x4a, 0xc5, 0x53, 0xdc, 0x81, 0xe9, 0xad, + 0x1f, 0x8c, 0x2d, 0xb3, 0xdd, 0x2c, 0x2e, 0xd4, 0xde, 0x43, 0x34, 0x80, + 0x04, 0xc1, 0x62, 0xc3, 0x7c, 0xf4, 0xe9, 0xf9, 0xd6, 0x37, 0xc4, 0x2e, + 0x96, 0xfb, 0x83, 0xdb, 0x23, 0xe4, 0x11, 0xc6, 0xc1, 0x26, 0x90, 0x36, + 0x72, 0xdd, 0xf1, 0xfa, 0x63, 0xef, 0x9d, 0x63, 0xd2, 0xc3, 0x2c, 0xe1, + 0xbf, 0x23, 0x62, 0x60, 0x7c, 0xb9, 0xd9, 0x28, 0x00, 0xf0, 0x9a, 0xa6, + 0x6e, 0x40, 0x0a, 0x99, 0xd1, 0x0a, 0xa9, 0x1e, 0xed, 0x9d, 0x05, 0x1f, + 0x0d, 0xd3, 0x47, 0x08, 0x8e, 0x98, 0xb4, 0x91, 0x1c, 0xee, 0xe7, 0x25, + 0x94, 0xee, 0x0e, 0x75, 0x71, 0x86, 0x5a, 0x3a, 0x7b, 0x4b, 0x45, 0x30, + 0x24, 0x39, 0x00, 0xc7, 0x8e, 0xa3, 0x1a, 0xa3, 0x52, 0xde, 0xa4, 0xa7, + 0xbb, 0x56, 0x52, 0xc4, 0x85, 0x69, 0x62, 0x97, 0x08, 0x8c, 0x73, 0x81, + 0xed, 0xae, 0x94, 0x61, 0x51, 0xa1, 0x84, 0xc6, 0x2a, 0xdb, 0x74, 0x52, + 0x34, 0x55, 0x06, 0x58, 0x93, 0x2a, 0xb1, 0x3f, 0x55, 0x3e, 0xc7, 0x55, + 0xcb, 0x8d, 0xce, 0xa2, 0x49, 0xd6, 0x26, 0x91, 0xd4, 0xc9, 0x83, 0x82, + 0x7d, 0x75, 0x76, 0x8c, 0xd0, 0x5c, 0x84, 0x80, 0xb7, 0x84, 0x1c, 0x61, + 0xb0, 0x39, 0x89, 0x3f, 0x6d, 0x4b, 0x6c, 0xf8, 0x71, 0x6b, 0xae, 0xf8, + 0x8d, 0x4f, 0xc2, 0xf4, 0x57, 0x89, 0xbc, 0x27, 0x1e, 0x2c, 0xd5, 0x95, + 0x09, 0x83, 0x12, 0x84, 0x2e, 0xe3, 0x04, 0xf5, 0x18, 0xc6, 0x33, 0xd7, + 0xbe, 0x8d, 0x85, 0x13, 0x3e, 0x93, 0x0a, 0x0f, 0x88, 0x76, 0x03, 0xbf, + 0x7d, 0x4f, 0x02, 0x2b, 0xc0, 0xac, 0x98, 0xc1, 0x03, 0x5c, 0xdd, 0xed, + 0xd3, 0xd4, 0x5c, 0xea, 0x29, 0x52, 0x4f, 0xf7, 0x78, 0xa6, 0x60, 0x24, + 0x3b, 0xe4, 0x02, 0x40, 0xfb, 0xed, 0xa9, 0xa1, 0x85, 0x29, 0x63, 0x31, + 0xa9, 0x2e, 0xa0, 0xec, 0x71, 0x8d, 0x0d, 0x12, 0x71, 0x0a, 0x4a, 0x41, + 0x25, 0x30, 0x63, 0x2c, 0x6c, 0xe8, 0xbb, 0x28, 0x3d, 0x73, 0xd0, 0x7d, + 0xf4, 0xce, 0xdf, 0x5d, 0x4f, 0x68, 0x00, 0x13, 0x3c, 0x15, 0x41, 0xbc, + 0xcc, 0x4e, 0xc0, 0xe0, 0xe3, 0x3e, 0xde, 0xda, 0x06, 0xd9, 0x70, 0xf0, + 0x23, 0x92, 0x15, 0xa7, 0x89, 0xe2, 0x95, 0xd7, 0xc4, 0x56, 0x1b, 0x9e, + 0x52, 0x0e, 0x41, 0xed, 0xd3, 0x4d, 0x2f, 0x37, 0x1a, 0x4b, 0x8f, 0x2b, + 0x55, 0xc4, 0xa5, 0xd1, 0x3c, 0x35, 0x7c, 0x79, 0xf9, 0x47, 0x40, 0x4f, + 0x7c, 0x0d, 0x25, 0xc7, 0xfd, 0xcb, 0x82, 0x51, 0x6d, 0xb5, 0xd6, 0x9b, + 0xb7, 0x10, 0xdb, 0x2e, 0xd0, 0xc4, 0xaf, 0x52, 0x41, 0x8a, 0xa0, 0x83, + 0xb3, 0xe1, 0x00, 0xc9, 0x1e, 0x9d, 0x0e, 0xa0, 0x98, 0xbd, 0x0d, 0xa6, + 0xe9, 0x49, 0x09, 0x65, 0x9e, 0xdf, 0x5a, 0x8f, 0x4e, 0x73, 0x95, 0x72, + 0xe7, 0x2a, 0x07, 0xa6, 0xdd, 0x74, 0xb7, 0x83, 0xee, 0x1e, 0x35, 0x3c, + 0xdf, 0x22, 0x16, 0x39, 0xed, 0xa8, 0x65, 0x0a, 0xc3, 0x66, 0x0a, 0x30, + 0x0f, 0xef, 0xa3, 0x2e, 0xf2, 0xc7, 0x4f, 0x75, 0xaf, 0x28, 0xea, 0x62, + 0x8e, 0x5a, 0x5a, 0xa6, 0x03, 0xe9, 0x72, 0x46, 0x3f, 0x38, 0xc8, 0xc1, + 0xd7, 0x47, 0x0f, 0xd0, 0xeb, 0x61, 0xfa, 0x20, 0x5a, 0xf5, 0x32, 0xf1, + 0x2d, 0xae, 0xac, 0x4c, 0x4b, 0xc8, 0x65, 0x89, 0x8c, 0x87, 0x02, 0x26, + 0x0c, 0x7f, 0x4c, 0xf6, 0xd7, 0xeb, 0x51, 0x92, 0x3b, 0xad, 0x7d, 0x2c, + 0xb4, 0xc0, 0x4b, 0x1f, 0x33, 0xa2, 0x73, 0x64, 0xb1, 0x27, 0xaf, 0xe3, + 0x44, 0x5c, 0x26, 0xb6, 0x8b, 0x64, 0x74, 0xef, 0x1c, 0x32, 0x4b, 0x0c, + 0xb2, 0x31, 0x95, 0x81, 0x39, 0x2e, 0x49, 0x05, 0xbe, 0xe3, 0x03, 0xbe, + 0x87, 0xbc, 0xcf, 0x53, 0x55, 0x73, 0xb5, 0x5c, 0xa8, 0xd3, 0xc2, 0xae, + 0xa8, 0x85, 0x4c, 0xa1, 0x4e, 0x39, 0x59, 0x47, 0x9b, 0x56, 0x37, 0x78, + 0x3a, 0x49, 0x4c, 0xd5, 0x69, 0x55, 0x31, 0x12, 0xf9, 0xc2, 0xb8, 0x71, + 0xf4, 0x8f, 0x61, 0xe9, 0xef, 0xdf, 0x44, 0x5e, 0xd6, 0x1b, 0x55, 0xfe, + 0x3a, 0xb1, 0x00, 0x9a, 0x9e, 0x78, 0x73, 0x4e, 0x84, 0xf9, 0x47, 0x62, + 0x71, 0xae, 0x78, 0xba, 0x2a, 0x2a, 0xc8, 0xed, 0xd5, 0xc9, 0x34, 0x69, + 0x55, 0x53, 0x2f, 0x2c, 0xab, 0xd0, 0x64, 0x1f, 0xaf, 0x1e, 0x9b, 0x6f, + 0xf7, 0xd0, 0xf7, 0x46, 0x79, 0xe5, 0x89, 0x6a, 0x66, 0x1c, 0xf4, 0x8a, + 0xc8, 0x54, 0x0d, 0x86, 0x48, 0x23, 0x07, 0xdf, 0xae, 0x80, 0xb4, 0x75, + 0x4b, 0xce, 0xed, 0x8a, 0xfa, 0xc9, 0x8b, 0xb6, 0x5a, 0x34, 0xce, 0x54, + 0x2f, 0x6d, 0xb5, 0x30, 0x64, 0xab, 0xb7, 0x24, 0x40, 0x78, 0x8c, 0x93, + 0x34, 0x9b, 0x0f, 0xa7, 0xae, 0x73, 0xfa, 0xea, 0x0a, 0x68, 0x96, 0x48, + 0x92, 0x44, 0x99, 0x54, 0x3f, 0xfc, 0x42, 0xc7, 0x04, 0x2e, 0x40, 0xdb, + 0xdb, 0x5f, 0x60, 0xad, 0x6a, 0x39, 0xe4, 0xf9, 0x44, 0x0f, 0x02, 0xc5, + 0xcc, 0x18, 0xaf, 0x28, 0xf3, 0x13, 0xe6, 0x03, 0xbf, 0x7d, 0x40, 0x8f, + 0xb1, 0x4a, 0xa6, 0x65, 0x54, 0x81, 0x23, 0x89, 0x37, 0x77, 0xc7, 0x99, + 0xbd, 0x4e, 0xbe, 0x32, 0x40, 0x0c, 0x8c, 0xbc, 0xc5, 0x7e, 0xac, 0x0e, + 0xa7, 0x3d, 0xc9, 0xed, 0xa1, 0x67, 0x50, 0x70, 0xb1, 0x33, 0x3c, 0x60, + 0x82, 0x09, 0xed, 0xae, 0xe2, 0x6c, 0x4e, 0x59, 0xc0, 0x0f, 0xb6, 0x0f, + 0x6c, 0xfa, 0xe8, 0x4b, 0x25, 0x74, 0x75, 0x91, 0x11, 0x5b, 0x9d, 0xd7, + 0x0c, 0xac, 0xdd, 0x7d, 0xb1, 0xa8, 0xf3, 0x5f, 0x5d, 0x70, 0x5a, 0x58, + 0x55, 0xe5, 0xab, 0x76, 0x21, 0x63, 0x5d, 0xce, 0x74, 0x3d, 0x65, 0x4b, + 0x53, 0xd5, 0xf8, 0xce, 0xa6, 0x47, 0xe5, 0xd8, 0x83, 0xb6, 0x7d, 0xf5, + 0xf7, 0x86, 0xae, 0x95, 0x14, 0xd7, 0x46, 0x9d, 0x27, 0x6a, 0x4a, 0xb7, + 0x23, 0xe5, 0xe4, 0x0e, 0x31, 0xcd, 0x9d, 0xc6, 0x71, 0xb1, 0x3a, 0x10, + 0x33, 0xe7, 0x8c, 0x29, 0x7b, 0x2f, 0x7c, 0x39, 0xc0, 0x4c, 0x1a, 0xdb, + 0xc4, 0x86, 0xe5, 0x4d, 0x70, 0x73, 0x3a, 0xac, 0x90, 0x8d, 0xfc, 0x3e, + 0xdb, 0x83, 0xd0, 0xab, 0x63, 0xf4, 0xd2, 0xa4, 0x8e, 0x6a, 0xaf, 0x88, + 0x57, 0x08, 0x3a, 0xcb, 0x55, 0x2b, 0x73, 0x12, 0x37, 0xc8, 0x03, 0x1a, + 0xe2, 0x5b, 0xa5, 0x55, 0x35, 0x5d, 0x75, 0xc3, 0x15, 0x14, 0xb7, 0x29, + 0x4f, 0x37, 0x82, 0xbb, 0x01, 0x9d, 0xd8, 0xfa, 0x0d, 0xfb, 0x63, 0x5f, + 0x78, 0x3f, 0x88, 0x3e, 0x43, 0x88, 0x23, 0xe2, 0x23, 0x49, 0x1d, 0x5c, + 0xa0, 0xb1, 0x71, 0x2f, 0x46, 0xe6, 0x03, 0x39, 0x03, 0xa1, 0xdb, 0x3a, + 0x46, 0x59, 0x5b, 0x38, 0xd9, 0x72, 0xca, 0x6f, 0x93, 0x42, 0xac, 0x92, + 0xba, 0xcd, 0x65, 0x9e, 0xd6, 0x64, 0x91, 0x59, 0xa0, 0x1e, 0x33, 0x74, + 0xcf, 0x72, 0x3d, 0xfa, 0x6b, 0x2c, 0xb9, 0x55, 0x86, 0xa8, 0xf1, 0xa2, + 0x8d, 0xa3, 0x47, 0xc3, 0x60, 0x9c, 0x63, 0x3d, 0x75, 0xa9, 0xf1, 0x6f, + 0x19, 0xd9, 0xea, 0xed, 0x50, 0xd4, 0xd9, 0x96, 0xad, 0x6b, 0x6a, 0x0e, + 0x25, 0x8e, 0xa1, 0xb9, 0xd6, 0x9f, 0xae, 0x79, 0x4e, 0x37, 0x27, 0xb1, + 0xd6, 0x43, 0x7f, 0xa8, 0xa5, 0x15, 0x8a, 0xa3, 0x69, 0x79, 0xb0, 0xd8, + 0x1b, 0x03, 0xdb, 0x3f, 0x7f, 0x5d, 0x2a, 0x9d, 0xee, 0x62, 0xb6, 0x96, + 0xba, 0xbb, 0x6b, 0x52, 0xaa, 0x2b, 0xc7, 0x24, 0x53, 0x90, 0x09, 0x46, + 0xe8, 0x41, 0x00, 0x86, 0xcf, 0x7c, 0xe7, 0x57, 0x7a, 0x4e, 0x1f, 0xb9, + 0x57, 0xf0, 0x4d, 0x24, 0x56, 0xc0, 0x90, 0xab, 0xb2, 0xb4, 0xb0, 0xf4, + 0x69, 0x64, 0xc9, 0xc3, 0x13, 0xfd, 0x5b, 0x74, 0xf4, 0x1a, 0x4b, 0xc4, + 0x75, 0x90, 0x49, 0x6e, 0xb7, 0x45, 0xf2, 0x75, 0x91, 0x5c, 0x69, 0xd7, + 0x13, 0x89, 0x36, 0x55, 0x42, 0xbe, 0x51, 0xef, 0xb6, 0x0f, 0xd8, 0x8d, + 0x1f, 0x65, 0xe2, 0x2a, 0xd9, 0x6a, 0x22, 0xad, 0x7a, 0xd6, 0x2b, 0x00, + 0x08, 0xc8, 0x48, 0x20, 0xa0, 0xec, 0x06, 0xda, 0xe6, 0xad, 0xc9, 0xbb, + 0x42, 0xd2, 0x57, 0xc8, 0xa9, 0xad, 0x97, 0x84, 0xbb, 0xc1, 0x6e, 0xf9, + 0x59, 0x3e, 0x6a, 0xa1, 0x7f, 0x92, 0x24, 0x1c, 0xbc, 0xde, 0xfa, 0x60, + 0x9c, 0x15, 0xc6, 0xd4, 0xb5, 0x22, 0xba, 0x8e, 0x23, 0x0c, 0xd1, 0xe5, + 0x87, 0xcb, 0x4c, 0x39, 0x87, 0xb6, 0x36, 0xdb, 0x45, 0x7c, 0x53, 0xb8, + 0x51, 0x56, 0xd3, 0x43, 0x74, 0xb7, 0xd5, 0xab, 0xba, 0x1e, 0x5e, 0x50, + 0x71, 0x2a, 0x12, 0xa3, 0xbf, 0xa6, 0x47, 0xe3, 0xf7, 0xd4, 0xfc, 0x01, + 0xf1, 0x17, 0xf8, 0x75, 0x9a, 0x9e, 0xdf, 0x7a, 0x54, 0x92, 0x30, 0x4b, + 0x19, 0x17, 0xeb, 0x52, 0x77, 0xdf, 0xd7, 0x3a, 0x67, 0xd5, 0x59, 0x36, + 0xc7, 0xf4, 0x0b, 0xc7, 0x75, 0x33, 0x7f, 0xe8, 0x1b, 0x7c, 0x0b, 0x48, + 0xb6, 0xea, 0x88, 0x1b, 0x9e, 0xb6, 0x34, 0x3b, 0x9c, 0x82, 0x01, 0xc7, + 0xf7, 0xfb, 0x8d, 0x67, 0x96, 0x88, 0x8b, 0xba, 0x21, 0x84, 0x4a, 0x59, + 0xb1, 0x82, 0x76, 0x24, 0xed, 0xad, 0x42, 0xb6, 0xb6, 0xd3, 0xc5, 0x6d, + 0x55, 0x47, 0x14, 0xae, 0x6a, 0x6b, 0x26, 0x39, 0x2a, 0x0b, 0x10, 0xa3, + 0xa0, 0xfc, 0x0c, 0x0d, 0x41, 0x27, 0x0a, 0xd3, 0x5a, 0x28, 0x8d, 0x1d, + 0x24, 0x86, 0x3a, 0x92, 0xb9, 0xf1, 0x25, 0x05, 0x5b, 0x20, 0x74, 0xdf, + 0xa0, 0xed, 0xa4, 0xe4, 0xd5, 0x42, 0x0d, 0x2f, 0x61, 0x49, 0xf0, 0x33, + 0x36, 0xeb, 0x3a, 0xdb, 0x95, 0xad, 0x51, 0x0a, 0x0a, 0xe9, 0x11, 0x01, + 0xf1, 0x10, 0x18, 0xf3, 0x8d, 0xf6, 0x18, 0xc8, 0x27, 0xd7, 0x54, 0xcb, + 0x5d, 0xee, 0xe5, 0x1f, 0x15, 0xa8, 0x48, 0x29, 0x62, 0x11, 0x31, 0x59, + 0x84, 0x3e, 0x50, 0x18, 0x67, 0x24, 0x2f, 0xa6, 0xd8, 0xeb, 0xdf, 0x42, + 0x53, 0xf1, 0x15, 0x42, 0xdc, 0xe9, 0x6d, 0xd7, 0x98, 0xde, 0xa2, 0x88, + 0xcb, 0xe1, 0x1e, 0x71, 0xba, 0x12, 0x71, 0xb1, 0xd1, 0x9c, 0x55, 0xc2, + 0x15, 0x10, 0xc5, 0x51, 0x78, 0x86, 0xa1, 0x63, 0x59, 0x6a, 0x3c, 0x2a, + 0x68, 0xc3, 0x79, 0xe4, 0x52, 0x7a, 0xff, 0x00, 0x6f, 0xd3, 0x4f, 0x96, + 0x6d, 0xd2, 0xda, 0xd5, 0x58, 0x26, 0xa4, 0xb7, 0x1a, 0x99, 0xa9, 0x4d, + 0xb1, 0xdc, 0xa8, 0x68, 0xc7, 0x20, 0x04, 0x0c, 0x8d, 0x86, 0xdf, 0x8d, + 0x53, 0xf8, 0xcb, 0xe1, 0x95, 0x0d, 0xe0, 0x1a, 0xd9, 0xaa, 0x62, 0x82, + 0x45, 0x89, 0x9e, 0x01, 0xcb, 0xcc, 0xe1, 0x80, 0x52, 0x03, 0xb0, 0xce, + 0x17, 0xd7, 0xb0, 0x3a, 0xb2, 0xf0, 0x35, 0xb1, 0xae, 0xb7, 0x8a, 0xfa, + 0x5a, 0xfb, 0x83, 0x47, 0x4f, 0xcc, 0x7e, 0x5d, 0x42, 0x85, 0x20, 0xe7, + 0xfe, 0x63, 0xbf, 0xe3, 0x56, 0x1a, 0xab, 0x5d, 0x65, 0xbe, 0xad, 0x05, + 0x6d, 0x23, 0x4f, 0x40, 0xaa, 0x73, 0x32, 0xb0, 0xe4, 0x60, 0x08, 0xc0, + 0x65, 0x1d, 0x88, 0xdf, 0x1e, 0xda, 0xdd, 0x2c, 0x92, 0x8b, 0xb8, 0xfa, + 0x1f, 0x14, 0xe2, 0xdb, 0x64, 0x1f, 0x02, 0x6d, 0xf5, 0x94, 0xb6, 0x39, + 0xe2, 0x92, 0x9a, 0x96, 0x8a, 0xa6, 0x96, 0x51, 0x0b, 0x2c, 0x1b, 0xc1, + 0x56, 0xa1, 0x47, 0xf3, 0x8b, 0xff, 0x00, 0x5b, 0x13, 0x91, 0xb6, 0x02, + 0xf4, 0xc1, 0xd6, 0x93, 0x1f, 0x2c, 0xf3, 0x2c, 0x09, 0x51, 0x0a, 0xc9, + 0x0e, 0x0c, 0x91, 0x23, 0x73, 0x11, 0x9d, 0xc1, 0x3d, 0x3a, 0xe9, 0x2d, + 0x3a, 0x45, 0x05, 0xbe, 0x3a, 0xaa, 0x78, 0x21, 0x8e, 0x49, 0x10, 0x78, + 0x66, 0x30, 0x04, 0x7e, 0x1e, 0x41, 0xd8, 0x7f, 0x49, 0xff, 0x00, 0x4d, + 0x35, 0x88, 0x40, 0x8c, 0x95, 0x2a, 0x86, 0x42, 0x00, 0x0e, 0xfc, 0xb8, + 0x61, 0x8e, 0x85, 0xbd, 0x86, 0xff, 0x00, 0xae, 0xab, 0x16, 0x69, 0x4a, + 0x5e, 0x46, 0xb5, 0x2e, 0x06, 0x53, 0xc9, 0xe1, 0xc6, 0x0b, 0xc6, 0xce, + 0x73, 0x8e, 0x55, 0x19, 0x24, 0x74, 0xce, 0xab, 0x75, 0xfc, 0x15, 0x6e, + 0xa9, 0xa9, 0x96, 0x7a, 0x87, 0x91, 0xfc, 0x46, 0x27, 0x94, 0x01, 0xdf, + 0xaf, 0x6d, 0x58, 0x62, 0x95, 0x5e, 0x36, 0xa8, 0xf1, 0xd5, 0xd4, 0x8f, + 0x21, 0x1b, 0x00, 0x3e, 0xfa, 0x1f, 0x9a, 0x69, 0xf2, 0x2a, 0x13, 0x95, + 0x41, 0xdc, 0xab, 0xe4, 0x1f, 0x6e, 0x9f, 0xbf, 0xb6, 0xb4, 0x67, 0xc3, + 0x8b, 0x2a, 0x4a, 0x6a, 0xca, 0xc8, 0x93, 0x5c, 0x95, 0x39, 0xf8, 0x3e, + 0x3a, 0x4b, 0x6d, 0xc9, 0xa0, 0x91, 0x9e, 0xa4, 0xd3, 0xca, 0xb6, 0xf5, + 0x6d, 0x96, 0x1f, 0x29, 0x23, 0x1f, 0xf3, 0x6d, 0x9c, 0xeb, 0xc7, 0xdc, + 0x43, 0x62, 0xab, 0xe7, 0xa8, 0x84, 0x41, 0x21, 0x97, 0x99, 0x94, 0xaf, + 0x2e, 0xfc, 0xc3, 0xb7, 0xed, 0xaf, 0x77, 0xca, 0x95, 0x02, 0xa9, 0xa7, + 0x82, 0x68, 0xc4, 0x0c, 0x9e, 0x60, 0xc3, 0x3e, 0x60, 0x46, 0xff, 0x00, + 0xa6, 0x75, 0x87, 0xfc, 0x49, 0xe3, 0xa8, 0x24, 0xbb, 0x56, 0xc7, 0x45, + 0x47, 0x4d, 0x1c, 0x48, 0x8e, 0xa2, 0x52, 0x3c, 0xf2, 0x49, 0xd3, 0x9b, + 0x1e, 0xdd, 0x89, 0xd6, 0x6d, 0x54, 0xfe, 0x24, 0x9c, 0x7f, 0xe0, 0xcd, + 0x9f, 0x6a, 0x4a, 0xcf, 0x2f, 0x5b, 0xae, 0x97, 0x3a, 0x54, 0xf9, 0x67, + 0x93, 0x23, 0x3c, 0xbc, 0x8e, 0x33, 0xbf, 0xa6, 0xb8, 0xa5, 0xa5, 0x34, + 0xb3, 0xbc, 0x8a, 0x9f, 0xcd, 0x99, 0xc8, 0x63, 0x9f, 0xa0, 0x13, 0xd7, + 0xfe, 0x9a, 0xb8, 0x52, 0x59, 0xd2, 0xb6, 0xbc, 0xd7, 0x54, 0xc2, 0x4c, + 0x4b, 0xbc, 0xac, 0xc7, 0xeb, 0x7e, 0xd8, 0x1f, 0xae, 0x84, 0xe2, 0x16, + 0x4a, 0x6a, 0xb4, 0x0b, 0x4c, 0x73, 0xca, 0x0f, 0x9b, 0xa3, 0x7b, 0xea, + 0xe1, 0x97, 0x7c, 0xb6, 0xc4, 0x5c, 0x64, 0x7c, 0x9e, 0xd6, 0x28, 0xea, + 0xed, 0x95, 0x14, 0x22, 0x49, 0x69, 0x84, 0x45, 0xdc, 0x63, 0x3c, 0xc5, + 0x4f, 0x31, 0x20, 0x7e, 0x40, 0xfc, 0xeb, 0xef, 0x1b, 0x5e, 0x45, 0xf7, + 0x88, 0xab, 0x6f, 0x53, 0x40, 0xb4, 0xf3, 0xd5, 0xc6, 0xbc, 0xc0, 0x28, + 0x5e, 0x76, 0x00, 0x02, 0xc5, 0x47, 0x4c, 0xe0, 0x6d, 0xed, 0xab, 0x67, + 0xc2, 0xeb, 0xa4, 0x94, 0xa6, 0xe7, 0xc4, 0x35, 0x53, 0x28, 0x92, 0x9a, + 0x94, 0xd3, 0xd3, 0xd3, 0x2c, 0x63, 0x05, 0x1b, 0x63, 0xe6, 0x3b, 0x2f, + 0xb7, 0xb9, 0xce, 0xb3, 0xc7, 0xb5, 0xde, 0xe4, 0xab, 0x68, 0x24, 0xa8, + 0xf1, 0xa9, 0x0c, 0xd9, 0x4e, 0x67, 0x1f, 0x56, 0xfe, 0xbe, 0x99, 0x23, + 0x4e, 0x8c, 0xd3, 0x93, 0x8b, 0xf4, 0x35, 0x31, 0xaf, 0xc9, 0x5d, 0x29, + 0x78, 0x3f, 0xe6, 0x40, 0xa4, 0x92, 0x8a, 0x49, 0x15, 0x32, 0x79, 0x0b, + 0xc6, 0xcc, 0x33, 0x90, 0x33, 0xcc, 0x3f, 0xb6, 0xab, 0xd5, 0xd0, 0x3c, + 0x10, 0x09, 0x26, 0x60, 0x99, 0x19, 0x03, 0xae, 0xfa, 0x79, 0x6a, 0x92, + 0xa2, 0xd7, 0x72, 0x6a, 0x1a, 0xc5, 0x3c, 0x92, 0x31, 0xe5, 0xcf, 0x4c, + 0xeb, 0xe7, 0x19, 0xa0, 0xae, 0x14, 0xb4, 0xf4, 0xa8, 0x8a, 0xc6, 0x4e, + 0x56, 0x23, 0xaf, 0xa6, 0x95, 0x1c, 0x8f, 0xe4, 0x49, 0xf4, 0x0c, 0xa6, + 0x55, 0x69, 0x26, 0x67, 0x5e, 0x63, 0xf4, 0xab, 0x6d, 0xf6, 0xd3, 0xfa, + 0x51, 0x1a, 0x2f, 0x89, 0x50, 0x39, 0xc3, 0x79, 0x95, 0x71, 0xd4, 0x1d, + 0x7e, 0xaa, 0xe1, 0x69, 0x6d, 0xf4, 0x80, 0xcb, 0x22, 0x78, 0xc1, 0xfc, + 0xb8, 0x18, 0xcf, 0x5d, 0x08, 0xbe, 0x24, 0x8e, 0x90, 0xbc, 0x6c, 0xb2, + 0x0d, 0x97, 0x1d, 0x3f, 0x5d, 0x33, 0xe4, 0x53, 0x57, 0x12, 0xdf, 0x28, + 0xb4, 0xf0, 0xf4, 0x94, 0x13, 0x19, 0x3c, 0x68, 0xca, 0x96, 0x25, 0x51, + 0x14, 0xec, 0x17, 0x07, 0xaf, 0xae, 0x74, 0x75, 0x6d, 0x03, 0x57, 0x45, + 0x5b, 0x54, 0x58, 0xe2, 0xa6, 0x89, 0x5c, 0x05, 0x5e, 0x9c, 0x88, 0x39, + 0xb3, 0xe9, 0xb9, 0x1a, 0x4b, 0x65, 0x49, 0x61, 0xaa, 0xa3, 0x6e, 0x61, + 0xcf, 0x14, 0xca, 0x18, 0x0e, 0x99, 0x27, 0xd7, 0x57, 0x35, 0xc4, 0x13, + 0x5d, 0x28, 0xe7, 0x40, 0x3c, 0x0a, 0x79, 0xd4, 0x64, 0xe3, 0x98, 0x92, + 0xb8, 0xfb, 0x75, 0x3a, 0x76, 0x9f, 0xa6, 0x6d, 0xd1, 0xcf, 0x72, 0x6b, + 0xf4, 0x53, 0x78, 0x96, 0x70, 0xb6, 0x1a, 0x48, 0x51, 0xb9, 0x52, 0xa9, + 0xe3, 0x9c, 0xc6, 0x06, 0xd9, 0x20, 0xab, 0x7e, 0xe3, 0x4c, 0xa8, 0xf0, + 0xb5, 0x16, 0xe7, 0xa6, 0x01, 0x3c, 0x02, 0x32, 0xec, 0x70, 0x3a, 0x64, + 0x8f, 0xdb, 0x4b, 0x67, 0x0c, 0x28, 0x78, 0x6e, 0x29, 0xd5, 0xe4, 0x09, + 0x3d, 0x44, 0xc5, 0x33, 0xb2, 0xa0, 0x61, 0x8c, 0x1f, 0xc6, 0x3b, 0x68, + 0xc9, 0xe6, 0x49, 0x29, 0x93, 0xe5, 0x61, 0x68, 0x64, 0x9e, 0x62, 0xdc, + 0x85, 0x89, 0xc6, 0x4e, 0x4e, 0xfd, 0xc6, 0x35, 0xa0, 0xd7, 0x0e, 0xc1, + 0x69, 0x61, 0x96, 0xe5, 0x7b, 0x86, 0x9a, 0x47, 0x1f, 0x2e, 0xb2, 0x12, + 0xa4, 0x0d, 0x94, 0x13, 0x9d, 0xb4, 0x5f, 0x11, 0xd2, 0x53, 0xc5, 0x7d, + 0x16, 0xda, 0x66, 0x73, 0x1f, 0x22, 0xb4, 0x92, 0x36, 0xf8, 0xdb, 0x6f, + 0xfc, 0x6a, 0x5b, 0x4d, 0x5a, 0xd0, 0x71, 0x07, 0x8a, 0xcd, 0x94, 0x73, + 0xe4, 0x21, 0x76, 0x39, 0xdc, 0x0c, 0x6a, 0x6b, 0xd2, 0x54, 0x41, 0x5a, + 0x2a, 0x4c, 0x7c, 0xa6, 0xb0, 0x99, 0x39, 0xc3, 0x67, 0x94, 0xff, 0x00, + 0xe3, 0x3b, 0x68, 0x46, 0x24, 0x2c, 0x8a, 0x8e, 0x59, 0x88, 0x39, 0x64, + 0xe4, 0x63, 0xc8, 0xca, 0x7e, 0x9c, 0x76, 0xd7, 0x10, 0x3a, 0xa8, 0x9a, + 0x22, 0x87, 0x2c, 0xc0, 0x47, 0x83, 0xb0, 0xc6, 0x76, 0xf7, 0x1d, 0x74, + 0x6b, 0xf8, 0x2d, 0x0a, 0xd1, 0xcb, 0x2a, 0x81, 0x36, 0x4a, 0xc8, 0xc3, + 0x02, 0x3f, 0x71, 0xe8, 0x4e, 0x82, 0xf9, 0x79, 0x10, 0xc9, 0x07, 0x3a, + 0x48, 0xc8, 0xde, 0x46, 0x56, 0xce, 0xdd, 0xb5, 0x44, 0x44, 0x82, 0x28, + 0xd5, 0x9d, 0x64, 0x8f, 0xcf, 0x9c, 0x82, 0x3a, 0x69, 0x6d, 0x73, 0xc9, + 0x33, 0x98, 0xd5, 0xb0, 0xca, 0x4e, 0xfe, 0x9b, 0xed, 0xfb, 0x68, 0xdb, + 0xa8, 0x9e, 0x9c, 0xe2, 0x56, 0x1c, 0xdd, 0x48, 0xce, 0x96, 0x54, 0x4a, + 0x42, 0xc4, 0x85, 0x0f, 0x34, 0xad, 0x93, 0x9d, 0x86, 0x35, 0x0b, 0x25, + 0x96, 0x70, 0x5d, 0x28, 0x9a, 0x97, 0xc3, 0x66, 0x65, 0x65, 0x98, 0x92, + 0x72, 0x3e, 0xda, 0x02, 0xa6, 0x08, 0xed, 0xf5, 0xb2, 0x4b, 0x5c, 0xa8, + 0xc0, 0xf9, 0x57, 0x0b, 0x80, 0x17, 0xfe, 0x5f, 0x4d, 0x18, 0x55, 0x16, + 0x55, 0x45, 0x05, 0x50, 0xae, 0x0e, 0x0e, 0xea, 0x73, 0xd7, 0x45, 0x9b, + 0x19, 0xbb, 0x55, 0xa4, 0xd3, 0xcb, 0x27, 0xf0, 0xda, 0x75, 0xe6, 0xcb, + 0xff, 0x00, 0xee, 0x11, 0xd8, 0x69, 0x51, 0x9b, 0x94, 0xdc, 0x59, 0xc8, + 0xc9, 0xfe, 0xa3, 0x62, 0xf1, 0x25, 0x7d, 0x7d, 0x4c, 0x13, 0xd1, 0xc9, + 0x57, 0x94, 0x01, 0x15, 0x49, 0xe7, 0x3c, 0xaa, 0x31, 0x81, 0xd3, 0x6d, + 0xb1, 0xab, 0xbd, 0x8a, 0xd9, 0x67, 0xb8, 0x45, 0x14, 0x0b, 0x77, 0x36, + 0xea, 0xc7, 0x20, 0x3d, 0x25, 0x64, 0x4c, 0xa4, 0xb9, 0xea, 0x73, 0xd3, + 0x1a, 0xad, 0xcb, 0x73, 0x92, 0x9d, 0xdc, 0xdb, 0xff, 0x00, 0xdd, 0x83, + 0x80, 0x14, 0xa8, 0xf3, 0x22, 0x0e, 0x8a, 0x0f, 0x6e, 0xbf, 0x9d, 0x7e, + 0xa7, 0x79, 0x2b, 0x2b, 0x60, 0x85, 0xe6, 0xe7, 0xfe, 0x50, 0x2c, 0xcc, + 0x77, 0x2e, 0xcc, 0xa3, 0x7f, 0x5f, 0xdb, 0xa6, 0xb3, 0xe4, 0xed, 0xc8, + 0x43, 0x34, 0x6e, 0x20, 0xe0, 0x9b, 0xcd, 0x92, 0x9a, 0x8e, 0x68, 0x0d, + 0x3d, 0x5c, 0x53, 0xb3, 0x2a, 0x3a, 0x36, 0xcb, 0x82, 0x37, 0x39, 0xe8, + 0x7d, 0xbd, 0x06, 0x97, 0xd1, 0x59, 0xb8, 0x21, 0xaa, 0xa3, 0xfe, 0x2d, + 0x78, 0xaa, 0x17, 0x29, 0x58, 0x44, 0xf2, 0xd3, 0xd3, 0x8f, 0x06, 0x39, + 0x0b, 0x64, 0x9c, 0x9e, 0xa0, 0x0f, 0x4d, 0xbb, 0xe7, 0x7d, 0x36, 0xe3, + 0x98, 0x6d, 0x16, 0x1e, 0x0f, 0xb4, 0xc3, 0x6e, 0xbc, 0x9a, 0x9b, 0x88, + 0xcb, 0xd4, 0x88, 0x2b, 0x4c, 0x91, 0xc6, 0x40, 0xc3, 0x02, 0x9b, 0x80, + 0x49, 0x23, 0x70, 0x7d, 0x46, 0xfa, 0xa5, 0xd0, 0xcb, 0x35, 0x1f, 0x0a, + 0xd5, 0xf1, 0x19, 0xa6, 0xa5, 0x25, 0x26, 0x14, 0x50, 0x16, 0x07, 0x31, + 0xc8, 0xe0, 0xb7, 0x30, 0x19, 0xdc, 0x80, 0xac, 0x37, 0xdb, 0x71, 0xa1, + 0x4e, 0xda, 0x41, 0x17, 0x9a, 0x9b, 0x1f, 0x10, 0xf0, 0xf5, 0x75, 0x5d, + 0x3b, 0xdc, 0x29, 0x65, 0xa2, 0x58, 0x0c, 0xef, 0x24, 0xd3, 0xa9, 0x32, + 0x8c, 0x80, 0x15, 0x41, 0xdf, 0x9b, 0x71, 0xb0, 0xed, 0x9d, 0x01, 0x0d, + 0x86, 0xdd, 0x7c, 0x09, 0x4f, 0x6f, 0xba, 0xc1, 0x43, 0x79, 0x6f, 0x39, + 0xa7, 0xa8, 0xa8, 0x01, 0x1f, 0x62, 0x72, 0x18, 0xec, 0x35, 0x8e, 0x54, + 0xdc, 0x6a, 0x65, 0xac, 0x53, 0x56, 0xcf, 0x50, 0x39, 0xc1, 0x2a, 0x64, + 0x6c, 0xbf, 0xa0, 0xce, 0x75, 0xa0, 0xf0, 0xa5, 0xc7, 0x87, 0x63, 0xe2, + 0x2a, 0x1b, 0x3d, 0xda, 0x2a, 0xc8, 0x9a, 0x66, 0x22, 0xa2, 0xa1, 0x9f, + 0x9c, 0xc5, 0xe5, 0x25, 0x79, 0x32, 0x3e, 0x9c, 0x80, 0x33, 0xef, 0xa3, + 0x7a, 0x7e, 0x77, 0x5f, 0xa0, 0x06, 0x75, 0xf3, 0x9f, 0xe1, 0xe2, 0x9d, + 0x92, 0x9e, 0x27, 0xa3, 0x8b, 0x96, 0x49, 0xd4, 0x61, 0x64, 0x3d, 0x4e, + 0x4f, 0xf5, 0x1f, 0x4f, 0xb6, 0xa1, 0xa8, 0xe1, 0x4b, 0xe9, 0x34, 0x72, + 0x4d, 0x4b, 0x3c, 0x26, 0xa9, 0x99, 0x51, 0x66, 0x1c, 0xac, 0x40, 0xc7, + 0x9b, 0x97, 0xa8, 0x19, 0x23, 0x7f, 0xbe, 0x99, 0xf0, 0x2f, 0x0f, 0x1e, + 0x26, 0xe3, 0x43, 0x40, 0x2a, 0x9e, 0x9e, 0x3a, 0x58, 0x9e, 0xa3, 0xc6, + 0x76, 0x0d, 0xba, 0x83, 0xca, 0x77, 0xdb, 0x39, 0xc7, 0x5e, 0xc4, 0xe9, + 0x25, 0xff, 0x00, 0x8c, 0x38, 0x8a, 0xe5, 0x75, 0x79, 0x2b, 0xef, 0x73, + 0xd4, 0x54, 0xc1, 0x21, 0x11, 0xb2, 0xbe, 0x02, 0x80, 0x71, 0xb6, 0x3f, + 0xcb, 0x58, 0x96, 0x18, 0xf3, 0x40, 0x51, 0xa1, 0xda, 0xb8, 0x66, 0xdd, + 0xc3, 0xd6, 0x88, 0xea, 0x6b, 0x0b, 0xc9, 0x73, 0x38, 0x6e, 0x68, 0xd8, + 0xe2, 0x36, 0xc6, 0xd8, 0x00, 0x8d, 0xf7, 0xd0, 0x95, 0x97, 0x5a, 0xfa, + 0xee, 0x78, 0xc5, 0xda, 0x49, 0x5d, 0x5b, 0x1e, 0x15, 0x46, 0xdc, 0xd8, + 0xf4, 0x3a, 0x93, 0xe1, 0x2f, 0xc4, 0x1a, 0x48, 0xee, 0xf4, 0xf4, 0x7c, + 0x5d, 0x04, 0x55, 0x49, 0x2b, 0x11, 0x15, 0x7c, 0x99, 0x2f, 0x19, 0x6e, + 0xcf, 0x9c, 0xf3, 0x2f, 0xbf, 0x6d, 0x5d, 0xea, 0xbe, 0x1e, 0x56, 0x9b, + 0xb2, 0x5f, 0x38, 0x76, 0xa2, 0x95, 0xff, 0x00, 0xdf, 0xa4, 0x22, 0x19, + 0x10, 0x05, 0xe5, 0x0c, 0x70, 0x41, 0x07, 0x07, 0xa7, 0x4c, 0x74, 0x3e, + 0xda, 0x46, 0x5d, 0x23, 0x6e, 0xd1, 0x7f, 0x13, 0x7d, 0x18, 0xe2, 0xdb, + 0xa7, 0xaa, 0xe2, 0x78, 0x3c, 0x59, 0x4c, 0x30, 0x49, 0x2f, 0x34, 0xaa, + 0xbe, 0xa3, 0x39, 0x1f, 0xae, 0xae, 0x15, 0x74, 0xf4, 0x44, 0x81, 0x2b, + 0xca, 0xd0, 0xe0, 0x8e, 0x5e, 0x6e, 0xa5, 0xba, 0x9f, 0xbe, 0xb4, 0xb4, + 0xf8, 0x71, 0x47, 0x53, 0x09, 0x17, 0x49, 0x07, 0xce, 0xb3, 0x16, 0x9a, + 0xaa, 0x12, 0x54, 0x6e, 0x09, 0x01, 0x50, 0x92, 0x01, 0x1b, 0x7d, 0xc6, + 0x75, 0x8c, 0xdf, 0x66, 0xfe, 0x1f, 0x7a, 0xaa, 0xb3, 0xf8, 0xce, 0xe6, + 0x09, 0x0a, 0xf3, 0xba, 0x72, 0xe4, 0x82, 0x46, 0xc3, 0x27, 0x6d, 0x6b, + 0xc3, 0x8a, 0x4b, 0xec, 0xca, 0x78, 0xe8, 0xd9, 0xf8, 0x53, 0x86, 0xe8, + 0xff, 0x00, 0x88, 0x53, 0xf1, 0x03, 0xd7, 0xc8, 0xa5, 0x11, 0x79, 0x60, + 0x31, 0x82, 0x55, 0xb9, 0x40, 0x2c, 0x09, 0x27, 0xfb, 0x6a, 0xd9, 0x56, + 0x22, 0x92, 0x05, 0x85, 0x2b, 0x0a, 0xcd, 0xe5, 0x7f, 0x13, 0x3e, 0x63, + 0x83, 0xf4, 0x91, 0xd3, 0xee, 0x74, 0x8e, 0x9a, 0xa2, 0xa6, 0x9e, 0xc5, + 0x48, 0xf4, 0xc3, 0xc7, 0x0d, 0x4e, 0xbc, 0xf2, 0x0c, 0x01, 0x18, 0x00, + 0x0e, 0x53, 0x9e, 0x9d, 0xc6, 0xdd, 0x71, 0xa0, 0x66, 0xad, 0x09, 0x4d, + 0x05, 0x5d, 0x12, 0x24, 0x22, 0x49, 0x3c, 0x09, 0xd2, 0x38, 0x4f, 0x21, + 0xc6, 0xfd, 0xce, 0x4f, 0x4f, 0x6d, 0x56, 0x4c, 0x8a, 0x32, 0x69, 0x9b, + 0x1f, 0x6e, 0x8b, 0x4d, 0x3d, 0x42, 0xc1, 0x4d, 0x3c, 0x35, 0x46, 0x26, + 0x75, 0x5c, 0xa8, 0x24, 0x30, 0x39, 0xe8, 0xb8, 0x1f, 0xb6, 0xab, 0x17, + 0xbe, 0x20, 0x7b, 0x45, 0x4a, 0xf3, 0xd1, 0x54, 0x07, 0x48, 0x8b, 0x98, + 0xc9, 0x18, 0xf0, 0xc9, 0xdc, 0x92, 0x76, 0xfc, 0x13, 0xaa, 0x97, 0x12, + 0x71, 0x7c, 0x54, 0x97, 0xda, 0x85, 0x9a, 0xb5, 0x60, 0xa6, 0x8c, 0x73, + 0x49, 0x84, 0xc0, 0x5d, 0x8e, 0x10, 0x2f, 0xa9, 0xdb, 0x7f, 0x6d, 0x71, + 0x6a, 0xe2, 0x2a, 0xdb, 0xdf, 0x0c, 0xca, 0x05, 0xae, 0x25, 0x5d, 0xf0, + 0x6b, 0x1b, 0x06, 0x55, 0x3d, 0x0a, 0x9d, 0xb9, 0x57, 0x1d, 0x4f, 0xf7, + 0xd2, 0xe3, 0x39, 0x49, 0x5a, 0x66, 0x57, 0x94, 0xbc, 0xf0, 0xb7, 0x13, + 0x47, 0x74, 0x82, 0xa2, 0x6b, 0x64, 0x6f, 0xf2, 0x71, 0xc4, 0x64, 0xe5, + 0x09, 0x80, 0xa4, 0xe0, 0xf4, 0x27, 0x7e, 0xfd, 0x3a, 0xeb, 0xb3, 0x72, + 0xfe, 0x35, 0x04, 0x75, 0x14, 0x2b, 0x35, 0x25, 0x50, 0x3b, 0xcb, 0x2f, + 0x91, 0xa6, 0x0b, 0xb6, 0x15, 0x8f, 0x4c, 0xee, 0x7a, 0x74, 0xd2, 0x0f, + 0x87, 0x0f, 0x05, 0x3d, 0x9a, 0x68, 0x26, 0xa3, 0x99, 0xe5, 0xa7, 0x8d, + 0xc7, 0x89, 0x1b, 0x64, 0x54, 0x31, 0xe9, 0xe1, 0xa6, 0xc4, 0xf4, 0x03, + 0x27, 0x6d, 0x58, 0xe8, 0x6d, 0x51, 0xcd, 0x47, 0x47, 0x1d, 0x78, 0xf9, + 0xa9, 0xa5, 0x0d, 0x24, 0xe2, 0x70, 0x57, 0x95, 0x1b, 0x7f, 0x32, 0x13, + 0xb1, 0x04, 0x74, 0x1b, 0x6d, 0xab, 0x87, 0xc9, 0xe9, 0xd8, 0x71, 0x7b, + 0xe3, 0x64, 0x7c, 0x6f, 0x73, 0xbc, 0x43, 0xc0, 0xd5, 0x32, 0xc5, 0x32, + 0x41, 0x5b, 0x28, 0xe5, 0x89, 0x63, 0x42, 0x79, 0x54, 0x92, 0x33, 0x91, + 0xed, 0xaf, 0x3d, 0xd6, 0xda, 0x2b, 0x11, 0xd8, 0xcf, 0x32, 0x2a, 0x91, + 0x92, 0x73, 0xb8, 0xc9, 0xf4, 0xd7, 0xa2, 0xe8, 0xed, 0xa6, 0xe5, 0x43, + 0x72, 0xb6, 0x4d, 0x54, 0xbe, 0x0e, 0x4a, 0x53, 0xf8, 0x52, 0xf3, 0xaa, + 0x2f, 0x63, 0x8f, 0xf2, 0xdf, 0xa8, 0xd6, 0x5f, 0xf1, 0x13, 0x83, 0xef, + 0x5c, 0x3f, 0x6c, 0x8e, 0xe5, 0x03, 0x53, 0xdc, 0x8f, 0x89, 0xc8, 0xc8, + 0x33, 0x94, 0x63, 0xd0, 0x9c, 0xf5, 0xd0, 0x64, 0x59, 0x67, 0x97, 0x73, + 0xe9, 0x01, 0x97, 0x1b, 0x6e, 0xd1, 0x4b, 0xbc, 0xda, 0xd7, 0x87, 0xed, + 0x8b, 0x2c, 0xf2, 0xd3, 0xf3, 0xd4, 0x43, 0xce, 0xac, 0x47, 0x98, 0x03, + 0xd0, 0x6a, 0x99, 0x62, 0xb4, 0x52, 0xdd, 0xab, 0xe6, 0xae, 0xb8, 0xd6, + 0x47, 0x49, 0x6d, 0x80, 0x9f, 0x1a, 0x79, 0xb3, 0x86, 0x38, 0xd9, 0x54, + 0x0d, 0xd8, 0x9d, 0x69, 0x09, 0xf0, 0xe6, 0xf1, 0x74, 0x64, 0xbd, 0x71, + 0x75, 0xc5, 0x69, 0xa8, 0xe3, 0x52, 0x1d, 0x61, 0x1c, 0xe6, 0x35, 0x09, + 0x95, 0xce, 0xf8, 0xc1, 0xd8, 0x63, 0xae, 0xb3, 0x0b, 0xf0, 0x47, 0xbc, + 0x7c, 0x85, 0x28, 0x8d, 0xa9, 0xa9, 0xd8, 0x08, 0x80, 0x5f, 0x2f, 0xdf, + 0x5a, 0xa3, 0x92, 0x2f, 0xe8, 0x02, 0x8d, 0x1f, 0x62, 0x95, 0x22, 0xb7, + 0x4f, 0x0d, 0x37, 0x34, 0x71, 0x19, 0x0e, 0x41, 0x4e, 0x5f, 0x10, 0x03, + 0xe5, 0x38, 0xfb, 0x68, 0x27, 0x2b, 0x5f, 0x6b, 0x92, 0x02, 0xd9, 0x31, + 0x39, 0x6c, 0x7a, 0x64, 0x6c, 0x7f, 0xef, 0xd7, 0x5a, 0x65, 0xb6, 0x81, + 0x38, 0x9a, 0xd3, 0xf3, 0x30, 0x2c, 0x86, 0xb6, 0xdb, 0x96, 0xac, 0x61, + 0x1f, 0xf2, 0xcc, 0x1c, 0xbb, 0x60, 0x8c, 0xe0, 0xae, 0x0e, 0xd8, 0xdf, + 0x39, 0xed, 0xac, 0xf6, 0x4a, 0x58, 0xa8, 0xaf, 0x95, 0x34, 0xb2, 0x11, + 0x14, 0x55, 0x00, 0xf2, 0x73, 0x7a, 0xe7, 0xa7, 0xf7, 0xd3, 0x78, 0x9b, + 0xb4, 0x86, 0x45, 0x96, 0xbf, 0x83, 0x97, 0x2b, 0x6d, 0x65, 0xc1, 0x2d, + 0x97, 0xbb, 0x2d, 0x3d, 0xca, 0xaa, 0x1c, 0xad, 0x1b, 0xcb, 0x8f, 0x2a, + 0xf4, 0x2b, 0xfe, 0x7a, 0xb8, 0xfc, 0x45, 0xe1, 0x7b, 0x14, 0xfc, 0x49, + 0x4d, 0xc4, 0x36, 0xa8, 0xe2, 0x5f, 0x05, 0x0a, 0x49, 0x4f, 0x08, 0xc4, + 0x71, 0x48, 0x36, 0xc8, 0xf5, 0xef, 0xac, 0xd3, 0xe1, 0xbc, 0x17, 0x48, + 0x3e, 0x23, 0x5a, 0x45, 0xa5, 0x11, 0xaa, 0xfc, 0x7c, 0x44, 0x59, 0xb0, + 0xbd, 0x08, 0xc9, 0x3e, 0x98, 0xdf, 0x5e, 0x8d, 0xa0, 0xb1, 0xd2, 0xc5, + 0x05, 0x7c, 0x8f, 0xe0, 0xcb, 0xcf, 0x1c, 0xaf, 0x56, 0xd3, 0xb9, 0x52, + 0xd2, 0x16, 0x2c, 0x70, 0xbd, 0x87, 0x5d, 0x61, 0xd5, 0x62, 0x6a, 0x54, + 0x9f, 0x62, 0xe7, 0xc9, 0x91, 0x5f, 0xf8, 0x5b, 0x9f, 0xe1, 0xdd, 0x67, + 0x10, 0xc9, 0xce, 0xcd, 0x1d, 0x42, 0x45, 0x14, 0x7b, 0x80, 0xa3, 0xa1, + 0x63, 0xef, 0x9c, 0xe3, 0x1a, 0xca, 0xeb, 0xa5, 0x14, 0xf9, 0x96, 0x1d, + 0xa4, 0x3e, 0x54, 0x3e, 0x9e, 0xfa, 0xf4, 0xdf, 0xc4, 0x2b, 0xd5, 0x8e, + 0x4b, 0x6d, 0x07, 0x0f, 0xbd, 0x3d, 0x14, 0xb6, 0xf9, 0x62, 0xf1, 0x43, + 0x42, 0x85, 0x63, 0x84, 0x93, 0x85, 0xc0, 0x19, 0x24, 0xe1, 0xb5, 0xe7, + 0x2b, 0xe5, 0xa4, 0x43, 0x57, 0x5f, 0x2b, 0x11, 0x24, 0x14, 0x93, 0x18, + 0xd0, 0xaf, 0x4d, 0xf2, 0x41, 0x07, 0xec, 0x3a, 0x69, 0xda, 0x75, 0xb3, + 0xc4, 0x28, 0xb2, 0xb6, 0x6a, 0x6a, 0x14, 0xb1, 0x8a, 0x46, 0x0b, 0x19, + 0x04, 0x0c, 0xff, 0x00, 0x56, 0x7a, 0xeb, 0x40, 0x59, 0xa5, 0x7b, 0x24, + 0x95, 0x0f, 0xcc, 0xdc, 0xd4, 0x3e, 0x21, 0x23, 0x66, 0x2c, 0x48, 0xe6, + 0xfc, 0x6a, 0x91, 0x80, 0xf1, 0x24, 0x81, 0x64, 0xf0, 0xd9, 0x8b, 0x06, + 0x2b, 0x80, 0xd8, 0xeb, 0x8f, 0x5d, 0x5e, 0x29, 0xea, 0x05, 0x57, 0x0e, + 0xc9, 0x3b, 0x05, 0x52, 0x68, 0x9e, 0x9d, 0x49, 0x6e, 0xfc, 0xe1, 0x87, + 0xfd, 0xfb, 0x6b, 0xad, 0x86, 0x06, 0xfd, 0x23, 0x05, 0xb5, 0x54, 0xc9, + 0x43, 0x71, 0xb4, 0x37, 0xca, 0xfc, 0xc2, 0xc1, 0x40, 0xf3, 0x00, 0x4e, + 0xec, 0xae, 0x58, 0x30, 0x23, 0xed, 0xcc, 0x73, 0xed, 0xa5, 0xf4, 0x54, + 0xeb, 0x27, 0x0b, 0xd4, 0x5c, 0xd2, 0x4f, 0xf7, 0xea, 0x7a, 0xc0, 0x4a, + 0x2f, 0x55, 0x89, 0x80, 0x2b, 0xfd, 0xb4, 0x55, 0xb6, 0x79, 0x57, 0x88, + 0xe2, 0xb6, 0x1e, 0x46, 0x67, 0xa1, 0x8e, 0x9a, 0x07, 0xe7, 0xdd, 0x1f, + 0xc3, 0xe6, 0x0c, 0x3d, 0xb7, 0x6e, 0xfd, 0xf5, 0x37, 0x09, 0x23, 0x35, + 0xaa, 0xfd, 0x6d, 0x9a, 0x37, 0x87, 0x34, 0xc9, 0x32, 0xf3, 0x8d, 0xa5, + 0x74, 0x7c, 0x10, 0x0f, 0x7c, 0xe7, 0x44, 0xfb, 0x35, 0x3e, 0xc0, 0x6b, + 0x8f, 0x35, 0xc2, 0x2a, 0xb0, 0xfc, 0xc6, 0x67, 0xe7, 0x56, 0xfe, 0xfb, + 0x7e, 0x75, 0x63, 0xb9, 0x24, 0x4f, 0x05, 0x14, 0x53, 0x2e, 0x11, 0x23, + 0xf1, 0x15, 0xd8, 0xe4, 0x85, 0xc1, 0x1b, 0x0f, 0x4e, 0x9a, 0xaf, 0xcd, + 0x49, 0x32, 0x43, 0x4b, 0x05, 0x45, 0x30, 0xa7, 0x78, 0xdf, 0x9c, 0x96, + 0xf2, 0xb1, 0x0d, 0x92, 0x3f, 0x1a, 0x71, 0x73, 0x0c, 0x6d, 0x74, 0x41, + 0xb1, 0x20, 0x8d, 0x08, 0x2e, 0xa7, 0xb7, 0x61, 0xa1, 0x34, 0x44, 0x55, + 0x58, 0x11, 0x62, 0x80, 0x2a, 0x00, 0xbc, 0xb9, 0xc9, 0xf5, 0xf5, 0xc7, + 0xa6, 0xa2, 0xa7, 0x56, 0x69, 0x53, 0x1b, 0x76, 0x27, 0x53, 0x73, 0x24, + 0xb4, 0x6a, 0xaf, 0x1a, 0x18, 0x8a, 0xf2, 0x63, 0x97, 0x24, 0x10, 0x71, + 0x9d, 0x7e, 0x82, 0x1a, 0x98, 0x26, 0x6a, 0x49, 0x31, 0x21, 0xe4, 0x2c, + 0x92, 0x8f, 0xa5, 0xd4, 0x77, 0x1a, 0xa2, 0x88, 0x2e, 0x93, 0x3f, 0x8e, + 0xf1, 0xab, 0x73, 0x78, 0x60, 0x17, 0xdb, 0x76, 0x27, 0xb6, 0x96, 0xcd, + 0x11, 0x59, 0x7c, 0x39, 0x06, 0x46, 0x39, 0xc1, 0xf4, 0x3e, 0xda, 0x77, + 0x08, 0x58, 0xae, 0x2e, 0x93, 0xd3, 0x99, 0xa3, 0xc2, 0xbb, 0x0e, 0x6c, + 0x13, 0xb6, 0x7a, 0xe9, 0x05, 0xd8, 0xf3, 0x54, 0x89, 0xa3, 0xe6, 0x08, + 0xa4, 0x31, 0x07, 0xaf, 0x2e, 0x48, 0xc6, 0xa1, 0x66, 0x87, 0xf0, 0xb3, + 0xe1, 0xed, 0x57, 0x1d, 0x5c, 0x18, 0xd2, 0xd5, 0x2d, 0x34, 0x74, 0x50, + 0xc6, 0xd3, 0x4a, 0xc0, 0x9c, 0xf3, 0xb1, 0xd8, 0x7b, 0xe3, 0x27, 0xf1, + 0xad, 0x6b, 0xfd, 0xa3, 0x2c, 0x14, 0x16, 0x5f, 0x87, 0xb6, 0x4a, 0x7a, + 0x0a, 0x54, 0x8a, 0x2a, 0x49, 0x45, 0x3a, 0x30, 0xfa, 0xb0, 0x63, 0x27, + 0x7f, 0x5c, 0xf2, 0xe7, 0x56, 0x1f, 0xf6, 0x75, 0xb5, 0x7f, 0x0c, 0xe0, + 0x9a, 0x5a, 0xca, 0x6e, 0x59, 0x69, 0xeb, 0xe1, 0x13, 0xbb, 0xa9, 0xc9, + 0x2f, 0xb8, 0x0a, 0x7e, 0xc0, 0x63, 0xf3, 0xa5, 0x3c, 0x65, 0xc0, 0x3c, + 0x61, 0xc7, 0x7c, 0x41, 0x5b, 0x70, 0xbd, 0x56, 0x43, 0x41, 0x6c, 0x81, + 0x5d, 0x2d, 0xb4, 0x60, 0x97, 0x7c, 0xff, 0x00, 0x4b, 0x30, 0x1b, 0x2e, + 0x4f, 0x53, 0x92, 0x7d, 0xb4, 0xa8, 0xc7, 0x6c, 0x5c, 0xbd, 0xb3, 0x9b, + 0x38, 0x2e, 0x68, 0xc0, 0xf8, 0x4f, 0x83, 0xae, 0xdc, 0x61, 0x70, 0x6a, + 0x2b, 0x3d, 0x3a, 0x4b, 0x2a, 0xc6, 0xd2, 0x3b, 0x33, 0xf2, 0xaa, 0x28, + 0xc0, 0x3c, 0xc7, 0xb1, 0xc9, 0x18, 0xfb, 0xea, 0x1b, 0xcf, 0x0e, 0xdc, + 0x78, 0x7a, 0x7f, 0x91, 0xbb, 0xd1, 0xd4, 0x51, 0xd4, 0x15, 0x0c, 0x12, + 0x45, 0xc7, 0x32, 0xee, 0x32, 0x3d, 0xb6, 0x3a, 0xf6, 0x17, 0xc3, 0xde, + 0x18, 0xa4, 0xe1, 0x4e, 0x16, 0x86, 0xd3, 0x4d, 0x1a, 0x34, 0xe2, 0x3c, + 0xcd, 0x37, 0x42, 0xed, 0xd7, 0xf4, 0xdf, 0x03, 0x59, 0x17, 0xfb, 0x4c, + 0xd9, 0x2a, 0x9a, 0xef, 0x6f, 0xbe, 0x63, 0xfd, 0xdd, 0xe9, 0xc5, 0x3b, + 0x80, 0x33, 0xc8, 0xe0, 0x92, 0x37, 0xf7, 0xe6, 0xfd, 0xb4, 0x9c, 0xb0, + 0xdb, 0x14, 0xcc, 0xf9, 0x31, 0xd2, 0x30, 0x6a, 0x88, 0xfc, 0x4e, 0x58, + 0x23, 0xfa, 0x9b, 0x73, 0xf6, 0xd3, 0x1b, 0xfd, 0xc2, 0x08, 0xbe, 0x16, + 0x4b, 0x60, 0x68, 0xa4, 0x79, 0x0d, 0xcc, 0x56, 0x2b, 0x96, 0xd8, 0x2f, + 0x86, 0x50, 0x29, 0xf7, 0xd6, 0x91, 0xc1, 0xdc, 0x22, 0xf7, 0xdf, 0x87, + 0x15, 0xf1, 0x5b, 0xad, 0x1f, 0x3d, 0x75, 0xa9, 0xae, 0x44, 0x86, 0x53, + 0x85, 0x58, 0x15, 0x14, 0x64, 0xb3, 0x1e, 0x80, 0x86, 0xe8, 0x3e, 0xf8, + 0xdb, 0x55, 0xcb, 0x47, 0xc3, 0xeb, 0x97, 0x12, 0xde, 0xeb, 0x78, 0x66, + 0x26, 0x8a, 0x29, 0xe0, 0x49, 0x8c, 0x85, 0xf7, 0x55, 0xe4, 0x38, 0x03, + 0x3e, 0xe7, 0x03, 0x3e, 0xfa, 0x4e, 0x37, 0xe5, 0x60, 0x24, 0x62, 0xf6, + 0xfc, 0xcf, 0x72, 0x46, 0xe5, 0x3c, 0xb0, 0x9c, 0xf5, 0xfc, 0x69, 0xb5, + 0xa1, 0x26, 0x6e, 0x28, 0x49, 0x23, 0x38, 0xf0, 0xc6, 0x7f, 0x04, 0x63, + 0xfc, 0xc6, 0xa3, 0xae, 0xb3, 0xd4, 0xf0, 0xed, 0xda, 0xb6, 0xd1, 0x72, + 0xa7, 0x68, 0x6a, 0xe9, 0xe4, 0x2a, 0xc0, 0x8d, 0x9b, 0x7e, 0xa0, 0xfa, + 0x77, 0x1a, 0xd0, 0x7e, 0x18, 0xfc, 0x3e, 0xba, 0xf1, 0x05, 0xc1, 0x27, + 0x86, 0x9c, 0xac, 0x4e, 0x57, 0xce, 0x0e, 0x47, 0x2e, 0xdb, 0x93, 0xdb, + 0xd7, 0x1a, 0xd1, 0x9b, 0x22, 0x8c, 0x2d, 0x91, 0xa2, 0xdb, 0xf0, 0xe9, + 0x6a, 0x65, 0xa1, 0xe2, 0x69, 0x12, 0x37, 0x4a, 0xb7, 0xb7, 0x83, 0x1b, + 0x03, 0x96, 0x74, 0x0c, 0x32, 0xa0, 0x6d, 0xd8, 0x75, 0xd6, 0x7d, 0x4b, + 0xc3, 0x57, 0x66, 0xb5, 0xcd, 0x75, 0x4b, 0x75, 0x4c, 0x74, 0x71, 0xbf, + 0xfc, 0x5f, 0x05, 0x82, 0x05, 0xed, 0xb9, 0x1e, 0xfa, 0xd6, 0xef, 0xe6, + 0xdd, 0xc1, 0xd7, 0x81, 0x65, 0xb4, 0xb1, 0x92, 0xe2, 0x22, 0x06, 0x5a, + 0x85, 0xcf, 0x90, 0x64, 0x6d, 0xef, 0x9c, 0x74, 0xd7, 0x1c, 0x4f, 0x54, + 0x78, 0xae, 0xd8, 0x54, 0x54, 0x57, 0xc3, 0x3d, 0x1c, 0x3f, 0xfe, 0x3a, + 0x4b, 0xfc, 0x83, 0x1a, 0x8f, 0xf0, 0x6c, 0x33, 0x9c, 0x6f, 0xae, 0x3e, + 0x3d, 0x46, 0xce, 0x7a, 0xb6, 0x2a, 0x8c, 0x9e, 0xa5, 0xa7, 0xf0, 0xa9, + 0xe2, 0x2f, 0xb5, 0x3e, 0x54, 0x0c, 0x0c, 0x82, 0x4e, 0xfb, 0xeb, 0xd2, + 0x56, 0xbb, 0x85, 0xf3, 0xff, 0x00, 0x4f, 0x58, 0x55, 0xea, 0x26, 0x8e, + 0x96, 0x6a, 0x28, 0x52, 0x61, 0x1a, 0x8f, 0x11, 0xb2, 0xa3, 0x05, 0x7e, + 0xfa, 0xf3, 0x7a, 0xe6, 0x40, 0x91, 0x92, 0x10, 0xf8, 0xb9, 0x3e, 0xc3, + 0x04, 0x1d, 0x7a, 0x37, 0xe1, 0xe7, 0x11, 0x40, 0x96, 0x98, 0xa2, 0xa6, + 0x11, 0x2b, 0x2c, 0x31, 0xaa, 0x34, 0xa7, 0x03, 0xc3, 0x5d, 0xca, 0xfd, + 0xfb, 0xea, 0x6b, 0x1c, 0x54, 0xa2, 0x9b, 0xa2, 0xf1, 0xe4, 0x49, 0xf2, + 0x5a, 0x2a, 0xe9, 0x2a, 0xad, 0xf4, 0x4e, 0x63, 0x9a, 0x69, 0xa4, 0x46, + 0xfe, 0x4b, 0x4a, 0xd9, 0x0a, 0x3f, 0xab, 0x9b, 0x03, 0x73, 0xdf, 0x18, + 0xce, 0x47, 0x5d, 0x79, 0xeb, 0x8e, 0xef, 0xd5, 0xfc, 0x59, 0xc5, 0x4e, + 0x22, 0xa7, 0x65, 0x8a, 0x91, 0x1a, 0x00, 0xef, 0x19, 0x8d, 0xf6, 0x62, + 0x72, 0xc0, 0xf4, 0x27, 0xd3, 0xb6, 0xb6, 0x4e, 0x3c, 0xa2, 0xbe, 0x7f, + 0xe9, 0xa8, 0xae, 0xb4, 0x33, 0x3f, 0x38, 0x98, 0x4c, 0xbe, 0x0e, 0x23, + 0xe4, 0x42, 0x7a, 0xb2, 0x0c, 0xf3, 0x11, 0x91, 0xdf, 0x4c, 0x78, 0x22, + 0xc1, 0x41, 0x15, 0x6d, 0x35, 0x6c, 0xa2, 0x3a, 0xeb, 0x93, 0xc2, 0x64, + 0x9a, 0xa7, 0x1e, 0x45, 0x7c, 0x82, 0x0e, 0x0e, 0xe4, 0xef, 0xb1, 0xf4, + 0x1a, 0x76, 0x15, 0x2c, 0x72, 0xb6, 0xbb, 0x34, 0xed, 0xba, 0x47, 0xff, + 0xd9 +}; + +void +jpeg_get_video_info (VideoDecodeInfo * info) +{ + info->profile = GST_VAAPI_PROFILE_JPEG_BASELINE; + info->width = JPEG_CLIP_WIDTH; + info->height = JPEG_CLIP_HEIGHT; + info->data = jpeg_clip; + info->data_size = JPEG_CLIP_DATA_SIZE; +} diff --git a/tests/internal/test-jpeg.h b/tests/internal/test-jpeg.h new file mode 100644 index 0000000000..9fa3ed1b29 --- /dev/null +++ b/tests/internal/test-jpeg.h @@ -0,0 +1,31 @@ +/* + * test-jpeg.h - JPEG test data + * + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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 TEST_JPEG_H +#define TEST_JPEG_H + +#include +#include "test-decode.h" + +void jpeg_get_video_info(VideoDecodeInfo *info); + +#endif /* TEST_JPEG_H */ diff --git a/tests/internal/test-mpeg2.c b/tests/internal/test-mpeg2.c new file mode 100644 index 0000000000..16e69b7362 --- /dev/null +++ b/tests/internal/test-mpeg2.c @@ -0,0 +1,1651 @@ +/* + * test-mpeg2.c - MPEG-2 test data + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "test-mpeg2.h" + +#define MPEG2_CLIP_WIDTH 320 +#define MPEG2_CLIP_HEIGHT 240 +#define MPEG2_CLIP_DATA_SIZE 19311 + +/* Data dump of a 320x240 MPEG-2 video clip (mpeg2.m2v), it has a single frame */ +static const guchar mpeg2_clip[MPEG2_CLIP_DATA_SIZE] = { + 0x00, 0x00, 0x01, 0xb3, 0x14, 0x00, 0xf0, 0x12, 0x07, 0x53, 0x23, 0x80, + 0x00, 0x00, 0x01, 0xb5, 0x14, 0x8a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xb5, 0x2b, 0x02, 0x02, 0x02, 0x05, 0x02, 0x07, 0x80, 0x00, 0x00, + 0x01, 0xb8, 0x00, 0x08, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0f, + 0xff, 0xf8, 0x00, 0x00, 0x01, 0xb5, 0x8f, 0xff, 0xf7, 0x5d, 0x80, 0x00, + 0x00, 0x01, 0x01, 0x43, 0xf8, 0x90, 0x03, 0xee, 0x36, 0xd4, 0x92, 0x85, + 0x86, 0x37, 0x48, 0x01, 0xb3, 0xf7, 0x9a, 0x1d, 0x5c, 0x38, 0xb1, 0x95, + 0xb9, 0x42, 0x43, 0xb2, 0xc2, 0x51, 0x24, 0x31, 0xb2, 0xed, 0x20, 0x73, + 0xd9, 0x08, 0xcc, 0x5b, 0xe2, 0x39, 0xbc, 0xdb, 0x12, 0xb7, 0x8c, 0x31, + 0xbf, 0x6c, 0x00, 0xc3, 0xeb, 0xc3, 0xd0, 0x6c, 0x3e, 0x16, 0xde, 0xa8, + 0x89, 0xf3, 0xc1, 0x17, 0xda, 0x5a, 0x4f, 0xca, 0xb0, 0x6b, 0x7c, 0x07, + 0xbb, 0x6c, 0x95, 0x8f, 0x74, 0x35, 0xaa, 0x45, 0x65, 0xb4, 0x35, 0xbf, + 0xd4, 0x22, 0xab, 0xfe, 0x80, 0x07, 0x7c, 0xed, 0x7a, 0x97, 0x2b, 0xaf, + 0x2f, 0x72, 0x64, 0x81, 0x86, 0x0f, 0x6f, 0x9a, 0x7b, 0x02, 0x10, 0x07, + 0x76, 0x2f, 0x01, 0x30, 0x01, 0x2d, 0x21, 0x37, 0x89, 0xbc, 0x74, 0x00, + 0xf4, 0xc3, 0x6b, 0xa4, 0x1f, 0x65, 0xa7, 0xb6, 0xff, 0x6d, 0x9f, 0x6f, + 0x6f, 0x77, 0xa8, 0x5b, 0xa7, 0x95, 0x90, 0x2e, 0x2b, 0x71, 0xec, 0x35, + 0xf4, 0x96, 0x92, 0x33, 0xa9, 0x92, 0x48, 0xdf, 0xcf, 0x50, 0x39, 0x13, + 0xd1, 0xbd, 0x25, 0x4f, 0xbe, 0x5b, 0x10, 0x25, 0x6e, 0x14, 0xdc, 0x5e, + 0xe0, 0x7b, 0x7a, 0x3d, 0x04, 0x2f, 0xf2, 0xb8, 0x84, 0x38, 0xdd, 0x16, + 0x94, 0xdb, 0x46, 0xfd, 0xdf, 0x3a, 0x00, 0x7a, 0xf9, 0x49, 0x45, 0xb7, + 0x52, 0xe9, 0x03, 0x9a, 0x4a, 0x40, 0xf8, 0x14, 0xdc, 0xa7, 0x4d, 0xf7, + 0xbc, 0x25, 0x04, 0xa0, 0x04, 0x2a, 0x81, 0x6d, 0xda, 0x36, 0x67, 0x1b, + 0xb8, 0x48, 0x96, 0xb7, 0x49, 0xea, 0xd9, 0x1c, 0x8d, 0xf8, 0xfb, 0x80, + 0x07, 0x50, 0x9c, 0x13, 0x43, 0xae, 0x94, 0x07, 0x36, 0xff, 0x8b, 0x00, + 0x1c, 0x8a, 0x35, 0x00, 0x20, 0x49, 0x40, 0xdb, 0x74, 0x05, 0x82, 0x10, + 0x03, 0xcd, 0x28, 0x29, 0x06, 0x56, 0xf1, 0x2f, 0xc0, 0x03, 0xd1, 0x22, + 0x26, 0xd0, 0x08, 0x0a, 0x03, 0x4d, 0x27, 0x37, 0x5d, 0x2f, 0x36, 0xb7, + 0xe9, 0xef, 0x7a, 0x00, 0xd0, 0x83, 0xe5, 0x14, 0x65, 0x8a, 0x62, 0xd9, + 0xe2, 0x31, 0xb8, 0x3e, 0xef, 0x15, 0xbd, 0xdc, 0xb8, 0xf4, 0xa3, 0x4a, + 0xb9, 0x36, 0x1c, 0xde, 0xe7, 0x41, 0x08, 0x01, 0xb8, 0x79, 0xe0, 0x11, + 0x4a, 0xbe, 0x07, 0xca, 0xdf, 0x2d, 0xea, 0x5d, 0x11, 0x99, 0xb0, 0x2c, + 0x3a, 0x6e, 0x41, 0xaa, 0x5b, 0x23, 0xf2, 0xb5, 0x5a, 0x41, 0xcd, 0xd8, + 0x42, 0xad, 0xf7, 0x78, 0xc8, 0x2d, 0xdc, 0x51, 0x70, 0x72, 0xcc, 0xd8, + 0xb4, 0x75, 0x85, 0x43, 0x94, 0x25, 0xbd, 0x5e, 0xf9, 0x3c, 0x49, 0xbc, + 0xe5, 0xa3, 0x2b, 0xb8, 0x49, 0x0a, 0x26, 0xd2, 0xa7, 0xea, 0x8d, 0xfd, + 0xb1, 0xf7, 0xdd, 0x22, 0x8b, 0xef, 0xce, 0x5a, 0x51, 0x66, 0x64, 0x33, + 0x8a, 0x85, 0x53, 0xc0, 0x7b, 0x51, 0x22, 0x34, 0xe8, 0xd7, 0xd0, 0x09, + 0x8f, 0x5a, 0x53, 0xb8, 0x54, 0x1b, 0x4b, 0x2c, 0xbb, 0xaa, 0x18, 0xd5, + 0x69, 0x6d, 0xd2, 0xfa, 0xba, 0x5b, 0x7c, 0x67, 0xc9, 0x37, 0x51, 0x02, + 0x37, 0x8a, 0x6a, 0xec, 0x2b, 0x03, 0x94, 0xe4, 0x1e, 0xad, 0xce, 0x96, + 0x95, 0x84, 0x34, 0x5a, 0x38, 0x63, 0x58, 0x90, 0x44, 0x0e, 0xa1, 0x35, + 0xf4, 0xa0, 0xf3, 0xe1, 0x55, 0x0a, 0x46, 0x12, 0x5b, 0x93, 0x2c, 0x0c, + 0x95, 0x51, 0x62, 0x94, 0x34, 0x34, 0x2d, 0xaa, 0x36, 0x8d, 0xf3, 0xbb, + 0x0e, 0xe3, 0x37, 0x54, 0x02, 0x32, 0x83, 0x29, 0xd0, 0xea, 0xce, 0x7e, + 0x95, 0x3c, 0x26, 0x9a, 0xd0, 0xcb, 0x9c, 0xba, 0xa8, 0x49, 0x8e, 0x2d, + 0x68, 0x4d, 0x65, 0xa9, 0xaa, 0x05, 0xb2, 0x8c, 0x37, 0xe9, 0x5e, 0xfc, + 0x00, 0x7a, 0xe7, 0x4e, 0x1e, 0xa3, 0xe5, 0x9b, 0xb9, 0x42, 0x52, 0xc3, + 0xe3, 0x3f, 0x3f, 0x39, 0x86, 0x59, 0xb8, 0x80, 0x2a, 0xa9, 0x65, 0x3d, + 0xa9, 0xd4, 0xfb, 0xf4, 0xf9, 0x65, 0x1e, 0xa9, 0x62, 0x6c, 0x18, 0x30, + 0xf8, 0xdb, 0x5f, 0xb7, 0x8e, 0xde, 0xe7, 0x1b, 0xe2, 0x84, 0xc0, 0x86, + 0xe3, 0x71, 0x37, 0x0a, 0x0b, 0x29, 0xbc, 0xe4, 0x33, 0x31, 0xbd, 0x1c, + 0xf3, 0x40, 0x1e, 0xee, 0x3b, 0x4c, 0x5f, 0xd0, 0x21, 0x00, 0x36, 0x96, + 0x3c, 0x7b, 0x76, 0xbd, 0xe9, 0xb5, 0xfd, 0x74, 0x81, 0xb6, 0xba, 0xdc, + 0x25, 0x14, 0xde, 0x6f, 0xda, 0x80, 0x1f, 0xa4, 0xf3, 0x08, 0x0b, 0x38, + 0x68, 0x6b, 0x75, 0x48, 0xdc, 0x52, 0x27, 0x1e, 0xf6, 0xa8, 0x0a, 0xaf, + 0x91, 0xb9, 0x68, 0x48, 0x67, 0x8b, 0x70, 0xf7, 0xc7, 0x96, 0x3a, 0x5f, + 0x59, 0x22, 0x59, 0xe2, 0xdc, 0xd7, 0x0c, 0xb9, 0x40, 0x07, 0xad, 0xf0, + 0x7e, 0x82, 0x74, 0x8c, 0x01, 0x6a, 0xe9, 0x63, 0x75, 0xcf, 0x59, 0x43, + 0xa1, 0x92, 0x04, 0x37, 0x86, 0xe2, 0xa5, 0x74, 0x50, 0x90, 0x1c, 0x43, + 0x3c, 0x6d, 0xf0, 0x18, 0xdb, 0xf6, 0xce, 0x24, 0x28, 0x29, 0xb9, 0xb4, + 0xac, 0xc0, 0x29, 0xbd, 0x2d, 0xab, 0xb6, 0xa3, 0x6a, 0xdf, 0xa6, 0x8e, + 0x73, 0xc5, 0xbb, 0x99, 0x90, 0x04, 0x66, 0x17, 0xea, 0xa7, 0xb7, 0xa5, + 0xe4, 0xa7, 0x6e, 0x69, 0x41, 0xbf, 0x9a, 0x60, 0xf3, 0xe0, 0xc6, 0x41, + 0x74, 0x02, 0xbe, 0x38, 0x7e, 0x50, 0x4a, 0xff, 0xd9, 0x2d, 0x0d, 0x29, + 0x7c, 0x1b, 0xaa, 0x27, 0x5c, 0x00, 0xdb, 0xfa, 0x20, 0x5b, 0xe2, 0x52, + 0xe5, 0x8f, 0x11, 0xa6, 0xd8, 0x58, 0x6a, 0x52, 0x15, 0x6d, 0x0b, 0xb5, + 0x40, 0xb6, 0x4d, 0xf0, 0x35, 0xb3, 0x76, 0xfa, 0xfe, 0x4b, 0xd0, 0x08, + 0x31, 0xb4, 0x40, 0x1a, 0xab, 0x62, 0x80, 0x84, 0x01, 0x35, 0xe0, 0x9b, + 0xff, 0xb2, 0x12, 0x19, 0x53, 0x94, 0x96, 0xd2, 0xdd, 0xbb, 0x0a, 0x66, + 0xd0, 0x1a, 0x36, 0x21, 0x40, 0x85, 0xff, 0x1b, 0x8f, 0x9e, 0xa6, 0x2a, + 0xb7, 0x75, 0xe3, 0x09, 0x0d, 0xb4, 0x18, 0xd4, 0xdd, 0xaf, 0x0e, 0x70, + 0xba, 0x4a, 0x56, 0xe5, 0x11, 0x4f, 0x95, 0x28, 0x0a, 0xa8, 0xc6, 0xf4, + 0x77, 0xf3, 0x79, 0x52, 0x4b, 0x4a, 0x5a, 0xb7, 0x3e, 0x7e, 0x6d, 0x24, + 0x23, 0x44, 0x2d, 0x5b, 0xc2, 0x2d, 0x76, 0x6d, 0xa4, 0x3a, 0xdd, 0x61, + 0x30, 0x00, 0xfe, 0x61, 0x26, 0x46, 0xfa, 0x10, 0x03, 0xf2, 0x2e, 0x00, + 0x16, 0xfd, 0xb1, 0xfe, 0xdb, 0x32, 0x95, 0xa5, 0x08, 0xaf, 0x9c, 0xc1, + 0xc5, 0x28, 0x6b, 0x7a, 0x80, 0x02, 0xd1, 0x16, 0xfb, 0xbc, 0x56, 0xe0, + 0x5e, 0x8f, 0x75, 0x0d, 0x81, 0xac, 0x13, 0x21, 0xa4, 0x8a, 0x48, 0x63, + 0x62, 0x42, 0xe3, 0x7e, 0xc1, 0xe0, 0x0f, 0xf9, 0x00, 0x72, 0x28, 0x4d, + 0x14, 0xfb, 0x92, 0x1d, 0x8e, 0xb6, 0xa6, 0x58, 0x5d, 0xf4, 0xac, 0x7e, + 0x40, 0x15, 0x80, 0x19, 0x7b, 0x3d, 0xf3, 0x65, 0xc2, 0xa7, 0x2e, 0xc3, + 0xee, 0xc5, 0x28, 0xe6, 0x4f, 0xf8, 0xbf, 0x6f, 0x97, 0x0b, 0xe3, 0xae, + 0xf5, 0x4a, 0x2f, 0x69, 0x61, 0x63, 0x5b, 0xb6, 0x46, 0x00, 0x63, 0x74, + 0x4a, 0xdc, 0xd7, 0xe5, 0x4c, 0x42, 0xdb, 0x1d, 0xe3, 0x7b, 0xa4, 0xd7, + 0x8d, 0x28, 0x32, 0x35, 0x99, 0x75, 0x4b, 0x78, 0x64, 0x0c, 0x8d, 0xfc, + 0xa0, 0x00, 0x9c, 0x59, 0x10, 0x89, 0x79, 0x77, 0xc8, 0xa7, 0x95, 0x0d, + 0xc7, 0x96, 0x51, 0x87, 0xc5, 0xad, 0x84, 0x01, 0x1b, 0xaf, 0xdc, 0x40, + 0xa1, 0x79, 0xce, 0x52, 0xe5, 0x93, 0x1e, 0x56, 0x55, 0x01, 0xec, 0xf5, + 0x6f, 0xd0, 0xa4, 0x6f, 0xe8, 0x01, 0xef, 0xc4, 0xde, 0x49, 0xef, 0x5b, + 0x36, 0x6c, 0x3a, 0xa5, 0x2e, 0x56, 0xee, 0xdd, 0x98, 0x62, 0x5a, 0x15, + 0xb4, 0xb4, 0x6e, 0xfd, 0x44, 0x21, 0x96, 0x31, 0xba, 0x1f, 0x62, 0x20, + 0x0f, 0x98, 0x00, 0x00, 0x01, 0x02, 0x43, 0xf8, 0x37, 0x13, 0x05, 0xdd, + 0xbe, 0xa9, 0x4b, 0x6c, 0xa2, 0xbc, 0xc5, 0x6e, 0x6c, 0x21, 0x12, 0x23, + 0x77, 0x3e, 0x68, 0x05, 0xa2, 0xdf, 0x8e, 0xcf, 0x02, 0xe1, 0x60, 0x73, + 0x79, 0x09, 0x08, 0x0e, 0x74, 0x25, 0x49, 0x1b, 0xcc, 0x42, 0xca, 0x21, + 0xb7, 0x90, 0xdf, 0x40, 0x10, 0xff, 0xe7, 0x1d, 0x2e, 0x92, 0x59, 0x94, + 0x80, 0x94, 0xbf, 0x16, 0xe7, 0xdc, 0x34, 0xb6, 0xd7, 0xb0, 0xd9, 0x2d, + 0x50, 0x81, 0xc5, 0x35, 0x0f, 0x6a, 0x6f, 0xd4, 0xea, 0xfd, 0x5e, 0xa0, + 0x03, 0x0a, 0xad, 0xc9, 0xee, 0x5f, 0x8e, 0x78, 0xb2, 0xc0, 0xc0, 0xe2, + 0xbd, 0x4a, 0x46, 0xd5, 0xed, 0x27, 0x2e, 0xe1, 0xea, 0x13, 0x76, 0xd1, + 0xc1, 0x65, 0x90, 0x99, 0xb6, 0x00, 0x1a, 0x24, 0x9e, 0x12, 0x87, 0xc8, + 0x14, 0x96, 0x10, 0xda, 0x60, 0x74, 0xd0, 0x2d, 0x85, 0x30, 0xaa, 0xdf, + 0x15, 0xff, 0x9c, 0x02, 0xaa, 0x36, 0xdb, 0x2d, 0xdb, 0x9b, 0xa0, 0x10, + 0xc4, 0x94, 0x87, 0x1b, 0x3e, 0x02, 0x17, 0xfc, 0x6b, 0x88, 0x70, 0xf4, + 0x21, 0x37, 0x7c, 0x5c, 0x9c, 0xba, 0xda, 0xac, 0x13, 0x59, 0x1f, 0x1b, + 0xca, 0x2b, 0x30, 0x5e, 0xe3, 0xa2, 0x78, 0xd0, 0xe2, 0x43, 0x7b, 0x87, + 0x53, 0x70, 0xbc, 0xa1, 0xb0, 0xf8, 0x12, 0xde, 0x44, 0x01, 0xf8, 0xaa, + 0x94, 0xf9, 0x43, 0x71, 0x51, 0xb4, 0x3f, 0x20, 0x9e, 0x6c, 0x49, 0x03, + 0x75, 0x76, 0x86, 0x42, 0x96, 0x95, 0x2b, 0x5a, 0x07, 0xb6, 0xfc, 0x97, + 0x8d, 0xfa, 0x7f, 0xa3, 0xcd, 0x91, 0xe6, 0x78, 0xc2, 0xc2, 0x5b, 0x77, + 0x7b, 0x48, 0xf6, 0x3d, 0x03, 0x21, 0xbd, 0x62, 0x58, 0x16, 0xb1, 0xbc, + 0xdc, 0xe7, 0xce, 0x77, 0x2b, 0xf4, 0x05, 0x7d, 0x29, 0x30, 0x69, 0xf2, + 0x37, 0x55, 0xd8, 0x00, 0x73, 0x3b, 0x89, 0x02, 0xad, 0x2c, 0x84, 0x3d, + 0xb0, 0x43, 0x25, 0x6c, 0x2c, 0x4a, 0xab, 0xe8, 0xde, 0x7d, 0xe3, 0x40, + 0x1d, 0x3f, 0xb7, 0x89, 0x90, 0x35, 0x1d, 0x76, 0xa8, 0xd2, 0x6c, 0x2d, + 0x28, 0x5b, 0x78, 0xb7, 0xf3, 0x7e, 0x57, 0xcc, 0x22, 0x49, 0xdd, 0x2a, + 0xa0, 0xd2, 0x83, 0x29, 0x6d, 0xf6, 0x3d, 0xbe, 0x73, 0x1c, 0x80, 0x10, + 0x45, 0x25, 0xa9, 0x5e, 0xad, 0xe0, 0xc5, 0xf2, 0x00, 0x70, 0x27, 0x84, + 0xd8, 0xa7, 0xee, 0xee, 0x59, 0x9b, 0x83, 0x40, 0x79, 0x22, 0xb5, 0x38, + 0x0c, 0xc5, 0x6e, 0x8c, 0xa0, 0x16, 0x87, 0x90, 0xa3, 0x6f, 0xed, 0x2f, + 0x0f, 0xf3, 0x59, 0x20, 0x13, 0x0f, 0x2d, 0x4e, 0x0a, 0x30, 0x39, 0x84, + 0xd3, 0x69, 0x8b, 0x92, 0x04, 0x17, 0x8e, 0x81, 0x1b, 0x15, 0x6e, 0x8e, + 0x29, 0xb8, 0x9c, 0x39, 0x53, 0x12, 0x5a, 0x51, 0x65, 0x42, 0xa4, 0x2b, + 0xd2, 0x9c, 0xdb, 0x38, 0x9e, 0x7a, 0x8b, 0x42, 0x4b, 0x2c, 0x30, 0xe4, + 0x6e, 0x88, 0x53, 0x7a, 0x27, 0xc6, 0xf0, 0xe8, 0x21, 0x00, 0x45, 0x28, + 0x92, 0xb5, 0x46, 0x1e, 0x7b, 0x64, 0x32, 0x6c, 0x9e, 0x31, 0x15, 0x15, + 0xb7, 0xe1, 0x68, 0x52, 0x80, 0x8a, 0xd1, 0xcd, 0xa2, 0x6d, 0xe6, 0x3f, + 0x65, 0xaa, 0x33, 0x0a, 0xc9, 0x12, 0x05, 0xa8, 0xd0, 0x86, 0x6c, 0x37, + 0xc6, 0xd8, 0x85, 0x94, 0x07, 0x36, 0x7e, 0xad, 0xeb, 0x92, 0x45, 0x2d, + 0xb6, 0x69, 0x99, 0xb8, 0x50, 0x16, 0xdc, 0x30, 0x43, 0x00, 0x77, 0x3a, + 0x80, 0x0c, 0x59, 0x1c, 0xd9, 0xcf, 0xc6, 0xd6, 0xf4, 0x11, 0xb0, 0x00, + 0xf4, 0x5e, 0x15, 0xe2, 0x91, 0x07, 0xb7, 0xad, 0xc9, 0x99, 0xed, 0x53, + 0x03, 0x22, 0xea, 0xcb, 0x40, 0x44, 0x3c, 0x73, 0x78, 0x31, 0x91, 0xbd, + 0x75, 0x04, 0x2f, 0xf7, 0xde, 0xc9, 0x20, 0x73, 0x61, 0x69, 0xcd, 0x82, + 0x90, 0x7c, 0x90, 0x86, 0xdd, 0x32, 0x25, 0x75, 0xd9, 0x03, 0x10, 0xec, + 0xb7, 0xc0, 0x73, 0x74, 0x76, 0x65, 0xce, 0x6c, 0xd0, 0x83, 0x65, 0x90, + 0x34, 0x7b, 0x70, 0xdc, 0x1d, 0xe6, 0x70, 0x46, 0x4c, 0xe0, 0xaf, 0x1a, + 0xdd, 0xcd, 0x04, 0x20, 0x08, 0xda, 0x62, 0x04, 0xaa, 0xcf, 0x45, 0x52, + 0x4b, 0x68, 0x37, 0x21, 0x21, 0xb6, 0xda, 0x01, 0x52, 0xe1, 0x0a, 0x96, + 0xdf, 0x21, 0x7c, 0x8f, 0xf5, 0x8d, 0x6f, 0x60, 0x85, 0xfe, 0x0e, 0x11, + 0x08, 0x66, 0xd2, 0x11, 0x4b, 0x58, 0x6c, 0xa9, 0x55, 0xbd, 0x08, 0xb9, + 0x48, 0xbd, 0xd3, 0x82, 0x90, 0xc8, 0x07, 0xb6, 0x81, 0xad, 0xe7, 0x37, + 0xd0, 0xa5, 0x18, 0x07, 0x36, 0x5e, 0x4a, 0x76, 0x72, 0x42, 0xbe, 0x44, + 0xb6, 0xd6, 0x8a, 0x8c, 0xbc, 0xda, 0xf7, 0x3a, 0xe6, 0x50, 0xbc, 0xa9, + 0xe8, 0x74, 0xa4, 0xb6, 0x89, 0xf8, 0xad, 0x03, 0x5b, 0xa3, 0x98, 0x96, + 0x69, 0x25, 0x5a, 0xc2, 0x3a, 0x8a, 0xc3, 0x70, 0xa1, 0xf1, 0x1e, 0x9b, + 0x21, 0xc1, 0x95, 0xae, 0xae, 0x27, 0x79, 0x4b, 0x09, 0x11, 0xba, 0xe4, + 0x6c, 0x00, 0xb3, 0xaf, 0x32, 0x6d, 0x1c, 0x41, 0xf3, 0x96, 0x58, 0x01, + 0xfb, 0x73, 0x3a, 0xc4, 0x90, 0x96, 0x48, 0x60, 0xf9, 0x63, 0x7e, 0x28, + 0x8b, 0x28, 0x9e, 0xa6, 0x1b, 0x03, 0x15, 0x64, 0x41, 0xad, 0xec, 0xbe, + 0x5d, 0xaf, 0x15, 0x9a, 0xfc, 0x81, 0xb7, 0x0e, 0xa9, 0xea, 0xd9, 0xba, + 0xcb, 0x61, 0xa5, 0xd0, 0xc5, 0x1c, 0xde, 0x87, 0xcf, 0x8f, 0xed, 0x11, + 0x98, 0x2f, 0x29, 0x69, 0x70, 0x02, 0xb7, 0xe4, 0x85, 0xcf, 0x05, 0xa3, + 0x1a, 0xf2, 0x17, 0x11, 0x93, 0x7d, 0xb0, 0x06, 0x7b, 0x99, 0xa4, 0x7e, + 0xa9, 0x03, 0x99, 0x2a, 0x79, 0xc7, 0x3f, 0x52, 0xde, 0x29, 0x94, 0xa5, + 0x8a, 0x4b, 0x8d, 0xe3, 0xdf, 0xf9, 0x6f, 0xba, 0x80, 0x3d, 0x15, 0xfe, + 0x00, 0x7d, 0x9e, 0xfc, 0x7b, 0x91, 0x93, 0x62, 0xe9, 0x3f, 0x9c, 0xcf, + 0x27, 0x07, 0xdb, 0x46, 0x16, 0x5a, 0xc6, 0xe2, 0x8b, 0xfb, 0xe8, 0x02, + 0x37, 0x88, 0x77, 0xc4, 0x1c, 0x95, 0x64, 0xaf, 0xde, 0x6c, 0xf2, 0x85, + 0x41, 0xc5, 0xb2, 0xb6, 0x57, 0xcb, 0x28, 0xf4, 0x89, 0x19, 0xd1, 0x96, + 0x50, 0xa6, 0xfc, 0xf7, 0xfc, 0x53, 0xfd, 0xc8, 0xf9, 0x9c, 0x3e, 0x06, + 0x27, 0x39, 0x78, 0xd4, 0x01, 0x5c, 0xa8, 0xa7, 0x0e, 0x6f, 0xd4, 0x42, + 0x01, 0x0b, 0xfc, 0xfe, 0x04, 0xb8, 0x84, 0xf9, 0x6c, 0xf0, 0x2c, 0xa6, + 0xc9, 0xfd, 0xdb, 0xfe, 0xfa, 0x72, 0xb6, 0x84, 0x38, 0xd4, 0x7f, 0xa8, + 0xea, 0xda, 0x44, 0xe0, 0x01, 0x9f, 0xb8, 0xbd, 0x72, 0x86, 0x99, 0x52, + 0x42, 0x14, 0x6e, 0xbd, 0x86, 0xee, 0x12, 0xe4, 0x6e, 0xbd, 0x86, 0xee, + 0x12, 0xe4, 0x6e, 0x90, 0x07, 0xbe, 0xfd, 0xf3, 0xcc, 0x86, 0x3e, 0xd4, + 0x92, 0x01, 0x87, 0x64, 0x5f, 0x16, 0xe9, 0x09, 0xef, 0x9d, 0x7d, 0xb6, + 0xbf, 0x68, 0xd5, 0x6d, 0x6d, 0xe0, 0x80, 0x14, 0x68, 0x20, 0x80, 0xaf, + 0xde, 0x73, 0xce, 0x50, 0xc9, 0xc4, 0x3b, 0x68, 0xcf, 0x46, 0xdd, 0x4b, + 0x3d, 0xb5, 0x54, 0xdb, 0x1b, 0xe7, 0x00, 0x3d, 0xfa, 0x40, 0x07, 0x8f, + 0xc7, 0x11, 0xf1, 0x5e, 0x55, 0x5a, 0xe7, 0x47, 0x47, 0xe4, 0x9e, 0x6a, + 0x88, 0x10, 0xdf, 0x17, 0x11, 0xf1, 0x84, 0x6b, 0xd0, 0x05, 0x84, 0xe9, + 0x3f, 0x44, 0xe9, 0x62, 0x5c, 0x1a, 0xdf, 0x4e, 0x00, 0x78, 0x00, 0xbb, + 0xb1, 0x3d, 0x63, 0x9f, 0xc6, 0x3e, 0x9a, 0xb2, 0xed, 0x19, 0xb1, 0xb1, + 0x00, 0x39, 0x00, 0x71, 0xf2, 0x00, 0xe0, 0x01, 0x97, 0x4e, 0xce, 0xf9, + 0xcd, 0xc8, 0x31, 0xf6, 0xea, 0x24, 0x31, 0xa0, 0xe8, 0xdc, 0xd4, 0xac, + 0x2e, 0xc6, 0x00, 0x00, 0x01, 0x03, 0x43, 0xf9, 0x6d, 0x84, 0xef, 0x3a, + 0x09, 0x80, 0x07, 0x34, 0x90, 0xde, 0x07, 0x7f, 0x39, 0x63, 0x7b, 0xb7, + 0x1b, 0xc6, 0xf3, 0x32, 0xc0, 0x8d, 0xe0, 0xbb, 0x14, 0x2a, 0x56, 0xf2, + 0x02, 0xdc, 0x4f, 0xe5, 0xf3, 0x3c, 0x7c, 0xdc, 0x5a, 0x1c, 0x7a, 0x37, + 0x04, 0xa6, 0x48, 0xad, 0xe3, 0xa1, 0x6d, 0xd7, 0x6d, 0x55, 0x38, 0x32, + 0x35, 0x87, 0xed, 0x02, 0x9b, 0x47, 0x21, 0xeb, 0x93, 0xd6, 0x56, 0xae, + 0x97, 0x24, 0x9b, 0xe2, 0x35, 0xb3, 0x83, 0x99, 0x46, 0xdd, 0xf0, 0x00, + 0xec, 0x80, 0x58, 0x51, 0xb0, 0x0a, 0x56, 0x5f, 0x6b, 0x05, 0x70, 0x2b, + 0x22, 0x00, 0x8f, 0x82, 0xc9, 0x76, 0xd2, 0x5b, 0x50, 0xe8, 0x64, 0x8b, + 0x42, 0x5b, 0x15, 0x0e, 0xad, 0x9c, 0x39, 0xae, 0x0d, 0x6d, 0xf1, 0x73, + 0x12, 0xdf, 0x4b, 0x0e, 0x09, 0x6f, 0x46, 0xec, 0x00, 0x3d, 0x8f, 0xe0, + 0xa0, 0xb5, 0x59, 0xe0, 0xde, 0x6e, 0xfe, 0x4d, 0x00, 0x18, 0x37, 0xd0, + 0x7b, 0x04, 0x2f, 0xf0, 0x7f, 0xb9, 0x94, 0x00, 0x68, 0x9e, 0xa9, 0x1b, + 0x40, 0x1c, 0xc0, 0x3d, 0x90, 0xd6, 0xec, 0x10, 0x9c, 0xe9, 0x44, 0x35, + 0x6e, 0x57, 0xb3, 0xed, 0xe7, 0x5d, 0xb1, 0xc0, 0x3d, 0x0e, 0xbd, 0x59, + 0xe8, 0x85, 0xaf, 0x83, 0x72, 0xb7, 0x1d, 0x9d, 0xbb, 0xcb, 0x8a, 0x1a, + 0x6c, 0x3f, 0x10, 0xf1, 0x8a, 0xb5, 0xae, 0x15, 0x8f, 0x17, 0xcf, 0x2f, + 0x2c, 0x31, 0x66, 0x15, 0x1b, 0x48, 0x54, 0x29, 0xb7, 0x71, 0x75, 0xbe, + 0xbb, 0x9f, 0xbd, 0x8a, 0x99, 0x29, 0xc3, 0x9f, 0x90, 0xaa, 0x36, 0x9d, + 0x47, 0xb7, 0xb2, 0xe7, 0x1d, 0xf3, 0x1d, 0x90, 0xf3, 0xcd, 0xe6, 0x5b, + 0x43, 0x46, 0x0d, 0x6f, 0x9a, 0x13, 0x76, 0x90, 0xed, 0xa1, 0xf6, 0xb7, + 0xbe, 0x70, 0x21, 0x7f, 0xbb, 0xb9, 0x88, 0x01, 0x0b, 0x73, 0x6a, 0x24, + 0x5a, 0xd3, 0x96, 0xe4, 0x02, 0x9b, 0xf4, 0xda, 0xe9, 0xb6, 0x94, 0x12, + 0x73, 0x57, 0xef, 0xaf, 0x77, 0x16, 0xf1, 0x14, 0x70, 0x6b, 0x71, 0x30, + 0x53, 0x88, 0x97, 0xb7, 0x76, 0x60, 0x23, 0xff, 0xea, 0xbe, 0x18, 0xea, + 0x12, 0x10, 0xda, 0x7d, 0xb8, 0xc7, 0xce, 0x73, 0xb4, 0x87, 0x16, 0x1d, + 0xb2, 0xaa, 0x90, 0xda, 0x5e, 0xe5, 0xd1, 0xad, 0x8e, 0x8e, 0xb7, 0xd5, + 0xbe, 0x60, 0x03, 0x39, 0x82, 0x34, 0xce, 0xe4, 0x83, 0x9f, 0x46, 0x0f, + 0x6f, 0x35, 0x7f, 0x2f, 0x97, 0x21, 0x45, 0x5f, 0x35, 0x81, 0xd6, 0x40, + 0xea, 0x58, 0x69, 0x0d, 0xbd, 0xe0, 0x03, 0xae, 0x60, 0xb8, 0x6f, 0x0f, + 0xd0, 0xdf, 0x2a, 0x5e, 0x6a, 0x87, 0x1a, 0x65, 0x3c, 0xe6, 0xe6, 0xff, + 0xf2, 0x00, 0x38, 0xf6, 0xc1, 0x5d, 0x85, 0xd8, 0xfb, 0xa8, 0xe2, 0xd6, + 0x07, 0x84, 0x1e, 0x18, 0xdb, 0xe4, 0x34, 0xbc, 0x6e, 0xb7, 0x42, 0x7e, + 0xcb, 0x9e, 0x0d, 0xf8, 0xc9, 0x22, 0x65, 0x94, 0x2e, 0xd4, 0x58, 0xa7, + 0x0d, 0x6b, 0xcd, 0x84, 0x67, 0xc7, 0xd9, 0x42, 0x0b, 0x2b, 0xd4, 0x63, + 0x67, 0x72, 0x48, 0x89, 0x28, 0xd4, 0x76, 0xbe, 0x2d, 0x94, 0xaa, 0x7a, + 0x8c, 0x6c, 0xb5, 0x05, 0x5c, 0x84, 0xa2, 0x90, 0x29, 0xb7, 0x6f, 0x4e, + 0x0d, 0x6c, 0x4a, 0x6c, 0xc0, 0x29, 0xb9, 0x20, 0x13, 0x69, 0x22, 0x48, + 0xdd, 0x42, 0x6e, 0xd8, 0x57, 0x8b, 0x74, 0x7f, 0xe6, 0x09, 0x23, 0x4e, + 0x1c, 0xfb, 0x03, 0x3b, 0xf3, 0xb1, 0xc8, 0x4d, 0x1a, 0xd9, 0x4b, 0xe5, + 0xb6, 0x46, 0xe1, 0x80, 0x84, 0x00, 0xc0, 0x7b, 0x7e, 0x78, 0x5e, 0x51, + 0x7c, 0x45, 0x8d, 0xec, 0x3d, 0xf0, 0xcd, 0x7d, 0x28, 0x02, 0x35, 0x88, + 0xdb, 0x3b, 0x7d, 0x13, 0x36, 0xf7, 0x02, 0x43, 0xf3, 0x35, 0x27, 0x85, + 0x6f, 0x6e, 0x45, 0x80, 0x07, 0x0f, 0xe6, 0x96, 0x13, 0x82, 0x7c, 0xec, + 0x40, 0x82, 0xc0, 0xe6, 0xe4, 0xea, 0xf9, 0x73, 0x94, 0x00, 0x67, 0x00, + 0xa6, 0xc9, 0xda, 0x41, 0x7f, 0x06, 0x7a, 0xeb, 0x7f, 0x34, 0xf7, 0x94, + 0x5f, 0x1c, 0x3c, 0x13, 0x3f, 0xe8, 0xa8, 0xde, 0xaf, 0xeb, 0x97, 0xfd, + 0xd6, 0xed, 0xb4, 0x21, 0x6c, 0x24, 0xb7, 0x43, 0xee, 0xe9, 0x7b, 0xcc, + 0xb4, 0x26, 0x79, 0xcb, 0x65, 0xf4, 0x1c, 0xd4, 0x80, 0x3a, 0xde, 0x54, + 0x0c, 0x20, 0xe7, 0xc3, 0xae, 0xe4, 0xa0, 0x53, 0x73, 0x3b, 0x0c, 0x74, + 0x9c, 0xca, 0x17, 0x6b, 0x57, 0x09, 0xf0, 0xe9, 0xe7, 0x3c, 0x6d, 0x6f, + 0x88, 0x26, 0x82, 0x17, 0xfc, 0x6e, 0x4f, 0x04, 0xa5, 0x56, 0xe9, 0x1b, + 0x37, 0x6c, 0xc6, 0xbc, 0x88, 0xfe, 0xc4, 0x4d, 0x7a, 0xc9, 0x50, 0x3a, + 0xc9, 0x29, 0x9b, 0x14, 0x28, 0x60, 0x4b, 0x75, 0x3f, 0xbd, 0x3f, 0x9f, + 0x39, 0xe6, 0x1b, 0x8a, 0xa7, 0x4b, 0x10, 0x65, 0x52, 0x82, 0xe0, 0xd6, + 0xf4, 0x26, 0x51, 0x78, 0x1d, 0x5b, 0x95, 0x0d, 0x53, 0x2b, 0x7e, 0x2f, + 0xe8, 0xf9, 0x9d, 0x47, 0xf6, 0x58, 0xe9, 0x30, 0xe2, 0xc3, 0xe1, 0x6d, + 0xdc, 0x50, 0x03, 0xdb, 0xcc, 0x94, 0x00, 0x5d, 0xe0, 0x07, 0xb6, 0x2f, + 0x97, 0xef, 0xc6, 0x3a, 0xc2, 0xc0, 0x99, 0xe7, 0x65, 0x89, 0x1b, 0x4e, + 0x59, 0x1f, 0xe7, 0xae, 0xc0, 0x1e, 0x61, 0x92, 0x5f, 0x55, 0xaa, 0x51, + 0xcc, 0xf6, 0x4e, 0x32, 0x56, 0x76, 0x99, 0x2b, 0x6e, 0xe8, 0x5c, 0xc9, + 0xe2, 0xa8, 0x78, 0x4b, 0x76, 0x85, 0xf3, 0x34, 0x5c, 0x52, 0x8e, 0xa5, + 0xed, 0x4a, 0x87, 0x9e, 0x3e, 0x90, 0x9b, 0xcf, 0xec, 0x57, 0x4b, 0x60, + 0x5a, 0xc9, 0x69, 0x0c, 0x63, 0x7a, 0x01, 0x26, 0x88, 0xb9, 0x32, 0x82, + 0x48, 0x02, 0x1b, 0x2c, 0xbe, 0x95, 0xb9, 0x2f, 0xe1, 0x4b, 0x6c, 0x4e, + 0x03, 0xdb, 0xc7, 0xce, 0xcf, 0x67, 0xf1, 0x1f, 0x83, 0xca, 0xb6, 0x20, + 0x06, 0xcd, 0xb8, 0xd9, 0xcb, 0x94, 0xb0, 0xa1, 0x88, 0xdc, 0xf9, 0x2c, + 0x4a, 0xb6, 0x85, 0x14, 0x42, 0x6c, 0xbb, 0x0d, 0x48, 0xd6, 0x51, 0x8f, + 0x21, 0x4a, 0xd4, 0x74, 0x6f, 0xdf, 0x89, 0x76, 0xf2, 0xe7, 0xcd, 0x32, + 0xc4, 0x4b, 0x52, 0xca, 0x5c, 0x08, 0x2c, 0x6b, 0x76, 0x88, 0xa4, 0x41, + 0x62, 0xed, 0x96, 0x71, 0xb0, 0xa4, 0x37, 0x2d, 0x91, 0x60, 0x69, 0x6d, + 0xee, 0x00, 0x18, 0x6f, 0x20, 0x0d, 0x48, 0xff, 0xd7, 0x2c, 0xb5, 0x4b, + 0x27, 0xf3, 0x91, 0xf3, 0x6a, 0x20, 0x04, 0xc5, 0x95, 0x10, 0x36, 0x0f, + 0x6f, 0x4c, 0x00, 0xc0, 0x57, 0x3e, 0xc0, 0x16, 0xcd, 0xba, 0x30, 0xcc, + 0x28, 0xed, 0xa7, 0xcf, 0x35, 0x94, 0xe0, 0xb6, 0x39, 0xdc, 0xb1, 0x25, + 0x09, 0x42, 0xd1, 0x8d, 0x7c, 0x87, 0x20, 0x53, 0x7b, 0xc0, 0x1b, 0x5d, + 0x00, 0x7f, 0xc3, 0xdf, 0xc6, 0xa1, 0x68, 0x61, 0x3c, 0xdb, 0x65, 0xf1, + 0x2d, 0xbd, 0xc3, 0x7c, 0x6c, 0x01, 0xa0, 0x9e, 0xd3, 0x9d, 0xd9, 0xd8, + 0xeb, 0x73, 0x5f, 0x76, 0xdd, 0x41, 0xe1, 0x6d, 0xcf, 0x00, 0x64, 0x44, + 0xea, 0x6c, 0x36, 0xdb, 0x40, 0x95, 0x2e, 0x9b, 0x42, 0x5b, 0x32, 0x36, + 0xba, 0x8b, 0x9b, 0x8e, 0xb4, 0x78, 0x6d, 0x87, 0x1e, 0xda, 0x08, 0xb3, + 0x75, 0x64, 0x6f, 0xeb, 0x3f, 0xcf, 0x7e, 0x85, 0x77, 0x8f, 0xcd, 0x55, + 0x87, 0x48, 0x75, 0x4a, 0x48, 0x6e, 0x00, 0xb0, 0x06, 0xe0, 0x07, 0xdc, + 0xd2, 0x33, 0xa7, 0x38, 0x54, 0x92, 0x1b, 0xa9, 0x5c, 0xa5, 0x64, 0x31, + 0x07, 0x37, 0x88, 0x00, 0x36, 0x20, 0x88, 0xa5, 0x8b, 0x90, 0xfc, 0xe2, + 0xcb, 0x24, 0x55, 0x01, 0xec, 0x6e, 0x37, 0xcf, 0xcf, 0xf0, 0x55, 0x99, + 0xf1, 0xe7, 0x4f, 0x77, 0x7b, 0x22, 0xc1, 0xab, 0x4f, 0x83, 0x23, 0x3f, + 0x8e, 0x37, 0x5c, 0x81, 0xf0, 0xea, 0x95, 0x0b, 0xad, 0x5c, 0x65, 0x41, + 0xad, 0xc0, 0x02, 0xe1, 0x53, 0xfc, 0x2a, 0x6b, 0xe8, 0x6d, 0xd7, 0x86, + 0xa1, 0x4d, 0xdc, 0x23, 0x00, 0x3c, 0xe8, 0x01, 0xb8, 0x03, 0x8f, 0x3e, + 0xfd, 0xf9, 0xda, 0x51, 0xb3, 0x99, 0xce, 0xd8, 0x71, 0x43, 0x46, 0x64, + 0x6f, 0x82, 0x11, 0x25, 0x11, 0xb9, 0x74, 0x0f, 0x1d, 0x46, 0x37, 0xb1, + 0x00, 0x68, 0x44, 0xa0, 0x0e, 0xc4, 0x60, 0x9f, 0x9e, 0xcc, 0x5b, 0x35, + 0xff, 0x9d, 0xd4, 0x37, 0x00, 0xc2, 0x7e, 0x14, 0x38, 0xa3, 0xe8, 0x5b, + 0x6f, 0xe4, 0x41, 0xb2, 0x46, 0x84, 0x8f, 0x49, 0x11, 0x80, 0x00, 0x00, + 0x01, 0x04, 0x43, 0xf9, 0x8e, 0xd8, 0xe7, 0x69, 0x90, 0x2f, 0x79, 0x44, + 0x6c, 0xf5, 0xf4, 0x47, 0x79, 0x4e, 0x1e, 0xb2, 0x59, 0x54, 0x21, 0x18, + 0x3d, 0xd3, 0x49, 0x98, 0x1a, 0x07, 0x35, 0x22, 0x72, 0x71, 0xd1, 0x70, + 0xe2, 0xd5, 0x75, 0x0a, 0x50, 0xd6, 0xf3, 0x52, 0xc6, 0xf1, 0xd1, 0xbc, + 0xba, 0xa0, 0x16, 0x17, 0xea, 0x39, 0xb4, 0x7c, 0xd3, 0x0d, 0x92, 0x8f, + 0x92, 0x27, 0x8b, 0x58, 0x28, 0x9f, 0xbc, 0xcd, 0xba, 0x52, 0x87, 0x5c, + 0x52, 0xdb, 0x41, 0x13, 0xb9, 0xcc, 0x42, 0x74, 0xa3, 0xeb, 0x86, 0x6d, + 0x55, 0x3a, 0xd6, 0x71, 0xf2, 0x2a, 0x33, 0xa3, 0x9b, 0xf2, 0xde, 0xee, + 0xd7, 0x3e, 0x15, 0x95, 0x81, 0x1f, 0x8d, 0xe4, 0x44, 0xba, 0x14, 0x7c, + 0xb2, 0xb7, 0xb1, 0x10, 0xab, 0x32, 0xdf, 0x09, 0x15, 0x5b, 0xb3, 0xda, + 0xfd, 0x79, 0x12, 0xb9, 0x28, 0x45, 0x92, 0x42, 0x13, 0x72, 0xcb, 0x16, + 0x12, 0x58, 0x54, 0x46, 0xfc, 0x88, 0x03, 0xf4, 0xb4, 0x9f, 0x54, 0x05, + 0x51, 0x7c, 0x9d, 0xe2, 0xa8, 0x58, 0x59, 0x6c, 0xa2, 0x93, 0xda, 0x1b, + 0xa8, 0x13, 0xb2, 0xc5, 0x6f, 0x47, 0x25, 0x15, 0xce, 0x5c, 0xa0, 0x94, + 0x01, 0x19, 0x6d, 0x04, 0xbf, 0xfd, 0x56, 0xf1, 0xd0, 0x0c, 0x15, 0x6f, + 0xa3, 0x77, 0x0f, 0x56, 0xd0, 0xe6, 0xe8, 0xb3, 0xcf, 0xac, 0xd4, 0xf5, + 0x29, 0xba, 0x1b, 0xf8, 0x39, 0xb0, 0xcc, 0x9f, 0x3a, 0xe9, 0xa4, 0x26, + 0xee, 0xbf, 0x3f, 0x09, 0x08, 0x6d, 0x34, 0xb9, 0x5a, 0x1b, 0xe4, 0xb7, + 0x53, 0xd8, 0x10, 0xbf, 0xdf, 0x98, 0x4b, 0xd8, 0xb3, 0xc5, 0xa8, 0xef, + 0x3c, 0xae, 0xc5, 0x08, 0x59, 0x49, 0x32, 0x8c, 0x6e, 0x74, 0x2e, 0xd2, + 0x4b, 0x21, 0xac, 0x37, 0xf5, 0x69, 0xf9, 0x52, 0x5c, 0x88, 0x4b, 0x6c, + 0x4f, 0xa0, 0x16, 0xf3, 0xe7, 0x68, 0x04, 0x1b, 0x8b, 0xe2, 0x91, 0x09, + 0x0c, 0xb9, 0x00, 0x0d, 0xf0, 0x5c, 0x04, 0xcf, 0xfd, 0x5a, 0x49, 0x67, + 0xe1, 0x31, 0xfc, 0x19, 0xb4, 0x30, 0xd7, 0x1b, 0x3d, 0x14, 0xef, 0x14, + 0xac, 0xc6, 0x23, 0x41, 0xe0, 0x73, 0x7e, 0x53, 0x78, 0xdf, 0xb7, 0x3f, + 0x1c, 0x73, 0x20, 0x6a, 0xe6, 0x72, 0x60, 0xe2, 0x62, 0xa5, 0xf5, 0x6d, + 0xbf, 0x6c, 0x84, 0x7f, 0xad, 0x4e, 0x2c, 0x80, 0x4e, 0xf3, 0x32, 0xe6, + 0xc3, 0xe9, 0x49, 0x06, 0xb6, 0x69, 0xc6, 0x4f, 0x8e, 0x04, 0x3d, 0xf3, + 0x29, 0x36, 0x5e, 0x73, 0x7c, 0xcc, 0x96, 0x2a, 0x15, 0x51, 0x67, 0x85, + 0x8d, 0x89, 0xfa, 0x7c, 0x84, 0x39, 0x80, 0x5b, 0x3b, 0x52, 0x54, 0x6f, + 0x57, 0x69, 0xb9, 0xb6, 0x37, 0xf4, 0x70, 0x07, 0x22, 0xe7, 0xc7, 0xdb, + 0x78, 0x7b, 0xc2, 0x73, 0x2c, 0xb1, 0x17, 0xf1, 0x1b, 0xe7, 0x3f, 0x7e, + 0xb7, 0xfc, 0x47, 0x9e, 0x41, 0x17, 0x28, 0xed, 0x3a, 0xc6, 0xf7, 0xbf, + 0xe7, 0x82, 0x0f, 0xf6, 0x4a, 0x2e, 0x00, 0x41, 0xba, 0xb7, 0x28, 0x5b, + 0x7b, 0xad, 0xda, 0x4e, 0xb7, 0x25, 0x0c, 0xb5, 0x0a, 0x6e, 0x5c, 0x8b, + 0xb2, 0xc6, 0xe1, 0xe3, 0x10, 0x5c, 0xb2, 0x04, 0x2b, 0x7f, 0x9e, 0x2d, + 0xf3, 0xf3, 0x03, 0x87, 0x86, 0x96, 0xdd, 0x61, 0x38, 0xed, 0x77, 0xcc, + 0x35, 0x60, 0xfb, 0x64, 0xa6, 0x0d, 0x1f, 0x69, 0x6d, 0x39, 0xb4, 0x01, + 0xb0, 0x9f, 0xf7, 0x2f, 0xd0, 0x9d, 0x7f, 0x0a, 0xeb, 0x69, 0xe0, 0x4c, + 0xa8, 0xdd, 0x27, 0x15, 0x9d, 0xed, 0x0b, 0x57, 0xea, 0x96, 0x03, 0x26, + 0xd2, 0x2b, 0xa2, 0x90, 0xf6, 0x36, 0xf0, 0x0c, 0x4b, 0x00, 0x06, 0x72, + 0xb7, 0xa6, 0x02, 0x17, 0xf8, 0x91, 0x63, 0xa4, 0x80, 0x3d, 0x37, 0xdf, + 0x78, 0x33, 0x21, 0xe4, 0xd5, 0x2a, 0x20, 0x4b, 0x7d, 0x7b, 0xe6, 0x02, + 0x0f, 0xf5, 0x80, 0x2c, 0xfe, 0x66, 0x89, 0xe2, 0x69, 0x59, 0x9b, 0xef, + 0xed, 0xe7, 0x27, 0x91, 0xf6, 0x93, 0xf6, 0x54, 0xa0, 0x11, 0x4b, 0x5b, + 0xe5, 0x30, 0x10, 0xbf, 0xea, 0xbe, 0xd8, 0x37, 0xf5, 0x62, 0x6d, 0xbe, + 0x0d, 0xd8, 0xfa, 0x7f, 0xb8, 0x00, 0x77, 0xef, 0x9e, 0x69, 0x47, 0xa3, + 0xb8, 0xf3, 0xc8, 0x32, 0x87, 0xe9, 0x52, 0x2b, 0x73, 0xce, 0x6e, 0x26, + 0x45, 0x08, 0x2d, 0xb8, 0xf2, 0xa2, 0x23, 0x7e, 0xbf, 0x1f, 0x9b, 0x73, + 0x53, 0x60, 0x4c, 0x29, 0x46, 0x52, 0xdb, 0xa4, 0x00, 0xa4, 0x8b, 0x9f, + 0x7e, 0x05, 0x88, 0x9a, 0xe9, 0x46, 0x51, 0x5f, 0x4f, 0x73, 0x37, 0xcc, + 0xf9, 0xfa, 0x85, 0xa9, 0xe3, 0x9b, 0xe7, 0x22, 0xe0, 0x01, 0xf6, 0x8a, + 0x8f, 0xd0, 0x9b, 0x78, 0xc4, 0x2c, 0x04, 0x68, 0x53, 0x7b, 0x5a, 0xa4, + 0x52, 0x0e, 0x4d, 0x30, 0x05, 0x7c, 0xae, 0x9e, 0x1d, 0x60, 0xd0, 0xb6, + 0xf2, 0x72, 0x82, 0x17, 0xfd, 0x57, 0x5c, 0x81, 0xb7, 0x4c, 0x29, 0xb0, + 0x85, 0xec, 0x2b, 0xc6, 0x46, 0xf3, 0x80, 0x14, 0xf0, 0xf0, 0x07, 0x3f, + 0x4e, 0x7d, 0xb1, 0xd0, 0x27, 0x7a, 0x7e, 0x2b, 0xa5, 0x2e, 0x15, 0x29, + 0xd5, 0xb2, 0xfc, 0x3e, 0x00, 0x3a, 0xf7, 0xbb, 0x64, 0x41, 0xdd, 0x3a, + 0x2e, 0x21, 0xc7, 0x16, 0xaa, 0x17, 0x55, 0xbe, 0xac, 0x00, 0xab, 0xa7, + 0x7c, 0x80, 0x57, 0xbd, 0xbf, 0x68, 0x11, 0xf9, 0xd0, 0xfc, 0x29, 0x00, + 0x8a, 0x34, 0x92, 0xdf, 0x37, 0x00, 0x75, 0xed, 0xee, 0x00, 0xfb, 0xdb, + 0x33, 0xa8, 0x47, 0xed, 0xf6, 0x2e, 0x87, 0x1d, 0x31, 0xce, 0x88, 0x54, + 0x29, 0xbd, 0x47, 0x3e, 0x0b, 0x15, 0x33, 0x4c, 0x09, 0x2e, 0xa5, 0xbe, + 0x2d, 0xbe, 0x6a, 0xc2, 0xd0, 0x25, 0xbf, 0x9b, 0x57, 0x66, 0xf0, 0x63, + 0xb2, 0x05, 0x0f, 0x0b, 0x6d, 0x2f, 0x2e, 0xd0, 0x29, 0xb6, 0x88, 0xdd, + 0xeb, 0x80, 0x09, 0xec, 0x2c, 0x07, 0xb6, 0x4f, 0x16, 0x8e, 0x12, 0x08, + 0x3f, 0xd8, 0x00, 0xfb, 0x39, 0x4a, 0x3d, 0x60, 0x8e, 0x64, 0xd7, 0x14, + 0xb0, 0xed, 0x2e, 0x5b, 0x43, 0x28, 0xe6, 0xdc, 0xc5, 0x80, 0x53, 0x4c, + 0x94, 0xb4, 0x6f, 0x29, 0x1b, 0x9b, 0x7e, 0xa4, 0xe3, 0x32, 0xd4, 0x8b, + 0x78, 0x8f, 0x4e, 0x4d, 0x01, 0xc2, 0x98, 0x6a, 0x0d, 0x2c, 0xf0, 0xc5, + 0x6f, 0x68, 0x22, 0xf6, 0x23, 0xe9, 0x05, 0x5e, 0xf2, 0x8e, 0xab, 0xd6, + 0xba, 0x2c, 0x0f, 0x85, 0x4b, 0x0a, 0x94, 0x28, 0x7b, 0x69, 0x00, 0x5e, + 0x4f, 0x00, 0x6a, 0x00, 0xe3, 0xdb, 0xb1, 0x79, 0xb4, 0x73, 0x85, 0x93, + 0xd7, 0x8e, 0x7b, 0x3f, 0x2a, 0x6c, 0x40, 0x1c, 0x51, 0x8d, 0xfa, 0x34, + 0x01, 0x0f, 0xdf, 0x5f, 0x44, 0x89, 0xcc, 0x90, 0xbb, 0x43, 0xde, 0xf2, + 0xc7, 0xdf, 0x5a, 0xd4, 0x2c, 0xae, 0x34, 0xbf, 0x06, 0xd9, 0xe5, 0xbb, + 0x4b, 0x6f, 0xf2, 0x77, 0x29, 0xc4, 0x85, 0xb6, 0x7e, 0xe2, 0xd8, 0x8d, + 0xfa, 0xc8, 0x00, 0x9c, 0x01, 0xc8, 0xbd, 0xd8, 0x1d, 0x1d, 0x90, 0x98, + 0x12, 0xd9, 0x40, 0x08, 0x7f, 0xfa, 0x46, 0x11, 0x49, 0xe2, 0x64, 0x2a, + 0x79, 0x98, 0xb4, 0xab, 0x4a, 0x8d, 0x98, 0x9e, 0x25, 0xb4, 0xf6, 0x5d, + 0xba, 0x55, 0x3d, 0xbf, 0x9b, 0x80, 0x3b, 0xf8, 0x70, 0x02, 0xf2, 0x30, + 0x03, 0xbb, 0xde, 0xad, 0xa5, 0x66, 0x80, 0x1e, 0x4e, 0x26, 0xbb, 0x50, + 0xba, 0x7e, 0xd4, 0x48, 0x58, 0x4b, 0x79, 0xa2, 0x27, 0x0f, 0xf7, 0xeb, + 0x48, 0xfd, 0x5a, 0x32, 0xc4, 0xeb, 0x72, 0x2c, 0x38, 0xed, 0xb5, 0x61, + 0x0a, 0x37, 0xe9, 0x7f, 0x9d, 0xbf, 0x5f, 0xef, 0xb8, 0xbd, 0xf5, 0xed, + 0xf6, 0xc8, 0x15, 0x87, 0x48, 0x14, 0xdf, 0x9f, 0x80, 0x1e, 0xf5, 0xa0, + 0x05, 0x14, 0x8d, 0xec, 0x2c, 0xe2, 0xe3, 0xed, 0xc1, 0x0e, 0x79, 0x47, + 0x13, 0x0b, 0xa9, 0xe0, 0x5a, 0xb4, 0x8b, 0xa4, 0xe3, 0x4e, 0x0a, 0x4b, + 0x63, 0x3e, 0x7f, 0x0a, 0x4a, 0xa7, 0x37, 0xcd, 0xfb, 0xb9, 0xc2, 0xdd, + 0xc6, 0xeb, 0xec, 0x1b, 0x92, 0x59, 0xfb, 0x39, 0xbe, 0x96, 0x00, 0xfc, + 0x5e, 0x09, 0xf7, 0x13, 0x38, 0xe8, 0x6a, 0x68, 0x05, 0x44, 0xcc, 0x7d, + 0x01, 0x5e, 0xd2, 0x8e, 0x1a, 0xad, 0xf3, 0x5f, 0xee, 0x7b, 0x7d, 0x44, + 0x5d, 0x15, 0x62, 0x25, 0x9b, 0xa1, 0x86, 0x14, 0x6f, 0x89, 0x41, 0x25, + 0x56, 0xfb, 0x57, 0xf0, 0x8b, 0x84, 0x5f, 0xbf, 0x7b, 0xc6, 0x8c, 0x47, + 0x64, 0x87, 0x3a, 0x21, 0x54, 0x7d, 0x3d, 0xb8, 0x7b, 0x78, 0x05, 0xa4, + 0xc9, 0xa1, 0x91, 0x1a, 0x1f, 0xa4, 0xfa, 0x52, 0xb7, 0xe4, 0x88, 0x00, + 0x15, 0x0a, 0x16, 0x96, 0xac, 0x55, 0x7d, 0x7e, 0x99, 0x86, 0xd2, 0xce, + 0xb0, 0x6d, 0x09, 0x6f, 0x19, 0xe7, 0x3d, 0xac, 0x8e, 0x7e, 0xd5, 0x36, + 0x9f, 0x86, 0xd5, 0x0b, 0x6f, 0x60, 0x00, 0xe8, 0x8b, 0x08, 0xc8, 0xfd, + 0x99, 0xa5, 0x96, 0xeb, 0x26, 0x45, 0x0b, 0xaa, 0x73, 0x7c, 0x9f, 0xda, + 0xd0, 0x06, 0xdf, 0x42, 0x27, 0x62, 0xc0, 0x45, 0xe6, 0xfb, 0x56, 0x0c, + 0x26, 0x4b, 0x0a, 0x2d, 0xa7, 0x93, 0x27, 0x42, 0x16, 0x0f, 0x53, 0x69, + 0xd0, 0x69, 0xc5, 0xb7, 0x3d, 0xb2, 0x4c, 0x58, 0xdf, 0x24, 0x01, 0xf9, + 0x3b, 0xa1, 0x04, 0x6e, 0xc4, 0xfc, 0x6a, 0x5b, 0x3c, 0xe3, 0xb7, 0x83, + 0x43, 0xe0, 0x65, 0xb0, 0xab, 0x65, 0x46, 0xfd, 0x38, 0x00, 0x8c, 0x8a, + 0x08, 0x3f, 0xcc, 0x00, 0xfc, 0x8e, 0xf0, 0x0b, 0x34, 0x11, 0xc0, 0x13, + 0x8f, 0x20, 0x31, 0x0a, 0x53, 0xb4, 0x7e, 0x9f, 0xe8, 0xde, 0x0f, 0xfb, + 0xcd, 0x00, 0x4a, 0x47, 0xd7, 0x79, 0x41, 0xf8, 0x01, 0x66, 0x49, 0x6e, + 0xd3, 0xc0, 0x72, 0x19, 0x09, 0x2d, 0xef, 0xdd, 0x1d, 0x04, 0xbe, 0x19, + 0x80, 0x2b, 0xc7, 0x07, 0x6a, 0x0e, 0x45, 0x43, 0x9b, 0xd6, 0xe3, 0x6f, + 0x39, 0x15, 0x60, 0xca, 0x6c, 0xab, 0x47, 0x37, 0x6c, 0xa6, 0xd6, 0x00, + 0x00, 0x01, 0x05, 0x43, 0xf9, 0x7d, 0x74, 0xbc, 0x58, 0xed, 0x01, 0x5e, + 0xd0, 0x82, 0x99, 0x05, 0xde, 0x29, 0x32, 0x84, 0xea, 0x9f, 0x46, 0x37, + 0x4e, 0x3e, 0x5b, 0x4c, 0xb6, 0x0e, 0x68, 0x2b, 0xdd, 0xc6, 0x95, 0x92, + 0xc5, 0x4d, 0xf0, 0x6e, 0x02, 0x9b, 0xc7, 0xc5, 0xd3, 0xa3, 0x7c, 0xf1, + 0x6e, 0xbb, 0x25, 0x90, 0x22, 0x69, 0xb2, 0x21, 0x46, 0xb3, 0x0b, 0xe7, + 0x9a, 0xfd, 0x76, 0x5a, 0xa6, 0xcf, 0x38, 0x8e, 0x9b, 0xa7, 0x19, 0x50, + 0xc8, 0xdd, 0x93, 0x43, 0x9e, 0x1e, 0xed, 0xb1, 0x66, 0x07, 0x2a, 0xa5, + 0x6d, 0xbb, 0x45, 0xba, 0x7d, 0x44, 0xce, 0x3b, 0xd2, 0xe5, 0x9d, 0x47, + 0xd7, 0x75, 0x77, 0x89, 0x15, 0x0f, 0x02, 0x75, 0xb9, 0x4d, 0x27, 0x45, + 0x3d, 0xb7, 0x2e, 0xa8, 0x1c, 0xdf, 0x96, 0xda, 0x6d, 0x88, 0xde, 0xcd, + 0xdc, 0x80, 0x1f, 0xf2, 0xfc, 0x92, 0x41, 0xf5, 0xf1, 0x02, 0xe0, 0xda, + 0x84, 0x36, 0xf2, 0xdc, 0x97, 0xc7, 0x04, 0x8b, 0x1b, 0x03, 0x9d, 0x05, + 0x7b, 0xf4, 0x6d, 0x9e, 0x18, 0x85, 0xb4, 0x5a, 0x38, 0x86, 0xdc, 0xd4, + 0xa9, 0x1b, 0xeb, 0x67, 0x37, 0xfd, 0xd6, 0x3b, 0xb7, 0xe4, 0x2c, 0xcc, + 0xd7, 0x98, 0x8f, 0xb2, 0x15, 0x0b, 0x44, 0x54, 0x6f, 0x1a, 0x08, 0x60, + 0x0d, 0x55, 0xbb, 0x02, 0x2a, 0xe5, 0xf2, 0xf4, 0x36, 0xd4, 0x6e, 0x56, + 0xc3, 0x1d, 0x29, 0x2f, 0x25, 0x6f, 0x42, 0x50, 0xea, 0xa4, 0x36, 0xd8, + 0x7b, 0x7b, 0xc4, 0x82, 0x17, 0xfa, 0xd7, 0xe4, 0x40, 0xb4, 0x46, 0xb4, + 0x8d, 0xd6, 0xf5, 0xa6, 0xbe, 0xd1, 0x85, 0x41, 0xed, 0xe8, 0x2a, 0xe5, + 0xe7, 0x49, 0x76, 0xda, 0xde, 0x66, 0x54, 0x73, 0xac, 0xbe, 0x3a, 0x89, + 0xe2, 0x39, 0xae, 0x87, 0x69, 0xed, 0x27, 0x37, 0xb4, 0x45, 0x00, 0x3e, + 0x84, 0x5e, 0x57, 0x01, 0x20, 0x00, 0xf9, 0x99, 0x38, 0x9e, 0x0a, 0x5c, + 0x21, 0x37, 0x9b, 0x81, 0xcd, 0xdb, 0xe9, 0xf3, 0xfd, 0xc7, 0x1e, 0x72, + 0x51, 0xb2, 0x58, 0xdc, 0x22, 0x63, 0x72, 0x8d, 0xac, 0xce, 0x6f, 0xd2, + 0x11, 0xb8, 0x04, 0x1f, 0xed, 0xc1, 0x1d, 0xca, 0x13, 0xe7, 0xbb, 0x56, + 0x0c, 0x19, 0x31, 0xaf, 0xc5, 0x00, 0x74, 0xf2, 0x31, 0x88, 0x1b, 0x37, + 0xbf, 0x3b, 0x76, 0x1e, 0x03, 0x88, 0x52, 0xa3, 0x72, 0xf9, 0x40, 0x07, + 0x3b, 0xf1, 0x99, 0x60, 0x4c, 0x32, 0xdb, 0x28, 0x4a, 0xa9, 0x2e, 0x35, + 0x9c, 0x60, 0x20, 0x80, 0x9f, 0x5e, 0xd2, 0xcf, 0x1e, 0x05, 0xc5, 0xf0, + 0xbc, 0x92, 0x1b, 0x53, 0xdb, 0xaa, 0xad, 0x45, 0x21, 0xab, 0x7b, 0xf7, + 0x99, 0xcf, 0x1b, 0x0c, 0xca, 0x39, 0x3d, 0xb5, 0xd3, 0x28, 0xca, 0x76, + 0xd2, 0xe9, 0x66, 0x36, 0x57, 0x99, 0xf1, 0xcd, 0xbe, 0x55, 0x3f, 0x69, + 0x66, 0xc1, 0xaa, 0x3e, 0x01, 0xcd, 0xe8, 0xfa, 0x7e, 0x80, 0x33, 0xc2, + 0x7c, 0xf3, 0x0a, 0xe1, 0xd6, 0x63, 0xa8, 0x0a, 0xe4, 0xb6, 0x94, 0x10, + 0x18, 0xd9, 0x79, 0xdb, 0xf4, 0xa2, 0x75, 0xf4, 0x2a, 0x7c, 0x9b, 0x84, + 0x38, 0x8a, 0xda, 0x35, 0xe7, 0xe4, 0xca, 0x4a, 0x6f, 0x85, 0xd0, 0x21, + 0x7f, 0xd3, 0xd7, 0x77, 0xc2, 0x18, 0xb7, 0xc2, 0xd6, 0xfa, 0xef, 0xd2, + 0xcf, 0xf8, 0x8d, 0x45, 0x01, 0x14, 0xb2, 0xc8, 0x34, 0x63, 0x7c, 0x75, + 0x17, 0x72, 0x12, 0xa2, 0x92, 0x0e, 0x6e, 0x8d, 0x90, 0x5f, 0x3a, 0xed, + 0x30, 0x2a, 0x3e, 0x36, 0x1a, 0x1d, 0x1b, 0x7e, 0x40, 0xc7, 0x56, 0xfa, + 0x46, 0xee, 0xd8, 0x08, 0x20, 0x27, 0x40, 0x1c, 0x79, 0x4a, 0x17, 0xd6, + 0x3e, 0xda, 0x17, 0x36, 0x55, 0xa1, 0x4d, 0xec, 0x85, 0xcd, 0xf7, 0x17, + 0xbc, 0x10, 0x2d, 0x2f, 0x6d, 0x0f, 0xc7, 0x9a, 0xf1, 0x87, 0x06, 0x50, + 0x96, 0xf0, 0xfd, 0x02, 0x10, 0x06, 0x8a, 0xe8, 0x41, 0x0b, 0x63, 0xf7, + 0x3c, 0x26, 0xd6, 0xf7, 0x3f, 0xcd, 0x84, 0x7d, 0x12, 0x84, 0x3b, 0x57, + 0xc4, 0x7f, 0xab, 0x71, 0x4c, 0x00, 0xab, 0x76, 0x5f, 0x57, 0xa5, 0xcf, + 0x16, 0xe4, 0xb8, 0x40, 0xd7, 0x80, 0x0c, 0x6a, 0xb7, 0xe7, 0xb5, 0xd5, + 0xd7, 0x8e, 0x28, 0xc4, 0x57, 0xc9, 0x4e, 0xb4, 0xba, 0x5d, 0x6f, 0xa0, + 0xe6, 0x0b, 0xff, 0x8a, 0x17, 0x79, 0xf2, 0x59, 0x2c, 0x37, 0x3a, 0xe6, + 0xba, 0x18, 0x7c, 0x2e, 0x01, 0xed, 0xe5, 0xba, 0xe4, 0x00, 0xe3, 0xa1, + 0x7d, 0x3e, 0xd8, 0x3c, 0xed, 0xb2, 0x85, 0x18, 0x5b, 0x7a, 0x3c, 0x73, + 0xc1, 0x03, 0xf3, 0x39, 0xe2, 0xd9, 0x88, 0x71, 0x3b, 0xbe, 0x3c, 0xe9, + 0x67, 0xc0, 0xe2, 0xe0, 0x14, 0xd9, 0x77, 0x41, 0x08, 0x01, 0xab, 0xe2, + 0x10, 0x9b, 0x91, 0xe0, 0x67, 0x89, 0x72, 0xb7, 0xe4, 0x7e, 0x3a, 0x00, + 0xb3, 0x5d, 0x85, 0xd9, 0x6c, 0x52, 0x8b, 0xbe, 0xb0, 0x08, 0x6e, 0x98, + 0x03, 0xed, 0x78, 0x03, 0xf1, 0x66, 0x3b, 0x8c, 0x83, 0x97, 0x30, 0x9a, + 0x5a, 0x40, 0xe9, 0x6c, 0x3e, 0x86, 0xb7, 0xe9, 0x10, 0x40, 0xfd, 0x40, + 0x07, 0x3d, 0xf0, 0x00, 0xf3, 0x8f, 0x61, 0x5a, 0xec, 0x85, 0xf2, 0xff, + 0x24, 0x29, 0xc6, 0x87, 0x7e, 0x83, 0x24, 0x6d, 0x60, 0x04, 0xa0, 0x0e, + 0x7d, 0xfa, 0x17, 0xb8, 0xf9, 0xe5, 0x92, 0x4c, 0x97, 0xcd, 0xf9, 0x13, + 0x6d, 0x32, 0x1c, 0xdd, 0x9f, 0x27, 0xad, 0x50, 0xb6, 0xea, 0x16, 0x7c, + 0xb5, 0x5b, 0xfc, 0xda, 0x00, 0xf3, 0xe3, 0xbe, 0x39, 0xf2, 0xe1, 0xef, + 0xe4, 0xb5, 0xcc, 0x78, 0x01, 0xf3, 0x88, 0x3b, 0xe5, 0x09, 0xf2, 0x42, + 0xac, 0x4b, 0x54, 0x7d, 0xad, 0xd4, 0xe2, 0xec, 0x15, 0xb8, 0x64, 0x08, + 0xb9, 0xb4, 0xf1, 0x9e, 0x10, 0x2d, 0xbe, 0xb6, 0x00, 0x8f, 0xa8, 0x00, + 0xc0, 0x01, 0x16, 0xef, 0x3c, 0xf2, 0x85, 0xf9, 0x63, 0xc4, 0x8b, 0x72, + 0x53, 0x43, 0xcb, 0x5c, 0x52, 0x4b, 0x6e, 0x04, 0x0f, 0xd3, 0x00, 0xb3, + 0x28, 0xbe, 0xdf, 0x75, 0xf2, 0x1d, 0x15, 0x6c, 0x8d, 0xbb, 0xe5, 0xba, + 0xb7, 0xd6, 0x42, 0x98, 0xee, 0x79, 0x6c, 0xb6, 0x37, 0xf8, 0xdd, 0xd8, + 0x00, 0x26, 0x5a, 0x09, 0x80, 0x06, 0xe9, 0x67, 0xab, 0x7d, 0x14, 0x10, + 0x3f, 0x38, 0x8c, 0x08, 0x3f, 0xae, 0x00, 0xf3, 0x04, 0x08, 0x23, 0xf0, + 0x84, 0xd3, 0x3e, 0x5f, 0xb2, 0x10, 0x38, 0x42, 0x7d, 0x85, 0x86, 0xb8, + 0x6b, 0x7e, 0xaa, 0x00, 0x27, 0x00, 0x7e, 0x2c, 0x01, 0xc8, 0x03, 0xb7, + 0x82, 0x10, 0x03, 0x3f, 0x6a, 0x4c, 0xeb, 0xae, 0xa9, 0x50, 0xcb, 0x4d, + 0xda, 0x81, 0x2d, 0xed, 0xb0, 0x3a, 0xd5, 0x6e, 0x9d, 0x2e, 0xb6, 0xda, + 0x5d, 0xa8, 0xde, 0x62, 0x28, 0x9e, 0x48, 0xbf, 0x71, 0x62, 0xc4, 0xf7, + 0xa0, 0x3d, 0xde, 0x5e, 0xfb, 0x74, 0x74, 0x85, 0x0e, 0x92, 0x23, 0x74, + 0xdb, 0x2e, 0x16, 0xc7, 0x22, 0x36, 0xcd, 0xab, 0x61, 0xd3, 0xcb, 0x69, + 0x21, 0xa7, 0x54, 0x83, 0xd5, 0x95, 0xb1, 0xe0, 0x21, 0x00, 0x35, 0xd6, + 0xc0, 0xe8, 0x00, 0x6f, 0x65, 0x9e, 0xb9, 0x24, 0x66, 0xc3, 0x70, 0x53, + 0xa8, 0x03, 0x0f, 0x7f, 0xaf, 0x5b, 0x1c, 0x5c, 0x57, 0xd2, 0x03, 0xec, + 0x93, 0x24, 0x2e, 0xa8, 0xe3, 0x83, 0x1b, 0xe6, 0xe6, 0x91, 0x1e, 0x44, + 0xfb, 0x80, 0x5a, 0xf1, 0x24, 0xd7, 0x16, 0xfa, 0xf9, 0x03, 0x89, 0x96, + 0x19, 0xb3, 0x03, 0x0a, 0x19, 0x1b, 0xed, 0x0a, 0x1d, 0x69, 0x21, 0xbf, + 0x18, 0xbd, 0xc0, 0x06, 0x8f, 0xf8, 0x7c, 0xa1, 0xab, 0x3e, 0x28, 0xa4, + 0x04, 0xb0, 0x03, 0x31, 0x47, 0x8e, 0x6f, 0x2e, 0x50, 0x03, 0xea, 0x92, + 0x78, 0xd2, 0xc9, 0x4d, 0xc9, 0x00, 0xc6, 0xa3, 0x7e, 0x9b, 0xfe, 0x2b, + 0x3b, 0xeb, 0x8b, 0xbd, 0xc1, 0xd7, 0x31, 0xcf, 0xd8, 0x62, 0x15, 0x2a, + 0x1c, 0x7b, 0x75, 0xb2, 0x76, 0x45, 0x17, 0xed, 0xbf, 0xee, 0x2e, 0x96, + 0x99, 0x8f, 0xd2, 0xe2, 0x42, 0xc7, 0x0d, 0x6e, 0x01, 0x13, 0x1c, 0x00, + 0xa4, 0x4f, 0xb7, 0x6e, 0xd8, 0x38, 0x02, 0x9d, 0xe1, 0x66, 0xd3, 0xd5, + 0x20, 0xd6, 0xfa, 0x8c, 0x17, 0x80, 0x0f, 0x38, 0x9f, 0x8c, 0xa9, 0x15, + 0x4d, 0xc9, 0x25, 0x1a, 0x31, 0x54, 0xa6, 0xf3, 0x9e, 0x9c, 0xcd, 0x58, + 0xa3, 0x91, 0x51, 0x28, 0x5b, 0x72, 0xd2, 0xe5, 0x95, 0xbc, 0x00, 0x0e, + 0x7e, 0xef, 0x23, 0x47, 0xe3, 0xf5, 0xce, 0x2a, 0x13, 0xc3, 0xd5, 0x14, + 0x04, 0x45, 0x29, 0x29, 0xbe, 0x72, 0x00, 0xf7, 0x0d, 0x17, 0xed, 0xc7, + 0x7c, 0x00, 0xaa, 0x4e, 0x35, 0xea, 0xf2, 0xc7, 0x42, 0xa9, 0x47, 0x9e, + 0xde, 0xf3, 0x3a, 0x7f, 0x3b, 0xcb, 0xd3, 0x06, 0x5c, 0x26, 0x96, 0xa3, + 0x0b, 0x43, 0xda, 0xae, 0xa7, 0xbf, 0x31, 0x34, 0xc4, 0x1b, 0x38, 0xbc, + 0x42, 0xae, 0xd0, 0xc5, 0x6e, 0xbd, 0xbb, 0xb2, 0xe1, 0xb4, 0x34, 0xc4, + 0x56, 0xa5, 0xa8, 0x8a, 0xdf, 0x40, 0x8d, 0x39, 0xfe, 0xf1, 0xcc, 0x94, + 0x68, 0x79, 0x99, 0xdd, 0x8e, 0x8a, 0x5a, 0xab, 0xa8, 0xd5, 0x29, 0xb9, + 0xc0, 0x0e, 0x05, 0x80, 0x19, 0x73, 0x3a, 0x31, 0x00, 0x25, 0x8f, 0xda, + 0x4c, 0x94, 0x38, 0xed, 0xf5, 0x6e, 0x48, 0x8e, 0x9f, 0xf1, 0xcb, 0xb7, + 0xad, 0xb4, 0x05, 0x7c, 0xc2, 0x60, 0xdf, 0x06, 0xf9, 0x71, 0xa0, 0x02, + 0x6d, 0x15, 0xaf, 0xb2, 0x0c, 0x86, 0xf1, 0xb2, 0xdf, 0x46, 0xc7, 0xb7, + 0x9a, 0x2c, 0xcb, 0xe9, 0x30, 0xa8, 0xa0, 0x53, 0x25, 0x31, 0xf5, 0x51, + 0x80, 0x00, 0x00, 0x01, 0x06, 0x43, 0xf8, 0xce, 0x95, 0xb6, 0x28, 0x43, + 0x6a, 0xca, 0xf1, 0x3b, 0x30, 0xc4, 0x1c, 0x79, 0x7e, 0x81, 0x8d, 0x9b, + 0x67, 0x9f, 0x09, 0x81, 0x4d, 0xd8, 0x13, 0x08, 0x2e, 0x3f, 0xc5, 0x5b, + 0xc6, 0x45, 0x6f, 0x08, 0x73, 0x68, 0x2b, 0x2b, 0xa4, 0xcc, 0xf1, 0xa3, + 0x47, 0x35, 0x3d, 0x3a, 0x3b, 0xad, 0x4b, 0x24, 0x1b, 0x55, 0xb6, 0x5d, + 0x00, 0xb2, 0xda, 0xb0, 0x31, 0x25, 0x2d, 0xb9, 0xe4, 0xdc, 0x6c, 0x49, + 0x92, 0x44, 0x65, 0x92, 0x45, 0xad, 0xf7, 0xb4, 0x10, 0xbf, 0xc8, 0x67, + 0xa3, 0x07, 0xf6, 0x40, 0x10, 0x23, 0x97, 0x58, 0x1b, 0x23, 0xbc, 0xd6, + 0xc0, 0x08, 0xd1, 0xba, 0xcf, 0x04, 0x2f, 0xf1, 0x36, 0x12, 0x9b, 0xc0, + 0x7b, 0x60, 0x21, 0x80, 0x53, 0xa0, 0x5a, 0x3b, 0x32, 0x97, 0xe1, 0x4b, + 0x6e, 0x95, 0x58, 0x50, 0x00, 0xd5, 0xac, 0xf6, 0xf6, 0x91, 0x64, 0x23, + 0x76, 0x9b, 0x9e, 0x2a, 0x8a, 0xd5, 0xa8, 0x01, 0xee, 0x3b, 0x24, 0xf5, + 0xa7, 0x85, 0x37, 0xab, 0xea, 0xdc, 0x76, 0xba, 0xa8, 0x4c, 0xaa, 0x93, + 0xc4, 0x63, 0x78, 0xc4, 0xbb, 0xce, 0x52, 0x87, 0x52, 0xa4, 0x54, 0x09, + 0x6d, 0x00, 0x4a, 0xe5, 0xf5, 0x46, 0xb1, 0xad, 0xfa, 0xd8, 0x1c, 0x68, + 0x16, 0xde, 0x33, 0x01, 0x08, 0x02, 0xbb, 0x76, 0x6a, 0xf8, 0xe4, 0x01, + 0xf3, 0x7a, 0x23, 0x29, 0x3b, 0x81, 0x66, 0xba, 0x86, 0xce, 0x5c, 0x74, + 0x3c, 0xf0, 0xc6, 0xf9, 0xe7, 0x40, 0x84, 0x00, 0xce, 0x10, 0x58, 0x5e, + 0xcd, 0xc5, 0xa3, 0x8b, 0x4a, 0x31, 0x87, 0x01, 0x8c, 0x9b, 0x48, 0x4d, + 0x67, 0xc6, 0xfa, 0xc7, 0x48, 0xd5, 0xd2, 0xa4, 0x6d, 0x52, 0x99, 0x24, + 0xbe, 0xa8, 0x8d, 0xd7, 0x12, 0xe7, 0xff, 0x5c, 0xee, 0x2e, 0x69, 0xf7, + 0xc9, 0x7c, 0xff, 0x63, 0x0a, 0x1e, 0xc9, 0x93, 0x75, 0x22, 0x7c, 0xd7, + 0x1e, 0x80, 0x12, 0x4b, 0xbc, 0xdd, 0xa7, 0x7e, 0x8e, 0x28, 0xf3, 0xca, + 0x6c, 0xef, 0xbe, 0x77, 0x99, 0x28, 0x51, 0x93, 0x64, 0x90, 0x05, 0x45, + 0x97, 0x02, 0x9b, 0xb0, 0x4e, 0x00, 0x34, 0x73, 0xfc, 0x94, 0xe5, 0xa8, + 0xe0, 0x17, 0xb5, 0x0e, 0x5b, 0x2b, 0xec, 0xa7, 0x9d, 0x31, 0xdd, 0x87, + 0xc3, 0xc7, 0xea, 0x7a, 0xb6, 0xa7, 0xab, 0x7a, 0x64, 0xd3, 0x63, 0x79, + 0x72, 0x80, 0x1b, 0xde, 0x72, 0xcc, 0x87, 0xad, 0xcd, 0xe5, 0x66, 0x05, + 0xdc, 0x90, 0x86, 0xde, 0x9d, 0xdb, 0x7d, 0x85, 0x09, 0x36, 0x4a, 0x04, + 0xdc, 0xe7, 0x79, 0x76, 0xda, 0x79, 0xfa, 0xf2, 0xe7, 0xa2, 0xb7, 0x0b, + 0x8b, 0x7e, 0xbb, 0x5d, 0xda, 0x2c, 0xa6, 0xe4, 0x20, 0x3d, 0xe5, 0x24, + 0x2e, 0xaa, 0x01, 0x07, 0x8c, 0x69, 0xa8, 0x2f, 0x45, 0x53, 0x29, 0xd4, + 0x3a, 0x8a, 0x7b, 0xc8, 0x45, 0x07, 0xd0, 0xa2, 0x9b, 0x43, 0x9a, 0x69, + 0x73, 0x1b, 0xaa, 0x55, 0x8a, 0x80, 0x11, 0x28, 0x0b, 0x9b, 0x4c, 0x03, + 0x2f, 0x88, 0x9e, 0x38, 0x57, 0x83, 0x63, 0xdf, 0xca, 0xc2, 0x5d, 0x95, + 0xba, 0xbc, 0x82, 0x10, 0x05, 0x3e, 0x44, 0x00, 0x87, 0x2e, 0x7a, 0x29, + 0x71, 0xa1, 0xbb, 0x9b, 0xc9, 0xd8, 0x7d, 0xc7, 0xe5, 0x08, 0xbe, 0x52, + 0xca, 0xdc, 0xc8, 0xbf, 0x4b, 0xef, 0x89, 0x06, 0xd2, 0xa7, 0x2b, 0x14, + 0x24, 0xa8, 0xde, 0xc7, 0x6c, 0x8e, 0x15, 0x24, 0x2c, 0x27, 0x05, 0x80, + 0x0c, 0x4e, 0x6c, 0x1d, 0xed, 0xe7, 0x8f, 0x3c, 0x81, 0x0b, 0xc4, 0xb4, + 0x0a, 0x56, 0x4d, 0x34, 0x3a, 0x56, 0xfc, 0x87, 0xe3, 0xdd, 0x4c, 0xe6, + 0xc3, 0xf3, 0x0d, 0xb8, 0x90, 0xb2, 0x91, 0x5b, 0xef, 0x8e, 0x78, 0xa0, + 0x40, 0xfd, 0x31, 0x60, 0x0f, 0x3b, 0xd7, 0x28, 0x0f, 0x77, 0x97, 0x72, + 0x36, 0x96, 0x57, 0x92, 0xb7, 0xc6, 0x5d, 0xef, 0x99, 0xaf, 0x7f, 0x0f, + 0x2c, 0xbc, 0xfc, 0x29, 0xdb, 0x49, 0xa5, 0xb5, 0x5e, 0xd9, 0x9f, 0xf2, + 0x38, 0x8e, 0x39, 0xb2, 0x06, 0x3b, 0x9e, 0x66, 0x68, 0xe0, 0xd1, 0xa1, + 0x2c, 0x17, 0xb5, 0xbc, 0xb1, 0xb2, 0x37, 0xfd, 0x08, 0xfb, 0x71, 0xdb, + 0xf7, 0xe0, 0x5c, 0xb1, 0x01, 0x14, 0x01, 0x39, 0x2e, 0x59, 0x65, 0xf1, + 0x66, 0xff, 0x60, 0xb7, 0x67, 0xc7, 0xbd, 0xcc, 0x4a, 0x08, 0x80, 0x09, + 0xb6, 0x24, 0xb5, 0x42, 0x46, 0xb7, 0xce, 0x00, 0x09, 0xb6, 0x80, 0x2d, + 0x00, 0x75, 0xef, 0xaf, 0xa1, 0x86, 0x88, 0x73, 0xec, 0x4a, 0x14, 0x3a, + 0x84, 0x37, 0xd0, 0xfd, 0xb2, 0xf6, 0xee, 0x6c, 0x4a, 0x02, 0xad, 0x2b, + 0x14, 0x20, 0x73, 0x74, 0x94, 0x03, 0x46, 0xec, 0x0c, 0x6f, 0xd4, 0xdd, + 0x27, 0xda, 0x6b, 0x3e, 0x53, 0x35, 0xb0, 0xe0, 0x05, 0x36, 0xb5, 0xd2, + 0x93, 0xa5, 0x24, 0xb5, 0xc6, 0x51, 0xbb, 0x9d, 0x5b, 0x0e, 0x01, 0x89, + 0x09, 0x2d, 0x44, 0x86, 0x56, 0xa7, 0x0a, 0x67, 0x19, 0x37, 0xbc, 0x9a, + 0xd7, 0x4a, 0x5b, 0x62, 0x9f, 0x9c, 0x6d, 0x54, 0x3a, 0x56, 0x6c, 0xdb, + 0xe2, 0xf0, 0x08, 0x40, 0x13, 0x15, 0xab, 0x00, 0x9f, 0x61, 0x25, 0xb3, + 0x00, 0xe0, 0x9c, 0x84, 0xb6, 0xdc, 0xab, 0x76, 0x40, 0xa5, 0xcb, 0xb2, + 0x10, 0x9a, 0x20, 0x75, 0xb0, 0x94, 0xc1, 0xd6, 0xb7, 0xdb, 0x77, 0xe6, + 0x21, 0x2d, 0xbe, 0x20, 0x00, 0xaf, 0x8a, 0x00, 0x4d, 0x04, 0x7d, 0x39, + 0x9b, 0x0e, 0xaa, 0xf7, 0x3a, 0xf9, 0x58, 0x30, 0x3a, 0x6d, 0x54, 0x29, + 0xbe, 0x99, 0xf0, 0xf7, 0x7b, 0xb8, 0xde, 0x70, 0xa2, 0x8b, 0x2e, 0x85, + 0x37, 0x75, 0xcf, 0xa4, 0x0d, 0xd7, 0x4a, 0x19, 0x6c, 0x8b, 0x15, 0xb8, + 0xee, 0xa7, 0xb7, 0x20, 0x03, 0xe6, 0xc2, 0xd4, 0xe2, 0xd6, 0xff, 0x23, + 0x73, 0x2a, 0x9f, 0xe0, 0xb1, 0xbe, 0x90, 0x2b, 0x8d, 0xe7, 0xad, 0xdd, + 0xcd, 0xa0, 0x2a, 0xda, 0xb1, 0x02, 0x0a, 0xa7, 0x04, 0x2d, 0x6f, 0xa4, + 0x80, 0x21, 0xfb, 0x80, 0x58, 0x29, 0xce, 0xaf, 0xc8, 0x54, 0x36, 0xad, + 0x1a, 0xdb, 0x88, 0xbf, 0x5d, 0x12, 0x00, 0xf7, 0x67, 0x31, 0x3f, 0x59, + 0x32, 0x01, 0x03, 0x6b, 0x72, 0x89, 0x70, 0x05, 0xbc, 0xc4, 0xf5, 0x87, + 0xb6, 0x3c, 0xcf, 0x3d, 0x84, 0xb8, 0xdf, 0x24, 0x01, 0xcf, 0x1b, 0xf5, + 0xeb, 0x70, 0x8d, 0xe7, 0x40, 0x05, 0x35, 0x2c, 0xaf, 0x74, 0x3a, 0x24, + 0xb4, 0x7b, 0x79, 0x72, 0x2f, 0x00, 0x06, 0x9f, 0x51, 0x46, 0xe3, 0xa5, + 0x28, 0x39, 0x1d, 0x6b, 0xed, 0x52, 0xcf, 0x48, 0x5c, 0x6f, 0x42, 0x00, + 0xfa, 0x8a, 0xfe, 0x77, 0x66, 0x73, 0x65, 0x96, 0x13, 0x24, 0xab, 0x4b, + 0x1f, 0x03, 0x0f, 0x6f, 0x2a, 0x08, 0x00, 0x5b, 0xf5, 0xe3, 0x91, 0x35, + 0xfd, 0x7b, 0x29, 0xd2, 0xe5, 0xda, 0x04, 0x15, 0x9b, 0x2c, 0x0c, 0x28, + 0x63, 0x77, 0x5a, 0x95, 0x6b, 0x69, 0xb4, 0x38, 0xda, 0x4b, 0x6f, 0x18, + 0x03, 0x97, 0x67, 0xc8, 0x97, 0x71, 0xc7, 0xb2, 0x1c, 0x5c, 0x73, 0x89, + 0xa8, 0x34, 0xb6, 0xf9, 0x29, 0x1f, 0x8e, 0x40, 0x1d, 0x5f, 0xa3, 0xed, + 0xc3, 0xae, 0x5d, 0x9c, 0x3b, 0x26, 0xc8, 0x7c, 0x3c, 0xc2, 0xdb, 0xe8, + 0x40, 0x05, 0x9e, 0xfd, 0x88, 0xfe, 0x40, 0x0a, 0xf3, 0xe2, 0x55, 0xe2, + 0x93, 0xb8, 0xe2, 0x07, 0xbd, 0xf3, 0x4c, 0x45, 0xa1, 0x0d, 0xe7, 0x6f, + 0x45, 0x4e, 0x84, 0x6c, 0x15, 0xaf, 0x7e, 0x57, 0x64, 0x44, 0xd8, 0xf9, + 0xa5, 0x6e, 0x5f, 0x52, 0xdb, 0x93, 0x97, 0x5f, 0x28, 0x96, 0xc1, 0x95, + 0x62, 0x2b, 0x48, 0xb8, 0x1c, 0x55, 0x60, 0x00, 0x00, 0x01, 0x07, 0x43, + 0xf9, 0xef, 0xbc, 0xbd, 0xf1, 0x2e, 0xf8, 0x28, 0xda, 0x7b, 0x6b, 0xe9, + 0xf8, 0x44, 0xed, 0xfc, 0xf3, 0xe1, 0x2d, 0x92, 0x40, 0xa6, 0xf6, 0xa0, + 0x0f, 0xc5, 0x69, 0x17, 0xdb, 0x08, 0xe2, 0x62, 0x0d, 0x41, 0x5b, 0xd5, + 0x93, 0x9b, 0x03, 0xaf, 0xe7, 0x16, 0x20, 0x4b, 0x5c, 0x08, 0x1f, 0x9e, + 0x44, 0xe0, 0x01, 0x87, 0xff, 0xdf, 0xe2, 0x0a, 0xdb, 0x0a, 0xf3, 0xdb, + 0xc6, 0xba, 0xcd, 0x87, 0x00, 0x4f, 0xc0, 0x49, 0x54, 0xa0, 0xc6, 0xf2, + 0xec, 0xb9, 0x6b, 0x78, 0xef, 0x94, 0x3e, 0x56, 0xfe, 0x39, 0x92, 0x3b, + 0x12, 0x4f, 0x09, 0x1b, 0x66, 0x82, 0x17, 0xfc, 0xcd, 0x6c, 0xfc, 0xca, + 0x55, 0xb0, 0x25, 0xbd, 0x28, 0x98, 0x4f, 0x17, 0xb4, 0xb0, 0xa7, 0xbb, + 0x10, 0x30, 0xf5, 0xb2, 0xdf, 0x4a, 0xdc, 0x96, 0x1b, 0x91, 0xb0, 0xd8, + 0xb1, 0xbb, 0xc4, 0x69, 0x3f, 0xe7, 0x93, 0x00, 0x06, 0x90, 0xb4, 0x08, + 0x6f, 0x99, 0x4f, 0xd4, 0x21, 0x15, 0x00, 0xa8, 0xdf, 0x53, 0x13, 0x6b, + 0xf2, 0xcc, 0x50, 0x11, 0x66, 0x2a, 0x8d, 0x3e, 0xc0, 0x29, 0xbe, 0x64, + 0xf2, 0xab, 0xa9, 0x2a, 0xc6, 0xde, 0xc2, 0xca, 0x21, 0xab, 0x69, 0x43, + 0xeb, 0x7e, 0xc0, 0x52, 0x91, 0xf6, 0xe9, 0x9a, 0x03, 0xca, 0x61, 0x55, + 0xbd, 0x30, 0x9d, 0x04, 0x1f, 0xeb, 0x22, 0x0a, 0xa0, 0x15, 0x8e, 0x88, + 0x64, 0x35, 0x40, 0x21, 0x30, 0xb0, 0xb2, 0x9b, 0xc2, 0xcf, 0xc9, 0xab, + 0xe1, 0x36, 0xb7, 0xd3, 0xa3, 0x9e, 0x00, 0xff, 0xb7, 0xc3, 0xc3, 0x2c, + 0x77, 0x2e, 0x31, 0x22, 0x9c, 0x66, 0x9f, 0xe2, 0xb2, 0x36, 0xce, 0x2b, + 0x6c, 0x80, 0x03, 0x36, 0xb3, 0x9b, 0xbc, 0x8e, 0x47, 0xe9, 0xc0, 0x0f, + 0x40, 0x1a, 0x64, 0xf6, 0x75, 0xa1, 0xe7, 0xf0, 0x2e, 0x5e, 0xf3, 0x4e, + 0x54, 0xb1, 0x56, 0xa1, 0x47, 0x14, 0xad, 0xf1, 0xaf, 0xfb, 0xf8, 0x14, + 0x67, 0x13, 0x75, 0x28, 0x09, 0x40, 0x0f, 0xbc, 0xaf, 0x39, 0x07, 0x15, + 0x12, 0x4d, 0xa3, 0xcb, 0x18, 0xde, 0xfb, 0xe0, 0xc1, 0x5e, 0xd9, 0xd3, + 0xf6, 0x86, 0x43, 0x70, 0xf1, 0x84, 0xc2, 0x9b, 0xca, 0xce, 0x5e, 0x00, + 0xe8, 0x50, 0x8e, 0x44, 0xbf, 0x27, 0xea, 0x4a, 0x2f, 0xcf, 0xbc, 0x83, + 0x40, 0x71, 0xc6, 0xc8, 0x64, 0xa0, 0x2a, 0x88, 0x5b, 0x72, 0x24, 0xb8, + 0xe5, 0xf5, 0x91, 0xaa, 0x07, 0xc8, 0xdf, 0x8e, 0xe3, 0x2b, 0x85, 0xbe, + 0xdc, 0x1e, 0x92, 0x6c, 0x83, 0x42, 0x80, 0xb6, 0xe8, 0x80, 0x34, 0xf8, + 0x9d, 0xf2, 0xf5, 0xf3, 0x79, 0x6a, 0x6d, 0x2e, 0xad, 0x03, 0x9b, 0x97, + 0x92, 0x7b, 0x3b, 0xaf, 0x30, 0x08, 0x67, 0x7e, 0x7b, 0x02, 0xe1, 0xb2, + 0xd9, 0xe1, 0x1b, 0x36, 0x6c, 0xc9, 0x69, 0x41, 0x76, 0x92, 0x9b, 0xbe, + 0xd6, 0xde, 0xd4, 0x8d, 0xfb, 0x2e, 0x1c, 0x00, 0x6e, 0x2b, 0xcb, 0xac, + 0x41, 0xa9, 0xb1, 0xd6, 0xca, 0x36, 0xd2, 0xcf, 0x2d, 0x91, 0x2c, 0xd7, + 0xa9, 0x61, 0x13, 0x99, 0x7d, 0x43, 0x1b, 0x86, 0x46, 0x80, 0x16, 0xf7, + 0x75, 0x02, 0x2b, 0xf6, 0x44, 0x1f, 0x5b, 0xd4, 0x13, 0x45, 0x3e, 0xdc, + 0x09, 0xb8, 0xaa, 0x10, 0x74, 0x89, 0x59, 0xb7, 0x58, 0x04, 0xea, 0xda, + 0x77, 0x63, 0xf3, 0x26, 0xe8, 0x64, 0x27, 0xb9, 0xda, 0x50, 0xd3, 0xb6, + 0xc3, 0xe0, 0x50, 0xd6, 0xeb, 0x79, 0x80, 0x1d, 0x80, 0x59, 0x2d, 0x1a, + 0x51, 0x3e, 0x7c, 0x73, 0x74, 0x34, 0x3a, 0xba, 0xd4, 0xb0, 0x21, 0xb9, + 0x50, 0xcf, 0x7b, 0xb5, 0x7c, 0x33, 0x6e, 0x6c, 0x01, 0x10, 0xdb, 0x60, + 0x51, 0x8c, 0xee, 0xd2, 0x7c, 0xfb, 0x97, 0x00, 0x45, 0xe6, 0xe5, 0x38, + 0x08, 0x54, 0x0e, 0x2c, 0x09, 0x6b, 0x6d, 0x87, 0x36, 0xd4, 0xbb, 0x57, + 0xd6, 0x52, 0x9b, 0xaa, 0xe5, 0xe1, 0xc2, 0xf7, 0x02, 0xcc, 0xdd, 0x4b, + 0x02, 0xcc, 0x1a, 0xdc, 0xf1, 0x33, 0x78, 0xdc, 0xcc, 0x41, 0xcf, 0x8f, + 0xf2, 0xb0, 0xbf, 0x16, 0x5e, 0x26, 0x10, 0x66, 0x3f, 0x03, 0x0f, 0xb5, + 0x4b, 0x2a, 0x9e, 0x31, 0xa5, 0xba, 0x1b, 0x7e, 0xb1, 0x61, 0x9a, 0x16, + 0x08, 0x5f, 0xf0, 0xbb, 0x84, 0x34, 0x29, 0xb5, 0xd9, 0x05, 0xd7, 0x62, + 0x06, 0xa1, 0x3a, 0xe4, 0x21, 0x2e, 0x36, 0x7e, 0xd1, 0xdc, 0x73, 0xc7, + 0x3a, 0x80, 0x4d, 0xc5, 0x26, 0x69, 0xf4, 0xf3, 0xa5, 0x95, 0xb7, 0xe5, + 0xbb, 0xc5, 0x72, 0x51, 0xa5, 0xc4, 0xee, 0xb8, 0x02, 0x23, 0x1e, 0x70, + 0x5c, 0x66, 0xd0, 0xdf, 0x89, 0x16, 0x68, 0xaa, 0x21, 0x22, 0x84, 0x8a, + 0xb8, 0x6a, 0x8f, 0x0c, 0x6a, 0xce, 0xd3, 0x0f, 0x1a, 0xb2, 0x2d, 0x6f, + 0x4e, 0x2b, 0x34, 0x01, 0xe0, 0xb8, 0xe7, 0xb8, 0x22, 0xed, 0x76, 0xc2, + 0xd4, 0x72, 0xcb, 0x03, 0x1b, 0xc5, 0x7c, 0x75, 0xce, 0xf4, 0x7e, 0xd0, + 0xa2, 0xca, 0xa5, 0xc2, 0xa8, 0xe8, 0xca, 0xb7, 0x9b, 0x43, 0xae, 0x12, + 0x1b, 0xfa, 0xe7, 0xfb, 0xb0, 0x41, 0xfc, 0xf2, 0x38, 0x03, 0xec, 0xe3, + 0x6c, 0x1d, 0x2b, 0xf8, 0xaf, 0x2d, 0x42, 0x30, 0x94, 0xdf, 0xb3, 0x9d, + 0xaa, 0xaa, 0xdf, 0xcf, 0x3d, 0x9b, 0xdb, 0xec, 0x8a, 0x02, 0x2d, 0x38, + 0x7b, 0x7e, 0xb4, 0x00, 0x6d, 0x01, 0x07, 0xf6, 0x3f, 0x84, 0x77, 0xe0, + 0x25, 0x00, 0x25, 0xec, 0xd9, 0x00, 0x47, 0x06, 0xb5, 0x40, 0xf6, 0xa8, + 0x1e, 0xdf, 0xd9, 0x78, 0x03, 0x2d, 0xa1, 0xc5, 0x56, 0xe4, 0xe0, 0x19, + 0xc4, 0x66, 0xe0, 0x0c, 0x5a, 0xdb, 0xb6, 0xed, 0xea, 0xe2, 0x99, 0x1b, + 0x99, 0xc7, 0xe1, 0xb9, 0x62, 0x2c, 0x96, 0x49, 0xb6, 0x0d, 0x8b, 0x1b, + 0x8f, 0xf6, 0xd0, 0x03, 0xcf, 0x77, 0xe4, 0x99, 0x4f, 0x9b, 0x2c, 0x59, + 0xb2, 0xc0, 0xa6, 0x50, 0xaa, 0xd1, 0x2a, 0x37, 0xeb, 0x05, 0x02, 0x17, + 0xfb, 0xa6, 0xcf, 0x41, 0xad, 0xea, 0x25, 0x36, 0x54, 0x6f, 0xce, 0xdf, + 0xcf, 0x69, 0xae, 0x14, 0xe5, 0xc5, 0x39, 0xe2, 0xe0, 0xb7, 0x38, 0xd2, + 0xbf, 0x15, 0x2c, 0xda, 0x75, 0xb0, 0x69, 0x71, 0xbe, 0xde, 0x20, 0x10, + 0x80, 0x2f, 0xdd, 0xf3, 0xd6, 0x22, 0xb6, 0x3c, 0x5f, 0x37, 0x16, 0x42, + 0x65, 0x29, 0xb8, 0x5b, 0x78, 0x09, 0x97, 0xa0, 0x4d, 0x00, 0x34, 0x6d, + 0xbd, 0xc4, 0x14, 0x2f, 0x41, 0x30, 0x01, 0x26, 0x94, 0xde, 0x2c, 0x8d, + 0xd0, 0x05, 0x62, 0x3d, 0x95, 0xda, 0x1b, 0x39, 0xe3, 0x69, 0x70, 0xe3, + 0x8b, 0x29, 0xbd, 0x58, 0x80, 0x0a, 0x75, 0xcf, 0x2c, 0x26, 0x6b, 0x96, + 0x90, 0x95, 0xa7, 0x8d, 0x97, 0x87, 0xca, 0x00, 0x34, 0x2f, 0xd1, 0x2b, + 0x10, 0x99, 0x54, 0x84, 0xdf, 0x3c, 0x01, 0xb8, 0x9c, 0xf2, 0xae, 0x97, + 0x1d, 0x16, 0xd7, 0xcc, 0x40, 0x1c, 0xc5, 0xba, 0x70, 0xf6, 0xf3, 0x7c, + 0x7f, 0x2d, 0xf9, 0xf8, 0x13, 0x7d, 0xa5, 0x01, 0xe3, 0xf1, 0xe8, 0x56, + 0x54, 0x45, 0x5c, 0x2d, 0x1a, 0xcf, 0x8d, 0x22, 0x00, 0x3a, 0xfb, 0xe5, + 0x15, 0xd8, 0xbc, 0x2a, 0xcb, 0xaf, 0x4b, 0x32, 0xf0, 0xf8, 0x6c, 0x83, + 0x4e, 0x1a, 0xde, 0x4c, 0x10, 0x00, 0xb0, 0x48, 0x01, 0xb0, 0x05, 0xb7, + 0xdf, 0x38, 0xd8, 0xb5, 0x09, 0xd8, 0x4d, 0xba, 0x93, 0x15, 0x5b, 0xe7, + 0xf3, 0xd9, 0xfc, 0x98, 0x6d, 0x90, 0x71, 0xc3, 0x4e, 0x18, 0x1a, 0x48, + 0x6c, 0x77, 0x2d, 0x8a, 0xad, 0xfb, 0x80, 0x07, 0x4b, 0xc7, 0x66, 0xf0, + 0xfc, 0x0c, 0xb3, 0x1e, 0x51, 0x44, 0x8a, 0xde, 0x64, 0x00, 0xb3, 0xdf, + 0x8f, 0x61, 0x78, 0x6f, 0x1d, 0xe4, 0x2d, 0x2c, 0xd8, 0x53, 0xcc, 0x0e, + 0xb5, 0xbe, 0x32, 0xff, 0x69, 0x40, 0x1e, 0x57, 0x3b, 0x1d, 0x4a, 0xbb, + 0x26, 0xe3, 0xcf, 0xee, 0x87, 0xe2, 0x4a, 0x74, 0x30, 0xe4, 0x6e, 0x50, + 0x00, 0x9f, 0x8c, 0x7a, 0x0a, 0xe9, 0xc3, 0x00, 0x2d, 0x7c, 0xc9, 0x6d, + 0xfc, 0x5b, 0x2d, 0x92, 0x51, 0xaa, 0x53, 0x7d, 0x01, 0x93, 0x55, 0x20, + 0x1b, 0x6e, 0xae, 0x64, 0xa4, 0xc8, 0xdf, 0xa6, 0xe0, 0x8b, 0xf6, 0x23, + 0x7d, 0x3d, 0xba, 0xf6, 0x78, 0xbf, 0x25, 0xf2, 0xdd, 0xa8, 0xbb, 0xa3, + 0x64, 0x5a, 0x52, 0xa4, 0x29, 0xa8, 0xfb, 0x00, 0x3b, 0x7e, 0x76, 0x41, + 0xef, 0xd9, 0xcf, 0x92, 0xcf, 0x37, 0x87, 0x2f, 0x94, 0x87, 0x59, 0x14, + 0x62, 0xb7, 0x91, 0x82, 0x7e, 0xae, 0xc3, 0x7e, 0x66, 0x4c, 0x2f, 0x05, + 0x3a, 0x19, 0x34, 0xad, 0xa6, 0x94, 0x70, 0xc6, 0xf5, 0x60, 0x09, 0x67, + 0x42, 0xdf, 0xb1, 0xdf, 0x3a, 0xa1, 0xd4, 0x6d, 0x44, 0x90, 0xba, 0x3c, + 0x73, 0x59, 0x6d, 0xd0, 0x13, 0x5b, 0xec, 0xfb, 0x08, 0xe9, 0xd9, 0xdd, + 0x10, 0x00, 0xf4, 0x5e, 0x5b, 0x2e, 0x3f, 0x45, 0xc0, 0x45, 0x00, 0x6d, + 0xb4, 0xd2, 0x6a, 0x9e, 0x50, 0xf6, 0xf2, 0x1f, 0x40, 0x07, 0xe2, 0xfa, + 0x4c, 0x00, 0x3e, 0x14, 0xe9, 0x25, 0x9e, 0xce, 0xc2, 0x91, 0xd0, 0x37, + 0xd6, 0x8f, 0x6e, 0x6f, 0xf5, 0xf9, 0xcf, 0x0e, 0xf3, 0x88, 0x04, 0x3b, + 0x9c, 0xd2, 0x61, 0xb1, 0x52, 0x98, 0xa5, 0x29, 0xfe, 0x8d, 0xb8, 0x00, + 0x4e, 0xe7, 0x0b, 0xda, 0x65, 0x45, 0xb8, 0x1d, 0x0d, 0x54, 0x55, 0x21, + 0x2b, 0x38, 0xc3, 0x00, 0x00, 0x00, 0x01, 0x08, 0x43, 0xf3, 0xc0, 0x0f, + 0xbd, 0x85, 0x00, 0x3b, 0xfb, 0x8a, 0xeb, 0x9e, 0x5c, 0x74, 0x97, 0xca, + 0x4d, 0xd3, 0x21, 0x32, 0x45, 0x52, 0xbd, 0x20, 0xe6, 0xfb, 0x10, 0x20, + 0x01, 0x6b, 0xaf, 0xd7, 0xa9, 0xcf, 0xd1, 0xd7, 0x6f, 0xee, 0x72, 0x65, + 0xdc, 0x86, 0x87, 0x4a, 0xa5, 0x15, 0xe2, 0xdf, 0x0a, 0x7d, 0xf3, 0xb2, + 0x44, 0x1c, 0x51, 0x48, 0xde, 0x82, 0x6d, 0x7c, 0x6e, 0x51, 0xf5, 0xbc, + 0xa2, 0xa5, 0x2d, 0xbe, 0x71, 0x1e, 0xdf, 0x61, 0x7d, 0x2a, 0xc3, 0xe6, + 0xaf, 0x56, 0x13, 0xd6, 0x1d, 0xf9, 0x88, 0x77, 0x8c, 0x6d, 0x54, 0x0c, + 0x20, 0x26, 0xff, 0xdd, 0x80, 0x02, 0xd2, 0x43, 0x6a, 0xd5, 0x73, 0xb5, + 0xef, 0x50, 0xa9, 0x13, 0x50, 0x23, 0x56, 0x95, 0x42, 0x47, 0x35, 0xdf, + 0x34, 0x50, 0x03, 0x7f, 0xb7, 0xd8, 0x4b, 0x9e, 0xa3, 0x2a, 0x89, 0xc0, + 0xba, 0x55, 0xbb, 0x4a, 0x0b, 0x2d, 0xb9, 0x6d, 0x5b, 0x2b, 0x03, 0x29, + 0x24, 0x0e, 0x6f, 0xd2, 0x80, 0x3b, 0x50, 0x05, 0x7f, 0xcf, 0x8d, 0xc3, + 0x87, 0x76, 0xfd, 0x93, 0x89, 0x60, 0x23, 0xff, 0xed, 0xfd, 0x46, 0xf8, + 0x80, 0xb3, 0x40, 0x1e, 0x09, 0xf8, 0xb4, 0x2e, 0x68, 0x8d, 0x14, 0xfb, + 0x01, 0x28, 0x01, 0x75, 0xc4, 0x86, 0xfd, 0xa9, 0xbd, 0xf9, 0x80, 0x3b, + 0xef, 0x9b, 0x68, 0xeb, 0x7b, 0x73, 0xf7, 0x38, 0x48, 0x5a, 0x07, 0x5b, + 0x0e, 0x38, 0x75, 0x6f, 0xca, 0x42, 0xaf, 0x3f, 0xce, 0xbf, 0xef, 0xb6, + 0x86, 0x71, 0x2d, 0x11, 0xed, 0x31, 0xc3, 0x49, 0xae, 0xe1, 0x57, 0x42, + 0x54, 0x63, 0x68, 0x4c, 0x90, 0x0b, 0x62, 0xd2, 0xdb, 0xf1, 0x6e, 0xa4, + 0xfb, 0x25, 0x8d, 0xf7, 0xd7, 0x72, 0xf7, 0x38, 0x01, 0xef, 0x74, 0x5b, + 0xb0, 0x65, 0xe0, 0x57, 0xcf, 0x7d, 0xee, 0x45, 0x3c, 0x08, 0x40, 0x08, + 0x13, 0x1b, 0xe4, 0xc0, 0x0f, 0xd4, 0x01, 0x18, 0x03, 0xef, 0xa7, 0x28, + 0x17, 0x5f, 0x6f, 0x19, 0x07, 0x1f, 0x29, 0x70, 0x2a, 0xa3, 0x7e, 0x94, + 0x00, 0x5b, 0x98, 0x23, 0x9e, 0x70, 0x50, 0x9e, 0x60, 0xc0, 0xfe, 0x37, + 0x62, 0x43, 0xec, 0x2c, 0x30, 0x2d, 0xbc, 0x1e, 0x85, 0x51, 0x06, 0x3f, + 0x98, 0xa1, 0x97, 0xf4, 0xad, 0x89, 0x86, 0x1f, 0xea, 0x31, 0xbf, 0xcf, + 0x40, 0x0f, 0xe6, 0x70, 0xfd, 0xb2, 0x51, 0xf4, 0xdb, 0x64, 0x8d, 0xc9, + 0xf7, 0xec, 0x00, 0xf1, 0xd6, 0xed, 0x81, 0xb1, 0x68, 0xc8, 0xdd, 0xe1, + 0x58, 0x00, 0x65, 0xe6, 0xf2, 0xf2, 0x9e, 0x4c, 0x96, 0xac, 0xf0, 0x6f, + 0x9f, 0x09, 0x9d, 0x09, 0xf8, 0x5a, 0x90, 0x25, 0xda, 0x1d, 0x29, 0xf0, + 0x6b, 0x75, 0x82, 0x1f, 0xfd, 0x4d, 0x84, 0x2a, 0xc2, 0x1a, 0xad, 0xe1, + 0xf9, 0x2f, 0xb8, 0xf4, 0x0a, 0xd7, 0x64, 0x56, 0x5e, 0x6d, 0xcc, 0x7f, + 0x25, 0x86, 0xcb, 0x76, 0x44, 0x90, 0x2a, 0x01, 0xed, 0xde, 0x7e, 0xa0, + 0xb7, 0xdf, 0x4a, 0x38, 0x29, 0x98, 0x4d, 0x37, 0xad, 0x76, 0xcf, 0x16, + 0xeb, 0x90, 0xb2, 0x9b, 0x5c, 0x1a, 0xdf, 0x8e, 0xe5, 0x5c, 0x6d, 0xa8, + 0x14, 0xb2, 0x7a, 0xd2, 0xdb, 0xd6, 0xc7, 0xcf, 0x9a, 0x92, 0xd0, 0xbd, + 0x76, 0xec, 0xd0, 0xa8, 0xb5, 0x4a, 0x0c, 0xaa, 0xd8, 0xbb, 0x80, 0x16, + 0x53, 0x37, 0x65, 0x0b, 0xa3, 0x42, 0xda, 0x02, 0x1f, 0xfd, 0x66, 0x3e, + 0x50, 0xab, 0x72, 0x12, 0x49, 0x05, 0xb6, 0xf9, 0xf9, 0x8d, 0xd7, 0x00, + 0x29, 0x6f, 0x4c, 0xd2, 0x78, 0xb1, 0x49, 0x02, 0x56, 0xbf, 0x0a, 0xb0, + 0x24, 0x63, 0x59, 0xde, 0xcf, 0x2b, 0x2b, 0xd4, 0x00, 0x53, 0x04, 0x41, + 0x4e, 0xb6, 0x82, 0x3f, 0xfe, 0x64, 0xa0, 0x51, 0xed, 0x97, 0x6d, 0xcd, + 0xdd, 0x93, 0x46, 0x95, 0x9c, 0x19, 0x36, 0x8d, 0xa5, 0x9a, 0x51, 0x61, + 0x2d, 0xd8, 0xee, 0x00, 0x1e, 0xbb, 0xaa, 0xf7, 0x0f, 0xae, 0x97, 0x33, + 0x5e, 0xf0, 0xc3, 0xd6, 0x15, 0x09, 0x2d, 0xd0, 0xdd, 0xc3, 0x9b, 0xaf, + 0xac, 0xa4, 0x5c, 0xba, 0x96, 0x45, 0x59, 0xba, 0x31, 0xba, 0x1c, 0xbe, + 0x6f, 0x9e, 0xdc, 0x00, 0x85, 0xdb, 0x0d, 0x42, 0x8e, 0x09, 0x6a, 0x74, + 0x9f, 0xf2, 0xfc, 0xe5, 0xd6, 0x86, 0xa7, 0x46, 0x50, 0xf0, 0x11, 0x9e, + 0x5b, 0x0a, 0xaf, 0xfb, 0xf5, 0x24, 0x09, 0x8f, 0xb2, 0x10, 0xe8, 0xca, + 0xd0, 0xda, 0x9e, 0xd8, 0xc4, 0xf9, 0xef, 0xa4, 0x08, 0x5d, 0x29, 0x14, + 0x2a, 0x36, 0xfb, 0x40, 0x2b, 0x17, 0xc7, 0x21, 0xe1, 0x16, 0x64, 0x73, + 0xe0, 0x5e, 0xfe, 0xa0, 0x59, 0x4d, 0x57, 0x69, 0xf6, 0x13, 0x9c, 0x72, + 0x81, 0x69, 0x13, 0x40, 0xea, 0xd4, 0x67, 0x37, 0xdb, 0x1e, 0xed, 0xd0, + 0x4a, 0xff, 0x9c, 0xca, 0x58, 0x40, 0xef, 0x05, 0x6b, 0x64, 0xde, 0x8a, + 0xbc, 0xc7, 0xd9, 0x14, 0x08, 0xdb, 0x9e, 0xf2, 0x4a, 0x30, 0x07, 0x33, + 0x88, 0x96, 0x85, 0x37, 0x87, 0xc8, 0x68, 0x8f, 0x6c, 0x7e, 0x84, 0xdb, + 0x68, 0x7a, 0x04, 0x23, 0x7d, 0x02, 0x82, 0x10, 0x03, 0x89, 0xf6, 0xc9, + 0x94, 0x12, 0x3f, 0xf7, 0x1d, 0x39, 0x77, 0x8e, 0x19, 0xb2, 0x90, 0xdb, + 0xe6, 0x8f, 0x90, 0x57, 0xd7, 0xae, 0x65, 0x0a, 0xc1, 0x56, 0x1a, 0xa7, + 0x9f, 0x06, 0xc0, 0xb6, 0x88, 0x53, 0x71, 0xd0, 0x30, 0x53, 0x7e, 0xe9, + 0xe9, 0xd1, 0x1c, 0x5e, 0x3b, 0xc7, 0x83, 0x16, 0xdf, 0x46, 0xf7, 0x9f, + 0xc8, 0x08, 0x3f, 0x95, 0xcf, 0xf8, 0x4a, 0x50, 0x49, 0xff, 0xde, 0x2c, + 0x80, 0x96, 0x00, 0x65, 0x12, 0x5b, 0xe0, 0x62, 0xac, 0x77, 0x9e, 0xdc, + 0x83, 0x12, 0x4a, 0x54, 0xf0, 0x6f, 0xb7, 0x7b, 0xc0, 0x41, 0xfc, 0x40, + 0x01, 0x16, 0x20, 0x04, 0x37, 0x99, 0x28, 0x59, 0x8b, 0x69, 0x29, 0xad, + 0x4e, 0x24, 0xb6, 0x14, 0xba, 0xdf, 0xec, 0x25, 0x41, 0xbe, 0x8a, 0xde, + 0x30, 0x01, 0xf3, 0xc1, 0x04, 0x06, 0x40, 0x1f, 0xfc, 0x8a, 0x77, 0x8d, + 0xe1, 0xf5, 0x60, 0x08, 0xaa, 0x07, 0xc0, 0xa6, 0xf5, 0x90, 0xaa, 0x00, + 0x2e, 0x6f, 0xcb, 0xe0, 0x0f, 0x90, 0x10, 0x00, 0xeb, 0x8e, 0x3e, 0xba, + 0x09, 0x7f, 0xf7, 0x49, 0xce, 0xa3, 0x0e, 0xb4, 0x9b, 0xe3, 0x0e, 0x6d, + 0x4e, 0xad, 0xbc, 0x29, 0x5b, 0xf0, 0x00, 0x0c, 0x3d, 0xba, 0x7f, 0xdb, + 0x8c, 0xf8, 0xce, 0x20, 0xfd, 0xe7, 0x7c, 0xa6, 0x2d, 0x0d, 0x39, 0xac, + 0xff, 0x0a, 0xe1, 0xfd, 0x57, 0xd7, 0xe4, 0x91, 0x77, 0x5f, 0xb9, 0x61, + 0xb6, 0xda, 0x87, 0xa0, 0xe0, 0x96, 0xe0, 0x89, 0xf2, 0xe4, 0xd8, 0xb5, + 0x00, 0x95, 0x1c, 0xad, 0xab, 0xce, 0x80, 0x3b, 0x00, 0x32, 0xc1, 0x5b, + 0x2c, 0x04, 0x6f, 0xfa, 0x7f, 0x91, 0x98, 0x34, 0x9a, 0x6d, 0x89, 0x02, + 0xdb, 0xcf, 0x44, 0x76, 0xda, 0x42, 0x46, 0xe5, 0xb0, 0x39, 0x5b, 0xfd, + 0x1f, 0xf7, 0xea, 0x82, 0x07, 0xe7, 0xf1, 0x08, 0x9e, 0xd7, 0x06, 0x79, + 0x79, 0xce, 0x57, 0xbc, 0x1c, 0x1d, 0x83, 0x2d, 0x6e, 0xf8, 0x03, 0x2e, + 0x78, 0x00, 0x4d, 0xce, 0x6f, 0x9d, 0x0c, 0x80, 0x3d, 0x0b, 0x0c, 0x87, + 0xb7, 0x8d, 0x04, 0x00, 0x2a, 0x73, 0xc0, 0x1b, 0x39, 0xef, 0xf9, 0x17, + 0x69, 0x6b, 0x99, 0xca, 0xd3, 0x62, 0xd3, 0x6c, 0x50, 0x96, 0xf9, 0xd8, + 0xae, 0x35, 0xdf, 0x13, 0x20, 0x8b, 0x85, 0xa6, 0x4c, 0x45, 0x8b, 0x36, + 0xae, 0x97, 0x7c, 0x5b, 0x67, 0xd8, 0x6b, 0xf7, 0x69, 0x08, 0xa6, 0xea, + 0xe4, 0xbb, 0xb6, 0xd0, 0x29, 0xbf, 0xa5, 0x80, 0x17, 0x7d, 0x4d, 0xf7, + 0xbb, 0xf3, 0xc3, 0xb9, 0x8a, 0x86, 0xa0, 0xc9, 0x85, 0x17, 0x10, 0xf3, + 0xc3, 0x15, 0xbc, 0x68, 0x03, 0x22, 0x37, 0x5d, 0x7b, 0x0a, 0x70, 0x05, + 0xbe, 0xd6, 0x93, 0x79, 0x78, 0xdd, 0x32, 0x40, 0xf1, 0xc5, 0x2b, 0x64, + 0x00, 0x71, 0xf6, 0xe6, 0x7b, 0xc5, 0x78, 0x9d, 0xb0, 0x9b, 0x77, 0x6a, + 0xdd, 0x58, 0x92, 0x14, 0x10, 0x34, 0xb6, 0xe6, 0x00, 0x36, 0x23, 0x70, + 0x66, 0x2d, 0xef, 0x6f, 0xed, 0xdc, 0x21, 0xd9, 0x0f, 0xa5, 0x86, 0xb2, + 0x7e, 0xd7, 0xf3, 0xbb, 0xb7, 0xc5, 0xb7, 0x7d, 0x37, 0x6d, 0xad, 0xf5, + 0xba, 0x00, 0x39, 0xde, 0x65, 0xdd, 0xe7, 0x30, 0x10, 0xc0, 0x18, 0x50, + 0xa7, 0x18, 0x92, 0xe6, 0xed, 0x1a, 0xef, 0xd5, 0x8d, 0x90, 0x01, 0xe7, + 0x64, 0x77, 0x89, 0xc5, 0xf6, 0x32, 0xd0, 0xff, 0x67, 0x47, 0x48, 0x90, + 0x83, 0x4d, 0xd8, 0x4b, 0xad, 0xe6, 0xc5, 0x3a, 0x74, 0x22, 0x4e, 0x84, + 0x70, 0x34, 0xd9, 0xc6, 0x7e, 0xf6, 0xd3, 0x82, 0x9a, 0xe7, 0xed, 0x79, + 0x8f, 0x5e, 0x72, 0xa2, 0xb8, 0xcd, 0x28, 0x98, 0x1c, 0x3a, 0x94, 0x06, + 0xdb, 0x48, 0xda, 0xd6, 0xfb, 0xa4, 0x4e, 0x05, 0x70, 0x46, 0xda, 0xef, + 0x7a, 0xfc, 0x53, 0x04, 0xf2, 0xf9, 0x0e, 0x98, 0x52, 0x87, 0xc8, 0x3e, + 0xd6, 0x6f, 0x60, 0x07, 0xa4, 0x71, 0x3d, 0xe6, 0xbf, 0x8c, 0x53, 0x03, + 0xac, 0xb1, 0x46, 0x14, 0x54, 0x1d, 0x06, 0xb7, 0x20, 0x00, 0xf7, 0xa7, + 0x77, 0xb1, 0xd3, 0x99, 0x8a, 0x82, 0xf4, 0x80, 0xbe, 0x72, 0xca, 0x38, + 0xa3, 0xe1, 0xde, 0xad, 0x97, 0xd9, 0xe2, 0xfd, 0xf9, 0x90, 0xc9, 0x46, + 0xa9, 0xb5, 0x10, 0xc8, 0x04, 0x1e, 0xa3, 0x98, 0xf1, 0x66, 0xdf, 0xa3, + 0x00, 0x58, 0xef, 0x97, 0x59, 0xcf, 0xd7, 0xdd, 0xfb, 0x4e, 0x99, 0x6a, + 0x80, 0xe3, 0x0f, 0x38, 0x61, 0x4d, 0xc0, 0xae, 0xeb, 0x32, 0xb8, 0x43, + 0xa1, 0x45, 0x16, 0x91, 0x0b, 0x0a, 0x6c, 0xde, 0xcb, 0x4c, 0x20, 0x4c, + 0x39, 0x74, 0xa8, 0x56, 0x8e, 0xf0, 0x02, 0xdb, 0xa7, 0xf1, 0x9c, 0xc7, + 0x50, 0x0b, 0x7b, 0xda, 0x74, 0x2e, 0xa2, 0xc7, 0x43, 0xd9, 0xc6, 0x6d, + 0xf9, 0xf3, 0x74, 0xcc, 0x36, 0x62, 0x8d, 0xa6, 0x1e, 0x8a, 0x58, 0x6b, + 0x27, 0x79, 0x5f, 0x83, 0x69, 0xe1, 0x65, 0x56, 0xee, 0x7c, 0xba, 0x8b, + 0xd9, 0x72, 0x00, 0x45, 0x98, 0x61, 0x67, 0x31, 0x7d, 0xe0, 0x57, 0xbd, + 0x58, 0x13, 0xb0, 0xeb, 0x3d, 0x51, 0x15, 0x86, 0x55, 0x80, 0x00, 0x00, + 0x01, 0x09, 0x43, 0xf1, 0xf9, 0x49, 0xf9, 0x85, 0x04, 0xad, 0x6e, 0xaf, + 0x32, 0x6e, 0x16, 0xdf, 0x2a, 0x77, 0x52, 0x11, 0xf8, 0xb7, 0x60, 0xe5, + 0x32, 0xc8, 0x58, 0xc2, 0xca, 0x4a, 0xa1, 0x2d, 0xf6, 0xba, 0x47, 0x22, + 0x00, 0x2d, 0x00, 0x7d, 0xbb, 0xbc, 0xdd, 0x4b, 0x49, 0xdd, 0x88, 0xe6, + 0x07, 0x2e, 0x07, 0xc3, 0xa5, 0x1a, 0x8d, 0xe5, 0xb8, 0xa6, 0xf3, 0x55, + 0x5b, 0xc0, 0xf7, 0x49, 0xde, 0xf0, 0x42, 0x36, 0x4b, 0xe0, 0xb6, 0x2b, + 0x6f, 0x73, 0xf4, 0x51, 0x1c, 0x01, 0xe7, 0xdb, 0x9a, 0x13, 0x7b, 0xf9, + 0x15, 0x1c, 0x4f, 0x04, 0x80, 0x03, 0xdd, 0x2f, 0x8a, 0x15, 0x0e, 0xa7, + 0xb7, 0xa8, 0x16, 0x45, 0xf6, 0xfa, 0x11, 0x4d, 0xf8, 0x82, 0xcc, 0x36, + 0xe6, 0xbf, 0x2f, 0x95, 0x55, 0x86, 0x7e, 0xad, 0x3d, 0x4b, 0x90, 0x21, + 0xba, 0x22, 0x7b, 0xa0, 0x0f, 0xbe, 0x9f, 0x77, 0x73, 0xc5, 0x8f, 0x7f, + 0x2f, 0x7d, 0x9b, 0x1f, 0xb1, 0xfa, 0xfd, 0x44, 0x43, 0xca, 0x8e, 0x0b, + 0x56, 0xe7, 0x75, 0xf2, 0xa3, 0x02, 0xab, 0x2d, 0x44, 0x6f, 0xd8, 0x73, + 0xae, 0x23, 0x7f, 0x04, 0xee, 0x3e, 0x00, 0x0a, 0x5d, 0xcf, 0x4b, 0x38, + 0xc9, 0x03, 0xc0, 0x4b, 0x0a, 0x43, 0x0a, 0xad, 0xf0, 0x40, 0x03, 0xb8, + 0xe7, 0xf9, 0xfb, 0x58, 0x7a, 0x6d, 0xd9, 0x9b, 0x57, 0x07, 0x15, 0x8a, + 0x6d, 0x0a, 0x46, 0xfd, 0x0f, 0xf4, 0x16, 0x00, 0x6b, 0xc7, 0xff, 0xb1, + 0x51, 0xf2, 0x9f, 0x78, 0xcd, 0x00, 0xb7, 0x6e, 0x53, 0xa9, 0x34, 0x3e, + 0x9b, 0x0e, 0x1b, 0x1b, 0xf2, 0x63, 0xe4, 0x11, 0x82, 0xa4, 0x80, 0x94, + 0x00, 0x66, 0x52, 0x51, 0x25, 0x9e, 0x16, 0xab, 0x3d, 0x23, 0x48, 0x0e, + 0x35, 0xbf, 0xae, 0x08, 0xfa, 0xb8, 0x10, 0x3f, 0x2c, 0x4e, 0x8b, 0xe3, + 0xbb, 0x40, 0x8e, 0x3e, 0x38, 0xeb, 0x88, 0xf9, 0xb0, 0xf0, 0xf7, 0xed, + 0xab, 0x14, 0x32, 0x14, 0xdf, 0x50, 0xf9, 0xf8, 0xc0, 0x02, 0x8e, 0x1c, + 0xe8, 0xb0, 0x11, 0xff, 0xee, 0xdb, 0x69, 0x60, 0x3c, 0x58, 0x52, 0x12, + 0x5b, 0xf2, 0xfe, 0x80, 0x53, 0x5b, 0xf4, 0x38, 0x03, 0xc7, 0xc0, 0x04, + 0xff, 0xe1, 0x7f, 0xdf, 0xb4, 0xc8, 0x08, 0xc0, 0x0a, 0xb4, 0x0c, 0xa6, + 0x07, 0x50, 0x1c, 0xd1, 0x88, 0x58, 0xd1, 0xb5, 0xb9, 0x75, 0x1d, 0xd3, + 0xf5, 0x7c, 0x21, 0x49, 0x4e, 0x1f, 0x5b, 0x38, 0x5b, 0xae, 0xcf, 0x04, + 0x3d, 0xbf, 0xce, 0x9f, 0x71, 0x0f, 0x00, 0x2e, 0xfb, 0xbb, 0x1d, 0x65, + 0x01, 0xe6, 0xbc, 0x46, 0xbb, 0x60, 0xca, 0x58, 0x45, 0x25, 0xb7, 0xce, + 0x3a, 0xe8, 0x02, 0xbe, 0xdc, 0x4f, 0x2c, 0x62, 0xc3, 0x15, 0xbf, 0x5c, + 0x00, 0x30, 0x17, 0xa0, 0x80, 0x05, 0x59, 0xef, 0xff, 0x16, 0x22, 0x4f, + 0xd7, 0x5c, 0x3d, 0xc8, 0x66, 0xd4, 0x27, 0x9d, 0x4d, 0x8b, 0x50, 0x68, + 0xd6, 0xfc, 0xd0, 0xfa, 0xf1, 0x7f, 0x24, 0x67, 0x71, 0x21, 0xd9, 0x5e, + 0x4f, 0xec, 0xc9, 0x93, 0x21, 0x74, 0x3c, 0x74, 0x6e, 0x82, 0x6f, 0x3b, + 0xa8, 0x43, 0xad, 0xa2, 0x96, 0xb5, 0xbc, 0x8f, 0xeb, 0x1c, 0x22, 0x47, + 0x64, 0xf5, 0x3e, 0xda, 0xa3, 0x4b, 0x6b, 0x08, 0xce, 0x00, 0x33, 0xf7, + 0x9b, 0x25, 0x0c, 0xaf, 0x32, 0x19, 0x46, 0xb7, 0xa7, 0x42, 0x01, 0xaf, + 0x7c, 0xb8, 0x03, 0xde, 0x79, 0x93, 0x80, 0xa2, 0xb2, 0x0c, 0x81, 0xa5, + 0xd6, 0xc1, 0xf7, 0x37, 0x0a, 0x44, 0x3d, 0x4a, 0x87, 0x86, 0x00, 0xd5, + 0x96, 0x4b, 0xae, 0x46, 0x4a, 0x52, 0xb7, 0xd0, 0xec, 0x5e, 0x11, 0xb8, + 0x7e, 0xbf, 0xac, 0x2c, 0xad, 0xe7, 0x1f, 0x93, 0x8b, 0x76, 0xa3, 0x8f, + 0x8a, 0x51, 0x94, 0xb4, 0x2b, 0x0f, 0x8d, 0xc0, 0xe6, 0x68, 0x19, 0xca, + 0x9e, 0x25, 0x29, 0x29, 0xb0, 0xf1, 0x28, 0xa1, 0x6e, 0xb7, 0x72, 0x06, + 0x45, 0x58, 0x9e, 0x10, 0x68, 0x4b, 0x52, 0x46, 0xcc, 0x7b, 0xb6, 0xe2, + 0x50, 0xab, 0x0a, 0x02, 0xeb, 0x5d, 0x87, 0x2d, 0xf5, 0x6d, 0xcf, 0xa0, + 0x5b, 0x7d, 0x61, 0x6b, 0xcd, 0xe2, 0xd9, 0x2f, 0x83, 0xf0, 0xaa, 0x10, + 0x31, 0xb7, 0xe4, 0xc8, 0x47, 0x94, 0xde, 0x02, 0xb5, 0xfb, 0x2e, 0x5b, + 0x16, 0x9d, 0xa0, 0x5b, 0x69, 0x23, 0x7e, 0x7b, 0x23, 0x75, 0xbb, 0x29, + 0xd0, 0xbf, 0x7f, 0x3b, 0x4b, 0x0c, 0x30, 0xda, 0x7b, 0x61, 0xd9, 0x39, + 0x14, 0x23, 0x70, 0xc8, 0x55, 0x31, 0xd4, 0xc7, 0x1c, 0x4c, 0x51, 0x81, + 0x67, 0xb7, 0xa0, 0x32, 0xb7, 0xa2, 0x8a, 0x8d, 0xea, 0xf6, 0xcb, 0xe5, + 0x78, 0xd8, 0xa7, 0xd2, 0xd5, 0xd2, 0x1c, 0x58, 0xe1, 0xed, 0xb7, 0x87, + 0xf9, 0x11, 0x95, 0x50, 0x72, 0x6e, 0x17, 0xa3, 0x09, 0x88, 0x31, 0xb9, + 0x76, 0x1b, 0xf3, 0x9b, 0x54, 0x05, 0x77, 0x8d, 0xc2, 0xe1, 0x30, 0x71, + 0xfe, 0xad, 0xd2, 0x17, 0x40, 0x0e, 0x05, 0xbe, 0x97, 0x46, 0x9a, 0x6b, + 0xb3, 0x32, 0x94, 0x04, 0x50, 0xf2, 0xef, 0x8c, 0x29, 0x93, 0x6e, 0xde, + 0x5c, 0xc2, 0x7f, 0x34, 0x9d, 0x81, 0x92, 0x72, 0xfc, 0x9b, 0x47, 0x0d, + 0x28, 0xf0, 0x98, 0xce, 0x45, 0x7c, 0xe8, 0x00, 0xfe, 0x1a, 0x19, 0x49, + 0xce, 0xe4, 0xc4, 0xd8, 0x1b, 0x64, 0xcb, 0x4a, 0x0d, 0x62, 0xe7, 0xef, + 0x59, 0xef, 0xbb, 0x25, 0x1c, 0x82, 0xf4, 0xc9, 0x29, 0xe3, 0x92, 0x92, + 0x1b, 0x1c, 0x33, 0xe1, 0xfd, 0xdb, 0x40, 0x47, 0xe6, 0xe5, 0x51, 0x83, + 0x0d, 0x18, 0x10, 0xd4, 0xd2, 0x73, 0x74, 0x08, 0x96, 0x71, 0x45, 0xe4, + 0xd4, 0x1c, 0x4f, 0x3f, 0x21, 0xd7, 0xc5, 0xb1, 0xdd, 0xa0, 0x0e, 0xbe, + 0x9d, 0x63, 0xed, 0x0d, 0xb3, 0xcf, 0x75, 0x29, 0xe3, 0xf7, 0x6c, 0xf4, + 0xb5, 0x97, 0x94, 0xb9, 0x66, 0x1b, 0xe2, 0x05, 0x1c, 0xdd, 0x5e, 0x45, + 0xc7, 0x6f, 0xe6, 0x4a, 0x59, 0x53, 0x75, 0x4c, 0x1e, 0x70, 0x4d, 0x61, + 0xa6, 0x95, 0x1b, 0xf1, 0x9e, 0xf2, 0x89, 0x99, 0x32, 0xca, 0x39, 0x43, + 0x4e, 0x6f, 0xd3, 0x1f, 0xde, 0xb4, 0x10, 0x3f, 0x2f, 0xee, 0xe2, 0x37, + 0xb7, 0xbc, 0xa5, 0xe6, 0xf5, 0x9d, 0xfb, 0x6b, 0xf5, 0xf9, 0x4f, 0x85, + 0xe5, 0x92, 0x2d, 0x09, 0x2d, 0xbe, 0x46, 0x6c, 0x9b, 0x23, 0xcb, 0x19, + 0x85, 0x86, 0x96, 0x88, 0xa5, 0x37, 0xbf, 0xff, 0x3b, 0x8c, 0x00, 0x79, + 0x77, 0xe3, 0xa1, 0x14, 0xf0, 0x0b, 0x45, 0xba, 0xd5, 0x79, 0xa6, 0xc9, + 0x61, 0x45, 0xda, 0x07, 0xb6, 0x67, 0xa4, 0x6c, 0x39, 0x45, 0x8d, 0xfd, + 0xc4, 0x00, 0xb0, 0x01, 0xf8, 0x8f, 0x6b, 0xcf, 0x9b, 0xaa, 0x5b, 0x16, + 0x21, 0x52, 0x7e, 0xc6, 0xc1, 0x90, 0xf1, 0xad, 0xf9, 0x59, 0x1d, 0xf1, + 0xf6, 0xf8, 0xf8, 0xf6, 0x99, 0x49, 0x86, 0xee, 0x75, 0xc6, 0x61, 0xb7, + 0x2d, 0x5a, 0xbb, 0x0f, 0xda, 0x79, 0xf5, 0xbb, 0xc2, 0xa0, 0x92, 0x7e, + 0xbf, 0x90, 0x0b, 0x61, 0x44, 0xed, 0x26, 0xe5, 0x91, 0xd9, 0x52, 0x69, + 0x95, 0x0b, 0x2e, 0x84, 0x56, 0xc9, 0xd8, 0xae, 0x45, 0x2e, 0x0a, 0x7c, + 0xb4, 0x9b, 0x15, 0x20, 0xfa, 0x6d, 0x2c, 0x28, 0xe6, 0xd2, 0x15, 0x1b, + 0x4d, 0xa5, 0x14, 0xdf, 0x3f, 0x9f, 0x3d, 0x89, 0xba, 0x87, 0x41, 0xaa, + 0x56, 0x0d, 0x56, 0xdf, 0x95, 0xf3, 0xdf, 0x2b, 0xf3, 0x68, 0xc7, 0x60, + 0xc9, 0x4b, 0x38, 0xaa, 0x71, 0x4d, 0x9f, 0xa9, 0x39, 0xdc, 0x5c, 0x29, + 0x7f, 0x57, 0x52, 0xdd, 0x42, 0x9b, 0xa5, 0x9d, 0x3f, 0x7e, 0x2c, 0xb7, + 0x61, 0x41, 0xd0, 0xa8, 0x54, 0x54, 0x0d, 0x38, 0x29, 0xa1, 0xb5, 0xab, + 0x4f, 0x6f, 0x3f, 0xd3, 0x89, 0xd7, 0x55, 0xe4, 0xed, 0xe7, 0x69, 0x35, + 0x06, 0x59, 0x22, 0x97, 0x4b, 0xfd, 0xb2, 0x74, 0x21, 0xf2, 0x45, 0x7d, + 0x50, 0xa3, 0xea, 0xa0, 0xf6, 0xe8, 0xfd, 0x44, 0x65, 0xe8, 0x07, 0x2f, + 0x55, 0xa6, 0xae, 0x52, 0xb1, 0x0a, 0x46, 0xe1, 0x3d, 0xdc, 0x60, 0xbf, + 0x38, 0x6c, 0x28, 0xf3, 0x0a, 0x85, 0x94, 0x3e, 0x56, 0x43, 0x19, 0xb7, + 0xaa, 0xf3, 0x79, 0xcc, 0x9c, 0x61, 0x94, 0xab, 0x62, 0x0c, 0x0a, 0x6d, + 0x80, 0x64, 0x59, 0x1b, 0x88, 0xe7, 0xec, 0x3c, 0x9d, 0x9c, 0xd7, 0xda, + 0xba, 0x8a, 0x34, 0x6b, 0x73, 0x5d, 0xd9, 0x07, 0xbd, 0xbc, 0xb8, 0xa2, + 0xee, 0x63, 0xae, 0x07, 0x5a, 0x85, 0x1e, 0x87, 0xd1, 0x8c, 0x80, 0x07, + 0xd1, 0xde, 0xd3, 0x9c, 0x2c, 0xb5, 0x58, 0x34, 0xb2, 0xe4, 0x0a, 0x8c, + 0xda, 0x63, 0x7d, 0xd1, 0x22, 0xc8, 0x9a, 0xec, 0xd3, 0x0d, 0x01, 0xc7, + 0x2f, 0xe4, 0xe8, 0x1f, 0x28, 0xcd, 0x81, 0x03, 0x55, 0xba, 0x93, 0xfe, + 0xff, 0x6b, 0xce, 0xcd, 0xef, 0x64, 0xd9, 0x8f, 0x9b, 0x2e, 0xdb, 0x38, + 0xc3, 0xe2, 0x0e, 0x29, 0xb8, 0x3f, 0x7e, 0x48, 0xc2, 0x3b, 0xd9, 0xb2, + 0xd3, 0xea, 0xef, 0x26, 0xe4, 0xae, 0x42, 0x8a, 0xa7, 0xdf, 0x02, 0x9b, + 0x3f, 0x26, 0x7c, 0xf4, 0x23, 0x5e, 0x3a, 0x4e, 0x21, 0xa9, 0x6c, 0xb4, + 0x62, 0x4a, 0x1a, 0xc0, 0xd6, 0x8c, 0x4b, 0x95, 0xbc, 0x4f, 0xde, 0x5c, + 0xec, 0x82, 0xde, 0xe2, 0xe9, 0x8e, 0x9c, 0xad, 0xa9, 0x87, 0xd2, 0x1b, + 0x5b, 0xee, 0x88, 0x92, 0xc8, 0x78, 0xd3, 0x88, 0x4d, 0xdf, 0x13, 0x3a, + 0xff, 0x7c, 0xe5, 0x76, 0x65, 0x4a, 0x1e, 0x9e, 0x56, 0x22, 0xd0, 0x21, + 0x07, 0x8f, 0x6f, 0x3b, 0xb6, 0x39, 0xef, 0xf2, 0x33, 0xc7, 0x24, 0xd4, + 0x38, 0x2d, 0x93, 0x69, 0x2a, 0xca, 0xda, 0x71, 0x6c, 0x7b, 0xf5, 0x42, + 0x92, 0x0f, 0x85, 0x46, 0xd9, 0xfc, 0xe7, 0x9f, 0x7e, 0x46, 0x0e, 0x48, + 0x5d, 0x64, 0x7e, 0xdf, 0x9c, 0x97, 0x8d, 0x94, 0x62, 0x1b, 0x84, 0xb4, + 0xa7, 0x05, 0x36, 0x98, 0xfb, 0xa2, 0x5d, 0x73, 0x85, 0xa3, 0x69, 0xea, + 0x50, 0x71, 0xd5, 0x88, 0xcd, 0xb4, 0x23, 0x3a, 0xf1, 0x96, 0x1b, 0xb2, + 0x04, 0x0e, 0x87, 0xfa, 0xb6, 0x67, 0xe4, 0xd7, 0x3a, 0x79, 0x50, 0xc3, + 0x12, 0x97, 0xbe, 0x07, 0x33, 0xba, 0x51, 0x1d, 0x24, 0x7d, 0x1d, 0xaf, + 0xd4, 0x2c, 0xe6, 0xe6, 0xcc, 0x9e, 0x7a, 0xb4, 0x26, 0xca, 0x7a, 0x50, + 0x1e, 0xb3, 0x8d, 0x6c, 0x00, 0x00, 0x01, 0x0a, 0x43, 0xf9, 0x00, 0x03, + 0xbf, 0xe0, 0xb1, 0x5c, 0x93, 0xba, 0x30, 0x72, 0x79, 0xf1, 0x4d, 0x53, + 0xac, 0x3e, 0x58, 0x53, 0x6f, 0xf9, 0x99, 0xc9, 0x1e, 0xf5, 0x2c, 0x80, + 0x4f, 0x96, 0xd8, 0xba, 0x81, 0x8a, 0x39, 0xbd, 0x28, 0x03, 0x87, 0xb8, + 0x8c, 0x29, 0xd6, 0xe4, 0x09, 0xdf, 0x3b, 0xaf, 0xa5, 0xa1, 0xf1, 0x55, + 0x21, 0xc3, 0x1b, 0xce, 0x08, 0xcf, 0x21, 0x4b, 0x2f, 0x8c, 0x6f, 0x1b, + 0x70, 0x9e, 0x4f, 0x8e, 0x50, 0x9c, 0xb1, 0x15, 0xbc, 0x74, 0x1c, 0xde, + 0xd0, 0xee, 0xf1, 0xd3, 0x20, 0x66, 0x61, 0x44, 0xda, 0x15, 0x21, 0x55, + 0xbd, 0x68, 0x03, 0xc7, 0xf1, 0xd7, 0x98, 0xbd, 0x4a, 0x7d, 0x97, 0x97, + 0xbe, 0xee, 0x97, 0x22, 0x42, 0xa8, 0xc8, 0x14, 0xde, 0x14, 0x9b, 0xce, + 0xad, 0x6b, 0x76, 0x51, 0x69, 0x90, 0x28, 0xa3, 0xda, 0x21, 0x52, 0x52, + 0x5b, 0x46, 0x1f, 0x15, 0xbf, 0xa0, 0x7b, 0x25, 0x11, 0xdf, 0x61, 0x20, + 0x13, 0xfe, 0x22, 0x14, 0x58, 0x70, 0xd2, 0xdb, 0xca, 0xda, 0x01, 0x53, + 0xdd, 0xb6, 0x20, 0xc2, 0xe7, 0x8b, 0x71, 0x04, 0x3a, 0x0a, 0xe6, 0x6e, + 0xec, 0x0d, 0x59, 0x12, 0x4f, 0x14, 0xad, 0xba, 0x02, 0x17, 0xfd, 0x3b, + 0x69, 0x2e, 0x92, 0x58, 0x2a, 0xd8, 0xa4, 0x26, 0xac, 0x2b, 0x15, 0xbf, + 0xb6, 0x80, 0x3b, 0x00, 0x5f, 0xec, 0x00, 0x5f, 0xfc, 0x8f, 0xe2, 0x74, + 0xa8, 0x4f, 0xc1, 0x62, 0x35, 0x61, 0x97, 0x13, 0x72, 0x9e, 0x10, 0xdf, + 0x6e, 0x11, 0xff, 0xe7, 0xa0, 0x06, 0x6f, 0xe5, 0xeb, 0xa3, 0x39, 0x79, + 0x97, 0x64, 0xa8, 0x9c, 0x5c, 0x59, 0x07, 0xb7, 0xe4, 0xfe, 0xf9, 0x00, + 0x35, 0xf6, 0x9c, 0xf9, 0xa4, 0x2e, 0x90, 0x3a, 0x49, 0x3b, 0xe4, 0x71, + 0x46, 0xd2, 0xa4, 0x3d, 0xbd, 0x0f, 0xfb, 0xed, 0x9f, 0x04, 0x70, 0x0a, + 0xfe, 0x05, 0x6d, 0x2f, 0xf2, 0x41, 0x5f, 0xc6, 0x61, 0x84, 0x0c, 0xcf, + 0xc2, 0x55, 0xb8, 0x78, 0x63, 0x67, 0xd3, 0xcc, 0xdf, 0x3b, 0x6a, 0x0f, + 0x74, 0x58, 0x81, 0x6d, 0xae, 0x5b, 0xa5, 0xd5, 0x0a, 0x6f, 0x9e, 0x2b, + 0x9a, 0x00, 0xf8, 0x8d, 0x9c, 0x65, 0x5b, 0x57, 0x79, 0x47, 0x48, 0x5d, + 0x55, 0x1a, 0x4a, 0x6f, 0x00, 0x2d, 0x61, 0x91, 0x47, 0x42, 0xc7, 0x48, + 0x51, 0xed, 0xea, 0xf5, 0xdc, 0x00, 0x3a, 0xec, 0x8a, 0x44, 0xec, 0x9f, + 0x00, 0x05, 0x3d, 0x90, 0x33, 0xbe, 0x6e, 0x69, 0xf0, 0x38, 0xb3, 0x2a, + 0x78, 0x94, 0xde, 0x0b, 0xfd, 0x40, 0x2d, 0xd7, 0xeb, 0x90, 0x35, 0x2e, + 0xd5, 0x83, 0x08, 0x4d, 0x35, 0x76, 0x54, 0xb0, 0x30, 0x29, 0xb0, 0xb0, + 0xb6, 0xfa, 0x36, 0xd7, 0xc8, 0xf9, 0x7d, 0x0a, 0xa0, 0x6d, 0xae, 0x27, + 0x10, 0x04, 0xdc, 0x40, 0x85, 0xb1, 0x5b, 0x81, 0xd6, 0x00, 0x19, 0x59, + 0x9a, 0xf0, 0x9b, 0x04, 0xcb, 0x81, 0x87, 0x05, 0xb6, 0x5f, 0xa7, 0x40, + 0x16, 0x08, 0x13, 0xcc, 0x81, 0x31, 0x0c, 0x84, 0xba, 0xdb, 0x4b, 0xe6, + 0xb2, 0x90, 0xd9, 0xd8, 0x39, 0xba, 0x78, 0x80, 0x07, 0xc2, 0x1d, 0x32, + 0xbe, 0x06, 0xcd, 0x47, 0x86, 0x0c, 0x94, 0x69, 0xe1, 0x8d, 0xbb, 0xdc, + 0xd0, 0x03, 0x9a, 0x40, 0x2a, 0xa5, 0x86, 0xe2, 0x26, 0xcf, 0x0d, 0x96, + 0x51, 0xc1, 0x8d, 0x92, 0xd7, 0xfd, 0x76, 0x0a, 0xc7, 0x28, 0xcc, 0x0f, + 0xe7, 0x22, 0x3e, 0x87, 0x43, 0xf4, 0x60, 0x62, 0x16, 0x5b, 0x6b, 0x22, + 0x6d, 0xf6, 0x23, 0x47, 0x62, 0x5a, 0xb6, 0xd8, 0x2b, 0xa8, 0xe9, 0xb7, + 0x76, 0x97, 0x4d, 0xd5, 0xb6, 0x90, 0xdb, 0x3f, 0xd4, 0x25, 0xb6, 0xd4, + 0xb6, 0xef, 0x32, 0x47, 0x45, 0x2c, 0xa3, 0xb3, 0xbd, 0x2b, 0x68, 0x1f, + 0x0a, 0x66, 0xe3, 0x00, 0x0f, 0xa1, 0x39, 0xf4, 0x6a, 0x20, 0x7e, 0x4a, + 0xa8, 0x70, 0xd5, 0x0d, 0x6b, 0x26, 0x5f, 0xbb, 0xf3, 0x64, 0xa1, 0x8b, + 0x5d, 0xbb, 0x2c, 0x08, 0x92, 0x17, 0xe0, 0xd4, 0xb9, 0xcb, 0xce, 0xf7, + 0x14, 0x24, 0x81, 0x66, 0x42, 0x13, 0x77, 0x40, 0x32, 0xa0, 0x5b, 0x7a, + 0x50, 0x0c, 0xcd, 0x24, 0xd6, 0xcb, 0xb5, 0x63, 0x9d, 0x28, 0x61, 0xb9, + 0xdb, 0xb0, 0xc8, 0x83, 0x07, 0x1e, 0x16, 0xdd, 0xb7, 0xe0, 0x00, 0x92, + 0xbd, 0xd2, 0x3a, 0xcf, 0xd0, 0x09, 0x2d, 0xa8, 0x7c, 0x58, 0x89, 0x14, + 0x22, 0xa3, 0x73, 0xfb, 0xb7, 0xdc, 0x40, 0x99, 0x2d, 0x01, 0x54, 0x9a, + 0x85, 0x1c, 0x37, 0x29, 0xc3, 0x4e, 0x6f, 0x57, 0xd7, 0x90, 0x8f, 0x81, + 0x62, 0x5d, 0xcb, 0xac, 0x01, 0x27, 0x90, 0xbc, 0xa9, 0x03, 0xd6, 0x02, + 0x27, 0xfe, 0x5b, 0x22, 0xf8, 0x28, 0xf6, 0xdd, 0xba, 0x23, 0x7c, 0xad, + 0xef, 0x7d, 0x9e, 0x27, 0x8c, 0xb9, 0x07, 0xee, 0xd7, 0x73, 0xbc, 0xef, + 0xe8, 0xe8, 0xa5, 0x7a, 0x37, 0x93, 0xd3, 0x45, 0x66, 0x27, 0x28, 0x19, + 0x6e, 0x6f, 0x9c, 0x18, 0x32, 0xd6, 0xd9, 0x78, 0x82, 0x81, 0x0b, 0xfe, + 0xab, 0xa0, 0xc2, 0xe5, 0x2a, 0xd2, 0x11, 0x5e, 0x25, 0xb6, 0x9c, 0xe5, + 0xef, 0x15, 0xaa, 0xe7, 0x02, 0x40, 0x01, 0x9b, 0xbb, 0x5f, 0xa1, 0x45, + 0x1c, 0x16, 0xc3, 0x4a, 0x23, 0x71, 0xdb, 0xbd, 0xbd, 0x79, 0x96, 0xd2, + 0x63, 0xb2, 0x3e, 0x2c, 0xb2, 0xd3, 0x51, 0x26, 0xf8, 0xb7, 0x4c, 0x49, + 0x31, 0xca, 0x65, 0x29, 0x10, 0xe4, 0xb1, 0x47, 0x35, 0x3f, 0x5e, 0x9f, + 0xc9, 0x75, 0x21, 0x72, 0xfe, 0xa2, 0xae, 0x12, 0xa8, 0xc6, 0xeb, 0xba, + 0xce, 0xc5, 0xde, 0x7a, 0xb4, 0x11, 0xbf, 0xf3, 0x75, 0xcf, 0x92, 0xcc, + 0xc0, 0xe8, 0x54, 0xab, 0x0b, 0x69, 0x67, 0x0f, 0xad, 0xd1, 0x9d, 0xed, + 0x17, 0x97, 0xbe, 0x86, 0xdc, 0x29, 0x4a, 0xbf, 0xaa, 0x36, 0x1c, 0x53, + 0x59, 0xed, 0xf1, 0x1c, 0xf7, 0xef, 0x1d, 0xc9, 0x40, 0x73, 0xb7, 0x56, + 0x3a, 0x64, 0x18, 0x16, 0x59, 0x61, 0x8d, 0x9c, 0x51, 0x05, 0xdd, 0x4a, + 0x27, 0x98, 0x34, 0x3a, 0xf2, 0xa9, 0x91, 0x0a, 0x2b, 0x00, 0xb6, 0x5d, + 0xef, 0x51, 0x5d, 0x62, 0x14, 0x4e, 0x92, 0xd2, 0xb1, 0xc7, 0xda, 0x58, + 0xe5, 0x0c, 0x66, 0xca, 0x16, 0x73, 0x7d, 0x22, 0x27, 0x09, 0x9a, 0x27, + 0xdf, 0x4d, 0x28, 0xb9, 0xba, 0xa8, 0x64, 0x2c, 0xe2, 0x8a, 0x88, 0x53, + 0x5b, 0xf5, 0xe2, 0x68, 0x18, 0x15, 0x24, 0xfd, 0x43, 0x6e, 0xd4, 0x43, + 0xb7, 0x16, 0x0e, 0x29, 0x5b, 0x17, 0x5b, 0x78, 0x78, 0x19, 0xe5, 0x3f, + 0x75, 0xcb, 0xbb, 0x46, 0x28, 0xd8, 0x73, 0x65, 0x8e, 0x77, 0x22, 0xb7, + 0x4d, 0x86, 0x0d, 0xbb, 0x6a, 0x98, 0x30, 0x60, 0x4b, 0x26, 0x1b, 0xb3, + 0xe1, 0xfa, 0x2b, 0xf2, 0x26, 0xa9, 0x52, 0xec, 0xda, 0x76, 0x49, 0x10, + 0x86, 0x31, 0xb4, 0xdf, 0x67, 0xfb, 0xbd, 0xf3, 0x5f, 0xaa, 0x52, 0x47, + 0xd9, 0x09, 0x67, 0x34, 0xde, 0x54, 0x4c, 0xb7, 0x28, 0x4e, 0x43, 0xc0, + 0x7c, 0xd6, 0x71, 0xa4, 0xe9, 0x76, 0xc8, 0xa7, 0x93, 0x6c, 0x98, 0xb4, + 0xb1, 0xb0, 0x74, 0x69, 0x6d, 0x02, 0x5b, 0xbb, 0xd8, 0x52, 0x71, 0xaf, + 0xbc, 0xc5, 0x50, 0xec, 0x94, 0xa8, 0x8a, 0x94, 0xb9, 0x3c, 0x5b, 0x95, + 0xc8, 0xb7, 0x0a, 0x7d, 0x97, 0x31, 0x0e, 0xb2, 0x3a, 0xa9, 0x91, 0x4b, + 0x29, 0x61, 0x5e, 0xac, 0xc4, 0xfa, 0x2a, 0x41, 0x83, 0x2e, 0x9a, 0x92, + 0x0e, 0x1e, 0x48, 0x6d, 0xdf, 0x63, 0x5f, 0x7b, 0xe6, 0xeb, 0xf7, 0x4f, + 0x9f, 0x89, 0x46, 0x42, 0x8b, 0x96, 0x8c, 0x60, 0xf6, 0x84, 0xb2, 0x9c, + 0xde, 0x5d, 0xdd, 0xf9, 0x85, 0xad, 0x9f, 0xa8, 0xa7, 0x59, 0xfa, 0x0c, + 0x1a, 0x16, 0xd7, 0xf3, 0xf3, 0xc7, 0x1c, 0xc9, 0x3a, 0xe0, 0x6d, 0xb5, + 0xd8, 0xb0, 0xe0, 0xc4, 0x6a, 0xba, 0x92, 0x45, 0x3e, 0x9e, 0x62, 0x42, + 0xfc, 0x4f, 0x6c, 0x1c, 0x3e, 0xf2, 0x65, 0x48, 0x75, 0x42, 0xe8, 0xd8, + 0x54, 0x61, 0x8d, 0x39, 0xbf, 0x5b, 0xf3, 0xce, 0x77, 0xf0, 0x27, 0x20, + 0x91, 0x68, 0x4c, 0xfc, 0xde, 0x52, 0x4e, 0x20, 0x66, 0x6c, 0x1b, 0x4a, + 0xa7, 0xc1, 0x8d, 0xcf, 0x13, 0xa2, 0x80, 0x0f, 0xdd, 0x82, 0xe6, 0x17, + 0x16, 0xe4, 0x18, 0x71, 0xa7, 0x28, 0x63, 0x73, 0x1d, 0x2b, 0x8a, 0x2c, + 0xa3, 0xcd, 0x7c, 0x85, 0x2c, 0x6e, 0x87, 0xb3, 0x8d, 0xcd, 0xba, 0xa3, + 0xe4, 0xa6, 0xe2, 0x50, 0xa6, 0x50, 0xa6, 0xdb, 0x75, 0x6d, 0x6e, 0xbf, + 0xc7, 0x96, 0x3b, 0x83, 0x90, 0xa7, 0x22, 0x19, 0x31, 0x14, 0x6a, 0x35, + 0x4e, 0xf3, 0x10, 0x29, 0xce, 0xb7, 0x6d, 0x3c, 0x3e, 0xf6, 0xb6, 0x0c, + 0x19, 0x69, 0xed, 0x5e, 0xdc, 0x11, 0xc6, 0x24, 0x09, 0x99, 0x6a, 0x16, + 0x16, 0x18, 0xda, 0x66, 0xaf, 0x9d, 0x36, 0x8d, 0x43, 0xc9, 0x8a, 0xc4, + 0x65, 0x68, 0x68, 0x16, 0xdf, 0x2b, 0xa7, 0x4e, 0xaf, 0x4f, 0xb2, 0x53, + 0x8a, 0xb6, 0xa5, 0xa4, 0x82, 0xe1, 0x2d, 0xac, 0xe3, 0xbc, 0xe3, 0x92, + 0xe6, 0x28, 0x0f, 0x10, 0xe1, 0x9e, 0x8d, 0x83, 0xab, 0xae, 0x32, 0x49, + 0x11, 0x20, 0xd0, 0x82, 0x9a, 0xcf, 0x8d, 0x7c, 0x73, 0x8d, 0xb6, 0xa8, + 0x10, 0x7d, 0x01, 0xab, 0x07, 0x30, 0x7d, 0x6d, 0xe6, 0x6b, 0x9d, 0xb6, + 0xbe, 0x8c, 0x08, 0x6a, 0x16, 0x72, 0xb2, 0x94, 0x04, 0x64, 0x85, 0xc0, + 0x92, 0xda, 0xae, 0x5d, 0xc6, 0x62, 0x71, 0xa1, 0x36, 0x86, 0x36, 0x0c, + 0xdd, 0xc9, 0x2b, 0xc2, 0xa0, 0x67, 0x84, 0x64, 0xc3, 0x00, 0x00, 0x00, + 0x01, 0x0b, 0x43, 0xf9, 0x16, 0xdf, 0x37, 0xad, 0x9e, 0xa7, 0x46, 0xde, + 0xf0, 0xfc, 0xc2, 0xef, 0x8b, 0x71, 0xd3, 0xcf, 0x16, 0x92, 0x8a, 0x6f, + 0x57, 0xc8, 0x21, 0x7f, 0xc8, 0x16, 0xb5, 0xbc, 0xb8, 0x52, 0xda, 0x43, + 0x6f, 0x16, 0x37, 0x5b, 0xd7, 0x0f, 0x0a, 0x1e, 0x1a, 0xd2, 0x53, 0x39, + 0xa0, 0x5b, 0x6c, 0x9f, 0x8b, 0x72, 0x7a, 0xca, 0xdc, 0xa9, 0x25, 0xc9, + 0x00, 0x20, 0x43, 0xa8, 0x09, 0x69, 0xed, 0x3a, 0x1f, 0x23, 0x4d, 0x2d, + 0xbe, 0x59, 0x84, 0x04, 0x99, 0x40, 0x47, 0x0c, 0x85, 0x85, 0x97, 0x49, + 0x2d, 0xda, 0x04, 0x3f, 0xfa, 0xb4, 0x92, 0xdc, 0x48, 0x08, 0x40, 0x0e, + 0x4e, 0x2b, 0xd7, 0x6d, 0x25, 0x95, 0x09, 0x4d, 0xe9, 0x39, 0xcb, 0xc9, + 0xb8, 0x43, 0xb1, 0xb1, 0xa3, 0x09, 0x0c, 0x8e, 0x46, 0xfa, 0x72, 0x10, + 0x76, 0x66, 0xdf, 0x0d, 0xb2, 0x2b, 0x68, 0x00, 0x6c, 0x28, 0x00, 0xf9, + 0xe4, 0x45, 0x35, 0x6a, 0x62, 0xd2, 0x21, 0x19, 0xe0, 0x66, 0x80, 0x47, + 0x69, 0xc1, 0x2a, 0x8c, 0x45, 0xc8, 0x2f, 0x2e, 0x2d, 0x38, 0xa5, 0x1b, + 0x83, 0x61, 0x55, 0xbd, 0x29, 0x17, 0xef, 0x84, 0x4f, 0x9b, 0xc3, 0xa0, + 0xf8, 0x6b, 0x84, 0xf5, 0x5f, 0xd1, 0x6e, 0xf3, 0xa1, 0xf9, 0x64, 0x9b, + 0x32, 0x14, 0x75, 0x52, 0xeb, 0x79, 0xf1, 0xe4, 0xe3, 0x0a, 0xa1, 0x54, + 0xb2, 0x89, 0x5e, 0x8d, 0x56, 0x1a, 0xdf, 0x82, 0xed, 0xfb, 0xc7, 0x41, + 0xe6, 0x58, 0x96, 0x1a, 0xae, 0x0b, 0x1c, 0x35, 0x0a, 0x18, 0xde, 0x64, + 0x5f, 0x39, 0xc7, 0xbe, 0x47, 0x66, 0xc3, 0xe6, 0xd5, 0x88, 0x51, 0xd4, + 0xf0, 0xca, 0xde, 0x88, 0x01, 0x87, 0xc7, 0x3d, 0x7f, 0x5d, 0xf3, 0xcf, + 0x2f, 0xe4, 0x99, 0x4c, 0x78, 0xa7, 0x65, 0x80, 0x16, 0x66, 0x2d, 0x57, + 0xa0, 0xca, 0x12, 0xdc, 0x3a, 0x2f, 0xa1, 0x1e, 0x5b, 0xcf, 0x57, 0x4e, + 0xdd, 0x4d, 0x89, 0x2d, 0x91, 0x70, 0xfa, 0xb2, 0x54, 0xa7, 0x96, 0xdd, + 0xb7, 0x12, 0x6c, 0x84, 0x30, 0x2d, 0xb7, 0xa5, 0x37, 0x9d, 0xf9, 0x78, + 0xeb, 0x64, 0xa1, 0x1b, 0x29, 0x5a, 0x80, 0x2b, 0x6c, 0x93, 0xf3, 0xce, + 0x61, 0x61, 0x85, 0xd9, 0x09, 0x2d, 0x8c, 0x57, 0x19, 0xf0, 0x29, 0xd3, + 0x24, 0x1b, 0x4f, 0xda, 0xfd, 0xa3, 0x49, 0xb6, 0xd5, 0xad, 0xa3, 0x87, + 0xe8, 0x9c, 0xe7, 0x78, 0x88, 0x00, 0x28, 0xce, 0x24, 0xbb, 0x54, 0xe1, + 0xb4, 0xe2, 0x13, 0x2b, 0x16, 0xd6, 0x8a, 0xdd, 0xc4, 0x6e, 0x35, 0xd8, + 0x9e, 0x7b, 0x46, 0xe9, 0xb8, 0xec, 0xc9, 0x2a, 0xad, 0xa8, 0x83, 0x6b, + 0x74, 0xfe, 0x6b, 0x80, 0x1c, 0xfc, 0x58, 0xee, 0xdf, 0x06, 0xe6, 0x3f, + 0x87, 0xf3, 0xc6, 0x44, 0x89, 0x29, 0x32, 0xa2, 0x4a, 0x59, 0xd5, 0x0f, + 0x6f, 0x31, 0x27, 0x96, 0xee, 0xa0, 0x52, 0x17, 0x5b, 0x50, 0x73, 0xf7, + 0x6e, 0x14, 0x03, 0xdd, 0x96, 0x14, 0x30, 0xea, 0xa3, 0x5b, 0x7d, 0xaa, + 0x95, 0xb7, 0xa3, 0x5b, 0xe9, 0x7f, 0x8d, 0x14, 0x26, 0x9a, 0xbe, 0x30, + 0xb9, 0x06, 0x96, 0xdb, 0xb6, 0x93, 0xba, 0xe9, 0xda, 0x09, 0x7f, 0xf5, + 0xed, 0xa8, 0xa7, 0x0e, 0x56, 0xf2, 0x7b, 0x60, 0x81, 0x0e, 0x96, 0xd0, + 0xd5, 0xbe, 0x28, 0xde, 0xfb, 0xea, 0xe7, 0x39, 0xe2, 0x78, 0x7e, 0x50, + 0xd9, 0xbf, 0x33, 0x49, 0xf6, 0x1c, 0x7b, 0xd6, 0x5c, 0xb9, 0x4a, 0x0a, + 0x66, 0xb7, 0x9d, 0x80, 0x53, 0x6d, 0x00, 0x29, 0xb2, 0xb6, 0xa2, 0xb9, + 0x04, 0x1f, 0xec, 0x7e, 0xf6, 0xed, 0x51, 0xc8, 0xe2, 0xa2, 0x8d, 0x2e, + 0xc5, 0x18, 0x59, 0xc9, 0x5b, 0xa5, 0x2c, 0xfb, 0x65, 0x9a, 0x19, 0x71, + 0x08, 0xe9, 0x6d, 0x90, 0x27, 0x92, 0xe2, 0xb5, 0x1f, 0xde, 0x60, 0x91, + 0x1d, 0x3d, 0xf7, 0x02, 0xc5, 0x74, 0x24, 0x53, 0xec, 0x38, 0xed, 0xa5, + 0xfa, 0x36, 0xc9, 0xba, 0x47, 0xc7, 0xde, 0x94, 0x32, 0xf1, 0x82, 0x77, + 0x9b, 0x14, 0x36, 0x06, 0x00, 0x8e, 0x37, 0x63, 0x7a, 0x0d, 0xf9, 0xde, + 0x67, 0x1d, 0x5f, 0x82, 0xb6, 0x9c, 0x98, 0x4e, 0x7c, 0xd4, 0x2d, 0x50, + 0xa3, 0x88, 0x6a, 0xdb, 0x78, 0xea, 0x77, 0xbf, 0x97, 0xbe, 0x81, 0x10, + 0x3b, 0x6c, 0xbf, 0xb1, 0xdb, 0x06, 0x78, 0x04, 0xb4, 0x12, 0x08, 0x40, + 0x0d, 0xb4, 0xd9, 0x60, 0x62, 0x3a, 0xd2, 0xd5, 0x61, 0xd4, 0xa2, 0x86, + 0x9e, 0xdc, 0xec, 0xa0, 0x06, 0x9d, 0xf3, 0xa9, 0x06, 0xa8, 0x04, 0xb5, + 0x7c, 0x07, 0xd3, 0xa0, 0x53, 0x03, 0x1a, 0x46, 0xb6, 0x08, 0xd3, 0x87, + 0x88, 0xdb, 0x82, 0xf9, 0x90, 0xac, 0xfc, 0xae, 0x19, 0x9c, 0x13, 0x57, + 0xc5, 0xba, 0x3b, 0x08, 0x3d, 0x42, 0x7c, 0x01, 0x56, 0x6c, 0x42, 0x9b, + 0xe7, 0x46, 0x87, 0xd8, 0x90, 0x30, 0xca, 0x02, 0xe6, 0xfa, 0xc1, 0x16, + 0xc0, 0x06, 0x64, 0x4e, 0xcd, 0x72, 0x14, 0xbb, 0xca, 0xae, 0x4d, 0x92, + 0xa1, 0xe8, 0x96, 0xc0, 0xa6, 0x74, 0xa6, 0x9c, 0xab, 0x4a, 0x6f, 0x33, + 0x9d, 0x39, 0xef, 0xa0, 0xeb, 0x42, 0xf6, 0x45, 0x1c, 0x77, 0xab, 0x76, + 0x1d, 0xef, 0xe4, 0x56, 0x2a, 0x16, 0x93, 0x12, 0x48, 0x65, 0x2d, 0x46, + 0x36, 0x5f, 0x90, 0x43, 0xff, 0x87, 0x59, 0xab, 0x12, 0xe4, 0x2a, 0x4d, + 0x2e, 0x55, 0x85, 0x21, 0xda, 0x16, 0xd8, 0x1f, 0xbc, 0x13, 0x9d, 0x92, + 0xec, 0x1b, 0x99, 0x72, 0x9d, 0x9a, 0x35, 0x4b, 0x3a, 0x05, 0x36, 0x67, + 0x36, 0x97, 0x4a, 0x46, 0xfd, 0x07, 0x3e, 0xe0, 0x16, 0x3e, 0xf1, 0x26, + 0x01, 0x2e, 0xf3, 0xa1, 0xd5, 0xd2, 0xc2, 0xce, 0xa3, 0x06, 0xfa, 0xb7, + 0x0e, 0x0b, 0xe0, 0x4f, 0x59, 0x93, 0x62, 0x17, 0x67, 0x73, 0x26, 0x62, + 0x6a, 0x06, 0x8d, 0xbe, 0x0c, 0x3b, 0xb8, 0x2f, 0x87, 0x64, 0xa3, 0x91, + 0xdc, 0xcd, 0x54, 0x28, 0x79, 0x0d, 0x83, 0xde, 0x62, 0x47, 0xa5, 0x38, + 0x9b, 0x2a, 0x98, 0x32, 0x9c, 0x8d, 0x11, 0xab, 0x46, 0xb6, 0xcf, 0xb2, + 0x72, 0x86, 0x6c, 0xa5, 0xfe, 0xd1, 0x12, 0xc2, 0xa3, 0x40, 0x0b, 0x6e, + 0x99, 0x71, 0x03, 0x26, 0x86, 0xa2, 0x56, 0x77, 0xdf, 0x37, 0xec, 0x5d, + 0x1d, 0x24, 0x51, 0x8d, 0x8b, 0xaf, 0xc1, 0x69, 0x07, 0xaa, 0x0c, 0x18, + 0xc4, 0x6a, 0xad, 0xd5, 0xe7, 0xc3, 0x8c, 0x7c, 0xcd, 0x2d, 0x69, 0x86, + 0x0f, 0x3e, 0x14, 0xa8, 0x4b, 0x6d, 0xa2, 0x77, 0xce, 0xd8, 0xeb, 0xd8, + 0x0f, 0x16, 0xd9, 0x2c, 0x88, 0x51, 0xed, 0xc2, 0x8f, 0x36, 0xc3, 0x10, + 0x75, 0x56, 0xec, 0xe7, 0x2f, 0x17, 0x7c, 0xaa, 0x4a, 0x02, 0x22, 0xd1, + 0x0f, 0x62, 0x14, 0xc5, 0x2e, 0x37, 0x7e, 0xc9, 0xc4, 0xb8, 0x90, 0x2f, + 0xd4, 0x05, 0xed, 0x9c, 0xc3, 0x76, 0xd5, 0x08, 0x4b, 0x1b, 0xaa, 0xe9, + 0xe5, 0x8b, 0x54, 0xa4, 0x6e, 0x7e, 0xd7, 0x64, 0x0e, 0x94, 0xe2, 0xcb, + 0xa5, 0x14, 0x35, 0xa0, 0x61, 0x4d, 0xaa, 0x96, 0x5b, 0x6a, 0xb9, 0xb7, + 0xf6, 0x19, 0x30, 0xb2, 0xea, 0xad, 0x6c, 0x5b, 0xcb, 0x8c, 0xcf, 0x2b, + 0x14, 0xea, 0xa8, 0x5c, 0x52, 0xce, 0x6e, 0x98, 0xae, 0xd0, 0xdb, 0x2d, + 0x19, 0x25, 0x42, 0xc8, 0x6d, 0xcc, 0xfc, 0xf5, 0x96, 0xee, 0xd1, 0xe3, + 0x68, 0x53, 0x38, 0xd9, 0x9c, 0xde, 0xff, 0xc4, 0xe6, 0xc3, 0x68, 0x59, + 0xed, 0x88, 0x57, 0x3b, 0x95, 0x77, 0x3c, 0x06, 0x23, 0x54, 0x25, 0xdc, + 0xf2, 0xe5, 0xe7, 0x8e, 0x1f, 0x94, 0x39, 0xf2, 0x53, 0x9b, 0xe8, 0x00, + 0x81, 0xfa, 0xa0, 0x0f, 0xbe, 0x40, 0x1e, 0xfd, 0xb8, 0x8e, 0x16, 0xe3, + 0x4d, 0x97, 0xae, 0x05, 0xee, 0x43, 0x2c, 0x7e, 0x5b, 0x03, 0xe5, 0x38, + 0x7b, 0x54, 0x65, 0x1b, 0xf9, 0xe9, 0x13, 0x1e, 0x91, 0x47, 0x14, 0x79, + 0x74, 0xa6, 0x4b, 0xd5, 0xc1, 0x56, 0xaa, 0x84, 0x54, 0x59, 0x11, 0x61, + 0x45, 0x0c, 0x6f, 0xba, 0x02, 0x07, 0xe7, 0x80, 0x59, 0x9f, 0xda, 0xe1, + 0x19, 0x34, 0x38, 0xde, 0x5f, 0x61, 0x97, 0x65, 0xc8, 0x62, 0xda, 0x3c, + 0xb4, 0x8d, 0xec, 0x7e, 0x08, 0xa4, 0x70, 0x06, 0xbf, 0xf8, 0xfa, 0xfe, + 0xe8, 0x76, 0x4b, 0x86, 0xc8, 0x4c, 0xcc, 0x83, 0x1b, 0xcd, 0x22, 0x73, + 0x1d, 0xcb, 0x9f, 0x96, 0x51, 0xd2, 0x37, 0x08, 0x87, 0x99, 0xb9, 0xb3, + 0xd1, 0xbf, 0x92, 0x02, 0x07, 0xe6, 0x7d, 0xa0, 0x03, 0x3f, 0xe3, 0xf8, + 0xf8, 0xf9, 0xca, 0x95, 0x1d, 0xe6, 0x85, 0xe3, 0x9f, 0x0b, 0x85, 0x50, + 0xc5, 0x6f, 0xd0, 0x00, 0x05, 0x20, 0x0e, 0x44, 0xfd, 0x40, 0x1f, 0xf7, + 0xaf, 0xeb, 0x40, 0x8e, 0xb8, 0xc2, 0xec, 0x31, 0x57, 0x74, 0x29, 0xbb, + 0xe0, 0x0c, 0x39, 0xdf, 0x8e, 0xe5, 0xde, 0x10, 0x22, 0xc0, 0x2e, 0x36, + 0x92, 0x25, 0xd1, 0x3f, 0x05, 0x50, 0x92, 0x88, 0x48, 0xd6, 0x20, 0x5f, + 0x06, 0x39, 0xf7, 0x28, 0x4e, 0x36, 0x5c, 0x24, 0xc9, 0x6b, 0x00, 0x00, + 0x00, 0x01, 0x0c, 0x43, 0xd4, 0x08, 0x1f, 0xa2, 0x01, 0x61, 0x14, 0x5e, + 0x67, 0xf0, 0x4e, 0xcf, 0xd6, 0xf2, 0xfe, 0x71, 0x0c, 0xe2, 0x54, 0xda, + 0xb6, 0x8c, 0x0a, 0xad, 0xd1, 0x00, 0x63, 0x8f, 0x22, 0x88, 0x22, 0xbb, + 0xbb, 0x4e, 0x04, 0x50, 0x0f, 0xb9, 0x5f, 0x25, 0x0f, 0xfd, 0xf9, 0xe4, + 0x28, 0x25, 0xbe, 0xad, 0xa2, 0xdc, 0x00, 0xd0, 0x00, 0x45, 0x9c, 0x50, + 0xc0, 0xe8, 0x6e, 0xbe, 0xad, 0x32, 0xfe, 0xe5, 0x26, 0xc2, 0x86, 0x54, + 0x63, 0xc8, 0x82, 0x7f, 0xc8, 0x03, 0xd0, 0xfb, 0x6f, 0xec, 0x10, 0x80, + 0x2a, 0xbf, 0xcc, 0x02, 0x27, 0x75, 0x2c, 0x0d, 0x3d, 0xbc, 0x2a, 0x93, + 0x65, 0x28, 0x02, 0x23, 0xdb, 0x8b, 0x74, 0xc2, 0xe9, 0x09, 0xbf, 0xc9, + 0x70, 0x10, 0x80, 0x1e, 0x47, 0xa4, 0x0d, 0xab, 0x52, 0x0e, 0x3a, 0x8d, + 0xa1, 0x6c, 0x2e, 0x2c, 0x59, 0xb4, 0x36, 0xda, 0x53, 0x0c, 0xfc, 0x57, + 0x00, 0x0c, 0x24, 0x39, 0x9c, 0xb7, 0x8d, 0xf4, 0x2d, 0xb7, 0x85, 0xda, + 0xdc, 0x0d, 0xf2, 0xb9, 0x03, 0x12, 0x42, 0x44, 0x6f, 0x75, 0xb2, 0xf6, + 0xfe, 0xcd, 0x0a, 0x0f, 0x35, 0xbc, 0xe6, 0x97, 0x8a, 0x42, 0xa6, 0x52, + 0x5a, 0x37, 0xd3, 0x04, 0xbf, 0xf3, 0x6b, 0xac, 0x0d, 0xf3, 0xdd, 0xd9, + 0x26, 0x1e, 0x36, 0x5a, 0x54, 0x3c, 0x6b, 0x4c, 0x2e, 0xa1, 0x29, 0x59, + 0x46, 0xf7, 0x7d, 0xbe, 0x35, 0xcf, 0xfe, 0xbb, 0x45, 0xe9, 0xd2, 0xeb, + 0x89, 0xfc, 0xef, 0x7c, 0xbe, 0x58, 0x6c, 0xa9, 0xe7, 0x13, 0x33, 0x32, + 0x18, 0x7c, 0x0b, 0x6f, 0x9d, 0x4e, 0x32, 0xe7, 0x19, 0x96, 0x0f, 0xb9, + 0x0e, 0xa6, 0x42, 0xce, 0x5a, 0x5d, 0x6a, 0x28, 0x88, 0xe7, 0x4f, 0x2b, + 0x90, 0x73, 0xed, 0x98, 0xaf, 0x53, 0xcb, 0x44, 0x08, 0x6b, 0x30, 0x38, + 0x5e, 0x6c, 0x88, 0x02, 0xb9, 0x57, 0xd6, 0x37, 0x9c, 0x98, 0x61, 0x49, + 0x46, 0xa6, 0x52, 0x99, 0x99, 0x23, 0x7d, 0x90, 0x05, 0x84, 0x52, 0x38, + 0xaf, 0xa8, 0x94, 0xf6, 0x2c, 0x11, 0x00, 0x17, 0x08, 0x98, 0xe3, 0x66, + 0xf2, 0x62, 0xc5, 0xf2, 0x0c, 0xa1, 0x4d, 0xf2, 0x27, 0x49, 0x38, 0x73, + 0x8b, 0x1e, 0x54, 0x87, 0x81, 0x4d, 0xd1, 0xca, 0x00, 0x64, 0xe7, 0x29, + 0x0a, 0x94, 0xdc, 0xc5, 0x9e, 0x51, 0xf5, 0x42, 0x0d, 0x75, 0x84, 0x30, + 0xc6, 0xf4, 0xf2, 0x2e, 0x54, 0xf4, 0x56, 0xe9, 0x90, 0xaa, 0x49, 0x6c, + 0x9e, 0xe0, 0x2d, 0xb3, 0xd4, 0x14, 0xf8, 0x00, 0x31, 0x88, 0xdd, 0xf2, + 0x3b, 0xaf, 0x3a, 0x59, 0x0d, 0xb2, 0x55, 0xfa, 0x1b, 0x62, 0xd0, 0xb2, + 0x43, 0x22, 0x64, 0x64, 0x39, 0xbe, 0x54, 0x4e, 0xf3, 0x11, 0x43, 0x0f, + 0x48, 0xbe, 0xad, 0xa3, 0xad, 0xd1, 0x53, 0xf2, 0xa0, 0x53, 0x71, 0xac, + 0x3a, 0xa8, 0x4a, 0x94, 0xdd, 0x17, 0xec, 0x58, 0x6a, 0x06, 0x29, 0x4a, + 0x39, 0xa1, 0x4e, 0x8c, 0xe3, 0x68, 0xa0, 0x16, 0xf1, 0xc6, 0xcd, 0x09, + 0x2e, 0x4a, 0xbe, 0xad, 0xfa, 0x64, 0x01, 0xb8, 0x9a, 0x00, 0xeb, 0xee, + 0x00, 0xe7, 0x7d, 0xfc, 0xa4, 0x28, 0xcc, 0x00, 0x3d, 0x17, 0xc3, 0x9d, + 0x07, 0x95, 0x84, 0xed, 0xb8, 0xb4, 0x07, 0x8b, 0x6b, 0x7e, 0x71, 0xdf, + 0xcb, 0xf2, 0x10, 0x8a, 0x6f, 0xd3, 0x20, 0x0a, 0x14, 0x10, 0x40, 0x4c, + 0x8f, 0xdd, 0xf3, 0xa0, 0x11, 0x73, 0xb9, 0xb0, 0x05, 0x4a, 0xb4, 0x34, + 0x62, 0xb7, 0x36, 0x6c, 0xe3, 0x7c, 0xb2, 0xe0, 0x6a, 0xee, 0xc0, 0x86, + 0x98, 0x5e, 0xe4, 0x25, 0xb7, 0xf2, 0x89, 0x08, 0x3e, 0xf4, 0x55, 0x40, + 0x47, 0xff, 0xd8, 0x27, 0x5d, 0xce, 0x48, 0x08, 0xff, 0xfb, 0xf8, 0x99, + 0xa5, 0x04, 0x94, 0x5b, 0x74, 0x2e, 0x80, 0x1f, 0x00, 0x1b, 0x23, 0xe5, + 0x02, 0x64, 0x76, 0x76, 0xa5, 0x94, 0x4c, 0xcd, 0x2e, 0x12, 0x9b, 0x37, + 0x34, 0x0c, 0x11, 0x4e, 0x0c, 0xbd, 0x0a, 0x17, 0x2e, 0x20, 0xdf, 0xd6, + 0xe6, 0x6d, 0x01, 0x1d, 0x48, 0xdd, 0x4b, 0x00, 0x0f, 0x05, 0x0a, 0xe1, + 0x36, 0x06, 0x42, 0x2c, 0x7c, 0xc0, 0xc1, 0x9e, 0x72, 0x16, 0x18, 0xde, + 0xb0, 0xc6, 0xf6, 0xcf, 0x6f, 0xce, 0x7b, 0x26, 0x4d, 0x4d, 0x7d, 0x18, + 0x55, 0x33, 0x65, 0xbb, 0x14, 0x08, 0x7d, 0xb5, 0xb8, 0xcb, 0x5d, 0xc7, + 0x1b, 0x60, 0xec, 0x99, 0x2c, 0x0e, 0x1e, 0x03, 0x36, 0xeb, 0x48, 0xff, + 0x62, 0x05, 0xb8, 0x58, 0xd4, 0x15, 0x3c, 0xb6, 0xd3, 0xa0, 0xd9, 0xa9, + 0xe2, 0xad, 0x97, 0x90, 0x42, 0xff, 0x5d, 0xbc, 0x20, 0x5e, 0x24, 0x2e, + 0xfa, 0x12, 0x98, 0x87, 0xb5, 0x53, 0x9b, 0x41, 0x22, 0xf4, 0x5f, 0x7c, + 0xef, 0x96, 0xd8, 0x32, 0x4e, 0x9c, 0x62, 0x8d, 0xfd, 0xac, 0x29, 0xbd, + 0x29, 0x19, 0xd3, 0xeb, 0xfd, 0xee, 0xd1, 0x7b, 0x75, 0x64, 0x7c, 0x5c, + 0xd9, 0x92, 0x4a, 0xba, 0x9e, 0x70, 0x9a, 0x90, 0x39, 0xb8, 0x2b, 0x09, + 0xf9, 0x64, 0x09, 0xb1, 0x70, 0xe1, 0xa7, 0x44, 0x3c, 0x21, 0xae, 0x74, + 0xd7, 0x08, 0xce, 0x67, 0x36, 0xd4, 0x3b, 0x69, 0x91, 0xd2, 0x58, 0x7a, + 0xc2, 0x83, 0x94, 0xb6, 0x89, 0x1b, 0x3a, 0x54, 0x56, 0xf4, 0xdc, 0xf6, + 0x15, 0xaf, 0xa2, 0xb2, 0x40, 0x09, 0x6c, 0x31, 0x16, 0xa1, 0xc3, 0xce, + 0x39, 0xb0, 0xe5, 0x79, 0x3d, 0xf5, 0xf2, 0x2f, 0xe9, 0x23, 0xa2, 0xa5, + 0x3c, 0x29, 0xbb, 0x3c, 0xdd, 0x14, 0x2f, 0x71, 0x0b, 0x3b, 0x3c, 0xae, + 0x38, 0xfa, 0x12, 0x35, 0x02, 0x5b, 0x3a, 0xce, 0xd3, 0x8e, 0x8b, 0x02, + 0x43, 0xb0, 0x3e, 0x0f, 0x2a, 0xfa, 0xb4, 0xc8, 0x53, 0x6d, 0xb5, 0x6b, + 0x6d, 0xce, 0xae, 0x5d, 0x18, 0x7c, 0x2d, 0x42, 0x9a, 0xfd, 0xd8, 0xfb, + 0x37, 0x28, 0x4d, 0xa5, 0x9c, 0x15, 0xea, 0xdc, 0x8e, 0xb2, 0xe7, 0x50, + 0xe8, 0x3e, 0x86, 0x8c, 0x21, 0x04, 0xb5, 0xb7, 0x11, 0xf0, 0xb1, 0xc7, + 0x0f, 0x30, 0xf2, 0xda, 0x6b, 0x68, 0xde, 0xcc, 0xf3, 0x72, 0xee, 0xbe, + 0x8e, 0xc2, 0xce, 0x90, 0x90, 0xdc, 0xd1, 0x40, 0x61, 0xd6, 0xdb, 0xb4, + 0xe0, 0xc1, 0xc8, 0xcc, 0x08, 0x60, 0x0b, 0x99, 0xa3, 0x4e, 0xab, 0xa3, + 0x1b, 0x1b, 0xdf, 0xe7, 0x61, 0xc0, 0x3c, 0x33, 0x2c, 0x09, 0x0d, 0x62, + 0x56, 0x2b, 0x76, 0x75, 0x72, 0xda, 0x99, 0x96, 0x8d, 0xb6, 0x16, 0xd8, + 0xf2, 0x9b, 0xce, 0x92, 0x0f, 0x6d, 0x8e, 0x7d, 0xc7, 0x9b, 0x32, 0x0d, + 0x2f, 0x10, 0xb8, 0xa5, 0x9c, 0xce, 0x26, 0x00, 0x1f, 0xfb, 0x48, 0x81, + 0xa6, 0xdc, 0xb9, 0xb3, 0xd4, 0xe6, 0x89, 0x52, 0x94, 0xd9, 0x66, 0xcc, + 0x79, 0x4d, 0xd3, 0x99, 0x67, 0x05, 0xa4, 0x0b, 0x53, 0xdb, 0xd4, 0x80, + 0x37, 0x14, 0xef, 0xaf, 0x5b, 0xc3, 0xbd, 0xf9, 0xca, 0x96, 0xbb, 0x1f, + 0xbc, 0x2d, 0x93, 0x5d, 0x77, 0x28, 0x6a, 0x96, 0xde, 0x9f, 0xe4, 0x47, + 0xbf, 0xfc, 0x01, 0x8f, 0x5f, 0x0e, 0x76, 0xaa, 0x19, 0x86, 0xbd, 0xff, + 0xb1, 0xbe, 0x90, 0xb6, 0xc1, 0x05, 0xf1, 0xbf, 0x1f, 0x1c, 0x00, 0x56, + 0xf9, 0x2e, 0x69, 0x3a, 0xf3, 0xd1, 0x99, 0xa5, 0x87, 0xa8, 0x79, 0x92, + 0x16, 0x10, 0xdc, 0xbd, 0x07, 0x00, 0xe4, 0x84, 0xde, 0x68, 0x89, 0xe5, + 0x57, 0x42, 0x9b, 0xe9, 0x80, 0x14, 0xfc, 0x8a, 0x77, 0x28, 0x2a, 0x3a, + 0x87, 0x4f, 0x37, 0x17, 0x71, 0x12, 0x1b, 0x0e, 0xf5, 0x6e, 0xc8, 0x01, + 0x3f, 0xce, 0x7c, 0x90, 0x26, 0xfb, 0x75, 0xfb, 0xf2, 0x79, 0x92, 0x9b, + 0x13, 0xf0, 0xb6, 0x0f, 0x5b, 0x5b, 0xd9, 0x80, 0x3c, 0xff, 0xe7, 0xc9, + 0x07, 0x7a, 0x9d, 0xc9, 0x40, 0x27, 0x2e, 0x66, 0xdb, 0x51, 0x74, 0xe1, + 0xd5, 0x50, 0xe8, 0xad, 0xee, 0xfe, 0x3f, 0xa2, 0x9e, 0x2c, 0x5e, 0x76, + 0xf7, 0xc0, 0x1e, 0x73, 0x39, 0xc7, 0xc8, 0x90, 0x38, 0x3a, 0xad, 0x44, + 0x38, 0x31, 0xbc, 0xde, 0xc4, 0x0a, 0xb8, 0x55, 0x2c, 0x34, 0xe8, 0x8d, + 0xca, 0xe7, 0x70, 0x88, 0x58, 0x5b, 0x7f, 0x34, 0x00, 0x78, 0x23, 0x90, + 0x03, 0x5e, 0xfd, 0xe7, 0xce, 0x5a, 0x4d, 0xe6, 0xbf, 0x76, 0xed, 0xa6, + 0x17, 0x87, 0x7a, 0x1c, 0xdd, 0xd0, 0x04, 0xd8, 0x29, 0xfb, 0x5f, 0xc6, + 0xec, 0x85, 0x2f, 0x96, 0xd5, 0xf2, 0x0b, 0xc0, 0xc6, 0xbb, 0xe8, 0x47, + 0x70, 0x03, 0xa2, 0x27, 0xba, 0xc1, 0x38, 0xaa, 0x66, 0x13, 0x95, 0x64, + 0xb1, 0x69, 0x41, 0x10, 0xb6, 0xf8, 0xb7, 0xb8, 0x8a, 0x46, 0xaf, 0x93, + 0xe3, 0x61, 0xf3, 0x97, 0x73, 0x1e, 0x67, 0x9c, 0x3a, 0xc5, 0x68, 0x7b, + 0xb8, 0xe9, 0x54, 0xa1, 0xb4, 0x04, 0x4d, 0xcd, 0x33, 0x31, 0x16, 0x46, + 0xfe, 0xd4, 0x00, 0xe9, 0xdc, 0x7c, 0x08, 0x7e, 0xe4, 0xbb, 0x52, 0x07, + 0xea, 0x54, 0x92, 0x0d, 0x6f, 0x0f, 0x7b, 0xc7, 0x6f, 0x4e, 0xeb, 0x50, + 0x11, 0xff, 0xef, 0x74, 0xcc, 0x43, 0xce, 0xaa, 0xdc, 0x91, 0x41, 0xc2, + 0xc8, 0xb3, 0x71, 0x00, 0x8c, 0x9d, 0xed, 0xc9, 0x10, 0xea, 0x6a, 0xe4, + 0x5a, 0x18, 0xdc, 0x20, 0x0a, 0x3a, 0xf6, 0x7f, 0x0e, 0xa2, 0x5c, 0x3b, + 0x76, 0xcc, 0xab, 0x2c, 0x4a, 0x50, 0x6f, 0x83, 0x79, 0xfc, 0x8a, 0x9e, + 0x4e, 0x8e, 0x74, 0xa1, 0x35, 0x5b, 0x33, 0x11, 0x12, 0x37, 0xd7, 0x00, + 0x40, 0xff, 0x79, 0xa2, 0x1d, 0x5d, 0x5d, 0x2a, 0xd9, 0x5e, 0xe3, 0x0d, + 0xa1, 0x6d, 0xf6, 0x00, 0x05, 0xdf, 0x34, 0x01, 0xb8, 0x03, 0xce, 0x6f, + 0x7d, 0x82, 0x47, 0xfe, 0x38, 0xda, 0x62, 0x1f, 0x0b, 0x81, 0xad, 0xf0, + 0xbe, 0xbe, 0xff, 0x22, 0x44, 0xed, 0xdf, 0x83, 0x16, 0xd8, 0xe7, 0x66, + 0xa1, 0x86, 0xdf, 0xca, 0x25, 0x28, 0xf8, 0xdf, 0x5c, 0x9f, 0x5e, 0xff, + 0xe2, 0xb7, 0xae, 0xf9, 0xe6, 0x8d, 0x2a, 0xd5, 0x36, 0x40, 0xc6, 0xf6, + 0x36, 0xbf, 0x97, 0xc3, 0x6e, 0x96, 0x4a, 0x6d, 0xa0, 0x7d, 0x8a, 0x4a, + 0x60, 0x00, 0x00, 0x01, 0x0d, 0x43, 0xf7, 0xdd, 0x8a, 0x78, 0x80, 0x06, + 0xc0, 0x0d, 0x05, 0x73, 0x52, 0x25, 0x20, 0x02, 0x10, 0x03, 0xf7, 0x2b, + 0x8d, 0x50, 0xea, 0x6d, 0xa5, 0x95, 0x43, 0x65, 0x6f, 0x4c, 0x00, 0xf8, + 0x5b, 0x80, 0x1b, 0x77, 0xcf, 0xcd, 0xdc, 0xa3, 0xe7, 0x9f, 0x0b, 0x24, + 0x3a, 0xfe, 0xa5, 0x29, 0x43, 0x1a, 0x10, 0x34, 0x89, 0xcd, 0xde, 0x5f, + 0xc5, 0xa7, 0x77, 0x37, 0xc9, 0x21, 0x8a, 0x61, 0xc1, 0x2d, 0xf3, 0xe0, + 0x07, 0xc0, 0x0d, 0x78, 0xe7, 0xe4, 0x88, 0xff, 0x6f, 0x68, 0x85, 0xf9, + 0x3e, 0x6d, 0x96, 0x6e, 0x2a, 0x40, 0xe9, 0x21, 0x77, 0xc1, 0xbc, 0x34, + 0xfc, 0x56, 0xe7, 0x96, 0x64, 0xb2, 0xac, 0xa5, 0x8e, 0x52, 0x82, 0x02, + 0x5b, 0xf8, 0x7d, 0xcb, 0xe7, 0x95, 0x60, 0x62, 0x4b, 0x2c, 0x21, 0x56, + 0xd9, 0x06, 0xd6, 0xfa, 0xb0, 0x02, 0x1c, 0x80, 0x09, 0x1c, 0x28, 0x89, + 0xf5, 0x10, 0xf8, 0x1d, 0x67, 0x7c, 0xf6, 0xee, 0xa4, 0x35, 0xda, 0x5e, + 0x54, 0x1c, 0xa3, 0x61, 0x4d, 0x98, 0x10, 0x3f, 0x4b, 0xf9, 0xa0, 0x0f, + 0xfe, 0x33, 0x3d, 0x88, 0xf9, 0x46, 0x49, 0xdb, 0xf2, 0x24, 0xe3, 0x4b, + 0xb8, 0xaa, 0xd9, 0xc2, 0xe2, 0x94, 0xde, 0x7b, 0xe1, 0xcd, 0xf1, 0x80, + 0x1c, 0x8a, 0xec, 0x01, 0x0f, 0xf0, 0x43, 0xb5, 0xd8, 0x1b, 0x39, 0x9d, + 0x87, 0x28, 0x0a, 0xa8, 0xdf, 0x46, 0xfb, 0x7f, 0x7e, 0x77, 0xfe, 0x40, + 0x31, 0xf4, 0x63, 0xae, 0x3b, 0xf3, 0x77, 0xc1, 0x0a, 0x40, 0xb6, 0xfa, + 0x37, 0xf7, 0xe7, 0xbf, 0xa8, 0x03, 0x71, 0x62, 0x44, 0xe8, 0x62, 0x6b, + 0xd4, 0x39, 0x3f, 0x08, 0x98, 0x32, 0x48, 0xdf, 0x3f, 0xfe, 0x0b, 0x00, + 0x10, 0x67, 0x57, 0x66, 0x0c, 0xa5, 0xe1, 0x65, 0x9e, 0xd3, 0x23, 0xba, + 0xe5, 0xf6, 0xda, 0x02, 0x29, 0x0b, 0x6b, 0xdb, 0x31, 0xf4, 0xbf, 0x06, + 0xfe, 0x5f, 0xdf, 0xbe, 0xfd, 0xb2, 0x75, 0xd6, 0xd4, 0x2d, 0x65, 0x88, + 0x89, 0xe8, 0xde, 0x08, 0x00, 0xf5, 0xe2, 0x3d, 0x9c, 0xfe, 0x79, 0xc9, + 0x13, 0xf0, 0xee, 0xe0, 0xea, 0x03, 0x56, 0xfa, 0x3f, 0xd5, 0xc0, 0x82, + 0x02, 0x7e, 0xdc, 0x9a, 0x5c, 0x39, 0x49, 0xf9, 0x21, 0xdb, 0x25, 0x2e, + 0x0d, 0x6f, 0x8d, 0x75, 0x67, 0x44, 0x0e, 0x6a, 0x84, 0x3d, 0x72, 0x98, + 0x38, 0xe1, 0xc3, 0x5b, 0x93, 0x78, 0x82, 0x66, 0xbb, 0x89, 0x83, 0xe2, + 0x5c, 0x6c, 0x2c, 0x34, 0xa8, 0xda, 0x11, 0x45, 0xe0, 0x87, 0x53, 0x2b, + 0x8e, 0x53, 0x35, 0x15, 0x2a, 0x1c, 0x1a, 0x90, 0xe6, 0xa3, 0xfb, 0xb6, + 0xed, 0xb6, 0x00, 0x46, 0x5d, 0x28, 0x28, 0x31, 0xbd, 0x8e, 0x77, 0x78, + 0xa2, 0xf5, 0xd8, 0x17, 0x69, 0xcd, 0xe0, 0x3e, 0xd2, 0xfd, 0x51, 0x20, + 0x5e, 0xcd, 0xca, 0xa8, 0x71, 0x68, 0xde, 0x97, 0xee, 0xb6, 0x92, 0x14, + 0x5b, 0x76, 0xce, 0x9d, 0xc0, 0x9d, 0x57, 0x00, 0xaa, 0xa0, 0xd8, 0x31, + 0xbc, 0xe0, 0xa9, 0x38, 0xe1, 0xda, 0x50, 0x48, 0xc8, 0xad, 0xf4, 0x0e, + 0x45, 0xe6, 0xfd, 0x26, 0xc7, 0xe1, 0x55, 0x1e, 0xb5, 0xd9, 0xa1, 0xd4, + 0x3c, 0x7c, 0x94, 0xa3, 0xda, 0x00, 0x27, 0xf9, 0xf6, 0xfa, 0x8a, 0x23, + 0x77, 0x5f, 0x14, 0x11, 0x00, 0x13, 0xae, 0xc8, 0x84, 0x7e, 0xf8, 0x8e, + 0x81, 0x1b, 0xc6, 0xae, 0xc8, 0x34, 0xa2, 0x8b, 0x6a, 0x44, 0x18, 0xda, + 0x13, 0x65, 0x6f, 0xe6, 0xe0, 0x38, 0xdb, 0x23, 0x6d, 0xd2, 0xe0, 0x16, + 0xd9, 0x3d, 0xdd, 0x08, 0x12, 0x3b, 0x68, 0x69, 0xb6, 0x8f, 0x2d, 0xb7, + 0xda, 0xaf, 0xb4, 0xc0, 0x82, 0xc6, 0x34, 0x51, 0xa4, 0xa6, 0x34, 0xaa, + 0xde, 0xde, 0xcc, 0x32, 0xcb, 0x35, 0x06, 0xd8, 0x55, 0x42, 0xd4, 0x7b, + 0x75, 0xbe, 0x94, 0x02, 0xdf, 0x99, 0x5e, 0xfc, 0x0c, 0x8e, 0xda, 0x52, + 0xd0, 0xc5, 0xb1, 0xb9, 0xe4, 0x68, 0xff, 0x97, 0xdd, 0x2c, 0xe5, 0x5d, + 0xdf, 0x27, 0x2c, 0xc2, 0xce, 0x3e, 0xb6, 0xbe, 0xb9, 0xbe, 0xde, 0xd8, + 0xee, 0x02, 0x6c, 0xc9, 0x0a, 0x83, 0x21, 0x50, 0x73, 0x73, 0xd3, 0x64, + 0x96, 0x46, 0x76, 0xa5, 0x6f, 0xde, 0xdb, 0xa4, 0x7f, 0x8f, 0x67, 0x6d, + 0xa3, 0xd2, 0xb8, 0x47, 0x75, 0xca, 0x02, 0x27, 0x48, 0x88, 0xdc, 0xdc, + 0xc9, 0x74, 0x5a, 0x84, 0x7e, 0x04, 0xf6, 0x28, 0x5d, 0xc1, 0xb0, 0xe9, + 0x69, 0x96, 0x84, 0x94, 0xc9, 0xec, 0x08, 0x5f, 0xe3, 0xc7, 0x3d, 0x6e, + 0xd3, 0xca, 0xd0, 0x33, 0x1f, 0x80, 0x03, 0x57, 0x4d, 0x8a, 0x13, 0x2b, + 0x55, 0x2c, 0xe3, 0x9e, 0xa9, 0x0f, 0x8d, 0xf6, 0xd5, 0x5a, 0xb4, 0xb9, + 0xc3, 0xa9, 0xc1, 0x0d, 0xea, 0x48, 0x6a, 0x92, 0x5b, 0xd5, 0x81, 0xf3, + 0x49, 0x2d, 0xd1, 0x51, 0xe0, 0x07, 0x06, 0xe2, 0x01, 0x08, 0x40, 0x17, + 0x28, 0xf3, 0xb6, 0xad, 0x24, 0xb2, 0xc3, 0x48, 0xfe, 0x7a, 0x58, 0x0a, + 0xdd, 0xd7, 0x25, 0x78, 0xe2, 0xab, 0x68, 0x11, 0xcb, 0xc5, 0x73, 0x56, + 0x3c, 0xc5, 0x49, 0x1d, 0xdf, 0x6f, 0xdb, 0x03, 0x52, 0xdd, 0x90, 0xa9, + 0x47, 0x4b, 0x5a, 0xb7, 0x61, 0x02, 0xfd, 0x1d, 0xde, 0x84, 0x95, 0x9b, + 0xd6, 0x5b, 0x4a, 0x42, 0xd1, 0x17, 0xc5, 0xae, 0x94, 0xda, 0xc6, 0xeb, + 0x9c, 0xc1, 0x74, 0x54, 0xcc, 0x2c, 0x62, 0xef, 0x12, 0xc2, 0xcf, 0x19, + 0x46, 0x9e, 0x1a, 0xcb, 0x0d, 0xe3, 0xe4, 0x46, 0x98, 0x78, 0xe1, 0x4e, + 0xb3, 0x74, 0x69, 0x34, 0xaa, 0xa8, 0xc7, 0x9e, 0x70, 0x89, 0x9e, 0xd3, + 0x9b, 0x46, 0xd5, 0x82, 0x7a, 0xb9, 0xe6, 0x30, 0xe0, 0xca, 0xd8, 0xdc, + 0x67, 0x0e, 0xce, 0x27, 0x8e, 0x45, 0x7f, 0xa2, 0xd2, 0x9a, 0x0e, 0x6a, + 0x3e, 0x37, 0xae, 0x13, 0xb6, 0xdf, 0x2c, 0xc8, 0x33, 0xf1, 0x9b, 0x4b, + 0xa1, 0x6c, 0x65, 0x33, 0x87, 0xc4, 0x81, 0x17, 0xb7, 0xe9, 0xe7, 0x0d, + 0x90, 0x61, 0x25, 0xab, 0x7d, 0xcd, 0x49, 0x29, 0x43, 0x25, 0x3b, 0x0b, + 0x83, 0x8f, 0x24, 0x35, 0x7c, 0x4d, 0xd7, 0xee, 0x94, 0x36, 0xc9, 0xae, + 0x86, 0x95, 0x4b, 0xa5, 0x9e, 0x30, 0x35, 0x6b, 0x45, 0x6b, 0x6e, 0xe7, + 0x5d, 0xd8, 0x03, 0x9b, 0x4e, 0x5b, 0xb2, 0xd3, 0x90, 0x86, 0xd5, 0xed, + 0x91, 0x40, 0xea, 0xa3, 0x9b, 0x35, 0x48, 0x92, 0xc0, 0x82, 0xda, 0xf9, + 0xf9, 0xd3, 0xc0, 0x22, 0xf5, 0x3d, 0x86, 0xb6, 0xe5, 0xc5, 0xb8, 0x68, + 0x52, 0x1a, 0x74, 0x39, 0x97, 0x9e, 0x88, 0x3e, 0xd9, 0xbc, 0xc5, 0x29, + 0x2e, 0x49, 0x4c, 0xcb, 0x42, 0x62, 0x95, 0x68, 0x53, 0x73, 0xfa, 0x97, + 0x8e, 0xe4, 0xdf, 0x49, 0x14, 0x34, 0x31, 0xba, 0x3f, 0x4e, 0xb0, 0x01, + 0xc8, 0x9c, 0x27, 0xe9, 0x65, 0x07, 0xf4, 0x56, 0x13, 0xa8, 0x0a, 0xdf, + 0x43, 0x4e, 0x0b, 0x68, 0x1a, 0x53, 0x73, 0xf0, 0x06, 0x35, 0x6f, 0xa3, + 0x7f, 0x47, 0x00, 0x5a, 0x01, 0x67, 0xdc, 0x8a, 0xef, 0x8d, 0x10, 0xf3, + 0xa4, 0xb8, 0x41, 0x73, 0xe7, 0x98, 0xd3, 0xa6, 0x15, 0x61, 0x43, 0xea, + 0xb7, 0x98, 0x12, 0xe0, 0x01, 0x0f, 0xb0, 0x8e, 0x5f, 0xe1, 0x38, 0x93, + 0x09, 0x46, 0x36, 0x0f, 0x6c, 0x98, 0x47, 0xd8, 0xfd, 0xc1, 0xf6, 0xbb, + 0x0c, 0x33, 0x4a, 0x1e, 0x32, 0x8e, 0x39, 0xbb, 0x80, 0x0f, 0x28, 0xb0, + 0x06, 0x20, 0x0f, 0xf8, 0xe2, 0x71, 0xb0, 0x75, 0xd2, 0x75, 0xd7, 0x24, + 0x0f, 0xa5, 0xc2, 0xa1, 0x51, 0xb9, 0xf2, 0xf9, 0x49, 0x29, 0x29, 0xbc, + 0x5c, 0x86, 0x61, 0x4d, 0xfb, 0x01, 0x5c, 0x00, 0x19, 0x77, 0xdf, 0x29, + 0x81, 0xa6, 0xb9, 0xf2, 0x4c, 0x5f, 0x16, 0xf9, 0x5c, 0x81, 0xdd, 0x6d, + 0xf1, 0x5c, 0xca, 0x43, 0xb2, 0x29, 0x29, 0xbe, 0x9e, 0x00, 0xd8, 0x58, + 0x20, 0x80, 0xb7, 0x06, 0x91, 0xc9, 0xd0, 0x67, 0x13, 0x6f, 0x16, 0x3a, + 0xc2, 0x6d, 0x01, 0xc8, 0xf4, 0x28, 0x6b, 0x7c, 0xaf, 0x8b, 0x75, 0xdf, + 0x17, 0x9c, 0x09, 0xb9, 0xcf, 0x95, 0x40, 0x11, 0x5d, 0xb0, 0xa8, 0xd8, + 0xec, 0x3f, 0x00, 0x06, 0x4a, 0xd9, 0x50, 0xd6, 0xfd, 0x57, 0xbc, 0xde, + 0xb9, 0xc7, 0xae, 0x06, 0x6c, 0x55, 0xcb, 0x02, 0x2c, 0x2d, 0xbe, 0x82, + 0x00, 0xec, 0x50, 0x01, 0xd3, 0xbb, 0x27, 0x9a, 0x3e, 0xf6, 0xf1, 0x3b, + 0xa1, 0xf9, 0x4a, 0xc3, 0xa2, 0xc9, 0x32, 0x14, 0x3d, 0xbc, 0xe7, 0xc6, + 0xf3, 0xfe, 0x82, 0x9d, 0xcb, 0xdc, 0x59, 0x30, 0xcd, 0xdb, 0xae, 0x1e, + 0x9e, 0x45, 0xc0, 0xf8, 0x30, 0x9a, 0xdd, 0xbf, 0xf6, 0x75, 0xf5, 0xbc, + 0x0a, 0xe3, 0x32, 0x1d, 0x26, 0xdb, 0x15, 0xc8, 0x7a, 0xac, 0x1b, 0x42, + 0x9b, 0xcc, 0xb8, 0xa7, 0x27, 0x80, 0x1e, 0xd9, 0x86, 0xc6, 0xf8, 0x7f, + 0x5f, 0x8e, 0x5f, 0xc0, 0xa1, 0x3b, 0x47, 0x57, 0x6b, 0xb2, 0xec, 0x83, + 0x8f, 0x80, 0x72, 0x36, 0xe0, 0x05, 0xe0, 0x0f, 0x2e, 0x91, 0xfc, 0x9e, + 0xeb, 0x95, 0x51, 0xfb, 0x62, 0xdc, 0xcb, 0x69, 0x90, 0xbd, 0x18, 0xad, + 0x8b, 0x8d, 0x70, 0x02, 0x69, 0xc7, 0x02, 0xdd, 0x40, 0x7b, 0x16, 0x2a, + 0xc4, 0x32, 0x1e, 0x50, 0xc0, 0xa8, 0xde, 0xa8, 0x00, 0xab, 0x6f, 0xf7, + 0xb1, 0x7d, 0x8a, 0x96, 0x8f, 0x86, 0xf3, 0xce, 0xe9, 0x65, 0x5a, 0x85, + 0xd5, 0x28, 0x96, 0xda, 0xda, 0x9b, 0x61, 0x4c, 0xee, 0x96, 0xdf, 0x9d, + 0xe8, 0xd0, 0x02, 0x87, 0x6a, 0xf7, 0x46, 0xae, 0xe8, 0xbd, 0xde, 0x70, + 0xb1, 0x9e, 0x5f, 0xa8, 0xbe, 0x2d, 0xe3, 0xdf, 0x79, 0xfe, 0xce, 0x11, + 0xc1, 0x92, 0xd7, 0xa2, 0x78, 0xa9, 0xde, 0x2d, 0xf4, 0x37, 0x89, 0x80, + 0x82, 0x02, 0xbb, 0xce, 0xc7, 0x58, 0x4c, 0xb2, 0x3d, 0x33, 0x24, 0xa1, + 0x11, 0x0a, 0x81, 0x4c, 0xbf, 0xdd, 0x84, 0x4f, 0x7e, 0xf4, 0x5b, 0xe2, + 0x2c, 0xb8, 0x66, 0x6d, 0x86, 0x60, 0xf0, 0x89, 0x1b, 0x1e, 0x83, 0xae, + 0x69, 0x0a, 0xb3, 0x85, 0x40, 0x2d, 0xbe, 0x98, 0xbe, 0xef, 0xc7, 0x2f, + 0x9f, 0x3d, 0xdd, 0xd3, 0xb8, 0xd9, 0x29, 0x86, 0x5b, 0xb4, 0x7e, 0x53, + 0x92, 0x28, 0xe6, 0xf2, 0xdf, 0x4e, 0x34, 0x01, 0xac, 0xf8, 0x9f, 0x99, + 0xfb, 0xdd, 0xd4, 0x95, 0x6e, 0xd2, 0xc9, 0xa7, 0xa0, 0xd6, 0xe7, 0x11, + 0x26, 0xfd, 0xc8, 0xc2, 0x05, 0xfb, 0x60, 0x6e, 0x65, 0x7e, 0x5b, 0xbb, + 0x20, 0x61, 0x69, 0x5b, 0x38, 0x03, 0x17, 0x71, 0xf4, 0xf7, 0xdc, 0x0f, + 0x87, 0xad, 0xce, 0x7a, 0x90, 0xd4, 0x0d, 0xc9, 0x62, 0xf8, 0xb7, 0x4f, + 0x12, 0xb9, 0xd9, 0xb2, 0x84, 0xa4, 0x58, 0x42, 0x69, 0x18, 0x05, 0x30, + 0x00, 0x00, 0x01, 0x0e, 0x43, 0xfa, 0xd0, 0x87, 0x4c, 0x11, 0xbc, 0xe4, + 0x90, 0xb2, 0xea, 0x14, 0x60, 0x5b, 0x78, 0x70, 0x02, 0x7e, 0x7a, 0x00, + 0x75, 0xd1, 0x02, 0xef, 0x35, 0x60, 0x22, 0x00, 0x26, 0x5b, 0x8f, 0xbb, + 0x80, 0x60, 0xc3, 0x14, 0xc3, 0xe1, 0x61, 0x81, 0x8d, 0xed, 0x7e, 0xa0, + 0x16, 0x00, 0x2d, 0x23, 0x5d, 0xe9, 0x2d, 0x2a, 0xae, 0x75, 0xa0, 0x66, + 0xcb, 0x2a, 0x16, 0x59, 0x29, 0xbb, 0x82, 0x78, 0xe7, 0x3d, 0xf8, 0x00, + 0xb2, 0x55, 0xab, 0x86, 0x3e, 0x1f, 0x1f, 0x4a, 0x91, 0x14, 0x69, 0x6d, + 0xf3, 0x59, 0x24, 0xd3, 0x2d, 0x21, 0x9c, 0xde, 0x45, 0x95, 0xf5, 0x27, + 0x82, 0xc6, 0xf5, 0x72, 0xed, 0x00, 0x2f, 0x79, 0x16, 0x41, 0x7c, 0xdf, + 0xdd, 0xef, 0x34, 0xcb, 0x84, 0x13, 0x09, 0xee, 0x8b, 0x92, 0xcb, 0x5d, + 0xe4, 0xa8, 0x72, 0xb7, 0xbf, 0xb5, 0xdb, 0xc4, 0x55, 0x83, 0x2e, 0xab, + 0xd6, 0x50, 0x11, 0x01, 0xed, 0xc5, 0xb6, 0x80, 0x5b, 0x65, 0xb4, 0xb4, + 0x59, 0x9b, 0x91, 0x14, 0x9b, 0x4b, 0xb4, 0xf2, 0xdb, 0xad, 0x9b, 0xb5, + 0xf2, 0x05, 0x98, 0x52, 0x4b, 0xfa, 0x18, 0x59, 0xde, 0xad, 0xb3, 0xa7, + 0x9a, 0x18, 0xa4, 0x86, 0xf4, 0x23, 0x7d, 0x0c, 0x5c, 0x2d, 0x03, 0x29, + 0x71, 0x65, 0x18, 0x43, 0x6f, 0x2c, 0x00, 0xb7, 0xe7, 0xcb, 0x24, 0xcc, + 0x71, 0x63, 0x4a, 0x1a, 0xde, 0x96, 0x48, 0xbb, 0x2e, 0x51, 0xb5, 0x21, + 0x85, 0xca, 0x49, 0x6c, 0x79, 0x2e, 0xba, 0x47, 0x5b, 0x07, 0x87, 0xd8, + 0x50, 0x61, 0x43, 0xeb, 0x68, 0xfe, 0x77, 0x87, 0x67, 0x94, 0xf0, 0xa7, + 0xd4, 0xac, 0xae, 0xdc, 0x85, 0x4f, 0x56, 0xfc, 0x08, 0x03, 0x59, 0x00, + 0x1e, 0x6f, 0xff, 0x79, 0xe2, 0x04, 0x08, 0x22, 0x67, 0x2b, 0x40, 0x4b, + 0x69, 0xbc, 0xac, 0x41, 0xd0, 0x3e, 0xb7, 0xe3, 0x8f, 0xaf, 0x0f, 0x22, + 0x66, 0x9a, 0x65, 0x83, 0x53, 0x2a, 0x12, 0x4a, 0x6f, 0xe8, 0x24, 0xc7, + 0x67, 0x7e, 0x56, 0xed, 0x43, 0xab, 0xdc, 0x1c, 0xa4, 0x30, 0xe8, 0xdf, + 0x9c, 0xc0, 0x14, 0x13, 0xc0, 0x16, 0x0a, 0xb7, 0x9e, 0xf6, 0xd1, 0xaa, + 0x23, 0x2d, 0xd3, 0x0e, 0xb4, 0x38, 0x64, 0x81, 0x2d, 0xc8, 0xe8, 0x01, + 0x66, 0xc9, 0x7c, 0x57, 0xc4, 0xf6, 0xe6, 0x52, 0x75, 0x02, 0xdb, 0xfc, + 0xdb, 0xf0, 0x23, 0x05, 0xab, 0xd0, 0x32, 0x1c, 0x69, 0xde, 0x0c, 0x04, + 0xd0, 0x0b, 0x5f, 0x35, 0x60, 0x0a, 0x83, 0xa1, 0x94, 0x2c, 0xb3, 0xa3, + 0x7b, 0x5f, 0xae, 0xe8, 0x94, 0xe3, 0x16, 0x0d, 0x2e, 0x42, 0xd2, 0x86, + 0x41, 0x8d, 0xc7, 0x71, 0x3f, 0xe3, 0xbe, 0x0d, 0xa5, 0x8c, 0x2a, 0xc9, + 0x43, 0x1b, 0x47, 0x2d, 0xe3, 0x2d, 0x94, 0x30, 0x2d, 0xb3, 0x95, 0x4f, + 0x6f, 0x73, 0xf3, 0x5f, 0xf7, 0x22, 0x0a, 0xee, 0x65, 0x3b, 0x03, 0xf9, + 0x17, 0x7a, 0xd4, 0xa3, 0x13, 0x39, 0xb1, 0x55, 0x47, 0x16, 0xdc, 0xc1, + 0x55, 0xff, 0x41, 0x1d, 0x70, 0x4f, 0x09, 0xd8, 0x28, 0x53, 0x9c, 0x48, + 0x89, 0x14, 0x32, 0x37, 0xbb, 0x11, 0x1c, 0x00, 0xe5, 0xff, 0xfe, 0x32, + 0x4a, 0x52, 0x9b, 0xc7, 0xdb, 0xda, 0x89, 0x36, 0xe0, 0xd3, 0x62, 0x55, + 0xb3, 0x46, 0xa0, 0xda, 0x31, 0xbe, 0x6e, 0x47, 0xf6, 0x76, 0xe6, 0x6e, + 0x65, 0xc3, 0x91, 0x75, 0x0d, 0x44, 0x08, 0x6d, 0x31, 0x34, 0xc2, 0xe0, + 0x04, 0x55, 0xad, 0x47, 0x90, 0x9b, 0xed, 0x09, 0x15, 0x08, 0xdc, 0xfc, + 0xd9, 0x9c, 0xf9, 0x97, 0x2c, 0xe7, 0xbc, 0x97, 0x75, 0xd1, 0xc9, 0x61, + 0x6a, 0x85, 0xd6, 0xf2, 0xd5, 0x04, 0x0b, 0xa6, 0x37, 0xa5, 0x76, 0x52, + 0x2f, 0x6e, 0x16, 0xe9, 0xe9, 0x4b, 0x40, 0xb6, 0xcc, 0x2d, 0x7e, 0xc4, + 0x61, 0x4f, 0x7d, 0xa0, 0x93, 0xff, 0x85, 0x81, 0xca, 0x16, 0xd9, 0x3a, + 0x1b, 0xb9, 0x64, 0x0a, 0xab, 0x63, 0x67, 0x90, 0xe6, 0xfc, 0xc3, 0xa5, + 0x17, 0x12, 0x10, 0xd0, 0x90, 0xde, 0x84, 0xd3, 0x79, 0x0e, 0xc0, 0xb9, + 0x46, 0x8c, 0x64, 0x00, 0x7f, 0x27, 0x5f, 0x3a, 0x57, 0x86, 0x8f, 0x6a, + 0x37, 0x2e, 0xf5, 0x29, 0x41, 0x11, 0x10, 0xe2, 0x9b, 0x59, 0x67, 0x92, + 0x56, 0xb3, 0xa2, 0x5f, 0x56, 0xfd, 0x4c, 0xda, 0x47, 0xf3, 0x87, 0x82, + 0x38, 0x01, 0xc5, 0xcb, 0x76, 0x80, 0x8a, 0xc3, 0x7c, 0x22, 0xb6, 0xaf, + 0x70, 0x42, 0x00, 0x8d, 0x7b, 0xac, 0x0a, 0x00, 0xa8, 0xce, 0xaa, 0x84, + 0xa9, 0x97, 0xd0, 0xb8, 0xd9, 0xf4, 0x10, 0xbf, 0xc4, 0x02, 0xaa, 0x58, + 0x24, 0xff, 0xde, 0x79, 0x96, 0x12, 0x92, 0xd2, 0x53, 0x77, 0x72, 0xd7, + 0x60, 0x9b, 0x3d, 0x3d, 0xb7, 0x5e, 0x9e, 0x0f, 0xb8, 0x00, 0x30, 0x56, + 0xe8, 0x80, 0x85, 0xff, 0x53, 0x40, 0xe6, 0xef, 0x80, 0x85, 0xff, 0x53, + 0x40, 0xe2, 0x43, 0x7e, 0x50, 0xa0, 0x07, 0xd7, 0x39, 0xa8, 0x13, 0xa2, + 0x6e, 0x3a, 0xf8, 0x99, 0x97, 0x03, 0x06, 0xd6, 0xeb, 0x60, 0x7e, 0xe3, + 0xad, 0xa1, 0x92, 0x81, 0x9b, 0x20, 0x5d, 0xc5, 0x02, 0x9b, 0x9e, 0x5f, + 0x1b, 0xd4, 0xce, 0x22, 0x17, 0x65, 0x00, 0x3d, 0xef, 0xe6, 0x49, 0x60, + 0x65, 0xb2, 0x2f, 0x8a, 0x63, 0x5f, 0x96, 0xd0, 0xfb, 0x43, 0x0b, 0xee, + 0xa6, 0x6a, 0x9c, 0x58, 0xd0, 0xd3, 0x9b, 0x73, 0x9b, 0xb0, 0xf0, 0x39, + 0xbc, 0xe2, 0x4c, 0xfb, 0x91, 0x84, 0x57, 0x48, 0x11, 0x6d, 0xba, 0x1b, + 0x43, 0xc3, 0xda, 0x77, 0x60, 0x89, 0xed, 0x74, 0xf0, 0x1e, 0xf5, 0xce, + 0x07, 0x00, 0x89, 0x06, 0xd3, 0xbc, 0x1b, 0xa2, 0x21, 0x3f, 0xe2, 0x7a, + 0x2b, 0xc3, 0x21, 0x72, 0x9c, 0xd5, 0xbf, 0x00, 0x2a, 0x13, 0xc6, 0xad, + 0x18, 0xaa, 0x61, 0x84, 0x34, 0x28, 0x94, 0xd0, 0xda, 0xd2, 0xdb, 0xc7, + 0xcc, 0x59, 0x72, 0x18, 0x30, 0x68, 0xca, 0x12, 0x8d, 0x5b, 0x83, 0xe6, + 0xe8, 0xc0, 0xca, 0x64, 0x08, 0x2d, 0x15, 0xb6, 0xee, 0xe3, 0xb8, 0x20, + 0xcd, 0xa1, 0x98, 0xb5, 0x03, 0x69, 0x34, 0x35, 0xb1, 0x3f, 0x26, 0xe4, + 0xa5, 0x85, 0x5b, 0x28, 0x0d, 0x58, 0x60, 0x73, 0x76, 0x6a, 0x9b, 0x69, + 0x09, 0xb9, 0x12, 0x63, 0x9d, 0x10, 0x87, 0x4e, 0xf5, 0x6d, 0x99, 0x27, + 0xb3, 0xf2, 0xa3, 0x73, 0xe2, 0xe4, 0xcd, 0x84, 0x35, 0x91, 0x91, 0xf1, + 0x83, 0x9b, 0xba, 0x47, 0xce, 0x31, 0xfe, 0x74, 0x74, 0x4b, 0xb2, 0x25, + 0x38, 0x71, 0xea, 0xdc, 0xc5, 0xb3, 0xdc, 0x0c, 0x41, 0xf4, 0x3a, 0x48, + 0x54, 0x3e, 0x9e, 0x36, 0xd6, 0xe9, 0x5a, 0x6c, 0x75, 0x50, 0x95, 0x83, + 0x7d, 0x5b, 0x6f, 0xde, 0x9b, 0x1c, 0x20, 0x56, 0x40, 0x1e, 0x3d, 0xf8, + 0xff, 0xcb, 0xa1, 0xde, 0x2a, 0xd9, 0xe4, 0x36, 0x65, 0x2f, 0xc2, 0xb7, + 0x87, 0x03, 0x8c, 0x00, 0x18, 0x37, 0x85, 0xe2, 0xbc, 0xfa, 0xe9, 0xcf, + 0xe3, 0x81, 0x98, 0x6d, 0x43, 0x31, 0x10, 0x79, 0x0d, 0xbe, 0x89, 0xf7, + 0xf9, 0x23, 0x7b, 0x91, 0xb1, 0xef, 0xe6, 0x3e, 0x17, 0x45, 0x73, 0x9b, + 0x09, 0xb2, 0x51, 0xd4, 0x61, 0x2d, 0xbc, 0x3f, 0xc7, 0x52, 0x2e, 0xee, + 0x8f, 0xba, 0x56, 0x64, 0x91, 0x0a, 0x38, 0x07, 0xb6, 0xd5, 0x6d, 0xcf, + 0x33, 0xe7, 0xdb, 0xdb, 0x65, 0x43, 0xae, 0x65, 0x0e, 0xdb, 0x6c, 0xa9, + 0x4e, 0xd3, 0x8a, 0x28, 0x63, 0x73, 0x5a, 0x4e, 0x29, 0x42, 0x56, 0x36, + 0x4d, 0xfb, 0xa0, 0x06, 0x3e, 0xd0, 0x8d, 0xf5, 0x76, 0xa7, 0x32, 0x95, + 0x09, 0xd5, 0xee, 0xdc, 0x57, 0x80, 0xac, 0x34, 0x63, 0x0f, 0xf8, 0x03, + 0x51, 0x1f, 0x3d, 0x3b, 0x9e, 0x74, 0x53, 0xec, 0x0f, 0x9c, 0x08, 0xde, + 0x03, 0xc9, 0xf6, 0x16, 0xb1, 0x54, 0xa4, 0x3c, 0x39, 0x8e, 0x7c, 0x8a, + 0x00, 0x45, 0xef, 0x1e, 0x47, 0xe2, 0xf1, 0x88, 0xee, 0x2e, 0x51, 0x77, + 0x9f, 0x2c, 0x7e, 0x97, 0xb5, 0x35, 0x24, 0xb4, 0x60, 0xc5, 0x6f, 0x25, + 0x9c, 0x5f, 0x62, 0x2f, 0xdf, 0xab, 0xe7, 0x64, 0x01, 0x26, 0x3c, 0x8d, + 0x97, 0x5e, 0xe9, 0x56, 0xd3, 0x4c, 0xe4, 0xac, 0xa8, 0x3a, 0xdc, 0x56, + 0x29, 0x65, 0x94, 0x34, 0x6c, 0x3d, 0xaa, 0x94, 0xdf, 0xb3, 0x13, 0xf0, + 0x23, 0x3e, 0xb7, 0x9e, 0x33, 0xb7, 0x6a, 0x21, 0xaf, 0x14, 0xf7, 0x6f, + 0x96, 0x18, 0xa7, 0x4b, 0x12, 0x01, 0x03, 0xaa, 0x36, 0x7f, 0xe8, 0x91, + 0x0e, 0x11, 0x5c, 0x25, 0xfc, 0xb8, 0xeb, 0xc3, 0xf8, 0xce, 0xde, 0xee, + 0x0a, 0xfc, 0xc3, 0xe5, 0x19, 0xad, 0xf1, 0x8e, 0x30, 0x02, 0xde, 0x05, + 0x23, 0x8c, 0x81, 0x9b, 0x20, 0xc2, 0xbf, 0x43, 0xfc, 0x1b, 0xe9, 0x7f, + 0x04, 0x57, 0x80, 0x3d, 0xeb, 0x81, 0x73, 0x45, 0x67, 0xea, 0x3a, 0x75, + 0xbd, 0xcd, 0xcc, 0x85, 0x50, 0x31, 0xe5, 0x4b, 0x95, 0x8e, 0xec, 0xc4, + 0x92, 0x40, 0x9b, 0x16, 0xb6, 0x74, 0x07, 0xed, 0xf4, 0x72, 0x3c, 0x50, + 0xa5, 0xdb, 0x69, 0x5f, 0x9d, 0x97, 0x23, 0xf5, 0xcb, 0x16, 0x7e, 0xcb, + 0xa8, 0x71, 0xcc, 0xa0, 0x0b, 0x7e, 0x1f, 0x2f, 0x4f, 0x8f, 0x83, 0xf2, + 0xe3, 0xdd, 0xae, 0xcd, 0x94, 0xaa, 0x36, 0x0c, 0xb0, 0x7a, 0x37, 0x50, + 0x8b, 0x9d, 0x00, 0x31, 0xea, 0x91, 0xb4, 0x5c, 0x95, 0x30, 0x3b, 0x3e, + 0x9f, 0x57, 0xbb, 0x98, 0x5a, 0x2f, 0x95, 0x87, 0xa8, 0x4a, 0x58, 0x8d, + 0xe5, 0x00, 0x1a, 0x11, 0xbd, 0xb0, 0x57, 0x5c, 0x4c, 0xeb, 0x21, 0x77, + 0xcb, 0x80, 0xc8, 0x34, 0xb4, 0x1b, 0x5b, 0x91, 0xf5, 0x65, 0x52, 0x15, + 0x29, 0x9d, 0xa5, 0xd6, 0xfe, 0xac, 0x47, 0x12, 0x08, 0x5f, 0xdc, 0xf3, + 0x7c, 0x8a, 0xa9, 0xbc, 0x75, 0xb6, 0xa5, 0x8b, 0x68, 0xd0, 0xd4, 0x6e, + 0x37, 0xb7, 0x02, 0x38, 0xe8, 0xcd, 0x74, 0x44, 0x9e, 0x5b, 0x14, 0xf8, + 0xad, 0xe8, 0xc0, 0x15, 0x09, 0xe4, 0x00, 0xac, 0x56, 0x11, 0xc8, 0x95, + 0xe7, 0x4a, 0x01, 0x63, 0x89, 0xcf, 0x7e, 0xb8, 0x11, 0x00, 0x10, 0x6c, + 0x3c, 0xcc, 0x2f, 0xd5, 0xbd, 0x00, 0x01, 0x8f, 0xb7, 0x5e, 0xe2, 0xdd, + 0xd0, 0x93, 0x76, 0xc0, 0x09, 0x97, 0x9e, 0x39, 0xf2, 0x7a, 0x96, 0xe0, + 0x20, 0x30, 0x31, 0xb9, 0xc5, 0x87, 0x49, 0x2c, 0x09, 0x09, 0x8d, 0x3c, + 0x93, 0x12, 0x84, 0xb7, 0xf2, 0x0f, 0x79, 0x3e, 0xb7, 0xe3, 0x1d, 0x64, + 0x0d, 0xd5, 0x32, 0xf8, 0x58, 0xde, 0x97, 0xb1, 0x64, 0x07, 0x5a, 0xe9, + 0x98, 0x12, 0x61, 0xb6, 0xd3, 0xdb, 0xea, 0xa0, 0x05, 0xe2, 0x63, 0xb3, + 0xbb, 0xe7, 0x12, 0x19, 0x9a, 0xec, 0xc7, 0xe8, 0x18, 0x94, 0xfb, 0xe4, + 0xe9, 0x4e, 0xba, 0x91, 0x42, 0x1b, 0xe0, 0xc2, 0x83, 0xa6, 0x6a, 0xe0, + 0xfc, 0x0e, 0xdf, 0xd5, 0x3d, 0xbb, 0x37, 0xf2, 0x5e, 0x2b, 0x1b, 0x92, + 0x6b, 0x00, 0x00, 0x00, 0x01, 0x0f, 0x43, 0xfd, 0x0a, 0x00, 0xf4, 0x58, + 0xaf, 0xbf, 0xbf, 0x02, 0x2d, 0x72, 0xa2, 0x9b, 0x98, 0xeb, 0x6b, 0xe4, + 0xc3, 0x96, 0xc9, 0x0b, 0x46, 0xf4, 0x06, 0xf1, 0xd7, 0x0b, 0xa5, 0x14, + 0x5c, 0xcb, 0xb2, 0x19, 0x4e, 0xa7, 0x97, 0x5b, 0x9b, 0xc3, 0x80, 0x0f, + 0x9f, 0xab, 0x9a, 0xa3, 0x1d, 0xa9, 0x53, 0x2d, 0xc4, 0x52, 0xea, 0x14, + 0xa3, 0x56, 0x37, 0x20, 0x52, 0xe7, 0x31, 0xcf, 0xd3, 0x51, 0x03, 0xf7, + 0xbe, 0x13, 0x2e, 0xd0, 0xc2, 0xc7, 0x51, 0xed, 0xf2, 0x99, 0x52, 0xac, + 0xf0, 0x2d, 0xb8, 0x60, 0xfb, 0x5b, 0xf5, 0x02, 0xaa, 0x6f, 0x36, 0x65, + 0x88, 0x50, 0x74, 0x42, 0x86, 0x9c, 0x1a, 0x81, 0xad, 0xe4, 0x00, 0x1e, + 0x4e, 0xfe, 0x3e, 0xf9, 0x32, 0x45, 0x29, 0x03, 0xae, 0xf9, 0x5d, 0x96, + 0x18, 0x58, 0xf8, 0xbe, 0x0d, 0xe1, 0xc0, 0x17, 0x6f, 0x04, 0x6e, 0x78, + 0x32, 0xe5, 0x5b, 0x53, 0x74, 0x53, 0xcb, 0xc9, 0xa1, 0xf4, 0x39, 0xf2, + 0x17, 0x6c, 0x6d, 0x9f, 0x02, 0xbb, 0xcf, 0xa7, 0xd6, 0xc1, 0x7c, 0x82, + 0x30, 0x02, 0x55, 0x0f, 0x0e, 0x85, 0x00, 0x90, 0xe5, 0xb6, 0x2f, 0x83, + 0x67, 0x31, 0x66, 0x92, 0x55, 0xb9, 0xb0, 0x3a, 0x2b, 0x7f, 0x41, 0xff, + 0x40, 0x03, 0xfe, 0x85, 0xf0, 0xf3, 0x28, 0x23, 0xff, 0xef, 0x0f, 0x0f, + 0xd3, 0x62, 0x8f, 0xa1, 0xa5, 0xb0, 0x14, 0xb8, 0x2a, 0x71, 0xc8, 0x98, + 0x01, 0x2e, 0x6c, 0xd5, 0x74, 0xe3, 0x30, 0xaf, 0x5b, 0x4e, 0x0d, 0x46, + 0xe3, 0xf1, 0x7b, 0xff, 0xd2, 0x29, 0xb5, 0xd0, 0xb3, 0x37, 0xc9, 0xdb, + 0xbc, 0xee, 0x39, 0xe5, 0xee, 0x01, 0x8b, 0x61, 0x34, 0x29, 0xbd, 0x0f, + 0xdf, 0xbd, 0xd8, 0xb8, 0xea, 0x1d, 0x9f, 0x8c, 0xf3, 0xde, 0x7c, 0xa9, + 0xa7, 0x87, 0x45, 0x2c, 0xc3, 0x94, 0x63, 0x6a, 0x64, 0xd5, 0xa8, 0xda, + 0xa4, 0xdc, 0x02, 0xdb, 0xe3, 0xf5, 0xf0, 0xe0, 0x04, 0x80, 0x06, 0xaf, + 0xaf, 0x50, 0x26, 0xf1, 0xbc, 0x4a, 0xe5, 0x85, 0x93, 0x6d, 0x54, 0x50, + 0xb6, 0xfc, 0xff, 0xf5, 0xcc, 0xcb, 0x0c, 0x37, 0xc6, 0x4a, 0xdf, 0xa5, + 0x48, 0xb9, 0xc5, 0x22, 0x7c, 0xf7, 0x95, 0x16, 0xc9, 0xb3, 0x31, 0x0d, + 0xb4, 0xf3, 0xec, 0xb1, 0x56, 0x24, 0x29, 0x5b, 0xe4, 0x80, 0x0d, 0xfe, + 0x01, 0x04, 0x06, 0x7f, 0xb3, 0x39, 0x15, 0xc8, 0xc0, 0xe2, 0x0b, 0x97, + 0xcc, 0xb0, 0x20, 0x29, 0xb0, 0x32, 0x66, 0x3b, 0x25, 0x0a, 0x7b, 0x64, + 0xf9, 0xe5, 0x24, 0x4f, 0x16, 0xfc, 0x30, 0xbd, 0xc0, 0x07, 0x9f, 0xfd, + 0xe7, 0x3c, 0xd4, 0x6a, 0x49, 0x64, 0x32, 0x37, 0x91, 0x22, 0xf7, 0xc1, + 0x17, 0x34, 0x40, 0x8e, 0xea, 0x17, 0x25, 0xe7, 0x16, 0xf3, 0xd6, 0x6c, + 0x35, 0x3c, 0xae, 0x1e, 0xb0, 0xa3, 0x9b, 0xe9, 0xc0, 0x05, 0x70, 0x57, + 0x0f, 0xdf, 0x8f, 0xe4, 0x01, 0xe6, 0x87, 0x1a, 0x5d, 0x94, 0xc9, 0xbe, + 0x5b, 0x96, 0x5b, 0x2c, 0x6f, 0x94, 0x49, 0xf8, 0xf8, 0x9a, 0xa1, 0x73, + 0x9c, 0x36, 0xda, 0x1a, 0x5c, 0x25, 0x37, 0x6e, 0x5a, 0x9f, 0x9a, 0x15, + 0x56, 0x94, 0xcc, 0xfb, 0x1b, 0x0e, 0x96, 0x00, 0x5b, 0x4d, 0xc0, 0x15, + 0xaa, 0x43, 0xc3, 0x21, 0xed, 0x88, 0xae, 0x05, 0x77, 0x00, 0x06, 0x7a, + 0xaa, 0x48, 0x46, 0xfa, 0xaf, 0xbd, 0xd9, 0xfc, 0x12, 0x46, 0xd3, 0x34, + 0x30, 0x0c, 0xf9, 0xfb, 0x66, 0xc0, 0xf3, 0xa6, 0x48, 0x6c, 0x94, 0xa3, + 0xea, 0x37, 0xcd, 0x36, 0xf9, 0xbf, 0x05, 0xe5, 0x08, 0x84, 0x02, 0xb5, + 0xb4, 0x96, 0xdc, 0xc8, 0xbe, 0x87, 0x10, 0xd9, 0xc3, 0x9b, 0xfa, 0x6f, + 0xc0, 0xbf, 0x70, 0x02, 0x3f, 0x69, 0xbd, 0x08, 0xed, 0x41, 0x10, 0x01, + 0x30, 0x51, 0xaa, 0x80, 0x91, 0xff, 0x92, 0xfe, 0xe0, 0xe5, 0xaa, 0xdb, + 0x3f, 0xff, 0x34, 0x01, 0xf6, 0x91, 0x08, 0xc2, 0x62, 0x9f, 0x69, 0xbc, + 0x71, 0xbf, 0x9d, 0x26, 0xd2, 0xad, 0x85, 0x41, 0xad, 0xe4, 0x3b, 0xf8, + 0x04, 0x1f, 0xd9, 0x00, 0x12, 0x00, 0x5b, 0x68, 0x64, 0x36, 0x3c, 0xca, + 0x38, 0x3f, 0xc8, 0xe4, 0xa5, 0xf8, 0x37, 0xe8, 0x2f, 0x91, 0x3b, 0xcf, + 0xb8, 0xb8, 0x06, 0x60, 0xc7, 0x5e, 0xdd, 0xa8, 0x93, 0x53, 0x15, 0x23, + 0xee, 0x20, 0xc2, 0x1b, 0x79, 0xef, 0x90, 0x52, 0x5d, 0xa0, 0x03, 0x46, + 0xca, 0x95, 0x16, 0x7a, 0xb7, 0xf1, 0x30, 0x07, 0x74, 0x10, 0x40, 0x5c, + 0x4f, 0xf7, 0xda, 0x20, 0xf5, 0xcf, 0x7e, 0x9c, 0x1f, 0x6c, 0x2a, 0x9b, + 0x62, 0xac, 0x92, 0xa0, 0xc1, 0xed, 0xf2, 0x8e, 0x13, 0x8b, 0xb7, 0x6f, + 0x81, 0x8b, 0x3c, 0x5b, 0xf4, 0xf9, 0x10, 0x48, 0x20, 0x80, 0xe7, 0xd3, + 0x3e, 0x5d, 0x9c, 0xe9, 0x76, 0xde, 0x36, 0xbf, 0x4d, 0xab, 0x7c, 0xe9, + 0x4b, 0x9a, 0x7a, 0xa5, 0x3d, 0x5b, 0xf3, 0x5f, 0xcc, 0x20, 0x76, 0xf7, + 0x49, 0x7c, 0x26, 0x6d, 0x1f, 0x06, 0x6b, 0x75, 0x17, 0xde, 0x9b, 0xe8, + 0x3e, 0x05, 0xb6, 0xaa, 0xa7, 0xb7, 0xc4, 0xe3, 0x83, 0x76, 0x65, 0x40, + 0x08, 0xee, 0x2b, 0x7b, 0xf8, 0x08, 0x40, 0x15, 0xa2, 0xce, 0x90, 0xf0, + 0x43, 0x00, 0x68, 0x14, 0x79, 0x3e, 0x58, 0x49, 0x6f, 0x17, 0x26, 0xf9, + 0xe1, 0x6a, 0x3b, 0xf3, 0x6b, 0xac, 0xf0, 0xa0, 0x6d, 0xbd, 0xc6, 0x4b, + 0xd0, 0x81, 0x32, 0x5a, 0x11, 0x1d, 0xc6, 0x85, 0x02, 0x27, 0xfd, 0x6a, + 0xfa, 0x48, 0xde, 0xb5, 0x0f, 0x6f, 0x41, 0x49, 0xe0, 0x73, 0x74, 0x71, + 0x9c, 0xce, 0xdd, 0xf8, 0xa1, 0x7e, 0xdb, 0xef, 0xc8, 0x4d, 0x59, 0xb3, + 0x56, 0xc1, 0xc9, 0x2c, 0xad, 0x81, 0xe6, 0x68, 0xbf, 0x7f, 0x6d, 0x81, + 0x59, 0xf3, 0x5d, 0xbc, 0x51, 0xc1, 0xc6, 0x58, 0x78, 0x49, 0x4c, 0xfd, + 0x3a, 0xd1, 0x5c, 0x77, 0x65, 0x83, 0x03, 0xbf, 0x92, 0xcd, 0xb0, 0xf3, + 0xf7, 0x39, 0x59, 0x00, 0x46, 0x5a, 0xb6, 0xbd, 0xc7, 0x89, 0xeb, 0xef, + 0xca, 0xe5, 0x5a, 0x56, 0xe0, 0x87, 0x88, 0xc7, 0xe4, 0x3c, 0x02, 0x57, + 0x6e, 0xfa, 0x16, 0xda, 0xb7, 0x54, 0x6f, 0x9b, 0x43, 0xde, 0x2a, 0xf8, + 0xc3, 0x62, 0x14, 0x12, 0x91, 0xbd, 0x35, 0xda, 0x44, 0x30, 0xcd, 0xf4, + 0xd7, 0xd2, 0xbd, 0x2a, 0x92, 0xdb, 0x83, 0xdc, 0xb9, 0x5d, 0x73, 0x9a, + 0x3e, 0x58, 0xf7, 0xdd, 0x88, 0x4c, 0x38, 0xb1, 0x81, 0x55, 0xba, 0x76, + 0x00, 0x1b, 0x07, 0x27, 0x8e, 0xf9, 0xd4, 0x1a, 0x73, 0x65, 0x5b, 0xa0, + 0xf5, 0x6f, 0x90, 0x58, 0xa3, 0x0b, 0xf5, 0x83, 0x82, 0xd4, 0x84, 0xc7, + 0x7f, 0x39, 0x0b, 0xf5, 0x80, 0x7c, 0x6b, 0xea, 0x67, 0x56, 0xcb, 0x68, + 0x61, 0xb8, 0x97, 0x4a, 0x1c, 0xa3, 0xce, 0x68, 0xf7, 0x57, 0xd8, 0xf8, + 0x81, 0xa9, 0x9a, 0x51, 0x0d, 0x19, 0x1c, 0xc1, 0xe8, 0xde, 0x19, 0x08, + 0x19, 0x14, 0xb0, 0x98, 0x9b, 0xe8, 0x39, 0xb9, 0xcf, 0x2b, 0x70, 0x95, + 0x28, 0xc0, 0xa0, 0xd6, 0xed, 0x2b, 0xde, 0xf9, 0x66, 0x21, 0xe0, 0x88, + 0x00, 0x95, 0x54, 0x2a, 0x61, 0xed, 0xc0, 0x2b, 0x08, 0x13, 0x3d, 0x75, + 0x2c, 0x24, 0xc6, 0x9a, 0xca, 0x14, 0x07, 0x37, 0xf6, 0x90, 0x02, 0x5f, + 0x20, 0x02, 0xd0, 0x06, 0xd3, 0xd9, 0xdb, 0x68, 0x0f, 0x7b, 0x27, 0xf0, + 0xfc, 0xe2, 0x4a, 0xb7, 0xf7, 0x76, 0x67, 0x85, 0xb1, 0xbd, 0x4f, 0x6f, + 0xd0, 0x40, 0x03, 0x9e, 0x78, 0x9b, 0xba, 0xa3, 0x41, 0x0b, 0xfd, 0x67, + 0x3a, 0x78, 0x4e, 0x6c, 0x5b, 0x7c, 0x63, 0x7d, 0x7b, 0xeb, 0x01, 0x07, + 0xf9, 0x7f, 0xff, 0x57, 0xeb, 0xac, 0x02, 0x7c, 0xec, 0xde, 0x1f, 0x83, + 0x0e, 0x5c, 0xd9, 0x24, 0x81, 0x8d, 0xf3, 0x90, 0x02, 0x3f, 0xf0, 0x81, + 0x00, 0x0d, 0xb3, 0xe3, 0xec, 0xfe, 0x51, 0x4c, 0x7f, 0x3d, 0x75, 0x90, + 0x9f, 0xce, 0xca, 0x86, 0x9b, 0x69, 0x85, 0xaa, 0x54, 0x34, 0x73, 0x46, + 0xda, 0xba, 0x57, 0x81, 0x88, 0xde, 0x5e, 0xae, 0x2a, 0x92, 0x9b, 0xf8, + 0x90, 0x02, 0x12, 0x33, 0xc0, 0x1d, 0x80, 0x36, 0x7c, 0x17, 0x2c, 0x1b, + 0x25, 0xeb, 0x9b, 0x24, 0xfd, 0xc2, 0xb4, 0x6c, 0xc1, 0xcd, 0xc9, 0xfa, + 0xf5, 0xbf, 0x04, 0x5e, 0x05, 0xf5, 0xcc, 0x3a, 0xa6, 0xe4, 0x78, 0x75, + 0x18, 0x3e, 0x58, 0xdf, 0xba, 0x3e, 0x5f, 0x48, 0xbf, 0x7f, 0x71, 0x7d, + 0xdd, 0x1b, 0x4b, 0xe7, 0x9b, 0xa6, 0x0c, 0xfd, 0x69, 0xd2, 0x05, 0x37, + 0xe6, 0xbf, 0xee, 0x02, 0x08, 0x16, 0x0b, 0xff, 0x74, 0x81, 0x5b, 0xc0, + 0xa3, 0x2f, 0x86, 0xdb, 0x6c, 0x21, 0xd6, 0xe7, 0xa8, 0xed, 0xb0, 0x96, + 0x3d, 0xb0, 0xdf, 0xc5, 0xad, 0xfc, 0x61, 0xe0, 0x63, 0x32, 0x90, 0xed, + 0x6d, 0x7e, 0xdb, 0xa0, 0x0c, 0x1d, 0xf7, 0x16, 0xb2, 0x06, 0x4f, 0xe8, + 0x92, 0xb2, 0xd0, 0xc2, 0x07, 0x19, 0x8b, 0xeb, 0x5b, 0xec, 0x80, 0x0b, + 0x5d, 0xef, 0xcf, 0xd8, 0x01, 0xcd, 0x17, 0x2a, 0x93, 0x60, 0x87, 0x11, + 0xcc, 0xe9, 0xd6, 0xa7, 0xe2, 0xcd, 0x7f, 0x12, 0x52, 0x86, 0x8c, 0xd6, + 0xf1, 0x20, 0x05, 0xa2, 0x27, 0xb8, 0x02, 0xa1, 0x64, 0x1d, 0xd3, 0x83, + 0x93, 0xe0, 0x5e, 0xe5, 0xca, 0x34, 0x3b, 0x69, 0x25, 0x2b, 0x67, 0x3f, + 0x25, 0x4f, 0x11, 0xed, 0x16, 0x0d, 0x24, 0x37, 0xf1, 0x28, 0x08, 0x5f, + 0xef, 0x38, 0x8b, 0xe3, 0x2d, 0xa4, 0xa8, 0xdd, 0xdf, 0x28, 0x00, 0xee, + 0x8a, 0xc0, 0x4c, 0x00, 0x3a, 0xa9, 0xea, 0xdc, 0xfe, 0xf1, 0xf4, 0x5e, + 0x72, 0xe7, 0xca, 0x36, 0x57, 0x2e, 0x6c, 0xb0, 0x22, 0x95, 0x5b, 0xed, + 0x40, 0x04, 0xa2, 0xa8, 0x01, 0x79, 0x1b, 0x31, 0xcf, 0x01, 0x13, 0xec, + 0x48, 0xa3, 0x29, 0x6a, 0x32, 0xb6, 0x8e, 0xa4, 0x0d, 0x7d, 0x21, 0x58, + 0xca, 0x94, 0x5b, 0x7b, 0xf9, 0x76, 0xfb, 0xc0, 0x06, 0x25, 0x06, 0x5b, + 0x3e, 0x84, 0xe9, 0xc4, 0x18, 0x4d, 0x59, 0xab, 0x42, 0x92, 0x37, 0x80, + 0x00, 0x77, 0xf0, 0x2f, 0x3d, 0xc5, 0xf5, 0xc3, 0xf8, 0xd8, 0xb2, 0xe4, + 0x7b, 0xf2, 0x6a, 0x51, 0x95, 0x06, 0x5f, 0x16, 0xfa, 0xc7, 0xd3, 0xbd, + 0xe0, 0x8b, 0xec, 0x27, 0xe6, 0x0e, 0x0e, 0xb9, 0xde, 0x57, 0x39, 0x69, + 0x51, 0x2d, 0xa5, 0x14, 0xd8, 0xa5, 0xc0, 0x06, 0x40, 0x0f, 0x1f, 0xf1, + 0x40, 0x2c, 0xc2, 0xd3, 0x2b, 0xb8, 0x7a, 0xe7, 0x9d, 0xbe, 0x7a, 0x36, + 0x16, 0x43, 0xad, 0xe3, 0xf5, 0x7c, 0xf5, 0x66, 0xc0, 0xca, 0xb9, 0x02, + 0xdb, 0x29, 0x4e, 0x46, 0xfe, 0x72, 0xe7, 0x4d, 0x00, 0xb3, 0x2c, 0xf0, + 0xef, 0x61, 0xa0, 0x97, 0xff, 0xb6, 0x2a, 0x05, 0xb7, 0xea, 0x88, 0x21, + 0xd8, 0x2b, 0xdb, 0x9e, 0x08, 0x0a, 0x02, 0x5d, 0xe6, 0xb8, 0xf9, 0x0a, + 0xa5, 0x0c, 0x2c, 0x7b, 0x7e, 0x5a, 0x9a, 0x01, 0x5c, 0xe2, 0x60, 0x04, + 0x22, 0xf7, 0x24, 0x21, 0xa4, 0x6f, 0xd3, 0xe0, 0x0f, 0x81, 0x0b, 0xfd, + 0x33, 0x9b, 0x6b, 0xc6, 0xc4, 0x90, 0x99, 0x92, 0x87, 0x86, 0x5b, 0xb5, + 0x59, 0x65, 0x20, 0x13, 0xac, 0xb0, 0x34, 0x3c, 0xf9, 0x5a, 0xf2, 0xcd, + 0x4a, 0xad, 0xf4, 0x12, 0x7c, 0x11, 0x7b, 0xcb, 0x8e, 0xb2, 0x9a, 0xeb, + 0x21, 0xa9, 0x12, 0x87, 0xe2, 0xee, 0xcb, 0x55, 0x15, 0x46, 0xb7, 0xe6, + 0x71, 0x1e, 0xcf, 0xf8, 0x00, 0x71, 0xd7, 0xb6, 0x3d, 0x60, 0xd0, 0x42, + 0x00, 0x69, 0x69, 0x48, 0x51, 0x61, 0xf6, 0xac, 0x85, 0x1e, 0x5b, 0x7d, + 0xcf, 0xe4, 0x89, 0xc0, 0x03, 0x0e, 0xe3, 0x9f, 0xb2, 0x29, 0xab, 0xc0, + 0x01, 0xec, 0x27, 0xe6, 0xeb, 0xcf, 0x44, 0xb0, 0xb8, 0x91, 0x1b, 0xd7, + 0xfd, 0xfd, 0xde, 0x00, 0xdf, 0xe6, 0x13, 0xd7, 0xf5, 0x09, 0xde, 0x46, + 0xd3, 0x2d, 0x2f, 0x7f, 0x6a, 0x64, 0x50, 0xe3, 0x8b, 0x6e, 0x9b, 0x2f, + 0x2f, 0xc3, 0x28, 0x00, 0xd0, 0xf5, 0x6e, 0x8a, 0x54, 0x95, 0x58, 0x00, + 0x00, 0x01, 0xb7 +}; + +void +mpeg2_get_video_info (VideoDecodeInfo * info) +{ + info->profile = GST_VAAPI_PROFILE_MPEG2_SIMPLE; + info->width = MPEG2_CLIP_WIDTH; + info->height = MPEG2_CLIP_HEIGHT; + info->data = mpeg2_clip; + info->data_size = MPEG2_CLIP_DATA_SIZE; +} diff --git a/tests/internal/test-mpeg2.h b/tests/internal/test-mpeg2.h new file mode 100644 index 0000000000..ba21d0f6f4 --- /dev/null +++ b/tests/internal/test-mpeg2.h @@ -0,0 +1,31 @@ +/* + * test-mpeg2.h - MPEG-2 test data + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * + * 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 TEST_MPEG2_H +#define TEST_MPEG2_H + +#include +#include "test-decode.h" + +void mpeg2_get_video_info(VideoDecodeInfo *info); + +#endif /* TEST_MPEG2_H */ diff --git a/tests/internal/test-mpeg4.c b/tests/internal/test-mpeg4.c new file mode 100644 index 0000000000..270359b47e --- /dev/null +++ b/tests/internal/test-mpeg4.c @@ -0,0 +1,1674 @@ +/* + * test-mpeg4.c - MPEG-4 test data + * + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "test-mpeg4.h" + +#define MPEG4_CLIP_WIDTH 320 +#define MPEG4_CLIP_HEIGHT 240 +#define MPEG4_CLIP_DATA_SIZE 19592 + +/* Data dump of a 320x240 MPEG-4 video clip (mpeg4.m4v), it has a single frame */ +static const guchar mpeg4_clip[MPEG4_CLIP_DATA_SIZE] = { + 0x00, 0x00, 0x01, 0xb0, 0x01, 0x00, 0x00, 0x01, 0xb5, 0x89, 0x13, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0xc4, 0x8d, 0x88, 0x00, + 0xcd, 0x0a, 0x04, 0x1e, 0x14, 0x43, 0x00, 0x00, 0x01, 0xb2, 0x4c, 0x61, + 0x76, 0x63, 0x35, 0x34, 0x2e, 0x36, 0x32, 0x2e, 0x31, 0x30, 0x30, 0x00, + 0x00, 0x01, 0xb3, 0x00, 0x10, 0x07, 0x00, 0x00, 0x01, 0xb6, 0x10, 0x60, + 0x85, 0x85, 0x41, 0x08, 0x78, 0xab, 0x44, 0x81, 0x29, 0x06, 0xd1, 0xd2, + 0x4d, 0xe9, 0x2d, 0x55, 0xe0, 0x95, 0x36, 0x42, 0x10, 0x71, 0xfc, 0xa0, + 0x4f, 0x8b, 0x9a, 0x0a, 0xd8, 0x84, 0xca, 0x81, 0x18, 0x48, 0x80, 0xf0, + 0xd0, 0x0b, 0x97, 0x12, 0x83, 0x01, 0x47, 0x13, 0x97, 0x59, 0xfe, 0x22, + 0x5b, 0x9d, 0x88, 0xfb, 0x38, 0x46, 0x2e, 0x29, 0x11, 0x39, 0xb3, 0x7a, + 0x08, 0x02, 0x5f, 0x16, 0xf6, 0x52, 0x8d, 0x3e, 0x33, 0x2f, 0x12, 0x04, + 0xb5, 0x5d, 0xa0, 0x88, 0xcd, 0xe2, 0xeb, 0x7a, 0xd9, 0xc0, 0x61, 0x30, + 0xbd, 0x4e, 0xce, 0x8a, 0xb8, 0xe6, 0xbf, 0x14, 0x43, 0xed, 0x8d, 0xd8, + 0x4d, 0x74, 0x47, 0x69, 0x5b, 0x23, 0x9c, 0xb5, 0xad, 0x82, 0x06, 0xfb, + 0xfe, 0x9d, 0xec, 0x5d, 0x70, 0x49, 0x0b, 0xca, 0x95, 0x5f, 0xb3, 0xec, + 0x0e, 0x6c, 0x0c, 0xdc, 0x68, 0x7b, 0xfc, 0x0f, 0xad, 0xbe, 0xcd, 0xd2, + 0x58, 0xbf, 0x38, 0x4e, 0x30, 0x2e, 0x49, 0x7c, 0x95, 0x52, 0xb9, 0x3a, + 0xc2, 0xfa, 0x69, 0x46, 0xf1, 0x14, 0x0e, 0x48, 0xd3, 0xa5, 0xa0, 0xc2, + 0x6f, 0x29, 0x19, 0x61, 0x21, 0xaf, 0x0e, 0x32, 0x79, 0x06, 0x49, 0x06, + 0x10, 0xf1, 0xb1, 0xef, 0x51, 0xf3, 0xa7, 0x14, 0x0f, 0xf2, 0x90, 0xaa, + 0x3d, 0xde, 0xcb, 0x20, 0x71, 0xd1, 0x35, 0x30, 0x86, 0xc3, 0x21, 0x7f, + 0xff, 0x70, 0xd2, 0xf4, 0x96, 0xac, 0xb1, 0x19, 0xff, 0x5f, 0xfe, 0xf3, + 0x0a, 0xc3, 0x94, 0x0b, 0x10, 0xe6, 0xe7, 0x55, 0x54, 0x36, 0x6d, 0x2a, + 0x35, 0x2d, 0x27, 0xa9, 0xd9, 0xb3, 0x7c, 0x37, 0x71, 0x85, 0x96, 0x2c, + 0x2e, 0xdc, 0x6a, 0xd9, 0x9c, 0x51, 0xfe, 0x4a, 0x8a, 0xd2, 0x90, 0x13, + 0x02, 0x19, 0x72, 0x86, 0x33, 0xf9, 0x11, 0x0c, 0x77, 0x2f, 0x57, 0x79, + 0xc6, 0x9b, 0x2b, 0x8a, 0x79, 0x36, 0xf0, 0xa9, 0x15, 0xa4, 0xae, 0x11, + 0x0e, 0x73, 0xe5, 0xca, 0x35, 0x74, 0x03, 0x2a, 0x41, 0x9b, 0xab, 0x53, + 0xe5, 0x9e, 0x11, 0x8b, 0x69, 0x7b, 0x45, 0x9a, 0xa2, 0x94, 0xf2, 0x14, + 0x50, 0x5b, 0x0a, 0x1b, 0x4a, 0x9e, 0xdd, 0x6b, 0x53, 0x52, 0xcf, 0x23, + 0x57, 0x37, 0xca, 0x0d, 0x2c, 0x0b, 0x50, 0xc7, 0x60, 0xe3, 0xf6, 0x44, + 0x1a, 0x1e, 0x0d, 0x4a, 0x79, 0xa9, 0x8c, 0x66, 0xed, 0x2a, 0x6f, 0x23, + 0x73, 0x39, 0x6d, 0x5e, 0x77, 0xa1, 0xa6, 0x1f, 0xdb, 0xe8, 0x0c, 0x97, + 0x8b, 0x38, 0xd6, 0xfd, 0x5e, 0x16, 0x7a, 0x67, 0x77, 0xb7, 0xab, 0x0a, + 0x46, 0xfb, 0xf1, 0x05, 0x62, 0xcd, 0xc2, 0xec, 0x11, 0x14, 0xa8, 0xa2, + 0x07, 0x39, 0xdb, 0x03, 0x96, 0x74, 0xa8, 0x18, 0x4e, 0x3f, 0x12, 0x53, + 0xff, 0xff, 0x9e, 0xff, 0xc1, 0x59, 0x9a, 0x1e, 0x68, 0x89, 0xbf, 0x5d, + 0x7e, 0x08, 0xba, 0xa4, 0x3a, 0xc0, 0x62, 0x0a, 0xd6, 0x94, 0xb5, 0x3d, + 0x2d, 0x62, 0x4b, 0x3f, 0x57, 0xed, 0x05, 0x7f, 0xfe, 0x1e, 0x29, 0x0d, + 0x00, 0xa7, 0x4c, 0xe6, 0x16, 0xd7, 0x96, 0x5a, 0x6f, 0xae, 0x35, 0xcc, + 0xcf, 0x4b, 0xb9, 0x1a, 0x5b, 0xb5, 0x44, 0x0e, 0xcb, 0x20, 0x71, 0x9c, + 0x50, 0xa4, 0x18, 0x84, 0xaa, 0x0b, 0xea, 0xb5, 0xa3, 0x3e, 0x14, 0x82, + 0xdd, 0x14, 0x8a, 0x38, 0xb0, 0x7b, 0xf5, 0x11, 0x42, 0x91, 0xbd, 0xec, + 0x96, 0x9e, 0x68, 0xba, 0xa6, 0xdb, 0xb4, 0xd0, 0xd8, 0xa6, 0x86, 0xea, + 0x01, 0xf3, 0x7f, 0xfb, 0xd8, 0xf9, 0x68, 0xe5, 0x51, 0xd5, 0x3d, 0xe6, + 0x62, 0xeb, 0x95, 0x71, 0xd5, 0x69, 0x6a, 0x8d, 0x8b, 0x29, 0x47, 0x10, + 0xd8, 0x0c, 0x0b, 0xab, 0x68, 0x71, 0xf6, 0xa7, 0x17, 0x9d, 0xa8, 0xca, + 0xed, 0xe2, 0xcb, 0xbd, 0x3a, 0xb5, 0x86, 0x94, 0x48, 0x50, 0x73, 0xcf, + 0xb6, 0x70, 0x4b, 0xfe, 0xb4, 0xab, 0x6b, 0x19, 0x9a, 0xda, 0x89, 0x3d, + 0x9b, 0xd9, 0x2d, 0xb7, 0x8b, 0xd0, 0xd0, 0xf9, 0xa6, 0x81, 0xba, 0x59, + 0x39, 0x33, 0xb0, 0xa8, 0xb2, 0x95, 0xd9, 0x10, 0x2e, 0x0c, 0x13, 0x48, + 0xee, 0x96, 0x0e, 0x2d, 0xcb, 0x71, 0x72, 0xb8, 0xba, 0xf5, 0x01, 0xea, + 0xc6, 0x7a, 0xdc, 0xf7, 0x91, 0xe8, 0xc0, 0x4e, 0x92, 0x75, 0xc2, 0xf9, + 0x42, 0xc6, 0xd8, 0xf7, 0xea, 0xc1, 0x13, 0x14, 0xdc, 0x94, 0xb6, 0x4d, + 0x99, 0x9c, 0xbc, 0x2c, 0x5d, 0x71, 0x38, 0xc7, 0xe9, 0x44, 0x05, 0x0d, + 0x30, 0x1d, 0xad, 0x3a, 0x13, 0x17, 0x65, 0x36, 0xf0, 0xaf, 0x67, 0xed, + 0x83, 0x6e, 0x2c, 0x50, 0x7d, 0x3c, 0x1f, 0x2a, 0x03, 0x6d, 0x0e, 0x6e, + 0xe2, 0xea, 0x79, 0x50, 0xea, 0x38, 0xe1, 0x6f, 0x7f, 0xde, 0x9c, 0x32, + 0x99, 0xb0, 0x9d, 0xb1, 0x73, 0x03, 0xc2, 0xf0, 0xfe, 0x07, 0xaa, 0x64, + 0xf6, 0x29, 0xd4, 0x59, 0x10, 0xd9, 0x20, 0x8b, 0xaa, 0x6b, 0xc2, 0xfb, + 0x4d, 0x07, 0x85, 0x9d, 0xee, 0x76, 0xd3, 0x53, 0xb5, 0x15, 0x78, 0x97, + 0xd7, 0xeb, 0x20, 0xe8, 0x2e, 0x53, 0xcb, 0xc8, 0x74, 0x62, 0xea, 0x9b, + 0x4e, 0x53, 0xe5, 0x9b, 0xaa, 0x19, 0x2d, 0xcd, 0xf4, 0x2d, 0x6b, 0x6a, + 0xe6, 0xf8, 0xa6, 0x5b, 0x41, 0x6e, 0x36, 0xd6, 0xcb, 0x3f, 0xdf, 0x87, + 0x41, 0xd5, 0x43, 0xab, 0xd5, 0xb8, 0x1b, 0x29, 0x3c, 0x7d, 0x2f, 0xef, + 0x59, 0xbe, 0xe7, 0x4b, 0x7f, 0xce, 0xac, 0x8a, 0xdd, 0x3c, 0x74, 0x42, + 0x2f, 0x64, 0x47, 0xf3, 0x3a, 0xad, 0x55, 0x85, 0x89, 0x59, 0x6b, 0x25, + 0x97, 0x30, 0xb3, 0xd5, 0x6a, 0x56, 0x0e, 0x05, 0x48, 0x24, 0x36, 0x79, + 0x34, 0x43, 0x30, 0xcc, 0x56, 0x9d, 0x6d, 0xbb, 0x33, 0x17, 0xb2, 0x73, + 0x90, 0x92, 0x43, 0xc2, 0xba, 0x47, 0x98, 0x9d, 0x67, 0x03, 0x47, 0xe2, + 0xb5, 0xad, 0xb3, 0xe5, 0xdb, 0x62, 0x37, 0xea, 0x6e, 0x45, 0x84, 0xc3, + 0x05, 0x2b, 0x09, 0xdd, 0x93, 0x38, 0xde, 0xf1, 0xb8, 0x81, 0x15, 0xe8, + 0x9c, 0xa0, 0x22, 0xa3, 0xef, 0x50, 0xa8, 0x19, 0x10, 0xac, 0xad, 0x7d, + 0xce, 0x8a, 0x8f, 0x9f, 0x4a, 0x89, 0xd1, 0xb3, 0x2d, 0xb7, 0xdb, 0xda, + 0x48, 0x35, 0x32, 0xcb, 0x30, 0xf0, 0xec, 0x1a, 0x97, 0x8e, 0xd3, 0x09, + 0x1b, 0xf1, 0x22, 0x75, 0x5e, 0x37, 0xe1, 0x10, 0x73, 0x4b, 0x0a, 0xe5, + 0xb3, 0xc1, 0xc9, 0x10, 0x64, 0xc0, 0x64, 0xad, 0x52, 0xc6, 0x0b, 0xfb, + 0xef, 0xff, 0xd8, 0x5b, 0xf8, 0x36, 0x9b, 0x62, 0xf3, 0xf0, 0x44, 0x01, + 0x36, 0x1b, 0x05, 0xa4, 0x3e, 0xd8, 0x30, 0xc1, 0x4a, 0x0c, 0x39, 0x03, + 0x7f, 0x56, 0x3c, 0x56, 0x55, 0xbd, 0x05, 0x62, 0xca, 0x51, 0xea, 0xf0, + 0xa8, 0xe8, 0xcd, 0x26, 0x83, 0x37, 0x9b, 0x8a, 0xf1, 0xbb, 0xe4, 0x41, + 0xdf, 0xfd, 0x32, 0xc4, 0x7c, 0xb2, 0x07, 0x20, 0xc2, 0x65, 0xc4, 0xb1, + 0xdb, 0x71, 0xbc, 0x03, 0x4a, 0xb5, 0x29, 0x68, 0xdb, 0x73, 0xb7, 0x38, + 0x8a, 0x71, 0x40, 0x9a, 0xfe, 0x90, 0x14, 0x25, 0xe1, 0xea, 0xec, 0x4e, + 0xad, 0x85, 0xb1, 0xae, 0x0c, 0x94, 0xa9, 0x06, 0x1a, 0x94, 0xde, 0xb5, + 0x78, 0x1e, 0xff, 0x41, 0x85, 0x4d, 0xbc, 0x36, 0x2d, 0x6c, 0x2f, 0x30, + 0x0c, 0xc8, 0x8e, 0xc6, 0xcf, 0x0f, 0x44, 0x60, 0x30, 0x8a, 0xab, 0x4d, + 0x6e, 0xce, 0x9b, 0xe6, 0x88, 0x84, 0x62, 0xf6, 0x41, 0x46, 0xd0, 0xe1, + 0xb4, 0xfe, 0x67, 0x2f, 0x98, 0xca, 0xa7, 0x14, 0xcb, 0xaa, 0x78, 0x86, + 0x08, 0x80, 0x24, 0x39, 0x27, 0x08, 0x41, 0x05, 0x89, 0x59, 0xfc, 0xff, + 0xd6, 0xee, 0xee, 0x33, 0x7f, 0x78, 0x6e, 0x95, 0xa9, 0x3c, 0x33, 0xc5, + 0x37, 0x7a, 0xbe, 0xd1, 0x9b, 0xc6, 0x54, 0x9e, 0x72, 0xd1, 0x51, 0x69, + 0x0e, 0xbd, 0x28, 0x84, 0x10, 0xaf, 0x3b, 0x41, 0x8b, 0x07, 0x83, 0x28, + 0x08, 0x82, 0xc4, 0xd5, 0x31, 0x37, 0xbb, 0x37, 0x96, 0x6f, 0x22, 0xdd, + 0x5a, 0x23, 0x71, 0x92, 0xe4, 0xaa, 0x44, 0x81, 0x19, 0xaf, 0x49, 0x14, + 0x0e, 0x87, 0x92, 0xd4, 0x36, 0xc5, 0x5e, 0x71, 0x75, 0x58, 0xa1, 0xac, + 0x95, 0x65, 0xa7, 0x45, 0x3f, 0x11, 0x3a, 0xd6, 0xff, 0x31, 0xab, 0x9a, + 0xbf, 0x46, 0x47, 0x15, 0x61, 0x4f, 0x2d, 0x40, 0x0b, 0xf9, 0xb7, 0x0a, + 0x4f, 0x25, 0x6c, 0xe2, 0x94, 0x50, 0x17, 0xdb, 0x36, 0x74, 0x77, 0xa5, + 0xab, 0x01, 0x00, 0xa1, 0x11, 0xe3, 0x2a, 0x58, 0xe7, 0x60, 0x79, 0x6b, + 0x91, 0xa9, 0xb1, 0x47, 0xd9, 0xb0, 0xae, 0xf4, 0x65, 0xda, 0xb0, 0x30, + 0xd0, 0xc1, 0x77, 0xe7, 0x76, 0x72, 0x42, 0xde, 0x02, 0x3c, 0xec, 0xaf, + 0x63, 0x15, 0xd6, 0x7b, 0x76, 0x64, 0x0b, 0x55, 0xd5, 0xf7, 0x88, 0x05, + 0xe4, 0xae, 0x7f, 0xc5, 0x2c, 0x5c, 0x24, 0x5c, 0x50, 0x6f, 0x5b, 0x9e, + 0x37, 0x78, 0x13, 0x44, 0x6c, 0x56, 0xdf, 0xbd, 0xc5, 0x05, 0x85, 0x55, + 0x62, 0x61, 0xef, 0xd5, 0x28, 0xbb, 0x37, 0x2e, 0x59, 0x69, 0x47, 0x0d, + 0x9f, 0xa8, 0x24, 0xaa, 0xe4, 0x52, 0xa6, 0x5e, 0xc4, 0x04, 0x22, 0xd4, + 0xac, 0xe7, 0xf2, 0xdb, 0x17, 0xfd, 0xf1, 0x66, 0xdc, 0xea, 0xd3, 0xb9, + 0xc0, 0x71, 0x98, 0x46, 0x6a, 0x9e, 0x1f, 0x6f, 0xd1, 0xe6, 0xff, 0xca, + 0x51, 0x07, 0x14, 0x84, 0x32, 0xa5, 0xfb, 0x75, 0x57, 0x35, 0x7d, 0x63, + 0x64, 0xa8, 0x2f, 0x10, 0x57, 0x1c, 0x6e, 0x2b, 0xf7, 0xfc, 0x58, 0xa5, + 0xb6, 0x24, 0x91, 0x9c, 0x35, 0x40, 0x88, 0x64, 0x0c, 0x35, 0x54, 0x7b, + 0x26, 0x7f, 0x39, 0x24, 0x53, 0xe2, 0xb2, 0x83, 0x4f, 0x48, 0x71, 0x0f, + 0xb7, 0x23, 0xef, 0xfb, 0xf6, 0x36, 0x97, 0x4a, 0xa7, 0xf1, 0x4d, 0x24, + 0x8b, 0x2e, 0x0c, 0x12, 0xda, 0x56, 0xf5, 0x4e, 0xea, 0x9c, 0x8a, 0x8b, + 0x20, 0xe3, 0x8b, 0xad, 0xc5, 0xb9, 0x04, 0x55, 0x38, 0x09, 0x63, 0x6f, + 0xf7, 0xca, 0x73, 0x06, 0xc5, 0xa8, 0x91, 0xce, 0x71, 0x60, 0xcc, 0x18, + 0x2a, 0x1f, 0x88, 0xcd, 0xff, 0xea, 0xa7, 0xa1, 0x5f, 0xfc, 0x06, 0x27, + 0x44, 0x46, 0x2a, 0xf3, 0xe0, 0x49, 0x6c, 0x13, 0xcf, 0xe1, 0x11, 0x82, + 0xd2, 0xe2, 0x30, 0x39, 0xb5, 0x0c, 0x9d, 0x52, 0xa6, 0x2f, 0x2c, 0xa8, + 0xbb, 0xaa, 0x77, 0x1a, 0xc1, 0xb2, 0x8c, 0x06, 0x23, 0x45, 0xb9, 0xa8, + 0x91, 0xcb, 0x2c, 0xf7, 0x8b, 0x24, 0x9d, 0x06, 0x37, 0xf0, 0xd3, 0x01, + 0x82, 0x91, 0x59, 0x67, 0xa4, 0xcc, 0xfc, 0xcd, 0xb4, 0x45, 0x11, 0x25, + 0x46, 0x88, 0x2d, 0x31, 0x7d, 0x0a, 0xa2, 0x35, 0xb9, 0x6a, 0xeb, 0x40, + 0x26, 0x28, 0x34, 0xc7, 0xde, 0x49, 0x51, 0xc4, 0x5f, 0xee, 0x14, 0x53, + 0x88, 0x6a, 0xd1, 0x4a, 0xf6, 0x02, 0xa1, 0x75, 0xcd, 0x1e, 0xea, 0x24, + 0xf1, 0x42, 0xc4, 0xab, 0x1c, 0x36, 0xce, 0x6f, 0x5a, 0xa5, 0xab, 0xfb, + 0xb6, 0x48, 0x55, 0x6a, 0xcb, 0x2c, 0x22, 0xa1, 0x06, 0x1a, 0xf0, 0xbf, + 0x2e, 0x20, 0x40, 0x72, 0x7d, 0xea, 0xde, 0x8c, 0x46, 0x88, 0xb1, 0x6e, + 0xe1, 0x5f, 0xb9, 0x56, 0xea, 0x0d, 0x29, 0x80, 0xb5, 0x22, 0x91, 0x6c, + 0xbf, 0x36, 0xb0, 0x9b, 0x90, 0xe9, 0x40, 0xa3, 0xea, 0xb3, 0xed, 0x4f, + 0x54, 0x73, 0x85, 0x22, 0x61, 0xc0, 0xe2, 0xa6, 0x6e, 0x95, 0x41, 0xc8, + 0x89, 0xf0, 0xcc, 0x11, 0xf0, 0xfa, 0x25, 0x87, 0x61, 0xdb, 0xb7, 0xd1, + 0xb5, 0x7b, 0x65, 0xb0, 0x3d, 0xcd, 0xd5, 0x84, 0x01, 0x8f, 0xd4, 0x8a, + 0x84, 0xfb, 0x72, 0x6f, 0x96, 0xee, 0x8b, 0xc8, 0xa3, 0x31, 0x48, 0x22, + 0x28, 0xe4, 0x93, 0xb7, 0x70, 0xdd, 0x27, 0x9e, 0xf5, 0x3f, 0xe6, 0x20, + 0xdb, 0xc1, 0x98, 0x26, 0x8d, 0x13, 0x98, 0xab, 0x4a, 0xeb, 0xae, 0xf2, + 0xea, 0x15, 0x89, 0x05, 0x46, 0x93, 0xb6, 0x58, 0x93, 0xf5, 0x0d, 0x8a, + 0x21, 0x4b, 0xea, 0xea, 0x81, 0xba, 0x33, 0x83, 0x11, 0xea, 0x79, 0xa5, + 0x51, 0x14, 0x81, 0x5b, 0x0b, 0xa6, 0x6b, 0x2a, 0xc3, 0x51, 0x7f, 0xb6, + 0xad, 0x60, 0x88, 0xa4, 0x60, 0xe7, 0x08, 0x94, 0x2d, 0x51, 0xee, 0xce, + 0xe6, 0xe6, 0x95, 0x14, 0xf7, 0xbd, 0x0a, 0x55, 0xca, 0x9a, 0x98, 0xdc, + 0xfc, 0x0b, 0x6f, 0x12, 0xa8, 0xb5, 0xb9, 0xc9, 0xff, 0x7e, 0xb5, 0xc4, + 0x71, 0x42, 0x0a, 0x1a, 0x99, 0xa5, 0x5f, 0x9c, 0xd5, 0x28, 0xef, 0x41, + 0x1e, 0xd2, 0x33, 0x58, 0x3c, 0xc0, 0x36, 0xcb, 0x2b, 0xda, 0xa3, 0x16, + 0x43, 0x62, 0x3b, 0xf9, 0x01, 0x82, 0xb2, 0xd4, 0x58, 0x7e, 0xa6, 0x47, + 0xe5, 0xf1, 0x56, 0x23, 0x85, 0x70, 0x6d, 0x88, 0x23, 0xcf, 0x6a, 0x79, + 0x14, 0xff, 0x6c, 0x92, 0x77, 0x76, 0xf5, 0x6e, 0x13, 0x8d, 0xeb, 0x19, + 0xa1, 0xec, 0xb6, 0xce, 0x1b, 0x38, 0xbb, 0x6a, 0x62, 0x9b, 0xe9, 0x36, + 0x56, 0xb7, 0xca, 0x34, 0xdd, 0x42, 0x1a, 0x23, 0x06, 0x1a, 0xba, 0x82, + 0x68, 0xd8, 0xf5, 0x28, 0x20, 0xee, 0x33, 0x14, 0x44, 0x8d, 0xa6, 0x6f, + 0xfe, 0x91, 0x5e, 0xa7, 0x8c, 0x2d, 0x78, 0xb4, 0x8a, 0x3f, 0xad, 0xe9, + 0xd1, 0x1e, 0xfc, 0x2b, 0x0c, 0xad, 0x0e, 0xf0, 0x4a, 0x2f, 0x10, 0x04, + 0x90, 0x40, 0xc6, 0xb0, 0xb6, 0xdf, 0x25, 0xcc, 0xac, 0xdc, 0xb6, 0xf2, + 0x7f, 0xb4, 0x6f, 0x81, 0xb6, 0x16, 0x16, 0x77, 0x01, 0x8e, 0x08, 0xc2, + 0x0a, 0xb1, 0xfd, 0x49, 0xbe, 0x12, 0xbf, 0x14, 0xfe, 0x5d, 0x9f, 0xde, + 0xa9, 0x92, 0xca, 0x1e, 0x40, 0xe3, 0x43, 0x50, 0x7c, 0xef, 0xfe, 0xe2, + 0x3c, 0x58, 0x12, 0xb3, 0x60, 0xb6, 0x6d, 0x54, 0xe2, 0x4a, 0xaf, 0xb6, + 0xca, 0x46, 0xbf, 0x35, 0xb5, 0x4b, 0xb3, 0xe4, 0x39, 0x6a, 0x20, 0x60, + 0xa8, 0x36, 0x02, 0x0a, 0x68, 0xa8, 0x7b, 0xfd, 0xc0, 0xe9, 0x9e, 0xfe, + 0x06, 0xbd, 0x0f, 0x60, 0x30, 0xd4, 0x19, 0x2d, 0x25, 0x4e, 0x3e, 0x2f, + 0x10, 0x6d, 0xd1, 0x07, 0xdf, 0xd1, 0x06, 0x7f, 0xb6, 0xdb, 0xde, 0x7e, + 0x7f, 0xa4, 0x69, 0x08, 0xe3, 0xff, 0x0f, 0xf7, 0xd5, 0xa9, 0x73, 0x32, + 0x55, 0xa8, 0x73, 0xfa, 0xa6, 0xf0, 0x36, 0x0b, 0x4e, 0xdb, 0xd8, 0x78, + 0xeb, 0xa7, 0xe8, 0x32, 0x0c, 0x5a, 0xac, 0x11, 0x3c, 0x9a, 0x37, 0xfc, + 0x9e, 0xb5, 0x16, 0xd9, 0xdc, 0xa8, 0x2f, 0x03, 0x80, 0x9c, 0xc5, 0x65, + 0xbd, 0x1b, 0xff, 0xf4, 0x09, 0xda, 0x70, 0xe8, 0xa0, 0x20, 0x01, 0xef, + 0x89, 0x35, 0x4d, 0x2a, 0x55, 0x29, 0x5e, 0x9b, 0xa6, 0x9c, 0x36, 0xed, + 0x89, 0x82, 0x00, 0x8e, 0x93, 0xd2, 0x30, 0x3b, 0xf7, 0x5a, 0xf7, 0x7f, + 0x8d, 0xc2, 0xdb, 0xaa, 0x6d, 0x5e, 0x7d, 0x46, 0xa9, 0xdc, 0x50, 0x22, + 0x02, 0xd8, 0x15, 0x82, 0x36, 0x09, 0x1f, 0x60, 0xb4, 0x79, 0x18, 0x10, + 0x3e, 0x0c, 0x1c, 0x49, 0x95, 0x4a, 0x1b, 0x4a, 0x82, 0xd1, 0x3b, 0x22, + 0x10, 0x34, 0x4d, 0x0b, 0x13, 0xff, 0x1a, 0xd5, 0x00, 0xc6, 0xfb, 0xf0, + 0x60, 0x4d, 0x0c, 0x42, 0x11, 0x78, 0x21, 0x01, 0xef, 0xab, 0xfb, 0x03, + 0xd6, 0x5b, 0x10, 0x71, 0x42, 0x8b, 0xef, 0xf1, 0x6a, 0xa6, 0x72, 0x8e, + 0x3d, 0x81, 0xb0, 0x31, 0x1c, 0x3c, 0x52, 0xe6, 0x1f, 0x00, 0x00, 0x8a, + 0x08, 0x6c, 0x46, 0x25, 0x2c, 0x3c, 0x1e, 0x03, 0xc3, 0xc0, 0x1e, 0x9a, + 0x8c, 0x1a, 0x70, 0x55, 0xba, 0xb6, 0x14, 0x3a, 0x44, 0xa9, 0x28, 0xe8, + 0x4a, 0x9d, 0xef, 0xf5, 0x22, 0xa5, 0x89, 0x22, 0xa8, 0x46, 0xaf, 0xdb, + 0xf1, 0x6c, 0x62, 0x76, 0xee, 0x2a, 0xc5, 0x2b, 0x15, 0x22, 0x84, 0x22, + 0xee, 0x14, 0x88, 0x9d, 0x74, 0xb9, 0xbe, 0x40, 0x5d, 0x55, 0x5e, 0xc0, + 0x5c, 0x5d, 0xff, 0x16, 0x42, 0xfd, 0xd2, 0xc9, 0xc8, 0xbe, 0xd1, 0x91, + 0xd9, 0xdd, 0x36, 0x05, 0xb7, 0x03, 0x6b, 0xc1, 0x93, 0x94, 0x2e, 0x55, + 0x31, 0x55, 0xbc, 0x5f, 0xff, 0xac, 0x92, 0xf2, 0xc9, 0x0f, 0x47, 0xa2, + 0x33, 0xe4, 0x9c, 0xb5, 0x32, 0xb9, 0x9b, 0xe4, 0x62, 0x83, 0xa3, 0xfc, + 0xcf, 0x6c, 0xe8, 0xd9, 0x9e, 0xf0, 0x52, 0xf4, 0x44, 0x0d, 0x60, 0x4e, + 0x78, 0x0f, 0xff, 0xa9, 0xe6, 0x45, 0xd4, 0x39, 0x9f, 0x96, 0x32, 0x6d, + 0x22, 0x3e, 0x13, 0x25, 0x89, 0xbf, 0x61, 0x77, 0xad, 0xf6, 0x4f, 0xe6, + 0xc0, 0xf5, 0x17, 0x57, 0xfc, 0xbd, 0x0e, 0x77, 0x0f, 0x8b, 0xd8, 0xfe, + 0x36, 0xab, 0x21, 0x65, 0xf3, 0x2a, 0x14, 0x75, 0x1c, 0x34, 0x5b, 0xc1, + 0x14, 0xc3, 0x56, 0xaa, 0x2b, 0xbe, 0x53, 0xb7, 0xad, 0x0c, 0x97, 0x27, + 0x66, 0x3c, 0x5c, 0xea, 0xad, 0x55, 0xdc, 0xc6, 0xc0, 0xa2, 0x95, 0x05, + 0xbc, 0x58, 0xd4, 0x06, 0x09, 0x06, 0xc9, 0xdb, 0xf6, 0x35, 0x65, 0x69, + 0x4b, 0x3f, 0xd5, 0xb5, 0x1f, 0x2a, 0x1e, 0x95, 0x00, 0x9d, 0x7a, 0x85, + 0x7a, 0xb1, 0x5a, 0x1e, 0x49, 0xc7, 0x20, 0x3f, 0xf7, 0x1b, 0xbb, 0xc4, + 0x7d, 0x18, 0x90, 0x97, 0xc8, 0x79, 0xb1, 0x96, 0x96, 0x2d, 0x35, 0x6d, + 0x9c, 0x24, 0xed, 0x36, 0xec, 0x39, 0x92, 0xa9, 0x6b, 0x6c, 0xa6, 0xe2, + 0xd6, 0x3c, 0x8a, 0xa0, 0xfb, 0x12, 0xa9, 0x56, 0xd4, 0xff, 0xaa, 0xc4, + 0xbe, 0x05, 0x4c, 0x0d, 0xc1, 0x2d, 0x97, 0xa4, 0xf3, 0x4c, 0xa8, 0xd8, + 0x5a, 0xd1, 0x57, 0x34, 0x36, 0xb3, 0xb2, 0x83, 0x0d, 0x32, 0xdf, 0x13, + 0x21, 0xf6, 0xc5, 0xaa, 0x80, 0xfd, 0x1b, 0x25, 0xc2, 0xd4, 0x45, 0x70, + 0x6f, 0x2c, 0x45, 0x5e, 0x2b, 0x53, 0x8c, 0xe7, 0x73, 0x9f, 0x8a, 0x25, + 0x1c, 0xa2, 0x92, 0xd8, 0x8c, 0x35, 0xc0, 0x5a, 0x2e, 0xd8, 0x91, 0xd0, + 0xf4, 0x7d, 0xdb, 0xeb, 0xc2, 0xc4, 0x1e, 0xb5, 0x0f, 0xba, 0x0c, 0x83, + 0x70, 0x12, 0x07, 0x62, 0x10, 0xf4, 0x18, 0xb1, 0x96, 0x7c, 0xaf, 0xd4, + 0xb3, 0xe1, 0xdf, 0xb5, 0x1f, 0xa9, 0xb9, 0x01, 0x2e, 0xd8, 0x69, 0xc6, + 0xb7, 0x93, 0x48, 0xad, 0x36, 0xb3, 0x93, 0xa1, 0xdf, 0xd0, 0xa0, 0x40, + 0x46, 0xa2, 0x4e, 0xff, 0xf7, 0xfc, 0xb3, 0x25, 0x29, 0x94, 0x4e, 0x17, + 0xf2, 0x2f, 0x8c, 0xb5, 0xc2, 0xcf, 0xe0, 0x7b, 0x71, 0x7c, 0x6e, 0x58, + 0xb7, 0x01, 0x82, 0x42, 0xca, 0xb9, 0x25, 0xc9, 0x92, 0x4c, 0x44, 0x68, + 0xf1, 0x83, 0x4d, 0x92, 0x45, 0x28, 0xd5, 0x06, 0xaf, 0x54, 0x03, 0x90, + 0x90, 0xfd, 0x20, 0x18, 0x32, 0x3b, 0x83, 0xa8, 0x36, 0xad, 0xef, 0xf9, + 0xe6, 0x3d, 0x03, 0x9b, 0x3a, 0x08, 0xc6, 0x24, 0x9d, 0xb1, 0xc4, 0xb4, + 0x42, 0xdc, 0x37, 0xf8, 0xd4, 0xbd, 0x20, 0x1d, 0xfd, 0x3e, 0x6b, 0x36, + 0xd5, 0xe0, 0x50, 0x75, 0x9f, 0xa7, 0xdb, 0xe0, 0x45, 0x58, 0x3c, 0xbf, + 0x45, 0xc9, 0x0f, 0x0f, 0x70, 0x7a, 0x5a, 0x24, 0xb3, 0x27, 0x4b, 0x27, + 0xb1, 0x74, 0x1c, 0xf1, 0x55, 0x5c, 0x68, 0x4f, 0x9a, 0x2d, 0xe8, 0x2d, + 0x8b, 0xdc, 0x53, 0x8f, 0x6d, 0x01, 0xce, 0x61, 0x6b, 0x3d, 0xe0, 0x2b, + 0x20, 0xc7, 0x84, 0xc3, 0xa2, 0xe1, 0xfe, 0x45, 0x62, 0x0a, 0x94, 0x7f, + 0xa3, 0x0a, 0x7c, 0xa0, 0x32, 0x9f, 0x52, 0xd6, 0x00, 0xa5, 0xca, 0xba, + 0x0a, 0xbc, 0x40, 0x1c, 0x02, 0xde, 0xa0, 0x8c, 0x39, 0x0f, 0x55, 0x7f, + 0x9f, 0xf8, 0x14, 0xfd, 0x2a, 0x99, 0x45, 0x65, 0xcf, 0x4c, 0xe8, 0xe6, + 0x02, 0x49, 0x89, 0x3d, 0x70, 0x3b, 0x8a, 0x1e, 0xd9, 0x5d, 0x1e, 0x88, + 0x3f, 0x2c, 0x95, 0x1a, 0x23, 0x5d, 0x26, 0x5d, 0xbc, 0xd2, 0xdb, 0x10, + 0xb8, 0xff, 0x87, 0x57, 0xb6, 0x02, 0x2f, 0xae, 0x7b, 0x61, 0x6e, 0xf8, + 0xae, 0x4d, 0x35, 0x00, 0x4a, 0xa5, 0xe2, 0x5b, 0x5e, 0x66, 0xe5, 0x6c, + 0xb7, 0xf9, 0x6b, 0x55, 0x41, 0x5c, 0x9b, 0x39, 0xd9, 0xd1, 0xb3, 0x5a, + 0xbc, 0x2d, 0xc2, 0x53, 0x07, 0xb7, 0x32, 0x11, 0x0b, 0x99, 0x6c, 0xab, + 0x43, 0xcf, 0x96, 0x46, 0x5b, 0xe1, 0x62, 0x35, 0x12, 0xf7, 0x78, 0x80, + 0x1c, 0x60, 0xd0, 0xfe, 0x87, 0xb2, 0x41, 0xb2, 0x0e, 0x2f, 0x14, 0xa1, + 0x87, 0xc9, 0x8f, 0x0b, 0xf4, 0x6f, 0x9a, 0xa2, 0x28, 0x37, 0xd9, 0x29, + 0xb3, 0xde, 0xa9, 0x56, 0x57, 0xfc, 0x6b, 0x29, 0x6f, 0xdb, 0x0f, 0x17, + 0xea, 0x09, 0x40, 0x9e, 0x70, 0xcd, 0x68, 0xcb, 0x1f, 0x4e, 0xe6, 0x49, + 0x11, 0x23, 0x46, 0x27, 0x37, 0x59, 0x65, 0x7f, 0x55, 0xeb, 0x5d, 0x6b, + 0xa8, 0xed, 0xc9, 0xd2, 0xce, 0xa8, 0x11, 0x14, 0x3d, 0x38, 0x4f, 0xda, + 0x4a, 0xa7, 0x5b, 0xaa, 0xb7, 0xad, 0x6f, 0xf6, 0x6a, 0x05, 0xe7, 0xec, + 0xb0, 0x2a, 0x2a, 0x14, 0x05, 0xa5, 0xa7, 0x87, 0xdb, 0xf0, 0xf5, 0xaf, + 0xc9, 0x9c, 0x1b, 0x72, 0x59, 0x14, 0x20, 0xe0, 0xc6, 0x83, 0x0d, 0x7b, + 0x71, 0xbc, 0x2b, 0x90, 0xa9, 0x71, 0x4a, 0x32, 0x21, 0x25, 0x1b, 0x20, + 0x86, 0xcf, 0x25, 0xd5, 0x9d, 0xf7, 0x86, 0x6b, 0x63, 0x34, 0xa9, 0xfd, + 0xe5, 0x03, 0x9d, 0x9c, 0xbb, 0x7b, 0x5b, 0xd9, 0xe9, 0x21, 0x22, 0x91, + 0xba, 0x30, 0xb0, 0x60, 0xac, 0x4b, 0x11, 0xb9, 0x4b, 0x52, 0xb1, 0x39, + 0xde, 0xf3, 0xf3, 0x6f, 0x49, 0x23, 0x87, 0xe0, 0xcd, 0x89, 0x1a, 0x5e, + 0x24, 0xb4, 0xc5, 0x66, 0x4a, 0x9e, 0x6e, 0xa4, 0x2d, 0xd5, 0x11, 0x6e, + 0x16, 0xb5, 0x00, 0x9f, 0x35, 0x40, 0x15, 0x07, 0xc8, 0x80, 0x1c, 0x30, + 0xc0, 0x38, 0xc6, 0x25, 0xf3, 0x4c, 0xb3, 0xb3, 0x9b, 0xc6, 0x79, 0xce, + 0xa2, 0xec, 0x2c, 0xfc, 0x19, 0x18, 0x83, 0x9b, 0x00, 0xa2, 0x97, 0x45, + 0x3a, 0x81, 0xcd, 0x86, 0xa0, 0x3a, 0x10, 0xbc, 0xda, 0xb6, 0xd5, 0xa6, + 0x6f, 0xb6, 0xf3, 0x4b, 0x39, 0xc5, 0x36, 0xa1, 0x80, 0x24, 0x33, 0x5c, + 0xb9, 0x6e, 0x6c, 0xe5, 0x88, 0xc9, 0xc5, 0xad, 0x81, 0xc2, 0xf2, 0xd1, + 0x05, 0xa6, 0x53, 0xc6, 0xb9, 0x8d, 0x15, 0xaf, 0x67, 0xa2, 0x29, 0x2a, + 0x90, 0xe1, 0xc1, 0x1f, 0xc1, 0x00, 0x7d, 0xa5, 0x5f, 0x62, 0xb3, 0x68, + 0x15, 0xfe, 0xd1, 0xcd, 0x19, 0xa0, 0x21, 0x80, 0x89, 0xaa, 0xd7, 0x9e, + 0x1c, 0x3d, 0xf5, 0x57, 0x50, 0x05, 0x8d, 0x96, 0x54, 0x3e, 0x4e, 0xae, + 0x29, 0x6b, 0xca, 0x60, 0x6b, 0x30, 0x1c, 0xa4, 0x8c, 0x83, 0x0c, 0x82, + 0x0b, 0x1b, 0x0b, 0x95, 0x08, 0x39, 0x77, 0x2b, 0x58, 0xc6, 0x42, 0xa5, + 0xd0, 0xc9, 0x0a, 0xa6, 0x83, 0x06, 0xe0, 0xf9, 0x5f, 0xfd, 0xd6, 0xe0, + 0x84, 0x93, 0x33, 0xa1, 0xfc, 0x2c, 0x0e, 0xbd, 0x85, 0x9a, 0xa6, 0xf5, + 0x6e, 0x51, 0x88, 0x31, 0x01, 0x46, 0x12, 0xab, 0x92, 0x03, 0x16, 0x08, + 0x4c, 0xed, 0x0e, 0x53, 0xec, 0x60, 0x18, 0x13, 0x6d, 0x1f, 0x66, 0x23, + 0xf9, 0xda, 0x38, 0x15, 0xb6, 0x16, 0x84, 0x60, 0x6c, 0xf4, 0x98, 0xd9, + 0x7e, 0x29, 0x66, 0xf3, 0x7f, 0xbf, 0xaa, 0x43, 0xd4, 0x21, 0xaa, 0x10, + 0x13, 0x20, 0x7c, 0x74, 0x07, 0x87, 0x59, 0xa3, 0xf2, 0xf6, 0xb5, 0x3d, + 0x5b, 0xde, 0xf2, 0x9b, 0x33, 0xbc, 0xbc, 0xf4, 0xe0, 0xd9, 0x15, 0x06, + 0x27, 0x0a, 0xa3, 0xe2, 0xe6, 0x5b, 0xf6, 0x6a, 0xb9, 0x23, 0x6a, 0x21, + 0x6e, 0x65, 0xb7, 0xd2, 0xa1, 0x0d, 0x42, 0xc5, 0xc4, 0x70, 0x38, 0x3c, + 0x05, 0x68, 0xf4, 0x7b, 0xf9, 0xbe, 0x69, 0xa5, 0x83, 0xf5, 0xd8, 0x6a, + 0x49, 0xc0, 0xf3, 0xca, 0x46, 0xfb, 0xa0, 0xa8, 0xff, 0xc6, 0xc2, 0xc7, + 0xf9, 0x60, 0x58, 0xbb, 0xce, 0x11, 0x3f, 0x00, 0x00, 0x8f, 0x08, 0x2c, + 0x44, 0x23, 0x2c, 0x98, 0x78, 0x6c, 0x19, 0x42, 0x65, 0x15, 0x07, 0x47, + 0x10, 0xe1, 0x26, 0x35, 0x5b, 0x2a, 0x65, 0xd0, 0x33, 0x94, 0xd1, 0x02, + 0x63, 0xad, 0xf0, 0x31, 0x60, 0xf1, 0x06, 0x82, 0xa8, 0xb8, 0x95, 0x71, + 0xc7, 0x97, 0x06, 0x13, 0xcf, 0x99, 0x98, 0x1e, 0xa8, 0xa6, 0xbb, 0x17, + 0x46, 0x86, 0xb8, 0x5c, 0x52, 0x22, 0x72, 0x65, 0x7a, 0x38, 0xee, 0xea, + 0xfa, 0x19, 0x39, 0x60, 0x45, 0x5f, 0x91, 0x1f, 0x51, 0x2c, 0xbd, 0x06, + 0x13, 0xad, 0xad, 0x08, 0x3d, 0xd1, 0x06, 0x6c, 0xed, 0xea, 0x85, 0xce, + 0x29, 0x4b, 0x99, 0xe4, 0x2c, 0x92, 0x31, 0xb0, 0x3b, 0xdd, 0x2b, 0xab, + 0x03, 0x02, 0xeb, 0x2b, 0x40, 0xe9, 0x64, 0x5a, 0x4a, 0xd5, 0x47, 0xb9, + 0x28, 0x6b, 0xde, 0x53, 0x47, 0xe3, 0xe9, 0x58, 0x6a, 0x4d, 0xdf, 0xce, + 0x5e, 0xf0, 0x96, 0xc4, 0x71, 0xc3, 0x78, 0xc2, 0xc5, 0x9d, 0x53, 0x28, + 0x2f, 0x4d, 0x09, 0x7f, 0xeb, 0x6c, 0x78, 0x6d, 0xef, 0x7a, 0x64, 0x42, + 0xbb, 0x8a, 0x64, 0xcf, 0x68, 0x87, 0x2f, 0x59, 0x51, 0x63, 0x5e, 0xb3, + 0xd8, 0x86, 0xdd, 0xb2, 0xf2, 0x86, 0xc4, 0x5d, 0x37, 0x87, 0x3c, 0x67, + 0xf9, 0x0b, 0x6f, 0x69, 0x2f, 0x2d, 0xe8, 0x30, 0xd6, 0x5a, 0x93, 0xed, + 0x64, 0xf5, 0x95, 0x42, 0x72, 0xb8, 0x84, 0x3a, 0x47, 0xc1, 0x38, 0x9d, + 0xae, 0xe2, 0x30, 0x4c, 0x38, 0xfe, 0x99, 0x25, 0xbd, 0x37, 0xe6, 0x86, + 0xa6, 0x8b, 0x7a, 0xb9, 0xb0, 0xaf, 0xb3, 0xcd, 0x63, 0x94, 0x89, 0x7e, + 0xfb, 0xc0, 0x91, 0xd2, 0x29, 0x5a, 0x46, 0x15, 0xb1, 0x1b, 0xec, 0xb1, + 0x00, 0x56, 0x9c, 0x57, 0x9d, 0x86, 0xea, 0x08, 0xbb, 0xcb, 0xd9, 0x43, + 0x20, 0xab, 0xa5, 0x86, 0x06, 0xe5, 0xcb, 0x72, 0x8d, 0xe6, 0xf0, 0xd1, + 0xf4, 0xff, 0xfb, 0xad, 0x30, 0x6f, 0xd2, 0xb5, 0x4a, 0x25, 0xec, 0x0c, + 0xc1, 0x82, 0xa2, 0xa2, 0x3c, 0x50, 0x9c, 0x35, 0x82, 0xf7, 0x2c, 0xd6, + 0x75, 0x86, 0xf9, 0x2e, 0xe9, 0x6c, 0x2a, 0x88, 0xf9, 0x65, 0xeb, 0xf8, + 0xf2, 0xc8, 0x08, 0xdb, 0xe0, 0x44, 0x4a, 0xc3, 0x3f, 0x99, 0x2d, 0xf0, + 0x81, 0xd4, 0x52, 0xfe, 0xf2, 0xc0, 0xaa, 0x12, 0x97, 0x2a, 0x2f, 0xf8, + 0xe3, 0x8a, 0x20, 0xe2, 0xe7, 0x99, 0xc5, 0xb9, 0xce, 0x76, 0x5a, 0x22, + 0xe2, 0x90, 0x4a, 0x86, 0x3d, 0xe1, 0xd3, 0x0a, 0x12, 0xe1, 0x6b, 0x69, + 0x6c, 0x2c, 0xcc, 0xc1, 0xcc, 0xf2, 0xfc, 0x85, 0xaa, 0x0a, 0x86, 0xd5, + 0x48, 0x30, 0x9d, 0x1e, 0xa8, 0x1c, 0x4c, 0x5a, 0xc9, 0x75, 0x17, 0x39, + 0x2a, 0x29, 0x01, 0x69, 0x8c, 0xe9, 0x56, 0x91, 0xb6, 0x3d, 0xf0, 0xfc, + 0xbc, 0x20, 0x37, 0x58, 0x52, 0xa7, 0xdd, 0x5f, 0xda, 0x1d, 0x6c, 0x37, + 0x03, 0x83, 0x22, 0x01, 0xd0, 0x86, 0xa9, 0x2d, 0x51, 0x29, 0x66, 0x83, + 0x1a, 0xd0, 0xca, 0x50, 0x4b, 0x2a, 0x10, 0x47, 0x5a, 0xd8, 0x32, 0xf8, + 0x57, 0x79, 0x0b, 0x4d, 0x8a, 0x43, 0xba, 0xf9, 0x4d, 0x3c, 0xbe, 0x29, + 0x05, 0xb1, 0x53, 0x3c, 0xc8, 0xa5, 0xb2, 0x2c, 0xad, 0x7c, 0x33, 0x17, + 0x9d, 0x38, 0x9d, 0x9f, 0x79, 0x2b, 0x0a, 0x7c, 0x39, 0xab, 0x21, 0x92, + 0xc9, 0x3c, 0x8c, 0xac, 0x52, 0x13, 0x41, 0x48, 0xcf, 0xd5, 0x89, 0x49, + 0xeb, 0x34, 0xb7, 0x55, 0x33, 0xc9, 0xfd, 0x5f, 0x54, 0x59, 0x81, 0xe0, + 0x38, 0xc5, 0x7f, 0x28, 0x22, 0xd6, 0x74, 0xad, 0x6e, 0x44, 0x0b, 0x42, + 0x2f, 0x21, 0x1b, 0x7a, 0x73, 0x45, 0xad, 0xa8, 0x5f, 0xf8, 0xad, 0x95, + 0x17, 0xbc, 0xbe, 0xe5, 0xc1, 0x97, 0x01, 0x86, 0x81, 0xc8, 0x7a, 0x0f, + 0x05, 0x01, 0x98, 0x06, 0x2b, 0xf9, 0x7e, 0xb0, 0x3f, 0x57, 0x59, 0x53, + 0x83, 0x8f, 0x16, 0x65, 0xfc, 0xf8, 0x31, 0x54, 0xb7, 0x01, 0x83, 0x8d, + 0x80, 0xc1, 0x52, 0xca, 0xd4, 0xee, 0xac, 0x8b, 0x90, 0xb4, 0xdf, 0x0d, + 0x47, 0x88, 0x47, 0xe9, 0x02, 0x11, 0x7a, 0x61, 0xc2, 0xb6, 0x26, 0xf8, + 0xab, 0x7f, 0x36, 0xf1, 0x78, 0xbc, 0xb4, 0x09, 0x82, 0x52, 0xe6, 0x6f, + 0x16, 0xa0, 0x92, 0x54, 0x84, 0x6d, 0xd2, 0xaa, 0xca, 0x74, 0x8d, 0x27, + 0x6f, 0xdb, 0x3f, 0xff, 0x79, 0xbb, 0xb8, 0x1d, 0x77, 0xfe, 0xe8, 0x79, + 0x43, 0x83, 0xab, 0x88, 0x60, 0x1a, 0x10, 0xc4, 0xa4, 0x89, 0x01, 0x13, + 0x1a, 0xd9, 0xbf, 0x04, 0x46, 0xfb, 0x9f, 0xac, 0xce, 0xfe, 0xf2, 0x50, + 0x24, 0x55, 0xe3, 0x2b, 0x8f, 0x1b, 0xf4, 0x55, 0xaa, 0xb4, 0xaf, 0xd9, + 0xa0, 0xac, 0x43, 0x4b, 0x2a, 0x25, 0xc3, 0x6e, 0x28, 0x05, 0x70, 0x58, + 0x30, 0x11, 0xf7, 0x22, 0x7b, 0x20, 0x32, 0x1f, 0x45, 0x11, 0x41, 0x50, + 0x78, 0xb7, 0x3a, 0x1c, 0x83, 0x04, 0x62, 0x97, 0x0b, 0x78, 0xd5, 0x2a, + 0xa6, 0x0a, 0x3c, 0xd8, 0xb8, 0x47, 0x06, 0xd5, 0x41, 0x09, 0x21, 0x73, + 0x52, 0xf3, 0xec, 0xa8, 0xcc, 0x9c, 0x1b, 0x67, 0x03, 0xd6, 0xe8, 0x6e, + 0xa6, 0x39, 0x41, 0x2b, 0xdf, 0x12, 0xee, 0x33, 0x17, 0x4d, 0xff, 0xd6, + 0xd4, 0xc5, 0xfd, 0xff, 0xd0, 0xef, 0xfd, 0x11, 0x77, 0x4e, 0x06, 0x51, + 0xe8, 0x1c, 0xf3, 0x2c, 0xe2, 0xb5, 0x7e, 0xad, 0xa9, 0xf2, 0xf9, 0x2f, + 0x26, 0x67, 0x56, 0xed, 0x0e, 0x54, 0x38, 0x4c, 0x10, 0x82, 0x00, 0x94, + 0xd6, 0x65, 0x54, 0xac, 0x77, 0xea, 0xb7, 0x1a, 0x05, 0x5b, 0x73, 0xde, + 0xd1, 0xbd, 0xe3, 0x19, 0xb8, 0xc6, 0xe2, 0x3c, 0x2b, 0xf0, 0xb4, 0x61, + 0x9f, 0x7d, 0x50, 0xde, 0x7b, 0x42, 0xd7, 0xb0, 0xf2, 0x61, 0x6d, 0x47, + 0x95, 0x4e, 0x35, 0x92, 0x2c, 0xbe, 0xc5, 0xad, 0xa6, 0x9e, 0xa2, 0x97, + 0x9e, 0x61, 0x56, 0xf8, 0xac, 0x41, 0xd6, 0x40, 0xa1, 0x5a, 0x0a, 0x40, + 0x80, 0x96, 0x98, 0x7e, 0x90, 0x79, 0xe1, 0xff, 0xb2, 0x83, 0x23, 0x8b, + 0x71, 0x4e, 0xcc, 0xb2, 0xae, 0x08, 0xe0, 0x20, 0xe1, 0x35, 0x6e, 0xd4, + 0x2b, 0x67, 0x8c, 0x31, 0x72, 0x5f, 0xd9, 0x3f, 0x7f, 0x6c, 0x05, 0x60, + 0x15, 0xe7, 0x01, 0x90, 0x81, 0x00, 0x61, 0x88, 0x25, 0x0d, 0x81, 0xb9, + 0x04, 0x65, 0x6a, 0xd3, 0x62, 0x78, 0xad, 0x81, 0xc8, 0xe7, 0x32, 0x81, + 0x76, 0xa7, 0xd1, 0xca, 0x1c, 0xe2, 0x91, 0x14, 0xb4, 0x18, 0x12, 0xc7, + 0x25, 0xe1, 0x04, 0x1b, 0x83, 0xed, 0x1d, 0x8f, 0x59, 0xd6, 0xbd, 0xb9, + 0x60, 0xf9, 0x0a, 0xb4, 0xf4, 0xd2, 0x68, 0x87, 0x30, 0x39, 0x06, 0x22, + 0x06, 0x48, 0xfc, 0x1a, 0x8e, 0xd3, 0x8f, 0xc1, 0x4f, 0x35, 0x46, 0xf9, + 0x6f, 0x51, 0xbe, 0xa8, 0x88, 0x8b, 0x6e, 0x8d, 0xc1, 0x86, 0x94, 0x72, + 0x02, 0x9a, 0xe8, 0x58, 0xd9, 0x5c, 0xf9, 0xe4, 0x47, 0x27, 0x1d, 0x06, + 0x4e, 0x01, 0xbc, 0xe0, 0x29, 0xf8, 0x4b, 0x18, 0x6a, 0x51, 0x98, 0x08, + 0x95, 0x40, 0xc9, 0x40, 0xeb, 0x1b, 0x77, 0x53, 0x87, 0xf2, 0xa3, 0xf3, + 0x39, 0x2e, 0x0c, 0xb8, 0x36, 0x7a, 0xd4, 0xf9, 0x50, 0x05, 0x9d, 0x65, + 0xcd, 0x86, 0xb0, 0x64, 0xe3, 0xb4, 0xc9, 0xb4, 0x46, 0x10, 0x58, 0x10, + 0x78, 0x9c, 0x72, 0x59, 0xdb, 0x36, 0x7a, 0x4b, 0x2d, 0xf5, 0x82, 0x2a, + 0x9b, 0x01, 0x24, 0xa3, 0x69, 0x8b, 0x87, 0xa9, 0x15, 0x04, 0x34, 0x8d, + 0xed, 0x9e, 0xb1, 0xb8, 0x86, 0xd9, 0x65, 0xef, 0x83, 0x6d, 0xc3, 0xe6, + 0xc2, 0x18, 0x8f, 0xf0, 0x82, 0x94, 0x3f, 0xd0, 0xf3, 0x8d, 0x66, 0x4c, + 0xea, 0xd3, 0x92, 0x77, 0x80, 0x4f, 0xa6, 0x42, 0x98, 0x30, 0x90, 0x3b, + 0xc6, 0xbc, 0x0c, 0x58, 0xae, 0x95, 0x2b, 0xba, 0xdb, 0x55, 0x16, 0x42, + 0xc8, 0xba, 0xe3, 0x10, 0x61, 0xa7, 0x8c, 0xaf, 0x49, 0xbc, 0x16, 0xb7, + 0x81, 0x57, 0x0b, 0x2d, 0xb1, 0x4c, 0x91, 0x10, 0x8a, 0xb3, 0x83, 0x30, + 0xf4, 0x20, 0xb2, 0xcf, 0xf3, 0xc9, 0x18, 0xd4, 0x89, 0x27, 0x03, 0xfd, + 0x56, 0x55, 0xb7, 0x6a, 0x3f, 0x12, 0x28, 0x07, 0x07, 0xa1, 0x60, 0x88, + 0xbc, 0x7a, 0xab, 0xdc, 0x6c, 0xb9, 0x26, 0x2b, 0x34, 0xdf, 0xf9, 0x9e, + 0x44, 0x1d, 0x95, 0x95, 0xe8, 0x2a, 0x03, 0xa2, 0xd0, 0x62, 0x73, 0x62, + 0x1a, 0xa1, 0xe8, 0x43, 0x6c, 0xb5, 0x8c, 0xef, 0x76, 0xd1, 0xc7, 0x96, + 0xed, 0xa8, 0xed, 0x50, 0x54, 0xa4, 0xc8, 0xb3, 0x2d, 0xef, 0x22, 0x8a, + 0x75, 0x3f, 0xfe, 0x9e, 0x6f, 0x60, 0x80, 0xc2, 0x56, 0x9b, 0xda, 0xa7, + 0x54, 0x42, 0xbd, 0xee, 0xf1, 0x9b, 0x17, 0xbe, 0xaa, 0x14, 0x28, 0xc5, + 0xf0, 0x58, 0x26, 0x4d, 0x37, 0x74, 0x0c, 0x4d, 0xfe, 0xff, 0x94, 0x6f, + 0xdb, 0x79, 0x16, 0x91, 0x49, 0x56, 0x00, 0x82, 0x63, 0xa0, 0x38, 0x24, + 0xe7, 0xb0, 0x72, 0xa3, 0x35, 0x85, 0xd4, 0x56, 0xe6, 0xa9, 0xc8, 0xb4, + 0x9c, 0xc2, 0x97, 0x0b, 0x41, 0x08, 0x78, 0xda, 0xa8, 0xad, 0x2a, 0x55, + 0x19, 0x54, 0x48, 0xc7, 0xb1, 0x16, 0x67, 0x3b, 0xf0, 0x26, 0xa5, 0xd3, + 0xdf, 0x2c, 0x62, 0xef, 0xfd, 0xfe, 0xe8, 0x31, 0x14, 0xca, 0xb1, 0x13, + 0x61, 0x74, 0x74, 0x95, 0x9f, 0x35, 0xf0, 0xfd, 0x37, 0xd2, 0x31, 0xec, + 0x0e, 0xd9, 0xbe, 0x85, 0xb2, 0x4e, 0xff, 0xeb, 0x16, 0x95, 0x61, 0xe0, + 0x60, 0x83, 0x32, 0x0d, 0xf4, 0xe2, 0x3a, 0xb9, 0xe4, 0x95, 0xb6, 0x07, + 0x4d, 0x68, 0x18, 0x40, 0x1f, 0xd8, 0x0c, 0x87, 0xe0, 0xe0, 0x29, 0x80, + 0xe3, 0x21, 0x9c, 0x14, 0xa2, 0x3b, 0x2c, 0xfa, 0x2a, 0x54, 0x1e, 0x35, + 0x7b, 0x55, 0xd5, 0xef, 0xef, 0xa2, 0x29, 0xcc, 0x04, 0x70, 0x61, 0x30, + 0xc1, 0x76, 0xd4, 0x67, 0xb3, 0x29, 0x66, 0xc0, 0x33, 0xd5, 0xf9, 0x51, + 0xda, 0x0b, 0x41, 0xbf, 0xfa, 0xa8, 0x9b, 0x51, 0x99, 0x30, 0xc9, 0x6a, + 0x0f, 0x87, 0x1e, 0x1d, 0x0e, 0xac, 0x5f, 0xe0, 0xaa, 0x4d, 0xde, 0xaf, + 0x3a, 0x38, 0xf1, 0x02, 0x82, 0x08, 0x71, 0x9d, 0xde, 0x2f, 0xbc, 0xe4, + 0x14, 0x2e, 0x3c, 0x52, 0x0a, 0xa2, 0xe5, 0x1d, 0xb4, 0x14, 0xca, 0x86, + 0x03, 0x87, 0x18, 0x10, 0x0b, 0xf7, 0x96, 0x67, 0x09, 0x77, 0xf2, 0x2c, + 0x6f, 0x86, 0x1b, 0xe1, 0x54, 0x3a, 0x9e, 0x8c, 0xce, 0x29, 0x45, 0xf4, + 0x4a, 0x3c, 0x50, 0x84, 0x44, 0x04, 0x70, 0x7c, 0x98, 0x01, 0xd4, 0xac, + 0xb7, 0x6f, 0x95, 0x62, 0xbb, 0x2d, 0xc5, 0x3b, 0xde, 0xa8, 0x99, 0x10, + 0x41, 0xc1, 0x69, 0x58, 0x6c, 0x58, 0x2c, 0x59, 0xb9, 0xf9, 0xb2, 0x02, + 0xb2, 0xea, 0x95, 0xf9, 0x6a, 0xeb, 0xaf, 0x3a, 0xa1, 0x40, 0x5a, 0xb3, + 0x77, 0xa2, 0x1b, 0x05, 0xf1, 0x5a, 0x72, 0xea, 0x93, 0x2f, 0xab, 0x4c, + 0x37, 0xd6, 0x9b, 0xcf, 0xcb, 0xd8, 0xcc, 0xc2, 0xdc, 0x6f, 0x34, 0x15, + 0xc5, 0xa5, 0x86, 0x09, 0xf0, 0xa8, 0xc2, 0xd3, 0x52, 0xa6, 0x50, 0xe4, + 0x31, 0x06, 0x0a, 0x4d, 0x17, 0xf9, 0xb2, 0xdc, 0xea, 0xf6, 0xdd, 0x51, + 0xd4, 0x5c, 0xa7, 0x05, 0xf3, 0xf9, 0xe6, 0xae, 0x94, 0x92, 0x89, 0x85, + 0x09, 0x38, 0x9d, 0xab, 0x3f, 0xcd, 0x5e, 0xac, 0x87, 0xb6, 0xf5, 0x67, + 0xc2, 0xdc, 0x99, 0x61, 0x23, 0xcc, 0xb1, 0xcf, 0x25, 0xb8, 0xdb, 0x3c, + 0x2d, 0xdf, 0xe6, 0x16, 0x4e, 0x5b, 0x6f, 0xa7, 0x14, 0xfc, 0x44, 0xe1, + 0x68, 0x31, 0x3c, 0xb0, 0xb8, 0x2f, 0xd3, 0xa5, 0xc5, 0x9c, 0xad, 0x77, + 0xb7, 0x83, 0x2e, 0x11, 0xbf, 0x2d, 0x17, 0x46, 0x8f, 0xa5, 0x0e, 0xa6, + 0xcf, 0xb5, 0x9a, 0x2f, 0x57, 0xca, 0x58, 0x86, 0x0b, 0x90, 0x3b, 0xb0, + 0x93, 0x19, 0x2b, 0xfd, 0xa1, 0xb9, 0xaa, 0x48, 0x0b, 0x61, 0xa7, 0xf5, + 0x4a, 0x7d, 0x6d, 0x07, 0x68, 0xc3, 0xa7, 0x05, 0xca, 0xa7, 0x0a, 0xd0, + 0x03, 0xba, 0xeb, 0x6d, 0x60, 0x44, 0x07, 0x82, 0xff, 0x8d, 0xaf, 0xe0, + 0x30, 0x16, 0xf7, 0xbb, 0x98, 0x1c, 0x6f, 0xaf, 0x00, 0x9a, 0x93, 0xa9, + 0xa3, 0x7d, 0x0e, 0xbc, 0xc8, 0x2b, 0x75, 0x95, 0xad, 0xfd, 0x29, 0xe5, + 0xa7, 0xfb, 0x8b, 0x85, 0x8a, 0x07, 0x65, 0xcd, 0x6a, 0xa5, 0x6a, 0xef, + 0x6f, 0xd4, 0x4f, 0x40, 0xe3, 0x9c, 0xef, 0x78, 0x1c, 0x9c, 0x3a, 0x01, + 0xd9, 0xdf, 0x0f, 0xe7, 0xb4, 0xb1, 0x92, 0xcf, 0x16, 0x74, 0x67, 0xd0, + 0x61, 0xaa, 0x63, 0xfd, 0xe8, 0xf9, 0x5b, 0x5e, 0x1b, 0xf7, 0xbf, 0x24, + 0xce, 0x68, 0x44, 0x90, 0x07, 0x42, 0xc5, 0x41, 0xfd, 0x2a, 0xd6, 0xd5, + 0x8e, 0x0d, 0xac, 0x58, 0xb0, 0x66, 0xf7, 0x3a, 0x83, 0x10, 0x97, 0x99, + 0xad, 0xb4, 0xa9, 0x36, 0x96, 0x34, 0xd4, 0x03, 0x7a, 0x56, 0x8b, 0x27, + 0xea, 0xdc, 0x85, 0x44, 0x97, 0x0a, 0xc0, 0xae, 0xe0, 0x0a, 0xa6, 0xbe, + 0x5a, 0xde, 0xe2, 0x8b, 0x9c, 0xdc, 0x1b, 0xad, 0x6d, 0xb1, 0x7a, 0x0c, + 0x35, 0x32, 0x07, 0x53, 0x7c, 0x70, 0x5b, 0x8a, 0x6f, 0x95, 0x5b, 0xb7, + 0x00, 0x86, 0xf6, 0x4f, 0x37, 0x0d, 0x29, 0x3a, 0xaa, 0x46, 0x7f, 0xa3, + 0xd9, 0xbf, 0xfa, 0x9c, 0x60, 0x7c, 0xab, 0xbd, 0x1b, 0xdb, 0x60, 0x2c, + 0x41, 0x82, 0xa6, 0x96, 0x77, 0xd1, 0xed, 0x88, 0x99, 0xf5, 0xfc, 0x88, + 0x64, 0xdd, 0xec, 0x0d, 0xa3, 0xc5, 0x21, 0x0c, 0x75, 0x5a, 0xa2, 0x0f, + 0xb2, 0x96, 0x7e, 0xef, 0x20, 0x70, 0x48, 0x7c, 0x52, 0xb5, 0x97, 0x11, + 0xcb, 0x41, 0x38, 0x2e, 0xb3, 0xf8, 0x55, 0x2e, 0x62, 0x8d, 0xe8, 0xa1, + 0xf1, 0xe7, 0xb5, 0xa5, 0x8f, 0x6d, 0x50, 0x6c, 0x51, 0x44, 0x21, 0xfe, + 0x45, 0xbe, 0x1f, 0x95, 0x94, 0x96, 0x4a, 0xe3, 0xa3, 0xf4, 0xfd, 0xfb, + 0x6c, 0x76, 0xb5, 0xb7, 0x9d, 0xda, 0xbc, 0xdc, 0x43, 0x39, 0xa5, 0xaa, + 0x11, 0xcd, 0x2a, 0x2c, 0x04, 0x8a, 0x1e, 0x35, 0x89, 0x3e, 0x5e, 0xd6, + 0x49, 0x31, 0x3e, 0xcf, 0xc4, 0x12, 0x3f, 0x08, 0xe3, 0xaf, 0xea, 0x7e, + 0xf0, 0x13, 0x89, 0x54, 0xa0, 0xb6, 0xca, 0x0c, 0x4c, 0x57, 0xb5, 0x4f, + 0xe8, 0x2d, 0xdb, 0x2a, 0xab, 0xfe, 0x69, 0x8b, 0xe5, 0xd9, 0xca, 0x37, + 0xbf, 0xbd, 0xde, 0x2c, 0xbc, 0xa1, 0xc2, 0x20, 0x10, 0x32, 0x03, 0xb9, + 0x8a, 0xb8, 0xaf, 0xea, 0xfc, 0x1f, 0x67, 0xe7, 0xba, 0xa3, 0xf1, 0x45, + 0xbc, 0x2c, 0x58, 0x34, 0xa0, 0x94, 0x7d, 0xa6, 0x1b, 0x4c, 0xc8, 0xe3, + 0xe3, 0x6f, 0xc0, 0xf0, 0x92, 0xdb, 0x0e, 0x12, 0x06, 0x12, 0x73, 0xd4, + 0x21, 0x6c, 0x6f, 0x73, 0x19, 0xe6, 0x08, 0x1e, 0x11, 0x7f, 0x3d, 0x64, + 0x0c, 0x41, 0x82, 0xa4, 0x1c, 0xd6, 0x39, 0xb1, 0x19, 0x89, 0xba, 0x59, + 0x87, 0xdb, 0x17, 0x17, 0x30, 0xaa, 0xb5, 0xce, 0xdd, 0x2d, 0x91, 0x7e, + 0xcb, 0xef, 0xc5, 0x97, 0x61, 0x40, 0x25, 0x0a, 0x87, 0x62, 0x40, 0xe5, + 0x88, 0xd3, 0x5f, 0x8d, 0x7d, 0x4e, 0x37, 0x9b, 0x62, 0x98, 0xb0, 0x14, + 0xb0, 0x16, 0xe0, 0xd0, 0x60, 0x19, 0x58, 0x1f, 0x04, 0x0c, 0xd4, 0xc3, + 0xc4, 0xf8, 0x59, 0xb6, 0x87, 0x9b, 0x91, 0x96, 0xb0, 0x15, 0xca, 0x46, + 0xdb, 0xa0, 0x55, 0x40, 0x31, 0x1d, 0xf8, 0x18, 0x4b, 0x04, 0x36, 0xd3, + 0xa9, 0x6c, 0x7f, 0x85, 0x7d, 0x06, 0x02, 0x8d, 0x45, 0x1d, 0x02, 0x1c, + 0xc0, 0x10, 0x3b, 0x4b, 0xfa, 0x37, 0x70, 0xc0, 0x7f, 0xd2, 0x06, 0xc2, + 0x82, 0x61, 0x20, 0x79, 0xa3, 0x82, 0xe0, 0xff, 0xe0, 0xdd, 0xcc, 0xfa, + 0xbf, 0xe7, 0x95, 0x96, 0x37, 0x65, 0xa1, 0xec, 0xfb, 0x01, 0xee, 0x0e, + 0x17, 0x50, 0x56, 0x5a, 0x0c, 0x70, 0xd3, 0x3e, 0x89, 0x36, 0xae, 0x38, + 0xef, 0xca, 0xa2, 0x3b, 0xc2, 0x62, 0x41, 0x00, 0x03, 0x7c, 0x01, 0x83, + 0xb0, 0x61, 0x04, 0xbc, 0x41, 0x67, 0xfb, 0xe6, 0x70, 0xa8, 0xaf, 0x6d, + 0xf9, 0x2b, 0x7a, 0x2a, 0xa6, 0x41, 0x84, 0x30, 0x36, 0x3f, 0xd5, 0x7f, + 0x2e, 0xd2, 0xc4, 0x7e, 0xc1, 0x06, 0x76, 0x5e, 0xac, 0x0c, 0x09, 0x4f, + 0x5b, 0x9a, 0x47, 0xe3, 0x7d, 0x05, 0xb3, 0x62, 0x81, 0x0b, 0xd2, 0xf9, + 0xa9, 0xab, 0xaf, 0x34, 0xa7, 0x51, 0x9f, 0x38, 0x0c, 0xac, 0x18, 0x4b, + 0x11, 0x81, 0x01, 0x8f, 0xb1, 0xdf, 0x17, 0x8e, 0xee, 0x52, 0xc1, 0xe6, + 0x2e, 0xa2, 0xf1, 0x1a, 0x70, 0x63, 0x4d, 0x03, 0xe5, 0xff, 0xf6, 0x78, + 0x20, 0x83, 0x0e, 0xc4, 0x31, 0x24, 0x0c, 0x34, 0xcb, 0x63, 0xe2, 0xee, + 0x70, 0x3e, 0x63, 0x54, 0x29, 0x25, 0xff, 0xf0, 0xaf, 0x43, 0x40, 0x48, + 0x1f, 0x87, 0x77, 0xb6, 0xdb, 0x6a, 0x1d, 0x5e, 0x8d, 0x4d, 0xaf, 0x70, + 0xb6, 0xa0, 0x6b, 0x08, 0x61, 0x0c, 0x7e, 0x07, 0xd2, 0xd4, 0xa3, 0xf6, + 0xcb, 0x75, 0x16, 0x64, 0x2a, 0x69, 0x8f, 0x20, 0x69, 0x8f, 0x0d, 0x9a, + 0xc3, 0x07, 0xd8, 0x59, 0x07, 0x99, 0xae, 0x64, 0x3e, 0x9b, 0x6c, 0x5f, + 0x48, 0x2b, 0x4f, 0xd0, 0xe9, 0x25, 0x79, 0x2a, 0xac, 0x37, 0x20, 0x66, + 0x41, 0x6b, 0x43, 0x48, 0xa2, 0xa7, 0x62, 0x7f, 0x85, 0x97, 0xf9, 0x36, + 0xd4, 0x52, 0x5b, 0x27, 0x68, 0x6d, 0x82, 0x63, 0x23, 0xd4, 0x9f, 0x12, + 0x87, 0xe9, 0x03, 0xf1, 0xd3, 0x25, 0xf9, 0x3c, 0x20, 0x2a, 0xd6, 0xb7, + 0x89, 0x3f, 0x2c, 0xbd, 0xa0, 0x61, 0x4e, 0xc0, 0x54, 0x30, 0x1e, 0x0d, + 0xcc, 0x8d, 0x02, 0xe0, 0x33, 0x56, 0x7c, 0x10, 0x07, 0x55, 0x19, 0x56, + 0xe6, 0x9b, 0xef, 0xbf, 0x70, 0x1f, 0x5e, 0x00, 0x52, 0x15, 0x2f, 0x5e, + 0x58, 0xb1, 0xb3, 0x40, 0xca, 0x5a, 0xf2, 0x62, 0xd2, 0xc8, 0xa2, 0x28, + 0x9a, 0x5d, 0xf5, 0xac, 0xb6, 0xc9, 0xce, 0x69, 0x59, 0x50, 0x72, 0x64, + 0x2c, 0x29, 0x2e, 0x2f, 0x61, 0xb0, 0x6e, 0x7e, 0xa4, 0x4e, 0x59, 0x40, + 0xb7, 0xd4, 0x73, 0x49, 0x4a, 0x8a, 0xd4, 0x19, 0x26, 0x23, 0x8f, 0x18, + 0x1f, 0xa4, 0x6f, 0x2c, 0x0f, 0x67, 0xba, 0xd5, 0x42, 0xa6, 0x22, 0x9d, + 0x1a, 0x87, 0x71, 0xd4, 0x4b, 0xe5, 0x7b, 0x6f, 0xa3, 0x5c, 0xdb, 0xf5, + 0x25, 0xbd, 0xe6, 0xa2, 0xab, 0x28, 0x11, 0x75, 0xf7, 0xfa, 0x89, 0x63, + 0x85, 0x3d, 0x31, 0xda, 0xa1, 0x1c, 0x20, 0xaa, 0x66, 0xb4, 0xad, 0x3f, + 0x6c, 0xcc, 0xcd, 0x0f, 0xf2, 0x55, 0xe5, 0x47, 0x37, 0x14, 0x6e, 0xe0, + 0x2d, 0xd6, 0x68, 0x20, 0xe8, 0x29, 0xbe, 0xd3, 0x21, 0xe5, 0xf9, 0x66, + 0x0e, 0x5a, 0xbc, 0xca, 0xbc, 0x97, 0x81, 0xc6, 0x99, 0x16, 0xab, 0x2c, + 0x6f, 0x9f, 0x6d, 0xbf, 0x4f, 0xf9, 0x66, 0xe6, 0x0d, 0xed, 0x40, 0xb0, + 0x88, 0x54, 0x7c, 0x73, 0xbe, 0x1b, 0x60, 0x22, 0xa8, 0x54, 0xa0, 0x3f, + 0xdf, 0x7d, 0x78, 0x89, 0x1f, 0x44, 0x42, 0x33, 0xff, 0xf4, 0x05, 0xaa, + 0x5d, 0x5b, 0x36, 0x10, 0xd5, 0x35, 0x90, 0x3f, 0x6b, 0xf7, 0x18, 0xdd, + 0xc2, 0xdf, 0x72, 0xe9, 0x65, 0xa0, 0x54, 0xa8, 0xae, 0x62, 0x90, 0xec, + 0x1c, 0x64, 0x42, 0x3e, 0x12, 0x1b, 0xcd, 0x2c, 0xe7, 0x3f, 0xfe, 0x8e, + 0x16, 0xeb, 0x4d, 0xf5, 0x15, 0xee, 0x08, 0xaa, 0x00, 0x49, 0x31, 0xf3, + 0x43, 0xc6, 0xfa, 0x38, 0x6d, 0x4d, 0x51, 0x54, 0x45, 0x2b, 0x20, 0x5e, + 0x06, 0xc7, 0x42, 0xd8, 0x40, 0x1c, 0x82, 0x20, 0x19, 0xde, 0xf3, 0xfb, + 0x3d, 0x10, 0xe6, 0x14, 0x89, 0x8b, 0xd6, 0xeb, 0x72, 0x78, 0x82, 0xca, + 0x16, 0xbf, 0x00, 0x00, 0x99, 0x08, 0x2c, 0x2c, 0x88, 0x5a, 0x0f, 0x05, + 0x00, 0xd8, 0xea, 0x23, 0xa0, 0xa6, 0x2e, 0x19, 0x40, 0xf8, 0xc1, 0x66, + 0xe6, 0xa2, 0x9b, 0x7c, 0x4a, 0x43, 0x22, 0x52, 0x8f, 0x08, 0xc2, 0x57, + 0x06, 0xf4, 0x78, 0x5c, 0x0f, 0x17, 0x00, 0x6c, 0x3a, 0xbb, 0x6a, 0xd4, + 0x23, 0x19, 0x04, 0xa2, 0x82, 0x51, 0x13, 0x9b, 0x31, 0x8c, 0x66, 0x76, + 0x4f, 0xdb, 0xab, 0xaf, 0xc5, 0x86, 0x01, 0x6c, 0xc5, 0x4d, 0x35, 0xf0, + 0xe6, 0xac, 0x37, 0x93, 0xa7, 0x14, 0x6a, 0xee, 0xd9, 0x7b, 0x02, 0x22, + 0xb5, 0x65, 0xd1, 0x84, 0xc9, 0x87, 0x21, 0xe6, 0xd7, 0x1e, 0xea, 0xc3, + 0x45, 0x53, 0x08, 0x31, 0x57, 0xfe, 0xc2, 0x06, 0x73, 0xbd, 0x5e, 0x58, + 0x59, 0x7b, 0x02, 0x83, 0x42, 0x4f, 0xd1, 0x41, 0x58, 0xa0, 0xb9, 0x57, + 0xa0, 0x8d, 0x24, 0x02, 0xb9, 0x7f, 0x4a, 0x6f, 0x29, 0xf7, 0xa4, 0x35, + 0xe9, 0x93, 0x4c, 0x3d, 0x2d, 0xe1, 0x6c, 0x51, 0x69, 0x27, 0x20, 0xc0, + 0x12, 0x8b, 0xa7, 0x5b, 0xda, 0xa1, 0x69, 0xca, 0x4a, 0xb9, 0xf1, 0xae, + 0xfa, 0xf9, 0x9d, 0xca, 0x36, 0xf8, 0xba, 0x55, 0xe5, 0x06, 0x13, 0x0a, + 0x30, 0xad, 0x8c, 0xcb, 0x66, 0xd9, 0xce, 0xa0, 0x9c, 0x90, 0x8d, 0xd1, + 0x98, 0xa9, 0x8d, 0xd1, 0x3c, 0x50, 0x3a, 0xef, 0xe1, 0x65, 0x44, 0x13, + 0x12, 0x9e, 0xca, 0x20, 0xea, 0x9f, 0x6c, 0x62, 0x55, 0x3c, 0xfa, 0x14, + 0x73, 0xa5, 0x40, 0x90, 0x2f, 0x12, 0x3d, 0xd1, 0xf3, 0x4a, 0xd6, 0xbf, + 0x67, 0x27, 0xcb, 0x62, 0x2b, 0x96, 0x07, 0x9c, 0x0d, 0x94, 0x3e, 0xfb, + 0x08, 0x6d, 0x45, 0x96, 0xc5, 0x9d, 0x26, 0x97, 0xcd, 0xd9, 0xa8, 0xcf, + 0xac, 0x3f, 0x57, 0xe6, 0x9a, 0xe5, 0xb7, 0x2e, 0xad, 0x14, 0x73, 0xb3, + 0xb1, 0x1c, 0x0b, 0x53, 0x2c, 0xe7, 0xc1, 0x97, 0xbf, 0x55, 0x11, 0x37, + 0xf9, 0x3f, 0xbd, 0xe5, 0xe7, 0x96, 0xb2, 0x06, 0xb9, 0xd3, 0x10, 0xcd, + 0xbe, 0x03, 0x1e, 0x88, 0x94, 0x07, 0xd8, 0x36, 0x88, 0xd1, 0x06, 0x60, + 0x2c, 0xf2, 0x41, 0x03, 0x0b, 0x2f, 0x8b, 0x69, 0x5c, 0x52, 0xa7, 0x54, + 0xe8, 0x2b, 0xfa, 0x16, 0x13, 0x4f, 0x97, 0xe2, 0x0e, 0xf6, 0xf3, 0xcc, + 0xf9, 0x5c, 0xe2, 0xdd, 0x92, 0xae, 0xe7, 0x19, 0x0b, 0xcb, 0xe2, 0x5c, + 0x51, 0x72, 0xf3, 0x07, 0x1f, 0x6a, 0x7b, 0xf2, 0xf3, 0x92, 0xca, 0x81, + 0x48, 0xa4, 0x71, 0x5a, 0xd5, 0x43, 0xdd, 0xd5, 0xaf, 0xb0, 0x3e, 0x52, + 0xd9, 0xbf, 0x7f, 0xc0, 0xe2, 0xae, 0x29, 0x50, 0x0b, 0x75, 0x07, 0xaa, + 0x44, 0x00, 0x65, 0xe9, 0x53, 0x2a, 0x14, 0x64, 0xed, 0xda, 0xb8, 0x79, + 0x7d, 0x30, 0x45, 0x11, 0x7e, 0x04, 0x40, 0x48, 0xbf, 0x4a, 0x87, 0x9f, + 0x83, 0x6b, 0xe6, 0xe2, 0xa6, 0x90, 0x4f, 0xf2, 0xf3, 0xd6, 0xc1, 0x10, + 0xab, 0xa0, 0xc3, 0x56, 0xfa, 0x72, 0xc5, 0x96, 0x23, 0xb0, 0x6c, 0x6e, + 0x1a, 0x36, 0x0e, 0x30, 0xa5, 0x0f, 0x65, 0xf7, 0x7b, 0xce, 0x59, 0x45, + 0x6d, 0x68, 0x59, 0x22, 0x2e, 0x28, 0x19, 0x47, 0x2a, 0xc7, 0xc1, 0x5a, + 0xdb, 0x00, 0x42, 0xf6, 0x14, 0x52, 0x38, 0x79, 0x74, 0x5b, 0xd5, 0x4b, + 0x59, 0xbf, 0xf5, 0x19, 0xca, 0x28, 0x41, 0x55, 0xea, 0x56, 0x17, 0xe4, + 0xfe, 0xe7, 0xaa, 0xd2, 0xde, 0xdb, 0x17, 0x9d, 0x1b, 0x19, 0x5a, 0xd2, + 0xc0, 0x62, 0xde, 0x2d, 0x4b, 0x7d, 0x46, 0x56, 0x57, 0xca, 0x9b, 0x55, + 0x4f, 0xe0, 0xdf, 0xb8, 0x32, 0x7f, 0xc7, 0xa6, 0x45, 0x2f, 0x14, 0xec, + 0xe5, 0x67, 0x7c, 0x89, 0x47, 0xa6, 0x2e, 0x81, 0x75, 0x2a, 0x02, 0xd0, + 0xe0, 0x0d, 0x71, 0x92, 0xf0, 0x84, 0x21, 0x96, 0x97, 0x5c, 0xac, 0x31, + 0xa5, 0x9b, 0x7f, 0x2a, 0xfd, 0x45, 0x6e, 0x08, 0xa0, 0xc1, 0x21, 0x5c, + 0x04, 0x54, 0xa5, 0x8c, 0xaa, 0xc2, 0xd9, 0x64, 0x1c, 0xcb, 0xdc, 0xaa, + 0x79, 0xdb, 0xcf, 0x83, 0x8c, 0x85, 0x66, 0xda, 0xd6, 0x58, 0xd9, 0xf9, + 0xd0, 0xf1, 0x43, 0x71, 0x1e, 0x6f, 0x62, 0x10, 0x5b, 0xca, 0x29, 0x16, + 0xb0, 0x6e, 0xc1, 0xf3, 0x0a, 0xd3, 0x36, 0xce, 0xa7, 0xf7, 0x93, 0xf8, + 0x18, 0x44, 0xbc, 0x97, 0x60, 0x30, 0x4e, 0xa2, 0x41, 0x23, 0xcc, 0xaa, + 0x56, 0xaf, 0xe5, 0xfe, 0x55, 0x58, 0x45, 0x9b, 0x17, 0xd3, 0x52, 0x15, + 0x98, 0x0a, 0xa0, 0xcd, 0x83, 0x0f, 0xb4, 0x75, 0xb8, 0x5e, 0xc2, 0xe9, + 0x2f, 0xfb, 0xa6, 0xda, 0x9d, 0x45, 0xd4, 0x24, 0x61, 0xa5, 0x29, 0x77, + 0xa2, 0xba, 0x20, 0x5e, 0xaa, 0x9c, 0xe2, 0xfd, 0xb5, 0xe6, 0xbd, 0x8c, + 0x1b, 0x53, 0x78, 0xa6, 0xf4, 0x32, 0x15, 0xa9, 0xc3, 0xe8, 0x2b, 0xc5, + 0xde, 0xbe, 0x4b, 0x0c, 0xb7, 0x78, 0xf2, 0x1e, 0x30, 0x5e, 0x39, 0x39, + 0x84, 0x7f, 0x36, 0x32, 0xa9, 0x1d, 0xff, 0x0f, 0x6f, 0x6c, 0xa2, 0x61, + 0x62, 0x1a, 0x84, 0x98, 0xbb, 0x00, 0x58, 0xfa, 0xdf, 0xab, 0x53, 0x63, + 0x12, 0x18, 0xec, 0x54, 0xd8, 0xc1, 0xbf, 0x00, 0x90, 0xae, 0x0c, 0x90, + 0x03, 0xda, 0x1e, 0x16, 0x8e, 0x93, 0xa9, 0x50, 0xdb, 0x73, 0xed, 0x59, + 0x2e, 0x95, 0xd9, 0xcd, 0x9c, 0x41, 0x8b, 0x02, 0x48, 0xb5, 0x38, 0xf9, + 0x5e, 0x49, 0xff, 0xf9, 0x6e, 0x45, 0xc9, 0x09, 0xc3, 0x2e, 0xfa, 0x8d, + 0xf1, 0x18, 0xbc, 0x4c, 0x55, 0x52, 0xc7, 0xdc, 0xb3, 0xb8, 0xb9, 0xe6, + 0xc2, 0x39, 0x6e, 0x55, 0xe5, 0x09, 0x47, 0xe5, 0xec, 0x64, 0x4f, 0xf6, + 0x43, 0xa6, 0xad, 0xbd, 0x50, 0x88, 0x96, 0x83, 0x8c, 0x83, 0x31, 0x20, + 0x28, 0x44, 0x32, 0xe8, 0xa3, 0xb8, 0xdc, 0xe0, 0x30, 0x8b, 0x2d, 0xe4, + 0x29, 0xcd, 0x31, 0x49, 0xc2, 0x18, 0x8e, 0x25, 0x95, 0x5b, 0x3c, 0xd2, + 0x25, 0x0d, 0x15, 0x41, 0x88, 0x24, 0x92, 0xca, 0x59, 0xb9, 0x16, 0x3a, + 0x5d, 0x6c, 0x2d, 0x6c, 0x30, 0x8e, 0xc4, 0x74, 0xcc, 0x5d, 0x85, 0xda, + 0xdd, 0x56, 0xb5, 0x8a, 0xf3, 0x79, 0x99, 0x67, 0x65, 0xf5, 0x9b, 0x9a, + 0xa4, 0x8d, 0x00, 0x84, 0x3b, 0x06, 0xee, 0x6a, 0xa6, 0x4b, 0x04, 0x14, + 0x3b, 0xa8, 0xdb, 0x88, 0xd6, 0xe1, 0x40, 0x24, 0x26, 0x3e, 0x12, 0xbf, + 0xfa, 0xa3, 0x1a, 0x2d, 0x5c, 0x3d, 0xab, 0xdb, 0x0d, 0xf1, 0x46, 0x7f, + 0x54, 0x83, 0x04, 0xa2, 0x3a, 0x0c, 0x3e, 0x2f, 0x1f, 0x87, 0xaa, 0x93, + 0x02, 0x9b, 0x99, 0xc9, 0x7a, 0x59, 0x94, 0xd5, 0x2c, 0xd0, 0x56, 0xdb, + 0xa1, 0xce, 0xe0, 0xb0, 0x60, 0xfd, 0x3e, 0xd8, 0xb3, 0xe1, 0x0d, 0x50, + 0x1a, 0xa3, 0xe5, 0x4d, 0x07, 0xdc, 0xd8, 0x0a, 0xd9, 0x38, 0x89, 0x6e, + 0x70, 0x37, 0x04, 0x90, 0xbc, 0x0a, 0x45, 0x7e, 0xf8, 0xf1, 0x40, 0xe4, + 0xb7, 0xfe, 0xfe, 0xa9, 0x52, 0x55, 0x39, 0x7b, 0x57, 0x06, 0x09, 0x51, + 0x4c, 0x0c, 0x5c, 0x23, 0x8f, 0x9a, 0xcd, 0x4a, 0x94, 0x7c, 0xc6, 0x29, + 0x52, 0xdd, 0x56, 0x37, 0x6f, 0x2a, 0xfc, 0x8a, 0x0a, 0xd4, 0xe8, 0x6c, + 0x5a, 0x2d, 0x58, 0x1c, 0x91, 0x54, 0x0f, 0x87, 0xdb, 0x83, 0x91, 0x17, + 0xd8, 0x91, 0xbb, 0xfe, 0x22, 0x9c, 0xf6, 0xef, 0xd3, 0xee, 0x86, 0xe1, + 0xf0, 0x30, 0xc0, 0x58, 0x54, 0xdf, 0x49, 0x0e, 0xd1, 0x04, 0xf3, 0x67, + 0xc7, 0xcc, 0xcf, 0x0e, 0x8b, 0xb7, 0x6a, 0x89, 0x0b, 0x95, 0x12, 0xa2, + 0x6a, 0x1c, 0x6c, 0x4f, 0xa5, 0x64, 0x3f, 0xdc, 0x83, 0x88, 0x36, 0xcd, + 0x42, 0x4a, 0xe1, 0xe0, 0x29, 0xda, 0xc2, 0xe6, 0x95, 0xa5, 0xf9, 0x60, + 0xf8, 0x74, 0x99, 0x36, 0xb3, 0x50, 0xda, 0x59, 0x24, 0xf4, 0x80, 0xc8, + 0x77, 0x4f, 0xac, 0x23, 0x03, 0x02, 0x18, 0x84, 0xad, 0x2a, 0x61, 0xf0, + 0x7c, 0xda, 0xa0, 0x37, 0xbf, 0xcd, 0x65, 0xbb, 0x27, 0xb3, 0x7b, 0xc4, + 0xd0, 0x1e, 0x23, 0xff, 0x70, 0xe4, 0x3c, 0x2c, 0x06, 0x15, 0xb6, 0x11, + 0xbc, 0xd2, 0x26, 0xc5, 0x7e, 0xf6, 0x62, 0x29, 0x30, 0xa0, 0xe5, 0xab, + 0xde, 0x70, 0x98, 0x24, 0xe7, 0xe1, 0x27, 0x0d, 0xf4, 0xe1, 0xd5, 0x6a, + 0xcb, 0x7e, 0x59, 0xde, 0xe7, 0x8b, 0x69, 0xa2, 0xb9, 0xde, 0xd0, 0xd0, + 0x1f, 0x3f, 0xff, 0xb8, 0x44, 0x51, 0xf6, 0xfa, 0x75, 0x55, 0x3e, 0xe6, + 0x7a, 0x77, 0x7a, 0xe2, 0x6c, 0x45, 0x0a, 0x9a, 0xf0, 0x70, 0xc6, 0x4a, + 0x53, 0xc7, 0x2b, 0xf6, 0x6a, 0x89, 0xef, 0x5e, 0x2c, 0x1e, 0xd4, 0x6b, + 0x9a, 0x07, 0x18, 0x51, 0x33, 0x65, 0xa9, 0x9a, 0xf9, 0xbf, 0x40, 0xa3, + 0xe9, 0x1d, 0x7a, 0x64, 0xc7, 0xac, 0x29, 0xe2, 0x39, 0xcb, 0x57, 0x8b, + 0x53, 0xc3, 0xd1, 0x2f, 0xfa, 0xa8, 0x7c, 0xb6, 0xc6, 0xd7, 0x8b, 0x22, + 0xb6, 0x72, 0x86, 0xa0, 0x24, 0xbf, 0xfa, 0x5b, 0xd1, 0x11, 0x7e, 0xc1, + 0x59, 0x90, 0x3b, 0x58, 0x03, 0x39, 0xbb, 0x25, 0x63, 0x8c, 0xe6, 0x08, + 0xbd, 0x2d, 0xe7, 0x78, 0x1c, 0x2d, 0x4c, 0x7c, 0x06, 0x0a, 0xd9, 0x31, + 0x98, 0x90, 0x23, 0x8e, 0xc7, 0x60, 0x1c, 0x9c, 0x70, 0x5c, 0xd3, 0x0d, + 0xb3, 0xa9, 0x58, 0x0f, 0x6d, 0x0e, 0xa7, 0xcb, 0x27, 0xe5, 0xd0, 0xdb, + 0xa3, 0x60, 0xec, 0x2c, 0x0a, 0xe2, 0x50, 0xfd, 0xb5, 0x41, 0x08, 0x4a, + 0x49, 0x9e, 0xd6, 0x77, 0xde, 0xf6, 0x5d, 0x5a, 0x4f, 0x2a, 0x61, 0x61, + 0xcf, 0xd4, 0x96, 0x0d, 0xfb, 0x0a, 0x83, 0x50, 0x62, 0x61, 0x6a, 0x44, + 0x94, 0xb8, 0xab, 0x57, 0xf7, 0xf9, 0xb9, 0xc4, 0x39, 0x65, 0xbc, 0x0d, + 0x4e, 0xf0, 0x38, 0xc3, 0x7d, 0x1f, 0xeb, 0x3f, 0x80, 0x6b, 0xe5, 0x90, + 0xb9, 0xa2, 0xce, 0x6a, 0xa6, 0x18, 0x40, 0xc9, 0x59, 0x5e, 0xee, 0xf7, + 0x41, 0x84, 0xe4, 0xf1, 0x47, 0x85, 0x7d, 0x8a, 0x38, 0x1f, 0xb7, 0xee, + 0xd5, 0x18, 0xa2, 0xdb, 0xc5, 0xef, 0x65, 0xce, 0xae, 0x1b, 0x9f, 0xb4, + 0xe1, 0x00, 0x7d, 0xfb, 0x6f, 0xf3, 0x76, 0xde, 0x73, 0x54, 0xde, 0xcc, + 0x35, 0x04, 0x43, 0x18, 0x79, 0x7a, 0xd6, 0xa5, 0xd9, 0xc0, 0x45, 0x19, + 0x87, 0x93, 0xb3, 0xd0, 0x09, 0xe4, 0x0b, 0x4a, 0xa8, 0xa8, 0xd6, 0xe0, + 0x14, 0x25, 0x71, 0xce, 0x58, 0xbc, 0xbd, 0x32, 0x44, 0x8d, 0x08, 0x1e, + 0x2a, 0x44, 0xa1, 0x0f, 0xff, 0xa6, 0xed, 0x42, 0x62, 0xb3, 0x40, 0xb6, + 0xff, 0x81, 0xef, 0x3d, 0xa8, 0x0a, 0xe4, 0x44, 0x78, 0x8a, 0x74, 0xde, + 0x4e, 0x37, 0x1b, 0xc9, 0x14, 0x14, 0xb8, 0x6c, 0xcf, 0x84, 0x0b, 0x2d, + 0x58, 0x44, 0xfd, 0x25, 0x95, 0x18, 0x55, 0x70, 0xbc, 0xb4, 0x9b, 0xd2, + 0xcc, 0xd6, 0x3e, 0x57, 0x7d, 0xf5, 0x2d, 0x72, 0xce, 0xa8, 0xab, 0x88, + 0xa1, 0xc6, 0x74, 0x05, 0x9c, 0x4b, 0x75, 0xb1, 0xf2, 0x55, 0x5a, 0x05, + 0xd4, 0x41, 0xea, 0xa8, 0x0c, 0x1b, 0x74, 0x1c, 0xa5, 0x4f, 0x70, 0x18, + 0x4d, 0x29, 0x6a, 0x9c, 0x9b, 0xe8, 0x5a, 0x36, 0xe0, 0x89, 0x64, 0xfa, + 0xdd, 0xe8, 0x69, 0x41, 0x20, 0xba, 0x7c, 0x50, 0x9c, 0x4a, 0xad, 0x48, + 0xa2, 0xc9, 0x93, 0x09, 0x0b, 0x29, 0x6f, 0x43, 0x5c, 0xe6, 0x89, 0xf7, + 0x20, 0xb4, 0xa6, 0x96, 0xcf, 0x6f, 0xd1, 0xd8, 0x50, 0x75, 0x5d, 0xf5, + 0x04, 0x52, 0xdf, 0x2d, 0xcf, 0x02, 0xb4, 0xd4, 0xcb, 0x62, 0x30, 0xa9, + 0x4c, 0x6f, 0xd0, 0x72, 0x9a, 0x6c, 0x9b, 0x9f, 0xb7, 0xc5, 0xab, 0x4b, + 0x2a, 0xf0, 0xf1, 0x50, 0xef, 0xb1, 0x9f, 0x45, 0xe5, 0x28, 0x50, 0x48, + 0x15, 0x72, 0xca, 0x0e, 0x30, 0x3f, 0x6e, 0x37, 0xc5, 0x0d, 0xb5, 0xed, + 0x24, 0xef, 0x39, 0xc0, 0xad, 0x6e, 0xe6, 0x26, 0xf2, 0x08, 0x5b, 0xc3, + 0x6b, 0x74, 0x99, 0x55, 0x20, 0xa6, 0xfe, 0x78, 0x0b, 0xb1, 0x50, 0x7d, + 0x7f, 0xcc, 0x9c, 0x0f, 0x7d, 0x44, 0x5c, 0x0b, 0x14, 0x4b, 0x04, 0x01, + 0x05, 0x42, 0xec, 0x6e, 0x46, 0x70, 0xa6, 0x70, 0xb6, 0x74, 0x18, 0x2b, + 0xf2, 0xcb, 0x0e, 0x99, 0xe0, 0xeb, 0xde, 0x9c, 0x9f, 0xcd, 0xad, 0x12, + 0xcc, 0x9d, 0x5e, 0x40, 0xe0, 0x89, 0x02, 0x44, 0x1b, 0xce, 0xd0, 0xdc, + 0x98, 0xf8, 0xf1, 0xa9, 0xf6, 0x55, 0xa6, 0x67, 0x79, 0x54, 0xa9, 0xf7, + 0xf8, 0x56, 0xbf, 0x2a, 0xc3, 0x51, 0x18, 0x37, 0x18, 0xf4, 0x0e, 0xdb, + 0xd1, 0x7d, 0xe9, 0xa0, 0xd8, 0x85, 0xae, 0x0d, 0x9c, 0x58, 0x2d, 0x01, + 0xa8, 0xf1, 0xb1, 0xf8, 0x40, 0x1f, 0xaa, 0x69, 0x7e, 0xfa, 0x95, 0x73, + 0xb7, 0xa2, 0xa0, 0x7b, 0xfd, 0xaf, 0xfb, 0x77, 0x3f, 0xd9, 0xfc, 0xb6, + 0x6c, 0xd5, 0xaf, 0x62, 0x37, 0x0b, 0xd9, 0xff, 0x94, 0xdc, 0xcf, 0xde, + 0x14, 0xf6, 0x1f, 0x08, 0xa0, 0xc1, 0x0c, 0x21, 0x07, 0xc9, 0xc1, 0x8b, + 0x55, 0x07, 0x4a, 0xf9, 0x15, 0xa0, 0x0f, 0x78, 0x47, 0x12, 0xba, 0xd2, + 0xd3, 0x08, 0xa8, 0xeb, 0xc3, 0xc0, 0xb5, 0x49, 0x9d, 0x7c, 0x7b, 0x4f, + 0x05, 0x85, 0x7c, 0x2c, 0x21, 0x18, 0x5a, 0x21, 0xa5, 0x16, 0xf5, 0xe5, + 0x9a, 0x2e, 0xdf, 0xf3, 0xcb, 0x4f, 0xac, 0x55, 0xb6, 0x79, 0x64, 0x40, + 0x97, 0x76, 0xe1, 0x96, 0x25, 0xce, 0xa1, 0x87, 0x86, 0xbf, 0x23, 0x0b, + 0xc9, 0x04, 0x64, 0xcc, 0x07, 0x96, 0x62, 0xbd, 0xb8, 0x39, 0x6d, 0xba, + 0x54, 0xc3, 0x52, 0x72, 0x70, 0x0a, 0x8e, 0x75, 0x7a, 0x55, 0x81, 0xc0, + 0x31, 0x18, 0x7a, 0xaa, 0x87, 0x23, 0xff, 0xb5, 0xe2, 0xbf, 0x46, 0x76, + 0x29, 0x41, 0xc9, 0xfb, 0x21, 0xe2, 0xf7, 0xca, 0x24, 0x05, 0xba, 0xd3, + 0x8d, 0xe4, 0x8b, 0x80, 0x53, 0x6c, 0xa9, 0x46, 0x9a, 0xb0, 0x60, 0x7c, + 0x52, 0x0c, 0xa1, 0x52, 0x61, 0xf6, 0xeb, 0x65, 0xbe, 0xde, 0xc1, 0xc0, + 0x71, 0xb2, 0x2c, 0x88, 0x1c, 0x64, 0x67, 0xf5, 0x45, 0xb3, 0x70, 0x92, + 0xd1, 0xa4, 0xb9, 0x73, 0x9d, 0x80, 0x92, 0xc8, 0xb8, 0xb0, 0x24, 0xb6, + 0x56, 0x81, 0xf4, 0xbe, 0xb7, 0x15, 0x2f, 0x96, 0xa9, 0xee, 0xfa, 0x22, + 0xa8, 0x2a, 0x95, 0x2a, 0x4c, 0x05, 0x76, 0x01, 0x84, 0x01, 0xea, 0x46, + 0xd3, 0xa7, 0x98, 0x3e, 0x65, 0xab, 0x3d, 0x54, 0x2c, 0xd6, 0xed, 0x9d, + 0x2d, 0x9e, 0x11, 0x75, 0x67, 0xa2, 0x10, 0x1a, 0x85, 0xe5, 0x4c, 0x0f, + 0x07, 0xe9, 0x7f, 0x99, 0x39, 0xbe, 0x61, 0x4f, 0xbb, 0xc0, 0xea, 0xfd, + 0x4a, 0x8c, 0xc0, 0xdc, 0x18, 0x80, 0x5d, 0x01, 0x87, 0x42, 0x3b, 0x69, + 0xe6, 0xab, 0xf2, 0x65, 0x5e, 0xbf, 0xeb, 0x61, 0xec, 0xa5, 0x5d, 0x0e, + 0xa0, 0xd8, 0x0c, 0xe0, 0x2d, 0x44, 0x77, 0x15, 0x28, 0x8a, 0x5b, 0x52, + 0x0a, 0x80, 0x62, 0x14, 0x53, 0x21, 0x0b, 0x66, 0x70, 0x46, 0xc5, 0x61, + 0xea, 0x6f, 0xe3, 0x71, 0x4a, 0x84, 0x5c, 0xbd, 0x14, 0x0b, 0x0b, 0x81, + 0xbc, 0x3f, 0x57, 0x54, 0x0e, 0x19, 0xcf, 0x28, 0xed, 0x57, 0x24, 0xc9, + 0xde, 0x74, 0xb3, 0xca, 0x46, 0xfa, 0x0e, 0xf1, 0x00, 0x54, 0x8c, 0x0f, + 0x00, 0x39, 0xaf, 0x70, 0xb3, 0x2d, 0xc9, 0x9d, 0xdd, 0xac, 0x97, 0xfe, + 0x44, 0x65, 0x8a, 0x4a, 0xb3, 0x31, 0x6d, 0x53, 0x85, 0x9e, 0x06, 0x21, + 0x27, 0x34, 0x49, 0x6f, 0xc0, 0xf0, 0x50, 0x0c, 0xa6, 0xc9, 0x7f, 0x7d, + 0x7c, 0xac, 0xbf, 0x64, 0xf4, 0x96, 0x77, 0xb3, 0xc0, 0xc8, 0x41, 0xc2, + 0x28, 0x31, 0x18, 0xee, 0xa8, 0x40, 0x44, 0x79, 0x68, 0xa8, 0xb0, 0xb2, + 0x21, 0x17, 0x0f, 0xc4, 0x64, 0xd5, 0xa4, 0x82, 0x41, 0x7a, 0xb4, 0xfb, + 0x80, 0x5f, 0xfe, 0x69, 0x8b, 0x64, 0x0e, 0xa4, 0x51, 0xa5, 0x58, 0x8f, + 0x42, 0xd2, 0xd8, 0x3c, 0x05, 0x09, 0x7d, 0xeb, 0x3e, 0x89, 0x32, 0x0d, + 0x87, 0x2d, 0xc5, 0x0d, 0x0c, 0xb0, 0xb7, 0x5b, 0x07, 0x07, 0x80, 0x90, + 0x5f, 0xd8, 0x23, 0x83, 0xc2, 0x7f, 0xd6, 0x23, 0xb4, 0xd4, 0x5c, 0xa8, + 0xb9, 0x8f, 0x34, 0xde, 0xf1, 0x7e, 0x16, 0xe9, 0x68, 0xe3, 0x14, 0x4a, + 0x0f, 0x9b, 0xff, 0xd9, 0xf1, 0xf8, 0x21, 0xfa, 0x7c, 0x70, 0xc4, 0xd1, + 0xfa, 0x8a, 0x59, 0xc5, 0x3f, 0xb8, 0xb2, 0x0a, 0x1f, 0x03, 0x02, 0x4e, + 0xf5, 0xf6, 0x6a, 0xa6, 0x2e, 0x8a, 0xf3, 0xba, 0x5e, 0x08, 0x23, 0xd9, + 0xf4, 0x4d, 0x65, 0x05, 0x32, 0x98, 0x8e, 0x56, 0x74, 0x19, 0x06, 0x03, + 0x06, 0xc1, 0xc1, 0x81, 0x52, 0x61, 0xf0, 0x1f, 0x5b, 0x80, 0xaa, 0x12, + 0x32, 0xa3, 0x4c, 0x5c, 0xc4, 0x8d, 0xd2, 0x5f, 0xd5, 0x03, 0x70, 0x23, + 0xa5, 0xbf, 0x06, 0x3a, 0x21, 0xf0, 0x96, 0xdf, 0x93, 0x63, 0x6c, 0xb0, + 0x1f, 0x76, 0x75, 0xa5, 0x59, 0xe5, 0xe4, 0xbc, 0x0f, 0x68, 0x89, 0x99, + 0xab, 0x16, 0x29, 0x06, 0x3a, 0xb5, 0xd0, 0x86, 0xae, 0x87, 0x8d, 0x6c, + 0xc0, 0xdb, 0x92, 0xa8, 0xea, 0x3e, 0x87, 0x20, 0xc4, 0xe7, 0x57, 0x00, + 0x00, 0xa3, 0x08, 0x6c, 0x98, 0x37, 0x15, 0x17, 0x84, 0x04, 0xc9, 0x9b, + 0x63, 0x15, 0xb0, 0xca, 0xa4, 0xda, 0xce, 0x08, 0x92, 0xc5, 0x5e, 0xe0, + 0x13, 0x04, 0xb0, 0xd6, 0x3b, 0x06, 0x08, 0x45, 0xd6, 0x7f, 0x47, 0x40, + 0x63, 0xe8, 0xe7, 0xb7, 0xbb, 0xee, 0x92, 0x51, 0xbe, 0x03, 0xe5, 0xc0, + 0x0e, 0x81, 0x75, 0x07, 0x82, 0x80, 0x64, 0xb9, 0x47, 0x38, 0x06, 0x98, + 0x52, 0x81, 0x7a, 0xd3, 0x82, 0xae, 0xf6, 0x3c, 0x94, 0x27, 0xc5, 0xb0, + 0xeb, 0x61, 0x58, 0x46, 0x56, 0xcd, 0x12, 0x93, 0x34, 0x9e, 0xe8, 0x29, + 0xfd, 0x31, 0x51, 0x7a, 0x94, 0x7d, 0xf7, 0xb9, 0xc9, 0x44, 0x55, 0x3b, + 0x14, 0xa9, 0x06, 0x21, 0x4b, 0x00, 0xbb, 0x66, 0xf8, 0xc8, 0x64, 0xf5, + 0x65, 0xd5, 0x25, 0xb6, 0xec, 0x90, 0x6e, 0xba, 0xdb, 0xe4, 0x32, 0x86, + 0x98, 0x57, 0xe0, 0x71, 0x8a, 0x4a, 0xac, 0x3e, 0x48, 0x5e, 0x5f, 0x8c, + 0x56, 0xf5, 0xac, 0xad, 0xfa, 0x0d, 0x94, 0x87, 0x9c, 0xb3, 0xa1, 0xc2, + 0x83, 0xe5, 0xf7, 0xae, 0x84, 0x29, 0x8d, 0x02, 0x18, 0x97, 0x82, 0x51, + 0x73, 0x6a, 0xe8, 0xde, 0x74, 0x71, 0x8b, 0x77, 0xec, 0xa0, 0x81, 0x9e, + 0x83, 0x09, 0x82, 0xf8, 0x33, 0x05, 0xed, 0x97, 0x80, 0x70, 0x8d, 0xf6, + 0x7f, 0xd6, 0x59, 0x2e, 0x9b, 0xf4, 0x0b, 0xcf, 0xef, 0x8b, 0x64, 0x0e, + 0x16, 0x70, 0x7b, 0x4e, 0x3d, 0x6c, 0x20, 0xd8, 0xad, 0x91, 0x13, 0xf9, + 0x15, 0x01, 0x0f, 0x5b, 0x28, 0x78, 0x56, 0x37, 0x69, 0x48, 0x3e, 0x47, + 0xff, 0x60, 0xb4, 0x10, 0x92, 0x7d, 0x85, 0x60, 0x19, 0xad, 0xb3, 0x41, + 0xc9, 0x04, 0x88, 0x5d, 0xf4, 0xd8, 0xb3, 0x57, 0xe5, 0xe5, 0x97, 0xed, + 0x86, 0xb9, 0xb2, 0x67, 0xb0, 0x1f, 0x23, 0xff, 0xb6, 0xc5, 0xba, 0xf8, + 0xd8, 0xa7, 0x71, 0xe1, 0xf0, 0x4b, 0x69, 0x58, 0x38, 0x14, 0x6a, 0xd5, + 0xe3, 0x3e, 0xd5, 0x57, 0x1a, 0x55, 0xf5, 0x57, 0x3b, 0x7b, 0xee, 0xc8, + 0x1e, 0x86, 0xb7, 0xe5, 0x40, 0xb7, 0x32, 0x10, 0xc7, 0xe0, 0xca, 0x07, + 0x49, 0xcb, 0xd0, 0xb1, 0x91, 0x41, 0x2e, 0xdb, 0x3d, 0x03, 0x30, 0x60, + 0xa4, 0x30, 0xd0, 0x52, 0xe5, 0x6e, 0xd6, 0xa3, 0x69, 0x59, 0xaa, 0xd1, + 0x62, 0xca, 0x76, 0xaf, 0x6d, 0xa0, 0xb4, 0x12, 0x4d, 0xe5, 0x56, 0x5d, + 0x6e, 0xa8, 0x06, 0x26, 0x59, 0xc2, 0x14, 0xc2, 0xfb, 0x42, 0x4f, 0xbb, + 0xe2, 0xa2, 0xcb, 0x99, 0x27, 0xa7, 0x4a, 0xa2, 0xdc, 0x9c, 0x06, 0x13, + 0x15, 0x54, 0xad, 0x2a, 0x95, 0x3d, 0x37, 0xc8, 0x22, 0x73, 0xa0, 0xc1, + 0x48, 0x47, 0x1d, 0x30, 0x39, 0x2c, 0xdb, 0x39, 0xbc, 0xce, 0xf2, 0x5d, + 0xe6, 0xad, 0x6c, 0x58, 0x4e, 0x2a, 0x6f, 0xf1, 0xa6, 0xb1, 0x9f, 0xb0, + 0x6a, 0x61, 0xbb, 0x79, 0xd9, 0x78, 0x1a, 0x39, 0xd9, 0x5b, 0xa4, 0xd0, + 0xb1, 0x24, 0x2f, 0x03, 0x6d, 0x79, 0x07, 0xda, 0xb1, 0x64, 0x1c, 0xe2, + 0x37, 0x6e, 0xd2, 0xd8, 0xcf, 0x6f, 0x72, 0x5c, 0xe0, 0x89, 0xcb, 0x65, + 0x44, 0x1c, 0x9c, 0x3e, 0x20, 0xd4, 0xfb, 0x2a, 0x2e, 0x20, 0x0c, 0x4f, + 0x6d, 0x66, 0xb1, 0x64, 0xfa, 0x14, 0x44, 0xae, 0x3d, 0xcf, 0x36, 0x80, + 0xe6, 0xdb, 0x9b, 0xd5, 0x91, 0x14, 0x74, 0x84, 0x60, 0x3f, 0x53, 0xd6, + 0x7c, 0x1c, 0x87, 0xad, 0x21, 0x9d, 0x88, 0x02, 0x94, 0x58, 0x57, 0x14, + 0x95, 0xf2, 0xcb, 0xde, 0x62, 0x2a, 0xba, 0x23, 0xc8, 0xff, 0x27, 0x25, + 0x8b, 0xdc, 0xea, 0x84, 0x15, 0x11, 0x33, 0xeb, 0x8e, 0x65, 0xd7, 0x6d, + 0x03, 0x2e, 0xc7, 0x50, 0xc9, 0x71, 0x45, 0x47, 0x16, 0xe0, 0x3b, 0x0c, + 0xab, 0x9b, 0xf5, 0x5e, 0x1f, 0x4d, 0x05, 0x68, 0x81, 0xaa, 0xf5, 0x5f, + 0xf5, 0x17, 0xbb, 0xd2, 0xc9, 0x01, 0xc3, 0x60, 0xdc, 0xc1, 0x92, 0xdf, + 0xb7, 0x8c, 0x5f, 0x77, 0x39, 0xa1, 0xea, 0x0e, 0xdb, 0x3b, 0xca, 0x1c, + 0x98, 0x69, 0xf6, 0x4f, 0x36, 0x39, 0x2a, 0xdb, 0xf9, 0xfe, 0x7a, 0x42, + 0xbf, 0x7a, 0xad, 0x39, 0x44, 0x5d, 0x30, 0xe7, 0xdc, 0xa5, 0x63, 0xdc, + 0x53, 0x56, 0xde, 0x0c, 0xe3, 0xce, 0x5a, 0xdd, 0xd9, 0x16, 0xe3, 0x1e, + 0xf6, 0x96, 0xd5, 0x94, 0xac, 0xbc, 0xe6, 0x15, 0x05, 0xa6, 0x77, 0xf8, + 0x9c, 0x7c, 0xd7, 0xd8, 0xfd, 0xde, 0x5a, 0x1d, 0x87, 0x76, 0xc5, 0xaa, + 0xc1, 0xb1, 0xe4, 0xda, 0x6c, 0x14, 0xec, 0x56, 0x2d, 0x51, 0xf5, 0x08, + 0xf8, 0x32, 0xec, 0x0e, 0x40, 0x4f, 0x6d, 0x0d, 0xe3, 0x2a, 0x90, 0x29, + 0xaa, 0x54, 0x51, 0x81, 0xc3, 0x41, 0xda, 0x6c, 0xf6, 0xc0, 0xf4, 0xb9, + 0x7f, 0xfa, 0xae, 0x39, 0x61, 0x15, 0x82, 0xf7, 0x1b, 0x1f, 0x7e, 0xa9, + 0xd1, 0xf3, 0x28, 0xe2, 0x9c, 0x88, 0x3b, 0x62, 0x38, 0x04, 0xc6, 0xe1, + 0x69, 0x76, 0xbc, 0xdf, 0x87, 0xb1, 0x8a, 0x1d, 0x6f, 0xad, 0xc9, 0x50, + 0x43, 0x41, 0xa0, 0x25, 0x46, 0x2d, 0xa9, 0x2c, 0x69, 0xa5, 0x7d, 0x46, + 0xd5, 0x55, 0xbf, 0xcb, 0xdb, 0xd9, 0x7a, 0xc0, 0x13, 0x46, 0x60, 0x44, + 0xab, 0xda, 0xa8, 0x7d, 0x6a, 0xbb, 0x77, 0x6e, 0x1b, 0x45, 0xde, 0x11, + 0x98, 0x63, 0x8c, 0xe2, 0x52, 0xee, 0x5c, 0x9f, 0x56, 0xae, 0x7a, 0xa1, + 0xc6, 0x65, 0x53, 0x2c, 0x0d, 0x70, 0xfb, 0x1d, 0x33, 0xa9, 0x4b, 0x9a, + 0xea, 0xed, 0xaa, 0xd0, 0xf9, 0x94, 0x1d, 0xbe, 0x58, 0x1d, 0xa0, 0x93, + 0x4a, 0x16, 0x58, 0xdc, 0xb4, 0x3f, 0x57, 0x15, 0x26, 0x8b, 0x45, 0xfe, + 0x80, 0xa6, 0x05, 0x67, 0x41, 0x92, 0x8e, 0xa2, 0x50, 0x38, 0x96, 0xa0, + 0x4c, 0xab, 0x74, 0xdd, 0xec, 0x44, 0x0c, 0x09, 0xa1, 0x7c, 0x3e, 0x05, + 0x6c, 0xdc, 0xc9, 0xec, 0xc9, 0x14, 0x20, 0x29, 0xa7, 0x83, 0x08, 0x30, + 0x96, 0xae, 0x60, 0x07, 0x08, 0xeb, 0xf0, 0x19, 0x6d, 0x18, 0xa2, 0x80, + 0xc1, 0x5d, 0x2e, 0xc1, 0xd4, 0x6d, 0x08, 0x0f, 0x26, 0x20, 0x25, 0x24, + 0xfa, 0x55, 0x6c, 0x30, 0xd6, 0x29, 0xfb, 0x7f, 0xcc, 0xf4, 0x25, 0xaf, + 0xd1, 0x11, 0x2d, 0x78, 0x4d, 0x06, 0x05, 0x10, 0x42, 0xad, 0x97, 0xfc, + 0x4b, 0xd8, 0x1e, 0x0f, 0xb2, 0x28, 0xb4, 0x18, 0x39, 0xfc, 0x45, 0x03, + 0x4c, 0x07, 0x29, 0x30, 0xcc, 0xd8, 0x27, 0x8b, 0x81, 0x44, 0x25, 0x08, + 0xca, 0x95, 0x03, 0x2c, 0xd7, 0xd2, 0xc6, 0xbb, 0xad, 0xec, 0xb7, 0xaa, + 0xd6, 0xed, 0x85, 0x6b, 0x15, 0x80, 0x9a, 0x82, 0x37, 0x87, 0x0c, 0x32, + 0x9d, 0x8c, 0x6d, 0x2a, 0x8a, 0x5b, 0xfd, 0xe6, 0xe4, 0xea, 0xfc, 0x93, + 0x54, 0x85, 0x82, 0xc5, 0x6c, 0xa8, 0xd5, 0x05, 0x97, 0x50, 0xdb, 0x96, + 0x52, 0xce, 0x93, 0xbf, 0xec, 0x04, 0x4f, 0xc5, 0x32, 0xff, 0xf2, 0x96, + 0x67, 0x50, 0x8a, 0x48, 0xe4, 0x9c, 0x79, 0x64, 0xcd, 0x86, 0xc0, 0x61, + 0x2c, 0x7a, 0x98, 0x4a, 0x2e, 0x2c, 0x4c, 0xa2, 0x0f, 0x52, 0x87, 0x8a, + 0x31, 0x65, 0x1e, 0xa8, 0xff, 0x62, 0x00, 0x60, 0x8c, 0x35, 0x02, 0x88, + 0x20, 0x36, 0xc9, 0x5a, 0x8e, 0xa1, 0xe2, 0x3b, 0x7a, 0x8a, 0x40, 0xe7, + 0x4c, 0x9a, 0x2e, 0x06, 0x48, 0xcb, 0x25, 0xff, 0x2f, 0x08, 0x2c, 0xa9, + 0x67, 0xff, 0xdf, 0x88, 0x1e, 0xed, 0xfc, 0x95, 0x12, 0xe2, 0x22, 0x90, + 0x7c, 0x78, 0x01, 0xc1, 0x79, 0x83, 0xc5, 0x43, 0xc0, 0xf3, 0x3a, 0x5c, + 0xc2, 0xc1, 0xd4, 0xe7, 0xed, 0x29, 0xd2, 0xbb, 0xa1, 0xa1, 0x60, 0xb1, + 0xae, 0xa9, 0xfa, 0xe4, 0x46, 0x5d, 0x5c, 0x16, 0xad, 0x85, 0xdd, 0x06, + 0x82, 0x39, 0x7d, 0x06, 0x5f, 0x3c, 0xc3, 0x19, 0xd1, 0x01, 0x4b, 0x2a, + 0x27, 0xb2, 0x50, 0xf1, 0x61, 0x17, 0x73, 0x8e, 0x15, 0x0f, 0x81, 0x00, + 0x74, 0x5d, 0xef, 0xfa, 0xf9, 0x20, 0xfd, 0xbf, 0x8d, 0xeb, 0x7f, 0xb7, + 0xd2, 0x21, 0x94, 0xa8, 0x18, 0x2a, 0xe0, 0xc5, 0x82, 0x40, 0xfe, 0xdb, + 0xf4, 0xe3, 0xf6, 0xff, 0xaa, 0x54, 0x7f, 0x7f, 0xcf, 0x49, 0xda, 0xb4, + 0x11, 0x1a, 0x0e, 0x00, 0x88, 0x30, 0xad, 0x26, 0x80, 0xf0, 0xe9, 0xac, + 0x9c, 0xf2, 0xb2, 0xc5, 0x94, 0xe6, 0xfe, 0xa8, 0xdb, 0xc0, 0x2b, 0x46, + 0xfb, 0x88, 0xca, 0x8b, 0x40, 0x54, 0xfe, 0xdf, 0x91, 0xbd, 0xf8, 0x5b, + 0x68, 0x08, 0x11, 0x40, 0xe3, 0x04, 0x7a, 0x91, 0x23, 0x41, 0xda, 0x61, + 0x29, 0x53, 0x49, 0x3d, 0x32, 0x15, 0x70, 0x41, 0xdd, 0x53, 0x81, 0xc2, + 0x90, 0xf0, 0x12, 0x92, 0x83, 0xc5, 0x6c, 0xaa, 0x99, 0x89, 0x41, 0x94, + 0x35, 0xda, 0x54, 0xa8, 0x1c, 0x94, 0x7f, 0x49, 0x59, 0x2f, 0x52, 0x55, + 0xba, 0xb1, 0x56, 0x16, 0x83, 0xe4, 0x40, 0x0e, 0x49, 0x82, 0xe4, 0xca, + 0x81, 0xe0, 0xe0, 0x17, 0x69, 0x84, 0x93, 0xa1, 0xed, 0x64, 0xae, 0xd2, + 0x48, 0x0b, 0x6d, 0xbb, 0xa1, 0xed, 0x9f, 0xee, 0x7a, 0x69, 0x6a, 0x8c, + 0xbc, 0x58, 0xaf, 0xb0, 0x39, 0xd1, 0x10, 0x2d, 0x77, 0xbf, 0x82, 0x37, + 0x95, 0x5c, 0xdb, 0xe6, 0x44, 0x76, 0x43, 0x92, 0xff, 0xf9, 0xa6, 0x3a, + 0x51, 0xa5, 0xbb, 0xa8, 0xa1, 0x5e, 0x80, 0xb4, 0x9b, 0x68, 0x0f, 0xa5, + 0x2d, 0x07, 0x17, 0xb0, 0xc3, 0x53, 0xbc, 0x2c, 0xaa, 0x63, 0x59, 0x11, + 0xcf, 0x4c, 0x2a, 0x02, 0x7a, 0x5a, 0x88, 0x16, 0xeb, 0xa9, 0x4a, 0xdc, + 0x91, 0x84, 0xc9, 0x6f, 0xef, 0xe4, 0xf6, 0xab, 0xf7, 0x9a, 0xe7, 0x91, + 0x96, 0xf0, 0x45, 0xc5, 0x05, 0x4a, 0x41, 0xc6, 0x0b, 0x32, 0xa9, 0xb2, + 0xbe, 0xb3, 0xcd, 0xb2, 0xf1, 0x47, 0xf9, 0x3a, 0x87, 0x90, 0x45, 0x31, + 0xf6, 0x61, 0xa0, 0x0e, 0xac, 0xc1, 0xc8, 0x92, 0x10, 0xdb, 0x4e, 0xd4, + 0x0e, 0xa7, 0xbf, 0x7d, 0x0b, 0x0d, 0x5b, 0x03, 0x93, 0xe2, 0xff, 0x62, + 0x44, 0xca, 0x18, 0x2e, 0x55, 0x31, 0x69, 0xca, 0xb0, 0xbe, 0x88, 0x80, + 0xe3, 0x2a, 0xe2, 0x6c, 0x8c, 0x7b, 0xd9, 0xf9, 0x76, 0x48, 0xa7, 0x76, + 0x15, 0x6f, 0xf8, 0x8b, 0x88, 0x14, 0xe8, 0x3e, 0x3f, 0xff, 0x6a, 0xd4, + 0x85, 0x72, 0xa5, 0x6f, 0x7f, 0x68, 0x14, 0xf5, 0xe7, 0xa1, 0x48, 0x72, + 0x84, 0x18, 0x9b, 0xec, 0x8c, 0x1c, 0xcc, 0x0f, 0x6c, 0xcb, 0x6a, 0xe5, + 0x7d, 0x9c, 0xe2, 0xd0, 0x12, 0x31, 0x6f, 0x83, 0x95, 0xf8, 0x8e, 0x2c, + 0xe3, 0x7a, 0xcb, 0x05, 0x93, 0xcd, 0x2d, 0x18, 0x52, 0x8a, 0x2c, 0x8d, + 0x79, 0x03, 0x90, 0x12, 0xb3, 0x4a, 0xea, 0xbd, 0xe0, 0x80, 0xa7, 0x0d, + 0xd4, 0x10, 0xd9, 0xef, 0x7f, 0x00, 0x00, 0xa8, 0x08, 0x6c, 0x82, 0x69, + 0x41, 0xb8, 0x5c, 0x0f, 0x0f, 0x00, 0x7a, 0xa0, 0x78, 0xb8, 0x02, 0x5d, + 0x57, 0x54, 0x23, 0x87, 0x44, 0x41, 0x0b, 0x18, 0x4a, 0x10, 0x07, 0x4a, + 0x64, 0xd2, 0xc2, 0xe5, 0x4d, 0x03, 0xc5, 0x40, 0x1b, 0x08, 0x83, 0x10, + 0x21, 0xe0, 0xec, 0x75, 0xfd, 0xfb, 0x42, 0x55, 0x4a, 0x3c, 0x9e, 0xb4, + 0x41, 0x63, 0x41, 0x5b, 0xe9, 0x10, 0x7f, 0xda, 0x8c, 0x15, 0x06, 0x45, + 0x8f, 0x0b, 0xa0, 0x73, 0x76, 0x20, 0xe1, 0x6f, 0x96, 0x5e, 0xd8, 0x15, + 0xa8, 0x25, 0x66, 0xcc, 0x12, 0x40, 0x3b, 0xf7, 0xb4, 0x15, 0xbf, 0x1f, + 0x7e, 0xa1, 0x2e, 0x67, 0xa1, 0xe4, 0x06, 0x0d, 0x1b, 0xee, 0x02, 0xb8, + 0x2c, 0x1f, 0x0f, 0x87, 0xe9, 0x47, 0xbf, 0x94, 0x74, 0x3a, 0x2f, 0x5b, + 0xaa, 0x5b, 0xdf, 0x49, 0xef, 0x59, 0x38, 0xb7, 0xd0, 0xee, 0xe8, 0x08, + 0x37, 0x8a, 0xcb, 0xc4, 0x81, 0x1f, 0x3e, 0x94, 0xb5, 0x53, 0x7f, 0xfc, + 0x2d, 0x52, 0x1f, 0xb3, 0xfb, 0xeb, 0x43, 0xa4, 0xd7, 0x5b, 0x51, 0x98, + 0xa7, 0x85, 0x78, 0xab, 0xc4, 0x45, 0xe0, 0xb2, 0x53, 0x2d, 0x87, 0xd5, + 0x00, 0xc1, 0xf2, 0xbc, 0xdf, 0xb0, 0x5a, 0x20, 0x33, 0x47, 0x09, 0xb7, + 0xb8, 0x20, 0xb3, 0x3f, 0x57, 0x0d, 0x9a, 0xcd, 0x8a, 0x54, 0x81, 0x50, + 0xb0, 0x20, 0x7a, 0x8f, 0x52, 0xfa, 0xfd, 0x89, 0x80, 0xa7, 0x10, 0x26, + 0x96, 0xa2, 0x6b, 0x15, 0xf2, 0x6c, 0x81, 0xa2, 0x90, 0x7c, 0x98, 0x01, + 0xd2, 0x06, 0xd1, 0xf2, 0xbd, 0x10, 0xd3, 0xa7, 0x48, 0xa7, 0xbb, 0x7d, + 0x7e, 0xd2, 0xf6, 0xb6, 0x1e, 0x2e, 0x97, 0xc5, 0x4b, 0xe2, 0x30, 0x60, + 0xac, 0x58, 0x10, 0x36, 0x41, 0x29, 0x52, 0xc5, 0x6c, 0xfa, 0x6e, 0xa0, + 0xbd, 0xe4, 0xe8, 0x30, 0xd3, 0xb8, 0x45, 0x30, 0x85, 0xb3, 0x20, 0xc1, + 0x0f, 0xc0, 0x7c, 0x7e, 0x3e, 0x1f, 0x52, 0xec, 0x9f, 0xc5, 0x5d, 0x6c, + 0x7a, 0x93, 0xdf, 0xea, 0x9f, 0x96, 0x48, 0x1e, 0x03, 0x1b, 0x10, 0x03, + 0xd0, 0x61, 0xa8, 0x7c, 0x06, 0xf2, 0xb1, 0xf2, 0xa4, 0xea, 0xd4, 0xe6, + 0x81, 0xbd, 0xff, 0x1a, 0x96, 0x77, 0x99, 0x10, 0x77, 0x46, 0xc8, 0x41, + 0x18, 0xc4, 0x33, 0xf2, 0x31, 0x00, 0x35, 0x03, 0x81, 0xe8, 0x38, 0x0f, + 0x89, 0x0a, 0x30, 0x7e, 0xd5, 0x52, 0xcf, 0x90, 0x32, 0x6e, 0xc8, 0x22, + 0xb6, 0x0f, 0x97, 0xff, 0xda, 0x60, 0x79, 0xb3, 0x78, 0xa6, 0x18, 0x5b, + 0x38, 0x75, 0xb0, 0x57, 0x03, 0x41, 0x24, 0xb8, 0xbf, 0xec, 0x97, 0x16, + 0xc8, 0xad, 0x52, 0x8d, 0xfb, 0x4b, 0x5b, 0xcf, 0xa2, 0x02, 0x78, 0x05, + 0x70, 0x16, 0xe1, 0x4b, 0x5a, 0x69, 0xb6, 0xae, 0x7c, 0x3a, 0xe7, 0x56, + 0x5a, 0xac, 0x85, 0xc1, 0xf0, 0x19, 0xa0, 0x80, 0x5e, 0x3b, 0x1d, 0xb0, + 0x07, 0x4b, 0xff, 0x0b, 0xa3, 0x1b, 0x1b, 0xf0, 0xe3, 0xc3, 0x86, 0x53, + 0xef, 0x50, 0xa8, 0x1b, 0x60, 0x6a, 0x0c, 0x46, 0x0a, 0x56, 0x95, 0x88, + 0x29, 0x9b, 0x6a, 0xef, 0x34, 0xb3, 0x46, 0xf5, 0x6e, 0xf1, 0x6e, 0xa8, + 0x46, 0x56, 0x56, 0x16, 0x5f, 0xd2, 0xda, 0xa4, 0x12, 0x1c, 0x4c, 0x99, + 0xcc, 0x04, 0x45, 0x54, 0x0c, 0x67, 0x2e, 0xf5, 0x47, 0xf5, 0x7b, 0x64, + 0xab, 0xf2, 0xe9, 0x5e, 0x03, 0x8c, 0x49, 0x7a, 0xa6, 0x87, 0xbe, 0x8a, + 0x6d, 0x53, 0x33, 0xb9, 0xb1, 0x65, 0xc9, 0x43, 0x93, 0x03, 0x44, 0xd9, + 0xbd, 0xf0, 0x37, 0x6c, 0xd5, 0x69, 0x13, 0x4c, 0x2d, 0xf6, 0x71, 0xae, + 0xff, 0x9d, 0x2c, 0xe8, 0xd9, 0x4f, 0x20, 0xd0, 0xbc, 0x1e, 0x96, 0x49, + 0xe5, 0x28, 0x61, 0x2a, 0xc8, 0x60, 0x30, 0x9e, 0xd8, 0x16, 0x2a, 0x63, + 0x95, 0x5f, 0x2f, 0x54, 0x95, 0x7f, 0x7b, 0x1a, 0x49, 0x96, 0xfd, 0x2f, + 0xd1, 0x66, 0x5f, 0x7e, 0x02, 0xb2, 0xa8, 0x02, 0xea, 0x79, 0xbf, 0x02, + 0x9e, 0x16, 0x0b, 0x83, 0xf8, 0xa7, 0x03, 0xdc, 0x5f, 0x3a, 0x6f, 0xb6, + 0x8a, 0xc5, 0x4c, 0x71, 0x3e, 0x7e, 0xf7, 0xb2, 0xf6, 0x6e, 0x71, 0x18, + 0xad, 0x2a, 0x3e, 0xf7, 0x87, 0x16, 0x7a, 0x75, 0x0e, 0x20, 0xb6, 0xc4, + 0x60, 0x8d, 0x21, 0x86, 0x27, 0x32, 0xf5, 0x64, 0x3c, 0x6d, 0x7c, 0xc9, + 0xe1, 0x9c, 0x98, 0x0c, 0x4e, 0x68, 0x18, 0x6f, 0x6a, 0xcd, 0x7e, 0xcb, + 0x8d, 0x54, 0x36, 0x42, 0xc4, 0x7d, 0x0e, 0x34, 0x6e, 0x16, 0x0c, 0x40, + 0xd5, 0xa0, 0xc1, 0xfa, 0xad, 0x51, 0x44, 0x16, 0x3f, 0xcc, 0x44, 0xb5, + 0x8b, 0x76, 0x83, 0x05, 0x52, 0xab, 0x1a, 0x60, 0x79, 0xec, 0xc9, 0x9e, + 0xbe, 0x9b, 0x39, 0xc5, 0x2b, 0xc8, 0x86, 0x88, 0xad, 0xa2, 0x2b, 0x06, + 0x38, 0x70, 0xc5, 0xd8, 0x1a, 0xc4, 0xc3, 0x86, 0xb5, 0x68, 0x56, 0xd7, + 0xb9, 0xbc, 0x93, 0xab, 0xf0, 0xf2, 0x91, 0x33, 0x6a, 0xbf, 0x6c, 0xb3, + 0x64, 0xf5, 0xb8, 0x51, 0xd9, 0x6f, 0xb8, 0x1b, 0x8d, 0xc1, 0x84, 0xda, + 0x33, 0x0b, 0xd2, 0x31, 0xfe, 0x15, 0xaf, 0x91, 0x6e, 0x64, 0xb2, 0xf2, + 0x40, 0xd4, 0x2c, 0xa6, 0xbf, 0x6a, 0x50, 0x34, 0xbd, 0x03, 0x42, 0x08, + 0xe3, 0x54, 0xa1, 0x5a, 0x59, 0x60, 0x6c, 0x36, 0x06, 0x1a, 0xd7, 0xb4, + 0xa8, 0x7c, 0xae, 0xe0, 0x88, 0x9f, 0xfe, 0xbf, 0x35, 0x78, 0xb5, 0x9d, + 0x05, 0xba, 0xc0, 0xab, 0x67, 0xcc, 0xa6, 0xe1, 0x5e, 0x45, 0x0c, 0x32, + 0xa5, 0x19, 0x6f, 0xff, 0xc0, 0x76, 0x72, 0x95, 0x83, 0x10, 0xda, 0x8f, + 0x83, 0x29, 0xc6, 0x6f, 0x07, 0x11, 0xa9, 0x95, 0x7e, 0xec, 0xef, 0x27, + 0x78, 0x27, 0x2f, 0x98, 0x5a, 0x5f, 0x22, 0x89, 0xbc, 0x93, 0x54, 0xa0, + 0x9c, 0x59, 0x60, 0xdc, 0x8e, 0x76, 0x46, 0xa4, 0x6b, 0x59, 0xa9, 0xfc, + 0xb5, 0x9d, 0xea, 0xcb, 0x6a, 0xdd, 0xe8, 0x38, 0xcc, 0x08, 0xdd, 0x4c, + 0x1f, 0xa7, 0xfa, 0x9b, 0x89, 0x59, 0x52, 0x56, 0x8f, 0x85, 0x92, 0x40, + 0xa1, 0x1d, 0x66, 0x66, 0x95, 0x66, 0xae, 0x19, 0x93, 0x9b, 0x2d, 0x57, + 0x7f, 0xf2, 0xde, 0x46, 0xa7, 0x33, 0xd1, 0x4f, 0x6d, 0xa8, 0x7b, 0x06, + 0x40, 0xef, 0x03, 0x11, 0x70, 0xb1, 0x5f, 0xcb, 0xf0, 0x71, 0xdf, 0x54, + 0x70, 0x66, 0x50, 0xe0, 0xfc, 0x0c, 0x10, 0x42, 0x1a, 0x6a, 0x10, 0x34, + 0x75, 0x9b, 0x8c, 0x8f, 0x53, 0xb7, 0x9e, 0x0f, 0x9a, 0xb3, 0x59, 0xcc, + 0x0e, 0xed, 0xff, 0x86, 0xe4, 0x03, 0xfe, 0xfd, 0x17, 0xf1, 0x65, 0x2b, + 0x71, 0x1a, 0xd5, 0x1f, 0x41, 0x2a, 0x1b, 0x08, 0x0c, 0x2a, 0x4e, 0xc9, + 0x78, 0xf9, 0x52, 0xaa, 0xaf, 0xff, 0xff, 0xd5, 0x97, 0x8f, 0xff, 0x36, + 0x35, 0x6c, 0x9d, 0xe5, 0xd1, 0x4c, 0x42, 0xd4, 0x67, 0x1b, 0x0f, 0xcd, + 0x03, 0x60, 0x1d, 0xb7, 0xdb, 0x44, 0xa6, 0x73, 0xdc, 0x96, 0x65, 0xe4, + 0xb6, 0xa3, 0x44, 0x16, 0x82, 0xbc, 0x0e, 0x2a, 0x07, 0x01, 0xe1, 0x19, + 0xa1, 0xf3, 0x0d, 0x34, 0x1f, 0xd0, 0x32, 0x9d, 0xbd, 0xff, 0x32, 0xb3, + 0xf4, 0x70, 0xb2, 0x0d, 0xd4, 0x0d, 0xbc, 0x1e, 0x87, 0x46, 0x01, 0x6e, + 0x59, 0x53, 0x8e, 0x1b, 0xf9, 0x7b, 0x36, 0x2d, 0x98, 0x20, 0x78, 0x40, + 0x48, 0xa7, 0x9b, 0xde, 0x5d, 0xcf, 0x6b, 0x79, 0x99, 0x29, 0x58, 0x31, + 0x15, 0x7b, 0xe3, 0xec, 0xfc, 0x61, 0x85, 0x79, 0xad, 0xa0, 0x0f, 0x6e, + 0xd2, 0x8a, 0x54, 0xa5, 0x48, 0x6c, 0x0c, 0x71, 0xc2, 0xcb, 0xd2, 0x62, + 0xcb, 0x56, 0x6c, 0x52, 0x39, 0xd9, 0x6e, 0xf0, 0xa9, 0x44, 0xcc, 0x5a, + 0x73, 0x9c, 0x1b, 0xe8, 0x30, 0xd4, 0xcc, 0xea, 0xb5, 0x38, 0x5b, 0x58, + 0x6a, 0x22, 0x1c, 0x15, 0x52, 0x8a, 0x1c, 0x18, 0xbb, 0xeb, 0xfe, 0xdd, + 0xe4, 0x1b, 0x96, 0xde, 0x72, 0xf4, 0x92, 0x08, 0x80, 0xe3, 0x2a, 0x8e, + 0x18, 0x4c, 0xa3, 0xad, 0xfd, 0x42, 0xf5, 0x44, 0x8a, 0x54, 0xf1, 0x17, + 0x4a, 0xc9, 0x6e, 0x80, 0x85, 0x73, 0xe9, 0xd6, 0x09, 0x0a, 0xb3, 0xe5, + 0xb2, 0x7f, 0x11, 0xe9, 0x6d, 0x4e, 0xdc, 0x2d, 0xa6, 0xff, 0x30, 0x6f, + 0x9a, 0x1b, 0xfc, 0x1f, 0x22, 0x00, 0x74, 0xc7, 0x09, 0x97, 0x52, 0xda, + 0x1b, 0xfe, 0x2e, 0x59, 0xd5, 0x96, 0x94, 0x6e, 0x65, 0x50, 0x53, 0x97, + 0x62, 0xe0, 0x67, 0xe1, 0xb5, 0xec, 0xce, 0x94, 0x69, 0x50, 0x3e, 0x5f, + 0xff, 0x64, 0x98, 0x6d, 0xa5, 0x79, 0x34, 0x71, 0x4a, 0xb8, 0x4b, 0x8b, + 0xce, 0xf0, 0x55, 0x9e, 0xef, 0x55, 0x9a, 0xe2, 0xaa, 0xa2, 0xa0, 0x83, + 0x8b, 0x44, 0xe6, 0x17, 0x55, 0x9f, 0x66, 0xab, 0xa1, 0xff, 0xfd, 0x03, + 0xcc, 0xc0, 0xf6, 0xd3, 0x50, 0xac, 0x04, 0x4b, 0x31, 0x3b, 0x36, 0x78, + 0x19, 0x12, 0x49, 0x90, 0xad, 0x6d, 0xbb, 0xa8, 0xd1, 0x06, 0xc3, 0x61, + 0x61, 0x6c, 0x68, 0xbb, 0x01, 0x97, 0x99, 0xdf, 0xe0, 0xdc, 0xb5, 0x7d, + 0xec, 0x47, 0x43, 0x64, 0x20, 0x2e, 0xe5, 0xa9, 0x15, 0xab, 0x8d, 0x4d, + 0x06, 0x1c, 0x7f, 0xf3, 0x17, 0xfb, 0x2a, 0xf7, 0xd6, 0xe5, 0xa8, 0x6f, + 0xb0, 0xaf, 0x01, 0xc6, 0x0e, 0x83, 0xc1, 0x7f, 0xc6, 0xdf, 0xef, 0xfd, + 0xac, 0xc5, 0x3c, 0x1c, 0x31, 0x9a, 0x06, 0x98, 0x2c, 0xea, 0xe3, 0x75, + 0x3a, 0xa1, 0x16, 0x03, 0x13, 0x99, 0x06, 0x10, 0x6e, 0xa7, 0xd0, 0x78, + 0x28, 0x05, 0xee, 0xfa, 0x72, 0xb0, 0xce, 0x7e, 0xdf, 0x7e, 0xd4, 0x56, + 0xf9, 0x42, 0x81, 0xb5, 0xa0, 0x24, 0x49, 0xdd, 0x8d, 0x6d, 0x6f, 0xd3, + 0xdc, 0xea, 0x8c, 0xf7, 0x3b, 0xc8, 0xb9, 0x68, 0x6c, 0x89, 0x40, 0x30, + 0x9f, 0x5e, 0x1e, 0x2c, 0x48, 0xd0, 0x1b, 0x92, 0xd1, 0xdb, 0x2c, 0x29, + 0xd0, 0xeb, 0xca, 0xbb, 0xe9, 0x09, 0x2d, 0x11, 0x41, 0xf2, 0x60, 0x07, + 0xe1, 0xfc, 0xcb, 0x56, 0xc0, 0xcd, 0x4e, 0x8a, 0x46, 0xc2, 0x52, 0x5f, + 0x2b, 0xdd, 0x69, 0x85, 0x48, 0xbb, 0xa0, 0xad, 0xde, 0xa1, 0x5e, 0xdb, + 0xb8, 0xa5, 0x42, 0x90, 0x7c, 0xf8, 0x01, 0xc5, 0x6a, 0x43, 0xdf, 0x67, + 0xb3, 0xdd, 0x93, 0xb4, 0x9b, 0x6a, 0x28, 0xbc, 0xa2, 0xb3, 0x7d, 0x56, + 0x88, 0x96, 0x5e, 0xde, 0x70, 0xd8, 0x24, 0x74, 0xe5, 0xcd, 0xfe, 0x5c, + 0x9f, 0x99, 0x94, 0x44, 0x11, 0x78, 0x0c, 0x13, 0xc3, 0x34, 0xaa, 0x96, + 0x5c, 0x2d, 0x81, 0xea, 0x8e, 0xf0, 0x60, 0x1b, 0x29, 0x3e, 0xbf, 0xb5, + 0x94, 0xbe, 0x02, 0x0d, 0xc8, 0x04, 0x4a, 0x89, 0x78, 0x54, 0x57, 0xa6, + 0x25, 0xb3, 0x1e, 0x1e, 0x66, 0x72, 0x5d, 0xdd, 0x2b, 0x5e, 0x23, 0x83, + 0x30, 0x61, 0x39, 0x60, 0x2d, 0x35, 0x65, 0x11, 0x72, 0xda, 0x8a, 0xf0, + 0x91, 0xd2, 0xc3, 0x51, 0x8a, 0x57, 0xa2, 0x0b, 0x77, 0xb5, 0x4d, 0xec, + 0x92, 0x52, 0x04, 0x16, 0xd5, 0x0a, 0x67, 0x56, 0x0f, 0x4d, 0x28, 0x25, + 0x7f, 0xb6, 0xb8, 0x07, 0x08, 0xe2, 0x40, 0x29, 0x8b, 0x87, 0xd8, 0x97, + 0xc0, 0x6f, 0xc9, 0x13, 0x16, 0xfa, 0xad, 0x4b, 0x41, 0x13, 0xd6, 0xf0, + 0x39, 0x47, 0x41, 0x86, 0x81, 0x79, 0xb1, 0xfe, 0x37, 0xf8, 0xc7, 0x97, + 0x9b, 0xde, 0xea, 0x07, 0x8e, 0x02, 0x10, 0x84, 0xde, 0x26, 0xf2, 0x72, + 0xc8, 0xa5, 0x5b, 0x5e, 0xaa, 0x41, 0x51, 0x7d, 0x39, 0x20, 0x8a, 0x36, + 0x90, 0xb4, 0x18, 0x56, 0x26, 0xf2, 0x68, 0xd7, 0x35, 0x1d, 0x58, 0x90, + 0x81, 0x7f, 0x67, 0x64, 0xc4, 0x40, 0xf9, 0x9f, 0xfd, 0xc8, 0x89, 0xcd, + 0x9a, 0xad, 0x46, 0x1a, 0xdf, 0x31, 0x93, 0xcb, 0x22, 0xc2, 0xab, 0xc3, + 0x51, 0x46, 0x15, 0x69, 0xc1, 0xb8, 0x30, 0x81, 0xf6, 0xd3, 0xb6, 0x3f, + 0xfa, 0xa8, 0x5b, 0x79, 0xc5, 0xe6, 0xc9, 0xe8, 0x55, 0x20, 0x70, 0xa4, + 0x1f, 0x5e, 0x00, 0x74, 0x2d, 0x2d, 0xb2, 0x10, 0x08, 0x9b, 0xbc, 0xc5, + 0x11, 0x6e, 0x85, 0x1c, 0x21, 0x43, 0xc5, 0xa8, 0xca, 0x4e, 0x2b, 0x61, + 0x3e, 0xc0, 0x56, 0xf9, 0x4a, 0x84, 0x35, 0x1a, 0x33, 0xf4, 0x9a, 0xdf, + 0xe5, 0xb4, 0xa8, 0xd4, 0x45, 0x4a, 0x4f, 0x53, 0x4a, 0xbd, 0xf2, 0xbf, + 0xf3, 0x54, 0x29, 0x92, 0x58, 0x86, 0xd4, 0x61, 0x55, 0xab, 0xc9, 0x96, + 0x6e, 0x2d, 0x11, 0x70, 0x83, 0x92, 0x1e, 0x6c, 0x34, 0x03, 0x68, 0xec, + 0x14, 0xa3, 0xcc, 0xfb, 0x23, 0xc1, 0xe3, 0x0d, 0xa6, 0xf2, 0x34, 0xf9, + 0xd6, 0xdb, 0xf4, 0x37, 0x53, 0x42, 0xc5, 0x18, 0x88, 0xac, 0x18, 0xe8, + 0x70, 0xba, 0x07, 0xc1, 0x05, 0xba, 0xdb, 0x6d, 0xf6, 0x4d, 0x02, 0xed, + 0xfe, 0x34, 0xd6, 0x6f, 0x51, 0x40, 0xdd, 0x71, 0xb0, 0x7a, 0x2d, 0x13, + 0x8f, 0x75, 0x5b, 0x10, 0x72, 0xc6, 0xc9, 0x33, 0xea, 0x55, 0xe2, 0x85, + 0x23, 0x94, 0xdc, 0xf9, 0x6f, 0xa4, 0x0e, 0x51, 0x0d, 0x01, 0x76, 0xa8, + 0x7c, 0x07, 0x84, 0x7d, 0x05, 0x3a, 0x46, 0x34, 0xb9, 0x5c, 0x59, 0xae, + 0xac, 0x91, 0x8f, 0xf0, 0x3b, 0xf4, 0xc0, 0x56, 0x63, 0x62, 0x2a, 0x90, + 0xec, 0x04, 0xd8, 0xd7, 0xe9, 0x5f, 0x43, 0xc0, 0x62, 0x17, 0xd9, 0x4d, + 0x9c, 0x4c, 0x17, 0x60, 0x18, 0x91, 0x38, 0xe9, 0x23, 0x0c, 0x0e, 0x7a, + 0x55, 0x83, 0x91, 0x07, 0xff, 0xda, 0xa7, 0x8b, 0xc2, 0xb1, 0xb6, 0x60, + 0x71, 0x80, 0x28, 0x64, 0xd2, 0xbe, 0x35, 0xcb, 0x65, 0x24, 0x9d, 0x99, + 0xd0, 0x61, 0xa8, 0xb9, 0x20, 0x3c, 0x1f, 0xfc, 0xaa, 0x82, 0x11, 0x7b, + 0x4d, 0xea, 0x74, 0xea, 0x59, 0x10, 0x7d, 0x14, 0xe7, 0x95, 0x78, 0x15, + 0x22, 0x26, 0x29, 0xe6, 0x28, 0x06, 0x21, 0x28, 0xac, 0x75, 0x7b, 0xd6, + 0x38, 0x22, 0x42, 0xc4, 0x59, 0xc8, 0x72, 0x6a, 0xc8, 0x42, 0xd4, 0x4d, + 0x3e, 0x95, 0x16, 0xcb, 0xd0, 0xe6, 0x14, 0xa3, 0xa7, 0xcc, 0xe5, 0x69, + 0xbd, 0xb8, 0x8b, 0x57, 0x44, 0xb1, 0xde, 0x3c, 0xf4, 0xf2, 0x75, 0x6d, + 0x7f, 0x9f, 0x93, 0xd0, 0x92, 0x2f, 0xce, 0xb9, 0x0c, 0x12, 0x95, 0x79, + 0x3b, 0x4a, 0xe1, 0x52, 0x8d, 0x29, 0x95, 0x67, 0xb6, 0x91, 0xcb, 0xe3, + 0xe6, 0x3c, 0xab, 0xaa, 0x3f, 0xfb, 0x3f, 0x2f, 0xef, 0x61, 0x57, 0x61, + 0x2a, 0x91, 0xb9, 0x95, 0xc1, 0x56, 0x06, 0xfe, 0x20, 0x26, 0xda, 0x5b, + 0xed, 0x2c, 0x56, 0x8c, 0x0c, 0x52, 0xcc, 0xa1, 0xc1, 0x59, 0x50, 0xb5, + 0x12, 0xff, 0x8e, 0x39, 0x3d, 0xb9, 0x85, 0xa5, 0x44, 0xbd, 0xb2, 0xa2, + 0x0e, 0x0c, 0x9d, 0x48, 0x25, 0x7c, 0xbb, 0x15, 0x4f, 0x37, 0x77, 0x2e, + 0xb3, 0xa9, 0xf5, 0xbd, 0xad, 0xfd, 0x9d, 0xbc, 0x91, 0x7d, 0xd1, 0x10, + 0xf2, 0x16, 0xda, 0x2b, 0x35, 0xfd, 0x0e, 0x2e, 0x72, 0xff, 0x46, 0xfb, + 0xfe, 0x2e, 0x0c, 0x26, 0x55, 0x26, 0x66, 0x28, 0xea, 0x2f, 0x96, 0xd8, + 0x82, 0xcc, 0xbc, 0x92, 0x70, 0x38, 0x58, 0x12, 0x64, 0x7e, 0xd4, 0x6d, + 0xaf, 0xfb, 0xb6, 0x73, 0x24, 0xc4, 0x01, 0xec, 0x2b, 0x07, 0x08, 0x82, + 0x7f, 0xcf, 0x2b, 0x69, 0x53, 0x68, 0x5a, 0x58, 0x97, 0xa4, 0xe8, 0x2d, + 0x4f, 0x91, 0xd9, 0x5c, 0xc1, 0xc5, 0x0f, 0xb2, 0x4d, 0xf4, 0xf5, 0xb1, + 0x07, 0x3f, 0x2b, 0x86, 0x83, 0xcd, 0xc8, 0xcf, 0xb3, 0xea, 0x0b, 0x6d, + 0xd5, 0x35, 0x0c, 0x93, 0x96, 0xda, 0x1a, 0xed, 0x06, 0x05, 0xc2, 0xe3, + 0xd6, 0xea, 0x6f, 0xe6, 0xcd, 0xa3, 0x60, 0xeb, 0x9c, 0x9a, 0x33, 0x52, + 0x55, 0xaa, 0x41, 0x2d, 0x7d, 0x4c, 0x0f, 0x05, 0xff, 0x1b, 0x25, 0xed, + 0x7b, 0x1b, 0xf7, 0x94, 0x33, 0x73, 0xd6, 0x29, 0xec, 0x6a, 0xdb, 0xd1, + 0x17, 0x14, 0x6f, 0x00, 0xa0, 0x31, 0x19, 0x87, 0x5a, 0xdf, 0xd5, 0x74, + 0x7a, 0xda, 0x6f, 0x6c, 0xbf, 0xfe, 0xe6, 0xe7, 0xec, 0x2a, 0xc5, 0x5e, + 0x47, 0xe0, 0xd7, 0x3a, 0x0f, 0x91, 0xff, 0xd8, 0xa5, 0xa1, 0xbb, 0x70, + 0x73, 0x37, 0xeb, 0x68, 0x80, 0x83, 0x32, 0x01, 0x0a, 0x27, 0x14, 0xaa, + 0xb8, 0xaf, 0x85, 0xe5, 0x93, 0x0b, 0x24, 0x53, 0x54, 0xc1, 0xb5, 0x92, + 0xbc, 0xdb, 0x73, 0xf9, 0xfa, 0xdf, 0xbe, 0xd6, 0x35, 0xf5, 0x00, 0xad, + 0x11, 0x4b, 0x22, 0xf6, 0x40, 0xd4, 0xc7, 0x2c, 0xc7, 0xc7, 0x2c, 0xff, + 0x7b, 0xb7, 0x18, 0x59, 0x41, 0x65, 0x50, 0xdd, 0x5a, 0xf7, 0xb4, 0x2c, + 0x37, 0x1b, 0x2c, 0xcb, 0xce, 0x66, 0x4d, 0xaa, 0x3b, 0x7b, 0x6f, 0x3a, + 0xb5, 0xbb, 0x8a, 0x54, 0x82, 0xdd, 0x46, 0xcb, 0xd8, 0x43, 0xf5, 0xf1, + 0x71, 0xb7, 0x2a, 0x84, 0x4b, 0x45, 0x23, 0x64, 0x65, 0x78, 0x68, 0xc9, + 0x86, 0xf8, 0xaf, 0x3c, 0xad, 0x54, 0xdd, 0xfe, 0x6e, 0xe7, 0xae, 0xc2, + 0xc4, 0xd1, 0x18, 0x77, 0xed, 0x07, 0x07, 0x86, 0x7e, 0xd4, 0xea, 0xb6, + 0x54, 0xdd, 0xe3, 0x0d, 0x22, 0x9a, 0x8a, 0x2e, 0x6b, 0xe2, 0x2e, 0x86, + 0xe0, 0xf9, 0x3f, 0xfd, 0x93, 0x10, 0x07, 0x57, 0x7c, 0x0f, 0x09, 0xff, + 0x9f, 0xd8, 0xef, 0x26, 0xf5, 0xbc, 0x52, 0x86, 0xf2, 0x61, 0x5e, 0x91, + 0xa6, 0xd3, 0x0d, 0xe2, 0x9d, 0x2f, 0x4f, 0x2f, 0x87, 0x13, 0x8d, 0x62, + 0x29, 0x27, 0x03, 0xd0, 0xd7, 0x4c, 0x25, 0x0b, 0x56, 0xfb, 0x1b, 0x26, + 0x40, 0x61, 0x11, 0x8e, 0x77, 0xa8, 0xa4, 0x66, 0xa9, 0x2b, 0xd0, 0xd8, + 0x3c, 0x07, 0xc7, 0xff, 0xee, 0xbd, 0xfa, 0x3a, 0xcd, 0x67, 0xec, 0x97, + 0xc0, 0x30, 0xc1, 0x53, 0x1e, 0x9f, 0xb9, 0xe5, 0x11, 0x72, 0xce, 0x60, + 0x88, 0x0b, 0x65, 0x34, 0x7a, 0x3e, 0xf7, 0x71, 0xac, 0xf6, 0x6f, 0xf9, + 0x0a, 0xa1, 0x64, 0xea, 0x00, 0xf7, 0x46, 0xfb, 0xa3, 0x75, 0x00, 0xfa, + 0x1f, 0xfd, 0xa9, 0x27, 0xf6, 0xe8, 0x7f, 0x6d, 0x94, 0x3c, 0x1c, 0x71, + 0x4f, 0x62, 0x25, 0xa2, 0x90, 0x5a, 0xa3, 0xf6, 0x18, 0x68, 0x3d, 0xad, + 0x49, 0x72, 0x49, 0x8d, 0x6f, 0x14, 0x62, 0xc8, 0xdc, 0xbd, 0x98, 0x61, + 0x32, 0xbf, 0xd2, 0xd2, 0xfd, 0xaa, 0x24, 0x8a, 0x3d, 0xb6, 0xcf, 0x14, + 0xdf, 0x07, 0x01, 0xb0, 0x3e, 0x6c, 0x00, 0xe9, 0xa5, 0xa5, 0xc0, 0x63, + 0xcd, 0xb7, 0xbb, 0xb6, 0x55, 0x1e, 0xc5, 0xa5, 0x9d, 0x40, 0x1c, 0x18, + 0x58, 0x41, 0x6d, 0x5c, 0x0e, 0x31, 0x4a, 0xe8, 0x67, 0x17, 0x20, 0x5d, + 0xa6, 0xb4, 0x72, 0xa5, 0x1c, 0xce, 0xc9, 0xfd, 0x5f, 0x6d, 0xea, 0x00, + 0x63, 0x46, 0x25, 0x2f, 0x52, 0xe5, 0x56, 0xc6, 0xee, 0xcd, 0xf4, 0xce, + 0xdc, 0x9d, 0xde, 0x54, 0x1d, 0x53, 0xa0, 0xc0, 0x92, 0xaf, 0x9b, 0x66, + 0xf0, 0xb1, 0x54, 0xcf, 0x5f, 0xa8, 0xf7, 0xaf, 0x32, 0x28, 0x02, 0x36, + 0xe8, 0x8a, 0xa6, 0x05, 0x85, 0x9a, 0x8d, 0xcd, 0xa8, 0xf9, 0x01, 0x19, + 0x61, 0x5a, 0xc9, 0xcb, 0xb5, 0xb2, 0xcf, 0xeb, 0x7b, 0xb3, 0x3f, 0x37, + 0x4b, 0x1b, 0xfe, 0x62, 0x1e, 0xf3, 0xc1, 0xab, 0xf5, 0x23, 0xb4, 0x8b, + 0xee, 0xe2, 0x3f, 0xa8, 0x43, 0xcf, 0x59, 0xce, 0xca, 0x1b, 0x03, 0x05, + 0x26, 0x1a, 0x64, 0x7f, 0x7d, 0x7c, 0xc3, 0x5e, 0xcf, 0x40, 0x64, 0x36, + 0xdd, 0xbc, 0xec, 0xed, 0xa1, 0xce, 0x99, 0x54, 0x40, 0x41, 0xcd, 0x8b, + 0xaf, 0x36, 0xaf, 0xc4, 0x00, 0xc3, 0x52, 0x65, 0x9a, 0x58, 0x54, 0xa3, + 0x80, 0xed, 0x90, 0xd7, 0x01, 0x82, 0x7b, 0x4b, 0x32, 0x3f, 0x4a, 0xc8, + 0xf1, 0x5f, 0xbe, 0x0a, 0xd4, 0xfd, 0xd9, 0xe6, 0x3c, 0xc7, 0x3c, 0xd6, + 0x6d, 0x95, 0x1d, 0xa1, 0xce, 0xf0, 0x15, 0xc1, 0x69, 0xec, 0x2f, 0x65, + 0xbe, 0xf9, 0x5a, 0x42, 0xcc, 0x5a, 0x71, 0x7d, 0xb5, 0x60, 0x46, 0x50, + 0x1b, 0x81, 0x52, 0xa0, 0x62, 0x25, 0xe6, 0x15, 0xe4, 0xaa, 0x6e, 0xd8, + 0x05, 0x45, 0x0b, 0x55, 0x51, 0x4e, 0x36, 0xda, 0xdc, 0xea, 0x25, 0xfb, + 0x5f, 0x1e, 0x99, 0x2c, 0xa7, 0xa6, 0x31, 0x8a, 0x18, 0xf1, 0x67, 0x51, + 0x7b, 0xd8, 0x22, 0x92, 0xc0, 0x5a, 0x18, 0x4d, 0x35, 0x8a, 0xdb, 0x6c, + 0xfd, 0x47, 0xd9, 0xb3, 0xd9, 0xeb, 0x7a, 0x59, 0x64, 0xb1, 0x68, 0x80, + 0x85, 0x34, 0xd4, 0x71, 0x4a, 0xb2, 0xa8, 0xce, 0xf7, 0x4d, 0x9f, 0x51, + 0xbe, 0x8e, 0x73, 0x54, 0x5d, 0x81, 0xc4, 0x58, 0xf4, 0xcf, 0xd9, 0x54, + 0x8a, 0x9a, 0xd2, 0xdb, 0xab, 0x6e, 0x77, 0x3b, 0x6c, 0xed, 0x80, 0xe2, + 0xa0, 0x5a, 0xc6, 0x79, 0xbb, 0x4b, 0x3d, 0xef, 0x56, 0xb2, 0xa1, 0x0e, + 0x01, 0xc5, 0x60, 0xb5, 0x86, 0xbd, 0xab, 0xd8, 0xa2, 0x29, 0x84, 0x8b, + 0x52, 0x52, 0xa1, 0x4e, 0x89, 0x95, 0xf3, 0x69, 0x6d, 0xb9, 0x7b, 0x6a, + 0x81, 0xb1, 0xef, 0xb4, 0x8b, 0x33, 0xda, 0xbf, 0xed, 0xb1, 0x02, 0x3e, + 0x0a, 0xb7, 0xed, 0x59, 0x44, 0x51, 0xef, 0xad, 0xc8, 0x8e, 0x93, 0xce, + 0x6b, 0x18, 0x1d, 0x7a, 0xb7, 0xf2, 0x51, 0xb0, 0x9d, 0x16, 0x8b, 0x68, + 0x7b, 0xbb, 0x32, 0x20, 0xf6, 0x1a, 0x27, 0xbb, 0x00, 0x00, 0xb2, 0x08, + 0x2c, 0x2d, 0x8f, 0x37, 0xa3, 0xa1, 0x28, 0x90, 0x74, 0x5d, 0x01, 0xe2, + 0xa0, 0x0d, 0x16, 0x27, 0x77, 0x8a, 0x68, 0xa5, 0x31, 0x23, 0x80, 0xc2, + 0x00, 0xeb, 0xa0, 0xf0, 0xb0, 0x0b, 0x97, 0x03, 0xc5, 0xc0, 0x1a, 0x2c, + 0x5d, 0x2b, 0x60, 0xe1, 0x99, 0x00, 0xb8, 0xa6, 0x10, 0x26, 0x66, 0x6a, + 0x3b, 0x56, 0x26, 0x6b, 0xff, 0x45, 0x2b, 0x12, 0x21, 0xb7, 0x9c, 0x25, + 0x26, 0x2c, 0xa2, 0x64, 0x43, 0x03, 0x3f, 0x94, 0x86, 0xc0, 0xb6, 0x43, + 0xea, 0x99, 0x26, 0xb9, 0x03, 0xc4, 0x7c, 0xee, 0xfe, 0xa0, 0x94, 0xab, + 0x0f, 0x19, 0x56, 0x8d, 0xed, 0x32, 0x2b, 0x79, 0x33, 0xa5, 0x52, 0x20, + 0xe4, 0x5c, 0x1c, 0xa5, 0xea, 0x37, 0xf9, 0x3f, 0x72, 0xd2, 0xb5, 0xc2, + 0x95, 0x74, 0x6c, 0xfe, 0xf1, 0x7e, 0x8a, 0xcc, 0xa6, 0x03, 0x89, 0x9b, + 0x12, 0x19, 0x54, 0x56, 0x1e, 0x0e, 0xe8, 0xfe, 0x6a, 0xf9, 0x79, 0x7f, + 0xda, 0xd7, 0xae, 0x68, 0x70, 0x02, 0x14, 0x4b, 0xfc, 0xf0, 0x73, 0xba, + 0x83, 0x3d, 0x3b, 0x78, 0x6c, 0x1c, 0x60, 0xf3, 0x02, 0x58, 0xed, 0xb4, + 0xac, 0x8f, 0x15, 0x66, 0x87, 0xd5, 0x46, 0xa9, 0xea, 0xf1, 0x98, 0x1e, + 0xfa, 0x74, 0x6c, 0x1f, 0x6f, 0x03, 0xdc, 0xd0, 0xef, 0xc0, 0xc4, 0xc2, + 0xfe, 0x01, 0x76, 0xbd, 0x32, 0x38, 0x39, 0xf7, 0xec, 0x2a, 0x51, 0x9d, + 0xde, 0xdd, 0x92, 0xcc, 0x97, 0x9c, 0xaa, 0x44, 0x4c, 0xe4, 0x05, 0x78, + 0x08, 0x16, 0x2a, 0x2f, 0xd5, 0x78, 0xa3, 0xd3, 0x7a, 0xb1, 0x5d, 0x85, + 0x4b, 0xc5, 0xb9, 0x41, 0x2c, 0x48, 0xa8, 0x0f, 0x2a, 0x03, 0xe9, 0x18, + 0x6c, 0x76, 0xca, 0xb1, 0xcb, 0x0a, 0x47, 0x2c, 0x30, 0xac, 0x15, 0x97, + 0xfd, 0x5e, 0x27, 0x8d, 0x15, 0x6e, 0x2d, 0x00, 0x45, 0x97, 0x08, 0x38, + 0x5b, 0x03, 0xea, 0xd2, 0xa6, 0xbb, 0x8a, 0x4b, 0x65, 0x9f, 0xc9, 0x16, + 0xbe, 0xf6, 0x62, 0x98, 0xd2, 0x22, 0xc5, 0x21, 0xe8, 0x30, 0xa8, 0xd5, + 0xbb, 0x5c, 0xe9, 0xbc, 0x06, 0x5b, 0xeb, 0xd5, 0x2d, 0xf2, 0x07, 0xfa, + 0x80, 0xc2, 0x17, 0x54, 0xa1, 0xef, 0x51, 0x0a, 0x08, 0x97, 0x35, 0xef, + 0x4d, 0xfc, 0xc2, 0xb4, 0xf6, 0x7d, 0x9a, 0x8f, 0xb7, 0x9c, 0xf4, 0x0d, + 0x02, 0xc6, 0x97, 0xdf, 0x03, 0x01, 0xf5, 0x9e, 0x0f, 0x62, 0x99, 0xc5, + 0xb6, 0x2f, 0xd8, 0x04, 0xc6, 0xe2, 0x6b, 0x5f, 0x1b, 0xa6, 0x07, 0xcc, + 0x48, 0xd4, 0xd6, 0xdb, 0xff, 0xf3, 0xbb, 0x23, 0x7a, 0xa7, 0xb6, 0xf5, + 0x70, 0x46, 0xaa, 0x14, 0x01, 0x03, 0x0b, 0x88, 0x6a, 0xc1, 0xb8, 0x98, + 0x72, 0xa3, 0xff, 0xbe, 0x51, 0x3c, 0xa9, 0xa8, 0xa6, 0xdb, 0x6f, 0x24, + 0x9e, 0x11, 0x77, 0x76, 0x85, 0x91, 0x0a, 0xd4, 0x51, 0xb6, 0xa0, 0x21, + 0xa6, 0x79, 0x5b, 0x81, 0xe2, 0x96, 0xe5, 0xa5, 0x88, 0x03, 0x6e, 0xb9, + 0xc2, 0xd7, 0x3e, 0xdc, 0xb0, 0x9b, 0x4b, 0xf6, 0x0e, 0x7b, 0x2a, 0x89, + 0x7f, 0xe4, 0x45, 0x9b, 0x50, 0x15, 0x15, 0x03, 0x02, 0x67, 0xf6, 0x08, + 0x1a, 0x5e, 0x3e, 0xd0, 0xeb, 0xd2, 0xb3, 0xe1, 0xaa, 0x69, 0xba, 0xc1, + 0x6a, 0x92, 0xbb, 0x7a, 0x53, 0xd3, 0xe3, 0x96, 0x44, 0xbc, 0x81, 0x0d, + 0xb6, 0xb7, 0xdf, 0x9f, 0xbe, 0xca, 0x88, 0xab, 0xea, 0x97, 0xc5, 0xa8, + 0x8a, 0xa3, 0x90, 0x05, 0xdd, 0xbd, 0x80, 0xe3, 0x0e, 0xdc, 0x39, 0x66, + 0x84, 0x9c, 0xd4, 0xe9, 0x98, 0x67, 0xc5, 0x7e, 0xf6, 0x5b, 0x60, 0x8a, + 0x89, 0x6e, 0x50, 0xe5, 0x49, 0xe3, 0x23, 0xc2, 0xd8, 0x25, 0xd2, 0xdc, + 0xb8, 0xa6, 0x42, 0xd3, 0x5b, 0x95, 0xa9, 0xd9, 0x60, 0x88, 0x02, 0x57, + 0x56, 0x5e, 0xca, 0xa4, 0x89, 0x4a, 0xa2, 0x91, 0xf3, 0x2a, 0xbf, 0xe1, + 0x13, 0xaa, 0x99, 0xa1, 0xe0, 0x11, 0x2b, 0xc3, 0x14, 0x3b, 0xd2, 0xdc, + 0xc1, 0xd9, 0x75, 0x2a, 0x4b, 0x98, 0x20, 0x9b, 0xce, 0x45, 0xef, 0x43, + 0x9d, 0xd8, 0xa0, 0x18, 0x4c, 0x68, 0xc5, 0x95, 0x2e, 0x67, 0x01, 0x4c, + 0xa7, 0x18, 0xfc, 0xef, 0xff, 0x88, 0x3b, 0x27, 0xba, 0x8e, 0x0d, 0xca, + 0xf8, 0x09, 0x0a, 0x33, 0xef, 0x6c, 0xd8, 0xdc, 0x6d, 0x45, 0x99, 0xa1, + 0xe2, 0xda, 0xb2, 0xd6, 0x50, 0xe3, 0x17, 0x07, 0xc9, 0xff, 0xed, 0x66, + 0x19, 0xab, 0x7b, 0x7b, 0xcc, 0xb0, 0x15, 0xeb, 0x72, 0xde, 0x40, 0xdf, + 0xa0, 0x92, 0x5d, 0x56, 0x01, 0xb6, 0x62, 0x85, 0xa7, 0x69, 0x2c, 0x51, + 0xea, 0x8c, 0x0a, 0x03, 0x83, 0x73, 0x1c, 0x2c, 0xb8, 0x2a, 0x98, 0xc1, + 0xc3, 0x38, 0xd2, 0x76, 0x65, 0xc8, 0xa1, 0xa9, 0xe9, 0x93, 0xb6, 0x2c, + 0x06, 0xff, 0x85, 0x7b, 0x98, 0x0b, 0x55, 0x7e, 0xa5, 0xa9, 0xd5, 0x72, + 0x34, 0x1c, 0x7b, 0xc5, 0x70, 0x92, 0x83, 0x10, 0x09, 0x43, 0xd5, 0xb2, + 0x49, 0x32, 0xc5, 0xea, 0x10, 0x60, 0x4f, 0x0c, 0x40, 0x82, 0xac, 0x14, + 0xdd, 0xeb, 0x5d, 0x99, 0xcd, 0x10, 0x75, 0x7c, 0x97, 0xf6, 0xe7, 0xbd, + 0xc0, 0x5a, 0xf9, 0xe2, 0xd5, 0x8a, 0x19, 0xf5, 0xa5, 0x6b, 0xca, 0x57, + 0x45, 0x67, 0xf1, 0xa4, 0xbe, 0x82, 0x03, 0x45, 0xa5, 0x93, 0xa5, 0x51, + 0x7b, 0x57, 0x42, 0x0b, 0x53, 0x4d, 0x0f, 0x61, 0x7b, 0x19, 0x27, 0xe7, + 0xe1, 0xb5, 0x9a, 0x53, 0x22, 0x3b, 0xcd, 0x05, 0xa1, 0x2c, 0x6c, 0x70, + 0xc2, 0xde, 0xfa, 0x9d, 0x2b, 0x2c, 0xc8, 0x5a, 0x86, 0xc0, 0xef, 0x04, + 0x50, 0x4b, 0xda, 0xf5, 0xc5, 0xd7, 0x99, 0x4b, 0xef, 0xef, 0xbf, 0x32, + 0x32, 0xa4, 0x3c, 0xcf, 0x52, 0xdd, 0xc8, 0x6e, 0x86, 0xa0, 0xb4, 0x21, + 0x62, 0x55, 0x4a, 0xbd, 0x2f, 0xb1, 0x2e, 0x95, 0xee, 0xea, 0xc5, 0xb3, + 0xf4, 0xd2, 0x90, 0x5a, 0x6a, 0xd8, 0xe1, 0xa5, 0x2d, 0xfb, 0x8c, 0xfe, + 0x95, 0x60, 0x8a, 0x87, 0x94, 0x37, 0x07, 0x19, 0xbf, 0x6b, 0x65, 0x80, + 0xad, 0x8a, 0x36, 0xad, 0x31, 0x4f, 0x14, 0x44, 0x6b, 0x95, 0x02, 0x4a, + 0xd3, 0xf7, 0x5e, 0xfa, 0x99, 0x9e, 0x2b, 0x9d, 0xc9, 0xdd, 0x2c, 0xa3, + 0x7e, 0x23, 0xe2, 0x95, 0x18, 0x16, 0xb0, 0x65, 0xd4, 0x5e, 0x28, 0x9b, + 0x11, 0x62, 0x9e, 0xd3, 0xdd, 0xbd, 0x5f, 0x9d, 0xa1, 0xa6, 0x2d, 0x05, + 0x69, 0xe3, 0x55, 0x65, 0xa0, 0xcc, 0xae, 0x70, 0x57, 0xe5, 0xa4, 0xc5, + 0xfe, 0xfa, 0x68, 0xe2, 0xf9, 0xbc, 0xb1, 0x1a, 0xf6, 0xec, 0x47, 0x78, + 0x36, 0xc0, 0xb6, 0xb5, 0x2a, 0x8e, 0x4c, 0x10, 0x4b, 0x57, 0x0f, 0x31, + 0x12, 0xe8, 0xab, 0xca, 0x15, 0xf1, 0x6e, 0x5a, 0x4a, 0x70, 0xd3, 0x78, + 0xae, 0x01, 0x8f, 0xec, 0x5e, 0x75, 0x15, 0xd8, 0x50, 0x73, 0xaf, 0xbb, + 0xf2, 0xda, 0x57, 0x2a, 0x9a, 0x8d, 0x48, 0x77, 0x68, 0x2a, 0x46, 0x10, + 0x69, 0x15, 0x75, 0x89, 0x8e, 0xc6, 0xb9, 0x6f, 0x51, 0x92, 0x2c, 0x44, + 0x86, 0x5e, 0x5e, 0xcc, 0xa1, 0x95, 0xb4, 0xd8, 0x38, 0xc4, 0x6b, 0xf7, + 0xa8, 0x26, 0x96, 0x08, 0xb6, 0x23, 0x28, 0x06, 0x08, 0x92, 0xce, 0xcc, + 0x0f, 0x3d, 0x2e, 0x81, 0x49, 0xcb, 0x2f, 0x09, 0x68, 0x25, 0x3a, 0xd3, + 0x3f, 0xe5, 0x46, 0x6e, 0x11, 0x6f, 0x16, 0xf5, 0x4f, 0xff, 0x4d, 0x23, + 0xe8, 0xc8, 0xf7, 0x2d, 0x4b, 0xaa, 0x6c, 0x9b, 0x81, 0xea, 0x18, 0xa7, + 0xb9, 0xd0, 0x60, 0x9e, 0x07, 0x0d, 0xde, 0xc1, 0xb6, 0x1a, 0x84, 0x45, + 0xaf, 0xf2, 0x77, 0x77, 0x7d, 0xef, 0x40, 0x23, 0x7d, 0x96, 0xf4, 0x09, + 0x9c, 0x1b, 0x8e, 0xc1, 0x99, 0x00, 0xe1, 0x1a, 0x6c, 0xd1, 0x2d, 0x51, + 0x6f, 0x68, 0x78, 0xab, 0xa9, 0xfe, 0x8a, 0xf0, 0x0b, 0x16, 0xe6, 0x29, + 0xd0, 0xe4, 0x05, 0x58, 0xda, 0x78, 0x3e, 0xc8, 0x8d, 0xb5, 0xa8, 0x70, + 0x8d, 0x72, 0x7d, 0x8d, 0x34, 0xaa, 0x95, 0x5f, 0xde, 0x23, 0x36, 0x78, + 0x30, 0xf8, 0x18, 0x10, 0xf0, 0x7f, 0x3c, 0xc2, 0xa2, 0xea, 0x1f, 0xfc, + 0x6e, 0x20, 0xb7, 0x77, 0x3c, 0x32, 0xcc, 0xf0, 0xe4, 0x1f, 0x2a, 0x00, + 0x71, 0x88, 0x86, 0x0c, 0x1f, 0x89, 0x39, 0x41, 0xe0, 0xbf, 0xe9, 0x56, + 0x81, 0x43, 0x59, 0xa3, 0x86, 0x96, 0x45, 0x2f, 0x9a, 0x51, 0xd0, 0x71, + 0x91, 0x6f, 0x24, 0xfb, 0x7e, 0x53, 0x80, 0x24, 0xac, 0x55, 0xff, 0x91, + 0x36, 0x38, 0x03, 0xa0, 0xc3, 0xb0, 0x38, 0x07, 0x80, 0xc6, 0x5c, 0x4e, + 0x5e, 0x85, 0x53, 0x1c, 0xb7, 0x28, 0x2a, 0x7f, 0x8a, 0x73, 0x35, 0x60, + 0x48, 0x06, 0x10, 0x41, 0x06, 0x12, 0xc0, 0x3c, 0x47, 0x6f, 0x9e, 0xfd, + 0x1e, 0x24, 0xe9, 0x53, 0x4c, 0x2d, 0xbc, 0xed, 0x0e, 0xd9, 0x1b, 0xd2, + 0xa0, 0xe0, 0xb3, 0xc0, 0xc2, 0xa0, 0xd8, 0xc0, 0x1c, 0x67, 0xff, 0xfe, + 0x6d, 0x2c, 0x50, 0x22, 0xa3, 0xaf, 0xe9, 0x44, 0x8a, 0x5d, 0x3b, 0x1b, + 0xbf, 0x17, 0x51, 0x80, 0x2d, 0x28, 0x7c, 0xaf, 0x8a, 0x6b, 0x5f, 0xc8, + 0x60, 0xa1, 0x03, 0x70, 0x81, 0xb0, 0xdc, 0x0f, 0x03, 0xfd, 0x8b, 0x0c, + 0x26, 0x68, 0x78, 0x3c, 0x54, 0xd8, 0xf4, 0xbd, 0x21, 0x73, 0x0d, 0x7e, + 0x28, 0xbe, 0x69, 0xaf, 0xc6, 0xa7, 0xa4, 0xbf, 0x1b, 0xe9, 0x5c, 0xa3, + 0x62, 0x63, 0x43, 0xf0, 0x43, 0xd6, 0x1a, 0x00, 0xcd, 0x1f, 0xfe, 0xc6, + 0xdb, 0x67, 0xca, 0xd5, 0x96, 0x45, 0x96, 0x9b, 0x3e, 0x1a, 0x35, 0x9b, + 0x46, 0xc0, 0x28, 0x38, 0x09, 0x1a, 0x9e, 0x78, 0x20, 0xc4, 0xd9, 0xdd, + 0xf8, 0x96, 0x9d, 0x4f, 0x67, 0x33, 0x92, 0xc0, 0x2a, 0x6f, 0x17, 0x01, + 0x06, 0x44, 0x76, 0xd8, 0x57, 0xf1, 0xf7, 0xae, 0xff, 0x59, 0xe6, 0x31, + 0xb2, 0xd5, 0xfd, 0xe2, 0xd8, 0x5b, 0x38, 0x22, 0x6e, 0xf5, 0x40, 0x2b, + 0x82, 0xd2, 0xe2, 0xee, 0x3f, 0x34, 0xe5, 0x85, 0x14, 0x9c, 0xd0, 0x65, + 0xe7, 0x37, 0x39, 0x0b, 0x34, 0x44, 0xbd, 0x5c, 0xb6, 0x06, 0xca, 0x38, + 0x0c, 0x35, 0x75, 0x47, 0x6e, 0xf6, 0xed, 0x5c, 0xa0, 0x4c, 0x0a, 0x35, + 0x58, 0xa1, 0x8c, 0xf7, 0xa7, 0x33, 0xd0, 0xab, 0x09, 0x08, 0x2a, 0x90, + 0x30, 0xba, 0x6a, 0xb5, 0xfe, 0x70, 0x97, 0x82, 0x63, 0xc3, 0xfd, 0xea, + 0x5d, 0x52, 0x8b, 0xa4, 0x6b, 0xf5, 0x77, 0x0d, 0x93, 0xa5, 0xb5, 0xb5, + 0x7b, 0x92, 0xed, 0x9d, 0x0f, 0x11, 0xdb, 0x62, 0x28, 0x08, 0xe7, 0x9a, + 0xc2, 0x28, 0x98, 0xf5, 0x29, 0x72, 0x4f, 0x84, 0x3e, 0x55, 0x7f, 0xdf, + 0x8f, 0xeb, 0x1e, 0xac, 0x2f, 0x67, 0xd3, 0x7b, 0xdd, 0xfa, 0xa2, 0xa0, + 0x2c, 0xd2, 0x2d, 0xfe, 0xe8, 0x77, 0xf5, 0x01, 0xe8, 0x31, 0x00, 0x83, + 0xd1, 0x33, 0x0c, 0x4f, 0x31, 0xe9, 0xe9, 0x88, 0x9a, 0x40, 0x8b, 0x88, + 0x86, 0xca, 0x14, 0x3c, 0x2e, 0xaa, 0xc6, 0xbd, 0x99, 0xd1, 0xc6, 0xa5, + 0x9e, 0xa2, 0x0a, 0xbf, 0x64, 0xbc, 0xb5, 0x1f, 0xa7, 0xc3, 0x80, 0xb5, + 0x95, 0x32, 0x8d, 0x6d, 0x5e, 0x0c, 0x29, 0xea, 0x88, 0x51, 0xb6, 0x32, + 0x06, 0x04, 0x41, 0x24, 0x7f, 0xff, 0x2a, 0x1d, 0x0f, 0xf0, 0x4a, 0x12, + 0x94, 0xe5, 0x64, 0xb0, 0xb6, 0x33, 0x2a, 0xe1, 0xe3, 0x0a, 0x14, 0x15, + 0x68, 0x73, 0xbf, 0xff, 0x80, 0x40, 0x4f, 0x55, 0xe0, 0x44, 0x63, 0xca, + 0x94, 0xeb, 0x79, 0x24, 0xef, 0xfe, 0xbe, 0xfe, 0xf3, 0x9d, 0x78, 0x5b, + 0x12, 0x22, 0x8f, 0x2e, 0x87, 0x83, 0x17, 0x26, 0x87, 0x68, 0x31, 0xa2, + 0xbe, 0x21, 0xe1, 0xb7, 0x1b, 0x46, 0xef, 0xb5, 0xcd, 0xe1, 0xb2, 0x25, + 0xa2, 0x01, 0x44, 0x35, 0x6f, 0xf7, 0x50, 0xf1, 0x00, 0xa8, 0xdb, 0x65, + 0xfe, 0xa8, 0xd7, 0x17, 0xc3, 0xf9, 0x26, 0xa9, 0xf8, 0x79, 0x74, 0x91, + 0x74, 0x04, 0xde, 0x10, 0xc7, 0xda, 0x7f, 0x9c, 0xca, 0xb7, 0x68, 0xbc, + 0x90, 0x29, 0x30, 0xc7, 0xbf, 0x43, 0xbd, 0xd5, 0x08, 0x0d, 0xf0, 0xd9, + 0xf1, 0x4a, 0xc6, 0xa7, 0x57, 0x25, 0x13, 0x97, 0x53, 0x6f, 0x54, 0xa3, + 0x5e, 0x2c, 0x8b, 0x88, 0x01, 0x84, 0xeb, 0x13, 0x46, 0xcd, 0x98, 0x8f, + 0xa8, 0x8a, 0x46, 0xa1, 0xb9, 0xb0, 0x0f, 0x1f, 0xa5, 0x06, 0x4b, 0x82, + 0x09, 0x67, 0x93, 0x30, 0x0a, 0x71, 0xd2, 0xaf, 0x48, 0x57, 0xcf, 0xad, + 0x2f, 0xea, 0x82, 0xbd, 0xd5, 0x70, 0x58, 0x61, 0x4f, 0x64, 0xe2, 0xf1, + 0x7e, 0x94, 0xc3, 0x96, 0x10, 0xc1, 0x48, 0x38, 0x10, 0xd2, 0x97, 0xdb, + 0xb3, 0xca, 0xd5, 0xd4, 0xfe, 0xb1, 0x69, 0xdb, 0x7b, 0x60, 0x12, 0x32, + 0x9e, 0xea, 0xf2, 0x45, 0x34, 0xc9, 0x49, 0x85, 0xa2, 0xad, 0x6f, 0x13, + 0x59, 0xdf, 0x27, 0x55, 0x58, 0xb5, 0x19, 0x66, 0xc8, 0x5a, 0xc7, 0x68, + 0x88, 0x06, 0x2d, 0x04, 0x63, 0x26, 0x07, 0xd2, 0xc4, 0x83, 0xd6, 0xbd, + 0x73, 0xf7, 0xc9, 0xfc, 0x1a, 0x71, 0x15, 0xe5, 0x0d, 0xf4, 0xf9, 0xcf, + 0xb3, 0xbe, 0x06, 0x1c, 0x17, 0xf3, 0xac, 0x7f, 0x85, 0xaa, 0x17, 0xb8, + 0xcf, 0x9b, 0xab, 0xda, 0x22, 0x81, 0x8f, 0xd0, 0x61, 0xa6, 0xf6, 0xf9, + 0x21, 0x78, 0x41, 0x80, 0xc8, 0x2f, 0x99, 0xf8, 0x13, 0xb2, 0x7c, 0x1c, + 0xa5, 0xe3, 0x54, 0xe7, 0x65, 0x31, 0xa2, 0xd5, 0x1f, 0xcc, 0xfc, 0x9b, + 0xed, 0x67, 0x88, 0xf6, 0x6c, 0xb9, 0x0b, 0x25, 0x41, 0x8a, 0x22, 0x8f, + 0x01, 0x00, 0x61, 0x3a, 0x6a, 0x94, 0xc5, 0x20, 0x53, 0x33, 0xa5, 0x42, + 0x2f, 0x50, 0xce, 0x88, 0xa0, 0xe3, 0x2c, 0x79, 0x28, 0x7d, 0x95, 0x4f, + 0x2f, 0x9b, 0xde, 0xee, 0xaf, 0x14, 0x5f, 0x7b, 0xa7, 0xa9, 0x3f, 0xf2, + 0x28, 0x63, 0xd5, 0x6b, 0x06, 0xe8, 0xd1, 0xae, 0xed, 0x8b, 0x1e, 0xab, + 0x2f, 0x4e, 0xde, 0x2a, 0x51, 0xbf, 0xf6, 0x31, 0x66, 0x95, 0x6a, 0xff, + 0x9d, 0x45, 0x41, 0x81, 0x7c, 0x68, 0x47, 0x6b, 0x04, 0xba, 0xa1, 0xbd, + 0x6d, 0x3e, 0x79, 0xac, 0xba, 0xaa, 0xfe, 0xfa, 0x7d, 0x5c, 0x25, 0xcc, + 0xd2, 0xac, 0xca, 0x1e, 0x83, 0x0a, 0xd5, 0x81, 0xee, 0x61, 0x60, 0x14, + 0x53, 0x9d, 0xd5, 0xb3, 0x92, 0xa1, 0x79, 0x66, 0x3c, 0xa0, 0x19, 0x7d, + 0xfe, 0xfe, 0x7a, 0xd0, 0xf3, 0x3f, 0x46, 0xe8, 0xf8, 0x1b, 0xa9, 0xd8, + 0xa5, 0x40, 0x10, 0x30, 0xb1, 0xc5, 0xc3, 0x4d, 0x35, 0x85, 0x8c, 0x2a, + 0x1f, 0x42, 0xd6, 0x16, 0xff, 0xf6, 0x15, 0x76, 0x2d, 0x67, 0x83, 0x60, + 0x71, 0x94, 0xac, 0xfe, 0xdc, 0xf5, 0xd9, 0xee, 0x76, 0xd9, 0xee, 0xca, + 0xa3, 0xa4, 0x26, 0x71, 0x5b, 0x2d, 0xb3, 0x1a, 0x5b, 0x3a, 0xa6, 0xfd, + 0x45, 0x5f, 0xb5, 0x04, 0xa1, 0xce, 0x03, 0x10, 0xaf, 0xa1, 0xe6, 0x08, + 0x0a, 0x94, 0xfd, 0xba, 0x56, 0x57, 0xbd, 0xbc, 0xa8, 0x6d, 0x13, 0xf4, + 0xfd, 0xad, 0xff, 0xd1, 0xcf, 0xf6, 0x76, 0xcc, 0x5b, 0x11, 0x5b, 0xd3, + 0x60, 0xfa, 0xbf, 0xfe, 0xa9, 0x75, 0x4c, 0x2d, 0xe7, 0x7e, 0xb7, 0x3a, + 0x8a, 0x3d, 0x16, 0x98, 0x51, 0x14, 0xef, 0x2e, 0xf2, 0x2f, 0xc9, 0xce, + 0x83, 0x04, 0xf7, 0xdc, 0xde, 0xa1, 0x0e, 0x51, 0x49, 0xd9, 0x78, 0x88, + 0x2c, 0xda, 0xf7, 0xa5, 0xd5, 0xef, 0xd0, 0x40, 0xf3, 0x25, 0x9c, 0x37, + 0xd0, 0x5a, 0xef, 0x30, 0x8b, 0x7b, 0xa5, 0x1d, 0xe3, 0xe5, 0xac, 0xe5, + 0xda, 0x6b, 0xa8, 0x2c, 0x5b, 0xa0, 0xc1, 0x41, 0x7b, 0xba, 0x59, 0x83, + 0x62, 0xb3, 0x4b, 0xd3, 0xcb, 0xb6, 0xae, 0xb5, 0xde, 0x28, 0xf4, 0x29, + 0xdf, 0xde, 0xb8, 0xbd, 0xf6, 0xd9, 0x92, 0xaf, 0x56, 0x82, 0x65, 0x14, + 0x37, 0xf0, 0xea, 0xc9, 0x3d, 0xc5, 0x2b, 0xf5, 0x63, 0x6f, 0xb6, 0xdb, + 0xc4, 0xde, 0x97, 0x57, 0x53, 0xd9, 0x9f, 0x8b, 0xcb, 0x61, 0x0c, 0x74, + 0xe5, 0xd4, 0x4e, 0x6c, 0x5b, 0x5a, 0x8d, 0x5a, 0x81, 0x11, 0x2d, 0x3a, + 0x7c, 0x7e, 0x23, 0x8f, 0x92, 0x6c, 0x68, 0x3d, 0x65, 0xb5, 0x0a, 0x47, + 0x0a, 0xbd, 0x7f, 0xfe, 0x12, 0xcc, 0x2a, 0x68, 0x35, 0xdf, 0x8b, 0x07, + 0xc3, 0xf1, 0x1d, 0x31, 0x78, 0x82, 0x3c, 0x05, 0x5d, 0x69, 0x5f, 0xd4, + 0xfb, 0xbe, 0xdb, 0xef, 0xf8, 0x96, 0x50, 0xb1, 0x62, 0xe4, 0xca, 0xc4, + 0x81, 0x1b, 0x1a, 0xd2, 0xd1, 0xeb, 0x73, 0xbe, 0xf6, 0xfb, 0x14, 0xb7, + 0x7d, 0xdb, 0x7d, 0xda, 0xa4, 0x6c, 0x12, 0x97, 0x8c, 0x07, 0x24, 0x42, + 0x98, 0xa8, 0x39, 0x01, 0x0d, 0x8e, 0x20, 0x32, 0xb5, 0x65, 0x78, 0x99, + 0x21, 0x65, 0x96, 0x45, 0x0c, 0xd0, 0xf5, 0x74, 0x56, 0xcc, 0x1b, 0xa0, + 0x06, 0x21, 0x36, 0xd8, 0x33, 0x62, 0x5c, 0x61, 0xb6, 0xbe, 0x90, 0xb9, + 0x86, 0xf3, 0x68, 0x19, 0xc5, 0xfd, 0x96, 0x5e, 0x5f, 0xd8, 0xa0, 0xaf, + 0x71, 0x72, 0xa0, 0x16, 0x19, 0x04, 0xb1, 0xd0, 0x43, 0x6d, 0x3c, 0x6d, + 0x86, 0x8b, 0xfd, 0xff, 0xee, 0xd0, 0x56, 0xfa, 0x4b, 0x91, 0x0f, 0xbb, + 0x9a, 0x0c, 0x36, 0x5a, 0x15, 0x06, 0xe6, 0x47, 0xe5, 0xec, 0x04, 0x1a, + 0xce, 0x02, 0x2b, 0x4d, 0xfc, 0xb7, 0x7e, 0xd2, 0xac, 0x93, 0xa5, 0xb7, + 0xd7, 0x3b, 0x67, 0x86, 0x70, 0x04, 0x8a, 0x96, 0xa4, 0x80, 0xf0, 0x90, + 0x07, 0xa9, 0x79, 0x45, 0x9e, 0x06, 0x05, 0xa3, 0x63, 0x56, 0xd2, 0x30, + 0x01, 0xec, 0xc1, 0xeb, 0x25, 0xe0, 0xca, 0x7f, 0x3d, 0x9c, 0x53, 0xfe, + 0x64, 0xe0, 0x14, 0x10, 0x03, 0x83, 0xa7, 0x13, 0x82, 0x83, 0x1b, 0x66, + 0xeb, 0x49, 0xb6, 0xf0, 0x19, 0x1f, 0xb2, 0x15, 0x7b, 0x62, 0x1f, 0x06, + 0xda, 0x0c, 0x13, 0x96, 0x2e, 0x1e, 0x0e, 0xd2, 0x32, 0xd3, 0x63, 0x82, + 0xff, 0x55, 0x33, 0x9e, 0x6b, 0xd6, 0xac, 0x6d, 0x6d, 0x06, 0x0a, 0x82, + 0x43, 0x09, 0x4b, 0xb2, 0xe0, 0x83, 0x5b, 0x1e, 0x27, 0x9c, 0x97, 0xff, + 0x8a, 0x1a, 0x6f, 0x7a, 0x88, 0x18, 0x22, 0xfd, 0xff, 0x74, 0x0b, 0x28, + 0x07, 0xcb, 0x80, 0x1c, 0xbc, 0x98, 0x04, 0x02, 0xc6, 0xcc, 0xaa, 0x03, + 0xde, 0xf3, 0x2a, 0x44, 0x0d, 0x9b, 0x39, 0x7c, 0xbd, 0xf4, 0xc0, 0x46, + 0x04, 0x91, 0x1a, 0x6d, 0xdc, 0xcf, 0x83, 0x21, 0xfc, 0xe8, 0xe2, 0x21, + 0xbf, 0x44, 0x0c, 0x34, 0x58, 0x7f, 0x9b, 0xf1, 0x24, 0xae, 0xcf, 0x64, + 0xe6, 0x69, 0x66, 0x0d, 0xef, 0xca, 0xfd, 0xfe, 0x29, 0x52, 0x82, 0x95, + 0x87, 0x40, 0x24, 0xaf, 0xbd, 0xe2, 0xe6, 0xda, 0xc1, 0x01, 0x3f, 0xdb, + 0x6e, 0xf6, 0x5c, 0x62, 0xec, 0x80, 0xaf, 0xa0, 0xc1, 0x58, 0xa9, 0x6a, + 0xaf, 0x65, 0x51, 0xef, 0x63, 0xd0, 0x04, 0x36, 0x0b, 0xe4, 0x80, 0x84, + 0xaf, 0xe9, 0x14, 0xab, 0x64, 0x40, 0x56, 0xce, 0xee, 0x83, 0x22, 0x96, + 0xe4, 0xb7, 0xa5, 0x9c, 0x52, 0xa0, 0x04, 0x06, 0x40, 0x0d, 0x05, 0x20, + 0xec, 0x7c, 0x0c, 0x57, 0xf6, 0xc1, 0x15, 0x27, 0x43, 0xb8, 0x54, 0xa2, + 0x54, 0x3f, 0xf0, 0x7a, 0x7a, 0x53, 0x83, 0x01, 0xb5, 0x6a, 0x14, 0x25, + 0x82, 0x53, 0x4b, 0x83, 0x08, 0x9d, 0x2f, 0xbb, 0xd3, 0x5b, 0xab, 0x62, + 0xc0, 0xc1, 0x41, 0x40, 0x86, 0x0c, 0x1f, 0xa4, 0xbb, 0xef, 0xa5, 0x56, + 0xca, 0xad, 0xe9, 0x5d, 0xda, 0x59, 0x61, 0xa3, 0xc3, 0x5f, 0xfe, 0xfe, + 0x2f, 0xff, 0x9e, 0x6b, 0x0f, 0xbf, 0x00, 0x00, 0xbc, 0x08, 0x6c, 0x78, + 0x3a, 0xa9, 0x82, 0x10, 0x8c, 0x5f, 0xf4, 0xbf, 0x03, 0x03, 0xd1, 0xea, + 0xb0, 0x2d, 0x14, 0xb6, 0x5b, 0xff, 0xde, 0x72, 0x15, 0x15, 0xe6, 0x47, + 0x8e, 0xc7, 0xc2, 0x52, 0x71, 0x24, 0x7e, 0xda, 0xbf, 0x34, 0x5b, 0x8c, + 0x4f, 0xee, 0x63, 0x7c, 0xbd, 0x43, 0x3b, 0x43, 0x91, 0x14, 0x15, 0xe6, + 0x46, 0xcd, 0x63, 0x4c, 0xab, 0xd8, 0xaf, 0xfe, 0xa5, 0x9a, 0xc9, 0x63, + 0x4a, 0xea, 0x86, 0x03, 0xb4, 0x2f, 0x0b, 0x6c, 0x0f, 0x80, 0xe9, 0x79, + 0x77, 0xe8, 0x84, 0x5d, 0x8a, 0xb1, 0x42, 0x85, 0x49, 0xd8, 0xe5, 0x68, + 0x44, 0xed, 0x03, 0x21, 0xb0, 0x8a, 0x0f, 0x95, 0xff, 0xd8, 0x9c, 0x38, + 0xb1, 0x63, 0x8d, 0x82, 0x9d, 0x35, 0x8d, 0x8f, 0x93, 0x7e, 0x72, 0xa9, + 0x6b, 0x29, 0x2c, 0xbc, 0x9d, 0x07, 0x6b, 0xf9, 0x90, 0xe6, 0x0d, 0x80, + 0xa3, 0xa3, 0xc9, 0x42, 0x00, 0x1d, 0x1c, 0xb4, 0xce, 0x7f, 0x4b, 0x12, + 0xef, 0xa0, 0xe2, 0xcb, 0x6d, 0xe5, 0xfe, 0x0d, 0xb1, 0x4f, 0x75, 0x4e, + 0x87, 0x80, 0x24, 0x56, 0x3d, 0x06, 0x4a, 0x07, 0x87, 0xca, 0x73, 0x13, + 0xf8, 0xbd, 0x3c, 0x9a, 0x06, 0x15, 0x6c, 0xb1, 0x12, 0xdd, 0xf8, 0xdb, + 0x0a, 0xc3, 0x82, 0xd1, 0x6a, 0x1e, 0x15, 0x9a, 0xe6, 0xc6, 0x40, 0x74, + 0x4b, 0x54, 0x24, 0x0f, 0xb5, 0xb6, 0x55, 0xf9, 0xab, 0xfe, 0xf9, 0xa5, + 0x28, 0xef, 0xcd, 0x40, 0xd0, 0xc0, 0x7f, 0xd4, 0xb4, 0x7f, 0x91, 0x33, + 0x4d, 0xee, 0x62, 0xbd, 0x5d, 0x96, 0x2a, 0x8d, 0x51, 0x11, 0xc9, 0x54, + 0x0a, 0x01, 0xa0, 0x10, 0xc0, 0xf8, 0xf4, 0x03, 0x52, 0xeb, 0x29, 0xf6, + 0x4c, 0xce, 0x8e, 0x13, 0x4d, 0xb1, 0xa6, 0xb0, 0xd7, 0x83, 0x70, 0xdc, + 0x18, 0x84, 0x5a, 0x07, 0x07, 0xca, 0xcb, 0x27, 0xf6, 0x2d, 0x43, 0xae, + 0xa3, 0x51, 0x51, 0x03, 0x05, 0x53, 0xd2, 0x6f, 0xe2, 0xca, 0x61, 0x86, + 0x9a, 0xa5, 0xed, 0x88, 0x04, 0x86, 0xd3, 0xa6, 0xf6, 0x2a, 0x4c, 0xdd, + 0x5f, 0x92, 0x62, 0xd6, 0x92, 0x2e, 0x64, 0x2e, 0xa6, 0xc1, 0x25, 0xac, + 0x10, 0x47, 0xed, 0xfb, 0xa2, 0x23, 0x5e, 0x93, 0x7e, 0x49, 0x2d, 0x05, + 0xaa, 0x82, 0x32, 0x7c, 0x48, 0x5f, 0x0b, 0x57, 0x2c, 0xca, 0x56, 0xb6, + 0x49, 0x56, 0xe0, 0xdd, 0x18, 0x30, 0x98, 0x5e, 0x3e, 0x95, 0x5b, 0x11, + 0x2d, 0xea, 0x9d, 0x97, 0x5a, 0xce, 0x70, 0xa9, 0x07, 0x46, 0x2a, 0x41, + 0x5c, 0x16, 0x10, 0xcd, 0xf6, 0x6a, 0x8f, 0x41, 0x62, 0x3d, 0x31, 0x7a, + 0xa1, 0xea, 0xb1, 0xb9, 0x67, 0xba, 0xb5, 0x10, 0x37, 0x66, 0xef, 0x49, + 0x3c, 0x16, 0x21, 0x44, 0x7f, 0xdd, 0xef, 0xf9, 0x9a, 0xb0, 0xd9, 0x69, + 0x36, 0x2d, 0x61, 0xe1, 0x9d, 0xc6, 0x7e, 0x9e, 0x6e, 0x20, 0xe8, 0x7a, + 0x4a, 0x7c, 0x43, 0xf1, 0xe4, 0xfa, 0x65, 0x4d, 0xed, 0xeb, 0x3f, 0xf1, + 0x5e, 0xc5, 0x97, 0x15, 0x8d, 0x5a, 0xb9, 0xf6, 0xbc, 0xa5, 0x84, 0xf7, + 0x14, 0xf9, 0x46, 0xde, 0x5b, 0xfc, 0x45, 0x61, 0x2b, 0x85, 0x8c, 0x24, + 0xf4, 0xcb, 0xbc, 0x95, 0x47, 0x42, 0xa3, 0xb4, 0x3f, 0x4c, 0xa0, 0x45, + 0xe2, 0x21, 0x12, 0x70, 0x52, 0x18, 0x15, 0x83, 0x7d, 0x2a, 0xa0, 0x0c, + 0x6c, 0x21, 0xb2, 0x3e, 0xf2, 0x98, 0x06, 0x1a, 0x2e, 0x55, 0xbd, 0x8d, + 0xed, 0x6e, 0x30, 0xc5, 0xee, 0x60, 0xdb, 0x7a, 0xa5, 0x49, 0x60, 0x74, + 0x0c, 0x40, 0xd4, 0xb8, 0x84, 0x80, 0x98, 0xa6, 0xde, 0x6d, 0xe8, 0xac, + 0x2f, 0x26, 0x4f, 0x9e, 0x54, 0xd3, 0x76, 0x01, 0x9f, 0xb5, 0x85, 0x48, + 0xb9, 0x6c, 0x96, 0x86, 0x80, 0x26, 0xae, 0xd6, 0xef, 0x51, 0x51, 0xac, + 0xe3, 0xd3, 0x5c, 0x73, 0xcf, 0x8d, 0xb6, 0x4b, 0x51, 0x94, 0x23, 0xa0, + 0xe3, 0x06, 0x99, 0x63, 0xe5, 0xe0, 0x43, 0xec, 0x71, 0x68, 0x87, 0x9d, + 0x9d, 0xe0, 0x6e, 0x0b, 0x7b, 0x56, 0xa8, 0xb6, 0xe6, 0x96, 0xec, 0xdf, + 0x66, 0x96, 0x58, 0x88, 0x3d, 0x96, 0x72, 0xc1, 0x14, 0x8d, 0x44, 0x89, + 0x9b, 0x4d, 0xd1, 0xc6, 0xde, 0x5d, 0x2d, 0xb8, 0x05, 0x14, 0xd4, 0x76, + 0x44, 0x0a, 0x4c, 0x97, 0xd3, 0x54, 0xee, 0xd8, 0xf1, 0x5b, 0x00, 0xa6, + 0x1f, 0x0f, 0xcb, 0xb7, 0x6c, 0x69, 0x66, 0xd5, 0x1b, 0xce, 0xb7, 0xb7, + 0x92, 0x87, 0x28, 0xcc, 0x27, 0x38, 0xca, 0x71, 0xf3, 0x7a, 0xbf, 0x87, + 0xe5, 0xdf, 0xc6, 0x50, 0x6e, 0x46, 0x27, 0x3f, 0x68, 0x72, 0x56, 0x0c, + 0x44, 0x44, 0x47, 0x54, 0xa3, 0x7c, 0x20, 0xf7, 0x7c, 0x3d, 0xd8, 0xd7, + 0x62, 0x39, 0x7f, 0x7b, 0x60, 0x54, 0xba, 0x6c, 0xbf, 0x54, 0x93, 0xb2, + 0xa9, 0xdf, 0x0e, 0xd2, 0x40, 0xe7, 0x24, 0xbd, 0x02, 0x4a, 0x79, 0x4b, + 0x4c, 0x0d, 0x7c, 0x12, 0x47, 0x3e, 0x37, 0x79, 0x65, 0x9a, 0x2a, 0x1e, + 0x0f, 0xda, 0x50, 0xb6, 0x07, 0xcd, 0xc2, 0xc5, 0xeb, 0x79, 0x7d, 0x01, + 0x1d, 0x40, 0x31, 0x0b, 0x57, 0xca, 0xa9, 0x33, 0x79, 0xf2, 0xad, 0x51, + 0x9b, 0xbc, 0xe4, 0x92, 0x44, 0x40, 0xc2, 0x75, 0x58, 0xc4, 0xe1, 0xfe, + 0xfe, 0x5f, 0xe6, 0x7f, 0xcc, 0x42, 0xc9, 0xc9, 0xc8, 0xc4, 0x99, 0x67, + 0x83, 0x4d, 0xee, 0x83, 0x10, 0x24, 0x93, 0x3c, 0xd2, 0xa1, 0xea, 0x66, + 0x6a, 0x94, 0xcc, 0x37, 0xa5, 0x9d, 0x5f, 0xb9, 0xfa, 0x0c, 0x73, 0x73, + 0xd6, 0x9f, 0x3e, 0x59, 0x5a, 0xc2, 0xa2, 0xab, 0x71, 0x40, 0x8b, 0x49, + 0x68, 0x72, 0x1b, 0x03, 0x10, 0x28, 0x91, 0x49, 0x79, 0x76, 0xb4, 0x5a, + 0x58, 0xdb, 0x4d, 0x83, 0x2f, 0xa2, 0x2d, 0x43, 0x21, 0xfb, 0x12, 0x35, + 0x96, 0x29, 0x7b, 0x17, 0x36, 0xb0, 0xc7, 0xbb, 0xea, 0x8e, 0xf2, 0xc0, + 0x2d, 0xd0, 0xe5, 0x70, 0xf0, 0x50, 0x92, 0xae, 0x64, 0xd2, 0xcc, 0x59, + 0x3d, 0xcd, 0xea, 0x15, 0xa5, 0x97, 0xb0, 0x36, 0x04, 0x85, 0xed, 0x3f, + 0xf2, 0x03, 0x0d, 0x98, 0xf7, 0x27, 0x27, 0xf5, 0x16, 0xa9, 0x42, 0x76, + 0xd7, 0x69, 0x9b, 0xa3, 0x69, 0x5a, 0xcf, 0x14, 0xa2, 0xe7, 0x06, 0x9f, + 0x77, 0x96, 0xcb, 0x96, 0xf0, 0x6d, 0xc5, 0xe5, 0xde, 0x5a, 0xb8, 0x2d, + 0xe3, 0x58, 0x10, 0x73, 0x07, 0x37, 0x9f, 0xbf, 0xe7, 0x3a, 0xa6, 0x87, + 0x92, 0x07, 0x96, 0x88, 0x84, 0x1d, 0xb9, 0xb8, 0xb5, 0xee, 0xdd, 0xda, + 0x36, 0xc1, 0x12, 0x1a, 0x76, 0xee, 0x95, 0x22, 0xea, 0x22, 0x45, 0x90, + 0x48, 0x09, 0x69, 0x60, 0x6e, 0xb6, 0x9d, 0xf4, 0x6c, 0xb2, 0x25, 0xca, + 0x78, 0x4d, 0x29, 0x7b, 0xb3, 0x96, 0xa2, 0x97, 0xb2, 0xc8, 0x88, 0x94, + 0xfc, 0x83, 0x2c, 0xa9, 0x8a, 0xde, 0xf3, 0x18, 0x92, 0x77, 0xf5, 0x68, + 0x79, 0x3f, 0x78, 0xb7, 0xca, 0x21, 0x54, 0xe8, 0xcf, 0x82, 0xae, 0x3d, + 0x49, 0xef, 0xaa, 0x99, 0x7d, 0x19, 0x62, 0x74, 0x41, 0xc5, 0x17, 0xaa, + 0x38, 0xb5, 0xe2, 0x92, 0xbc, 0x31, 0x27, 0xbd, 0x77, 0xa4, 0xcd, 0x8f, + 0x07, 0xa0, 0xa3, 0x07, 0x02, 0x9c, 0x46, 0x03, 0x4d, 0xa4, 0x82, 0x06, + 0xdf, 0x36, 0x88, 0xb5, 0x0a, 0xd7, 0x06, 0xf8, 0xcb, 0x5d, 0x06, 0x1a, + 0x93, 0xee, 0x34, 0x01, 0xc9, 0x34, 0x44, 0x55, 0xec, 0xe1, 0xae, 0x5b, + 0xa7, 0xc9, 0x44, 0x8d, 0x7f, 0xc9, 0x95, 0x01, 0x86, 0x4b, 0xbc, 0xb0, + 0xe6, 0xaf, 0x56, 0x5b, 0xd0, 0x39, 0xd2, 0xa1, 0x14, 0x05, 0xb1, 0x1c, + 0x4a, 0x0f, 0xc7, 0xda, 0x24, 0x0e, 0x75, 0x8c, 0x2a, 0x50, 0x58, 0x8e, + 0x16, 0x5b, 0xce, 0x5d, 0x1b, 0xe2, 0xe1, 0x61, 0x78, 0xe1, 0x1c, 0xc9, + 0x84, 0x49, 0x86, 0x3f, 0x46, 0x07, 0xe9, 0x7c, 0x97, 0x99, 0x64, 0x66, + 0x8e, 0x22, 0x32, 0x49, 0x43, 0x62, 0x30, 0xa4, 0xc3, 0x45, 0x4a, 0x36, + 0xcd, 0xb3, 0xb0, 0xda, 0x22, 0x26, 0x24, 0x00, 0x70, 0xfd, 0xa5, 0x7f, + 0xf0, 0xfc, 0x40, 0xa9, 0x98, 0x0e, 0xbe, 0xaa, 0x16, 0x6a, 0x74, 0x5c, + 0x2d, 0x8a, 0x56, 0xcc, 0x02, 0xa6, 0x11, 0x2e, 0xf3, 0x65, 0x94, 0x38, + 0xe2, 0xc6, 0xec, 0x43, 0xc0, 0xd0, 0x16, 0x8a, 0x2a, 0x44, 0xc6, 0x3e, + 0x4e, 0x39, 0xef, 0x2e, 0x6f, 0x97, 0x2b, 0x88, 0xfb, 0x2d, 0x97, 0xdc, + 0x11, 0x14, 0x1e, 0x1f, 0x7c, 0x4b, 0x4c, 0xa8, 0x21, 0xb3, 0xa9, 0x7b, + 0xfb, 0x26, 0xcf, 0x36, 0x8f, 0x1a, 0x63, 0x93, 0xbe, 0x90, 0x19, 0x01, + 0x58, 0x76, 0x04, 0x45, 0xa3, 0x01, 0xe3, 0x1b, 0x19, 0x2f, 0xd1, 0x05, + 0x56, 0x97, 0x33, 0x41, 0x58, 0xa1, 0x7d, 0xbf, 0x9f, 0x0f, 0x69, 0x21, + 0x5f, 0x70, 0x15, 0xf8, 0x65, 0x14, 0xa2, 0x43, 0x19, 0x9a, 0xc4, 0x62, + 0x75, 0xbe, 0xec, 0xd5, 0xe5, 0x2d, 0xa8, 0x6d, 0x01, 0x22, 0xab, 0x2c, + 0x75, 0x5b, 0x17, 0x02, 0x28, 0xfa, 0xa6, 0xfa, 0x71, 0xce, 0x08, 0x0c, + 0x50, 0x32, 0x58, 0x57, 0xc1, 0x51, 0x8a, 0x01, 0xa0, 0x80, 0xde, 0x07, + 0xcc, 0xe9, 0x6f, 0xb7, 0x90, 0x19, 0x76, 0xaa, 0x82, 0x9e, 0x87, 0xa0, + 0x24, 0xf0, 0x28, 0x95, 0x32, 0xc6, 0xfd, 0x22, 0xb6, 0xac, 0x95, 0x7e, + 0xa3, 0x63, 0x64, 0xfd, 0x40, 0x1c, 0xa8, 0xa0, 0xef, 0x83, 0xe5, 0x40, + 0x0e, 0xa0, 0x1d, 0x06, 0xc0, 0x36, 0x95, 0xb5, 0x63, 0xce, 0xe6, 0xad, + 0x0b, 0x28, 0x75, 0xb2, 0x2c, 0xb0, 0x70, 0x16, 0x31, 0x1f, 0xda, 0x4e, + 0xda, 0x81, 0x03, 0xd8, 0x0e, 0x03, 0xe9, 0x7e, 0x39, 0xa5, 0xed, 0x37, + 0x14, 0x17, 0x6e, 0xa2, 0x9c, 0xb2, 0xd9, 0xd0, 0x70, 0x74, 0x50, 0x64, + 0x2d, 0xa7, 0xde, 0x76, 0xa9, 0x51, 0xc8, 0x33, 0xe4, 0x01, 0x3d, 0xa6, + 0x0b, 0xc2, 0x00, 0x80, 0xce, 0xe4, 0x1c, 0x26, 0x6a, 0x23, 0xe6, 0x4b, + 0xb5, 0x1d, 0x02, 0x7b, 0xd3, 0x21, 0x9e, 0x04, 0x1f, 0x97, 0xb6, 0x20, + 0xb7, 0x14, 0xb5, 0xd1, 0xb7, 0xb9, 0xb9, 0xcb, 0x51, 0xac, 0x37, 0xd0, + 0x4b, 0x4c, 0x63, 0x77, 0xa4, 0xd5, 0xc9, 0x87, 0x10, 0x36, 0x3f, 0x10, + 0x68, 0x29, 0xf4, 0x11, 0x53, 0x66, 0xfc, 0x3a, 0xdb, 0x1b, 0xe7, 0x56, + 0x5f, 0x4b, 0x54, 0x6e, 0x60, 0x2d, 0x04, 0x8a, 0xc7, 0x89, 0xa8, 0x95, + 0x7b, 0xf6, 0x74, 0xb6, 0x4a, 0xd0, 0xe4, 0xae, 0xa8, 0xbc, 0xe4, 0xbf, + 0x0e, 0x57, 0x52, 0x1d, 0x02, 0x50, 0x5e, 0xd1, 0x23, 0xc1, 0xf3, 0x29, + 0xc7, 0xd6, 0x34, 0x9c, 0xb0, 0x72, 0x54, 0x8b, 0x64, 0x9d, 0x5d, 0xcb, + 0x89, 0x40, 0x77, 0xdb, 0x5a, 0x1f, 0x6f, 0xae, 0xdf, 0x2a, 0x1c, 0xab, + 0xde, 0x07, 0x9e, 0xd9, 0x11, 0x06, 0x60, 0xc3, 0x57, 0x9e, 0xe4, 0xef, + 0x54, 0x85, 0x91, 0x00, 0x00, 0xc1, 0x08, 0x6c, 0x37, 0x01, 0xaf, 0x67, + 0xc1, 0x16, 0x4e, 0xf3, 0x6a, 0x94, 0x75, 0x75, 0xea, 0xe0, 0xc2, 0x71, + 0x28, 0x84, 0x0c, 0xad, 0x58, 0xf8, 0x15, 0x99, 0xed, 0xfe, 0x5f, 0xe6, + 0x32, 0xba, 0x8f, 0x28, 0xb7, 0xf2, 0xd6, 0x3d, 0xaa, 0x14, 0xb6, 0x04, + 0x00, 0xaf, 0xc5, 0x88, 0x84, 0x14, 0xa0, 0xa6, 0x4c, 0x91, 0xb5, 0x4a, + 0xa6, 0xb7, 0xc8, 0x1f, 0xde, 0xdd, 0x96, 0x70, 0x18, 0x93, 0x0a, 0x81, + 0x84, 0xe1, 0x9b, 0xc9, 0x58, 0x57, 0xea, 0x20, 0x37, 0x3c, 0x96, 0xd8, + 0x06, 0x2c, 0xa5, 0xb2, 0xd9, 0x7b, 0x7d, 0xfd, 0x11, 0x73, 0x4a, 0x94, + 0x82, 0xdc, 0x2f, 0x99, 0x2a, 0x30, 0x4b, 0x16, 0xab, 0x9e, 0x6c, 0x31, + 0x03, 0x0f, 0x55, 0xb0, 0xda, 0x5f, 0x6c, 0xfb, 0x29, 0xda, 0x57, 0xea, + 0xcc, 0xac, 0xac, 0x94, 0x7d, 0xb7, 0xf4, 0x1c, 0x5d, 0x18, 0x06, 0x02, + 0x8d, 0x66, 0x73, 0x4a, 0xcb, 0x7e, 0xac, 0x3b, 0x2d, 0x16, 0x06, 0x7a, + 0x55, 0x85, 0xb7, 0xdf, 0xb3, 0xfd, 0x51, 0xfd, 0x8a, 0x25, 0xe2, 0xd6, + 0x40, 0xec, 0x12, 0x06, 0xbb, 0x77, 0xec, 0xeb, 0x5f, 0xff, 0xf7, 0x33, + 0x69, 0x69, 0x6f, 0x6b, 0x62, 0x0f, 0x2c, 0x5e, 0x83, 0x21, 0xc0, 0x60, + 0x96, 0x2a, 0x9b, 0xdf, 0x75, 0x42, 0x35, 0x19, 0xde, 0xe2, 0xe8, 0xe7, + 0x83, 0x7d, 0x58, 0x69, 0x37, 0xd2, 0x43, 0x87, 0x1e, 0x6d, 0x7c, 0x9d, + 0xab, 0x59, 0x09, 0x6a, 0xd3, 0xa8, 0xcf, 0x0b, 0x1a, 0x00, 0xd4, 0xfe, + 0xcc, 0xf7, 0xa6, 0x45, 0x12, 0x2e, 0xba, 0x04, 0x40, 0x97, 0x37, 0x39, + 0x67, 0x94, 0x59, 0x44, 0x54, 0x37, 0xa2, 0x83, 0xa5, 0x5e, 0x0e, 0xaf, + 0x4a, 0x73, 0x96, 0x12, 0x8d, 0xc1, 0xd8, 0x2b, 0x37, 0xdf, 0xff, 0xba, + 0xa2, 0x85, 0x90, 0xc3, 0x65, 0x30, 0x0e, 0xd6, 0xd9, 0x2e, 0x53, 0x24, + 0x68, 0x3f, 0x55, 0x47, 0x76, 0x2f, 0xac, 0x87, 0xb2, 0x5e, 0x83, 0x12, + 0x2e, 0xa0, 0x2c, 0x04, 0xc0, 0xf8, 0x76, 0xd0, 0x18, 0xd5, 0x38, 0xa3, + 0x99, 0x7b, 0xd5, 0x94, 0x54, 0x21, 0x5f, 0x97, 0xc5, 0x93, 0x37, 0x34, + 0xb6, 0x6a, 0xdc, 0x58, 0xaa, 0xca, 0xb0, 0x23, 0x9e, 0x06, 0x20, 0x20, + 0x02, 0x17, 0xe2, 0x65, 0x55, 0x96, 0x5b, 0xdd, 0xbb, 0xea, 0x58, 0x05, + 0x1a, 0x60, 0x6e, 0x59, 0xd0, 0xdc, 0x0a, 0xe1, 0x82, 0x98, 0x85, 0xbd, + 0xe8, 0x3e, 0x4f, 0xff, 0x65, 0x7b, 0xa7, 0x53, 0x16, 0xb2, 0x91, 0x23, + 0x61, 0xec, 0x84, 0xaa, 0x71, 0x65, 0x89, 0xe7, 0xed, 0x8e, 0x72, 0x4e, + 0x95, 0x7b, 0x27, 0x03, 0x7b, 0x22, 0x20, 0x60, 0x8c, 0x20, 0xfc, 0x7f, + 0x58, 0x68, 0x3e, 0xf6, 0x95, 0xd0, 0xea, 0x41, 0x13, 0xc8, 0x7b, 0x46, + 0x88, 0x8f, 0xbb, 0xff, 0x50, 0xf5, 0x0d, 0x44, 0x8e, 0x0a, 0xad, 0xce, + 0x4e, 0xbd, 0x53, 0x19, 0xe2, 0x51, 0x07, 0xc3, 0xff, 0x2b, 0x51, 0x8d, + 0x96, 0xcc, 0xc4, 0x1c, 0x9f, 0x85, 0x92, 0x5a, 0x32, 0xba, 0x0c, 0x26, + 0xe1, 0x08, 0x7c, 0x0c, 0xa0, 0x7c, 0xa8, 0x79, 0x9f, 0xad, 0xf9, 0x37, + 0xf7, 0x8b, 0xdd, 0x51, 0x96, 0xdb, 0x3d, 0x3f, 0xa3, 0x75, 0x1d, 0xa5, + 0x62, 0xb1, 0xb8, 0x28, 0xd2, 0x46, 0xc1, 0x54, 0x24, 0x35, 0x95, 0x43, + 0x29, 0xe2, 0xb5, 0x6a, 0xef, 0xef, 0x4b, 0x7c, 0xbc, 0x0f, 0x30, 0xad, + 0xb0, 0x54, 0x82, 0xa3, 0x00, 0x50, 0x5c, 0x04, 0x51, 0xe4, 0xf4, 0xd9, + 0xe2, 0xc6, 0x47, 0x05, 0x7c, 0xca, 0x36, 0x58, 0xd0, 0x73, 0xc8, 0x65, + 0xec, 0x5a, 0x50, 0x5a, 0xbb, 0x78, 0x41, 0x48, 0xd8, 0x8e, 0x58, 0x0a, + 0xdc, 0x4f, 0x9e, 0xdd, 0x06, 0x43, 0x3d, 0xfc, 0xf5, 0xe7, 0x2d, 0x50, + 0x38, 0xd0, 0x7c, 0xbf, 0xfe, 0xc5, 0xad, 0x6c, 0xdd, 0xe6, 0x2e, 0x2e, + 0x38, 0x61, 0x5c, 0xf2, 0x56, 0x22, 0xb6, 0x11, 0xe4, 0x9d, 0x36, 0x78, + 0xf8, 0x85, 0x44, 0x01, 0x07, 0xed, 0xdb, 0x61, 0x67, 0x61, 0xa2, 0x74, + 0xb8, 0x1e, 0x52, 0x79, 0x1c, 0x99, 0x7f, 0xe7, 0x0a, 0x6c, 0x0a, 0xc6, + 0x3f, 0xed, 0x5b, 0xcb, 0x71, 0x6b, 0x4d, 0x57, 0x23, 0xe0, 0x87, 0x8a, + 0xfe, 0x55, 0x29, 0x62, 0x85, 0xd0, 0x93, 0x22, 0xb4, 0xee, 0xcb, 0x2e, + 0x21, 0x36, 0x34, 0x65, 0x1c, 0x23, 0xdb, 0x18, 0x0f, 0xe2, 0xbc, 0x50, + 0xa2, 0xf7, 0x9c, 0xbb, 0xb5, 0x1d, 0xde, 0xc4, 0x41, 0xc0, 0x58, 0xbb, + 0x4a, 0xc3, 0xea, 0x99, 0xa0, 0x60, 0xe0, 0xbf, 0x71, 0x7a, 0x0c, 0x1c, + 0xb7, 0x4b, 0x38, 0x1c, 0x95, 0x47, 0xa0, 0x96, 0xe6, 0xf9, 0x59, 0xaf, + 0xb5, 0xbc, 0x37, 0xc9, 0x09, 0x87, 0x81, 0xdc, 0x1f, 0x33, 0xea, 0x05, + 0xd5, 0x97, 0x53, 0x7c, 0x92, 0x7f, 0xa5, 0x28, 0x9c, 0x63, 0x64, 0x07, + 0xab, 0x9c, 0xe5, 0x05, 0xa9, 0x64, 0x87, 0x98, 0x0e, 0x2f, 0x67, 0x6a, + 0xf5, 0x56, 0x32, 0xa9, 0x4a, 0x1e, 0x4b, 0x3f, 0xe0, 0x76, 0x3c, 0xcf, + 0xc6, 0xc5, 0xf3, 0xeb, 0x8e, 0x7a, 0x55, 0x17, 0xa8, 0xf9, 0x28, 0x56, + 0x24, 0xc0, 0x2e, 0x07, 0xf7, 0xdc, 0xc5, 0x2c, 0x0f, 0x98, 0x52, 0x86, + 0xfe, 0xfa, 0xf7, 0xb0, 0x66, 0xa4, 0x18, 0x86, 0x33, 0x2c, 0xda, 0x39, + 0xd9, 0xfc, 0x69, 0xa9, 0x14, 0xf2, 0x44, 0x53, 0x91, 0x61, 0x13, 0x42, + 0xd3, 0x0f, 0x7d, 0x97, 0xfe, 0xe2, 0x64, 0x9f, 0xfc, 0x80, 0x66, 0xfa, + 0x74, 0xdd, 0xb2, 0x70, 0xea, 0xc3, 0xc6, 0xff, 0xa5, 0xc0, 0x6f, 0xfc, + 0x52, 0xa7, 0x67, 0xbd, 0x16, 0x42, 0xb8, 0x30, 0x26, 0x98, 0x4e, 0xd0, + 0x7e, 0x3e, 0x50, 0x86, 0x0d, 0xd7, 0x5e, 0x71, 0x6b, 0x4f, 0xa8, 0x92, + 0xfb, 0x5a, 0x2c, 0xef, 0x40, 0xd7, 0x3c, 0xa3, 0x9c, 0xec, 0x07, 0x07, + 0x3c, 0x01, 0x32, 0xda, 0x55, 0x9c, 0xc3, 0x57, 0xb2, 0x29, 0x95, 0x0f, + 0x48, 0x76, 0xc0, 0xeb, 0x7a, 0x8a, 0x52, 0xd3, 0x6b, 0xf1, 0x70, 0xdb, + 0x48, 0x92, 0x2b, 0x53, 0x59, 0xcc, 0xa1, 0xe7, 0x3b, 0x91, 0x7b, 0xf2, + 0x4a, 0x6f, 0x0c, 0x20, 0x5b, 0x2a, 0x8f, 0xf2, 0xe4, 0xb0, 0xae, 0x59, + 0xc5, 0xc8, 0x65, 0xba, 0x53, 0x56, 0xe5, 0x58, 0x2b, 0x2a, 0xd4, 0x98, + 0xba, 0x0b, 0xc0, 0xc9, 0x70, 0x60, 0xae, 0x15, 0x16, 0x7c, 0x6c, 0x45, + 0x19, 0x83, 0x7b, 0xd5, 0xbd, 0x0a, 0x69, 0xff, 0x6d, 0xcc, 0x5a, 0xb2, + 0x39, 0x53, 0x24, 0xd9, 0x5a, 0x5a, 0x72, 0x8a, 0x4b, 0xe6, 0xd5, 0x6d, + 0x66, 0x31, 0xd8, 0x86, 0xaf, 0xda, 0xa4, 0x15, 0x20, 0xb5, 0xeb, 0xf2, + 0xd4, 0x77, 0xa3, 0x2b, 0x38, 0x44, 0x70, 0x19, 0x48, 0x29, 0xbd, 0x73, + 0x33, 0x01, 0x4e, 0xcd, 0xe1, 0x50, 0x14, 0x95, 0x0b, 0xd6, 0xce, 0x64, + 0x78, 0x9e, 0x07, 0x4e, 0x4d, 0x4e, 0x2a, 0x55, 0xef, 0xe3, 0x31, 0x85, + 0xfb, 0xb6, 0x87, 0x51, 0x4f, 0xea, 0x9e, 0xd1, 0xb9, 0x5a, 0xe1, 0x68, + 0xf4, 0xbd, 0x28, 0xfd, 0x55, 0xdd, 0x05, 0x30, 0x29, 0xd5, 0x4e, 0xa8, + 0x4a, 0x5d, 0xff, 0x6c, 0x2c, 0x88, 0xa7, 0x06, 0xe1, 0x6d, 0x44, 0x93, + 0xfc, 0x0f, 0xc0, 0xcf, 0x3b, 0xde, 0x8d, 0xb7, 0xf5, 0x1f, 0xec, 0x11, + 0x51, 0x03, 0xe4, 0x40, 0x0e, 0x2c, 0xd9, 0x18, 0x6b, 0xfb, 0x33, 0x81, + 0xed, 0xe4, 0x88, 0xa7, 0xbd, 0xe6, 0xea, 0xc1, 0xc0, 0x38, 0x3d, 0x23, + 0x2b, 0x10, 0x38, 0xa4, 0xc6, 0x43, 0xe0, 0x41, 0x1f, 0x0f, 0x75, 0x5e, + 0x7c, 0x72, 0xc6, 0xb5, 0x32, 0xee, 0x6c, 0x5e, 0xf6, 0x55, 0xa7, 0x11, + 0xe0, 0x6e, 0x04, 0x5e, 0x5d, 0xb1, 0xf8, 0x20, 0x96, 0x68, 0x29, 0x87, + 0xcc, 0x02, 0x9b, 0xd2, 0xb7, 0x9e, 0x56, 0xae, 0x81, 0xbf, 0xb1, 0x3d, + 0xc9, 0x39, 0x83, 0x6d, 0xdd, 0x0e, 0x43, 0xd0, 0x28, 0x58, 0x02, 0x03, + 0x48, 0x40, 0xd2, 0xf1, 0xd8, 0x8e, 0x3d, 0xd4, 0xe3, 0xe1, 0xc1, 0x72, + 0xd8, 0xa8, 0x41, 0x2e, 0x8d, 0x37, 0xf9, 0x6f, 0x7d, 0x63, 0x25, 0x5b, + 0x73, 0x32, 0x52, 0xad, 0xf0, 0x71, 0xf0, 0x63, 0x82, 0xf6, 0xf3, 0x19, + 0x12, 0xd8, 0x11, 0x8b, 0x59, 0x5d, 0xaa, 0x3d, 0x67, 0x9c, 0xe7, 0xd8, + 0x62, 0xcf, 0x16, 0x5a, 0xa1, 0x6c, 0xdd, 0xff, 0xb4, 0xa8, 0x3d, 0x2a, + 0x33, 0x09, 0xd9, 0x33, 0xd8, 0x3b, 0x12, 0x04, 0x96, 0x98, 0xfc, 0x54, + 0xce, 0x27, 0xac, 0xc5, 0x59, 0xe6, 0x98, 0xfc, 0x8d, 0x5e, 0x5b, 0x7f, + 0xfb, 0x85, 0x43, 0x85, 0xa9, 0x5e, 0x81, 0x50, 0xb0, 0xbd, 0x1d, 0xa7, + 0x1d, 0x77, 0xea, 0xcb, 0xbe, 0x9c, 0x4a, 0x85, 0x41, 0xfb, 0x0a, 0xad, + 0xfe, 0x2f, 0x27, 0x2f, 0xb0, 0xac, 0xc8, 0x83, 0x13, 0x7b, 0x3d, 0x47, + 0x1c, 0x68, 0xaa, 0xae, 0x59, 0xee, 0x61, 0xbb, 0xc0, 0xb0, 0x31, 0x89, + 0x69, 0x84, 0x9a, 0x3e, 0x4e, 0x3f, 0x2e, 0xd5, 0x5a, 0x59, 0x20, 0x80, + 0xaa, 0x61, 0x64, 0x6c, 0x3d, 0x93, 0xe2, 0x0a, 0x8d, 0x02, 0xea, 0x2d, + 0xd5, 0x00, 0xb6, 0x61, 0xca, 0x0e, 0x03, 0x10, 0xaa, 0x65, 0xda, 0xc0, + 0x56, 0x96, 0xf5, 0xbd, 0x89, 0xff, 0xdf, 0x31, 0x57, 0xdf, 0x44, 0x53, + 0x90, 0x19, 0x06, 0x01, 0x11, 0x4c, 0x60, 0x41, 0x1d, 0x03, 0x2f, 0x31, + 0xbf, 0x7c, 0x3e, 0x99, 0x76, 0xb4, 0x57, 0x92, 0xde, 0x87, 0x85, 0xa3, + 0x6d, 0xd5, 0x12, 0x95, 0x03, 0x8c, 0x0c, 0x42, 0x08, 0x92, 0x0c, 0x1f, + 0x08, 0x41, 0xf8, 0xe2, 0x37, 0xaa, 0xff, 0xe5, 0x43, 0x8c, 0x97, 0x16, + 0xfd, 0x85, 0xb1, 0x62, 0xb5, 0x0a, 0x3a, 0x36, 0x02, 0xb8, 0x60, 0x89, + 0x70, 0x1c, 0x12, 0x13, 0x2a, 0x91, 0x50, 0xf3, 0xcd, 0x34, 0xde, 0x42, + 0xd9, 0x73, 0xb6, 0xdb, 0x3a, 0xba, 0x90, 0x60, 0x9c, 0x82, 0xda, 0x72, + 0x36, 0x18, 0x15, 0x88, 0x69, 0xc4, 0x94, 0xfb, 0xe6, 0x39, 0x83, 0xe5, + 0xe7, 0x36, 0x4e, 0xff, 0x3a, 0xbf, 0x6e, 0xe7, 0xca, 0x8e, 0x23, 0xe2, + 0xe5, 0x4a, 0xb9, 0x41, 0x4d, 0x99, 0x2c, 0x0e, 0xd8, 0x5d, 0x47, 0x4d, + 0xb9, 0x30, 0x6a, 0x0a, 0x46, 0xea, 0x66, 0xd9, 0x03, 0xdf, 0xd6, 0x2f, + 0xa4, 0x2d, 0x1e, 0x7b, 0x93, 0xdf, 0x9e, 0x42, 0xc2, 0x82, 0xc1, 0xc3, + 0x61, 0xb0, 0x31, 0x08, 0xff, 0xc0, 0xd5, 0x80, 0x35, 0x47, 0x42, 0x4f, + 0x99, 0x80, 0xe1, 0xf3, 0x00, 0x67, 0xdb, 0x6e, 0xa9, 0xbe, 0x9d, 0x96, + 0x6e, 0x29, 0xc4, 0x63, 0x72, 0xd0, 0xef, 0x01, 0x85, 0x65, 0xe0, 0x05, + 0xe1, 0x6b, 0x62, 0x90, 0x37, 0x8d, 0x0e, 0xbe, 0xa3, 0x0b, 0x7f, 0x9e, + 0xe7, 0xad, 0x35, 0x79, 0xca, 0x0c, 0x34, 0x1d, 0x7b, 0xec, 0x88, 0x93, + 0x27, 0xd6, 0x5f, 0x88, 0xa7, 0x91, 0x40, 0x71, 0x83, 0xa0, 0xf0, 0x3f, + 0xe2, 0xb3, 0xea, 0x0e, 0x49, 0x01, 0x8a, 0xa4, 0x91, 0xa4, 0xcd, 0xf3, + 0x6a, 0xd6, 0x4b, 0x7e, 0xce, 0x67, 0xb7, 0x73, 0x57, 0x05, 0x77, 0xc2, + 0xc0, 0x90, 0x5d, 0x81, 0xfa, 0x46, 0x07, 0xea, 0x24, 0x1c, 0xfa, 0x55, + 0x19, 0xaa, 0x56, 0xb2, 0x55, 0xea, 0x8f, 0x00, 0x93, 0xbf, 0xb1, 0x03, + 0xb0, 0xb5, 0xb1, 0xa8, 0x96, 0x23, 0xb2, 0x20, 0x36, 0x25, 0x45, 0x59, + 0x7b, 0xbb, 0xd6, 0x4b, 0x6c, 0x97, 0x0b, 0x6e, 0xcf, 0x59, 0x99, 0xe0, + 0x7c, 0xbf, 0xfe, 0xc6, 0xfe, 0x53, 0x36, 0xed, 0x63, 0xbe, 0x2b, 0xc5, + 0x02, 0x24, 0xec, 0x0e, 0xe5, 0x1b, 0x82, 0xb8, 0xc1, 0x8d, 0xf7, 0xbe, + 0x5e, 0xcc, 0xf8, 0x79, 0xc5, 0x7a, 0xa3, 0xcb, 0xdb, 0xfb, 0x6d, 0xa5, + 0xb3, 0x88, 0xd0, 0x69, 0x58, 0x74, 0x16, 0x8a, 0x63, 0x1d, 0xdf, 0xb4, + 0xcd, 0xbf, 0x51, 0x81, 0xfb, 0x1b, 0xad, 0xc2, 0xd9, 0xd5, 0x84, 0x4c, + 0x51, 0x88, 0xc1, 0x85, 0x65, 0xe6, 0x76, 0x38, 0xc2, 0x66, 0xde, 0xf8, + 0xb7, 0x7d, 0xad, 0x29, 0x92, 0xd5, 0xd1, 0xe5, 0x59, 0x1f, 0xfb, 0xa0, + 0xf9, 0x5f, 0xfd, 0x89, 0x12, 0x09, 0x50, 0xbf, 0x2f, 0x19, 0x6b, 0x97, + 0xf3, 0x0b, 0x57, 0xe8, 0x83, 0x22, 0xd2, 0x4c, 0x2b, 0x02, 0x78, 0x2c, + 0x14, 0x0f, 0x00, 0xe6, 0xb6, 0x5c, 0xd2, 0x86, 0x2f, 0xdb, 0xd5, 0xbc, + 0x57, 0xdb, 0xab, 0xce, 0xb7, 0x7e, 0x1c, 0x62, 0xe5, 0x42, 0xb9, 0x56, + 0x24, 0x30, 0x3c, 0x1d, 0xe0, 0x39, 0x2e, 0xda, 0xb0, 0x38, 0x14, 0xd3, + 0xb1, 0xad, 0x88, 0xe7, 0xe0, 0x7a, 0x39, 0x6d, 0x48, 0x75, 0x80, 0xf9, + 0x70, 0x03, 0xad, 0x92, 0x10, 0x10, 0x16, 0x36, 0xa8, 0x96, 0x21, 0x54, + 0x9a, 0xd6, 0x25, 0xb0, 0x3f, 0xdf, 0xcf, 0x75, 0x4f, 0x6e, 0xc9, 0xd8, + 0x8e, 0x61, 0x52, 0x01, 0xb8, 0x31, 0x17, 0x03, 0x40, 0xdc, 0xdd, 0xf3, + 0x25, 0x8c, 0xb0, 0x04, 0x3c, 0x1e, 0xe3, 0x17, 0xeb, 0xf7, 0xfe, 0xc1, + 0xba, 0x85, 0xb0, 0x3b, 0x06, 0x23, 0x18, 0x00, 0x6c, 0xdf, 0xa5, 0xf6, + 0xe3, 0x3e, 0x98, 0xce, 0xf8, 0x3c, 0xd9, 0xca, 0x9b, 0x22, 0x30, 0x36, + 0xc9, 0x5e, 0x62, 0x3b, 0xaa, 0x30, 0x18, 0xe8, 0xc9, 0xb2, 0xfb, 0x9f, + 0x57, 0x55, 0x02, 0xb3, 0xde, 0x51, 0xe6, 0x04, 0x0e, 0x6f, 0x7f, 0xe5, + 0x83, 0xc6, 0x73, 0x17, 0xcd, 0xca, 0x37, 0xd0, 0xf4, 0x04, 0xda, 0x58, + 0x68, 0x2c, 0xb4, 0xa9, 0xed, 0xb0, 0x84, 0x90, 0x7d, 0xa1, 0x05, 0xac, + 0xdc, 0xbf, 0x4d, 0xe5, 0xff, 0x7f, 0xb2, 0x77, 0x64, 0xcb, 0xce, 0x68, + 0x2d, 0xc2, 0xd3, 0x45, 0xec, 0x5e, 0x28, 0xcb, 0x68, 0xba, 0xf2, 0x13, + 0xd7, 0xd3, 0x81, 0xa6, 0xcb, 0x92, 0xe3, 0x54, 0xb5, 0x6d, 0x56, 0x5b, + 0xe2, 0xcd, 0xdd, 0x43, 0x3a, 0x0e, 0x2b, 0x0f, 0x11, 0x19, 0x0c, 0x00, + 0x1c, 0x07, 0x47, 0x82, 0x5a, 0xbd, 0x4d, 0xf1, 0xc9, 0x70, 0x78, 0xa6, + 0x6a, 0xdc, 0xdc, 0x88, 0xe4, 0x50, 0x09, 0x0b, 0x85, 0x93, 0xdc, 0x42, + 0x66, 0x61, 0x94, 0xc7, 0xa9, 0x12, 0x83, 0x16, 0xab, 0xb9, 0xec, 0x6f, + 0x8c, 0x36, 0xa2, 0xc1, 0x12, 0xd8, 0x8d, 0xe2, 0x42, 0xf2, 0xf6, 0xcb, + 0x9a, 0xf3, 0x09, 0x98, 0xd6, 0x4b, 0xdb, 0xe0, 0xe1, 0x86, 0xb9, 0xd9, + 0x3a, 0xbf, 0xff, 0x74, 0xa9, 0xac, 0x30, 0x2f, 0xa0, 0xdf, 0x1f, 0x24, + 0xe8, 0xf0, 0x0f, 0x26, 0x1c, 0xab, 0xdb, 0x14, 0x56, 0xc3, 0xc9, 0xfd, + 0xad, 0xf3, 0xfc, 0x2a, 0x52, 0xa7, 0x17, 0xd5, 0x20, 0xc4, 0x49, 0x97, + 0x76, 0x26, 0x0f, 0xdb, 0x53, 0x1b, 0x66, 0x52, 0xd5, 0xca, 0xc5, 0x07, + 0x5c, 0xa0, 0x97, 0x13, 0x16, 0xdc, 0xba, 0xcf, 0xb7, 0xfc, 0xdd, 0x51, + 0x04, 0x55, 0x25, 0x96, 0xc0, 0xf6, 0x74, 0x1c, 0x64, 0xd0, 0x30, 0xd9, + 0x5e, 0x7c, 0x08, 0xe4, 0x83, 0x0a, 0xbc, 0x07, 0x38, 0x31, 0x32, 0xae, + 0x88, 0x49, 0xcb, 0x35, 0x40, 0x7c, 0x3d, 0xe4, 0x2e, 0x8a, 0x40, 0xc8, + 0x29, 0xcb, 0x57, 0xec, 0xd5, 0x0a, 0x71, 0x9e, 0xc2, 0xb2, 0xd0, 0xf3, + 0x85, 0x80, 0x96, 0x17, 0x23, 0x7a, 0xc9, 0x73, 0x4d, 0xc2, 0xbd, 0x63, + 0x8a, 0x78, 0x6b, 0x88, 0xc2, 0x85, 0x1b, 0x10, 0xab, 0x63, 0xc0, 0x66, + 0xd3, 0x27, 0x61, 0x8a, 0x94, 0x78, 0x3d, 0x6c, 0xb9, 0x8f, 0xf2, 0xa5, + 0xcf, 0x75, 0x7d, 0x47, 0x3e, 0x0c, 0x13, 0x0e, 0xc0, 0x30, 0x21, 0x8e, + 0xf0, 0x78, 0xd8, 0x90, 0x5f, 0x76, 0x96, 0xec, 0xdf, 0x2b, 0x6d, 0x76, + 0xdb, 0x62, 0xaf, 0xca, 0x68, 0x80, 0x88, 0x20, 0xfd, 0x27, 0xc0, 0x30, + 0x7a, 0x0a, 0x7b, 0x63, 0x02, 0x00, 0x7b, 0xc9, 0xdd, 0x47, 0x37, 0x92, + 0x07, 0x2a, 0x40, 0x40, 0x63, 0x6c, 0x76, 0xde, 0xea, 0x49, 0x0b, 0x73, + 0x9f, 0x55, 0x89, 0x23, 0x19, 0x36, 0x46, 0x27, 0xb3, 0xd3, 0xbf, 0x11, + 0x74, 0x88, 0x96, 0x35, 0x64, 0x40, 0x90, 0xae, 0x4c, 0x80, 0xf8, 0x21, + 0xf0, 0x03, 0xd5, 0x09, 0x13, 0x92, 0x6a, 0xaf, 0xb7, 0xff, 0xad, 0x6e, + 0xd4, 0x73, 0xd0, 0x36, 0x51, 0xc2, 0xd0, 0xb4, 0x29, 0x35, 0x85, 0xa5, + 0x5a, 0x36, 0x47, 0xa1, 0x21, 0x30, 0x0e, 0x1e, 0x0f, 0x63, 0x29, 0x44, + 0xb9, 0xf5, 0x78, 0x97, 0xdf, 0x1c, 0x71, 0xbd, 0x9a, 0xdb, 0x32, 0x45, + 0x3f, 0xed, 0xd2, 0xcc, 0xcc, 0x52, 0x2c, 0x5d, 0x21, 0x7a, 0x9f, 0x24, + 0xc1, 0xb7, 0xd3, 0xb5, 0x3f, 0xbd, 0x46, 0xb7, 0x25, 0x96, 0x06, 0xb4, + 0x12, 0x5d, 0xb2, 0xb3, 0xb5, 0xb1, 0x69, 0x67, 0x96, 0x53, 0x27, 0x77, + 0xa0, 0x8d, 0xc2, 0x22, 0x6a, 0x32, 0x25, 0xcf, 0x4e, 0x4e, 0x0f, 0xcb, + 0x0d, 0xe4, 0xc9, 0x29, 0x60, 0x30, 0x9d, 0x54, 0x56, 0xc2, 0xa5, 0x32, + 0x49, 0xce, 0xf6, 0xce, 0xa2, 0xe8, 0x2d, 0x3e, 0xf8, 0x70, 0x3f, 0xcf, + 0x2f, 0x41, 0xc5, 0xfe, 0x57, 0x56, 0x40, 0x38, 0xbe, 0xa0, 0xfa, 0xdf, + 0xfe, 0x8e, 0x7d, 0xf0, 0x02, 0xec, 0xd2, 0xbf, 0x46, 0x58, 0x1d, 0x81, + 0x91, 0xc5, 0x6c, 0x7b, 0xe6, 0x09, 0x26, 0xb1, 0x3d, 0x7d, 0x65, 0x0d, + 0x4b, 0x31, 0x40, 0xac, 0xbb, 0x7f, 0xe0, 0xed, 0xa4, 0x96, 0x03, 0x15, + 0x32, 0x5d, 0x4a, 0xea, 0x2a, 0xaf, 0xd6, 0xe7, 0xc2, 0x98, 0x67, 0xd8, + 0x0d, 0xcd, 0x4a, 0xbc, 0x98, 0x3f, 0x65, 0x3b, 0x38, 0xa1, 0x6d, 0xf0, + 0x7e, 0x59, 0x7d, 0x43, 0x75, 0xbc, 0x05, 0x01, 0x28, 0xc8, 0x93, 0x41, + 0x97, 0x10, 0x93, 0xe5, 0x9f, 0x06, 0x5f, 0xec, 0x55, 0x08, 0xda, 0xf3, + 0x2d, 0x76, 0x5b, 0x04, 0x45, 0x07, 0xb5, 0x2f, 0xb4, 0x0c, 0x8b, 0x5a, + 0xe7, 0x0b, 0x31, 0x45, 0x81, 0x92, 0xe2, 0x61, 0x9b, 0x17, 0x66, 0xa7, + 0xdc, 0x47, 0x7e, 0x59, 0x72, 0x2d, 0x2e, 0xf6, 0x55, 0xe8, 0x72, 0x46, + 0x8c, 0x6f, 0x2d, 0x67, 0x7d, 0xf1, 0xcc, 0xdc, 0x50, 0xb1, 0x5e, 0x77, + 0xdc, 0x94, 0x18, 0x4e, 0x92, 0xa0, 0x61, 0xba, 0x71, 0x11, 0x4e, 0xc2, + 0xaa, 0x6d, 0x0b, 0xf3, 0x1f, 0x62, 0xff, 0x77, 0xbf, 0x5d, 0x7e, 0x8b, + 0x8d, 0x74, 0x16, 0xb7, 0xa8, 0x9f, 0xd7, 0xcf, 0xde, 0x5a, 0xa7, 0xaa, + 0x51, 0xf2, 0x72, 0xce, 0x9e, 0xbd, 0xdf, 0x7f, 0x23, 0x70, 0xa8, 0xae, + 0x4d, 0xf0, 0x8b, 0x9b, 0x50, 0x3f, 0x97, 0x95, 0x64, 0x51, 0x2a, 0x25, + 0x3d, 0x50, 0x6a, 0x48, 0x43, 0x73, 0x56, 0xec, 0x0d, 0x0a, 0x60, 0xaf, + 0xd2, 0xb6, 0x25, 0xcf, 0x96, 0x69, 0x5e, 0x45, 0xbb, 0x22, 0xfc, 0x22, + 0x94, 0xc3, 0x65, 0x17, 0x9d, 0xbd, 0x84, 0x8a, 0x79, 0x29, 0xfe, 0xb6, + 0x18, 0x81, 0x46, 0x0d, 0x5a, 0x04, 0x26, 0x20, 0xe5, 0xaa, 0xde, 0xa5, + 0x6d, 0x98, 0xd7, 0xa7, 0x20, 0x32, 0x2f, 0x45, 0xe8, 0x6c, 0xa7, 0x98, + 0x0c, 0x27, 0x0e, 0x00, 0xc1, 0x08, 0x4b, 0x56, 0x3f, 0x00, 0xf1, 0x27, + 0xea, 0xdb, 0xbb, 0xa9, 0xda, 0x03, 0x7b, 0x28, 0xdb, 0xb1, 0x5e, 0x45, + 0x83, 0x85, 0x05, 0xa1, 0x60, 0x30, 0x81, 0x82, 0x19, 0x78, 0x22, 0x84, + 0x36, 0x58, 0xff, 0x71, 0xb2, 0xe6, 0xea, 0xac, 0xca, 0xb4, 0x2c, 0x5a, + 0xdd, 0x80, 0xaf, 0xda, 0xa4, 0x4c, 0x4c, 0x46, 0x05, 0x18, 0x1c, 0x05, + 0x00, 0xf9, 0x52, 0xa1, 0xe3, 0x1f, 0x4e, 0x3f, 0x6e, 0xfb, 0x44, 0xb4, + 0xab, 0x7b, 0xdc, 0x02, 0xbe, 0xf5, 0xd2, 0xb6, 0xd4, 0x40, 0xeb, 0x0b, + 0x33, 0xc0, 0xc2, 0xbe, 0xde, 0xd9, 0x10, 0x18, 0x69, 0x48, 0x9b, 0x08, + 0x62, 0x48, 0x07, 0x97, 0x01, 0xc6, 0x23, 0x23, 0xff, 0xdc, 0xcb, 0xfc, + 0xf6, 0x49, 0x8a, 0x77, 0x76, 0xf6, 0xc2, 0xc8, 0x22, 0xe2, 0x89, 0x4b, + 0x41, 0xc6, 0x21, 0x30, 0x92, 0x98, 0x49, 0xc0, 0xfc, 0xb9, 0x96, 0x95, + 0xb5, 0xdb, 0x14, 0xfa, 0xf7, 0x9a, 0xb5, 0xe5, 0x0d, 0xd7, 0x70, 0x39, + 0x00, 0x3c, 0x43, 0x6c, 0x20, 0x89, 0x7f, 0x2f, 0x6e, 0xd9, 0xe5, 0x20, + 0x61, 0xa4, 0x73, 0xd8, 0x88, 0x11, 0xd6, 0x52, 0x2d, 0x09, 0xc0, 0xc0, + 0x18, 0x3d, 0x68, 0x0d, 0x25, 0x1d, 0x03, 0x21, 0x8c, 0xd5, 0x78, 0x81, + 0x4f, 0xac, 0x92, 0xac, 0x1b, 0x16, 0x03, 0x05, 0x77, 0x2f, 0x6b, 0xdf, + 0x0c, 0xa6, 0x16, 0x32, 0xf3, 0xbb, 0x51, 0x40, 0xa4, 0xc9, 0x72, 0xad, + 0xd0, 0x51, 0xe0, 0x96, 0xa7, 0x26, 0x03, 0x0e, 0x28, 0xfa, 0xe7, 0x17, + 0x52, 0x1f, 0xc6, 0x6f, 0xe0, 0x2d, 0x85, 0xc2, 0x38, 0x1f, 0x83, 0xa0, + 0x0d, 0x49, 0xa9, 0xcb, 0xc0, 0xd0, 0xf1, 0x81, 0xf7, 0xf5, 0xbf, 0x2f, + 0xba, 0xaf, 0x59, 0xfd, 0xe4, 0xf7, 0xb0, 0x6f, 0xb9, 0xbe, 0x1b, 0xe8, + 0x2b, 0x8b, 0x41, 0x8e, 0x8b, 0x13, 0x82, 0x95, 0x30, 0x8c, 0x91, 0x50, + 0x87, 0xaa, 0x77, 0xcd, 0xea, 0x65, 0x0a, 0x16, 0xda, 0x20, 0xce, 0xdb, + 0xc0, 0xdb, 0x3b, 0xaa, 0x01, 0x6c, 0x9a, 0x44, 0xa9, 0xa0, 0xc9, 0x53, + 0x14, 0xdf, 0xc1, 0x81, 0x34, 0x42, 0x9e, 0xe0, 0x32, 0x8b, 0x28, 0x8a, + 0x19, 0xcb, 0xd0, 0xc1, 0xe6, 0x9a, 0x1f, 0xf8, 0x49, 0x4c, 0x98, 0xbd, + 0x37, 0xe7, 0xd8, 0x67, 0x25, 0x86, 0xe2, 0xc8, 0xac, 0x0e, 0x44, 0x41, + 0x68, 0x61, 0x05, 0x08, 0x29, 0x4b, 0x84, 0xa6, 0x2f, 0xb7, 0xfd, 0xd8, + 0xa4, 0xa9, 0x15, 0x52, 0xba, 0xd2, 0x08, 0xa1, 0xc0, 0x5b, 0x7d, 0x9d, + 0x33, 0x53, 0x0f, 0x20, 0x1a, 0x59, 0x8d, 0x81, 0xc9, 0x6c, 0xac, 0x41, + 0xdd, 0x2d, 0x88, 0xb3, 0x3f, 0x7d, 0x79, 0xfb, 0x43, 0xd1, 0x16, 0x82, + 0x41, 0x4f, 0x88, 0xe5, 0xc1, 0xff, 0x8b, 0xaa, 0x76, 0xb5, 0x5e, 0xe0, + 0x74, 0x39, 0xf5, 0xfd, 0xd4, 0x2b, 0x66, 0x8a, 0x8f, 0x17, 0x01, 0xb0, + 0x0f, 0x4c, 0x0d, 0xd2, 0xf2, 0xa2, 0xe2, 0xda, 0x58, 0xaa, 0xf0, 0xae, + 0xf2, 0xae, 0x1b, 0x28, 0xe8, 0x24, 0x86, 0xf1, 0xd3, 0x40, 0xc0, 0x88, + 0xac, 0x3a, 0x49, 0xff, 0x27, 0x6c, 0x18, 0x6f, 0xbe, 0x07, 0x25, 0x10, + 0x7f, 0x41, 0x83, 0x90, 0xf7, 0x54, 0x28, 0xe8, 0x08, 0x2b, 0x5a, 0xe8, + 0x6e, 0xa0, 0x58, 0xad, 0x85, 0x4c, 0x2c, 0xeb, 0x7b, 0xc0, 0x64, 0x7c, + 0xa8, 0x79, 0xc9, 0x16, 0x38, 0x0c, 0xe5, 0x6a, 0x87, 0x40, 0xab, 0x10, + 0xf9, 0xef, 0x6b, 0x3e, 0x2f, 0x4f, 0xad, 0x29, 0xb4, 0x71, 0x9c, 0xfd, + 0xec, 0xf8, 0x38, 0xc0, 0x51, 0x45, 0xda, 0x8c, 0x3c, 0x18, 0xde, 0xca, + 0xec, 0x01, 0xe2, 0x47, 0xea, 0x7d, 0xdf, 0xa9, 0xb2, 0xb6, 0xcd, 0xd9, + 0xe5, 0xe8, 0x83, 0xf5, 0xa7, 0xc3, 0x40, 0x4a, 0xd5, 0x77, 0x9f, 0x58, + 0x2d, 0xf4, 0xc3, 0x67, 0x7c, 0xdb, 0x4a, 0xdb, 0x9d, 0xcf, 0x7b, 0x2c, + 0x03, 0x33, 0xd3, 0x96, 0xd0, 0x28, 0x58, 0xa7, 0x4a, 0xb0, 0x44, 0x52, + 0x5a, 0x58, 0x59, 0xa0, 0xc4, 0x50, 0x10, 0x07, 0x4a, 0x82, 0x00, 0x95, + 0x14, 0xfe, 0x29, 0x4f, 0xb8, 0xad, 0x46, 0x7e, 0x37, 0xe5, 0xfd, 0x27, + 0x3d, 0x60, 0xdf, 0x30, 0x39, 0x06, 0x21, 0x16, 0x81, 0xe6, 0x47, 0x80, + 0xdd, 0xd2, 0xe5, 0x79, 0x38, 0x38, 0xac, 0x51, 0xcf, 0x5b, 0x53, 0xf9, + 0x11, 0x79, 0x9d, 0x2c, 0x1c, 0x66, 0xf2, 0x83, 0x10, 0x07, 0xf0, 0x86, + 0x25, 0xab, 0xd6, 0x9b, 0x63, 0x14, 0xa6, 0x2e, 0x8d, 0xcf, 0x34, 0xa8, + 0x0a, 0xef, 0xb9, 0x65, 0x9d, 0xc2, 0xac, 0xc5, 0x83, 0xdc, 0x02, 0x26, + 0x4b, 0xff, 0x36, 0x23, 0x04, 0x83, 0x7a, 0x46 +}; + +void +mpeg4_get_video_info (VideoDecodeInfo * info) +{ + info->profile = GST_VAAPI_PROFILE_MPEG4_SIMPLE; + info->width = MPEG4_CLIP_WIDTH; + info->height = MPEG4_CLIP_HEIGHT; + info->data = mpeg4_clip; + info->data_size = MPEG4_CLIP_DATA_SIZE; +} diff --git a/tests/internal/test-mpeg4.h b/tests/internal/test-mpeg4.h new file mode 100644 index 0000000000..aaa613dd1d --- /dev/null +++ b/tests/internal/test-mpeg4.h @@ -0,0 +1,31 @@ +/* + * test-mpeg4.h - MPEG-4 test data + * + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * 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 TEST_MPEG4_H +#define TEST_MPEG4_H + +#include +#include "test-decode.h" + +void mpeg4_get_video_info(VideoDecodeInfo *info); + +#endif /* TEST_MPEG4_H */ diff --git a/tests/internal/test-subpicture-data.c b/tests/internal/test-subpicture-data.c new file mode 100644 index 0000000000..0bd213394f --- /dev/null +++ b/tests/internal/test-subpicture-data.c @@ -0,0 +1,1431 @@ +/* + * test-subpicture-data.c - subpicture data + * + * Copyright (C) <2011> Intel Corporation + * Copyright (C) <2011> Collabora Ltd. + * Copyright (C) <2011> Thibault Saunier + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "test-subpicture-data.h" + +#define SUBPICTURE_WIDTH 184 +#define SUBPICTURE_HEIGHT 38 +#define SUBPICTURE_DATA_SIZE 27968 + +/* Raw RGBA data */ +static const guint32 text[] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x09000000, 0x63000000, 0x08000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x44000000, 0x88000000, 0x88000000, 0x88000000, 0x88000000, + 0x88000000, 0x88000000, 0x88000000, 0x88000000, 0x88000000, + 0x44000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x44000000, 0x88000000, 0x44000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x44000000, 0x88000000, + 0x44000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x69000000, 0xff0000b4, 0x65000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0x80000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0x80000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0x80000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6a000000, + 0xff0000b6, 0x9c000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x3c000000, 0xbb000000, + 0xff0000ff, 0xdd000000, 0xbb000000, 0xbb000000, 0xbb000000, + 0xbb000000, 0xdd000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x08000000, 0x61000000, + 0x60000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x00000000, 0x1f000000, 0x5c000000, 0x78000000, 0x60000000, + 0x27000000, 0x00000000, 0x00000000, 0x44000000, 0xc4000000, + 0xff0000ff, 0xe2000000, 0x88000000, 0x88000000, 0x88000000, + 0x0f000000, 0x00000000, 0x00000000, 0x42000000, 0x78000000, + 0x78000000, 0x41000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x1f000000, 0x5c000000, 0x78000000, + 0x60000000, 0x27000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x1f000000, 0x5c000000, 0x78000000, 0x60000000, + 0x27000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x42000000, 0x78000000, 0x78000000, 0x41000000, + 0x00000000, 0x00000000, 0x00000000, 0x44000000, 0x88000000, + 0x88000000, 0x45000000, 0x3d000000, 0x73000000, 0x6c000000, + 0x37000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x44000000, + 0xc4000000, 0xff0000ff, 0xe2000000, 0x88000000, 0x88000000, + 0x88000000, 0x53000000, 0x88000000, 0x88000000, 0x44000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x41000000, + 0x78000000, 0x78000000, 0x46000000, 0x01000000, 0x00000000, + 0x00000000, 0x44000000, 0x88000000, 0x88000000, 0x49000000, + 0x55000000, 0x78000000, 0x4a000000, 0x02000000, 0x02000000, + 0x4f000000, 0x78000000, 0x4d000000, 0x01000000, 0x00000000, + 0x00000000, 0x44000000, 0x88000000, 0x88000000, 0x45000000, + 0x3e000000, 0x77000000, 0x78000000, 0x43000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x42000000, 0x78000000, 0x78000000, 0x41000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1f000000, + 0x5c000000, 0x78000000, 0x60000000, 0x27000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x00000000, 0x00000000, 0x44000000, 0x88000000, 0x80000000, + 0x77000000, 0x9e000000, 0x00000000, 0x00000000, 0x9000000a, + 0xfd000076, 0xff0000b6, 0xff0000ef, 0xfe0000dc, 0xf50000a0, + 0xc8000036, 0x35000000, 0x80000000, 0xff0000ff, 0xff0000ff, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff00009c, 0x1c000000, + 0x10000000, 0xc900001f, 0xff0000ad, 0xff0000e7, 0xff0000e7, + 0xff0000ad, 0xc900001f, 0x13000000, 0x00000000, 0x00000000, + 0x9000000a, 0xfd000076, 0xff0000b6, 0xff0000ef, 0xfe0000dc, + 0xf50000a0, 0xc8000036, 0x35000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x9000000a, + 0xfd000076, 0xff0000b6, 0xff0000ef, 0xfe0000dc, 0xf50000a0, + 0xc8000036, 0x35000000, 0x00000000, 0x10000000, 0xc900001f, + 0xff0000ad, 0xff0000e7, 0xff0000e7, 0xff0000ad, 0xc900001f, + 0x13000000, 0x00000000, 0x80000000, 0xff0000ff, 0xff0000ff, + 0xee000011, 0xff0000a3, 0xff0000e5, 0xff0000ca, 0xfc000072, + 0x94000010, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff00009c, + 0x9b000000, 0xff0000ff, 0xff0000ff, 0x80000000, 0x00000000, + 0x00000000, 0x10000000, 0xc900001f, 0xff0000ad, 0xfe0000e7, + 0xff0000e7, 0xff0000af, 0xc600001f, 0x11000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xff0000ff, 0xf700001f, 0xff0000b6, + 0xff0000eb, 0xf80000ac, 0xbb00001a, 0xc8000022, 0xff0000b3, + 0xff0000e6, 0xf900008a, 0xad000017, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xff0000ff, 0xf300001b, 0xff0000ad, + 0xfe0000e3, 0xff0000e9, 0xff0000ad, 0xc100001d, 0x0f000000, + 0x00000000, 0x00000000, 0x10000000, 0xc900001f, 0xff0000ad, + 0xff0000e7, 0xff0000e7, 0xff0000ad, 0xc900001f, 0x13000000, + 0x00000000, 0x00000000, 0x9000000a, 0xfd000076, 0xff0000b6, + 0xff0000ef, 0xfe0000dc, 0xf50000a0, 0xc8000036, 0x35000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xe2000000, 0x88000000, + 0x88000000, 0xc4000000, 0xff0000ff, 0x80000000, 0x00000000, + 0x00000000, 0x00000000, 0x43000000, 0xff000078, 0xf8000096, + 0xbe00002c, 0xb9000011, 0xe5000051, 0xfa0000cf, 0xff0000ff, + 0x8d000000, 0x3c000000, 0xbb000000, 0xff0000ff, 0xdd000000, + 0xbb000000, 0xbb000000, 0xbb000000, 0x57000000, 0xbc00001a, + 0xff0000e4, 0xf5000098, 0xc8000033, 0xd1000033, 0xf900009a, + 0xff0000e4, 0xbe00001a, 0x00000000, 0x43000000, 0xff000078, + 0xf8000096, 0xbe00002c, 0xb9000011, 0xe5000051, 0xfa0000cf, + 0xff0000ff, 0x8d000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x43000000, 0xff000078, 0xf8000096, + 0xbe00002c, 0xb9000011, 0xe5000051, 0xfa0000cf, 0xff0000ff, + 0x8d000000, 0x00000000, 0xbc00001a, 0xff0000e4, 0xf5000098, + 0xc8000033, 0xd1000033, 0xf900009a, 0xff0000e4, 0xbe00001a, + 0x00000000, 0x3c000000, 0xbb000000, 0xff0000ff, 0xff0000b1, + 0xea000077, 0xbd00001d, 0xda000042, 0xfd0000bc, 0xfa000074, + 0x36000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x3c000000, 0xbb000000, 0xff0000ff, + 0xdd000000, 0xbb000000, 0xbb000000, 0xbb000000, 0x81000000, + 0xbb000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0xb700001a, 0xff0000e6, 0xf500008e, 0xc9000031, 0xd000002c, + 0xf8000087, 0xff0000dd, 0xb1000014, 0x00000000, 0x3c000000, + 0xbb000000, 0xff0000ff, 0xff0000a9, 0xd4000054, 0xc5000024, + 0xfc0000a8, 0xfa0000b4, 0xff0000a7, 0xd5000054, 0xc4000024, + 0xfc0000aa, 0xfc000088, 0x3e000000, 0x00000000, 0x3c000000, + 0xbb000000, 0xff0000ff, 0xff0000cf, 0xf2000087, 0xc600002d, + 0xd1000033, 0xf900009a, 0xff0000e1, 0xb6000017, 0x00000000, + 0x00000000, 0xbc00001a, 0xff0000e4, 0xf5000098, 0xc8000033, + 0xd1000033, 0xf900009a, 0xff0000e4, 0xbe00001a, 0x00000000, + 0x43000000, 0xff000078, 0xf8000096, 0xbe00002c, 0xb9000011, + 0xe5000051, 0xfa0000cf, 0xff0000ff, 0x8d000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, + 0xff0000ff, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x00000000, 0x75000000, 0xfe0000e4, 0xc5000025, 0x4c000000, + 0x16000000, 0x09000000, 0xcd000040, 0xff0000ff, 0xc0000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x00000000, 0x2e000000, 0xff00009c, 0xf8000092, + 0x7e000000, 0x4c000000, 0x1a000000, 0x30000000, 0xfa000096, + 0xff00009b, 0x37000000, 0x75000000, 0xfe0000e4, 0xc5000025, + 0x4c000000, 0x16000000, 0x09000000, 0xcd000040, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x75000000, 0xfe0000e4, 0xc5000025, 0x4c000000, + 0x16000000, 0x09000000, 0xcd000040, 0xff0000ff, 0xc0000000, + 0x2e000000, 0xff00009c, 0xf8000092, 0x7e000000, 0x4c000000, + 0x1a000000, 0x30000000, 0xfa000096, 0xff00009b, 0x37000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xf5000078, 0x5e000000, + 0x3c000000, 0x0f000000, 0xcd00004b, 0xfe0000c1, 0x89000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xc0000000, 0x00000000, 0x2e000000, 0xff00009b, + 0xf900009e, 0x82000000, 0x47000000, 0x19000000, 0x25000000, + 0xf700008e, 0xfe000086, 0x25000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xee000060, 0x56000000, 0x2a000000, 0xb9000036, + 0xff0000ff, 0xe9000060, 0x55000000, 0x2a000000, 0xba000038, + 0xff0000ca, 0x91000000, 0x00000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xf7000084, 0x70000000, 0x44000000, 0x17000000, + 0x30000000, 0xfb000096, 0xff000098, 0x32000000, 0x2e000000, + 0xff00009c, 0xf8000092, 0x7e000000, 0x4c000000, 0x1a000000, + 0x30000000, 0xfa000096, 0xff00009b, 0x37000000, 0x75000000, + 0xfe0000e4, 0xc5000025, 0x4c000000, 0x16000000, 0x09000000, + 0xcd000040, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xdd000000, 0xbb000000, 0xbb000000, 0xdd000000, + 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x00000000, + 0x49000000, 0xf70000a8, 0xfb0000cb, 0xea000055, 0x82000005, + 0x48000000, 0x44000000, 0x88000000, 0x9e000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x00000000, 0x5d000000, 0xff0000da, 0xd0000049, 0x49000000, + 0x00000000, 0x00000000, 0x00000000, 0xbe00004b, 0xfe0000d9, + 0x96000000, 0x49000000, 0xf70000a8, 0xfb0000cb, 0xea000055, + 0x82000005, 0x48000000, 0x44000000, 0x88000000, 0x9e000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x49000000, 0xf70000a8, 0xfb0000cb, 0xea000055, 0x82000005, + 0x48000000, 0x44000000, 0x88000000, 0x9e000000, 0x5d000000, + 0xff0000da, 0xd0000049, 0x49000000, 0x00000000, 0x00000000, + 0x00000000, 0xbe00004b, 0xfe0000d9, 0x96000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xd1000028, 0x3c000000, 0x00000000, + 0x00000000, 0x90000011, 0xff0000fc, 0xaf000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xc0000000, 0x00000000, 0x5d000000, 0xff0000da, 0xeb000034, + 0xad000000, 0x88000000, 0x88000000, 0x88000000, 0xde00002f, + 0xff0000cb, 0x7b000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xcd000020, 0x30000000, 0x00000000, 0x84000005, 0xff0000ff, + 0xcd000020, 0x30000000, 0x00000000, 0x85000006, 0xff0000fc, + 0xb1000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xd300002c, 0x42000000, 0x00000000, 0x00000000, 0x00000000, + 0xbe00004b, 0xfe0000d8, 0x95000000, 0x5d000000, 0xff0000da, + 0xd0000049, 0x49000000, 0x00000000, 0x00000000, 0x00000000, + 0xbe00004b, 0xfe0000d9, 0x96000000, 0x49000000, 0xf70000a8, + 0xfb0000cb, 0xea000055, 0x82000005, 0x48000000, 0x44000000, + 0x88000000, 0x9e000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x3c000000, 0x77000000, + 0x9e000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x8f000007, 0xf900007e, 0xfc0000dd, 0xff0000f2, 0xfb0000c2, + 0xf200005c, 0x72000001, 0x00000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x00000000, + 0x78000000, 0xff0000f6, 0xc0000012, 0x25000000, 0x00000000, + 0x00000000, 0x00000000, 0x92000013, 0xff0000f6, 0xb4000000, + 0x00000000, 0x8f000007, 0xf900007e, 0xfc0000dd, 0xff0000f2, + 0xfb0000c2, 0xf200005c, 0x72000001, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x8f000007, 0xf900007e, 0xfc0000dd, 0xff0000f2, 0xfb0000c2, + 0xf200005c, 0x72000001, 0x00000000, 0x78000000, 0xff0000f6, + 0xc0000012, 0x25000000, 0x00000000, 0x00000000, 0x00000000, + 0x92000013, 0xff0000f6, 0xb4000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xc0000000, 0x14000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xbf000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x00000000, 0x7a000000, 0xff0000f6, 0xff0000ff, 0xff0000ff, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ee, + 0xa8000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x10000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x10000000, 0x00000000, 0x80000000, 0xff0000ff, 0xbf000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x16000000, 0x00000000, 0x00000000, 0x00000000, 0x92000013, + 0xff0000f6, 0xb3000000, 0x78000000, 0xff0000f6, 0xc0000012, + 0x25000000, 0x00000000, 0x00000000, 0x00000000, 0x92000013, + 0xff0000f6, 0xb4000000, 0x00000000, 0x8f000007, 0xf900007e, + 0xfc0000dd, 0xff0000f2, 0xfb0000c2, 0xf200005c, 0x72000001, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x44000000, + 0x88000000, 0x44000000, 0x00000000, 0x44000000, 0x88000000, + 0x65000000, 0x84000000, 0xc8000014, 0xf4000059, 0xfc0000cc, + 0xfb000098, 0x40000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x5d000000, + 0xff0000da, 0xdc00004a, 0x09000000, 0x00000000, 0x00000000, + 0x00000000, 0xbe00004b, 0xfe0000d9, 0xb1000000, 0x44000000, + 0x88000000, 0x65000000, 0x84000000, 0xc8000014, 0xf4000059, + 0xfc0000cc, 0xfb000098, 0x40000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x44000000, 0x88000000, + 0x65000000, 0x84000000, 0xc8000014, 0xf4000059, 0xfc0000cc, + 0xfb000098, 0x40000000, 0x5d000000, 0xff0000da, 0xdc00004a, + 0x09000000, 0x00000000, 0x00000000, 0x00000000, 0xbe00004b, + 0xfe0000d9, 0xb1000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x69000000, 0xff0000d9, 0xe8000028, 0xbb000000, 0xbb000000, + 0xbb000000, 0xbb000000, 0xda000000, 0xff000000, 0xc1000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xd6000036, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xbe00004b, 0xfe0000d8, + 0xb1000000, 0x5d000000, 0xff0000da, 0xdc00004a, 0x09000000, + 0x00000000, 0x00000000, 0x00000000, 0xbe00004b, 0xfe0000d9, + 0xb1000000, 0x44000000, 0x88000000, 0x65000000, 0x84000000, + 0xc8000014, 0xf4000059, 0xfc0000cc, 0xfb000098, 0x40000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0x80000000, 0x00000000, 0x80000000, 0xff0000ff, 0xba00003a, + 0x00000000, 0x00000000, 0x0b000000, 0xc1000027, 0xff0000e2, + 0x9d000000, 0x00000000, 0x7f000000, 0xff0000fd, 0xc0000002, + 0x00000000, 0x43000000, 0x88000000, 0x71000000, 0xff00009b, + 0xfb000095, 0x39000000, 0x00000000, 0x00000000, 0x18000000, + 0xf9000096, 0xff00009b, 0x85000000, 0x80000000, 0xff0000ff, + 0xba00003a, 0x00000000, 0x00000000, 0x0b000000, 0xc1000027, + 0xff0000e2, 0x9d000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xba00003a, + 0x00000000, 0x00000000, 0x0b000000, 0xc1000027, 0xff0000e2, + 0x9d000000, 0x2b000000, 0xff00009b, 0xfb000095, 0x39000000, + 0x00000000, 0x00000000, 0x18000000, 0xf9000096, 0xff00009b, + 0x85000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x7f000000, 0xff0000fd, + 0xc0000002, 0x00000000, 0x43000000, 0x88000000, 0x46000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x2b000000, + 0xff000097, 0xf4000080, 0x1b000000, 0x00000000, 0x00000000, + 0x08000000, 0xe0000059, 0xff0000b5, 0x55000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xf9000089, 0x28000000, 0x00000000, + 0x00000000, 0x18000000, 0xf9000096, 0xff000097, 0x83000000, + 0x2b000000, 0xff00009b, 0xfb000095, 0x39000000, 0x00000000, + 0x00000000, 0x18000000, 0xf9000096, 0xff00009b, 0x85000000, + 0x80000000, 0xff0000ff, 0xba00003a, 0x00000000, 0x00000000, + 0x0b000000, 0xc1000027, 0xff0000e2, 0x9d000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x44000000, + 0xc4000000, 0xff0000ff, 0xe2000000, 0x88000000, 0x88000000, + 0x88000000, 0x88000000, 0xc4000000, 0xff0000ff, 0xc0000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xfc0000c5, 0xcf00004a, + 0x91000010, 0xab00002c, 0xfa00009d, 0xff000074, 0x95000000, + 0x00000000, 0x66000000, 0xff0000c1, 0xee000050, 0x8e00000d, + 0xe400005a, 0xfe0000c7, 0x66000000, 0xb800001a, 0xff0000e4, + 0xf8000099, 0xac000033, 0xac000033, 0xf5000099, 0xff0000e4, + 0xcc00001a, 0x4e000000, 0x80000000, 0xff0000ff, 0xfc0000c5, + 0xcf00004a, 0x91000010, 0xab00002c, 0xfa00009d, 0xff000074, + 0x95000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xfc0000c5, 0xcf00004a, + 0x91000010, 0xab00002c, 0xfa00009d, 0xff000074, 0x95000000, + 0x00000000, 0xb800001a, 0xff0000e4, 0xf8000099, 0xac000033, + 0xac000033, 0xf5000099, 0xff0000e4, 0xcc00001a, 0x4e000000, + 0x44000000, 0xc4000000, 0xff0000ff, 0xe2000000, 0x44000000, + 0x00000000, 0x44000000, 0xc4000000, 0xff0000ff, 0xe2000000, + 0x44000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x66000000, 0xff0000c1, 0xee000050, + 0x8e00000d, 0xe400005a, 0xfe0000c7, 0xaa000000, 0xc4000000, + 0xff0000ff, 0xe2000000, 0x44000000, 0x00000000, 0xad000015, + 0xff0000d3, 0xf200007f, 0xaa00002d, 0x9d00001d, 0xe6000061, + 0xff0000e9, 0xe9000025, 0x60000000, 0x44000000, 0xc4000000, + 0xff0000ff, 0xe2000000, 0x44000000, 0x44000000, 0xc4000000, + 0xff0000ff, 0xe2000000, 0x44000000, 0x44000000, 0xc4000000, + 0xff0000ff, 0xe2000000, 0x44000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xff0000bc, 0xf5000088, 0xa900002d, 0xac000033, + 0xf5000099, 0xff0000e1, 0xc9000017, 0x4c000000, 0x00000000, + 0xb800001a, 0xff0000e4, 0xf8000099, 0xac000033, 0xac000033, + 0xf5000099, 0xff0000e4, 0xcc00001a, 0x4e000000, 0x80000000, + 0xff0000ff, 0xfc0000c5, 0xcf00004a, 0x91000010, 0xab00002c, + 0xfa00009d, 0xff000074, 0x95000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xc0000000, 0x00000000, + 0x36000000, 0xd300003b, 0xfb0000aa, 0xff0000e1, 0xff0000f0, + 0xff0000b6, 0xfc000076, 0xae000008, 0x3a000000, 0x00000000, + 0x15000000, 0xee000046, 0xff0000bd, 0xff0000ef, 0xfd0000be, + 0xeb00003f, 0x6f000000, 0x13000000, 0xcd00001f, 0xff0000ae, + 0xff0000e8, 0xff0000e8, 0xff0000ae, 0xd900001f, 0x7d000000, + 0x0d000000, 0x36000000, 0xd300003b, 0xfb0000aa, 0xff0000e1, + 0xff0000f0, 0xff0000b6, 0xfc000076, 0xae000008, 0x3a000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x36000000, 0xd300003b, 0xfb0000aa, 0xff0000e1, 0xff0000f0, + 0xff0000b6, 0xfc000076, 0xae000008, 0x3a000000, 0x00000000, + 0x13000000, 0xcd00001f, 0xff0000ae, 0xff0000e8, 0xff0000e8, + 0xff0000ae, 0xd900001f, 0x7d000000, 0x0d000000, 0x80000000, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0x80000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0x80000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x15000000, 0xee000046, 0xff0000bd, 0xff0000ef, + 0xfd0000be, 0xeb00003f, 0xbc000000, 0xff0000ff, 0xff0000ff, + 0xff0000ff, 0x80000000, 0x00000000, 0x0e000000, 0xc0000018, + 0xff0000a4, 0xff0000e1, 0xff0000e5, 0xfc00009b, 0xec000042, + 0x8d000000, 0x13000000, 0x80000000, 0xff0000ff, 0xff0000ff, + 0xff0000ff, 0x80000000, 0x80000000, 0xff0000ff, 0xff0000ff, + 0xff0000ff, 0x80000000, 0x80000000, 0xff0000ff, 0xff0000ff, + 0xff0000ff, 0x80000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xf8000012, 0xff0000a6, 0xff0000e2, 0xff0000e9, 0xff0000ad, + 0xd100001d, 0x78000000, 0x0c000000, 0x00000000, 0x13000000, + 0xcd00001f, 0xff0000ae, 0xff0000e8, 0xff0000e8, 0xff0000ae, + 0xd900001f, 0x7d000000, 0x0d000000, 0x36000000, 0xd300003b, + 0xfb0000aa, 0xff0000e1, 0xff0000f0, 0xff0000b6, 0xfc000076, + 0xae000008, 0x3a000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x3c000000, 0x77000000, 0xbb000000, + 0xbb000000, 0xbb000000, 0xbb000000, 0xbb000000, 0xbb000000, + 0xbb000000, 0xbb000000, 0x9e000000, 0x00000000, 0x00000000, + 0x00000000, 0x4a000000, 0x96000000, 0xb2000000, 0xa8000000, + 0x6e000000, 0x3b000000, 0x04000000, 0x00000000, 0x00000000, + 0x0f000000, 0x78000000, 0xaa000000, 0xaa000000, 0x68000000, + 0x20000000, 0x00000000, 0x00000000, 0x47000000, 0xa5000000, + 0xb4000000, 0x94000000, 0x57000000, 0x10000000, 0x00000000, + 0x00000000, 0x00000000, 0x4a000000, 0x96000000, 0xb2000000, + 0xa8000000, 0x6e000000, 0x3b000000, 0x04000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x4a000000, 0x96000000, 0xb2000000, 0xa8000000, + 0x6e000000, 0x3b000000, 0x04000000, 0x00000000, 0x00000000, + 0x00000000, 0x47000000, 0xa5000000, 0xb4000000, 0x94000000, + 0x57000000, 0x10000000, 0x00000000, 0x3c000000, 0x77000000, + 0xbb000000, 0xbb000000, 0x9e000000, 0x00000000, 0x3c000000, + 0x77000000, 0xbb000000, 0xbb000000, 0x9e000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x0f000000, 0x78000000, 0xaa000000, 0xaa000000, + 0x68000000, 0x54000000, 0x77000000, 0xbb000000, 0xbb000000, + 0x9e000000, 0x00000000, 0x00000000, 0x00000000, 0x3b000000, + 0x9f000000, 0xb0000000, 0x9e000000, 0x51000000, 0x21000000, + 0x00000000, 0x3c000000, 0x77000000, 0xbb000000, 0xbb000000, + 0x9e000000, 0x3c000000, 0x77000000, 0xbb000000, 0xbb000000, + 0x9e000000, 0x3c000000, 0x77000000, 0xbb000000, 0xbb000000, + 0x9e000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x43000000, 0x9d000000, 0xb3000000, 0x95000000, 0x57000000, + 0x0f000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x47000000, 0xa5000000, 0xb4000000, 0x94000000, 0x57000000, + 0x10000000, 0x00000000, 0x00000000, 0x00000000, 0x4a000000, + 0x96000000, 0xb2000000, 0xa8000000, 0x6e000000, 0x3b000000, + 0x04000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x44000000, 0xc4000000, 0xff0000ff, 0xe2000000, 0x44000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0x80000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x3c000000, 0x77000000, + 0xbb000000, 0xbb000000, 0x9e000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x09000000, 0x63000000, 0x08000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x44000000, 0x88000000, 0x44000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x44000000, + 0x88000000, 0x88000000, 0x44000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x69000000, 0xff0000b4, 0x65000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x44000000, 0x88000000, 0x88000000, + 0x44000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x44000000, + 0x88000000, 0x88000000, 0x44000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0x80000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xff0000ff, 0x80000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x6a000000, 0xff0000b6, 0x9c000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xff0000ff, 0x80000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xff0000ff, 0x80000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x3c000000, 0xbb000000, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x08000000, + 0x61000000, 0x60000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x3c000000, 0xbb000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x3c000000, 0xbb000000, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x44000000, 0xc4000000, + 0xff0000ff, 0xe2000000, 0x88000000, 0x88000000, 0x88000000, + 0x0f000000, 0x00000000, 0x00000000, 0x41000000, 0x78000000, + 0x78000000, 0x46000000, 0x01000000, 0x00000000, 0x00000000, + 0x44000000, 0x88000000, 0x88000000, 0x45000000, 0x3d000000, + 0x73000000, 0x6c000000, 0x37000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x41000000, + 0x78000000, 0x78000000, 0x46000000, 0x01000000, 0x00000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x38000000, 0x6e000000, 0x79000000, 0x43000000, 0x00000000, + 0x00000000, 0x00000000, 0x44000000, 0x88000000, 0x88000000, + 0x44000000, 0x38000000, 0x75000000, 0x86000000, 0x88000000, + 0x44000000, 0x00000000, 0x00000000, 0x42000000, 0x78000000, + 0x78000000, 0x41000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x1f000000, 0x5c000000, 0x78000000, + 0x60000000, 0x27000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x42000000, 0x78000000, 0x78000000, + 0x41000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x1f000000, 0x5c000000, 0x78000000, 0x60000000, + 0x27000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x1f000000, 0x5c000000, 0x78000000, 0x60000000, 0x27000000, + 0x00000000, 0x00000000, 0x44000000, 0x88000000, 0x88000000, + 0x44000000, 0x00000000, 0x44000000, 0x88000000, 0x88000000, + 0x45000000, 0x3d000000, 0x73000000, 0x6c000000, 0x37000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x43000000, 0x79000000, 0x6f000000, 0x38000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x44000000, + 0x88000000, 0x88000000, 0x44000000, 0x00000000, 0x00000000, + 0x44000000, 0x88000000, 0x88000000, 0x44000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x43000000, 0x79000000, + 0x6f000000, 0x38000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x00000000, 0x00000000, 0x00000000, 0x02000000, 0x46000000, + 0x76000000, 0x65000000, 0x27000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xff0000ff, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff00009c, 0x1c000000, + 0x10000000, 0xc900001f, 0xff0000ad, 0xfe0000e7, 0xff0000e7, + 0xff0000af, 0xc600001f, 0x11000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xff0000ff, 0xee000011, 0xff0000a3, 0xff0000e5, + 0xff0000ca, 0xfc000072, 0x94000010, 0x00000000, 0x00000000, + 0x00000000, 0x10000000, 0xc900001f, 0xff0000ad, 0xfe0000e7, + 0xff0000e7, 0xff0000af, 0xc600001f, 0x11000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xf7000011, 0xff0000a2, + 0xfe0000e0, 0xff0000e9, 0xff0000ad, 0xc100001d, 0x0f000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xff0000ff, 0xef000014, + 0xff0000a3, 0xff0000dd, 0xff0000ff, 0xff0000ff, 0x80000000, + 0x10000000, 0xc900001f, 0xff0000ad, 0xff0000e7, 0xff0000e7, + 0xff0000ad, 0xc900001f, 0x13000000, 0x00000000, 0x00000000, + 0x9000000a, 0xfd000076, 0xff0000b6, 0xff0000ef, 0xfe0000dc, + 0xf50000a0, 0xc8000036, 0x35000000, 0x00000000, 0x10000000, + 0xc900001f, 0xff0000ad, 0xff0000e7, 0xff0000e7, 0xff0000ad, + 0xc900001f, 0x13000000, 0x00000000, 0x00000000, 0x9000000a, + 0xfd000076, 0xff0000b6, 0xff0000ef, 0xfe0000dc, 0xf50000a0, + 0xc8000036, 0x35000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x9000000a, 0xfd000076, + 0xff0000b6, 0xff0000ef, 0xfe0000dc, 0xf50000a0, 0xc8000036, + 0x35000000, 0x80000000, 0xff0000ff, 0xff0000ff, 0x80000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xff0000ff, 0xee000011, + 0xff0000a3, 0xff0000e5, 0xff0000ca, 0xfc000072, 0x94000010, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x10000000, 0xc900001e, + 0xff0000ad, 0xff0000e9, 0xfe0000e0, 0xff0000a2, 0xed000011, + 0xff0000ff, 0xc0000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xff0000ff, 0x80000000, 0x00000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xff0000ff, 0x80000000, 0x00000000, 0x00000000, + 0x10000000, 0xc900001e, 0xff0000ad, 0xff0000e9, 0xfe0000e0, + 0xff0000a2, 0xed000011, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x36000000, 0xdd000045, 0xff0000bf, 0xff0000ef, + 0xff0000b9, 0xfc000063, 0x7e00000b, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x3c000000, 0xbb000000, 0xff0000ff, 0xdd000000, + 0xbb000000, 0xbb000000, 0xbb000000, 0x57000000, 0xb700001a, + 0xff0000e6, 0xf500008e, 0xc9000031, 0xd000002c, 0xf8000087, + 0xff0000dd, 0xb1000014, 0x00000000, 0x3c000000, 0xbb000000, + 0xff0000ff, 0xff0000b1, 0xea000077, 0xbd00001d, 0xda000042, + 0xfd0000bc, 0xfa000074, 0x36000000, 0x00000000, 0x00000000, + 0xb700001a, 0xff0000e6, 0xf500008e, 0xc9000031, 0xd000002c, + 0xf8000087, 0xff0000dd, 0xb1000014, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xff0000bd, 0xf200008c, 0xc500002f, + 0xd1000033, 0xf900009a, 0xff0000e1, 0xb6000017, 0x00000000, + 0x3c000000, 0xbb000000, 0xff0000ff, 0xff0000b8, 0xe0000067, + 0xb8000015, 0xf000005c, 0xff0000ff, 0xc0000000, 0xbc00001a, + 0xff0000e4, 0xf5000098, 0xc8000033, 0xd1000033, 0xf900009a, + 0xff0000e4, 0xbe00001a, 0x00000000, 0x43000000, 0xff000078, + 0xf8000096, 0xbe00002c, 0xb9000011, 0xe5000051, 0xfa0000cf, + 0xff0000ff, 0x8d000000, 0x00000000, 0xbc00001a, 0xff0000e4, + 0xf5000098, 0xc8000033, 0xd1000033, 0xf900009a, 0xff0000e4, + 0xbe00001a, 0x00000000, 0x43000000, 0xff000078, 0xf8000096, + 0xbe00002c, 0xb9000011, 0xe5000051, 0xfa0000cf, 0xff0000ff, + 0x8d000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x43000000, 0xff000078, 0xf8000096, 0xbe00002c, + 0xb9000011, 0xe5000051, 0xfa0000cf, 0xff0000ff, 0x8d000000, + 0x3c000000, 0xbb000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x3c000000, 0xbb000000, 0xff0000ff, 0xff0000b1, 0xea000077, + 0xbd00001d, 0xda000042, 0xfd0000bc, 0xfa000074, 0x36000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xb7000019, 0xff0000e2, 0xf5000098, + 0xc8000033, 0xd100002f, 0xf800008c, 0xff0000bc, 0xff0000ff, + 0xc0000000, 0x00000000, 0x3c000000, 0xbb000000, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x3c000000, 0xbb000000, + 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0xb7000019, + 0xff0000e2, 0xf5000098, 0xc8000033, 0xd100002f, 0xf800008c, + 0xff0000bc, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xf2000076, 0xbe000014, 0xd7000031, + 0xfe0000b1, 0xff00008e, 0x33000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x00000000, 0x2e000000, 0xff00009b, 0xf900009e, + 0x82000000, 0x47000000, 0x19000000, 0x25000000, 0xf700008e, + 0xfe000086, 0x25000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xf5000078, 0x5e000000, 0x3c000000, 0x0f000000, 0xcd00004b, + 0xfe0000c1, 0x89000000, 0x00000000, 0x2e000000, 0xff00009b, + 0xf900009e, 0x82000000, 0x47000000, 0x19000000, 0x25000000, + 0xf700008e, 0xfe000086, 0x25000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xf900008a, 0x68000000, 0x46000000, 0x18000000, + 0x30000000, 0xfb000096, 0xff000098, 0x32000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xf0000068, 0x5d000000, 0x34000000, + 0x42000000, 0x90000000, 0xb4000000, 0xff00009c, 0xf8000092, + 0x7e000000, 0x4c000000, 0x1a000000, 0x30000000, 0xfa000096, + 0xff00009b, 0x37000000, 0x75000000, 0xfe0000e4, 0xc5000025, + 0x4c000000, 0x16000000, 0x09000000, 0xcd000040, 0xff0000ff, + 0xc0000000, 0x2e000000, 0xff00009c, 0xf8000092, 0x7e000000, + 0x4c000000, 0x1a000000, 0x30000000, 0xfa000096, 0xff00009b, + 0x37000000, 0x75000000, 0xfe0000e4, 0xc5000025, 0x4c000000, + 0x16000000, 0x09000000, 0xcd000040, 0xff0000ff, 0xc0000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x75000000, 0xfe0000e4, 0xc5000025, 0x4c000000, 0x16000000, + 0x09000000, 0xcd000040, 0xff0000ff, 0xc0000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xf5000078, 0x5e000000, 0x3c000000, + 0x0f000000, 0xcd00004b, 0xfe0000c1, 0x89000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x2a000000, 0xff00009a, 0xf9000092, 0x7d000000, 0x4c000000, + 0x1a000000, 0x26000000, 0xf600008b, 0xff0000ff, 0xc0000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xc0000000, 0x00000000, 0x2a000000, 0xff00009a, 0xf9000092, + 0x7d000000, 0x4c000000, 0x1a000000, 0x26000000, 0xf600008b, + 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x3c000000, + 0x77000000, 0x9b000000, 0x3b000000, 0x0a000000, 0xaf000027, + 0xff0000e4, 0x8f000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x00000000, 0x5d000000, 0xff0000da, 0xeb000034, 0xad000000, + 0x88000000, 0x88000000, 0x88000000, 0xde00002f, 0xff0000cb, + 0x7b000000, 0x00000000, 0x80000000, 0xff0000ff, 0xd1000028, + 0x3c000000, 0x00000000, 0x00000000, 0x90000011, 0xff0000fc, + 0xaf000000, 0x00000000, 0x5d000000, 0xff0000da, 0xeb000034, + 0xad000000, 0x88000000, 0x88000000, 0x88000000, 0xde00002f, + 0xff0000cb, 0x7b000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xd7000036, 0x45000000, 0x00000000, 0x00000000, 0x00000000, + 0xbe00004b, 0xfe0000d8, 0x95000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xcb000019, 0x34000000, 0x00000000, 0x00000000, + 0x00000000, 0x5d000000, 0xff0000da, 0xd0000049, 0x49000000, + 0x00000000, 0x00000000, 0x00000000, 0xbe00004b, 0xfe0000d9, + 0x96000000, 0x49000000, 0xf70000a8, 0xfb0000cb, 0xea000055, + 0x82000005, 0x48000000, 0x44000000, 0x88000000, 0x9e000000, + 0x5d000000, 0xff0000da, 0xd0000049, 0x49000000, 0x00000000, + 0x00000000, 0x00000000, 0xbe00004b, 0xfe0000d9, 0x96000000, + 0x49000000, 0xf70000a8, 0xfb0000cb, 0xea000055, 0x82000005, + 0x48000000, 0x44000000, 0x88000000, 0x9e000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x49000000, + 0xf70000a8, 0xfb0000cb, 0xea000055, 0x82000005, 0x48000000, + 0x44000000, 0x88000000, 0x9e000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xd1000028, 0x3c000000, 0x00000000, 0x00000000, + 0x90000011, 0xff0000fc, 0xaf000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x5b000000, + 0xff0000da, 0xd0000049, 0x49000000, 0x00000000, 0x00000000, + 0x00000000, 0xb0000037, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x00000000, 0x5b000000, 0xff0000da, 0xd0000049, 0x49000000, + 0x00000000, 0x00000000, 0x00000000, 0xb0000037, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x2d000000, + 0x60000000, 0x81000000, 0x88000000, 0xc4000000, 0xff0000f6, + 0xb3000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x00000000, + 0x7a000000, 0xff0000f6, 0xff0000ff, 0xff0000ff, 0xff0000ff, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ee, 0xa8000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x14000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xbf000000, + 0x00000000, 0x7a000000, 0xff0000f6, 0xff0000ff, 0xff0000ff, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ee, + 0xa8000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000001, + 0x1b000000, 0x00000000, 0x00000000, 0x00000000, 0x92000013, + 0xff0000f6, 0xb3000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xc0000000, 0x0d000000, 0x00000000, 0x00000000, 0x00000000, + 0x78000000, 0xff0000f6, 0xc0000012, 0x25000000, 0x00000000, + 0x00000000, 0x00000000, 0x92000013, 0xff0000f6, 0xb4000000, + 0x00000000, 0x8f000007, 0xf900007e, 0xfc0000dd, 0xff0000f2, + 0xfb0000c2, 0xf200005c, 0x72000001, 0x00000000, 0x78000000, + 0xff0000f6, 0xc0000012, 0x25000000, 0x00000000, 0x00000000, + 0x00000000, 0x92000013, 0xff0000f6, 0xb4000000, 0x00000000, + 0x8f000007, 0xf900007e, 0xfc0000dd, 0xff0000f2, 0xfb0000c2, + 0xf200005c, 0x72000001, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8f000007, + 0xf900007e, 0xfc0000dd, 0xff0000f2, 0xfb0000c2, 0xf200005c, + 0x72000001, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xc0000000, 0x14000000, 0x00000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xbf000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x78000000, 0xff0000f6, + 0xc0000012, 0x25000000, 0x00000000, 0x00000000, 0x00000000, + 0x80000001, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x78000000, 0xff0000f6, 0xc0000012, 0x25000000, 0x00000000, + 0x00000000, 0x00000000, 0x80000001, 0xff0000ff, 0xc0000000, + 0x00000000, 0x01000000, 0xa1000010, 0xfe00007f, 0xfe0000c1, + 0xff0000f9, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xbd000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x69000000, + 0xff0000d9, 0xe8000028, 0xbb000000, 0xbb000000, 0xbb000000, + 0xbb000000, 0xda000000, 0xff000000, 0xc1000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x69000000, 0xff0000d9, 0xe8000028, 0xbb000000, 0xbb000000, + 0xbb000000, 0xbb000000, 0xda000000, 0xff000000, 0xc1000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xd300002b, 0x01000000, + 0x00000000, 0x00000000, 0x00000000, 0xbe00004b, 0xfe0000d8, + 0xb1000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x5d000000, + 0xff0000da, 0xdc00004a, 0x09000000, 0x00000000, 0x00000000, + 0x00000000, 0xbe00004b, 0xfe0000d9, 0xb1000000, 0x44000000, + 0x88000000, 0x65000000, 0x84000000, 0xc8000014, 0xf4000059, + 0xfc0000cc, 0xfb000098, 0x40000000, 0x5d000000, 0xff0000da, + 0xdc00004a, 0x09000000, 0x00000000, 0x00000000, 0x00000000, + 0xbe00004b, 0xfe0000d9, 0xb1000000, 0x44000000, 0x88000000, + 0x65000000, 0x84000000, 0xc8000014, 0xf4000059, 0xfc0000cc, + 0xfb000098, 0x40000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x44000000, 0x88000000, 0x65000000, + 0x84000000, 0xc8000014, 0xf4000059, 0xfc0000cc, 0xfb000098, + 0x40000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x5b000000, 0xff0000da, 0xdc000049, + 0x09000000, 0x00000000, 0x00000000, 0x00000000, 0xa700002c, + 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x7e000000, + 0xff0000fc, 0xc7000011, 0x00000000, 0x00000000, 0x00000000, + 0xa500002a, 0xff0000ff, 0xc0000000, 0x00000000, 0x5b000000, + 0xff0000da, 0xdc000049, 0x09000000, 0x00000000, 0x00000000, + 0x00000000, 0xa700002c, 0xff0000ff, 0xc0000000, 0x00000000, + 0x48000000, 0xff000083, 0xfb0000a8, 0xc7000038, 0xb500000a, + 0xba000000, 0xdd000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x7f000000, 0xff0000fd, 0xc0000002, + 0x00000000, 0x43000000, 0x88000000, 0x71000000, 0xff000097, + 0xf4000080, 0x1b000000, 0x00000000, 0x00000000, 0x08000000, + 0xe0000059, 0xff0000b5, 0x55000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x2b000000, + 0xff000097, 0xf4000080, 0x1b000000, 0x00000000, 0x00000000, + 0x08000000, 0xe0000059, 0xff0000b5, 0x55000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xf7000083, 0x1f000000, 0x00000000, + 0x00000000, 0x18000000, 0xf9000096, 0xff000097, 0x83000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x2b000000, 0xff00009b, + 0xfb000095, 0x39000000, 0x00000000, 0x00000000, 0x18000000, + 0xf9000096, 0xff00009b, 0x85000000, 0x80000000, 0xff0000ff, + 0xba00003a, 0x00000000, 0x00000000, 0x0b000000, 0xc1000027, + 0xff0000e2, 0x9d000000, 0x2b000000, 0xff00009b, 0xfb000095, + 0x39000000, 0x00000000, 0x00000000, 0x18000000, 0xf9000096, + 0xff00009b, 0x85000000, 0x80000000, 0xff0000ff, 0xba00003a, + 0x00000000, 0x00000000, 0x0b000000, 0xc1000027, 0xff0000e2, + 0x9d000000, 0x00000000, 0x44000000, 0x88000000, 0x45000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xba00003a, 0x00000000, + 0x00000000, 0x0b000000, 0xc1000027, 0xff0000e2, 0x9d000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x2a000000, 0xff000099, 0xfb000092, 0x38000000, + 0x00000000, 0x00000000, 0x0b000000, 0xf0000084, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x67000000, 0xfe0000c2, + 0xdf000048, 0x09000000, 0x00000000, 0x07000000, 0xec00007a, + 0xff0000ff, 0xc0000000, 0x00000000, 0x2a000000, 0xff000099, + 0xfb000092, 0x38000000, 0x00000000, 0x00000000, 0x0b000000, + 0xf0000084, 0xff0000ff, 0xc0000000, 0x00000000, 0x76000000, + 0xff0000e1, 0xbd000026, 0x54000000, 0x1c000000, 0x05000000, + 0x98000015, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x44000000, 0x88000000, 0x88000000, 0x44000000, 0x00000000, + 0x00000000, 0x66000000, 0xff0000c1, 0xee000050, 0x8e00000d, + 0xe400005a, 0xfe0000c7, 0x66000000, 0xad000015, 0xff0000d3, + 0xf200007f, 0xaa00002d, 0x9d00001d, 0xe6000061, 0xff0000e9, + 0xe9000025, 0x60000000, 0x44000000, 0xc4000000, 0xff0000ff, + 0xe2000000, 0x44000000, 0x00000000, 0x44000000, 0xc4000000, + 0xff0000ff, 0xe2000000, 0x44000000, 0x00000000, 0xad000015, + 0xff0000d3, 0xf200007f, 0xaa00002d, 0x9d00001d, 0xe6000061, + 0xff0000e9, 0xe9000025, 0x60000000, 0x44000000, 0xc4000000, + 0xff0000ff, 0xff0000cc, 0xf3000083, 0xa900002b, 0xac000033, + 0xf5000099, 0xff0000e1, 0xc9000017, 0x4c000000, 0x44000000, + 0xc4000000, 0xff0000ff, 0xe2000000, 0x88000000, 0x44000000, + 0x00000000, 0x00000000, 0x00000000, 0xb800001a, 0xff0000e4, + 0xf8000099, 0xac000033, 0xac000033, 0xf5000099, 0xff0000e4, + 0xcc00001a, 0x4e000000, 0x80000000, 0xff0000ff, 0xfc0000c5, + 0xcf00004a, 0x91000010, 0xab00002c, 0xfa00009d, 0xff000074, + 0x95000000, 0x00000000, 0xb800001a, 0xff0000e4, 0xf8000099, + 0xac000033, 0xac000033, 0xf5000099, 0xff0000e4, 0xcc00001a, + 0x4e000000, 0x80000000, 0xff0000ff, 0xfc0000c5, 0xcf00004a, + 0x91000010, 0xab00002c, 0xfa00009d, 0xff000074, 0x95000000, + 0x00000000, 0x8e000009, 0xff0000e8, 0x72000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xfc0000c5, 0xcf00004a, 0x91000010, + 0xab00002c, 0xfa00009d, 0xff000074, 0x95000000, 0x44000000, + 0xc4000000, 0xff0000ff, 0xe2000000, 0x44000000, 0x44000000, + 0xc4000000, 0xff0000ff, 0xe2000000, 0x44000000, 0x00000000, + 0x44000000, 0xc4000000, 0xff0000ff, 0xe2000000, 0x44000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0xb8000019, 0xff0000e2, 0xf7000097, 0xab000032, + 0xa900002b, 0xef000083, 0xff0000cc, 0xff0000ff, 0xe2000000, + 0x44000000, 0x00000000, 0x30000000, 0xf9000076, 0xfd0000ba, + 0xc4000041, 0x9c00001c, 0xe9000076, 0xff0000b0, 0xff0000ff, + 0xe2000000, 0x44000000, 0x00000000, 0xb8000019, 0xff0000e2, + 0xf7000097, 0xab000032, 0xa900002b, 0xef000083, 0xff0000cc, + 0xff0000ff, 0xe2000000, 0x44000000, 0x47000000, 0xfd000086, + 0xfd0000af, 0xbd000038, 0x8f00000e, 0xc000003c, 0xfe0000b5, + 0xff0000ff, 0xe2000000, 0x44000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xff0000ff, 0x80000000, 0x00000000, 0x00000000, + 0x15000000, 0xee000046, 0xff0000bd, 0xff0000ef, 0xfd0000be, + 0xeb00003f, 0x6f000000, 0x0e000000, 0xc0000018, 0xff0000a4, + 0xff0000e1, 0xff0000e5, 0xfc00009b, 0xec000042, 0x8d000000, + 0x13000000, 0x80000000, 0xff0000ff, 0xff0000ff, 0xff0000ff, + 0x80000000, 0x00000000, 0x80000000, 0xff0000ff, 0xff0000ff, + 0xff0000ff, 0x80000000, 0x00000000, 0x0e000000, 0xc0000018, + 0xff0000a4, 0xff0000e1, 0xff0000e5, 0xfc00009b, 0xec000042, + 0x8d000000, 0x13000000, 0x80000000, 0xff0000ff, 0xff0000ff, + 0xfa00001a, 0xff0000ad, 0xff0000e4, 0xff0000e9, 0xff0000ad, + 0xd100001d, 0x78000000, 0x0c000000, 0x80000000, 0xff0000ff, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0x80000000, 0x00000000, + 0x00000000, 0x00000000, 0x13000000, 0xcd00001f, 0xff0000ae, + 0xff0000e8, 0xff0000e8, 0xff0000ae, 0xd900001f, 0x7d000000, + 0x0d000000, 0x36000000, 0xd300003b, 0xfb0000aa, 0xff0000e1, + 0xff0000f0, 0xff0000b6, 0xfc000076, 0xae000008, 0x3a000000, + 0x00000000, 0x13000000, 0xcd00001f, 0xff0000ae, 0xff0000e8, + 0xff0000e8, 0xff0000ae, 0xd900001f, 0x7d000000, 0x0d000000, + 0x36000000, 0xd300003b, 0xfb0000aa, 0xff0000e1, 0xff0000f0, + 0xff0000b6, 0xfc000076, 0xae000008, 0x3a000000, 0x00000000, + 0xba00002b, 0xff0000ba, 0x9f000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x36000000, + 0xd300003b, 0xfb0000aa, 0xff0000e1, 0xff0000f0, 0xff0000b6, + 0xfc000076, 0xae000008, 0x3a000000, 0x80000000, 0xff0000ff, + 0xff0000ff, 0xff0000ff, 0x80000000, 0x80000000, 0xff0000ff, + 0xff0000ff, 0xff0000ff, 0x80000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0x80000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0f000000, 0xc300001e, 0xff0000ae, 0xff0000e9, 0xfe0000e5, + 0xff0000ae, 0xf600001a, 0xff0000ff, 0xff0000ff, 0x80000000, + 0x00000000, 0x00000000, 0x96000011, 0xfd000075, 0xff0000cc, + 0xff0000e6, 0xff0000a4, 0xf2000011, 0xff0000ff, 0xff0000ff, + 0x80000000, 0x00000000, 0x0f000000, 0xc300001e, 0xff0000ae, + 0xff0000e9, 0xfe0000e5, 0xff0000ae, 0xf600001a, 0xff0000ff, + 0xff0000ff, 0x80000000, 0x00000000, 0x9b000011, 0xfc000082, + 0xff0000cb, 0xff0000f2, 0xff0000ca, 0xfe000048, 0xff0000ff, + 0xff0000ff, 0x80000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x00000000, + 0x0f000000, 0x78000000, 0xaa000000, 0xaa000000, 0x68000000, + 0x20000000, 0x00000000, 0x00000000, 0x3b000000, 0x9f000000, + 0xb0000000, 0x9e000000, 0x51000000, 0x21000000, 0x00000000, + 0x3c000000, 0x77000000, 0xbb000000, 0xbb000000, 0x9e000000, + 0x00000000, 0x3c000000, 0x77000000, 0xbb000000, 0xbb000000, + 0x9e000000, 0x00000000, 0x00000000, 0x00000000, 0x3b000000, + 0x9f000000, 0xb0000000, 0x9e000000, 0x51000000, 0x21000000, + 0x00000000, 0x3c000000, 0x77000000, 0xbb000000, 0x9e000000, + 0x47000000, 0xa5000000, 0xb3000000, 0x95000000, 0x57000000, + 0x0f000000, 0x00000000, 0x3c000000, 0x77000000, 0xbb000000, + 0xbb000000, 0xbb000000, 0x9e000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x47000000, 0xa5000000, + 0xb4000000, 0x94000000, 0x57000000, 0x10000000, 0x00000000, + 0x00000000, 0x00000000, 0x4a000000, 0x96000000, 0xb2000000, + 0xa8000000, 0x6e000000, 0x3b000000, 0x04000000, 0x00000000, + 0x00000000, 0x00000000, 0x47000000, 0xa5000000, 0xb4000000, + 0x94000000, 0x57000000, 0x10000000, 0x00000000, 0x00000000, + 0x00000000, 0x4a000000, 0x96000000, 0xb2000000, 0xa8000000, + 0x6e000000, 0x3b000000, 0x04000000, 0x13000000, 0xf600007d, + 0xf900006e, 0x66000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x4a000000, 0x96000000, 0xb2000000, 0xa8000000, 0x6e000000, + 0x3b000000, 0x04000000, 0x3c000000, 0x77000000, 0xbb000000, + 0xbb000000, 0x9e000000, 0x3c000000, 0x77000000, 0xbb000000, + 0xbb000000, 0x9e000000, 0x00000000, 0x3c000000, 0x77000000, + 0xbb000000, 0xbb000000, 0x9e000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x47000000, 0xa5000000, 0xb5000000, 0x94000000, + 0x7f000000, 0x7e000000, 0xbb000000, 0x9e000000, 0x00000000, + 0x00000000, 0x00000000, 0x3d000000, 0x8d000000, 0xaa000000, + 0x93000000, 0x7b000000, 0x7c000000, 0xbb000000, 0x9e000000, + 0x00000000, 0x00000000, 0x00000000, 0x47000000, 0xa5000000, + 0xb5000000, 0x94000000, 0x7f000000, 0x7e000000, 0xbb000000, + 0x9e000000, 0x00000000, 0x00000000, 0x35000000, 0x8d000000, + 0xaa000000, 0xa1000000, 0x8e000000, 0x8a000000, 0xbb000000, + 0x9e000000, 0x00000000, 0x3c000000, 0x77000000, 0xbb000000, + 0x9e000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x6d000000, 0xff000097, 0x9c000002, + 0x37000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x06000000, 0x79000000, 0x4d000000, 0x01000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000 +}; + +void +subpicture_get_info (VideoSubpictureInfo * info) +{ + info->width = SUBPICTURE_WIDTH; + info->height = SUBPICTURE_HEIGHT; + info->data = text; + info->data_size = SUBPICTURE_DATA_SIZE; +} diff --git a/tests/internal/test-subpicture-data.h b/tests/internal/test-subpicture-data.h new file mode 100644 index 0000000000..cc37988aa5 --- /dev/null +++ b/tests/internal/test-subpicture-data.h @@ -0,0 +1,40 @@ +/* + * test-subpicture-data.h - subpicture data + * + * Copyright (C) <2011> Intel Corporation + * Copyright (C) <2011> Collabora Ltd. + * Copyright (C) <2011> Thibault Saunier + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef TEST_SUBPICTURE_DATA +#define TEST_SUBPICTURE_DATA + +#include +#include "test-decode.h" + +typedef struct _VideoSubpictureInfo VideoSubpictureInfo; + +struct _VideoSubpictureInfo { + guint width; + guint height; + const guint32 *data; + guint data_size; +}; + +void subpicture_get_info(VideoSubpictureInfo *info); + +#endif /* TEST_SUBPICTURE_DATA*/ diff --git a/tests/internal/test-subpicture.c b/tests/internal/test-subpicture.c new file mode 100644 index 0000000000..804f0a9e32 --- /dev/null +++ b/tests/internal/test-subpicture.c @@ -0,0 +1,171 @@ +/* + * test-subpicture.c - Test GstVaapiSubpicture + * + * Copyright (C) <2011-2013> Intel Corporation + * Copyright (C) <2011> Collabora Ltd. + * Copyright (C) <2011> Thibault Saunier + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "gst/vaapi/sysdeps.h" +#include +#include "decoder.h" +#include "output.h" +#include "test-subpicture-data.h" + +static inline void +pause (void) +{ + g_print ("Press any key to continue...\n"); + getchar (); +} + +static gchar *g_codec_str; +static gdouble g_global_alpha = 1.0; + +static GOptionEntry g_options[] = { + {"codec", 'c', + 0, + G_OPTION_ARG_STRING, &g_codec_str, + "codec to test", NULL}, + {"global-alpha", 'g', + 0, + G_OPTION_ARG_DOUBLE, &g_global_alpha, + "global-alpha value", NULL}, + {NULL,} +}; + +static void +upload_subpicture (GstBuffer * buffer, const VideoSubpictureInfo * subinfo) +{ + const guint32 *const src = subinfo->data; + guint i, len = subinfo->data_size / 4; + GstMapInfo map_info; + guint32 *dst; + + if (!gst_buffer_map (buffer, &map_info, GST_MAP_WRITE)) + return; + dst = (guint32 *) map_info.data; + + /* Convert from RGBA source to ARGB */ + for (i = 0; i < len; i++) { + const guint32 rgba = src[i]; + dst[i] = (rgba >> 8) | (rgba << 24); + } + + gst_buffer_unmap (buffer, &map_info); +} + +int +main (int argc, char *argv[]) +{ + GstVaapiDisplay *display; + GstVaapiWindow *window; + GstVaapiDecoder *decoder; + GstVaapiSurfaceProxy *proxy; + GstVaapiSurface *surface; + GstBuffer *buffer; + VideoSubpictureInfo subinfo; + GstVaapiRectangle subrect; + GstVideoOverlayRectangle *overlay; + GstVideoOverlayComposition *compo; + guint flags = 0; + + static const guint win_width = 640; + static const guint win_height = 480; + + if (!video_output_init (&argc, argv, g_options)) + g_error ("failed to initialize video output subsystem"); + + if (g_global_alpha != 1.0) + flags |= GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA; + + g_print ("Test subpicture\n"); + + display = video_output_create_display (NULL); + if (!display) + g_error ("could not create VA display"); + + window = video_output_create_window (display, win_width, win_height); + if (!window) + g_error ("could not create window"); + + decoder = decoder_new (display, g_codec_str); + if (!decoder) + g_error ("could not create decoder"); + + if (!decoder_put_buffers (decoder)) + g_error ("could not fill decoder with sample data"); + + proxy = decoder_get_surface (decoder); + if (!proxy) + g_error ("could not get decoded surface"); + + surface = gst_vaapi_surface_proxy_get_surface (proxy); + + subpicture_get_info (&subinfo); + buffer = gst_buffer_new_and_alloc (subinfo.data_size); + upload_subpicture (buffer, &subinfo); + + /* We position the subpicture at the bottom center */ + subrect.x = (gst_vaapi_surface_get_width (surface) - subinfo.width) / 2; + subrect.y = gst_vaapi_surface_get_height (surface) - subinfo.height - 10; + subrect.height = subinfo.height; + subrect.width = subinfo.width; + + { + GstVideoMeta *const vmeta = + gst_buffer_add_video_meta (buffer, GST_VIDEO_FRAME_FLAG_NONE, + GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_RGB, + subinfo.width, subinfo.height); + if (!vmeta) + g_error ("could not create video meta"); + + overlay = gst_video_overlay_rectangle_new_raw (buffer, + subrect.x, subrect.y, subrect.width, subrect.height, flags); + } + if (!overlay) + g_error ("could not create video overlay"); + gst_buffer_unref (buffer); + + if (flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA) + gst_video_overlay_rectangle_set_global_alpha (overlay, g_global_alpha); + + compo = gst_video_overlay_composition_new (overlay); + if (!compo) + g_error ("could not create video overlay composition"); + gst_video_overlay_rectangle_unref (overlay); + + if (!gst_vaapi_surface_set_subpictures_from_composition (surface, compo)) + g_error ("could not create subpictures from video overlay compoition"); + + gst_vaapi_window_show (window); + + if (!gst_vaapi_window_put_surface (window, surface, NULL, NULL, + GST_VAAPI_PICTURE_STRUCTURE_FRAME)) + g_error ("could not render surface"); + + pause (); + + gst_video_overlay_composition_unref (compo); + gst_vaapi_surface_proxy_unref (proxy); + gst_object_unref (decoder); + gst_object_unref (window); + gst_object_unref (display); + g_free (g_codec_str); + video_output_exit (); + return 0; +} diff --git a/tests/internal/test-surfaces.c b/tests/internal/test-surfaces.c new file mode 100644 index 0000000000..9f515eedb3 --- /dev/null +++ b/tests/internal/test-surfaces.c @@ -0,0 +1,107 @@ +/* + * test-surfaces.c - Test GstVaapiSurface and GstVaapiSurfacePool + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include +#include +#include "output.h" + +#define MAX_SURFACES 4 + +int +main (int argc, char *argv[]) +{ + GstVaapiDisplay *display; + GstVaapiSurface *surface; + GstVaapiID surface_id; + GstVaapiSurface *surfaces[MAX_SURFACES]; + GstVaapiVideoPool *pool; + gint i; + + static const GstVaapiChromaType chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420; + static const guint width = 320; + static const guint height = 240; + + if (!video_output_init (&argc, argv, NULL)) + g_error ("failed to initialize video output subsystem"); + + display = video_output_create_display (NULL); + if (!display) + g_error ("could not create Gst/VA display"); + + surface = gst_vaapi_surface_new (display, chroma_type, width, height); + if (!surface) + g_error ("could not create Gst/VA surface"); + + surface_id = gst_vaapi_surface_get_id (surface); + g_print ("created surface %" GST_VAAPI_ID_FORMAT "\n", + GST_VAAPI_ID_ARGS (surface_id)); + + gst_vaapi_surface_unref (surface); + + pool = gst_vaapi_surface_pool_new (display, GST_VIDEO_FORMAT_ENCODED, + width, height, 0); + if (!pool) + g_error ("could not create Gst/VA surface pool"); + + for (i = 0; i < MAX_SURFACES; i++) { + surface = gst_vaapi_video_pool_get_object (pool); + if (!surface) + g_error ("could not allocate Gst/VA surface from pool"); + g_print ("created surface %" GST_VAAPI_ID_FORMAT " from pool\n", + GST_VAAPI_ID_ARGS (gst_vaapi_surface_get_id (surface))); + surfaces[i] = surface; + } + + /* Check the pool doesn't return the last free'd surface */ + surface = (GstVaapiSurface *) + gst_mini_object_ref (GST_MINI_OBJECT_CAST (surfaces[1])); + + for (i = 0; i < 2; i++) + gst_vaapi_video_pool_put_object (pool, surfaces[i]); + + for (i = 0; i < 2; i++) { + surfaces[i] = gst_vaapi_video_pool_get_object (pool); + if (!surfaces[i]) + g_error ("could not re-allocate Gst/VA surface%d from pool", i); + g_print ("created surface %" GST_VAAPI_ID_FORMAT " from pool (realloc)\n", + GST_VAAPI_ID_ARGS (gst_vaapi_surface_get_id (surfaces[i]))); + } + + if (surface == surfaces[0]) + g_error ("Gst/VA pool doesn't queue free surfaces"); + + for (i = MAX_SURFACES - 1; i >= 0; i--) { + if (!surfaces[i]) + continue; + gst_vaapi_video_pool_put_object (pool, surfaces[i]); + surfaces[i] = NULL; + } + + /* Unref in random order to check objects are correctly refcounted */ + gst_object_unref (display); + gst_vaapi_video_pool_unref (pool); + gst_vaapi_surface_unref (surface); + video_output_exit (); + return 0; +} diff --git a/tests/internal/test-textures.c b/tests/internal/test-textures.c new file mode 100644 index 0000000000..0f7e1e9270 --- /dev/null +++ b/tests/internal/test-textures.c @@ -0,0 +1,179 @@ +/* + * test-textures.c - Test GstVaapiTexture + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gst/vaapi/sysdeps.h" +#include +#include +#include +#include +#include +#include "image.h" + +static inline void +pause (void) +{ + g_print ("Press any key to continue...\n"); + getchar (); +} + +static inline guint +gl_get_current_texture_2d (void) +{ + GLint texture; + glGetIntegerv (GL_TEXTURE_BINDING_2D, &texture); + return (guint) texture; +} + +int +main (int argc, char *argv[]) +{ + GstVaapiDisplay *display; + GstVaapiWindow *window; + GstVaapiWindowGLX *glx_window; + GstVaapiSurface *surface; + GstVaapiImage *image; + GstVaapiTexture *textures[2]; + GstVaapiTexture *texture; + GLuint texture_id; + GstVaapiRectangle src_rect; + GstVaapiRectangle dst_rect; + guint flags = GST_VAAPI_PICTURE_STRUCTURE_FRAME; + + static const GstVaapiChromaType chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420; + static const guint width = 320; + static const guint height = 240; + static const guint win_width = 640; + static const guint win_height = 480; + + gst_init (&argc, &argv); + + display = gst_vaapi_display_glx_new (NULL); + if (!display) + g_error ("could not create VA display"); + + surface = gst_vaapi_surface_new (display, chroma_type, width, height); + if (!surface) + g_error ("could not create VA surface"); + + image = image_generate (display, GST_VIDEO_FORMAT_NV12, width, height); + if (!image) + g_error ("could not create VA image"); + if (!image_upload (image, surface)) + g_error ("could not upload VA image to surface"); + + window = gst_vaapi_window_glx_new (display, win_width, win_height); + if (!window) + g_error ("could not create window"); + glx_window = GST_VAAPI_WINDOW_GLX (window); + + gst_vaapi_window_show (window); + + if (!gst_vaapi_window_glx_make_current (glx_window)) + g_error ("coult not bind GL context"); + + g_print ("#\n"); + g_print ("# Create texture with gst_vaapi_texture_glx_new()\n"); + g_print ("#\n"); + { + texture = gst_vaapi_texture_glx_new (display, + GL_TEXTURE_2D, GL_RGBA, width, height); + if (!texture) + g_error ("could not create VA texture"); + + textures[0] = texture; + texture_id = gst_vaapi_texture_get_id (texture); + + if (!gst_vaapi_texture_put_surface (texture, surface, NULL, flags)) + g_error ("could not transfer VA surface to texture"); + + if (!gst_vaapi_window_glx_put_texture (glx_window, texture, NULL, NULL)) + g_error ("could not render texture into the window"); + } + + g_print ("#\n"); + g_print ("# Create texture with gst_vaapi_texture_glx_new_wrapped()\n"); + g_print ("#\n"); + { + const GLenum target = GL_TEXTURE_2D; + const GLenum format = GL_BGRA; + + glEnable (target); + glGenTextures (1, &texture_id); + glBindTexture (target, texture_id); + glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glPixelStorei (GL_UNPACK_ALIGNMENT, 4); + glTexImage2D (target, + 0, GL_RGBA8, width, height, 0, format, GL_UNSIGNED_BYTE, NULL); + glDisable (target); + + texture = gst_vaapi_texture_glx_new_wrapped (display, + texture_id, target, format); + if (!texture) + g_error ("could not create VA texture"); + + if (texture_id != gst_vaapi_texture_get_id (texture)) + g_error ("invalid texture id"); + + if (gl_get_current_texture_2d () != texture_id) + g_error ("gst_vaapi_texture_glx_new_wrapped() altered texture bindings"); + + textures[1] = texture; + + if (!gst_vaapi_texture_put_surface (texture, surface, NULL, flags)) + g_error ("could not transfer VA surface to texture"); + + if (gl_get_current_texture_2d () != texture_id) + g_error ("gst_vaapi_texture_put_surface() altered texture bindings"); + + src_rect.x = 0; + src_rect.y = 0; + src_rect.width = width; + src_rect.height = height; + + dst_rect.x = win_width / 2; + dst_rect.y = win_height / 2; + dst_rect.width = win_width / 2; + dst_rect.height = win_height / 2; + + if (!gst_vaapi_window_glx_put_texture (glx_window, texture, + &src_rect, &dst_rect)) + g_error ("could not render texture into the window"); + + if (gl_get_current_texture_2d () != texture_id) + g_error ("gst_vaapi_window_glx_put_texture() altered texture bindings"); + } + + gst_vaapi_window_glx_swap_buffers (glx_window); + pause (); + + gst_mini_object_unref (GST_MINI_OBJECT_CAST (textures[0])); + gst_mini_object_unref (GST_MINI_OBJECT_CAST (textures[1])); + glDeleteTextures (1, &texture_id); + + gst_object_unref (window); + gst_object_unref (display); + gst_deinit (); + return 0; +} diff --git a/tests/internal/test-vc1.c b/tests/internal/test-vc1.c new file mode 100644 index 0000000000..4a8dc9e848 --- /dev/null +++ b/tests/internal/test-vc1.c @@ -0,0 +1,1780 @@ +/* + * test-vc1.c - VC-1 test data + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "test-vc1.h" + +#define VC1_CLIP_WIDTH 293 +#define VC1_CLIP_HEIGHT 240 +#define VC1_CLIP_DATA_SIZE 20864 + +/* Data dump of a 320x240 VC-1 video clip (vc1.raw), it has a single frame */ +static const guchar vc1_clip[VC1_CLIP_DATA_SIZE] = { + 0x00, 0x00, 0x01, 0x0f, 0xca, 0x00, 0x09, 0xf0, 0x77, 0x0a, 0x09, 0x20, + 0x1d, 0xff, 0x0a, 0x0b, 0x80, 0x84, 0x80, 0x00, 0x00, 0x01, 0x0e, 0x4c, + 0x10, 0x80, 0x00, 0x00, 0x01, 0x0d, 0xc1, 0xd8, 0xd4, 0x47, 0xd0, 0xaa, + 0xc4, 0x45, 0xaa, 0xb8, 0x01, 0xdf, 0x4c, 0xc1, 0x3a, 0xfa, 0x13, 0x67, + 0x6a, 0xed, 0x2c, 0x67, 0xbc, 0xef, 0xdc, 0x69, 0x99, 0xf8, 0x53, 0x97, + 0x01, 0xdc, 0xbe, 0xd8, 0x3b, 0xa2, 0x96, 0xe8, 0xa1, 0x94, 0x02, 0x57, + 0x82, 0x82, 0xd6, 0x14, 0xc7, 0x61, 0x5a, 0x00, 0x22, 0x81, 0x73, 0x33, + 0x20, 0x00, 0xa0, 0x09, 0xc0, 0x50, 0xfa, 0x06, 0xce, 0x35, 0x91, 0x8d, + 0x19, 0x0f, 0x07, 0x1e, 0x84, 0x5b, 0x3a, 0x29, 0x03, 0xad, 0x8f, 0x8a, + 0xd2, 0x22, 0xf0, 0xfc, 0x28, 0xd2, 0x95, 0x4a, 0xfe, 0x74, 0x4b, 0x23, + 0xe7, 0xd4, 0x12, 0x1f, 0x37, 0x01, 0x88, 0xf8, 0xa4, 0x09, 0x76, 0x51, + 0xae, 0xf4, 0x23, 0x6d, 0x29, 0x8c, 0x54, 0xaa, 0x2c, 0x68, 0x10, 0x7e, + 0x71, 0xbf, 0x10, 0xb4, 0x77, 0x97, 0x8b, 0xa1, 0x54, 0xd1, 0xda, 0xb5, + 0x5f, 0x61, 0xf0, 0x64, 0x64, 0x29, 0x25, 0x7d, 0x42, 0xe0, 0xff, 0x2a, + 0x83, 0x29, 0x61, 0xfc, 0xee, 0xe5, 0x11, 0x04, 0xc0, 0x43, 0xc0, 0xc4, + 0x0e, 0x18, 0x43, 0xb6, 0x08, 0x55, 0xa0, 0x22, 0xf4, 0x58, 0x01, 0xc6, + 0x43, 0x0d, 0xba, 0x04, 0x3e, 0x8e, 0x5f, 0xc1, 0x11, 0x56, 0xef, 0xd7, + 0x78, 0xe2, 0xd2, 0xdb, 0x84, 0x16, 0x76, 0xc6, 0x92, 0x15, 0xf6, 0xc2, + 0x76, 0x2f, 0xd2, 0xef, 0x46, 0x02, 0x60, 0x24, 0xda, 0x16, 0x48, 0x95, + 0xc4, 0x87, 0x81, 0xa7, 0xdd, 0xd7, 0x77, 0x56, 0xb7, 0xb5, 0x28, 0x9d, + 0x6b, 0x7b, 0xd6, 0x8b, 0x80, 0x42, 0x28, 0xb0, 0x28, 0x82, 0x50, 0x04, + 0x65, 0x1a, 0xc3, 0x79, 0x74, 0x6c, 0x3e, 0x9e, 0x69, 0x0e, 0xc1, 0xed, + 0x8d, 0xe9, 0xf0, 0xf4, 0xf8, 0xde, 0xc1, 0x62, 0x1d, 0x1f, 0x4a, 0x5d, + 0x02, 0x11, 0xfa, 0xd8, 0x10, 0xb8, 0xa0, 0xc5, 0xf5, 0x85, 0xd1, 0x19, + 0x14, 0x06, 0x21, 0x5b, 0xa5, 0x37, 0xcd, 0xf2, 0xbc, 0x3b, 0x7f, 0xe3, + 0x1c, 0x62, 0x51, 0x4b, 0x09, 0x2e, 0x48, 0x1f, 0x4e, 0x19, 0xe4, 0x90, + 0x22, 0x81, 0xf4, 0xf7, 0x16, 0x4f, 0xe5, 0x97, 0x12, 0x9b, 0x92, 0x6e, + 0xcc, 0x61, 0xd6, 0x4a, 0x59, 0x66, 0x7d, 0xc2, 0x1d, 0x33, 0x7e, 0x62, + 0x29, 0x81, 0x80, 0xb7, 0xa4, 0xcb, 0xc4, 0xc3, 0x9b, 0x1d, 0x2b, 0x00, + 0xc9, 0x78, 0x82, 0xef, 0xd7, 0xa5, 0xad, 0x08, 0x18, 0x7c, 0x97, 0x61, + 0x3e, 0xaf, 0x4e, 0x21, 0xd6, 0x5a, 0x35, 0xd6, 0xf9, 0xdf, 0x89, 0xe9, + 0x09, 0x99, 0x3e, 0x53, 0x81, 0x80, 0x21, 0xd9, 0x44, 0x7f, 0xb9, 0xe7, + 0x7d, 0x1d, 0xa6, 0xd4, 0xb6, 0x60, 0x71, 0xa3, 0x87, 0x13, 0x40, 0x7a, + 0x50, 0xac, 0x02, 0x87, 0xe3, 0x7a, 0xab, 0xce, 0x11, 0xed, 0x51, 0x97, + 0xc5, 0xf0, 0x33, 0xf5, 0x3b, 0x7e, 0x05, 0xda, 0x4d, 0x29, 0x23, 0xa7, + 0xca, 0x43, 0x0e, 0x72, 0xf0, 0x96, 0xe9, 0x95, 0x4a, 0x32, 0xb0, 0xc4, + 0xe5, 0x65, 0x73, 0xc3, 0x30, 0xea, 0xfb, 0x93, 0x04, 0x64, 0x48, 0x48, + 0x20, 0x1a, 0x8c, 0xde, 0xb0, 0x24, 0x7d, 0xd6, 0xe9, 0x5b, 0xb9, 0x0b, + 0x18, 0xb9, 0xc4, 0x4a, 0x81, 0xaa, 0xfb, 0x6b, 0x2f, 0xe6, 0x77, 0x00, + 0x17, 0xa8, 0x1f, 0x7f, 0x8b, 0xcd, 0xaf, 0xb5, 0xc1, 0x26, 0x99, 0x3f, + 0x74, 0xd9, 0x69, 0x4c, 0x4c, 0xe5, 0x8a, 0x51, 0x3b, 0x47, 0x18, 0x33, + 0x1a, 0xc5, 0xc3, 0xe1, 0xeb, 0xc7, 0x80, 0xa4, 0xb3, 0x5f, 0x22, 0x64, + 0xcc, 0x97, 0xcb, 0xdb, 0xe5, 0xc9, 0x09, 0x89, 0x65, 0xfd, 0x61, 0x76, + 0xc3, 0xf7, 0xfe, 0x7d, 0xe1, 0x70, 0x07, 0x9a, 0x17, 0x95, 0x08, 0x4d, + 0xec, 0xfb, 0x38, 0x61, 0x06, 0x1e, 0x96, 0x91, 0x19, 0x42, 0x88, 0xf1, + 0x45, 0x04, 0x69, 0x63, 0x1c, 0x99, 0xf8, 0x26, 0xf4, 0xfc, 0xf0, 0xeb, + 0x48, 0x06, 0x9d, 0xef, 0x46, 0x72, 0x41, 0xa9, 0xa5, 0xb8, 0x4a, 0xf0, + 0xd3, 0x82, 0x65, 0x88, 0x98, 0x40, 0x97, 0x4a, 0x95, 0x10, 0x52, 0xca, + 0x47, 0xec, 0x14, 0x75, 0x86, 0xd5, 0x7d, 0xf7, 0xda, 0xa5, 0x09, 0xc6, + 0x50, 0x02, 0x8f, 0xd7, 0x51, 0x42, 0x43, 0x60, 0x27, 0x67, 0xa0, 0xd6, + 0xd8, 0xcf, 0x58, 0xc5, 0x13, 0x27, 0xa2, 0x4e, 0x4f, 0xc3, 0xc2, 0x50, + 0xcb, 0x8d, 0x00, 0x53, 0x87, 0x5a, 0x6b, 0x4d, 0xb4, 0x07, 0x0b, 0x40, + 0xb3, 0xba, 0xc3, 0x14, 0xb8, 0x75, 0xda, 0x84, 0x50, 0x96, 0x12, 0xc6, + 0xd1, 0x00, 0xa5, 0xa3, 0x4c, 0x11, 0x45, 0x02, 0xc7, 0x2f, 0xe2, 0x8f, + 0xb7, 0xe9, 0xff, 0xe2, 0x48, 0x8b, 0x28, 0x1c, 0x38, 0x8c, 0x41, 0xc9, + 0xd0, 0xfa, 0x13, 0x4f, 0xfd, 0x6b, 0x72, 0xa5, 0x0e, 0xd7, 0x2f, 0x2b, + 0xee, 0x37, 0xe6, 0xb0, 0x41, 0x4d, 0x45, 0x83, 0x88, 0x6d, 0x14, 0x6d, + 0xa6, 0xb1, 0x59, 0x7d, 0x7e, 0xa7, 0x8d, 0x48, 0xc3, 0x4c, 0x80, 0x91, + 0xf0, 0x4d, 0xfc, 0xaf, 0xe6, 0xae, 0x9a, 0x24, 0xca, 0x73, 0xc4, 0x13, + 0xf8, 0x28, 0xd2, 0xbf, 0xdf, 0xc4, 0xd0, 0x4e, 0xf4, 0x3e, 0x2c, 0x60, + 0x6a, 0xd4, 0x6e, 0x44, 0x8a, 0xae, 0x09, 0x37, 0xb1, 0x98, 0xaf, 0x69, + 0xf0, 0xee, 0x6f, 0x0a, 0x55, 0x6d, 0x12, 0x7c, 0xf0, 0x08, 0x78, 0xd2, + 0x98, 0x7c, 0xdf, 0xd7, 0xa0, 0x0d, 0xf3, 0x52, 0x65, 0xf6, 0xb9, 0xfe, + 0xf3, 0x73, 0x4c, 0xe2, 0x3a, 0x27, 0x64, 0x00, 0x28, 0x54, 0x2d, 0x4a, + 0x59, 0x42, 0x43, 0xea, 0x26, 0xeb, 0x13, 0x2a, 0x5a, 0x9a, 0x35, 0xe9, + 0xe3, 0xe0, 0x3d, 0x84, 0xf0, 0x12, 0xbe, 0x84, 0x3f, 0x1c, 0xe6, 0x06, + 0xab, 0x30, 0x0d, 0xa3, 0xba, 0xe4, 0x24, 0xe0, 0x6f, 0x5c, 0xab, 0x43, + 0x9a, 0xf6, 0xf4, 0xd9, 0x74, 0x7e, 0x2c, 0x63, 0xf3, 0xd2, 0x17, 0x0b, + 0x57, 0xda, 0x1d, 0xd0, 0x47, 0x52, 0xc7, 0xc9, 0xb8, 0x14, 0x12, 0x23, + 0xc1, 0x23, 0x9b, 0x78, 0x51, 0x81, 0x7b, 0x66, 0x48, 0xbb, 0xc8, 0x7a, + 0x67, 0x84, 0x0a, 0xff, 0x82, 0xe9, 0x7e, 0xea, 0x5f, 0x5b, 0x94, 0xd6, + 0x24, 0x48, 0x3b, 0xa6, 0x25, 0x29, 0xd1, 0x92, 0x12, 0x9a, 0x5f, 0x84, + 0x3e, 0xb4, 0xe4, 0x3f, 0x15, 0xad, 0xe9, 0xec, 0xbc, 0x10, 0x7d, 0xc9, + 0xcd, 0xeb, 0x71, 0xd3, 0x79, 0x1a, 0xc2, 0xf5, 0x0d, 0x31, 0xac, 0x6a, + 0xac, 0xbc, 0x7f, 0x67, 0x43, 0x78, 0xc5, 0x23, 0x97, 0x56, 0x88, 0x3c, + 0xb0, 0x8e, 0x2c, 0x8a, 0x2b, 0x63, 0xfe, 0xb2, 0xaa, 0xb1, 0x71, 0x72, + 0x74, 0x41, 0xc3, 0x78, 0x0c, 0x5f, 0x92, 0x8d, 0x64, 0xe0, 0xf8, 0xde, + 0x09, 0x8f, 0xcd, 0x39, 0x45, 0x5a, 0x5d, 0x12, 0x6b, 0x26, 0xad, 0xfe, + 0xc0, 0x51, 0x1e, 0x00, 0xe9, 0x36, 0xf1, 0xb6, 0x74, 0x7b, 0x67, 0x6e, + 0xe2, 0xe4, 0xf4, 0x8e, 0x40, 0x87, 0xc6, 0x14, 0xcc, 0xa8, 0x25, 0x37, + 0x72, 0x0c, 0xc0, 0xf4, 0xff, 0xf4, 0x7d, 0xdc, 0xa8, 0xda, 0x68, 0xa5, + 0xbf, 0x04, 0xa3, 0x2c, 0x9f, 0xc7, 0x0a, 0x7c, 0x37, 0x86, 0xe7, 0x76, + 0x4e, 0x50, 0x79, 0xa5, 0xd1, 0x5f, 0x2e, 0x6f, 0x9a, 0x5c, 0x75, 0x73, + 0xd3, 0x7a, 0x10, 0x69, 0x45, 0xf1, 0x99, 0xca, 0x04, 0x24, 0x0a, 0x76, + 0xf5, 0xb9, 0xf7, 0xca, 0xf3, 0xfe, 0xde, 0x28, 0x70, 0x47, 0x3c, 0x35, + 0x17, 0x70, 0x21, 0x42, 0x32, 0x81, 0xfb, 0x3d, 0xc8, 0xf0, 0x35, 0xfe, + 0xe7, 0xee, 0x1b, 0x1e, 0xdd, 0xce, 0x19, 0xa2, 0x95, 0x95, 0x43, 0x2f, + 0xb2, 0x26, 0xcc, 0xbb, 0xb7, 0x8b, 0x8b, 0xff, 0x1c, 0xeb, 0x82, 0xa9, + 0x4f, 0x25, 0x58, 0xfa, 0x41, 0x22, 0x4a, 0xcb, 0x38, 0xc4, 0xff, 0x12, + 0x0d, 0xf7, 0x3b, 0xed, 0x0c, 0x7e, 0x29, 0xd3, 0x19, 0xe2, 0x2c, 0xff, + 0x8e, 0xbf, 0xe1, 0x1b, 0xc9, 0x6f, 0xac, 0x51, 0x97, 0x49, 0x68, 0x4d, + 0x20, 0x27, 0x3f, 0x11, 0xfe, 0x1e, 0x7f, 0xef, 0xda, 0x76, 0xba, 0xba, + 0xf2, 0xdb, 0x60, 0x36, 0x9a, 0xa3, 0x28, 0x89, 0xc8, 0x64, 0xb0, 0x90, + 0x79, 0xcb, 0x9d, 0x45, 0xcc, 0xdd, 0x6d, 0xf0, 0xd5, 0xb5, 0x8a, 0x64, + 0x51, 0x96, 0xcb, 0x12, 0x70, 0x0a, 0xca, 0x69, 0x34, 0x20, 0x43, 0x31, + 0x3c, 0xba, 0xb2, 0x80, 0xe1, 0xb2, 0x65, 0x79, 0x6f, 0x4e, 0x6e, 0x92, + 0x4b, 0xbf, 0x80, 0x2a, 0xb7, 0x97, 0x7f, 0xc9, 0xf5, 0xbc, 0xef, 0x1e, + 0x7f, 0xc9, 0xb6, 0x3d, 0x86, 0x4c, 0x89, 0x62, 0xac, 0x2b, 0xd0, 0x26, + 0x9d, 0xab, 0xeb, 0xfb, 0x5d, 0x4b, 0x6c, 0xe5, 0x58, 0x29, 0xb3, 0x4a, + 0x09, 0xed, 0x17, 0xf1, 0x00, 0xbb, 0x5c, 0x17, 0xc4, 0x56, 0x3b, 0xfc, + 0x13, 0x08, 0xc5, 0xcf, 0xc4, 0x14, 0x5f, 0xe2, 0xf8, 0xa5, 0xe2, 0xde, + 0x2f, 0x85, 0xde, 0xf7, 0xf7, 0x4d, 0xcd, 0x7b, 0xf2, 0xb6, 0x8b, 0x72, + 0x03, 0x6b, 0x2c, 0x7f, 0xde, 0x40, 0xf4, 0x76, 0x52, 0x2b, 0x61, 0x2d, + 0x72, 0xa2, 0x21, 0x0c, 0x1b, 0x44, 0x6c, 0x40, 0x04, 0xbc, 0x5e, 0xff, + 0xcb, 0xb6, 0x65, 0x99, 0xc6, 0xdb, 0xf7, 0x6f, 0xbc, 0x75, 0xd6, 0xcb, + 0x79, 0x6d, 0xd6, 0x94, 0xbd, 0xb7, 0x47, 0x89, 0xc6, 0xf6, 0xf0, 0xab, + 0x67, 0x60, 0x37, 0x32, 0x7d, 0x0f, 0x31, 0x08, 0xe2, 0x4e, 0x11, 0x0d, + 0x64, 0x1e, 0x66, 0xc6, 0xc6, 0xc5, 0x34, 0x56, 0xf8, 0xbf, 0x12, 0x83, + 0x7a, 0x75, 0xe0, 0x67, 0xae, 0x7b, 0x7e, 0xfb, 0xb6, 0x33, 0x38, 0xaa, + 0xea, 0x98, 0x9b, 0xfd, 0x36, 0x0d, 0x7e, 0x0f, 0xd4, 0xf9, 0x56, 0x6a, + 0xd5, 0x40, 0xb4, 0x38, 0xae, 0x6a, 0x7a, 0xc5, 0x40, 0x2c, 0x87, 0x72, + 0x80, 0x3e, 0x20, 0xf3, 0x48, 0xed, 0xbd, 0xb8, 0x13, 0xdf, 0xb7, 0xae, + 0x6a, 0xe6, 0x62, 0x6e, 0x73, 0x4c, 0xf0, 0x06, 0xba, 0x6c, 0xb2, 0xed, + 0xb6, 0x83, 0x32, 0x77, 0x63, 0xff, 0x84, 0x7e, 0xca, 0x91, 0xd7, 0x14, + 0xc7, 0xae, 0x12, 0x91, 0x49, 0xb6, 0x32, 0x92, 0x97, 0x5e, 0x39, 0x5a, + 0x71, 0x86, 0xdc, 0x92, 0xbb, 0x47, 0x8c, 0x3e, 0x24, 0xfc, 0x05, 0xf2, + 0x38, 0x7b, 0xdd, 0x4c, 0xec, 0x52, 0x8f, 0x80, 0x57, 0xd1, 0x52, 0x6b, + 0x0a, 0xb9, 0x81, 0xfd, 0x6b, 0xd2, 0x43, 0x58, 0x2c, 0x2a, 0xb8, 0x3d, + 0x66, 0xb0, 0x61, 0x9b, 0x3e, 0x7a, 0xc9, 0x38, 0x62, 0xc8, 0x6b, 0x4f, + 0xa0, 0xe3, 0xed, 0x13, 0x7b, 0xd6, 0x7c, 0xbb, 0x35, 0xaf, 0x81, 0xed, + 0x88, 0x91, 0x35, 0x2a, 0x5c, 0x5f, 0x47, 0xa7, 0x2f, 0x6f, 0xf5, 0x23, + 0x38, 0x20, 0x87, 0x5f, 0x65, 0x81, 0xfa, 0x44, 0x88, 0xd4, 0x96, 0x5e, + 0xc2, 0x84, 0xca, 0x39, 0x20, 0x28, 0x93, 0x94, 0x06, 0x4f, 0xc5, 0x41, + 0xff, 0x4e, 0x9d, 0xe6, 0xdb, 0x29, 0x50, 0xaf, 0x46, 0x49, 0x00, 0x24, + 0x04, 0xf2, 0xcd, 0x13, 0x84, 0x82, 0xa3, 0xc9, 0x21, 0x36, 0x26, 0x6f, + 0xad, 0xff, 0xb7, 0x6f, 0xf2, 0x6e, 0x15, 0x83, 0xa8, 0xb5, 0x2e, 0x89, + 0xfb, 0xca, 0xfe, 0xfa, 0x80, 0x2d, 0xc7, 0x43, 0xfe, 0xbe, 0xd5, 0x1b, + 0x8a, 0x4d, 0x08, 0xed, 0x55, 0x2c, 0x83, 0xc1, 0xe5, 0x7b, 0xc5, 0x1b, + 0x5d, 0xdd, 0xb7, 0x53, 0xf1, 0x3b, 0xd7, 0x7d, 0xed, 0xe6, 0x11, 0xbe, + 0x75, 0xb5, 0xb4, 0x22, 0x42, 0x53, 0x10, 0x81, 0x34, 0x7b, 0x81, 0x3c, + 0x94, 0x13, 0xc7, 0x2c, 0xed, 0xa1, 0xa3, 0x0a, 0x15, 0x7a, 0xb0, 0x26, + 0x69, 0xe0, 0x45, 0x19, 0xb1, 0x9c, 0x88, 0x9d, 0xe1, 0x61, 0x20, 0xee, + 0x3f, 0xe6, 0xa3, 0x8c, 0x61, 0x85, 0xa7, 0x28, 0xd2, 0x09, 0x7b, 0x69, + 0xb0, 0x95, 0x37, 0xd8, 0x96, 0x3c, 0xcc, 0x2c, 0x90, 0x83, 0x28, 0x8c, + 0x8b, 0x3b, 0xfe, 0xb7, 0xb5, 0x19, 0x15, 0x5e, 0xcf, 0x5f, 0xaf, 0x8c, + 0x76, 0x95, 0x02, 0x97, 0xe9, 0xac, 0x02, 0xb2, 0xee, 0x82, 0xe7, 0x16, + 0xca, 0x5b, 0x08, 0x22, 0xc6, 0x4e, 0xd2, 0xab, 0x10, 0x0f, 0x68, 0x5c, + 0xc2, 0x3d, 0x16, 0xf8, 0x74, 0x11, 0xd6, 0x4c, 0x65, 0xe1, 0x26, 0x9a, + 0x2d, 0xb0, 0x20, 0x66, 0xd2, 0xed, 0x60, 0xf4, 0xd1, 0xc2, 0x7d, 0x44, + 0xd7, 0xbd, 0x45, 0x36, 0x7b, 0xdc, 0xef, 0x87, 0xba, 0xbe, 0x16, 0x40, + 0x13, 0xa3, 0x3a, 0x6e, 0x12, 0xc0, 0xa3, 0xe2, 0x01, 0xfa, 0xde, 0xe5, + 0x75, 0xb9, 0x8a, 0x12, 0x19, 0x44, 0x8a, 0x12, 0xc9, 0x51, 0x84, 0xa5, + 0xcb, 0xc0, 0xec, 0xee, 0xd3, 0xaf, 0x34, 0xa4, 0x91, 0x34, 0x52, 0x01, + 0xeb, 0x00, 0x8e, 0x62, 0x71, 0x6f, 0x32, 0x80, 0x3e, 0xdc, 0x17, 0x3b, + 0x7d, 0x4b, 0x50, 0x4e, 0x81, 0x90, 0x98, 0xde, 0x4c, 0xc6, 0x90, 0x09, + 0x6e, 0xbb, 0x4e, 0x1f, 0x87, 0x0b, 0x2e, 0x1f, 0xed, 0x42, 0x0e, 0x2d, + 0x04, 0x24, 0xb0, 0x40, 0xc3, 0xde, 0x12, 0x24, 0x15, 0x2a, 0x68, 0x09, + 0xf8, 0xf8, 0x71, 0xf1, 0x85, 0x16, 0x12, 0xa4, 0x58, 0xc1, 0xa6, 0x19, + 0x1a, 0x68, 0x9d, 0xa1, 0x94, 0x32, 0x08, 0x11, 0x51, 0x14, 0xb1, 0xa4, + 0x24, 0x0c, 0xdd, 0x2c, 0x04, 0x20, 0x19, 0x72, 0x35, 0x60, 0xda, 0x79, + 0x84, 0x11, 0x05, 0xf0, 0xe6, 0x52, 0xf8, 0x9f, 0x3a, 0xd0, 0x9e, 0xe1, + 0xe4, 0x50, 0x99, 0x8c, 0xb4, 0xba, 0x33, 0xc7, 0xc0, 0x33, 0x00, 0x76, + 0x0e, 0x10, 0x19, 0x31, 0x23, 0x8d, 0x34, 0x96, 0xdf, 0xd8, 0x6b, 0x24, + 0x65, 0x3f, 0x4d, 0x1c, 0x95, 0x5a, 0x79, 0xc2, 0xe5, 0xb2, 0x36, 0xc5, + 0xa6, 0x8b, 0x28, 0x03, 0x95, 0xda, 0x51, 0xa3, 0x96, 0x00, 0xf9, 0xe0, + 0xbc, 0x7e, 0xc5, 0xab, 0x8a, 0x64, 0xa5, 0x7c, 0xf3, 0x65, 0x98, 0xc1, + 0x92, 0x4b, 0x9f, 0xa6, 0x87, 0x8a, 0x35, 0xa5, 0x35, 0x14, 0x93, 0x26, + 0x05, 0xfe, 0xec, 0x4b, 0xdc, 0xea, 0xd6, 0xb6, 0x54, 0x23, 0x2c, 0x24, + 0x72, 0xfe, 0x71, 0x90, 0x31, 0xfd, 0x00, 0x84, 0xc2, 0xc8, 0x63, 0x8a, + 0x88, 0xcb, 0x27, 0xf0, 0x7e, 0x05, 0x1e, 0xf3, 0xb4, 0xfa, 0x7e, 0xe1, + 0x77, 0x67, 0xe3, 0xa6, 0x28, 0x11, 0x48, 0xe3, 0xbd, 0x00, 0x25, 0x7b, + 0x30, 0xcb, 0xec, 0x27, 0xc1, 0x61, 0x28, 0x1c, 0x56, 0x66, 0x12, 0x10, + 0xba, 0x08, 0x03, 0x91, 0x43, 0xd3, 0x6d, 0x2a, 0xcd, 0x2a, 0x58, 0x64, + 0x68, 0x24, 0x4f, 0xc7, 0x47, 0xf1, 0x7c, 0x69, 0x9a, 0x14, 0x64, 0x5e, + 0x53, 0xbd, 0x74, 0x85, 0xa9, 0x29, 0xa6, 0x7e, 0xae, 0x39, 0x35, 0x40, + 0x8c, 0xe5, 0x59, 0x30, 0x5c, 0x7f, 0x46, 0xa1, 0x37, 0x29, 0x04, 0x07, + 0xc5, 0xf1, 0xcf, 0x30, 0x0f, 0x89, 0x87, 0x31, 0x4f, 0x33, 0xa2, 0x04, + 0xb2, 0x9b, 0x30, 0x55, 0x14, 0xb1, 0x82, 0xac, 0x3e, 0xb8, 0x1a, 0xb9, + 0xca, 0xa5, 0xe9, 0x4b, 0x28, 0x77, 0x3a, 0x63, 0xe8, 0xad, 0xbe, 0x98, + 0xd2, 0x2d, 0x32, 0xc6, 0x30, 0x82, 0x0e, 0xc1, 0x8f, 0xb9, 0x70, 0x13, + 0xca, 0x42, 0xd8, 0x07, 0x0f, 0x23, 0xd9, 0x5a, 0xed, 0x92, 0x9b, 0x38, + 0xc5, 0xa0, 0x65, 0xb1, 0x08, 0x90, 0xcb, 0x61, 0x2c, 0x05, 0x1f, 0xa6, + 0x2a, 0x55, 0x24, 0x2f, 0x40, 0xc2, 0x4f, 0x5c, 0xb3, 0xcc, 0xd5, 0xfb, + 0x57, 0xda, 0x92, 0x08, 0xed, 0x0e, 0x56, 0x4e, 0x55, 0x6d, 0xfc, 0xc3, + 0x66, 0x95, 0x9c, 0x81, 0x27, 0xe5, 0x6c, 0x9d, 0x42, 0x94, 0x38, 0x68, + 0x48, 0x22, 0x58, 0x48, 0x86, 0xfa, 0x83, 0x66, 0xb6, 0xbd, 0xca, 0x0d, + 0x0c, 0x72, 0x68, 0xd6, 0x07, 0xe4, 0xcc, 0x84, 0x76, 0x85, 0x0f, 0x9c, + 0x7a, 0x2d, 0x6a, 0xed, 0x3e, 0x34, 0xda, 0x2b, 0xf2, 0xf4, 0x67, 0xa6, + 0x00, 0xd1, 0x64, 0x5e, 0x45, 0x12, 0x82, 0x2d, 0x95, 0x2f, 0xac, 0x58, + 0xf9, 0xea, 0x65, 0x4b, 0x27, 0xdb, 0x3d, 0xdd, 0x8d, 0x8a, 0x5e, 0xda, + 0xb5, 0xd6, 0x05, 0x88, 0x64, 0x1c, 0x84, 0x7f, 0x69, 0x12, 0x11, 0x2f, + 0x80, 0x7d, 0x12, 0xbb, 0xaa, 0x50, 0x71, 0x9b, 0x4c, 0xba, 0xdf, 0xaa, + 0x5e, 0xf6, 0x34, 0x1f, 0xef, 0xa5, 0x4f, 0xfa, 0x95, 0x34, 0xef, 0x84, + 0xed, 0xd9, 0x2f, 0x1c, 0xcd, 0xc6, 0x5e, 0x90, 0xfb, 0x13, 0xf3, 0xf0, + 0xfa, 0x3f, 0x7f, 0x77, 0xca, 0x76, 0x12, 0x9a, 0x3c, 0x92, 0x86, 0xed, + 0xcb, 0xe0, 0x22, 0x84, 0x86, 0x5d, 0x02, 0xf2, 0xfa, 0x37, 0x83, 0x64, + 0xad, 0x1f, 0x0d, 0xdb, 0x95, 0x8f, 0x3d, 0x70, 0xbe, 0xff, 0xfb, 0x5d, + 0xfd, 0xbe, 0x1b, 0x92, 0xcc, 0xb6, 0x95, 0xef, 0x63, 0x8a, 0x72, 0xc8, + 0x4e, 0x88, 0xf9, 0xa3, 0xb9, 0x07, 0x9c, 0xb3, 0x3f, 0xad, 0xca, 0x84, + 0xb2, 0x06, 0x42, 0x28, 0xb7, 0xc4, 0xf1, 0x07, 0x9c, 0xcf, 0x8e, 0xe7, + 0xd9, 0xc9, 0xa8, 0xf8, 0x9e, 0x1b, 0x96, 0x48, 0xf6, 0xa9, 0x55, 0x5d, + 0x6d, 0xff, 0xff, 0xed, 0x49, 0xc8, 0x82, 0x8e, 0x33, 0x09, 0x78, 0x68, + 0x44, 0x2c, 0xd9, 0xbf, 0xd4, 0x22, 0x03, 0xad, 0x38, 0x01, 0x7b, 0xeb, + 0x1b, 0x8b, 0x6c, 0x94, 0xda, 0x81, 0x6e, 0xd8, 0x6a, 0x26, 0x02, 0x28, + 0xa3, 0x2f, 0xa8, 0x0f, 0xef, 0x0d, 0xbc, 0xb9, 0xa2, 0x57, 0xb2, 0x72, + 0x28, 0x81, 0x9b, 0x5d, 0x54, 0x86, 0x7b, 0xf9, 0xed, 0x13, 0xe1, 0x8c, + 0xa4, 0x32, 0x35, 0xe4, 0x8e, 0x01, 0xe1, 0xdd, 0x71, 0xc5, 0xfe, 0x50, + 0x53, 0xdf, 0xef, 0x6b, 0x69, 0x81, 0x35, 0x5a, 0x65, 0x16, 0x87, 0xce, + 0x42, 0x86, 0x32, 0xd4, 0x48, 0x97, 0x3f, 0x10, 0x39, 0xa3, 0xf6, 0x03, + 0xc1, 0xb2, 0xe7, 0xe3, 0xed, 0xae, 0x92, 0x06, 0xca, 0xd0, 0xd0, 0x96, + 0x51, 0xd2, 0x4b, 0x9f, 0xef, 0x5a, 0xdc, 0x66, 0x2b, 0x56, 0xa3, 0x5f, + 0xe3, 0x4b, 0x67, 0x39, 0x09, 0x6f, 0x27, 0x68, 0xd0, 0x75, 0x66, 0xf3, + 0x5c, 0x7c, 0x99, 0x97, 0xbe, 0x95, 0xb7, 0x22, 0xde, 0x54, 0x77, 0x8e, + 0x97, 0x05, 0x21, 0xa4, 0x00, 0x9a, 0x1d, 0xcc, 0xf5, 0x5e, 0xc6, 0xcf, + 0x48, 0x84, 0xab, 0x80, 0xe4, 0x3d, 0x25, 0xc0, 0x88, 0xc7, 0x62, 0xce, + 0x40, 0x32, 0x45, 0xc4, 0x89, 0x44, 0x64, 0xeb, 0x20, 0xe7, 0xba, 0x5a, + 0x97, 0xe7, 0xb1, 0x1a, 0xa6, 0xeb, 0xe2, 0x4f, 0x30, 0x03, 0x60, 0xc2, + 0x84, 0xcc, 0xf0, 0x0a, 0xa8, 0xb0, 0x97, 0x22, 0x48, 0x78, 0x40, 0x46, + 0x9f, 0xc4, 0x83, 0xfe, 0x62, 0x7b, 0xfe, 0xbb, 0xfb, 0x3d, 0x36, 0x2a, + 0xf5, 0xde, 0xb3, 0xbd, 0xf9, 0x4f, 0xcb, 0x1e, 0xbf, 0xcd, 0xe0, 0xef, + 0x3f, 0x34, 0x9b, 0xf3, 0x96, 0xd1, 0x30, 0x84, 0x69, 0x8d, 0x00, 0xf3, + 0x77, 0x1e, 0x06, 0x66, 0x09, 0x3d, 0xd2, 0xeb, 0x76, 0x2f, 0x96, 0xba, + 0x56, 0x73, 0x18, 0x6b, 0x5b, 0x89, 0xef, 0x1e, 0x9f, 0x4e, 0x5c, 0x62, + 0x73, 0xa5, 0x71, 0x7f, 0xa6, 0xb6, 0x27, 0x05, 0x89, 0xa6, 0x34, 0x6f, + 0xb8, 0x6a, 0x5c, 0xb3, 0x72, 0xe7, 0xc1, 0x2a, 0x9e, 0xc1, 0x3f, 0xbf, + 0x7f, 0x71, 0x7f, 0x6f, 0x3b, 0xfd, 0xf7, 0xbf, 0xb1, 0xfd, 0xaa, 0xdf, + 0x4b, 0x7f, 0x73, 0x6d, 0x7a, 0x2e, 0x2f, 0x95, 0xb6, 0xe6, 0xe5, 0xbc, + 0x18, 0x58, 0xcc, 0x4c, 0x3b, 0x49, 0x10, 0x88, 0x3e, 0x20, 0xe6, 0xfe, + 0x33, 0x5c, 0xc2, 0xc7, 0x6e, 0xbe, 0x7a, 0xbb, 0xaa, 0xd6, 0xd7, 0x13, + 0x81, 0xfb, 0xfd, 0xfe, 0x76, 0xfa, 0x26, 0xb9, 0x01, 0x87, 0x3d, 0x8f, + 0x5d, 0xe2, 0xa1, 0xc6, 0xa9, 0x2a, 0x26, 0xf7, 0x8f, 0x04, 0x23, 0x0c, + 0xd5, 0x49, 0x36, 0x72, 0x25, 0x74, 0x12, 0x66, 0xee, 0x7b, 0xe6, 0x2f, + 0xbf, 0x1f, 0xdf, 0xcc, 0xd2, 0x7d, 0xfd, 0xd5, 0x0b, 0x2d, 0xf7, 0xe3, + 0x37, 0x5b, 0xf7, 0xe3, 0xf7, 0xe5, 0x09, 0xfe, 0x7b, 0xca, 0xc7, 0x68, + 0xa7, 0xcb, 0x9d, 0xec, 0x38, 0xe4, 0x5e, 0xec, 0x02, 0x87, 0xd4, 0xc3, + 0xd9, 0x51, 0x5f, 0x3b, 0xef, 0xed, 0x78, 0x14, 0xe9, 0xde, 0xb7, 0xff, + 0x4f, 0x6d, 0x5d, 0x1c, 0x36, 0xed, 0xe5, 0x57, 0xe5, 0xd8, 0x39, 0x87, + 0x8b, 0x8e, 0xc7, 0x57, 0x97, 0xdd, 0x8a, 0x76, 0x40, 0xba, 0x23, 0xee, + 0x4d, 0x7c, 0x65, 0x72, 0xc8, 0x9d, 0x2f, 0xee, 0x36, 0xd4, 0xfb, 0xd6, + 0xff, 0x49, 0x7a, 0x7f, 0x93, 0xfa, 0x7b, 0x3f, 0x5a, 0x79, 0xf9, 0x85, + 0xd6, 0xeb, 0x7b, 0xf5, 0xd1, 0x64, 0x2e, 0x72, 0xf0, 0x98, 0x36, 0x03, + 0xed, 0xfe, 0xc0, 0x4e, 0x06, 0xec, 0x09, 0x8b, 0x83, 0x8d, 0x7f, 0x7b, + 0xa6, 0x75, 0xd7, 0x6e, 0xf3, 0xa8, 0xdb, 0xd2, 0xb6, 0x5b, 0xf8, 0xc5, + 0xe3, 0x86, 0xd1, 0x5a, 0xf9, 0xe7, 0x4e, 0x7a, 0x69, 0xb1, 0x65, 0xc3, + 0xc9, 0xb0, 0xfb, 0xbd, 0xea, 0xb7, 0x05, 0xd2, 0x73, 0x9a, 0x39, 0xdc, + 0xde, 0x2a, 0xef, 0xdf, 0x8c, 0xc3, 0xcd, 0xdf, 0x85, 0xf4, 0x89, 0xae, + 0xbc, 0xeb, 0xbf, 0xe7, 0xad, 0xe6, 0x9c, 0x6a, 0x60, 0xef, 0x5a, 0xff, + 0x4e, 0x95, 0xa6, 0x96, 0x2f, 0x3f, 0x97, 0x2c, 0x4d, 0x96, 0xd6, 0xe7, + 0xf4, 0x11, 0xe9, 0x5d, 0x5e, 0x28, 0x9c, 0x75, 0x55, 0xcc, 0xef, 0x65, + 0x6a, 0x2b, 0x29, 0xb7, 0xff, 0x43, 0x9d, 0xcb, 0x91, 0x60, 0x58, 0x50, + 0x79, 0xef, 0xb4, 0xd8, 0x7a, 0x1d, 0x94, 0x2a, 0xe4, 0x54, 0x74, 0x4c, + 0xe5, 0x8c, 0xeb, 0xfb, 0x13, 0xfd, 0x4a, 0xc3, 0xee, 0x3f, 0x71, 0x33, + 0xf9, 0xba, 0xa5, 0x17, 0xde, 0xcf, 0x45, 0x28, 0x75, 0xfe, 0xb8, 0x35, + 0xa5, 0x79, 0x9b, 0x54, 0x37, 0xc8, 0xa7, 0x8b, 0x0d, 0x56, 0x92, 0x3f, + 0xd8, 0xc8, 0x68, 0xf4, 0xe2, 0x1c, 0xbc, 0x4a, 0x5a, 0x9d, 0xea, 0x85, + 0x57, 0xa1, 0x45, 0x58, 0xb9, 0xc8, 0x23, 0x7a, 0xc5, 0xfe, 0x2f, 0xbd, + 0x9d, 0xe9, 0xbf, 0x19, 0x2a, 0x14, 0x0d, 0x78, 0xa4, 0x01, 0x03, 0x0e, + 0x97, 0x91, 0x0c, 0x5c, 0x6b, 0x9d, 0x29, 0x50, 0x5e, 0xfc, 0x18, 0x51, + 0x91, 0x9b, 0x03, 0x41, 0x1c, 0xb9, 0xe4, 0x42, 0x59, 0xcf, 0x3b, 0xd6, + 0xe9, 0xe3, 0x19, 0xc0, 0x82, 0x28, 0x60, 0x3f, 0x1e, 0x32, 0xe0, 0x05, + 0xca, 0x07, 0x5c, 0x8e, 0x37, 0xb0, 0xcb, 0x0d, 0xf1, 0x21, 0x91, 0x96, + 0x41, 0xb4, 0x67, 0x56, 0xab, 0x7d, 0x75, 0x02, 0x86, 0x83, 0xbf, 0x39, + 0x7b, 0x9d, 0x0c, 0x7c, 0xb0, 0x7d, 0x38, 0x4f, 0x9c, 0xf2, 0xe6, 0x52, + 0xdd, 0x2f, 0xc4, 0x3d, 0x75, 0x5e, 0xbb, 0x53, 0x7a, 0x4f, 0xa6, 0xf5, + 0x3a, 0xdb, 0xa1, 0xc0, 0x02, 0x62, 0xf2, 0xe6, 0x90, 0xca, 0x92, 0x3e, + 0x9c, 0x9f, 0x72, 0x0b, 0x7f, 0x63, 0xa7, 0x5f, 0x07, 0x2a, 0x62, 0xa9, + 0xe6, 0x22, 0x25, 0xb7, 0x96, 0xad, 0x51, 0x0b, 0xc6, 0x47, 0x9d, 0x76, + 0xbc, 0x1f, 0x83, 0x2c, 0x65, 0xd9, 0x15, 0xfb, 0x7c, 0x85, 0x6a, 0xd6, + 0xa6, 0xc8, 0x04, 0x5c, 0x25, 0xa1, 0x96, 0x91, 0xfa, 0x31, 0xaf, 0xd2, + 0x0d, 0xdd, 0x7f, 0x8a, 0x09, 0x4f, 0xd9, 0x38, 0x3f, 0xb6, 0x1e, 0x52, + 0xf3, 0x8a, 0x27, 0x25, 0xe2, 0x93, 0x08, 0x7c, 0x69, 0xa4, 0x39, 0xd6, + 0x59, 0x07, 0x0c, 0xd2, 0x91, 0x9c, 0xf3, 0x04, 0xf7, 0x7b, 0x99, 0x72, + 0x2c, 0x73, 0x7b, 0x6d, 0xe7, 0x7b, 0x1a, 0x8b, 0x71, 0x8e, 0x8c, 0xf2, + 0xea, 0x3a, 0x52, 0xee, 0x44, 0x91, 0xf8, 0x26, 0xfc, 0xc2, 0xde, 0x9b, + 0xd9, 0x6c, 0x3c, 0xc4, 0xaf, 0x75, 0x64, 0x3c, 0xa4, 0x27, 0xdc, 0xf8, + 0x5f, 0x91, 0x28, 0x87, 0xaa, 0xce, 0xea, 0x6e, 0x5c, 0xa2, 0x00, 0x04, + 0xcb, 0x4c, 0xe5, 0x99, 0xca, 0x00, 0x27, 0x34, 0x72, 0x5e, 0x0b, 0x4e, + 0x03, 0xbd, 0x7d, 0x10, 0x11, 0x90, 0xca, 0x8c, 0xbf, 0x04, 0xbe, 0xb2, + 0x5b, 0x65, 0xf1, 0x22, 0x83, 0xd1, 0x84, 0x3d, 0x16, 0x26, 0x30, 0xf1, + 0x03, 0xe6, 0x64, 0xa8, 0xc8, 0x20, 0x3c, 0x3b, 0x01, 0x72, 0xbc, 0xea, + 0xaa, 0x94, 0xf2, 0x80, 0x1d, 0x93, 0xc3, 0x3c, 0xbf, 0x4f, 0xce, 0x48, + 0x8f, 0xb5, 0x38, 0x83, 0x5c, 0x4d, 0x7f, 0xd6, 0x68, 0x70, 0x0c, 0x90, + 0x8c, 0x5d, 0x2b, 0xc2, 0x60, 0x51, 0xad, 0xfb, 0xfb, 0x22, 0x97, 0x02, + 0xe6, 0xda, 0x4c, 0x7c, 0x46, 0xfe, 0x36, 0xec, 0x8b, 0x9a, 0x09, 0x48, + 0x7d, 0x13, 0x2e, 0xd7, 0x1b, 0x3f, 0xcb, 0xe9, 0xa5, 0x90, 0xc4, 0x30, + 0x0c, 0x92, 0x23, 0x22, 0x89, 0x91, 0x62, 0x73, 0xb0, 0x8f, 0x55, 0xd2, + 0x9e, 0x1c, 0x3a, 0x22, 0x57, 0x87, 0xd9, 0x6e, 0x47, 0x93, 0xdd, 0xfd, + 0x53, 0xa0, 0x5e, 0x40, 0x92, 0x04, 0x54, 0x57, 0x3a, 0x69, 0x45, 0x7f, + 0xe7, 0x8d, 0x03, 0x8b, 0xff, 0xe2, 0x76, 0x13, 0xc1, 0x22, 0x2d, 0xf3, + 0xa9, 0x8b, 0xb9, 0x63, 0x33, 0x56, 0xa3, 0x9f, 0x02, 0xf5, 0x3d, 0x6c, + 0x89, 0xe3, 0xc9, 0x88, 0xc3, 0xa3, 0xf0, 0x5e, 0x05, 0xcd, 0x22, 0xeb, + 0xe1, 0x0c, 0x36, 0x2c, 0xb6, 0x7b, 0x40, 0x30, 0xf3, 0xab, 0x2f, 0xe0, + 0x4f, 0x03, 0x97, 0x2b, 0xd9, 0xfe, 0xfe, 0x23, 0xa7, 0x9f, 0x05, 0xdc, + 0x66, 0x82, 0xd2, 0x54, 0x6d, 0x87, 0xfa, 0x0c, 0x8e, 0x48, 0x25, 0xde, + 0xb0, 0x13, 0x77, 0x71, 0x55, 0x1e, 0x89, 0x63, 0x8d, 0xdb, 0x8a, 0x1c, + 0x31, 0x0d, 0xa2, 0xfa, 0xa0, 0x5c, 0x50, 0x34, 0x11, 0x22, 0x61, 0x1e, + 0xe0, 0x55, 0xfe, 0xd7, 0x5a, 0x5c, 0x91, 0x2b, 0xaf, 0x65, 0x91, 0x8c, + 0xe7, 0x1c, 0x34, 0x88, 0x22, 0x63, 0x2c, 0x56, 0x70, 0x4e, 0x15, 0x02, + 0x9b, 0x52, 0xff, 0x22, 0x14, 0xff, 0xb3, 0x05, 0x6e, 0xb7, 0xb6, 0x41, + 0x11, 0x21, 0x44, 0xe4, 0xf6, 0x90, 0xf0, 0x4d, 0x79, 0xf3, 0x34, 0x32, + 0xf2, 0x33, 0xb4, 0x94, 0x69, 0x49, 0xeb, 0xd3, 0x43, 0x7b, 0x07, 0x60, + 0xd1, 0xdc, 0x81, 0x43, 0x1a, 0x68, 0x1c, 0x9f, 0x64, 0xe3, 0x1c, 0x8d, + 0xaf, 0x40, 0x52, 0xd5, 0x28, 0x26, 0x69, 0x9c, 0x9a, 0x26, 0x80, 0x4e, + 0xc8, 0x12, 0x24, 0xeb, 0x56, 0x54, 0xe9, 0xb5, 0x2a, 0x0c, 0x44, 0xd2, + 0xd2, 0xe7, 0x56, 0xab, 0x97, 0x16, 0xac, 0x18, 0x41, 0x28, 0x4e, 0x11, + 0x46, 0x03, 0x2c, 0x79, 0x8c, 0x3f, 0xcf, 0x77, 0x96, 0x84, 0xc9, 0x03, + 0x26, 0xee, 0x7d, 0x3e, 0x15, 0xb6, 0x6b, 0x1d, 0x90, 0xdd, 0x87, 0x29, + 0x88, 0x06, 0x69, 0x19, 0x8c, 0x27, 0xef, 0x9d, 0x1a, 0x9f, 0xca, 0x12, + 0xff, 0x70, 0xee, 0x16, 0x10, 0x71, 0x95, 0x2a, 0x19, 0x79, 0x54, 0x3e, + 0x8b, 0xa7, 0x49, 0xc4, 0xe8, 0x4f, 0x2a, 0xac, 0xe0, 0x04, 0x66, 0x28, + 0xcf, 0x2a, 0x87, 0x64, 0x3e, 0x5d, 0x04, 0x3e, 0xc4, 0x89, 0x06, 0xc9, + 0x64, 0x98, 0xa0, 0xe7, 0x07, 0x6f, 0x05, 0xb4, 0xfb, 0x66, 0x9e, 0x33, + 0xb3, 0xbc, 0xe3, 0x10, 0x86, 0xa4, 0x10, 0xc9, 0xfd, 0x89, 0x97, 0x13, + 0x9e, 0x74, 0x49, 0x61, 0x29, 0xca, 0x9b, 0x98, 0x1a, 0x10, 0x84, 0x89, + 0xac, 0x02, 0xa3, 0xbf, 0xf2, 0x5f, 0xff, 0x8a, 0xfc, 0xf9, 0xab, 0xd6, + 0x90, 0xe5, 0xe0, 0x58, 0x2f, 0xd1, 0xde, 0x44, 0xc0, 0x5a, 0x67, 0x52, + 0x63, 0x28, 0x0a, 0x04, 0x63, 0xcf, 0xc1, 0x21, 0x38, 0xe9, 0x8b, 0xaf, + 0x2e, 0x4e, 0x40, 0x81, 0xa0, 0x9a, 0x1b, 0x69, 0x3f, 0x67, 0x07, 0x28, + 0x8c, 0x24, 0x24, 0x68, 0x63, 0x12, 0xee, 0xce, 0xdf, 0x8b, 0xeb, 0x4d, + 0x45, 0x07, 0xe7, 0xea, 0x49, 0xbb, 0xd1, 0x36, 0x6e, 0xdd, 0xd7, 0xe0, + 0xaf, 0x12, 0xf4, 0x08, 0x48, 0x9b, 0xd4, 0x26, 0x19, 0x6a, 0x5e, 0x7b, + 0xce, 0xd7, 0xde, 0xdd, 0x6a, 0x1f, 0xc1, 0x9b, 0xbd, 0x13, 0xb6, 0x1d, + 0x84, 0x15, 0x93, 0x3c, 0xf4, 0xf0, 0x06, 0xfa, 0xcd, 0xce, 0x89, 0x78, + 0x76, 0xe7, 0x23, 0x72, 0xe7, 0xf1, 0x3e, 0x27, 0x86, 0x54, 0x75, 0xec, + 0xef, 0x9e, 0x7b, 0xf2, 0x75, 0x57, 0x46, 0xc4, 0x2b, 0xf0, 0x55, 0x6c, + 0x95, 0x71, 0xc4, 0xf7, 0xd6, 0x32, 0xee, 0xd9, 0xa5, 0x8c, 0x6d, 0xce, + 0x40, 0x25, 0xc9, 0x01, 0x80, 0x7d, 0x75, 0xbf, 0x8a, 0xeb, 0xbc, 0x48, + 0xe7, 0xa7, 0x2e, 0x58, 0x06, 0x2c, 0xd5, 0xee, 0x20, 0x90, 0x22, 0xa8, + 0x4a, 0x41, 0x1e, 0xe7, 0x62, 0x9b, 0x13, 0x28, 0x02, 0x4d, 0xd6, 0xd0, + 0xb1, 0x80, 0x96, 0x39, 0xa3, 0x4c, 0xa4, 0x7b, 0x83, 0xf7, 0x78, 0x9f, + 0xbe, 0x0a, 0xf9, 0x98, 0xcb, 0x17, 0x7d, 0x46, 0xe4, 0x10, 0xbd, 0xa6, + 0x89, 0xca, 0x00, 0x98, 0xd0, 0x2f, 0xaa, 0x84, 0x09, 0xc2, 0xac, 0xc5, + 0xd6, 0xe9, 0x91, 0x1b, 0x5e, 0x49, 0x52, 0x73, 0x15, 0xf5, 0x6b, 0xf0, + 0xdb, 0xd4, 0x32, 0x8d, 0x34, 0xb8, 0x5c, 0x25, 0xe4, 0x21, 0x7a, 0x7c, + 0x44, 0x2e, 0x54, 0xe3, 0x5d, 0xf2, 0x59, 0xfd, 0x63, 0x6b, 0xb6, 0x2f, + 0x3b, 0xdb, 0xb3, 0x39, 0x94, 0xe5, 0x26, 0x26, 0x79, 0x5a, 0x0c, 0x26, + 0x12, 0xfc, 0x41, 0x57, 0x89, 0x63, 0x11, 0x0b, 0xc6, 0x46, 0x57, 0xa3, + 0xb2, 0xa5, 0x2a, 0x5d, 0xf6, 0xfd, 0x7c, 0x73, 0xe2, 0xaf, 0x6f, 0x5b, + 0xa4, 0xb3, 0x05, 0x1c, 0x7d, 0xc1, 0x89, 0xfa, 0xcd, 0x03, 0x29, 0xa0, + 0x25, 0x18, 0xcd, 0xe1, 0xf1, 0xee, 0x5a, 0x21, 0xbf, 0x4a, 0xb8, 0x4c, + 0x9c, 0x87, 0x21, 0x09, 0x19, 0xe4, 0xa5, 0xe2, 0x03, 0x50, 0x31, 0x34, + 0x7c, 0x49, 0xbf, 0xe6, 0x56, 0x6c, 0xb6, 0xdf, 0x4e, 0xa6, 0x34, 0xd9, + 0xd8, 0x90, 0x50, 0x26, 0x54, 0x11, 0x14, 0x08, 0x28, 0x1f, 0x05, 0x1b, + 0xa6, 0x5d, 0x39, 0x42, 0x77, 0xb6, 0xc7, 0xc4, 0xfa, 0xb1, 0x43, 0x0a, + 0x93, 0x86, 0xf9, 0xe0, 0xfe, 0xa9, 0x65, 0x99, 0xfe, 0xeb, 0x93, 0xe3, + 0x61, 0xb2, 0x2b, 0x6c, 0xde, 0xd6, 0xc6, 0x02, 0xc5, 0xc1, 0x91, 0x53, + 0x5e, 0xf4, 0xcb, 0xf9, 0x70, 0x03, 0xb0, 0xde, 0x85, 0x18, 0xc6, 0x4b, + 0xd0, 0xe2, 0x7a, 0x6a, 0x28, 0xc3, 0xec, 0x45, 0xc4, 0xf1, 0x91, 0x4a, + 0x44, 0x4c, 0x78, 0xe3, 0xa4, 0x47, 0xd8, 0x6a, 0x9a, 0xc8, 0x21, 0x67, + 0x10, 0x11, 0x35, 0x36, 0x42, 0xa2, 0xde, 0x4d, 0xb0, 0xc3, 0xb2, 0x5d, + 0x44, 0x27, 0x18, 0xbc, 0xd5, 0xbf, 0xd4, 0x9d, 0xe4, 0xb5, 0x50, 0x88, + 0x3a, 0xf8, 0x30, 0x8f, 0x64, 0xed, 0xbb, 0x28, 0x9e, 0x78, 0x9e, 0x41, + 0x6d, 0x98, 0x2f, 0x6c, 0x1c, 0xe9, 0xe0, 0x51, 0x93, 0x2a, 0xd2, 0xa7, + 0xdc, 0xcc, 0x91, 0x70, 0x40, 0xc9, 0x99, 0x82, 0x10, 0xec, 0xa9, 0xf9, + 0xde, 0x9d, 0x5b, 0xd6, 0x9d, 0xb7, 0xb5, 0xb3, 0xe8, 0x33, 0x31, 0x0e, + 0x49, 0x79, 0x25, 0x65, 0x51, 0x99, 0x28, 0x01, 0x3f, 0xad, 0x50, 0x9e, + 0x5f, 0x5c, 0x0c, 0x73, 0x42, 0xac, 0x53, 0xb7, 0x71, 0x87, 0x5d, 0x3b, + 0x53, 0x03, 0x30, 0x06, 0x7c, 0x66, 0xfa, 0x34, 0xfe, 0xa9, 0x41, 0xbf, + 0xba, 0x85, 0xf6, 0xa8, 0xe4, 0xbb, 0x95, 0xf2, 0xce, 0x59, 0x01, 0x32, + 0x50, 0x92, 0x13, 0xf8, 0xa9, 0x42, 0xad, 0x36, 0x27, 0x84, 0xd8, 0x5c, + 0xe8, 0x84, 0xa4, 0x0a, 0x43, 0xc4, 0x7d, 0xdb, 0x8a, 0x8e, 0xdb, 0x4f, + 0x34, 0xb8, 0x29, 0x1f, 0x4e, 0xa0, 0xc8, 0xa8, 0x88, 0xbf, 0xda, 0x86, + 0xcf, 0xc5, 0xac, 0xed, 0x0e, 0x37, 0x26, 0xa4, 0xba, 0x6e, 0x40, 0xc3, + 0x3a, 0x1f, 0x12, 0x44, 0xa4, 0xb0, 0x27, 0x28, 0x34, 0xe7, 0x7b, 0x2f, + 0x87, 0xe7, 0x86, 0xfe, 0xce, 0x04, 0x38, 0xd3, 0x18, 0x99, 0x30, 0x29, + 0xd6, 0x42, 0xce, 0xba, 0x73, 0xd8, 0x35, 0x6f, 0x43, 0x6a, 0x82, 0x5b, + 0x51, 0x12, 0x0e, 0xd4, 0x61, 0x48, 0xb9, 0x4a, 0xfb, 0x34, 0x95, 0x71, + 0x4c, 0xb8, 0x9a, 0xa7, 0x6e, 0xc6, 0x81, 0x38, 0xa4, 0x57, 0x83, 0xca, + 0x64, 0x19, 0xb4, 0x90, 0x91, 0x32, 0xac, 0x9b, 0x79, 0xce, 0x42, 0x01, + 0xf0, 0x66, 0x7f, 0x38, 0xa5, 0xad, 0x44, 0x43, 0x1f, 0xca, 0x0f, 0x59, + 0xbe, 0x8f, 0x9d, 0xff, 0x16, 0xc9, 0xb6, 0xb7, 0x37, 0xa4, 0x46, 0x54, + 0x62, 0xac, 0x03, 0x2a, 0xac, 0x07, 0x39, 0xf1, 0xc9, 0xcd, 0x9b, 0xd7, + 0x6b, 0x47, 0x13, 0x25, 0xb0, 0x68, 0x24, 0x1e, 0xb0, 0xb8, 0xec, 0x19, + 0xa7, 0x2e, 0xaf, 0x0e, 0xb2, 0x1b, 0xd1, 0x63, 0x56, 0x83, 0xce, 0x19, + 0xe9, 0xcb, 0x14, 0x0b, 0x19, 0x4f, 0xc3, 0x61, 0x55, 0x8d, 0xfe, 0x94, + 0x86, 0x4a, 0x0d, 0x78, 0xbb, 0x1b, 0x8a, 0x8d, 0x3d, 0xe4, 0xbe, 0x0e, + 0xf4, 0xa0, 0x97, 0x91, 0x02, 0xfe, 0x7d, 0xf4, 0xda, 0x44, 0x07, 0x79, + 0xc8, 0xa2, 0x4d, 0x24, 0x50, 0x39, 0x3f, 0x9c, 0x0f, 0x33, 0xba, 0x96, + 0x0b, 0xf9, 0x2b, 0xb7, 0x87, 0xc5, 0x74, 0x69, 0xba, 0xb6, 0xe2, 0x67, + 0x2d, 0xe0, 0xcc, 0x00, 0x0d, 0x5b, 0x64, 0x77, 0xb8, 0x4d, 0x1a, 0x23, + 0x2f, 0xd3, 0xf6, 0x47, 0x76, 0xff, 0x6d, 0x74, 0xde, 0x84, 0x36, 0xc3, + 0x7b, 0x62, 0x8c, 0x2f, 0xc4, 0x54, 0x15, 0x16, 0xc7, 0xd8, 0x10, 0xd7, + 0xa6, 0x0e, 0xd9, 0xa3, 0x1a, 0x41, 0x19, 0x76, 0x44, 0xa5, 0xda, 0x9e, + 0x6b, 0x0a, 0xaf, 0xea, 0x27, 0x29, 0x3f, 0xaf, 0x01, 0xb7, 0xb0, 0x31, + 0xff, 0x9e, 0x15, 0x21, 0x3d, 0xec, 0x3e, 0x24, 0x8a, 0x38, 0x63, 0x94, + 0x3c, 0x08, 0x39, 0xd9, 0x44, 0x99, 0x28, 0x64, 0x6b, 0x09, 0xcd, 0xe8, + 0xf8, 0x99, 0xb1, 0x33, 0x6d, 0xd6, 0xa4, 0xa5, 0xd2, 0x3c, 0x09, 0x39, + 0x38, 0x8b, 0x23, 0x14, 0x64, 0xb6, 0x01, 0xa2, 0x7e, 0x2c, 0xbe, 0xd5, + 0x24, 0xe5, 0xd8, 0x19, 0xce, 0xc8, 0x77, 0x8c, 0xec, 0x6c, 0x8a, 0x38, + 0x2d, 0x8b, 0xa8, 0x42, 0x2d, 0xb1, 0x34, 0x28, 0x9c, 0x85, 0x19, 0x78, + 0x40, 0x0a, 0xee, 0xff, 0xfa, 0xa3, 0xd9, 0xa2, 0x26, 0x55, 0xdb, 0x8f, + 0xa0, 0xc5, 0xd7, 0xa1, 0x07, 0x67, 0x87, 0x0f, 0x4e, 0x31, 0x09, 0x74, + 0x2a, 0xd2, 0xf3, 0xfb, 0xf3, 0x8c, 0x51, 0x65, 0x27, 0x74, 0x67, 0x2c, + 0x64, 0x7e, 0x6e, 0x32, 0xce, 0x12, 0x0b, 0x1b, 0xb6, 0xa2, 0xda, 0xb4, + 0xc2, 0xf4, 0xaa, 0xfe, 0x3a, 0x47, 0x52, 0x9c, 0x91, 0x43, 0x1f, 0xe7, + 0xee, 0x71, 0x8e, 0xa2, 0x3e, 0xbd, 0xf3, 0x2e, 0xbd, 0xbc, 0xae, 0x76, + 0x7f, 0x15, 0x3d, 0x41, 0xc1, 0xf3, 0xed, 0xc2, 0xdb, 0x3a, 0xcd, 0x2d, + 0xf4, 0xd4, 0x5e, 0x10, 0x02, 0x84, 0xd1, 0x23, 0x5d, 0xac, 0x86, 0x4c, + 0x7d, 0x17, 0xd3, 0xbc, 0x7f, 0xec, 0x42, 0xa9, 0x74, 0x01, 0x01, 0xa3, + 0x8e, 0x20, 0x8c, 0x26, 0x66, 0x4e, 0x03, 0xf5, 0x07, 0xac, 0x2b, 0xaf, + 0x5a, 0xd2, 0xbf, 0xef, 0x74, 0xf1, 0x5c, 0xb1, 0xa7, 0x48, 0x1a, 0x48, + 0x0c, 0x69, 0xc6, 0x32, 0xc0, 0x70, 0x80, 0x77, 0x9a, 0x4c, 0x6f, 0xd7, + 0x22, 0xd8, 0xcd, 0x42, 0x3f, 0xae, 0xf9, 0x01, 0x08, 0x06, 0x9c, 0xca, + 0xc8, 0x3d, 0x63, 0x2b, 0x54, 0x7e, 0x76, 0xc1, 0x2c, 0xe0, 0xf5, 0x50, + 0x54, 0x51, 0x1b, 0xcb, 0x77, 0x36, 0xed, 0x30, 0x2e, 0x63, 0xad, 0x34, + 0x38, 0x9a, 0xd6, 0x9b, 0x0c, 0xcd, 0x2c, 0x91, 0x7f, 0x19, 0xfc, 0x4d, + 0x58, 0xac, 0x47, 0xdd, 0x17, 0xf3, 0xb8, 0xa0, 0x10, 0x3f, 0x16, 0xad, + 0x9b, 0x06, 0xc9, 0x97, 0x7b, 0x3f, 0x40, 0xb0, 0x0d, 0x1d, 0x85, 0xcb, + 0x12, 0x79, 0x61, 0x8e, 0x31, 0x20, 0x51, 0x9e, 0x59, 0x97, 0x87, 0x6d, + 0xfa, 0x4a, 0x43, 0x70, 0x8f, 0x75, 0x9f, 0x31, 0x75, 0xd9, 0xa6, 0x84, + 0x9b, 0x40, 0xaf, 0x62, 0xa1, 0x7b, 0x4a, 0x6e, 0x72, 0xdc, 0xd0, 0xa0, + 0x04, 0x35, 0x94, 0xd5, 0xa7, 0x3e, 0xc6, 0xd3, 0x73, 0x7b, 0xfd, 0x5b, + 0x64, 0x1d, 0x94, 0x48, 0x69, 0x8a, 0x89, 0xd8, 0x50, 0x22, 0x30, 0x94, + 0xfb, 0x5f, 0xaa, 0x53, 0x0b, 0xb9, 0x53, 0xe4, 0xbe, 0x0a, 0x27, 0x97, + 0x77, 0x53, 0x0d, 0xc5, 0xde, 0x64, 0x7f, 0x73, 0x77, 0x23, 0x5a, 0x47, + 0xb0, 0xda, 0x7c, 0x3e, 0x00, 0xd4, 0x4f, 0x80, 0x3c, 0xd8, 0x7f, 0x4d, + 0x76, 0x56, 0x8f, 0x55, 0xdd, 0x6d, 0x63, 0xde, 0xeb, 0xa3, 0x8e, 0x44, + 0xcf, 0xcc, 0x9e, 0xe7, 0x42, 0x94, 0x7b, 0xb9, 0x1d, 0x7d, 0x15, 0xb3, + 0x0a, 0x9e, 0xe8, 0xd5, 0x8f, 0x2e, 0xe4, 0xa6, 0x79, 0x55, 0x82, 0xff, + 0xfe, 0x79, 0x3a, 0x3d, 0xa7, 0x02, 0x04, 0x8d, 0x65, 0x6e, 0xab, 0x9c, + 0x62, 0xd8, 0x6f, 0x7e, 0xab, 0x21, 0x70, 0x12, 0x88, 0x76, 0x68, 0x5b, + 0xe2, 0x4b, 0xc6, 0x69, 0x0d, 0x5f, 0xf8, 0x21, 0x92, 0xe5, 0x49, 0xef, + 0xe6, 0x79, 0x9d, 0xcf, 0x6d, 0x5a, 0x7d, 0xbf, 0x08, 0x61, 0x62, 0xbd, + 0x87, 0x75, 0x8e, 0x36, 0x1c, 0x0a, 0x13, 0x94, 0x9c, 0x03, 0x01, 0x2e, + 0x47, 0xd8, 0x93, 0x13, 0xab, 0xab, 0x8d, 0xfe, 0x4d, 0xb3, 0x4e, 0x0a, + 0x18, 0x67, 0x84, 0x38, 0x21, 0x11, 0xb0, 0x58, 0x7c, 0x78, 0x23, 0xaf, + 0xbc, 0x58, 0xf7, 0x3b, 0xeb, 0x69, 0x59, 0xc9, 0x1a, 0x03, 0xe6, 0x00, + 0x43, 0xc0, 0x15, 0x56, 0x9b, 0x19, 0xb3, 0xbc, 0xdb, 0xeb, 0xec, 0xca, + 0xb8, 0x6a, 0x18, 0x7c, 0x59, 0xba, 0xa4, 0xc6, 0x84, 0x91, 0x12, 0x4b, + 0x41, 0xf2, 0xbc, 0x5a, 0x52, 0x29, 0x99, 0x0c, 0x5e, 0xb0, 0x9f, 0x0c, + 0xd4, 0xc5, 0x6e, 0xed, 0xf9, 0xb0, 0xc1, 0xc1, 0x7d, 0xae, 0x67, 0x4c, + 0xc0, 0x55, 0xf4, 0xed, 0x03, 0xad, 0xc5, 0xb4, 0x83, 0xfe, 0xec, 0x16, + 0x70, 0x08, 0xdd, 0x5c, 0x45, 0xb4, 0xb7, 0x99, 0x9b, 0xec, 0xa0, 0x06, + 0x42, 0x44, 0xd0, 0x9f, 0xda, 0x05, 0xb7, 0xef, 0x7c, 0xd5, 0xa3, 0x0f, + 0x4c, 0x36, 0xf7, 0x92, 0x98, 0xc4, 0x64, 0x89, 0xa7, 0x2a, 0x39, 0x41, + 0xa1, 0x28, 0xcb, 0xc4, 0xc1, 0x77, 0xda, 0x49, 0xf7, 0xfa, 0xb3, 0x72, + 0x93, 0xa0, 0xad, 0x09, 0x9b, 0xd9, 0x82, 0x44, 0xf6, 0x84, 0x9c, 0xbf, + 0xad, 0x73, 0xde, 0x15, 0x76, 0xee, 0x9c, 0x4f, 0xce, 0x5f, 0x5d, 0xf4, + 0x90, 0x51, 0xfc, 0xaf, 0xfc, 0x59, 0x2a, 0x70, 0x92, 0x66, 0xeb, 0xd3, + 0x04, 0x29, 0xc8, 0xc2, 0x49, 0x40, 0x9a, 0xac, 0xff, 0x94, 0x31, 0x42, + 0x81, 0x83, 0x17, 0x6f, 0x87, 0xdc, 0x62, 0xe7, 0x74, 0x50, 0xc9, 0xc6, + 0x83, 0xbf, 0x7a, 0xe0, 0xae, 0x11, 0xbd, 0x86, 0x0f, 0x02, 0xdc, 0x2a, + 0x58, 0xee, 0x50, 0x04, 0xcf, 0x28, 0x7d, 0xa0, 0xdf, 0xd8, 0x2b, 0xec, + 0xe3, 0x79, 0xff, 0xd9, 0x2b, 0xc3, 0x23, 0x3a, 0x4a, 0x19, 0x26, 0x69, + 0x7c, 0x5a, 0xcb, 0xf5, 0x66, 0x11, 0xdd, 0x7e, 0x4f, 0x99, 0xc6, 0xf2, + 0x6f, 0xf6, 0xe5, 0x3f, 0x60, 0x46, 0xfe, 0x52, 0x26, 0xab, 0x3a, 0xcc, + 0x48, 0xbf, 0xdf, 0xcc, 0xaf, 0x67, 0xc5, 0x02, 0x99, 0x93, 0x43, 0x0b, + 0x11, 0x31, 0xda, 0x9c, 0xa6, 0x64, 0xb9, 0x4b, 0xed, 0x05, 0x56, 0xf8, + 0x75, 0xdf, 0xbc, 0x7d, 0xfd, 0xee, 0x69, 0x59, 0xfb, 0x68, 0x7e, 0xfd, + 0x94, 0xd3, 0x46, 0x1d, 0xa2, 0x61, 0x59, 0x8c, 0x7b, 0x05, 0x58, 0x07, + 0x8a, 0xfe, 0x37, 0x7b, 0xbc, 0x9c, 0x40, 0x04, 0x4d, 0x08, 0x31, 0xca, + 0x3c, 0xb9, 0x74, 0x67, 0x46, 0xbc, 0xc9, 0x79, 0x78, 0x4e, 0x60, 0xbf, + 0xf8, 0x92, 0x51, 0xa4, 0xda, 0x35, 0xfd, 0xe8, 0x89, 0x4b, 0xe0, 0xc8, + 0x9c, 0xb2, 0xbe, 0xb9, 0x3c, 0x26, 0x4b, 0x6a, 0x8a, 0xfa, 0xa8, 0x5c, + 0xd3, 0x0b, 0x9a, 0x86, 0xd9, 0x5a, 0xa1, 0x2b, 0x13, 0x2d, 0xf1, 0xe9, + 0xde, 0x99, 0x78, 0x0d, 0xc9, 0xae, 0x6d, 0x4e, 0x8e, 0x3c, 0x25, 0x2d, + 0x1f, 0xb1, 0x04, 0x69, 0x86, 0x4b, 0x23, 0xc3, 0x70, 0x8c, 0x5d, 0x08, + 0xc0, 0x3b, 0x8f, 0x88, 0x8f, 0x82, 0x42, 0x20, 0xef, 0xf8, 0xbb, 0x92, + 0x06, 0x8b, 0x19, 0x3e, 0xc6, 0x34, 0xa5, 0x95, 0x90, 0xf0, 0x16, 0xac, + 0xee, 0x4b, 0xed, 0x7c, 0xb6, 0x83, 0x2a, 0x67, 0x14, 0x8d, 0xec, 0x4c, + 0xe5, 0x6e, 0x96, 0x92, 0xa6, 0x05, 0x2a, 0xb1, 0x57, 0xb8, 0x7c, 0x31, + 0xc7, 0x56, 0xf4, 0xf3, 0xc9, 0x06, 0x3f, 0x51, 0x8e, 0x93, 0x45, 0xe6, + 0x22, 0xed, 0x44, 0x71, 0xff, 0x61, 0x38, 0x7f, 0xc4, 0x57, 0xff, 0x3c, + 0x04, 0x1a, 0xa1, 0xc8, 0x80, 0xb0, 0x97, 0x30, 0x2b, 0x17, 0xe5, 0x67, + 0xa2, 0x54, 0x38, 0xdc, 0x5e, 0x48, 0x27, 0xe8, 0x08, 0xd7, 0xfd, 0xef, + 0x99, 0x34, 0xb1, 0x40, 0x06, 0x14, 0x49, 0x43, 0x2b, 0x18, 0xbe, 0x5a, + 0x1d, 0xc1, 0x8e, 0xcf, 0x0a, 0xca, 0xf0, 0x13, 0x5b, 0x8b, 0x3f, 0xe8, + 0x3c, 0xa0, 0x84, 0x46, 0x09, 0x69, 0x14, 0x70, 0x1f, 0x06, 0x61, 0x3d, + 0xd3, 0x25, 0x24, 0x5f, 0x37, 0x0b, 0x36, 0xea, 0xbd, 0xce, 0xd9, 0xb5, + 0x0f, 0x21, 0x84, 0x25, 0xb4, 0x8b, 0x34, 0xe5, 0x41, 0xa7, 0x58, 0x47, + 0xcc, 0x97, 0x91, 0x1e, 0xcc, 0x63, 0x88, 0x8b, 0x84, 0xb9, 0xf7, 0x0c, + 0x59, 0xb4, 0x28, 0x8a, 0xa8, 0xcc, 0xa9, 0xc4, 0x9a, 0xb6, 0x2e, 0xca, + 0x0d, 0x8c, 0x52, 0x08, 0x9b, 0xd7, 0xee, 0x2a, 0x1b, 0x0e, 0xde, 0x81, + 0x38, 0x62, 0x97, 0x43, 0xe3, 0xd2, 0x20, 0x5a, 0x30, 0x92, 0xe9, 0x1f, + 0x14, 0x99, 0x69, 0x8c, 0xa1, 0x13, 0xc8, 0x48, 0x4e, 0xf5, 0x73, 0x3a, + 0xf4, 0xa1, 0xfb, 0xf4, 0x7c, 0xfb, 0x3f, 0x2d, 0xe6, 0x2d, 0x78, 0x10, + 0x03, 0x70, 0x7c, 0xc1, 0x90, 0x96, 0x4f, 0x09, 0x04, 0xfd, 0x03, 0x55, + 0xf7, 0x1a, 0x58, 0x5f, 0x6a, 0x26, 0x25, 0x80, 0xc6, 0x9f, 0xf7, 0x1b, + 0x45, 0x06, 0xdc, 0xcd, 0xf4, 0x65, 0x4b, 0xfb, 0xbe, 0xd7, 0x45, 0x19, + 0x1d, 0x41, 0x90, 0x82, 0x39, 0x14, 0x83, 0x35, 0x9c, 0xf3, 0xd7, 0x9f, + 0x9a, 0x70, 0x43, 0x03, 0x90, 0xde, 0x6d, 0x84, 0xb0, 0xe9, 0x55, 0x68, + 0xfb, 0xcd, 0xfb, 0x3c, 0x9b, 0x44, 0xb0, 0x22, 0x8b, 0x97, 0x79, 0x83, + 0xe9, 0xee, 0x5b, 0x59, 0xab, 0x8a, 0x69, 0x85, 0x37, 0x57, 0x11, 0x8f, + 0x97, 0x21, 0x80, 0xa1, 0x2c, 0x89, 0xc9, 0xed, 0x6c, 0xce, 0x4d, 0xb5, + 0xe2, 0xb7, 0xd2, 0xc4, 0xa2, 0x70, 0xe1, 0xb4, 0x45, 0x78, 0x2f, 0x0e, + 0x63, 0x06, 0x33, 0xc7, 0x9d, 0x1a, 0x52, 0x13, 0xdf, 0xda, 0xdb, 0xe8, + 0x57, 0x49, 0x1d, 0x81, 0xac, 0x71, 0x8c, 0x64, 0x90, 0x29, 0x19, 0xd1, + 0x33, 0xf9, 0xc0, 0xce, 0x13, 0xf2, 0x59, 0x16, 0xf0, 0xea, 0x6a, 0x75, + 0x78, 0x07, 0x75, 0xf0, 0xf9, 0x0a, 0x66, 0x52, 0x48, 0xd0, 0x4e, 0xd0, + 0x6b, 0x89, 0xd6, 0x9b, 0xef, 0x7e, 0xef, 0x23, 0x29, 0x0a, 0x4c, 0x28, + 0xe4, 0xc8, 0x1f, 0x15, 0x13, 0x3a, 0xca, 0x98, 0x20, 0x7f, 0xe2, 0x9d, + 0x2a, 0xe6, 0x1c, 0x77, 0xa5, 0x06, 0xe3, 0x19, 0xce, 0x7f, 0x38, 0xcf, + 0x5e, 0xd1, 0xef, 0xf8, 0x81, 0x20, 0xfa, 0x98, 0x45, 0x9f, 0x2b, 0x27, + 0xe0, 0x73, 0x8c, 0xe1, 0x01, 0x2c, 0x05, 0x0a, 0xa7, 0x19, 0xd9, 0xe5, + 0xf6, 0x06, 0xd4, 0x02, 0xdb, 0xee, 0x38, 0x41, 0x35, 0x02, 0x48, 0xa4, + 0x72, 0x0a, 0xa2, 0x6c, 0x6a, 0x8a, 0x18, 0x08, 0x4b, 0x26, 0x44, 0xa4, + 0x0a, 0x1e, 0x20, 0xcf, 0xfc, 0xa8, 0x72, 0x37, 0xe6, 0xe4, 0xea, 0xb4, + 0x4c, 0xe9, 0xe5, 0x6e, 0x1c, 0x57, 0x83, 0x2f, 0x44, 0x50, 0xc0, 0x3c, + 0x37, 0x07, 0x38, 0xbd, 0x6a, 0xc7, 0x88, 0x90, 0x0b, 0x7d, 0xe9, 0x20, + 0x2a, 0xbc, 0x73, 0xad, 0x07, 0x60, 0x52, 0x9a, 0x47, 0x2f, 0xe2, 0xc6, + 0x9a, 0xc0, 0x0d, 0x37, 0x12, 0x60, 0x99, 0x51, 0xfc, 0x5e, 0xdf, 0xc0, + 0x23, 0x7f, 0x47, 0xa2, 0x5c, 0xa6, 0x2f, 0xa5, 0x62, 0x13, 0xc6, 0x3b, + 0x61, 0xf1, 0x52, 0xe1, 0x90, 0x9b, 0xba, 0x4a, 0x67, 0x02, 0x3f, 0xfd, + 0x8d, 0xfe, 0xd7, 0xe1, 0xed, 0xd6, 0x26, 0x3a, 0xd9, 0x48, 0x3c, 0x00, + 0x11, 0x36, 0x33, 0x18, 0x6c, 0x9e, 0x57, 0x89, 0xe5, 0x44, 0xfe, 0xae, + 0x69, 0xd9, 0x4c, 0x22, 0x1f, 0x18, 0xe9, 0x07, 0xf8, 0xbf, 0x42, 0x8c, + 0x0b, 0xf1, 0xb5, 0x6c, 0x95, 0x2f, 0xcb, 0x0c, 0x85, 0x90, 0xc0, 0xfa, + 0x98, 0xcb, 0x32, 0xd8, 0xfb, 0x1a, 0x57, 0x49, 0xf5, 0xea, 0x9b, 0x27, + 0x3d, 0xf6, 0x11, 0xf5, 0xfc, 0xa9, 0x7f, 0xca, 0xe3, 0xf5, 0xb3, 0x50, + 0xd5, 0x78, 0xcf, 0x28, 0x99, 0x82, 0x11, 0x96, 0x46, 0x51, 0x00, 0x25, + 0x56, 0x4e, 0xf6, 0xa6, 0x59, 0xd3, 0x97, 0xdf, 0x0c, 0x1f, 0x4e, 0xa6, + 0x69, 0x50, 0x2f, 0xad, 0xe4, 0x84, 0x8b, 0x82, 0xc6, 0x45, 0x2f, 0xb8, + 0x07, 0x9a, 0x5c, 0x1e, 0xa8, 0xe7, 0x9a, 0xcc, 0xff, 0xf4, 0x89, 0x30, + 0xa7, 0x52, 0x9b, 0x99, 0x65, 0x28, 0xda, 0xef, 0x4f, 0x5a, 0x8c, 0x27, + 0x36, 0x4a, 0x06, 0x5d, 0xc0, 0x5c, 0x79, 0x96, 0xbf, 0x2d, 0xd6, 0xcb, + 0xa4, 0xcc, 0xc7, 0x15, 0xa0, 0x93, 0xb0, 0x2f, 0xa1, 0x19, 0x5f, 0x6e, + 0x66, 0x94, 0xe7, 0x37, 0x74, 0xf8, 0x22, 0x57, 0xed, 0xca, 0x0f, 0x0d, + 0x31, 0x54, 0xe2, 0x5b, 0xc6, 0xb1, 0x3d, 0x97, 0xb5, 0xdb, 0xaa, 0x5d, + 0x60, 0x0f, 0x08, 0x22, 0x1e, 0x2d, 0x80, 0x99, 0x92, 0x1a, 0x4d, 0x2d, + 0x90, 0x41, 0x38, 0x40, 0x0d, 0x07, 0xe0, 0xbc, 0x0c, 0x76, 0x58, 0x61, + 0xb2, 0xd1, 0x4b, 0x97, 0x68, 0x12, 0x3f, 0x6a, 0x4f, 0xc3, 0xf9, 0x1f, + 0xc8, 0x58, 0x39, 0x7b, 0xbc, 0x7f, 0x5a, 0xf9, 0xc4, 0x1a, 0x14, 0x88, + 0x27, 0x1d, 0xc6, 0xf6, 0x66, 0x95, 0x87, 0xcb, 0x99, 0xee, 0x50, 0x8d, + 0x56, 0xff, 0x90, 0x0b, 0xb4, 0x94, 0x77, 0xcb, 0x06, 0x63, 0x7a, 0x65, + 0xf1, 0xfc, 0x35, 0x59, 0x68, 0xee, 0x50, 0x25, 0xf2, 0x5c, 0xff, 0x28, + 0x9e, 0xd1, 0xd5, 0xea, 0x84, 0x14, 0x90, 0x28, 0xfc, 0x5f, 0xa0, 0x3e, + 0xc8, 0xee, 0x61, 0xeb, 0x05, 0x9c, 0x6e, 0x44, 0x58, 0x78, 0xfc, 0xfe, + 0x0c, 0xb5, 0x01, 0xf9, 0xab, 0xf3, 0xbf, 0xcd, 0x6f, 0x8e, 0x31, 0xdc, + 0x4a, 0xb4, 0x12, 0xe9, 0x8a, 0x15, 0x90, 0x62, 0x4d, 0xc1, 0xef, 0xbf, + 0x53, 0xeb, 0x8f, 0x90, 0x1d, 0x17, 0xbf, 0xc7, 0xa3, 0x0c, 0x35, 0x26, + 0x76, 0x9b, 0xa4, 0x56, 0xf0, 0xfc, 0x41, 0xe0, 0x96, 0x02, 0x75, 0x9b, + 0x0f, 0xfe, 0x1a, 0x9c, 0x10, 0x79, 0xa5, 0xfa, 0x2c, 0x5b, 0x6f, 0xfa, + 0xf3, 0x16, 0xea, 0xca, 0xed, 0xb5, 0xe9, 0xd3, 0x73, 0xf0, 0x41, 0x29, + 0x98, 0x4a, 0x00, 0x10, 0x03, 0xe8, 0x02, 0x6f, 0x15, 0xf8, 0x42, 0x65, + 0xb6, 0x8b, 0xf7, 0x12, 0x96, 0x55, 0xf6, 0x0e, 0x38, 0xaa, 0xc7, 0x6f, + 0x70, 0x7b, 0x40, 0x0f, 0xce, 0x02, 0xa7, 0xe3, 0xba, 0x8f, 0xff, 0xaa, + 0x76, 0x7e, 0x3c, 0xc9, 0x43, 0x98, 0x59, 0xa5, 0x4c, 0x68, 0x99, 0x03, + 0x01, 0x45, 0x11, 0x0d, 0x04, 0x60, 0xfa, 0x9d, 0xa9, 0xf7, 0xfd, 0x9e, + 0x3b, 0xac, 0xc6, 0xf9, 0xdd, 0xd2, 0x8c, 0x9b, 0x13, 0x58, 0x83, 0xcc, + 0x69, 0x6e, 0x63, 0x58, 0x79, 0x80, 0x10, 0xc6, 0x61, 0x21, 0xe0, 0x61, + 0x42, 0xac, 0x07, 0x95, 0xfd, 0xbd, 0xb7, 0xa8, 0x17, 0xed, 0x71, 0xc2, + 0x58, 0xf3, 0x36, 0x5e, 0x4e, 0x09, 0xe0, 0x3f, 0x6e, 0x1d, 0x28, 0x7c, + 0x4b, 0x9d, 0x1f, 0xd7, 0x84, 0x27, 0x29, 0xd3, 0x1f, 0xcf, 0x0a, 0xfc, + 0xdb, 0x3a, 0xde, 0xda, 0xd1, 0x3a, 0x50, 0x4a, 0x5a, 0x82, 0x80, 0x48, + 0xd1, 0x38, 0x49, 0x9d, 0x88, 0xb7, 0x39, 0x16, 0xa7, 0xb7, 0xbb, 0xdf, + 0x82, 0xfa, 0xa4, 0x08, 0xca, 0x13, 0x20, 0xe4, 0xcc, 0x69, 0x10, 0x89, + 0x85, 0xdc, 0xfe, 0xca, 0xd5, 0xbb, 0x1c, 0x75, 0x71, 0x94, 0x70, 0xce, + 0x46, 0x58, 0x33, 0x92, 0x5d, 0x61, 0x29, 0xe4, 0xa1, 0xaf, 0xed, 0x8e, + 0x35, 0x89, 0xa7, 0x45, 0x82, 0x33, 0x85, 0xa5, 0x36, 0x9f, 0x70, 0xbd, + 0xf4, 0x63, 0x5d, 0xc2, 0x3c, 0xd8, 0xea, 0x53, 0x7b, 0x6a, 0xf0, 0xa9, + 0x19, 0xbb, 0x9b, 0x1d, 0xf5, 0xaf, 0x4e, 0x71, 0xf4, 0xae, 0x44, 0x12, + 0x18, 0x71, 0x03, 0x4d, 0x9d, 0x04, 0x89, 0x47, 0xc4, 0x02, 0x69, 0xb9, + 0x6b, 0x79, 0x76, 0x29, 0x6f, 0xe6, 0x9b, 0x40, 0xe8, 0x4b, 0x94, 0x84, + 0xd1, 0x90, 0x3d, 0xaf, 0xcf, 0x3e, 0xdb, 0xe5, 0xec, 0x5e, 0x2d, 0x7f, + 0x1a, 0x92, 0x32, 0x10, 0xcc, 0xcb, 0xb5, 0xf0, 0x13, 0x15, 0xb4, 0x2e, + 0xec, 0x11, 0x65, 0x90, 0x42, 0x1b, 0xb5, 0x20, 0xa7, 0x7c, 0x92, 0xd1, + 0x33, 0x9d, 0xea, 0xa8, 0x46, 0xca, 0x2a, 0x60, 0x3d, 0xcf, 0x5d, 0x8f, + 0xa5, 0x25, 0x42, 0xe5, 0xff, 0x2a, 0x0b, 0x60, 0xcf, 0xfd, 0x8c, 0xb7, + 0xd9, 0x83, 0xa2, 0xc9, 0x6f, 0xc2, 0x5a, 0x30, 0xc2, 0xd8, 0x41, 0xd7, + 0x9a, 0xbe, 0x1b, 0xfe, 0x3c, 0xa3, 0x0f, 0x2d, 0x02, 0xe0, 0x4a, 0x66, + 0x92, 0x2d, 0xb4, 0x11, 0x48, 0xcb, 0xed, 0x04, 0xd9, 0xd1, 0x5b, 0xe3, + 0x7f, 0x9f, 0x99, 0x3b, 0x92, 0x95, 0x51, 0x64, 0x3a, 0x5d, 0x94, 0xce, + 0xfb, 0x73, 0xf1, 0xde, 0x2b, 0xf0, 0xcf, 0xb2, 0x00, 0x44, 0xe4, 0x92, + 0xbd, 0x3f, 0x5b, 0xa5, 0x1f, 0x97, 0xeb, 0x84, 0x52, 0x18, 0xd5, 0xad, + 0x79, 0x2d, 0x47, 0xfd, 0x24, 0xa3, 0x43, 0x2d, 0x0f, 0xa2, 0x9a, 0xd0, + 0xe5, 0x70, 0x23, 0x04, 0x82, 0x3d, 0x84, 0xab, 0x22, 0xf8, 0x82, 0x90, + 0x48, 0x56, 0x50, 0xb7, 0x9a, 0x41, 0x2d, 0xfc, 0x6f, 0x25, 0x0b, 0x86, + 0x01, 0x8b, 0x35, 0x18, 0xc4, 0xa4, 0x68, 0x78, 0x3a, 0x99, 0xd4, 0xa0, + 0xd3, 0xa3, 0x23, 0xf5, 0xde, 0x69, 0xba, 0x22, 0x60, 0x89, 0x56, 0x51, + 0x87, 0xe9, 0xea, 0x48, 0xbc, 0xdf, 0xe2, 0x9e, 0x7b, 0xfc, 0x88, 0x6b, + 0x6a, 0xe9, 0x65, 0xb8, 0x9c, 0xe9, 0x72, 0x28, 0xc9, 0xe9, 0x89, 0x11, + 0xf1, 0x2a, 0xd1, 0x4f, 0x7e, 0xf9, 0x5e, 0x07, 0x4f, 0xee, 0xdc, 0x82, + 0x4a, 0x53, 0x30, 0xf9, 0x96, 0x85, 0x1f, 0x99, 0xac, 0xd9, 0xfa, 0x44, + 0xa4, 0xe5, 0x4f, 0x16, 0xe7, 0x9c, 0x42, 0x11, 0x2d, 0x95, 0x2c, 0xbf, + 0x00, 0x17, 0x9e, 0x98, 0xc9, 0x9e, 0x77, 0x85, 0xe2, 0x0b, 0x29, 0xb7, + 0xa2, 0x4f, 0x04, 0xc9, 0x2d, 0xa3, 0x04, 0x8f, 0x82, 0x5e, 0x16, 0x58, + 0x33, 0x00, 0x21, 0x34, 0x72, 0xe4, 0x2a, 0xd9, 0x44, 0x7a, 0x63, 0xfc, + 0xf5, 0xa5, 0x80, 0x7f, 0x9e, 0xb6, 0xb9, 0xa5, 0xe3, 0xb4, 0x99, 0x1f, + 0x4d, 0x61, 0x1e, 0xcd, 0xa6, 0x37, 0x9f, 0x38, 0x8c, 0xfa, 0x28, 0xa5, + 0x81, 0x18, 0xe4, 0xbb, 0x29, 0xcf, 0x1c, 0x74, 0xd7, 0x69, 0xa7, 0xd9, + 0xed, 0x4c, 0x10, 0x93, 0xf3, 0x47, 0x81, 0xe7, 0x90, 0x32, 0x6d, 0xc4, + 0x74, 0x2a, 0xcd, 0x2f, 0x04, 0xd2, 0x00, 0xcc, 0x20, 0x7e, 0x71, 0xab, + 0x73, 0xf4, 0xda, 0xd9, 0xe2, 0xf7, 0x2c, 0xf4, 0x86, 0x42, 0x85, 0x13, + 0x47, 0x25, 0x2e, 0xe0, 0x65, 0x6f, 0x5a, 0x22, 0xbc, 0x1c, 0xf1, 0x8f, + 0x87, 0xff, 0xda, 0x99, 0x50, 0x54, 0xa4, 0x48, 0x47, 0x0f, 0xf6, 0x2d, + 0xdf, 0x99, 0xc9, 0xb4, 0xb4, 0x67, 0x8c, 0x06, 0x3e, 0x80, 0xf9, 0x9a, + 0x03, 0x25, 0x97, 0x84, 0x04, 0x93, 0x97, 0xa5, 0x52, 0xc4, 0x43, 0x0e, + 0x91, 0x45, 0x0c, 0x06, 0xf5, 0x15, 0x89, 0x47, 0x15, 0xba, 0xaa, 0x03, + 0x90, 0xf1, 0x43, 0x8a, 0x33, 0xc6, 0xc7, 0x19, 0x21, 0x47, 0x00, 0xac, + 0x89, 0xec, 0xa9, 0xb6, 0xb8, 0x34, 0x7b, 0xf2, 0x51, 0xd3, 0xf9, 0xf4, + 0x18, 0x19, 0x87, 0xd0, 0x07, 0x54, 0x70, 0xf9, 0x79, 0x74, 0x51, 0xee, + 0x41, 0x0d, 0xfa, 0xed, 0x8f, 0x0e, 0x2f, 0xf7, 0xd4, 0x8b, 0xc3, 0xb5, + 0x72, 0x26, 0x5c, 0xe5, 0xbe, 0x9c, 0x3e, 0x01, 0x04, 0xfc, 0x6d, 0x7b, + 0xc2, 0x4f, 0xfe, 0x2c, 0x5e, 0xea, 0xf1, 0x64, 0x31, 0xc5, 0x31, 0x31, + 0x42, 0x7d, 0x98, 0x80, 0x64, 0x42, 0x47, 0xc4, 0x45, 0xed, 0xfc, 0xf2, + 0x9f, 0x45, 0xad, 0xda, 0xaf, 0x51, 0x61, 0x97, 0x45, 0x68, 0x31, 0xc9, + 0xa1, 0x46, 0x5e, 0x03, 0xa9, 0xaa, 0x05, 0x14, 0x51, 0x61, 0xe9, 0xbd, + 0x58, 0x6c, 0x6d, 0x09, 0xd2, 0x48, 0x65, 0x7d, 0x79, 0xd9, 0xc9, 0x1e, + 0xca, 0xa5, 0xdc, 0xa7, 0x86, 0x77, 0xd6, 0x41, 0x45, 0x0f, 0x88, 0x7e, + 0xb1, 0xa5, 0xfa, 0xdd, 0xaa, 0x2d, 0xa8, 0x89, 0xa1, 0x32, 0x3b, 0x0b, + 0xe0, 0x0a, 0xf5, 0x72, 0x29, 0x9c, 0x03, 0xce, 0x00, 0x42, 0x46, 0x06, + 0x79, 0xbc, 0xd2, 0xfd, 0x23, 0x08, 0x00, 0x7c, 0xad, 0x65, 0xc5, 0x69, + 0x51, 0xa8, 0xcc, 0x68, 0x45, 0x7b, 0xc4, 0x72, 0xdc, 0xf0, 0x43, 0xd0, + 0xa3, 0x24, 0x94, 0x4f, 0xd3, 0x03, 0x53, 0xf9, 0x47, 0xf2, 0xcd, 0x79, + 0xa7, 0x4b, 0x7c, 0xbb, 0x69, 0x00, 0x51, 0xaf, 0x4e, 0x11, 0xf1, 0x3e, + 0x80, 0xaa, 0x8d, 0x57, 0x2f, 0xc9, 0x6a, 0xff, 0x3d, 0xbc, 0xdb, 0xad, + 0xea, 0x75, 0xfb, 0xdb, 0x70, 0x64, 0xd1, 0x1b, 0xed, 0x4a, 0x55, 0x01, + 0xe0, 0x6d, 0x99, 0x6f, 0x17, 0x56, 0x2d, 0x1e, 0x17, 0x47, 0x26, 0x1d, + 0x50, 0xcf, 0x00, 0xdc, 0xb2, 0x28, 0x2a, 0x9f, 0xd7, 0xf7, 0x2e, 0xb6, + 0xb9, 0xe3, 0x91, 0xca, 0x9e, 0x58, 0xdb, 0x64, 0x4a, 0x42, 0x31, 0xfa, + 0x8a, 0xba, 0x7c, 0xa5, 0x8a, 0x76, 0xce, 0xdc, 0x47, 0xe3, 0xf8, 0xeb, + 0x3a, 0xdc, 0x90, 0xb1, 0xc4, 0x28, 0x1c, 0xaa, 0x08, 0x51, 0xfb, 0x74, + 0x76, 0xbd, 0x83, 0x75, 0x3e, 0xef, 0x2d, 0xb3, 0x21, 0x60, 0x04, 0xa2, + 0xf8, 0x05, 0x14, 0x72, 0xa8, 0x61, 0x20, 0xe5, 0x26, 0x77, 0x71, 0x70, + 0x4f, 0x8a, 0xfa, 0x3b, 0x88, 0x7b, 0x59, 0x65, 0x10, 0xdd, 0xa2, 0x22, + 0x55, 0x58, 0x28, 0xfc, 0xb5, 0xe9, 0x91, 0x7a, 0xf2, 0x35, 0x08, 0x50, + 0x9a, 0x5f, 0xd2, 0xda, 0xb6, 0x5b, 0xda, 0xb9, 0x14, 0x83, 0xb2, 0x5f, + 0xee, 0x73, 0x0f, 0xa8, 0x6c, 0xb3, 0xe2, 0x4a, 0x47, 0xc1, 0x3d, 0xf5, + 0x44, 0x8d, 0x50, 0xfa, 0xa2, 0x3e, 0x85, 0xf0, 0x1f, 0x7d, 0x49, 0x47, + 0xc5, 0x43, 0x7f, 0x40, 0xa5, 0xe2, 0x09, 0x03, 0xae, 0x98, 0x4b, 0xd3, + 0x07, 0xb9, 0x1e, 0x05, 0x7c, 0xf1, 0xb1, 0xe7, 0x26, 0xd6, 0xc9, 0xc9, + 0x0f, 0x06, 0xd6, 0x9d, 0xfc, 0x2a, 0xdb, 0x7f, 0x43, 0x39, 0x61, 0x69, + 0x32, 0xe7, 0x98, 0xdb, 0xde, 0x51, 0xd7, 0x21, 0xd1, 0x2a, 0x84, 0x9d, + 0x16, 0x32, 0xa1, 0x4e, 0x70, 0x41, 0x23, 0x97, 0x2f, 0xa2, 0x4f, 0x4e, + 0xb4, 0x97, 0xae, 0x5e, 0x6f, 0x05, 0x03, 0x7a, 0x23, 0x40, 0x3c, 0x2d, + 0x42, 0xa5, 0x95, 0x6c, 0x40, 0xec, 0x65, 0x30, 0x72, 0x8e, 0x11, 0x0c, + 0x49, 0xa0, 0x9b, 0x28, 0xcf, 0x9f, 0xca, 0x67, 0x7b, 0xa0, 0x68, 0x16, + 0xf1, 0x31, 0xe3, 0x6f, 0xc2, 0xb6, 0xee, 0xf3, 0xd6, 0xb6, 0x68, 0x19, + 0x86, 0x97, 0xc5, 0x22, 0x57, 0xa8, 0x1b, 0xe4, 0x78, 0xd7, 0x1d, 0xf9, + 0xe8, 0xcf, 0x15, 0x9b, 0x73, 0x48, 0xc2, 0xd5, 0x50, 0xd1, 0x6d, 0x3d, + 0xf8, 0xfd, 0xdb, 0x57, 0x90, 0x60, 0xdf, 0x30, 0xdd, 0x85, 0x47, 0xc6, + 0xa3, 0x5e, 0x19, 0xef, 0x8c, 0xd9, 0x29, 0xe2, 0x46, 0x59, 0xb1, 0x72, + 0x9d, 0x59, 0xbf, 0x72, 0xae, 0x37, 0x1c, 0xc4, 0x87, 0xc5, 0x23, 0x15, + 0xc3, 0xc2, 0xcb, 0xe1, 0x1a, 0x52, 0x48, 0x21, 0xf7, 0x20, 0xd8, 0xb9, + 0xdf, 0xbd, 0xd5, 0x4e, 0x45, 0x50, 0x29, 0x16, 0xe4, 0xc8, 0x4d, 0xf1, + 0x8a, 0x34, 0x61, 0x0e, 0x50, 0xca, 0x22, 0x7e, 0x22, 0x31, 0xd9, 0xc5, + 0x67, 0xa6, 0x83, 0x1a, 0x5c, 0x91, 0x0c, 0xf2, 0xdf, 0x19, 0x9d, 0x00, + 0x95, 0x0f, 0x72, 0xba, 0xa2, 0xd9, 0xff, 0x1f, 0xc7, 0x45, 0xbc, 0xcc, + 0x49, 0x90, 0xc9, 0x78, 0xc1, 0x8e, 0x98, 0x51, 0x10, 0x34, 0xf6, 0xc9, + 0x64, 0xd5, 0x55, 0x14, 0xc5, 0xc5, 0x71, 0x2e, 0x51, 0x79, 0xbe, 0xaa, + 0xff, 0xa6, 0xb3, 0x8d, 0x62, 0x34, 0x49, 0x63, 0xa3, 0x51, 0xd0, 0x91, + 0x23, 0x29, 0x11, 0xe2, 0x85, 0xdc, 0xd2, 0x61, 0x57, 0x25, 0x76, 0x2b, + 0x42, 0x08, 0x69, 0xac, 0x57, 0xa4, 0x35, 0x34, 0x4b, 0xd5, 0x86, 0xf0, + 0x35, 0x9d, 0xb9, 0x17, 0x98, 0xbe, 0x69, 0x70, 0xd9, 0xcd, 0x0f, 0xe5, + 0xe5, 0xaf, 0x97, 0x1f, 0xa4, 0xc7, 0xd3, 0x8b, 0x22, 0x32, 0x78, 0x49, + 0x84, 0x64, 0xaa, 0xe7, 0xe9, 0x86, 0xd8, 0xb8, 0xad, 0xe9, 0xc5, 0x11, + 0xcb, 0xf3, 0xad, 0xb5, 0x14, 0xa5, 0xe2, 0xf1, 0x43, 0xb5, 0xdf, 0xd3, + 0x7e, 0xb7, 0x9e, 0x50, 0x68, 0xf6, 0xcb, 0x9e, 0x43, 0x4b, 0xf5, 0x19, + 0x0c, 0xa9, 0x1f, 0xd6, 0x14, 0x0e, 0xdc, 0xe0, 0x09, 0x64, 0xa5, 0xe6, + 0x02, 0x95, 0x71, 0x7c, 0xed, 0xb9, 0xb4, 0x87, 0x6c, 0x96, 0x50, 0xcc, + 0x13, 0xa1, 0x36, 0xee, 0xbf, 0x7e, 0xdc, 0x58, 0xf7, 0x7f, 0xd1, 0x04, + 0x13, 0x01, 0xa4, 0x6d, 0xb4, 0x9a, 0x1a, 0xd0, 0x9e, 0x4f, 0xe0, 0xe7, + 0xdc, 0x93, 0xb6, 0xfd, 0xd4, 0x54, 0xd8, 0xed, 0x0b, 0xeb, 0x38, 0x5b, + 0xfe, 0xde, 0xf9, 0x0e, 0x0f, 0xad, 0x17, 0x04, 0x84, 0x2c, 0x25, 0x0f, + 0x99, 0xd2, 0x10, 0xcb, 0x19, 0x1a, 0xcc, 0x59, 0x6f, 0xe8, 0x17, 0x6f, + 0xe5, 0x04, 0xb3, 0x40, 0x00, 0x02, 0x40, 0x77, 0x01, 0x1b, 0x6a, 0xb0, + 0x55, 0xf7, 0x29, 0x1c, 0x95, 0x64, 0x42, 0xdd, 0xbf, 0x21, 0x1d, 0xa9, + 0x43, 0x24, 0x8b, 0xfc, 0x52, 0xc0, 0xce, 0x58, 0x00, 0xf0, 0x1d, 0x19, + 0x7d, 0x2c, 0x52, 0xfe, 0x5f, 0x3d, 0x5e, 0x94, 0x05, 0x22, 0x72, 0x87, + 0x80, 0xb1, 0x4b, 0xb4, 0x94, 0xb2, 0x4d, 0x2f, 0x8e, 0x25, 0xbb, 0x22, + 0x6c, 0x35, 0x03, 0x4c, 0xcd, 0x16, 0x45, 0xf2, 0x64, 0x9f, 0x82, 0x08, + 0x78, 0x33, 0x8d, 0x1a, 0x20, 0x78, 0xbb, 0x99, 0xbf, 0xf8, 0x4e, 0x91, + 0x76, 0x5d, 0x26, 0x18, 0x5b, 0x0c, 0xf0, 0x42, 0x6a, 0xa0, 0x71, 0xfe, + 0xa7, 0xd2, 0x26, 0xd1, 0x69, 0x5e, 0x73, 0x42, 0x1d, 0xb0, 0x99, 0xd6, + 0x49, 0x03, 0xe2, 0x2e, 0x1d, 0xd1, 0x86, 0x6c, 0x95, 0xf5, 0x14, 0x13, + 0x56, 0xb5, 0x6e, 0x0a, 0xde, 0x8a, 0x28, 0x62, 0x37, 0x9d, 0x99, 0x29, + 0xd0, 0x86, 0x14, 0x26, 0x81, 0x6a, 0xa8, 0x07, 0xbb, 0x23, 0x58, 0x54, + 0xd7, 0x5a, 0x36, 0xef, 0xe7, 0xd8, 0x1b, 0x86, 0xba, 0x6e, 0x29, 0xe6, + 0x9c, 0x91, 0xb8, 0x19, 0xe7, 0xb3, 0x03, 0xba, 0x1a, 0x39, 0x64, 0x34, + 0x8f, 0x72, 0x0f, 0x2d, 0xff, 0x0d, 0x8a, 0xaf, 0x34, 0x4e, 0x31, 0xf6, + 0x64, 0xbb, 0x5c, 0x0c, 0x66, 0x87, 0xb4, 0xd0, 0x95, 0x37, 0x98, 0x14, + 0x48, 0x01, 0x10, 0x8d, 0x60, 0x1b, 0xd2, 0xc6, 0xe9, 0x02, 0xff, 0x3c, + 0x01, 0xcc, 0xa5, 0x95, 0xa3, 0x42, 0x4d, 0x59, 0x00, 0x33, 0x5d, 0x38, + 0xe7, 0x71, 0x79, 0xeb, 0xcc, 0x2b, 0xd3, 0x34, 0xb5, 0xd7, 0x61, 0xac, + 0x14, 0xb2, 0xec, 0x52, 0x1a, 0x0e, 0x97, 0x02, 0x49, 0xed, 0xfc, 0x06, + 0xbb, 0x7f, 0x6f, 0xfa, 0x23, 0xad, 0x6f, 0x96, 0x2e, 0xee, 0x03, 0x36, + 0x34, 0x08, 0x4f, 0x26, 0x4f, 0xcd, 0x3e, 0x28, 0x54, 0x97, 0xbd, 0xfb, + 0x31, 0x46, 0x1a, 0x6b, 0x9b, 0xcf, 0x2d, 0xca, 0x37, 0xab, 0x8f, 0xd6, + 0x30, 0xc5, 0x95, 0x6d, 0xfe, 0x6f, 0xc8, 0x1b, 0x70, 0x90, 0x25, 0xb1, + 0x92, 0x02, 0xb0, 0x9d, 0x81, 0x0e, 0x26, 0x51, 0x97, 0x60, 0xbe, 0x25, + 0x62, 0xae, 0x5c, 0xd6, 0xbd, 0xfc, 0xca, 0xad, 0x6a, 0x6a, 0xdb, 0x4b, + 0x19, 0x8a, 0x04, 0xce, 0x73, 0x73, 0x39, 0x22, 0x6b, 0x2f, 0x5f, 0x22, + 0x78, 0xd6, 0xd1, 0xcb, 0xa3, 0xf0, 0x48, 0x78, 0x80, 0xb9, 0x69, 0xe4, + 0x57, 0xdc, 0x0e, 0x47, 0x6a, 0x28, 0x94, 0x88, 0xca, 0xac, 0x83, 0x27, + 0xbb, 0x11, 0x74, 0x74, 0xc8, 0xce, 0x11, 0x01, 0xc0, 0x0e, 0x92, 0xaf, + 0x58, 0xf9, 0xd3, 0xae, 0xa5, 0xed, 0x81, 0x84, 0x69, 0xd5, 0xcb, 0xe3, + 0x65, 0xc9, 0x84, 0xbb, 0x5d, 0x89, 0xe3, 0x8f, 0x98, 0x04, 0xf7, 0x06, + 0x93, 0x9f, 0xd8, 0xb3, 0x61, 0xfe, 0xfa, 0xd2, 0x86, 0x39, 0x53, 0xed, + 0x58, 0x0b, 0x61, 0x88, 0x46, 0x8f, 0x8f, 0x1f, 0xdf, 0x1a, 0x7a, 0x77, + 0x06, 0x72, 0xc5, 0x6a, 0x88, 0x60, 0x2f, 0x4a, 0x60, 0xe4, 0xbe, 0xa0, + 0x59, 0x69, 0xb0, 0xc6, 0x49, 0x7a, 0x95, 0x03, 0x0e, 0xa9, 0x60, 0x22, + 0xa3, 0xd4, 0xc6, 0x54, 0x63, 0xdc, 0x1c, 0x5a, 0x8a, 0x25, 0x19, 0x4f, + 0xc4, 0x8d, 0xae, 0xba, 0x9b, 0x3e, 0xe1, 0xd2, 0x27, 0x1c, 0x68, 0x87, + 0x18, 0x06, 0x5f, 0x64, 0x25, 0xba, 0x67, 0x0e, 0xda, 0x9a, 0xb9, 0x97, + 0x9e, 0x52, 0x32, 0x44, 0x25, 0x9a, 0xa7, 0xa3, 0xae, 0xce, 0x19, 0x6d, + 0x33, 0x04, 0x63, 0x93, 0x14, 0x43, 0x8c, 0xaf, 0xa8, 0x4f, 0xa8, 0xe3, + 0x53, 0x6f, 0x77, 0x4b, 0xc6, 0xd9, 0x6c, 0x02, 0x8f, 0xd8, 0x17, 0x9d, + 0x52, 0x10, 0x2b, 0x4f, 0x92, 0x91, 0xd1, 0xa2, 0x94, 0x8f, 0xd5, 0xb9, + 0xd2, 0xf5, 0xd9, 0xec, 0x47, 0x4f, 0x27, 0x87, 0x21, 0x6d, 0x2c, 0x81, + 0x87, 0x07, 0xb5, 0x29, 0x26, 0x46, 0x7c, 0x47, 0x38, 0x97, 0x98, 0x13, + 0xa2, 0xaa, 0x47, 0x9d, 0x23, 0x3c, 0x9c, 0x2d, 0x80, 0x56, 0x10, 0xb9, + 0xbe, 0x78, 0xe8, 0x61, 0x17, 0x92, 0x8b, 0x88, 0x70, 0xf4, 0x31, 0xf0, + 0x0c, 0x07, 0xe7, 0xbd, 0x1c, 0x34, 0xe5, 0x8e, 0x8c, 0xe8, 0xd6, 0x4e, + 0x38, 0xef, 0x0b, 0x59, 0xf7, 0xc1, 0x5f, 0x0f, 0xa4, 0x21, 0x93, 0x90, + 0x27, 0x80, 0x21, 0x29, 0xe5, 0x7d, 0x12, 0xfd, 0x0e, 0x27, 0x0b, 0x42, + 0x8e, 0xcd, 0x12, 0x50, 0x96, 0x5b, 0x94, 0xa0, 0x3e, 0x29, 0xee, 0x1a, + 0x6f, 0xc5, 0x07, 0x9a, 0xef, 0xbc, 0x9e, 0x9e, 0x8b, 0x6f, 0x99, 0x96, + 0x78, 0x3b, 0x2c, 0xd2, 0xc5, 0x05, 0x91, 0x96, 0x5e, 0x39, 0x06, 0xb2, + 0x0f, 0x34, 0xa5, 0x98, 0x98, 0x67, 0xd9, 0x4e, 0x92, 0xb8, 0x46, 0xc0, + 0x7a, 0xf4, 0xf2, 0x90, 0x97, 0xcf, 0x33, 0x9e, 0x0b, 0xb7, 0xf3, 0xef, + 0xa5, 0xa5, 0xbf, 0x97, 0xf9, 0x04, 0x46, 0xea, 0x31, 0x21, 0x94, 0x61, + 0x19, 0x17, 0xd1, 0x9d, 0xe7, 0xfa, 0x3a, 0xaa, 0x52, 0x55, 0x46, 0x72, + 0x1b, 0x97, 0xd9, 0x6b, 0x5e, 0x3d, 0x15, 0x83, 0x55, 0x01, 0x95, 0x52, + 0x27, 0xd1, 0x0c, 0x41, 0x90, 0x67, 0x44, 0x7d, 0x4f, 0xd8, 0x7a, 0x3e, + 0x9f, 0xae, 0xc3, 0x00, 0x86, 0xc3, 0xc2, 0x06, 0xd8, 0x99, 0xb4, 0xfc, + 0x00, 0xbf, 0x8e, 0xa3, 0x0c, 0xf9, 0x14, 0x48, 0x2a, 0xb0, 0x5e, 0xf8, + 0xfe, 0x6b, 0x83, 0x13, 0xaa, 0x94, 0xd0, 0x62, 0x9b, 0xbb, 0xa7, 0x33, + 0x26, 0x18, 0xca, 0x60, 0x48, 0x0c, 0x5c, 0xe3, 0x13, 0x94, 0x24, 0xfe, + 0x00, 0xf3, 0x1f, 0xa2, 0x2f, 0xae, 0x49, 0x92, 0xe7, 0xf6, 0x49, 0x1e, + 0xf7, 0x57, 0x4c, 0xe5, 0x4c, 0x5f, 0x8c, 0xa3, 0xdc, 0x70, 0xbe, 0x5b, + 0x8c, 0x3c, 0xdb, 0xd3, 0x84, 0x02, 0x6e, 0xdc, 0xd5, 0x6a, 0xc9, 0xc2, + 0x5f, 0x95, 0x3a, 0x2d, 0x44, 0x87, 0x09, 0x52, 0x90, 0x41, 0x1f, 0xa8, + 0x93, 0x76, 0xae, 0x53, 0xd3, 0xef, 0x26, 0x15, 0x27, 0x38, 0x04, 0xc7, + 0xda, 0xed, 0xb1, 0x11, 0xe8, 0x2a, 0x67, 0x03, 0xd0, 0xfe, 0x5f, 0x85, + 0xfc, 0xa0, 0x6a, 0x73, 0x6e, 0xac, 0x15, 0x8d, 0xa2, 0xca, 0x5b, 0x32, + 0x52, 0xc1, 0x2e, 0xf4, 0xe6, 0x68, 0x99, 0xbd, 0xeb, 0x05, 0x4e, 0x8f, + 0xb7, 0x5c, 0xd1, 0x31, 0x5b, 0x17, 0x98, 0x81, 0xef, 0x69, 0x3d, 0x23, + 0x01, 0xc3, 0x34, 0xc7, 0x69, 0x39, 0x5e, 0xb3, 0x1e, 0x99, 0xa6, 0xbf, + 0x78, 0xee, 0x88, 0xe2, 0xdb, 0xd7, 0x4e, 0x17, 0xa0, 0x27, 0x0f, 0xe6, + 0x9f, 0x9f, 0x74, 0x0c, 0xa4, 0xd2, 0x47, 0xe3, 0xc1, 0xb5, 0xc9, 0x13, + 0xaa, 0x72, 0x22, 0xbb, 0x7d, 0xd6, 0xb8, 0x76, 0x6c, 0x5e, 0xd5, 0xf7, + 0x22, 0x69, 0x7c, 0x40, 0x4f, 0x64, 0xcd, 0x02, 0x43, 0x4a, 0x09, 0x1d, + 0x95, 0x90, 0x16, 0x3f, 0xaa, 0x4d, 0xdf, 0x5d, 0xea, 0x76, 0xb0, 0x52, + 0x92, 0xa1, 0xde, 0xd6, 0x2f, 0x66, 0x7d, 0x53, 0x65, 0xb4, 0xa6, 0x3e, + 0x0a, 0x85, 0x03, 0x56, 0x82, 0x6f, 0x17, 0xe6, 0xb6, 0xef, 0x0f, 0x4e, + 0x01, 0xc5, 0xba, 0x01, 0xdb, 0x23, 0x4c, 0x9f, 0x11, 0x59, 0x28, 0x71, + 0xc4, 0xf2, 0xeb, 0x00, 0xa9, 0x72, 0x7b, 0xd7, 0x02, 0x94, 0xd8, 0xaf, + 0xad, 0x16, 0x92, 0x51, 0xea, 0xe4, 0xb6, 0xf6, 0xe1, 0x80, 0xaf, 0x6b, + 0x0d, 0x2c, 0xbc, 0x6f, 0xb4, 0x0c, 0xa9, 0xd4, 0xf8, 0xb8, 0x19, 0xc5, + 0x69, 0x5d, 0x8f, 0xce, 0x4b, 0x98, 0x11, 0xae, 0x66, 0x19, 0x66, 0x6e, + 0xe5, 0x88, 0xc9, 0x23, 0xf5, 0xc6, 0x3d, 0x52, 0x4d, 0x5a, 0x6d, 0x5e, + 0xdc, 0x00, 0x21, 0x41, 0x53, 0xab, 0x97, 0x3d, 0xa3, 0xfb, 0xd9, 0xdf, + 0x90, 0x77, 0xeb, 0x4f, 0x8d, 0xec, 0xca, 0x17, 0xad, 0x65, 0xb9, 0x92, + 0x0c, 0x24, 0xd4, 0x80, 0x19, 0x78, 0x49, 0x7d, 0x9b, 0xcf, 0xdd, 0xaf, + 0xfd, 0xb8, 0xdd, 0x89, 0x4b, 0xe5, 0xb9, 0x99, 0x9b, 0x70, 0x24, 0xc5, + 0x86, 0x42, 0x92, 0x2c, 0x47, 0xd5, 0x1a, 0x50, 0x5d, 0x4d, 0xcf, 0xdc, + 0xb4, 0x19, 0x9a, 0xe2, 0x94, 0x5f, 0x1b, 0x19, 0x40, 0xd3, 0x5c, 0xe3, + 0x09, 0xe3, 0x7c, 0x15, 0x60, 0x49, 0xf7, 0xf9, 0xdb, 0x8e, 0x38, 0x69, + 0xfa, 0xa2, 0xe6, 0x18, 0x11, 0xc3, 0x57, 0xa0, 0xec, 0x1b, 0x43, 0x3a, + 0xb1, 0x5a, 0x6a, 0xcd, 0x5a, 0x2e, 0x59, 0x10, 0x8b, 0xc1, 0xfc, 0xbd, + 0x75, 0xc9, 0x5e, 0x5c, 0xe2, 0x28, 0xb8, 0x72, 0xbc, 0xb3, 0x8a, 0x5e, + 0x82, 0x32, 0x50, 0xa3, 0xe0, 0x77, 0xf6, 0xe0, 0x46, 0xbe, 0xda, 0x52, + 0xa5, 0x13, 0xa5, 0x99, 0xcd, 0xc3, 0x55, 0x31, 0x83, 0x10, 0x72, 0xa3, + 0x2d, 0x14, 0x49, 0xda, 0x57, 0x81, 0xd7, 0x7f, 0xbd, 0x29, 0x6d, 0xb8, + 0x21, 0xe4, 0x4b, 0x58, 0x99, 0x74, 0x84, 0xef, 0x77, 0xd6, 0x92, 0xe0, + 0x81, 0xe1, 0xc0, 0x3c, 0x10, 0x81, 0xf9, 0xa9, 0xaa, 0x63, 0x74, 0x98, + 0x91, 0xa8, 0x72, 0x16, 0xa6, 0xf3, 0xf9, 0x89, 0xe4, 0xe6, 0x48, 0xac, + 0x50, 0x65, 0x11, 0x4c, 0xef, 0xfe, 0xcf, 0x89, 0xd3, 0x9f, 0xc1, 0xfc, + 0xdc, 0xea, 0x75, 0x19, 0xc7, 0xd0, 0x12, 0xaf, 0x20, 0x64, 0x82, 0x08, + 0x8e, 0xc8, 0x0f, 0x15, 0x51, 0x7b, 0xe2, 0x6b, 0xb0, 0x1c, 0xcd, 0xad, + 0xd1, 0x77, 0x2d, 0xad, 0xa0, 0xec, 0x81, 0xa7, 0xa8, 0x28, 0xcd, 0xb1, + 0xcc, 0xa5, 0x43, 0xc4, 0x5b, 0xb8, 0x9c, 0x84, 0xa5, 0x2c, 0xac, 0xba, + 0xc0, 0x2a, 0x61, 0xc7, 0xf1, 0xb6, 0x57, 0x56, 0xe5, 0xca, 0x96, 0xbb, + 0xfb, 0x8e, 0x49, 0x3e, 0x50, 0x2f, 0x36, 0x73, 0x5b, 0x44, 0x5b, 0x36, + 0x9c, 0xa0, 0x90, 0xc6, 0x96, 0x4e, 0x73, 0x1f, 0x68, 0x47, 0x43, 0xd3, + 0x6b, 0x1f, 0x4d, 0x43, 0x1e, 0xbf, 0x1c, 0x28, 0xe9, 0xf5, 0x3d, 0xac, + 0x48, 0x4c, 0xd4, 0x6d, 0x32, 0x25, 0xf3, 0x71, 0x29, 0xe9, 0xf0, 0x08, + 0x2a, 0xd2, 0x75, 0xc1, 0xa6, 0x5f, 0x1f, 0xca, 0xbb, 0x76, 0x91, 0xdc, + 0xca, 0x13, 0x3b, 0x18, 0xd9, 0x66, 0x48, 0xb0, 0x29, 0x01, 0x39, 0xfd, + 0x35, 0x8b, 0xd7, 0xac, 0xeb, 0xe3, 0x92, 0x96, 0xef, 0xe1, 0x7e, 0xd7, + 0xd0, 0xe9, 0xd6, 0xcf, 0xd7, 0x28, 0x58, 0x0a, 0x20, 0xcc, 0xc1, 0x8a, + 0x45, 0x45, 0xe0, 0x71, 0xca, 0x66, 0x75, 0xb0, 0x97, 0x89, 0x13, 0x7b, + 0xa3, 0x27, 0x5d, 0xce, 0x36, 0x58, 0xf6, 0x0a, 0x66, 0xf5, 0x83, 0xc8, + 0xef, 0x6e, 0x6f, 0x98, 0x79, 0x52, 0xd7, 0xd4, 0xa3, 0x3f, 0xda, 0x70, + 0xe2, 0x41, 0x10, 0x55, 0x20, 0x71, 0xb0, 0xd8, 0xd9, 0x14, 0x19, 0xc6, + 0x76, 0x0d, 0x45, 0x78, 0xb5, 0x70, 0x88, 0x65, 0x5a, 0x6b, 0xeb, 0x2f, + 0x28, 0x38, 0xf9, 0xbc, 0x28, 0xbe, 0xca, 0x44, 0x86, 0x4e, 0xd4, 0x29, + 0xc6, 0x16, 0xca, 0x3e, 0xb7, 0x33, 0x58, 0x04, 0x33, 0x7c, 0xac, 0xb5, + 0x9f, 0xf9, 0xfd, 0x6d, 0xb9, 0xff, 0x5a, 0x35, 0xa6, 0xd8, 0xa5, 0x28, + 0x30, 0xf5, 0x16, 0x95, 0xa9, 0x14, 0x65, 0x97, 0x56, 0x01, 0x4d, 0xf8, + 0x71, 0xc9, 0x93, 0xad, 0xac, 0x97, 0x1d, 0xab, 0x70, 0x21, 0x2d, 0xf3, + 0x26, 0x16, 0x66, 0xcb, 0xa2, 0x67, 0x56, 0x09, 0xd9, 0x9d, 0x9c, 0xec, + 0x37, 0x4d, 0x71, 0xbd, 0xef, 0xaf, 0x22, 0x78, 0xd9, 0x4c, 0xdd, 0xab, + 0x9a, 0x12, 0x28, 0x7d, 0xb4, 0xd4, 0x9c, 0x01, 0xf2, 0x85, 0x2f, 0xbc, + 0x58, 0x77, 0x85, 0x32, 0xdf, 0x4e, 0x79, 0x41, 0x41, 0xda, 0x6e, 0x9f, + 0x60, 0x09, 0x82, 0xf4, 0x50, 0x15, 0x68, 0x0f, 0xfd, 0x0b, 0x5b, 0x09, + 0x33, 0x98, 0x9c, 0x92, 0x1d, 0xc1, 0x38, 0xbe, 0xdc, 0x17, 0xbe, 0x88, + 0xa8, 0xa6, 0x88, 0xa2, 0x0f, 0x81, 0xcd, 0xb6, 0xde, 0x42, 0xc7, 0x7d, + 0x53, 0xc6, 0xab, 0xd3, 0x94, 0x9d, 0x2e, 0x79, 0x2f, 0x0b, 0x76, 0x63, + 0x36, 0xa5, 0x85, 0x7f, 0x94, 0x07, 0x53, 0xe7, 0xa8, 0x6a, 0x0d, 0xb1, + 0xda, 0x1f, 0xad, 0xb6, 0x5b, 0x13, 0xe7, 0x21, 0xcc, 0xe7, 0x29, 0x09, + 0x48, 0x1a, 0x19, 0x7e, 0x22, 0x1b, 0x1b, 0xe5, 0xf2, 0x1a, 0x08, 0x25, + 0x30, 0xca, 0xf1, 0xd6, 0x97, 0x56, 0x3a, 0xa7, 0x3f, 0x0b, 0xce, 0xaf, + 0xfc, 0x50, 0x24, 0x34, 0xab, 0xf0, 0x9c, 0x91, 0x12, 0xc0, 0x4f, 0xd5, + 0xed, 0xa4, 0xf4, 0xe4, 0x36, 0x54, 0x49, 0xed, 0x36, 0x61, 0x6d, 0xa4, + 0x1e, 0x63, 0x24, 0x3c, 0x40, 0xb0, 0xb2, 0x44, 0xe3, 0x6d, 0xf2, 0xa6, + 0x96, 0x97, 0xe9, 0x97, 0xd4, 0x76, 0x80, 0x0c, 0x6d, 0xa8, 0xb1, 0x39, + 0x48, 0x48, 0x7c, 0x1b, 0x46, 0x9e, 0x94, 0x7a, 0xbf, 0xfd, 0xc6, 0xff, + 0x72, 0xf0, 0x4d, 0x4b, 0x22, 0x46, 0x32, 0x8e, 0x51, 0x23, 0xe7, 0xb2, + 0xe7, 0xa7, 0x05, 0x38, 0xb9, 0x25, 0xcc, 0xe2, 0xbf, 0x08, 0xff, 0x77, + 0xf9, 0xb6, 0x37, 0xcd, 0x29, 0x47, 0xc3, 0x10, 0xe4, 0xc9, 0xd5, 0xaa, + 0x41, 0xe8, 0x6c, 0x6d, 0x17, 0xa2, 0x8a, 0x08, 0xcc, 0xde, 0xa3, 0xcb, + 0xeb, 0x66, 0x86, 0x2c, 0x0b, 0xd3, 0xeb, 0xb3, 0x4b, 0x9e, 0x64, 0x70, + 0xf3, 0xa2, 0x8e, 0x30, 0x14, 0x32, 0x09, 0xea, 0xbd, 0x57, 0x4b, 0x6b, + 0x1e, 0xa3, 0x12, 0x01, 0xc2, 0x46, 0x65, 0x23, 0xe9, 0xac, 0x21, 0xb2, + 0xba, 0x60, 0xef, 0x6e, 0xa8, 0x32, 0x16, 0x1b, 0x69, 0x41, 0x23, 0x93, + 0xfb, 0x48, 0x7a, 0xb3, 0xe2, 0xab, 0x9b, 0x1a, 0x44, 0xce, 0x8a, 0x35, + 0xfc, 0x87, 0x3e, 0xe4, 0xa5, 0xec, 0xcf, 0x98, 0x04, 0x32, 0xc2, 0x32, + 0x4b, 0x48, 0x96, 0xed, 0x6a, 0xd1, 0xca, 0x3a, 0xf0, 0xb9, 0x32, 0x14, + 0xe3, 0x11, 0x23, 0x87, 0x09, 0x49, 0x59, 0x20, 0x6b, 0x3a, 0xb7, 0xc5, + 0xa7, 0xb3, 0x86, 0xd1, 0x87, 0x0d, 0xcf, 0x04, 0x92, 0x2a, 0x87, 0xa4, + 0x36, 0xc9, 0x03, 0x3f, 0x05, 0x2f, 0x39, 0xad, 0xfb, 0xbb, 0x25, 0x0c, + 0xbe, 0x23, 0xe4, 0x18, 0x1c, 0x24, 0x71, 0xd1, 0x6c, 0xba, 0x6a, 0xba, + 0xa6, 0xa7, 0x93, 0x08, 0x43, 0x92, 0x13, 0xfa, 0x02, 0xe0, 0x0e, 0xf6, + 0x26, 0x20, 0x11, 0x5c, 0x4f, 0x54, 0xc0, 0xb2, 0x0b, 0x5e, 0x79, 0x41, + 0xd9, 0x03, 0xd8, 0x4f, 0xb4, 0x60, 0xf7, 0x2c, 0xbd, 0xd8, 0xcd, 0xdd, + 0x19, 0xee, 0x46, 0x5f, 0x44, 0x2b, 0x57, 0x3f, 0xe3, 0x6b, 0x41, 0x4b, + 0x63, 0x19, 0x2b, 0x69, 0xb3, 0xe4, 0x14, 0xe0, 0xfc, 0x70, 0x6f, 0xc5, + 0x9e, 0xe2, 0x56, 0xfe, 0x62, 0xc7, 0x2b, 0x68, 0x43, 0x34, 0xb0, 0xf8, + 0x71, 0xd9, 0x0e, 0xbd, 0x20, 0x29, 0x83, 0xf1, 0xfe, 0xed, 0xec, 0xd5, + 0xeb, 0x12, 0xc9, 0x13, 0x9d, 0x1f, 0xb4, 0xce, 0x39, 0xd8, 0x15, 0xa9, + 0x6c, 0x24, 0x8d, 0x6f, 0xc5, 0x0a, 0x0c, 0xa2, 0x7e, 0x29, 0x67, 0xf1, + 0x3a, 0xf8, 0xd6, 0xd0, 0x3b, 0x28, 0x30, 0x94, 0x0c, 0x28, 0x77, 0x06, + 0x79, 0x3f, 0xfc, 0x67, 0xf2, 0x76, 0x8b, 0xb5, 0xc0, 0x4a, 0x1a, 0x79, + 0x9c, 0x04, 0xef, 0xc1, 0x61, 0x0e, 0xe9, 0xe0, 0xf3, 0x4a, 0x03, 0x00, + 0xf1, 0x4a, 0xa6, 0x66, 0x51, 0x53, 0x76, 0x35, 0x72, 0xc7, 0x59, 0x4b, + 0x34, 0x34, 0xc9, 0x1d, 0x91, 0x21, 0x1a, 0x5f, 0xb6, 0x81, 0x9e, 0x7a, + 0x62, 0x4a, 0xb8, 0x54, 0xb7, 0xdf, 0xe7, 0xd7, 0xb0, 0x5f, 0xa8, 0x1c, + 0x93, 0xae, 0x94, 0x3d, 0x82, 0x83, 0xe7, 0x9c, 0x50, 0x79, 0xa5, 0x03, + 0xf2, 0x3f, 0x19, 0xd7, 0x3f, 0x5f, 0x33, 0xf1, 0x5b, 0x65, 0x03, 0x4d, + 0x40, 0x88, 0x66, 0x67, 0x3f, 0x16, 0x8e, 0x7c, 0x4f, 0xd6, 0x15, 0xb3, + 0x1d, 0xed, 0x86, 0xc7, 0x2b, 0x82, 0x4e, 0x4e, 0xc1, 0x9b, 0x25, 0xc1, + 0xf5, 0x3f, 0x6e, 0xde, 0xbd, 0x23, 0x44, 0xa1, 0xb4, 0x84, 0xfb, 0x0a, + 0x95, 0x59, 0x57, 0x60, 0x73, 0x54, 0xcf, 0x4d, 0x2d, 0x5d, 0x8d, 0xc3, + 0xc8, 0x2a, 0x98, 0x7d, 0xb2, 0x59, 0x94, 0xe6, 0x90, 0x43, 0xed, 0xa2, + 0xc2, 0x13, 0x33, 0xf5, 0xee, 0x21, 0x72, 0x82, 0xaa, 0x33, 0xfc, 0x92, + 0x15, 0xc1, 0xf6, 0xef, 0x7d, 0xdf, 0x25, 0x8a, 0xbe, 0x36, 0xe8, 0x69, + 0x91, 0x42, 0x93, 0x4f, 0x1d, 0xc4, 0x92, 0xa5, 0xf3, 0xc1, 0x5d, 0x3d, + 0x1b, 0x36, 0xd7, 0xc4, 0x35, 0x7d, 0xe5, 0x02, 0x5b, 0xca, 0x8f, 0xcc, + 0x0c, 0x86, 0x7b, 0x20, 0xbc, 0xc2, 0xc1, 0x6f, 0x5a, 0x7c, 0xfe, 0x66, + 0x6d, 0xeb, 0x5e, 0xa5, 0xba, 0xbe, 0x26, 0xd3, 0xda, 0xe8, 0x51, 0x26, + 0x57, 0xac, 0xcf, 0x3f, 0x86, 0x1d, 0x38, 0x71, 0xa4, 0x35, 0x70, 0xe9, + 0x50, 0x02, 0x72, 0xc2, 0x22, 0x79, 0x78, 0xeb, 0x7d, 0xcf, 0xc7, 0x87, + 0xbc, 0x7e, 0xc7, 0x1c, 0x8d, 0x13, 0x44, 0xf3, 0xd0, 0x8a, 0x25, 0xf6, + 0xf7, 0x3c, 0xd9, 0x6f, 0xf2, 0x37, 0x9e, 0xad, 0x33, 0x43, 0x86, 0x40, + 0x4e, 0x90, 0x92, 0x33, 0x8c, 0x49, 0x90, 0x26, 0xf5, 0x25, 0x7d, 0xfe, + 0xf7, 0x16, 0x7e, 0x57, 0xef, 0xde, 0x6f, 0x2f, 0x93, 0xbe, 0x57, 0xda, + 0xae, 0x04, 0x35, 0x40, 0xcc, 0x4d, 0x72, 0x03, 0x2b, 0xb8, 0x1a, 0xfb, + 0xda, 0x1b, 0xb6, 0xff, 0x86, 0x6b, 0x76, 0xa6, 0xee, 0x71, 0xdd, 0xe8, + 0x10, 0xd8, 0x00, 0x94, 0x00, 0xa4, 0x6b, 0x00, 0x46, 0xd3, 0x8d, 0x16, + 0x64, 0x4c, 0x21, 0xd5, 0xc0, 0xca, 0x64, 0x44, 0xd2, 0xe6, 0xee, 0x4f, + 0xc4, 0xfa, 0x35, 0x45, 0x64, 0xc5, 0x51, 0xa8, 0x7c, 0x14, 0x77, 0xeb, + 0x97, 0x87, 0x0b, 0xae, 0x1d, 0x9c, 0x6e, 0x0d, 0xba, 0xb8, 0xa8, 0x8c, + 0xc8, 0x97, 0xd7, 0xb5, 0x43, 0xf3, 0x6b, 0x2d, 0x86, 0xdd, 0x01, 0xf6, + 0x07, 0xde, 0x7d, 0x7f, 0xb7, 0x3c, 0xe2, 0x30, 0x6b, 0x98, 0x99, 0xce, + 0xa6, 0xcb, 0x18, 0xa4, 0xa7, 0x3b, 0xc9, 0x62, 0xb9, 0x61, 0x3c, 0x87, + 0xe0, 0x7f, 0x85, 0x0f, 0xda, 0x1f, 0x83, 0x76, 0x6e, 0x9c, 0x53, 0x95, + 0x0c, 0x75, 0xe3, 0xc2, 0x90, 0x91, 0x96, 0x54, 0x87, 0x70, 0xcf, 0xb6, + 0x84, 0xe2, 0xbe, 0x31, 0xe5, 0x4a, 0x79, 0x00, 0x4a, 0x25, 0x06, 0x54, + 0x19, 0x39, 0x4d, 0x14, 0x28, 0xfd, 0x71, 0x91, 0xa2, 0x69, 0xee, 0x2b, + 0xa2, 0x88, 0x97, 0x37, 0x4f, 0x3e, 0xfa, 0xb7, 0x2a, 0x41, 0x55, 0x10, + 0xdf, 0xc4, 0x24, 0xfc, 0xde, 0xa9, 0x45, 0x74, 0xb5, 0xb9, 0xee, 0xef, + 0xd7, 0xb3, 0x8d, 0xc3, 0x41, 0x0c, 0xe8, 0x23, 0x5e, 0x41, 0x29, 0x83, + 0x23, 0x90, 0xc9, 0xf1, 0x54, 0x0e, 0xb8, 0xbf, 0x95, 0x5a, 0x28, 0x2c, + 0x5d, 0xd2, 0xd6, 0x50, 0x60, 0x5b, 0x1d, 0xbe, 0x64, 0x4d, 0x10, 0x28, + 0x92, 0x87, 0x88, 0x7d, 0x3f, 0x8d, 0xaf, 0xfc, 0x0f, 0x0c, 0x00, 0xa3, + 0x29, 0xd2, 0x10, 0x8b, 0xd9, 0x14, 0xb8, 0x3b, 0x81, 0x76, 0x64, 0xc2, + 0x97, 0xbe, 0x6f, 0x92, 0x61, 0x8b, 0xb7, 0x05, 0xbd, 0x3e, 0x6d, 0x54, + 0x50, 0x0c, 0x87, 0x95, 0x97, 0xf4, 0x49, 0x2d, 0x06, 0xac, 0xb8, 0xa9, + 0x31, 0xd3, 0x76, 0x92, 0x4a, 0xa3, 0xd9, 0x1f, 0xf4, 0x08, 0xd9, 0x29, + 0x49, 0xa9, 0xe3, 0x65, 0xee, 0x68, 0x60, 0x12, 0x97, 0xcc, 0xfc, 0xe1, + 0x5d, 0x26, 0xcc, 0xbe, 0xa8, 0x4e, 0xdd, 0x9a, 0x28, 0x21, 0xc3, 0x41, + 0x2f, 0x8a, 0x4e, 0x60, 0xb7, 0x03, 0x8c, 0x1f, 0x6f, 0x05, 0x5e, 0x99, + 0x73, 0x33, 0x43, 0xd2, 0xe7, 0x22, 0x75, 0xbc, 0x98, 0xe0, 0x34, 0x7e, + 0x2c, 0xb0, 0x0f, 0xa9, 0xee, 0xbc, 0x82, 0xa8, 0x1d, 0xa0, 0xd0, 0x95, + 0x5e, 0xa1, 0x33, 0x95, 0xf4, 0xdb, 0xe0, 0xf5, 0x3c, 0x1c, 0xa4, 0x5e, + 0x12, 0x08, 0x40, 0x7c, 0xc6, 0x12, 0x22, 0xb3, 0x6d, 0x81, 0xa2, 0x88, + 0xac, 0x97, 0x6f, 0x2a, 0xc9, 0xd6, 0xde, 0x6b, 0xb6, 0x02, 0x58, 0x18, + 0x40, 0xc7, 0x92, 0x06, 0x63, 0x26, 0x11, 0x98, 0xf1, 0x05, 0x50, 0x73, + 0x37, 0x4c, 0xcf, 0x8e, 0x77, 0xe6, 0x0f, 0x6e, 0x4f, 0x36, 0x5e, 0x7a, + 0x94, 0xd1, 0x13, 0xa5, 0xb1, 0x22, 0x0c, 0x20, 0xa1, 0x97, 0x8c, 0x7e, + 0xcb, 0xf9, 0xfa, 0x17, 0x4a, 0x4a, 0x40, 0x5e, 0xef, 0xe6, 0x48, 0x6c, + 0x3b, 0x18, 0xca, 0x2c, 0x67, 0x91, 0x09, 0x85, 0x6a, 0xcd, 0xdd, 0xdb, + 0xdb, 0x82, 0x07, 0xa7, 0x57, 0xa2, 0x42, 0x84, 0xf8, 0xe7, 0xd2, 0xbe, + 0x8b, 0x80, 0xe4, 0xda, 0x07, 0x4e, 0xcc, 0x11, 0xc9, 0xf6, 0x5f, 0x5e, + 0x22, 0xcd, 0xf3, 0x82, 0xa9, 0x6d, 0x7a, 0xc4, 0x26, 0x70, 0xec, 0x1d, + 0x6a, 0x79, 0x7f, 0x37, 0x28, 0x88, 0x1a, 0x53, 0x84, 0xf8, 0x00, 0xad, + 0x47, 0x7b, 0xfe, 0x19, 0xc9, 0xac, 0xab, 0x55, 0x76, 0xde, 0x4b, 0x6d, + 0x6f, 0x2e, 0x77, 0xca, 0xd7, 0x4e, 0x73, 0x18, 0xcd, 0xc3, 0x41, 0xac, + 0x39, 0x9a, 0x22, 0xac, 0xbf, 0xd2, 0xc0, 0xec, 0x4c, 0x54, 0xfb, 0xb9, + 0x76, 0x39, 0xd4, 0xcf, 0x63, 0xd6, 0xd6, 0x3c, 0xfe, 0x6f, 0xc0, 0x22, + 0xc0, 0x14, 0x36, 0xb8, 0x02, 0x19, 0x1e, 0x6a, 0x8b, 0xa3, 0x39, 0x78, + 0x1a, 0x82, 0x9e, 0x78, 0xf6, 0x58, 0xdb, 0x2e, 0x0a, 0x70, 0xc3, 0xa7, + 0x45, 0x41, 0x19, 0x8d, 0xca, 0x91, 0xed, 0x28, 0x12, 0x8c, 0xbb, 0x91, + 0xbd, 0xb3, 0xf0, 0x6a, 0xff, 0x79, 0x7f, 0xdf, 0xbc, 0x03, 0x6c, 0x4f, + 0x05, 0xe1, 0xaf, 0x39, 0x14, 0x37, 0x08, 0xbd, 0xd8, 0xa5, 0x3a, 0x0d, + 0xe2, 0x65, 0xdd, 0x9f, 0x80, 0x0c, 0xca, 0xd2, 0x19, 0x36, 0x1d, 0x84, + 0xfa, 0xa0, 0xa7, 0xb3, 0x26, 0x14, 0x4e, 0x53, 0xb5, 0x98, 0x15, 0x7b, + 0x53, 0x55, 0xc7, 0x55, 0x59, 0x65, 0xf7, 0xf9, 0xb5, 0x6b, 0x96, 0x59, + 0x7d, 0xb6, 0xf2, 0xab, 0x6f, 0x4e, 0x48, 0xa1, 0x30, 0x18, 0x01, 0x2a, + 0x3e, 0x20, 0x3a, 0xc6, 0x6d, 0x2a, 0x23, 0x0d, 0x17, 0x3d, 0x66, 0x30, + 0xe5, 0xe5, 0xac, 0x86, 0x84, 0x08, 0x01, 0x7a, 0xcc, 0xed, 0xf9, 0xfa, + 0x83, 0xcf, 0x09, 0x95, 0xdf, 0xf8, 0xed, 0x8c, 0x12, 0x7d, 0xf0, 0xcc, + 0x3e, 0x35, 0xfe, 0x10, 0x50, 0xed, 0x35, 0xcc, 0x8a, 0x13, 0x18, 0x67, + 0x22, 0x79, 0x04, 0xd8, 0x43, 0xd2, 0x38, 0xb3, 0xe8, 0x4c, 0x57, 0x6b, + 0xab, 0xfa, 0x95, 0x4e, 0x2c, 0x5e, 0x14, 0x0e, 0x7e, 0x06, 0xd6, 0x7d, + 0xcd, 0xe9, 0xb7, 0xbb, 0x8b, 0x76, 0x35, 0xe5, 0xf1, 0x87, 0x6c, 0x92, + 0x2c, 0x44, 0x8e, 0x59, 0xa3, 0x84, 0x27, 0x55, 0xaa, 0xe7, 0x8a, 0xda, + 0x3a, 0x08, 0xa3, 0x3c, 0x94, 0x69, 0x07, 0x98, 0xf9, 0x33, 0x0a, 0xe8, + 0xfe, 0xfd, 0x7e, 0x55, 0x0c, 0x5b, 0x81, 0xba, 0x56, 0xb4, 0x86, 0xd9, + 0xca, 0x80, 0xc8, 0x12, 0xe8, 0x83, 0x8d, 0x51, 0x04, 0xb9, 0xcf, 0xe8, + 0x0f, 0x34, 0x97, 0xe7, 0x3b, 0xab, 0xaf, 0x85, 0x7f, 0x6f, 0x38, 0x1e, + 0x7b, 0xd8, 0x54, 0x31, 0xa7, 0x82, 0x4f, 0x2c, 0xa0, 0xff, 0x18, 0x73, + 0x8f, 0xbc, 0x57, 0xfe, 0x8f, 0x7f, 0xe5, 0x34, 0xfa, 0x16, 0x59, 0xa5, + 0x36, 0x3c, 0x01, 0x22, 0x89, 0x33, 0x99, 0x73, 0x93, 0xf1, 0x6b, 0x99, + 0xe3, 0xaa, 0xab, 0xf0, 0x37, 0x21, 0x09, 0xb2, 0x5d, 0x5a, 0x61, 0x89, + 0xb9, 0x62, 0xaf, 0x90, 0x3f, 0x8a, 0x42, 0x9d, 0x6b, 0x41, 0x86, 0x00, + 0x51, 0x78, 0x28, 0x41, 0x37, 0x35, 0x84, 0x73, 0xc6, 0x1e, 0x42, 0x52, + 0x91, 0x4a, 0x93, 0xce, 0x78, 0x0a, 0x08, 0x51, 0xec, 0x92, 0x15, 0x48, + 0x58, 0xe4, 0x94, 0x48, 0xbb, 0x8b, 0xd7, 0xf6, 0x5b, 0xac, 0x69, 0x5f, + 0x9a, 0x9d, 0x6c, 0xd9, 0x8e, 0xef, 0xb0, 0x71, 0xf8, 0x1a, 0xc4, 0xa8, + 0x90, 0x93, 0xec, 0x1a, 0x66, 0xbd, 0x29, 0x0f, 0xa9, 0xce, 0xf1, 0x65, + 0xb2, 0xc7, 0xb4, 0x4a, 0x92, 0x3d, 0x94, 0xcb, 0xae, 0x15, 0xc8, 0x99, + 0x44, 0x6d, 0x82, 0x00, 0x89, 0x20, 0x96, 0x97, 0x38, 0xd0, 0x5b, 0x8e, + 0xfa, 0x6d, 0x6a, 0x40, 0xa0, 0x72, 0xb2, 0x92, 0x27, 0xb5, 0xbc, 0x34, + 0x50, 0xfa, 0x5f, 0x1a, 0xfa, 0xe5, 0xdd, 0x75, 0x76, 0xb7, 0x7c, 0x19, + 0xbb, 0xe2, 0x89, 0x31, 0xab, 0xc9, 0x59, 0x72, 0x19, 0x7f, 0x3e, 0x60, + 0x9c, 0x8d, 0x4d, 0xdf, 0x90, 0xea, 0xcb, 0x65, 0xca, 0x03, 0x96, 0x59, + 0x22, 0x32, 0x8c, 0xfc, 0x0c, 0x97, 0x1f, 0x39, 0x75, 0xff, 0xd1, 0x79, + 0x9b, 0xce, 0x89, 0xd2, 0xe5, 0x8d, 0x04, 0xf0, 0xe2, 0x59, 0x48, 0xd0, + 0xf9, 0xc3, 0xbe, 0xee, 0x58, 0x06, 0xb7, 0xe6, 0xd1, 0x80, 0x6b, 0x13, + 0xb4, 0x41, 0x11, 0x06, 0x51, 0x8c, 0x66, 0xf9, 0x7e, 0x34, 0x07, 0xc1, + 0x4f, 0xfe, 0x9b, 0x31, 0xdf, 0x1e, 0x62, 0x44, 0xe7, 0x26, 0xc6, 0xa2, + 0x28, 0x25, 0x22, 0x28, 0xf8, 0x8d, 0xad, 0x27, 0x0b, 0xc7, 0x78, 0x01, + 0x82, 0x8c, 0x15, 0xe7, 0x96, 0x55, 0x1c, 0x63, 0xf1, 0xcc, 0x5d, 0xba, + 0x89, 0xbf, 0x1a, 0xd9, 0x98, 0xaf, 0xa1, 0x87, 0x6c, 0x8c, 0x86, 0xf4, + 0x4f, 0xc7, 0xf3, 0x13, 0x7c, 0x94, 0x5d, 0x95, 0x46, 0xbf, 0xad, 0x0d, + 0x9d, 0x3c, 0xe8, 0x12, 0x88, 0x99, 0x92, 0x5a, 0x15, 0x62, 0x50, 0xdb, + 0x67, 0x7a, 0xf3, 0x53, 0x6d, 0x5a, 0xd2, 0x12, 0x2f, 0x2e, 0xd0, 0x50, + 0x22, 0x8c, 0x3f, 0x3b, 0x45, 0x54, 0x5c, 0x54, 0x35, 0xe7, 0xb3, 0x78, + 0xf5, 0x10, 0x53, 0x38, 0xd8, 0xa1, 0x5f, 0x28, 0xe4, 0xc1, 0xf0, 0x66, + 0x54, 0x56, 0xdb, 0xed, 0xff, 0xd3, 0x60, 0x08, 0x41, 0xb5, 0xa0, 0x41, + 0x8c, 0x51, 0x96, 0x60, 0x0e, 0x3a, 0x5a, 0xf0, 0x13, 0xbc, 0x49, 0xd5, + 0xf9, 0xd7, 0xcf, 0xcc, 0x04, 0x20, 0x97, 0x64, 0x1a, 0xe6, 0x36, 0x03, + 0xa1, 0x4b, 0xaf, 0x34, 0x1d, 0x06, 0x31, 0x80, 0x8c, 0x0a, 0x5c, 0xf0, + 0x93, 0x03, 0xde, 0xb3, 0xd9, 0xca, 0xda, 0x9e, 0xd8, 0x99, 0xce, 0x9b, + 0xef, 0x72, 0x29, 0x72, 0x79, 0xfc, 0x5f, 0x01, 0xd7, 0x36, 0x93, 0x03, + 0xda, 0xcf, 0xd3, 0x2f, 0xa0, 0xad, 0xb4, 0x3f, 0xc7, 0x30, 0x92, 0xf0, + 0x3b, 0x49, 0x5d, 0xa2, 0x5c, 0xd2, 0x39, 0x45, 0x2f, 0xe8, 0xad, 0xfc, + 0xa6, 0x3f, 0xed, 0x61, 0x3d, 0x0a, 0x24, 0x1c, 0x02, 0x78, 0x41, 0xda, + 0xff, 0x02, 0xaa, 0xcf, 0xb1, 0xf3, 0xa3, 0xae, 0x72, 0xff, 0xe2, 0x83, + 0xfa, 0x92, 0xf6, 0xe3, 0x45, 0x8a, 0xcb, 0x10, 0x74, 0x19, 0xdc, 0x97, + 0x8d, 0x02, 0x75, 0x17, 0x0b, 0x05, 0x2f, 0x59, 0x62, 0x48, 0x61, 0xca, + 0x18, 0x07, 0x65, 0x11, 0x8e, 0x63, 0xde, 0xd2, 0xaf, 0xb6, 0x66, 0xaf, + 0xd1, 0x1f, 0xaf, 0x63, 0xe4, 0xc3, 0x50, 0xf1, 0xd0, 0x04, 0xc6, 0x3b, + 0x66, 0xc9, 0xd6, 0x25, 0xe2, 0xe7, 0xfa, 0xdf, 0xca, 0x26, 0xde, 0x2f, + 0xdc, 0xf9, 0x33, 0x13, 0x72, 0xa8, 0x9e, 0x6c, 0x18, 0x09, 0xc1, 0x39, + 0x1a, 0x6e, 0x81, 0x80, 0x4f, 0x2c, 0xde, 0xb3, 0xae, 0xf2, 0xf6, 0xbe, + 0xa5, 0xed, 0x7d, 0x66, 0xac, 0xd0, 0x63, 0xba, 0x74, 0x9a, 0x4e, 0xe7, + 0x18, 0x71, 0x4d, 0xf0, 0xfb, 0x72, 0x49, 0x13, 0x72, 0x6b, 0x00, 0xf3, + 0x6e, 0xc8, 0x76, 0x3a, 0xf2, 0xba, 0x5b, 0xf8, 0xd8, 0x70, 0x8a, 0x1a, + 0x16, 0x7e, 0x43, 0x41, 0xde, 0x02, 0x50, 0x23, 0x70, 0xa5, 0x90, 0x2b, + 0x22, 0x97, 0xc1, 0xf2, 0xb9, 0xe9, 0xa9, 0x43, 0xb0, 0x43, 0xf9, 0x37, + 0x8c, 0x6a, 0x86, 0x49, 0x13, 0xca, 0x03, 0xc1, 0x32, 0x68, 0x1d, 0xd3, + 0x2e, 0x9b, 0x6f, 0x51, 0xb8, 0x46, 0x19, 0x51, 0x34, 0x64, 0xd0, 0x62, + 0x23, 0xf1, 0x7c, 0x46, 0x60, 0xdf, 0xca, 0xd6, 0x6a, 0xf3, 0x9e, 0x20, + 0x00, 0xd1, 0x94, 0xa8, 0x04, 0xb0, 0xf0, 0x41, 0xf3, 0xd6, 0xad, 0xb3, + 0x8a, 0x30, 0xb3, 0x4a, 0x53, 0x11, 0x8d, 0x1b, 0xd0, 0x0f, 0xc5, 0x97, + 0xd0, 0x20, 0x4f, 0x4b, 0x36, 0xe2, 0x06, 0x14, 0xd9, 0xa0, 0x18, 0x78, + 0x05, 0x02, 0x23, 0x09, 0xcf, 0xe3, 0xfa, 0x0a, 0x66, 0x71, 0xf6, 0xe0, + 0xf1, 0xc0, 0xc5, 0xa0, 0xa7, 0xff, 0xb5, 0xca, 0x89, 0x2d, 0x3c, 0x67, + 0x3f, 0x37, 0x80, 0xce, 0x59, 0x5f, 0x3f, 0xa8, 0x4b, 0xa6, 0xcd, 0x0a, + 0x65, 0x1a, 0x25, 0x13, 0x18, 0x5e, 0xb2, 0x7b, 0x9f, 0x35, 0xc6, 0xc6, + 0x45, 0x7b, 0x3b, 0x32, 0x8c, 0x04, 0xcc, 0x85, 0xe8, 0x68, 0xd2, 0x62, + 0xed, 0xe7, 0x57, 0x18, 0xad, 0xda, 0xe1, 0xd9, 0x89, 0x09, 0x1f, 0x06, + 0x79, 0x5e, 0x82, 0xcd, 0x80, 0x61, 0xb1, 0x0b, 0x8a, 0x24, 0x09, 0xc1, + 0xe9, 0x4a, 0xac, 0x8d, 0xe7, 0x55, 0xcc, 0x55, 0x07, 0x7d, 0xdb, 0xbd, + 0x8b, 0x29, 0x4e, 0x78, 0xfb, 0x46, 0x64, 0x94, 0xaf, 0xa1, 0x19, 0x6f, + 0xcd, 0xbe, 0x72, 0x60, 0xe3, 0x55, 0xe1, 0xa5, 0x61, 0x83, 0xbb, 0xce, + 0x8c, 0x62, 0xe3, 0x2e, 0x84, 0x1f, 0x3c, 0xdc, 0x03, 0xf4, 0x41, 0xab, + 0x68, 0x63, 0xe3, 0x94, 0x8e, 0x1c, 0xe4, 0x80, 0xc6, 0xfb, 0x10, 0xb9, + 0xaf, 0xee, 0xcd, 0xfe, 0xfa, 0x9c, 0x18, 0xd8, 0xbc, 0xd6, 0xe0, 0xa8, + 0xe1, 0xfe, 0x78, 0x82, 0x0e, 0xd7, 0x0e, 0x80, 0xc9, 0x1f, 0x11, 0x5e, + 0x57, 0x35, 0x41, 0xdb, 0x6c, 0x39, 0xdb, 0xda, 0xfc, 0xb3, 0x12, 0x26, + 0x05, 0x9a, 0x01, 0xd4, 0x86, 0x4e, 0x60, 0x6a, 0x69, 0x72, 0xf1, 0x15, + 0x9f, 0x63, 0xaf, 0x9b, 0xe7, 0x1c, 0xbc, 0x33, 0xde, 0x3b, 0x6a, 0x74, + 0x8a, 0x9e, 0x74, 0x5c, 0xa0, 0x64, 0xc3, 0x01, 0xf1, 0x04, 0xef, 0xaf, + 0x45, 0x52, 0x5b, 0xed, 0xb2, 0xf8, 0x80, 0xb9, 0xc6, 0x04, 0x40, 0x1e, + 0x0b, 0xd0, 0x0f, 0xcf, 0x73, 0x2a, 0x65, 0xd2, 0xee, 0xcc, 0xdb, 0xe6, + 0xe8, 0x84, 0xff, 0xda, 0xb1, 0x25, 0x3a, 0x14, 0x94, 0x67, 0x0e, 0x03, + 0xdc, 0x93, 0xfe, 0x50, 0x19, 0x60, 0x61, 0xa5, 0xf3, 0xd2, 0x2d, 0x8e, + 0x6b, 0xa2, 0xc5, 0x63, 0xa9, 0x99, 0x8e, 0xe7, 0x21, 0x5e, 0x08, 0x4c, + 0xe5, 0x22, 0x66, 0x88, 0xc0, 0x7c, 0x0e, 0x5d, 0x97, 0xb2, 0x15, 0x30, + 0xd5, 0xee, 0xd4, 0x25, 0x22, 0x82, 0x28, 0x64, 0xc9, 0x96, 0x12, 0x46, + 0x53, 0xcb, 0xa1, 0xb7, 0x38, 0xe2, 0x8e, 0x52, 0x5a, 0x03, 0x1e, 0xf4, + 0x4a, 0xb2, 0x8e, 0x77, 0xfa, 0x6b, 0xe6, 0x8c, 0x12, 0xc3, 0x4d, 0x12, + 0x87, 0xc1, 0x78, 0x29, 0xfa, 0x86, 0xd9, 0xe0, 0xbc, 0x10, 0x87, 0xc6, + 0x42, 0x13, 0x8d, 0x19, 0x0f, 0x02, 0x4f, 0x56, 0xac, 0xb3, 0xce, 0x6a, + 0x84, 0xb9, 0x39, 0x59, 0x26, 0x23, 0xe0, 0xcf, 0x72, 0x2e, 0xb9, 0xa2, + 0xda, 0x32, 0x18, 0x77, 0x12, 0xc9, 0xc1, 0x95, 0x80, 0x93, 0x93, 0xac, + 0x2d, 0xdf, 0x4c, 0xc2, 0x53, 0x0d, 0xa3, 0x2c, 0xac, 0x3e, 0xfe, 0x72, + 0xdb, 0xf6, 0x20, 0x80, 0x21, 0xbd, 0x98, 0x71, 0x5d, 0x21, 0xf3, 0x45, + 0x64, 0x71, 0x0b, 0xb0, 0x33, 0x40, 0xa3, 0x33, 0x57, 0xe5, 0x96, 0x87, + 0xc4, 0xec, 0x80, 0x90, 0x1d, 0xfb, 0x31, 0x73, 0x5d, 0x7f, 0x70, 0xb3, + 0x61, 0xa4, 0x8b, 0x3c, 0xc8, 0x44, 0x4d, 0x09, 0xb2, 0x32, 0x74, 0x3e, + 0xa0, 0xaf, 0xd7, 0x66, 0xe8, 0xd0, 0xb1, 0xc3, 0xa8, 0x81, 0xbc, 0x70, + 0xe8, 0x6e, 0x68, 0x89, 0x14, 0xaf, 0x8f, 0x4b, 0x60, 0xae, 0x6a, 0xcd, + 0xa8, 0xbc, 0xd7, 0xbd, 0x35, 0x15, 0xbc, 0xcb, 0x9c, 0x84, 0x27, 0x86, + 0x69, 0xe5, 0x09, 0x21, 0xf6, 0xa4, 0xd9, 0xaf, 0x33, 0x48, 0x84, 0x93, + 0x91, 0x24, 0x96, 0xe5, 0x4c, 0x78, 0xee, 0xec, 0x79, 0x5b, 0x0a, 0x3c, + 0xa8, 0x62, 0xe9, 0xa9, 0x68, 0x21, 0x2c, 0x6a, 0x48, 0x4a, 0x17, 0x19, + 0x60, 0x65, 0xa5, 0x0c, 0x97, 0xd4, 0xc9, 0xde, 0x56, 0xe9, 0xf0, 0xf7, + 0x56, 0x57, 0x6c, 0x8e, 0x3e, 0xf6, 0x52, 0xe1, 0x86, 0x42, 0x80, 0x01, + 0x80, 0xa1, 0x28, 0x64, 0x32, 0x8f, 0x80, 0xf3, 0x7d, 0xa2, 0x97, 0x84, + 0x82, 0xe7, 0x91, 0x41, 0x92, 0x08, 0xe6, 0x02, 0x69, 0x37, 0xfe, 0xcd, + 0xa2, 0x85, 0xfa, 0xb7, 0x64, 0xab, 0x78, 0x95, 0xb4, 0x85, 0x44, 0x28, + 0xa5, 0xe5, 0xb8, 0xc0, 0x11, 0xac, 0x21, 0x5a, 0xd3, 0x98, 0x5e, 0x8a, + 0x08, 0x60, 0x14, 0x0d, 0x53, 0xde, 0xce, 0x06, 0xd4, 0x37, 0xb1, 0x22, + 0xe2, 0x68, 0x34, 0xc7, 0xc5, 0xa3, 0xf5, 0x1b, 0xce, 0xed, 0x45, 0x24, + 0xd9, 0x4a, 0x08, 0xdd, 0x65, 0x07, 0x8b, 0xbf, 0x81, 0xda, 0x3b, 0x31, + 0xdc, 0xb1, 0x7b, 0x3d, 0x8a, 0xb4, 0x74, 0x6e, 0xc8, 0xd4, 0x46, 0xd9, + 0xb6, 0x97, 0x45, 0x3b, 0xa0, 0x24, 0x88, 0xc3, 0xc4, 0x1d, 0x58, 0xa5, + 0xa7, 0xf0, 0x7c, 0xae, 0xd6, 0x77, 0x47, 0x7c, 0xe2, 0xb0, 0x18, 0xef, + 0x2c, 0x35, 0x82, 0x8c, 0x89, 0x93, 0x76, 0x40, 0x52, 0xbc, 0xf1, 0xf9, + 0x7f, 0x77, 0x03, 0x74, 0xdc, 0x12, 0xfd, 0x74, 0x2e, 0x16, 0xe6, 0x19, + 0xd5, 0xe0, 0x8b, 0x06, 0x4b, 0x99, 0x1f, 0x68, 0x3c, 0xd1, 0xbe, 0xe8, + 0x9c, 0xf7, 0xb5, 0x9d, 0x17, 0x1f, 0xaf, 0x47, 0xc5, 0x38, 0x92, 0x2c, + 0x1b, 0x54, 0x6f, 0x2b, 0x1d, 0x09, 0xeb, 0x4d, 0x89, 0x8e, 0x32, 0xe7, + 0x59, 0x84, 0x91, 0xfd, 0x57, 0xd9, 0x79, 0x4f, 0x8a, 0xdb, 0xc3, 0x3a, + 0x09, 0xe0, 0x07, 0x36, 0xdd, 0x93, 0x94, 0x1e, 0x69, 0x6b, 0xe1, 0x31, + 0xae, 0x72, 0xed, 0x66, 0x80, 0x06, 0x1b, 0x4a, 0x45, 0xdc, 0xbc, 0xdc, + 0x93, 0x44, 0xce, 0xf4, 0x01, 0xdc, 0x08, 0x73, 0x02, 0x32, 0xa3, 0xf0, + 0x61, 0x9a, 0x50, 0x04, 0x3b, 0x28, 0xb3, 0x9a, 0xbf, 0xe7, 0x5c, 0x5a, + 0x99, 0x4b, 0xf7, 0xff, 0x3b, 0x76, 0x7b, 0x7a, 0xcc, 0xcd, 0x49, 0xdf, + 0x49, 0x48, 0xcc, 0x99, 0x34, 0x14, 0x07, 0xda, 0x06, 0xfb, 0x9d, 0x97, + 0xc4, 0xd9, 0x2e, 0x25, 0x34, 0x63, 0x0c, 0x97, 0xce, 0xfa, 0x3b, 0xcf, + 0x87, 0x18, 0xdd, 0xf7, 0x3f, 0x8b, 0xe1, 0x00, 0xcb, 0x61, 0x03, 0x2c, + 0x38, 0xbc, 0x31, 0xdc, 0x80, 0xc4, 0x3f, 0xd5, 0x8c, 0x64, 0xe1, 0x09, + 0x4e, 0x86, 0x59, 0xec, 0x85, 0x55, 0xf0, 0x3a, 0xa7, 0xae, 0xae, 0x02, + 0xd1, 0x9c, 0x00, 0xc9, 0x20, 0x3e, 0x3c, 0x3f, 0x6e, 0x2e, 0xd9, 0x64, + 0xb9, 0x0c, 0x82, 0x32, 0x81, 0xe7, 0x46, 0xf5, 0x72, 0xb5, 0x70, 0x5c, + 0x4c, 0xaf, 0xda, 0xfc, 0x29, 0x07, 0x12, 0x3b, 0x09, 0xde, 0xd3, 0x29, + 0x06, 0xa0, 0x66, 0x94, 0x72, 0xbe, 0xa0, 0x3f, 0xc3, 0xef, 0x4f, 0xf2, + 0x77, 0x21, 0x37, 0x58, 0xd9, 0x62, 0x25, 0x08, 0x41, 0xf4, 0x47, 0xc4, + 0xcb, 0xcb, 0xac, 0x63, 0x14, 0x12, 0xb6, 0xe8, 0xfa, 0xb7, 0x12, 0x6d, + 0x41, 0xd1, 0x1c, 0x8c, 0x3b, 0x3d, 0x10, 0x20, 0xcb, 0xcb, 0x9c, 0xab, + 0x1a, 0x27, 0xe1, 0x71, 0xce, 0x95, 0x67, 0x02, 0xe4, 0x8b, 0x90, 0xe2, + 0x13, 0xb3, 0xb3, 0x0d, 0x33, 0xb3, 0xb3, 0x96, 0x7e, 0xb3, 0xb6, 0x89, + 0x44, 0x94, 0x0a, 0x0c, 0xc0, 0xd6, 0xc3, 0xe9, 0x14, 0x19, 0x0a, 0xfb, + 0xd0, 0x9d, 0x0a, 0x39, 0x61, 0xbe, 0xbb, 0x5f, 0xa4, 0xd4, 0xf8, 0xc4, + 0x7c, 0x91, 0x18, 0xe8, 0x84, 0x46, 0x1f, 0x25, 0x29, 0x9c, 0xbb, 0xd4, + 0x41, 0x9e, 0xdb, 0x04, 0x3b, 0xef, 0x46, 0x72, 0xc6, 0xdb, 0x40, 0x25, + 0x92, 0x7c, 0x34, 0x68, 0x2b, 0x43, 0xbd, 0x4b, 0xfd, 0x8c, 0x51, 0xa2, + 0xcd, 0x91, 0x3e, 0x7b, 0xfe, 0x67, 0xb7, 0x93, 0x5b, 0x62, 0x43, 0x25, + 0x7f, 0xd2, 0x98, 0xd5, 0xfd, 0x63, 0x21, 0x2a, 0x18, 0x0d, 0x0a, 0x3d, + 0xc6, 0x78, 0xe5, 0xd2, 0x92, 0xb1, 0x2a, 0x11, 0xd0, 0x9b, 0xa0, 0x4a, + 0x54, 0x1a, 0x68, 0x04, 0xca, 0x18, 0x7a, 0xc0, 0x4b, 0xeb, 0x76, 0xc9, + 0x81, 0x8e, 0x32, 0xb4, 0x5b, 0x50, 0xa0, 0x94, 0xe6, 0x80, 0xc9, 0x19, + 0xf8, 0x26, 0x57, 0xef, 0xf7, 0x29, 0x71, 0x17, 0xfb, 0xeb, 0x85, 0xa8, + 0xa8, 0x41, 0x5b, 0x26, 0x48, 0x51, 0x83, 0x4c, 0x89, 0x1b, 0xa1, 0x8e, + 0x91, 0xf1, 0xe9, 0x8c, 0xff, 0xba, 0xee, 0xd7, 0x6b, 0x0f, 0xf5, 0x39, + 0x60, 0x69, 0xda, 0xbc, 0x76, 0xd8, 0x15, 0x79, 0x9a, 0x79, 0x59, 0x54, + 0xa5, 0x46, 0xb2, 0x65, 0x7e, 0x34, 0xd4, 0xc4, 0xf6, 0xc7, 0x98, 0x26, + 0x39, 0x9c, 0x30, 0x18, 0xc0, 0x04, 0xac, 0xba, 0xca, 0x5f, 0xcd, 0x7b, + 0x03, 0xd7, 0x0d, 0xa0, 0x71, 0xdd, 0x90, 0x86, 0x85, 0x5e, 0x44, 0xfc, + 0xe3, 0x41, 0xf7, 0xc2, 0xd6, 0x6b, 0xee, 0xa5, 0x6b, 0x2f, 0x72, 0x18, + 0xbb, 0xc8, 0x48, 0xa0, 0x26, 0x48, 0x9b, 0xca, 0xac, 0x6d, 0x73, 0x5a, + 0x5d, 0x3d, 0xef, 0x97, 0xdc, 0x83, 0x4d, 0x47, 0x40, 0xee, 0x60, 0x85, + 0x61, 0xf6, 0x23, 0x2c, 0x80, 0x7c, 0x45, 0x5b, 0x49, 0x91, 0x43, 0x0c, + 0x50, 0x6c, 0xa2, 0x19, 0x0c, 0x03, 0x1f, 0xe7, 0x85, 0x15, 0x7f, 0x75, + 0xb2, 0xf2, 0x64, 0x05, 0x1a, 0x28, 0xbc, 0xa9, 0x21, 0x97, 0x42, 0x86, + 0x5e, 0x10, 0x01, 0xb9, 0x3c, 0x91, 0xfb, 0x95, 0x32, 0xde, 0x1a, 0xdd, + 0x32, 0x09, 0x81, 0x94, 0x9d, 0xda, 0x12, 0xed, 0x5a, 0x53, 0x4a, 0xc8, + 0xa2, 0xeb, 0xa8, 0x41, 0xcd, 0xaf, 0xfc, 0xe3, 0xb5, 0x89, 0x53, 0x90, + 0x30, 0x22, 0x59, 0x0a, 0x00, 0xcb, 0x01, 0xf0, 0x49, 0xb3, 0x5b, 0x7f, + 0x61, 0xc3, 0xc8, 0xee, 0xd9, 0x6d, 0xc8, 0xe1, 0x01, 0xa6, 0xe7, 0x26, + 0x84, 0xe8, 0xc8, 0x9c, 0x20, 0x3e, 0x18, 0x2a, 0xb7, 0x15, 0xd6, 0x66, + 0xb1, 0x51, 0x09, 0x20, 0xc1, 0x1a, 0x8b, 0x2d, 0x01, 0xdc, 0xac, 0xf6, + 0x1f, 0x6a, 0x74, 0x58, 0x8f, 0x30, 0x61, 0x46, 0x0e, 0x04, 0x91, 0x73, + 0x29, 0x08, 0x51, 0x0f, 0x92, 0x6f, 0x03, 0xaa, 0x88, 0x1d, 0x95, 0x57, + 0x6e, 0xec, 0xc2, 0xf8, 0xae, 0x43, 0x50, 0x14, 0xa4, 0x18, 0x19, 0x50, + 0x19, 0x08, 0x7c, 0x78, 0xde, 0xe7, 0xb3, 0x5e, 0x5c, 0x17, 0xde, 0xc0, + 0x66, 0x90, 0xed, 0x65, 0xaa, 0x00, 0x4e, 0x85, 0x3c, 0x6c, 0x79, 0x20, + 0x0d, 0x0f, 0xaa, 0x95, 0xa8, 0x5e, 0xb7, 0x8f, 0xbf, 0x3c, 0x07, 0x12, + 0x11, 0x91, 0xbd, 0xa9, 0x1f, 0x31, 0xf3, 0xd7, 0x8a, 0x6c, 0xd2, 0xa9, + 0xbd, 0x7d, 0xd1, 0x63, 0x39, 0x63, 0x64, 0x85, 0xe1, 0x94, 0xba, 0xb1, + 0xb5, 0xc0, 0xf4, 0xe2, 0xf7, 0x7b, 0xab, 0xc3, 0x99, 0xee, 0x43, 0x23, + 0x18, 0x80, 0x18, 0x50, 0xc3, 0xc0, 0x8e, 0x42, 0xf9, 0xef, 0xe5, 0xad, + 0xe2, 0x6d, 0xd8, 0xb6, 0x2e, 0xde, 0x45, 0xa3, 0x21, 0x87, 0x97, 0x70, + 0x33, 0xcb, 0xfa, 0xe6, 0x45, 0x7b, 0x46, 0x89, 0xf9, 0xa1, 0x2b, 0x09, + 0x65, 0x28, 0x87, 0x9b, 0xb8, 0x79, 0x04, 0x69, 0x01, 0xda, 0xbd, 0x17, + 0x7c, 0x84, 0x94, 0x23, 0x4b, 0x0a, 0x57, 0xe3, 0xf3, 0xed, 0x5d, 0x27, + 0xcc, 0x12, 0xe4, 0x07, 0xd3, 0x01, 0x46, 0x49, 0x43, 0x26, 0xf4, 0x70, + 0x85, 0x6b, 0x65, 0x9f, 0xaa, 0xa4, 0x88, 0x66, 0x20, 0x88, 0x44, 0x03, + 0x4c, 0x32, 0xa0, 0xa2, 0x5c, 0x8f, 0xb4, 0x0d, 0x90, 0x1f, 0x39, 0x41, + 0xfb, 0x48, 0x5c, 0x04, 0x70, 0xd9, 0x47, 0xec, 0x43, 0xae, 0x77, 0x33, + 0x84, 0xda, 0x48, 0xa6, 0xbd, 0xed, 0x92, 0xca, 0x38, 0x60, 0x28, 0x80, + 0x18, 0xd1, 0xa1, 0xd9, 0x46, 0xc7, 0xae, 0x2e, 0xcf, 0xd6, 0x4f, 0xb3, + 0x3c, 0xb7, 0xd0, 0x01, 0x03, 0x31, 0x97, 0xda, 0xd5, 0xee, 0xd7, 0x26, + 0x06, 0x12, 0xa5, 0xe8, 0x2f, 0xdf, 0x80, 0x18, 0xe2, 0x59, 0x64, 0xe1, + 0x20, 0x10, 0xc8, 0x97, 0x92, 0x4b, 0xad, 0x54, 0x02, 0x12, 0xc3, 0xcd, + 0x8a, 0x33, 0xc7, 0xf4, 0xfd, 0x4d, 0xeb, 0x6d, 0x4c, 0xa3, 0x34, 0x00, + 0xf8, 0xa8, 0xc8, 0x21, 0x90, 0x43, 0x3f, 0xae, 0x7b, 0xaf, 0x37, 0x7a, + 0x72, 0xc3, 0x47, 0xce, 0xbb, 0xbf, 0xd0, 0x80, 0x6e, 0x00, 0xd6, 0x71, + 0x42, 0x92, 0x12, 0x9c, 0x62, 0x09, 0xc7, 0x3f, 0x62, 0x36, 0xd2, 0xfe, + 0xff, 0xba, 0xb5, 0x08, 0x27, 0x88, 0x26, 0x86, 0x3b, 0xd4, 0x34, 0x8c, + 0x08, 0xf8, 0x24, 0xb3, 0x46, 0x1b, 0x60, 0xf3, 0x86, 0x32, 0x90, 0x47, + 0xb6, 0x92, 0x1f, 0x8b, 0xb6, 0xa1, 0x7a, 0x4e, 0x67, 0x04, 0x86, 0x51, + 0xfa, 0x96, 0xb4, 0xba, 0xe3, 0xe3, 0x6a, 0x97, 0x0a, 0x02, 0x30, 0x0a, + 0xd5, 0x08, 0x35, 0x42, 0x67, 0x00, 0xac, 0xa0, 0xd6, 0x6a, 0xcc, 0x52, + 0xa3, 0xe5, 0xec, 0xb9, 0x9c, 0xcb, 0xce, 0x53, 0xca, 0x63, 0x97, 0x95, + 0x91, 0x16, 0x6c, 0x65, 0x16, 0xcb, 0x6c, 0x3c, 0xa0, 0xa3, 0x34, 0x42, + 0x29, 0x5e, 0x01, 0x5e, 0xf4, 0xd2, 0xe1, 0x32, 0x9e, 0x42, 0x12, 0x3f, + 0x72, 0x3a, 0x8d, 0xe8, 0xab, 0x8b, 0x0a, 0x86, 0x29, 0x99, 0x00, 0xe3, + 0x38, 0x9a, 0x34, 0x0c, 0xd0, 0xcb, 0x4a, 0x21, 0x11, 0xdc, 0x07, 0xad, + 0x53, 0xe5, 0xb2, 0x30, 0x69, 0x13, 0x92, 0xc9, 0x64, 0xb3, 0x00, 0x35, + 0x33, 0x4d, 0xc0, 0xca, 0x64, 0x3e, 0x08, 0x03, 0x3a, 0x38, 0xde, 0x0d, + 0xd2, 0x96, 0xb7, 0xb7, 0xab, 0xc4, 0x9a, 0x26, 0x74, 0x27, 0xe9, 0xf1, + 0x0a, 0xc3, 0x6f, 0x5a, 0x79, 0xd5, 0xf2, 0x92, 0xd5, 0x33, 0x30, 0x40, + 0x41, 0x06, 0x81, 0x8d, 0xe1, 0xde, 0x9c, 0x8a, 0xbd, 0xb4, 0xb5, 0xc5, + 0x82, 0x8b, 0xe3, 0xc3, 0xf3, 0x03, 0xd3, 0x84, 0xa2, 0xcc, 0x03, 0xed, + 0x67, 0xe6, 0x20, 0x32, 0x94, 0x92, 0x18, 0x0e, 0x44, 0x61, 0x52, 0xaf, + 0xb8, 0x51, 0x7c, 0xac, 0x20, 0x67, 0x2c, 0x3b, 0x90, 0xe1, 0x90, 0x99, + 0x43, 0x24, 0x3d, 0x3f, 0x68, 0xad, 0xda, 0x91, 0x3e, 0x30, 0xc5, 0x2f, + 0xf1, 0x50, 0x71, 0x45, 0xf0, 0x09, 0x4e, 0x34, 0xd2, 0x7d, 0x94, 0xb3, + 0xe9, 0xbd, 0x44, 0x0d, 0x34, 0x18, 0x4f, 0xc4, 0x5c, 0xc3, 0x04, 0x3c, + 0x9b, 0x08, 0xc5, 0x2d, 0x65, 0x23, 0x40, 0x64, 0xa5, 0xf4, 0x77, 0xfb, + 0xbf, 0xca, 0x23, 0x89, 0x8d, 0x03, 0x4b, 0x40, 0xf6, 0xb4, 0x49, 0x39, + 0x24, 0x7c, 0x4f, 0x79, 0xce, 0x13, 0x0b, 0x38, 0xc9, 0xbf, 0xc5, 0x94, + 0x64, 0x07, 0xd0, 0x2d, 0xed, 0xe0, 0x30, 0x14, 0x68, 0xfd, 0x3f, 0x08, + 0x42, 0x62, 0xa3, 0xd3, 0x1c, 0x88, 0x58, 0xe8, 0x8c, 0x9b, 0x22, 0x3c, + 0x41, 0xa6, 0xa5, 0x7d, 0x1d, 0xbf, 0xc0, 0xf9, 0xf9, 0xbe, 0x78, 0x67, + 0x0a, 0x2f, 0xbf, 0x39, 0xd4, 0xb2, 0x6f, 0x07, 0xcc, 0x09, 0xe5, 0x7d, + 0x54, 0xfc, 0xbb, 0x30, 0xc6, 0x22, 0x66, 0x84, 0xf2, 0xb4, 0x8c, 0xa1, + 0x74, 0xaf, 0x04, 0x8e, 0x73, 0x71, 0x1a, 0xf0, 0x67, 0xad, 0x8a, 0x18, + 0xd0, 0xf1, 0x63, 0x95, 0xf4, 0xc7, 0xc4, 0x7e, 0x75, 0xb6, 0x12, 0xd8, + 0xd4, 0xe7, 0x03, 0x11, 0xb2, 0x1e, 0x70, 0x8f, 0xb2, 0xbf, 0x18, 0x7b, + 0xf8, 0x98, 0x97, 0xe1, 0xe7, 0x08, 0x0c, 0x6f, 0x55, 0x19, 0x94, 0xfa, + 0xd5, 0x89, 0xb7, 0xdc, 0xf1, 0x2b, 0xc6, 0x4b, 0x32, 0x8c, 0x26, 0x26, + 0x96, 0x72, 0x4d, 0x55, 0x3d, 0xba, 0x6e, 0xbc, 0xb6, 0x98, 0xe1, 0x9c, + 0x6e, 0x18, 0x12, 0x84, 0xf1, 0x8d, 0x14, 0x0e, 0x5e, 0x01, 0xe2, 0x74, + 0xf7, 0x4a, 0x55, 0xff, 0xb7, 0x3c, 0xe7, 0xfe, 0xd2, 0x97, 0xce, 0xed, + 0xc6, 0xc6, 0xec, 0xfd, 0x89, 0xe9, 0x52, 0x26, 0x8b, 0x82, 0xfa, 0x44, + 0x8c, 0x21, 0xbc, 0xa5, 0x79, 0x76, 0x5b, 0xb7, 0x93, 0x70, 0x56, 0xe0, + 0x00, 0x48, 0x84, 0xee, 0x09, 0x17, 0x61, 0x46, 0x90, 0x44, 0x07, 0x32, + 0x9c, 0xc7, 0x71, 0x56, 0x64, 0x67, 0x46, 0x3e, 0xbf, 0x93, 0xdf, 0x4e, + 0xa6, 0x2c, 0x0a, 0x05, 0x0a, 0x6b, 0x15, 0x0f, 0xe9, 0x0d, 0xb6, 0xf0, + 0xce, 0x0a, 0x32, 0xa1, 0x59, 0x11, 0xe3, 0xa6, 0xac, 0xe1, 0xb4, 0xc4, + 0xbf, 0xcc, 0xac, 0x9d, 0xed, 0xe7, 0x34, 0x49, 0xf1, 0x26, 0xad, 0x58, + 0xdb, 0xf1, 0xb5, 0x00, 0xa1, 0x05, 0xed, 0xb2, 0xe0, 0xc2, 0x96, 0x82, + 0x05, 0xa4, 0x95, 0x59, 0x76, 0xbf, 0xe6, 0x96, 0xb8, 0xd0, 0x29, 0xe5, + 0xad, 0x2b, 0x7b, 0x73, 0xb3, 0x2d, 0x01, 0x20, 0x4d, 0x12, 0x72, 0xdc, + 0x92, 0x5d, 0x1c, 0x24, 0x2e, 0xb8, 0x33, 0x70, 0xe9, 0x41, 0x56, 0xaf, + 0x9f, 0xeb, 0x1a, 0xa5, 0xae, 0x1a, 0x74, 0x68, 0x04, 0x24, 0xc0, 0x01, + 0x38, 0x4e, 0xc8, 0xc9, 0x9f, 0x01, 0xc3, 0x39, 0xc3, 0xb5, 0x0c, 0xa3, + 0xe2, 0xaa, 0x6e, 0xf0, 0x69, 0x07, 0xda, 0x17, 0xbf, 0x6a, 0xcd, 0x92, + 0x26, 0x87, 0xd7, 0x87, 0xae, 0x0a, 0x3d, 0xf5, 0x87, 0xfc, 0x3b, 0x9c, + 0xb1, 0xf2, 0xe8, 0x90, 0x12, 0x92, 0x27, 0xb9, 0x40, 0xea, 0xc5, 0x63, + 0xab, 0xfe, 0xf3, 0xbe, 0x62, 0x07, 0xa2, 0x95, 0xf3, 0x47, 0x72, 0x1b, + 0xd9, 0xaf, 0xd2, 0x2c, 0x51, 0x28, 0x8c, 0x9f, 0xcc, 0xe4, 0xfb, 0x83, + 0x33, 0xdd, 0xba, 0xbe, 0xb4, 0xbb, 0x33, 0xf7, 0x4d, 0x8c, 0xe0, 0xb6, + 0x41, 0xc9, 0x13, 0xc3, 0x72, 0xad, 0xd1, 0xd1, 0xed, 0x58, 0x16, 0xf9, + 0xff, 0xde, 0xf5, 0x0b, 0xfb, 0x38, 0xbb, 0x1b, 0x8c, 0x1e, 0xdf, 0x9a, + 0x5f, 0xd5, 0x8d, 0xb9, 0x8c, 0x60, 0x1c, 0xbc, 0xc2, 0x58, 0x44, 0x23, + 0x94, 0x67, 0xf4, 0x1d, 0x27, 0x10, 0x46, 0xfb, 0x75, 0xa0, 0xc3, 0x22, + 0x6d, 0x45, 0xc1, 0x94, 0xa6, 0xc5, 0x08, 0x7e, 0x30, 0x56, 0x7d, 0xb6, + 0x59, 0xcd, 0x35, 0xfe, 0xcf, 0xfc, 0xf0, 0x1a, 0xe7, 0xb8, 0xf3, 0x04, + 0x0c, 0xa7, 0x05, 0x09, 0xe0, 0x15, 0x86, 0x4e, 0x56, 0xce, 0xff, 0x8b, + 0x6e, 0xed, 0x94, 0x26, 0x79, 0xa2, 0x12, 0xe4, 0x25, 0x38, 0x12, 0xce, + 0xe7, 0x92, 0xfa, 0x6a, 0xaa, 0xb6, 0xa8, 0x84, 0x71, 0xd9, 0x9b, 0x72, + 0xd9, 0x14, 0xb1, 0x66, 0x85, 0x09, 0x91, 0x29, 0xe5, 0xc9, 0x17, 0xa0, + 0x09, 0xfa, 0x20, 0xa5, 0xc3, 0x66, 0x2e, 0x3b, 0x53, 0x59, 0xd1, 0x0c, + 0x40, 0x5c, 0xd2, 0xf7, 0x95, 0x46, 0x53, 0x01, 0x10, 0x4e, 0x53, 0xfd, + 0x46, 0xb7, 0x82, 0x6b, 0xe8, 0xea, 0x52, 0xc6, 0x9b, 0xe5, 0xa5, 0x88, + 0x2a, 0xf0, 0x28, 0x23, 0x51, 0x99, 0x77, 0x00, 0x46, 0x77, 0x3c, 0x9a, + 0xfa, 0x51, 0x28, 0xad, 0x8d, 0x13, 0x0d, 0xe9, 0x41, 0x1a, 0x12, 0x43, + 0xee, 0x12, 0x28, 0xbb, 0x8e, 0xf6, 0x0e, 0x18, 0xc0, 0x57, 0x6f, 0x2d, + 0x28, 0x32, 0x33, 0xf2, 0xa4, 0x06, 0xf2, 0x7b, 0xa3, 0xf1, 0x6b, 0x06, + 0xcf, 0x23, 0x81, 0xe7, 0x90, 0xc5, 0xa8, 0xa9, 0x27, 0x64, 0x97, 0x44, + 0xba, 0x07, 0x1a, 0x52, 0xc9, 0xa2, 0x97, 0x56, 0x19, 0xca, 0x2a, 0x7e, + 0xd8, 0x92, 0x79, 0xbd, 0x7a, 0x0d, 0xf9, 0x61, 0x80, 0x9b, 0x83, 0x31, + 0xa6, 0xa6, 0xe8, 0x32, 0x38, 0x40, 0x99, 0x81, 0x75, 0xd5, 0xa5, 0xd8, + 0xbd, 0x0c, 0x71, 0xb8, 0x1c, 0xe5, 0x65, 0x99, 0x50, 0x09, 0x0c, 0xb3, + 0xe2, 0x7b, 0x5a, 0xbc, 0x1c, 0x0d, 0x21, 0xa9, 0xc8, 0x33, 0x01, 0x2c, + 0x64, 0x66, 0x6f, 0x49, 0xf4, 0xf8, 0xb7, 0x5a, 0x5f, 0xe8, 0x86, 0x10, + 0xcc, 0x01, 0x08, 0xc6, 0x9e, 0x8b, 0xc8, 0x91, 0x47, 0x72, 0x22, 0x55, + 0x83, 0xfb, 0xa5, 0xa7, 0x50, 0xd3, 0x4d, 0xcb, 0xd2, 0xa5, 0x96, 0x60, + 0x35, 0x1e, 0x52, 0x00, 0xa3, 0x39, 0x23, 0xf6, 0x4c, 0x6d, 0x4b, 0x14, + 0x96, 0xf9, 0xa9, 0x43, 0xd9, 0x80, 0x27, 0x6a, 0xf3, 0xa2, 0xcf, 0xc3, + 0x19, 0x19, 0x4f, 0x2a, 0x69, 0x72, 0x32, 0x95, 0x65, 0x3e, 0x9b, 0xfa, + 0x8e, 0x23, 0x36, 0x83, 0xb0, 0x71, 0xd4, 0x0d, 0x52, 0xaf, 0x99, 0x02, + 0xf9, 0x7b, 0x20, 0x8c, 0x82, 0x33, 0x8e, 0x5d, 0xb1, 0x34, 0x18, 0x1c, + 0x32, 0xad, 0x70, 0x4c, 0x88, 0x95, 0x1e, 0xc2, 0xf8, 0xda, 0x70, 0xe0, + 0xc8, 0x62, 0xfc, 0xdc, 0xc8, 0x96, 0x02, 0x83, 0x41, 0x56, 0xbf, 0xc5, + 0xfc, 0xba, 0xdc, 0x53, 0x94, 0x9c, 0x63, 0x38, 0x9c, 0x19, 0x29, 0x99, + 0xa4, 0x60, 0x12, 0xac, 0x53, 0x6b, 0xcc, 0xb1, 0xc3, 0xca, 0x50, 0x24, + 0x4f, 0x68, 0x12, 0x35, 0x53, 0x3b, 0xbe, 0xca, 0x08, 0x87, 0x79, 0x49, + 0x20, 0xd5, 0x60, 0xea, 0x68, 0xc4, 0x50, 0xcb, 0x29, 0x50, 0xf7, 0x02, + 0xfe, 0xba, 0x30, 0x35, 0x3e, 0x06, 0xf5, 0x86, 0x7c, 0x32, 0x22, 0x53, + 0x24, 0xa2, 0x82, 0x33, 0x19, 0x3e, 0xc8, 0x35, 0xbb, 0x30, 0xd2, 0x05, + 0x8b, 0x9f, 0xf0, 0x22, 0xdd, 0xa3, 0x22, 0x81, 0x48, 0x37, 0xda, 0x88, + 0x20, 0xae, 0x96, 0x5c, 0xa1, 0xbd, 0x18, 0x49, 0xe6, 0xe6, 0x6b, 0xdb, + 0xeb, 0x19, 0x06, 0x9c, 0xe8, 0x99, 0x11, 0x93, 0xc9, 0x7d, 0x42, 0xff, + 0xe3, 0xa3, 0x00, 0x82, 0x88, 0x1e, 0x94, 0x67, 0x47, 0xe2, 0xd6, 0x5a, + 0x64, 0xb2, 0x26, 0x40, 0xa1, 0xe9, 0xc2, 0x45, 0x33, 0x4a, 0x8a, 0x5f, + 0x61, 0x3c, 0x11, 0x2d, 0x23, 0xa6, 0x9c, 0xe4, 0x8a, 0x17, 0xa0, 0x4f, + 0xe2, 0xf8, 0xb8, 0xbc, 0xd1, 0x6a, 0x34, 0xa1, 0x94, 0x19, 0x32, 0x97, + 0x80, 0xd5, 0x67, 0x26, 0x01, 0xce, 0x95, 0x41, 0xcb, 0x42, 0x8e, 0x50, + 0x83, 0x0e, 0x70, 0x8d, 0xc0, 0x7a, 0xdc, 0x88, 0xa2, 0x48, 0x9c, 0xf2, + 0x52, 0xfb, 0x6c, 0x49, 0x62, 0xec, 0xcd, 0xe1, 0x39, 0x06, 0xfb, 0x09, + 0xf6, 0x8e, 0x84, 0x8e, 0xe9, 0x25, 0xb9, 0x39, 0x7e, 0x9c, 0xaf, 0x11, + 0x1b, 0x04, 0xf9, 0x7d, 0x9a, 0x1a, 0x4a, 0xab, 0x00, 0xdb, 0xba, 0x4a, + 0xe6, 0xd2, 0x6b, 0x9b, 0x85, 0xf2, 0xcc, 0x32, 0xab, 0xc7, 0x2d, 0x21, + 0x59, 0x3a, 0xb0, 0x27, 0xbf, 0xc5, 0xf2, 0x7b, 0x3f, 0x43, 0x6c, 0xab, + 0xbf, 0xd5, 0xe5, 0x2e, 0xcd, 0x4e, 0xbe, 0xe1, 0xc8, 0x3c, 0x96, 0x13, + 0xed, 0x14, 0xe8, 0xf8, 0x81, 0x7c, 0x49, 0x06, 0x5b, 0xd1, 0xca, 0x45, + 0x2f, 0x2a, 0x34, 0x2e, 0x03, 0xc5, 0x86, 0x64, 0x40, 0x8e, 0x1e, 0x80, + 0x0d, 0x42, 0x14, 0x80, 0x6f, 0xb4, 0xc9, 0xe4, 0xf6, 0xed, 0xda, 0xd4, + 0x45, 0x0d, 0x42, 0xc1, 0x76, 0xe2, 0xbb, 0xd1, 0x05, 0x66, 0x4a, 0xd4, + 0xd1, 0xca, 0x85, 0xc8, 0xcb, 0xfb, 0x84, 0xa5, 0xca, 0x98, 0x8f, 0xbf, + 0xcf, 0xc5, 0x71, 0x5f, 0xfe, 0xe6, 0x92, 0x56, 0x20, 0xa4, 0x34, 0x8a, + 0x35, 0x7a, 0xaa, 0xa2, 0xb5, 0x79, 0xe1, 0x24, 0xa9, 0xee, 0xc3, 0x2c, + 0x4d, 0x59, 0xa0, 0x41, 0xf5, 0x87, 0xa8, 0xa0, 0xeb, 0x02, 0xe9, 0xfd, + 0xdf, 0x77, 0xbb, 0x72, 0xc4, 0x17, 0x9e, 0xdb, 0xe1, 0x18, 0x70, 0xca, + 0x6a, 0x87, 0x24, 0x68, 0xb8, 0x80, 0x84, 0x94, 0xc1, 0xe7, 0xd5, 0x07, + 0xde, 0xd4, 0xdc, 0xce, 0x2a, 0xde, 0x74, 0xb8, 0xd9, 0xfd, 0x5a, 0x0f, + 0x91, 0x9a, 0x70, 0x8a, 0x34, 0x0a, 0xc9, 0x5f, 0x88, 0x28, 0xf9, 0x3a, + 0x79, 0xd6, 0xee, 0x4c, 0x82, 0xa4, 0x97, 0x24, 0x4a, 0x43, 0x2b, 0x25, + 0xf5, 0x55, 0xcb, 0x6f, 0x23, 0xb1, 0x2c, 0x9a, 0x43, 0xe6, 0x9e, 0xe1, + 0x70, 0x77, 0x07, 0x09, 0x14, 0x9c, 0x00, 0x5e, 0xb9, 0x22, 0x28, 0xd7, + 0xf9, 0x41, 0xe6, 0x13, 0xa6, 0x2b, 0x73, 0x5a, 0x4f, 0x6b, 0x98, 0x39, + 0xba, 0xf8, 0xa7, 0xfc, 0x07, 0x1d, 0xbf, 0x69, 0xcc, 0x00, 0xd1, 0x66, + 0xa6, 0x41, 0x00, 0x91, 0x41, 0x1e, 0xe0, 0x07, 0xcb, 0x16, 0xfe, 0xc6, + 0xe6, 0xd5, 0x54, 0xb4, 0x51, 0x4e, 0xf7, 0x2a, 0xb4, 0x86, 0xa0, 0x77, + 0xb8, 0x2b, 0xf2, 0x41, 0x2f, 0xb2, 0x03, 0xc0, 0x7a, 0x92, 0x7b, 0xcb, + 0xd5, 0x9a, 0x65, 0xd2, 0x37, 0x80, 0xbe, 0xdc, 0x4e, 0x0c, 0x3e, 0xaa, + 0x86, 0xef, 0x86, 0x01, 0xa8, 0x77, 0x36, 0xd7, 0xf2, 0xf5, 0xb9, 0xeb, + 0xd8, 0x6e, 0x5e, 0x12, 0x5d, 0xfc, 0xf7, 0x93, 0xb6, 0x91, 0xbc, 0x00, + 0x04, 0x67, 0x97, 0xf7, 0x37, 0xac, 0x3b, 0x81, 0xbe, 0xab, 0x3e, 0xfa, + 0x92, 0x67, 0xb1, 0x60, 0x4e, 0xf4, 0x64, 0x27, 0x08, 0x08, 0x32, 0x40, + 0x9a, 0x3e, 0x2c, 0x4c, 0x9a, 0x53, 0x45, 0xcc, 0xe1, 0xfa, 0x70, 0xda, + 0x8c, 0x00, 0x49, 0x6d, 0x0e, 0x4b, 0x22, 0xf6, 0x7f, 0xd1, 0x49, 0x37, + 0xa0, 0x28, 0x48, 0x5e, 0xa4, 0xc5, 0x76, 0xb8, 0x86, 0x1a, 0xa5, 0x34, + 0xe6, 0x0a, 0x25, 0x80, 0x48, 0x9f, 0x01, 0x25, 0xb3, 0xde, 0xf1, 0x0b, + 0xaf, 0x6b, 0x22, 0x1c, 0x60, 0x1c, 0xc9, 0xa3, 0x17, 0x96, 0x19, 0xb2, + 0x1b, 0xcb, 0xc2, 0x1d, 0xf6, 0x9f, 0xc2, 0x89, 0x99, 0xcd, 0x9b, 0x7f, + 0x67, 0x7e, 0x39, 0xdf, 0x37, 0x9b, 0xd3, 0xf3, 0x7f, 0xfe, 0xb8, 0x34, + 0xb0, 0xf0, 0x03, 0xbf, 0x33, 0x23, 0xa5, 0x01, 0x51, 0x28, 0x09, 0x90, + 0x89, 0x78, 0x4f, 0xd0, 0x1c, 0xf6, 0x61, 0xc6, 0xb4, 0xd4, 0x08, 0x9d, + 0x22, 0xcf, 0x08, 0xa4, 0x70, 0xc6, 0x79, 0x77, 0xa8, 0x15, 0xe9, 0x0d, + 0x74, 0x0a, 0xc6, 0x04, 0xb0, 0x6f, 0x39, 0x80, 0x43, 0xcc, 0xa8, 0xfc, + 0x5a, 0x32, 0xa0, 0x2a, 0xd6, 0x01, 0xb9, 0x41, 0xd1, 0xd8, 0x96, 0x5a, + 0x07, 0x25, 0xf4, 0x5c, 0x48, 0x1f, 0x0b, 0x38, 0x4c, 0x2e, 0x15, 0x23, + 0x32, 0xe2, 0xee, 0x7c, 0x7d, 0xf8, 0xa5, 0x89, 0xde, 0x89, 0x2f, 0xc7, + 0x4d, 0xba, 0x2f, 0xfe, 0x48, 0x95, 0x19, 0x4e, 0x06, 0x64, 0x4e, 0x54, + 0xfc, 0x0c, 0xf6, 0xc3, 0x5a, 0x17, 0xb0, 0x90, 0x9e, 0x52, 0x5c, 0xf2, + 0x51, 0xa4, 0x15, 0xc5, 0xf2, 0x98, 0xce, 0x50, 0xfc, 0xef, 0x86, 0x91, + 0x5b, 0x95, 0x23, 0x42, 0x48, 0xa3, 0x90, 0xea, 0xcb, 0x47, 0x98, 0xdf, + 0xf2, 0xcc, 0xfc, 0x5b, 0x0d, 0xdc, 0x8e, 0x78, 0x86, 0x58, 0xf2, 0xed, + 0xa0, 0x6a, 0xea, 0xe1, 0x51, 0xf1, 0x0c, 0xfb, 0x3a, 0x2c, 0x4e, 0x59, + 0xec, 0x82, 0x32, 0x65, 0x93, 0xc2, 0xd9, 0xa4, 0x32, 0x72, 0x41, 0x91, + 0x45, 0x23, 0x43, 0xc3, 0xab, 0x8a, 0xfb, 0xaf, 0x21, 0xc6, 0x42, 0x85, + 0x61, 0x24, 0xcb, 0x25, 0x09, 0xf4, 0xf6, 0x54, 0x1e, 0x45, 0xe1, 0x42, + 0x19, 0x49, 0x1c, 0x96, 0x11, 0x3c, 0x89, 0x2f, 0xf3, 0xa9, 0x48, 0x39, + 0x02, 0x14, 0x50, 0x26, 0x8f, 0x64, 0x33, 0x85, 0x4f, 0x35, 0x85, 0xe7, + 0xdd, 0x7f, 0x7d, 0xfb, 0xd9, 0xd4, 0x62, 0x06, 0x1a, 0x57, 0x10, 0xfe, + 0x12, 0xc6, 0x9e, 0x26, 0xb6, 0x5d, 0x41, 0xde, 0x66, 0x1e, 0xcf, 0x32, + 0x7b, 0x20, 0x4e, 0xec, 0xf1, 0x84, 0xb2, 0x28, 0x55, 0xd2, 0x4f, 0xcd, + 0x23, 0xff, 0xcb, 0xd4, 0x96, 0x6a, 0x16, 0xc9, 0x1a, 0xd8, 0x02, 0x59, + 0x7f, 0x06, 0x3e, 0x7d, 0xe1, 0x0f, 0x60, 0x79, 0xec, 0x1b, 0x41, 0x5f, + 0x99, 0xb9, 0x65, 0x5d, 0x82, 0xbe, 0x2f, 0x97, 0x8f, 0xd2, 0xef, 0x0e, + 0x32, 0xd7, 0xab, 0x65, 0xc5, 0xa1, 0x92, 0xf1, 0x74, 0x65, 0xf3, 0x00, + 0xb1, 0xab, 0x54, 0x7f, 0x26, 0x43, 0x2c, 0x4e, 0xba, 0x6d, 0x83, 0xb9, + 0x1a, 0x75, 0xec, 0x98, 0x6d, 0x1f, 0xa1, 0x37, 0xdb, 0xaa, 0x3e, 0xb4, + 0x1a, 0xef, 0xe9, 0x4a, 0x7a, 0x76, 0xe3, 0x66, 0x0c, 0x92, 0xf5, 0x06, + 0xcc, 0x39, 0x3d, 0x78, 0x84, 0x7a, 0x7e, 0xb0, 0x7d, 0xd5, 0xff, 0x20, + 0x07, 0x08, 0x68, 0x35, 0xbf, 0x04, 0xd8, 0xc6, 0x59, 0x67, 0xec, 0xa4, + 0x24, 0xfc, 0xce, 0x83, 0x4f, 0x44, 0x3e, 0xde, 0x86, 0xd4, 0x79, 0x9b, + 0xb0, 0xaf, 0x98, 0x4c, 0xf2, 0xa8, 0xe0, 0x1f, 0x47, 0x83, 0x85, 0x12, + 0xfb, 0x32, 0x01, 0x0a, 0x5a, 0xca, 0xc6, 0x92, 0x31, 0x8a, 0x45, 0x1a, + 0x3f, 0x57, 0x1f, 0xb8, 0x96, 0xe1, 0xfd, 0x20, 0xc8, 0x98, 0x54, 0x56, + 0x01, 0x27, 0x2a, 0x50, 0xcd, 0x0f, 0x9e, 0x36, 0xe2, 0x97, 0xae, 0x69, + 0x36, 0x86, 0x5e, 0x54, 0xcc, 0x68, 0x69, 0x73, 0x32, 0xdb, 0x56, 0xbf, + 0xfb, 0xa7, 0x66, 0x20, 0xd6, 0xcb, 0x06, 0x82, 0x07, 0x98, 0x46, 0x6f, + 0xb9, 0x61, 0xbe, 0x3d, 0x57, 0x3d, 0xed, 0x8f, 0x50, 0x2e, 0x56, 0x2f, + 0x37, 0x75, 0xed, 0x94, 0xc2, 0x72, 0x66, 0x91, 0x07, 0x95, 0xa5, 0x6d, + 0xf1, 0xb5, 0xaf, 0x8e, 0xd8, 0xcb, 0x20, 0x1a, 0x44, 0x09, 0xbc, 0xd0, + 0x13, 0x2c, 0x12, 0xb2, 0xa1, 0xf1, 0x3e, 0xda, 0x6b, 0x21, 0xad, 0x9d, + 0x53, 0x59, 0x33, 0x6e, 0x1a, 0x50, 0xb0, 0xc3, 0x19, 0x55, 0x31, 0x00, + 0x61, 0x7c, 0xa9, 0xe5, 0xf8, 0xb7, 0x7f, 0x2e, 0x8f, 0x9b, 0x6e, 0xd1, + 0x3a, 0x1c, 0x66, 0xd0, 0x65, 0xc3, 0x04, 0xe6, 0xe6, 0xf0, 0x98, 0x09, + 0x21, 0x95, 0xe2, 0x18, 0xa7, 0xb2, 0xbd, 0x90, 0x14, 0x05, 0x78, 0xcf, + 0x21, 0x65, 0xa1, 0x93, 0x47, 0x09, 0x15, 0xbe, 0x1f, 0x92, 0xf0, 0x15, + 0x32, 0x84, 0xd8, 0xe0, 0x22, 0x8c, 0xdc, 0xa3, 0x2f, 0x83, 0xf1, 0x43, + 0x14, 0x4c, 0x7e, 0xe1, 0xa0, 0x18, 0xef, 0x5f, 0xa2, 0x1b, 0xe6, 0x66, + 0x97, 0x2a, 0x3e, 0x2d, 0x7f, 0x80, 0x5a, 0x1b, 0xc7, 0x2e, 0x94, 0xdf, + 0x17, 0xe0, 0xfe, 0x8a, 0x77, 0x05, 0xc3, 0x3c, 0x33, 0x28, 0xc2, 0x90, + 0xc9, 0x66, 0x0a, 0x2a, 0x60, 0xa6, 0xec, 0x11, 0x9e, 0x54, 0xd2, 0x82, + 0x5f, 0xdc, 0x10, 0x88, 0x5b, 0x24, 0x6f, 0x4f, 0x69, 0x4a, 0xf5, 0xb8, + 0x5c, 0xac, 0xc6, 0xf7, 0x77, 0x35, 0x19, 0x81, 0x0a, 0x32, 0x0d, 0x92, + 0x11, 0xa3, 0xf1, 0xa2, 0xc8, 0x99, 0x4c, 0xb9, 0x43, 0x2d, 0x28, 0x4a, + 0xf5, 0x3e, 0x23, 0x36, 0x1d, 0xd1, 0xc3, 0x94, 0x87, 0xdc, 0x06, 0xfb, + 0x07, 0x78, 0x60, 0xed, 0x05, 0x2c, 0x9f, 0x65, 0x0f, 0xe5, 0x09, 0x53, + 0x9e, 0x84, 0x91, 0x66, 0x72, 0x4f, 0xc7, 0x1f, 0x05, 0xd6, 0x68, 0x7c, + 0x58, 0xd0, 0xcc, 0xd0, 0xec, 0xc2, 0x86, 0x98, 0x51, 0x7c, 0xa6, 0xa3, + 0x33, 0x56, 0xa1, 0x6f, 0xf1, 0xf8, 0x20, 0xcc, 0x48, 0xed, 0x46, 0xf2, + 0x69, 0x72, 0xf1, 0x72, 0x39, 0x69, 0x09, 0xde, 0x33, 0xf1, 0x54, 0x2b, + 0xcc, 0x4e, 0x3e, 0x52, 0x29, 0x11, 0xd8, 0x4f, 0x8f, 0x06, 0x60, 0xfd, + 0xdd, 0x5d, 0x34, 0xae, 0x37, 0xe6, 0x5c, 0x5e, 0x75, 0xc1, 0xd3, 0xbe, + 0x50, 0x24, 0xb6, 0xf7, 0x23, 0x87, 0xa5, 0xc3, 0x94, 0x12, 0xfc, 0x01, + 0xf7, 0xfb, 0xfb, 0x3b, 0xbe, 0x9e, 0xea, 0xce, 0x5e, 0x2e, 0xf5, 0xba, + 0x4f, 0x90, 0x5e, 0xa6, 0x8e, 0x4f, 0x4e, 0x84, 0x8d, 0x0f, 0x14, 0x61, + 0xf6, 0xe9, 0xd5, 0x5e, 0x6b, 0x35, 0x5b, 0xea, 0xba, 0xd0, 0x3b, 0xd4, + 0xb5, 0x33, 0x37, 0x63, 0xb7, 0x94, 0x98, 0x99, 0x4f, 0x2a, 0x7e, 0x3b, + 0x48, 0x1c, 0xeb, 0xb4, 0xa6, 0x9e, 0x76, 0x2b, 0xc2, 0x89, 0x3b, 0xf8, + 0x36, 0x55, 0xce, 0x57, 0x8d, 0xd0, 0x0b, 0xdd, 0x53, 0x34, 0xa0, 0x93, + 0x01, 0xb1, 0x80, 0x25, 0xa5, 0x51, 0xf1, 0x3d, 0x3e, 0xbc, 0xb3, 0x56, + 0x99, 0xb7, 0x12, 0xa1, 0x73, 0x23, 0x5f, 0x14, 0xf1, 0xb8, 0x83, 0x2e, + 0x73, 0x84, 0xf8, 0x82, 0xb4, 0x54, 0xcb, 0x4c, 0x6b, 0xdb, 0xf3, 0xf1, + 0x04, 0xad, 0x66, 0xb6, 0x7b, 0x9a, 0x25, 0x2c, 0x63, 0x80, 0xfb, 0x61, + 0x8c, 0x0d, 0x1e, 0xe0, 0x4e, 0xfe, 0x37, 0x63, 0x1e, 0x7a, 0x86, 0xfe, + 0xb7, 0x9d, 0x2b, 0x79, 0xd7, 0x9c, 0x0a, 0x0d, 0x35, 0x12, 0x40, 0x83, + 0x49, 0x55, 0x8c, 0x3d, 0x3a, 0xfb, 0x4a, 0x3e, 0xb6, 0xb6, 0xbb, 0xed, + 0x13, 0x6d, 0x2f, 0x9d, 0x95, 0x6e, 0xdc, 0xa9, 0x09, 0x9e, 0x7c, 0xfe, + 0x9c, 0xd5, 0xdd, 0x9d, 0xf3, 0x9e, 0xcf, 0xcb, 0xb9, 0x7e, 0xd7, 0x16, + 0xa2, 0x21, 0x08, 0x27, 0xa0, 0x8c, 0xb2, 0x20, 0x84, 0x6c, 0xee, 0xed, + 0xd3, 0x85, 0xee, 0x7c, 0x6d, 0xc1, 0x18, 0xf4, 0x55, 0x42, 0xa2, 0x29, + 0x55, 0x60, 0x27, 0xdb, 0xbd, 0x76, 0x26, 0x7a, 0x8f, 0x98, 0xcd, 0xa2, + 0xe9, 0xa9, 0x1e, 0xd0, 0x08, 0x4c, 0x26, 0xa8, 0x44, 0x61, 0x89, 0xab, + 0x01, 0xe1, 0xff, 0xb9, 0xbb, 0xc9, 0xc0, 0x14, 0xff, 0xfb, 0x38, 0xb7, + 0xcd, 0x04, 0xa1, 0xe5, 0x81, 0x38, 0xd8, 0x0a, 0x14, 0x6a, 0xd7, 0xe9, + 0x17, 0xb9, 0x25, 0xd0, 0xac, 0xff, 0x0b, 0xff, 0xb4, 0x60, 0xba, 0xbf, + 0x14, 0x9d, 0xee, 0x9b, 0xb3, 0x5c, 0x36, 0xe1, 0x1b, 0x07, 0x70, 0xec, + 0x25, 0x04, 0x03, 0x5e, 0x1d, 0x64, 0x4d, 0x3a, 0xb0, 0xdb, 0xab, 0x34, + 0xf4, 0xff, 0xbc, 0xb0, 0xda, 0x45, 0xa4, 0x96, 0x4f, 0xd8, 0x9b, 0x81, + 0x7f, 0xcd, 0x7e, 0xb6, 0xfb, 0x82, 0x4d, 0x88, 0x35, 0x25, 0x6c, 0x64, + 0x17, 0x97, 0x02, 0x29, 0x14, 0x92, 0x11, 0xf3, 0x2f, 0xf5, 0x69, 0x5c, + 0x40, 0x36, 0x9c, 0xf0, 0x29, 0xc3, 0x40, 0xb6, 0x58, 0x14, 0x27, 0x31, + 0x42, 0x0a, 0xcd, 0x12, 0x7b, 0x83, 0x82, 0x79, 0x2d, 0x7f, 0x1d, 0x07, + 0x43, 0x8e, 0x96, 0x8c, 0x98, 0xa0, 0xf3, 0xcf, 0x90, 0x4e, 0x1f, 0x77, + 0x4a, 0x95, 0xaf, 0x3e, 0x8d, 0x81, 0x9f, 0x79, 0x66, 0x73, 0x92, 0x43, + 0xb8, 0x07, 0x8b, 0xba, 0xc1, 0xaf, 0xbd, 0xee, 0x7f, 0x99, 0xbf, 0x1c, + 0xde, 0x07, 0xac, 0xb2, 0x24, 0x83, 0xb2, 0x38, 0x76, 0xca, 0xf0, 0xdc, + 0x5a, 0xf6, 0xf7, 0xfd, 0xdc, 0xb8, 0xc4, 0xf6, 0xc4, 0x50, 0xe3, 0x48, + 0x11, 0x4e, 0x64, 0xbd, 0xa7, 0x2e, 0x73, 0x94, 0xaa, 0xc3, 0xe2, 0x3d, + 0xec, 0x8f, 0xb7, 0xff, 0xe3, 0x30, 0xbe, 0x4e, 0x5d, 0x0d, 0xb1, 0xa1, + 0xe9, 0xfb, 0x29, 0x07, 0xd8, 0x37, 0xd1, 0xd7, 0xea, 0x2e, 0x3f, 0x5c, + 0x3a, 0xf0, 0xa9, 0x75, 0xd9, 0x5d, 0x54, 0xbf, 0x2f, 0x9e, 0x9d, 0x2b, + 0x73, 0x97, 0xe1, 0x88, 0x5c, 0xe2, 0xe2, 0xa2, 0xd8, 0xe4, 0xbc, 0xe4, + 0xa3, 0x0c, 0x30, 0x25, 0x77, 0x00, 0x88, 0xea, 0x97, 0x2b, 0xfe, 0xae, + 0xdd, 0xdd, 0x6a, 0x16, 0x26, 0x40, 0xa9, 0xc4, 0x03, 0x2d, 0x89, 0x82, + 0x06, 0x9a, 0x33, 0xbd, 0x3e, 0x20, 0x8e, 0xc5, 0x8b, 0x63, 0xda, 0xf5, + 0xed, 0xaf, 0x83, 0xfd, 0xd8, 0x65, 0x62, 0x0e, 0xd2, 0x72, 0xa3, 0x0a, + 0x1d, 0x90, 0xeb, 0x8e, 0xdd, 0xf7, 0x58, 0xdf, 0x8f, 0x65, 0xec, 0x3b, + 0x5c, 0x18, 0x8c, 0xb6, 0x22, 0x4a, 0x7d, 0x63, 0x90, 0xc0, 0x9c, 0x3c, + 0x9c, 0x65, 0x04, 0x7e, 0xc3, 0xe7, 0xa5, 0x12, 0x57, 0x96, 0x63, 0x31, + 0xeb, 0xe6, 0x29, 0x9e, 0xdc, 0xab, 0x30, 0x3b, 0x18, 0x58, 0x38, 0x28, + 0x20, 0x40, 0x3e, 0x01, 0x56, 0x41, 0xe2, 0xf2, 0x3f, 0x7b, 0xf3, 0x37, + 0x60, 0x53, 0x14, 0xd6, 0x75, 0xe8, 0xb1, 0xfe, 0xb7, 0x06, 0x1b, 0x7c, + 0x36, 0x36, 0xcc, 0x88, 0x94, 0xf5, 0x03, 0x89, 0x09, 0x42, 0x3e, 0x8b, + 0x8d, 0x58, 0xfd, 0x5c, 0xcd, 0x2f, 0xd9, 0x96, 0xcd, 0xd7, 0x3d, 0x9d, + 0x88, 0x13, 0x91, 0x16, 0x31, 0x38, 0xaf, 0x47, 0xb5, 0xbd, 0x88, 0x48, + 0xfd, 0x2f, 0x39, 0xa5, 0xe0, 0x59, 0x31, 0x52, 0x99, 0xbf, 0x23, 0x72, + 0x3b, 0xf5, 0xbb, 0xd7, 0xdd, 0xda, 0xa6, 0x26, 0x0d, 0x4c, 0x8d, 0x13, + 0x93, 0xda, 0x52, 0x43, 0x22, 0x02, 0xa1, 0x66, 0xb8, 0x71, 0x7c, 0xad, + 0x57, 0x9b, 0x65, 0x53, 0x2b, 0x32, 0xa7, 0x04, 0xd1, 0x0c, 0x8e, 0x34, + 0xf2, 0xcf, 0x88, 0x3c, 0xd2, 0xd1, 0x9f, 0x17, 0xfd, 0x4e, 0x2d, 0xb7, + 0x62, 0xac, 0x9d, 0xef, 0xb4, 0x96, 0x1b, 0x52, 0x94, 0x16, 0x69, 0xa6, + 0x65, 0xa4, 0xac, 0x04, 0x94, 0x4f, 0x89, 0xd3, 0x7d, 0xde, 0xe1, 0xba, + 0xd3, 0x2d, 0x8f, 0x05, 0x19, 0xa2, 0x89, 0x92, 0x3f, 0x10, 0xce, 0xb0, + 0xf9, 0x5e, 0xfb, 0x3c, 0xb6, 0x59, 0xe5, 0xab, 0xb0, 0x21, 0x7d, 0xb3, + 0x57, 0xf2, 0x82, 0xbf, 0x63, 0xce, 0x0c, 0x00, 0x16, 0x7e, 0xdb, 0x22, + 0x0c, 0xb1, 0xa4, 0x72, 0x49, 0x1f, 0xb4, 0x4f, 0x51, 0xb0, 0xe9, 0xba, + 0x69, 0xb7, 0x6a, 0xc8, 0xc4, 0x57, 0xfc, 0x94, 0xa1, 0xf4, 0x93, 0xd9, + 0x02, 0xe3, 0xde, 0xde, 0x7f, 0x6a, 0x19, 0x52, 0xa2, 0xd0, 0xc1, 0x87, + 0x40, 0xe3, 0x00, 0x52, 0xf6, 0x04, 0x85, 0x64, 0xc5, 0xd5, 0xa7, 0x98, + 0x36, 0xea, 0x7c, 0xce, 0x84, 0x32, 0x93, 0x1c, 0x95, 0x06, 0x38, 0x4b, + 0xe1, 0xa3, 0xf0, 0x22, 0x4f, 0x3e, 0xa4, 0x0c, 0x19, 0x2f, 0x70, 0x0b, + 0x50, 0x8a, 0x9a, 0x2d, 0x87, 0x5f, 0xc6, 0xa8, 0x6c, 0xa8, 0xd7, 0xa1, + 0x46, 0x02, 0xe8, 0x22, 0x4d, 0x01, 0x29, 0x19, 0x7c, 0xf2, 0xdf, 0xcd, + 0xdc, 0xbb, 0xce, 0x11, 0x93, 0x4a, 0xca, 0x95, 0x58, 0x24, 0x6d, 0x7f, + 0xf3, 0xd2, 0xdd, 0x16, 0xcb, 0x1f, 0x3c, 0xeb, 0xce, 0x8a, 0x24, 0x44, + 0xb4, 0xfb, 0x12, 0x46, 0x61, 0x12, 0x32, 0x91, 0xab, 0x27, 0x49, 0x3f, + 0x31, 0x13, 0xae, 0xba, 0x4f, 0x6f, 0x0a, 0x39, 0x7a, 0xc6, 0x9e, 0x43, + 0x1f, 0x34, 0x56, 0x00, 0xf1, 0xad, 0x68, 0x63, 0xa5, 0x51, 0x03, 0x09, + 0x38, 0xd9, 0x1e, 0xdf, 0xd8, 0x39, 0xd7, 0x07, 0x6c, 0x77, 0x51, 0xb8, + 0x6a, 0xf6, 0x82, 0x3b, 0x46, 0x58, 0xd5, 0x69, 0xd1, 0xf7, 0xf3, 0xef, + 0xb8, 0xf7, 0xb8, 0x7f, 0xc7, 0x7f, 0x8f, 0xeb, 0xb1, 0xe6, 0x3d, 0x1a, + 0xcb, 0x0a, 0xc7, 0x0d, 0x3a, 0xbe, 0xb3, 0x2d, 0x00, 0x52, 0x89, 0x85, + 0xf2, 0x08, 0x50, 0xad, 0xfc, 0x50, 0xa0, 0x25, 0x0f, 0x02, 0x78, 0x82, + 0x9f, 0xf2, 0x56, 0x86, 0x81, 0x9b, 0xb9, 0x9e, 0x49, 0x23, 0xe2, 0xd3, + 0x3b, 0x28, 0x9c, 0x32, 0x18, 0x07, 0xcf, 0x32, 0xbc, 0x2f, 0xe4, 0xa0, + 0xbc, 0x68, 0x08, 0x94, 0x01, 0xe1, 0x0f, 0x33, 0x43, 0x27, 0xf1, 0x68, + 0x8f, 0xb0, 0xcf, 0x3e, 0x27, 0x2d, 0xd4, 0xd3, 0x2f, 0x3e, 0x17, 0xa9, + 0x49, 0xa6, 0x08, 0x9a, 0x04, 0xd0, 0xc8, 0xa4, 0xb9, 0xd6, 0x98, 0xdd, + 0x37, 0xe2, 0x9c, 0xe7, 0x3c, 0x49, 0xc0, 0x58, 0xd4, 0x4e, 0x8e, 0x5f, + 0xc7, 0xf5, 0x7e, 0x6f, 0xcb, 0x3c, 0x28, 0x4b, 0x58, 0x78, 0x00, 0xa0, + 0x27, 0x94, 0x12, 0x87, 0x81, 0x67, 0x14, 0x10, 0x82, 0x89, 0xc9, 0xcc, + 0x4e, 0x85, 0xdd, 0x5a, 0xeb, 0x11, 0xc9, 0x08, 0x28, 0xa9, 0x86, 0x39, + 0x8c, 0x1b, 0x08, 0x16, 0xc7, 0xfb, 0xb4, 0xd3, 0x98, 0x9f, 0xd5, 0xe8, + 0x3e, 0x41, 0x30, 0x4b, 0x2c, 0x29, 0x02, 0x4f, 0x81, 0xbf, 0xd1, 0xeb, + 0x55, 0x7e, 0xc2, 0xcb, 0x84, 0xc1, 0x4f, 0x5c, 0xac, 0x59, 0x94, 0x94, + 0xb7, 0x86, 0x7f, 0x31, 0xf6, 0xb8, 0xd7, 0x0b, 0x22, 0x7c, 0x47, 0x6c, + 0xd0, 0xa8, 0xff, 0x6f, 0x82, 0x63, 0x17, 0x6c, 0xa8, 0x09, 0x48, 0x4b, + 0xc1, 0xab, 0x50, 0xda, 0xa3, 0xaf, 0xfa, 0xe4, 0x2f, 0x7c, 0x83, 0xa4, + 0x8e, 0xc0, 0xd5, 0xec, 0x70, 0xef, 0x24, 0x8e, 0xe1, 0x2f, 0x29, 0x64, + 0xef, 0x58, 0xc2, 0xea, 0xf1, 0xe1, 0xb3, 0xce, 0xa9, 0xd4, 0x62, 0x89, + 0x96, 0x42, 0x9c, 0xa6, 0x72, 0x21, 0x2c, 0xe0, 0xef, 0x9d, 0xbd, 0x6d, + 0x7f, 0xf8, 0xa7, 0x5e, 0x0f, 0xb2, 0xcb, 0x61, 0x24, 0x51, 0x80, 0x91, + 0x02, 0x54, 0x12, 0x33, 0xfa, 0x3b, 0x2a, 0x38, 0xb7, 0x97, 0xc0, 0x5b, + 0x42, 0x8d, 0xed, 0xf8, 0xc8, 0x93, 0x96, 0x0c, 0x14, 0x72, 0xa7, 0x3b, + 0xd6, 0xa3, 0xf7, 0xf9, 0xff, 0x79, 0xd9, 0x9b, 0x63, 0x83, 0xa4, 0x08, + 0x67, 0x13, 0x48, 0xa5, 0xe3, 0x9a, 0x13, 0xee, 0x21, 0xab, 0x97, 0x69, + 0xc3, 0xd0, 0xe8, 0x6b, 0x23, 0x44, 0x23, 0x7b, 0x47, 0x0e, 0x0a, 0x52, + 0x47, 0xed, 0x2e, 0xe2, 0x5c, 0x6e, 0x75, 0x68, 0xea, 0xf6, 0x02, 0x70, + 0xf4, 0x86, 0x32, 0xe7, 0x34, 0x32, 0x11, 0xc9, 0xca, 0x85, 0x64, 0x3d, + 0x2b, 0x5a, 0x80, 0x71, 0x0c, 0x09, 0x78, 0xa6, 0x11, 0xf1, 0x10, 0x4a, + 0xac, 0x11, 0x03, 0x32, 0x7c, 0xca, 0x80, 0xba, 0x99, 0x92, 0xb2, 0xdd, + 0x92, 0xfd, 0x33, 0xfb, 0x69, 0x6d, 0x45, 0x0b, 0x76, 0xb7, 0x03, 0x0c, + 0x84, 0xa6, 0x52, 0x89, 0x22, 0x85, 0xe9, 0xc2, 0x14, 0xe4, 0x4d, 0xa5, + 0x39, 0xe5, 0x05, 0x09, 0x81, 0x97, 0x0e, 0x52, 0x57, 0xc7, 0x3e, 0x8b, + 0xec, 0x3d, 0x3d, 0x41, 0xb9, 0x41, 0x23, 0xb2, 0x61, 0x91, 0x9c, 0x25, + 0x02, 0xe5, 0x1c, 0xa1, 0x3f, 0xb1, 0xab, 0x31, 0x45, 0xe8, 0x97, 0xdb, + 0x97, 0x9d, 0x19, 0x40, 0x86, 0x5a, 0x43, 0x09, 0x2b, 0xd1, 0x14, 0x3e, + 0x2e, 0x5f, 0xa6, 0xaa, 0x2c, 0x85, 0x10, 0x68, 0x20, 0x91, 0xf9, 0xc4, + 0xa7, 0x3f, 0x98, 0x37, 0xa7, 0xe7, 0x82, 0xff, 0x18, 0xb4, 0x38, 0x71, + 0x43, 0x00, 0x09, 0x59, 0x82, 0x4d, 0xad, 0xbf, 0x59, 0xe7, 0x71, 0x0b, + 0x09, 0x98, 0x34, 0xd8, 0xee, 0xe4, 0x19, 0x48, 0x37, 0x6a, 0x51, 0x95, + 0x60, 0x0a, 0xb4, 0x39, 0x05, 0xc3, 0x21, 0x94, 0x8a, 0x18, 0x0a, 0x11, + 0xa0, 0x04, 0x4c, 0xde, 0xad, 0xe3, 0x5c, 0xe3, 0x5e, 0x5b, 0xa3, 0xba, + 0x46, 0xbf, 0x63, 0xa1, 0x50, 0xf2, 0x0d, 0xe5, 0xd5, 0x4f, 0xc8, 0xf1, + 0x5c, 0xde, 0xa2, 0x83, 0xec, 0xcf, 0x3d, 0x5e, 0xfe, 0x56, 0xf3, 0xad, + 0xe5, 0x57, 0x92, 0xc9, 0xa5, 0x25, 0x4d, 0x97, 0x22, 0x11, 0x67, 0x62, + 0x4b, 0x46, 0x58, 0x97, 0xd0, 0x13, 0x6f, 0x7f, 0xa7, 0xe5, 0x62, 0xf3, + 0xc3, 0x00, 0x95, 0x48, 0x69, 0x25, 0x81, 0x7f, 0xc1, 0xee, 0xb0, 0x58, + 0x6d, 0x79, 0x9f, 0x53, 0x9e, 0xa8, 0xbb, 0x93, 0x90, 0xc2, 0x08, 0x0a, + 0x22, 0x53, 0xab, 0x53, 0x26, 0x7c, 0xbc, 0x26, 0x9f, 0xe2, 0xc8, 0x78, + 0x75, 0x3b, 0x08, 0x54, 0xf2, 0x86, 0x44, 0x63, 0x6c, 0x48, 0x9c, 0x67, + 0xee, 0x3e, 0x01, 0xf0, 0xb6, 0x6c, 0x8d, 0xf9, 0x22, 0xb8, 0xbe, 0xfe, + 0xb5, 0x7d, 0xda, 0x99, 0x7b, 0xa5, 0x3c, 0x60, 0x8d, 0x24, 0xb1, 0x40, + 0xf7, 0x26, 0x7e, 0x2b, 0x40, 0x4f, 0x67, 0x4d, 0x90, 0xe6, 0x43, 0x7c, + 0x53, 0x58, 0x2e, 0x09, 0x3d, 0x89, 0xff, 0xb7, 0x76, 0x5f, 0x8d, 0xf9, + 0x85, 0x92, 0xe1, 0xbb, 0x50, 0x3b, 0x5e, 0x50, 0x46, 0x7d, 0xa3, 0x1a, + 0x00, 0x7d, 0x85, 0xd1, 0xce, 0x62, 0x79, 0xf3, 0xaa, 0x93, 0x23, 0x39, + 0xb8, 0x2a, 0x09, 0x13, 0x94, 0x32, 0x7e, 0x2e, 0xbb, 0x7d, 0x05, 0x4d, + 0x25, 0x05, 0x53, 0xfd, 0x4d, 0xb8, 0x69, 0xe3, 0xb1, 0x6a, 0x8f, 0x44, + 0x20, 0x46, 0x4e, 0x7e, 0x07, 0x57, 0x7e, 0xe5, 0xad, 0xfb, 0xcf, 0x79, + 0xed, 0xd7, 0x09, 0x27, 0xaa, 0x0f, 0x5f, 0xd3, 0xd1, 0x0c, 0xc0, 0xc9, + 0x95, 0xa9, 0x63, 0x0e, 0xe0, 0x43, 0xa4, 0x77, 0x40, 0xfc, 0xda, 0xa7, + 0x7d, 0xb6, 0xd4, 0x35, 0xd9, 0x9e, 0x4f, 0x62, 0x45, 0x2b, 0x62, 0x84, + 0x86, 0xe7, 0x07, 0x70, 0xbb, 0xef, 0x7e, 0x0b, 0x7e, 0xe3, 0xa3, 0xc0, + 0x74, 0xc0, 0x1d, 0xf0, 0xe5, 0x18, 0x00, 0x08, 0x83, 0x40, 0xe5, 0xca, + 0x58, 0x4b, 0x7c, 0x36, 0x76, 0x29, 0x65, 0x05, 0x49, 0xf7, 0xdf, 0xe5, + 0x44, 0xe7, 0x71, 0x74, 0xe7, 0x83, 0x7b, 0x53, 0x0d, 0x3a, 0x78, 0xf2, + 0x40, 0x22, 0x11, 0x4b, 0x97, 0x88, 0xae, 0xec, 0xa7, 0x3f, 0x21, 0x5a, + 0x81, 0x9e, 0x9f, 0x4b, 0x7d, 0xb1, 0xa2, 0xa7, 0x08, 0x96, 0x70, 0x96, + 0xc6, 0xb1, 0x6a, 0x36, 0xe2, 0x15, 0x75, 0xb0, 0xca, 0x95, 0x7e, 0x45, + 0xc0, 0x45, 0xb2, 0xb4, 0x6b, 0xc3, 0x0c, 0x28, 0x25, 0x64, 0xfe, 0xa2, + 0x15, 0x03, 0x3f, 0xaa, 0xde, 0xf2, 0xb5, 0xed, 0xe4, 0x03, 0x38, 0x37, + 0xb2, 0x48, 0xa0, 0x8b, 0x60, 0x28, 0xcb, 0x2d, 0xa7, 0x84, 0x2e, 0x2d, + 0xe3, 0x0a, 0x37, 0x36, 0xca, 0x1a, 0xaa, 0x03, 0xb4, 0x2f, 0xe5, 0xad, + 0xf7, 0xc9, 0x0f, 0x8b, 0xab, 0x47, 0x66, 0xcb, 0x99, 0x83, 0x52, 0xc7, + 0xa0, 0x96, 0x2a, 0xc3, 0x17, 0xbf, 0xe0, 0x62, 0xde, 0xe2, 0x1d, 0x21, + 0x0b, 0x4f, 0x1d, 0x0c, 0x97, 0xda, 0x8b, 0xc2, 0x9e, 0xea, 0x1e, 0xd5, + 0x88, 0x1b, 0x4e, 0xec, 0xca, 0xd0, 0x08, 0x0d, 0x20, 0x65, 0x29, 0x48, + 0x7c, 0xc0, 0x9f, 0xce, 0x3a, 0xaf, 0xe2, 0x5b, 0xfd, 0xfc, 0xb7, 0x63, + 0xbd, 0x6c, 0x40, 0x10, 0xab, 0xda, 0x72, 0xce, 0x88, 0xca, 0x1f, 0x6d, + 0x49, 0x02, 0x76, 0x22, 0x5a, 0x27, 0xe2, 0x82, 0xa3, 0x9f, 0xdb, 0xdd, + 0xa6, 0xfc, 0x09, 0xd6, 0xce, 0xec, 0xde, 0xe9, 0x34, 0xe0, 0x76, 0xa3, + 0x33, 0x29, 0x83, 0x4d, 0xd0, 0x39, 0x04, 0x19, 0xdf, 0xb5, 0x4f, 0xd8, + 0x29, 0xe5, 0x21, 0xba, 0x63, 0x67, 0x73, 0x40, 0x13, 0xbc, 0x3d, 0x39, + 0x94, 0x21, 0x28, 0x43, 0x59, 0x13, 0xe2, 0x7b, 0xdc, 0xb8, 0x0e, 0x75, + 0xdd, 0x96, 0x7d, 0x63, 0x52, 0xd9, 0x9b, 0x8d, 0xb1, 0xa0, 0x8f, 0x81, + 0x7e, 0x5f, 0x67, 0xfe, 0xae, 0x20, 0x58, 0xb3, 0x54, 0xe1, 0x9c, 0x98, + 0x3b, 0xed, 0x13, 0x2c, 0x47, 0x91, 0x38, 0x05, 0x0c, 0x24, 0x20, 0x03, + 0xc7, 0x83, 0x2f, 0xde, 0x76, 0xd3, 0xa1, 0xfc, 0x83, 0x65, 0xc2, 0xae, + 0xc6, 0x7f, 0xda, 0x0d, 0x68, 0xa1, 0x03, 0xce, 0x54, 0x75, 0x97, 0xe1, + 0x46, 0x7c, 0xd7, 0x9b, 0x9e, 0x0f, 0xed, 0x17, 0xb1, 0xf9, 0x7a, 0x86, + 0xc5, 0x54, 0x8b, 0xd3, 0x92, 0xac, 0x91, 0x83, 0x1e, 0xa2, 0x81, 0xcc, + 0xe8, 0x94, 0x3e, 0xaf, 0x17, 0x33, 0x37, 0x2f, 0x2b, 0x1f, 0x88, 0x75, + 0x27, 0x84, 0xda, 0x89, 0x72, 0x10, 0x9a, 0x13, 0x03, 0x19, 0x9e, 0x69, + 0x1f, 0x03, 0x3a, 0xb4, 0x2b, 0xaf, 0x1c, 0xf4, 0x4e, 0xf4, 0x26, 0xc6, + 0x14, 0x02, 0xf4, 0x4c, 0x2d, 0x90, 0xe5, 0x8c, 0x95, 0x8f, 0xf5, 0xf9, + 0x1e, 0x38, 0x1f, 0xc7, 0x57, 0x45, 0xdd, 0xab, 0x14, 0x24, 0x1e, 0x16, + 0xf3, 0x1c, 0x7b, 0xeb, 0x60, 0x3e, 0xa9, 0x75, 0xe4, 0xbd, 0xe7, 0xa7, + 0x66, 0x72, 0x2e, 0xec, 0xa1, 0x6a, 0x9d, 0xc9, 0x3c, 0x79, 0xb4, 0x07, + 0x95, 0x48, 0x88, 0x21, 0xa1, 0xf5, 0x33, 0x26, 0x34, 0x54, 0xf3, 0xc5, + 0x44, 0x1a, 0x61, 0xea, 0x27, 0x82, 0x84, 0xe4, 0x7e, 0xa9, 0x06, 0x1e, + 0x49, 0xc7, 0x1a, 0x62, 0x8c, 0x84, 0x33, 0x79, 0xcd, 0xa5, 0xb3, 0xb9, + 0x4f, 0x1d, 0x1f, 0xab, 0x89, 0x3b, 0xbc, 0x08, 0x64, 0x78, 0x31, 0xd1, + 0x9d, 0x5e, 0x60, 0x8a, 0x08, 0xf7, 0x31, 0xe7, 0xb3, 0x88, 0x65, 0x73, + 0x01, 0x46, 0x02, 0x8c, 0xcc, 0xa4, 0x8a, 0x07, 0x2e, 0x59, 0x5f, 0x3c, + 0x16, 0xcc, 0xda, 0x51, 0x69, 0x04, 0x20, 0xd5, 0x14, 0x8c, 0x26, 0x34, + 0xbe, 0x39, 0x00, 0x8c, 0x60, 0xc6, 0x83, 0xd0, 0x93, 0x99, 0xf7, 0x29, + 0x81, 0x0c, 0x31, 0x21, 0x0f, 0x32, 0xc7, 0x00, 0x48, 0x25, 0x9f, 0xb3, + 0x84, 0x89, 0xe1, 0x3e, 0x90, 0xf8, 0x0d, 0x66, 0x4e, 0xed, 0xc5, 0x3e, + 0xd3, 0x14, 0xce, 0x55, 0x3e, 0xf6, 0x0d, 0xc5, 0x6d, 0xe3, 0xad, 0x68, + 0x8a, 0x07, 0x19, 0xf1, 0x8a, 0xca, 0x28, 0xf3, 0x6b, 0x54, 0x31, 0x97, + 0x8c, 0xf2, 0x90, 0xc2, 0x17, 0xef, 0x13, 0x63, 0x8d, 0xbd, 0x29, 0x8a, + 0x46, 0x48, 0x63, 0xe5, 0xa5, 0x65, 0xf8, 0x19, 0x92, 0xc5, 0x6d, 0x3a, + 0x95, 0xd9, 0xce, 0xdc, 0x03, 0x01, 0x9c, 0x28, 0x55, 0x32, 0x49, 0x24, + 0x0f, 0x39, 0x5d, 0x66, 0x55, 0xac, 0x5b, 0x4d, 0xc3, 0xa7, 0xe7, 0x70, + 0x9c, 0x57, 0x42, 0xbc, 0x95, 0xa6, 0xa2, 0xc0, 0xa2, 0x4f, 0x64, 0xef, + 0x38, 0x20, 0xce, 0x2a, 0x0b, 0xf1, 0x74, 0x7f, 0x6f, 0x94, 0xf7, 0xac, + 0xa0, 0xaf, 0xd3, 0x97, 0xbc, 0xb5, 0x8a, 0x81, 0x18, 0xd8, 0x74, 0x28, + 0x50, 0xf9, 0xfe, 0xdb, 0x69, 0x9a, 0xfc, 0xb5, 0x3a, 0xbc, 0xa2, 0x89, + 0x74, 0xb3, 0x92, 0xf0, 0x05, 0x5f, 0xde, 0xd1, 0x0b, 0xea, 0xc1, 0x23, + 0x31, 0x87, 0xed, 0x24, 0x67, 0x38, 0x00, 0x3f, 0x38, 0xde, 0xba, 0x70, + 0xbc, 0x57, 0x90, 0x30, 0xa0, 0x66, 0x32, 0x53, 0x43, 0xb2, 0x78, 0x50, + 0xf3, 0x28, 0x06, 0xf9, 0x94, 0xba, 0x7b, 0xbd, 0xf6, 0x7b, 0x6f, 0xfd, + 0xce, 0x5f, 0xae, 0xc3, 0x1c, 0x3f, 0x4b, 0x66, 0x25, 0xa2, 0x27, 0x49, + 0xe6, 0xed, 0x0a, 0x22, 0x84, 0xeb, 0x22, 0xf8, 0xf6, 0xb3, 0xf1, 0xdf, + 0x9b, 0xa7, 0x17, 0x07, 0x28, 0xd3, 0xc4, 0x93, 0x46, 0x41, 0x06, 0x19, + 0x39, 0x04, 0x7c, 0x41, 0x16, 0x66, 0xf0, 0x7b, 0x0a, 0x6e, 0x3b, 0xc7, + 0x3a, 0xc9, 0x3e, 0x3d, 0x5d, 0x2f, 0x4d, 0xdd, 0xea, 0x14, 0x0e, 0x50, + 0x22, 0x8e, 0x2e, 0x1f, 0x64, 0x4f, 0x0d, 0x58, 0x07, 0x37, 0x5d, 0x84, + 0x45, 0x69, 0xdc, 0x43, 0xa8, 0x18, 0xd3, 0x92, 0x32, 0x42, 0x68, 0x1a, + 0xb1, 0x4b, 0x16, 0x70, 0xab, 0x94, 0xa2, 0x89, 0xd6, 0xdc, 0xf7, 0x5f, + 0xe0, 0x0f, 0xf6, 0xd7, 0x3a, 0xe6, 0x1e, 0x46, 0xca, 0x30, 0xa9, 0xa1, + 0x90, 0x32, 0xa0, 0x5f, 0x88, 0x27, 0x41, 0x1f, 0xa8, 0x34, 0xd9, 0xe7, + 0x49, 0x27, 0x68, 0xba, 0x5b, 0x1d, 0x75, 0x13, 0xc9, 0x9c, 0x96, 0x4f, + 0xc1, 0x37, 0x39, 0xdf, 0xae, 0x4d, 0x6b, 0xe4, 0x84, 0x63, 0x11, 0xf1, + 0x50, 0x08, 0xf8, 0xc8, 0x50, 0xb1, 0xbe, 0xdf, 0x52, 0x69, 0x89, 0x8a, + 0x9d, 0xb9, 0x96, 0x30, 0x23, 0x22, 0x18, 0x43, 0x8a, 0xf4, 0xbb, 0x46, + 0xed, 0x72, 0x67, 0x08, 0x5c, 0x7a, 0x9f, 0xa8, 0x18, 0xf8, 0xc1, 0x21, + 0x34, 0x67, 0xe9, 0xfa, 0xad, 0xc8, 0x53, 0x18, 0x50, 0x12, 0xa1, 0x21, + 0x33, 0x92, 0xf0, 0x89, 0xf5, 0x65, 0xfc, 0xba, 0x8a, 0x18, 0xba, 0xba, + 0x66, 0x06, 0x3e, 0x64, 0x68, 0xb6, 0x83, 0xcf, 0x79, 0x75, 0xf9, 0x90, + 0x86, 0x4b, 0xc5, 0x5f, 0xff, 0x6c, 0xa3, 0xab, 0x8a, 0x43, 0x28, 0xf4, + 0x7d, 0x4e, 0x69, 0x13, 0x30, 0x32, 0xea, 0xf4, 0xea, 0xd8, 0xc7, 0xf4, + 0xcb, 0xff, 0x4b, 0xd3, 0x8a, 0x36, 0x0c, 0xf0, 0x1f, 0x01, 0x4c, 0xd7, + 0x41, 0x20, 0xc4, 0xde, 0xc7, 0xa5, 0x76, 0xf0, 0x65, 0xf3, 0x03, 0x10, + 0x8e, 0xda, 0x7f, 0xd9, 0x89, 0x47, 0xce, 0x11, 0x88, 0x45, 0x36, 0x9d, + 0x4c, 0x65, 0x5b, 0xea, 0xc5, 0xe5, 0x87, 0x75, 0x29, 0xd4, 0xff, 0x15, + 0x4f, 0x7a, 0x3c, 0x4d, 0x07, 0x62, 0x8e, 0xab, 0x73, 0x26, 0x50, 0x02, + 0xc6, 0x11, 0xf3, 0x34, 0x3b, 0x82, 0x52, 0xb1, 0xe1, 0x64, 0x9e, 0x9b, + 0xff, 0x10, 0x40, 0x08, 0x0e, 0x34, 0x01, 0x33, 0x82, 0x6f, 0x4b, 0x46, + 0x80, 0x42, 0xb2, 0xb1, 0x45, 0xdd, 0xed, 0x99, 0x39, 0x18, 0x28, 0xbc, + 0xa8, 0xe1, 0xf1, 0x90, 0x4b, 0xfa, 0xf2, 0x6a, 0x9c, 0xa2, 0x06, 0xdc, + 0xfe, 0x97, 0x20, 0x51, 0x24, 0xb8, 0x07, 0x1a, 0x1c, 0x7d, 0xa4, 0x7b, + 0x68, 0x93, 0x9e, 0x2e, 0x4c, 0x3b, 0xd9, 0xae, 0x77, 0x97, 0x40, 0xd2, + 0xd4, 0x92, 0x51, 0x39, 0x2a, 0x19, 0x10, 0x05, 0x91, 0xfc, 0x7f, 0x96, + 0x34, 0x80, 0x4b, 0x8c, 0x0c, 0x61, 0x46, 0x8f, 0xd1, 0xf7, 0x62, 0xad, + 0x6a, 0xfd, 0x78, 0xb9, 0x9d, 0x45, 0x8c, 0x95, 0x44, 0x21, 0xdc, 0x35, + 0xa9, 0x92, 0x31, 0xb5, 0x06, 0x1a, 0x79, 0x46, 0x16, 0x28, 0x51, 0x4b, + 0x48, 0x56, 0x68, 0x31, 0x45, 0x46, 0xcd, 0x05, 0x0a, 0x18, 0x7c, 0x9f, + 0x64, 0xec, 0xb6, 0x6a, 0xf4, 0xed, 0x0f, 0x86, 0xd0, 0x28, 0x24, 0x5e, + 0x86, 0x1c, 0xa5, 0x61, 0x03, 0x95, 0x39, 0x40, 0x17, 0xf9, 0x82, 0xd3, + 0xf8, 0xc5, 0x2a, 0x8c, 0xde, 0x73, 0xc3, 0x7a, 0x7b, 0x91, 0x61, 0x86, + 0x83, 0x09, 0xcf, 0xb0, 0x74, 0x3e, 0x7a, 0xc7, 0xe6, 0x76, 0x47, 0x2a, + 0xf4, 0x7c, 0xe7, 0x0c, 0xc2, 0x63, 0x64, 0xc6, 0x57, 0x80, 0x17, 0x08, + 0x14, 0x17, 0xe7, 0x21, 0xdb, 0x66, 0x54, 0x18, 0x88, 0x0b, 0x65, 0x42, + 0x97, 0x46, 0x7d, 0x91, 0x26, 0x5e, 0x59, 0x3c, 0x48, 0x06, 0xbc, 0x20, + 0x66, 0x89, 0x39, 0x64, 0xd6, 0x5a, 0x7a, 0x05, 0x10, 0x89, 0x44, 0x4a, + 0x73, 0x98, 0x3e, 0x9f, 0xb0, 0xc3, 0x3c, 0xea, 0x77, 0x95, 0xc6, 0xc5, + 0x5b, 0x08, 0x07, 0x2b, 0xaa, 0x63, 0x25, 0x4c, 0xf6, 0xa7, 0x08, 0xf9, + 0x42, 0x4c, 0xc7, 0xa9, 0xe9, 0x58, 0x0a, 0x9e, 0x4a, 0x0e, 0xf6, 0x2b, + 0xf5, 0x35, 0x20, 0x55, 0x65, 0x46, 0xda, 0x32, 0xdc, 0xb5, 0x29, 0x4a, + 0x79, 0x2a, 0x1e, 0x20, 0xa3, 0x3f, 0xfb, 0x5c, 0xf7, 0xce, 0x5f, 0x3b, + 0x96, 0xb9, 0x16, 0xf4, 0x6f, 0xe9, 0x5b, 0x63, 0x86, 0x85, 0xbe, 0x7f, + 0xe8, 0x3b, 0x30, 0xdb, 0xc0, 0xd4, 0xeb, 0xf8, 0xcd, 0x40, 0x4e, 0x72, + 0x1f, 0x37, 0x74, 0xb7, 0x28, 0x93, 0xe2, 0x0d, 0xdf, 0x5b, 0x9f, 0xa0, + 0x1b, 0x82, 0x13, 0x2d, 0x52, 0x3b, 0xdd, 0x17, 0x32, 0x93, 0x36, 0x82, + 0x5f, 0x68, 0x3c, 0x1d, 0xf3, 0x54, 0xcd, 0x2e, 0x24, 0x5f, 0xcb, 0x73, + 0x5e, 0xf1, 0x31, 0xf7, 0xb5, 0x3d, 0x6c, 0x43, 0x65, 0x2a, 0x8d, 0xf9, + 0x05, 0xb2, 0xa4, 0x67, 0x46, 0x50, 0x65, 0x8a, 0xb0, 0xcc, 0xbf, 0xea, + 0xa5, 0x46, 0xfd, 0x39, 0xb7, 0x75, 0xa8, 0x8f, 0xd3, 0x91, 0x5a, 0x79, + 0x98, 0x2b, 0x7b, 0xa3, 0x97, 0x49, 0xa1, 0x08, 0xb4, 0x62, 0x97, 0x58, + 0x13, 0x9b, 0xef, 0x5e, 0x7e, 0xfd, 0x23, 0xf7, 0x6f, 0xf2, 0xfc, 0x79, + 0x9f, 0x5a, 0x56, 0x33, 0x0d, 0x73, 0x67, 0x9a, 0x9b, 0xed, 0xc0, 0x30, + 0xe2, 0xa3, 0x5e, 0x12, 0x91, 0x3f, 0x68, 0x95, 0xbf, 0x77, 0xfd, 0xd4, + 0x4d, 0x8b, 0xd5, 0xf6, 0xb1, 0x4c, 0x95, 0xb7, 0x50, 0xba, 0xb5, 0xf1, + 0x06, 0x33, 0xd2, 0x9b, 0x32, 0x8b, 0xb9, 0x34, 0x4b, 0xe3, 0x4c, 0x91, + 0xdc, 0x27, 0xd7, 0xa9, 0x61, 0xe2, 0xfb, 0x41, 0xf7, 0xf6, 0xb9, 0x67, + 0x3d, 0x38, 0x5a, 0xc7, 0xf5, 0x62, 0xae, 0x9b, 0x86, 0x65, 0x29, 0xa8, + 0x90, 0x03, 0x3a, 0x27, 0x48, 0xe2, 0x63, 0x0c, 0xaf, 0xa8, 0x26, 0xfd, + 0x8f, 0xee, 0xb7, 0x22, 0xa9, 0x97, 0x6d, 0x8b, 0xe7, 0x56, 0x56, 0xec, + 0x50, 0x9d, 0x18, 0x20, 0x59, 0xc8, 0x4c, 0x9d, 0xe8, 0xfd, 0x86, 0x6e, + 0xb9, 0xfd, 0xa6, 0x95, 0x30, 0x02, 0xa9, 0x4b, 0xb0, 0x83, 0x51, 0x8f, + 0x6d, 0x00, 0x75, 0xd1, 0x37, 0x85, 0x47, 0xec, 0x75, 0xb3, 0xab, 0xb3, + 0xf4, 0xd3, 0x62, 0x2d, 0x95, 0x0f, 0xe6, 0xd6, 0xbb, 0x49, 0xc2, 0x08, + 0x77, 0x4b, 0x91, 0x18, 0xc2, 0xb3, 0x90, 0x99, 0x90, 0x81, 0x2b, 0xc9, + 0xba, 0x79, 0xe3, 0xca, 0x1b, 0x71, 0x5a, 0x6d, 0xbc, 0xd9, 0x98, 0x92, + 0xba, 0x7b, 0xe5, 0xeb, 0x9b, 0x29, 0xde, 0x6e, 0x85, 0x20, 0x10, 0x82, + 0xb0, 0x0a, 0x73, 0x3a, 0xd1, 0xf6, 0x58, 0x5a, 0xd7, 0xc6, 0xb6, 0x29, + 0x42, 0xca, 0x32, 0x3b, 0x04, 0xa2, 0xd4, 0x09, 0x93, 0xf6, 0xb9, 0x2a, + 0x12, 0xfb, 0x52, 0x22, 0xfc, 0xbe, 0x66, 0xb3, 0x71, 0xd1, 0xdc, 0xe6, + 0xf5, 0xd4, 0x09, 0xea, 0xd5, 0x57, 0x35, 0x1d, 0x00, 0x09, 0x44, 0xcc, + 0x94, 0x65, 0x4a, 0x52, 0xee, 0x44, 0xb5, 0x26, 0xe3, 0x8c, 0xef, 0x61, + 0x65, 0x73, 0x37, 0xed, 0x4b, 0x8c, 0xa4, 0x08, 0x32, 0x87, 0x21, 0xd1, + 0x26, 0xad, 0xbf, 0xb4, 0xf6, 0x4e, 0x57, 0x4e, 0x53, 0xa2, 0xed, 0x3c, + 0xdd, 0xda, 0x70, 0x93, 0xd3, 0x12, 0x9d, 0x69, 0x85, 0x02, 0x06, 0x3c, + 0x27, 0x27, 0x0b, 0xc9, 0x21, 0xe0, 0x7f, 0xf6, 0xb1, 0x38, 0xe9, 0xbd, + 0x22, 0x14, 0xd8, 0x83, 0x79, 0x36, 0x90, 0x08, 0x76, 0x50, 0xb0, 0xab, + 0xc6, 0xd6, 0x75, 0xe5, 0x32, 0x3f, 0xcf, 0xc7, 0x05, 0x7e, 0x98, 0x9b, + 0xe4, 0x1b, 0xda, 0x72, 0x06, 0xc2, 0x45, 0x5e, 0x9b, 0xf6, 0x6d, 0xcb, + 0xe7, 0x82, 0x8c, 0xc7, 0xff, 0x56, 0xdc, 0xb2, 0x2f, 0xee, 0x6d, 0xe0, + 0xd3, 0x5d, 0x87, 0xcc, 0x8a, 0xbc, 0xe3, 0xb5, 0xa3, 0xe9, 0xb2, 0x89, + 0x82, 0x60, 0xb7, 0x73, 0x74, 0xb0, 0xf0, 0x3b, 0x28, 0x20, 0xb0, 0x1e, + 0xe3, 0x3f, 0x8b, 0x7f, 0xf7, 0xf6, 0x43, 0x4d, 0x33, 0xb2, 0x02, 0x27, + 0x4d, 0x8d, 0x80, 0xfc, 0xd1, 0xe0, 0x24, 0xe7, 0x82, 0xdf, 0xe9, 0x1c, + 0x62, 0x34, 0xd2, 0x9b, 0xd1, 0x9a, 0x5f, 0x61, 0x6a, 0xd4, 0xd9, 0x8f, + 0x5c, 0x8e, 0xa3, 0x19, 0x6b, 0xd2, 0xda, 0x16, 0x54, 0xc4, 0xf8, 0xb1, + 0x95, 0x48, 0x3e, 0x26, 0x5c, 0x27, 0x1c, 0xf2, 0xd2, 0x0d, 0x36, 0x3f, + 0x69, 0x9e, 0x6d, 0x81, 0x86, 0x1f, 0x50, 0xcd, 0xa9, 0x76, 0x08, 0xe1, + 0xd3, 0xb0, 0xda, 0xfb, 0xd8, 0x5d, 0x93, 0xb1, 0x8e, 0x6d, 0x14, 0xed, + 0xdf, 0xf7, 0x57, 0xff, 0xff, 0x8c, 0x4d, 0x15, 0x36, 0x21, 0x87, 0x64, + 0xb0, 0x67, 0xe5, 0x89, 0x90, 0x9a, 0x26, 0x86, 0xa5, 0x2c, 0x20, 0xc3, + 0xcd, 0x4b, 0x7c, 0x6c, 0xc0, 0xfa, 0x40, 0xca, 0x08, 0x65, 0xa3, 0x40, + 0x31, 0x9a, 0x59, 0xfb, 0x46, 0xd7, 0xe7, 0xda, 0xa1, 0x46, 0x9b, 0x3c, + 0x05, 0x40, 0x11, 0x5e, 0x7e, 0xd5, 0x8e, 0x58, 0xaf, 0x43, 0x0c, 0x86, + 0x5f, 0x88, 0x37, 0x81, 0x4e, 0x7c, 0xea, 0xdf, 0x32, 0xde, 0x9d, 0x7f, + 0x43, 0x1c, 0x15, 0x96, 0x10, 0xe4, 0xe8, 0x50, 0xab, 0x6f, 0x37, 0x6a, + 0xf7, 0x6c, 0x68, 0x21, 0xda, 0x19, 0x5d, 0x2d, 0xc7, 0x9d, 0xcc, 0x88, + 0x18, 0x8c, 0xe3, 0x00, 0x68, 0x05, 0x1c, 0xa2, 0x6a, 0xc3, 0xaf, 0xbd, + 0xd1, 0xb3, 0xc5, 0xba, 0xa5, 0xb7, 0xc6, 0x91, 0xf3, 0x4f, 0x1c, 0xba, + 0x10, 0x23, 0x21, 0x2a, 0x4e, 0xd8, 0xf9, 0x72, 0xf1, 0x3a, 0x7b, 0xab, + 0x9c, 0x2d, 0xec, 0x6f, 0x2b, 0x15, 0xcb, 0x38, 0xa6, 0x60, 0x83, 0x5a, + 0x08, 0x9d, 0xed, 0x67, 0xb5, 0x27, 0x2b, 0xb9, 0x0b, 0xa0, 0x8f, 0xf6, + 0xfd, 0x68, 0x27, 0xe6, 0xbb, 0x6b, 0x53, 0x86, 0x30, 0x14, 0x1b, 0x89, + 0x51, 0x39, 0x5b, 0x38, 0x60, 0xce, 0x8d, 0x65, 0xc7, 0x81, 0xbd, 0x5e, + 0xd1, 0x08, 0xdd, 0x65, 0x15, 0x1d, 0xff, 0xfa, 0x86, 0x2d, 0x9c, 0x1d, + 0xf3, 0x01, 0xc3, 0xc3, 0x38, 0x6a, 0x9a, 0x65, 0x38, 0xc2, 0x82, 0x38, + 0xef, 0xe3, 0x70, 0xc2, 0xc9, 0xf3, 0xc3, 0x99, 0x75, 0x14, 0xa9, 0x85, + 0x21, 0x5a, 0xd2, 0xd0, 0xd0, 0x4a, 0x26, 0x31, 0xc7, 0x90, 0xee, 0x41, + 0x9a, 0x8f, 0xbf, 0x9d, 0xaf, 0x4b, 0x7b, 0x56, 0x23, 0x6e, 0xbf, 0x6b, + 0x87, 0x1a, 0x56, 0x91, 0xe5, 0xec, 0xf9, 0xbe, 0xe1, 0x51, 0xaf, 0x50, + 0xcb, 0xee, 0x4e, 0x33, 0xdf, 0xb3, 0xbe, 0x8e, 0xed, 0x7a, 0x47, 0x12, + 0x0e, 0x28, 0xa8, 0xe3, 0x41, 0xb0, 0xdb, 0x12, 0xaf, 0x10, 0x0e, 0x32, + 0x13, 0x99, 0xf9, 0xf0, 0xf5, 0x48, 0x61, 0xa2, 0xec, 0x3a, 0x8c, 0x5c, + 0xa8, 0xab, 0xef, 0x77, 0xea, 0xe2, 0x8a, 0xc8, 0xb3, 0x8d, 0xcf, 0x70, + 0xf0, 0x4d, 0x7e, 0x1c, 0xa2, 0x40, 0x6a, 0x28, 0x50, 0x3e, 0x29, 0x5f, + 0x76, 0x05, 0x99, 0x90, 0x18, 0xf8, 0x48, 0xa8, 0xb5, 0x77, 0xd9, 0xb8, + 0xd5, 0xba, 0x6a, 0x58, 0xdb, 0x83, 0x72, 0x62, 0xee, 0xfa, 0x70, 0x4b, + 0x97, 0x4b, 0x45, 0x00, 0x68, 0xc1, 0x23, 0xdc, 0x09, 0xd8, 0x3c, 0xca, + 0xb8, 0x73, 0xab, 0x6d, 0x6e, 0x27, 0x95, 0xcd, 0x42, 0x2f, 0x51, 0x2e, + 0x70, 0x65, 0x1a, 0x06, 0x67, 0x1b, 0x09, 0xf6, 0xf0, 0x02, 0x40, 0x59, + 0x3a, 0x77, 0x1b, 0x9d, 0x52, 0x3e, 0x46, 0xc7, 0x5a, 0x4e, 0xdc, 0xa6, + 0x6e, 0x3f, 0x6c, 0xdc, 0x82, 0x1b, 0x16, 0x66, 0x43, 0x23, 0x32, 0xab, + 0x27, 0x78, 0xb1, 0x5d, 0xad, 0x54, 0x48, 0x9a, 0x3e, 0x7b, 0x49, 0x60, + 0x6d, 0x2d, 0xd9, 0xbf, 0x29, 0xa1, 0xa7, 0xb7, 0x34, 0x09, 0x94, 0xa0, + 0x64, 0xbf, 0x04, 0xf7, 0x8f, 0x5b, 0x71, 0xfa, 0xa5, 0x9c, 0xdb, 0x43, + 0x1c, 0x0c, 0x66, 0x7b, 0x21, 0xd3, 0xe3, 0x69, 0x6e, 0xf8, 0x67, 0x04, + 0x3c, 0xb1, 0xa6, 0x7c, 0x57, 0xea, 0x83, 0x08, 0x45, 0x2e, 0x5d, 0x1a, + 0x8d, 0x02, 0xe4, 0xe5, 0xfc, 0x61, 0x50, 0x61, 0x13, 0x9b, 0x6e, 0x54, + 0x28, 0x0a, 0x09, 0xd7, 0x97, 0x2c, 0x72, 0x27, 0xb6, 0xa8, 0xe5, 0x43, + 0x27, 0x29, 0xcf, 0xc4, 0x05, 0x2b, 0x78, 0xed, 0x69, 0xe0, 0x20, 0x48, + 0x8c, 0x02, 0x5f, 0x40, 0x71, 0xfd, 0x39, 0xbe, 0x2f, 0xbb, 0xeb, 0xde, + 0xbd, 0xb4, 0x2f, 0x97, 0xa0, 0xcc, 0xdb, 0xed, 0x1c, 0x73, 0x5e, 0x70, + 0x32, 0xdf, 0x45, 0xcc, 0xf2, 0xbe, 0x80, 0xed, 0xf6, 0xce, 0x60, 0xeb, + 0x66, 0x4a, 0x4b, 0x17, 0x87, 0xf1, 0x8c, 0x46, 0x0b, 0x5a, 0x74, 0x13, + 0xcf, 0x51, 0x4c, 0xfa, 0x37, 0xb8, 0xe7, 0xf7, 0xf8, 0xbf, 0xb7, 0x0e, + 0xee, 0x74, 0xff, 0x3e, 0x35, 0x0c, 0x3e, 0x5b, 0x64, 0x82, 0x27, 0x63, + 0x27, 0x24, 0xa1, 0xf6, 0x0d, 0x99, 0xae, 0x3a, 0xe7, 0xe2, 0xf7, 0xdc, + 0x47, 0x45, 0x00, 0x93, 0x0d, 0x9b, 0x37, 0xba, 0xce, 0x1c, 0x80, 0x44, + 0x81, 0x4a, 0x28, 0x9a, 0xc1, 0xce, 0x2d, 0x49, 0xea, 0xe2, 0x73, 0xe7, + 0xb0, 0x4c, 0xe3, 0x0d, 0x4e, 0xf7, 0x9a, 0x5c, 0x1d, 0xa0, 0xa2, 0xf4, + 0x06, 0x12, 0x0f, 0x3d, 0x2d, 0x3f, 0xb7, 0xe5, 0xbf, 0xff, 0x60, 0x84, + 0x94, 0x7a, 0xef, 0xce, 0xd2, 0x15, 0x1a, 0x80, 0x75, 0x18, 0x28, 0xb0, + 0x9a, 0x08, 0x48, 0x43, 0x84, 0x6f, 0x83, 0xdb, 0xb0, 0xd0, 0x51, 0xf5, + 0x15, 0x19, 0xc2, 0xc2, 0x53, 0xf9, 0xbf, 0x93, 0x37, 0xfc, 0xcb, 0x3a, + 0x2f, 0x16, 0x6a, 0x54, 0x67, 0xa7, 0xa6, 0xe4, 0xd1, 0x25, 0xe0, 0x30, + 0x06, 0x13, 0x00, 0x0a, 0x2e, 0x11, 0xf1, 0x33, 0x9e, 0xb4, 0xe7, 0x1c, + 0xe3, 0x0c, 0x91, 0xfb, 0x52, 0x62, 0x46, 0xcd, 0xed, 0x77, 0x12, 0xff, + 0x15, 0x7b, 0xd7, 0x3b, 0x22, 0xcd, 0xd7, 0xf4, 0x0c, 0xe1, 0x85, 0x68, + 0x0a, 0x24, 0xd0, 0x07, 0x0e, 0xf5, 0x68, 0x5d, 0x55, 0xb5, 0xe3, 0x28, + 0x68, 0x23, 0x40, 0xec, 0x0d, 0x94, 0x8c, 0xa8, 0x09, 0x77, 0x16, 0xe5, + 0xab, 0xc5, 0xe8, 0x53, 0xe2, 0xc1, 0xce, 0x5c, 0xa9, 0x55, 0x10, 0xea, + 0x9b, 0x3e, 0x8a, 0x1d, 0xae, 0x60, 0x1d, 0x09, 0xc7, 0xf7, 0xf5, 0xca, + 0x92, 0x02, 0x5f, 0x35, 0x96, 0x74, 0x72, 0x85, 0x29, 0xf8, 0x04, 0x20, + 0x70, 0xf7, 0xb9, 0x34, 0x46, 0x3a, 0xb2, 0x92, 0x05, 0x1f, 0xa3, 0x05, + 0x5d, 0xb0, 0x10, 0x15, 0xbe, 0x01, 0x21, 0x03, 0x57, 0x46, 0xef, 0x43, + 0x80, 0x10, 0xc9, 0x78, 0xf2, 0x33, 0x39, 0xd3, 0xc0, 0x6a, 0x92, 0xd9, + 0x69, 0x22, 0xbf, 0xd9, 0xd1, 0xf4, 0xda, 0xb5, 0xe9, 0xe8, 0x65, 0x1a, + 0x60, 0x3b, 0x19, 0xbd, 0x44, 0xe8, 0x89, 0x77, 0x28, 0xb9, 0xbb, 0xcd, + 0x2d, 0xfb, 0x7b, 0xf0, 0x74, 0x32, 0xbf, 0x6f, 0x4c, 0x74, 0xf8, 0x0a, + 0x0f, 0x31, 0x24, 0x51, 0xfa, 0x01, 0x51, 0xe3, 0x8d, 0x4f, 0xfe, 0x08, + 0x8d, 0x02, 0xd8, 0x71, 0xa3, 0xfd, 0xc8, 0x19, 0x7b, 0xd1, 0x87, 0x6c, + 0x72, 0x73, 0x7f, 0x9e, 0x31, 0xb7, 0xbf, 0xc3, 0x6f, 0xcf, 0xd3, 0xd9, + 0x7a, 0x3a, 0x76, 0xc5, 0xe5, 0xb9, 0x7b, 0x20, 0x13, 0xa3, 0x2d, 0xa1, + 0x7a, 0xa2, 0x60, 0x49, 0xfd, 0xba, 0x2f, 0x2c, 0xb9, 0x48, 0x49, 0xfe, + 0x80, 0x8e, 0xc4, 0xd0, 0x96, 0x92, 0xf7, 0x0e, 0x4e, 0x6d, 0x8c, 0x32, + 0x1a, 0x3f, 0x14, 0xf8, 0x2d, 0x63, 0x44, 0x1d, 0x1d, 0xba, 0xc2, 0xcc, + 0xa6, 0x36, 0x8b, 0x48, 0xd5, 0xea, 0x8e, 0x87, 0xce, 0x0c, 0xfb, 0x46, + 0x0e, 0xb9, 0xa4, 0x68, 0x0c, 0x9f, 0xa6, 0xb3, 0xfd, 0x39, 0xad, 0x69, + 0x2e, 0x53, 0x48, 0x9c, 0x02, 0xac, 0x51, 0xd8, 0x19, 0x24, 0x82, 0x1e, + 0x24, 0x91, 0x52, 0x0f, 0xba, 0x53, 0x25, 0x07, 0x0e, 0x83, 0xe0, 0x09, + 0x72, 0xa2, 0x32, 0x2c, 0xee, 0x0e, 0x88, 0x5b, 0x42, 0x25, 0x3c, 0x69, + 0xb7, 0xc5, 0x9a, 0x07, 0xc0, 0x6b, 0x94, 0x28, 0x01, 0x39, 0x34, 0xd1, + 0xab, 0xf4, 0x32, 0x55, 0x82, 0x3c, 0x07, 0x2a, 0x11, 0x7a, 0x10, 0xc9, + 0x55, 0xaa, 0x84, 0x39, 0xd8, 0x3c, 0x4e, 0x09, 0x65, 0xe9, 0x03, 0x39, + 0xd0, 0xf1, 0x79, 0x70, 0x83, 0x07, 0x68, 0x72, 0x4f, 0x3f, 0x8e, 0x05, + 0xe1, 0x41, 0xe4, 0xf8, 0x1b, 0xc6, 0x13, 0xd4, 0x95, 0xed, 0xe5, 0x2f, + 0xab, 0x97, 0xaf, 0xa9, 0x6b, 0x59, 0x3c, 0x09, 0xe3, 0x3d, 0x26, 0xdb, + 0x04, 0x72, 0x19, 0x05, 0x28, 0x1f, 0x00, 0x67, 0x29, 0x2a, 0xe1, 0x7b, + 0xdb, 0x8b, 0xfb, 0x71, 0xde, 0x13, 0x5f, 0xe1, 0xb6, 0x91, 0x99, 0x90, + 0x99, 0x4a, 0xf8, 0xf0, 0x79, 0xe2, 0x2d, 0x76, 0x9b, 0x1e, 0x29, 0xed, + 0xf7, 0x8b, 0xa2, 0x1c, 0xf9, 0xec, 0xde, 0xf4, 0x35, 0x40, 0xca, 0x4c, + 0xf0, 0x30, 0x4a, 0xcb, 0x9f, 0x72, 0x0f, 0xfe, 0x06, 0xcd, 0x54, 0xb0, + 0x5d, 0x30, 0x59, 0xd6, 0x0d, 0x7e, 0x7e, 0x71, 0x45, 0xb6, 0xc3, 0xac, + 0x5b, 0x76, 0xa7, 0xc6, 0x67, 0x08, 0x2d, 0xd1, 0xa7, 0x32, 0x1a, 0x90, + 0x83, 0xc1, 0x55, 0x6a, 0xca, 0x9c, 0x8e, 0xb3, 0x7b, 0x8f, 0xc5, 0x05, + 0x4f, 0x91, 0xef, 0xee, 0xa5, 0x7d, 0xcd, 0xd6, 0xb0, 0xad, 0xc1, 0x94, + 0x98, 0x20, 0x04, 0x26, 0x54, 0xd6, 0x72, 0xb4, 0x28, 0xe4, 0xe4, 0xdf, + 0x43, 0x7e, 0xfd, 0x15, 0x17, 0x8d, 0xd9, 0xd4, 0x62, 0xa9, 0x62, 0x47, + 0x6d, 0x32, 0x26, 0x11, 0x41, 0x04, 0x6f, 0x50, 0x3c, 0xd2, 0x9a, 0xeb, + 0x76, 0x2e, 0x7e, 0xcf, 0xfe, 0xbc, 0xbd, 0xae, 0x5f, 0x23, 0x77, 0x86, + 0x9c, 0xf1, 0x99, 0xa7, 0x8c, 0xd9, 0x21, 0x58, 0x07, 0x9b, 0x3b, 0xfa, + 0xe4, 0xc1, 0x72, 0xd9, 0x01, 0xc5, 0xe5, 0xb8, 0xc0, 0xe8, 0xb9, 0x11, + 0x96, 0xcf, 0x39, 0x8c, 0x8a, 0x77, 0x3e, 0xd7, 0x8d, 0x27, 0xf1, 0x0b, + 0xfc, 0xa0, 0xa7, 0x7a, 0x61, 0x44, 0xcc, 0xfc, 0x15, 0xea, 0x0b, 0xf7, + 0x74, 0x9b, 0xa7, 0xda, 0x73, 0x9b, 0xec, 0x62, 0x43, 0x19, 0xbb, 0x16, + 0xba, 0x0d, 0x1e, 0xd6, 0xa1, 0x4c, 0xbd, 0x58, 0xac, 0xcf, 0x79, 0x9d, + 0xf2, 0xbd, 0xfa, 0x9c, 0xfd, 0x79, 0x81, 0x0c, 0x7d, 0xb8, 0xe9, 0xf9, + 0x99, 0x64, 0xee, 0xa9, 0xa4, 0xe9, 0xcc, 0x94, 0x09, 0x6c, 0x3d, 0x7e, + 0x59, 0x55, 0x80, 0x5e, 0xf1, 0xf5, 0xff, 0x5d, 0x74, 0xf2, 0xea, 0xe6, + 0xfa, 0xb1, 0x7a, 0x48, 0xeb, 0x72, 0x53, 0x18, 0x60, 0x14, 0xfb, 0x54, + 0x72, 0xab, 0x04, 0x13, 0xa7, 0x47, 0xfb, 0xbb, 0x21, 0x14, 0x3d, 0xd3, + 0x56, 0x53, 0x89, 0xa4, 0x6b, 0x02, 0x79, 0x83, 0x74, 0x85, 0x2e, 0x9c, + 0xbe, 0x03, 0xf4, 0x0b, 0xa2, 0xdc, 0xf2, 0xdb, 0x57, 0x2a, 0x25, 0x5b, + 0x63, 0x01, 0x67, 0x18, 0xc4, 0x1c, 0xa7, 0xfa, 0x99, 0xc2, 0x3d, 0x26, + 0xaf, 0x9b, 0x9f, 0x9f, 0x4c, 0x03, 0x73, 0xb9, 0xd7, 0x98, 0x22, 0x67, + 0x0e, 0x5c, 0x60, 0xc8, 0xf8, 0xc0, 0x54, 0x9b, 0xfb, 0x4c, 0xd9, 0x38, + 0xf8, 0xfc, 0x90, 0x78, 0x5b, 0xeb, 0xf0, 0xe9, 0x3f, 0xa5, 0x32, 0xc8, + 0x28, 0xc3, 0xf8, 0x6f, 0x63, 0x62, 0x59, 0x54, 0xf1, 0x81, 0xc9, 0xa1, + 0xf3, 0x97, 0xdf, 0x1f, 0xff, 0xfb, 0x75, 0xe3, 0xf2, 0xc3, 0x2d, 0x7c, + 0x6f, 0x41, 0xa1, 0xa0, 0x1d, 0xc8, 0x34, 0x44, 0xca, 0x15, 0x93, 0xde, + 0xda, 0xb9, 0x17, 0x93, 0x7f, 0x17, 0x5a, 0xfe, 0xe1, 0x3b, 0x94, 0x4c, + 0xd9, 0x54, 0x27, 0x08, 0x13, 0x9c, 0x04, 0x89, 0x65, 0x51, 0xee, 0x41, + 0xd7, 0x93, 0x1b, 0xef, 0x40, 0x6f, 0xac, 0xc5, 0x55, 0xe5, 0xad, 0x42, + 0xa2, 0x65, 0xf7, 0x7a, 0xc3, 0xae, 0x99, 0xc8, 0xd3, 0x44, 0x7d, 0x36, + 0x47, 0xaa, 0xe2, 0xd9, 0xe2, 0xa0, 0xcf, 0x34, 0xb7, 0xca, 0x0f, 0x2e, + 0x9f, 0xa5, 0x21, 0x07, 0xf6, 0x70, 0x32, 0x34, 0xf2, 0xcf, 0x19, 0x19, + 0xa2, 0x28, 0x4b, 0xea, 0x0f, 0x34, 0xbb, 0x4a, 0x27, 0x17, 0x35, 0xc7, + 0x27, 0x12, 0xda, 0xd7, 0x9d, 0xde, 0x30, 0x71, 0xda, 0x0c, 0x6a, 0xbe, + 0x72, 0x0c, 0x6b, 0x00, 0xa6, 0xb7, 0xc5, 0x3a, 0x43, 0xfb, 0x3b, 0xe4, + 0x20, 0x5a, 0x79, 0x10, 0xa9, 0x9e, 0xfc, 0x84, 0x48, 0xc6, 0x2b, 0xa0, + 0xa4, 0x5a, 0x90, 0x13, 0x9e, 0xf1, 0x5f, 0x0f, 0x97, 0x0e, 0x5e, 0x10, + 0xe2, 0x42, 0x1f, 0x22, 0x73, 0xe4, 0xe0, 0xa5, 0x2a, 0x0c, 0x7c, 0xae, + 0x95, 0x57, 0x95, 0xb1, 0x40, 0x76, 0xc7, 0x0d, 0xa2, 0xe0, 0x30, 0x62, + 0x77, 0x07, 0x07, 0x65, 0xd6, 0xef, 0x23, 0x8d, 0xac, 0x3c, 0xc9, 0x45, + 0xe5, 0x21, 0xe2, 0x1f, 0xee, 0x96, 0x60, 0xae, 0x6f, 0x51, 0x3f, 0x11, + 0x0c, 0xcd, 0x1a, 0x7b, 0x32, 0xa1, 0xda, 0xe3, 0x90, 0x05, 0x0a, 0xa9, + 0x27, 0xaf, 0xc8, 0x39, 0xbe, 0xe1, 0x7a, 0xf7, 0x94, 0x22, 0x1a, 0xd2, + 0xad, 0xc6, 0xa7, 0xb8, 0x77, 0x5b, 0x93, 0xe5, 0x4e, 0x50, 0x30, 0x8c, + 0x0e, 0x12, 0x0f, 0x34, 0xb6, 0x7b, 0xe0, 0xef, 0x3b, 0xbb, 0xb6, 0x92, + 0xe8, 0xfc, 0xd4, 0x1d, 0x67, 0x18, 0x8a, 0x50, 0x9a, 0x48, 0x81, 0x4f, + 0x2f, 0x54, 0x12, 0xbe, 0xdb, 0xd2, 0x67, 0xae, 0x1d, 0x2a, 0x5f, 0x8d, + 0x0f, 0x55, 0xbf, 0x40, 0x00, 0x00, 0x01, 0x0a +}; + +void +vc1_get_video_info (VideoDecodeInfo * info) +{ + info->profile = GST_VAAPI_PROFILE_VC1_ADVANCED; + info->width = VC1_CLIP_WIDTH; + info->height = VC1_CLIP_HEIGHT; + info->data = vc1_clip; + info->data_size = VC1_CLIP_DATA_SIZE; +} diff --git a/tests/internal/test-vc1.h b/tests/internal/test-vc1.h new file mode 100644 index 0000000000..3b948640db --- /dev/null +++ b/tests/internal/test-vc1.h @@ -0,0 +1,31 @@ +/* + * test-vc1.h - VC-1 test data + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * + * 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 TEST_VC1_H +#define TEST_VC1_H + +#include +#include "test-decode.h" + +void vc1_get_video_info(VideoDecodeInfo *info); + +#endif /* TEST_VC1_H */ diff --git a/tests/internal/test-windows.c b/tests/internal/test-windows.c new file mode 100644 index 0000000000..b9c9ad1701 --- /dev/null +++ b/tests/internal/test-windows.c @@ -0,0 +1,238 @@ +/* + * test-windows.c - Test GstVaapiWindow + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2012-2013 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gst/vaapi/sysdeps.h" +#include +#include +#if USE_DRM +# include +# include +#endif +#if USE_X11 +# include +# include +#endif +#if USE_WAYLAND +# include +# include +#endif +#if USE_EGL +# include +# include +#endif +#include "image.h" + +static inline void +pause (void) +{ + g_print ("Press any key to continue...\n"); + getchar (); +} + +static GstVaapiSurface * +create_test_surface (GstVaapiDisplay * display, guint width, guint height) +{ + GstVaapiImage *image = NULL; + GstVaapiSurface *surface; + guint i; + + static const GstVaapiChromaType chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420; + static const GstVideoFormat image_formats[] = { + GST_VIDEO_FORMAT_NV12, + GST_VIDEO_FORMAT_YV12, + GST_VIDEO_FORMAT_I420, + GST_VIDEO_FORMAT_VUYA, + GST_VIDEO_FORMAT_ARGB, + GST_VIDEO_FORMAT_BGRA, + GST_VIDEO_FORMAT_RGBA, + GST_VIDEO_FORMAT_ABGR, + GST_VIDEO_FORMAT_UNKNOWN + }; + + surface = gst_vaapi_surface_new (display, chroma_type, width, height); + if (!surface) + g_error ("could not create Gst/VA surface"); + + for (i = 0; image_formats[i] != GST_VIDEO_FORMAT_UNKNOWN; i++) { + const GstVideoFormat format = image_formats[i]; + + image = image_generate (display, format, width, height); + if (!image) + break; + if (image_upload (image, surface)) + break; + } + if (!image) + g_error ("could not create Gst/VA image"); + + if (!gst_vaapi_surface_sync (surface)) + g_error ("could not complete image upload"); + + gst_vaapi_image_unref (image); + return surface; +} + +int +main (int argc, char *argv[]) +{ + GstVaapiDisplay *display; + GstVaapiWindow *window; + GstVaapiSurface *surface; + guint flags = GST_VAAPI_PICTURE_STRUCTURE_FRAME; + + static const guint width = 320; + static const guint height = 240; + static const guint win_width = 640; + static const guint win_height = 480; + + gst_init (&argc, &argv); + +#if USE_DRM + display = gst_vaapi_display_drm_new (NULL); + if (!display) + g_error ("could not create Gst/VA (DRM) display"); + + surface = create_test_surface (display, width, height); + if (!surface) + g_error ("could not create Gst/VA surface"); + + g_print ("#\n"); + g_print ("# Create window with gst_vaapi_window_drm_new()\n"); + g_print ("#\n"); + { + window = gst_vaapi_window_drm_new (display, win_width, win_height); + if (!window) + g_error ("could not create dummy window"); + + gst_vaapi_window_show (window); + + if (!gst_vaapi_window_put_surface (window, surface, NULL, NULL, flags)) + g_error ("could not render surface"); + + pause (); + gst_object_unref (window); + } + + gst_vaapi_surface_unref (surface); + gst_object_unref (display); +#endif + +#if USE_X11 + display = gst_vaapi_display_x11_new (NULL); + if (!display) + g_error ("could not create Gst/VA display"); + + surface = create_test_surface (display, width, height); + if (!surface) + g_error ("could not create Gst/VA surface"); + + g_print ("#\n"); + g_print ("# Create window with gst_vaapi_window_x11_new()\n"); + g_print ("#\n"); + { + window = gst_vaapi_window_x11_new (display, win_width, win_height); + if (!window) + g_error ("could not create window"); + + gst_vaapi_window_show (window); + + if (!gst_vaapi_window_put_surface (window, surface, NULL, NULL, flags)) + g_error ("could not render surface"); + + pause (); + gst_object_unref (window); + } + + g_print ("#\n"); + g_print ("# Create window with gst_vaapi_window_x11_new_with_xid()\n"); + g_print ("#\n"); + { + Display *const dpy = + gst_vaapi_display_x11_get_display (GST_VAAPI_DISPLAY_X11 (display)); + Window rootwin, win; + int screen; + unsigned long white_pixel, black_pixel; + + screen = DefaultScreen (dpy); + rootwin = RootWindow (dpy, screen); + white_pixel = WhitePixel (dpy, screen); + black_pixel = BlackPixel (dpy, screen); + + win = XCreateSimpleWindow (dpy, + rootwin, 0, 0, win_width, win_height, 0, black_pixel, white_pixel); + if (!win) + g_error ("could not create X window"); + + window = gst_vaapi_window_x11_new_with_xid (display, win); + if (!window) + g_error ("could not create window"); + + gst_vaapi_window_show (window); + + if (!gst_vaapi_window_put_surface (window, surface, NULL, NULL, flags)) + g_error ("could not render surface"); + + pause (); + gst_object_unref (window); + XUnmapWindow (dpy, win); + XDestroyWindow (dpy, win); + } + + gst_vaapi_surface_unref (surface); + gst_object_unref (display); +#endif + +#if USE_WAYLAND + display = gst_vaapi_display_wayland_new (NULL); + if (!display) + g_error ("could not create Gst/VA (Wayland) display"); + + surface = create_test_surface (display, width, height); + if (!surface) + g_error ("could not create Gst/VA surface"); + + g_print ("#\n"); + g_print ("# Create window with gst_vaapi_window_wayland_new()\n"); + g_print ("#\n"); + { + window = gst_vaapi_window_wayland_new (display, win_width, win_height); + if (!window) + g_error ("could not create window"); + + gst_vaapi_window_show (window); + + if (!gst_vaapi_window_put_surface (window, surface, NULL, NULL, flags)) + g_error ("could not render surface"); + + pause (); + gst_object_unref (window); + } + + gst_vaapi_surface_unref (surface); + gst_object_unref (display); +#endif + + gst_deinit (); + return 0; +} diff --git a/tests/internal/y4mreader.c b/tests/internal/y4mreader.c new file mode 100644 index 0000000000..76847bb217 --- /dev/null +++ b/tests/internal/y4mreader.c @@ -0,0 +1,261 @@ +/* + * y4mreader.c - Y4M parser + * + * Copyright (C) 2015 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gst/vaapi/sysdeps.h" +#include "y4mreader.h" + +/* format documentation: + * http://wiki.multimedia.cx/index.php?title=YUV4MPEG2 */ + +static inline gboolean +parse_int (const gchar * str, guint * out_value_ptr) +{ + gint saved_errno; + glong value; + gboolean ret; + + if (!str) + return FALSE; + str += 1; + if (*str == '\0') + return FALSE; + + saved_errno = errno; + errno = 0; + value = strtol (str, NULL, 0); + ret = (errno == 0); + errno = saved_errno; + if (value > 0 && value <= G_MAXUINT) + *out_value_ptr = value; + else + ret = FALSE; + + return ret; +} + +static gboolean +parse_header (Y4MReader * file) +{ + gint i, j, b; + guint8 header[BUFSIZ]; + size_t s; + gchar *str; + + memset (header, 0, BUFSIZ); + s = fread (header, 1, 9, file->fp); + if (s < 9) + return FALSE; + + if (memcmp (header, "YUV4MPEG2", 9) != 0) + return FALSE; + + for (i = 9; i < BUFSIZ - 1; i++) { + b = fgetc (file->fp); + if (b == EOF) + return FALSE; + if (b == 0xa) + break; + header[i] = b; + } + + if (i == BUFSIZ - 1) + return FALSE; + + j = 9; + while (j < i) { + if ((header[j] != 0x20) && (header[j - 1] == 0x20)) { + switch (header[j]) { + case 'W': + if (!parse_int ((gchar *) & header[j], &file->width)) + return FALSE; + break; + case 'H': + if (!parse_int ((gchar *) & header[j], &file->height)) + return FALSE; + break; + case 'C': + str = (char *) &header[j + 1]; + if (strncmp (str, "420", 3) != 0) { + g_warning ("Unsupported chroma subsampling."); + return FALSE; /* unsupported chroma subsampling */ + } + break; + case 'I': + str = (char *) &header[j + 1]; + if (*str != 'p' && *str != '?') { + g_warning ("Interlaced content are not supported."); + return FALSE; /* interlaced is unsupported */ + } + break; + case 'F': /* frame rate ratio */ + { + guint num, den; + + if (!parse_int ((gchar *) & header[j], &num)) + return FALSE; + while ((header[j] != ':') && (j < i)) + j++; + if (!parse_int ((gchar *) & header[j], &den)) + return FALSE; + + if (num <= 0 || den <= 0) { + file->fps_n = 30; /* default to 30 fps */ + file->fps_d = 1; + } else { + file->fps_n = num; + file->fps_d = den; + } + break; + } + case 'A': /* sample aspect ration */ + break; + case 'X': /* metadata */ + break; + default: + break; + } + } + j++; + } + + return TRUE; +} + +Y4MReader * +y4m_reader_open (const gchar * filename) +{ + Y4MReader *imagefile; + + imagefile = g_slice_new0 (Y4MReader); + + if (filename) { + imagefile->fp = fopen (filename, "r"); + if (!imagefile->fp) { + g_warning ("open file %s error", filename); + goto bail; + } + } else { + imagefile->fp = stdin; + } + + if (!parse_header (imagefile)) + goto bail; + + return imagefile; + +bail: + if (imagefile->fp && imagefile->fp != stdin) + fclose (imagefile->fp); + + g_slice_free (Y4MReader, imagefile); + return NULL; +} + +void +y4m_reader_close (Y4MReader * file) +{ + g_return_if_fail (file); + + if (file->fp && file->fp != stdin) + fclose (file->fp); + + g_slice_free (Y4MReader, file); +} + +static gboolean +skip_frame_header (Y4MReader * file) +{ + gint i, b; + guint8 header[BUFSIZ]; + size_t s; + + memset (header, 0, BUFSIZ); + s = fread (header, 1, 5, file->fp); + if (s < 5) + return FALSE; + + if (memcmp (header, "FRAME", 5) != 0) + return FALSE; + + for (i = 5; i < BUFSIZ - 1; i++) { + b = fgetc (file->fp); + if (b == EOF) + return FALSE; + if (b == 0xa) + break; + header[i] = b; + } + + return (i < BUFSIZ - 1); +} + +gboolean +y4m_reader_load_image (Y4MReader * file, GstVaapiImage * image) +{ + guint8 *plane; + size_t s; + guint frame_size, stride, i; + + g_return_val_if_fail (gst_vaapi_image_is_mapped (image), FALSE); + g_return_val_if_fail (file && file->fp, FALSE); + + /* only valid for I420 */ + frame_size = file->height * file->width * 3 / 2; + if (gst_vaapi_image_get_data_size (image) < frame_size) + return FALSE; + if (gst_vaapi_image_get_plane_count (image) != 3) + return FALSE; + + if (!skip_frame_header (file)) + return FALSE; + + /* Y plane */ + plane = gst_vaapi_image_get_plane (image, 0); + stride = gst_vaapi_image_get_pitch (image, 0); + for (i = 0; i < file->height; i++) { + s = fread (plane, 1, file->width, file->fp); + if (s != file->width) + return FALSE; + plane += stride; + } + + /* U plane */ + plane = gst_vaapi_image_get_plane (image, 1); + stride = gst_vaapi_image_get_pitch (image, 1); + for (i = 0; i < file->height / 2; i++) { + s = fread (plane, 1, file->width / 2, file->fp); + if (s != file->width / 2) + return FALSE; + plane += stride; + } + + /* V plane */ + plane = gst_vaapi_image_get_plane (image, 2); + stride = gst_vaapi_image_get_pitch (image, 2); + for (i = 0; i < file->height / 2; i++) { + s = fread (plane, 1, file->width / 2, file->fp); + if (s != file->width / 2) + return FALSE; + plane += stride; + } + + return TRUE; +} diff --git a/tests/internal/y4mreader.h b/tests/internal/y4mreader.h new file mode 100644 index 0000000000..369efb6f9b --- /dev/null +++ b/tests/internal/y4mreader.h @@ -0,0 +1,41 @@ +/* + * y4mreader.h - Y4M parser + * + * Copyright (C) 2015 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +typedef struct _Y4MReader Y4MReader; + +struct _Y4MReader +{ + FILE *fp; + guint width; + guint height; + gint fps_n; + gint fps_d; +}; + +Y4MReader *y4m_reader_open (const gchar * filename); + +void y4m_reader_close (Y4MReader * file); + +gboolean y4m_reader_load_image (Y4MReader * file, GstVaapiImage * image); diff --git a/tests/meson.build b/tests/meson.build new file mode 100644 index 0000000000..2b8b8155df --- /dev/null +++ b/tests/meson.build @@ -0,0 +1,8 @@ +if not get_option('tests').disabled() and gstcheck_dep.found() + subdir('check') +endif + +if not get_option('examples').disabled() + subdir('examples') + subdir('internal') +endif