From: johnny14 Date: Tue, 5 Sep 2017 02:23:37 +0000 (+0900) Subject: initial release X-Git-Tag: submit/tizen_4.0/20171122.022337~5 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a919dfb6cbc3b097a8ad60f20fa5ae0d2f1c1ddb;p=platform%2Fadaptation%2Fnexell%2Fgst-plugins-video-dec.git initial release this package for nexell hardware decoder Change-Id: Id68f29bf5c60f1464c136c0abb6b9693e8f5fa06 Signed-off-by: johnny Nam --- diff --git a/LICENSE.LGPLv2+ b/LICENSE.LGPLv2+ new file mode 100644 index 0000000..eb685a5 --- /dev/null +++ b/LICENSE.LGPLv2+ @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..5ff2f58 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = src + +EXTRA_DIST = autogen.sh diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..35598a4 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# you can either set the environment variables AUTOCONF, AUTOHEADER, AUTOMAKE, +# ACLOCAL, AUTOPOINT and/or LIBTOOLIZE to the right versions, or leave them +# unset and get the defaults + + +autoreconf --verbose --force --install --make || { + echo 'autogen.sh failed'; + exit 1; +} + + diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..d65969e --- /dev/null +++ b/configure.ac @@ -0,0 +1,96 @@ +dnl required version of autoconf +AC_PREREQ([2.53]) + +dnl Package Name is gstnxvideodec version 0.1.0 +AC_INIT(gstnxvideodec,[0.1.0]) + +dnl required versions of gstreamer and plugins-base +GST_REQUIRED=1.0.0 +GSTPB_REQUIRED=1.0.0 + +AC_CONFIG_SRCDIR([src]) +AC_CONFIG_HEADERS([config.h]) + +dnl required version of automake +AM_INIT_AUTOMAKE([1.10 foreign dist-bzip2]) + +dnl enable mainainer mode by default +AM_MAINTAINER_MODE([enable]) + +dnl check for tools (compiler etc.) +AC_PROG_CC + +dnl required version of libtool +LT_PREREQ([2.2.6]) +LT_INIT + +dnl give error and exit if we don't have pkgconfig +AC_CHECK_PROG(HAVE_PKGCONFIG, pkg-config, [ ], [ + AC_MSG_ERROR([You need to have pkg-config installed!]) +]) + + +dnl our libraries and install dirs use GST_API_VERSION in the filename +dnl to allow side-by-side installation of different API versions +GST_API_VERSION=1.0 +AC_SUBST(GST_API_VERSION) +AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", + [GStreamer API Version]) + +dnl Check for the required version of GStreamer core (and gst-plugins-base) +dnl This will export GST_CFLAGS and GST_LIBS variables for use in Makefile.am +dnl +dnl If you need libraries from gst-plugins-base here, also add: +dnl for libgstaudio-1.0: gstreamer-audio-1.0 >= $GST_REQUIRED +dnl for libgstvideo-1.0: gstreamer-video-1.0 >= $GST_REQUIRED +dnl for libgsttag-1.0: gstreamer-tag-1.0 >= $GST_REQUIRED +dnl for libgstpbutils-1.0: gstreamer-pbutils-1.0 >= $GST_REQUIRED +dnl for libgstfft-1.0: gstreamer-fft-1.0 >= $GST_REQUIRED +dnl for libgstinterfaces-1.0: gstreamer-interfaces-1.0 >= $GST_REQUIRED +dnl for libgstrtp-1.0: gstreamer-rtp-1.0 >= $GST_REQUIRED +dnl for libgstrtsp-1.0: gstreamer-rtsp-1.0 >= $GST_REQUIRED +dnl etc. +PKG_CHECK_MODULES(GST, [ + gstreamer-1.0 >= $GST_REQUIRED + gstreamer-base-1.0 >= $GST_REQUIRED + gstreamer-controller-1.0 >= $GST_REQUIRED + gstreamer-audio-1.0 >= $GST_REQUIRED +], [ + AC_SUBST(GST_CFLAGS) + AC_SUBST(GST_LIBS) +], [ + AC_MSG_ERROR([ + You need to install or upgrade the GStreamer development + packages on your system. On debian-based systems these are + libgstreamer1.0-dev and libgstreamer-plugins-base1.0-dev. + on RPM-based systems gstreamer1.0-devel, libgstreamer1.0-devel + or similar. The minimum version required is $GST_REQUIRED. + ]) +]) + +dnl check if compiler understands -Wall (if yes, add -Wall to GST_CFLAGS) +AC_MSG_CHECKING([to see if compiler understands -Wall]) +save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -Wall" +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ ], [ ])], [ + GST_CFLAGS="$GST_CFLAGS -Wall" + AC_MSG_RESULT([yes]) +], [ + AC_MSG_RESULT([no]) +]) + +dnl set the plugindir where plugins should be installed (for src/Makefile.am) +if test "x${prefix}" = "x$HOME"; then + plugindir="$HOME/.gstreamer-1.0/plugins" +else + plugindir="\$(libdir)/gstreamer-1.0" +fi +AC_SUBST(plugindir) + +dnl set proper LDFLAGS for plugins +GST_PLUGIN_LDFLAGS='-module -avoid-version -export-symbols-regex [_]*\(gst_\|Gst\|GST_\).*' +AC_SUBST(GST_PLUGIN_LDFLAGS) + +AC_CONFIG_FILES([Makefile src/Makefile]) +AC_OUTPUT + diff --git a/packaging/gst-plugins-video-dec.spec b/packaging/gst-plugins-video-dec.spec new file mode 100644 index 0000000..1094bee --- /dev/null +++ b/packaging/gst-plugins-video-dec.spec @@ -0,0 +1,41 @@ +Name: gst-plugins-video-dec +Version: 1.0.3 +Release: 1 +License: LGPLv2+ +Summary: nexell video decoder gstreamer plugin +Group: Development/Libraries +Source: %{name}-%{version}.tar.gz + +BuildRequires: pkgconfig automake autoconf libtool +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: gstreamer-devel +BuildRequires: glibc-devel +BuildRequires: gst-plugins-base-devel +BuildRequires: nx-gst-meta-devel +BuildRequires: nx-video-api-devel + +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description +Nexell video decoder gstreamer plugin + +%prep +%setup -q + +%build +autoreconf -v --install || exit 1 +%configure +make %{?_smp_mflags} + +%postun -p /sbin/ldconfig + +%install +rm -rf %{buildroot} +make install DESTDIR=%{buildroot} + +find %{buildroot} -type f -name "*.la" -delete + +%files +%{_libdir}/gstreamer-1.0/libgstnxvideodec.so* +%license LICENSE.LGPLv2+ diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..c617ebb --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,32 @@ +# Note: plugindir is set in configure + +plugin_LTLIBRARIES = libgstnxvideodec.la + +############################################################################## +# TODO: for the next set of variables, name the prefix if you named the .la, # +# e.g. libmysomething.la => libmysomething_la_SOURCES # +# libmysomething_la_CFLAGS # +# libmysomething_la_LIBADD # +# libmysomething_la_LDFLAGS # +############################################################################## + +# sources used to compile this plug-in +libgstnxvideodec_la_SOURCES = gstnxvideodec.c decoder.c + +# compiler and linker flags used to compile this plugin, set in configure.ac +libgstnxvideodec_la_CFLAGS = \ + $(GST_CFLAGS) \ + -I$(includedir) + +libgstnxvideodec_la_LIBADD = \ + $(GST_LIBS) \ + -lgstvideo-1.0 \ + -lgstpbutils-1.0 \ + -lnxgstmeta \ + -lnx_video_api + +libgstnxvideodec_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -L$(libdir) +libgstnxvideodec_la_LIBTOOLFLAGS = --tag=disable-static + +# headers we need but don't want installed +noinst_HEADERS = gstnxvideodec.h decoder.h diff --git a/src/decoder.c b/src/decoder.c new file mode 100644 index 0000000..8220df9 --- /dev/null +++ b/src/decoder.c @@ -0,0 +1,989 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "decoder.h" +#include "gstnxvideodec.h" + +#define MAX_OUTPUT_BUF 6 + +static gint ParseH264Info (guint8 * pData, gint size, NX_AVCC_TYPE * pH264Info); +static gint ParseAvcStream (guint8 * pInBuf, gint inSize, gint nalLengthSize, + unsigned char *pBuffer, gint * pIsKey); +static gint InitializeCodaVpu (NX_VIDEO_DEC_STRUCT * pHDec, guint8 * pInitBuf, + gint initBufSize); +static gint FlushDecoder (NX_VIDEO_DEC_STRUCT * pNxVideoDecHandle); +static gint Initialize (NX_VIDEO_DEC_STRUCT * pHDec, GstBuffer * pGstBuf, + NX_V4L2DEC_OUT * pDecOut, gboolean bKeyFrame, guint8 * pInBuf, gint inSize, + gint64 timestamp, NX_AVCC_TYPE * h264Info); +//TimeStamp +static void InitVideoTimeStamp (NX_VIDEO_DEC_STRUCT * hDec); +static void PushVideoTimeStamp (NX_VIDEO_DEC_STRUCT * hDec, gint64 timestamp, + guint flag); +static gint PopVideoTimeStamp (NX_VIDEO_DEC_STRUCT * hDec, gint64 * pTimestamp, + guint * pFlag); + +// +// Find Codec Matching Codec Information +// +gint +FindCodecInfo (GstVideoCodecState * pState, NX_VIDEO_DEC_STRUCT * pDecHandle) +{ + guint codecType = -1; + GstStructure *pStructure = gst_caps_get_structure (pState->caps, 0);; + const gchar *pMime = gst_structure_get_name (pStructure); + + FUNC_IN (); + + pDecHandle->width = GST_VIDEO_INFO_WIDTH (&pState->info); + pDecHandle->height = GST_VIDEO_INFO_HEIGHT (&pState->info); + pDecHandle->fpsNum = GST_VIDEO_INFO_FPS_N (&pState->info); + pDecHandle->fpsDen = GST_VIDEO_INFO_FPS_D (&pState->info); + + if (0 == pDecHandle->fpsNum) { + pDecHandle->fpsNum = 30; + pDecHandle->fpsDen = 1; + } + + g_print ("mime type = %s\n", pMime); + + // H.264 + if (!strcmp (pMime, "video/x-h264")) { + codecType = V4L2_PIX_FMT_H264; + } + // H.263 + else if (!strcmp (pMime, "video/x-h263")) { + codecType = V4L2_PIX_FMT_H263; + } + // xvid + else if (!strcmp (pMime, "video/x-xvid")) { + codecType = V4L2_PIX_FMT_MPEG4; + } + // mpeg 2 & 4 + else if (!strcmp (pMime, "video/mpeg")) { + gint mpegVer = 0; + gst_structure_get_int (pStructure, "mpegversion", &mpegVer); + if ((2 == mpegVer) || (1 == mpegVer)) { + codecType = V4L2_PIX_FMT_MPEG2; + } else if (4 == mpegVer) { + codecType = V4L2_PIX_FMT_MPEG4; + } + } + // divx + else if (!strcmp (pMime, "video/x-divx")) { + gint divxVer = 0; + gst_structure_get_int (pStructure, "divxversion", &divxVer); + + if (3 == divxVer) { + codecType = V4L2_PIX_FMT_DIV3; + } else if (4 == divxVer) { + codecType = V4L2_PIX_FMT_DIV4; + } else if (5 == divxVer) { + codecType = V4L2_PIX_FMT_DIV5; + } else if (6 == divxVer) { + codecType = V4L2_PIX_FMT_DIV6; + } + } + // msmpeg + else if (!strcmp (pMime, "video/x-msmpeg")) { + gint msMpegVer = 0; + gst_structure_get_int (pStructure, "msmpegversion", &msMpegVer); + if (43 == msMpegVer) { + codecType = V4L2_PIX_FMT_DIV3; + } + } + + if (codecType == -1) { + GST_ERROR ("out of profile or not supported video codec.(mime_type=%s)\n", + pMime); + } + + if (pDecHandle->width > NX_MAX_WIDTH || pDecHandle->height > NX_MAX_HEIGHT) + goto error_outofrange; + + FUNC_OUT (); + + return codecType; + +error_outofrange: + GST_ERROR ("out of resolution for %s.(Max %dx%d, In %dx%d )\n", pMime, + NX_MAX_WIDTH, NX_MAX_HEIGHT, pDecHandle->width, pDecHandle->height); + return -1; +} + +gboolean +GetExtraInfo (NX_VIDEO_DEC_STRUCT * pDecHandle, guint8 * pCodecData, + gint codecDataSize) +{ + if (codecDataSize > 0 && pCodecData) { + if (pDecHandle->codecType == V4L2_PIX_FMT_H264) { + if (pDecHandle->pH264Info) { + g_free (pDecHandle->pH264Info); + } + pDecHandle->pH264Info = (NX_AVCC_TYPE *) g_malloc (sizeof (NX_AVCC_TYPE)); + memset (pDecHandle->pH264Info, 0, sizeof (NX_AVCC_TYPE)); + // H264(AVC) + if (ParseH264Info (pCodecData, codecDataSize, pDecHandle->pH264Info) != 0) { + GST_ERROR ("Error unsupported h264 stream!\n"); + return FALSE; + } else { + // Debugging + g_print ("NumSps = %d, NumPps = %d, type = %s\n", + pDecHandle->pH264Info->numSps, + pDecHandle->pH264Info->numPps, + (pDecHandle->pH264Info->eStreamType == + NX_H264_STREAM_AVCC) ? "avcC type" : "AnnexB type"); + } + } else { + memcpy (pDecHandle->pExtraData, pCodecData, codecDataSize); + } + } else { + g_print ("Codec_data not exist.\n"); + } + + return TRUE; +} + +NX_VIDEO_DEC_STRUCT * +OpenVideoDec () +{ + NX_VIDEO_DEC_STRUCT *pDecHandle = NULL; + + FUNC_IN (); + + pDecHandle = g_malloc (sizeof (NX_VIDEO_DEC_STRUCT)); + + if (NULL == pDecHandle) { + GST_ERROR ("%s(%d) Create VideoHandle failed.\n", __FILE__, __LINE__); + return NULL; + } + + memset (pDecHandle, 0, sizeof (NX_VIDEO_DEC_STRUCT)); + + FUNC_OUT (); + + return pDecHandle; +} + +gint +InitVideoDec (NX_VIDEO_DEC_STRUCT * pDecHandle) +{ + gint ret = 0; + FUNC_IN (); + + pDecHandle->hCodec = NX_V4l2DecOpen (pDecHandle->codecType); + if (NULL == pDecHandle->hCodec) { + GST_ERROR ("%s(%d) NX_V4l2DecOpen() failed.\n", __FILE__, __LINE__); + return -1; + } + + pDecHandle->pTmpStrmBuf = g_malloc (MAX_INPUT_BUF_SIZE); + pDecHandle->tmpStrmBufSize = MAX_INPUT_BUF_SIZE; + pDecHandle->tmpStrmBufIndex = 0; + + InitVideoTimeStamp (pDecHandle); + + pDecHandle->bNeedIframe = TRUE; + + FUNC_OUT (); + + return ret; +} + +gint +VideoDecodeFrame (NX_VIDEO_DEC_STRUCT * pDecHandle, GstBuffer * pGstBuf, + NX_V4L2DEC_OUT * pDecOut, gboolean bKeyFrame) +{ + NX_VIDEO_DEC_STRUCT *pHDec = pDecHandle; + guint8 *pInBuf = NULL; + GstMapInfo mapInfo; + gint inSize = 0; + NX_AVCC_TYPE *h264Info = NULL; + gint isKey = 0; + guint8 *pDecBuf = NULL; + gint decBufSize = 0; + gint ret = 0; + gint64 timestamp = 0; + NX_V4L2DEC_IN decIn; + + FUNC_IN (); + + if (pHDec->bFlush) { + FlushDecoder (pHDec); + pHDec->bFlush = FALSE; + pHDec->bNeedKey = TRUE; + pHDec->bNeedIframe = TRUE; + pHDec->bIsFlush = TRUE; + } + + if (pHDec->bNeedKey) { + if (FALSE == bKeyFrame) { + pDecOut->dispIdx = -1; + return ret; + } + pHDec->bNeedKey = FALSE; + } + + h264Info = pHDec->pH264Info; + gst_buffer_map (pGstBuf, &mapInfo, GST_MAP_READ); + pInBuf = mapInfo.data; + inSize = gst_buffer_get_size (pGstBuf); + + // Push Input Time Stamp + if (GST_BUFFER_PTS_IS_VALID (pGstBuf)) { + PushVideoTimeStamp (pHDec, GST_BUFFER_PTS (pGstBuf), + GST_BUFFER_FLAGS (pGstBuf)); + timestamp = GST_BUFFER_PTS (pGstBuf); + } else if (GST_BUFFER_DTS_IS_VALID (pGstBuf)) { + PushVideoTimeStamp (pHDec, GST_BUFFER_DTS (pGstBuf), + GST_BUFFER_FLAGS (pGstBuf)); + timestamp = GST_BUFFER_DTS (pGstBuf); + } + + if (FALSE == pHDec->bInitialized) { + ret = + Initialize (pHDec, pGstBuf, pDecOut, bKeyFrame, pInBuf, inSize, + timestamp, h264Info); + + if ((ret == DEC_ERR) && (pDecOut->dispIdx = -1)) { + goto VideoDecodeFrame_Exit; + } else if ((ret == DEC_INIT_ERR) || (ret == DEC_ERR)) { + goto VideoDecodeFrame_Exit; + } else if ((ret == 0) && (pDecOut->dispIdx = -1)) { + if (0 == pHDec->extraDataSize) { + if (((GST_BUFFER_FLAG_DISCONT | GST_BUFFER_FLAG_DELTA_UNIT) == + GST_BUFFER_FLAGS (pGstBuf)) && (0 == bKeyFrame)) { + return ret; + } + } else { + goto VideoDecodeFrame_Exit; + } + } + } else { + if (pHDec->bIsFlush) { + // Input to two frame NX_V4l2DecDecodeFrame() after seek(flush) + pHDec->frameCount++; + + if (pHDec->codecType == V4L2_PIX_FMT_H264) { + if (pHDec->h264Alignment == H264_PARSE_ALIGN_NAL) { + pDecBuf = pHDec->pTmpStrmBuf + pHDec->tmpStrmBufIndex; + decBufSize = ParseAvcStream (pInBuf, inSize, 4, pDecBuf, &isKey); + pHDec->tmpStrmBufIndex = pHDec->tmpStrmBufIndex + decBufSize; + } else if ((h264Info) && (h264Info->eStreamType == NX_H264_STREAM_AVCC)) { + pDecBuf = pHDec->pTmpStrmBuf + pHDec->tmpStrmBufIndex; + decBufSize = + ParseAvcStream (pInBuf, inSize, h264Info->nalLengthSize, pDecBuf, + &isKey); + pHDec->tmpStrmBufIndex = pHDec->tmpStrmBufIndex + decBufSize; + } + // Annex B Type + else { + memcpy (pHDec->pTmpStrmBuf + pHDec->tmpStrmBufIndex, pInBuf, inSize); + pHDec->tmpStrmBufIndex = pHDec->tmpStrmBufIndex + inSize; + } + } else { + memcpy (pHDec->pTmpStrmBuf + pHDec->tmpStrmBufIndex, pInBuf, inSize); + pHDec->tmpStrmBufIndex = pHDec->tmpStrmBufIndex + inSize; + + } + if (pHDec->frameCount >= 2) { + pHDec->bIsFlush = FALSE; + pHDec->frameCount = 0; + pDecBuf = pHDec->pTmpStrmBuf; + decBufSize = pHDec->tmpStrmBufIndex; + pHDec->tmpStrmBufIndex = 0; + } else { + ret = 0; + pDecOut->dispIdx = -1; + goto VideoDecodeFrame_Exit; + } + } else { + if (pHDec->codecType == V4L2_PIX_FMT_H264) { + if (pHDec->h264Alignment == H264_PARSE_ALIGN_NAL) { + pDecBuf = pHDec->pTmpStrmBuf; + decBufSize = ParseAvcStream (pInBuf, inSize, 4, pDecBuf, &isKey); + } else if ((h264Info) && (h264Info->eStreamType == NX_H264_STREAM_AVCC)) { + pDecBuf = pHDec->pTmpStrmBuf; + decBufSize = + ParseAvcStream (pInBuf, inSize, h264Info->nalLengthSize, pDecBuf, + &isKey); + } + // Annex B Type + else { + pDecBuf = pInBuf; + decBufSize = inSize; + } + } else { + pDecBuf = pInBuf; + decBufSize = inSize; + } + } + + decIn.strmBuf = pDecBuf; + decIn.strmSize = decBufSize; + decIn.timeStamp = timestamp; + decIn.eos = 0; + VDecSemPend (pHDec->pSem); + ret = NX_V4l2DecDecodeFrame (pHDec->hCodec, &decIn, pDecOut); + + if ((0 == ret) && (0 <= pDecOut->dispIdx)) { + if ((TRUE == pHDec->bNeedIframe) + && (PIC_TYPE_I != pDecOut->picType[DISPLAY_FRAME])) { + NX_V4l2DecClrDspFlag (pHDec->hCodec, NULL, pDecOut->dispIdx); + VDecSemPost (pHDec->pSem); + ret = DEC_ERR; + goto VideoDecodeFrame_Exit; + } else { + pHDec->bNeedIframe = FALSE; + } + } + + if ((0 != ret) || (0 > pDecOut->dispIdx)) { + VDecSemPost (pHDec->pSem); + } + + if (0 != ret) { + g_print ("NX_V4l2DecDecodeFrame!!!!, ret = %d\n", ret); + ret = DEC_ERR; + } + } +VideoDecodeFrame_Exit: + gst_buffer_unmap (pGstBuf, &mapInfo); + + FUNC_OUT (); + + return ret; +} + +void +CloseVideoDec (NX_VIDEO_DEC_STRUCT * pDecHandle) +{ + if (pDecHandle == NULL) { + g_free (pDecHandle); + GST_ERROR ("pDecHandle is null\n"); + return; + } + if (pDecHandle->hCodec) { + NX_V4l2DecClose (pDecHandle->hCodec); + pDecHandle->hCodec = NULL; + } + + if (pDecHandle->pExtraData) { + g_free (pDecHandle->pExtraData); + pDecHandle->pExtraData = NULL; + pDecHandle->extraDataSize = 0; + } + + if (pDecHandle->pH264Info) { + g_free (pDecHandle->pH264Info); + pDecHandle->pH264Info = NULL; + } + + if (pDecHandle->pTmpStrmBuf) { + g_free (pDecHandle->pTmpStrmBuf); + pDecHandle->pTmpStrmBuf = NULL; + } + + g_free (pDecHandle); +} + +gint +DisplayDone (NX_VIDEO_DEC_STRUCT * pDecHandle, gint v4l2BufferIdx) +{ + FUNC_IN (); + + if (pDecHandle->hCodec && (v4l2BufferIdx >= 0)) { + NX_V4l2DecClrDspFlag (pDecHandle->hCodec, NULL, v4l2BufferIdx); + VDecSemPost (pDecHandle->pSem); + } + + FUNC_OUT (); + + return 0; +} + +gint +GetTimeStamp (NX_VIDEO_DEC_STRUCT * pDecHandle, gint64 * pTimestamp) +{ + gint ret = 0; + guint flag; + + ret = PopVideoTimeStamp (pDecHandle, pTimestamp, &flag); + + return ret; +} + +// Copy Image YV12 to General YV12 +gint +CopyImageToBufferYV12 (uint8_t * pSrcY, uint8_t * pSrcU, uint8_t * pSrcV, + uint8_t * pDst, uint32_t strideY, uint32_t strideUV, uint32_t width, + uint32_t height) +{ + uint32_t i; + if (width == strideY) { + memcpy (pDst, pSrcY, width * height); + pDst += width * height; + } else { + for (i = 0; i < height; i++) { + memcpy (pDst, pSrcY, width); + pSrcY += strideY; + pDst += width; + } + } + + width /= 2; + height /= 2; + if (width == strideUV) { + memcpy (pDst, pSrcU, width * height); + pDst += width * height; + memcpy (pDst, pSrcV, width * height); + } else { + for (i = 0; i < height; i++) { + memcpy (pDst, pSrcU, width); + pSrcY += strideY; + pDst += width; + } + for (i = 0; i < height; i++) { + memcpy (pDst, pSrcV, width); + pSrcY += strideY; + pDst += width; + } + } + return 0; +} + +static gint +Initialize (NX_VIDEO_DEC_STRUCT * pHDec, GstBuffer * pGstBuf, + NX_V4L2DEC_OUT * pDecOut, gboolean bKeyFrame, guint8 * pInBuf, gint inSize, + gint64 timestamp, NX_AVCC_TYPE * h264Info) +{ + gint seqSize = 0; + gint ret = 0; + guint8 *pSeqData = NULL; + gboolean bDecode = FALSE; + gint isKey = 0; + gint decBufSize = 0; + NX_V4L2DEC_IN decIn; + guint8 *pDecBuf = pHDec->pTmpStrmBuf; + + if (0 == pHDec->extraDataSize) { + if (((GST_BUFFER_FLAG_DISCONT | GST_BUFFER_FLAG_DELTA_UNIT) == + GST_BUFFER_FLAGS (pGstBuf)) && (0 == bKeyFrame)) { + pDecOut->dispIdx = -1; + return ret; + } + + if (pHDec->h264Alignment == H264_PARSE_ALIGN_NAL) { + gint size = 0; + if (0 == GST_BUFFER_DURATION (pGstBuf)) { + size = ParseAvcStream (pInBuf, inSize, 4, pDecBuf + pHDec->pos, &isKey); + pHDec->size = pHDec->size + size; + pHDec->pos = pHDec->pos + size; + + pDecOut->dispIdx = -1; + ret = DEC_ERR; + return ret; + } else { + size = ParseAvcStream (pInBuf, inSize, 4, pDecBuf + pHDec->pos, &isKey); + pHDec->size = pHDec->size + size; + pHDec->pos = pHDec->pos + size; + seqSize = pHDec->pos; + pSeqData = pDecBuf; + bDecode = TRUE; + } + } else if (V4L2_PIX_FMT_DIV3 == pHDec->codecType) { + seqSize = 0; + pSeqData = NULL; + bDecode = TRUE; + } else { + seqSize = inSize; + pSeqData = pInBuf; + } + } else { + if (V4L2_PIX_FMT_H263 == pHDec->codecType + || V4L2_PIX_FMT_MPEG2 == pHDec->codecType) { + memcpy (pDecBuf, pHDec->pExtraData, pHDec->extraDataSize); + decBufSize = pHDec->extraDataSize; + memcpy (pDecBuf + decBufSize, pInBuf, inSize); + decBufSize += inSize; + + seqSize = decBufSize; + pSeqData = pDecBuf; + } else if (V4L2_PIX_FMT_H264 == pHDec->codecType) { + if ((h264Info) && (h264Info->eStreamType == NX_H264_STREAM_AVCC)) { + gint size; + memcpy (pDecBuf, h264Info->spsppsData, h264Info->spsppsSize); + decBufSize = h264Info->spsppsSize; + size = + ParseAvcStream (pInBuf, inSize, h264Info->nalLengthSize, + pDecBuf + decBufSize, &isKey); + decBufSize += size; + } + // Annex B Type + else { + memcpy (pDecBuf, pHDec->pExtraData, pHDec->extraDataSize); + decBufSize = pHDec->extraDataSize; + memcpy (pDecBuf + decBufSize, pInBuf, inSize); + decBufSize += inSize; + } + seqSize = decBufSize; + pSeqData = pDecBuf; + } else { + seqSize = pHDec->extraDataSize; + pSeqData = pHDec->pExtraData; + bDecode = TRUE; + } + } + + // Initialize VPU + ret = InitializeCodaVpu (pHDec, pSeqData, seqSize); + + if (0 > ret) { + GST_ERROR ("VPU initialized Failed!!!!\n"); + NX_V4l2DecClose (pHDec->hCodec); + pHDec->hCodec = NULL; + ret = DEC_INIT_ERR; + return ret; + } + + pHDec->bInitialized = TRUE; + + if (TRUE == bDecode) { + if (pHDec->codecType == V4L2_PIX_FMT_H264) { + if (pHDec->h264Alignment == H264_PARSE_ALIGN_NAL) { + pDecBuf = pDecBuf + pHDec->pos - inSize; + decBufSize = inSize; + } else if ((h264Info) && (h264Info->eStreamType == NX_H264_STREAM_AVCC)) { + pDecBuf = pHDec->pTmpStrmBuf; + decBufSize = + ParseAvcStream (pInBuf, inSize, h264Info->nalLengthSize, pDecBuf, + &isKey); + } + // Annex B Type + else { + pDecBuf = pInBuf; + decBufSize = inSize; + } + } else { + pDecBuf = pInBuf; + decBufSize = inSize; + } + + decIn.strmBuf = pDecBuf; + decIn.strmSize = decBufSize; + decIn.timeStamp = timestamp; + decIn.eos = 0; + VDecSemPend (pHDec->pSem); + ret = NX_V4l2DecDecodeFrame (pHDec->hCodec, &decIn, pDecOut); + + if ((0 == ret) && (0 <= pDecOut->dispIdx)) { + if ((TRUE == pHDec->bNeedIframe) + && (PIC_TYPE_I != pDecOut->picType[DISPLAY_FRAME])) { + NX_V4l2DecClrDspFlag (pHDec->hCodec, NULL, pDecOut->dispIdx); + VDecSemPost (pHDec->pSem); + ret = DEC_ERR; + return ret; + } else { + pHDec->bNeedIframe = FALSE; + } + } + + if ((0 != ret) || (0 > pDecOut->dispIdx)) { + VDecSemPost (pHDec->pSem); + } + + if (0 != ret) { + g_print ("NX_V4l2DecDecodeFrame!!!!, ret = %d\n", ret); + ret = DEC_ERR; + } + } else { + ret = 0; + pDecOut->dispIdx = -1; + } + + return ret; +} + +static gint +FlushDecoder (NX_VIDEO_DEC_STRUCT * pDecHandle) +{ + + FUNC_IN (); + + InitVideoTimeStamp (pDecHandle); + + if (pDecHandle->hCodec) { + NX_V4l2DecFlush (pDecHandle->hCodec); + } + + FUNC_OUT (); + + return 0; +} + +static gint +InitializeCodaVpu (NX_VIDEO_DEC_STRUCT * pHDec, guint8 * pSeqInfo, + gint seqInfoSize) +{ + gint ret = -1; + + FUNC_IN (); + + if (pHDec->hCodec) { + NX_V4L2DEC_SEQ_IN seqIn; + NX_V4L2DEC_SEQ_OUT seqOut; + memset (&seqIn, 0, sizeof (seqIn)); + memset (&seqOut, 0, sizeof (seqOut)); + seqIn.width = pHDec->width; + seqIn.height = pHDec->height; + seqIn.seqBuf = pSeqInfo; + seqIn.seqSize = seqInfoSize; + + if (0 != (ret = NX_V4l2DecParseVideoCfg (pHDec->hCodec, &seqIn, &seqOut))) { + GST_ERROR ("NX_V4l2DecParseVideoCfg() is failed!!, ret = %d\n", ret); + return ret; + } + + seqIn.width = seqOut.width; + seqIn.height = seqOut.height; + pHDec->bufferCountActual = seqOut.minBuffers + MAX_OUTPUT_BUF; + seqIn.numBuffers = pHDec->bufferCountActual; + seqIn.imgPlaneNum = pHDec->imgPlaneNum; + seqIn.imgFormat = seqOut.imgFourCC; + ret = NX_V4l2DecInit (pHDec->hCodec, &seqIn); + + if (0 != ret) { + GST_ERROR ("NX_V4l2DecInit() is failed!!, ret = %d\n", ret); + } + + pHDec->minRequiredFrameBuffer = seqOut.minBuffers; + pHDec->pSem = VDecSemCreate (MAX_OUTPUT_BUF); + g_print + ("<<<<<<<<<< InitializeCodaVpu(Min=%d, %dx%d) (ret = %d) >>>>>>>>>\n", + pHDec->minRequiredFrameBuffer, seqOut.width, seqOut.height, ret); + + pHDec->frameCount = 0; + pHDec->bIsFlush = FALSE; + } + + FUNC_OUT (); + + return ret; +} + +// +// +// H.264 Decoder +// + +// +// avcC format +// Name Bits Descriptions +// =============================================== +// CFG version 8 bits "1" +// AVC porfile indication 8 bits Profile code +// Profile compatibility 8 bits Compatible profile +// AVC level indication 8 bits Level code +// Reserved 6 bits 0b111111 +// Length size minus one 2 bits Nal unit length size +// Reserved 3 bits 0b111 +// Num of SPS 5 bits Number of SPS +// SPS length 16bits SPS length N +// SPS Data N byts SPS data +// Num of PPS 8 bits Number of PPS +// PPS length 16bits PPS length M +// PPS Data M Byts PPS data +// +static gint +ParseSpsPpsFromAVCC (unsigned char *pExtraData, gint extraDataSize, + NX_AVCC_TYPE * pH264Info) +{ + + gint length, i, pos = 0; + + FUNC_IN (); + + if (1 != pExtraData[0] || 11 > extraDataSize) { + GST_ERROR ("Error : Invalid \"avcC\" data(%d)\n", extraDataSize); + return -1; + } + // Parser "avcC" format data + pos++; // Skip Version + pH264Info->profileIndication = pExtraData[pos]; + pos++; + pH264Info->compatibleProfile = pExtraData[pos]; + pos++; + pH264Info->levelIndication = pExtraData[pos]; + pos++; + pH264Info->nalLengthSize = (pExtraData[pos] & 0x03) + 1; + pos++; + + if (100 < pH264Info->profileIndication) { + GST_ERROR ("H264 profile too high!(%d)\n", pH264Info->profileIndication); + return -1; + } + // parser spsp + pH264Info->spsppsSize = 0; + pH264Info->numSps = (pExtraData[pos] & 0x1f); + pos++; + + for (i = 0; i < pH264Info->numSps; i++) { + length = (pExtraData[pos] << 8) | pExtraData[pos + 1]; + pos += 2; + if ((pos + length) > extraDataSize) { + GST_ERROR ("extraData size too small(SPS)\n"); + return -1; + } + pH264Info->spsppsData[pH264Info->spsppsSize + 0] = 0; + pH264Info->spsppsData[pH264Info->spsppsSize + 1] = 0; + pH264Info->spsppsData[pH264Info->spsppsSize + 2] = 0; + pH264Info->spsppsData[pH264Info->spsppsSize + 3] = 1; + pH264Info->spsppsSize += 4; + memcpy (pH264Info->spsppsData + pH264Info->spsppsSize, pExtraData + pos, + length); + pH264Info->spsppsSize += length; + pos += length; + } + + // parse pps + pH264Info->numPps = pExtraData[pos]; + pos++; + for (i = 0; i < pH264Info->numPps; i++) { + length = (pExtraData[pos] << 8) | pExtraData[pos + 1]; + pos += 2; + if ((pos + length) > extraDataSize) { + GST_ERROR ("extraData size too small(PPS)\n"); + return -1; + } + pH264Info->spsppsData[pH264Info->spsppsSize + 0] = 0; + pH264Info->spsppsData[pH264Info->spsppsSize + 1] = 0; + pH264Info->spsppsData[pH264Info->spsppsSize + 2] = 0; + pH264Info->spsppsData[pH264Info->spsppsSize + 3] = 1; + pH264Info->spsppsSize += 4; + memcpy (pH264Info->spsppsData + pH264Info->spsppsSize, pExtraData + pos, + length); + pH264Info->spsppsSize += length; + pos += length; + } + + if (1 > pH264Info->numSps || 1 > pH264Info->numPps) { + return -1; + } + + FUNC_OUT (); + + return 0; +} + +static gint +ParseH264Info (guint8 * pData, gint size, NX_AVCC_TYPE * pH264Info) +{ + FUNC_IN (); + + if (size <= 0) { + return -1; + } + + if (pData[0] == 0) { + pH264Info->eStreamType = NX_H264_STREAM_ANNEXB; + memcpy (pH264Info->spsppsData, pData, size); + pH264Info->spsppsSize = size; + } else { + pH264Info->eStreamType = NX_H264_STREAM_AVCC; + return ParseSpsPpsFromAVCC (pData, size, pH264Info); + } + + FUNC_OUT (); + + return 0; +} + +static gint +ParseAvcStream (guint8 * pInBuf, gint inSize, gint nalLengthSize, + unsigned char *pBuffer, gint * pIsKey) +{ + + int nalLength; + int pos = 0; + *pIsKey = 0; + + FUNC_IN (); + + // 'avcC' format + do { + nalLength = 0; + if (nalLengthSize == 4) { + nalLength = + pInBuf[0] << 24 | pInBuf[1] << 16 | pInBuf[2] << 8 | pInBuf[3]; + } else if (nalLengthSize == 2) { + nalLength = pInBuf[0] << 8 | pInBuf[1]; + } else if (nalLengthSize == 3) { + nalLength = pInBuf[0] << 16 | pInBuf[1] << 8 | pInBuf[2]; + } else if (nalLengthSize == 1) { + nalLength = pInBuf[0]; + } + + pInBuf += nalLengthSize; + inSize -= nalLengthSize; + + if (0 == nalLength || inSize < (int) nalLength) { + GST_ERROR + ("Error : avcC type nal length error (nalLength = %d, inSize=%d, nalLengthSize=%d)\n", + nalLength, inSize, nalLengthSize); + return -1; + } + // put nal start code + pBuffer[pos + 0] = 0x00; + pBuffer[pos + 1] = 0x00; + pBuffer[pos + 2] = 0x00; + pBuffer[pos + 3] = 0x01; + pos += 4; + + if ((pInBuf[0] & 0x1f) == 0x5) { + *pIsKey = 1; + } + + memcpy (pBuffer + pos, pInBuf, nalLength); + pos += nalLength; + + inSize -= nalLength; + pInBuf += nalLength; + } while (2 < inSize); + + FUNC_OUT (); + + return pos; +} + +/////////////////////////////////////////////////////////////////////////////// +static void +InitVideoTimeStamp (NX_VIDEO_DEC_STRUCT * hDec) +{ + gint i; + for (i = 0; i < NX_MAX_BUF; i++) { + hDec->outTimeStamp[i].flag = (gint) - 1; + hDec->outTimeStamp[i].timestamp = (gint) 0; + } + hDec->inFlag = 0; + hDec->outFlag = 0; +} + +static void +PushVideoTimeStamp (NX_VIDEO_DEC_STRUCT * hDec, gint64 timestamp, guint flag) +{ + gint i = 0; + if (-1 != timestamp) { + hDec->inFlag++; + if (NX_MAX_BUF <= hDec->inFlag) + hDec->inFlag = 0; + + for (i = 0; i < NX_MAX_BUF; i++) { + if (hDec->outTimeStamp[i].flag == (gint) - 1) { + hDec->outTimeStamp[i].timestamp = timestamp; + hDec->outTimeStamp[i].flag = flag; + break; + } + } + } +} + +static gint +PopVideoTimeStamp (NX_VIDEO_DEC_STRUCT * hDec, gint64 * pTimestamp, + guint * pFlag) +{ + gint i = 0; + gint64 minTime = 0x7FFFFFFFFFFFFFFFll; + gint minIdx = -1; + for (i = 0; i < NX_MAX_BUF; i++) { + if (hDec->outTimeStamp[i].flag != (guint) - 1) { + if (minTime > hDec->outTimeStamp[i].timestamp) { + minTime = hDec->outTimeStamp[i].timestamp; + minIdx = i; + } + } + } + if (minIdx != -1) { + *pTimestamp = hDec->outTimeStamp[minIdx].timestamp; + *pFlag = hDec->outTimeStamp[minIdx].flag; + hDec->outTimeStamp[minIdx].flag = (gint) - 1; + return 0; + } else { +// g_print("Cannot Found Time Stamp!!!\n"); + return -1; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +// +// Semaphore functions for output buffer. +// +NX_VDEC_SEMAPHORE * +VDecSemCreate (int init) +{ + NX_VDEC_SEMAPHORE *pSem = + (NX_VDEC_SEMAPHORE *) g_malloc (sizeof (NX_VDEC_SEMAPHORE)); + FUNC_IN (); + pSem->value = init; + pthread_mutex_init (&pSem->mutex, NULL); + pthread_cond_init (&pSem->cond, NULL); + FUNC_OUT (); + return pSem; +} + +void +VDecSemDestroy (NX_VDEC_SEMAPHORE * pSem) +{ + FUNC_IN (); + if (pSem) { + pthread_mutex_destroy (&pSem->mutex); + pthread_cond_destroy (&pSem->cond); + g_free (pSem); + } + FUNC_OUT (); +} + +gboolean +VDecSemPend (NX_VDEC_SEMAPHORE * pSem) +{ + FUNC_IN (); + pthread_mutex_lock (&pSem->mutex); + + if (pSem->value == 0) { + pthread_cond_wait (&pSem->cond, &pSem->mutex); + } + pSem->value--; + + pthread_mutex_unlock (&pSem->mutex); + FUNC_OUT (); + return TRUE; +} + +gboolean +VDecSemPost (NX_VDEC_SEMAPHORE * pSem) +{ + FUNC_IN (); + pthread_mutex_lock (&pSem->mutex); + + pSem->value++; + pthread_cond_signal (&pSem->cond); + + pthread_mutex_unlock (&pSem->mutex); + FUNC_OUT (); + return TRUE; +} + +gboolean +VDecSemSignal (NX_VDEC_SEMAPHORE * pSem) +{ + FUNC_IN (); + pthread_mutex_lock (&pSem->mutex); + pthread_cond_signal (&pSem->cond); + pthread_mutex_unlock (&pSem->mutex); + FUNC_OUT (); + return TRUE; +} diff --git a/src/decoder.h b/src/decoder.h new file mode 100644 index 0000000..771a55f --- /dev/null +++ b/src/decoder.h @@ -0,0 +1,146 @@ +#include +#include +#include +#include +#include + +#ifndef __DECODER_H__ +#define __DECODER_H__ + +G_BEGIN_DECLS +#define VID_OUTPORT_MIN_BUF_CNT 12 // Max Avaiable Frames +#define VID_OUTPORT_MIN_BUF_CNT_H264_UNDER720P 22 // ~720p +#define VID_OUTPORT_MIN_BUF_CNT_H264_1080P 12 // 1080p +#define MAX_INPUT_BUF_SIZE (1024*1024*4) +////////////////////////////////////////////////////////////////////////////// +// +#define NX_MAX_WIDTH 1920 +#define NX_MAX_HEIGHT 1088 +#define NX_MAX_BUF 32 + enum +{ + DEC_INIT_ERR = -1, + DEC_ERR = -2, +}; + +enum +{ + H264_PARSE_ALIGN_NONE = 0, + H264_PARSE_ALIGN_NAL, + H264_PARSE_ALIGN_AU +}; + +typedef enum +{ + NX_H264_STREAM_UNKNOWN, + NX_H264_STREAM_AVCC, + NX_H264_STREAM_ANNEXB, +} NX_H264_STREAM_TYPE; + +typedef struct +{ + NX_H264_STREAM_TYPE eStreamType; + gint profileIndication; + gint compatibleProfile; + gint levelIndication; + gint nalLengthSize; // for AVCC Type stream + gint numSps; + gint numPps; + guint8 spsppsData[2048]; + gint spsppsSize; +} NX_AVCC_TYPE; + +struct OutBufferTimeInfo +{ + gint64 timestamp; + guint flag; +}; + +struct _NX_VDEC_SEMAPHORE +{ + guint value; + pthread_cond_t cond; + pthread_mutex_t mutex; +}; + +typedef struct _NX_VIDEO_DEC_STRUCT NX_VIDEO_DEC_STRUCT; +typedef struct _NX_VDEC_SEMAPHORE NX_VDEC_SEMAPHORE; + +struct _NX_VIDEO_DEC_STRUCT +{ + // input stream informations + gint width; + gint height; + guint fpsNum; + guint fpsDen; + + // decoder + NX_V4L2DEC_HANDLE hCodec; + gboolean bInitialized; + gint codecType; + guint8 *pExtraData; + gint extraDataSize; + gint bufferCountActual; + gint minRequiredFrameBuffer; + gboolean bFlush; + gboolean bNeedKey; + gboolean bNeedIframe; + gint imgPlaneNum; + gint pos; + gint size; + + // Temporal Buffer + guint8 *pTmpStrmBuf; + gint tmpStrmBufSize; + gint tmpStrmBufIndex; + // Output Timestamp + struct OutBufferTimeInfo outTimeStamp[NX_MAX_BUF]; + gint inFlag; + gint outFlag; + // + // Codec Specific Informations + // + // for H.264 + NX_AVCC_TYPE *pH264Info; + gint h264Alignment; + + // Input to two frame NX_V4l2DecDecodeFrame() after seek(flush) + gint frameCount; + + gboolean bIsFlush; + + NX_VDEC_SEMAPHORE *pSem; +}; +// +////////////////////////////////////////////////////////////////////////////// + +//Find Codec Matching Codec Information +gint FindCodecInfo (GstVideoCodecState * pState, + NX_VIDEO_DEC_STRUCT * pDecHandle); +gboolean GetExtraInfo (NX_VIDEO_DEC_STRUCT * pDecHandle, guint8 * pCodecData, + gint codecDataSize); + +//Video Decoder +NX_VIDEO_DEC_STRUCT *OpenVideoDec (); +gint InitVideoDec (NX_VIDEO_DEC_STRUCT * pDecHandle); +gint VideoDecodeFrame (NX_VIDEO_DEC_STRUCT * pDecHandle, GstBuffer * pGstBuf, + NX_V4L2DEC_OUT * pDecOut, gboolean bKeyFrame); +void CloseVideoDec (NX_VIDEO_DEC_STRUCT * pDecHandle); + +gint DisplayDone (NX_VIDEO_DEC_STRUCT * pDecHandle, gint v4l2BufferIdx); +gint GetTimeStamp (NX_VIDEO_DEC_STRUCT * pDecHandle, gint64 * pTimestamp); +gint CopyImageToBufferYV12 (uint8_t * pSrcY, uint8_t * pSrcU, uint8_t * pSrcV, + uint8_t * pDst, uint32_t strideY, uint32_t strideUV, uint32_t width, + uint32_t height); + +// +// Semaphore functions for output buffer. +// +NX_VDEC_SEMAPHORE *VDecSemCreate (int init); +void VDecSemDestroy (NX_VDEC_SEMAPHORE * pSem); +gboolean VDecSemPend (NX_VDEC_SEMAPHORE * pSem); +gboolean VDecSemPost (NX_VDEC_SEMAPHORE * pSem); +gboolean VDecSemSignal (NX_VDEC_SEMAPHORE * pSem); + +G_END_DECLS +#endif //__DECODER_H__ diff --git a/src/gstnxvideodec.c b/src/gstnxvideodec.c new file mode 100644 index 0000000..4f862dd --- /dev/null +++ b/src/gstnxvideodec.c @@ -0,0 +1,1003 @@ +/* + * GStreamer + * Copyright (C) 2005 Thomas Vander Stichele + * Copyright (C) 2005 Ronald S. Bultje + * Copyright (C) 2016 ray <> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** + * SECTION:element-nxvideodec + * + * FIXME:Describe nxvideodec here. + * + * + * Example launch line + * |[ + * gst-launch -v -m fakesrc ! nxvideodec ! fakesink silent=TRUE + * ]| + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include "gstnxvideodec.h" + +// This SUPPORT_NO_MEMORY_COPY function is disabled now. +// if the video decoder mmap is supported this function, it will be enabled. +#define SUPPORT_NO_MEMORY_COPY 0 + +GST_DEBUG_CATEGORY_STATIC (gst_nxvideodec_debug_category); +#define GST_CAT_DEFAULT gst_nxvideodec_debug_category + +/* prototypes */ +static void gst_nxvideodec_set_property (GObject * object, + guint property_id, const GValue * value, GParamSpec * pspec); +static void gst_nxvideodec_get_property (GObject * object, + guint property_id, GValue * value, GParamSpec * pspec); + +static gboolean gst_nxvideodec_start (GstVideoDecoder * decoder); +static gboolean gst_nxvideodec_stop (GstVideoDecoder * decoder); +static gboolean gst_nxvideodec_set_format (GstVideoDecoder * decoder, + GstVideoCodecState * state); +static gboolean gst_nxvideodec_flush (GstVideoDecoder * decoder); +static GstFlowReturn gst_nxvideodec_handle_frame (GstVideoDecoder * decoder, + GstVideoCodecFrame * frame); +static void nxvideodec_base_init (gpointer gclass); +static void nxvideodec_buffer_finalize (gpointer pData); +static GstMemory *nxvideodec_mmvideobuf_copy (NX_V4L2DEC_OUT * pDecOut); + +#if SUPPORT_NO_MEMORY_COPY +static void nxvideodec_get_offset_stride (gint width, gint height, + guint8 * pSrc, gsize * pOffset, gint * pStride); +enum +{ + PROP_0, +}; +#else +enum +{ + PROP_0, + PROP_TYPE //0: 1:MM_VIDEO_BUFFER_TYPE_GEM +}; +enum +{ + BUFFER_TYPE_NORMAL, + BUFFER_TYPE_GEM +}; +#endif + +enum +{ + STOP, + PLAY +}; + +#ifndef ALIGN +#define ALIGN(X,N) ( (X+N-1) & (~(N-1)) ) +#endif + +struct video_meta_mmap_buffer +{ + gint v4l2BufferIdx; + GstNxVideoDec *pNxVideoDec; +}; + +#define PLUGIN_LONG_NAME "S5P6818 H/W Video Decoder" +#define PLUGIN_DESC "Nexell H/W Video Decoder for S5P6818, Version: 0.1.0" +#define PLUGIN_AUTHOR "Hyun Chul Jun " + +// pad templates +static GstStaticPadTemplate gst_nxvideodec_src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-raw, " + "format = (string) { I420 }, " + "width = (int) [ 64, 1920 ], " "height = (int) [ 64, 1088 ] ") + + ); + + +static void +nxvideodec_base_init (gpointer gclass) +{ + GstElementClass *pElement_class = GST_ELEMENT_CLASS (gclass); + GstCaps *pCapslist = NULL; + GstNxVideoDecClass *pKlass = GST_NXVIDEODEC_CLASS (pElement_class); + + FUNC_IN (); + + gst_element_class_set_details_simple (pElement_class, + PLUGIN_LONG_NAME, "Codec/Decoder/Video", PLUGIN_DESC, PLUGIN_AUTHOR); + + pCapslist = gst_caps_new_empty (); + + // H.263 + gst_caps_append_structure (pCapslist, + gst_structure_new ("video/x-h263", + "variant", G_TYPE_STRING, "itu", NULL)); + + // H.264 + gst_caps_append_structure (pCapslist, + gst_structure_new ("video/x-h264", + "width", GST_TYPE_INT_RANGE, 64, NX_MAX_WIDTH, + "height", GST_TYPE_INT_RANGE, 64, NX_MAX_HEIGHT, NULL)); + + // XVID + gst_caps_append_structure (pCapslist, + gst_structure_new ("video/x-xvid", + "width", GST_TYPE_INT_RANGE, 64, NX_MAX_WIDTH, + "height", GST_TYPE_INT_RANGE, 64, NX_MAX_HEIGHT, NULL)); + + + // MPEG2 + gst_caps_append_structure (pCapslist, + gst_structure_new ("video/mpeg", + "mpegversion", GST_TYPE_INT_RANGE, 1, 2, + "systemstream", G_TYPE_BOOLEAN, FALSE, NULL)); + + // MPEG4 + gst_caps_append_structure (pCapslist, + gst_structure_new ("video/mpeg", + "mpegversion", G_TYPE_INT, 4, + "systemstream", G_TYPE_BOOLEAN, FALSE, NULL)); + + // DIVX + gst_caps_append_structure (pCapslist, + gst_structure_new ("video/x-divx", + "width", GST_TYPE_INT_RANGE, 64, NX_MAX_WIDTH, + "height", GST_TYPE_INT_RANGE, 64, NX_MAX_HEIGHT, + "divxversion", GST_TYPE_INT_RANGE, 3, 6, NULL)); + + // MSMPEG + gst_caps_append_structure (pCapslist, + gst_structure_new ("video/x-msmpeg", + "width", GST_TYPE_INT_RANGE, 64, NX_MAX_WIDTH, + "height", GST_TYPE_INT_RANGE, 64, NX_MAX_HEIGHT, + "msmpegversion", G_TYPE_INT, 43, NULL)); + + // pad templates + pKlass->pSinktempl = + gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, pCapslist); + gst_element_class_add_pad_template (pElement_class, pKlass->pSinktempl); + gst_element_class_add_pad_template (pElement_class, + gst_static_pad_template_get (&gst_nxvideodec_src_template)); + + FUNC_OUT (); +} + +G_DEFINE_TYPE_WITH_CODE (GstNxVideoDec, gst_nxvideodec, GST_TYPE_VIDEO_DECODER, + GST_DEBUG_CATEGORY_INIT (gst_nxvideodec_debug_category, "nxvideodec", 0, + "debug category for nxvideodec element")); + +// class initialization +static void +gst_nxvideodec_class_init (GstNxVideoDecClass * pKlass) +{ + FUNC_IN (); + + GObjectClass *pGobjectClass = G_OBJECT_CLASS (pKlass); + GstVideoDecoderClass *pVideoDecoderClass = GST_VIDEO_DECODER_CLASS (pKlass); + + nxvideodec_base_init (pKlass); + + pGobjectClass->set_property = gst_nxvideodec_set_property; + pGobjectClass->get_property = gst_nxvideodec_get_property; + + pVideoDecoderClass->start = GST_DEBUG_FUNCPTR (gst_nxvideodec_start); + pVideoDecoderClass->stop = GST_DEBUG_FUNCPTR (gst_nxvideodec_stop); + + pVideoDecoderClass->set_format = + GST_DEBUG_FUNCPTR (gst_nxvideodec_set_format); + pVideoDecoderClass->flush = GST_DEBUG_FUNCPTR (gst_nxvideodec_flush); + pVideoDecoderClass->handle_frame = + GST_DEBUG_FUNCPTR (gst_nxvideodec_handle_frame); + +#if SUPPORT_NO_MEMORY_COPY +#else + g_object_class_install_property (pGobjectClass, + PROP_TYPE, + g_param_spec_int ("buffer-type", "buffer-type", + "Buffer Type(0:NORMAL 1:MM_VIDEO_BUFFER_TYPE_GEM)", 0, 1, + BUFFER_TYPE_GEM, G_PARAM_READWRITE)); +#endif + + FUNC_OUT (); +} + +static void +gst_nxvideodec_init (GstNxVideoDec * pNxVideoDec) +{ + FUNC_IN (); + + GST_DEBUG_OBJECT (pNxVideoDec, "dec_init"); + + // Initialize variables + pNxVideoDec->pNxVideoDecHandle = NULL; + pNxVideoDec->pInputState = NULL; + pNxVideoDec->isState = STOP; +#if SUPPORT_NO_MEMORY_COPY +#else + pNxVideoDec->bufferType = BUFFER_TYPE_GEM; +#endif + pthread_mutex_init (&pNxVideoDec->mutex, NULL); + + FUNC_OUT (); +} + +void +gst_nxvideodec_set_property (GObject * pObject, guint propertyId, + const GValue * pValue, GParamSpec * pPspec) +{ + GstNxVideoDec *pNxvideodec = GST_NXVIDEODEC (pObject); + FUNC_IN (); + + GST_DEBUG_OBJECT (pNxvideodec, "set_property"); + + switch (propertyId) { +#if SUPPORT_NO_MEMORY_COPY +#else + case PROP_TYPE: + pNxvideodec->bufferType = g_value_get_int (pValue); + break; +#endif + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (pObject, propertyId, pPspec); + break; + } + + FUNC_OUT (); +} + +void +gst_nxvideodec_get_property (GObject * pObject, guint propertyId, + GValue * pValue, GParamSpec * pPspec) +{ + GstNxVideoDec *pNxvideodec = GST_NXVIDEODEC (pObject); + FUNC_IN (); + + GST_DEBUG_OBJECT (pNxvideodec, "get_property"); + + switch (propertyId) { +#if SUPPORT_NO_MEMORY_COPY +#else + case PROP_TYPE: + g_value_set_int (pValue, pNxvideodec->bufferType); + break; +#endif + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (pObject, propertyId, pPspec); + break; + } + + FUNC_OUT (); +} + +static gboolean +gst_nxvideodec_start (GstVideoDecoder * pDecoder) +{ + GstNxVideoDec *pNxVideoDec = GST_NXVIDEODEC (pDecoder); + FUNC_IN (); + + GST_DEBUG_OBJECT (pNxVideoDec, "start"); + + if (pNxVideoDec->pNxVideoDecHandle) { + CloseVideoDec (pNxVideoDec->pNxVideoDecHandle); + pNxVideoDec->pNxVideoDecHandle = NULL; + } + + pNxVideoDec->pNxVideoDecHandle = OpenVideoDec (); + + if (pNxVideoDec->pNxVideoDecHandle == NULL) { + GST_ERROR ("VideoDecHandle is NULL !\n"); + return FALSE; + } + + pthread_mutex_lock (&pNxVideoDec->mutex); + pNxVideoDec->isState = PLAY; + pthread_mutex_unlock (&pNxVideoDec->mutex); + + FUNC_OUT (); + + return TRUE; +} + +static gboolean +gst_nxvideodec_stop (GstVideoDecoder * pDecoder) +{ + GstNxVideoDec *pNxVideoDec = GST_NXVIDEODEC (pDecoder); + FUNC_IN (); + if (pNxVideoDec == NULL) { + GST_ERROR ("pDecoder is NULL !\n"); + return FALSE; + } + + GST_DEBUG_OBJECT (pNxVideoDec, "stop"); + + pthread_mutex_lock (&pNxVideoDec->mutex); + pNxVideoDec->isState = STOP; + pthread_mutex_unlock (&pNxVideoDec->mutex); + + if (pNxVideoDec->pNxVideoDecHandle->pSem) { + VDecSemSignal (pNxVideoDec->pNxVideoDecHandle->pSem); + VDecSemDestroy (pNxVideoDec->pNxVideoDecHandle->pSem); + pNxVideoDec->pNxVideoDecHandle->pSem = NULL; + } + + CloseVideoDec (pNxVideoDec->pNxVideoDecHandle); + + pthread_mutex_destroy (&pNxVideoDec->mutex); + + FUNC_OUT (); + return TRUE; +} + +static gboolean +gst_nxvideodec_set_format (GstVideoDecoder * pDecoder, + GstVideoCodecState * pState) +{ + GstNxVideoDec *pNxVideoDec = GST_NXVIDEODEC (pDecoder); + GstStructure *pStructure = NULL; + const gchar *pMimeType = NULL; + GstBuffer *pCodecData = NULL; + GstVideoCodecState *pOutputState = NULL; + NX_VIDEO_DEC_STRUCT *pDecHandle = NULL; + gint ret = FALSE; + + FUNC_IN (); + + GST_DEBUG_OBJECT (pNxVideoDec, "set_format"); + + if (pNxVideoDec->pInputState) { + gst_video_codec_state_unref (pNxVideoDec->pInputState); + pNxVideoDec->pInputState = NULL; + } + + pNxVideoDec->pInputState = gst_video_codec_state_ref (pState); + + // Check Support Codec Type + pStructure = gst_caps_get_structure (pNxVideoDec->pInputState->caps, 0); + pMimeType = gst_structure_get_name (pStructure); + if (pNxVideoDec->pNxVideoDecHandle) { + pDecHandle = pNxVideoDec->pNxVideoDecHandle; + } else { + return FALSE; + } + + pDecHandle->codecType = FindCodecInfo (pState, pDecHandle); + + if (pDecHandle->codecType < 0) { + GST_ERROR ("Unsupported VideoDecoder Mime Type : %s\n", pMimeType); + return FALSE; + } + + if (pDecHandle->pExtraData) { + g_free (pDecHandle->pExtraData); + pDecHandle->pExtraData = NULL; + pDecHandle->extraDataSize = 0; + } + + pCodecData = pNxVideoDec->pInputState->codec_data; + + if (pCodecData) { + GstMapInfo mapInfo; + + if (!gst_buffer_map (pCodecData, &mapInfo, GST_MAP_READ)) { + GST_ERROR ("Cannot map input buffer!\n"); + return FALSE; + } + + if (mapInfo.size > 0 && mapInfo.data) { + pDecHandle->pExtraData = (guint8 *) g_malloc (mapInfo.size); + pDecHandle->extraDataSize = mapInfo.size; + } + + if (FALSE == GetExtraInfo (pDecHandle, (guint8 *) mapInfo.data, + mapInfo.size)) { + gst_buffer_unmap (pCodecData, &mapInfo); + return FALSE; + } + gst_buffer_unmap (pCodecData, &mapInfo); + } else { + g_print ("No Codec Data\n"); + } + + if (pDecHandle->codecType == V4L2_PIX_FMT_H264) { + const gchar *pStr = NULL; + + if ((pStr = gst_structure_get_string (pStructure, "alignment"))) { + if (strcmp (pStr, "au") == 0) { + pDecHandle->h264Alignment = H264_PARSE_ALIGN_AU; + GST_DEBUG_OBJECT (pNxVideoDec, ">>>>> H264 alignment: au Type."); + } else if (strcmp (pStr, "nal") == 0) { + pDecHandle->h264Alignment = H264_PARSE_ALIGN_NAL; + GST_DEBUG_OBJECT (pNxVideoDec, ">>>>> H264 alignment: nal Type."); + } else { + GST_DEBUG_OBJECT (pNxVideoDec, "unknown alignment: %s", pStr); + } + } + } + + pOutputState = + gst_video_decoder_set_output_state (pDecoder, GST_VIDEO_FORMAT_I420, + pDecHandle->width, pDecHandle->height, pNxVideoDec->pInputState); + + pOutputState->caps = gst_caps_new_simple ("video/x-raw", + "format", G_TYPE_STRING, + gst_video_format_to_string (GST_VIDEO_FORMAT_I420), "width", G_TYPE_INT, + pDecHandle->width, "height", G_TYPE_INT, pDecHandle->height, "framerate", + GST_TYPE_FRACTION, pDecHandle->fpsNum, pDecHandle->fpsDen, NULL); + + gst_video_codec_state_unref (pOutputState); + + pNxVideoDec->pNxVideoDecHandle->imgPlaneNum = 1; +#if SUPPORT_NO_MEMORY_COPY + GST_DEBUG_OBJECT (pNxVideoDec, ">>>>> Accelerable."); +#else + if (BUFFER_TYPE_GEM == pNxVideoDec->bufferType) { + GST_DEBUG_OBJECT (pNxVideoDec, ">>>>> Accelerable."); + } +#endif + + ret = gst_video_decoder_negotiate (pDecoder); + + if (FALSE == ret) { + GST_ERROR ("Fail Negotiate !\n"); + return ret; + } + + if (0 != InitVideoDec (pNxVideoDec->pNxVideoDecHandle)) { + return FALSE; + } + + FUNC_OUT (); + + return ret; +} + +static gboolean +gst_nxvideodec_flush (GstVideoDecoder * pDecoder) +{ + GstNxVideoDec *pNxvideodec = GST_NXVIDEODEC (pDecoder); + + FUNC_IN (); + + GST_DEBUG_OBJECT (pNxvideodec, "flush"); + + if (pNxvideodec->pNxVideoDecHandle) { + pNxvideodec->pNxVideoDecHandle->bFlush = TRUE; + } + + FUNC_OUT (); + + return TRUE; +} + +#if SUPPORT_NO_MEMORY_COPY +static void +nxvideodec_get_offset_stride (gint width, gint height, guint8 * pSrc, + gsize * pOffset, gint * pStride) +{ + guint8 *plu = NULL; + guint8 *pcb = NULL; + guint8 *pcr = NULL; + gint luStride = 0; + gint luVStride = 0; + gint cStride = 0; + gint cVStride = 0; + + luStride = ALIGN (width, 32); + luVStride = ALIGN (height, 16); + cStride = luStride / 2; + cVStride = ALIGN (height / 2, 16); + plu = pSrc; + pcb = plu + luStride * luVStride; + pcr = pcb + cStride * cVStride; + + pOffset[0] = 0; + pOffset[1] = pcb - plu; + pOffset[2] = pcr - plu; + + pStride[0] = luStride; + pStride[1] = cStride; + pStride[2] = cStride; +} + +static GstFlowReturn +gst_nxvideodec_handle_frame (GstVideoDecoder * pDecoder, + GstVideoCodecFrame * pFrame) +{ + GstNxVideoDec *pNxVideoDec = GST_NXVIDEODEC (pDecoder); + NX_V4L2DEC_OUT decOut; + gint64 timeStamp = 0; + GstMapInfo mapInfo; + gint ret = 0; + gboolean bKeyFrame = FALSE; + + GstMemory *pGstmem = NULL; + GstBuffer *pGstbuf = NULL; + struct video_meta_mmap_buffer *pMeta = NULL; + + NX_VID_MEMORY_INFO *pImg = NULL; + GstVideoCodecState *pState = NULL; + + unsigned char *pVadd = NULL; + GstVideoMeta *pVmeta = NULL; + gint videoImgSize = 0; + + guint n_planes = 0; + gsize offset[3] = { 0, }; + gint stride[3] = { 0, }; + + GstMemory *pMemMMVideoData = NULL; + + FUNC_IN (); + + if (!gst_buffer_map (pFrame->input_buffer, &mapInfo, GST_MAP_READ)) { + GST_ERROR ("Cannot map input buffer!"); + gst_video_codec_frame_unref (pFrame); + return GST_FLOW_ERROR; + } + + bKeyFrame = GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (pFrame); + + ret = + VideoDecodeFrame (pNxVideoDec->pNxVideoDecHandle, pFrame->input_buffer, + &decOut, bKeyFrame); + + gst_buffer_unmap (pFrame->input_buffer, &mapInfo); + if (DEC_ERR == ret) { + GetTimeStamp (pNxVideoDec->pNxVideoDecHandle, &timeStamp); + return gst_video_decoder_drop_frame (pDecoder, pFrame); + } else if (DEC_INIT_ERR == ret) { + return GST_FLOW_ERROR; + } + + if (decOut.dispIdx < 0) { + return GST_FLOW_OK; + } + + GST_DEBUG_OBJECT (pNxVideoDec, " decOut.dispIdx: %d\n", decOut.dispIdx); + + pMeta = + (struct video_meta_mmap_buffer *) g_malloc (sizeof (struct + video_meta_mmap_buffer)); + + if (!pMeta) { + GST_ERROR_OBJECT (pNxVideoDec, "failed to malloc for meta"); + gst_video_codec_frame_unref (pFrame); + return GST_FLOW_ERROR; + } + + pImg = &decOut.hImg; + pMeta->v4l2BufferIdx = decOut.dispIdx; + pVadd = pImg->pBuffer[0]; + pMeta->pNxVideoDec = pNxVideoDec; + + videoImgSize = + pNxVideoDec->pNxVideoDecHandle->width * + pNxVideoDec->pNxVideoDecHandle->height * 1.5; + + pGstmem = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY, + pVadd, videoImgSize, 0, videoImgSize, pMeta, nxvideodec_buffer_finalize); + + if (!pGstmem) { + GST_ERROR_OBJECT (pNxVideoDec, + "failed to gst_memory_new_wrapped for mmap buffer"); + gst_video_codec_frame_unref (pFrame); + goto HANDLE_ERROR; + } + + pGstbuf = gst_buffer_new (); + if (!pGstbuf) { + GST_ERROR_OBJECT (pNxVideoDec, "failed to gst_buffer_new"); + gst_video_codec_frame_unref (pFrame); + goto HANDLE_ERROR; + } + gst_buffer_append_memory (pGstbuf, pGstmem); + + n_planes = 3; + nxvideodec_get_offset_stride (pNxVideoDec->pNxVideoDecHandle->width, + pNxVideoDec->pNxVideoDecHandle->height, (guint8 *) pImg->pBuffer[0], + offset, stride); + + pState = gst_video_decoder_get_output_state (pDecoder); + + pVmeta = + gst_buffer_add_video_meta_full (pGstbuf, GST_VIDEO_FRAME_FLAG_NONE, + GST_VIDEO_INFO_FORMAT (&pState->info), + GST_VIDEO_INFO_WIDTH (&pState->info), + GST_VIDEO_INFO_HEIGHT (&pState->info), n_planes, offset, stride); + if (!pVmeta) { + GST_ERROR_OBJECT (pNxVideoDec, "failed to gst_buffer_add_video_meta_full"); + gst_video_codec_state_unref (pState); + gst_video_codec_frame_unref (pFrame); + goto HANDLE_ERROR; + } + + pMemMMVideoData = nxvideodec_mmvideobuf_copy (&decOut); + if (!pMemMMVideoData) { + GST_ERROR ("failed to get zero copy data"); + gst_video_codec_state_unref (pState); + gst_video_codec_frame_unref (pFrame); + goto HANDLE_ERROR; + } else { + gst_buffer_append_memory (pGstbuf, pMemMMVideoData); + } + gst_buffer_add_mmvideobuffer_meta (pGstbuf, 1); + + pFrame->output_buffer = pGstbuf; + + if (-1 == GetTimeStamp (pNxVideoDec->pNxVideoDecHandle, &timeStamp)) { + GST_DEBUG_OBJECT (pNxVideoDec, "Cannot Found Time Stamp!!!"); + } + pFrame->pts = timeStamp; + GST_BUFFER_PTS (pFrame->output_buffer) = timeStamp; + + gst_video_codec_state_unref (pState); + + ret = gst_video_decoder_finish_frame (pDecoder, pFrame); + + FUNC_OUT (); + + return ret; + +HANDLE_ERROR: + if (pGstbuf) { + g_free (pGstbuf); + } + if (pGstmem) { + g_free (pGstmem); + } + if (pMeta) { + nxvideodec_buffer_finalize (pMeta); + } + + return GST_FLOW_ERROR; +} +#else +static GstFlowReturn +gst_nxvideodec_handle_frame (GstVideoDecoder * pDecoder, + GstVideoCodecFrame * pFrame) +{ + GstNxVideoDec *pNxVideoDec = GST_NXVIDEODEC (pDecoder); + NX_V4L2DEC_OUT decOut; + gint64 timeStamp = 0; + GstMapInfo mapInfo; + gint ret = 0; + gboolean bKeyFrame = FALSE; + GstMemory *pGstmem = NULL; + GstBuffer *pGstbuf = NULL; + struct video_meta_mmap_buffer *pMeta = NULL; + GstMemory *pMemMMVideoData = NULL; + + FUNC_IN (); + + if (!gst_buffer_map (pFrame->input_buffer, &mapInfo, GST_MAP_READ)) { + GST_ERROR ("Cannot map input buffer!"); + gst_video_codec_frame_unref (pFrame); + return GST_FLOW_ERROR; + } + + bKeyFrame = GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (pFrame); + + ret = + VideoDecodeFrame (pNxVideoDec->pNxVideoDecHandle, pFrame->input_buffer, + &decOut, bKeyFrame); + + gst_buffer_unmap (pFrame->input_buffer, &mapInfo); + if (DEC_ERR == ret) { + GetTimeStamp (pNxVideoDec->pNxVideoDecHandle, &timeStamp); + return gst_video_decoder_drop_frame (pDecoder, pFrame); + } else if (DEC_INIT_ERR == ret) { + return GST_FLOW_ERROR; + } + + if (decOut.dispIdx < 0) { + return GST_FLOW_OK; + } + + GST_DEBUG_OBJECT (pNxVideoDec, " decOut.dispIdx: %d\n", decOut.dispIdx); + + if (BUFFER_TYPE_GEM == pNxVideoDec->bufferType) { + pGstbuf = gst_buffer_new (); + if (!pGstbuf) { + GST_ERROR_OBJECT (pNxVideoDec, "failed to gst_buffer_new"); + gst_video_codec_frame_unref (pFrame); + goto HANDLE_ERROR; + } + + pMemMMVideoData = nxvideodec_mmvideobuf_copy (&decOut); + if (!pMemMMVideoData) { + GST_ERROR ("failed to get zero copy data"); + gst_video_codec_frame_unref (pFrame); + goto HANDLE_ERROR; + } + gst_buffer_append_memory (pGstbuf, pMemMMVideoData); + + pMeta = + (struct video_meta_mmap_buffer *) g_malloc (sizeof (struct + video_meta_mmap_buffer)); + if (!pMeta) { + GST_ERROR_OBJECT (pNxVideoDec, "failed to malloc for meta"); + gst_video_codec_frame_unref (pFrame); + return GST_FLOW_ERROR; + } + pMeta->v4l2BufferIdx = decOut.dispIdx; + pMeta->pNxVideoDec = pNxVideoDec; + pGstmem = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY, + pMeta, + sizeof (struct video_meta_mmap_buffer), + 0, + sizeof (struct video_meta_mmap_buffer), + pMeta, nxvideodec_buffer_finalize); + if (!pGstmem) { + GST_ERROR_OBJECT (pNxVideoDec, + "failed to gst_memory_new_wrapped for mmap buffer"); + gst_video_codec_frame_unref (pFrame); + goto HANDLE_ERROR; + } + gst_buffer_append_memory (pGstbuf, pGstmem); + + gst_buffer_add_mmvideobuffer_meta (pGstbuf, 0); + + pFrame->output_buffer = pGstbuf; + + if (-1 == GetTimeStamp (pNxVideoDec->pNxVideoDecHandle, &timeStamp)) { + GST_DEBUG_OBJECT (pNxVideoDec, "Cannot Found Time Stamp!!!"); + } + pFrame->pts = timeStamp; + GST_BUFFER_PTS (pFrame->output_buffer) = timeStamp; + } else { + GstVideoFrame videoFrame; + NX_VID_MEMORY_INFO *pImg = NULL; + guint8 *pPtr = NULL;; + GstVideoCodecState *pState = NULL; + GstFlowReturn flowRet; + guint8 *plu = NULL; + guint8 *pcb = NULL; + guint8 *pcr = NULL; + gint luStride = 0; + gint luVStride = 0; + gint cStride = 0; + gint cVStride = 0; + + flowRet = gst_video_decoder_allocate_output_frame (pDecoder, pFrame); + pState = gst_video_decoder_get_output_state (pDecoder); + if (flowRet != GST_FLOW_OK) { + gst_video_codec_state_unref (pState); + gst_video_codec_frame_unref (pFrame); + return flowRet; + } + + if (!gst_video_frame_map (&videoFrame, &pState->info, pFrame->output_buffer, + GST_MAP_WRITE)) { + GST_ERROR ("Cannot video frame map!\n"); + gst_video_codec_state_unref (pState); + gst_video_codec_frame_unref (pFrame); + return GST_FLOW_ERROR; + } + + if (-1 == GetTimeStamp (pNxVideoDec->pNxVideoDecHandle, &timeStamp)) { + GST_DEBUG_OBJECT (pNxVideoDec, "Cannot Found Time Stamp!!!"); + } + pFrame->pts = timeStamp; + GST_BUFFER_PTS (pFrame->output_buffer) = timeStamp; + + pImg = &decOut.hImg; + pPtr = GST_VIDEO_FRAME_COMP_DATA (&videoFrame, 0); + + luStride = ALIGN (pNxVideoDec->pNxVideoDecHandle->width, 32); + luVStride = ALIGN (pNxVideoDec->pNxVideoDecHandle->height, 16); + cStride = luStride / 2; + cVStride = ALIGN (pNxVideoDec->pNxVideoDecHandle->height / 2, 16); + plu = (guint8 *) pImg->pBuffer[0]; + pcb = plu + luStride * luVStride; + pcr = pcb + cStride * cVStride; + + CopyImageToBufferYV12 ((guint8 *) plu, (guint8 *) pcb, (guint8 *) pcr, + pPtr, luStride, cStride, pNxVideoDec->pNxVideoDecHandle->width, + pNxVideoDec->pNxVideoDecHandle->height); + + DisplayDone (pNxVideoDec->pNxVideoDecHandle, decOut.dispIdx); + + gst_video_frame_unmap (&videoFrame); + gst_video_codec_state_unref (pState); + } + + ret = gst_video_decoder_finish_frame (pDecoder, pFrame); + + FUNC_OUT (); + + return ret; + +HANDLE_ERROR: + if (pGstbuf) { + g_free (pGstbuf); + } + if (pMeta) { + nxvideodec_buffer_finalize (pMeta); + } + + return GST_FLOW_ERROR; +} +#endif + +static void +nxvideodec_buffer_finalize (gpointer pData) +{ + gint ret = 0; + + FUNC_IN (); + + struct video_meta_mmap_buffer *pMeta = + (struct video_meta_mmap_buffer *) pData; + + if (!pMeta) { + GST_ERROR ("Error: pData is null !"); + return; + } + + if ((pMeta->pNxVideoDec) && (pMeta->pNxVideoDec->pNxVideoDecHandle)) { + pthread_mutex_lock (&pMeta->pNxVideoDec->mutex); + if (PLAY == pMeta->pNxVideoDec->isState) { + GST_DEBUG_OBJECT (pMeta->pNxVideoDec, "v4l2BufferIdx: %d\n", + pMeta->v4l2BufferIdx); + ret = + DisplayDone (pMeta->pNxVideoDec->pNxVideoDecHandle, + pMeta->v4l2BufferIdx); + if (ret) { + g_print ("Fail: DisplayDone !"); + } + } + pthread_mutex_unlock (&pMeta->pNxVideoDec->mutex); + } else { + GST_ERROR ("Error: hCodec is null !"); + } + + if (pMeta) { + g_free (pMeta); + } +} + +static GstMemory * +nxvideodec_mmvideobuf_copy (NX_V4L2DEC_OUT * pDecOut) +{ + GstMemory *pMeta = NULL; + MMVideoBuffer *pMMVideoBuf = NULL; + + pMMVideoBuf = (MMVideoBuffer *) g_malloc (sizeof (MMVideoBuffer)); + if (!pMMVideoBuf) { + GST_ERROR ("failed to alloc MMVideoBuffer"); + return NULL; + } + + memset ((void *) pMMVideoBuf, 0, sizeof (MMVideoBuffer)); + + if (1 == pDecOut->hImg.planes) { + pMMVideoBuf->type = MM_VIDEO_BUFFER_TYPE_GEM; + pMMVideoBuf->format = MM_PIXEL_FORMAT_I420; + pMMVideoBuf->plane_num = 3; + pMMVideoBuf->width[0] = pDecOut->hImg.width; + pMMVideoBuf->height[0] = pDecOut->hImg.height; + pMMVideoBuf->stride_width[0] = GST_ROUND_UP_32 (pDecOut->hImg.stride[0]); + pMMVideoBuf->stride_width[1] = + GST_ROUND_UP_16 (pMMVideoBuf->stride_width[0] >> 1); + pMMVideoBuf->stride_width[2] = pMMVideoBuf->stride_width[1]; + pMMVideoBuf->stride_height[0] = GST_ROUND_UP_16 (pDecOut->hImg.height); + pMMVideoBuf->stride_height[1] = GST_ROUND_UP_16 (pDecOut->hImg.height >> 1); + pMMVideoBuf->stride_height[2] = pMMVideoBuf->stride_height[1]; + pMMVideoBuf->size[0] = pDecOut->hImg.size[0]; + pMMVideoBuf->data[0] = pDecOut->hImg.pBuffer[0]; + pMMVideoBuf->handle_num = 1; + pMMVideoBuf->handle.gem[0] = pDecOut->hImg.flink[0]; + pMMVideoBuf->buffer_index = pDecOut->dispIdx; + } else if (3 == pDecOut->hImg.planes) { + pMMVideoBuf->type = MM_VIDEO_BUFFER_TYPE_GEM; + pMMVideoBuf->format = MM_PIXEL_FORMAT_I420; + pMMVideoBuf->plane_num = 3; + pMMVideoBuf->width[0] = pDecOut->hImg.width; + pMMVideoBuf->height[0] = pDecOut->hImg.height; + pMMVideoBuf->stride_width[0] = pDecOut->hImg.stride[0]; + pMMVideoBuf->stride_width[1] = pDecOut->hImg.stride[1]; + pMMVideoBuf->stride_width[2] = pDecOut->hImg.stride[2]; + pMMVideoBuf->size[0] = pDecOut->hImg.size[0]; + pMMVideoBuf->size[1] = pDecOut->hImg.size[1]; + pMMVideoBuf->size[2] = pDecOut->hImg.size[2]; + pMMVideoBuf->data[0] = pDecOut->hImg.pBuffer[0]; + pMMVideoBuf->data[1] = pDecOut->hImg.pBuffer[1]; + pMMVideoBuf->data[2] = pDecOut->hImg.pBuffer[2]; + pMMVideoBuf->handle_num = 3; + pMMVideoBuf->handle.gem[0] = pDecOut->hImg.flink[0]; + pMMVideoBuf->handle.gem[1] = pDecOut->hImg.flink[1]; + pMMVideoBuf->handle.gem[2] = pDecOut->hImg.flink[2]; + pMMVideoBuf->buffer_index = pDecOut->dispIdx; + } + + pMeta = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY, + pMMVideoBuf, + sizeof (MMVideoBuffer), 0, sizeof (MMVideoBuffer), pMMVideoBuf, g_free); + + return pMeta; +} + +static gboolean +plugin_init (GstPlugin * plugin) +{ + gboolean ret; + + FUNC_IN (); + + /* FIXME Remember to set the rank if it's an element that is meant + to be autoplugged by decodebin. */ + ret = gst_element_register (plugin, "nxvideodec", GST_RANK_NONE, + GST_TYPE_NXVIDEODEC); + FUNC_OUT (); + + return ret; +} + +#ifndef VERSION +#define VERSION "0.1.0" +#endif +#ifndef PACKAGE +#define PACKAGE "S5P6818 GStreamer PlugIn" +#endif +#ifndef PACKAGE_NAME +#define PACKAGE_NAME "S5P6818 GStreamer PlugIn" +#endif +#ifndef GST_PACKAGE_ORIGIN +#define GST_PACKAGE_ORIGIN "http://www.nexell.co.kr" +#endif + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + nxvideodec, + "Nexell H/W Video Decoder for S5P6818", + plugin_init, VERSION, "LGPL", PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/src/gstnxvideodec.h b/src/gstnxvideodec.h new file mode 100644 index 0000000..c1e50de --- /dev/null +++ b/src/gstnxvideodec.h @@ -0,0 +1,105 @@ +/* + * GStreamer + * Copyright (C) 2005 Thomas Vander Stichele + * Copyright (C) 2005 Ronald S. Bultje + * Copyright (C) 2016 ray <> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_NXVIDEODEC_H__ +#define __GST_NXVIDEODEC_H__ + +#include +#include +#include + +/* Debug Flags */ +#define DBG_FUNCTION 0 + +#if DBG_FUNCTION +#define FUNC_IN() g_print("%s() In\n", __func__) +#define FUNC_OUT() g_print("%s() Out\n", __func__) +#else +#define FUNC_IN() do{}while(0) +#define FUNC_OUT() do{}while(0) +#endif // DBG_FUNCTION + +G_BEGIN_DECLS +#define GST_TYPE_NXVIDEODEC (gst_nxvideodec_get_type()) +#define GST_NXVIDEODEC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_NXVIDEODEC,GstNxVideoDec)) +#define GST_NXVIDEODEC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_NXVIDEODEC,GstNxVideoDecClass)) +#define GST_IS_NXVIDEODEC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_NXVIDEODEC)) +#define GST_IS_NXVIDEODEC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_NXVIDEODEC)) +#define USE_NATIVE_DRM_BUFFER +typedef struct _GstNxVideoDec GstNxVideoDec; +typedef struct _GstNxVideoDecClass GstNxVideoDecClass; +typedef struct _GstNxDecOutBuffer GstNxDecOutBuffer; + +#include +#include "decoder.h" + +struct _GstNxDecOutBuffer +{ + GstBuffer *pGstBuffer; + gint v4l2BufferIdx; + GstNxVideoDec *pNxVideoDec; +}; + +struct _GstNxVideoDec +{ + GstVideoDecoder base_nxvideodec; + NX_VIDEO_DEC_STRUCT *pNxVideoDecHandle; + gint bufferType; + // video state + GstVideoCodecState *pInputState; + gint isState; + pthread_mutex_t mutex; +}; + +struct _GstNxVideoDecClass +{ + GstVideoDecoderClass base_nxvideodec_class; + GstPadTemplate *pSinktempl; +}; + +GType gst_nxvideodec_get_type (void); + +G_END_DECLS +#endif // __GST_NXVIDEODEC_H__