From: Zhao Halley Date: Fri, 30 Nov 2012 03:20:58 +0000 (+0800) Subject: import ext/codecparsers instead of git submodule X-Git-Tag: accepted/2.0/20130307.032524^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=25bcbad01ef070fefe19f3e0ac41a7c91029404b;p=profile%2Fivi%2Fgstreamer-vaapi.git import ext/codecparsers instead of git submodule --- diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e40ceed..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "ext/codecparsers"] - path = ext/codecparsers - url = git://gitorious.org/vaapi/gstreamer-codecparsers.git diff --git a/autogen.sh b/autogen.sh index 4314352..2df1e30 100755 --- a/autogen.sh +++ b/autogen.sh @@ -15,16 +15,16 @@ cd "$srcdir" mkdir -p m4 -GIT=`which git` -if test -z "$GIT"; then - echo "*** No git found ***" - exit 1 -else - if test ! -f ext/codecparsers/autogen.sh; then - $GIT submodule init - fi - $GIT submodule update -fi +## GIT=`which git` +## if test -z "$GIT"; then +## echo "*** No git found ***" +## exit 1 +## else +## if test ! -f ext/codecparsers/autogen.sh; then +## $GIT submodule init +## fi +## $GIT submodule update +## fi GTKDOCIZE=`which gtkdocize` if test -z "$GTKDOCIZE"; then diff --git a/ext/codecparsers b/ext/codecparsers deleted file mode 160000 index 73d6aab..0000000 --- a/ext/codecparsers +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 73d6aab46c14d943f2a0238e70812d775f06ffee diff --git a/ext/codecparsers/COPYING.LIB b/ext/codecparsers/COPYING.LIB new file mode 100644 index 0000000..eb685a5 --- /dev/null +++ b/ext/codecparsers/COPYING.LIB @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/ext/codecparsers/INSTALL b/ext/codecparsers/INSTALL new file mode 100644 index 0000000..b42a17a --- /dev/null +++ b/ext/codecparsers/INSTALL @@ -0,0 +1,182 @@ +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. diff --git a/ext/codecparsers/Makefile.am b/ext/codecparsers/Makefile.am new file mode 100644 index 0000000..63df8d2 --- /dev/null +++ b/ext/codecparsers/Makefile.am @@ -0,0 +1,11 @@ +ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} + +AUTOMAKE_OPTIONS = foreign + +SUBDIRS = gst-libs tests + +# Extra clean files so that maintainer-clean removes *everything* +MAINTAINERCLEANFILES = \ + aclocal.m4 compile config.guess config.sub \ + configure depcomp install-sh ltmain.sh \ + Makefile.in missing config.h.in diff --git a/ext/codecparsers/TAG b/ext/codecparsers/TAG new file mode 100644 index 0000000..eed050b --- /dev/null +++ b/ext/codecparsers/TAG @@ -0,0 +1 @@ +0b3e0ed080fabe87ead446609bc688f5279437ee diff --git a/ext/codecparsers/autogen.sh b/ext/codecparsers/autogen.sh new file mode 100755 index 0000000..e5a49c4 --- /dev/null +++ b/ext/codecparsers/autogen.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +PROJECT="codecparsers" + +test -n "$srcdir" || srcdir="`dirname \"$0\"`" +test -n "$srcdir" || srcdir=. + +if ! test -f "$srcdir/configure.ac"; then + echo "Failed to find the top-level $PROJECT directory" + exit 1 +fi + +olddir="`pwd`" +cd "$srcdir" + +mkdir -p m4 + +AUTORECONF=`which autoreconf` +if test -z $AUTORECONF; then + echo "*** No autoreconf found ***" + exit 1 +else + autoreconf -v --install || exit $? +fi + +cd "$olddir" + +if test -z "$NO_CONFIGURE"; then + $srcdir/configure "$@" && echo "Now type 'make' to compile $PROJECT." +fi diff --git a/ext/codecparsers/configure.ac b/ext/codecparsers/configure.ac new file mode 100644 index 0000000..dd41609 --- /dev/null +++ b/ext/codecparsers/configure.ac @@ -0,0 +1,100 @@ +# codecparsers package version number +m4_define([gst_codecparsers_major_version], [0]) +m4_define([gst_codecparsers_minor_version], [10]) +m4_define([gst_codecparsers_micro_version], [23]) +m4_define([gst_codecparsers_pre_version], [1]) +m4_define([gst_codecparsers_version], + [gst_codecparsers_major_version.gst_codecparsers_minor_version.gst_codecparsers_micro_version]) +m4_if(gst_codecparsers_pre_version, [0], [], [ +m4_append([gst_codecparsers_version], gst_codecparsers_pre_version, [.pre]) +]) + +# glib version number +m4_define([glib_major_version], [2]) +m4_define([glib_minor_version], [28]) +m4_define([glib_micro_version], [0]) +m4_define([glib_major_minor_version], + [glib_major_version.glib_minor_version]) +m4_define([glib_version], + [glib_major_version.glib_minor_version.glib_micro_version]) + +# gst version number +m4_define([gst_major_version], [0]) +m4_define([gst_minor_version], [10]) +m4_define([gst_micro_version], [36]) +m4_define([gst_major_minor_version], + [gst_major_version.gst_minor_version]) +m4_define([gst_version], + [gst_major_version.gst_minor_version.gst_micro_version]) + +# gst plugins-base version number +m4_define([gst_plugins_base_major_version], [0]) +m4_define([gst_plugins_base_minor_version], [10]) +m4_define([gst_plugins_base_micro_version], [31]) +m4_define([gst_plugins_base_version], + [gst_plugins_base_major_version.gst_plugins_base_minor_version.gst_plugins_base_micro_version]) + +AC_PREREQ([2.58]) +AC_INIT([gst_codecparsers], [gst_codecparsers_version], + [gwenole.beauchesne@intel.com], + [gstreamer-codecparsers]) + +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_SRCDIR([Makefile.am]) +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_AUX_DIR([build-aux]) + +AC_CANONICAL_TARGET + +AM_INIT_AUTOMAKE([1.9 tar-ustar no-dist-gzip dist-bzip2]) + +dnl Versions for GStreamer and plugins-base +GST_MAJORMINOR=gst_major_minor_version +GST_API_VERSION=$GST_MAJORMINOR +GST_VERSION_REQUIRED=gst_version +GST_PLUGINS_BASE_VERSION_REQUIRED=gst_plugins_base_version +AC_SUBST(GST_MAJORMINOR) +AC_SUBST(GST_API_VERSION) +AC_SUBST(GST_VERSION_REQUIRED) +AC_SUBST(GST_PLUGINS_BASE_VERSION_REQUIRED) + +dnl Use pretty build output with automake >= 1.11 +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])], [ + AM_DEFAULT_VERBOSITY=1 + AC_SUBST(AM_DEFAULT_VERBOSITY) +]) + +dnl Check for tools +AC_PROG_CC +AM_PROG_CC_C_O + +dnl Initialize libtool +LT_PREREQ([2.2]) +LT_INIT + +dnl Check for GLib +GLIB_VERSION_REQUIRED=glib_version +PKG_CHECK_MODULES([GLIB], [glib-2.0 >= $GLIB_VERSION_REQUIRED]) +AC_SUBST(GLIB_VERSION_REQUIRED) + +dnl GStreamer Core +PKG_CHECK_MODULES([GST], [gstreamer-$GST_MAJORMINOR >= gst_version]) +PKG_CHECK_MODULES([GST_BASE], [gstreamer-base-$GST_MAJORMINOR >= gst_version]) +PKG_CHECK_MODULES([GST_CHECK], [gstreamer-check-$GST_MAJORMINOR]) + +dnl GST_ALL_LDFLAGS: +dnl LDFLAGS really should only contain flags, not libs - they get added before +dnl whatevertarget_LIBS and -L flags here affect the rest of the linking +GST_ALL_LDFLAGS="-no-undefined" +AC_SUBST(GST_ALL_LDFLAGS) + +AC_CONFIG_FILES([ + Makefile + gst-libs/Makefile + gst-libs/gst/Makefile + gst-libs/gst/codecparsers/Makefile + tests/Makefile + tests/check/Makefile + tests/check/libs/Makefile +]) +AC_OUTPUT diff --git a/ext/codecparsers/gst-libs/Makefile.am b/ext/codecparsers/gst-libs/Makefile.am new file mode 100644 index 0000000..d5356a6 --- /dev/null +++ b/ext/codecparsers/gst-libs/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = gst + +# Extra clean files so that maintainer-clean removes *everything* +MAINTAINERCLEANFILES = Makefile.in diff --git a/ext/codecparsers/gst-libs/gst/Makefile.am b/ext/codecparsers/gst-libs/gst/Makefile.am new file mode 100644 index 0000000..125d345 --- /dev/null +++ b/ext/codecparsers/gst-libs/gst/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = codecparsers + +# Extra clean files so that maintainer-clean removes *everything* +MAINTAINERCLEANFILES = Makefile.in diff --git a/ext/codecparsers/gst-libs/gst/codecparsers/Makefile.am b/ext/codecparsers/gst-libs/gst/codecparsers/Makefile.am new file mode 100644 index 0000000..74ab273 --- /dev/null +++ b/ext/codecparsers/gst-libs/gst/codecparsers/Makefile.am @@ -0,0 +1,45 @@ +lib_LTLIBRARIES = libgstcodecparsers-@GST_API_VERSION@.la + +libgstcodecparsers_@GST_API_VERSION@_la_SOURCES = \ + gstmpegvideoparser.c gsth264parser.c gstvc1parser.c gstmpeg4parser.c \ + gstjpegparser.c \ + parserutils.c + +libgstcodecparsers_@GST_API_VERSION@includedir = \ + $(includedir)/gstreamer-@GST_API_VERSION@/gst/codecparsers + +noinst_HEADERS = parserutils.h + +libgstcodecparsers_@GST_API_VERSION@include_HEADERS = \ + gstmpegvideoparser.h gsth264parser.h gstvc1parser.h gstmpeg4parser.h \ + gstjpegparser.h + +libgstcodecparsers_@GST_API_VERSION@_la_CFLAGS = \ + $(GST_PLUGINS_BAD_CFLAGS) \ + -DGST_USE_UNSTABLE_API \ + $(GST_CFLAGS) + +libgstcodecparsers_@GST_API_VERSION@_la_LIBADD = \ + $(GST_BASE_LIBS) \ + $(GST_LIBS) + +libgstcodecparsers_@GST_API_VERSION@_la_LDFLAGS = \ + $(GST_LIB_LDFLAGS) \ + $(GST_ALL_LDFLAGS) \ + $(GST_LT_LDFLAGS) + +Android.mk: $(BUILT_SOURCES) Makefile.am + androgenizer -:PROJECT libgstcodecparsers -:STATIC libgstcodecparsers-@GST_API_VERSION@ \ + -:TAGS eng debug \ + -:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \ + -:SOURCES $(libgstcodecparsers_@GST_API_VERSION@_la_SOURCES) \ + $(built_sources) \ + -:CFLAGS $(DEFS) $(libgstcodecparsers_@GST_API_VERSION@_la_CFLAGS) \ + -:LDFLAGS $(libgstcodecparsers_@GST_API_VERSION@_la_LDFLAGS) \ + $(libgstcodecparsers@GST_API_VERSION@_la_LIBADD) \ + -ldl \ + -:HEADER_TARGET gstreamer-@GST_API_VERSION@/gst/codecparsers \ + -:HEADERS $(libgstcodecparsersinclude_HEADERS) \ + $(built_headers) \ + -:PASSTHROUGH LOCAL_ARM_MODE:=arm \ + > $@ diff --git a/ext/codecparsers/gst-libs/gst/codecparsers/gsth264parser.c b/ext/codecparsers/gst-libs/gst/codecparsers/gsth264parser.c new file mode 100644 index 0000000..572f33a --- /dev/null +++ b/ext/codecparsers/gst-libs/gst/codecparsers/gsth264parser.c @@ -0,0 +1,1980 @@ +/* Gstreamer + * Copyright (C) <2011> Intel Corporation + * Copyright (C) <2011> Collabora Ltd. + * Copyright (C) <2011> Thibault Saunier + * + * Some bits C-c,C-v'ed and s/4/3 from h264parse and videoparsers/h264parse.c: + * Copyright (C) <2010> Mark Nauwelaerts + * Copyright (C) <2010> Collabora Multimedia + * Copyright (C) <2010> Nokia Corporation + * + * (C) 2005 Michal Benes + * (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/** + * SECTION:gsth264parser + * @short_description: Convenience library for h264 video + * bitstream parsing. + * + * It offers you bitstream parsing in AVC mode or not. To identify Nals in a bitstream and + * parse its headers, you should call: + * + * + * #gst_h264_parser_identify_nalu to identify the following nalu in not AVC bitstreams + * + * + * #gst_h264_parser_identify_nalu_avc to identify the nalu in AVC bitstreams + * + * + * + * Then, depending on the #GstH264NalUnitType of the newly parsed #GstH264NalUnit, you should + * call the differents functions to parse the structure: + * + * + * From #GST_H264_NAL_SLICE to #GST_H264_NAL_SLICE_IDR: #gst_h264_parser_parse_slice_hdr + * + * + * #GST_H264_NAL_SEI: #gst_h264_parser_parse_sei + * + * + * #GST_H264_NAL_SPS: #gst_h264_parser_parse_sps + * + * + * #GST_H264_NAL_PPS: #gst_h264_parser_parse_pps + * + * + * Any other: #gst_h264_parser_parse_nal + * + * + * + * Note: You should always call gst_h264_parser_parse_nal if you don't actually need + * #GstH264NalUnitType to be parsed for your personnal use, in order to guarantee that the + * #GstH264NalParser is always up to date. + * + * For more details about the structures, look at the ITU-T H.264 and ISO/IEC 14496-10 – MPEG-4 + * Part 10 specifications, you can download them from: + * + * + * + * ITU-T H.264: http://www.itu.int/rec/T-REC-H.264 + * + * + * ISO/IEC 14496-10: http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=56538 + * + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "gsth264parser.h" + +#include +#include +#include + +GST_DEBUG_CATEGORY (h264_parser_debug); +#define GST_CAT_DEFAULT h264_parser_debug + +/**** Default scaling_lists according to Table 7-2 *****/ +static const guint8 default_4x4_intra[16] = { + 6, 13, 13, 20, 20, 20, 28, 28, 28, 28, 32, 32, + 32, 37, 37, 42 +}; + +static const guint8 default_4x4_inter[16] = { + 10, 14, 14, 20, 20, 20, 24, 24, 24, 24, 27, 27, + 27, 30, 30, 34 +}; + +static const guint8 default_8x8_intra[64] = { + 6, 10, 10, 13, 11, 13, 16, 16, 16, 16, 18, 18, + 18, 18, 18, 23, 23, 23, 23, 23, 23, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, + 27, 27, 27, 27, 27, 29, 29, 29, 29, 29, 29, 29, 31, 31, 31, 31, 31, 31, 33, + 33, 33, 33, 33, 36, 36, 36, 36, 38, 38, 38, 40, 40, 42 +}; + +static const guint8 default_8x8_inter[64] = { + 9, 13, 13, 15, 13, 15, 17, 17, 17, 17, 19, 19, + 19, 19, 19, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 24, 24, 24, + 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27, 27, 27, 28, + 28, 28, 28, 28, 30, 30, 30, 30, 32, 32, 32, 33, 33, 35 +}; + +static const guint8 zigzag_8x8[64] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + +static const guint8 zigzag_4x4[16] = { + 0, 1, 4, 8, + 5, 2, 3, 6, + 9, 12, 13, 10, + 7, 11, 14, 15, +}; + +typedef struct +{ + guint par_n, par_d; +} PAR; + +/* Table E-1 - Meaning of sample aspect ratio indicator (1..16) */ +static PAR aspect_ratios[17] = { + {0, 0}, + {1, 1}, + {12, 11}, + {10, 11}, + {16, 11}, + {40, 33}, + {24, 11}, + {20, 11}, + {32, 11}, + {80, 33}, + {18, 11}, + {15, 11}, + {64, 33}, + {160, 99}, + {4, 3}, + {3, 2}, + {2, 1} +}; + +/* Compute Ceil(Log2(v)) */ +/* Derived from branchless code for integer log2(v) from: + */ +static guint +ceil_log2 (guint32 v) +{ + guint r, shift; + + v--; + r = (v > 0xFFFF) << 4; + v >>= r; + shift = (v > 0xFF) << 3; + v >>= shift; + r |= shift; + shift = (v > 0xF) << 2; + v >>= shift; + r |= shift; + shift = (v > 0x3) << 1; + v >>= shift; + r |= shift; + r |= (v >> 1); + return r + 1; +} + +/****** Nal parser ******/ + +typedef struct +{ + const guint8 *data; + guint size; + + guint n_epb; /* Number of emulation prevention bytes */ + guint byte; /* Byte position */ + guint bits_in_cache; /* bitpos in the cache of next bit */ + guint8 first_byte; + guint64 cache; /* cached bytes */ +} NalReader; + +static void +nal_reader_init (NalReader * nr, const guint8 * data, guint size) +{ + nr->data = data; + nr->size = size; + nr->n_epb = 0; + + nr->byte = 0; + nr->bits_in_cache = 0; + /* fill with something other than 0 to detect emulation prevention bytes */ + nr->first_byte = 0xff; + nr->cache = 0xff; +} + +static inline gboolean +nal_reader_read (NalReader * nr, guint nbits) +{ + if (G_UNLIKELY (nr->byte * 8 + (nbits - nr->bits_in_cache) > nr->size * 8)) { + GST_DEBUG ("Can not read %u bits, bits in cache %u, Byte * 8 %u, size in " + "bits %u", nbits, nr->bits_in_cache, nr->byte * 8, nr->size * 8); + return FALSE; + } + + while (nr->bits_in_cache < nbits) { + guint8 byte; + gboolean check_three_byte; + + check_three_byte = TRUE; + next_byte: + if (G_UNLIKELY (nr->byte >= nr->size)) + return FALSE; + + byte = nr->data[nr->byte++]; + + /* check if the byte is a emulation_prevention_three_byte */ + if (check_three_byte && byte == 0x03 && nr->first_byte == 0x00 && + ((nr->cache & 0xff) == 0)) { + /* next byte goes unconditionally to the cache, even if it's 0x03 */ + check_three_byte = FALSE; + nr->n_epb++; + goto next_byte; + } + nr->cache = (nr->cache << 8) | nr->first_byte; + nr->first_byte = byte; + nr->bits_in_cache += 8; + } + + return TRUE; +} + +static inline gboolean +nal_reader_skip (NalReader * nr, guint nbits) +{ + if (G_UNLIKELY (!nal_reader_read (nr, nbits))) + return FALSE; + + nr->bits_in_cache -= nbits; + + return TRUE; +} + +static inline gboolean +nal_reader_skip_to_byte (NalReader * nr) +{ + if (nr->bits_in_cache == 0) { + if (G_LIKELY ((nr->size - nr->byte) > 0)) + nr->byte++; + else + return FALSE; + } + + nr->bits_in_cache = 0; + + return TRUE; +} + +static inline guint +nal_reader_get_pos (const NalReader * nr) +{ + return nr->byte * 8 - nr->bits_in_cache; +} + +static inline guint +nal_reader_get_remaining (const NalReader * nr) +{ + return (nr->size - nr->byte) * 8 + nr->bits_in_cache; +} + +static inline guint +nal_reader_get_epb_count (const NalReader * nr) +{ + return nr->n_epb; +} + +#define GST_NAL_READER_READ_BITS(bits) \ +static gboolean \ +nal_reader_get_bits_uint##bits (NalReader *nr, guint##bits *val, guint nbits) \ +{ \ + guint shift; \ + \ + if (!nal_reader_read (nr, nbits)) \ + return FALSE; \ + \ + /* bring the required bits down and truncate */ \ + shift = nr->bits_in_cache - nbits; \ + *val = nr->first_byte >> shift; \ + \ + *val |= nr->cache << (8 - shift); \ + /* mask out required bits */ \ + if (nbits < bits) \ + *val &= ((guint##bits)1 << nbits) - 1; \ + \ + nr->bits_in_cache = shift; \ + \ + return TRUE; \ +} \ + +GST_NAL_READER_READ_BITS (8); +GST_NAL_READER_READ_BITS (16); +GST_NAL_READER_READ_BITS (32); + +static gboolean +nal_reader_get_ue (NalReader * nr, guint32 * val) +{ + guint i = 0; + guint8 bit; + guint32 value; + + if (G_UNLIKELY (!nal_reader_get_bits_uint8 (nr, &bit, 1))) { + + return FALSE; + } + + while (bit == 0) { + i++; + if G_UNLIKELY + ((!nal_reader_get_bits_uint8 (nr, &bit, 1))) + return FALSE; + } + + if (G_UNLIKELY (i > 32)) + return FALSE; + + if (G_UNLIKELY (!nal_reader_get_bits_uint32 (nr, &value, i))) + return FALSE; + + *val = (1 << i) - 1 + value; + + return TRUE; +} + +static inline gboolean +nal_reader_get_se (NalReader * nr, gint32 * val) +{ + guint32 value; + + if (G_UNLIKELY (!nal_reader_get_ue (nr, &value))) + return FALSE; + + if (value % 2) + *val = (value / 2) + 1; + else + *val = -(value / 2); + + return TRUE; +} + +#define CHECK_ALLOWED(val, min, max) { \ + if (val < min || val > max) { \ + GST_WARNING ("value not in allowed range. value: %d, range %d-%d", \ + val, min, max); \ + goto error; \ + } \ +} + +#define READ_UINT8(nr, val, nbits) { \ + if (!nal_reader_get_bits_uint8 (nr, &val, nbits)) { \ + GST_WARNING ("failed to read uint8, nbits: %d", nbits); \ + goto error; \ + } \ +} + +#define READ_UINT16(nr, val, nbits) { \ + if (!nal_reader_get_bits_uint16 (nr, &val, nbits)) { \ + GST_WARNING ("failed to read uint16, nbits: %d", nbits); \ + goto error; \ + } \ +} + +#define READ_UINT32(nr, val, nbits) { \ + if (!nal_reader_get_bits_uint32 (nr, &val, nbits)) { \ + GST_WARNING ("failed to read uint32, nbits: %d", nbits); \ + goto error; \ + } \ +} + +#define READ_UINT64(nr, val, nbits) { \ + if (!nal_reader_get_bits_uint64 (nr, &val, nbits)) { \ + GST_WARNING ("failed to read uint32, nbits: %d", nbits); \ + goto error; \ + } \ +} + +#define READ_UE(nr, val) { \ + if (!nal_reader_get_ue (nr, &val)) { \ + GST_WARNING ("failed to read UE"); \ + goto error; \ + } \ +} + +#define READ_UE_ALLOWED(nr, val, min, max) { \ + guint32 tmp; \ + READ_UE (nr, tmp); \ + CHECK_ALLOWED (tmp, min, max); \ + val = tmp; \ +} + +#define READ_SE(nr, val) { \ + if (!nal_reader_get_se (nr, &val)) { \ + GST_WARNING ("failed to read SE"); \ + goto error; \ + } \ +} + +#define READ_SE_ALLOWED(nr, val, min, max) { \ + gint32 tmp; \ + READ_SE (nr, tmp); \ + CHECK_ALLOWED (tmp, min, max); \ + val = tmp; \ +} + +/*********** end of nal parser ***************/ + +/***** Utils ****/ +#define EXTENDED_SAR 255 + +static GstH264SPS * +gst_h264_parser_get_sps (GstH264NalParser * nalparser, guint8 sps_id) +{ + GstH264SPS *sps; + + sps = &nalparser->sps[sps_id]; + + if (sps->valid) + return sps; + + return NULL; +} + +static GstH264PPS * +gst_h264_parser_get_pps (GstH264NalParser * nalparser, guint8 pps_id) +{ + GstH264PPS *pps; + + pps = &nalparser->pps[pps_id]; + + if (pps->valid) + return pps; + + return NULL; +} + +static inline void +set_nalu_datas (GstH264NalUnit * nalu) +{ + guint8 *data = nalu->data + nalu->offset; + + nalu->type = (data[0] & 0x1f); + nalu->ref_idc = (data[0] & 0x60) >> 5; + nalu->idr_pic_flag = (nalu->type == 5 ? 1 : 0); + + GST_DEBUG ("Nal type %u, ref_idc %u", nalu->type, nalu->ref_idc); +} + +static inline gint +scan_for_start_codes (const guint8 * data, guint size) +{ + GstByteReader br; + gst_byte_reader_init (&br, data, size); + + /* NALU not empty, so we can at least expect 1 (even 2) bytes following sc */ + return gst_byte_reader_masked_scan_uint32 (&br, 0xffffff00, 0x00000100, + 0, size); +} + +static gboolean +gst_h264_parser_more_data (NalReader * nr) +{ + NalReader nr_tmp; + guint remaining, nbits; + guint8 rbsp_stop_one_bit, zero_bits; + + remaining = nal_reader_get_remaining (nr); + if (remaining == 0) + return FALSE; + + nr_tmp = *nr; + nr = &nr_tmp; + + if (!nal_reader_get_bits_uint8 (nr, &rbsp_stop_one_bit, 1)) + return FALSE; + if (!rbsp_stop_one_bit) + return TRUE; + + nbits = --remaining % 8; + while (remaining > 0) { + if (!nal_reader_get_bits_uint8 (nr, &zero_bits, nbits)) + return FALSE; + if (zero_bits != 0) + return TRUE; + remaining -= nbits; + nbits = 8; + } + return FALSE; +} + +/****** Parsing functions *****/ + +static gboolean +gst_h264_parse_hrd_parameters (GstH264HRDParams * hrd, NalReader * nr) +{ + guint sched_sel_idx; + + GST_DEBUG ("parsing \"HRD Parameters\""); + + READ_UE_ALLOWED (nr, hrd->cpb_cnt_minus1, 0, 31); + READ_UINT8 (nr, hrd->bit_rate_scale, 4); + READ_UINT8 (nr, hrd->cpb_size_scale, 4); + + for (sched_sel_idx = 0; sched_sel_idx <= hrd->cpb_cnt_minus1; sched_sel_idx++) { + READ_UE (nr, hrd->bit_rate_value_minus1[sched_sel_idx]); + READ_UE (nr, hrd->cpb_size_value_minus1[sched_sel_idx]); + READ_UINT8 (nr, hrd->cbr_flag[sched_sel_idx], 1); + } + + READ_UINT8 (nr, hrd->initial_cpb_removal_delay_length_minus1, 5); + READ_UINT8 (nr, hrd->cpb_removal_delay_length_minus1, 5); + READ_UINT8 (nr, hrd->dpb_output_delay_length_minus1, 5); + READ_UINT8 (nr, hrd->time_offset_length, 5); + + return TRUE; + +error: + GST_WARNING ("error parsing \"HRD Parameters\""); + return FALSE; +} + +static gboolean +gst_h264_parse_vui_parameters (GstH264SPS * sps, NalReader * nr) +{ + GstH264VUIParams *vui = &sps->vui_parameters; + + GST_DEBUG ("parsing \"VUI Parameters\""); + + /* set default values for fields that might not be present in the bitstream + and have valid defaults */ + vui->aspect_ratio_idc = 0; + vui->video_format = 5; + vui->video_full_range_flag = 0; + vui->colour_primaries = 2; + vui->transfer_characteristics = 2; + vui->matrix_coefficients = 2; + vui->chroma_sample_loc_type_top_field = 0; + vui->chroma_sample_loc_type_bottom_field = 0; + vui->low_delay_hrd_flag = 0; + vui->par_n = 0; + vui->par_d = 0; + + READ_UINT8 (nr, vui->aspect_ratio_info_present_flag, 1); + if (vui->aspect_ratio_info_present_flag) { + READ_UINT8 (nr, vui->aspect_ratio_idc, 8); + if (vui->aspect_ratio_idc == EXTENDED_SAR) { + READ_UINT16 (nr, vui->sar_width, 16); + READ_UINT16 (nr, vui->sar_height, 16); + vui->par_n = vui->sar_width; + vui->par_d = vui->sar_height; + } else if (vui->aspect_ratio_idc <= 16) { + vui->par_n = aspect_ratios[vui->aspect_ratio_idc].par_n; + vui->par_d = aspect_ratios[vui->aspect_ratio_idc].par_d; + } + } + + READ_UINT8 (nr, vui->overscan_info_present_flag, 1); + if (vui->overscan_info_present_flag) + READ_UINT8 (nr, vui->overscan_appropriate_flag, 1); + + READ_UINT8 (nr, vui->video_signal_type_present_flag, 1); + if (vui->video_signal_type_present_flag) { + + READ_UINT8 (nr, vui->video_format, 3); + READ_UINT8 (nr, vui->video_full_range_flag, 1); + READ_UINT8 (nr, vui->colour_description_present_flag, 1); + if (vui->colour_description_present_flag) { + READ_UINT8 (nr, vui->colour_primaries, 8); + READ_UINT8 (nr, vui->transfer_characteristics, 8); + READ_UINT8 (nr, vui->matrix_coefficients, 8); + } + } + + READ_UINT8 (nr, vui->chroma_loc_info_present_flag, 1); + if (vui->chroma_loc_info_present_flag) { + READ_UE_ALLOWED (nr, vui->chroma_sample_loc_type_top_field, 0, 5); + READ_UE_ALLOWED (nr, vui->chroma_sample_loc_type_bottom_field, 0, 5); + } + + READ_UINT8 (nr, vui->timing_info_present_flag, 1); + if (vui->timing_info_present_flag) { + READ_UINT32 (nr, vui->num_units_in_tick, 32); + if (vui->num_units_in_tick == 0) + GST_WARNING ("num_units_in_tick = 0 detected in stream " + "(incompliant to H.264 E.2.1)."); + + READ_UINT32 (nr, vui->time_scale, 32); + if (vui->time_scale == 0) + GST_WARNING ("time_scale = 0 detected in stream " + "(incompliant to H.264 E.2.1)."); + + READ_UINT8 (nr, vui->fixed_frame_rate_flag, 1); + } + + READ_UINT8 (nr, vui->nal_hrd_parameters_present_flag, 1); + if (vui->nal_hrd_parameters_present_flag) { + if (!gst_h264_parse_hrd_parameters (&vui->nal_hrd_parameters, nr)) + goto error; + } + + READ_UINT8 (nr, vui->vcl_hrd_parameters_present_flag, 1); + if (vui->vcl_hrd_parameters_present_flag) { + if (!gst_h264_parse_hrd_parameters (&vui->vcl_hrd_parameters, nr)) + goto error; + } + + if (vui->nal_hrd_parameters_present_flag || + vui->vcl_hrd_parameters_present_flag) + READ_UINT8 (nr, vui->low_delay_hrd_flag, 1); + + READ_UINT8 (nr, vui->pic_struct_present_flag, 1); + READ_UINT8 (nr, vui->bitstream_restriction_flag, 1); + if (vui->bitstream_restriction_flag) { + READ_UINT8 (nr, vui->motion_vectors_over_pic_boundaries_flag, 1); + READ_UE (nr, vui->max_bytes_per_pic_denom); + READ_UE_ALLOWED (nr, vui->max_bits_per_mb_denom, 0, 16); + READ_UE_ALLOWED (nr, vui->log2_max_mv_length_horizontal, 0, 16); + READ_UE_ALLOWED (nr, vui->log2_max_mv_length_vertical, 0, 16); + READ_UE (nr, vui->num_reorder_frames); + READ_UE (nr, vui->max_dec_frame_buffering); + } + + return TRUE; + +error: + GST_WARNING ("error parsing \"VUI Parameters\""); + return FALSE; +} + +static gboolean +gst_h264_parser_parse_scaling_list (NalReader * nr, + guint8 scaling_lists_4x4[6][16], guint8 scaling_lists_8x8[6][64], + const guint8 fallback_4x4_inter[16], const guint8 fallback_4x4_intra[16], + const guint8 fallback_8x8_inter[64], const guint8 fallback_8x8_intra[64], + guint8 n_lists) +{ + guint i; + + GST_DEBUG ("parsing scaling lists"); + + for (i = 0; i < 12; i++) { + gboolean use_default = FALSE; + + if (i < n_lists) { + guint8 scaling_list_present_flag; + + READ_UINT8 (nr, scaling_list_present_flag, 1); + if (scaling_list_present_flag) { + guint8 *scaling_list; + const guint8 *scan; + guint size; + guint j; + guint8 last_scale, next_scale; + + if (i < 6) { + scaling_list = scaling_lists_4x4[i]; + scan = zigzag_4x4; + size = 16; + } else { + scaling_list = scaling_lists_8x8[i - 6]; + scan = zigzag_8x8; + size = 64; + } + + last_scale = 8; + next_scale = 8; + for (j = 0; j < size; j++) { + if (next_scale != 0) { + gint32 delta_scale; + + READ_SE (nr, delta_scale); + next_scale = (last_scale + delta_scale) & 0xff; + } + if (j == 0 && next_scale == 0) { + use_default = TRUE; + break; + } + last_scale = scaling_list[scan[j]] = + (next_scale == 0) ? last_scale : next_scale; + } + } else + use_default = TRUE; + } else + use_default = TRUE; + + if (use_default) { + switch (i) { + case 0: + memcpy (scaling_lists_4x4[0], fallback_4x4_intra, 16); + break; + case 1: + memcpy (scaling_lists_4x4[1], scaling_lists_4x4[0], 16); + break; + case 2: + memcpy (scaling_lists_4x4[2], scaling_lists_4x4[1], 16); + break; + case 3: + memcpy (scaling_lists_4x4[3], fallback_4x4_inter, 16); + break; + case 4: + memcpy (scaling_lists_4x4[4], scaling_lists_4x4[3], 16); + break; + case 5: + memcpy (scaling_lists_4x4[5], scaling_lists_4x4[4], 16); + break; + case 6: + memcpy (scaling_lists_8x8[0], fallback_8x8_intra, 64); + break; + case 7: + memcpy (scaling_lists_8x8[1], fallback_8x8_inter, 64); + break; + case 8: + memcpy (scaling_lists_8x8[2], scaling_lists_8x8[0], 64); + break; + case 9: + memcpy (scaling_lists_8x8[3], scaling_lists_8x8[1], 64); + break; + case 10: + memcpy (scaling_lists_8x8[4], scaling_lists_8x8[2], 64); + break; + case 11: + memcpy (scaling_lists_8x8[5], scaling_lists_8x8[3], 64); + break; + + default: + break; + } + } + } + + return TRUE; + +error: + GST_WARNING ("error parsing scaling lists"); + return FALSE; +} + +static gboolean +slice_parse_ref_pic_list_modification_1 (GstH264SliceHdr * slice, + NalReader * nr, guint list) +{ + GstH264RefPicListModification *entries; + guint8 *ref_pic_list_modification_flag, *n_ref_pic_list_modification; + guint32 modification_of_pic_nums_idc; + guint i = 0; + + if (list == 0) { + entries = slice->ref_pic_list_modification_l0; + ref_pic_list_modification_flag = &slice->ref_pic_list_modification_flag_l0; + n_ref_pic_list_modification = &slice->n_ref_pic_list_modification_l0; + } else { + entries = slice->ref_pic_list_modification_l1; + ref_pic_list_modification_flag = &slice->ref_pic_list_modification_flag_l1; + n_ref_pic_list_modification = &slice->n_ref_pic_list_modification_l1; + } + + READ_UINT8 (nr, *ref_pic_list_modification_flag, 1); + if (*ref_pic_list_modification_flag) { + while (1) { + READ_UE (nr, modification_of_pic_nums_idc); + if (modification_of_pic_nums_idc == 3) + break; + if (modification_of_pic_nums_idc == 0 || + modification_of_pic_nums_idc == 1) { + READ_UE_ALLOWED (nr, entries[i].value.abs_diff_pic_num_minus1, 0, + slice->max_pic_num - 1); + } else if (modification_of_pic_nums_idc == 2) { + READ_UE (nr, entries[i].value.long_term_pic_num); + } + entries[i++].modification_of_pic_nums_idc = modification_of_pic_nums_idc; + } + } + *n_ref_pic_list_modification = i; + return TRUE; + +error: + GST_WARNING ("error parsing \"Reference picture list %u modification\"", + list); + return FALSE; +} + +static gboolean +slice_parse_ref_pic_list_modification (GstH264SliceHdr * slice, NalReader * nr) +{ + if (!GST_H264_IS_I_SLICE (slice) && !GST_H264_IS_SI_SLICE (slice)) { + if (!slice_parse_ref_pic_list_modification_1 (slice, nr, 0)) + return FALSE; + } + + if (GST_H264_IS_B_SLICE (slice)) { + if (!slice_parse_ref_pic_list_modification_1 (slice, nr, 1)) + return FALSE; + } + return TRUE; +} + +static gboolean +gst_h264_slice_parse_dec_ref_pic_marking (GstH264SliceHdr * slice, + GstH264NalUnit * nalu, NalReader * nr) +{ + GstH264DecRefPicMarking *dec_ref_pic_m; + + GST_DEBUG ("parsing \"Decoded reference picture marking\""); + + dec_ref_pic_m = &slice->dec_ref_pic_marking; + + if (nalu->idr_pic_flag) { + READ_UINT8 (nr, dec_ref_pic_m->no_output_of_prior_pics_flag, 1); + READ_UINT8 (nr, dec_ref_pic_m->long_term_reference_flag, 1); + } else { + READ_UINT8 (nr, dec_ref_pic_m->adaptive_ref_pic_marking_mode_flag, 1); + if (dec_ref_pic_m->adaptive_ref_pic_marking_mode_flag) { + guint32 mem_mgmt_ctrl_op; + GstH264RefPicMarking *refpicmarking; + + dec_ref_pic_m->n_ref_pic_marking = 0; + while (1) { + refpicmarking = + &dec_ref_pic_m->ref_pic_marking[dec_ref_pic_m->n_ref_pic_marking]; + + READ_UE (nr, mem_mgmt_ctrl_op); + if (mem_mgmt_ctrl_op == 0) + break; + + refpicmarking->memory_management_control_operation = mem_mgmt_ctrl_op; + + if (mem_mgmt_ctrl_op == 1 || mem_mgmt_ctrl_op == 3) + READ_UE (nr, refpicmarking->difference_of_pic_nums_minus1); + + if (mem_mgmt_ctrl_op == 2) + READ_UE (nr, refpicmarking->long_term_pic_num); + + if (mem_mgmt_ctrl_op == 3 || mem_mgmt_ctrl_op == 6) + READ_UE (nr, refpicmarking->long_term_frame_idx); + + if (mem_mgmt_ctrl_op == 4) + READ_UE (nr, refpicmarking->max_long_term_frame_idx_plus1); + + dec_ref_pic_m->n_ref_pic_marking++; + } + } + } + + return TRUE; + +error: + GST_WARNING ("error parsing \"Decoded reference picture marking\""); + return FALSE; +} + +static gboolean +gst_h264_slice_parse_pred_weight_table (GstH264SliceHdr * slice, + NalReader * nr, guint8 chroma_array_type) +{ + GstH264PredWeightTable *p; + gint16 default_luma_weight, default_chroma_weight; + gint i; + + GST_DEBUG ("parsing \"Prediction weight table\""); + + p = &slice->pred_weight_table; + + READ_UE_ALLOWED (nr, p->luma_log2_weight_denom, 0, 7); + /* set default values */ + default_luma_weight = 1 << p->luma_log2_weight_denom; + for (i = 0; i < G_N_ELEMENTS (p->luma_weight_l0); i++) + p->luma_weight_l0[i] = default_luma_weight; + memset (p->luma_offset_l0, 0, sizeof (p->luma_offset_l0)); + if (GST_H264_IS_B_SLICE (slice)) { + for (i = 0; i < G_N_ELEMENTS (p->luma_weight_l1); i++) + p->luma_weight_l1[i] = default_luma_weight; + memset (p->luma_offset_l1, 0, sizeof (p->luma_offset_l1)); + } + + if (chroma_array_type != 0) { + READ_UE_ALLOWED (nr, p->chroma_log2_weight_denom, 0, 7); + /* set default values */ + default_chroma_weight = 1 << p->chroma_log2_weight_denom; + for (i = 0; i < G_N_ELEMENTS (p->chroma_weight_l0); i++) { + p->chroma_weight_l0[i][0] = default_chroma_weight; + p->chroma_weight_l0[i][1] = default_chroma_weight; + } + memset (p->chroma_offset_l0, 0, sizeof (p->chroma_offset_l0)); + if (GST_H264_IS_B_SLICE (slice)) { + for (i = 0; i < G_N_ELEMENTS (p->chroma_weight_l1); i++) { + p->chroma_weight_l1[i][0] = default_chroma_weight; + p->chroma_weight_l1[i][1] = default_chroma_weight; + } + memset (p->chroma_offset_l1, 0, sizeof (p->chroma_offset_l1)); + } + } + + for (i = 0; i <= slice->num_ref_idx_l0_active_minus1; i++) { + guint8 luma_weight_l0_flag; + + READ_UINT8 (nr, luma_weight_l0_flag, 1); + if (luma_weight_l0_flag) { + READ_SE_ALLOWED (nr, p->luma_weight_l0[i], -128, 127); + READ_SE_ALLOWED (nr, p->luma_offset_l0[i], -128, 127); + } + if (chroma_array_type != 0) { + guint8 chroma_weight_l0_flag; + gint j; + + READ_UINT8 (nr, chroma_weight_l0_flag, 1); + if (chroma_weight_l0_flag) { + for (j = 0; j < 2; j++) { + READ_SE_ALLOWED (nr, p->chroma_weight_l0[i][j], -128, 127); + READ_SE_ALLOWED (nr, p->chroma_offset_l0[i][j], -128, 127); + } + } + } + } + + if (GST_H264_IS_B_SLICE (slice)) { + for (i = 0; i <= slice->num_ref_idx_l1_active_minus1; i++) { + guint8 luma_weight_l1_flag; + + READ_UINT8 (nr, luma_weight_l1_flag, 1); + if (luma_weight_l1_flag) { + READ_SE_ALLOWED (nr, p->luma_weight_l1[i], -128, 127); + READ_SE_ALLOWED (nr, p->luma_offset_l1[i], -128, 127); + } + if (chroma_array_type != 0) { + guint8 chroma_weight_l1_flag; + gint j; + + READ_UINT8 (nr, chroma_weight_l1_flag, 1); + if (chroma_weight_l1_flag) { + for (j = 0; j < 2; j++) { + READ_SE_ALLOWED (nr, p->chroma_weight_l1[i][j], -128, 127); + READ_SE_ALLOWED (nr, p->chroma_offset_l1[i][j], -128, 127); + } + } + } + } + } + + return TRUE; + +error: + GST_WARNING ("error parsing \"Prediction weight table\""); + return FALSE; +} + +static gboolean +gst_h264_parser_parse_buffering_period (GstH264NalParser * nalparser, + GstH264BufferingPeriod * per, NalReader * nr) +{ + GstH264SPS *sps; + guint8 sps_id; + + GST_DEBUG ("parsing \"Buffering period\""); + + READ_UE_ALLOWED (nr, sps_id, 0, GST_H264_MAX_SPS_COUNT - 1); + sps = gst_h264_parser_get_sps (nalparser, sps_id); + if (!sps) { + GST_WARNING ("couldn't find associated sequence parameter set with id: %d", + sps_id); + return GST_H264_PARSER_BROKEN_LINK; + } + per->sps = sps; + + if (sps->vui_parameters_present_flag) { + GstH264VUIParams *vui = &sps->vui_parameters; + + if (vui->nal_hrd_parameters_present_flag) { + GstH264HRDParams *hrd = &vui->nal_hrd_parameters; + guint8 sched_sel_idx; + + for (sched_sel_idx = 0; sched_sel_idx <= hrd->cpb_cnt_minus1; + sched_sel_idx++) { + READ_UINT8 (nr, per->nal_initial_cpb_removal_delay[sched_sel_idx], 5); + READ_UINT8 (nr, + per->nal_initial_cpb_removal_delay_offset[sched_sel_idx], 5); + } + } + + if (vui->vcl_hrd_parameters_present_flag) { + GstH264HRDParams *hrd = &vui->vcl_hrd_parameters; + guint8 sched_sel_idx; + + for (sched_sel_idx = 0; sched_sel_idx <= hrd->cpb_cnt_minus1; + sched_sel_idx++) { + READ_UINT8 (nr, per->vcl_initial_cpb_removal_delay[sched_sel_idx], 5); + READ_UINT8 (nr, + per->vcl_initial_cpb_removal_delay_offset[sched_sel_idx], 5); + } + } + } + + return GST_H264_PARSER_OK; + +error: + GST_WARNING ("error parsing \"Buffering period\""); + return GST_H264_PARSER_ERROR; +} + +static gboolean +gst_h264_parse_clock_timestamp (GstH264ClockTimestamp * tim, + GstH264VUIParams * vui, NalReader * nr) +{ + guint8 full_timestamp_flag; + guint8 time_offset_length; + + GST_DEBUG ("parsing \"Clock timestamp\""); + + /* defalt values */ + tim->time_offset = 0; + + READ_UINT8 (nr, tim->ct_type, 2); + READ_UINT8 (nr, tim->nuit_field_based_flag, 1); + READ_UINT8 (nr, tim->counting_type, 5); + READ_UINT8 (nr, full_timestamp_flag, 1); + READ_UINT8 (nr, tim->discontinuity_flag, 1); + READ_UINT8 (nr, tim->cnt_dropped_flag, 1); + READ_UINT8 (nr, tim->n_frames, 8); + + if (full_timestamp_flag) { + tim->seconds_flag = TRUE; + READ_UINT8 (nr, tim->seconds_value, 6); + + tim->minutes_flag = TRUE; + READ_UINT8 (nr, tim->minutes_value, 6); + + tim->hours_flag = TRUE; + READ_UINT8 (nr, tim->hours_value, 5); + } else { + READ_UINT8 (nr, tim->seconds_flag, 1); + if (tim->seconds_flag) { + READ_UINT8 (nr, tim->seconds_value, 6); + READ_UINT8 (nr, tim->minutes_flag, 1); + if (tim->minutes_flag) { + READ_UINT8 (nr, tim->minutes_value, 6); + READ_UINT8 (nr, tim->hours_flag, 1); + if (tim->hours_flag) + READ_UINT8 (nr, tim->hours_value, 5); + } + } + } + + time_offset_length = 0; + if (vui->nal_hrd_parameters_present_flag) + time_offset_length = vui->nal_hrd_parameters.time_offset_length; + else if (vui->vcl_hrd_parameters_present_flag) + time_offset_length = vui->vcl_hrd_parameters.time_offset_length; + + if (time_offset_length > 0) + READ_UINT32 (nr, tim->time_offset, time_offset_length); + + return TRUE; + +error: + GST_WARNING ("error parsing \"Clock timestamp\""); + return FALSE; +} + +static gboolean +gst_h264_parser_parse_pic_timing (GstH264NalParser * nalparser, + GstH264PicTiming * tim, NalReader * nr) +{ + GST_DEBUG ("parsing \"Picture timing\""); + if (!nalparser->last_sps || !nalparser->last_sps->valid) { + GST_WARNING ("didn't get the associated sequence paramater set for the " + "current access unit"); + goto error; + } + + /* default values */ + memset (tim->clock_timestamp_flag, 0, 3); + + if (nalparser->last_sps->vui_parameters_present_flag) { + GstH264VUIParams *vui = &nalparser->last_sps->vui_parameters; + + if (vui->nal_hrd_parameters_present_flag) { + READ_UINT32 (nr, tim->cpb_removal_delay, + vui->nal_hrd_parameters.cpb_removal_delay_length_minus1 + 1); + READ_UINT32 (nr, tim->dpb_output_delay, + vui->nal_hrd_parameters.dpb_output_delay_length_minus1 + 1); + } else if (vui->nal_hrd_parameters_present_flag) { + READ_UINT32 (nr, tim->cpb_removal_delay, + vui->vcl_hrd_parameters.cpb_removal_delay_length_minus1 + 1); + READ_UINT32 (nr, tim->dpb_output_delay, + vui->vcl_hrd_parameters.dpb_output_delay_length_minus1 + 1); + } + + if (vui->pic_struct_present_flag) { + const guint8 num_clock_ts_table[9] = { + 1, 1, 1, 2, 2, 3, 3, 2, 3 + }; + guint8 num_clock_num_ts; + guint i; + + tim->pic_struct_present_flag = TRUE; + READ_UINT8 (nr, tim->pic_struct, 4); + CHECK_ALLOWED ((gint8) tim->pic_struct, 0, 8); + + num_clock_num_ts = num_clock_ts_table[tim->pic_struct]; + for (i = 0; i < num_clock_num_ts; i++) { + READ_UINT8 (nr, tim->clock_timestamp_flag[i], 1); + if (tim->clock_timestamp_flag[i]) { + if (!gst_h264_parse_clock_timestamp (&tim->clock_timestamp[i], vui, + nr)) + goto error; + } + } + } + } + + return GST_H264_PARSER_OK; + +error: + GST_WARNING ("error parsing \"Picture timing\""); + return GST_H264_PARSER_ERROR; +} + +/******** API *************/ + +/** + * gst_h264_nal_parser_new: + * + * Creates a new #GstH264NalParser. It should be freed with + * gst_h264_nal_parser_free after use. + * + * Returns: a new #GstH264NalParser + */ +GstH264NalParser * +gst_h264_nal_parser_new (void) +{ + GstH264NalParser *nalparser; + + nalparser = g_slice_new0 (GstH264NalParser); + GST_DEBUG_CATEGORY_INIT (h264_parser_debug, "codecparsers_h264", 0, + "h264 parser library"); + + return nalparser; +} + +/** + * gst_h264_nal_parser_free: + * @nalparser: the #GstH264NalParser to free + * + * Frees @nalparser and sets it to %NULL + */ +void +gst_h264_nal_parser_free (GstH264NalParser * nalparser) +{ + g_slice_free (GstH264NalParser, nalparser); + + nalparser = NULL; +} + +/** + * gst_h264_parser_identify_nalu_unchecked: + * @nalparser: a #GstH264NalParser + * @data: The data to parse + * @offset: the offset from which to parse @data + * @size: the size of @data + * @nalu: The #GstH264NalUnit where to store parsed nal headers + * + * Parses @data and fills @nalu from the next nalu data from @data. + * + * This differs from @gst_h264_parser_identify_nalu in that it doesn't + * check whether the packet is complete or not. + * + * Note: Only use this function if you already know the provided @data + * is a complete NALU, else use @gst_h264_parser_identify_nalu. + * + * Returns: a #GstH264ParserResult + */ +GstH264ParserResult +gst_h264_parser_identify_nalu_unchecked (GstH264NalParser * nalparser, + const guint8 * data, guint offset, gsize size, GstH264NalUnit * nalu) +{ + gint off1; + + if (size < offset + 4) { + GST_DEBUG ("Can't parse, buffer has too small size %" G_GSIZE_FORMAT + ", offset %u", size, offset); + return GST_H264_PARSER_ERROR; + } + + off1 = scan_for_start_codes (data + offset, size - offset); + + if (off1 < 0) { + GST_DEBUG ("No start code prefix in this buffer"); + return GST_H264_PARSER_NO_NAL; + } + + if (offset + off1 == size - 1) { + GST_DEBUG ("Missing data to identify nal unit"); + + return GST_H264_PARSER_ERROR; + } + + nalu->valid = TRUE; + nalu->sc_offset = offset + off1; + + /* sc might have 2 or 3 0-bytes */ + if (nalu->sc_offset > 0 && data[nalu->sc_offset - 1] == 00) + nalu->sc_offset--; + + nalu->offset = offset + off1 + 3; + nalu->data = (guint8 *) data; + + set_nalu_datas (nalu); + + if (nalu->type == GST_H264_NAL_SEQ_END || + nalu->type == GST_H264_NAL_STREAM_END) { + GST_DEBUG ("end-of-seq or end-of-stream nal found"); + nalu->size = 0; + return GST_H264_PARSER_OK; + } + + nalu->size = size - nalu->offset; + + return GST_H264_PARSER_OK; +} + +/** + * gst_h264_parser_identify_nalu: + * @nalparser: a #GstH264NalParser + * @data: The data to parse + * @offset: the offset from which to parse @data + * @size: the size of @data + * @nalu: The #GstH264NalUnit where to store parsed nal headers + * + * Parses @data and fills @nalu from the next nalu data from @data + * + * Returns: a #GstH264ParserResult + */ +GstH264ParserResult +gst_h264_parser_identify_nalu (GstH264NalParser * nalparser, + const guint8 * data, guint offset, gsize size, GstH264NalUnit * nalu) +{ + GstH264ParserResult res; + gint off2; + + res = + gst_h264_parser_identify_nalu_unchecked (nalparser, data, offset, size, + nalu); + + if (res != GST_H264_PARSER_OK || nalu->size == 0) + goto beach; + + off2 = scan_for_start_codes (data + nalu->offset, size - nalu->offset); + if (off2 < 0) { + GST_DEBUG ("Nal start %d, No end found", nalu->offset); + + return GST_H264_PARSER_NO_NAL_END; + } + + if (off2 > 0 && data[nalu->offset + off2 - 1] == 00) + off2--; + + nalu->size = off2; + if (nalu->size < 2) + return GST_H264_PARSER_BROKEN_DATA; + + GST_DEBUG ("Complete nal found. Off: %d, Size: %d", nalu->offset, nalu->size); + +beach: + return res; +} + + +/** + * gst_h264_parser_identify_nalu_avc: + * @nalparser: a #GstH264NalParser + * @data: The data to parse, must be the beging of the Nal unit + * @offset: the offset from which to parse @data + * @size: the size of @data + * @nal_length_size: the size in bytes of the AVC nal length prefix. + * @nalu: The #GstH264NalUnit where to store parsed nal headers + * + * Parses @data and sets @nalu. + * + * Returns: a #GstH264ParserResult + */ +GstH264ParserResult +gst_h264_parser_identify_nalu_avc (GstH264NalParser * nalparser, + const guint8 * data, guint offset, gsize size, guint8 nal_length_size, + GstH264NalUnit * nalu) +{ + GstBitReader br; + + if (size < offset + nal_length_size) { + GST_DEBUG ("Can't parse, buffer has too small size %" G_GSIZE_FORMAT + ", offset %u", size, offset); + return GST_H264_PARSER_ERROR; + } + + size = size - offset; + gst_bit_reader_init (&br, data + offset, size); + + nalu->size = gst_bit_reader_get_bits_uint32_unchecked (&br, + nal_length_size * 8); + nalu->sc_offset = offset; + nalu->offset = offset + nal_length_size; + + if (size < nalu->size + nal_length_size) { + nalu->size = 0; + + return GST_H264_PARSER_NO_NAL_END; + } + + nalu->data = (guint8 *) data; + + set_nalu_datas (nalu); + + if (nalu->size < 2) + return GST_H264_PARSER_BROKEN_DATA; + + nalu->valid = TRUE; + + return GST_H264_PARSER_OK; +} + +/** + * gst_h264_parser_parse_nal: + * @nalparser: a #GstH264NalParser + * @nalu: The #GstH264NalUnit to parse + * + * This function should be called in the case one doesn't need to + * parse a specific structure. It is necessary to do so to make + * sure @nalparser is up to date. + * + * Returns: a #GstH264ParserResult + */ +GstH264ParserResult +gst_h264_parser_parse_nal (GstH264NalParser * nalparser, GstH264NalUnit * nalu) +{ + GstH264SPS sps; + GstH264PPS pps; + + switch (nalu->type) { + case GST_H264_NAL_SPS: + return gst_h264_parser_parse_sps (nalparser, nalu, &sps, FALSE); + break; + case GST_H264_NAL_PPS: + return gst_h264_parser_parse_pps (nalparser, nalu, &pps); + } + + return GST_H264_PARSER_OK; +} + +/** + * gst_h264_parser_parse_sps: + * @nalparser: a #GstH264NalParser + * @nalu: The #GST_H264_NAL_SPS #GstH264NalUnit to parse + * @sps: The #GstH264SPS to fill. + * @parse_vui_params: Whether to parse the vui_params or not + * + * Parses @data, and fills the @sps structure. + * + * Returns: a #GstH264ParserResult + */ +GstH264ParserResult +gst_h264_parser_parse_sps (GstH264NalParser * nalparser, GstH264NalUnit * nalu, + GstH264SPS * sps, gboolean parse_vui_params) +{ + GstH264ParserResult res = gst_h264_parse_sps (nalu, sps, parse_vui_params); + + if (res == GST_H264_PARSER_OK) { + GST_DEBUG ("adding sequence parameter set with id: %d to array", sps->id); + + nalparser->sps[sps->id] = *sps; + nalparser->last_sps = &nalparser->sps[sps->id]; + } + + + + return res; +} + +/** + * gst_h264_parse_sps: + * @nalu: The #GST_H264_NAL_SPS #GstH264NalUnit to parse + * @sps: The #GstH264SPS to fill. + * @parse_vui_params: Whether to parse the vui_params or not + * + * Parses @data, and fills the @sps structure. + * + * Returns: a #GstH264ParserResult + */ +GstH264ParserResult +gst_h264_parse_sps (GstH264NalUnit * nalu, GstH264SPS * sps, + gboolean parse_vui_params) +{ + NalReader nr; + gint width, height; + guint8 frame_cropping_flag; + guint subwc[] = { 1, 2, 2, 1 }; + guint subhc[] = { 1, 2, 1, 1 }; + GstH264VUIParams *vui = NULL; + + GST_DEBUG ("parsing SPS"); + nal_reader_init (&nr, nalu->data + nalu->offset + 1, nalu->size - 1); + + /* set default values for fields that might not be present in the bitstream + and have valid defaults */ + sps->chroma_format_idc = 1; + sps->separate_colour_plane_flag = 0; + sps->bit_depth_luma_minus8 = 0; + sps->bit_depth_chroma_minus8 = 0; + memset (sps->scaling_lists_4x4, 16, 96); + memset (sps->scaling_lists_8x8, 16, 384); + sps->mb_adaptive_frame_field_flag = 0; + sps->frame_crop_left_offset = 0; + sps->frame_crop_right_offset = 0; + sps->frame_crop_top_offset = 0; + sps->frame_crop_bottom_offset = 0; + sps->delta_pic_order_always_zero_flag = 0; + + READ_UINT8 (&nr, sps->profile_idc, 8); + READ_UINT8 (&nr, sps->constraint_set0_flag, 1); + READ_UINT8 (&nr, sps->constraint_set1_flag, 1); + READ_UINT8 (&nr, sps->constraint_set2_flag, 1); + READ_UINT8 (&nr, sps->constraint_set3_flag, 1); + + /* skip reserved_zero_4bits */ + if (!nal_reader_skip (&nr, 4)) + goto error; + + READ_UINT8 (&nr, sps->level_idc, 8); + + READ_UE_ALLOWED (&nr, sps->id, 0, GST_H264_MAX_SPS_COUNT - 1); + + if (sps->profile_idc == 100 || sps->profile_idc == 110 || + sps->profile_idc == 122 || sps->profile_idc == 244 || + sps->profile_idc == 44 || sps->profile_idc == 83 || + sps->profile_idc == 86) { + READ_UE_ALLOWED (&nr, sps->chroma_format_idc, 0, 3); + if (sps->chroma_format_idc == 3) + READ_UINT8 (&nr, sps->separate_colour_plane_flag, 1); + + READ_UE_ALLOWED (&nr, sps->bit_depth_luma_minus8, 0, 6); + READ_UE_ALLOWED (&nr, sps->bit_depth_chroma_minus8, 0, 6); + READ_UINT8 (&nr, sps->qpprime_y_zero_transform_bypass_flag, 1); + + READ_UINT8 (&nr, sps->scaling_matrix_present_flag, 1); + if (sps->scaling_matrix_present_flag) { + guint8 n_lists; + + n_lists = (sps->chroma_format_idc != 3) ? 8 : 12; + if (!gst_h264_parser_parse_scaling_list (&nr, + sps->scaling_lists_4x4, sps->scaling_lists_8x8, + default_4x4_inter, default_4x4_intra, + default_8x8_inter, default_8x8_intra, n_lists)) + goto error; + } + } + + READ_UE_ALLOWED (&nr, sps->log2_max_frame_num_minus4, 0, 12); + + sps->max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4); + + READ_UE_ALLOWED (&nr, sps->pic_order_cnt_type, 0, 2); + if (sps->pic_order_cnt_type == 0) { + READ_UE_ALLOWED (&nr, sps->log2_max_pic_order_cnt_lsb_minus4, 0, 12); + } else if (sps->pic_order_cnt_type == 1) { + guint i; + + READ_UINT8 (&nr, sps->delta_pic_order_always_zero_flag, 1); + READ_SE (&nr, sps->offset_for_non_ref_pic); + READ_SE (&nr, sps->offset_for_top_to_bottom_field); + READ_UE_ALLOWED (&nr, sps->num_ref_frames_in_pic_order_cnt_cycle, 0, 255); + + for (i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; i++) + READ_SE (&nr, sps->offset_for_ref_frame[i]); + } + + READ_UE (&nr, sps->num_ref_frames); + READ_UINT8 (&nr, sps->gaps_in_frame_num_value_allowed_flag, 1); + READ_UE (&nr, sps->pic_width_in_mbs_minus1); + READ_UE (&nr, sps->pic_height_in_map_units_minus1); + READ_UINT8 (&nr, sps->frame_mbs_only_flag, 1); + + if (!sps->frame_mbs_only_flag) + READ_UINT8 (&nr, sps->mb_adaptive_frame_field_flag, 1); + + READ_UINT8 (&nr, sps->direct_8x8_inference_flag, 1); + READ_UINT8 (&nr, frame_cropping_flag, 1); + if (frame_cropping_flag) { + READ_UE (&nr, sps->frame_crop_left_offset); + READ_UE (&nr, sps->frame_crop_right_offset); + READ_UE (&nr, sps->frame_crop_top_offset); + READ_UE (&nr, sps->frame_crop_bottom_offset); + } + + READ_UINT8 (&nr, sps->vui_parameters_present_flag, 1); + if (sps->vui_parameters_present_flag && parse_vui_params) { + if (!gst_h264_parse_vui_parameters (sps, &nr)) + goto error; + vui = &sps->vui_parameters; + } + + /* calculate ChromaArrayType */ + if (sps->separate_colour_plane_flag) + sps->chroma_array_type = 0; + else + sps->chroma_array_type = sps->chroma_format_idc; + + /* Calculate width and height */ + width = (sps->pic_width_in_mbs_minus1 + 1); + width *= 16; + height = (sps->pic_height_in_map_units_minus1 + 1); + height *= 16 * (2 - sps->frame_mbs_only_flag); + GST_LOG ("initial width=%d, height=%d", width, height); + + width -= (sps->frame_crop_left_offset + sps->frame_crop_right_offset) + * subwc[sps->chroma_format_idc]; + height -= (sps->frame_crop_top_offset + sps->frame_crop_bottom_offset + * subhc[sps->chroma_format_idc] * (2 - sps->frame_mbs_only_flag)); + if (width < 0 || height < 0) { + GST_WARNING ("invalid width/height in SPS"); + goto error; + } + GST_LOG ("final width=%u, height=%u", width, height); + sps->width = width; + sps->height = height; + + sps->fps_num = 0; + sps->fps_den = 1; + + if (vui && vui->timing_info_present_flag) { + /* derive framerate */ + /* FIXME verify / also handle other cases */ + GST_LOG ("Framerate: %u %u %u %u", parse_vui_params, + vui->fixed_frame_rate_flag, sps->frame_mbs_only_flag, + vui->pic_struct_present_flag); + + if (parse_vui_params && vui->fixed_frame_rate_flag && + sps->frame_mbs_only_flag && !vui->pic_struct_present_flag) { + sps->fps_num = vui->time_scale; + sps->fps_den = vui->num_units_in_tick; + /* picture is a frame = 2 fields */ + sps->fps_den *= 2; + GST_LOG ("framerate %d/%d", sps->fps_num, sps->fps_den); + } + } else { + GST_LOG ("No VUI, unknown framerate"); + } + + sps->valid = TRUE; + + return GST_H264_PARSER_OK; + +error: + GST_WARNING ("error parsing \"Sequence parameter set\""); + sps->valid = FALSE; + return GST_H264_PARSER_ERROR; +} + +/** + * gst_h264_parse_pps: + * @nalparser: a #GstH264NalParser + * @nalu: The #GST_H264_NAL_PPS #GstH264NalUnit to parse + * @pps: The #GstH264PPS to fill. + * + * Parses @data, and fills the @pps structure. + * + * Returns: a #GstH264ParserResult + */ +GstH264ParserResult +gst_h264_parse_pps (GstH264NalParser * nalparser, GstH264NalUnit * nalu, + GstH264PPS * pps) +{ + NalReader nr; + GstH264SPS *sps; + gint sps_id; + guint8 pic_scaling_matrix_present_flag; + gint qp_bd_offset; + + GST_DEBUG ("parsing PPS"); + + nal_reader_init (&nr, nalu->data + nalu->offset + 1, nalu->size - 1); + + READ_UE_ALLOWED (&nr, pps->id, 0, GST_H264_MAX_PPS_COUNT - 1); + READ_UE_ALLOWED (&nr, sps_id, 0, GST_H264_MAX_SPS_COUNT - 1); + + sps = gst_h264_parser_get_sps (nalparser, sps_id); + if (!sps) { + GST_WARNING ("couldn't find associated sequence parameter set with id: %d", + sps_id); + return GST_H264_PARSER_BROKEN_LINK; + } + pps->sequence = sps; + qp_bd_offset = 6 * (sps->bit_depth_luma_minus8 + + sps->separate_colour_plane_flag); + + /* set default values for fields that might not be present in the bitstream + and have valid defaults */ + pps->slice_group_id = NULL; + pps->transform_8x8_mode_flag = 0; + memcpy (&pps->scaling_lists_4x4, &sps->scaling_lists_4x4, 96); + memcpy (&pps->scaling_lists_8x8, &sps->scaling_lists_8x8, 384); + + READ_UINT8 (&nr, pps->entropy_coding_mode_flag, 1); + READ_UINT8 (&nr, pps->pic_order_present_flag, 1); + READ_UE_ALLOWED (&nr, pps->num_slice_groups_minus1, 0, 7); + if (pps->num_slice_groups_minus1 > 0) { + READ_UE_ALLOWED (&nr, pps->slice_group_map_type, 0, 6); + + if (pps->slice_group_map_type == 0) { + gint i; + + for (i = 0; i <= pps->num_slice_groups_minus1; i++) + READ_UE (&nr, pps->run_length_minus1[i]); + } else if (pps->slice_group_map_type == 2) { + gint i; + + for (i = 0; i <= pps->num_slice_groups_minus1; i++) { + READ_UE (&nr, pps->top_left[i]); + READ_UE (&nr, pps->bottom_right[i]); + } + } else if (pps->slice_group_map_type >= 3 && pps->slice_group_map_type <= 5) { + READ_UINT8 (&nr, pps->slice_group_change_direction_flag, 1); + READ_UE (&nr, pps->slice_group_change_rate_minus1); + } else if (pps->slice_group_map_type == 6) { + gint bits; + gint i; + + READ_UE (&nr, pps->pic_size_in_map_units_minus1); + bits = g_bit_storage (pps->num_slice_groups_minus1); + + pps->slice_group_id = + g_new (guint8, pps->pic_size_in_map_units_minus1 + 1); + for (i = 0; i <= pps->pic_size_in_map_units_minus1; i++) + READ_UINT8 (&nr, pps->slice_group_id[i], bits); + } + } + + READ_UE_ALLOWED (&nr, pps->num_ref_idx_l0_active_minus1, 0, 31); + READ_UE_ALLOWED (&nr, pps->num_ref_idx_l1_active_minus1, 0, 31); + READ_UINT8 (&nr, pps->weighted_pred_flag, 1); + READ_UINT8 (&nr, pps->weighted_bipred_idc, 2); + READ_SE_ALLOWED (&nr, pps->pic_init_qp_minus26, -(26 + qp_bd_offset), 25); + READ_SE_ALLOWED (&nr, pps->pic_init_qs_minus26, -26, 25); + READ_SE_ALLOWED (&nr, pps->chroma_qp_index_offset, -12, 12); + pps->second_chroma_qp_index_offset = pps->chroma_qp_index_offset; + READ_UINT8 (&nr, pps->deblocking_filter_control_present_flag, 1); + READ_UINT8 (&nr, pps->constrained_intra_pred_flag, 1); + READ_UINT8 (&nr, pps->redundant_pic_cnt_present_flag, 1); + + if (!gst_h264_parser_more_data (&nr)) + goto done; + + READ_UINT8 (&nr, pps->transform_8x8_mode_flag, 1); + + READ_UINT8 (&nr, pic_scaling_matrix_present_flag, 1); + if (pic_scaling_matrix_present_flag) { + guint8 n_lists; + + n_lists = 6 + ((sps->chroma_format_idc != 3) ? 2 : 6) * + pps->transform_8x8_mode_flag; + + if (sps->scaling_matrix_present_flag) { + if (!gst_h264_parser_parse_scaling_list (&nr, + pps->scaling_lists_4x4, pps->scaling_lists_8x8, + sps->scaling_lists_4x4[0], sps->scaling_lists_4x4[3], + sps->scaling_lists_8x8[0], sps->scaling_lists_8x8[3], n_lists)) + goto error; + } else { + if (!gst_h264_parser_parse_scaling_list (&nr, + pps->scaling_lists_4x4, pps->scaling_lists_8x8, + default_4x4_inter, default_4x4_intra, + default_8x8_inter, default_8x8_intra, n_lists)) + goto error; + } + } + + READ_SE_ALLOWED (&nr, pps->second_chroma_qp_index_offset, -12, 12); + +done: + pps->valid = TRUE; + return GST_H264_PARSER_OK; + +error: + GST_WARNING ("error parsing \"Picture parameter set\""); + pps->valid = FALSE; + return GST_H264_PARSER_ERROR; +} + +/** + * gst_h264_parser_parse_pps: + * @nalparser: a #GstH264NalParser + * @nalu: The #GST_H264_NAL_PPS #GstH264NalUnit to parse + * @pps: The #GstH264PPS to fill. + * + * Parses @data, and fills the @pps structure. + * + * Returns: a #GstH264ParserResult + */ +GstH264ParserResult +gst_h264_parser_parse_pps (GstH264NalParser * nalparser, + GstH264NalUnit * nalu, GstH264PPS * pps) +{ + GstH264ParserResult res = gst_h264_parse_pps (nalparser, nalu, pps); + + if (res == GST_H264_PARSER_OK) { + GST_DEBUG ("adding picture parameter set with id: %d to array", pps->id); + + nalparser->pps[pps->id] = *pps; + nalparser->last_pps = &nalparser->pps[pps->id]; + } + + return res; +} + +/** + * gst_h264_parser_parse_slice_hdr: + * @nalparser: a #GstH264NalParser + * @nalu: The #GST_H264_NAL_SLICE #GstH264NalUnit to parse + * @slice: The #GstH264SliceHdr to fill. + * @parse_pred_weight_table: Whether to parse the pred_weight_table or not + * @parse_dec_ref_pic_marking: Whether to parse the dec_ref_pic_marking or not + * + * Parses @data, and fills the @slice structure. + * + * Returns: a #GstH264ParserResult + */ +GstH264ParserResult +gst_h264_parser_parse_slice_hdr (GstH264NalParser * nalparser, + GstH264NalUnit * nalu, GstH264SliceHdr * slice, + gboolean parse_pred_weight_table, gboolean parse_dec_ref_pic_marking) +{ + NalReader nr; + gint pps_id; + GstH264PPS *pps; + GstH264SPS *sps; + + if (!nalu->size) { + GST_DEBUG ("Invalid Nal Unit"); + return GST_H264_PARSER_ERROR; + } + + + nal_reader_init (&nr, nalu->data + nalu->offset + 1, nalu->size - 1); + + READ_UE (&nr, slice->first_mb_in_slice); + READ_UE (&nr, slice->type); + + GST_DEBUG ("parsing \"Slice header\", slice type %u", slice->type); + + READ_UE_ALLOWED (&nr, pps_id, 0, GST_H264_MAX_PPS_COUNT - 1); + pps = gst_h264_parser_get_pps (nalparser, pps_id); + + if (!pps) { + GST_WARNING ("couldn't find associated picture parameter set with id: %d", + pps_id); + + return GST_H264_PARSER_BROKEN_LINK; + } + + slice->pps = pps; + sps = pps->sequence; + if (!sps) { + GST_WARNING ("couldn't find associated sequence parameter set with id: %d", + pps->id); + return GST_H264_PARSER_BROKEN_LINK; + } + + /* set default values for fields that might not be present in the bitstream + and have valid defaults */ + slice->field_pic_flag = 0; + slice->bottom_field_flag = 0; + slice->delta_pic_order_cnt_bottom = 0; + slice->delta_pic_order_cnt[0] = 0; + slice->delta_pic_order_cnt[1] = 0; + slice->redundant_pic_cnt = 0; + slice->num_ref_idx_l0_active_minus1 = pps->num_ref_idx_l0_active_minus1; + slice->num_ref_idx_l1_active_minus1 = pps->num_ref_idx_l1_active_minus1; + slice->disable_deblocking_filter_idc = 0; + slice->slice_alpha_c0_offset_div2 = 0; + + if (sps->separate_colour_plane_flag) + READ_UINT8 (&nr, slice->colour_plane_id, 2); + + READ_UINT16 (&nr, slice->frame_num, sps->log2_max_frame_num_minus4 + 4); + + if (!sps->frame_mbs_only_flag) { + READ_UINT8 (&nr, slice->field_pic_flag, 1); + if (slice->field_pic_flag) + READ_UINT8 (&nr, slice->bottom_field_flag, 1); + } + + /* calculate MaxPicNum */ + if (slice->field_pic_flag) + slice->max_pic_num = sps->max_frame_num; + else + slice->max_pic_num = 2 * sps->max_frame_num; + + if (nalu->type == 5) + READ_UE_ALLOWED (&nr, slice->idr_pic_id, 0, G_MAXUINT16); + + if (sps->pic_order_cnt_type == 0) { + READ_UINT16 (&nr, slice->pic_order_cnt_lsb, + sps->log2_max_pic_order_cnt_lsb_minus4 + 4); + + if (pps->pic_order_present_flag && !slice->field_pic_flag) + READ_SE (&nr, slice->delta_pic_order_cnt_bottom); + } + + if (sps->pic_order_cnt_type == 1 && !sps->delta_pic_order_always_zero_flag) { + READ_SE (&nr, slice->delta_pic_order_cnt[0]); + if (pps->pic_order_present_flag && !slice->field_pic_flag) + READ_SE (&nr, slice->delta_pic_order_cnt[1]); + } + + if (pps->redundant_pic_cnt_present_flag) + READ_UE_ALLOWED (&nr, slice->redundant_pic_cnt, 0, G_MAXINT8); + + if (GST_H264_IS_B_SLICE (slice)) + READ_UINT8 (&nr, slice->direct_spatial_mv_pred_flag, 1); + + if (GST_H264_IS_P_SLICE (slice) || GST_H264_IS_SP_SLICE (slice) || + GST_H264_IS_B_SLICE (slice)) { + guint8 num_ref_idx_active_override_flag; + + READ_UINT8 (&nr, num_ref_idx_active_override_flag, 1); + if (num_ref_idx_active_override_flag) { + READ_UE_ALLOWED (&nr, slice->num_ref_idx_l0_active_minus1, 0, 31); + + if (GST_H264_IS_B_SLICE (slice)) + READ_UE_ALLOWED (&nr, slice->num_ref_idx_l1_active_minus1, 0, 31); + } + } + + if (!slice_parse_ref_pic_list_modification (slice, &nr)) + goto error; + + if ((pps->weighted_pred_flag && (GST_H264_IS_P_SLICE (slice) + || GST_H264_IS_SP_SLICE (slice))) + || (pps->weighted_bipred_idc == 1 && GST_H264_IS_B_SLICE (slice))) { + if (!gst_h264_slice_parse_pred_weight_table (slice, &nr, + sps->chroma_array_type)) + goto error; + } + + if (nalu->ref_idc != 0) { + if (!gst_h264_slice_parse_dec_ref_pic_marking (slice, nalu, &nr)) + goto error; + } + + if (pps->entropy_coding_mode_flag && !GST_H264_IS_I_SLICE (slice) && + !GST_H264_IS_SI_SLICE (slice)) + READ_UE_ALLOWED (&nr, slice->cabac_init_idc, 0, 2); + + READ_SE_ALLOWED (&nr, slice->slice_qp_delta, -87, 77); + + if (GST_H264_IS_SP_SLICE (slice) || GST_H264_IS_SI_SLICE (slice)) { + guint8 sp_for_switch_flag; + + if (GST_H264_IS_SP_SLICE (slice)) + READ_UINT8 (&nr, sp_for_switch_flag, 1); + READ_SE_ALLOWED (&nr, slice->slice_qs_delta, -51, 51); + } + + if (pps->deblocking_filter_control_present_flag) { + READ_UE_ALLOWED (&nr, slice->disable_deblocking_filter_idc, 0, 2); + if (slice->disable_deblocking_filter_idc != 1) { + READ_SE_ALLOWED (&nr, slice->slice_alpha_c0_offset_div2, -6, 6); + READ_SE_ALLOWED (&nr, slice->slice_beta_offset_div2, -6, 6); + } + } + + if (pps->num_slice_groups_minus1 > 0 && + pps->slice_group_map_type >= 3 && pps->slice_group_map_type <= 5) { + /* Ceil(Log2(PicSizeInMapUnits / SliceGroupChangeRate + 1)) [7-33] */ + guint32 PicWidthInMbs = sps->pic_width_in_mbs_minus1 + 1; + guint32 PicHeightInMapUnits = sps->pic_height_in_map_units_minus1 + 1; + guint32 PicSizeInMapUnits = PicWidthInMbs * PicHeightInMapUnits; + guint32 SliceGroupChangeRate = pps->slice_group_change_rate_minus1 + 1; + const guint n = ceil_log2 (PicSizeInMapUnits / SliceGroupChangeRate + 1); + READ_UINT16 (&nr, slice->slice_group_change_cycle, n); + } + + slice->header_size = nal_reader_get_pos (&nr); + slice->n_emulation_prevention_bytes = nal_reader_get_epb_count (&nr); + + return GST_H264_PARSER_OK; + +error: + GST_WARNING ("error parsing \"Slice header\""); + return GST_H264_PARSER_ERROR; +} + +/** + * gst_h264_parser_parse_sei: + * @nalparser: a #GstH264NalParser + * @nalu: The #GST_H264_NAL_SEI #GstH264NalUnit to parse + * @sei: The #GstH264SEIMessage to fill. + * + * Parses @data, and fills the @sei structures. + * + * Returns: a #GstH264ParserResult + */ +GstH264ParserResult +gst_h264_parser_parse_sei (GstH264NalParser * nalparser, GstH264NalUnit * nalu, + GstH264SEIMessage * sei) +{ + NalReader nr; + + guint32 payloadSize; + guint8 payload_type_byte, payload_size_byte; + guint remaining, payload_size; + gboolean res; + + GST_DEBUG ("parsing \"Sei message\""); + + nal_reader_init (&nr, nalu->data + nalu->offset + 1, nalu->size - 1); + + /* init */ + memset (sei, 0, sizeof (*sei)); + + sei->payloadType = 0; + do { + READ_UINT8 (&nr, payload_type_byte, 8); + sei->payloadType += payload_type_byte; + } while (payload_type_byte == 0xff); + + payloadSize = 0; + do { + READ_UINT8 (&nr, payload_size_byte, 8); + payloadSize += payload_size_byte; + } + while (payload_size_byte == 0xff); + + remaining = nal_reader_get_remaining (&nr) * 8; + payload_size = payloadSize < remaining ? payloadSize : remaining; + + GST_DEBUG ("SEI message received: payloadType %u, payloadSize = %u bytes", + sei->payloadType, payload_size); + + if (sei->payloadType == GST_H264_SEI_BUF_PERIOD) { + /* size not set; might depend on emulation_prevention_three_byte */ + res = gst_h264_parser_parse_buffering_period (nalparser, + &sei->payload.buffering_period, &nr); + } else if (sei->payloadType == GST_H264_SEI_PIC_TIMING) { + /* size not set; might depend on emulation_prevention_three_byte */ + res = gst_h264_parser_parse_pic_timing (nalparser, + &sei->payload.pic_timing, &nr); + } else + res = GST_H264_PARSER_OK; + + return res; + +error: + GST_WARNING ("error parsing \"Sei message\""); + return GST_H264_PARSER_ERROR; +} diff --git a/ext/codecparsers/gst-libs/gst/codecparsers/gsth264parser.h b/ext/codecparsers/gst-libs/gst/codecparsers/gsth264parser.h new file mode 100644 index 0000000..7f8ce83 --- /dev/null +++ b/ext/codecparsers/gst-libs/gst/codecparsers/gsth264parser.h @@ -0,0 +1,723 @@ +/* Gstreamer + * Copyright (C) <2011> Intel Corporation + * Copyright (C) <2011> Collabora Ltd. + * Copyright (C) <2011> Thibault Saunier + * + * Some bits C-c,C-v'ed and s/4/3 from h264parse and videoparsers/h264parse.c: + * Copyright (C) <2010> Mark Nauwelaerts + * Copyright (C) <2010> Collabora Multimedia + * Copyright (C) <2010> Nokia Corporation + * + * (C) 2005 Michal Benes + * (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_H264_PARSER_H__ +#define __GST_H264_PARSER_H__ + +#ifndef GST_USE_UNSTABLE_API +#warning "The H.264 parsing library is unstable API and may change in future." +#warning "You can define GST_USE_UNSTABLE_API to avoid this warning." +#endif + +#include + +G_BEGIN_DECLS + +#define GST_H264_MAX_SPS_COUNT 32 +#define GST_H264_MAX_PPS_COUNT 256 + +#define GST_H264_IS_P_SLICE(slice) (((slice)->type % 5) == GST_H264_P_SLICE) +#define GST_H264_IS_B_SLICE(slice) (((slice)->type % 5) == GST_H264_B_SLICE) +#define GST_H264_IS_I_SLICE(slice) (((slice)->type % 5) == GST_H264_I_SLICE) +#define GST_H264_IS_SP_SLICE(slice) (((slice)->type % 5) == GST_H264_SP_SLICE) +#define GST_H264_IS_SI_SLICE(slice) (((slice)->type % 5) == GST_H264_SI_SLICE) + +/** + * GstH264NalUnitType: + * @GST_H264_NAL_UNKNOWN: Unknown nal type + * @GST_H264_NAL_SLICE: Slice nal + * @GST_H264_NAL_SLICE_DPA: DPA slice nal + * @GST_H264_NAL_SLICE_DPB: DPB slice nal + * @GST_H264_NAL_SLICE_DPC: DPC slice nal + * @GST_H264_NAL_SLICE_IDR: DPR slice nal + * @GST_H264_NAL_SEI: Supplemental enhancement information (SEI) nal unit + * @GST_H264_NAL_SPS: Sequence parameter set (SPS) nal unit + * @GST_H264_NAL_PPS: Picture parameter set (PPS) nal unit + * @GST_H264_NAL_AU_DELIMITER: Access unit (AU) delimiter nal unit + * @GST_H264_NAL_SEQ_END: End of sequence nal unit + * @GST_H264_NAL_STREAM_END: End of stream nal unit + * @GST_H264_NAL_FILLER_DATA: Filler data nal lunit + * + * Indicates the type of H264 Nal Units + */ +typedef enum +{ + GST_H264_NAL_UNKNOWN = 0, + GST_H264_NAL_SLICE = 1, + GST_H264_NAL_SLICE_DPA = 2, + GST_H264_NAL_SLICE_DPB = 3, + GST_H264_NAL_SLICE_DPC = 4, + GST_H264_NAL_SLICE_IDR = 5, + GST_H264_NAL_SEI = 6, + GST_H264_NAL_SPS = 7, + GST_H264_NAL_PPS = 8, + GST_H264_NAL_AU_DELIMITER = 9, + GST_H264_NAL_SEQ_END = 10, + GST_H264_NAL_STREAM_END = 11, + GST_H264_NAL_FILLER_DATA = 12 +} GstH264NalUnitType; + +/** + * GstH264ParserResult: + * @GST_H264_PARSER_OK: The parsing succeded + * @GST_H264_PARSER_BROKEN_DATA: The data to parse is broken + * @GST_H264_PARSER_BROKEN_LINK: The link to structure needed for the parsing couldn't be found + * @GST_H264_PARSER_ERROR: An error accured when parsing + * @GST_H264_PARSER_NO_NAL: No nal found during the parsing + * @GST_H264_PARSER_NO_NAL_END: Start of the nal found, but not the end. + * + * The result of parsing H264 data. + */ +typedef enum +{ + GST_H264_PARSER_OK, + GST_H264_PARSER_BROKEN_DATA, + GST_H264_PARSER_BROKEN_LINK, + GST_H264_PARSER_ERROR, + GST_H264_PARSER_NO_NAL, + GST_H264_PARSER_NO_NAL_END +} GstH264ParserResult; + +/** + * GstH264SEIPayloadType: + * @GST_H264_SEI_BUF_PERIOD: Buffering Period SEI Message + * @GST_H264_SEI_PIC_TIMING: Picture Timing SEI Message + * ... + * + * The type of SEI message. + */ +typedef enum +{ + GST_H264_SEI_BUF_PERIOD = 0, + GST_H264_SEI_PIC_TIMING = 1 + /* and more... */ +} GstH264SEIPayloadType; + +/** + * GstH264SEIPicStructType: + * @GST_H264_SEI_PIC_STRUCT_FRAME: Picture is a frame + * @GST_H264_SEI_PIC_STRUCT_TOP_FIELD: Top field of frame + * @GST_H264_SEI_PIC_STRUCT_BOTTOM_FIELD: Botom field of frame + * @GST_H264_SEI_PIC_STRUCT_TOP_BOTTOM: Top bottom field of frame + * @GST_H264_SEI_PIC_STRUCT_BOTTOM_TOP: bottom top field of frame + * @GST_H264_SEI_PIC_STRUCT_TOP_BOTTOM_TOP: top bottom top field of frame + * @GST_H264_SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM: bottom top bottom field of frame + * @GST_H264_SEI_PIC_STRUCT_FRAME_DOUBLING: indicates that the frame should + * be displayed two times consecutively + * @GST_H264_SEI_PIC_STRUCT_FRAME_TRIPLING: indicates that the frame should be + * displayed three times consecutively + * + * SEI pic_struct type + */ +typedef enum +{ + GST_H264_SEI_PIC_STRUCT_FRAME = 0, + GST_H264_SEI_PIC_STRUCT_TOP_FIELD = 1, + GST_H264_SEI_PIC_STRUCT_BOTTOM_FIELD = 2, + GST_H264_SEI_PIC_STRUCT_TOP_BOTTOM = 3, + GST_H264_SEI_PIC_STRUCT_BOTTOM_TOP = 4, + GST_H264_SEI_PIC_STRUCT_TOP_BOTTOM_TOP = 5, + GST_H264_SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM = 6, + GST_H264_SEI_PIC_STRUCT_FRAME_DOUBLING = 7, + GST_H264_SEI_PIC_STRUCT_FRAME_TRIPLING = 8 +} GstH264SEIPicStructType; + +/** + * GstH264SliceType: + * + * Type of Picture slice + */ + +typedef enum +{ + GST_H264_P_SLICE = 0, + GST_H264_B_SLICE = 1, + GST_H264_I_SLICE = 2, + GST_H264_SP_SLICE = 3, + GST_H264_SI_SLICE = 4, + GST_H264_S_P_SLICE = 5, + GST_H264_S_B_SLICE = 6, + GST_H264_S_I_SLICE = 7, + GST_H264_S_SP_SLICE = 8, + GST_H264_S_SI_SLICE = 9 +} GstH264SliceType; + +typedef struct _GstH264NalParser GstH264NalParser; + +typedef struct _GstH264NalUnit GstH264NalUnit; + +typedef struct _GstH264SPS GstH264SPS; +typedef struct _GstH264PPS GstH264PPS; +typedef struct _GstH264HRDParams GstH264HRDParams; +typedef struct _GstH264VUIParams GstH264VUIParams; + +typedef struct _GstH264RefPicListModification GstH264RefPicListModification; +typedef struct _GstH264DecRefPicMarking GstH264DecRefPicMarking; +typedef struct _GstH264RefPicMarking GstH264RefPicMarking; +typedef struct _GstH264PredWeightTable GstH264PredWeightTable; +typedef struct _GstH264SliceHdr GstH264SliceHdr; + +typedef struct _GstH264ClockTimestamp GstH264ClockTimestamp; +typedef struct _GstH264PicTiming GstH264PicTiming; +typedef struct _GstH264BufferingPeriod GstH264BufferingPeriod; +typedef struct _GstH264SEIMessage GstH264SEIMessage; + +/** + * GstH264NalUnit: + * @ref_idc: not equal to 0 specifies that the content of the NAL unit contains a sequence + * parameter set, a sequence * parameter set extension, a subset sequence parameter set, a + * picture parameter set, a slice of a reference picture, a slice data partition of a + * reference picture, or a prefix NAL unit preceding a slice of a reference picture. + * @type: A #GstH264NalUnitType + * @idr_pic_flag: calculated idr_pic_flag + * @size: The size of the nal unit starting from @offset + * @offset: The offset of the actual start of the nal unit + * @sc_offset:The offset of the start code of the nal unit + * @valid: If the nal unit is valid, which mean it has + * already been parsed + * @data: The data from which the Nalu has been parsed + * + * Structure defining the Nal unit headers + */ +struct _GstH264NalUnit +{ + guint16 ref_idc; + guint16 type; + + /* calculated values */ + guint8 idr_pic_flag; + guint size; + guint offset; + guint sc_offset; + gboolean valid; + + guint8 *data; +}; + +/** + * GstH264HRDParams: + * @cpb_cnt_minus1: plus 1 specifies the number of alternative + * CPB specifications in the bitstream + * @bit_rate_scale: specifies the maximum input bit rate of the + * SchedSelIdx-th CPB + * @cpb_size_scale: specifies the CPB size of the SchedSelIdx-th CPB + * @guint32 bit_rate_value_minus1: specifies the maximum input bit rate for the + * SchedSelIdx-th CPB + * @cpb_size_value_minus1: is used together with cpb_size_scale to specify the + * SchedSelIdx-th CPB size + * @cbr_flag: Specifies if running in itermediate bitrate mode or constant + * @initial_cpb_removal_delay_length_minus1: specifies the length in bits of + * the cpb_removal_delay syntax element + * @cpb_removal_delay_length_minus1: specifies the length in bits of the + * dpb_output_delay syntax element + * @dpb_output_delay_length_minus1: >0 specifies the length in bits of the time_offset syntax element. + * =0 specifies that the time_offset syntax element is not present + * @time_offset_length: Length of the time offset + * + * Defines the HRD parameters + */ +struct _GstH264HRDParams +{ + guint8 cpb_cnt_minus1; + guint8 bit_rate_scale; + guint8 cpb_size_scale; + + guint32 bit_rate_value_minus1[32]; + guint32 cpb_size_value_minus1[32]; + guint8 cbr_flag[32]; + + guint8 initial_cpb_removal_delay_length_minus1; + guint8 cpb_removal_delay_length_minus1; + guint8 dpb_output_delay_length_minus1; + guint8 time_offset_length; +}; + +/** + * GstH264VUIParams: + * @aspect_ratio_info_present_flag: %TRUE specifies that aspect_ratio_idc is present. + * %FALSE specifies that aspect_ratio_idc is not present + * @aspect_ratio_idc specifies the value of the sample aspect ratio of the luma samples + * @sar_width indicates the horizontal size of the sample aspect ratio + * @sar_height indicates the vertical size of the sample aspect ratio + * @overscan_info_present_flag: %TRUE overscan_appropriate_flag is present %FALSE otherwize + * @overscan_appropriate_flag: %TRUE indicates that the cropped decoded pictures + * output are suitable for display using overscan. %FALSE the cropped decoded pictures + * output contain visually important information + * @video_signal_type_present_flag: %TRUE specifies that video_format, video_full_range_flag and + * colour_description_present_flag are present. + * @video_format: indicates the representation of the picture + * @video_full_range_flag: indicates the black level and range of the luma and chroma signals + * @colour_description_present_flag: %TRUE specifies that colour_primaries, + * transfer_characteristics and matrix_coefficients are present + * @colour_primaries: indicates the chromaticity coordinates of the source primaries + * @transfer_characteristics: indicates the opto-electronic transfer characteristic + * @matrix_coefficients: describes the matrix coefficients used in deriving luma and chroma signals + * @chroma_loc_info_present_flag: %TRUE specifies that chroma_sample_loc_type_top_field and + * chroma_sample_loc_type_bottom_field are present, %FALSE otherwize + * @chroma_sample_loc_type_top_field: specify the location of chroma for top field + * @chroma_sample_loc_type_bottom_field specify the location of chroma for bottom field + * @timing_info_present_flag: %TRUE specifies that num_units_in_tick, + * time_scale and fixed_frame_rate_flag are present in the bitstream + * @num_units_in_tick: is the number of time units of a clock operating at the frequency time_scale Hz + * time_scale: is the number of time units that pass in one second + * @fixed_frame_rate_flag: %TRUE indicates that the temporal distance between the HRD output times + * of any two consecutive pictures in output order is constrained as specified in the spec, %FALSE + * otherwize. + * @nal_hrd_parameters_present_flag: %TRUE if nal hrd parameters present in the bitstream + * @vcl_hrd_parameters_present_flag: %TRUE if nal vlc hrd parameters present in the bitstream + * @low_delay_hrd_flag: specifies the HRD operational mode + * @pic_struct_present_flag: %TRUE specifies that picture timing SEI messages are present or not + * @bitstream_restriction_flag: %TRUE specifies that the following coded video sequence bitstream restriction + * parameters are present + * @motion_vectors_over_pic_boundaries_flag: %FALSE indicates that no sample outside the + * picture boundaries and no sample at a fractional sample position, %TRUE indicates that one or more + * samples outside picture boundaries may be used in inter prediction + * @max_bytes_per_pic_denom: indicates a number of bytes not exceeded by the sum of the sizes of + * the VCL NAL units associated with any coded picture in the coded video sequence. + * @max_bits_per_mb_denom: indicates the maximum number of coded bits of macroblock_layer + * @log2_max_mv_length_horizontal: indicate the maximum absolute value of a decoded horizontal + * motion vector component + * @log2_max_mv_length_vertical: indicate the maximum absolute value of a decoded vertical + * motion vector component + * @num_reorder_frames: indicates the maximum number of frames, complementary field pairs, + * or non-paired fields that precede any frame, + * @max_dec_frame_buffering: specifies the required size of the HRD decoded picture buffer in + * units of frame buffers. + * + * The structure representing the VUI parameters. + */ +struct _GstH264VUIParams +{ + guint8 aspect_ratio_info_present_flag; + guint8 aspect_ratio_idc; + /* if aspect_ratio_idc == 255 */ + guint16 sar_width; + guint16 sar_height; + + guint8 overscan_info_present_flag; + /* if overscan_info_present_flag */ + guint8 overscan_appropriate_flag; + + guint8 video_signal_type_present_flag; + guint8 video_format; + guint8 video_full_range_flag; + guint8 colour_description_present_flag; + guint8 colour_primaries; + guint8 transfer_characteristics; + guint8 matrix_coefficients; + + guint8 chroma_loc_info_present_flag; + guint8 chroma_sample_loc_type_top_field; + guint8 chroma_sample_loc_type_bottom_field; + + guint8 timing_info_present_flag; + /* if timing_info_present_flag */ + guint32 num_units_in_tick; + guint32 time_scale; + guint8 fixed_frame_rate_flag; + + guint8 nal_hrd_parameters_present_flag; + /* if nal_hrd_parameters_present_flag */ + GstH264HRDParams nal_hrd_parameters; + + guint8 vcl_hrd_parameters_present_flag; + /* if nal_hrd_parameters_present_flag */ + GstH264HRDParams vcl_hrd_parameters; + + guint8 low_delay_hrd_flag; + guint8 pic_struct_present_flag; + + guint8 bitstream_restriction_flag; + /* if bitstream_restriction_flag */ + guint8 motion_vectors_over_pic_boundaries_flag; + guint32 max_bytes_per_pic_denom; + guint32 max_bits_per_mb_denom; + guint32 log2_max_mv_length_horizontal; + guint32 log2_max_mv_length_vertical; + guint32 num_reorder_frames; + guint32 max_dec_frame_buffering; + + /* calculated values */ + guint par_n; + guint par_d; +}; + +/** + * GstH264SPS: + * @id: The ID of the sequence parameter set + * @profile_idc: indicate the profile to which the coded video sequence conforms + * + * H264 Sequence Parameter Set (SPS) + */ +struct _GstH264SPS +{ + gint id; + + guint8 profile_idc; + guint8 constraint_set0_flag; + guint8 constraint_set1_flag; + guint8 constraint_set2_flag; + guint8 constraint_set3_flag; + guint8 level_idc; + + guint8 chroma_format_idc; + guint8 separate_colour_plane_flag; + guint8 bit_depth_luma_minus8; + guint8 bit_depth_chroma_minus8; + guint8 qpprime_y_zero_transform_bypass_flag; + + guint8 scaling_matrix_present_flag; + guint8 scaling_lists_4x4[6][16]; + guint8 scaling_lists_8x8[6][64]; + + guint8 log2_max_frame_num_minus4; + guint8 pic_order_cnt_type; + + /* if pic_order_cnt_type == 0 */ + guint8 log2_max_pic_order_cnt_lsb_minus4; + + /* else if pic_order_cnt_type == 1 */ + guint8 delta_pic_order_always_zero_flag; + gint32 offset_for_non_ref_pic; + gint32 offset_for_top_to_bottom_field; + guint8 num_ref_frames_in_pic_order_cnt_cycle; + gint32 offset_for_ref_frame[255]; + + guint32 num_ref_frames; + guint8 gaps_in_frame_num_value_allowed_flag; + guint32 pic_width_in_mbs_minus1; + guint32 pic_height_in_map_units_minus1; + guint8 frame_mbs_only_flag; + + guint8 mb_adaptive_frame_field_flag; + + guint8 direct_8x8_inference_flag; + + guint8 frame_cropping_flag; + + /* if frame_cropping_flag */ + guint32 frame_crop_left_offset; + guint32 frame_crop_right_offset; + guint32 frame_crop_top_offset; + guint32 frame_crop_bottom_offset; + + guint8 vui_parameters_present_flag; + /* if vui_parameters_present_flag */ + GstH264VUIParams vui_parameters; + + /* calculated values */ + guint8 chroma_array_type; + guint32 max_frame_num; + gint width, height; + gint fps_num, fps_den; + gboolean valid; +}; + +/** + * GstH264PPS: + * + * H264 Picture Parameter Set + */ +struct _GstH264PPS +{ + gint id; + + GstH264SPS *sequence; + + guint8 entropy_coding_mode_flag; + guint8 pic_order_present_flag; + + guint32 num_slice_groups_minus1; + + /* if num_slice_groups_minus1 > 0 */ + guint8 slice_group_map_type; + /* and if slice_group_map_type == 0 */ + guint32 run_length_minus1[8]; + /* or if slice_group_map_type == 2 */ + guint32 top_left[8]; + guint32 bottom_right[8]; + /* or if slice_group_map_type == (3, 4, 5) */ + guint8 slice_group_change_direction_flag; + guint32 slice_group_change_rate_minus1; + /* or if slice_group_map_type == 6 */ + guint32 pic_size_in_map_units_minus1; + guint8 *slice_group_id; + + guint8 num_ref_idx_l0_active_minus1; + guint8 num_ref_idx_l1_active_minus1; + guint8 weighted_pred_flag; + guint8 weighted_bipred_idc; + gint8 pic_init_qp_minus26; + gint8 pic_init_qs_minus26; + gint8 chroma_qp_index_offset; + guint8 deblocking_filter_control_present_flag; + guint8 constrained_intra_pred_flag; + guint8 redundant_pic_cnt_present_flag; + + guint8 transform_8x8_mode_flag; + + guint8 scaling_lists_4x4[6][16]; + guint8 scaling_lists_8x8[6][64]; + + guint8 second_chroma_qp_index_offset; + + gboolean valid; +}; + +struct _GstH264RefPicListModification +{ + guint8 modification_of_pic_nums_idc; + union + { + /* if modification_of_pic_nums_idc == 0 || 1 */ + guint32 abs_diff_pic_num_minus1; + /* if modification_of_pic_nums_idc == 2 */ + guint32 long_term_pic_num; + } value; +}; + +struct _GstH264PredWeightTable +{ + guint8 luma_log2_weight_denom; + guint8 chroma_log2_weight_denom; + + gint16 luma_weight_l0[32]; + gint8 luma_offset_l0[32]; + + /* if seq->ChromaArrayType != 0 */ + gint16 chroma_weight_l0[32][2]; + gint8 chroma_offset_l0[32][2]; + + /* if slice->slice_type % 5 == 1 */ + gint16 luma_weight_l1[32]; + gint8 luma_offset_l1[32]; + + /* and if seq->ChromaArrayType != 0 */ + gint16 chroma_weight_l1[32][2]; + gint8 chroma_offset_l1[32][2]; +}; + +struct _GstH264RefPicMarking +{ + guint8 memory_management_control_operation; + + guint32 difference_of_pic_nums_minus1; + guint32 long_term_pic_num; + guint32 long_term_frame_idx; + guint32 max_long_term_frame_idx_plus1; +}; + +struct _GstH264DecRefPicMarking +{ + /* if slice->nal_unit.IdrPicFlag */ + guint8 no_output_of_prior_pics_flag; + guint8 long_term_reference_flag; + + guint8 adaptive_ref_pic_marking_mode_flag; + GstH264RefPicMarking ref_pic_marking[10]; + guint8 n_ref_pic_marking; +}; + + +struct _GstH264SliceHdr +{ + guint32 first_mb_in_slice; + guint32 type; + GstH264PPS *pps; + + /* if seq->separate_colour_plane_flag */ + guint8 colour_plane_id; + + guint16 frame_num; + + guint8 field_pic_flag; + guint8 bottom_field_flag; + + /* if nal_unit.type == 5 */ + guint16 idr_pic_id; + + /* if seq->pic_order_cnt_type == 0 */ + guint16 pic_order_cnt_lsb; + /* if seq->pic_order_present_flag && !field_pic_flag */ + gint32 delta_pic_order_cnt_bottom; + + gint32 delta_pic_order_cnt[2]; + guint8 redundant_pic_cnt; + + /* if slice_type == B_SLICE */ + guint8 direct_spatial_mv_pred_flag; + + guint8 num_ref_idx_l0_active_minus1; + guint8 num_ref_idx_l1_active_minus1; + + guint8 ref_pic_list_modification_flag_l0; + guint8 n_ref_pic_list_modification_l0; + GstH264RefPicListModification ref_pic_list_modification_l0[32]; + guint8 ref_pic_list_modification_flag_l1; + guint8 n_ref_pic_list_modification_l1; + GstH264RefPicListModification ref_pic_list_modification_l1[32]; + + GstH264PredWeightTable pred_weight_table; + /* if nal_unit.ref_idc != 0 */ + GstH264DecRefPicMarking dec_ref_pic_marking; + + guint8 cabac_init_idc; + gint8 slice_qp_delta; + gint8 slice_qs_delta; + + guint8 disable_deblocking_filter_idc; + gint8 slice_alpha_c0_offset_div2; + gint8 slice_beta_offset_div2; + + guint16 slice_group_change_cycle; + + /* calculated values */ + guint32 max_pic_num; + gboolean valid; + + /* Size of the slice_header() in bits */ + guint header_size; + + /* Number of emulation prevention bytes (EPB) in this slice_header() */ + guint n_emulation_prevention_bytes; +}; + + +struct _GstH264ClockTimestamp +{ + guint8 ct_type; + guint8 nuit_field_based_flag; + guint8 counting_type; + guint8 discontinuity_flag; + guint8 cnt_dropped_flag; + guint8 n_frames; + + guint8 seconds_flag; + guint8 seconds_value; + + guint8 minutes_flag; + guint8 minutes_value; + + guint8 hours_flag; + guint8 hours_value; + + guint32 time_offset; +}; + +struct _GstH264PicTiming +{ + guint32 cpb_removal_delay; + guint32 dpb_output_delay; + + guint8 pic_struct_present_flag; + /* if pic_struct_present_flag */ + guint8 pic_struct; + + guint8 clock_timestamp_flag[3]; + GstH264ClockTimestamp clock_timestamp[3]; +}; + +struct _GstH264BufferingPeriod +{ + GstH264SPS *sps; + + /* seq->vui_parameters->nal_hrd_parameters_present_flag */ + guint8 nal_initial_cpb_removal_delay[32]; + guint8 nal_initial_cpb_removal_delay_offset[32]; + + /* seq->vui_parameters->vcl_hrd_parameters_present_flag */ + guint8 vcl_initial_cpb_removal_delay[32]; + guint8 vcl_initial_cpb_removal_delay_offset[32]; +}; + +struct _GstH264SEIMessage +{ + GstH264SEIPayloadType payloadType; + + union { + GstH264BufferingPeriod buffering_period; + GstH264PicTiming pic_timing; + /* ... could implement more */ + } payload; +}; + +/** + * GstH264NalParser: + * + * H264 NAL Parser (opaque structure). + */ +struct _GstH264NalParser +{ + /*< private >*/ + GstH264SPS sps[GST_H264_MAX_SPS_COUNT]; + GstH264PPS pps[GST_H264_MAX_PPS_COUNT]; + GstH264SPS *last_sps; + GstH264PPS *last_pps; +}; + +GstH264NalParser *gst_h264_nal_parser_new (void); + +GstH264ParserResult gst_h264_parser_identify_nalu (GstH264NalParser *nalparser, + const guint8 *data, guint offset, + gsize size, GstH264NalUnit *nalu); + +GstH264ParserResult gst_h264_parser_identify_nalu_unchecked (GstH264NalParser *nalparser, + const guint8 *data, guint offset, + gsize size, GstH264NalUnit *nalu); + +GstH264ParserResult gst_h264_parser_identify_nalu_avc (GstH264NalParser *nalparser, const guint8 *data, + guint offset, gsize size, guint8 nal_length_size, + GstH264NalUnit *nalu); + +GstH264ParserResult gst_h264_parser_parse_nal (GstH264NalParser *nalparser, + GstH264NalUnit *nalu); + +GstH264ParserResult gst_h264_parser_parse_slice_hdr (GstH264NalParser *nalparser, GstH264NalUnit *nalu, + GstH264SliceHdr *slice, gboolean parse_pred_weight_table, + gboolean parse_dec_ref_pic_marking); + +GstH264ParserResult gst_h264_parser_parse_sps (GstH264NalParser *nalparser, GstH264NalUnit *nalu, + GstH264SPS *sps, gboolean parse_vui_params); + +GstH264ParserResult gst_h264_parser_parse_pps (GstH264NalParser *nalparser, + GstH264NalUnit *nalu, GstH264PPS *pps); + +GstH264ParserResult gst_h264_parser_parse_sei (GstH264NalParser *nalparser, + GstH264NalUnit *nalu, GstH264SEIMessage *sei); + +void gst_h264_nal_parser_free (GstH264NalParser *nalparser); + +GstH264ParserResult gst_h264_parse_sps (GstH264NalUnit *nalu, + GstH264SPS *sps, gboolean parse_vui_params); + +GstH264ParserResult gst_h264_parse_pps (GstH264NalParser *nalparser, + GstH264NalUnit *nalu, GstH264PPS *pps); + +G_END_DECLS +#endif diff --git a/ext/codecparsers/gst-libs/gst/codecparsers/gstjpegparser.c b/ext/codecparsers/gst-libs/gst/codecparsers/gstjpegparser.c new file mode 100644 index 0000000..80de3ff --- /dev/null +++ b/ext/codecparsers/gst-libs/gst/codecparsers/gstjpegparser.c @@ -0,0 +1,611 @@ +/* + * gstjpegparser.c - JPEG parser + * + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include "gstjpegparser.h" + +#ifndef GST_DISABLE_GST_DEBUG + +#define GST_CAT_DEFAULT ensure_debug_category() + +static GstDebugCategory * +ensure_debug_category (void) +{ + static gsize cat_gonce = 0; + + if (g_once_init_enter (&cat_gonce)) { + gsize cat_done; + + cat_done = (gsize) _gst_debug_category_new ("codecparsers_jpeg", 0, + "GstJpegCodecParser"); + + g_once_init_leave (&cat_gonce, cat_done); + } + + return (GstDebugCategory *) cat_gonce; +} +#else + +#define ensure_debug_category() /* NOOP */ + +#endif /* GST_DISABLE_GST_DEBUG */ + +#define DEBUG_PRINT_COMMENT 0 + +#define READ_UINT8(reader, val) G_STMT_START { \ + if (!gst_byte_reader_get_uint8 ((reader), &(val))) { \ + GST_WARNING ("failed to read uint8"); \ + goto failed; \ + } \ + } G_STMT_END + +#define READ_UINT16(reader, val) G_STMT_START { \ + if (!gst_byte_reader_get_uint16_be ((reader), &(val))) { \ + GST_WARNING ("failed to read uint16"); \ + goto failed; \ + } \ + } G_STMT_END + +#define READ_BYTES(reader, buf, length) G_STMT_START { \ + const guint8 *vals; \ + if (!gst_byte_reader_get_data (reader, length, &vals)) { \ + GST_WARNING ("failed to read bytes, size:%d", length); \ + goto failed; \ + } \ + memcpy (buf, vals, length); \ + } G_STMT_END + +#define U_READ_UINT8(reader, val) G_STMT_START { \ + (val) = gst_byte_reader_get_uint8_unchecked(reader); \ + } G_STMT_END + +#define U_READ_UINT16(reader, val) G_STMT_START { \ + (val) = gst_byte_reader_get_uint16_be_unchecked(reader); \ + } G_STMT_END + + +/* Table used to address an 8x8 matrix in zig-zag order */ +/* *INDENT-OFF* */ +static const guint8 zigzag_index[64] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; +/* *INDENT-ON* */ + +/* Table K.1 - Luminance quantization table */ +/* *INDENT-OFF* */ +static const guint8 default_luminance_quant_table[64] = { + 16, 11, 10, 16, 24, 40, 51, 61, + 12, 12, 14, 19, 26, 58, 60, 55, + 14, 13, 16, 24, 40, 57, 69, 56, + 14, 17, 22, 29, 51, 87, 80, 62, + 18, 22, 37, 56, 68, 109, 103, 77, + 24, 35, 55, 64, 81, 104, 113, 92, + 49, 64, 78, 87, 103, 121, 120, 101, + 72, 92, 95, 98, 112, 100, 103, 99 +}; +/* *INDENT-ON* */ + +/* Table K.2 - Chrominance quantization table */ +/* *INDENT-OFF* */ +static const guint8 default_chrominance_quant_table[64] = { + 17, 18, 24, 47, 99, 99, 99, 99, + 18, 21, 26, 66, 99, 99, 99, 99, + 24, 26, 56, 99, 99, 99, 99, 99, + 47, 66, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99 +}; +/* *INDENT-ON* */ + +typedef struct _GstJpegHuffmanTableEntry GstJpegHuffmanTableEntry; +struct _GstJpegHuffmanTableEntry +{ + guint8 value; /* category */ + guint8 length; /* code length in bits */ +}; + +/* Table K.3 - Table for luminance DC coefficient differences */ +static const GstJpegHuffmanTableEntry default_luminance_dc_table[] = { + {0x00, 2}, {0x01, 3}, {0x02, 3}, {0x03, 3}, {0x04, 3}, {0x05, 3}, + {0x06, 4}, {0x07, 5}, {0x08, 6}, {0x09, 7}, {0x0a, 8}, {0x0b, 9} +}; + +/* Table K.4 - Table for chrominance DC coefficient differences */ +static const GstJpegHuffmanTableEntry default_chrominance_dc_table[] = { + {0x00, 2}, {0x01, 2}, {0x02, 2}, {0x03, 3}, {0x04, 4}, {0x05, 5}, + {0x06, 6}, {0x07, 7}, {0x08, 8}, {0x09, 9}, {0x0a, 10}, {0x0b, 11} +}; + +/* Table K.5 - Table for luminance AC coefficients */ +/* *INDENT-OFF* */ +static const GstJpegHuffmanTableEntry default_luminance_ac_table[] = { + {0x00, 4}, {0x01, 2}, {0x02, 2}, {0x03, 3}, {0x04, 4}, {0x05, 5}, + {0x06, 7}, {0x07, 8}, {0x08, 10}, {0x09, 16}, {0x0a, 16}, {0x11, 4}, + {0x12, 5}, {0x13, 7}, {0x14, 9}, {0x15, 11}, {0x16, 16}, {0x17, 16}, + {0x18, 16}, {0x19, 16}, {0x1a, 16}, {0x21, 5}, {0x22, 8}, {0x23, 10}, + {0x24, 12}, {0x25, 16}, {0x26, 16}, {0x27, 16}, {0x28, 16}, {0x29, 16}, + {0x2a, 16}, {0x31, 6}, {0x32, 9}, {0x33, 12}, {0x34, 16}, {0x35, 16}, + {0x36, 16}, {0x37, 16}, {0x38, 16}, {0x39, 16}, {0x3a, 16}, {0x41, 6}, + {0x42, 10}, {0x43, 16}, {0x44, 16}, {0x45, 16}, {0x46, 16}, {0x47, 16}, + {0x48, 16}, {0x49, 16}, {0x4a, 16}, {0x51, 7}, {0x52, 11}, {0x53, 16}, + {0x54, 16}, {0x55, 16}, {0x56, 16}, {0x57, 16}, {0x58, 16}, {0x59, 16}, + {0x5a, 16}, {0x61, 7}, {0x62, 12}, {0x63, 16}, {0x64, 16}, {0x65, 16}, + {0x66, 16}, {0x67, 16}, {0x68, 16}, {0x69, 16}, {0x6a, 16}, {0x71, 8}, + {0x72, 12}, {0x73, 16}, {0x74, 16}, {0x75, 16}, {0x76, 16}, {0x77, 16}, + {0x78, 16}, {0x79, 16}, {0x7a, 16}, {0x81, 9}, {0x82, 15}, {0x83, 16}, + {0x84, 16}, {0x85, 16}, {0x86, 16}, {0x87, 16}, {0x88, 16}, {0x89, 16}, + {0x8a, 16}, {0x91, 9}, {0x92, 16}, {0x93, 16}, {0x94, 16}, {0x95, 16}, + {0x96, 16}, {0x97, 16}, {0x98, 16}, {0x99, 16}, {0x9a, 16}, {0xa1, 9}, + {0xa2, 16}, {0xa3, 16}, {0xa4, 16}, {0xa5, 16}, {0xa6, 16}, {0xa7, 16}, + {0xa8, 16}, {0xa9, 16}, {0xaa, 16}, {0xb1, 10}, {0xb2, 16}, {0xb3, 16}, + {0xb4, 16}, {0xb5, 16}, {0xb6, 16}, {0xb7, 16}, {0xb8, 16}, {0xb9, 16}, + {0xba, 16}, {0xc1, 10}, {0xc2, 16}, {0xc3, 16}, {0xc4, 16}, {0xc5, 16}, + {0xc6, 16}, {0xc7, 16}, {0xc8, 16}, {0xc9, 16}, {0xca, 16}, {0xd1, 11}, + {0xd2, 16}, {0xd3, 16}, {0xd4, 16}, {0xd5, 16}, {0xd6, 16}, {0xd7, 16}, + {0xd8, 16}, {0xd9, 16}, {0xda, 16}, {0xe1, 16}, {0xe2, 16}, {0xe3, 16}, + {0xe4, 16}, {0xe5, 16}, {0xe6, 16}, {0xe7, 16}, {0xe8, 16}, {0xe9, 16}, + {0xea, 16}, {0xf0, 11}, {0xf1, 16}, {0xf2, 16}, {0xf3, 16}, {0xf4, 16}, + {0xf5, 16}, {0xf6, 16}, {0xf7, 16}, {0xf8, 16}, {0xf9, 16}, {0xfa, 16} +}; +/* *INDENT-ON* */ + +/* Table K.6 - Table for chrominance AC coefficients */ +/* *INDENT-OFF* */ +static const GstJpegHuffmanTableEntry default_chrominance_ac_table[] = { + {0x00, 2}, {0x01, 2}, {0x02, 3}, {0x03, 4}, {0x04, 5}, {0x05, 5}, + {0x06, 6}, {0x07, 7}, {0x08, 9}, {0x09, 10}, {0x0a, 12}, {0x11, 4}, + {0x12, 6}, {0x13, 8}, {0x14, 9}, {0x15, 11}, {0x16, 12}, {0x17, 16}, + {0x18, 16}, {0x19, 16}, {0x1a, 16}, {0x21, 5}, {0x22, 8}, {0x23, 10}, + {0x24, 12}, {0x25, 15}, {0x26, 16}, {0x27, 16}, {0x28, 16}, {0x29, 16}, + {0x2a, 16}, {0x31, 5}, {0x32, 8}, {0x33, 10}, {0x34, 12}, {0x35, 16}, + {0x36, 16}, {0x37, 16}, {0x38, 16}, {0x39, 16}, {0x3a, 16}, {0x41, 6}, + {0x42, 9}, {0x43, 16}, {0x44, 16}, {0x45, 16}, {0x46, 16}, {0x47, 16}, + {0x48, 16}, {0x49, 16}, {0x4a, 16}, {0x51, 6}, {0x52, 10}, {0x53, 16}, + {0x54, 16}, {0x55, 16}, {0x56, 16}, {0x57, 16}, {0x58, 16}, {0x59, 16}, + {0x5a, 16}, {0x61, 7}, {0x62, 11}, {0x63, 16}, {0x64, 16}, {0x65, 16}, + {0x66, 16}, {0x67, 16}, {0x68, 16}, {0x69, 16}, {0x6a, 16}, {0x71, 7}, + {0x72, 11}, {0x73, 16}, {0x74, 16}, {0x75, 16}, {0x76, 16}, {0x77, 16}, + {0x78, 16}, {0x79, 16}, {0x7a, 16}, {0x81, 8}, {0x82, 16}, {0x83, 16}, + {0x84, 16}, {0x85, 16}, {0x86, 16}, {0x87, 16}, {0x88, 16}, {0x89, 16}, + {0x8a, 16}, {0x91, 9}, {0x92, 16}, {0x93, 16}, {0x94, 16}, {0x95, 16}, + {0x96, 16}, {0x97, 16}, {0x98, 16}, {0x99, 16}, {0x9a, 16}, {0xa1, 9}, + {0xa2, 16}, {0xa3, 16}, {0xa4, 16}, {0xa5, 16}, {0xa6, 16}, {0xa7, 16}, + {0xa8, 16}, {0xa9, 16}, {0xaa, 16}, {0xb1, 9}, {0xb2, 16}, {0xb3, 16}, + {0xb4, 16}, {0xb5, 16}, {0xb6, 16}, {0xb7, 16}, {0xb8, 16}, {0xb9, 16}, + {0xba, 16}, {0xc1, 9}, {0xc2, 16}, {0xc3, 16}, {0xc4, 16}, {0xc5, 16}, + {0xc6, 16}, {0xc7, 16}, {0xc8, 16}, {0xc9, 16}, {0xca, 16}, {0xd1, 11}, + {0xd2, 16}, {0xd3, 16}, {0xd4, 16}, {0xd5, 16}, {0xd6, 16}, {0xd7, 16}, + {0xd8, 16}, {0xd9, 16}, {0xda, 16}, {0xe1, 14}, {0xe2, 16}, {0xe3, 16}, + {0xe4, 16}, {0xe5, 16}, {0xe6, 16}, {0xe7, 16}, {0xe8, 16}, {0xe9, 16}, + {0xea, 16}, {0xf0, 10}, {0xf1, 15}, {0xf2, 16}, {0xf3, 16}, {0xf4, 16}, + {0xf5, 16}, {0xf6, 16}, {0xf7, 16}, {0xf8, 16}, {0xf9, 16}, {0xfa, 16} +}; +/* *INDENT-ON* */ + +static inline gboolean +jpeg_parse_to_next_marker (GstByteReader * br, guint8 * marker) +{ + gint ofs; + + ofs = gst_jpeg_scan_for_marker_code (br->data, br->size, br->byte); + if (ofs < 0) + return FALSE; + + if (marker) + *marker = br->data[ofs + 1]; + gst_byte_reader_skip (br, ofs - br->byte + 2); + return TRUE; +} + +gint +gst_jpeg_scan_for_marker_code (const guint8 * data, gsize size, guint offset) +{ + guint i; + + g_return_val_if_fail (data != NULL, -1); + g_return_val_if_fail (size > offset, -1); + + for (i = offset; i < size - 1;) { + if (data[i] != 0xff) + i++; + else { + const guint8 v = data[i + 1]; + if (v >= 0xc0 && v <= 0xfe) + return i; + i += 2; + } + } + return -1; +} + +gboolean +gst_jpeg_parse_frame_hdr (GstJpegFrameHdr * frame_hdr, + const guint8 * data, gsize size, guint offset) +{ + GstByteReader br; + guint16 length; + guint8 val; + guint i; + + g_return_val_if_fail (frame_hdr != NULL, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (size > offset, FALSE); + + size -= offset; + gst_byte_reader_init (&br, &data[offset], size); + g_return_val_if_fail (size >= 8, FALSE); + + U_READ_UINT16 (&br, length); /* Lf */ + g_return_val_if_fail (size >= length, FALSE); + + U_READ_UINT8 (&br, frame_hdr->sample_precision); + U_READ_UINT16 (&br, frame_hdr->height); + U_READ_UINT16 (&br, frame_hdr->width); + U_READ_UINT8 (&br, frame_hdr->num_components); + g_return_val_if_fail (frame_hdr->num_components <= + GST_JPEG_MAX_SCAN_COMPONENTS, FALSE); + + length -= 8; + g_return_val_if_fail (length >= 3 * frame_hdr->num_components, FALSE); + for (i = 0; i < frame_hdr->num_components; i++) { + U_READ_UINT8 (&br, frame_hdr->components[i].identifier); + U_READ_UINT8 (&br, val); + frame_hdr->components[i].horizontal_factor = (val >> 4) & 0x0F; + frame_hdr->components[i].vertical_factor = (val & 0x0F); + U_READ_UINT8 (&br, frame_hdr->components[i].quant_table_selector); + g_return_val_if_fail ((frame_hdr->components[i].horizontal_factor <= 4 && + frame_hdr->components[i].vertical_factor <= 4 && + frame_hdr->components[i].quant_table_selector < 4), FALSE); + length -= 3; + } + + g_assert (length == 0); + return TRUE; +} + +gboolean +gst_jpeg_parse_scan_hdr (GstJpegScanHdr * scan_hdr, + const guint8 * data, gsize size, guint offset) +{ + GstByteReader br; + guint16 length; + guint8 val; + guint i; + + g_return_val_if_fail (scan_hdr != NULL, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (size > offset, FALSE); + + size -= offset; + gst_byte_reader_init (&br, &data[offset], size); + g_return_val_if_fail (size >= 3, FALSE); + + U_READ_UINT16 (&br, length); /* Ls */ + g_return_val_if_fail (size >= length, FALSE); + + U_READ_UINT8 (&br, scan_hdr->num_components); + g_return_val_if_fail (scan_hdr->num_components <= + GST_JPEG_MAX_SCAN_COMPONENTS, FALSE); + + length -= 3; + g_return_val_if_fail (length >= 2 * scan_hdr->num_components, FALSE); + for (i = 0; i < scan_hdr->num_components; i++) { + U_READ_UINT8 (&br, scan_hdr->components[i].component_selector); + U_READ_UINT8 (&br, val); + scan_hdr->components[i].dc_selector = (val >> 4) & 0x0F; + scan_hdr->components[i].ac_selector = val & 0x0F; + g_return_val_if_fail ((scan_hdr->components[i].dc_selector < 4 && + scan_hdr->components[i].ac_selector < 4), FALSE); + length -= 2; + } + + /* FIXME: Ss, Se, Ah, Al */ + g_assert (length == 3); + return TRUE; +} + +gboolean +gst_jpeg_parse_huffman_table (GstJpegHuffmanTables * huf_tables, + const guint8 * data, gsize size, guint offset) +{ + GstByteReader br; + GstJpegHuffmanTable *huf_table; + guint16 length; + guint8 val, table_class, table_index; + guint32 value_count; + guint i; + + g_return_val_if_fail (huf_tables != NULL, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (size > offset, FALSE); + + size -= offset; + gst_byte_reader_init (&br, &data[offset], size); + g_return_val_if_fail (size >= 2, FALSE); + + U_READ_UINT16 (&br, length); /* Lh */ + g_return_val_if_fail (size >= length, FALSE); + + while (gst_byte_reader_get_remaining (&br)) { + U_READ_UINT8 (&br, val); + table_class = ((val >> 4) & 0x0F); + table_index = (val & 0x0F); + g_return_val_if_fail (table_index < GST_JPEG_MAX_SCAN_COMPONENTS, FALSE); + if (table_class == 0) { + huf_table = &huf_tables->dc_tables[table_index]; + } else { + huf_table = &huf_tables->ac_tables[table_index]; + } + READ_BYTES (&br, huf_table->huf_bits, 16); + value_count = 0; + for (i = 0; i < 16; i++) + value_count += huf_table->huf_bits[i]; + READ_BYTES (&br, huf_table->huf_values, value_count); + huf_table->valid = TRUE; + } + return TRUE; + +failed: + return FALSE; +} + +gboolean +gst_jpeg_parse_quant_table (GstJpegQuantTables * quant_tables, + const guint8 * data, gsize size, guint offset) +{ + GstByteReader br; + GstJpegQuantTable *quant_table; + guint16 length; + guint8 val, table_index; + guint i; + + g_return_val_if_fail (quant_tables != NULL, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (size > offset, FALSE); + + size -= offset; + gst_byte_reader_init (&br, &data[offset], size); + g_return_val_if_fail (size >= 2, FALSE); + + U_READ_UINT16 (&br, length); /* Lq */ + g_return_val_if_fail (size >= length, FALSE); + + while (gst_byte_reader_get_remaining (&br)) { + U_READ_UINT8 (&br, val); + table_index = (val & 0x0f); + g_return_val_if_fail (table_index < GST_JPEG_MAX_SCAN_COMPONENTS, FALSE); + quant_table = &quant_tables->quant_tables[table_index]; + quant_table->quant_precision = ((val >> 4) & 0x0f); + + g_return_val_if_fail (gst_byte_reader_get_remaining (&br) >= + GST_JPEG_MAX_QUANT_ELEMENTS * (1 + ! !quant_table->quant_precision), + FALSE); + for (i = 0; i < GST_JPEG_MAX_QUANT_ELEMENTS; i++) { + if (!quant_table->quant_precision) { /* 8-bit values */ + U_READ_UINT8 (&br, val); + quant_table->quant_table[i] = val; + } else { /* 16-bit values */ + U_READ_UINT16 (&br, quant_table->quant_table[i]); + } + } + quant_table->valid = TRUE; + } + return TRUE; +} + +gboolean +gst_jpeg_parse_restart_interval (guint * interval, + const guint8 * data, gsize size, guint offset) +{ + GstByteReader br; + guint16 length, val; + + g_return_val_if_fail (interval != NULL, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (size > offset, FALSE); + + size -= offset; + gst_byte_reader_init (&br, &data[offset], size); + g_return_val_if_fail (size >= 4, FALSE); + + U_READ_UINT16 (&br, length); /* Lr */ + g_return_val_if_fail (size >= length, FALSE); + + U_READ_UINT16 (&br, val); + *interval = val; + return TRUE; +} + +static int +compare_huffman_table_entry (const void *a, const void *b) +{ + const GstJpegHuffmanTableEntry *const e1 = *(GstJpegHuffmanTableEntry **) a; + const GstJpegHuffmanTableEntry *const e2 = *(GstJpegHuffmanTableEntry **) b; + + if (e1->length == e2->length) + return (gint) e1->value - (gint) e2->value; + return (gint) e1->length - (gint) e2->length; +} + +static void +build_huffman_table (GstJpegHuffmanTable * huf_table, + const GstJpegHuffmanTableEntry * entries, guint num_entries) +{ + const GstJpegHuffmanTableEntry *sorted_entries[256]; + guint i, j, n; + + g_assert (num_entries <= G_N_ELEMENTS (sorted_entries)); + + for (i = 0; i < num_entries; i++) + sorted_entries[i] = &entries[i]; + qsort (sorted_entries, num_entries, sizeof (sorted_entries[0]), + compare_huffman_table_entry); + + for (i = 0, j = 1, n = 0; i < num_entries; i++) { + const GstJpegHuffmanTableEntry *const e = sorted_entries[i]; + if (e->length != j) { + huf_table->huf_bits[j++ - 1] = n; + for (; j < e->length; j++) + huf_table->huf_bits[j - 1] = 0; + n = 0; + } + huf_table->huf_values[i] = e->value; + n++; + } + + for (; j < G_N_ELEMENTS (huf_table->huf_bits); j++) + huf_table->huf_bits[j] = 0; + for (; i < G_N_ELEMENTS (huf_table->huf_values); i++) + huf_table->huf_values[i] = 0; + huf_table->valid = TRUE; +} + +void +gst_jpeg_get_default_huffman_tables (GstJpegHuffmanTables * huf_tables) +{ + g_assert (huf_tables); + + /* Build DC tables */ + build_huffman_table (&huf_tables->dc_tables[0], default_luminance_dc_table, + G_N_ELEMENTS (default_luminance_dc_table)); + build_huffman_table (&huf_tables->dc_tables[1], default_chrominance_dc_table, + G_N_ELEMENTS (default_chrominance_dc_table)); + memcpy (&huf_tables->dc_tables[2], &huf_tables->dc_tables[1], + sizeof (huf_tables->dc_tables[2])); + + /* Build AC tables */ + build_huffman_table (&huf_tables->ac_tables[0], default_luminance_ac_table, + G_N_ELEMENTS (default_luminance_ac_table)); + build_huffman_table (&huf_tables->ac_tables[1], default_chrominance_ac_table, + G_N_ELEMENTS (default_chrominance_ac_table)); + memcpy (&huf_tables->ac_tables[2], &huf_tables->ac_tables[1], + sizeof (huf_tables->ac_tables[2])); +} + +static void +build_quant_table (GstJpegQuantTable * quant_table, const guint8 values[64]) +{ + guint i; + + for (i = 0; i < 64; i++) + quant_table->quant_table[i] = values[zigzag_index[i]]; + quant_table->quant_precision = 0; /* Pq = 0 (8-bit precision) */ + quant_table->valid = TRUE; +} + +void +gst_jpeg_get_default_quantization_tables (GstJpegQuantTables * quant_tables) +{ + g_assert (quant_tables); + + build_quant_table (&quant_tables->quant_tables[0], + default_luminance_quant_table); + build_quant_table (&quant_tables->quant_tables[1], + default_chrominance_quant_table); + build_quant_table (&quant_tables->quant_tables[2], + default_chrominance_quant_table); +} + +gboolean +gst_jpeg_parse (GstJpegMarkerSegment * seg, + const guint8 * data, gsize size, guint offset) +{ + GstByteReader br; + guint16 length; + + g_return_val_if_fail (seg != NULL, FALSE); + + if (size <= offset) { + GST_DEBUG ("failed to parse from offset %u, buffer is too small", offset); + return FALSE; + } + + size -= offset; + gst_byte_reader_init (&br, &data[offset], size); + + if (!jpeg_parse_to_next_marker (&br, &seg->marker)) { + GST_DEBUG ("failed to find marker code"); + return FALSE; + } + + seg->offset = offset + gst_byte_reader_get_pos (&br); + seg->size = -1; + + /* Try to find end of segment */ + switch (seg->marker) { + case GST_JPEG_MARKER_SOI: + case GST_JPEG_MARKER_EOI: + fixed_size_segment: + seg->size = 2; + break; + + case (GST_JPEG_MARKER_SOF_MIN + 0): /* Lf */ + case (GST_JPEG_MARKER_SOF_MIN + 1): /* Lf */ + case (GST_JPEG_MARKER_SOF_MIN + 2): /* Lf */ + case (GST_JPEG_MARKER_SOF_MIN + 3): /* Lf */ + case (GST_JPEG_MARKER_SOF_MIN + 9): /* Lf */ + case (GST_JPEG_MARKER_SOF_MIN + 10): /* Lf */ + case (GST_JPEG_MARKER_SOF_MIN + 11): /* Lf */ + case GST_JPEG_MARKER_SOS: /* Ls */ + case GST_JPEG_MARKER_DQT: /* Lq */ + case GST_JPEG_MARKER_DHT: /* Lh */ + case GST_JPEG_MARKER_DAC: /* La */ + case GST_JPEG_MARKER_DRI: /* Lr */ + case GST_JPEG_MARKER_COM: /* Lc */ + case GST_JPEG_MARKER_DNL: /* Ld */ + variable_size_segment: + READ_UINT16 (&br, length); + seg->size = length; + break; + + default: + /* Application data segment length (Lp) */ + if (seg->marker >= GST_JPEG_MARKER_APP_MIN && + seg->marker <= GST_JPEG_MARKER_APP_MAX) + goto variable_size_segment; + + /* Restart markers (fixed size, two bytes only) */ + if (seg->marker >= GST_JPEG_MARKER_RST_MIN && + seg->marker <= GST_JPEG_MARKER_RST_MAX) + goto fixed_size_segment; + + /* Fallback: scan for next marker */ + if (!jpeg_parse_to_next_marker (&br, NULL)) + goto failed; + seg->size = gst_byte_reader_get_pos (&br) - seg->offset; + break; + } + return TRUE; + +failed: + return FALSE; +} diff --git a/ext/codecparsers/gst-libs/gst/codecparsers/gstjpegparser.h b/ext/codecparsers/gst-libs/gst/codecparsers/gstjpegparser.h new file mode 100644 index 0000000..7237584 --- /dev/null +++ b/ext/codecparsers/gst-libs/gst/codecparsers/gstjpegparser.h @@ -0,0 +1,414 @@ +/* + * gstjpegparser.h - JPEG parser + * + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_JPEG_PARSER_H +#define GST_JPEG_PARSER_H + +#ifndef GST_USE_UNSTABLE_API +# warning "The JPEG parsing library is unstable API and may change in future." +# warning "You can define GST_USE_UNSTABLE_API to avoid this warning." +#endif + +#include + +G_BEGIN_DECLS + +/** + * GST_JPEG_MAX_FRAME_COMPONENTS: + * + * Maximum number of image components in a frame (Nf). + */ +#define GST_JPEG_MAX_FRAME_COMPONENTS 256 + +/** + * GST_JPEG_MAX_SCAN_COMPONENTS: + * + * Maximum number of image components in a scan (Ns). + */ +#define GST_JPEG_MAX_SCAN_COMPONENTS 4 + +/** + * GST_JPEG_MAX_QUANT_ELEMENTS: + * + * Number of elements in the quantization table. + */ +#define GST_JPEG_MAX_QUANT_ELEMENTS 64 + +typedef struct _GstJpegQuantTable GstJpegQuantTable; +typedef struct _GstJpegQuantTables GstJpegQuantTables; +typedef struct _GstJpegHuffmanTable GstJpegHuffmanTable; +typedef struct _GstJpegHuffmanTables GstJpegHuffmanTables; +typedef struct _GstJpegScanComponent GstJpegScanComponent; +typedef struct _GstJpegScanHdr GstJpegScanHdr; +typedef struct _GstJpegFrameComponent GstJpegFrameComponent; +typedef struct _GstJpegFrameHdr GstJpegFrameHdr; +typedef struct _GstJpegMarkerSegment GstJpegMarkerSegment; + +/** + * GstJpegMarkerCode: + * @GST_JPEG_MARKER_SOF_MIN: Start of frame min marker code + * @GST_JPEG_MARKER_SOF_MAX: Start of frame max marker code + * @GST_JPEG_MARKER_DHT: Huffman tabler marker code + * @GST_JPEG_MARKER_DAC: Arithmetic coding marker code + * @GST_JPEG_MARKER_RST_MIN: Restart interval min marker code + * @GST_JPEG_MARKER_RST_MAX: Restart interval max marker code + * @GST_JPEG_MARKER_SOI: Start of image marker code + * @GST_JPEG_MARKER_EOI: End of image marker code + * @GST_JPEG_MARKER_SOS: Start of scan marker code + * @GST_JPEG_MARKER_DQT: Define quantization table marker code + * @GST_JPEG_MARKER_DNL: Define number of lines marker code + * @GST_JPEG_MARKER_DRI: Define restart interval marker code + * @GST_JPEG_MARKER_APP_MIN: Application segment min marker code + * @GST_JPEG_MARKER_APP_MAX: Application segment max marker code + * @GST_JPEG_MARKER_COM: Comment marker code + * + * Indicates the type of JPEG segment. + */ +typedef enum { + GST_JPEG_MARKER_SOF_MIN = 0xC0, + GST_JPEG_MARKER_SOF_MAX = 0xCF, + GST_JPEG_MARKER_DHT = 0xC4, + GST_JPEG_MARKER_DAC = 0xCC, + GST_JPEG_MARKER_RST_MIN = 0xD0, + GST_JPEG_MARKER_RST_MAX = 0xD7, + GST_JPEG_MARKER_SOI = 0xD8, + GST_JPEG_MARKER_EOI = 0xD9, + GST_JPEG_MARKER_SOS = 0xDA, + GST_JPEG_MARKER_DQT = 0xDB, + GST_JPEG_MARKER_DNL = 0xDC, + GST_JPEG_MARKER_DRI = 0xDD, + GST_JPEG_MARKER_APP_MIN = 0xE0, + GST_JPEG_MARKER_APP_MAX = 0xEF, + GST_JPEG_MARKER_COM = 0xFE, +} GstJpegMarkerCode; + +/** + * GstJpegProfile: + * @GST_JPEG_PROFILE_BASELINE: Baseline DCT + * @GST_JPEG_PROFILE_EXTENDED: Extended sequential DCT + * @GST_JPEG_PROFILE_PROGRESSIVE: Progressive DCT + * @GST_JPEG_PROFILE_LOSSLESS: Lossless (sequential) + * + * JPEG encoding processes. + */ +typedef enum { + GST_JPEG_PROFILE_BASELINE = 0x00, + GST_JPEG_PROFILE_EXTENDED = 0x01, + GST_JPEG_PROFILE_PROGRESSIVE = 0x02, + GST_JPEG_PROFILE_LOSSLESS = 0x03, +} GstJpegProfile; + +/** + * GstJpegEntropyCodingMode: + * @GST_JPEG_ENTROPY_CODING_HUFFMAN: Huffman coding + * @GST_JPEG_ENTROPY_CODING_ARITHMETIC: arithmetic coding + * + * JPEG entropy coding mode. + */ +typedef enum { + GST_JPEG_ENTROPY_CODING_HUFFMAN = 0x00, + GST_JPEG_ENTROPY_CODING_ARITHMETIC = 0x08 +} GstJpegEntropyCodingMode; + +/** + * GstJpegQuantTable: + * @quant_precision: Quantization table element precision (Pq) + * @quant_table: Quantization table elements (Qk) + * @valid: If the quantization table is valid, which means it has + * already been parsed + * + * Quantization table. + */ +struct _GstJpegQuantTable +{ + guint8 quant_precision; + guint16 quant_table[GST_JPEG_MAX_QUANT_ELEMENTS]; + gboolean valid; +}; + +/** + * GstJpegQuantTables: + * @quant_tables: All quantization tables + * + * Helper data structure that holds all quantization tables used to + * decode an image. + */ +struct _GstJpegQuantTables +{ + GstJpegQuantTable quant_tables[GST_JPEG_MAX_SCAN_COMPONENTS]; +}; + +/** + * GstJpegHuffmanTable: + * @huf_bits: Number of Huffman codes of length i + 1 (Li) + * @huf_vales: Value associated with each Huffman code (Vij) + * @valid: If the Huffman table is valid, which means it has already + * been parsed + * + * Huffman table. + */ +struct _GstJpegHuffmanTable +{ + guint8 huf_bits[16]; + guint8 huf_values[256]; + gboolean valid; +}; + +/** + * GstJpegHuffmanTables: + * @dc_tables: DC Huffman tables + * @ac_tables: AC Huffman tables + * + * Helper data structure that holds all AC/DC Huffman tables used to + * decode an image. + */ +struct _GstJpegHuffmanTables +{ + GstJpegHuffmanTable dc_tables[GST_JPEG_MAX_SCAN_COMPONENTS]; + GstJpegHuffmanTable ac_tables[GST_JPEG_MAX_SCAN_COMPONENTS]; +}; + +/** + * GstJpegScanComponent: + * @component_selector: Scan component selector (Csj) + * @dc_selector: DC entropy coding table destination selector (Tdj) + * @ac_selector: AC entropy coding table destination selector (Taj) + + * Component-specification parameters. + */ +struct _GstJpegScanComponent +{ + guint8 component_selector; /* 0 .. 255 */ + guint8 dc_selector; /* 0 .. 3 */ + guint8 ac_selector; /* 0 .. 3 */ +}; + +/** + * GstJpegScanHdr: + * @num_components: Number of image components in scan (Ns) + * @components: Image components + * + * Scan header. + */ +struct _GstJpegScanHdr +{ + guint8 num_components; /* 1 .. 4 */ + GstJpegScanComponent components[GST_JPEG_MAX_SCAN_COMPONENTS]; +}; + +/** + * GstJpegFrameComponent: + * @identifier: Component identifier (Ci) + * @horizontal_factor: Horizontal sampling factor (Hi) + * @vertical_factor: Vertical sampling factor (Vi) + * @quant_table_selector: Quantization table destination selector (Tqi) + * + * Component-specification parameters. + */ +struct _GstJpegFrameComponent +{ + guint8 identifier; /* 0 .. 255 */ + guint8 horizontal_factor; /* 1 .. 4 */ + guint8 vertical_factor; /* 1 .. 4 */ + guint8 quant_table_selector; /* 0 .. 3 */ +}; + +/** + * GstJpegFrameHdr: + * @sample_precision: Sample precision (P) + * @height: Number of lines (Y) + * @width: Number of samples per line (X) + * @num_components: Number of image components in frame (Nf) + * @components: Image components + * @restart_interval: Number of MCU in the restart interval (Ri) + * + * Frame header. + */ +struct _GstJpegFrameHdr +{ + guint8 sample_precision; /* 2 .. 16 */ + guint16 width; /* 1 .. 65535 */ + guint16 height; /* 0 .. 65535 */ + guint8 num_components; /* 1 .. 255 */ + GstJpegFrameComponent components[GST_JPEG_MAX_FRAME_COMPONENTS]; +}; + +/** + * GstJpegMarkerSegment: + * @type: The type of the segment that starts at @offset + * @offset: The offset to the segment start in bytes. This is the + * exact start of the segment, no marker code included + * @size: The size in bytes of the segment, or -1 if the end was not + * found. It is the exact size of the segment, no marker code included + * + * A structure that contains the type of a segment, its offset and its size. + */ +struct _GstJpegMarkerSegment +{ + guint8 marker; + guint offset; + gint size; +}; + +/** + * gst_jpeg_scan_for_marker_code: + * @data: The data to parse + * @size: The size of @data + * @offset: The offset from which to start parsing + * + * Scans the JPEG bitstream contained in @data for the next marker + * code. If found, the function returns an offset to the marker code, + * including the 0xff prefix code but excluding any extra fill bytes. + * + * Returns: offset to the marker code if found, or -1 if not found. + */ +gint gst_jpeg_scan_for_marker_code (const guint8 * data, + gsize size, + guint offset); + +/** + * gst_jpeg_parse: + * @data: The data to parse + * @size: The size of @data + * @offset: The offset from which to start parsing + * + * Parses the JPEG bitstream contained in @data, and returns the + * detected segment as a #GstJpegMarkerSegment. + * + * Returns: TRUE if a packet start code was found. + */ +gboolean gst_jpeg_parse (GstJpegMarkerSegment * seg, + const guint8 * data, + gsize size, + guint offset); + +/** + * gst_jpeg_parse_frame_hdr: + * @hdr: (out): The #GstJpegFrameHdr structure to fill in + * @data: The data from which to parse the frame header + * @size: The size of @data + * @offset: The offset in bytes from which to start parsing @data + * + * Parses the @hdr JPEG frame header structure members from @data. + * + * Returns: TRUE if the frame header was correctly parsed. + */ +gboolean gst_jpeg_parse_frame_hdr (GstJpegFrameHdr * hdr, + const guint8 * data, + gsize size, + guint offset); + +/** + * gst_jpeg_parse_scan_hdr: + * @hdr: (out): The #GstJpegScanHdr structure to fill in + * @data: The data from which to parse the scan header + * @size: The size of @data + * @offset: The offset in bytes from which to start parsing @data + * + * Parses the @hdr JPEG scan header structure members from @data. + * + * Returns: TRUE if the scan header was correctly parsed + */ +gboolean gst_jpeg_parse_scan_hdr (GstJpegScanHdr * hdr, + const guint8 * data, + gsize size, + guint offset); + +/** + * gst_jpeg_parse_quantization_table: + * @quant_tables: (out): The #GstJpegQuantizationTable structure to fill in + * @num_quant_tables: The number of allocated quantization tables in @quant_tables + * @data: The data from which to parse the quantization table + * @size: The size of @data + * @offset: The offset in bytes from which to start parsing @data + * + * Parses the JPEG quantization table structure members from @data. + * + * Note: @quant_tables represents the complete set of possible + * quantization tables. However, the parser will only write to the + * quantization table specified by the table destination identifier + * (Tq). While doing so, the @valid flag of the specified quantization + * table will also be set to %TRUE. + * + * Returns: TRUE if the quantization table was correctly parsed. + */ +gboolean gst_jpeg_parse_quant_table (GstJpegQuantTables *quant_tables, + const guint8 * data, + gsize size, + guint offset); + +/** + * gst_jpeg_parse_huffman_table: + * @huf_tables: (out): The #GstJpegHuffmanTable structure to fill in + * @data: The data from which to parse the Huffman table + * @size: The size of @data + * @offset: The offset in bytes from which to start parsing @data + * + * Parses the JPEG Huffman table structure members from @data. + * + * Note: @huf_tables represents the complete set of possible Huffman + * tables. However, the parser will only write to the Huffman table + * specified by the table destination identifier (Th). While doing so, + * the @valid flag of the specified Huffman table will also be set to + * %TRUE; + * + * Returns: TRUE if the Huffman table was correctly parsed. + */ +gboolean gst_jpeg_parse_huffman_table (GstJpegHuffmanTables *huf_tables, + const guint8 * data, + gsize size, + guint offset); + +/** + * gst_jpeg_parse_restart_interval: + * @interval: (out): The parsed restart interval value + * @data: The data from which to parse the restart interval specification + * @size: The size of @data + * @offset: The offset in bytes from which to start parsing @data + * + * Returns: TRUE if the restart interval value was correctly parsed. + */ +gboolean gst_jpeg_parse_restart_interval (guint * interval, + const guint8 * data, + gsize size, + guint offset); + +/** + * gst_jpeg_get_default_huffman_tables: + * @huf_tables: (out): The default DC/AC Huffman tables to fill in + * + * Fills in @huf_tables with the default AC/DC Huffman tables, as + * specified by the JPEG standard. + */ +void gst_jpeg_get_default_huffman_tables (GstJpegHuffmanTables *huf_tables); + +/** + * gst_jpeg_get_default_quantization_table: + * @quant_tables: (out): The default luma/chroma quant-tables in zigzag mode + * + * Fills in @quant_tables with the default quantization tables, as + * specified by the JPEG standard. + */ +void gst_jpeg_get_default_quantization_tables (GstJpegQuantTables *quant_tables); + +G_END_DECLS + +#endif /* GST_JPEG_PARSER_H */ diff --git a/ext/codecparsers/gst-libs/gst/codecparsers/gstmpeg4parser.c b/ext/codecparsers/gst-libs/gst/codecparsers/gstmpeg4parser.c new file mode 100644 index 0000000..2af6914 --- /dev/null +++ b/ext/codecparsers/gst-libs/gst/codecparsers/gstmpeg4parser.c @@ -0,0 +1,1749 @@ +/* Gstreamer + * Copyright (C) <2011> Intel + * Copyright (C) <2011> Collabora Ltd. + * Copyright (C) <2011> Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +/** + * SECTION:gstmpeg4parser + * @short_description: Convenience library for parsing mpeg4 part 2 video + * bitstream. + * + * For more details about the structures, you can refer to the + * specifications: ISO-IEC-14496-2_2004_MPEG4_VISUAL.pdf + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + + +#include "gstmpeg4parser.h" +#include "parserutils.h" + +#ifndef GST_DISABLE_GST_DEBUG + +#define GST_CAT_DEFAULT ensure_debug_category() + +static GstDebugCategory * +ensure_debug_category (void) +{ + static gsize cat_gonce = 0; + + if (g_once_init_enter (&cat_gonce)) { + gsize cat_done; + + cat_done = (gsize) _gst_debug_category_new ("codecparsers_mpeg4", 0, + "GstMpeg4 codec parsing library"); + + g_once_init_leave (&cat_gonce, cat_done); + } + + return (GstDebugCategory *) cat_gonce; +} + +#else + +#define ensure_debug_category() /* NOOP */ + +#endif /* GST_DISABLE_GST_DEBUG */ + +#define CHECK_MARKER(br) G_STMT_START { \ + guint8 marker;\ + if (!gst_bit_reader_get_bits_uint8 (br, &marker, 1)) { \ + GST_WARNING ("failed to read marker bit"); \ + goto failed; \ + } else if (!marker) {\ + GST_WARNING ("Wrong marker bit"); \ + goto failed;\ + }\ +} G_STMT_END + +#define MARKER_UNCHECKED(br) G_STMT_START { \ + if (!gst_bit_reader_get_bits_uint8_unchecked (br, 1)) { \ + GST_WARNING ("Wrong marker bit"); \ + goto failed; \ + } \ +} G_STMT_END + +#define CHECK_REMAINING(br, needed) G_STMT_START { \ + if (gst_bit_reader_get_remaining (br) < needed) \ + goto failed; \ +} G_STMT_END + +static const guint8 default_intra_quant_mat[64] = { + 8, 17, 18, 19, 21, 23, 25, 27, + 17, 18, 19, 21, 23, 25, 27, 28, + 20, 21, 22, 23, 24, 26, 28, 30, + 21, 22, 23, 24, 26, 28, 30, 32, + 22, 23, 24, 26, 28, 30, 32, 35, + 23, 24, 26, 28, 30, 32, 35, 38, + 25, 26, 28, 30, 32, 35, 38, 41, + 27, 28, 30, 32, 35, 38, 41, 45 +}; + +static const guint8 default_non_intra_quant_mat[64] = { + 16, 17, 18, 19, 20, 21, 22, 23, + 17, 18, 19, 20, 21, 22, 23, 24, + 18, 19, 20, 21, 22, 23, 24, 25, + 19, 20, 21, 22, 23, 24, 26, 27, + 20, 21, 22, 23, 25, 26, 27, 28, + 21, 22, 23, 24, 26, 27, 28, 30, + 22, 23, 24, 26, 27, 28, 30, 31, + 23, 24, 25, 27, 28, 30, 31, 33, +}; + +static const guint8 mpeg4_zigzag_8x8[64] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + +static const VLCTable mpeg4_dmv_size_vlc_table[] = { + {0x00, 2, 0}, + {0x02, 3, 1}, + {0x03, 3, 2}, + {0x04, 3, 3}, + {0x05, 3, 4}, + {0x06, 3, 5}, + {0x0e, 4, 6}, + {0x1e, 5, 7}, + {0x3e, 6, 8}, + {0x7e, 7, 9}, + {0xfe, 8, 10}, + {0x1fe, 9, 11}, + {0x3fe, 10, 12}, + {0x7fe, 11, 13}, + {0xffe, 12, 14} +}; + +static void +mpeg4_util_par_from_info (guint8 aspect_ratio_info, guint8 * par_width, + guint8 * par_height) +{ + switch (aspect_ratio_info) { + case 0x02: + *par_width = 12; + *par_height = 11; + break; + case 0x03: + *par_width = 10; + *par_height = 11; + break; + case 0x04: + *par_width = 16; + *par_height = 11; + break; + case 0x05: + *par_width = 40; + *par_height = 33; + break; + + case 0x01: + default: + *par_width = 1; + *par_height = 1; + } +} + +static gboolean +parse_quant (GstBitReader * br, guint8 quant_mat[64], + const guint8 default_quant_mat[64], guint8 * load_quant_mat) +{ + READ_UINT8 (br, *load_quant_mat, 1); + if (*load_quant_mat) { + guint i; + guint8 val; + + val = 1; + for (i = 0; i < 64; i++) { + + if (val != 0) + READ_UINT8 (br, val, 8); + + if (val == 0) { + if (i == 0) + goto invalid_quant_mat; + quant_mat[mpeg4_zigzag_8x8[i]] = quant_mat[mpeg4_zigzag_8x8[i - 1]]; + } else + quant_mat[mpeg4_zigzag_8x8[i]] = val; + } + } else + memcpy (quant_mat, default_quant_mat, 64); + + return TRUE; + +failed: + GST_WARNING ("failed parsing quant matrix"); + return FALSE; + +invalid_quant_mat: + GST_WARNING ("the first value should be non zero"); + goto failed; +} + +static gboolean +parse_signal_type (GstBitReader * br, GstMpeg4VideoSignalType * signal_type) +{ + READ_UINT8 (br, signal_type->type, 1); + + if (signal_type->type) { + + READ_UINT8 (br, signal_type->format, 3); + READ_UINT8 (br, signal_type->range, 1); + READ_UINT8 (br, signal_type->color_description, 1); + + if (signal_type->color_description) { + READ_UINT8 (br, signal_type->color_primaries, 8); + READ_UINT8 (br, signal_type->transfer_characteristics, 8); + READ_UINT8 (br, signal_type->matrix_coefficients, 8); + } + } + + return TRUE; + +failed: + GST_WARNING ("failed parsing \"Video Signal Type\""); + + return FALSE; +} + +static gboolean +parse_sprite_trajectory (GstBitReader * br, + GstMpeg4SpriteTrajectory * sprite_traj, guint no_of_sprite_warping_points) +{ + guint i, length; + + for (i = 0; i < no_of_sprite_warping_points; i++) { + + if (!decode_vlc (br, &length, mpeg4_dmv_size_vlc_table, + G_N_ELEMENTS (mpeg4_dmv_size_vlc_table))) + goto failed; + + if (length) + READ_UINT16 (br, sprite_traj->vop_ref_points[i], length); + CHECK_MARKER (br); + + if (!decode_vlc (br, &length, mpeg4_dmv_size_vlc_table, + G_N_ELEMENTS (mpeg4_dmv_size_vlc_table))) + goto failed; + + if (length) + READ_UINT16 (br, sprite_traj->sprite_ref_points[i], length); + CHECK_MARKER (br); + } + + return TRUE; + +failed: + GST_WARNING ("Could not parse the sprite trajectory"); + return FALSE; +} + +static guint +find_psc (GstByteReader * br) +{ + guint psc_pos = -1, psc; + + if (!gst_byte_reader_peek_uint24_be (br, &psc)) + goto failed; + + /* Scan for the picture start code (22 bits - 0x0020) */ + while ((gst_byte_reader_get_remaining (br) >= 3)) { + if (gst_byte_reader_peek_uint24_be (br, &psc) && + ((psc & 0xfffffc) == 0x000080)) { + psc_pos = gst_byte_reader_get_pos (br); + break; + } else + gst_byte_reader_skip_unchecked (br, 1); + } + +failed: + + return psc_pos; +} + +static inline guint8 +compute_resync_marker_size (const GstMpeg4VideoObjectPlane * vop, + guint32 * pattern, guint32 * mask) +{ + guint8 off; + + /* FIXME handle the binary only shape case */ + switch (vop->coding_type) { + case (GST_MPEG4_I_VOP): + off = 16; + break; + case (GST_MPEG4_S_VOP): + case (GST_MPEG4_P_VOP): + off = 15 + vop->fcode_forward; + + break; + case (GST_MPEG4_B_VOP): + off = MAX (15 + MAX (vop->fcode_forward, vop->fcode_backward), 17); + + break; + default: + return -1; + } + + if (mask && pattern) { + switch (off) { + case 16: + *pattern = 0x00008000; + *mask = 0xffff8000; + break; + case 17: + *pattern = 0x00004000; + *mask = 0xffffc000; + break; + case 18: + *pattern = 0x00002000; + *mask = 0xffffe000; + break; + case 19: + *pattern = 0x00001000; + *mask = 0xfffff000; + break; + case 20: + *pattern = 0x00000800; + *mask = 0xfffff800; + break; + case 21: + *pattern = 0x00000400; + *mask = 0xfffffc00; + break; + case 22: + *pattern = 0x00000200; + *mask = 0xfffffe00; + break; + case 23: + *pattern = 0x00000100; + *mask = 0xffffff00; + break; + } + } + + return off++; /* Take the following 1 into account */ +} + +/** + * gst_mpeg4_next_resync: + * @packet: The #GstMpeg4Packet to fill + * @vop: The previously parsed #GstMpeg4VideoObjectPlane + * @offset: offset from which to start the parsing + * @data: The data to parse + * @size: The size of the @data to parse + * + * Parses @data and fills @packet with the information of the next resync packet + * found. + * + * Returns: a #GstMpeg4ParseResult + */ +static GstMpeg4ParseResult +gst_mpeg4_next_resync (GstMpeg4Packet * packet, + const GstMpeg4VideoObjectPlane * vop, const guint8 * data, gsize size, + gboolean first_resync_marker) +{ + guint markersize = 0, off1, off2; + guint32 mask = 0xff, pattern = 0xff; + GstByteReader br; + + gst_byte_reader_init (&br, data, size); + + g_return_val_if_fail (packet != NULL, GST_MPEG4_PARSER_ERROR); + g_return_val_if_fail (vop != NULL, GST_MPEG4_PARSER_ERROR); + + markersize = compute_resync_marker_size (vop, &pattern, &mask); + + if (first_resync_marker) { + off1 = 0; + } else { + off1 = gst_byte_reader_masked_scan_uint32 (&br, mask, pattern, 0, size); + } + + if (off1 == -1) + return GST_MPEG4_PARSER_NO_PACKET; + + GST_DEBUG ("Resync code found at %i", off1); + + packet->offset = off1; + packet->type = GST_MPEG4_RESYNC; + packet->marker_size = markersize; + + off2 = gst_byte_reader_masked_scan_uint32 (&br, mask, pattern, + off1 + 2, size - off1 - 2); + + if (off2 == -1) + return GST_MPEG4_PARSER_NO_PACKET_END; + + packet->size = off2 - off1; + + return GST_MPEG4_PARSER_OK; +} + + +/********** API **********/ + +/** + * gst_mpeg4_parse: + * @packet: The #GstMpeg4Packet to fill + * @skip_user_data: %TRUE to skip user data packet %FALSE otherwize + * @vop: The last parsed #GstMpeg4VideoObjectPlane or %NULL if you do + * not need to detect the resync codes. + * @offset: offset from which to start the parsing + * @data: The data to parse + * @size: The size of the @data to parse + * + * Parses @data and fills @packet with the information of the next packet + * found. + * + * Returns: a #GstMpeg4ParseResult + */ +GstMpeg4ParseResult +gst_mpeg4_parse (GstMpeg4Packet * packet, gboolean skip_user_data, + GstMpeg4VideoObjectPlane * vop, const guint8 * data, guint offset, + gsize size) +{ + gint off1, off2; + GstByteReader br; + GstMpeg4ParseResult resync_res; + static guint first_resync_marker = TRUE; + + gst_byte_reader_init (&br, data, size); + + g_return_val_if_fail (packet != NULL, GST_MPEG4_PARSER_ERROR); + + if (size - offset <= 4) { + GST_DEBUG ("Can't parse, buffer is to small size %" G_GSSIZE_FORMAT + " at offset %d", size, offset); + return GST_MPEG4_PARSER_ERROR; + } + + if (vop) { + resync_res = + gst_mpeg4_next_resync (packet, vop, data + offset, size - offset, + first_resync_marker); + first_resync_marker = FALSE; + + /* We found a complet slice */ + if (resync_res == GST_MPEG4_PARSER_OK) + return resync_res; + else if (resync_res == GST_MPEG4_PARSER_NO_PACKET_END) { + /* It doesn't mean there is no standard packet end, look for it */ + off1 = packet->offset; + goto find_end; + } else if (resync_res == GST_MPEG4_PARSER_NO_PACKET) + return resync_res; + } else { + first_resync_marker = TRUE; + } + + off1 = gst_byte_reader_masked_scan_uint32 (&br, 0xffffff00, 0x00000100, + offset, size - offset); + + if (off1 == -1) { + GST_DEBUG ("No start code prefix in this buffer"); + return GST_MPEG4_PARSER_NO_PACKET; + } + + /* Recursively skip user data if needed */ + if (skip_user_data && data[off1 + 3] == GST_MPEG4_USER_DATA) + /* If we are here, we know no resync code has been found the first time, so we + * don't look for it this time */ + return gst_mpeg4_parse (packet, skip_user_data, NULL, data, off1 + 3, size); + + packet->offset = off1 + 3; + packet->data = data; + packet->type = (GstMpeg4StartCode) (data[off1 + 3]); + +find_end: + off2 = gst_byte_reader_masked_scan_uint32 (&br, 0xffffff00, 0x00000100, + off1 + 4, size - off1 - 4); + + if (off2 == -1) { + GST_DEBUG ("Packet start %d, No end found", off1 + 4); + + packet->size = G_MAXUINT; + return GST_MPEG4_PARSER_NO_PACKET_END; + } + + if (packet->type == GST_MPEG4_RESYNC) { + packet->size = (gsize) off2 - off1; + } else { + packet->size = (gsize) off2 - off1 - 3; + } + + GST_DEBUG ("Complete packet of type %x found at: %d, Size: %" G_GSSIZE_FORMAT, + packet->type, packet->offset, packet->size); + return GST_MPEG4_PARSER_OK; + +} + +/** + * gst_h263_parse: + * @packet: The #GstMpeg4Packet to fill + * @offset: offset from which to start the parsing + * @data: The data to parse + * @size: The size of the @data to parse + * + * Parses @data and fills @packet with the information of the next packet + * found. + * + * Note that the type of the packet is meaningless in this case. + * + * Returns: a #GstMpeg4ParseResult + */ +GstMpeg4ParseResult +gst_h263_parse (GstMpeg4Packet * packet, + const guint8 * data, guint offset, gsize size) +{ + gint off1, off2; + GstByteReader br; + + gst_byte_reader_init (&br, data + offset, size - offset); + + g_return_val_if_fail (packet != NULL, GST_MPEG4_PARSER_ERROR); + + if (size - offset < 3) { + GST_DEBUG ("Can't parse, buffer is to small size %" G_GSSIZE_FORMAT + " at offset %d", size, offset); + return GST_MPEG4_PARSER_ERROR; + } + + off1 = find_psc (&br); + + if (off1 == -1) { + GST_DEBUG ("No start code prefix in this buffer"); + return GST_MPEG4_PARSER_NO_PACKET; + } + + packet->offset = off1 + offset; + packet->data = data; + + gst_byte_reader_skip_unchecked (&br, 3); + off2 = find_psc (&br); + + if (off2 == -1) { + GST_DEBUG ("Packet start %d, No end found", off1); + + packet->size = G_MAXUINT; + return GST_MPEG4_PARSER_NO_PACKET_END; + } + + packet->size = (gsize) off2 - off1; + + GST_DEBUG ("Complete packet found at: %d, Size: %" G_GSSIZE_FORMAT, + packet->offset, packet->size); + + return GST_MPEG4_PARSER_OK; +} + +/** + * gst_mpeg4_parse_visual_object_sequence: + * @vos: The #GstMpeg4VisualObjectSequence structure to fill + * @data: The data to parse, should contain the visual_object_sequence_start_code + * but not the start code prefix + * @size: The size of the @data to parse + * + * Parses @data containing the visual object sequence packet, and fills + * the @vos structure. + * + * Returns: a #GstMpeg4ParseResult + */ +GstMpeg4ParseResult +gst_mpeg4_parse_visual_object_sequence (GstMpeg4VisualObjectSequence * vos, + const guint8 * data, gsize size) +{ + guint8 vos_start_code; + GstBitReader br = GST_BIT_READER_INIT (data, size); + + g_return_val_if_fail (vos != NULL, GST_MPEG4_PARSER_ERROR); + + READ_UINT8 (&br, vos_start_code, 8); + if (vos_start_code != GST_MPEG4_VISUAL_OBJ_SEQ_START) + goto wrong_start_code; + + READ_UINT8 (&br, vos->profile_and_level_indication, 8); + + switch (vos->profile_and_level_indication) { + case 0x01: + vos->profile = GST_MPEG4_PROFILE_SIMPLE; + vos->level = GST_MPEG4_LEVEL1; + break; + case 0x02: + vos->profile = GST_MPEG4_PROFILE_SIMPLE; + vos->level = GST_MPEG4_LEVEL2; + break; + case 0x03: + vos->profile = GST_MPEG4_PROFILE_SIMPLE; + vos->level = GST_MPEG4_LEVEL3; + break; + case 0x08: + vos->profile = GST_MPEG4_PROFILE_SIMPLE; + vos->level = GST_MPEG4_LEVEL0; + break; + case 0x10: + vos->profile = GST_MPEG4_PROFILE_SIMPLE_SCALABLE; + vos->level = GST_MPEG4_LEVEL0; + break; + case 0x11: + vos->profile = GST_MPEG4_PROFILE_SIMPLE_SCALABLE; + vos->level = GST_MPEG4_LEVEL1; + break; + case 0x12: + vos->profile = GST_MPEG4_PROFILE_SIMPLE_SCALABLE; + vos->level = GST_MPEG4_LEVEL2; + break; + case 0x21: + vos->profile = GST_MPEG4_PROFILE_CORE; + vos->level = GST_MPEG4_LEVEL1; + break; + case 0x22: + vos->profile = GST_MPEG4_PROFILE_CORE; + vos->level = GST_MPEG4_LEVEL2; + break; + case 0x32: + vos->profile = GST_MPEG4_PROFILE_MAIN; + vos->level = GST_MPEG4_LEVEL2; + break; + case 0x33: + vos->profile = GST_MPEG4_PROFILE_MAIN; + vos->level = GST_MPEG4_LEVEL3; + break; + case 0x34: + vos->profile = GST_MPEG4_PROFILE_MAIN; + vos->level = GST_MPEG4_LEVEL4; + break; + case 0x42: + vos->profile = GST_MPEG4_PROFILE_N_BIT; + vos->level = GST_MPEG4_LEVEL2; + break; + case 0x51: + vos->profile = GST_MPEG4_PROFILE_SCALABLE_TEXTURE; + vos->level = GST_MPEG4_LEVEL1; + break; + case 0x61: + vos->profile = GST_MPEG4_PROFILE_SIMPLE_FACE_ANIMATION; + vos->level = GST_MPEG4_LEVEL1; + break; + case 0x62: + vos->profile = GST_MPEG4_PROFILE_SIMPLE_FACE_ANIMATION; + vos->level = GST_MPEG4_LEVEL2; + break; + case 0x63: + vos->profile = GST_MPEG4_PROFILE_SIMPLE_FBA; + vos->level = GST_MPEG4_LEVEL1; + break; + case 0x64: + vos->profile = GST_MPEG4_PROFILE_SIMPLE_FBA; + vos->level = GST_MPEG4_LEVEL2; + break; + case 0x71: + vos->profile = GST_MPEG4_PROFILE_BASIC_ANIMATED_TEXTURE; + vos->level = GST_MPEG4_LEVEL1; + break; + case 0x72: + vos->profile = GST_MPEG4_PROFILE_BASIC_ANIMATED_TEXTURE; + vos->level = GST_MPEG4_LEVEL2; + break; + case 0x81: + vos->profile = GST_MPEG4_PROFILE_HYBRID; + vos->level = GST_MPEG4_LEVEL1; + break; + case 0x82: + vos->profile = GST_MPEG4_PROFILE_HYBRID; + vos->level = GST_MPEG4_LEVEL2; + break; + case 0x91: + vos->profile = GST_MPEG4_PROFILE_ADVANCED_REALTIME_SIMPLE; + vos->level = GST_MPEG4_LEVEL1; + break; + case 0x92: + vos->profile = GST_MPEG4_PROFILE_ADVANCED_REALTIME_SIMPLE; + vos->level = GST_MPEG4_LEVEL2; + break; + case 0x93: + vos->profile = GST_MPEG4_PROFILE_ADVANCED_REALTIME_SIMPLE; + vos->level = GST_MPEG4_LEVEL3; + break; + case 0x94: + vos->profile = GST_MPEG4_PROFILE_ADVANCED_REALTIME_SIMPLE; + vos->level = GST_MPEG4_LEVEL4; + break; + case 0xa1: + vos->profile = GST_MPEG4_PROFILE_CORE_SCALABLE; + vos->level = GST_MPEG4_LEVEL1; + break; + case 0xa2: + vos->profile = GST_MPEG4_PROFILE_CORE_SCALABLE; + vos->level = GST_MPEG4_LEVEL2; + break; + case 0xa3: + vos->profile = GST_MPEG4_PROFILE_CORE_SCALABLE; + vos->level = GST_MPEG4_LEVEL3; + break; + case 0xb1: + vos->profile = GST_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY; + vos->level = GST_MPEG4_LEVEL1; + break; + case 0xb2: + vos->profile = GST_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY; + vos->level = GST_MPEG4_LEVEL2; + break; + case 0xb3: + vos->profile = GST_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY; + vos->level = GST_MPEG4_LEVEL3; + break; + case 0xb4: + vos->profile = GST_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY; + vos->level = GST_MPEG4_LEVEL4; + break; + case 0xc1: + vos->profile = GST_MPEG4_PROFILE_ADVANCED_CORE; + vos->level = GST_MPEG4_LEVEL1; + break; + case 0xc2: + vos->profile = GST_MPEG4_PROFILE_ADVANCED_CORE; + vos->level = GST_MPEG4_LEVEL2; + break; + case 0xc3: + vos->profile = GST_MPEG4_PROFILE_ADVANCED_CORE; + vos->level = GST_MPEG4_LEVEL3; + break; + case 0xd1: + vos->profile = GST_MPEG4_PROFILE_ADVANCED_SCALABLE_TEXTURE; + vos->level = GST_MPEG4_LEVEL1; + break; + case 0xd2: + vos->profile = GST_MPEG4_PROFILE_ADVANCED_SCALABLE_TEXTURE; + vos->level = GST_MPEG4_LEVEL2; + break; + case 0xd3: + vos->profile = GST_MPEG4_PROFILE_ADVANCED_SCALABLE_TEXTURE; + vos->level = GST_MPEG4_LEVEL3; + break; + case 0xe1: + vos->profile = GST_MPEG4_PROFILE_SIMPLE_STUDIO; + vos->level = GST_MPEG4_LEVEL1; + break; + case 0xe2: + vos->profile = GST_MPEG4_PROFILE_SIMPLE_STUDIO; + vos->level = GST_MPEG4_LEVEL2; + break; + case 0xe3: + vos->profile = GST_MPEG4_PROFILE_SIMPLE_STUDIO; + vos->level = GST_MPEG4_LEVEL3; + break; + case 0xe4: + vos->profile = GST_MPEG4_PROFILE_SIMPLE_STUDIO; + vos->level = GST_MPEG4_LEVEL4; + break; + case 0xe5: + vos->profile = GST_MPEG4_PROFILE_CORE_STUDIO; + vos->level = GST_MPEG4_LEVEL1; + break; + case 0xe6: + vos->profile = GST_MPEG4_PROFILE_CORE_STUDIO; + vos->level = GST_MPEG4_LEVEL2; + break; + case 0xe7: + vos->profile = GST_MPEG4_PROFILE_CORE_STUDIO; + vos->level = GST_MPEG4_LEVEL3; + break; + case 0xe8: + vos->profile = GST_MPEG4_PROFILE_CORE_STUDIO; + vos->level = GST_MPEG4_LEVEL4; + break; + case 0xf0: + vos->profile = GST_MPEG4_PROFILE_ADVANCED_SIMPLE; + vos->level = GST_MPEG4_LEVEL0; + break; + case 0xf1: + vos->profile = GST_MPEG4_PROFILE_ADVANCED_SIMPLE; + vos->level = GST_MPEG4_LEVEL1; + break; + case 0xf2: + vos->profile = GST_MPEG4_PROFILE_ADVANCED_SIMPLE; + vos->level = GST_MPEG4_LEVEL2; + break; + case 0xf3: + vos->profile = GST_MPEG4_PROFILE_ADVANCED_SIMPLE; + vos->level = GST_MPEG4_LEVEL3; + break; + case 0xf4: + vos->profile = GST_MPEG4_PROFILE_ADVANCED_SIMPLE; + vos->level = GST_MPEG4_LEVEL4; + break; + case 0xf5: + vos->profile = GST_MPEG4_PROFILE_ADVANCED_SIMPLE; + vos->level = GST_MPEG4_LEVEL5; + break; + case 0xf7: + vos->profile = GST_MPEG4_PROFILE_ADVANCED_SIMPLE; + vos->level = GST_MPEG4_LEVEL3b; + break; + case 0xf8: + vos->profile = GST_MPEG4_PROFILE_FINE_GRANULARITY_SCALABLE; + vos->level = GST_MPEG4_LEVEL0; + break; + case 0xf9: + vos->profile = GST_MPEG4_PROFILE_FINE_GRANULARITY_SCALABLE; + vos->level = GST_MPEG4_LEVEL1; + break; + case 0xfa: + vos->profile = GST_MPEG4_PROFILE_FINE_GRANULARITY_SCALABLE; + vos->level = GST_MPEG4_LEVEL2; + break; + case 0xfb: + vos->profile = GST_MPEG4_PROFILE_FINE_GRANULARITY_SCALABLE; + vos->level = GST_MPEG4_LEVEL3; + break; + case 0xfc: + vos->profile = GST_MPEG4_PROFILE_FINE_GRANULARITY_SCALABLE; + vos->level = GST_MPEG4_LEVEL4; + break; + case 0xfd: + vos->profile = GST_MPEG4_PROFILE_FINE_GRANULARITY_SCALABLE; + vos->level = GST_MPEG4_LEVEL5; + break; + default: + vos->profile = GST_MPEG4_PROFILE_RESERVED; + vos->level = GST_MPEG4_LEVEL_RESERVED; + break; + } + + return GST_MPEG4_PARSER_OK; + +wrong_start_code: + GST_WARNING ("got buffer with wrong start code"); + return GST_MPEG4_PARSER_ERROR; + +failed: + GST_WARNING ("failed parsing \"Visual Object\""); + return GST_MPEG4_PARSER_ERROR; +} + +/** + * gst_mpeg4_parse_visual_object: + * @vo: The #GstMpeg4VisualObject structure to fill + * @signal_type: The #GstMpeg4VideoSignalType to fill or %NULL + * @data: The data to parse, should contain the vo_start_code + * but not the start code prefix + * @size: The size of the @data to parse + * + * Parses @data containing the visual object packet, and fills + * the @vo structure. + * + * Returns: a #GstMpeg4ParseResult + */ +GstMpeg4ParseResult +gst_mpeg4_parse_visual_object (GstMpeg4VisualObject * vo, + GstMpeg4VideoSignalType * signal_type, const guint8 * data, gsize size) +{ + guint8 vo_start_code, type; + GstBitReader br = GST_BIT_READER_INIT (data, size); + + g_return_val_if_fail (vo != NULL, GST_MPEG4_PARSER_ERROR); + + GST_DEBUG ("Parsing visual object"); + + READ_UINT8 (&br, vo_start_code, 8); + if (vo_start_code != GST_MPEG4_VISUAL_OBJ) + goto wrong_start_code; + + /* set default values */ + vo->verid = 0x1; + vo->priority = 1; + + READ_UINT8 (&br, vo->is_identifier, 1); + if (vo->is_identifier) { + READ_UINT8 (&br, vo->verid, 4); + READ_UINT8 (&br, vo->priority, 3); + } + + READ_UINT8 (&br, type, 4); + vo->type = type; + + if ((type == GST_MPEG4_VIDEO_ID || + type == GST_MPEG4_STILL_TEXTURE_ID) && signal_type) { + + if (!parse_signal_type (&br, signal_type)) + goto failed; + + } else if (signal_type) { + signal_type->type = 0; + } + + return GST_MPEG4_PARSER_OK; + +wrong_start_code: + GST_WARNING ("got buffer with wrong start code"); + return GST_MPEG4_PARSER_ERROR; + +failed: + GST_WARNING ("failed parsing \"Visual Object\""); + return GST_MPEG4_PARSER_ERROR; +} + +/** + * gst_mpeg4_parse_video_object_layer: + * @vol: The #GstMpeg4VideoObjectLayer structure to fill + * @vo: The #GstMpeg4VisualObject currently being parsed or %NULL + * @data: The data to parse + * @size: The size of the @data to parse + * + * Parses @data containing the video object layer packet, and fills + * the @vol structure. + * + * Returns: a #GstMpeg4ParseResult + */ +GstMpeg4ParseResult +gst_mpeg4_parse_video_object_layer (GstMpeg4VideoObjectLayer * vol, + GstMpeg4VisualObject * vo, const guint8 * data, gsize size) +{ + guint8 video_object_layer_start_code; + + /* Used for enums types */ + guint8 tmp; + GstBitReader br = GST_BIT_READER_INIT (data, size); + + g_return_val_if_fail (vol != NULL, GST_MPEG4_PARSER_ERROR); + + GST_DEBUG ("Parsing video object layer"); + + READ_UINT8 (&br, video_object_layer_start_code, 8); + if (!(video_object_layer_start_code >= GST_MPEG4_VIDEO_LAYER_FIRST && + video_object_layer_start_code <= GST_MPEG4_VIDEO_LAYER_LAST)) + goto wrong_start_code; + + /* set default values */ + if (vo) { + vol->verid = vo->verid; + vol->priority = vo->priority; + } else { + vol->verid = 1; + vol->priority = 0; + } + + vol->low_delay = FALSE; + vol->chroma_format = 1; + vol->vbv_parameters = FALSE; + vol->quant_precision = 5; + vol->bits_per_pixel = 8; + vol->quarter_sample = FALSE; + vol->newpred_enable = FALSE; + vol->interlaced = 0; + vol->width = 0; + vol->height = 0; + + READ_UINT8 (&br, vol->random_accessible_vol, 1); + READ_UINT8 (&br, vol->video_object_type_indication, 8); + + READ_UINT8 (&br, vol->is_object_layer_identifier, 1); + if (vol->is_object_layer_identifier) { + READ_UINT8 (&br, vol->verid, 4); + READ_UINT8 (&br, vol->priority, 3); + } + + READ_UINT8 (&br, tmp, 4); + vol->aspect_ratio_info = tmp; + if (vol->aspect_ratio_info != GST_MPEG4_EXTENDED_PAR) { + mpeg4_util_par_from_info (vol->aspect_ratio_info, &vol->par_width, + &vol->par_height); + + } else { + gint v; + + READ_UINT8 (&br, vol->par_width, 8); + v = vol->par_width; + CHECK_ALLOWED (v, 1, 255); + + READ_UINT8 (&br, vol->par_height, 8); + v = vol->par_height; + CHECK_ALLOWED (v, 1, 255); + } + GST_DEBUG ("Pixel aspect ratio %d/%d", vol->par_width, vol->par_width); + + READ_UINT8 (&br, vol->control_parameters, 1); + if (vol->control_parameters) { + guint8 chroma_format; + + READ_UINT8 (&br, chroma_format, 2); + vol->chroma_format = chroma_format; + READ_UINT8 (&br, vol->low_delay, 1); + + READ_UINT8 (&br, vol->vbv_parameters, 1); + if (vol->vbv_parameters) { + CHECK_REMAINING (&br, 79); + + vol->first_half_bitrate = + gst_bit_reader_get_bits_uint16_unchecked (&br, 15); + MARKER_UNCHECKED (&br); + + vol->latter_half_bitrate = + gst_bit_reader_get_bits_uint16_unchecked (&br, 15); + MARKER_UNCHECKED (&br); + + vol->bit_rate = + (vol->first_half_bitrate << 15) | vol->latter_half_bitrate; + + vol->first_half_vbv_buffer_size = + gst_bit_reader_get_bits_uint16_unchecked (&br, 15); + MARKER_UNCHECKED (&br); + + vol->latter_half_vbv_buffer_size = + gst_bit_reader_get_bits_uint8_unchecked (&br, 3); + + vol->vbv_buffer_size = (vol->first_half_vbv_buffer_size << 15) | + vol->latter_half_vbv_buffer_size; + + vol->first_half_vbv_occupancy = + gst_bit_reader_get_bits_uint16_unchecked (&br, 11); + MARKER_UNCHECKED (&br); + + vol->latter_half_vbv_occupancy = + gst_bit_reader_get_bits_uint16_unchecked (&br, 15); + MARKER_UNCHECKED (&br); + } + } + + READ_UINT8 (&br, tmp, 2); + vol->shape = tmp; + + if (vol->shape == GST_MPEG4_GRAYSCALE) { + /* TODO support grayscale shapes, for now we just pass */ + + /* Something the standard starts to define... */ + GST_WARNING ("Grayscale shaped not supported"); + goto failed; + } + + if (vol->shape == GST_MPEG4_GRAYSCALE && vol->verid != 0x01) + READ_UINT8 (&br, vol->shape_extension, 4); + + CHECK_REMAINING (&br, 19); + + MARKER_UNCHECKED (&br); + vol->vop_time_increment_resolution = + gst_bit_reader_get_bits_uint16_unchecked (&br, 16); + if (vol->vop_time_increment_resolution < 1) { + GST_WARNING ("value not in allowed range. value: %d, range %d-%d", + vol->vop_time_increment_resolution, 1, G_MAXUINT16); + goto failed; + } + vol->vop_time_increment_bits = + g_bit_storage (vol->vop_time_increment_resolution); + + MARKER_UNCHECKED (&br); + vol->fixed_vop_rate = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + if (vol->fixed_vop_rate) + READ_UINT16 (&br, vol->fixed_vop_time_increment, + vol->vop_time_increment_bits); + + if (vol->shape != GST_MPEG4_BINARY_ONLY) { + if (vol->shape == GST_MPEG4_RECTANGULAR) { + CHECK_REMAINING (&br, 29); + + MARKER_UNCHECKED (&br); + vol->width = gst_bit_reader_get_bits_uint16_unchecked (&br, 13); + MARKER_UNCHECKED (&br); + vol->height = gst_bit_reader_get_bits_uint16_unchecked (&br, 13); + MARKER_UNCHECKED (&br); + } + + READ_UINT8 (&br, vol->interlaced, 1); + READ_UINT8 (&br, vol->obmc_disable, 1); + + if (vol->verid == 0x1) + READ_UINT8 (&br, tmp, 1); + else + READ_UINT8 (&br, tmp, 2); + vol->sprite_enable = tmp; + + if (vol->sprite_enable == GST_MPEG4_SPRITE_STATIC || + vol->sprite_enable == GST_MPEG4_SPRITE_GMG) { + + if (vol->sprite_enable == GST_MPEG4_SPRITE_GMG) + CHECK_REMAINING (&br, 9); + else { + CHECK_REMAINING (&br, 65); + + vol->sprite_width = gst_bit_reader_get_bits_uint16_unchecked (&br, 13); + MARKER_UNCHECKED (&br); + + vol->sprite_height = gst_bit_reader_get_bits_uint16_unchecked (&br, 13); + MARKER_UNCHECKED (&br); + + vol->sprite_left_coordinate = + gst_bit_reader_get_bits_uint16_unchecked (&br, 13); + MARKER_UNCHECKED (&br); + + vol->sprite_top_coordinate = + gst_bit_reader_get_bits_uint16_unchecked (&br, 13); + MARKER_UNCHECKED (&br); + } + vol->no_of_sprite_warping_points = + gst_bit_reader_get_bits_uint8_unchecked (&br, 6); + vol->sprite_warping_accuracy = + gst_bit_reader_get_bits_uint8_unchecked (&br, 2); + vol->sprite_brightness_change = + gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + + if (vol->sprite_enable != GST_MPEG4_SPRITE_GMG) + vol->low_latency_sprite_enable = + gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + } + + if (vol->verid != 0x1 && vol->shape != GST_MPEG4_RECTANGULAR) + READ_UINT8 (&br, vol->sadct_disable, 1); + + READ_UINT8 (&br, vol->not_8_bit, 1); + if (vol->not_8_bit) { + READ_UINT8 (&br, vol->quant_precision, 4); + CHECK_ALLOWED (vol->quant_precision, 3, 9); + + READ_UINT8 (&br, vol->bits_per_pixel, 4); + CHECK_ALLOWED (vol->bits_per_pixel, 4, 12); + } + + if (vol->shape == GST_MPEG4_GRAYSCALE) { + /* We don't actually support it */ + READ_UINT8 (&br, vol->no_gray_quant_update, 1); + READ_UINT8 (&br, vol->composition_method, 1); + READ_UINT8 (&br, vol->linear_composition, 1); + } + + READ_UINT8 (&br, vol->quant_type, 1); + if (vol->quant_type) { + if (!parse_quant (&br, vol->intra_quant_mat, default_intra_quant_mat, + &vol->load_intra_quant_mat)) + goto failed; + + if (!parse_quant (&br, vol->non_intra_quant_mat, + default_non_intra_quant_mat, &vol->load_non_intra_quant_mat)) + goto failed; + + if (vol->shape == GST_MPEG4_GRAYSCALE) { + /* Something the standard starts to define... */ + GST_WARNING ("Grayscale shaped not supported"); + goto failed; + } + + } else { + memset (&vol->intra_quant_mat, 0, 64); + memset (&vol->non_intra_quant_mat, 0, 64); + } + + if (vol->verid != 0x1) + READ_UINT8 (&br, vol->quarter_sample, 1); + + READ_UINT8 (&br, vol->complexity_estimation_disable, 1); + if (!vol->complexity_estimation_disable) { + guint8 estimation_method; + guint8 estimation_disable; + + /* skip unneeded properties */ + READ_UINT8 (&br, estimation_method, 2); + if (estimation_method < 2) { + READ_UINT8 (&br, estimation_disable, 1); + if (!estimation_disable) + SKIP (&br, 6); + READ_UINT8 (&br, estimation_disable, 1); + if (!estimation_disable) + SKIP (&br, 4); + CHECK_MARKER (&br); + READ_UINT8 (&br, estimation_disable, 1); + if (!estimation_disable) + SKIP (&br, 4); + READ_UINT8 (&br, estimation_disable, 1); + if (!estimation_disable) + SKIP (&br, 6); + CHECK_MARKER (&br); + + if (estimation_method == 1) { + READ_UINT8 (&br, estimation_disable, 1); + if (!estimation_disable) + SKIP (&br, 2); + } + } + } + + READ_UINT8 (&br, vol->resync_marker_disable, 1); + READ_UINT8 (&br, vol->data_partitioned, 1); + + if (vol->data_partitioned) + READ_UINT8 (&br, vol->reversible_vlc, 1); + + if (vol->verid != 0x01) { + READ_UINT8 (&br, vol->newpred_enable, 1); + if (vol->newpred_enable) + /* requested_upstream_message_type and newpred_segment_type */ + SKIP (&br, 3); + + READ_UINT8 (&br, vol->reduced_resolution_vop_enable, 1); + } + + READ_UINT8 (&br, vol->scalability, 1); + if (vol->scalability) { + SKIP (&br, 26); /* Few not needed props */ + READ_UINT8 (&br, vol->enhancement_type, 1); + } + + /* More unused infos */ + } else if (vol->verid != 0x01) { + GST_WARNING ("Binary only shapes not fully supported"); + goto failed; + } + /* ... */ + + return GST_MPEG4_PARSER_OK; + +failed: + GST_WARNING ("failed parsing \"Video Object Layer\""); + return GST_MPEG4_PARSER_ERROR; + +wrong_start_code: + GST_WARNING ("got buffer with wrong start code"); + goto failed; +} + +/** + * gst_mpeg4_parse_group_of_vop: + * @gov: The #GstMpeg4GroupOfVOP structure to fill + * @data: The data to parse + * @size: The size of the @data to parse + * + * Parses @data containing the group of video object plane packet, and fills + * the @gov structure. + * + * Returns: a #GstMpeg4ParseResult + */ +GstMpeg4ParseResult +gst_mpeg4_parse_group_of_vop (GstMpeg4GroupOfVOP * + gov, const guint8 * data, gsize size) +{ + guint8 gov_start_code; + GstBitReader br = GST_BIT_READER_INIT (data, size); + + g_return_val_if_fail (gov != NULL, GST_MPEG4_PARSER_ERROR); + + READ_UINT8 (&br, gov_start_code, 8); + if (gov_start_code != GST_MPEG4_GROUP_OF_VOP) + goto wrong_start_code; + + CHECK_REMAINING (&br, 65); + + gov->hours = gst_bit_reader_get_bits_uint8_unchecked (&br, 5); + gov->minutes = gst_bit_reader_get_bits_uint8_unchecked (&br, 6); + /* marker bit */ + MARKER_UNCHECKED (&br); + gov->seconds = gst_bit_reader_get_bits_uint8_unchecked (&br, 6); + + gov->closed = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + gov->broken_link = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + + return GST_MPEG4_PARSER_OK; + +failed: + GST_WARNING ("failed parsing \"Group of Video Object Plane\""); + return GST_MPEG4_PARSER_ERROR; + +wrong_start_code: + GST_WARNING ("got buffer with wrong start code"); + goto failed; +} + +/** + * gst_mpeg4_parse_video_object_plane: + * @vop: The #GstMpeg4VideoObjectPlane currently being parsed + * @sprite_trajectory: A #GstMpeg4SpriteTrajectory to fill or %NULL + * @vol: The #GstMpeg4VideoObjectLayer structure to fill + * @data: The data to parse + * @size: The size of the @data to parse + * + * Parses @data containing the video object plane packet, and fills the @vol + * structure. + * + * Returns: a #GstMpeg4ParseResult + */ +GstMpeg4ParseResult +gst_mpeg4_parse_video_object_plane (GstMpeg4VideoObjectPlane * vop, + GstMpeg4SpriteTrajectory * sprite_trajectory, + GstMpeg4VideoObjectLayer * vol, const guint8 * data, gsize size) +{ + guint8 vop_start_code, coding_type, modulo_time_base; + GstBitReader br = GST_BIT_READER_INIT (data, size); + + g_return_val_if_fail (vop != NULL, GST_MPEG4_PARSER_ERROR); + + if (vol->shape == GST_MPEG4_BINARY_ONLY) { + /* TODO: implement binary only shapes */ + GST_WARNING ("Binary only shapes not supported"); + goto failed; + } + + READ_UINT8 (&br, vop_start_code, 8); + if (vop_start_code != GST_MPEG4_VIDEO_OBJ_PLANE) + goto wrong_start_code; + + + /* set default values */ + vop->modulo_time_base = 0; + vop->rounding_type = 0; + vop->top_field_first = 1; + vop->alternate_vertical_scan_flag = 0; + vop->fcode_forward = 1; + vop->fcode_backward = 1; + + /* Compute macroblock informations */ + if (vol->interlaced) + vop->mb_height = (2 * (vol->height + 31) / 32); + else + vop->mb_height = (vol->height + 15) / 16; + + vop->mb_width = (vol->width + 15) / 16; + vop->mb_num = vop->mb_height * vop->mb_width; + + READ_UINT8 (&br, coding_type, 2); + vop->coding_type = coding_type; + + READ_UINT8 (&br, modulo_time_base, 1); + while (modulo_time_base) { + vop->modulo_time_base++; + + READ_UINT8 (&br, modulo_time_base, 1); + } + + CHECK_REMAINING (&br, vol->vop_time_increment_bits + 3); + + MARKER_UNCHECKED (&br); + vop->time_increment = + gst_bit_reader_get_bits_uint16_unchecked (&br, + vol->vop_time_increment_bits); + MARKER_UNCHECKED (&br); + + vop->coded = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + if (!vop->coded) + return GST_MPEG4_PARSER_OK; + + if (vol->newpred_enable) { + guint16 nbbits = + vop->time_increment + 3 < 15 ? vop->time_increment + 3 : 15; + + READ_UINT16 (&br, vop->id, nbbits); + READ_UINT8 (&br, vop->id_for_prediction_indication, 1); + if (vop->id_for_prediction_indication) { + /* Would be nice if the standard actually told us... */ + READ_UINT16 (&br, vop->id, nbbits); + CHECK_MARKER (&br); + } + } + + if (vol->shape != GST_MPEG4_BINARY_ONLY && + (vop->coding_type == GST_MPEG4_P_VOP || + (vop->coding_type == GST_MPEG4_S_VOP && + vol->sprite_enable == GST_MPEG4_SPRITE_GMG))) + READ_UINT8 (&br, vop->rounding_type, 1); + + if ((vol->reduced_resolution_vop_enable) && + (vol->shape == GST_MPEG4_RECTANGULAR || + (vop->coding_type = GST_MPEG4_P_VOP || + vop->coding_type == GST_MPEG4_I_VOP))) + READ_UINT8 (&br, vop->reduced_resolution, 1); + + if (vol->shape != GST_MPEG4_RECTANGULAR) { + if (vol->sprite_enable == GST_MPEG4_SPRITE_STATIC && + vop->coding_type == GST_MPEG4_I_VOP) { + CHECK_REMAINING (&br, 55); + + vop->width = gst_bit_reader_get_bits_uint16_unchecked (&br, 13); + MARKER_UNCHECKED (&br); + + vop->height = gst_bit_reader_get_bits_uint16_unchecked (&br, 13); + MARKER_UNCHECKED (&br); + + vop->horizontal_mc_spatial_ref = + gst_bit_reader_get_bits_uint16_unchecked (&br, 13); + MARKER_UNCHECKED (&br); + + vop->vertical_mc_spatial_ref = + gst_bit_reader_get_bits_uint16_unchecked (&br, 13); + MARKER_UNCHECKED (&br); + + /* Recompute the Macroblock informations + * accordingly to the new values */ + if (vol->interlaced) + vop->mb_height = (2 * (vol->height + 31) / 32); + else + vop->mb_height = (vol->height + 15) / 16; + + vop->mb_width = (vol->width + 15) / 16; + vop->mb_num = vop->mb_height * vop->mb_width; + } + + if ((vol->shape != GST_MPEG4_BINARY_ONLY) && + vol->scalability && vol->enhancement_type) + READ_UINT8 (&br, vop->background_composition, 1); + + READ_UINT8 (&br, vop->change_conv_ratio_disable, 1); + + READ_UINT8 (&br, vop->constant_alpha, 1); + if (vop->constant_alpha) + READ_UINT8 (&br, vop->constant_alpha_value, 1); + } + + if (vol->shape != GST_MPEG4_BINARY_ONLY) { + if (!vol->complexity_estimation_disable) { + GST_WARNING ("Complexity estimation not supported"); + goto failed; + } + + READ_UINT8 (&br, vop->intra_dc_vlc_thr, 3); + + if (vol->interlaced) { + READ_UINT8 (&br, vop->top_field_first, 1); + READ_UINT8 (&br, vop->alternate_vertical_scan_flag, 1); + } + } + + if ((vol->sprite_enable == GST_MPEG4_SPRITE_STATIC || + vol->sprite_enable == GST_MPEG4_SPRITE_GMG) && + vop->coding_type == GST_MPEG4_S_VOP) { + + /* only if @sprite_trajectory is not NULL we parse it */ + if (sprite_trajectory && vol->no_of_sprite_warping_points) + parse_sprite_trajectory (&br, sprite_trajectory, + vol->no_of_sprite_warping_points); + + if (vol->sprite_brightness_change) { + GST_WARNING ("sprite_brightness_change not supported"); + goto failed; + } + + if (vol->sprite_enable == GST_MPEG4_SPRITE_STATIC) { + GST_WARNING ("sprite enable static not supported"); + goto failed; + } + } + + if (vol->shape != GST_MPEG4_BINARY_ONLY) { + READ_UINT16 (&br, vop->quant, vol->quant_precision); + + if (vol->shape == GST_MPEG4_GRAYSCALE) { + /* TODO implement grayscale support */ + GST_WARNING ("Grayscale shapes no supported"); + + /* TODO implement me */ + goto failed; + } + + if (vop->coding_type != GST_MPEG4_I_VOP) { + READ_UINT8 (&br, vop->fcode_forward, 3); + CHECK_ALLOWED (vop->fcode_forward, 1, 7); + } + + if (vop->coding_type == GST_MPEG4_B_VOP) { + READ_UINT8 (&br, vop->fcode_backward, 3); + CHECK_ALLOWED (vop->fcode_backward, 1, 7); + } + } + + if (!vol->scalability) { + if (vol->shape != GST_MPEG4_RECTANGULAR) + READ_UINT8 (&br, vop->shape_coding_type, 1); + + } else { + if (vol->enhancement_type) { + READ_UINT8 (&br, vop->load_backward_shape, 1); + + if (vop->load_backward_shape) { + GST_WARNING ("Load backward shape not supported"); + goto failed; + } + + READ_UINT8 (&br, vop->ref_select_code, 2); + } + } + + vop->size = gst_bit_reader_get_pos (&br); + /* More things to possibly parse ... */ + + return GST_MPEG4_PARSER_OK; + +failed: + GST_WARNING ("failed parsing \"Video Object Plane\""); + return GST_MPEG4_PARSER_ERROR; + +wrong_start_code: + GST_WARNING ("got buffer with wrong start code"); + goto failed; +} + +/** + * gst_mpeg4_parse_video_plane_with_short_header: + * @shorthdr: The #GstMpeg4VideoPlaneShortHdr to parse + * @data: The data to parse + * @size: The size of the @data to parse + */ +GstMpeg4ParseResult +gst_mpeg4_parse_video_plane_short_header (GstMpeg4VideoPlaneShortHdr * + shorthdr, const guint8 * data, gsize size) +{ + guint8 zero_bits; + + GstBitReader br = GST_BIT_READER_INIT (data, size); + + g_return_val_if_fail (shorthdr != NULL, GST_MPEG4_PARSER_ERROR); + + if (gst_bit_reader_get_remaining (&br) < 48) + goto failed; + + if (gst_bit_reader_get_bits_uint32_unchecked (&br, 22) != 0x20) + goto failed; + + shorthdr->temporal_reference = + gst_bit_reader_get_bits_uint8_unchecked (&br, 8); + CHECK_MARKER (&br); + zero_bits = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + if (zero_bits != 0x00) + goto failed; + + shorthdr->split_screen_indicator = + gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + shorthdr->document_camera_indicator = + gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + shorthdr->full_picture_freeze_release = + gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + shorthdr->source_format = gst_bit_reader_get_bits_uint8_unchecked (&br, 3); + + /* Set parameters/Table 6-25 */ + switch (shorthdr->source_format) { + case 0x01: + shorthdr->vop_width = 128; + shorthdr->vop_height = 96; + shorthdr->num_macroblocks_in_gob = 8; + shorthdr->num_gobs_in_vop = 6; + break; + case 0x02: + shorthdr->vop_width = 176; + shorthdr->vop_height = 144; + shorthdr->num_macroblocks_in_gob = 11; + shorthdr->num_gobs_in_vop = 9; + break; + case 0x03: + shorthdr->vop_width = 352; + shorthdr->vop_height = 288; + shorthdr->num_macroblocks_in_gob = 22; + shorthdr->num_gobs_in_vop = 18; + break; + case 0x04: + shorthdr->vop_width = 704; + shorthdr->vop_height = 576; + shorthdr->num_macroblocks_in_gob = 88; + shorthdr->num_gobs_in_vop = 18; + break; + case 0x05: + shorthdr->vop_width = 1408; + shorthdr->vop_height = 1152; + shorthdr->num_macroblocks_in_gob = 352; + shorthdr->num_gobs_in_vop = 18; + break; + default: + shorthdr->vop_width = 0; + shorthdr->vop_height = 0; + shorthdr->num_macroblocks_in_gob = 0; + shorthdr->num_gobs_in_vop = 0; + } + + shorthdr->picture_coding_type = + gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + zero_bits = gst_bit_reader_get_bits_uint8_unchecked (&br, 4); + + if (zero_bits != 0x00) + goto failed; + + shorthdr->vop_quant = gst_bit_reader_get_bits_uint8_unchecked (&br, 5); + zero_bits = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + + if (zero_bits != 0x00) + goto failed; + + do { + READ_UINT8 (&br, shorthdr->pei, 1); + + if (shorthdr->pei == 1) + READ_UINT8 (&br, shorthdr->psupp, 8); + + } while (shorthdr->pei == 1); + + shorthdr->size = gst_bit_reader_get_pos (&br); + + return GST_MPEG4_PARSER_OK; + +failed: + GST_WARNING ("Could not parse the Plane short header"); + + return GST_MPEG4_PARSER_ERROR; +} + +/** + * gst_mpeg4_parse_video_packet_header: + * @videopackethdr: The #GstMpeg4VideoPacketHdr structure to fill + * @vol: The last parsed #GstMpeg4VideoObjectLayer, will be updated + * with the informations found during the parsing + * @vop: The last parsed #GstMpeg4VideoObjectPlane, will be updated + * with the informations found during the parsing + * @sprite_trajectory: A #GstMpeg4SpriteTrajectory to fill or %NULL + * with the informations found during the parsing + * @data: The data to parse, should be set after the resync marker. + * @size: The size of the data to parse + * + * Parsers @data containing the video packet header + * and fills the @videopackethdr structure + */ +GstMpeg4ParseResult +gst_mpeg4_parse_video_packet_header (GstMpeg4VideoPacketHdr * videopackethdr, + GstMpeg4VideoObjectLayer * vol, GstMpeg4VideoObjectPlane * vop, + GstMpeg4SpriteTrajectory * sprite_trajectory, const guint8 * data, + gsize size) +{ + guint8 markersize; + GstBitReader br = GST_BIT_READER_INIT (data, size); + + g_return_val_if_fail (videopackethdr != NULL, GST_MPEG4_PARSER_ERROR); + g_return_val_if_fail (vol != NULL, GST_MPEG4_PARSER_ERROR); + + markersize = compute_resync_marker_size (vop, NULL, NULL); + + CHECK_REMAINING (&br, markersize); + + if (gst_bit_reader_get_bits_uint32_unchecked (&br, markersize + 1) != 0x01) + goto failed; + + if (vol->shape != GST_MPEG4_RECTANGULAR) { + READ_UINT8 (&br, videopackethdr->header_extension_code, 1); + if (vol->sprite_enable == GST_MPEG4_SPRITE_STATIC && + vop->coding_type == GST_MPEG4_I_VOP) { + + CHECK_REMAINING (&br, 56); + + U_READ_UINT16 (&br, vop->width, 13); + CHECK_MARKER (&br); + U_READ_UINT16 (&br, vop->height, 13); + CHECK_MARKER (&br); + U_READ_UINT16 (&br, vop->horizontal_mc_spatial_ref, 13); + CHECK_MARKER (&br); + U_READ_UINT16 (&br, vop->vertical_mc_spatial_ref, 13); + CHECK_MARKER (&br); + + /* Update macroblock infirmations */ + vop->mb_height = (vop->height + 15) / 16; + vop->mb_width = (vop->width + 15) / 16; + vop->mb_num = vop->mb_height * vop->mb_width; + } + } + + READ_UINT16 (&br, videopackethdr->macroblock_number, + g_bit_storage (vop->mb_num - 1)); + + if (vol->shape != GST_MPEG4_BINARY_ONLY) + READ_UINT16 (&br, videopackethdr->quant_scale, vol->quant_precision); + + if (vol->shape == GST_MPEG4_RECTANGULAR) + READ_UINT8 (&br, videopackethdr->header_extension_code, 1); + + if (videopackethdr->header_extension_code) { + guint timeincr = 0; + guint8 bit = 0, coding_type; + + do { + READ_UINT8 (&br, bit, 1); + timeincr++; + } while (bit); + + vol->vop_time_increment_bits = timeincr; + + CHECK_MARKER (&br); + READ_UINT16 (&br, vop->time_increment, timeincr); + CHECK_MARKER (&br); + READ_UINT8 (&br, coding_type, 2); + vop->coding_type = coding_type; + + if (vol->shape != GST_MPEG4_RECTANGULAR) { + READ_UINT8 (&br, vop->change_conv_ratio_disable, 1); + if (vop->coding_type != GST_MPEG4_I_VOP) + READ_UINT8 (&br, vop->shape_coding_type, 1); + } + + if (vol->shape != GST_MPEG4_BINARY_ONLY) { + READ_UINT8 (&br, vop->intra_dc_vlc_thr, 3); + + if (sprite_trajectory && vol->sprite_enable == GST_MPEG4_SPRITE_GMG && + vop->coding_type == GST_MPEG4_S_VOP && + vol->no_of_sprite_warping_points > 0) { + + parse_sprite_trajectory (&br, sprite_trajectory, + vol->no_of_sprite_warping_points); + } + + if (vol->reduced_resolution_vop_enable && + vol->shape == GST_MPEG4_RECTANGULAR && + (vop->coding_type == GST_MPEG4_P_VOP || + vop->coding_type == GST_MPEG4_I_VOP)) + READ_UINT8 (&br, vop->reduced_resolution, 1); + + if (vop->coding_type != GST_MPEG4_I_VOP) { + READ_UINT8 (&br, vop->fcode_forward, 3); + CHECK_ALLOWED (vop->fcode_forward, 1, 7); + } + + if (vop->coding_type == GST_MPEG4_B_VOP) { + READ_UINT8 (&br, vop->fcode_backward, 3); + CHECK_ALLOWED (vop->fcode_backward, 1, 7); + } + } + } + + if (vol->newpred_enable) { + guint16 nbbits = + vol->vop_time_increment_bits + 3 < 15 ? vop->time_increment + 3 : 15; + + READ_UINT16 (&br, vop->id, nbbits); + READ_UINT8 (&br, vop->id_for_prediction_indication, 1); + if (vop->id_for_prediction_indication) { + /* Would be nice if the standard actually told us... */ + READ_UINT16 (&br, vop->id, nbbits); + CHECK_MARKER (&br); + } + } + + videopackethdr->size = gst_bit_reader_get_pos (&br); + +failed: + GST_DEBUG ("Failed to parse video packet header"); + + return GST_MPEG4_PARSER_NO_PACKET; +} diff --git a/ext/codecparsers/gst-libs/gst/codecparsers/gstmpeg4parser.h b/ext/codecparsers/gst-libs/gst/codecparsers/gstmpeg4parser.h new file mode 100644 index 0000000..6864b06 --- /dev/null +++ b/ext/codecparsers/gst-libs/gst/codecparsers/gstmpeg4parser.h @@ -0,0 +1,578 @@ +/* + * GStreamer + * Copyright (C) 2009 Carl-Anton Ingmarsson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_MPEG4UTIL_H__ +#define __GST_MPEG4UTIL_H__ + +#include +#include + +typedef struct _GstMpeg4VisualObjectSequence GstMpeg4VisualObjectSequence; +typedef struct _GstMpeg4VisualObject GstMpeg4VisualObject; +typedef struct _GstMpeg4VideoObjectLayer GstMpeg4VideoObjectLayer; +typedef struct _GstMpeg4GroupOfVOP GstMpeg4GroupOfVOP; +typedef struct _GstMpeg4VideoObjectPlane GstMpeg4VideoObjectPlane; +typedef struct _GstMpeg4VideoSignalType GstMpeg4VideoSignalType; +typedef struct _GstMpeg4VideoPlaneShortHdr GstMpeg4VideoPlaneShortHdr; +typedef struct _GstMpeg4VideoPacketHdr GstMpeg4VideoPacketHdr; + +typedef struct _GstMpeg4SpriteTrajectory GstMpeg4SpriteTrajectory; + +typedef struct _GstMpeg4Packet GstMpeg4Packet; + +/** + * GstMpeg4StartCode: + * + * Defines the different startcodes present in the bitstream as + * defined in: Table 6-3 — Start code values + */ +typedef enum +{ + GST_MPEG4_VIDEO_OBJ_FIRST = 0x00, + GST_MPEG4_VIDEO_OBJ_LAST = 0x1f, + GST_MPEG4_VIDEO_LAYER_FIRST = 0x20, + GST_MPEG4_VIDEO_LAYER_LAST = 0x2f, + GST_MPEG4_VISUAL_OBJ_SEQ_START = 0xb0, + GST_MPEG4_VISUAL_OBJ_SEQ_END = 0xb1, + GST_MPEG4_USER_DATA = 0xb2, + GST_MPEG4_GROUP_OF_VOP = 0xb3, + GST_MPEG4_VIDEO_SESSION_ERR = 0xb4, + GST_MPEG4_VISUAL_OBJ = 0xb5, + GST_MPEG4_VIDEO_OBJ_PLANE = 0xb6, + GST_MPEG4_FBA = 0xba, + GST_MPEG4_FBA_PLAN = 0xbb, + GST_MPEG4_MESH = 0xbc, + GST_MPEG4_MESH_PLAN = 0xbd, + GST_MPEG4_STILL_TEXTURE_OBJ = 0xbe, + GST_MPEG4_TEXTURE_SPATIAL = 0xbf, + GST_MPEG4_TEXTURE_SNR_LAYER = 0xc0, + GST_MPEG4_TEXTURE_TILE = 0xc1, + GST_MPEG4_SHAPE_LAYER = 0xc2, + GST_MPEG4_STUFFING = 0xc3, + GST_MPEG4_SYSTEM_FIRST = 0xc6, + GST_MPEG4_SYSTEM_LAST = 0xff, + GST_MPEG4_RESYNC = 0xfff +} GstMpeg4StartCode; + +/** + * GstMpeg4VisualObjectType: + * + * Defines the different visual object types as + * defined in: Table 6-5 -- Meaning of visual object type + */ +typedef enum { + GST_MPEG4_VIDEO_ID = 0x01, + GST_MPEG4_STILL_TEXTURE_ID = 0x02, + GST_MPEG4_STILL_MESH_ID = 0x03, + GST_MPEG4_STILL_FBA_ID = 0x04, + GST_MPEG4_STILL_3D_MESH_ID = 0x05, + /*... reserved */ + +} GstMpeg4VisualObjectType; + +/** + * GstMpeg4AspectRatioInfo: + * @GST_MPEG4_SQUARE: 1:1 square + * @GST_MPEG4_625_TYPE_4_3: 12:11 (625-type for 4:3 picture) + * @GST_MPEG4_525_TYPE_4_3: 10:11 (525-type for 4:3 picture) + * @GST_MPEG4_625_TYPE_16_9: 16:11 (625-type stretched for 16:9 picture) + * @GST_MPEG4_525_TYPE_16_9: 40:33 (525-type stretched for 16:9 picture) + * @GST_MPEG4_EXTENDED_PAR: Extended par + * + * Defines the different pixel aspect ratios as + * defined in: Table 6-12 -- Meaning of pixel aspect ratio + */ +typedef enum { + GST_MPEG4_SQUARE = 0x01, + GST_MPEG4_625_TYPE_4_3 = 0x02, + GST_MPEG4_525_TYPE_4_3 = 0x03, + GST_MPEG4_625_TYPE_16_9 = 0x04, + GST_MPEG4_525_TYPE_16_9 = 0x05, + GST_MPEG4_EXTENDED_PAR = 0x0f, +} GstMpeg4AspectRatioInfo; + +/** + * GstMpeg4ParseResult: + * @GST_MPEG4_PARSER_OK: The parsing went well + * @GST_MPEG4_PARSER_BROKEN_DATA: The bitstream was broken + * @GST_MPEG4_PARSER_NO_PACKET: There was no packet in the buffer + * @GST_MPEG4_PARSER_NO_PACKET_END: There was no packet end in the buffer + * @GST_MPEG4_PARSER_NO_PACKET_ERROR: An error accured durint the parsing + * + * Result type of any parsing function. + */ +typedef enum { + GST_MPEG4_PARSER_OK, + GST_MPEG4_PARSER_BROKEN_DATA, + GST_MPEG4_PARSER_NO_PACKET, + GST_MPEG4_PARSER_NO_PACKET_END, + GST_MPEG4_PARSER_ERROR, +} GstMpeg4ParseResult; + +/** + * GstMpeg4VideoObjectCodingType: + * @GST_MPEG4_I_VOP: intra-coded (I) + * @GST_MPEG4_P_VOP: predictive-coded (P) + * @GST_MPEG4_B_VOP: bidirectionally-predictive-coded (B) + * @GST_MPEG4_S_VOP: sprite (S) + * + * The vop coding types as defined in: + * Table 6-20 -- Meaning of vop_coding_type + */ +typedef enum { + GST_MPEG4_I_VOP = 0x0, + GST_MPEG4_P_VOP = 0x1, + GST_MPEG4_B_VOP = 0x2, + GST_MPEG4_S_VOP = 0x3 +} GstMpeg4VideoObjectCodingType; + +/** + * GstMpeg4ChromaFormat + * + * The chroma format in use as + * defined in: Table 6-13 -- Meaning of chroma_format + */ +typedef enum { + /* Other value are reserved */ + GST_MPEG4_CHROMA_4_2_0 = 0x01 +} GstMpeg4ChromaFormat; + +/** + * GstMpeg4VideoObjectLayerShape: + * + * The different video object layer shapes as defined in: + * Table 6-16 — Video Object Layer shape type + */ +typedef enum { + GST_MPEG4_RECTANGULAR, + GST_MPEG4_BINARY, + GST_MPEG4_BINARY_ONLY, + GST_MPEG4_GRAYSCALE +} GstMpeg4VideoObjectLayerShape; + +/** + * GstMpeg4SpriteEnable: + * + * Indicates the usage of static sprite coding + * or global motion compensation (GMC) as defined in: + * Table V2 - 2 -- Meaning of sprite_enable codewords + */ +typedef enum { + GST_MPEG4_SPRITE_UNUSED, + GST_MPEG4_SPRITE_STATIC, + GST_MPEG4_SPRITE_GMG +} GstMpeg4SpriteEnable; + +/** + * GstMpeg4Profile: + * + * Different defined profiles as defined in: + * 9- Profiles and levels + * + * It is computed using: + * Table G.1 — FLC table for profile_and_level_indication + */ +typedef enum { + GST_MPEG4_PROFILE_CORE, + GST_MPEG4_PROFILE_MAIN, + GST_MPEG4_PROFILE_N_BIT, + GST_MPEG4_PROFILE_SIMPLE, + GST_MPEG4_PROFILE_HYBRID, + GST_MPEG4_PROFILE_RESERVED, + GST_MPEG4_PROFILE_SIMPLE_FBA, + GST_MPEG4_PROFILE_CORE_STUDIO, + GST_MPEG4_PROFILE_SIMPLE_STUDIO, + GST_MPEG4_PROFILE_CORE_SCALABLE, + GST_MPEG4_PROFILE_ADVANCED_CORE, + GST_MPEG4_PROFILE_ADVANCED_SIMPLE, + GST_MPEG4_PROFILE_SIMPLE_SCALABLE, + GST_MPEG4_PROFILE_SCALABLE_TEXTURE, + GST_MPEG4_PROFILE_SIMPLE_FACE_ANIMATION, + GST_MPEG4_PROFILE_BASIC_ANIMATED_TEXTURE, + GST_MPEG4_PROFILE_ADVANCED_REALTIME_SIMPLE, + GST_MPEG4_PROFILE_ADVANCED_SCALABLE_TEXTURE, + GST_MPEG4_PROFILE_FINE_GRANULARITY_SCALABLE, + GST_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY +} GstMpeg4Profile; + +/** + * GstMpeg4Level: + * + * Different levels as defined in: + * 9- Profiles and levels + * + * It is computed using: + * Table G.1 — FLC table for profile_and_level_indication + */ +typedef enum { + GST_MPEG4_LEVEL0, + GST_MPEG4_LEVEL1, + GST_MPEG4_LEVEL2, + GST_MPEG4_LEVEL3, + GST_MPEG4_LEVEL3b, + GST_MPEG4_LEVEL4, + GST_MPEG4_LEVEL5, + GST_MPEG4_LEVEL_RESERVED +} GstMpeg4Level; + +/** + * GstMpeg4VisualObjectSequence: + * + * The visual object sequence structure as defined in: + * 6.2.2 Visual Object Sequence and Visual Object + */ +struct _GstMpeg4VisualObjectSequence { + guint8 profile_and_level_indication; + + /* Computed according to: + * Table G.1 — FLC table for profile_and_level_indication */ + GstMpeg4Level level; + GstMpeg4Profile profile; +}; + +/** + * The visual object structure as defined in: + * 6.2.2 Visual Object Sequence and Visual Object + */ +struct _GstMpeg4VisualObject { + guint8 is_identifier; + /* If is_identifier */ + guint8 verid; + guint8 priority; + + GstMpeg4VisualObjectType type; +}; + +/** + * GstMpeg4VideoSignalType: + * + * The video signal type structure as defined in: + * 6.2.2 Visual Object Sequence and Visual Object. + */ +struct _GstMpeg4VideoSignalType { + guint8 type; + + guint8 format; + guint8 range; + guint8 color_description; + guint8 color_primaries; + guint8 transfer_characteristics; + guint8 matrix_coefficients; +}; + +/** + * GstMpeg4VideoPlaneShortHdr: + * + * The video plane short header structure as defined in: + * 6.2.5.2 Video Plane with Short Header + */ +struct _GstMpeg4VideoPlaneShortHdr { + guint8 temporal_reference; + guint8 split_screen_indicator; + guint8 document_camera_indicator; + guint8 full_picture_freeze_release; + guint8 source_format; + guint8 picture_coding_type; + guint8 vop_quant; + guint8 pei; + guint8 psupp; + + /* Gob layer specific fields */ + guint8 gob_header_empty; + guint8 gob_number; + guint8 gob_frame_id; + guint8 quant_scale; + + /* Computed + * If all the values are set to 0, then it is reserved + * Table 6-25 -- Parameters Defined by source_format Field + */ + guint16 vop_width; + guint16 vop_height; + guint16 num_macroblocks_in_gob; + guint8 num_gobs_in_vop; + + /* The size in bits */ + guint size; +}; + +/** + * GstMpeg4VideoObjectLayer: + * + * The video object layer structure as defined in: + * 6.2.3 Video Object Layer + */ +struct _GstMpeg4VideoObjectLayer { + guint8 random_accessible_vol; + guint8 video_object_type_indication; + + guint8 is_object_layer_identifier; + /* if is_object_layer_identifier */ + guint8 verid; + guint8 priority; + + GstMpeg4AspectRatioInfo aspect_ratio_info; + guint8 par_width; + guint8 par_height; + + guint8 control_parameters; + /* if control_parameters */ + GstMpeg4ChromaFormat chroma_format; + guint8 low_delay; + guint8 vbv_parameters; + /* if vbv_parameters */ + guint16 first_half_bitrate; + guint16 latter_half_bitrate; + guint16 first_half_vbv_buffer_size; + guint16 latter_half_vbv_buffer_size; + guint16 first_half_vbv_occupancy; + guint16 latter_half_vbv_occupancy; + + /* Computed values */ + guint32 bit_rate; + guint32 vbv_buffer_size; + + GstMpeg4VideoObjectLayerShape shape; + /* if shape == GST_MPEG4_GRAYSCALE && verid =! 1 */ + guint8 shape_extension; + + guint16 vop_time_increment_resolution; + guint8 vop_time_increment_bits; + guint8 fixed_vop_rate; + /* if fixed_vop_rate */ + guint16 fixed_vop_time_increment; + + guint16 width; + guint16 height; + guint8 interlaced; + guint8 obmc_disable; + + GstMpeg4SpriteEnable sprite_enable; + /* if vol->sprite_enable == SPRITE_GMG or SPRITE_STATIC*/ + /* if vol->sprite_enable != GST_MPEG4_SPRITE_GMG */ + guint16 sprite_width; + guint16 sprite_height; + guint16 sprite_left_coordinate; + guint16 sprite_top_coordinate; + + guint8 no_of_sprite_warping_points; + guint8 sprite_warping_accuracy; + guint8 sprite_brightness_change; + /* if vol->sprite_enable != GST_MPEG4_SPRITE_GMG */ + guint8 low_latency_sprite_enable; + + /* if shape != GST_MPEG4_RECTANGULAR */ + guint8 sadct_disable; + + guint8 not_8_bit; + + /* if no_8_bit */ + guint8 quant_precision; + guint8 bits_per_pixel; + + /* if shape == GRAYSCALE */ + guint8 no_gray_quant_update; + guint8 composition_method; + guint8 linear_composition; + + guint8 quant_type; + /* if quant_type */ + guint8 load_intra_quant_mat; + guint8 intra_quant_mat[64]; + guint8 load_non_intra_quant_mat; + guint8 non_intra_quant_mat[64]; + + guint8 quarter_sample; + guint8 complexity_estimation_disable; + guint8 resync_marker_disable; + guint8 data_partitioned; + guint8 reversible_vlc; + guint8 newpred_enable; + guint8 reduced_resolution_vop_enable; + guint8 scalability; + guint8 enhancement_type; + + GstMpeg4VideoPlaneShortHdr short_hdr; +}; + +/** + * GstMpeg4SpriteTrajectory: + * + * The sprite trajectory structure as defined in: + * 7.8.4 Sprite reference point decoding and + * 6.2.5.4 Sprite coding + */ +struct _GstMpeg4SpriteTrajectory { + guint16 vop_ref_points[63]; /* Defined as "du" in 6.2.5.4 */ + guint16 sprite_ref_points[63]; /* Defined as "dv" in 6.2.5.4 */ +}; + +/** + * GstMpeg4GroupOfVOP: + * + * The group of video object plane structure as defined in: + * 6.2.4 Group of Video Object Plane + */ +struct _GstMpeg4GroupOfVOP { + guint8 hours; + guint8 minutes; + guint8 seconds; + + guint8 closed; + guint8 broken_link; +}; + +/** + * GstMpeg4VideoObjectPlane: + * + * The Video object plane structure as defined in: + * 6.2.5 Video Object Plane and Video Plane with Short Header + */ +struct _GstMpeg4VideoObjectPlane { + GstMpeg4VideoObjectCodingType coding_type; + + guint8 modulo_time_base; + guint16 time_increment; + + guint8 coded; + /* if newpred_enable */ + guint16 id; + guint8 id_for_prediction_indication; + guint16 id_for_prediction; + + guint16 width; + guint16 height; + guint16 horizontal_mc_spatial_ref; + guint16 vertical_mc_spatial_ref; + + guint8 rounding_type; + /*if vol->shape != GST_MPEG4_RECTANGULAR */ + guint8 background_composition; + guint8 change_conv_ratio_disable; + guint8 constant_alpha; + guint8 constant_alpha_value; + guint8 reduced_resolution; + + guint8 intra_dc_vlc_thr; + + + guint8 top_field_first; + guint8 alternate_vertical_scan_flag; + + guint16 quant; + + guint8 fcode_forward; + guint8 fcode_backward; + + guint8 shape_coding_type; + guint8 load_backward_shape; + guint8 ref_select_code; + + /* Computed macroblock informations */ + guint16 mb_height; + guint16 mb_width; + guint mb_num; + + /* The size of the header */ + guint size; +}; + +/** + * GstMpeg4VideoPacketHdr: + * @size: Size of the header in bit. + * + * The video packet header structure as defined in: + * 6.2.5.2 Video Plane with Short Header + */ +struct _GstMpeg4VideoPacketHdr { + guint8 header_extension_code; + guint16 macroblock_number; + guint16 quant_scale; + guint size; +}; + +/** + * GstMpeg4Packet: + * @type: the type of the packet that start at @offset + * @data: the data containing packet starting at @offset + * @offset: offset of the start of the packet (without the 3 bytes startcode), but + * including the #GstMpeg4StartCode byte. + * @size: The size in bytes of the packet or %G_MAXUINT if the end wasn't found. + * @marker_size: The size in bit of the resync marker. + * + * A structure that contains the type of a packet, its offset and its size + */ +struct _GstMpeg4Packet +{ + const guint8 *data; + guint offset; + gsize size; + guint marker_size; + + GstMpeg4StartCode type; +}; + +GstMpeg4ParseResult gst_h263_parse (GstMpeg4Packet * packet, + const guint8 * data, guint offset, + gsize size); + + +GstMpeg4ParseResult gst_mpeg4_parse (GstMpeg4Packet * packet, + gboolean skip_user_data, + GstMpeg4VideoObjectPlane *vop, + const guint8 * data, guint offset, + gsize size); + +GstMpeg4ParseResult +gst_mpeg4_parse_video_object_plane (GstMpeg4VideoObjectPlane *vop, + GstMpeg4SpriteTrajectory *sprite_trajectory, + GstMpeg4VideoObjectLayer *vol, + const guint8 * data, + gsize size); + +GstMpeg4ParseResult +gst_mpeg4_parse_group_of_vop (GstMpeg4GroupOfVOP *gov, + const guint8 * data, gsize size); + +GstMpeg4ParseResult +gst_mpeg4_parse_video_object_layer (GstMpeg4VideoObjectLayer *vol, + GstMpeg4VisualObject *vo, + const guint8 * data, gsize size); + +GstMpeg4ParseResult +gst_mpeg4_parse_visual_object (GstMpeg4VisualObject *vo, + GstMpeg4VideoSignalType *signal_type, + const guint8 * data, gsize size); + +GstMpeg4ParseResult +gst_mpeg4_parse_visual_object_sequence (GstMpeg4VisualObjectSequence *vos, + const guint8 * data, gsize size); +GstMpeg4ParseResult +gst_mpeg4_parse_video_plane_short_header (GstMpeg4VideoPlaneShortHdr * shorthdr, + const guint8 * data, gsize size); + +GstMpeg4ParseResult +gst_mpeg4_parse_video_packet_header (GstMpeg4VideoPacketHdr * videopackethdr, + GstMpeg4VideoObjectLayer * vol, + GstMpeg4VideoObjectPlane * vop, + GstMpeg4SpriteTrajectory * sprite_trajectory, + const guint8 * data, gsize size); + +#endif /* __GST_MPEG4UTIL_H__ */ diff --git a/ext/codecparsers/gst-libs/gst/codecparsers/gstmpegvideoparser.c b/ext/codecparsers/gst-libs/gst/codecparsers/gstmpegvideoparser.c new file mode 100644 index 0000000..94726c7 --- /dev/null +++ b/ext/codecparsers/gst-libs/gst/codecparsers/gstmpegvideoparser.c @@ -0,0 +1,825 @@ +/* Gstreamer + * Copyright (C) <2011> Intel Corporation + * Copyright (C) <2011> Collabora Ltd. + * Copyright (C) <2011> Thibault Saunier + * + * From bad/sys/vdpau/mpeg/mpegutil.c: + * Copyright (C) <2007> Jan Schmidt + * Copyright (C) <2009> Carl-Anton Ingmarsson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/** + * SECTION:gstmpegvideoparser + * @short_description: Convenience library for mpeg1 and 2 video + * bitstream parsing. + * + * + * + * Provides useful functions for mpeg videos bitstream parsing. + * + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "gstmpegvideoparser.h" +#include "parserutils.h" + +#include +#include +#include + +#define MARKER_BIT 0x1 + +/* default intra quant matrix, in zig-zag order */ +static const guint8 default_intra_quantizer_matrix[64] = { + 8, + 16, 16, + 19, 16, 19, + 22, 22, 22, 22, + 22, 22, 26, 24, 26, + 27, 27, 27, 26, 26, 26, + 26, 27, 27, 27, 29, 29, 29, + 34, 34, 34, 29, 29, 29, 27, 27, + 29, 29, 32, 32, 34, 34, 37, + 38, 37, 35, 35, 34, 35, + 38, 38, 40, 40, 40, + 48, 48, 46, 46, + 56, 56, 58, + 69, 69, + 83 +}; + +static const guint8 mpeg_zigzag_8x8[64] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + +GST_DEBUG_CATEGORY (mpegvideo_parser_debug); +#define GST_CAT_DEFAULT mpegvideo_parser_debug + +static gboolean initialized = FALSE; + +static inline gboolean +find_start_code (GstBitReader * b) +{ + guint32 bits; + + /* 0 bits until byte aligned */ + while (b->bit != 0) { + GET_BITS (b, 1, &bits); + } + + /* 0 bytes until startcode */ + while (gst_bit_reader_peek_bits_uint32 (b, &bits, 32)) { + if (bits >> 8 == 0x1) { + return TRUE; + } else if (gst_bit_reader_skip (b, 8) == FALSE) + break; + } + + return FALSE; + +failed: + return FALSE; +} + +/* Set the Pixel Aspect Ratio in our hdr from a ASR code in the data */ +static void +set_par_from_asr_mpeg1 (GstMpegVideoSequenceHdr * seqhdr, guint8 asr_code) +{ + int ratios[16][2] = { + {0, 0}, /* 0, Invalid */ + {1, 1}, /* 1, 1.0 */ + {10000, 6735}, /* 2, 0.6735 */ + {64, 45}, /* 3, 0.7031 16:9 625 line */ + {10000, 7615}, /* 4, 0.7615 */ + {10000, 8055}, /* 5, 0.8055 */ + {32, 27}, /* 6, 0.8437 */ + {10000, 8935}, /* 7, 0.8935 */ + {10000, 9375}, /* 8, 0.9375 */ + {10000, 9815}, /* 9, 0.9815 */ + {10000, 10255}, /* 10, 1.0255 */ + {10000, 10695}, /* 11, 1.0695 */ + {8, 9}, /* 12, 1.125 */ + {10000, 11575}, /* 13, 1.1575 */ + {10000, 12015}, /* 14, 1.2015 */ + {0, 0}, /* 15, invalid */ + }; + asr_code &= 0xf; + + seqhdr->par_w = ratios[asr_code][0]; + seqhdr->par_h = ratios[asr_code][1]; +} + +static void +set_fps_from_code (GstMpegVideoSequenceHdr * seqhdr, guint8 fps_code) +{ + const gint framerates[][2] = { + {30, 1}, {24000, 1001}, {24, 1}, {25, 1}, + {30000, 1001}, {30, 1}, {50, 1}, {60000, 1001}, + {60, 1}, {30, 1} + }; + + if (fps_code && fps_code < 10) { + seqhdr->fps_n = framerates[fps_code][0]; + seqhdr->fps_d = framerates[fps_code][1]; + } else { + GST_DEBUG ("unknown/invalid frame_rate_code %d", fps_code); + /* Force a valid framerate */ + /* FIXME or should this be kept unknown ?? */ + seqhdr->fps_n = 30000; + seqhdr->fps_d = 1001; + } +} + +/* @size and @offset are wrt current reader position */ +static inline guint +scan_for_start_codes (const GstByteReader * reader, guint offset, guint size) +{ + const guint8 *data; + guint i = 0; + + g_return_val_if_fail ((guint64) offset + size <= reader->size - reader->byte, + -1); + + /* we can't find the pattern with less than 4 bytes */ + if (G_UNLIKELY (size < 4)) + return -1; + + data = reader->data + reader->byte + offset; + + while (i <= (size - 4)) { + if (data[i + 2] > 1) { + i += 3; + } else if (data[i + 1]) { + i += 2; + } else if (data[i] || data[i + 2] != 1) { + i++; + } else { + break; + } + } + + if (i <= (size - 4)) + return offset + i; + + /* nothing found */ + return -1; +} + +/****** API *******/ + +/** + * gst_mpeg_video_parse: + * @data: The data to parse + * @size: The size of @data + * @offset: The offset from which to start parsing + * + * Parses the MPEG 1/2 video bitstream contained in @data , and returns the + * detect packets as a list of #GstMpegVideoTypeOffsetSize. + * + * Returns: TRUE if a packet start code was found + */ +gboolean +gst_mpeg_video_parse (GstMpegVideoPacket * packet, + const guint8 * data, gsize size, guint offset) +{ + gint off; + GstByteReader br; + + if (!initialized) { + GST_DEBUG_CATEGORY_INIT (mpegvideo_parser_debug, "codecparsers_mpegvideo", + 0, "Mpegvideo parser library"); + initialized = TRUE; + } + + if (size <= offset) { + GST_DEBUG ("Can't parse from offset %d, buffer is to small", offset); + return FALSE; + } + + size -= offset; + gst_byte_reader_init (&br, &data[offset], size); + + off = scan_for_start_codes (&br, 0, size); + + if (off < 0) { + GST_DEBUG ("No start code prefix in this buffer"); + return FALSE; + } + + if (gst_byte_reader_skip (&br, off + 3) == FALSE) + goto failed; + + if (gst_byte_reader_get_uint8 (&br, &packet->type) == FALSE) + goto failed; + + packet->data = data; + packet->offset = offset + off + 4; + packet->size = -1; + + /* try to find end of packet */ + size -= off + 4; + off = scan_for_start_codes (&br, 0, size); + + if (off > 0) + packet->size = off; + + return TRUE; + +failed: + { + GST_WARNING ("Failed to parse"); + return FALSE; + } +} + +/** + * gst_mpeg_video_parse_sequence_header: + * @seqhdr: (out): The #GstMpegVideoSequenceHdr structure to fill + * @data: The data from which to parse the sequence header + * @size: The size of @data + * @offset: The offset in byte from which to start parsing @data + * + * Parses the @seqhdr Mpeg Video Sequence Header structure members from @data + * + * Returns: %TRUE if the seqhdr could be parsed correctly, %FALSE otherwize. + */ +gboolean +gst_mpeg_video_parse_sequence_header (GstMpegVideoSequenceHdr * seqhdr, + const guint8 * data, gsize size, guint offset) +{ + GstBitReader br; + guint8 bits; + guint8 load_intra_flag, load_non_intra_flag; + + g_return_val_if_fail (seqhdr != NULL, FALSE); + + size -= offset; + + if (size < 4) + return FALSE; + + gst_bit_reader_init (&br, &data[offset], size); + + /* Setting the height/width codes */ + READ_UINT16 (&br, seqhdr->width, 12); + READ_UINT16 (&br, seqhdr->height, 12); + + READ_UINT8 (&br, seqhdr->aspect_ratio_info, 4); + /* Interpret PAR according to MPEG-1. Needs to be reinterpreted + * later, if a sequence_display extension is seen */ + set_par_from_asr_mpeg1 (seqhdr, seqhdr->aspect_ratio_info); + + READ_UINT8 (&br, seqhdr->frame_rate_code, 4); + set_fps_from_code (seqhdr, seqhdr->frame_rate_code); + + READ_UINT32 (&br, seqhdr->bitrate_value, 18); + if (seqhdr->bitrate_value == 0x3ffff) { + /* VBR stream */ + seqhdr->bitrate = 0; + } else { + /* Value in header is in units of 400 bps */ + seqhdr->bitrate *= 400; + } + + READ_UINT8 (&br, bits, 1); + if (bits != MARKER_BIT) + goto failed; + + /* VBV buffer size */ + READ_UINT16 (&br, seqhdr->vbv_buffer_size_value, 10); + + /* constrained_parameters_flag */ + READ_UINT8 (&br, seqhdr->constrained_parameters_flag, 1); + + /* load_intra_quantiser_matrix */ + READ_UINT8 (&br, load_intra_flag, 1); + if (load_intra_flag) { + gint i; + for (i = 0; i < 64; i++) + READ_UINT8 (&br, seqhdr->intra_quantizer_matrix[mpeg_zigzag_8x8[i]], 8); + } else + memcpy (seqhdr->intra_quantizer_matrix, default_intra_quantizer_matrix, 64); + + /* non intra quantizer matrix */ + READ_UINT8 (&br, load_non_intra_flag, 1); + if (load_non_intra_flag) { + gint i; + for (i = 0; i < 64; i++) + READ_UINT8 (&br, seqhdr->non_intra_quantizer_matrix[mpeg_zigzag_8x8[i]], + 8); + } else + memset (seqhdr->non_intra_quantizer_matrix, 16, 64); + + /* dump some info */ + GST_LOG ("width x height: %d x %d", seqhdr->width, seqhdr->height); + GST_LOG ("fps: %d/%d", seqhdr->fps_n, seqhdr->fps_d); + GST_LOG ("par: %d/%d", seqhdr->par_w, seqhdr->par_h); + GST_LOG ("bitrate: %d", seqhdr->bitrate); + + return TRUE; + + /* ERRORS */ +failed: + { + GST_WARNING ("Failed to parse sequence header"); + /* clear out stuff */ + memset (seqhdr, 0, sizeof (*seqhdr)); + return FALSE; + } +} + +/** + * gst_mpeg_video_parse_sequence_extension: + * @seqext: (out): The #GstMpegVideoSequenceExt structure to fill + * @data: The data from which to parse the sequence extension + * @size: The size of @data + * @offset: The offset in byte from which to start parsing @data + * + * Parses the @seqext Mpeg Video Sequence Extension structure members from @data + * + * Returns: %TRUE if the seqext could be parsed correctly, %FALSE otherwize. + */ +gboolean +gst_mpeg_video_parse_sequence_extension (GstMpegVideoSequenceExt * seqext, + const guint8 * data, gsize size, guint offset) +{ + GstBitReader br; + + g_return_val_if_fail (seqext != NULL, FALSE); + + size -= offset; + + if (size < 6) { + GST_DEBUG ("not enough bytes to parse the extension"); + return FALSE; + } + + gst_bit_reader_init (&br, &data[offset], size); + + if (gst_bit_reader_get_bits_uint8_unchecked (&br, 4) != + GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE) { + GST_DEBUG ("Not parsing a sequence extension"); + return FALSE; + } + + /* skip profile and level escape bit */ + gst_bit_reader_skip_unchecked (&br, 1); + + seqext->profile = gst_bit_reader_get_bits_uint8_unchecked (&br, 3); + seqext->level = gst_bit_reader_get_bits_uint8_unchecked (&br, 4); + + /* progressive */ + seqext->progressive = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + + /* chroma format */ + seqext->chroma_format = gst_bit_reader_get_bits_uint8_unchecked (&br, 2); + + /* resolution extension */ + seqext->horiz_size_ext = gst_bit_reader_get_bits_uint8_unchecked (&br, 2); + seqext->vert_size_ext = gst_bit_reader_get_bits_uint8_unchecked (&br, 2); + + seqext->bitrate_ext = gst_bit_reader_get_bits_uint16_unchecked (&br, 12); + + /* skip marker bits */ + gst_bit_reader_skip_unchecked (&br, 1); + + seqext->vbv_buffer_size_extension = + gst_bit_reader_get_bits_uint8_unchecked (&br, 8); + seqext->low_delay = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + + /* framerate extension */ + seqext->fps_n_ext = gst_bit_reader_get_bits_uint8_unchecked (&br, 2); + seqext->fps_d_ext = gst_bit_reader_get_bits_uint8_unchecked (&br, 2); + + return TRUE; +} + +gboolean +gst_mpeg_video_parse_sequence_display_extension (GstMpegVideoSequenceDisplayExt + * seqdisplayext, const guint8 * data, gsize size, guint offset) +{ + GstBitReader br; + + g_return_val_if_fail (seqdisplayext != NULL, FALSE); + if (offset > size) + return FALSE; + + size -= offset; + if (size < 5) { + GST_DEBUG ("not enough bytes to parse the extension"); + return FALSE; + } + + gst_bit_reader_init (&br, &data[offset], size); + + if (gst_bit_reader_get_bits_uint8_unchecked (&br, 4) != + GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY) { + GST_DEBUG ("Not parsing a sequence display extension"); + return FALSE; + } + + seqdisplayext->video_format = + gst_bit_reader_get_bits_uint8_unchecked (&br, 3); + seqdisplayext->colour_description_flag = + gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + + if (seqdisplayext->colour_description_flag) { + seqdisplayext->colour_primaries = + gst_bit_reader_get_bits_uint8_unchecked (&br, 8); + seqdisplayext->transfer_characteristics = + gst_bit_reader_get_bits_uint8_unchecked (&br, 8); + seqdisplayext->matrix_coefficients = + gst_bit_reader_get_bits_uint8_unchecked (&br, 8); + } + + if (gst_bit_reader_get_remaining (&br) < 29) { + GST_DEBUG ("Not enough remaining bytes to parse the extension"); + return FALSE; + } + + seqdisplayext->display_horizontal_size = + gst_bit_reader_get_bits_uint16_unchecked (&br, 14); + /* skip marker bit */ + gst_bit_reader_skip_unchecked (&br, 1); + seqdisplayext->display_vertical_size = + gst_bit_reader_get_bits_uint16_unchecked (&br, 14); + + return TRUE; +} + +gboolean +gst_mpeg_video_finalise_mpeg2_sequence_header (GstMpegVideoSequenceHdr * seqhdr, + GstMpegVideoSequenceExt * seqext, + GstMpegVideoSequenceDisplayExt * displayext) +{ + guint32 w; + guint32 h; + + if (seqext) { + seqhdr->fps_n = seqhdr->fps_n * (seqext->fps_n_ext + 1); + seqhdr->fps_d = seqhdr->fps_d * (seqext->fps_d_ext + 1); + /* Extend width and height to 14 bits by adding the extension bits */ + seqhdr->width |= (seqext->horiz_size_ext << 12); + seqhdr->height |= (seqext->vert_size_ext << 12); + } + + w = seqhdr->width; + h = seqhdr->height; + if (displayext) { + /* Use the display size for calculating PAR when display ext present */ + w = displayext->display_horizontal_size; + h = displayext->display_vertical_size; + } + + /* Pixel_width = DAR_width * display_vertical_size */ + /* Pixel_height = DAR_height * display_horizontal_size */ + switch (seqhdr->aspect_ratio_info) { + case 0x01: /* Square pixels */ + seqhdr->par_w = seqhdr->par_h = 1; + break; + case 0x02: /* 3:4 DAR = 4:3 pixels */ + seqhdr->par_w = 4 * h; + seqhdr->par_h = 3 * w; + break; + case 0x03: /* 9:16 DAR */ + seqhdr->par_w = 16 * h; + seqhdr->par_h = 9 * w; + break; + case 0x04: /* 1:2.21 DAR */ + seqhdr->par_w = 221 * h; + seqhdr->par_h = 100 * w; + break; + default: + GST_DEBUG ("unknown/invalid aspect_ratio_information %d", + seqhdr->aspect_ratio_info); + break; + } + + return TRUE; +} + +/** + * gst_mpeg_video_parse_quant_matrix_extension: + * @quant: (out): The #GstMpegVideoQuantMatrixExt structure to fill + * @data: The data from which to parse the Quantization Matrix extension + * @size: The size of @data + * @offset: The offset in byte from which to start the parsing + * + * Parses the @quant Mpeg Video Quant Matrix Extension structure members from + * @data + * + * Returns: %TRUE if the quant matrix extension could be parsed correctly, + * %FALSE otherwize. + */ +gboolean +gst_mpeg_video_parse_quant_matrix_extension (GstMpegVideoQuantMatrixExt * quant, + const guint8 * data, gsize size, guint offset) +{ + guint8 i; + GstBitReader br; + + g_return_val_if_fail (quant != NULL, FALSE); + + size -= offset; + + if (size < 1) { + GST_DEBUG ("not enough bytes to parse the extension"); + return FALSE; + } + + gst_bit_reader_init (&br, &data[offset], size); + + if (gst_bit_reader_get_bits_uint8_unchecked (&br, 4) != + GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX) { + GST_DEBUG ("Not parsing a quant matrix extension"); + return FALSE; + } + + READ_UINT8 (&br, quant->load_intra_quantiser_matrix, 1); + if (quant->load_intra_quantiser_matrix) { + for (i = 0; i < 64; i++) { + READ_UINT8 (&br, quant->intra_quantiser_matrix[mpeg_zigzag_8x8[i]], 8); + } + } + + READ_UINT8 (&br, quant->load_non_intra_quantiser_matrix, 1); + if (quant->load_non_intra_quantiser_matrix) { + for (i = 0; i < 64; i++) { + READ_UINT8 (&br, quant->non_intra_quantiser_matrix[mpeg_zigzag_8x8[i]], + 8); + } + } + + READ_UINT8 (&br, quant->load_chroma_intra_quantiser_matrix, 1); + if (quant->load_chroma_intra_quantiser_matrix) { + for (i = 0; i < 64; i++) { + READ_UINT8 (&br, quant->chroma_intra_quantiser_matrix[mpeg_zigzag_8x8[i]], + 8); + } + } + + READ_UINT8 (&br, quant->load_chroma_non_intra_quantiser_matrix, 1); + if (quant->load_chroma_non_intra_quantiser_matrix) { + for (i = 0; i < 64; i++) { + READ_UINT8 (&br, + quant->chroma_non_intra_quantiser_matrix[mpeg_zigzag_8x8[i]], 8); + } + } + + return TRUE; + +failed: + GST_WARNING ("error parsing \"Quant Matrix Extension\""); + return FALSE; +} + +/** + * gst_mpeg_video_parse_picture_extension: + * @ext: (out): The #GstMpegVideoPictureExt structure to fill + * @data: The data from which to parse the picture extension + * @size: The size of @data + * @offset: The offset in byte from which to start the parsing + * + * Parse the @ext Mpeg Video Picture Extension structure members from @data + * + * Returns: %TRUE if the picture extension could be parsed correctly, + * %FALSE otherwize. + */ +gboolean +gst_mpeg_video_parse_picture_extension (GstMpegVideoPictureExt * ext, + const guint8 * data, gsize size, guint offset) +{ + GstBitReader br; + + g_return_val_if_fail (ext != NULL, FALSE); + + size -= offset; + + if (size < 4) + return FALSE; + + gst_bit_reader_init (&br, &data[offset], size); + + if (gst_bit_reader_get_bits_uint8_unchecked (&br, 4) != + GST_MPEG_VIDEO_PACKET_EXT_PICTURE) { + GST_DEBUG ("Not parsing a picture extension"); + return FALSE; + } + + /* f_code */ + READ_UINT8 (&br, ext->f_code[0][0], 4); + READ_UINT8 (&br, ext->f_code[0][1], 4); + READ_UINT8 (&br, ext->f_code[1][0], 4); + READ_UINT8 (&br, ext->f_code[1][1], 4); + + /* intra DC precision */ + READ_UINT8 (&br, ext->intra_dc_precision, 2); + + /* picture structure */ + READ_UINT8 (&br, ext->picture_structure, 2); + + /* top field first */ + READ_UINT8 (&br, ext->top_field_first, 1); + + /* frame pred frame dct */ + READ_UINT8 (&br, ext->frame_pred_frame_dct, 1); + + /* concealment motion vectors */ + READ_UINT8 (&br, ext->concealment_motion_vectors, 1); + + /* q scale type */ + READ_UINT8 (&br, ext->q_scale_type, 1); + + /* intra vlc format */ + READ_UINT8 (&br, ext->intra_vlc_format, 1); + + /* alternate scan */ + READ_UINT8 (&br, ext->alternate_scan, 1); + + /* repeat first field */ + READ_UINT8 (&br, ext->repeat_first_field, 1); + + /* chroma_420_type */ + READ_UINT8 (&br, ext->chroma_420_type, 1); + + /* progressive_frame */ + READ_UINT8 (&br, ext->progressive_frame, 1); + + /* composite display */ + READ_UINT8 (&br, ext->composite_display, 1); + + if (ext->composite_display) { + + /* v axis */ + READ_UINT8 (&br, ext->v_axis, 1); + + /* field sequence */ + READ_UINT8 (&br, ext->field_sequence, 3); + + /* sub carrier */ + READ_UINT8 (&br, ext->sub_carrier, 1); + + /* burst amplitude */ + READ_UINT8 (&br, ext->burst_amplitude, 7); + + /* sub_carrier phase */ + READ_UINT8 (&br, ext->sub_carrier_phase, 8); + } + + return TRUE; + +failed: + GST_WARNING ("error parsing \"Picture Coding Extension\""); + return FALSE; + +} + +/** + * gst_mpeg_video_parse_picture_header: + * @hdr: (out): The #GstMpegVideoPictureHdr structure to fill + * @data: The data from which to parse the picture header + * @size: The size of @data + * @offset: The offset in byte from which to start the parsing + * + * Parsers the @hdr Mpeg Video Picture Header structure members from @data + * + * Returns: %TRUE if the picture sequence could be parsed correctly, %FALSE + * otherwize. + */ +gboolean +gst_mpeg_video_parse_picture_header (GstMpegVideoPictureHdr * hdr, + const guint8 * data, gsize size, guint offset) +{ + GstBitReader br; + + size = size - offset; + + if (size < 4) + goto failed; + + gst_bit_reader_init (&br, &data[offset], size); + + /* temperal sequence number */ + if (!gst_bit_reader_get_bits_uint16 (&br, &hdr->tsn, 10)) + goto failed; + + + /* frame type */ + if (!gst_bit_reader_get_bits_uint8 (&br, (guint8 *) & hdr->pic_type, 3)) + goto failed; + + + if (hdr->pic_type == 0 || hdr->pic_type > 4) + goto failed; /* Corrupted picture packet */ + + /* skip VBV delay */ + if (!gst_bit_reader_skip (&br, 16)) + goto failed; + + if (hdr->pic_type == GST_MPEG_VIDEO_PICTURE_TYPE_P + || hdr->pic_type == GST_MPEG_VIDEO_PICTURE_TYPE_B) { + + READ_UINT8 (&br, hdr->full_pel_forward_vector, 1); + + READ_UINT8 (&br, hdr->f_code[0][0], 3); + hdr->f_code[0][1] = hdr->f_code[0][0]; + } else { + hdr->full_pel_forward_vector = 0; + hdr->f_code[0][0] = hdr->f_code[0][1] = 0; + } + + if (hdr->pic_type == GST_MPEG_VIDEO_PICTURE_TYPE_B) { + READ_UINT8 (&br, hdr->full_pel_backward_vector, 1); + + READ_UINT8 (&br, hdr->f_code[1][0], 3); + hdr->f_code[1][1] = hdr->f_code[1][0]; + } else { + hdr->full_pel_backward_vector = 0; + hdr->f_code[1][0] = hdr->f_code[1][1] = 0; + } + + return TRUE; + +failed: + { + GST_WARNING ("Failed to parse picture header"); + return FALSE; + } +} + +/** + * gst_mpeg_video_parse_gop: + * @gop: (out): The #GstMpegVideoGop structure to fill + * @data: The data from which to parse the gop + * @size: The size of @data + * @offset: The offset in byte from which to start the parsing + * + * Parses the @gop Mpeg Video Group of Picture structure members from @data + * + * Returns: %TRUE if the gop could be parsed correctly, %FALSE otherwize. + */ +gboolean +gst_mpeg_video_parse_gop (GstMpegVideoGop * gop, const guint8 * data, + gsize size, guint offset) +{ + GstBitReader br; + + g_return_val_if_fail (gop != NULL, FALSE); + + size -= offset; + + if (size < 4) + return FALSE; + + gst_bit_reader_init (&br, &data[offset], size); + + READ_UINT8 (&br, gop->drop_frame_flag, 1); + + READ_UINT8 (&br, gop->hour, 5); + + READ_UINT8 (&br, gop->minute, 6); + + /* skip unused bit */ + if (!gst_bit_reader_skip (&br, 1)) + return FALSE; + + READ_UINT8 (&br, gop->second, 6); + + READ_UINT8 (&br, gop->frame, 6); + + READ_UINT8 (&br, gop->closed_gop, 1); + + READ_UINT8 (&br, gop->broken_link, 1); + + return TRUE; + +failed: + GST_WARNING ("error parsing \"GOP\""); + return FALSE; +} diff --git a/ext/codecparsers/gst-libs/gst/codecparsers/gstmpegvideoparser.h b/ext/codecparsers/gst-libs/gst/codecparsers/gstmpegvideoparser.h new file mode 100644 index 0000000..88ab393 --- /dev/null +++ b/ext/codecparsers/gst-libs/gst/codecparsers/gstmpegvideoparser.h @@ -0,0 +1,431 @@ +/* Gstreamer + * Copyright (C) <2011> Intel Corporation + * Copyright (C) <2011> Collabora Ltd. + * Copyright (C) <2011> Thibault Saunier + * + * From bad/sys/vdpau/mpeg/mpegutil.c: + * Copyright (C) <2007> Jan Schmidt + * Copyright (C) <2009> Carl-Anton Ingmarsson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_MPEG_VIDEO_UTILS_H__ +#define __GST_MPEG_VIDEO_UTILS_H__ + +#ifndef GST_USE_UNSTABLE_API +#warning "The Mpeg video parsing library is unstable API and may change in future." +#warning "You can define GST_USE_UNSTABLE_API to avoid this warning." +#endif + +#include + +G_BEGIN_DECLS + +/** + * GstMpegVideoPacketTypeCode: + * @GST_MPEG_VIDEO_PACKET_PICTURE: Picture packet starting code + * @GST_MPEG_VIDEO_PACKET_SLICE_MIN: Slice min packet starting code + * @GST_MPEG_VIDEO_PACKET_SLICE_MAX: Slice max packet starting code + * @GST_MPEG_VIDEO_PACKET_USER_DATA: User data packet starting code + * @GST_MPEG_VIDEO_PACKET_SEQUENCE : Sequence packet starting code + * @GST_MPEG_VIDEO_PACKET_EXTENSION: Extension packet starting code + * @GST_MPEG_VIDEO_PACKET_SEQUENCE_END: Sequence end packet code + * @GST_MPEG_VIDEO_PACKET_GOP: Group of Picture packet starting code + * @GST_MPEG_VIDEO_PACKET_NONE: None packet code + * + * Indicates the type of MPEG packet + */ +typedef enum { + GST_MPEG_VIDEO_PACKET_PICTURE = 0x00, + GST_MPEG_VIDEO_PACKET_SLICE_MIN = 0x01, + GST_MPEG_VIDEO_PACKET_SLICE_MAX = 0xaf, + GST_MPEG_VIDEO_PACKET_USER_DATA = 0xb2, + GST_MPEG_VIDEO_PACKET_SEQUENCE = 0xb3, + GST_MPEG_VIDEO_PACKET_EXTENSION = 0xb5, + GST_MPEG_VIDEO_PACKET_SEQUENCE_END = 0xb7, + GST_MPEG_VIDEO_PACKET_GOP = 0xb8, + GST_MPEG_VIDEO_PACKET_NONE = 0xff +} GstMpegVideoPacketTypeCode; + +/** + * GST_MPEG_VIDEO_PACKET_IS_SLICE: + * @typecode: The MPEG video packet type code + * + * Checks whether a packet type code is a slice. + * + * Returns: %TRUE if the packet type code corresponds to a slice, + * else %FALSE. + */ +#define GST_MPEG_VIDEO_PACKET_IS_SLICE(typecode) ((typecode) >= GST_MPEG_VIDEO_PACKET_SLICE_MIN && \ + (typecode) <= GST_MPEG_VIDEO_PACKET_SLICE_MAX) + +/** + * GstMpegVideoPacketExtensionCode: + * @GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE: Sequence extension code + * @GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY: Sequence Display extension code + * @GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX: Quantization Matrix extension code + * @GST_MPEG_VIDEO_PACKET_EXT_PICTURE: Picture coding extension + * + * Indicates what type of packets are in this block, some are mutually + * exclusive though - ie, sequence packs are accumulated separately. GOP & + * Picture may occur together or separately. + */ +typedef enum { + GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE = 0x01, + GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY = 0x02, + GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX = 0x03, + GST_MPEG_VIDEO_PACKET_EXT_PICTURE = 0x08 +} GstMpegVideoPacketExtensionCode; + +/** + * GstMpegVideoLevel: + * @GST_MPEG_VIDEO_LEVEL_LOW: Low level (LL) + * @GST_MPEG_VIDEO_LEVEL_MAIN: Main level (ML) + * @GST_MPEG_VIDEO_LEVEL_HIGH_1440: High 1440 level (H-14) + * @GST_MPEG_VIDEO_LEVEL_HIGH: High level (HL) + * + * Mpeg-2 Levels. + **/ +typedef enum { + GST_MPEG_VIDEO_LEVEL_HIGH = 0x04, + GST_MPEG_VIDEO_LEVEL_HIGH_1440 = 0x06, + GST_MPEG_VIDEO_LEVEL_MAIN = 0x08, + GST_MPEG_VIDEO_LEVEL_LOW = 0x0a +} GstMpegVideoLevel; + +/** + * GstMpegVideoProfile: + * @GST_MPEG_VIDEO_PROFILE_422: 4:2:2 profile (422) + * @GST_MPEG_VIDEO_PROFILE_HIGH: High profile (HP) + * @GST_MPEG_VIDEO_PROFILE_SPATIALLY_SCALABLE: Spatially Scalable profile (Spatial) + * @GST_MPEG_VIDEO_PROFILE_SNR_SCALABLE: SNR Scalable profile (SNR) + * @GST_MPEG_VIDEO_PROFILE_MAIN: Main profile (MP) + * @GST_MPEG_VIDEO_PROFILE_SIMPLE: Simple profile (SP) + * + * Mpeg-2 Profiles. + **/ +typedef enum { + GST_MPEG_VIDEO_PROFILE_422 = 0x00, + GST_MPEG_VIDEO_PROFILE_HIGH = 0x01, + GST_MPEG_VIDEO_PROFILE_SPATIALLY_SCALABLE = 0x02, + GST_MPEG_VIDEO_PROFILE_SNR_SCALABLE = 0x03, + GST_MPEG_VIDEO_PROFILE_MAIN = 0x04, + GST_MPEG_VIDEO_PROFILE_SIMPLE = 0x05 +} GstMpegVideoProfile; + +/** + * GstMpegVideoChromaFormat: + * @GST_MPEG_VIDEO_CHROMA_RES: Invalid (reserved for future use) + * @GST_MPEG_VIDEO_CHROMA_420: 4:2:0 subsampling + * @GST_MPEG_VIDEO_CHROMA_422: 4:2:2 subsampling + * @GST_MPEG_VIDEO_CHROMA_444: 4:4:4 (non-subsampled) + * + * Chroma subsampling type. + */ +typedef enum { + GST_MPEG_VIDEO_CHROMA_RES = 0x00, + GST_MPEG_VIDEO_CHROMA_420 = 0x01, + GST_MPEG_VIDEO_CHROMA_422 = 0x02, + GST_MPEG_VIDEO_CHROMA_444 = 0x03, +} GstMpegVideoChromaFormat; + +/** + * GstMpegVideoPictureType: + * @GST_MPEG_VIDEO_PICTURE_TYPE_I: Intra-coded (I) frame + * @GST_MPEG_VIDEO_PICTURE_TYPE_P: Predictive-codec (P) frame + * @GST_MPEG_VIDEO_PICTURE_TYPE_B: Bidirectionally predictive-coded (B) frame + * @GST_MPEG_VIDEO_PICTURE_TYPE_D: D frame + * + * Picture type. + */ +typedef enum { + GST_MPEG_VIDEO_PICTURE_TYPE_I = 0x01, + GST_MPEG_VIDEO_PICTURE_TYPE_P = 0x02, + GST_MPEG_VIDEO_PICTURE_TYPE_B = 0x03, + GST_MPEG_VIDEO_PICTURE_TYPE_D = 0x04 +} GstMpegVideoPictureType; + +/** + * GstMpegVideoPictureStructure: + * @GST_MPEG_VIDEO_PICTURE_STRUCTURE_TOP_FIELD: Top field + * @GST_MPEG_VIDEO_PICTURE_STRUCTURE_BOTTOM_FIELD: Bottom field + * @GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME: Frame picture + * + * Picture structure type. + */ +typedef enum { + GST_MPEG_VIDEO_PICTURE_STRUCTURE_TOP_FIELD = 0x01, + GST_MPEG_VIDEO_PICTURE_STRUCTURE_BOTTOM_FIELD = 0x02, + GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME = 0x03 +} GstMpegVideoPictureStructure; + +typedef struct _GstMpegVideoSequenceHdr GstMpegVideoSequenceHdr; +typedef struct _GstMpegVideoSequenceExt GstMpegVideoSequenceExt; +typedef struct _GstMpegVideoSequenceDisplayExt GstMpegVideoSequenceDisplayExt; +typedef struct _GstMpegVideoPictureHdr GstMpegVideoPictureHdr; +typedef struct _GstMpegVideoGop GstMpegVideoGop; +typedef struct _GstMpegVideoPictureExt GstMpegVideoPictureExt; +typedef struct _GstMpegVideoQuantMatrixExt GstMpegVideoQuantMatrixExt; +typedef struct _GstMpegVideoPacket GstMpegVideoPacket; + +/** + * GstMpegVideoSequenceHdr: + * @width: Width of each frame + * @height: Height of each frame + * @par_w: Calculated Pixel Aspect Ratio width + * @par_h: Calculated Pixel Aspect Ratio height + * @fps_n: Calculated Framrate nominator + * @fps_d: Calculated Framerate denominator + * @bitrate_value: Value of the bitrate as is in the stream (400bps unit) + * @bitrate: the real bitrate of the Mpeg video stream in bits per second, 0 if VBR stream + * @constrained_parameters_flag: %TRUE if this stream uses contrained parameters. + * @intra_quantizer_matrix: intra-quantization table + * @non_intra_quantizer_matrix: non-intra quantization table + * + * The Mpeg2 Video Sequence Header structure. + */ +struct _GstMpegVideoSequenceHdr +{ + guint16 width, height; + guint8 aspect_ratio_info; + guint8 frame_rate_code; + guint32 bitrate_value; + guint16 vbv_buffer_size_value; + + guint8 constrained_parameters_flag; + + guint8 intra_quantizer_matrix[64]; + guint8 non_intra_quantizer_matrix[64]; + + /* Calculated values */ + guint par_w, par_h; + guint fps_n, fps_d; + guint bitrate; +}; + +/** + * GstMpegVideoSequenceExt: + * @profile: mpeg2 decoder profile + * @level: mpeg2 decoder level + * @progressive: %TRUE if the frames are progressive %FALSE otherwise + * @chroma_format: indicates the chrominance format + * @horiz_size_ext: Horizontal size + * @vert_size_ext: Vertical size + * @bitrate_ext: The bitrate + * @vbv_buffer_size_extension: VBV vuffer size + * @low_delay: %TRUE if the sequence doesn't contain any B-pictures, %FALSE + * otherwise + * @fps_n_ext: Framerate nominator code + * @fps_d_ext: Framerate denominator code + * + * The Mpeg2 Video Sequence Extension structure. + **/ +struct _GstMpegVideoSequenceExt +{ + /* mpeg2 decoder profile */ + guint8 profile; + /* mpeg2 decoder level */ + guint8 level; + + guint8 progressive; + guint8 chroma_format; + + guint8 horiz_size_ext, vert_size_ext; + + guint16 bitrate_ext; + guint8 vbv_buffer_size_extension; + guint8 low_delay; + guint8 fps_n_ext, fps_d_ext; + +}; + +/** + * GstMpegVideoSequenceDisplayExt: + * @profile: mpeg2 decoder profil + + */ +struct _GstMpegVideoSequenceDisplayExt +{ + guint8 video_format; + guint8 colour_description_flag; + + /* if colour_description_flag: */ + guint8 colour_primaries; + guint8 transfer_characteristics; + guint8 matrix_coefficients; + + guint16 display_horizontal_size; + guint16 display_vertical_size; +}; + +/** + * GstMpegVideoQuantMatrixExt: + * @load_intra_quantiser_matrix: + * @intra_quantiser_matrix: + * @load_non_intra_quantiser_matrix: + * @non_intra_quantiser_matrix: + * @load_chroma_intra_quantiser_matrix: + * @chroma_intra_quantiser_matrix: + * @load_chroma_non_intra_quantiser_matrix: + * @chroma_non_intra_quantiser_matrix: + * + * The Quant Matrix Extension structure + */ +struct _GstMpegVideoQuantMatrixExt +{ + guint8 load_intra_quantiser_matrix; + guint8 intra_quantiser_matrix[64]; + guint8 load_non_intra_quantiser_matrix; + guint8 non_intra_quantiser_matrix[64]; + guint8 load_chroma_intra_quantiser_matrix; + guint8 chroma_intra_quantiser_matrix[64]; + guint8 load_chroma_non_intra_quantiser_matrix; + guint8 chroma_non_intra_quantiser_matrix[64]; +}; + +/** + * GstMpegVideoPictureHdr: + * @tsn: Temporal Sequence Number + * @pic_type: Type of the frame + * @full_pel_forward_vector: the full pel forward flag of + * the frame: 0 or 1. + * @full_pel_backward_vector: the full pel backward flag + * of the frame: 0 or 1. + * @f_code: F code + * + * The Mpeg2 Video Picture Header structure. + */ +struct _GstMpegVideoPictureHdr +{ + guint16 tsn; + guint8 pic_type; + + guint8 full_pel_forward_vector, full_pel_backward_vector; + + guint8 f_code[2][2]; +}; + +/** + * GstMpegVideoPictureExt: + * @intra_dc_precision: Intra DC precision + * @picture_structure: Structure of the picture + * @top_field_first: Top field first + * @frame_pred_frame_dct: Frame + * @concealment_motion_vectors: Concealment Motion Vectors + * @q_scale_type: Q Scale Type + * @intra_vlc_format: Intra Vlc Format + * @alternate_scan: Alternate Scan + * @repeat_first_field: Repeat First Field + * @chroma_420_type: Chroma 420 Type + * @progressive_frame: %TRUE if the frame is progressive %FALSE otherwize + * + * The Mpeg2 Video Picture Extension structure. + */ +struct _GstMpegVideoPictureExt +{ + guint8 f_code[2][2]; + + guint8 intra_dc_precision; + guint8 picture_structure; + guint8 top_field_first; + guint8 frame_pred_frame_dct; + guint8 concealment_motion_vectors; + guint8 q_scale_type; + guint8 intra_vlc_format; + guint8 alternate_scan; + guint8 repeat_first_field; + guint8 chroma_420_type; + guint8 progressive_frame; + guint8 composite_display; + guint8 v_axis; + guint8 field_sequence; + guint8 sub_carrier; + guint8 burst_amplitude; + guint8 sub_carrier_phase; +}; + +/** + * GstMpegVideoGop: + * @drop_frame_flag: Drop Frame Flag + * @hour: Hour (0-23) + * @minute: Minute (O-59) + * @second: Second (0-59) + * @frame: Frame (0-59) + * @closed_gop: Closed Gop + * @broken_link: Broken link + * + * The Mpeg Video Group of Picture structure. + */ +struct _GstMpegVideoGop +{ + guint8 drop_frame_flag; + + guint8 hour, minute, second, frame; + + guint8 closed_gop; + guint8 broken_link; +}; + +/** + * GstMpegVideoTypeOffsetSize: + * + * @type: the type of the packet that start at @offset + * @data: the data containing the packet starting at @offset + * @offset: the offset of the packet start in bytes, it is the exact, start of the packet, no sync code included + * @size: The size in bytes of the packet or -1 if the end wasn't found. It is the exact size of the packet, no sync code included + * + * A structure that contains the type of a packet, its offset and its size + */ +struct _GstMpegVideoPacket +{ + const guint8 *data; + guint8 type; + guint offset; + gint size; +}; + +gboolean gst_mpeg_video_parse (GstMpegVideoPacket * packet, + const guint8 * data, gsize size, guint offset); + +gboolean gst_mpeg_video_parse_sequence_header (GstMpegVideoSequenceHdr * params, + const guint8 * data, gsize size, guint offset); + +/* seqext and displayext may be NULL if not received */ +gboolean gst_mpeg_video_finalise_mpeg2_sequence_header (GstMpegVideoSequenceHdr *hdr, + GstMpegVideoSequenceExt *seqext, GstMpegVideoSequenceDisplayExt *displayext); + +gboolean gst_mpeg_video_parse_picture_header (GstMpegVideoPictureHdr* hdr, + const guint8 * data, gsize size, guint offset); + +gboolean gst_mpeg_video_parse_picture_extension (GstMpegVideoPictureExt *ext, + const guint8 * data, gsize size, guint offset); + +gboolean gst_mpeg_video_parse_gop (GstMpegVideoGop * gop, + const guint8 * data, gsize size, guint offset); + +gboolean gst_mpeg_video_parse_sequence_extension (GstMpegVideoSequenceExt * seqext, + const guint8 * data, gsize size, guint offset); + +gboolean gst_mpeg_video_parse_sequence_display_extension (GstMpegVideoSequenceDisplayExt * seqdisplayext, + const guint8 * data, gsize size, guint offset); + +gboolean gst_mpeg_video_parse_quant_matrix_extension (GstMpegVideoQuantMatrixExt * quant, + const guint8 * data, gsize size, guint offset); + +G_END_DECLS + +#endif diff --git a/ext/codecparsers/gst-libs/gst/codecparsers/gstvc1parser.c b/ext/codecparsers/gst-libs/gst/codecparsers/gstvc1parser.c new file mode 100644 index 0000000..4ec9788 --- /dev/null +++ b/ext/codecparsers/gst-libs/gst/codecparsers/gstvc1parser.c @@ -0,0 +1,2135 @@ +/* Gstreamer + * Copyright (C) <2011> Intel + * Copyright (C) <2011> Collabora Ltd. + * Copyright (C) <2011> Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +/** + * SECTION:gstvc1parser + * @short_description: Convenience library for parsing vc1 video + * bitstream. + * + * For more details about the structures, look at the + * smpte specifications (S421m-2006.pdf). + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "gstvc1parser.h" +#include "parserutils.h" +#include +#include +#include + +#ifndef GST_DISABLE_GST_DEBUG + +#define GST_CAT_DEFAULT ensure_debug_category() + +static GstDebugCategory * +ensure_debug_category (void) +{ + static gsize cat_gonce = 0; + + if (g_once_init_enter (&cat_gonce)) { + gsize cat_done; + + cat_done = (gsize) _gst_debug_category_new ("codecparsers_vc1", 0, + "VC1 codec parsing library"); + + g_once_init_leave (&cat_gonce, cat_done); + } + + return (GstDebugCategory *) cat_gonce; +} + +#else + +#define ensure_debug_category() /* NOOP */ + +#endif /* GST_DISABLE_GST_DEBUG */ + +static const guint8 vc1_pquant_table[3][32] = { + { /* Implicit quantizer */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 29, 31}, + { /* Explicit quantizer, pquantizer uniform */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}, + { /* Explicit quantizer, pquantizer non-uniform */ + 0, 1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 29, 31} +}; + +static const guint8 vc1_mvmode_table[2][5] = { + /* Table 47: P Picture High rate (PQUANT <= 12) MVMODE code table */ + { + GST_VC1_MVMODE_1MV, + GST_VC1_MVMODE_MIXED_MV, + GST_VC1_MVMODE_1MV_HPEL, + GST_VC1_MVMODE_INTENSITY_COMP, + GST_VC1_MVMODE_1MV_HPEL_BILINEAR}, + /* Table 46: P Picture Low rate (PQUANT > 12) MVMODE code table */ + { + GST_VC1_MVMODE_1MV_HPEL_BILINEAR, + GST_VC1_MVMODE_1MV, + GST_VC1_MVMODE_1MV_HPEL, + GST_VC1_MVMODE_INTENSITY_COMP, + GST_VC1_MVMODE_MIXED_MV} +}; + +static const guint8 vc1_mvmode2_table[2][4] = { + /* Table 50: P Picture High rate (PQUANT <= 12) MVMODE2 code table */ + { + GST_VC1_MVMODE_1MV, + GST_VC1_MVMODE_MIXED_MV, + GST_VC1_MVMODE_1MV_HPEL, + GST_VC1_MVMODE_1MV_HPEL_BILINEAR}, + /* Table 49: P Picture Low rate (PQUANT > 12) MVMODE2 code table */ + { + GST_VC1_MVMODE_1MV_HPEL_BILINEAR, + GST_VC1_MVMODE_1MV, + GST_VC1_MVMODE_1MV_HPEL, + GST_VC1_MVMODE_MIXED_MV} +}; + +/* Table 40: BFRACTION VLC Table */ +static const VLCTable vc1_bfraction_vlc_table[] = { + {GST_VC1_BFRACTION_BASIS / 2, 0x00, 3}, + {GST_VC1_BFRACTION_BASIS / 3, 0x01, 3}, + {(GST_VC1_BFRACTION_BASIS * 2) / 3, 0x02, 3}, + {GST_VC1_BFRACTION_BASIS / 4, 0x02, 3}, + {(GST_VC1_BFRACTION_BASIS * 3) / 4, 0x04, 3}, + {GST_VC1_BFRACTION_BASIS / 5, 0x05, 3}, + {(GST_VC1_BFRACTION_BASIS * 2) / 5, 0x06, 3}, + {(GST_VC1_BFRACTION_BASIS * 3) / 5, 0x70, 7}, + {(GST_VC1_BFRACTION_BASIS * 4) / 5, 0x71, 7}, + {GST_VC1_BFRACTION_BASIS / 6, 0x72, 7}, + {(GST_VC1_BFRACTION_BASIS * 5) / 6, 0x73, 7}, + {GST_VC1_BFRACTION_BASIS / 7, 0x74, 7}, + {(GST_VC1_BFRACTION_BASIS * 2) / 7, 0x75, 7}, + {(GST_VC1_BFRACTION_BASIS * 3) / 7, 0x76, 7}, + {(GST_VC1_BFRACTION_BASIS * 4) / 7, 0x77, 7}, + {(GST_VC1_BFRACTION_BASIS * 5) / 7, 0x78, 7}, + {(GST_VC1_BFRACTION_BASIS * 6) / 7, 0x79, 7}, + {GST_VC1_BFRACTION_BASIS / 8, 0x7a, 7}, + {(GST_VC1_BFRACTION_BASIS * 3) / 8, 0x7b, 7}, + {(GST_VC1_BFRACTION_BASIS * 5) / 8, 0x7c, 7}, + {(GST_VC1_BFRACTION_BASIS * 7) / 8, 0x7d, 7}, + {GST_VC1_BFRACTION_RESERVED, 0x7e, 7}, + {GST_VC1_BFRACTION_PTYPE_BI, 0x7f, 7} +}; + +/* Imode types */ +enum +{ + IMODE_RAW, + IMODE_NORM2, + IMODE_DIFF2, + IMODE_NORM6, + IMODE_DIFF6, + IMODE_ROWSKIP, + IMODE_COLSKIP +}; + +/* Table 69: IMODE VLC Codetable */ +static const VLCTable vc1_imode_vlc_table[] = { + {IMODE_NORM2, 0x02, 2}, + {IMODE_NORM6, 0x03, 2}, + {IMODE_ROWSKIP, 0x02, 3}, + {IMODE_COLSKIP, 0x03, 3}, + {IMODE_DIFF2, 0x01, 3}, + {IMODE_DIFF6, 0x01, 4}, + {IMODE_RAW, 0x00, 4} +}; + +/* Table 80: Norm-2/Diff-2 Code Table */ +static const VLCTable vc1_norm2_vlc_table[4] = { + {0, 0, 1}, + {2, 4, 3}, + {1, 5, 3}, + {3, 3, 2} +}; + +/* Table 81: Code table for 3x2 and 2x3 tiles */ +static const VLCTable vc1_norm6_vlc_table[64] = { + {0, 1, 1}, + {1, 2, 4}, + {2, 3, 4}, + {3, 0, 8}, + {4, 4, 4}, + {5, 1, 8}, + {6, 2, 8}, + {7, (2 << 5) | 7, 10}, + {8, 5, 4}, + {9, 3, 8}, + {10, 4, 8}, + {11, (2 << 5) | 11, 10}, + {12, 5, 8}, + {13, (2 << 5) | 13, 10}, + {14, (2 << 5) | 14, 10}, + {15, (3 << 8) | 14, 13}, + {16, 6, 4}, + {17, 6, 8}, + {18, 7, 8}, + {19, (2 << 5) | 19, 10}, + {20, 8, 8}, + {21, (2 << 5) | 21, 10}, + {22, (2 << 5) | 22, 10}, + {23, (3 << 8) | 13, 13}, + {24, 9, 8}, + {25, (2 << 5) | 25, 10}, + {26, (2 << 5) | 26, 10}, + {27, (3 << 8) | 12, 13}, + {28, (2 << 5) | 28, 10}, + {29, (3 << 8) | 11, 13}, + {30, (3 << 8) | 10, 13}, + {31, (3 << 4) | 7, 9}, + {32, 7, 4}, + {33, 10, 8}, + {34, 11, 8}, + {35, (2 << 5) | 3, 10}, + {36, 12, 8}, + {37, (2 << 5) | 5, 10}, + {38, (2 << 5) | 6, 10}, + {39, (3 << 8) | 9, 13}, + {40, 13, 8}, + {41, (2 << 5) | 9, 10}, + {42, (2 << 5) | 10, 10}, + {43, (3 << 8) | 8, 13}, + {44, (2 << 5) | 12, 10}, + {45, (3 << 8) | 7, 13}, + {46, (3 << 8) | 6, 13}, + {47, (3 << 4) | 6, 9}, + {48, 14, 8}, + {49, (2 << 5) | 17, 10}, + {50, (2 << 5) | 18, 10}, + {51, (3 << 8) | 5, 13}, + {52, (2 << 5) | 20, 10}, + {53, (3 << 8) | 4, 13}, + {54, (3 << 8) | 3, 13}, + {55, (3 << 4) | 5, 9}, + {56, (2 << 5) | 24, 10}, + {57, (3 << 8) | 2, 13}, + {58, (3 << 8) | 1, 13}, + {59, (3 << 4) | 4, 9}, + {60, (3 << 8) | 0, 13}, + {61, (3 << 4) | 3, 9}, + {62, (3 << 4) | 2, 9}, + {63, (3 << 1) | 1, 6} +}; + +/* SMPTE 421M Table 7 */ +typedef struct +{ + gint par_n, par_d; +} PAR; + +static PAR aspect_ratios[] = { + {0, 0}, + {1, 1}, + {12, 11}, + {10, 11}, + {16, 11}, + {40, 33}, + {24, 11}, + {20, 11}, + {32, 11}, + {80, 33}, + {18, 11}, + {15, 11}, + {64, 33}, + {160, 99}, + {0, 0}, + {0, 0} +}; + +/* SMPTE 421M Table 8 */ +static const guint framerates_n[] = { + 0, + 24 * 1000, + 25 * 1000, + 30 * 1000, + 50 * 1000, + 60 * 1000, + 48 * 1000, + 72 * 1000 +}; + +/* SMPTE 421M Table 9 */ +static const guint framerates_d[] = { + 0, + 1000, + 1001 +}; + + +static inline gboolean +decode_colskip (GstBitReader * br, guint8 * data, guint width, guint height, + guint stride, guint invert) +{ + guint x, y; + guint8 colskip, v; + + GST_DEBUG ("Parsing colskip"); + + invert &= 1; + for (x = 0; x < width; x++) { + READ_UINT8 (br, colskip, 1); + + if (data) { + if (colskip) { + for (y = 0; y < height; y++) { + READ_UINT8 (br, v, 1); + data[y * stride] = v ^ invert; + } + } else { + for (y = 0; y < height; y++) + data[y * stride] = invert; + } + data++; + } else if (colskip) + SKIP (br, height); + } + + return TRUE; + +failed: + GST_WARNING ("Failed to parse colskip"); + + return FALSE; +} + +static inline gboolean +decode_rowskip (GstBitReader * br, guint8 * data, guint width, guint height, + guint stride, guint invert) +{ + guint x, y; + guint8 rowskip, v; + + GST_DEBUG ("Parsing rowskip"); + + invert &= 1; + for (y = 0; y < height; y++) { + READ_UINT8 (br, rowskip, 1); + + if (data) { + if (!rowskip) + memset (data, invert, width); + else { + for (x = 0; x < width; x++) { + READ_UINT8 (br, v, 1); + data[x] = v ^ invert; + } + } + data += stride; + } else if (rowskip) + SKIP (br, width); + } + + return TRUE; + +failed: + GST_WARNING ("Failed to parse rowskip"); + + return FALSE; +} + +static inline gint8 +decode012 (GstBitReader * br) +{ + guint8 n; + + READ_UINT8 (br, n, 1); + + if (n == 0) + return 0; + + READ_UINT8 (br, n, 1); + + return n + 1; + +failed: + GST_WARNING ("Could not decode 0 1 2 returning -1"); + + return -1; +} + +static inline guint +calculate_nb_pan_scan_win (GstVC1AdvancedSeqHdr * advseqhdr, + GstVC1PicAdvanced * pic) +{ + if (advseqhdr->interlace && !advseqhdr->psf) { + if (advseqhdr->pulldown) + return pic->rff + 2; + + return 2; + + } else { + if (advseqhdr->pulldown) + return pic->rptfrm + 1; + + return 1; + } +} + +static gboolean +decode_refdist (GstBitReader * br, guint16 * value) +{ + guint16 tmp; + gint i = 2; + + if (!gst_bit_reader_peek_bits_uint16 (br, &tmp, i)) + goto failed; + + if (tmp < 0x03) { + READ_UINT16 (br, *value, i); + + return TRUE; + } + + do { + i++; + + if (!gst_bit_reader_peek_bits_uint16 (br, &tmp, i)) + goto failed; + + if (!(tmp >> i)) { + READ_UINT16 (br, *value, i); + + return TRUE; + } + } while (i < 16); + + +failed: + { + GST_WARNING ("Could not decode end 0 returning"); + + return FALSE; + } +} + +/*** bitplanes decoding ***/ +static gboolean +bitplane_decoding (GstBitReader * br, guint8 * data, + GstVC1SeqHdr * seqhdr, guint8 * is_raw) +{ + const guint width = seqhdr->mb_width; + const guint height = seqhdr->mb_height; + const guint stride = seqhdr->mb_stride; + guint imode, invert, invert_mask; + guint x, y, v; + guint8 *pdata = data; + + *is_raw = FALSE; + + GET_BITS (br, 1, &invert); + invert_mask = -invert; + + if (!decode_vlc (br, &imode, vc1_imode_vlc_table, + G_N_ELEMENTS (vc1_imode_vlc_table))) + goto failed; + + switch (imode) { + case IMODE_RAW: + + GST_DEBUG ("Parsing IMODE_RAW"); + + *is_raw = TRUE; + return TRUE; + + case IMODE_DIFF2: + invert_mask = 0; + /* fall-through */ + case IMODE_NORM2: + invert_mask &= 3; + + GST_DEBUG ("Parsing IMODE_DIFF2 or IMODE_NORM2 biplane"); + + x = 0; + if ((height * width) & 1) { + GET_BITS (br, 1, &v); + if (pdata) { + *pdata++ = (v ^ invert_mask) & 1; + if (++x == width) { + x = 0; + pdata += stride - width; + } + } + } + + for (y = 0; y < height * width; y += 2) { + if (!decode_vlc (br, &v, vc1_norm2_vlc_table, + G_N_ELEMENTS (vc1_norm2_vlc_table))) + goto failed; + if (pdata) { + v ^= invert_mask; + *pdata++ = v >> 1; + if (++x == width) { + x = 0; + pdata += stride - width; + } + *pdata++ = v & 1; + if (++x == width) { + x = 0; + pdata += stride - width; + } + } + } + break; + + case IMODE_DIFF6: + invert_mask = 0; + /* fall-through */ + case IMODE_NORM6: + + GST_DEBUG ("Parsing IMODE_DIFF6 or IMODE_NORM6 biplane"); + + if (!(height % 3) && (width % 3)) { /* decode 2x3 "vertical" tiles */ + for (y = 0; y < height; y += 3) { + for (x = width & 1; x < width; x += 2) { + if (!decode_vlc (br, &v, vc1_norm6_vlc_table, + G_N_ELEMENTS (vc1_norm6_vlc_table))) + goto failed; + + if (pdata) { + v ^= invert_mask; + pdata[x + 0] = v & 1; + pdata[x + 1] = (v >> 1) & 1; + pdata[x + 0 + stride] = (v >> 2) & 1; + pdata[x + 1 + stride] = (v >> 3) & 1; + pdata[x + 0 + stride * 2] = (v >> 4) & 1; + pdata[x + 1 + stride * 2] = (v >> 5) & 1; + } + } + if (pdata) + pdata += 3 * stride; + } + + x = width & 1; + y = 0; + } else { /* decode 3x2 "horizontal" tiles */ + + if (pdata) + pdata += (height & 1) * width; + for (y = height & 1; y < height; y += 2) { + for (x = width % 3; x < width; x += 3) { + if (!decode_vlc (br, &v, vc1_norm6_vlc_table, + G_N_ELEMENTS (vc1_norm6_vlc_table))) + goto failed; + + if (pdata) { + v ^= invert_mask; + pdata[x + 0] = v & 1; + pdata[x + 1] = (v >> 1) & 1; + pdata[x + 2] = (v >> 2) & 1; + pdata[x + 0 + stride] = (v >> 3) & 1; + pdata[x + 1 + stride] = (v >> 4) & 1; + pdata[x + 2 + stride] = (v >> 5) & 1; + } + } + if (pdata) + pdata += 2 * stride; + } + + x = width % 3; + y = height & 1; + } + + if (x) { + if (data) + pdata = data + y * stride; + if (!decode_colskip (br, pdata, x, height, stride, invert_mask)) + goto failed; + } + + if (y) { + if (data) + pdata = data + x; + if (!decode_rowskip (br, pdata, width, y, stride, invert_mask)) + goto failed; + } + break; + case IMODE_ROWSKIP: + + GST_DEBUG ("Parsing IMODE_ROWSKIP biplane"); + + if (!decode_rowskip (br, data, width, height, stride, invert_mask)) + goto failed; + break; + case IMODE_COLSKIP: + + GST_DEBUG ("Parsing IMODE_COLSKIP biplane"); + + if (!decode_colskip (br, data, width, height, stride, invert_mask)) + goto failed; + break; + } + + if (!data) + return TRUE; + + /* Applying diff operator */ + if (imode == IMODE_DIFF2 || imode == IMODE_DIFF6) { + pdata = data; + pdata[0] ^= invert; + + for (x = 1; x < width; x++) + pdata[x] ^= pdata[x - 1]; + + for (y = 1; y < height; y++) { + pdata[stride] ^= pdata[0]; + + for (x = 1; x < width; x++) { + if (pdata[stride + x - 1] != pdata[x]) + pdata[stride + x] ^= invert; + else + pdata[stride + x] ^= pdata[stride + x - 1]; + } + pdata += stride; + } + } + + return TRUE; + +failed: + GST_WARNING ("Failed to decode bitplane"); + + return FALSE; +} + +static gboolean +parse_vopdquant (GstBitReader * br, GstVC1FrameHdr * framehdr, guint8 dquant) +{ + GstVC1VopDquant *vopdquant = &framehdr->vopdquant; + + GST_DEBUG ("Parsing vopdquant"); + + vopdquant->dqbilevel = 0; + + if (dquant == 2) { + READ_UINT8 (br, vopdquant->dquantfrm, 1); + + READ_UINT8 (br, vopdquant->pqdiff, 3); + + if (vopdquant->pqdiff != 7) + vopdquant->altpquant = framehdr->pquant + vopdquant->pqdiff + 1; + else { + READ_UINT8 (br, vopdquant->abspq, 5); + vopdquant->altpquant = vopdquant->abspq; + } + } else { + READ_UINT8 (br, vopdquant->dquantfrm, 1); + GST_DEBUG (" %u DquantFrm %u", gst_bit_reader_get_pos (br), + vopdquant->dquantfrm); + + if (vopdquant->dquantfrm) { + READ_UINT8 (br, vopdquant->dqprofile, 1); + + switch (vopdquant->dqprofile) { + case GST_VC1_DQPROFILE_SINGLE_EDGE: + case GST_VC1_DQPROFILE_DOUBLE_EDGES: + READ_UINT8 (br, vopdquant->dqsbedge, 2); + break; + + case GST_VC1_DQPROFILE_ALL_MBS: + READ_UINT8 (br, vopdquant->dqbilevel, 1); + break; + } + + if (vopdquant->dqbilevel + || vopdquant->dqprofile != GST_VC1_DQPROFILE_ALL_MBS) { + { + READ_UINT8 (br, vopdquant->pqdiff, 3); + + if (vopdquant->pqdiff == 7) + READ_UINT8 (br, vopdquant->abspq, 5); + } + } + } + } + + return TRUE; + +failed: + GST_WARNING ("Failed to parse vopdquant"); + + return FALSE; +} + +static inline gint +scan_for_start_codes (const guint8 * data, guint size) +{ + GstByteReader br; + gst_byte_reader_init (&br, data, size); + + /* NALU not empty, so we can at least expect 1 (even 2) bytes following sc */ + return gst_byte_reader_masked_scan_uint32 (&br, 0xffffff00, 0x00000100, + 0, size); +} + +static inline gint +get_unary (GstBitReader * br, gint stop, gint len) +{ + int i; + guint8 current = 0xff; + + for (i = 0; i < len; i++) { + current = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + if (current == stop) + return i; + } + + return i; +} + +static inline void +calculate_framerate_bitrate (guint8 frmrtq_postproc, guint8 bitrtq_postproc, + guint * framerate, guint * bitrate) +{ + if (frmrtq_postproc == 0 && bitrtq_postproc == 31) { + *framerate = 0; + *bitrate = 0; + } else if (frmrtq_postproc == 0 && bitrtq_postproc == 30) { + *framerate = 2; + *bitrate = 1952; + } else if (frmrtq_postproc == 1 && bitrtq_postproc == 31) { + *framerate = 6; + *bitrate = 2016; + } else { + if (frmrtq_postproc == 7) { + *framerate = 30; + } else { + *framerate = 2 + (frmrtq_postproc * 4); + } + if (bitrtq_postproc == 31) { + *bitrate = 2016; + } else { + *bitrate = 32 + (bitrtq_postproc * 64); + } + } +} + +static inline void +calculate_mb_size (GstVC1SeqHdr * seqhdr, guint width, guint height) +{ + seqhdr->mb_width = (width + 15) >> 4; + seqhdr->mb_height = (height + 15) >> 4; + seqhdr->mb_stride = seqhdr->mb_width + 1; +} + +static GstVC1ParserResult +parse_hrd_param_flag (GstBitReader * br, GstVC1HrdParam * hrd_param) +{ + guint i; + + GST_DEBUG ("Parsing Hrd param flag"); + + + if (gst_bit_reader_get_remaining (br) < 13) + goto failed; + + hrd_param->hrd_num_leaky_buckets = + gst_bit_reader_get_bits_uint8_unchecked (br, 5); + hrd_param->bit_rate_exponent = + gst_bit_reader_get_bits_uint8_unchecked (br, 4); + hrd_param->buffer_size_exponent = + gst_bit_reader_get_bits_uint8_unchecked (br, 4); + + if (gst_bit_reader_get_remaining (br) < + (32 * hrd_param->hrd_num_leaky_buckets)) + goto failed; + + for (i = 0; i < hrd_param->hrd_num_leaky_buckets; i++) { + hrd_param->hrd_rate[i] = gst_bit_reader_get_bits_uint16_unchecked (br, 16); + hrd_param->hrd_buffer[i] = + gst_bit_reader_get_bits_uint16_unchecked (br, 16); + } + + return GST_VC1_PARSER_OK; + +failed: + GST_WARNING ("Failed to parse hrd param flag"); + + return GST_VC1_PARSER_ERROR; +} + +static GstVC1ParserResult +parse_sequence_header_advanced (GstVC1SeqHdr * seqhdr, GstBitReader * br) +{ + GstVC1AdvancedSeqHdr *advanced = &seqhdr->advanced; + guint8 tmp; + + GST_DEBUG ("Parsing sequence header in advanced mode"); + + READ_UINT8 (br, tmp, 3); + advanced->level = tmp; + advanced->par_n = 0; + advanced->par_d = 0; + advanced->fps_n = 0; + advanced->fps_d = 0; + + READ_UINT8 (br, advanced->colordiff_format, 2); + READ_UINT8 (br, advanced->frmrtq_postproc, 3); + READ_UINT8 (br, advanced->bitrtq_postproc, 5); + + calculate_framerate_bitrate (advanced->frmrtq_postproc, + advanced->bitrtq_postproc, &advanced->framerate, &advanced->bitrate); + + GST_DEBUG ("level %u, colordiff_format %u , frmrtq_postproc %u," + " bitrtq_postproc %u", advanced->level, advanced->colordiff_format, + advanced->frmrtq_postproc, advanced->bitrtq_postproc); + + if (gst_bit_reader_get_remaining (br) < 32) + goto failed; + + advanced->postprocflag = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + advanced->max_coded_width = gst_bit_reader_get_bits_uint16_unchecked (br, 12); + advanced->max_coded_height = + gst_bit_reader_get_bits_uint16_unchecked (br, 12); + advanced->max_coded_width = (advanced->max_coded_width + 1) << 1; + advanced->max_coded_height = (advanced->max_coded_height + 1) << 1; + calculate_mb_size (seqhdr, advanced->max_coded_width, + advanced->max_coded_height); + advanced->pulldown = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + advanced->interlace = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + advanced->tfcntrflag = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + advanced->finterpflag = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + + GST_DEBUG ("postprocflag %u, max_coded_width %u, max_coded_height %u," + "pulldown %u, interlace %u, tfcntrflag %u, finterpflag %u", + advanced->postprocflag, advanced->max_coded_width, + advanced->max_coded_height, advanced->pulldown, + advanced->interlace, advanced->tfcntrflag, advanced->finterpflag); + + /* Skipping reserved bit */ + gst_bit_reader_skip_unchecked (br, 1); + + advanced->psf = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + advanced->display_ext = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + if (advanced->display_ext) { + READ_UINT16 (br, advanced->disp_horiz_size, 14); + READ_UINT16 (br, advanced->disp_vert_size, 14); + + advanced->disp_horiz_size++; + advanced->disp_vert_size++; + + READ_UINT8 (br, advanced->aspect_ratio_flag, 1); + + if (advanced->aspect_ratio_flag) { + READ_UINT8 (br, advanced->aspect_ratio, 4); + + if (advanced->aspect_ratio == 15) { + /* Aspect Width (6.1.14.3.2) and Aspect Height (6.1.14.3.3) + * syntax elements hold a binary encoding of sizes ranging + * from 1 to 256 */ + READ_UINT8 (br, advanced->aspect_horiz_size, 8); + READ_UINT8 (br, advanced->aspect_vert_size, 8); + advanced->par_n = 1 + advanced->aspect_horiz_size; + advanced->par_d = 1 + advanced->aspect_vert_size; + } else { + advanced->par_n = aspect_ratios[advanced->aspect_ratio].par_n; + advanced->par_d = aspect_ratios[advanced->aspect_ratio].par_d; + } + } + READ_UINT8 (br, advanced->framerate_flag, 1); + if (advanced->framerate_flag) { + READ_UINT8 (br, advanced->framerateind, 1); + + if (!advanced->framerateind) { + READ_UINT8 (br, advanced->frameratenr, 8); + READ_UINT8 (br, advanced->frameratedr, 4); + } else { + READ_UINT16 (br, advanced->framerateexp, 16); + } + if (advanced->frameratenr > 0 && + advanced->frameratenr < 8 && + advanced->frameratedr > 0 && advanced->frameratedr < 3) { + advanced->fps_n = framerates_n[advanced->frameratenr]; + advanced->fps_d = framerates_d[advanced->frameratedr]; + } else { + advanced->fps_n = advanced->framerateexp + 1; + advanced->fps_d = 32; + } + } + READ_UINT8 (br, advanced->color_format_flag, 1); + + if (advanced->color_format_flag) { + if (gst_bit_reader_get_remaining (br) < 24) + goto failed; + + advanced->color_prim = gst_bit_reader_get_bits_uint8_unchecked (br, 8); + advanced->transfer_char = gst_bit_reader_get_bits_uint8_unchecked (br, 8); + advanced->matrix_coef = gst_bit_reader_get_bits_uint8_unchecked (br, 8); + } + } + READ_UINT8 (br, advanced->hrd_param_flag, 1); + if (advanced->hrd_param_flag) + return parse_hrd_param_flag (br, &advanced->hrd_param); + + return GST_VC1_PARSER_OK; + +failed: + GST_WARNING ("Failed to parse advanced headers"); + + return GST_VC1_PARSER_ERROR; +} + +static GstVC1ParserResult +parse_frame_header_advanced (GstBitReader * br, GstVC1FrameHdr * framehdr, + GstVC1SeqHdr * seqhdr, GstVC1BitPlanes * bitplanes, gboolean field2) +{ + GstVC1AdvancedSeqHdr *advhdr = &seqhdr->advanced; + GstVC1PicAdvanced *pic = &framehdr->pic.advanced; + GstVC1EntryPointHdr *entrypthdr = &advhdr->entrypoint; + guint8 mvmodeidx; + + GST_DEBUG ("Parsing Frame header advanced %u", advhdr->interlace); + + /* Set the conveninence fields */ + framehdr->profile = seqhdr->profile; + framehdr->dquant = entrypthdr->dquant; + + if (advhdr->interlace) { + gint8 fcm = decode012 (br); + + if (fcm < 0) + goto failed; + + pic->fcm = (guint8) fcm; + } else + pic->fcm = GST_VC1_FRAME_PROGRESSIVE; + + if (pic->fcm == GST_VC1_FIELD_INTERLACE) { + READ_UINT8 (br, pic->fptype, 3); + if (field2) { + switch (pic->fptype) { + case 0x00: + case 0x02: + framehdr->ptype = GST_VC1_PICTURE_TYPE_I; + case 0x01: + case 0x03: + framehdr->ptype = GST_VC1_PICTURE_TYPE_P; + case 0x04: + case 0x06: + framehdr->ptype = GST_VC1_PICTURE_TYPE_B; + case 0x05: + case 0x07: + framehdr->ptype = GST_VC1_PICTURE_TYPE_BI; + } + } else { + switch (pic->fptype) { + case 0x00: + case 0x01: + framehdr->ptype = GST_VC1_PICTURE_TYPE_I; + case 0x02: + case 0x03: + framehdr->ptype = GST_VC1_PICTURE_TYPE_P; + case 0x04: + case 0x05: + framehdr->ptype = GST_VC1_PICTURE_TYPE_B; + case 0x06: + case 0x07: + framehdr->ptype = GST_VC1_PICTURE_TYPE_BI; + } + } + } else + framehdr->ptype = (guint8) get_unary (br, 0, 4); + + if (advhdr->tfcntrflag) { + READ_UINT8 (br, pic->tfcntr, 8); + GST_DEBUG ("tfcntr %u", pic->tfcntr); + } + + if (advhdr->pulldown) { + if (!advhdr->interlace || advhdr->psf) { + + READ_UINT8 (br, pic->rptfrm, 2); + GST_DEBUG ("rptfrm %u", pic->rptfrm); + + } else { + + READ_UINT8 (br, pic->tff, 1); + READ_UINT8 (br, pic->rff, 1); + GST_DEBUG ("tff %u, rff %u", pic->tff, pic->rff); + } + } + + if (entrypthdr->panscan_flag) { + READ_UINT8 (br, pic->ps_present, 1); + + if (pic->ps_present) { + guint i, nb_pan_scan_win = calculate_nb_pan_scan_win (advhdr, pic); + + if (gst_bit_reader_get_remaining (br) < 64 * nb_pan_scan_win) + goto failed; + + for (i = 0; i < nb_pan_scan_win; i++) { + pic->ps_hoffset = gst_bit_reader_get_bits_uint32_unchecked (br, 18); + pic->ps_voffset = gst_bit_reader_get_bits_uint32_unchecked (br, 18); + pic->ps_width = gst_bit_reader_get_bits_uint16_unchecked (br, 14); + pic->ps_height = gst_bit_reader_get_bits_uint16_unchecked (br, 14); + } + } + } + + if (framehdr->ptype == GST_VC1_PICTURE_TYPE_SKIPPED) + return GST_VC1_PARSER_OK; + + READ_UINT8 (br, pic->rndctrl, 1); + + if (advhdr->interlace) { + READ_UINT8 (br, pic->uvsamp, 1); + GST_DEBUG ("uvsamp %u", pic->uvsamp); + if (pic->fcm == GST_VC1_FIELD_INTERLACE && entrypthdr->refdist_flag && + pic->fptype < 4) + decode_refdist (br, &pic->refdist); + else + pic->refdist = 0; + } + + if (advhdr->finterpflag) { + READ_UINT8 (br, framehdr->interpfrm, 1); + GST_DEBUG ("interpfrm %u", framehdr->interpfrm); + } + + if ((pic->fcm != GST_VC1_FIELD_INTERLACE && + framehdr->ptype == GST_VC1_PICTURE_TYPE_B) || + (pic->fcm == GST_VC1_FIELD_INTERLACE && (pic->fptype > 4))) { + + guint bfraction; + + if (!decode_vlc (br, &bfraction, vc1_bfraction_vlc_table, + G_N_ELEMENTS (vc1_bfraction_vlc_table))) + goto failed; + + pic->bfraction = bfraction; + GST_DEBUG ("bfraction %u", pic->bfraction); + + if (pic->bfraction == GST_VC1_BFRACTION_PTYPE_BI) { + framehdr->ptype = GST_VC1_PICTURE_TYPE_BI; + } + + } + + READ_UINT8 (br, framehdr->pqindex, 5); + if (!framehdr->pqindex) + goto failed; + + /* compute pquant */ + if (entrypthdr->quantizer == GST_VC1_QUANTIZER_IMPLICITLY) + framehdr->pquant = vc1_pquant_table[0][framehdr->pqindex]; + else + framehdr->pquant = vc1_pquant_table[1][framehdr->pqindex]; + + framehdr->pquantizer = 1; + if (entrypthdr->quantizer == GST_VC1_QUANTIZER_IMPLICITLY) + framehdr->pquantizer = framehdr->pqindex < 9; + if (entrypthdr->quantizer == GST_VC1_QUANTIZER_NON_UNIFORM) + framehdr->pquantizer = 0; + + if (framehdr->pqindex <= 8) + READ_UINT8 (br, framehdr->halfqp, 1); + else + framehdr->halfqp = 0; + + if (entrypthdr->quantizer == GST_VC1_QUANTIZER_EXPLICITLY) { + READ_UINT8 (br, framehdr->pquantizer, 1); + } + + if (advhdr->postprocflag) + READ_UINT8 (br, pic->postproc, 2); + + GST_DEBUG ("Parsing %u picture, pqindex %u, pquant %u pquantizer %u" + "halfqp %u", framehdr->ptype, framehdr->pqindex, framehdr->pquant, + framehdr->pquantizer, framehdr->halfqp); + + switch (framehdr->ptype) { + case GST_VC1_PICTURE_TYPE_I: + case GST_VC1_PICTURE_TYPE_BI: + if (pic->fcm == GST_VC1_FRAME_INTERLACE) { + if (!bitplane_decoding (br, bitplanes ? bitplanes->fieldtx : NULL, + seqhdr, &pic->fieldtx)) + goto failed; + } + + if (!bitplane_decoding (br, bitplanes ? bitplanes->acpred : NULL, + seqhdr, &pic->acpred)) + goto failed; + + if (entrypthdr->overlap && framehdr->pquant <= 8) { + pic->condover = decode012 (br); + + if (pic->condover == (guint8) - 1) + goto failed; + + else if (pic->condover == GST_VC1_CONDOVER_SELECT) { + if (!bitplane_decoding (br, bitplanes ? bitplanes->overflags : NULL, + seqhdr, &pic->overflags)) + goto failed; + + GST_DEBUG ("overflags %u", pic->overflags); + } + } + + framehdr->transacfrm = get_unary (br, 0, 2); + pic->transacfrm2 = get_unary (br, 0, 2); + READ_UINT8 (br, framehdr->transdctab, 1); + + if (framehdr->dquant) + parse_vopdquant (br, framehdr, framehdr->dquant); + + GST_DEBUG + ("acpred %u, condover %u, transacfrm %u, transacfrm2 %u, transdctab %u", + pic->acpred, pic->condover, framehdr->transacfrm, pic->transacfrm2, + framehdr->transdctab); + break; + + case GST_VC1_PICTURE_TYPE_B: + if (entrypthdr->extended_mv) + pic->mvrange = get_unary (br, 0, 3); + else + pic->mvrange = 0; + + if (pic->fcm != GST_VC1_FRAME_PROGRESSIVE) { + if (entrypthdr->extended_dmv) + pic->dmvrange = get_unary (br, 0, 3); + } + + if (pic->fcm == GST_VC1_FRAME_INTERLACE) + READ_UINT8 (br, pic->intcomp, 1); + else + READ_UINT8 (br, pic->mvmode, 1); + + if (pic->fcm == GST_VC1_FIELD_INTERLACE) { + + if (!bitplane_decoding (br, bitplanes ? bitplanes->forwardmb : NULL, + seqhdr, &pic->forwardmb)) + goto failed; + + } else { + if (!bitplane_decoding (br, bitplanes ? bitplanes->directmb : NULL, + seqhdr, &pic->directmb)) + goto failed; + + if (!bitplane_decoding (br, bitplanes ? bitplanes->skipmb : NULL, + seqhdr, &pic->skipmb)) + goto failed; + } + + if (pic->fcm != GST_VC1_FRAME_PROGRESSIVE) { + if (gst_bit_reader_get_remaining (br) < 7) + goto failed; + + pic->mbmodetab = gst_bit_reader_get_bits_uint8_unchecked (br, 2); + pic->imvtab = gst_bit_reader_get_bits_uint8_unchecked (br, 2); + pic->icbptab = gst_bit_reader_get_bits_uint8_unchecked (br, 3); + + if (pic->fcm == GST_VC1_FRAME_INTERLACE) + READ_UINT8 (br, pic->mvbptab2, 2); + + if (pic->fcm == GST_VC1_FRAME_INTERLACE || + (pic->fcm == GST_VC1_FIELD_INTERLACE + && pic->mvmode == GST_VC1_MVMODE_MIXED_MV)) + READ_UINT8 (br, pic->mvbptab4, 2); + + } else { + READ_UINT8 (br, pic->mvtab, 2); + READ_UINT8 (br, pic->cbptab, 2); + } + + if (framehdr->dquant) { + parse_vopdquant (br, framehdr, framehdr->dquant); + } + + if (entrypthdr->vstransform) { + READ_UINT8 (br, pic->ttmbf, 1); + + if (pic->ttmbf) { + READ_UINT8 (br, pic->ttfrm, 2); + } + } + + framehdr->transacfrm = get_unary (br, 0, 2); + READ_UINT8 (br, framehdr->transdctab, 1); + + GST_DEBUG ("transacfrm %u transdctab %u mvmode %u mvtab %u," + "cbptab %u directmb %u skipmb %u", framehdr->transacfrm, + framehdr->transdctab, pic->mvmode, pic->mvtab, pic->cbptab, + pic->directmb, pic->skipmb); + + break; + case GST_VC1_PICTURE_TYPE_P: + if (pic->fcm == GST_VC1_FIELD_INTERLACE) { + READ_UINT8 (br, pic->numref, 1); + + if (pic->numref) + READ_UINT8 (br, pic->reffield, 1); + } + + if (entrypthdr->extended_mv) + pic->mvrange = get_unary (br, 0, 3); + else + pic->mvrange = 0; + + if (pic->fcm != GST_VC1_FRAME_PROGRESSIVE) { + if (entrypthdr->extended_dmv) + pic->dmvrange = get_unary (br, 0, 3); + } + + if (pic->fcm == GST_VC1_FRAME_INTERLACE) { + READ_UINT8 (br, pic->mvswitch4, 1); + READ_UINT8 (br, pic->intcomp, 1); + + if (pic->intcomp) { + READ_UINT8 (br, pic->lumscale, 6); + READ_UINT8 (br, pic->lumshift, 6); + } + } else { + + mvmodeidx = framehdr->pquant > 12; + pic->mvmode = vc1_mvmode_table[mvmodeidx][get_unary (br, 1, 4)]; + + if (pic->mvmode == GST_VC1_MVMODE_INTENSITY_COMP) { + pic->mvmode2 = vc1_mvmode2_table[mvmodeidx][get_unary (br, 1, 3)]; + + if (pic->fcm == GST_VC1_FIELD_INTERLACE) + pic->intcompfield = decode012 (br); + + READ_UINT8 (br, pic->lumscale, 6); + READ_UINT8 (br, pic->lumshift, 6); + GST_DEBUG ("lumscale %u lumshift %u", pic->lumscale, pic->lumshift); + + if (pic->fcm == GST_VC1_FIELD_INTERLACE && pic->intcompfield) { + READ_UINT8 (br, pic->lumscale2, 6); + READ_UINT8 (br, pic->lumshift2, 6); + } + } + + if (pic->fcm == GST_VC1_FRAME_PROGRESSIVE) { + if (pic->mvmode == GST_VC1_MVMODE_MIXED_MV || + (pic->mvmode == GST_VC1_MVMODE_INTENSITY_COMP && + pic->mvmode2 == GST_VC1_MVMODE_MIXED_MV)) { + + if (!bitplane_decoding (br, bitplanes ? bitplanes->mvtypemb : NULL, + seqhdr, &pic->mvtypemb)) + goto failed; + + GST_DEBUG ("mvtypemb %u", pic->mvtypemb); + } + } + } + + if (pic->fcm != GST_VC1_FIELD_INTERLACE) { + if (!bitplane_decoding (br, bitplanes ? bitplanes->skipmb : NULL, + seqhdr, &pic->skipmb)) + goto failed; + } + + if (pic->fcm != GST_VC1_FRAME_PROGRESSIVE) { + if (gst_bit_reader_get_remaining (br) < 7) + goto failed; + + pic->mbmodetab = gst_bit_reader_get_bits_uint8_unchecked (br, 2); + pic->imvtab = gst_bit_reader_get_bits_uint8_unchecked (br, 2); + pic->icbptab = gst_bit_reader_get_bits_uint8_unchecked (br, 3); + + if (pic->fcm != GST_VC1_FIELD_INTERLACE) { + READ_UINT8 (br, pic->mvbptab2, 2); + + if (pic->mvswitch4) + READ_UINT8 (br, pic->mvbptab4, 2); + + } else if (pic->mvmode == GST_VC1_MVMODE_MIXED_MV) + READ_UINT8 (br, pic->mvbptab4, 2); + + } else { + if (gst_bit_reader_get_remaining (br) < 4) + goto failed; + pic->mvtab = gst_bit_reader_get_bits_uint8_unchecked (br, 2); + pic->cbptab = gst_bit_reader_get_bits_uint8_unchecked (br, 2); + } + + if (framehdr->dquant) { + parse_vopdquant (br, framehdr, framehdr->dquant); + } + + if (entrypthdr->vstransform) { + READ_UINT8 (br, pic->ttmbf, 1); + + if (pic->ttmbf) { + READ_UINT8 (br, pic->ttfrm, 2); + } + } + + framehdr->transacfrm = get_unary (br, 0, 2); + READ_UINT8 (br, framehdr->transdctab, 1); + + GST_DEBUG ("transacfrm %u transdctab %u mvmode %u mvtab %u," + "cbptab %u skipmb %u", framehdr->transacfrm, framehdr->transdctab, + pic->mvmode, pic->mvtab, pic->cbptab, pic->skipmb); + + break; + + default: + goto failed; + break; + } + + return GST_VC1_PARSER_OK; + +failed: + GST_WARNING ("Failed to parse frame header"); + + return GST_VC1_PARSER_ERROR; +} + +static GstVC1ParserResult +parse_frame_header (GstBitReader * br, GstVC1FrameHdr * framehdr, + GstVC1SeqHdr * seqhdr, GstVC1BitPlanes * bitplanes) +{ + guint8 mvmodeidx, tmp; + GstVC1PicSimpleMain *pic = &framehdr->pic.simple; + GstVC1SeqStructC *structc = &seqhdr->struct_c; + + GST_DEBUG ("Parsing frame header in simple or main mode"); + + /* Set the conveninence fields */ + framehdr->profile = seqhdr->profile; + framehdr->dquant = structc->dquant; + + framehdr->interpfrm = 0; + if (structc->finterpflag) + READ_UINT8 (br, framehdr->interpfrm, 1); + + READ_UINT8 (br, pic->frmcnt, 2); + + pic->rangeredfrm = 0; + if (structc->rangered) { + READ_UINT8 (br, pic->rangeredfrm, 1); + } + + /* Figuring out the picture type */ + READ_UINT8 (br, tmp, 1); + framehdr->ptype = tmp; + + if (structc->maxbframes) { + if (!framehdr->ptype) { + READ_UINT8 (br, tmp, 1); + + if (tmp) + framehdr->ptype = GST_VC1_PICTURE_TYPE_I; + else + framehdr->ptype = GST_VC1_PICTURE_TYPE_B; + + } else + framehdr->ptype = GST_VC1_PICTURE_TYPE_P; + + } else { + if (framehdr->ptype) + framehdr->ptype = GST_VC1_PICTURE_TYPE_P; + else + framehdr->ptype = GST_VC1_PICTURE_TYPE_I; + } + + + if (framehdr->ptype == GST_VC1_PICTURE_TYPE_B) { + guint bfraction; + if (!decode_vlc (br, &bfraction, vc1_bfraction_vlc_table, + G_N_ELEMENTS (vc1_bfraction_vlc_table))) + goto failed; + + pic->bfraction = bfraction; + GST_DEBUG ("bfraction %d", pic->bfraction); + + if (pic->bfraction == GST_VC1_BFRACTION_PTYPE_BI) { + framehdr->ptype = GST_VC1_PICTURE_TYPE_BI; + } + } + + if (framehdr->ptype == GST_VC1_PICTURE_TYPE_I || + framehdr->ptype == GST_VC1_PICTURE_TYPE_BI) + READ_UINT8 (br, pic->bf, 7); + + READ_UINT8 (br, framehdr->pqindex, 5); + if (!framehdr->pqindex) + return GST_VC1_PARSER_ERROR; + + GST_DEBUG ("pqindex %u", framehdr->pqindex); + + /* compute pquant */ + if (structc->quantizer == GST_VC1_QUANTIZER_IMPLICITLY) + framehdr->pquant = vc1_pquant_table[0][framehdr->pqindex]; + else + framehdr->pquant = vc1_pquant_table[1][framehdr->pqindex]; + + GST_DEBUG ("pquant %u", framehdr->pquant); + + if (framehdr->pqindex <= 8) + READ_UINT8 (br, framehdr->halfqp, 1); + else + framehdr->halfqp = 0; + + /* Set pquantizer */ + framehdr->pquantizer = 1; + if (structc->quantizer == GST_VC1_QUANTIZER_IMPLICITLY) + framehdr->pquantizer = framehdr->pqindex < 9; + else if (structc->quantizer == GST_VC1_QUANTIZER_NON_UNIFORM) + framehdr->pquantizer = 0; + + if (structc->quantizer == GST_VC1_QUANTIZER_EXPLICITLY) + READ_UINT8 (br, framehdr->pquantizer, 1); + + if (structc->extended_mv == 1) { + pic->mvrange = get_unary (br, 0, 3); + GST_DEBUG ("mvrange %u", pic->mvrange); + } + + if (structc->multires && (framehdr->ptype == GST_VC1_PICTURE_TYPE_P || + framehdr->ptype == GST_VC1_PICTURE_TYPE_I)) { + READ_UINT8 (br, pic->respic, 2); + GST_DEBUG ("Respic %u", pic->respic); + } + + GST_DEBUG ("Parsing %u Frame, pquantizer %u, halfqp %u, rangeredfrm %u, " + "interpfrm %u", framehdr->ptype, framehdr->pquantizer, framehdr->halfqp, + pic->rangeredfrm, framehdr->interpfrm); + + switch (framehdr->ptype) { + case GST_VC1_PICTURE_TYPE_I: + case GST_VC1_PICTURE_TYPE_BI: + framehdr->transacfrm = get_unary (br, 0, 2); + pic->transacfrm2 = get_unary (br, 0, 2); + READ_UINT8 (br, framehdr->transdctab, 1); + + GST_DEBUG ("transacfrm %u, transacfrm2 %u, transdctab %u", + framehdr->transacfrm, pic->transacfrm2, framehdr->transdctab); + break; + + case GST_VC1_PICTURE_TYPE_P: + mvmodeidx = framehdr->pquant > 12; + pic->mvmode = vc1_mvmode_table[mvmodeidx][get_unary (br, 1, 4)]; + + if (pic->mvmode == GST_VC1_MVMODE_INTENSITY_COMP) { + pic->mvmode2 = vc1_mvmode2_table[mvmodeidx][get_unary (br, 1, 3)]; + READ_UINT8 (br, pic->lumscale, 6); + READ_UINT8 (br, pic->lumshift, 6); + GST_DEBUG ("lumscale %u lumshift %u", pic->lumscale, pic->lumshift); + } + + if (pic->mvmode == GST_VC1_MVMODE_MIXED_MV || + (pic->mvmode == GST_VC1_MVMODE_INTENSITY_COMP && + pic->mvmode2 == GST_VC1_MVMODE_MIXED_MV)) { + if (!bitplane_decoding (br, bitplanes ? bitplanes->mvtypemb : NULL, + seqhdr, &pic->mvtypemb)) + goto failed; + GST_DEBUG ("mvtypemb %u", pic->mvtypemb); + } + if (!bitplane_decoding (br, bitplanes ? bitplanes->skipmb : NULL, + seqhdr, &pic->skipmb)) + goto failed; + + READ_UINT8 (br, pic->mvtab, 2); + READ_UINT8 (br, pic->cbptab, 2); + + if (framehdr->dquant) { + parse_vopdquant (br, framehdr, framehdr->dquant); + } + + if (structc->vstransform) { + READ_UINT8 (br, pic->ttmbf, 1); + GST_DEBUG ("ttmbf %u", pic->ttmbf); + + if (pic->ttmbf) { + READ_UINT8 (br, pic->ttfrm, 2); + GST_DEBUG ("ttfrm %u", pic->ttfrm); + } + } + + framehdr->transacfrm = get_unary (br, 0, 2); + READ_UINT8 (br, framehdr->transdctab, 1); + + GST_DEBUG ("transacfrm %u transdctab %u mvmode %u mvtab %u," + "cbptab %u skipmb %u", framehdr->transacfrm, framehdr->transdctab, + pic->mvmode, pic->mvtab, pic->cbptab, pic->skipmb); + break; + + case GST_VC1_PICTURE_TYPE_B: + READ_UINT8 (br, pic->mvmode, 1); + if (!bitplane_decoding (br, bitplanes ? bitplanes->directmb : NULL, + seqhdr, &pic->directmb)) + goto failed; + + if (!bitplane_decoding (br, bitplanes ? bitplanes->skipmb : NULL, + seqhdr, &pic->skipmb)) + goto failed; + + READ_UINT8 (br, pic->mvtab, 2); + READ_UINT8 (br, pic->cbptab, 2); + + if (framehdr->dquant) + parse_vopdquant (br, framehdr, framehdr->dquant); + + if (structc->vstransform) { + READ_UINT8 (br, pic->ttmbf, 1); + + if (pic->ttmbf) { + READ_UINT8 (br, pic->ttfrm, 2); + } + } + + framehdr->transacfrm = get_unary (br, 0, 2); + READ_UINT8 (br, framehdr->transdctab, 1); + + GST_DEBUG ("transacfrm %u transdctab %u mvmode %u mvtab %u," + "cbptab %u directmb %u skipmb %u", framehdr->transacfrm, + framehdr->transdctab, pic->mvmode, pic->mvtab, pic->cbptab, + pic->directmb, pic->skipmb); + + break; + + default: + goto failed; + break; + } + + return GST_VC1_PARSER_OK; + +failed: + GST_WARNING ("Failed to parse Simple picture header"); + + return GST_VC1_PARSER_ERROR; +} + +static GstVC1ParserResult +parse_sequence_header_struct_a (GstBitReader * br, GstVC1SeqStructA * structa) +{ + if (gst_bit_reader_get_remaining (br) < 64) { + GST_WARNING ("Failed to parse struct A"); + + return GST_VC1_PARSER_ERROR; + } + + structa->vert_size = gst_bit_reader_get_bits_uint32_unchecked (br, 32); + structa->horiz_size = gst_bit_reader_get_bits_uint32_unchecked (br, 32); + + return GST_VC1_PARSER_OK; +} + +static GstVC1ParserResult +parse_sequence_header_struct_b (GstBitReader * br, GstVC1SeqStructB * structb) +{ + if (gst_bit_reader_get_remaining (br) < 96) { + GST_WARNING ("Failed to parse sequence header"); + + return GST_VC1_PARSER_ERROR; + } + + structb->level = gst_bit_reader_get_bits_uint8_unchecked (br, 3); + structb->cbr = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + + /* res4 */ + gst_bit_reader_skip_unchecked (br, 4); + + structb->hrd_buffer = gst_bit_reader_get_bits_uint32_unchecked (br, 24); + structb->hrd_rate = gst_bit_reader_get_bits_uint32_unchecked (br, 32); + structb->framerate = gst_bit_reader_get_bits_uint32_unchecked (br, 32); + + return GST_VC1_PARSER_OK; +} + +static GstVC1ParserResult +parse_sequence_header_struct_c (GstBitReader * br, GstVC1SeqStructC * structc) +{ + guint8 old_interlaced_mode, tmp; + + READ_UINT8 (br, tmp, 2); + structc->profile = tmp; + + if (structc->profile == GST_VC1_PROFILE_ADVANCED) + return GST_VC1_PARSER_OK; + + GST_DEBUG ("Parsing sequence header in simple or main mode"); + + if (gst_bit_reader_get_remaining (br) < 29) + goto failed; + + /* Reserved bits */ + old_interlaced_mode = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + if (old_interlaced_mode) + GST_WARNING ("Old interlaced mode used"); + + structc->wmvp = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + if (structc->wmvp) + GST_DEBUG ("WMVP mode"); + + structc->frmrtq_postproc = gst_bit_reader_get_bits_uint8_unchecked (br, 3); + structc->bitrtq_postproc = gst_bit_reader_get_bits_uint8_unchecked (br, 5); + structc->loop_filter = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + + calculate_framerate_bitrate (structc->frmrtq_postproc, + structc->bitrtq_postproc, &structc->framerate, &structc->bitrate); + + /* Skipping reserved3 bit */ + gst_bit_reader_skip_unchecked (br, 1); + + structc->multires = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + + /* Skipping reserved4 bit */ + gst_bit_reader_skip_unchecked (br, 1); + + structc->fastuvmc = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + structc->extended_mv = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + structc->dquant = gst_bit_reader_get_bits_uint8_unchecked (br, 2); + structc->vstransform = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + + /* Skipping reserved5 bit */ + gst_bit_reader_skip_unchecked (br, 1); + + structc->overlap = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + structc->syncmarker = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + structc->rangered = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + structc->maxbframes = gst_bit_reader_get_bits_uint8_unchecked (br, 3); + structc->quantizer = gst_bit_reader_get_bits_uint8_unchecked (br, 2); + structc->finterpflag = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + + GST_DEBUG ("frmrtq_postproc %u, bitrtq_postproc %u, loop_filter %u, " + "multires %u, fastuvmc %u, extended_mv %u, dquant %u, vstransform %u, " + "overlap %u, syncmarker %u, rangered %u, maxbframes %u, quantizer %u, " + "finterpflag %u", structc->frmrtq_postproc, structc->bitrtq_postproc, + structc->loop_filter, structc->multires, structc->fastuvmc, + structc->extended_mv, structc->dquant, structc->vstransform, + structc->overlap, structc->syncmarker, structc->rangered, + structc->maxbframes, structc->quantizer, structc->finterpflag); + + if (structc->wmvp) { + if (gst_bit_reader_get_remaining (br) < 29) + goto failed; + + structc->coded_width = gst_bit_reader_get_bits_uint16_unchecked (br, 11); + structc->coded_height = gst_bit_reader_get_bits_uint16_unchecked (br, 11); + structc->framerate = gst_bit_reader_get_bits_uint8_unchecked (br, 5); + gst_bit_reader_skip_unchecked (br, 1); + structc->slice_code = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + + GST_DEBUG ("coded_width %u, coded_height %u, framerate %u slice_code %u", + structc->coded_width, structc->coded_height, structc->framerate, + structc->slice_code); + } + + return GST_VC1_PARSER_OK; + +failed: + GST_WARNING ("Failed to struct C"); + + return GST_VC1_PARSER_ERROR; +} + +/**** API ****/ +/** + * gst_vc1_identify_next_bdu: + * @data: The data to parse + * @size: the size of @data + * @bdu: (out): The #GstVC1BDU where to store parsed bdu headers + * + * Parses @data and fills @bdu fields + * + * Returns: a #GstVC1ParserResult + */ +GstVC1ParserResult +gst_vc1_identify_next_bdu (const guint8 * data, gsize size, GstVC1BDU * bdu) +{ + gint off1, off2; + + g_return_val_if_fail (bdu != NULL, GST_VC1_PARSER_ERROR); + + if (size < 4) { + GST_DEBUG ("Can't parse, buffer has too small size %" G_GSSIZE_FORMAT, + size); + return GST_VC1_PARSER_ERROR; + } + + off1 = scan_for_start_codes (data, size); + + if (off1 < 0) { + GST_DEBUG ("No start code prefix in this buffer"); + return GST_VC1_PARSER_NO_BDU; + } + + bdu->sc_offset = off1; + + bdu->offset = off1 + 4; + bdu->data = (guint8 *) data; + bdu->type = (GstVC1StartCode) (data[bdu->offset - 1]); + + if (bdu->type == GST_VC1_END_OF_SEQ) { + GST_DEBUG ("End-of-Seq BDU found"); + bdu->size = 0; + return GST_VC1_PARSER_OK; + } + + off2 = scan_for_start_codes (data + bdu->offset, size - bdu->offset); + if (off2 < 0) { + GST_DEBUG ("Bdu start %d, No end found", bdu->offset); + + return GST_VC1_PARSER_NO_BDU_END; + } + + if (off2 > 0 && data[bdu->offset + off2 - 1] == 00) + off2--; + + bdu->size = off2; + + GST_DEBUG ("Complete bdu found. Off: %d, Size: %d", bdu->offset, bdu->size); + return GST_VC1_PARSER_OK; +} + +/** + * gst_vc1_parse_sequence_layer: + * @data: The data to parse + * @size: the size of @data + * @structa: The #GstVC1SeqLayer to set. + * + * Parses @data, and fills @seqlayer fields. + * + * Returns: a #GstVC1ParserResult + */ +GstVC1ParserResult +gst_vc1_parse_sequence_layer (const guint8 * data, gsize size, + GstVC1SeqLayer * seqlayer) +{ + guint32 tmp; + GstBitReader br = GST_BIT_READER_INIT (data, size); + + g_return_val_if_fail (seqlayer != NULL, GST_VC1_PARSER_ERROR); + + READ_UINT32 (&br, tmp, 8); + if (tmp != 0xC5) + goto failed; + + READ_UINT32 (&br, seqlayer->numframes, 24); + + READ_UINT32 (&br, tmp, 32); + if (tmp != 0x04) + goto failed; + + if (parse_sequence_header_struct_c (&br, &seqlayer->struct_c) == + GST_VC1_PARSER_ERROR) + goto failed; + + if (parse_sequence_header_struct_a (&br, &seqlayer->struct_a) == + GST_VC1_PARSER_ERROR) + goto failed; + + READ_UINT32 (&br, tmp, 32); + if (tmp != 0x0C) + goto failed; + + if (parse_sequence_header_struct_b (&br, &seqlayer->struct_b) == + GST_VC1_PARSER_ERROR) + goto failed; + + return GST_VC1_PARSER_OK; + +failed: + GST_WARNING ("Failed to parse sequence layer"); + + return GST_VC1_PARSER_ERROR; +} + +/** + * gst_vc1_parse_sequence_header_struct_a: + * @data: The data to parse + * @size: the size of @data + * @structa: The #GstVC1SeqStructA to set. + * + * Parses @data, and fills @structa fields. + * + * Returns: a #GstVC1ParserResult + */ +GstVC1ParserResult +gst_vc1_parse_sequence_header_struct_a (const guint8 * data, + gsize size, GstVC1SeqStructA * structa) +{ + GstBitReader br = GST_BIT_READER_INIT (data, size); + + g_return_val_if_fail (structa != NULL, GST_VC1_PARSER_ERROR); + + return parse_sequence_header_struct_a (&br, structa); +} + +/** + * gst_vc1_parse_sequence_header_struct_b: + * @data: The data to parse + * @size: the size of @data + * @structa: The #GstVC1SeqStructB to set. + * + * Parses @data, and fills @structb fields. + * + * Returns: a #GstVC1ParserResult + */ +GstVC1ParserResult +gst_vc1_parse_sequence_header_struct_b (const guint8 * data, + gsize size, GstVC1SeqStructB * structb) +{ + GstBitReader br = GST_BIT_READER_INIT (data, size); + + g_return_val_if_fail (structb != NULL, GST_VC1_PARSER_ERROR); + + return parse_sequence_header_struct_b (&br, structb); +} + +/** + * gst_vc1_parse_sequence_header_struct_c: + * @data: The data to parse + * @size: the size of @data + * @structc: The #GstVC1SeqStructC to set. + * + * Parses @data, and fills @structc fields. + * + * Returns: a #GstVC1ParserResult + */ +GstVC1ParserResult +gst_vc1_parse_sequence_header_struct_c (const guint8 * data, gsize size, + GstVC1SeqStructC * structc) +{ + GstBitReader br = GST_BIT_READER_INIT (data, size); + + g_return_val_if_fail (structc != NULL, GST_VC1_PARSER_ERROR); + + return parse_sequence_header_struct_c (&br, structc); +} + +/** +* gst_vc1_parse_sequence_header: +* @data: The data to parse +* @size: the size of @data +* @seqhdr: The #GstVC1SeqHdr to set. + * + * Parses @data, and fills @seqhdr fields. + * + * Returns: a #GstVC1ParserResult + */ +GstVC1ParserResult +gst_vc1_parse_sequence_header (const guint8 * data, gsize size, + GstVC1SeqHdr * seqhdr) +{ + GstBitReader br = GST_BIT_READER_INIT (data, size); + + g_return_val_if_fail (seqhdr != NULL, GST_VC1_PARSER_ERROR); + + if (parse_sequence_header_struct_c (&br, &seqhdr->struct_c) == + GST_VC1_PARSER_ERROR) + goto failed; + + /* Convenience field */ + seqhdr->profile = seqhdr->struct_c.profile; + + if (seqhdr->profile == GST_VC1_PROFILE_ADVANCED) + return parse_sequence_header_advanced (seqhdr, &br); + + /* Compute MB height and width */ + calculate_mb_size (seqhdr, seqhdr->struct_c.coded_width, + seqhdr->struct_c.coded_height); + + return GST_VC1_PARSER_OK; + +failed: + GST_WARNING ("Failed to parse sequence header"); + + return GST_VC1_PARSER_ERROR; +} + +/** + * gst_vc1_parse_entry_point_header: + * @data: The data to parse + * @size: the size of @data + * @entrypoint: (out): The #GstVC1EntryPointHdr to set. + * @seqhdr: The #GstVC1SeqHdr currently being parsed + * + * Parses @data, and sets @entrypoint fields. + * + * Returns: a #GstVC1EntryPointHdr + */ +GstVC1ParserResult +gst_vc1_parse_entry_point_header (const guint8 * data, gsize size, + GstVC1EntryPointHdr * entrypoint, GstVC1SeqHdr * seqhdr) +{ + GstBitReader br; + guint8 i; + GstVC1AdvancedSeqHdr *advanced = &seqhdr->advanced; + + g_return_val_if_fail (entrypoint != NULL, GST_VC1_PARSER_ERROR); + + gst_bit_reader_init (&br, data, size); + + if (gst_bit_reader_get_remaining (&br) < 13) + goto failed; + + entrypoint->broken_link = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + entrypoint->closed_entry = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + entrypoint->panscan_flag = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + entrypoint->refdist_flag = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + entrypoint->loopfilter = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + entrypoint->fastuvmc = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + entrypoint->extended_mv = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + entrypoint->dquant = gst_bit_reader_get_bits_uint8_unchecked (&br, 2); + entrypoint->vstransform = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + entrypoint->overlap = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + entrypoint->quantizer = gst_bit_reader_get_bits_uint8_unchecked (&br, 2); + + if (advanced->hrd_param_flag) { + if (seqhdr->advanced.hrd_param.hrd_num_leaky_buckets > + MAX_HRD_NUM_LEAKY_BUCKETS) { + GST_WARNING + ("hrd_num_leaky_buckets (%d) > MAX_HRD_NUM_LEAKY_BUCKETS (%d)", + seqhdr->advanced.hrd_param.hrd_num_leaky_buckets, + MAX_HRD_NUM_LEAKY_BUCKETS); + goto failed; + } + for (i = 0; i < seqhdr->advanced.hrd_param.hrd_num_leaky_buckets; i++) + READ_UINT8 (&br, entrypoint->hrd_full[i], 8); + } + + READ_UINT8 (&br, entrypoint->coded_size_flag, 1); + if (entrypoint->coded_size_flag) { + READ_UINT16 (&br, entrypoint->coded_width, 12); + READ_UINT16 (&br, entrypoint->coded_height, 12); + entrypoint->coded_height = (entrypoint->coded_height + 1) << 1; + entrypoint->coded_width = (entrypoint->coded_width + 1) << 1; + calculate_mb_size (seqhdr, entrypoint->coded_width, + entrypoint->coded_height); + } + + if (entrypoint->extended_mv) + READ_UINT8 (&br, entrypoint->extended_dmv, 1); + + READ_UINT8 (&br, entrypoint->range_mapy_flag, 1); + if (entrypoint->range_mapy_flag) + READ_UINT8 (&br, entrypoint->range_mapy, 3); + + READ_UINT8 (&br, entrypoint->range_mapuv_flag, 1); + if (entrypoint->range_mapy_flag) + READ_UINT8 (&br, entrypoint->range_mapuv, 3); + + advanced->entrypoint = *entrypoint; + + return GST_VC1_PARSER_OK; + +failed: + GST_WARNING ("Failed to parse entry point header"); + + return GST_VC1_PARSER_ERROR; +} + +/** + * gst_vc1_parse_frame_layer: + * @data: The data to parse + * @size: the size of @data + * @framelayer: The #GstVC1FrameLayer to fill. + * + * Parses @data, and fills @framelayer fields. + * + * Returns: a #GstVC1ParserResult + */ +GstVC1ParserResult +gst_vc1_parse_frame_layer (const guint8 * data, gsize size, + GstVC1FrameLayer * framelayer) +{ + GstBitReader br = GST_BIT_READER_INIT (data, size); + + if (gst_bit_reader_get_remaining (&br) < 64) { + GST_WARNING ("Could not parse frame layer"); + + return GST_VC1_PARSER_ERROR; + } + + /* set default values */ + framelayer->skiped_p_frame = 0; + + framelayer->key = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + gst_bit_reader_skip_unchecked (&br, 7); + + framelayer->framesize = gst_bit_reader_get_bits_uint32_unchecked (&br, 24); + + if (framelayer->framesize == 0 || framelayer->framesize == 1) + framelayer->skiped_p_frame = 1; + + /* compute next_framelayer_offset */ + framelayer->next_framelayer_offset = framelayer->framesize + 8; + + framelayer->timestamp = gst_bit_reader_get_bits_uint32_unchecked (&br, 32); + + return GST_VC1_PARSER_OK; +} + +/** + * gst_vc1_parse_frame_header: + * @data: The data to parse + * @size: the size of @data + * @framehdr: The #GstVC1FrameHdr to fill. + * @seqhdr: The #GstVC1SeqHdr currently being parsed + * @bitplanes: The #GstVC1BitPlanes to store bitplanes in or %NULL + * + * Parses @data, and fills @entrypoint fields. + * + * Returns: a #GstVC1ParserResult + */ +GstVC1ParserResult +gst_vc1_parse_frame_header (const guint8 * data, gsize size, + GstVC1FrameHdr * framehdr, GstVC1SeqHdr * seqhdr, + GstVC1BitPlanes * bitplanes) +{ + GstBitReader br; + GstVC1ParserResult result; + + gst_bit_reader_init (&br, data, size); + + if (seqhdr->profile == GST_VC1_PROFILE_ADVANCED) + result = parse_frame_header_advanced (&br, framehdr, seqhdr, bitplanes, + FALSE); + else + result = parse_frame_header (&br, framehdr, seqhdr, bitplanes); + + framehdr->header_size = gst_bit_reader_get_pos (&br); + return result; +} + +/** + * gst_vc1_parse_field_header: + * @data: The data to parse + * @size: the size of @data + * @fieldhdr: The #GstVC1FrameHdr to fill. + * @seqhdr: The #GstVC1SeqHdr currently being parsed + * @bitplanes: The #GstVC1BitPlanes to store bitplanes in or %NULL + * + * Parses @data, and fills @fieldhdr fields. + * + * Returns: a #GstVC1ParserResult + */ +GstVC1ParserResult +gst_vc1_parse_field_header (const guint8 * data, gsize size, + GstVC1FrameHdr * fieldhdr, GstVC1SeqHdr * seqhdr, + GstVC1BitPlanes * bitplanes) +{ + GstBitReader br; + GstVC1ParserResult result; + + gst_bit_reader_init (&br, data, size); + + result = parse_frame_header_advanced (&br, fieldhdr, seqhdr, bitplanes, TRUE); + + return result; +} + +/** + * gst_vc1_bitplanes_new: + * @seqhdr: The #GstVC1SeqHdr from which to set @bitplanes + * + * Creates a new #GstVC1BitPlanes. It should be freed with + * gst_vc1_bitplanes_free() after use. + * + * Returns: a new #GstVC1BitPlanes + */ +GstVC1BitPlanes * +gst_vc1_bitplanes_new (void) +{ + return g_slice_new0 (GstVC1BitPlanes); +} + +/** + * gst_vc1_bitplane_free: + * @bitplanes: the #GstVC1BitPlanes to free + * + * Frees @bitplanes. + */ +void +gst_vc1_bitplanes_free (GstVC1BitPlanes * bitplanes) +{ + gst_vc1_bitplanes_free_1 (bitplanes); + g_slice_free (GstVC1BitPlanes, bitplanes); +} + +/** + * gst_vc1_bitplane_free_1: + * @bitplanes: The #GstVC1BitPlanes to free + * + * Frees @bitplanes fields. + */ +void +gst_vc1_bitplanes_free_1 (GstVC1BitPlanes * bitplanes) +{ + g_free (bitplanes->acpred); + g_free (bitplanes->fieldtx); + g_free (bitplanes->overflags); + g_free (bitplanes->mvtypemb); + g_free (bitplanes->skipmb); + g_free (bitplanes->directmb); + g_free (bitplanes->forwardmb); +} + +/** + * gst_vc1_bitplanes_ensure_size: + * @bitplanes: The #GstVC1BitPlanes to reset + * @seqhdr: The #GstVC1SeqHdr from which to set @bitplanes + * + * Fills the @bitplanes structure from @seqhdr, this function + * should be called after #gst_vc1_parse_sequence_header if + * in simple or main mode, or after #gst_vc1_parse_entry_point_header + * if in advanced mode. + * + * Returns: %TRUE if everything went fine, %FALSE otherwize + */ +gboolean +gst_vc1_bitplanes_ensure_size (GstVC1BitPlanes * bitplanes, + GstVC1SeqHdr * seqhdr) +{ + g_return_val_if_fail (bitplanes != NULL, FALSE); + g_return_val_if_fail (seqhdr != NULL, FALSE); + + if (bitplanes->size) { + bitplanes->size = seqhdr->mb_height * seqhdr->mb_stride; + bitplanes->acpred = + g_realloc_n (bitplanes->acpred, bitplanes->size, sizeof (guint8)); + bitplanes->fieldtx = + g_realloc_n (bitplanes->fieldtx, bitplanes->size, sizeof (guint8)); + bitplanes->overflags = + g_realloc_n (bitplanes->overflags, bitplanes->size, sizeof (guint8)); + bitplanes->mvtypemb = + g_realloc_n (bitplanes->mvtypemb, bitplanes->size, sizeof (guint8)); + bitplanes->skipmb = + g_realloc_n (bitplanes->skipmb, bitplanes->size, sizeof (guint8)); + bitplanes->directmb = + g_realloc_n (bitplanes->directmb, bitplanes->size, sizeof (guint8)); + bitplanes->forwardmb = + g_realloc_n (bitplanes->forwardmb, bitplanes->size, sizeof (guint8)); + } else { + bitplanes->size = seqhdr->mb_height * seqhdr->mb_stride; + bitplanes->acpred = g_malloc0 (bitplanes->size * sizeof (guint8)); + bitplanes->fieldtx = g_malloc0 (bitplanes->size * sizeof (guint8)); + bitplanes->overflags = g_malloc0 (bitplanes->size * sizeof (guint8)); + bitplanes->mvtypemb = g_malloc0 (bitplanes->size * sizeof (guint8)); + bitplanes->skipmb = g_malloc0 (bitplanes->size * sizeof (guint8)); + bitplanes->directmb = g_malloc0 (bitplanes->size * sizeof (guint8)); + bitplanes->forwardmb = g_malloc0 (bitplanes->size * sizeof (guint8)); + } + + return TRUE; +} diff --git a/ext/codecparsers/gst-libs/gst/codecparsers/gstvc1parser.h b/ext/codecparsers/gst-libs/gst/codecparsers/gstvc1parser.h new file mode 100644 index 0000000..c137cb6 --- /dev/null +++ b/ext/codecparsers/gst-libs/gst/codecparsers/gstvc1parser.h @@ -0,0 +1,622 @@ +/* Gstreamer + * Copyright (C) <2011> Intel + * Copyright (C) <2011> Collabora Ltd. + * Copyright (C) <2011> Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_VC1_PARSER_H__ +#define __GST_VC1_PARSER_H__ + +#ifndef GST_USE_UNSTABLE_API +#warning "The VC1 parsing library is unstable API and may change in future." +#warning "You can define GST_USE_UNSTABLE_API to avoid this warning." +#endif + +#include + +G_BEGIN_DECLS + +#define MAX_HRD_NUM_LEAKY_BUCKETS 31 + +/** + * @GST_VC1_BFRACTION_BASIS: The @bfraction variable should be divided + * by this constant to have the actual value. + */ +#define GST_VC1_BFRACTION_BASIS 840 + +#define GST_VC1_BFRACTION_RESERVED (GST_VC1_BFRACTION_BASIS + 1) +#define GST_VC1_BFRACTION_PTYPE_BI (GST_VC1_BFRACTION_BASIS + 2) + +typedef enum { + GST_VC1_END_OF_SEQ = 0x0A, + GST_VC1_SLICE = 0x0B, + GST_VC1_FIELD = 0x0C, + GST_VC1_FRAME = 0x0D, + GST_VC1_ENTRYPOINT = 0x0E, + GST_VC1_SEQUENCE = 0x0F, + GST_VC1_SLICE_USER = 0x1B, + GST_VC1_FIELD_USER = 0x1C, + GST_VC1_FRAME_USER = 0x1D, + GST_VC1_ENTRY_POINT_USER = 0x1E, + GST_VC1_SEQUENCE_USER = 0x1F +} GstVC1StartCode; + +typedef enum { + GST_VC1_PROFILE_SIMPLE, + GST_VC1_PROFILE_MAIN, + GST_VC1_PROFILE_RESERVED, + GST_VC1_PROFILE_ADVANCED +} GstVC1Profile; + +typedef enum { + GST_VC1_PARSER_OK, + GST_VC1_PARSER_BROKEN_DATA, + GST_VC1_PARSER_NO_BDU, + GST_VC1_PARSER_NO_BDU_END, + GST_VC1_PARSER_ERROR, +} GstVC1ParserResult; + +typedef enum +{ + GST_VC1_PICTURE_TYPE_P, + GST_VC1_PICTURE_TYPE_B, + GST_VC1_PICTURE_TYPE_I, + GST_VC1_PICTURE_TYPE_BI, + GST_VC1_PICTURE_TYPE_SKIPPED +} GstVC1PictureType; + +typedef enum +{ + GST_VC1_LEVEL_LOW = 0, /* Simple/Main profile low level */ + GST_VC1_LEVEL_MEDIUM = 1, /* Simple/Main profile medium level */ + GST_VC1_LEVEL_HIGH = 2, /* Main profile high level */ + + GST_VC1_LEVEL_L0 = 0, /* Advanced profile level 0 */ + GST_VC1_LEVEL_L1 = 1, /* Advanced profile level 1 */ + GST_VC1_LEVEL_L2 = 2, /* Advanced profile level 2 */ + GST_VC1_LEVEL_L3 = 3, /* Advanced profile level 3 */ + GST_VC1_LEVEL_L4 = 4, /* Advanced profile level 4 */ + + /* 5 to 7 reserved */ + GST_VC1_LEVEL_UNKNOWN = 255 /* Unknown profile */ +} GstVC1Level; + +typedef enum +{ + GST_VC1_QUANTIZER_IMPLICITLY, + GST_VC1_QUANTIZER_EXPLICITLY, + GST_VC1_QUANTIZER_NON_UNIFORM, + GST_VC1_QUANTIZER_UNIFORM +} GstVC1QuantizerSpec; + +typedef enum { + GST_VC1_DQPROFILE_FOUR_EDGES, + GST_VC1_DQPROFILE_DOUBLE_EDGES, + GST_VC1_DQPROFILE_SINGLE_EDGE, + GST_VC1_DQPROFILE_ALL_MBS +} GstVC1DQProfile; + +typedef enum { + GST_VC1_CONDOVER_NONE, + GST_VC1_CONDOVER_ALL, + GST_VC1_CONDOVER_SELECT +} GstVC1Condover; + +/** + * GstVC1MvMode: + * + */ +typedef enum +{ + GST_VC1_MVMODE_1MV_HPEL_BILINEAR, + GST_VC1_MVMODE_1MV, + GST_VC1_MVMODE_1MV_HPEL, + GST_VC1_MVMODE_MIXED_MV, + GST_VC1_MVMODE_INTENSITY_COMP +} GstVC1MvMode; + +typedef enum +{ + GST_VC1_FRAME_PROGRESSIVE = 0x0, + GST_VC1_FRAME_INTERLACE = 0x10, + GST_VC1_FIELD_INTERLACE = 0x11 +} GstVC1FrameCodingMode; + +typedef struct _GstVC1SeqHdr GstVC1SeqHdr; +typedef struct _GstVC1AdvancedSeqHdr GstVC1AdvancedSeqHdr; +typedef struct _GstVC1HrdParam GstVC1HrdParam; +typedef struct _GstVC1EntryPointHdr GstVC1EntryPointHdr; + +typedef struct _GstVC1SeqLayer GstVC1SeqLayer; + +typedef struct _GstVC1SeqStructA GstVC1SeqStructA; +typedef struct _GstVC1SeqStructB GstVC1SeqStructB; +typedef struct _GstVC1SeqStructC GstVC1SeqStructC; + +/* Pictures Structures */ +typedef struct _GstVC1FrameLayer GstVC1FrameLayer; +typedef struct _GstVC1FrameHdr GstVC1FrameHdr; +typedef struct _GstVC1PicAdvanced GstVC1PicAdvanced; +typedef struct _GstVC1PicSimpleMain GstVC1PicSimpleMain; +typedef struct _GstVC1Picture GstVC1Picture; + +typedef struct _GstVC1VopDquant GstVC1VopDquant; + +typedef struct _GstVC1BitPlanes GstVC1BitPlanes; + +typedef struct _GstVC1BDU GstVC1BDU; + +struct _GstVC1HrdParam +{ + guint8 hrd_num_leaky_buckets; + guint8 bit_rate_exponent; + guint8 buffer_size_exponent; + guint16 hrd_rate[MAX_HRD_NUM_LEAKY_BUCKETS]; + guint16 hrd_buffer[MAX_HRD_NUM_LEAKY_BUCKETS]; +}; + +/** + * GstVC1EntryPointHdr: + * + * Structure for entrypoint header, this will be used only in advanced profiles + */ +struct _GstVC1EntryPointHdr +{ + guint8 broken_link; + guint8 closed_entry; + guint8 panscan_flag; + guint8 refdist_flag; + guint8 loopfilter; + guint8 fastuvmc; + guint8 extended_mv; + guint8 dquant; + guint8 vstransform; + guint8 overlap; + guint8 quantizer; + guint8 coded_size_flag; + guint16 coded_width; + guint16 coded_height; + guint8 extended_dmv; + guint8 range_mapy_flag; + guint8 range_mapy; + guint8 range_mapuv_flag; + guint8 range_mapuv; + + guint8 hrd_full[MAX_HRD_NUM_LEAKY_BUCKETS]; +}; + +/** + * GstVC1AdvancedSeqHdr: + * + * Structure for the advanced profile sequence headers specific parameters. + */ +struct _GstVC1AdvancedSeqHdr +{ + GstVC1Level level; + + guint8 frmrtq_postproc; + guint8 bitrtq_postproc; + guint8 postprocflag; + guint16 max_coded_width; + guint16 max_coded_height; + guint8 pulldown; + guint8 interlace; + guint8 tfcntrflag; + guint8 finterpflag; + guint8 psf; + guint8 display_ext; + guint16 disp_horiz_size; + guint16 disp_vert_size; + guint8 aspect_ratio_flag; + guint8 aspect_ratio; + guint8 aspect_horiz_size; + guint8 aspect_vert_size; + guint8 framerate_flag; + guint8 framerateind; + guint8 frameratenr; + guint8 frameratedr; + guint16 framerateexp; + guint8 color_format_flag; + guint8 color_prim; + guint8 transfer_char; + guint8 matrix_coef; + guint8 hrd_param_flag; + guint8 colordiff_format; + + GstVC1HrdParam hrd_param; + + /* computed */ + guint framerate; /* Around in fps, 0 if unknown*/ + guint bitrate; /* Around in kpbs, 0 if unknown*/ + guint par_n; + guint par_d; + guint fps_n; + guint fps_d; + + /* The last parsed entry point */ + GstVC1EntryPointHdr entrypoint; +}; + +struct _GstVC1SeqStructA +{ + guint32 vert_size; + guint32 horiz_size; +}; + +struct _GstVC1SeqStructB +{ + GstVC1Level level; + + guint8 cbr; + guint32 framerate; + + /* In simple and main profiles only */ + guint32 hrd_buffer; + guint32 hrd_rate; +}; + +struct _GstVC1SeqStructC +{ + GstVC1Profile profile; + + /* Only in simple and main profiles */ + guint8 frmrtq_postproc; + guint8 bitrtq_postproc; + guint8 res_sprite; + guint8 loop_filter; + guint8 multires; + guint8 fastuvmc; + guint8 extended_mv; + guint8 dquant; + guint8 vstransform; + guint8 overlap; + guint8 syncmarker; + guint8 rangered; + guint8 maxbframes; + guint8 quantizer; + guint8 finterpflag; + + /* Computed */ + guint framerate; /* Around in fps, 0 if unknown*/ + guint bitrate; /* Around in kpbs, 0 if unknown*/ + + /* This should be filled by user if previously known */ + guint16 coded_width; + /* This should be filled by user if previously known */ + guint16 coded_height; + + /* Wmvp specific */ + guint8 wmvp; /* Specify if the stream is wmp or not */ + /* In the wmvp case, the framerate is not computed but in the bistream */ + guint8 slice_code; +}; + +struct _GstVC1SeqLayer +{ + guint32 numframes; + + GstVC1SeqStructA struct_a; + GstVC1SeqStructB struct_b; + GstVC1SeqStructC struct_c; +}; + +/** + * GstVC1SeqHdr: + * + * Structure for sequence headers in any profile. + */ +struct _GstVC1SeqHdr +{ + GstVC1Profile profile; + + GstVC1SeqStructC struct_c; + + /* calculated */ + guint mb_height; + guint mb_width; + guint mb_stride; + + GstVC1AdvancedSeqHdr advanced; + +}; + +/** + * GstVC1PicSimpleMain: + * @bfaction: Should be divided by #GST_VC1_BFRACTION_BASIS + * to get the real value. + */ +struct _GstVC1PicSimpleMain +{ + guint8 frmcnt; + guint8 mvrange; + guint8 rangeredfrm; + + /* I and P pic simple and main profiles only */ + guint8 respic; + + /* I and BI pic simple and main profiles only */ + guint8 transacfrm2; + guint8 bf; + + /* B and P pic simple and main profiles only */ + guint8 mvmode; + guint8 mvtab; + guint8 ttmbf; + + /* P pic simple and main profiles only */ + guint8 mvmode2; + guint8 lumscale; + guint8 lumshift; + + guint8 cbptab; + guint8 ttfrm; + + /* B and BI picture only + * Should be divided by #GST_VC1_BFRACTION_BASIS + * to get the real value. */ + guint16 bfraction; + + /* Biplane value, those fields only mention the fact + * that the bitplane is in raw mode or not */ + guint8 mvtypemb; + guint8 skipmb; + guint8 directmb; /* B pic main profile only */ +}; + +/** + * GstVC1PicAdvanced: + * @bfaction: Should be divided by #GST_VC1_BFRACTION_BASIS + * to get the real value. + */ +struct _GstVC1PicAdvanced +{ + GstVC1FrameCodingMode fcm; + guint8 tfcntr; + + guint8 rptfrm; + guint8 tff; + guint8 rff; + guint8 ps_present; + guint32 ps_hoffset; + guint32 ps_voffset; + guint16 ps_width; + guint16 ps_height; + guint8 rndctrl; + guint8 uvsamp; + guint8 postproc; + + /* B and P picture specific */ + guint8 mvrange; + guint8 mvmode; + guint8 mvtab; + guint8 cbptab; + guint8 ttmbf; + guint8 ttfrm; + + /* B and BI picture only + * Should be divided by #GST_VC1_BFRACTION_BASIS + * to get the real value. */ + guint16 bfraction; + + /* ppic */ + guint8 mvmode2; + guint8 lumscale; + guint8 lumshift; + + /* bipic */ + guint8 bf; + guint8 condover; + guint8 transacfrm2; + + /* Biplane value, those fields only mention the fact + * that the bitplane is in raw mode or not */ + guint8 acpred; + guint8 overflags; + guint8 mvtypemb; + guint8 skipmb; + guint8 directmb; + guint8 forwardmb; /* B pic interlace field only */ + + /* For interlaced pictures only */ + guint8 fieldtx; + + /* P and B pictures */ + guint8 intcomp; + guint8 dmvrange; + guint8 mbmodetab; + guint8 imvtab; + guint8 icbptab; + guint8 mvbptab2; + guint8 mvbptab4; /* If 4mvswitch in ppic */ + + /* P picture */ + guint8 mvswitch4; + + /* For interlaced fields only */ + guint16 refdist; + guint8 fptype; /* Raw value */ + + /* P pic */ + guint8 numref; + guint8 reffield; + guint8 lumscale2; + guint8 lumshift2; + guint8 intcompfield; + +}; + +struct _GstVC1BitPlanes +{ + guint8 *acpred; + guint8 *fieldtx; + guint8 *overflags; + guint8 *mvtypemb; + guint8 *skipmb; + guint8 *directmb; + guint8 *forwardmb; + + guint size; /* Size of the arrays */ +}; + +struct _GstVC1VopDquant +{ + guint8 pqdiff; + guint8 abspq; + + /* Computed */ + guint8 altpquant; + + /* if dqant != 2*/ + guint8 dquantfrm; + guint8 dqprofile; + + /* if dqprofile == GST_VC1_DQPROFILE_SINGLE_EDGE + * or GST_VC1_DQPROFILE_DOUBLE_EDGE:*/ + guint8 dqsbedge; + + /* if dqprofile == GST_VC1_DQPROFILE_SINGLE_EDGE + * or GST_VC1_DQPROFILE_DOUBLE_EDGE:*/ + guint8 dqbedge; + + /* if dqprofile == GST_VC1_DQPROFILE_ALL_MBS */ + guint8 dqbilevel; + +}; + +struct _GstVC1FrameLayer +{ + guint8 key; + guint32 framesize; + + guint32 timestamp; + + /* calculated */ + guint32 next_framelayer_offset; + guint8 skiped_p_frame; +}; + +/** + * GstVC1FrameHdr: + * + * Structure that represent picture in any profile or mode. + * You should look at @ptype and @profile to know what is currently + * in use. + */ +struct _GstVC1FrameHdr +{ + /* common fields */ + GstVC1PictureType ptype; + guint8 interpfrm; + guint8 halfqp; + guint8 transacfrm; + guint8 transdctab; + guint8 pqindex; + guint8 pquantizer; + + /* Computed */ + guint8 pquant; + + /* Convenience fields */ + guint8 profile; + guint8 dquant; + + /* If dquant */ + GstVC1VopDquant vopdquant; + + union { + GstVC1PicSimpleMain simple; + GstVC1PicAdvanced advanced; + } pic; + + /* Size of the picture layer in bits */ + guint header_size; +}; + +/** + * GstVC1BDU: + * + * Structure that represents a Bitstream Data Unit. + */ +struct _GstVC1BDU +{ + GstVC1StartCode type; + guint size; + guint sc_offset; + guint offset; + guint8 * data; +}; + +GstVC1ParserResult gst_vc1_identify_next_bdu (const guint8 *data, + gsize size, + GstVC1BDU *bdu); + + +GstVC1ParserResult gst_vc1_parse_sequence_header (const guint8 *data, + gsize size, + GstVC1SeqHdr * seqhdr); + +GstVC1ParserResult gst_vc1_parse_entry_point_header (const guint8 *data, + gsize size, + GstVC1EntryPointHdr * entrypoint, + GstVC1SeqHdr *seqhdr); + +GstVC1ParserResult gst_vc1_parse_sequence_layer (const guint8 *data, + gsize size, + GstVC1SeqLayer * seqlayer); + +GstVC1ParserResult +gst_vc1_parse_sequence_header_struct_a (const guint8 *data, + gsize size, + GstVC1SeqStructA *structa); +GstVC1ParserResult +gst_vc1_parse_sequence_header_struct_b (const guint8 *data, + gsize size, + GstVC1SeqStructB *structb); + +GstVC1ParserResult +gst_vc1_parse_sequence_header_struct_c (const guint8 *data, + gsize size, + GstVC1SeqStructC *structc); + +GstVC1ParserResult gst_vc1_parse_frame_layer (const guint8 *data, + gsize size, + GstVC1FrameLayer * framelayer); + +GstVC1ParserResult gst_vc1_parse_frame_header (const guint8 *data, + gsize size, + GstVC1FrameHdr * framehdr, + GstVC1SeqHdr *seqhdr, + GstVC1BitPlanes *bitplanes); + +GstVC1ParserResult gst_vc1_parse_field_header (const guint8 *data, + gsize size, + GstVC1FrameHdr * fieldhdr, + GstVC1SeqHdr *seqhdr, + GstVC1BitPlanes *bitplanes); + +GstVC1BitPlanes * gst_vc1_bitplanes_new (void); + +void gst_vc1_bitplanes_free (GstVC1BitPlanes *bitplanes); + +void gst_vc1_bitplanes_free_1 (GstVC1BitPlanes *bitplanes); + +gboolean gst_vc1_bitplanes_ensure_size (GstVC1BitPlanes *bitplanes, + GstVC1SeqHdr *seqhdr); + +G_END_DECLS +#endif diff --git a/ext/codecparsers/gst-libs/gst/codecparsers/parserutils.c b/ext/codecparsers/gst-libs/gst/codecparsers/parserutils.c new file mode 100644 index 0000000..d4a3f40 --- /dev/null +++ b/ext/codecparsers/gst-libs/gst/codecparsers/parserutils.c @@ -0,0 +1,57 @@ +/* Gstreamer + * Copyright (C) <2011> Intel Corporation + * Copyright (C) <2011> Collabora Ltd. + * Copyright (C) <2011> Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "parserutils.h" + +gboolean +decode_vlc (GstBitReader * br, guint * res, const VLCTable * table, + guint length) +{ + guint8 i; + guint cbits = 0; + guint32 value = 0; + + for (i = 0; i < length; i++) { + if (cbits != table[i].cbits) { + cbits = table[i].cbits; + if (!gst_bit_reader_peek_bits_uint32 (br, &value, cbits)) { + goto failed; + } + } + + if (value == table[i].cword) { + SKIP (br, cbits); + if (res) + *res = table[i].value; + + return TRUE; + } + } + + GST_DEBUG ("Did not find code"); + +failed: + { + GST_WARNING ("Could not decode VLC returning"); + + return FALSE; + } +} diff --git a/ext/codecparsers/gst-libs/gst/codecparsers/parserutils.h b/ext/codecparsers/gst-libs/gst/codecparsers/parserutils.h new file mode 100644 index 0000000..6b54ded --- /dev/null +++ b/ext/codecparsers/gst-libs/gst/codecparsers/parserutils.h @@ -0,0 +1,108 @@ +/* Gstreamer + * Copyright (C) <2011> Intel + * Copyright (C) <2011> Collabora Ltd. + * Copyright (C) <2011> Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __PARSER_UTILS__ +#define __PARSER_UTILS__ + +#include +#include + +/* Parsing utils */ +#define GET_BITS(b, num, bits) G_STMT_START { \ + if (!gst_bit_reader_get_bits_uint32(b, bits, num)) \ + goto failed; \ + GST_TRACE ("parsed %d bits: %d", num, *(bits)); \ +} G_STMT_END + +#define CHECK_ALLOWED(val, min, max) G_STMT_START { \ + if (val < min || val > max) { \ + GST_WARNING ("value not in allowed range. value: %d, range %d-%d", \ + val, min, max); \ + goto failed; \ + } \ +} G_STMT_END + +#define READ_UINT8(reader, val, nbits) G_STMT_START { \ + if (!gst_bit_reader_get_bits_uint8 (reader, &val, nbits)) { \ + GST_WARNING ("failed to read uint8, nbits: %d", nbits); \ + goto failed; \ + } \ +} G_STMT_END + +#define READ_UINT16(reader, val, nbits) G_STMT_START { \ + if (!gst_bit_reader_get_bits_uint16 (reader, &val, nbits)) { \ + GST_WARNING ("failed to read uint16, nbits: %d", nbits); \ + goto failed; \ + } \ +} G_STMT_END + +#define READ_UINT32(reader, val, nbits) G_STMT_START { \ + if (!gst_bit_reader_get_bits_uint32 (reader, &val, nbits)) { \ + GST_WARNING ("failed to read uint32, nbits: %d", nbits); \ + goto failed; \ + } \ +} G_STMT_END + +#define READ_UINT64(reader, val, nbits) G_STMT_START { \ + if (!gst_bit_reader_get_bits_uint64 (reader, &val, nbits)) { \ + GST_WARNING ("failed to read uint64, nbits: %d", nbits); \ + goto failed; \ + } \ +} G_STMT_END + + +#define U_READ_UINT8(reader, val, nbits) G_STMT_START { \ + val = gst_bit_reader_get_bits_uint8_unchecked (reader, nbits); \ +} G_STMT_END + +#define U_READ_UINT16(reader, val, nbits) G_STMT_START { \ + val = gst_bit_reader_get_bits_uint16_unchecked (reader, nbits); \ +} G_STMT_END + +#define U_READ_UINT32(reader, val, nbits) G_STMT_START { \ + val = gst_bit_reader_get_bits_uint32_unchecked (reader, nbits); \ +} G_STMT_END + +#define U_READ_UINT64(reader, val, nbits) G_STMT_START { \ + val = gst_bit_reader_get_bits_uint64_unchecked (reader, nbits); \ +} G_STMT_END + +#define SKIP(reader, nbits) G_STMT_START { \ + if (!gst_bit_reader_skip (reader, nbits)) { \ + GST_WARNING ("failed to skip nbits: %d", nbits); \ + goto failed; \ + } \ +} G_STMT_END + +typedef struct _VLCTable VLCTable; + +struct _VLCTable +{ + guint value; + guint cword; + guint cbits; +}; + +gboolean +decode_vlc (GstBitReader * br, guint * res, const VLCTable * table, + guint length); + +#endif /* __PARSER_UTILS__ */ diff --git a/ext/codecparsers/tests/Makefile.am b/ext/codecparsers/tests/Makefile.am new file mode 100644 index 0000000..5591bb6 --- /dev/null +++ b/ext/codecparsers/tests/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = check + +# Extra clean files so that maintainer-clean removes *everything* +MAINTAINERCLEANFILES = Makefile.in diff --git a/ext/codecparsers/tests/check/Makefile.am b/ext/codecparsers/tests/check/Makefile.am new file mode 100644 index 0000000..d29d457 --- /dev/null +++ b/ext/codecparsers/tests/check/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = libs + +# Extra clean files so that maintainer-clean removes *everything* +MAINTAINERCLEANFILES = Makefile.in diff --git a/ext/codecparsers/tests/check/libs/.gitignore b/ext/codecparsers/tests/check/libs/.gitignore new file mode 100644 index 0000000..238cb3d --- /dev/null +++ b/ext/codecparsers/tests/check/libs/.gitignore @@ -0,0 +1,4 @@ +.dirstamp +h264parser +mpegvideoparser +vc1parser diff --git a/ext/codecparsers/tests/check/libs/Makefile.am b/ext/codecparsers/tests/check/libs/Makefile.am new file mode 100644 index 0000000..e034655 --- /dev/null +++ b/ext/codecparsers/tests/check/libs/Makefile.am @@ -0,0 +1,24 @@ +noinst_PROGRAMS = \ + h264parser \ + mpegvideoparser \ + vc1parser \ + $(NULL) + +AM_CFLAGS = \ + -I$(top_srcdir)/gst-libs \ + $(GST_PLUGINS_BASE_CFLAGS) \ + -DGST_USE_UNSTABLE_API \ + $(GST_CHECK_CFLAGS) \ + $(GST_BASE_CFLAGS) \ + $(GST_CFLAGS) \ + $(NULL) + +LDADD = \ + $(GST_PLUGINS_BASE_LIBS) \ + $(GST_CHECK_LIBS) \ + $(GST_BASE_LIBS) \ + $(GST_LIBS) \ + $(top_builddir)/gst-libs/gst/codecparsers/libgstcodecparsers-$(GST_MAJORMINOR).la + +# Extra clean files so that maintainer-clean removes *everything* +MAINTAINERCLEANFILES = Makefile.in diff --git a/ext/codecparsers/tests/check/libs/h264parser.c b/ext/codecparsers/tests/check/libs/h264parser.c new file mode 100644 index 0000000..285a4f4 --- /dev/null +++ b/ext/codecparsers/tests/check/libs/h264parser.c @@ -0,0 +1,182 @@ +/* Gstreamer + * Copyright (C) <2011> Intel Corporation + * Copyright (C) <2011> Collabora Ltd. + * Copyright (C) <2011> Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#include +#include + +static guint8 slice_dpa[] = { + 0x00, 0x00, 0x01, 0x02, 0x00, 0x02, 0x01, 0x03, 0x00, + 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x09, 0x00, 0x0a, 0x00, + 0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x10, 0x00, + 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, + 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, 0x00, + 0x1d, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x20, 0x00, 0x21, 0x00, 0x22, 0x00, + 0x23, 0x00, 0x24, 0x00, 0x25, 0x00, 0x26, 0x00, 0x27, 0x00, 0x28, 0x00, + 0x29, 0x00, 0x2a, 0x00, 0x2b, 0x00, 0x2c, 0x00, 0x2d, 0x00, 0x2e, 0x00, + 0x2f, 0x00, 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, + 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, + 0x3b, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x40, 0x00, + 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, + 0x47, 0x00, 0x48, 0x00, 0x49, 0x00, 0x4a, 0x00, 0x4b, 0x00, 0x4c, 0x00, + 0x4d, 0x00, 0x4e, 0x00, 0x4f, 0x00, 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, + 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, 0x58, 0x00, + 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5e, 0x00, + 0x5f, 0x00, 0x60, 0x00, 0x61, 0x01, 0x04, 0x00, 0xc4, 0x00, 0xa6, 0x00, + 0xc5, 0x00, 0xab, 0x00, 0x82, 0x00, 0xc2, 0x00, 0xd8, 0x00, 0xc6, 0x00, + 0xe4, 0x00, 0xbe, 0x00, 0xb0, 0x00, 0xe6, 0x00, 0xb6, 0x00, 0xb7, 0x00, + 0xb4, 0x00, 0xb5, 0x00, 0x87, 0x00, 0xb2, 0x00, 0xb3, 0x00, 0xd9, 0x00, + 0x8c, 0x00, 0xe5, 0x00, 0xbf, 0x00, 0xb1, 0x00, 0xe7, 0x00, 0xbb, 0x00, + 0xa3, 0x00, 0x84, 0x00, 0x85, 0x00, 0xbd, 0x00, 0x96, 0x00, 0xe8, 0x00, + 0x86, 0x00, 0x8e, 0x00, 0x8b, 0x00, 0x9d, 0x00, 0xa9, 0x00, 0x8a, 0x01, + 0x05, 0x00, 0x83, 0x00, 0xf2, 0x00, 0xf3, 0x00, 0x8d, 0x00, 0x97, 0x00, + 0x88, 0x00, 0xde, 0x00, 0xf1, 0x00, 0x9e, 0x00, 0xaa, 0x00, 0xf5, 0x00, + 0xf4, 0x00, 0xf6, 0x00, 0xa2, 0x00, 0xad, 0x00, 0xc9, 0x00, 0xc7, 0x00, + 0xae, 0x00, 0x62, 0x00, 0x63, 0x00, 0x90, 0x00, 0x64, 0x00, 0xcb, 0x00, + 0x65, 0x00, 0xc8, 0x00, 0xca, 0x00, 0xcf, 0x00, 0xcc, 0x00, 0xcd, 0x00, + 0xce, 0x00, 0xe9, 0x00, 0x66, 0x00, 0xd3, 0x00, 0xd0, 0x00, 0xd1, 0x00, + 0xaf, 0x00, 0x67, 0x00, 0x91, 0x00, 0xd6, 0x00, 0xd4, 0x00, 0xd5, 0x00, + 0x68, 0x00, 0xeb, 0x00, 0xed, 0x00, 0x89, 0x00, 0x6a, 0x00, 0x69, 0x00, + 0x6b, 0x00, 0x6d, 0x00, 0x6c, 0x00, 0x6e, 0x00, 0xa0, 0x00, 0x6f, 0x00, + 0x71, 0x00, 0x70, 0x00, 0x72, 0x00, 0x73, 0x00, 0x75, 0x00, 0x74, 0x00, + 0x76, 0x00, 0x77, 0x00, 0xea, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x79, 0x00, + 0x7b, 0x00, 0x7d, 0x00, 0x7c, 0x00, 0xa1, 0x00, 0x7f, 0x00, 0x7e, 0x00, + 0x80, 0x00, 0x81, 0x00, 0xec, 0x00, 0xee, 0x00, 0xba, 0x01, 0x06, 0x00, + 0xef, 0x00, 0xe1, 0x00, 0xe0, 0x00, 0xdc, 0x01, 0x07, 0x01, 0x08, 0x01, + 0x09, 0x01, 0x0a, 0x01, 0x0b, 0x01, 0x0c, 0x00, 0xdb, 0x00, 0xe2, 0x01, + 0x0d, 0x01, 0x0e, 0x01, 0x0f, 0x01, 0x10, 0x01, 0x11, 0x01, 0x12, 0x00, + 0xdf, 0x01, 0x13, 0x01, 0x14, 0x01, 0x15, 0x01, 0x16, 0x01, 0x17, 0x00, + 0xfd, 0x00, 0xff, 0x01, 0x18, 0x01, 0x19, 0x01, 0x1a, 0x01, 0x1b, 0x01, + 0x1c, 0x01, 0x1d, 0x01, 0x1e, 0x01, 0x1f, 0x01, 0x20, 0x01, 0x21, 0x01, + 0x22, 0x01, 0x23, 0x01, 0x24, 0x01, 0x25, 0x01, 0x26, 0x00, 0xfe, 0x01, + 0x00, 0x01, 0x27, 0x01, 0x28, 0x01, 0x29, 0x01, 0x2a, 0x01, 0x2b, 0x01, + 0x2c, 0x01, 0x2d, 0x01, 0x2e, 0x01, 0x2f, 0x01, 0x30, 0x01, 0x31, 0x00, + 0xe3, 0x00, 0xd7, 0x01, 0x32, 0x00, 0xf8, 0x00, 0xf9, 0x01, 0x33, 0x01, + 0x34, 0x01, 0x35, 0x01, 0x36, 0x01, 0x37, 0x01, 0x38, 0x01, 0x39, 0x01, + 0x3a, 0x01, 0x3b, 0x01, 0x3c, 0x01, 0x3d, 0x01, 0x3e, 0x01, 0x3f, 0x01, + 0x40, 0x01, 0x41, 0x01, 0x42, 0x01, 0x43, 0x01, 0x44, 0x01, 0x45, 0x01, + 0x46, 0x01, 0x47, 0x01, 0x48, 0x01, 0x49, 0x01, 0x4a, 0x01, 0x4b, 0x01, + 0x4c, 0x00, 0x08, 0x05, 0x2e, 0x6e, 0x75, 0x6c, 0x6c, 0x0c, 0x76, 0x69, + 0x73, 0x69, 0x62, 0x6c, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x04, 0x45, + 0x75, 0x72, 0x6f, 0x06, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x0a, 0x62, + 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x6d, 0x61, 0x74, 0x68, 0x06, 0x53, 0x61, + 0x63, 0x75, 0x74, 0x65, 0x06, 0x54, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x06, + 0x5a, 0x61, 0x63, 0x75, 0x74, 0x65, 0x06, 0x73, 0x61, 0x63, 0x75, 0x74, + 0x65, 0x06, 0x74, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x06, 0x7a, 0x61, 0x63, + 0x75, 0x74, 0x65, 0x07, 0x41, 0x6f, 0x67, 0x6f, 0x6e, 0x65, 0x6b, 0x07, + 0x61, 0x6f, 0x67, 0x6f, 0x6e, 0x65, 0x6b, 0x0c, 0x73, 0x63, 0x6f, 0x6d, + 0x6d, 0x61, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x53, 0x63, 0x6f, + 0x6d, 0x6d, 0x61, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0a, 0x5a, 0x64, + 0x6f, 0x74, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x06, 0x4c, 0x63, 0x61, + 0x72, 0x6f, 0x6e, 0x06, 0x6c, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x0a, 0x7a, + 0x64, 0x6f, 0x74, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x06, 0x52, 0x61, + 0x63, 0x75, 0x74, 0x65, 0x06, 0x41, 0x62, 0x72, 0x65, 0x76, 0x65, 0x06, + 0x4c, 0x61, 0x63, 0x75, 0x74, 0x65, 0x07, 0x45, 0x6f, 0x67, 0x6f, 0x6e, + 0x65, 0x6b, 0x06, 0x45, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x06, 0x44, 0x63, + 0x61, 0x72, 0x6f, 0x6e, 0x07, 0x44, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e, + 0x06, 0x4e, 0x61, 0x63, 0x75, 0x74, 0x65, 0x06, 0x4e, 0x63, 0x61, 0x72, + 0x6f, 0x6e, 0x0d, 0x4f, 0x68, 0x75, 0x6e, 0x67, 0x61, 0x72, 0x75, 0x6d, + 0x6c, 0x61, 0x75, 0x74, 0x06, 0x52, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x05, + 0x55, 0x72, 0x69, 0x6e, 0x67, 0x09, 0x6e, 0x75, 0x6e, 0x67, 0x61, 0x64, + 0x65, 0x73, 0x68, 0x0d, 0x55, 0x68, 0x75, 0x6e, 0x67, 0x61, 0x72, 0x75, + 0x6d, 0x6c, 0x61, 0x75, 0x74, 0x0c, 0x54, 0x63, 0x6f, 0x6d, 0x6d, 0x61, + 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x06, 0x72, 0x61, 0x63, 0x75, 0x74, + 0x65, 0x06, 0x61, 0x62, 0x72, 0x65, 0x76, 0x65, 0x06, 0x6c, 0x61, 0x63, + 0x75, 0x74, 0x65, 0x07, 0x65, 0x6f, 0x67, 0x6f, 0x6e, 0x65, 0x6b, 0x06, + 0x65, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x06, 0x64, 0x63, 0x61, 0x72, 0x6f, + 0x6e, 0x07, 0x64, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x06, 0x6e, 0x61, + 0x63, 0x75, 0x74, 0x65, 0x06, 0x6e, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x0d, + 0x6f, 0x68, 0x75, 0x6e, 0x67, 0x61, 0x72, 0x75, 0x6d, 0x6c, 0x61, 0x75, + 0x74, 0x06, 0x72, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x05, 0x75, 0x72, 0x69, + 0x6e, 0x67, 0x0d, 0x75, 0x68, 0x75, 0x6e, 0x67, 0x61, 0x72, 0x75, 0x6d, + 0x6c, 0x61, 0x75, 0x74, 0x0c, 0x74, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61, + 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0a, 0x49, 0x64, 0x6f, 0x74, 0x61, 0x63, + 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x52, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61, + 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x72, 0x63, 0x6f, 0x6d, 0x6d, 0x61, + 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x07, 0x49, 0x6f, 0x67, 0x6f, 0x6e, + 0x65, 0x6b, 0x07, 0x41, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x07, 0x45, + 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x0a, 0x45, 0x64, 0x6f, 0x74, 0x61, + 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x47, 0x63, 0x6f, 0x6d, 0x6d, 0x61, + 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x4b, 0x63, 0x6f, 0x6d, 0x6d, + 0x61, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x07, 0x49, 0x6d, 0x61, 0x63, + 0x72, 0x6f, 0x6e, 0x0c, 0x4c, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61, 0x63, + 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x4e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61, + 0x63, 0x63, 0x65, 0x6e, 0x74, 0x07, 0x4f, 0x6d, 0x61, 0x63, 0x72, 0x6f, + 0x6e, 0x07, 0x55, 0x6f, 0x67, 0x6f, 0x6e, 0x65, 0x6b, 0x07, 0x55, 0x6d, + 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x07, 0x69, 0x6f, 0x67, 0x6f, 0x6e, 0x65, + 0x6b, 0x07, 0x61, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x07, 0x65, 0x6d, + 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x0a, 0x65, 0x64, 0x6f, 0x74, 0x61, 0x63, + 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x67, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61, + 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x6b, 0x63, 0x6f, 0x6d, 0x6d, 0x61, + 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x07, 0x69, 0x6d, 0x61, 0x63, 0x72, + 0x6f, 0x6e, 0x0c, 0x6c, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61, 0x63, 0x63, + 0x65, 0x6e, 0x74, 0x0c, 0x6e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61, 0x63, + 0x63, 0x65, 0x6e, 0x74, 0x07, 0x6f, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e, + 0x07, 0x75, 0x6f, 0x67, 0x6f, 0x6e, 0x65, 0x6b, 0x07, 0x75, 0x6d, 0x61, + 0x63, 0x72, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02 +}; + +GST_START_TEST (test_h264_parse_slice_dpa) +{ + GstH264ParserResult res; + GstH264NalUnit nalu; + + GstH264NalParser *parser = gst_h264_nal_parser_new (); + + res = gst_h264_parser_identify_nalu (parser, slice_dpa, 0, + sizeof (slice_dpa), &nalu); + + assert_equals_int (res, GST_H264_PARSER_OK); + assert_equals_int (nalu.type, GST_H264_NAL_SLICE_DPA); + + gst_h264_nal_parser_free (parser); +} + +GST_END_TEST; + +static Suite * +h264parser_suite (void) +{ + Suite *s = suite_create ("H264 Parser library"); + + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_h264_parse_slice_dpa); + + return s; +} + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = h264parser_suite (); + + SRunner *sr = srunner_create (s); + + gst_check_init (&argc, &argv); + + srunner_run_all (sr, CK_NORMAL); + nf = srunner_ntests_failed (sr); + srunner_free (sr); + + return nf; +} diff --git a/ext/codecparsers/tests/check/libs/mpegvideoparser.c b/ext/codecparsers/tests/check/libs/mpegvideoparser.c new file mode 100644 index 0000000..930fbb0 --- /dev/null +++ b/ext/codecparsers/tests/check/libs/mpegvideoparser.c @@ -0,0 +1,199 @@ +/* Gstreamer + * Copyright (C) <2011> Intel Corporation + * Copyright (C) <2011> Collabora Ltd. + * Copyright (C) <2011> Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + +/* actually seq + gop */ +static const guint8 mpeg2_seq[] = { + 0x00, 0x00, 0x01, 0xb3, 0x02, 0x00, 0x18, 0x15, 0xff, 0xff, 0xe0, 0x28, + 0x00, 0x00, 0x01, 0xb3, 0x78, 0x04, 0x38, 0x37, 0xff, 0xff, 0xf0, 0x00, + 0x00, 0x00, 0x01, 0xb5, 0x14, 0x8a, 0x00, 0x11, 0x03, 0x71, + 0x00, 0x00, 0x01, 0xb8, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x03, 0x00, 0x08, 0x00, 0x00 +}; + +static const guint8 mis_identified_datas[] = { + 0x00, 0x00, 0x01, 0x1f, 0x4a, 0xf4, 0xd4, 0xd8, 0x08, 0x23, 0xdd, + 0x7c, 0xd3, 0x75, 0x21, 0x43, 0x85, 0x31, 0x43, 0x04, 0x24, 0x30, + 0x18, 0x43, 0xba, 0x1a, 0x50, 0x60, 0xbb, 0x53, 0x56, 0x80, 0x41, + 0xb9, 0xd4, 0x25, 0x42, 0xea, 0x71, 0xb7, 0x49, 0x84, 0x0b, 0x14, + 0x24, 0xc2, 0xaa, 0xba, 0xf9, 0xf7, 0x5b, 0x78, 0xa2, 0xba, 0xd3, + 0xc7, 0x12, 0xee, 0xbe, 0xba, 0xfa, 0xeb, 0xeb, 0xaf, 0xbe, 0x6f, + 0xce, 0x92, 0x05, 0x15, 0x22, 0x44, 0xf4, 0xc9, 0x1b, 0xcd, 0x84, + 0x80, 0x87, 0x35, 0x6c, 0x07, 0x82, 0xaf, 0x3c, 0x3a, 0x89, 0x48, + 0x3a, 0x26, 0x00, 0x64, 0x03, 0x12, 0x60, 0x03, 0xf4, 0x8c, 0x21, + 0x16, 0xbe, 0x3c, 0x7c, 0x18, 0x03, 0x10, 0x0c, 0x80, 0xa0, 0x05, + 0xe1, 0x85, 0x94, 0x90, 0xc4, 0x74, 0x05, 0x72, 0x80, 0x7a, 0x8e, + 0x3e, 0x00, 0x30, + /* The accelerated version of scan_for_start_codes() + * mis-identifies the following as a start code */ + 0x01, 0x00, 0x01, 0x80, 0x68, 0x14, + 0x26, 0xe4, 0x80, 0x98, 0x0a, 0xba, 0x77, 0x01, 0xc2, 0x42, 0x12, + 0xc4, 0x59, 0x2a, 0xbb, 0x49, 0xf2, 0xc5, 0xa8, 0xd9, 0x30, 0x33, + 0x16, 0x50, 0x60, 0x61, 0x41, 0xaa, 0x0d, 0x41, 0x5b, 0x17, 0x77, + 0x76, 0x1a, 0x14, 0x3a, 0x08, 0x19, 0x3d, 0x6c, 0x94, 0x55, 0xd0, + 0x94, 0x5a, 0xeb, 0x61, 0x22, 0xa7, 0xa6, 0x83, 0x47, 0x6d, 0x4d, + 0x84, 0xc4, 0x6f, 0x78, 0xd8, 0x3a, 0xb4, 0x02, 0x0c, 0x36, 0xa6, + 0x0b, 0x18, 0x49, 0xf7, 0xad, 0x00, 0x82, 0x09, 0xba, 0x12, 0xba, + 0x1d, 0x44, 0x94, 0x0a, 0x1b, 0x03, 0xbb, 0xa2, 0x53, 0x02, 0xc0, + 0x41, 0xac, 0x22, + /* the real start code is here */ + 0x00, 0x00, 0x01, 0x20, 0x4a, 0xfd, 0xf5, 0x50 +}; + +static GstMpegVideoPacketTypeCode ordercode[] = { + GST_MPEG_VIDEO_PACKET_SEQUENCE, + GST_MPEG_VIDEO_PACKET_EXTENSION, + GST_MPEG_VIDEO_PACKET_GOP, +}; + +GST_START_TEST (test_mpeg_parse) +{ + gint i, off; + GstMpegVideoPacket packet; + + off = 12; + for (i = 0; i < 4; ++i) { + fail_unless (gst_mpeg_video_parse (&packet, mpeg2_seq, sizeof (mpeg2_seq), + off)); + fail_unless (packet.offset == off + 4); + if (i == 3) { + fail_unless (GST_MPEG_VIDEO_PACKET_SLICE_MIN <= packet.type && + packet.type <= GST_MPEG_VIDEO_PACKET_SLICE_MAX); + fail_unless (packet.size < 0); + } else { + assert_equals_int (ordercode[i], packet.type); + } + off = packet.offset + packet.size; + } +} + +GST_END_TEST; + +GST_START_TEST (test_mpeg_parse_sequence_header) +{ + GstMpegVideoSequenceHdr seqhdr; + GstMpegVideoPacket packet; + + gst_mpeg_video_parse (&packet, mpeg2_seq, sizeof (mpeg2_seq), 12); + + fail_unless (packet.type == GST_MPEG_VIDEO_PACKET_SEQUENCE); + fail_unless (gst_mpeg_video_parse_sequence_header (&seqhdr, mpeg2_seq, + sizeof (mpeg2_seq), packet.offset)); + assert_equals_int (seqhdr.width, 1920); + assert_equals_int (seqhdr.height, 1080); + assert_equals_int (seqhdr.aspect_ratio_info, 3); + assert_equals_int (seqhdr.par_w, 64); + assert_equals_int (seqhdr.par_h, 45); + assert_equals_int (seqhdr.frame_rate_code, 7); + assert_equals_int (seqhdr.fps_n, 60000); + assert_equals_int (seqhdr.fps_d, 1001); + assert_equals_int (seqhdr.bitrate_value, 262143); + assert_equals_int (seqhdr.bitrate, 0); + assert_equals_int (seqhdr.vbv_buffer_size_value, 512); + fail_unless (seqhdr.constrained_parameters_flag == FALSE); +} + +GST_END_TEST; + +GST_START_TEST (test_mpeg_parse_sequence_extension) +{ + GstMpegVideoSequenceExt seqext; + GstMpegVideoPacket packet; + + gst_mpeg_video_parse (&packet, mpeg2_seq, sizeof (mpeg2_seq), 24); + + fail_unless (packet.type == GST_MPEG_VIDEO_PACKET_EXTENSION); + fail_unless (gst_mpeg_video_parse_sequence_extension (&seqext, + mpeg2_seq, sizeof (mpeg2_seq), packet.offset)); + assert_equals_int (seqext.profile, 4); + assert_equals_int (seqext.level, 8); + assert_equals_int (seqext.progressive, 1); + assert_equals_int (seqext.chroma_format, 1); + assert_equals_int (seqext.horiz_size_ext, 0); + assert_equals_int (seqext.vert_size_ext, 0); + assert_equals_int (seqext.vert_size_ext, 0); + assert_equals_int (seqext.bitrate_ext, 8); + assert_equals_int (seqext.vbv_buffer_size_extension, 3); + assert_equals_int (seqext.low_delay, 0); + assert_equals_int (seqext.fps_n_ext, 3); + assert_equals_int (seqext.fps_d_ext, 2); +} + +GST_END_TEST; + +GST_START_TEST (test_mis_identified_datas) +{ + GstMpegVideoPacket packet = { 0, }; + const guint8 *data = mis_identified_datas; + gint i, off; + + off = 0; + for (i = 0; i < 2; i++) { + gst_mpeg_video_parse (&packet, mis_identified_datas, + sizeof (mis_identified_datas), off); + assert_equals_int (data[packet.offset - 4], 0); + assert_equals_int (data[packet.offset - 3], 0); + assert_equals_int (data[packet.offset - 2], 1); + off = packet.offset + packet.size; + if (i == 1) + fail_unless (packet.size < 0); + else + fail_unless (packet.size > 0); + } +} + +GST_END_TEST; + +static Suite * +videoparsers_suite (void) +{ + Suite *s = suite_create ("Video Parsers library"); + + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_mpeg_parse); + tcase_add_test (tc_chain, test_mpeg_parse_sequence_header); + tcase_add_test (tc_chain, test_mpeg_parse_sequence_extension); + tcase_add_test (tc_chain, test_mis_identified_datas); + + return s; +} + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = videoparsers_suite (); + + SRunner *sr = srunner_create (s); + + gst_check_init (&argc, &argv); + + srunner_run_all (sr, CK_NORMAL); + nf = srunner_ntests_failed (sr); + srunner_free (sr); + + return nf; +} diff --git a/ext/codecparsers/tests/check/libs/vc1parser.c b/ext/codecparsers/tests/check/libs/vc1parser.c new file mode 100644 index 0000000..e72cf7f --- /dev/null +++ b/ext/codecparsers/tests/check/libs/vc1parser.c @@ -0,0 +1,1240 @@ +/* Gstreamer + * Copyright (C) <2011> Intel + * Copyright (C) <2011> Collabora Ltd. + * Copyright (C) <2011> Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#include +#include + +static const guint8 sequence_fullframe[] = { + 0x00, 0x00, 0x01, 0x0f, 0xca, 0x86, 0x13, 0xf0, 0xef, 0x88, + 0x80, 0x00, 0x00, 0x01, 0x0e, 0x48, 0x3f, 0x4f, 0xc3, 0xbc, + 0x3f, 0x2b, 0x3f, 0x3c, 0x3f, 0x00, 0x00, 0x01, 0x0d, 0x3f, + 0x0c, 0x14, 0x27, 0x3f, 0x68, 0x0c, 0x03, 0x3f, 0x3f, 0x55, + 0x3f, 0x60, 0x71, 0x24, 0x38, 0x28, 0x1b, 0xda, 0xac, 0x01, + 0x3f, 0x3f, 0x3f, 0x33, 0x3f, 0x61, 0x75, 0x70, 0x3f, 0x3f, + 0x3f, 0x0d, 0x3f, 0x03, 0x3f, 0x3f, 0x1b, 0x3f, 0x3f, 0x61, + 0x1a, 0x73, 0x01, 0x26, 0x07, 0x0e, 0x29, 0x3f, 0x1d, 0x68, + 0xe1, 0xa2, 0x98, 0x59, 0x21, 0x3f, 0x1e, 0x7c, 0x3f, 0x3f, + 0x3f, 0x65, 0x49, 0x3f, 0x3f, 0x7e, 0x3f, 0x07, 0x6a, 0x0f, + 0xdb, 0x87, 0x3f, 0x3f, 0x3f, 0x41, 0x3f, 0x3f, 0x77, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x44, 0x3f, 0x4a, 0x50, 0x53, + 0x3f, 0x3f, 0x65, 0x3f, 0x2e, 0x3f, 0x3f, 0x3f, 0x08, 0x3f, + 0x3f, 0x04, 0x5e, 0x11, 0x7d, 0x12, 0x3f, 0x4a, 0x6b, 0x50, + 0x42, 0x3f, 0x15, 0x3f, 0x3f, 0x61, 0x3f, 0x3f, 0x75, 0x41, + 0x3f, 0x3f, 0x75, 0x71, 0x3f, 0x3f, 0x3b, 0x3f, 0x0d, 0x3f, + 0x3f, 0x6e, 0x3f, 0x3f, 0x06, 0x3f, 0x30, 0x08, 0x72, 0x3f, + 0x3b, 0x3f, 0x67, 0x6e, 0x3f, 0x50, 0x1b, 0x61, 0x5a, 0x20, + 0x2b, 0x70, 0x3f, 0x2c, 0x22, 0x3f, 0x36, 0x3f, 0x44, 0x40, + 0x00, 0x00, 0x01, 0x05, 0x3f +}; + +static const guint8 pframe_header_main[] = { + 0x4e, 0x29, 0x1a, 0x11 +}; + +static const guint8 pframe_main[] = { + 0x6a, 0x88, 0xbc, 0x1d, 0x40, 0x16, 0x96, 0x90, 0x05, 0x82, + 0xac, 0x22, 0x88, 0xe0, 0x5d, 0x52, 0xca, 0x85, 0x4c, 0x47, + 0x9d, 0xc9, 0x25, 0x45, 0x56, 0x99, 0x44, 0x15, 0xa5, 0xc5, + 0xe1, 0x35, 0x11, 0x72, 0xc1, 0x27, 0x22, 0x6a, 0x08, 0x9a, + 0x72, 0x4e, 0xe7, 0xa3, 0xf7, 0x23, 0x9d, 0x11, 0x8d, 0xc8, + 0xe6, 0x4f, 0x46, 0x98, 0xe2, 0x03, 0xcc, 0x6c, 0xe8, 0x77, + 0xd4, 0x7c, 0xfc, 0x13, 0x39, 0x20, 0x23, 0x03, 0x24, 0xcd, + 0x15, 0xbf, 0x54, 0x61, 0xf2, 0x25, 0x25, 0xa0, 0x83, 0xa0, +}; + +static const guint8 bframe_header_main[] = { + 0x4e, 0x39, 0x1a, 0x11 +}; + +static const guint8 bframe_main[] = { + 0x80, 0xae, 0x01, 0x43, 0x47, 0x6a, 0x9f, 0x53, 0x04, 0x55, 0x2a, + 0x8b, 0x42, 0x75, 0x8b, 0x35, 0x50, 0xf5, 0x95, 0x56, 0xf2, 0x00, + 0xe0, 0xa0, 0x60, 0x2c, 0xe8, 0x6b, 0x60, 0x0b, 0x20, 0x00, 0x11, + 0xf1, 0x51, 0xfe, 0x91, 0x60, 0x6a, 0xe6, 0x12, 0x04, 0x2c, 0xe3, + 0x07, 0x0a, 0x09, 0x09, 0x12, 0xcb, 0xe1, 0x42, 0x88, 0x10, 0x67, + 0x80, 0x4c, 0xbf, 0x26, 0x00, 0x82, 0x61, 0x07, 0x21, 0x63, 0x4c, + 0x0c, 0x32, 0x03, 0x53, 0x19, 0x1b, 0x4d, 0xca, 0xc9, 0xe0, 0xc1, + 0x6d, 0x32, 0x48, 0xc9, 0xd7, 0xa6, 0x63, 0x4d, 0xeb, 0xd4, 0x1c, + 0x02, 0x05, 0xfe, 0x57, 0x29, 0x00, 0x58, 0xb0, 0x67, 0x2d, 0x04, + 0xee, 0x1b, 0xaf, 0x53, 0x40, 0x89, 0xbe, 0xf5, 0x76, 0x20, 0x0b, + 0x83, 0xc1, 0x88, 0xee, 0x83, 0x94, 0xab, 0x1c, 0x79, 0xdd, 0x44, + 0xe5, 0x15, 0xae, 0xa5, 0xd3, 0xd5, 0x68, 0x31, 0x3e, 0x5a, 0xa4, + 0x6b, 0x9e, 0xe3, 0xd2, 0x49, 0x00, 0x1d, 0x6d, 0xeb, 0x0d, 0x6b, + 0x54, 0xcd, 0xd2, 0xaf, 0x1f, 0x2b, 0xba, 0xf3, 0xd9, 0x4c, 0x71 +}; + +static const guint8 i_bi_frame_header[] = { + 0x4e, 0x79, 0x1a, 0x11 +}; + +static const guint8 biframe_main[] = { + 0x0f, 0xe0, 0x4c, 0x56, 0x19, 0xdb, 0x40, 0x68, 0xd9, 0x14, 0x2c, 0x92, + 0x55, 0x1f, 0x59, 0xd5, 0x5b, 0xd8, 0x55, 0x13, 0x19, 0x64, 0x40, 0x2c, + 0x27, 0x38, 0x71, 0x9d, 0x05, 0x52, 0x02, 0x18, 0x7b, 0x9d, 0x22, 0x88, + 0x97, 0xaa, 0x54, 0x95, 0x52, 0x49, 0x23, 0x0b, 0x98, 0xee, 0x6c, 0x26, + 0xe6, 0xff, 0xff, 0x1a, 0x25, 0x15, 0xc3, 0x30, 0x4f, 0x1f, 0xbd, 0xb1, + 0x09, 0x1b, 0x55, 0x33, 0x6c, 0xcd, 0x8c, 0x11, 0x87, 0x1b, 0x86, 0x02, + 0x78, 0xfd, 0x69, 0xc1, 0xa2, 0x3b, 0x27, 0x08, 0xc8, 0x63, 0x5f, 0x52, + 0x10, 0x50, 0xe0, 0xf4, 0x4a, 0xfd, 0x83, 0x30, 0x3f, 0x20, 0x8d, 0x3a, + 0x88, 0xa0, 0x00, 0x23, 0xd8, 0x51, 0xd0, 0xf6, 0x8c, 0xc4, 0xe8, 0x2d, + 0x8c, 0x10, 0x13, 0xae, 0xb2, 0xaa, 0xc0, 0x92, 0x68, 0x33, 0x7b, 0x8f, + 0x63, 0x0e, 0xda, 0x35, 0xc6, 0xa1, 0x11, 0xe6, 0x44, 0xe3, 0xb1, 0x52, + 0xe9, 0x01, 0x05, 0x93, 0x1a, 0x36, 0x41, 0xf6, 0x62, 0x66, 0x05, 0xfb, + 0xd6, 0x99, 0x80, 0x8a, 0x97, 0xad, 0xa4, 0x25, 0xec, 0x1a, 0x04, 0xf3, + 0x0c, 0x9c, 0xe0, 0xea, 0x49, 0xfa, 0x4d, 0x58, 0xc8, 0x1b, 0x63, 0x23, + 0xdc, 0x07, 0x9d, 0xe9, 0x84, 0x93, 0x12, 0xc8, 0xfc, 0x86, 0x98, 0xb0, + 0x3d, 0xc8, 0xb4, 0xed, 0x4c, 0x18, 0xbe, 0xd8, 0x38, 0x1b, 0x6d, 0x39, + 0x90, 0x06, 0x43, 0x75, 0x82, 0x89, 0xc1, 0x6f, 0xf1, 0x12, 0x6d, 0x84, + 0x54, 0x45, 0x62, 0x2d, 0x00, 0x0a, 0x0e, 0x06, 0xf0, 0x04, 0x06, 0x5a +}; + +static const guint8 iframe_main[] = { + 0x10, 0x04, 0x88, 0x18, 0x1f, 0xdf, 0xe1, 0xe1, 0xde, 0x17, 0x85, 0xe1, + 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, + 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, + 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, + 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, + 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, + 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, + 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, + 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, + 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, + 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, + 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, + 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, + 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78 +}; + +static const guint8 iframe_adv_hdr[] = { + 0xdb, 0xfe, 0x3b, 0xf2, 0x1b, 0xca, 0x3b, 0xf8, 0x86, 0xf1, 0x80, + 0xca, 0x02, 0x02, 0x03, 0x09, 0xa5, 0xb8, 0xd7, 0x07, 0xfc +}; + +static const guint8 entrypoint[] = { + 0x5a, 0xc7, 0xfc, 0xef, 0xc8, 0x6c, 0x40 +}; + +static const guint8 iframe_adv[] = { + 0x69, 0x1c, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0x16, 0x0c, 0x0f, 0x13, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, + 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, + 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, + 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, + 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, + 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, + 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, + 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, + 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, + 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, + 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, + 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, + 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, + 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, + 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, + 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, + 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, + 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, + 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f +}; + +static const guint8 bframe_adv[] = { + 0x46, 0x03, 0x1f, 0xf0, 0x8d, 0xd8, 0xbf, 0xc0, 0xcc, 0x14, + 0x24, 0xdc, 0x60, 0xe2, 0xa8, 0x5e, 0x0d, 0xff, 0xfc, 0x3b, + 0x12, 0xfd, 0xe1, 0x2e, 0xd1, 0x84, 0xb0, 0xc2, 0xc4, 0xc1, + 0x60, 0x20, 0x4a, 0x7c, 0x33, 0xff, 0xf2, 0x10, 0xd8, 0x5c, + 0xf6, 0x7f, 0xc4, 0xd5, 0x0e, 0x0e, 0x51, 0xa8, 0x57, 0xff, + 0xfa, 0x43, 0x1f, 0xd0, 0x80, 0xdc, 0x58, 0x02, 0x02, 0xaf, + 0x10, 0xc6, 0x10, 0x12, 0x80, 0xd8, 0x07, 0xff, 0x9d, 0x00, + 0x50, 0x51, 0xa8, 0x0a, 0xd3, 0xef, 0x54, 0x03, 0xcb, 0x3f, + 0xff, 0x2b, 0x8b, 0x21, 0xcb, 0xdb, 0xf1, 0x62, 0x4e, 0x4d, + 0x8b, 0x03, 0x00, 0x16, 0x53, 0xff, 0xa6, 0x65, 0x12, 0x70, + 0xe0, 0x3f, 0xf4, 0x85, 0xb8, 0x4b, 0xc6, 0x04, 0x52, 0xff, + 0xc1, 0xf0, 0x80, 0x39, 0x85, 0x9f, 0xf4, 0xca, 0x91, 0x28, + 0x10, 0x64, 0x2c, 0xe0, 0xff, 0xff, 0x03, 0x2c, 0x3a, 0xfe, + 0x03, 0xc3, 0x2d, 0x0e, 0x60, 0x61, 0x80, 0x09, 0x9f, 0xff, + 0x03, 0x88, 0xc5, 0xd7, 0x9f, 0xfe, 0x1c, 0x14, 0x62, 0xc0, + 0x62, 0xc1, 0x7f, 0xef, 0x87, 0x7d, 0x6c, 0xbf, 0xf7, 0xc2, + 0x00, 0x10, 0x59, 0xd7, 0xfc, 0x33, 0x15, 0xbd, 0x35, 0xec, + 0x17, 0x0b, 0x07, 0x20, 0xd8, 0x42, 0x7e, 0xbf, 0xfc, 0x56, + 0xdd, 0x1f, 0x9c, 0x3a, 0x70, 0x45, 0x93, 0x01, 0x05, 0x37, + 0xb7, 0xff, 0x9f, 0x25, 0x5b, 0xb1, 0xbb, 0x87, 0x35, 0x02, + 0x70, 0x7e, 0x89, 0xb7, 0xf8, 0x5a, 0xb8, 0xb0, 0xb5, 0x04, + 0x4d, 0x2e, 0x11, 0xb9, 0x74, 0xa1, 0x95, 0xf0, 0x7f, 0x7b, + 0x38, 0x58, 0x50, 0x61, 0x9f, 0x3f, 0x80, 0x42, 0x7d, 0x15, + 0x82, 0x00, 0x1d, 0x85, 0x2b, 0x85, 0xf7, 0x14, 0x94, 0x60, + 0x42, 0x38, 0x28, 0xa8, 0x68, 0x2d, 0x28, 0x31, 0xbc, 0x36, + 0x48, 0x64, 0xc0, 0x21, 0x56, 0x30, 0xb9, 0xc0, 0x45, 0x90, + 0xe7, 0x12, 0x83, 0x84, 0xb1, 0x25, 0x86, 0x12, 0x18, 0x2d, + 0x08, 0xe8, 0x2a, 0x98, 0x8e, 0x0d, 0x00, 0xaa, 0x72, 0x75, + 0x61, 0x87, 0x00, 0x44, 0x57, 0xd4, 0x26, 0x02, 0x23, 0x90, + 0xc0, 0x04, 0x90, 0x80, 0x70, 0x46, 0x11, 0xe0, 0x20, 0x26, + 0x8c, 0x04, 0xa2, 0x88, 0x8e, 0x30, 0xc0, 0x30, 0x60, 0xdf, + 0xa2, 0xdf, 0x02, 0xd0, 0x01, 0x40, 0x99, 0x4e, 0xa4, 0x7f, + 0x84, 0x89, 0x63, 0x07, 0x0d, 0x19, 0x1d, 0x6c, 0x88, 0xca, + 0x1c, 0x1d, 0x07, 0x43, 0xc1, 0x02, 0x9c, 0x60, 0xa3, 0x09, + 0x0b, 0xc1, 0xfd, 0xa6, 0xa8, 0x21, 0x83, 0x8c, 0x08, 0x49, + 0x40, 0x56, 0xf9, 0xa6, 0x6a, 0x01, 0x52, 0x0d, 0x0e, 0x12, + 0xe1, 0x4c, 0xbf, 0x88, 0xe5, 0xa8, 0xb8, 0x02, 0x26, 0x0c, + 0x24, 0x74, 0x15, 0x38, 0x70, 0x25, 0x30, 0x24, 0x5e, 0xe0, + 0x22, 0x70, 0x68, 0x96, 0x7f, 0xec, 0x10, 0x23, 0x94, 0x30, + 0x61, 0x62, 0x38, 0xb0, 0x29, 0x2d, 0x78, 0x21, 0xb3, 0xca, + 0x40, 0xee, 0x11, 0xa0, 0x6f, 0xf8, 0x07, 0x71, 0x70, 0x47, + 0xb8, 0x5f, 0x5e, 0x89, 0x6c, 0x31, 0x58, 0x22, 0x0f, 0xff, + 0xf7, 0x17, 0x00, 0x30, 0x85, 0xf3, 0xc2, 0xb0, 0x55, 0xfe, + 0xbf, 0xfe, 0x0a, 0x7c, 0x16, 0x07, 0xf0, 0xdb, 0x81, 0xf9, + 0x40, 0x30, 0x81, 0x84, 0xac, 0x0f, 0xff, 0xe2, 0xb3, 0x4f, + 0xc3, 0x8d, 0x30, 0x76, 0x9a, 0x33, 0xa0, 0x10, 0x50, 0xc8, + 0x60, 0xae, 0x2b, 0x22, 0xff, 0xf8, 0xa9, 0x02, 0xf9, 0xf6, + 0x7a, 0x44, 0x37, 0x69, 0x8b, 0x01, 0x2b, 0x9f, 0xff, 0x81, + 0x60, 0x7a, 0xb9, 0x01, 0x0b, 0x27, 0x70, 0x40, 0xa1, 0x50, + 0x60, 0xa4, 0x61, 0xa1, 0x66, 0x30, 0x91, 0x55, 0x6f, 0xff, + 0xe6, 0x0d, 0x14, 0xae, 0xc8, 0x1a, 0x2c, 0x23, 0x4c, 0xc9, + 0x94, 0x4c, 0x07, 0x61, 0x0d, 0x46, 0x63, 0x89, 0xca, 0xbf, + 0xff, 0xea, 0x27, 0x0c, 0x30, 0x1e, 0x66, 0x1c, 0x13, 0x50, + 0xb0, 0xd8, 0x34, 0x02, 0x14, 0x30, 0x01, 0x54, 0x6a, 0xbf, + 0xff, 0x97, 0xa2, 0x3a, 0x83, 0x85, 0x04, 0x8a, 0xc2, 0x60, + 0xc0, 0x85, 0x57, 0x71, 0x61, 0x45, 0x22, 0x01, 0x07, 0x00, + 0x22, 0xff, 0xfb, 0x5b, 0xf1, 0x80, 0x8b, 0x46, 0x81, 0x68, + 0x02, 0xe2, 0x71, 0x00, 0x11, 0x81, 0x86, 0x2f, 0xff, 0xf7, + 0x5f, 0xdd, 0x42, 0x06, 0x03, 0x38, 0xb4, 0x01, 0xf6, 0xc0, + 0xff, 0xc7, 0xfb, 0xb8, 0x15, 0x0b, 0xfc, 0x1c, 0x09, 0x86, + 0x18, 0x30, 0x34, 0x15, 0x9c, 0x6a, 0x55, 0xff, 0xff, 0xbf, + 0xe2, 0xc0, 0xc3, 0x86, 0xe2, 0x38, 0x18, 0xb3, 0x14, 0x81, + 0xc0, 0x06, 0x04, 0xc2, 0x98, 0xb0, 0x12, 0x7f, 0xff, 0x8c, + 0x06, 0xbf, 0x71, 0x85, 0x0c, 0x08, 0x47, 0x11, 0x87, 0xa0, + 0xa4, 0xe0, 0x63, 0x0a, 0x0c, 0xae, 0x0a, 0xbf, 0xfe, 0xe0, + 0x78, 0xb0, 0x13, 0xb8, 0x20, 0xc3, 0x5d, 0xc5, 0x21, 0x44, + 0x82, 0x48, 0x00, 0x18, 0x24, 0x54, 0x00, 0x03, 0x5c, 0x1b, + 0xff, 0xc3, 0x9a, 0x16, 0x30, 0xb1, 0x85, 0x07, 0x38, 0xc8, + 0x59, 0x20, 0x81, 0x4c, 0x56, 0x75, 0x27, 0x0d, 0x08, 0x71, + 0x58, 0x47, 0x0e, 0x12, 0x85, 0x81, 0x61, 0xbf, 0xfc, 0x5a, + 0x4a, 0x0c, 0x28, 0x56, 0x20, 0x03, 0x14, 0x63, 0x0a, 0x2a, + 0x45, 0x80, 0xd1, 0x38, 0x28, 0x68, 0x32, 0x27, 0xa2, 0x05, + 0xff, 0xf7, 0x03, 0xe2, 0x30, 0x3c, 0x56, 0x61, 0x4e, 0x30, + 0x18, 0xad, 0x80, 0xdc, 0x15, 0x04, 0xa7, 0x0c, 0x18, 0x30, + 0x10, 0x38, 0x62, 0xff, 0xe1, 0x87, 0x3c, 0x20, 0x60, 0x63, + 0x0a, 0x02, 0x29, 0xf0, 0xc2, 0xa4, 0x2c, 0x04, 0x66, 0x2b, + 0x02, 0x72, 0xff, 0xce, 0x07, 0xd0, 0x10, 0x0e, 0x13, 0xc5, + 0x22, 0xc3, 0x02, 0x96, 0x10, 0x33, 0x18, 0x08, 0x1e, 0xe7, + 0xff, 0x9f, 0xd0, 0x61, 0xb9, 0x0a, 0xdf, 0xdc, 0x83, 0x85, + 0x61, 0x38, 0x61, 0x69, 0x24, 0x12, 0x7f, 0xf0, 0x3a, 0x73, + 0x03, 0x09, 0x87, 0x7c, 0x30, 0xb8, 0x58, 0x9c, 0x18, 0x30, + 0x05, 0xd0, 0x4c, 0xff, 0xcb, 0xe3, 0x86, 0x14, 0x5a, 0xc3, + 0x0b, 0x8a, 0xd7, 0x05, 0x15, 0x06, 0x0a, 0x00, 0x50, 0x78, + 0x93, 0xff, 0x7f, 0xc6, 0xc5, 0x97, 0xf0, 0x97, 0x18, 0x70, + 0x71, 0x8c, 0x14, 0x58, 0x03, 0xb4, 0x61, 0xa0, 0x7f, 0xef, + 0xae, 0x18, 0x29, 0x84, 0xee, 0xbf, 0x88, 0xa0, 0x33, 0x0e, + 0x11, 0x41, 0xfc, 0xff, 0xf1, 0xa8, 0xda, 0x1c, 0xa1, 0x81, + 0x05, 0x8a, 0x9f, 0xf1, 0x2c, 0x30, 0x55, 0x18, 0x40, 0xc2, + 0x7d, 0x8b, 0xf7, 0x8a, 0x80, 0x42, 0x58, 0x94, 0x30, 0x51, + 0x1c, 0x00, 0x83, 0x08, 0x4b, 0x3e, 0x1c, 0x1b, 0xe2, 0xb0, + 0x4b, 0x06, 0x03, 0x32, 0xa8, 0xc0, 0xc6, 0x08, 0xb5, 0x6c, + 0x02, 0xa6, 0x00, 0x22, 0xa0, 0xd8, 0x53, 0x1a, 0x0c, 0x0d, + 0x78, 0x97, 0x8c, 0x1c, 0x60, 0xa2, 0x5e, 0xc3, 0x21, 0x86, + 0x8c, 0x0c, 0x55, 0x41, 0x28, 0x46, 0x1b, 0x82, 0x35, 0x85, + 0x4e, 0x03, 0xc1, 0x62, 0x31, 0x8b, 0x83, 0x0b, 0x18, 0x54, + 0x30, 0xbc, 0x1c, 0x38, 0x13, 0x02, 0x08, 0x03, 0x18, 0x08, + 0x86, 0x1a, 0x36, 0x09, 0x33, 0x15, 0x1d, 0x00, 0x0b, 0xf0, + 0xc1, 0x60, 0x2c, 0x0c, 0x58, 0x13, 0x01, 0xc6, 0x0e, 0xa2, + 0xc7, 0x87, 0x0b, 0x3e, 0x16, 0x40, 0x22, 0x88, 0xb8, 0x27, + 0x11, 0x07, 0x07, 0x04, 0xf4, 0xfb, 0x84, 0x30, 0x8e, 0x08, + 0x30, 0xb2, 0x18, 0x08, 0xd8, 0x53, 0xf8, 0x8a, 0x5f, 0x15, + 0x86, 0x10, 0x1b, 0x54, 0x03, 0x11, 0x40, 0x3f, 0xe8, 0x30, + 0x84, 0x15, 0x02, 0xc4, 0x61, 0x44, 0x61, 0x62, 0xe1, 0x7f, + 0xba, 0x84, 0xe1, 0x03, 0x0b, 0x1a, 0x02, 0x2c, 0xcb, 0xfc, + 0x39, 0xc2, 0x4c, 0x26, 0x36, 0x18, 0x68, 0x19, 0x5d, 0x7f, + 0x49, 0x5c, 0x61, 0xc2, 0xd0, 0xa7, 0x42, 0xfe, 0xeb, 0x9a, + 0x01, 0x10, 0x10, 0x9c, 0x2b, 0x46, 0x00, 0x08, 0x91, 0x60, + 0x61, 0x5f, 0x1a, 0x0a, 0xce, 0x2c, 0x0b, 0x30, 0xc2, 0xff, + 0x41, 0x1f, 0xf8, 0xc0, 0x23, 0x03, 0x18, 0x69, 0x62, 0x58, + 0x0f, 0xe0, 0x43, 0x02, 0x11, 0x85, 0x21, 0x84, 0xf7, 0xff, + 0xb7, 0xc6, 0x14, 0x50, 0xc1, 0x0c, 0x66, 0xa1, 0x2e, 0xb0, + 0xc0, 0xa5, 0xd0, 0xcc, 0xc6, 0x15, 0xa8, 0xa5, 0xfc, 0x38, + 0x4b, 0x00, 0xe1, 0xc0, 0x25, 0xc4, 0x54, 0x09, 0x14, 0x50, + 0x4b, 0xd2, 0x25, 0xc5, 0x68, 0xac, 0x2a, 0x04, 0xe2, 0x90, + 0x27, 0xf1, 0x2f, 0xdc, 0x61, 0x67, 0xe2, 0x32, 0x0d, 0xc0, + 0x80, 0xe2, 0xb6, 0x2b, 0x0d, 0x8a, 0x18, 0x30, 0x51, 0x4a, + 0xbb, 0xff, 0xfc, 0x4e, 0xfc, 0x6a, 0xa2, 0xb0, 0x97, 0x0e, + 0x75, 0x0c, 0x21, 0x82, 0x06, 0x8b, 0x11, 0x86, 0x8c, 0x38, + 0x2c, 0x0c, 0x5a, 0x97, 0xff, 0x83, 0x17, 0x87, 0x20, 0x96, + 0x29, 0x05, 0x8a, 0xc6, 0x10, 0x2b, 0x38, 0x20, 0xc0, 0x06, + 0xc0, 0x82, 0xc0, 0xc8, 0x60, 0x4a, 0x1a, 0xd1, 0xaf, 0xff, + 0xb8, 0xc3, 0x38, 0x43, 0x04, 0x8a, 0x31, 0x81, 0x0a, 0x30, + 0x81, 0x86, 0x8c, 0x2c, 0x08, 0x5c, 0x18, 0x00, 0x0b, 0x82, + 0x84, 0x60, 0x0e, 0x07, 0xff, 0xf1, 0x2f, 0x0c, 0x13, 0x40, + 0x84, 0xe5, 0x41, 0x58, 0x1d, 0xf1, 0x90, 0x70, 0x94, 0x30, + 0xa6, 0x02, 0x82, 0x90, 0xb5, 0x81, 0xff, 0xfc, 0xf1, 0xbe, + 0x60, 0x4c, 0x18, 0x30, 0xe1, 0x84, 0x0a, 0x50, 0x21, 0x80, + 0x90, 0xb0, 0x2d, 0x30, 0xb4, 0x34, 0x04, 0x11, 0x6f, 0xff, + 0xf8, 0x5c, 0x61, 0x45, 0xe0, 0x40, 0x22, 0x30, 0xaa, 0x18, + 0x30, 0x41, 0x2c, 0x60, 0xc3, 0x09, 0x11, 0xe8, 0x42, 0x30, + 0x8e, 0x04, 0x0c, 0x2b, 0x7f, 0xfe, 0x80, 0x45, 0xf8, 0x8e, + 0x23, 0x0d, 0xc3, 0x81, 0x04, 0x51, 0x14, 0x0f, 0xe2, 0x1a, 0x10, + 0x07, 0xf2, 0x48, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x29, 0x96, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x92, 0x03, 0x42, 0x1e, 0xc1, + 0x80, 0xba, 0x03, 0x54, 0x13, 0xe6, 0x88, 0xc0, 0xb6, 0x28, + 0x30, 0x39, 0x08, 0x01, 0x48, 0x53, 0x16, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x07, 0x81, 0x00, 0x00, + 0x00, 0x50, 0x2b, 0x0a, 0x42, 0x50, 0x45, 0x85, 0x4e, 0x08, + 0x64, 0x0c, 0x58, 0x86, 0x30, 0x06, 0x06, 0x70, 0x24, 0x00, + 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x44, 0xb6, 0x1f, 0xe4, 0xb6, 0x31, 0x25, 0x43, 0xb1, 0x87, + 0xc1, 0x11, 0x86, 0xa1, 0x10, 0xe4, 0x3d, 0x5e, 0x1c, 0x42, + 0xe9, 0x64, 0xb9, 0x6b, 0x80, 0x29, 0x85, 0xdb, 0xc3, 0x4c, + 0x52, 0xb0, 0x84, 0x86, 0x88, 0x0c, 0x00, 0x02, 0x43, 0xb3, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x83, 0x00, 0x00, + 0x0a, 0x26, 0x8a, 0x1e, 0x82, 0x98, 0x07, 0x01, 0x51, 0x85, + 0x80, 0x42, 0x11, 0x8f, 0xd2, 0x30, 0xbf, 0x0a, 0x09, 0xcb, + 0x45, 0x10, 0x98, 0x78, 0x18, 0xe0, 0xf8, 0xf4, 0x2d, 0x01, + 0x80, 0xc0, 0x60, 0x30, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xd8, 0x24, 0x00, 0x14, 0x87, 0xe0, 0x11, 0x01, 0xc1, + 0x2a, 0x07, 0x07, 0x01, 0x81, 0xa1, 0x9e, 0x74, 0x38, 0x1c, + 0x0e, 0x04, 0x2c, 0x21, 0x84, 0x02, 0xd4, 0x31, 0x00, 0xa8, + 0x82, 0x36, 0x30, 0xc8, 0xe4, 0x0c, 0x32, 0xbb, 0x8a, 0xb7, + 0x00, 0x98, 0x08, 0x2e, 0x61, 0xec, 0x00, 0x4a, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xbf, 0xf8, 0x04, 0x03, 0x40, 0x00, + 0x45, 0xe9, 0x40, 0x40, 0xd2, 0x0a, 0x84, 0x78, 0xf4, 0x66, + 0xf8, 0x4a, 0x92, 0x82, 0x4c, 0xc9, 0xd0, 0x12, 0xb4, 0x68, + 0x83, 0x27, 0xb0, 0x36, 0x02, 0x80, 0x98, 0x09, 0x84, 0xe1, + 0x60, 0x0c, 0x0d, 0x03, 0x74, 0x0b, 0x86, 0x40, 0x1e, 0x89, + 0xf0, 0x1f, 0x81, 0x4e, 0x00, 0x2b, 0xf0, 0x04, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x78, 0x00, 0x00, 0x09, 0x96, 0x24, + 0x09, 0x0d, 0x14, 0x03, 0x87, 0x80, 0xe8, 0x54, 0x09, 0x0f, + 0xf4, 0x09, 0x33, 0x9e, 0xd0, 0x4e, 0x0c, 0x31, 0x80, 0x41, + 0x84, 0x98, 0xe3, 0xc1, 0x88, 0x27, 0xa0, 0xd2, 0x0a, 0x90, + 0x66, 0x4b, 0x0d, 0xc0, 0xac, 0x61, 0x97, 0x9c, 0x12, 0x1b, + 0xec, 0x51, 0x5c, 0x48, 0xa2, 0x9e, 0x1d, 0x03, 0x12, 0x03, + 0x0c, 0xe4, 0x53, 0xb2, 0x80, 0x1c, 0xe2, 0xc2, 0xc0, 0x00, + 0x00, 0x00, 0x00, 0x05, 0x60, 0x01, 0x57, 0x04, 0x86, 0x48, + 0x04, 0xf9, 0x01, 0x20, 0x2e, 0x15, 0x94, 0x01, 0x0e, 0xf2, + 0x9f, 0x40, 0x51, 0x6c, 0x0d, 0x06, 0x24, 0x50, 0x48, 0x00, + 0x83, 0x65, 0x05, 0x67, 0x25, 0x36, 0x7a, 0x26, 0x83, 0xd1, + 0x9e, 0xc2, 0x7f, 0x40, 0xd0, 0x2a, 0x14, 0x26, 0xb8, 0xac, + 0x64, 0x86, 0xd8, 0x47, 0x84, 0x89, 0x4e, 0x79, 0xc8, 0x21, + 0x4c, 0x24, 0x17, 0xa6, 0x6a, 0x51, 0x32, 0x6b, 0x93, 0x20, + 0xa1, 0x72, 0x65, 0x97, 0x77, 0x03, 0x18, 0x88, 0x41, 0xe0, + 0x88, 0x40, 0x21, 0x4e, 0xb6, 0x05, 0x60, 0x02, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x8f, 0x03, 0x44, 0xc0, + 0x23, 0x20, 0x06, 0x88, 0x32, 0x16, 0x19, 0xc2, 0xc9, 0x79, + 0xf4, 0xd9, 0x3d, 0x32, 0x22, 0xc9, 0x4e, 0x41, 0x80, 0x4c, + 0x34, 0x0b, 0x31, 0x82, 0x19, 0x80, 0x93, 0x3c, 0xf2, 0x04, + 0xa4, 0x39, 0x21, 0x8c, 0xd6, 0x12, 0x40, 0x80, 0x84, 0x1a, + 0x6e, 0xe3, 0x09, 0xe8, 0x4c, 0x1a, 0x00, 0xe0, 0x49, 0xa8, + 0x02, 0xb2, 0x31, 0x06, 0x60, 0xf8, 0x28, 0x11, 0x68, 0x24, + 0x14, 0x82, 0xfc, 0x82, 0xf9, 0x82, 0x07, 0x48, 0xab, 0x25, + 0xca, 0x0e, 0x44, 0x6a, 0x28, 0x24, 0x28, 0x54, 0x1a, 0x80, + 0x44, 0x46, 0x80, 0xa4, 0x63, 0x2e, 0x02, 0x90, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x21, 0xbf, 0xc1, 0xa0, 0x78, 0x2c, + 0xc5, 0xde, 0x80, 0xc0, 0x4c, 0x22, 0x22, 0x53, 0x01, 0xc8, + 0x38, 0x18, 0x42, 0xbb, 0x05, 0xb3, 0x26, 0xc0, 0xf6, 0x4b, + 0x01, 0xd0, 0x12, 0x01, 0xac, 0x0f, 0x18, 0x73, 0x6d, 0x2c, + 0x8c, 0x85, 0x28, 0x4c, 0x90, 0x80, 0x10, 0x82, 0x5d, 0x50, + 0x13, 0xd6, 0x34, 0xc8, 0x08, 0x4b, 0x09, 0x86, 0x64, 0x06, + 0xb3, 0xdd, 0xa6, 0x4b, 0xd2, 0x6c, 0x97, 0x27, 0xf0, 0x8d, + 0x45, 0xd1, 0x81, 0xc2, 0x0c, 0x2e, 0x44, 0x98, 0xe1, 0x26, + 0xbd, 0xaa, 0x12, 0x6b, 0xfb, 0x80, 0x90, 0xdc, 0x42, 0x16, + 0xdf, 0xd4, 0xd4, 0x08, 0x5c, 0xa3, 0x75, 0xbc, 0x82, 0x09, + 0x83, 0x01, 0x81, 0x70, 0xbb, 0x30, 0xb4, 0x41, 0x4c, 0x68, + 0x30, 0x29, 0x02, 0x82, 0x1f, 0x0c, 0x71, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x07, 0x83, 0x80, 0x18, 0x06, 0x10, 0x47, 0x43, + 0xb0, 0x48, 0x81, 0xa0, 0x13, 0x6d, 0x9c, 0x84, 0xc5, 0xd9, + 0x85, 0x6e, 0x15, 0x79, 0x5c, 0xc5, 0x32, 0xf8, 0x51, 0x31, + 0x96, 0x2e, 0x00, 0x01, 0x05, 0xc0, 0x92, 0x89, 0x08, 0x60, + 0x9b, 0x32, 0x58, 0x25, 0xad, 0xc0, 0x8a, 0x18, 0x66, 0x43, + 0x58, 0x51, 0xb0, 0x11, 0x08, 0x94, 0x01, 0x22, 0x5b, 0xe0, + 0x4c, 0x84, 0x14, 0x80, 0x4a, 0x9c, 0x02, 0x8a, 0x00, 0x38, + 0xe1, 0xf5, 0x3b, 0x20, 0x21, 0x28, 0x1e, 0x0b, 0xd8, 0x80, + 0x81, 0x8a, 0x89, 0x64, 0xb1, 0x2f, 0xe3, 0x30, 0x2d, 0xd4, + 0x20, 0x08, 0x43, 0xf1, 0x19, 0x0a, 0x85, 0x9e, 0xb2, 0xd0, + 0x00, 0x54, 0x56, 0x50, 0x2c, 0x04, 0x80, 0xee, 0x0e, 0x8a, + 0x54, 0x29, 0x10, 0xa5, 0x82, 0xfb, 0x82, 0xc3, 0x80, 0x10, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x37, 0xf0, 0x00, 0x01, + 0xeb, 0x59, 0x3d, 0x83, 0x21, 0x41, 0xf6, 0xdd, 0x22, 0xc9, + 0x72, 0x6c, 0x8a, 0xc1, 0x04, 0x9a, 0x5b, 0x94, 0x12, 0x1e, + 0x5a, 0x09, 0x11, 0x2c, 0x0a, 0x2d, 0x05, 0x6b, 0x57, 0x64, + 0xcc, 0x34, 0x47, 0x00, 0x88, 0x2a, 0xa0, 0x7a, 0x41, 0x8b, + 0xb2, 0x88, 0x20, 0x9b, 0xf0, 0x24, 0x40, 0x46, 0x09, 0x54, + 0xe0, 0x68, 0x27, 0xf0, 0x09, 0x68, 0x80, 0xb4, 0x23, 0x53, + 0x38, 0x84, 0x1f, 0x02, 0x6d, 0x62, 0x05, 0x78, 0x49, 0x98, + 0x0e, 0x18, 0xc6, 0x43, 0x20, 0x21, 0x02, 0x0a, 0x44, 0x64, + 0x1c, 0x1d, 0x04, 0xa0, 0xc8, 0x07, 0x07, 0xe1, 0x28, 0xa6, + 0x6c, 0x37, 0xc5, 0x51, 0x86, 0xdd, 0x00, 0xbd, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x2b, 0x80, 0x01, 0xb3, 0x13, 0xe8, 0x76, + 0x09, 0xea, 0x04, 0x23, 0x0b, 0x21, 0x01, 0x02, 0x18, 0x07, + 0x00, 0x8c, 0xd2, 0x0d, 0x64, 0xc8, 0x1b, 0x09, 0x30, 0x48, + 0xa5, 0x97, 0x0d, 0x20, 0xa0, 0x91, 0x27, 0x08, 0x32, 0x41, + 0x56, 0x04, 0x99, 0xcf, 0x20, 0x4a, 0x09, 0xb8, 0x86, 0x49, + 0x19, 0xc0, 0x48, 0xd4, 0xf3, 0x82, 0xae, 0x38, 0x63, 0x04, + 0x26, 0x16, 0x1e, 0x30, 0xd7, 0x4c, 0x80, 0x12, 0x50, 0xfd, + 0x92, 0xe2, 0x03, 0x9f, 0x40, 0x2b, 0x67, 0x38, 0x16, 0x17, + 0x4f, 0xf9, 0x76, 0xaf, 0x09, 0x8b, 0xb9, 0x84, 0x00, 0x02, + 0x8f, 0x2c, 0x00, 0x5d, 0x03, 0x50, 0x00, 0x42, 0x13, 0x06, + 0x60, 0x96, 0xc3, 0xd0, 0x00, 0x3c, 0x10, 0xc0, 0x4e, 0x02, + 0x00, 0x04, 0xe0, 0xf0, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x24, 0x1b, 0xe0, 0x00, 0x04, 0x02, 0xe9, 0x4c, 0x97, 0x26, + 0x40, 0x70, 0x24, 0x3b, 0x50, 0xb6, 0x40, 0x54, 0x41, 0x26, + 0x79, 0xa4, 0x94, 0xbc, 0xc5, 0x97, 0x18, 0x61, 0x88, 0x2e, + 0x70, 0x22, 0x62, 0x3c, 0x02, 0x05, 0x80, 0x90, 0xea, 0x06, + 0x68, 0xf4, 0xb2, 0x66, 0x06, 0x09, 0x33, 0x07, 0x54, 0x83, + 0x64, 0xcc, 0x28, 0xc1, 0x60, 0xba, 0x08, 0x8d, 0x1a, 0xf1, + 0xa0, 0x84, 0x85, 0x81, 0x94, 0x23, 0x06, 0x2f, 0x22, 0xb2, +}; + +static const guint8 bframe2_adv[] = { + 0x46, 0x88, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0xf8, 0xa1, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, +}; + +static const guint8 pframe_adv[] = { + 0x24, 0x20, 0x04, 0xbf, 0x85, 0x88, 0x65, 0xc1, 0x00, 0xdc, + 0x4c, 0x06, 0xce, 0x05, 0x01, 0x01, 0x41, 0x0c, 0x60, 0x42, + 0x67, 0xff, 0xfb, 0x85, 0x0b, 0x9c, 0x56, 0x0d, 0x0b, 0x1b, + 0x8c, 0x08, 0x08, 0x47, 0x1b, 0xce, 0xc1, 0x83, 0x09, 0x8a, + 0xa1, 0x83, 0x09, 0x16, 0x7f, 0xff, 0x98, 0x94, 0xff, 0x81, + 0x4f, 0xf9, 0x41, 0xe1, 0x83, 0x01, 0xff, 0xff, 0x14, 0x40, + 0xcd, 0x70, 0xd7, 0xf2, 0xf7, 0xc1, 0xf1, 0x18, 0x59, 0xff, + 0xfc, 0x51, 0x18, 0x68, 0x2c, 0xd4, 0x54, 0x16, 0xbf, 0xfe, + 0x0c, 0xf1, 0x81, 0x28, 0x67, 0xff, 0x86, 0x39, 0x05, 0xe6, + 0x5f, 0xff, 0xe0, 0x48, 0xc0, 0xff, 0xfe, 0x61, 0x18, 0x37, + 0xff, 0x97, 0xdc, 0x1c, 0x45, 0x06, 0x06, 0xff, 0xf0, 0x30, + 0x7d, 0x17, 0xff, 0xff, 0x86, 0x07, 0x03, 0xff, 0xf9, 0x01, + 0xf0, 0x7f, 0xff, 0xdf, 0xc1, 0x20, 0x9f, 0xfd, 0x0c, 0x0f, + 0x86, 0x7f, 0xff, 0xee, 0x50, 0xef, 0xfe, 0xc1, 0xa5, 0xc6, + 0x1b, 0xff, 0xff, 0x86, 0x61, 0x9f, 0xfc, 0x1c, 0x1f, 0xa2, + 0xff, 0xff, 0xe0, 0xf8, 0x10, 0x1f, 0xfe, 0x0e, 0x0f, 0x99, + 0x95, 0xff, 0xff, 0xb8, 0x3e, 0xe5, 0xff, 0x81, 0x83, 0xe1, + 0x6b, 0xff, 0xff, 0x40, 0xc0, 0x7c, 0x30, 0xbf, 0xe0, 0xb2, + 0x0e, 0x09, 0x61, 0x53, 0xff, 0xfd, 0x60, 0x20, 0xfc, 0x27, + 0xf0, 0x96, 0x51, 0x26, 0x6c, 0xcf, 0xff, 0xff, 0xe7, 0x60, + 0xe0, 0xb5, 0xee, 0x82, 0xa0, 0xb8, 0x41, 0x32, 0x3f, 0x2f, + 0xcd, 0x3f, 0xa0, 0xa8, 0x96, 0x8e, 0x2a, 0x4c, 0x08, 0x6e, + 0x36, 0x1a, 0x83, 0x2a, 0x8b, 0x02, 0xcb, 0x2f, 0xff, 0xe9, + 0xf8, 0xa4, 0x0e, 0x00, 0x12, 0xc1, 0x88, 0xc3, 0x0c, 0x05, + 0x51, 0x44, 0x61, 0xa3, 0x0b, 0x18, 0x58, 0x38, 0x70, 0x97, + 0xff, 0xff, 0xf8, 0x8c, 0x14, 0x2c, 0x0c, 0x19, 0x86, 0x0c, + 0x27, 0x09, 0xc1, 0x03, 0x08, 0x62, 0xc0, 0xff, 0xff, 0xfe, + 0x94, 0x6d, 0x22, 0x77, 0xc0, 0x44, 0x71, 0x1c, 0x60, 0xe5, + 0xb7, 0xff, 0xfe, 0xbf, 0xba, 0x57, 0x82, 0x0c, 0x24, 0xc8, + 0x5a, 0xbf, 0xff, 0xff, 0xcb, 0x14, 0xc8, 0x30, 0x43, 0x16, + 0x29, 0x51, 0x86, 0x0b, 0x00, 0x51, 0x60, 0x60, 0xc0, 0x17, + 0x75, 0xff, 0xf9, 0x77, 0x0e, 0x18, 0x4b, 0x84, 0xc5, 0x47, + 0x11, 0xc5, 0x10, 0x68, 0x1b, 0x8c, 0x00, 0x6a, 0x71, 0x60, + 0xc0, 0x46, 0xe2, 0xe0, 0x22, 0x65, 0xff, 0xd6, 0x09, 0x0e, + 0x01, 0x15, 0x55, 0x85, 0x48, 0x28, 0x8f, 0xc2, 0x42, 0x06, + 0x1c, 0x23, 0x8b, 0x01, 0x42, 0x74, 0x08, 0x61, 0x9f, 0xff, + 0xc2, 0xca, 0x19, 0x81, 0x02, 0x10, 0x20, 0xc0, 0x1c, 0x5c, + 0x13, 0x84, 0xe6, 0x1a, 0x8b, 0x02, 0x38, 0x98, 0x09, 0x98, + 0xa3, 0xff, 0xfd, 0xc9, 0x05, 0x5e, 0x82, 0x18, 0xc1, 0x40, + 0xc6, 0xf6, 0x04, 0x14, 0x40, 0x60, 0x80, 0xfd, 0x04, 0x6f, + 0xff, 0xf4, 0x58, 0x0a, 0xf8, 0x86, 0x30, 0x02, 0x14, 0x44, + 0xe2, 0xc2, 0x43, 0x3c, 0x1b, 0xff, 0x86, 0xb5, 0x66, 0x16, + 0xf0, 0x7f, 0xa0, 0x9c, 0x5e, 0x84, 0x07, 0xd1, 0x73, 0xff, + 0xee, 0x88, 0xc2, 0xe1, 0x7f, 0xfc, 0xc0, 0xf0, 0x59, 0x65, + 0xfe, 0x9f, 0x70, 0xbf, 0xff, 0xdc, 0x1e, 0x2a, 0x02, 0x57, + 0xff, 0xc0, 0x26, 0x2d, 0x3c, 0x4d, 0x5f, 0xff, 0xc4, 0xc1, + 0x30, 0x11, 0x15, 0xc4, 0xaf, 0xfc, 0x5c, 0x0e, 0x0e, 0x0e, + 0x84, 0x8c, 0x34, 0x34, 0xbf, 0xff, 0x11, 0x81, 0x30, 0x10, + 0x48, 0x87, 0xf9, 0x43, 0x05, 0x25, 0x04, 0x11, 0x43, 0x70, + 0x4f, 0xff, 0xfd, 0x04, 0xe1, 0x0e, 0xfe, 0x6f, 0x83, 0x88, + 0xe1, 0x98, 0x76, 0x0f, 0xfc, 0x89, 0x0e, 0xe7, 0xc2, 0x78, + 0x4c, 0x24, 0xd4, 0x18, 0x8c, 0xbf, 0x27, 0x16, 0xd0, 0xb0, + 0xc9, 0xf4, 0x12, 0x6a, 0x08, 0xe4, 0x5c, 0x24, 0xbf, 0x46, + 0x60, 0xf6, 0x53, 0xf5, 0x6c, 0xff, 0x2e, 0x32, 0x09, 0x1e, + 0xab, 0x09, 0x00, 0x1e, 0x88, 0x56, 0x6e, 0x7a, 0x1c, 0xd0, + 0x30, 0x3c, 0xab, 0xf0, 0x44, 0x5a, 0x90, 0x4f, 0x9a, 0xf0, + 0xe6, 0x7d, 0x62, 0xc1, 0x87, 0x4b, 0xdb, 0xfd, 0x68, 0xd9, + 0x35, 0x3b, 0x01, 0x04, 0x81, 0x2c, 0x24, 0xee, 0xb3, 0x9b, + 0x65, 0x30, 0x49, 0x20, 0xa8, 0x08, 0xf6, 0xaf, 0x33, 0x80, + 0x38, 0x49, 0xa3, 0x94, 0x6e, 0x35, 0x06, 0x4d, 0xc3, 0x30, + 0x92, 0x7c, 0x3c, 0x6b, 0x9e, 0xd5, 0x31, 0x4d, 0x69, 0x87, + 0x2e, 0x04, 0x7e, 0x04, 0x12, 0x5f, 0xa3, 0x0a, 0xe4, 0x5b, + 0x21, 0x6c, 0x45, 0x54, 0x29, 0x11, 0x48, 0x8a, 0xa8, 0x52, + 0x22, 0xa8, 0x33, 0x06, 0xe0, 0xbd, 0xe8, 0x41, 0x00, 0x03, + 0x52, 0xe7, 0x00, 0x7d, 0xf0, 0x42, 0x4d, 0x0f, 0x20, 0x26, + 0x24, 0x09, 0xbb, 0x48, 0x1c, 0xeb, 0xa5, 0xa2, 0x0e, 0xed, + 0x11, 0x66, 0x97, 0x93, 0xb8, 0x4a, 0x70, 0x8a, 0x75, 0x38, + 0x47, 0xc1, 0x26, 0x3e, 0x50, 0x87, 0x33, 0xf2, 0x37, 0xc7, + 0x3b, 0x67, 0x09, 0x33, 0x44, 0xfc, 0xcd, 0xda, 0x19, 0xa6, + 0x3f, 0x27, 0xec, 0x24, 0x12, 0x64, 0x06, 0x13, 0xdd, 0x9e, + 0x81, 0x92, 0x17, 0x5f, 0xb3, 0xd9, 0x37, 0xf2, 0x0f, 0x15, + 0x00, 0x87, 0xb3, 0xe6, 0xc9, 0xc1, 0xbc, 0x24, 0x7f, 0x0f, + 0x7c, 0x76, 0x4c, 0xe0, 0xfb, 0xf7, 0x66, 0x4c, 0x9c, 0x19, + 0x32, 0x6f, 0xb2, 0x64, 0xfa, 0x00, 0x01, 0x26, 0xaa, 0xa4, + 0x16, 0x45, 0x1f, 0x94, 0xee, 0xde, 0x33, 0x09, 0x2e, 0x48, + 0xc2, 0x4b, 0xf4, 0x62, 0x91, 0x16, 0x00, 0x52, 0x20, 0xe2, + 0xba, 0xe2, 0x35, 0x42, 0xa7, 0xa0, 0x9c, 0x9e, 0xcc, 0x39, + 0x9d, 0x31, 0x00, 0xc3, 0xe0, 0x2a, 0x1f, 0x85, 0x61, 0xd3, + 0x63, 0x3f, 0x22, 0xa8, 0xd9, 0xc1, 0x50, 0x50, 0x2f, 0x21, + 0xb1, 0xd8, 0x49, 0x34, 0xa0, 0xb0, 0x0c, 0x7d, 0xe9, 0x53, + 0x27, 0x09, 0xf9, 0x1b, 0x33, 0x5d, 0x93, 0xb8, 0x48, 0x89, + 0xbb, 0x18, 0x4e, 0xf0, 0x44, 0x86, 0x13, 0x7a, 0x16, 0xc4, + 0x36, 0xc7, 0x24, 0xe2, 0x39, 0x20, 0x20, 0x62, 0xb0, 0xf1, + 0xa0, 0x21, 0xc7, 0x2a, 0xdf, 0xd6, 0xd1, 0x5e, 0xcf, 0xba, + 0x09, 0x92, 0xa4, 0xb7, 0xd6, 0x7b, 0x0b, 0xaa, 0x60, 0xe7, + 0x8c, 0xe2, 0xfb, 0xf8, 0xb1, 0x96, 0x70, 0xc5, 0xf7, 0x3d, + 0x7a, 0xce, 0x13, 0x09, 0x0f, 0xd4, 0x2c, 0xfe, 0x30, 0xdd, + 0xdc, 0x11, 0xb1, 0x4e, 0xab, 0x98, 0x0d, 0x45, 0xf0, 0x41, + 0x9d, 0x0c, 0xd6, 0xa1, 0x8e, 0x5c, 0xf4, 0xdf, 0x93, 0x88, + 0x3f, 0x23, 0x61, 0x23, 0x6e, 0xf4, 0x78, 0xac, 0xfa, 0x00, + 0x00, 0x07, 0x1f, 0x94, 0xe9, 0x13, 0xd3, 0x05, 0x61, 0x99, + 0x22, 0x49, 0xf8, 0x6d, 0xb9, 0xb3, 0x83, 0xa6, 0x70, 0x78, + 0xf3, 0x37, 0x54, 0xdf, 0xb6, 0x82, 0x67, 0x07, 0x3d, 0x66, + 0xea, 0x86, 0x72, 0xd3, 0x38, 0x3b, 0x0a, 0xcd, 0xd5, 0x0e, + 0x00, 0x07, 0x19, 0x6d, 0x92, 0x77, 0x3e, 0x0d, 0xba, 0x66, + 0xa6, 0x8c, 0x8d, 0x48, 0xf2, 0xe2, 0x38, 0x31, 0x7f, 0x71, + 0xf9, 0xe8, 0x6c, 0x46, 0xb1, 0x91, 0xc5, 0x6a, 0xbb, 0x16, + 0x36, 0x44, 0xb3, 0x67, 0x64, 0xcf, 0xee, 0xcc, 0x04, 0x61, + 0x7b, 0x91, 0x7e, 0xcd, 0x47, 0x27, 0x16, 0x0f, 0x04, 0x8f, + 0x02, 0x84, 0x8f, 0x85, 0xb5, 0xb3, 0x5a, 0x81, 0x23, 0xa8, +}; + +static const guint8 pframe2_adv[] = { + 0x1c, 0x22, 0x1f, 0xdc, 0x9d, 0x3b, 0x81, 0x61, 0x85, 0x2, + 0x57, 0xa0, 0x50, 0xac, 0x03, 0x81, 0x0c, 0x39, 0x4f, 0xff, + 0xc2, 0x20, 0x9f, 0xf4, 0x86, 0x16, 0x8e, 0xe1, 0xda, 0x0c, + 0x24, 0x4b, 0x3f, 0xff, 0x03, 0x77, 0xfe, 0x05, 0x10, 0xc5, + 0x81, 0x3a, 0x50, 0x71, 0x4c, 0x56, 0x10, 0xfa, 0x06, 0x82, + 0xaf, 0xfe, 0x19, 0x49, 0x17, 0xb6, 0x42, 0xad, 0xf0, 0xe8, + 0x6f, 0xc0, 0x97, 0xff, 0x83, 0xd0, 0xce, 0x15, 0x16, 0x85, + 0xa6, 0x77, 0x09, 0xb3, 0xe1, 0x88, 0x30, 0xd0, 0x0f, 0x18, + 0x60, 0x40, 0x5f, 0xfe, 0x07, 0x6f, 0x6c, 0x18, 0x09, 0xdf, + 0xc3, 0x00, 0xee, 0x98, 0x39, 0x8b, 0x40, 0xff, 0xf8, 0x64, + 0xfb, 0xae, 0xae, 0x25, 0xc1, 0x61, 0xa1, 0xa1, 0x63, 0x06, + 0xba, 0xb8, 0x9a, 0x00, 0xe6, 0x40, 0x75, 0xff, 0x08, 0xfc, + 0xa2, 0x88, 0xa2, 0xf7, 0xd4, 0x47, 0xe2, 0x8b, 0x20, 0x11, + 0x02, 0xe0, 0xc1, 0x80, 0xdf, 0xe0, 0xff, 0xe2, 0x18, 0xe0, + 0x40, 0x42, 0xe0, 0xc0, 0x82, 0x59, 0x49, 0x9c, 0x4c, 0x60, + 0x95, 0x86, 0x60, 0xff, 0xf8, 0x22, 0x7d, 0x21, 0xa1, 0x62, + 0x60, 0xc0, 0x06, 0x06, 0x30, 0x90, 0xa0, 0xc1, 0xbb, 0xa0, + 0x10, 0x8e, 0xcf, 0xca, 0x17, 0x4f, 0xf0, 0x34, 0xfb, 0x00, + 0x88, 0xe0, 0xa3, 0x07, 0x04, 0x18, 0x30, 0xe2, 0xc8, 0x50, + 0xb4, 0x14, 0xac, 0x12, 0x9d, 0x30, 0xcf, 0xfb, 0x97, 0xeb, + 0x42, 0x14, 0x83, 0x45, 0x30, 0x31, 0x70, 0x4d, 0x14, 0xc5, + 0x10, 0x51, 0x4c, 0x61, 0x21, 0x4f, 0xf8, 0x1d, 0x7f, 0x0c, + 0xf8, 0x30, 0x1e, 0xa3, 0x00, 0x08, 0x0b, 0x15, 0x46, 0x0a, + 0x0a, 0x26, 0x87, 0x02, 0x06, 0x0a, 0xa3, 0x0a, 0x54, 0x18, + 0x62, 0x80, 0x70, 0x3f, 0xf0, 0xcf, 0xe6, 0x0e, 0x1a, 0x82, + 0x34, 0x30, 0x59, 0x14, 0xc6, 0xa3, 0x04, 0x18, 0x70, 0xc1, + 0x82, 0xc6, 0x05, 0x21, 0x27, 0xe0, 0x7f, 0xe1, 0x8d, 0xae, + 0x91, 0x6a, 0x1c, 0x04, 0x30, 0x00, 0xc1, 0xba, 0x90, 0x59, + 0x89, 0xda, 0xd4, 0x61, 0x8b, 0xc1, 0xfe, 0xda, 0x8c, 0x30, + 0xa0, 0x3d, 0xa3, 0x06, 0x0d, 0x01, 0x85, 0x08, 0x6e, 0x16, + 0x04, 0x30, 0x01, 0x30, 0x51, 0x06, 0x15, 0x1a, 0x03, 0xe2, + 0xd5, 0xeb, 0xa1, 0x98, 0x2d, 0x02, 0x97, 0x77, 0x57, 0x16, + 0x05, 0x61, 0x14, 0x92, 0x32, 0x50, 0x01, 0x4c, 0x46, 0x18, + 0x40, 0x97, 0x9a, 0x0a, 0x97, 0x70, 0xaf, 0x84, 0x84, 0xbd, + 0x7a, 0x45, 0x60, 0xa1, 0x14, 0x47, 0x17, 0x06, 0x00, 0x30, + 0x29, 0x44, 0x51, 0x24, 0x60, 0x62, 0x30, 0x15, 0x08, 0x19, + 0xda, 0xa2, 0x32, 0x06, 0x81, 0xf0, 0x0c, 0x30, 0x43, 0xeb, + 0x00, 0x06, 0x40, 0x60, 0x40, 0xb0, 0xe1, 0x68, 0x34, 0x0c, + 0x04, 0x6e, 0x29, 0x08, 0xc3, 0x01, 0x1b, 0x06, 0xe0, 0x00, + 0x37, 0x55, 0x03, 0xdc, 0x0e, 0xea, 0x04, 0xb2, 0xda, 0x09, + 0x21, 0x54, 0x60, 0xa2, 0x5d, 0x86, 0x02, 0x22, 0x81, 0x80, + 0x0b, 0x44, 0x82, 0x3d, 0x04, 0x71, 0x4a, 0x10, 0x11, 0xfc, + 0x61, 0x04, 0xc0, 0x5b, 0x01, 0x00, 0x46, 0x12, 0x07, 0x11, + 0x83, 0x05, 0x31, 0x24, 0x4a, 0x0c, 0x09, 0x04, 0x15, 0x00, + 0xd0, 0xdc, 0x0f, 0xd3, 0xfd, 0xc5, 0x86, 0x38, 0x5f, 0x85, + 0xc0, 0x42, 0xc2, 0x48, 0x61, 0x20, 0x41, 0x62, 0x48, 0xb0, + 0x0a, 0x49, 0x60, 0xb8, 0x96, 0xef, 0xad, 0xba, 0x60, 0x23, + 0x88, 0xa2, 0x39, 0x60, 0xa8, 0x23, 0x86, 0x8d, 0x02, 0x81, + 0x86, 0x18, 0x30, 0x23, 0x13, 0x42, 0xa3, 0x5b, 0x38, 0x14, + 0x20, 0x5a, 0x18, 0x4a, 0xae, 0x68, 0x8d, 0x4a, 0x8c, 0x00, + 0x51, 0x0e, 0x63, 0x18, 0x10, 0x9a, 0x0c, 0x70, 0x41, 0x38, + 0x46, 0x21, 0x18, 0x25, 0x00, 0x50, 0x95, 0xb8, 0x38, 0x75, + 0xe1, 0xab, 0xe8, 0xa2, 0x3f, 0x18, 0x77, 0xb9, 0xc5, 0x81, + 0x86, 0x0b, 0x2a, 0x21, 0x8c, 0x08, 0x2e, 0x2a, 0x0a, 0xa4, + 0x10, 0xd8, 0x58, 0x3e, 0x80, 0x25, 0x09, 0xcf, 0x47, 0x16, + 0xb9, 0x8a, 0x8e, 0x26, 0x0a, 0x76, 0x51, 0x18, 0x80, 0x19, + 0xa8, 0x0c, 0x9e, 0x5f, 0x6f, 0xd8, 0x59, 0xf7, 0x05, 0x13, + 0x14, 0x53, 0x30, 0x40, 0xa5, 0x04, 0x55, 0xb1, 0x00, 0x55, + 0x74, 0xf9, 0x83, 0xd4, 0xf1, 0x37, 0xee, 0x16, 0x32, 0x12, + 0xf4, 0x14, 0xc8, 0x4b, 0x30, 0xd4, 0x02, 0x92, 0x80, 0x61, + 0x02, 0x88, 0x94, 0xbf, 0xf8, 0x18, 0xc3, 0x97, 0xe5, 0x58, + 0xa8, 0x35, 0x98, 0x1a, 0xc1, 0x41, 0xd4, 0x19, 0xc6, 0x18, + 0x48, 0xb0, 0xbf, 0xfc, 0x1c, 0x56, 0x6e, 0x13, 0xcc, 0x04, + 0x4b, 0x07, 0x27, 0x55, 0x2f, 0x7d, 0x44, 0x61, 0x65, 0x3f, + 0xf0, 0xc0, 0xc0, 0xab, 0x89, 0x83, 0x0d, 0x67, 0x16, 0x00, + 0xc8, 0xa1, 0x84, 0x41, 0x95, 0x33, 0xb8, 0x2e, 0x18, 0x25, + 0xff, 0xf8, 0x18, 0x96, 0xa2, 0xc0, 0x18, 0x58, 0x06, 0x3a, + 0xbf, 0xc1, 0x96, 0xed, 0x10, 0xc4, 0x98, 0xc0, 0x46, 0x13, + 0xff, 0xe1, 0x63, 0x03, 0x17, 0x01, 0x6e, 0x74, 0x06, 0x70, + 0x2a, 0x6a, 0xb3, 0x74, 0x07, 0x61, 0x58, 0x2c, 0x2d, 0xbf, + 0xfd, 0x01, 0x42, 0x30, 0x85, 0xfb, 0xc6, 0x1a, 0x0a, 0x14, + 0x2c, 0x5c, 0x08, 0xbc, 0x43, 0x2f, 0xc2, 0x5f, 0x72, 0x8b, + 0x9c, 0x32, 0x06, 0x0a, 0x27, 0x03, 0x50, 0x61, 0x5f, 0x41, + 0x4e, 0x19, 0x83, 0xff, 0xfb, 0x42, 0x3e, 0x6e, 0x34, 0x12, + 0x7f, 0x75, 0x18, 0x04, 0x1f, 0x06, 0x86, 0x7f, 0xf9, 0x44, + 0x97, 0xee, 0x0d, 0xe9, 0xf2, 0x38, 0x3e, 0xf8, 0x37, 0xfe, + 0x98, 0x1c, 0xd6, 0x30, 0x11, 0x2f, 0xff, 0xe0, 0x76, 0x50, + 0x38, 0x5f, 0xfe, 0x70, 0xc4, 0x29, 0x0b, 0x82, 0x2f, 0xff, + 0xe0, 0x62, 0x48, 0xc3, 0x85, 0x10, 0xa1, 0x69, 0x17, 0xfe, + 0x50, 0xc8, 0x5f, 0x4f, 0xff, 0xfc, 0x30, 0xa0, 0x7f, 0xe9, + 0x0c, 0x00, 0xc2, 0x7f, 0xff, 0xf9, 0x0a, 0x82, 0x56, 0x0d, + 0xfe, 0xd0, 0x8e, 0xff, 0xff, 0xfd, 0x04, 0x64, 0x58, 0x5f, + 0xfe, 0x0f, 0xdc, 0x5a, 0xff, 0xff, 0xe0, 0x9c, 0x33, 0xfd, + 0x60, 0x7c, 0x38, 0x0f, 0xff, 0xff, 0x81, 0xf8, 0x1f, 0xfc, + 0x0f, 0x82, 0x7f, 0xff, 0xe8, 0xe5, 0x3c, 0x0f, 0xf7, 0xc0, + 0xf8, 0xc3, 0x17, 0xff, 0xff, 0x13, 0x37, 0xc1, 0xbf, 0xe0, + 0x70, 0xcc, 0xbf, 0xff, 0xf1, 0x85, 0xfc, 0x1f, 0xfe, 0x07, + 0x83, 0x2f, 0xff, 0xff, 0x1b, 0x7c, 0x1f, 0xfd, 0x42, 0x94, + 0x36, 0x9f, 0xff, 0xfc, 0x1f, 0xe0, 0xfd, 0x99, 0x86, 0x02, + 0x1a, 0x29, 0x81, 0x21, 0x7f, 0xff, 0xfc, 0x83, 0x95, 0x85, + 0x11, 0x60, 0x60, 0x22, 0xc8, 0xd0, 0xc2, 0xc4, 0xb5, 0x83, + 0x95, 0x27, 0xa7, 0xff, 0xfc, 0x85, 0x85, 0xb4, 0x47, 0x24, + 0x18, 0x28, 0xaa, 0x1a, 0x23, 0x2a, 0x84, 0xdb, 0xff, 0xff, + 0xf2, 0x63, 0x92, 0xc4, 0xc0, 0x21, 0xc0, 0xc2, 0xc0, 0x00, + 0x82, 0xc6, 0x00, 0x28, 0x89, 0x72, 0xff, 0xff, 0xef, 0x16, + 0x05, 0x11, 0x1c, 0x61, 0x22, 0x38, 0x50, 0xb8, 0x2a, 0xbb, + 0x9c, 0xe7, 0xcf, 0xff, 0xff, 0xe6, 0x30, 0xce, 0x0f, 0xc0, + 0x04, 0x71, 0x1d, 0xff, 0xff, 0xff, 0xfb, 0xb7, 0x07, 0xe1, + 0x21, 0x82, 0xc0, 0x87, 0x6b, 0xb7, 0xff, 0xff, 0xf7, 0x0c, + 0x10, 0xc5, 0x85, 0x40, 0x96, 0x12, 0x58, 0xe1, 0xc1, 0x5d, + 0xff, 0xff, 0xfb, 0x89, 0xcb, 0x84, 0x30, 0x9c, 0x2a, 0xc5, + 0x41, 0x64, 0x5a, 0xee, 0x0d, 0x8a, 0x61, 0x4b, 0xff, 0xff, + 0x0c, 0xc0, 0x86, 0x10, 0x23, 0x8a, 0x42, 0xe3, 0x0a, 0xc0, + 0x23, 0x07, 0x14, 0x6e, 0x2c, 0x09, 0x4e, 0x2c, 0x05, 0x82, + 0x01, 0x02, 0x2f, 0xff, 0xf4, 0x07, 0xb0, 0x8d, 0x02, 0x09, + 0x14, 0x45, 0x81, 0x86, 0xb8, 0x10, 0xb0, 0x27, 0x00, 0x30, + 0xaa, 0x21, 0x85, 0x80, 0x5c, 0x56, 0x2f, 0xff, 0xf0, 0x7a, + 0x0c, 0x01, 0x68, 0x14, 0x08, 0x1a, 0x82, 0x3d, 0xc2, 0xc4, + 0xe0, 0x60, 0xc0, 0x0e, 0x30, 0x10, 0x6f, 0xff, 0xf4, 0x5b, + 0x8b, 0x3e, 0x30, 0x92, 0x70, 0xc1, 0x86, 0x80, 0x48, 0x33, + 0xc0, 0x82, 0xc5, 0x8f, 0xff, 0xf0, 0xb7, 0x88, 0xed, 0xf1, + 0x85, 0x80, 0x7c, 0x1b, 0xa0, 0x9d, 0xff, 0xfe, 0x51, 0x47, + 0x45, 0xff, 0x94, 0x2f, 0x0c, 0x15, 0x46, 0xff, 0xff, 0xd3, + 0x0c, 0x58, 0x67, 0xfe, 0x74, 0x57, 0x11, 0x80, 0xc6, 0x14, + 0xe2, 0xc0, 0xa9, 0xff, 0x9d, 0xd4, 0x34, 0x61, 0xc2, 0x5a, + 0x09, 0x7f, 0xfa, 0x60, 0xc0, 0x80, 0x8c, 0x6e, 0x62, 0x6a, + 0xff, 0xc4, 0x50, 0x3c, 0x86, 0x1a, 0x70, 0x3f, 0xfe, 0x0d, + 0x8b, 0x90, 0xc7, 0x04, 0x10, 0xd7, 0xfe, 0x10, 0x00, 0x28, + 0x82, 0x0b, 0x01, 0xc3, 0x0a, 0x84, 0x7f, 0xfb, 0xc2, 0x36, + 0x10, 0xf3, 0xf5, 0xe1, 0x64, 0x80, 0x88, 0x0e, 0x29, 0x94, + 0x1f, 0xf2, 0x49, 0xcf, 0xc9, 0xe4, 0xf3, 0xf2, 0x79, 0x3c, + 0xfc, 0x9e, 0x4f, 0x3f, 0x27, 0x93, 0xcf, 0xc9, 0xe4, 0xf3, + 0xf2, 0x79, 0x3c, 0xe2, 0x2f, 0xc9, 0xc9, 0x5c, 0x62, 0x09, + 0x32, 0x51, 0x20, 0x69, 0x21, 0xa1, 0x4e, 0xe0, 0x60, 0x79, + 0xcd, 0x39, 0x96, 0x2a, 0x12, 0x65, 0x1b, 0x59, 0x45, 0x60, + 0x94, 0x98, 0x24, 0xd4, 0x4e, 0xc1, 0xf0, 0x48, 0x73, 0xbd, + 0xf8, 0xce, 0xd1, 0x9d, 0x6f, 0x70, 0xcc, 0x91, 0x08, 0xc2, + 0x4e, 0x77, 0x92, 0x21, 0x18, 0x49, 0xd0, 0xf7, 0x47, 0x21, + 0x08, 0xc2, 0x4e, 0x87, 0x92, 0x21, 0x18, 0x48, 0x90, 0xba, + 0x67, 0x43, 0xf2, 0x44, 0x58, 0x24, 0xe7, 0x79, 0x2b, 0xbe, + 0x78, 0xc2, 0x94, 0xbc, 0x90, 0x94, 0x7a, 0x84, 0xc4, 0x82, + 0x71, 0xeb, 0x25, 0xf2, 0x4e, 0xe6, 0x1f, 0x0f, 0x59, 0x08, + 0xb7, 0x41, 0xf1, 0x55, 0xc2, 0x4c, 0x29, 0x7a, 0x09, 0x33, + 0xd9, 0x81, 0x9e, 0x49, 0x9b, 0x2c, 0xf2, 0x79, 0xf9, 0x3c, + 0x9e, 0x7e, 0x4f, 0x27, 0x9f, 0x93, 0xc9, 0xe7, 0xe4, 0xf2, + 0x79, 0xc6, 0x63, 0x3e, 0x73, 0xc8, 0xf2, 0xe7, 0xe4, 0xf2, + 0x79, 0xf9, 0x3c, 0x9e, 0x7e, 0x4f, 0x27, 0x9f, 0x93, 0xc9, + 0xe7, 0xe4, 0xf2, 0x42, 0x4b, 0x35, 0xa2, 0x8b, 0xd5, 0x18, + 0x71, 0xf4, 0x0f, 0xc8, 0x49, 0x92, 0x6d, 0x61, 0xc1, 0x4a, + 0x94, 0x7d, 0x09, 0x15, 0x4c, 0x00, 0x48, 0xa8, 0x78, 0x12, + 0x29, 0xfb, 0x3f, 0x89, 0x82, 0x4d, 0xc3, 0x3a, 0x09, 0x32, + 0x3d, 0xf7, 0x92, 0x2e, 0x2e, 0x9b, 0xbb, 0x11, 0x8d, 0x9a, + 0x3f, 0x68, 0x01, 0x99, 0x0f, 0x21, 0x0a, 0xe6, 0x75, 0x0d, + 0x92, 0x32, 0xc9, 0xfc, 0x08, 0x25, 0xb2, 0xf7, 0xfd, 0xfc, + 0x01, 0xc9, 0x93, 0xc9, 0x6f, 0x08, 0x49, 0x9c, 0xf2, 0x75, + 0x92, 0x76, 0x09, 0x35, 0x26, 0x6f, 0x24, 0x3c, 0x82, 0x40, + 0x12, 0x19, 0xb6, 0x64, 0x27, 0xbf, 0x2d, 0xbb, 0x59, 0x60, + 0x91, 0x54, 0xe3, 0x6f, 0x64, 0x64, 0x99, 0xe4, 0xb3, 0x71, + 0x4c, 0xf2, 0x79, 0xfe, 0x4f, 0x27, 0x9f, 0x93, 0xc9, 0xe7, + 0xe4, 0xf2, 0x79, 0xf9, 0x3c, 0x9e, 0x7e, 0x4f, 0x27, 0x9f, + 0x93, 0xc9, 0xe7, 0xe4, 0xf2, 0x79, 0xf9, 0x3c, 0x9e, 0x7e, + 0x4f, 0x24, 0x24, 0x42, 0xaa, 0xc2, 0x40, 0x93, 0xc7, 0xe1, + 0xa8, 0xc6, 0xd9, 0x84, 0xa5, 0x02, 0xd6, 0x84, 0x8a, 0x76, + 0x0e, 0xc5, 0xec, 0xc7, 0x70, 0x08, 0xa8, 0x70, 0xf8, 0xa5, + 0x45, 0x2e, 0x09, 0x10, 0xef, 0x82, 0x40, 0x43, 0x08, 0x52, + 0x61, 0x86, 0x47, 0x28, 0xb1, 0xb4, 0x5f, 0x96, 0xb7, 0xec, + 0xd8, 0xe6, 0xec, 0xdf, 0x4d, 0xb9, 0x3c, 0x96, 0x6c, 0x2b, + 0x24, 0x42, 0x3d, 0xfa, 0xbc, 0xad, 0xe3, 0xa2, 0x37, 0x62, + 0x15, 0xf7, 0xed, 0xb0, 0xee, 0x4d, 0x5d, 0xf3, 0x81, 0x19, + 0x23, 0x16, 0x81, 0x9b, 0x25, 0x76, 0x65, 0x1d, 0x92, 0xf9, + 0x39, 0xdf, 0x7e, 0x6a, 0x3b, 0x64, 0x8e, 0x4c, 0xc1, 0x7a, + 0xc9, 0x3d, 0x66, 0x68, 0x4d, 0xd9, 0x27, 0x1c, 0x88, 0x74, + 0x24, 0x46, 0x2a, 0x68, 0xa6, 0x72, 0x70, 0x86, 0xac, 0xd0, + 0x46, 0x99, 0x06, 0xdb, 0x25, 0x32, 0x08, 0x7b, 0x2f, 0x04, + 0x5f, 0xb3, 0x9e, 0x4c, 0xfc, 0x9d, 0x94, 0x23, 0x3c, 0x9e, + 0x7f, 0x93, 0xc9, 0xe7, 0xe4, 0xf2, 0x79, 0xf9, 0x3c, 0x9e, + 0x71, 0x07, 0x10, 0x7e, 0x7e, 0x4f, 0x27, 0x9f, 0x93, 0xc9, + 0xe7, 0xe4, 0xf2, 0x79, 0xf9, 0x3c, 0x9e, 0x7e, 0x4f, 0x24, + 0x24, 0x76, 0xa5, 0xca, 0x61, 0xc4, 0x7a, 0x92, 0x3d, 0x0a, + 0x5c, 0x9f, 0xca, 0x47, 0x09, 0x31, 0xa2, 0x52, 0x18, 0xb5, + 0x65, 0x1f, 0x44, 0x65, 0xf6, 0xc2, 0x44, 0x0f, 0x91, 0xb8, + 0x31, 0x21, 0xc2, 0x44, 0x23, 0x70, 0x90, 0xf6, 0xe1, 0x22, + 0x09, 0xfc, 0x00, 0x20, 0x77, 0x61, 0x20, 0xce, 0x3b, 0x45, + 0x9e, 0xb5, 0xa8, 0x01, 0xb0, 0x4d, 0xe3, 0x0e, 0x7e, 0x24, + 0xc3, 0xbd, 0xf8, 0x64, 0x9d, 0xd9, 0x88, 0x6d, 0x93, 0xc9, + 0x66, 0x8b, 0x39, 0x93, 0x57, 0x59, 0xee, 0x4b, 0xe8, 0x4e, + 0xb2, 0x45, 0x2f, 0xb4, 0xe8, 0x64, 0xaf, 0x2d, 0xc0, 0xdf, + 0xb2, 0x4f, 0x31, 0x32, 0x4f, 0x2e, 0x62, 0x83, 0xf5, 0xd0, + 0xa1, 0xf9, 0x3a, 0x97, 0xdf, 0xdf, 0x3d, 0x53, 0x92, 0x32, + 0x5c, 0xc7, 0xb4, 0xcc, 0xc8, 0x71, 0xbd, 0xd9, 0xf9, 0x2c, + 0xf2, 0x79, 0xfe, 0x4f, 0x27, 0x9f, 0x93, 0xc9, 0xe7, 0xe4, + 0xf2, 0x79, 0xf9, 0x3c, 0x9e, 0x73, 0xc8, 0xf2, 0xe7, 0xe4, + 0xf2, 0x79, 0xf9, 0x3c, 0x9e, 0x7e, 0x4f, 0x27, 0x9f, 0x93, + 0xc9, 0xe7, 0x3c, 0xf9, 0x38, 0xd8, 0x8c, 0x8e, 0x98, 0x62, + 0x16, 0x31, 0x3d, 0xa0, 0x73, 0x1f, 0x8a, 0x46, 0x10, 0x0c, + 0x11, 0xcb, 0x2f, 0x57, 0x1d, 0x82, 0x4f, 0x47, 0x64, 0x58, + 0x01, 0x07, 0x07, 0x2c, 0x50, 0xe1, 0x4a, 0xc9, 0x29, 0xa6, + 0xe6, 0x66, 0x13, 0x7d, 0x84, 0x89, 0x3f, 0x00, 0x48, 0x82, + 0x57, 0x10, 0x8f, 0xe5, 0xe5, 0xf7, 0x3e, 0xd6, 0xf3, 0x0c, + 0xb7, 0xe7, 0xc9, 0x8f, 0x3e, 0x4f, 0x6a, 0xfc, 0xf3, 0xd5, + 0xe9, 0x4a, 0x0a, 0x46, 0x52, 0x52, 0x97, 0x88, 0xe5, 0xb8, + 0x7e, 0x1c, 0xdc, 0x58, 0x72, 0xdb, 0xe1, 0xe4, 0x8b, 0x6f, + 0xea, 0x41, 0xa1, 0x03, 0x6f, 0xd0, 0xe6, 0x5d, 0xd1, 0x90, + 0xeb, 0x7d, 0xb6, 0x7e, 0xe8, 0x0e, 0x8e, 0x53, 0xef, 0xe7, + 0xdc, 0x2c, 0x91, 0x96, 0xec, 0x12, 0x28, 0x9b, 0x93, 0xb9, + 0x74, 0xaf, 0x00, 0xd8, 0x90, 0xd5, 0x99, 0x21, 0xe5, 0x9d, + 0x03, 0x5f, 0x5c, 0x95, 0x22, 0x9b, 0x09, 0x38, 0x1e, 0x48, + 0xcf, 0x24, 0x39, 0x4c, 0xcd, 0x8d, 0x64, 0x8e, 0x82, 0x4d +}; + +GST_START_TEST (test_vc1_identify_bdu) +{ + GstVC1ParserResult res; + GstVC1BDU bdu; + GstVC1SeqHdr hdr; + GstVC1EntryPointHdr entrypt; + + res = gst_vc1_identify_next_bdu (sequence_fullframe, + sizeof (sequence_fullframe), &bdu); + + assert_equals_int (res, GST_VC1_PARSER_OK); + assert_equals_int (bdu.type, GST_VC1_SEQUENCE); + + res = gst_vc1_parse_sequence_header (bdu.data + bdu.offset, bdu.size, &hdr); + assert_equals_int (res, GST_VC1_PARSER_OK); + assert_equals_int (hdr.profile, GST_VC1_PROFILE_ADVANCED); + + assert_equals_int (hdr.advanced.level, GST_VC1_LEVEL_L1); + assert_equals_int (hdr.advanced.colordiff_format, 1); + + res = gst_vc1_identify_next_bdu (sequence_fullframe + bdu.sc_offset + + bdu.size, sizeof (sequence_fullframe) - bdu.sc_offset - bdu.size, &bdu); + + fail_unless (res == GST_VC1_PARSER_OK); + fail_unless (bdu.type == GST_VC1_ENTRYPOINT); + + res = gst_vc1_parse_entry_point_header (bdu.data + bdu.offset, + bdu.size, &entrypt, &hdr); + fail_unless (res == GST_VC1_PARSER_OK); +} + +GST_END_TEST; + +GST_START_TEST (test_vc1_parse_p_frame_header_main) +{ + GstVC1FrameHdr framehdr; + GstVC1SeqHdr seqhdr; + + GstVC1SeqStructC *structc = &seqhdr.struct_c; + GstVC1PicSimpleMain *pic = &framehdr.pic.simple; + + structc->coded_height = 240; + structc->coded_width = 320; + + assert_equals_int (gst_vc1_parse_sequence_header (pframe_header_main, + sizeof (pframe_header_main), &seqhdr), GST_VC1_PARSER_OK); + + assert_equals_int (seqhdr.profile, GST_VC1_PROFILE_MAIN); + + assert_equals_int (structc->frmrtq_postproc, 7); + assert_equals_int (structc->bitrtq_postproc, 2); + assert_equals_int (structc->loop_filter, 1); + assert_equals_int (structc->multires, 0); + assert_equals_int (structc->extended_mv, 0); + assert_equals_int (structc->rangered, 0); + assert_equals_int (structc->vstransform, 1); + assert_equals_int (structc->overlap, 1); + assert_equals_int (structc->syncmarker, 0); + assert_equals_int (structc->dquant, 1); + assert_equals_int (structc->quantizer, 0); + assert_equals_int (structc->maxbframes, 1); + + assert_equals_int (gst_vc1_parse_frame_header (pframe_main, + sizeof (pframe_main), &framehdr, &seqhdr, NULL), GST_VC1_PARSER_OK); + assert_equals_int (framehdr.ptype, GST_VC1_PICTURE_TYPE_P); + assert_equals_int (framehdr.interpfrm, 0); + assert_equals_int (pic->frmcnt, 1); + assert_equals_int (pic->rangeredfrm, 0); + assert_equals_int (framehdr.pqindex, 10); + assert_equals_int (framehdr.pquant, 7); + assert_equals_int (framehdr.halfqp, 0); + assert_equals_int (framehdr.pquantizer, 0); + +} + +GST_END_TEST; + +GST_START_TEST (test_vc1_parse_b_frame_header_main) +{ + GstVC1FrameHdr framehdr; + GstVC1SeqHdr seqhdr; + GstVC1BitPlanes b = { 0, }; + + GstVC1SeqStructC *structc = &seqhdr.struct_c; + GstVC1PicSimpleMain *pic = &framehdr.pic.simple; + + structc->coded_height = 240; + structc->coded_width = 320; + + assert_equals_int (gst_vc1_parse_sequence_header (bframe_header_main, + sizeof (bframe_header_main), &seqhdr), GST_VC1_PARSER_OK); + + assert_equals_int (seqhdr.profile, GST_VC1_PROFILE_MAIN); + assert_equals_int (seqhdr.mb_height, 15); + assert_equals_int (seqhdr.mb_width, 20); + + gst_vc1_bitplanes_ensure_size (&b, &seqhdr); + + assert_equals_int (b.size, 315); + + assert_equals_int (structc->frmrtq_postproc, 7); + assert_equals_int (structc->bitrtq_postproc, 3); + assert_equals_int (structc->loop_filter, 1); + assert_equals_int (structc->multires, 0); + assert_equals_int (structc->extended_mv, 0); + assert_equals_int (structc->rangered, 0); + assert_equals_int (structc->vstransform, 1); + assert_equals_int (structc->overlap, 1); + assert_equals_int (structc->syncmarker, 0); + assert_equals_int (structc->dquant, 1); + assert_equals_int (structc->quantizer, 0); + assert_equals_int (structc->maxbframes, 1); + + assert_equals_int (gst_vc1_parse_frame_header (bframe_main, + sizeof (bframe_main), &framehdr, &seqhdr, &b), GST_VC1_PARSER_OK); + + assert_equals_int (framehdr.ptype, GST_VC1_PICTURE_TYPE_B); + assert_equals_int (framehdr.interpfrm, 0); + + assert_equals_int (pic->frmcnt, 2); + assert_equals_int (pic->rangeredfrm, 0); + assert_equals_int (pic->ttmbf, 0); + assert_equals_int (pic->mvtab, 2); + assert_equals_int (pic->cbptab, 1); + assert_equals_int (framehdr.pquant, 7); + assert_equals_int (framehdr.halfqp, 0); + assert_equals_int (framehdr.pquantizer, 0); + + gst_vc1_bitplanes_free_1 (&b); +} + +GST_END_TEST; + +GST_START_TEST (test_vc1_parse_bi_frame_header_main) +{ + GstVC1FrameHdr framehdr; + GstVC1SeqHdr seqhdr; + + GstVC1SeqStructC *structc = &seqhdr.struct_c; + GstVC1PicSimpleMain *pic = &framehdr.pic.simple; + + structc->coded_height = 240; + structc->coded_width = 320; + + assert_equals_int (gst_vc1_parse_sequence_header (i_bi_frame_header, + sizeof (i_bi_frame_header), &seqhdr), GST_VC1_PARSER_OK); + + assert_equals_int (seqhdr.profile, GST_VC1_PROFILE_MAIN); + assert_equals_int (structc->frmrtq_postproc, 7); + assert_equals_int (structc->bitrtq_postproc, 7); + assert_equals_int (structc->loop_filter, 1); + assert_equals_int (structc->multires, 0); + assert_equals_int (structc->extended_mv, 0); + assert_equals_int (structc->rangered, 0); + assert_equals_int (structc->vstransform, 1); + assert_equals_int (structc->overlap, 1); + assert_equals_int (structc->syncmarker, 0); + assert_equals_int (structc->dquant, 1); + assert_equals_int (structc->quantizer, 0); + assert_equals_int (structc->maxbframes, 1); + + assert_equals_int (gst_vc1_parse_frame_header (biframe_main, + sizeof (biframe_main), &framehdr, &seqhdr, NULL), GST_VC1_PARSER_OK); + assert_equals_int (framehdr.ptype, GST_VC1_PICTURE_TYPE_BI); + assert_equals_int (framehdr.interpfrm, 0); + + assert_equals_int (pic->frmcnt, 0); + assert_equals_int (pic->rangeredfrm, 0); + assert_equals_int (framehdr.pqindex, 6); + assert_equals_int (framehdr.pquant, 6); + assert_equals_int (framehdr.halfqp, 0); + assert_equals_int (framehdr.pquantizer, 1); +} + +GST_END_TEST; + +GST_START_TEST (test_vc1_parse_i_frame_header_main) +{ + GstVC1FrameHdr framehdr; + GstVC1SeqHdr seqhdr; + + GstVC1SeqStructC *structc = &seqhdr.struct_c; + GstVC1PicSimpleMain *pic = &framehdr.pic.simple; + + structc->coded_height = 240; + structc->coded_width = 320; + + assert_equals_int (gst_vc1_parse_sequence_header (i_bi_frame_header, + sizeof (i_bi_frame_header), &seqhdr), GST_VC1_PARSER_OK); + + assert_equals_int (seqhdr.profile, GST_VC1_PROFILE_MAIN); + assert_equals_int (structc->frmrtq_postproc, 7); + assert_equals_int (structc->bitrtq_postproc, 7); + assert_equals_int (structc->loop_filter, 1); + assert_equals_int (structc->multires, 0); + assert_equals_int (structc->extended_mv, 0); + assert_equals_int (structc->rangered, 0); + assert_equals_int (structc->vstransform, 1); + assert_equals_int (structc->overlap, 1); + assert_equals_int (structc->syncmarker, 0); + assert_equals_int (structc->dquant, 1); + assert_equals_int (structc->quantizer, 0); + assert_equals_int (structc->maxbframes, 1); + + assert_equals_int (gst_vc1_parse_frame_header (iframe_main, + sizeof (iframe_main), &framehdr, &seqhdr, NULL), GST_VC1_PARSER_OK); + assert_equals_int (framehdr.ptype, GST_VC1_PICTURE_TYPE_I); + assert_equals_int (framehdr.interpfrm, 0); + + assert_equals_int (pic->frmcnt, 0); + assert_equals_int (pic->rangeredfrm, 0); + assert_equals_int (framehdr.pqindex, 4); + assert_equals_int (framehdr.pquant, 4); + assert_equals_int (framehdr.halfqp, 1); + assert_equals_int (framehdr.pquantizer, 1); +} + +GST_END_TEST; + +GST_START_TEST (test_vc1_parse_i_frame_header_adv) +{ + GstVC1FrameHdr framehdr; + GstVC1SeqHdr seqhdr; + + GstVC1AdvancedSeqHdr *advhdr = &seqhdr.advanced; + GstVC1EntryPointHdr *entrypt = &advhdr->entrypoint; + GstVC1PicAdvanced *pic = &framehdr.pic.advanced; + + assert_equals_int (gst_vc1_parse_sequence_header (iframe_adv_hdr, + sizeof (iframe_adv_hdr), &seqhdr), GST_VC1_PARSER_OK); + + assert_equals_int (seqhdr.profile, GST_VC1_PROFILE_ADVANCED); + assert_equals_int (advhdr->level, GST_VC1_LEVEL_L3); + assert_equals_int (advhdr->frmrtq_postproc, 7); + assert_equals_int (advhdr->bitrtq_postproc, 31); + assert_equals_int (advhdr->postprocflag, 0); + assert_equals_int (advhdr->max_coded_width, 1920); + assert_equals_int (advhdr->max_coded_height, 1080); + assert_equals_int (advhdr->interlace, 1); + assert_equals_int (advhdr->tfcntrflag, 0); + assert_equals_int (advhdr->finterpflag, 0); + + assert_equals_int (advhdr->display_ext, 1); + assert_equals_int (advhdr->disp_horiz_size, 1920); + assert_equals_int (advhdr->disp_vert_size, 1080); + + assert_equals_int (gst_vc1_parse_entry_point_header (entrypoint, + sizeof (entrypoint), entrypt, &seqhdr), GST_VC1_PARSER_OK); + + assert_equals_int (entrypt->broken_link, 0); + assert_equals_int (entrypt->closed_entry, 1); + assert_equals_int (entrypt->panscan_flag, 0); + assert_equals_int (entrypt->refdist_flag, 1); + assert_equals_int (entrypt->loopfilter, 1); + assert_equals_int (entrypt->fastuvmc, 0); + assert_equals_int (entrypt->extended_mv, 1); + assert_equals_int (entrypt->dquant, 1); + assert_equals_int (entrypt->vstransform, 1); + assert_equals_int (entrypt->overlap, 0); + assert_equals_int (entrypt->quantizer, 0); + assert_equals_int (entrypt->coded_height, 1080); + assert_equals_int (entrypt->coded_width, 1920); + + assert_equals_int (gst_vc1_parse_frame_header (iframe_adv, + sizeof (iframe_adv), &framehdr, &seqhdr, NULL), GST_VC1_PARSER_OK); + + assert_equals_int (framehdr.ptype, GST_VC1_PICTURE_TYPE_I); + assert_equals_int (framehdr.pqindex, 3); + assert_equals_int (framehdr.pquant, 3); + assert_equals_int (framehdr.halfqp, 1); + assert_equals_int (framehdr.pquantizer, 1); + + assert_equals_int (pic->fcm, 0); + assert_equals_int (pic->tff, 1); + assert_equals_int (pic->rff, 0); + assert_equals_int (pic->rndctrl, 0); +} + +GST_END_TEST; + +GST_START_TEST (test_vc1_parse_b_frame_header_adv) +{ + GstVC1FrameHdr framehdr; + GstVC1SeqHdr seqhdr; + + GstVC1AdvancedSeqHdr *advhdr = &seqhdr.advanced; + GstVC1EntryPointHdr *entrypt = &advhdr->entrypoint; + GstVC1PicAdvanced *pic = &framehdr.pic.advanced; + + assert_equals_int (gst_vc1_parse_sequence_header (iframe_adv_hdr, + sizeof (iframe_adv_hdr), &seqhdr), GST_VC1_PARSER_OK); + + assert_equals_int (seqhdr.profile, GST_VC1_PROFILE_ADVANCED); + assert_equals_int (advhdr->level, GST_VC1_LEVEL_L3); + assert_equals_int (advhdr->frmrtq_postproc, 7); + assert_equals_int (advhdr->bitrtq_postproc, 31); + assert_equals_int (advhdr->postprocflag, 0); + assert_equals_int (advhdr->max_coded_width, 1920); + assert_equals_int (advhdr->max_coded_height, 1080); + assert_equals_int (advhdr->interlace, 1); + assert_equals_int (advhdr->tfcntrflag, 0); + assert_equals_int (advhdr->finterpflag, 0); + + assert_equals_int (advhdr->display_ext, 1); + assert_equals_int (advhdr->disp_horiz_size, 1920); + assert_equals_int (advhdr->disp_vert_size, 1080); + + assert_equals_int (gst_vc1_parse_entry_point_header (entrypoint, + sizeof (entrypoint), entrypt, &seqhdr), GST_VC1_PARSER_OK); + + assert_equals_int (entrypt->broken_link, 0); + assert_equals_int (entrypt->closed_entry, 1); + assert_equals_int (entrypt->panscan_flag, 0); + assert_equals_int (entrypt->refdist_flag, 1); + assert_equals_int (entrypt->loopfilter, 1); + assert_equals_int (entrypt->fastuvmc, 0); + assert_equals_int (entrypt->extended_mv, 1); + assert_equals_int (entrypt->dquant, 1); + assert_equals_int (entrypt->vstransform, 1); + assert_equals_int (entrypt->overlap, 0); + assert_equals_int (entrypt->quantizer, 0); + + assert_equals_int (gst_vc1_parse_frame_header (bframe_adv, + sizeof (bframe_adv), &framehdr, &seqhdr, NULL), GST_VC1_PARSER_OK); + + assert_equals_int (framehdr.ptype, GST_VC1_PICTURE_TYPE_B); + assert_equals_int (framehdr.pqindex, 1); + assert_equals_int (framehdr.pquant, 1); + assert_equals_int (framehdr.halfqp, 1); + assert_equals_int (framehdr.pquantizer, 1); + + assert_equals_int (framehdr.vopdquant.dquantfrm, 0); + assert_equals_int (framehdr.transacfrm, 1); + + assert_equals_int (gst_vc1_parse_frame_header (bframe2_adv, + sizeof (bframe2_adv), &framehdr, &seqhdr, NULL), GST_VC1_PARSER_OK); + assert_equals_int (framehdr.ptype, GST_VC1_PICTURE_TYPE_B); + assert_equals_int (framehdr.pqindex, 4); + assert_equals_int (framehdr.pquant, 4); + assert_equals_int (framehdr.halfqp, 0); + assert_equals_int (framehdr.pquantizer, 1); + assert_equals_int (framehdr.transacfrm, 0); + + assert_equals_int (pic->mvrange, 0); + assert_equals_int (pic->mvmode, 0); +} + + +GST_END_TEST; + +GST_START_TEST (test_vc1_parse_p_frame_header_adv) +{ + GstVC1FrameHdr framehdr; + GstVC1SeqHdr seqhdr; + + GstVC1AdvancedSeqHdr *advhdr = &seqhdr.advanced; + GstVC1EntryPointHdr *entrypt = &advhdr->entrypoint; + GstVC1PicAdvanced *pic = &framehdr.pic.advanced; + + assert_equals_int (gst_vc1_parse_sequence_header (iframe_adv_hdr, + sizeof (iframe_adv_hdr), &seqhdr), GST_VC1_PARSER_OK); + + assert_equals_int (seqhdr.profile, GST_VC1_PROFILE_ADVANCED); + assert_equals_int (advhdr->level, GST_VC1_LEVEL_L3); + assert_equals_int (advhdr->frmrtq_postproc, 7); + assert_equals_int (advhdr->bitrtq_postproc, 31); + assert_equals_int (advhdr->postprocflag, 0); + assert_equals_int (advhdr->max_coded_width, 1920); + assert_equals_int (advhdr->max_coded_height, 1080); + assert_equals_int (advhdr->interlace, 1); + assert_equals_int (advhdr->tfcntrflag, 0); + assert_equals_int (advhdr->finterpflag, 0); + + assert_equals_int (advhdr->display_ext, 1); + assert_equals_int (advhdr->disp_horiz_size, 1920); + assert_equals_int (advhdr->disp_vert_size, 1080); + + assert_equals_int (gst_vc1_parse_entry_point_header (entrypoint, + sizeof (entrypoint), entrypt, &seqhdr), GST_VC1_PARSER_OK); + assert_equals_int (entrypt->broken_link, 0); + assert_equals_int (entrypt->closed_entry, 1); + assert_equals_int (entrypt->panscan_flag, 0); + assert_equals_int (entrypt->refdist_flag, 1); + assert_equals_int (entrypt->loopfilter, 1); + assert_equals_int (entrypt->fastuvmc, 0); + assert_equals_int (entrypt->extended_mv, 1); + assert_equals_int (entrypt->dquant, 1); + assert_equals_int (entrypt->vstransform, 1); + assert_equals_int (entrypt->overlap, 0); + assert_equals_int (entrypt->quantizer, 0); + assert_equals_int (entrypt->coded_height, 1080); + assert_equals_int (entrypt->coded_width, 1920); + + + assert_equals_int (gst_vc1_parse_frame_header (pframe_adv, + sizeof (pframe_adv), &framehdr, &seqhdr, NULL), GST_VC1_PARSER_OK); + assert_equals_int (framehdr.ptype, GST_VC1_PICTURE_TYPE_P); + assert_equals_int (framehdr.pqindex, 1); + assert_equals_int (framehdr.pquant, 1); + assert_equals_int (framehdr.halfqp, 0); + assert_equals_int (framehdr.pquantizer, 1); + + assert_equals_int (pic->mvmode, 0); + assert_equals_int (pic->mvrange, 0); + + assert_equals_int (gst_vc1_parse_frame_header (pframe2_adv, + sizeof (pframe2_adv), &framehdr, &seqhdr, NULL), GST_VC1_PARSER_OK); + assert_equals_int (framehdr.ptype, GST_VC1_PICTURE_TYPE_P); + assert_equals_int (framehdr.pqindex, 1); + assert_equals_int (framehdr.pquant, 1); + assert_equals_int (framehdr.halfqp, 0); + assert_equals_int (framehdr.pquantizer, 1); + + assert_equals_int (pic->mvmode, 3); + assert_equals_int (pic->mvrange, 0); +} + +GST_END_TEST static Suite * +vc1parser_suite (void) +{ + Suite *s = suite_create ("VC1 Parser library"); + + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_vc1_identify_bdu); + tcase_add_test (tc_chain, test_vc1_parse_p_frame_header_main); + tcase_add_test (tc_chain, test_vc1_parse_b_frame_header_main); + tcase_add_test (tc_chain, test_vc1_parse_bi_frame_header_main); + tcase_add_test (tc_chain, test_vc1_parse_i_frame_header_main); + tcase_add_test (tc_chain, test_vc1_parse_i_frame_header_adv); + tcase_add_test (tc_chain, test_vc1_parse_b_frame_header_adv); + tcase_add_test (tc_chain, test_vc1_parse_p_frame_header_adv); + + return s; +} + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = vc1parser_suite (); + + SRunner *sr = srunner_create (s); + + gst_check_init (&argc, &argv); + + srunner_run_all (sr, CK_NORMAL); + nf = srunner_ntests_failed (sr); + srunner_free (sr); + + return nf; +}