From: johnny14 Date: Tue, 5 Sep 2017 05:32:00 +0000 (+0900) Subject: initial import X-Git-Tag: accepted/tizen/4.0/unified/20171123.065508~6 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=afc1d7dfc7fe09682481247a18d40bd52eb4bb8b;p=platform%2Fadaptation%2Fnexell%2Fnx-video-api.git initial import this package for nexell hardware codec Change-Id: I33059b8e7ff3eaae5d425c8a07e2d24a5c72f902 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/Makefile.cross b/Makefile.cross new file mode 100644 index 0000000..974c7fa --- /dev/null +++ b/Makefile.cross @@ -0,0 +1,80 @@ +################################################################################ +# +# libnx_video_api.so +# +include ./buildcfg.mk + +# Directory Path +INC_PATH := ../sysroot/include +LIB_PATH := ../sysroot/lib + +# Target Information +LIBNAME := libnx_video_api +TARGET := $(LIBNAME).so + +# Sources +COBJS := \ + ./src/nx_video_alloc.o \ + ./src/nx_video_enc.o \ + ./src/nx_video_dec.o +CPPOBJS := +OBJS := $(COBJS) $(CPPOBJS) + +# Add Include Path +INCLUDE += -I./ -I./src -I./src/include -I$(INC_PATH) + +# Add Dependent Libraries +LIBRARY += -L$(LIB_PATH) + +# Compile Options +CFLAGS += -fPIC + +# Build +all: $(TARGET) + +$(TARGET): depend $(OBJS) + $(quiet)$(CC) $(LDFLAGS) -shared -Wl,-soname,$(TARGET) -o $@ $(OBJS) $(LIBRARY) + +install: + @echo "$(ColorMagenta)[[[ Intall $(LIBNAME) ]]]$(ColorEnd)" + install -m 755 -d $(LIB_PATH) + install -m 755 -d $(INC_PATH) + install -m 644 $(TARGET) $(LIB_PATH) + install -m 644 ./src/include/linux/videodev2_nxp_media.h $(INC_PATH) + install -m 644 ./src/nx_video_alloc.h $(INC_PATH) + install -m 644 ./src/nx_video_api.h $(INC_PATH) + +clean: + @echo "$(ColorMagenta)[[[ Clean $(LIBNAME) ]]]$(ColorEnd)" + rm -f $(COBJS) $(CPPOBJS) $(TARGET) $(LIBNAME).a .depend + +distclean: + @echo "$(ColorMagenta)[[[ Distclean $(LIBNAME) ]]]$(ColorEnd)" + rm -f $(COBJS) $(CPPOBJS) $(TARGET) .depend + rm -f $(LIB_PATH)/$(TARGET) + rm -f $(INC_PATH)/videodev2_nxp_media.h + rm -f $(INC_PATH)/nx_video_alloc.h + rm -f $(INC_PATH)/nx_video_api.h + +update: + @cmp -s \ + ../linux-artik7/include/uapi/linux/videodev2_nxp_media.h \ + ./src/include/linux/videodev2_nxp_media.h; \ + RETVAL=$$?; \ + if [ $$RETVAL -ne 0 ]; then \ + echo "$(ColorMagenta)[[[ Update Private Header ]]]$(ColorEnd)"; \ + cp -a \ + ../linux-artik7/include/uapi/linux/videodev2_nxp_media.h \ + ./src/include/linux; \ + fi + +# Dependency +ifeq (.depend,$(wildcard .depend)) +include .depend +endif + +SRCS := $(COBJS:.o=.c) $(CPPOBJS:.o=.cpp) +INCS := $(INCLUDE) +depend dep: + @echo "$(ColorMagenta)[[[ Build $(LIBNAME) ]]]$(ColorEnd)" + $(quiet)$(CC) -M $(CFLAGS) $(INCS) $(SRCS) > .depend diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..c896097 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,14 @@ +#! /bin/sh + +srcdir=`dirname "$0"` +test -z "$srcdir" && srcdir=. + +ORIGDIR=`pwd` +cd "$srcdir" + +autoreconf --force --verbose --install || exit 1 +cd "$ORIGDIR" || exit $? + +if test -z "$NOCONFIGURE"; then + "$srcdir"/configure "$@" +fi diff --git a/buildcfg.mk b/buildcfg.mk new file mode 100644 index 0000000..6513dff --- /dev/null +++ b/buildcfg.mk @@ -0,0 +1,89 @@ +######################################################################### +# Embedded Linux Build Enviornment: +# +######################################################################### +OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR)) + +ARCHNAME := S5P6818 +CROSS_COMPILE ?= aarch64-linux-gnu- + +ifneq ($(verbose),1) + quiet := @ +endif + +INTERACTIVE := $(shell [ -t 0 ] && echo 1) +ifdef INTERACTIVE +# Light Color + ColorRed=\033[0;91m + ColorGreen=\033[0;92m + ColorYellow=\033[0;93m + ColorBlue=\033[0;93m + ColorMagenta=\033[0;95m + ColorCyan=\033[0;96m + ColorEnd=\033[0m +# Dark Color + # ColorRed=\033[0;31m + # ColorGreen=\033[0;32m + # ColorYellow=\033[0;33m + # ColorBlue=\033[0;33m + # ColorMagenta=\033[0;35m + # ColorCyan=\033[0;36m + # ColorEnd=\033[0m +else + ColorRed= + ColorGreen= + ColorYellow= + ColorBlue= + ColorMagenta= + ColorCyan= + ColorEnd= +endif + +######################################################################### +# Toolchain. +######################################################################### +CROSS := $(CROSS_COMPILE) +CC := $(CROSS)gcc +CPP := $(CROSS)g++ +AR := $(CROSS)ar +AS := $(CROSS)as +LD := $(CROSS)ld +NM := $(CROSS)nm +RANLIB := $(CROSS)ranlib +OBJCOPY := $(CROSS)objcopy +STRIP := $(CROSS)strip + +######################################################################### +# Library & Header macro +######################################################################### +INCLUDE := + +######################################################################### +# Build Options +######################################################################### +OPTS := -Wall -O2 -Wextra -Wcast-align -Wno-unused-parameter -Wshadow -Wwrite-strings -Wcast-qual -fno-strict-aliasing -fstrict-overflow -fsigned-char -fno-omit-frame-pointer -fno-optimize-sibling-calls +COPTS := $(OPTS) +CPPOPTS := $(OPTS) -Wnon-virtual-dtor + +CFLAGS := $(COPTS) +CPPFLAGS := $(CPPOPTS) +AFLAGS := + +ARFLAGS := crv +LDFLAGS := +LIBRARY := + +######################################################################### +# Generic Rules +######################################################################### +%.o: %.c + @echo "Compiling : $(CC) $(ColorCyan)$(notdir $<)$(ColorEnd)" + $(quiet)$(CC) $(CFLAGS) $(INCLUDE) -c -o $@ $< + +%.o: %.s + @echo "Compiling : $(AS) $(ColorCyan)$(notdir $<)$(ColorEnd)" + $(quiet)$(AS) $(AFLAGS) $(INCLUDE) -c -o $@ $< + +%.o: %.cpp + @echo "Compiling : $(CPP) $(ColorCyan)$(notdir $<)$(ColorEnd)" + $(quiet)$(CPP) $(CPPFLAGS) $(INCLUDE) -c -o $@ $< diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..a953fe2 --- /dev/null +++ b/configure.ac @@ -0,0 +1,28 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ([2.69]) +AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS]) +AC_CONFIG_SRCDIR([Makefile.am]) +AC_CONFIG_HEADERS([config.h]) + +AM_INIT_AUTOMAKE([1.10 foreign dist-bzip2]) + +# Checks for programs. +AC_PROG_CXX +AC_PROG_CC + +# Checks for libraries. + +# Checks for header files. + +# Initialize libtool +LT_PREREQ([2.2]) +LT_INIT([disable-static]) + +# Checks for typedefs, structures, and compiler characteristics. + +# Checks for library functions. + +AC_CONFIG_FILES([Makefile src/Makefile]) +AC_OUTPUT diff --git a/packaging/nx-video-api.spec b/packaging/nx-video-api.spec new file mode 100644 index 0000000..a5df13e --- /dev/null +++ b/packaging/nx-video-api.spec @@ -0,0 +1,51 @@ +Name: nx-video-api +Version: 1.0.2 +Release: 1 +License: LGPLv2+ +Summary: Nexell video APIs +Group: Development/Libraries +Source: %{name}-%{version}.tar.gz + +BuildRequires: pkgconfig automake autoconf libtool +BuildRequires: pkgconfig(libdrm) + +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description +Nexell video APIs + +%package devel +Summary: Nexell video API development +Group: Development/Libraries +License: Apache 2.0 +Requires: %{name} = %{version}-%{release} + +%description devel +Nexell scaler (devel) + +%prep +%setup -q + +%build +export CFLAGS="-I/usr/include/libdrm" +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}/libnx_video_api.so +%{_libdir}/libnx_video_api.so.* +%license LICENSE.LGPLv2+ + +%files devel +%{_includedir}/* +%license LICENSE.LGPLv2+ diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..55bf7b3 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,20 @@ +AM_CFLAGS = \ + $(WARN_CFLAGS) \ + -I./include \ + -I${includedir} + +libnx_video_api_la_LTLIBRARIES = libnx_video_api.la +libnx_video_api_ladir = ${libdir} +libnx_video_api_la_LDFLAGS = -L${libdir} -ldrm + +libnx_video_api_la_SOURCES = \ + nx_video_alloc.c \ + nx_video_enc.c \ + nx_video_dec.c + +libnx_video_apiincludedir = ${includedir} +libnx_video_apiinclude_HEADERS = \ + include/linux/videodev2_nxp_media.h \ + nx_video_alloc.h \ + nx_video_api.h \ + mm_types.h diff --git a/src/include/linux/videodev2_nxp_media.h b/src/include/linux/videodev2_nxp_media.h new file mode 100644 index 0000000..672f720 --- /dev/null +++ b/src/include/linux/videodev2_nxp_media.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2016 Nexell Co., Ltd. + * Author: Seonghee, Kim + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _VIDEODEV2_NXP_MEDIA_H +#define _VIDEODEV2_NXP_MEDIA_H + +/* + * F O R M A T S + */ + + +/* compressed formats */ +#define V4L2_PIX_FMT_DIV3 v4l2_fourcc('D', 'I', 'V', '3') +#define V4L2_PIX_FMT_DIV4 v4l2_fourcc('D', 'I', 'V', '4') +#define V4L2_PIX_FMT_DIV5 v4l2_fourcc('D', 'I', 'V', '5') +#define V4L2_PIX_FMT_DIV6 v4l2_fourcc('D', 'I', 'V', '6') +#define V4L2_PIX_FMT_DIVX v4l2_fourcc('D', 'I', 'V', 'X') +#define V4L2_PIX_FMT_RV8 v4l2_fourcc('R', 'V', '3', '0') +#define V4L2_PIX_FMT_RV9 v4l2_fourcc('R', 'V', '4', '0') +#define V4L2_PIX_FMT_WMV9 v4l2_fourcc('W', 'M', 'V', '3') +#define V4L2_PIX_FMT_WVC1 v4l2_fourcc('W', 'V', 'C', '1') +#define V4L2_PIX_FMT_FLV1 v4l2_fourcc('F', 'L', 'V', '1') +#define V4L2_PIX_FMT_THEORA v4l2_fourcc('T', 'H', 'E', 'O') + +/* two non contiguous planes - one Y, one Cr + Cb interleaved */ +/* 24 Y/CbCr 4:4:4 */ +#define V4L2_PIX_FMT_NV24M v4l2_fourcc('N', 'M', '2', '4') +/* 24 Y/CrCb 4:4:4 */ +#define V4L2_PIX_FMT_NV42M v4l2_fourcc('N', 'M', '4', '2') + +/* three non contiguous planes - Y, Cb, Cr */ +/* 16 YUV422 planar */ +#define V4L2_PIX_FMT_YUV422M v4l2_fourcc('Y', 'M', '1', '6') +/* 24 YUV444 planar */ +#define V4L2_PIX_FMT_YUV444M v4l2_fourcc('Y', 'M', '2', '4') + + + +/* + * C O N T R O L S + */ + + +/* Video Codec */ +#define V4L2_CID_NXP_VPU_BASE (V4L2_CTRL_CLASS_MPEG | 0x3000) + +#define V4L2_CID_MPEG_VIDEO_FPS_NUM (V4L2_CID_NXP_VPU_BASE + 0x1) +#define V4L2_CID_MPEG_VIDEO_FPS_DEN (V4L2_CID_NXP_VPU_BASE + 0x2) +#define V4L2_CID_MPEG_VIDEO_SEARCH_RANGE (V4L2_CID_NXP_VPU_BASE + 0x4) +#define V4L2_CID_MPEG_VIDEO_H264_AUD_INSERT (V4L2_CID_NXP_VPU_BASE + 0x5) +#define V4L2_CID_MPEG_VIDEO_RC_DELAY (V4L2_CID_NXP_VPU_BASE + 0x6) +#define V4L2_CID_MPEG_VIDEO_RC_GAMMA_FACTOR (V4L2_CID_NXP_VPU_BASE + 0x7) +#define V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE (V4L2_CID_NXP_VPU_BASE + 0x8) +#define V4L2_CID_MPEG_VIDEO_FORCE_I_FRAME (V4L2_CID_NXP_VPU_BASE + 0x9) +#define V4L2_CID_MPEG_VIDEO_FORCE_SKIP_FRAME (V4L2_CID_NXP_VPU_BASE + 0xA) + +#define V4L2_CID_MPEG_VIDEO_H263_PROFILE (V4L2_CID_NXP_VPU_BASE + 0xB) +enum v4l2_mpeg_video_h263_profile +{ + V4L2_MPEG_VIDEO_H263_PROFILE_P0 = 0, + V4L2_MPEG_VIDEO_H263_PROFILE_P3 = 1, +}; + +#define V4L2_CID_MPEG_VIDEO_THUMBNAIL_MODE (V4L2_CID_NXP_VPU_BASE + 0xC) + +#endif diff --git a/src/mm_types.h b/src/mm_types.h new file mode 100644 index 0000000..02323a5 --- /dev/null +++ b/src/mm_types.h @@ -0,0 +1,588 @@ +/* + * libmm-common + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Jonghyuk Choi + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/** + * This file declares common data structure of multimedia framework. + * + * @file mm_types.h + * @author + * @version 1.0 + * @brief This file declares common data structure of multimedia framework. + */ + +/** + @addtogroup COMMON + @{ + */ + +#ifndef __MM_TYPES_H__ +#define __MM_TYPES_H__ + +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +#define MM_MAX_FILENAME_LEN 256 /**< Maximum length of the file name */ +#define MM_MAX_URL_LEN 2048 /**< Maximum length of the maximum URL */ + +/** + * @def Defines range of logical volume factor. + * It's for logical volume control in player. + * So, don't use this one for media volume. + * range : 0 ~ 1.0 (1.0 = 100%) + */ +#define MM_VOLUME_LEVEL_MIN 0 /**< Minimum factor of volume */ +#define MM_VOLUME_LEVEL_MAX 1.0 /**< Maximum factor of volume */ + +/** + * Multimedia Framework handle type. + */ + typedef void *MMHandleType; /**< Handle type */ + + +/** + * Enumerations of video capture devices. + */ + enum MMVideoDeviceType + { + MM_VIDEO_DEVICE_NONE = -1, /**< No camera */ + MM_VIDEO_DEVICE_CAMERA0, /**< Primary camera */ + MM_VIDEO_DEVICE_CAMERA1, /**< Secondary camera */ + MM_VIDEO_DEVICE_NUM, /**< Number of video capture devices */ + }; + +/** + * Enumerations of audio capture devices. + */ + enum MMAudioDeviceType + { + MM_AUDIO_DEVICE_MIC, /**< Mic device */ + MM_AUDIO_DEVICE_MODEM, /**< Modem */ + MM_AUDIO_DEVICE_RADIO, /**< Radio */ + MM_AUDIO_DEVICE_NUM, /**< Number of audio capture devices */ + }; + +/** + * Enumerations of display surfaces. + */ + typedef enum + { + MM_DISPLAY_SURFACE_OVERLAY, /**< Overlay surface - default */ + MM_DISPLAY_SURFACE_EVAS, /**< Evas object surface */ + MM_DISPLAY_SURFACE_GL, /**< GL surface */ + MM_DISPLAY_SURFACE_NULL, /**< This just disposes of buffers */ + MM_DISPLAY_SURFACE_REMOTE, /**< Daemon client surface */ + MM_DISPLAY_SURFACE_NUM, /**< number of enum */ + } MMDisplaySurfaceType; + +/** + * Enumerations of display modes. + */ + enum MMDisplayModeType + { + MM_DISPLAY_MODE_DEFAULT, /**< default - primary display(UI+Video) + secondary display(UI+Video) if available */ + MM_DISPLAY_MODE_PRI_VIDEO_ON_AND_SEC_VIDEO_FULL_SCREEN, /**< primary display(UI+Video) + secondary display(Video Full Screen) if available */ + MM_DISPLAY_MODE_PRI_VIDEO_OFF_AND_SEC_VIDEO_FULL_SCREEN, /**< primary display(UI only) + secondary display(Video Full Screen) if available */ + MM_DISPLAY_MODE_NUM, /**< number of enum */ + }; + +/** + * Enumerations of display devices. + */ + enum MMDisplayDeviceType + { + MM_DISPLAY_DEVICE_MAINLCD, /**< Main LCD - default */ + MM_DISPLAY_DEVICE_SUBLCD, /**< Sub LCD */ + MM_DISPLAY_DEVICE_TVOUT, /**< TV out */ + MM_DISPLAY_DEVICE_MAINLCD_AND_SUBLCD, /**< Main LCD and Sub LCD */ + MM_DISPLAY_DEVICE_MAINLCD_AND_TVOUT, /**< Main LCD and TV */ + MM_DISPLAY_DEVICE_NUM, /**< number of enum */ + }; + +/** + * Enumerations of display scales. + */ + enum MMDisplayScaleType + { + MM_DISPLAY_SCALE_DEFAULT, /**< Default size */ + MM_DISPLAY_SCALE_DOUBLE_LENGTH, /**< Expand width, height to double size */ + MM_DISPLAY_SCALE_TRIPLE_LENGTH, /**< Expand width, height to triple size */ + MM_DISPLAY_SCALE_NUM, /**< Number of display scales */ + }; + +/** + * Enumerations of storage. + */ + enum MMStorageType + { + MM_STORAGE_INTERNAL, /**< Internal storage */ + MM_STORAGE_EXTERNAL, /**< External storage such as memory card */ + MM_STORAGE_NUM, /**< Number of storage type */ + }; + +/** + * Enumerations for quality. + */ + enum MMQualityType + { + MM_QUALITY_LOW, /**< Low quality */ + MM_QUALITY_HIGH, /**< High quality */ + MM_QUALITY_NUM, /**< Number of quality type */ + }; + +/** + * Enumerations of channel type. + */ + enum MMVolumeChannelType + { + MM_VOLUME_CHANNEL_LEFT, /**< Left channel */ + MM_VOLUME_CHANNEL_RIGHT, /**< Right channel */ + MM_VOLUME_CHANNEL_NUM, /**< Numbers of channels */ + MM_CHANNEL_LEFT = MM_VOLUME_CHANNEL_LEFT, /**< Left channel */ + MM_CHANNEL_RIGHT = MM_VOLUME_CHANNEL_RIGHT, /**< Right channel */ + MM_CHANNEL_NUM = MM_VOLUME_CHANNEL_NUM, /**< Numbers of channels */ + }; + +/* + * Enumerations of SW Volume Table Type. + */ + enum MMSoftwareVolumeTableType + { + MM_SOUND_VOLUME_TYPE_SYSTEM, /**< Volume table for System */ + MM_SOUND_VOLUME_TYPE_NOTIFICATION, /**< Volume table for Notification */ + MM_SOUND_VOLUME_TYPE_ALARM, /**< Volume table for Alarm */ + MM_SOUND_VOLUME_TYPE_RINGTONE, /**< Volume table for Ringtone */ + MM_SOUND_VOLUME_TYPE_MEDIA, /**< Volume table for Multimedia */ + MM_SOUND_VOLUME_TYPE_CALL, /**< Volume table for Call */ + MM_SOUND_VOLUME_TYPE_VOIP, /**< Volume table for VOIP */ + MM_SOUND_VOLUME_TYPE_VOICE, /**< Volume table for VOICE */ + MM_SOUND_VOLUME_TYPE_SVOICE, /**< Volume table for SVOICE */ + MM_SOUND_VOLUME_TYPE_EMERGENCY, /**< Volume table for Emergency (FIXED) */ + MM_SOUND_VOLUME_TYPE_NUM, + MM_SOUND_VOLUME_TABLE_NUM = MM_SOUND_VOLUME_TYPE_NUM, + }; + +/* + * Enumerations of SW Volume Gain. + */ + enum MMSoftwareVolumeGainType + { + MM_SOUND_VOLUME_GAIN_DEFAULT = 0, /**< Volume gain for Default */ + MM_SOUND_VOLUME_GAIN_DIALER = 1 << 8, /**< Volume gain for Dialer */ + MM_SOUND_VOLUME_GAIN_TOUCH = 2 << 8, /**< Volume gain for Touch */ + MM_SOUND_VOLUME_GAIN_AF = 3 << 8, /**< Volume gain for AF */ + MM_SOUND_VOLUME_GAIN_SHUTTER1 = 4 << 8, /**< Volume gain for Shutter1 */ + MM_SOUND_VOLUME_GAIN_SHUTTER2 = 5 << 8, /**< Volume gain for Shutter2 */ + MM_SOUND_VOLUME_GAIN_CAMCORDING = 6 << 8, /**< Volume gain for Camcording */ + MM_SOUND_VOLUME_GAIN_MIDI = 7 << 8, /**< Volume gain for Midi */ + MM_SOUND_VOLUME_GAIN_BOOTING = 8 << 8, /**< Volume gain for Booting */ + MM_SOUND_VOLUME_GAIN_VIDEO = 9 << 8, /**< Volume gain for Video */ + MM_SOUND_VOLUME_GAIN_TTS = 10 << 8, /**< Volume gain for TTS */ + MM_SOUND_VOLUME_GAIN_NUM + }; + +#define MM_SOUND_PRIORITY_ALLOW_MIX (0x80) /**< This define has deprecated */ +/* + * Enumerations of Sound Priority. + */ + enum MMSoundPriorityType + { + MM_SOUND_PRIORITY_0, /**< This enum has deprecated */ + MM_SOUND_PRIORITY_1, /**< This enum has deprecated */ + MM_SOUND_PRIORITY_2, /**< This enum has deprecated */ + MM_SOUND_PRIORITY_3, /**< This enum has deprecated */ + MM_SOUND_PRIORITY_4, /**< This enum has deprecated */ + MM_SOUND_PRIORITY_5, /**< This enum has deprecated */ + MM_SOUND_PRIORITY_NUM, + }; + +/** + * Enumerations of video codec. + */ + enum MMVideoCodecType + { + MM_VIDEO_CODEC_INVALID = -1, /**< Invalid codec type */ + MM_VIDEO_CODEC_NONE, /**< None (will be deprecated) */ + MM_VIDEO_CODEC_H263, /**< H263 codec */ + MM_VIDEO_CODEC_H264, /**< H264 codec */ + MM_VIDEO_CODEC_H26L, /**< H26L codec */ + MM_VIDEO_CODEC_MPEG4, /**< MPEG4 codec */ + MM_VIDEO_CODEC_MPEG1, /**< MPEG1 codec */ + MM_VIDEO_CODEC_WMV, /**< WMV codec */ + MM_VIDEO_CODEC_DIVX, /**< DIVX codec */ + MM_VIDEO_CODEC_XVID, /**< XVID codec */ + MM_VIDEO_CODEC_H261, /**< H261 codec */ + MM_VIDEO_CODEC_H262, /**< H262/MPEG2-part2 codec */ + MM_VIDEO_CODEC_H263V2, /**< H263v2 codec */ + MM_VIDEO_CODEC_H263V3, /**< H263v3 codec */ + MM_VIDEO_CODEC_MJPEG, /**< Motion JPEG Video codec */ + MM_VIDEO_CODEC_MPEG2, /**< MPEG2 codec */ + MM_VIDEO_CODEC_MPEG4_SIMPLE, /**< MPEG4 part-2 Simple profile codec */ + MM_VIDEO_CODEC_MPEG4_ADV_SIMPLE, /**< MPEG4 part-2 Advanced Simple profile codec */ + MM_VIDEO_CODEC_MPEG4_MAIN, /**< MPEG4 part-2 Main profile codec */ + MM_VIDEO_CODEC_MPEG4_CORE, /**< MPEG4 part-2 Core profile codec */ + MM_VIDEO_CODEC_MPEG4_ACE, /**< MPEG4 part-2 Adv Coding Eff profile codec */ + MM_VIDEO_CODEC_MPEG4_ARTS, /**< MPEG4 part-2 Adv RealTime Simple profile codec */ + MM_VIDEO_CODEC_MPEG4_AVC, /**< MPEG4 part-10 (h.264) codec */ + MM_VIDEO_CODEC_REAL, /**< Real video */ + MM_VIDEO_CODEC_VC1, /**< VC-1 video */ + MM_VIDEO_CODEC_AVS, /**< AVS video */ + MM_VIDEO_CODEC_CINEPAK, /**< Cinepak video codec */ + MM_VIDEO_CODEC_INDEO, /**< Indeo video codec */ + MM_VIDEO_CODEC_THEORA, /**< Theora video codec */ + MM_VIDEO_CODEC_FLV, /**< Adobe Flash Video codec */ + MM_VIDEO_CODEC_NUM, /**< Number of video codec type */ + }; + +/** + * Enumerations of audio codec. + */ + enum MMAudioCodecType + { + MM_AUDIO_CODEC_INVALID = -1, /**< Invalid codec type */ + MM_AUDIO_CODEC_AMR, /**< AMR codec */ + MM_AUDIO_CODEC_G723_1, /**< G723.1 codec */ + MM_AUDIO_CODEC_MP3, /**< MP3 codec */ + MM_AUDIO_CODEC_OGG, /**< OGG codec */ + MM_AUDIO_CODEC_AAC, /**< AAC codec */ + MM_AUDIO_CODEC_WMA, /**< WMA codec */ + MM_AUDIO_CODEC_MMF, /**< MMF codec */ + MM_AUDIO_CODEC_ADPCM, /**< ADPCM codec */ + MM_AUDIO_CODEC_WAVE, /**< WAVE codec */ + MM_AUDIO_CODEC_WAVE_NEW, /**< WAVE codec */ + MM_AUDIO_CODEC_MIDI, /**< MIDI codec */ + MM_AUDIO_CODEC_IMELODY, /**< IMELODY codec */ + MM_AUDIO_CODEC_MXMF, + MM_AUDIO_CODEC_MPA, /**< MPEG1-Layer1 codec */ + MM_AUDIO_CODEC_MP2, /**< MPEG1-Layer2 codec */ + MM_AUDIO_CODEC_G711, /**< G711 codec */ + MM_AUDIO_CODEC_G722, /**< G722 wideband speech codec */ + MM_AUDIO_CODEC_G722_1, /**< G722.1 codec */ + MM_AUDIO_CODEC_G722_2, /**< G722.2 (AMR-WB) codec */ + MM_AUDIO_CODEC_G723, /**< G723 wideband speech codec */ + MM_AUDIO_CODEC_G726, /**< G726 (ADPCM) codec */ + MM_AUDIO_CODEC_G728, /**< G728 speech codec */ + MM_AUDIO_CODEC_G729, /**< G729 codec */ + MM_AUDIO_CODEC_G729A, /**< G729a codec */ + MM_AUDIO_CODEC_G729_1, /**< G729.1 codec */ + MM_AUDIO_CODEC_REAL, /**< Real audio */ + MM_AUDIO_CODEC_AAC_LC, /**< AAC-Low complexity codec */ + MM_AUDIO_CODEC_AAC_MAIN, /**< AAC-Main profile codec */ + MM_AUDIO_CODEC_AAC_SRS, /**< AAC-Scalable sample rate codec */ + MM_AUDIO_CODEC_AAC_LTP, /**< AAC-Long term prediction codec */ + MM_AUDIO_CODEC_AAC_HE_V1, /**< AAC-High Efficiency v1 codec */ + MM_AUDIO_CODEC_AAC_HE_V2, /**< AAC-High efficiency v2 codec */ + MM_AUDIO_CODEC_AC3, /**< DolbyDigital codec */ + MM_AUDIO_CODEC_ALAC, /**< Apple Lossless audio codec */ + MM_AUDIO_CODEC_ATRAC, /**< Sony proprietary audio codec */ + MM_AUDIO_CODEC_SPEEX, /**< SPEEX audio codec */ + MM_AUDIO_CODEC_VORBIS, /**< Vorbis audio codec */ + MM_AUDIO_CODEC_AIFF, /**< AIFF codec */ + MM_AUDIO_CODEC_AU, /**< AU codec */ + MM_AUDIO_CODEC_NONE, /**< None (will be deprecated) */ + MM_AUDIO_CODEC_PCM, /**< PCM codec */ + MM_AUDIO_CODEC_ALAW, /**< ALAW codec */ + MM_AUDIO_CODEC_MULAW, /**< MULAW codec */ + MM_AUDIO_CODEC_MS_ADPCM, /**< MS ADPCM codec */ + MM_AUDIO_CODEC_FLAC, /**< Free Lossless audio codec */ + MM_AUDIO_CODEC_NUM, /**< Number of audio codec type */ + }; + +/** + * Enumerations of image codec. + */ + enum MMImageCodecType + { + MM_IMAGE_CODEC_INVALID = -1, /**< Invalid codec type */ + MM_IMAGE_CODEC_JPEG, /**< JPEG codec */ + MM_IMAGE_CODEC_PNG, /**< PNG codec */ + MM_IMAGE_CODEC_BMP, /**< BMP codec */ + MM_IMAGE_CODEC_WBMP, /**< WBMP codec */ + MM_IMAGE_CODEC_TIFF, /**< TIFF codec */ + MM_IMAGE_CODEC_PCX, /**< PCX codec */ + MM_IMAGE_CODEC_GIF, /**< GIF codec */ + MM_IMAGE_CODEC_ICO, /**< ICO codec */ + MM_IMAGE_CODEC_RAS, /**< RAS codec */ + MM_IMAGE_CODEC_TGA, /**< TGA codec */ + MM_IMAGE_CODEC_XBM, /**< XBM codec */ + MM_IMAGE_CODEC_XPM, /**< XPM codec */ + MM_IMAGE_CODEC_SRW, /**< SRW (Samsung standard RAW) */ + MM_IMAGE_CODEC_JPEG_SRW, /**< JPEG + SRW */ + MM_IMAGE_CODEC_NUM, /**< Number of image codecs */ + }; + +/** + * Enumerations of file container format. + */ + enum MMFileFormatType + { + MM_FILE_FORMAT_INVALID = -1, /**< Invalid file format */ + MM_FILE_FORMAT_3GP, /**< 3GP file format */ + MM_FILE_FORMAT_ASF, /**< Advanced Systems File file format */ + MM_FILE_FORMAT_AVI, /**< Audio Video Interleaved file format */ + MM_FILE_FORMAT_MATROSKA, /**< MATROSAK file format */ + MM_FILE_FORMAT_MP4, /**< MP4 file format */ + MM_FILE_FORMAT_OGG, /**< OGG file format */ + MM_FILE_FORMAT_NUT, /**< NUT file format */ + MM_FILE_FORMAT_QT, /**< MOV file format */ + MM_FILE_FORMAT_REAL, /**< RealMedia file format */ + MM_FILE_FORMAT_AMR, /**< AMR file format */ + MM_FILE_FORMAT_AAC, /**< AAC file format */ + MM_FILE_FORMAT_MP3, /**< MP3 file format */ + MM_FILE_FORMAT_AIFF, /**< AIFF file format */ + MM_FILE_FORMAT_AU, /**< Audio file format */ + MM_FILE_FORMAT_WAV, /**< WAV file format */ + MM_FILE_FORMAT_MID, /**< MID file format */ + MM_FILE_FORMAT_MMF, /**< MMF file format */ + MM_FILE_FORMAT_DIVX, /**< DivX file format */ + MM_FILE_FORMAT_FLV, /**< Flash video file format */ + MM_FILE_FORMAT_VOB, /**< DVD-Video Object file format */ + MM_FILE_FORMAT_IMELODY, /**< IMelody file format */ + MM_FILE_FORMAT_WMA, /**< WMA file format */ + MM_FILE_FORMAT_WMV, /**< WMV file format */ + MM_FILE_FORMAT_JPG, /**< JPEG file format */ + MM_FILE_FORMAT_FLAC, /**< FLAC file format */ + MM_FILE_FORMAT_M2TS, /**< MPEG2-Transport Stream file format */ + MM_FILE_FORMAT_M2PS, /**< MPEG2-Program Stream file format */ + MM_FILE_FORMAT_M1VIDEO, /**< MPEG1-Video file format */ + MM_FILE_FORMAT_M1AUDIO, /**< MPEG1-Audio file format */ + MM_FILE_FORMAT_NUM, /**< Number of file format type */ + }; + +/** + * Enumerations of display layers. + */ + typedef enum + { + MM_VIDEO_LAYER_PRIMARY, /**< Primary of the video layer */ + MM_VIDEO_LAYER_OVERLAY, /**< Overlay of the video layer */ + MM_VIDEO_LAYER_NUM /**< Number of the video layer */ + } MMVideoLayerType; + +/** + * Enumerations of Pixel formats + */ + typedef enum + { + MM_PIXEL_FORMAT_INVALID = -1, /**< Invalid pixel format */ + MM_PIXEL_FORMAT_NV12, /**< NV12 pixel format */ + MM_PIXEL_FORMAT_NV12T, /**< NV12 Tiled pixel format */ + MM_PIXEL_FORMAT_NV16, /**< NV16 pixel format */ + MM_PIXEL_FORMAT_NV21, /**< NV21 pixel format */ + MM_PIXEL_FORMAT_YUYV, /**< YUYV(YUY2) pixel format */ + MM_PIXEL_FORMAT_UYVY, /**< UYVY pixel format */ + MM_PIXEL_FORMAT_422P, /**< YUV422(Y:U:V) planar pixel format */ + MM_PIXEL_FORMAT_I420, /**< I420 pixel format */ + MM_PIXEL_FORMAT_YV12, /**< YV12 pixel format */ + MM_PIXEL_FORMAT_RGB565, /**< RGB565 pixel format */ + MM_PIXEL_FORMAT_RGB888, /**< RGB888 pixel format */ + MM_PIXEL_FORMAT_RGBA, /**< RGBA pixel format */ + MM_PIXEL_FORMAT_ARGB, /**< ARGB pixel format */ + MM_PIXEL_FORMAT_ENCODED, /**< Encoded pixel format : JPEG */ + MM_PIXEL_FORMAT_ITLV_JPEG_UYVY, /**< FIXME: JPEG+UYVY Interleaved format */ + MM_PIXEL_FORMAT_ENCODED_H264, /**< Encoded pixel format : H.264 */ + MM_PIXEL_FORMAT_NUM /**< Number of the pixel format */ + } MMPixelFormatType; + +/** + * Enumerations of video input rotation type. + */ + typedef enum + { + MM_VIDEO_INPUT_ROTATION_NONE, /**< No rotation of the display */ + MM_VIDEO_INPUT_ROTATION_90, /**< 90 degree rotation */ + MM_VIDEO_INPUT_ROTATION_180, /**< 180 degree rotation */ + MM_VIDEO_INPUT_ROTATION_270, /**< 270 degree rotation */ + MM_VIDEO_INPUT_ROTATION_NUM /**< Number of the rotation */ + } MMVideoInputRotationType; + +/** + * Enumerations of display rotation type. + */ + typedef enum + { + MM_DISPLAY_ROTATION_NONE, /**< No rotation of the display */ + MM_DISPLAY_ROTATION_90, /**< 90 degree rotation */ + MM_DISPLAY_ROTATION_180, /**< 180 degree rotation */ + MM_DISPLAY_ROTATION_270, /**< 270 degree rotation */ + MM_DISPLAY_ROTATION_NUM /**< Number of the rotation */ + } MMDisplayRotationType; + +/** + * Enumerations of flip type. + */ + typedef enum + { + MM_FLIP_NONE, /**< No Flip */ + MM_FLIP_HORIZONTAL, /**< Horizontal flip */ + MM_FLIP_VERTICAL, /**< Vertical flip */ + MM_FLIP_BOTH, /**< Horizontal and Vertical flip */ + MM_FLIP_NUM /**< Number of flip */ + } MMFlipType; + +/** + * Enumerations of streaming type. + */ + typedef enum + { + STREAMING_SERVICE_VOD, /**< Streaming is vod */ + STREAMING_SERVICE_LIVE, /**< Streaming is live stream */ + STREAMING_SERVICE_NONE, /**< Not an streaming */ + STREAMING_SERVICE_NUM, /**< Number of the streaming type */ + } MMStreamingType; + +/** + * Resolution + */ + typedef struct + { + int width; /**< width */ + int height; /**< height */ + } MMResolutionType; + +/** + * Type definition of rectangle. + * This will be deprecated. + */ + typedef struct + { + unsigned int x; /**< Start x point */ + unsigned int y; /**< Start y point */ + unsigned int width; /**< width */ + unsigned int height; /**< Height */ + } MMRectType; + +#define BT_ADDR_LEN 18 /**< Length of BT address */ +/** + * bluetooth information. + */ + typedef struct + { + int mode; /**< BT enable/disable */ + char addr[BT_ADDR_LEN]; /**< BT device address */ + } MMBluetoothType; + + +/** + * Enumerations of bluetooth mode + */ + enum MMBluetoothMode + { + MM_BLUETOOTH_DISABLE = 0, + MM_BLUETOOTH_ENABLE + }; + +/* + * Enumerations of sound path policy + */ + enum MMAudioRoutePolicy + { + MM_AUDIOROUTE_USE_EXTERNAL_SETTING = -1, + MM_AUDIOROUTE_PLAYBACK_NORMAL, + MM_AUDIOROUTE_PLAYBACK_ALERT, + MM_AUDIOROUTE_PLAYBACK_HEADSET_ONLY, + MM_AUDIOROUTE_CAPTURE_NORMAL = 0, + MM_AUDIOROUTE_CAPTURE_MAINMIC_ONLY, + MM_AUDIOROUTE_CAPTURE_STEREOMIC_ONLY, + }; + +/* + * Enumerations of display geometry method + */ + typedef enum + { + MM_DISPLAY_METHOD_LETTER_BOX = 0, + MM_DISPLAY_METHOD_ORIGIN_SIZE, + MM_DISPLAY_METHOD_FULL_SCREEN, + MM_DISPLAY_METHOD_CROPPED_FULL, + MM_DISPLAY_METHOD_ORIGIN_OR_LETTER, + MM_DISPLAY_METHOD_CUSTOM_ROI, + } MMDisplayGeometryMethod; + +/* + * Enumerations of ROI mode of display geometry method + */ + typedef enum + { + MM_DISPLAY_METHOD_CUSTOM_ROI_FULL_SCREEN = 0, + MM_DISPLAY_METHOD_CUSTOM_ROI_LETER_BOX + } MMDisplayGeometryMethodRoiMode; + + +#define MM_VIDEO_BUFFER_PLANE_MAX 4 /**< Max num of video buffer plane */ +/* + * Enumerations of multimedia video buffer type + */ + typedef enum + { + MM_VIDEO_BUFFER_TYPE_PHYSICAL_ADDRESS = 0, + MM_VIDEO_BUFFER_TYPE_DMABUF_FD, + MM_VIDEO_BUFFER_TYPE_TBM_BO, + MM_VIDEO_BUFFER_TYPE_GEM, + } MMVideoBufferType; + + typedef struct + { + void *paddr[MM_VIDEO_BUFFER_PLANE_MAX]; /**< physical address */ + int dmabuf_fd[MM_VIDEO_BUFFER_PLANE_MAX]; /**< dmabuf fd */ + void *bo[MM_VIDEO_BUFFER_PLANE_MAX]; /**< TBM bo */ + int gem[MM_VIDEO_BUFFER_PLANE_MAX]; /**< GEM handle */ + } MMVideoBufferHandle; + +/* + * Type definition of multimedia video buffer + */ + typedef struct + { + MMVideoBufferType type; /**< buffer type + - The field of handle that type indicates should be filled, + and other fields of handle are optional. */ + MMPixelFormatType format; /**< buffer type */ + int plane_num; /**< number of planes */ + int width[MM_VIDEO_BUFFER_PLANE_MAX]; /**< width of buffer */ + int height[MM_VIDEO_BUFFER_PLANE_MAX]; /**< height of buffer */ + int stride_width[MM_VIDEO_BUFFER_PLANE_MAX]; /**< stride width of buffer */ + int stride_height[MM_VIDEO_BUFFER_PLANE_MAX]; /**< stride height of buffer */ + int size[MM_VIDEO_BUFFER_PLANE_MAX]; /**< size of planes */ + void *data[MM_VIDEO_BUFFER_PLANE_MAX]; /**< data pointer(user address) of planes */ + int handle_num; /**< number of buffer handle */ + int handle_size[MM_VIDEO_BUFFER_PLANE_MAX]; /**< size of handles */ + MMVideoBufferHandle handle; /**< handle of buffer */ + int is_secured; /**< secured buffer flag. ex) TrustZone memory, user can not access it. */ + int flush_request; /**< flush request flag + - If this flag is TRUE, sink element will make copy of last buffer, + and it will return all buffers from src element. + Then, src element can restart without changing pipeline state. */ + int buffer_index; + } MMVideoBuffer; + + +#ifdef __cplusplus +} +#endif + + +#endif /* __MM_TYPES_H__ */ diff --git a/src/nx_video_alloc.c b/src/nx_video_alloc.c new file mode 100644 index 0000000..9bf84f4 --- /dev/null +++ b/src/nx_video_alloc.c @@ -0,0 +1,507 @@ +/* + * Copyright (C) 2016 Nexell Co., Ltd. + * Author: SeongO, Park + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include // PROT_READ/PROT_WRITE/MAP_SHARED/mmap/munmap + +#include +#include + +#include +#include +#include + +#define DRM_DEVICE_NAME "/dev/dri/card0" + +#define DRM_IOCTL_NR(n) _IOC_NR(n) +#define DRM_IOC_VOID _IOC_NONE +#define DRM_IOC_READ _IOC_READ +#define DRM_IOC_WRITE _IOC_WRITE +#define DRM_IOC_READWRITE _IOC_READ|_IOC_WRITE +#define DRM_IOC(dir, group, nr, size) _IOC(dir, group, nr, size) + +static int +drm_ioctl (int32_t drm_fd, uint32_t request, void *arg) +{ + int ret; + + do { + ret = ioctl (drm_fd, request, arg); + } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); + return ret; +} + +static int +drm_command_write_read (int fd, uint32_t command_index, + void *data, uint32_t size) +{ + uint32_t request; + + request = DRM_IOC (DRM_IOC_READ | DRM_IOC_WRITE, DRM_IOCTL_BASE, + DRM_COMMAND_BASE + command_index, size); + if (drm_ioctl (fd, request, data)) + return -errno; + return 0; +} + +/** + * return gem_fd + */ +static int +alloc_gem (int drm_fd, int size, int flags) +{ + struct nx_drm_gem_create arg = { 0, }; + int ret; + + arg.size = (uint32_t) size; + arg.flags = flags; + + ret = drm_command_write_read (drm_fd, DRM_NX_GEM_CREATE, &arg, sizeof (arg)); + if (ret) { + perror ("drm_command_write_read\n"); + return ret; + } + //printf("[DRM ALLOC] gem %d, size %d, flags 0x%x\n", arg.handle, size, flags); + + return arg.handle; +} + +static void +free_gem (int drm_fd, int gem) +{ + struct drm_gem_close arg = { 0, }; + + arg.handle = gem; + drm_ioctl (drm_fd, DRM_IOCTL_GEM_CLOSE, &arg); +} + +/** + * return dmabuf fd + */ +static int +gem_to_dmafd (int drm_fd, int gem_fd) +{ + int ret; + struct drm_prime_handle arg = { 0, }; + + arg.handle = gem_fd; + ret = drm_ioctl (drm_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &arg); + if (0 != ret) { + return -1; + } + return arg.fd; +} + +static uint32_t +get_flink_name (int fd, int gem) +{ + struct drm_gem_flink arg = { 0, }; + + arg.handle = gem; + if (drm_ioctl (fd, DRM_IOCTL_GEM_FLINK, &arg)) { + printf ("fail : get flink from gem:%d (DRM_IOCTL_GEM_FLINK)\n", gem); + return 0; + } + return arg.name; +} + +static uint32_t +gem_from_flink (int fd, uint32_t flink_name) +{ + struct drm_gem_open arg = { 0, }; + /* struct nx_drm_gem_info info = { 0, }; */ + + arg.name = flink_name; + if (drm_ioctl (fd, DRM_IOCTL_GEM_OPEN, &arg)) { + printf ("fail : cannot open gem name=%d\n", flink_name); + return -EINVAL; + } + return arg.handle; +} + + +// +// Nexell Private Video Memory Allocator for DRM +// + +#ifndef ALIGN +#define ALIGN(X,N) ( (X+N-1) & (~(N-1)) ) +#endif + +#define ALIGNED16(X) ALIGN(X,16) + + +// Nexell Private Memory Allocator +NX_MEMORY_INFO * +NX_AllocateMemory (int size, int align) +{ + int gemFd = -1; + int dmaFd = -1; + int32_t flags = 0; + NX_MEMORY_INFO *pMem; + + int drmFd = open (DRM_DEVICE_NAME, O_RDWR); + if (drmFd < 0) + return NULL; + + drmDropMaster (drmFd); + + gemFd = alloc_gem (drmFd, size, flags); + if (gemFd < 0) + goto ErrorExit; + + dmaFd = gem_to_dmafd (drmFd, gemFd); + if (dmaFd < 0) + goto ErrorExit; + + pMem = (NX_MEMORY_INFO *) calloc (1, sizeof (NX_MEMORY_INFO)); + pMem->drmFd = drmFd; + pMem->dmaFd = dmaFd; + pMem->gemFd = gemFd; + pMem->flink = get_flink_name (drmFd, gemFd); + pMem->size = size; + pMem->align = align; + return pMem; + +ErrorExit: + if (gemFd > 0) { + free_gem (drmFd, gemFd); + } + if (drmFd > 0) + close (drmFd); + return NULL; +} + +void +NX_FreeMemory (NX_MEMORY_INFO * pMem) +{ + if (pMem) { + if (pMem->pBuffer) { + munmap (pMem->pBuffer, pMem->size); + } + + free_gem (pMem->drmFd, pMem->gemFd); + close (pMem->dmaFd); + close (pMem->drmFd); + free (pMem); + } +} + + +// Video Specific Allocator Wrapper +// +// Suport Format & Planes +// YUV420 Format : +// 1 Plane : I420, NV12 +// 2 Plane : NV12 +// 3 Plane : I420 +// +NX_VID_MEMORY_INFO * +NX_AllocateVideoMemory (int width, int height, int32_t planes, uint32_t format, + int align) +{ + int gemFd[NX_MAX_PLANES] = { 0, }; + int dmaFd[NX_MAX_PLANES] = { 0, }; + int32_t flags = 0, i = 0; + int32_t luStride, cStride; + int32_t luVStride, cVStride; + int32_t stride[NX_MAX_PLANES]; + int32_t size[NX_MAX_PLANES]; + uint32_t flink[NX_MAX_PLANES]; + + NX_VID_MEMORY_INFO *pVidMem; + + int drmFd = open (DRM_DEVICE_NAME, O_RDWR); + if (drmFd < 0) + return NULL; + + drmDropMaster (drmFd); + + // Luma + luStride = ALIGN (width, 32); + luVStride = ALIGN (height, 16); + + // Chroma + switch (format) { + case DRM_FORMAT_YUV420: + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + case V4L2_PIX_FMT_YUV420M: + case V4L2_PIX_FMT_NV12M: + case V4L2_PIX_FMT_NV21M: + cStride = luStride / 2; + cVStride = ALIGN (height / 2, 16); + break; + + case DRM_FORMAT_YUV422: + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: + case V4L2_PIX_FMT_YUV422M: +#if 0 // Disabled by DIGNSYS + case V4L2_PIX_FMT_NV16M: + case V4L2_PIX_FMT_NV61M: +#endif + cStride = luStride / 2; + cVStride = luVStride; + break; + + case DRM_FORMAT_YUV444: + //case DRM_FORMAT_NV24: + //case DRM_FORMAT_NV42: + case V4L2_PIX_FMT_YUV444M: + case V4L2_PIX_FMT_NV24M: + case V4L2_PIX_FMT_NV42M: + cStride = luStride; + cVStride = luVStride; + break; + + case V4L2_PIX_FMT_GREY: + cStride = 0; + cVStride = 0; + break; + default: + printf ("Unknown format type\n"); + goto ErrorExit; + } + + // Decide Memory Size + switch (planes) { + case 1: + size[0] = luStride * luVStride + cStride * cVStride * 2; + stride[0] = luStride; + gemFd[0] = alloc_gem (drmFd, size[0], flags); + if (gemFd[0] < 0) + goto ErrorExit; + dmaFd[0] = gem_to_dmafd (drmFd, gemFd[0]); + if (dmaFd[0] < 0) + goto ErrorExit; + flink[0] = get_flink_name (drmFd, gemFd[0]); + break; + case 2: + // Buffer 1 + size[0] = luStride * luVStride; + stride[0] = luStride; + gemFd[0] = alloc_gem (drmFd, size[0], flags); + if (gemFd[0] < 0) + goto ErrorExit; + dmaFd[0] = gem_to_dmafd (drmFd, gemFd[0]); + if (dmaFd[0] < 0) + goto ErrorExit; + flink[0] = get_flink_name (drmFd, gemFd[0]); + + // Buffer 2 + size[1] = cStride * cVStride * 2; + stride[1] = cStride * 2; + gemFd[1] = alloc_gem (drmFd, size[1], flags); + if (gemFd[1] < 0) + goto ErrorExit; + dmaFd[1] = gem_to_dmafd (drmFd, gemFd[1]); + if (dmaFd[1] < 0) + goto ErrorExit; + flink[1] = get_flink_name (drmFd, gemFd[1]); + break; + case 3: + // Buffer 1 + size[0] = luStride * luVStride; + stride[0] = luStride; + gemFd[0] = alloc_gem (drmFd, size[0], flags); + if (gemFd[0] < 0) + goto ErrorExit; + dmaFd[0] = gem_to_dmafd (drmFd, gemFd[0]); + if (dmaFd[0] < 0) + goto ErrorExit; + flink[0] = get_flink_name (drmFd, gemFd[0]); + + // Buffer 2 + size[1] = cStride * cVStride; + stride[1] = cStride; + gemFd[1] = alloc_gem (drmFd, size[1], flags); + if (gemFd[1] < 0) + goto ErrorExit; + dmaFd[1] = gem_to_dmafd (drmFd, gemFd[1]); + if (dmaFd[1] < 0) + goto ErrorExit; + flink[1] = get_flink_name (drmFd, gemFd[1]); + + // Buffer 3 + size[2] = cStride * cVStride; + stride[2] = cStride; + gemFd[2] = alloc_gem (drmFd, size[2], flags); + if (gemFd[2] < 0) + goto ErrorExit; + dmaFd[2] = gem_to_dmafd (drmFd, gemFd[2]); + if (dmaFd[2] < 0) + goto ErrorExit; + flink[2] = get_flink_name (drmFd, gemFd[2]); + break; + break; + } + + pVidMem = (NX_VID_MEMORY_INFO *) calloc (1, sizeof (NX_VID_MEMORY_INFO)); + pVidMem->width = width; + pVidMem->height = height; + pVidMem->align = align; + pVidMem->planes = planes; + pVidMem->format = format; + pVidMem->drmFd = drmFd; + for (i = 0; i < planes; i++) { + pVidMem->dmaFd[i] = dmaFd[i]; + pVidMem->gemFd[i] = gemFd[i]; + pVidMem->size[i] = size[i]; + pVidMem->stride[i] = stride[i]; + pVidMem->flink[i] = flink[i]; + } + return pVidMem; + +ErrorExit: + for (i = 0; i < planes; i++) { + if (gemFd[i] > 0) { + free_gem (drmFd, gemFd[i]); + } + if (dmaFd[i] > 0) { + close (dmaFd[i]); + } + } + if (drmFd > 0) + close (drmFd); + + return NULL; +} + +void +NX_FreeVideoMemory (NX_VID_MEMORY_INFO * pMem) +{ + int32_t i; + if (pMem) { + for (i = 0; i < pMem->planes; i++) { + if (pMem->pBuffer[i]) { + munmap (pMem->pBuffer[i], pMem->size[i]); + } + free_gem (pMem->drmFd, pMem->gemFd[i]); + close (pMem->dmaFd[i]); + } + close (pMem->drmFd); + free (pMem); + } +} + + +// +// Memory Mapping/Unmapping Memory +// +int +NX_MapMemory (NX_MEMORY_INFO * pMem) +{ + void *pBuf; + if (!pMem) + return -1; + + // Already Mapped + if (pMem->pBuffer) + return -1; + + pBuf = + mmap (0, pMem->size, PROT_READ | PROT_WRITE, MAP_SHARED, pMem->dmaFd, 0); + if (pBuf == MAP_FAILED) { + return -1; + } + pMem->pBuffer = pBuf; + return 0; +} + + +int +NX_UnmapMemory (NX_MEMORY_INFO * pMem) +{ + if (!pMem) + return -1; + + if (!pMem->pBuffer) + return -1; + + if (0 != munmap (pMem->pBuffer, pMem->size)) + return -1; + + pMem->pBuffer = NULL; + return 0; +} + +int +NX_MapVideoMemory (NX_VID_MEMORY_INFO * pMem) +{ + int32_t i; + void *pBuf; + if (!pMem) + return -1; + + // Already Mapped + for (i = 0; i < pMem->planes; i++) { + if (pMem->pBuffer[i]) + return -1; + else { + pBuf = + mmap (0, pMem->size[i], PROT_READ | PROT_WRITE, MAP_SHARED, + pMem->dmaFd[i], 0); + if (pBuf == MAP_FAILED) { + return -1; + } + } + pMem->pBuffer[i] = pBuf; + } + return 0; +} + +int +NX_UnmapVideoMemory (NX_VID_MEMORY_INFO * pMem) +{ + int32_t i; + if (!pMem) + return -1; + for (i = 0; i < pMem->planes; i++) { + if (pMem->pBuffer[i]) { + munmap (pMem->pBuffer[i], pMem->size[i]); + } else + return -1; + } + return 0; +} + +int +NX_GetGEMHandles (int drmFd, NX_VID_MEMORY_INFO * pMem, + uint32_t handles[NX_MAX_PLANES]) +{ + int32_t i; + memset (handles, 0, sizeof (uint32_t) * NX_MAX_PLANES); + + for (i = 0; i < pMem->planes; i++) { + handles[i] = gem_from_flink (drmFd, pMem->flink[i]); + if (0 > (int) handles[i]) { + return -1; + } + } + return 0; +} + +int +NX_GetGemHandle (int drmFd, NX_VID_MEMORY_INFO * pMem, int32_t plane) +{ + if (plane >= NX_MAX_PLANES || plane < 0) + return -1; + + return gem_from_flink (drmFd, pMem->flink[plane]); +} diff --git a/src/nx_video_alloc.h b/src/nx_video_alloc.h new file mode 100644 index 0000000..a612a4b --- /dev/null +++ b/src/nx_video_alloc.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2016 Nexell Co., Ltd. + * Author: SeongO, Park + */ + +#ifndef __NX_VIDEO_ALLOC_H__ +#define __NX_VIDEO_ALLOC_H__ + + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +#define NX_MAX_PLANES 4 + +// +// Nexell Private Memory Type +// + typedef struct + { + int drmFd; // DRM Device Handle + int dmaFd; // DMA Memory Handle + int gemFd; // GEM Handle + uint32_t flink; // flink name + int32_t size; // Allocate Size + int32_t align; // Start Address Align + void *pBuffer; // Virtual Address Pointer + uint32_t reserved; + } NX_MEMORY_INFO, *NX_MEMORY_HANDLE; + + +// +// Nexell Private Video Memory Type +// + typedef struct + { + int32_t width; // Video Image's Width + int32_t height; // Video Image's Height + int32_t align; // Start address align + int32_t planes; // Number of valid planes + uint32_t format; // Pixel Format(N/A) + + int drmFd; // Drm Device Handle + int dmaFd[NX_MAX_PLANES]; // DMA memory Handle + int gemFd[NX_MAX_PLANES]; // GEM Handle + uint32_t flink[NX_MAX_PLANES]; // flink name + int32_t size[NX_MAX_PLANES]; // Each plane's size. + int32_t stride[NX_MAX_PLANES]; // Each plane's stride. + void *pBuffer[NX_MAX_PLANES]; // virtual address. + uint32_t reserved[NX_MAX_PLANES]; // for debugging or future user. + } NX_VID_MEMORY_INFO, *NX_VID_MEMORY_HANDLE; + +// Nexell Private Memory Allocator + NX_MEMORY_INFO *NX_AllocateMemory (int size, int align); + void NX_FreeMemory (NX_MEMORY_INFO * pMem); + +// Video Specific Allocator Wrapper + NX_VID_MEMORY_INFO *NX_AllocateVideoMemory (int width, int height, + int32_t planes, uint32_t format, int align); + void NX_FreeVideoMemory (NX_VID_MEMORY_INFO * pMem); + + int NX_MapMemory (NX_MEMORY_INFO * pMem); + int NX_UnmapMemory (NX_MEMORY_INFO * pMem); + + int NX_MapVideoMemory (NX_VID_MEMORY_INFO * pMem); + int NX_UnmapVideoMemory (NX_VID_MEMORY_INFO * pMem); + + int NX_GetGEMHandles (int drmFd, NX_VID_MEMORY_INFO * pMem, + uint32_t handles[NX_MAX_PLANES]); + int NX_GetGemHandle (int drmFd, NX_VID_MEMORY_INFO * pMem, int32_t plane); + +#ifdef __cplusplus +}; +#endif + +#endif // __NX_VIDEO_ALLOC_H__ diff --git a/src/nx_video_api.h b/src/nx_video_api.h new file mode 100644 index 0000000..2174e4e --- /dev/null +++ b/src/nx_video_api.h @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2016 Nexell Co. All Rights Reserved + * Nexell Co. Proprietary & Confidential + * + * NEXELL INFORMS THAT THIS CODE AND INFORMATION IS PROVIDED "AS IS" BASE + * AND WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS + * FOR A PARTICULAR PURPOSE. + * + * File : nx_video_api.h + * Brief : V4L2 Video En/Decoder + * Author : SungWon Jo (doriya@nexell.co.kr) + * History : 2016.04.25 : Create + */ + +#ifndef __NX_VIDEO_API_H__ +#define __NX_VIDEO_API_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define MAX_FRAME_BUFFER_NUM 32 +#define MAX_IMAGE_WIDTH 1920 +#define MAX_IMAGE_HEIGHT 1088 + + + typedef struct NX_V4L2ENC_INFO *NX_V4L2ENC_HANDLE; + typedef struct NX_V4L2DEC_INFO *NX_V4L2DEC_HANDLE; + + enum + { + PIC_TYPE_I = 0, + PIC_TYPE_P = 1, + PIC_TYPE_B = 2, + PIC_TYPE_VC1_BI = 3, + PIC_TYPE_SKIP = 5, + PIC_TYPE_IDR = 6, +#if 0 + /* TBD */ + PIC_TYPE_VC1_B = 3, + PIC_TYPE_D = 3, /* D picture in mpeg2, and is only composed of DC codfficients */ + PIC_TYPE_S = 3, /* S picture in mpeg4, and is an acronym of Sprite. and used for GMC */ + PIC_TYPE_MP4_P_SKIP_NOT_CODED = 4, /* Not Coded P Picture at mpeg4 packed mode */ +#endif + PIC_TYPE_UNKNOWN = 0xff, + }; + + enum + { + NONE_FIELD = 0, + FIELD_INTERLACED = 1, + TOP_FIELD_FIRST = 2, + BOTTOM_FIELD_FIRST = 3, + }; + + enum + { + DECODED_FRAME = 0, + DISPLAY_FRAME = 1 + }; + + typedef enum + { + VID_CHG_KEYFRAME = (1 << 1), /* Key frame interval */ + VID_CHG_BITRATE = (1 << 2), /* Bit Rate */ + VID_CHG_FRAMERATE = (1 << 3), /* Frame Rate */ + VID_CHG_INTRARF = (1 << 4), /* Intra Refresh */ + } VID_ENC_CHG_PARA_E; + + typedef struct + { + uint32_t dispLeft; /* Specifies the x-coordinate of the upper-left corner of the frame memory */ + uint32_t dispTop; /* Specifies the y-coordinate of the upper-left corner of the frame memory */ + uint32_t dispRight; /* Specifies the x-coordinate of the lower-right corner of the frame memory */ + uint32_t dispBottom; /* Specifies the y-coordinate of the lower-right corner of the frame memory */ + } IMG_DISP_INFO; + + typedef struct tNX_V4L2ENC_PARA + { + int32_t width; /* Width of image */ + int32_t height; /* Height of image */ + int32_t keyFrmInterval; /* Size of key frame interval */ + int32_t fpsNum; /* Frame per second */ + int32_t fpsDen; + + uint32_t profile; + + /* Rate Control Parameters (They are valid only when CBR.) */ + uint32_t bitrate; /* Target bitrate in bits per second */ + int32_t maximumQp; /* Maximum quantization parameter in CBR */ + /* In MPEG-4/H.263 mode, available range is 3 to 31. In H.264 mode, the allowed range is 13 to 51. */ + int32_t disableSkip; /* Disable rate control automatic skip frame */ + int32_t RCDelay; /* Reference decoder initial buffer removal delay in mili-second(ms) */ + /* Valid value is 0 ~ 0x7FFF. */ + /* 0 does not check reference decoder buffer delay constraint. */ + uint32_t rcVbvSize; /* Reference decoder buffer size in bits */ + /* This value is ignored if RCDelay is 0. */ + /* Valid value is 0 ~ 0x7FFFFFFF. */ + /* 0 dose not check Reference decoder buffer size constraint. */ + int32_t gammaFactor; /* A gamma is the smoothing factor in the estimation. A value for gamma is factor * 32768, factor value is selected from the 0 <= factor >= 1. */ + /* If the factor value getting close to 0, Qp will be changed slowly. If the factor value getting close to 1, Qp will be chgnged quickly. */ + /* Default gamma value is 0.75 * 32768. */ + int32_t initialQp; /* Initial quantization parameter */ + + int32_t numIntraRefreshMbs; /* Intra MB refresh number(Cyclic Intra Refresh) */ + /* It must be less than encoded Mbs(width * height / 256) */ + int32_t searchRange; /* search range of motion estimaiton(0 : 128 x 64, 1 : 64 x 32, 2 : 32 x 16, 3 : 16 x 16) */ + + /* for H.264 Encoder */ + int32_t enableAUDelimiter; /* Insert Access Unit Delimiter before NAL unit. */ + + uint32_t imgFormat; /* Fourcc of Input Image */ + uint32_t imgBufferNum; /* Number of Input Image Buffer */ + uint32_t imgPlaneNum; /* Number of Input Image Plane */ + + /* for JPEG Specific Parameter */ + int32_t rotAngle; + int32_t mirDirection; /* 0 : not mir, 1 : horizontal mir, 2 : vertical mir, 3 : horizontal & vertical mir */ + + int32_t jpgQuality; /* 1 ~ 100 */ + } NX_V4L2ENC_PARA; + + typedef struct tNX_V4L2ENC_IN + { + NX_VID_MEMORY_HANDLE pImage; /* Original captured frame's pointer */ + int32_t imgIndex; + uint64_t timeStamp; /* Time stamp */ + int32_t forcedIFrame; /* Flag of forced intra frame */ + int32_t forcedSkipFrame; /* Flag of forced skip frame */ + int32_t quantParam; /* User quantization parameter(It is valid only when VBR.) */ + } NX_V4L2ENC_IN; + + typedef struct tNX_V4L2ENC_OUT + { + uint8_t *strmBuf; /* compressed stream's pointer */ + int32_t strmSize; /* compressed stream's size */ + int32_t frameType; /* Frame type */ + NX_VID_MEMORY_INFO reconImg; /* TBD. Reconstructed image's pointer */ + } NX_V4L2ENC_OUT; + + typedef struct tNX_V4L2ENC_CHG_PARA + { + int32_t chgFlg; + int32_t keyFrmInterval; /* Size of key frame interval */ + int32_t bitrate; /* Target bitrate in bits/second */ + int32_t fpsNum; /* Frame per second */ + int32_t fpsDen; + int32_t disableSkip; /* Disable skip frame mode */ + int32_t numIntraRefreshMbs; /* Intra MB refresh number(Cyclic Intra Refresh) */ + } NX_V4L2ENC_CHG_PARA; + + typedef struct tNX_V4L2DEC_SEQ_IN + { + uint32_t imgFormat; /* Fourcc for Decoded Image */ + uint32_t imgPlaneNum; /* Number of Input Image Plane */ + + uint8_t *seqBuf; /* Sequence header's pointer */ + int32_t seqSize; /* Sequence header's size */ + + uint64_t timeStamp; + + int32_t width; + int32_t height; + + /* for External Buffer(optional) */ + NX_VID_MEMORY_HANDLE *pMemHandle; /* Frame buffer for external buffer mode */ + + int32_t numBuffers; /* Internal buffer mode : number of extra buffer */ + /* External buffer mode : number of external frame buffer */ + + /* for JPEG Decoder */ + int32_t thumbnailMode; /* 0 : jpeg mode, 1 : thumbnail mode */ + } NX_V4L2DEC_SEQ_IN; + + typedef struct tNX_V4L2DEC_SEQ_OUT + { + int32_t minBuffers; /* Needed minimum number for decoder */ + int32_t width; + int32_t height; + int32_t interlace; + + int32_t frameRateNum; /* Frame Rate Numerator */ + int32_t frameRateDen; /* Frame Rate Denominator (-1 : no information) */ + + int32_t imgFourCC; /* FourCC according to decoded image type */ + int32_t thumbnailWidth; /* Width of thumbnail image */ + int32_t thumbnailHeight; /* Height of thumbnail image */ + + uint32_t usedByte; + + IMG_DISP_INFO dispInfo; + } NX_V4L2DEC_SEQ_OUT; + + typedef struct tNX_V4L2DEC_IN + { + uint8_t *strmBuf; /* A compressed stream's pointer */ + int32_t strmSize; /* A compressed stream's size */ + uint64_t timeStamp; /* Time stamp */ + int32_t eos; + + /* for JPEG Decoder */ + int32_t downScaleWidth; /* 0 : No scaling, 1 : 1/2 down scaling, 2 : 1/4 down scaling, 3 : 1/8 down scaling */ + int32_t downScaleHeight; /* 0 : No scaling, 1 : 1/2 down scaling, 2 : 1/4 down scaling, 3 : 1/8 down scaling */ + } NX_V4L2DEC_IN; + + typedef struct tNX_V4L2DEC_OUT + { + NX_VID_MEMORY_INFO hImg; /* Decoded frame's pointer */ + IMG_DISP_INFO dispInfo; + + int32_t decIdx; /* Decode Index */ + int32_t dispIdx; /* Display Index */ + + uint32_t usedByte; + int32_t picType[2]; /* Picture Type */ + uint64_t timeStamp[2]; /* Time stamp */ + int32_t interlace[2]; + int32_t outFrmReliable_0_100[2]; /* Percentage of MB's are reliable ranging from 0[all damage] to 100 [all clear] */ + } NX_V4L2DEC_OUT; + + +/* + * V4L2 Encoder + */ + NX_V4L2ENC_HANDLE NX_V4l2EncOpen (uint32_t codecType); + int32_t NX_V4l2EncClose (NX_V4L2ENC_HANDLE hEnc); + int32_t NX_V4l2EncInit (NX_V4L2ENC_HANDLE hEnc, NX_V4L2ENC_PARA * pEncPara); + int32_t NX_V4l2EncGetSeqInfo (NX_V4L2ENC_HANDLE hEnc, uint8_t ** ppSeqBuf, + int32_t * iSeqSize); + int32_t NX_V4l2EncEncodeFrame (NX_V4L2ENC_HANDLE hEnc, NX_V4L2ENC_IN * pEncIn, + NX_V4L2ENC_OUT * pEncOut); + int32_t NX_V4L2EncChangeParameter (NX_V4L2ENC_HANDLE hEnc, + NX_V4L2ENC_CHG_PARA * pChgPara); + + +/* + * V4L2 Decoder + */ + NX_V4L2DEC_HANDLE NX_V4l2DecOpen (uint32_t codecType); + int32_t NX_V4l2DecClose (NX_V4L2DEC_HANDLE hDec); + int32_t NX_V4l2DecParseVideoCfg (NX_V4L2DEC_HANDLE hDec, + NX_V4L2DEC_SEQ_IN * pSeqIn, NX_V4L2DEC_SEQ_OUT * pSeqOut); + int32_t NX_V4l2DecInit (NX_V4L2DEC_HANDLE hDec, NX_V4L2DEC_SEQ_IN * pSeqIn); + int32_t NX_V4l2DecDecodeFrame (NX_V4L2DEC_HANDLE hDec, NX_V4L2DEC_IN * pDecIn, + NX_V4L2DEC_OUT * pDecOut); + int32_t NX_V4l2DecClrDspFlag (NX_V4L2DEC_HANDLE hDec, + NX_VID_MEMORY_HANDLE hFrameBuf, int32_t iFrameIdx); + int32_t NX_V4l2DecFlush (NX_V4L2DEC_HANDLE hDec); + int32_t NX_DecGetFrameType (NX_V4L2DEC_HANDLE hDec, NX_V4L2DEC_IN * pDecIn, + uint32_t codecType, int32_t * piFrameType); + + +#ifdef __cplusplus +} +#endif + +#endif /* __NX_VIDEO_API_H__ */ diff --git a/src/nx_video_dec.c b/src/nx_video_dec.c new file mode 100644 index 0000000..cfb013a --- /dev/null +++ b/src/nx_video_dec.c @@ -0,0 +1,1357 @@ +/* + * Copyright (C) 2016 Nexell Co. All Rights Reserved + * Nexell Co. Proprietary & Confidential + * + * NEXELL INFORMS THAT THIS CODE AND INFORMATION IS PROVIDED "AS IS" BASE + * AND WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS + * FOR A PARTICULAR PURPOSE. + * + * File : nx_video_api.c + * Brief : V4L2 Video Decoder + * Author : SungWon Jo (doriya@nexell.co.kr) + * History : 2016.04.25 : Create + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + + +/*----------------------------------------------------------------------------*/ +#define NX_V4L2_DEC_NAME "nx-vpu-dec" +#define VIDEODEV_MINOR_MAX 63 +#define STREAM_BUFFER_NUM 1 + + +struct NX_V4L2DEC_INFO +{ + int fd; + uint32_t codecType; + int32_t width; + int32_t height; + + int32_t useExternalFrameBuffer; + int32_t numFrameBuffers; + NX_VID_MEMORY_HANDLE hImage[MAX_FRAME_BUFFER_NUM]; + + NX_MEMORY_HANDLE hStream[STREAM_BUFFER_NUM]; + + /* Initialize Output Information */ + uint8_t pSeqData[1024]; /* SPS PPS (H.264) or Decoder Specific Information(for MPEG4) */ + int32_t seqDataSize; + + IMG_DISP_INFO dispInfo; + + int32_t planesNum; + + int32_t frameCnt; + + /* For MPEG4 */ + int vopTimeBits; + + /* For VC1 */ + int32_t iInterlace; +}; + + +/* + * Find Device Node + */ + +/*----------------------------------------------------------------------------*/ +static int32_t +V4l2DecOpen (void) +{ + int fd = -1; + + bool found = false; + struct stat s; + FILE *stream_fd; + char filename[64], name[64]; + int32_t i = 0; + + while (!found && (i <= VIDEODEV_MINOR_MAX)) { + /* video device node */ + sprintf (filename, "/dev/video%d", i); + + /* if the node is video device */ + if ((lstat (filename, &s) == 0) && S_ISCHR (s.st_mode) + && ((int) ((unsigned short) (s.st_rdev) >> 8) == 81)) { + /* open sysfs entry */ + sprintf (filename, "/sys/class/video4linux/video%d/name", i); + stream_fd = fopen (filename, "r"); + if (stream_fd == NULL) { + printf ("failed to open sysfs entry for videodev \n"); + i++; + continue; + } + + /* read sysfs entry for device name */ + if (fgets (name, sizeof (name), stream_fd) == 0) { + printf ("failed to read sysfs entry for videodev\n"); + } else { + if (strncmp (name, NX_V4L2_DEC_NAME, strlen (NX_V4L2_DEC_NAME)) == 0) { + printf ("node found for device %s: /dev/video%d \n", NX_V4L2_DEC_NAME, + i); + found = true; + } + } + + fclose (stream_fd); + } + + i++; + } + + if (found) { + sprintf (filename, "/dev/video%d", i - 1); + fd = open (filename, O_RDWR); + } + + return fd; +} + + +#ifndef MKTAG +#define MKTAG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24)) +#endif + +#ifndef PUT_LE32 +#define PUT_LE32(_p, _var) \ + *_p++ = (uint8_t)((_var) >> 0); \ + *_p++ = (uint8_t)((_var) >> 8); \ + *_p++ = (uint8_t)((_var) >> 16); \ + *_p++ = (uint8_t)((_var) >> 24); +#endif + +#ifndef PUT_BE32 +#define PUT_BE32(_p, _var) \ + *_p++ = (uint8_t)((_var) >> 24); \ + *_p++ = (uint8_t)((_var) >> 16); \ + *_p++ = (uint8_t)((_var) >> 8); \ + *_p++ = (uint8_t)((_var) >> 0); +#endif + +#ifndef PUT_LE16 +#define PUT_LE16(_p, _var) \ + *_p++ = (uint8_t)((_var) >> 0); \ + *_p++ = (uint8_t)((_var) >> 8); +#endif + +#ifndef PUT_BE16 +#define PUT_BE16(_p, _var) \ + *_p++ = (uint8_t)((_var) >> 8); \ + *_p++ = (uint8_t)((_var) >> 0); +#endif + + +typedef struct +{ + uint32_t dwUsedBits; + uint8_t *pbyStart; + uint32_t dwPktSize; +} VLD_STREAM; + +static int32_t +vld_count_leading_zero (uint32_t dwWord) +{ + int32_t iLZ = 0; + + if ((dwWord >> (32 - 16)) == 0) + iLZ = 16; + if ((dwWord >> (32 - 8 - iLZ)) == 0) + iLZ += 8; + if ((dwWord >> (32 - 4 - iLZ)) == 0) + iLZ += 4; + if ((dwWord >> (32 - 2 - iLZ)) == 0) + iLZ += 2; + if ((dwWord >> (32 - 1 - iLZ)) == 0) + iLZ += 1; + + return iLZ; +} + +static uint32_t +vld_show_bits (VLD_STREAM * pstVldStm, int32_t iBits) +{ + uint32_t dwUsedBits = pstVldStm->dwUsedBits; + int32_t iBitCnt = 8 - (dwUsedBits & 0x7); + uint8_t *pbyRead = (uint8_t *) pstVldStm->pbyStart + (dwUsedBits >> 3); + uint32_t dwRead; + + dwRead = *pbyRead++ << 24; + if (iBits > iBitCnt) { + dwRead += *pbyRead++ << 16; + if (iBits > iBitCnt + 8) { + dwRead += *pbyRead++ << 8; + if (iBits > iBitCnt + 16) + dwRead += *pbyRead++; + } + } + + return (dwRead << (8 - iBitCnt)) >> (32 - iBits); +} + +static uint32_t +vld_get_bits (VLD_STREAM * pstVldStm, int32_t iBits) +{ + uint32_t dwUsedBits = pstVldStm->dwUsedBits; + int32_t iBitCnt = 8 - (dwUsedBits & 0x7); + uint8_t *pbyRead = (uint8_t *) pstVldStm->pbyStart + (dwUsedBits >> 3); + uint32_t dwRead; + + pstVldStm->dwUsedBits += iBits; + + dwRead = *pbyRead++ << 24; + if (iBits > iBitCnt) { + dwRead += *pbyRead++ << 16; + if (iBits > iBitCnt + 8) { + dwRead += *pbyRead++ << 8; + if (iBits > iBitCnt + 16) + dwRead += *pbyRead++; + } + } + + return (dwRead << (8 - iBitCnt)) >> (32 - iBits); +} + +static void +vld_flush_bits (VLD_STREAM * pstVldStm, int iBits) +{ + pstVldStm->dwUsedBits += iBits; +} + +static uint32_t +vld_get_uev (VLD_STREAM * pstVldStm) +{ + int32_t iLZ = vld_count_leading_zero (vld_show_bits (pstVldStm, 32)); + + vld_flush_bits (pstVldStm, iLZ); + return (vld_get_bits (pstVldStm, iLZ + 1) - 1); +} + +static void +Mp4DecParseVideoCfg (NX_V4L2DEC_HANDLE hDec, uint8_t * pbyStream, + int32_t iStreamSize) +{ + uint8_t *pbyStrm = pbyStream; + uint32_t uPreFourByte = (uint32_t) - 1; + + hDec->vopTimeBits = 0; + + do { + if (pbyStrm >= (pbyStream + iStreamSize)) + break; + + uPreFourByte = (uPreFourByte << 8) + *pbyStrm++; + + if (uPreFourByte >= 0x00000120 && uPreFourByte <= 0x0000012F) { + VLD_STREAM stStrm = { 0, pbyStrm, iStreamSize }; + int32_t i; + + vld_flush_bits (&stStrm, 1 + 8); /* random_accessible_vol, video_object_type_indication */ + if (vld_get_bits (&stStrm, 1)) /* is_object_layer_identifier */ + vld_flush_bits (&stStrm, 4 + 3); /* video_object_layer_verid, video_object_layer_priority */ + + if (vld_get_bits (&stStrm, 4) == 0xF) /* aspect_ratio_info */ + vld_flush_bits (&stStrm, 8 + 8); /* par_width, par_height */ + + if (vld_get_bits (&stStrm, 1)) { /* vol_control_parameters */ + if (vld_get_bits (&stStrm, 2 + 1 + 1) & 1) { /* chroma_format, low_delay, vbv_parameters */ + vld_flush_bits (&stStrm, 15 + 1); /* first_half_bit_rate, marker_bit */ + vld_flush_bits (&stStrm, 15 + 1); /* latter_half_bit_rate, marker_bit */ + vld_flush_bits (&stStrm, 15 + 1); /* first_half_vbv_buffer_size, marker_bit */ + vld_flush_bits (&stStrm, 3 + 11 + 1); /* latter_half_vbv_buffer_size, first_half_vbv_occupancy, marker_bit */ + vld_flush_bits (&stStrm, 15 + 1); /* latter_half_vbv_occupancy, marker_bit */ + } + } + + vld_flush_bits (&stStrm, 2 + 1); /* video_object_layer_shape, marker_bit */ + + for (i = 0; i < 16; i++) /* vop_time_increment_resolution */ + if (vld_get_bits (&stStrm, 1)) + break; + hDec->vopTimeBits = 16 - i; + break; + } + } while (1); +} + +static int32_t +Mp4DecParseFrameHeader (NX_V4L2DEC_HANDLE hDec, uint8_t * pbyStream, + int32_t iStreamSize) +{ + VLD_STREAM stStrm = { 0, pbyStream, iStreamSize }; + int32_t iSize = iStreamSize; + + if (vld_get_bits (&stStrm, 32) == 0x000001B6) { + vld_flush_bits (&stStrm, 2); /* vop_coding_type */ + + do { + if (vld_get_bits (&stStrm, 1) == 0) + break; + } while (stStrm.dwUsedBits < ((uint32_t) iStreamSize << 3)); + + vld_flush_bits (&stStrm, 1 + hDec->vopTimeBits + 1); /* marker_bits, vop_time_increment, marker_bits */ + + if (vld_get_bits (&stStrm, 1) == 0) /* vop_coded */ + iSize = 0; + } + + return iSize; +} + +static int32_t +GetSequenceHeader (NX_V4L2DEC_HANDLE hDec, NX_V4L2DEC_SEQ_IN * pSeqIn) +{ + uint8_t *pbySrc = pSeqIn->seqBuf; + uint8_t *pbyDst = (uint8_t *) hDec->hStream[0]->pBuffer; + int32_t iSize = pSeqIn->seqSize; + + switch (hDec->codecType) { + case V4L2_PIX_FMT_H264: + if (pSeqIn->seqSize > 0) { + memcpy (pbyDst, pbySrc, pSeqIn->seqSize); + + if ((pbySrc[2] == 0) && (pbySrc[7] > 51)) + pbyDst[7] = 51; + else if ((pbySrc[2] == 1) && (pbySrc[6] > 51)) + pbyDst[6] = 51; + break; + } else + return -1; + + case V4L2_PIX_FMT_DIV3: + if (pSeqIn->seqSize == 0) { + if ((pSeqIn->width > 0) && (pSeqIn->height > 0)) { + PUT_LE32 (pbyDst, MKTAG ('C', 'N', 'M', 'V')); + PUT_LE16 (pbyDst, 0x00); /* version */ + PUT_LE16 (pbyDst, 0x20); /* length of header in bytes */ + PUT_LE32 (pbyDst, MKTAG ('D', 'I', 'V', '3')); /* codec FourCC */ + PUT_LE16 (pbyDst, pSeqIn->width); + PUT_LE16 (pbyDst, pSeqIn->height); + PUT_LE32 (pbyDst, 0); /* frame rate */ + PUT_LE32 (pbyDst, 0); /* time scale(?) */ + PUT_LE32 (pbyDst, 0); /* number of frames in file */ + PUT_LE32 (pbyDst, 0); /* unused */ + iSize += 32; + } else + return -1; + } else { + PUT_BE32 (pbyDst, pSeqIn->seqSize); + iSize += 4; + memcpy (pbyDst, pbyDst, pSeqIn->seqSize); + } + break; + + case V4L2_PIX_FMT_WMV9: + if ((pSeqIn->seqSize > 0) && (pSeqIn->width > 0) && (pSeqIn->height > 0)) { +#ifdef RCV_V2 + PUT_LE32 (pbyDst, (0xC5 << 24) | 0x00); /* version */ +#else + /* RCV_V1 */ + PUT_LE32 (pbyDst, (0x85 << 24) | 0x00); +#endif + + PUT_LE32 (pbyDst, pSeqIn->seqSize); + memcpy (pbyDst, pbySrc, pSeqIn->seqSize); + pbyDst += pSeqIn->seqSize; + PUT_LE32 (pbyDst, pSeqIn->height); + PUT_LE32 (pbyDst, pSeqIn->width); + iSize += 16; +#ifdef RCV_V2 + PUT_LE32 (pbyDst, 12); + /* STRUCT_B_FRIST (LEVEL:3|CBR:1:RESERVE:4:HRD_BUFFER|24) */ + PUT_LE32 (pbyDst, 2 << 29 | 1 << 28 | 0x80 << 24 | 1 << 0); + PUT_LE32 (pbyDst, 0); /* bitrate */ + PUT_LE32 (pbyDst, 0); /* framerate */ + iSize += 16; +#endif + break; + } else + return -1; + + case V4L2_PIX_FMT_RV8: + case V4L2_PIX_FMT_RV9: + if ((pSeqIn->seqSize > 0) && (pSeqIn->width > 0) && (pSeqIn->height > 0)) { + iSize += 26; + + PUT_BE32 (pbyDst, iSize); /* Length */ + PUT_LE32 (pbyDst, MKTAG ('V', 'I', 'D', 'O')); /* MOFTag */ + + if (hDec->codecType == V4L2_PIX_FMT_RV8) { + PUT_LE32 (pbyDst, MKTAG ('R', 'V', '3', '0')); + } else { + PUT_LE32 (pbyDst, MKTAG ('R', 'V', '4', '0')); + } + + PUT_BE16 (pbyDst, pSeqIn->width); + PUT_BE16 (pbyDst, pSeqIn->height); + PUT_BE16 (pbyDst, 0x0c); /* BitCount */ + PUT_BE16 (pbyDst, 0x00); /* PadWidth */ + PUT_BE16 (pbyDst, 0x00); /* PadHeight */ + PUT_LE32 (pbyDst, 0); /* framerate */ + memcpy (pbyDst, pbySrc, pSeqIn->seqSize); + break; + } else + return -1; + + case V4L2_PIX_FMT_VP8: + if ((pSeqIn->seqSize > 0) && (pSeqIn->width > 0) && (pSeqIn->height > 0)) { + PUT_LE32 (pbyDst, MKTAG ('D', 'K', 'I', 'F')); /* signature 'DKIF' */ + PUT_LE16 (pbyDst, 0x00); /* version */ + PUT_LE16 (pbyDst, 0x20); /* length of header in bytes */ + PUT_LE32 (pbyDst, MKTAG ('V', 'P', '8', '0')); /* codec FourCC */ + PUT_LE16 (pbyDst, pSeqIn->width); /* width */ + PUT_LE16 (pbyDst, pSeqIn->height); /* height */ + PUT_LE32 (pbyDst, 0); /* frame rate */ + PUT_LE32 (pbyDst, 0); /* time scale(?) */ + PUT_LE32 (pbyDst, 0); /* number of frames in file */ + PUT_LE32 (pbyDst, 0); /* unused */ + iSize += 32; + + PUT_LE32 (pbyDst, pSeqIn->seqSize); + PUT_LE32 (pbyDst, 0); + PUT_LE32 (pbyDst, 0); + memcpy (pbyDst, pbySrc, pSeqIn->seqSize); + iSize += 12; + break; + } else + return -1; + + case V4L2_PIX_FMT_XVID: + case V4L2_PIX_FMT_DIVX: + case V4L2_PIX_FMT_DIV4: + case V4L2_PIX_FMT_DIV5: + case V4L2_PIX_FMT_DIV6: + case V4L2_PIX_FMT_MPEG4: + Mp4DecParseVideoCfg (hDec, pbySrc, pSeqIn->seqSize); + + default: + if (pSeqIn->seqSize > 0) + memcpy (pbyDst, pbySrc, pSeqIn->seqSize); + else + return -1; + } + + return iSize; +} + +static int32_t +GetFrameStream (NX_V4L2DEC_HANDLE hDec, NX_V4L2DEC_IN * pDecIn, int32_t * idx) +{ + int32_t iSize = pDecIn->strmSize; + uint8_t *pbySrc = pDecIn->strmBuf; + uint8_t *pbyDst; + + if (iSize <= 0) + return 0; + + *idx = hDec->frameCnt % STREAM_BUFFER_NUM; + pbyDst = (uint8_t *) hDec->hStream[*idx]->pBuffer; + + switch (hDec->codecType) { + case V4L2_PIX_FMT_H264: + memcpy (pbyDst, pbySrc, iSize); + if (iSize > 8) { + if ((pbySrc[2] == 0) && ((pbySrc[4] & 0x1F) == 7) && (pbySrc[7] > 51)) + pbyDst[7] = 51; + else if ((pbySrc[2] == 1) && ((pbySrc[3] & 0x1F) == 7) + && (pbySrc[6] > 51)) + pbyDst[6] = 51; + } + break; + + case V4L2_PIX_FMT_WVC1: + /* check start code as prefix (0x00, 0x00, 0x01) */ + if (pbySrc[0] != 0 || pbySrc[1] != 0 || pbySrc[2] != 1) { + *pbyDst++ = 0x00; + *pbyDst++ = 0x00; + *pbyDst++ = 0x01; + *pbyDst++ = 0x0D; + memcpy (pbyDst, pbySrc, iSize); + iSize += 4; + } else { + /* no extra header size, there is start code in input stream */ + memcpy (pbyDst, pbySrc, iSize); + } + break; + + case V4L2_PIX_FMT_WMV9: + PUT_LE32 (pbyDst, iSize | 0); /* Key Frame = 0x80000000 */ + iSize += 4; + +#ifdef RCV_V2 + PUT_LE32 (pbyDst, 0); + iSize += 4; +#endif + + memcpy (pbyDst, pbySrc, pDecIn->strmSize); + break; + + case V4L2_PIX_FMT_RV8: + case V4L2_PIX_FMT_RV9: + { + int32_t cSlice, nSlice; + int32_t i, val, offset; + + cSlice = pbySrc[0] + 1; + nSlice = iSize - 1 - (cSlice * 8); + + PUT_BE32 (pbyDst, nSlice); + PUT_LE32 (pbyDst, 0); + PUT_BE16 (pbyDst, 0); /* frame number */ + PUT_BE16 (pbyDst, 0x02); /* Flags */ + PUT_BE32 (pbyDst, 0x00); /* LastPacket */ + PUT_BE32 (pbyDst, cSlice); /* NumSegments */ + + offset = 1; + for (i = 0; i < cSlice; i++) { + val = + (pbySrc[offset + 3] << 24) | (pbySrc[offset + + 2] << 16) | (pbySrc[offset + 1] << 8) | pbySrc[offset]; + PUT_BE32 (pbyDst, val); /* isValid */ + offset += 4; + val = + (pbySrc[offset + 3] << 24) | (pbySrc[offset + + 2] << 16) | (pbySrc[offset + 1] << 8) | pbySrc[offset]; + PUT_BE32 (pbyDst, val); /* Offset */ + offset += 4; + } + + memcpy (pbyDst, pbySrc + (1 + (cSlice * 8)), nSlice); + iSize = 20 + (cSlice * 8) + nSlice; + } + break; + + case V4L2_PIX_FMT_DIV3: + case V4L2_PIX_FMT_VP8: + PUT_LE32 (pbyDst, iSize); + PUT_LE32 (pbyDst, 0); + PUT_LE32 (pbyDst, 0); + memcpy (pbyDst, pbySrc, iSize); + iSize += 12; + break; + + case V4L2_PIX_FMT_XVID: + case V4L2_PIX_FMT_DIVX: + case V4L2_PIX_FMT_DIV4: + case V4L2_PIX_FMT_DIV5: + case V4L2_PIX_FMT_DIV6: + case V4L2_PIX_FMT_MPEG4: + /* For PB Frame */ + if (hDec->vopTimeBits > 0) { + iSize = Mp4DecParseFrameHeader (hDec, pbySrc, iSize); + } + + default: + memcpy ((void *) pbyDst, (void *) pbySrc, iSize); + } + + return iSize; +} + + +/* + * V4L2 Decoder + */ + +/*----------------------------------------------------------------------------*/ +NX_V4L2DEC_HANDLE +NX_V4l2DecOpen (uint32_t codecType) +{ + NX_V4L2DEC_HANDLE hDec = + (NX_V4L2DEC_HANDLE) malloc (sizeof (struct NX_V4L2DEC_INFO)); + + memset (hDec, 0, sizeof (struct NX_V4L2DEC_INFO)); + + hDec->fd = V4l2DecOpen (); + if (hDec->fd <= 0) { + printf ("Failed to open video decoder device\n"); + goto ERROR_EXIT; + } + + /* Query capabilities of Device */ + { + struct v4l2_capability cap; + + memset (&cap, 0, sizeof (cap)); + + if (ioctl (hDec->fd, VIDIOC_QUERYCAP, &cap) != 0) { + printf ("failed to ioctl: VIDIOC_QUERYCAP\n"); + goto ERROR_EXIT; + } + } + + hDec->codecType = codecType; + + return hDec; + +ERROR_EXIT: + free (hDec); + + return NULL; +} + +/*----------------------------------------------------------------------------*/ +int32_t +NX_V4l2DecClose (NX_V4L2DEC_HANDLE hDec) +{ + int32_t ret = 0, i; + + if (NULL == hDec) { + printf ("Fail, Invalid Handle.\n"); + return -1; + } + + { + enum v4l2_buf_type type; + + type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + if (ioctl (hDec->fd, VIDIOC_STREAMOFF, &type) != 0) { + printf ("failed to ioctl: VIDIOC_STREAMOFF(Stream)\n"); + return -1; + } + + type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + if (ioctl (hDec->fd, VIDIOC_STREAMOFF, &type) != 0) { + printf ("failed to ioctl: VIDIOC_STREAMOFF(Image)\n"); + return -1; + } + + for (i = 0; i < STREAM_BUFFER_NUM; i++) + NX_FreeMemory (hDec->hStream[i]); + + close (hDec->fd); + } + + if (hDec->useExternalFrameBuffer == 0) { + for (i = 0; i < hDec->numFrameBuffers; i++) { + if (hDec->hImage[i]) { + NX_FreeVideoMemory (hDec->hImage[i]); + hDec->hImage[i] = NULL; + } + } + } + + free (hDec); + + return ret; +} + +/*----------------------------------------------------------------------------*/ +int32_t +NX_V4l2DecParseVideoCfg (NX_V4L2DEC_HANDLE hDec, NX_V4L2DEC_SEQ_IN * pSeqIn, + NX_V4L2DEC_SEQ_OUT * pSeqOut) +{ + int32_t imgWidth = pSeqIn->width; + int32_t imgHeight = pSeqIn->height; + + memset (pSeqOut, 0, sizeof (NX_V4L2DEC_SEQ_OUT)); + + if (NULL == hDec) { + printf ("Fail, Invalid Handle.\n"); + return -1; + } + + hDec->seqDataSize = (pSeqIn->seqSize < 1024) ? (pSeqIn->seqSize) : (1024); + memcpy (hDec->pSeqData, pSeqIn->seqBuf, hDec->seqDataSize); + + /* Set Stream Formet */ + { + struct v4l2_format fmt; + + memset (&fmt, 0, sizeof (fmt)); + + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.pixelformat = hDec->codecType; + + if ((imgWidth == 0) || (imgHeight == 0)) + fmt.fmt.pix_mp.plane_fmt[0].sizeimage = + MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT * 3 / 4; + else + fmt.fmt.pix_mp.plane_fmt[0].sizeimage = imgWidth * imgHeight * 3 / 4; + + fmt.fmt.pix_mp.width = imgWidth; + fmt.fmt.pix_mp.height = imgHeight; + fmt.fmt.pix_mp.num_planes = 1; + + if (ioctl (hDec->fd, VIDIOC_S_FMT, &fmt) != 0) { + printf ("Failed to ioctx : VIDIOC_S_FMT(Input Stream)\n"); + return -1; + } + } + + /* Malloc Stream Buffer */ + { + struct v4l2_requestbuffers req; + int32_t i, buffCnt = STREAM_BUFFER_NUM; + + /* IOCTL : VIDIOC_REQBUFS For Input Stream */ + memset (&req, 0, sizeof (req)); + req.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + req.count = buffCnt; + req.memory = V4L2_MEMORY_DMABUF; + + if (ioctl (hDec->fd, VIDIOC_REQBUFS, &req) != 0) { + printf ("failed to ioctl: VIDIOC_REQBUFS(Input Stream)\n"); + return -1; + } + + for (i = 0; i < buffCnt; i++) { + hDec->hStream[i] = + NX_AllocateMemory (MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT * 3 / 4, 4096); + if (hDec->hStream[i] == NULL) { + printf ("Failed to allocate stream buffer(%d, %d)\n", i, + MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT * 3 / 4); + return -1; + } + + if (NX_MapMemory (hDec->hStream[i]) != 0) { + printf ("Stream memory Mapping Failed\n"); + return -1; + } + } + } + + /* Set Parameter */ + { + if (hDec->codecType == V4L2_PIX_FMT_MJPEG) { + struct v4l2_control ctrl; + + ctrl.id = V4L2_CID_MPEG_VIDEO_THUMBNAIL_MODE; + ctrl.value = pSeqIn->thumbnailMode; + + if (ioctl (hDec->fd, VIDIOC_S_CTRL, &ctrl) != 0) { + printf ("failed to ioctl: Set Thumbnail Mode\n"); + return -1; + } + } + } + + /* Parser Sequence Header */ + { + struct v4l2_plane planes[1]; + struct v4l2_buffer buf; + enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + int32_t iSeqSize = GetSequenceHeader (hDec, pSeqIn); + + if (iSeqSize <= 0) { + printf ("Fail, input data has error!!"); + return -1; + } + + memset (&buf, 0, sizeof (buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + buf.m.planes = planes; + buf.length = 1; + buf.memory = V4L2_MEMORY_DMABUF; + buf.index = 0; + + buf.m.planes[0].m.userptr = (unsigned long) hDec->hStream[0]->pBuffer; + buf.m.planes[0].m.fd = hDec->hStream[0]->dmaFd; + buf.m.planes[0].length = hDec->hStream[0]->size; + buf.m.planes[0].bytesused = iSeqSize; + buf.m.planes[0].data_offset = 0; + + buf.timestamp.tv_sec = pSeqIn->timeStamp / 1000; + buf.timestamp.tv_usec = (pSeqIn->timeStamp % 1000) * 1000; + + if (ioctl (hDec->fd, VIDIOC_QBUF, &buf) != 0) { + printf ("failed to ioctl: VIDIOC_QBUF(Header Stream)\n"); + return -1; + } + + if (ioctl (hDec->fd, VIDIOC_STREAMON, &type) != 0) { + printf ("Fail, ioctl(): VIDIOC_STREAMON. (Input)\n"); + return -1; + } + + memset (&buf, 0, sizeof (buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + buf.m.planes = planes; + buf.length = 1; + buf.memory = V4L2_MEMORY_DMABUF; + + if (ioctl (hDec->fd, VIDIOC_DQBUF, &buf) != 0) { + printf ("failed to ioctl: VIDIOC_DQBUF(Header Stream)\n"); + return -1; + } + + pSeqOut->usedByte = buf.bytesused; + + if (buf.field == V4L2_FIELD_NONE) + pSeqOut->interlace = NONE_FIELD; + else if (V4L2_FIELD_INTERLACED) + pSeqOut->interlace = FIELD_INTERLACED; + + hDec->iInterlace = pSeqOut->interlace; + } + + /* Get Image Information */ + { + struct v4l2_format fmt; + struct v4l2_crop crop; + + memset (&fmt, 0, sizeof (fmt)); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + + if (ioctl (hDec->fd, VIDIOC_G_FMT, &fmt) != 0) { + printf ("Fail, ioctl(): VIDIOC_G_FMT.\n"); + return -1; + } + + pSeqOut->imgFourCC = fmt.fmt.pix_mp.pixelformat; + pSeqOut->width = fmt.fmt.pix_mp.width; + pSeqOut->height = fmt.fmt.pix_mp.height; + pSeqOut->minBuffers = fmt.fmt.pix_mp.reserved[1]; + hDec->numFrameBuffers = pSeqOut->minBuffers; + + memset (&crop, 0, sizeof (crop)); + crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + + if (ioctl (hDec->fd, VIDIOC_G_CROP, &crop) != 0) { + printf ("Fail, ioctl(): VIDIOC_G_CROP\n"); + return -1; + } + + pSeqOut->dispInfo.dispLeft = crop.c.left; + pSeqOut->dispInfo.dispTop = crop.c.top; + pSeqOut->dispInfo.dispRight = crop.c.left + crop.c.width; + pSeqOut->dispInfo.dispBottom = crop.c.top + crop.c.height; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +int32_t +NX_V4l2DecInit (NX_V4L2DEC_HANDLE hDec, NX_V4L2DEC_SEQ_IN * pSeqIn) +{ + /* Set Output Image */ + { + struct v4l2_format fmt; + + memset (&fmt, 0, sizeof (fmt)); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.pixelformat = pSeqIn->imgFormat; + fmt.fmt.pix_mp.width = pSeqIn->width; + fmt.fmt.pix_mp.height = pSeqIn->height; + fmt.fmt.pix_mp.num_planes = pSeqIn->imgPlaneNum; + + if (ioctl (hDec->fd, VIDIOC_S_FMT, &fmt) != 0) { + printf ("failed to ioctl: VIDIOC_S_FMT(Output Yuv)\n"); + return -1; + } + + hDec->planesNum = pSeqIn->imgPlaneNum; + } + + /* Malloc Output Image */ + { + struct v4l2_requestbuffers req; + struct v4l2_plane planes[3]; + struct v4l2_buffer buf; + enum v4l2_buf_type type; + int32_t imgBuffCnt, i, j; + + /* Calculate Buffer Number */ + if (pSeqIn->pMemHandle == NULL) { + hDec->useExternalFrameBuffer = false; + imgBuffCnt = hDec->numFrameBuffers + pSeqIn->numBuffers; + } else { + hDec->useExternalFrameBuffer = true; + if (2 > pSeqIn->numBuffers - hDec->numFrameBuffers) + printf ("External Buffer too small.(min=%d, buffers=%d)\n", + hDec->numFrameBuffers, pSeqIn->numBuffers); + + imgBuffCnt = pSeqIn->numBuffers; + } + hDec->numFrameBuffers = imgBuffCnt; + + /* Request Output Buffer */ + memset (&req, 0, sizeof (req)); + req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + req.count = imgBuffCnt; + req.memory = V4L2_MEMORY_DMABUF; + + if (ioctl (hDec->fd, VIDIOC_REQBUFS, &req) != 0) { + printf ("failed to ioctl: VIDIOC_REQBUFS(Output YUV)\n"); + return -1; + } + + memset (&buf, 0, sizeof (buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + buf.m.planes = planes; + buf.length = pSeqIn->imgPlaneNum; + buf.memory = V4L2_MEMORY_DMABUF; + + /* Allocate Buffer(Internal or External) */ + for (i = 0; i < imgBuffCnt; i++) { + if (true == hDec->useExternalFrameBuffer) { + hDec->hImage[i] = pSeqIn->pMemHandle[i]; + } else { + hDec->hImage[i] = + NX_AllocateVideoMemory (pSeqIn->width, pSeqIn->height, + pSeqIn->imgPlaneNum, pSeqIn->imgFormat, 4096); + if (hDec->hImage[i] == NULL) { + printf ("Failed to allocate image buffer(%d, %d, %d)\n", i, + pSeqIn->width, pSeqIn->height); + return -1; + } + + if (NX_MapVideoMemory (hDec->hImage[i]) != 0) { + printf ("Video Memory Mapping Failed\n"); + return -1; + } + } + + buf.index = i; + + for (j = 0; j < (int32_t) pSeqIn->imgPlaneNum; j++) { + buf.m.planes[j].m.fd = hDec->hImage[i]->dmaFd[j]; + buf.m.planes[j].length = hDec->hImage[i]->size[j]; + } + + if (ioctl (hDec->fd, VIDIOC_QBUF, &buf) != 0) { + printf ("failed to ioctl: VIDIOC_QBUF(Output YUV - %d)\n", i); + return -1; + } + } + + type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + if (ioctl (hDec->fd, VIDIOC_STREAMON, &type) != 0) { + printf ("failed to ioctl: VIDIOC_STREAMON\n"); + return -1; + } + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +int32_t +NX_V4l2DecDecodeFrame (NX_V4L2DEC_HANDLE hDec, NX_V4L2DEC_IN * pDecIn, + NX_V4L2DEC_OUT * pDecOut) +{ + struct v4l2_buffer buf; + struct v4l2_plane planes[3]; + int idx; + int32_t iStrmSize; + int32_t frameType; + + if (NULL == hDec) { + printf ("Fail, Invalid Handle.\n"); + return -1; + } + + iStrmSize = GetFrameStream (hDec, pDecIn, &idx); + + /* Queue Input Buffer */ + memset (&buf, 0, sizeof (buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + buf.m.planes = planes; + buf.length = 1; + buf.memory = V4L2_MEMORY_DMABUF; + buf.index = idx; + buf.timestamp.tv_sec = pDecIn->timeStamp / 1000; + buf.timestamp.tv_usec = (pDecIn->timeStamp % 1000) * 1000; + buf.flags = pDecIn->eos ? 1 : 0; + + /* buf.m.planes[0].m.userptr = (unsigned long)hStream->pBuffer; */ + buf.m.planes[0].m.fd = hDec->hStream[idx]->dmaFd; + buf.m.planes[0].length = hDec->hStream[idx]->size; + buf.m.planes[0].bytesused = iStrmSize; + buf.m.planes[0].data_offset = 0; + + if (ioctl (hDec->fd, VIDIOC_QBUF, &buf) != 0) { + printf ("Fail, ioctl(): VIDIOC_QBUF.(Input)\n"); + return -1; + } + + if (iStrmSize > 0) { + /* Dequeue Input ES Buffer -> Get Decoded Order Result */ + memset (&buf, 0, sizeof (buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + buf.m.planes = planes; + buf.length = 1; + buf.memory = V4L2_MEMORY_DMABUF; + + if (ioctl (hDec->fd, VIDIOC_DQBUF, &buf) != 0) { + printf ("Fail, ioctl(): VIDIOC_DQBUF.(Input)\n"); + return -1; + } + + pDecOut->decIdx = buf.index; + pDecOut->usedByte = buf.bytesused; + pDecOut->outFrmReliable_0_100[DECODED_FRAME] = buf.reserved; + pDecOut->timeStamp[DECODED_FRAME] = + ((uint64_t) buf.timestamp.tv_sec) * 1000 + buf.timestamp.tv_usec / 1000; + frameType = buf.flags; + + if (frameType & V4L2_BUF_FLAG_KEYFRAME) + pDecOut->picType[DECODED_FRAME] = PIC_TYPE_I; + else if (frameType & V4L2_BUF_FLAG_PFRAME) + pDecOut->picType[DECODED_FRAME] = PIC_TYPE_P; + else if (frameType & V4L2_BUF_FLAG_BFRAME) + pDecOut->picType[DECODED_FRAME] = PIC_TYPE_B; + else + pDecOut->picType[DECODED_FRAME] = PIC_TYPE_UNKNOWN; + + if (buf.field == V4L2_FIELD_NONE) + pDecOut->interlace[DECODED_FRAME] = NONE_FIELD; + else if (buf.field == V4L2_FIELD_SEQ_TB) + pDecOut->interlace[DECODED_FRAME] = TOP_FIELD_FIRST; + else if (buf.field == V4L2_FIELD_SEQ_BT) + pDecOut->interlace[DECODED_FRAME] = BOTTOM_FIELD_FIRST; + } else if (pDecIn->strmSize > 0) { + pDecOut->usedByte = pDecIn->strmSize; + } + + /* Dequeue Output YUV Buffer -> Get Display Order Result */ + memset (&buf, 0, sizeof (buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + buf.m.planes = planes; + buf.length = hDec->planesNum; + buf.memory = V4L2_MEMORY_DMABUF; + + if (ioctl (hDec->fd, VIDIOC_DQBUF, &buf) != 0) { + printf ("Fail, ioctl(): VIDIOC_DQBUF(Output)\n"); + return -100; + } + + pDecOut->dispIdx = buf.index; + // pDecOut->dispInfo = &hDec->dispInfo; // TBD. + + if (pDecOut->dispIdx >= 0) { + pDecOut->hImg = *hDec->hImage[buf.index]; + pDecOut->timeStamp[DISPLAY_FRAME] = + ((uint64_t) buf.timestamp.tv_sec) * 1000 + buf.timestamp.tv_usec / 1000; + pDecOut->outFrmReliable_0_100[DISPLAY_FRAME] = buf.reserved; + frameType = buf.flags; + + if (frameType & V4L2_BUF_FLAG_KEYFRAME) + pDecOut->picType[DISPLAY_FRAME] = PIC_TYPE_I; + else if (frameType & V4L2_BUF_FLAG_PFRAME) + pDecOut->picType[DISPLAY_FRAME] = PIC_TYPE_P; + else if (frameType & V4L2_BUF_FLAG_BFRAME) + pDecOut->picType[DISPLAY_FRAME] = PIC_TYPE_B; + else + pDecOut->picType[DISPLAY_FRAME] = PIC_TYPE_UNKNOWN; + + if (buf.field == V4L2_FIELD_NONE) + pDecOut->interlace[DISPLAY_FRAME] = NONE_FIELD; + else if (buf.field == V4L2_FIELD_SEQ_TB) + pDecOut->interlace[DISPLAY_FRAME] = TOP_FIELD_FIRST; + else if (buf.field == V4L2_FIELD_SEQ_BT) + pDecOut->interlace[DISPLAY_FRAME] = BOTTOM_FIELD_FIRST; + } + + hDec->frameCnt++; + + if (pDecOut->dispIdx == -1) + return -1; + + return 0; +} + +/*----------------------------------------------------------------------------*/ +int32_t +NX_V4l2DecClrDspFlag (NX_V4L2DEC_HANDLE hDec, NX_VID_MEMORY_HANDLE hFrameBuf, + int32_t iFrameIdx) +{ + struct v4l2_buffer buf; + struct v4l2_plane planes[3]; + int32_t index = -1; + int32_t i; + + if (NULL == hDec) { + printf ("Fail, Invalid Handle.\n"); + return -1; + } + + if (iFrameIdx >= 0) { + index = iFrameIdx; + } else { + /* Search Buffer Index */ + if (hFrameBuf != NULL) { + for (i = 0; i < hDec->numFrameBuffers; i++) { + if (hFrameBuf == hDec->hImage[i]) { + index = i; + break; + } + } + } + } + + if (index < 0) { + printf ("Fail, Invalid FrameBuffer or FrameIndex.\n"); + return -1; + } + + memset (&buf, 0, sizeof (buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + buf.index = index; + buf.m.planes = planes; + buf.length = hDec->planesNum; + buf.memory = V4L2_MEMORY_DMABUF; + + for (i = 0; i < hDec->planesNum; i++) { + buf.m.planes[i].m.fd = hDec->hImage[index]->dmaFd[i]; + buf.m.planes[i].length = hDec->hImage[index]->size[i]; + } + + /* Queue Output Buffer */ + if (ioctl (hDec->fd, VIDIOC_QBUF, &buf) != 0) { + printf ("Fail, ioctl(): VIDIOC_QBUF.(Clear Display Index, index = %d)\n", + index); + return -1; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +int32_t +NX_V4l2DecFlush (NX_V4L2DEC_HANDLE hDec) +{ + enum v4l2_buf_type type; + + if (NULL == hDec) { + printf ("Fail, Invalid Handle.\n"); + return -1; + } + + type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + if (ioctl (hDec->fd, VIDIOC_STREAMOFF, &type) != 0) { + printf ("failed to ioctl: VIDIOC_STREAMOFF(Stream)\n"); + return -1; + } + + type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + if (ioctl (hDec->fd, VIDIOC_STREAMOFF, &type) != 0) { + printf ("failed to ioctl: VIDIOC_STREAMOFF(Image)\n"); + return -1; + } + + type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + if (ioctl (hDec->fd, VIDIOC_STREAMON, &type) != 0) { + printf ("Fail, ioctl(): VIDIOC_STREAMON. (Input)\n"); + return -1; + } + + type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + if (ioctl (hDec->fd, VIDIOC_STREAMON, &type) != 0) { + printf ("failed to ioctl: VIDIOC_STREAMON\n"); + return -1; + } + + { + struct v4l2_plane planes[3]; + struct v4l2_buffer buf; + int32_t i, j; + + memset (&buf, 0, sizeof (buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + buf.m.planes = planes; + buf.length = hDec->planesNum; + buf.memory = V4L2_MEMORY_DMABUF; + + for (i = 0; i < hDec->numFrameBuffers; i++) { + buf.index = i; + + for (j = 0; j < (int32_t) hDec->planesNum; j++) { + buf.m.planes[j].m.fd = hDec->hImage[i]->dmaFd[j]; + buf.m.planes[j].length = hDec->hImage[i]->size[j]; + } + + if (ioctl (hDec->fd, VIDIOC_QBUF, &buf) != 0) { + printf ("failed to ioctl: VIDIOC_QBUF(Output YUV - %d)\n", i); + return -1; + } + } + } + + return 0; +} + +/* Optional Function */ +int32_t +NX_DecGetFrameType (NX_V4L2DEC_HANDLE hDec, NX_V4L2DEC_IN * pDecIn, + uint32_t codecType, int32_t * piFrameType) +{ + uint8_t *pbyStrm = pDecIn->strmBuf; + uint32_t uPreFourByte = (uint32_t) - 1; + int32_t iFrmType = PIC_TYPE_UNKNOWN; + + if ((pbyStrm == NULL) || (piFrameType == NULL)) + return -1; + + if (!codecType) + codecType = hDec->codecType; + + switch (codecType) { + case V4L2_PIX_FMT_H264: + do { + if (pbyStrm >= (pDecIn->strmBuf + pDecIn->strmSize)) + return -1; + + uPreFourByte = (uPreFourByte << 8) + *pbyStrm++; + + if ((uPreFourByte == 0x00000001) || (uPreFourByte << 8 == 0x00000100)) { + int32_t iNaluType = pbyStrm[0] & 0x1F; + + /* Slice start code */ + if (iNaluType == 5) { + iFrmType = PIC_TYPE_IDR; + break; + } else if (iNaluType == 1) { + VLD_STREAM stStrm = { 8, pbyStrm, pDecIn->strmSize }; + + vld_get_uev (&stStrm); /* First_mb_in_slice */ + iFrmType = vld_get_uev (&stStrm); /* Slice type */ + + if (iFrmType == 0 || iFrmType == 5) + iFrmType = PIC_TYPE_P; + else if (iFrmType == 1 || iFrmType == 6) + iFrmType = PIC_TYPE_B; + else if (iFrmType == 2 || iFrmType == 7) + iFrmType = PIC_TYPE_I; + break; + } + } + } while (1); + break; + + case V4L2_PIX_FMT_MPEG2: + do { + if (pbyStrm >= (pDecIn->strmBuf + pDecIn->strmSize)) + return -1; + + uPreFourByte = (uPreFourByte << 8) + *pbyStrm++; + + /* Picture start code */ + if (uPreFourByte == 0x00000100) { + VLD_STREAM stStrm = { 0, pbyStrm, pDecIn->strmSize }; + + vld_flush_bits (&stStrm, 10); /* temporal_reference */ + iFrmType = vld_get_bits (&stStrm, 3); /* picture_coding_type */ + + if (iFrmType == 1) + iFrmType = PIC_TYPE_I; + else if (iFrmType == 2) + iFrmType = PIC_TYPE_P; + else if (iFrmType == 3) + iFrmType = PIC_TYPE_B; + break; + } + } while (1); + break; + + case V4L2_PIX_FMT_WVC1: + if (hDec == NULL || hDec->seqDataSize == 0) + return -1; + + { + VLD_STREAM stStrm = { 0, pbyStrm, pDecIn->strmSize }; + + if (hDec->iInterlace != NONE_FIELD) { + /* FCM */ + if (vld_get_bits (&stStrm, 1) == 1) + vld_flush_bits (&stStrm, 1); + } + + iFrmType = vld_get_bits (&stStrm, 1); + if (iFrmType == 0) { + iFrmType = PIC_TYPE_P; + } else { + iFrmType = vld_get_bits (&stStrm, 1); + if (iFrmType == 0) { + iFrmType = PIC_TYPE_B; + } else { + iFrmType = vld_get_bits (&stStrm, 1); + if (iFrmType == 0) { + iFrmType = PIC_TYPE_I; + } else { + iFrmType = vld_get_bits (&stStrm, 1); + if (iFrmType == 0) + iFrmType = PIC_TYPE_VC1_BI; + else + iFrmType = PIC_TYPE_SKIP; + } + } + } + } + break; + + case V4L2_PIX_FMT_WMV9: + if (hDec == NULL || hDec->seqDataSize == 0) + return -1; + + { + int32_t rangeRed; + int32_t fInterPFlag; + int32_t maxBframes; + VLD_STREAM stStrm = { 24, hDec->pSeqData, hDec->seqDataSize }; + + /* Parse Sequece Header */ + rangeRed = vld_get_bits (&stStrm, 1); + maxBframes = vld_get_bits (&stStrm, 3); + vld_flush_bits (&stStrm, 2); + fInterPFlag = vld_get_bits (&stStrm, 1); + + /* Parse Frame Header */ + stStrm.dwUsedBits = 0; + stStrm.pbyStart = pbyStrm; + stStrm.dwPktSize = pDecIn->strmSize; + + if (fInterPFlag == 1) + vld_flush_bits (&stStrm, 1); /* INTERPFRM */ + + vld_flush_bits (&stStrm, 2); /* FRMCNT */ + + if (rangeRed == 1) + vld_flush_bits (&stStrm, 1); /* RANGEREDFRM */ + + iFrmType = vld_get_bits (&stStrm, 1); + if (maxBframes > 0) { + if (iFrmType == 1) { + iFrmType = PIC_TYPE_P; + } else { + iFrmType = vld_get_bits (&stStrm, 1); + if (iFrmType == 1) + iFrmType = PIC_TYPE_I; + else if (iFrmType == 0) + iFrmType = PIC_TYPE_B; /* or BI */ + } + } else { + if (iFrmType == 0) + iFrmType = PIC_TYPE_I; + else if (iFrmType == 1) + iFrmType = PIC_TYPE_P; + } + + } + break; + + default: + return -1; + } + + *piFrameType = iFrmType; + + return 0; +} diff --git a/src/nx_video_enc.c b/src/nx_video_enc.c new file mode 100644 index 0000000..234d185 --- /dev/null +++ b/src/nx_video_enc.c @@ -0,0 +1,661 @@ +/* + * Copyright (C) 2016 Nexell Co. All Rights Reserved + * Nexell Co. Proprietary & Confidential + * + * NEXELL INFORMS THAT THIS CODE AND INFORMATION IS PROVIDED "AS IS" BASE + * AND WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS + * FOR A PARTICULAR PURPOSE. + * + * File : nx_video_enc.c + * Brief : V4L2 Video Encoder + * Author : SungWon Jo (doriya@nexell.co.kr) + * History : 2016.04.25 : Create + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +/*----------------------------------------------------------------------------*/ +#define NX_V4L2_ENC_NAME "nx-vpu-enc" +#define VIDEODEV_MINOR_MAX 63 +#define MAX_CTRL_NUM 32 +#define STREAM_BUFFER_NUM 1 + + +struct NX_V4L2ENC_INFO +{ + int fd; + uint32_t codecType; + int32_t planesNum; + int32_t outBuffCnt; + int32_t frameCnt; + uint8_t *pSeqBuf; + int32_t seqSize; + NX_MEMORY_HANDLE hBitStream[STREAM_BUFFER_NUM]; + NX_VID_MEMORY_HANDLE hImg[MAX_FRAME_BUFFER_NUM]; +}; + + +/* + * Find Device Node + */ + +/*----------------------------------------------------------------------------*/ +static int +V4l2EncOpen (void) +{ + int fd = -1; + + bool found = false; + struct stat s; + FILE *stream_fd; + char filename[64], name[64]; + int i = 0; + + while (!found && (i <= VIDEODEV_MINOR_MAX)) { + /* video device node */ + sprintf (filename, "/dev/video%d", i); + + /* if the node is video device */ + if ((lstat (filename, &s) == 0) && S_ISCHR (s.st_mode) + && ((int) ((unsigned short) (s.st_rdev) >> 8) == 81)) { + /* open sysfs entry */ + sprintf (filename, "/sys/class/video4linux/video%d/name", i); + stream_fd = fopen (filename, "r"); + if (stream_fd == NULL) { + printf ("failed to open sysfs entry for videodev \n"); + i++; + continue; + } + + /* read sysfs entry for device name */ + if (fgets (name, sizeof (name), stream_fd) == 0) { + printf ("failed to read sysfs entry for videodev\n"); + } else { + if (strncmp (name, NX_V4L2_ENC_NAME, strlen (NX_V4L2_ENC_NAME)) == 0) { + printf ("node found for device %s: /dev/video%d\n", NX_V4L2_ENC_NAME, + i); + found = true; + } + } + + fclose (stream_fd); + } + + i++; + } + + if (found) { + sprintf (filename, "/dev/video%d", i - 1); + fd = open (filename, O_RDWR); + } + + return fd; +} + +/* + * V4L2 Encoder + */ + +/*----------------------------------------------------------------------------*/ +NX_V4L2ENC_HANDLE +NX_V4l2EncOpen (uint32_t codecType) +{ + NX_V4L2ENC_HANDLE hEnc = + (NX_V4L2ENC_HANDLE) malloc (sizeof (struct NX_V4L2ENC_INFO)); + + memset (hEnc, 0, sizeof (struct NX_V4L2ENC_INFO)); + + hEnc->fd = V4l2EncOpen (); + if (hEnc->fd <= 0) { + printf ("failed to open video encoder device\n"); + goto ERROR_EXIT; + } + + /* Query capabilities of Device */ + { + struct v4l2_capability cap; + + memset (&cap, 0, sizeof (cap)); + + if (ioctl (hEnc->fd, VIDIOC_QUERYCAP, &cap) != 0) { + printf ("failed to ioctl: VIDIOC_QUERYCAP\n"); + goto ERROR_EXIT; + } + } + + hEnc->codecType = codecType; + + return hEnc; + +ERROR_EXIT: + free (hEnc); + + return NULL; +} + +/*----------------------------------------------------------------------------*/ +int32_t +NX_V4l2EncClose (NX_V4L2ENC_HANDLE hEnc) +{ + enum v4l2_buf_type type; + int32_t ret = 0; + int i; + + if (NULL == hEnc) { + printf ("Fail, Invalid Handle.\n"); + return -1; + } + + type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + if (ioctl (hEnc->fd, VIDIOC_STREAMOFF, &type) != 0) { + printf ("Fail, ioctl(): VIDIOC_STREAMOFF - Stream\n"); + ret = -1; + } + + type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + if (ioctl (hEnc->fd, VIDIOC_STREAMOFF, &type) != 0) { + printf ("Fail, ioctl(): VIDIOC_STREAMOFF - Image\n"); + ret = -1; + } + + for (i = 0; i < hEnc->outBuffCnt; i++) + NX_FreeMemory (hEnc->hBitStream[i]); + + if (hEnc->pSeqBuf) + free (hEnc->pSeqBuf); + + close (hEnc->fd); + + free (hEnc); + + return ret; +} + +/*----------------------------------------------------------------------------*/ +int32_t +NX_V4l2EncInit (NX_V4L2ENC_HANDLE hEnc, NX_V4L2ENC_PARA * pEncPara) +{ + int inWidth = pEncPara->width; + int inHeight = pEncPara->height; + int i; + + if (NULL == hEnc) { + printf ("Fail, Invalid Handle.\n"); + return -1; + } + + /* Set Stream Format */ + { + struct v4l2_format fmt; + + memset (&fmt, 0, sizeof (fmt)); + + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.pixelformat = hEnc->codecType; + fmt.fmt.pix_mp.plane_fmt[0].sizeimage = inWidth * inHeight * 3 / 4; + + if (ioctl (hEnc->fd, VIDIOC_S_FMT, &fmt) != 0) { + printf ("failed to ioctl: VIDIOC_S_FMT(Stream)\n"); + return -1; + } + } + + /* Set Image Format */ + { + struct v4l2_format fmt; + + memset (&fmt, 0, sizeof (fmt)); + + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.pixelformat = pEncPara->imgFormat; + fmt.fmt.pix_mp.width = inWidth; + fmt.fmt.pix_mp.height = inHeight; + fmt.fmt.pix_mp.num_planes = pEncPara->imgPlaneNum; + + if (ioctl (hEnc->fd, VIDIOC_S_FMT, &fmt) != 0) { + printf ("Failed to s_fmt : YUV \n"); + return -1; + } + + hEnc->planesNum = pEncPara->imgPlaneNum; + } + + /* Set Encoder Parameter */ + { + if (hEnc->codecType != V4L2_PIX_FMT_MJPEG) { + struct v4l2_ext_control ext_ctrl[MAX_CTRL_NUM]; + struct v4l2_ext_controls ext_ctrls; + + ext_ctrl[0].id = V4L2_CID_MPEG_VIDEO_FPS_NUM; + ext_ctrl[0].value = pEncPara->fpsNum; + ext_ctrl[1].id = V4L2_CID_MPEG_VIDEO_FPS_DEN; + ext_ctrl[1].value = pEncPara->fpsDen; + ext_ctrl[2].id = V4L2_CID_MPEG_VIDEO_GOP_SIZE; + ext_ctrl[2].value = pEncPara->keyFrmInterval; + + ext_ctrl[3].id = V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB; + ext_ctrl[3].value = pEncPara->numIntraRefreshMbs; + ext_ctrl[4].id = V4L2_CID_MPEG_VIDEO_SEARCH_RANGE; + ext_ctrl[4].value = pEncPara->searchRange; + + ext_ctrl[5].id = V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE; + ext_ctrl[5].value = (pEncPara->bitrate) ? (1) : (0); + ext_ctrl[6].id = V4L2_CID_MPEG_VIDEO_BITRATE; + ext_ctrl[6].value = pEncPara->bitrate; + ext_ctrl[7].id = V4L2_CID_MPEG_VIDEO_VBV_SIZE; + ext_ctrl[7].value = pEncPara->rcVbvSize; + ext_ctrl[8].id = V4L2_CID_MPEG_VIDEO_RC_DELAY; + ext_ctrl[8].value = pEncPara->RCDelay; + ext_ctrl[9].id = V4L2_CID_MPEG_VIDEO_RC_GAMMA_FACTOR; + ext_ctrl[9].value = pEncPara->gammaFactor; + ext_ctrl[10].id = V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE; + ext_ctrl[10].value = pEncPara->disableSkip; + + if (hEnc->codecType == V4L2_PIX_FMT_H264) { + ext_ctrl[11].id = V4L2_CID_MPEG_VIDEO_H264_AUD_INSERT; + ext_ctrl[11].value = pEncPara->enableAUDelimiter; + ext_ctrl[12].id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP; + ext_ctrl[12].value = pEncPara->maximumQp; + + ext_ctrls.count = 13; + + if ((pEncPara->bitrate == 0) || (pEncPara->initialQp > 0)) { + ext_ctrl[13].id = V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP; + ext_ctrl[13].value = pEncPara->initialQp; + ext_ctrl[14].id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP; + ext_ctrl[14].value = pEncPara->initialQp; + + ext_ctrls.count += 2; + } + //ext_ctrl[15].id = V4L2_CID_MPEG_VIDEO_H264_PROFILE; + //ext_ctrl[15].value = ; + } else if (hEnc->codecType == V4L2_PIX_FMT_MPEG4) { + ext_ctrl[11].id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP; + ext_ctrl[11].value = pEncPara->maximumQp; + + ext_ctrls.count = 12; + + if ((pEncPara->bitrate == 0) || (pEncPara->initialQp > 0)) { + ext_ctrl[12].id = V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP; + ext_ctrl[12].value = pEncPara->initialQp; + ext_ctrl[13].id = V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP; + ext_ctrl[13].value = pEncPara->initialQp; + + ext_ctrls.count += 2; + } + } else if (hEnc->codecType == V4L2_PIX_FMT_H263) { + ext_ctrl[11].id = V4L2_CID_MPEG_VIDEO_H263_PROFILE; + ext_ctrl[11].value = pEncPara->profile; + ext_ctrl[12].id = V4L2_CID_MPEG_VIDEO_H263_MAX_QP; + ext_ctrl[12].value = pEncPara->maximumQp; + + ext_ctrls.count = 13; + + if ((pEncPara->bitrate == 0) || (pEncPara->initialQp > 0)) { + ext_ctrl[13].id = V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP; + ext_ctrl[13].value = pEncPara->initialQp; + ext_ctrl[14].id = V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP; + ext_ctrl[14].value = pEncPara->initialQp; + + ext_ctrls.count += 2; + } + } + + ext_ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG; + ext_ctrls.controls = ext_ctrl; + + if (ioctl (hEnc->fd, VIDIOC_S_EXT_CTRLS, &ext_ctrls) != 0) { + printf ("Fail, ioctl(): VIDIOC_S_EXT_CTRLS\n"); + return -1; + } + } else { + struct v4l2_control ctrl; + + ctrl.id = V4L2_CID_JPEG_COMPRESSION_QUALITY; + ctrl.value = pEncPara->jpgQuality; + + if (ioctl (hEnc->fd, VIDIOC_S_CTRL, &ctrl) != 0) { + printf ("Fail, ioctl(): VIDIOC_S_CTRL\n"); + return -1; + } + } + } + + /* Malloc Input Image Buffer */ + { + struct v4l2_requestbuffers req; + int32_t bufferCount = pEncPara->imgBufferNum; + + /* IOCTL : VIDIOC_REQBUFS For Input Yuv */ + memset (&req, 0, sizeof (req)); + req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + req.count = bufferCount; + req.memory = V4L2_MEMORY_DMABUF; /* V4L2_MEMORY_USERPTR, V4L2_MEMORY_DMABUF, V4L2_MEMORY_MMAP */ + + if (ioctl (hEnc->fd, VIDIOC_REQBUFS, &req) != 0) { + printf ("failed to ioctl: VIDIOC_REQBUFS(Input YUV)\n"); + return -1; + } + } + + /* Malloc Output Stream Buffer */ + { + struct v4l2_requestbuffers req; + int bufferCount = STREAM_BUFFER_NUM; + + /* IOCTL : VIDIOC_REQBUFS For Output Stream */ + memset (&req, 0, sizeof (req)); + req.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + req.count = bufferCount; + req.memory = V4L2_MEMORY_DMABUF; + + if (ioctl (hEnc->fd, VIDIOC_REQBUFS, &req) != 0) { + printf ("failed to ioctl: VIDIOC_REQBUFS(Output ES)\n"); + return -1; + } + + /* Allocate Output Buffer */ + for (i = 0; i < bufferCount; i++) { + hEnc->hBitStream[i] = + NX_AllocateMemory (inWidth * inHeight * 3 / 4, 4096); + if (hEnc->hBitStream[i] == NULL) { + printf ("Failed to allocate stream buffer(%d, %d)\n", i, + inWidth * inHeight * 3 / 4); + return -1; + } + + if (NX_MapMemory (hEnc->hBitStream[i]) != 0) { + printf ("Stream memory Mapping Failed\n"); + return -1; + } + } + + hEnc->outBuffCnt = bufferCount; + } + + /* Get Sequence header */ + { + struct v4l2_plane planes[1]; + struct v4l2_buffer buf; + enum v4l2_buf_type type; + + memset (&buf, 0, sizeof (buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + buf.m.planes = planes; + buf.length = 1; + buf.memory = V4L2_MEMORY_DMABUF; + buf.index = 0; + + buf.m.planes[0].m.fd = hEnc->hBitStream[0]->dmaFd; + //buf.m.planes[0].m.userptr = (unsigned long)hEnc->hBitStream[0]->pBuffer; + buf.m.planes[0].length = hEnc->hBitStream[0]->size; + buf.m.planes[0].bytesused = hEnc->hBitStream[0]->size; + buf.m.planes[0].data_offset = 0; + + if (ioctl (hEnc->fd, VIDIOC_QBUF, &buf) != 0) { + printf ("failed to ioctl: VIDIOC_QBUF(Header)\n"); + return -1; + } + + type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + if (ioctl (hEnc->fd, VIDIOC_STREAMON, &type) != 0) { + printf ("failed to ioctl: VIDIOC_STREAMON\n"); + return -1; + } + + if (ioctl (hEnc->fd, VIDIOC_DQBUF, &buf) != 0) { + printf ("failed to ioctl: VIDIOC_DQBUF(Header)\n"); + return -1; + } + + if (buf.m.planes[0].bytesused > 0) { + hEnc->seqSize = buf.m.planes[0].bytesused; + hEnc->pSeqBuf = (uint8_t *) malloc (hEnc->seqSize); + memcpy (hEnc->pSeqBuf, (void *) hEnc->hBitStream[buf.index]->pBuffer, + hEnc->seqSize); + } + } + + /* Input Image Stream On */ + { + enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + + if (ioctl (hEnc->fd, VIDIOC_STREAMON, &type) != 0) { + printf ("Fail, ioctl(): VIDIOC_STREAMON(Image)\n"); + return -1; + } + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +int32_t +NX_V4l2EncGetSeqInfo (NX_V4L2ENC_HANDLE hEnc, uint8_t ** ppSeqBuf, + int32_t * iSeqSize) +{ + if (hEnc == NULL) { + printf ("Fail, Invalid Handle.\n"); + return -1; + } + + *ppSeqBuf = hEnc->pSeqBuf; + *iSeqSize = hEnc->seqSize; + + return 0; +} + +/*----------------------------------------------------------------------------*/ +int32_t +NX_V4l2EncEncodeFrame (NX_V4L2ENC_HANDLE hEnc, NX_V4L2ENC_IN * pEncIn, + NX_V4L2ENC_OUT * pEncOut) +{ + struct v4l2_plane planes[3]; + struct v4l2_buffer buf; + int i; + + if (hEnc == NULL) { + printf ("Fail, Invalid Handle.\n"); + return -1; + } + + memset (pEncOut, 0, sizeof (NX_V4L2ENC_OUT)); + + /* Set Encode Parameter */ + if (hEnc->codecType != V4L2_PIX_FMT_MJPEG) { + struct v4l2_control ctrl; + + ctrl.id = V4L2_CID_MPEG_VIDEO_FORCE_I_FRAME; + ctrl.value = pEncIn->forcedIFrame; + + if (ioctl (hEnc->fd, VIDIOC_S_CTRL, &ctrl) != 0) { + printf ("failed to ioctl: Forced Intra Frame\n"); + return -1; + } + + ctrl.id = V4L2_CID_MPEG_VIDEO_FORCE_SKIP_FRAME; + ctrl.value = pEncIn->forcedSkipFrame; + + if (ioctl (hEnc->fd, VIDIOC_S_CTRL, &ctrl) != 0) { + printf ("failed to ioctl: Forced Skip Frame\n"); + return -1; + } + + if (hEnc->codecType == V4L2_PIX_FMT_H264) + ctrl.id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP; + else if (hEnc->codecType == V4L2_PIX_FMT_MPEG4) + ctrl.id = V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP; + else if (hEnc->codecType == V4L2_PIX_FMT_H263) + ctrl.id = V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP; + + ctrl.value = pEncIn->quantParam; + + if (ioctl (hEnc->fd, VIDIOC_S_CTRL, &ctrl) != 0) { + printf ("failed to ioctl: Forced QP\n"); + return -1; + } + } + + /* Queue Input Buffer */ + memset (&buf, 0, sizeof (buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + buf.m.planes = planes; + buf.length = hEnc->planesNum; + buf.memory = V4L2_MEMORY_DMABUF; + buf.index = pEncIn->imgIndex; + + for (i = 0; i < hEnc->planesNum; i++) { + buf.m.planes[i].m.fd = pEncIn->pImage->dmaFd[i]; + buf.m.planes[i].length = pEncIn->pImage->size[i]; + } + + if (ioctl (hEnc->fd, VIDIOC_QBUF, &buf) != 0) { + printf ("Fail, ioctl(): VIDIOC_QBUF(Image)\n"); + return -1; + } + + /* Queue Output Bitstream Buffer */ + { + int idx = hEnc->frameCnt % hEnc->outBuffCnt; + + memset (&buf, 0, sizeof (buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + buf.m.planes = planes; + buf.length = 1; + buf.memory = V4L2_MEMORY_DMABUF; + buf.index = idx; + + buf.m.planes[0].m.fd = hEnc->hBitStream[idx]->dmaFd; + //buf.m.planes[0].m.userptr = (unsigned long)hBitStream[idx]->pBuffer; + buf.m.planes[0].length = hEnc->hBitStream[idx]->size; + buf.m.planes[0].bytesused = hEnc->hBitStream[idx]->size; + buf.m.planes[0].data_offset = 0; + + if (ioctl (hEnc->fd, VIDIOC_QBUF, &buf) != 0) { + printf ("failed to ioctl: VIDIOC_QBUF(Stream)\n"); + return -1; + } + } + + /* Dequeue Input Image Buffer */ + { + memset (&buf, 0, sizeof (buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + buf.m.planes = planes; + buf.length = hEnc->planesNum; + buf.memory = V4L2_MEMORY_DMABUF; + + if (ioctl (hEnc->fd, VIDIOC_DQBUF, &buf) != 0) { + printf ("Fail, ioctl(): VIDIOC_DQBUF(Input Image)\n"); + return -1; + } + } + + /* Dequeue Output Stream Buffer */ + { + memset (&buf, 0, sizeof (buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + buf.m.planes = planes; + buf.length = 1; + buf.memory = V4L2_MEMORY_DMABUF; //V4L2_MEMORY_USERPTR; + + if (ioctl (hEnc->fd, VIDIOC_DQBUF, &buf) != 0) { + printf ("Fail, ioctl(): VIDIOC_DQBUF(Compressed Stream)\n"); + return -1; + } + + pEncOut->strmBuf = (uint8_t *) hEnc->hBitStream[buf.index]->pBuffer; + pEncOut->strmSize = buf.m.planes[0].bytesused; + + if (buf.flags & V4L2_BUF_FLAG_KEYFRAME) + pEncOut->frameType = PIC_TYPE_I; + else if (buf.flags & V4L2_BUF_FLAG_PFRAME) + pEncOut->frameType = + (pEncIn->forcedSkipFrame == 0) ? (PIC_TYPE_P) : (PIC_TYPE_SKIP); + else if (buf.flags & V4L2_BUF_FLAG_BFRAME) + pEncOut->frameType = PIC_TYPE_B; + else + pEncOut->frameType = PIC_TYPE_UNKNOWN; + } + + hEnc->frameCnt++; + + return 0; +} + +int32_t +NX_V4l2EncChangeParameter (NX_V4L2ENC_HANDLE hEnc, + NX_V4L2ENC_CHG_PARA * pChgPara) +{ + struct v4l2_control ctrl; + + if (hEnc == NULL) { + printf ("Fail, Invalid Handle.\n"); + return -1; + } + + if (pChgPara->chgFlg & VID_CHG_KEYFRAME) { + ctrl.id = V4L2_CID_MPEG_VIDEO_GOP_SIZE; + ctrl.value = pChgPara->keyFrmInterval; + + if (ioctl (hEnc->fd, VIDIOC_S_CTRL, &ctrl) != 0) { + printf ("failed to ioctl: Change Key Frame Interval\n"); + return -1; + } + } + + if (pChgPara->chgFlg & VID_CHG_BITRATE) { + ctrl.id = V4L2_CID_MPEG_VIDEO_BITRATE; + ctrl.value = pChgPara->bitrate; + + if (ioctl (hEnc->fd, VIDIOC_S_CTRL, &ctrl) != 0) { + printf ("failed to ioctl: Change Bitrate\n"); + return -1; + } + } + + if (pChgPara->chgFlg & VID_CHG_FRAMERATE) { + ctrl.id = V4L2_CID_MPEG_VIDEO_FPS_NUM; + ctrl.value = pChgPara->fpsNum; + + if (ioctl (hEnc->fd, VIDIOC_S_CTRL, &ctrl) != 0) { + printf ("failed to ioctl: Change Fps Number\n"); + return -1; + } + + ctrl.id = V4L2_CID_MPEG_VIDEO_FPS_DEN; + ctrl.value = pChgPara->fpsDen; + + if (ioctl (hEnc->fd, VIDIOC_S_CTRL, &ctrl) != 0) { + printf ("failed to ioctl: Change Fps Density\n"); + return -1; + } + } + + if (pChgPara->chgFlg & VID_CHG_INTRARF) { + ctrl.id = V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB; + ctrl.value = pChgPara->numIntraRefreshMbs; + + if (ioctl (hEnc->fd, VIDIOC_S_CTRL, &ctrl) != 0) { + printf ("failed to ioctl: Change Intra Refresh Mbs\n"); + return -1; + } + } + + return 0; +}