[
  {
    "path": ".gitignore",
    "content": "# -----\nbuild/\nffmpeg-temp/\nandroid/ffmpeg-*\nandroid/openssl-*\nios/ffmpeg-*\nios/openssl-*\nextra\n.DS_Store\nijkmedia/ijkyuv/\nijkmedia/ijksoundtouch\nijkprof/android-ndk-profiler/\n\n# built application files\n*.apk\n*.ap_\n\n# files for the dex VM\n*.dex\n\n# Java class files\n*.class\n\n# generated files\nbin/\ngen/\nlibs/\nobj/\nijkmedia/ijkplayer/ijkversion.h\n\n# Local configuration file (sdk path, etc)\nlocal.properties\n\n# Android Studio\n.idea\n.gradle\nbuild/\n\n# Xcode\nxcuserdata\nxcshareddata\n*.xccheckout\n\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: android\nandroid:\n  components:\n    - platform-tools\n    - tools\n    - build-tools-23.0.3\n    - android-23\n    - extra-android-support\n    - extra-android-m2repository\n\nscript:\n    - cd android/ijkplayer\n    - ./gradlew assemble\n"
  },
  {
    "path": "COPYING.GPLv2",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Free Software Foundation, Inc.,\n 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicense is intended to guarantee your freedom to share and change free\nsoftware--to make sure the software is free for all its users.  This\nGeneral Public License applies to most of the Free Software\nFoundation's software and to any other program whose authors commit to\nusing it.  (Some other Free Software Foundation software is covered by\nthe GNU Lesser General Public License instead.)  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if you\ndistribute copies of the software, or if you modify it.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must give the recipients all the rights that\nyou have.  You must make sure that they, too, receive or can get the\nsource code.  And you must show them these terms so they know their\nrights.\n\n  We protect your rights with two steps: (1) copyright the software, and\n(2) offer you this license which gives you legal permission to copy,\ndistribute and/or modify the software.\n\n  Also, for each author's protection and ours, we want to make certain\nthat everyone understands that there is no warranty for this free\nsoftware.  If the software is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original, so\nthat any problems introduced by others will not reflect on the original\nauthors' reputations.\n\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that redistributors of a free\nprogram will individually obtain patent licenses, in effect making the\nprogram proprietary.  To prevent this, we have made it clear that any\npatent must be licensed for everyone's free use or not licensed at all.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                    GNU GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License applies to any program or other work which contains\na notice placed by the copyright holder saying it may be distributed\nunder the terms of this General Public License.  The \"Program\", below,\nrefers to any such program or work, and a \"work based on the Program\"\nmeans either the Program or any derivative work under copyright law:\nthat is to say, a work containing the Program or a portion of it,\neither verbatim or with modifications and/or translated into another\nlanguage.  (Hereinafter, translation is included without limitation in\nthe term \"modification\".)  Each licensee is addressed as \"you\".\n\nActivities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning the Program is not restricted, and the output from the Program\nis covered only if its contents constitute a work based on the\nProgram (independent of having been made by running the Program).\nWhether that is true depends on what the Program does.\n\n  1. You may copy and distribute verbatim copies of the Program's\nsource code as you receive it, in any medium, provided that you\nconspicuously and appropriately publish on each copy an appropriate\ncopyright notice and disclaimer of warranty; keep intact all the\nnotices that refer to this License and to the absence of any warranty;\nand give any other recipients of the Program a copy of this License\nalong with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and\nyou may at your option offer warranty protection in exchange for a fee.\n\n  2. You may modify your copy or copies of the Program or any portion\nof it, thus forming a work based on the Program, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) You must cause the modified files to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in\n    whole or in part contains or is derived from the Program or any\n    part thereof, to be licensed as a whole at no charge to all third\n    parties under the terms of this License.\n\n    c) If the modified program normally reads commands interactively\n    when run, you must cause it, when started running for such\n    interactive use in the most ordinary way, to print or display an\n    announcement including an appropriate copyright notice and a\n    notice that there is no warranty (or else, saying that you provide\n    a warranty) and that users may redistribute the program under\n    these conditions, and telling the user how to view a copy of this\n    License.  (Exception: if the Program itself is interactive but\n    does not normally print such an announcement, your work based on\n    the Program is not required to print an announcement.)\n\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Program,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Program, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Program.\n\nIn addition, mere aggregation of another work not based on the Program\nwith the Program (or with a work based on the Program) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may copy and distribute the Program (or a work based on it,\nunder Section 2) in object code or executable form under the terms of\nSections 1 and 2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable\n    source code, which must be distributed under the terms of Sections\n    1 and 2 above on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three\n    years, to give any third party, for a charge no more than your\n    cost of physically performing source distribution, a complete\n    machine-readable copy of the corresponding source code, to be\n    distributed under the terms of Sections 1 and 2 above on a medium\n    customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer\n    to distribute corresponding source code.  (This alternative is\n    allowed only for noncommercial distribution and only if you\n    received the program in object code or executable form with such\n    an offer, in accord with Subsection b above.)\n\nThe source code for a work means the preferred form of the work for\nmaking modifications to it.  For an executable work, complete source\ncode means all the source code for all modules it contains, plus any\nassociated interface definition files, plus the scripts used to\ncontrol compilation and installation of the executable.  However, as a\nspecial exception, the source code distributed need not include\nanything that is normally distributed (in either source or binary\nform) with the major components (compiler, kernel, and so on) of the\noperating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering\naccess to copy from a designated place, then offering equivalent\naccess to copy the source code from the same place counts as\ndistribution of the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n  4. You may not copy, modify, sublicense, or distribute the Program\nexcept as expressly provided under this License.  Any attempt\notherwise to copy, modify, sublicense or distribute the Program is\nvoid, and will automatically terminate your rights under this License.\nHowever, parties who have received copies, or rights, from you under\nthis License will not have their licenses terminated so long as such\nparties remain in full compliance.\n\n  5. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Program or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Program (or any work based on the\nProgram), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n  6. Each time you redistribute the Program (or any work based on the\nProgram), the recipient automatically receives a license from the\noriginal licensor to copy, distribute or modify the Program subject to\nthese terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\n  7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Program at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Program by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under\nany particular circumstance, the balance of the section is intended to\napply and the section as a whole is intended to apply in other\ncircumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system, which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n  8. If the distribution and/or use of the Program is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Program under this License\nmay add an explicit geographical distribution limitation excluding\nthose countries, so that distribution is permitted only in or among\ncountries not thus excluded.  In such case, this License incorporates\nthe limitation as if written in the body of this License.\n\n  9. The Free Software Foundation may publish revised and/or new versions\nof the General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any\nlater version\", you have the option of following the terms and conditions\neither of that version or of any later version published by the Free\nSoftware Foundation.  If the Program does not specify a version number of\nthis License, you may choose any version ever published by the Free Software\nFoundation.\n\n  10. If you wish to incorporate parts of the Program into other free\nprograms whose distribution conditions are different, write to the author\nto ask for permission.  For software which is copyrighted by the Free\nSoftware Foundation, write to the Free Software Foundation; we sometimes\nmake exceptions for this.  Our decision will be guided by the two goals\nof preserving the free status of all derivatives of our free software and\nof promoting the sharing and reuse of software generally.\n\n                            NO WARRANTY\n\n  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\nFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\nOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\nPROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\nOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\nTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\nPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\nREPAIR OR CORRECTION.\n\n  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\nREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\nINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\nOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\nTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\nYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\nPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this\nwhen it starts in an interactive mode:\n\n    Gnomovision version 69, Copyright (C) year name of author\n    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, the commands you use may\nbe called something other than `show w' and `show c'; they could even be\nmouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the program, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n  `Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n  <signature of Ty Coon>, 1 April 1989\n  Ty Coon, President of Vice\n\nThis General Public License does not permit incorporating your program into\nproprietary programs.  If your program is a subroutine library, you may\nconsider it more useful to permit linking proprietary applications with the\nlibrary.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.\n"
  },
  {
    "path": "COPYING.GPLv3",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<http://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<http://www.gnu.org/philosophy/why-not-lgpl.html>.\n"
  },
  {
    "path": "COPYING.LGPLv2.1",
    "content": "                  GNU LESSER GENERAL PUBLIC LICENSE\n                       Version 2.1, February 1999\n\n Copyright (C) 1991, 1999 Free Software Foundation, Inc.\n 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n[This is the first released version of the Lesser GPL.  It also counts\n as the successor of the GNU Library Public License, version 2, hence\n the version number 2.1.]\n\n                            Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicenses are intended to guarantee your freedom to share and change\nfree software--to make sure the software is free for all its users.\n\n  This license, the Lesser General Public License, applies to some\nspecially designated software packages--typically libraries--of the\nFree Software Foundation and other authors who decide to use it.  You\ncan use it too, but we suggest you first think carefully about whether\nthis license or the ordinary General Public License is the better\nstrategy to use in any particular case, based on the explanations below.\n\n  When we speak of free software, we are referring to freedom of use,\nnot price.  Our General Public Licenses are designed to make sure that\nyou have the freedom to distribute copies of free software (and charge\nfor this service if you wish); that you receive source code or can get\nit if you want it; that you can change the software and use pieces of\nit in new free programs; and that you are informed that you can do\nthese things.\n\n  To protect your rights, we need to make restrictions that forbid\ndistributors to deny you these rights or to ask you to surrender these\nrights.  These restrictions translate to certain responsibilities for\nyou if you distribute copies of the library or if you modify it.\n\n  For example, if you distribute copies of the library, whether gratis\nor for a fee, you must give the recipients all the rights that we gave\nyou.  You must make sure that they, too, receive or can get the source\ncode.  If you link other code with the library, you must provide\ncomplete object files to the recipients, so that they can relink them\nwith the library after making changes to the library and recompiling\nit.  And you must show them these terms so they know their rights.\n\n  We protect your rights with a two-step method: (1) we copyright the\nlibrary, and (2) we offer you this license, which gives you legal\npermission to copy, distribute and/or modify the library.\n\n  To protect each distributor, we want to make it very clear that\nthere is no warranty for the free library.  Also, if the library is\nmodified by someone else and passed on, the recipients should know\nthat what they have is not the original version, so that the original\nauthor's reputation will not be affected by problems that might be\nintroduced by others.\n\f\n  Finally, software patents pose a constant threat to the existence of\nany free program.  We wish to make sure that a company cannot\neffectively restrict the users of a free program by obtaining a\nrestrictive license from a patent holder.  Therefore, we insist that\nany patent license obtained for a version of the library must be\nconsistent with the full freedom of use specified in this license.\n\n  Most GNU software, including some libraries, is covered by the\nordinary GNU General Public License.  This license, the GNU Lesser\nGeneral Public License, applies to certain designated libraries, and\nis quite different from the ordinary General Public License.  We use\nthis license for certain libraries in order to permit linking those\nlibraries into non-free programs.\n\n  When a program is linked with a library, whether statically or using\na shared library, the combination of the two is legally speaking a\ncombined work, a derivative of the original library.  The ordinary\nGeneral Public License therefore permits such linking only if the\nentire combination fits its criteria of freedom.  The Lesser General\nPublic License permits more lax criteria for linking other code with\nthe library.\n\n  We call this license the \"Lesser\" General Public License because it\ndoes Less to protect the user's freedom than the ordinary General\nPublic License.  It also provides other free software developers Less\nof an advantage over competing non-free programs.  These disadvantages\nare the reason we use the ordinary General Public License for many\nlibraries.  However, the Lesser license provides advantages in certain\nspecial circumstances.\n\n  For example, on rare occasions, there may be a special need to\nencourage the widest possible use of a certain library, so that it becomes\na de-facto standard.  To achieve this, non-free programs must be\nallowed to use the library.  A more frequent case is that a free\nlibrary does the same job as widely used non-free libraries.  In this\ncase, there is little to gain by limiting the free library to free\nsoftware only, so we use the Lesser General Public License.\n\n  In other cases, permission to use a particular library in non-free\nprograms enables a greater number of people to use a large body of\nfree software.  For example, permission to use the GNU C Library in\nnon-free programs enables many more people to use the whole GNU\noperating system, as well as its variant, the GNU/Linux operating\nsystem.\n\n  Although the Lesser General Public License is Less protective of the\nusers' freedom, it does ensure that the user of a program that is\nlinked with the Library has the freedom and the wherewithal to run\nthat program using a modified version of the Library.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.  Pay close attention to the difference between a\n\"work based on the library\" and a \"work that uses the library\".  The\nformer contains code derived from the library, whereas the latter must\nbe combined with the library in order to run.\n\f\n                  GNU LESSER GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License Agreement applies to any software library or other\nprogram which contains a notice placed by the copyright holder or\nother authorized party saying it may be distributed under the terms of\nthis Lesser General Public License (also called \"this License\").\nEach licensee is addressed as \"you\".\n\n  A \"library\" means a collection of software functions and/or data\nprepared so as to be conveniently linked with application programs\n(which use some of those functions and data) to form executables.\n\n  The \"Library\", below, refers to any such software library or work\nwhich has been distributed under these terms.  A \"work based on the\nLibrary\" means either the Library or any derivative work under\ncopyright law: that is to say, a work containing the Library or a\nportion of it, either verbatim or with modifications and/or translated\nstraightforwardly into another language.  (Hereinafter, translation is\nincluded without limitation in the term \"modification\".)\n\n  \"Source code\" for a work means the preferred form of the work for\nmaking modifications to it.  For a library, complete source code means\nall the source code for all modules it contains, plus any associated\ninterface definition files, plus the scripts used to control compilation\nand installation of the library.\n\n  Activities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning a program using the Library is not restricted, and output from\nsuch a program is covered only if its contents constitute a work based\non the Library (independent of the use of the Library in a tool for\nwriting it).  Whether that is true depends on what the Library does\nand what the program that uses the Library does.\n\n  1. You may copy and distribute verbatim copies of the Library's\ncomplete source code as you receive it, in any medium, provided that\nyou conspicuously and appropriately publish on each copy an\nappropriate copyright notice and disclaimer of warranty; keep intact\nall the notices that refer to this License and to the absence of any\nwarranty; and distribute a copy of this License along with the\nLibrary.\n\n  You may charge a fee for the physical act of transferring a copy,\nand you may at your option offer warranty protection in exchange for a\nfee.\n\f\n  2. You may modify your copy or copies of the Library or any portion\nof it, thus forming a work based on the Library, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) The modified work must itself be a software library.\n\n    b) You must cause the files modified to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    c) You must cause the whole of the work to be licensed at no\n    charge to all third parties under the terms of this License.\n\n    d) If a facility in the modified Library refers to a function or a\n    table of data to be supplied by an application program that uses\n    the facility, other than as an argument passed when the facility\n    is invoked, then you must make a good faith effort to ensure that,\n    in the event an application does not supply such function or\n    table, the facility still operates, and performs whatever part of\n    its purpose remains meaningful.\n\n    (For example, a function in a library to compute square roots has\n    a purpose that is entirely well-defined independent of the\n    application.  Therefore, Subsection 2d requires that any\n    application-supplied function or table used by this function must\n    be optional: if the application does not supply it, the square\n    root function must still compute square roots.)\n\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Library,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Library, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote\nit.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Library.\n\nIn addition, mere aggregation of another work not based on the Library\nwith the Library (or with a work based on the Library) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may opt to apply the terms of the ordinary GNU General Public\nLicense instead of this License to a given copy of the Library.  To do\nthis, you must alter all the notices that refer to this License, so\nthat they refer to the ordinary GNU General Public License, version 2,\ninstead of to this License.  (If a newer version than version 2 of the\nordinary GNU General Public License has appeared, then you can specify\nthat version instead if you wish.)  Do not make any other change in\nthese notices.\n\f\n  Once this change is made in a given copy, it is irreversible for\nthat copy, so the ordinary GNU General Public License applies to all\nsubsequent copies and derivative works made from that copy.\n\n  This option is useful when you wish to copy part of the code of\nthe Library into a program that is not a library.\n\n  4. You may copy and distribute the Library (or a portion or\nderivative of it, under Section 2) in object code or executable form\nunder the terms of Sections 1 and 2 above provided that you accompany\nit with the complete corresponding machine-readable source code, which\nmust be distributed under the terms of Sections 1 and 2 above on a\nmedium customarily used for software interchange.\n\n  If distribution of object code is made by offering access to copy\nfrom a designated place, then offering equivalent access to copy the\nsource code from the same place satisfies the requirement to\ndistribute the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n  5. A program that contains no derivative of any portion of the\nLibrary, but is designed to work with the Library by being compiled or\nlinked with it, is called a \"work that uses the Library\".  Such a\nwork, in isolation, is not a derivative work of the Library, and\ntherefore falls outside the scope of this License.\n\n  However, linking a \"work that uses the Library\" with the Library\ncreates an executable that is a derivative of the Library (because it\ncontains portions of the Library), rather than a \"work that uses the\nlibrary\".  The executable is therefore covered by this License.\nSection 6 states terms for distribution of such executables.\n\n  When a \"work that uses the Library\" uses material from a header file\nthat is part of the Library, the object code for the work may be a\nderivative work of the Library even though the source code is not.\nWhether this is true is especially significant if the work can be\nlinked without the Library, or if the work is itself a library.  The\nthreshold for this to be true is not precisely defined by law.\n\n  If such an object file uses only numerical parameters, data\nstructure layouts and accessors, and small macros and small inline\nfunctions (ten lines or less in length), then the use of the object\nfile is unrestricted, regardless of whether it is legally a derivative\nwork.  (Executables containing this object code plus portions of the\nLibrary will still fall under Section 6.)\n\n  Otherwise, if the work is a derivative of the Library, you may\ndistribute the object code for the work under the terms of Section 6.\nAny executables containing that work also fall under Section 6,\nwhether or not they are linked directly with the Library itself.\n\f\n  6. As an exception to the Sections above, you may also combine or\nlink a \"work that uses the Library\" with the Library to produce a\nwork containing portions of the Library, and distribute that work\nunder terms of your choice, provided that the terms permit\nmodification of the work for the customer's own use and reverse\nengineering for debugging such modifications.\n\n  You must give prominent notice with each copy of the work that the\nLibrary is used in it and that the Library and its use are covered by\nthis License.  You must supply a copy of this License.  If the work\nduring execution displays copyright notices, you must include the\ncopyright notice for the Library among them, as well as a reference\ndirecting the user to the copy of this License.  Also, you must do one\nof these things:\n\n    a) Accompany the work with the complete corresponding\n    machine-readable source code for the Library including whatever\n    changes were used in the work (which must be distributed under\n    Sections 1 and 2 above); and, if the work is an executable linked\n    with the Library, with the complete machine-readable \"work that\n    uses the Library\", as object code and/or source code, so that the\n    user can modify the Library and then relink to produce a modified\n    executable containing the modified Library.  (It is understood\n    that the user who changes the contents of definitions files in the\n    Library will not necessarily be able to recompile the application\n    to use the modified definitions.)\n\n    b) Use a suitable shared library mechanism for linking with the\n    Library.  A suitable mechanism is one that (1) uses at run time a\n    copy of the library already present on the user's computer system,\n    rather than copying library functions into the executable, and (2)\n    will operate properly with a modified version of the library, if\n    the user installs one, as long as the modified version is\n    interface-compatible with the version that the work was made with.\n\n    c) Accompany the work with a written offer, valid for at\n    least three years, to give the same user the materials\n    specified in Subsection 6a, above, for a charge no more\n    than the cost of performing this distribution.\n\n    d) If distribution of the work is made by offering access to copy\n    from a designated place, offer equivalent access to copy the above\n    specified materials from the same place.\n\n    e) Verify that the user has already received a copy of these\n    materials or that you have already sent this user a copy.\n\n  For an executable, the required form of the \"work that uses the\nLibrary\" must include any data and utility programs needed for\nreproducing the executable from it.  However, as a special exception,\nthe materials to be distributed need not include anything that is\nnormally distributed (in either source or binary form) with the major\ncomponents (compiler, kernel, and so on) of the operating system on\nwhich the executable runs, unless that component itself accompanies\nthe executable.\n\n  It may happen that this requirement contradicts the license\nrestrictions of other proprietary libraries that do not normally\naccompany the operating system.  Such a contradiction means you cannot\nuse both them and the Library together in an executable that you\ndistribute.\n\f\n  7. You may place library facilities that are a work based on the\nLibrary side-by-side in a single library together with other library\nfacilities not covered by this License, and distribute such a combined\nlibrary, provided that the separate distribution of the work based on\nthe Library and of the other library facilities is otherwise\npermitted, and provided that you do these two things:\n\n    a) Accompany the combined library with a copy of the same work\n    based on the Library, uncombined with any other library\n    facilities.  This must be distributed under the terms of the\n    Sections above.\n\n    b) Give prominent notice with the combined library of the fact\n    that part of it is a work based on the Library, and explaining\n    where to find the accompanying uncombined form of the same work.\n\n  8. You may not copy, modify, sublicense, link with, or distribute\nthe Library except as expressly provided under this License.  Any\nattempt otherwise to copy, modify, sublicense, link with, or\ndistribute the Library is void, and will automatically terminate your\nrights under this License.  However, parties who have received copies,\nor rights, from you under this License will not have their licenses\nterminated so long as such parties remain in full compliance.\n\n  9. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Library or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Library (or any work based on the\nLibrary), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Library or works based on it.\n\n  10. Each time you redistribute the Library (or any work based on the\nLibrary), the recipient automatically receives a license from the\noriginal licensor to copy, distribute, link with or modify the Library\nsubject to these terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties with\nthis License.\n\f\n  11. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Library at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Library by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Library.\n\nIf any portion of this section is held invalid or unenforceable under any\nparticular circumstance, the balance of the section is intended to apply,\nand the section as a whole is intended to apply in other circumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n  12. If the distribution and/or use of the Library is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Library under this License may add\nan explicit geographical distribution limitation excluding those countries,\nso that distribution is permitted only in or among countries not thus\nexcluded.  In such case, this License incorporates the limitation as if\nwritten in the body of this License.\n\n  13. The Free Software Foundation may publish revised and/or new\nversions of the Lesser General Public License from time to time.\nSuch new versions will be similar in spirit to the present version,\nbut may differ in detail to address new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Library\nspecifies a version number of this License which applies to it and\n\"any later version\", you have the option of following the terms and\nconditions either of that version or of any later version published by\nthe Free Software Foundation.  If the Library does not specify a\nlicense version number, you may choose any version ever published by\nthe Free Software Foundation.\n\f\n  14. If you wish to incorporate parts of the Library into other free\nprograms whose distribution conditions are incompatible with these,\nwrite to the author to ask for permission.  For software which is\ncopyrighted by the Free Software Foundation, write to the Free\nSoftware Foundation; we sometimes make exceptions for this.  Our\ndecision will be guided by the two goals of preserving the free status\nof all derivatives of our free software and of promoting the sharing\nand reuse of software generally.\n\n                            NO WARRANTY\n\n  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO\nWARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.\nEXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR\nOTHER PARTIES PROVIDE THE LIBRARY \"AS IS\" WITHOUT WARRANTY OF ANY\nKIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE\nLIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME\nTHE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN\nWRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY\nAND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU\nFOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR\nCONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE\nLIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING\nRENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A\nFAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF\nSUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH\nDAMAGES.\n\n                     END OF TERMS AND CONDITIONS\n\f\n           How to Apply These Terms to Your New Libraries\n\n  If you develop a new library, and you want it to be of the greatest\npossible use to the public, we recommend making it free software that\neveryone can redistribute and change.  You can do so by permitting\nredistribution under these terms (or, alternatively, under the terms of the\nordinary General Public License).\n\n  To apply these terms, attach the following notices to the library.  It is\nsafest to attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least the\n\"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the library's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This library is free software; you can redistribute it and/or\n    modify it under the terms of the GNU Lesser General Public\n    License as published by the Free Software Foundation; either\n    version 2.1 of the License, or (at your option) any later version.\n\n    This library is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n    Lesser General Public License for more details.\n\n    You should have received a copy of the GNU Lesser General Public\n    License along with this library; if not, write to the Free Software\n    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n\nAlso add information on how to contact you by electronic and paper mail.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the library, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the\n  library `Frob' (a library for tweaking knobs) written by James Random Hacker.\n\n  <signature of Ty Coon>, 1 April 1990\n  Ty Coon, President of Vice\n\nThat's all there is to it!\n"
  },
  {
    "path": "COPYING.LGPLv3",
    "content": "                   GNU LESSER GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n\n  This version of the GNU Lesser General Public License incorporates\nthe terms and conditions of version 3 of the GNU General Public\nLicense, supplemented by the additional permissions listed below.\n\n  0. Additional Definitions.\n\n  As used herein, \"this License\" refers to version 3 of the GNU Lesser\nGeneral Public License, and the \"GNU GPL\" refers to version 3 of the GNU\nGeneral Public License.\n\n  \"The Library\" refers to a covered work governed by this License,\nother than an Application or a Combined Work as defined below.\n\n  An \"Application\" is any work that makes use of an interface provided\nby the Library, but which is not otherwise based on the Library.\nDefining a subclass of a class defined by the Library is deemed a mode\nof using an interface provided by the Library.\n\n  A \"Combined Work\" is a work produced by combining or linking an\nApplication with the Library.  The particular version of the Library\nwith which the Combined Work was made is also called the \"Linked\nVersion\".\n\n  The \"Minimal Corresponding Source\" for a Combined Work means the\nCorresponding Source for the Combined Work, excluding any source code\nfor portions of the Combined Work that, considered in isolation, are\nbased on the Application, and not on the Linked Version.\n\n  The \"Corresponding Application Code\" for a Combined Work means the\nobject code and/or source code for the Application, including any data\nand utility programs needed for reproducing the Combined Work from the\nApplication, but excluding the System Libraries of the Combined Work.\n\n  1. Exception to Section 3 of the GNU GPL.\n\n  You may convey a covered work under sections 3 and 4 of this License\nwithout being bound by section 3 of the GNU GPL.\n\n  2. Conveying Modified Versions.\n\n  If you modify a copy of the Library, and, in your modifications, a\nfacility refers to a function or data to be supplied by an Application\nthat uses the facility (other than as an argument passed when the\nfacility is invoked), then you may convey a copy of the modified\nversion:\n\n   a) under this License, provided that you make a good faith effort to\n   ensure that, in the event an Application does not supply the\n   function or data, the facility still operates, and performs\n   whatever part of its purpose remains meaningful, or\n\n   b) under the GNU GPL, with none of the additional permissions of\n   this License applicable to that copy.\n\n  3. Object Code Incorporating Material from Library Header Files.\n\n  The object code form of an Application may incorporate material from\na header file that is part of the Library.  You may convey such object\ncode under terms of your choice, provided that, if the incorporated\nmaterial is not limited to numerical parameters, data structure\nlayouts and accessors, or small macros, inline functions and templates\n(ten or fewer lines in length), you do both of the following:\n\n   a) Give prominent notice with each copy of the object code that the\n   Library is used in it and that the Library and its use are\n   covered by this License.\n\n   b) Accompany the object code with a copy of the GNU GPL and this license\n   document.\n\n  4. Combined Works.\n\n  You may convey a Combined Work under terms of your choice that,\ntaken together, effectively do not restrict modification of the\nportions of the Library contained in the Combined Work and reverse\nengineering for debugging such modifications, if you also do each of\nthe following:\n\n   a) Give prominent notice with each copy of the Combined Work that\n   the Library is used in it and that the Library and its use are\n   covered by this License.\n\n   b) Accompany the Combined Work with a copy of the GNU GPL and this license\n   document.\n\n   c) For a Combined Work that displays copyright notices during\n   execution, include the copyright notice for the Library among\n   these notices, as well as a reference directing the user to the\n   copies of the GNU GPL and this license document.\n\n   d) Do one of the following:\n\n       0) Convey the Minimal Corresponding Source under the terms of this\n       License, and the Corresponding Application Code in a form\n       suitable for, and under terms that permit, the user to\n       recombine or relink the Application with a modified version of\n       the Linked Version to produce a modified Combined Work, in the\n       manner specified by section 6 of the GNU GPL for conveying\n       Corresponding Source.\n\n       1) Use a suitable shared library mechanism for linking with the\n       Library.  A suitable mechanism is one that (a) uses at run time\n       a copy of the Library already present on the user's computer\n       system, and (b) will operate properly with a modified version\n       of the Library that is interface-compatible with the Linked\n       Version.\n\n   e) Provide Installation Information, but only if you would otherwise\n   be required to provide such information under section 6 of the\n   GNU GPL, and only to the extent that such information is\n   necessary to install and execute a modified version of the\n   Combined Work produced by recombining or relinking the\n   Application with a modified version of the Linked Version. (If\n   you use option 4d0, the Installation Information must accompany\n   the Minimal Corresponding Source and Corresponding Application\n   Code. If you use option 4d1, you must provide the Installation\n   Information in the manner specified by section 6 of the GNU GPL\n   for conveying Corresponding Source.)\n\n  5. Combined Libraries.\n\n  You may place library facilities that are a work based on the\nLibrary side by side in a single library together with other library\nfacilities that are not Applications and are not covered by this\nLicense, and convey such a combined library under terms of your\nchoice, if you do both of the following:\n\n   a) Accompany the combined library with a copy of the same work based\n   on the Library, uncombined with any other library facilities,\n   conveyed under the terms of this License.\n\n   b) Give prominent notice with the combined library that part of it\n   is a work based on the Library, and explaining where to find the\n   accompanying uncombined form of the same work.\n\n  6. Revised Versions of the GNU Lesser General Public License.\n\n  The Free Software Foundation may publish revised and/or new versions\nof the GNU Lesser General Public License from time to time. Such new\nversions will be similar in spirit to the present version, but may\ndiffer in detail to address new problems or concerns.\n\n  Each version is given a distinguishing version number. If the\nLibrary as you received it specifies that a certain numbered version\nof the GNU Lesser General Public License \"or any later version\"\napplies to it, you have the option of following the terms and\nconditions either of that published version or of any later version\npublished by the Free Software Foundation. If the Library as you\nreceived it does not specify a version number of the GNU Lesser\nGeneral Public License, you may choose any version of the GNU Lesser\nGeneral Public License ever published by the Free Software Foundation.\n\n  If the Library as you received it specifies that a proxy can decide\nwhether future versions of the GNU Lesser General Public License shall\napply, that proxy's public statement of acceptance of any version is\npermanent authorization for you to choose that version for the\nLibrary.\n"
  },
  {
    "path": "MODULE_LICENSE_APACHE2",
    "content": ""
  },
  {
    "path": "NEWS.md",
    "content": "tag next\n--------------------------------\n- ffmpeg: upgrade to 4.0\n\ntag k0.8.8\n--------------------------------\n- ffmpeg: upgrade to 3.4\n- ffmpeg: fix hls some issue\n- android: fix seek bug when no audio\n- openssl: upgrade to 1.0.2n\n- ios: vtb support h265\n\ntag k0.8.7\n--------------------------------\n\ntag k0.8.6\n--------------------------------\n- ijkplayer: fix opengl config error\n- ffmpeg: fix a concat issue \n\ntag k0.8.5\n--------------------------------\n- ijkplayer: fix opengl config error\n- ijkplayer: fix some bug about audio\n\ntag k0.8.4\n--------------------------------\n- ffmpeg: enable hevc by default\n- ijkio: support cache share\n- ijkplayer: fix some bug\n\ntag k0.8.3\n--------------------------------\n- ffmpeg: dns cache refactor\n- ijkio: cache support synchronize read avoid frequent lseek\n- ijkplayer: fix some bug\n\ntag k0.8.2\n--------------------------------\n- ffmpeg: fix some bug\n- ijkio: update and modify features\n- ijkplayer: support don't calculate real frame rate, the first frame will speed up\n\ntag k0.8.1\n--------------------------------\n- ffmpeg: support dns cache\n- ijkio: support inject extra node\n\ntag k0.8.0\n--------------------------------\n- ffmpeg: upgrade to 3.3\n- ffmpeg: enable flac\n- android: support sync mediacodec\n- android: support framedrop when use mediacodec\n- openssl: upgrade to 1.0.2k\n- jni4android: upgrade to v0.0.2\n\ntag k0.7.9\n--------------------------------\n- ffmpeg: add tcp timeout control\n- android: support soundtouch\n\ntag k0.7.8\n--------------------------------\n- ffplay: support accurate seek\n- ijkio: fix some issue\n- ios: add ijkplayer dynamic target with ssl\n\ntag k0.7.7\n--------------------------------\n- ffmpeg: enable ijkio protocol\n- ffmpeg: avoid some unreasonable pts\n- ios: fix a crash caused by videotoolbox sync initialization fail\n\ntag k0.7.6\n--------------------------------\n- ffmpeg: ass subtitle support\n- msg_queue: add resource for msg_queue\n- ios: separate vtb sync mode from mixed vtb\n- android: fix some thread competition\n- android: support setSpeed for pre-M(api<23) versions\n\ntag k0.7.5\n--------------------------------\n- ffmpeg: disable-asm on architecture x86\n- ffmpeg: revert some cutted demuxer and decoder\n- ios: add playback volume interface\n\ntag k0.7.4\n--------------------------------\n- ffplay: fix sample buffer leak introduced in k0.7.1\n- doc: add takeoff checklist\n\ntag k0.7.3\n--------------------------------\n- ios: turn videotoolbox into singleton\n- ffmpeg: merge ipv6 issue in tcp.c\n\ntag k0.7.2\n-------------------------------\n- ios: fix a compile error\n\ntag k0.7.1\n-------------------------------\n- ffmpeg: upgrade to n3.2\n\ntag k0.6.3\n--------------------------------\n- ffmpeg: disable clock_gettime added in xcode8\n- android: make NDKr13 happy\n\ntag k0.6.2\n--------------------------------\n- ffmpeg: fix wild pointer when decoder was not found\n- player: fix bug introduced in k0.6.0\n\ntag k0.6.1\n--------------------------------\n- concat: fix crash introduced in k0.6.0\n- flvdec: fix seek problem introduced in k0.6.0\n- hls: fix regression with ranged media segments\n\ntag k0.6.0\n--------------------------------\n- openssl: upgrade to 1.0.2h\n- ffmpeg: upgrade to n3.1\n- MediaCodec: add options to enable resolution change.\n- VideoToolbox: add options to enable resolution change.\n\ntag k0.5.1\n--------------------------------\n- ffmpeg: fix crash introduced in k0.5.0\n\ntag k0.5.0\n--------------------------------\n- ffmpeg: upgrade to n3.0\n- android: support NDKr11\n\ntag k0.4.5\n--------------------------------\n- ios: support playbackRate change. (iOS 7.0 or later)\n- android: support speed change. (Android 6.0 or later)\n- player: do not link avfilter by default.\n- android: add x86_64 support\n- android: move jjk out to jni4android project\n- android: support OpenGL ES2 render\n\ntag k0.4.4\n--------------------------------\n- ios: replace MPMoviePlayerXXX with IJKMPMoviePlayerXXX\n- ios: remove target 'IjkMediaPlayer'. 'IjkMediaFramework' should be used instead.\n- android: switch ExoPlayer to r1.5.2\n\ntag k0.4.3\n--------------------------------\n- android: fix several crash when reconfiguring MediaCodec\n- android: add jjk to generate API native wrapper\n- android: support IMediaDataSource for user to supply media data\n\ntag k0.4.2\n--------------------------------\n- ios: support Xcode 7\n- ios: drop support of iOS 5.x\n- ffmpeg: enable libavfilter\n- player: limited support of libavfilter\n- android: add ExoPlayer as an alternative backend player\n\ntag k0.4.1\n--------------------------------\n- android: support downloading from jcenter\n\ntag k0.4.0\n--------------------------------\n- ffmpeg: switch to ffmpeg n2.8\n\ntag k0.3.3\n--------------------------------\n- player: custom protocol as io hook\n- android/sample: support rotation meta (TextureView only)\n\ntag k0.3.2\n--------------------------------\n- android: drop support of Eclipse\n- android: update to SDK 23\n- android/sample: better UI\n- ios: support SAR\n- android/sample: support background play\n\ntag k0.3.1\n--------------------------------\n- player: key-value options API\n- player: remove ijkutil\n- build: support cygwin\n- ios: optimize performance of VideoToolbox.\n\ntag k0.3.0\n--------------------------------\n- android: support build with Android Studio / Gradle\n- build: improve library fetch\n- openssl: switch to openssl 1.0.1o\n\ntag k0.2.4\n--------------------------------\n- ios: remove armv7s build from default\n- player: introduce key-value options\n- ios: demo improvement\n- ios: support init/play in background.\n- ffmpeg: switch to ffmpeg n2.7\n\ntag k0.2.3\n--------------------------------\n- android: support OpenSL ES\n- ios: support NV12 Render\n- ios: support VideoToolBox\n- ffmpeg: switch to ffmpeg n2.6\n\ntag n0.2.2:\n--------------------------------\n- ffmpeg: switch to ffmpeg n2.5\n- android: fix leak in jni\n- player: retrieve media informations\n\ntag n0.2.1:\n--------------------------------\n- android: support MediaCodec (API 16+)\n\ntag n0.2.0\n--------------------------------\n- player: fix crash on invalid audio\n- android: support build with ndk-r10\n- ios: add IJKAVMoviePlayerController based on AVPlayer API\n- ios: remove some unused interface\n- ios8: fix latency of aout_pause_audio()\n- ios8: upgrade project\n- ffmpeg: switch to ffmpeg n2.4\n\ntag n0.1.3\n--------------------------------\n- ffmpeg: switch to ffmpeg n2.2\n- player: fix complete/error state handle\n- ffmpeg: build with x86_64, armv5\n- android: replace vlc-chroma-asm with libyuv\n\ntag n0.1.2:\n--------------------------------\n- ffmpeg: build with openssl\n- player: fix aout leak\n- player: reduce memory footprint for I420/YV12 overlay\n- ios: snapshot last displayed image\n\ntag n0.1.1:\n--------------------------------\n- player: remove ugly frame drop trick\n- ios: simplify application state handle\n- ios: fix 5.1 channel support\n- player: handle ffmpeg error\n- player: fix leak\n- player: improve buffer indicator\n- player: drop frame for high fps video\n\ntag n0.1.0:\n--------------------------------\n- android: replace AbstractMediaPlayer with IMediaPlayer and other misc interfaces\n- android: remove list player classes due to lack of regression test\n- ios: support build with SDK7\n- ffmpeg: switch to n2.1 base\n- ios: fix possible block on ijkmp_pause\n- ios: set CAEAGLLayer.contentsScale to avoid bad image on retina devices\n- ios: fix handle of AudioSession interruption\n- ios: add AudioQueue api as replacement of AudioUnit api\n- ijksdl: fix non-I420 pixel-format support\n- player: improve late packet/frame dropping\n- player: prefer h264 stream if multiple video stream exists\n\ntag n0.0.6:\n--------------------------------\n- android: fix NativeWindow leak\n- ios: fix a deadlock related to AudioUnit\n- ios: support ffmpeg concat playback\n- ios: add ffmpeg options methods\n- android: limait audio sample-rate to 4kHz~48kHz\n- ios: fix gles texture alignment\n\ntag n0.0.5:\n--------------------------------\n- build: disable -fmodulo-sched -fmodulo-sched-allow-regmoves, may crash on gcc4.7~4.8\n- player: support ios\n- ijksdl: support ios gles2 video output\n- ijksdl: support ios AudioUnit audio output\n- build: add android/ios sub directory\n- player: fix some dead lock\n- build: use shell scripts instead of git-submodule\n- android: use RV32 as default chroma\n\ntag n0.0.4:\n--------------------------------\n- ffmpeg: enable ac3\n- android: target API-18\n- build: switch to NDKr9 gcc4.8 toolchain\n\ntag n0.0.3:\n--------------------------------\n- ffmpeg: switch to tag n2.0\n- ffmpeg: remove rarely used decoders, parsers, demuxers\n- avformat/hls: fix many bugs\n- avformat/http: support reading compressed data\n- avformat/mov: optimize short seek\n- player: fix AudioTrack latency\n- player: refactor play/pause/step/buffering logic\n- player: fix A/V sync\n- yuv2rgb: treat YUVJ420P as YUV420P\n- yuv2rgb: support zero copy of YUV420P frame output to YV12 surface\n- ijksdl: fix SDL_GetTickHR() returns wrong time \n"
  },
  {
    "path": "NOTICE",
    "content": "\n   Copyright (c) 2005-2008, The Android Open Source Project\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n"
  },
  {
    "path": "README.md",
    "content": "# ijkplayer\n\n Platform | Build Status\n -------- | ------------\n Android | [![Build Status](https://travis-ci.org/Bilibili/ci-ijk-ffmpeg-android.svg?branch=master)](https://travis-ci.org/Bilibili/ci-ijk-ffmpeg-android)\n iOS | [![Build Status](https://travis-ci.org/Bilibili/ci-ijk-ffmpeg-ios.svg?branch=master)](https://travis-ci.org/Bilibili/ci-ijk-ffmpeg-ios)\n\nVideo player based on [ffplay](http://ffmpeg.org)\n\n### Download\n\n- Android:\n - Gradle\n```\n# required\nallprojects {\n    repositories {\n        jcenter()\n    }\n}\n\ndependencies {\n    # required, enough for most devices.\n    compile 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'\n    compile 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.8'\n\n    # Other ABIs: optional\n    compile 'tv.danmaku.ijk.media:ijkplayer-armv5:0.8.8'\n    compile 'tv.danmaku.ijk.media:ijkplayer-arm64:0.8.8'\n    compile 'tv.danmaku.ijk.media:ijkplayer-x86:0.8.8'\n    compile 'tv.danmaku.ijk.media:ijkplayer-x86_64:0.8.8'\n\n    # ExoPlayer as IMediaPlayer: optional, experimental\n    compile 'tv.danmaku.ijk.media:ijkplayer-exo:0.8.8'\n}\n```\n- iOS\n - in coming...\n\n### My Build Environment\n- Common\n - Mac OS X 10.11.5\n- Android\n - [NDK r10e](http://developer.android.com/tools/sdk/ndk/index.html)\n - Android Studio 2.1.3\n - Gradle 2.14.1\n- iOS\n - Xcode 7.3 (7D175)\n- [HomeBrew](http://brew.sh)\n - ruby -e \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)\"\n - brew install git\n\n### Latest Changes\n- [NEWS.md](NEWS.md)\n\n### Features\n- Common\n - remove rarely used ffmpeg components to reduce binary size [config/module-lite.sh](config/module-lite.sh)\n - workaround for some buggy online video.\n- Android\n - platform: API 9~23\n - cpu: ARMv7a, ARM64v8a, x86 (ARMv5 is not tested on real devices)\n - api: [MediaPlayer-like](android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IMediaPlayer.java)\n - video-output: NativeWindow, OpenGL ES 2.0\n - audio-output: AudioTrack, OpenSL ES\n - hw-decoder: MediaCodec (API 16+, Android 4.1+)\n - alternative-backend: android.media.MediaPlayer, ExoPlayer\n- iOS\n - platform: iOS 7.0~10.2.x\n - cpu: armv7, arm64, i386, x86_64, (armv7s is obselete)\n - api: [MediaPlayer.framework-like](ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaPlayback.h)\n - video-output: OpenGL ES 2.0\n - audio-output: AudioQueue, AudioUnit\n - hw-decoder: VideoToolbox (iOS 8+)\n - alternative-backend: AVFoundation.Framework.AVPlayer, MediaPlayer.Framework.MPMoviePlayerControlelr (obselete since iOS 8)\n\n### NOT-ON-PLAN\n- obsolete platforms (Android: API-8 and below; iOS: pre-6.0)\n- obsolete cpu: ARMv5, ARMv6, MIPS (I don't even have these types of devices…)\n- native subtitle render\n- avfilter support\n\n### Before Build\n```\n# install homebrew, git, yasm\nruby -e \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)\"\nbrew install git\nbrew install yasm\n\n# add these lines to your ~/.bash_profile or ~/.profile\n# export ANDROID_SDK=<your sdk path>\n# export ANDROID_NDK=<your ndk path>\n\n# on Cygwin (unmaintained)\n# install git, make, yasm\n```\n\n- If you prefer more codec/format\n```\ncd config\nrm module.sh\nln -s module-default.sh module.sh\ncd android/contrib\n# cd ios\nsh compile-ffmpeg.sh clean\n```\n\n- If you prefer less codec/format for smaller binary size (include hevc function)\n```\ncd config\nrm module.sh\nln -s module-lite-hevc.sh module.sh\ncd android/contrib\n# cd ios\nsh compile-ffmpeg.sh clean\n```\n\n- If you prefer less codec/format for smaller binary size (by default)\n```\ncd config\nrm module.sh\nln -s module-lite.sh module.sh\ncd android/contrib\n# cd ios\nsh compile-ffmpeg.sh clean\n```\n\n- For Ubuntu/Debian users.\n```\n# choose [No] to use bash\nsudo dpkg-reconfigure dash\n```\n\n- If you'd like to share your config, pull request is welcome.\n\n### Build Android\n```\ngit clone https://github.com/Bilibili/ijkplayer.git ijkplayer-android\ncd ijkplayer-android\ngit checkout -B latest k0.8.8\n\n./init-android.sh\n\ncd android/contrib\n./compile-ffmpeg.sh clean\n./compile-ffmpeg.sh all\n\ncd ..\n./compile-ijk.sh all\n\n# Android Studio:\n#     Open an existing Android Studio project\n#     Select android/ijkplayer/ and import\n#\n#     define ext block in your root build.gradle\n#     ext {\n#       compileSdkVersion = 23       // depending on your sdk version\n#       buildToolsVersion = \"23.0.0\" // depending on your build tools version\n#\n#       targetSdkVersion = 23        // depending on your sdk version\n#     }\n#\n# If you want to enable debugging ijkplayer(native modules) on Android Studio 2.2+: (experimental)\n#     sh android/patch-debugging-with-lldb.sh armv7a\n#     Install Android Studio 2.2(+)\n#     Preference -> Android SDK -> SDK Tools\n#     Select (LLDB, NDK, Android SDK Build-tools,Cmake) and install\n#     Open an existing Android Studio project\n#     Select android/ijkplayer\n#     Sync Project with Gradle Files\n#     Run -> Edit Configurations -> Debugger -> Symbol Directories\n#     Add \"ijkplayer-armv7a/.externalNativeBuild/ndkBuild/release/obj/local/armeabi-v7a\" to Symbol Directories\n#     Run -> Debug 'ijkplayer-example'\n#     if you want to reverse patches:\n#     sh patch-debugging-with-lldb.sh reverse armv7a\n#\n# Eclipse: (obselete)\n#     File -> New -> Project -> Android Project from Existing Code\n#     Select android/ and import all project\n#     Import appcompat-v7\n#     Import preference-v7\n#\n# Gradle\n#     cd ijkplayer\n#     gradle\n\n```\n\n\n### Build iOS\n```\ngit clone https://github.com/Bilibili/ijkplayer.git ijkplayer-ios\ncd ijkplayer-ios\ngit checkout -B latest k0.8.8\n\n./init-ios.sh\n\ncd ios\n./compile-ffmpeg.sh clean\n./compile-ffmpeg.sh all\n\n# Demo\n#     open ios/IJKMediaDemo/IJKMediaDemo.xcodeproj with Xcode\n# \n# Import into Your own Application\n#     Select your project in Xcode.\n#     File -> Add Files to ... -> Select ios/IJKMediaPlayer/IJKMediaPlayer.xcodeproj\n#     Select your Application's target.\n#     Build Phases -> Target Dependencies -> Select IJKMediaFramework\n#     Build Phases -> Link Binary with Libraries -> Add:\n#         IJKMediaFramework.framework\n#\n#         AudioToolbox.framework\n#         AVFoundation.framework\n#         CoreGraphics.framework\n#         CoreMedia.framework\n#         CoreVideo.framework\n#         libbz2.tbd\n#         libz.tbd\n#         MediaPlayer.framework\n#         MobileCoreServices.framework\n#         OpenGLES.framework\n#         QuartzCore.framework\n#         UIKit.framework\n#         VideoToolbox.framework\n#\n#         ... (Maybe something else, if you get any link error)\n# \n```\n\n\n### Support (支持) ###\n- Please do not send e-mail to me. Public technical discussion on github is preferred.\n- 请尽量在 github 上公开讨论[技术问题](https://github.com/bilibili/ijkplayer/issues)，不要以邮件方式私下询问，恕不一一回复。\n\n\n### License\n\n```\nCopyright (c) 2017 Bilibili\nLicensed under LGPLv2.1 or later\n```\n\nijkplayer required features are based on or derives from projects below:\n- LGPL\n  - [FFmpeg](http://git.videolan.org/?p=ffmpeg.git)\n  - [libVLC](http://git.videolan.org/?p=vlc.git)\n  - [kxmovie](https://github.com/kolyvan/kxmovie)\n  - [soundtouch](http://www.surina.net/soundtouch/sourcecode.html)\n- zlib license\n  - [SDL](http://www.libsdl.org)\n- BSD-style license\n  - [libyuv](https://code.google.com/p/libyuv/)\n- ISC license\n  - [libyuv/source/x86inc.asm](https://code.google.com/p/libyuv/source/browse/trunk/source/x86inc.asm)\n\nandroid/ijkplayer-exo is based on or derives from projects below:\n- Apache License 2.0\n  - [ExoPlayer](https://github.com/google/ExoPlayer)\n\nandroid/example is based on or derives from projects below:\n- GPL\n  - [android-ndk-profiler](https://github.com/richq/android-ndk-profiler) (not included by default)\n\nios/IJKMediaDemo is based on or derives from projects below:\n- Unknown license\n  - [iOS7-BarcodeScanner](https://github.com/jpwiddy/iOS7-BarcodeScanner)\n\nijkplayer's build scripts are based on or derives from projects below:\n- [gas-preprocessor](http://git.libav.org/?p=gas-preprocessor.git)\n- [VideoLAN](http://git.videolan.org)\n- [yixia/FFmpeg-Android](https://github.com/yixia/FFmpeg-Android)\n- [kewlbear/FFmpeg-iOS-build-script](https://github.com/kewlbear/FFmpeg-iOS-build-script) \n\n### Commercial Use\nijkplayer is licensed under LGPLv2.1 or later, so itself is free for commercial use under LGPLv2.1 or later\n\nBut ijkplayer is also based on other different projects under various licenses, which I have no idea whether they are compatible to each other or to your product.\n\n[IANAL](https://en.wikipedia.org/wiki/IANAL), you should always ask your lawyer for these stuffs before use it in your product.\n"
  },
  {
    "path": "android/.gitignore",
    "content": "#--------------------\n# Android.gitignore\n# https://github.com/github/gitignore/blob/master/Android.gitignore\n#--------------------\n# Built application files\n*.apk\n*.ap_\n\n# Files for the Dalvik VM\n*.dex\n\n# Java class files\n*.class\n\n# Generated files\nbin/\ngen/\n\n# Gradle files\n.gradle/\nbuild/\n\n# Local configuration file (sdk path, etc)\nlocal.properties\n\n# Proguard folder generated by Eclipse\nproguard/\n\n# Log Files\n*.log\n\n#--------------------\n# Gradle.gitignore\n# https://github.com/github/gitignore/blob/master/Gradle.gitignore\n#--------------------\n.gradle\nbuild/\n\n# Ignore Gradle GUI config\ngradle-app.setting\n\n# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)\n!gradle-wrapper.jar\n\n\n#--------------------\n# Android Studio .gitignore\n# https://gist.github.com/iainconnor/8605514\n#--------------------\n# Built application files\n/*/build/\n \n# Crashlytics configuations\ncom_crashlytics_export_strings.xml\n \n# Local configuration file (sdk path, etc)\nlocal.properties\n \n# Gradle generated files\n.gradle/\n \n# Signing files\n.signing/\n \n# User-specific configurations\n.idea/libraries/\n.idea/workspace.xml\n.idea/tasks.xml\n.idea/.name\n.idea/compiler.xml\n.idea/copyright/profiles_settings.xml\n.idea/encodings.xml\n.idea/misc.xml\n.idea/modules.xml\n.idea/scopes/scope_settings.xml\n.idea/vcs.xml\n*.iml\n \n# OS-specific files\n.DS_Store\n.DS_Store?\n._*\n.Spotlight-V100\n.Trashes\nehthumbs.db\nThumbs.db\n"
  },
  {
    "path": "android/build-on-travis.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2014 Bilibili\n# Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nset -e\n\nif [ -z \"$ANDROID_NDK\" -o -z \"$ANDROID_NDK\" ]; then\n    echo \"You must define ANDROID_NDK, ANDROID_SDK before starting.\"\n    echo \"They must point to your NDK and SDK directories.\\n\"\n    exit 1\nfi\n\n\nREQUEST_TARGET=$1\nACT_ABI_32=\"armv5 armv7a x86\"\nACT_ABI_64=\"armv5 armv7a arm64 x86 x86_64\"\nACT_ABI_ALL=$ACT_ABI_64\n\n\nIJK_VERSION=`../version.sh show`\n\n\n\nwget_uploaded_version() {\n    PARAM_TARGET=$1\n\n    VERSION_URL=\"https://jcenter.bintray.com/tv/danmaku/ijk/media/ijkplayer-$PARAM_TARGET/$IJK_VERSION\"\n    echo \"VERSION_URL=\"$VERSION_URL\n    wget $VERSION_URL -O /dev/null\n}\n\ndo_build_native() {\n    PARAM_TARGET=$1\n\n    wget_uploaded_version $PARAM_TARGET && echo \"ijkplayer-$PARAM_TARGET $IJK_VERSION already uploaded, skip...\" && return 0\n\n    cd contrib\n    ./compile-ffmpeg.sh $PARAM_TARGET\n    cd ..\n    ./compile-ijk.sh $PARAM_TARGET\n    cd ijkplayer\n    ./gradlew :ijkplayer-$PARAM_TARGET:bintrayUpload\n    cd ..\n}\n\ndo_build_java() {\n    wget_uploaded_version java && echo \"ijkplayer-$PARAM_TARGET $IJK_VERSION already uploaded, skip...\" && return 0\n\n    cd ijkplayer\n    ./gradlew :ijkplayer-java:bintrayUpload\n    cd ..\n}\n\ndo_build_exo() {\n    wget_uploaded_version exo && echo \"ijkplayer-$PARAM_TARGET $IJK_VERSION already uploaded, skip...\" && return 0\n\n    cd ijkplayer\n    ./gradlew :ijkplayer-exo:bintrayUpload\n    cd ..\n}\n\ncase \"$REQUEST_TARGET\" in\n    armv5|armv7a|arm64|x86|x86_64)\n        do_build_native $REQUEST_TARGET\n    ;;\n    java)\n        do_build_java\n    ;;\n    exo)\n        do_build_exo\n    ;;\n    all32)\n        do_build_java\n        for ABI in $ACT_ABI_32\n        do\n            do_build_native \"$ABI\";\n        done\n        do_build_exo\n    ;;\n    all|all64)\n        do_build_java\n        for ABI in $ACT_ABI_64\n        do\n            do_build_native \"$ABI\";\n        done\n        do_build_exo\n    ;;\n    *)\n        echo \"Usage:\"\n        echo \"  build-on-travis.sh armv5|armv7a|arm64|x86|x86_64\"\n        echo \"  build-on-travis.sh java\"\n        echo \"  build-on-travis.sh exo\"\n        echo \"  build-on-travis.sh all|all32\"\n        echo \"  build-on-travis.sh all64\"\n    ;;\nesac\n\n"
  },
  {
    "path": "android/compile-ijk.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2014 Bilibili\n# Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nif [ -z \"$ANDROID_NDK\" -o -z \"$ANDROID_NDK\" ]; then\n    echo \"You must define ANDROID_NDK, ANDROID_SDK before starting.\"\n    echo \"They must point to your NDK and SDK directories.\\n\"\n    exit 1\nfi\n\nREQUEST_TARGET=$1\nREQUEST_SUB_CMD=$2\nACT_ABI_32=\"armv5 armv7a x86\"\nACT_ABI_64=\"armv5 armv7a arm64 x86 x86_64\"\nACT_ABI_ALL=$ACT_ABI_64\nUNAME_S=$(uname -s)\n\nFF_MAKEFLAGS=\nif which nproc >/dev/null\nthen\n    FF_MAKEFLAGS=-j`nproc`\nelif [ \"$UNAME_S\" = \"Darwin\" ] && which sysctl >/dev/null\nthen\n    FF_MAKEFLAGS=-j`sysctl -n machdep.cpu.thread_count`\nfi\n\ndo_sub_cmd () {\n    SUB_CMD=$1\n    if [ -L \"./android-ndk-prof\" ]; then\n        rm android-ndk-prof\n    fi\n\n    if [ \"$PARAM_SUB_CMD\" = 'prof' ]; then\n        echo 'profiler build: YES';\n        ln -s ../../../../../../ijkprof/android-ndk-profiler/jni android-ndk-prof\n    else\n        echo 'profiler build: NO';\n        ln -s ../../../../../../ijkprof/android-ndk-profiler-dummy/jni android-ndk-prof\n    fi\n\n    case $SUB_CMD in\n        prof)\n            $ANDROID_NDK/ndk-build $FF_MAKEFLAGS\n        ;;\n        clean)\n            $ANDROID_NDK/ndk-build clean\n        ;;\n        rebuild)\n            $ANDROID_NDK/ndk-build clean\n            $ANDROID_NDK/ndk-build $FF_MAKEFLAGS\n        ;;\n        *)\n            $ANDROID_NDK/ndk-build $FF_MAKEFLAGS\n        ;;\n    esac\n}\n\ndo_ndk_build () {\n    PARAM_TARGET=$1\n    PARAM_SUB_CMD=$2\n    case \"$PARAM_TARGET\" in\n        armv5|armv7a)\n            cd \"ijkplayer/ijkplayer-$PARAM_TARGET/src/main/jni\"\n            do_sub_cmd $PARAM_SUB_CMD\n            cd -\n        ;;\n        arm64|x86|x86_64)\n            cd \"ijkplayer/ijkplayer-$PARAM_TARGET/src/main/jni\"\n            if [ \"$PARAM_SUB_CMD\" = 'prof' ]; then PARAM_SUB_CMD=''; fi\n            do_sub_cmd $PARAM_SUB_CMD\n            cd -\n        ;;\n    esac\n}\n\n\ncase \"$REQUEST_TARGET\" in\n    \"\")\n        do_ndk_build armv7a;\n    ;;\n    armv5|armv7a|arm64|x86|x86_64)\n        do_ndk_build $REQUEST_TARGET $REQUEST_SUB_CMD;\n    ;;\n    all32)\n        for ABI in $ACT_ABI_32\n        do\n            do_ndk_build \"$ABI\" $REQUEST_SUB_CMD;\n        done\n    ;;\n    all|all64)\n        for ABI in $ACT_ABI_64\n        do\n            do_ndk_build \"$ABI\" $REQUEST_SUB_CMD;\n        done\n    ;;\n    clean)\n        for ABI in $ACT_ABI_ALL\n        do\n            do_ndk_build \"$ABI\" clean;\n        done\n    ;;\n    *)\n        echo \"Usage:\"\n        echo \"  compile-ijk.sh armv5|armv7a|arm64|x86|x86_64\"\n        echo \"  compile-ijk.sh all|all32\"\n        echo \"  compile-ijk.sh all64\"\n        echo \"  compile-ijk.sh clean\"\n    ;;\nesac\n\n"
  },
  {
    "path": "android/contrib/.gitignore",
    "content": "build\nffmpeg-*\nlibsoxr-*\nopenssl-*\n"
  },
  {
    "path": "android/contrib/compile-ffmpeg.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# This script is based on projects below\n# https://github.com/yixia/FFmpeg-Android\n# http://git.videolan.org/?p=vlc-ports/android.git;a=summary\n\n#----------\nUNI_BUILD_ROOT=`pwd`\nFF_TARGET=$1\nFF_TARGET_EXTRA=$2\nset -e\nset +x\n\nFF_ACT_ARCHS_32=\"armv5 armv7a x86\"\nFF_ACT_ARCHS_64=\"armv5 armv7a arm64 x86 x86_64\"\nFF_ACT_ARCHS_ALL=$FF_ACT_ARCHS_64\n\necho_archs() {\n    echo \"====================\"\n    echo \"[*] check archs\"\n    echo \"====================\"\n    echo \"FF_ALL_ARCHS = $FF_ACT_ARCHS_ALL\"\n    echo \"FF_ACT_ARCHS = $*\"\n    echo \"\"\n}\n\necho_usage() {\n    echo \"Usage:\"\n    echo \"  compile-ffmpeg.sh armv5|armv7a|arm64|x86|x86_64\"\n    echo \"  compile-ffmpeg.sh all|all32\"\n    echo \"  compile-ffmpeg.sh all64\"\n    echo \"  compile-ffmpeg.sh clean\"\n    echo \"  compile-ffmpeg.sh check\"\n    exit 1\n}\n\necho_nextstep_help() {\n    echo \"\"\n    echo \"--------------------\"\n    echo \"[*] Finished\"\n    echo \"--------------------\"\n    echo \"# to continue to build ijkplayer, run script below,\"\n    echo \"sh compile-ijk.sh \"\n}\n\n#----------\ncase \"$FF_TARGET\" in\n    \"\")\n        echo_archs armv7a\n        sh tools/do-compile-ffmpeg.sh armv7a\n    ;;\n    armv5|armv7a|arm64|x86|x86_64)\n        echo_archs $FF_TARGET $FF_TARGET_EXTRA\n        sh tools/do-compile-ffmpeg.sh $FF_TARGET $FF_TARGET_EXTRA\n        echo_nextstep_help\n    ;;\n    all32)\n        echo_archs $FF_ACT_ARCHS_32\n        for ARCH in $FF_ACT_ARCHS_32\n        do\n            sh tools/do-compile-ffmpeg.sh $ARCH $FF_TARGET_EXTRA\n        done\n        echo_nextstep_help\n    ;;\n    all|all64)\n        echo_archs $FF_ACT_ARCHS_64\n        for ARCH in $FF_ACT_ARCHS_64\n        do\n            sh tools/do-compile-ffmpeg.sh $ARCH $FF_TARGET_EXTRA\n        done\n        echo_nextstep_help\n    ;;\n    clean)\n        echo_archs FF_ACT_ARCHS_64\n        for ARCH in $FF_ACT_ARCHS_ALL\n        do\n            if [ -d ffmpeg-$ARCH ]; then\n                cd ffmpeg-$ARCH && git clean -xdf && cd -\n            fi\n        done\n        rm -rf ./build/ffmpeg-*\n    ;;\n    check)\n        echo_archs FF_ACT_ARCHS_ALL\n    ;;\n    *)\n        echo_usage\n        exit 1\n    ;;\nesac\n"
  },
  {
    "path": "android/contrib/compile-libsoxr.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n#----------\nUNI_BUILD_ROOT=`pwd`\nFF_TARGET=$1\nset -e\nset +x\n\nFF_ACT_ARCHS_32=\"armv5 armv7a x86\"\nFF_ACT_ARCHS_64=\"armv5 armv7a arm64 x86 x86_64\"\nFF_ACT_ARCHS_ALL=$FF_ACT_ARCHS_64\n\necho_archs() {\n    echo \"====================\"\n    echo \"[*] check archs\"\n    echo \"====================\"\n    echo \"FF_ALL_ARCHS = $FF_ACT_ARCHS_ALL\"\n    echo \"FF_ACT_ARCHS = $*\"\n    echo \"\"\n}\n\necho_usage() {\n    echo \"Usage:\"\n    echo \"  compile-libsoxr.sh armv5|armv7a|arm64|x86|x86_64\"\n    echo \"  compile-libsoxr.sh all|all32\"\n    echo \"  compile-libsoxr.sh all64\"\n    echo \"  compile-libsoxr.sh clean\"\n    echo \"  compile-libsoxr.sh check\"\n    exit 1\n}\n\necho_nextstep_help() {\n    #----------\n    echo \"\"\n    echo \"--------------------\"\n    echo \"[*] Finished\"\n    echo \"--------------------\"\n    echo \"# to continue to build ffmpeg, run script below,\"\n    echo \"sh compile-ffmpeg.sh \"\n    echo \"# to continue to build ijkplayer, run script below,\"\n    echo \"sh compile-ijk.sh \"\n}\n\n#----------\ncase \"$FF_TARGET\" in\n    \"\")\n        echo_archs armv7a\n        sh tools/do-compile-libsoxr.sh armv7a\n    ;;\n    armv5|armv7a|arm64|x86|x86_64)\n        echo_archs $FF_TARGET\n        sh tools/do-compile-libsoxr.sh $FF_TARGET\n        echo_nextstep_help\n    ;;\n    all32)\n        echo_archs $FF_ACT_ARCHS_32\n        for ARCH in $FF_ACT_ARCHS_32\n        do\n            sh tools/do-compile-libsoxr.sh $ARCH\n        done\n        echo_nextstep_help\n    ;;\n    all|all64)\n        echo_archs $FF_ACT_ARCHS_64\n        for ARCH in $FF_ACT_ARCHS_64\n        do\n            sh tools/do-compile-libsoxr.sh $ARCH\n        done\n        echo_nextstep_help\n    ;;\n    clean)\n        echo_archs FF_ACT_ARCHS_64\n        for ARCH in $FF_ACT_ARCHS_ALL\n        do\n            if [ -d libsoxr-$ARCH ]; then\n                cd libsoxr-$ARCH && git clean -xdf && cd -\n            fi\n        done\n        rm -rf ./build/libsoxr-*\n    ;;\n    check)\n        echo_archs FF_ACT_ARCHS_ALL\n    ;;\n    *)\n        echo_usage\n        exit 1\n    ;;\nesac\n"
  },
  {
    "path": "android/contrib/compile-openssl.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n#----------\nUNI_BUILD_ROOT=`pwd`\nFF_TARGET=$1\nset -e\nset +x\n\nFF_ACT_ARCHS_32=\"armv5 armv7a x86\"\nFF_ACT_ARCHS_64=\"armv5 armv7a arm64 x86 x86_64\"\nFF_ACT_ARCHS_ALL=$FF_ACT_ARCHS_64\n\necho_archs() {\n    echo \"====================\"\n    echo \"[*] check archs\"\n    echo \"====================\"\n    echo \"FF_ALL_ARCHS = $FF_ACT_ARCHS_ALL\"\n    echo \"FF_ACT_ARCHS = $*\"\n    echo \"\"\n}\n\necho_usage() {\n    echo \"Usage:\"\n    echo \"  compile-openssl.sh armv5|armv7a|arm64|x86|x86_64\"\n    echo \"  compile-openssl.sh all|all32\"\n    echo \"  compile-openssl.sh all64\"\n    echo \"  compile-openssl.sh clean\"\n    echo \"  compile-openssl.sh check\"\n    exit 1\n}\n\necho_nextstep_help() {\n    #----------\n    echo \"\"\n    echo \"--------------------\"\n    echo \"[*] Finished\"\n    echo \"--------------------\"\n    echo \"# to continue to build ffmpeg, run script below,\"\n    echo \"sh compile-ffmpeg.sh \"\n    echo \"# to continue to build ijkplayer, run script below,\"\n    echo \"sh compile-ijk.sh \"\n}\n\n#----------\ncase \"$FF_TARGET\" in\n    \"\")\n        echo_archs armv7a\n        sh tools/do-compile-openssl.sh armv7a\n    ;;\n    armv5|armv7a|arm64|x86|x86_64)\n        echo_archs $FF_TARGET\n        sh tools/do-compile-openssl.sh $FF_TARGET\n        echo_nextstep_help\n    ;;\n    all32)\n        echo_archs $FF_ACT_ARCHS_32\n        for ARCH in $FF_ACT_ARCHS_32\n        do\n            sh tools/do-compile-openssl.sh $ARCH\n        done\n        echo_nextstep_help\n    ;;\n    all|all64)\n        echo_archs $FF_ACT_ARCHS_64\n        for ARCH in $FF_ACT_ARCHS_64\n        do\n            sh tools/do-compile-openssl.sh $ARCH\n        done\n        echo_nextstep_help\n    ;;\n    clean)\n        echo_archs FF_ACT_ARCHS_64\n        for ARCH in $FF_ACT_ARCHS_ALL\n        do\n            if [ -d openssl-$ARCH ]; then\n                cd openssl-$ARCH && git clean -xdf && cd -\n            fi\n        done\n        rm -rf ./build/openssl-*\n    ;;\n    check)\n        echo_archs FF_ACT_ARCHS_ALL\n    ;;\n    *)\n        echo_usage\n        exit 1\n    ;;\nesac\n"
  },
  {
    "path": "android/contrib/setup-as-commiter.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\ncd ffmpeg-armv7a\n\ngit remote set-url --push origin git@github.com:bbcallen/FFmpeg.git\n\ngit remote add ffmpeg git://source.ffmpeg.org/ffmpeg.git\ngit remote add libav git://git.libav.org/libav.git\ngit remote add chromium https://chromium.googlesource.com/chromium/third_party/ffmpeg\ngit remote add gitcafe git@gitcafe.com:bbcallen/FFmpeg.git\ngit remote add oschina git@git.oschina.net:bbcallen/ffmpeg.git\ngit remote add csdn git@code.csdn.net:bbcallen/FFmpeg.git\ngit fetch --all\n\ngit branch --track ffmpeg ffmpeg/master\ngit branch --track libav libav/master\ngit branch --track chromium chromium/master\n"
  },
  {
    "path": "android/contrib/sync-mirrors.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\ncd ffmpeg-armv7a\n\ngit checkout ffmpeg\ngit pull\ngit checkout -\n\ngit checkout libav\ngit pull\ngit checkout -\n\ngit checkout master\ngit pull\ngit merge ffmpeg\ngit checkout -\n\ngit push origin --all --follow-tags\ngit push gitcafe --all --follow-tags\ngit push oschina --all --follow-tags\ngit push csdn --all --follow-tags\n\ncd -\n"
  },
  {
    "path": "android/contrib/tools/do-compile-ffmpeg.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# This script is based on projects below\n# https://github.com/yixia/FFmpeg-Android\n# http://git.videolan.org/?p=vlc-ports/android.git;a=summary\n\n#--------------------\necho \"====================\"\necho \"[*] check env $1\"\necho \"====================\"\nset -e\n\n\n#--------------------\n# common defines\nFF_ARCH=$1\nFF_BUILD_OPT=$2\necho \"FF_ARCH=$FF_ARCH\"\necho \"FF_BUILD_OPT=$FF_BUILD_OPT\"\nif [ -z \"$FF_ARCH\" ]; then\n    echo \"You must specific an architecture 'arm, armv7a, x86, ...'.\"\n    echo \"\"\n    exit 1\nfi\n\n\nFF_BUILD_ROOT=`pwd`\nFF_ANDROID_PLATFORM=android-9\n\n\nFF_BUILD_NAME=\nFF_SOURCE=\nFF_CROSS_PREFIX=\nFF_DEP_OPENSSL_INC=\nFF_DEP_OPENSSL_LIB=\n\nFF_DEP_LIBSOXR_INC=\nFF_DEP_LIBSOXR_LIB=\n\nFF_CFG_FLAGS=\n\nFF_EXTRA_CFLAGS=\nFF_EXTRA_LDFLAGS=\nFF_DEP_LIBS=\n\nFF_MODULE_DIRS=\"compat libavcodec libavfilter libavformat libavutil libswresample libswscale\"\nFF_ASSEMBLER_SUB_DIRS=\n\n\n#--------------------\necho \"\"\necho \"--------------------\"\necho \"[*] make NDK standalone toolchain\"\necho \"--------------------\"\n. ./tools/do-detect-env.sh\nFF_MAKE_TOOLCHAIN_FLAGS=$IJK_MAKE_TOOLCHAIN_FLAGS\nFF_MAKE_FLAGS=$IJK_MAKE_FLAG\nFF_GCC_VER=$IJK_GCC_VER\nFF_GCC_64_VER=$IJK_GCC_64_VER\n\n\n#----- armv7a begin -----\nif [ \"$FF_ARCH\" = \"armv7a\" ]; then\n    FF_BUILD_NAME=ffmpeg-armv7a\n    FF_BUILD_NAME_OPENSSL=openssl-armv7a\n    FF_BUILD_NAME_LIBSOXR=libsoxr-armv7a\n    FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME\n\n    FF_CROSS_PREFIX=arm-linux-androideabi\n    FF_TOOLCHAIN_NAME=${FF_CROSS_PREFIX}-${FF_GCC_VER}\n\n    FF_CFG_FLAGS=\"$FF_CFG_FLAGS --arch=arm --cpu=cortex-a8\"\n    FF_CFG_FLAGS=\"$FF_CFG_FLAGS --enable-neon\"\n    FF_CFG_FLAGS=\"$FF_CFG_FLAGS --enable-thumb\"\n\n    FF_EXTRA_CFLAGS=\"$FF_EXTRA_CFLAGS -march=armv7-a -mcpu=cortex-a8 -mfpu=vfpv3-d16 -mfloat-abi=softfp -mthumb\"\n    FF_EXTRA_LDFLAGS=\"$FF_EXTRA_LDFLAGS -Wl,--fix-cortex-a8\"\n\n    FF_ASSEMBLER_SUB_DIRS=\"arm\"\n\nelif [ \"$FF_ARCH\" = \"armv5\" ]; then\n    FF_BUILD_NAME=ffmpeg-armv5\n    FF_BUILD_NAME_OPENSSL=openssl-armv5\n    FF_BUILD_NAME_LIBSOXR=libsoxr-armv5\n    FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME\n\n    FF_CROSS_PREFIX=arm-linux-androideabi\n    FF_TOOLCHAIN_NAME=${FF_CROSS_PREFIX}-${FF_GCC_VER}\n\n    FF_CFG_FLAGS=\"$FF_CFG_FLAGS --arch=arm\"\n\n    FF_EXTRA_CFLAGS=\"$FF_EXTRA_CFLAGS -march=armv5te -mtune=arm9tdmi -msoft-float\"\n    FF_EXTRA_LDFLAGS=\"$FF_EXTRA_LDFLAGS\"\n\n    FF_ASSEMBLER_SUB_DIRS=\"arm\"\n\nelif [ \"$FF_ARCH\" = \"x86\" ]; then\n    FF_BUILD_NAME=ffmpeg-x86\n    FF_BUILD_NAME_OPENSSL=openssl-x86\n    FF_BUILD_NAME_LIBSOXR=libsoxr-x86\n    FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME\n\n    FF_CROSS_PREFIX=i686-linux-android\n    FF_TOOLCHAIN_NAME=x86-${FF_GCC_VER}\n\n    FF_CFG_FLAGS=\"$FF_CFG_FLAGS --arch=x86 --cpu=i686 --enable-yasm\"\n\n    FF_EXTRA_CFLAGS=\"$FF_EXTRA_CFLAGS -march=atom -msse3 -ffast-math -mfpmath=sse\"\n    FF_EXTRA_LDFLAGS=\"$FF_EXTRA_LDFLAGS\"\n\n    FF_ASSEMBLER_SUB_DIRS=\"x86\"\n\nelif [ \"$FF_ARCH\" = \"x86_64\" ]; then\n    FF_ANDROID_PLATFORM=android-21\n\n    FF_BUILD_NAME=ffmpeg-x86_64\n    FF_BUILD_NAME_OPENSSL=openssl-x86_64\n    FF_BUILD_NAME_LIBSOXR=libsoxr-x86_64\n    FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME\n\n    FF_CROSS_PREFIX=x86_64-linux-android\n    FF_TOOLCHAIN_NAME=${FF_CROSS_PREFIX}-${FF_GCC_64_VER}\n\n    FF_CFG_FLAGS=\"$FF_CFG_FLAGS --arch=x86_64 --enable-yasm\"\n\n    FF_EXTRA_CFLAGS=\"$FF_EXTRA_CFLAGS\"\n    FF_EXTRA_LDFLAGS=\"$FF_EXTRA_LDFLAGS\"\n\n    FF_ASSEMBLER_SUB_DIRS=\"x86\"\n\nelif [ \"$FF_ARCH\" = \"arm64\" ]; then\n    FF_ANDROID_PLATFORM=android-21\n\n    FF_BUILD_NAME=ffmpeg-arm64\n    FF_BUILD_NAME_OPENSSL=openssl-arm64\n    FF_BUILD_NAME_LIBSOXR=libsoxr-arm64\n    FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME\n\n    FF_CROSS_PREFIX=aarch64-linux-android\n    FF_TOOLCHAIN_NAME=${FF_CROSS_PREFIX}-${FF_GCC_64_VER}\n\n    FF_CFG_FLAGS=\"$FF_CFG_FLAGS --arch=aarch64 --enable-yasm\"\n\n    FF_EXTRA_CFLAGS=\"$FF_EXTRA_CFLAGS\"\n    FF_EXTRA_LDFLAGS=\"$FF_EXTRA_LDFLAGS\"\n\n    FF_ASSEMBLER_SUB_DIRS=\"aarch64 neon\"\n\nelse\n    echo \"unknown architecture $FF_ARCH\";\n    exit 1\nfi\n\nif [ ! -d $FF_SOURCE ]; then\n    echo \"\"\n    echo \"!! ERROR\"\n    echo \"!! Can not find FFmpeg directory for $FF_BUILD_NAME\"\n    echo \"!! Run 'sh init-android.sh' first\"\n    echo \"\"\n    exit 1\nfi\n\nFF_TOOLCHAIN_PATH=$FF_BUILD_ROOT/build/$FF_BUILD_NAME/toolchain\nFF_MAKE_TOOLCHAIN_FLAGS=\"$FF_MAKE_TOOLCHAIN_FLAGS --install-dir=$FF_TOOLCHAIN_PATH\"\n\nFF_SYSROOT=$FF_TOOLCHAIN_PATH/sysroot\nFF_PREFIX=$FF_BUILD_ROOT/build/$FF_BUILD_NAME/output\nFF_DEP_OPENSSL_INC=$FF_BUILD_ROOT/build/$FF_BUILD_NAME_OPENSSL/output/include\nFF_DEP_OPENSSL_LIB=$FF_BUILD_ROOT/build/$FF_BUILD_NAME_OPENSSL/output/lib\nFF_DEP_LIBSOXR_INC=$FF_BUILD_ROOT/build/$FF_BUILD_NAME_LIBSOXR/output/include\nFF_DEP_LIBSOXR_LIB=$FF_BUILD_ROOT/build/$FF_BUILD_NAME_LIBSOXR/output/lib\n\ncase \"$UNAME_S\" in\n    CYGWIN_NT-*)\n        FF_SYSROOT=\"$(cygpath -am $FF_SYSROOT)\"\n        FF_PREFIX=\"$(cygpath -am $FF_PREFIX)\"\n    ;;\nesac\n\n\nmkdir -p $FF_PREFIX\n# mkdir -p $FF_SYSROOT\n\n\nFF_TOOLCHAIN_TOUCH=\"$FF_TOOLCHAIN_PATH/touch\"\nif [ ! -f \"$FF_TOOLCHAIN_TOUCH\" ]; then\n    $ANDROID_NDK/build/tools/make-standalone-toolchain.sh \\\n        $FF_MAKE_TOOLCHAIN_FLAGS \\\n        --platform=$FF_ANDROID_PLATFORM \\\n        --toolchain=$FF_TOOLCHAIN_NAME\n    touch $FF_TOOLCHAIN_TOUCH;\nfi\n\n\n#--------------------\necho \"\"\necho \"--------------------\"\necho \"[*] check ffmpeg env\"\necho \"--------------------\"\nexport PATH=$FF_TOOLCHAIN_PATH/bin/:$PATH\n#export CC=\"ccache ${FF_CROSS_PREFIX}-gcc\"\nexport CC=\"${FF_CROSS_PREFIX}-gcc\"\nexport LD=${FF_CROSS_PREFIX}-ld\nexport AR=${FF_CROSS_PREFIX}-ar\nexport STRIP=${FF_CROSS_PREFIX}-strip\n\nFF_CFLAGS=\"-O3 -Wall -pipe \\\n    -std=c99 \\\n    -ffast-math \\\n    -fstrict-aliasing -Werror=strict-aliasing \\\n    -Wno-psabi -Wa,--noexecstack \\\n    -DANDROID -DNDEBUG\"\n\n# cause av_strlcpy crash with gcc4.7, gcc4.8\n# -fmodulo-sched -fmodulo-sched-allow-regmoves\n\n# --enable-thumb is OK\n#FF_CFLAGS=\"$FF_CFLAGS -mthumb\"\n\n# not necessary\n#FF_CFLAGS=\"$FF_CFLAGS -finline-limit=300\"\n\nexport COMMON_FF_CFG_FLAGS=\n. $FF_BUILD_ROOT/../../config/module.sh\n\n\n#--------------------\n# with openssl\nif [ -f \"${FF_DEP_OPENSSL_LIB}/libssl.a\" ]; then\n    echo \"OpenSSL detected\"\n# FF_CFG_FLAGS=\"$FF_CFG_FLAGS --enable-nonfree\"\n    FF_CFG_FLAGS=\"$FF_CFG_FLAGS --enable-openssl\"\n\n    FF_CFLAGS=\"$FF_CFLAGS -I${FF_DEP_OPENSSL_INC}\"\n    FF_DEP_LIBS=\"$FF_DEP_LIBS -L${FF_DEP_OPENSSL_LIB} -lssl -lcrypto\"\nfi\n\nif [ -f \"${FF_DEP_LIBSOXR_LIB}/libsoxr.a\" ]; then\n    echo \"libsoxr detected\"\n    FF_CFG_FLAGS=\"$FF_CFG_FLAGS --enable-libsoxr\"\n\n    FF_CFLAGS=\"$FF_CFLAGS -I${FF_DEP_LIBSOXR_INC}\"\n    FF_DEP_LIBS=\"$FF_DEP_LIBS -L${FF_DEP_LIBSOXR_LIB} -lsoxr\"\nfi\n\nFF_CFG_FLAGS=\"$FF_CFG_FLAGS $COMMON_FF_CFG_FLAGS\"\n\n#--------------------\n# Standard options:\nFF_CFG_FLAGS=\"$FF_CFG_FLAGS --prefix=$FF_PREFIX\"\n\n# Advanced options (experts only):\nFF_CFG_FLAGS=\"$FF_CFG_FLAGS --cross-prefix=${FF_CROSS_PREFIX}-\"\nFF_CFG_FLAGS=\"$FF_CFG_FLAGS --enable-cross-compile\"\nFF_CFG_FLAGS=\"$FF_CFG_FLAGS --target-os=linux\"\nFF_CFG_FLAGS=\"$FF_CFG_FLAGS --enable-pic\"\n# FF_CFG_FLAGS=\"$FF_CFG_FLAGS --disable-symver\"\n\nif [ \"$FF_ARCH\" = \"x86\" ]; then\n    FF_CFG_FLAGS=\"$FF_CFG_FLAGS --disable-asm\"\nelse\n    # Optimization options (experts only):\n    FF_CFG_FLAGS=\"$FF_CFG_FLAGS --enable-asm\"\n    FF_CFG_FLAGS=\"$FF_CFG_FLAGS --enable-inline-asm\"\nfi\n\ncase \"$FF_BUILD_OPT\" in\n    debug)\n        FF_CFG_FLAGS=\"$FF_CFG_FLAGS --disable-optimizations\"\n        FF_CFG_FLAGS=\"$FF_CFG_FLAGS --enable-debug\"\n        FF_CFG_FLAGS=\"$FF_CFG_FLAGS --disable-small\"\n    ;;\n    *)\n        FF_CFG_FLAGS=\"$FF_CFG_FLAGS --enable-optimizations\"\n        FF_CFG_FLAGS=\"$FF_CFG_FLAGS --enable-debug\"\n        FF_CFG_FLAGS=\"$FF_CFG_FLAGS --enable-small\"\n    ;;\nesac\n\n#--------------------\necho \"\"\necho \"--------------------\"\necho \"[*] configurate ffmpeg\"\necho \"--------------------\"\ncd $FF_SOURCE\nif [ -f \"./config.h\" ]; then\n    echo 'reuse configure'\nelse\n    which $CC\n    ./configure $FF_CFG_FLAGS \\\n        --extra-cflags=\"$FF_CFLAGS $FF_EXTRA_CFLAGS\" \\\n        --extra-ldflags=\"$FF_DEP_LIBS $FF_EXTRA_LDFLAGS\"\n    make clean\nfi\n\n#--------------------\necho \"\"\necho \"--------------------\"\necho \"[*] compile ffmpeg\"\necho \"--------------------\"\ncp config.* $FF_PREFIX\nmake $FF_MAKE_FLAGS > /dev/null\nmake install\nmkdir -p $FF_PREFIX/include/libffmpeg\ncp -f config.h $FF_PREFIX/include/libffmpeg/config.h\n\n#--------------------\necho \"\"\necho \"--------------------\"\necho \"[*] link ffmpeg\"\necho \"--------------------\"\necho $FF_EXTRA_LDFLAGS\n\nFF_C_OBJ_FILES=\nFF_ASM_OBJ_FILES=\nfor MODULE_DIR in $FF_MODULE_DIRS\ndo\n    C_OBJ_FILES=\"$MODULE_DIR/*.o\"\n    if ls $C_OBJ_FILES 1> /dev/null 2>&1; then\n        echo \"link $MODULE_DIR/*.o\"\n        FF_C_OBJ_FILES=\"$FF_C_OBJ_FILES $C_OBJ_FILES\"\n    fi\n\n    for ASM_SUB_DIR in $FF_ASSEMBLER_SUB_DIRS\n    do\n        ASM_OBJ_FILES=\"$MODULE_DIR/$ASM_SUB_DIR/*.o\"\n        if ls $ASM_OBJ_FILES 1> /dev/null 2>&1; then\n            echo \"link $MODULE_DIR/$ASM_SUB_DIR/*.o\"\n            FF_ASM_OBJ_FILES=\"$FF_ASM_OBJ_FILES $ASM_OBJ_FILES\"\n        fi\n    done\ndone\n\n$CC -lm -lz -shared --sysroot=$FF_SYSROOT -Wl,--no-undefined -Wl,-z,noexecstack $FF_EXTRA_LDFLAGS \\\n    -Wl,-soname,libijkffmpeg.so \\\n    $FF_C_OBJ_FILES \\\n    $FF_ASM_OBJ_FILES \\\n    $FF_DEP_LIBS \\\n    -o $FF_PREFIX/libijkffmpeg.so\n\nmysedi() {\n    f=$1\n    exp=$2\n    n=`basename $f`\n    cp $f /tmp/$n\n    sed $exp /tmp/$n > $f\n    rm /tmp/$n\n}\n\necho \"\"\necho \"--------------------\"\necho \"[*] create files for shared ffmpeg\"\necho \"--------------------\"\nrm -rf $FF_PREFIX/shared\nmkdir -p $FF_PREFIX/shared/lib/pkgconfig\nln -s $FF_PREFIX/include $FF_PREFIX/shared/include\nln -s $FF_PREFIX/libijkffmpeg.so $FF_PREFIX/shared/lib/libijkffmpeg.so\ncp $FF_PREFIX/lib/pkgconfig/*.pc $FF_PREFIX/shared/lib/pkgconfig\nfor f in $FF_PREFIX/lib/pkgconfig/*.pc; do\n    # in case empty dir\n    if [ ! -f $f ]; then\n        continue\n    fi\n    cp $f $FF_PREFIX/shared/lib/pkgconfig\n    f=$FF_PREFIX/shared/lib/pkgconfig/`basename $f`\n    # OSX sed doesn't have in-place(-i)\n    mysedi $f 's/\\/output/\\/output\\/shared/g'\n    mysedi $f 's/-lavcodec/-lijkffmpeg/g'\n    mysedi $f 's/-lavfilter/-lijkffmpeg/g'\n    mysedi $f 's/-lavformat/-lijkffmpeg/g'\n    mysedi $f 's/-lavutil/-lijkffmpeg/g'\n    mysedi $f 's/-lswresample/-lijkffmpeg/g'\n    mysedi $f 's/-lswscale/-lijkffmpeg/g'\ndone\n"
  },
  {
    "path": "android/contrib/tools/do-compile-libsoxr.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2014 Miguel Botón <waninkoko@gmail.com>\n# Copyright (C) 2014 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n#--------------------\nset -e\n\nif [ -z \"$ANDROID_NDK\" ]; then\n    echo \"You must define ANDROID_NDK before starting.\"\n    echo \"They must point to your NDK directories.\\n\"\n    exit 1\nfi\n\n#--------------------\n# common defines\nFF_ARCH=$1\nif [ -z \"$FF_ARCH\" ]; then\n    echo \"You must specific an architecture 'arm, armv7a, x86, ...'.\\n\"\n    exit 1\nfi\n\n\nFF_BUILD_ROOT=`pwd`\n\nFF_BUILD_NAME=\nFF_SOURCE=\nFF_CROSS_PREFIX=\n\nFF_CFG_FLAGS=\nFF_PLATFORM_CFG_FLAGS=\n\nFF_EXTRA_CFLAGS=\nFF_EXTRA_LDFLAGS=\n\nFF_CMAKE_ABI=\nFF_CMAKE_EXTRA_FLAGS=\n\n#----- armv7a begin -----\nif [ \"$FF_ARCH\" = \"armv7a\" ]; then\n    FF_BUILD_NAME=libsoxr-armv7a\n    FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME\n\n    FF_CMAKE_ABI=\"armeabi-v7a with NEON\"\n    FF_CMAKE_EXTRA_FLAGS=\"-DHAVE_WORDS_BIGENDIAN_EXITCODE=1 -DWITH_SIMD=0\"\n\nelif [ \"$FF_ARCH\" = \"armv5\" ]; then\n    FF_BUILD_NAME=libsoxr-armv5\n    FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME\n\n    FF_CMAKE_ABI=\"armeabi\"\n    FF_CMAKE_EXTRA_FLAGS=\"-DHAVE_WORDS_BIGENDIAN_EXITCODE=1 -DWITH_SIMD=0\"\n\nelif [ \"$FF_ARCH\" = \"x86\" ]; then\n    FF_BUILD_NAME=libsoxr-x86\n    FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME\n\n    FF_CMAKE_ABI=\"x86\"\n    FF_CMAKE_EXTRA_FLAGS=\"-DHAVE_WORDS_BIGENDIAN_EXITCODE=1\"\n\nelif [ \"$FF_ARCH\" = \"x86_64\" ]; then\n    FF_ANDROID_PLATFORM=android-21\n\n    FF_BUILD_NAME=libsoxr-x86_64\n    FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME\n\n    FF_CMAKE_ABI=\"x86_64\"\n\nelif [ \"$FF_ARCH\" = \"arm64\" ]; then\n    FF_ANDROID_PLATFORM=android-21\n\n    FF_BUILD_NAME=libsoxr-arm64\n    FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME\n\n    FF_CMAKE_ABI=\"arm64-v8a\"\n\nelse\n    echo \"unknown architecture $FF_ARCH\";\n    exit 1\nfi\n\nFF_PREFIX=$FF_BUILD_ROOT/build/$FF_BUILD_NAME/output\nFF_CMAKE_BUILD_DIR=$FF_BUILD_ROOT/build/$FF_BUILD_NAME/build\n\nmkdir -p $FF_PREFIX\nmkdir -p $FF_CMAKE_BUILD_DIR\n\n#--------------------\necho \"\"\necho \"--------------------\"\necho \"[*] configurate libsoxr\"\necho \"--------------------\"\ncd $FF_CMAKE_BUILD_DIR\nFF_CMAKE_CFG_FLAGS=\"-DCMAKE_TOOLCHAIN_FILE=${FF_SOURCE}/android.toolchain.cmake -DANDROID_NDK=$ANDROID_NDK -DBUILD_EXAMPLES=0 -DBUILD_LSR_TESTS=0 -DBUILD_SHARED_LIBS=0 -DBUILD_TESTS=0 -DCMAKE_BUILD_TYPE=Release -DWITH_LSR_BINDINGS=0 -DWITH_OPENMP=0 -DWITH_PFFFT=0\"\necho \"cmake $FF_CMAKE_CFG_FLAGS -DANDROID_ABI=$FF_CMAKE_ABI -DCMAKE_INSTALL_PREFIX=$FF_PREFIX\"\ncmake $FF_CMAKE_CFG_FLAGS $FF_CMAKE_EXTRA_FLAGS -DANDROID_ABI=$FF_CMAKE_ABI -DCMAKE_INSTALL_PREFIX=$FF_PREFIX $FF_SOURCE\n\n\n#--------------------\necho \"\"\necho \"--------------------\"\necho \"[*] compile libsoxr\"\necho \"--------------------\"\nmake -j4\nmake install\n"
  },
  {
    "path": "android/contrib/tools/do-compile-openssl.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2014 Miguel Botón <waninkoko@gmail.com>\n# Copyright (C) 2014 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n#--------------------\nset -e\n\nif [ -z \"$ANDROID_NDK\" ]; then\n    echo \"You must define ANDROID_NDK before starting.\"\n    echo \"They must point to your NDK directories.\\n\"\n    exit 1\nfi\n\n#--------------------\n# common defines\nFF_ARCH=$1\nif [ -z \"$FF_ARCH\" ]; then\n    echo \"You must specific an architecture 'arm, armv7a, x86, ...'.\\n\"\n    exit 1\nfi\n\n\nFF_BUILD_ROOT=`pwd`\nFF_ANDROID_PLATFORM=android-9\n\n\nFF_BUILD_NAME=\nFF_SOURCE=\nFF_CROSS_PREFIX=\n\nFF_CFG_FLAGS=\nFF_PLATFORM_CFG_FLAGS=\n\nFF_EXTRA_CFLAGS=\nFF_EXTRA_LDFLAGS=\n\n\n\n#--------------------\necho \"\"\necho \"--------------------\"\necho \"[*] make NDK standalone toolchain\"\necho \"--------------------\"\n. ./tools/do-detect-env.sh\nFF_MAKE_TOOLCHAIN_FLAGS=$IJK_MAKE_TOOLCHAIN_FLAGS\nFF_MAKE_FLAGS=$IJK_MAKE_FLAG\nFF_GCC_VER=$IJK_GCC_VER\nFF_GCC_64_VER=$IJK_GCC_64_VER\n\n\n#----- armv7a begin -----\nif [ \"$FF_ARCH\" = \"armv7a\" ]; then\n    FF_BUILD_NAME=openssl-armv7a\n    FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME\n\t\n    FF_CROSS_PREFIX=arm-linux-androideabi\n\tFF_TOOLCHAIN_NAME=${FF_CROSS_PREFIX}-${FF_GCC_VER}\n\n    FF_PLATFORM_CFG_FLAGS=\"android-armv7\"\n\nelif [ \"$FF_ARCH\" = \"armv5\" ]; then\n    FF_BUILD_NAME=openssl-armv5\n    FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME\n\t\n    FF_CROSS_PREFIX=arm-linux-androideabi\n\tFF_TOOLCHAIN_NAME=${FF_CROSS_PREFIX}-${FF_GCC_VER}\n\n    FF_PLATFORM_CFG_FLAGS=\"android\"\n\nelif [ \"$FF_ARCH\" = \"x86\" ]; then\n    FF_BUILD_NAME=openssl-x86\n    FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME\n\t\n    FF_CROSS_PREFIX=i686-linux-android\n\tFF_TOOLCHAIN_NAME=x86-${FF_GCC_VER}\n\n    FF_PLATFORM_CFG_FLAGS=\"android-x86\"\n\n    FF_CFG_FLAGS=\"$FF_CFG_FLAGS no-asm\"\n\nelif [ \"$FF_ARCH\" = \"x86_64\" ]; then\n    FF_ANDROID_PLATFORM=android-21\n\n    FF_BUILD_NAME=openssl-x86_64\n    FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME\n\n    FF_CROSS_PREFIX=x86_64-linux-android\n    FF_TOOLCHAIN_NAME=${FF_CROSS_PREFIX}-${FF_GCC_64_VER}\n\n    FF_PLATFORM_CFG_FLAGS=\"linux-x86_64\"\n\nelif [ \"$FF_ARCH\" = \"arm64\" ]; then\n    FF_ANDROID_PLATFORM=android-21\n\n    FF_BUILD_NAME=openssl-arm64\n    FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME\n\n    FF_CROSS_PREFIX=aarch64-linux-android\n    FF_TOOLCHAIN_NAME=${FF_CROSS_PREFIX}-${FF_GCC_64_VER}\n\n    FF_PLATFORM_CFG_FLAGS=\"linux-aarch64\"\n\nelse\n    echo \"unknown architecture $FF_ARCH\";\n    exit 1\nfi\n\nFF_TOOLCHAIN_PATH=$FF_BUILD_ROOT/build/$FF_BUILD_NAME/toolchain\n\nFF_SYSROOT=$FF_TOOLCHAIN_PATH/sysroot\nFF_PREFIX=$FF_BUILD_ROOT/build/$FF_BUILD_NAME/output\n\nmkdir -p $FF_PREFIX\n# mkdir -p $FF_SYSROOT\n\n\n#--------------------\necho \"\"\necho \"--------------------\"\necho \"[*] make NDK standalone toolchain\"\necho \"--------------------\"\n. ./tools/do-detect-env.sh\nFF_MAKE_TOOLCHAIN_FLAGS=$IJK_MAKE_TOOLCHAIN_FLAGS\nFF_MAKE_FLAGS=$IJK_MAKE_FLAG\n\n\nFF_MAKE_TOOLCHAIN_FLAGS=\"$FF_MAKE_TOOLCHAIN_FLAGS --install-dir=$FF_TOOLCHAIN_PATH\"\nFF_TOOLCHAIN_TOUCH=\"$FF_TOOLCHAIN_PATH/touch\"\nif [ ! -f \"$FF_TOOLCHAIN_TOUCH\" ]; then\n    $ANDROID_NDK/build/tools/make-standalone-toolchain.sh \\\n        $FF_MAKE_TOOLCHAIN_FLAGS \\\n        --platform=$FF_ANDROID_PLATFORM \\\n        --toolchain=$FF_TOOLCHAIN_NAME\n    touch $FF_TOOLCHAIN_TOUCH;\nfi\n\n\n#--------------------\necho \"\"\necho \"--------------------\"\necho \"[*] check openssl env\"\necho \"--------------------\"\nexport PATH=$FF_TOOLCHAIN_PATH/bin:$PATH\n\nexport COMMON_FF_CFG_FLAGS=\n\nFF_CFG_FLAGS=\"$FF_CFG_FLAGS $COMMON_FF_CFG_FLAGS\"\n\n#--------------------\n# Standard options:\nFF_CFG_FLAGS=\"$FF_CFG_FLAGS zlib-dynamic\"\nFF_CFG_FLAGS=\"$FF_CFG_FLAGS no-shared\"\nFF_CFG_FLAGS=\"$FF_CFG_FLAGS --openssldir=$FF_PREFIX\"\nFF_CFG_FLAGS=\"$FF_CFG_FLAGS --cross-compile-prefix=${FF_CROSS_PREFIX}-\"\nFF_CFG_FLAGS=\"$FF_CFG_FLAGS $FF_PLATFORM_CFG_FLAGS\"\n\n#--------------------\necho \"\"\necho \"--------------------\"\necho \"[*] configurate openssl\"\necho \"--------------------\"\ncd $FF_SOURCE\n#if [ -f \"./Makefile\" ]; then\n#    echo 'reuse configure'\n#else\n    echo \"./Configure $FF_CFG_FLAGS\"\n    ./Configure $FF_CFG_FLAGS\n#        --extra-cflags=\"$FF_CFLAGS $FF_EXTRA_CFLAGS\" \\\n#        --extra-ldflags=\"$FF_EXTRA_LDFLAGS\"\n#fi\n\n#--------------------\necho \"\"\necho \"--------------------\"\necho \"[*] compile openssl\"\necho \"--------------------\"\nmake depend\nmake $FF_MAKE_FLAGS\nmake install_sw\n\n#--------------------\necho \"\"\necho \"--------------------\"\necho \"[*] link openssl\"\necho \"--------------------\"\n"
  },
  {
    "path": "android/contrib/tools/do-detect-env.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# This script is based on projects below\n# https://github.com/yixia/FFmpeg-Android\n# http://git.videolan.org/?p=vlc-ports/android.git;a=summary\n\n#--------------------\nset -e\n\nUNAME_S=$(uname -s)\nUNAME_SM=$(uname -sm)\necho \"build on $UNAME_SM\"\n\necho \"ANDROID_NDK=$ANDROID_NDK\"\n\nif [ -z \"$ANDROID_NDK\" ]; then\n    echo \"You must define ANDROID_NDK before starting.\"\n    echo \"They must point to your NDK directories.\"\n    echo \"\"\n    exit 1\nfi\n\n\n\n# try to detect NDK version\nexport IJK_GCC_VER=4.9\nexport IJK_GCC_64_VER=4.9\nexport IJK_MAKE_TOOLCHAIN_FLAGS=\nexport IJK_MAKE_FLAG=\nexport IJK_NDK_REL=$(grep -o '^r[0-9]*.*' $ANDROID_NDK/RELEASE.TXT 2>/dev/null | sed 's/[[:space:]]*//g' | cut -b2-)\ncase \"$IJK_NDK_REL\" in\n    10e*)\n        # we don't use 4.4.3 because it doesn't handle threads correctly.\n        if test -d ${ANDROID_NDK}/toolchains/arm-linux-androideabi-4.8\n        # if gcc 4.8 is present, it's there for all the archs (x86, mips, arm)\n        then\n            echo \"NDKr$IJK_NDK_REL detected\"\n\n            case \"$UNAME_S\" in\n                Darwin)\n                    export IJK_MAKE_TOOLCHAIN_FLAGS=\"$IJK_MAKE_TOOLCHAIN_FLAGS --system=darwin-x86_64\"\n                ;;\n                CYGWIN_NT-*)\n                    export IJK_MAKE_TOOLCHAIN_FLAGS=\"$IJK_MAKE_TOOLCHAIN_FLAGS --system=windows-x86_64\"\n                ;;\n            esac\n        else\n            echo \"You need the NDKr10e or later\"\n            exit 1\n        fi\n    ;;\n    *)\n        IJK_NDK_REL=$(grep -o '^Pkg\\.Revision.*=[0-9]*.*' $ANDROID_NDK/source.properties 2>/dev/null | sed 's/[[:space:]]*//g' | cut -d \"=\" -f 2)\n        echo \"IJK_NDK_REL=$IJK_NDK_REL\"\n        case \"$IJK_NDK_REL\" in\n            11*|12*|13*|14*)\n                if test -d ${ANDROID_NDK}/toolchains/arm-linux-androideabi-4.9\n                then\n                    echo \"NDKr$IJK_NDK_REL detected\"\n                else\n                    echo \"You need the NDKr10e or later\"\n                    exit 1\n                fi\n            ;;\n            *)\n                echo \"You need the NDKr10e or later\"\n                exit 1\n            ;;\n        esac\n    ;;\nesac\n\n\ncase \"$UNAME_S\" in\n    Darwin)\n        export IJK_MAKE_FLAG=-j`sysctl -n machdep.cpu.thread_count`\n    ;;\n    CYGWIN_NT-*)\n        IJK_WIN_TEMP=\"$(cygpath -am /tmp)\"\n        export TEMPDIR=$IJK_WIN_TEMP/\n\n        echo \"Cygwin temp prefix=$IJK_WIN_TEMP/\"\n    ;;\nesac\n"
  },
  {
    "path": "android/ijk-addr2line.sh",
    "content": "#! /bin/sh\n\naddr2line -e ijkplayer/ijkplayer-armv7a/src/main/obj/local/armeabi-v7a/lib$1.so\n"
  },
  {
    "path": "android/ijk-ndk-stack.sh",
    "content": "#!/bin/sh\n\nadb logcat | ndk-stack -sym ijkplayer/ijkplayer-armv7a/src/main/obj/local/armeabi-v7a\n"
  },
  {
    "path": "android/ijkplayer/.gitignore",
    "content": ".gradle\n/local.properties\n/.idea/workspace.xml\n/.idea/libraries\n.DS_Store\n/build\n/captures\nandroid-ndk-prof\n"
  },
  {
    "path": "android/ijkplayer/build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    repositories {\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:2.1.3'\n\n        classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1'\n        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7'\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        jcenter()\n    }\n}\n\next {\n    compileSdkVersion = 25\n    buildToolsVersion = \"25.0.3\"\n\n    targetSdkVersion = 25\n\n    versionCode = 800800\n    versionName = \"0.8.8\"\n}\n\nwrapper {\n    gradleVersion = '2.14.1'\n}\n"
  },
  {
    "path": "android/ijkplayer/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Wed Aug 24 16:26:25 CST 2016\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-2.14.1-all.zip\n"
  },
  {
    "path": "android/ijkplayer/gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\n# Default value: -Xmx10248m -XX:MaxPermSize=256m\n# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n\nVERSION_NAME=0.8.8\nVERSION_CODE=800800\nGROUP=tv.danmaku.ijk.media\n\n# http://central.sonatype.org/pages/requirements.html\nPOM_USER_ORG=bilibili\nPOM_DESCRIPTION=Video player based on FFmpeg n3.1\nPOM_URL=https://github.com/Bilibili/ijkplayer\nPOM_SCM_URL=https://github.com/Bilibili/ijkplayer\nPOM_SCM_CONNECTION=scm:git:git@github.com:Bilibili/ijkplayer.git\nPOM_SCM_DEV_CONNECTION=scm:git:git@github.com:Bilibili/ijkplayer.git\nPOM_LICENSE_NAME=LGPL-2.1\nPOM_LICENSE_URL=https://www.gnu.org/licenses/lgpl-2.1.html\nPOM_LICENSE_DIST=repo\nPOM_DEVELOPER_ID=bbcallen\nPOM_DEVELOPER_NAME=Zhang Rui\nPOM_DEVELOPER_EMAIL=bbcallen@gmail.com\n"
  },
  {
    "path": "android/ijkplayer/gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched.\nif $cygwin ; then\n    [ -n \"$JAVA_HOME\" ] && JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\nfi\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >&-\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >&-\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "android/ijkplayer/gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windowz variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\ngoto execute\r\n\r\n:4NT_args\r\n@rem Get arguments from the 4NT Shell from JP Software\r\nset CMD_LINE_ARGS=%$\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-arm64/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-arm64/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    // http://tools.android.com/tech-docs/new-build-system/tips\n    //noinspection GroovyAssignabilityCheck\n    compileSdkVersion rootProject.ext.compileSdkVersion\n    //noinspection GroovyAssignabilityCheck\n    buildToolsVersion rootProject.ext.buildToolsVersion\n\n    defaultConfig {\n        minSdkVersion 21\n        targetSdkVersion rootProject.ext.targetSdkVersion\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n    sourceSets.main {\n        jniLibs.srcDirs 'src/main/libs'\n        jni.srcDirs = [] // This prevents the auto generation of Android.mk\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n}\n\napply from: new File(rootProject.projectDir, \"tools/gradle-on-demand.gradle\");\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-arm64/gradle.properties",
    "content": "POM_NAME=ijkplayer-arm64\nPOM_ARTIFACT_ID=ijkplayer-arm64\nPOM_PACKAGING=aar"
  },
  {
    "path": "android/ijkplayer/ijkplayer-arm64/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /opt/android/ADK/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}"
  },
  {
    "path": "android/ijkplayer/ijkplayer-arm64/src/androidTest/java/tv/danmaku/ijk/media/player_arm64/ApplicationTest.java",
    "content": "package tv.danmaku.ijk.media.player_arm64;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\"http://d.android.com/tools/testing/testing_android.html\">Testing Fundamentals</a>\n */\npublic class ApplicationTest extends ApplicationTestCase<Application> {\n    public ApplicationTest() {\n        super(Application.class);\n    }\n}"
  },
  {
    "path": "android/ijkplayer/ijkplayer-arm64/src/main/.classpath",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<classpath>\n\t<classpathentry kind=\"con\" path=\"com.android.ide.eclipse.adt.ANDROID_FRAMEWORK\"/>\n\t<classpathentry exported=\"true\" kind=\"con\" path=\"com.android.ide.eclipse.adt.LIBRARIES\"/>\n\t<classpathentry exported=\"true\" kind=\"con\" path=\"com.android.ide.eclipse.adt.DEPENDENCIES\"/>\n\t<classpathentry kind=\"src\" path=\"java\"/>\n\t<classpathentry kind=\"src\" path=\"src\"/>\n\t<classpathentry kind=\"src\" path=\"gen\"/>\n\t<classpathentry kind=\"output\" path=\"bin/classes\"/>\n</classpath>\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-arm64/src/main/.project",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<projectDescription>\n\t<name>ijkplayer-arm64</name>\n\t<comment></comment>\n\t<projects>\n\t</projects>\n\t<buildSpec>\n\t\t<buildCommand>\n\t\t\t<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>org.eclipse.jdt.core.javabuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>com.android.ide.eclipse.adt.ApkBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t</buildSpec>\n\t<natures>\n\t\t<nature>com.android.ide.eclipse.adt.AndroidNature</nature>\n\t\t<nature>org.eclipse.jdt.core.javanature</nature>\n\t</natures>\n</projectDescription>\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-arm64/src/main/.settings/org.eclipse.jdt.core.prefs",
    "content": "eclipse.preferences.version=1\norg.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6\norg.eclipse.jdt.core.compiler.compliance=1.6\norg.eclipse.jdt.core.compiler.source=1.6\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-arm64/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"tv.danmaku.ijk.media.player_arm64\">\n\n    <uses-sdk\n        android:minSdkVersion=\"21\" />\n\n</manifest>\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-arm64/src/main/java/tv/danmaku/ijk/media/player_arm64/Pragma.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player_arm64;\n\npublic class Pragma {\n\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-arm64/src/main/jni/Application.mk",
    "content": "# Copyright (c) 2013-2014 Bilibili\n# copyright (c) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n#\n# This file is part of ijkPlayer.\n#\n# ijkPlayer is free software; you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation; either\n# version 2.1 of the License, or (at your option) any later version.\n#\n# ijkPlayer is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# Lesser General Public License for more details.\n#\n# You should have received a copy of the GNU Lesser General Public\n# License along with ijkPlayer; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n\nAPP_OPTIM := release\nAPP_PLATFORM := android-21\nAPP_ABI := arm64-v8a\nNDK_TOOLCHAIN_VERSION=4.9\nAPP_PIE := false\n\nAPP_STL := stlport_static\n\nAPP_CFLAGS := -O3 -Wall -pipe \\\n    -ffast-math \\\n    -fstrict-aliasing -Werror=strict-aliasing \\\n    -Wno-psabi -Wa,--noexecstack \\\n    -DANDROID -DNDEBUG\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-arm64/src/main/project.properties",
    "content": "# This file is automatically generated by Android Tools.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n#\n# This file must be checked in Version Control Systems.\n#\n# To customize properties used by the Ant build system edit\n# \"ant.properties\", and override values to adapt the script to your\n# project structure.\n#\n# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):\n#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt\n\n# Project target.\ntarget=android-22\nandroid.library=true\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-arm64/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <string name=\"ijkplayer_dummy\" tools:ignore=\"UnusedResources\"></string>\n\n</resources>"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv5/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv5/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    // http://tools.android.com/tech-docs/new-build-system/tips\n    //noinspection GroovyAssignabilityCheck\n    compileSdkVersion rootProject.ext.compileSdkVersion\n    //noinspection GroovyAssignabilityCheck\n    buildToolsVersion rootProject.ext.buildToolsVersion\n\n    defaultConfig {\n        minSdkVersion 9\n        targetSdkVersion rootProject.ext.targetSdkVersion\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n    sourceSets.main {\n        jniLibs.srcDirs 'src/main/libs'\n        jni.srcDirs = [] // This prevents the auto generation of Android.mk\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n}\n\napply from: new File(rootProject.projectDir, \"tools/gradle-on-demand.gradle\");\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv5/gradle.properties",
    "content": "POM_NAME=ijkplayer-armv5\nPOM_ARTIFACT_ID=ijkplayer-armv5\nPOM_PACKAGING=aar"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv5/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /opt/android/ADK/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv5/src/androidTest/java/tv/danmaku/ijk/media/player_armv5/ApplicationTest.java",
    "content": "package tv.danmaku.ijk.media.player_armv5;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\"http://d.android.com/tools/testing/testing_android.html\">Testing Fundamentals</a>\n */\npublic class ApplicationTest extends ApplicationTestCase<Application> {\n    public ApplicationTest() {\n        super(Application.class);\n    }\n}"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv5/src/main/.classpath",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<classpath>\n\t<classpathentry kind=\"con\" path=\"com.android.ide.eclipse.adt.ANDROID_FRAMEWORK\"/>\n\t<classpathentry exported=\"true\" kind=\"con\" path=\"com.android.ide.eclipse.adt.LIBRARIES\"/>\n\t<classpathentry exported=\"true\" kind=\"con\" path=\"com.android.ide.eclipse.adt.DEPENDENCIES\"/>\n\t<classpathentry kind=\"src\" path=\"java\"/>\n\t<classpathentry kind=\"src\" path=\"src\"/>\n\t<classpathentry kind=\"src\" path=\"gen\"/>\n\t<classpathentry kind=\"output\" path=\"bin/classes\"/>\n</classpath>\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv5/src/main/.project",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<projectDescription>\n\t<name>ijkplayer-armv5</name>\n\t<comment></comment>\n\t<projects>\n\t</projects>\n\t<buildSpec>\n\t\t<buildCommand>\n\t\t\t<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>org.eclipse.jdt.core.javabuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>com.android.ide.eclipse.adt.ApkBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t</buildSpec>\n\t<natures>\n\t\t<nature>com.android.ide.eclipse.adt.AndroidNature</nature>\n\t\t<nature>org.eclipse.jdt.core.javanature</nature>\n\t</natures>\n</projectDescription>\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv5/src/main/.settings/org.eclipse.jdt.core.prefs",
    "content": "eclipse.preferences.version=1\norg.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6\norg.eclipse.jdt.core.compiler.compliance=1.6\norg.eclipse.jdt.core.compiler.source=1.6\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv5/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"tv.danmaku.ijk.media.player_armv5\" >\n\n    <uses-sdk\n        android:minSdkVersion=\"9\" />\n\n</manifest>"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv5/src/main/java/tv/danmaku/ijk/media/player_armv5/Pragma.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player_armv5;\n\npublic class Pragma {\n\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv5/src/main/jni/Application.mk",
    "content": "# Copyright (c) 2013-2014 Bilibili\n# copyright (c) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n#\n# This file is part of ijkPlayer.\n#\n# ijkPlayer is free software; you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation; either\n# version 2.1 of the License, or (at your option) any later version.\n#\n# ijkPlayer is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# Lesser General Public License for more details.\n#\n# You should have received a copy of the GNU Lesser General Public\n# License along with ijkPlayer; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n\nAPP_OPTIM := release\nAPP_PLATFORM := android-9\nAPP_ABI := armeabi\nNDK_TOOLCHAIN_VERSION=4.9\nAPP_PIE := false\n\nAPP_STL := stlport_static\n\nAPP_CFLAGS := -O3 -Wall -pipe \\\n    -ffast-math \\\n    -fstrict-aliasing -Werror=strict-aliasing \\\n    -Wno-psabi -Wa,--noexecstack \\\n    -DANDROID -DNDEBUG\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv5/src/main/project.properties",
    "content": "# This file is automatically generated by Android Tools.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n#\n# This file must be checked in Version Control Systems.\n#\n# To customize properties used by the Ant build system edit\n# \"ant.properties\", and override values to adapt the script to your\n# project structure.\n#\n# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):\n#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt\n\n# Project target.\ntarget=android-22\nandroid.library=true\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv5/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <string name=\"ijkplayer_dummy\" tools:ignore=\"UnusedResources\"></string>\n\n</resources>"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv7a/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv7a/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    // http://tools.android.com/tech-docs/new-build-system/tips\n    //noinspection GroovyAssignabilityCheck\n    compileSdkVersion rootProject.ext.compileSdkVersion\n    //noinspection GroovyAssignabilityCheck\n    buildToolsVersion rootProject.ext.buildToolsVersion\n\n    defaultConfig {\n        minSdkVersion 9\n        targetSdkVersion rootProject.ext.targetSdkVersion\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n    sourceSets.main {\n        jniLibs.srcDirs 'src/main/libs'\n        jni.srcDirs = [] // This prevents the auto generation of Android.mk\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n}\n\napply from: new File(rootProject.projectDir, \"tools/gradle-on-demand.gradle\");\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv7a/gradle.properties",
    "content": "POM_NAME=ijkplayer-armv7a\nPOM_ARTIFACT_ID=ijkplayer-armv7a\nPOM_PACKAGING=aar"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv7a/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /opt/android/ADK/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv7a/src/androidTest/java/tv/danmaku/ijk/media/player_armv7a/ApplicationTest.java",
    "content": "package tv.danmaku.ijk.media.player_armv7a;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\"http://d.android.com/tools/testing/testing_android.html\">Testing Fundamentals</a>\n */\npublic class ApplicationTest extends ApplicationTestCase<Application> {\n    public ApplicationTest() {\n        super(Application.class);\n    }\n}"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv7a/src/main/.classpath",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<classpath>\n\t<classpathentry kind=\"con\" path=\"com.android.ide.eclipse.adt.ANDROID_FRAMEWORK\"/>\n\t<classpathentry exported=\"true\" kind=\"con\" path=\"com.android.ide.eclipse.adt.LIBRARIES\"/>\n\t<classpathentry exported=\"true\" kind=\"con\" path=\"com.android.ide.eclipse.adt.DEPENDENCIES\"/>\n\t<classpathentry kind=\"src\" path=\"java\"/>\n\t<classpathentry kind=\"src\" path=\"src\"/>\n\t<classpathentry kind=\"src\" path=\"gen\"/>\n\t<classpathentry kind=\"output\" path=\"bin/classes\"/>\n</classpath>\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv7a/src/main/.project",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<projectDescription>\n\t<name>ijkplayer-armv7a</name>\n\t<comment></comment>\n\t<projects>\n\t</projects>\n\t<buildSpec>\n\t\t<buildCommand>\n\t\t\t<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>org.eclipse.jdt.core.javabuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>com.android.ide.eclipse.adt.ApkBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t</buildSpec>\n\t<natures>\n\t\t<nature>com.android.ide.eclipse.adt.AndroidNature</nature>\n\t\t<nature>org.eclipse.jdt.core.javanature</nature>\n\t</natures>\n</projectDescription>\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv7a/src/main/.settings/org.eclipse.jdt.core.prefs",
    "content": "eclipse.preferences.version=1\norg.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6\norg.eclipse.jdt.core.compiler.compliance=1.6\norg.eclipse.jdt.core.compiler.source=1.6\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv7a/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"tv.danmaku.ijk.media.player_armv7a\" >\n\n    <uses-sdk\n        android:minSdkVersion=\"9\" />\n\n</manifest>"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv7a/src/main/java/tv/danmaku/ijk/media/player_armv7a/Pragma.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player_armv7a;\n\npublic class Pragma {\n\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv7a/src/main/jni/Android.mk",
    "content": "# Copyright (c) 2013 Bilibili\n# copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n#\n# This file is part of ijkPlayer.\n#\n# ijkPlayer is free software; you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation; either\n# version 2.1 of the License, or (at your option) any later version.\n#\n# ijkPlayer is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# Lesser General Public License for more details.\n#\n# You should have received a copy of the GNU Lesser General Public\n# License along with ijkPlayer; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n\nLOCAL_PATH := $(call my-dir)\n\nMY_APP_JNI_ROOT := $(realpath $(LOCAL_PATH))\nMY_APP_PRJ_ROOT := $(realpath $(MY_APP_JNI_ROOT)/..)\nMY_APP_ANDROID_ROOT := $(realpath $(MY_APP_PRJ_ROOT)/../../../..)\n\nifeq ($(TARGET_ARCH_ABI),armeabi-v7a)\nMY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-armv7a/output)\nMY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include)\nendif\nifeq ($(TARGET_ARCH_ABI),armeabi)\nMY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-armv5/output)\nMY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include)\nendif\nifeq ($(TARGET_ARCH_ABI),arm64-v8a)\nMY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-arm64/output)\nMY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include)\nendif\nifeq ($(TARGET_ARCH_ABI),x86)\nMY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-x86/output)\nMY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include)\nendif\nifeq ($(TARGET_ARCH_ABI),x86_64)\nMY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-x86_64/output)\nMY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include)\nendif\n\ninclude $(call all-subdir-makefiles)\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv7a/src/main/jni/Application.mk",
    "content": "# Copyright (c) 2013 Bilibili\n# copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n#\n# This file is part of ijkPlayer.\n#\n# ijkPlayer is free software; you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation; either\n# version 2.1 of the License, or (at your option) any later version.\n#\n# ijkPlayer is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# Lesser General Public License for more details.\n#\n# You should have received a copy of the GNU Lesser General Public\n# License along with ijkPlayer; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n\nAPP_OPTIM := release\nAPP_PLATFORM := android-9\nAPP_ABI := armeabi-v7a\nNDK_TOOLCHAIN_VERSION=4.9\nAPP_PIE := false\n\nAPP_STL := stlport_static\n\nAPP_CFLAGS := -O3 -Wall -pipe \\\n    -ffast-math \\\n    -fstrict-aliasing -Werror=strict-aliasing \\\n    -Wno-psabi -Wa,--noexecstack \\\n    -DANDROID -DNDEBUG\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv7a/src/main/jni/ffmpeg/Android.mk",
    "content": "LOCAL_PATH := $(call my-dir)\n\ninclude $(CLEAR_VARS)\nLOCAL_MODULE := ijkffmpeg\nLOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/libijkffmpeg.so\ninclude $(PREBUILT_SHARED_LIBRARY)"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv7a/src/main/project.properties",
    "content": "# This file is automatically generated by Android Tools.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n#\n# This file must be checked in Version Control Systems.\n#\n# To customize properties used by the Ant build system edit\n# \"ant.properties\", and override values to adapt the script to your\n# project structure.\n#\n# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):\n#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt\n\n# Project target.\ntarget=android-22\nandroid.library=true\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-armv7a/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <string name=\"ijkplayer_dummy\" tools:ignore=\"UnusedResources\"></string>\n\n</resources>"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    // http://tools.android.com/tech-docs/new-build-system/tips\n    //noinspection GroovyAssignabilityCheck\n    compileSdkVersion rootProject.ext.compileSdkVersion\n    //noinspection GroovyAssignabilityCheck\n    buildToolsVersion rootProject.ext.buildToolsVersion\n\n    lintOptions {\n        abortOnError false\n    }\n    defaultConfig {\n        applicationId \"tv.danmaku.ijk.media.example\"\n        minSdkVersion 9\n        targetSdkVersion rootProject.ext.targetSdkVersion\n        versionCode rootProject.ext.versionCode\n        versionName rootProject.ext.versionName\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n    productFlavors {\n        all32 { minSdkVersion 9 }\n        all64 { minSdkVersion 21 }\n        // armv5 {}\n        // armv7a {}\n        // arm64 { minSdkVersion 21 }\n        // x86 {}\n    }\n}\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    compile 'com.android.support:appcompat-v7:23.0.1'\n    compile 'com.android.support:preference-v7:23.0.1'\n    compile 'com.android.support:support-annotations:23.0.1'\n\n    compile 'com.squareup:otto:1.3.8'\n\n    compile project(':ijkplayer-java')\n    compile project(':ijkplayer-exo')\n\n    all32Compile project(':ijkplayer-armv5')\n    all32Compile project(':ijkplayer-armv7a')\n    all32Compile project(':ijkplayer-x86')\n\n    all64Compile project(':ijkplayer-armv5')\n    all64Compile project(':ijkplayer-armv7a')\n    all64Compile project(':ijkplayer-arm64')\n    all64Compile project(':ijkplayer-x86')\n    all64Compile project(':ijkplayer-x86_64')\n\n    // compile 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'\n    // compile 'tv.danmaku.ijk.media:ijkplayer-exo:0.8.8'\n\n    // all32Compile 'tv.danmaku.ijk.media:ijkplayer-armv5:0.8.8'\n    // all32Compile 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.8'\n    // all32Compile 'tv.danmaku.ijk.media:ijkplayer-x86:0.8.8'\n\n    // all64Compile 'tv.danmaku.ijk.media:ijkplayer-armv5:0.8.8'\n    // all64Compile 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.8'\n    // all64Compile 'tv.danmaku.ijk.media:ijkplayer-arm64:0.8.8'\n    // all64Compile 'tv.danmaku.ijk.media:ijkplayer-x86:0.8.8'\n    // all64Compile 'tv.danmaku.ijk.media:ijkplayer-x86_64:0.8.8'\n\n    // armv5Compile project(':player-armv5')\n    // armv7aCompile project(':player-armv7a')\n    // arm64Compile project(':player-arm64')\n    // x86Compile project(':player-x86')\n    // x86_64Compile project(':player-x86_64')\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /opt/android/ADK/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/androidTest/java/tv/danmaku/ijk/media/example/ApplicationTest.java",
    "content": "package tv.danmaku.ijk.media.example;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\"http://d.android.com/tools/testing/testing_android.html\">Testing Fundamentals</a>\n */\npublic class ApplicationTest extends ApplicationTestCase<Application> {\n    public ApplicationTest() {\n        super(Application.class);\n    }\n}"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/.classpath",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<classpath>\n\t<classpathentry kind=\"src\" path=\"java\"/>\n\t<classpathentry kind=\"con\" path=\"com.android.ide.eclipse.adt.ANDROID_FRAMEWORK\"/>\n\t<classpathentry exported=\"true\" kind=\"con\" path=\"com.android.ide.eclipse.adt.LIBRARIES\"/>\n\t<classpathentry exported=\"true\" kind=\"con\" path=\"com.android.ide.eclipse.adt.DEPENDENCIES\"/>\n\t<classpathentry combineaccessrules=\"false\" exported=\"true\" kind=\"src\" path=\"/android-support-v7-appcompat\"/>\n\t<classpathentry combineaccessrules=\"false\" exported=\"true\" kind=\"src\" path=\"/ijkplayer-arm64\"/>\n\t<classpathentry combineaccessrules=\"false\" exported=\"true\" kind=\"src\" path=\"/ijkplayer-armv5\"/>\n\t<classpathentry combineaccessrules=\"false\" exported=\"true\" kind=\"src\" path=\"/ijkplayer-armv7a\"/>\n\t<classpathentry combineaccessrules=\"false\" exported=\"true\" kind=\"src\" path=\"/ijkplayer-java\"/>\n\t<classpathentry combineaccessrules=\"false\" exported=\"true\" kind=\"src\" path=\"/ijkplayer-x86\"/>\n\t<classpathentry kind=\"src\" path=\"src\"/>\n\t<classpathentry kind=\"src\" path=\"gen\"/>\n\t<classpathentry kind=\"output\" path=\"bin/classes\"/>\n</classpath>\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/.project",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<projectDescription>\n\t<name>ijkplayer-sample</name>\n\t<comment></comment>\n\t<projects>\n\t</projects>\n\t<buildSpec>\n\t\t<buildCommand>\n\t\t\t<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>org.eclipse.jdt.core.javabuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>com.android.ide.eclipse.adt.ApkBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t</buildSpec>\n\t<natures>\n\t\t<nature>com.android.ide.eclipse.adt.AndroidNature</nature>\n\t\t<nature>org.eclipse.jdt.core.javanature</nature>\n\t</natures>\n</projectDescription>\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/.settings/org.eclipse.jdt.core.prefs",
    "content": "eclipse.preferences.version=1\norg.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6\norg.eclipse.jdt.core.compiler.compliance=1.6\norg.eclipse.jdt.core.compiler.source=1.6\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"tv.danmaku.ijk.media.example\">\n\n    <uses-sdk\n        android:minSdkVersion=\"9\"\n        android:targetSdkVersion=\"22\" />\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"android.permission.WAKE_LOCK\" />\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n\n    <!-- for umeng -->\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:theme=\"@style/AppTheme\">\n        <activity\n            android:name=\"tv.danmaku.ijk.media.example.activities.FileExplorerActivity\"\n            android:configChanges=\"orientation|keyboardHidden|screenSize\"\n            android:label=\"@string/app_name\"\n            android:screenOrientation=\"user\"\n            android:theme=\"@style/AppTheme\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n        <activity\n            android:name=\"tv.danmaku.ijk.media.example.activities.SampleMediaActivity\"\n            android:configChanges=\"orientation|keyboardHidden|screenSize\"\n            android:label=\"@string/app_name\"\n            android:screenOrientation=\"user\"\n            android:theme=\"@style/AppTheme\">\n        </activity>\n        <activity\n            android:name=\"tv.danmaku.ijk.media.example.activities.RecentMediaActivity\"\n            android:configChanges=\"orientation|keyboardHidden|screenSize\"\n            android:label=\"@string/app_name\"\n            android:screenOrientation=\"user\"\n            android:theme=\"@style/AppTheme\">\n        </activity>\n        <activity\n            android:name=\"tv.danmaku.ijk.media.example.activities.SettingsActivity\"\n            android:configChanges=\"orientation|keyboardHidden|screenSize\"\n            android:label=\"@string/app_name\"\n            android:screenOrientation=\"user\"\n            android:theme=\"@style/AppTheme\" />\n        <activity\n            android:name=\"tv.danmaku.ijk.media.example.activities.VideoActivity\"\n            android:configChanges=\"orientation|keyboardHidden|screenSize\"\n            android:label=\"@string/app_name\"\n            android:screenOrientation=\"user\"\n            android:theme=\"@style/FullscreenTheme\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n\n                <data android:mimeType=\"video/*\" />\n                <data android:mimeType=\"audio/*\" />\n                <data android:scheme=\"http\" />\n                <data android:scheme=\"file\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.SEND\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n\n                <data android:mimeType=\"video/*\" />\n            </intent-filter>\n        </activity>\n\n        <service\n            android:name=\"tv.danmaku.ijk.media.example.services.MediaPlayerService\"\n            android:enabled=\"false\"\n            android:exported=\"false\"\n            android:icon=\"@mipmap/ic_launcher\"\n            android:label=\"@string/app_name\" >\n        </service>\n    </application>\n\n</manifest>"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/activities/FileExplorerActivity.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.activities;\n\nimport android.os.Bundle;\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.FragmentTransaction;\nimport android.text.TextUtils;\n\nimport com.squareup.otto.Subscribe;\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport tv.danmaku.ijk.media.example.R;\nimport tv.danmaku.ijk.media.example.application.AppActivity;\nimport tv.danmaku.ijk.media.example.application.Settings;\nimport tv.danmaku.ijk.media.example.eventbus.FileExplorerEvents;\nimport tv.danmaku.ijk.media.example.fragments.FileListFragment;\n\npublic class FileExplorerActivity extends AppActivity {\n    private Settings mSettings;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        if (mSettings == null) {\n            mSettings = new Settings(this);\n        }\n\n        String lastDirectory = mSettings.getLastDirectory();\n        if (!TextUtils.isEmpty(lastDirectory) && new File(lastDirectory).isDirectory())\n            doOpenDirectory(lastDirectory, false);\n        else\n            doOpenDirectory(\"/\", false);\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n\n        FileExplorerEvents.getBus().register(this);\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n\n        FileExplorerEvents.getBus().unregister(this);\n    }\n\n    private void doOpenDirectory(String path, boolean addToBackStack) {\n        Fragment newFragment = FileListFragment.newInstance(path);\n        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\n\n        transaction.replace(R.id.body, newFragment);\n\n        if (addToBackStack)\n            transaction.addToBackStack(null);\n        transaction.commit();\n    }\n\n    @Subscribe\n    public void onClickFile(FileExplorerEvents.OnClickFile event) {\n        File f = event.mFile;\n        try {\n            f = f.getAbsoluteFile();\n            f = f.getCanonicalFile();\n            if (TextUtils.isEmpty(f.toString()))\n                f = new File(\"/\");\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n\n        if (f.isDirectory()) {\n            String path = f.toString();\n            mSettings.setLastDirectory(path);\n            doOpenDirectory(path, true);\n        } else if (f.exists()) {\n            VideoActivity.intentTo(this, f.getPath(), f.getName());\n        }\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/activities/RecentMediaActivity.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.activities;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.FragmentTransaction;\nimport android.view.Menu;\nimport android.view.MenuItem;\n\nimport tv.danmaku.ijk.media.example.R;\nimport tv.danmaku.ijk.media.example.application.AppActivity;\nimport tv.danmaku.ijk.media.example.fragments.RecentMediaListFragment;\n\npublic class RecentMediaActivity extends AppActivity {\n    public static Intent newIntent(Context context) {\n        Intent intent = new Intent(context, RecentMediaActivity.class);\n        return intent;\n    }\n\n    public static void intentTo(Context context) {\n        context.startActivity(newIntent(context));\n    }\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        Fragment newFragment = RecentMediaListFragment.newInstance();\n        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\n\n        transaction.replace(R.id.body, newFragment);\n        transaction.commit();\n    }\n\n    @Override\n    public boolean onPrepareOptionsMenu(Menu menu) {\n        boolean show = super.onPrepareOptionsMenu(menu);\n        if (!show)\n            return show;\n\n        MenuItem item = menu.findItem(R.id.action_recent);\n        if (item != null)\n            item.setVisible(false);\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/activities/SampleMediaActivity.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.activities;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.FragmentTransaction;\nimport android.view.Menu;\nimport android.view.MenuItem;\n\nimport tv.danmaku.ijk.media.example.R;\nimport tv.danmaku.ijk.media.example.application.AppActivity;\nimport tv.danmaku.ijk.media.example.fragments.SampleMediaListFragment;\n\npublic class SampleMediaActivity extends AppActivity  {\n    public static Intent newIntent(Context context) {\n        Intent intent = new Intent(context, SampleMediaActivity.class);\n        return intent;\n    }\n\n    public static void intentTo(Context context) {\n        context.startActivity(newIntent(context));\n    }\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        Fragment newFragment = SampleMediaListFragment.newInstance();\n        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\n\n        transaction.replace(R.id.body, newFragment);\n        transaction.commit();\n    }\n\n    @Override\n    public boolean onPrepareOptionsMenu(Menu menu) {\n        boolean show = super.onPrepareOptionsMenu(menu);\n        if (!show)\n            return show;\n\n        MenuItem item = menu.findItem(R.id.action_recent);\n        if (item != null)\n            item.setVisible(false);\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/activities/SettingsActivity.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.activities;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.FragmentTransaction;\nimport android.support.v7.app.AppCompatActivity;\nimport android.support.v7.widget.Toolbar;\n\nimport tv.danmaku.ijk.media.example.R;\nimport tv.danmaku.ijk.media.example.fragments.SettingsFragment;\n\npublic class SettingsActivity extends AppCompatActivity {\n    public static Intent newIntent(Context context) {\n        Intent intent = new Intent(context, SettingsActivity.class);\n        return intent;\n    }\n\n    public static void intentTo(Context context) {\n        context.startActivity(newIntent(context));\n    }\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_app);\n\n        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);\n        setSupportActionBar(toolbar);\n\n        Fragment newFragment = SettingsFragment.newInstance();\n        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\n        transaction.replace(R.id.body, newFragment);\n        transaction.commit();\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/activities/VideoActivity.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.activities;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.graphics.Color;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.FragmentTransaction;\nimport android.support.v4.widget.DrawerLayout;\nimport android.support.v7.app.ActionBar;\nimport android.support.v7.app.AppCompatActivity;\nimport android.support.v7.widget.Toolbar;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.ViewGroup;\nimport android.widget.TableLayout;\nimport android.widget.TextView;\n\nimport tv.danmaku.ijk.media.player.IjkMediaPlayer;\nimport tv.danmaku.ijk.media.player.misc.ITrackInfo;\nimport tv.danmaku.ijk.media.example.R;\nimport tv.danmaku.ijk.media.example.application.Settings;\nimport tv.danmaku.ijk.media.example.content.RecentMediaStorage;\nimport tv.danmaku.ijk.media.example.fragments.TracksFragment;\nimport tv.danmaku.ijk.media.example.widget.media.AndroidMediaController;\nimport tv.danmaku.ijk.media.example.widget.media.IjkVideoView;\nimport tv.danmaku.ijk.media.example.widget.media.MeasureHelper;\n\npublic class VideoActivity extends AppCompatActivity implements TracksFragment.ITrackHolder {\n    private static final String TAG = \"VideoActivity\";\n\n    private String mVideoPath;\n    private Uri    mVideoUri;\n\n    private AndroidMediaController mMediaController;\n    private IjkVideoView mVideoView;\n    private TextView mToastTextView;\n    private TableLayout mHudView;\n    private DrawerLayout mDrawerLayout;\n    private ViewGroup mRightDrawer;\n\n    private Settings mSettings;\n    private boolean mBackPressed;\n\n    public static Intent newIntent(Context context, String videoPath, String videoTitle) {\n        Intent intent = new Intent(context, VideoActivity.class);\n        intent.putExtra(\"videoPath\", videoPath);\n        intent.putExtra(\"videoTitle\", videoTitle);\n        return intent;\n    }\n\n    public static void intentTo(Context context, String videoPath, String videoTitle) {\n        context.startActivity(newIntent(context, videoPath, videoTitle));\n    }\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_player);\n\n        mSettings = new Settings(this);\n\n        // handle arguments\n        mVideoPath = getIntent().getStringExtra(\"videoPath\");\n\n        Intent intent = getIntent();\n        String intentAction = intent.getAction();\n        if (!TextUtils.isEmpty(intentAction)) {\n            if (intentAction.equals(Intent.ACTION_VIEW)) {\n                mVideoPath = intent.getDataString();\n            } else if (intentAction.equals(Intent.ACTION_SEND)) {\n                mVideoUri = intent.getParcelableExtra(Intent.EXTRA_STREAM);\n                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {\n                    String scheme = mVideoUri.getScheme();\n                    if (TextUtils.isEmpty(scheme)) {\n                        Log.e(TAG, \"Null unknown scheme\\n\");\n                        finish();\n                        return;\n                    }\n                    if (scheme.equals(ContentResolver.SCHEME_ANDROID_RESOURCE)) {\n                        mVideoPath = mVideoUri.getPath();\n                    } else if (scheme.equals(ContentResolver.SCHEME_CONTENT)) {\n                        Log.e(TAG, \"Can not resolve content below Android-ICS\\n\");\n                        finish();\n                        return;\n                    } else {\n                        Log.e(TAG, \"Unknown scheme \" + scheme + \"\\n\");\n                        finish();\n                        return;\n                    }\n                }\n            }\n        }\n\n        if (!TextUtils.isEmpty(mVideoPath)) {\n            new RecentMediaStorage(this).saveUrlAsync(mVideoPath);\n        }\n\n        // init UI\n        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);\n        setSupportActionBar(toolbar);\n\n        ActionBar actionBar = getSupportActionBar();\n        mMediaController = new AndroidMediaController(this, false);\n        mMediaController.setSupportActionBar(actionBar);\n\n        mToastTextView = (TextView) findViewById(R.id.toast_text_view);\n        mHudView = (TableLayout) findViewById(R.id.hud_view);\n        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);\n        mRightDrawer = (ViewGroup) findViewById(R.id.right_drawer);\n\n        mDrawerLayout.setScrimColor(Color.TRANSPARENT);\n\n        // init player\n        IjkMediaPlayer.loadLibrariesOnce(null);\n        IjkMediaPlayer.native_profileBegin(\"libijkplayer.so\");\n\n        mVideoView = (IjkVideoView) findViewById(R.id.video_view);\n        mVideoView.setMediaController(mMediaController);\n        mVideoView.setHudView(mHudView);\n        // prefer mVideoPath\n        if (mVideoPath != null)\n            mVideoView.setVideoPath(mVideoPath);\n        else if (mVideoUri != null)\n            mVideoView.setVideoURI(mVideoUri);\n        else {\n            Log.e(TAG, \"Null Data Source\\n\");\n            finish();\n            return;\n        }\n        mVideoView.start();\n    }\n\n    @Override\n    public void onBackPressed() {\n        mBackPressed = true;\n\n        super.onBackPressed();\n    }\n\n    @Override\n    protected void onStop() {\n        super.onStop();\n\n        if (mBackPressed || !mVideoView.isBackgroundPlayEnabled()) {\n            mVideoView.stopPlayback();\n            mVideoView.release(true);\n            mVideoView.stopBackgroundPlay();\n        } else {\n            mVideoView.enterBackground();\n        }\n        IjkMediaPlayer.native_profileEnd();\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.menu_player, menu);\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        int id = item.getItemId();\n        if (id == R.id.action_toggle_ratio) {\n            int aspectRatio = mVideoView.toggleAspectRatio();\n            String aspectRatioText = MeasureHelper.getAspectRatioText(this, aspectRatio);\n            mToastTextView.setText(aspectRatioText);\n            mMediaController.showOnce(mToastTextView);\n            return true;\n        } else if (id == R.id.action_toggle_player) {\n            int player = mVideoView.togglePlayer();\n            String playerText = IjkVideoView.getPlayerText(this, player);\n            mToastTextView.setText(playerText);\n            mMediaController.showOnce(mToastTextView);\n            return true;\n        } else if (id == R.id.action_toggle_render) {\n            int render = mVideoView.toggleRender();\n            String renderText = IjkVideoView.getRenderText(this, render);\n            mToastTextView.setText(renderText);\n            mMediaController.showOnce(mToastTextView);\n            return true;\n        } else if (id == R.id.action_show_info) {\n            mVideoView.showMediaInfo();\n        } else if (id == R.id.action_show_tracks) {\n            if (mDrawerLayout.isDrawerOpen(mRightDrawer)) {\n                Fragment f = getSupportFragmentManager().findFragmentById(R.id.right_drawer);\n                if (f != null) {\n                    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\n                    transaction.remove(f);\n                    transaction.commit();\n                }\n                mDrawerLayout.closeDrawer(mRightDrawer);\n            } else {\n                Fragment f = TracksFragment.newInstance();\n                FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\n                transaction.replace(R.id.right_drawer, f);\n                transaction.commit();\n                mDrawerLayout.openDrawer(mRightDrawer);\n            }\n        }\n\n        return super.onOptionsItemSelected(item);\n    }\n\n    @Override\n    public ITrackInfo[] getTrackInfo() {\n        if (mVideoView == null)\n            return null;\n\n        return mVideoView.getTrackInfo();\n    }\n\n    @Override\n    public void selectTrack(int stream) {\n        mVideoView.selectTrack(stream);\n    }\n\n    @Override\n    public void deselectTrack(int stream) {\n        mVideoView.deselectTrack(stream);\n    }\n\n    @Override\n    public int getSelectedTrack(int trackType) {\n        if (mVideoView == null)\n            return -1;\n\n        return mVideoView.getSelectedTrack(trackType);\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/application/AppActivity.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.application;\n\nimport android.Manifest;\nimport android.annotation.SuppressLint;\nimport android.content.pm.PackageManager;\nimport android.os.Bundle;\nimport android.support.v4.app.ActivityCompat;\nimport android.support.v4.content.ContextCompat;\nimport android.support.v7.app.AppCompatActivity;\nimport android.support.v7.widget.Toolbar;\nimport android.view.Menu;\nimport android.view.MenuItem;\n\nimport tv.danmaku.ijk.media.example.R;\nimport tv.danmaku.ijk.media.example.activities.RecentMediaActivity;\nimport tv.danmaku.ijk.media.example.activities.SampleMediaActivity;\nimport tv.danmaku.ijk.media.example.activities.SettingsActivity;\n\n@SuppressLint(\"Registered\")\npublic class AppActivity extends AppCompatActivity {\n    private static final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 1;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_app);\n\n        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);\n        setSupportActionBar(toolbar);\n\n        if (ContextCompat.checkSelfPermission(this,\n                Manifest.permission.READ_EXTERNAL_STORAGE)\n                != PackageManager.PERMISSION_GRANTED) {\n            if (ActivityCompat.shouldShowRequestPermissionRationale(this,\n                    Manifest.permission.READ_EXTERNAL_STORAGE)) {\n                // TODO: show explanation\n            } else {\n                ActivityCompat.requestPermissions(this,\n                        new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},\n                        MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);\n            }\n        }\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {\n        switch (requestCode) {\n            case MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE: {\n                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {\n                    // permission was granted, yay! Do the task you need to do.\n                } else {\n                    // permission denied, boo! Disable the functionality that depends on this permission.\n                }\n            }\n        }\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.menu_app, menu);\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        int id = item.getItemId();\n        if (id == R.id.action_settings) {\n            SettingsActivity.intentTo(this);\n            return true;\n        } else if (id == R.id.action_recent) {\n            RecentMediaActivity.intentTo(this);\n        } else if (id == R.id.action_sample) {\n            SampleMediaActivity.intentTo(this);\n        }\n\n        return super.onOptionsItemSelected(item);\n    }\n\n    @Override\n    public boolean onPrepareOptionsMenu(Menu menu) {\n        boolean show = super.onPrepareOptionsMenu(menu);\n        if (!show)\n            return show;\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/application/Settings.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.application;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.preference.PreferenceManager;\n\nimport tv.danmaku.ijk.media.example.R;\n\npublic class Settings {\n    private Context mAppContext;\n    private SharedPreferences mSharedPreferences;\n\n    public static final int PV_PLAYER__Auto = 0;\n    public static final int PV_PLAYER__AndroidMediaPlayer = 1;\n    public static final int PV_PLAYER__IjkMediaPlayer = 2;\n    public static final int PV_PLAYER__IjkExoMediaPlayer = 3;\n\n    public Settings(Context context) {\n        mAppContext = context.getApplicationContext();\n        mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(mAppContext);\n    }\n\n    public boolean getEnableBackgroundPlay() {\n        String key = mAppContext.getString(R.string.pref_key_enable_background_play);\n        return mSharedPreferences.getBoolean(key, false);\n    }\n\n    public int getPlayer() {\n        String key = mAppContext.getString(R.string.pref_key_player);\n        String value = mSharedPreferences.getString(key, \"\");\n        try {\n            return Integer.valueOf(value).intValue();\n        } catch (NumberFormatException e) {\n            return 0;\n        }\n    }\n\n    public boolean getUsingMediaCodec() {\n        String key = mAppContext.getString(R.string.pref_key_using_media_codec);\n        return mSharedPreferences.getBoolean(key, false);\n    }\n\n    public boolean getUsingMediaCodecAutoRotate() {\n        String key = mAppContext.getString(R.string.pref_key_using_media_codec_auto_rotate);\n        return mSharedPreferences.getBoolean(key, false);\n    }\n\n    public boolean getMediaCodecHandleResolutionChange() {\n        String key = mAppContext.getString(R.string.pref_key_media_codec_handle_resolution_change);\n        return mSharedPreferences.getBoolean(key, false);\n    }\n\n    public boolean getUsingOpenSLES() {\n        String key = mAppContext.getString(R.string.pref_key_using_opensl_es);\n        return mSharedPreferences.getBoolean(key, false);\n    }\n\n    public String getPixelFormat() {\n        String key = mAppContext.getString(R.string.pref_key_pixel_format);\n        return mSharedPreferences.getString(key, \"\");\n    }\n\n    public boolean getEnableNoView() {\n        String key = mAppContext.getString(R.string.pref_key_enable_no_view);\n        return mSharedPreferences.getBoolean(key, false);\n    }\n\n    public boolean getEnableSurfaceView() {\n        String key = mAppContext.getString(R.string.pref_key_enable_surface_view);\n        return mSharedPreferences.getBoolean(key, false);\n    }\n\n    public boolean getEnableTextureView() {\n        String key = mAppContext.getString(R.string.pref_key_enable_texture_view);\n        return mSharedPreferences.getBoolean(key, false);\n    }\n\n    public boolean getEnableDetachedSurfaceTextureView() {\n        String key = mAppContext.getString(R.string.pref_key_enable_detached_surface_texture);\n        return mSharedPreferences.getBoolean(key, false);\n    }\n\n    public boolean getUsingMediaDataSource() {\n        String key = mAppContext.getString(R.string.pref_key_using_mediadatasource);\n        return mSharedPreferences.getBoolean(key, false);\n    }\n\n    public String getLastDirectory() {\n        String key = mAppContext.getString(R.string.pref_key_last_directory);\n        return mSharedPreferences.getString(key, \"/\");\n    }\n\n    public void setLastDirectory(String path) {\n        String key = mAppContext.getString(R.string.pref_key_last_directory);\n        mSharedPreferences.edit().putString(key, path).apply();\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/content/PathCursor.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.content;\n\nimport android.database.AbstractCursor;\nimport android.provider.BaseColumns;\nimport android.text.TextUtils;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.TreeSet;\n\npublic class PathCursor extends AbstractCursor {\n    private List<FileItem> mFileList = new ArrayList<>();\n\n    public static final String CN_ID = BaseColumns._ID;\n    public static final String CN_FILE_NAME = \"file_name\";\n    public static final String CN_FILE_PATH = \"file_path\";\n    public static final String CN_IS_DIRECTORY = \"is_directory\";\n    public static final String CN_IS_VIDEO = \"is_video\";\n    public static final String[] columnNames = new String[]{CN_ID, CN_FILE_NAME, CN_FILE_PATH, CN_IS_DIRECTORY, CN_IS_VIDEO};\n    public static final int CI_ID = 0;\n    public static final int CI_FILE_NAME = 1;\n    public static final int CI_FILE_PATH = 2;\n    public static final int CI_IS_DIRECTORY = 3;\n    public static final int CI_IS_VIDEO = 4;\n\n    PathCursor(File parentDirectory, File[] fileList) {\n        if (parentDirectory.getParent() != null) {\n            FileItem parentFile = new FileItem(new File(parentDirectory, \"..\"));\n            parentFile.isDirectory = true;\n            mFileList.add(parentFile);\n        }\n\n        if (fileList != null) {\n            for (File file : fileList) {\n                mFileList.add(new FileItem(file));\n            }\n            Collections.sort(this.mFileList, sComparator);\n        }\n    }\n\n    @Override\n    public int getCount() {\n        return mFileList.size();\n    }\n\n    @Override\n    public String[] getColumnNames() {\n        return columnNames;\n    }\n\n    @Override\n    public String getString(int column) {\n        switch (column) {\n            case CI_FILE_NAME:\n                return mFileList.get(getPosition()).file.getName();\n            case CI_FILE_PATH:\n                return mFileList.get(getPosition()).file.toString();\n        }\n        return null;\n    }\n\n    @Override\n    public short getShort(int column) {\n        return (short) getLong(column);\n    }\n\n    @Override\n    public int getInt(int column) {\n        return (int) getLong(column);\n    }\n\n    @Override\n    public long getLong(int column) {\n        switch (column) {\n            case CI_ID:\n                return getPosition();\n            case CI_IS_DIRECTORY:\n                return mFileList.get(getPosition()).isDirectory ? 1 : 0;\n            case CI_IS_VIDEO:\n                return mFileList.get(getPosition()).isVideo ? 1 : 0;\n        }\n        return 0;\n    }\n\n    @Override\n    public float getFloat(int column) {\n        return 0;\n    }\n\n    @Override\n    public double getDouble(int column) {\n        return 0;\n    }\n\n    @Override\n    public boolean isNull(int column) {\n        return mFileList == null;\n    }\n\n    public static Comparator<FileItem> sComparator = new Comparator<FileItem>() {\n        @Override\n        public int compare(FileItem lhs, FileItem rhs) {\n            if (lhs.isDirectory && !rhs.isDirectory)\n                return -1;\n            else if (!lhs.isDirectory && rhs.isDirectory)\n                return 1;\n            return lhs.file.getName().compareToIgnoreCase(rhs.file.getName());\n        }\n    };\n\n    private static Set<String> sMediaExtSet = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);\n\n    static {\n        sMediaExtSet.add(\"flv\");\n        sMediaExtSet.add(\"mp4\");\n    }\n\n    private class FileItem {\n        public File file;\n        public boolean isDirectory;\n        public boolean isVideo;\n\n        public FileItem(String file) {\n            this(new File(file));\n        }\n\n        public FileItem(File file) {\n            this.file = file;\n            this.isDirectory = file.isDirectory();\n\n            String fileName = file.getName();\n            if (!TextUtils.isEmpty(fileName)) {\n                int extPos = fileName.lastIndexOf('.');\n                if (extPos >= 0) {\n                    String ext = fileName.substring(extPos + 1);\n                    if (!TextUtils.isEmpty(ext) && sMediaExtSet.contains(ext)) {\n                        this.isVideo = true;\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/content/PathCursorLoader.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.content;\n\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.os.Environment;\nimport android.support.v4.content.AsyncTaskLoader;\n\nimport java.io.File;\n\npublic class PathCursorLoader extends AsyncTaskLoader<Cursor> {\n    private File mPath;\n\n    public PathCursorLoader(Context context) {\n        this(context, Environment.getExternalStorageDirectory());\n    }\n\n    public PathCursorLoader(Context context, String path) {\n        super(context);\n        mPath = new File(path).getAbsoluteFile();\n    }\n\n    public PathCursorLoader(Context context, File path) {\n        super(context);\n        mPath = path;\n    }\n\n    @Override\n    public Cursor loadInBackground() {\n        File[] file_list = mPath.listFiles();\n        return new PathCursor(mPath, file_list);\n    }\n\n    @Override\n    protected void onStartLoading() {\n        forceLoad();\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/content/RecentMediaStorage.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.content;\n\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.database.sqlite.SQLiteOpenHelper;\nimport android.os.AsyncTask;\nimport android.support.v4.content.AsyncTaskLoader;\nimport android.text.TextUtils;\n\npublic class RecentMediaStorage {\n    private Context mAppContext;\n\n    public RecentMediaStorage(Context context) {\n        mAppContext = context.getApplicationContext();\n    }\n\n    public void saveUrlAsync(String url) {\n        new AsyncTask<String, Void, Void>() {\n            @Override\n            protected Void doInBackground(String... params) {\n                saveUrl(params[0]);\n                return null;\n            }\n        }.execute(url);\n    }\n\n    public void saveUrl(String url) {\n        ContentValues cv = new ContentValues();\n        cv.putNull(Entry.COLUMN_NAME_ID);\n        cv.put(Entry.COLUMN_NAME_URL, url);\n        cv.put(Entry.COLUMN_NAME_LAST_ACCESS, System.currentTimeMillis());\n        cv.put(Entry.COLUMN_NAME_NAME, getNameOfUrl(url));\n        save(cv);\n    }\n\n    public void save(ContentValues contentValue) {\n        OpenHelper openHelper = new OpenHelper(mAppContext);\n        SQLiteDatabase db = openHelper.getWritableDatabase();\n        db.replace(Entry.TABLE_NAME, null, contentValue);\n    }\n\n    public static String getNameOfUrl(String url) {\n        return getNameOfUrl(url, \"\");\n    }\n\n    public static String getNameOfUrl(String url, String defaultName) {\n        String name = null;\n        int pos = url.lastIndexOf('/');\n        if (pos >= 0)\n            name = url.substring(pos + 1);\n\n        if (TextUtils.isEmpty(name))\n            name = defaultName;\n\n        return name;\n    }\n\n    public static class Entry {\n        public static final String TABLE_NAME = \"RecentMedia\";\n        public static final String COLUMN_NAME_ID = \"id\";\n        public static final String COLUMN_NAME_URL = \"url\";\n        public static final String COLUMN_NAME_NAME = \"name\";\n        public static final String COLUMN_NAME_LAST_ACCESS = \"last_access\";\n    }\n\n    public static final String ALL_COLUMNS[] = new String[]{\n            Entry.COLUMN_NAME_ID + \" as _id\",\n            Entry.COLUMN_NAME_ID,\n            Entry.COLUMN_NAME_URL,\n            Entry.COLUMN_NAME_NAME,\n            Entry.COLUMN_NAME_LAST_ACCESS};\n\n    public static class OpenHelper extends SQLiteOpenHelper {\n        private static final int DATABASE_VERSION = 1;\n        private static final String DATABASE_NAME = \"RecentMedia.db\";\n        private static final String SQL_CREATE_ENTRIES =\n                \" CREATE TABLE IF NOT EXISTS \" + Entry.TABLE_NAME + \" (\" +\n                        Entry.COLUMN_NAME_ID + \" INTEGER PRIMARY KEY AUTOINCREMENT, \" +\n                        Entry.COLUMN_NAME_URL + \" VARCHAR UNIQUE, \" +\n                        Entry.COLUMN_NAME_NAME + \" VARCHAR, \" +\n                        Entry.COLUMN_NAME_LAST_ACCESS + \" INTEGER) \";\n\n        public OpenHelper(Context context) {\n            super(context, DATABASE_NAME, null, DATABASE_VERSION);\n        }\n\n        @Override\n        public void onCreate(SQLiteDatabase db) {\n            db.execSQL(SQL_CREATE_ENTRIES);\n        }\n\n        @Override\n        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {\n        }\n    }\n\n    public static class CursorLoader extends AsyncTaskLoader<Cursor> {\n        public CursorLoader(Context context) {\n            super(context);\n        }\n\n        @Override\n        public Cursor loadInBackground() {\n            Context context = getContext();\n            OpenHelper openHelper = new OpenHelper(context);\n            SQLiteDatabase db = openHelper.getReadableDatabase();\n\n            return db.query(Entry.TABLE_NAME, ALL_COLUMNS, null, null, null, null,\n                    Entry.COLUMN_NAME_LAST_ACCESS + \" DESC\",\n                    \"100\");\n        }\n\n        @Override\n        protected void onStartLoading() {\n            forceLoad();\n        }\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/eventbus/FileExplorerEvents.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.eventbus;\n\nimport com.squareup.otto.Bus;\n\nimport java.io.File;\n\npublic class FileExplorerEvents {\n    private static final Bus BUS = new Bus();\n\n    public static Bus getBus() {\n        return BUS;\n    }\n\n    private FileExplorerEvents() {\n        // No instances.\n    }\n\n    public static class OnClickFile {\n        public File mFile;\n\n        public OnClickFile(String path) {\n            this(new File(path));\n        }\n\n        public OnClickFile(File file) {\n            mFile = file;\n        }\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/fragments/FileListFragment.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.fragments;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.LoaderManager;\nimport android.support.v4.content.Loader;\nimport android.support.v4.widget.SimpleCursorAdapter;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.ImageView;\nimport android.widget.ListView;\nimport android.widget.TextView;\n\nimport java.io.File;\n\nimport tv.danmaku.ijk.media.example.R;\nimport tv.danmaku.ijk.media.example.content.PathCursor;\nimport tv.danmaku.ijk.media.example.content.PathCursorLoader;\nimport tv.danmaku.ijk.media.example.eventbus.FileExplorerEvents;\n\npublic class FileListFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {\n    private static final String ARG_PATH = \"path\";\n\n    private TextView mPathView;\n    private ListView mFileListView;\n    private VideoAdapter mAdapter;\n    private String mPath;\n\n    public static FileListFragment newInstance(String path) {\n        FileListFragment f = new FileListFragment();\n\n        // Supply index input as an argument.\n        Bundle args = new Bundle();\n        args.putString(ARG_PATH, path);\n        f.setArguments(args);\n\n        return f;\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        ViewGroup viewGroup = (ViewGroup) inflater.inflate(R.layout.fragment_file_list, container, false);\n        mPathView = (TextView) viewGroup.findViewById(R.id.path_view);\n        mFileListView = (ListView) viewGroup.findViewById(R.id.file_list_view);\n\n        mPathView.setVisibility(View.VISIBLE);\n\n        return viewGroup;\n    }\n\n    @Override\n    public void onActivityCreated(@Nullable Bundle savedInstanceState) {\n        super.onActivityCreated(savedInstanceState);\n\n        Activity activity = getActivity();\n\n        Bundle bundle = getArguments();\n        if (bundle != null) {\n            mPath = bundle.getString(ARG_PATH);\n            mPath = new File(mPath).getAbsolutePath();\n            mPathView.setText(mPath);\n        }\n\n        mAdapter = new VideoAdapter(activity);\n        mFileListView.setAdapter(mAdapter);\n        mFileListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {\n            @Override\n            public void onItemClick(AdapterView<?> parent, View view, final int position, final long id) {\n                String path = mAdapter.getFilePath(position);\n                if (TextUtils.isEmpty(path))\n                    return;\n                FileExplorerEvents.getBus().post(new FileExplorerEvents.OnClickFile(path));\n            }\n        });\n\n        getLoaderManager().initLoader(1, null, this);\n    }\n\n    @Override\n    public Loader<Cursor> onCreateLoader(int id, Bundle args) {\n        if (TextUtils.isEmpty(mPath))\n            return null;\n        return new PathCursorLoader(getActivity(), mPath);\n    }\n\n    @Override\n    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {\n        mAdapter.swapCursor(data);\n        mAdapter.notifyDataSetChanged();\n    }\n\n    @Override\n    public void onLoaderReset(Loader<Cursor> loader) {\n\n    }\n\n    final class VideoAdapter extends SimpleCursorAdapter {\n        final class ViewHolder {\n            public ImageView iconImageView;\n            public TextView nameTextView;\n        }\n\n        public VideoAdapter(Context context) {\n            super(context, android.R.layout.simple_list_item_2, null,\n                    new String[]{PathCursor.CN_FILE_NAME, PathCursor.CN_FILE_PATH},\n                    new int[]{android.R.id.text1, android.R.id.text2}, 0);\n        }\n\n        @Override\n        public View getView(int position, View convertView, ViewGroup parent) {\n            View view = convertView;\n            if (view == null) {\n                LayoutInflater inflater = LayoutInflater.from(parent.getContext());\n                view = inflater.inflate(R.layout.fragment_file_list_item, parent, false);\n            }\n\n            ViewHolder viewHolder = (ViewHolder) view.getTag();\n            if (viewHolder == null) {\n                viewHolder = new ViewHolder();\n                viewHolder.iconImageView = (ImageView) view.findViewById(R.id.icon);\n                viewHolder.nameTextView = (TextView) view.findViewById(R.id.name);\n            }\n\n            if (isDirectory(position)) {\n                viewHolder.iconImageView.setImageResource(R.drawable.ic_theme_folder);\n            } else if (isVideo(position)) {\n                viewHolder.iconImageView.setImageResource(R.drawable.ic_theme_play_arrow);\n            } else {\n                viewHolder.iconImageView.setImageResource(R.drawable.ic_theme_description);\n            }\n            viewHolder.nameTextView.setText(getFileName(position));\n\n            return view;\n        }\n\n        @Override\n        public long getItemId(int position) {\n            final Cursor cursor = moveToPosition(position);\n            if (cursor == null)\n                return 0;\n\n            return cursor.getLong(PathCursor.CI_ID);\n        }\n\n        Cursor moveToPosition(int position) {\n            final Cursor cursor = getCursor();\n            if (cursor.getCount() == 0 || position >= cursor.getCount()) {\n                return null;\n            }\n            cursor.moveToPosition(position);\n            return cursor;\n        }\n\n        public boolean isDirectory(int position) {\n            final Cursor cursor = moveToPosition(position);\n            if (cursor == null)\n                return true;\n\n            return cursor.getInt(PathCursor.CI_IS_DIRECTORY) != 0;\n        }\n\n        public boolean isVideo(int position) {\n            final Cursor cursor = moveToPosition(position);\n            if (cursor == null)\n                return true;\n\n            return cursor.getInt(PathCursor.CI_IS_VIDEO) != 0;\n        }\n\n        public String getFileName(int position) {\n            final Cursor cursor = moveToPosition(position);\n            if (cursor == null)\n                return \"\";\n\n            return cursor.getString(PathCursor.CI_FILE_NAME);\n        }\n\n        public String getFilePath(int position) {\n            final Cursor cursor = moveToPosition(position);\n            if (cursor == null)\n                return \"\";\n\n            return cursor.getString(PathCursor.CI_FILE_PATH);\n        }\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/fragments/RecentMediaListFragment.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.fragments;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.LoaderManager;\nimport android.support.v4.content.Loader;\nimport android.support.v4.widget.SimpleCursorAdapter;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.ListView;\n\nimport tv.danmaku.ijk.media.example.R;\nimport tv.danmaku.ijk.media.example.activities.VideoActivity;\nimport tv.danmaku.ijk.media.example.content.RecentMediaStorage;\n\npublic class RecentMediaListFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {\n    private ListView mFileListView;\n    private RecentMediaAdapter mAdapter;\n\n    public static RecentMediaListFragment newInstance() {\n        RecentMediaListFragment f = new RecentMediaListFragment();\n        return f;\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        ViewGroup viewGroup = (ViewGroup) inflater.inflate(R.layout.fragment_file_list, container, false);\n        mFileListView = (ListView) viewGroup.findViewById(R.id.file_list_view);\n        return viewGroup;\n    }\n\n    @Override\n    public void onActivityCreated(@Nullable Bundle savedInstanceState) {\n        super.onActivityCreated(savedInstanceState);\n\n        final Activity activity = getActivity();\n\n        mAdapter = new RecentMediaAdapter(activity);\n        mFileListView.setAdapter(mAdapter);\n        mFileListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {\n            @Override\n            public void onItemClick(AdapterView<?> parent, View view, final int position, final long id) {\n                String url = mAdapter.getUrl(position);\n                String name = mAdapter.getName(position);\n                VideoActivity.intentTo(activity, url, name);\n            }\n        });\n\n        getLoaderManager().initLoader(2, null, this);\n    }\n\n    @Override\n    public Loader<Cursor> onCreateLoader(int id, Bundle args) {\n        return new RecentMediaStorage.CursorLoader(getActivity());\n    }\n\n    @Override\n    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {\n        mAdapter.swapCursor(data);\n        mAdapter.notifyDataSetChanged();\n    }\n\n    @Override\n    public void onLoaderReset(Loader<Cursor> loader) {\n\n    }\n\n    final class RecentMediaAdapter extends SimpleCursorAdapter {\n        private int mIndex_id = -1;\n        private int mIndex_url = -1;\n        private int mIndex_name = -1;\n\n        public RecentMediaAdapter(Context context) {\n            super(context, android.R.layout.simple_list_item_2, null,\n                    new String[]{RecentMediaStorage.Entry.COLUMN_NAME_NAME, RecentMediaStorage.Entry.COLUMN_NAME_URL},\n                    new int[]{android.R.id.text1, android.R.id.text2}, 0);\n        }\n\n        @Override\n        public Cursor swapCursor(Cursor c) {\n            Cursor res = super.swapCursor(c);\n\n            mIndex_id = c.getColumnIndex(RecentMediaStorage.Entry.COLUMN_NAME_ID);\n            mIndex_url = c.getColumnIndex(RecentMediaStorage.Entry.COLUMN_NAME_URL);\n            mIndex_name = c.getColumnIndex(RecentMediaStorage.Entry.COLUMN_NAME_NAME);\n\n            return res;\n        }\n\n        @Override\n        public long getItemId(int position) {\n            final Cursor cursor = moveToPosition(position);\n            if (cursor == null)\n                return 0;\n\n            return cursor.getLong(mIndex_id);\n        }\n\n        Cursor moveToPosition(int position) {\n            final Cursor cursor = getCursor();\n            if (cursor.getCount() == 0 || position >= cursor.getCount()) {\n                return null;\n            }\n            cursor.moveToPosition(position);\n            return cursor;\n        }\n\n        public String getUrl(int position) {\n            final Cursor cursor = moveToPosition(position);\n            if (cursor == null)\n                return \"\";\n\n            return cursor.getString(mIndex_url);\n        }\n\n        public String getName(int position) {\n            final Cursor cursor = moveToPosition(position);\n            if (cursor == null)\n                return \"\";\n\n            return cursor.getString(mIndex_name);\n        }\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/fragments/SampleMediaListFragment.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.fragments;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.support.v4.app.Fragment;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.ArrayAdapter;\nimport android.widget.ListView;\nimport android.widget.TextView;\n\nimport tv.danmaku.ijk.media.example.R;\nimport tv.danmaku.ijk.media.example.activities.VideoActivity;\n\npublic class SampleMediaListFragment extends Fragment {\n    private ListView mFileListView;\n    private SampleMediaAdapter mAdapter;\n\n    public static SampleMediaListFragment newInstance() {\n        SampleMediaListFragment f = new SampleMediaListFragment();\n        return f;\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        ViewGroup viewGroup = (ViewGroup) inflater.inflate(R.layout.fragment_file_list, container, false);\n        mFileListView = (ListView) viewGroup.findViewById(R.id.file_list_view);\n        return viewGroup;\n    }\n\n    @Override\n    public void onActivityCreated(@Nullable Bundle savedInstanceState) {\n        super.onActivityCreated(savedInstanceState);\n\n        final Activity activity = getActivity();\n\n        mAdapter = new SampleMediaAdapter(activity);\n        mFileListView.setAdapter(mAdapter);\n        mFileListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {\n            @Override\n            public void onItemClick(AdapterView<?> parent, View view, final int position, final long id) {\n                SampleMediaItem item = mAdapter.getItem(position);\n                String name = item.mName;\n                String url = item.mUrl;\n                VideoActivity.intentTo(activity, url, name);\n            }\n        });\n\n        String manifest_string =\n                \"{\\n\" +\n                \"    \\\"version\\\": \\\"1.0.0\\\",\\n\" +\n                \"    \\\"adaptationSet\\\": [\\n\" +\n                \"        {\\n\" +\n                \"            \\\"duration\\\": 1000,\\n\" +\n                \"            \\\"id\\\": 1,\\n\" +\n                \"            \\\"representation\\\": [\\n\" +\n                \"                {\\n\" +\n                \"                    \\\"id\\\": 1,\\n\" +\n                \"                    \\\"codec\\\": \\\"avc1.64001e,mp4a.40.5\\\",\\n\" +\n                \"                    \\\"url\\\": \\\"http://las-tech.org.cn/kwai/las-test_ld500d.flv\\\",\\n\" +\n                \"                    \\\"backupUrl\\\": [],\\n\" +\n                \"                    \\\"host\\\": \\\"las-tech.org.cn\\\",\\n\" +\n                \"                    \\\"maxBitrate\\\": 700,\\n\" +\n                \"                    \\\"width\\\": 640,\\n\" +\n                \"                    \\\"height\\\": 360,\\n\" +\n                \"                    \\\"frameRate\\\": 25,\\n\" +\n                \"                    \\\"qualityType\\\": \\\"SMOOTH\\\",\\n\" +\n                \"                    \\\"qualityTypeName\\\": \\\"流畅\\\",\\n\" +\n                \"                    \\\"hidden\\\": false,\\n\" +\n                \"                    \\\"disabledFromAdaptive\\\": false,\\n\" +\n                \"                    \\\"defaultSelected\\\": false\\n\" +\n                \"                },\\n\" +\n                \"                {\\n\" +\n                \"                    \\\"id\\\": 2,\\n\" +\n                \"                    \\\"codec\\\": \\\"avc1.64001f,mp4a.40.5\\\",\\n\" +\n                \"                    \\\"url\\\": \\\"http://las-tech.org.cn/kwai/las-test_sd1000d.flv\\\",\\n\" +\n                \"                    \\\"backupUrl\\\": [],\\n\" +\n                \"                    \\\"host\\\": \\\"las-tech.org.cn\\\",\\n\" +\n                \"                    \\\"maxBitrate\\\": 1300,\\n\" +\n                \"                    \\\"width\\\": 960,\\n\" +\n                \"                    \\\"height\\\": 540,\\n\" +\n                \"                    \\\"frameRate\\\": 25,\\n\" +\n                \"                    \\\"qualityType\\\": \\\"STANDARD\\\",\\n\" +\n                \"                    \\\"qualityTypeName\\\": \\\"标清\\\",\\n\" +\n                \"                    \\\"hidden\\\": false,\\n\" +\n                \"                    \\\"disabledFromAdaptive\\\": false,\\n\" +\n                \"                    \\\"defaultSelected\\\": true\\n\" +\n                \"                },\\n\" +\n                \"                {\\n\" +\n                \"                    \\\"id\\\": 3,\\n\" +\n                \"                    \\\"codec\\\": \\\"avc1.64001f,mp4a.40.5\\\",\\n\" +\n                \"                    \\\"url\\\": \\\"http://las-tech.org.cn/kwai/las-test.flv\\\",\\n\" +\n                \"                    \\\"backupUrl\\\": [],\\n\" +\n                \"                    \\\"host\\\": \\\"las-tech.org.cn\\\",\\n\" +\n                \"                    \\\"maxBitrate\\\": 2300,\\n\" +\n                \"                    \\\"width\\\": 1280,\\n\" +\n                \"                    \\\"height\\\": 720,\\n\" +\n                \"                    \\\"frameRate\\\": 30,\\n\" +\n                \"                    \\\"qualityType\\\": \\\"HIGH\\\",\\n\" +\n                \"                    \\\"qualityTypeName\\\": \\\"高清\\\",\\n\" +\n                \"                    \\\"hidden\\\": false,\\n\" +\n                \"                    \\\"disabledFromAdaptive\\\": false,\\n\" +\n                \"                    \\\"defaultSelected\\\": false\\n\" +\n                \"                }\\n\" +\n                \"            ]\\n\" +\n                \"        }\\n\" +\n                \"    ]\\n\" +\n                \"}\";\n\n        mAdapter.addItem(manifest_string, \"las test\");\n        mAdapter.addItem(\"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8\", \"bipbop basic master playlist\");\n        mAdapter.addItem(\"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/prog_index.m3u8\", \"bipbop basic 400x300 @ 232 kbps\");\n        mAdapter.addItem(\"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear2/prog_index.m3u8\", \"bipbop basic 640x480 @ 650 kbps\");\n        mAdapter.addItem(\"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear3/prog_index.m3u8\", \"bipbop basic 640x480 @ 1 Mbps\");\n        mAdapter.addItem(\"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear4/prog_index.m3u8\", \"bipbop basic 960x720 @ 2 Mbps\");\n        mAdapter.addItem(\"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear0/prog_index.m3u8\", \"bipbop basic 22.050Hz stereo @ 40 kbps\");\n        mAdapter.addItem(\"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8\", \"bipbop advanced master playlist\");\n        mAdapter.addItem(\"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/gear1/prog_index.m3u8\", \"bipbop advanced 416x234 @ 265 kbps\");\n        mAdapter.addItem(\"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/gear2/prog_index.m3u8\", \"bipbop advanced 640x360 @ 580 kbps\");\n        mAdapter.addItem(\"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/gear3/prog_index.m3u8\", \"bipbop advanced 960x540 @ 910 kbps\");\n        mAdapter.addItem(\"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/gear4/prog_index.m3u8\", \"bipbop advanced 1289x720 @ 1 Mbps\");\n        mAdapter.addItem(\"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/gear5/prog_index.m3u8\", \"bipbop advanced 1920x1080 @ 2 Mbps\");\n        mAdapter.addItem(\"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/gear0/prog_index.m3u8\", \"bipbop advanced 22.050Hz stereo @ 40 kbps\");\n    }\n\n    final class SampleMediaItem {\n        String mUrl;\n        String mName;\n\n        public SampleMediaItem(String url, String name) {\n            mUrl = url;\n            mName = name;\n        }\n    }\n\n    final class SampleMediaAdapter extends ArrayAdapter<SampleMediaItem> {\n        public SampleMediaAdapter(Context context) {\n            super(context, android.R.layout.simple_list_item_2);\n        }\n\n        public void addItem(String url, String name) {\n            add(new SampleMediaItem(url, name));\n        }\n\n        @Override\n        public long getItemId(int position) {\n            return position;\n        }\n\n        @Override\n        public View getView(int position, View convertView, ViewGroup parent) {\n            View view = convertView;\n            if (view == null) {\n                LayoutInflater inflater = LayoutInflater.from(parent.getContext());\n                view = inflater.inflate(android.R.layout.simple_list_item_2, parent, false);\n            }\n\n            ViewHolder viewHolder = (ViewHolder) view.getTag();\n            if (viewHolder == null) {\n                viewHolder = new ViewHolder();\n                viewHolder.mNameTextView = (TextView) view.findViewById(android.R.id.text1);\n                viewHolder.mUrlTextView = (TextView) view.findViewById(android.R.id.text2);\n            }\n\n            SampleMediaItem item = getItem(position);\n            viewHolder.mNameTextView.setText(item.mName);\n            viewHolder.mUrlTextView.setText(item.mUrl);\n\n            return view;\n        }\n\n        final class ViewHolder {\n            public TextView mNameTextView;\n            public TextView mUrlTextView;\n        }\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/fragments/SettingsFragment.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.fragments;\n\nimport android.os.Bundle;\nimport android.support.v7.preference.PreferenceFragmentCompat;\n\nimport tv.danmaku.ijk.media.example.R;\n\npublic class SettingsFragment extends PreferenceFragmentCompat {\n    public static SettingsFragment newInstance() {\n        SettingsFragment f = new SettingsFragment();\n        return f;\n    }\n\n    @Override\n    public void onCreatePreferences(Bundle bundle, String s) {\n        addPreferencesFromResource(R.xml.settings);\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/fragments/TracksFragment.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.fragments;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.support.v4.app.Fragment;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.ArrayAdapter;\nimport android.widget.ListView;\nimport android.widget.TextView;\n\nimport java.util.Locale;\n\nimport tv.danmaku.ijk.media.player.misc.ITrackInfo;\nimport tv.danmaku.ijk.media.example.R;\n\npublic class TracksFragment extends Fragment {\n    private ListView mTrackListView;\n    private TrackAdapter mAdapter;\n\n    public static TracksFragment newInstance() {\n        TracksFragment f = new TracksFragment();\n        return f;\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        ViewGroup viewGroup = (ViewGroup) inflater.inflate(R.layout.fragment_track_list, container, false);\n        mTrackListView = (ListView) viewGroup.findViewById(R.id.track_list_view);\n        return viewGroup;\n    }\n\n    @Override\n    public void onActivityCreated(@Nullable Bundle savedInstanceState) {\n        super.onActivityCreated(savedInstanceState);\n\n        final Activity activity = getActivity();\n\n        mAdapter = new TrackAdapter(activity);\n        mTrackListView.setAdapter(mAdapter);\n\n        if (activity instanceof ITrackHolder) {\n            final ITrackHolder trackHolder = (ITrackHolder) activity;\n            mAdapter.setTrackHolder(trackHolder);\n\n            int selectedVideoTrack = trackHolder.getSelectedTrack(ITrackInfo.MEDIA_TRACK_TYPE_VIDEO);\n            int selectedAudioTrack = trackHolder.getSelectedTrack(ITrackInfo.MEDIA_TRACK_TYPE_AUDIO);\n            int selectedSubtitleTrack = trackHolder.getSelectedTrack(ITrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT);\n            if (selectedVideoTrack >= 0)\n                mTrackListView.setItemChecked(selectedVideoTrack, true);\n            if (selectedAudioTrack >= 0)\n                mTrackListView.setItemChecked(selectedAudioTrack, true);\n            if (selectedSubtitleTrack >= 0)\n                mTrackListView.setItemChecked(selectedSubtitleTrack, true);\n\n            mTrackListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {\n                @Override\n                public void onItemClick(AdapterView<?> parent, View view, final int position, final long id) {\n                    TrackItem trackItem = (TrackItem) mTrackListView.getItemAtPosition(position);\n                    for (int i = 0; i < mAdapter.getCount(); ++i) {\n                        TrackItem compareItem = mAdapter.getItem(i);\n                        if (compareItem.mIndex == trackItem.mIndex)\n                            continue;\n\n                        if (compareItem.mTrackInfo.getTrackType() != trackItem.mTrackInfo.getTrackType())\n                            continue;\n\n                        if (mTrackListView.isItemChecked(i))\n                            mTrackListView.setItemChecked(i, false);\n                    }\n                    if (mTrackListView.isItemChecked(position)) {\n                        trackHolder.selectTrack(trackItem.mIndex);\n                    } else {\n                        trackHolder.deselectTrack(trackItem.mIndex);\n                    }\n                }\n            });\n        } else {\n            Log.e(\"TracksFragment\", \"activity is not an instance of ITrackHolder.\");\n        }\n    }\n\n    public interface ITrackHolder {\n        ITrackInfo[] getTrackInfo();\n        int getSelectedTrack(int trackType);\n        void selectTrack(int stream);\n        void deselectTrack(int stream);\n    }\n\n    final class TrackItem {\n        public int mIndex;\n        public ITrackInfo mTrackInfo;\n\n        public String mInfoInline;\n\n        public TrackItem(int index, ITrackInfo trackInfo) {\n            mIndex = index;\n            mTrackInfo = trackInfo;\n            mInfoInline = String.format(Locale.US, \"# %d: %s\", mIndex, mTrackInfo.getInfoInline());\n        }\n\n        public String getInfoInline() {\n            return mInfoInline;\n        }\n    }\n\n    final class TrackAdapter extends ArrayAdapter<TrackItem> {\n        private ITrackHolder mTrackHolder;\n        private ITrackInfo[] mTrackInfos;\n\n        public TrackAdapter(Context context) {\n            super(context, android.R.layout.simple_list_item_checked);\n        }\n\n        public void setTrackHolder(ITrackHolder trackHolder) {\n            clear();\n            mTrackHolder = trackHolder;\n            mTrackInfos = mTrackHolder.getTrackInfo();\n            if (mTrackInfos != null) {\n                for(ITrackInfo trackInfo: mTrackInfos) {\n                    int index = getCount();\n                    TrackItem item = new TrackItem(index, trackInfo);\n                    add(item);\n                }\n            }\n        }\n\n        @Override\n        public long getItemId(int position) {\n            return position;\n        }\n\n        @Override\n        public View getView(int position, View convertView, ViewGroup parent) {\n            View view = convertView;\n            if (view == null) {\n                LayoutInflater inflater = LayoutInflater.from(parent.getContext());\n                view = inflater.inflate(android.R.layout.simple_list_item_checked, parent, false);\n            }\n\n            ViewHolder viewHolder = (ViewHolder) view.getTag();\n            if (viewHolder == null) {\n                viewHolder = new ViewHolder();\n                viewHolder.mNameTextView = (TextView) view.findViewById(android.R.id.text1);\n            }\n\n            TrackItem item = getItem(position);\n            viewHolder.mNameTextView.setText(item.getInfoInline());\n\n            return view;\n        }\n\n        final class ViewHolder {\n            public TextView mNameTextView;\n        }\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/services/MediaPlayerService.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.services;\n\nimport android.app.Service;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.IBinder;\nimport android.support.annotation.Nullable;\n\nimport tv.danmaku.ijk.media.player.IMediaPlayer;\n\npublic class MediaPlayerService extends Service {\n    private static IMediaPlayer sMediaPlayer;\n\n    public static Intent newIntent(Context context) {\n        Intent intent = new Intent(context, MediaPlayerService.class);\n        return intent;\n    }\n\n    public static void intentToStart(Context context) {\n        context.startService(newIntent(context));\n    }\n\n    public static void intentToStop(Context context) {\n        context.stopService(newIntent(context));\n    }\n\n    @Nullable\n    @Override\n    public IBinder onBind(Intent intent) {\n        return null;\n    }\n\n    public static void setMediaPlayer(IMediaPlayer mp) {\n        if (sMediaPlayer != null && sMediaPlayer != mp) {\n            if (sMediaPlayer.isPlaying())\n                sMediaPlayer.stop();\n            sMediaPlayer.release();\n            sMediaPlayer = null;\n        }\n        sMediaPlayer = mp;\n    }\n\n    public static IMediaPlayer getMediaPlayer() {\n        return sMediaPlayer;\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/media/AndroidMediaController.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.widget.media;\n\nimport android.content.Context;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.support.v7.app.ActionBar;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport android.widget.MediaController;\n\nimport java.util.ArrayList;\n\npublic class AndroidMediaController extends MediaController implements IMediaController {\n    private ActionBar mActionBar;\n\n    public AndroidMediaController(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        initView(context);\n    }\n\n    public AndroidMediaController(Context context, boolean useFastForward) {\n        super(context, useFastForward);\n        initView(context);\n    }\n\n    public AndroidMediaController(Context context) {\n        super(context);\n        initView(context);\n    }\n\n    private void initView(Context context) {\n    }\n\n    public void setSupportActionBar(@Nullable ActionBar actionBar) {\n        mActionBar = actionBar;\n        if (isShowing()) {\n            actionBar.show();\n        } else {\n            actionBar.hide();\n        }\n    }\n\n    @Override\n    public void show() {\n        super.show();\n        if (mActionBar != null)\n            mActionBar.show();\n    }\n\n    @Override\n    public void hide() {\n        super.hide();\n        if (mActionBar != null)\n            mActionBar.hide();\n        for (View view : mShowOnceArray)\n            view.setVisibility(View.GONE);\n        mShowOnceArray.clear();\n    }\n\n    //----------\n    // Extends\n    //----------\n    private ArrayList<View> mShowOnceArray = new ArrayList<View>();\n\n    public void showOnce(@NonNull View view) {\n        mShowOnceArray.add(view);\n        view.setVisibility(View.VISIBLE);\n        show();\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/media/FileMediaDataSource.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.widget.media;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\n\nimport tv.danmaku.ijk.media.player.misc.IMediaDataSource;\n\npublic class FileMediaDataSource implements IMediaDataSource {\n    private RandomAccessFile mFile;\n    private long mFileSize;\n\n    public FileMediaDataSource(File file) throws IOException {\n        mFile = new RandomAccessFile(file, \"r\");\n        mFileSize = mFile.length();\n    }\n\n    @Override\n    public int readAt(long position, byte[] buffer, int offset, int size) throws IOException {\n        if (mFile.getFilePointer() != position)\n            mFile.seek(position);\n\n        if (size == 0)\n            return 0;\n\n        return mFile.read(buffer, 0, size);\n    }\n\n    @Override\n    public long getSize() throws IOException {\n        return mFileSize;\n    }\n\n    @Override\n    public void close() throws IOException {\n        mFileSize = 0;\n        mFile.close();\n        mFile = null;\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/media/IMediaController.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.widget.media;\n\nimport android.view.View;\nimport android.widget.MediaController;\n\npublic interface IMediaController {\n    void hide();\n\n    boolean isShowing();\n\n    void setAnchorView(View view);\n\n    void setEnabled(boolean enabled);\n\n    void setMediaPlayer(MediaController.MediaPlayerControl player);\n\n    void show(int timeout);\n\n    void show();\n\n    //----------\n    // Extends\n    //----------\n    void showOnce(View view);\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/media/IRenderView.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.widget.media;\n\nimport android.graphics.SurfaceTexture;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.view.Surface;\nimport android.view.SurfaceHolder;\nimport android.view.View;\n\nimport tv.danmaku.ijk.media.player.IMediaPlayer;\n\npublic interface IRenderView {\n    int AR_ASPECT_FIT_PARENT = 0; // without clip\n    int AR_ASPECT_FILL_PARENT = 1; // may clip\n    int AR_ASPECT_WRAP_CONTENT = 2;\n    int AR_MATCH_PARENT = 3;\n    int AR_16_9_FIT_PARENT = 4;\n    int AR_4_3_FIT_PARENT = 5;\n\n    View getView();\n\n    boolean shouldWaitForResize();\n\n    void setVideoSize(int videoWidth, int videoHeight);\n\n    void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen);\n\n    void setVideoRotation(int degree);\n\n    void setAspectRatio(int aspectRatio);\n\n    void addRenderCallback(@NonNull IRenderCallback callback);\n\n    void removeRenderCallback(@NonNull IRenderCallback callback);\n\n    interface ISurfaceHolder {\n        void bindToMediaPlayer(IMediaPlayer mp);\n\n        @NonNull\n        IRenderView getRenderView();\n\n        @Nullable\n        SurfaceHolder getSurfaceHolder();\n\n        @Nullable\n        Surface openSurface();\n\n        @Nullable\n        SurfaceTexture getSurfaceTexture();\n    }\n\n    interface IRenderCallback {\n        /**\n         * @param holder\n         * @param width  could be 0\n         * @param height could be 0\n         */\n        void onSurfaceCreated(@NonNull ISurfaceHolder holder, int width, int height);\n\n        /**\n         * @param holder\n         * @param format could be 0\n         * @param width\n         * @param height\n         */\n        void onSurfaceChanged(@NonNull ISurfaceHolder holder, int format, int width, int height);\n\n        void onSurfaceDestroyed(@NonNull ISurfaceHolder holder);\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/media/IjkVideoView.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.widget.media;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.res.Resources;\nimport android.media.AudioManager;\nimport android.media.MediaPlayer;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.support.annotation.NonNull;\nimport android.support.v7.app.AlertDialog;\nimport android.text.TextUtils;\nimport android.util.AttributeSet;\nimport android.util.Log;\nimport android.view.Gravity;\nimport android.view.KeyEvent;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.widget.FrameLayout;\nimport android.widget.MediaController;\nimport android.widget.TableLayout;\nimport android.widget.TextView;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport tv.danmaku.ijk.media.exo.IjkExoMediaPlayer;\nimport tv.danmaku.ijk.media.player.AndroidMediaPlayer;\nimport tv.danmaku.ijk.media.player.IMediaPlayer;\nimport tv.danmaku.ijk.media.player.IjkMediaPlayer;\nimport tv.danmaku.ijk.media.player.IjkTimedText;\nimport tv.danmaku.ijk.media.player.TextureMediaPlayer;\nimport tv.danmaku.ijk.media.player.misc.IMediaDataSource;\nimport tv.danmaku.ijk.media.player.misc.IMediaFormat;\nimport tv.danmaku.ijk.media.player.misc.ITrackInfo;\nimport tv.danmaku.ijk.media.player.misc.IjkMediaFormat;\nimport tv.danmaku.ijk.media.example.R;\nimport tv.danmaku.ijk.media.example.application.Settings;\nimport tv.danmaku.ijk.media.example.services.MediaPlayerService;\n\npublic class IjkVideoView extends FrameLayout implements MediaController.MediaPlayerControl {\n    private String TAG = \"IjkVideoView\";\n    // settable by the client\n    private Uri mUri;\n    private String mManifestString;\n    private Map<String, String> mHeaders;\n\n    // all possible internal states\n    private static final int STATE_ERROR = -1;\n    private static final int STATE_IDLE = 0;\n    private static final int STATE_PREPARING = 1;\n    private static final int STATE_PREPARED = 2;\n    private static final int STATE_PLAYING = 3;\n    private static final int STATE_PAUSED = 4;\n    private static final int STATE_PLAYBACK_COMPLETED = 5;\n\n    // mCurrentState is a VideoView object's current state.\n    // mTargetState is the state that a method caller intends to reach.\n    // For instance, regardless the VideoView object's current state,\n    // calling pause() intends to bring the object to a target state\n    // of STATE_PAUSED.\n    private int mCurrentState = STATE_IDLE;\n    private int mTargetState = STATE_IDLE;\n\n    // All the stuff we need for playing and showing a video\n    private IRenderView.ISurfaceHolder mSurfaceHolder = null;\n    private IMediaPlayer mMediaPlayer = null;\n    // private int         mAudioSession;\n    private int mVideoWidth;\n    private int mVideoHeight;\n    private int mSurfaceWidth;\n    private int mSurfaceHeight;\n    private int mVideoRotationDegree;\n    private IMediaController mMediaController;\n    private IMediaPlayer.OnCompletionListener mOnCompletionListener;\n    private IMediaPlayer.OnPreparedListener mOnPreparedListener;\n    private int mCurrentBufferPercentage;\n    private IMediaPlayer.OnErrorListener mOnErrorListener;\n    private IMediaPlayer.OnInfoListener mOnInfoListener;\n    private int mSeekWhenPrepared;  // recording the seek position while preparing\n    private boolean mCanPause = true;\n    private boolean mCanSeekBack = true;\n    private boolean mCanSeekForward = true;\n\n    /** Subtitle rendering widget overlaid on top of the video. */\n    // private RenderingWidget mSubtitleWidget;\n\n    /**\n     * Listener for changes to subtitle data, used to redraw when needed.\n     */\n    // private RenderingWidget.OnChangedListener mSubtitlesChangedListener;\n\n    private Context mAppContext;\n    private Settings mSettings;\n    private IRenderView mRenderView;\n    private int mVideoSarNum;\n    private int mVideoSarDen;\n\n    private InfoHudViewHolder mHudViewHolder;\n\n    private long mPrepareStartTime = 0;\n    private long mPrepareEndTime = 0;\n\n    private long mSeekStartTime = 0;\n    private long mSeekEndTime = 0;\n\n    private TextView subtitleDisplay;\n\n    public IjkVideoView(Context context) {\n        super(context);\n        initVideoView(context);\n    }\n\n    public IjkVideoView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        initVideoView(context);\n    }\n\n    public IjkVideoView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        initVideoView(context);\n    }\n\n    @TargetApi(Build.VERSION_CODES.LOLLIPOP)\n    public IjkVideoView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n        initVideoView(context);\n    }\n\n    // REMOVED: onMeasure\n    // REMOVED: onInitializeAccessibilityEvent\n    // REMOVED: onInitializeAccessibilityNodeInfo\n    // REMOVED: resolveAdjustedSize\n\n    private void initVideoView(Context context) {\n        mAppContext = context.getApplicationContext();\n        mSettings = new Settings(mAppContext);\n\n        initBackground();\n        initRenders();\n\n        mVideoWidth = 0;\n        mVideoHeight = 0;\n        // REMOVED: getHolder().addCallback(mSHCallback);\n        // REMOVED: getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);\n        setFocusable(true);\n        setFocusableInTouchMode(true);\n        requestFocus();\n        // REMOVED: mPendingSubtitleTracks = new Vector<Pair<InputStream, MediaFormat>>();\n        mCurrentState = STATE_IDLE;\n        mTargetState = STATE_IDLE;\n\n        subtitleDisplay = new TextView(context);\n        subtitleDisplay.setTextSize(24);\n        subtitleDisplay.setGravity(Gravity.CENTER);\n        FrameLayout.LayoutParams layoutParams_txt = new FrameLayout.LayoutParams(\n                FrameLayout.LayoutParams.MATCH_PARENT,\n                FrameLayout.LayoutParams.WRAP_CONTENT,\n                Gravity.BOTTOM);\n        addView(subtitleDisplay, layoutParams_txt);\n    }\n\n    public void setRenderView(IRenderView renderView) {\n        if (mRenderView != null) {\n            if (mMediaPlayer != null)\n                mMediaPlayer.setDisplay(null);\n\n            View renderUIView = mRenderView.getView();\n            mRenderView.removeRenderCallback(mSHCallback);\n            mRenderView = null;\n            removeView(renderUIView);\n        }\n\n        if (renderView == null)\n            return;\n\n        mRenderView = renderView;\n        renderView.setAspectRatio(mCurrentAspectRatio);\n        if (mVideoWidth > 0 && mVideoHeight > 0)\n            renderView.setVideoSize(mVideoWidth, mVideoHeight);\n        if (mVideoSarNum > 0 && mVideoSarDen > 0)\n            renderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);\n\n        View renderUIView = mRenderView.getView();\n        FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(\n                FrameLayout.LayoutParams.WRAP_CONTENT,\n                FrameLayout.LayoutParams.WRAP_CONTENT,\n                Gravity.CENTER);\n        renderUIView.setLayoutParams(lp);\n        addView(renderUIView);\n\n        mRenderView.addRenderCallback(mSHCallback);\n        mRenderView.setVideoRotation(mVideoRotationDegree);\n    }\n\n    public void setRender(int render) {\n        switch (render) {\n            case RENDER_NONE:\n                setRenderView(null);\n                break;\n            case RENDER_TEXTURE_VIEW: {\n                TextureRenderView renderView = new TextureRenderView(getContext());\n                if (mMediaPlayer != null) {\n                    renderView.getSurfaceHolder().bindToMediaPlayer(mMediaPlayer);\n                    renderView.setVideoSize(mMediaPlayer.getVideoWidth(), mMediaPlayer.getVideoHeight());\n                    renderView.setVideoSampleAspectRatio(mMediaPlayer.getVideoSarNum(), mMediaPlayer.getVideoSarDen());\n                    renderView.setAspectRatio(mCurrentAspectRatio);\n                }\n                setRenderView(renderView);\n                break;\n            }\n            case RENDER_SURFACE_VIEW: {\n                SurfaceRenderView renderView = new SurfaceRenderView(getContext());\n                setRenderView(renderView);\n                break;\n            }\n            default:\n                Log.e(TAG, String.format(Locale.getDefault(), \"invalid render %d\\n\", render));\n                break;\n        }\n    }\n\n    public void setHudView(TableLayout tableLayout) {\n        mHudViewHolder = new InfoHudViewHolder(getContext(), tableLayout);\n    }\n\n    /**\n     * Sets video path.\n     *\n     * @param path the path of the video.\n     */\n    public void setVideoPath(String path) {\n        if (path.contains(\"adaptationSet\")){\n            mManifestString = path;\n            setVideoURI(Uri.parse(\"ijklas:\"));\n        } else {\n            setVideoURI(Uri.parse(path));\n        }\n    }\n\n    /**\n     * Sets video URI.\n     *\n     * @param uri the URI of the video.\n     */\n    public void setVideoURI(Uri uri) {\n        setVideoURI(uri, null);\n    }\n\n    /**\n     * Sets video URI using specific headers.\n     *\n     * @param uri     the URI of the video.\n     * @param headers the headers for the URI request.\n     *                Note that the cross domain redirection is allowed by default, but that can be\n     *                changed with key/value pairs through the headers parameter with\n     *                \"android-allow-cross-domain-redirect\" as the key and \"0\" or \"1\" as the value\n     *                to disallow or allow cross domain redirection.\n     */\n    private void setVideoURI(Uri uri, Map<String, String> headers) {\n        mUri = uri;\n        mHeaders = headers;\n        mSeekWhenPrepared = 0;\n        openVideo();\n        requestLayout();\n        invalidate();\n    }\n\n    // REMOVED: addSubtitleSource\n    // REMOVED: mPendingSubtitleTracks\n\n    public void stopPlayback() {\n        if (mMediaPlayer != null) {\n            mMediaPlayer.stop();\n            mMediaPlayer.release();\n            mMediaPlayer = null;\n            if (mHudViewHolder != null)\n                mHudViewHolder.setMediaPlayer(null);\n            mCurrentState = STATE_IDLE;\n            mTargetState = STATE_IDLE;\n            AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE);\n            am.abandonAudioFocus(null);\n        }\n    }\n\n    @TargetApi(Build.VERSION_CODES.M)\n    private void openVideo() {\n        if (mUri == null || mSurfaceHolder == null) {\n            // not ready for playback just yet, will try again later\n            return;\n        }\n        // we shouldn't clear the target state, because somebody might have\n        // called start() previously\n        release(false);\n\n        AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE);\n        am.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);\n\n        try {\n            mMediaPlayer = createPlayer(mSettings.getPlayer());\n\n            // TODO: create SubtitleController in MediaPlayer, but we need\n            // a context for the subtitle renderers\n            final Context context = getContext();\n            // REMOVED: SubtitleController\n\n            // REMOVED: mAudioSession\n            mMediaPlayer.setOnPreparedListener(mPreparedListener);\n            mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);\n            mMediaPlayer.setOnCompletionListener(mCompletionListener);\n            mMediaPlayer.setOnErrorListener(mErrorListener);\n            mMediaPlayer.setOnInfoListener(mInfoListener);\n            mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);\n            mMediaPlayer.setOnSeekCompleteListener(mSeekCompleteListener);\n            mMediaPlayer.setOnTimedTextListener(mOnTimedTextListener);\n            mCurrentBufferPercentage = 0;\n            String scheme = mUri.getScheme();\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&\n                    mSettings.getUsingMediaDataSource() &&\n                    (TextUtils.isEmpty(scheme) || scheme.equalsIgnoreCase(\"file\"))) {\n                IMediaDataSource dataSource = new FileMediaDataSource(new File(mUri.toString()));\n                mMediaPlayer.setDataSource(dataSource);\n            }  else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {\n                mMediaPlayer.setDataSource(mAppContext, mUri, mHeaders);\n            } else {\n                mMediaPlayer.setDataSource(mUri.toString());\n            }\n            bindSurfaceHolder(mMediaPlayer, mSurfaceHolder);\n            mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);\n            mMediaPlayer.setScreenOnWhilePlaying(true);\n            mPrepareStartTime = System.currentTimeMillis();\n            mMediaPlayer.prepareAsync();\n            if (mHudViewHolder != null)\n                mHudViewHolder.setMediaPlayer(mMediaPlayer);\n\n            // REMOVED: mPendingSubtitleTracks\n\n            // we don't set the target state here either, but preserve the\n            // target state that was there before.\n            mCurrentState = STATE_PREPARING;\n            attachMediaController();\n        } catch (IOException ex) {\n            Log.w(TAG, \"Unable to open content: \" + mUri, ex);\n            mCurrentState = STATE_ERROR;\n            mTargetState = STATE_ERROR;\n            mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);\n        } catch (IllegalArgumentException ex) {\n            Log.w(TAG, \"Unable to open content: \" + mUri, ex);\n            mCurrentState = STATE_ERROR;\n            mTargetState = STATE_ERROR;\n            mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);\n        } finally {\n            // REMOVED: mPendingSubtitleTracks.clear();\n        }\n    }\n\n    public void setMediaController(IMediaController controller) {\n        if (mMediaController != null) {\n            mMediaController.hide();\n        }\n        mMediaController = controller;\n        attachMediaController();\n    }\n\n    private void attachMediaController() {\n        if (mMediaPlayer != null && mMediaController != null) {\n            mMediaController.setMediaPlayer(this);\n            View anchorView = this.getParent() instanceof View ?\n                    (View) this.getParent() : this;\n            mMediaController.setAnchorView(anchorView);\n            mMediaController.setEnabled(isInPlaybackState());\n        }\n    }\n\n    IMediaPlayer.OnVideoSizeChangedListener mSizeChangedListener =\n            new IMediaPlayer.OnVideoSizeChangedListener() {\n                public void onVideoSizeChanged(IMediaPlayer mp, int width, int height, int sarNum, int sarDen) {\n                    mVideoWidth = mp.getVideoWidth();\n                    mVideoHeight = mp.getVideoHeight();\n                    mVideoSarNum = mp.getVideoSarNum();\n                    mVideoSarDen = mp.getVideoSarDen();\n                    if (mVideoWidth != 0 && mVideoHeight != 0) {\n                        if (mRenderView != null) {\n                            mRenderView.setVideoSize(mVideoWidth, mVideoHeight);\n                            mRenderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);\n                        }\n                        // REMOVED: getHolder().setFixedSize(mVideoWidth, mVideoHeight);\n                        requestLayout();\n                    }\n                }\n            };\n\n    IMediaPlayer.OnPreparedListener mPreparedListener = new IMediaPlayer.OnPreparedListener() {\n        public void onPrepared(IMediaPlayer mp) {\n            mPrepareEndTime = System.currentTimeMillis();\n            mHudViewHolder.updateLoadCost(mPrepareEndTime - mPrepareStartTime);\n            mCurrentState = STATE_PREPARED;\n\n            // Get the capabilities of the player for this stream\n            // REMOVED: Metadata\n\n            if (mOnPreparedListener != null) {\n                mOnPreparedListener.onPrepared(mMediaPlayer);\n            }\n            if (mMediaController != null) {\n                mMediaController.setEnabled(true);\n            }\n            mVideoWidth = mp.getVideoWidth();\n            mVideoHeight = mp.getVideoHeight();\n\n            int seekToPosition = mSeekWhenPrepared;  // mSeekWhenPrepared may be changed after seekTo() call\n            if (seekToPosition != 0) {\n                seekTo(seekToPosition);\n            }\n            if (mVideoWidth != 0 && mVideoHeight != 0) {\n                //Log.i(\"@@@@\", \"video size: \" + mVideoWidth +\"/\"+ mVideoHeight);\n                // REMOVED: getHolder().setFixedSize(mVideoWidth, mVideoHeight);\n                if (mRenderView != null) {\n                    mRenderView.setVideoSize(mVideoWidth, mVideoHeight);\n                    mRenderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);\n                    if (!mRenderView.shouldWaitForResize() || mSurfaceWidth == mVideoWidth && mSurfaceHeight == mVideoHeight) {\n                        // We didn't actually change the size (it was already at the size\n                        // we need), so we won't get a \"surface changed\" callback, so\n                        // start the video here instead of in the callback.\n                        if (mTargetState == STATE_PLAYING) {\n                            start();\n                            if (mMediaController != null) {\n                                mMediaController.show();\n                            }\n                        } else if (!isPlaying() &&\n                                (seekToPosition != 0 || getCurrentPosition() > 0)) {\n                            if (mMediaController != null) {\n                                // Show the media controls when we're paused into a video and make 'em stick.\n                                mMediaController.show(0);\n                            }\n                        }\n                    }\n                }\n            } else {\n                // We don't know the video size yet, but should start anyway.\n                // The video size might be reported to us later.\n                if (mTargetState == STATE_PLAYING) {\n                    start();\n                }\n            }\n        }\n    };\n\n    private IMediaPlayer.OnCompletionListener mCompletionListener =\n            new IMediaPlayer.OnCompletionListener() {\n                public void onCompletion(IMediaPlayer mp) {\n                    mCurrentState = STATE_PLAYBACK_COMPLETED;\n                    mTargetState = STATE_PLAYBACK_COMPLETED;\n                    if (mMediaController != null) {\n                        mMediaController.hide();\n                    }\n                    if (mOnCompletionListener != null) {\n                        mOnCompletionListener.onCompletion(mMediaPlayer);\n                    }\n                }\n            };\n\n    private IMediaPlayer.OnInfoListener mInfoListener =\n            new IMediaPlayer.OnInfoListener() {\n                public boolean onInfo(IMediaPlayer mp, int arg1, int arg2) {\n                    if (mOnInfoListener != null) {\n                        mOnInfoListener.onInfo(mp, arg1, arg2);\n                    }\n                    switch (arg1) {\n                        case IMediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING:\n                            Log.d(TAG, \"MEDIA_INFO_VIDEO_TRACK_LAGGING:\");\n                            break;\n                        case IMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START:\n                            Log.d(TAG, \"MEDIA_INFO_VIDEO_RENDERING_START:\");\n                            break;\n                        case IMediaPlayer.MEDIA_INFO_BUFFERING_START:\n                            Log.d(TAG, \"MEDIA_INFO_BUFFERING_START:\");\n                            break;\n                        case IMediaPlayer.MEDIA_INFO_BUFFERING_END:\n                            Log.d(TAG, \"MEDIA_INFO_BUFFERING_END:\");\n                            break;\n                        case IMediaPlayer.MEDIA_INFO_NETWORK_BANDWIDTH:\n                            Log.d(TAG, \"MEDIA_INFO_NETWORK_BANDWIDTH: \" + arg2);\n                            break;\n                        case IMediaPlayer.MEDIA_INFO_BAD_INTERLEAVING:\n                            Log.d(TAG, \"MEDIA_INFO_BAD_INTERLEAVING:\");\n                            break;\n                        case IMediaPlayer.MEDIA_INFO_NOT_SEEKABLE:\n                            Log.d(TAG, \"MEDIA_INFO_NOT_SEEKABLE:\");\n                            break;\n                        case IMediaPlayer.MEDIA_INFO_METADATA_UPDATE:\n                            Log.d(TAG, \"MEDIA_INFO_METADATA_UPDATE:\");\n                            break;\n                        case IMediaPlayer.MEDIA_INFO_UNSUPPORTED_SUBTITLE:\n                            Log.d(TAG, \"MEDIA_INFO_UNSUPPORTED_SUBTITLE:\");\n                            break;\n                        case IMediaPlayer.MEDIA_INFO_SUBTITLE_TIMED_OUT:\n                            Log.d(TAG, \"MEDIA_INFO_SUBTITLE_TIMED_OUT:\");\n                            break;\n                        case IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED:\n                            mVideoRotationDegree = arg2;\n                            Log.d(TAG, \"MEDIA_INFO_VIDEO_ROTATION_CHANGED: \" + arg2);\n                            if (mRenderView != null)\n                                mRenderView.setVideoRotation(arg2);\n                            break;\n                        case IMediaPlayer.MEDIA_INFO_AUDIO_RENDERING_START:\n                            Log.d(TAG, \"MEDIA_INFO_AUDIO_RENDERING_START:\");\n                            break;\n                    }\n                    return true;\n                }\n            };\n\n    private IMediaPlayer.OnErrorListener mErrorListener =\n            new IMediaPlayer.OnErrorListener() {\n                public boolean onError(IMediaPlayer mp, int framework_err, int impl_err) {\n                    Log.d(TAG, \"Error: \" + framework_err + \",\" + impl_err);\n                    mCurrentState = STATE_ERROR;\n                    mTargetState = STATE_ERROR;\n                    if (mMediaController != null) {\n                        mMediaController.hide();\n                    }\n\n                    /* If an error handler has been supplied, use it and finish. */\n                    if (mOnErrorListener != null) {\n                        if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err)) {\n                            return true;\n                        }\n                    }\n\n                    /* Otherwise, pop up an error dialog so the user knows that\n                     * something bad has happened. Only try and pop up the dialog\n                     * if we're attached to a window. When we're going away and no\n                     * longer have a window, don't bother showing the user an error.\n                     */\n                    if (getWindowToken() != null) {\n                        Resources r = mAppContext.getResources();\n                        int messageId;\n\n                        if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) {\n                            messageId = R.string.VideoView_error_text_invalid_progressive_playback;\n                        } else {\n                            messageId = R.string.VideoView_error_text_unknown;\n                        }\n\n                        new AlertDialog.Builder(getContext())\n                                .setMessage(messageId)\n                                .setPositiveButton(R.string.VideoView_error_button,\n                                        new DialogInterface.OnClickListener() {\n                                            public void onClick(DialogInterface dialog, int whichButton) {\n                                            /* If we get here, there is no onError listener, so\n                                             * at least inform them that the video is over.\n                                             */\n                                                if (mOnCompletionListener != null) {\n                                                    mOnCompletionListener.onCompletion(mMediaPlayer);\n                                                }\n                                            }\n                                        })\n                                .setCancelable(false)\n                                .show();\n                    }\n                    return true;\n                }\n            };\n\n    private IMediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener =\n            new IMediaPlayer.OnBufferingUpdateListener() {\n                public void onBufferingUpdate(IMediaPlayer mp, int percent) {\n                    mCurrentBufferPercentage = percent;\n                }\n            };\n\n    private IMediaPlayer.OnSeekCompleteListener mSeekCompleteListener = new IMediaPlayer.OnSeekCompleteListener() {\n\n        @Override\n        public void onSeekComplete(IMediaPlayer mp) {\n            mSeekEndTime = System.currentTimeMillis();\n            mHudViewHolder.updateSeekCost(mSeekEndTime - mSeekStartTime);\n        }\n    };\n\n    private IMediaPlayer.OnTimedTextListener mOnTimedTextListener = new IMediaPlayer.OnTimedTextListener() {\n        @Override\n        public void onTimedText(IMediaPlayer mp, IjkTimedText text) {\n            if (text != null) {\n                subtitleDisplay.setText(text.getText());\n            }\n        }\n    };\n\n    /**\n     * Register a callback to be invoked when the media file\n     * is loaded and ready to go.\n     *\n     * @param l The callback that will be run\n     */\n    public void setOnPreparedListener(IMediaPlayer.OnPreparedListener l) {\n        mOnPreparedListener = l;\n    }\n\n    /**\n     * Register a callback to be invoked when the end of a media file\n     * has been reached during playback.\n     *\n     * @param l The callback that will be run\n     */\n    public void setOnCompletionListener(IMediaPlayer.OnCompletionListener l) {\n        mOnCompletionListener = l;\n    }\n\n    /**\n     * Register a callback to be invoked when an error occurs\n     * during playback or setup.  If no listener is specified,\n     * or if the listener returned false, VideoView will inform\n     * the user of any errors.\n     *\n     * @param l The callback that will be run\n     */\n    public void setOnErrorListener(IMediaPlayer.OnErrorListener l) {\n        mOnErrorListener = l;\n    }\n\n    /**\n     * Register a callback to be invoked when an informational event\n     * occurs during playback or setup.\n     *\n     * @param l The callback that will be run\n     */\n    public void setOnInfoListener(IMediaPlayer.OnInfoListener l) {\n        mOnInfoListener = l;\n    }\n\n    // REMOVED: mSHCallback\n    private void bindSurfaceHolder(IMediaPlayer mp, IRenderView.ISurfaceHolder holder) {\n        if (mp == null)\n            return;\n\n        if (holder == null) {\n            mp.setDisplay(null);\n            return;\n        }\n\n        holder.bindToMediaPlayer(mp);\n    }\n\n    IRenderView.IRenderCallback mSHCallback = new IRenderView.IRenderCallback() {\n        @Override\n        public void onSurfaceChanged(@NonNull IRenderView.ISurfaceHolder holder, int format, int w, int h) {\n            if (holder.getRenderView() != mRenderView) {\n                Log.e(TAG, \"onSurfaceChanged: unmatched render callback\\n\");\n                return;\n            }\n\n            mSurfaceWidth = w;\n            mSurfaceHeight = h;\n            boolean isValidState = (mTargetState == STATE_PLAYING);\n            boolean hasValidSize = !mRenderView.shouldWaitForResize() || (mVideoWidth == w && mVideoHeight == h);\n            if (mMediaPlayer != null && isValidState && hasValidSize) {\n                if (mSeekWhenPrepared != 0) {\n                    seekTo(mSeekWhenPrepared);\n                }\n                start();\n            }\n        }\n\n        @Override\n        public void onSurfaceCreated(@NonNull IRenderView.ISurfaceHolder holder, int width, int height) {\n            if (holder.getRenderView() != mRenderView) {\n                Log.e(TAG, \"onSurfaceCreated: unmatched render callback\\n\");\n                return;\n            }\n\n            mSurfaceHolder = holder;\n            if (mMediaPlayer != null)\n                bindSurfaceHolder(mMediaPlayer, holder);\n            else\n                openVideo();\n        }\n\n        @Override\n        public void onSurfaceDestroyed(@NonNull IRenderView.ISurfaceHolder holder) {\n            if (holder.getRenderView() != mRenderView) {\n                Log.e(TAG, \"onSurfaceDestroyed: unmatched render callback\\n\");\n                return;\n            }\n\n            // after we return from this we can't use the surface any more\n            mSurfaceHolder = null;\n            // REMOVED: if (mMediaController != null) mMediaController.hide();\n            // REMOVED: release(true);\n            releaseWithoutStop();\n        }\n    };\n\n    public void releaseWithoutStop() {\n        if (mMediaPlayer != null)\n            mMediaPlayer.setDisplay(null);\n    }\n\n    /*\n     * release the media player in any state\n     */\n    public void release(boolean cleartargetstate) {\n        if (mMediaPlayer != null) {\n            mMediaPlayer.reset();\n            mMediaPlayer.release();\n            mMediaPlayer = null;\n            // REMOVED: mPendingSubtitleTracks.clear();\n            mCurrentState = STATE_IDLE;\n            if (cleartargetstate) {\n                mTargetState = STATE_IDLE;\n            }\n            AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE);\n            am.abandonAudioFocus(null);\n        }\n    }\n\n    @Override\n    public boolean onTouchEvent(MotionEvent ev) {\n        if (isInPlaybackState() && mMediaController != null) {\n            toggleMediaControlsVisiblity();\n        }\n        return false;\n    }\n\n    @Override\n    public boolean onTrackballEvent(MotionEvent ev) {\n        if (isInPlaybackState() && mMediaController != null) {\n            toggleMediaControlsVisiblity();\n        }\n        return false;\n    }\n\n    @Override\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        boolean isKeyCodeSupported = keyCode != KeyEvent.KEYCODE_BACK &&\n                keyCode != KeyEvent.KEYCODE_VOLUME_UP &&\n                keyCode != KeyEvent.KEYCODE_VOLUME_DOWN &&\n                keyCode != KeyEvent.KEYCODE_VOLUME_MUTE &&\n                keyCode != KeyEvent.KEYCODE_MENU &&\n                keyCode != KeyEvent.KEYCODE_CALL &&\n                keyCode != KeyEvent.KEYCODE_ENDCALL;\n        if (isInPlaybackState() && isKeyCodeSupported && mMediaController != null) {\n            if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK ||\n                    keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {\n                if (mMediaPlayer.isPlaying()) {\n                    pause();\n                    mMediaController.show();\n                } else {\n                    start();\n                    mMediaController.hide();\n                }\n                return true;\n            } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) {\n                if (!mMediaPlayer.isPlaying()) {\n                    start();\n                    mMediaController.hide();\n                }\n                return true;\n            } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP\n                    || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) {\n                if (mMediaPlayer.isPlaying()) {\n                    pause();\n                    mMediaController.show();\n                }\n                return true;\n            } else {\n                toggleMediaControlsVisiblity();\n            }\n        }\n\n        return super.onKeyDown(keyCode, event);\n    }\n\n    private void toggleMediaControlsVisiblity() {\n        if (mMediaController.isShowing()) {\n            mMediaController.hide();\n        } else {\n            mMediaController.show();\n        }\n    }\n\n    @Override\n    public void start() {\n        if (isInPlaybackState()) {\n            mMediaPlayer.start();\n            mCurrentState = STATE_PLAYING;\n        }\n        mTargetState = STATE_PLAYING;\n    }\n\n    @Override\n    public void pause() {\n        if (isInPlaybackState()) {\n            if (mMediaPlayer.isPlaying()) {\n                mMediaPlayer.pause();\n                mCurrentState = STATE_PAUSED;\n            }\n        }\n        mTargetState = STATE_PAUSED;\n    }\n\n    public void suspend() {\n        release(false);\n    }\n\n    public void resume() {\n        openVideo();\n    }\n\n    @Override\n    public int getDuration() {\n        if (isInPlaybackState()) {\n            return (int) mMediaPlayer.getDuration();\n        }\n\n        return -1;\n    }\n\n    @Override\n    public int getCurrentPosition() {\n        if (isInPlaybackState()) {\n            return (int) mMediaPlayer.getCurrentPosition();\n        }\n        return 0;\n    }\n\n    @Override\n    public void seekTo(int msec) {\n        if (isInPlaybackState()) {\n            mSeekStartTime = System.currentTimeMillis();\n            mMediaPlayer.seekTo(msec);\n            mSeekWhenPrepared = 0;\n        } else {\n            mSeekWhenPrepared = msec;\n        }\n    }\n\n    @Override\n    public boolean isPlaying() {\n        return isInPlaybackState() && mMediaPlayer.isPlaying();\n    }\n\n    @Override\n    public int getBufferPercentage() {\n        if (mMediaPlayer != null) {\n            return mCurrentBufferPercentage;\n        }\n        return 0;\n    }\n\n    private boolean isInPlaybackState() {\n        return (mMediaPlayer != null &&\n                mCurrentState != STATE_ERROR &&\n                mCurrentState != STATE_IDLE &&\n                mCurrentState != STATE_PREPARING);\n    }\n\n    @Override\n    public boolean canPause() {\n        return mCanPause;\n    }\n\n    @Override\n    public boolean canSeekBackward() {\n        return mCanSeekBack;\n    }\n\n    @Override\n    public boolean canSeekForward() {\n        return mCanSeekForward;\n    }\n\n    @Override\n    public int getAudioSessionId() {\n        return 0;\n    }\n\n    // REMOVED: getAudioSessionId();\n    // REMOVED: onAttachedToWindow();\n    // REMOVED: onDetachedFromWindow();\n    // REMOVED: onLayout();\n    // REMOVED: draw();\n    // REMOVED: measureAndLayoutSubtitleWidget();\n    // REMOVED: setSubtitleWidget();\n    // REMOVED: getSubtitleLooper();\n\n    //-------------------------\n    // Extend: Aspect Ratio\n    //-------------------------\n\n    private static final int[] s_allAspectRatio = {\n            IRenderView.AR_ASPECT_FIT_PARENT,\n            IRenderView.AR_ASPECT_FILL_PARENT,\n            IRenderView.AR_ASPECT_WRAP_CONTENT,\n            // IRenderView.AR_MATCH_PARENT,\n            IRenderView.AR_16_9_FIT_PARENT,\n            IRenderView.AR_4_3_FIT_PARENT};\n    private int mCurrentAspectRatioIndex = 0;\n    private int mCurrentAspectRatio = s_allAspectRatio[0];\n\n    public int toggleAspectRatio() {\n        mCurrentAspectRatioIndex++;\n        mCurrentAspectRatioIndex %= s_allAspectRatio.length;\n\n        mCurrentAspectRatio = s_allAspectRatio[mCurrentAspectRatioIndex];\n        if (mRenderView != null)\n            mRenderView.setAspectRatio(mCurrentAspectRatio);\n        return mCurrentAspectRatio;\n    }\n\n    //-------------------------\n    // Extend: Render\n    //-------------------------\n    public static final int RENDER_NONE = 0;\n    public static final int RENDER_SURFACE_VIEW = 1;\n    public static final int RENDER_TEXTURE_VIEW = 2;\n\n    private List<Integer> mAllRenders = new ArrayList<Integer>();\n    private int mCurrentRenderIndex = 0;\n    private int mCurrentRender = RENDER_NONE;\n\n    private void initRenders() {\n        mAllRenders.clear();\n\n        if (mSettings.getEnableSurfaceView())\n            mAllRenders.add(RENDER_SURFACE_VIEW);\n        if (mSettings.getEnableTextureView() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)\n            mAllRenders.add(RENDER_TEXTURE_VIEW);\n        if (mSettings.getEnableNoView())\n            mAllRenders.add(RENDER_NONE);\n\n        if (mAllRenders.isEmpty())\n            mAllRenders.add(RENDER_SURFACE_VIEW);\n        mCurrentRender = mAllRenders.get(mCurrentRenderIndex);\n        setRender(mCurrentRender);\n    }\n\n    public int toggleRender() {\n        mCurrentRenderIndex++;\n        mCurrentRenderIndex %= mAllRenders.size();\n\n        mCurrentRender = mAllRenders.get(mCurrentRenderIndex);\n        setRender(mCurrentRender);\n        return mCurrentRender;\n    }\n\n    @NonNull\n    public static String getRenderText(Context context, int render) {\n        String text;\n        switch (render) {\n            case RENDER_NONE:\n                text = context.getString(R.string.VideoView_render_none);\n                break;\n            case RENDER_SURFACE_VIEW:\n                text = context.getString(R.string.VideoView_render_surface_view);\n                break;\n            case RENDER_TEXTURE_VIEW:\n                text = context.getString(R.string.VideoView_render_texture_view);\n                break;\n            default:\n                text = context.getString(R.string.N_A);\n                break;\n        }\n        return text;\n    }\n\n    //-------------------------\n    // Extend: Player\n    //-------------------------\n    public int togglePlayer() {\n        if (mMediaPlayer != null)\n            mMediaPlayer.release();\n\n        if (mRenderView != null)\n            mRenderView.getView().invalidate();\n        openVideo();\n        return mSettings.getPlayer();\n    }\n\n    @NonNull\n    public static String getPlayerText(Context context, int player) {\n        String text;\n        switch (player) {\n            case Settings.PV_PLAYER__AndroidMediaPlayer:\n                text = context.getString(R.string.VideoView_player_AndroidMediaPlayer);\n                break;\n            case Settings.PV_PLAYER__IjkMediaPlayer:\n                text = context.getString(R.string.VideoView_player_IjkMediaPlayer);\n                break;\n            case Settings.PV_PLAYER__IjkExoMediaPlayer:\n                text = context.getString(R.string.VideoView_player_IjkExoMediaPlayer);\n                break;\n            default:\n                text = context.getString(R.string.N_A);\n                break;\n        }\n        return text;\n    }\n\n    public IMediaPlayer createPlayer(int playerType) {\n        IMediaPlayer mediaPlayer = null;\n\n        switch (playerType) {\n            case Settings.PV_PLAYER__IjkExoMediaPlayer: {\n                IjkExoMediaPlayer IjkExoMediaPlayer = new IjkExoMediaPlayer(mAppContext);\n                mediaPlayer = IjkExoMediaPlayer;\n            }\n            break;\n            case Settings.PV_PLAYER__AndroidMediaPlayer: {\n                AndroidMediaPlayer androidMediaPlayer = new AndroidMediaPlayer();\n                mediaPlayer = androidMediaPlayer;\n            }\n            break;\n            case Settings.PV_PLAYER__IjkMediaPlayer:\n            default: {\n                IjkMediaPlayer ijkMediaPlayer = null;\n                if (mUri != null) {\n                    ijkMediaPlayer = new IjkMediaPlayer();\n                    ijkMediaPlayer.native_setLogLevel(IjkMediaPlayer.IJK_LOG_DEBUG);\n\n                    if (mManifestString != null) {\n                        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, \"iformat\", \"ijklas\");\n                        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, \"find_stream_info\", 0);\n                        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, \"manifest_string\", mManifestString);\n                    }\n                    if (mSettings.getUsingMediaCodec()) {\n                        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, \"mediacodec\", 1);\n                        if (mSettings.getUsingMediaCodecAutoRotate()) {\n                            ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, \"mediacodec-auto-rotate\", 1);\n                        } else {\n                            ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, \"mediacodec-auto-rotate\", 0);\n                        }\n                        if (mSettings.getMediaCodecHandleResolutionChange()) {\n                            ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, \"mediacodec-handle-resolution-change\", 1);\n                        } else {\n                            ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, \"mediacodec-handle-resolution-change\", 0);\n                        }\n                    } else {\n                        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, \"mediacodec\", 0);\n                    }\n\n                    if (mSettings.getUsingOpenSLES()) {\n                        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, \"opensles\", 1);\n                    } else {\n                        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, \"opensles\", 0);\n                    }\n\n                    String pixelFormat = mSettings.getPixelFormat();\n                    if (TextUtils.isEmpty(pixelFormat)) {\n                        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, \"overlay-format\", IjkMediaPlayer.SDL_FCC_RV32);\n                    } else {\n                        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, \"overlay-format\", pixelFormat);\n                    }\n                    ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, \"framedrop\", 1);\n                    ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, \"start-on-prepared\", 0);\n\n                    ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, \"http-detect-range-support\", 0);\n\n                    ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, \"skip_loop_filter\", 48);\n                }\n                mediaPlayer = ijkMediaPlayer;\n            }\n            break;\n        }\n\n        if (mSettings.getEnableDetachedSurfaceTextureView()) {\n            mediaPlayer = new TextureMediaPlayer(mediaPlayer);\n        }\n\n        return mediaPlayer;\n    }\n\n    //-------------------------\n    // Extend: Background\n    //-------------------------\n\n    private boolean mEnableBackgroundPlay = false;\n\n    private void initBackground() {\n        mEnableBackgroundPlay = mSettings.getEnableBackgroundPlay();\n        if (mEnableBackgroundPlay) {\n            MediaPlayerService.intentToStart(getContext());\n            mMediaPlayer = MediaPlayerService.getMediaPlayer();\n            if (mHudViewHolder != null)\n                mHudViewHolder.setMediaPlayer(mMediaPlayer);\n        }\n    }\n\n    public boolean isBackgroundPlayEnabled() {\n        return mEnableBackgroundPlay;\n    }\n\n    public void enterBackground() {\n        MediaPlayerService.setMediaPlayer(mMediaPlayer);\n    }\n\n    public void stopBackgroundPlay() {\n        MediaPlayerService.setMediaPlayer(null);\n    }\n\n    //-------------------------\n    // Extend: Background\n    //-------------------------\n    public void showMediaInfo() {\n        if (mMediaPlayer == null)\n            return;\n\n        int selectedVideoTrack = MediaPlayerCompat.getSelectedTrack(mMediaPlayer, ITrackInfo.MEDIA_TRACK_TYPE_VIDEO);\n        int selectedAudioTrack = MediaPlayerCompat.getSelectedTrack(mMediaPlayer, ITrackInfo.MEDIA_TRACK_TYPE_AUDIO);\n        int selectedSubtitleTrack = MediaPlayerCompat.getSelectedTrack(mMediaPlayer, ITrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT);\n\n        TableLayoutBinder builder = new TableLayoutBinder(getContext());\n        builder.appendSection(R.string.mi_player);\n        builder.appendRow2(R.string.mi_player, MediaPlayerCompat.getName(mMediaPlayer));\n        builder.appendSection(R.string.mi_media);\n        builder.appendRow2(R.string.mi_resolution, buildResolution(mVideoWidth, mVideoHeight, mVideoSarNum, mVideoSarDen));\n        builder.appendRow2(R.string.mi_length, buildTimeMilli(mMediaPlayer.getDuration()));\n\n        ITrackInfo trackInfos[] = mMediaPlayer.getTrackInfo();\n        if (trackInfos != null) {\n            int index = -1;\n            for (ITrackInfo trackInfo : trackInfos) {\n                index++;\n\n                int trackType = trackInfo.getTrackType();\n                if (index == selectedVideoTrack) {\n                    builder.appendSection(getContext().getString(R.string.mi_stream_fmt1, index) + \" \" + getContext().getString(R.string.mi__selected_video_track));\n                } else if (index == selectedAudioTrack) {\n                    builder.appendSection(getContext().getString(R.string.mi_stream_fmt1, index) + \" \" + getContext().getString(R.string.mi__selected_audio_track));\n                } else if (index == selectedSubtitleTrack) {\n                    builder.appendSection(getContext().getString(R.string.mi_stream_fmt1, index) + \" \" + getContext().getString(R.string.mi__selected_subtitle_track));\n                } else {\n                    builder.appendSection(getContext().getString(R.string.mi_stream_fmt1, index));\n                }\n                builder.appendRow2(R.string.mi_type, buildTrackType(trackType));\n                builder.appendRow2(R.string.mi_language, buildLanguage(trackInfo.getLanguage()));\n\n                IMediaFormat mediaFormat = trackInfo.getFormat();\n                if (mediaFormat == null) {\n                } else if (mediaFormat instanceof IjkMediaFormat) {\n                    switch (trackType) {\n                        case ITrackInfo.MEDIA_TRACK_TYPE_VIDEO:\n                            builder.appendRow2(R.string.mi_codec, mediaFormat.getString(IjkMediaFormat.KEY_IJK_CODEC_LONG_NAME_UI));\n                            builder.appendRow2(R.string.mi_profile_level, mediaFormat.getString(IjkMediaFormat.KEY_IJK_CODEC_PROFILE_LEVEL_UI));\n                            builder.appendRow2(R.string.mi_pixel_format, mediaFormat.getString(IjkMediaFormat.KEY_IJK_CODEC_PIXEL_FORMAT_UI));\n                            builder.appendRow2(R.string.mi_resolution, mediaFormat.getString(IjkMediaFormat.KEY_IJK_RESOLUTION_UI));\n                            builder.appendRow2(R.string.mi_frame_rate, mediaFormat.getString(IjkMediaFormat.KEY_IJK_FRAME_RATE_UI));\n                            builder.appendRow2(R.string.mi_bit_rate, mediaFormat.getString(IjkMediaFormat.KEY_IJK_BIT_RATE_UI));\n                            break;\n                        case ITrackInfo.MEDIA_TRACK_TYPE_AUDIO:\n                            builder.appendRow2(R.string.mi_codec, mediaFormat.getString(IjkMediaFormat.KEY_IJK_CODEC_LONG_NAME_UI));\n                            builder.appendRow2(R.string.mi_profile_level, mediaFormat.getString(IjkMediaFormat.KEY_IJK_CODEC_PROFILE_LEVEL_UI));\n                            builder.appendRow2(R.string.mi_sample_rate, mediaFormat.getString(IjkMediaFormat.KEY_IJK_SAMPLE_RATE_UI));\n                            builder.appendRow2(R.string.mi_channels, mediaFormat.getString(IjkMediaFormat.KEY_IJK_CHANNEL_UI));\n                            builder.appendRow2(R.string.mi_bit_rate, mediaFormat.getString(IjkMediaFormat.KEY_IJK_BIT_RATE_UI));\n                            break;\n                        default:\n                            break;\n                    }\n                }\n            }\n        }\n\n        AlertDialog.Builder adBuilder = builder.buildAlertDialogBuilder();\n        adBuilder.setTitle(R.string.media_information);\n        adBuilder.setNegativeButton(R.string.close, null);\n        adBuilder.show();\n    }\n\n    private String buildResolution(int width, int height, int sarNum, int sarDen) {\n        StringBuilder sb = new StringBuilder();\n        sb.append(width);\n        sb.append(\" x \");\n        sb.append(height);\n\n        if (sarNum > 1 || sarDen > 1) {\n            sb.append(\"[\");\n            sb.append(sarNum);\n            sb.append(\":\");\n            sb.append(sarDen);\n            sb.append(\"]\");\n        }\n\n        return sb.toString();\n    }\n\n    private String buildTimeMilli(long duration) {\n        long total_seconds = duration / 1000;\n        long hours = total_seconds / 3600;\n        long minutes = (total_seconds % 3600) / 60;\n        long seconds = total_seconds % 60;\n        if (duration <= 0) {\n            return \"--:--\";\n        }\n        if (hours >= 100) {\n            return String.format(Locale.US, \"%d:%02d:%02d\", hours, minutes, seconds);\n        } else if (hours > 0) {\n            return String.format(Locale.US, \"%02d:%02d:%02d\", hours, minutes, seconds);\n        } else {\n            return String.format(Locale.US, \"%02d:%02d\", minutes, seconds);\n        }\n    }\n\n    private String buildTrackType(int type) {\n        Context context = getContext();\n        switch (type) {\n            case ITrackInfo.MEDIA_TRACK_TYPE_VIDEO:\n                return context.getString(R.string.TrackType_video);\n            case ITrackInfo.MEDIA_TRACK_TYPE_AUDIO:\n                return context.getString(R.string.TrackType_audio);\n            case ITrackInfo.MEDIA_TRACK_TYPE_SUBTITLE:\n                return context.getString(R.string.TrackType_subtitle);\n            case ITrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT:\n                return context.getString(R.string.TrackType_timedtext);\n            case ITrackInfo.MEDIA_TRACK_TYPE_METADATA:\n                return context.getString(R.string.TrackType_metadata);\n            case ITrackInfo.MEDIA_TRACK_TYPE_UNKNOWN:\n            default:\n                return context.getString(R.string.TrackType_unknown);\n        }\n    }\n\n    private String buildLanguage(String language) {\n        if (TextUtils.isEmpty(language))\n            return \"und\";\n        return language;\n    }\n\n    public ITrackInfo[] getTrackInfo() {\n        if (mMediaPlayer == null)\n            return null;\n\n        return mMediaPlayer.getTrackInfo();\n    }\n\n    public void selectTrack(int stream) {\n        MediaPlayerCompat.selectTrack(mMediaPlayer, stream);\n    }\n\n    public void deselectTrack(int stream) {\n        MediaPlayerCompat.deselectTrack(mMediaPlayer, stream);\n    }\n\n    public int getSelectedTrack(int trackType) {\n        return MediaPlayerCompat.getSelectedTrack(mMediaPlayer, trackType);\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/media/InfoHudViewHolder.java",
    "content": "package tv.danmaku.ijk.media.example.widget.media;\n\nimport android.content.Context;\nimport android.os.Handler;\nimport android.os.Message;\nimport android.util.SparseArray;\nimport android.view.View;\nimport android.widget.TableLayout;\n\nimport java.util.Locale;\n\nimport tv.danmaku.ijk.media.player.IMediaPlayer;\nimport tv.danmaku.ijk.media.player.IjkMediaPlayer;\nimport tv.danmaku.ijk.media.player.MediaPlayerProxy;\nimport tv.danmaku.ijk.media.example.R;\n\npublic class InfoHudViewHolder {\n    private TableLayoutBinder mTableLayoutBinder;\n    private SparseArray<View> mRowMap = new SparseArray<View>();\n    private IMediaPlayer mMediaPlayer;\n    private long mLoadCost = 0;\n    private long mSeekCost = 0;\n\n    public InfoHudViewHolder(Context context, TableLayout tableLayout) {\n        mTableLayoutBinder = new TableLayoutBinder(context, tableLayout);\n    }\n\n    private void appendSection(int nameId) {\n        mTableLayoutBinder.appendSection(nameId);\n    }\n\n    private void appendRow(int nameId) {\n        View rowView = mTableLayoutBinder.appendRow2(nameId, null);\n        mRowMap.put(nameId, rowView);\n    }\n\n    private void setRowValue(int id, String value) {\n        View rowView = mRowMap.get(id);\n        if (rowView == null) {\n            rowView = mTableLayoutBinder.appendRow2(id, value);\n            mRowMap.put(id, rowView);\n        } else {\n            mTableLayoutBinder.setValueText(rowView, value);\n        }\n    }\n\n    public void setMediaPlayer(IMediaPlayer mp) {\n        mMediaPlayer = mp;\n        if (mMediaPlayer != null) {\n            mHandler.sendEmptyMessageDelayed(MSG_UPDATE_HUD, 500);\n        } else {\n            mHandler.removeMessages(MSG_UPDATE_HUD);\n        }\n    }\n\n    private static String formatedDurationMilli(long duration) {\n        if (duration >=  1000) {\n            return String.format(Locale.US, \"%.2f sec\", ((float)duration) / 1000);\n        } else {\n            return String.format(Locale.US, \"%d msec\", duration);\n        }\n    }\n\n    private static String formatedSpeed(long bytes,long elapsed_milli) {\n        if (elapsed_milli <= 0) {\n            return \"0 B/s\";\n        }\n\n        if (bytes <= 0) {\n            return \"0 B/s\";\n        }\n\n        float bytes_per_sec = ((float)bytes) * 1000.f /  elapsed_milli;\n        if (bytes_per_sec >= 1000 * 1000) {\n            return String.format(Locale.US, \"%.2f MB/s\", ((float)bytes_per_sec) / 1000 / 1000);\n        } else if (bytes_per_sec >= 1000) {\n            return String.format(Locale.US, \"%.1f KB/s\", ((float)bytes_per_sec) / 1000);\n        } else {\n            return String.format(Locale.US, \"%d B/s\", (long)bytes_per_sec);\n        }\n    }\n\n    public void updateLoadCost(long time)  {\n        mLoadCost = time;\n    }\n\n    public void updateSeekCost(long time)  {\n        mSeekCost = time;\n    }\n\n    private static String formatedSize(long bytes) {\n        if (bytes >= 100 * 1000) {\n            return String.format(Locale.US, \"%.2f MB\", ((float)bytes) / 1000 / 1000);\n        } else if (bytes >= 100) {\n            return String.format(Locale.US, \"%.1f KB\", ((float)bytes) / 1000);\n        } else {\n            return String.format(Locale.US, \"%d B\", bytes);\n        }\n    }\n\n    private static final int MSG_UPDATE_HUD = 1;\n    private Handler mHandler = new Handler() {\n        @Override\n        public void handleMessage(Message msg) {\n            switch (msg.what) {\n                case MSG_UPDATE_HUD: {\n                    InfoHudViewHolder holder = InfoHudViewHolder.this;\n                    IjkMediaPlayer mp = null;\n                    if (mMediaPlayer == null)\n                        break;\n                    if (mMediaPlayer instanceof IjkMediaPlayer) {\n                        mp = (IjkMediaPlayer) mMediaPlayer;\n                    } else if (mMediaPlayer instanceof MediaPlayerProxy) {\n                        MediaPlayerProxy proxy = (MediaPlayerProxy) mMediaPlayer;\n                        IMediaPlayer internal = proxy.getInternalMediaPlayer();\n                        if (internal != null && internal instanceof IjkMediaPlayer)\n                            mp = (IjkMediaPlayer) internal;\n                    }\n                    if (mp == null)\n                        break;\n\n                    int vdec = mp.getVideoDecoder();\n                    switch (vdec) {\n                        case IjkMediaPlayer.FFP_PROPV_DECODER_AVCODEC:\n                            setRowValue(R.string.vdec, \"avcodec\");\n                            break;\n                        case IjkMediaPlayer.FFP_PROPV_DECODER_MEDIACODEC:\n                            setRowValue(R.string.vdec, \"MediaCodec\");\n                            break;\n                        default:\n                            setRowValue(R.string.vdec, \"\");\n                            break;\n                    }\n\n                    float fpsOutput = mp.getVideoOutputFramesPerSecond();\n                    float fpsDecode = mp.getVideoDecodeFramesPerSecond();\n                    setRowValue(R.string.fps, String.format(Locale.US, \"%.2f / %.2f\", fpsDecode, fpsOutput));\n\n                    long videoCachedDuration = mp.getVideoCachedDuration();\n                    long audioCachedDuration = mp.getAudioCachedDuration();\n                    long videoCachedBytes    = mp.getVideoCachedBytes();\n                    long audioCachedBytes    = mp.getAudioCachedBytes();\n                    long tcpSpeed            = mp.getTcpSpeed();\n                    long bitRate             = mp.getBitRate();\n                    long seekLoadDuration    = mp.getSeekLoadDuration();\n\n                    setRowValue(R.string.v_cache, String.format(Locale.US, \"%s, %s\", formatedDurationMilli(videoCachedDuration), formatedSize(videoCachedBytes)));\n                    setRowValue(R.string.a_cache, String.format(Locale.US, \"%s, %s\", formatedDurationMilli(audioCachedDuration), formatedSize(audioCachedBytes)));\n                    setRowValue(R.string.load_cost, String.format(Locale.US, \"%d ms\", mLoadCost));\n                    setRowValue(R.string.seek_cost, String.format(Locale.US, \"%d ms\", mSeekCost));\n                    setRowValue(R.string.seek_load_cost, String.format(Locale.US, \"%d ms\", seekLoadDuration));\n                    setRowValue(R.string.tcp_speed, String.format(Locale.US, \"%s\", formatedSpeed(tcpSpeed, 1000)));\n                    setRowValue(R.string.bit_rate, String.format(Locale.US, \"%.2f kbs\", bitRate/1000f));\n\n                    mHandler.removeMessages(MSG_UPDATE_HUD);\n                    mHandler.sendEmptyMessageDelayed(MSG_UPDATE_HUD, 500);\n                }\n            }\n        }\n    };\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/media/MeasureHelper.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.widget.media;\n\nimport android.content.Context;\nimport android.support.annotation.NonNull;\nimport android.view.View;\n\nimport java.lang.ref.WeakReference;\n\nimport tv.danmaku.ijk.media.example.R;\n\npublic final class MeasureHelper {\n    private WeakReference<View> mWeakView;\n\n    private int mVideoWidth;\n    private int mVideoHeight;\n    private int mVideoSarNum;\n    private int mVideoSarDen;\n\n    private int mVideoRotationDegree;\n\n    private int mMeasuredWidth;\n    private int mMeasuredHeight;\n\n    private int mCurrentAspectRatio = IRenderView.AR_ASPECT_FIT_PARENT;\n\n    public MeasureHelper(View view) {\n        mWeakView = new WeakReference<View>(view);\n    }\n\n    public View getView() {\n        if (mWeakView == null)\n            return null;\n        return mWeakView.get();\n    }\n\n    public void setVideoSize(int videoWidth, int videoHeight) {\n        mVideoWidth = videoWidth;\n        mVideoHeight = videoHeight;\n    }\n\n    public void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen) {\n        mVideoSarNum = videoSarNum;\n        mVideoSarDen = videoSarDen;\n    }\n\n    public void setVideoRotation(int videoRotationDegree) {\n        mVideoRotationDegree = videoRotationDegree;\n    }\n\n    /**\n     * Must be called by View.onMeasure(int, int)\n     *\n     * @param widthMeasureSpec\n     * @param heightMeasureSpec\n     */\n    public void doMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        //Log.i(\"@@@@\", \"onMeasure(\" + MeasureSpec.toString(widthMeasureSpec) + \", \"\n        //        + MeasureSpec.toString(heightMeasureSpec) + \")\");\n        if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270) {\n            int tempSpec = widthMeasureSpec;\n            widthMeasureSpec  = heightMeasureSpec;\n            heightMeasureSpec = tempSpec;\n        }\n\n        int width = View.getDefaultSize(mVideoWidth, widthMeasureSpec);\n        int height = View.getDefaultSize(mVideoHeight, heightMeasureSpec);\n        if (mCurrentAspectRatio == IRenderView.AR_MATCH_PARENT) {\n            width = widthMeasureSpec;\n            height = heightMeasureSpec;\n        } else if (mVideoWidth > 0 && mVideoHeight > 0) {\n            int widthSpecMode = View.MeasureSpec.getMode(widthMeasureSpec);\n            int widthSpecSize = View.MeasureSpec.getSize(widthMeasureSpec);\n            int heightSpecMode = View.MeasureSpec.getMode(heightMeasureSpec);\n            int heightSpecSize = View.MeasureSpec.getSize(heightMeasureSpec);\n\n            if (widthSpecMode == View.MeasureSpec.AT_MOST && heightSpecMode == View.MeasureSpec.AT_MOST) {\n                float specAspectRatio = (float) widthSpecSize / (float) heightSpecSize;\n                float displayAspectRatio;\n                switch (mCurrentAspectRatio) {\n                    case IRenderView.AR_16_9_FIT_PARENT:\n                        displayAspectRatio = 16.0f / 9.0f;\n                        if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270)\n                            displayAspectRatio = 1.0f / displayAspectRatio;\n                        break;\n                    case IRenderView.AR_4_3_FIT_PARENT:\n                        displayAspectRatio = 4.0f / 3.0f;\n                        if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270)\n                            displayAspectRatio = 1.0f / displayAspectRatio;\n                        break;\n                    case IRenderView.AR_ASPECT_FIT_PARENT:\n                    case IRenderView.AR_ASPECT_FILL_PARENT:\n                    case IRenderView.AR_ASPECT_WRAP_CONTENT:\n                    default:\n                        displayAspectRatio = (float) mVideoWidth / (float) mVideoHeight;\n                        if (mVideoSarNum > 0 && mVideoSarDen > 0)\n                            displayAspectRatio = displayAspectRatio * mVideoSarNum / mVideoSarDen;\n                        break;\n                }\n                boolean shouldBeWider = displayAspectRatio > specAspectRatio;\n\n                switch (mCurrentAspectRatio) {\n                    case IRenderView.AR_ASPECT_FIT_PARENT:\n                    case IRenderView.AR_16_9_FIT_PARENT:\n                    case IRenderView.AR_4_3_FIT_PARENT:\n                        if (shouldBeWider) {\n                            // too wide, fix width\n                            width = widthSpecSize;\n                            height = (int) (width / displayAspectRatio);\n                        } else {\n                            // too high, fix height\n                            height = heightSpecSize;\n                            width = (int) (height * displayAspectRatio);\n                        }\n                        break;\n                    case IRenderView.AR_ASPECT_FILL_PARENT:\n                        if (shouldBeWider) {\n                            // not high enough, fix height\n                            height = heightSpecSize;\n                            width = (int) (height * displayAspectRatio);\n                        } else {\n                            // not wide enough, fix width\n                            width = widthSpecSize;\n                            height = (int) (width / displayAspectRatio);\n                        }\n                        break;\n                    case IRenderView.AR_ASPECT_WRAP_CONTENT:\n                    default:\n                        if (shouldBeWider) {\n                            // too wide, fix width\n                            width = Math.min(mVideoWidth, widthSpecSize);\n                            height = (int) (width / displayAspectRatio);\n                        } else {\n                            // too high, fix height\n                            height = Math.min(mVideoHeight, heightSpecSize);\n                            width = (int) (height * displayAspectRatio);\n                        }\n                        break;\n                }\n            } else if (widthSpecMode == View.MeasureSpec.EXACTLY && heightSpecMode == View.MeasureSpec.EXACTLY) {\n                // the size is fixed\n                width = widthSpecSize;\n                height = heightSpecSize;\n\n                // for compatibility, we adjust size based on aspect ratio\n                if (mVideoWidth * height < width * mVideoHeight) {\n                    //Log.i(\"@@@\", \"image too wide, correcting\");\n                    width = height * mVideoWidth / mVideoHeight;\n                } else if (mVideoWidth * height > width * mVideoHeight) {\n                    //Log.i(\"@@@\", \"image too tall, correcting\");\n                    height = width * mVideoHeight / mVideoWidth;\n                }\n            } else if (widthSpecMode == View.MeasureSpec.EXACTLY) {\n                // only the width is fixed, adjust the height to match aspect ratio if possible\n                width = widthSpecSize;\n                height = width * mVideoHeight / mVideoWidth;\n                if (heightSpecMode == View.MeasureSpec.AT_MOST && height > heightSpecSize) {\n                    // couldn't match aspect ratio within the constraints\n                    height = heightSpecSize;\n                }\n            } else if (heightSpecMode == View.MeasureSpec.EXACTLY) {\n                // only the height is fixed, adjust the width to match aspect ratio if possible\n                height = heightSpecSize;\n                width = height * mVideoWidth / mVideoHeight;\n                if (widthSpecMode == View.MeasureSpec.AT_MOST && width > widthSpecSize) {\n                    // couldn't match aspect ratio within the constraints\n                    width = widthSpecSize;\n                }\n            } else {\n                // neither the width nor the height are fixed, try to use actual video size\n                width = mVideoWidth;\n                height = mVideoHeight;\n                if (heightSpecMode == View.MeasureSpec.AT_MOST && height > heightSpecSize) {\n                    // too tall, decrease both width and height\n                    height = heightSpecSize;\n                    width = height * mVideoWidth / mVideoHeight;\n                }\n                if (widthSpecMode == View.MeasureSpec.AT_MOST && width > widthSpecSize) {\n                    // too wide, decrease both width and height\n                    width = widthSpecSize;\n                    height = width * mVideoHeight / mVideoWidth;\n                }\n            }\n        } else {\n            // no size yet, just adopt the given spec sizes\n        }\n\n        mMeasuredWidth = width;\n        mMeasuredHeight = height;\n    }\n\n    public int getMeasuredWidth() {\n        return mMeasuredWidth;\n    }\n\n    public int getMeasuredHeight() {\n        return mMeasuredHeight;\n    }\n\n    public void setAspectRatio(int aspectRatio) {\n        mCurrentAspectRatio = aspectRatio;\n    }\n\n    @NonNull\n    public static String getAspectRatioText(Context context, int aspectRatio) {\n        String text;\n        switch (aspectRatio) {\n            case IRenderView.AR_ASPECT_FIT_PARENT:\n                text = context.getString(R.string.VideoView_ar_aspect_fit_parent);\n                break;\n            case IRenderView.AR_ASPECT_FILL_PARENT:\n                text = context.getString(R.string.VideoView_ar_aspect_fill_parent);\n                break;\n            case IRenderView.AR_ASPECT_WRAP_CONTENT:\n                text = context.getString(R.string.VideoView_ar_aspect_wrap_content);\n                break;\n            case IRenderView.AR_MATCH_PARENT:\n                text = context.getString(R.string.VideoView_ar_match_parent);\n                break;\n            case IRenderView.AR_16_9_FIT_PARENT:\n                text = context.getString(R.string.VideoView_ar_16_9_fit_parent);\n                break;\n            case IRenderView.AR_4_3_FIT_PARENT:\n                text = context.getString(R.string.VideoView_ar_4_3_fit_parent);\n                break;\n            default:\n                text = context.getString(R.string.N_A);\n                break;\n        }\n        return text;\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/media/MediaPlayerCompat.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.widget.media;\n\nimport tv.danmaku.ijk.media.player.IMediaPlayer;\nimport tv.danmaku.ijk.media.player.IjkMediaPlayer;\nimport tv.danmaku.ijk.media.player.MediaPlayerProxy;\nimport tv.danmaku.ijk.media.player.TextureMediaPlayer;\n\npublic class MediaPlayerCompat {\n    public static String getName(IMediaPlayer mp) {\n        if (mp == null) {\n            return \"null\";\n        } else if (mp instanceof TextureMediaPlayer) {\n            StringBuilder sb = new StringBuilder(\"TextureMediaPlayer <\");\n            IMediaPlayer internalMediaPlayer = ((TextureMediaPlayer) mp).getInternalMediaPlayer();\n            if (internalMediaPlayer == null) {\n                sb.append(\"null>\");\n            } else {\n                sb.append(internalMediaPlayer.getClass().getSimpleName());\n                sb.append(\">\");\n            }\n            return sb.toString();\n        } else {\n            return mp.getClass().getSimpleName();\n        }\n    }\n\n    public static IjkMediaPlayer getIjkMediaPlayer(IMediaPlayer mp) {\n        IjkMediaPlayer ijkMediaPlayer = null;\n        if (mp == null) {\n            return null;\n        } if (mp instanceof IjkMediaPlayer) {\n            ijkMediaPlayer = (IjkMediaPlayer) mp;\n        } else if (mp instanceof MediaPlayerProxy && ((MediaPlayerProxy) mp).getInternalMediaPlayer() instanceof IjkMediaPlayer) {\n            ijkMediaPlayer = (IjkMediaPlayer) ((MediaPlayerProxy) mp).getInternalMediaPlayer();\n        }\n        return ijkMediaPlayer;\n    }\n\n    public static void selectTrack(IMediaPlayer mp, int stream) {\n        IjkMediaPlayer ijkMediaPlayer = getIjkMediaPlayer(mp);\n        if (ijkMediaPlayer == null)\n            return;\n        ijkMediaPlayer.selectTrack(stream);\n    }\n\n    public static void deselectTrack(IMediaPlayer mp, int stream) {\n        IjkMediaPlayer ijkMediaPlayer = getIjkMediaPlayer(mp);\n        if (ijkMediaPlayer == null)\n            return;\n        ijkMediaPlayer.deselectTrack(stream);\n    }\n\n    public static int getSelectedTrack(IMediaPlayer mp, int trackType) {\n        IjkMediaPlayer ijkMediaPlayer = getIjkMediaPlayer(mp);\n        if (ijkMediaPlayer == null)\n            return -1;\n        return ijkMediaPlayer.getSelectedTrack(trackType);\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/media/SurfaceRenderView.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.widget.media;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.graphics.SurfaceTexture;\nimport android.os.Build;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.util.AttributeSet;\nimport android.util.Log;\nimport android.view.Surface;\nimport android.view.SurfaceHolder;\nimport android.view.SurfaceView;\nimport android.view.View;\nimport android.view.accessibility.AccessibilityEvent;\nimport android.view.accessibility.AccessibilityNodeInfo;\n\nimport java.lang.ref.WeakReference;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport tv.danmaku.ijk.media.player.IMediaPlayer;\nimport tv.danmaku.ijk.media.player.ISurfaceTextureHolder;\n\npublic class SurfaceRenderView extends SurfaceView implements IRenderView {\n    private MeasureHelper mMeasureHelper;\n\n    public SurfaceRenderView(Context context) {\n        super(context);\n        initView(context);\n    }\n\n    public SurfaceRenderView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        initView(context);\n    }\n\n    public SurfaceRenderView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        initView(context);\n    }\n\n    @TargetApi(Build.VERSION_CODES.LOLLIPOP)\n    public SurfaceRenderView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n        initView(context);\n    }\n\n    private void initView(Context context) {\n        mMeasureHelper = new MeasureHelper(this);\n        mSurfaceCallback = new SurfaceCallback(this);\n        getHolder().addCallback(mSurfaceCallback);\n        //noinspection deprecation\n        getHolder().setType(SurfaceHolder.SURFACE_TYPE_NORMAL);\n    }\n\n    @Override\n    public View getView() {\n        return this;\n    }\n\n    @Override\n    public boolean shouldWaitForResize() {\n        return true;\n    }\n\n    //--------------------\n    // Layout & Measure\n    //--------------------\n    @Override\n    public void setVideoSize(int videoWidth, int videoHeight) {\n        if (videoWidth > 0 && videoHeight > 0) {\n            mMeasureHelper.setVideoSize(videoWidth, videoHeight);\n            getHolder().setFixedSize(videoWidth, videoHeight);\n            requestLayout();\n        }\n    }\n\n    @Override\n    public void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen) {\n        if (videoSarNum > 0 && videoSarDen > 0) {\n            mMeasureHelper.setVideoSampleAspectRatio(videoSarNum, videoSarDen);\n            requestLayout();\n        }\n    }\n\n    @Override\n    public void setVideoRotation(int degree) {\n        Log.e(\"\", \"SurfaceView doesn't support rotation (\" + degree + \")!\\n\");\n    }\n\n    @Override\n    public void setAspectRatio(int aspectRatio) {\n        mMeasureHelper.setAspectRatio(aspectRatio);\n        requestLayout();\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        mMeasureHelper.doMeasure(widthMeasureSpec, heightMeasureSpec);\n        setMeasuredDimension(mMeasureHelper.getMeasuredWidth(), mMeasureHelper.getMeasuredHeight());\n    }\n\n    //--------------------\n    // SurfaceViewHolder\n    //--------------------\n\n    private static final class InternalSurfaceHolder implements IRenderView.ISurfaceHolder {\n        private SurfaceRenderView mSurfaceView;\n        private SurfaceHolder mSurfaceHolder;\n\n        public InternalSurfaceHolder(@NonNull SurfaceRenderView surfaceView,\n                                     @Nullable SurfaceHolder surfaceHolder) {\n            mSurfaceView = surfaceView;\n            mSurfaceHolder = surfaceHolder;\n        }\n\n        public void bindToMediaPlayer(IMediaPlayer mp) {\n            if (mp != null) {\n                if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) &&\n                        (mp instanceof ISurfaceTextureHolder)) {\n                    ISurfaceTextureHolder textureHolder = (ISurfaceTextureHolder) mp;\n                    textureHolder.setSurfaceTexture(null);\n                }\n                mp.setDisplay(mSurfaceHolder);\n            }\n        }\n\n        @NonNull\n        @Override\n        public IRenderView getRenderView() {\n            return mSurfaceView;\n        }\n\n        @Nullable\n        @Override\n        public SurfaceHolder getSurfaceHolder() {\n            return mSurfaceHolder;\n        }\n\n        @Nullable\n        @Override\n        public SurfaceTexture getSurfaceTexture() {\n            return null;\n        }\n\n        @Nullable\n        @Override\n        public Surface openSurface() {\n            if (mSurfaceHolder == null)\n                return null;\n            return mSurfaceHolder.getSurface();\n        }\n    }\n\n    //-------------------------\n    // SurfaceHolder.Callback\n    //-------------------------\n\n    @Override\n    public void addRenderCallback(IRenderCallback callback) {\n        mSurfaceCallback.addRenderCallback(callback);\n    }\n\n    @Override\n    public void removeRenderCallback(IRenderCallback callback) {\n        mSurfaceCallback.removeRenderCallback(callback);\n    }\n\n    private SurfaceCallback mSurfaceCallback;\n\n    private static final class SurfaceCallback implements SurfaceHolder.Callback {\n        private SurfaceHolder mSurfaceHolder;\n        private boolean mIsFormatChanged;\n        private int mFormat;\n        private int mWidth;\n        private int mHeight;\n\n        private WeakReference<SurfaceRenderView> mWeakSurfaceView;\n        private Map<IRenderCallback, Object> mRenderCallbackMap = new ConcurrentHashMap<IRenderCallback, Object>();\n\n        public SurfaceCallback(@NonNull SurfaceRenderView surfaceView) {\n            mWeakSurfaceView = new WeakReference<SurfaceRenderView>(surfaceView);\n        }\n\n        public void addRenderCallback(@NonNull IRenderCallback callback) {\n            mRenderCallbackMap.put(callback, callback);\n\n            ISurfaceHolder surfaceHolder = null;\n            if (mSurfaceHolder != null) {\n                if (surfaceHolder == null)\n                    surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder);\n                callback.onSurfaceCreated(surfaceHolder, mWidth, mHeight);\n            }\n\n            if (mIsFormatChanged) {\n                if (surfaceHolder == null)\n                    surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder);\n                callback.onSurfaceChanged(surfaceHolder, mFormat, mWidth, mHeight);\n            }\n        }\n\n        public void removeRenderCallback(@NonNull IRenderCallback callback) {\n            mRenderCallbackMap.remove(callback);\n        }\n\n        @Override\n        public void surfaceCreated(SurfaceHolder holder) {\n            mSurfaceHolder = holder;\n            mIsFormatChanged = false;\n            mFormat = 0;\n            mWidth = 0;\n            mHeight = 0;\n\n            ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder);\n            for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {\n                renderCallback.onSurfaceCreated(surfaceHolder, 0, 0);\n            }\n        }\n\n        @Override\n        public void surfaceDestroyed(SurfaceHolder holder) {\n            mSurfaceHolder = null;\n            mIsFormatChanged = false;\n            mFormat = 0;\n            mWidth = 0;\n            mHeight = 0;\n\n            ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder);\n            for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {\n                renderCallback.onSurfaceDestroyed(surfaceHolder);\n            }\n        }\n\n        @Override\n        public void surfaceChanged(SurfaceHolder holder, int format,\n                                   int width, int height) {\n            mSurfaceHolder = holder;\n            mIsFormatChanged = true;\n            mFormat = format;\n            mWidth = width;\n            mHeight = height;\n\n            // mMeasureHelper.setVideoSize(width, height);\n\n            ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder);\n            for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {\n                renderCallback.onSurfaceChanged(surfaceHolder, format, width, height);\n            }\n        }\n    }\n\n    //--------------------\n    // Accessibility\n    //--------------------\n\n    @Override\n    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {\n        super.onInitializeAccessibilityEvent(event);\n        event.setClassName(SurfaceRenderView.class.getName());\n    }\n\n    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)\n    @Override\n    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {\n        super.onInitializeAccessibilityNodeInfo(info);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {\n            info.setClassName(SurfaceRenderView.class.getName());\n        }\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/media/TableLayoutBinder.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.widget.media;\n\nimport android.content.Context;\nimport android.support.v7.app.AlertDialog;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TableLayout;\nimport android.widget.TextView;\n\nimport tv.danmaku.ijk.media.example.R;\n\npublic class TableLayoutBinder {\n    private Context mContext;\n    public ViewGroup mTableView;\n    public TableLayout mTableLayout;\n\n    public TableLayoutBinder(Context context) {\n        this(context, R.layout.table_media_info);\n    }\n\n    public TableLayoutBinder(Context context, int layoutResourceId) {\n        mContext = context;\n        mTableView = (ViewGroup) LayoutInflater.from(mContext).inflate(layoutResourceId, null);\n        mTableLayout = (TableLayout) mTableView.findViewById(R.id.table);\n    }\n\n    public TableLayoutBinder(Context context, TableLayout tableLayout) {\n        mContext = context;\n        mTableView = tableLayout;\n        mTableLayout = tableLayout;\n    }\n\n    public View appendRow1(String name, String value) {\n        return appendRow(R.layout.table_media_info_row1, name, value);\n    }\n\n    public View appendRow1(int nameId, String value) {\n        return appendRow1(mContext.getString(nameId), value);\n    }\n\n    public View appendRow2(String name, String value) {\n        return appendRow(R.layout.table_media_info_row2, name, value);\n    }\n\n    public View appendRow2(int nameId, String value) {\n        return appendRow2(mContext.getString(nameId), value);\n    }\n\n    public View appendSection(String name) {\n        return appendRow(R.layout.table_media_info_section, name, null);\n    }\n\n    public View appendSection(int nameId) {\n        return appendSection(mContext.getString(nameId));\n    }\n\n    public View appendRow(int layoutId, String name, String value) {\n        ViewGroup rowView = (ViewGroup) LayoutInflater.from(mContext).inflate(layoutId, mTableLayout, false);\n        setNameValueText(rowView, name, value);\n\n        mTableLayout.addView(rowView);\n        return rowView;\n    }\n\n    public ViewHolder obtainViewHolder(View rowView) {\n        ViewHolder viewHolder = (ViewHolder) rowView.getTag();\n        if (viewHolder == null) {\n            viewHolder = new ViewHolder();\n            viewHolder.mNameTextView = (TextView) rowView.findViewById(R.id.name);\n            viewHolder.mValueTextView = (TextView) rowView.findViewById(R.id.value);\n            rowView.setTag(viewHolder);\n        }\n        return viewHolder;\n    }\n\n    public void setNameValueText(View rowView, String name, String value) {\n        ViewHolder viewHolder = obtainViewHolder(rowView);\n        viewHolder.setName(name);\n        viewHolder.setValue(value);\n    }\n\n    public void setValueText(View rowView, String value) {\n        ViewHolder viewHolder = obtainViewHolder(rowView);\n        viewHolder.setValue(value);\n    }\n\n    public ViewGroup buildLayout() {\n        return mTableView;\n    }\n\n    public AlertDialog.Builder buildAlertDialogBuilder() {\n        AlertDialog.Builder dlgBuilder = new AlertDialog.Builder(mContext);\n        dlgBuilder.setView(buildLayout());\n        return dlgBuilder;\n    }\n\n    private static class ViewHolder {\n        public TextView mNameTextView;\n        public TextView mValueTextView;\n\n        public void setName(String name) {\n            if (mNameTextView != null) {\n                mNameTextView.setText(name);\n            }\n        }\n\n        public void setValue(String value) {\n            if (mValueTextView != null) {\n                mValueTextView.setText(value);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/media/TextureRenderView.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.widget.media;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.graphics.SurfaceTexture;\nimport android.os.Build;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.util.AttributeSet;\nimport android.util.Log;\nimport android.view.Surface;\nimport android.view.SurfaceHolder;\nimport android.view.TextureView;\nimport android.view.View;\nimport android.view.accessibility.AccessibilityEvent;\nimport android.view.accessibility.AccessibilityNodeInfo;\n\nimport java.lang.ref.WeakReference;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport tv.danmaku.ijk.media.player.IMediaPlayer;\nimport tv.danmaku.ijk.media.player.ISurfaceTextureHolder;\nimport tv.danmaku.ijk.media.player.ISurfaceTextureHost;\n\n@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)\npublic class TextureRenderView extends TextureView implements IRenderView {\n    private static final String TAG = \"TextureRenderView\";\n    private MeasureHelper mMeasureHelper;\n\n    public TextureRenderView(Context context) {\n        super(context);\n        initView(context);\n    }\n\n    public TextureRenderView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        initView(context);\n    }\n\n    public TextureRenderView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        initView(context);\n    }\n\n    @TargetApi(Build.VERSION_CODES.LOLLIPOP)\n    public TextureRenderView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n        initView(context);\n    }\n\n    private void initView(Context context) {\n        mMeasureHelper = new MeasureHelper(this);\n        mSurfaceCallback = new SurfaceCallback(this);\n        setSurfaceTextureListener(mSurfaceCallback);\n    }\n\n    @Override\n    public View getView() {\n        return this;\n    }\n\n    @Override\n    public boolean shouldWaitForResize() {\n        return false;\n    }\n\n    @Override\n    protected void onDetachedFromWindow() {\n        mSurfaceCallback.willDetachFromWindow();\n        super.onDetachedFromWindow();\n        mSurfaceCallback.didDetachFromWindow();\n    }\n\n    //--------------------\n    // Layout & Measure\n    //--------------------\n    @Override\n    public void setVideoSize(int videoWidth, int videoHeight) {\n        if (videoWidth > 0 && videoHeight > 0) {\n            mMeasureHelper.setVideoSize(videoWidth, videoHeight);\n            requestLayout();\n        }\n    }\n\n    @Override\n    public void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen) {\n        if (videoSarNum > 0 && videoSarDen > 0) {\n            mMeasureHelper.setVideoSampleAspectRatio(videoSarNum, videoSarDen);\n            requestLayout();\n        }\n    }\n\n    @Override\n    public void setVideoRotation(int degree) {\n        mMeasureHelper.setVideoRotation(degree);\n        setRotation(degree);\n    }\n\n    @Override\n    public void setAspectRatio(int aspectRatio) {\n        mMeasureHelper.setAspectRatio(aspectRatio);\n        requestLayout();\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        mMeasureHelper.doMeasure(widthMeasureSpec, heightMeasureSpec);\n        setMeasuredDimension(mMeasureHelper.getMeasuredWidth(), mMeasureHelper.getMeasuredHeight());\n    }\n\n    //--------------------\n    // TextureViewHolder\n    //--------------------\n\n    public IRenderView.ISurfaceHolder getSurfaceHolder() {\n        return new InternalSurfaceHolder(this, mSurfaceCallback.mSurfaceTexture, mSurfaceCallback);\n    }\n\n    private static final class InternalSurfaceHolder implements IRenderView.ISurfaceHolder {\n        private TextureRenderView mTextureView;\n        private SurfaceTexture mSurfaceTexture;\n        private ISurfaceTextureHost mSurfaceTextureHost;\n\n        public InternalSurfaceHolder(@NonNull TextureRenderView textureView,\n                                     @Nullable SurfaceTexture surfaceTexture,\n                                     @NonNull ISurfaceTextureHost surfaceTextureHost) {\n            mTextureView = textureView;\n            mSurfaceTexture = surfaceTexture;\n            mSurfaceTextureHost = surfaceTextureHost;\n        }\n\n        @TargetApi(Build.VERSION_CODES.JELLY_BEAN)\n        public void bindToMediaPlayer(IMediaPlayer mp) {\n            if (mp == null)\n                return;\n\n            if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) &&\n                    (mp instanceof ISurfaceTextureHolder)) {\n                ISurfaceTextureHolder textureHolder = (ISurfaceTextureHolder) mp;\n                mTextureView.mSurfaceCallback.setOwnSurfaceTexture(false);\n\n                SurfaceTexture surfaceTexture = textureHolder.getSurfaceTexture();\n                if (surfaceTexture != null) {\n                    mTextureView.setSurfaceTexture(surfaceTexture);\n                } else {\n                    textureHolder.setSurfaceTexture(mSurfaceTexture);\n                    textureHolder.setSurfaceTextureHost(mTextureView.mSurfaceCallback);\n                }\n            } else {\n                mp.setSurface(openSurface());\n            }\n        }\n\n        @NonNull\n        @Override\n        public IRenderView getRenderView() {\n            return mTextureView;\n        }\n\n        @Nullable\n        @Override\n        public SurfaceHolder getSurfaceHolder() {\n            return null;\n        }\n\n        @Nullable\n        @Override\n        public SurfaceTexture getSurfaceTexture() {\n            return mSurfaceTexture;\n        }\n\n        @Nullable\n        @Override\n        public Surface openSurface() {\n            if (mSurfaceTexture == null)\n                return null;\n            return new Surface(mSurfaceTexture);\n        }\n    }\n\n    //-------------------------\n    // SurfaceHolder.Callback\n    //-------------------------\n\n    @Override\n    public void addRenderCallback(IRenderCallback callback) {\n        mSurfaceCallback.addRenderCallback(callback);\n    }\n\n    @Override\n    public void removeRenderCallback(IRenderCallback callback) {\n        mSurfaceCallback.removeRenderCallback(callback);\n    }\n\n    private SurfaceCallback mSurfaceCallback;\n\n    private static final class SurfaceCallback implements TextureView.SurfaceTextureListener, ISurfaceTextureHost {\n        private SurfaceTexture mSurfaceTexture;\n        private boolean mIsFormatChanged;\n        private int mWidth;\n        private int mHeight;\n\n        private boolean mOwnSurfaceTexture = true;\n        private boolean mWillDetachFromWindow = false;\n        private boolean mDidDetachFromWindow = false;\n\n        private WeakReference<TextureRenderView> mWeakRenderView;\n        private Map<IRenderCallback, Object> mRenderCallbackMap = new ConcurrentHashMap<IRenderCallback, Object>();\n\n        public SurfaceCallback(@NonNull TextureRenderView renderView) {\n            mWeakRenderView = new WeakReference<TextureRenderView>(renderView);\n        }\n\n        public void setOwnSurfaceTexture(boolean ownSurfaceTexture) {\n            mOwnSurfaceTexture = ownSurfaceTexture;\n        }\n\n        public void addRenderCallback(@NonNull IRenderCallback callback) {\n            mRenderCallbackMap.put(callback, callback);\n\n            ISurfaceHolder surfaceHolder = null;\n            if (mSurfaceTexture != null) {\n                if (surfaceHolder == null)\n                    surfaceHolder = new InternalSurfaceHolder(mWeakRenderView.get(), mSurfaceTexture, this);\n                callback.onSurfaceCreated(surfaceHolder, mWidth, mHeight);\n            }\n\n            if (mIsFormatChanged) {\n                if (surfaceHolder == null)\n                    surfaceHolder = new InternalSurfaceHolder(mWeakRenderView.get(), mSurfaceTexture, this);\n                callback.onSurfaceChanged(surfaceHolder, 0, mWidth, mHeight);\n            }\n        }\n\n        public void removeRenderCallback(@NonNull IRenderCallback callback) {\n            mRenderCallbackMap.remove(callback);\n        }\n\n        @Override\n        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {\n            mSurfaceTexture = surface;\n            mIsFormatChanged = false;\n            mWidth = 0;\n            mHeight = 0;\n\n            ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakRenderView.get(), surface, this);\n            for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {\n                renderCallback.onSurfaceCreated(surfaceHolder, 0, 0);\n            }\n        }\n\n        @Override\n        public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {\n            mSurfaceTexture = surface;\n            mIsFormatChanged = true;\n            mWidth = width;\n            mHeight = height;\n\n            ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakRenderView.get(), surface, this);\n            for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {\n                renderCallback.onSurfaceChanged(surfaceHolder, 0, width, height);\n            }\n        }\n\n        @Override\n        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {\n            mSurfaceTexture = surface;\n            mIsFormatChanged = false;\n            mWidth = 0;\n            mHeight = 0;\n\n            ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakRenderView.get(), surface, this);\n            for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {\n                renderCallback.onSurfaceDestroyed(surfaceHolder);\n            }\n\n            Log.d(TAG, \"onSurfaceTextureDestroyed: destroy: \" + mOwnSurfaceTexture);\n            return mOwnSurfaceTexture;\n        }\n\n        @Override\n        public void onSurfaceTextureUpdated(SurfaceTexture surface) {\n        }\n\n        //-------------------------\n        // ISurfaceTextureHost\n        //-------------------------\n\n        @Override\n        public void releaseSurfaceTexture(SurfaceTexture surfaceTexture) {\n            if (surfaceTexture == null) {\n                Log.d(TAG, \"releaseSurfaceTexture: null\");\n            } else if (mDidDetachFromWindow) {\n                if (surfaceTexture != mSurfaceTexture) {\n                    Log.d(TAG, \"releaseSurfaceTexture: didDetachFromWindow(): release different SurfaceTexture\");\n                    surfaceTexture.release();\n                } else if (!mOwnSurfaceTexture) {\n                    Log.d(TAG, \"releaseSurfaceTexture: didDetachFromWindow(): release detached SurfaceTexture\");\n                    surfaceTexture.release();\n                } else {\n                    Log.d(TAG, \"releaseSurfaceTexture: didDetachFromWindow(): already released by TextureView\");\n                }\n            } else if (mWillDetachFromWindow) {\n                if (surfaceTexture != mSurfaceTexture) {\n                    Log.d(TAG, \"releaseSurfaceTexture: willDetachFromWindow(): release different SurfaceTexture\");\n                    surfaceTexture.release();\n                } else if (!mOwnSurfaceTexture) {\n                    Log.d(TAG, \"releaseSurfaceTexture: willDetachFromWindow(): re-attach SurfaceTexture to TextureView\");\n                    setOwnSurfaceTexture(true);\n                } else {\n                    Log.d(TAG, \"releaseSurfaceTexture: willDetachFromWindow(): will released by TextureView\");\n                }\n            } else {\n                if (surfaceTexture != mSurfaceTexture) {\n                    Log.d(TAG, \"releaseSurfaceTexture: alive: release different SurfaceTexture\");\n                    surfaceTexture.release();\n                } else if (!mOwnSurfaceTexture) {\n                    Log.d(TAG, \"releaseSurfaceTexture: alive: re-attach SurfaceTexture to TextureView\");\n                    setOwnSurfaceTexture(true);\n                } else {\n                    Log.d(TAG, \"releaseSurfaceTexture: alive: will released by TextureView\");\n                }\n            }\n        }\n\n        public void willDetachFromWindow() {\n            Log.d(TAG, \"willDetachFromWindow()\");\n            mWillDetachFromWindow = true;\n        }\n\n        public void didDetachFromWindow() {\n            Log.d(TAG, \"didDetachFromWindow()\");\n            mDidDetachFromWindow = true;\n        }\n    }\n\n    //--------------------\n    // Accessibility\n    //--------------------\n\n    @Override\n    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {\n        super.onInitializeAccessibilityEvent(event);\n        event.setClassName(TextureRenderView.class.getName());\n    }\n\n    @Override\n    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {\n        super.onInitializeAccessibilityNodeInfo(info);\n        info.setClassName(TextureRenderView.class.getName());\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/preference/IjkListPreference.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.example.widget.preference;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.support.v7.preference.ListPreference;\nimport android.text.TextUtils;\nimport android.util.AttributeSet;\n\nimport tv.danmaku.ijk.media.example.R;\n\npublic class IjkListPreference extends ListPreference {\n    private CharSequence[] mEntrySummaries;\n\n    public IjkListPreference(Context context) {\n        super(context);\n        initPreference(context, null);\n    }\n\n    public IjkListPreference(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        initPreference(context, attrs);\n    }\n\n    public IjkListPreference(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        initPreference(context, attrs);\n    }\n\n    public IjkListPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n        initPreference(context, attrs);\n    }\n\n    private void initPreference(Context context, AttributeSet attrs) {\n        TypedArray a = context.obtainStyledAttributes(attrs,\n                R.styleable.IjkListPreference, 0, 0);\n        if (a == null)\n            return;\n\n        mEntrySummaries = a\n                .getTextArray(R.styleable.IjkListPreference_entrySummaries);\n\n        a.recycle();\n    }\n\n    @Override\n    protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {\n        super.onSetInitialValue(restoreValue, defaultValue);\n        syncSummary();\n    }\n\n    @Override\n    public void setValue(String value) {\n        super.setValue(value);\n        syncSummary();\n    }\n\n    @Override\n    public void setValueIndex(int index) {\n        super.setValueIndex(index);\n        syncSummary();\n    }\n\n    public int getEntryIndex() {\n        CharSequence[] entryValues = getEntryValues();\n        CharSequence value = getValue();\n\n        if (entryValues == null || value == null) {\n            return -1;\n        }\n\n        for (int i = 0; i < entryValues.length; ++i) {\n            if (TextUtils.equals(value, entryValues[i])) {\n                return i;\n            }\n        }\n\n        return -1;\n    }\n\n    // ----- summary --------------------\n    public void setEntrySummaries(Context context, int resId) {\n        setEntrySummaries(context.getResources().getTextArray(resId));\n    }\n\n    public void setEntrySummaries(CharSequence[] entrySummaries) {\n        mEntrySummaries = entrySummaries;\n        notifyChanged();\n    }\n\n    public CharSequence[] getEntrySummaries() {\n        return mEntrySummaries;\n    }\n\n    private void syncSummary() {\n        int index = getEntryIndex();\n        if (index < 0)\n            return;\n\n        if (mEntrySummaries != null && index < mEntrySummaries.length) {\n            setSummary(mEntrySummaries[index]);\n        } else {\n            setSummary(getEntries()[index]);\n        }\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/project.properties",
    "content": "# This file is automatically generated by Android Tools.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n#\n# This file must be checked in Version Control Systems.\n#\n# To customize properties used by the Ant build system edit\n# \"ant.properties\", and override values to adapt the script to your\n# project structure.\n#\n# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):\n#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt\n\n# Project target.\ntarget=android-22\nandroid.library.reference.1=../../../player-arm64/src/main\nandroid.library.reference.2=../../../player-armv5/src/main\nandroid.library.reference.3=../../../player-armv7a/src/main\nandroid.library.reference.4=../../../player-x86/src/main\nandroid.library.reference.5=../../../player-java/src/main\nandroid.library.reference.6=../../../../contrib/appcompat\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/res/layout/activity_app.xml",
    "content": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    tools:context=\".activities.FileExplorerActivity\">\n\n    <include layout=\"@layout/widget_toolbar\" />\n\n    <FrameLayout\n        android:id=\"@+id/body\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" />\n</LinearLayout>\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/res/layout/activity_player.xml",
    "content": "<android.support.v4.widget.DrawerLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    tools:context=\".activities.VideoActivity\"\n    android:id=\"@+id/drawer_layout\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <!-- The main content view -->\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"#0099cc\">\n\n        <tv.danmaku.ijk.media.example.widget.media.IjkVideoView\n            android:id=\"@+id/video_view\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_gravity=\"center\"></tv.danmaku.ijk.media.example.widget.media.IjkVideoView>\n\n        <TextView\n            android:id=\"@+id/toast_text_view\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"left|center_vertical\"\n            android:background=\"@color/ijk_transparent_dark\"\n            android:padding=\"16dp\"\n            android:textSize=\"16sp\"\n            android:visibility=\"gone\" />\n\n        <TableLayout\n            android:id=\"@+id/hud_view\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"right|center_vertical\"\n            android:background=\"@color/ijk_transparent_dark\"\n            android:padding=\"8dp\" />\n\n        <android.support.v7.widget.Toolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"@color/ijk_transparent_dark\"\n            android:minHeight=\"?attr/actionBarSize\"\n            android:theme=\"@style/ThemeOverlay.AppCompat.ActionBar\"\n            app:popupTheme=\"@style/ThemeOverlay.AppCompat.Light\"\n            tools:context=\".toolbar_widget\" />\n    </FrameLayout>\n\n    <!-- The navigation drawer -->\n    <FrameLayout android:id=\"@+id/right_drawer\"\n        android:layout_width=\"240dp\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"right\"\n        android:background=\"@color/ijk_transparent_dark\" />\n</android.support.v4.widget.DrawerLayout>"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/res/layout/fragment_file_list.xml",
    "content": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\"\n    android:paddingBottom=\"0dp\"\n    android:paddingLeft=\"@dimen/ijk_horizontal_margin\"\n    android:paddingRight=\"@dimen/ijk_horizontal_margin\"\n    android:paddingTop=\"0dp\">\n\n    <EditText\n        android:id=\"@+id/path_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:inputType=\"none\"\n        android:editable=\"false\"\n        android:visibility=\"gone\"\n        android:lines=\"1\" />\n\n    <ListView\n        android:id=\"@+id/file_list_view\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:choiceMode=\"singleChoice\"\n        tools:context=\".file_list_view\" />\n\n</LinearLayout>"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/res/layout/fragment_file_list_item.xml",
    "content": "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:padding=\"0dp\">\n\n    <ImageView\n        android:id=\"@+id/icon\"\n        android:layout_width=\"48dp\"\n        android:layout_height=\"48dp\"\n        android:layout_alignParentLeft=\"true\"\n        tools:ignore=\"ContentDescription\" />\n\n    <TextView\n        android:id=\"@+id/name\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentRight=\"true\"\n        android:layout_centerVertical=\"true\"\n        android:layout_toRightOf=\"@id/icon\" />\n</RelativeLayout>"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/res/layout/fragment_track_list.xml",
    "content": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\"\n    android:paddingBottom=\"0dp\"\n    android:paddingLeft=\"0dp\"\n    android:paddingRight=\"0dp\"\n    android:paddingTop=\"0dp\">\n\n    <ListView\n        android:id=\"@+id/track_list_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:choiceMode=\"multipleChoice\"\n        tools:context=\".track_list_view\" />\n\n</LinearLayout>"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/res/layout/table_media_info.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"fill_parent\" >\n\n    <TableLayout\n        android:id=\"@+id/table\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:shrinkColumns=\"1\" >\n    </TableLayout>\n\n</ScrollView>"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/res/layout/table_media_info_row1.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TableRow xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_marginLeft=\"10dip\"\n    android:paddingBottom=\"2dip\"\n    android:paddingTop=\"2dip\" >\n\n    <TextView\n        android:id=\"@+id/name\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:textSize=\"15sp\" />\n\n    <TextView\n        android:id=\"@+id/value\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingLeft=\"10dip\"\n        android:paddingRight=\"10dip\"\n        android:textSize=\"15sp\" />\n\n</TableRow>"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/res/layout/table_media_info_row2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TableRow xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:paddingBottom=\"0dip\"\n    android:paddingLeft=\"16dip\"\n    android:paddingRight=\"16dip\"\n    android:paddingTop=\"0dip\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\">\n\n    <TextView\n        android:id=\"@+id/name\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:textSize=\"12sp\" />\n\n    <TextView\n        android:id=\"@+id/value\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingLeft=\"10dip\"\n        android:paddingRight=\"10dip\"\n        android:textSize=\"12sp\" />\n\n</TableRow>"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/res/layout/table_media_info_section.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TableRow xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:paddingBottom=\"2dip\"\n    android:paddingLeft=\"8dip\"\n    android:paddingRight=\"8dip\"\n    android:paddingTop=\"4dip\" >\n\n    <TextView\n        android:id=\"@+id/name\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:textSize=\"16sp\"\n        android:textStyle=\"bold\" />\n\n</TableRow>"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/res/layout/widget_toolbar.xml",
    "content": "<merge xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <android.support.v7.widget.Toolbar\n        android:id=\"@+id/toolbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"?attr/colorPrimaryDark\"\n        android:minHeight=\"?attr/actionBarSize\"\n        android:theme=\"@style/ThemeOverlay.AppCompat.Dark.ActionBar\"\n        app:popupTheme=\"@style/ThemeOverlay.AppCompat.Light\"\n        tools:context=\".toolbar_widget\" />\n\n</merge>"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/res/menu/menu_app.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    tools:context=\".menu_app\">\n    <item\n        android:id=\"@+id/action_sample\"\n        android:title=\"@string/sample\"\n        app:showAsAction=\"ifRoom\" />\n    <item\n        android:id=\"@+id/action_recent\"\n        android:title=\"@string/recent\"\n        app:showAsAction=\"ifRoom\" />\n    <item\n        android:id=\"@+id/action_settings\"\n        android:title=\"@string/settings\"\n        app:showAsAction=\"ifRoom\" />\n</menu>"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/res/menu/menu_player.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    tools:context=\".menu_app\">\n    <item\n        android:id=\"@+id/action_toggle_player\"\n        android:title=\"@string/toggle_player\"\n        app:showAsAction=\"ifRoom\" />\n    <item\n        android:id=\"@+id/action_toggle_render\"\n        android:title=\"@string/toggle_render\"\n        app:showAsAction=\"ifRoom\" />\n    <item\n        android:id=\"@+id/action_toggle_ratio\"\n        android:title=\"@string/toggle_ratio\"\n        app:showAsAction=\"ifRoom\" />\n    <item\n        android:id=\"@+id/action_show_info\"\n        android:title=\"@string/show_info\"\n        app:showAsAction=\"ifRoom\" />\n    <item\n        android:id=\"@+id/action_show_tracks\"\n        android:title=\"@string/tracks\"\n        app:showAsAction=\"ifRoom\" />\n</menu>"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/res/values/attrs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <attr name=\"entrySummaries\" format=\"reference\" />\n\n    <declare-styleable name=\"IjkListPreference\">\n        <attr name=\"entrySummaries\" />\n    </declare-styleable>\n</resources>"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/res/values/colors.xml",
    "content": "<resources>\n\n    <color name=\"black_overlay\">#66000000</color>\n\n    <color name=\"ijk_color_blue_main\">@color/ijk_color_blue_500</color>\n    <color name=\"ijk_color_blue_50\">#E3F2FD</color>\n    <color name=\"ijk_color_blue_100\">#BBDEFB</color>\n    <color name=\"ijk_color_blue_200\">#90CAF9</color>\n    <color name=\"ijk_color_blue_300\">#64B5F6</color>\n    <color name=\"ijk_color_blue_400\">#42A5F5</color>\n    <color name=\"ijk_color_blue_500\">#2196F3</color>\n    <color name=\"ijk_color_blue_600\">#1E88E5</color>\n    <color name=\"ijk_color_blue_700\">#1976D2</color>\n    <color name=\"ijk_color_blue_800\">#1565C0</color>\n    <color name=\"ijk_color_blue_900\">#0D47A1</color>\n\n    <color name=\"ijk_transparent_dark\">#77000000</color>\n\n</resources>\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/res/values/dimens.xml",
    "content": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n\n    <dimen name=\"ijk_horizontal_margin\">@dimen/activity_horizontal_margin</dimen>\n    <dimen name=\"ijk_vertical_margin\">@dimen/activity_vertical_margin</dimen>\n</resources>\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/res/values/ids.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <item name=\"render_view\" type=\"id\"/>\n</resources>"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"app_name\">ijkmediademo</string>\n\n    <string name=\"N_A\">N/A</string>\n    <string name=\"close\">Close</string>\n    <string name=\"exit\">Exit</string>\n    <string name=\"sample\">Sample</string>\n    <string name=\"recent\">Recent</string>\n    <string name=\"settings\">Settings</string>\n    <string name=\"tracks\">Tracks</string>\n    <string name=\"toggle_player\">Player</string>\n    <string name=\"toggle_render\">Render</string>\n    <string name=\"toggle_ratio\">Scale</string>\n    <string name=\"show_info\">Info</string>\n    <string name=\"vdec\">vdec</string>\n    <string name=\"fps\">fps</string>\n    <string name=\"v_cache\">v-cache</string>\n    <string name=\"a_cache\">a-cache</string>\n    <string name=\"load_cost\">load-cost</string>\n    <string name=\"seek_cost\">seek_cost</string>\n    <string name=\"seek_load_cost\">seek_load_cost</string>\n    <string name=\"tcp_speed\">tcp_speed</string>\n    <string name=\"bit_rate\">bit_rate</string>\n\n    <string name=\"media_information\">Media Information</string>\n    <string name=\"mi_player\">Player</string>\n    <string name=\"mi_media\">Media</string>\n    <string name=\"mi_profile_level\">Profile level</string>\n    <string name=\"mi_pixel_format\">Pixel format</string>\n    <string name=\"mi_resolution\">Resolution</string>\n    <string name=\"mi_length\">Length</string>\n    <string name=\"mi_stream_fmt1\">Stream #%d</string>\n    <string name=\"mi_type\">Type</string>\n    <string name=\"mi_language\">Language</string>\n    <string name=\"mi_codec\">Codec</string>\n    <string name=\"mi_frame_rate\">Frame rate</string>\n    <string name=\"mi_bit_rate\">Bit rate</string>\n    <string name=\"mi_sample_rate\">Sample rate</string>\n    <string name=\"mi_channels\">Channels</string>\n    <string name=\"mi__selected_video_track\">*</string>\n    <string name=\"mi__selected_audio_track\">*</string>\n    <string name=\"mi__selected_subtitle_track\">*</string>\n\n    <string name=\"TrackType_video\">Video</string>\n    <string name=\"TrackType_audio\">Audio</string>\n    <string name=\"TrackType_subtitle\">Subtitle</string>\n    <string name=\"TrackType_timedtext\">Timed text</string>\n    <string name=\"TrackType_metadata\">Meta data</string>\n    <string name=\"TrackType_unknown\">Unknown</string>\n\n    <string name=\"VideoView_error_text_invalid_progressive_playback\">Invalid progressive playback</string>\n    <string name=\"VideoView_error_text_unknown\">Unknown</string>\n    <string name=\"VideoView_error_button\">OK</string>\n\n    <string name=\"VideoView_ar_aspect_fit_parent\">Aspect / Fit parent</string>\n    <string name=\"VideoView_ar_aspect_fill_parent\">Aspect / Fill parent</string>\n    <string name=\"VideoView_ar_aspect_wrap_content\">Aspect / Wrap content</string>\n    <string name=\"VideoView_ar_match_parent\">Free / Fill parent</string>\n    <string name=\"VideoView_ar_16_9_fit_parent\">16:9 / Fit parent</string>\n    <string name=\"VideoView_ar_4_3_fit_parent\">4:3 / Fit parent</string>\n\n    <string name=\"VideoView_render_none\">Render: None</string>\n    <string name=\"VideoView_render_surface_view\">Render: SurfaceView</string>\n    <string name=\"VideoView_render_texture_view\">Render: TextureView</string>\n\n    <string name=\"VideoView_player_none\">Player: None</string>\n    <string name=\"VideoView_player_AndroidMediaPlayer\">Player: AndroidMediaPlayer</string>\n    <string name=\"VideoView_player_IjkMediaPlayer\">Player: IjkMediaPlayer</string>\n    <string name=\"VideoView_player_IjkExoMediaPlayer\">Player: IjkExoMediaPlayer</string>\n\n</resources>\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/res/values/strings_pref.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- -->\n    <string name=\"pref_title_general\">General</string>\n\n    <string name=\"pref_key_enable_background_play\">pref.enable_background_play</string>\n    <string name=\"pref_title_enable_background_play\">Enable background play</string>\n    <string name=\"pref_summary_enable_background_play\">need Android 4.0+</string>\n\n    <string name=\"pref_key_using_android_player\">pref.using_android_player</string>\n    <string name=\"pref_title_using_android_player\">Using system player</string>\n    <string name=\"pref_summary_using_android_player\"></string>\n\n    <string name=\"pref_key_player\">pref.player</string>\n    <string name=\"pref_title_player\">Choose Player</string>\n    <string-array name=\"pref_entries_player\">\n        <item>Auto Select</item>\n        <item>AndroidMediaPlayer</item>\n        <item>IjkMediaPlayer</item>\n        <item>IjkExoMediaPlayer</item>\n    </string-array>\n    <string-array name=\"pref_entry_values_player\">\n        <item>0</item>\n        <item>1</item>\n        <item>2</item>\n        <item>3</item>\n    </string-array>\n    <string-array name=\"pref_entry_summaries_player\">\n        <item>Auto Select</item>\n        <item>AndroidMediaPlayer</item>\n        <item>IjkMediaPlayer</item>\n        <item>IjkExoMediaPlayer</item>\n    </string-array>\n\n    <!-- -->\n    <string name=\"pref_title_ijkplayer_video\">Video: ijkplayer</string>\n\n    <string name=\"pref_key_using_media_codec\">pref.using_media_codec</string>\n    <string name=\"pref_title_using_media_codec\">Using MediaCodec</string>\n    <string name=\"pref_summary_using_media_codec\"></string>\n\n    <string name=\"pref_key_using_media_codec_auto_rotate\">pref.using_media_codec_auto_rotate</string>\n    <string name=\"pref_title_using_media_codec_auto_rotate\">Using MediaCodec auto rotate</string>\n    <string name=\"pref_summary_using_media_codec_auto_rotate\"></string>\n\n    <string name=\"pref_key_media_codec_handle_resolution_change\">pref.media_codec_handle_resolution_change</string>\n    <string name=\"pref_title_media_codec_handle_resolution_change\">MediaCodec handle resolution change</string>\n    <string name=\"pref_summary_media_codec_handle_resolution_change\"></string>\n\n    <string name=\"pref_key_pixel_format\">pref.pixel_format</string>\n    <string name=\"pref_title_pixel_format\">Pixel Format</string>\n    <string-array name=\"pref_entries_pixel_format\">\n        <item>Auto Select</item>\n        <item>RGB 565</item>\n        <item>RGB 888</item>\n        <item>RGBX 8888</item>\n        <item>YV12</item>\n        <item>OpenGL ES2</item>\n    </string-array>\n    <string-array name=\"pref_entry_values_pixel_format\">\n        <item></item>\n        <item>fcc-rv16</item>\n        <item>fcc-rv24</item>\n        <item>fcc-rv32</item>\n        <item>fcc-yv12</item>\n        <item>fcc-_es2</item>\n    </string-array>\n    <string-array name=\"pref_entry_summaries_pixel_format\">\n        <item>Auto Select</item>\n        <item>RGB 565</item>\n        <item>RGB 888</item>\n        <item>RGBX 8888</item>\n        <item>YV12</item>\n        <item>OpenGL ES2</item>\n    </string-array>\n\n    <!-- -->\n    <string name=\"pref_title_ijkplayer_audio\">Audio: ijkplayer</string>\n\n    <string name=\"pref_key_using_opensl_es\">pref.using_opensl_es</string>\n    <string name=\"pref_title_using_opensl_es\">Using OpenSL ES</string>\n    <string name=\"pref_summary_using_opensl_es\"></string>\n\n    <!-- -->\n    <string name=\"pref_title_render_view\">RenderView</string>\n\n    <string name=\"pref_key_enable_no_view\">pref.enable_no_view</string>\n    <string name=\"pref_title_enable_no_view\">Enable NoView</string>\n    <string name=\"pref_summary_enable_no_view\"></string>\n\n    <string name=\"pref_key_enable_surface_view\">pref.enable_surface_view</string>\n    <string name=\"pref_title_enable_surface_view\">Enable SurfaceView</string>\n    <string name=\"pref_summary_enable_surface_view\"></string>\n\n    <string name=\"pref_key_enable_texture_view\">pref.enable_texture_view</string>\n    <string name=\"pref_title_enable_texture_view\">Enable TextureView</string>\n    <string name=\"pref_summary_enable_texture_view\"></string>\n\n    <string name=\"pref_key_enable_detached_surface_texture\">pref.enable_detached_surface_texture</string>\n    <string name=\"pref_title_enable_detached_surface_texture\">Enable detached SurfaceTexture</string>\n    <string name=\"pref_summary_enable_detached_surface_texture\"></string>\n\n    <!-- -->\n    <string name=\"pref_title_misc\">Misc</string>\n    <string name=\"pref_key_using_mediadatasource\">pref.using_mediadatasource</string>\n    <string name=\"pref_title_using_mediadatasource\">Using MediaDataSource</string>\n    <string name=\"pref_summary_using_mediadatasource\"></string>\n\n    <!-- -->\n    <string name=\"pref_key_last_directory\"></string>\n\n</resources>\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/res/values/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <style name=\"Widget.App.ActionButton\" parent=\"@style/Widget.AppCompat.ActionButton\">\n        <item name=\"textAllCaps\">false</item>\n    </style>\n\n    <style name=\"Theme.App.Light.NoActionBar\" parent=\"Theme.AppCompat.Light.NoActionBar\">\n        <item name=\"preferenceTheme\">@style/PreferenceThemeOverlay</item>\n\n        <item name=\"actionButtonStyle\">@style/Widget.App.ActionButton</item>\n    </style>\n\n    <style name=\"Theme.App.NoActionBar\" parent=\"Theme.AppCompat.NoActionBar\">\n        <item name=\"android:windowContentOverlay\">@null</item>\n        <item name=\"android:windowBackground\">@null</item>\n\n        <item name=\"actionButtonStyle\">@style/Widget.App.ActionButton</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/res/values/themes.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <style name=\"AppTheme\" parent=\"Theme.App.Light.NoActionBar\">\n    </style>\n\n    <style name=\"FullscreenTheme\" parent=\"Theme.App.NoActionBar\">\n    </style>\n</resources>"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/res/values-v11/styles.xml",
    "content": "<resources>\n</resources>\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/res/values-v14/styles.xml",
    "content": "<resources>\n</resources>\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/res/values-w820dp/dimens.xml",
    "content": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as screen margins) for screens with more than 820dp of available width. This\n         would include 7\" and 10\" devices in landscape (~960dp and ~1280dp respectively). -->\n    <dimen name=\"activity_horizontal_margin\">64dp</dimen>\n</resources>\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-example/src/main/res/xml/settings.xml",
    "content": "<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <PreferenceCategory android:title=\"@string/pref_title_general\">\n        <CheckBoxPreference\n            android:defaultValue=\"false\"\n            android:disableDependentsState=\"true\"\n            android:key=\"@string/pref_key_enable_background_play\"\n            android:persistent=\"true\"\n            android:summary=\"@string/pref_summary_enable_background_play\"\n            android:title=\"@string/pref_title_enable_background_play\" />\n        <tv.danmaku.ijk.media.example.widget.preference.IjkListPreference\n            android:defaultValue=\"0\"\n            android:entries=\"@@array/pref_entries_player\"\n            android:entryValues=\"@array/pref_entry_values_player\"\n            android:key=\"@string/pref_key_player\"\n            android:persistent=\"true\"\n            android:title=\"@string/pref_title_player\"\n            app:entrySummaries=\"@array/pref_entry_summaries_player\" />\n    </PreferenceCategory>\n    <PreferenceCategory android:title=\"@string/pref_title_ijkplayer_video\">\n        <CheckBoxPreference\n            android:defaultValue=\"false\"\n            android:key=\"@string/pref_key_using_media_codec\"\n            android:persistent=\"true\"\n            android:summary=\"@string/pref_summary_using_media_codec\"\n            android:title=\"@string/pref_title_using_media_codec\" />\n        <CheckBoxPreference\n            android:defaultValue=\"false\"\n            android:key=\"@string/pref_key_using_media_codec_auto_rotate\"\n            android:persistent=\"true\"\n            android:summary=\"@string/pref_summary_using_media_codec_auto_rotate\"\n            android:title=\"@string/pref_title_using_media_codec_auto_rotate\" />\n        <CheckBoxPreference\n            android:defaultValue=\"false\"\n            android:key=\"@string/pref_key_media_codec_handle_resolution_change\"\n            android:persistent=\"true\"\n            android:summary=\"@string/pref_summary_media_codec_handle_resolution_change\"\n            android:title=\"@string/pref_title_media_codec_handle_resolution_change\" />\n        <tv.danmaku.ijk.media.example.widget.preference.IjkListPreference\n            android:defaultValue=\"\"\n            android:entries=\"@array/pref_entries_pixel_format\"\n            android:entryValues=\"@array/pref_entry_values_pixel_format\"\n            android:key=\"@string/pref_key_pixel_format\"\n            android:persistent=\"true\"\n            android:title=\"@string/pref_title_pixel_format\"\n            app:entrySummaries=\"@array/pref_entry_summaries_pixel_format\" />\n    </PreferenceCategory>\n    <PreferenceCategory android:title=\"@string/pref_title_ijkplayer_audio\">\n        <CheckBoxPreference\n            android:defaultValue=\"false\"\n            android:key=\"@string/pref_key_using_opensl_es\"\n            android:persistent=\"true\"\n            android:summary=\"@string/pref_summary_using_opensl_es\"\n            android:title=\"@string/pref_title_using_opensl_es\" />\n    </PreferenceCategory>\n    <PreferenceCategory android:title=\"@string/pref_title_render_view\">\n        <CheckBoxPreference\n            android:defaultValue=\"false\"\n            android:key=\"@string/pref_key_enable_no_view\"\n            android:persistent=\"true\"\n            android:summary=\"@string/pref_summary_enable_no_view\"\n            android:title=\"@string/pref_title_enable_no_view\" />\n        <CheckBoxPreference\n            android:defaultValue=\"false\"\n            android:key=\"@string/pref_key_enable_surface_view\"\n            android:persistent=\"true\"\n            android:summary=\"@string/pref_summary_enable_surface_view\"\n            android:title=\"@string/pref_title_enable_surface_view\" />\n        <CheckBoxPreference\n            android:defaultValue=\"false\"\n            android:key=\"@string/pref_key_enable_texture_view\"\n            android:persistent=\"true\"\n            android:summary=\"@string/pref_summary_enable_texture_view\"\n            android:title=\"@string/pref_title_enable_texture_view\" />\n        <CheckBoxPreference\n            android:defaultValue=\"false\"\n            android:key=\"@string/pref_key_enable_detached_surface_texture\"\n            android:persistent=\"true\"\n            android:summary=\"@string/pref_summary_enable_detached_surface_texture\"\n            android:title=\"@string/pref_title_enable_detached_surface_texture\" />\n    </PreferenceCategory>\n    <PreferenceCategory android:title=\"@string/pref_title_misc\">\n        <CheckBoxPreference\n            android:defaultValue=\"false\"\n            android:key=\"@string/pref_key_using_mediadatasource\"\n            android:persistent=\"true\"\n            android:summary=\"@string/pref_summary_using_mediadatasource\"\n            android:title=\"@string/pref_title_using_mediadatasource\" />\n    </PreferenceCategory>\n</PreferenceScreen>"
  },
  {
    "path": "android/ijkplayer/ijkplayer-exo/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-exo/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    // http://tools.android.com/tech-docs/new-build-system/tips\n    //noinspection GroovyAssignabilityCheck\n    compileSdkVersion rootProject.ext.compileSdkVersion\n    //noinspection GroovyAssignabilityCheck\n    buildToolsVersion rootProject.ext.buildToolsVersion\n\n    lintOptions {\n        abortOnError false\n    }\n    defaultConfig {\n        minSdkVersion 9\n        targetSdkVersion rootProject.ext.targetSdkVersion\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n\n    compile 'com.google.android.exoplayer:exoplayer:r1.5.11'\n\n    compile project(':ijkplayer-java')\n    // compile 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'\n}\n\ngradle.startParameter.taskNames.each { task ->\n    def subProjectName = task;\n    if (task.startsWith(':'))\n        subProjectName = task.split(\":\")[1]\n    if (subProjectName.equals(project.name))\n        apply from: new File(rootProject.projectDir, \"tools/gradle-on-demand.gradle\");\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-exo/gradle.properties",
    "content": "POM_NAME=ijkplayer-exo\nPOM_ARTIFACT_ID=ijkplayer-exo\nPOM_PACKAGING=aar"
  },
  {
    "path": "android/ijkplayer/ijkplayer-exo/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /opt/android/ADK/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-exo/src/androidTest/java/tv/danmaku/ijk/media/exo/ApplicationTest.java",
    "content": "package tv.danmaku.ijk.media.exo;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\"http://d.android.com/tools/testing/testing_android.html\">Testing Fundamentals</a>\n */\npublic class ApplicationTest extends ApplicationTestCase<Application> {\n    public ApplicationTest() {\n        super(Application.class);\n    }\n}"
  },
  {
    "path": "android/ijkplayer/ijkplayer-exo/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"tv.danmaku.ijk.media.exo\">\n\n    <application android:allowBackup=\"true\" android:label=\"@string/app_name\"\n        android:supportsRtl=\"true\">\n\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-exo/src/main/java/tv/danmaku/ijk/media/exo/IjkExoMediaPlayer.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.exo;\n\nimport android.content.Context;\nimport android.net.Uri;\nimport android.view.Surface;\nimport android.view.SurfaceHolder;\n\nimport com.google.android.exoplayer.ExoPlayer;\nimport com.google.android.exoplayer.util.Util;\n\nimport java.io.FileDescriptor;\nimport java.util.Map;\n\nimport tv.danmaku.ijk.media.exo.demo.EventLogger;\nimport tv.danmaku.ijk.media.exo.demo.player.DemoPlayer;\nimport tv.danmaku.ijk.media.exo.demo.player.DemoPlayer.RendererBuilder;\nimport tv.danmaku.ijk.media.exo.demo.player.ExtractorRendererBuilder;\nimport tv.danmaku.ijk.media.exo.demo.player.HlsRendererBuilder;\nimport tv.danmaku.ijk.media.exo.demo.player.SmoothStreamingRendererBuilder;\nimport tv.danmaku.ijk.media.exo.demo.SmoothStreamingTestMediaDrmCallback;\nimport tv.danmaku.ijk.media.player.AbstractMediaPlayer;\nimport tv.danmaku.ijk.media.player.IMediaPlayer;\nimport tv.danmaku.ijk.media.player.MediaInfo;\nimport tv.danmaku.ijk.media.player.misc.IjkTrackInfo;\n\npublic class IjkExoMediaPlayer extends AbstractMediaPlayer {\n    private Context mAppContext;\n    private DemoPlayer mInternalPlayer;\n    private EventLogger mEventLogger;\n    private String mDataSource;\n    private int mVideoWidth;\n    private int mVideoHeight;\n    private Surface mSurface;\n\n    private RendererBuilder mRendererBuilder;\n\n    public IjkExoMediaPlayer(Context context) {\n        mAppContext = context.getApplicationContext();\n\n        mDemoListener = new DemoPlayerListener();\n\n        mEventLogger = new EventLogger();\n        mEventLogger.startSession();\n    }\n\n    @Override\n    public void setDisplay(SurfaceHolder sh) {\n        if (sh == null)\n            setSurface(null);\n        else\n            setSurface(sh.getSurface());\n    }\n\n    @Override\n    public void setSurface(Surface surface) {\n        mSurface = surface;\n        if (mInternalPlayer != null)\n            mInternalPlayer.setSurface(surface);\n    }\n\n    @Override\n    public void setDataSource(Context context, Uri uri) {\n        mDataSource = uri.toString();\n        mRendererBuilder = getRendererBuilder();\n    }\n\n    @Override\n    public void setDataSource(Context context, Uri uri, Map<String, String> headers) {\n        // TODO: handle headers\n        setDataSource(context, uri);\n    }\n\n    @Override\n    public void setDataSource(String path) {\n        setDataSource(mAppContext, Uri.parse(path));\n    }\n\n    @Override\n    public void setDataSource(FileDescriptor fd) {\n        // TODO: no support\n        throw new UnsupportedOperationException(\"no support\");\n    }\n\n    @Override\n    public String getDataSource() {\n        return mDataSource;\n    }\n\n    @Override\n    public void prepareAsync() throws IllegalStateException {\n        if (mInternalPlayer != null)\n            throw new IllegalStateException(\"can't prepare a prepared player\");\n\n        mInternalPlayer = new DemoPlayer(mRendererBuilder);\n        mInternalPlayer.addListener(mDemoListener);\n        mInternalPlayer.addListener(mEventLogger);\n        mInternalPlayer.setInfoListener(mEventLogger);\n        mInternalPlayer.setInternalErrorListener(mEventLogger);\n\n        if (mSurface != null)\n            mInternalPlayer.setSurface(mSurface);\n\n        mInternalPlayer.prepare();\n        mInternalPlayer.setPlayWhenReady(false);\n    }\n\n    @Override\n    public void start() throws IllegalStateException {\n        if (mInternalPlayer == null)\n            return;\n        mInternalPlayer.setPlayWhenReady(true);\n    }\n\n    @Override\n    public void stop() throws IllegalStateException {\n        if (mInternalPlayer == null)\n            return;\n        mInternalPlayer.release();\n    }\n\n    @Override\n    public void pause() throws IllegalStateException {\n        if (mInternalPlayer == null)\n            return;\n        mInternalPlayer.setPlayWhenReady(false);\n    }\n\n    @Override\n    public void setWakeMode(Context context, int mode) {\n        // FIXME: implement\n    }\n\n    @Override\n    public void setScreenOnWhilePlaying(boolean screenOn) {\n        // TODO: do nothing\n    }\n\n    @Override\n    public IjkTrackInfo[] getTrackInfo() {\n        // TODO: implement\n        return null;\n    }\n\n    @Override\n    public int getVideoWidth() {\n        return mVideoWidth;\n    }\n\n    @Override\n    public int getVideoHeight() {\n        return mVideoHeight;\n    }\n\n    @Override\n    public boolean isPlaying() {\n        if (mInternalPlayer == null)\n            return false;\n        int state = mInternalPlayer.getPlaybackState();\n        switch (state) {\n            case ExoPlayer.STATE_BUFFERING:\n            case ExoPlayer.STATE_READY:\n                return mInternalPlayer.getPlayWhenReady();\n            case ExoPlayer.STATE_IDLE:\n            case ExoPlayer.STATE_PREPARING:\n            case ExoPlayer.STATE_ENDED:\n            default:\n                return false;\n        }\n    }\n\n    @Override\n    public void seekTo(long msec) throws IllegalStateException {\n        if (mInternalPlayer == null)\n            return;\n        mInternalPlayer.seekTo(msec);\n    }\n\n    @Override\n    public long getCurrentPosition() {\n        if (mInternalPlayer == null)\n            return 0;\n        return mInternalPlayer.getCurrentPosition();\n    }\n\n    @Override\n    public long getDuration() {\n        if (mInternalPlayer == null)\n            return 0;\n        return mInternalPlayer.getDuration();\n    }\n\n    @Override\n    public int getVideoSarNum() {\n        return 1;\n    }\n\n    @Override\n    public int getVideoSarDen() {\n        return 1;\n    }\n\n    @Override\n    public void reset() {\n        if (mInternalPlayer != null) {\n            mInternalPlayer.release();\n            mInternalPlayer.removeListener(mDemoListener);\n            mInternalPlayer.removeListener(mEventLogger);\n            mInternalPlayer.setInfoListener(null);\n            mInternalPlayer.setInternalErrorListener(null);\n            mInternalPlayer = null;\n        }\n\n        mSurface = null;\n        mDataSource = null;\n        mVideoWidth = 0;\n        mVideoHeight = 0;\n    }\n\n    @Override\n    public void setLooping(boolean looping) {\n        // TODO: no support\n        throw new UnsupportedOperationException(\"no support\");\n    }\n\n    @Override\n    public boolean isLooping() {\n        // TODO: no support\n        return false;\n    }\n\n    @Override\n    public void setVolume(float leftVolume, float rightVolume) {\n        // TODO: no support\n    }\n\n\n    @Override\n    public int getAudioSessionId() {\n        // TODO: no support\n        return 0;\n    }\n\n    @Override\n    public MediaInfo getMediaInfo() {\n        // TODO: no support\n        return null;\n    }\n\n    @Override\n    public void setLogEnabled(boolean enable) {\n        // do nothing\n    }\n\n    @Override\n    public boolean isPlayable() {\n        return true;\n    }\n\n    @Override\n    public void setAudioStreamType(int streamtype) {\n        // do nothing\n    }\n\n    @Override\n    public void setKeepInBackground(boolean keepInBackground) {\n        // do nothing\n    }\n\n    @Override\n    public void release() {\n        if (mInternalPlayer != null) {\n            reset();\n\n            mDemoListener = null;\n\n            mEventLogger.endSession();\n            mEventLogger = null;\n        }\n    }\n\n    public int getBufferedPercentage() {\n        if (mInternalPlayer == null)\n            return 0;\n\n        return mInternalPlayer.getBufferedPercentage();\n    }\n\n    private RendererBuilder getRendererBuilder() {\n        Uri contentUri = Uri.parse(mDataSource);\n        String userAgent = Util.getUserAgent(mAppContext, \"IjkExoMediaPlayer\");\n        int contentType = inferContentType(contentUri);\n        switch (contentType) {\n            case Util.TYPE_SS:\n                return new SmoothStreamingRendererBuilder(mAppContext, userAgent, contentUri.toString(),\n                        new SmoothStreamingTestMediaDrmCallback());\n         /*   case Util.TYPE_DASH:\n                return new DashRendererBuilder(mAppContext , userAgent, contentUri.toString(),\n                        new WidevineTestMediaDrmCallback(contentId, provider));*/\n            case Util.TYPE_HLS:\n                return new HlsRendererBuilder(mAppContext, userAgent, contentUri.toString());\n            case Util.TYPE_OTHER:\n            default:\n                return new ExtractorRendererBuilder(mAppContext, userAgent, contentUri);\n        }\n    }\n    \n    /**\n     * Makes a best guess to infer the type from a media {@link Uri}\n     *\n     * @param uri The {@link Uri} of the media.\n     * @return The inferred type.\n     */\n    private static int inferContentType(Uri uri) {\n        String lastPathSegment = uri.getLastPathSegment();\n        return Util.inferContentType(lastPathSegment);\n    }\n\n    private class DemoPlayerListener implements DemoPlayer.Listener {\n        private boolean mIsPrepareing = false;\n        private boolean mDidPrepare = false;\n        private boolean mIsBuffering = false;\n\n        public void onStateChanged(boolean playWhenReady, int playbackState)\n        {\n            if (mIsBuffering) {\n                switch (playbackState) {\n                    case ExoPlayer.STATE_ENDED:\n                    case ExoPlayer.STATE_READY:\n                        notifyOnInfo(IMediaPlayer.MEDIA_INFO_BUFFERING_END, mInternalPlayer.getBufferedPercentage());\n                        mIsBuffering = false;\n                        break;\n                }\n            }\n\n            if (mIsPrepareing) {\n                switch (playbackState) {\n                    case ExoPlayer.STATE_READY:\n                        notifyOnPrepared();\n                        mIsPrepareing = false;\n                        mDidPrepare = false;\n                        break;\n                }\n            }\n\n            switch (playbackState) {\n                case ExoPlayer.STATE_IDLE:\n                    notifyOnCompletion();\n                    break;\n                case ExoPlayer.STATE_PREPARING:\n                    mIsPrepareing = true;\n                    break;\n                case ExoPlayer.STATE_BUFFERING:\n                    notifyOnInfo(IMediaPlayer.MEDIA_INFO_BUFFERING_START, mInternalPlayer.getBufferedPercentage());\n                    mIsBuffering = true;\n                    break;\n                case ExoPlayer.STATE_READY:\n                    break;\n                case ExoPlayer.STATE_ENDED:\n                    notifyOnCompletion();\n                    break;\n                default:\n                    break;\n            }\n        }\n\n        public void onError(Exception e)\n        {\n            notifyOnError(IMediaPlayer.MEDIA_ERROR_UNKNOWN, IMediaPlayer.MEDIA_ERROR_UNKNOWN);\n        }\n\n        public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees,\n                                float pixelWidthHeightRatio)\n        {\n            mVideoWidth = width;\n            mVideoHeight = height;\n            notifyOnVideoSizeChanged(width, height, 1, 1);\n            if (unappliedRotationDegrees > 0)\n                notifyOnInfo(IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED, unappliedRotationDegrees);\n        }\n    }\n\n    private DemoPlayerListener mDemoListener;\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-exo/src/main/java/tv/danmaku/ijk/media/exo/demo/EventLogger.java",
    "content": "/*\n * Copyright (C) 2014 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage tv.danmaku.ijk.media.exo.demo;\n\nimport android.media.MediaCodec.CryptoException;\nimport android.os.SystemClock;\nimport android.util.Log;\nimport com.google.android.exoplayer.ExoPlayer;\nimport com.google.android.exoplayer.MediaCodecTrackRenderer.DecoderInitializationException;\nimport com.google.android.exoplayer.TimeRange;\nimport com.google.android.exoplayer.audio.AudioTrack;\nimport com.google.android.exoplayer.chunk.Format;\nimport tv.danmaku.ijk.media.exo.demo.player.DemoPlayer;\nimport com.google.android.exoplayer.util.VerboseLogUtil;\nimport java.io.IOException;\nimport java.text.NumberFormat;\nimport java.util.Locale;\n\n/**\n * Logs player events using {link Log}.\n */\npublic class EventLogger implements DemoPlayer.Listener, DemoPlayer.InfoListener,\n    DemoPlayer.InternalErrorListener {\n\n  private static final String TAG = \"EventLogger\";\n  private static final NumberFormat TIME_FORMAT;\n  static {\n    TIME_FORMAT = NumberFormat.getInstance(Locale.US);\n    TIME_FORMAT.setMinimumFractionDigits(2);\n    TIME_FORMAT.setMaximumFractionDigits(2);\n  }\n\n  private long sessionStartTimeMs;\n  private long[] loadStartTimeMs;\n  private long[] availableRangeValuesUs;\n\n  public EventLogger() {\n    loadStartTimeMs = new long[DemoPlayer.RENDERER_COUNT];\n  }\n\n  public void startSession() {\n    sessionStartTimeMs = SystemClock.elapsedRealtime();\n    Log.d(TAG, \"start [0]\");\n  }\n\n  public void endSession() {\n    Log.d(TAG, \"end [\" + getSessionTimeString() + \"]\");\n  }\n\n  // DemoPlayer.Listener\n\n  @Override\n  public void onStateChanged(boolean playWhenReady, int state) {\n    Log.d(TAG, \"state [\" + getSessionTimeString() + \", \" + playWhenReady + \", \"\n        + getStateString(state) + \"]\");\n  }\n\n  @Override\n  public void onError(Exception e) {\n    Log.e(TAG, \"playerFailed [\" + getSessionTimeString() + \"]\", e);\n  }\n\n  @Override\n  public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees,\n      float pixelWidthHeightRatio) {\n    Log.d(TAG, \"videoSizeChanged [\" + width + \", \" + height + \", \" + unappliedRotationDegrees\n        + \", \" + pixelWidthHeightRatio + \"]\");\n  }\n\n  // DemoPlayer.InfoListener\n\n  @Override\n  public void onBandwidthSample(int elapsedMs, long bytes, long bitrateEstimate) {\n    Log.d(TAG, \"bandwidth [\" + getSessionTimeString() + \", \" + bytes + \", \"\n        + getTimeString(elapsedMs) + \", \" + bitrateEstimate + \"]\");\n  }\n\n  @Override\n  public void onDroppedFrames(int count, long elapsed) {\n    Log.d(TAG, \"droppedFrames [\" + getSessionTimeString() + \", \" + count + \"]\");\n  }\n\n  @Override\n  public void onLoadStarted(int sourceId, long length, int type, int trigger, Format format,\n      long mediaStartTimeMs, long mediaEndTimeMs) {\n    loadStartTimeMs[sourceId] = SystemClock.elapsedRealtime();\n    if (VerboseLogUtil.isTagEnabled(TAG)) {\n      Log.v(TAG, \"loadStart [\" + getSessionTimeString() + \", \" + sourceId + \", \" + type\n          + \", \" + mediaStartTimeMs + \", \" + mediaEndTimeMs + \"]\");\n    }\n  }\n\n  @Override\n  public void onLoadCompleted(int sourceId, long bytesLoaded, int type, int trigger, Format format,\n       long mediaStartTimeMs, long mediaEndTimeMs, long elapsedRealtimeMs, long loadDurationMs) {\n    if (VerboseLogUtil.isTagEnabled(TAG)) {\n      long downloadTime = SystemClock.elapsedRealtime() - loadStartTimeMs[sourceId];\n      Log.v(TAG, \"loadEnd [\" + getSessionTimeString() + \", \" + sourceId + \", \" + downloadTime\n          + \"]\");\n    }\n  }\n\n  @Override\n  public void onVideoFormatEnabled(Format format, int trigger, long mediaTimeMs) {\n    Log.d(TAG, \"videoFormat [\" + getSessionTimeString() + \", \" + format.id + \", \"\n        + Integer.toString(trigger) + \"]\");\n  }\n\n  @Override\n  public void onAudioFormatEnabled(Format format, int trigger, long mediaTimeMs) {\n    Log.d(TAG, \"audioFormat [\" + getSessionTimeString() + \", \" + format.id + \", \"\n        + Integer.toString(trigger) + \"]\");\n  }\n\n  // DemoPlayer.InternalErrorListener\n\n  @Override\n  public void onLoadError(int sourceId, IOException e) {\n    printInternalError(\"loadError\", e);\n  }\n\n  @Override\n  public void onRendererInitializationError(Exception e) {\n    printInternalError(\"rendererInitError\", e);\n  }\n\n  @Override\n  public void onDrmSessionManagerError(Exception e) {\n    printInternalError(\"drmSessionManagerError\", e);\n  }\n\n  @Override\n  public void onDecoderInitializationError(DecoderInitializationException e) {\n    printInternalError(\"decoderInitializationError\", e);\n  }\n\n  @Override\n  public void onAudioTrackInitializationError(AudioTrack.InitializationException e) {\n    printInternalError(\"audioTrackInitializationError\", e);\n  }\n\n  @Override\n  public void onAudioTrackWriteError(AudioTrack.WriteException e) {\n    printInternalError(\"audioTrackWriteError\", e);\n  }\n\n  @Override\n  public void onAudioTrackUnderrun(int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) {\n    printInternalError(\"audioTrackUnderrun [\" + bufferSize + \", \" + bufferSizeMs + \", \"\n        + elapsedSinceLastFeedMs + \"]\", null);\n  }\n\n  @Override\n  public void onCryptoError(CryptoException e) {\n    printInternalError(\"cryptoError\", e);\n  }\n\n  @Override\n  public void onDecoderInitialized(String decoderName, long elapsedRealtimeMs,\n      long initializationDurationMs) {\n    Log.d(TAG, \"decoderInitialized [\" + getSessionTimeString() + \", \" + decoderName + \"]\");\n  }\n\n  @Override\n  public void onAvailableRangeChanged(int sourceId, TimeRange availableRange) {\n    availableRangeValuesUs = availableRange.getCurrentBoundsUs(availableRangeValuesUs);\n    Log.d(TAG, \"availableRange [\" + availableRange.isStatic() + \", \" + availableRangeValuesUs[0]\n        + \", \" + availableRangeValuesUs[1] + \"]\");\n  }\n\n  private void printInternalError(String type, Exception e) {\n    Log.e(TAG, \"internalError [\" + getSessionTimeString() + \", \" + type + \"]\", e);\n  }\n\n  private String getStateString(int state) {\n    switch (state) {\n      case ExoPlayer.STATE_BUFFERING:\n        return \"B\";\n      case ExoPlayer.STATE_ENDED:\n        return \"E\";\n      case ExoPlayer.STATE_IDLE:\n        return \"I\";\n      case ExoPlayer.STATE_PREPARING:\n        return \"P\";\n      case ExoPlayer.STATE_READY:\n        return \"R\";\n      default:\n        return \"?\";\n    }\n  }\n\n  private String getSessionTimeString() {\n    return getTimeString(SystemClock.elapsedRealtime() - sessionStartTimeMs);\n  }\n\n  private String getTimeString(long timeMs) {\n    return TIME_FORMAT.format((timeMs) / 1000f);\n  }\n\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-exo/src/main/java/tv/danmaku/ijk/media/exo/demo/SmoothStreamingTestMediaDrmCallback.java",
    "content": "/*\n * Copyright (C) 2014 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage tv.danmaku.ijk.media.exo.demo;\n\nimport android.annotation.TargetApi;\nimport android.text.TextUtils;\nimport com.google.android.exoplayer.drm.ExoMediaDrm.KeyRequest;\nimport com.google.android.exoplayer.drm.ExoMediaDrm.ProvisionRequest;\nimport com.google.android.exoplayer.drm.MediaDrmCallback;\nimport com.google.android.exoplayer.drm.StreamingDrmSessionManager;\nimport com.google.android.exoplayer.util.Util;\nimport java.io.IOException;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.UUID;\n\n/**\n * Demo {link StreamingDrmSessionManager} for smooth streaming test content.\n */\n@TargetApi(18)\npublic class SmoothStreamingTestMediaDrmCallback implements MediaDrmCallback {\n\n  private static final String PLAYREADY_TEST_DEFAULT_URI =\n      \"http://playready.directtaps.net/pr/svc/rightsmanager.asmx\";\n  private static final Map<String, String> PROVISIONING_REQUEST_PROPERTIES =\n      Collections.singletonMap(\"Content-Type\", \"application/octet-stream\");\n  private static final Map<String, String> KEY_REQUEST_PROPERTIES;\n  static {\n    HashMap<String, String> keyRequestProperties = new HashMap<>();\n    keyRequestProperties.put(\"Content-Type\", \"text/xml\");\n    keyRequestProperties.put(\"SOAPAction\",\n        \"http://schemas.microsoft.com/DRM/2007/03/protocols/AcquireLicense\");\n    KEY_REQUEST_PROPERTIES = keyRequestProperties;\n  }\n\n  @Override\n  public byte[] executeProvisionRequest(UUID uuid, ProvisionRequest request) throws IOException {\n    String url = request.getDefaultUrl() + \"&signedRequest=\" + new String(request.getData());\n    return Util.executePost(url, null, PROVISIONING_REQUEST_PROPERTIES);\n  }\n\n  @Override\n  public byte[] executeKeyRequest(UUID uuid, KeyRequest request) throws Exception {\n    String url = request.getDefaultUrl();\n    if (TextUtils.isEmpty(url)) {\n      url = PLAYREADY_TEST_DEFAULT_URI;\n    }\n    return Util.executePost(url, request.getData(), KEY_REQUEST_PROPERTIES);\n  }\n\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-exo/src/main/java/tv/danmaku/ijk/media/exo/demo/player/DashRendererBuilder.java",
    "content": "/*\n * Copyright (C) 2014 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage tv.danmaku.ijk.media.exo.demo.player;\n\nimport android.content.Context;\nimport android.media.AudioManager;\nimport android.media.MediaCodec;\nimport android.os.Handler;\nimport android.util.Log;\nimport com.google.android.exoplayer.DefaultLoadControl;\nimport com.google.android.exoplayer.LoadControl;\nimport com.google.android.exoplayer.MediaCodecAudioTrackRenderer;\nimport com.google.android.exoplayer.MediaCodecSelector;\nimport com.google.android.exoplayer.MediaCodecVideoTrackRenderer;\nimport com.google.android.exoplayer.TrackRenderer;\nimport com.google.android.exoplayer.audio.AudioCapabilities;\nimport com.google.android.exoplayer.chunk.ChunkSampleSource;\nimport com.google.android.exoplayer.chunk.ChunkSource;\nimport com.google.android.exoplayer.chunk.FormatEvaluator.AdaptiveEvaluator;\nimport com.google.android.exoplayer.dash.DashChunkSource;\nimport com.google.android.exoplayer.dash.DefaultDashTrackSelector;\nimport com.google.android.exoplayer.dash.mpd.AdaptationSet;\nimport com.google.android.exoplayer.dash.mpd.MediaPresentationDescription;\nimport com.google.android.exoplayer.dash.mpd.MediaPresentationDescriptionParser;\nimport com.google.android.exoplayer.dash.mpd.Period;\nimport com.google.android.exoplayer.dash.mpd.UtcTimingElement;\nimport com.google.android.exoplayer.dash.mpd.UtcTimingElementResolver;\nimport com.google.android.exoplayer.dash.mpd.UtcTimingElementResolver.UtcTimingCallback;\nimport tv.danmaku.ijk.media.exo.demo.player.DemoPlayer.RendererBuilder;\nimport com.google.android.exoplayer.drm.FrameworkMediaCrypto;\nimport com.google.android.exoplayer.drm.MediaDrmCallback;\nimport com.google.android.exoplayer.drm.StreamingDrmSessionManager;\nimport com.google.android.exoplayer.drm.UnsupportedDrmException;\nimport com.google.android.exoplayer.text.TextTrackRenderer;\nimport com.google.android.exoplayer.upstream.DataSource;\nimport com.google.android.exoplayer.upstream.DefaultAllocator;\nimport com.google.android.exoplayer.upstream.DefaultBandwidthMeter;\nimport com.google.android.exoplayer.upstream.DefaultUriDataSource;\nimport com.google.android.exoplayer.upstream.UriDataSource;\nimport com.google.android.exoplayer.util.ManifestFetcher;\nimport com.google.android.exoplayer.util.Util;\nimport java.io.IOException;\n\n/**\n * A {link RendererBuilder} for DASH.\n */\npublic class DashRendererBuilder implements RendererBuilder {\n\n  private static final String TAG = \"DashRendererBuilder\";\n\n  private static final int BUFFER_SEGMENT_SIZE = 64 * 1024;\n  private static final int VIDEO_BUFFER_SEGMENTS = 200;\n  private static final int AUDIO_BUFFER_SEGMENTS = 54;\n  private static final int TEXT_BUFFER_SEGMENTS = 2;\n  private static final int LIVE_EDGE_LATENCY_MS = 30000;\n\n  private static final int SECURITY_LEVEL_UNKNOWN = -1;\n  private static final int SECURITY_LEVEL_1 = 1;\n  private static final int SECURITY_LEVEL_3 = 3;\n\n  private final Context context;\n  private final String userAgent;\n  private final String url;\n  private final MediaDrmCallback drmCallback;\n\n  private AsyncRendererBuilder currentAsyncBuilder;\n\n  public DashRendererBuilder(Context context, String userAgent, String url,\n      MediaDrmCallback drmCallback) {\n    this.context = context;\n    this.userAgent = userAgent;\n    this.url = url;\n    this.drmCallback = drmCallback;\n  }\n\n  @Override\n  public void buildRenderers(DemoPlayer player) {\n    currentAsyncBuilder = new AsyncRendererBuilder(context, userAgent, url, drmCallback, player);\n    currentAsyncBuilder.init();\n  }\n\n  @Override\n  public void cancel() {\n    if (currentAsyncBuilder != null) {\n      currentAsyncBuilder.cancel();\n      currentAsyncBuilder = null;\n    }\n  }\n\n  private static final class AsyncRendererBuilder\n      implements ManifestFetcher.ManifestCallback<MediaPresentationDescription>, UtcTimingCallback {\n\n    private final Context context;\n    private final String userAgent;\n    private final MediaDrmCallback drmCallback;\n    private final DemoPlayer player;\n    private final ManifestFetcher<MediaPresentationDescription> manifestFetcher;\n    private final UriDataSource manifestDataSource;\n\n    private boolean canceled;\n    private MediaPresentationDescription manifest;\n    private long elapsedRealtimeOffset;\n\n    public AsyncRendererBuilder(Context context, String userAgent, String url,\n        MediaDrmCallback drmCallback, DemoPlayer player) {\n      this.context = context;\n      this.userAgent = userAgent;\n      this.drmCallback = drmCallback;\n      this.player = player;\n      MediaPresentationDescriptionParser parser = new MediaPresentationDescriptionParser();\n      manifestDataSource = new DefaultUriDataSource(context, userAgent);\n      manifestFetcher = new ManifestFetcher<>(url, manifestDataSource, parser);\n    }\n\n    public void init() {\n      manifestFetcher.singleLoad(player.getMainHandler().getLooper(), this);\n    }\n\n    public void cancel() {\n      canceled = true;\n    }\n\n    @Override\n    public void onSingleManifest(MediaPresentationDescription manifest) {\n      if (canceled) {\n        return;\n      }\n\n      this.manifest = manifest;\n      if (manifest.dynamic && manifest.utcTiming != null) {\n        UtcTimingElementResolver.resolveTimingElement(manifestDataSource, manifest.utcTiming,\n            manifestFetcher.getManifestLoadCompleteTimestamp(), this);\n      } else {\n        buildRenderers();\n      }\n    }\n\n    @Override\n    public void onSingleManifestError(IOException e) {\n      if (canceled) {\n        return;\n      }\n\n      player.onRenderersError(e);\n    }\n\n    @Override\n    public void onTimestampResolved(UtcTimingElement utcTiming, long elapsedRealtimeOffset) {\n      if (canceled) {\n        return;\n      }\n\n      this.elapsedRealtimeOffset = elapsedRealtimeOffset;\n      buildRenderers();\n    }\n\n    @Override\n    public void onTimestampError(UtcTimingElement utcTiming, IOException e) {\n      if (canceled) {\n        return;\n      }\n\n      Log.e(TAG, \"Failed to resolve UtcTiming element [\" + utcTiming + \"]\", e);\n      // Be optimistic and continue in the hope that the device clock is correct.\n      buildRenderers();\n    }\n\n    private void buildRenderers() {\n      Period period = manifest.getPeriod(0);\n      Handler mainHandler = player.getMainHandler();\n      LoadControl loadControl = new DefaultLoadControl(new DefaultAllocator(BUFFER_SEGMENT_SIZE));\n      DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter(mainHandler, player);\n\n      boolean hasContentProtection = false;\n      for (int i = 0; i < period.adaptationSets.size(); i++) {\n        AdaptationSet adaptationSet = period.adaptationSets.get(i);\n        if (adaptationSet.type != AdaptationSet.TYPE_UNKNOWN) {\n          hasContentProtection |= adaptationSet.hasContentProtection();\n        }\n      }\n\n      // Check drm support if necessary.\n      boolean filterHdContent = false;\n      StreamingDrmSessionManager<FrameworkMediaCrypto> drmSessionManager = null;\n      if (hasContentProtection) {\n        if (Util.SDK_INT < 18) {\n          player.onRenderersError(\n              new UnsupportedDrmException(UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME));\n          return;\n        }\n        try {\n          drmSessionManager = StreamingDrmSessionManager.newWidevineInstance(\n              player.getPlaybackLooper(), drmCallback, null, player.getMainHandler(), player);\n          filterHdContent = getWidevineSecurityLevel(drmSessionManager) != SECURITY_LEVEL_1;\n        } catch (UnsupportedDrmException e) {\n          player.onRenderersError(e);\n          return;\n        }\n      }\n\n      // Build the video renderer.\n      DataSource videoDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);\n      ChunkSource videoChunkSource = new DashChunkSource(manifestFetcher,\n          DefaultDashTrackSelector.newVideoInstance(context, true, filterHdContent),\n          videoDataSource, new AdaptiveEvaluator(bandwidthMeter), LIVE_EDGE_LATENCY_MS,\n          elapsedRealtimeOffset, mainHandler, player, DemoPlayer.TYPE_VIDEO);\n      ChunkSampleSource videoSampleSource = new ChunkSampleSource(videoChunkSource, loadControl,\n          VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player,\n          DemoPlayer.TYPE_VIDEO);\n      TrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(context, videoSampleSource,\n          MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000,\n          drmSessionManager, true, mainHandler, player, 50);\n\n      // Build the audio renderer.\n      DataSource audioDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);\n      ChunkSource audioChunkSource = new DashChunkSource(manifestFetcher,\n          DefaultDashTrackSelector.newAudioInstance(), audioDataSource, null, LIVE_EDGE_LATENCY_MS,\n          elapsedRealtimeOffset, mainHandler, player, DemoPlayer.TYPE_AUDIO);\n      ChunkSampleSource audioSampleSource = new ChunkSampleSource(audioChunkSource, loadControl,\n          AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player,\n          DemoPlayer.TYPE_AUDIO);\n      TrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(audioSampleSource,\n          MediaCodecSelector.DEFAULT, drmSessionManager, true, mainHandler, player,\n          AudioCapabilities.getCapabilities(context), AudioManager.STREAM_MUSIC);\n\n      // Build the text renderer.\n      DataSource textDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);\n      ChunkSource textChunkSource = new DashChunkSource(manifestFetcher,\n          DefaultDashTrackSelector.newTextInstance(), textDataSource, null, LIVE_EDGE_LATENCY_MS,\n          elapsedRealtimeOffset, mainHandler, player, DemoPlayer.TYPE_TEXT);\n      ChunkSampleSource textSampleSource = new ChunkSampleSource(textChunkSource, loadControl,\n          TEXT_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player,\n          DemoPlayer.TYPE_TEXT);\n      TrackRenderer textRenderer = new TextTrackRenderer(textSampleSource, player,\n          mainHandler.getLooper());\n\n      // Invoke the callback.\n      TrackRenderer[] renderers = new TrackRenderer[DemoPlayer.RENDERER_COUNT];\n      renderers[DemoPlayer.TYPE_VIDEO] = videoRenderer;\n      renderers[DemoPlayer.TYPE_AUDIO] = audioRenderer;\n      renderers[DemoPlayer.TYPE_TEXT] = textRenderer;\n      player.onRenderers(renderers, bandwidthMeter);\n    }\n\n    private static int getWidevineSecurityLevel(StreamingDrmSessionManager sessionManager) {\n      String securityLevelProperty = sessionManager.getPropertyString(\"securityLevel\");\n      return securityLevelProperty.equals(\"L1\") ? SECURITY_LEVEL_1 : securityLevelProperty\n          .equals(\"L3\") ? SECURITY_LEVEL_3 : SECURITY_LEVEL_UNKNOWN;\n    }\n\n  }\n\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-exo/src/main/java/tv/danmaku/ijk/media/exo/demo/player/DemoPlayer.java",
    "content": "/*\n * Copyright (C) 2014 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage tv.danmaku.ijk.media.exo.demo.player;\n\nimport android.media.MediaCodec.CryptoException;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.view.Surface;\nimport com.google.android.exoplayer.CodecCounters;\nimport com.google.android.exoplayer.DummyTrackRenderer;\nimport com.google.android.exoplayer.ExoPlaybackException;\nimport com.google.android.exoplayer.ExoPlayer;\nimport com.google.android.exoplayer.MediaCodecAudioTrackRenderer;\nimport com.google.android.exoplayer.MediaCodecTrackRenderer;\nimport com.google.android.exoplayer.MediaCodecTrackRenderer.DecoderInitializationException;\nimport com.google.android.exoplayer.MediaCodecVideoTrackRenderer;\nimport com.google.android.exoplayer.MediaFormat;\nimport com.google.android.exoplayer.SingleSampleSource;\nimport com.google.android.exoplayer.TimeRange;\nimport com.google.android.exoplayer.TrackRenderer;\nimport com.google.android.exoplayer.audio.AudioTrack;\nimport com.google.android.exoplayer.chunk.ChunkSampleSource;\nimport com.google.android.exoplayer.chunk.Format;\nimport com.google.android.exoplayer.dash.DashChunkSource;\nimport com.google.android.exoplayer.drm.StreamingDrmSessionManager;\nimport com.google.android.exoplayer.extractor.ExtractorSampleSource;\nimport com.google.android.exoplayer.hls.HlsSampleSource;\nimport com.google.android.exoplayer.metadata.MetadataTrackRenderer.MetadataRenderer;\nimport com.google.android.exoplayer.metadata.id3.Id3Frame;\nimport com.google.android.exoplayer.text.Cue;\nimport com.google.android.exoplayer.text.TextRenderer;\nimport com.google.android.exoplayer.upstream.BandwidthMeter;\nimport com.google.android.exoplayer.upstream.DefaultBandwidthMeter;\nimport com.google.android.exoplayer.util.DebugTextViewHelper;\nimport com.google.android.exoplayer.util.PlayerControl;\nimport java.io.IOException;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.CopyOnWriteArrayList;\n\n/**\n * A wrapper around {link ExoPlayer} that provides a higher level interface. It can be prepared\n * with one of a number of {link RendererBuilder} classes to suit different use cases (e.g. DASH,\n * SmoothStreaming and so on).\n */\npublic class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventListener,\n    HlsSampleSource.EventListener, ExtractorSampleSource.EventListener,\n    SingleSampleSource.EventListener, DefaultBandwidthMeter.EventListener,\n    MediaCodecVideoTrackRenderer.EventListener, MediaCodecAudioTrackRenderer.EventListener,\n    StreamingDrmSessionManager.EventListener, DashChunkSource.EventListener, TextRenderer,\n    MetadataRenderer<List<Id3Frame>>, DebugTextViewHelper.Provider {\n\n  /**\n   * Builds renderers for the player.\n   */\n  public interface RendererBuilder {\n    /**\n     * Builds renderers for playback.\n     *\n     * @param player The player for which renderers are being built. {link DemoPlayer#onRenderers}\n     *     should be invoked once the renderers have been built. If building fails,\n     *     {link DemoPlayer#onRenderersError} should be invoked.\n     */\n    void buildRenderers(DemoPlayer player);\n    /**\n     * Cancels the current build operation, if there is one. Else does nothing.\n     * <p>\n     * A canceled build operation must not invoke {link DemoPlayer#onRenderers} or\n     * {link DemoPlayer#onRenderersError} on the player, which may have been released.\n     */\n    void cancel();\n  }\n\n  /**\n   * A listener for core events.\n   */\n  public interface Listener {\n    void onStateChanged(boolean playWhenReady, int playbackState);\n    void onError(Exception e);\n    void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees,\n        float pixelWidthHeightRatio);\n  }\n\n  /**\n   * A listener for internal errors.\n   * <p>\n   * These errors are not visible to the user, and hence this listener is provided for\n   * informational purposes only. Note however that an internal error may cause a fatal\n   * error if the player fails to recover. If this happens, {link Listener#onError(Exception)}\n   * will be invoked.\n   */\n  public interface InternalErrorListener {\n    void onRendererInitializationError(Exception e);\n    void onAudioTrackInitializationError(AudioTrack.InitializationException e);\n    void onAudioTrackWriteError(AudioTrack.WriteException e);\n    void onAudioTrackUnderrun(int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs);\n    void onDecoderInitializationError(DecoderInitializationException e);\n    void onCryptoError(CryptoException e);\n    void onLoadError(int sourceId, IOException e);\n    void onDrmSessionManagerError(Exception e);\n  }\n\n  /**\n   * A listener for debugging information.\n   */\n  public interface InfoListener {\n    void onVideoFormatEnabled(Format format, int trigger, long mediaTimeMs);\n    void onAudioFormatEnabled(Format format, int trigger, long mediaTimeMs);\n    void onDroppedFrames(int count, long elapsed);\n    void onBandwidthSample(int elapsedMs, long bytes, long bitrateEstimate);\n    void onLoadStarted(int sourceId, long length, int type, int trigger, Format format,\n        long mediaStartTimeMs, long mediaEndTimeMs);\n    void onLoadCompleted(int sourceId, long bytesLoaded, int type, int trigger, Format format,\n        long mediaStartTimeMs, long mediaEndTimeMs, long elapsedRealtimeMs, long loadDurationMs);\n    void onDecoderInitialized(String decoderName, long elapsedRealtimeMs,\n        long initializationDurationMs);\n    void onAvailableRangeChanged(int sourceId, TimeRange availableRange);\n  }\n\n  /**\n   * A listener for receiving notifications of timed text.\n   */\n  public interface CaptionListener {\n    void onCues(List<Cue> cues);\n  }\n\n  /**\n   * A listener for receiving ID3 metadata parsed from the media stream.\n   */\n  public interface Id3MetadataListener {\n    void onId3Metadata(List<Id3Frame> id3Frames);\n  }\n\n  // Constants pulled into this class for convenience.\n  public static final int STATE_IDLE = ExoPlayer.STATE_IDLE;\n  public static final int STATE_PREPARING = ExoPlayer.STATE_PREPARING;\n  public static final int STATE_BUFFERING = ExoPlayer.STATE_BUFFERING;\n  public static final int STATE_READY = ExoPlayer.STATE_READY;\n  public static final int STATE_ENDED = ExoPlayer.STATE_ENDED;\n  public static final int TRACK_DISABLED = ExoPlayer.TRACK_DISABLED;\n  public static final int TRACK_DEFAULT = ExoPlayer.TRACK_DEFAULT;\n\n  public static final int RENDERER_COUNT = 4;\n  public static final int TYPE_VIDEO = 0;\n  public static final int TYPE_AUDIO = 1;\n  public static final int TYPE_TEXT = 2;\n  public static final int TYPE_METADATA = 3;\n\n  private static final int RENDERER_BUILDING_STATE_IDLE = 1;\n  private static final int RENDERER_BUILDING_STATE_BUILDING = 2;\n  private static final int RENDERER_BUILDING_STATE_BUILT = 3;\n\n  private final RendererBuilder rendererBuilder;\n  private final ExoPlayer player;\n  private final PlayerControl playerControl;\n  private final Handler mainHandler;\n  private final CopyOnWriteArrayList<Listener> listeners;\n\n  private int rendererBuildingState;\n  private int lastReportedPlaybackState;\n  private boolean lastReportedPlayWhenReady;\n\n  private Surface surface;\n  private TrackRenderer videoRenderer;\n  private CodecCounters codecCounters;\n  private Format videoFormat;\n  private int videoTrackToRestore;\n\n  private BandwidthMeter bandwidthMeter;\n  private boolean backgrounded;\n\n  private CaptionListener captionListener;\n  private Id3MetadataListener id3MetadataListener;\n  private InternalErrorListener internalErrorListener;\n  private InfoListener infoListener;\n\n  public DemoPlayer(RendererBuilder rendererBuilder) {\n    this.rendererBuilder = rendererBuilder;\n    player = ExoPlayer.Factory.newInstance(RENDERER_COUNT, 1000, 5000);\n    player.addListener(this);\n    playerControl = new PlayerControl(player);\n    mainHandler = new Handler();\n    listeners = new CopyOnWriteArrayList<>();\n    lastReportedPlaybackState = STATE_IDLE;\n    rendererBuildingState = RENDERER_BUILDING_STATE_IDLE;\n    // Disable text initially.\n    player.setSelectedTrack(TYPE_TEXT, TRACK_DISABLED);\n  }\n\n  public PlayerControl getPlayerControl() {\n    return playerControl;\n  }\n\n  public void addListener(Listener listener) {\n    listeners.add(listener);\n  }\n\n  public void removeListener(Listener listener) {\n    listeners.remove(listener);\n  }\n\n  public void setInternalErrorListener(InternalErrorListener listener) {\n    internalErrorListener = listener;\n  }\n\n  public void setInfoListener(InfoListener listener) {\n    infoListener = listener;\n  }\n\n  public void setCaptionListener(CaptionListener listener) {\n    captionListener = listener;\n  }\n\n  public void setMetadataListener(Id3MetadataListener listener) {\n    id3MetadataListener = listener;\n  }\n\n  public void setSurface(Surface surface) {\n    this.surface = surface;\n    pushSurface(false);\n  }\n\n  public Surface getSurface() {\n    return surface;\n  }\n\n  public void blockingClearSurface() {\n    surface = null;\n    pushSurface(true);\n  }\n\n  public int getTrackCount(int type) {\n    return player.getTrackCount(type);\n  }\n\n  public MediaFormat getTrackFormat(int type, int index) {\n    return player.getTrackFormat(type, index);\n  }\n\n  public int getSelectedTrack(int type) {\n    return player.getSelectedTrack(type);\n  }\n\n  public void setSelectedTrack(int type, int index) {\n    player.setSelectedTrack(type, index);\n    if (type == TYPE_TEXT && index < 0 && captionListener != null) {\n      captionListener.onCues(Collections.<Cue>emptyList());\n    }\n  }\n\n  public boolean getBackgrounded() {\n    return backgrounded;\n  }\n\n  public void setBackgrounded(boolean backgrounded) {\n    if (this.backgrounded == backgrounded) {\n      return;\n    }\n    this.backgrounded = backgrounded;\n    if (backgrounded) {\n      videoTrackToRestore = getSelectedTrack(TYPE_VIDEO);\n      setSelectedTrack(TYPE_VIDEO, TRACK_DISABLED);\n      blockingClearSurface();\n    } else {\n      setSelectedTrack(TYPE_VIDEO, videoTrackToRestore);\n    }\n  }\n\n  public void prepare() {\n    if (rendererBuildingState == RENDERER_BUILDING_STATE_BUILT) {\n      player.stop();\n    }\n    rendererBuilder.cancel();\n    videoFormat = null;\n    videoRenderer = null;\n    rendererBuildingState = RENDERER_BUILDING_STATE_BUILDING;\n    maybeReportPlayerState();\n    rendererBuilder.buildRenderers(this);\n  }\n\n  /**\n   * Invoked with the results from a {link RendererBuilder}.\n   *\n   * @param renderers Renderers indexed by {link DemoPlayer} TYPE_* constants. An individual\n   *     element may be null if there do not exist tracks of the corresponding type.\n   * @param bandwidthMeter Provides an estimate of the currently available bandwidth. May be null.\n   */\n  /* package */ void onRenderers(TrackRenderer[] renderers, BandwidthMeter bandwidthMeter) {\n    for (int i = 0; i < RENDERER_COUNT; i++) {\n      if (renderers[i] == null) {\n        // Convert a null renderer to a dummy renderer.\n        renderers[i] = new DummyTrackRenderer();\n      }\n    }\n    // Complete preparation.\n    this.videoRenderer = renderers[TYPE_VIDEO];\n    this.codecCounters = videoRenderer instanceof MediaCodecTrackRenderer\n        ? ((MediaCodecTrackRenderer) videoRenderer).codecCounters\n        : renderers[TYPE_AUDIO] instanceof MediaCodecTrackRenderer\n        ? ((MediaCodecTrackRenderer) renderers[TYPE_AUDIO]).codecCounters : null;\n    this.bandwidthMeter = bandwidthMeter;\n    pushSurface(false);\n    player.prepare(renderers);\n    rendererBuildingState = RENDERER_BUILDING_STATE_BUILT;\n  }\n\n  /**\n   * Invoked if a {link RendererBuilder} encounters an error.\n   *\n   * @param e Describes the error.\n   */\n  /* package */ void onRenderersError(Exception e) {\n    if (internalErrorListener != null) {\n      internalErrorListener.onRendererInitializationError(e);\n    }\n    for (Listener listener : listeners) {\n      listener.onError(e);\n    }\n    rendererBuildingState = RENDERER_BUILDING_STATE_IDLE;\n    maybeReportPlayerState();\n  }\n\n  public void setPlayWhenReady(boolean playWhenReady) {\n    player.setPlayWhenReady(playWhenReady);\n  }\n\n  public void seekTo(long positionMs) {\n    player.seekTo(positionMs);\n  }\n\n  public void release() {\n    rendererBuilder.cancel();\n    rendererBuildingState = RENDERER_BUILDING_STATE_IDLE;\n    surface = null;\n    player.release();\n  }\n\n  public int getPlaybackState() {\n    if (rendererBuildingState == RENDERER_BUILDING_STATE_BUILDING) {\n      return STATE_PREPARING;\n    }\n    int playerState = player.getPlaybackState();\n    if (rendererBuildingState == RENDERER_BUILDING_STATE_BUILT && playerState == STATE_IDLE) {\n      // This is an edge case where the renderers are built, but are still being passed to the\n      // player's playback thread.\n      return STATE_PREPARING;\n    }\n    return playerState;\n  }\n\n  @Override\n  public Format getFormat() {\n    return videoFormat;\n  }\n\n  @Override\n  public BandwidthMeter getBandwidthMeter() {\n    return bandwidthMeter;\n  }\n\n  @Override\n  public CodecCounters getCodecCounters() {\n    return codecCounters;\n  }\n\n  @Override\n  public long getCurrentPosition() {\n    return player.getCurrentPosition();\n  }\n\n  public long getDuration() {\n    return player.getDuration();\n  }\n\n  public int getBufferedPercentage() {\n    return player.getBufferedPercentage();\n  }\n\n  public boolean getPlayWhenReady() {\n    return player.getPlayWhenReady();\n  }\n\n  /* package */ Looper getPlaybackLooper() {\n    return player.getPlaybackLooper();\n  }\n\n  /* package */ Handler getMainHandler() {\n    return mainHandler;\n  }\n\n  @Override\n  public void onPlayerStateChanged(boolean playWhenReady, int state) {\n    maybeReportPlayerState();\n  }\n\n  @Override\n  public void onPlayerError(ExoPlaybackException exception) {\n    rendererBuildingState = RENDERER_BUILDING_STATE_IDLE;\n    for (Listener listener : listeners) {\n      listener.onError(exception);\n    }\n  }\n\n  @Override\n  public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees,\n      float pixelWidthHeightRatio) {\n    for (Listener listener : listeners) {\n      listener.onVideoSizeChanged(width, height, unappliedRotationDegrees, pixelWidthHeightRatio);\n    }\n  }\n\n  @Override\n  public void onDroppedFrames(int count, long elapsed) {\n    if (infoListener != null) {\n      infoListener.onDroppedFrames(count, elapsed);\n    }\n  }\n\n  @Override\n  public void onBandwidthSample(int elapsedMs, long bytes, long bitrateEstimate) {\n    if (infoListener != null) {\n      infoListener.onBandwidthSample(elapsedMs, bytes, bitrateEstimate);\n    }\n  }\n\n  @Override\n  public void onDownstreamFormatChanged(int sourceId, Format format, int trigger,\n      long mediaTimeMs) {\n    if (infoListener == null) {\n      return;\n    }\n    if (sourceId == TYPE_VIDEO) {\n      videoFormat = format;\n      infoListener.onVideoFormatEnabled(format, trigger, mediaTimeMs);\n    } else if (sourceId == TYPE_AUDIO) {\n      infoListener.onAudioFormatEnabled(format, trigger, mediaTimeMs);\n    }\n  }\n\n  @Override\n  public void onDrmKeysLoaded() {\n    // Do nothing.\n  }\n\n  @Override\n  public void onDrmSessionManagerError(Exception e) {\n    if (internalErrorListener != null) {\n      internalErrorListener.onDrmSessionManagerError(e);\n    }\n  }\n\n  @Override\n  public void onDecoderInitializationError(DecoderInitializationException e) {\n    if (internalErrorListener != null) {\n      internalErrorListener.onDecoderInitializationError(e);\n    }\n  }\n\n  @Override\n  public void onAudioTrackInitializationError(AudioTrack.InitializationException e) {\n    if (internalErrorListener != null) {\n      internalErrorListener.onAudioTrackInitializationError(e);\n    }\n  }\n\n  @Override\n  public void onAudioTrackWriteError(AudioTrack.WriteException e) {\n    if (internalErrorListener != null) {\n      internalErrorListener.onAudioTrackWriteError(e);\n    }\n  }\n\n  @Override\n  public void onAudioTrackUnderrun(int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) {\n    if (internalErrorListener != null) {\n      internalErrorListener.onAudioTrackUnderrun(bufferSize, bufferSizeMs, elapsedSinceLastFeedMs);\n    }\n  }\n\n  @Override\n  public void onCryptoError(CryptoException e) {\n    if (internalErrorListener != null) {\n      internalErrorListener.onCryptoError(e);\n    }\n  }\n\n  @Override\n  public void onDecoderInitialized(String decoderName, long elapsedRealtimeMs,\n      long initializationDurationMs) {\n    if (infoListener != null) {\n      infoListener.onDecoderInitialized(decoderName, elapsedRealtimeMs, initializationDurationMs);\n    }\n  }\n\n  @Override\n  public void onLoadError(int sourceId, IOException e) {\n    if (internalErrorListener != null) {\n      internalErrorListener.onLoadError(sourceId, e);\n    }\n  }\n\n  @Override\n  public void onCues(List<Cue> cues) {\n    if (captionListener != null && getSelectedTrack(TYPE_TEXT) != TRACK_DISABLED) {\n      captionListener.onCues(cues);\n    }\n  }\n\n  @Override\n  public void onMetadata(List<Id3Frame> id3Frames) {\n    if (id3MetadataListener != null && getSelectedTrack(TYPE_METADATA) != TRACK_DISABLED) {\n      id3MetadataListener.onId3Metadata(id3Frames);\n    }\n  }\n\n  @Override\n  public void onAvailableRangeChanged(int sourceId, TimeRange availableRange) {\n    if (infoListener != null) {\n      infoListener.onAvailableRangeChanged(sourceId, availableRange);\n    }\n  }\n\n  @Override\n  public void onPlayWhenReadyCommitted() {\n    // Do nothing.\n  }\n\n  @Override\n  public void onDrawnToSurface(Surface surface) {\n    // Do nothing.\n  }\n\n  @Override\n  public void onLoadStarted(int sourceId, long length, int type, int trigger, Format format,\n      long mediaStartTimeMs, long mediaEndTimeMs) {\n    if (infoListener != null) {\n      infoListener.onLoadStarted(sourceId, length, type, trigger, format, mediaStartTimeMs,\n          mediaEndTimeMs);\n    }\n  }\n\n  @Override\n  public void onLoadCompleted(int sourceId, long bytesLoaded, int type, int trigger, Format format,\n      long mediaStartTimeMs, long mediaEndTimeMs, long elapsedRealtimeMs, long loadDurationMs) {\n    if (infoListener != null) {\n      infoListener.onLoadCompleted(sourceId, bytesLoaded, type, trigger, format, mediaStartTimeMs,\n          mediaEndTimeMs, elapsedRealtimeMs, loadDurationMs);\n    }\n  }\n\n  @Override\n  public void onLoadCanceled(int sourceId, long bytesLoaded) {\n    // Do nothing.\n  }\n\n  @Override\n  public void onUpstreamDiscarded(int sourceId, long mediaStartTimeMs, long mediaEndTimeMs) {\n    // Do nothing.\n  }\n\n  private void maybeReportPlayerState() {\n    boolean playWhenReady = player.getPlayWhenReady();\n    int playbackState = getPlaybackState();\n    if (lastReportedPlayWhenReady != playWhenReady || lastReportedPlaybackState != playbackState) {\n      for (Listener listener : listeners) {\n        listener.onStateChanged(playWhenReady, playbackState);\n      }\n      lastReportedPlayWhenReady = playWhenReady;\n      lastReportedPlaybackState = playbackState;\n    }\n  }\n\n  private void pushSurface(boolean blockForSurfacePush) {\n    if (videoRenderer == null) {\n      return;\n    }\n\n    if (blockForSurfacePush) {\n      player.blockingSendMessage(\n          videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, surface);\n    } else {\n      player.sendMessage(\n          videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, surface);\n    }\n  }\n\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-exo/src/main/java/tv/danmaku/ijk/media/exo/demo/player/ExtractorRendererBuilder.java",
    "content": "/*\n * Copyright (C) 2014 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage tv.danmaku.ijk.media.exo.demo.player;\n\nimport android.content.Context;\nimport android.media.AudioManager;\nimport android.media.MediaCodec;\nimport android.net.Uri;\nimport android.os.Handler;\nimport com.google.android.exoplayer.MediaCodecAudioTrackRenderer;\nimport com.google.android.exoplayer.MediaCodecSelector;\nimport com.google.android.exoplayer.MediaCodecVideoTrackRenderer;\nimport com.google.android.exoplayer.TrackRenderer;\nimport com.google.android.exoplayer.audio.AudioCapabilities;\nimport tv.danmaku.ijk.media.exo.demo.player.DemoPlayer.RendererBuilder;\nimport com.google.android.exoplayer.extractor.Extractor;\nimport com.google.android.exoplayer.extractor.ExtractorSampleSource;\nimport com.google.android.exoplayer.text.TextTrackRenderer;\nimport com.google.android.exoplayer.upstream.Allocator;\nimport com.google.android.exoplayer.upstream.DataSource;\nimport com.google.android.exoplayer.upstream.DefaultAllocator;\nimport com.google.android.exoplayer.upstream.DefaultBandwidthMeter;\nimport com.google.android.exoplayer.upstream.DefaultUriDataSource;\n\n/**\n * A {link RendererBuilder} for streams that can be read using an {link Extractor}.\n */\npublic class ExtractorRendererBuilder implements RendererBuilder {\n\n  private static final int BUFFER_SEGMENT_SIZE = 64 * 1024;\n  private static final int BUFFER_SEGMENT_COUNT = 256;\n\n  private final Context context;\n  private final String userAgent;\n  private final Uri uri;\n\n  public ExtractorRendererBuilder(Context context, String userAgent, Uri uri) {\n    this.context = context;\n    this.userAgent = userAgent;\n    this.uri = uri;\n  }\n\n  @Override\n  public void buildRenderers(DemoPlayer player) {\n    Allocator allocator = new DefaultAllocator(BUFFER_SEGMENT_SIZE);\n    Handler mainHandler = player.getMainHandler();\n\n    // Build the video and audio renderers.\n    DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter(mainHandler, null);\n    DataSource dataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);\n    ExtractorSampleSource sampleSource = new ExtractorSampleSource(uri, dataSource, allocator,\n        BUFFER_SEGMENT_COUNT * BUFFER_SEGMENT_SIZE, mainHandler, player, 0);\n    MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(context,\n        sampleSource, MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000,\n        mainHandler, player, 50);\n    MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource,\n        MediaCodecSelector.DEFAULT, null, true, mainHandler, player,\n        AudioCapabilities.getCapabilities(context), AudioManager.STREAM_MUSIC);\n    TrackRenderer textRenderer = new TextTrackRenderer(sampleSource, player,\n        mainHandler.getLooper());\n\n    // Invoke the callback.\n    TrackRenderer[] renderers = new TrackRenderer[DemoPlayer.RENDERER_COUNT];\n    renderers[DemoPlayer.TYPE_VIDEO] = videoRenderer;\n    renderers[DemoPlayer.TYPE_AUDIO] = audioRenderer;\n    renderers[DemoPlayer.TYPE_TEXT] = textRenderer;\n    player.onRenderers(renderers, bandwidthMeter);\n  }\n\n  @Override\n  public void cancel() {\n    // Do nothing.\n  }\n\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-exo/src/main/java/tv/danmaku/ijk/media/exo/demo/player/HlsRendererBuilder.java",
    "content": "/*\n * Copyright (C) 2014 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage tv.danmaku.ijk.media.exo.demo.player;\n\nimport android.content.Context;\nimport android.media.AudioManager;\nimport android.media.MediaCodec;\nimport android.os.Handler;\nimport com.google.android.exoplayer.DefaultLoadControl;\nimport com.google.android.exoplayer.LoadControl;\nimport com.google.android.exoplayer.MediaCodecAudioTrackRenderer;\nimport com.google.android.exoplayer.MediaCodecSelector;\nimport com.google.android.exoplayer.MediaCodecVideoTrackRenderer;\nimport com.google.android.exoplayer.SampleSource;\nimport com.google.android.exoplayer.TrackRenderer;\nimport com.google.android.exoplayer.audio.AudioCapabilities;\nimport tv.danmaku.ijk.media.exo.demo.player.DemoPlayer.RendererBuilder;\nimport com.google.android.exoplayer.hls.DefaultHlsTrackSelector;\nimport com.google.android.exoplayer.hls.HlsChunkSource;\nimport com.google.android.exoplayer.hls.HlsMasterPlaylist;\nimport com.google.android.exoplayer.hls.HlsPlaylist;\nimport com.google.android.exoplayer.hls.HlsPlaylistParser;\nimport com.google.android.exoplayer.hls.HlsSampleSource;\nimport com.google.android.exoplayer.hls.PtsTimestampAdjusterProvider;\nimport com.google.android.exoplayer.metadata.MetadataTrackRenderer;\nimport com.google.android.exoplayer.metadata.id3.Id3Frame;\nimport com.google.android.exoplayer.metadata.id3.Id3Parser;\nimport com.google.android.exoplayer.text.TextTrackRenderer;\nimport com.google.android.exoplayer.text.eia608.Eia608TrackRenderer;\nimport com.google.android.exoplayer.upstream.DataSource;\nimport com.google.android.exoplayer.upstream.DefaultAllocator;\nimport com.google.android.exoplayer.upstream.DefaultBandwidthMeter;\nimport com.google.android.exoplayer.upstream.DefaultUriDataSource;\nimport com.google.android.exoplayer.util.ManifestFetcher;\nimport com.google.android.exoplayer.util.ManifestFetcher.ManifestCallback;\nimport java.io.IOException;\nimport java.util.List;\n\n/**\n * A {link RendererBuilder} for HLS.\n */\npublic class HlsRendererBuilder implements RendererBuilder {\n\n  private static final int BUFFER_SEGMENT_SIZE = 64 * 1024;\n  private static final int MAIN_BUFFER_SEGMENTS = 254;\n  private static final int AUDIO_BUFFER_SEGMENTS = 54;\n  private static final int TEXT_BUFFER_SEGMENTS = 2;\n\n  private final Context context;\n  private final String userAgent;\n  private final String url;\n\n  private AsyncRendererBuilder currentAsyncBuilder;\n\n  public HlsRendererBuilder(Context context, String userAgent, String url) {\n    this.context = context;\n    this.userAgent = userAgent;\n    this.url = url;\n  }\n\n  @Override\n  public void buildRenderers(DemoPlayer player) {\n    currentAsyncBuilder = new AsyncRendererBuilder(context, userAgent, url, player);\n    currentAsyncBuilder.init();\n  }\n\n  @Override\n  public void cancel() {\n    if (currentAsyncBuilder != null) {\n      currentAsyncBuilder.cancel();\n      currentAsyncBuilder = null;\n    }\n  }\n\n  private static final class AsyncRendererBuilder implements ManifestCallback<HlsPlaylist> {\n\n    private final Context context;\n    private final String userAgent;\n    private final DemoPlayer player;\n    private final ManifestFetcher<HlsPlaylist> playlistFetcher;\n\n    private boolean canceled;\n\n    public AsyncRendererBuilder(Context context, String userAgent, String url, DemoPlayer player) {\n      this.context = context;\n      this.userAgent = userAgent;\n      this.player = player;\n      HlsPlaylistParser parser = new HlsPlaylistParser();\n      playlistFetcher = new ManifestFetcher<>(url, new DefaultUriDataSource(context, userAgent),\n          parser);\n    }\n\n    public void init() {\n      playlistFetcher.singleLoad(player.getMainHandler().getLooper(), this);\n    }\n\n    public void cancel() {\n      canceled = true;\n    }\n\n    @Override\n    public void onSingleManifestError(IOException e) {\n      if (canceled) {\n        return;\n      }\n\n      player.onRenderersError(e);\n    }\n\n    @Override\n    public void onSingleManifest(HlsPlaylist manifest) {\n      if (canceled) {\n        return;\n      }\n\n      Handler mainHandler = player.getMainHandler();\n      LoadControl loadControl = new DefaultLoadControl(new DefaultAllocator(BUFFER_SEGMENT_SIZE));\n      DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();\n      PtsTimestampAdjusterProvider timestampAdjusterProvider = new PtsTimestampAdjusterProvider();\n\n      boolean haveSubtitles = false;\n      boolean haveAudios = false;\n      if (manifest instanceof HlsMasterPlaylist) {\n        HlsMasterPlaylist masterPlaylist = (HlsMasterPlaylist) manifest;\n        haveSubtitles = !masterPlaylist.subtitles.isEmpty();\n        haveAudios = !masterPlaylist.audios.isEmpty();\n      }\n\n      // Build the video/id3 renderers.\n      DataSource dataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);\n      HlsChunkSource chunkSource = new HlsChunkSource(true /* isMaster */, dataSource, manifest,\n          DefaultHlsTrackSelector.newDefaultInstance(context), bandwidthMeter,\n          timestampAdjusterProvider);\n      HlsSampleSource sampleSource = new HlsSampleSource(chunkSource, loadControl,\n          MAIN_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_VIDEO);\n      MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(context,\n          sampleSource, MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT,\n          5000, mainHandler, player, 50);\n      MetadataTrackRenderer<List<Id3Frame>> id3Renderer = new MetadataTrackRenderer<>(\n          sampleSource, new Id3Parser(), player, mainHandler.getLooper());\n\n      // Build the audio renderer.\n      MediaCodecAudioTrackRenderer audioRenderer;\n      if (haveAudios) {\n        DataSource audioDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);\n        HlsChunkSource audioChunkSource = new HlsChunkSource(false /* isMaster */, audioDataSource,\n            manifest, DefaultHlsTrackSelector.newAudioInstance(), bandwidthMeter,\n            timestampAdjusterProvider);\n        HlsSampleSource audioSampleSource = new HlsSampleSource(audioChunkSource, loadControl,\n            AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player,\n            DemoPlayer.TYPE_AUDIO);\n        audioRenderer = new MediaCodecAudioTrackRenderer(\n            new SampleSource[] {sampleSource, audioSampleSource}, MediaCodecSelector.DEFAULT, null,\n            true, player.getMainHandler(), player, AudioCapabilities.getCapabilities(context),\n            AudioManager.STREAM_MUSIC);\n      } else {\n        audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource,\n            MediaCodecSelector.DEFAULT, null, true, player.getMainHandler(), player,\n            AudioCapabilities.getCapabilities(context), AudioManager.STREAM_MUSIC);\n      }\n\n      // Build the text renderer.\n      TrackRenderer textRenderer;\n      if (haveSubtitles) {\n        DataSource textDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);\n        HlsChunkSource textChunkSource = new HlsChunkSource(false /* isMaster */, textDataSource,\n            manifest, DefaultHlsTrackSelector.newSubtitleInstance(), bandwidthMeter,\n            timestampAdjusterProvider);\n        HlsSampleSource textSampleSource = new HlsSampleSource(textChunkSource, loadControl,\n            TEXT_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_TEXT);\n        textRenderer = new TextTrackRenderer(textSampleSource, player, mainHandler.getLooper());\n      } else {\n        textRenderer = new Eia608TrackRenderer(sampleSource, player, mainHandler.getLooper());\n      }\n\n      TrackRenderer[] renderers = new TrackRenderer[DemoPlayer.RENDERER_COUNT];\n      renderers[DemoPlayer.TYPE_VIDEO] = videoRenderer;\n      renderers[DemoPlayer.TYPE_AUDIO] = audioRenderer;\n      renderers[DemoPlayer.TYPE_METADATA] = id3Renderer;\n      renderers[DemoPlayer.TYPE_TEXT] = textRenderer;\n      player.onRenderers(renderers, bandwidthMeter);\n    }\n\n  }\n\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-exo/src/main/java/tv/danmaku/ijk/media/exo/demo/player/SmoothStreamingRendererBuilder.java",
    "content": "/*\n * Copyright (C) 2014 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage tv.danmaku.ijk.media.exo.demo.player;\n\nimport android.content.Context;\nimport android.media.AudioManager;\nimport android.media.MediaCodec;\nimport android.os.Handler;\nimport com.google.android.exoplayer.DefaultLoadControl;\nimport com.google.android.exoplayer.LoadControl;\nimport com.google.android.exoplayer.MediaCodecAudioTrackRenderer;\nimport com.google.android.exoplayer.MediaCodecSelector;\nimport com.google.android.exoplayer.MediaCodecVideoTrackRenderer;\nimport com.google.android.exoplayer.TrackRenderer;\nimport com.google.android.exoplayer.audio.AudioCapabilities;\nimport com.google.android.exoplayer.chunk.ChunkSampleSource;\nimport com.google.android.exoplayer.chunk.ChunkSource;\nimport com.google.android.exoplayer.chunk.FormatEvaluator.AdaptiveEvaluator;\nimport tv.danmaku.ijk.media.exo.demo.player.DemoPlayer.RendererBuilder;\nimport com.google.android.exoplayer.drm.DrmSessionManager;\nimport com.google.android.exoplayer.drm.FrameworkMediaCrypto;\nimport com.google.android.exoplayer.drm.MediaDrmCallback;\nimport com.google.android.exoplayer.drm.StreamingDrmSessionManager;\nimport com.google.android.exoplayer.drm.UnsupportedDrmException;\nimport com.google.android.exoplayer.smoothstreaming.DefaultSmoothStreamingTrackSelector;\nimport com.google.android.exoplayer.smoothstreaming.SmoothStreamingChunkSource;\nimport com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest;\nimport com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifestParser;\nimport com.google.android.exoplayer.text.TextTrackRenderer;\nimport com.google.android.exoplayer.upstream.DataSource;\nimport com.google.android.exoplayer.upstream.DefaultAllocator;\nimport com.google.android.exoplayer.upstream.DefaultBandwidthMeter;\nimport com.google.android.exoplayer.upstream.DefaultHttpDataSource;\nimport com.google.android.exoplayer.upstream.DefaultUriDataSource;\nimport com.google.android.exoplayer.util.ManifestFetcher;\nimport com.google.android.exoplayer.util.Util;\nimport java.io.IOException;\n\n/**\n * A {link RendererBuilder} for SmoothStreaming.\n */\npublic class SmoothStreamingRendererBuilder implements RendererBuilder {\n\n  private static final int BUFFER_SEGMENT_SIZE = 64 * 1024;\n  private static final int VIDEO_BUFFER_SEGMENTS = 200;\n  private static final int AUDIO_BUFFER_SEGMENTS = 54;\n  private static final int TEXT_BUFFER_SEGMENTS = 2;\n  private static final int LIVE_EDGE_LATENCY_MS = 30000;\n\n  private final Context context;\n  private final String userAgent;\n  private final String url;\n  private final MediaDrmCallback drmCallback;\n\n  private AsyncRendererBuilder currentAsyncBuilder;\n\n  public SmoothStreamingRendererBuilder(Context context, String userAgent, String url,\n      MediaDrmCallback drmCallback) {\n    this.context = context;\n    this.userAgent = userAgent;\n    this.url = Util.toLowerInvariant(url).endsWith(\"/manifest\") ? url : url + \"/Manifest\";\n    this.drmCallback = drmCallback;\n  }\n\n  @Override\n  public void buildRenderers(DemoPlayer player) {\n    currentAsyncBuilder = new AsyncRendererBuilder(context, userAgent, url, drmCallback, player);\n    currentAsyncBuilder.init();\n  }\n\n  @Override\n  public void cancel() {\n    if (currentAsyncBuilder != null) {\n      currentAsyncBuilder.cancel();\n      currentAsyncBuilder = null;\n    }\n  }\n\n  private static final class AsyncRendererBuilder\n      implements ManifestFetcher.ManifestCallback<SmoothStreamingManifest> {\n\n    private final Context context;\n    private final String userAgent;\n    private final MediaDrmCallback drmCallback;\n    private final DemoPlayer player;\n    private final ManifestFetcher<SmoothStreamingManifest> manifestFetcher;\n\n    private boolean canceled;\n\n    public AsyncRendererBuilder(Context context, String userAgent, String url,\n        MediaDrmCallback drmCallback, DemoPlayer player) {\n      this.context = context;\n      this.userAgent = userAgent;\n      this.drmCallback = drmCallback;\n      this.player = player;\n      SmoothStreamingManifestParser parser = new SmoothStreamingManifestParser();\n      manifestFetcher = new ManifestFetcher<>(url, new DefaultHttpDataSource(userAgent, null),\n          parser);\n    }\n\n    public void init() {\n      manifestFetcher.singleLoad(player.getMainHandler().getLooper(), this);\n    }\n\n    public void cancel() {\n      canceled = true;\n    }\n\n    @Override\n    public void onSingleManifestError(IOException exception) {\n      if (canceled) {\n        return;\n      }\n\n      player.onRenderersError(exception);\n    }\n\n    @Override\n    public void onSingleManifest(SmoothStreamingManifest manifest) {\n      if (canceled) {\n        return;\n      }\n\n      Handler mainHandler = player.getMainHandler();\n      LoadControl loadControl = new DefaultLoadControl(new DefaultAllocator(BUFFER_SEGMENT_SIZE));\n      DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter(mainHandler, player);\n\n      // Check drm support if necessary.\n      DrmSessionManager<FrameworkMediaCrypto> drmSessionManager = null;\n      if (manifest.protectionElement != null) {\n        if (Util.SDK_INT < 18) {\n          player.onRenderersError(\n              new UnsupportedDrmException(UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME));\n          return;\n        }\n        try {\n          drmSessionManager = StreamingDrmSessionManager.newFrameworkInstance(\n              manifest.protectionElement.uuid, player.getPlaybackLooper(), drmCallback, null,\n              player.getMainHandler(), player);\n        } catch (UnsupportedDrmException e) {\n          player.onRenderersError(e);\n          return;\n        }\n      }\n\n      // Build the video renderer.\n      DataSource videoDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);\n      ChunkSource videoChunkSource = new SmoothStreamingChunkSource(manifestFetcher,\n          DefaultSmoothStreamingTrackSelector.newVideoInstance(context, true, false),\n          videoDataSource, new AdaptiveEvaluator(bandwidthMeter), LIVE_EDGE_LATENCY_MS);\n      ChunkSampleSource videoSampleSource = new ChunkSampleSource(videoChunkSource, loadControl,\n          VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player,\n          DemoPlayer.TYPE_VIDEO);\n      TrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(context, videoSampleSource,\n          MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000,\n          drmSessionManager, true, mainHandler, player, 50);\n\n      // Build the audio renderer.\n      DataSource audioDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);\n      ChunkSource audioChunkSource = new SmoothStreamingChunkSource(manifestFetcher,\n          DefaultSmoothStreamingTrackSelector.newAudioInstance(),\n          audioDataSource, null, LIVE_EDGE_LATENCY_MS);\n      ChunkSampleSource audioSampleSource = new ChunkSampleSource(audioChunkSource, loadControl,\n          AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player,\n          DemoPlayer.TYPE_AUDIO);\n      TrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(audioSampleSource,\n          MediaCodecSelector.DEFAULT, drmSessionManager, true, mainHandler, player,\n          AudioCapabilities.getCapabilities(context), AudioManager.STREAM_MUSIC);\n\n      // Build the text renderer.\n      DataSource textDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);\n      ChunkSource textChunkSource = new SmoothStreamingChunkSource(manifestFetcher,\n          DefaultSmoothStreamingTrackSelector.newTextInstance(),\n          textDataSource, null, LIVE_EDGE_LATENCY_MS);\n      ChunkSampleSource textSampleSource = new ChunkSampleSource(textChunkSource, loadControl,\n          TEXT_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player,\n          DemoPlayer.TYPE_TEXT);\n      TrackRenderer textRenderer = new TextTrackRenderer(textSampleSource, player,\n          mainHandler.getLooper());\n\n      // Invoke the callback.\n      TrackRenderer[] renderers = new TrackRenderer[DemoPlayer.RENDERER_COUNT];\n      renderers[DemoPlayer.TYPE_VIDEO] = videoRenderer;\n      renderers[DemoPlayer.TYPE_AUDIO] = audioRenderer;\n      renderers[DemoPlayer.TYPE_TEXT] = textRenderer;\n      player.onRenderers(renderers, bandwidthMeter);\n    }\n\n  }\n\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-exo/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">ijkplayer-exo</string>\n</resources>\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    // http://tools.android.com/tech-docs/new-build-system/tips\n    //noinspection GroovyAssignabilityCheck\n    compileSdkVersion rootProject.ext.compileSdkVersion\n    //noinspection GroovyAssignabilityCheck\n    buildToolsVersion rootProject.ext.buildToolsVersion\n\n    lintOptions {\n        abortOnError false\n    }\n    defaultConfig {\n        minSdkVersion 9\n        targetSdkVersion rootProject.ext.targetSdkVersion\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n}\n\napply from: new File(rootProject.projectDir, \"tools/gradle-on-demand.gradle\");\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/gradle.properties",
    "content": "POM_NAME=ijkplayer-java\nPOM_ARTIFACT_ID=ijkplayer-java\nPOM_PACKAGING=aar"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /opt/android/ADK/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/androidTest/java/tv/danmaku/ijk/media/player/ApplicationTest.java",
    "content": "package tv.danmaku.ijk.media.player;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\"http://d.android.com/tools/testing/testing_android.html\">Testing Fundamentals</a>\n */\npublic class ApplicationTest extends ApplicationTestCase<Application> {\n    public ApplicationTest() {\n        super(Application.class);\n    }\n}"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/.classpath",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<classpath>\n\t<classpathentry kind=\"src\" path=\"java\"/>\n\t<classpathentry kind=\"con\" path=\"com.android.ide.eclipse.adt.ANDROID_FRAMEWORK\"/>\n\t<classpathentry exported=\"true\" kind=\"con\" path=\"com.android.ide.eclipse.adt.LIBRARIES\"/>\n\t<classpathentry exported=\"true\" kind=\"con\" path=\"com.android.ide.eclipse.adt.DEPENDENCIES\"/>\n\t<classpathentry kind=\"src\" path=\"src\"/>\n\t<classpathentry kind=\"src\" path=\"gen\"/>\n\t<classpathentry kind=\"output\" path=\"bin/classes\"/>\n</classpath>\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/.project",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<projectDescription>\n\t<name>ijkplayer-java</name>\n\t<comment></comment>\n\t<projects>\n\t</projects>\n\t<buildSpec>\n\t\t<buildCommand>\n\t\t\t<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>org.eclipse.jdt.core.javabuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>com.android.ide.eclipse.adt.ApkBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t</buildSpec>\n\t<natures>\n\t\t<nature>com.android.ide.eclipse.adt.AndroidNature</nature>\n\t\t<nature>org.eclipse.jdt.core.javanature</nature>\n\t</natures>\n</projectDescription>\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/.settings/org.eclipse.jdt.core.prefs",
    "content": "eclipse.preferences.version=1\norg.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6\norg.eclipse.jdt.core.compiler.compliance=1.6\norg.eclipse.jdt.core.compiler.source=1.6\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"tv.danmaku.ijk.media.player\" >\n\n    <uses-sdk\n        android:minSdkVersion=\"9\" />\n\n</manifest>"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/AbstractMediaPlayer.java",
    "content": "/*\n * Copyright (C) 2013-2014 Bilibili\n * Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player;\n\nimport tv.danmaku.ijk.media.player.misc.IMediaDataSource;\n\n@SuppressWarnings(\"WeakerAccess\")\npublic abstract class AbstractMediaPlayer implements IMediaPlayer {\n    private OnPreparedListener mOnPreparedListener;\n    private OnCompletionListener mOnCompletionListener;\n    private OnBufferingUpdateListener mOnBufferingUpdateListener;\n    private OnSeekCompleteListener mOnSeekCompleteListener;\n    private OnVideoSizeChangedListener mOnVideoSizeChangedListener;\n    private OnErrorListener mOnErrorListener;\n    private OnInfoListener mOnInfoListener;\n    private OnTimedTextListener mOnTimedTextListener;\n\n    public final void setOnPreparedListener(OnPreparedListener listener) {\n        mOnPreparedListener = listener;\n    }\n\n    public final void setOnCompletionListener(OnCompletionListener listener) {\n        mOnCompletionListener = listener;\n    }\n\n    public final void setOnBufferingUpdateListener(\n            OnBufferingUpdateListener listener) {\n        mOnBufferingUpdateListener = listener;\n    }\n\n    public final void setOnSeekCompleteListener(OnSeekCompleteListener listener) {\n        mOnSeekCompleteListener = listener;\n    }\n\n    public final void setOnVideoSizeChangedListener(\n            OnVideoSizeChangedListener listener) {\n        mOnVideoSizeChangedListener = listener;\n    }\n\n    public final void setOnErrorListener(OnErrorListener listener) {\n        mOnErrorListener = listener;\n    }\n\n    public final void setOnInfoListener(OnInfoListener listener) {\n        mOnInfoListener = listener;\n    }\n\n    public final void setOnTimedTextListener(OnTimedTextListener listener) {\n        mOnTimedTextListener = listener;\n    }\n\n    public void resetListeners() {\n        mOnPreparedListener = null;\n        mOnBufferingUpdateListener = null;\n        mOnCompletionListener = null;\n        mOnSeekCompleteListener = null;\n        mOnVideoSizeChangedListener = null;\n        mOnErrorListener = null;\n        mOnInfoListener = null;\n        mOnTimedTextListener = null;\n    }\n\n    protected final void notifyOnPrepared() {\n        if (mOnPreparedListener != null)\n            mOnPreparedListener.onPrepared(this);\n    }\n\n    protected final void notifyOnCompletion() {\n        if (mOnCompletionListener != null)\n            mOnCompletionListener.onCompletion(this);\n    }\n\n    protected final void notifyOnBufferingUpdate(int percent) {\n        if (mOnBufferingUpdateListener != null)\n            mOnBufferingUpdateListener.onBufferingUpdate(this, percent);\n    }\n\n    protected final void notifyOnSeekComplete() {\n        if (mOnSeekCompleteListener != null)\n            mOnSeekCompleteListener.onSeekComplete(this);\n    }\n\n    protected final void notifyOnVideoSizeChanged(int width, int height,\n                                                  int sarNum, int sarDen) {\n        if (mOnVideoSizeChangedListener != null)\n            mOnVideoSizeChangedListener.onVideoSizeChanged(this, width, height,\n                    sarNum, sarDen);\n    }\n\n    protected final boolean notifyOnError(int what, int extra) {\n        return mOnErrorListener != null && mOnErrorListener.onError(this, what, extra);\n    }\n\n    protected final boolean notifyOnInfo(int what, int extra) {\n        return mOnInfoListener != null && mOnInfoListener.onInfo(this, what, extra);\n    }\n\n    protected final void notifyOnTimedText(IjkTimedText text) {\n        if (mOnTimedTextListener != null)\n            mOnTimedTextListener.onTimedText(this, text);\n    }\n\n    public void setDataSource(IMediaDataSource mediaDataSource) {\n        throw new UnsupportedOperationException();\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/AndroidMediaPlayer.java",
    "content": "/*\n * Copyright (C) 2006 Bilibili\n * Copyright (C) 2006 The Android Open Source Project\n * Copyright (C) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.media.AudioManager;\nimport android.media.MediaDataSource;\nimport android.media.MediaPlayer;\nimport android.media.TimedText;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.text.TextUtils;\nimport android.view.Surface;\nimport android.view.SurfaceHolder;\n\nimport java.io.FileDescriptor;\nimport java.io.IOException;\nimport java.lang.ref.WeakReference;\nimport java.util.Map;\n\nimport tv.danmaku.ijk.media.player.misc.AndroidTrackInfo;\nimport tv.danmaku.ijk.media.player.misc.IMediaDataSource;\nimport tv.danmaku.ijk.media.player.misc.ITrackInfo;\nimport tv.danmaku.ijk.media.player.pragma.DebugLog;\n\npublic class AndroidMediaPlayer extends AbstractMediaPlayer {\n    private final MediaPlayer mInternalMediaPlayer;\n    private final AndroidMediaPlayerListenerHolder mInternalListenerAdapter;\n    private String mDataSource;\n    private MediaDataSource mMediaDataSource;\n\n    private final Object mInitLock = new Object();\n    private boolean mIsReleased;\n\n    private static MediaInfo sMediaInfo;\n\n    public AndroidMediaPlayer() {\n        synchronized (mInitLock) {\n            mInternalMediaPlayer = new MediaPlayer();\n        }\n        mInternalMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);\n        mInternalListenerAdapter = new AndroidMediaPlayerListenerHolder(this);\n        attachInternalListeners();\n    }\n\n    public MediaPlayer getInternalMediaPlayer() {\n        return mInternalMediaPlayer;\n    }\n\n    @Override\n    public void setDisplay(SurfaceHolder sh) {\n        synchronized (mInitLock) {\n            if (!mIsReleased) {\n                mInternalMediaPlayer.setDisplay(sh);\n            }\n        }\n    }\n\n    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)\n    @Override\n    public void setSurface(Surface surface) {\n        mInternalMediaPlayer.setSurface(surface);\n    }\n\n    @Override\n    public void setDataSource(Context context, Uri uri)\n            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {\n        mInternalMediaPlayer.setDataSource(context, uri);\n    }\n\n    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)\n    @Override\n    public void setDataSource(Context context, Uri uri, Map<String, String> headers)\n            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {\n        mInternalMediaPlayer.setDataSource(context, uri, headers);\n    }\n\n    @Override\n    public void setDataSource(FileDescriptor fd)\n            throws IOException, IllegalArgumentException, IllegalStateException {\n        mInternalMediaPlayer.setDataSource(fd);\n    }\n\n    @Override\n    public void setDataSource(String path) throws IOException,\n            IllegalArgumentException, SecurityException, IllegalStateException {\n        mDataSource = path;\n\n        Uri uri = Uri.parse(path);\n        String scheme = uri.getScheme();\n        if (!TextUtils.isEmpty(scheme) && scheme.equalsIgnoreCase(\"file\")) {\n            mInternalMediaPlayer.setDataSource(uri.getPath());\n        } else {\n            mInternalMediaPlayer.setDataSource(path);\n        }\n    }\n\n    @TargetApi(Build.VERSION_CODES.M)\n    @Override\n    public void setDataSource(IMediaDataSource mediaDataSource) {\n        releaseMediaDataSource();\n\n        mMediaDataSource = new MediaDataSourceProxy(mediaDataSource);\n        mInternalMediaPlayer.setDataSource(mMediaDataSource);\n    }\n\n    @TargetApi(Build.VERSION_CODES.M)\n    private static class MediaDataSourceProxy extends MediaDataSource {\n        private final IMediaDataSource mMediaDataSource;\n\n        public MediaDataSourceProxy(IMediaDataSource mediaDataSource) {\n            mMediaDataSource = mediaDataSource;\n        }\n\n        @Override\n        public int readAt(long position, byte[] buffer, int offset, int size) throws IOException {\n            return mMediaDataSource.readAt(position, buffer, offset, size);\n        }\n\n        @Override\n        public long getSize() throws IOException {\n            return mMediaDataSource.getSize();\n        }\n\n        @Override\n        public void close() throws IOException {\n            mMediaDataSource.close();\n        }\n    }\n\n    @Override\n    public String getDataSource() {\n        return mDataSource;\n    }\n\n    private void releaseMediaDataSource() {\n        if (mMediaDataSource != null) {\n            try {\n                mMediaDataSource.close();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n            mMediaDataSource = null;\n        }\n    }\n\n    @Override\n    public void prepareAsync() throws IllegalStateException {\n        mInternalMediaPlayer.prepareAsync();\n    }\n\n    @Override\n    public void start() throws IllegalStateException {\n        mInternalMediaPlayer.start();\n    }\n\n    @Override\n    public void stop() throws IllegalStateException {\n        mInternalMediaPlayer.stop();\n    }\n\n    @Override\n    public void pause() throws IllegalStateException {\n        mInternalMediaPlayer.pause();\n    }\n\n    @Override\n    public void setScreenOnWhilePlaying(boolean screenOn) {\n        mInternalMediaPlayer.setScreenOnWhilePlaying(screenOn);\n    }\n\n    @Override\n    public ITrackInfo[] getTrackInfo() {\n        return AndroidTrackInfo.fromMediaPlayer(mInternalMediaPlayer);\n    }\n\n    @Override\n    public int getVideoWidth() {\n        return mInternalMediaPlayer.getVideoWidth();\n    }\n\n    @Override\n    public int getVideoHeight() {\n        return mInternalMediaPlayer.getVideoHeight();\n    }\n\n    @Override\n    public int getVideoSarNum() {\n        return 1;\n    }\n\n    @Override\n    public int getVideoSarDen() {\n        return 1;\n    }\n\n    @Override\n    public boolean isPlaying() {\n        try {\n            return mInternalMediaPlayer.isPlaying();\n        } catch (IllegalStateException e) {\n            DebugLog.printStackTrace(e);\n            return false;\n        }\n    }\n\n    @Override\n    public void seekTo(long msec) throws IllegalStateException {\n        mInternalMediaPlayer.seekTo((int) msec);\n    }\n\n    @Override\n    public long getCurrentPosition() {\n        try {\n            return mInternalMediaPlayer.getCurrentPosition();\n        } catch (IllegalStateException e) {\n            DebugLog.printStackTrace(e);\n            return 0;\n        }\n    }\n\n    @Override\n    public long getDuration() {\n        try {\n            return mInternalMediaPlayer.getDuration();\n        } catch (IllegalStateException e) {\n            DebugLog.printStackTrace(e);\n            return 0;\n        }\n    }\n\n    @Override\n    public void release() {\n        mIsReleased = true;\n        mInternalMediaPlayer.release();\n        releaseMediaDataSource();\n        resetListeners();\n        attachInternalListeners();\n    }\n\n    @Override\n    public void reset() {\n        try {\n            mInternalMediaPlayer.reset();\n        } catch (IllegalStateException e) {\n            DebugLog.printStackTrace(e);\n        }\n        releaseMediaDataSource();\n        resetListeners();\n        attachInternalListeners();\n    }\n\n    @Override\n    public void setLooping(boolean looping) {\n        mInternalMediaPlayer.setLooping(looping);\n    }\n\n    @Override\n    public boolean isLooping() {\n        return mInternalMediaPlayer.isLooping();\n    }\n\n    @Override\n    public void setVolume(float leftVolume, float rightVolume) {\n        mInternalMediaPlayer.setVolume(leftVolume, rightVolume);\n    }\n\n    @Override\n    public int getAudioSessionId() {\n        return mInternalMediaPlayer.getAudioSessionId();\n    }\n\n    @Override\n    public MediaInfo getMediaInfo() {\n        if (sMediaInfo == null) {\n            MediaInfo module = new MediaInfo();\n\n            module.mVideoDecoder = \"android\";\n            module.mVideoDecoderImpl = \"HW\";\n\n            module.mAudioDecoder = \"android\";\n            module.mAudioDecoderImpl = \"HW\";\n\n            sMediaInfo = module;\n        }\n\n        return sMediaInfo;\n    }\n\n    @Override\n    public void setLogEnabled(boolean enable) {\n    }\n\n    @Override\n    public boolean isPlayable() {\n        return true;\n    }\n\n    /*--------------------\n     * misc\n     */\n    @Override\n    public void setWakeMode(Context context, int mode) {\n        mInternalMediaPlayer.setWakeMode(context, mode);\n    }\n\n    @Override\n    public void setAudioStreamType(int streamtype) {\n        mInternalMediaPlayer.setAudioStreamType(streamtype);\n    }\n\n    @Override\n    public void setKeepInBackground(boolean keepInBackground) {\n    }\n\n    /*--------------------\n     * Listeners adapter\n     */\n    private void attachInternalListeners() {\n        mInternalMediaPlayer.setOnPreparedListener(mInternalListenerAdapter);\n        mInternalMediaPlayer\n                .setOnBufferingUpdateListener(mInternalListenerAdapter);\n        mInternalMediaPlayer.setOnCompletionListener(mInternalListenerAdapter);\n        mInternalMediaPlayer\n                .setOnSeekCompleteListener(mInternalListenerAdapter);\n        mInternalMediaPlayer\n                .setOnVideoSizeChangedListener(mInternalListenerAdapter);\n        mInternalMediaPlayer.setOnErrorListener(mInternalListenerAdapter);\n        mInternalMediaPlayer.setOnInfoListener(mInternalListenerAdapter);\n        mInternalMediaPlayer.setOnTimedTextListener(mInternalListenerAdapter);\n    }\n\n    private class AndroidMediaPlayerListenerHolder implements\n            MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener,\n            MediaPlayer.OnBufferingUpdateListener,\n            MediaPlayer.OnSeekCompleteListener,\n            MediaPlayer.OnVideoSizeChangedListener,\n            MediaPlayer.OnErrorListener, MediaPlayer.OnInfoListener,\n            MediaPlayer.OnTimedTextListener {\n        public final WeakReference<AndroidMediaPlayer> mWeakMediaPlayer;\n\n        public AndroidMediaPlayerListenerHolder(AndroidMediaPlayer mp) {\n            mWeakMediaPlayer = new WeakReference<AndroidMediaPlayer>(mp);\n        }\n\n        @Override\n        public boolean onInfo(MediaPlayer mp, int what, int extra) {\n            AndroidMediaPlayer self = mWeakMediaPlayer.get();\n            return self != null && notifyOnInfo(what, extra);\n\n        }\n\n        @Override\n        public boolean onError(MediaPlayer mp, int what, int extra) {\n            AndroidMediaPlayer self = mWeakMediaPlayer.get();\n            return self != null && notifyOnError(what, extra);\n\n        }\n\n        @Override\n        public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {\n            AndroidMediaPlayer self = mWeakMediaPlayer.get();\n            if (self == null)\n                return;\n\n            notifyOnVideoSizeChanged(width, height, 1, 1);\n        }\n\n        @Override\n        public void onSeekComplete(MediaPlayer mp) {\n            AndroidMediaPlayer self = mWeakMediaPlayer.get();\n            if (self == null)\n                return;\n\n            notifyOnSeekComplete();\n        }\n\n        @Override\n        public void onBufferingUpdate(MediaPlayer mp, int percent) {\n            AndroidMediaPlayer self = mWeakMediaPlayer.get();\n            if (self == null)\n                return;\n\n            notifyOnBufferingUpdate(percent);\n        }\n\n        @Override\n        public void onCompletion(MediaPlayer mp) {\n            AndroidMediaPlayer self = mWeakMediaPlayer.get();\n            if (self == null)\n                return;\n\n            notifyOnCompletion();\n        }\n\n        @Override\n        public void onPrepared(MediaPlayer mp) {\n            AndroidMediaPlayer self = mWeakMediaPlayer.get();\n            if (self == null)\n                return;\n\n            notifyOnPrepared();\n        }\n\n        @Override\n        public void onTimedText(MediaPlayer mp, TimedText text) {\n            AndroidMediaPlayer self = mWeakMediaPlayer.get();\n            if (self == null)\n                return;\n\n            IjkTimedText ijkText = null;\n\n            if (text != null) {\n                ijkText = new IjkTimedText(text.getBounds(), text.getText());\n            }\n\n            notifyOnTimedText(ijkText);\n        }\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IMediaPlayer.java",
    "content": "/*\n * Copyright (C) 2013-2014 Bilibili\n * Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.view.Surface;\nimport android.view.SurfaceHolder;\n\nimport java.io.FileDescriptor;\nimport java.io.IOException;\nimport java.util.Map;\n\nimport tv.danmaku.ijk.media.player.misc.IMediaDataSource;\nimport tv.danmaku.ijk.media.player.misc.ITrackInfo;\n\npublic interface IMediaPlayer {\n    /*\n     * Do not change these values without updating their counterparts in native\n     */\n    int MEDIA_INFO_UNKNOWN = 1;\n    int MEDIA_INFO_STARTED_AS_NEXT = 2;\n    int MEDIA_INFO_VIDEO_RENDERING_START = 3;\n    int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700;\n    int MEDIA_INFO_BUFFERING_START = 701;\n    int MEDIA_INFO_BUFFERING_END = 702;\n    int MEDIA_INFO_NETWORK_BANDWIDTH = 703;\n    int MEDIA_INFO_BAD_INTERLEAVING = 800;\n    int MEDIA_INFO_NOT_SEEKABLE = 801;\n    int MEDIA_INFO_METADATA_UPDATE = 802;\n    int MEDIA_INFO_TIMED_TEXT_ERROR = 900;\n    int MEDIA_INFO_UNSUPPORTED_SUBTITLE = 901;\n    int MEDIA_INFO_SUBTITLE_TIMED_OUT = 902;\n\n    int MEDIA_INFO_VIDEO_ROTATION_CHANGED = 10001;\n    int MEDIA_INFO_AUDIO_RENDERING_START  = 10002;\n    int MEDIA_INFO_AUDIO_DECODED_START    = 10003;\n    int MEDIA_INFO_VIDEO_DECODED_START    = 10004;\n    int MEDIA_INFO_OPEN_INPUT             = 10005;\n    int MEDIA_INFO_FIND_STREAM_INFO       = 10006;\n    int MEDIA_INFO_COMPONENT_OPEN         = 10007;\n    int MEDIA_INFO_VIDEO_SEEK_RENDERING_START = 10008;\n    int MEDIA_INFO_AUDIO_SEEK_RENDERING_START = 10009;\n    int MEDIA_INFO_MEDIA_ACCURATE_SEEK_COMPLETE = 10100;\n\n    int MEDIA_ERROR_UNKNOWN = 1;\n    int MEDIA_ERROR_SERVER_DIED = 100;\n    int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200;\n    int MEDIA_ERROR_IO = -1004;\n    int MEDIA_ERROR_MALFORMED = -1007;\n    int MEDIA_ERROR_UNSUPPORTED = -1010;\n    int MEDIA_ERROR_TIMED_OUT = -110;\n\n    void setDisplay(SurfaceHolder sh);\n\n    void setDataSource(Context context, Uri uri)\n            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;\n\n    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)\n    void setDataSource(Context context, Uri uri, Map<String, String> headers)\n            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;\n\n    void setDataSource(FileDescriptor fd)\n            throws IOException, IllegalArgumentException, IllegalStateException;\n\n    void setDataSource(String path)\n            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;\n\n    String getDataSource();\n\n    void prepareAsync() throws IllegalStateException;\n\n    void start() throws IllegalStateException;\n\n    void stop() throws IllegalStateException;\n\n    void pause() throws IllegalStateException;\n\n    void setScreenOnWhilePlaying(boolean screenOn);\n\n    int getVideoWidth();\n\n    int getVideoHeight();\n\n    boolean isPlaying();\n\n    void seekTo(long msec) throws IllegalStateException;\n\n    long getCurrentPosition();\n\n    long getDuration();\n\n    void release();\n\n    void reset();\n\n    void setVolume(float leftVolume, float rightVolume);\n\n    int getAudioSessionId();\n\n    MediaInfo getMediaInfo();\n\n    @SuppressWarnings(\"EmptyMethod\")\n    @Deprecated\n    void setLogEnabled(boolean enable);\n\n    @Deprecated\n    boolean isPlayable();\n\n    void setOnPreparedListener(OnPreparedListener listener);\n\n    void setOnCompletionListener(OnCompletionListener listener);\n\n    void setOnBufferingUpdateListener(\n            OnBufferingUpdateListener listener);\n\n    void setOnSeekCompleteListener(\n            OnSeekCompleteListener listener);\n\n    void setOnVideoSizeChangedListener(\n            OnVideoSizeChangedListener listener);\n\n    void setOnErrorListener(OnErrorListener listener);\n\n    void setOnInfoListener(OnInfoListener listener);\n\n    void setOnTimedTextListener(OnTimedTextListener listener);\n\n    /*--------------------\n     * Listeners\n     */\n    interface OnPreparedListener {\n        void onPrepared(IMediaPlayer mp);\n    }\n\n    interface OnCompletionListener {\n        void onCompletion(IMediaPlayer mp);\n    }\n\n    interface OnBufferingUpdateListener {\n        void onBufferingUpdate(IMediaPlayer mp, int percent);\n    }\n\n    interface OnSeekCompleteListener {\n        void onSeekComplete(IMediaPlayer mp);\n    }\n\n    interface OnVideoSizeChangedListener {\n        void onVideoSizeChanged(IMediaPlayer mp, int width, int height,\n                                int sar_num, int sar_den);\n    }\n\n    interface OnErrorListener {\n        boolean onError(IMediaPlayer mp, int what, int extra);\n    }\n\n    interface OnInfoListener {\n        boolean onInfo(IMediaPlayer mp, int what, int extra);\n    }\n\n    interface OnTimedTextListener {\n        void onTimedText(IMediaPlayer mp, IjkTimedText text);\n    }\n\n    /*--------------------\n     * Optional\n     */\n    void setAudioStreamType(int streamtype);\n\n    @Deprecated\n    void setKeepInBackground(boolean keepInBackground);\n\n    int getVideoSarNum();\n\n    int getVideoSarDen();\n\n    @Deprecated\n    void setWakeMode(Context context, int mode);\n\n    void setLooping(boolean looping);\n\n    boolean isLooping();\n\n    /*--------------------\n     * AndroidMediaPlayer: JELLY_BEAN\n     */\n    ITrackInfo[] getTrackInfo();\n\n    /*--------------------\n     * AndroidMediaPlayer: ICE_CREAM_SANDWICH:\n     */\n    void setSurface(Surface surface);\n\n    /*--------------------\n     * AndroidMediaPlayer: M:\n     */\n    void setDataSource(IMediaDataSource mediaDataSource);\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/ISurfaceTextureHolder.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player;\n\nimport android.graphics.SurfaceTexture;\n\npublic interface ISurfaceTextureHolder {\n    void setSurfaceTexture(SurfaceTexture surfaceTexture);\n\n    SurfaceTexture getSurfaceTexture();\n\n    void setSurfaceTextureHost(ISurfaceTextureHost surfaceTextureHost);\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/ISurfaceTextureHost.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player;\n\nimport android.graphics.SurfaceTexture;\n\npublic interface ISurfaceTextureHost {\n    void releaseSurfaceTexture(SurfaceTexture surfaceTexture);\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkLibLoader.java",
    "content": "/*\n * Copyright (C) 2013-2014 Bilibili\n * Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player;\n\npublic interface IjkLibLoader {\n    void loadLibrary(String libName) throws UnsatisfiedLinkError,\n            SecurityException;\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaCodecInfo.java",
    "content": "package tv.danmaku.ijk.media.player;\n\nimport android.annotation.TargetApi;\nimport android.media.MediaCodecInfo;\nimport android.media.MediaCodecInfo.CodecCapabilities;\nimport android.media.MediaCodecInfo.CodecProfileLevel;\nimport android.os.Build;\nimport android.text.TextUtils;\nimport android.util.Log;\n\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.TreeMap;\n\npublic class IjkMediaCodecInfo {\n    private final static String TAG = \"IjkMediaCodecInfo\";\n\n    public static final int RANK_MAX = 1000;\n    public static final int RANK_TESTED = 800;\n    public static final int RANK_ACCEPTABLE = 700;\n    public static final int RANK_LAST_CHANCE = 600;\n    public static final int RANK_SECURE = 300;\n    public static final int RANK_SOFTWARE = 200;\n    public static final int RANK_NON_STANDARD = 100;\n    public static final int RANK_NO_SENSE = 0;\n\n    public MediaCodecInfo mCodecInfo;\n    public int mRank = 0;\n    public String mMimeType;\n\n    private static Map<String, Integer> sKnownCodecList;\n\n    private static synchronized Map<String, Integer> getKnownCodecList() {\n        if (sKnownCodecList != null)\n            return sKnownCodecList;\n\n        sKnownCodecList = new TreeMap<String, Integer>(\n                String.CASE_INSENSITIVE_ORDER);\n\n        // ----- Nvidia -----\n        // Tegra3\n        // Nexus 7 (2012)\n        // Tegra K1\n        // Nexus 9\n        sKnownCodecList.put(\"OMX.Nvidia.h264.decode\", RANK_TESTED);\n        sKnownCodecList.put(\"OMX.Nvidia.h264.decode.secure\", RANK_SECURE);\n\n        // ----- Intel -----\n        // Atom Z3735\n        // Teclast X98 Air\n        sKnownCodecList.put(\"OMX.Intel.hw_vd.h264\", RANK_TESTED + 1);\n        // Atom Z2560\n        // Dell Venue 7 3730\n        sKnownCodecList.put(\"OMX.Intel.VideoDecoder.AVC\", RANK_TESTED);\n\n        // ----- Qualcomm -----\n        // MSM8260\n        // Xiaomi MI 1S\n        sKnownCodecList.put(\"OMX.qcom.video.decoder.avc\", RANK_TESTED);\n        sKnownCodecList.put(\"OMX.ittiam.video.decoder.avc\", RANK_NO_SENSE);\n\n        // ----- Samsung -----\n        // Exynos 3110\n        // Nexus S\n        sKnownCodecList.put(\"OMX.SEC.avc.dec\", RANK_TESTED);\n        sKnownCodecList.put(\"OMX.SEC.AVC.Decoder\", RANK_TESTED - 1);\n        // OMX.SEC.avcdec doesn't reorder output pictures on GT-9100\n        sKnownCodecList.put(\"OMX.SEC.avcdec\", RANK_TESTED - 2);\n        sKnownCodecList.put(\"OMX.SEC.avc.sw.dec\", RANK_SOFTWARE);\n        // Exynos 5 ?\n        sKnownCodecList.put(\"OMX.Exynos.avc.dec\", RANK_TESTED);\n        sKnownCodecList.put(\"OMX.Exynos.AVC.Decoder\", RANK_TESTED - 1);\n\n        // ------ Huawei hisilicon ------\n        // Kirin 910, Mali 450 MP\n        // Huawei HONOR 3C (H30-L01)\n        sKnownCodecList.put(\"OMX.k3.video.decoder.avc\", RANK_TESTED);\n        // Kirin 920, Mali T624\n        // Huawei HONOR 6\n        sKnownCodecList.put(\"OMX.IMG.MSVDX.Decoder.AVC\", RANK_TESTED);\n\n        // ----- TI -----\n        // TI OMAP4460\n        // Galaxy Nexus\n        sKnownCodecList.put(\"OMX.TI.DUCATI1.VIDEO.DECODER\", RANK_TESTED);\n\n        // ------ RockChip ------\n        // Youku TVBox\n        sKnownCodecList.put(\"OMX.rk.video_decoder.avc\", RANK_TESTED);\n\n        // ------ AMLogic -----\n        // MiBox1, 1s, 2\n        sKnownCodecList.put(\"OMX.amlogic.avc.decoder.awesome\", RANK_TESTED);\n\n        // ------ Marvell ------\n        // Lenovo A788t\n        sKnownCodecList.put(\"OMX.MARVELL.VIDEO.HW.CODA7542DECODER\", RANK_TESTED);\n        sKnownCodecList.put(\"OMX.MARVELL.VIDEO.H264DECODER\", RANK_SOFTWARE);\n\n        // ----- TODO: need test -----\n        sKnownCodecList.remove(\"OMX.Action.Video.Decoder\");\n        sKnownCodecList.remove(\"OMX.allwinner.video.decoder.avc\");\n        sKnownCodecList.remove(\"OMX.BRCM.vc4.decoder.avc\");\n        sKnownCodecList.remove(\"OMX.brcm.video.h264.hw.decoder\");\n        sKnownCodecList.remove(\"OMX.brcm.video.h264.decoder\");\n        sKnownCodecList.remove(\"OMX.cosmo.video.decoder.avc\");\n        sKnownCodecList.remove(\"OMX.duos.h264.decoder\");\n        sKnownCodecList.remove(\"OMX.hantro.81x0.video.decoder\");\n        sKnownCodecList.remove(\"OMX.hantro.G1.video.decoder\");\n        sKnownCodecList.remove(\"OMX.hisi.video.decoder\");\n        sKnownCodecList.remove(\"OMX.LG.decoder.video.avc\");\n        sKnownCodecList.remove(\"OMX.MS.AVC.Decoder\");\n        sKnownCodecList.remove(\"OMX.RENESAS.VIDEO.DECODER.H264\");\n        sKnownCodecList.remove(\"OMX.RTK.video.decoder\");\n        sKnownCodecList.remove(\"OMX.sprd.h264.decoder\");\n        sKnownCodecList.remove(\"OMX.ST.VFM.H264Dec\");\n        sKnownCodecList.remove(\"OMX.vpu.video_decoder.avc\");\n        sKnownCodecList.remove(\"OMX.WMT.decoder.avc\");\n\n        // Really ?\n        sKnownCodecList.remove(\"OMX.bluestacks.hw.decoder\");\n\n        // ---------------\n        // Useless codec\n        // ----- google -----\n        sKnownCodecList.put(\"OMX.google.h264.decoder\", RANK_SOFTWARE);\n        sKnownCodecList.put(\"OMX.google.h264.lc.decoder\", RANK_SOFTWARE);\n        // ----- huawei k920 -----\n        sKnownCodecList.put(\"OMX.k3.ffmpeg.decoder\", RANK_SOFTWARE);\n        sKnownCodecList.put(\"OMX.ffmpeg.video.decoder\", RANK_SOFTWARE);\n        // ----- unknown -----\n        sKnownCodecList.put(\"OMX.sprd.soft.h264.decoder\", RANK_SOFTWARE);\n\n        return sKnownCodecList;\n    }\n\n    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)\n    public static IjkMediaCodecInfo setupCandidate(MediaCodecInfo codecInfo,\n            String mimeType) {\n        if (codecInfo == null\n                || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)\n            return null;\n\n        String name = codecInfo.getName();\n        if (TextUtils.isEmpty(name))\n            return null;\n\n        name = name.toLowerCase(Locale.US);\n        int rank = RANK_NO_SENSE;\n        if (!name.startsWith(\"omx.\")) {\n            rank = RANK_NON_STANDARD;\n        } else if (name.startsWith(\"omx.pv\")) {\n            rank = RANK_SOFTWARE;\n        } else if (name.startsWith(\"omx.google.\")) {\n            rank = RANK_SOFTWARE;\n        } else if (name.startsWith(\"omx.ffmpeg.\")) {\n            rank = RANK_SOFTWARE;\n        } else if (name.startsWith(\"omx.k3.ffmpeg.\")) {\n            rank = RANK_SOFTWARE;\n        } else if (name.startsWith(\"omx.avcodec.\")) {\n            rank = RANK_SOFTWARE;\n        } else if (name.startsWith(\"omx.ittiam.\")) {\n            // unknown codec in qualcomm SoC\n            rank = RANK_NO_SENSE;\n        } else if (name.startsWith(\"omx.mtk.\")) {\n            // 1. MTK only works on 4.3 and above\n            // 2. MTK works on MIUI 6 (4.2.1)\n            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2)\n                rank = RANK_NO_SENSE;\n            else\n                rank = RANK_TESTED;\n        } else {\n            Integer knownRank = getKnownCodecList().get(name);\n            if (knownRank != null) {\n                rank = knownRank;\n            } else {\n                try {\n                    CodecCapabilities cap = codecInfo\n                            .getCapabilitiesForType(mimeType);\n                    if (cap != null)\n                        rank = RANK_ACCEPTABLE;\n                    else\n                        rank = RANK_LAST_CHANCE;\n                } catch (Throwable e) {\n                    rank = RANK_LAST_CHANCE;\n                }\n            }\n        }\n\n        IjkMediaCodecInfo candidate = new IjkMediaCodecInfo();\n        candidate.mCodecInfo = codecInfo;\n        candidate.mRank = rank;\n        candidate.mMimeType = mimeType;\n        return candidate;\n    }\n\n    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)\n    public void dumpProfileLevels(String mimeType) {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)\n            return;\n\n        try {\n            CodecCapabilities caps = mCodecInfo\n                    .getCapabilitiesForType(mimeType);\n            int maxProfile = 0;\n            int maxLevel = 0;\n            if (caps != null) {\n                if (caps.profileLevels != null) {\n                    for (CodecProfileLevel profileLevel : caps.profileLevels) {\n                        if (profileLevel == null)\n                            continue;\n\n                        maxProfile = Math.max(maxProfile, profileLevel.profile);\n                        maxLevel = Math.max(maxLevel, profileLevel.level);\n                    }\n                }\n            }\n\n            Log.i(TAG,\n                    String.format(Locale.US, \"%s\",\n                            getProfileLevelName(maxProfile, maxLevel)));\n        } catch (Throwable e) {\n            Log.i(TAG, \"profile-level: exception\");\n        }\n    }\n\n    public static String getProfileLevelName(int profile, int level) {\n        return String.format(Locale.US, \" %s Profile Level %s (%d,%d)\",\n                getProfileName(profile), getLevelName(level), profile, level);\n    }\n\n    public static String getProfileName(int profile) {\n        switch (profile) {\n        case CodecProfileLevel.AVCProfileBaseline:\n            return \"Baseline\";\n        case CodecProfileLevel.AVCProfileMain:\n            return \"Main\";\n        case CodecProfileLevel.AVCProfileExtended:\n            return \"Extends\";\n        case CodecProfileLevel.AVCProfileHigh:\n            return \"High\";\n        case CodecProfileLevel.AVCProfileHigh10:\n            return \"High10\";\n        case CodecProfileLevel.AVCProfileHigh422:\n            return \"High422\";\n        case CodecProfileLevel.AVCProfileHigh444:\n            return \"High444\";\n        default:\n            return \"Unknown\";\n        }\n    }\n\n    public static String getLevelName(int level) {\n        switch (level) {\n        case CodecProfileLevel.AVCLevel1:\n            return \"1\";\n        case CodecProfileLevel.AVCLevel1b:\n            return \"1b\";\n        case CodecProfileLevel.AVCLevel11:\n            return \"11\";\n        case CodecProfileLevel.AVCLevel12:\n            return \"12\";\n        case CodecProfileLevel.AVCLevel13:\n            return \"13\";\n        case CodecProfileLevel.AVCLevel2:\n            return \"2\";\n        case CodecProfileLevel.AVCLevel21:\n            return \"21\";\n        case CodecProfileLevel.AVCLevel22:\n            return \"22\";\n        case CodecProfileLevel.AVCLevel3:\n            return \"3\";\n        case CodecProfileLevel.AVCLevel31:\n            return \"31\";\n        case CodecProfileLevel.AVCLevel32:\n            return \"32\";\n        case CodecProfileLevel.AVCLevel4:\n            return \"4\";\n        case CodecProfileLevel.AVCLevel41:\n            return \"41\";\n        case CodecProfileLevel.AVCLevel42:\n            return \"42\";\n        case CodecProfileLevel.AVCLevel5:\n            return \"5\";\n        case CodecProfileLevel.AVCLevel51:\n            return \"51\";\n        case 65536: // CodecProfileLevel.AVCLevel52:\n            return \"52\";\n        default:\n            return \"0\";\n        }\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaMeta.java",
    "content": "package tv.danmaku.ijk.media.player;\n\nimport android.os.Bundle;\nimport android.text.TextUtils;\n\nimport java.util.ArrayList;\nimport java.util.Locale;\n\n@SuppressWarnings(\"SameParameterValue\")\npublic class IjkMediaMeta {\n    // media meta\n    public static final String IJKM_KEY_FORMAT = \"format\";\n    public static final String IJKM_KEY_DURATION_US = \"duration_us\";\n    public static final String IJKM_KEY_START_US = \"start_us\";\n    public static final String IJKM_KEY_BITRATE = \"bitrate\";\n    public static final String IJKM_KEY_VIDEO_STREAM = \"video\";\n    public static final String IJKM_KEY_AUDIO_STREAM = \"audio\";\n    public static final String IJKM_KEY_TIMEDTEXT_STREAM = \"timedtext\";\n\n    // stream meta\n    public static final String IJKM_KEY_TYPE = \"type\";\n    public static final String IJKM_VAL_TYPE__VIDEO = \"video\";\n    public static final String IJKM_VAL_TYPE__AUDIO = \"audio\";\n    public static final String IJKM_VAL_TYPE__TIMEDTEXT = \"timedtext\";\n    public static final String IJKM_VAL_TYPE__UNKNOWN = \"unknown\";\n    public static final String IJKM_KEY_LANGUAGE = \"language\";\n\n    public static final String IJKM_KEY_CODEC_NAME = \"codec_name\";\n    public static final String IJKM_KEY_CODEC_PROFILE = \"codec_profile\";\n    public static final String IJKM_KEY_CODEC_LEVEL = \"codec_level\";\n    public static final String IJKM_KEY_CODEC_LONG_NAME = \"codec_long_name\";\n    public static final String IJKM_KEY_CODEC_PIXEL_FORMAT = \"codec_pixel_format\";\n    public static final String IJKM_KEY_CODEC_PROFILE_ID = \"codec_profile_id\";\n\n    // stream: video\n    public static final String IJKM_KEY_WIDTH = \"width\";\n    public static final String IJKM_KEY_HEIGHT = \"height\";\n    public static final String IJKM_KEY_FPS_NUM = \"fps_num\";\n    public static final String IJKM_KEY_FPS_DEN = \"fps_den\";\n    public static final String IJKM_KEY_TBR_NUM = \"tbr_num\";\n    public static final String IJKM_KEY_TBR_DEN = \"tbr_den\";\n    public static final String IJKM_KEY_SAR_NUM = \"sar_num\";\n    public static final String IJKM_KEY_SAR_DEN = \"sar_den\";\n    // stream: audio\n    public static final String IJKM_KEY_SAMPLE_RATE = \"sample_rate\";\n    public static final String IJKM_KEY_CHANNEL_LAYOUT = \"channel_layout\";\n\n    public static final String IJKM_KEY_STREAMS = \"streams\";\n\n    public static final long AV_CH_FRONT_LEFT = 0x00000001;\n    public static final long AV_CH_FRONT_RIGHT = 0x00000002;\n    public static final long AV_CH_FRONT_CENTER = 0x00000004;\n    public static final long AV_CH_LOW_FREQUENCY = 0x00000008;\n    public static final long AV_CH_BACK_LEFT = 0x00000010;\n    public static final long AV_CH_BACK_RIGHT = 0x00000020;\n    public static final long AV_CH_FRONT_LEFT_OF_CENTER = 0x00000040;\n    public static final long AV_CH_FRONT_RIGHT_OF_CENTER = 0x00000080;\n    public static final long AV_CH_BACK_CENTER = 0x00000100;\n    public static final long AV_CH_SIDE_LEFT = 0x00000200;\n    public static final long AV_CH_SIDE_RIGHT = 0x00000400;\n    public static final long AV_CH_TOP_CENTER = 0x00000800;\n    public static final long AV_CH_TOP_FRONT_LEFT = 0x00001000;\n    public static final long AV_CH_TOP_FRONT_CENTER = 0x00002000;\n    public static final long AV_CH_TOP_FRONT_RIGHT = 0x00004000;\n    public static final long AV_CH_TOP_BACK_LEFT = 0x00008000;\n    public static final long AV_CH_TOP_BACK_CENTER = 0x00010000;\n    public static final long AV_CH_TOP_BACK_RIGHT = 0x00020000;\n    public static final long AV_CH_STEREO_LEFT = 0x20000000;\n    public static final long AV_CH_STEREO_RIGHT = 0x40000000;\n    public static final long AV_CH_WIDE_LEFT = 0x0000000080000000L;\n    public static final long AV_CH_WIDE_RIGHT = 0x0000000100000000L;\n    public static final long AV_CH_SURROUND_DIRECT_LEFT = 0x0000000200000000L;\n    public static final long AV_CH_SURROUND_DIRECT_RIGHT = 0x0000000400000000L;\n    public static final long AV_CH_LOW_FREQUENCY_2 = 0x0000000800000000L;\n\n    public static final long AV_CH_LAYOUT_MONO = (AV_CH_FRONT_CENTER);\n    public static final long AV_CH_LAYOUT_STEREO = (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT);\n    public static final long AV_CH_LAYOUT_2POINT1 = (AV_CH_LAYOUT_STEREO | AV_CH_LOW_FREQUENCY);\n    public static final long AV_CH_LAYOUT_2_1 = (AV_CH_LAYOUT_STEREO | AV_CH_BACK_CENTER);\n    public static final long AV_CH_LAYOUT_SURROUND = (AV_CH_LAYOUT_STEREO | AV_CH_FRONT_CENTER);\n    public static final long AV_CH_LAYOUT_3POINT1 = (AV_CH_LAYOUT_SURROUND | AV_CH_LOW_FREQUENCY);\n    public static final long AV_CH_LAYOUT_4POINT0 = (AV_CH_LAYOUT_SURROUND | AV_CH_BACK_CENTER);\n    public static final long AV_CH_LAYOUT_4POINT1 = (AV_CH_LAYOUT_4POINT0 | AV_CH_LOW_FREQUENCY);\n    public static final long AV_CH_LAYOUT_2_2 = (AV_CH_LAYOUT_STEREO\n            | AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT);\n    public static final long AV_CH_LAYOUT_QUAD = (AV_CH_LAYOUT_STEREO\n            | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT);\n    public static final long AV_CH_LAYOUT_5POINT0 = (AV_CH_LAYOUT_SURROUND\n            | AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT);\n    public static final long AV_CH_LAYOUT_5POINT1 = (AV_CH_LAYOUT_5POINT0 | AV_CH_LOW_FREQUENCY);\n    public static final long AV_CH_LAYOUT_5POINT0_BACK = (AV_CH_LAYOUT_SURROUND\n            | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT);\n    public static final long AV_CH_LAYOUT_5POINT1_BACK = (AV_CH_LAYOUT_5POINT0_BACK | AV_CH_LOW_FREQUENCY);\n    public static final long AV_CH_LAYOUT_6POINT0 = (AV_CH_LAYOUT_5POINT0 | AV_CH_BACK_CENTER);\n    public static final long AV_CH_LAYOUT_6POINT0_FRONT = (AV_CH_LAYOUT_2_2\n            | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER);\n    public static final long AV_CH_LAYOUT_HEXAGONAL = (AV_CH_LAYOUT_5POINT0_BACK | AV_CH_BACK_CENTER);\n    public static final long AV_CH_LAYOUT_6POINT1 = (AV_CH_LAYOUT_5POINT1 | AV_CH_BACK_CENTER);\n    public static final long AV_CH_LAYOUT_6POINT1_BACK = (AV_CH_LAYOUT_5POINT1_BACK | AV_CH_BACK_CENTER);\n    public static final long AV_CH_LAYOUT_6POINT1_FRONT = (AV_CH_LAYOUT_6POINT0_FRONT | AV_CH_LOW_FREQUENCY);\n    public static final long AV_CH_LAYOUT_7POINT0 = (AV_CH_LAYOUT_5POINT0\n            | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT);\n    public static final long AV_CH_LAYOUT_7POINT0_FRONT = (AV_CH_LAYOUT_5POINT0\n            | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER);\n    public static final long AV_CH_LAYOUT_7POINT1 = (AV_CH_LAYOUT_5POINT1\n            | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT);\n    public static final long AV_CH_LAYOUT_7POINT1_WIDE = (AV_CH_LAYOUT_5POINT1\n            | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER);\n    public static final long AV_CH_LAYOUT_7POINT1_WIDE_BACK = (AV_CH_LAYOUT_5POINT1_BACK\n            | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER);\n    public static final long AV_CH_LAYOUT_OCTAGONAL = (AV_CH_LAYOUT_5POINT0\n            | AV_CH_BACK_LEFT | AV_CH_BACK_CENTER | AV_CH_BACK_RIGHT);\n    public static final long AV_CH_LAYOUT_STEREO_DOWNMIX = (AV_CH_STEREO_LEFT | AV_CH_STEREO_RIGHT);\n\n    public static final int FF_PROFILE_H264_CONSTRAINED = (1<<9);  // 8+1; constraint_set1_flag\n    public static final int FF_PROFILE_H264_INTRA = (1<<11);       // 8+3; constraint_set3_flag\n\n    public static final int FF_PROFILE_H264_BASELINE = 66;\n    public static final int FF_PROFILE_H264_CONSTRAINED_BASELINE = (66|FF_PROFILE_H264_CONSTRAINED);\n    public static final int FF_PROFILE_H264_MAIN = 77;\n    public static final int FF_PROFILE_H264_EXTENDED = 88;\n    public static final int FF_PROFILE_H264_HIGH = 100;\n    public static final int FF_PROFILE_H264_HIGH_10 = 110;\n    public static final int FF_PROFILE_H264_HIGH_10_INTRA = (110|FF_PROFILE_H264_INTRA);\n    public static final int FF_PROFILE_H264_HIGH_422 = 122;\n    public static final int FF_PROFILE_H264_HIGH_422_INTRA = (122|FF_PROFILE_H264_INTRA);\n    public static final int FF_PROFILE_H264_HIGH_444 = 144;\n    public static final int FF_PROFILE_H264_HIGH_444_PREDICTIVE = 244;\n    public static final int FF_PROFILE_H264_HIGH_444_INTRA = (244|FF_PROFILE_H264_INTRA);\n    public static final int FF_PROFILE_H264_CAVLC_444 = 44;\n\n    public Bundle mMediaMeta;\n\n    public String mFormat;\n    public long mDurationUS;\n    public long mStartUS;\n    public long mBitrate;\n\n    public final ArrayList<IjkStreamMeta> mStreams = new ArrayList<IjkStreamMeta>();\n    public IjkStreamMeta mVideoStream;\n    public IjkStreamMeta mAudioStream;\n\n    public String getString(String key) {\n        return mMediaMeta.getString(key);\n    }\n\n    public int getInt(String key) {\n        return getInt(key, 0);\n    }\n\n    public int getInt(String key, int defaultValue) {\n        String value = getString(key);\n        if (TextUtils.isEmpty(value))\n            return defaultValue;\n\n        try {\n            return Integer.parseInt(value);\n        } catch (NumberFormatException e) {\n            return defaultValue;\n        }\n    }\n\n    public long getLong(String key) {\n        return getLong(key, 0);\n    }\n\n    public long getLong(String key, long defaultValue) {\n        String value = getString(key);\n        if (TextUtils.isEmpty(value))\n            return defaultValue;\n\n        try {\n            return Long.parseLong(value);\n        } catch (NumberFormatException e) {\n            return defaultValue;\n        }\n    }\n\n    public ArrayList<Bundle> getParcelableArrayList(String key) {\n        return mMediaMeta.getParcelableArrayList(key);\n    }\n\n    public String getDurationInline() {\n        long duration = mDurationUS + 5000;\n        long secs = duration / 1000000;\n        long mins = secs / 60;\n        secs %= 60;\n        long hours = mins / 60;\n        mins %= 60;\n        return String.format(Locale.US, \"%02d:%02d:%02d\", hours, mins, secs);\n    }\n\n    public static IjkMediaMeta parse(Bundle mediaMeta) {\n        if (mediaMeta == null)\n            return null;\n\n        IjkMediaMeta meta = new IjkMediaMeta();\n        meta.mMediaMeta = mediaMeta;\n\n        meta.mFormat = meta.getString(IJKM_KEY_FORMAT);\n        meta.mDurationUS = meta.getLong(IJKM_KEY_DURATION_US);\n        meta.mStartUS = meta.getLong(IJKM_KEY_START_US);\n        meta.mBitrate = meta.getLong(IJKM_KEY_BITRATE);\n\n        int videoStreamIndex = meta.getInt(IJKM_KEY_VIDEO_STREAM, -1);\n        int audioStreamIndex = meta.getInt(IJKM_KEY_AUDIO_STREAM, -1);\n        int subtitleStreamIndex = meta.getInt(IJKM_KEY_TIMEDTEXT_STREAM, -1);\n\n        ArrayList<Bundle> streams = meta\n                .getParcelableArrayList(IJKM_KEY_STREAMS);\n        if (streams == null)\n            return meta;\n\n        int index = -1;\n        for (Bundle streamBundle : streams) {\n            index++;\n\n            if (streamBundle == null) {\n                continue;\n            }\n\n            IjkStreamMeta streamMeta = new IjkStreamMeta(index);\n            streamMeta.mMeta = streamBundle;\n            streamMeta.mType = streamMeta.getString(IJKM_KEY_TYPE);\n            streamMeta.mLanguage = streamMeta.getString(IJKM_KEY_LANGUAGE);\n            if (TextUtils.isEmpty(streamMeta.mType))\n                continue;\n\n            streamMeta.mCodecName = streamMeta.getString(IJKM_KEY_CODEC_NAME);\n            streamMeta.mCodecProfile = streamMeta\n                    .getString(IJKM_KEY_CODEC_PROFILE);\n            streamMeta.mCodecLongName = streamMeta\n                    .getString(IJKM_KEY_CODEC_LONG_NAME);\n            streamMeta.mBitrate = streamMeta.getInt(IJKM_KEY_BITRATE);\n\n            if (streamMeta.mType.equalsIgnoreCase(IJKM_VAL_TYPE__VIDEO)) {\n                streamMeta.mWidth = streamMeta.getInt(IJKM_KEY_WIDTH);\n                streamMeta.mHeight = streamMeta.getInt(IJKM_KEY_HEIGHT);\n                streamMeta.mFpsNum = streamMeta.getInt(IJKM_KEY_FPS_NUM);\n                streamMeta.mFpsDen = streamMeta.getInt(IJKM_KEY_FPS_DEN);\n                streamMeta.mTbrNum = streamMeta.getInt(IJKM_KEY_TBR_NUM);\n                streamMeta.mTbrDen = streamMeta.getInt(IJKM_KEY_TBR_DEN);\n                streamMeta.mSarNum = streamMeta.getInt(IJKM_KEY_SAR_NUM);\n                streamMeta.mSarDen = streamMeta.getInt(IJKM_KEY_SAR_DEN);\n\n                if (videoStreamIndex == index) {\n                    meta.mVideoStream = streamMeta;\n                }\n            } else if (streamMeta.mType.equalsIgnoreCase(IJKM_VAL_TYPE__AUDIO)) {\n                streamMeta.mSampleRate = streamMeta\n                        .getInt(IJKM_KEY_SAMPLE_RATE);\n                streamMeta.mChannelLayout = streamMeta\n                        .getLong(IJKM_KEY_CHANNEL_LAYOUT);\n\n                if (audioStreamIndex == index) {\n                    meta.mAudioStream = streamMeta;\n                }\n            }\n            meta.mStreams.add(streamMeta);\n        }\n\n        return meta;\n    }\n\n    public static class IjkStreamMeta {\n        public Bundle mMeta;\n\n        public final int mIndex;\n        public String mType;\n        public String mLanguage;\n\n        // common\n        public String mCodecName;\n        public String mCodecProfile;\n        public String mCodecLongName;\n        public long mBitrate;\n\n        // video\n        public int mWidth;\n        public int mHeight;\n        public int mFpsNum;\n        public int mFpsDen;\n        public int mTbrNum;\n        public int mTbrDen;\n        public int mSarNum;\n        public int mSarDen;\n\n        // audio\n        public int mSampleRate;\n        public long mChannelLayout;\n\n        public IjkStreamMeta(int index) {\n            mIndex = index;\n        }\n\n        public String getString(String key) {\n            return mMeta.getString(key);\n        }\n\n        public int getInt(String key) {\n            return getInt(key, 0);\n        }\n\n        public int getInt(String key, int defaultValue) {\n            String value = getString(key);\n            if (TextUtils.isEmpty(value))\n                return defaultValue;\n\n            try {\n                return Integer.parseInt(value);\n            } catch (NumberFormatException e) {\n                return defaultValue;\n            }\n        }\n\n        public long getLong(String key) {\n            return getLong(key, 0);\n        }\n\n        public long getLong(String key, long defaultValue) {\n            String value = getString(key);\n            if (TextUtils.isEmpty(value))\n                return defaultValue;\n\n            try {\n                return Long.parseLong(value);\n            } catch (NumberFormatException e) {\n                return defaultValue;\n            }\n        }\n\n        public String getCodecLongNameInline() {\n            if (!TextUtils.isEmpty(mCodecLongName)) {\n                return mCodecLongName;\n            } else if (!TextUtils.isEmpty(mCodecName)) {\n                return mCodecName;\n            } else {\n                return \"N/A\";\n            }\n        }\n\n        public String getCodecShortNameInline() {\n            if (!TextUtils.isEmpty(mCodecName)) {\n                return mCodecName;\n            } else {\n                return \"N/A\";\n            }\n        }\n\n        public String getResolutionInline() {\n            if (mWidth <= 0 || mHeight <= 0) {\n                return \"N/A\";\n            } else if (mSarNum <= 0 || mSarDen <= 0) {\n                return String.format(Locale.US, \"%d x %d\", mWidth, mHeight);\n            } else {\n                return String.format(Locale.US, \"%d x %d [SAR %d:%d]\", mWidth,\n                        mHeight, mSarNum, mSarDen);\n            }\n        }\n\n        public String getFpsInline() {\n            if (mFpsNum <= 0 || mFpsDen <= 0) {\n                return \"N/A\";\n            } else {\n                return String.valueOf(((float) (mFpsNum)) / mFpsDen);\n            }\n        }\n\n        public String getBitrateInline() {\n            if (mBitrate <= 0) {\n                return \"N/A\";\n            } else if (mBitrate < 1000) {\n                return String.format(Locale.US, \"%d bit/s\", mBitrate);\n            } else {\n                return String.format(Locale.US, \"%d kb/s\", mBitrate / 1000);\n            }\n        }\n\n        public String getSampleRateInline() {\n            if (mSampleRate <= 0) {\n                return \"N/A\";\n            } else {\n                return String.format(Locale.US, \"%d Hz\", mSampleRate);\n            }\n        }\n\n        public String getChannelLayoutInline() {\n            if (mChannelLayout <= 0) {\n                return \"N/A\";\n            } else {\n                if (mChannelLayout == AV_CH_LAYOUT_MONO) {\n                    return \"mono\";\n                } else if (mChannelLayout == AV_CH_LAYOUT_STEREO) {\n                    return \"stereo\";\n                } else {\n                    return String.format(Locale.US, \"%x\", mChannelLayout);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaPlayer.java",
    "content": "/*\n * Copyright (C) 2006 Bilibili\n * Copyright (C) 2006 The Android Open Source Project\n * Copyright (C) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player;\n\nimport android.annotation.SuppressLint;\nimport android.annotation.TargetApi;\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.res.AssetFileDescriptor;\nimport android.graphics.SurfaceTexture;\nimport android.graphics.Rect;\nimport android.media.MediaCodecInfo;\nimport android.media.MediaCodecList;\nimport android.media.RingtoneManager;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.os.Message;\nimport android.os.ParcelFileDescriptor;\nimport android.os.PowerManager;\nimport android.provider.Settings;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.view.Surface;\nimport android.view.SurfaceHolder;\n\nimport java.io.FileDescriptor;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.lang.ref.WeakReference;\nimport java.lang.reflect.Field;\nimport java.security.InvalidParameterException;\nimport java.util.ArrayList;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport tv.danmaku.ijk.media.player.annotations.AccessedByNative;\nimport tv.danmaku.ijk.media.player.annotations.CalledByNative;\nimport tv.danmaku.ijk.media.player.misc.IAndroidIO;\nimport tv.danmaku.ijk.media.player.misc.IMediaDataSource;\nimport tv.danmaku.ijk.media.player.misc.ITrackInfo;\nimport tv.danmaku.ijk.media.player.misc.IjkTrackInfo;\nimport tv.danmaku.ijk.media.player.pragma.DebugLog;\n\n/**\n * @author bbcallen\n *\n *         Java wrapper of ffplay.\n */\npublic final class IjkMediaPlayer extends AbstractMediaPlayer {\n    private final static String TAG = IjkMediaPlayer.class.getName();\n\n    private static final int MEDIA_NOP = 0; // interface test message\n    private static final int MEDIA_PREPARED = 1;\n    private static final int MEDIA_PLAYBACK_COMPLETE = 2;\n    private static final int MEDIA_BUFFERING_UPDATE = 3;\n    private static final int MEDIA_SEEK_COMPLETE = 4;\n    private static final int MEDIA_SET_VIDEO_SIZE = 5;\n    private static final int MEDIA_TIMED_TEXT = 99;\n    private static final int MEDIA_ERROR = 100;\n    private static final int MEDIA_INFO = 200;\n\n    protected static final int MEDIA_SET_VIDEO_SAR = 10001;\n\n    //----------------------------------------\n    // options\n    public static final int IJK_LOG_UNKNOWN = 0;\n    public static final int IJK_LOG_DEFAULT = 1;\n\n    public static final int IJK_LOG_VERBOSE = 2;\n    public static final int IJK_LOG_DEBUG = 3;\n    public static final int IJK_LOG_INFO = 4;\n    public static final int IJK_LOG_WARN = 5;\n    public static final int IJK_LOG_ERROR = 6;\n    public static final int IJK_LOG_FATAL = 7;\n    public static final int IJK_LOG_SILENT = 8;\n\n    public static final int OPT_CATEGORY_FORMAT     = 1;\n    public static final int OPT_CATEGORY_CODEC      = 2;\n    public static final int OPT_CATEGORY_SWS        = 3;\n    public static final int OPT_CATEGORY_PLAYER     = 4;\n\n    public static final int SDL_FCC_YV12 = 0x32315659; // YV12\n    public static final int SDL_FCC_RV16 = 0x36315652; // RGB565\n    public static final int SDL_FCC_RV32 = 0x32335652; // RGBX8888\n    //----------------------------------------\n\n    //----------------------------------------\n    // properties\n    public static final int PROP_FLOAT_VIDEO_DECODE_FRAMES_PER_SECOND       = 10001;\n    public static final int PROP_FLOAT_VIDEO_OUTPUT_FRAMES_PER_SECOND       = 10002;\n    public static final int FFP_PROP_FLOAT_PLAYBACK_RATE                    = 10003;\n    public static final int FFP_PROP_FLOAT_DROP_FRAME_RATE                  = 10007;\n\n    public static final int FFP_PROP_INT64_SELECTED_VIDEO_STREAM            = 20001;\n    public static final int FFP_PROP_INT64_SELECTED_AUDIO_STREAM            = 20002;\n    public static final int FFP_PROP_INT64_SELECTED_TIMEDTEXT_STREAM        = 20011;\n\n    public static final int FFP_PROP_INT64_VIDEO_DECODER                    = 20003;\n    public static final int FFP_PROP_INT64_AUDIO_DECODER                    = 20004;\n    public static final int     FFP_PROPV_DECODER_UNKNOWN                   = 0;\n    public static final int     FFP_PROPV_DECODER_AVCODEC                   = 1;\n    public static final int     FFP_PROPV_DECODER_MEDIACODEC                = 2;\n    public static final int     FFP_PROPV_DECODER_VIDEOTOOLBOX              = 3;\n    public static final int FFP_PROP_INT64_VIDEO_CACHED_DURATION            = 20005;\n    public static final int FFP_PROP_INT64_AUDIO_CACHED_DURATION            = 20006;\n    public static final int FFP_PROP_INT64_VIDEO_CACHED_BYTES               = 20007;\n    public static final int FFP_PROP_INT64_AUDIO_CACHED_BYTES               = 20008;\n    public static final int FFP_PROP_INT64_VIDEO_CACHED_PACKETS             = 20009;\n    public static final int FFP_PROP_INT64_AUDIO_CACHED_PACKETS             = 20010;\n    public static final int FFP_PROP_INT64_ASYNC_STATISTIC_BUF_BACKWARDS    = 20201;\n    public static final int FFP_PROP_INT64_ASYNC_STATISTIC_BUF_FORWARDS     = 20202;\n    public static final int FFP_PROP_INT64_ASYNC_STATISTIC_BUF_CAPACITY     = 20203;\n    public static final int FFP_PROP_INT64_TRAFFIC_STATISTIC_BYTE_COUNT     = 20204;\n    public static final int FFP_PROP_INT64_CACHE_STATISTIC_PHYSICAL_POS     = 20205;\n    public static final int FFP_PROP_INT64_CACHE_STATISTIC_FILE_FORWARDS    = 20206;\n    public static final int FFP_PROP_INT64_CACHE_STATISTIC_FILE_POS         = 20207;\n    public static final int FFP_PROP_INT64_CACHE_STATISTIC_COUNT_BYTES      = 20208;\n    public static final int FFP_PROP_INT64_LOGICAL_FILE_SIZE                = 20209;\n    public static final int FFP_PROP_INT64_SHARE_CACHE_DATA                 = 20210;\n    public static final int FFP_PROP_INT64_BIT_RATE                         = 20100;\n    public static final int FFP_PROP_INT64_TCP_SPEED                        = 20200;\n    public static final int FFP_PROP_INT64_LATEST_SEEK_LOAD_DURATION        = 20300;\n    public static final int FFP_PROP_INT64_IMMEDIATE_RECONNECT              = 20211;\n    //----------------------------------------\n\n    @AccessedByNative\n    private long mNativeMediaPlayer;\n    @AccessedByNative\n    private long mNativeMediaDataSource;\n\n    @AccessedByNative\n    private long mNativeAndroidIO;\n\n    @AccessedByNative\n    private int mNativeSurfaceTexture;\n\n    @AccessedByNative\n    private int mListenerContext;\n\n    private SurfaceHolder mSurfaceHolder;\n    private EventHandler mEventHandler;\n    private PowerManager.WakeLock mWakeLock = null;\n    private boolean mScreenOnWhilePlaying;\n    private boolean mStayAwake;\n\n    private int mVideoWidth;\n    private int mVideoHeight;\n    private int mVideoSarNum;\n    private int mVideoSarDen;\n\n    private String mDataSource;\n\n    /**\n     * Default library loader\n     * Load them by yourself, if your libraries are not installed at default place.\n     */\n    private static final IjkLibLoader sLocalLibLoader = new IjkLibLoader() {\n        @Override\n        public void loadLibrary(String libName) throws UnsatisfiedLinkError, SecurityException {\n            System.loadLibrary(libName);\n        }\n    };\n\n    private static volatile boolean mIsLibLoaded = false;\n    public static void loadLibrariesOnce(IjkLibLoader libLoader) {\n        synchronized (IjkMediaPlayer.class) {\n            if (!mIsLibLoaded) {\n                if (libLoader == null)\n                    libLoader = sLocalLibLoader;\n\n                libLoader.loadLibrary(\"ijkffmpeg\");\n                libLoader.loadLibrary(\"ijksdl\");\n                libLoader.loadLibrary(\"ijkplayer\");\n                mIsLibLoaded = true;\n            }\n        }\n    }\n\n    private static volatile boolean mIsNativeInitialized = false;\n    private static void initNativeOnce() {\n        synchronized (IjkMediaPlayer.class) {\n            if (!mIsNativeInitialized) {\n                native_init();\n                mIsNativeInitialized = true;\n            }\n        }\n    }\n\n    /**\n     * Default constructor. Consider using one of the create() methods for\n     * synchronously instantiating a IjkMediaPlayer from a Uri or resource.\n     * <p>\n     * When done with the IjkMediaPlayer, you should call {@link #release()}, to\n     * free the resources. If not released, too many IjkMediaPlayer instances\n     * may result in an exception.\n     * </p>\n     */\n    public IjkMediaPlayer() {\n        this(sLocalLibLoader);\n    }\n\n    /**\n     * do not loadLibaray\n     * @param libLoader\n     *              custom library loader, can be null.\n     */\n    public IjkMediaPlayer(IjkLibLoader libLoader) {\n        initPlayer(libLoader);\n    }\n\n    private void initPlayer(IjkLibLoader libLoader) {\n        loadLibrariesOnce(libLoader);\n        initNativeOnce();\n\n        Looper looper;\n        if ((looper = Looper.myLooper()) != null) {\n            mEventHandler = new EventHandler(this, looper);\n        } else if ((looper = Looper.getMainLooper()) != null) {\n            mEventHandler = new EventHandler(this, looper);\n        } else {\n            mEventHandler = null;\n        }\n\n        /*\n         * Native setup requires a weak reference to our object. It's easier to\n         * create it here than in C++.\n         */\n        native_setup(new WeakReference<IjkMediaPlayer>(this));\n    }\n\n    private native void _setFrameAtTime(String imgCachePath, long startTime, long endTime, int num, int imgDefinition)\n            throws IllegalArgumentException, IllegalStateException;\n\n    /*\n     * Update the IjkMediaPlayer SurfaceTexture. Call after setting a new\n     * display surface.\n     */\n    private native void _setVideoSurface(Surface surface);\n\n    /**\n     * Sets the {@link SurfaceHolder} to use for displaying the video portion of\n     * the media.\n     *\n     * Either a surface holder or surface must be set if a display or video sink\n     * is needed. Not calling this method or {@link #setSurface(Surface)} when\n     * playing back a video will result in only the audio track being played. A\n     * null surface holder or surface will result in only the audio track being\n     * played.\n     *\n     * @param sh\n     *            the SurfaceHolder to use for video display\n     */\n    @Override\n    public void setDisplay(SurfaceHolder sh) {\n        mSurfaceHolder = sh;\n        Surface surface;\n        if (sh != null) {\n            surface = sh.getSurface();\n        } else {\n            surface = null;\n        }\n        _setVideoSurface(surface);\n        updateSurfaceScreenOn();\n    }\n\n    /**\n     * Sets the {@link Surface} to be used as the sink for the video portion of\n     * the media. This is similar to {@link #setDisplay(SurfaceHolder)}, but\n     * does not support {@link #setScreenOnWhilePlaying(boolean)}. Setting a\n     * Surface will un-set any Surface or SurfaceHolder that was previously set.\n     * A null surface will result in only the audio track being played.\n     *\n     * If the Surface sends frames to a {@link SurfaceTexture}, the timestamps\n     * returned from {@link SurfaceTexture#getTimestamp()} will have an\n     * unspecified zero point. These timestamps cannot be directly compared\n     * between different media sources, different instances of the same media\n     * source, or multiple runs of the same program. The timestamp is normally\n     * monotonically increasing and is unaffected by time-of-day adjustments,\n     * but it is reset when the position is set.\n     *\n     * @param surface\n     *            The {@link Surface} to be used for the video portion of the\n     *            media.\n     */\n    @Override\n    public void setSurface(Surface surface) {\n        if (mScreenOnWhilePlaying && surface != null) {\n            DebugLog.w(TAG,\n                    \"setScreenOnWhilePlaying(true) is ineffective for Surface\");\n        }\n        mSurfaceHolder = null;\n        _setVideoSurface(surface);\n        updateSurfaceScreenOn();\n    }\n\n    /**\n     * Sets the data source as a content Uri.\n     *\n     * @param context the Context to use when resolving the Uri\n     * @param uri the Content URI of the data you want to play\n     * @throws IllegalStateException if it is called in an invalid state\n     */\n    @Override\n    public void setDataSource(Context context, Uri uri)\n            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {\n        setDataSource(context, uri, null);\n    }\n\n    /**\n     * Sets the data source as a content Uri.\n     *\n     * @param context the Context to use when resolving the Uri\n     * @param uri the Content URI of the data you want to play\n     * @param headers the headers to be sent together with the request for the data\n     *                Note that the cross domain redirection is allowed by default, but that can be\n     *                changed with key/value pairs through the headers parameter with\n     *                \"android-allow-cross-domain-redirect\" as the key and \"0\" or \"1\" as the value\n     *                to disallow or allow cross domain redirection.\n     * @throws IllegalStateException if it is called in an invalid state\n     */\n    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)\n    @Override\n    public void setDataSource(Context context, Uri uri, Map<String, String> headers)\n            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {\n        final String scheme = uri.getScheme();\n        if (ContentResolver.SCHEME_FILE.equals(scheme)) {\n            setDataSource(uri.getPath());\n            return;\n        } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)\n                && Settings.AUTHORITY.equals(uri.getAuthority())) {\n            // Redirect ringtones to go directly to underlying provider\n            uri = RingtoneManager.getActualDefaultRingtoneUri(context,\n                    RingtoneManager.getDefaultType(uri));\n            if (uri == null) {\n                throw new FileNotFoundException(\"Failed to resolve default ringtone\");\n            }\n        }\n\n        AssetFileDescriptor fd = null;\n        try {\n            ContentResolver resolver = context.getContentResolver();\n            fd = resolver.openAssetFileDescriptor(uri, \"r\");\n            if (fd == null) {\n                return;\n            }\n            // Note: using getDeclaredLength so that our behavior is the same\n            // as previous versions when the content provider is returning\n            // a full file.\n            if (fd.getDeclaredLength() < 0) {\n                setDataSource(fd.getFileDescriptor());\n            } else {\n                setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getDeclaredLength());\n            }\n            return;\n        } catch (SecurityException ignored) {\n        } catch (IOException ignored) {\n        } finally {\n            if (fd != null) {\n                fd.close();\n            }\n        }\n\n        Log.d(TAG, \"Couldn't open file on client side, trying server side\");\n\n        setDataSource(uri.toString(), headers);\n    }\n\n    /**\n     * Sets the data source (file-path or http/rtsp URL) to use.\n     *\n     * @param path\n     *            the path of the file, or the http/rtsp URL of the stream you\n     *            want to play\n     * @throws IllegalStateException\n     *             if it is called in an invalid state\n     *\n     *             <p>\n     *             When <code>path</code> refers to a local file, the file may\n     *             actually be opened by a process other than the calling\n     *             application. This implies that the pathname should be an\n     *             absolute path (as any other process runs with unspecified\n     *             current working directory), and that the pathname should\n     *             reference a world-readable file.\n     */\n    @Override\n    public void setDataSource(String path)\n            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {\n        mDataSource = path;\n        _setDataSource(path, null, null);\n    }\n\n    /**\n     * Sets the data source (file-path or http/rtsp URL) to use.\n     *\n     * @param path the path of the file, or the http/rtsp URL of the stream you want to play\n     * @param headers the headers associated with the http request for the stream you want to play\n     * @throws IllegalStateException if it is called in an invalid state\n     */\n    public void setDataSource(String path, Map<String, String> headers)\n            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException\n    {\n        if (headers != null && !headers.isEmpty()) {\n            StringBuilder sb = new StringBuilder();\n            for(Map.Entry<String, String> entry: headers.entrySet()) {\n                sb.append(entry.getKey());\n                sb.append(\":\");\n                String value = entry.getValue();\n                if (!TextUtils.isEmpty(value))\n                    sb.append(entry.getValue());\n                sb.append(\"\\r\\n\");\n                setOption(OPT_CATEGORY_FORMAT, \"headers\", sb.toString());\n                setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, \"protocol_whitelist\", \"async,cache,crypto,file,http,https,ijkhttphook,ijkinject,ijklivehook,ijklongurl,ijksegment,ijktcphook,pipe,rtp,tcp,tls,udp,ijkurlhook,data\");\n            }\n        }\n        setDataSource(path);\n    }\n\n    /**\n     * Sets the data source (FileDescriptor) to use. It is the caller's responsibility\n     * to close the file descriptor. It is safe to do so as soon as this call returns.\n     *\n     * @param fd the FileDescriptor for the file you want to play\n     * @throws IllegalStateException if it is called in an invalid state\n     */\n    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)\n    @Override\n    public void setDataSource(FileDescriptor fd)\n            throws IOException, IllegalArgumentException, IllegalStateException {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR1) {\n            int native_fd = -1;\n            try {\n                Field f = fd.getClass().getDeclaredField(\"descriptor\"); //NoSuchFieldException\n                f.setAccessible(true);\n                native_fd = f.getInt(fd); //IllegalAccessException\n            } catch (NoSuchFieldException e) {\n                throw new RuntimeException(e);\n            } catch (IllegalAccessException e) {\n                throw new RuntimeException(e);\n            }\n            _setDataSourceFd(native_fd);\n        } else {\n            ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(fd);\n            try {\n                _setDataSourceFd(pfd.getFd());\n            } finally {\n                pfd.close();\n            }\n        }\n    }\n\n    /**\n     * Sets the data source (FileDescriptor) to use.  The FileDescriptor must be\n     * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility\n     * to close the file descriptor. It is safe to do so as soon as this call returns.\n     *\n     * @param fd the FileDescriptor for the file you want to play\n     * @param offset the offset into the file where the data to be played starts, in bytes\n     * @param length the length in bytes of the data to be played\n     * @throws IllegalStateException if it is called in an invalid state\n     */\n    private void setDataSource(FileDescriptor fd, long offset, long length)\n            throws IOException, IllegalArgumentException, IllegalStateException {\n        // FIXME: handle offset, length\n        setDataSource(fd);\n    }\n\n    public void setDataSource(IMediaDataSource mediaDataSource)\n            throws IllegalArgumentException, SecurityException, IllegalStateException {\n        _setDataSource(mediaDataSource);\n    }\n\n    public void setAndroidIOCallback(IAndroidIO androidIO)\n            throws IllegalArgumentException, SecurityException, IllegalStateException {\n        _setAndroidIOCallback(androidIO);\n    }\n\n    private native void _setDataSource(String path, String[] keys, String[] values)\n            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;\n\n    private native void _setDataSourceFd(int fd)\n            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;\n\n    private native void _setDataSource(IMediaDataSource mediaDataSource)\n            throws IllegalArgumentException, SecurityException, IllegalStateException;\n\n    private native void _setAndroidIOCallback(IAndroidIO androidIO)\n            throws IllegalArgumentException, SecurityException, IllegalStateException;\n\n    @Override\n    public String getDataSource() {\n        return mDataSource;\n    }\n\n    @Override\n    public void prepareAsync() throws IllegalStateException {\n        _prepareAsync();\n    }\n\n    public native void _prepareAsync() throws IllegalStateException;\n\n    @Override\n    public void start() throws IllegalStateException {\n        stayAwake(true);\n        _start();\n    }\n\n    private native void _start() throws IllegalStateException;\n\n    @Override\n    public void stop() throws IllegalStateException {\n        stayAwake(false);\n        _stop();\n    }\n\n    private native void _stop() throws IllegalStateException;\n\n    @Override\n    public void pause() throws IllegalStateException {\n        stayAwake(false);\n        _pause();\n    }\n\n    private native void _pause() throws IllegalStateException;\n\n    @SuppressLint(\"Wakelock\")\n    @Override\n    public void setWakeMode(Context context, int mode) {\n        boolean washeld = false;\n        if (mWakeLock != null) {\n            if (mWakeLock.isHeld()) {\n                washeld = true;\n                mWakeLock.release();\n            }\n            mWakeLock = null;\n        }\n\n        PowerManager pm = (PowerManager) context\n                .getSystemService(Context.POWER_SERVICE);\n        mWakeLock = pm.newWakeLock(mode | PowerManager.ON_AFTER_RELEASE,\n                IjkMediaPlayer.class.getName());\n        mWakeLock.setReferenceCounted(false);\n        if (washeld) {\n            mWakeLock.acquire();\n        }\n    }\n\n    @Override\n    public void setScreenOnWhilePlaying(boolean screenOn) {\n        if (mScreenOnWhilePlaying != screenOn) {\n            if (screenOn && mSurfaceHolder == null) {\n                DebugLog.w(TAG,\n                        \"setScreenOnWhilePlaying(true) is ineffective without a SurfaceHolder\");\n            }\n            mScreenOnWhilePlaying = screenOn;\n            updateSurfaceScreenOn();\n        }\n    }\n\n    @SuppressLint(\"Wakelock\")\n    private void stayAwake(boolean awake) {\n        if (mWakeLock != null) {\n            if (awake && !mWakeLock.isHeld()) {\n                mWakeLock.acquire();\n            } else if (!awake && mWakeLock.isHeld()) {\n                mWakeLock.release();\n            }\n        }\n        mStayAwake = awake;\n        updateSurfaceScreenOn();\n    }\n\n    private void updateSurfaceScreenOn() {\n        if (mSurfaceHolder != null) {\n            mSurfaceHolder.setKeepScreenOn(mScreenOnWhilePlaying && mStayAwake);\n        }\n    }\n\n    @Override\n    public IjkTrackInfo[] getTrackInfo() {\n        Bundle bundle = getMediaMeta();\n        if (bundle == null)\n            return null;\n\n        IjkMediaMeta mediaMeta = IjkMediaMeta.parse(bundle);\n        if (mediaMeta == null || mediaMeta.mStreams == null)\n            return null;\n\n        ArrayList<IjkTrackInfo> trackInfos = new ArrayList<IjkTrackInfo>();\n        for (IjkMediaMeta.IjkStreamMeta streamMeta: mediaMeta.mStreams) {\n            IjkTrackInfo trackInfo = new IjkTrackInfo(streamMeta);\n            if (streamMeta.mType.equalsIgnoreCase(IjkMediaMeta.IJKM_VAL_TYPE__VIDEO)) {\n                trackInfo.setTrackType(ITrackInfo.MEDIA_TRACK_TYPE_VIDEO);\n            } else if (streamMeta.mType.equalsIgnoreCase(IjkMediaMeta.IJKM_VAL_TYPE__AUDIO)) {\n                trackInfo.setTrackType(ITrackInfo.MEDIA_TRACK_TYPE_AUDIO);\n            } else if (streamMeta.mType.equalsIgnoreCase(IjkMediaMeta.IJKM_VAL_TYPE__TIMEDTEXT)) {\n                trackInfo.setTrackType(ITrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT);\n            }\n            trackInfos.add(trackInfo);\n        }\n\n        return trackInfos.toArray(new IjkTrackInfo[trackInfos.size()]);\n    }\n\n    // TODO: @Override\n    public int getSelectedTrack(int trackType) {\n        switch (trackType) {\n            case ITrackInfo.MEDIA_TRACK_TYPE_VIDEO:\n                return (int)_getPropertyLong(FFP_PROP_INT64_SELECTED_VIDEO_STREAM, -1);\n            case ITrackInfo.MEDIA_TRACK_TYPE_AUDIO:\n                return (int)_getPropertyLong(FFP_PROP_INT64_SELECTED_AUDIO_STREAM, -1);\n            case ITrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT:\n                return (int)_getPropertyLong(FFP_PROP_INT64_SELECTED_TIMEDTEXT_STREAM, -1);\n            default:\n                return -1;\n        }\n    }\n\n    // experimental, should set DEFAULT_MIN_FRAMES and MAX_MIN_FRAMES to 25\n    // TODO: @Override\n    public void selectTrack(int track) {\n        _setStreamSelected(track, true);\n    }\n\n    // experimental, should set DEFAULT_MIN_FRAMES and MAX_MIN_FRAMES to 25\n    // TODO: @Override\n    public void deselectTrack(int track) {\n        _setStreamSelected(track, false);\n    }\n\n    private native void _setStreamSelected(int stream, boolean select);\n\n    @Override\n    public int getVideoWidth() {\n        return mVideoWidth;\n    }\n\n    @Override\n    public int getVideoHeight() {\n        return mVideoHeight;\n    }\n\n    @Override\n    public int getVideoSarNum() {\n        return mVideoSarNum;\n    }\n\n    @Override\n    public int getVideoSarDen() {\n        return mVideoSarDen;\n    }\n\n    @Override\n    public native boolean isPlaying();\n\n    @Override\n    public native void seekTo(long msec) throws IllegalStateException;\n\n    @Override\n    public native long getCurrentPosition();\n\n    @Override\n    public native long getDuration();\n\n    /**\n     * Releases resources associated with this IjkMediaPlayer object. It is\n     * considered good practice to call this method when you're done using the\n     * IjkMediaPlayer. In particular, whenever an Activity of an application is\n     * paused (its onPause() method is called), or stopped (its onStop() method\n     * is called), this method should be invoked to release the IjkMediaPlayer\n     * object, unless the application has a special need to keep the object\n     * around. In addition to unnecessary resources (such as memory and\n     * instances of codecs) being held, failure to call this method immediately\n     * if a IjkMediaPlayer object is no longer needed may also lead to\n     * continuous battery consumption for mobile devices, and playback failure\n     * for other applications if no multiple instances of the same codec are\n     * supported on a device. Even if multiple instances of the same codec are\n     * supported, some performance degradation may be expected when unnecessary\n     * multiple instances are used at the same time.\n     */\n    @Override\n    public void release() {\n        stayAwake(false);\n        updateSurfaceScreenOn();\n        resetListeners();\n        _release();\n    }\n\n    private native void _release();\n\n    @Override\n    public void reset() {\n        stayAwake(false);\n        _reset();\n        // make sure none of the listeners get called anymore\n        mEventHandler.removeCallbacksAndMessages(null);\n\n        mVideoWidth = 0;\n        mVideoHeight = 0;\n    }\n\n    private native void _reset();\n\n    /**\n     * Sets the player to be looping or non-looping.\n     *\n     * @param looping whether to loop or not\n     */\n    @Override\n    public void setLooping(boolean looping) {\n        int loopCount = looping ? 0 : 1;\n        setOption(OPT_CATEGORY_PLAYER, \"loop\", loopCount);\n        _setLoopCount(loopCount);\n    }\n\n    private native void _setLoopCount(int loopCount);\n\n    /**\n     * Checks whether the MediaPlayer is looping or non-looping.\n     *\n     * @return true if the MediaPlayer is currently looping, false otherwise\n     */\n    @Override\n    public boolean isLooping() {\n        int loopCount = _getLoopCount();\n        return loopCount != 1;\n    }\n\n    private native int _getLoopCount();\n\n    public void setSpeed(float speed) {\n        _setPropertyFloat(FFP_PROP_FLOAT_PLAYBACK_RATE, speed);\n    }\n\n    public float getSpeed(float speed) {\n        return _getPropertyFloat(FFP_PROP_FLOAT_PLAYBACK_RATE, .0f);\n    }\n\n    public int getVideoDecoder() {\n        return (int)_getPropertyLong(FFP_PROP_INT64_VIDEO_DECODER, FFP_PROPV_DECODER_UNKNOWN);\n    }\n\n    public float getVideoOutputFramesPerSecond() {\n        return _getPropertyFloat(PROP_FLOAT_VIDEO_OUTPUT_FRAMES_PER_SECOND, 0.0f);\n    }\n\n    public float getVideoDecodeFramesPerSecond() {\n        return _getPropertyFloat(PROP_FLOAT_VIDEO_DECODE_FRAMES_PER_SECOND, 0.0f);\n    }\n\n    public long getVideoCachedDuration() {\n        return _getPropertyLong(FFP_PROP_INT64_VIDEO_CACHED_DURATION, 0);\n    }\n\n    public long getAudioCachedDuration() {\n        return _getPropertyLong(FFP_PROP_INT64_AUDIO_CACHED_DURATION, 0);\n    }\n\n    public long getVideoCachedBytes() {\n        return _getPropertyLong(FFP_PROP_INT64_VIDEO_CACHED_BYTES, 0);\n    }\n\n    public long getAudioCachedBytes() {\n        return _getPropertyLong(FFP_PROP_INT64_AUDIO_CACHED_BYTES, 0);\n    }\n\n    public long getVideoCachedPackets() {\n        return _getPropertyLong(FFP_PROP_INT64_VIDEO_CACHED_PACKETS, 0);\n    }\n\n    public long getAudioCachedPackets() {\n        return _getPropertyLong(FFP_PROP_INT64_AUDIO_CACHED_PACKETS, 0);\n    }\n\n    public long getAsyncStatisticBufBackwards() {\n        return _getPropertyLong(FFP_PROP_INT64_ASYNC_STATISTIC_BUF_BACKWARDS, 0);\n    }\n\n    public long getAsyncStatisticBufForwards() {\n        return _getPropertyLong(FFP_PROP_INT64_ASYNC_STATISTIC_BUF_FORWARDS, 0);\n    }\n\n    public long getAsyncStatisticBufCapacity() {\n        return _getPropertyLong(FFP_PROP_INT64_ASYNC_STATISTIC_BUF_CAPACITY, 0);\n    }\n\n    public long getTrafficStatisticByteCount() {\n        return _getPropertyLong(FFP_PROP_INT64_TRAFFIC_STATISTIC_BYTE_COUNT, 0);\n    }\n\n    public long getCacheStatisticPhysicalPos() {\n        return _getPropertyLong(FFP_PROP_INT64_CACHE_STATISTIC_PHYSICAL_POS, 0);\n    }\n\n    public long getCacheStatisticFileForwards() {\n        return _getPropertyLong(FFP_PROP_INT64_CACHE_STATISTIC_FILE_FORWARDS, 0);\n    }\n\n    public long getCacheStatisticFilePos() {\n        return _getPropertyLong(FFP_PROP_INT64_CACHE_STATISTIC_FILE_POS, 0);\n    }\n\n    public long getCacheStatisticCountBytes() {\n        return _getPropertyLong(FFP_PROP_INT64_CACHE_STATISTIC_COUNT_BYTES, 0);\n    }\n\n    public long getFileSize() {\n        return _getPropertyLong(FFP_PROP_INT64_LOGICAL_FILE_SIZE, 0);\n    }\n\n    public long getBitRate() {\n        return _getPropertyLong(FFP_PROP_INT64_BIT_RATE, 0);\n    }\n\n    public long getTcpSpeed() {\n        return _getPropertyLong(FFP_PROP_INT64_TCP_SPEED, 0);\n    }\n\n    public long getSeekLoadDuration() {\n        return _getPropertyLong(FFP_PROP_INT64_LATEST_SEEK_LOAD_DURATION, 0);\n    }\n\n    private native float _getPropertyFloat(int property, float defaultValue);\n    private native void  _setPropertyFloat(int property, float value);\n    private native long  _getPropertyLong(int property, long defaultValue);\n    private native void  _setPropertyLong(int property, long value);\n\n    public float getDropFrameRate() {\n        return _getPropertyFloat(FFP_PROP_FLOAT_DROP_FRAME_RATE, .0f);\n    }\n\n    @Override\n    public native void setVolume(float leftVolume, float rightVolume);\n\n    @Override\n    public native int getAudioSessionId();\n\n    @Override\n    public MediaInfo getMediaInfo() {\n        MediaInfo mediaInfo = new MediaInfo();\n        mediaInfo.mMediaPlayerName = \"ijkplayer\";\n\n        String videoCodecInfo = _getVideoCodecInfo();\n        if (!TextUtils.isEmpty(videoCodecInfo)) {\n            String nodes[] = videoCodecInfo.split(\",\");\n            if (nodes.length >= 2) {\n                mediaInfo.mVideoDecoder = nodes[0];\n                mediaInfo.mVideoDecoderImpl = nodes[1];\n            } else if (nodes.length >= 1) {\n                mediaInfo.mVideoDecoder = nodes[0];\n                mediaInfo.mVideoDecoderImpl = \"\";\n            }\n        }\n\n        String audioCodecInfo = _getAudioCodecInfo();\n        if (!TextUtils.isEmpty(audioCodecInfo)) {\n            String nodes[] = audioCodecInfo.split(\",\");\n            if (nodes.length >= 2) {\n                mediaInfo.mAudioDecoder = nodes[0];\n                mediaInfo.mAudioDecoderImpl = nodes[1];\n            } else if (nodes.length >= 1) {\n                mediaInfo.mAudioDecoder = nodes[0];\n                mediaInfo.mAudioDecoderImpl = \"\";\n            }\n        }\n\n        try {\n            mediaInfo.mMeta = IjkMediaMeta.parse(_getMediaMeta());\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n        return mediaInfo;\n    }\n\n    @Override\n    public void setLogEnabled(boolean enable) {\n        // do nothing\n    }\n\n    @Override\n    public boolean isPlayable() {\n        return true;\n    }\n\n    private native String _getVideoCodecInfo();\n    private native String _getAudioCodecInfo();\n\n    public void setOption(int category, String name, String value)\n    {\n        _setOption(category, name, value);\n    }\n\n    public void setOption(int category, String name, long value)\n    {\n        _setOption(category, name, value);\n    }\n\n    private native void _setOption(int category, String name, String value);\n    private native void _setOption(int category, String name, long value);\n\n    public Bundle getMediaMeta() {\n        return _getMediaMeta();\n    }\n    private native Bundle _getMediaMeta();\n\n    public static String getColorFormatName(int mediaCodecColorFormat) {\n        return _getColorFormatName(mediaCodecColorFormat);\n    }\n\n    private static native String _getColorFormatName(int mediaCodecColorFormat);\n\n    @Override\n    public void setAudioStreamType(int streamtype) {\n        // do nothing\n    }\n\n    @Override\n    public void setKeepInBackground(boolean keepInBackground) {\n        // do nothing\n    }\n\n    private static native void native_init();\n\n    private native void native_setup(Object IjkMediaPlayer_this);\n\n    private native void native_finalize();\n\n    private native void native_message_loop(Object IjkMediaPlayer_this);\n\n    protected void finalize() throws Throwable {\n        super.finalize();\n        native_finalize();\n    }\n\n    public void httphookReconnect() {\n        _setPropertyLong(FFP_PROP_INT64_IMMEDIATE_RECONNECT, 1);\n    }\n\n    public void setCacheShare(int share) {\n        _setPropertyLong(FFP_PROP_INT64_SHARE_CACHE_DATA, (long)share);\n    }\n\n    private static class EventHandler extends Handler {\n        private final WeakReference<IjkMediaPlayer> mWeakPlayer;\n\n        public EventHandler(IjkMediaPlayer mp, Looper looper) {\n            super(looper);\n            mWeakPlayer = new WeakReference<IjkMediaPlayer>(mp);\n        }\n\n        @Override\n        public void handleMessage(Message msg) {\n            IjkMediaPlayer player = mWeakPlayer.get();\n            if (player == null || player.mNativeMediaPlayer == 0) {\n                DebugLog.w(TAG,\n                        \"IjkMediaPlayer went away with unhandled events\");\n                return;\n            }\n\n            switch (msg.what) {\n            case MEDIA_PREPARED:\n                player.notifyOnPrepared();\n                return;\n\n            case MEDIA_PLAYBACK_COMPLETE:\n                player.stayAwake(false);\n                player.notifyOnCompletion();\n                return;\n\n            case MEDIA_BUFFERING_UPDATE:\n                long bufferPosition = msg.arg1;\n                if (bufferPosition < 0) {\n                    bufferPosition = 0;\n                }\n\n                long percent = 0;\n                long duration = player.getDuration();\n                if (duration > 0) {\n                    percent = bufferPosition * 100 / duration;\n                }\n                if (percent >= 100) {\n                    percent = 100;\n                }\n\n                // DebugLog.efmt(TAG, \"Buffer (%d%%) %d/%d\",  percent, bufferPosition, duration);\n                player.notifyOnBufferingUpdate((int)percent);\n                return;\n\n            case MEDIA_SEEK_COMPLETE:\n                player.notifyOnSeekComplete();\n                return;\n\n            case MEDIA_SET_VIDEO_SIZE:\n                player.mVideoWidth = msg.arg1;\n                player.mVideoHeight = msg.arg2;\n                player.notifyOnVideoSizeChanged(player.mVideoWidth, player.mVideoHeight,\n                        player.mVideoSarNum, player.mVideoSarDen);\n                return;\n\n            case MEDIA_ERROR:\n                DebugLog.e(TAG, \"Error (\" + msg.arg1 + \",\" + msg.arg2 + \")\");\n                if (!player.notifyOnError(msg.arg1, msg.arg2)) {\n                    player.notifyOnCompletion();\n                }\n                player.stayAwake(false);\n                return;\n\n            case MEDIA_INFO:\n                switch (msg.arg1) {\n                    case MEDIA_INFO_VIDEO_RENDERING_START:\n                        DebugLog.i(TAG, \"Info: MEDIA_INFO_VIDEO_RENDERING_START\\n\");\n                        break;\n                }\n                player.notifyOnInfo(msg.arg1, msg.arg2);\n                // No real default action so far.\n                return;\n            case MEDIA_TIMED_TEXT:\n                if (msg.obj == null) {\n                    player.notifyOnTimedText(null);\n                } else {\n                    IjkTimedText text = new IjkTimedText(new Rect(0, 0, 1, 1), (String)msg.obj);\n                    player.notifyOnTimedText(text);\n                }\n                return;\n            case MEDIA_NOP: // interface test message - ignore\n                break;\n\n            case MEDIA_SET_VIDEO_SAR:\n                player.mVideoSarNum = msg.arg1;\n                player.mVideoSarDen = msg.arg2;\n                player.notifyOnVideoSizeChanged(player.mVideoWidth, player.mVideoHeight,\n                        player.mVideoSarNum, player.mVideoSarDen);\n                break;\n\n            default:\n                DebugLog.e(TAG, \"Unknown message type \" + msg.what);\n            }\n        }\n    }\n\n    /*\n     * Called from native code when an interesting event happens. This method\n     * just uses the EventHandler system to post the event back to the main app\n     * thread. We use a weak reference to the original IjkMediaPlayer object so\n     * that the native code is safe from the object disappearing from underneath\n     * it. (This is the cookie passed to native_setup().)\n     */\n    @CalledByNative\n    private static void postEventFromNative(Object weakThiz, int what,\n            int arg1, int arg2, Object obj) {\n        if (weakThiz == null)\n            return;\n\n        @SuppressWarnings(\"rawtypes\")\n        IjkMediaPlayer mp = (IjkMediaPlayer) ((WeakReference) weakThiz).get();\n        if (mp == null) {\n            return;\n        }\n\n        if (what == MEDIA_INFO && arg1 == MEDIA_INFO_STARTED_AS_NEXT) {\n            // this acquires the wakelock if needed, and sets the client side\n            // state\n            mp.start();\n        }\n        if (mp.mEventHandler != null) {\n            Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj);\n            mp.mEventHandler.sendMessage(m);\n        }\n    }\n\n    /*\n     * ControlMessage\n     */\n\n    private OnControlMessageListener mOnControlMessageListener;\n    public void setOnControlMessageListener(OnControlMessageListener listener) {\n        mOnControlMessageListener = listener;\n    }\n\n    public interface OnControlMessageListener {\n        String onControlResolveSegmentUrl(int segment);\n    }\n\n    /*\n     * NativeInvoke\n     */\n\n    private OnNativeInvokeListener mOnNativeInvokeListener;\n    public void setOnNativeInvokeListener(OnNativeInvokeListener listener) {\n        mOnNativeInvokeListener = listener;\n    }\n\n    public interface OnNativeInvokeListener {\n\n        int CTRL_WILL_TCP_OPEN = 0x20001;               // NO ARGS\n        int CTRL_DID_TCP_OPEN = 0x20002;                // ARG_ERROR, ARG_FAMILIY, ARG_IP, ARG_PORT, ARG_FD\n\n        int CTRL_WILL_HTTP_OPEN = 0x20003;              // ARG_URL, ARG_SEGMENT_INDEX, ARG_RETRY_COUNTER\n        int CTRL_WILL_LIVE_OPEN = 0x20005;              // ARG_URL, ARG_RETRY_COUNTER\n        int CTRL_WILL_CONCAT_RESOLVE_SEGMENT = 0x20007; // ARG_URL, ARG_SEGMENT_INDEX, ARG_RETRY_COUNTER\n\n        int EVENT_WILL_HTTP_OPEN = 0x1;                 // ARG_URL\n        int EVENT_DID_HTTP_OPEN = 0x2;                  // ARG_URL, ARG_ERROR, ARG_HTTP_CODE\n        int EVENT_WILL_HTTP_SEEK = 0x3;                 // ARG_URL, ARG_OFFSET\n        int EVENT_DID_HTTP_SEEK = 0x4;                  // ARG_URL, ARG_OFFSET, ARG_ERROR, ARG_HTTP_CODE, ARG_FILE_SIZE\n\n        String ARG_URL = \"url\";\n        String ARG_SEGMENT_INDEX = \"segment_index\";\n        String ARG_RETRY_COUNTER = \"retry_counter\";\n\n        String ARG_ERROR = \"error\";\n        String ARG_FAMILIY = \"family\";\n        String ARG_IP = \"ip\";\n        String ARG_PORT = \"port\";\n        String ARG_FD = \"fd\";\n\n        String ARG_OFFSET = \"offset\";\n        String ARG_HTTP_CODE = \"http_code\";\n        String ARG_FILE_SIZE = \"file_size\";\n\n        /*\n         * @return true if invoke is handled\n         * @throws Exception on any error\n         */\n        boolean onNativeInvoke(int what, Bundle args);\n    }\n\n    @CalledByNative\n    private static boolean onNativeInvoke(Object weakThiz, int what, Bundle args) {\n        DebugLog.ifmt(TAG, \"onNativeInvoke %d\", what);\n        if (weakThiz == null || !(weakThiz instanceof WeakReference<?>))\n            throw new IllegalStateException(\"<null weakThiz>.onNativeInvoke()\");\n\n        @SuppressWarnings(\"unchecked\")\n        WeakReference<IjkMediaPlayer> weakPlayer = (WeakReference<IjkMediaPlayer>) weakThiz;\n        IjkMediaPlayer player = weakPlayer.get();\n        if (player == null)\n            throw new IllegalStateException(\"<null weakPlayer>.onNativeInvoke()\");\n\n        OnNativeInvokeListener listener = player.mOnNativeInvokeListener;\n        if (listener != null && listener.onNativeInvoke(what, args))\n            return true;\n\n        switch (what) {\n            case OnNativeInvokeListener.CTRL_WILL_CONCAT_RESOLVE_SEGMENT: {\n                OnControlMessageListener onControlMessageListener = player.mOnControlMessageListener;\n                if (onControlMessageListener == null)\n                    return false;\n\n                int segmentIndex = args.getInt(OnNativeInvokeListener.ARG_SEGMENT_INDEX, -1);\n                if (segmentIndex < 0)\n                    throw new InvalidParameterException(\"onNativeInvoke(invalid segment index)\");\n\n                String newUrl = onControlMessageListener.onControlResolveSegmentUrl(segmentIndex);\n                if (newUrl == null)\n                    throw new RuntimeException(new IOException(\"onNativeInvoke() = <NULL newUrl>\"));\n\n                args.putString(OnNativeInvokeListener.ARG_URL, newUrl);\n                return true;\n            }\n            default:\n                return false;\n        }\n    }\n\n    /*\n     * MediaCodec select\n     */\n\n    public interface OnMediaCodecSelectListener {\n        String onMediaCodecSelect(IMediaPlayer mp, String mimeType, int profile, int level);\n    }\n    private OnMediaCodecSelectListener mOnMediaCodecSelectListener;\n    public void setOnMediaCodecSelectListener(OnMediaCodecSelectListener listener) {\n        mOnMediaCodecSelectListener = listener;\n    }\n\n    public void resetListeners() {\n        super.resetListeners();\n        mOnMediaCodecSelectListener = null;\n    }\n\n    @CalledByNative\n    private static String onSelectCodec(Object weakThiz, String mimeType, int profile, int level) {\n        if (weakThiz == null || !(weakThiz instanceof WeakReference<?>))\n            return null;\n\n        @SuppressWarnings(\"unchecked\")\n        WeakReference<IjkMediaPlayer> weakPlayer = (WeakReference<IjkMediaPlayer>) weakThiz;\n        IjkMediaPlayer player = weakPlayer.get();\n        if (player == null)\n            return null;\n\n        OnMediaCodecSelectListener listener = player.mOnMediaCodecSelectListener;\n        if (listener == null)\n            listener = DefaultMediaCodecSelector.sInstance;\n\n        return listener.onMediaCodecSelect(player, mimeType, profile, level);\n    }\n\n    public static class DefaultMediaCodecSelector implements OnMediaCodecSelectListener {\n        public static final DefaultMediaCodecSelector sInstance = new DefaultMediaCodecSelector();\n\n        @SuppressWarnings(\"deprecation\")\n        @TargetApi(Build.VERSION_CODES.JELLY_BEAN)\n        public String onMediaCodecSelect(IMediaPlayer mp, String mimeType, int profile, int level) {\n            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)\n                return null;\n\n            if (TextUtils.isEmpty(mimeType))\n                return null;\n\n            Log.i(TAG, String.format(Locale.US, \"onSelectCodec: mime=%s, profile=%d, level=%d\", mimeType, profile, level));\n            ArrayList<IjkMediaCodecInfo> candidateCodecList = new ArrayList<IjkMediaCodecInfo>();\n            int numCodecs = MediaCodecList.getCodecCount();\n            for (int i = 0; i < numCodecs; i++) {\n                MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);\n                Log.d(TAG, String.format(Locale.US, \"  found codec: %s\", codecInfo.getName()));\n                if (codecInfo.isEncoder())\n                    continue;\n\n                String[] types = codecInfo.getSupportedTypes();\n                if (types == null)\n                    continue;\n\n                for(String type: types) {\n                    if (TextUtils.isEmpty(type))\n                        continue;\n\n                    Log.d(TAG, String.format(Locale.US, \"    mime: %s\", type));\n                    if (!type.equalsIgnoreCase(mimeType))\n                        continue;\n\n                    IjkMediaCodecInfo candidate = IjkMediaCodecInfo.setupCandidate(codecInfo, mimeType);\n                    if (candidate == null)\n                        continue;\n\n                    candidateCodecList.add(candidate);\n                    Log.i(TAG, String.format(Locale.US, \"candidate codec: %s rank=%d\", codecInfo.getName(), candidate.mRank));\n                    candidate.dumpProfileLevels(mimeType);\n                }\n            }\n\n            if (candidateCodecList.isEmpty()) {\n                return null;\n            }\n\n            IjkMediaCodecInfo bestCodec = candidateCodecList.get(0);\n\n            for (IjkMediaCodecInfo codec : candidateCodecList) {\n                if (codec.mRank > bestCodec.mRank) {\n                    bestCodec = codec;\n                }\n            }\n\n            if (bestCodec.mRank < IjkMediaCodecInfo.RANK_LAST_CHANCE) {\n                Log.w(TAG, String.format(Locale.US, \"unaccetable codec: %s\", bestCodec.mCodecInfo.getName()));\n                return null;\n            }\n\n            Log.i(TAG, String.format(Locale.US, \"selected codec: %s rank=%d\", bestCodec.mCodecInfo.getName(), bestCodec.mRank));\n            return bestCodec.mCodecInfo.getName();\n        }\n    }\n\n    public static native void native_profileBegin(String libName);\n    public static native void native_profileEnd();\n    public static native void native_setLogLevel(int level);\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkTimedText.java",
    "content": "/*\n * Copyright (C) 2016 Zheng Yuan <zhengyuan10503@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player;\n\nimport android.graphics.Rect;\nimport java.lang.String;\n\npublic final class IjkTimedText {\n\n    private Rect mTextBounds = null;\n    private String mTextChars = null;\n\n    public IjkTimedText(Rect bounds, String text) {\n        mTextBounds = bounds;\n        mTextChars = text;\n    }\n\n    public Rect getBounds() {\n        return mTextBounds;\n    }\n\n    public String getText() {\n        return mTextChars;\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/MediaInfo.java",
    "content": "/*\n * Copyright (C) 2013-2014 Bilibili\n * Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player;\n\npublic class MediaInfo {\n    public String mMediaPlayerName;\n\n    public String mVideoDecoder;\n    public String mVideoDecoderImpl;\n\n    public String mAudioDecoder;\n    public String mAudioDecoderImpl;\n\n    public IjkMediaMeta mMeta;\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/MediaPlayerProxy.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.view.Surface;\nimport android.view.SurfaceHolder;\n\nimport java.io.FileDescriptor;\nimport java.io.IOException;\nimport java.util.Map;\n\nimport tv.danmaku.ijk.media.player.misc.IMediaDataSource;\nimport tv.danmaku.ijk.media.player.misc.ITrackInfo;\n\npublic class MediaPlayerProxy implements IMediaPlayer {\n    protected final IMediaPlayer mBackEndMediaPlayer;\n\n    public MediaPlayerProxy(IMediaPlayer backEndMediaPlayer) {\n        mBackEndMediaPlayer = backEndMediaPlayer;\n    }\n\n    public IMediaPlayer getInternalMediaPlayer() {\n        return mBackEndMediaPlayer;\n    }\n\n    @Override\n    public void setDisplay(SurfaceHolder sh) {\n        mBackEndMediaPlayer.setDisplay(sh);\n    }\n\n    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)\n    @Override\n    public void setSurface(Surface surface) {\n        mBackEndMediaPlayer.setSurface(surface);\n    }\n\n    @Override\n    public void setDataSource(Context context, Uri uri)\n            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {\n        mBackEndMediaPlayer.setDataSource(context, uri);\n    }\n\n    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)\n    @Override\n    public void setDataSource(Context context, Uri uri, Map<String, String> headers)\n            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {\n        mBackEndMediaPlayer.setDataSource(context, uri, headers);\n    }\n\n    @Override\n    public void setDataSource(FileDescriptor fd)\n            throws IOException, IllegalArgumentException, IllegalStateException {\n        mBackEndMediaPlayer.setDataSource(fd);\n    }\n\n    @Override\n    public void setDataSource(String path) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {\n        mBackEndMediaPlayer.setDataSource(path);\n    }\n\n    @Override\n    public void setDataSource(IMediaDataSource mediaDataSource)  {\n        mBackEndMediaPlayer.setDataSource(mediaDataSource);\n    }\n\n    @Override\n    public String getDataSource() {\n        return mBackEndMediaPlayer.getDataSource();\n    }\n\n    @Override\n    public void prepareAsync() throws IllegalStateException {\n        mBackEndMediaPlayer.prepareAsync();\n    }\n\n    @Override\n    public void start() throws IllegalStateException {\n        mBackEndMediaPlayer.start();\n    }\n\n    @Override\n    public void stop() throws IllegalStateException {\n        mBackEndMediaPlayer.stop();\n    }\n\n    @Override\n    public void pause() throws IllegalStateException {\n        mBackEndMediaPlayer.pause();\n    }\n\n    @Override\n    public void setScreenOnWhilePlaying(boolean screenOn) {\n        mBackEndMediaPlayer.setScreenOnWhilePlaying(screenOn);\n    }\n\n    @Override\n    public int getVideoWidth() {\n        return mBackEndMediaPlayer.getVideoWidth();\n    }\n\n    @Override\n    public int getVideoHeight() {\n        return mBackEndMediaPlayer.getVideoHeight();\n    }\n\n    @Override\n    public boolean isPlaying() {\n        return mBackEndMediaPlayer.isPlaying();\n    }\n\n    @Override\n    public void seekTo(long msec) throws IllegalStateException {\n        mBackEndMediaPlayer.seekTo(msec);\n    }\n\n    @Override\n    public long getCurrentPosition() {\n        return mBackEndMediaPlayer.getCurrentPosition();\n    }\n\n    @Override\n    public long getDuration() {\n        return mBackEndMediaPlayer.getDuration();\n    }\n\n    @Override\n    public void release() {\n        mBackEndMediaPlayer.release();\n    }\n\n    @Override\n    public void reset() {\n        mBackEndMediaPlayer.reset();\n    }\n\n    @Override\n    public void setVolume(float leftVolume, float rightVolume) {\n        mBackEndMediaPlayer.setVolume(leftVolume, rightVolume);\n    }\n\n    @Override\n    public int getAudioSessionId() {\n        return mBackEndMediaPlayer.getAudioSessionId();\n    }\n\n    @Override\n    public MediaInfo getMediaInfo() {\n        return mBackEndMediaPlayer.getMediaInfo();\n    }\n\n    @Override\n    public void setLogEnabled(boolean enable) {\n\n    }\n\n    @Override\n    public boolean isPlayable() {\n        return false;\n    }\n\n    @Override\n    public void setOnPreparedListener(OnPreparedListener listener) {\n        if (listener != null) {\n            final OnPreparedListener finalListener = listener;\n            mBackEndMediaPlayer.setOnPreparedListener(new OnPreparedListener() {\n                @Override\n                public void onPrepared(IMediaPlayer mp) {\n                    finalListener.onPrepared(MediaPlayerProxy.this);\n                }\n            });\n        } else {\n            mBackEndMediaPlayer.setOnPreparedListener(null);\n        }\n    }\n\n    @Override\n    public void setOnCompletionListener(OnCompletionListener listener) {\n        if (listener != null) {\n            final OnCompletionListener finalListener = listener;\n            mBackEndMediaPlayer.setOnCompletionListener(new OnCompletionListener() {\n                @Override\n                public void onCompletion(IMediaPlayer mp) {\n                    finalListener.onCompletion(MediaPlayerProxy.this);\n                }\n            });\n        } else {\n            mBackEndMediaPlayer.setOnCompletionListener(null);\n        }\n    }\n\n    @Override\n    public void setOnBufferingUpdateListener(OnBufferingUpdateListener listener) {\n        if (listener != null) {\n            final OnBufferingUpdateListener finalListener = listener;\n            mBackEndMediaPlayer.setOnBufferingUpdateListener(new OnBufferingUpdateListener() {\n                @Override\n                public void onBufferingUpdate(IMediaPlayer mp, int percent) {\n                    finalListener.onBufferingUpdate(MediaPlayerProxy.this, percent);\n                }\n            });\n        } else {\n            mBackEndMediaPlayer.setOnBufferingUpdateListener(null);\n        }\n    }\n\n    @Override\n    public void setOnSeekCompleteListener(OnSeekCompleteListener listener) {\n        if (listener != null) {\n            final OnSeekCompleteListener finalListener = listener;\n            mBackEndMediaPlayer.setOnSeekCompleteListener(new OnSeekCompleteListener() {\n                @Override\n                public void onSeekComplete(IMediaPlayer mp) {\n                    finalListener.onSeekComplete(MediaPlayerProxy.this);\n                }\n            });\n        } else {\n            mBackEndMediaPlayer.setOnSeekCompleteListener(null);\n        }\n    }\n\n    @Override\n    public void setOnVideoSizeChangedListener(OnVideoSizeChangedListener listener) {\n        if (listener != null) {\n            final OnVideoSizeChangedListener finalListener = listener;\n            mBackEndMediaPlayer.setOnVideoSizeChangedListener(new OnVideoSizeChangedListener() {\n                @Override\n                public void onVideoSizeChanged(IMediaPlayer mp, int width, int height, int sar_num, int sar_den) {\n                    finalListener.onVideoSizeChanged(MediaPlayerProxy.this, width, height, sar_num, sar_den);\n                }\n            });\n        } else {\n            mBackEndMediaPlayer.setOnVideoSizeChangedListener(null);\n        }\n    }\n\n    @Override\n    public void setOnErrorListener(OnErrorListener listener) {\n        if (listener != null) {\n            final OnErrorListener finalListener = listener;\n            mBackEndMediaPlayer.setOnErrorListener(new OnErrorListener() {\n                @Override\n                public boolean onError(IMediaPlayer mp, int what, int extra) {\n                    return finalListener.onError(MediaPlayerProxy.this, what, extra);\n                }\n            });\n        } else {\n            mBackEndMediaPlayer.setOnErrorListener(null);\n        }\n    }\n\n    @Override\n    public void setOnInfoListener(OnInfoListener listener) {\n        if (listener != null) {\n            final OnInfoListener finalListener = listener;\n            mBackEndMediaPlayer.setOnInfoListener(new OnInfoListener() {\n                @Override\n                public boolean onInfo(IMediaPlayer mp, int what, int extra) {\n                    return finalListener.onInfo(MediaPlayerProxy.this, what, extra);\n                }\n            });\n        } else {\n            mBackEndMediaPlayer.setOnInfoListener(null);\n        }\n    }\n\n    @Override\n    public void setOnTimedTextListener(OnTimedTextListener listener) {\n        if (listener != null) {\n            final OnTimedTextListener finalListener = listener;\n            mBackEndMediaPlayer.setOnTimedTextListener(new OnTimedTextListener() {\n                @Override\n                public void onTimedText(IMediaPlayer mp, IjkTimedText text) {\n                    finalListener.onTimedText(MediaPlayerProxy.this, text);\n                }\n            });\n        } else {\n            mBackEndMediaPlayer.setOnTimedTextListener(null);\n        }\n    }\n\n    @Override\n    public void setAudioStreamType(int streamtype) {\n        mBackEndMediaPlayer.setAudioStreamType(streamtype);\n    }\n\n    @Override\n    public void setKeepInBackground(boolean keepInBackground) {\n        mBackEndMediaPlayer.setKeepInBackground(keepInBackground);\n    }\n\n    @Override\n    public int getVideoSarNum() {\n        return mBackEndMediaPlayer.getVideoSarNum();\n    }\n\n    @Override\n    public int getVideoSarDen() {\n        return mBackEndMediaPlayer.getVideoSarDen();\n    }\n\n    @Override\n    public void setWakeMode(Context context, int mode) {\n        mBackEndMediaPlayer.setWakeMode(context, mode);\n    }\n\n    @Override\n    public ITrackInfo[] getTrackInfo() {\n        return mBackEndMediaPlayer.getTrackInfo();\n    }\n\n    @Override\n    public void setLooping(boolean looping) {\n        mBackEndMediaPlayer.setLooping(looping);\n    }\n\n    @Override\n    public boolean isLooping() {\n        return mBackEndMediaPlayer.isLooping();\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/TextureMediaPlayer.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player;\n\nimport android.annotation.TargetApi;\nimport android.graphics.SurfaceTexture;\nimport android.os.Build;\nimport android.view.Surface;\nimport android.view.SurfaceHolder;\n\n@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)\npublic class TextureMediaPlayer extends MediaPlayerProxy implements IMediaPlayer, ISurfaceTextureHolder {\n    private SurfaceTexture mSurfaceTexture;\n    private ISurfaceTextureHost mSurfaceTextureHost;\n\n    public TextureMediaPlayer(IMediaPlayer backEndMediaPlayer) {\n        super(backEndMediaPlayer);\n    }\n\n    public void releaseSurfaceTexture() {\n        if (mSurfaceTexture != null) {\n            if (mSurfaceTextureHost != null) {\n                mSurfaceTextureHost.releaseSurfaceTexture(mSurfaceTexture);\n            } else {\n                mSurfaceTexture.release();\n            }\n            mSurfaceTexture = null;\n        }\n    }\n\n    //--------------------\n    // IMediaPlayer\n    //--------------------\n    @Override\n    public void reset() {\n        super.reset();\n        releaseSurfaceTexture();\n    }\n\n    @Override\n    public void release() {\n        super.release();\n        releaseSurfaceTexture();\n    }\n\n    @Override\n    public void setDisplay(SurfaceHolder sh) {\n        if (mSurfaceTexture == null)\n            super.setDisplay(sh);\n    }\n\n    @Override\n    public void setSurface(Surface surface) {\n        if (mSurfaceTexture == null)\n            super.setSurface(surface);\n    }\n\n    //--------------------\n    // ISurfaceTextureHolder\n    //--------------------\n\n    @Override\n    public void setSurfaceTexture(SurfaceTexture surfaceTexture) {\n        if (mSurfaceTexture == surfaceTexture)\n            return;\n\n        releaseSurfaceTexture();\n        mSurfaceTexture = surfaceTexture;\n        if (surfaceTexture == null) {\n            super.setSurface(null);\n        } else {\n            super.setSurface(new Surface(surfaceTexture));\n        }\n    }\n\n    @Override\n    public SurfaceTexture getSurfaceTexture() {\n        return mSurfaceTexture;\n    }\n\n    @Override\n    public void setSurfaceTextureHost(ISurfaceTextureHost surfaceTextureHost) {\n        mSurfaceTextureHost = surfaceTextureHost;\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/annotations/AccessedByNative.java",
    "content": "/*\n * Copyright (C) 2013-2014 Bilibili\n * Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * is used by the JNI generator to create the necessary JNI\n * bindings and expose this method to native code.\n */\n@Target(ElementType.FIELD)\n@Retention(RetentionPolicy.CLASS)\npublic @interface AccessedByNative {\n}"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/annotations/CalledByNative.java",
    "content": "/*\n * Copyright (C) 2013-2014 Bilibili\n * Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * is used by the JNI generator to create the necessary JNI\n * bindings and expose this method to native code.\n */\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.CLASS)\npublic @interface CalledByNative {\n    /*\n     * If present, tells which inner class the method belongs to.\n     */\n    String value() default \"\";\n}"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/exceptions/IjkMediaException.java",
    "content": "/*\n * Copyright (C) 2013-2014 Bilibili\n * Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player.exceptions;\n\npublic class IjkMediaException extends Exception {\n    private static final long serialVersionUID = 7234796519009099506L;\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/ffmpeg/FFmpegApi.java",
    "content": "package tv.danmaku.ijk.media.player.ffmpeg;\n\npublic class FFmpegApi {\n    public static native String av_base64_encode(byte in[]);\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/AndroidMediaFormat.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player.misc;\n\nimport android.annotation.TargetApi;\nimport android.media.MediaFormat;\nimport android.os.Build;\n\npublic class AndroidMediaFormat implements IMediaFormat {\n    private final MediaFormat mMediaFormat;\n\n    public AndroidMediaFormat(MediaFormat mediaFormat) {\n        mMediaFormat = mediaFormat;\n    }\n\n    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)\n    @Override\n    public int getInteger(String name) {\n        if (mMediaFormat == null)\n            return 0;\n\n        return mMediaFormat.getInteger(name);\n    }\n\n    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)\n    @Override\n    public String getString(String name) {\n        if (mMediaFormat == null)\n            return null;\n\n        return mMediaFormat.getString(name);\n    }\n\n    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)\n    @Override\n    public String toString() {\n        StringBuilder out = new StringBuilder(128);\n        out.append(getClass().getName());\n        out.append('{');\n        if (mMediaFormat != null) {\n            out.append(mMediaFormat.toString());\n        } else {\n            out.append(\"null\");\n        }\n        out.append('}');\n        return out.toString();\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/AndroidTrackInfo.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player.misc;\n\nimport android.annotation.TargetApi;\nimport android.media.MediaFormat;\nimport android.media.MediaPlayer;\nimport android.os.Build;\n\npublic class AndroidTrackInfo implements ITrackInfo {\n    private final MediaPlayer.TrackInfo mTrackInfo;\n\n    public static AndroidTrackInfo[] fromMediaPlayer(MediaPlayer mp) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)\n            return fromTrackInfo(mp.getTrackInfo());\n\n        return null;\n    }\n\n    private static AndroidTrackInfo[] fromTrackInfo(MediaPlayer.TrackInfo[] trackInfos) {\n        if (trackInfos == null)\n            return null;\n\n        AndroidTrackInfo androidTrackInfo[] = new AndroidTrackInfo[trackInfos.length];\n        for (int i = 0; i < trackInfos.length; ++i) {\n            androidTrackInfo[i] = new AndroidTrackInfo(trackInfos[i]);\n        }\n\n        return androidTrackInfo;\n    }\n\n    private AndroidTrackInfo(MediaPlayer.TrackInfo trackInfo) {\n        mTrackInfo = trackInfo;\n    }\n\n    @TargetApi(Build.VERSION_CODES.KITKAT)\n    @Override\n    public IMediaFormat getFormat() {\n        if (mTrackInfo == null)\n            return null;\n\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)\n            return null;\n\n        MediaFormat mediaFormat = mTrackInfo.getFormat();\n        if (mediaFormat == null)\n            return null;\n\n        return new AndroidMediaFormat(mediaFormat);\n    }\n\n    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)\n    @Override\n    public String getLanguage() {\n        if (mTrackInfo == null)\n            return \"und\";\n\n        return mTrackInfo.getLanguage();\n    }\n\n    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)\n    @Override\n    public int getTrackType() {\n        if (mTrackInfo == null)\n            return MEDIA_TRACK_TYPE_UNKNOWN;\n\n        return mTrackInfo.getTrackType();\n    }\n\n    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)\n    @Override\n    public String toString() {\n        StringBuilder out = new StringBuilder(128);\n        out.append(getClass().getSimpleName());\n        out.append('{');\n        if (mTrackInfo != null) {\n            out.append(mTrackInfo.toString());\n        } else {\n            out.append(\"null\");\n        }\n        out.append('}');\n        return out.toString();\n    }\n\n    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)\n    @Override\n    public String getInfoInline() {\n        if (mTrackInfo != null) {\n            return mTrackInfo.toString();\n        } else {\n            return \"null\";\n        }\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IAndroidIO.java",
    "content": "/*\n * Copyright (C) 2016 Bilibili\n * Copyright (C) 2016 Raymond Zheng <raymondzheng1412@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player.misc;\n\nimport java.io.IOException;\n\n@SuppressWarnings(\"RedundantThrows\")\npublic interface IAndroidIO {\n    int  open(String url) throws IOException;\n    int  read(byte[] buffer, int size) throws IOException;\n    long seek(long offset, int whence) throws IOException;\n    int  close() throws IOException;\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IMediaDataSource.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player.misc;\n\nimport java.io.IOException;\n\n@SuppressWarnings(\"RedundantThrows\")\npublic interface IMediaDataSource {\n    int\t readAt(long position, byte[] buffer, int offset, int size) throws IOException;\n\n    long getSize() throws IOException;\n\n    void close() throws IOException;\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IMediaFormat.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player.misc;\n\npublic interface IMediaFormat {\n    // Common keys\n    String KEY_MIME = \"mime\";\n\n    // Video Keys\n    String KEY_WIDTH = \"width\";\n    String KEY_HEIGHT = \"height\";\n\n    String getString(String name);\n\n    int getInteger(String name);\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/ITrackInfo.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player.misc;\n\npublic interface ITrackInfo {\n    int MEDIA_TRACK_TYPE_AUDIO = 2;\n    int MEDIA_TRACK_TYPE_METADATA = 5;\n    int MEDIA_TRACK_TYPE_SUBTITLE = 4;\n    int MEDIA_TRACK_TYPE_TIMEDTEXT = 3;\n    int MEDIA_TRACK_TYPE_UNKNOWN = 0;\n    int MEDIA_TRACK_TYPE_VIDEO = 1;\n\n    IMediaFormat getFormat();\n\n    String getLanguage();\n\n    int getTrackType();\n\n    String getInfoInline();\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IjkMediaFormat.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player.misc;\n\nimport android.annotation.TargetApi;\nimport android.os.Build;\nimport android.text.TextUtils;\n\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport tv.danmaku.ijk.media.player.IjkMediaMeta;\n\npublic class IjkMediaFormat implements IMediaFormat {\n    // Common\n    public static final String KEY_IJK_CODEC_LONG_NAME_UI = \"ijk-codec-long-name-ui\";\n    public static final String KEY_IJK_CODEC_NAME_UI = \"ijk-codec-name-ui\";\n    public static final String KEY_IJK_BIT_RATE_UI = \"ijk-bit-rate-ui\";\n\n    // Video\n    public static final String KEY_IJK_CODEC_PROFILE_LEVEL_UI = \"ijk-profile-level-ui\";\n    public static final String KEY_IJK_CODEC_PIXEL_FORMAT_UI = \"ijk-pixel-format-ui\";\n    public static final String KEY_IJK_RESOLUTION_UI = \"ijk-resolution-ui\";\n    public static final String KEY_IJK_FRAME_RATE_UI = \"ijk-frame-rate-ui\";\n\n    // Audio\n    public static final String KEY_IJK_SAMPLE_RATE_UI = \"ijk-sample-rate-ui\";\n    public static final String KEY_IJK_CHANNEL_UI = \"ijk-channel-ui\";\n\n    // Codec\n    public static final String CODEC_NAME_H264 = \"h264\";\n\n    public final IjkMediaMeta.IjkStreamMeta mMediaFormat;\n\n    public IjkMediaFormat(IjkMediaMeta.IjkStreamMeta streamMeta) {\n        mMediaFormat = streamMeta;\n    }\n\n    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)\n    @Override\n    public int getInteger(String name) {\n        if (mMediaFormat == null)\n            return 0;\n\n        return mMediaFormat.getInt(name);\n    }\n\n    @Override\n    public String getString(String name) {\n        if (mMediaFormat == null)\n            return null;\n\n        if (sFormatterMap.containsKey(name)) {\n            Formatter formatter = sFormatterMap.get(name);\n            return formatter.format(this);\n        }\n\n        return mMediaFormat.getString(name);\n    }\n\n    //-------------------------\n    // Formatter\n    //-------------------------\n\n    private static abstract class Formatter {\n        public String format(IjkMediaFormat mediaFormat) {\n            String value = doFormat(mediaFormat);\n            if (TextUtils.isEmpty(value))\n                return getDefaultString();\n            return value;\n        }\n\n        protected abstract String doFormat(IjkMediaFormat mediaFormat);\n\n        @SuppressWarnings(\"SameReturnValue\")\n        protected String getDefaultString() {\n            return \"N/A\";\n        }\n    }\n\n    private static final Map<String, Formatter> sFormatterMap = new HashMap<String, Formatter>();\n\n    {\n        sFormatterMap.put(KEY_IJK_CODEC_LONG_NAME_UI, new Formatter() {\n            @Override\n            public String doFormat(IjkMediaFormat mediaFormat) {\n                return mMediaFormat.getString(IjkMediaMeta.IJKM_KEY_CODEC_LONG_NAME);\n            }\n        });\n        sFormatterMap.put(KEY_IJK_CODEC_NAME_UI, new Formatter() {\n            @Override\n            public String doFormat(IjkMediaFormat mediaFormat) {\n                return mMediaFormat.getString(IjkMediaMeta.IJKM_KEY_CODEC_NAME);\n            }\n        });\n        sFormatterMap.put(KEY_IJK_BIT_RATE_UI, new Formatter() {\n            @Override\n            protected String doFormat(IjkMediaFormat mediaFormat) {\n                int bitRate = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_BITRATE);\n                if (bitRate <= 0) {\n                    return null;\n                } else if (bitRate < 1000) {\n                    return String.format(Locale.US, \"%d bit/s\", bitRate);\n                } else {\n                    return String.format(Locale.US, \"%d kb/s\", bitRate / 1000);\n                }\n            }\n        });\n        sFormatterMap.put(KEY_IJK_CODEC_PROFILE_LEVEL_UI, new Formatter() {\n            @Override\n            protected String doFormat(IjkMediaFormat mediaFormat) {\n                int profileIndex = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_CODEC_PROFILE_ID);\n                String profile;\n                switch (profileIndex) {\n                    case IjkMediaMeta.FF_PROFILE_H264_BASELINE:\n                        profile = \"Baseline\";\n                        break;\n                    case IjkMediaMeta.FF_PROFILE_H264_CONSTRAINED_BASELINE:\n                        profile = \"Constrained Baseline\";\n                        break;\n                    case IjkMediaMeta.FF_PROFILE_H264_MAIN:\n                        profile = \"Main\";\n                        break;\n                    case IjkMediaMeta.FF_PROFILE_H264_EXTENDED:\n                        profile = \"Extended\";\n                        break;\n                    case IjkMediaMeta.FF_PROFILE_H264_HIGH:\n                        profile = \"High\";\n                        break;\n                    case IjkMediaMeta.FF_PROFILE_H264_HIGH_10:\n                        profile = \"High 10\";\n                        break;\n                    case IjkMediaMeta.FF_PROFILE_H264_HIGH_10_INTRA:\n                        profile = \"High 10 Intra\";\n                        break;\n                    case IjkMediaMeta.FF_PROFILE_H264_HIGH_422:\n                        profile = \"High 4:2:2\";\n                        break;\n                    case IjkMediaMeta.FF_PROFILE_H264_HIGH_422_INTRA:\n                        profile = \"High 4:2:2 Intra\";\n                        break;\n                    case IjkMediaMeta.FF_PROFILE_H264_HIGH_444:\n                        profile = \"High 4:4:4\";\n                        break;\n                    case IjkMediaMeta.FF_PROFILE_H264_HIGH_444_PREDICTIVE:\n                        profile = \"High 4:4:4 Predictive\";\n                        break;\n                    case IjkMediaMeta.FF_PROFILE_H264_HIGH_444_INTRA:\n                        profile = \"High 4:4:4 Intra\";\n                        break;\n                    case IjkMediaMeta.FF_PROFILE_H264_CAVLC_444:\n                        profile = \"CAVLC 4:4:4\";\n                        break;\n                    default:\n                        return null;\n                }\n\n                StringBuilder sb = new StringBuilder();\n                sb.append(profile);\n\n                String codecName = mediaFormat.getString(IjkMediaMeta.IJKM_KEY_CODEC_NAME);\n                if (!TextUtils.isEmpty(codecName) && codecName.equalsIgnoreCase(CODEC_NAME_H264)) {\n                    int level = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_CODEC_LEVEL);\n                    if (level < 10)\n                        return sb.toString();\n\n                    sb.append(\" Profile Level \");\n                    sb.append((level / 10) % 10);\n                    if ((level % 10) != 0) {\n                        sb.append(\".\");\n                        sb.append(level % 10);\n                    }\n                }\n\n                return sb.toString();\n            }\n        });\n        sFormatterMap.put(KEY_IJK_CODEC_PIXEL_FORMAT_UI, new Formatter() {\n            @Override\n            protected String doFormat(IjkMediaFormat mediaFormat) {\n                return mediaFormat.getString(IjkMediaMeta.IJKM_KEY_CODEC_PIXEL_FORMAT);\n            }\n        });\n        sFormatterMap.put(KEY_IJK_RESOLUTION_UI, new Formatter() {\n            @Override\n            protected String doFormat(IjkMediaFormat mediaFormat) {\n                int width = mediaFormat.getInteger(KEY_WIDTH);\n                int height = mediaFormat.getInteger(KEY_HEIGHT);\n                int sarNum = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_SAR_NUM);\n                int sarDen = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_SAR_DEN);\n\n                if (width <= 0 || height <= 0) {\n                    return null;\n                } else if (sarNum <= 0 || sarDen <= 0) {\n                    return String.format(Locale.US, \"%d x %d\", width, height);\n                } else {\n                    return String.format(Locale.US, \"%d x %d [SAR %d:%d]\", width,\n                            height, sarNum, sarDen);\n                }\n            }\n        });\n        sFormatterMap.put(KEY_IJK_FRAME_RATE_UI, new Formatter() {\n            @Override\n            protected String doFormat(IjkMediaFormat mediaFormat) {\n                int fpsNum = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_FPS_NUM);\n                int fpsDen = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_FPS_DEN);\n                if (fpsNum <= 0 || fpsDen <= 0) {\n                    return null;\n                } else {\n                    return String.valueOf(((float) (fpsNum)) / fpsDen);\n                }\n            }\n        });\n        sFormatterMap.put(KEY_IJK_SAMPLE_RATE_UI, new Formatter() {\n            @Override\n            protected String doFormat(IjkMediaFormat mediaFormat) {\n                int sampleRate = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_SAMPLE_RATE);\n                if (sampleRate <= 0) {\n                    return null;\n                } else {\n                    return String.format(Locale.US, \"%d Hz\", sampleRate);\n                }\n            }\n        });\n        sFormatterMap.put(KEY_IJK_CHANNEL_UI, new Formatter() {\n            @Override\n            protected String doFormat(IjkMediaFormat mediaFormat) {\n                int channelLayout = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_CHANNEL_LAYOUT);\n                if (channelLayout <= 0) {\n                    return null;\n                } else {\n                    if (channelLayout == IjkMediaMeta.AV_CH_LAYOUT_MONO) {\n                        return \"mono\";\n                    } else if (channelLayout == IjkMediaMeta.AV_CH_LAYOUT_STEREO) {\n                        return \"stereo\";\n                    } else {\n                        return String.format(Locale.US, \"%x\", channelLayout);\n                    }\n                }\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IjkTrackInfo.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player.misc;\n\nimport android.text.TextUtils;\n\nimport tv.danmaku.ijk.media.player.IjkMediaMeta;\n\npublic class IjkTrackInfo implements ITrackInfo {\n    private int mTrackType = MEDIA_TRACK_TYPE_UNKNOWN;\n    private IjkMediaMeta.IjkStreamMeta mStreamMeta;\n\n    public IjkTrackInfo(IjkMediaMeta.IjkStreamMeta streamMeta) {\n        mStreamMeta = streamMeta;\n    }\n\n    public void setMediaMeta(IjkMediaMeta.IjkStreamMeta streamMeta) {\n        mStreamMeta = streamMeta;\n    }\n\n    @Override\n    public IMediaFormat getFormat() {\n        return new IjkMediaFormat(mStreamMeta);\n    }\n\n    @Override\n    public String getLanguage() {\n        if (mStreamMeta == null || TextUtils.isEmpty(mStreamMeta.mLanguage))\n            return \"und\";\n\n        return mStreamMeta.mLanguage;\n    }\n\n    @Override\n    public int getTrackType() {\n        return mTrackType;\n    }\n\n    public void setTrackType(int trackType) {\n        mTrackType = trackType;\n    }\n\n    @Override\n    public String toString() {\n        return getClass().getSimpleName() + '{' + getInfoInline() + \"}\";\n    }\n\n    @Override\n    public String getInfoInline() {\n        StringBuilder out = new StringBuilder(128);\n        switch (mTrackType) {\n            case MEDIA_TRACK_TYPE_VIDEO:\n                out.append(\"VIDEO\");\n                out.append(\", \");\n                out.append(mStreamMeta.getCodecShortNameInline());\n                out.append(\", \");\n                out.append(mStreamMeta.getBitrateInline());\n                out.append(\", \");\n                out.append(mStreamMeta.getResolutionInline());\n                break;\n            case MEDIA_TRACK_TYPE_AUDIO:\n                out.append(\"AUDIO\");\n                out.append(\", \");\n                out.append(mStreamMeta.getCodecShortNameInline());\n                out.append(\", \");\n                out.append(mStreamMeta.getBitrateInline());\n                out.append(\", \");\n                out.append(mStreamMeta.getSampleRateInline());\n                break;\n            case MEDIA_TRACK_TYPE_TIMEDTEXT:\n                out.append(\"TIMEDTEXT\");\n                out.append(\", \");\n                out.append(mStreamMeta.mLanguage);\n                break;\n            case MEDIA_TRACK_TYPE_SUBTITLE:\n                out.append(\"SUBTITLE\");\n                break;\n            default:\n                out.append(\"UNKNOWN\");\n                break;\n        }\n        return out.toString();\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/pragma/DebugLog.java",
    "content": "/*\n * Copyright (C) 2013 Bilibili\n * Copyright (C) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player.pragma;\n\nimport java.util.Locale;\n\n\nimport android.util.Log;\n\n@SuppressWarnings({\"SameParameterValue\", \"WeakerAccess\"})\npublic class DebugLog {\n    public static final boolean ENABLE_ERROR = Pragma.ENABLE_VERBOSE;\n    public static final boolean ENABLE_INFO = Pragma.ENABLE_VERBOSE;\n    public static final boolean ENABLE_WARN = Pragma.ENABLE_VERBOSE;\n    public static final boolean ENABLE_DEBUG = Pragma.ENABLE_VERBOSE;\n    public static final boolean ENABLE_VERBOSE = Pragma.ENABLE_VERBOSE;\n\n    public static void e(String tag, String msg) {\n        if (ENABLE_ERROR) {\n            Log.e(tag, msg);\n        }\n    }\n\n    public static void e(String tag, String msg, Throwable tr) {\n        if (ENABLE_ERROR) {\n            Log.e(tag, msg, tr);\n        }\n    }\n\n    public static void efmt(String tag, String fmt, Object... args) {\n        if (ENABLE_ERROR) {\n            String msg = String.format(Locale.US, fmt, args);\n            Log.e(tag, msg);\n        }\n    }\n\n    public static void i(String tag, String msg) {\n        if (ENABLE_INFO) {\n            Log.i(tag, msg);\n        }\n    }\n\n    public static void i(String tag, String msg, Throwable tr) {\n        if (ENABLE_INFO) {\n            Log.i(tag, msg, tr);\n        }\n    }\n\n    public static void ifmt(String tag, String fmt, Object... args) {\n        if (ENABLE_INFO) {\n            String msg = String.format(Locale.US, fmt, args);\n            Log.i(tag, msg);\n        }\n    }\n\n    public static void w(String tag, String msg) {\n        if (ENABLE_WARN) {\n            Log.w(tag, msg);\n        }\n    }\n\n    public static void w(String tag, String msg, Throwable tr) {\n        if (ENABLE_WARN) {\n            Log.w(tag, msg, tr);\n        }\n    }\n\n    public static void wfmt(String tag, String fmt, Object... args) {\n        if (ENABLE_WARN) {\n            String msg = String.format(Locale.US, fmt, args);\n            Log.w(tag, msg);\n        }\n    }\n\n    public static void d(String tag, String msg) {\n        if (ENABLE_DEBUG) {\n            Log.d(tag, msg);\n        }\n    }\n\n    public static void d(String tag, String msg, Throwable tr) {\n        if (ENABLE_DEBUG) {\n            Log.d(tag, msg, tr);\n        }\n    }\n\n    public static void dfmt(String tag, String fmt, Object... args) {\n        if (ENABLE_DEBUG) {\n            String msg = String.format(Locale.US, fmt, args);\n            Log.d(tag, msg);\n        }\n    }\n\n    public static void v(String tag, String msg) {\n        if (ENABLE_VERBOSE) {\n            Log.v(tag, msg);\n        }\n    }\n\n    public static void v(String tag, String msg, Throwable tr) {\n        if (ENABLE_VERBOSE) {\n            Log.v(tag, msg, tr);\n        }\n    }\n\n    public static void vfmt(String tag, String fmt, Object... args) {\n        if (ENABLE_VERBOSE) {\n            String msg = String.format(Locale.US, fmt, args);\n            Log.v(tag, msg);\n        }\n    }\n\n    public static void printStackTrace(Throwable e) {\n        if (ENABLE_WARN) {\n            e.printStackTrace();\n        }\n    }\n\n    public static void printCause(Throwable e) {\n        if (ENABLE_WARN) {\n            Throwable cause = e.getCause();\n            if (cause != null)\n                e = cause;\n\n            printStackTrace(e);\n        }\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/pragma/Pragma.java",
    "content": "/*\n * Copyright (C) 2013 Bilibili\n * Copyright (C) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage tv.danmaku.ijk.media.player.pragma;\n\n/*-\n * configurated by app project\n */\npublic class Pragma {\n    public static final boolean ENABLE_VERBOSE = true;\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/project.properties",
    "content": "# This file is automatically generated by Android Tools.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n#\n# This file must be checked in Version Control Systems.\n#\n# To customize properties used by the Ant build system edit\n# \"ant.properties\", and override values to adapt the script to your\n# project structure.\n#\n# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):\n#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt\n\n# Project target.\ntarget=android-22\nandroid.library=true\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-java/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"ijkplayer_dummy\"></string>\n\n</resources>"
  },
  {
    "path": "android/ijkplayer/ijkplayer-x86/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-x86/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    // http://tools.android.com/tech-docs/new-build-system/tips\n    //noinspection GroovyAssignabilityCheck\n    compileSdkVersion rootProject.ext.compileSdkVersion\n    //noinspection GroovyAssignabilityCheck\n    buildToolsVersion rootProject.ext.buildToolsVersion\n\n    defaultConfig {\n        minSdkVersion 9\n        targetSdkVersion rootProject.ext.targetSdkVersion\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n    sourceSets.main {\n        jniLibs.srcDirs 'src/main/libs'\n        jni.srcDirs = [] // This prevents the auto generation of Android.mk\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n}\n\napply from: new File(rootProject.projectDir, \"tools/gradle-on-demand.gradle\");\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-x86/gradle.properties",
    "content": "POM_NAME=ijkplayer-x86\nPOM_ARTIFACT_ID=ijkplayer-x86\nPOM_PACKAGING=aar"
  },
  {
    "path": "android/ijkplayer/ijkplayer-x86/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /opt/android/ADK/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-x86/src/androidTest/java/tv/danmaku/ijk/media/ijkplayer/ApplicationTest.java",
    "content": "package tv.danmaku.ijk.media.ijkplayer;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\"http://d.android.com/tools/testing/testing_android.html\">Testing Fundamentals</a>\n */\npublic class ApplicationTest extends ApplicationTestCase<Application> {\n    public ApplicationTest() {\n        super(Application.class);\n    }\n}"
  },
  {
    "path": "android/ijkplayer/ijkplayer-x86/src/main/.classpath",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<classpath>\n\t<classpathentry kind=\"con\" path=\"com.android.ide.eclipse.adt.ANDROID_FRAMEWORK\"/>\n\t<classpathentry exported=\"true\" kind=\"con\" path=\"com.android.ide.eclipse.adt.LIBRARIES\"/>\n\t<classpathentry exported=\"true\" kind=\"con\" path=\"com.android.ide.eclipse.adt.DEPENDENCIES\"/>\n\t<classpathentry kind=\"src\" path=\"java\"/>\n\t<classpathentry kind=\"src\" path=\"src\"/>\n\t<classpathentry kind=\"src\" path=\"gen\"/>\n\t<classpathentry kind=\"output\" path=\"bin/classes\"/>\n</classpath>\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-x86/src/main/.project",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<projectDescription>\n\t<name>ijkplayer-x86</name>\n\t<comment></comment>\n\t<projects>\n\t</projects>\n\t<buildSpec>\n\t\t<buildCommand>\n\t\t\t<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>org.eclipse.jdt.core.javabuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>com.android.ide.eclipse.adt.ApkBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t</buildSpec>\n\t<natures>\n\t\t<nature>com.android.ide.eclipse.adt.AndroidNature</nature>\n\t\t<nature>org.eclipse.jdt.core.javanature</nature>\n\t</natures>\n</projectDescription>\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-x86/src/main/.settings/org.eclipse.jdt.core.prefs",
    "content": "eclipse.preferences.version=1\norg.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6\norg.eclipse.jdt.core.compiler.compliance=1.6\norg.eclipse.jdt.core.compiler.source=1.6\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-x86/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"tv.danmaku.ijk.media.player_x86\">\n\n    <uses-sdk\n        android:minSdkVersion=\"9\" />\n\n</manifest>\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-x86/src/main/java/tv/danmaku/ijk/media/player_x86/Pragma.java",
    "content": "/*\n * Copyright (C) 2015 Bilibili\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage tv.danmaku.ijk.media.player_x86;\n\npublic class Pragma {\n\n}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-x86/src/main/jni/Application.mk",
    "content": "# Copyright (c) 2013-2014 Bilibili\n# copyright (c) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n#\n# This file is part of ijkPlayer.\n#\n# ijkPlayer is free software; you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation; either\n# version 2.1 of the License, or (at your option) any later version.\n#\n# ijkPlayer is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# Lesser General Public License for more details.\n#\n# You should have received a copy of the GNU Lesser General Public\n# License along with ijkPlayer; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n\nAPP_OPTIM := release\nAPP_PLATFORM := android-9\nAPP_ABI := x86\nNDK_TOOLCHAIN_VERSION=4.9\nAPP_PIE := false\n\nAPP_STL := stlport_static\n\nAPP_CFLAGS := -O3 -Wall -pipe \\\n    -ffast-math \\\n    -fstrict-aliasing -Werror=strict-aliasing \\\n    -Wno-psabi -Wa,--noexecstack \\\n    -DANDROID -DNDEBUG\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-x86/src/main/jni/ffmpeg/Android.mk",
    "content": "LOCAL_PATH := $(call my-dir)\n\ninclude $(CLEAR_VARS)\nLOCAL_MODULE := ijkffmpeg\nLOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/libijkffmpeg.so\ninclude $(PREBUILT_SHARED_LIBRARY)"
  },
  {
    "path": "android/ijkplayer/ijkplayer-x86/src/main/project.properties",
    "content": "# This file is automatically generated by Android Tools.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n#\n# This file must be checked in Version Control Systems.\n#\n# To customize properties used by the Ant build system edit\n# \"ant.properties\", and override values to adapt the script to your\n# project structure.\n#\n# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):\n#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt\n\n# Project target.\ntarget=android-22\nandroid.library=true\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-x86/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <string name=\"ijkplayer_dummy\" tools:ignore=\"UnusedResources\"></string>\n\n</resources>"
  },
  {
    "path": "android/ijkplayer/ijkplayer-x86_64/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-x86_64/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    // http://tools.android.com/tech-docs/new-build-system/tips\n    //noinspection GroovyAssignabilityCheck\n    compileSdkVersion rootProject.ext.compileSdkVersion\n    //noinspection GroovyAssignabilityCheck\n    buildToolsVersion rootProject.ext.buildToolsVersion\n\n    defaultConfig {\n        minSdkVersion 21\n        targetSdkVersion rootProject.ext.targetSdkVersion\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n    sourceSets.main {\n        jniLibs.srcDirs 'src/main/libs'\n        jni.srcDirs = [] // This prevents the auto generation of Android.mk\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n}\n\napply from: new File(rootProject.projectDir, \"tools/gradle-on-demand.gradle\");\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-x86_64/gradle.properties",
    "content": "POM_NAME=ijkplayer-x86_64\nPOM_ARTIFACT_ID=ijkplayer-x86_64\nPOM_PACKAGING=aar"
  },
  {
    "path": "android/ijkplayer/ijkplayer-x86_64/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /opt/android/ADK/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-x86_64/src/androidTest/java/com/example/ijkplayer_x86_64/ApplicationTest.java",
    "content": "package com.example.ijkplayer_x86_64;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\"http://d.android.com/tools/testing/testing_android.html\">Testing Fundamentals</a>\n */\npublic class ApplicationTest extends ApplicationTestCase<Application> {\n    public ApplicationTest() {\n        super(Application.class);\n    }\n}"
  },
  {
    "path": "android/ijkplayer/ijkplayer-x86_64/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"tv.danmaku.ijk.media.player_x86_64\">\n\n    <uses-sdk\n        android:minSdkVersion=\"21\" />\n\n</manifest>\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-x86_64/src/main/jni/Application.mk",
    "content": "# Copyright (c) 2013-2014 Bilibili\n# copyright (c) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n#\n# This file is part of ijkPlayer.\n#\n# ijkPlayer is free software; you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation; either\n# version 2.1 of the License, or (at your option) any later version.\n#\n# ijkPlayer is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# Lesser General Public License for more details.\n#\n# You should have received a copy of the GNU Lesser General Public\n# License along with ijkPlayer; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n\nAPP_OPTIM := release\nAPP_PLATFORM := android-21\nAPP_ABI := x86_64\nNDK_TOOLCHAIN_VERSION=4.9\nAPP_PIE := false\n\nAPP_STL := stlport_static\n\nAPP_CFLAGS := -O3 -Wall -pipe \\\n    -ffast-math \\\n    -fstrict-aliasing -Werror=strict-aliasing \\\n    -Wno-psabi -Wa,--noexecstack \\\n    -DANDROID -DNDEBUG\n"
  },
  {
    "path": "android/ijkplayer/ijkplayer-x86_64/src/main/jni/ffmpeg/Android.mk",
    "content": "LOCAL_PATH := $(call my-dir)\n\ninclude $(CLEAR_VARS)\nLOCAL_MODULE := ijkffmpeg\nLOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/libijkffmpeg.so\ninclude $(PREBUILT_SHARED_LIBRARY)"
  },
  {
    "path": "android/ijkplayer/ijkplayer-x86_64/src/main/res/values/strings.xml",
    "content": "<resources xmlns:tools=\"http://schemas.android.com/tools\">\n    <string name=\"app_name\" tools:ignore=\"UnusedResources\">ijkplayer-x86_64</string>\n</resources>\n"
  },
  {
    "path": "android/ijkplayer/settings.gradle",
    "content": "include ':ijkplayer-armv5', ':ijkplayer-x86_64'\ninclude ':ijkplayer-armv7a'\ninclude ':ijkplayer-arm64'\ninclude ':ijkplayer-x86'\n\ninclude ':ijkplayer-java'\ninclude ':ijkplayer-exo'\n\ninclude ':ijkplayer-example'\n\n"
  },
  {
    "path": "android/ijkplayer/tools/gradle-bintray-upload.gradle",
    "content": "/*\n * Copyright 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\napply plugin: 'com.github.dcendents.android-maven'\napply plugin: 'com.jfrog.bintray'\n\ngroup = GROUP\nversion = VERSION_NAME\n\nbintray {\n    user = project.hasProperty('BINTRAY_USER') ? BINTRAY_USER : System.getenv('BINTRAY_USER')\n    key = project.hasProperty('BINTRAY_APIKEY') ? BINTRAY_APIKEY : System.getenv('BINTRAY_APIKEY')\n\n    configurations = ['archives']\n\n    dryRun = false\n    publish = true\n\n    pkg {\n        repo = 'maven'\n        name = POM_NAME\n        userOrg = POM_USER_ORG\n        desc = POM_DESCRIPTION\n        websiteUrl = POM_URL\n        vcsUrl = POM_SCM_URL\n        licenses = [POM_LICENSE_NAME]\n        labels = ['FFmpeg', 'Android', 'player']\n        publicDownloadNumbers = true\n        version {\n            name = VERSION_NAME\n            gpg {\n                sign = true\n                passphrase = project.hasProperty('GPG_PASSWORD') ? GPG_PASSWORD : System.getenv('GPG_PASSWORD')\n            }\n        }\n    }\n}\n\ninstall {\n    repositories.mavenInstaller {\n        pom.project {\n            name POM_NAME\n            packaging POM_PACKAGING\n            description POM_DESCRIPTION\n            url POM_URL\n\n            licenses {\n                license {\n                    name POM_LICENSE_NAME\n                    url POM_LICENSE_URL\n                    distribution POM_LICENSE_DIST\n                }\n            }\n\n            scm {\n                url POM_SCM_URL\n                connection POM_SCM_CONNECTION\n                developerConnection POM_SCM_DEV_CONNECTION\n            }\n\n            developers {\n                developer {\n                    id POM_DEVELOPER_ID\n                    name POM_DEVELOPER_NAME\n                    email POM_DEVELOPER_EMAIL\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/tools/gradle-mvn-push.gradle",
    "content": "/*\n * Copyright 2013 Chris Banes\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\napply plugin: 'maven'\napply plugin: 'signing'\n\ndef isReleaseBuild() {\n    return VERSION_NAME.contains(\"SNAPSHOT\") == false\n}\n\ndef getReleaseRepositoryUrl() {\n    return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL\n            : \"https://oss.sonatype.org/service/local/staging/deploy/maven2/\"\n}\n\ndef getSnapshotRepositoryUrl() {\n    return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL\n            : \"https://oss.sonatype.org/content/repositories/snapshots/\"\n}\n\ndef getRepositoryUsername() {\n    return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : \"\"\n}\n\ndef getRepositoryPassword() {\n    return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : \"\"\n}\n\nafterEvaluate { project ->\n    uploadArchives {\n        repositories {\n            mavenDeployer {\n                beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }\n\n                pom.groupId = GROUP\n                pom.artifactId = POM_ARTIFACT_ID\n                pom.version = VERSION_NAME\n\n                repository(url: getReleaseRepositoryUrl()) {\n                    authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())\n                }\n                snapshotRepository(url: getSnapshotRepositoryUrl()) {\n                    authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())\n                }\n\n                pom.project {\n                    name POM_NAME\n                    packaging POM_PACKAGING\n                    description POM_DESCRIPTION\n                    url POM_URL\n\n                    licenses {\n                        license {\n                            name POM_LICENSE_NAME\n                            url POM_LICENSE_URL\n                            distribution POM_LICENSE_DIST\n                        }\n                    }\n\n                    scm {\n                        url POM_SCM_URL\n                        connection POM_SCM_CONNECTION\n                        developerConnection POM_SCM_DEV_CONNECTION\n                    }\n\n                    developers {\n                        developer {\n                            id POM_DEVELOPER_ID\n                            name POM_DEVELOPER_NAME\n                            email POM_DEVELOPER_EMAIL\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    android.libraryVariants.all { variant ->\n        if(variant.buildType.name.equals(\"release\")) {\n            def jarTask = project.tasks.create(name: \"jar${variant.name.capitalize()}\", type: Jar) {\n                from variant.javaCompile.destinationDir\n                exclude \"**/R.class\"\n                exclude \"**/R\\$**.class\"\n                exclude \"**/BuildConfig.class\"\n            }\n            jarTask.dependsOn variant.javaCompile\n        }\n    }\n\n    signing {\n        required { isReleaseBuild() && gradle.taskGraph.hasTask(\"uploadArchives\") }\n        sign configurations.archives\n    }\n\n    task androidJavadocs(type: Javadoc) {\n        failOnError false\n        source = android.sourceSets.main.java.srcDirs\n        classpath += project.files(android.getBootClasspath().join(File.pathSeparator))\n    }\n\n    task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {\n        classifier = 'javadoc'\n        from androidJavadocs.destinationDir\n    }\n\n    task androidSourcesJar(type: Jar) {\n        classifier = 'sources'\n        from android.sourceSets.main.java.sourceFiles\n    }\n\n    artifacts {\n        archives androidSourcesJar\n        archives androidJavadocsJar\n        archives jarRelease\n    }\n}\n"
  },
  {
    "path": "android/ijkplayer/tools/gradle-on-demand.gradle",
    "content": "/*\n * Copyright 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\ngradle.startParameter.taskNames.each { task ->\n    def taskName = task.split(\":\").last()\n    switch (taskName) {\n        case \"uploadArchives\":\n            apply from: new File(rootProject.projectDir, 'tools/gradle-mvn-push.gradle')\n            break;\n        case \"bintrayUpload\":\n            apply from: new File(rootProject.projectDir, 'tools/gradle-bintray-upload.gradle')\n            break;\n        default:\n            // do nothing\n            break;\n    }\n}\n"
  },
  {
    "path": "android/patch-debugging-with-lldb.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2014 Chen Hui <calmer91@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\npatch_enable () {\n    PARAM_TARGET=$1\n    case \"$PARAM_TARGET\" in\n        armv5|armv7a|arm64|x86|x86_64)\n            git apply -- android/patches/0001-gitignore-ignore-.externalNativeBuild.patch\n            echo \"git apply ==> patches/0001-gitignore-ignore-.externalNativeBuild.patch\"\n            git apply -- android/patches/0002-gradle-upgrade-build-tool-to-2.2.0-beta2.patch\n            echo \"git apply ==> patches/0002-gradle-upgrade-build-tool-to-2.2.0-beta2.patch\"\n            git apply -- android/patches/0003-$PARAM_TARGET-enable-debugging-with-LLDB.patch\n            echo \"git apply ==> patches/0003-$PARAM_TARGET-enable-debugging-with-LLDB.patch\"\n            git apply -- android/patches/0004-$PARAM_TARGET-link-prebuilt-staic-libraries-of-ffmepg.patch\n            echo \"git apply ==> patches/0004-$PARAM_TARGET-link-prebuilt-staic-libraries-of-ffmepg.patch\"\n        ;;\n    esac\n}\n\npatch_disable () {\n    PARAM_TARGET=$1\n    case \"$PARAM_TARGET\" in\n        armv5|armv7a|arm64|x86|x86_64)\n            git apply -R android/patches/0004-$PARAM_TARGET-link-prebuilt-staic-libraries-of-ffmepg.patch\n            echo \"git apply reverse ==> patches/0004-$PARAM_TARGET-link-prebuilt-staic-libraries-of-ffmepg.patch\"\n\n            git checkout android/ijkplayer/ijkplayer-$PARAM_TARGET/src/main/jni/Android.mk\n            git checkout android/ijkplayer/ijkplayer-example/build.gradle\n            git checkout android/ijkplayer/ijkplayer-$PARAM_TARGET/build.gradle\n            git checkout android/ijkplayer/settings.gradle\n#            git apply -R android/patches/0003-$PARAM_TARGET-enable-debugging-with-LLDB.patch\n            echo \"git apply reverse ==> patches/0003-$PARAM_TARGET-enable-debugging-with-LLDB.patch\"\n            git apply -R android/patches/0002-gradle-upgrade-build-tool-to-2.2.0-beta2.patch\n            echo \"git apply reverse ==> patches/0002-gradle-upgrade-build-tool-to-2.2.0-beta2.patch\"\n            git apply -R android/patches/0001-gitignore-ignore-.externalNativeBuild.patch\n            echo \"git apply reverse ==> patches/0001-gitignore-ignore-.externalNativeBuild.patch\"\n        ;;\n    esac\n}\n\ncase \"$1\" in\n    armv5|armv7a|arm64|x86|x86_64)\n        # patch_enable $1\n        echo \"patch apply ==> $1\"\n        patch_enable $1\n    ;;\n    reverse)\n        case \"$2\" in\n            armv5|armv7a|arm64|x86|x86_64)\n                echo \"patch reverse ==> $2\"\n                patch_disable $2\n            ;;\n            *)\n            echo \"Usage:\"\n            echo \"  patch-debugging-with-lldb.sh armv5|armv7a|arm64|x86|x86_64\"\n            echo \"  patch-debugging-with-lldb.sh reverse armv5|armv7a|arm64|x86|x86_64\"        \n            ;;\n        esac\n    ;;\n    *)\n        echo \"Usage:\"\n        echo \"  patch-debugging-with-lldb.sh armv5|armv7a|arm64|x86|x86_64\"\n        echo \"  patch-debugging-with-lldb.sh reverse armv5|armv7a|arm64|x86|x86_64\"\n    ;;\nesac"
  },
  {
    "path": "android/patches/0001-gitignore-ignore-.externalNativeBuild.patch",
    "content": "From dc4847b1e8ff5d35576f840db59aec0a3d3fc72b Mon Sep 17 00:00:00 2001\nFrom: ctiao <calmer91@gmail.com>\nDate: Mon, 29 Aug 2016 14:48:08 +0800\nSubject: [PATCH 1/2] gitignore: ignore \".externalNativeBuild\"\n\n---\n android/ijkplayer/.gitignore | 1 +\n 1 file changed, 1 insertion(+)\n\ndiff --git a/android/ijkplayer/.gitignore b/android/ijkplayer/.gitignore\nindex eac8754..2a3badc 100644\n--- a/android/ijkplayer/.gitignore\n+++ b/android/ijkplayer/.gitignore\n@@ -6,3 +6,4 @@\n /build\n /captures\n android-ndk-prof\n+.externalNativeBuild\n\\ No newline at end of file\n-- \n2.7.4 (Apple Git-66)\n\n"
  },
  {
    "path": "android/patches/0002-gradle-upgrade-build-tool-to-2.2.0-beta2.patch",
    "content": "From 5d70fa0496f9ebfbcfa3786d85c74c690d66781e Mon Sep 17 00:00:00 2001\nFrom: ctiao <calmer91@gmail.com>\nDate: Mon, 29 Aug 2016 14:50:34 +0800\nSubject: [PATCH 2/2] gradle: upgrade build-tool to 2.2.0-rc1\n\n---\n android/ijkplayer/build.gradle | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/android/ijkplayer/build.gradle b/android/ijkplayer/build.gradle\nindex 0de03ec..6132c1d 100644\n--- a/android/ijkplayer/build.gradle\n+++ b/android/ijkplayer/build.gradle\n@@ -5,7 +5,7 @@ buildscript {\n         jcenter()\n     }\n     dependencies {\n-        classpath 'com.android.tools.build:gradle:2.1.3'\n+        classpath 'com.android.tools.build:gradle:2.2.0-rc1'\n \n         classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1'\n         classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7'\n-- \n2.7.4 (Apple Git-66)\n\n"
  },
  {
    "path": "android/patches/0003-arm64-enable-debugging-with-LLDB.patch",
    "content": "From 8f72e4cdcc3c3ef2d5290be4a755943b972d7239 Mon Sep 17 00:00:00 2001\nFrom: ctiao <calmer91@gmail.com>\nDate: Mon, 29 Aug 2016 17:06:00 +0800\nSubject: [PATCH] arm64: enable debugging with LLDB\n\n---\n android/ijkplayer/ijkplayer-arm64/build.gradle     | 20 ++++++++++++---\n .../ijkplayer-arm64/src/main/jni/Android.mk        | 29 +++++++++++++++++++++-\n android/ijkplayer/ijkplayer-example/build.gradle   | 16 ++++++------\n android/ijkplayer/settings.gradle                  |  6 ++---\n 4 files changed, 56 insertions(+), 15 deletions(-)\n mode change 120000 => 100644 android/ijkplayer/ijkplayer-arm64/src/main/jni/Android.mk\n\ndiff --git a/android/ijkplayer/ijkplayer-arm64/build.gradle b/android/ijkplayer/ijkplayer-arm64/build.gradle\nindex a8cbe0c..ccd04e0 100644\n--- a/android/ijkplayer/ijkplayer-arm64/build.gradle\n+++ b/android/ijkplayer/ijkplayer-arm64/build.gradle\n@@ -10,16 +10,30 @@ android {\n     defaultConfig {\n         minSdkVersion 21\n         targetSdkVersion rootProject.ext.targetSdkVersion\n+        externalNativeBuild {\n+            ndkBuild {\n+                arguments \"NDK_APPLICATION_MK:=src/main/jni/Application.mk\"\n+                abiFilters \"arm64-v8a\"\n+            }\n+        }\n     }\n     buildTypes {\n         release {\n             minifyEnabled false\n             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n         }\n+        debug {\n+            debuggable true\n+            jniDebuggable true\n+            ndk {\n+                debuggable true\n+            }\n+        }\n     }\n-    sourceSets.main {\n-        jniLibs.srcDirs 'src/main/libs'\n-        jni.srcDirs = [] // This prevents the auto generation of Android.mk\n+    externalNativeBuild {\n+        ndkBuild {\n+            path 'src/main/jni/Android.mk'\n+        }\n     }\n }\n \ndiff --git a/android/ijkplayer/ijkplayer-arm64/src/main/jni/Android.mk b/android/ijkplayer/ijkplayer-arm64/src/main/jni/Android.mk\ndeleted file mode 120000\nindex fb30867..0000000\n--- a/android/ijkplayer/ijkplayer-arm64/src/main/jni/Android.mk\n+++ /dev/null\n@@ -1 +0,0 @@\n-../../../../ijkplayer-armv7a/src/main/jni/Android.mk\n\\ No newline at end of file\ndiff --git a/android/ijkplayer/ijkplayer-arm64/src/main/jni/Android.mk b/android/ijkplayer/ijkplayer-arm64/src/main/jni/Android.mk\nnew file mode 100644\nindex 0000000..6b53c1f\n--- /dev/null\n+++ b/android/ijkplayer/ijkplayer-arm64/src/main/jni/Android.mk\n@@ -0,0 +1,28 @@\n+# copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n+#\n+# This file is part of ijkPlayer.\n+#\n+# ijkPlayer is free software; you can redistribute it and/or\n+# modify it under the terms of the GNU Lesser General Public\n+# License as published by the Free Software Foundation; either\n+# version 2.1 of the License, or (at your option) any later version.\n+#\n+# ijkPlayer is distributed in the hope that it will be useful,\n+# but WITHOUT ANY WARRANTY; without even the implied warranty of\n+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+# Lesser General Public License for more details.\n+#\n+# You should have received a copy of the GNU Lesser General Public\n+# License along with ijkPlayer; if not, write to the Free Software\n+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n+\n+LOCAL_PATH := $(call my-dir)\n+\n+MY_APP_JNI_ROOT := $(realpath $(LOCAL_PATH))\n+MY_APP_PRJ_ROOT := $(realpath $(MY_APP_JNI_ROOT)/..)\n+MY_APP_ANDROID_ROOT := $(realpath $(MY_APP_PRJ_ROOT)/../../../..)\n+\n+MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-arm64/output)\n+MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include)\n+\n+include $(call all-subdir-makefiles)\ndiff --git a/android/ijkplayer/ijkplayer-example/build.gradle b/android/ijkplayer/ijkplayer-example/build.gradle\nindex 9afe650..77df829 100644\n--- a/android/ijkplayer/ijkplayer-example/build.gradle\n+++ b/android/ijkplayer/ijkplayer-example/build.gradle\n@@ -44,15 +44,15 @@ dependencies {\n     compile project(':ijkplayer-java')\n     compile project(':ijkplayer-exo')\n \n-    all32Compile project(':ijkplayer-armv5')\n-    all32Compile project(':ijkplayer-armv7a')\n-    all32Compile project(':ijkplayer-x86')\n-\n-    all64Compile project(':ijkplayer-armv5')\n-    all64Compile project(':ijkplayer-armv7a')\n+//    all32Compile project(':ijkplayer-armv5')\n+//    all32Compile project(':ijkplayer-armv7a')\n+//    all32Compile project(':ijkplayer-x86')\n+//\n+//    all64Compile project(':ijkplayer-armv5')\n+//    all64Compile project(':ijkplayer-armv7a')\n     all64Compile project(':ijkplayer-arm64')\n-    all64Compile project(':ijkplayer-x86')\n-    all64Compile project(':ijkplayer-x86_64')\n+//    all64Compile project(':ijkplayer-x86')\n+//    all64Compile project(':ijkplayer-x86_64')\n \n     // armv5Compile project(':player-armv5')\n     // armv7aCompile project(':player-armv7a')\ndiff --git a/android/ijkplayer/settings.gradle b/android/ijkplayer/settings.gradle\nindex 758234a..c9e72d9 100644\n--- a/android/ijkplayer/settings.gradle\n+++ b/android/ijkplayer/settings.gradle\n@@ -1,7 +1,7 @@\n-include ':ijkplayer-armv5', ':ijkplayer-x86_64'\n-include ':ijkplayer-armv7a'\n+//include ':ijkplayer-armv5', ':ijkplayer-x86_64'\n+//include ':ijkplayer-armv7a'\n include ':ijkplayer-arm64'\n-include ':ijkplayer-x86'\n+//include ':ijkplayer-x86'\n \n include ':ijkplayer-java'\n include ':ijkplayer-exo'\n-- \n2.7.4 (Apple Git-66)\n\n"
  },
  {
    "path": "android/patches/0003-armv5-enable-debugging-with-LLDB.patch",
    "content": "From e7a63003b2f3d15f795128b95085da57dd838945 Mon Sep 17 00:00:00 2001\nFrom: ctiao <calmer91@gmail.com>\nDate: Mon, 29 Aug 2016 16:23:52 +0800\nSubject: [PATCH] armv5: enable debugging with LLDB\n\n---\n android/ijkplayer/ijkplayer-armv5/build.gradle     | 20 ++++++++++++---\n .../ijkplayer-armv5/src/main/jni/Android.mk        | 29 +++++++++++++++++++++-\n android/ijkplayer/ijkplayer-example/build.gradle   | 14 +++++------\n android/ijkplayer/settings.gradle                  |  8 +++---\n 4 files changed, 56 insertions(+), 15 deletions(-)\n mode change 120000 => 100644 android/ijkplayer/ijkplayer-armv5/src/main/jni/Android.mk\n\ndiff --git a/android/ijkplayer/ijkplayer-armv5/build.gradle b/android/ijkplayer/ijkplayer-armv5/build.gradle\nindex b3b7b3a..d05f33e 100644\n--- a/android/ijkplayer/ijkplayer-armv5/build.gradle\n+++ b/android/ijkplayer/ijkplayer-armv5/build.gradle\n@@ -10,16 +10,30 @@ android {\n     defaultConfig {\n         minSdkVersion 9\n         targetSdkVersion rootProject.ext.targetSdkVersion\n+        externalNativeBuild {\n+            ndkBuild {\n+                arguments \"NDK_APPLICATION_MK:=src/main/jni/Application.mk\"\n+                abiFilters \"armeabi\"\n+            }\n+        }\n     }\n     buildTypes {\n         release {\n             minifyEnabled false\n             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n         }\n+        debug {\n+            debuggable true\n+            jniDebuggable true\n+            ndk {\n+                debuggable true\n+            }\n+        }\n     }\n-    sourceSets.main {\n-        jniLibs.srcDirs 'src/main/libs'\n-        jni.srcDirs = [] // This prevents the auto generation of Android.mk\n+    externalNativeBuild {\n+        ndkBuild {\n+            path 'src/main/jni/Android.mk'\n+        }\n     }\n }\n \ndiff --git a/android/ijkplayer/ijkplayer-armv5/src/main/jni/Android.mk b/android/ijkplayer/ijkplayer-armv5/src/main/jni/Android.mk\ndeleted file mode 120000\nindex fb30867..0000000\n--- a/android/ijkplayer/ijkplayer-armv5/src/main/jni/Android.mk\n+++ /dev/null\n@@ -1 +0,0 @@\n-../../../../ijkplayer-armv7a/src/main/jni/Android.mk\n\\ No newline at end of file\ndiff --git a/android/ijkplayer/ijkplayer-armv5/src/main/jni/Android.mk b/android/ijkplayer/ijkplayer-armv5/src/main/jni/Android.mk\nnew file mode 100644\nindex 0000000..47d400e\n--- /dev/null\n+++ b/android/ijkplayer/ijkplayer-armv5/src/main/jni/Android.mk\n@@ -0,0 +1,28 @@\n+# copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n+#\n+# This file is part of ijkPlayer.\n+#\n+# ijkPlayer is free software; you can redistribute it and/or\n+# modify it under the terms of the GNU Lesser General Public\n+# License as published by the Free Software Foundation; either\n+# version 2.1 of the License, or (at your option) any later version.\n+#\n+# ijkPlayer is distributed in the hope that it will be useful,\n+# but WITHOUT ANY WARRANTY; without even the implied warranty of\n+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+# Lesser General Public License for more details.\n+#\n+# You should have received a copy of the GNU Lesser General Public\n+# License along with ijkPlayer; if not, write to the Free Software\n+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n+\n+LOCAL_PATH := $(call my-dir)\n+\n+MY_APP_JNI_ROOT := $(realpath $(LOCAL_PATH))\n+MY_APP_PRJ_ROOT := $(realpath $(MY_APP_JNI_ROOT)/..)\n+MY_APP_ANDROID_ROOT := $(realpath $(MY_APP_PRJ_ROOT)/../../../..)\n+\n+MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-armv5/output)\n+MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include)\n+\n+include $(call all-subdir-makefiles)\ndiff --git a/android/ijkplayer/ijkplayer-example/build.gradle b/android/ijkplayer/ijkplayer-example/build.gradle\nindex 9afe650..3c5c819 100644\n--- a/android/ijkplayer/ijkplayer-example/build.gradle\n+++ b/android/ijkplayer/ijkplayer-example/build.gradle\n@@ -45,14 +45,14 @@ dependencies {\n     compile project(':ijkplayer-exo')\n \n     all32Compile project(':ijkplayer-armv5')\n-    all32Compile project(':ijkplayer-armv7a')\n-    all32Compile project(':ijkplayer-x86')\n-\n+//    all32Compile project(':ijkplayer-armv7a')\n+//    all32Compile project(':ijkplayer-x86')\n+//\n     all64Compile project(':ijkplayer-armv5')\n-    all64Compile project(':ijkplayer-armv7a')\n-    all64Compile project(':ijkplayer-arm64')\n-    all64Compile project(':ijkplayer-x86')\n-    all64Compile project(':ijkplayer-x86_64')\n+//    all64Compile project(':ijkplayer-armv7a')\n+//    all64Compile project(':ijkplayer-arm64')\n+//    all64Compile project(':ijkplayer-x86')\n+//    all64Compile project(':ijkplayer-x86_64')\n \n     // armv5Compile project(':player-armv5')\n     // armv7aCompile project(':player-armv7a')\ndiff --git a/android/ijkplayer/settings.gradle b/android/ijkplayer/settings.gradle\nindex 758234a..b0873e0 100644\n--- a/android/ijkplayer/settings.gradle\n+++ b/android/ijkplayer/settings.gradle\n@@ -1,7 +1,7 @@\n-include ':ijkplayer-armv5', ':ijkplayer-x86_64'\n-include ':ijkplayer-armv7a'\n-include ':ijkplayer-arm64'\n-include ':ijkplayer-x86'\n+include ':ijkplayer-armv5'//, ':ijkplayer-x86_64'\n+//include ':ijkplayer-armv7a'\n+//include ':ijkplayer-arm64'\n+//include ':ijkplayer-x86'\n \n include ':ijkplayer-java'\n include ':ijkplayer-exo'\n-- \n2.7.4 (Apple Git-66)\n\n"
  },
  {
    "path": "android/patches/0003-armv7a-enable-debugging-with-LLDB.patch",
    "content": "From 69f62140cc4062f433cbd093301a1fc84ff61305 Mon Sep 17 00:00:00 2001\nFrom: ctiao <calmer91@gmail.com>\nDate: Mon, 29 Aug 2016 16:15:00 +0800\nSubject: [PATCH] armv7a: enable debugging with LLDB\n\n---\n android/ijkplayer/ijkplayer-armv7a/build.gradle    | 23 +++++++++++++++++++---\n .../ijkplayer-armv7a/src/main/jni/Android.mk       | 18 -----------------\n android/ijkplayer/ijkplayer-example/build.gradle   | 14 ++++++-------\n android/ijkplayer/settings.gradle                  |  6 +++---\n 4 files changed, 30 insertions(+), 31 deletions(-)\n\ndiff --git a/android/ijkplayer/ijkplayer-armv7a/build.gradle b/android/ijkplayer/ijkplayer-armv7a/build.gradle\nindex b3b7b3a..9cc99b5 100644\n--- a/android/ijkplayer/ijkplayer-armv7a/build.gradle\n+++ b/android/ijkplayer/ijkplayer-armv7a/build.gradle\n@@ -10,16 +10,33 @@ android {\n     defaultConfig {\n         minSdkVersion 9\n         targetSdkVersion rootProject.ext.targetSdkVersion\n+        externalNativeBuild {\n+            ndkBuild {\n+                arguments \"NDK_APPLICATION_MK:=src/main/jni/Application.mk\"//,\"APP_ABI=armeabi-v7a\",\"NDK_ALL_ABIS=armeabi-v7a\"//,\"NDK_LIBS_OUT:=src/main/libs\"\n+//                cFlags \"-DTEST_C_FLAG1\", \"-DTEST_C_FLAG2\"  // output dir -> 'src/main/libs'\n+//                cppFlags \"-DTEST_CPP_FLAG2\", \"-DTEST_CPP_FLAG2\"\n+                abiFilters \"armeabi-v7a\"\n+            }\n+        }\n     }\n     buildTypes {\n         release {\n             minifyEnabled false\n             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n         }\n+        debug {\n+            debuggable true\n+            jniDebuggable true\n+            ndk {\n+                debuggable true\n+            }\n+        }\n     }\n-    sourceSets.main {\n-        jniLibs.srcDirs 'src/main/libs'\n-        jni.srcDirs = [] // This prevents the auto generation of Android.mk\n+\n+    externalNativeBuild {\n+        ndkBuild {\n+            path 'src/main/jni/Android.mk'\n+        }\n     }\n }\n \ndiff --git a/android/ijkplayer/ijkplayer-armv7a/src/main/jni/Android.mk b/android/ijkplayer/ijkplayer-armv7a/src/main/jni/Android.mk\nindex ba2db29..a126226 100644\n--- a/android/ijkplayer/ijkplayer-armv7a/src/main/jni/Android.mk\n+++ b/android/ijkplayer/ijkplayer-armv7a/src/main/jni/Android.mk\n@@ -22,25 +22,7 @@ MY_APP_JNI_ROOT := $(realpath $(LOCAL_PATH))\n MY_APP_PRJ_ROOT := $(realpath $(MY_APP_JNI_ROOT)/..)\n MY_APP_ANDROID_ROOT := $(realpath $(MY_APP_PRJ_ROOT)/../../../..)\n \n-ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)\n MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-armv7a/output)\n MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include)\n-endif\n-ifeq ($(TARGET_ARCH_ABI),armeabi)\n-MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-armv5/output)\n-MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include)\n-endif\n-ifeq ($(TARGET_ARCH_ABI),arm64-v8a)\n-MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-arm64/output)\n-MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include)\n-endif\n-ifeq ($(TARGET_ARCH_ABI),x86)\n-MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-x86/output)\n-MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include)\n-endif\n-ifeq ($(TARGET_ARCH_ABI),x86_64)\n-MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-x86_64/output)\n-MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include)\n-endif\n \n include $(call all-subdir-makefiles)\ndiff --git a/android/ijkplayer/ijkplayer-example/build.gradle b/android/ijkplayer/ijkplayer-example/build.gradle\nindex 9afe650..3d6df0f 100644\n--- a/android/ijkplayer/ijkplayer-example/build.gradle\n+++ b/android/ijkplayer/ijkplayer-example/build.gradle\n@@ -44,15 +44,15 @@ dependencies {\n     compile project(':ijkplayer-java')\n     compile project(':ijkplayer-exo')\n \n-    all32Compile project(':ijkplayer-armv5')\n+//    all32Compile project(':ijkplayer-armv5')\n     all32Compile project(':ijkplayer-armv7a')\n-    all32Compile project(':ijkplayer-x86')\n-\n-    all64Compile project(':ijkplayer-armv5')\n+//    all32Compile project(':ijkplayer-x86')\n+//\n+//    all64Compile project(':ijkplayer-armv5')\n     all64Compile project(':ijkplayer-armv7a')\n-    all64Compile project(':ijkplayer-arm64')\n-    all64Compile project(':ijkplayer-x86')\n-    all64Compile project(':ijkplayer-x86_64')\n+//    all64Compile project(':ijkplayer-arm64')\n+//    all64Compile project(':ijkplayer-x86')\n+//    all64Compile project(':ijkplayer-x86_64')\n \n     // armv5Compile project(':player-armv5')\n     // armv7aCompile project(':player-armv7a')\ndiff --git a/android/ijkplayer/settings.gradle b/android/ijkplayer/settings.gradle\nindex 758234a..b51e5d3 100644\n--- a/android/ijkplayer/settings.gradle\n+++ b/android/ijkplayer/settings.gradle\n@@ -1,7 +1,7 @@\n-include ':ijkplayer-armv5', ':ijkplayer-x86_64'\n+//include ':ijkplayer-armv5', ':ijkplayer-x86_64'\n include ':ijkplayer-armv7a'\n-include ':ijkplayer-arm64'\n-include ':ijkplayer-x86'\n+//include ':ijkplayer-arm64'\n+//include ':ijkplayer-x86'\n \n include ':ijkplayer-java'\n include ':ijkplayer-exo'\n-- \n2.7.4 (Apple Git-66)\n\n"
  },
  {
    "path": "android/patches/0003-x86-enable-debugging-with-LLDB.patch",
    "content": "From 9d779640e6e71181e9432d21eec11e79d53451df Mon Sep 17 00:00:00 2001\nFrom: ctiao <calmer91@gmail.com>\nDate: Mon, 29 Aug 2016 17:36:42 +0800\nSubject: [PATCH] x86: enable debugging with LLDB\n\n---\n android/ijkplayer/ijkplayer-example/build.gradle   | 14 +++++------\n android/ijkplayer/ijkplayer-x86/build.gradle       | 20 ++++++++++++---\n .../ijkplayer-x86/src/main/jni/Android.mk          | 29 +++++++++++++++++++++-\n android/ijkplayer/settings.gradle                  |  6 ++---\n 4 files changed, 55 insertions(+), 14 deletions(-)\n mode change 120000 => 100644 android/ijkplayer/ijkplayer-x86/src/main/jni/Android.mk\n\ndiff --git a/android/ijkplayer/ijkplayer-example/build.gradle b/android/ijkplayer/ijkplayer-example/build.gradle\nindex 9afe650..4f428b3 100644\n--- a/android/ijkplayer/ijkplayer-example/build.gradle\n+++ b/android/ijkplayer/ijkplayer-example/build.gradle\n@@ -44,15 +44,15 @@ dependencies {\n     compile project(':ijkplayer-java')\n     compile project(':ijkplayer-exo')\n \n-    all32Compile project(':ijkplayer-armv5')\n-    all32Compile project(':ijkplayer-armv7a')\n+//    all32Compile project(':ijkplayer-armv5')\n+//    all32Compile project(':ijkplayer-armv7a')\n     all32Compile project(':ijkplayer-x86')\n-\n-    all64Compile project(':ijkplayer-armv5')\n-    all64Compile project(':ijkplayer-armv7a')\n-    all64Compile project(':ijkplayer-arm64')\n+//\n+//    all64Compile project(':ijkplayer-armv5')\n+//    all64Compile project(':ijkplayer-armv7a')\n+//    all64Compile project(':ijkplayer-arm64')\n     all64Compile project(':ijkplayer-x86')\n-    all64Compile project(':ijkplayer-x86_64')\n+//    all64Compile project(':ijkplayer-x86_64')\n \n     // armv5Compile project(':player-armv5')\n     // armv7aCompile project(':player-armv7a')\ndiff --git a/android/ijkplayer/ijkplayer-x86/build.gradle b/android/ijkplayer/ijkplayer-x86/build.gradle\nindex b3b7b3a..75fa48a 100644\n--- a/android/ijkplayer/ijkplayer-x86/build.gradle\n+++ b/android/ijkplayer/ijkplayer-x86/build.gradle\n@@ -10,16 +10,30 @@ android {\n     defaultConfig {\n         minSdkVersion 9\n         targetSdkVersion rootProject.ext.targetSdkVersion\n+        externalNativeBuild {\n+            ndkBuild {\n+                arguments \"NDK_APPLICATION_MK:=src/main/jni/Application.mk\"\n+                abiFilters \"x86\"\n+            }\n+        }\n     }\n     buildTypes {\n         release {\n             minifyEnabled false\n             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n         }\n+        debug {\n+            debuggable true\n+            jniDebuggable true\n+            ndk {\n+                debuggable true\n+            }\n+        }\n     }\n-    sourceSets.main {\n-        jniLibs.srcDirs 'src/main/libs'\n-        jni.srcDirs = [] // This prevents the auto generation of Android.mk\n+    externalNativeBuild {\n+        ndkBuild {\n+            path 'src/main/jni/Android.mk'\n+        }\n     }\n }\n \ndiff --git a/android/ijkplayer/ijkplayer-x86/src/main/jni/Android.mk b/android/ijkplayer/ijkplayer-x86/src/main/jni/Android.mk\ndeleted file mode 120000\nindex fb30867..0000000\n--- a/android/ijkplayer/ijkplayer-x86/src/main/jni/Android.mk\n+++ /dev/null\n@@ -1 +0,0 @@\n-../../../../ijkplayer-armv7a/src/main/jni/Android.mk\n\\ No newline at end of file\ndiff --git a/android/ijkplayer/ijkplayer-x86/src/main/jni/Android.mk b/android/ijkplayer/ijkplayer-x86/src/main/jni/Android.mk\nnew file mode 100644\nindex 0000000..a126226\n--- /dev/null\n+++ b/android/ijkplayer/ijkplayer-x86/src/main/jni/Android.mk\n@@ -0,0 +1,28 @@\n+# copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n+#\n+# This file is part of ijkPlayer.\n+#\n+# ijkPlayer is free software; you can redistribute it and/or\n+# modify it under the terms of the GNU Lesser General Public\n+# License as published by the Free Software Foundation; either\n+# version 2.1 of the License, or (at your option) any later version.\n+#\n+# ijkPlayer is distributed in the hope that it will be useful,\n+# but WITHOUT ANY WARRANTY; without even the implied warranty of\n+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+# Lesser General Public License for more details.\n+#\n+# You should have received a copy of the GNU Lesser General Public\n+# License along with ijkPlayer; if not, write to the Free Software\n+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n+\n+LOCAL_PATH := $(call my-dir)\n+\n+MY_APP_JNI_ROOT := $(realpath $(LOCAL_PATH))\n+MY_APP_PRJ_ROOT := $(realpath $(MY_APP_JNI_ROOT)/..)\n+MY_APP_ANDROID_ROOT := $(realpath $(MY_APP_PRJ_ROOT)/../../../..)\n+\n+MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-armv7a/output)\n+MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include)\n+\n+include $(call all-subdir-makefiles)\ndiff --git a/android/ijkplayer/settings.gradle b/android/ijkplayer/settings.gradle\nindex 758234a..a3c9164 100644\n--- a/android/ijkplayer/settings.gradle\n+++ b/android/ijkplayer/settings.gradle\n@@ -1,6 +1,6 @@\n-include ':ijkplayer-armv5', ':ijkplayer-x86_64'\n-include ':ijkplayer-armv7a'\n-include ':ijkplayer-arm64'\n+//include ':ijkplayer-armv5', ':ijkplayer-x86_64'\n+//include ':ijkplayer-armv7a'\n+//include ':ijkplayer-arm64'\n include ':ijkplayer-x86'\n \n include ':ijkplayer-java'\n-- \n2.7.4 (Apple Git-66)\n\n"
  },
  {
    "path": "android/patches/0003-x86_64-enable-debugging-with-LLDB.patch",
    "content": "From 7797e3b03276d391746e47e0e81eedfe3ddfec66 Mon Sep 17 00:00:00 2001\nFrom: ctiao <calmer91@gmail.com>\nDate: Mon, 29 Aug 2016 17:01:10 +0800\nSubject: [PATCH] x86_64: enable debugging with LLDB\n\n---\n android/ijkplayer/ijkplayer-example/build.gradle   | 16 ++++++------\n android/ijkplayer/ijkplayer-x86_64/build.gradle    | 20 ++++++++++++---\n .../ijkplayer-x86_64/src/main/jni/Android.mk       | 29 +++++++++++++++++++++-\n android/ijkplayer/settings.gradle                  |  8 +++---\n 4 files changed, 57 insertions(+), 16 deletions(-)\n mode change 120000 => 100644 android/ijkplayer/ijkplayer-x86_64/src/main/jni/Android.mk\n\ndiff --git a/android/ijkplayer/ijkplayer-example/build.gradle b/android/ijkplayer/ijkplayer-example/build.gradle\nindex 9afe650..9f169ad 100644\n--- a/android/ijkplayer/ijkplayer-example/build.gradle\n+++ b/android/ijkplayer/ijkplayer-example/build.gradle\n@@ -44,14 +44,14 @@ dependencies {\n     compile project(':ijkplayer-java')\n     compile project(':ijkplayer-exo')\n \n-    all32Compile project(':ijkplayer-armv5')\n-    all32Compile project(':ijkplayer-armv7a')\n-    all32Compile project(':ijkplayer-x86')\n-\n-    all64Compile project(':ijkplayer-armv5')\n-    all64Compile project(':ijkplayer-armv7a')\n-    all64Compile project(':ijkplayer-arm64')\n-    all64Compile project(':ijkplayer-x86')\n+//    all32Compile project(':ijkplayer-armv5')\n+//    all32Compile project(':ijkplayer-armv7a')\n+//    all32Compile project(':ijkplayer-x86')\n+//\n+//    all64Compile project(':ijkplayer-armv5')\n+//    all64Compile project(':ijkplayer-armv7a')\n+//    all64Compile project(':ijkplayer-arm64')\n+//    all64Compile project(':ijkplayer-x86')\n     all64Compile project(':ijkplayer-x86_64')\n \n     // armv5Compile project(':player-armv5')\ndiff --git a/android/ijkplayer/ijkplayer-x86_64/build.gradle b/android/ijkplayer/ijkplayer-x86_64/build.gradle\nindex a8cbe0c..b4a6673 100644\n--- a/android/ijkplayer/ijkplayer-x86_64/build.gradle\n+++ b/android/ijkplayer/ijkplayer-x86_64/build.gradle\n@@ -10,16 +10,30 @@ android {\n     defaultConfig {\n         minSdkVersion 21\n         targetSdkVersion rootProject.ext.targetSdkVersion\n+        externalNativeBuild {\n+            ndkBuild {\n+                arguments \"NDK_APPLICATION_MK:=src/main/jni/Application.mk\"\n+                abiFilters \"x86_64\"\n+            }\n+        }\n     }\n     buildTypes {\n         release {\n             minifyEnabled false\n             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n         }\n+        debug {\n+            debuggable true\n+            jniDebuggable true\n+            ndk {\n+                debuggable true\n+            }\n+        }\n     }\n-    sourceSets.main {\n-        jniLibs.srcDirs 'src/main/libs'\n-        jni.srcDirs = [] // This prevents the auto generation of Android.mk\n+    externalNativeBuild {\n+        ndkBuild {\n+            path 'src/main/jni/Android.mk'\n+        }\n     }\n }\n \ndiff --git a/android/ijkplayer/ijkplayer-x86_64/src/main/jni/Android.mk b/android/ijkplayer/ijkplayer-x86_64/src/main/jni/Android.mk\ndeleted file mode 120000\nindex fb30867..0000000\n--- a/android/ijkplayer/ijkplayer-x86_64/src/main/jni/Android.mk\n+++ /dev/null\n@@ -1 +0,0 @@\n-../../../../ijkplayer-armv7a/src/main/jni/Android.mk\n\\ No newline at end of file\ndiff --git a/android/ijkplayer/ijkplayer-x86_64/src/main/jni/Android.mk b/android/ijkplayer/ijkplayer-x86_64/src/main/jni/Android.mk\nnew file mode 100644\nindex 0000000..273aa7b\n--- /dev/null\n+++ b/android/ijkplayer/ijkplayer-x86_64/src/main/jni/Android.mk\n@@ -0,0 +1,28 @@\n+# copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n+#\n+# This file is part of ijkPlayer.\n+#\n+# ijkPlayer is free software; you can redistribute it and/or\n+# modify it under the terms of the GNU Lesser General Public\n+# License as published by the Free Software Foundation; either\n+# version 2.1 of the License, or (at your option) any later version.\n+#\n+# ijkPlayer is distributed in the hope that it will be useful,\n+# but WITHOUT ANY WARRANTY; without even the implied warranty of\n+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+# Lesser General Public License for more details.\n+#\n+# You should have received a copy of the GNU Lesser General Public\n+# License along with ijkPlayer; if not, write to the Free Software\n+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n+\n+LOCAL_PATH := $(call my-dir)\n+\n+MY_APP_JNI_ROOT := $(realpath $(LOCAL_PATH))\n+MY_APP_PRJ_ROOT := $(realpath $(MY_APP_JNI_ROOT)/..)\n+MY_APP_ANDROID_ROOT := $(realpath $(MY_APP_PRJ_ROOT)/../../../..)\n+\n+MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-x86_64/output)\n+MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include)\n+\n+include $(call all-subdir-makefiles)\ndiff --git a/android/ijkplayer/settings.gradle b/android/ijkplayer/settings.gradle\nindex 758234a..f1f857f 100644\n--- a/android/ijkplayer/settings.gradle\n+++ b/android/ijkplayer/settings.gradle\n@@ -1,7 +1,7 @@\n-include ':ijkplayer-armv5', ':ijkplayer-x86_64'\n-include ':ijkplayer-armv7a'\n-include ':ijkplayer-arm64'\n-include ':ijkplayer-x86'\n+include ':ijkplayer-x86_64'\n+//include ':ijkplayer-armv7a'\n+//include ':ijkplayer-arm64'\n+//include ':ijkplayer-x86'\n \n include ':ijkplayer-java'\n include ':ijkplayer-exo'\n-- \n2.7.4 (Apple Git-66)\n\n"
  },
  {
    "path": "android/patches/0004-armv7a-link-prebuilt-staic-libraries-of-ffmepg.patch",
    "content": "From fb17b98cfeb265e09220568df17cc493192e6ebe Mon Sep 17 00:00:00 2001\nFrom: ctiao <calmer91@gmail.com>\nDate: Fri, 2 Sep 2016 16:39:02 +0800\nSubject: [PATCH] armv7a: link prebuilt staic libraries of ffmepg\n\n---\n .../src/main/jni/ffmpeg/Android.mk                 | 42 ++++++++++++++++++++--\n .../danmaku/ijk/media/player/IjkMediaPlayer.java   |  1 -\n ijkmedia/ijkplayer/Android.mk                      |  6 ++--\n ijkmedia/ijksdl/Android.mk                         |  4 +--\n 4 files changed, 44 insertions(+), 9 deletions(-)\n\ndiff --git a/android/ijkplayer/ijkplayer-armv7a/src/main/jni/ffmpeg/Android.mk b/android/ijkplayer/ijkplayer-armv7a/src/main/jni/ffmpeg/Android.mk\nindex ec33908..3c525bd 100644\n--- a/android/ijkplayer/ijkplayer-armv7a/src/main/jni/ffmpeg/Android.mk\n+++ b/android/ijkplayer/ijkplayer-armv7a/src/main/jni/ffmpeg/Android.mk\n@@ -1,6 +1,42 @@\n LOCAL_PATH := $(call my-dir)\n+include $(CLEAR_VARS)\n+LOCAL_MODULE    := avcodec\n+LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libavcodec.a\n+LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH)\n+LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH)\n+include $(PREBUILT_STATIC_LIBRARY)\n+\n+include $(CLEAR_VARS)\n+LOCAL_MODULE    := avformat\n+LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libavformat.a\n+LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH)\n+LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH)\n+include $(PREBUILT_STATIC_LIBRARY)\n+\n+include $(CLEAR_VARS)\n+LOCAL_MODULE    := swscale\n+LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libswscale.a\n+LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_OUTPUT_PATH)/include\n+LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH)\n+include $(PREBUILT_STATIC_LIBRARY)\n+\n+include $(CLEAR_VARS)\n+LOCAL_MODULE    := avutil\n+LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libavutil.a\n+LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH)\n+LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH)\n+include $(PREBUILT_STATIC_LIBRARY)\n+\n+include $(CLEAR_VARS)\n+LOCAL_MODULE    := avfilter\n+LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libavfilter.a\n+LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH)\n+LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH)\n+include $(PREBUILT_STATIC_LIBRARY)\n \n include $(CLEAR_VARS)\n-LOCAL_MODULE := ijkffmpeg\n-LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/libijkffmpeg.so\n-include $(PREBUILT_SHARED_LIBRARY)\n\\ No newline at end of file\n+LOCAL_MODULE    := swresample\n+LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libswresample.a\n+LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH)\n+LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH)\n+include $(PREBUILT_STATIC_LIBRARY)\ndiff --git a/android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaPlayer.java b/android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaPlayer.java\nindex 985f848..7ad3fe4 100755\n--- a/android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaPlayer.java\n+++ b/android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaPlayer.java\n@@ -165,7 +165,6 @@ public final class IjkMediaPlayer extends AbstractMediaPlayer {\n                 if (libLoader == null)\n                     libLoader = sLocalLibLoader;\n \n-                libLoader.loadLibrary(\"ijkffmpeg\");\n                 libLoader.loadLibrary(\"ijksdl\");\n                 libLoader.loadLibrary(\"ijkplayer\");\n                 mIsLibLoaded = true;\ndiff --git a/ijkmedia/ijkplayer/Android.mk b/ijkmedia/ijkplayer/Android.mk\nindex 92372ab..6c9270d 100644\n--- a/ijkmedia/ijkplayer/Android.mk\n+++ b/ijkmedia/ijkplayer/Android.mk\n@@ -26,7 +26,7 @@ ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)\n LOCAL_CFLAGS += -mfloat-abi=soft\n endif\n LOCAL_CFLAGS += -std=c99\n-LOCAL_LDLIBS += -llog -landroid\n+LOCAL_LDLIBS += -llog -landroid -lm -lz\n \n LOCAL_C_INCLUDES += $(LOCAL_PATH)\n LOCAL_C_INCLUDES += $(realpath $(LOCAL_PATH)/..)\n@@ -59,8 +59,8 @@ LOCAL_SRC_FILES  += ijkavformat/ijkurlhook.c\n LOCAL_SRC_FILES  += ijkavformat/ijklongurl.c\n LOCAL_SRC_FILES  += ijkavformat/ijksegment.c\n \n-LOCAL_SHARED_LIBRARIES := ijkffmpeg ijksdl\n-LOCAL_STATIC_LIBRARIES := android-ndk-profiler\n+LOCAL_SHARED_LIBRARIES := ijksdl\n+LOCAL_STATIC_LIBRARIES := avformat avcodec swscale swresample avfilter avutil android-ndk-profiler\n \n LOCAL_MODULE := ijkplayer\n include $(BUILD_SHARED_LIBRARY)\ndiff --git a/ijkmedia/ijksdl/Android.mk b/ijkmedia/ijksdl/Android.mk\nindex 08ebbab..4f6d804 100644\n--- a/ijkmedia/ijksdl/Android.mk\n+++ b/ijkmedia/ijksdl/Android.mk\n@@ -70,8 +70,8 @@ LOCAL_SRC_FILES += android/ijksdl_vout_android_nativewindow.c\n LOCAL_SRC_FILES += android/ijksdl_vout_android_surface.c\n LOCAL_SRC_FILES += android/ijksdl_vout_overlay_android_mediacodec.c\n \n-LOCAL_SHARED_LIBRARIES := ijkffmpeg ijkj4a\n-LOCAL_STATIC_LIBRARIES := cpufeatures yuv_static\n+LOCAL_STATIC_LIBRARIES := avformat avcodec swscale swresample avfilter avutil cpufeatures yuv_static\n+LOCAL_SHARED_LIBRARIES := ijkj4a\n \n LOCAL_MODULE := ijksdl\n include $(BUILD_SHARED_LIBRARY)\n-- \n2.7.4 (Apple Git-66)\n\n"
  },
  {
    "path": "android/patches/0004-x86-link-prebuilt-staic-libraries-of-ffmepg.patch",
    "content": "From e8d39a74162855acb1332bd877f22fe1d881aa61 Mon Sep 17 00:00:00 2001\nFrom: ctiao <calmer91@gmail.com>\nDate: Fri, 2 Sep 2016 17:01:57 +0800\nSubject: [PATCH] x86: link prebuilt staic libraries of ffmepg\n\n---\n .../danmaku/ijk/media/player/IjkMediaPlayer.java   |  1 -\n .../ijkplayer-x86/src/main/jni/ffmpeg/Android.mk   | 43 ++++++++++++++++++++--\n ijkmedia/ijkplayer/Android.mk                      |  6 +--\n ijkmedia/ijksdl/Android.mk                         |  4 +-\n 4 files changed, 45 insertions(+), 9 deletions(-)\n\ndiff --git a/android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaPlayer.java b/android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaPlayer.java\nindex 985f848..7ad3fe4 100755\n--- a/android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaPlayer.java\n+++ b/android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaPlayer.java\n@@ -165,7 +165,6 @@ public final class IjkMediaPlayer extends AbstractMediaPlayer {\n                 if (libLoader == null)\n                     libLoader = sLocalLibLoader;\n \n-                libLoader.loadLibrary(\"ijkffmpeg\");\n                 libLoader.loadLibrary(\"ijksdl\");\n                 libLoader.loadLibrary(\"ijkplayer\");\n                 mIsLibLoaded = true;\ndiff --git a/android/ijkplayer/ijkplayer-x86/src/main/jni/ffmpeg/Android.mk b/android/ijkplayer/ijkplayer-x86/src/main/jni/ffmpeg/Android.mk\nindex ec33908..44c50b1 100644\n--- a/android/ijkplayer/ijkplayer-x86/src/main/jni/ffmpeg/Android.mk\n+++ b/android/ijkplayer/ijkplayer-x86/src/main/jni/ffmpeg/Android.mk\n@@ -1,6 +1,43 @@\n LOCAL_PATH := $(call my-dir)\n \n include $(CLEAR_VARS)\n-LOCAL_MODULE := ijkffmpeg\n-LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/libijkffmpeg.so\n-include $(PREBUILT_SHARED_LIBRARY)\n\\ No newline at end of file\n+LOCAL_MODULE    := avcodec\n+LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libavcodec.a\n+LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH)\n+LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH)\n+include $(PREBUILT_STATIC_LIBRARY)\n+\n+include $(CLEAR_VARS)\n+LOCAL_MODULE    := avformat\n+LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libavformat.a\n+LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH)\n+LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH)\n+include $(PREBUILT_STATIC_LIBRARY)\n+\n+include $(CLEAR_VARS)\n+LOCAL_MODULE    := swscale\n+LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libswscale.a\n+LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_OUTPUT_PATH)/include\n+LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH)\n+include $(PREBUILT_STATIC_LIBRARY)\n+\n+include $(CLEAR_VARS)\n+LOCAL_MODULE    := avutil\n+LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libavutil.a\n+LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH)\n+LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH)\n+include $(PREBUILT_STATIC_LIBRARY)\n+\n+include $(CLEAR_VARS)\n+LOCAL_MODULE    := avfilter\n+LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libavfilter.a\n+LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH)\n+LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH)\n+include $(PREBUILT_STATIC_LIBRARY)\n+\n+include $(CLEAR_VARS)\n+LOCAL_MODULE    := swresample\n+LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libswresample.a\n+LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH)\n+LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH)\n+include $(PREBUILT_STATIC_LIBRARY)\ndiff --git a/ijkmedia/ijkplayer/Android.mk b/ijkmedia/ijkplayer/Android.mk\nindex 92372ab..6c9270d 100644\n--- a/ijkmedia/ijkplayer/Android.mk\n+++ b/ijkmedia/ijkplayer/Android.mk\n@@ -26,7 +26,7 @@ ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)\n LOCAL_CFLAGS += -mfloat-abi=soft\n endif\n LOCAL_CFLAGS += -std=c99\n-LOCAL_LDLIBS += -llog -landroid\n+LOCAL_LDLIBS += -llog -landroid -lm -lz\n \n LOCAL_C_INCLUDES += $(LOCAL_PATH)\n LOCAL_C_INCLUDES += $(realpath $(LOCAL_PATH)/..)\n@@ -59,8 +59,8 @@ LOCAL_SRC_FILES  += ijkavformat/ijkurlhook.c\n LOCAL_SRC_FILES  += ijkavformat/ijklongurl.c\n LOCAL_SRC_FILES  += ijkavformat/ijksegment.c\n \n-LOCAL_SHARED_LIBRARIES := ijkffmpeg ijksdl\n-LOCAL_STATIC_LIBRARIES := android-ndk-profiler\n+LOCAL_SHARED_LIBRARIES := ijksdl\n+LOCAL_STATIC_LIBRARIES := avformat avcodec swscale swresample avfilter avutil android-ndk-profiler\n \n LOCAL_MODULE := ijkplayer\n include $(BUILD_SHARED_LIBRARY)\ndiff --git a/ijkmedia/ijksdl/Android.mk b/ijkmedia/ijksdl/Android.mk\nindex 08ebbab..4f6d804 100644\n--- a/ijkmedia/ijksdl/Android.mk\n+++ b/ijkmedia/ijksdl/Android.mk\n@@ -70,8 +70,8 @@ LOCAL_SRC_FILES += android/ijksdl_vout_android_nativewindow.c\n LOCAL_SRC_FILES += android/ijksdl_vout_android_surface.c\n LOCAL_SRC_FILES += android/ijksdl_vout_overlay_android_mediacodec.c\n \n-LOCAL_SHARED_LIBRARIES := ijkffmpeg ijkj4a\n-LOCAL_STATIC_LIBRARIES := cpufeatures yuv_static\n+LOCAL_STATIC_LIBRARIES := avformat avcodec swscale swresample avfilter avutil cpufeatures yuv_static\n+LOCAL_SHARED_LIBRARIES := ijkj4a\n \n LOCAL_MODULE := ijksdl\n include $(BUILD_SHARED_LIBRARY)\n-- \n2.7.4 (Apple Git-66)\n\n"
  },
  {
    "path": "android/patches/0004-x86_64-link-prebuilt-staic-libraries-of-ffmepg.patch",
    "content": "From f123440d855e912f4ce94f48d06a84caffb9bfe2 Mon Sep 17 00:00:00 2001\nFrom: ctiao <calmer91@gmail.com>\nDate: Fri, 2 Sep 2016 17:06:00 +0800\nSubject: [PATCH] x86_64: link prebuilt staic libraries of ffmepg\n\n---\n .../danmaku/ijk/media/player/IjkMediaPlayer.java   |  1 -\n .../src/main/jni/ffmpeg/Android.mk                 | 42 ++++++++++++++++++++--\n ijkmedia/ijkplayer/Android.mk                      |  6 ++--\n ijkmedia/ijksdl/Android.mk                         |  4 +--\n 4 files changed, 44 insertions(+), 9 deletions(-)\n\ndiff --git a/android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaPlayer.java b/android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaPlayer.java\nindex 985f848..7ad3fe4 100755\n--- a/android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaPlayer.java\n+++ b/android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaPlayer.java\n@@ -165,7 +165,6 @@ public final class IjkMediaPlayer extends AbstractMediaPlayer {\n                 if (libLoader == null)\n                     libLoader = sLocalLibLoader;\n \n-                libLoader.loadLibrary(\"ijkffmpeg\");\n                 libLoader.loadLibrary(\"ijksdl\");\n                 libLoader.loadLibrary(\"ijkplayer\");\n                 mIsLibLoaded = true;\ndiff --git a/android/ijkplayer/ijkplayer-x86_64/src/main/jni/ffmpeg/Android.mk b/android/ijkplayer/ijkplayer-x86_64/src/main/jni/ffmpeg/Android.mk\nindex ec33908..3c525bd 100644\n--- a/android/ijkplayer/ijkplayer-x86_64/src/main/jni/ffmpeg/Android.mk\n+++ b/android/ijkplayer/ijkplayer-x86_64/src/main/jni/ffmpeg/Android.mk\n@@ -1,6 +1,42 @@\n LOCAL_PATH := $(call my-dir)\n+include $(CLEAR_VARS)\n+LOCAL_MODULE    := avcodec\n+LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libavcodec.a\n+LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH)\n+LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH)\n+include $(PREBUILT_STATIC_LIBRARY)\n+\n+include $(CLEAR_VARS)\n+LOCAL_MODULE    := avformat\n+LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libavformat.a\n+LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH)\n+LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH)\n+include $(PREBUILT_STATIC_LIBRARY)\n+\n+include $(CLEAR_VARS)\n+LOCAL_MODULE    := swscale\n+LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libswscale.a\n+LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_OUTPUT_PATH)/include\n+LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH)\n+include $(PREBUILT_STATIC_LIBRARY)\n+\n+include $(CLEAR_VARS)\n+LOCAL_MODULE    := avutil\n+LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libavutil.a\n+LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH)\n+LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH)\n+include $(PREBUILT_STATIC_LIBRARY)\n+\n+include $(CLEAR_VARS)\n+LOCAL_MODULE    := avfilter\n+LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libavfilter.a\n+LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH)\n+LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH)\n+include $(PREBUILT_STATIC_LIBRARY)\n \n include $(CLEAR_VARS)\n-LOCAL_MODULE := ijkffmpeg\n-LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/libijkffmpeg.so\n-include $(PREBUILT_SHARED_LIBRARY)\n\\ No newline at end of file\n+LOCAL_MODULE    := swresample\n+LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libswresample.a\n+LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH)\n+LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH)\n+include $(PREBUILT_STATIC_LIBRARY)\ndiff --git a/ijkmedia/ijkplayer/Android.mk b/ijkmedia/ijkplayer/Android.mk\nindex 92372ab..6c9270d 100644\n--- a/ijkmedia/ijkplayer/Android.mk\n+++ b/ijkmedia/ijkplayer/Android.mk\n@@ -26,7 +26,7 @@ ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)\n LOCAL_CFLAGS += -mfloat-abi=soft\n endif\n LOCAL_CFLAGS += -std=c99\n-LOCAL_LDLIBS += -llog -landroid\n+LOCAL_LDLIBS += -llog -landroid -lm -lz\n \n LOCAL_C_INCLUDES += $(LOCAL_PATH)\n LOCAL_C_INCLUDES += $(realpath $(LOCAL_PATH)/..)\n@@ -59,8 +59,8 @@ LOCAL_SRC_FILES  += ijkavformat/ijkurlhook.c\n LOCAL_SRC_FILES  += ijkavformat/ijklongurl.c\n LOCAL_SRC_FILES  += ijkavformat/ijksegment.c\n \n-LOCAL_SHARED_LIBRARIES := ijkffmpeg ijksdl\n-LOCAL_STATIC_LIBRARIES := android-ndk-profiler\n+LOCAL_SHARED_LIBRARIES := ijksdl\n+LOCAL_STATIC_LIBRARIES := avformat avcodec swscale swresample avfilter avutil android-ndk-profiler\n \n LOCAL_MODULE := ijkplayer\n include $(BUILD_SHARED_LIBRARY)\ndiff --git a/ijkmedia/ijksdl/Android.mk b/ijkmedia/ijksdl/Android.mk\nindex 08ebbab..4f6d804 100644\n--- a/ijkmedia/ijksdl/Android.mk\n+++ b/ijkmedia/ijksdl/Android.mk\n@@ -70,8 +70,8 @@ LOCAL_SRC_FILES += android/ijksdl_vout_android_nativewindow.c\n LOCAL_SRC_FILES += android/ijksdl_vout_android_surface.c\n LOCAL_SRC_FILES += android/ijksdl_vout_overlay_android_mediacodec.c\n \n-LOCAL_SHARED_LIBRARIES := ijkffmpeg ijkj4a\n-LOCAL_STATIC_LIBRARIES := cpufeatures yuv_static\n+LOCAL_STATIC_LIBRARIES := avformat avcodec swscale swresample avfilter avutil cpufeatures yuv_static\n+LOCAL_SHARED_LIBRARIES := ijkj4a\n \n LOCAL_MODULE := ijksdl\n include $(BUILD_SHARED_LIBRARY)\n-- \n2.7.4 (Apple Git-66)\n\n"
  },
  {
    "path": "compile-android-j4a.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2016 Bilibili\n# Copyright (C) 2016 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nset -e\n\ncd extra/jni4android-fork\n./configure --incdir=../../ijkmedia/ijkj4a --bindir=../bin\nmake install\ncd -\n\ncd ijkmedia/ijkj4a\nmake\ncd -\n"
  },
  {
    "path": "config/module-default.sh",
    "content": "#! /usr/bin/env bash\n\n#--------------------\n# Standard options:\nexport COMMON_FF_CFG_FLAGS=\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --prefix=PREFIX\"\n\n# Licensing options:\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-gpl\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-version3\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-nonfree\"\n\n# Configuration options:\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-static\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-shared\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-small\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-runtime-cpudetect\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-gray\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-swscale-alpha\"\n\n# Program options:\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-programs\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-ffmpeg\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-ffplay\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-ffprobe\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-ffserver\"\n\n# Documentation options:\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-doc\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-htmlpages\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-manpages\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-podpages\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-txtpages\"\n\n# Component options:\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-avdevice\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-avcodec\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-avformat\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-avutil\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-swresample\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-swscale\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-postproc\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-avfilter\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-avresample\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-pthreads\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-w32threads\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-os2threads\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-network\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-dct\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-dwt\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-lsp\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-lzo\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-mdct\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-rdft\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-fft\"\n\n# Hardware accelerators:\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-dxva2\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-vaapi\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-vda\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-vdpau\"\n\n# Individual component options:\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-everything\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-encoders\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-decoders\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-hwaccels\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-muxers\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-demuxers\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-parsers\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-bsfs\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocols\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-devices\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-filters\"\n\n# External library support:\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-iconv\"\n# ...\n\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-protocol=async\"\n\n# Advanced options (experts only):\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --cross-prefix=${FF_CROSS_PREFIX}-\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-cross-compile\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --sysroot=PATH\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --sysinclude=PATH\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --target-os=TAGET_OS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --target-exec=CMD\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --target-path=DIR\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --toolchain=NAME\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --nm=NM\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --ar=AR\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --as=AS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --yasmexe=EXE\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --cc=CC\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --cxx=CXX\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --dep-cc=DEPCC\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --ld=LD\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --host-cc=HOSTCC\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --host-cflags=HCFLAGS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --host-cppflags=HCPPFLAGS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --host-ld=HOSTLD\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --host-ldflags=HLDFLAGS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --host-libs=HLIBS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --host-os=OS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --extra-cflags=ECFLAGS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --extra-cxxflags=ECFLAGS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --extra-ldflags=ELDFLAGS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --extra-libs=ELIBS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --extra-version=STRING\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --optflags=OPTFLAGS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --build-suffix=SUFFIX\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --malloc-prefix=PREFIX\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --progs-suffix=SUFFIX\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --arch=ARCH\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --cpu=CPU\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-pic\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-sram\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-thumb\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-symver\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-hardcoded-tables\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-safe-bitstream-reader\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-memalign-hack\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-lto\"\n\n# Optimization options (experts only):\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-asm\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-altivec\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-amd3dnow\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-amd3dnowext\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-mmx\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-mmxext\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-sse\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-sse2\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-sse3\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-ssse3\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-sse4\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-sse42\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-avx\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-fma4\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-armv5te\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-armv6\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-armv6t2\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-vfp\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-neon\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-vis\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-inline-asm\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-yasm\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-mips32r2\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-mipsdspr1\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-mipsdspr2\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-mipsfpu\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-fast-unaligned\"\n\n# Developer options (useful when working on FFmpeg itself):\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-coverage\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-debug\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-debug=LEVEL\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-optimizations\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-extra-warnings\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-stripping\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --assert-level=level\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-memory-poisoning\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --valgrind=VALGRIND\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-ftrapv\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --samples=PATH\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-xmm-clobber-test\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-random\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-random\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-random=LIST\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-random=LIST\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --random-seed=VALUE\""
  },
  {
    "path": "config/module-lite-hevc.sh",
    "content": "#! /usr/bin/env bash\n\n#--------------------\n# Standard options:\nexport COMMON_FF_CFG_FLAGS=\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --prefix=PREFIX\"\n\n# Licensing options:\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-gpl\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-version3\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-nonfree\"\n\n# Configuration options:\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-static\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-shared\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-small\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-runtime-cpudetect\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-gray\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-swscale-alpha\"\n\n# Program options:\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-programs\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-ffmpeg\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-ffplay\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-ffprobe\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-ffserver\"\n\n# Documentation options:\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-doc\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-htmlpages\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-manpages\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-podpages\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-txtpages\"\n\n# Component options:\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-avdevice\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-avcodec\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-avformat\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-avutil\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-swresample\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-swscale\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-postproc\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-avfilter\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-avresample\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-pthreads\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-w32threads\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-os2threads\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-network\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-dct\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-dwt\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-lsp\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-lzo\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-mdct\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-rdft\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-fft\"\n\n# Hardware accelerators:\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-dxva2\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-vaapi\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-vda\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-vdpau\"\n\n# Individual component options:\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-everything\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-encoders\"\n\n# ./configure --list-decoders\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-decoders\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-decoder=aac\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-decoder=aac_latm\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-decoder=flv\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-decoder=h263\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-decoder=h263i\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-decoder=h263p\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-decoder=h264\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-decoder=mp3*\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-decoder=vp6\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-decoder=vp6a\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-decoder=vp6f\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-decoder=hevc\"\n\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-hwaccels\"\n\n# ./configure --list-muxers\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-muxers\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-muxer=mpegts\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-muxer=mp4\"\n\n# ./configure --list-demuxers\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-demuxers\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=aac\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=concat\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=data\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=flv\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=hls\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=latm\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=live_flv\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=loas\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=m4v\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=mov\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=mp3\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=mpegps\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=mpegts\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=mpegvideo\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=hevc\"\n\n# ./configure --list-parsers\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-parsers\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-parser=aac\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-parser=aac_latm\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-parser=ac3\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-parser=h263\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-parser=h264\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-parser=hevc\"\n\n# ./configure --list-bsf\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-bsfs\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-bsf=mjpeg2jpeg\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-bsf=mjpeg2jpeg\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-bsf=mjpega_dump_header\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-bsf=mov2textsub\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-bsf=text2movsub\"\n\n# ./configure --list-protocols\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-protocols\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-protocol=async\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=bluray\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=ffrtmpcrypt\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-protocol=ffrtmphttp\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=gopher\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=librtmp*\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=libssh\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=mmsh\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=mmst\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=rtmp*\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-protocol=rtmp\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-protocol=rtmpt\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=rtp\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=sctp\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=srtp\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=unix\"\n\n#\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-devices\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-filters\"\n\n# External library support:\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-iconv\"\n# ...\n\n# Advanced options (experts only):\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --cross-prefix=${FF_CROSS_PREFIX}-\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-cross-compile\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --sysroot=PATH\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --sysinclude=PATH\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --target-os=TAGET_OS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --target-exec=CMD\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --target-path=DIR\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --toolchain=NAME\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --nm=NM\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --ar=AR\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --as=AS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --yasmexe=EXE\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --cc=CC\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --cxx=CXX\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --dep-cc=DEPCC\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --ld=LD\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --host-cc=HOSTCC\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --host-cflags=HCFLAGS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --host-cppflags=HCPPFLAGS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --host-ld=HOSTLD\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --host-ldflags=HLDFLAGS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --host-libs=HLIBS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --host-os=OS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --extra-cflags=ECFLAGS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --extra-cxxflags=ECFLAGS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --extra-ldflags=ELDFLAGS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --extra-libs=ELIBS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --extra-version=STRING\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --optflags=OPTFLAGS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --build-suffix=SUFFIX\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --malloc-prefix=PREFIX\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --progs-suffix=SUFFIX\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --arch=ARCH\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --cpu=CPU\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-pic\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-sram\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-thumb\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-symver\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-hardcoded-tables\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-safe-bitstream-reader\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-memalign-hack\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-lto\"\n\n# Optimization options (experts only):\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-asm\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-altivec\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-amd3dnow\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-amd3dnowext\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-mmx\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-mmxext\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-sse\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-sse2\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-sse3\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-ssse3\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-sse4\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-sse42\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-avx\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-fma4\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-armv5te\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-armv6\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-armv6t2\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-vfp\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-neon\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-vis\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-inline-asm\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-yasm\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-mips32r2\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-mipsdspr1\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-mipsdspr2\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-mipsfpu\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-fast-unaligned\"\n\n# Developer options (useful when working on FFmpeg itself):\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-coverage\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-debug\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-debug=LEVEL\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-optimizations\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-extra-warnings\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-stripping\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --assert-level=level\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-memory-poisoning\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --valgrind=VALGRIND\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-ftrapv\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --samples=PATH\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-xmm-clobber-test\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-random\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-random\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-random=LIST\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-random=LIST\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --random-seed=VALUE\"\n"
  },
  {
    "path": "config/module-lite.sh",
    "content": "#! /usr/bin/env bash\n\n#--------------------\n# Standard options:\nexport COMMON_FF_CFG_FLAGS=\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --prefix=PREFIX\"\n\n# Licensing options:\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-gpl\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-version3\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-nonfree\"\n\n# Configuration options:\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-static\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-shared\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-small\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-runtime-cpudetect\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-gray\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-swscale-alpha\"\n\n# Program options:\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-programs\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-ffmpeg\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-ffplay\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-ffprobe\"\n#export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-ffserver\"\n\n# Documentation options:\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-doc\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-htmlpages\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-manpages\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-podpages\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-txtpages\"\n\n# Component options:\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-avdevice\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-avcodec\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-avformat\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-avutil\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-swresample\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-swscale\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-postproc\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-avfilter\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-avresample\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-pthreads\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-w32threads\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-os2threads\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-network\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-dct\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-dwt\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-lsp\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-lzo\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-mdct\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-rdft\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-fft\"\n\n# Hardware accelerators:\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-d3d11va\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-dxva2\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-vaapi\"\n#export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-vda\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-vdpau\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-videotoolbox\"\n\n# Individual component options:\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-everything\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-encoders\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-encoder=png\"\n\n# ./configure --list-decoders\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-decoders\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-decoder=aac\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-decoder=aac_latm\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-decoder=flv\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-decoder=h264\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-decoder=mp3*\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-decoder=vp6f\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-decoder=flac\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-decoder=hevc\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-decoder=vp8\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-decoder=vp9\"\n\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-hwaccels\"\n\n# ./configure --list-muxers\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-muxers\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-muxer=mp4\"\n\n# ./configure --list-demuxers\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-demuxers\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=ijk*\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=aac\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=concat\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=data\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=flv\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=hls\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=live_flv\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=mov\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=mp3\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=mpegps\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=mpegts\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=mpegvideo\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=flac\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=hevc\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-demuxer=webm_dash_manifest\"\n\n# ./configure --list-parsers\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-parsers\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-parser=aac\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-parser=aac_latm\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-parser=h264\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-parser=flac\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-parser=hevc\"\n\n# ./configure --list-bsf\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-bsfs\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-bsf=chomp\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-bsf=dca_core\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-bsf=dump_extradata\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-bsf=hevc_mp4toannexb\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-bsf=imx_dump_header\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-bsf=mjpeg2jpeg\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-bsf=mjpega_dump_header\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-bsf=mov2textsub\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-bsf=mp3_header_decompress\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-bsf=mpeg4_unpack_bframes\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-bsf=noise\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-bsf=remove_extradata\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-bsf=text2movsub\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-bsf=vp9_superframe\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-bsf=eac3_core\"\n\n# ./configure --list-protocols\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-protocols\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-protocol=async\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=bluray\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=concat\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=crypto\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=ffrtmpcrypt\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-protocol=ffrtmphttp\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=gopher\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=icecast\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=librtmp*\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=libssh\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=md5\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=mmsh\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=mmst\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=rtmp*\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-protocol=rtmp\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-protocol=rtmpt\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=rtp\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=sctp\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=srtp\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=subfile\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-protocol=unix\"\n\n#\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-devices\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-filters\"\n\n# External library support:\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-iconv\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-audiotoolbox\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-videotoolbox\"\n\n# ...\n\n# Advanced options (experts only):\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --cross-prefix=${FF_CROSS_PREFIX}-\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-cross-compile\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --sysroot=PATH\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --sysinclude=PATH\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --target-os=TAGET_OS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --target-exec=CMD\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --target-path=DIR\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --toolchain=NAME\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --nm=NM\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --ar=AR\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --as=AS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --yasmexe=EXE\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --cc=CC\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --cxx=CXX\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --dep-cc=DEPCC\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --ld=LD\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --host-cc=HOSTCC\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --host-cflags=HCFLAGS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --host-cppflags=HCPPFLAGS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --host-ld=HOSTLD\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --host-ldflags=HLDFLAGS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --host-libs=HLIBS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --host-os=OS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --extra-cflags=ECFLAGS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --extra-cxxflags=ECFLAGS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --extra-ldflags=ELDFLAGS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --extra-libs=ELIBS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --extra-version=STRING\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --optflags=OPTFLAGS\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --build-suffix=SUFFIX\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --malloc-prefix=PREFIX\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --progs-suffix=SUFFIX\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --arch=ARCH\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --cpu=CPU\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-pic\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-sram\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-thumb\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-symver\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-hardcoded-tables\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-safe-bitstream-reader\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-memalign-hack\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-lto\"\n\n# Optimization options (experts only):\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-asm\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-altivec\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-amd3dnow\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-amd3dnowext\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-mmx\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-mmxext\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-sse\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-sse2\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-sse3\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-ssse3\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-sse4\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-sse42\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-avx\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-fma4\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-armv5te\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-armv6\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-armv6t2\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-vfp\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-neon\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-vis\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-inline-asm\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-yasm\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-mips32r2\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-mipsdspr1\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-mipsdspr2\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-mipsfpu\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-fast-unaligned\"\n\n# Developer options (useful when working on FFmpeg itself):\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-coverage\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-debug\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-debug=LEVEL\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-optimizations\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-extra-warnings\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-stripping\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --assert-level=level\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-memory-poisoning\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --valgrind=VALGRIND\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-ftrapv\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --samples=PATH\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-xmm-clobber-test\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-random\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-random\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --enable-random=LIST\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-random=LIST\"\n# export COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --random-seed=VALUE\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-linux-perf\"\nexport COMMON_FF_CFG_FLAGS=\"$COMMON_FF_CFG_FLAGS --disable-bzlib\"\n\n"
  },
  {
    "path": "doc/preflight_checklist.md",
    "content": "ChangeLog\n-----------------------\n* Update NEWS.md\n* Update README.md\n* Commit and push\n\nFFmpeg\n-----------------------\n* Build and test iOS and Android demo locally\n* Modify ffmpeg version in init-ios.sh and init-android.sh\n* Modify ffmpeg version in `IJKFFMoviePlayerController` (by running `sh init-ios.sh`)\n* Commit and push\n\nOpenSSL\n----------------------\n* Check openssl latest stable version\n\nijkplayer\n-----------------------\n* Update version.sh\n* Create a tag (subtitle)\n* Commit and push (TAG ONLY)\n\nTravis-ci\n-----------------------\n* Modify ijk version in `.travis.yaml` in iOS and Android ci repo.\n* Ensure compile task has been started on travis-ci.\n* Ensure Andoird release has been released in bintray.\n\nTake off\n-----------------------\n* Push master to github\n"
  },
  {
    "path": "ijkmedia/Android.mk",
    "content": "# Copyright (c) 2013 Bilibili\n# copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n#\n# This file is part of ijkPlayer.\n#\n# ijkPlayer is free software; you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation; either\n# version 2.1 of the License, or (at your option) any later version.\n#\n# ijkPlayer is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# Lesser General Public License for more details.\n#\n# You should have received a copy of the GNU Lesser General Public\n# License along with ijkPlayer; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n\nLOCAL_PATH := $(call my-dir)\ninclude $(call all-subdir-makefiles)\n"
  },
  {
    "path": "ijkmedia/ijkj4a/.gitignore",
    "content": "bin\n"
  },
  {
    "path": "ijkmedia/ijkj4a/Android.mk",
    "content": "# copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n#\n# This file is part of ijkPlayer.\n#\n# ijkPlayer is free software; you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation; either\n# version 2.1 of the License, or (at your option) any later version.\n#\n# ijkPlayer is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# Lesser General Public License for more details.\n#\n# You should have received a copy of the GNU Lesser General Public\n# License along with ijkPlayer; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n\nLOCAL_PATH := $(call my-dir)\n\ninclude $(CLEAR_VARS)\nLOCAL_CFLAGS += -std=c99\n\nLOCAL_C_INCLUDES += $(LOCAL_PATH)\nLOCAL_C_INCLUDES += $(realpath $(LOCAL_PATH))\n\nLOCAL_SRC_FILES += j4a/j4a_allclasses.c\nLOCAL_SRC_FILES += j4a/j4a_base.c\nLOCAL_SRC_FILES += j4a/class/android/media/AudioTrack.c\nLOCAL_SRC_FILES += j4a/class/android/media/MediaCodec.c\nLOCAL_SRC_FILES += j4a/class/android/media/MediaFormat.c\nLOCAL_SRC_FILES += j4a/class/android/media/PlaybackParams.c\nLOCAL_SRC_FILES += j4a/class/android/os/Build.c\nLOCAL_SRC_FILES += j4a/class/android/os/Bundle.c\nLOCAL_SRC_FILES += j4a/class/java/nio/Buffer.c\nLOCAL_SRC_FILES += j4a/class/java/nio/ByteBuffer.c\nLOCAL_SRC_FILES += j4a/class/java/util/ArrayList.c\nLOCAL_SRC_FILES += j4a/class/tv/danmaku/ijk/media/player/misc/IMediaDataSource.c\nLOCAL_SRC_FILES += j4a/class/tv/danmaku/ijk/media/player/misc/IAndroidIO.c\nLOCAL_SRC_FILES += j4a/class/tv/danmaku/ijk/media/player/IjkMediaPlayer.c\n\nLOCAL_SRC_FILES += j4au/class/android/media/AudioTrack.util.c\nLOCAL_SRC_FILES += j4au/class/java/nio/ByteBuffer.util.c\n\nLOCAL_MODULE := ijkj4a\ninclude $(BUILD_STATIC_LIBRARY)\n\n$(call import-module,android/cpufeatures)\n"
  },
  {
    "path": "ijkmedia/ijkj4a/Makefile",
    "content": "J4A = ../../extra/bin/j4a\nROOT_CLASS_INCLUDES = j4a/j4a_allclasses.include.h\nROOT_CLASS_LOADERS = j4a/j4a_allclasses.loader.h\n\nall: ijkj4a\n\n# test java -> c\nJAVA_SRCS = \\\n\tjava/java/nio/Buffer.java \\\n\tjava/java/nio/ByteBuffer.java \\\n\tjava/java/util/ArrayList.java \\\n\tjava/android/media/AudioTrack.java \\\n\tjava/android/media/MediaCodec.java \\\n\tjava/android/media/MediaFormat.java \\\n\tjava/android/media/PlaybackParams.java \\\n\tjava/android/os/Build.java \\\n\tjava/android/os/Bundle.java \\\n\tjava/tv/danmaku/ijk/media/player/misc/IMediaDataSource.java \\\n\tjava/tv/danmaku/ijk/media/player/misc/IAndroidIO.java \\\n\tjava/tv/danmaku/ijk/media/player/IjkMediaPlayer.java \\\n\nC_SRCS := $(JAVA_SRCS:java/%.java=j4a/class/%.c)\nH_SRCS := $(C_SRCS:%.c=%.h)\n\n$(C_SRCS): j4a/class/%.c: $(J4A)\n\n$(C_SRCS): j4a/class/%.c: java/%.java\nifneq (\"$<\", \"j4a/class/.c\")\n\t@mkdir -p $(shell dirname $@)\n\t$(J4A) -c $< -o $@\n\t@cat j4a/class/$*.include.j4a >> $(ROOT_CLASS_INCLUDES)\n\t@echo >> $(ROOT_CLASS_INCLUDES)\n\t@cat j4a/class/$*.loader.j4a >> $(ROOT_CLASS_LOADERS)\n\t@echo >> $(ROOT_CLASS_LOADERS)\nendif\n\nijkj4a: prebuild $(C_SRCS)\n\nprebuild:\n\t@rm -f $(ROOT_CLASS_INCLUDES)\n\t@rm -f $(ROOT_CLASS_LOADERS)\n\n# -----\n.PHONY: all clean ijkj4a prebuild\n\nclean:\n\t@rm -f $(C_SRCS)\n\t@rm -f $(H_SRCS)\n\t@rm -f $(ROOT_CLASS_INCLUDES)\n\t@rm -f $(ROOT_CLASS_LOADERS)\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/android/media/AudioTrack.c",
    "content": "/*\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * https://github.com/Bilibili/jni4android\n * This file is automatically generated by jni4android, do not modify.\n */\n\n#include \"AudioTrack.h\"\n\ntypedef struct J4AC_android_media_AudioTrack {\n    jclass id;\n\n    jmethodID constructor_AudioTrack;\n    jmethodID method_getMinBufferSize;\n    jmethodID method_getMaxVolume;\n    jmethodID method_getMinVolume;\n    jmethodID method_getNativeOutputSampleRate;\n    jmethodID method_play;\n    jmethodID method_pause;\n    jmethodID method_stop;\n    jmethodID method_flush;\n    jmethodID method_release;\n    jmethodID method_write;\n    jmethodID method_setStereoVolume;\n    jmethodID method_getAudioSessionId;\n    jmethodID method_getPlaybackParams;\n    jmethodID method_setPlaybackParams;\n    jmethodID method_getStreamType;\n    jmethodID method_getSampleRate;\n    jmethodID method_getPlaybackRate;\n    jmethodID method_setPlaybackRate;\n} J4AC_android_media_AudioTrack;\nstatic J4AC_android_media_AudioTrack class_J4AC_android_media_AudioTrack;\n\njobject J4AC_android_media_AudioTrack__AudioTrack(JNIEnv *env, jint streamType, jint sampleRateInHz, jint channelConfig, jint audioFormat, jint bufferSizeInBytes, jint mode)\n{\n    return (*env)->NewObject(env, class_J4AC_android_media_AudioTrack.id, class_J4AC_android_media_AudioTrack.constructor_AudioTrack, streamType, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes, mode);\n}\n\njobject J4AC_android_media_AudioTrack__AudioTrack__catchAll(JNIEnv *env, jint streamType, jint sampleRateInHz, jint channelConfig, jint audioFormat, jint bufferSizeInBytes, jint mode)\n{\n    jobject ret_object = J4AC_android_media_AudioTrack__AudioTrack(env, streamType, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes, mode);\n    if (J4A_ExceptionCheck__catchAll(env) || !ret_object) {\n        return NULL;\n    }\n\n    return ret_object;\n}\n\njobject J4AC_android_media_AudioTrack__AudioTrack__asGlobalRef__catchAll(JNIEnv *env, jint streamType, jint sampleRateInHz, jint channelConfig, jint audioFormat, jint bufferSizeInBytes, jint mode)\n{\n    jobject ret_object   = NULL;\n    jobject local_object = J4AC_android_media_AudioTrack__AudioTrack__catchAll(env, streamType, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes, mode);\n    if (J4A_ExceptionCheck__catchAll(env) || !local_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\n    ret_object = J4A_NewGlobalRef__catchAll(env, local_object);\n    if (!ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &local_object);\n    return ret_object;\n}\n\njint J4AC_android_media_AudioTrack__getMinBufferSize(JNIEnv *env, jint sampleRateInHz, jint channelConfig, jint audioFormat)\n{\n    return (*env)->CallStaticIntMethod(env, class_J4AC_android_media_AudioTrack.id, class_J4AC_android_media_AudioTrack.method_getMinBufferSize, sampleRateInHz, channelConfig, audioFormat);\n}\n\njint J4AC_android_media_AudioTrack__getMinBufferSize__catchAll(JNIEnv *env, jint sampleRateInHz, jint channelConfig, jint audioFormat)\n{\n    jint ret_value = J4AC_android_media_AudioTrack__getMinBufferSize(env, sampleRateInHz, channelConfig, audioFormat);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\njfloat J4AC_android_media_AudioTrack__getMaxVolume(JNIEnv *env)\n{\n    return (*env)->CallStaticFloatMethod(env, class_J4AC_android_media_AudioTrack.id, class_J4AC_android_media_AudioTrack.method_getMaxVolume);\n}\n\njfloat J4AC_android_media_AudioTrack__getMaxVolume__catchAll(JNIEnv *env)\n{\n    jfloat ret_value = J4AC_android_media_AudioTrack__getMaxVolume(env);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\njfloat J4AC_android_media_AudioTrack__getMinVolume(JNIEnv *env)\n{\n    return (*env)->CallStaticFloatMethod(env, class_J4AC_android_media_AudioTrack.id, class_J4AC_android_media_AudioTrack.method_getMinVolume);\n}\n\njfloat J4AC_android_media_AudioTrack__getMinVolume__catchAll(JNIEnv *env)\n{\n    jfloat ret_value = J4AC_android_media_AudioTrack__getMinVolume(env);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\njint J4AC_android_media_AudioTrack__getNativeOutputSampleRate(JNIEnv *env, jint streamType)\n{\n    return (*env)->CallStaticIntMethod(env, class_J4AC_android_media_AudioTrack.id, class_J4AC_android_media_AudioTrack.method_getNativeOutputSampleRate, streamType);\n}\n\njint J4AC_android_media_AudioTrack__getNativeOutputSampleRate__catchAll(JNIEnv *env, jint streamType)\n{\n    jint ret_value = J4AC_android_media_AudioTrack__getNativeOutputSampleRate(env, streamType);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\nvoid J4AC_android_media_AudioTrack__play(JNIEnv *env, jobject thiz)\n{\n    (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_play);\n}\n\nvoid J4AC_android_media_AudioTrack__play__catchAll(JNIEnv *env, jobject thiz)\n{\n    J4AC_android_media_AudioTrack__play(env, thiz);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\nvoid J4AC_android_media_AudioTrack__pause(JNIEnv *env, jobject thiz)\n{\n    (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_pause);\n}\n\nvoid J4AC_android_media_AudioTrack__pause__catchAll(JNIEnv *env, jobject thiz)\n{\n    J4AC_android_media_AudioTrack__pause(env, thiz);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\nvoid J4AC_android_media_AudioTrack__stop(JNIEnv *env, jobject thiz)\n{\n    (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_stop);\n}\n\nvoid J4AC_android_media_AudioTrack__stop__catchAll(JNIEnv *env, jobject thiz)\n{\n    J4AC_android_media_AudioTrack__stop(env, thiz);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\nvoid J4AC_android_media_AudioTrack__flush(JNIEnv *env, jobject thiz)\n{\n    (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_flush);\n}\n\nvoid J4AC_android_media_AudioTrack__flush__catchAll(JNIEnv *env, jobject thiz)\n{\n    J4AC_android_media_AudioTrack__flush(env, thiz);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\nvoid J4AC_android_media_AudioTrack__release(JNIEnv *env, jobject thiz)\n{\n    (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_release);\n}\n\nvoid J4AC_android_media_AudioTrack__release__catchAll(JNIEnv *env, jobject thiz)\n{\n    J4AC_android_media_AudioTrack__release(env, thiz);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\njint J4AC_android_media_AudioTrack__write(JNIEnv *env, jobject thiz, jbyteArray audioData, jint offsetInBytes, jint sizeInBytes)\n{\n    return (*env)->CallIntMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_write, audioData, offsetInBytes, sizeInBytes);\n}\n\njint J4AC_android_media_AudioTrack__write__catchAll(JNIEnv *env, jobject thiz, jbyteArray audioData, jint offsetInBytes, jint sizeInBytes)\n{\n    jint ret_value = J4AC_android_media_AudioTrack__write(env, thiz, audioData, offsetInBytes, sizeInBytes);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\njint J4AC_android_media_AudioTrack__setStereoVolume(JNIEnv *env, jobject thiz, jfloat leftGain, jfloat rightGain)\n{\n    return (*env)->CallIntMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_setStereoVolume, leftGain, rightGain);\n}\n\njint J4AC_android_media_AudioTrack__setStereoVolume__catchAll(JNIEnv *env, jobject thiz, jfloat leftGain, jfloat rightGain)\n{\n    jint ret_value = J4AC_android_media_AudioTrack__setStereoVolume(env, thiz, leftGain, rightGain);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\njint J4AC_android_media_AudioTrack__getAudioSessionId(JNIEnv *env, jobject thiz)\n{\n    return (*env)->CallIntMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_getAudioSessionId);\n}\n\njint J4AC_android_media_AudioTrack__getAudioSessionId__catchAll(JNIEnv *env, jobject thiz)\n{\n    jint ret_value = J4AC_android_media_AudioTrack__getAudioSessionId(env, thiz);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\njobject J4AC_android_media_AudioTrack__getPlaybackParams(JNIEnv *env, jobject thiz)\n{\n    return (*env)->CallObjectMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_getPlaybackParams);\n}\n\njobject J4AC_android_media_AudioTrack__getPlaybackParams__catchAll(JNIEnv *env, jobject thiz)\n{\n    jobject ret_object = J4AC_android_media_AudioTrack__getPlaybackParams(env, thiz);\n    if (J4A_ExceptionCheck__catchAll(env) || !ret_object) {\n        return NULL;\n    }\n\n    return ret_object;\n}\n\njobject J4AC_android_media_AudioTrack__getPlaybackParams__asGlobalRef__catchAll(JNIEnv *env, jobject thiz)\n{\n    jobject ret_object   = NULL;\n    jobject local_object = J4AC_android_media_AudioTrack__getPlaybackParams__catchAll(env, thiz);\n    if (J4A_ExceptionCheck__catchAll(env) || !local_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\n    ret_object = J4A_NewGlobalRef__catchAll(env, local_object);\n    if (!ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &local_object);\n    return ret_object;\n}\n\nvoid J4AC_android_media_AudioTrack__setPlaybackParams(JNIEnv *env, jobject thiz, jobject params)\n{\n    (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_setPlaybackParams, params);\n}\n\nvoid J4AC_android_media_AudioTrack__setPlaybackParams__catchAll(JNIEnv *env, jobject thiz, jobject params)\n{\n    J4AC_android_media_AudioTrack__setPlaybackParams(env, thiz, params);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\njint J4AC_android_media_AudioTrack__getStreamType(JNIEnv *env, jobject thiz)\n{\n    return (*env)->CallIntMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_getStreamType);\n}\n\njint J4AC_android_media_AudioTrack__getStreamType__catchAll(JNIEnv *env, jobject thiz)\n{\n    jint ret_value = J4AC_android_media_AudioTrack__getStreamType(env, thiz);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\njint J4AC_android_media_AudioTrack__getSampleRate(JNIEnv *env, jobject thiz)\n{\n    return (*env)->CallIntMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_getSampleRate);\n}\n\njint J4AC_android_media_AudioTrack__getSampleRate__catchAll(JNIEnv *env, jobject thiz)\n{\n    jint ret_value = J4AC_android_media_AudioTrack__getSampleRate(env, thiz);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\njint J4AC_android_media_AudioTrack__getPlaybackRate(JNIEnv *env, jobject thiz)\n{\n    return (*env)->CallIntMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_getPlaybackRate);\n}\n\njint J4AC_android_media_AudioTrack__getPlaybackRate__catchAll(JNIEnv *env, jobject thiz)\n{\n    jint ret_value = J4AC_android_media_AudioTrack__getPlaybackRate(env, thiz);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\njint J4AC_android_media_AudioTrack__setPlaybackRate(JNIEnv *env, jobject thiz, jint sampleRateInHz)\n{\n    return (*env)->CallIntMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_setPlaybackRate, sampleRateInHz);\n}\n\njint J4AC_android_media_AudioTrack__setPlaybackRate__catchAll(JNIEnv *env, jobject thiz, jint sampleRateInHz)\n{\n    jint ret_value = J4AC_android_media_AudioTrack__setPlaybackRate(env, thiz, sampleRateInHz);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\nint J4A_loadClass__J4AC_android_media_AudioTrack(JNIEnv *env)\n{\n    int         ret                   = -1;\n    const char *J4A_UNUSED(name)      = NULL;\n    const char *J4A_UNUSED(sign)      = NULL;\n    jclass      J4A_UNUSED(class_id)  = NULL;\n    int         J4A_UNUSED(api_level) = 0;\n\n    if (class_J4AC_android_media_AudioTrack.id != NULL)\n        return 0;\n\n    sign = \"android/media/AudioTrack\";\n    class_J4AC_android_media_AudioTrack.id = J4A_FindClass__asGlobalRef__catchAll(env, sign);\n    if (class_J4AC_android_media_AudioTrack.id == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_AudioTrack.id;\n    name     = \"<init>\";\n    sign     = \"(IIIIII)V\";\n    class_J4AC_android_media_AudioTrack.constructor_AudioTrack = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_AudioTrack.constructor_AudioTrack == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_AudioTrack.id;\n    name     = \"getMinBufferSize\";\n    sign     = \"(III)I\";\n    class_J4AC_android_media_AudioTrack.method_getMinBufferSize = J4A_GetStaticMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_AudioTrack.method_getMinBufferSize == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_AudioTrack.id;\n    name     = \"getMaxVolume\";\n    sign     = \"()F\";\n    class_J4AC_android_media_AudioTrack.method_getMaxVolume = J4A_GetStaticMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_AudioTrack.method_getMaxVolume == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_AudioTrack.id;\n    name     = \"getMinVolume\";\n    sign     = \"()F\";\n    class_J4AC_android_media_AudioTrack.method_getMinVolume = J4A_GetStaticMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_AudioTrack.method_getMinVolume == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_AudioTrack.id;\n    name     = \"getNativeOutputSampleRate\";\n    sign     = \"(I)I\";\n    class_J4AC_android_media_AudioTrack.method_getNativeOutputSampleRate = J4A_GetStaticMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_AudioTrack.method_getNativeOutputSampleRate == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_AudioTrack.id;\n    name     = \"play\";\n    sign     = \"()V\";\n    class_J4AC_android_media_AudioTrack.method_play = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_AudioTrack.method_play == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_AudioTrack.id;\n    name     = \"pause\";\n    sign     = \"()V\";\n    class_J4AC_android_media_AudioTrack.method_pause = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_AudioTrack.method_pause == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_AudioTrack.id;\n    name     = \"stop\";\n    sign     = \"()V\";\n    class_J4AC_android_media_AudioTrack.method_stop = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_AudioTrack.method_stop == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_AudioTrack.id;\n    name     = \"flush\";\n    sign     = \"()V\";\n    class_J4AC_android_media_AudioTrack.method_flush = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_AudioTrack.method_flush == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_AudioTrack.id;\n    name     = \"release\";\n    sign     = \"()V\";\n    class_J4AC_android_media_AudioTrack.method_release = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_AudioTrack.method_release == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_AudioTrack.id;\n    name     = \"write\";\n    sign     = \"([BII)I\";\n    class_J4AC_android_media_AudioTrack.method_write = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_AudioTrack.method_write == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_AudioTrack.id;\n    name     = \"setStereoVolume\";\n    sign     = \"(FF)I\";\n    class_J4AC_android_media_AudioTrack.method_setStereoVolume = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_AudioTrack.method_setStereoVolume == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_AudioTrack.id;\n    name     = \"getAudioSessionId\";\n    sign     = \"()I\";\n    class_J4AC_android_media_AudioTrack.method_getAudioSessionId = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_AudioTrack.method_getAudioSessionId == NULL)\n        goto fail;\n\n    if (J4A_GetSystemAndroidApiLevel(env) >= 23) {\n        class_id = class_J4AC_android_media_AudioTrack.id;\n        name     = \"getPlaybackParams\";\n        sign     = \"()Landroid/media/PlaybackParams;\";\n        class_J4AC_android_media_AudioTrack.method_getPlaybackParams = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n        if (class_J4AC_android_media_AudioTrack.method_getPlaybackParams == NULL)\n            goto fail;\n    }\n\n    if (J4A_GetSystemAndroidApiLevel(env) >= 23) {\n        class_id = class_J4AC_android_media_AudioTrack.id;\n        name     = \"setPlaybackParams\";\n        sign     = \"(Landroid/media/PlaybackParams;)V\";\n        class_J4AC_android_media_AudioTrack.method_setPlaybackParams = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n        if (class_J4AC_android_media_AudioTrack.method_setPlaybackParams == NULL)\n            goto fail;\n    }\n\n    class_id = class_J4AC_android_media_AudioTrack.id;\n    name     = \"getStreamType\";\n    sign     = \"()I\";\n    class_J4AC_android_media_AudioTrack.method_getStreamType = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_AudioTrack.method_getStreamType == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_AudioTrack.id;\n    name     = \"getSampleRate\";\n    sign     = \"()I\";\n    class_J4AC_android_media_AudioTrack.method_getSampleRate = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_AudioTrack.method_getSampleRate == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_AudioTrack.id;\n    name     = \"getPlaybackRate\";\n    sign     = \"()I\";\n    class_J4AC_android_media_AudioTrack.method_getPlaybackRate = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_AudioTrack.method_getPlaybackRate == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_AudioTrack.id;\n    name     = \"setPlaybackRate\";\n    sign     = \"(I)I\";\n    class_J4AC_android_media_AudioTrack.method_setPlaybackRate = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_AudioTrack.method_setPlaybackRate == NULL)\n        goto fail;\n\n    J4A_ALOGD(\"J4ALoader: OK: '%s' loaded\\n\", \"android.media.AudioTrack\");\n    ret = 0;\nfail:\n    return ret;\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/android/media/AudioTrack.h",
    "content": "/*\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * https://github.com/Bilibili/jni4android\n * This file is automatically generated by jni4android, do not modify.\n */\n\n#ifndef J4A__android_media_AudioTrack__H\n#define J4A__android_media_AudioTrack__H\n\n#include \"j4a/j4a_base.h\"\n\njobject J4AC_android_media_AudioTrack__AudioTrack(JNIEnv *env, jint streamType, jint sampleRateInHz, jint channelConfig, jint audioFormat, jint bufferSizeInBytes, jint mode);\njobject J4AC_android_media_AudioTrack__AudioTrack__catchAll(JNIEnv *env, jint streamType, jint sampleRateInHz, jint channelConfig, jint audioFormat, jint bufferSizeInBytes, jint mode);\njobject J4AC_android_media_AudioTrack__AudioTrack__asGlobalRef__catchAll(JNIEnv *env, jint streamType, jint sampleRateInHz, jint channelConfig, jint audioFormat, jint bufferSizeInBytes, jint mode);\njint J4AC_android_media_AudioTrack__getMinBufferSize(JNIEnv *env, jint sampleRateInHz, jint channelConfig, jint audioFormat);\njint J4AC_android_media_AudioTrack__getMinBufferSize__catchAll(JNIEnv *env, jint sampleRateInHz, jint channelConfig, jint audioFormat);\njfloat J4AC_android_media_AudioTrack__getMaxVolume(JNIEnv *env);\njfloat J4AC_android_media_AudioTrack__getMaxVolume__catchAll(JNIEnv *env);\njfloat J4AC_android_media_AudioTrack__getMinVolume(JNIEnv *env);\njfloat J4AC_android_media_AudioTrack__getMinVolume__catchAll(JNIEnv *env);\njint J4AC_android_media_AudioTrack__getNativeOutputSampleRate(JNIEnv *env, jint streamType);\njint J4AC_android_media_AudioTrack__getNativeOutputSampleRate__catchAll(JNIEnv *env, jint streamType);\nvoid J4AC_android_media_AudioTrack__play(JNIEnv *env, jobject thiz);\nvoid J4AC_android_media_AudioTrack__play__catchAll(JNIEnv *env, jobject thiz);\nvoid J4AC_android_media_AudioTrack__pause(JNIEnv *env, jobject thiz);\nvoid J4AC_android_media_AudioTrack__pause__catchAll(JNIEnv *env, jobject thiz);\nvoid J4AC_android_media_AudioTrack__stop(JNIEnv *env, jobject thiz);\nvoid J4AC_android_media_AudioTrack__stop__catchAll(JNIEnv *env, jobject thiz);\nvoid J4AC_android_media_AudioTrack__flush(JNIEnv *env, jobject thiz);\nvoid J4AC_android_media_AudioTrack__flush__catchAll(JNIEnv *env, jobject thiz);\nvoid J4AC_android_media_AudioTrack__release(JNIEnv *env, jobject thiz);\nvoid J4AC_android_media_AudioTrack__release__catchAll(JNIEnv *env, jobject thiz);\njint J4AC_android_media_AudioTrack__write(JNIEnv *env, jobject thiz, jbyteArray audioData, jint offsetInBytes, jint sizeInBytes);\njint J4AC_android_media_AudioTrack__write__catchAll(JNIEnv *env, jobject thiz, jbyteArray audioData, jint offsetInBytes, jint sizeInBytes);\njint J4AC_android_media_AudioTrack__setStereoVolume(JNIEnv *env, jobject thiz, jfloat leftGain, jfloat rightGain);\njint J4AC_android_media_AudioTrack__setStereoVolume__catchAll(JNIEnv *env, jobject thiz, jfloat leftGain, jfloat rightGain);\njint J4AC_android_media_AudioTrack__getAudioSessionId(JNIEnv *env, jobject thiz);\njint J4AC_android_media_AudioTrack__getAudioSessionId__catchAll(JNIEnv *env, jobject thiz);\njobject J4AC_android_media_AudioTrack__getPlaybackParams(JNIEnv *env, jobject thiz);\njobject J4AC_android_media_AudioTrack__getPlaybackParams__catchAll(JNIEnv *env, jobject thiz);\njobject J4AC_android_media_AudioTrack__getPlaybackParams__asGlobalRef__catchAll(JNIEnv *env, jobject thiz);\nvoid J4AC_android_media_AudioTrack__setPlaybackParams(JNIEnv *env, jobject thiz, jobject params);\nvoid J4AC_android_media_AudioTrack__setPlaybackParams__catchAll(JNIEnv *env, jobject thiz, jobject params);\njint J4AC_android_media_AudioTrack__getStreamType(JNIEnv *env, jobject thiz);\njint J4AC_android_media_AudioTrack__getStreamType__catchAll(JNIEnv *env, jobject thiz);\njint J4AC_android_media_AudioTrack__getSampleRate(JNIEnv *env, jobject thiz);\njint J4AC_android_media_AudioTrack__getSampleRate__catchAll(JNIEnv *env, jobject thiz);\njint J4AC_android_media_AudioTrack__getPlaybackRate(JNIEnv *env, jobject thiz);\njint J4AC_android_media_AudioTrack__getPlaybackRate__catchAll(JNIEnv *env, jobject thiz);\njint J4AC_android_media_AudioTrack__setPlaybackRate(JNIEnv *env, jobject thiz, jint sampleRateInHz);\njint J4AC_android_media_AudioTrack__setPlaybackRate__catchAll(JNIEnv *env, jobject thiz, jint sampleRateInHz);\nint J4A_loadClass__J4AC_android_media_AudioTrack(JNIEnv *env);\n\n#define J4A_HAVE_SIMPLE__J4AC_android_media_AudioTrack\n\n#define J4AC_AudioTrack__AudioTrack J4AC_android_media_AudioTrack__AudioTrack\n#define J4AC_AudioTrack__AudioTrack__asGlobalRef__catchAll J4AC_android_media_AudioTrack__AudioTrack__asGlobalRef__catchAll\n#define J4AC_AudioTrack__AudioTrack__catchAll J4AC_android_media_AudioTrack__AudioTrack__catchAll\n#define J4AC_AudioTrack__getMinBufferSize J4AC_android_media_AudioTrack__getMinBufferSize\n#define J4AC_AudioTrack__getMinBufferSize__catchAll J4AC_android_media_AudioTrack__getMinBufferSize__catchAll\n#define J4AC_AudioTrack__getMaxVolume J4AC_android_media_AudioTrack__getMaxVolume\n#define J4AC_AudioTrack__getMaxVolume__catchAll J4AC_android_media_AudioTrack__getMaxVolume__catchAll\n#define J4AC_AudioTrack__getMinVolume J4AC_android_media_AudioTrack__getMinVolume\n#define J4AC_AudioTrack__getMinVolume__catchAll J4AC_android_media_AudioTrack__getMinVolume__catchAll\n#define J4AC_AudioTrack__getNativeOutputSampleRate J4AC_android_media_AudioTrack__getNativeOutputSampleRate\n#define J4AC_AudioTrack__getNativeOutputSampleRate__catchAll J4AC_android_media_AudioTrack__getNativeOutputSampleRate__catchAll\n#define J4AC_AudioTrack__play J4AC_android_media_AudioTrack__play\n#define J4AC_AudioTrack__play__catchAll J4AC_android_media_AudioTrack__play__catchAll\n#define J4AC_AudioTrack__pause J4AC_android_media_AudioTrack__pause\n#define J4AC_AudioTrack__pause__catchAll J4AC_android_media_AudioTrack__pause__catchAll\n#define J4AC_AudioTrack__stop J4AC_android_media_AudioTrack__stop\n#define J4AC_AudioTrack__stop__catchAll J4AC_android_media_AudioTrack__stop__catchAll\n#define J4AC_AudioTrack__flush J4AC_android_media_AudioTrack__flush\n#define J4AC_AudioTrack__flush__catchAll J4AC_android_media_AudioTrack__flush__catchAll\n#define J4AC_AudioTrack__release J4AC_android_media_AudioTrack__release\n#define J4AC_AudioTrack__release__catchAll J4AC_android_media_AudioTrack__release__catchAll\n#define J4AC_AudioTrack__write J4AC_android_media_AudioTrack__write\n#define J4AC_AudioTrack__write__catchAll J4AC_android_media_AudioTrack__write__catchAll\n#define J4AC_AudioTrack__setStereoVolume J4AC_android_media_AudioTrack__setStereoVolume\n#define J4AC_AudioTrack__setStereoVolume__catchAll J4AC_android_media_AudioTrack__setStereoVolume__catchAll\n#define J4AC_AudioTrack__getAudioSessionId J4AC_android_media_AudioTrack__getAudioSessionId\n#define J4AC_AudioTrack__getAudioSessionId__catchAll J4AC_android_media_AudioTrack__getAudioSessionId__catchAll\n#define J4AC_AudioTrack__getPlaybackParams J4AC_android_media_AudioTrack__getPlaybackParams\n#define J4AC_AudioTrack__getPlaybackParams__asGlobalRef__catchAll J4AC_android_media_AudioTrack__getPlaybackParams__asGlobalRef__catchAll\n#define J4AC_AudioTrack__getPlaybackParams__catchAll J4AC_android_media_AudioTrack__getPlaybackParams__catchAll\n#define J4AC_AudioTrack__setPlaybackParams J4AC_android_media_AudioTrack__setPlaybackParams\n#define J4AC_AudioTrack__setPlaybackParams__catchAll J4AC_android_media_AudioTrack__setPlaybackParams__catchAll\n#define J4AC_AudioTrack__getStreamType J4AC_android_media_AudioTrack__getStreamType\n#define J4AC_AudioTrack__getStreamType__catchAll J4AC_android_media_AudioTrack__getStreamType__catchAll\n#define J4AC_AudioTrack__getSampleRate J4AC_android_media_AudioTrack__getSampleRate\n#define J4AC_AudioTrack__getSampleRate__catchAll J4AC_android_media_AudioTrack__getSampleRate__catchAll\n#define J4AC_AudioTrack__getPlaybackRate J4AC_android_media_AudioTrack__getPlaybackRate\n#define J4AC_AudioTrack__getPlaybackRate__catchAll J4AC_android_media_AudioTrack__getPlaybackRate__catchAll\n#define J4AC_AudioTrack__setPlaybackRate J4AC_android_media_AudioTrack__setPlaybackRate\n#define J4AC_AudioTrack__setPlaybackRate__catchAll J4AC_android_media_AudioTrack__setPlaybackRate__catchAll\n#define J4A_loadClass__J4AC_AudioTrack J4A_loadClass__J4AC_android_media_AudioTrack\n\n#endif//J4A__android_media_AudioTrack__H\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/android/media/AudioTrack.include.j4a",
    "content": "#include \"j4a/class/android/media/AudioTrack.h\""
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/android/media/AudioTrack.loader.j4a",
    "content": "    J4A_LOAD_CLASS(android_media_AudioTrack);"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/android/media/MediaCodec.c",
    "content": "/*\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * https://github.com/Bilibili/jni4android\n * This file is automatically generated by jni4android, do not modify.\n */\n\n#include \"MediaCodec.h\"\n\ntypedef struct J4AC_android_media_MediaCodec__BufferInfo {\n    jclass id;\n\n    jfieldID field_flags;\n    jfieldID field_offset;\n    jfieldID field_presentationTimeUs;\n    jfieldID field_size;\n    jmethodID constructor_BufferInfo;\n} J4AC_android_media_MediaCodec__BufferInfo;\nstatic J4AC_android_media_MediaCodec__BufferInfo class_J4AC_android_media_MediaCodec__BufferInfo;\n\ntypedef struct J4AC_android_media_MediaCodec {\n    jclass id;\n\n    jmethodID method_createByCodecName;\n    jmethodID method_configure;\n    jmethodID method_getOutputFormat;\n    jmethodID method_getInputBuffers;\n    jmethodID method_dequeueInputBuffer;\n    jmethodID method_queueInputBuffer;\n    jmethodID method_dequeueOutputBuffer;\n    jmethodID method_releaseOutputBuffer;\n    jmethodID method_start;\n    jmethodID method_stop;\n    jmethodID method_flush;\n    jmethodID method_release;\n} J4AC_android_media_MediaCodec;\nstatic J4AC_android_media_MediaCodec class_J4AC_android_media_MediaCodec;\n\njint J4AC_android_media_MediaCodec__BufferInfo__flags__get(JNIEnv *env, jobject thiz)\n{\n    return (*env)->GetIntField(env, thiz, class_J4AC_android_media_MediaCodec__BufferInfo.field_flags);\n}\n\njint J4AC_android_media_MediaCodec__BufferInfo__flags__get__catchAll(JNIEnv *env, jobject thiz)\n{\n    jint ret_value = J4AC_android_media_MediaCodec__BufferInfo__flags__get(env, thiz);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\nvoid J4AC_android_media_MediaCodec__BufferInfo__flags__set(JNIEnv *env, jobject thiz, jint value)\n{\n    (*env)->SetIntField(env, thiz, class_J4AC_android_media_MediaCodec__BufferInfo.field_flags, value);\n}\n\nvoid J4AC_android_media_MediaCodec__BufferInfo__flags__set__catchAll(JNIEnv *env, jobject thiz, jint value)\n{\n    J4AC_android_media_MediaCodec__BufferInfo__flags__set(env, thiz, value);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\njint J4AC_android_media_MediaCodec__BufferInfo__offset__get(JNIEnv *env, jobject thiz)\n{\n    return (*env)->GetIntField(env, thiz, class_J4AC_android_media_MediaCodec__BufferInfo.field_offset);\n}\n\njint J4AC_android_media_MediaCodec__BufferInfo__offset__get__catchAll(JNIEnv *env, jobject thiz)\n{\n    jint ret_value = J4AC_android_media_MediaCodec__BufferInfo__offset__get(env, thiz);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\nvoid J4AC_android_media_MediaCodec__BufferInfo__offset__set(JNIEnv *env, jobject thiz, jint value)\n{\n    (*env)->SetIntField(env, thiz, class_J4AC_android_media_MediaCodec__BufferInfo.field_offset, value);\n}\n\nvoid J4AC_android_media_MediaCodec__BufferInfo__offset__set__catchAll(JNIEnv *env, jobject thiz, jint value)\n{\n    J4AC_android_media_MediaCodec__BufferInfo__offset__set(env, thiz, value);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\njlong J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__get(JNIEnv *env, jobject thiz)\n{\n    return (*env)->GetLongField(env, thiz, class_J4AC_android_media_MediaCodec__BufferInfo.field_presentationTimeUs);\n}\n\njlong J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__get__catchAll(JNIEnv *env, jobject thiz)\n{\n    jlong ret_value = J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__get(env, thiz);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\nvoid J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__set(JNIEnv *env, jobject thiz, jlong value)\n{\n    (*env)->SetLongField(env, thiz, class_J4AC_android_media_MediaCodec__BufferInfo.field_presentationTimeUs, value);\n}\n\nvoid J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__set__catchAll(JNIEnv *env, jobject thiz, jlong value)\n{\n    J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__set(env, thiz, value);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\njint J4AC_android_media_MediaCodec__BufferInfo__size__get(JNIEnv *env, jobject thiz)\n{\n    return (*env)->GetIntField(env, thiz, class_J4AC_android_media_MediaCodec__BufferInfo.field_size);\n}\n\njint J4AC_android_media_MediaCodec__BufferInfo__size__get__catchAll(JNIEnv *env, jobject thiz)\n{\n    jint ret_value = J4AC_android_media_MediaCodec__BufferInfo__size__get(env, thiz);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\nvoid J4AC_android_media_MediaCodec__BufferInfo__size__set(JNIEnv *env, jobject thiz, jint value)\n{\n    (*env)->SetIntField(env, thiz, class_J4AC_android_media_MediaCodec__BufferInfo.field_size, value);\n}\n\nvoid J4AC_android_media_MediaCodec__BufferInfo__size__set__catchAll(JNIEnv *env, jobject thiz, jint value)\n{\n    J4AC_android_media_MediaCodec__BufferInfo__size__set(env, thiz, value);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\njobject J4AC_android_media_MediaCodec__BufferInfo__BufferInfo(JNIEnv *env)\n{\n    return (*env)->NewObject(env, class_J4AC_android_media_MediaCodec__BufferInfo.id, class_J4AC_android_media_MediaCodec__BufferInfo.constructor_BufferInfo);\n}\n\njobject J4AC_android_media_MediaCodec__BufferInfo__BufferInfo__catchAll(JNIEnv *env)\n{\n    jobject ret_object = J4AC_android_media_MediaCodec__BufferInfo__BufferInfo(env);\n    if (J4A_ExceptionCheck__catchAll(env) || !ret_object) {\n        return NULL;\n    }\n\n    return ret_object;\n}\n\njobject J4AC_android_media_MediaCodec__BufferInfo__BufferInfo__asGlobalRef__catchAll(JNIEnv *env)\n{\n    jobject ret_object   = NULL;\n    jobject local_object = J4AC_android_media_MediaCodec__BufferInfo__BufferInfo__catchAll(env);\n    if (J4A_ExceptionCheck__catchAll(env) || !local_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\n    ret_object = J4A_NewGlobalRef__catchAll(env, local_object);\n    if (!ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &local_object);\n    return ret_object;\n}\n\nint J4A_loadClass__J4AC_android_media_MediaCodec__BufferInfo(JNIEnv *env)\n{\n    int         ret                   = -1;\n    const char *J4A_UNUSED(name)      = NULL;\n    const char *J4A_UNUSED(sign)      = NULL;\n    jclass      J4A_UNUSED(class_id)  = NULL;\n    int         J4A_UNUSED(api_level) = 0;\n\n    if (class_J4AC_android_media_MediaCodec__BufferInfo.id != NULL)\n        return 0;\n\n    sign = \"android/media/MediaCodec$BufferInfo\";\n    class_J4AC_android_media_MediaCodec__BufferInfo.id = J4A_FindClass__asGlobalRef__catchAll(env, sign);\n    if (class_J4AC_android_media_MediaCodec__BufferInfo.id == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_MediaCodec__BufferInfo.id;\n    name     = \"flags\";\n    sign     = \"I\";\n    class_J4AC_android_media_MediaCodec__BufferInfo.field_flags = J4A_GetFieldID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_MediaCodec__BufferInfo.field_flags == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_MediaCodec__BufferInfo.id;\n    name     = \"offset\";\n    sign     = \"I\";\n    class_J4AC_android_media_MediaCodec__BufferInfo.field_offset = J4A_GetFieldID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_MediaCodec__BufferInfo.field_offset == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_MediaCodec__BufferInfo.id;\n    name     = \"presentationTimeUs\";\n    sign     = \"J\";\n    class_J4AC_android_media_MediaCodec__BufferInfo.field_presentationTimeUs = J4A_GetFieldID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_MediaCodec__BufferInfo.field_presentationTimeUs == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_MediaCodec__BufferInfo.id;\n    name     = \"size\";\n    sign     = \"I\";\n    class_J4AC_android_media_MediaCodec__BufferInfo.field_size = J4A_GetFieldID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_MediaCodec__BufferInfo.field_size == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_MediaCodec__BufferInfo.id;\n    name     = \"<init>\";\n    sign     = \"()V\";\n    class_J4AC_android_media_MediaCodec__BufferInfo.constructor_BufferInfo = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_MediaCodec__BufferInfo.constructor_BufferInfo == NULL)\n        goto fail;\n\n    J4A_ALOGD(\"J4ALoader: OK: '%s' loaded\\n\", \"android.media.MediaCodec$BufferInfo\");\n    ret = 0;\nfail:\n    return ret;\n}\n\njobject J4AC_android_media_MediaCodec__createByCodecName(JNIEnv *env, jstring name)\n{\n    return (*env)->CallStaticObjectMethod(env, class_J4AC_android_media_MediaCodec.id, class_J4AC_android_media_MediaCodec.method_createByCodecName, name);\n}\n\njobject J4AC_android_media_MediaCodec__createByCodecName__catchAll(JNIEnv *env, jstring name)\n{\n    jobject ret_object = J4AC_android_media_MediaCodec__createByCodecName(env, name);\n    if (J4A_ExceptionCheck__catchAll(env) || !ret_object) {\n        return NULL;\n    }\n\n    return ret_object;\n}\n\njobject J4AC_android_media_MediaCodec__createByCodecName__asGlobalRef__catchAll(JNIEnv *env, jstring name)\n{\n    jobject ret_object   = NULL;\n    jobject local_object = J4AC_android_media_MediaCodec__createByCodecName__catchAll(env, name);\n    if (J4A_ExceptionCheck__catchAll(env) || !local_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\n    ret_object = J4A_NewGlobalRef__catchAll(env, local_object);\n    if (!ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &local_object);\n    return ret_object;\n}\n\njobject J4AC_android_media_MediaCodec__createByCodecName__withCString(JNIEnv *env, const char *name_cstr__)\n{\n    jobject ret_object = NULL;\n    jstring name = NULL;\n\n    name = (*env)->NewStringUTF(env, name_cstr__);\n    if (J4A_ExceptionCheck__throwAny(env) || !name)\n        goto fail;\n\n    ret_object = J4AC_android_media_MediaCodec__createByCodecName(env, name);\n    if (J4A_ExceptionCheck__throwAny(env) || !ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &name);\n    return ret_object;\n}\n\njobject J4AC_android_media_MediaCodec__createByCodecName__withCString__catchAll(JNIEnv *env, const char *name_cstr__)\n{\n    jobject ret_object = NULL;\n    jstring name = NULL;\n\n    name = (*env)->NewStringUTF(env, name_cstr__);\n    if (J4A_ExceptionCheck__catchAll(env) || !name)\n        goto fail;\n\n    ret_object = J4AC_android_media_MediaCodec__createByCodecName__catchAll(env, name);\n    if (J4A_ExceptionCheck__catchAll(env) || !ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &name);\n    return ret_object;\n}\n\njobject J4AC_android_media_MediaCodec__createByCodecName__withCString__asGlobalRef__catchAll(JNIEnv *env, const char *name_cstr__)\n{\n    jobject ret_object   = NULL;\n    jobject local_object = J4AC_android_media_MediaCodec__createByCodecName__withCString__catchAll(env, name_cstr__);\n    if (J4A_ExceptionCheck__catchAll(env) || !local_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\n    ret_object = J4A_NewGlobalRef__catchAll(env, local_object);\n    if (!ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &local_object);\n    return ret_object;\n}\n\nvoid J4AC_android_media_MediaCodec__configure(JNIEnv *env, jobject thiz, jobject format, jobject surface, jobject crypto, jint flags)\n{\n    (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_MediaCodec.method_configure, format, surface, crypto, flags);\n}\n\nvoid J4AC_android_media_MediaCodec__configure__catchAll(JNIEnv *env, jobject thiz, jobject format, jobject surface, jobject crypto, jint flags)\n{\n    J4AC_android_media_MediaCodec__configure(env, thiz, format, surface, crypto, flags);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\njobject J4AC_android_media_MediaCodec__getOutputFormat(JNIEnv *env, jobject thiz)\n{\n    return (*env)->CallObjectMethod(env, thiz, class_J4AC_android_media_MediaCodec.method_getOutputFormat);\n}\n\njobject J4AC_android_media_MediaCodec__getOutputFormat__catchAll(JNIEnv *env, jobject thiz)\n{\n    jobject ret_object = J4AC_android_media_MediaCodec__getOutputFormat(env, thiz);\n    if (J4A_ExceptionCheck__catchAll(env) || !ret_object) {\n        return NULL;\n    }\n\n    return ret_object;\n}\n\njobject J4AC_android_media_MediaCodec__getOutputFormat__asGlobalRef__catchAll(JNIEnv *env, jobject thiz)\n{\n    jobject ret_object   = NULL;\n    jobject local_object = J4AC_android_media_MediaCodec__getOutputFormat__catchAll(env, thiz);\n    if (J4A_ExceptionCheck__catchAll(env) || !local_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\n    ret_object = J4A_NewGlobalRef__catchAll(env, local_object);\n    if (!ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &local_object);\n    return ret_object;\n}\n\njobjectArray J4AC_android_media_MediaCodec__getInputBuffers(JNIEnv *env, jobject thiz)\n{\n    return (*env)->CallObjectMethod(env, thiz, class_J4AC_android_media_MediaCodec.method_getInputBuffers);\n}\n\njobjectArray J4AC_android_media_MediaCodec__getInputBuffers__catchAll(JNIEnv *env, jobject thiz)\n{\n    jobjectArray ret_object = J4AC_android_media_MediaCodec__getInputBuffers(env, thiz);\n    if (J4A_ExceptionCheck__catchAll(env) || !ret_object) {\n        return NULL;\n    }\n\n    return ret_object;\n}\n\njobjectArray J4AC_android_media_MediaCodec__getInputBuffers__asGlobalRef__catchAll(JNIEnv *env, jobject thiz)\n{\n    jobjectArray ret_object   = NULL;\n    jobjectArray local_object = J4AC_android_media_MediaCodec__getInputBuffers__catchAll(env, thiz);\n    if (J4A_ExceptionCheck__catchAll(env) || !local_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\n    ret_object = J4A_NewGlobalRef__catchAll(env, local_object);\n    if (!ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &local_object);\n    return ret_object;\n}\n\njint J4AC_android_media_MediaCodec__dequeueInputBuffer(JNIEnv *env, jobject thiz, jlong timeoutUs)\n{\n    return (*env)->CallIntMethod(env, thiz, class_J4AC_android_media_MediaCodec.method_dequeueInputBuffer, timeoutUs);\n}\n\njint J4AC_android_media_MediaCodec__dequeueInputBuffer__catchAll(JNIEnv *env, jobject thiz, jlong timeoutUs)\n{\n    jint ret_value = J4AC_android_media_MediaCodec__dequeueInputBuffer(env, thiz, timeoutUs);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\nvoid J4AC_android_media_MediaCodec__queueInputBuffer(JNIEnv *env, jobject thiz, jint index, jint offset, jint size, jlong presentationTimeUs, jint flags)\n{\n    (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_MediaCodec.method_queueInputBuffer, index, offset, size, presentationTimeUs, flags);\n}\n\nvoid J4AC_android_media_MediaCodec__queueInputBuffer__catchAll(JNIEnv *env, jobject thiz, jint index, jint offset, jint size, jlong presentationTimeUs, jint flags)\n{\n    J4AC_android_media_MediaCodec__queueInputBuffer(env, thiz, index, offset, size, presentationTimeUs, flags);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\njint J4AC_android_media_MediaCodec__dequeueOutputBuffer(JNIEnv *env, jobject thiz, jobject info, jlong timeoutUs)\n{\n    return (*env)->CallIntMethod(env, thiz, class_J4AC_android_media_MediaCodec.method_dequeueOutputBuffer, info, timeoutUs);\n}\n\njint J4AC_android_media_MediaCodec__dequeueOutputBuffer__catchAll(JNIEnv *env, jobject thiz, jobject info, jlong timeoutUs)\n{\n    jint ret_value = J4AC_android_media_MediaCodec__dequeueOutputBuffer(env, thiz, info, timeoutUs);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\nvoid J4AC_android_media_MediaCodec__releaseOutputBuffer(JNIEnv *env, jobject thiz, jint index, jboolean render)\n{\n    (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_MediaCodec.method_releaseOutputBuffer, index, render);\n}\n\nvoid J4AC_android_media_MediaCodec__releaseOutputBuffer__catchAll(JNIEnv *env, jobject thiz, jint index, jboolean render)\n{\n    J4AC_android_media_MediaCodec__releaseOutputBuffer(env, thiz, index, render);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\nvoid J4AC_android_media_MediaCodec__start(JNIEnv *env, jobject thiz)\n{\n    (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_MediaCodec.method_start);\n}\n\nvoid J4AC_android_media_MediaCodec__start__catchAll(JNIEnv *env, jobject thiz)\n{\n    J4AC_android_media_MediaCodec__start(env, thiz);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\nvoid J4AC_android_media_MediaCodec__stop(JNIEnv *env, jobject thiz)\n{\n    (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_MediaCodec.method_stop);\n}\n\nvoid J4AC_android_media_MediaCodec__stop__catchAll(JNIEnv *env, jobject thiz)\n{\n    J4AC_android_media_MediaCodec__stop(env, thiz);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\nvoid J4AC_android_media_MediaCodec__flush(JNIEnv *env, jobject thiz)\n{\n    (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_MediaCodec.method_flush);\n}\n\nvoid J4AC_android_media_MediaCodec__flush__catchAll(JNIEnv *env, jobject thiz)\n{\n    J4AC_android_media_MediaCodec__flush(env, thiz);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\nvoid J4AC_android_media_MediaCodec__release(JNIEnv *env, jobject thiz)\n{\n    (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_MediaCodec.method_release);\n}\n\nvoid J4AC_android_media_MediaCodec__release__catchAll(JNIEnv *env, jobject thiz)\n{\n    J4AC_android_media_MediaCodec__release(env, thiz);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\nint J4A_loadClass__J4AC_android_media_MediaCodec(JNIEnv *env)\n{\n    int         ret                   = -1;\n    const char *J4A_UNUSED(name)      = NULL;\n    const char *J4A_UNUSED(sign)      = NULL;\n    jclass      J4A_UNUSED(class_id)  = NULL;\n    int         J4A_UNUSED(api_level) = 0;\n\n    if (class_J4AC_android_media_MediaCodec.id != NULL)\n        return 0;\n\n    api_level = J4A_GetSystemAndroidApiLevel(env);\n\n    if (api_level < 16) {\n        J4A_ALOGW(\"J4ALoader: Ignore: '%s' need API %d\\n\", \"android.media.MediaCodec\", api_level);\n        goto ignore;\n    }\n\n    sign = \"android/media/MediaCodec\";\n    class_J4AC_android_media_MediaCodec.id = J4A_FindClass__asGlobalRef__catchAll(env, sign);\n    if (class_J4AC_android_media_MediaCodec.id == NULL)\n        goto fail;\n\n    ret = J4A_loadClass__J4AC_android_media_MediaCodec__BufferInfo(env);\n    if (ret)\n        goto fail;\n\n    class_id = class_J4AC_android_media_MediaCodec.id;\n    name     = \"createByCodecName\";\n    sign     = \"(Ljava/lang/String;)Landroid/media/MediaCodec;\";\n    class_J4AC_android_media_MediaCodec.method_createByCodecName = J4A_GetStaticMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_MediaCodec.method_createByCodecName == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_MediaCodec.id;\n    name     = \"configure\";\n    sign     = \"(Landroid/media/MediaFormat;Landroid/view/Surface;Landroid/media/MediaCrypto;I)V\";\n    class_J4AC_android_media_MediaCodec.method_configure = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_MediaCodec.method_configure == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_MediaCodec.id;\n    name     = \"getOutputFormat\";\n    sign     = \"()Landroid/media/MediaFormat;\";\n    class_J4AC_android_media_MediaCodec.method_getOutputFormat = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_MediaCodec.method_getOutputFormat == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_MediaCodec.id;\n    name     = \"getInputBuffers\";\n    sign     = \"()[Ljava/nio/ByteBuffer;\";\n    class_J4AC_android_media_MediaCodec.method_getInputBuffers = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_MediaCodec.method_getInputBuffers == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_MediaCodec.id;\n    name     = \"dequeueInputBuffer\";\n    sign     = \"(J)I\";\n    class_J4AC_android_media_MediaCodec.method_dequeueInputBuffer = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_MediaCodec.method_dequeueInputBuffer == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_MediaCodec.id;\n    name     = \"queueInputBuffer\";\n    sign     = \"(IIIJI)V\";\n    class_J4AC_android_media_MediaCodec.method_queueInputBuffer = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_MediaCodec.method_queueInputBuffer == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_MediaCodec.id;\n    name     = \"dequeueOutputBuffer\";\n    sign     = \"(Landroid/media/MediaCodec$BufferInfo;J)I\";\n    class_J4AC_android_media_MediaCodec.method_dequeueOutputBuffer = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_MediaCodec.method_dequeueOutputBuffer == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_MediaCodec.id;\n    name     = \"releaseOutputBuffer\";\n    sign     = \"(IZ)V\";\n    class_J4AC_android_media_MediaCodec.method_releaseOutputBuffer = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_MediaCodec.method_releaseOutputBuffer == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_MediaCodec.id;\n    name     = \"start\";\n    sign     = \"()V\";\n    class_J4AC_android_media_MediaCodec.method_start = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_MediaCodec.method_start == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_MediaCodec.id;\n    name     = \"stop\";\n    sign     = \"()V\";\n    class_J4AC_android_media_MediaCodec.method_stop = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_MediaCodec.method_stop == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_MediaCodec.id;\n    name     = \"flush\";\n    sign     = \"()V\";\n    class_J4AC_android_media_MediaCodec.method_flush = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_MediaCodec.method_flush == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_MediaCodec.id;\n    name     = \"release\";\n    sign     = \"()V\";\n    class_J4AC_android_media_MediaCodec.method_release = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_MediaCodec.method_release == NULL)\n        goto fail;\n\n    J4A_ALOGD(\"J4ALoader: OK: '%s' loaded\\n\", \"android.media.MediaCodec\");\nignore:\n    ret = 0;\nfail:\n    return ret;\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/android/media/MediaCodec.h",
    "content": "/*\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * https://github.com/Bilibili/jni4android\n * This file is automatically generated by jni4android, do not modify.\n */\n\n#ifndef J4A__android_media_MediaCodec__H\n#define J4A__android_media_MediaCodec__H\n\n#include \"j4a/j4a_base.h\"\n\njint J4AC_android_media_MediaCodec__BufferInfo__flags__get(JNIEnv *env, jobject thiz);\njint J4AC_android_media_MediaCodec__BufferInfo__flags__get__catchAll(JNIEnv *env, jobject thiz);\nvoid J4AC_android_media_MediaCodec__BufferInfo__flags__set(JNIEnv *env, jobject thiz, jint value);\nvoid J4AC_android_media_MediaCodec__BufferInfo__flags__set__catchAll(JNIEnv *env, jobject thiz, jint value);\njint J4AC_android_media_MediaCodec__BufferInfo__offset__get(JNIEnv *env, jobject thiz);\njint J4AC_android_media_MediaCodec__BufferInfo__offset__get__catchAll(JNIEnv *env, jobject thiz);\nvoid J4AC_android_media_MediaCodec__BufferInfo__offset__set(JNIEnv *env, jobject thiz, jint value);\nvoid J4AC_android_media_MediaCodec__BufferInfo__offset__set__catchAll(JNIEnv *env, jobject thiz, jint value);\njlong J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__get(JNIEnv *env, jobject thiz);\njlong J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__get__catchAll(JNIEnv *env, jobject thiz);\nvoid J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__set(JNIEnv *env, jobject thiz, jlong value);\nvoid J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__set__catchAll(JNIEnv *env, jobject thiz, jlong value);\njint J4AC_android_media_MediaCodec__BufferInfo__size__get(JNIEnv *env, jobject thiz);\njint J4AC_android_media_MediaCodec__BufferInfo__size__get__catchAll(JNIEnv *env, jobject thiz);\nvoid J4AC_android_media_MediaCodec__BufferInfo__size__set(JNIEnv *env, jobject thiz, jint value);\nvoid J4AC_android_media_MediaCodec__BufferInfo__size__set__catchAll(JNIEnv *env, jobject thiz, jint value);\njobject J4AC_android_media_MediaCodec__BufferInfo__BufferInfo(JNIEnv *env);\njobject J4AC_android_media_MediaCodec__BufferInfo__BufferInfo__catchAll(JNIEnv *env);\njobject J4AC_android_media_MediaCodec__BufferInfo__BufferInfo__asGlobalRef__catchAll(JNIEnv *env);\njobject J4AC_android_media_MediaCodec__createByCodecName(JNIEnv *env, jstring name);\njobject J4AC_android_media_MediaCodec__createByCodecName__catchAll(JNIEnv *env, jstring name);\njobject J4AC_android_media_MediaCodec__createByCodecName__asGlobalRef__catchAll(JNIEnv *env, jstring name);\njobject J4AC_android_media_MediaCodec__createByCodecName__withCString(JNIEnv *env, const char *name_cstr__);\njobject J4AC_android_media_MediaCodec__createByCodecName__withCString__catchAll(JNIEnv *env, const char *name_cstr__);\njobject J4AC_android_media_MediaCodec__createByCodecName__withCString__asGlobalRef__catchAll(JNIEnv *env, const char *name_cstr__);\nvoid J4AC_android_media_MediaCodec__configure(JNIEnv *env, jobject thiz, jobject format, jobject surface, jobject crypto, jint flags);\nvoid J4AC_android_media_MediaCodec__configure__catchAll(JNIEnv *env, jobject thiz, jobject format, jobject surface, jobject crypto, jint flags);\njobject J4AC_android_media_MediaCodec__getOutputFormat(JNIEnv *env, jobject thiz);\njobject J4AC_android_media_MediaCodec__getOutputFormat__catchAll(JNIEnv *env, jobject thiz);\njobject J4AC_android_media_MediaCodec__getOutputFormat__asGlobalRef__catchAll(JNIEnv *env, jobject thiz);\njobjectArray J4AC_android_media_MediaCodec__getInputBuffers(JNIEnv *env, jobject thiz);\njobjectArray J4AC_android_media_MediaCodec__getInputBuffers__catchAll(JNIEnv *env, jobject thiz);\njobjectArray J4AC_android_media_MediaCodec__getInputBuffers__asGlobalRef__catchAll(JNIEnv *env, jobject thiz);\njint J4AC_android_media_MediaCodec__dequeueInputBuffer(JNIEnv *env, jobject thiz, jlong timeoutUs);\njint J4AC_android_media_MediaCodec__dequeueInputBuffer__catchAll(JNIEnv *env, jobject thiz, jlong timeoutUs);\nvoid J4AC_android_media_MediaCodec__queueInputBuffer(JNIEnv *env, jobject thiz, jint index, jint offset, jint size, jlong presentationTimeUs, jint flags);\nvoid J4AC_android_media_MediaCodec__queueInputBuffer__catchAll(JNIEnv *env, jobject thiz, jint index, jint offset, jint size, jlong presentationTimeUs, jint flags);\njint J4AC_android_media_MediaCodec__dequeueOutputBuffer(JNIEnv *env, jobject thiz, jobject info, jlong timeoutUs);\njint J4AC_android_media_MediaCodec__dequeueOutputBuffer__catchAll(JNIEnv *env, jobject thiz, jobject info, jlong timeoutUs);\nvoid J4AC_android_media_MediaCodec__releaseOutputBuffer(JNIEnv *env, jobject thiz, jint index, jboolean render);\nvoid J4AC_android_media_MediaCodec__releaseOutputBuffer__catchAll(JNIEnv *env, jobject thiz, jint index, jboolean render);\nvoid J4AC_android_media_MediaCodec__start(JNIEnv *env, jobject thiz);\nvoid J4AC_android_media_MediaCodec__start__catchAll(JNIEnv *env, jobject thiz);\nvoid J4AC_android_media_MediaCodec__stop(JNIEnv *env, jobject thiz);\nvoid J4AC_android_media_MediaCodec__stop__catchAll(JNIEnv *env, jobject thiz);\nvoid J4AC_android_media_MediaCodec__flush(JNIEnv *env, jobject thiz);\nvoid J4AC_android_media_MediaCodec__flush__catchAll(JNIEnv *env, jobject thiz);\nvoid J4AC_android_media_MediaCodec__release(JNIEnv *env, jobject thiz);\nvoid J4AC_android_media_MediaCodec__release__catchAll(JNIEnv *env, jobject thiz);\nint J4A_loadClass__J4AC_android_media_MediaCodec(JNIEnv *env);\n\n#define J4A_HAVE_SIMPLE__J4AC_android_media_MediaCodec\n\n#define J4AC_MediaCodec__BufferInfo__flags__get J4AC_android_media_MediaCodec__BufferInfo__flags__get\n#define J4AC_MediaCodec__BufferInfo__flags__get__catchAll J4AC_android_media_MediaCodec__BufferInfo__flags__get__catchAll\n#define J4AC_MediaCodec__BufferInfo__flags__set J4AC_android_media_MediaCodec__BufferInfo__flags__set\n#define J4AC_MediaCodec__BufferInfo__flags__set__catchAll J4AC_android_media_MediaCodec__BufferInfo__flags__set__catchAll\n#define J4AC_MediaCodec__BufferInfo__offset__get J4AC_android_media_MediaCodec__BufferInfo__offset__get\n#define J4AC_MediaCodec__BufferInfo__offset__get__catchAll J4AC_android_media_MediaCodec__BufferInfo__offset__get__catchAll\n#define J4AC_MediaCodec__BufferInfo__offset__set J4AC_android_media_MediaCodec__BufferInfo__offset__set\n#define J4AC_MediaCodec__BufferInfo__offset__set__catchAll J4AC_android_media_MediaCodec__BufferInfo__offset__set__catchAll\n#define J4AC_MediaCodec__BufferInfo__presentationTimeUs__get J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__get\n#define J4AC_MediaCodec__BufferInfo__presentationTimeUs__get__catchAll J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__get__catchAll\n#define J4AC_MediaCodec__BufferInfo__presentationTimeUs__set J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__set\n#define J4AC_MediaCodec__BufferInfo__presentationTimeUs__set__catchAll J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__set__catchAll\n#define J4AC_MediaCodec__BufferInfo__size__get J4AC_android_media_MediaCodec__BufferInfo__size__get\n#define J4AC_MediaCodec__BufferInfo__size__get__catchAll J4AC_android_media_MediaCodec__BufferInfo__size__get__catchAll\n#define J4AC_MediaCodec__BufferInfo__size__set J4AC_android_media_MediaCodec__BufferInfo__size__set\n#define J4AC_MediaCodec__BufferInfo__size__set__catchAll J4AC_android_media_MediaCodec__BufferInfo__size__set__catchAll\n#define J4AC_MediaCodec__BufferInfo__BufferInfo J4AC_android_media_MediaCodec__BufferInfo__BufferInfo\n#define J4AC_MediaCodec__BufferInfo__BufferInfo__asGlobalRef__catchAll J4AC_android_media_MediaCodec__BufferInfo__BufferInfo__asGlobalRef__catchAll\n#define J4AC_MediaCodec__BufferInfo__BufferInfo__catchAll J4AC_android_media_MediaCodec__BufferInfo__BufferInfo__catchAll\n#define J4AC_MediaCodec__createByCodecName J4AC_android_media_MediaCodec__createByCodecName\n#define J4AC_MediaCodec__createByCodecName__asGlobalRef__catchAll J4AC_android_media_MediaCodec__createByCodecName__asGlobalRef__catchAll\n#define J4AC_MediaCodec__createByCodecName__catchAll J4AC_android_media_MediaCodec__createByCodecName__catchAll\n#define J4AC_MediaCodec__createByCodecName__withCString J4AC_android_media_MediaCodec__createByCodecName__withCString\n#define J4AC_MediaCodec__createByCodecName__withCString__asGlobalRef__catchAll J4AC_android_media_MediaCodec__createByCodecName__withCString__asGlobalRef__catchAll\n#define J4AC_MediaCodec__createByCodecName__withCString__catchAll J4AC_android_media_MediaCodec__createByCodecName__withCString__catchAll\n#define J4AC_MediaCodec__configure J4AC_android_media_MediaCodec__configure\n#define J4AC_MediaCodec__configure__catchAll J4AC_android_media_MediaCodec__configure__catchAll\n#define J4AC_MediaCodec__getOutputFormat J4AC_android_media_MediaCodec__getOutputFormat\n#define J4AC_MediaCodec__getOutputFormat__asGlobalRef__catchAll J4AC_android_media_MediaCodec__getOutputFormat__asGlobalRef__catchAll\n#define J4AC_MediaCodec__getOutputFormat__catchAll J4AC_android_media_MediaCodec__getOutputFormat__catchAll\n#define J4AC_MediaCodec__getInputBuffers J4AC_android_media_MediaCodec__getInputBuffers\n#define J4AC_MediaCodec__getInputBuffers__asGlobalRef__catchAll J4AC_android_media_MediaCodec__getInputBuffers__asGlobalRef__catchAll\n#define J4AC_MediaCodec__getInputBuffers__catchAll J4AC_android_media_MediaCodec__getInputBuffers__catchAll\n#define J4AC_MediaCodec__dequeueInputBuffer J4AC_android_media_MediaCodec__dequeueInputBuffer\n#define J4AC_MediaCodec__dequeueInputBuffer__catchAll J4AC_android_media_MediaCodec__dequeueInputBuffer__catchAll\n#define J4AC_MediaCodec__queueInputBuffer J4AC_android_media_MediaCodec__queueInputBuffer\n#define J4AC_MediaCodec__queueInputBuffer__catchAll J4AC_android_media_MediaCodec__queueInputBuffer__catchAll\n#define J4AC_MediaCodec__dequeueOutputBuffer J4AC_android_media_MediaCodec__dequeueOutputBuffer\n#define J4AC_MediaCodec__dequeueOutputBuffer__catchAll J4AC_android_media_MediaCodec__dequeueOutputBuffer__catchAll\n#define J4AC_MediaCodec__releaseOutputBuffer J4AC_android_media_MediaCodec__releaseOutputBuffer\n#define J4AC_MediaCodec__releaseOutputBuffer__catchAll J4AC_android_media_MediaCodec__releaseOutputBuffer__catchAll\n#define J4AC_MediaCodec__start J4AC_android_media_MediaCodec__start\n#define J4AC_MediaCodec__start__catchAll J4AC_android_media_MediaCodec__start__catchAll\n#define J4AC_MediaCodec__stop J4AC_android_media_MediaCodec__stop\n#define J4AC_MediaCodec__stop__catchAll J4AC_android_media_MediaCodec__stop__catchAll\n#define J4AC_MediaCodec__flush J4AC_android_media_MediaCodec__flush\n#define J4AC_MediaCodec__flush__catchAll J4AC_android_media_MediaCodec__flush__catchAll\n#define J4AC_MediaCodec__release J4AC_android_media_MediaCodec__release\n#define J4AC_MediaCodec__release__catchAll J4AC_android_media_MediaCodec__release__catchAll\n#define J4A_loadClass__J4AC_MediaCodec J4A_loadClass__J4AC_android_media_MediaCodec\n\n#endif//J4A__android_media_MediaCodec__H\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/android/media/MediaCodec.include.j4a",
    "content": "#include \"j4a/class/android/media/MediaCodec.h\""
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/android/media/MediaCodec.loader.j4a",
    "content": "    J4A_LOAD_CLASS(android_media_MediaCodec);"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/android/media/MediaFormat.c",
    "content": "/*\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * https://github.com/Bilibili/jni4android\n * This file is automatically generated by jni4android, do not modify.\n */\n\n#include \"MediaFormat.h\"\n\ntypedef struct J4AC_android_media_MediaFormat {\n    jclass id;\n\n    jmethodID constructor_MediaFormat;\n    jmethodID method_createVideoFormat;\n    jmethodID method_getInteger;\n    jmethodID method_setInteger;\n    jmethodID method_setByteBuffer;\n} J4AC_android_media_MediaFormat;\nstatic J4AC_android_media_MediaFormat class_J4AC_android_media_MediaFormat;\n\njobject J4AC_android_media_MediaFormat__MediaFormat(JNIEnv *env)\n{\n    return (*env)->NewObject(env, class_J4AC_android_media_MediaFormat.id, class_J4AC_android_media_MediaFormat.constructor_MediaFormat);\n}\n\njobject J4AC_android_media_MediaFormat__MediaFormat__catchAll(JNIEnv *env)\n{\n    jobject ret_object = J4AC_android_media_MediaFormat__MediaFormat(env);\n    if (J4A_ExceptionCheck__catchAll(env) || !ret_object) {\n        return NULL;\n    }\n\n    return ret_object;\n}\n\njobject J4AC_android_media_MediaFormat__MediaFormat__asGlobalRef__catchAll(JNIEnv *env)\n{\n    jobject ret_object   = NULL;\n    jobject local_object = J4AC_android_media_MediaFormat__MediaFormat__catchAll(env);\n    if (J4A_ExceptionCheck__catchAll(env) || !local_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\n    ret_object = J4A_NewGlobalRef__catchAll(env, local_object);\n    if (!ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &local_object);\n    return ret_object;\n}\n\njobject J4AC_android_media_MediaFormat__createVideoFormat(JNIEnv *env, jstring mime, jint width, jint height)\n{\n    return (*env)->CallStaticObjectMethod(env, class_J4AC_android_media_MediaFormat.id, class_J4AC_android_media_MediaFormat.method_createVideoFormat, mime, width, height);\n}\n\njobject J4AC_android_media_MediaFormat__createVideoFormat__catchAll(JNIEnv *env, jstring mime, jint width, jint height)\n{\n    jobject ret_object = J4AC_android_media_MediaFormat__createVideoFormat(env, mime, width, height);\n    if (J4A_ExceptionCheck__catchAll(env) || !ret_object) {\n        return NULL;\n    }\n\n    return ret_object;\n}\n\njobject J4AC_android_media_MediaFormat__createVideoFormat__asGlobalRef__catchAll(JNIEnv *env, jstring mime, jint width, jint height)\n{\n    jobject ret_object   = NULL;\n    jobject local_object = J4AC_android_media_MediaFormat__createVideoFormat__catchAll(env, mime, width, height);\n    if (J4A_ExceptionCheck__catchAll(env) || !local_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\n    ret_object = J4A_NewGlobalRef__catchAll(env, local_object);\n    if (!ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &local_object);\n    return ret_object;\n}\n\njobject J4AC_android_media_MediaFormat__createVideoFormat__withCString(JNIEnv *env, const char *mime_cstr__, jint width, jint height)\n{\n    jobject ret_object = NULL;\n    jstring mime = NULL;\n\n    mime = (*env)->NewStringUTF(env, mime_cstr__);\n    if (J4A_ExceptionCheck__throwAny(env) || !mime)\n        goto fail;\n\n    ret_object = J4AC_android_media_MediaFormat__createVideoFormat(env, mime, width, height);\n    if (J4A_ExceptionCheck__throwAny(env) || !ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &mime);\n    return ret_object;\n}\n\njobject J4AC_android_media_MediaFormat__createVideoFormat__withCString__catchAll(JNIEnv *env, const char *mime_cstr__, jint width, jint height)\n{\n    jobject ret_object = NULL;\n    jstring mime = NULL;\n\n    mime = (*env)->NewStringUTF(env, mime_cstr__);\n    if (J4A_ExceptionCheck__catchAll(env) || !mime)\n        goto fail;\n\n    ret_object = J4AC_android_media_MediaFormat__createVideoFormat__catchAll(env, mime, width, height);\n    if (J4A_ExceptionCheck__catchAll(env) || !ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &mime);\n    return ret_object;\n}\n\njobject J4AC_android_media_MediaFormat__createVideoFormat__withCString__asGlobalRef__catchAll(JNIEnv *env, const char *mime_cstr__, jint width, jint height)\n{\n    jobject ret_object   = NULL;\n    jobject local_object = J4AC_android_media_MediaFormat__createVideoFormat__withCString__catchAll(env, mime_cstr__, width, height);\n    if (J4A_ExceptionCheck__catchAll(env) || !local_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\n    ret_object = J4A_NewGlobalRef__catchAll(env, local_object);\n    if (!ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &local_object);\n    return ret_object;\n}\n\njint J4AC_android_media_MediaFormat__getInteger(JNIEnv *env, jobject thiz, jstring name)\n{\n    return (*env)->CallIntMethod(env, thiz, class_J4AC_android_media_MediaFormat.method_getInteger, name);\n}\n\njint J4AC_android_media_MediaFormat__getInteger__catchAll(JNIEnv *env, jobject thiz, jstring name)\n{\n    jint ret_value = J4AC_android_media_MediaFormat__getInteger(env, thiz, name);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\njint J4AC_android_media_MediaFormat__getInteger__withCString(JNIEnv *env, jobject thiz, const char *name_cstr__)\n{\n    jint ret_value = 0;\n    jstring name = NULL;\n\n    name = (*env)->NewStringUTF(env, name_cstr__);\n    if (J4A_ExceptionCheck__throwAny(env) || !name)\n        goto fail;\n\n    ret_value = J4AC_android_media_MediaFormat__getInteger(env, thiz, name);\n    if (J4A_ExceptionCheck__throwAny(env)) {\n        ret_value = 0;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &name);\n    return ret_value;\n}\n\njint J4AC_android_media_MediaFormat__getInteger__withCString__catchAll(JNIEnv *env, jobject thiz, const char *name_cstr__)\n{\n    jint ret_value = 0;\n    jstring name = NULL;\n\n    name = (*env)->NewStringUTF(env, name_cstr__);\n    if (J4A_ExceptionCheck__catchAll(env) || !name)\n        goto fail;\n\n    ret_value = J4AC_android_media_MediaFormat__getInteger__catchAll(env, thiz, name);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        ret_value = 0;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &name);\n    return ret_value;\n}\n\nvoid J4AC_android_media_MediaFormat__setInteger(JNIEnv *env, jobject thiz, jstring name, jint value)\n{\n    (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_MediaFormat.method_setInteger, name, value);\n}\n\nvoid J4AC_android_media_MediaFormat__setInteger__catchAll(JNIEnv *env, jobject thiz, jstring name, jint value)\n{\n    J4AC_android_media_MediaFormat__setInteger(env, thiz, name, value);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\nvoid J4AC_android_media_MediaFormat__setInteger__withCString(JNIEnv *env, jobject thiz, const char *name_cstr__, jint value)\n{\n    jstring name = NULL;\n\n    name = (*env)->NewStringUTF(env, name_cstr__);\n    if (J4A_ExceptionCheck__throwAny(env) || !name)\n        goto fail;\n\n    J4AC_android_media_MediaFormat__setInteger(env, thiz, name, value);\n\nfail:\n    J4A_DeleteLocalRef__p(env, &name);\n}\n\nvoid J4AC_android_media_MediaFormat__setInteger__withCString__catchAll(JNIEnv *env, jobject thiz, const char *name_cstr__, jint value)\n{\n    jstring name = NULL;\n\n    name = (*env)->NewStringUTF(env, name_cstr__);\n    if (J4A_ExceptionCheck__catchAll(env) || !name)\n        goto fail;\n\n    J4AC_android_media_MediaFormat__setInteger__catchAll(env, thiz, name, value);\n\nfail:\n    J4A_DeleteLocalRef__p(env, &name);\n}\n\nvoid J4AC_android_media_MediaFormat__setByteBuffer(JNIEnv *env, jobject thiz, jstring name, jobject bytes)\n{\n    (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_MediaFormat.method_setByteBuffer, name, bytes);\n}\n\nvoid J4AC_android_media_MediaFormat__setByteBuffer__catchAll(JNIEnv *env, jobject thiz, jstring name, jobject bytes)\n{\n    J4AC_android_media_MediaFormat__setByteBuffer(env, thiz, name, bytes);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\nvoid J4AC_android_media_MediaFormat__setByteBuffer__withCString(JNIEnv *env, jobject thiz, const char *name_cstr__, jobject bytes)\n{\n    jstring name = NULL;\n\n    name = (*env)->NewStringUTF(env, name_cstr__);\n    if (J4A_ExceptionCheck__throwAny(env) || !name)\n        goto fail;\n\n    J4AC_android_media_MediaFormat__setByteBuffer(env, thiz, name, bytes);\n\nfail:\n    J4A_DeleteLocalRef__p(env, &name);\n}\n\nvoid J4AC_android_media_MediaFormat__setByteBuffer__withCString__catchAll(JNIEnv *env, jobject thiz, const char *name_cstr__, jobject bytes)\n{\n    jstring name = NULL;\n\n    name = (*env)->NewStringUTF(env, name_cstr__);\n    if (J4A_ExceptionCheck__catchAll(env) || !name)\n        goto fail;\n\n    J4AC_android_media_MediaFormat__setByteBuffer__catchAll(env, thiz, name, bytes);\n\nfail:\n    J4A_DeleteLocalRef__p(env, &name);\n}\n\nint J4A_loadClass__J4AC_android_media_MediaFormat(JNIEnv *env)\n{\n    int         ret                   = -1;\n    const char *J4A_UNUSED(name)      = NULL;\n    const char *J4A_UNUSED(sign)      = NULL;\n    jclass      J4A_UNUSED(class_id)  = NULL;\n    int         J4A_UNUSED(api_level) = 0;\n\n    if (class_J4AC_android_media_MediaFormat.id != NULL)\n        return 0;\n\n    api_level = J4A_GetSystemAndroidApiLevel(env);\n\n    if (api_level < 16) {\n        J4A_ALOGW(\"J4ALoader: Ignore: '%s' need API %d\\n\", \"android.media.MediaFormat\", api_level);\n        goto ignore;\n    }\n\n    sign = \"android/media/MediaFormat\";\n    class_J4AC_android_media_MediaFormat.id = J4A_FindClass__asGlobalRef__catchAll(env, sign);\n    if (class_J4AC_android_media_MediaFormat.id == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_MediaFormat.id;\n    name     = \"<init>\";\n    sign     = \"()V\";\n    class_J4AC_android_media_MediaFormat.constructor_MediaFormat = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_MediaFormat.constructor_MediaFormat == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_MediaFormat.id;\n    name     = \"createVideoFormat\";\n    sign     = \"(Ljava/lang/String;II)Landroid/media/MediaFormat;\";\n    class_J4AC_android_media_MediaFormat.method_createVideoFormat = J4A_GetStaticMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_MediaFormat.method_createVideoFormat == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_MediaFormat.id;\n    name     = \"getInteger\";\n    sign     = \"(Ljava/lang/String;)I\";\n    class_J4AC_android_media_MediaFormat.method_getInteger = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_MediaFormat.method_getInteger == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_MediaFormat.id;\n    name     = \"setInteger\";\n    sign     = \"(Ljava/lang/String;I)V\";\n    class_J4AC_android_media_MediaFormat.method_setInteger = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_MediaFormat.method_setInteger == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_MediaFormat.id;\n    name     = \"setByteBuffer\";\n    sign     = \"(Ljava/lang/String;Ljava/nio/ByteBuffer;)V\";\n    class_J4AC_android_media_MediaFormat.method_setByteBuffer = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_MediaFormat.method_setByteBuffer == NULL)\n        goto fail;\n\n    J4A_ALOGD(\"J4ALoader: OK: '%s' loaded\\n\", \"android.media.MediaFormat\");\nignore:\n    ret = 0;\nfail:\n    return ret;\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/android/media/MediaFormat.h",
    "content": "/*\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * https://github.com/Bilibili/jni4android\n * This file is automatically generated by jni4android, do not modify.\n */\n\n#ifndef J4A__android_media_MediaFormat__H\n#define J4A__android_media_MediaFormat__H\n\n#include \"j4a/j4a_base.h\"\n\njobject J4AC_android_media_MediaFormat__MediaFormat(JNIEnv *env);\njobject J4AC_android_media_MediaFormat__MediaFormat__catchAll(JNIEnv *env);\njobject J4AC_android_media_MediaFormat__MediaFormat__asGlobalRef__catchAll(JNIEnv *env);\njobject J4AC_android_media_MediaFormat__createVideoFormat(JNIEnv *env, jstring mime, jint width, jint height);\njobject J4AC_android_media_MediaFormat__createVideoFormat__catchAll(JNIEnv *env, jstring mime, jint width, jint height);\njobject J4AC_android_media_MediaFormat__createVideoFormat__asGlobalRef__catchAll(JNIEnv *env, jstring mime, jint width, jint height);\njobject J4AC_android_media_MediaFormat__createVideoFormat__withCString(JNIEnv *env, const char *mime_cstr__, jint width, jint height);\njobject J4AC_android_media_MediaFormat__createVideoFormat__withCString__catchAll(JNIEnv *env, const char *mime_cstr__, jint width, jint height);\njobject J4AC_android_media_MediaFormat__createVideoFormat__withCString__asGlobalRef__catchAll(JNIEnv *env, const char *mime_cstr__, jint width, jint height);\njint J4AC_android_media_MediaFormat__getInteger(JNIEnv *env, jobject thiz, jstring name);\njint J4AC_android_media_MediaFormat__getInteger__catchAll(JNIEnv *env, jobject thiz, jstring name);\njint J4AC_android_media_MediaFormat__getInteger__withCString(JNIEnv *env, jobject thiz, const char *name_cstr__);\njint J4AC_android_media_MediaFormat__getInteger__withCString__catchAll(JNIEnv *env, jobject thiz, const char *name_cstr__);\nvoid J4AC_android_media_MediaFormat__setInteger(JNIEnv *env, jobject thiz, jstring name, jint value);\nvoid J4AC_android_media_MediaFormat__setInteger__catchAll(JNIEnv *env, jobject thiz, jstring name, jint value);\nvoid J4AC_android_media_MediaFormat__setInteger__withCString(JNIEnv *env, jobject thiz, const char *name_cstr__, jint value);\nvoid J4AC_android_media_MediaFormat__setInteger__withCString__catchAll(JNIEnv *env, jobject thiz, const char *name_cstr__, jint value);\nvoid J4AC_android_media_MediaFormat__setByteBuffer(JNIEnv *env, jobject thiz, jstring name, jobject bytes);\nvoid J4AC_android_media_MediaFormat__setByteBuffer__catchAll(JNIEnv *env, jobject thiz, jstring name, jobject bytes);\nvoid J4AC_android_media_MediaFormat__setByteBuffer__withCString(JNIEnv *env, jobject thiz, const char *name_cstr__, jobject bytes);\nvoid J4AC_android_media_MediaFormat__setByteBuffer__withCString__catchAll(JNIEnv *env, jobject thiz, const char *name_cstr__, jobject bytes);\nint J4A_loadClass__J4AC_android_media_MediaFormat(JNIEnv *env);\n\n#define J4A_HAVE_SIMPLE__J4AC_android_media_MediaFormat\n\n#define J4AC_MediaFormat__MediaFormat J4AC_android_media_MediaFormat__MediaFormat\n#define J4AC_MediaFormat__MediaFormat__asGlobalRef__catchAll J4AC_android_media_MediaFormat__MediaFormat__asGlobalRef__catchAll\n#define J4AC_MediaFormat__MediaFormat__catchAll J4AC_android_media_MediaFormat__MediaFormat__catchAll\n#define J4AC_MediaFormat__createVideoFormat J4AC_android_media_MediaFormat__createVideoFormat\n#define J4AC_MediaFormat__createVideoFormat__asGlobalRef__catchAll J4AC_android_media_MediaFormat__createVideoFormat__asGlobalRef__catchAll\n#define J4AC_MediaFormat__createVideoFormat__catchAll J4AC_android_media_MediaFormat__createVideoFormat__catchAll\n#define J4AC_MediaFormat__createVideoFormat__withCString J4AC_android_media_MediaFormat__createVideoFormat__withCString\n#define J4AC_MediaFormat__createVideoFormat__withCString__asGlobalRef__catchAll J4AC_android_media_MediaFormat__createVideoFormat__withCString__asGlobalRef__catchAll\n#define J4AC_MediaFormat__createVideoFormat__withCString__catchAll J4AC_android_media_MediaFormat__createVideoFormat__withCString__catchAll\n#define J4AC_MediaFormat__getInteger J4AC_android_media_MediaFormat__getInteger\n#define J4AC_MediaFormat__getInteger__catchAll J4AC_android_media_MediaFormat__getInteger__catchAll\n#define J4AC_MediaFormat__getInteger__withCString J4AC_android_media_MediaFormat__getInteger__withCString\n#define J4AC_MediaFormat__getInteger__withCString__catchAll J4AC_android_media_MediaFormat__getInteger__withCString__catchAll\n#define J4AC_MediaFormat__setInteger J4AC_android_media_MediaFormat__setInteger\n#define J4AC_MediaFormat__setInteger__catchAll J4AC_android_media_MediaFormat__setInteger__catchAll\n#define J4AC_MediaFormat__setInteger__withCString J4AC_android_media_MediaFormat__setInteger__withCString\n#define J4AC_MediaFormat__setInteger__withCString__catchAll J4AC_android_media_MediaFormat__setInteger__withCString__catchAll\n#define J4AC_MediaFormat__setByteBuffer J4AC_android_media_MediaFormat__setByteBuffer\n#define J4AC_MediaFormat__setByteBuffer__catchAll J4AC_android_media_MediaFormat__setByteBuffer__catchAll\n#define J4AC_MediaFormat__setByteBuffer__withCString J4AC_android_media_MediaFormat__setByteBuffer__withCString\n#define J4AC_MediaFormat__setByteBuffer__withCString__catchAll J4AC_android_media_MediaFormat__setByteBuffer__withCString__catchAll\n#define J4A_loadClass__J4AC_MediaFormat J4A_loadClass__J4AC_android_media_MediaFormat\n\n#endif//J4A__android_media_MediaFormat__H\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/android/media/MediaFormat.include.j4a",
    "content": "#include \"j4a/class/android/media/MediaFormat.h\""
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/android/media/MediaFormat.loader.j4a",
    "content": "    J4A_LOAD_CLASS(android_media_MediaFormat);"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/android/media/PlaybackParams.c",
    "content": "/*\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * https://github.com/Bilibili/jni4android\n * This file is automatically generated by jni4android, do not modify.\n */\n\n#include \"PlaybackParams.h\"\n\ntypedef struct J4AC_android_media_PlaybackParams {\n    jclass id;\n\n    jmethodID method_setSpeed;\n} J4AC_android_media_PlaybackParams;\nstatic J4AC_android_media_PlaybackParams class_J4AC_android_media_PlaybackParams;\n\njobject J4AC_android_media_PlaybackParams__setSpeed(JNIEnv *env, jobject thiz, jfloat speed)\n{\n    return (*env)->CallObjectMethod(env, thiz, class_J4AC_android_media_PlaybackParams.method_setSpeed, speed);\n}\n\njobject J4AC_android_media_PlaybackParams__setSpeed__catchAll(JNIEnv *env, jobject thiz, jfloat speed)\n{\n    jobject ret_object = J4AC_android_media_PlaybackParams__setSpeed(env, thiz, speed);\n    if (J4A_ExceptionCheck__catchAll(env) || !ret_object) {\n        return NULL;\n    }\n\n    return ret_object;\n}\n\njobject J4AC_android_media_PlaybackParams__setSpeed__asGlobalRef__catchAll(JNIEnv *env, jobject thiz, jfloat speed)\n{\n    jobject ret_object   = NULL;\n    jobject local_object = J4AC_android_media_PlaybackParams__setSpeed__catchAll(env, thiz, speed);\n    if (J4A_ExceptionCheck__catchAll(env) || !local_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\n    ret_object = J4A_NewGlobalRef__catchAll(env, local_object);\n    if (!ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &local_object);\n    return ret_object;\n}\n\nint J4A_loadClass__J4AC_android_media_PlaybackParams(JNIEnv *env)\n{\n    int         ret                   = -1;\n    const char *J4A_UNUSED(name)      = NULL;\n    const char *J4A_UNUSED(sign)      = NULL;\n    jclass      J4A_UNUSED(class_id)  = NULL;\n    int         J4A_UNUSED(api_level) = 0;\n\n    if (class_J4AC_android_media_PlaybackParams.id != NULL)\n        return 0;\n\n    api_level = J4A_GetSystemAndroidApiLevel(env);\n\n    if (api_level < 23) {\n        J4A_ALOGW(\"J4ALoader: Ignore: '%s' need API %d\\n\", \"android.media.PlaybackParams\", api_level);\n        goto ignore;\n    }\n\n    sign = \"android/media/PlaybackParams\";\n    class_J4AC_android_media_PlaybackParams.id = J4A_FindClass__asGlobalRef__catchAll(env, sign);\n    if (class_J4AC_android_media_PlaybackParams.id == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_media_PlaybackParams.id;\n    name     = \"setSpeed\";\n    sign     = \"(F)Landroid/media/PlaybackParams;\";\n    class_J4AC_android_media_PlaybackParams.method_setSpeed = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_media_PlaybackParams.method_setSpeed == NULL)\n        goto fail;\n\n    J4A_ALOGD(\"J4ALoader: OK: '%s' loaded\\n\", \"android.media.PlaybackParams\");\nignore:\n    ret = 0;\nfail:\n    return ret;\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/android/media/PlaybackParams.h",
    "content": "/*\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * https://github.com/Bilibili/jni4android\n * This file is automatically generated by jni4android, do not modify.\n */\n\n#ifndef J4A__android_media_PlaybackParams__H\n#define J4A__android_media_PlaybackParams__H\n\n#include \"j4a/j4a_base.h\"\n\njobject J4AC_android_media_PlaybackParams__setSpeed(JNIEnv *env, jobject thiz, jfloat speed);\njobject J4AC_android_media_PlaybackParams__setSpeed__catchAll(JNIEnv *env, jobject thiz, jfloat speed);\njobject J4AC_android_media_PlaybackParams__setSpeed__asGlobalRef__catchAll(JNIEnv *env, jobject thiz, jfloat speed);\nint J4A_loadClass__J4AC_android_media_PlaybackParams(JNIEnv *env);\n\n#define J4A_HAVE_SIMPLE__J4AC_android_media_PlaybackParams\n\n#define J4AC_PlaybackParams__setSpeed J4AC_android_media_PlaybackParams__setSpeed\n#define J4AC_PlaybackParams__setSpeed__asGlobalRef__catchAll J4AC_android_media_PlaybackParams__setSpeed__asGlobalRef__catchAll\n#define J4AC_PlaybackParams__setSpeed__catchAll J4AC_android_media_PlaybackParams__setSpeed__catchAll\n#define J4A_loadClass__J4AC_PlaybackParams J4A_loadClass__J4AC_android_media_PlaybackParams\n\n#endif//J4A__android_media_PlaybackParams__H\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/android/media/PlaybackParams.include.j4a",
    "content": "#include \"j4a/class/android/media/PlaybackParams.h\""
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/android/media/PlaybackParams.loader.j4a",
    "content": "    J4A_LOAD_CLASS(android_media_PlaybackParams);"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/android/os/Build.c",
    "content": "/*\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * https://github.com/Bilibili/jni4android\n * This file is automatically generated by jni4android, do not modify.\n */\n\n#include \"Build.h\"\n\ntypedef struct J4AC_android_os_Build__VERSION {\n    jclass id;\n\n    jfieldID field_SDK_INT;\n} J4AC_android_os_Build__VERSION;\nstatic J4AC_android_os_Build__VERSION class_J4AC_android_os_Build__VERSION;\n\ntypedef struct J4AC_android_os_Build {\n    jclass id;\n\n} J4AC_android_os_Build;\nstatic J4AC_android_os_Build class_J4AC_android_os_Build;\n\njint J4AC_android_os_Build__VERSION__SDK_INT__get(JNIEnv *env)\n{\n    return (*env)->GetStaticIntField(env, class_J4AC_android_os_Build__VERSION.id, class_J4AC_android_os_Build__VERSION.field_SDK_INT);\n}\n\njint J4AC_android_os_Build__VERSION__SDK_INT__get__catchAll(JNIEnv *env)\n{\n    jint ret_value = J4AC_android_os_Build__VERSION__SDK_INT__get(env);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\nvoid J4AC_android_os_Build__VERSION__SDK_INT__set(JNIEnv *env, jint value)\n{\n    (*env)->SetStaticIntField(env, class_J4AC_android_os_Build__VERSION.id, class_J4AC_android_os_Build__VERSION.field_SDK_INT, value);\n}\n\nvoid J4AC_android_os_Build__VERSION__SDK_INT__set__catchAll(JNIEnv *env, jint value)\n{\n    J4AC_android_os_Build__VERSION__SDK_INT__set(env, value);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\nint J4A_loadClass__J4AC_android_os_Build__VERSION(JNIEnv *env)\n{\n    int         ret                   = -1;\n    const char *J4A_UNUSED(name)      = NULL;\n    const char *J4A_UNUSED(sign)      = NULL;\n    jclass      J4A_UNUSED(class_id)  = NULL;\n    int         J4A_UNUSED(api_level) = 0;\n\n    if (class_J4AC_android_os_Build__VERSION.id != NULL)\n        return 0;\n\n    sign = \"android/os/Build$VERSION\";\n    class_J4AC_android_os_Build__VERSION.id = J4A_FindClass__asGlobalRef__catchAll(env, sign);\n    if (class_J4AC_android_os_Build__VERSION.id == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_os_Build__VERSION.id;\n    name     = \"SDK_INT\";\n    sign     = \"I\";\n    class_J4AC_android_os_Build__VERSION.field_SDK_INT = J4A_GetStaticFieldID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_os_Build__VERSION.field_SDK_INT == NULL)\n        goto fail;\n\n    J4A_ALOGD(\"J4ALoader: OK: '%s' loaded\\n\", \"android.os.Build$VERSION\");\n    ret = 0;\nfail:\n    return ret;\n}\n\nint J4A_loadClass__J4AC_android_os_Build(JNIEnv *env)\n{\n    int         ret                   = -1;\n    const char *J4A_UNUSED(name)      = NULL;\n    const char *J4A_UNUSED(sign)      = NULL;\n    jclass      J4A_UNUSED(class_id)  = NULL;\n    int         J4A_UNUSED(api_level) = 0;\n\n    if (class_J4AC_android_os_Build.id != NULL)\n        return 0;\n\n    sign = \"android/os/Build\";\n    class_J4AC_android_os_Build.id = J4A_FindClass__asGlobalRef__catchAll(env, sign);\n    if (class_J4AC_android_os_Build.id == NULL)\n        goto fail;\n\n    ret = J4A_loadClass__J4AC_android_os_Build__VERSION(env);\n    if (ret)\n        goto fail;\n\n    J4A_ALOGD(\"J4ALoader: OK: '%s' loaded\\n\", \"android.os.Build\");\n    ret = 0;\nfail:\n    return ret;\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/android/os/Build.h",
    "content": "/*\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * https://github.com/Bilibili/jni4android\n * This file is automatically generated by jni4android, do not modify.\n */\n\n#ifndef J4A__android_os_Build__H\n#define J4A__android_os_Build__H\n\n#include \"j4a/j4a_base.h\"\n\njint J4AC_android_os_Build__VERSION__SDK_INT__get(JNIEnv *env);\njint J4AC_android_os_Build__VERSION__SDK_INT__get__catchAll(JNIEnv *env);\nvoid J4AC_android_os_Build__VERSION__SDK_INT__set(JNIEnv *env, jint value);\nvoid J4AC_android_os_Build__VERSION__SDK_INT__set__catchAll(JNIEnv *env, jint value);\nint J4A_loadClass__J4AC_android_os_Build(JNIEnv *env);\n\n#endif//J4A__android_os_Build__H\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/android/os/Build.include.j4a",
    "content": "#include \"j4a/class/android/os/Build.h\""
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/android/os/Build.loader.j4a",
    "content": "    J4A_LOAD_CLASS(android_os_Build);"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/android/os/Bundle.c",
    "content": "/*\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * https://github.com/Bilibili/jni4android\n * This file is automatically generated by jni4android, do not modify.\n */\n\n#include \"Bundle.h\"\n\ntypedef struct J4AC_android_os_Bundle {\n    jclass id;\n\n    jmethodID constructor_Bundle;\n    jmethodID method_getInt;\n    jmethodID method_putInt;\n    jmethodID method_getString;\n    jmethodID method_putString;\n    jmethodID method_putParcelableArrayList;\n    jmethodID method_getLong;\n    jmethodID method_putLong;\n} J4AC_android_os_Bundle;\nstatic J4AC_android_os_Bundle class_J4AC_android_os_Bundle;\n\njobject J4AC_android_os_Bundle__Bundle(JNIEnv *env)\n{\n    return (*env)->NewObject(env, class_J4AC_android_os_Bundle.id, class_J4AC_android_os_Bundle.constructor_Bundle);\n}\n\njobject J4AC_android_os_Bundle__Bundle__catchAll(JNIEnv *env)\n{\n    jobject ret_object = J4AC_android_os_Bundle__Bundle(env);\n    if (J4A_ExceptionCheck__catchAll(env) || !ret_object) {\n        return NULL;\n    }\n\n    return ret_object;\n}\n\njobject J4AC_android_os_Bundle__Bundle__asGlobalRef__catchAll(JNIEnv *env)\n{\n    jobject ret_object   = NULL;\n    jobject local_object = J4AC_android_os_Bundle__Bundle__catchAll(env);\n    if (J4A_ExceptionCheck__catchAll(env) || !local_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\n    ret_object = J4A_NewGlobalRef__catchAll(env, local_object);\n    if (!ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &local_object);\n    return ret_object;\n}\n\njint J4AC_android_os_Bundle__getInt(JNIEnv *env, jobject thiz, jstring key, jint defaultValue)\n{\n    return (*env)->CallIntMethod(env, thiz, class_J4AC_android_os_Bundle.method_getInt, key, defaultValue);\n}\n\njint J4AC_android_os_Bundle__getInt__catchAll(JNIEnv *env, jobject thiz, jstring key, jint defaultValue)\n{\n    jint ret_value = J4AC_android_os_Bundle__getInt(env, thiz, key, defaultValue);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\njint J4AC_android_os_Bundle__getInt__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__, jint defaultValue)\n{\n    jint ret_value = 0;\n    jstring key = NULL;\n\n    key = (*env)->NewStringUTF(env, key_cstr__);\n    if (J4A_ExceptionCheck__throwAny(env) || !key)\n        goto fail;\n\n    ret_value = J4AC_android_os_Bundle__getInt(env, thiz, key, defaultValue);\n    if (J4A_ExceptionCheck__throwAny(env)) {\n        ret_value = 0;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &key);\n    return ret_value;\n}\n\njint J4AC_android_os_Bundle__getInt__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__, jint defaultValue)\n{\n    jint ret_value = 0;\n    jstring key = NULL;\n\n    key = (*env)->NewStringUTF(env, key_cstr__);\n    if (J4A_ExceptionCheck__catchAll(env) || !key)\n        goto fail;\n\n    ret_value = J4AC_android_os_Bundle__getInt__catchAll(env, thiz, key, defaultValue);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        ret_value = 0;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &key);\n    return ret_value;\n}\n\nvoid J4AC_android_os_Bundle__putInt(JNIEnv *env, jobject thiz, jstring key, jint value)\n{\n    (*env)->CallVoidMethod(env, thiz, class_J4AC_android_os_Bundle.method_putInt, key, value);\n}\n\nvoid J4AC_android_os_Bundle__putInt__catchAll(JNIEnv *env, jobject thiz, jstring key, jint value)\n{\n    J4AC_android_os_Bundle__putInt(env, thiz, key, value);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\nvoid J4AC_android_os_Bundle__putInt__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__, jint value)\n{\n    jstring key = NULL;\n\n    key = (*env)->NewStringUTF(env, key_cstr__);\n    if (J4A_ExceptionCheck__throwAny(env) || !key)\n        goto fail;\n\n    J4AC_android_os_Bundle__putInt(env, thiz, key, value);\n\nfail:\n    J4A_DeleteLocalRef__p(env, &key);\n}\n\nvoid J4AC_android_os_Bundle__putInt__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__, jint value)\n{\n    jstring key = NULL;\n\n    key = (*env)->NewStringUTF(env, key_cstr__);\n    if (J4A_ExceptionCheck__catchAll(env) || !key)\n        goto fail;\n\n    J4AC_android_os_Bundle__putInt__catchAll(env, thiz, key, value);\n\nfail:\n    J4A_DeleteLocalRef__p(env, &key);\n}\n\njstring J4AC_android_os_Bundle__getString(JNIEnv *env, jobject thiz, jstring key)\n{\n    return (*env)->CallObjectMethod(env, thiz, class_J4AC_android_os_Bundle.method_getString, key);\n}\n\njstring J4AC_android_os_Bundle__getString__catchAll(JNIEnv *env, jobject thiz, jstring key)\n{\n    jstring ret_object = J4AC_android_os_Bundle__getString(env, thiz, key);\n    if (J4A_ExceptionCheck__catchAll(env) || !ret_object) {\n        return NULL;\n    }\n\n    return ret_object;\n}\n\njstring J4AC_android_os_Bundle__getString__asGlobalRef__catchAll(JNIEnv *env, jobject thiz, jstring key)\n{\n    jstring ret_object   = NULL;\n    jstring local_object = J4AC_android_os_Bundle__getString__catchAll(env, thiz, key);\n    if (J4A_ExceptionCheck__catchAll(env) || !local_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\n    ret_object = J4A_NewGlobalRef__catchAll(env, local_object);\n    if (!ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &local_object);\n    return ret_object;\n}\n\nconst char *J4AC_android_os_Bundle__getString__asCBuffer(JNIEnv *env, jobject thiz, jstring key, char *out_buf, int out_len)\n{\n    const char *ret_value = NULL;\n    const char *c_str     = NULL;\n    jstring local_string = J4AC_android_os_Bundle__getString(env, thiz, key);\n    if (J4A_ExceptionCheck__throwAny(env) || !local_string) {\n        goto fail;\n    }\n\n    c_str = (*env)->GetStringUTFChars(env, local_string, NULL );\n    if (J4A_ExceptionCheck__throwAny(env) || !c_str) {\n        goto fail;\n    }\n\n    strlcpy(out_buf, c_str, out_len);\n    ret_value = out_buf;\n\nfail:\n    J4A_ReleaseStringUTFChars__p(env, local_string, &c_str);\n    J4A_DeleteLocalRef__p(env, &local_string);\n    return ret_value;\n}\n\nconst char *J4AC_android_os_Bundle__getString__asCBuffer__catchAll(JNIEnv *env, jobject thiz, jstring key, char *out_buf, int out_len)\n{\n    const char *ret_value = NULL;\n    const char *c_str     = NULL;\n    jstring local_string = J4AC_android_os_Bundle__getString__catchAll(env, thiz, key);\n    if (J4A_ExceptionCheck__catchAll(env) || !local_string) {\n        goto fail;\n    }\n\n    c_str = (*env)->GetStringUTFChars(env, local_string, NULL );\n    if (J4A_ExceptionCheck__catchAll(env) || !c_str) {\n        goto fail;\n    }\n\n    strlcpy(out_buf, c_str, out_len);\n    ret_value = out_buf;\n\nfail:\n    J4A_ReleaseStringUTFChars__p(env, local_string, &c_str);\n    J4A_DeleteLocalRef__p(env, &local_string);\n    return ret_value;\n}\n\njstring J4AC_android_os_Bundle__getString__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__)\n{\n    jstring ret_object = NULL;\n    jstring key = NULL;\n\n    key = (*env)->NewStringUTF(env, key_cstr__);\n    if (J4A_ExceptionCheck__throwAny(env) || !key)\n        goto fail;\n\n    ret_object = J4AC_android_os_Bundle__getString(env, thiz, key);\n    if (J4A_ExceptionCheck__throwAny(env) || !ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &key);\n    return ret_object;\n}\n\njstring J4AC_android_os_Bundle__getString__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__)\n{\n    jstring ret_object = NULL;\n    jstring key = NULL;\n\n    key = (*env)->NewStringUTF(env, key_cstr__);\n    if (J4A_ExceptionCheck__catchAll(env) || !key)\n        goto fail;\n\n    ret_object = J4AC_android_os_Bundle__getString__catchAll(env, thiz, key);\n    if (J4A_ExceptionCheck__catchAll(env) || !ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &key);\n    return ret_object;\n}\n\njstring J4AC_android_os_Bundle__getString__withCString__asGlobalRef__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__)\n{\n    jstring ret_object   = NULL;\n    jstring local_object = J4AC_android_os_Bundle__getString__withCString__catchAll(env, thiz, key_cstr__);\n    if (J4A_ExceptionCheck__catchAll(env) || !local_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\n    ret_object = J4A_NewGlobalRef__catchAll(env, local_object);\n    if (!ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &local_object);\n    return ret_object;\n}\n\nconst char *J4AC_android_os_Bundle__getString__withCString__asCBuffer(JNIEnv *env, jobject thiz, const char *key_cstr__, char *out_buf, int out_len)\n{\n    const char *ret_value = NULL;\n    const char *c_str     = NULL;\n    jstring local_string = J4AC_android_os_Bundle__getString__withCString(env, thiz, key_cstr__);\n    if (J4A_ExceptionCheck__throwAny(env) || !local_string) {\n        goto fail;\n    }\n\n    c_str = (*env)->GetStringUTFChars(env, local_string, NULL );\n    if (J4A_ExceptionCheck__throwAny(env) || !c_str) {\n        goto fail;\n    }\n\n    strlcpy(out_buf, c_str, out_len);\n    ret_value = out_buf;\n\nfail:\n    J4A_ReleaseStringUTFChars__p(env, local_string, &c_str);\n    J4A_DeleteLocalRef__p(env, &local_string);\n    return ret_value;\n}\n\nconst char *J4AC_android_os_Bundle__getString__withCString__asCBuffer__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__, char *out_buf, int out_len)\n{\n    const char *ret_value = NULL;\n    const char *c_str     = NULL;\n    jstring local_string = J4AC_android_os_Bundle__getString__withCString__catchAll(env, thiz, key_cstr__);\n    if (J4A_ExceptionCheck__catchAll(env) || !local_string) {\n        goto fail;\n    }\n\n    c_str = (*env)->GetStringUTFChars(env, local_string, NULL );\n    if (J4A_ExceptionCheck__catchAll(env) || !c_str) {\n        goto fail;\n    }\n\n    strlcpy(out_buf, c_str, out_len);\n    ret_value = out_buf;\n\nfail:\n    J4A_ReleaseStringUTFChars__p(env, local_string, &c_str);\n    J4A_DeleteLocalRef__p(env, &local_string);\n    return ret_value;\n}\n\nvoid J4AC_android_os_Bundle__putString(JNIEnv *env, jobject thiz, jstring key, jstring value)\n{\n    (*env)->CallVoidMethod(env, thiz, class_J4AC_android_os_Bundle.method_putString, key, value);\n}\n\nvoid J4AC_android_os_Bundle__putString__catchAll(JNIEnv *env, jobject thiz, jstring key, jstring value)\n{\n    J4AC_android_os_Bundle__putString(env, thiz, key, value);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\nvoid J4AC_android_os_Bundle__putString__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__, const char *value_cstr__)\n{\n    jstring key = NULL;\n    jstring value = NULL;\n\n    key = (*env)->NewStringUTF(env, key_cstr__);\n    if (J4A_ExceptionCheck__throwAny(env) || !key)\n        goto fail;\n    value = (*env)->NewStringUTF(env, value_cstr__);\n    if (J4A_ExceptionCheck__throwAny(env) || !value)\n        goto fail;\n\n    J4AC_android_os_Bundle__putString(env, thiz, key, value);\n\nfail:\n    J4A_DeleteLocalRef__p(env, &key);\n    J4A_DeleteLocalRef__p(env, &value);\n}\n\nvoid J4AC_android_os_Bundle__putString__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__, const char *value_cstr__)\n{\n    jstring key = NULL;\n    jstring value = NULL;\n\n    key = (*env)->NewStringUTF(env, key_cstr__);\n    if (J4A_ExceptionCheck__catchAll(env) || !key)\n        goto fail;\n    value = (*env)->NewStringUTF(env, value_cstr__);\n    if (J4A_ExceptionCheck__catchAll(env) || !value)\n        goto fail;\n\n    J4AC_android_os_Bundle__putString__catchAll(env, thiz, key, value);\n\nfail:\n    J4A_DeleteLocalRef__p(env, &key);\n    J4A_DeleteLocalRef__p(env, &value);\n}\n\nvoid J4AC_android_os_Bundle__putParcelableArrayList(JNIEnv *env, jobject thiz, jstring key, jobject value)\n{\n    (*env)->CallVoidMethod(env, thiz, class_J4AC_android_os_Bundle.method_putParcelableArrayList, key, value);\n}\n\nvoid J4AC_android_os_Bundle__putParcelableArrayList__catchAll(JNIEnv *env, jobject thiz, jstring key, jobject value)\n{\n    J4AC_android_os_Bundle__putParcelableArrayList(env, thiz, key, value);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\nvoid J4AC_android_os_Bundle__putParcelableArrayList__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__, jobject value)\n{\n    jstring key = NULL;\n\n    key = (*env)->NewStringUTF(env, key_cstr__);\n    if (J4A_ExceptionCheck__throwAny(env) || !key)\n        goto fail;\n\n    J4AC_android_os_Bundle__putParcelableArrayList(env, thiz, key, value);\n\nfail:\n    J4A_DeleteLocalRef__p(env, &key);\n}\n\nvoid J4AC_android_os_Bundle__putParcelableArrayList__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__, jobject value)\n{\n    jstring key = NULL;\n\n    key = (*env)->NewStringUTF(env, key_cstr__);\n    if (J4A_ExceptionCheck__catchAll(env) || !key)\n        goto fail;\n\n    J4AC_android_os_Bundle__putParcelableArrayList__catchAll(env, thiz, key, value);\n\nfail:\n    J4A_DeleteLocalRef__p(env, &key);\n}\n\njlong J4AC_android_os_Bundle__getLong(JNIEnv *env, jobject thiz, jstring key)\n{\n    return (*env)->CallLongMethod(env, thiz, class_J4AC_android_os_Bundle.method_getLong, key);\n}\n\njlong J4AC_android_os_Bundle__getLong__catchAll(JNIEnv *env, jobject thiz, jstring key)\n{\n    jlong ret_value = J4AC_android_os_Bundle__getLong(env, thiz, key);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\njlong J4AC_android_os_Bundle__getLong__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__)\n{\n    jlong ret_value = 0;\n    jstring key = NULL;\n\n    key = (*env)->NewStringUTF(env, key_cstr__);\n    if (J4A_ExceptionCheck__throwAny(env) || !key)\n        goto fail;\n\n    ret_value = J4AC_android_os_Bundle__getLong(env, thiz, key);\n    if (J4A_ExceptionCheck__throwAny(env)) {\n        ret_value = 0;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &key);\n    return ret_value;\n}\n\njlong J4AC_android_os_Bundle__getLong__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__)\n{\n    jlong ret_value = 0;\n    jstring key = NULL;\n\n    key = (*env)->NewStringUTF(env, key_cstr__);\n    if (J4A_ExceptionCheck__catchAll(env) || !key)\n        goto fail;\n\n    ret_value = J4AC_android_os_Bundle__getLong__catchAll(env, thiz, key);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        ret_value = 0;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &key);\n    return ret_value;\n}\n\nvoid J4AC_android_os_Bundle__putLong(JNIEnv *env, jobject thiz, jstring key, jlong value)\n{\n    (*env)->CallVoidMethod(env, thiz, class_J4AC_android_os_Bundle.method_putLong, key, value);\n}\n\nvoid J4AC_android_os_Bundle__putLong__catchAll(JNIEnv *env, jobject thiz, jstring key, jlong value)\n{\n    J4AC_android_os_Bundle__putLong(env, thiz, key, value);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\nvoid J4AC_android_os_Bundle__putLong__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__, jlong value)\n{\n    jstring key = NULL;\n\n    key = (*env)->NewStringUTF(env, key_cstr__);\n    if (J4A_ExceptionCheck__throwAny(env) || !key)\n        goto fail;\n\n    J4AC_android_os_Bundle__putLong(env, thiz, key, value);\n\nfail:\n    J4A_DeleteLocalRef__p(env, &key);\n}\n\nvoid J4AC_android_os_Bundle__putLong__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__, jlong value)\n{\n    jstring key = NULL;\n\n    key = (*env)->NewStringUTF(env, key_cstr__);\n    if (J4A_ExceptionCheck__catchAll(env) || !key)\n        goto fail;\n\n    J4AC_android_os_Bundle__putLong__catchAll(env, thiz, key, value);\n\nfail:\n    J4A_DeleteLocalRef__p(env, &key);\n}\n\nint J4A_loadClass__J4AC_android_os_Bundle(JNIEnv *env)\n{\n    int         ret                   = -1;\n    const char *J4A_UNUSED(name)      = NULL;\n    const char *J4A_UNUSED(sign)      = NULL;\n    jclass      J4A_UNUSED(class_id)  = NULL;\n    int         J4A_UNUSED(api_level) = 0;\n\n    if (class_J4AC_android_os_Bundle.id != NULL)\n        return 0;\n\n    sign = \"android/os/Bundle\";\n    class_J4AC_android_os_Bundle.id = J4A_FindClass__asGlobalRef__catchAll(env, sign);\n    if (class_J4AC_android_os_Bundle.id == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_os_Bundle.id;\n    name     = \"<init>\";\n    sign     = \"()V\";\n    class_J4AC_android_os_Bundle.constructor_Bundle = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_os_Bundle.constructor_Bundle == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_os_Bundle.id;\n    name     = \"getInt\";\n    sign     = \"(Ljava/lang/String;I)I\";\n    class_J4AC_android_os_Bundle.method_getInt = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_os_Bundle.method_getInt == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_os_Bundle.id;\n    name     = \"putInt\";\n    sign     = \"(Ljava/lang/String;I)V\";\n    class_J4AC_android_os_Bundle.method_putInt = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_os_Bundle.method_putInt == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_os_Bundle.id;\n    name     = \"getString\";\n    sign     = \"(Ljava/lang/String;)Ljava/lang/String;\";\n    class_J4AC_android_os_Bundle.method_getString = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_os_Bundle.method_getString == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_os_Bundle.id;\n    name     = \"putString\";\n    sign     = \"(Ljava/lang/String;Ljava/lang/String;)V\";\n    class_J4AC_android_os_Bundle.method_putString = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_os_Bundle.method_putString == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_os_Bundle.id;\n    name     = \"putParcelableArrayList\";\n    sign     = \"(Ljava/lang/String;Ljava/util/ArrayList;)V\";\n    class_J4AC_android_os_Bundle.method_putParcelableArrayList = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_os_Bundle.method_putParcelableArrayList == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_os_Bundle.id;\n    name     = \"getLong\";\n    sign     = \"(Ljava/lang/String;)J\";\n    class_J4AC_android_os_Bundle.method_getLong = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_os_Bundle.method_getLong == NULL)\n        goto fail;\n\n    class_id = class_J4AC_android_os_Bundle.id;\n    name     = \"putLong\";\n    sign     = \"(Ljava/lang/String;J)V\";\n    class_J4AC_android_os_Bundle.method_putLong = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_android_os_Bundle.method_putLong == NULL)\n        goto fail;\n\n    J4A_ALOGD(\"J4ALoader: OK: '%s' loaded\\n\", \"android.os.Bundle\");\n    ret = 0;\nfail:\n    return ret;\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/android/os/Bundle.h",
    "content": "/*\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * https://github.com/Bilibili/jni4android\n * This file is automatically generated by jni4android, do not modify.\n */\n\n#ifndef J4A__android_os_Bundle__H\n#define J4A__android_os_Bundle__H\n\n#include \"j4a/j4a_base.h\"\n\njobject J4AC_android_os_Bundle__Bundle(JNIEnv *env);\njobject J4AC_android_os_Bundle__Bundle__catchAll(JNIEnv *env);\njobject J4AC_android_os_Bundle__Bundle__asGlobalRef__catchAll(JNIEnv *env);\njint J4AC_android_os_Bundle__getInt(JNIEnv *env, jobject thiz, jstring key, jint defaultValue);\njint J4AC_android_os_Bundle__getInt__catchAll(JNIEnv *env, jobject thiz, jstring key, jint defaultValue);\njint J4AC_android_os_Bundle__getInt__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__, jint defaultValue);\njint J4AC_android_os_Bundle__getInt__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__, jint defaultValue);\nvoid J4AC_android_os_Bundle__putInt(JNIEnv *env, jobject thiz, jstring key, jint value);\nvoid J4AC_android_os_Bundle__putInt__catchAll(JNIEnv *env, jobject thiz, jstring key, jint value);\nvoid J4AC_android_os_Bundle__putInt__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__, jint value);\nvoid J4AC_android_os_Bundle__putInt__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__, jint value);\njstring J4AC_android_os_Bundle__getString(JNIEnv *env, jobject thiz, jstring key);\njstring J4AC_android_os_Bundle__getString__catchAll(JNIEnv *env, jobject thiz, jstring key);\njstring J4AC_android_os_Bundle__getString__asGlobalRef__catchAll(JNIEnv *env, jobject thiz, jstring key);\nconst char *J4AC_android_os_Bundle__getString__asCBuffer(JNIEnv *env, jobject thiz, jstring key, char *out_buf, int out_len);\nconst char *J4AC_android_os_Bundle__getString__asCBuffer__catchAll(JNIEnv *env, jobject thiz, jstring key, char *out_buf, int out_len);\njstring J4AC_android_os_Bundle__getString__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__);\njstring J4AC_android_os_Bundle__getString__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__);\njstring J4AC_android_os_Bundle__getString__withCString__asGlobalRef__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__);\nconst char *J4AC_android_os_Bundle__getString__withCString__asCBuffer(JNIEnv *env, jobject thiz, const char *key_cstr__, char *out_buf, int out_len);\nconst char *J4AC_android_os_Bundle__getString__withCString__asCBuffer__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__, char *out_buf, int out_len);\nvoid J4AC_android_os_Bundle__putString(JNIEnv *env, jobject thiz, jstring key, jstring value);\nvoid J4AC_android_os_Bundle__putString__catchAll(JNIEnv *env, jobject thiz, jstring key, jstring value);\nvoid J4AC_android_os_Bundle__putString__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__, const char *value_cstr__);\nvoid J4AC_android_os_Bundle__putString__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__, const char *value_cstr__);\nvoid J4AC_android_os_Bundle__putParcelableArrayList(JNIEnv *env, jobject thiz, jstring key, jobject value);\nvoid J4AC_android_os_Bundle__putParcelableArrayList__catchAll(JNIEnv *env, jobject thiz, jstring key, jobject value);\nvoid J4AC_android_os_Bundle__putParcelableArrayList__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__, jobject value);\nvoid J4AC_android_os_Bundle__putParcelableArrayList__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__, jobject value);\njlong J4AC_android_os_Bundle__getLong(JNIEnv *env, jobject thiz, jstring key);\njlong J4AC_android_os_Bundle__getLong__catchAll(JNIEnv *env, jobject thiz, jstring key);\njlong J4AC_android_os_Bundle__getLong__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__);\njlong J4AC_android_os_Bundle__getLong__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__);\nvoid J4AC_android_os_Bundle__putLong(JNIEnv *env, jobject thiz, jstring key, jlong value);\nvoid J4AC_android_os_Bundle__putLong__catchAll(JNIEnv *env, jobject thiz, jstring key, jlong value);\nvoid J4AC_android_os_Bundle__putLong__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__, jlong value);\nvoid J4AC_android_os_Bundle__putLong__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__, jlong value);\nint J4A_loadClass__J4AC_android_os_Bundle(JNIEnv *env);\n\n#define J4A_HAVE_SIMPLE__J4AC_android_os_Bundle\n\n#define J4AC_Bundle__Bundle J4AC_android_os_Bundle__Bundle\n#define J4AC_Bundle__Bundle__asGlobalRef__catchAll J4AC_android_os_Bundle__Bundle__asGlobalRef__catchAll\n#define J4AC_Bundle__Bundle__catchAll J4AC_android_os_Bundle__Bundle__catchAll\n#define J4AC_Bundle__getInt J4AC_android_os_Bundle__getInt\n#define J4AC_Bundle__getInt__catchAll J4AC_android_os_Bundle__getInt__catchAll\n#define J4AC_Bundle__getInt__withCString J4AC_android_os_Bundle__getInt__withCString\n#define J4AC_Bundle__getInt__withCString__catchAll J4AC_android_os_Bundle__getInt__withCString__catchAll\n#define J4AC_Bundle__putInt J4AC_android_os_Bundle__putInt\n#define J4AC_Bundle__putInt__catchAll J4AC_android_os_Bundle__putInt__catchAll\n#define J4AC_Bundle__putInt__withCString J4AC_android_os_Bundle__putInt__withCString\n#define J4AC_Bundle__putInt__withCString__catchAll J4AC_android_os_Bundle__putInt__withCString__catchAll\n#define J4AC_Bundle__getString J4AC_android_os_Bundle__getString\n#define J4AC_Bundle__getString__asCBuffer J4AC_android_os_Bundle__getString__asCBuffer\n#define J4AC_Bundle__getString__asCBuffer__catchAll J4AC_android_os_Bundle__getString__asCBuffer__catchAll\n#define J4AC_Bundle__getString__asGlobalRef__catchAll J4AC_android_os_Bundle__getString__asGlobalRef__catchAll\n#define J4AC_Bundle__getString__catchAll J4AC_android_os_Bundle__getString__catchAll\n#define J4AC_Bundle__getString__withCString J4AC_android_os_Bundle__getString__withCString\n#define J4AC_Bundle__getString__withCString__asCBuffer J4AC_android_os_Bundle__getString__withCString__asCBuffer\n#define J4AC_Bundle__getString__withCString__asCBuffer__catchAll J4AC_android_os_Bundle__getString__withCString__asCBuffer__catchAll\n#define J4AC_Bundle__getString__withCString__asGlobalRef__catchAll J4AC_android_os_Bundle__getString__withCString__asGlobalRef__catchAll\n#define J4AC_Bundle__getString__withCString__catchAll J4AC_android_os_Bundle__getString__withCString__catchAll\n#define J4AC_Bundle__putString J4AC_android_os_Bundle__putString\n#define J4AC_Bundle__putString__catchAll J4AC_android_os_Bundle__putString__catchAll\n#define J4AC_Bundle__putString__withCString J4AC_android_os_Bundle__putString__withCString\n#define J4AC_Bundle__putString__withCString__catchAll J4AC_android_os_Bundle__putString__withCString__catchAll\n#define J4AC_Bundle__putParcelableArrayList J4AC_android_os_Bundle__putParcelableArrayList\n#define J4AC_Bundle__putParcelableArrayList__catchAll J4AC_android_os_Bundle__putParcelableArrayList__catchAll\n#define J4AC_Bundle__putParcelableArrayList__withCString J4AC_android_os_Bundle__putParcelableArrayList__withCString\n#define J4AC_Bundle__putParcelableArrayList__withCString__catchAll J4AC_android_os_Bundle__putParcelableArrayList__withCString__catchAll\n#define J4AC_Bundle__getLong J4AC_android_os_Bundle__getLong\n#define J4AC_Bundle__getLong__catchAll J4AC_android_os_Bundle__getLong__catchAll\n#define J4AC_Bundle__getLong__withCString J4AC_android_os_Bundle__getLong__withCString\n#define J4AC_Bundle__getLong__withCString__catchAll J4AC_android_os_Bundle__getLong__withCString__catchAll\n#define J4AC_Bundle__putLong J4AC_android_os_Bundle__putLong\n#define J4AC_Bundle__putLong__catchAll J4AC_android_os_Bundle__putLong__catchAll\n#define J4AC_Bundle__putLong__withCString J4AC_android_os_Bundle__putLong__withCString\n#define J4AC_Bundle__putLong__withCString__catchAll J4AC_android_os_Bundle__putLong__withCString__catchAll\n#define J4A_loadClass__J4AC_Bundle J4A_loadClass__J4AC_android_os_Bundle\n\n#endif//J4A__android_os_Bundle__H\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/android/os/Bundle.include.j4a",
    "content": "#include \"j4a/class/android/os/Bundle.h\""
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/android/os/Bundle.loader.j4a",
    "content": "    J4A_LOAD_CLASS(android_os_Bundle);"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/java/nio/Buffer.c",
    "content": "/*\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * https://github.com/Bilibili/jni4android\n * This file is automatically generated by jni4android, do not modify.\n */\n\n#include \"Buffer.h\"\n\ntypedef struct J4AC_java_nio_Buffer {\n    jclass id;\n} J4AC_java_nio_Buffer;\nstatic J4AC_java_nio_Buffer class_J4AC_java_nio_Buffer;\n\nint J4A_loadClass__J4AC_java_nio_Buffer(JNIEnv *env)\n{\n    int         ret                   = -1;\n    const char *J4A_UNUSED(name)      = NULL;\n    const char *J4A_UNUSED(sign)      = NULL;\n    jclass      J4A_UNUSED(class_id)  = NULL;\n    int         J4A_UNUSED(api_level) = 0;\n\n    if (class_J4AC_java_nio_Buffer.id != NULL)\n        return 0;\n\n    sign = \"java/nio/Buffer\";\n    class_J4AC_java_nio_Buffer.id = J4A_FindClass__asGlobalRef__catchAll(env, sign);\n    if (class_J4AC_java_nio_Buffer.id == NULL)\n        goto fail;\n\n    J4A_ALOGD(\"J4ALoader: OK: '%s' loaded\\n\", \"java.nio.Buffer\");\n    ret = 0;\nfail:\n    return ret;\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/java/nio/Buffer.h",
    "content": "/*\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * https://github.com/Bilibili/jni4android\n * This file is automatically generated by jni4android, do not modify.\n */\n\n#ifndef J4A__java_nio_Buffer__H\n#define J4A__java_nio_Buffer__H\n\n#include \"j4a/j4a_base.h\"\n\nint J4A_loadClass__J4AC_java_nio_Buffer(JNIEnv *env);\n\n#endif//J4A__java_nio_Buffer__H\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/java/nio/Buffer.include.j4a",
    "content": "#include \"j4a/class/java/nio/Buffer.h\""
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/java/nio/Buffer.loader.j4a",
    "content": "    J4A_LOAD_CLASS(java_nio_Buffer);"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/java/nio/ByteBuffer.c",
    "content": "/*\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * https://github.com/Bilibili/jni4android\n * This file is automatically generated by jni4android, do not modify.\n */\n\n#include \"ByteBuffer.h\"\n\ntypedef struct J4AC_java_nio_ByteBuffer {\n    jclass id;\n\n    jmethodID method_allocate;\n    jmethodID method_allocateDirect;\n    jmethodID method_limit;\n} J4AC_java_nio_ByteBuffer;\nstatic J4AC_java_nio_ByteBuffer class_J4AC_java_nio_ByteBuffer;\n\njobject J4AC_java_nio_ByteBuffer__allocate(JNIEnv *env, jint capacity)\n{\n    return (*env)->CallStaticObjectMethod(env, class_J4AC_java_nio_ByteBuffer.id, class_J4AC_java_nio_ByteBuffer.method_allocate, capacity);\n}\n\njobject J4AC_java_nio_ByteBuffer__allocate__catchAll(JNIEnv *env, jint capacity)\n{\n    jobject ret_object = J4AC_java_nio_ByteBuffer__allocate(env, capacity);\n    if (J4A_ExceptionCheck__catchAll(env) || !ret_object) {\n        return NULL;\n    }\n\n    return ret_object;\n}\n\njobject J4AC_java_nio_ByteBuffer__allocate__asGlobalRef__catchAll(JNIEnv *env, jint capacity)\n{\n    jobject ret_object   = NULL;\n    jobject local_object = J4AC_java_nio_ByteBuffer__allocate__catchAll(env, capacity);\n    if (J4A_ExceptionCheck__catchAll(env) || !local_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\n    ret_object = J4A_NewGlobalRef__catchAll(env, local_object);\n    if (!ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &local_object);\n    return ret_object;\n}\n\njobject J4AC_java_nio_ByteBuffer__allocateDirect(JNIEnv *env, jint capacity)\n{\n    return (*env)->CallStaticObjectMethod(env, class_J4AC_java_nio_ByteBuffer.id, class_J4AC_java_nio_ByteBuffer.method_allocateDirect, capacity);\n}\n\njobject J4AC_java_nio_ByteBuffer__allocateDirect__catchAll(JNIEnv *env, jint capacity)\n{\n    jobject ret_object = J4AC_java_nio_ByteBuffer__allocateDirect(env, capacity);\n    if (J4A_ExceptionCheck__catchAll(env) || !ret_object) {\n        return NULL;\n    }\n\n    return ret_object;\n}\n\njobject J4AC_java_nio_ByteBuffer__allocateDirect__asGlobalRef__catchAll(JNIEnv *env, jint capacity)\n{\n    jobject ret_object   = NULL;\n    jobject local_object = J4AC_java_nio_ByteBuffer__allocateDirect__catchAll(env, capacity);\n    if (J4A_ExceptionCheck__catchAll(env) || !local_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\n    ret_object = J4A_NewGlobalRef__catchAll(env, local_object);\n    if (!ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &local_object);\n    return ret_object;\n}\n\njobject J4AC_java_nio_ByteBuffer__limit(JNIEnv *env, jobject thiz, jint newLimit)\n{\n    return (*env)->CallObjectMethod(env, thiz, class_J4AC_java_nio_ByteBuffer.method_limit, newLimit);\n}\n\njobject J4AC_java_nio_ByteBuffer__limit__catchAll(JNIEnv *env, jobject thiz, jint newLimit)\n{\n    jobject ret_object = J4AC_java_nio_ByteBuffer__limit(env, thiz, newLimit);\n    if (J4A_ExceptionCheck__catchAll(env) || !ret_object) {\n        return NULL;\n    }\n\n    return ret_object;\n}\n\njobject J4AC_java_nio_ByteBuffer__limit__asGlobalRef__catchAll(JNIEnv *env, jobject thiz, jint newLimit)\n{\n    jobject ret_object   = NULL;\n    jobject local_object = J4AC_java_nio_ByteBuffer__limit__catchAll(env, thiz, newLimit);\n    if (J4A_ExceptionCheck__catchAll(env) || !local_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\n    ret_object = J4A_NewGlobalRef__catchAll(env, local_object);\n    if (!ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &local_object);\n    return ret_object;\n}\n\nint J4A_loadClass__J4AC_java_nio_ByteBuffer(JNIEnv *env)\n{\n    int         ret                   = -1;\n    const char *J4A_UNUSED(name)      = NULL;\n    const char *J4A_UNUSED(sign)      = NULL;\n    jclass      J4A_UNUSED(class_id)  = NULL;\n    int         J4A_UNUSED(api_level) = 0;\n\n    if (class_J4AC_java_nio_ByteBuffer.id != NULL)\n        return 0;\n\n    sign = \"java/nio/ByteBuffer\";\n    class_J4AC_java_nio_ByteBuffer.id = J4A_FindClass__asGlobalRef__catchAll(env, sign);\n    if (class_J4AC_java_nio_ByteBuffer.id == NULL)\n        goto fail;\n\n    class_id = class_J4AC_java_nio_ByteBuffer.id;\n    name     = \"allocate\";\n    sign     = \"(I)Ljava/nio/ByteBuffer;\";\n    class_J4AC_java_nio_ByteBuffer.method_allocate = J4A_GetStaticMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_java_nio_ByteBuffer.method_allocate == NULL)\n        goto fail;\n\n    class_id = class_J4AC_java_nio_ByteBuffer.id;\n    name     = \"allocateDirect\";\n    sign     = \"(I)Ljava/nio/ByteBuffer;\";\n    class_J4AC_java_nio_ByteBuffer.method_allocateDirect = J4A_GetStaticMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_java_nio_ByteBuffer.method_allocateDirect == NULL)\n        goto fail;\n\n    class_id = class_J4AC_java_nio_ByteBuffer.id;\n    name     = \"limit\";\n    sign     = \"(I)Ljava/nio/Buffer;\";\n    class_J4AC_java_nio_ByteBuffer.method_limit = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_java_nio_ByteBuffer.method_limit == NULL)\n        goto fail;\n\n    J4A_ALOGD(\"J4ALoader: OK: '%s' loaded\\n\", \"java.nio.ByteBuffer\");\n    ret = 0;\nfail:\n    return ret;\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/java/nio/ByteBuffer.h",
    "content": "/*\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * https://github.com/Bilibili/jni4android\n * This file is automatically generated by jni4android, do not modify.\n */\n\n#ifndef J4A__java_nio_ByteBuffer__H\n#define J4A__java_nio_ByteBuffer__H\n\n#include \"j4a/j4a_base.h\"\n\njobject J4AC_java_nio_ByteBuffer__allocate(JNIEnv *env, jint capacity);\njobject J4AC_java_nio_ByteBuffer__allocate__catchAll(JNIEnv *env, jint capacity);\njobject J4AC_java_nio_ByteBuffer__allocate__asGlobalRef__catchAll(JNIEnv *env, jint capacity);\njobject J4AC_java_nio_ByteBuffer__allocateDirect(JNIEnv *env, jint capacity);\njobject J4AC_java_nio_ByteBuffer__allocateDirect__catchAll(JNIEnv *env, jint capacity);\njobject J4AC_java_nio_ByteBuffer__allocateDirect__asGlobalRef__catchAll(JNIEnv *env, jint capacity);\njobject J4AC_java_nio_ByteBuffer__limit(JNIEnv *env, jobject thiz, jint newLimit);\njobject J4AC_java_nio_ByteBuffer__limit__catchAll(JNIEnv *env, jobject thiz, jint newLimit);\njobject J4AC_java_nio_ByteBuffer__limit__asGlobalRef__catchAll(JNIEnv *env, jobject thiz, jint newLimit);\nint J4A_loadClass__J4AC_java_nio_ByteBuffer(JNIEnv *env);\n\n#define J4A_HAVE_SIMPLE__J4AC_java_nio_ByteBuffer\n\n#define J4AC_ByteBuffer__allocate J4AC_java_nio_ByteBuffer__allocate\n#define J4AC_ByteBuffer__allocate__asGlobalRef__catchAll J4AC_java_nio_ByteBuffer__allocate__asGlobalRef__catchAll\n#define J4AC_ByteBuffer__allocate__catchAll J4AC_java_nio_ByteBuffer__allocate__catchAll\n#define J4AC_ByteBuffer__allocateDirect J4AC_java_nio_ByteBuffer__allocateDirect\n#define J4AC_ByteBuffer__allocateDirect__asGlobalRef__catchAll J4AC_java_nio_ByteBuffer__allocateDirect__asGlobalRef__catchAll\n#define J4AC_ByteBuffer__allocateDirect__catchAll J4AC_java_nio_ByteBuffer__allocateDirect__catchAll\n#define J4AC_ByteBuffer__limit J4AC_java_nio_ByteBuffer__limit\n#define J4AC_ByteBuffer__limit__asGlobalRef__catchAll J4AC_java_nio_ByteBuffer__limit__asGlobalRef__catchAll\n#define J4AC_ByteBuffer__limit__catchAll J4AC_java_nio_ByteBuffer__limit__catchAll\n#define J4A_loadClass__J4AC_ByteBuffer J4A_loadClass__J4AC_java_nio_ByteBuffer\n\n#endif//J4A__java_nio_ByteBuffer__H\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/java/nio/ByteBuffer.include.j4a",
    "content": "#include \"j4a/class/java/nio/ByteBuffer.h\""
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/java/nio/ByteBuffer.loader.j4a",
    "content": "    J4A_LOAD_CLASS(java_nio_ByteBuffer);"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/java/util/ArrayList.c",
    "content": "/*\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * https://github.com/Bilibili/jni4android\n * This file is automatically generated by jni4android, do not modify.\n */\n\n#include \"ArrayList.h\"\n\ntypedef struct J4AC_java_util_ArrayList {\n    jclass id;\n\n    jmethodID constructor_ArrayList;\n    jmethodID method_add;\n} J4AC_java_util_ArrayList;\nstatic J4AC_java_util_ArrayList class_J4AC_java_util_ArrayList;\n\njobject J4AC_java_util_ArrayList__ArrayList(JNIEnv *env)\n{\n    return (*env)->NewObject(env, class_J4AC_java_util_ArrayList.id, class_J4AC_java_util_ArrayList.constructor_ArrayList);\n}\n\njobject J4AC_java_util_ArrayList__ArrayList__catchAll(JNIEnv *env)\n{\n    jobject ret_object = J4AC_java_util_ArrayList__ArrayList(env);\n    if (J4A_ExceptionCheck__catchAll(env) || !ret_object) {\n        return NULL;\n    }\n\n    return ret_object;\n}\n\njobject J4AC_java_util_ArrayList__ArrayList__asGlobalRef__catchAll(JNIEnv *env)\n{\n    jobject ret_object   = NULL;\n    jobject local_object = J4AC_java_util_ArrayList__ArrayList__catchAll(env);\n    if (J4A_ExceptionCheck__catchAll(env) || !local_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\n    ret_object = J4A_NewGlobalRef__catchAll(env, local_object);\n    if (!ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &local_object);\n    return ret_object;\n}\n\njboolean J4AC_java_util_ArrayList__add(JNIEnv *env, jobject thiz, jobject object)\n{\n    return (*env)->CallBooleanMethod(env, thiz, class_J4AC_java_util_ArrayList.method_add, object);\n}\n\njboolean J4AC_java_util_ArrayList__add__catchAll(JNIEnv *env, jobject thiz, jobject object)\n{\n    jboolean ret_value = J4AC_java_util_ArrayList__add(env, thiz, object);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return false;\n    }\n\n    return ret_value;\n}\n\nint J4A_loadClass__J4AC_java_util_ArrayList(JNIEnv *env)\n{\n    int         ret                   = -1;\n    const char *J4A_UNUSED(name)      = NULL;\n    const char *J4A_UNUSED(sign)      = NULL;\n    jclass      J4A_UNUSED(class_id)  = NULL;\n    int         J4A_UNUSED(api_level) = 0;\n\n    if (class_J4AC_java_util_ArrayList.id != NULL)\n        return 0;\n\n    sign = \"java/util/ArrayList\";\n    class_J4AC_java_util_ArrayList.id = J4A_FindClass__asGlobalRef__catchAll(env, sign);\n    if (class_J4AC_java_util_ArrayList.id == NULL)\n        goto fail;\n\n    class_id = class_J4AC_java_util_ArrayList.id;\n    name     = \"<init>\";\n    sign     = \"()V\";\n    class_J4AC_java_util_ArrayList.constructor_ArrayList = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_java_util_ArrayList.constructor_ArrayList == NULL)\n        goto fail;\n\n    class_id = class_J4AC_java_util_ArrayList.id;\n    name     = \"add\";\n    sign     = \"(Ljava/lang/Object;)Z\";\n    class_J4AC_java_util_ArrayList.method_add = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_java_util_ArrayList.method_add == NULL)\n        goto fail;\n\n    J4A_ALOGD(\"J4ALoader: OK: '%s' loaded\\n\", \"java.util.ArrayList\");\n    ret = 0;\nfail:\n    return ret;\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/java/util/ArrayList.h",
    "content": "/*\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * https://github.com/Bilibili/jni4android\n * This file is automatically generated by jni4android, do not modify.\n */\n\n#ifndef J4A__java_util_ArrayList__H\n#define J4A__java_util_ArrayList__H\n\n#include \"j4a/j4a_base.h\"\n\njobject J4AC_java_util_ArrayList__ArrayList(JNIEnv *env);\njobject J4AC_java_util_ArrayList__ArrayList__catchAll(JNIEnv *env);\njobject J4AC_java_util_ArrayList__ArrayList__asGlobalRef__catchAll(JNIEnv *env);\njboolean J4AC_java_util_ArrayList__add(JNIEnv *env, jobject thiz, jobject object);\njboolean J4AC_java_util_ArrayList__add__catchAll(JNIEnv *env, jobject thiz, jobject object);\nint J4A_loadClass__J4AC_java_util_ArrayList(JNIEnv *env);\n\n#define J4A_HAVE_SIMPLE__J4AC_java_util_ArrayList\n\n#define J4AC_ArrayList__ArrayList J4AC_java_util_ArrayList__ArrayList\n#define J4AC_ArrayList__ArrayList__asGlobalRef__catchAll J4AC_java_util_ArrayList__ArrayList__asGlobalRef__catchAll\n#define J4AC_ArrayList__ArrayList__catchAll J4AC_java_util_ArrayList__ArrayList__catchAll\n#define J4AC_ArrayList__add J4AC_java_util_ArrayList__add\n#define J4AC_ArrayList__add__catchAll J4AC_java_util_ArrayList__add__catchAll\n#define J4A_loadClass__J4AC_ArrayList J4A_loadClass__J4AC_java_util_ArrayList\n\n#endif//J4A__java_util_ArrayList__H\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/java/util/ArrayList.include.j4a",
    "content": "#include \"j4a/class/java/util/ArrayList.h\""
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/java/util/ArrayList.loader.j4a",
    "content": "    J4A_LOAD_CLASS(java_util_ArrayList);"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/tv/danmaku/ijk/media/player/IjkMediaPlayer.c",
    "content": "/*\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * https://github.com/Bilibili/jni4android\n * This file is automatically generated by jni4android, do not modify.\n */\n\n#include \"IjkMediaPlayer.h\"\n\ntypedef struct J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer {\n    jclass id;\n\n    jfieldID field_mNativeMediaPlayer;\n    jfieldID field_mNativeMediaDataSource;\n    jfieldID field_mNativeAndroidIO;\n    jmethodID method_postEventFromNative;\n    jmethodID method_onSelectCodec;\n    jmethodID method_onNativeInvoke;\n} J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer;\nstatic J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer;\n\njlong J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__get(JNIEnv *env, jobject thiz)\n{\n    return (*env)->GetLongField(env, thiz, class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.field_mNativeMediaPlayer);\n}\n\njlong J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__get__catchAll(JNIEnv *env, jobject thiz)\n{\n    jlong ret_value = J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__get(env, thiz);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\nvoid J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__set(JNIEnv *env, jobject thiz, jlong value)\n{\n    (*env)->SetLongField(env, thiz, class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.field_mNativeMediaPlayer, value);\n}\n\nvoid J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__set__catchAll(JNIEnv *env, jobject thiz, jlong value)\n{\n    J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__set(env, thiz, value);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\njlong J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__get(JNIEnv *env, jobject thiz)\n{\n    return (*env)->GetLongField(env, thiz, class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.field_mNativeMediaDataSource);\n}\n\njlong J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__get__catchAll(JNIEnv *env, jobject thiz)\n{\n    jlong ret_value = J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__get(env, thiz);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\nvoid J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__set(JNIEnv *env, jobject thiz, jlong value)\n{\n    (*env)->SetLongField(env, thiz, class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.field_mNativeMediaDataSource, value);\n}\n\nvoid J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__set__catchAll(JNIEnv *env, jobject thiz, jlong value)\n{\n    J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__set(env, thiz, value);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\njlong J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__get(JNIEnv *env, jobject thiz)\n{\n    return (*env)->GetLongField(env, thiz, class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.field_mNativeAndroidIO);\n}\n\njlong J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__get__catchAll(JNIEnv *env, jobject thiz)\n{\n    jlong ret_value = J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__get(env, thiz);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\nvoid J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__set(JNIEnv *env, jobject thiz, jlong value)\n{\n    (*env)->SetLongField(env, thiz, class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.field_mNativeAndroidIO, value);\n}\n\nvoid J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__set__catchAll(JNIEnv *env, jobject thiz, jlong value)\n{\n    J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__set(env, thiz, value);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\nvoid J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__postEventFromNative(JNIEnv *env, jobject weakThiz, jint what, jint arg1, jint arg2, jobject obj)\n{\n    (*env)->CallStaticVoidMethod(env, class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.id, class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.method_postEventFromNative, weakThiz, what, arg1, arg2, obj);\n}\n\nvoid J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__postEventFromNative__catchAll(JNIEnv *env, jobject weakThiz, jint what, jint arg1, jint arg2, jobject obj)\n{\n    J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__postEventFromNative(env, weakThiz, what, arg1, arg2, obj);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\njstring J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec(JNIEnv *env, jobject weakThiz, jstring mimeType, jint profile, jint level)\n{\n    return (*env)->CallStaticObjectMethod(env, class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.id, class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.method_onSelectCodec, weakThiz, mimeType, profile, level);\n}\n\njstring J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__catchAll(JNIEnv *env, jobject weakThiz, jstring mimeType, jint profile, jint level)\n{\n    jstring ret_object = J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec(env, weakThiz, mimeType, profile, level);\n    if (J4A_ExceptionCheck__catchAll(env) || !ret_object) {\n        return NULL;\n    }\n\n    return ret_object;\n}\n\njstring J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__asGlobalRef__catchAll(JNIEnv *env, jobject weakThiz, jstring mimeType, jint profile, jint level)\n{\n    jstring ret_object   = NULL;\n    jstring local_object = J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__catchAll(env, weakThiz, mimeType, profile, level);\n    if (J4A_ExceptionCheck__catchAll(env) || !local_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\n    ret_object = J4A_NewGlobalRef__catchAll(env, local_object);\n    if (!ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &local_object);\n    return ret_object;\n}\n\nconst char *J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__asCBuffer(JNIEnv *env, jobject weakThiz, jstring mimeType, jint profile, jint level, char *out_buf, int out_len)\n{\n    const char *ret_value = NULL;\n    const char *c_str     = NULL;\n    jstring local_string = J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec(env, weakThiz, mimeType, profile, level);\n    if (J4A_ExceptionCheck__throwAny(env) || !local_string) {\n        goto fail;\n    }\n\n    c_str = (*env)->GetStringUTFChars(env, local_string, NULL );\n    if (J4A_ExceptionCheck__throwAny(env) || !c_str) {\n        goto fail;\n    }\n\n    strlcpy(out_buf, c_str, out_len);\n    ret_value = out_buf;\n\nfail:\n    J4A_ReleaseStringUTFChars__p(env, local_string, &c_str);\n    J4A_DeleteLocalRef__p(env, &local_string);\n    return ret_value;\n}\n\nconst char *J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__asCBuffer__catchAll(JNIEnv *env, jobject weakThiz, jstring mimeType, jint profile, jint level, char *out_buf, int out_len)\n{\n    const char *ret_value = NULL;\n    const char *c_str     = NULL;\n    jstring local_string = J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__catchAll(env, weakThiz, mimeType, profile, level);\n    if (J4A_ExceptionCheck__catchAll(env) || !local_string) {\n        goto fail;\n    }\n\n    c_str = (*env)->GetStringUTFChars(env, local_string, NULL );\n    if (J4A_ExceptionCheck__catchAll(env) || !c_str) {\n        goto fail;\n    }\n\n    strlcpy(out_buf, c_str, out_len);\n    ret_value = out_buf;\n\nfail:\n    J4A_ReleaseStringUTFChars__p(env, local_string, &c_str);\n    J4A_DeleteLocalRef__p(env, &local_string);\n    return ret_value;\n}\n\njstring J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString(JNIEnv *env, jobject weakThiz, const char *mimeType_cstr__, jint profile, jint level)\n{\n    jstring ret_object = NULL;\n    jstring mimeType = NULL;\n\n    mimeType = (*env)->NewStringUTF(env, mimeType_cstr__);\n    if (J4A_ExceptionCheck__throwAny(env) || !mimeType)\n        goto fail;\n\n    ret_object = J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec(env, weakThiz, mimeType, profile, level);\n    if (J4A_ExceptionCheck__throwAny(env) || !ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &mimeType);\n    return ret_object;\n}\n\njstring J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__catchAll(JNIEnv *env, jobject weakThiz, const char *mimeType_cstr__, jint profile, jint level)\n{\n    jstring ret_object = NULL;\n    jstring mimeType = NULL;\n\n    mimeType = (*env)->NewStringUTF(env, mimeType_cstr__);\n    if (J4A_ExceptionCheck__catchAll(env) || !mimeType)\n        goto fail;\n\n    ret_object = J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__catchAll(env, weakThiz, mimeType, profile, level);\n    if (J4A_ExceptionCheck__catchAll(env) || !ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &mimeType);\n    return ret_object;\n}\n\njstring J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__asGlobalRef__catchAll(JNIEnv *env, jobject weakThiz, const char *mimeType_cstr__, jint profile, jint level)\n{\n    jstring ret_object   = NULL;\n    jstring local_object = J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__catchAll(env, weakThiz, mimeType_cstr__, profile, level);\n    if (J4A_ExceptionCheck__catchAll(env) || !local_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\n    ret_object = J4A_NewGlobalRef__catchAll(env, local_object);\n    if (!ret_object) {\n        ret_object = NULL;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &local_object);\n    return ret_object;\n}\n\nconst char *J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__asCBuffer(JNIEnv *env, jobject weakThiz, const char *mimeType_cstr__, jint profile, jint level, char *out_buf, int out_len)\n{\n    const char *ret_value = NULL;\n    const char *c_str     = NULL;\n    jstring local_string = J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString(env, weakThiz, mimeType_cstr__, profile, level);\n    if (J4A_ExceptionCheck__throwAny(env) || !local_string) {\n        goto fail;\n    }\n\n    c_str = (*env)->GetStringUTFChars(env, local_string, NULL );\n    if (J4A_ExceptionCheck__throwAny(env) || !c_str) {\n        goto fail;\n    }\n\n    strlcpy(out_buf, c_str, out_len);\n    ret_value = out_buf;\n\nfail:\n    J4A_ReleaseStringUTFChars__p(env, local_string, &c_str);\n    J4A_DeleteLocalRef__p(env, &local_string);\n    return ret_value;\n}\n\nconst char *J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__asCBuffer__catchAll(JNIEnv *env, jobject weakThiz, const char *mimeType_cstr__, jint profile, jint level, char *out_buf, int out_len)\n{\n    const char *ret_value = NULL;\n    const char *c_str     = NULL;\n    jstring local_string = J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__catchAll(env, weakThiz, mimeType_cstr__, profile, level);\n    if (J4A_ExceptionCheck__catchAll(env) || !local_string) {\n        goto fail;\n    }\n\n    c_str = (*env)->GetStringUTFChars(env, local_string, NULL );\n    if (J4A_ExceptionCheck__catchAll(env) || !c_str) {\n        goto fail;\n    }\n\n    strlcpy(out_buf, c_str, out_len);\n    ret_value = out_buf;\n\nfail:\n    J4A_ReleaseStringUTFChars__p(env, local_string, &c_str);\n    J4A_DeleteLocalRef__p(env, &local_string);\n    return ret_value;\n}\n\njboolean J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onNativeInvoke(JNIEnv *env, jobject weakThiz, jint what, jobject args)\n{\n    return (*env)->CallStaticBooleanMethod(env, class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.id, class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.method_onNativeInvoke, weakThiz, what, args);\n}\n\njboolean J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onNativeInvoke__catchAll(JNIEnv *env, jobject weakThiz, jint what, jobject args)\n{\n    jboolean ret_value = J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onNativeInvoke(env, weakThiz, what, args);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return false;\n    }\n\n    return ret_value;\n}\n\nint J4A_loadClass__J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer(JNIEnv *env)\n{\n    int         ret                   = -1;\n    const char *J4A_UNUSED(name)      = NULL;\n    const char *J4A_UNUSED(sign)      = NULL;\n    jclass      J4A_UNUSED(class_id)  = NULL;\n    int         J4A_UNUSED(api_level) = 0;\n\n    if (class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.id != NULL)\n        return 0;\n\n    sign = \"tv/danmaku/ijk/media/player/IjkMediaPlayer\";\n    class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.id = J4A_FindClass__asGlobalRef__catchAll(env, sign);\n    if (class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.id == NULL)\n        goto fail;\n\n    class_id = class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.id;\n    name     = \"mNativeMediaPlayer\";\n    sign     = \"J\";\n    class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.field_mNativeMediaPlayer = J4A_GetFieldID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.field_mNativeMediaPlayer == NULL)\n        goto fail;\n\n    class_id = class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.id;\n    name     = \"mNativeMediaDataSource\";\n    sign     = \"J\";\n    class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.field_mNativeMediaDataSource = J4A_GetFieldID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.field_mNativeMediaDataSource == NULL)\n        goto fail;\n\n    class_id = class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.id;\n    name     = \"mNativeAndroidIO\";\n    sign     = \"J\";\n    class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.field_mNativeAndroidIO = J4A_GetFieldID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.field_mNativeAndroidIO == NULL)\n        goto fail;\n\n    class_id = class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.id;\n    name     = \"postEventFromNative\";\n    sign     = \"(Ljava/lang/Object;IIILjava/lang/Object;)V\";\n    class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.method_postEventFromNative = J4A_GetStaticMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.method_postEventFromNative == NULL)\n        goto fail;\n\n    class_id = class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.id;\n    name     = \"onSelectCodec\";\n    sign     = \"(Ljava/lang/Object;Ljava/lang/String;II)Ljava/lang/String;\";\n    class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.method_onSelectCodec = J4A_GetStaticMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.method_onSelectCodec == NULL)\n        goto fail;\n\n    class_id = class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.id;\n    name     = \"onNativeInvoke\";\n    sign     = \"(Ljava/lang/Object;ILandroid/os/Bundle;)Z\";\n    class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.method_onNativeInvoke = J4A_GetStaticMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.method_onNativeInvoke == NULL)\n        goto fail;\n\n    J4A_ALOGD(\"J4ALoader: OK: '%s' loaded\\n\", \"tv.danmaku.ijk.media.player.IjkMediaPlayer\");\n    ret = 0;\nfail:\n    return ret;\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/tv/danmaku/ijk/media/player/IjkMediaPlayer.h",
    "content": "/*\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * https://github.com/Bilibili/jni4android\n * This file is automatically generated by jni4android, do not modify.\n */\n\n#ifndef J4A__tv_danmaku_ijk_media_player_IjkMediaPlayer__H\n#define J4A__tv_danmaku_ijk_media_player_IjkMediaPlayer__H\n\n#include \"j4a/j4a_base.h\"\n\njlong J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__get(JNIEnv *env, jobject thiz);\njlong J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__get__catchAll(JNIEnv *env, jobject thiz);\nvoid J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__set(JNIEnv *env, jobject thiz, jlong value);\nvoid J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__set__catchAll(JNIEnv *env, jobject thiz, jlong value);\njlong J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__get(JNIEnv *env, jobject thiz);\njlong J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__get__catchAll(JNIEnv *env, jobject thiz);\nvoid J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__set(JNIEnv *env, jobject thiz, jlong value);\nvoid J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__set__catchAll(JNIEnv *env, jobject thiz, jlong value);\njlong J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__get(JNIEnv *env, jobject thiz);\njlong J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__get__catchAll(JNIEnv *env, jobject thiz);\nvoid J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__set(JNIEnv *env, jobject thiz, jlong value);\nvoid J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__set__catchAll(JNIEnv *env, jobject thiz, jlong value);\nvoid J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__postEventFromNative(JNIEnv *env, jobject weakThiz, jint what, jint arg1, jint arg2, jobject obj);\nvoid J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__postEventFromNative__catchAll(JNIEnv *env, jobject weakThiz, jint what, jint arg1, jint arg2, jobject obj);\njstring J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec(JNIEnv *env, jobject weakThiz, jstring mimeType, jint profile, jint level);\njstring J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__catchAll(JNIEnv *env, jobject weakThiz, jstring mimeType, jint profile, jint level);\njstring J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__asGlobalRef__catchAll(JNIEnv *env, jobject weakThiz, jstring mimeType, jint profile, jint level);\nconst char *J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__asCBuffer(JNIEnv *env, jobject weakThiz, jstring mimeType, jint profile, jint level, char *out_buf, int out_len);\nconst char *J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__asCBuffer__catchAll(JNIEnv *env, jobject weakThiz, jstring mimeType, jint profile, jint level, char *out_buf, int out_len);\njstring J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString(JNIEnv *env, jobject weakThiz, const char *mimeType_cstr__, jint profile, jint level);\njstring J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__catchAll(JNIEnv *env, jobject weakThiz, const char *mimeType_cstr__, jint profile, jint level);\njstring J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__asGlobalRef__catchAll(JNIEnv *env, jobject weakThiz, const char *mimeType_cstr__, jint profile, jint level);\nconst char *J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__asCBuffer(JNIEnv *env, jobject weakThiz, const char *mimeType_cstr__, jint profile, jint level, char *out_buf, int out_len);\nconst char *J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__asCBuffer__catchAll(JNIEnv *env, jobject weakThiz, const char *mimeType_cstr__, jint profile, jint level, char *out_buf, int out_len);\njboolean J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onNativeInvoke(JNIEnv *env, jobject weakThiz, jint what, jobject args);\njboolean J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onNativeInvoke__catchAll(JNIEnv *env, jobject weakThiz, jint what, jobject args);\nint J4A_loadClass__J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer(JNIEnv *env);\n\n#define J4A_HAVE_SIMPLE__J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer\n\n#define J4AC_IjkMediaPlayer__mNativeMediaPlayer__get J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__get\n#define J4AC_IjkMediaPlayer__mNativeMediaPlayer__get__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__get__catchAll\n#define J4AC_IjkMediaPlayer__mNativeMediaPlayer__set J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__set\n#define J4AC_IjkMediaPlayer__mNativeMediaPlayer__set__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__set__catchAll\n#define J4AC_IjkMediaPlayer__mNativeMediaDataSource__get J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__get\n#define J4AC_IjkMediaPlayer__mNativeMediaDataSource__get__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__get__catchAll\n#define J4AC_IjkMediaPlayer__mNativeMediaDataSource__set J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__set\n#define J4AC_IjkMediaPlayer__mNativeMediaDataSource__set__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__set__catchAll\n#define J4AC_IjkMediaPlayer__mNativeAndroidIO__get J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__get\n#define J4AC_IjkMediaPlayer__mNativeAndroidIO__get__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__get__catchAll\n#define J4AC_IjkMediaPlayer__mNativeAndroidIO__set J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__set\n#define J4AC_IjkMediaPlayer__mNativeAndroidIO__set__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__set__catchAll\n#define J4AC_IjkMediaPlayer__postEventFromNative J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__postEventFromNative\n#define J4AC_IjkMediaPlayer__postEventFromNative__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__postEventFromNative__catchAll\n#define J4AC_IjkMediaPlayer__onSelectCodec J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec\n#define J4AC_IjkMediaPlayer__onSelectCodec__asCBuffer J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__asCBuffer\n#define J4AC_IjkMediaPlayer__onSelectCodec__asCBuffer__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__asCBuffer__catchAll\n#define J4AC_IjkMediaPlayer__onSelectCodec__asGlobalRef__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__asGlobalRef__catchAll\n#define J4AC_IjkMediaPlayer__onSelectCodec__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__catchAll\n#define J4AC_IjkMediaPlayer__onSelectCodec__withCString J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString\n#define J4AC_IjkMediaPlayer__onSelectCodec__withCString__asCBuffer J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__asCBuffer\n#define J4AC_IjkMediaPlayer__onSelectCodec__withCString__asCBuffer__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__asCBuffer__catchAll\n#define J4AC_IjkMediaPlayer__onSelectCodec__withCString__asGlobalRef__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__asGlobalRef__catchAll\n#define J4AC_IjkMediaPlayer__onSelectCodec__withCString__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__catchAll\n#define J4AC_IjkMediaPlayer__onNativeInvoke J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onNativeInvoke\n#define J4AC_IjkMediaPlayer__onNativeInvoke__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onNativeInvoke__catchAll\n#define J4A_loadClass__J4AC_IjkMediaPlayer J4A_loadClass__J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer\n\n#endif//J4A__tv_danmaku_ijk_media_player_IjkMediaPlayer__H\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/tv/danmaku/ijk/media/player/IjkMediaPlayer.include.j4a",
    "content": "#include \"j4a/class/tv/danmaku/ijk/media/player/IjkMediaPlayer.h\""
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/tv/danmaku/ijk/media/player/IjkMediaPlayer.loader.j4a",
    "content": "    J4A_LOAD_CLASS(tv_danmaku_ijk_media_player_IjkMediaPlayer);"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/tv/danmaku/ijk/media/player/misc/IAndroidIO.c",
    "content": "/*\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * https://github.com/Bilibili/jni4android\n * This file is automatically generated by jni4android, do not modify.\n */\n\n#include \"IAndroidIO.h\"\n\ntypedef struct J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO {\n    jclass id;\n\n    jmethodID method_open;\n    jmethodID method_read;\n    jmethodID method_seek;\n    jmethodID method_close;\n} J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO;\nstatic J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO;\n\njint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open(JNIEnv *env, jobject thiz, jstring url)\n{\n    return (*env)->CallIntMethod(env, thiz, class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.method_open, url);\n}\n\njint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open__catchAll(JNIEnv *env, jobject thiz, jstring url)\n{\n    jint ret_value = J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open(env, thiz, url);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\njint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open__withCString(JNIEnv *env, jobject thiz, const char *url_cstr__)\n{\n    jint ret_value = 0;\n    jstring url = NULL;\n\n    url = (*env)->NewStringUTF(env, url_cstr__);\n    if (J4A_ExceptionCheck__throwAny(env) || !url)\n        goto fail;\n\n    ret_value = J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open(env, thiz, url);\n    if (J4A_ExceptionCheck__throwAny(env)) {\n        ret_value = 0;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &url);\n    return ret_value;\n}\n\njint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open__withCString__catchAll(JNIEnv *env, jobject thiz, const char *url_cstr__)\n{\n    jint ret_value = 0;\n    jstring url = NULL;\n\n    url = (*env)->NewStringUTF(env, url_cstr__);\n    if (J4A_ExceptionCheck__catchAll(env) || !url)\n        goto fail;\n\n    ret_value = J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open__catchAll(env, thiz, url);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        ret_value = 0;\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &url);\n    return ret_value;\n}\n\njint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__read(JNIEnv *env, jobject thiz, jbyteArray buffer, jint size)\n{\n    return (*env)->CallIntMethod(env, thiz, class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.method_read, buffer, size);\n}\n\njint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__read__catchAll(JNIEnv *env, jobject thiz, jbyteArray buffer, jint size)\n{\n    jint ret_value = J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__read(env, thiz, buffer, size);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\njlong J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__seek(JNIEnv *env, jobject thiz, jlong offset, jint whence)\n{\n    return (*env)->CallLongMethod(env, thiz, class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.method_seek, offset, whence);\n}\n\njlong J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__seek__catchAll(JNIEnv *env, jobject thiz, jlong offset, jint whence)\n{\n    jlong ret_value = J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__seek(env, thiz, offset, whence);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\njint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__close(JNIEnv *env, jobject thiz)\n{\n    return (*env)->CallIntMethod(env, thiz, class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.method_close);\n}\n\njint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__close__catchAll(JNIEnv *env, jobject thiz)\n{\n    jint ret_value = J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__close(env, thiz);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\nint J4A_loadClass__J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO(JNIEnv *env)\n{\n    int         ret                   = -1;\n    const char *J4A_UNUSED(name)      = NULL;\n    const char *J4A_UNUSED(sign)      = NULL;\n    jclass      J4A_UNUSED(class_id)  = NULL;\n    int         J4A_UNUSED(api_level) = 0;\n\n    if (class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.id != NULL)\n        return 0;\n\n    sign = \"tv/danmaku/ijk/media/player/misc/IAndroidIO\";\n    class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.id = J4A_FindClass__asGlobalRef__catchAll(env, sign);\n    if (class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.id == NULL)\n        goto fail;\n\n    class_id = class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.id;\n    name     = \"open\";\n    sign     = \"(Ljava/lang/String;)I\";\n    class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.method_open = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.method_open == NULL)\n        goto fail;\n\n    class_id = class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.id;\n    name     = \"read\";\n    sign     = \"([BI)I\";\n    class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.method_read = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.method_read == NULL)\n        goto fail;\n\n    class_id = class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.id;\n    name     = \"seek\";\n    sign     = \"(JI)J\";\n    class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.method_seek = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.method_seek == NULL)\n        goto fail;\n\n    class_id = class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.id;\n    name     = \"close\";\n    sign     = \"()I\";\n    class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.method_close = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.method_close == NULL)\n        goto fail;\n\n    J4A_ALOGD(\"J4ALoader: OK: '%s' loaded\\n\", \"tv.danmaku.ijk.media.player.misc.IAndroidIO\");\n    ret = 0;\nfail:\n    return ret;\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/tv/danmaku/ijk/media/player/misc/IAndroidIO.h",
    "content": "/*\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * https://github.com/Bilibili/jni4android\n * This file is automatically generated by jni4android, do not modify.\n */\n\n#ifndef J4A__tv_danmaku_ijk_media_player_misc_IAndroidIO__H\n#define J4A__tv_danmaku_ijk_media_player_misc_IAndroidIO__H\n\n#include \"j4a/j4a_base.h\"\n\njint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open(JNIEnv *env, jobject thiz, jstring url);\njint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open__catchAll(JNIEnv *env, jobject thiz, jstring url);\njint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open__withCString(JNIEnv *env, jobject thiz, const char *url_cstr__);\njint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open__withCString__catchAll(JNIEnv *env, jobject thiz, const char *url_cstr__);\njint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__read(JNIEnv *env, jobject thiz, jbyteArray buffer, jint size);\njint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__read__catchAll(JNIEnv *env, jobject thiz, jbyteArray buffer, jint size);\njlong J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__seek(JNIEnv *env, jobject thiz, jlong offset, jint whence);\njlong J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__seek__catchAll(JNIEnv *env, jobject thiz, jlong offset, jint whence);\njint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__close(JNIEnv *env, jobject thiz);\njint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__close__catchAll(JNIEnv *env, jobject thiz);\nint J4A_loadClass__J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO(JNIEnv *env);\n\n#define J4A_HAVE_SIMPLE__J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO\n\n#define J4AC_IAndroidIO__open J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open\n#define J4AC_IAndroidIO__open__catchAll J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open__catchAll\n#define J4AC_IAndroidIO__open__withCString J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open__withCString\n#define J4AC_IAndroidIO__open__withCString__catchAll J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open__withCString__catchAll\n#define J4AC_IAndroidIO__read J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__read\n#define J4AC_IAndroidIO__read__catchAll J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__read__catchAll\n#define J4AC_IAndroidIO__seek J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__seek\n#define J4AC_IAndroidIO__seek__catchAll J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__seek__catchAll\n#define J4AC_IAndroidIO__close J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__close\n#define J4AC_IAndroidIO__close__catchAll J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__close__catchAll\n#define J4A_loadClass__J4AC_IAndroidIO J4A_loadClass__J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO\n\n#endif//J4A__tv_danmaku_ijk_media_player_misc_IAndroidIO__H\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/tv/danmaku/ijk/media/player/misc/IAndroidIO.include.j4a",
    "content": "#include \"j4a/class/tv/danmaku/ijk/media/player/misc/IAndroidIO.h\""
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/tv/danmaku/ijk/media/player/misc/IAndroidIO.loader.j4a",
    "content": "    J4A_LOAD_CLASS(tv_danmaku_ijk_media_player_misc_IAndroidIO);"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/tv/danmaku/ijk/media/player/misc/IMediaDataSource.c",
    "content": "/*\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * https://github.com/Bilibili/jni4android\n * This file is automatically generated by jni4android, do not modify.\n */\n\n#include \"IMediaDataSource.h\"\n\ntypedef struct J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource {\n    jclass id;\n\n    jmethodID method_readAt;\n    jmethodID method_getSize;\n    jmethodID method_close;\n} J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource;\nstatic J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource;\n\njint J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__readAt(JNIEnv *env, jobject thiz, jlong position, jbyteArray buffer, jint offset, jint size)\n{\n    return (*env)->CallIntMethod(env, thiz, class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.method_readAt, position, buffer, offset, size);\n}\n\njint J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__readAt__catchAll(JNIEnv *env, jobject thiz, jlong position, jbyteArray buffer, jint offset, jint size)\n{\n    jint ret_value = J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__readAt(env, thiz, position, buffer, offset, size);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\njlong J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__getSize(JNIEnv *env, jobject thiz)\n{\n    return (*env)->CallLongMethod(env, thiz, class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.method_getSize);\n}\n\njlong J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__getSize__catchAll(JNIEnv *env, jobject thiz)\n{\n    jlong ret_value = J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__getSize(env, thiz);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return 0;\n    }\n\n    return ret_value;\n}\n\nvoid J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__close(JNIEnv *env, jobject thiz)\n{\n    (*env)->CallVoidMethod(env, thiz, class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.method_close);\n}\n\nvoid J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__close__catchAll(JNIEnv *env, jobject thiz)\n{\n    J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__close(env, thiz);\n    J4A_ExceptionCheck__catchAll(env);\n}\n\nint J4A_loadClass__J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource(JNIEnv *env)\n{\n    int         ret                   = -1;\n    const char *J4A_UNUSED(name)      = NULL;\n    const char *J4A_UNUSED(sign)      = NULL;\n    jclass      J4A_UNUSED(class_id)  = NULL;\n    int         J4A_UNUSED(api_level) = 0;\n\n    if (class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.id != NULL)\n        return 0;\n\n    sign = \"tv/danmaku/ijk/media/player/misc/IMediaDataSource\";\n    class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.id = J4A_FindClass__asGlobalRef__catchAll(env, sign);\n    if (class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.id == NULL)\n        goto fail;\n\n    class_id = class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.id;\n    name     = \"readAt\";\n    sign     = \"(J[BII)I\";\n    class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.method_readAt = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.method_readAt == NULL)\n        goto fail;\n\n    class_id = class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.id;\n    name     = \"getSize\";\n    sign     = \"()J\";\n    class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.method_getSize = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.method_getSize == NULL)\n        goto fail;\n\n    class_id = class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.id;\n    name     = \"close\";\n    sign     = \"()V\";\n    class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.method_close = J4A_GetMethodID__catchAll(env, class_id, name, sign);\n    if (class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.method_close == NULL)\n        goto fail;\n\n    J4A_ALOGD(\"J4ALoader: OK: '%s' loaded\\n\", \"tv.danmaku.ijk.media.player.misc.IMediaDataSource\");\n    ret = 0;\nfail:\n    return ret;\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/tv/danmaku/ijk/media/player/misc/IMediaDataSource.h",
    "content": "/*\n * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * https://github.com/Bilibili/jni4android\n * This file is automatically generated by jni4android, do not modify.\n */\n\n#ifndef J4A__tv_danmaku_ijk_media_player_misc_IMediaDataSource__H\n#define J4A__tv_danmaku_ijk_media_player_misc_IMediaDataSource__H\n\n#include \"j4a/j4a_base.h\"\n\njint J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__readAt(JNIEnv *env, jobject thiz, jlong position, jbyteArray buffer, jint offset, jint size);\njint J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__readAt__catchAll(JNIEnv *env, jobject thiz, jlong position, jbyteArray buffer, jint offset, jint size);\njlong J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__getSize(JNIEnv *env, jobject thiz);\njlong J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__getSize__catchAll(JNIEnv *env, jobject thiz);\nvoid J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__close(JNIEnv *env, jobject thiz);\nvoid J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__close__catchAll(JNIEnv *env, jobject thiz);\nint J4A_loadClass__J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource(JNIEnv *env);\n\n#define J4A_HAVE_SIMPLE__J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource\n\n#define J4AC_IMediaDataSource__readAt J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__readAt\n#define J4AC_IMediaDataSource__readAt__catchAll J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__readAt__catchAll\n#define J4AC_IMediaDataSource__getSize J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__getSize\n#define J4AC_IMediaDataSource__getSize__catchAll J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__getSize__catchAll\n#define J4AC_IMediaDataSource__close J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__close\n#define J4AC_IMediaDataSource__close__catchAll J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__close__catchAll\n#define J4A_loadClass__J4AC_IMediaDataSource J4A_loadClass__J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource\n\n#endif//J4A__tv_danmaku_ijk_media_player_misc_IMediaDataSource__H\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/tv/danmaku/ijk/media/player/misc/IMediaDataSource.include.j4a",
    "content": "#include \"j4a/class/tv/danmaku/ijk/media/player/misc/IMediaDataSource.h\""
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/class/tv/danmaku/ijk/media/player/misc/IMediaDataSource.loader.j4a",
    "content": "    J4A_LOAD_CLASS(tv_danmaku_ijk_media_player_misc_IMediaDataSource);"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/j4a_allclasses.c",
    "content": "/*\n * copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of jni4android.\n *\n * jni4android is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * jni4android is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with jni4android; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"j4a_allclasses.h\"\n\nint J4A_LoadAll__catchAll(JNIEnv *env)\n{\n    int ret = 0;\n\n    // load android.os.Build at very beginning\n    J4A_LOAD_CLASS(android_os_Build);\n\n#include \"j4a/j4a_allclasses.loader.h\"\n\nfail:\n    return ret;\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/j4a_allclasses.h",
    "content": "/*\n * copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of jni4android.\n *\n * jni4android is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * jni4android is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with jni4android; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKJ4A__J4A__J4A_ALLCLASSES__H\n#define IJKJ4A__J4A__J4A_ALLCLASSES__H\n\n#include \"j4a_base.h\"\n#include \"j4a_allclasses.include.h\"\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/j4a_allclasses.include.h",
    "content": "#include \"j4a/class/java/nio/Buffer.h\"\n#include \"j4a/class/java/nio/ByteBuffer.h\"\n#include \"j4a/class/java/util/ArrayList.h\"\n#include \"j4a/class/android/media/AudioTrack.h\"\n#include \"j4a/class/android/media/MediaCodec.h\"\n#include \"j4a/class/android/media/MediaFormat.h\"\n#include \"j4a/class/android/media/PlaybackParams.h\"\n#include \"j4a/class/android/os/Build.h\"\n#include \"j4a/class/android/os/Bundle.h\"\n#include \"j4a/class/tv/danmaku/ijk/media/player/misc/IMediaDataSource.h\"\n#include \"j4a/class/tv/danmaku/ijk/media/player/misc/IAndroidIO.h\"\n#include \"j4a/class/tv/danmaku/ijk/media/player/IjkMediaPlayer.h\"\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/j4a_allclasses.loader.h",
    "content": "    J4A_LOAD_CLASS(java_nio_Buffer);\n    J4A_LOAD_CLASS(java_nio_ByteBuffer);\n    J4A_LOAD_CLASS(java_util_ArrayList);\n    J4A_LOAD_CLASS(android_media_AudioTrack);\n    J4A_LOAD_CLASS(android_media_MediaCodec);\n    J4A_LOAD_CLASS(android_media_MediaFormat);\n    J4A_LOAD_CLASS(android_media_PlaybackParams);\n    J4A_LOAD_CLASS(android_os_Build);\n    J4A_LOAD_CLASS(android_os_Bundle);\n    J4A_LOAD_CLASS(tv_danmaku_ijk_media_player_misc_IMediaDataSource);\n    J4A_LOAD_CLASS(tv_danmaku_ijk_media_player_misc_IAndroidIO);\n    J4A_LOAD_CLASS(tv_danmaku_ijk_media_player_IjkMediaPlayer);\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/j4a_base.c",
    "content": "/*\n * copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of jni4android.\n *\n * jni4android is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * jni4android is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with jni4android; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"j4a_base.h\"\n#include \"j4a/class/android/os/Build.h\"\n\n/********************\n * Exception Handle\n ********************/\n\nbool J4A_ExceptionCheck__throwAny(JNIEnv *env)\n{\n    if ((*env)->ExceptionCheck(env)) {\n        (*env)->ExceptionDescribe(env);\n        return true;\n    }\n\n    return false;\n}\n\nbool J4A_ExceptionCheck__catchAll(JNIEnv *env)\n{\n    if ((*env)->ExceptionCheck(env)) {\n        (*env)->ExceptionDescribe(env);\n        (*env)->ExceptionClear(env);\n        return true;\n    }\n\n    return false;\n}\n\nint J4A_ThrowExceptionOfClass(JNIEnv* env, jclass clazz, const char* msg)\n{\n    if ((*env)->ThrowNew(env, clazz, msg) != JNI_OK)\n        J4A_ALOGE(\"%s: Failed: msg: '%s'\\n\", __func__, msg);\n\n    return 0;\n}\n\nint J4A_ThrowException(JNIEnv* env, const char* class_sign, const char* msg)\n{\n    int ret = -1;\n\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        J4A_ALOGE(\"pending exception throwed.\\n\");\n    }\n\n    jclass exceptionClass = J4A_FindClass__catchAll(env, class_sign);\n    if (exceptionClass == NULL) {\n        J4A_FUNC_FAIL_TRACE();\n        ret = -1;\n        goto fail;\n    }\n\n    ret = J4A_ThrowExceptionOfClass(env, exceptionClass, msg);\n    if (ret) {\n        J4A_FUNC_FAIL_TRACE();\n        goto fail;\n    }\n\n    ret = 0;\nfail:\n    J4A_DeleteLocalRef__p(env, &exceptionClass);\n    return ret;\n}\n\nint J4A_ThrowIllegalStateException(JNIEnv *env, const char* msg)\n{\n    return J4A_ThrowException(env, \"java/lang/IllegalStateException\", msg);\n}\n\n/********************\n * References\n ********************/\n\njclass J4A_NewGlobalRef__catchAll(JNIEnv *env, jobject obj)\n{\n    jclass obj_global = (*env)->NewGlobalRef(env, obj);\n    if (J4A_ExceptionCheck__catchAll(env) || !(obj_global)) {\n        J4A_FUNC_FAIL_TRACE();\n        goto fail;\n    }\n\nfail:\n    return obj_global;\n}\n\nvoid J4A_DeleteLocalRef(JNIEnv *env, jobject obj)\n{\n    if (!obj)\n        return;\n    (*env)->DeleteLocalRef(env, obj);\n}\n\nvoid J4A_DeleteLocalRef__p(JNIEnv *env, jobject *obj)\n{\n    if (!obj)\n        return;\n    J4A_DeleteLocalRef(env, *obj);\n    *obj = NULL;\n}\n\nvoid J4A_DeleteGlobalRef(JNIEnv *env, jobject obj)\n{\n    if (!obj)\n        return;\n    (*env)->DeleteGlobalRef(env, obj);\n}\n\nvoid J4A_DeleteGlobalRef__p(JNIEnv *env, jobject *obj)\n{\n    if (!obj)\n        return;\n    J4A_DeleteGlobalRef(env, *obj);\n    *obj = NULL;\n}\n\nvoid J4A_ReleaseStringUTFChars(JNIEnv *env, jstring str, const char *c_str)\n{\n    if (!str || !c_str)\n        return;\n    (*env)->ReleaseStringUTFChars(env, str, c_str);\n}\n\nvoid J4A_ReleaseStringUTFChars__p(JNIEnv *env, jstring str, const char **c_str)\n{\n    if (!str || !c_str)\n        return;\n    J4A_ReleaseStringUTFChars(env, str, *c_str);\n    *c_str = NULL;\n}\n\n/********************\n * Class Load\n ********************/\n\njclass J4A_FindClass__catchAll(JNIEnv *env, const char *class_sign)\n{\n    jclass clazz = (*env)->FindClass(env, class_sign);\n    if (J4A_ExceptionCheck__catchAll(env) || !(clazz)) {\n        J4A_FUNC_FAIL_TRACE();\n        clazz = NULL;\n        goto fail;\n    }\n\nfail:\n    return clazz;\n}\n\njclass J4A_FindClass__asGlobalRef__catchAll(JNIEnv *env, const char *class_sign)\n{\n    jclass clazz_global = NULL;\n    jclass clazz = J4A_FindClass__catchAll(env, class_sign);\n    if (!clazz) {\n        J4A_FUNC_FAIL_TRACE1(class_sign);\n        goto fail;\n    }\n\n    clazz_global = J4A_NewGlobalRef__catchAll(env, clazz);\n    if (!clazz_global) {\n        J4A_FUNC_FAIL_TRACE1(class_sign);\n        goto fail;\n    }\n\nfail:\n    J4A_DeleteLocalRef__p(env, &clazz);\n    return clazz_global;\n}\n\njmethodID J4A_GetMethodID__catchAll(JNIEnv *env, jclass clazz, const char *method_name, const char *method_sign)\n{\n    jmethodID method_id = (*env)->GetMethodID(env, clazz, method_name, method_sign);\n    if (J4A_ExceptionCheck__catchAll(env) || !method_id) {\n        J4A_FUNC_FAIL_TRACE2(method_name, method_sign);\n        method_id = NULL;\n        goto fail;\n    }\n\nfail:\n    return method_id;\n}\n\njmethodID J4A_GetStaticMethodID__catchAll(JNIEnv *env, jclass clazz, const char *method_name, const char *method_sign)\n{\n    jmethodID method_id = (*env)->GetStaticMethodID(env, clazz, method_name, method_sign);\n    if (J4A_ExceptionCheck__catchAll(env) || !method_id) {\n        J4A_FUNC_FAIL_TRACE2(method_name, method_sign);\n        method_id = NULL;\n        goto fail;\n    }\n\nfail:\n    return method_id;\n}\n\njfieldID J4A_GetFieldID__catchAll(JNIEnv *env, jclass clazz, const char *field_name, const char *field_sign)\n{\n    jfieldID field_id = (*env)->GetFieldID(env, clazz, field_name, field_sign);\n    if (J4A_ExceptionCheck__catchAll(env) || !field_id) {\n        J4A_FUNC_FAIL_TRACE2(field_name, field_sign);\n        field_id = NULL;\n        goto fail;\n    }\n\nfail:\n    return field_id;\n}\n\njfieldID J4A_GetStaticFieldID__catchAll(JNIEnv *env, jclass clazz, const char *field_name, const char *field_sign)\n{\n    jfieldID field_id = (*env)->GetStaticFieldID(env, clazz, field_name, field_sign);\n    if (J4A_ExceptionCheck__catchAll(env) || !field_id) {\n        J4A_FUNC_FAIL_TRACE2(field_name, field_sign);\n        field_id = NULL;\n        goto fail;\n    }\n\nfail:\n    return field_id;\n}\n\n/********************\n * Misc Functions\n ********************/\n\njbyteArray J4A_NewByteArray__catchAll(JNIEnv *env, jsize capacity)\n{\n    jbyteArray local = (*env)->NewByteArray(env, capacity);\n    if (J4A_ExceptionCheck__catchAll(env) || !local)\n        return NULL;\n\n    return local;\n}\n\njbyteArray J4A_NewByteArray__asGlobalRef__catchAll(JNIEnv *env, jsize capacity)\n{\n    jbyteArray local = (*env)->NewByteArray(env, capacity);\n    if (J4A_ExceptionCheck__catchAll(env) || !local)\n        return NULL;\n\n    jbyteArray global = (*env)->NewGlobalRef(env, local);\n    J4A_DeleteLocalRef__p(env, &local);\n    return global;\n}\n\nint J4A_GetSystemAndroidApiLevel(JNIEnv *env)\n{\n    static int SDK_INT = 0;\n    if (SDK_INT > 0)\n        return SDK_INT;\n\n    SDK_INT = J4AC_android_os_Build__VERSION__SDK_INT__get__catchAll(env);\n    J4A_ALOGI(\"API-Level: %d\\n\", SDK_INT);\n    return SDK_INT;\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4a/j4a_base.h",
    "content": "/*\n * copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of jni4android.\n *\n * jni4android is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * jni4android is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with jni4android; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef J4A_BASE_H\n#define J4A_BASE_H\n\n#include <string.h>\n#include <stdbool.h>\n#include <stdint.h>\n#include <jni.h>\n#include <android/log.h>\n\n#ifndef J4A_UNUSED\n#define J4A_UNUSED(x) x __attribute__((unused))\n#endif\n\n#define J4A_LOG_TAG \"J4A\"\n#define J4A_VLOGV(...)  __android_log_vprint(ANDROID_LOG_VERBOSE,   J4A_LOG_TAG, __VA_ARGS__)\n#define J4A_VLOGD(...)  __android_log_vprint(ANDROID_LOG_DEBUG,     J4A_LOG_TAG, __VA_ARGS__)\n#define J4A_VLOGI(...)  __android_log_vprint(ANDROID_LOG_INFO,      J4A_LOG_TAG, __VA_ARGS__)\n#define J4A_VLOGW(...)  __android_log_vprint(ANDROID_LOG_WARN,      J4A_LOG_TAG, __VA_ARGS__)\n#define J4A_VLOGE(...)  __android_log_vprint(ANDROID_LOG_ERROR,     J4A_LOG_TAG, __VA_ARGS__)\n\n#define J4A_ALOGV(...)  __android_log_print(ANDROID_LOG_VERBOSE,    J4A_LOG_TAG, __VA_ARGS__)\n#define J4A_ALOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,      J4A_LOG_TAG, __VA_ARGS__)\n#define J4A_ALOGI(...)  __android_log_print(ANDROID_LOG_INFO,       J4A_LOG_TAG, __VA_ARGS__)\n#define J4A_ALOGW(...)  __android_log_print(ANDROID_LOG_WARN,       J4A_LOG_TAG, __VA_ARGS__)\n#define J4A_ALOGE(...)  __android_log_print(ANDROID_LOG_ERROR,      J4A_LOG_TAG, __VA_ARGS__)\n\n#define J4A_FUNC_FAIL_TRACE()               do {J4A_ALOGE(\"%s: failed\\n\", __func__);} while (0)\n#define J4A_FUNC_FAIL_TRACE1(x__)           do {J4A_ALOGE(\"%s: failed: %s\\n\", __func__, x__);} while (0)\n#define J4A_FUNC_FAIL_TRACE2(x1__, x2__)    do {J4A_ALOGE(\"%s: failed: %s %s\\n\", __func__, x1__, x2__);} while (0)\n\n#define J4A_LOAD_CLASS(class__) \\\n    do { \\\n        ret = J4A_loadClass__J4AC_##class__(env); \\\n        if (ret) \\\n            goto fail; \\\n    } while (0)\n\n/********************\n * Exception Handle\n ********************/\n\nbool J4A_ExceptionCheck__throwAny(JNIEnv *env);\nbool J4A_ExceptionCheck__catchAll(JNIEnv *env);\nint  J4A_ThrowExceptionOfClass(JNIEnv* env, jclass clazz, const char* msg);\nint  J4A_ThrowException(JNIEnv* env, const char* class_sign, const char* msg);\nint  J4A_ThrowIllegalStateException(JNIEnv *env, const char* msg);\n\n/********************\n * References\n ********************/\njclass J4A_NewGlobalRef__catchAll(JNIEnv *env, jobject obj);\nvoid   J4A_DeleteLocalRef(JNIEnv *env, jobject obj);\nvoid   J4A_DeleteLocalRef__p(JNIEnv *env, jobject *obj);\nvoid   J4A_DeleteGlobalRef(JNIEnv *env, jobject obj);\nvoid   J4A_DeleteGlobalRef__p(JNIEnv *env, jobject *obj);\n\nvoid   J4A_ReleaseStringUTFChars(JNIEnv *env, jstring str, const char *c_str);\nvoid   J4A_ReleaseStringUTFChars__p(JNIEnv *env, jstring str, const char **c_str);\n\n/********************\n * Class Load\n ********************/\n\nint    J4A_LoadAll__catchAll(JNIEnv *env);\njclass J4A_FindClass__catchAll(JNIEnv *env, const char *class_sign);\njclass J4A_FindClass__asGlobalRef__catchAll(JNIEnv *env, const char *class_sign);\n\njmethodID J4A_GetMethodID__catchAll(JNIEnv *env, jclass clazz, const char *method_name, const char *method_sign);\njmethodID J4A_GetStaticMethodID__catchAll(JNIEnv *env, jclass clazz, const char *method_name, const char *method_sign);\n\njfieldID J4A_GetFieldID__catchAll(JNIEnv *env, jclass clazz, const char *field_name, const char *method_sign);\njfieldID J4A_GetStaticFieldID__catchAll(JNIEnv *env, jclass clazz, const char *field_name, const char *method_sign);\n\n/********************\n * Misc Functions\n ********************/\n\njbyteArray J4A_NewByteArray__catchAll(JNIEnv *env, jsize capacity);\njbyteArray J4A_NewByteArray__asGlobalRef__catchAll(JNIEnv *env, jsize capacity);\n\nint J4A_GetSystemAndroidApiLevel(JNIEnv *env);\n\n#endif//J4A_INTERNAL_H\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4au/class/android/media/AudioTrack.util.c",
    "content": "/*\n * copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"AudioTrack.util.h\"\n#include \"j4a/class/android/media/PlaybackParams.h\"\n\n#ifndef STREAM_MUSIC\n#define STREAM_MUSIC 3\n#endif\nvoid J4AC_android_media_AudioTrack__setSpeed(JNIEnv *env, jobject thiz, jfloat speed)\n{\n    if (J4A_GetSystemAndroidApiLevel(env) < 23) {\n        jint sample_rate = J4AC_android_media_AudioTrack__getSampleRate(env,thiz);\n        if (J4A_ExceptionCheck__throwAny(env)) {\n            return;\n        }\n        J4AC_android_media_AudioTrack__setPlaybackRate__catchAll(env, thiz,\n                                                                 (jint) (sample_rate * speed));\n        return;\n    }\n\n    jobject temp = NULL;\n    jobject params = J4AC_android_media_AudioTrack__getPlaybackParams(env, thiz);\n    if (J4A_ExceptionCheck__throwAny(env) || !params)\n        goto fail;\n\n    temp = J4AC_android_media_PlaybackParams__setSpeed(env, params, speed);\n    J4A_DeleteLocalRef__p(env, &temp);\n    if (J4A_ExceptionCheck__throwAny(env))\n        goto fail;\n\n    J4A_ALOGE(\"%s %f\", __func__, (double)speed);\n    J4AC_android_media_AudioTrack__setPlaybackParams(env, thiz, params);\n    if (J4A_ExceptionCheck__throwAny(env))\n        goto fail;\n\nfail:\n    J4A_DeleteLocalRef__p(env, &params);\n}\n\nvoid J4AC_android_media_AudioTrack__setSpeed__catchAll(JNIEnv *env, jobject thiz, jfloat speed)\n{\n    J4A_ALOGE(\"%s\", __func__);\n    J4AC_android_media_AudioTrack__setSpeed(env, thiz, speed);\n    if (J4A_ExceptionCheck__catchAll(env))\n        return;\n\n    return;\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4au/class/android/media/AudioTrack.util.h",
    "content": "/*\n * copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef J4AU__android_media_AudioTrack__UTIL__H\n#define J4AU__android_media_AudioTrack__UTIL__H\n\n#include \"j4a/j4a_base.h\"\n#include \"j4a/class/android/media/AudioTrack.h\"\n\nvoid J4AC_android_media_AudioTrack__setSpeed(JNIEnv *env, jobject thiz, jfloat speed);\nvoid J4AC_android_media_AudioTrack__setSpeed__catchAll(JNIEnv *env, jobject thiz, jfloat speed);\n\n#ifdef J4A_HAVE_SIMPLE__J4AC_android_media_AudioTrack\n#define J4AC_AudioTrack__setSpeed           J4AC_android_media_AudioTrack__setSpeed\n#define J4AC_AudioTrack__setSpeed__catchAll J4AC_android_media_AudioTrack__setSpeed__catchAll\n#endif\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4au/class/java/nio/ByteBuffer.util.c",
    "content": "/*\n * copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ByteBuffer.util.h\"\n\nvoid *J4AC_java_nio_ByteBuffer__getDirectBufferAddress(JNIEnv *env, jobject thiz)\n{\n    return (*env)->GetDirectBufferAddress(env, thiz);\n}\n\nvoid *J4AC_java_nio_ByteBuffer__getDirectBufferAddress__catchAll(JNIEnv *env, jobject thiz)\n{\n    void *ret = (*env)->GetDirectBufferAddress(env, thiz);\n    if (J4A_ExceptionCheck__catchAll(env) || !ret)\n        return NULL;\n\n    return ret;\n}\n\nint J4AC_java_nio_ByteBuffer__assignData__catchAll(JNIEnv *env, jobject thiz, void* data, size_t size)\n{\n    jobject buffer = J4AC_java_nio_ByteBuffer__limit(env, thiz, size);\n    if (J4A_ExceptionCheck__catchAll(env) || !buffer)\n        return -1;\n    J4A_DeleteLocalRef__p(env, &buffer);\n\n    uint8_t *c_buffer = J4AC_java_nio_ByteBuffer__getDirectBufferAddress__catchAll(env, thiz);\n    if (!c_buffer)\n        return -1;\n\n    memcpy(c_buffer, data, size);\n    return 0;\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/j4au/class/java/nio/ByteBuffer.util.h",
    "content": "/*\n * copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef J4A__java_nio_ByteBuffer__UTIL__H\n#define J4A__java_nio_ByteBuffer__UTIL__H\n\n#include \"j4a/j4a_base.h\"\n#include \"j4a/class/java/nio/ByteBuffer.h\"\n\nvoid *J4AC_java_nio_ByteBuffer__getDirectBufferAddress(JNIEnv *env, jobject thiz);\nvoid *J4AC_java_nio_ByteBuffer__getDirectBufferAddress__catchAll(JNIEnv *env, jobject thiz);\nint   J4AC_java_nio_ByteBuffer__assignData__catchAll(JNIEnv *env, jobject thiz, void* data, size_t size);\n\n#ifdef J4A_HAVE_SIMPLE__J4AC_java_nio_ByteBuffer\n#define J4AC_ByteBuffer__getDirectBufferAddress             J4AC_java_nio_ByteBuffer__getDirectBufferAddress\n#define J4AC_ByteBuffer__getDirectBufferAddress__catchAll   J4AC_java_nio_ByteBuffer__getDirectBufferAddress__catchAll\n#define J4AC_ByteBuffer__assignData__catchAll               J4AC_java_nio_ByteBuffer__assignData__catchAll\n#endif\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkj4a/java/android/media/AudioTrack.java",
    "content": "package android.media;\n\n@SimpleCClassName\n@IncludeUtil\npublic class AudioTrack {\n    public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode);\n\n    public static int   getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat);\n    public static float getMaxVolume();\n    public static float getMinVolume();\n    public static int   getNativeOutputSampleRate(int streamType);\n\n    public void play();\n    public void pause();\n    public void stop();\n    public void flush();\n    public void release();\n\n    public int write(byte[] audioData, int offsetInBytes, int sizeInBytes);\n\n    public int setStereoVolume(float leftGain, float rightGain);\n    public int getAudioSessionId();\n\n    @MinApi(23)\n    public PlaybackParams getPlaybackParams();\n    @MinApi(23)\n    void setPlaybackParams(PlaybackParams params);\n\n\n    int getStreamType();\n    int getSampleRate();\n    int getPlaybackRate();\n    int setPlaybackRate(int sampleRateInHz);\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/java/android/media/MediaCodec.java",
    "content": "package android.media;\n\nimport java.nio.ByteBuffer;\nimport android.view.Surface;\n\n@SimpleCClassName\n@MinApi(16)\npublic class MediaCodec {\n    public static class BufferInfo {\n        public int  flags;\n        public int  offset;\n        public long presentationTimeUs;\n        public int  size;\n\n        public BufferInfo();\n    }\n\n    public static MediaCodec createByCodecName(String name);\n\n    public void configure(MediaFormat format, Surface surface, MediaCrypto crypto, int flags);\n\n    public final MediaFormat getOutputFormat();\n\n    public ByteBuffer[] getInputBuffers();\n\n    public final int  dequeueInputBuffer(long timeoutUs);\n    public final void queueInputBuffer(int index, int offset, int size, long presentationTimeUs, int flags);\n\n    public final int  dequeueOutputBuffer(MediaCodec.BufferInfo info, long timeoutUs);\n    public final void releaseOutputBuffer(int index, boolean render);\n\n    public final void start();\n    public final void stop();\n    public final void flush();\n    public final void release();\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/java/android/media/MediaCrypto.java",
    "content": "package android.media;\n\n@Hide\n@MinApi(16)\npublic class MediaCrypto {\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/java/android/media/MediaFormat.java",
    "content": "package android.media;\n\nimport java.nio.ByteBuffer;\n\n@SimpleCClassName\n@MinApi(16)\npublic class MediaFormat {\n    public MediaFormat();\n\n    public final static MediaFormat createVideoFormat(String mime, int width, int height);\n\n    public final int   getInteger(String name);\n    public final void  setInteger(String name, int value);\n    public final void  setByteBuffer(String name, ByteBuffer bytes);\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/java/android/media/PlaybackParams.java",
    "content": "package android.media;\n\n@SimpleCClassName\n@MinApi(23)\npublic class PlaybackParams {\n    public PlaybackParams setSpeed(float speed);\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/java/android/os/Build.java",
    "content": "package android.os;\n\npublic class Build {\n    public static class VERSION {\n        public static final int SDK_INT;\n    }\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/java/android/os/Bundle.java",
    "content": "package android.os;\n\nimport java.util.ArrayList;\n\n@SimpleCClassName\npublic class Bundle {\n    public Bundle();\n\n    public int  getInt(String key, int defaultValue);\n    public void putInt(String key, int value);\n\n    public String getString(String key);\n    public void   putString(String key, String value);\n\n    public void putParcelableArrayList(String key, ArrayList value);\n    public long getLong(String key);\n    public void putLong(String key, long value);\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/java/java/nio/Buffer.java",
    "content": "package java.nio;\n\npublic class Buffer {\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/java/java/nio/ByteBuffer.java",
    "content": "package java.nio;\n\nimport android.os.Build;\n\n@SimpleCClassName\n@IncludeUtil\npublic class ByteBuffer {\n    public static ByteBuffer allocate(int capacity);\n    public static ByteBuffer allocateDirect(int capacity);\n    public final  Buffer     limit(int newLimit);\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/java/java/util/ArrayList.java",
    "content": "package java.util;\n\n@SimpleCClassName\npublic class ArrayList {\n    public ArrayList();\n    boolean add(Object object);\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/java/tv/danmaku/ijk/media/player/IjkMediaPlayer.java",
    "content": "package tv.danmaku.ijk.media.player;\n\nimport android.os.Bundle;\n\n@SimpleCClassName\npublic class IjkMediaPlayer {\n    private long mNativeMediaPlayer;\n    private long mNativeMediaDataSource;\n    private long mNativeAndroidIO;\n\n    private static void postEventFromNative(Object weakThiz, int what, int arg1, int arg2, Object obj);\n    private static String onSelectCodec(Object weakThiz, String mimeType, int profile, int level);\n    private static boolean onNativeInvoke(Object weakThiz, int what, Bundle args);\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/java/tv/danmaku/ijk/media/player/misc/IAndroidIO.java",
    "content": "package tv.danmaku.ijk.media.player.misc;\n\n@SimpleCClassName\npublic interface IAndroidIO {\n    int  open(String url);\n    int  read(byte[] buffer, int size);\n    long seek(long offset, int whence);\n    int  close();\n}\n"
  },
  {
    "path": "ijkmedia/ijkj4a/java/tv/danmaku/ijk/media/player/misc/IMediaDataSource.java",
    "content": "package tv.danmaku.ijk.media.player.misc;\n\n@SimpleCClassName\npublic interface IMediaDataSource {\n    int  readAt(long position, byte[] buffer, int offset, int size);\n    long getSize();\n    void close();\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/.gitignore",
    "content": "ijkversion.h\n"
  },
  {
    "path": "ijkmedia/ijkplayer/Android.mk",
    "content": "#\n# Copyright (c) 2013 Bilibili\n# Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n#\n# This file is part of ijkPlayer.\n#\n# ijkPlayer is free software; you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation; either\n# version 2.1 of the License, or (at your option) any later version.\n#\n# ijkPlayer is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# Lesser General Public License for more details.\n#\n# You should have received a copy of the GNU Lesser General Public\n# License along with ijkPlayer; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n\nLOCAL_PATH := $(call my-dir)\n\ninclude $(CLEAR_VARS)\n# -mfloat-abi=soft is a workaround for FP register corruption on Exynos 4210\n# http://www.spinics.net/lists/arm-kernel/msg368417.html\nifeq ($(TARGET_ARCH_ABI),armeabi-v7a)\nLOCAL_CFLAGS += -mfloat-abi=soft\nendif\nLOCAL_CFLAGS += -std=c99\nLOCAL_LDLIBS += -llog -landroid\n\nLOCAL_C_INCLUDES += $(LOCAL_PATH)\nLOCAL_C_INCLUDES += $(realpath $(LOCAL_PATH)/..)\nLOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH)\nLOCAL_C_INCLUDES += $(realpath $(LOCAL_PATH)/../ijkj4a)\n\nLOCAL_SRC_FILES += ff_cmdutils.c\nLOCAL_SRC_FILES += ff_ffplay.c\nLOCAL_SRC_FILES += ff_ffpipeline.c\nLOCAL_SRC_FILES += ff_ffpipenode.c\nLOCAL_SRC_FILES += ijkmeta.c\nLOCAL_SRC_FILES += ijkplayer.c\n\nLOCAL_SRC_FILES += pipeline/ffpipeline_ffplay.c\nLOCAL_SRC_FILES += pipeline/ffpipenode_ffplay_vdec.c\n\nLOCAL_SRC_FILES += android/ffmpeg_api_jni.c\nLOCAL_SRC_FILES += android/ijkplayer_android.c\nLOCAL_SRC_FILES += android/ijkplayer_jni.c\n\nLOCAL_SRC_FILES += android/pipeline/ffpipeline_android.c\nLOCAL_SRC_FILES += android/pipeline/ffpipenode_android_mediacodec_vdec.c\n\nLOCAL_SRC_FILES += ijkavformat/allformats.c\nLOCAL_SRC_FILES += ijkavformat/cJSON.c\nLOCAL_SRC_FILES += ijkavformat/ijklas.c\nLOCAL_SRC_FILES += ijkavformat/ijklivehook.c\nLOCAL_SRC_FILES += ijkavformat/ijkmediadatasource.c\nLOCAL_SRC_FILES += ijkavformat/ijkio.c\nLOCAL_SRC_FILES += ijkavformat/ijkiomanager.c\nLOCAL_SRC_FILES += ijkavformat/ijkiocache.c\nLOCAL_SRC_FILES += ijkavformat/ijkioffio.c\nLOCAL_SRC_FILES += ijkavformat/ijkioandroidio.c\nLOCAL_SRC_FILES += ijkavformat/ijkioprotocol.c\nLOCAL_SRC_FILES += ijkavformat/ijkioapplication.c\nLOCAL_SRC_FILES += ijkavformat/ijkiourlhook.c\n\nLOCAL_SRC_FILES  += ijkavformat/ijkasync.c\nLOCAL_SRC_FILES  += ijkavformat/ijkurlhook.c\nLOCAL_SRC_FILES  += ijkavformat/ijklongurl.c\nLOCAL_SRC_FILES  += ijkavformat/ijksegment.c\n\nLOCAL_SRC_FILES += ijkavutil/ijkdict.c\nLOCAL_SRC_FILES += ijkavutil/ijkutils.c\nLOCAL_SRC_FILES += ijkavutil/ijkthreadpool.c\nLOCAL_SRC_FILES += ijkavutil/ijktree.c\nLOCAL_SRC_FILES += ijkavutil/ijkfifo.c\nLOCAL_SRC_FILES += ijkavutil/ijkstl.cpp\n\nLOCAL_SHARED_LIBRARIES := ijkffmpeg ijksdl\nLOCAL_STATIC_LIBRARIES := android-ndk-profiler ijksoundtouch\n\nLOCAL_MODULE := ijkplayer\n\nVERSION_SH  = $(LOCAL_PATH)/version.sh\nVERSION_H   = ijkversion.h\n$(info $(shell ($(VERSION_SH) $(LOCAL_PATH) $(VERSION_H))))\ninclude $(BUILD_SHARED_LIBRARY)\n"
  },
  {
    "path": "ijkmedia/ijkplayer/android/ffmpeg_api_jni.c",
    "content": "/*\n * ffmpeg_api_jni.c\n *\n * Copyright (c) 2014 Bilibili\n * Copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ffmpeg_api_jni.h\"\n\n#include <assert.h>\n#include <string.h>\n#include <jni.h>\n#include \"../ff_ffinc.h\"\n#include \"ijksdl/ijksdl_log.h\"\n#include \"ijksdl/android/ijksdl_android_jni.h\"\n\n#define JNI_CLASS_FFMPEG_API \"tv/danmaku/ijk/media/player/ffmpeg/FFmpegApi\"\n\ntypedef struct ffmpeg_api_fields_t {\n    jclass clazz;\n} ffmpeg_api_fields_t;\nstatic ffmpeg_api_fields_t g_clazz;\n\nstatic jstring\nFFmpegApi_av_base64_encode(JNIEnv *env, jclass clazz, jbyteArray in)\n{\n    jstring ret_string = NULL;\n    char*   out_buffer = 0;\n    int     out_size   = 0;\n    jbyte*  in_buffer  = 0;\n    jsize   in_size    = (*env)->GetArrayLength(env, in);\n    if (in_size <= 0)\n        goto fail;\n\n    in_buffer = (*env)->GetByteArrayElements(env, in, NULL);\n    if (!in_buffer)\n        goto fail;\n\n    out_size = AV_BASE64_SIZE(in_size);\n    out_buffer = malloc(out_size + 1);\n    if (!out_buffer)\n        goto fail;\n    out_buffer[out_size] = 0;\n\n    if (!av_base64_encode(out_buffer, out_size, (const uint8_t *)in_buffer, in_size))\n        goto fail;\n\n    ret_string = (*env)->NewStringUTF(env, out_buffer);\nfail:\n    if (in_buffer) {\n        (*env)->ReleaseByteArrayElements(env, in, in_buffer, JNI_ABORT);\n        in_buffer = NULL;\n    }\n    if (out_buffer) {\n        free(out_buffer);\n        out_buffer = NULL;\n    }\n    return ret_string;\n}\n\nstatic JNINativeMethod g_methods[] = {\n    {\"av_base64_encode\", \"([B)Ljava/lang/String;\", (void *) FFmpegApi_av_base64_encode},\n};\n\nint FFmpegApi_global_init(JNIEnv *env)\n{\n    int ret = 0;\n\n    IJK_FIND_JAVA_CLASS(env, g_clazz.clazz, JNI_CLASS_FFMPEG_API);\n    (*env)->RegisterNatives(env, g_clazz.clazz, g_methods, NELEM(g_methods));\n\n    return ret;\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/android/ffmpeg_api_jni.h",
    "content": "/*\n * ffmpeg_api_jni.h\n *\n * Copyright (c) 2014 Bilibili\n * Copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKPLAYER_ANDROID__FFMPEG_API_JNI_H\n\n#include <jni.h>\n\nint FFmpegApi_global_init(JNIEnv *env);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/android/ijkplayer_android.c",
    "content": "/*\n * ijkplayer_android.c\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijkplayer_android.h\"\n\n#include <assert.h>\n#include \"ijksdl/android/ijksdl_android.h\"\n#include \"../ff_fferror.h\"\n#include \"../ff_ffplay.h\"\n#include \"../ijkplayer_internal.h\"\n#include \"../pipeline/ffpipeline_ffplay.h\"\n#include \"pipeline/ffpipeline_android.h\"\n\nIjkMediaPlayer *ijkmp_android_create(int(*msg_loop)(void*))\n{\n    IjkMediaPlayer *mp = ijkmp_create(msg_loop);\n    if (!mp)\n        goto fail;\n\n    mp->ffplayer->vout = SDL_VoutAndroid_CreateForAndroidSurface();\n    if (!mp->ffplayer->vout)\n        goto fail;\n\n    mp->ffplayer->pipeline = ffpipeline_create_from_android(mp->ffplayer);\n    if (!mp->ffplayer->pipeline)\n        goto fail;\n\n    ffpipeline_set_vout(mp->ffplayer->pipeline, mp->ffplayer->vout);\n\n    return mp;\n\nfail:\n    ijkmp_dec_ref_p(&mp);\n    return NULL;\n}\n\nvoid ijkmp_android_set_surface_l(JNIEnv *env, IjkMediaPlayer *mp, jobject android_surface)\n{\n    if (!mp || !mp->ffplayer || !mp->ffplayer->vout)\n        return;\n\n    SDL_VoutAndroid_SetAndroidSurface(env, mp->ffplayer->vout, android_surface);\n    ffpipeline_set_surface(env, mp->ffplayer->pipeline, android_surface);\n}\n\nvoid ijkmp_android_set_surface(JNIEnv *env, IjkMediaPlayer *mp, jobject android_surface)\n{\n    if (!mp)\n        return;\n\n    MPTRACE(\"ijkmp_set_android_surface(surface=%p)\", (void*)android_surface);\n    pthread_mutex_lock(&mp->mutex);\n    ijkmp_android_set_surface_l(env, mp, android_surface);\n    pthread_mutex_unlock(&mp->mutex);\n    MPTRACE(\"ijkmp_set_android_surface(surface=%p)=void\", (void*)android_surface);\n}\n\nvoid ijkmp_android_set_volume(JNIEnv *env, IjkMediaPlayer *mp, float left, float right)\n{\n    if (!mp)\n        return;\n\n    MPTRACE(\"ijkmp_android_set_volume(%f, %f)\", left, right);\n    pthread_mutex_lock(&mp->mutex);\n\n    if (mp && mp->ffplayer && mp->ffplayer->pipeline) {\n        ffpipeline_set_volume(mp->ffplayer->pipeline, left, right);\n    }\n\n    pthread_mutex_unlock(&mp->mutex);\n    MPTRACE(\"ijkmp_android_set_volume(%f, %f)=void\", left, right);\n}\n\nint ijkmp_android_get_audio_session_id(JNIEnv *env, IjkMediaPlayer *mp)\n{\n    int audio_session_id = 0;\n    if (!mp)\n        return audio_session_id;\n\n    MPTRACE(\"%s()\", __func__);\n    pthread_mutex_lock(&mp->mutex);\n\n    if (mp && mp->ffplayer && mp->ffplayer->aout) {\n        audio_session_id = SDL_AoutGetAudioSessionId(mp->ffplayer->aout);\n    }\n\n    pthread_mutex_unlock(&mp->mutex);\n    MPTRACE(\"%s()=%d\", __func__, audio_session_id);\n\n    return audio_session_id;\n}\n\nvoid ijkmp_android_set_mediacodec_select_callback(IjkMediaPlayer *mp, bool (*callback)(void *opaque, ijkmp_mediacodecinfo_context *mcc), void *opaque)\n{\n    if (!mp)\n        return;\n\n    MPTRACE(\"ijkmp_android_set_mediacodec_select_callback()\");\n    pthread_mutex_lock(&mp->mutex);\n\n    if (mp && mp->ffplayer && mp->ffplayer->pipeline) {\n        ffpipeline_set_mediacodec_select_callback(mp->ffplayer->pipeline, callback, opaque);\n    }\n\n    pthread_mutex_unlock(&mp->mutex);\n    MPTRACE(\"ijkmp_android_set_mediacodec_select_callback()=void\");\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/android/ijkplayer_android.h",
    "content": "/*\n * ijkplayer_android.h\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKPLAYER_ANDROID__IJKPLAYER_ANDROID_H\n#define IJKPLAYER_ANDROID__IJKPLAYER_ANDROID_H\n\n#include <jni.h>\n#include \"ijkplayer_android_def.h\"\n#include \"../ijkplayer.h\"\n\ntypedef struct ijkmp_android_media_format_context {\n    const char *mime_type;\n    int         profile;\n    int         level;\n} ijkmp_android_media_format_context;\n\n// ref_count is 1 after open\nIjkMediaPlayer *ijkmp_android_create(int(*msg_loop)(void*));\n\nvoid ijkmp_android_set_surface(JNIEnv *env, IjkMediaPlayer *mp, jobject android_surface);\nvoid ijkmp_android_set_volume(JNIEnv *env, IjkMediaPlayer *mp, float left, float right);\nint  ijkmp_android_get_audio_session_id(JNIEnv *env, IjkMediaPlayer *mp);\nvoid ijkmp_android_set_mediacodec_select_callback(IjkMediaPlayer *mp, bool (*callback)(void *opaque, ijkmp_mediacodecinfo_context *mcc), void *opaque);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/android/ijkplayer_android_def.h",
    "content": "/*\n * ijkplayer_android_def.h\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKPLAYER_ANDROID__IJKPLAYER_ANDROID_DEF_H\n#define IJKPLAYER_ANDROID__IJKPLAYER_ANDROID_DEF_H\n\n/*\n * frameworks/av/include/media/mediaplayer.h\n */\n\n//\nenum media_event_type {\n    MEDIA_NOP               = 0,        // interface test message\n    MEDIA_PREPARED          = 1,\n    MEDIA_PLAYBACK_COMPLETE = 2,\n    MEDIA_BUFFERING_UPDATE  = 3,        // arg1 = percentage, arg2 = cached duration\n    MEDIA_SEEK_COMPLETE     = 4,\n    MEDIA_SET_VIDEO_SIZE    = 5,        // arg1 = width, arg2 = height\n    MEDIA_GET_IMG_STATE     = 6,        // arg1 = timestamp, arg2 = result code, obj = file name\n    MEDIA_TIMED_TEXT        = 99,       // not supported yet\n    MEDIA_ERROR             = 100,      // arg1, arg2\n    MEDIA_INFO              = 200,      // arg1, arg2\n\n\n    MEDIA_SET_VIDEO_SAR     = 10001,    // arg1 = sar.num, arg2 = sar.den\n};\n\n// Generic error codes for the media player framework.  Errors are fatal, the\n// playback must abort.\n//\n// Errors are communicated back to the client using the\n// MediaPlayerListener::notify method defined below.\n// In this situation, 'notify' is invoked with the following:\n//   'msg' is set to MEDIA_ERROR.\n//   'ext1' should be a value from the enum media_error_type.\n//   'ext2' contains an implementation dependant error code to provide\n//          more details. Should default to 0 when not used.\n//\n// The codes are distributed as follow:\n//   0xx: Reserved\n//   1xx: Android Player errors. Something went wrong inside the MediaPlayer.\n//   2xx: Media errors (e.g Codec not supported). There is a problem with the\n//        media itself.\n//   3xx: Runtime errors. Some extraordinary condition arose making the playback\n//        impossible.\n//\nenum media_error_type {\n    // 0xx\n    MEDIA_ERROR_UNKNOWN = 1,\n    // 1xx\n    MEDIA_ERROR_SERVER_DIED = 100,\n    // 2xx\n    MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200,\n    // 3xx\n\n    // -xx\n    MEDIA_ERROR_IO          = -1004,\n    MEDIA_ERROR_MALFORMED   = -1007,\n    MEDIA_ERROR_UNSUPPORTED = -1010,\n    MEDIA_ERROR_TIMED_OUT   = -110,\n\n    MEDIA_ERROR_IJK_PLAYER  = -10000,\n};\n\n// Info and warning codes for the media player framework.  These are non fatal,\n// the playback is going on but there might be some user visible issues.\n//\n// Info and warning messages are communicated back to the client using the\n// MediaPlayerListener::notify method defined below.  In this situation,\n// 'notify' is invoked with the following:\n//   'msg' is set to MEDIA_INFO.\n//   'ext1' should be a value from the enum media_info_type.\n//   'ext2' contains an implementation dependant info code to provide\n//          more details. Should default to 0 when not used.\n//\n// The codes are distributed as follow:\n//   0xx: Reserved\n//   7xx: Android Player info/warning (e.g player lagging behind.)\n//   8xx: Media info/warning (e.g media badly interleaved.)\n//\nenum media_info_type {\n    // 0xx\n    MEDIA_INFO_UNKNOWN = 1,\n    // The player was started because it was used as the next player for another\n    // player, which just completed playback\n    MEDIA_INFO_STARTED_AS_NEXT = 2,\n    // The player just pushed the very first video frame for rendering\n    MEDIA_INFO_VIDEO_RENDERING_START = 3,\n    // 7xx\n    // The video is too complex for the decoder: it can't decode frames fast\n    // enough. Possibly only the audio plays fine at this stage.\n    MEDIA_INFO_VIDEO_TRACK_LAGGING = 700,\n    // MediaPlayer is temporarily pausing playback internally in order to\n    // buffer more data.\n    MEDIA_INFO_BUFFERING_START = 701,\n    // MediaPlayer is resuming playback after filling buffers.\n    MEDIA_INFO_BUFFERING_END = 702,\n    // Bandwidth in recent past\n    MEDIA_INFO_NETWORK_BANDWIDTH = 703,\n\n    // 8xx\n    // Bad interleaving means that a media has been improperly interleaved or not\n    // interleaved at all, e.g has all the video samples first then all the audio\n    // ones. Video is playing but a lot of disk seek may be happening.\n    MEDIA_INFO_BAD_INTERLEAVING = 800,\n    // The media is not seekable (e.g live stream).\n    MEDIA_INFO_NOT_SEEKABLE = 801,\n    // New media metadata is available.\n    MEDIA_INFO_METADATA_UPDATE = 802,\n\n    //9xx\n    MEDIA_INFO_TIMED_TEXT_ERROR = 900,\n\n    //100xx\n    MEDIA_INFO_VIDEO_ROTATION_CHANGED = 10001,\n    MEDIA_INFO_AUDIO_RENDERING_START  = 10002,\n    MEDIA_INFO_AUDIO_DECODED_START    = 10003,\n    MEDIA_INFO_VIDEO_DECODED_START    = 10004,\n    MEDIA_INFO_OPEN_INPUT             = 10005,\n    MEDIA_INFO_FIND_STREAM_INFO       = 10006,\n    MEDIA_INFO_COMPONENT_OPEN         = 10007,\n    MEDIA_INFO_VIDEO_SEEK_RENDERING_START = 10008,\n    MEDIA_INFO_AUDIO_SEEK_RENDERING_START = 10009,\n\n    MEDIA_INFO_MEDIA_ACCURATE_SEEK_COMPLETE = 10100,\n};\n\ntypedef struct ijkmp_mediacodecinfo_context\n{\n    char mime_type[128];    //< in\n    int  profile;           //< in\n    int  level;             //< in\n    char codec_name[128];   //< out\n} ijkmp_mediacodecinfo_context;\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/android/ijkplayer_jni.c",
    "content": "/*\n * ijkplayer_jni.c\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include <assert.h>\n#include <string.h>\n#include <pthread.h>\n#include <jni.h>\n#include <unistd.h>\n#include \"j4a/class/java/util/ArrayList.h\"\n#include \"j4a/class/android/os/Bundle.h\"\n#include \"j4a/class/tv/danmaku/ijk/media/player/IjkMediaPlayer.h\"\n#include \"j4a/class/tv/danmaku/ijk/media/player/misc/IMediaDataSource.h\"\n#include \"j4a/class/tv/danmaku/ijk/media/player/misc/IAndroidIO.h\"\n#include \"ijksdl/ijksdl_log.h\"\n#include \"../ff_ffplay.h\"\n#include \"ffmpeg_api_jni.h\"\n#include \"ijkplayer_android_def.h\"\n#include \"ijkplayer_android.h\"\n#include \"ijksdl/android/ijksdl_android_jni.h\"\n#include \"ijksdl/android/ijksdl_codec_android_mediadef.h\"\n#include \"ijkavformat/ijkavformat.h\"\n\n#define JNI_MODULE_PACKAGE      \"tv/danmaku/ijk/media/player\"\n#define JNI_CLASS_IJKPLAYER     \"tv/danmaku/ijk/media/player/IjkMediaPlayer\"\n#define JNI_IJK_MEDIA_EXCEPTION \"tv/danmaku/ijk/media/player/exceptions/IjkMediaException\"\n\n#define IJK_CHECK_MPRET_GOTO(retval, env, label) \\\n    JNI_CHECK_GOTO((retval != EIJK_INVALID_STATE), env, \"java/lang/IllegalStateException\", NULL, label); \\\n    JNI_CHECK_GOTO((retval != EIJK_OUT_OF_MEMORY), env, \"java/lang/OutOfMemoryError\", NULL, label); \\\n    JNI_CHECK_GOTO((retval == 0), env, JNI_IJK_MEDIA_EXCEPTION, NULL, label);\n\nstatic JavaVM* g_jvm;\n\ntypedef struct player_fields_t {\n    pthread_mutex_t mutex;\n    jclass clazz;\n} player_fields_t;\nstatic player_fields_t g_clazz;\n\nstatic int inject_callback(void *opaque, int type, void *data, size_t data_size);\nstatic bool mediacodec_select_callback(void *opaque, ijkmp_mediacodecinfo_context *mcc);\n\nstatic IjkMediaPlayer *jni_get_media_player(JNIEnv* env, jobject thiz)\n{\n    pthread_mutex_lock(&g_clazz.mutex);\n\n    IjkMediaPlayer *mp = (IjkMediaPlayer *) (intptr_t) J4AC_IjkMediaPlayer__mNativeMediaPlayer__get__catchAll(env, thiz);\n    if (mp) {\n        ijkmp_inc_ref(mp);\n    }\n\n    pthread_mutex_unlock(&g_clazz.mutex);\n    return mp;\n}\n\nstatic IjkMediaPlayer *jni_set_media_player(JNIEnv* env, jobject thiz, IjkMediaPlayer *mp)\n{\n    pthread_mutex_lock(&g_clazz.mutex);\n\n    IjkMediaPlayer *old = (IjkMediaPlayer*) (intptr_t) J4AC_IjkMediaPlayer__mNativeMediaPlayer__get__catchAll(env, thiz);\n    if (mp) {\n        ijkmp_inc_ref(mp);\n    }\n    J4AC_IjkMediaPlayer__mNativeMediaPlayer__set__catchAll(env, thiz, (intptr_t) mp);\n\n    pthread_mutex_unlock(&g_clazz.mutex);\n\n    // NOTE: ijkmp_dec_ref may block thread\n    if (old != NULL ) {\n        ijkmp_dec_ref_p(&old);\n    }\n\n    return old;\n}\n\nstatic int64_t jni_set_media_data_source(JNIEnv* env, jobject thiz, jobject media_data_source)\n{\n    int64_t nativeMediaDataSource = 0;\n\n    pthread_mutex_lock(&g_clazz.mutex);\n\n    jobject old = (jobject) (intptr_t) J4AC_IjkMediaPlayer__mNativeMediaDataSource__get__catchAll(env, thiz);\n    if (old) {\n        J4AC_IMediaDataSource__close__catchAll(env, old);\n        J4A_DeleteGlobalRef__p(env, &old);\n        J4AC_IjkMediaPlayer__mNativeMediaDataSource__set__catchAll(env, thiz, 0);\n    }\n\n    if (media_data_source) {\n        jobject global_media_data_source = (*env)->NewGlobalRef(env, media_data_source);\n        if (J4A_ExceptionCheck__catchAll(env) || !global_media_data_source)\n            goto fail;\n\n        nativeMediaDataSource = (int64_t) (intptr_t) global_media_data_source;\n        J4AC_IjkMediaPlayer__mNativeMediaDataSource__set__catchAll(env, thiz, (jlong) nativeMediaDataSource);\n    }\n\nfail:\n    pthread_mutex_unlock(&g_clazz.mutex);\n    return nativeMediaDataSource;\n}\n\nstatic int64_t jni_set_ijkio_androidio(JNIEnv* env, jobject thiz, jobject ijk_io)\n{\n    int64_t nativeAndroidIO = 0;\n\n    pthread_mutex_lock(&g_clazz.mutex);\n\n    jobject old = (jobject) (intptr_t) J4AC_IjkMediaPlayer__mNativeAndroidIO__get__catchAll(env, thiz);\n    if (old) {\n        J4AC_IAndroidIO__close__catchAll(env, old);\n        J4A_DeleteGlobalRef__p(env, &old);\n        J4AC_IjkMediaPlayer__mNativeAndroidIO__set__catchAll(env, thiz, 0);\n    }\n\n    if (ijk_io) {\n        jobject global_ijkio_androidio = (*env)->NewGlobalRef(env, ijk_io);\n        if (J4A_ExceptionCheck__catchAll(env) || !global_ijkio_androidio)\n            goto fail;\n\n        nativeAndroidIO = (int64_t) (intptr_t) global_ijkio_androidio;\n        J4AC_IjkMediaPlayer__mNativeAndroidIO__set__catchAll(env, thiz, (jlong) nativeAndroidIO);\n    }\n\nfail:\n    pthread_mutex_unlock(&g_clazz.mutex);\n    return nativeAndroidIO;\n}\n\nstatic int message_loop(void *arg);\n\nstatic void\nIjkMediaPlayer_setDataSourceAndHeaders(\n    JNIEnv *env, jobject thiz, jstring path,\n    jobjectArray keys, jobjectArray values)\n{\n    MPTRACE(\"%s\\n\", __func__);\n    int retval = 0;\n    const char *c_path = NULL;\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    JNI_CHECK_GOTO(path, env, \"java/lang/IllegalArgumentException\", \"mpjni: setDataSource: null path\", LABEL_RETURN);\n    JNI_CHECK_GOTO(mp, env, \"java/lang/IllegalStateException\", \"mpjni: setDataSource: null mp\", LABEL_RETURN);\n\n    c_path = (*env)->GetStringUTFChars(env, path, NULL );\n    JNI_CHECK_GOTO(c_path, env, \"java/lang/OutOfMemoryError\", \"mpjni: setDataSource: path.string oom\", LABEL_RETURN);\n\n    ALOGV(\"setDataSource: path %s\", c_path);\n    retval = ijkmp_set_data_source(mp, c_path);\n    (*env)->ReleaseStringUTFChars(env, path, c_path);\n\n    IJK_CHECK_MPRET_GOTO(retval, env, LABEL_RETURN);\n\nLABEL_RETURN:\n    ijkmp_dec_ref_p(&mp);\n}\n\nstatic void\nIjkMediaPlayer_setDataSourceFd(JNIEnv *env, jobject thiz, jint fd)\n{\n    MPTRACE(\"%s\\n\", __func__);\n    int retval = 0;\n    int dupFd = 0;\n    char uri[128];\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    JNI_CHECK_GOTO(fd > 0, env, \"java/lang/IllegalArgumentException\", \"mpjni: setDataSourceFd: null fd\", LABEL_RETURN);\n    JNI_CHECK_GOTO(mp, env, \"java/lang/IllegalStateException\", \"mpjni: setDataSourceFd: null mp\", LABEL_RETURN);\n\n    dupFd = dup(fd);\n\n    ALOGV(\"setDataSourceFd: dup(%d)=%d\\n\", fd, dupFd);\n    snprintf(uri, sizeof(uri), \"pipe:%d\", dupFd);\n    retval = ijkmp_set_data_source(mp, uri);\n\n    IJK_CHECK_MPRET_GOTO(retval, env, LABEL_RETURN);\n\nLABEL_RETURN:\n    ijkmp_dec_ref_p(&mp);\n}\n\nstatic void\nIjkMediaPlayer_setDataSourceCallback(JNIEnv *env, jobject thiz, jobject callback)\n{\n    MPTRACE(\"%s\\n\", __func__);\n    int retval = 0;\n    char uri[128];\n    int64_t nativeMediaDataSource = 0;\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    JNI_CHECK_GOTO(callback, env, \"java/lang/IllegalArgumentException\", \"mpjni: setDataSourceCallback: null fd\", LABEL_RETURN);\n    JNI_CHECK_GOTO(mp, env, \"java/lang/IllegalStateException\", \"mpjni: setDataSourceCallback: null mp\", LABEL_RETURN);\n\n    nativeMediaDataSource = jni_set_media_data_source(env, thiz, callback);\n    JNI_CHECK_GOTO(nativeMediaDataSource, env, \"java/lang/IllegalStateException\", \"mpjni: jni_set_media_data_source: NewGlobalRef\", LABEL_RETURN);\n\n    ALOGV(\"setDataSourceCallback: %\"PRId64\"\\n\", nativeMediaDataSource);\n    snprintf(uri, sizeof(uri), \"ijkmediadatasource:%\"PRId64, nativeMediaDataSource);\n\n    retval = ijkmp_set_data_source(mp, uri);\n\n    IJK_CHECK_MPRET_GOTO(retval, env, LABEL_RETURN);\n\nLABEL_RETURN:\n    ijkmp_dec_ref_p(&mp);\n}\n\nstatic void\nIjkMediaPlayer_setAndroidIOCallback(JNIEnv *env, jobject thiz, jobject callback) {\n    MPTRACE(\"%s\\n\", __func__);\n    int64_t nativeAndroidIO = 0;\n\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    JNI_CHECK_GOTO(callback, env, \"java/lang/IllegalArgumentException\", \"mpjni: setAndroidIOCallback: null fd\", LABEL_RETURN);\n    JNI_CHECK_GOTO(mp, env, \"java/lang/IllegalStateException\", \"mpjni: setAndroidIOCallback: null mp\", LABEL_RETURN);\n\n    nativeAndroidIO = jni_set_ijkio_androidio(env, thiz, callback);\n    JNI_CHECK_GOTO(nativeAndroidIO, env, \"java/lang/IllegalStateException\", \"mpjni: jni_set_ijkio_androidio: NewGlobalRef\", LABEL_RETURN);\n\n    ijkmp_set_option_int(mp, FFP_OPT_CATEGORY_FORMAT, \"androidio-inject-callback\", nativeAndroidIO);\n\nLABEL_RETURN:\n    ijkmp_dec_ref_p(&mp);\n}\n\nstatic void\nIjkMediaPlayer_setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface)\n{\n    MPTRACE(\"%s\\n\", __func__);\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    JNI_CHECK_GOTO(mp, env, NULL, \"mpjni: setVideoSurface: null mp\", LABEL_RETURN);\n\n    ijkmp_android_set_surface(env, mp, jsurface);\n\nLABEL_RETURN:\n    ijkmp_dec_ref_p(&mp);\n    return;\n}\n\nstatic void\nIjkMediaPlayer_prepareAsync(JNIEnv *env, jobject thiz)\n{\n    MPTRACE(\"%s\\n\", __func__);\n    int retval = 0;\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    JNI_CHECK_GOTO(mp, env, \"java/lang/IllegalStateException\", \"mpjni: prepareAsync: null mp\", LABEL_RETURN);\n\n    retval = ijkmp_prepare_async(mp);\n    IJK_CHECK_MPRET_GOTO(retval, env, LABEL_RETURN);\n\nLABEL_RETURN:\n    ijkmp_dec_ref_p(&mp);\n}\n\nstatic void\nIjkMediaPlayer_start(JNIEnv *env, jobject thiz)\n{\n    MPTRACE(\"%s\\n\", __func__);\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    JNI_CHECK_GOTO(mp, env, \"java/lang/IllegalStateException\", \"mpjni: start: null mp\", LABEL_RETURN);\n\n    ijkmp_start(mp);\n\nLABEL_RETURN:\n    ijkmp_dec_ref_p(&mp);\n}\n\nstatic void\nIjkMediaPlayer_stop(JNIEnv *env, jobject thiz)\n{\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    JNI_CHECK_GOTO(mp, env, \"java/lang/IllegalStateException\", \"mpjni: stop: null mp\", LABEL_RETURN);\n\n    ijkmp_stop(mp);\n\nLABEL_RETURN:\n    ijkmp_dec_ref_p(&mp);\n}\n\nstatic void\nIjkMediaPlayer_pause(JNIEnv *env, jobject thiz)\n{\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    JNI_CHECK_GOTO(mp, env, \"java/lang/IllegalStateException\", \"mpjni: pause: null mp\", LABEL_RETURN);\n\n    ijkmp_pause(mp);\n\nLABEL_RETURN:\n    ijkmp_dec_ref_p(&mp);\n}\n\nstatic void\nIjkMediaPlayer_seekTo(JNIEnv *env, jobject thiz, jlong msec)\n{\n    MPTRACE(\"%s\\n\", __func__);\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    JNI_CHECK_GOTO(mp, env, \"java/lang/IllegalStateException\", \"mpjni: seekTo: null mp\", LABEL_RETURN);\n\n    ijkmp_seek_to(mp, msec);\n\nLABEL_RETURN:\n    ijkmp_dec_ref_p(&mp);\n}\n\nstatic jboolean\nIjkMediaPlayer_isPlaying(JNIEnv *env, jobject thiz)\n{\n    jboolean retval = JNI_FALSE;\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    JNI_CHECK_GOTO(mp, env, NULL, \"mpjni: isPlaying: null mp\", LABEL_RETURN);\n\n    retval = ijkmp_is_playing(mp) ? JNI_TRUE : JNI_FALSE;\n\nLABEL_RETURN:\n    ijkmp_dec_ref_p(&mp);\n    return retval;\n}\n\nstatic jlong\nIjkMediaPlayer_getCurrentPosition(JNIEnv *env, jobject thiz)\n{\n    jlong retval = 0;\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    JNI_CHECK_GOTO(mp, env, NULL, \"mpjni: getCurrentPosition: null mp\", LABEL_RETURN);\n\n    retval = ijkmp_get_current_position(mp);\n\nLABEL_RETURN:\n    ijkmp_dec_ref_p(&mp);\n    return retval;\n}\n\nstatic jlong\nIjkMediaPlayer_getDuration(JNIEnv *env, jobject thiz)\n{\n    jlong retval = 0;\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    JNI_CHECK_GOTO(mp, env, NULL, \"mpjni: getDuration: null mp\", LABEL_RETURN);\n\n    retval = ijkmp_get_duration(mp);\n\nLABEL_RETURN:\n    ijkmp_dec_ref_p(&mp);\n    return retval;\n}\n\nstatic void\nIjkMediaPlayer_release(JNIEnv *env, jobject thiz)\n{\n    MPTRACE(\"%s\\n\", __func__);\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    if (!mp)\n        return;\n\n    ijkmp_android_set_surface(env, mp, NULL);\n    // explicit shutdown mp, in case it is not the last mp-ref here\n    ijkmp_shutdown(mp);\n    //only delete weak_thiz at release\n    jobject weak_thiz = (jobject) ijkmp_set_weak_thiz(mp, NULL );\n    (*env)->DeleteGlobalRef(env, weak_thiz);\n    jni_set_media_player(env, thiz, NULL);\n    jni_set_media_data_source(env, thiz, NULL);\n\n    ijkmp_dec_ref_p(&mp);\n}\n\nstatic void IjkMediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this);\nstatic void\nIjkMediaPlayer_reset(JNIEnv *env, jobject thiz)\n{\n    MPTRACE(\"%s\\n\", __func__);\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    if (!mp)\n        return;\n\n    jobject weak_thiz = (jobject) ijkmp_set_weak_thiz(mp, NULL );\n\n    IjkMediaPlayer_release(env, thiz);\n    IjkMediaPlayer_native_setup(env, thiz, weak_thiz);\n\n    ijkmp_dec_ref_p(&mp);\n}\n\nstatic void\nIjkMediaPlayer_setLoopCount(JNIEnv *env, jobject thiz, jint loop_count)\n{\n    MPTRACE(\"%s\\n\", __func__);\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    JNI_CHECK_GOTO(mp, env, NULL, \"mpjni: setLoopCount: null mp\", LABEL_RETURN);\n\n    ijkmp_set_loop(mp, loop_count);\n\nLABEL_RETURN:\n    ijkmp_dec_ref_p(&mp);\n}\n\nstatic jint\nIjkMediaPlayer_getLoopCount(JNIEnv *env, jobject thiz)\n{\n    jint loop_count = 1;\n    MPTRACE(\"%s\\n\", __func__);\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    JNI_CHECK_GOTO(mp, env, NULL, \"mpjni: getLoopCount: null mp\", LABEL_RETURN);\n\n    loop_count = ijkmp_get_loop(mp);\n\nLABEL_RETURN:\n    ijkmp_dec_ref_p(&mp);\n    return loop_count;\n}\n\nstatic jfloat\nijkMediaPlayer_getPropertyFloat(JNIEnv *env, jobject thiz, jint id, jfloat default_value)\n{\n    jfloat value = default_value;\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    JNI_CHECK_GOTO(mp, env, NULL, \"mpjni: getPropertyFloat: null mp\", LABEL_RETURN);\n\n    value = ijkmp_get_property_float(mp, id, default_value);\n\nLABEL_RETURN:\n    ijkmp_dec_ref_p(&mp);\n    return value;\n}\n\nstatic void\nijkMediaPlayer_setPropertyFloat(JNIEnv *env, jobject thiz, jint id, jfloat value)\n{\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    JNI_CHECK_GOTO(mp, env, NULL, \"mpjni: setPropertyFloat: null mp\", LABEL_RETURN);\n\n    ijkmp_set_property_float(mp, id, value);\n\nLABEL_RETURN:\n    ijkmp_dec_ref_p(&mp);\n    return;\n}\n\nstatic jlong\nijkMediaPlayer_getPropertyLong(JNIEnv *env, jobject thiz, jint id, jlong default_value)\n{\n    jlong value = default_value;\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    JNI_CHECK_GOTO(mp, env, NULL, \"mpjni: getPropertyLong: null mp\", LABEL_RETURN);\n\n    value = ijkmp_get_property_int64(mp, id, default_value);\n\nLABEL_RETURN:\n    ijkmp_dec_ref_p(&mp);\n    return value;\n}\n\nstatic void\nijkMediaPlayer_setPropertyLong(JNIEnv *env, jobject thiz, jint id, jlong value)\n{\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    JNI_CHECK_GOTO(mp, env, NULL, \"mpjni: setPropertyLong: null mp\", LABEL_RETURN);\n\n    ijkmp_set_property_int64(mp, id, value);\n\nLABEL_RETURN:\n    ijkmp_dec_ref_p(&mp);\n    return;\n}\n\nstatic void\nijkMediaPlayer_setStreamSelected(JNIEnv *env, jobject thiz, jint stream, jboolean selected)\n{\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    int ret = 0;\n    JNI_CHECK_GOTO(mp, env, NULL, \"mpjni: setStreamSelected: null mp\", LABEL_RETURN);\n\n    ret = ijkmp_set_stream_selected(mp, stream, selected);\n    if (ret < 0) {\n        ALOGE(\"failed to %s %d\", selected ? \"select\" : \"deselect\", stream);\n        goto LABEL_RETURN;\n    }\n\nLABEL_RETURN:\n    ijkmp_dec_ref_p(&mp);\n    return;\n}\n\nstatic void\nIjkMediaPlayer_setVolume(JNIEnv *env, jobject thiz, jfloat leftVolume, jfloat rightVolume)\n{\n    MPTRACE(\"%s\\n\", __func__);\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    JNI_CHECK_GOTO(mp, env, NULL, \"mpjni: setVolume: null mp\", LABEL_RETURN);\n\n    ijkmp_android_set_volume(env, mp, leftVolume, rightVolume);\n\nLABEL_RETURN:\n    ijkmp_dec_ref_p(&mp);\n}\n\nstatic jint\nIjkMediaPlayer_getAudioSessionId(JNIEnv *env, jobject thiz)\n{\n    jint audio_session_id = 0;\n    MPTRACE(\"%s\\n\", __func__);\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    JNI_CHECK_GOTO(mp, env, NULL, \"mpjni: getAudioSessionId: null mp\", LABEL_RETURN);\n\n    audio_session_id = ijkmp_android_get_audio_session_id(env, mp);\n\nLABEL_RETURN:\n    ijkmp_dec_ref_p(&mp);\n    return audio_session_id;\n}\n\nstatic void\nIjkMediaPlayer_setOption(JNIEnv *env, jobject thiz, jint category, jobject name, jobject value)\n{\n    MPTRACE(\"%s\\n\", __func__);\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    const char *c_name = NULL;\n    const char *c_value = NULL;\n    JNI_CHECK_GOTO(mp, env, \"java/lang/IllegalStateException\", \"mpjni: setOption: null mp\", LABEL_RETURN);\n\n    if (!name) {\n        goto LABEL_RETURN;\n    }\n\n    c_name = (*env)->GetStringUTFChars(env, name, NULL );\n    JNI_CHECK_GOTO(c_name, env, \"java/lang/OutOfMemoryError\", \"mpjni: setOption: name.string oom\", LABEL_RETURN);\n    JNI_CHECK_GOTO(mp, env, NULL, \"mpjni: IjkMediaPlayer_setOption: null name\", LABEL_RETURN);\n\n    if (value) {\n        c_value = (*env)->GetStringUTFChars(env, value, NULL );\n        JNI_CHECK_GOTO(c_name, env, \"java/lang/OutOfMemoryError\", \"mpjni: setOption: name.string oom\", LABEL_RETURN);\n    }\n\n    ijkmp_set_option(mp, category, c_name, c_value);\n\nLABEL_RETURN:\n    if (c_name)\n        (*env)->ReleaseStringUTFChars(env, name, c_name);\n    if (c_value)\n        (*env)->ReleaseStringUTFChars(env, value, c_value);\n    ijkmp_dec_ref_p(&mp);\n}\n\nstatic void\nIjkMediaPlayer_setOptionLong(JNIEnv *env, jobject thiz, jint category, jobject name, jlong value)\n{\n    MPTRACE(\"%s\\n\", __func__);\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    const char *c_name = NULL;\n    JNI_CHECK_GOTO(mp, env, \"java/lang/IllegalStateException\", \"mpjni: setOptionLong: null mp\", LABEL_RETURN);\n\n    c_name = (*env)->GetStringUTFChars(env, name, NULL );\n    JNI_CHECK_GOTO(c_name, env, \"java/lang/OutOfMemoryError\", \"mpjni: setOptionLong: name.string oom\", LABEL_RETURN);\n\n    ijkmp_set_option_int(mp, category, c_name, value);\n\nLABEL_RETURN:\n    if (c_name)\n        (*env)->ReleaseStringUTFChars(env, name, c_name);\n    ijkmp_dec_ref_p(&mp);\n}\n\nstatic jstring\nIjkMediaPlayer_getColorFormatName(JNIEnv *env, jclass clazz, jint mediaCodecColorFormat)\n{\n    const char *codec_name = SDL_AMediaCodec_getColorFormatName(mediaCodecColorFormat);\n    if (!codec_name)\n        return NULL ;\n\n    return (*env)->NewStringUTF(env, codec_name);\n}\n\nstatic jstring\nIjkMediaPlayer_getVideoCodecInfo(JNIEnv *env, jobject thiz)\n{\n    MPTRACE(\"%s\\n\", __func__);\n    jstring jcodec_info = NULL;\n    int ret = 0;\n    char *codec_info = NULL;\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    JNI_CHECK_GOTO(mp, env, \"java/lang/IllegalStateException\", \"mpjni: getVideoCodecInfo: null mp\", LABEL_RETURN);\n\n    ret = ijkmp_get_video_codec_info(mp, &codec_info);\n    if (ret < 0 || !codec_info)\n        goto LABEL_RETURN;\n\n    jcodec_info = (*env)->NewStringUTF(env, codec_info);\nLABEL_RETURN:\n    if (codec_info)\n        free(codec_info);\n\n    ijkmp_dec_ref_p(&mp);\n    return jcodec_info;\n}\n\nstatic jstring\nIjkMediaPlayer_getAudioCodecInfo(JNIEnv *env, jobject thiz)\n{\n    MPTRACE(\"%s\\n\", __func__);\n    jstring jcodec_info = NULL;\n    int ret = 0;\n    char *codec_info = NULL;\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    JNI_CHECK_GOTO(mp, env, \"java/lang/IllegalStateException\", \"mpjni: getAudioCodecInfo: null mp\", LABEL_RETURN);\n\n    ret = ijkmp_get_audio_codec_info(mp, &codec_info);\n    if (ret < 0 || !codec_info)\n        goto LABEL_RETURN;\n\n    jcodec_info = (*env)->NewStringUTF(env, codec_info);\nLABEL_RETURN:\n    if (codec_info)\n        free(codec_info);\n\n    ijkmp_dec_ref_p(&mp);\n    return jcodec_info;\n}\n\ninline static void fillMetaInternal(JNIEnv *env, jobject jbundle, IjkMediaMeta *meta, const char *key, const char *default_value)\n{\n    const char *value = ijkmeta_get_string_l(meta, key);\n    if (value == NULL )\n        value = default_value;\n\n    J4AC_Bundle__putString__withCString__catchAll(env, jbundle, key, value);\n}\n\nstatic jobject\nIjkMediaPlayer_getMediaMeta(JNIEnv *env, jobject thiz)\n{\n    MPTRACE(\"%s\\n\", __func__);\n    bool is_locked = false;\n    jobject jret_bundle = NULL;\n    jobject jlocal_bundle = NULL;\n    jobject jstream_bundle = NULL;\n    jobject jarray_list = NULL;\n    IjkMediaMeta *meta = NULL;\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    JNI_CHECK_GOTO(mp, env, \"java/lang/IllegalStateException\", \"mpjni: getMediaMeta: null mp\", LABEL_RETURN);\n\n    meta = ijkmp_get_meta_l(mp);\n    if (!meta)\n        goto LABEL_RETURN;\n\n    ijkmeta_lock(meta);\n    is_locked = true;\n\n    jlocal_bundle = J4AC_Bundle__Bundle(env);\n    if (J4A_ExceptionCheck__throwAny(env)) {\n        goto LABEL_RETURN;\n    }\n\n    fillMetaInternal(env, jlocal_bundle, meta, IJKM_KEY_FORMAT, NULL );\n    fillMetaInternal(env, jlocal_bundle, meta, IJKM_KEY_DURATION_US, NULL );\n    fillMetaInternal(env, jlocal_bundle, meta, IJKM_KEY_START_US, NULL );\n    fillMetaInternal(env, jlocal_bundle, meta, IJKM_KEY_BITRATE, NULL );\n\n    fillMetaInternal(env, jlocal_bundle, meta, IJKM_KEY_VIDEO_STREAM, \"-1\");\n    fillMetaInternal(env, jlocal_bundle, meta, IJKM_KEY_AUDIO_STREAM, \"-1\");\n    fillMetaInternal(env, jlocal_bundle, meta, IJKM_KEY_TIMEDTEXT_STREAM, \"-1\");\n\n    jarray_list = J4AC_ArrayList__ArrayList(env);\n    if (J4A_ExceptionCheck__throwAny(env)) {\n        goto LABEL_RETURN;\n    }\n\n    size_t count = ijkmeta_get_children_count_l(meta);\n    for (size_t i = 0; i < count; ++i) {\n        IjkMediaMeta *streamRawMeta = ijkmeta_get_child_l(meta, i);\n        if (streamRawMeta) {\n            jstream_bundle = J4AC_Bundle__Bundle(env);\n            if (J4A_ExceptionCheck__throwAny(env)) {\n                goto LABEL_RETURN;\n            }\n\n            fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_TYPE,     IJKM_VAL_TYPE__UNKNOWN);\n            fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_LANGUAGE, NULL);\n            const char *type = ijkmeta_get_string_l(streamRawMeta, IJKM_KEY_TYPE);\n            if (type) {\n                fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_CODEC_NAME, NULL );\n                fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_CODEC_PROFILE, NULL );\n                fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_CODEC_LEVEL, NULL );\n                fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_CODEC_LONG_NAME, NULL );\n                fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_CODEC_PIXEL_FORMAT, NULL );\n                fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_BITRATE, NULL );\n                fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_CODEC_PROFILE_ID, NULL );\n\n                if (0 == strcmp(type, IJKM_VAL_TYPE__VIDEO)) {\n                    fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_WIDTH, NULL );\n                    fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_HEIGHT, NULL );\n                    fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_FPS_NUM, NULL );\n                    fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_FPS_DEN, NULL );\n                    fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_TBR_NUM, NULL );\n                    fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_TBR_DEN, NULL );\n                    fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_SAR_NUM, NULL );\n                    fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_SAR_DEN, NULL );\n                } else if (0 == strcmp(type, IJKM_VAL_TYPE__AUDIO)) {\n                    fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_SAMPLE_RATE, NULL );\n                    fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_CHANNEL_LAYOUT, NULL );\n                }\n                J4AC_ArrayList__add(env, jarray_list, jstream_bundle);\n                if (J4A_ExceptionCheck__throwAny(env)) {\n                    goto LABEL_RETURN;\n                }\n            }\n\n            SDL_JNI_DeleteLocalRefP(env, &jstream_bundle);\n        }\n    }\n\n    J4AC_Bundle__putParcelableArrayList__withCString__catchAll(env, jlocal_bundle, IJKM_KEY_STREAMS, jarray_list);\n    jret_bundle = jlocal_bundle;\n    jlocal_bundle = NULL;\nLABEL_RETURN:\n    if (is_locked && meta)\n        ijkmeta_unlock(meta);\n\n    SDL_JNI_DeleteLocalRefP(env, &jstream_bundle);\n    SDL_JNI_DeleteLocalRefP(env, &jlocal_bundle);\n    SDL_JNI_DeleteLocalRefP(env, &jarray_list);\n\n    ijkmp_dec_ref_p(&mp);\n    return jret_bundle;\n}\n\nstatic void\nIjkMediaPlayer_native_init(JNIEnv *env)\n{\n    MPTRACE(\"%s\\n\", __func__);\n}\n\nstatic void\nIjkMediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)\n{\n    MPTRACE(\"%s\\n\", __func__);\n    IjkMediaPlayer *mp = ijkmp_android_create(message_loop);\n    JNI_CHECK_GOTO(mp, env, \"java/lang/OutOfMemoryError\", \"mpjni: native_setup: ijkmp_create() failed\", LABEL_RETURN);\n\n    jni_set_media_player(env, thiz, mp);\n    ijkmp_set_weak_thiz(mp, (*env)->NewGlobalRef(env, weak_this));\n    ijkmp_set_inject_opaque(mp, ijkmp_get_weak_thiz(mp));\n    ijkmp_set_ijkio_inject_opaque(mp, ijkmp_get_weak_thiz(mp));\n    ijkmp_android_set_mediacodec_select_callback(mp, mediacodec_select_callback, ijkmp_get_weak_thiz(mp));\n\nLABEL_RETURN:\n    ijkmp_dec_ref_p(&mp);\n}\n\nstatic void\nIjkMediaPlayer_native_finalize(JNIEnv *env, jobject thiz, jobject name, jobject value)\n{\n    MPTRACE(\"%s\\n\", __func__);\n    IjkMediaPlayer_release(env, thiz);\n}\n\n// NOTE: support to be called from read_thread\nstatic int\ninject_callback(void *opaque, int what, void *data, size_t data_size)\n{\n    JNIEnv     *env     = NULL;\n    jobject     jbundle = NULL;\n    int         ret     = -1;\n    SDL_JNI_SetupThreadEnv(&env);\n\n    jobject weak_thiz = (jobject) opaque;\n    if (weak_thiz == NULL )\n        goto fail;\n    switch (what) {\n        case AVAPP_CTRL_WILL_HTTP_OPEN:\n        case AVAPP_CTRL_WILL_LIVE_OPEN:\n        case AVAPP_CTRL_WILL_CONCAT_SEGMENT_OPEN: {\n            AVAppIOControl *real_data = (AVAppIOControl *)data;\n            real_data->is_handled = 0;\n\n            jbundle = J4AC_Bundle__Bundle__catchAll(env);\n            if (!jbundle) {\n                ALOGE(\"%s: J4AC_Bundle__Bundle__catchAll failed for case %d\\n\", __func__, what);\n                goto fail;\n            }\n            J4AC_Bundle__putString__withCString__catchAll(env, jbundle, \"url\", real_data->url);\n            J4AC_Bundle__putInt__withCString__catchAll(env, jbundle, \"segment_index\", real_data->segment_index);\n            J4AC_Bundle__putInt__withCString__catchAll(env, jbundle, \"retry_counter\", real_data->retry_counter);\n            real_data->is_handled = J4AC_IjkMediaPlayer__onNativeInvoke(env, weak_thiz, what, jbundle);\n            if (J4A_ExceptionCheck__catchAll(env)) {\n                goto fail;\n            }\n\n            J4AC_Bundle__getString__withCString__asCBuffer(env, jbundle, \"url\", real_data->url, sizeof(real_data->url));\n            if (J4A_ExceptionCheck__catchAll(env)) {\n                goto fail;\n            }\n            ret = 0;\n            break;\n        }\n        case AVAPP_EVENT_WILL_HTTP_OPEN:\n        case AVAPP_EVENT_DID_HTTP_OPEN:\n        case AVAPP_EVENT_WILL_HTTP_SEEK:\n        case AVAPP_EVENT_DID_HTTP_SEEK: {\n            AVAppHttpEvent *real_data = (AVAppHttpEvent *) data;\n            jbundle = J4AC_Bundle__Bundle__catchAll(env);\n            if (!jbundle) {\n                ALOGE(\"%s: J4AC_Bundle__Bundle__catchAll failed for case %d\\n\", __func__, what);\n                goto fail;\n            }\n            J4AC_Bundle__putString__withCString__catchAll(env, jbundle, \"url\", real_data->url);\n            J4AC_Bundle__putLong__withCString__catchAll(env, jbundle, \"offset\", real_data->offset);\n            J4AC_Bundle__putInt__withCString__catchAll(env, jbundle, \"error\", real_data->error);\n            J4AC_Bundle__putInt__withCString__catchAll(env, jbundle, \"http_code\", real_data->http_code);\n            J4AC_Bundle__putLong__withCString__catchAll(env, jbundle, \"file_size\", real_data->filesize);\n            J4AC_IjkMediaPlayer__onNativeInvoke(env, weak_thiz, what, jbundle);\n            if (J4A_ExceptionCheck__catchAll(env))\n                goto fail;\n            ret = 0;\n            break;\n        }\n        case AVAPP_CTRL_DID_TCP_OPEN:\n        case AVAPP_CTRL_WILL_TCP_OPEN: {\n            AVAppTcpIOControl *real_data = (AVAppTcpIOControl *)data;\n            jbundle = J4AC_Bundle__Bundle__catchAll(env);\n            if (!jbundle) {\n                ALOGE(\"%s: J4AC_Bundle__Bundle__catchAll failed for case %d\\n\", __func__, what);\n                goto fail;\n            }\n            J4AC_Bundle__putInt__withCString__catchAll(env, jbundle, \"error\", real_data->error);\n            J4AC_Bundle__putInt__withCString__catchAll(env, jbundle, \"family\", real_data->family);\n            J4AC_Bundle__putString__withCString__catchAll(env, jbundle, \"ip\", real_data->ip);\n            J4AC_Bundle__putInt__withCString__catchAll(env, jbundle, \"port\", real_data->port);\n            J4AC_Bundle__putInt__withCString__catchAll(env, jbundle, \"fd\", real_data->fd);\n            J4AC_IjkMediaPlayer__onNativeInvoke(env, weak_thiz, what, jbundle);\n            if (J4A_ExceptionCheck__catchAll(env))\n                goto fail;\n            ret = 0;\n            break;\n        }\n        default: {\n            ret = 0;\n        }\n    }\nfail:\n    SDL_JNI_DeleteLocalRefP(env, &jbundle);\n    return ret;\n}\n\nstatic bool mediacodec_select_callback(void *opaque, ijkmp_mediacodecinfo_context *mcc)\n{\n    JNIEnv *env = NULL;\n    jobject weak_this = (jobject) opaque;\n    const char *found_codec_name = NULL;\n\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"%s: SetupThreadEnv failed\\n\", __func__);\n        return -1;\n    }\n\n    found_codec_name = J4AC_IjkMediaPlayer__onSelectCodec__withCString__asCBuffer(env, weak_this, mcc->mime_type, mcc->profile, mcc->level, mcc->codec_name, sizeof(mcc->codec_name));\n    if (J4A_ExceptionCheck__catchAll(env) || !found_codec_name) {\n        ALOGE(\"%s: onSelectCodec failed\\n\", __func__);\n        goto fail;\n    }\n\nfail:\n    return found_codec_name;\n}\n\ninline static void post_event(JNIEnv *env, jobject weak_this, int what, int arg1, int arg2)\n{\n    // MPTRACE(\"post_event(%p, %p, %d, %d, %d)\", (void*)env, (void*) weak_this, what, arg1, arg2);\n    J4AC_IjkMediaPlayer__postEventFromNative(env, weak_this, what, arg1, arg2, NULL);\n    // MPTRACE(\"post_event()=void\");\n}\n\ninline static void post_event2(JNIEnv *env, jobject weak_this, int what, int arg1, int arg2, jobject obj)\n{\n    // MPTRACE(\"post_event2(%p, %p, %d, %d, %d, %p)\", (void*)env, (void*) weak_this, what, arg1, arg2, (void*)obj);\n    J4AC_IjkMediaPlayer__postEventFromNative(env, weak_this, what, arg1, arg2, obj);\n    // MPTRACE(\"post_event2()=void\");\n}\n\nstatic void message_loop_n(JNIEnv *env, IjkMediaPlayer *mp)\n{\n    jobject weak_thiz = (jobject) ijkmp_get_weak_thiz(mp);\n    JNI_CHECK_GOTO(weak_thiz, env, NULL, \"mpjni: message_loop_n: null weak_thiz\", LABEL_RETURN);\n\n    while (1) {\n        AVMessage msg;\n\n        int retval = ijkmp_get_msg(mp, &msg, 1);\n        if (retval < 0)\n            break;\n\n        // block-get should never return 0\n        assert(retval > 0);\n\n        switch (msg.what) {\n        case FFP_MSG_FLUSH:\n            MPTRACE(\"FFP_MSG_FLUSH:\\n\");\n            post_event(env, weak_thiz, MEDIA_NOP, 0, 0);\n            break;\n        case FFP_MSG_ERROR:\n            MPTRACE(\"FFP_MSG_ERROR: %d\\n\", msg.arg1);\n            post_event(env, weak_thiz, MEDIA_ERROR, MEDIA_ERROR_IJK_PLAYER, msg.arg1);\n            break;\n        case FFP_MSG_PREPARED:\n            MPTRACE(\"FFP_MSG_PREPARED:\\n\");\n            post_event(env, weak_thiz, MEDIA_PREPARED, 0, 0);\n            break;\n        case FFP_MSG_COMPLETED:\n            MPTRACE(\"FFP_MSG_COMPLETED:\\n\");\n            post_event(env, weak_thiz, MEDIA_PLAYBACK_COMPLETE, 0, 0);\n            break;\n        case FFP_MSG_VIDEO_SIZE_CHANGED:\n            MPTRACE(\"FFP_MSG_VIDEO_SIZE_CHANGED: %d, %d\\n\", msg.arg1, msg.arg2);\n            post_event(env, weak_thiz, MEDIA_SET_VIDEO_SIZE, msg.arg1, msg.arg2);\n            break;\n        case FFP_MSG_SAR_CHANGED:\n            MPTRACE(\"FFP_MSG_SAR_CHANGED: %d, %d\\n\", msg.arg1, msg.arg2);\n            post_event(env, weak_thiz, MEDIA_SET_VIDEO_SAR, msg.arg1, msg.arg2);\n            break;\n        case FFP_MSG_VIDEO_RENDERING_START:\n            MPTRACE(\"FFP_MSG_VIDEO_RENDERING_START:\\n\");\n            post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_VIDEO_RENDERING_START, 0);\n            break;\n        case FFP_MSG_AUDIO_RENDERING_START:\n            MPTRACE(\"FFP_MSG_AUDIO_RENDERING_START:\\n\");\n            post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_AUDIO_RENDERING_START, 0);\n            break;\n        case FFP_MSG_VIDEO_ROTATION_CHANGED:\n            MPTRACE(\"FFP_MSG_VIDEO_ROTATION_CHANGED: %d\\n\", msg.arg1);\n            post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_VIDEO_ROTATION_CHANGED, msg.arg1);\n            break;\n        case FFP_MSG_AUDIO_DECODED_START:\n            MPTRACE(\"FFP_MSG_AUDIO_DECODED_START:\\n\");\n            post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_AUDIO_DECODED_START, 0);\n            break;\n        case FFP_MSG_VIDEO_DECODED_START:\n            MPTRACE(\"FFP_MSG_VIDEO_DECODED_START:\\n\");\n            post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_VIDEO_DECODED_START, 0);\n            break;\n        case FFP_MSG_OPEN_INPUT:\n            MPTRACE(\"FFP_MSG_OPEN_INPUT:\\n\");\n            post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_OPEN_INPUT, 0);\n            break;\n        case FFP_MSG_FIND_STREAM_INFO:\n            MPTRACE(\"FFP_MSG_FIND_STREAM_INFO:\\n\");\n            post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_FIND_STREAM_INFO, 0);\n            break;\n        case FFP_MSG_COMPONENT_OPEN:\n            MPTRACE(\"FFP_MSG_COMPONENT_OPEN:\\n\");\n            post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_COMPONENT_OPEN, 0);\n            break;\n        case FFP_MSG_BUFFERING_START:\n            MPTRACE(\"FFP_MSG_BUFFERING_START:\\n\");\n            post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_BUFFERING_START, msg.arg1);\n            break;\n        case FFP_MSG_BUFFERING_END:\n            MPTRACE(\"FFP_MSG_BUFFERING_END:\\n\");\n            post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_BUFFERING_END, msg.arg1);\n            break;\n        case FFP_MSG_BUFFERING_UPDATE:\n            // MPTRACE(\"FFP_MSG_BUFFERING_UPDATE: %d, %d\", msg.arg1, msg.arg2);\n            post_event(env, weak_thiz, MEDIA_BUFFERING_UPDATE, msg.arg1, msg.arg2);\n            break;\n        case FFP_MSG_BUFFERING_BYTES_UPDATE:\n            break;\n        case FFP_MSG_BUFFERING_TIME_UPDATE:\n            break;\n        case FFP_MSG_SEEK_COMPLETE:\n            MPTRACE(\"FFP_MSG_SEEK_COMPLETE:\\n\");\n            post_event(env, weak_thiz, MEDIA_SEEK_COMPLETE, 0, 0);\n            break;\n        case FFP_MSG_ACCURATE_SEEK_COMPLETE:\n            MPTRACE(\"FFP_MSG_ACCURATE_SEEK_COMPLETE:\\n\");\n            post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_MEDIA_ACCURATE_SEEK_COMPLETE, msg.arg1);\n            break;\n        case FFP_MSG_PLAYBACK_STATE_CHANGED:\n            break;\n        case FFP_MSG_TIMED_TEXT:\n            if (msg.obj) {\n                jstring text = (*env)->NewStringUTF(env, (char *)msg.obj);\n                post_event2(env, weak_thiz, MEDIA_TIMED_TEXT, 0, 0, text);\n                J4A_DeleteLocalRef__p(env, &text);\n            }\n            else {\n                post_event2(env, weak_thiz, MEDIA_TIMED_TEXT, 0, 0, NULL);\n            }\n            break;\n        case FFP_MSG_GET_IMG_STATE:\n            if (msg.obj) {\n                jstring file_name = (*env)->NewStringUTF(env, (char *)msg.obj);\n                post_event2(env, weak_thiz, MEDIA_GET_IMG_STATE, msg.arg1, msg.arg2, file_name);\n                J4A_DeleteLocalRef__p(env, &file_name);\n            }\n            else {\n                post_event2(env, weak_thiz, MEDIA_GET_IMG_STATE, msg.arg1, msg.arg2, NULL);\n            }\n            break;\n        case FFP_MSG_VIDEO_SEEK_RENDERING_START:\n            MPTRACE(\"FFP_MSG_VIDEO_SEEK_RENDERING_START:\\n\");\n            post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_VIDEO_SEEK_RENDERING_START, msg.arg1);\n            break;\n        case FFP_MSG_AUDIO_SEEK_RENDERING_START:\n            MPTRACE(\"FFP_MSG_AUDIO_SEEK_RENDERING_START:\\n\");\n            post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_AUDIO_SEEK_RENDERING_START, msg.arg1);\n            break;\n        default:\n            ALOGE(\"unknown FFP_MSG_xxx(%d)\\n\", msg.what);\n            break;\n        }\n        msg_free_res(&msg);\n    }\n\nLABEL_RETURN:\n    ;\n}\n\nstatic int message_loop(void *arg)\n{\n    MPTRACE(\"%s\\n\", __func__);\n\n    JNIEnv *env = NULL;\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"%s: SetupThreadEnv failed\\n\", __func__);\n        return -1;\n    }\n\n    IjkMediaPlayer *mp = (IjkMediaPlayer*) arg;\n    JNI_CHECK_GOTO(mp, env, NULL, \"mpjni: native_message_loop: null mp\", LABEL_RETURN);\n\n    message_loop_n(env, mp);\n\nLABEL_RETURN:\n    ijkmp_dec_ref_p(&mp);\n\n    MPTRACE(\"message_loop exit\");\n    return 0;\n}\n\n// ----------------------------------------------------------------------------\nvoid monstartup(const char *libname);\nvoid moncleanup(void);\n\nstatic void\nIjkMediaPlayer_native_profileBegin(JNIEnv *env, jclass clazz, jstring libName)\n{\n    MPTRACE(\"%s\\n\", __func__);\n\n    const char *c_lib_name = NULL;\n    static int s_monstartup = 0;\n\n    if (!libName)\n        return;\n\n    if (s_monstartup) {\n        ALOGW(\"monstartup already called\\b\");\n        return;\n    }\n\n    c_lib_name = (*env)->GetStringUTFChars(env, libName, NULL );\n    JNI_CHECK_GOTO(c_lib_name, env, \"java/lang/OutOfMemoryError\", \"mpjni: monstartup: libName.string oom\", LABEL_RETURN);\n\n    s_monstartup = 1;\n    monstartup(c_lib_name);\n    ALOGD(\"monstartup: %s\\n\", c_lib_name);\n\nLABEL_RETURN:\n    if (c_lib_name)\n        (*env)->ReleaseStringUTFChars(env, libName, c_lib_name);\n}\n\nstatic void\nIjkMediaPlayer_native_profileEnd(JNIEnv *env, jclass clazz)\n{\n    MPTRACE(\"%s\\n\", __func__);\n    static int s_moncleanup = 0;\n\n    if (s_moncleanup) {\n        ALOGW(\"moncleanu already called\\b\");\n        return;\n    }\n\n    s_moncleanup = 1;\n    moncleanup();\n    ALOGD(\"moncleanup\\n\");\n}\n\nstatic void\nIjkMediaPlayer_native_setLogLevel(JNIEnv *env, jclass clazz, jint level)\n{\n    MPTRACE(\"%s(%d)\\n\", __func__, level);\n    ijkmp_global_set_log_level(level);\n    ALOGD(\"moncleanup\\n\");\n}\n\nstatic void\nIjkMediaPlayer_setFrameAtTime(JNIEnv *env, jobject thiz, jstring path, jlong start_time, jlong end_time, jint num, jint definition) {\n    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);\n    const char *c_path = NULL;\n    JNI_CHECK_GOTO(path, env, \"java/lang/IllegalArgumentException\", \"mpjni: setFrameAtTime: null path\", LABEL_RETURN);\n    JNI_CHECK_GOTO(mp, env, \"java/lang/IllegalStateException\", \"mpjni: setFrameAtTime: null mp\", LABEL_RETURN);\n\n    c_path = (*env)->GetStringUTFChars(env, path, NULL );\n    JNI_CHECK_GOTO(c_path, env, \"java/lang/OutOfMemoryError\", \"mpjni: setFrameAtTime: path.string oom\", LABEL_RETURN);\n\n    ALOGV(\"setFrameAtTime: path %s\", c_path);\n    ijkmp_set_frame_at_time(mp, c_path, start_time, end_time, num, definition);\n    (*env)->ReleaseStringUTFChars(env, path, c_path);\n\nLABEL_RETURN:\n    ijkmp_dec_ref_p(&mp);\n    return;\n}\n\n\n\n\n\n// ----------------------------------------------------------------------------\n\nstatic JNINativeMethod g_methods[] = {\n    {\n        \"_setDataSource\",\n        \"(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V\",\n        (void *) IjkMediaPlayer_setDataSourceAndHeaders\n    },\n    { \"_setDataSourceFd\",       \"(I)V\",     (void *) IjkMediaPlayer_setDataSourceFd },\n    { \"_setDataSource\",         \"(Ltv/danmaku/ijk/media/player/misc/IMediaDataSource;)V\", (void *)IjkMediaPlayer_setDataSourceCallback },\n    { \"_setAndroidIOCallback\",  \"(Ltv/danmaku/ijk/media/player/misc/IAndroidIO;)V\", (void *)IjkMediaPlayer_setAndroidIOCallback },\n\n    { \"_setVideoSurface\",       \"(Landroid/view/Surface;)V\", (void *) IjkMediaPlayer_setVideoSurface },\n    { \"_prepareAsync\",          \"()V\",      (void *) IjkMediaPlayer_prepareAsync },\n    { \"_start\",                 \"()V\",      (void *) IjkMediaPlayer_start },\n    { \"_stop\",                  \"()V\",      (void *) IjkMediaPlayer_stop },\n    { \"seekTo\",                 \"(J)V\",     (void *) IjkMediaPlayer_seekTo },\n    { \"_pause\",                 \"()V\",      (void *) IjkMediaPlayer_pause },\n    { \"isPlaying\",              \"()Z\",      (void *) IjkMediaPlayer_isPlaying },\n    { \"getCurrentPosition\",     \"()J\",      (void *) IjkMediaPlayer_getCurrentPosition },\n    { \"getDuration\",            \"()J\",      (void *) IjkMediaPlayer_getDuration },\n    { \"_release\",               \"()V\",      (void *) IjkMediaPlayer_release },\n    { \"_reset\",                 \"()V\",      (void *) IjkMediaPlayer_reset },\n    { \"setVolume\",              \"(FF)V\",    (void *) IjkMediaPlayer_setVolume },\n    { \"getAudioSessionId\",      \"()I\",      (void *) IjkMediaPlayer_getAudioSessionId },\n    { \"native_init\",            \"()V\",      (void *) IjkMediaPlayer_native_init },\n    { \"native_setup\",           \"(Ljava/lang/Object;)V\", (void *) IjkMediaPlayer_native_setup },\n    { \"native_finalize\",        \"()V\",      (void *) IjkMediaPlayer_native_finalize },\n\n    { \"_setOption\",             \"(ILjava/lang/String;Ljava/lang/String;)V\", (void *) IjkMediaPlayer_setOption },\n    { \"_setOption\",             \"(ILjava/lang/String;J)V\",                  (void *) IjkMediaPlayer_setOptionLong },\n\n    { \"_getColorFormatName\",    \"(I)Ljava/lang/String;\",    (void *) IjkMediaPlayer_getColorFormatName },\n    { \"_getVideoCodecInfo\",     \"()Ljava/lang/String;\",     (void *) IjkMediaPlayer_getVideoCodecInfo },\n    { \"_getAudioCodecInfo\",     \"()Ljava/lang/String;\",     (void *) IjkMediaPlayer_getAudioCodecInfo },\n    { \"_getMediaMeta\",          \"()Landroid/os/Bundle;\",    (void *) IjkMediaPlayer_getMediaMeta },\n    { \"_setLoopCount\",          \"(I)V\",                     (void *) IjkMediaPlayer_setLoopCount },\n    { \"_getLoopCount\",          \"()I\",                      (void *) IjkMediaPlayer_getLoopCount },\n    { \"_getPropertyFloat\",      \"(IF)F\",                    (void *) ijkMediaPlayer_getPropertyFloat },\n    { \"_setPropertyFloat\",      \"(IF)V\",                    (void *) ijkMediaPlayer_setPropertyFloat },\n    { \"_getPropertyLong\",       \"(IJ)J\",                    (void *) ijkMediaPlayer_getPropertyLong },\n    { \"_setPropertyLong\",       \"(IJ)V\",                    (void *) ijkMediaPlayer_setPropertyLong },\n    { \"_setStreamSelected\",     \"(IZ)V\",                    (void *) ijkMediaPlayer_setStreamSelected },\n\n    { \"native_profileBegin\",    \"(Ljava/lang/String;)V\",    (void *) IjkMediaPlayer_native_profileBegin },\n    { \"native_profileEnd\",      \"()V\",                      (void *) IjkMediaPlayer_native_profileEnd },\n\n    { \"native_setLogLevel\",     \"(I)V\",                     (void *) IjkMediaPlayer_native_setLogLevel },\n    { \"_setFrameAtTime\",        \"(Ljava/lang/String;JJII)V\", (void *) IjkMediaPlayer_setFrameAtTime },\n};\n\nJNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved)\n{\n    JNIEnv* env = NULL;\n\n    g_jvm = vm;\n    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {\n        return -1;\n    }\n    assert(env != NULL);\n\n    pthread_mutex_init(&g_clazz.mutex, NULL );\n\n    // FindClass returns LocalReference\n    IJK_FIND_JAVA_CLASS(env, g_clazz.clazz, JNI_CLASS_IJKPLAYER);\n    (*env)->RegisterNatives(env, g_clazz.clazz, g_methods, NELEM(g_methods) );\n\n    ijkmp_global_init();\n    ijkmp_global_set_inject_callback(inject_callback);\n\n    FFmpegApi_global_init(env);\n\n    return JNI_VERSION_1_4;\n}\n\nJNIEXPORT void JNI_OnUnload(JavaVM *jvm, void *reserved)\n{\n    ijkmp_global_uninit();\n\n    pthread_mutex_destroy(&g_clazz.mutex);\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/android/pipeline/ffpipeline_android.c",
    "content": "/*\n * ffpipeline_android.c\n *\n * Copyright (c) 2014 Bilibili\n * Copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ffpipeline_android.h\"\n#include <jni.h>\n#include \"ffpipenode_android_mediacodec_vdec.h\"\n#include \"../../pipeline/ffpipenode_ffplay_vdec.h\"\n#include \"../../ff_ffplay.h\"\n#include \"ijksdl/android/ijksdl_android_jni.h\"\n#include \"ijksdl/android/ijksdl_android.h\"\n\nstatic SDL_Class g_pipeline_class = {\n    .name = \"ffpipeline_android_media\",\n};\n\ntypedef struct IJKFF_Pipeline_Opaque {\n    FFPlayer      *ffp;\n    SDL_mutex     *surface_mutex;\n    jobject        jsurface;\n    volatile bool  is_surface_need_reconfigure;\n\n    bool         (*mediacodec_select_callback)(void *opaque, ijkmp_mediacodecinfo_context *mcc);\n    void          *mediacodec_select_callback_opaque;\n\n    SDL_Vout      *weak_vout;\n\n    float          left_volume;\n    float          right_volume;\n} IJKFF_Pipeline_Opaque;\n\nstatic void func_destroy(IJKFF_Pipeline *pipeline)\n{\n    IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;\n    JNIEnv *env = NULL;\n\n    SDL_DestroyMutexP(&opaque->surface_mutex);\n\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"amediacodec-pipeline:destroy: SetupThreadEnv failed\\n\");\n        goto fail;\n    }\n\n    SDL_JNI_DeleteGlobalRefP(env, &opaque->jsurface);\nfail:\n    return;\n}\n\nstatic IJKFF_Pipenode *func_open_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp)\n{\n    IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;\n    IJKFF_Pipenode        *node = NULL;\n\n    if (ffp->mediacodec_all_videos || ffp->mediacodec_avc || ffp->mediacodec_hevc || ffp->mediacodec_mpeg2)\n        node = ffpipenode_create_video_decoder_from_android_mediacodec(ffp, pipeline, opaque->weak_vout);\n    if (!node) {\n        node = ffpipenode_create_video_decoder_from_ffplay(ffp);\n    }\n\n    return node;\n}\n\nstatic SDL_Aout *func_open_audio_output(IJKFF_Pipeline *pipeline, FFPlayer *ffp)\n{\n    SDL_Aout *aout = NULL;\n    if (ffp->opensles) {\n        aout = SDL_AoutAndroid_CreateForOpenSLES();\n    } else {\n        aout = SDL_AoutAndroid_CreateForAudioTrack();\n    }\n    if (aout)\n        SDL_AoutSetStereoVolume(aout, pipeline->opaque->left_volume, pipeline->opaque->right_volume);\n    return aout;\n}\n\nstatic IJKFF_Pipenode *func_init_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp)\n{\n    IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;\n    IJKFF_Pipenode        *node = NULL;\n\n    if (ffp->mediacodec_all_videos || ffp->mediacodec_avc || ffp->mediacodec_hevc || ffp->mediacodec_mpeg2)\n        node = ffpipenode_init_decoder_from_android_mediacodec(ffp, pipeline, opaque->weak_vout);\n\n    return node;\n}\n\nstatic int func_config_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp)\n{\n    IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;\n    int                       ret = NULL;\n\n    if (ffp->node_vdec) {\n        ret = ffpipenode_config_from_android_mediacodec(ffp, pipeline, opaque->weak_vout, ffp->node_vdec);\n    }\n\n    return ret;\n}\n\n\ninline static bool check_ffpipeline(IJKFF_Pipeline* pipeline, const char *func_name)\n{\n    if (!pipeline || !pipeline->opaque || !pipeline->opaque_class) {\n        ALOGE(\"%s.%s: invalid pipeline\\n\", pipeline->opaque_class->name, func_name);\n        return false;\n    }\n\n    if (pipeline->opaque_class != &g_pipeline_class) {\n        ALOGE(\"%s.%s: unsupported method\\n\", pipeline->opaque_class->name, func_name);\n        return false;\n    }\n\n    return true;\n}\n\nIJKFF_Pipeline *ffpipeline_create_from_android(FFPlayer *ffp)\n{\n    ALOGD(\"ffpipeline_create_from_android()\\n\");\n    IJKFF_Pipeline *pipeline = ffpipeline_alloc(&g_pipeline_class, sizeof(IJKFF_Pipeline_Opaque));\n    if (!pipeline)\n        return pipeline;\n\n    IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;\n    opaque->ffp                   = ffp;\n    opaque->surface_mutex         = SDL_CreateMutex();\n    opaque->left_volume           = 1.0f;\n    opaque->right_volume          = 1.0f;\n    if (!opaque->surface_mutex) {\n        ALOGE(\"ffpipeline-android:create SDL_CreateMutex failed\\n\");\n        goto fail;\n    }\n\n    pipeline->func_destroy              = func_destroy;\n    pipeline->func_open_video_decoder   = func_open_video_decoder;\n    pipeline->func_open_audio_output    = func_open_audio_output;\n    pipeline->func_init_video_decoder   = func_init_video_decoder;\n    pipeline->func_config_video_decoder = func_config_video_decoder;\n\n    return pipeline;\nfail:\n    ffpipeline_free_p(&pipeline);\n    return NULL;\n}\n\nint ffpipeline_lock_surface(IJKFF_Pipeline* pipeline)\n{\n    IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;\n    return SDL_LockMutex(opaque->surface_mutex);\n}\n\nint ffpipeline_unlock_surface(IJKFF_Pipeline* pipeline)\n{\n    IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;\n    return SDL_UnlockMutex(opaque->surface_mutex);\n}\n\njobject ffpipeline_get_surface_as_global_ref_l(JNIEnv *env, IJKFF_Pipeline* pipeline)\n{\n    if (!check_ffpipeline(pipeline, __func__))\n        return NULL;\n\n    IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;\n    if (!opaque->surface_mutex)\n        return NULL;\n\n    jobject global_ref = NULL;\n    if (opaque->jsurface)\n        global_ref = (*env)->NewGlobalRef(env, opaque->jsurface);\n\n    return global_ref;\n}\n\njobject ffpipeline_get_surface_as_global_ref(JNIEnv *env, IJKFF_Pipeline* pipeline)\n{\n    ffpipeline_lock_surface(pipeline);\n    jobject new_surface = ffpipeline_get_surface_as_global_ref_l(env, pipeline);\n    ffpipeline_unlock_surface(pipeline);\n    return new_surface;\n}\n\nvoid ffpipeline_set_vout(IJKFF_Pipeline* pipeline, SDL_Vout *vout)\n{\n    if (!check_ffpipeline(pipeline, __func__))\n        return;\n\n    IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;\n    opaque->weak_vout = vout;\n}\n\nint ffpipeline_set_surface(JNIEnv *env, IJKFF_Pipeline* pipeline, jobject surface)\n{\n    ALOGD(\"%s()\\n\", __func__);\n    if (!check_ffpipeline(pipeline, __func__))\n        return -1;\n\n    IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;\n    if (!opaque->surface_mutex)\n        return -1;\n\n    ffpipeline_lock_surface(pipeline);\n    {\n        jobject prev_surface = opaque->jsurface;\n\n        if ((surface == prev_surface) ||\n            (surface && prev_surface && (*env)->IsSameObject(env, surface, prev_surface))) {\n            // same object, no need to reconfigure\n        } else {\n            SDL_VoutAndroid_setAMediaCodec(opaque->weak_vout, NULL);\n            if (surface) {\n                opaque->jsurface = (*env)->NewGlobalRef(env, surface);\n            } else {\n                opaque->jsurface = NULL;\n            }\n            opaque->is_surface_need_reconfigure = true;\n\n            if (prev_surface != NULL) {\n                SDL_JNI_DeleteGlobalRefP(env, &prev_surface);\n            }\n        }\n    }\n    ffpipeline_unlock_surface(pipeline);\n\n    return 0;\n}\n\nbool ffpipeline_is_surface_need_reconfigure_l(IJKFF_Pipeline* pipeline)\n{\n    if (!check_ffpipeline(pipeline, __func__))\n        return false;\n\n    return pipeline->opaque->is_surface_need_reconfigure;\n}\n\nvoid ffpipeline_set_surface_need_reconfigure_l(IJKFF_Pipeline* pipeline, bool need_reconfigure)\n{\n    ALOGD(\"%s(%d)\\n\", __func__, (int)need_reconfigure);\n    if (!check_ffpipeline(pipeline, __func__))\n        return;\n\n    pipeline->opaque->is_surface_need_reconfigure = need_reconfigure;\n}\n\nvoid ffpipeline_set_mediacodec_select_callback(IJKFF_Pipeline* pipeline, bool (*callback)(void *opaque, ijkmp_mediacodecinfo_context *mcc), void *opaque)\n{\n    ALOGD(\"%s\\n\", __func__);\n    if (!check_ffpipeline(pipeline, __func__))\n        return;\n\n    pipeline->opaque->mediacodec_select_callback        = callback;\n    pipeline->opaque->mediacodec_select_callback_opaque = opaque;\n}\n\nbool ffpipeline_select_mediacodec_l(IJKFF_Pipeline* pipeline, ijkmp_mediacodecinfo_context *mcc)\n{\n    ALOGD(\"%s\\n\", __func__);\n    if (!check_ffpipeline(pipeline, __func__))\n        return false;\n\n    if (!mcc || !pipeline->opaque->mediacodec_select_callback)\n        return false;\n\n    return pipeline->opaque->mediacodec_select_callback(pipeline->opaque->mediacodec_select_callback_opaque, mcc);\n}\n\nvoid ffpipeline_set_volume(IJKFF_Pipeline* pipeline, float left, float right)\n{\n    ALOGD(\"%s\\n\", __func__);\n    if (!check_ffpipeline(pipeline, __func__))\n        return;\n\n    IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;\n    opaque->left_volume  = left;\n    opaque->right_volume = right;\n\n    if (opaque->ffp && opaque->ffp->aout) {\n        SDL_AoutSetStereoVolume(opaque->ffp->aout, left, right);\n    }\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/android/pipeline/ffpipeline_android.h",
    "content": "/*\n * ffpipeline_android.h\n *\n * Copyright (c) 2014 Bilibili\n * Copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef FFPLAY__FF_FFPIPELINE_ANDROID_H\n#define FFPLAY__FF_FFPIPELINE_ANDROID_H\n\n#include <stdbool.h>\n#include <jni.h>\n#include \"../ijkplayer_android_def.h\"\n#include \"../../ff_ffpipeline.h\"\n#include \"ijksdl/ijksdl_vout.h\"\n\ntypedef struct FFPlayer       FFPlayer;\ntypedef struct IJKFF_Pipeline IJKFF_Pipeline;\n\nIJKFF_Pipeline *ffpipeline_create_from_android(FFPlayer *ffp);\n\nvoid    ffpipeline_set_vout(IJKFF_Pipeline* pipeline, SDL_Vout *vout);\n\nint     ffpipeline_set_surface(JNIEnv *env, IJKFF_Pipeline* pipeline, jobject surface);\n\nint     ffpipeline_lock_surface(IJKFF_Pipeline* pipeline);\nint     ffpipeline_unlock_surface(IJKFF_Pipeline* pipeline);\njobject ffpipeline_get_surface_as_global_ref_l(JNIEnv *env, IJKFF_Pipeline* pipeline);\njobject ffpipeline_get_surface_as_global_ref(JNIEnv *env, IJKFF_Pipeline* pipeline);\n\nbool    ffpipeline_is_surface_need_reconfigure_l(IJKFF_Pipeline* pipeline);\nvoid    ffpipeline_set_surface_need_reconfigure_l(IJKFF_Pipeline* pipeline, bool need_reconfigure);\n\nvoid    ffpipeline_set_mediacodec_select_callback(IJKFF_Pipeline* pipeline, bool (*callback)(void *opaque, ijkmp_mediacodecinfo_context *mcc), void *opaque);\nbool    ffpipeline_select_mediacodec_l(IJKFF_Pipeline* pipeline, ijkmp_mediacodecinfo_context *mcc);\n\nvoid    ffpipeline_set_volume(IJKFF_Pipeline* pipeline, float left, float right);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/android/pipeline/ffpipenode_android_mediacodec_vdec.c",
    "content": "/*\n * ffpipenode_android_mediacodec_vdec.c\n *\n * Copyright (c) 2014 Bilibili\n * Copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ffpipenode_android_mediacodec_vdec.h\"\n#include \"ijksdl/android/ijksdl_android_jni.h\"\n#include \"ijksdl/android/ijksdl_codec_android_mediaformat_java.h\"\n#include \"ijksdl/android/ijksdl_codec_android_mediacodec_java.h\"\n#include \"ijksdl/android/ijksdl_codec_android_mediacodec_dummy.h\"\n#include \"ijksdl/android/ijksdl_vout_android_nativewindow.h\"\n#include \"ijksdl/android/ijksdl_vout_overlay_android_mediacodec.h\"\n#include \"ijkplayer/ff_ffpipenode.h\"\n#include \"ijkplayer/ff_ffplay.h\"\n#include \"ijkplayer/ff_ffplay_debug.h\"\n#include \"h264_nal.h\"\n#include \"hevc_nal.h\"\n#include \"mpeg4_esds.h\"\n#include \"ffpipeline_android.h\"\n\n#define AMC_USE_AVBITSTREAM_FILTER 0\n#ifndef AMCTRACE\n//#define AMCTRACE(...)\n#define AMCTRACE ALOGE\n#endif\n\n#define AMC_INPUT_TIMEOUT_US  (100 * 1000)\n#define AMC_OUTPUT_TIMEOUT_US (100 * 1000)\n\n#define AMC_SYNC_INPUT_TIMEOUT_US  (30 * 1000)\n#define AMC_SYNC_OUTPUT_TIMEOUT_US (30 * 1000)\n\n#define MAX_FAKE_FRAMES (2)\n\n#define ACODEC_RETRY -1\n#define ACODEC_EXIT  -2\n\ntypedef struct AMC_Buf_Out {\n    int port;\n    int acodec_serial;\n    SDL_AMediaCodecBufferInfo info;\n    double pts;\n} AMC_Buf_Out;\n\ntypedef struct IJKFF_Pipenode_Opaque {\n    FFPlayer                 *ffp;\n    IJKFF_Pipeline           *pipeline;\n    Decoder                  *decoder;\n    SDL_Vout                 *weak_vout;\n\n    ijkmp_mediacodecinfo_context mcc;\n\n    jobject                   jsurface;\n    SDL_AMediaFormat         *input_aformat;\n    SDL_AMediaCodec          *acodec;\n    SDL_AMediaFormat         *output_aformat;\n    char                      acodec_name[128];\n    int                       frame_width;\n    int                       frame_height;\n    int                       frame_rotate_degrees;\n\n    AVCodecContext           *avctx; // not own\n    AVCodecParameters        *codecpar;\n    AVBitStreamFilterContext *bsfc;  // own\n\n#if AMC_USE_AVBITSTREAM_FILTER\n    uint8_t                  *orig_extradata;\n    int                       orig_extradata_size;\n#else\n    size_t                    nal_size;\n#endif\n\n    SDL_Thread               _enqueue_thread;\n    SDL_Thread               *enqueue_thread;\n\n    SDL_mutex                *acodec_mutex;\n    SDL_cond                 *acodec_cond;\n\n    volatile bool             acodec_flush_request;\n    volatile bool             acodec_reconfigure_request;\n\n    SDL_mutex                *acodec_first_dequeue_output_mutex;\n    SDL_cond                 *acodec_first_dequeue_output_cond;\n    volatile bool             acodec_first_dequeue_output_request;\n    bool                      aformat_need_recreate;\n\n    SDL_mutex                *any_input_mutex;\n    SDL_cond                 *any_input_cond;\n\n    int                       input_packet_count;\n    int                       input_error_count;\n    int                       output_error_count;\n\n    bool                      quirk_reconfigure_with_new_codec;\n\n    int                       n_buf_out;\n    AMC_Buf_Out               *amc_buf_out;\n    int                       off_buf_out;\n    double                    last_queued_pts;\n\n    SDL_SpeedSampler          sampler;\n    volatile bool             abort;\n} IJKFF_Pipenode_Opaque;\n\nstatic SDL_AMediaCodec *create_codec_l(JNIEnv *env, IJKFF_Pipenode *node)\n{\n    IJKFF_Pipenode_Opaque        *opaque   = node->opaque;\n    ijkmp_mediacodecinfo_context *mcc      = &opaque->mcc;\n    SDL_AMediaCodec              *acodec   = NULL;\n\n    if (opaque->jsurface == NULL) {\n        // we don't need real codec if we don't have a surface\n        acodec = SDL_AMediaCodecDummy_create();\n    } else {\n        acodec = SDL_AMediaCodecJava_createByCodecName(env, mcc->codec_name);\n        if (acodec) {\n            strncpy(opaque->acodec_name, mcc->codec_name, sizeof(opaque->acodec_name) / sizeof(*opaque->acodec_name));\n            opaque->acodec_name[sizeof(opaque->acodec_name) / sizeof(*opaque->acodec_name) - 1] = 0;\n        }\n    }\n\n#if 0\n    if (!acodec)\n        acodec = SDL_AMediaCodecJava_createDecoderByType(env, mcc->mime_type);\n#endif\n\n    if (acodec) {\n        // QUIRK: always recreate MediaCodec for reconfigure\n        opaque->quirk_reconfigure_with_new_codec = true;\n        /*-\n        if (0 == strncasecmp(mcc->codec_name, \"OMX.TI.DUCATI1.\", 15)) {\n            opaque->quirk_reconfigure_with_new_codec = true;\n        }\n        */\n        /* delaying output makes it possible to correct frame order, hopefully */\n        if (0 == strncasecmp(mcc->codec_name, \"OMX.TI.DUCATI1.\", 15)) {\n            /* this is the only acceptable value on Nexus S */\n            opaque->n_buf_out = 1;\n            ALOGD(\"using buffered output for %s\", mcc->codec_name);\n        }\n    }\n\n    if (opaque->frame_rotate_degrees == 90 || opaque->frame_rotate_degrees == 270) {\n        opaque->frame_width  = opaque->codecpar->height;\n        opaque->frame_height = opaque->codecpar->width;\n    } else {\n        opaque->frame_width  = opaque->codecpar->width;\n        opaque->frame_height = opaque->codecpar->height;\n    }\n\n    return acodec;\n}\n\nstatic int recreate_format_l(JNIEnv *env, IJKFF_Pipenode *node)\n{\n    IJKFF_Pipenode_Opaque *opaque         = node->opaque;\n    FFPlayer              *ffp            = opaque->ffp;\n    int                    rotate_degrees = 0;\n\n    ALOGI(\"AMediaFormat: %s, %dx%d\\n\", opaque->mcc.mime_type, opaque->codecpar->width, opaque->codecpar->height);\n    SDL_AMediaFormat_deleteP(&opaque->output_aformat);\n    opaque->input_aformat = SDL_AMediaFormatJava_createVideoFormat(env, opaque->mcc.mime_type, opaque->codecpar->width, opaque->codecpar->height);\n    if (opaque->codecpar->extradata && opaque->codecpar->extradata_size > 0) {\n        if ((opaque->codecpar->codec_id == AV_CODEC_ID_H264 && opaque->codecpar->extradata[0] == 1)\n            || (opaque->codecpar->codec_id == AV_CODEC_ID_HEVC && opaque->codecpar->extradata_size > 3\n                && (opaque->codecpar->extradata[0] == 1 || opaque->codecpar->extradata[1] == 1))) {\n#if AMC_USE_AVBITSTREAM_FILTER\n            if (opaque->codecpar->codec_id == AV_CODEC_ID_H264) {\n                opaque->bsfc = av_bitstream_filter_init(\"h264_mp4toannexb\");\n                if (!opaque->bsfc) {\n                    ALOGE(\"Cannot open the h264_mp4toannexb BSF!\\n\");\n                    goto fail;\n                }\n            } else {\n                opaque->bsfc = av_bitstream_filter_init(\"hevc_mp4toannexb\");\n                if (!opaque->bsfc) {\n                    ALOGE(\"Cannot open the hevc_mp4toannexb BSF!\\n\");\n                    goto fail;\n                }\n            }\n\n            opaque->orig_extradata_size = opaque->codecpar->extradata_size;\n            opaque->orig_extradata = (uint8_t*) av_mallocz(opaque->codecpar->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);\n            if (!opaque->orig_extradata) {\n                goto fail;\n            }\n            memcpy(opaque->orig_extradata, opaque->codecpar->extradata, opaque->codecpar->extradata_size);\n            for(int i = 0; i < opaque->codecpar->extradata_size; i+=4) {\n                ALOGE(\"csd-0[%d]: %02x%02x%02x%02x\\n\", opaque->codecpar->extradata_size, (int)opaque->codecpar->extradata[i+0], (int)opaque->codecpar->extradata[i+1], (int)opaque->codecpar->extradata[i+2], (int)opaque->codecpar->extradata[i+3]);\n            }\n            SDL_AMediaFormat_setBuffer(opaque->input_aformat, \"csd-0\", opaque->codecpar->extradata, opaque->codecpar->extradata_size);\n#else\n            size_t   sps_pps_size   = 0;\n            size_t   convert_size   = opaque->codecpar->extradata_size + 20;\n            uint8_t *convert_buffer = (uint8_t *)calloc(1, convert_size);\n            if (!convert_buffer) {\n                ALOGE(\"%s:sps_pps_buffer: alloc failed\\n\", __func__);\n                goto fail;\n            }\n            if (opaque->codecpar->codec_id == AV_CODEC_ID_H264) {\n                if (0 != convert_sps_pps(opaque->codecpar->extradata, opaque->codecpar->extradata_size,\n                                         convert_buffer, convert_size,\n                                         &sps_pps_size, &opaque->nal_size)) {\n                    ALOGE(\"%s:convert_sps_pps: failed\\n\", __func__);\n                    goto fail;\n                }\n            } else {\n                if (0 != convert_hevc_nal_units(opaque->codecpar->extradata, opaque->codecpar->extradata_size,\n                                                convert_buffer, convert_size,\n                                                &sps_pps_size, &opaque->nal_size)) {\n                    ALOGE(\"%s:convert_hevc_nal_units: failed\\n\", __func__);\n                    goto fail;\n                }\n            }\n            SDL_AMediaFormat_setBuffer(opaque->input_aformat, \"csd-0\", convert_buffer, sps_pps_size);\n            for(int i = 0; i < sps_pps_size; i+=4) {\n                ALOGE(\"csd-0[%d]: %02x%02x%02x%02x\\n\", (int)sps_pps_size, (int)convert_buffer[i+0], (int)convert_buffer[i+1], (int)convert_buffer[i+2], (int)convert_buffer[i+3]);\n            }\n            free(convert_buffer);\n#endif\n        } else if (opaque->codecpar->codec_id == AV_CODEC_ID_MPEG4) {\n            size_t esds_dec_dscr_type_length = opaque->codecpar->extradata_size + 0x18;\n            size_t esds_es_dscr_type_length = esds_dec_dscr_type_length + 0x08;\n            size_t esds_size = esds_es_dscr_type_length + 0x05;\n            uint8_t *convert_buffer = (uint8_t *)calloc(1, esds_size);\n            restore_mpeg4_esds(opaque->codecpar, opaque->codecpar->extradata, opaque->codecpar->extradata_size, esds_es_dscr_type_length, esds_dec_dscr_type_length, convert_buffer);\n            SDL_AMediaFormat_setBuffer(opaque->input_aformat, \"csd-0\", convert_buffer, esds_size);\n            free(convert_buffer);\n        } else {\n            // Codec specific data\n            // SDL_AMediaFormat_setBuffer(opaque->aformat, \"csd-0\", opaque->codecpar->extradata, opaque->codecpar->extradata_size);\n            ALOGE(\"csd-0: naked\\n\");\n        }\n    } else {\n        ALOGE(\"no buffer(%d)\\n\", opaque->codecpar->extradata_size);\n    }\n\n    rotate_degrees = ffp_get_video_rotate_degrees(ffp);\n    if (ffp->mediacodec_auto_rotate &&\n        rotate_degrees != 0 &&\n        SDL_Android_GetApiLevel() >= IJK_API_21_LOLLIPOP) {\n        ALOGI(\"amc: rotate in decoder: %d\\n\", rotate_degrees);\n        opaque->frame_rotate_degrees = rotate_degrees;\n        SDL_AMediaFormat_setInt32(opaque->input_aformat, \"rotation-degrees\", rotate_degrees);\n        ffp_notify_msg2(ffp, FFP_MSG_VIDEO_ROTATION_CHANGED, 0);\n    } else {\n        ALOGI(\"amc: rotate notify: %d\\n\", rotate_degrees);\n        ffp_notify_msg2(ffp, FFP_MSG_VIDEO_ROTATION_CHANGED, rotate_degrees);\n    }\n\n    return 0;\nfail:\n    return -1;\n}\n\nstatic int reconfigure_codec_l(JNIEnv *env, IJKFF_Pipenode *node, jobject new_surface)\n{\n    IJKFF_Pipenode_Opaque *opaque   = node->opaque;\n    int                    ret      = 0;\n    sdl_amedia_status_t    amc_ret  = 0;\n    jobject                prev_jsurface = NULL;\n\n    prev_jsurface = opaque->jsurface;\n    if (new_surface) {\n        opaque->jsurface = (*env)->NewGlobalRef(env, new_surface);\n        if (J4A_ExceptionCheck__catchAll(env) || !opaque->jsurface)\n            goto fail;\n    } else {\n        opaque->jsurface = NULL;\n    }\n\n    SDL_JNI_DeleteGlobalRefP(env, &prev_jsurface);\n\n    if (!opaque->acodec) {\n        opaque->acodec = create_codec_l(env, node);\n        if (!opaque->acodec) {\n            ALOGE(\"%s:open_video_decoder: create_codec failed\\n\", __func__);\n            ret = -1;\n            goto fail;\n        }\n    }\n\n    if (SDL_AMediaCodec_isConfigured(opaque->acodec)) {\n        if (opaque->acodec) {\n            if (SDL_AMediaCodec_isStarted(opaque->acodec)) {\n                SDL_VoutAndroid_invalidateAllBuffers(opaque->weak_vout);\n                SDL_AMediaCodec_stop(opaque->acodec);\n            }\n            if (opaque->quirk_reconfigure_with_new_codec) {\n                ALOGI(\"quirk: reconfigure with new codec\");\n                SDL_AMediaCodec_decreaseReferenceP(&opaque->acodec);\n                SDL_VoutAndroid_setAMediaCodec(opaque->weak_vout, NULL);\n\n                opaque->acodec = create_codec_l(env, node);\n                if (!opaque->acodec) {\n                    ALOGE(\"%s:open_video_decoder: create_codec failed\\n\", __func__);\n                    ret = -1;\n                    goto fail;\n                }\n            }\n        }\n\n        assert(opaque->weak_vout);\n    }\n\n    amc_ret = SDL_AMediaCodec_configure_surface(env, opaque->acodec, opaque->input_aformat, opaque->jsurface, NULL, 0);\n    if (amc_ret != SDL_AMEDIA_OK) {\n        ALOGE(\"%s:configure_surface: failed\\n\", __func__);\n        ret = -1;\n        goto fail;\n    }\n\n    amc_ret = SDL_AMediaCodec_start(opaque->acodec);\n    if (amc_ret != SDL_AMEDIA_OK) {\n        ALOGE(\"%s:SDL_AMediaCodec_start: failed\\n\", __func__);\n        ret = -1;\n        goto fail;\n    }\n\n    opaque->acodec_first_dequeue_output_request = true;\n    ALOGI(\"%s:new acodec: %p\\n\", __func__, opaque->acodec);\n    SDL_VoutAndroid_setAMediaCodec(opaque->weak_vout, opaque->acodec);\n\n    ret = 0;\nfail:\n    return ret;\n}\n\nstatic int configure_codec_l(JNIEnv *env, IJKFF_Pipenode *node, jobject new_surface)\n{\n    IJKFF_Pipenode_Opaque        *opaque = node->opaque;\n    int                              ret = 0;\n    sdl_amedia_status_t          amc_ret = 0;\n    jobject                prev_jsurface = NULL;\n    ijkmp_mediacodecinfo_context *mcc    = &opaque->mcc;\n\n    prev_jsurface = opaque->jsurface;\n    if (new_surface) {\n        opaque->jsurface = (*env)->NewGlobalRef(env, new_surface);\n        if (J4A_ExceptionCheck__catchAll(env) || !opaque->jsurface)\n            goto fail;\n    } else {\n        opaque->jsurface = NULL;\n    }\n\n    SDL_JNI_DeleteGlobalRefP(env, &prev_jsurface);\n\n    if (!opaque->acodec || !mcc) {\n        goto fail;\n    }\n\n    strncpy(opaque->acodec_name, mcc->codec_name, sizeof(opaque->acodec_name) / sizeof(*opaque->acodec_name));\n    opaque->acodec_name[sizeof(opaque->acodec_name) / sizeof(*opaque->acodec_name) - 1] = 0;\n\n    // QUIRK: always recreate MediaCodec for reconfigure\n    opaque->quirk_reconfigure_with_new_codec = true;\n    /* delaying output makes it possible to correct frame order, hopefully */\n    if (0 == strncasecmp(mcc->codec_name, \"OMX.TI.DUCATI1.\", 15)) {\n        /* this is the only acceptable value on Nexus S */\n        opaque->n_buf_out = 1;\n        ALOGD(\"using buffered output for %s\", mcc->codec_name);\n    }\n\n    if (opaque->frame_rotate_degrees == 90 || opaque->frame_rotate_degrees == 270) {\n        opaque->frame_width  = opaque->codecpar->height;\n        opaque->frame_height = opaque->codecpar->width;\n    } else {\n        opaque->frame_width  = opaque->codecpar->width;\n        opaque->frame_height = opaque->codecpar->height;\n    }\n    amc_ret = SDL_AMediaCodec_configure_surface(env, opaque->acodec, opaque->input_aformat, opaque->jsurface, NULL, 0);\n    if (amc_ret != SDL_AMEDIA_OK) {\n        ALOGE(\"%s:configure_surface: failed\\n\", __func__);\n        ret = -1;\n        goto fail;\n    }\n    amc_ret = SDL_AMediaCodec_start(opaque->acodec);\n    if (amc_ret != SDL_AMEDIA_OK) {\n        ALOGE(\"%s:SDL_AMediaCodec_start: failed\\n\", __func__);\n        ret = -1;\n        goto fail;\n    }\n\n    opaque->acodec_first_dequeue_output_request = true;\n    ALOGI(\"%s:new acodec: %p\\n\", __func__, opaque->acodec);\n    SDL_VoutAndroid_setAMediaCodec(opaque->weak_vout, opaque->acodec);\n\n    ret = 0;\nfail:\n    return ret;\n}\n\n#if 0\nstatic int reconfigure_codec(JNIEnv *env, IJKFF_Pipenode *node)\n{\n    IJKFF_Pipenode_Opaque *opaque = node->opaque;\n    SDL_LockMutex(opaque->acodec_mutex);\n    int ret = reconfigure_codec_l(env, node);\n    SDL_UnlockMutex(opaque->acodec_mutex);\n    return ret;\n}\n#endif\n\nstatic int amc_fill_frame(\n    IJKFF_Pipenode            *node,\n    AVFrame                   *frame,\n    int                       *got_frame,\n    int                        output_buffer_index,\n    int                        acodec_serial,\n    SDL_AMediaCodecBufferInfo *buffer_info)\n{\n    IJKFF_Pipenode_Opaque *opaque     = node->opaque;\n    FFPlayer              *ffp        = opaque->ffp;\n    VideoState            *is         = ffp->is;\n\n    frame->opaque = SDL_VoutAndroid_obtainBufferProxy(opaque->weak_vout, acodec_serial, output_buffer_index, buffer_info);\n    if (!frame->opaque)\n        goto fail;\n\n    frame->width  = opaque->frame_width;\n    frame->height = opaque->frame_height;\n    frame->format = IJK_AV_PIX_FMT__ANDROID_MEDIACODEC;\n    frame->sample_aspect_ratio = opaque->codecpar->sample_aspect_ratio;\n    frame->pts    = av_rescale_q(buffer_info->presentationTimeUs, AV_TIME_BASE_Q, is->video_st->time_base);\n    if (frame->pts < 0)\n        frame->pts = AV_NOPTS_VALUE;\n    // ALOGE(\"%s: %f\", __func__, (float)frame->pts);\n\n    *got_frame = 1;\n    return 0;\nfail:\n    *got_frame = 0;\n    return -1;\n}\n\nstatic int feed_input_buffer2(JNIEnv *env, IJKFF_Pipenode *node, int64_t timeUs, int *enqueue_count)\n{\n    IJKFF_Pipenode_Opaque *opaque   = node->opaque;\n    FFPlayer              *ffp      = opaque->ffp;\n    IJKFF_Pipeline        *pipeline = opaque->pipeline;\n    VideoState            *is       = ffp->is;\n    Decoder               *d        = &is->viddec;\n    PacketQueue           *q        = d->queue;\n    sdl_amedia_status_t    amc_ret  = 0;\n    int                    ret      = 0;\n    ssize_t  input_buffer_index     = 0;\n    ssize_t  copy_size              = 0;\n    int64_t  time_stamp             = 0;\n    uint32_t queue_flags            = 0;\n\n    if (enqueue_count)\n        *enqueue_count = 0;\n\n    if (d->queue->abort_request) {\n        ret = ACODEC_EXIT;\n        goto fail;\n    }\n\n    if (!d->packet_pending || d->queue->serial != d->pkt_serial) {\n#if AMC_USE_AVBITSTREAM_FILTER\n#else\n        H264ConvertState convert_state = {0, 0};\n#endif\n        AVPacket pkt;\n        do {\n            if (d->queue->nb_packets == 0)\n                SDL_CondSignal(d->empty_queue_cond);\n            if (ffp_packet_queue_get_or_buffering(ffp, d->queue, &pkt, &d->pkt_serial, &d->finished) < 0) {\n                ret = -1;\n                goto fail;\n            }\n            if (ffp_is_flush_packet(&pkt) || opaque->acodec_flush_request) {\n                // request flush before lock, or never get mutex\n                opaque->acodec_flush_request = true;\n                if (SDL_AMediaCodec_isStarted(opaque->acodec)) {\n                    if (opaque->input_packet_count > 0) {\n                        // flush empty queue cause error on OMX.SEC.AVC.Decoder (Nexus S)\n                        SDL_VoutAndroid_invalidateAllBuffers(opaque->weak_vout);\n                        SDL_AMediaCodec_flush(opaque->acodec);\n                        opaque->input_packet_count = 0;\n                    }\n                    // If codec is configured in synchronous mode, codec will resume automatically\n                    // SDL_AMediaCodec_start(opaque->acodec);\n                }\n                opaque->acodec_flush_request = false;\n                d->finished = 0;\n                d->next_pts = d->start_pts;\n                d->next_pts_tb = d->start_pts_tb;\n            }\n        } while (ffp_is_flush_packet(&pkt) || d->queue->serial != d->pkt_serial);\n        av_packet_split_side_data(&pkt);\n        av_packet_unref(&d->pkt);\n        d->pkt_temp = d->pkt = pkt;\n        d->packet_pending = 1;\n\n        if (opaque->ffp->mediacodec_handle_resolution_change &&\n            opaque->codecpar->codec_id == AV_CODEC_ID_H264) {\n            uint8_t  *size_data      = NULL;\n            int       size_data_size = 0;\n            AVPacket *avpkt          = &d->pkt_temp;\n            size_data = av_packet_get_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, &size_data_size);\n            // minimum avcC(sps,pps) = 7\n            if (size_data && size_data_size >= 7) {\n                int             got_picture = 0;\n                AVFrame        *frame      = av_frame_alloc();\n                AVDictionary   *codec_opts = NULL;\n                const AVCodec  *codec      = opaque->decoder->avctx->codec;\n                AVCodecContext *new_avctx  = avcodec_alloc_context3(codec);\n                int change_ret = 0;\n\n                if (!new_avctx)\n                    return AVERROR(ENOMEM);\n\n                avcodec_parameters_to_context(new_avctx, opaque->codecpar);\n                av_freep(&new_avctx->extradata);\n                new_avctx->extradata = av_mallocz(size_data_size + AV_INPUT_BUFFER_PADDING_SIZE);\n                if (!new_avctx->extradata) {\n                    avcodec_free_context(&new_avctx);\n                    return AVERROR(ENOMEM);\n                }\n                memcpy(new_avctx->extradata, size_data, size_data_size);\n                new_avctx->extradata_size = size_data_size;\n\n                av_dict_set(&codec_opts, \"threads\", \"1\", 0);\n                change_ret = avcodec_open2(new_avctx, codec, &codec_opts);\n                av_dict_free(&codec_opts);\n                if (change_ret < 0) {\n                    avcodec_free_context(&new_avctx);\n                    return change_ret;\n                }\n\n                change_ret = avcodec_decode_video2(new_avctx, frame, &got_picture, avpkt);\n                if (change_ret < 0) {\n                    avcodec_free_context(&new_avctx);\n                    return change_ret;\n                } else {\n                    if (opaque->codecpar->width  != new_avctx->width &&\n                        opaque->codecpar->height != new_avctx->height) {\n                        ALOGW(\"AV_PKT_DATA_NEW_EXTRADATA: %d x %d\\n\", new_avctx->width, new_avctx->height);\n                        avcodec_parameters_from_context(opaque->codecpar, new_avctx);\n                        opaque->aformat_need_recreate = true;\n                        ffpipeline_set_surface_need_reconfigure_l(pipeline, true);\n                    }\n                }\n\n                av_frame_unref(frame);\n                avcodec_free_context(&new_avctx);\n            }\n        }\n\n        if (opaque->codecpar->codec_id == AV_CODEC_ID_H264 || opaque->codecpar->codec_id == AV_CODEC_ID_HEVC) {\n            convert_h264_to_annexb(d->pkt_temp.data, d->pkt_temp.size, opaque->nal_size, &convert_state);\n            int64_t time_stamp = d->pkt_temp.pts;\n            if (!time_stamp && d->pkt_temp.dts)\n                time_stamp = d->pkt_temp.dts;\n            if (time_stamp > 0) {\n                time_stamp = av_rescale_q(time_stamp, is->video_st->time_base, AV_TIME_BASE_Q);\n            } else {\n                time_stamp = 0;\n            }\n        }\n    }\n\n    if (d->pkt_temp.data) {\n        // reconfigure surface if surface changed\n        // NULL surface cause no display\n        if (ffpipeline_is_surface_need_reconfigure_l(pipeline)) {\n            jobject new_surface = NULL;\n\n            // request reconfigure before lock, or never get mutex\n            ffpipeline_lock_surface(pipeline);\n            ffpipeline_set_surface_need_reconfigure_l(pipeline, false);\n            new_surface = ffpipeline_get_surface_as_global_ref_l(env, pipeline);\n            ffpipeline_unlock_surface(pipeline);\n\n            if (!opaque->aformat_need_recreate &&\n                (opaque->jsurface == new_surface ||\n                (opaque->jsurface && new_surface && (*env)->IsSameObject(env, new_surface, opaque->jsurface)))) {\n                ALOGI(\"%s: same surface, reuse previous surface\\n\", __func__);\n                J4A_DeleteGlobalRef__p(env, &new_surface);\n            } else {\n                if (d->queue->abort_request) {\n                    ret = ACODEC_EXIT;\n                    goto fail;\n                }\n\n                if (opaque->aformat_need_recreate) {\n                    ALOGI(\"%s: recreate aformat\\n\", __func__);\n                    ret = recreate_format_l(env, node);\n                    if (ret) {\n                        ALOGE(\"amc: recreate_format_l failed\\n\");\n                        goto fail;\n                    }\n                    opaque->aformat_need_recreate = false;\n                }\n\n                ret = reconfigure_codec_l(env, node, new_surface);\n\n                J4A_DeleteGlobalRef__p(env, &new_surface);\n\n                if (ret != 0) {\n                    ALOGE(\"%s: reconfigure_codec failed\\n\", __func__);\n                    ret = 0;\n                    goto fail;\n                }\n\n                if (q->abort_request || opaque->acodec_flush_request) {\n                    ret = 0;\n                    goto fail;\n                }\n            }\n        }\n\n        queue_flags = 0;\n        input_buffer_index = SDL_AMediaCodec_dequeueInputBuffer(opaque->acodec, timeUs);\n        if (input_buffer_index < 0) {\n            if (SDL_AMediaCodec_isInputBuffersValid(opaque->acodec)) {\n                // timeout\n                ret = 0;\n                goto fail;\n            } else {\n                // enqueue fake frame\n                queue_flags |= AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME;\n                copy_size    = d->pkt_temp.size;\n            }\n        } else {\n            SDL_AMediaCodecFake_flushFakeFrames(opaque->acodec);\n\n            copy_size = SDL_AMediaCodec_writeInputData(opaque->acodec, input_buffer_index, d->pkt_temp.data, d->pkt_temp.size);\n            if (!copy_size) {\n                ALOGE(\"%s: SDL_AMediaCodec_getInputBuffer failed\\n\", __func__);\n                ret = -1;\n                goto fail;\n            }\n        }\n\n        time_stamp = d->pkt_temp.pts;\n        if (time_stamp == AV_NOPTS_VALUE && d->pkt_temp.dts != AV_NOPTS_VALUE)\n            time_stamp = d->pkt_temp.dts;\n        if (time_stamp >= 0) {\n            time_stamp = av_rescale_q(time_stamp, is->video_st->time_base, AV_TIME_BASE_Q);\n        } else {\n            time_stamp = 0;\n        }\n        // ALOGE(\"queueInputBuffer, %lld\\n\", time_stamp);\n        amc_ret = SDL_AMediaCodec_queueInputBuffer(opaque->acodec, input_buffer_index, 0, copy_size, time_stamp, queue_flags);\n        if (amc_ret != SDL_AMEDIA_OK) {\n            ALOGE(\"%s: SDL_AMediaCodec_getInputBuffer failed\\n\", __func__);\n            ret = -1;\n            goto fail;\n        }\n        // ALOGE(\"%s: queue %d/%d\", __func__, (int)copy_size, (int)input_buffer_size);\n        opaque->input_packet_count++;\n        if (enqueue_count)\n            ++*enqueue_count;\n    }\n\n    if (copy_size < 0) {\n        d->packet_pending = 0;\n    } else {\n        d->pkt_temp.dts =\n        d->pkt_temp.pts = AV_NOPTS_VALUE;\n        if (d->pkt_temp.data) {\n            d->pkt_temp.data += copy_size;\n            d->pkt_temp.size -= copy_size;\n            if (d->pkt_temp.size <= 0)\n                d->packet_pending = 0;\n        } else {\n            // FIXME: detect if decode finished\n            // if (!got_frame) {\n                d->packet_pending = 0;\n                d->finished = d->pkt_serial;\n            // }\n        }\n    }\n\nfail:\n    return ret;\n}\n\nstatic int feed_input_buffer(JNIEnv *env, IJKFF_Pipenode *node, int64_t timeUs, int *enqueue_count)\n{\n    IJKFF_Pipenode_Opaque *opaque   = node->opaque;\n    FFPlayer              *ffp      = opaque->ffp;\n    IJKFF_Pipeline        *pipeline = opaque->pipeline;\n    VideoState            *is       = ffp->is;\n    Decoder               *d        = &is->viddec;\n    PacketQueue           *q        = d->queue;\n    sdl_amedia_status_t    amc_ret  = 0;\n    int                    ret      = 0;\n    ssize_t  input_buffer_index = 0;\n    ssize_t  copy_size          = 0;\n    int64_t  time_stamp         = 0;\n    uint32_t queue_flags        = 0;\n\n    if (enqueue_count)\n        *enqueue_count = 0;\n\n    if (d->queue->abort_request) {\n        ret = 0;\n        goto fail;\n    }\n\n    if (!d->packet_pending || d->queue->serial != d->pkt_serial) {\n#if AMC_USE_AVBITSTREAM_FILTER\n#else\n        H264ConvertState convert_state = {0, 0};\n#endif\n        AVPacket pkt;\n        do {\n            if (d->queue->nb_packets == 0)\n                SDL_CondSignal(d->empty_queue_cond);\n            if (ffp_packet_queue_get_or_buffering(ffp, d->queue, &pkt, &d->pkt_serial, &d->finished) < 0) {\n                ret = -1;\n                goto fail;\n            }\n            if (ffp_is_flush_packet(&pkt) || opaque->acodec_flush_request) {\n                // request flush before lock, or never get mutex\n                opaque->acodec_flush_request = true;\n                SDL_LockMutex(opaque->acodec_mutex);\n                if (SDL_AMediaCodec_isStarted(opaque->acodec)) {\n                    if (opaque->input_packet_count > 0) {\n                        // flush empty queue cause error on OMX.SEC.AVC.Decoder (Nexus S)\n                        SDL_VoutAndroid_invalidateAllBuffers(opaque->weak_vout);\n                        SDL_AMediaCodec_flush(opaque->acodec);\n                        opaque->input_packet_count = 0;\n                    }\n                    // If codec is configured in synchronous mode, codec will resume automatically\n                    // SDL_AMediaCodec_start(opaque->acodec);\n                }\n                opaque->acodec_flush_request = false;\n                SDL_CondSignal(opaque->acodec_cond);\n                SDL_UnlockMutex(opaque->acodec_mutex);\n                d->finished = 0;\n                d->next_pts = d->start_pts;\n                d->next_pts_tb = d->start_pts_tb;\n            }\n        } while (ffp_is_flush_packet(&pkt) || d->queue->serial != d->pkt_serial);\n        av_packet_split_side_data(&pkt);\n        av_packet_unref(&d->pkt);\n        d->pkt_temp = d->pkt = pkt;\n        d->packet_pending = 1;\n\n        if (opaque->ffp->mediacodec_handle_resolution_change &&\n            opaque->codecpar->codec_id == AV_CODEC_ID_H264) {\n            uint8_t  *size_data      = NULL;\n            int       size_data_size = 0;\n            AVPacket *avpkt          = &d->pkt_temp;\n            size_data = av_packet_get_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, &size_data_size);\n            // minimum avcC(sps,pps) = 7\n            if (size_data && size_data_size >= 7) {\n                int             got_picture = 0;\n                AVFrame        *frame      = av_frame_alloc();\n                AVDictionary   *codec_opts = NULL;\n                const AVCodec  *codec      = opaque->decoder->avctx->codec;\n                AVCodecContext *new_avctx  = avcodec_alloc_context3(codec);\n                int change_ret = 0;\n                if (!new_avctx)\n                    return AVERROR(ENOMEM);\n\n                avcodec_parameters_to_context(new_avctx, opaque->codecpar);\n                av_freep(&new_avctx->extradata);\n                new_avctx->extradata = av_mallocz(size_data_size + AV_INPUT_BUFFER_PADDING_SIZE);\n                if (!new_avctx->extradata) {\n                    avcodec_free_context(&new_avctx);\n                    return AVERROR(ENOMEM);\n                }\n                memcpy(new_avctx->extradata, size_data, size_data_size);\n                new_avctx->extradata_size = size_data_size;\n\n                av_dict_set(&codec_opts, \"threads\", \"1\", 0);\n                change_ret = avcodec_open2(new_avctx, codec, &codec_opts);\n                av_dict_free(&codec_opts);\n                if (change_ret < 0) {\n                    avcodec_free_context(&new_avctx);\n                    return change_ret;\n                }\n\n                change_ret = avcodec_decode_video2(new_avctx, frame, &got_picture, avpkt);\n                if (change_ret < 0) {\n                    avcodec_free_context(&new_avctx);\n                    return change_ret;\n                } else {\n                    if (opaque->codecpar->width  != new_avctx->width &&\n                        opaque->codecpar->height != new_avctx->height) {\n                        ALOGW(\"AV_PKT_DATA_NEW_EXTRADATA: %d x %d\\n\", new_avctx->width, new_avctx->height);\n                        avcodec_parameters_from_context(opaque->codecpar, new_avctx);\n                        opaque->aformat_need_recreate = true;\n                        ffpipeline_set_surface_need_reconfigure_l(pipeline, true);\n                    }\n                }\n\n                av_frame_unref(frame);\n                avcodec_free_context(&new_avctx);\n            }\n        }\n\n#if AMC_USE_AVBITSTREAM_FILTER\n        // d->pkt_temp->data could be allocated by av_bitstream_filter_filter\n        if (d->bfsc_ret > 0) {\n            if (d->bfsc_data)\n                av_freep(&d->bfsc_data);\n            d->bfsc_ret = 0;\n        }\n        d->bfsc_ret =\n            av_bitstream_filter_filter(opaque->bsfc, opaque->avctx, NULL, &d->pkt_temp.data, &d->pkt_temp.size,\n                                       d->pkt.data, d->pkt.size, d->pkt.flags & AV_PKT_FLAG_KEY);\n        if (d->bfsc_ret > 0) {\n            d->bfsc_data = d->pkt_temp.data;\n        } else if (d->bfsc_ret < 0) {\n            ALOGE(\"%s: av_bitstream_filter_filter failed\\n\", __func__);\n            ret = -1;\n            goto fail;\n        }\n\n        if (d->pkt_temp.size == d->pkt.size + opaque->avctx->extradata_size) {\n            d->pkt_temp.data += opaque->avctx->extradata_size;\n            d->pkt_temp.size  = d->pkt.size;\n        }\n\n        AMCTRACE(\"bsfc->filter(%d): %p[%d] -> %p[%d]\", d->bfsc_ret, d->pkt.data, (int)d->pkt.size, d->pkt_temp.data, (int)d->pkt_temp.size);\n#else\n#if 0\n        AMCTRACE(\"raw [%d][%d] %02x%02x%02x%02x%02x%02x%02x%02x\", (int)d->pkt_temp.size,\n            (int)opaque->nal_size,\n            d->pkt_temp.data[0],\n            d->pkt_temp.data[1],\n            d->pkt_temp.data[2],\n            d->pkt_temp.data[3],\n            d->pkt_temp.data[4],\n            d->pkt_temp.data[5],\n            d->pkt_temp.data[6],\n            d->pkt_temp.data[7]);\n#endif\n        if (opaque->codecpar->codec_id == AV_CODEC_ID_H264 || opaque->codecpar->codec_id == AV_CODEC_ID_HEVC) {\n            convert_h264_to_annexb(d->pkt_temp.data, d->pkt_temp.size, opaque->nal_size, &convert_state);\n            int64_t time_stamp = d->pkt_temp.pts;\n            if (!time_stamp && d->pkt_temp.dts)\n                time_stamp = d->pkt_temp.dts;\n            if (time_stamp > 0) {\n                time_stamp = av_rescale_q(time_stamp, is->video_st->time_base, AV_TIME_BASE_Q);\n            } else {\n                time_stamp = 0;\n            }\n        }\n#if 0\n        AMCTRACE(\"input[%d][%d][%lld,%lld (%d, %d) -> %lld] %02x%02x%02x%02x%02x%02x%02x%02x\", (int)d->pkt_temp.size,\n            (int)opaque->nal_size,\n            (int64_t)d->pkt_temp.pts,\n            (int64_t)d->pkt_temp.dts,\n            (int)is->video_st->time_base.num,\n            (int)is->video_st->time_base.den,\n            (int64_t)time_stamp,\n            d->pkt_temp.data[0],\n            d->pkt_temp.data[1],\n            d->pkt_temp.data[2],\n            d->pkt_temp.data[3],\n            d->pkt_temp.data[4],\n            d->pkt_temp.data[5],\n            d->pkt_temp.data[6],\n            d->pkt_temp.data[7]);\n#endif\n#endif\n    }\n\n    if (d->pkt_temp.data) {\n        // reconfigure surface if surface changed\n        // NULL surface cause no display\n        if (ffpipeline_is_surface_need_reconfigure_l(pipeline)) {\n            jobject new_surface = NULL;\n\n            // request reconfigure before lock, or never get mutex\n            ffpipeline_lock_surface(pipeline);\n            ffpipeline_set_surface_need_reconfigure_l(pipeline, false);\n            new_surface = ffpipeline_get_surface_as_global_ref_l(env, pipeline);\n            ffpipeline_unlock_surface(pipeline);\n\n            if (!opaque->aformat_need_recreate &&\n                (opaque->jsurface == new_surface ||\n                (opaque->jsurface && new_surface && (*env)->IsSameObject(env, new_surface, opaque->jsurface)))) {\n                ALOGI(\"%s: same surface, reuse previous surface\\n\", __func__);\n                J4A_DeleteGlobalRef__p(env, &new_surface);\n            } else {\n                if (opaque->aformat_need_recreate) {\n                    ALOGI(\"%s: recreate aformat\\n\", __func__);\n                    ret = recreate_format_l(env, node);\n                    if (ret) {\n                        ALOGE(\"amc: recreate_format_l failed\\n\");\n                        goto fail;\n                    }\n                    opaque->aformat_need_recreate = false;\n                }\n\n                opaque->acodec_reconfigure_request = true;\n                SDL_LockMutex(opaque->acodec_mutex);\n                ret = reconfigure_codec_l(env, node, new_surface);\n                opaque->acodec_reconfigure_request = false;\n                SDL_CondSignal(opaque->acodec_cond);\n                SDL_UnlockMutex(opaque->acodec_mutex);\n\n                J4A_DeleteGlobalRef__p(env, &new_surface);\n\n                if (ret != 0) {\n                    ALOGE(\"%s: reconfigure_codec failed\\n\", __func__);\n                    ret = 0;\n                    goto fail;\n                }\n\n                SDL_LockMutex(opaque->acodec_first_dequeue_output_mutex);\n                while (!q->abort_request &&\n                    !opaque->acodec_reconfigure_request &&\n                    !opaque->acodec_flush_request &&\n                    opaque->acodec_first_dequeue_output_request) {\n                    SDL_CondWaitTimeout(opaque->acodec_first_dequeue_output_cond, opaque->acodec_first_dequeue_output_mutex, 100);\n                }\n                SDL_UnlockMutex(opaque->acodec_first_dequeue_output_mutex);\n\n                if (q->abort_request || opaque->acodec_reconfigure_request || opaque->acodec_flush_request) {\n                    ret = 0;\n                    goto fail;\n                }\n            }\n        }\n\n#if 0\n        // no need to decode without surface\n        if (!opaque->jsurface) {\n            ret = amc_decode_picture_fake(node, 1000);\n            goto fail;\n        }\n#endif\n\n        queue_flags = 0;\n        input_buffer_index = SDL_AMediaCodec_dequeueInputBuffer(opaque->acodec, timeUs);\n        if (input_buffer_index < 0) {\n            if (SDL_AMediaCodec_isInputBuffersValid(opaque->acodec)) {\n                // timeout\n                ret = 0;\n                goto fail;\n            } else {\n                // enqueue fake frame\n                queue_flags |= AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME;\n                copy_size    = d->pkt_temp.size;\n            }\n        } else {\n            SDL_AMediaCodecFake_flushFakeFrames(opaque->acodec);\n\n            copy_size = SDL_AMediaCodec_writeInputData(opaque->acodec, input_buffer_index, d->pkt_temp.data, d->pkt_temp.size);\n            if (!copy_size) {\n                ALOGE(\"%s: SDL_AMediaCodec_getInputBuffer failed\\n\", __func__);\n                ret = -1;\n                goto fail;\n            }\n        }\n\n        time_stamp = d->pkt_temp.pts;\n        if (time_stamp == AV_NOPTS_VALUE && d->pkt_temp.dts != AV_NOPTS_VALUE)\n            time_stamp = d->pkt_temp.dts;\n        if (time_stamp >= 0) {\n            time_stamp = av_rescale_q(time_stamp, is->video_st->time_base, AV_TIME_BASE_Q);\n        } else {\n            time_stamp = 0;\n        }\n        // ALOGE(\"queueInputBuffer, %lld\\n\", time_stamp);\n        amc_ret = SDL_AMediaCodec_queueInputBuffer(opaque->acodec, input_buffer_index, 0, copy_size, time_stamp, queue_flags);\n        if (amc_ret != SDL_AMEDIA_OK) {\n            ALOGE(\"%s: SDL_AMediaCodec_getInputBuffer failed\\n\", __func__);\n            ret = -1;\n            goto fail;\n        }\n        // ALOGE(\"%s: queue %d/%d\", __func__, (int)copy_size, (int)input_buffer_size);\n        opaque->input_packet_count++;\n        if (enqueue_count)\n            ++*enqueue_count;\n    }\n\n    if (copy_size < 0) {\n        d->packet_pending = 0;\n    } else {\n        d->pkt_temp.dts =\n        d->pkt_temp.pts = AV_NOPTS_VALUE;\n        if (d->pkt_temp.data) {\n            d->pkt_temp.data += copy_size;\n            d->pkt_temp.size -= copy_size;\n            if (d->pkt_temp.size <= 0)\n                d->packet_pending = 0;\n        } else {\n            // FIXME: detect if decode finished\n            // if (!got_frame) {\n                d->packet_pending = 0;\n                d->finished = d->pkt_serial;\n            // }\n        }\n    }\n\nfail:\n    return ret;\n}\n\nstatic int enqueue_thread_func(void *arg)\n{\n    JNIEnv                *env      = NULL;\n    IJKFF_Pipenode        *node     = arg;\n    IJKFF_Pipenode_Opaque *opaque   = node->opaque;\n    FFPlayer              *ffp      = opaque->ffp;\n    VideoState            *is       = ffp->is;\n    Decoder               *d        = &is->viddec;\n    PacketQueue           *q        = d->queue;\n    int                    ret      = -1;\n    int                    dequeue_count = 0;\n\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"%s: SetupThreadEnv failed\\n\", __func__);\n        goto fail;\n    }\n\n    while (!q->abort_request && !opaque->abort) {\n        ret = feed_input_buffer(env, node, AMC_INPUT_TIMEOUT_US, &dequeue_count);\n        if (ret != 0) {\n            goto fail;\n        }\n    }\n\n    ret = 0;\nfail:\n    SDL_AMediaCodecFake_abort(opaque->acodec);\n    ALOGI(\"MediaCodec: %s: exit: %d\", __func__, ret);\n    return ret;\n}\n\nstatic double pts_from_buffer_info(IJKFF_Pipenode *node, SDL_AMediaCodecBufferInfo *buffer_info)\n{\n    IJKFF_Pipenode_Opaque *opaque     = node->opaque;\n    FFPlayer              *ffp        = opaque->ffp;\n    VideoState            *is         = ffp->is;\n    AVRational             tb         = is->video_st->time_base;\n    int64_t amc_pts = av_rescale_q(buffer_info->presentationTimeUs, AV_TIME_BASE_Q, is->video_st->time_base);\n    double pts = amc_pts < 0 ? NAN : amc_pts * av_q2d(tb);\n\n    return pts;\n}\n\n/* it's OK here */\nstatic void sort_amc_buf_out(AMC_Buf_Out *buf_out, int size) {\n    AMC_Buf_Out *a, *b, tmp;\n    int i, j;\n\n    for (i = 0; i < size; i++) {\n        for (j = i + 1; j < size; j++) {\n            a = buf_out + i;\n            b = buf_out + j;\n            if (a->pts < b->pts) {\n                tmp = *a;\n                *a = *b;\n                *b = tmp;\n            }\n        }\n    }\n}\n\nstatic int drain_output_buffer_l(JNIEnv *env, IJKFF_Pipenode *node, int64_t timeUs, int *dequeue_count, AVFrame *frame, int *got_frame)\n{\n    IJKFF_Pipenode_Opaque *opaque   = node->opaque;\n    FFPlayer              *ffp      = opaque->ffp;\n    int                    ret      = 0;\n    SDL_AMediaCodecBufferInfo bufferInfo;\n    ssize_t                   output_buffer_index = 0;\n\n    if (dequeue_count)\n        *dequeue_count = 0;\n\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"%s:create: SetupThreadEnv failed\\n\", __func__);\n        goto fail;\n    }\n\n    output_buffer_index = SDL_AMediaCodecFake_dequeueOutputBuffer(opaque->acodec, &bufferInfo, timeUs);\n    if (output_buffer_index == AMEDIACODEC__INFO_OUTPUT_BUFFERS_CHANGED) {\n        ALOGI(\"AMEDIACODEC__INFO_OUTPUT_BUFFERS_CHANGED\\n\");\n        // continue;\n    } else if (output_buffer_index == AMEDIACODEC__INFO_OUTPUT_FORMAT_CHANGED) {\n        ALOGI(\"AMEDIACODEC__INFO_OUTPUT_FORMAT_CHANGED\\n\");\n        SDL_AMediaFormat_deleteP(&opaque->output_aformat);\n        opaque->output_aformat = SDL_AMediaCodec_getOutputFormat(opaque->acodec);\n        if (opaque->output_aformat) {\n            int width        = 0;\n            int height       = 0;\n            int color_format = 0;\n            int stride       = 0;\n            int slice_height = 0;\n            int crop_left    = 0;\n            int crop_top     = 0;\n            int crop_right   = 0;\n            int crop_bottom  = 0;\n\n            SDL_AMediaFormat_getInt32(opaque->output_aformat, \"width\",          &width);\n            SDL_AMediaFormat_getInt32(opaque->output_aformat, \"height\",         &height);\n            SDL_AMediaFormat_getInt32(opaque->output_aformat, \"color-format\",   &color_format);\n\n            SDL_AMediaFormat_getInt32(opaque->output_aformat, \"stride\",         &stride);\n            SDL_AMediaFormat_getInt32(opaque->output_aformat, \"slice-height\",   &slice_height);\n            SDL_AMediaFormat_getInt32(opaque->output_aformat, \"crop-left\",      &crop_left);\n            SDL_AMediaFormat_getInt32(opaque->output_aformat, \"crop-top\",       &crop_top);\n            SDL_AMediaFormat_getInt32(opaque->output_aformat, \"crop-right\",     &crop_right);\n            SDL_AMediaFormat_getInt32(opaque->output_aformat, \"crop-bottom\",    &crop_bottom);\n\n            // TI decoder could crash after reconfigure\n            // ffp_notify_msg3(ffp, FFP_MSG_VIDEO_SIZE_CHANGED, width, height);\n            // opaque->frame_width  = width;\n            // opaque->frame_height = height;\n            ALOGI(\n                \"AMEDIACODEC__INFO_OUTPUT_FORMAT_CHANGED\\n\"\n                \"    width-height: (%d x %d)\\n\"\n                \"    color-format: (%s: 0x%x)\\n\"\n                \"    stride:       (%d)\\n\"\n                \"    slice-height: (%d)\\n\"\n                \"    crop:         (%d, %d, %d, %d)\\n\"\n                ,\n                width, height,\n                SDL_AMediaCodec_getColorFormatName(color_format), color_format,\n                stride,\n                slice_height,\n                crop_left, crop_top, crop_right, crop_bottom);\n        }\n        // continue;\n    } else if (output_buffer_index == AMEDIACODEC__INFO_TRY_AGAIN_LATER) {\n        AMCTRACE(\"AMEDIACODEC__INFO_TRY_AGAIN_LATER\\n\");\n        // continue;\n    } else if (output_buffer_index < 0) {\n        SDL_LockMutex(opaque->any_input_mutex);\n        SDL_CondWaitTimeout(opaque->any_input_cond, opaque->any_input_mutex, 1000);\n        SDL_UnlockMutex(opaque->any_input_mutex);\n\n        goto done;\n    } else if (output_buffer_index >= 0) {\n        ffp->stat.vdps = SDL_SpeedSamplerAdd(&opaque->sampler, FFP_SHOW_VDPS_MEDIACODEC, \"vdps[MediaCodec]\");\n\n        if (dequeue_count)\n            ++*dequeue_count;\n\n#ifdef FFP_SHOW_AMC_VDPS\n        {\n            if (opaque->benchmark_start_time == 0) {\n                opaque->benchmark_start_time   = SDL_GetTickHR();\n            }\n            opaque->benchmark_frame_count += 1;\n            if (0 == (opaque->benchmark_frame_count % 240)) {\n                Uint64 diff = SDL_GetTickHR() - opaque->benchmark_start_time;\n                double per_frame_ms = ((double) diff) / opaque->benchmark_frame_count;\n                double fps          = ((double) opaque->benchmark_frame_count) * 1000 / diff;\n                ALOGE(\"%lf fps, %lf ms/frame, %\"PRIu64\" frames\\n\",\n                      fps, per_frame_ms, opaque->benchmark_frame_count);\n            }\n        }\n#endif\n#ifdef FFP_AMC_DISABLE_OUTPUT\n        if (!(bufferInfo.flags & AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME)) {\n            SDL_AMediaCodec_releaseOutputBuffer(opaque->acodec, output_buffer_index, false);\n        }\n        goto done;\n#endif\n\n        if (opaque->n_buf_out) {\n            AMC_Buf_Out *buf_out;\n\n            if (opaque->off_buf_out < opaque->n_buf_out) {\n                // ALOGD(\"filling buffer... %d\", opaque->off_buf_out);\n                buf_out = &opaque->amc_buf_out[opaque->off_buf_out++];\n                buf_out->acodec_serial = SDL_AMediaCodec_getSerial(opaque->acodec);\n                buf_out->port = output_buffer_index;\n                buf_out->info = bufferInfo;\n                buf_out->pts = pts_from_buffer_info(node, &bufferInfo);\n                sort_amc_buf_out(opaque->amc_buf_out, opaque->off_buf_out);\n            } else {\n                double pts;\n\n                pts = pts_from_buffer_info(node, &bufferInfo);\n                if (opaque->last_queued_pts != AV_NOPTS_VALUE &&\n                    pts < opaque->last_queued_pts) {\n                    // FIXME: drop unordered picture to avoid dither\n                    // ALOGE(\"early picture, drop!\");\n                    // SDL_AMediaCodec_releaseOutputBuffer(opaque->acodec, output_buffer_index, false);\n                    // goto done;\n                }\n                /* already sorted */\n                buf_out = &opaque->amc_buf_out[opaque->off_buf_out - 1];\n                /* new picture is the most aged, send now */\n                if (pts < buf_out->pts) {\n                    ret = amc_fill_frame(node, frame, got_frame, output_buffer_index, SDL_AMediaCodec_getSerial(opaque->acodec), &bufferInfo);\n                    opaque->last_queued_pts = pts;\n                    // ALOGD(\"pts = %f\", pts);\n                } else {\n                    int i;\n\n                    /* find one to send */\n                    for (i = opaque->off_buf_out - 1; i >= 0; i--) {\n                        buf_out = &opaque->amc_buf_out[i];\n                        if (pts > buf_out->pts) {\n                            ret = amc_fill_frame(node, frame, got_frame, buf_out->port, buf_out->acodec_serial, &buf_out->info);\n                            opaque->last_queued_pts = buf_out->pts;\n                            // ALOGD(\"pts = %f\", buf_out->pts);\n                            /* replace for sort later */\n                            buf_out->acodec_serial = SDL_AMediaCodec_getSerial(opaque->acodec);\n                            buf_out->port = output_buffer_index;\n                            buf_out->info = bufferInfo;\n                            buf_out->pts = pts_from_buffer_info(node, &bufferInfo);\n                            sort_amc_buf_out(opaque->amc_buf_out, opaque->n_buf_out);\n                            break;\n                        }\n                    }\n                    /* need to discard current buffer */\n                    if (i < 0) {\n                        // ALOGE(\"buffer too small, drop picture!\");\n                        if (!(bufferInfo.flags & AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME)) {\n                            SDL_AMediaCodec_releaseOutputBuffer(opaque->acodec, output_buffer_index, false);\n                            goto done;\n                        }\n                    }\n                }\n            }\n        } else {\n            ret = amc_fill_frame(node, frame, got_frame, output_buffer_index, SDL_AMediaCodec_getSerial(opaque->acodec), &bufferInfo);\n        }\n    }\n\ndone:\n    if (opaque->decoder->queue->abort_request)\n        ret = -1;\n    else\n        ret = 0;\nfail:\n    return ret;\n}\n\nstatic int drain_output_buffer2_l(JNIEnv *env, IJKFF_Pipenode *node, int64_t timeUs, int *dequeue_count, AVFrame *frame, int *got_frame)\n{\n    IJKFF_Pipenode_Opaque *opaque         = node->opaque;\n    FFPlayer              *ffp            = opaque->ffp;\n    SDL_AMediaCodecBufferInfo bufferInfo;\n    ssize_t          output_buffer_index  = 0;\n\n    if (dequeue_count)\n        *dequeue_count = 0;\n\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"%s:create: SetupThreadEnv failed\\n\", __func__);\n        return ACODEC_RETRY;\n    }\n\n    output_buffer_index = SDL_AMediaCodecFake_dequeueOutputBuffer(opaque->acodec, &bufferInfo, timeUs);\n    if (output_buffer_index == AMEDIACODEC__INFO_OUTPUT_BUFFERS_CHANGED) {\n        ALOGD(\"AMEDIACODEC__INFO_OUTPUT_BUFFERS_CHANGED\\n\");\n        return ACODEC_RETRY;\n    } else if (output_buffer_index == AMEDIACODEC__INFO_OUTPUT_FORMAT_CHANGED) {\n        ALOGD(\"AMEDIACODEC__INFO_OUTPUT_FORMAT_CHANGED\\n\");\n        SDL_AMediaFormat_deleteP(&opaque->output_aformat);\n        opaque->output_aformat = SDL_AMediaCodec_getOutputFormat(opaque->acodec);\n        if (opaque->output_aformat) {\n            int width        = 0;\n            int height       = 0;\n            int color_format = 0;\n            int stride       = 0;\n            int slice_height = 0;\n            int crop_left    = 0;\n            int crop_top     = 0;\n            int crop_right   = 0;\n            int crop_bottom  = 0;\n\n            SDL_AMediaFormat_getInt32(opaque->output_aformat, \"width\",          &width);\n            SDL_AMediaFormat_getInt32(opaque->output_aformat, \"height\",         &height);\n            SDL_AMediaFormat_getInt32(opaque->output_aformat, \"color-format\",   &color_format);\n\n            SDL_AMediaFormat_getInt32(opaque->output_aformat, \"stride\",         &stride);\n            SDL_AMediaFormat_getInt32(opaque->output_aformat, \"slice-height\",   &slice_height);\n            SDL_AMediaFormat_getInt32(opaque->output_aformat, \"crop-left\",      &crop_left);\n            SDL_AMediaFormat_getInt32(opaque->output_aformat, \"crop-top\",       &crop_top);\n            SDL_AMediaFormat_getInt32(opaque->output_aformat, \"crop-right\",     &crop_right);\n            SDL_AMediaFormat_getInt32(opaque->output_aformat, \"crop-bottom\",    &crop_bottom);\n\n            // TI decoder could crash after reconfigure\n            // ffp_notify_msg3(ffp, FFP_MSG_VIDEO_SIZE_CHANGED, width, height);\n            // opaque->frame_width  = width;\n            // opaque->frame_height = height;\n            ALOGI(\n                \"AMEDIACODEC__INFO_OUTPUT_FORMAT_CHANGED\\n\"\n                \"    width-height: (%d x %d)\\n\"\n                \"    color-format: (%s: 0x%x)\\n\"\n                \"    stride:       (%d)\\n\"\n                \"    slice-height: (%d)\\n\"\n                \"    crop:         (%d, %d, %d, %d)\\n\"\n                ,\n                width, height,\n                SDL_AMediaCodec_getColorFormatName(color_format), color_format,\n                stride,\n                slice_height,\n                crop_left, crop_top, crop_right, crop_bottom);\n        }\n        return ACODEC_RETRY;\n        // continue;\n    } else if (output_buffer_index == AMEDIACODEC__INFO_TRY_AGAIN_LATER) {\n        return 0;\n        // continue;\n    } else if (output_buffer_index < 0) {\n        return 0;\n    } else if (output_buffer_index >= 0) {\n        ffp->stat.vdps = SDL_SpeedSamplerAdd(&opaque->sampler, FFP_SHOW_VDPS_MEDIACODEC, \"vdps[MediaCodec]\");\n\n        if (dequeue_count)\n            ++*dequeue_count;\n\n        if (opaque->n_buf_out) {\n            AMC_Buf_Out *buf_out;\n            if (opaque->off_buf_out < opaque->n_buf_out) {\n                // ALOGD(\"filling buffer... %d\", opaque->off_buf_out);\n                buf_out = &opaque->amc_buf_out[opaque->off_buf_out++];\n                buf_out->acodec_serial = SDL_AMediaCodec_getSerial(opaque->acodec);\n                buf_out->port = output_buffer_index;\n                buf_out->info = bufferInfo;\n                buf_out->pts = pts_from_buffer_info(node, &bufferInfo);\n                sort_amc_buf_out(opaque->amc_buf_out, opaque->off_buf_out);\n            } else {\n                double pts;\n\n                pts = pts_from_buffer_info(node, &bufferInfo);\n                if (opaque->last_queued_pts != AV_NOPTS_VALUE &&\n                    pts < opaque->last_queued_pts) {\n                    // FIXME: drop unordered picture to avoid dither\n                    // ALOGE(\"early picture, drop!\");\n                    // SDL_AMediaCodec_releaseOutputBuffer(opaque->acodec, output_buffer_index, false);\n                    // goto done;\n                }\n                /* already sorted */\n                buf_out = &opaque->amc_buf_out[opaque->off_buf_out - 1];\n                /* new picture is the most aged, send now */\n                if (pts < buf_out->pts) {\n                    amc_fill_frame(node, frame, got_frame, output_buffer_index, SDL_AMediaCodec_getSerial(opaque->acodec), &bufferInfo);\n                    opaque->last_queued_pts = pts;\n                    // ALOGD(\"pts = %f\", pts);\n                } else {\n                    int i;\n\n                    /* find one to send */\n                    for (i = opaque->off_buf_out - 1; i >= 0; i--) {\n                        buf_out = &opaque->amc_buf_out[i];\n                        if (pts > buf_out->pts) {\n                            amc_fill_frame(node, frame, got_frame, buf_out->port, buf_out->acodec_serial, &buf_out->info);\n                            opaque->last_queued_pts = buf_out->pts;\n                            // ALOGD(\"pts = %f\", buf_out->pts);\n                            /* replace for sort later */\n                            buf_out->acodec_serial = SDL_AMediaCodec_getSerial(opaque->acodec);\n                            buf_out->port = output_buffer_index;\n                            buf_out->info = bufferInfo;\n                            buf_out->pts = pts_from_buffer_info(node, &bufferInfo);\n                            sort_amc_buf_out(opaque->amc_buf_out, opaque->n_buf_out);\n                            break;\n                        }\n                    }\n                    /* need to discard current buffer */\n                    if (i < 0) {\n                        // ALOGE(\"buffer too small, drop picture!\");\n                        if (!(bufferInfo.flags & AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME)) {\n                            SDL_AMediaCodec_releaseOutputBuffer(opaque->acodec, output_buffer_index, false);\n                            return 0;\n                        }\n                    }\n                }\n            }\n        } else {\n            amc_fill_frame(node, frame, got_frame, output_buffer_index, SDL_AMediaCodec_getSerial(opaque->acodec), &bufferInfo);\n        }\n    }\n\n    return 0;\n}\n\nstatic int drain_output_buffer(JNIEnv *env, IJKFF_Pipenode *node, int64_t timeUs, int *dequeue_count, AVFrame *frame, int *got_frame)\n{\n    IJKFF_Pipenode_Opaque *opaque = node->opaque;\n    SDL_LockMutex(opaque->acodec_mutex);\n\n    if (opaque->acodec_flush_request || opaque->acodec_reconfigure_request) {\n        // TODO: invalid picture here?\n        // let feed_input_buffer() get mutex\n        SDL_CondWaitTimeout(opaque->acodec_cond, opaque->acodec_mutex, 100);\n    }\n\n    int ret = drain_output_buffer_l(env, node, timeUs, dequeue_count, frame, got_frame);\n    SDL_UnlockMutex(opaque->acodec_mutex);\n    return ret;\n}\n\nstatic void func_destroy(IJKFF_Pipenode *node)\n{\n    if (!node || !node->opaque)\n        return;\n\n    IJKFF_Pipenode_Opaque *opaque = node->opaque;\n\n    SDL_DestroyCondP(&opaque->any_input_cond);\n    SDL_DestroyMutexP(&opaque->any_input_mutex);\n    SDL_DestroyCondP(&opaque->acodec_cond);\n    SDL_DestroyMutexP(&opaque->acodec_mutex);\n    SDL_DestroyCondP(&opaque->acodec_first_dequeue_output_cond);\n    SDL_DestroyMutexP(&opaque->acodec_first_dequeue_output_mutex);\n\n    SDL_AMediaCodec_decreaseReferenceP(&opaque->acodec);\n    SDL_AMediaFormat_deleteP(&opaque->input_aformat);\n    SDL_AMediaFormat_deleteP(&opaque->output_aformat);\n\n#if AMC_USE_AVBITSTREAM_FILTER\n    av_freep(&opaque->orig_extradata);\n\n    if (opaque->bsfc) {\n        av_bitstream_filter_close(opaque->bsfc);\n        opaque->bsfc = NULL;\n    }\n#endif\n\n    avcodec_parameters_free(&opaque->codecpar);\n\n    JNIEnv *env = NULL;\n    if (JNI_OK == SDL_JNI_SetupThreadEnv(&env)) {\n        if (opaque->jsurface != NULL) {\n            SDL_JNI_DeleteGlobalRefP(env, &opaque->jsurface);\n        }\n    }\n}\n\nstatic int drain_output_buffer2(JNIEnv *env, IJKFF_Pipenode *node, int64_t timeUs, int *dequeue_count, AVFrame *frame, AVRational frame_rate)\n{\n    IJKFF_Pipenode_Opaque *opaque    = node->opaque;\n    FFPlayer              *ffp       = opaque->ffp;\n    VideoState            *is        = ffp->is;\n    AVRational            tb         = is->video_st->time_base;\n    int                   got_frame  = 0;\n    int                   ret        = -1;\n    double                duration;\n    double                pts;\n    while (ret) {\n        got_frame = 0;\n        ret = drain_output_buffer2_l(env, node, timeUs, dequeue_count, frame, &got_frame);\n\n        if (opaque->decoder->queue->abort_request) {\n            if (got_frame && frame->opaque)\n                SDL_VoutAndroid_releaseBufferProxyP(opaque->weak_vout, (SDL_AMediaCodecBufferProxy **)&frame->opaque, false);\n\n            return ACODEC_EXIT;\n        }\n\n        if (ret != 0) {\n            if (got_frame && frame->opaque)\n                SDL_VoutAndroid_releaseBufferProxyP(opaque->weak_vout, (SDL_AMediaCodecBufferProxy **)&frame->opaque, false);\n        }\n    }\n\n    if (got_frame) {\n        duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational){frame_rate.den, frame_rate.num}) : 0);\n        pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb);\n        if (ffp->framedrop > 0 || (ffp->framedrop && ffp_get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) {\n            ffp->stat.decode_frame_count++;\n            if (frame->pts != AV_NOPTS_VALUE) {\n                double dpts = pts;\n                double diff = dpts - ffp_get_master_clock(is);\n                if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD &&\n                    diff - is->frame_last_filter_delay < 0 &&\n                    is->viddec.pkt_serial == is->vidclk.serial &&\n                    is->videoq.nb_packets) {\n                    is->frame_drops_early++;\n                    is->continuous_frame_drops_early++;\n                    if (is->continuous_frame_drops_early > ffp->framedrop) {\n                        is->continuous_frame_drops_early = 0;\n                    } else {\n                        ffp->stat.drop_frame_count++;\n                        ffp->stat.drop_frame_rate = (float)(ffp->stat.drop_frame_count) / (float)(ffp->stat.decode_frame_count);\n                        if (frame->opaque) {\n                            SDL_VoutAndroid_releaseBufferProxyP(opaque->weak_vout, (SDL_AMediaCodecBufferProxy **)&frame->opaque, false);\n                        }\n                        av_frame_unref(frame);\n                        return ret;\n                    }\n                }\n            }\n        }\n        ret = ffp_queue_picture(ffp, frame, pts, duration, av_frame_get_pkt_pos(frame), is->viddec.pkt_serial);\n        if (ret) {\n            if (frame->opaque)\n                SDL_VoutAndroid_releaseBufferProxyP(opaque->weak_vout, (SDL_AMediaCodecBufferProxy **)&frame->opaque, false);\n        }\n        av_frame_unref(frame);\n    }\n\n    return ret;\n}\n\nstatic int func_run_sync_loop(IJKFF_Pipenode *node) {\n    JNIEnv                *env           = NULL;\n    IJKFF_Pipenode_Opaque *opaque        = node->opaque;\n    FFPlayer              *ffp           = opaque->ffp;\n    VideoState            *is            = ffp->is;\n    Decoder               *d             = &is->viddec;\n    PacketQueue           *q             = d->queue;\n    int                    ret           = 0;\n    int                    dequeue_count = 0;\n    int                    enqueue_count = 0;\n    AVFrame               *frame         = NULL;\n    AVRational             frame_rate    = av_guess_frame_rate(is->ic, is->video_st, NULL);\n    if (!opaque->acodec) {\n        return ffp_video_thread(ffp);\n    }\n\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"%s: SetupThreadEnv failed\\n\", __func__);\n        return -1;\n    }\n\n    frame = av_frame_alloc();\n    if (!frame)\n        goto fail;\n\n    while (!q->abort_request) {\n        ret = drain_output_buffer2(env, node, AMC_SYNC_OUTPUT_TIMEOUT_US, &dequeue_count, frame, frame_rate);\n        ret = feed_input_buffer2(env, node, AMC_SYNC_INPUT_TIMEOUT_US, &enqueue_count);\n    }\n\nfail:\n    av_frame_free(&frame);\n    opaque->abort = true;\n    if (opaque->n_buf_out) {\n        free(opaque->amc_buf_out);\n        opaque->n_buf_out = 0;\n        opaque->amc_buf_out = NULL;\n        opaque->off_buf_out = 0;\n        opaque->last_queued_pts = AV_NOPTS_VALUE;\n    }\n    if (opaque->acodec) {\n        SDL_VoutAndroid_invalidateAllBuffers(opaque->weak_vout);\n    }\n    SDL_AMediaCodec_stop(opaque->acodec);\n    SDL_AMediaCodec_decreaseReferenceP(&opaque->acodec);\n    ALOGI(\"MediaCodec: %s: exit: %d\", __func__, ret);\n    return ret;\n}\n\nstatic int func_run_sync(IJKFF_Pipenode *node)\n{\n    JNIEnv                *env      = NULL;\n    IJKFF_Pipenode_Opaque *opaque   = node->opaque;\n    FFPlayer              *ffp      = opaque->ffp;\n    VideoState            *is       = ffp->is;\n    Decoder               *d        = &is->viddec;\n    PacketQueue           *q        = d->queue;\n    int                    ret      = 0;\n    int                    dequeue_count = 0;\n    AVFrame               *frame    = NULL;\n    int                    got_frame = 0;\n    AVRational             tb         = is->video_st->time_base;\n    AVRational             frame_rate = av_guess_frame_rate(is->ic, is->video_st, NULL);\n    double                 duration;\n    double                 pts;\n\n    if (!opaque->acodec) {\n        return ffp_video_thread(ffp);\n    }\n\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"%s: SetupThreadEnv failed\\n\", __func__);\n        return -1;\n    }\n\n    frame = av_frame_alloc();\n    if (!frame)\n        goto fail;\n\n    opaque->enqueue_thread = SDL_CreateThreadEx(&opaque->_enqueue_thread, enqueue_thread_func, node, \"amediacodec_input_thread\");\n    if (!opaque->enqueue_thread) {\n        ALOGE(\"%s: SDL_CreateThreadEx failed\\n\", __func__);\n        ret = -1;\n        goto fail;\n    }\n\n    while (!q->abort_request) {\n        int64_t timeUs = opaque->acodec_first_dequeue_output_request ? 0 : AMC_OUTPUT_TIMEOUT_US;\n        got_frame = 0;\n        ret = drain_output_buffer(env, node, timeUs, &dequeue_count, frame, &got_frame);\n        if (opaque->acodec_first_dequeue_output_request) {\n            SDL_LockMutex(opaque->acodec_first_dequeue_output_mutex);\n            opaque->acodec_first_dequeue_output_request = false;\n            SDL_CondSignal(opaque->acodec_first_dequeue_output_cond);\n            SDL_UnlockMutex(opaque->acodec_first_dequeue_output_mutex);\n        }\n        if (ret != 0) {\n            ret = -1;\n            if (got_frame && frame->opaque)\n                SDL_VoutAndroid_releaseBufferProxyP(opaque->weak_vout, (SDL_AMediaCodecBufferProxy **)&frame->opaque, false);\n            goto fail;\n        }\n        if (got_frame) {\n            duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational){frame_rate.den, frame_rate.num}) : 0);\n            pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb);\n            if (ffp->framedrop > 0 || (ffp->framedrop && ffp_get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) {\n                ffp->stat.decode_frame_count++;\n                if (frame->pts != AV_NOPTS_VALUE) {\n                    double dpts = pts;\n                    double diff = dpts - ffp_get_master_clock(is);\n                    if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD &&\n                        diff - is->frame_last_filter_delay < 0 &&\n                        is->viddec.pkt_serial == is->vidclk.serial &&\n                        is->videoq.nb_packets) {\n                        is->frame_drops_early++;\n                        is->continuous_frame_drops_early++;\n                        if (is->continuous_frame_drops_early > ffp->framedrop) {\n                            is->continuous_frame_drops_early = 0;\n                        } else {\n                            ffp->stat.drop_frame_count++;\n                            ffp->stat.drop_frame_rate = (float)(ffp->stat.drop_frame_count) / (float)(ffp->stat.decode_frame_count);\n                            if (frame->opaque) {\n                                SDL_VoutAndroid_releaseBufferProxyP(opaque->weak_vout, (SDL_AMediaCodecBufferProxy **)&frame->opaque, false);\n                            }\n                            av_frame_unref(frame);\n                            continue;\n                        }\n                    }\n                }\n            }\n            ret = ffp_queue_picture(ffp, frame, pts, duration, av_frame_get_pkt_pos(frame), is->viddec.pkt_serial);\n            if (ret) {\n                if (frame->opaque)\n                    SDL_VoutAndroid_releaseBufferProxyP(opaque->weak_vout, (SDL_AMediaCodecBufferProxy **)&frame->opaque, false);\n            }\n            av_frame_unref(frame);\n        }\n    }\n\nfail:\n    av_frame_free(&frame);\n    opaque->abort = true;\n    SDL_WaitThread(opaque->enqueue_thread, NULL);\n    SDL_AMediaCodecFake_abort(opaque->acodec);\n    if (opaque->n_buf_out) {\n        free(opaque->amc_buf_out);\n        opaque->n_buf_out = 0;\n        opaque->amc_buf_out = NULL;\n        opaque->off_buf_out = 0;\n        opaque->last_queued_pts = AV_NOPTS_VALUE;\n    }\n    if (opaque->acodec) {\n        SDL_VoutAndroid_invalidateAllBuffers(opaque->weak_vout);\n        SDL_LockMutex(opaque->acodec_mutex);\n        SDL_UnlockMutex(opaque->acodec_mutex);\n    }\n    SDL_AMediaCodec_stop(opaque->acodec);\n    SDL_AMediaCodec_decreaseReferenceP(&opaque->acodec);\n    ALOGI(\"MediaCodec: %s: exit: %d\", __func__, ret);\n    return ret;\n#if 0\nfallback_to_ffplay:\n    ALOGW(\"fallback to ffplay decoder\\n\");\n    return ffp_video_thread(opaque->ffp);\n#endif\n}\n\nstatic int func_flush(IJKFF_Pipenode *node)\n{\n    IJKFF_Pipenode_Opaque *opaque   = node->opaque;\n\n    if (!opaque)\n        return -1;\n\n    opaque->acodec_flush_request = true;\n\n    return 0;\n}\n\nint ffpipenode_config_from_android_mediacodec(FFPlayer *ffp, IJKFF_Pipeline *pipeline, SDL_Vout *vout, IJKFF_Pipenode *node) {\n    int                   ret     = 0;\n    VideoState            *is     = ffp->is;\n    IJKFF_Pipenode_Opaque *opaque = node->opaque;\n    JNIEnv                *env    = NULL;\n    jobject              jsurface = NULL;\n    opaque->decoder               = &is->viddec;\n\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"%s:create: SetupThreadEnv failed\\n\", __func__);\n        goto fail;\n    }\n\n    ret = avcodec_parameters_from_context(opaque->codecpar, opaque->decoder->avctx);\n    if (ret)\n        goto fail;\n\n    switch (opaque->codecpar->codec_id) {\n    case AV_CODEC_ID_H264:\n        if (!ffp->mediacodec_avc && !ffp->mediacodec_all_videos) {\n            ALOGE(\"%s: MediaCodec: AVC/H264 is disabled. codec_id:%d \\n\", __func__, opaque->codecpar->codec_id);\n            goto fail;\n        }\n        switch (opaque->codecpar->profile) {\n            case FF_PROFILE_H264_BASELINE:\n                ALOGI(\"%s: MediaCodec: H264_BASELINE: enabled\\n\", __func__);\n                break;\n            case FF_PROFILE_H264_CONSTRAINED_BASELINE:\n                ALOGI(\"%s: MediaCodec: H264_CONSTRAINED_BASELINE: enabled\\n\", __func__);\n                break;\n            case FF_PROFILE_H264_MAIN:\n                ALOGI(\"%s: MediaCodec: H264_MAIN: enabled\\n\", __func__);\n                break;\n            case FF_PROFILE_H264_EXTENDED:\n                ALOGI(\"%s: MediaCodec: H264_EXTENDED: enabled\\n\", __func__);\n                break;\n            case FF_PROFILE_H264_HIGH:\n                ALOGI(\"%s: MediaCodec: H264_HIGH: enabled\\n\", __func__);\n                break;\n            case FF_PROFILE_H264_HIGH_10:\n                ALOGW(\"%s: MediaCodec: H264_HIGH_10: disabled\\n\", __func__);\n                goto fail;\n            case FF_PROFILE_H264_HIGH_10_INTRA:\n                ALOGW(\"%s: MediaCodec: H264_HIGH_10_INTRA: disabled\\n\", __func__);\n                goto fail;\n            case FF_PROFILE_H264_HIGH_422:\n                ALOGW(\"%s: MediaCodec: H264_HIGH_10_422: disabled\\n\", __func__);\n                goto fail;\n            case FF_PROFILE_H264_HIGH_422_INTRA:\n                ALOGW(\"%s: MediaCodec: H264_HIGH_10_INTRA: disabled\\n\", __func__);\n                goto fail;\n            case FF_PROFILE_H264_HIGH_444:\n                ALOGW(\"%s: MediaCodec: H264_HIGH_10_444: disabled\\n\", __func__);\n                goto fail;\n            case FF_PROFILE_H264_HIGH_444_PREDICTIVE:\n                ALOGW(\"%s: MediaCodec: H264_HIGH_444_PREDICTIVE: disabled\\n\", __func__);\n                goto fail;\n            case FF_PROFILE_H264_HIGH_444_INTRA:\n                ALOGW(\"%s: MediaCodec: H264_HIGH_444_INTRA: disabled\\n\", __func__);\n                goto fail;\n            case FF_PROFILE_H264_CAVLC_444:\n                ALOGW(\"%s: MediaCodec: H264_CAVLC_444: disabled\\n\", __func__);\n                goto fail;\n            default:\n                ALOGW(\"%s: MediaCodec: (%d) unknown profile: disabled\\n\", __func__, opaque->codecpar->profile);\n                goto fail;\n        }\n        strcpy(opaque->mcc.mime_type, SDL_AMIME_VIDEO_AVC);\n        opaque->mcc.profile = opaque->codecpar->profile;\n        opaque->mcc.level   = opaque->codecpar->level;\n        break;\n    case AV_CODEC_ID_HEVC:\n        if (!ffp->mediacodec_hevc && !ffp->mediacodec_all_videos) {\n            ALOGE(\"%s: MediaCodec/HEVC is disabled. codec_id:%d \\n\", __func__, opaque->codecpar->codec_id);\n            goto fail;\n        }\n        strcpy(opaque->mcc.mime_type, SDL_AMIME_VIDEO_HEVC);\n        opaque->mcc.profile = opaque->codecpar->profile;\n        opaque->mcc.level   = opaque->codecpar->level;\n        break;\n    case AV_CODEC_ID_MPEG2VIDEO:\n        if (!ffp->mediacodec_mpeg2 && !ffp->mediacodec_all_videos) {\n            ALOGE(\"%s: MediaCodec/MPEG2VIDEO is disabled. codec_id:%d \\n\", __func__, opaque->codecpar->codec_id);\n            goto fail;\n        }\n        strcpy(opaque->mcc.mime_type, SDL_AMIME_VIDEO_MPEG2VIDEO);\n        opaque->mcc.profile = opaque->codecpar->profile;\n        opaque->mcc.level   = opaque->codecpar->level;\n        break;\n    case AV_CODEC_ID_MPEG4:\n        if (!ffp->mediacodec_mpeg4 && !ffp->mediacodec_all_videos) {\n            ALOGE(\"%s: MediaCodec/MPEG4 is disabled. codec_id:%d \\n\", __func__, opaque->codecpar->codec_id);\n            goto fail;\n        }\n        if ((opaque->codecpar->codec_tag & 0x0000FFFF) == 0x00005844) {\n            ALOGE(\"%s: divx is not supported \\n\", __func__);\n            goto fail;\n        }\n        strcpy(opaque->mcc.mime_type, SDL_AMIME_VIDEO_MPEG4);\n        opaque->mcc.profile = opaque->codecpar->profile >= 0 ? opaque->codecpar->profile : 0;\n        opaque->mcc.level   = opaque->codecpar->level >= 0 ? opaque->codecpar->level : 1;\n        break;\n\n    default:\n        ALOGE(\"%s:create: not H264 or H265/HEVC, codec_id:%d \\n\", __func__, opaque->codecpar->codec_id);\n        goto fail;\n    }\n\n    if (strcmp(opaque->mcc.mime_type, ffp->video_mime_type)) {\n        ALOGW(\"amc: video_mime_type error opaque->mcc.mime_type = %s\\n\", opaque->mcc.mime_type);\n        goto fail;\n    }\n\n    ret = recreate_format_l(env, node);\n    if (ret) {\n        ALOGE(\"amc: recreate_format_l failed\\n\");\n        goto fail;\n    }\n\n    jsurface = ffpipeline_get_surface_as_global_ref(env, pipeline);\n    ret = configure_codec_l(env, node, jsurface);\n    J4A_DeleteGlobalRef__p(env, &jsurface);\n    if (ret != 0)\n        goto fail;\n\n    ffp_set_video_codec_info(ffp, MEDIACODEC_MODULE_NAME, opaque->mcc.codec_name);\n\n    opaque->off_buf_out = 0;\n    if (opaque->n_buf_out) {\n        int i;\n\n        opaque->amc_buf_out = calloc(opaque->n_buf_out, sizeof(*opaque->amc_buf_out));\n        assert(opaque->amc_buf_out != NULL);\n        for (i = 0; i < opaque->n_buf_out; i++)\n            opaque->amc_buf_out[i].pts = AV_NOPTS_VALUE;\n    }\n\n    SDL_SpeedSamplerReset(&opaque->sampler);\n    ffp->stat.vdec_type = FFP_PROPV_DECODER_MEDIACODEC;\n\n    return 0;\n\nfail:\n    ret = -1;\n    ffpipenode_free_p(&node);\n    return ret;\n}\n\nIJKFF_Pipenode *ffpipenode_init_decoder_from_android_mediacodec(FFPlayer *ffp, IJKFF_Pipeline *pipeline, SDL_Vout *vout)\n{\n    if (SDL_Android_GetApiLevel() < IJK_API_16_JELLY_BEAN)\n        return NULL;\n\n    if (!ffp || !ffp->is)\n        return NULL;\n\n    IJKFF_Pipenode *node = ffpipenode_alloc(sizeof(IJKFF_Pipenode_Opaque));\n    if (!node)\n        return node;\n\n    VideoState            *is     = ffp->is;\n    IJKFF_Pipenode_Opaque *opaque = node->opaque;\n    JNIEnv                *env    = NULL;\n\n    node->func_destroy  = func_destroy;\n    if (ffp->mediacodec_sync) {\n        node->func_run_sync = func_run_sync_loop;\n    } else {\n        node->func_run_sync = func_run_sync;\n    }\n    node->func_flush    = func_flush;\n    opaque->pipeline    = pipeline;\n    opaque->ffp         = ffp;\n    opaque->decoder     = &is->viddec;\n    opaque->weak_vout   = vout;\n\n    opaque->acodec_mutex                      = SDL_CreateMutex();\n    opaque->acodec_cond                       = SDL_CreateCond();\n    opaque->acodec_first_dequeue_output_mutex = SDL_CreateMutex();\n    opaque->acodec_first_dequeue_output_cond  = SDL_CreateCond();\n    opaque->any_input_mutex                   = SDL_CreateMutex();\n    opaque->any_input_cond                    = SDL_CreateCond();\n\n    if (!opaque->acodec_cond || !opaque->acodec_cond || !opaque->acodec_first_dequeue_output_mutex || !opaque->acodec_first_dequeue_output_cond) {\n        ALOGE(\"%s:open_video_decoder: SDL_CreateCond() failed\\n\", __func__);\n        goto fail;\n    }\n\n    opaque->codecpar = avcodec_parameters_alloc();\n    if (!opaque->codecpar)\n        goto fail;\n\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"%s:create: SetupThreadEnv failed\\n\", __func__);\n        goto fail;\n    }\n\n    ALOGI(\"%s:use default mediacodec name: %s\\n\", __func__, ffp->mediacodec_default_name);\n    strcpy(opaque->mcc.codec_name, ffp->mediacodec_default_name);\n    opaque->acodec = SDL_AMediaCodecJava_createByCodecName(env, ffp->mediacodec_default_name);\n\n    if (!opaque->acodec) {\n        goto fail;\n    }\n\n    return node;\nfail:\n    ALOGW(\"%s: init fail\\n\", __func__);\n    ffpipenode_free_p(&node);\n    return NULL;\n}\n\nIJKFF_Pipenode *ffpipenode_create_video_decoder_from_android_mediacodec(FFPlayer *ffp, IJKFF_Pipeline *pipeline, SDL_Vout *vout)\n{\n    ALOGD(\"ffpipenode_create_video_decoder_from_android_mediacodec()\\n\");\n    if (SDL_Android_GetApiLevel() < IJK_API_16_JELLY_BEAN)\n        return NULL;\n\n    if (!ffp || !ffp->is)\n        return NULL;\n\n    IJKFF_Pipenode *node = ffpipenode_alloc(sizeof(IJKFF_Pipenode_Opaque));\n    if (!node)\n        return node;\n\n    VideoState            *is     = ffp->is;\n    IJKFF_Pipenode_Opaque *opaque = node->opaque;\n    JNIEnv                *env    = NULL;\n    int                    ret    = 0;\n    jobject                jsurface = NULL;\n\n    node->func_destroy  = func_destroy;\n    if (ffp->mediacodec_sync) {\n        node->func_run_sync = func_run_sync_loop;\n    } else {\n        node->func_run_sync = func_run_sync;\n    }\n    node->func_flush    = func_flush;\n    opaque->pipeline    = pipeline;\n    opaque->ffp         = ffp;\n    opaque->decoder     = &is->viddec;\n    opaque->weak_vout   = vout;\n\n    opaque->codecpar = avcodec_parameters_alloc();\n    if (!opaque->codecpar)\n        goto fail;\n\n    ret = avcodec_parameters_from_context(opaque->codecpar, opaque->decoder->avctx);\n    if (ret)\n        goto fail;\n\n    switch (opaque->codecpar->codec_id) {\n    case AV_CODEC_ID_H264:\n        if (!ffp->mediacodec_avc && !ffp->mediacodec_all_videos) {\n            ALOGE(\"%s: MediaCodec: AVC/H264 is disabled. codec_id:%d \\n\", __func__, opaque->codecpar->codec_id);\n            goto fail;\n        }\n        switch (opaque->codecpar->profile) {\n            case FF_PROFILE_H264_BASELINE:\n                ALOGI(\"%s: MediaCodec: H264_BASELINE: enabled\\n\", __func__);\n                break;\n            case FF_PROFILE_H264_CONSTRAINED_BASELINE:\n                ALOGI(\"%s: MediaCodec: H264_CONSTRAINED_BASELINE: enabled\\n\", __func__);\n                break;\n            case FF_PROFILE_H264_MAIN:\n                ALOGI(\"%s: MediaCodec: H264_MAIN: enabled\\n\", __func__);\n                break;\n            case FF_PROFILE_H264_EXTENDED:\n                ALOGI(\"%s: MediaCodec: H264_EXTENDED: enabled\\n\", __func__);\n                break;\n            case FF_PROFILE_H264_HIGH:\n                ALOGI(\"%s: MediaCodec: H264_HIGH: enabled\\n\", __func__);\n                break;\n            case FF_PROFILE_H264_HIGH_10:\n                ALOGW(\"%s: MediaCodec: H264_HIGH_10: disabled\\n\", __func__);\n                goto fail;\n            case FF_PROFILE_H264_HIGH_10_INTRA:\n                ALOGW(\"%s: MediaCodec: H264_HIGH_10_INTRA: disabled\\n\", __func__);\n                goto fail;\n            case FF_PROFILE_H264_HIGH_422:\n                ALOGW(\"%s: MediaCodec: H264_HIGH_10_422: disabled\\n\", __func__);\n                goto fail;\n            case FF_PROFILE_H264_HIGH_422_INTRA:\n                ALOGW(\"%s: MediaCodec: H264_HIGH_10_INTRA: disabled\\n\", __func__);\n                goto fail;\n            case FF_PROFILE_H264_HIGH_444:\n                ALOGW(\"%s: MediaCodec: H264_HIGH_10_444: disabled\\n\", __func__);\n                goto fail;\n            case FF_PROFILE_H264_HIGH_444_PREDICTIVE:\n                ALOGW(\"%s: MediaCodec: H264_HIGH_444_PREDICTIVE: disabled\\n\", __func__);\n                goto fail;\n            case FF_PROFILE_H264_HIGH_444_INTRA:\n                ALOGW(\"%s: MediaCodec: H264_HIGH_444_INTRA: disabled\\n\", __func__);\n                goto fail;\n            case FF_PROFILE_H264_CAVLC_444:\n                ALOGW(\"%s: MediaCodec: H264_CAVLC_444: disabled\\n\", __func__);\n                goto fail;\n            default:\n                ALOGW(\"%s: MediaCodec: (%d) unknown profile: disabled\\n\", __func__, opaque->codecpar->profile);\n                goto fail;\n        }\n        strcpy(opaque->mcc.mime_type, SDL_AMIME_VIDEO_AVC);\n        opaque->mcc.profile = opaque->codecpar->profile;\n        opaque->mcc.level   = opaque->codecpar->level;\n        break;\n    case AV_CODEC_ID_HEVC:\n        if (!ffp->mediacodec_hevc && !ffp->mediacodec_all_videos) {\n            ALOGE(\"%s: MediaCodec/HEVC is disabled. codec_id:%d \\n\", __func__, opaque->codecpar->codec_id);\n            goto fail;\n        }\n        strcpy(opaque->mcc.mime_type, SDL_AMIME_VIDEO_HEVC);\n        opaque->mcc.profile = opaque->codecpar->profile;\n        opaque->mcc.level   = opaque->codecpar->level;\n        break;\n    case AV_CODEC_ID_MPEG2VIDEO:\n        if (!ffp->mediacodec_mpeg2 && !ffp->mediacodec_all_videos) {\n            ALOGE(\"%s: MediaCodec/MPEG2VIDEO is disabled. codec_id:%d \\n\", __func__, opaque->codecpar->codec_id);\n            goto fail;\n        }\n        strcpy(opaque->mcc.mime_type, SDL_AMIME_VIDEO_MPEG2VIDEO);\n        opaque->mcc.profile = opaque->codecpar->profile;\n        opaque->mcc.level   = opaque->codecpar->level;\n        break;\n    case AV_CODEC_ID_MPEG4:\n        if (!ffp->mediacodec_mpeg4 && !ffp->mediacodec_all_videos) {\n            ALOGE(\"%s: MediaCodec/MPEG4 is disabled. codec_id:%d \\n\", __func__, opaque->codecpar->codec_id);\n            goto fail;\n        }\n        if ((opaque->codecpar->codec_tag & 0x0000FFFF) == 0x00005844) {\n            ALOGE(\"%s: divx is not supported \\n\", __func__);\n            goto fail;\n        }\n        strcpy(opaque->mcc.mime_type, SDL_AMIME_VIDEO_MPEG4);\n        opaque->mcc.profile = opaque->codecpar->profile >= 0 ? opaque->codecpar->profile : 0;\n        opaque->mcc.level   = opaque->codecpar->level >= 0 ? opaque->codecpar->level : 1;\n        break;\n\n    default:\n        ALOGE(\"%s:create: not H264 or H265/HEVC, codec_id:%d \\n\", __func__, opaque->codecpar->codec_id);\n        goto fail;\n    }\n\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"%s:create: SetupThreadEnv failed\\n\", __func__);\n        goto fail;\n    }\n\n    opaque->acodec_mutex                      = SDL_CreateMutex();\n    opaque->acodec_cond                       = SDL_CreateCond();\n    opaque->acodec_first_dequeue_output_mutex = SDL_CreateMutex();\n    opaque->acodec_first_dequeue_output_cond  = SDL_CreateCond();\n    opaque->any_input_mutex                   = SDL_CreateMutex();\n    opaque->any_input_cond                    = SDL_CreateCond();\n\n    if (!opaque->acodec_cond || !opaque->acodec_cond || !opaque->acodec_first_dequeue_output_mutex || !opaque->acodec_first_dequeue_output_cond) {\n        ALOGE(\"%s:open_video_decoder: SDL_CreateCond() failed\\n\", __func__);\n        goto fail;\n    }\n\n    ret = recreate_format_l(env, node);\n    if (ret) {\n        ALOGE(\"amc: recreate_format_l failed\\n\");\n        goto fail;\n    }\n\n    if (!ffpipeline_select_mediacodec_l(pipeline, &opaque->mcc) || !opaque->mcc.codec_name[0]) {\n        ALOGE(\"amc: no suitable codec\\n\");\n        goto fail;\n    }\n\n    jsurface = ffpipeline_get_surface_as_global_ref(env, pipeline);\n    ret = reconfigure_codec_l(env, node, jsurface);\n    J4A_DeleteGlobalRef__p(env, &jsurface);\n    if (ret != 0)\n        goto fail;\n\n    ffp_set_video_codec_info(ffp, MEDIACODEC_MODULE_NAME, opaque->mcc.codec_name);\n\n    opaque->off_buf_out = 0;\n    if (opaque->n_buf_out) {\n        int i;\n\n        opaque->amc_buf_out = calloc(opaque->n_buf_out, sizeof(*opaque->amc_buf_out));\n        assert(opaque->amc_buf_out != NULL);\n        for (i = 0; i < opaque->n_buf_out; i++)\n            opaque->amc_buf_out[i].pts = AV_NOPTS_VALUE;\n    }\n\n    SDL_SpeedSamplerReset(&opaque->sampler);\n    ffp->stat.vdec_type = FFP_PROPV_DECODER_MEDIACODEC;\n    return node;\nfail:\n    ffpipenode_free_p(&node);\n    return NULL;\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/android/pipeline/ffpipenode_android_mediacodec_vdec.h",
    "content": "/*\n * ffpipenode_android_mediacodec_vdec.h\n *\n * Copyright (c) 2014 Bilibili\n * Copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef FFPLAY__FF_FFPIPENODE_ANDROID_MEDIACODEC_VDEC_H\n#define FFPLAY__FF_FFPIPENODE_ANDROID_MEDIACODEC_VDEC_H\n\n#include \"../../ff_ffpipenode.h\"\n#include \"../../ff_ffpipeline.h\"\n#include \"ijksdl/ijksdl_vout.h\"\n\ntypedef struct FFPlayer FFPlayer;\n\nIJKFF_Pipenode *ffpipenode_create_video_decoder_from_android_mediacodec(FFPlayer *ffp, IJKFF_Pipeline *pipeline, SDL_Vout *vout);\nIJKFF_Pipenode *ffpipenode_init_decoder_from_android_mediacodec(FFPlayer *ffp, IJKFF_Pipeline *pipeline, SDL_Vout *vout);\nint ffpipenode_config_from_android_mediacodec(FFPlayer *ffp, IJKFF_Pipeline *pipeline, SDL_Vout *vout, IJKFF_Pipenode *node);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/android/pipeline/h264_nal.h",
    "content": "/*\n * h264_nal.h\n *\n * Copyright (c) 2010-2011 Bilibili\n * Copyright (c) 2010-2011 Jean-Baptiste Kempf <jb@videolan.org>\n * Copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include <limits.h>\n#include \"libavcodec/avcodec.h\"\n#include \"ijksdl/ijksdl_log.h\"\n#if 1\n/* Parse the SPS/PPS Metadata and convert it to annex b format */\nstatic int convert_sps_pps( const uint8_t *p_buf, size_t i_buf_size,\n                            uint8_t *p_out_buf, size_t i_out_buf_size,\n                            size_t *p_sps_pps_size, size_t *p_nal_size)\n{\n    // int i_profile;\n    uint32_t i_data_size = i_buf_size, i_nal_size, i_sps_pps_size = 0;\n    unsigned int i_loop_end;\n\n    /* */\n    if( i_data_size < 7 )\n    {\n        ALOGE( \"Input Metadata too small\" );\n        return -1;\n    }\n\n    /* Read infos in first 6 bytes */\n    // i_profile    = (p_buf[1] << 16) | (p_buf[2] << 8) | p_buf[3];\n    if (p_nal_size)\n        *p_nal_size  = (p_buf[4] & 0x03) + 1;\n    p_buf       += 5;\n    i_data_size -= 5;\n\n    for ( unsigned int j = 0; j < 2; j++ )\n    {\n        /* First time is SPS, Second is PPS */\n        if( i_data_size < 1 )\n        {\n            ALOGE( \"PPS too small after processing SPS/PPS %u\",\n                    i_data_size );\n            return -1;\n        }\n        i_loop_end = p_buf[0] & (j == 0 ? 0x1f : 0xff);\n        p_buf++; i_data_size--;\n\n        for ( unsigned int i = 0; i < i_loop_end; i++)\n        {\n            if( i_data_size < 2 )\n            {\n                ALOGE( \"SPS is too small %u\", i_data_size );\n                return -1;\n            }\n\n            i_nal_size = (p_buf[0] << 8) | p_buf[1];\n            p_buf += 2;\n            i_data_size -= 2;\n\n            if( i_data_size < i_nal_size )\n            {\n                ALOGE( \"SPS size does not match NAL specified size %u\",\n                        i_data_size );\n                return -1;\n            }\n            if( i_sps_pps_size + 4 + i_nal_size > i_out_buf_size )\n            {\n                ALOGE( \"Output SPS/PPS buffer too small\" );\n                return -1;\n            }\n\n            p_out_buf[i_sps_pps_size++] = 0;\n            p_out_buf[i_sps_pps_size++] = 0;\n            p_out_buf[i_sps_pps_size++] = 0;\n            p_out_buf[i_sps_pps_size++] = 1;\n\n            memcpy( p_out_buf + i_sps_pps_size, p_buf, i_nal_size );\n            i_sps_pps_size += i_nal_size;\n\n            p_buf += i_nal_size;\n            i_data_size -= i_nal_size;\n        }\n    }\n\n    *p_sps_pps_size = i_sps_pps_size;\n\n    return 0;\n}\n#endif\n#if 1\n/* Convert H.264 NAL format to annex b in-place */\ntypedef struct H264ConvertState {\n    uint32_t nal_len;\n    uint32_t nal_pos;\n} H264ConvertState;\n\nstatic void convert_h264_to_annexb( uint8_t *p_buf, size_t i_len,\n                                    size_t i_nal_size,\n                                    H264ConvertState *state )\n{\n    if( i_nal_size < 3 || i_nal_size > 4 )\n        return;\n\n    /* This only works for NAL sizes 3-4 */\n    while( i_len > 0 )\n    {\n        if( state->nal_pos < i_nal_size ) {\n            unsigned int i;\n            for( i = 0; state->nal_pos < i_nal_size && i < i_len; i++, state->nal_pos++ ) {\n                state->nal_len = (state->nal_len << 8) | p_buf[i];\n                p_buf[i] = 0;\n            }\n            if( state->nal_pos < i_nal_size )\n                return;\n            p_buf[i - 1] = 1;\n            p_buf += i;\n            i_len -= i;\n        }\n        if( state->nal_len > INT_MAX )\n            return;\n        if( state->nal_len > i_len )\n        {\n            state->nal_len -= i_len;\n            return;\n        }\n        else\n        {\n            p_buf += state->nal_len;\n            i_len -= state->nal_len;\n            state->nal_len = 0;\n            state->nal_pos = 0;\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/android/pipeline/hevc_nal.h",
    "content": "/*\n * hevc_nal.h\n * \n * Copyright (c) 2015 Chodison Chen <c_soft_dev@163.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include <limits.h>\n#include \"libavcodec/avcodec.h\"\n#include \"ijksdl/ijksdl_log.h\"\n\n/* Inspired by libavcodec/hevc.c */\nint convert_hevc_nal_units(const uint8_t *p_buf,size_t i_buf_size,\n                           uint8_t *p_out_buf,size_t i_out_buf_size,\n                           size_t *p_sps_pps_size,size_t *p_nal_size)\n{\n    int i, num_arrays;\n    const uint8_t *p_end = p_buf + i_buf_size;\n    uint32_t i_sps_pps_size = 0;\n\n    if( i_buf_size <= 3 || ( !p_buf[0] && !p_buf[1] && p_buf[2] <= 1 ) )\n        return -1;\n\n    if( p_end - p_buf < 23 )\n    {\n        ALOGE( \"Input Metadata too small\" );\n        return -1;\n    }\n\n    p_buf += 21;\n\n    if( p_nal_size )\n        *p_nal_size = (*p_buf & 0x03) + 1;\n    p_buf++;\n\n    num_arrays = *p_buf++;\n\n    for( i = 0; i < num_arrays; i++ )\n    {\n        int type, cnt, j;\n\n        if( p_end - p_buf < 3 )\n        {\n            ALOGE( \"Input Metadata too small\" );\n            return -1;\n        }\n        type = *(p_buf++) & 0x3f;\n        (void)(type);\n\n        cnt = p_buf[0] << 8 | p_buf[1];\n        p_buf += 2;\n\n        for( j = 0; j < cnt; j++ )\n        {\n            int i_nal_size;\n\n            if( p_end - p_buf < 2 )\n            {\n                ALOGE( \"Input Metadata too small\" );\n                return -1;\n            }\n\n            i_nal_size = p_buf[0] << 8 | p_buf[1];\n            p_buf += 2;\n\n            if( i_nal_size < 0 || p_end - p_buf < i_nal_size )\n            {\n                ALOGE( \"NAL unit size does not match Input Metadata size\" );\n                return -1;\n            }\n\n            if( i_sps_pps_size + 4 + i_nal_size > i_out_buf_size )\n            {\n                ALOGE( \"Output buffer too small\" );\n                return -1;\n            }\n\n            p_out_buf[i_sps_pps_size++] = 0;\n            p_out_buf[i_sps_pps_size++] = 0;\n            p_out_buf[i_sps_pps_size++] = 0;\n            p_out_buf[i_sps_pps_size++] = 1;\n\n            memcpy(p_out_buf + i_sps_pps_size, p_buf, i_nal_size);\n            p_buf += i_nal_size;\n\n            i_sps_pps_size += i_nal_size;\n        }\n    }\n\n    *p_sps_pps_size = i_sps_pps_size;\n\n    return 0;\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/android/pipeline/mpeg4_esds.h",
    "content": "/*\n * mpeg4_esds.h\n * \n * Copyright (c) 2015 yuazhen <zhengyuan10503@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include <limits.h>\n#include <stdint.h>\n#include \"libavcodec/avcodec.h\"\n\nstatic void restore_mpeg4_esds(AVCodecParameters *codecpar,\n                                 uint8_t *p_buf, size_t i_buf_size,\n                                 size_t i_es_dscr_length, size_t i_dec_dscr_length,\n                                 uint8_t *p_esds_buf)\n{\n    p_esds_buf[0] = 0x03;\n    p_esds_buf[1] = 0x80;\n    p_esds_buf[2] = 0x80;\n    p_esds_buf[3] = 0x80;\n    p_esds_buf[4] = i_es_dscr_length;\n    uint16_t *es_id = (uint16_t *)&p_esds_buf[5];\n    *es_id = htobe16(1);\n    \n    p_esds_buf[8] = 0x04;\n    p_esds_buf[9] = 0x80;\n    p_esds_buf[10] = 0x80;\n    p_esds_buf[11] = 0x80;\n    p_esds_buf[12] = i_dec_dscr_length;\n    p_esds_buf[13] = 0x20;\n    p_esds_buf[14] = 0x11;\n    uint32_t *max_br = (uint32_t *)&p_esds_buf[18];\n    uint32_t *avg_br = (uint32_t *)&p_esds_buf[22];\n    *max_br = *avg_br = htobe32(codecpar->bit_rate);\n\n    p_esds_buf[26] = 0x05;\n    p_esds_buf[27] = 0x80;\n    p_esds_buf[28] = 0x80;\n    p_esds_buf[29] = 0x80;\n    p_esds_buf[30] = i_buf_size;\n    memcpy(&p_esds_buf[31], p_buf, i_buf_size);\n\n    p_esds_buf[31+i_buf_size] = 0x06;\n    p_esds_buf[31+i_buf_size+1] = 0x80;\n    p_esds_buf[31+i_buf_size+2] = 0x80;\n    p_esds_buf[31+i_buf_size+3] = 0x80;\n    p_esds_buf[31+i_buf_size+4] = 0x01;\n    p_esds_buf[31+i_buf_size+5] = 0x02;\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/config.h",
    "content": "/*\n * Copyright (c) 2015 Bilibili\n * Copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef FFPLAY__CONFIG_H\n#define FFPLAY__CONFIG_H\n\n#include \"libffmpeg/config.h\"\n\n// FIXME: merge filter related code and enable it\n// remove these lines to enable avfilter\n#ifdef CONFIG_AVFILTER\n#undef CONFIG_AVFILTER\n#endif\n#define CONFIG_AVFILTER 0\n\n#ifdef FFP_MERGE\n#undef FFP_MERGE\n#endif\n\n#ifdef FFP_SUB\n#undef FFP_SUB\n#endif\n\n#ifndef FFMPEG_LOG_TAG\n#define FFMPEG_LOG_TAG \"IJKFFMPEG\"\n#endif\n\n#endif//FFPLAY__CONFIG_H\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ff_cmdutils.c",
    "content": "/*\n * ff_cmdutils.c\n *      based on ffmpeg/cmdutils.c\n *\n * Copyright (c) 2000-2003 Bilibili\n * Copyright (c) 2000-2003 Fabrice Bellard\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ff_cmdutils.h\"\n\n#include \"libavutil/display.h\"\n#include \"libavutil/eval.h\"\n\n// MERGE: sws_opts\n// MERGE: swr_opts\n// MERGE: format_opts, codec_opts, resample_opts\n// MERGE: this_year\n// MERGE: report_file;\n// MERGE: init_opts\n// MERGE: uninit_opts\n// MERGE: log_callback_help\n// MERGE: log_callback_report(void *ptr, int level, const char *fmt, va_list vl)\n// MERGE: parse_number_or_die\n// MERGE: parse_time_or_die\n// MERGE: show_help_options\n// MERGE: show_help_children\n// MERGE: find_option\n// MERGE: #include <windows.h>\n// MERGE: #include <shellapi.h>\n// MERGE: win32_argv_utf8\n// MERGE: win32_argc\n// MERGE: prepare_app_arguments\n// MERGE: write_option\n// MERGE: parse_option\n// MERGE: parse_options\n// MERGE: parse_optgroup\n// MERGE: locate_option\n// MERGE: dump_argument\n// MERGE: parse_loglevel\n// MERGE: #define FLAGS\n// MERGE: opt_default\n// MERGE: match_group_separator\n// MERGE: finish_group\n// MERGE: add_opt\n// MERGE: init_parse_context\n// MERGE: uninit_parse_context\n// MERGE: split_commandline\n// MERGE: opt_loglevel\n// MERGE: expand_filename_template\n// MERGE: init_report\n// MERGE: opt_report\n// MERGE: opt_max_alloc\n// MERGE: opt_cpuflags\n// MERGE: opt_timelimit\n\nvoid print_error(const char *filename, int err)\n{\n    char errbuf[128];\n    const char *errbuf_ptr = errbuf;\n\n    if (av_strerror(err, errbuf, sizeof(errbuf)) < 0)\n        errbuf_ptr = strerror(AVUNERROR(err));\n    av_log(NULL, AV_LOG_ERROR, \"%s: %s\\n\", filename, errbuf_ptr);\n}\n\n// MERGE: warned_cfg\n// MERGE: INDENT\n// MERGE: SHOW_VERSION\n// MERGE: SHOW_CONFIG\n// MERGE: SHOW_COPYRIGHT\n// MERGE: PRINT_LIB_INFO\n// MERGE: print_all_libs_info\n// MERGE: print_program_info\n// MERGE: show_banner\n// MERGE: show_version\n// MERGE: show_license\n// MERGE: show_formats\n// MERGE: PRINT_CODEC_SUPPORTED\n// MERGE: print_codec\n// MERGE: get_media_type_char\n// MERGE: next_codec_for_id\n// MERGE: compare_codec_desc\n// MERGE: get_codecs_sorted\n// MERGE: print_codecs_for_id\n// MERGE: show_codecs\n// MERGE: print_codecs\n// MERGE: show_decoders\n// MERGE: show_encoders\n// MERGE: show_bsfs\n// MERGE: show_protocols\n// MERGE: show_filters\n// MERGE: show_pix_fmts\n// MERGE: show_layouts\n// MERGE: show_sample_fmts\n// MERGE: show_help_codec\n// MERGE: show_help_demuxer\n// MERGE: show_help_muxer\n// MERGE: show_help\n// MERGE: read_yesno\n// MERGE: cmdutils_read_file\n// MERGE: get_preset_file\n\nstatic int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec)\n{\n    int ret = avformat_match_stream_specifier(s, st, spec);\n    if (ret < 0)\n        av_log(s, AV_LOG_ERROR, \"Invalid stream specifier: %s.\\n\", spec);\n    return ret;\n}\n\nAVDictionary *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id,\n                                AVFormatContext *s, AVStream *st, AVCodec *codec)\n{\n    AVDictionary    *ret = NULL;\n    AVDictionaryEntry *t = NULL;\n    int            flags = s->oformat ? AV_OPT_FLAG_ENCODING_PARAM\n                                      : AV_OPT_FLAG_DECODING_PARAM;\n    char          prefix = 0;\n    const AVClass    *cc = avcodec_get_class();\n\n    if (!codec)\n        codec            = s->oformat ? avcodec_find_encoder(codec_id)\n                                      : avcodec_find_decoder(codec_id);\n\n    switch (st->codecpar->codec_type) {\n    case AVMEDIA_TYPE_VIDEO:\n        prefix  = 'v';\n        flags  |= AV_OPT_FLAG_VIDEO_PARAM;\n        break;\n    case AVMEDIA_TYPE_AUDIO:\n        prefix  = 'a';\n        flags  |= AV_OPT_FLAG_AUDIO_PARAM;\n        break;\n    case AVMEDIA_TYPE_SUBTITLE:\n        prefix  = 's';\n        flags  |= AV_OPT_FLAG_SUBTITLE_PARAM;\n        break;\n    default:\n        break;\n    }\n\n    while ((t = av_dict_get(opts, \"\", t, AV_DICT_IGNORE_SUFFIX))) {\n        char *p = strchr(t->key, ':');\n\n        /* check stream specification in opt name */\n        if (p)\n            switch (check_stream_specifier(s, st, p + 1)) {\n            case  1: *p = 0; break;\n            case  0:         continue;\n            default:         return NULL;\n            }\n\n        if (av_opt_find(&cc, t->key, NULL, flags, AV_OPT_SEARCH_FAKE_OBJ) ||\n            (codec && codec->priv_class &&\n             av_opt_find(&codec->priv_class, t->key, NULL, flags,\n                         AV_OPT_SEARCH_FAKE_OBJ)))\n            av_dict_set(&ret, t->key, t->value, 0);\n        else if (t->key[0] == prefix &&\n                 av_opt_find(&cc, t->key + 1, NULL, flags,\n                             AV_OPT_SEARCH_FAKE_OBJ))\n            av_dict_set(&ret, t->key + 1, t->value, 0);\n\n        if (p)\n            *p = ':';\n    }\n    return ret;\n}\n\nAVDictionary **setup_find_stream_info_opts(AVFormatContext *s,\n                                           AVDictionary *codec_opts)\n{\n    int i;\n    AVDictionary **opts;\n\n    if (!s->nb_streams)\n        return NULL;\n    opts = av_mallocz(s->nb_streams * sizeof(*opts));\n    if (!opts) {\n        av_log(NULL, AV_LOG_ERROR,\n               \"Could not alloc memory for stream options.\\n\");\n        return NULL;\n    }\n    for (i = 0; i < s->nb_streams; i++)\n        opts[i] = filter_codec_opts(codec_opts, s->streams[i]->codecpar->codec_id,\n                                    s, s->streams[i], NULL);\n    return opts;\n}\n\nvoid *grow_array(void *array, int elem_size, int *size, int new_size)\n{\n    if (new_size >= INT_MAX / elem_size) {\n        av_log(NULL, AV_LOG_ERROR, \"Array too big.\\n\");\n        return NULL;\n    }\n    if (*size < new_size) {\n        uint8_t *tmp = av_realloc_array(array, new_size, elem_size);\n        if (!tmp) {\n            av_log(NULL, AV_LOG_ERROR, \"Could not alloc buffer.\\n\");\n            return NULL;\n        }\n        memset(tmp + *size*elem_size, 0, (new_size-*size) * elem_size);\n        *size = new_size;\n        return tmp;\n    }\n    return array;\n}\n\ndouble get_rotation(AVStream *st)\n{\n    AVDictionaryEntry *rotate_tag = av_dict_get(st->metadata, \"rotate\", NULL, 0);\n    uint8_t* displaymatrix = av_stream_get_side_data(st,\n                                                     AV_PKT_DATA_DISPLAYMATRIX, NULL);\n    double theta = 0;\n\n    if (rotate_tag && *rotate_tag->value && strcmp(rotate_tag->value, \"0\")) {\n        char *tail;\n        theta = av_strtod(rotate_tag->value, &tail);\n        if (*tail)\n            theta = 0;\n    }\n    if (displaymatrix && !theta)\n        theta = -av_display_rotation_get((int32_t*) displaymatrix);\n\n    theta -= 360*floor(theta/360 + 0.9/360);\n\n    if (fabs(theta - 90*round(theta/90)) > 2)\n        av_log(NULL, AV_LOG_WARNING, \"Odd rotation angle.\\n\"\n               \"If you want to help, upload a sample \"\n               \"of this file to ftp://upload.ffmpeg.org/incoming/ \"\n               \"and contact the ffmpeg-devel mailing list. (ffmpeg-devel@ffmpeg.org)\");\n\n    return theta;\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ff_cmdutils.h",
    "content": "/*\n * ff_cmdutils.h\n *      based on ffmpeg/cmdutils.h\n *\n * Copyright (c) 2000-2003 Bilibili\n * Copyright (c) 2000-2003 Fabrice Bellard\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef FFPLAY__FF_CMDUTILS_H\n#define FFPLAY__FF_CMDUTILS_H\n\n#include \"ff_ffinc.h\"\n\nvoid            print_error(const char *filename, int err);\nAVDictionary  **setup_find_stream_info_opts(AVFormatContext *s, AVDictionary *codec_opts);\nAVDictionary   *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id,\n                                  AVFormatContext *s, AVStream *st, AVCodec *codec);\n/**\n * Realloc array to hold new_size elements of elem_size.\n * Calls exit() on failure.\n *\n * @param array array to reallocate\n * @param elem_size size in bytes of each element\n * @param size new element count will be written here\n * @param new_size number of elements to place in reallocated array\n * @return reallocated array\n */\nvoid *grow_array(void *array, int elem_size, int *size, int new_size);\n\n#define GROW_ARRAY(array, nb_elems)\\\n    array = grow_array(array, sizeof(*array), &nb_elems, nb_elems + 1)\n\ndouble          get_rotation(AVStream *st);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ff_fferror.h",
    "content": "/*\n * ff_fferror.h\n *\n * Copyright (c) 2003 Bilibili\n * Copyright (c) 2003 Fabrice Bellard\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef FFPLAY__FF_FFERROR_H\n#define FFPLAY__FF_FFERROR_H\n\n#define EIJK_FAILED             -1\n#define EIJK_OUT_OF_MEMORY      -2\n#define EIJK_INVALID_STATE      -3\n#define EIJK_NULL_IS_PTR        -4\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ff_ffinc.h",
    "content": "/*\n * ff_ffinc.h\n *      ffmpeg headers\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef FFPLAY__FF_FFINC_H\n#define FFPLAY__FF_FFINC_H\n\n#include <stdbool.h>\n#include <assert.h>\n#include \"libavutil/avstring.h\"\n#include \"libavutil/time.h\"\n#include \"libavformat/avformat.h\"\n#include \"libavcodec/avfft.h\"\n#include \"libswscale/swscale.h\"\n#include \"libavutil/application.h\"\n#include \"libavutil/base64.h\"\n#include \"libavutil/error.h\"\n#include \"libavutil/opt.h\"\n#include \"libavutil/version.h\"\n#include \"libswresample/swresample.h\"\n\n#include \"ijksdl/ijksdl.h\"\n\ntypedef int (*ijk_inject_callback)(void *opaque, int type, void *data, size_t data_size);\n\n#define FFP_OPT_CATEGORY_FORMAT 1\n#define FFP_OPT_CATEGORY_CODEC  2\n#define FFP_OPT_CATEGORY_SWS    3\n#define FFP_OPT_CATEGORY_PLAYER 4\n#define FFP_OPT_CATEGORY_SWR    5\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ff_ffmsg.h",
    "content": "/*\n * ff_ffmsg.h\n *      based on PacketQueue in ffplay.c\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef FFPLAY__FF_FFMSG_H\n#define FFPLAY__FF_FFMSG_H\n\n#define FFP_MSG_FLUSH                       0\n#define FFP_MSG_ERROR                       100     /* arg1 = error */\n#define FFP_MSG_PREPARED                    200\n#define FFP_MSG_COMPLETED                   300\n#define FFP_MSG_VIDEO_SIZE_CHANGED          400     /* arg1 = width, arg2 = height */\n#define FFP_MSG_SAR_CHANGED                 401     /* arg1 = sar.num, arg2 = sar.den */\n#define FFP_MSG_VIDEO_RENDERING_START       402\n#define FFP_MSG_AUDIO_RENDERING_START       403\n#define FFP_MSG_VIDEO_ROTATION_CHANGED      404     /* arg1 = degree */\n#define FFP_MSG_AUDIO_DECODED_START         405\n#define FFP_MSG_VIDEO_DECODED_START         406\n#define FFP_MSG_OPEN_INPUT                  407\n#define FFP_MSG_FIND_STREAM_INFO            408\n#define FFP_MSG_COMPONENT_OPEN              409\n#define FFP_MSG_VIDEO_SEEK_RENDERING_START  410\n#define FFP_MSG_AUDIO_SEEK_RENDERING_START  411\n\n#define FFP_MSG_BUFFERING_START             500\n#define FFP_MSG_BUFFERING_END               501\n#define FFP_MSG_BUFFERING_UPDATE            502     /* arg1 = buffering head position in time, arg2 = minimum percent in time or bytes */\n#define FFP_MSG_BUFFERING_BYTES_UPDATE      503     /* arg1 = cached data in bytes,            arg2 = high water mark */\n#define FFP_MSG_BUFFERING_TIME_UPDATE       504     /* arg1 = cached duration in milliseconds, arg2 = high water mark */\n#define FFP_MSG_SEEK_COMPLETE               600     /* arg1 = seek position,                   arg2 = error */\n#define FFP_MSG_PLAYBACK_STATE_CHANGED      700\n#define FFP_MSG_TIMED_TEXT                  800\n#define FFP_MSG_ACCURATE_SEEK_COMPLETE      900     /* arg1 = current position*/\n#define FFP_MSG_GET_IMG_STATE               1000    /* arg1 = timestamp, arg2 = result code, obj = file name*/\n\n#define FFP_MSG_VIDEO_DECODER_OPEN          10001\n\n#define FFP_REQ_START                       20001\n#define FFP_REQ_PAUSE                       20002\n#define FFP_REQ_SEEK                        20003\n\n#define FFP_PROP_FLOAT_VIDEO_DECODE_FRAMES_PER_SECOND   10001\n#define FFP_PROP_FLOAT_VIDEO_OUTPUT_FRAMES_PER_SECOND   10002\n#define FFP_PROP_FLOAT_PLAYBACK_RATE                    10003\n#define FFP_PROP_FLOAT_PLAYBACK_VOLUME                  10006\n#define FFP_PROP_FLOAT_AVDELAY                          10004\n#define FFP_PROP_FLOAT_AVDIFF                           10005\n#define FFP_PROP_FLOAT_DROP_FRAME_RATE                  10007\n\n#define FFP_PROP_INT64_SELECTED_VIDEO_STREAM            20001\n#define FFP_PROP_INT64_SELECTED_AUDIO_STREAM            20002\n#define FFP_PROP_INT64_SELECTED_TIMEDTEXT_STREAM        20011\n#define FFP_PROP_INT64_VIDEO_DECODER                    20003\n#define FFP_PROP_INT64_AUDIO_DECODER                    20004\n#define     FFP_PROPV_DECODER_UNKNOWN                   0\n#define     FFP_PROPV_DECODER_AVCODEC                   1\n#define     FFP_PROPV_DECODER_MEDIACODEC                2\n#define     FFP_PROPV_DECODER_VIDEOTOOLBOX              3\n#define FFP_PROP_INT64_VIDEO_CACHED_DURATION            20005\n#define FFP_PROP_INT64_AUDIO_CACHED_DURATION            20006\n#define FFP_PROP_INT64_VIDEO_CACHED_BYTES               20007\n#define FFP_PROP_INT64_AUDIO_CACHED_BYTES               20008\n#define FFP_PROP_INT64_VIDEO_CACHED_PACKETS             20009\n#define FFP_PROP_INT64_AUDIO_CACHED_PACKETS             20010\n\n#define FFP_PROP_INT64_BIT_RATE                         20100\n\n#define FFP_PROP_INT64_TCP_SPEED                        20200\n\n#define FFP_PROP_INT64_ASYNC_STATISTIC_BUF_BACKWARDS    20201\n#define FFP_PROP_INT64_ASYNC_STATISTIC_BUF_FORWARDS     20202\n#define FFP_PROP_INT64_ASYNC_STATISTIC_BUF_CAPACITY     20203\n#define FFP_PROP_INT64_TRAFFIC_STATISTIC_BYTE_COUNT     20204\n\n#define FFP_PROP_INT64_LATEST_SEEK_LOAD_DURATION        20300\n\n#define FFP_PROP_INT64_CACHE_STATISTIC_PHYSICAL_POS     20205\n\n#define FFP_PROP_INT64_CACHE_STATISTIC_FILE_FORWARDS    20206\n\n#define FFP_PROP_INT64_CACHE_STATISTIC_FILE_POS         20207\n\n#define FFP_PROP_INT64_CACHE_STATISTIC_COUNT_BYTES      20208\n\n#define FFP_PROP_INT64_LOGICAL_FILE_SIZE                20209\n#define FFP_PROP_INT64_SHARE_CACHE_DATA                 20210\n#define FFP_PROP_INT64_IMMEDIATE_RECONNECT              20211\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ff_ffmsg_queue.h",
    "content": "/*\n * ff_ffmsg_queue.h\n *      based on PacketQueue in ffplay.c\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef FFPLAY__FF_FFMSG_QUEUE_H\n#define FFPLAY__FF_FFMSG_QUEUE_H\n\n#include \"ff_ffinc.h\"\n#include \"ff_ffmsg.h\"\n\n// #define FFP_SHOW_MSG_RECYCLE\n\ntypedef struct AVMessage {\n    int what;\n    int arg1;\n    int arg2;\n    void *obj;\n    void (*free_l)(void *obj);\n    struct AVMessage *next;\n} AVMessage;\n\ntypedef struct MessageQueue {\n    AVMessage *first_msg, *last_msg;\n    int nb_messages;\n    int abort_request;\n    SDL_mutex *mutex;\n    SDL_cond *cond;\n\n    AVMessage *recycle_msg;\n    int recycle_count;\n    int alloc_count;\n} MessageQueue;\n\ninline static void msg_free_res(AVMessage *msg)\n{\n    if (!msg || !msg->obj)\n        return;\n    assert(msg->free_l);\n    msg->free_l(msg->obj);\n    msg->obj = NULL;\n}\n\ninline static int msg_queue_put_private(MessageQueue *q, AVMessage *msg)\n{\n    AVMessage *msg1;\n\n    if (q->abort_request)\n        return -1;\n\n#ifdef FFP_MERGE\n    msg1 = av_malloc(sizeof(AVMessage));\n#else\n    msg1 = q->recycle_msg;\n    if (msg1) {\n        q->recycle_msg = msg1->next;\n        q->recycle_count++;\n    } else {\n        q->alloc_count++;\n        msg1 = av_malloc(sizeof(AVMessage));\n    }\n#ifdef FFP_SHOW_MSG_RECYCLE\n    int total_count = q->recycle_count + q->alloc_count;\n    if (!(total_count % 10)) {\n        av_log(NULL, AV_LOG_DEBUG, \"msg-recycle \\t%d + \\t%d = \\t%d\\n\", q->recycle_count, q->alloc_count, total_count);\n    }\n#endif\n#endif\n    if (!msg1)\n        return -1;\n\n    *msg1 = *msg;\n    msg1->next = NULL;\n\n    if (!q->last_msg)\n        q->first_msg = msg1;\n    else\n        q->last_msg->next = msg1;\n    q->last_msg = msg1;\n    q->nb_messages++;\n    SDL_CondSignal(q->cond);\n    return 0;\n}\n\ninline static int msg_queue_put(MessageQueue *q, AVMessage *msg)\n{\n    int ret;\n\n    SDL_LockMutex(q->mutex);\n    ret = msg_queue_put_private(q, msg);\n    SDL_UnlockMutex(q->mutex);\n\n    return ret;\n}\n\ninline static void msg_init_msg(AVMessage *msg)\n{\n    memset(msg, 0, sizeof(AVMessage));\n}\n\ninline static void msg_queue_put_simple1(MessageQueue *q, int what)\n{\n    AVMessage msg;\n    msg_init_msg(&msg);\n    msg.what = what;\n    msg_queue_put(q, &msg);\n}\n\ninline static void msg_queue_put_simple2(MessageQueue *q, int what, int arg1)\n{\n    AVMessage msg;\n    msg_init_msg(&msg);\n    msg.what = what;\n    msg.arg1 = arg1;\n    msg_queue_put(q, &msg);\n}\n\ninline static void msg_queue_put_simple3(MessageQueue *q, int what, int arg1, int arg2)\n{\n    AVMessage msg;\n    msg_init_msg(&msg);\n    msg.what = what;\n    msg.arg1 = arg1;\n    msg.arg2 = arg2;\n    msg_queue_put(q, &msg);\n}\n\ninline static void msg_obj_free_l(void *obj)\n{\n    av_free(obj);\n}\n\ninline static void msg_queue_put_simple4(MessageQueue *q, int what, int arg1, int arg2, void *obj, int obj_len)\n{\n    AVMessage msg;\n    msg_init_msg(&msg);\n    msg.what = what;\n    msg.arg1 = arg1;\n    msg.arg2 = arg2;\n    msg.obj = av_malloc(obj_len);\n    memcpy(msg.obj, obj, obj_len);\n    msg.free_l = msg_obj_free_l;\n    msg_queue_put(q, &msg);\n}\n\ninline static void msg_queue_init(MessageQueue *q)\n{\n    memset(q, 0, sizeof(MessageQueue));\n    q->mutex = SDL_CreateMutex();\n    q->cond = SDL_CreateCond();\n    q->abort_request = 1;\n}\n\ninline static void msg_queue_flush(MessageQueue *q)\n{\n    AVMessage *msg, *msg1;\n\n    SDL_LockMutex(q->mutex);\n    for (msg = q->first_msg; msg != NULL; msg = msg1) {\n        msg1 = msg->next;\n#ifdef FFP_MERGE\n        av_freep(&msg);\n#else\n        msg->next = q->recycle_msg;\n        q->recycle_msg = msg;\n#endif\n    }\n    q->last_msg = NULL;\n    q->first_msg = NULL;\n    q->nb_messages = 0;\n    SDL_UnlockMutex(q->mutex);\n}\n\ninline static void msg_queue_destroy(MessageQueue *q)\n{\n    msg_queue_flush(q);\n\n    SDL_LockMutex(q->mutex);\n    while(q->recycle_msg) {\n        AVMessage *msg = q->recycle_msg;\n        if (msg)\n            q->recycle_msg = msg->next;\n        msg_free_res(msg);\n        av_freep(&msg);\n    }\n    SDL_UnlockMutex(q->mutex);\n\n    SDL_DestroyMutex(q->mutex);\n    SDL_DestroyCond(q->cond);\n}\n\ninline static void msg_queue_abort(MessageQueue *q)\n{\n    SDL_LockMutex(q->mutex);\n\n    q->abort_request = 1;\n\n    SDL_CondSignal(q->cond);\n\n    SDL_UnlockMutex(q->mutex);\n}\n\ninline static void msg_queue_start(MessageQueue *q)\n{\n    SDL_LockMutex(q->mutex);\n    q->abort_request = 0;\n\n    AVMessage msg;\n    msg_init_msg(&msg);\n    msg.what = FFP_MSG_FLUSH;\n    msg_queue_put_private(q, &msg);\n    SDL_UnlockMutex(q->mutex);\n}\n\n/* return < 0 if aborted, 0 if no msg and > 0 if msg.  */\ninline static int msg_queue_get(MessageQueue *q, AVMessage *msg, int block)\n{\n    AVMessage *msg1;\n    int ret;\n\n    SDL_LockMutex(q->mutex);\n\n    for (;;) {\n        if (q->abort_request) {\n            ret = -1;\n            break;\n        }\n\n        msg1 = q->first_msg;\n        if (msg1) {\n            q->first_msg = msg1->next;\n            if (!q->first_msg)\n                q->last_msg = NULL;\n            q->nb_messages--;\n            *msg = *msg1;\n            msg1->obj = NULL;\n#ifdef FFP_MERGE\n            av_free(msg1);\n#else\n            msg1->next = q->recycle_msg;\n            q->recycle_msg = msg1;\n#endif\n            ret = 1;\n            break;\n        } else if (!block) {\n            ret = 0;\n            break;\n        } else {\n            SDL_CondWait(q->cond, q->mutex);\n        }\n    }\n    SDL_UnlockMutex(q->mutex);\n    return ret;\n}\n\ninline static void msg_queue_remove(MessageQueue *q, int what)\n{\n    AVMessage **p_msg, *msg, *last_msg;\n    SDL_LockMutex(q->mutex);\n\n    last_msg = q->first_msg;\n\n    if (!q->abort_request && q->first_msg) {\n        p_msg = &q->first_msg;\n        while (*p_msg) {\n            msg = *p_msg;\n\n            if (msg->what == what) {\n                *p_msg = msg->next;\n#ifdef FFP_MERGE\n                av_free(msg);\n#else\n                msg_free_res(msg);\n                msg->next = q->recycle_msg;\n                q->recycle_msg = msg;\n#endif\n                q->nb_messages--;\n            } else {\n                last_msg = msg;\n                p_msg = &msg->next;\n            }\n        }\n\n        if (q->first_msg) {\n            q->last_msg = last_msg;\n        } else {\n            q->last_msg = NULL;\n        }\n    }\n\n    SDL_UnlockMutex(q->mutex);\n}\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ff_ffpipeline.c",
    "content": "/*\n * ff_ffpipeline.c\n *\n * Copyright (c) 2014 Bilibili\n * Copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ff_ffpipeline.h\"\n#include <stdlib.h>\n#include <string.h>\n\nIJKFF_Pipeline *ffpipeline_alloc(SDL_Class *opaque_class, size_t opaque_size)\n{\n    IJKFF_Pipeline *pipeline = (IJKFF_Pipeline*) calloc(1, sizeof(IJKFF_Pipeline));\n    if (!pipeline)\n        return NULL;\n\n    pipeline->opaque_class = opaque_class;\n    pipeline->opaque       = calloc(1, opaque_size);\n    if (!pipeline->opaque) {\n        free(pipeline);\n        return NULL;\n    }\n\n    return pipeline;\n}\n\nvoid ffpipeline_free(IJKFF_Pipeline *pipeline)\n{\n    if (!pipeline)\n        return;\n\n    if (pipeline->func_destroy) {\n        pipeline->func_destroy(pipeline);\n    }\n\n    free(pipeline->opaque);\n    memset(pipeline, 0, sizeof(IJKFF_Pipeline));\n    free(pipeline);\n}\n\nvoid ffpipeline_free_p(IJKFF_Pipeline **pipeline)\n{\n    if (!pipeline)\n        return;\n\n    ffpipeline_free(*pipeline);\n}\n\nIJKFF_Pipenode* ffpipeline_open_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp)\n{\n    return pipeline->func_open_video_decoder(pipeline, ffp);\n}\n\nIJKFF_Pipenode* ffpipeline_init_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp)\n{\n    return pipeline->func_init_video_decoder(pipeline, ffp);\n}\n\nint ffpipeline_config_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp)\n{\n    return pipeline->func_config_video_decoder(pipeline, ffp);\n}\n\nSDL_Aout *ffpipeline_open_audio_output(IJKFF_Pipeline *pipeline, FFPlayer *ffp)\n{\n    return pipeline->func_open_audio_output(pipeline, ffp);\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ff_ffpipeline.h",
    "content": "/*\n * ff_ffpipeline.h\n *\n * Copyright (c) 2014 Bilibili\n * Copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef FFPLAY__FF_FFPIPELINE_H\n#define FFPLAY__FF_FFPIPELINE_H\n\n#include \"ijksdl/ijksdl_class.h\"\n#include \"ijksdl/ijksdl_mutex.h\"\n#include \"ijksdl/ijksdl_aout.h\"\n#include \"ff_ffpipenode.h\"\n#include \"ff_ffplay_def.h\"\n\ntypedef struct IJKFF_Pipeline_Opaque IJKFF_Pipeline_Opaque;\ntypedef struct IJKFF_Pipeline IJKFF_Pipeline;\nstruct IJKFF_Pipeline {\n    SDL_Class             *opaque_class;\n    IJKFF_Pipeline_Opaque *opaque;\n\n    void            (*func_destroy)             (IJKFF_Pipeline *pipeline);\n    IJKFF_Pipenode *(*func_open_video_decoder)  (IJKFF_Pipeline *pipeline, FFPlayer *ffp);\n    SDL_Aout       *(*func_open_audio_output)   (IJKFF_Pipeline *pipeline, FFPlayer *ffp);\n    IJKFF_Pipenode *(*func_init_video_decoder)  (IJKFF_Pipeline *pipeline, FFPlayer *ffp);\n    int           (*func_config_video_decoder)  (IJKFF_Pipeline *pipeline, FFPlayer *ffp);\n};\n\nIJKFF_Pipeline *ffpipeline_alloc(SDL_Class *opaque_class, size_t opaque_size);\nvoid ffpipeline_free(IJKFF_Pipeline *pipeline);\nvoid ffpipeline_free_p(IJKFF_Pipeline **pipeline);\n\nIJKFF_Pipenode *ffpipeline_open_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp);\nSDL_Aout       *ffpipeline_open_audio_output(IJKFF_Pipeline *pipeline, FFPlayer *ffp);\n\nIJKFF_Pipenode* ffpipeline_init_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp);\nint ffpipeline_config_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ff_ffpipenode.c",
    "content": "/*\n * ff_ffpipeline_vdec.c\n *\n * Copyright (c) 2003 Bilibili\n * Copyright (c) 2003 Fabrice Bellard\n * Copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ff_ffpipenode.h\"\n#include <stdlib.h>\n#include <string.h>\n\nIJKFF_Pipenode *ffpipenode_alloc(size_t opaque_size)\n{\n    IJKFF_Pipenode *node = (IJKFF_Pipenode*) calloc(1, sizeof(IJKFF_Pipenode));\n    if (!node)\n        return NULL;\n\n    node->opaque = calloc(1, opaque_size);\n    if (!node->opaque) {\n        free(node);\n        return NULL;\n    }\n\n    node->mutex = SDL_CreateMutex();\n    if (node->mutex == NULL) {\n        free(node->opaque);\n        free(node);\n        return NULL;\n    }\n\n    return node;\n}\n\nvoid ffpipenode_free(IJKFF_Pipenode *node)\n{\n    if (!node)\n        return;\n\n    if (node->func_destroy) {\n        node->func_destroy(node);\n    }\n\n    SDL_DestroyMutexP(&node->mutex);\n\n    free(node->opaque);\n    memset(node, 0, sizeof(IJKFF_Pipenode));\n    free(node);\n}\n\nvoid ffpipenode_free_p(IJKFF_Pipenode **node)\n{\n    if (!node)\n        return;\n\n    ffpipenode_free(*node);\n    *node = NULL;\n}\n\nint ffpipenode_run_sync(IJKFF_Pipenode *node)\n{\n    return node->func_run_sync(node);\n}\n\nint ffpipenode_flush(IJKFF_Pipenode *node)\n{\n    if (!node || !node->func_flush)\n        return 0;\n\n    return node->func_flush(node);\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ff_ffpipenode.h",
    "content": "/*\n * ff_ffpipenode.h\n *\n * Copyright (c) 2014 Bilibili\n * Copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef FFPLAY__FF_FFPIPENODE_H\n#define FFPLAY__FF_FFPIPENODE_H\n\n#include \"ijksdl/ijksdl_mutex.h\"\n\ntypedef struct IJKFF_Pipenode_Opaque IJKFF_Pipenode_Opaque;\ntypedef struct IJKFF_Pipenode IJKFF_Pipenode;\nstruct IJKFF_Pipenode {\n    SDL_mutex *mutex;\n    void *opaque;\n\n    void (*func_destroy) (IJKFF_Pipenode *node);\n    int  (*func_run_sync)(IJKFF_Pipenode *node);\n    int  (*func_flush)   (IJKFF_Pipenode *node); // optional\n};\n\nIJKFF_Pipenode *ffpipenode_alloc(size_t opaque_size);\nvoid ffpipenode_free(IJKFF_Pipenode *node);\nvoid ffpipenode_free_p(IJKFF_Pipenode **node);\n\nint  ffpipenode_run_sync(IJKFF_Pipenode *node);\nint  ffpipenode_flush(IJKFF_Pipenode *node);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ff_ffplay.c",
    "content": "/*\n * Copyright (c) 2003 Bilibili\n * Copyright (c) 2003 Fabrice Bellard\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ff_ffplay.h\"\n\n/**\n * @file\n * simple media player based on the FFmpeg libraries\n */\n\n#include \"config.h\"\n#include <inttypes.h>\n#include <math.h>\n#include <limits.h>\n#include <signal.h>\n#include <stdint.h>\n#include <fcntl.h>\n#include <sys/types.h>\n#include <unistd.h>\n\n#include \"libavutil/avstring.h\"\n#include \"libavutil/eval.h\"\n#include \"libavutil/mathematics.h\"\n#include \"libavutil/pixdesc.h\"\n#include \"libavutil/imgutils.h\"\n#include \"libavutil/dict.h\"\n#include \"libavutil/parseutils.h\"\n#include \"libavutil/samplefmt.h\"\n#include \"libavutil/avassert.h\"\n#include \"libavutil/time.h\"\n#include \"libavformat/avformat.h\"\n#if CONFIG_AVDEVICE\n#include \"libavdevice/avdevice.h\"\n#endif\n#include \"libswscale/swscale.h\"\n#include \"libavutil/opt.h\"\n#include \"libavcodec/avfft.h\"\n#include \"libswresample/swresample.h\"\n\n#if CONFIG_AVFILTER\n# include \"libavcodec/avcodec.h\"\n# include \"libavfilter/avfilter.h\"\n# include \"libavfilter/buffersink.h\"\n# include \"libavfilter/buffersrc.h\"\n#endif\n\n#include \"ijksdl/ijksdl_log.h\"\n#include \"ijkavformat/ijkavformat.h\"\n#include \"ff_cmdutils.h\"\n#include \"ff_fferror.h\"\n#include \"ff_ffpipeline.h\"\n#include \"ff_ffpipenode.h\"\n#include \"ff_ffplay_debug.h\"\n#include \"ijkmeta.h\"\n#include \"ijkversion.h\"\n#include \"ijkplayer.h\"\n#include <stdatomic.h>\n#if defined(__ANDROID__)\n#include \"ijksoundtouch/ijksoundtouch_wrap.h\"\n#endif\n\n#ifndef AV_CODEC_FLAG2_FAST\n#define AV_CODEC_FLAG2_FAST CODEC_FLAG2_FAST\n#endif\n\n#ifndef AV_CODEC_CAP_DR1\n#define AV_CODEC_CAP_DR1 CODEC_CAP_DR1\n#endif\n\n// FIXME: 9 work around NDKr8e or gcc4.7 bug\n// isnan() may not recognize some double NAN, so we test both double and float\n#if defined(__ANDROID__)\n#ifdef isnan\n#undef isnan\n#endif\n#define isnan(x) (isnan((double)(x)) || isnanf((float)(x)))\n#endif\n\n#if defined(__ANDROID__)\n#define printf(...) ALOGD(__VA_ARGS__)\n#endif\n\n#define FFP_IO_STAT_STEP (50 * 1024)\n\n#define FFP_BUF_MSG_PERIOD (3)\n\n// static const AVOption ffp_context_options[] = ...\n#include \"ff_ffplay_options.h\"\n\nstatic AVPacket flush_pkt;\n\n#if CONFIG_AVFILTER\n// FFP_MERGE: opt_add_vfilter\n#endif\n\n#define IJKVERSION_GET_MAJOR(x)     ((x >> 16) & 0xFF)\n#define IJKVERSION_GET_MINOR(x)     ((x >>  8) & 0xFF)\n#define IJKVERSION_GET_MICRO(x)     ((x      ) & 0xFF)\n\n#if CONFIG_AVFILTER\nstatic inline\nint cmp_audio_fmts(enum AVSampleFormat fmt1, int64_t channel_count1,\n                   enum AVSampleFormat fmt2, int64_t channel_count2)\n{\n    /* If channel count == 1, planar and non-planar formats are the same */\n    if (channel_count1 == 1 && channel_count2 == 1)\n        return av_get_packed_sample_fmt(fmt1) != av_get_packed_sample_fmt(fmt2);\n    else\n        return channel_count1 != channel_count2 || fmt1 != fmt2;\n}\n\nstatic inline\nint64_t get_valid_channel_layout(int64_t channel_layout, int channels)\n{\n    if (channel_layout && av_get_channel_layout_nb_channels(channel_layout) == channels)\n        return channel_layout;\n    else\n        return 0;\n}\n#endif\n\nstatic void free_picture(Frame *vp);\n\nstatic int packet_queue_put_private(PacketQueue *q, AVPacket *pkt)\n{\n    MyAVPacketList *pkt1;\n\n    if (q->abort_request)\n       return -1;\n\n#ifdef FFP_MERGE\n    pkt1 = av_malloc(sizeof(MyAVPacketList));\n#else\n    pkt1 = q->recycle_pkt;\n    if (pkt1) {\n        q->recycle_pkt = pkt1->next;\n        q->recycle_count++;\n    } else {\n        q->alloc_count++;\n        pkt1 = av_malloc(sizeof(MyAVPacketList));\n    }\n#ifdef FFP_SHOW_PKT_RECYCLE\n    int total_count = q->recycle_count + q->alloc_count;\n    if (!(total_count % 50)) {\n        av_log(ffp, AV_LOG_DEBUG, \"pkt-recycle \\t%d + \\t%d = \\t%d\\n\", q->recycle_count, q->alloc_count, total_count);\n    }\n#endif\n#endif\n    if (!pkt1)\n        return -1;\n    pkt1->pkt = *pkt;\n    pkt1->next = NULL;\n    if (pkt == &flush_pkt)\n        q->serial++;\n    pkt1->serial = q->serial;\n\n    if (!q->last_pkt)\n        q->first_pkt = pkt1;\n    else\n        q->last_pkt->next = pkt1;\n    q->last_pkt = pkt1;\n    q->nb_packets++;\n    q->size += pkt1->pkt.size + sizeof(*pkt1);\n\n    q->duration += FFMAX(pkt1->pkt.duration, MIN_PKT_DURATION);\n\n    /* XXX: should duplicate packet data in DV case */\n    SDL_CondSignal(q->cond);\n    return 0;\n}\n\nstatic int packet_queue_put(PacketQueue *q, AVPacket *pkt)\n{\n    int ret;\n\n    SDL_LockMutex(q->mutex);\n    ret = packet_queue_put_private(q, pkt);\n    SDL_UnlockMutex(q->mutex);\n\n    if (pkt != &flush_pkt && ret < 0)\n        av_packet_unref(pkt);\n\n    return ret;\n}\n\nstatic int packet_queue_put_nullpacket(PacketQueue *q, int stream_index)\n{\n    AVPacket pkt1, *pkt = &pkt1;\n    av_init_packet(pkt);\n    pkt->data = NULL;\n    pkt->size = 0;\n    pkt->stream_index = stream_index;\n    return packet_queue_put(q, pkt);\n}\n\n/* packet queue handling */\nstatic int packet_queue_init(PacketQueue *q)\n{\n    memset(q, 0, sizeof(PacketQueue));\n    q->mutex = SDL_CreateMutex();\n    if (!q->mutex) {\n        av_log(NULL, AV_LOG_FATAL, \"SDL_CreateMutex(): %s\\n\", SDL_GetError());\n        return AVERROR(ENOMEM);\n    }\n    q->cond = SDL_CreateCond();\n    if (!q->cond) {\n        av_log(NULL, AV_LOG_FATAL, \"SDL_CreateCond(): %s\\n\", SDL_GetError());\n        return AVERROR(ENOMEM);\n    }\n    q->abort_request = 1;\n    return 0;\n}\n\nstatic void packet_queue_flush(PacketQueue *q)\n{\n    MyAVPacketList *pkt, *pkt1;\n\n    SDL_LockMutex(q->mutex);\n    for (pkt = q->first_pkt; pkt; pkt = pkt1) {\n        pkt1 = pkt->next;\n        av_packet_unref(&pkt->pkt);\n#ifdef FFP_MERGE\n        av_freep(&pkt);\n#else\n        pkt->next = q->recycle_pkt;\n        q->recycle_pkt = pkt;\n#endif\n    }\n    q->last_pkt = NULL;\n    q->first_pkt = NULL;\n    q->nb_packets = 0;\n    q->size = 0;\n    q->duration = 0;\n    SDL_UnlockMutex(q->mutex);\n}\n\nstatic void packet_queue_destroy(PacketQueue *q)\n{\n    packet_queue_flush(q);\n\n    SDL_LockMutex(q->mutex);\n    while(q->recycle_pkt) {\n        MyAVPacketList *pkt = q->recycle_pkt;\n        if (pkt)\n            q->recycle_pkt = pkt->next;\n        av_freep(&pkt);\n    }\n    SDL_UnlockMutex(q->mutex);\n\n    SDL_DestroyMutex(q->mutex);\n    SDL_DestroyCond(q->cond);\n}\n\nstatic void packet_queue_abort(PacketQueue *q)\n{\n    SDL_LockMutex(q->mutex);\n\n    q->abort_request = 1;\n\n    SDL_CondSignal(q->cond);\n\n    SDL_UnlockMutex(q->mutex);\n}\n\nstatic void packet_queue_start(PacketQueue *q)\n{\n    SDL_LockMutex(q->mutex);\n    q->abort_request = 0;\n    packet_queue_put_private(q, &flush_pkt);\n    SDL_UnlockMutex(q->mutex);\n}\n\n/* return < 0 if aborted, 0 if no packet and > 0 if packet.  */\nstatic int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block, int *serial)\n{\n    MyAVPacketList *pkt1;\n    int ret;\n\n    SDL_LockMutex(q->mutex);\n\n    for (;;) {\n        if (q->abort_request) {\n            ret = -1;\n            break;\n        }\n\n        pkt1 = q->first_pkt;\n        if (pkt1) {\n            q->first_pkt = pkt1->next;\n            if (!q->first_pkt)\n                q->last_pkt = NULL;\n            q->nb_packets--;\n            q->size -= pkt1->pkt.size + sizeof(*pkt1);\n            q->duration -= FFMAX(pkt1->pkt.duration, MIN_PKT_DURATION);\n            *pkt = pkt1->pkt;\n            if (serial)\n                *serial = pkt1->serial;\n#ifdef FFP_MERGE\n            av_free(pkt1);\n#else\n            pkt1->next = q->recycle_pkt;\n            q->recycle_pkt = pkt1;\n#endif\n            ret = 1;\n            break;\n        } else if (!block) {\n            ret = 0;\n            break;\n        } else {\n            SDL_CondWait(q->cond, q->mutex);\n        }\n    }\n    SDL_UnlockMutex(q->mutex);\n    return ret;\n}\n\nstatic int packet_queue_get_or_buffering(FFPlayer *ffp, PacketQueue *q, AVPacket *pkt, int *serial, int *finished)\n{\n    assert(finished);\n    if (!ffp->packet_buffering)\n        return packet_queue_get(q, pkt, 1, serial);\n\n    while (1) {\n        int new_packet = packet_queue_get(q, pkt, 0, serial);\n        if (new_packet < 0)\n            return -1;\n        else if (new_packet == 0) {\n            if (q->is_buffer_indicator && !*finished)\n                ffp_toggle_buffering(ffp, 1);\n            new_packet = packet_queue_get(q, pkt, 1, serial);\n            if (new_packet < 0)\n                return -1;\n        }\n\n        if (*finished == *serial) {\n            av_packet_unref(pkt);\n            continue;\n        }\n        else\n            break;\n    }\n\n    return 1;\n}\n\nstatic void decoder_init(Decoder *d, AVCodecContext *avctx, PacketQueue *queue, SDL_cond *empty_queue_cond) {\n    memset(d, 0, sizeof(Decoder));\n    d->avctx = avctx;\n    d->queue = queue;\n    d->empty_queue_cond = empty_queue_cond;\n    d->start_pts = AV_NOPTS_VALUE;\n\n    d->first_frame_decoded_time = SDL_GetTickHR();\n    d->first_frame_decoded = 0;\n\n    SDL_ProfilerReset(&d->decode_profiler, -1);\n}\n\nstatic int convert_image(FFPlayer *ffp, AVFrame *src_frame, int64_t src_frame_pts, int width, int height) {\n    GetImgInfo *img_info = ffp->get_img_info;\n    VideoState *is = ffp->is;\n    AVFrame *dst_frame = NULL;\n    AVPacket avpkt;\n    int got_packet = 0;\n    int dst_width = 0;\n    int dst_height = 0;\n    int bytes = 0;\n    void *buffer = NULL;\n    char file_path[1024] = {0};\n    char file_name[16] = {0};\n    int fd = -1;\n    int ret = 0;\n    int tmp = 0;\n    float origin_dar = 0;\n    float dar = 0;\n    AVRational display_aspect_ratio;\n    int file_name_length = 0;\n\n    if (!height || !width || !img_info->width || !img_info->height) {\n        ret = -1;\n        return ret;\n    }\n\n    dar = (float) img_info->width / img_info->height;\n\n    if (is->viddec.avctx) {\n        av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den,\n            is->viddec.avctx->width * (int64_t)is->viddec.avctx->sample_aspect_ratio.num,\n            is->viddec.avctx->height * (int64_t)is->viddec.avctx->sample_aspect_ratio.den,\n            1024 * 1024);\n\n        if (!display_aspect_ratio.num || !display_aspect_ratio.den) {\n            origin_dar = (float) width / height;\n        } else {\n            origin_dar = (float) display_aspect_ratio.num / display_aspect_ratio.den;\n        }\n    } else {\n        ret = -1;\n        return ret;\n    }\n\n    if ((int)(origin_dar * 100) != (int)(dar * 100)) {\n        tmp = img_info->width / origin_dar;\n        if (tmp > img_info->height) {\n            img_info->width = img_info->height * origin_dar;\n        } else {\n            img_info->height = tmp;\n        }\n        av_log(NULL, AV_LOG_INFO, \"%s img_info->width = %d, img_info->height = %d\\n\", __func__, img_info->width, img_info->height);\n    }\n\n    dst_width = img_info->width;\n    dst_height = img_info->height;\n\n    av_init_packet(&avpkt);\n    avpkt.size = 0;\n    avpkt.data = NULL;\n\n    if (!img_info->frame_img_convert_ctx) {\n        img_info->frame_img_convert_ctx = sws_getContext(width,\n\t\t    height,\n\t\t    src_frame->format,\n\t\t    dst_width,\n\t\t    dst_height,\n\t\t    AV_PIX_FMT_RGB24,\n\t\t    SWS_BICUBIC,\n\t\t    NULL,\n\t\t    NULL,\n\t\t    NULL);\n\n        if (!img_info->frame_img_convert_ctx) {\n            ret = -1;\n            av_log(NULL, AV_LOG_ERROR, \"%s sws_getContext failed\\n\", __func__);\n            goto fail0;\n        }\n    }\n\n    if (!img_info->frame_img_codec_ctx) {\n        AVCodec *image_codec = avcodec_find_encoder(AV_CODEC_ID_PNG);\n        if (!image_codec) {\n            ret = -1;\n            av_log(NULL, AV_LOG_ERROR, \"%s avcodec_find_encoder failed\\n\", __func__);\n            goto fail0;\n        }\n\t    img_info->frame_img_codec_ctx = avcodec_alloc_context3(image_codec);\n        if (!img_info->frame_img_codec_ctx) {\n            ret = -1;\n            av_log(NULL, AV_LOG_ERROR, \"%s avcodec_alloc_context3 failed\\n\", __func__);\n            goto fail0;\n        }\n        img_info->frame_img_codec_ctx->bit_rate = ffp->stat.bit_rate;\n        img_info->frame_img_codec_ctx->width = dst_width;\n        img_info->frame_img_codec_ctx->height = dst_height;\n        img_info->frame_img_codec_ctx->pix_fmt = AV_PIX_FMT_RGB24;\n        img_info->frame_img_codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO;\n        img_info->frame_img_codec_ctx->time_base.num = ffp->is->video_st->time_base.num;\n        img_info->frame_img_codec_ctx->time_base.den = ffp->is->video_st->time_base.den;\n        avcodec_open2(img_info->frame_img_codec_ctx, image_codec, NULL);\n    }\n\n    dst_frame = av_frame_alloc();\n    if (!dst_frame) {\n        ret = -1;\n        av_log(NULL, AV_LOG_ERROR, \"%s av_frame_alloc failed\\n\", __func__);\n        goto fail0;\n    }\n    bytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, dst_width, dst_height, 1);\n\tbuffer = (uint8_t *) av_malloc(bytes * sizeof(uint8_t));\n    if (!buffer) {\n        ret = -1;\n        av_log(NULL, AV_LOG_ERROR, \"%s av_image_get_buffer_size failed\\n\", __func__);\n        goto fail1;\n    }\n\n    dst_frame->format = AV_PIX_FMT_RGB24;\n    dst_frame->width = dst_width;\n    dst_frame->height = dst_height;\n\n    ret = av_image_fill_arrays(dst_frame->data,\n            dst_frame->linesize,\n            buffer,\n            AV_PIX_FMT_RGB24,\n            dst_width,\n            dst_height,\n            1);\n\n    if (ret < 0) {\n        ret = -1;\n        av_log(NULL, AV_LOG_ERROR, \"%s av_image_fill_arrays failed\\n\", __func__);\n        goto fail2;\n    }\n\n    ret = sws_scale(img_info->frame_img_convert_ctx,\n            (const uint8_t * const *) src_frame->data,\n            src_frame->linesize,\n            0,\n            src_frame->height,\n            dst_frame->data,\n            dst_frame->linesize);\n\n    if (ret <= 0) {\n        ret = -1;\n        av_log(NULL, AV_LOG_ERROR, \"%s sws_scale failed\\n\", __func__);\n        goto fail2;\n    }\n\n    ret = avcodec_encode_video2(img_info->frame_img_codec_ctx, &avpkt, dst_frame, &got_packet);\n\n    if (ret >= 0 && got_packet > 0) {\n        strcpy(file_path, img_info->img_path);\n        strcat(file_path, \"/\");\n        sprintf(file_name, \"%lld\", src_frame_pts);\n        strcat(file_name, \".png\");\n        strcat(file_path, file_name);\n\n        fd = open(file_path, O_RDWR | O_TRUNC | O_CREAT, 0600);\n        if (fd < 0) {\n            ret = -1;\n            av_log(NULL, AV_LOG_ERROR, \"%s open path = %s failed %s\\n\", __func__, file_path, strerror(errno));\n            goto fail2;\n        }\n        write(fd, avpkt.data, avpkt.size);\n        close(fd);\n\n        img_info->count--;\n\n        file_name_length = (int)strlen(file_name) + 1;\n\n        if (img_info->count <= 0)\n            ffp_notify_msg4(ffp, FFP_MSG_GET_IMG_STATE, (int) src_frame_pts, 1, file_name, file_name_length);\n        else\n            ffp_notify_msg4(ffp, FFP_MSG_GET_IMG_STATE, (int) src_frame_pts, 0, file_name, file_name_length);\n\n        ret = 0;\n    }\n\nfail2:\n    av_free(buffer);\nfail1:\n    av_frame_free(&dst_frame);\nfail0:\n    av_packet_unref(&avpkt);\n\n    return ret;\n}\n\nstatic int decoder_decode_frame(FFPlayer *ffp, Decoder *d, AVFrame *frame, AVSubtitle *sub) {\n    int ret = AVERROR(EAGAIN);\n\n    for (;;) {\n        AVPacket pkt;\n\n        if (d->queue->serial == d->pkt_serial) {\n            do {\n                if (d->queue->abort_request)\n                    return -1;\n\n                switch (d->avctx->codec_type) {\n                    case AVMEDIA_TYPE_VIDEO:\n                        ret = avcodec_receive_frame(d->avctx, frame);\n                        if (ret >= 0) {\n                            ffp->stat.vdps = SDL_SpeedSamplerAdd(&ffp->vdps_sampler, FFP_SHOW_VDPS_AVCODEC, \"vdps[avcodec]\");\n                            if (ffp->decoder_reorder_pts == -1) {\n                                frame->pts = frame->best_effort_timestamp;\n                            } else if (!ffp->decoder_reorder_pts) {\n                                frame->pts = frame->pkt_dts;\n                            }\n                        }\n                        break;\n                    case AVMEDIA_TYPE_AUDIO:\n                        ret = avcodec_receive_frame(d->avctx, frame);\n                        if (ret >= 0) {\n                            AVRational tb = (AVRational){1, frame->sample_rate};\n                            if (frame->pts != AV_NOPTS_VALUE)\n                                frame->pts = av_rescale_q(frame->pts, av_codec_get_pkt_timebase(d->avctx), tb);\n                            else if (d->next_pts != AV_NOPTS_VALUE)\n                                frame->pts = av_rescale_q(d->next_pts, d->next_pts_tb, tb);\n                            if (frame->pts != AV_NOPTS_VALUE) {\n                                d->next_pts = frame->pts + frame->nb_samples;\n                                d->next_pts_tb = tb;\n                            }\n                        }\n                        break;\n                    default:\n                        break;\n                }\n                if (ret == AVERROR_EOF) {\n                    d->finished = d->pkt_serial;\n                    avcodec_flush_buffers(d->avctx);\n                    return 0;\n                }\n                if (ret >= 0)\n                    return 1;\n            } while (ret != AVERROR(EAGAIN));\n        }\n\n        do {\n            if (d->queue->nb_packets == 0)\n                SDL_CondSignal(d->empty_queue_cond);\n            if (d->packet_pending) {\n                av_packet_move_ref(&pkt, &d->pkt);\n                d->packet_pending = 0;\n            } else {\n                if (packet_queue_get_or_buffering(ffp, d->queue, &pkt, &d->pkt_serial, &d->finished) < 0)\n                    return -1;\n            }\n        } while (d->queue->serial != d->pkt_serial);\n\n        if (pkt.data == flush_pkt.data) {\n            avcodec_flush_buffers(d->avctx);\n            d->finished = 0;\n            d->next_pts = d->start_pts;\n            d->next_pts_tb = d->start_pts_tb;\n        } else {\n            if (d->avctx->codec_type == AVMEDIA_TYPE_SUBTITLE) {\n                int got_frame = 0;\n                ret = avcodec_decode_subtitle2(d->avctx, sub, &got_frame, &pkt);\n                if (ret < 0) {\n                    ret = AVERROR(EAGAIN);\n                } else {\n                    if (got_frame && !pkt.data) {\n                       d->packet_pending = 1;\n                       av_packet_move_ref(&d->pkt, &pkt);\n                    }\n                    ret = got_frame ? 0 : (pkt.data ? AVERROR(EAGAIN) : AVERROR_EOF);\n                }\n            } else {\n                if (avcodec_send_packet(d->avctx, &pkt) == AVERROR(EAGAIN)) {\n                    av_log(d->avctx, AV_LOG_ERROR, \"Receive_frame and send_packet both returned EAGAIN, which is an API violation.\\n\");\n                    d->packet_pending = 1;\n                    av_packet_move_ref(&d->pkt, &pkt);\n                }\n            }\n            av_packet_unref(&pkt);\n        }\n    }\n}\n\nstatic void decoder_destroy(Decoder *d) {\n    av_packet_unref(&d->pkt);\n    avcodec_free_context(&d->avctx);\n}\n\nstatic void frame_queue_unref_item(Frame *vp)\n{\n    av_frame_unref(vp->frame);\n    SDL_VoutUnrefYUVOverlay(vp->bmp);\n    avsubtitle_free(&vp->sub);\n}\n\nstatic int frame_queue_init(FrameQueue *f, PacketQueue *pktq, int max_size, int keep_last)\n{\n    int i;\n    memset(f, 0, sizeof(FrameQueue));\n    if (!(f->mutex = SDL_CreateMutex())) {\n        av_log(NULL, AV_LOG_FATAL, \"SDL_CreateMutex(): %s\\n\", SDL_GetError());\n        return AVERROR(ENOMEM);\n    }\n    if (!(f->cond = SDL_CreateCond())) {\n        av_log(NULL, AV_LOG_FATAL, \"SDL_CreateCond(): %s\\n\", SDL_GetError());\n        return AVERROR(ENOMEM);\n    }\n    f->pktq = pktq;\n    f->max_size = FFMIN(max_size, FRAME_QUEUE_SIZE);\n    f->keep_last = !!keep_last;\n    for (i = 0; i < f->max_size; i++)\n        if (!(f->queue[i].frame = av_frame_alloc()))\n            return AVERROR(ENOMEM);\n    return 0;\n}\n\nstatic void frame_queue_destory(FrameQueue *f)\n{\n    int i;\n    for (i = 0; i < f->max_size; i++) {\n        Frame *vp = &f->queue[i];\n        frame_queue_unref_item(vp);\n        av_frame_free(&vp->frame);\n        free_picture(vp);\n    }\n    SDL_DestroyMutex(f->mutex);\n    SDL_DestroyCond(f->cond);\n}\n\nstatic void frame_queue_signal(FrameQueue *f)\n{\n    SDL_LockMutex(f->mutex);\n    SDL_CondSignal(f->cond);\n    SDL_UnlockMutex(f->mutex);\n}\n\nstatic Frame *frame_queue_peek(FrameQueue *f)\n{\n    return &f->queue[(f->rindex + f->rindex_shown) % f->max_size];\n}\n\nstatic Frame *frame_queue_peek_next(FrameQueue *f)\n{\n    return &f->queue[(f->rindex + f->rindex_shown + 1) % f->max_size];\n}\n\nstatic Frame *frame_queue_peek_last(FrameQueue *f)\n{\n    return &f->queue[f->rindex];\n}\n\nstatic Frame *frame_queue_peek_writable(FrameQueue *f)\n{\n    /* wait until we have space to put a new frame */\n    SDL_LockMutex(f->mutex);\n    while (f->size >= f->max_size &&\n           !f->pktq->abort_request) {\n        SDL_CondWait(f->cond, f->mutex);\n    }\n    SDL_UnlockMutex(f->mutex);\n\n    if (f->pktq->abort_request)\n        return NULL;\n\n    return &f->queue[f->windex];\n}\n\nstatic Frame *frame_queue_peek_readable(FrameQueue *f)\n{\n    /* wait until we have a readable a new frame */\n    SDL_LockMutex(f->mutex);\n    while (f->size - f->rindex_shown <= 0 &&\n           !f->pktq->abort_request) {\n        SDL_CondWait(f->cond, f->mutex);\n    }\n    SDL_UnlockMutex(f->mutex);\n\n    if (f->pktq->abort_request)\n        return NULL;\n\n    return &f->queue[(f->rindex + f->rindex_shown) % f->max_size];\n}\n\nstatic void frame_queue_push(FrameQueue *f)\n{\n    if (++f->windex == f->max_size)\n        f->windex = 0;\n    SDL_LockMutex(f->mutex);\n    f->size++;\n    SDL_CondSignal(f->cond);\n    SDL_UnlockMutex(f->mutex);\n}\n\nstatic void frame_queue_next(FrameQueue *f)\n{\n    if (f->keep_last && !f->rindex_shown) {\n        f->rindex_shown = 1;\n        return;\n    }\n    frame_queue_unref_item(&f->queue[f->rindex]);\n    if (++f->rindex == f->max_size)\n        f->rindex = 0;\n    SDL_LockMutex(f->mutex);\n    f->size--;\n    SDL_CondSignal(f->cond);\n    SDL_UnlockMutex(f->mutex);\n}\n\n/* return the number of undisplayed frames in the queue */\nstatic int frame_queue_nb_remaining(FrameQueue *f)\n{\n    return f->size - f->rindex_shown;\n}\n\n/* return last shown position */\n#ifdef FFP_MERGE\nstatic int64_t frame_queue_last_pos(FrameQueue *f)\n{\n    Frame *fp = &f->queue[f->rindex];\n    if (f->rindex_shown && fp->serial == f->pktq->serial)\n        return fp->pos;\n    else\n        return -1;\n}\n#endif\n\nstatic void decoder_abort(Decoder *d, FrameQueue *fq)\n{\n    packet_queue_abort(d->queue);\n    frame_queue_signal(fq);\n    SDL_WaitThread(d->decoder_tid, NULL);\n    d->decoder_tid = NULL;\n    packet_queue_flush(d->queue);\n}\n\n// FFP_MERGE: fill_rectangle\n// FFP_MERGE: fill_border\n// FFP_MERGE: ALPHA_BLEND\n// FFP_MERGE: RGBA_IN\n// FFP_MERGE: YUVA_IN\n// FFP_MERGE: YUVA_OUT\n// FFP_MERGE: BPP\n// FFP_MERGE: blend_subrect\n\nstatic void free_picture(Frame *vp)\n{\n    if (vp->bmp) {\n        SDL_VoutFreeYUVOverlay(vp->bmp);\n        vp->bmp = NULL;\n    }\n}\n\n// FFP_MERGE: realloc_texture\n// FFP_MERGE: calculate_display_rect\n// FFP_MERGE: upload_texture\n// FFP_MERGE: video_image_display\n\nstatic size_t parse_ass_subtitle(const char *ass, char *output)\n{\n    char *tok = NULL;\n    tok = strchr(ass, ':'); if (tok) tok += 1; // skip event\n    tok = strchr(tok, ','); if (tok) tok += 1; // skip layer\n    tok = strchr(tok, ','); if (tok) tok += 1; // skip start_time\n    tok = strchr(tok, ','); if (tok) tok += 1; // skip end_time\n    tok = strchr(tok, ','); if (tok) tok += 1; // skip style\n    tok = strchr(tok, ','); if (tok) tok += 1; // skip name\n    tok = strchr(tok, ','); if (tok) tok += 1; // skip margin_l\n    tok = strchr(tok, ','); if (tok) tok += 1; // skip margin_r\n    tok = strchr(tok, ','); if (tok) tok += 1; // skip margin_v\n    tok = strchr(tok, ','); if (tok) tok += 1; // skip effect\n    if (tok) {\n        char *text = tok;\n        size_t idx = 0;\n        do {\n            char *found = strstr(text, \"\\\\N\");\n            if (found) {\n                size_t n = found - text;\n                memcpy(output+idx, text, n);\n                output[idx + n] = '\\n';\n                idx = n + 1;\n                text = found + 2;\n            }\n            else {\n                size_t left_text_len = strlen(text);\n                memcpy(output+idx, text, left_text_len);\n                if (output[idx + left_text_len - 1] == '\\n')\n                    output[idx + left_text_len - 1] = '\\0';\n                else\n                    output[idx + left_text_len] = '\\0';\n                break;\n            }\n        } while(1);\n        return strlen(output) + 1;\n    }\n    return 0;\n}\n\nstatic void video_image_display2(FFPlayer *ffp)\n{\n    VideoState *is = ffp->is;\n    Frame *vp;\n    Frame *sp = NULL;\n\n    vp = frame_queue_peek_last(&is->pictq);\n\n    if (vp->bmp) {\n        if (is->subtitle_st) {\n            if (frame_queue_nb_remaining(&is->subpq) > 0) {\n                sp = frame_queue_peek(&is->subpq);\n\n                if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000)) {\n                    if (!sp->uploaded) {\n                        if (sp->sub.num_rects > 0) {\n                            char buffered_text[4096];\n                            if (sp->sub.rects[0]->text) {\n                                strncpy(buffered_text, sp->sub.rects[0]->text, 4096);\n                            }\n                            else if (sp->sub.rects[0]->ass) {\n                                parse_ass_subtitle(sp->sub.rects[0]->ass, buffered_text);\n                            }\n                            ffp_notify_msg4(ffp, FFP_MSG_TIMED_TEXT, 0, 0, buffered_text, sizeof(buffered_text));\n                        }\n                        sp->uploaded = 1;\n                    }\n                }\n            }\n        }\n        if (ffp->render_wait_start && !ffp->start_on_prepared && is->pause_req) {\n            if (!ffp->first_video_frame_rendered) {\n                ffp->first_video_frame_rendered = 1;\n                ffp_notify_msg1(ffp, FFP_MSG_VIDEO_RENDERING_START);\n            }\n            while (is->pause_req && !is->abort_request) {\n                SDL_Delay(20);\n            }\n        }\n        SDL_VoutDisplayYUVOverlay(ffp->vout, vp->bmp);\n        ffp->stat.vfps = SDL_SpeedSamplerAdd(&ffp->vfps_sampler, FFP_SHOW_VFPS_FFPLAY, \"vfps[ffplay]\");\n        if (!ffp->first_video_frame_rendered) {\n            ffp->first_video_frame_rendered = 1;\n            ffp_notify_msg1(ffp, FFP_MSG_VIDEO_RENDERING_START);\n        }\n\n        if (is->latest_video_seek_load_serial == vp->serial) {\n            int latest_video_seek_load_serial = __atomic_exchange_n(&(is->latest_video_seek_load_serial), -1, memory_order_seq_cst);\n            if (latest_video_seek_load_serial == vp->serial) {\n                ffp->stat.latest_seek_load_duration = (av_gettime() - is->latest_seek_load_start_at) / 1000;\n                if (ffp->av_sync_type == AV_SYNC_VIDEO_MASTER) {\n                    ffp_notify_msg2(ffp, FFP_MSG_VIDEO_SEEK_RENDERING_START, 1);\n                } else {\n                    ffp_notify_msg2(ffp, FFP_MSG_VIDEO_SEEK_RENDERING_START, 0);\n                }\n            }\n        }\n    }\n}\n\n// FFP_MERGE: compute_mod\n// FFP_MERGE: video_audio_display\n\nstatic void stream_component_close(FFPlayer *ffp, int stream_index)\n{\n    VideoState *is = ffp->is;\n    AVFormatContext *ic = is->ic;\n    AVCodecParameters *codecpar;\n\n    if (stream_index < 0 || stream_index >= ic->nb_streams)\n        return;\n    codecpar = ic->streams[stream_index]->codecpar;\n\n    switch (codecpar->codec_type) {\n    case AVMEDIA_TYPE_AUDIO:\n        decoder_abort(&is->auddec, &is->sampq);\n        SDL_AoutCloseAudio(ffp->aout);\n\n        decoder_destroy(&is->auddec);\n        swr_free(&is->swr_ctx);\n        av_freep(&is->audio_buf1);\n        is->audio_buf1_size = 0;\n        is->audio_buf = NULL;\n\n#ifdef FFP_MERGE\n        if (is->rdft) {\n            av_rdft_end(is->rdft);\n            av_freep(&is->rdft_data);\n            is->rdft = NULL;\n            is->rdft_bits = 0;\n        }\n#endif\n        break;\n    case AVMEDIA_TYPE_VIDEO:\n        decoder_abort(&is->viddec, &is->pictq);\n        decoder_destroy(&is->viddec);\n        break;\n    case AVMEDIA_TYPE_SUBTITLE:\n        decoder_abort(&is->subdec, &is->subpq);\n        decoder_destroy(&is->subdec);\n        break;\n    default:\n        break;\n    }\n\n    ic->streams[stream_index]->discard = AVDISCARD_ALL;\n    switch (codecpar->codec_type) {\n    case AVMEDIA_TYPE_AUDIO:\n        is->audio_st = NULL;\n        is->audio_stream = -1;\n        break;\n    case AVMEDIA_TYPE_VIDEO:\n        is->video_st = NULL;\n        is->video_stream = -1;\n        break;\n    case AVMEDIA_TYPE_SUBTITLE:\n        is->subtitle_st = NULL;\n        is->subtitle_stream = -1;\n        break;\n    default:\n        break;\n    }\n}\n\nstatic void stream_close(FFPlayer *ffp)\n{\n    VideoState *is = ffp->is;\n    /* XXX: use a special url_shutdown call to abort parse cleanly */\n    is->abort_request = 1;\n    packet_queue_abort(&is->videoq);\n    packet_queue_abort(&is->audioq);\n    av_log(NULL, AV_LOG_DEBUG, \"wait for read_tid\\n\");\n    SDL_WaitThread(is->read_tid, NULL);\n\n    /* close each stream */\n    if (is->audio_stream >= 0)\n        stream_component_close(ffp, is->audio_stream);\n    if (is->video_stream >= 0)\n        stream_component_close(ffp, is->video_stream);\n    if (is->subtitle_stream >= 0)\n        stream_component_close(ffp, is->subtitle_stream);\n\n    avformat_close_input(&is->ic);\n\n    av_log(NULL, AV_LOG_DEBUG, \"wait for video_refresh_tid\\n\");\n    SDL_WaitThread(is->video_refresh_tid, NULL);\n\n    packet_queue_destroy(&is->videoq);\n    packet_queue_destroy(&is->audioq);\n    packet_queue_destroy(&is->subtitleq);\n\n    /* free all pictures */\n    frame_queue_destory(&is->pictq);\n    frame_queue_destory(&is->sampq);\n    frame_queue_destory(&is->subpq);\n    SDL_DestroyCond(is->audio_accurate_seek_cond);\n    SDL_DestroyCond(is->video_accurate_seek_cond);\n    SDL_DestroyCond(is->continue_read_thread);\n    SDL_DestroyMutex(is->accurate_seek_mutex);\n    SDL_DestroyMutex(is->play_mutex);\n#if !CONFIG_AVFILTER\n    sws_freeContext(is->img_convert_ctx);\n#endif\n#ifdef FFP_MERGE\n    sws_freeContext(is->sub_convert_ctx);\n#endif\n\n#if defined(__ANDROID__)\n    if (ffp->soundtouch_enable && is->handle != NULL) {\n        ijk_soundtouch_destroy(is->handle);\n    }\n#endif\n    if (ffp->get_img_info) {\n        if (ffp->get_img_info->frame_img_convert_ctx) {\n            sws_freeContext(ffp->get_img_info->frame_img_convert_ctx);\n        }\n        if (ffp->get_img_info->frame_img_codec_ctx) {\n            avcodec_free_context(&ffp->get_img_info->frame_img_codec_ctx);\n        }\n        av_freep(&ffp->get_img_info->img_path);\n        av_freep(&ffp->get_img_info);\n    }\n    av_free(is->filename);\n    av_free(is);\n    ffp->is = NULL;\n}\n\n// FFP_MERGE: do_exit\n// FFP_MERGE: sigterm_handler\n// FFP_MERGE: video_open\n// FFP_MERGE: video_display\n\n/* display the current picture, if any */\nstatic void video_display2(FFPlayer *ffp)\n{\n    VideoState *is = ffp->is;\n    if (is->video_st)\n        video_image_display2(ffp);\n}\n\nstatic double get_clock(Clock *c)\n{\n    if (*c->queue_serial != c->serial)\n        return NAN;\n    if (c->paused) {\n        return c->pts;\n    } else {\n        double time = av_gettime_relative() / 1000000.0;\n        return c->pts_drift + time - (time - c->last_updated) * (1.0 - c->speed);\n    }\n}\n\nstatic void set_clock_at(Clock *c, double pts, int serial, double time)\n{\n    c->pts = pts;\n    c->last_updated = time;\n    c->pts_drift = c->pts - time;\n    c->serial = serial;\n}\n\nstatic void set_clock(Clock *c, double pts, int serial)\n{\n    double time = av_gettime_relative() / 1000000.0;\n    set_clock_at(c, pts, serial, time);\n}\n\nstatic void set_clock_speed(Clock *c, double speed)\n{\n    set_clock(c, get_clock(c), c->serial);\n    c->speed = speed;\n}\n\nstatic void init_clock(Clock *c, int *queue_serial)\n{\n    c->speed = 1.0;\n    c->paused = 0;\n    c->queue_serial = queue_serial;\n    set_clock(c, NAN, -1);\n}\n\nstatic void sync_clock_to_slave(Clock *c, Clock *slave)\n{\n    double clock = get_clock(c);\n    double slave_clock = get_clock(slave);\n    if (!isnan(slave_clock) && (isnan(clock) || fabs(clock - slave_clock) > AV_NOSYNC_THRESHOLD))\n        set_clock(c, slave_clock, slave->serial);\n}\n\nstatic int get_master_sync_type(VideoState *is) {\n    if (is->av_sync_type == AV_SYNC_VIDEO_MASTER) {\n        if (is->video_st)\n            return AV_SYNC_VIDEO_MASTER;\n        else\n            return AV_SYNC_AUDIO_MASTER;\n    } else if (is->av_sync_type == AV_SYNC_AUDIO_MASTER) {\n        if (is->audio_st)\n            return AV_SYNC_AUDIO_MASTER;\n        else\n            return AV_SYNC_EXTERNAL_CLOCK;\n    } else {\n        return AV_SYNC_EXTERNAL_CLOCK;\n    }\n}\n\n/* get the current master clock value */\nstatic double get_master_clock(VideoState *is)\n{\n    double val;\n\n    switch (get_master_sync_type(is)) {\n        case AV_SYNC_VIDEO_MASTER:\n            val = get_clock(&is->vidclk);\n            break;\n        case AV_SYNC_AUDIO_MASTER:\n            val = get_clock(&is->audclk);\n            break;\n        default:\n            val = get_clock(&is->extclk);\n            break;\n    }\n    return val;\n}\n\nstatic void check_external_clock_speed(VideoState *is) {\n   if ((is->video_stream >= 0 && is->videoq.nb_packets <= EXTERNAL_CLOCK_MIN_FRAMES) ||\n       (is->audio_stream >= 0 && is->audioq.nb_packets <= EXTERNAL_CLOCK_MIN_FRAMES)) {\n       set_clock_speed(&is->extclk, FFMAX(EXTERNAL_CLOCK_SPEED_MIN, is->extclk.speed - EXTERNAL_CLOCK_SPEED_STEP));\n   } else if ((is->video_stream < 0 || is->videoq.nb_packets > EXTERNAL_CLOCK_MAX_FRAMES) &&\n              (is->audio_stream < 0 || is->audioq.nb_packets > EXTERNAL_CLOCK_MAX_FRAMES)) {\n       set_clock_speed(&is->extclk, FFMIN(EXTERNAL_CLOCK_SPEED_MAX, is->extclk.speed + EXTERNAL_CLOCK_SPEED_STEP));\n   } else {\n       double speed = is->extclk.speed;\n       if (speed != 1.0)\n           set_clock_speed(&is->extclk, speed + EXTERNAL_CLOCK_SPEED_STEP * (1.0 - speed) / fabs(1.0 - speed));\n   }\n}\n\n/* seek in the stream */\nstatic void stream_seek(VideoState *is, int64_t pos, int64_t rel, int seek_by_bytes)\n{\n    if (!is->seek_req) {\n        is->seek_pos = pos;\n        is->seek_rel = rel;\n        is->seek_flags &= ~AVSEEK_FLAG_BYTE;\n        if (seek_by_bytes)\n            is->seek_flags |= AVSEEK_FLAG_BYTE;\n        is->seek_req = 1;\n        SDL_CondSignal(is->continue_read_thread);\n    }\n}\n\n/* pause or resume the video */\nstatic void stream_toggle_pause_l(FFPlayer *ffp, int pause_on)\n{\n    VideoState *is = ffp->is;\n    if (is->paused && !pause_on) {\n        is->frame_timer += av_gettime_relative() / 1000000.0 - is->vidclk.last_updated;\n\n#ifdef FFP_MERGE\n        if (is->read_pause_return != AVERROR(ENOSYS)) {\n            is->vidclk.paused = 0;\n        }\n#endif\n        set_clock(&is->vidclk, get_clock(&is->vidclk), is->vidclk.serial);\n        set_clock(&is->audclk, get_clock(&is->audclk), is->audclk.serial);\n    } else {\n    }\n    set_clock(&is->extclk, get_clock(&is->extclk), is->extclk.serial);\n    if (is->step && (is->pause_req || is->buffering_on)) {\n        is->paused = is->vidclk.paused = is->extclk.paused = pause_on;\n    } else {\n        is->paused = is->audclk.paused = is->vidclk.paused = is->extclk.paused = pause_on;\n        SDL_AoutPauseAudio(ffp->aout, pause_on);\n    }\n}\n\nstatic void stream_update_pause_l(FFPlayer *ffp)\n{\n    VideoState *is = ffp->is;\n    if (!is->step && (is->pause_req || is->buffering_on)) {\n        stream_toggle_pause_l(ffp, 1);\n    } else {\n        stream_toggle_pause_l(ffp, 0);\n    }\n}\n\nstatic void toggle_pause_l(FFPlayer *ffp, int pause_on)\n{\n    VideoState *is = ffp->is;\n    if (is->pause_req && !pause_on) {\n        set_clock(&is->vidclk, get_clock(&is->vidclk), is->vidclk.serial);\n        set_clock(&is->audclk, get_clock(&is->audclk), is->audclk.serial);\n    }\n    is->pause_req = pause_on;\n    ffp->auto_resume = !pause_on;\n    stream_update_pause_l(ffp);\n    is->step = 0;\n}\n\nstatic void toggle_pause(FFPlayer *ffp, int pause_on)\n{\n    SDL_LockMutex(ffp->is->play_mutex);\n    toggle_pause_l(ffp, pause_on);\n    SDL_UnlockMutex(ffp->is->play_mutex);\n}\n\n// FFP_MERGE: toggle_mute\n// FFP_MERGE: update_volume\n\nstatic void step_to_next_frame_l(FFPlayer *ffp)\n{\n    VideoState *is = ffp->is;\n    is->step = 1;\n    /* if the stream is paused unpause it, then step */\n    if (is->paused)\n        stream_toggle_pause_l(ffp, 0);\n}\n\nstatic double compute_target_delay(FFPlayer *ffp, double delay, VideoState *is)\n{\n    double sync_threshold, diff = 0;\n\n    /* update delay to follow master synchronisation source */\n    if (get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER) {\n        /* if video is slave, we try to correct big delays by\n           duplicating or deleting a frame */\n        diff = get_clock(&is->vidclk) - get_master_clock(is);\n\n        /* skip or repeat frame. We take into account the\n           delay to compute the threshold. I still don't know\n           if it is the best guess */\n        sync_threshold = FFMAX(AV_SYNC_THRESHOLD_MIN, FFMIN(AV_SYNC_THRESHOLD_MAX, delay));\n        /* -- by bbcallen: replace is->max_frame_duration with AV_NOSYNC_THRESHOLD */\n        if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD) {\n            if (diff <= -sync_threshold)\n                delay = FFMAX(0, delay + diff);\n            else if (diff >= sync_threshold && delay > AV_SYNC_FRAMEDUP_THRESHOLD)\n                delay = delay + diff;\n            else if (diff >= sync_threshold)\n                delay = 2 * delay;\n        }\n    }\n\n    if (ffp) {\n        ffp->stat.avdelay = delay;\n        ffp->stat.avdiff  = diff;\n    }\n#ifdef FFP_SHOW_AUDIO_DELAY\n    av_log(NULL, AV_LOG_TRACE, \"video: delay=%0.3f A-V=%f\\n\",\n            delay, -diff);\n#endif\n\n    return delay;\n}\n\nstatic double vp_duration(VideoState *is, Frame *vp, Frame *nextvp) {\n    if (vp->serial == nextvp->serial) {\n        double duration = nextvp->pts - vp->pts;\n        if (isnan(duration) || duration <= 0 || duration > is->max_frame_duration)\n            return vp->duration;\n        else\n            return duration;\n    } else {\n        return 0.0;\n    }\n}\n\nstatic void update_video_pts(VideoState *is, double pts, int64_t pos, int serial) {\n    /* update current video pts */\n    set_clock(&is->vidclk, pts, serial);\n    sync_clock_to_slave(&is->extclk, &is->vidclk);\n}\n\n/* called to display each frame */\nstatic void video_refresh(FFPlayer *opaque, double *remaining_time)\n{\n    FFPlayer *ffp = opaque;\n    VideoState *is = ffp->is;\n    double time;\n\n    Frame *sp, *sp2;\n\n    if (!is->paused && get_master_sync_type(is) == AV_SYNC_EXTERNAL_CLOCK && is->realtime)\n        check_external_clock_speed(is);\n\n    if (!ffp->display_disable && is->show_mode != SHOW_MODE_VIDEO && is->audio_st) {\n        time = av_gettime_relative() / 1000000.0;\n        if (is->force_refresh || is->last_vis_time + ffp->rdftspeed < time) {\n            video_display2(ffp);\n            is->last_vis_time = time;\n        }\n        *remaining_time = FFMIN(*remaining_time, is->last_vis_time + ffp->rdftspeed - time);\n    }\n\n    if (is->video_st) {\nretry:\n        if (frame_queue_nb_remaining(&is->pictq) == 0) {\n            // nothing to do, no picture to display in the queue\n        } else {\n            double last_duration, duration, delay;\n            Frame *vp, *lastvp;\n\n            /* dequeue the picture */\n            lastvp = frame_queue_peek_last(&is->pictq);\n            vp = frame_queue_peek(&is->pictq);\n\n            if (vp->serial != is->videoq.serial) {\n                frame_queue_next(&is->pictq);\n                goto retry;\n            }\n\n            if (lastvp->serial != vp->serial)\n                is->frame_timer = av_gettime_relative() / 1000000.0;\n\n            if (is->paused)\n                goto display;\n\n            /* compute nominal last_duration */\n            last_duration = vp_duration(is, lastvp, vp);\n            delay = compute_target_delay(ffp, last_duration, is);\n\n            time= av_gettime_relative()/1000000.0;\n            if (isnan(is->frame_timer) || time < is->frame_timer)\n                is->frame_timer = time;\n            if (time < is->frame_timer + delay) {\n                *remaining_time = FFMIN(is->frame_timer + delay - time, *remaining_time);\n                goto display;\n            }\n\n            is->frame_timer += delay;\n            if (delay > 0 && time - is->frame_timer > AV_SYNC_THRESHOLD_MAX)\n                is->frame_timer = time;\n\n            SDL_LockMutex(is->pictq.mutex);\n            if (!isnan(vp->pts))\n                update_video_pts(is, vp->pts, vp->pos, vp->serial);\n            SDL_UnlockMutex(is->pictq.mutex);\n\n            if (frame_queue_nb_remaining(&is->pictq) > 1) {\n                Frame *nextvp = frame_queue_peek_next(&is->pictq);\n                duration = vp_duration(is, vp, nextvp);\n                if(!is->step && (ffp->framedrop > 0 || (ffp->framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) && time > is->frame_timer + duration) {\n                    frame_queue_next(&is->pictq);\n                    goto retry;\n                }\n            }\n\n            if (is->subtitle_st) {\n                while (frame_queue_nb_remaining(&is->subpq) > 0) {\n                    sp = frame_queue_peek(&is->subpq);\n\n                    if (frame_queue_nb_remaining(&is->subpq) > 1)\n                        sp2 = frame_queue_peek_next(&is->subpq);\n                    else\n                        sp2 = NULL;\n\n                    if (sp->serial != is->subtitleq.serial\n                            || (is->vidclk.pts > (sp->pts + ((float) sp->sub.end_display_time / 1000)))\n                            || (sp2 && is->vidclk.pts > (sp2->pts + ((float) sp2->sub.start_display_time / 1000))))\n                    {\n                        if (sp->uploaded) {\n                            ffp_notify_msg4(ffp, FFP_MSG_TIMED_TEXT, 0, 0, \"\", 1);\n                        }\n                        frame_queue_next(&is->subpq);\n                    } else {\n                        break;\n                    }\n                }\n            }\n\n            frame_queue_next(&is->pictq);\n            is->force_refresh = 1;\n\n            SDL_LockMutex(ffp->is->play_mutex);\n            if (is->step) {\n                is->step = 0;\n                if (!is->paused)\n                    stream_update_pause_l(ffp);\n            }\n            SDL_UnlockMutex(ffp->is->play_mutex);\n        }\ndisplay:\n        /* display picture */\n        if (!ffp->display_disable && is->force_refresh && is->show_mode == SHOW_MODE_VIDEO && is->pictq.rindex_shown)\n            video_display2(ffp);\n    }\n    is->force_refresh = 0;\n    if (ffp->show_status) {\n        static int64_t last_time;\n        int64_t cur_time;\n        int aqsize, vqsize, sqsize __unused;\n        double av_diff;\n\n        cur_time = av_gettime_relative();\n        if (!last_time || (cur_time - last_time) >= 30000) {\n            aqsize = 0;\n            vqsize = 0;\n            sqsize = 0;\n            if (is->audio_st)\n                aqsize = is->audioq.size;\n            if (is->video_st)\n                vqsize = is->videoq.size;\n#ifdef FFP_MERGE\n            if (is->subtitle_st)\n                sqsize = is->subtitleq.size;\n#else\n            sqsize = 0;\n#endif\n            av_diff = 0;\n            if (is->audio_st && is->video_st)\n                av_diff = get_clock(&is->audclk) - get_clock(&is->vidclk);\n            else if (is->video_st)\n                av_diff = get_master_clock(is) - get_clock(&is->vidclk);\n            else if (is->audio_st)\n                av_diff = get_master_clock(is) - get_clock(&is->audclk);\n            av_log(NULL, AV_LOG_INFO,\n                   \"%7.2f %s:%7.3f fd=%4d aq=%5dKB vq=%5dKB sq=%5dB f=%\"PRId64\"/%\"PRId64\"   \\r\",\n                   get_master_clock(is),\n                   (is->audio_st && is->video_st) ? \"A-V\" : (is->video_st ? \"M-V\" : (is->audio_st ? \"M-A\" : \"   \")),\n                   av_diff,\n                   is->frame_drops_early + is->frame_drops_late,\n                   aqsize / 1024,\n                   vqsize / 1024,\n                   sqsize,\n                   is->video_st ? is->viddec.avctx->pts_correction_num_faulty_dts : 0,\n                   is->video_st ? is->viddec.avctx->pts_correction_num_faulty_pts : 0);\n            fflush(stdout);\n            last_time = cur_time;\n        }\n    }\n}\n\n/* allocate a picture (needs to do that in main thread to avoid\n   potential locking problems */\nstatic void alloc_picture(FFPlayer *ffp, int frame_format)\n{\n    VideoState *is = ffp->is;\n    Frame *vp;\n#ifdef FFP_MERGE\n    int sdl_format;\n#endif\n\n    vp = &is->pictq.queue[is->pictq.windex];\n\n    free_picture(vp);\n\n#ifdef FFP_MERGE\n    video_open(is, vp);\n#endif\n\n    SDL_VoutSetOverlayFormat(ffp->vout, ffp->overlay_format);\n    vp->bmp = SDL_Vout_CreateOverlay(vp->width, vp->height,\n                                   frame_format,\n                                   ffp->vout);\n#ifdef FFP_MERGE\n    if (vp->format == AV_PIX_FMT_YUV420P)\n        sdl_format = SDL_PIXELFORMAT_YV12;\n    else\n        sdl_format = SDL_PIXELFORMAT_ARGB8888;\n\n    if (realloc_texture(&vp->bmp, sdl_format, vp->width, vp->height, SDL_BLENDMODE_NONE, 0) < 0) {\n#else\n    /* RV16, RV32 contains only one plane */\n    if (!vp->bmp || (!vp->bmp->is_private && vp->bmp->pitches[0] < vp->width)) {\n#endif\n        /* SDL allocates a buffer smaller than requested if the video\n         * overlay hardware is unable to support the requested size. */\n        av_log(NULL, AV_LOG_FATAL,\n               \"Error: the video system does not support an image\\n\"\n                        \"size of %dx%d pixels. Try using -lowres or -vf \\\"scale=w:h\\\"\\n\"\n                        \"to reduce the image size.\\n\", vp->width, vp->height );\n        free_picture(vp);\n    }\n\n    SDL_LockMutex(is->pictq.mutex);\n    vp->allocated = 1;\n    SDL_CondSignal(is->pictq.cond);\n    SDL_UnlockMutex(is->pictq.mutex);\n}\n\nstatic int queue_picture(FFPlayer *ffp, AVFrame *src_frame, double pts, double duration, int64_t pos, int serial)\n{\n    VideoState *is = ffp->is;\n    Frame *vp;\n    int video_accurate_seek_fail = 0;\n    int64_t video_seek_pos = 0;\n    int64_t now = 0;\n    int64_t deviation = 0;\n\n    int64_t deviation2 = 0;\n    int64_t deviation3 = 0;\n\n    if (ffp->enable_accurate_seek && is->video_accurate_seek_req && !is->seek_req) {\n        if (!isnan(pts)) {\n            video_seek_pos = is->seek_pos;\n            is->accurate_seek_vframe_pts = pts * 1000 * 1000;\n            deviation = llabs((int64_t)(pts * 1000 * 1000) - is->seek_pos);\n            if ((pts * 1000 * 1000 < is->seek_pos) || deviation > MAX_DEVIATION) {\n                now = av_gettime_relative() / 1000;\n                if (is->drop_vframe_count == 0) {\n                    SDL_LockMutex(is->accurate_seek_mutex);\n                    if (is->accurate_seek_start_time <= 0 && (is->audio_stream < 0 || is->audio_accurate_seek_req)) {\n                        is->accurate_seek_start_time = now;\n                    }\n                    SDL_UnlockMutex(is->accurate_seek_mutex);\n                    av_log(NULL, AV_LOG_INFO, \"video accurate_seek start, is->seek_pos=%lld, pts=%lf, is->accurate_seek_time = %lld\\n\", is->seek_pos, pts, is->accurate_seek_start_time);\n                }\n                is->drop_vframe_count++;\n\n                while (is->audio_accurate_seek_req && !is->abort_request) {\n                    int64_t apts = is->accurate_seek_aframe_pts ;\n                    deviation2 = apts - pts * 1000 * 1000;\n                    deviation3 = apts - is->seek_pos;\n\n                    if (deviation2 > -100 * 1000 && deviation3 < 0) {\n                        break;\n                    } else {\n                        av_usleep(20 * 1000);\n                    }\n                    now = av_gettime_relative() / 1000;\n                    if ((now - is->accurate_seek_start_time) > ffp->accurate_seek_timeout) {\n                        break;\n                    }\n                }\n\n                if ((now - is->accurate_seek_start_time) <= ffp->accurate_seek_timeout) {\n                    return 1;  // drop some old frame when do accurate seek\n                } else {\n                    av_log(NULL, AV_LOG_WARNING, \"video accurate_seek is error, is->drop_vframe_count=%d, now = %lld, pts = %lf\\n\", is->drop_vframe_count, now, pts);\n                    video_accurate_seek_fail = 1;  // if KEY_FRAME interval too big, disable accurate seek\n                }\n            } else {\n                av_log(NULL, AV_LOG_INFO, \"video accurate_seek is ok, is->drop_vframe_count =%d, is->seek_pos=%lld, pts=%lf\\n\", is->drop_vframe_count, is->seek_pos, pts);\n                if (video_seek_pos == is->seek_pos) {\n                    is->drop_vframe_count       = 0;\n                    SDL_LockMutex(is->accurate_seek_mutex);\n                    is->video_accurate_seek_req = 0;\n                    SDL_CondSignal(is->audio_accurate_seek_cond);\n                    if (video_seek_pos == is->seek_pos && is->audio_accurate_seek_req && !is->abort_request) {\n                        SDL_CondWaitTimeout(is->video_accurate_seek_cond, is->accurate_seek_mutex, ffp->accurate_seek_timeout);\n                    } else {\n                        ffp_notify_msg2(ffp, FFP_MSG_ACCURATE_SEEK_COMPLETE, (int)(pts * 1000));\n                    }\n                    if (video_seek_pos != is->seek_pos && !is->abort_request) {\n                        is->video_accurate_seek_req = 1;\n                        SDL_UnlockMutex(is->accurate_seek_mutex);\n                        return 1;\n                    }\n\n                    SDL_UnlockMutex(is->accurate_seek_mutex);\n                }\n            }\n        } else {\n            video_accurate_seek_fail = 1;\n        }\n\n        if (video_accurate_seek_fail) {\n            is->drop_vframe_count = 0;\n            SDL_LockMutex(is->accurate_seek_mutex);\n            is->video_accurate_seek_req = 0;\n            SDL_CondSignal(is->audio_accurate_seek_cond);\n            if (is->audio_accurate_seek_req && !is->abort_request) {\n                SDL_CondWaitTimeout(is->video_accurate_seek_cond, is->accurate_seek_mutex, ffp->accurate_seek_timeout);\n            } else {\n                if (!isnan(pts)) {\n                    ffp_notify_msg2(ffp, FFP_MSG_ACCURATE_SEEK_COMPLETE, (int)(pts * 1000));\n                } else {\n                    ffp_notify_msg2(ffp, FFP_MSG_ACCURATE_SEEK_COMPLETE, 0);\n                }\n            }\n            SDL_UnlockMutex(is->accurate_seek_mutex);\n        }\n        is->accurate_seek_start_time = 0;\n        video_accurate_seek_fail = 0;\n        is->accurate_seek_vframe_pts = 0;\n    }\n\n#if defined(DEBUG_SYNC)\n    printf(\"frame_type=%c pts=%0.3f\\n\",\n           av_get_picture_type_char(src_frame->pict_type), pts);\n#endif\n\n    if (!(vp = frame_queue_peek_writable(&is->pictq)))\n        return -1;\n\n    vp->sar = src_frame->sample_aspect_ratio;\n#ifdef FFP_MERGE\n    vp->uploaded = 0;\n#endif\n\n    /* alloc or resize hardware picture buffer */\n    if (!vp->bmp || !vp->allocated ||\n        vp->width  != src_frame->width ||\n        vp->height != src_frame->height ||\n        vp->format != src_frame->format) {\n\n        if (vp->width != src_frame->width || vp->height != src_frame->height)\n            ffp_notify_msg3(ffp, FFP_MSG_VIDEO_SIZE_CHANGED, src_frame->width, src_frame->height);\n\n        vp->allocated = 0;\n        vp->width = src_frame->width;\n        vp->height = src_frame->height;\n        vp->format = src_frame->format;\n\n        /* the allocation must be done in the main thread to avoid\n           locking problems. */\n        alloc_picture(ffp, src_frame->format);\n\n        if (is->videoq.abort_request)\n            return -1;\n    }\n\n    /* if the frame is not skipped, then display it */\n    if (vp->bmp) {\n        /* get a pointer on the bitmap */\n        SDL_VoutLockYUVOverlay(vp->bmp);\n\n#ifdef FFP_MERGE\n#if CONFIG_AVFILTER\n        // FIXME use direct rendering\n        av_image_copy(data, linesize, (const uint8_t **)src_frame->data, src_frame->linesize,\n                        src_frame->format, vp->width, vp->height);\n#else\n        // sws_getCachedContext(...);\n#endif\n#endif\n        // FIXME: set swscale options\n        if (SDL_VoutFillFrameYUVOverlay(vp->bmp, src_frame) < 0) {\n            av_log(NULL, AV_LOG_FATAL, \"Cannot initialize the conversion context\\n\");\n            exit(1);\n        }\n        /* update the bitmap content */\n        SDL_VoutUnlockYUVOverlay(vp->bmp);\n\n        vp->pts = pts;\n        vp->duration = duration;\n        vp->pos = pos;\n        vp->serial = serial;\n        vp->sar = src_frame->sample_aspect_ratio;\n        vp->bmp->sar_num = vp->sar.num;\n        vp->bmp->sar_den = vp->sar.den;\n\n#ifdef FFP_MERGE\n        av_frame_move_ref(vp->frame, src_frame);\n#endif\n        frame_queue_push(&is->pictq);\n        if (!is->viddec.first_frame_decoded) {\n            ALOGD(\"Video: first frame decoded\\n\");\n            ffp_notify_msg1(ffp, FFP_MSG_VIDEO_DECODED_START);\n            is->viddec.first_frame_decoded_time = SDL_GetTickHR();\n            is->viddec.first_frame_decoded = 1;\n        }\n    }\n    return 0;\n}\n\nstatic int get_video_frame(FFPlayer *ffp, AVFrame *frame)\n{\n    VideoState *is = ffp->is;\n    int got_picture;\n\n    ffp_video_statistic_l(ffp);\n    if ((got_picture = decoder_decode_frame(ffp, &is->viddec, frame, NULL)) < 0)\n        return -1;\n\n    if (got_picture) {\n        double dpts = NAN;\n\n        if (frame->pts != AV_NOPTS_VALUE)\n            dpts = av_q2d(is->video_st->time_base) * frame->pts;\n\n        frame->sample_aspect_ratio = av_guess_sample_aspect_ratio(is->ic, is->video_st, frame);\n\n        if (ffp->framedrop>0 || (ffp->framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) {\n            ffp->stat.decode_frame_count++;\n            if (frame->pts != AV_NOPTS_VALUE) {\n                double diff = dpts - get_master_clock(is);\n                if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD &&\n                    diff - is->frame_last_filter_delay < 0 &&\n                    is->viddec.pkt_serial == is->vidclk.serial &&\n                    is->videoq.nb_packets) {\n                    is->frame_drops_early++;\n                    is->continuous_frame_drops_early++;\n                    if (is->continuous_frame_drops_early > ffp->framedrop) {\n                        is->continuous_frame_drops_early = 0;\n                    } else {\n                        ffp->stat.drop_frame_count++;\n                        ffp->stat.drop_frame_rate = (float)(ffp->stat.drop_frame_count) / (float)(ffp->stat.decode_frame_count);\n                        av_frame_unref(frame);\n                        got_picture = 0;\n                    }\n                }\n            }\n        }\n    }\n\n    return got_picture;\n}\n\n#if CONFIG_AVFILTER\nstatic int configure_filtergraph(AVFilterGraph *graph, const char *filtergraph,\n                                 AVFilterContext *source_ctx, AVFilterContext *sink_ctx)\n{\n    int ret, i;\n    int nb_filters = graph->nb_filters;\n    AVFilterInOut *outputs = NULL, *inputs = NULL;\n\n    if (filtergraph) {\n        outputs = avfilter_inout_alloc();\n        inputs  = avfilter_inout_alloc();\n        if (!outputs || !inputs) {\n            ret = AVERROR(ENOMEM);\n            goto fail;\n        }\n\n        outputs->name       = av_strdup(\"in\");\n        outputs->filter_ctx = source_ctx;\n        outputs->pad_idx    = 0;\n        outputs->next       = NULL;\n\n        inputs->name        = av_strdup(\"out\");\n        inputs->filter_ctx  = sink_ctx;\n        inputs->pad_idx     = 0;\n        inputs->next        = NULL;\n\n        if ((ret = avfilter_graph_parse_ptr(graph, filtergraph, &inputs, &outputs, NULL)) < 0)\n            goto fail;\n    } else {\n        if ((ret = avfilter_link(source_ctx, 0, sink_ctx, 0)) < 0)\n            goto fail;\n    }\n\n    /* Reorder the filters to ensure that inputs of the custom filters are merged first */\n    for (i = 0; i < graph->nb_filters - nb_filters; i++)\n        FFSWAP(AVFilterContext*, graph->filters[i], graph->filters[i + nb_filters]);\n\n    ret = avfilter_graph_config(graph, NULL);\nfail:\n    avfilter_inout_free(&outputs);\n    avfilter_inout_free(&inputs);\n    return ret;\n}\n\nstatic int configure_video_filters(FFPlayer *ffp, AVFilterGraph *graph, VideoState *is, const char *vfilters, AVFrame *frame)\n{\n    static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_BGRA, AV_PIX_FMT_NONE };\n    char sws_flags_str[512] = \"\";\n    char buffersrc_args[256];\n    int ret;\n    AVFilterContext *filt_src = NULL, *filt_out = NULL, *last_filter = NULL;\n    AVCodecParameters *codecpar = is->video_st->codecpar;\n    AVRational fr = av_guess_frame_rate(is->ic, is->video_st, NULL);\n    AVDictionaryEntry *e = NULL;\n\n    while ((e = av_dict_get(ffp->sws_dict, \"\", e, AV_DICT_IGNORE_SUFFIX))) {\n        if (!strcmp(e->key, \"sws_flags\")) {\n            av_strlcatf(sws_flags_str, sizeof(sws_flags_str), \"%s=%s:\", \"flags\", e->value);\n        } else\n            av_strlcatf(sws_flags_str, sizeof(sws_flags_str), \"%s=%s:\", e->key, e->value);\n    }\n    if (strlen(sws_flags_str))\n        sws_flags_str[strlen(sws_flags_str)-1] = '\\0';\n\n    graph->scale_sws_opts = av_strdup(sws_flags_str);\n\n    snprintf(buffersrc_args, sizeof(buffersrc_args),\n             \"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d\",\n             frame->width, frame->height, frame->format,\n             is->video_st->time_base.num, is->video_st->time_base.den,\n             codecpar->sample_aspect_ratio.num, FFMAX(codecpar->sample_aspect_ratio.den, 1));\n    if (fr.num && fr.den)\n        av_strlcatf(buffersrc_args, sizeof(buffersrc_args), \":frame_rate=%d/%d\", fr.num, fr.den);\n\n    if ((ret = avfilter_graph_create_filter(&filt_src,\n                                            avfilter_get_by_name(\"buffer\"),\n                                            \"ffplay_buffer\", buffersrc_args, NULL,\n                                            graph)) < 0)\n        goto fail;\n\n    ret = avfilter_graph_create_filter(&filt_out,\n                                       avfilter_get_by_name(\"buffersink\"),\n                                       \"ffplay_buffersink\", NULL, NULL, graph);\n    if (ret < 0)\n        goto fail;\n\n    if ((ret = av_opt_set_int_list(filt_out, \"pix_fmts\", pix_fmts,  AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0)\n        goto fail;\n\n    last_filter = filt_out;\n\n/* Note: this macro adds a filter before the lastly added filter, so the\n * processing order of the filters is in reverse */\n#define INSERT_FILT(name, arg) do {                                          \\\n    AVFilterContext *filt_ctx;                                               \\\n                                                                             \\\n    ret = avfilter_graph_create_filter(&filt_ctx,                            \\\n                                       avfilter_get_by_name(name),           \\\n                                       \"ffplay_\" name, arg, NULL, graph);    \\\n    if (ret < 0)                                                             \\\n        goto fail;                                                           \\\n                                                                             \\\n    ret = avfilter_link(filt_ctx, 0, last_filter, 0);                        \\\n    if (ret < 0)                                                             \\\n        goto fail;                                                           \\\n                                                                             \\\n    last_filter = filt_ctx;                                                  \\\n} while (0)\n\n    if (ffp->autorotate) {\n        double theta  = get_rotation(is->video_st);\n\n        if (fabs(theta - 90) < 1.0) {\n            INSERT_FILT(\"transpose\", \"clock\");\n        } else if (fabs(theta - 180) < 1.0) {\n            INSERT_FILT(\"hflip\", NULL);\n            INSERT_FILT(\"vflip\", NULL);\n        } else if (fabs(theta - 270) < 1.0) {\n            INSERT_FILT(\"transpose\", \"cclock\");\n        } else if (fabs(theta) > 1.0) {\n            char rotate_buf[64];\n            snprintf(rotate_buf, sizeof(rotate_buf), \"%f*PI/180\", theta);\n            INSERT_FILT(\"rotate\", rotate_buf);\n        }\n    }\n\n#ifdef FFP_AVFILTER_PLAYBACK_RATE\n    if (fabsf(ffp->pf_playback_rate) > 0.00001 &&\n        fabsf(ffp->pf_playback_rate - 1.0f) > 0.00001) {\n        char setpts_buf[256];\n        float rate = 1.0f / ffp->pf_playback_rate;\n        rate = av_clipf_c(rate, 0.5f, 2.0f);\n        av_log(ffp, AV_LOG_INFO, \"vf_rate=%f(1/%f)\\n\", ffp->pf_playback_rate, rate);\n        snprintf(setpts_buf, sizeof(setpts_buf), \"%f*PTS\", rate);\n        INSERT_FILT(\"setpts\", setpts_buf);\n    }\n#endif\n\n    if ((ret = configure_filtergraph(graph, vfilters, filt_src, last_filter)) < 0)\n        goto fail;\n\n    is->in_video_filter  = filt_src;\n    is->out_video_filter = filt_out;\n\nfail:\n    return ret;\n}\n\nstatic int configure_audio_filters(FFPlayer *ffp, const char *afilters, int force_output_format)\n{\n    VideoState *is = ffp->is;\n    static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE };\n    int sample_rates[2] = { 0, -1 };\n    int64_t channel_layouts[2] = { 0, -1 };\n    int channels[2] = { 0, -1 };\n    AVFilterContext *filt_asrc = NULL, *filt_asink = NULL;\n    char aresample_swr_opts[512] = \"\";\n    AVDictionaryEntry *e = NULL;\n    char asrc_args[256];\n    int ret;\n    char afilters_args[4096];\n\n    avfilter_graph_free(&is->agraph);\n    if (!(is->agraph = avfilter_graph_alloc()))\n        return AVERROR(ENOMEM);\n\n    while ((e = av_dict_get(ffp->swr_opts, \"\", e, AV_DICT_IGNORE_SUFFIX)))\n        av_strlcatf(aresample_swr_opts, sizeof(aresample_swr_opts), \"%s=%s:\", e->key, e->value);\n    if (strlen(aresample_swr_opts))\n        aresample_swr_opts[strlen(aresample_swr_opts)-1] = '\\0';\n    av_opt_set(is->agraph, \"aresample_swr_opts\", aresample_swr_opts, 0);\n\n    ret = snprintf(asrc_args, sizeof(asrc_args),\n                   \"sample_rate=%d:sample_fmt=%s:channels=%d:time_base=%d/%d\",\n                   is->audio_filter_src.freq, av_get_sample_fmt_name(is->audio_filter_src.fmt),\n                   is->audio_filter_src.channels,\n                   1, is->audio_filter_src.freq);\n    if (is->audio_filter_src.channel_layout)\n        snprintf(asrc_args + ret, sizeof(asrc_args) - ret,\n                 \":channel_layout=0x%\"PRIx64,  is->audio_filter_src.channel_layout);\n\n    ret = avfilter_graph_create_filter(&filt_asrc,\n                                       avfilter_get_by_name(\"abuffer\"), \"ffplay_abuffer\",\n                                       asrc_args, NULL, is->agraph);\n    if (ret < 0)\n        goto end;\n\n\n    ret = avfilter_graph_create_filter(&filt_asink,\n                                       avfilter_get_by_name(\"abuffersink\"), \"ffplay_abuffersink\",\n                                       NULL, NULL, is->agraph);\n    if (ret < 0)\n        goto end;\n\n    if ((ret = av_opt_set_int_list(filt_asink, \"sample_fmts\", sample_fmts,  AV_SAMPLE_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0)\n        goto end;\n    if ((ret = av_opt_set_int(filt_asink, \"all_channel_counts\", 1, AV_OPT_SEARCH_CHILDREN)) < 0)\n        goto end;\n\n    if (force_output_format) {\n        channel_layouts[0] = is->audio_tgt.channel_layout;\n        channels       [0] = is->audio_tgt.channels;\n        sample_rates   [0] = is->audio_tgt.freq;\n        if ((ret = av_opt_set_int(filt_asink, \"all_channel_counts\", 0, AV_OPT_SEARCH_CHILDREN)) < 0)\n            goto end;\n        if ((ret = av_opt_set_int_list(filt_asink, \"channel_layouts\", channel_layouts,  -1, AV_OPT_SEARCH_CHILDREN)) < 0)\n            goto end;\n        if ((ret = av_opt_set_int_list(filt_asink, \"channel_counts\" , channels       ,  -1, AV_OPT_SEARCH_CHILDREN)) < 0)\n            goto end;\n        if ((ret = av_opt_set_int_list(filt_asink, \"sample_rates\"   , sample_rates   ,  -1, AV_OPT_SEARCH_CHILDREN)) < 0)\n            goto end;\n    }\n\n    afilters_args[0] = 0;\n    if (afilters)\n        snprintf(afilters_args, sizeof(afilters_args), \"%s\", afilters);\n\n#ifdef FFP_AVFILTER_PLAYBACK_RATE\n    if (fabsf(ffp->pf_playback_rate) > 0.00001 &&\n        fabsf(ffp->pf_playback_rate - 1.0f) > 0.00001) {\n        if (afilters_args[0])\n            av_strlcatf(afilters_args, sizeof(afilters_args), \",\");\n\n        av_log(ffp, AV_LOG_INFO, \"af_rate=%f\\n\", ffp->pf_playback_rate);\n        av_strlcatf(afilters_args, sizeof(afilters_args), \"atempo=%f\", ffp->pf_playback_rate);\n    }\n#endif\n\n    if ((ret = configure_filtergraph(is->agraph, afilters_args[0] ? afilters_args : NULL, filt_asrc, filt_asink)) < 0)\n        goto end;\n\n    is->in_audio_filter  = filt_asrc;\n    is->out_audio_filter = filt_asink;\n\nend:\n    if (ret < 0)\n        avfilter_graph_free(&is->agraph);\n    return ret;\n}\n#endif  /* CONFIG_AVFILTER */\n\nstatic int audio_thread(void *arg)\n{\n    FFPlayer *ffp = arg;\n    VideoState *is = ffp->is;\n    AVFrame *frame = av_frame_alloc();\n    Frame *af;\n#if CONFIG_AVFILTER\n    int last_serial = -1;\n    int64_t dec_channel_layout;\n    int reconfigure;\n#endif\n    int got_frame = 0;\n    AVRational tb;\n    int ret = 0;\n    int audio_accurate_seek_fail = 0;\n    int64_t audio_seek_pos = 0;\n    double frame_pts = 0;\n    double audio_clock = 0;\n    int64_t now = 0;\n    double samples_duration = 0;\n    int64_t deviation = 0;\n    int64_t deviation2 = 0;\n    int64_t deviation3 = 0;\n\n    if (!frame)\n        return AVERROR(ENOMEM);\n\n    do {\n        ffp_audio_statistic_l(ffp);\n        if ((got_frame = decoder_decode_frame(ffp, &is->auddec, frame, NULL)) < 0)\n            goto the_end;\n\n        if (got_frame) {\n                tb = (AVRational){1, frame->sample_rate};\n                if (ffp->enable_accurate_seek && is->audio_accurate_seek_req && !is->seek_req) {\n                    frame_pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb);\n                    now = av_gettime_relative() / 1000;\n                    if (!isnan(frame_pts)) {\n                        samples_duration = (double) frame->nb_samples / frame->sample_rate;\n                        audio_clock = frame_pts + samples_duration;\n                        is->accurate_seek_aframe_pts = audio_clock * 1000 * 1000;\n                        audio_seek_pos = is->seek_pos;\n                        deviation = llabs((int64_t)(audio_clock * 1000 * 1000) - is->seek_pos);\n                        if ((audio_clock * 1000 * 1000 < is->seek_pos ) || deviation > MAX_DEVIATION) {\n                            if (is->drop_aframe_count == 0) {\n                                SDL_LockMutex(is->accurate_seek_mutex);\n                                if (is->accurate_seek_start_time <= 0 && (is->video_stream < 0 || is->video_accurate_seek_req)) {\n                                    is->accurate_seek_start_time = now;\n                                }\n                                SDL_UnlockMutex(is->accurate_seek_mutex);\n                                av_log(NULL, AV_LOG_INFO, \"audio accurate_seek start, is->seek_pos=%lld, audio_clock=%lf, is->accurate_seek_start_time = %lld\\n\", is->seek_pos, audio_clock, is->accurate_seek_start_time);\n                            }\n                            is->drop_aframe_count++;\n                            while (is->video_accurate_seek_req && !is->abort_request) {\n                                int64_t vpts = is->accurate_seek_vframe_pts;\n                                deviation2 = vpts  - audio_clock * 1000 * 1000;\n                                deviation3 = vpts  - is->seek_pos;\n                                if (deviation2 > -100 * 1000 && deviation3 < 0) {\n\n                                    break;\n                                } else {\n                                    av_usleep(20 * 1000);\n                                }\n                                now = av_gettime_relative() / 1000;\n                                if ((now - is->accurate_seek_start_time) > ffp->accurate_seek_timeout) {\n                                    break;\n                                }\n                            }\n\n                            if(!is->video_accurate_seek_req && is->video_stream >= 0 && audio_clock * 1000 * 1000 > is->accurate_seek_vframe_pts) {\n                                audio_accurate_seek_fail = 1;\n                            } else {\n                                now = av_gettime_relative() / 1000;\n                                if ((now - is->accurate_seek_start_time) <= ffp->accurate_seek_timeout) {\n                                    av_frame_unref(frame);\n                                    continue;  // drop some old frame when do accurate seek\n                                } else {\n                                    audio_accurate_seek_fail = 1;\n                                }\n                            }\n                        } else {\n                            if (audio_seek_pos == is->seek_pos) {\n                                av_log(NULL, AV_LOG_INFO, \"audio accurate_seek is ok, is->drop_aframe_count=%d, audio_clock = %lf\\n\", is->drop_aframe_count, audio_clock);\n                                is->drop_aframe_count       = 0;\n                                SDL_LockMutex(is->accurate_seek_mutex);\n                                is->audio_accurate_seek_req = 0;\n                                SDL_CondSignal(is->video_accurate_seek_cond);\n                                if (audio_seek_pos == is->seek_pos && is->video_accurate_seek_req && !is->abort_request) {\n                                    SDL_CondWaitTimeout(is->audio_accurate_seek_cond, is->accurate_seek_mutex, ffp->accurate_seek_timeout);\n                                } else {\n                                    ffp_notify_msg2(ffp, FFP_MSG_ACCURATE_SEEK_COMPLETE, (int)(audio_clock * 1000));\n                                }\n\n                                if (audio_seek_pos != is->seek_pos && !is->abort_request) {\n                                    is->audio_accurate_seek_req = 1;\n                                    SDL_UnlockMutex(is->accurate_seek_mutex);\n                                    av_frame_unref(frame);\n                                    continue;\n                                }\n\n                                SDL_UnlockMutex(is->accurate_seek_mutex);\n                            }\n                        }\n                    } else {\n                        audio_accurate_seek_fail = 1;\n                    }\n                    if (audio_accurate_seek_fail) {\n                        av_log(NULL, AV_LOG_INFO, \"audio accurate_seek is error, is->drop_aframe_count=%d, now = %lld, audio_clock = %lf\\n\", is->drop_aframe_count, now, audio_clock);\n                        is->drop_aframe_count       = 0;\n                        SDL_LockMutex(is->accurate_seek_mutex);\n                        is->audio_accurate_seek_req = 0;\n                        SDL_CondSignal(is->video_accurate_seek_cond);\n                        if (is->video_accurate_seek_req && !is->abort_request) {\n                            SDL_CondWaitTimeout(is->audio_accurate_seek_cond, is->accurate_seek_mutex, ffp->accurate_seek_timeout);\n                        } else {\n                            ffp_notify_msg2(ffp, FFP_MSG_ACCURATE_SEEK_COMPLETE, (int)(audio_clock * 1000));\n                        }\n                        SDL_UnlockMutex(is->accurate_seek_mutex);\n                    }\n                    is->accurate_seek_start_time = 0;\n                    audio_accurate_seek_fail = 0;\n                }\n\n#if CONFIG_AVFILTER\n                dec_channel_layout = get_valid_channel_layout(frame->channel_layout, frame->channels);\n\n                reconfigure =\n                    cmp_audio_fmts(is->audio_filter_src.fmt, is->audio_filter_src.channels,\n                                   frame->format, frame->channels)    ||\n                    is->audio_filter_src.channel_layout != dec_channel_layout ||\n                    is->audio_filter_src.freq           != frame->sample_rate ||\n                    is->auddec.pkt_serial               != last_serial        ||\n                    ffp->af_changed;\n\n                if (reconfigure) {\n                    SDL_LockMutex(ffp->af_mutex);\n                    ffp->af_changed = 0;\n                    char buf1[1024], buf2[1024];\n                    av_get_channel_layout_string(buf1, sizeof(buf1), -1, is->audio_filter_src.channel_layout);\n                    av_get_channel_layout_string(buf2, sizeof(buf2), -1, dec_channel_layout);\n                    av_log(NULL, AV_LOG_DEBUG,\n                           \"Audio frame changed from rate:%d ch:%d fmt:%s layout:%s serial:%d to rate:%d ch:%d fmt:%s layout:%s serial:%d\\n\",\n                           is->audio_filter_src.freq, is->audio_filter_src.channels, av_get_sample_fmt_name(is->audio_filter_src.fmt), buf1, last_serial,\n                           frame->sample_rate, frame->channels, av_get_sample_fmt_name(frame->format), buf2, is->auddec.pkt_serial);\n\n                    is->audio_filter_src.fmt            = frame->format;\n                    is->audio_filter_src.channels       = frame->channels;\n                    is->audio_filter_src.channel_layout = dec_channel_layout;\n                    is->audio_filter_src.freq           = frame->sample_rate;\n                    last_serial                         = is->auddec.pkt_serial;\n\n                    if ((ret = configure_audio_filters(ffp, ffp->afilters, 1)) < 0) {\n                        SDL_UnlockMutex(ffp->af_mutex);\n                        goto the_end;\n                    }\n                    SDL_UnlockMutex(ffp->af_mutex);\n                }\n\n            if ((ret = av_buffersrc_add_frame(is->in_audio_filter, frame)) < 0)\n                goto the_end;\n\n            while ((ret = av_buffersink_get_frame_flags(is->out_audio_filter, frame, 0)) >= 0) {\n                tb = av_buffersink_get_time_base(is->out_audio_filter);\n#endif\n                if (!(af = frame_queue_peek_writable(&is->sampq)))\n                    goto the_end;\n\n                af->pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb);\n                af->pos = frame->pkt_pos;\n                af->serial = is->auddec.pkt_serial;\n                af->duration = av_q2d((AVRational){frame->nb_samples, frame->sample_rate});\n\n                av_frame_move_ref(af->frame, frame);\n                frame_queue_push(&is->sampq);\n\n#if CONFIG_AVFILTER\n                if (is->audioq.serial != is->auddec.pkt_serial)\n                    break;\n            }\n            if (ret == AVERROR_EOF)\n                is->auddec.finished = is->auddec.pkt_serial;\n#endif\n        }\n    } while (ret >= 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF);\n the_end:\n#if CONFIG_AVFILTER\n    avfilter_graph_free(&is->agraph);\n#endif\n    av_frame_free(&frame);\n    return ret;\n}\n\nstatic int decoder_start(Decoder *d, int (*fn)(void *), void *arg, const char *name)\n{\n    packet_queue_start(d->queue);\n    d->decoder_tid = SDL_CreateThreadEx(&d->_decoder_tid, fn, arg, name);\n    if (!d->decoder_tid) {\n        av_log(NULL, AV_LOG_ERROR, \"SDL_CreateThread(): %s\\n\", SDL_GetError());\n        return AVERROR(ENOMEM);\n    }\n    return 0;\n}\n\nstatic int ffplay_video_thread(void *arg)\n{\n    FFPlayer *ffp = arg;\n    VideoState *is = ffp->is;\n    AVFrame *frame = av_frame_alloc();\n    double pts;\n    double duration;\n    int ret;\n    AVRational tb = is->video_st->time_base;\n    AVRational frame_rate = av_guess_frame_rate(is->ic, is->video_st, NULL);\n    int64_t dst_pts = -1;\n    int64_t last_dst_pts = -1;\n    int retry_convert_image = 0;\n    int convert_frame_count = 0;\n\n#if CONFIG_AVFILTER\n    AVFilterGraph *graph = avfilter_graph_alloc();\n    AVFilterContext *filt_out = NULL, *filt_in = NULL;\n    int last_w = 0;\n    int last_h = 0;\n    enum AVPixelFormat last_format = -2;\n    int last_serial = -1;\n    int last_vfilter_idx = 0;\n    if (!graph) {\n        av_frame_free(&frame);\n        return AVERROR(ENOMEM);\n    }\n\n#else\n    ffp_notify_msg2(ffp, FFP_MSG_VIDEO_ROTATION_CHANGED, ffp_get_video_rotate_degrees(ffp));\n#endif\n\n    if (!frame) {\n#if CONFIG_AVFILTER\n        avfilter_graph_free(&graph);\n#endif\n        return AVERROR(ENOMEM);\n    }\n\n    for (;;) {\n        ret = get_video_frame(ffp, frame);\n        if (ret < 0)\n            goto the_end;\n        if (!ret)\n            continue;\n\n        if (ffp->get_frame_mode) {\n            if (!ffp->get_img_info || ffp->get_img_info->count <= 0) {\n                av_frame_unref(frame);\n                continue;\n            }\n\n            last_dst_pts = dst_pts;\n\n            if (dst_pts < 0) {\n                dst_pts = ffp->get_img_info->start_time;\n            } else {\n                dst_pts += (ffp->get_img_info->end_time - ffp->get_img_info->start_time) / (ffp->get_img_info->num - 1);\n            }\n\n            pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb);\n            pts = pts * 1000;\n            if (pts >= dst_pts) {\n                while (retry_convert_image <= MAX_RETRY_CONVERT_IMAGE) {\n                    ret = convert_image(ffp, frame, (int64_t)pts, frame->width, frame->height);\n                    if (!ret) {\n                        convert_frame_count++;\n                        break;\n                    }\n                    retry_convert_image++;\n                    av_log(NULL, AV_LOG_ERROR, \"convert image error retry_convert_image = %d\\n\", retry_convert_image);\n                }\n\n                retry_convert_image = 0;\n                if (ret || ffp->get_img_info->count <= 0) {\n                    if (ret) {\n                        av_log(NULL, AV_LOG_ERROR, \"convert image abort ret = %d\\n\", ret);\n                        ffp_notify_msg3(ffp, FFP_MSG_GET_IMG_STATE, 0, ret);\n                    } else {\n                        av_log(NULL, AV_LOG_INFO, \"convert image complete convert_frame_count = %d\\n\", convert_frame_count);\n                    }\n                    goto the_end;\n                }\n            } else {\n                dst_pts = last_dst_pts;\n            }\n            av_frame_unref(frame);\n            continue;\n        }\n\n#if CONFIG_AVFILTER\n        if (   last_w != frame->width\n            || last_h != frame->height\n            || last_format != frame->format\n            || last_serial != is->viddec.pkt_serial\n            || ffp->vf_changed\n            || last_vfilter_idx != is->vfilter_idx) {\n            SDL_LockMutex(ffp->vf_mutex);\n            ffp->vf_changed = 0;\n            av_log(NULL, AV_LOG_DEBUG,\n                   \"Video frame changed from size:%dx%d format:%s serial:%d to size:%dx%d format:%s serial:%d\\n\",\n                   last_w, last_h,\n                   (const char *)av_x_if_null(av_get_pix_fmt_name(last_format), \"none\"), last_serial,\n                   frame->width, frame->height,\n                   (const char *)av_x_if_null(av_get_pix_fmt_name(frame->format), \"none\"), is->viddec.pkt_serial);\n            avfilter_graph_free(&graph);\n            graph = avfilter_graph_alloc();\n            if ((ret = configure_video_filters(ffp, graph, is, ffp->vfilters_list ? ffp->vfilters_list[is->vfilter_idx] : NULL, frame)) < 0) {\n                // FIXME: post error\n                SDL_UnlockMutex(ffp->vf_mutex);\n                goto the_end;\n            }\n            filt_in  = is->in_video_filter;\n            filt_out = is->out_video_filter;\n            last_w = frame->width;\n            last_h = frame->height;\n            last_format = frame->format;\n            last_serial = is->viddec.pkt_serial;\n            last_vfilter_idx = is->vfilter_idx;\n            frame_rate = av_buffersink_get_frame_rate(filt_out);\n            SDL_UnlockMutex(ffp->vf_mutex);\n        }\n\n        ret = av_buffersrc_add_frame(filt_in, frame);\n        if (ret < 0)\n            goto the_end;\n\n        while (ret >= 0) {\n            is->frame_last_returned_time = av_gettime_relative() / 1000000.0;\n\n            ret = av_buffersink_get_frame_flags(filt_out, frame, 0);\n            if (ret < 0) {\n                if (ret == AVERROR_EOF)\n                    is->viddec.finished = is->viddec.pkt_serial;\n                ret = 0;\n                break;\n            }\n\n            is->frame_last_filter_delay = av_gettime_relative() / 1000000.0 - is->frame_last_returned_time;\n            if (fabs(is->frame_last_filter_delay) > AV_NOSYNC_THRESHOLD / 10.0)\n                is->frame_last_filter_delay = 0;\n            tb = av_buffersink_get_time_base(filt_out);\n#endif\n            duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational){frame_rate.den, frame_rate.num}) : 0);\n            pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb);\n            ret = queue_picture(ffp, frame, pts, duration, frame->pkt_pos, is->viddec.pkt_serial);\n            av_frame_unref(frame);\n#if CONFIG_AVFILTER\n        }\n#endif\n\n        if (ret < 0)\n            goto the_end;\n    }\n the_end:\n#if CONFIG_AVFILTER\n    avfilter_graph_free(&graph);\n#endif\n    av_log(NULL, AV_LOG_INFO, \"convert image convert_frame_count = %d\\n\", convert_frame_count);\n    av_frame_free(&frame);\n    return 0;\n}\n\nstatic int video_thread(void *arg)\n{\n    FFPlayer *ffp = (FFPlayer *)arg;\n    int       ret = 0;\n\n    if (ffp->node_vdec) {\n        ret = ffpipenode_run_sync(ffp->node_vdec);\n    }\n    return ret;\n}\n\nstatic int subtitle_thread(void *arg)\n{\n    FFPlayer *ffp = arg;\n    VideoState *is = ffp->is;\n    Frame *sp;\n    int got_subtitle;\n    double pts;\n\n    for (;;) {\n        if (!(sp = frame_queue_peek_writable(&is->subpq)))\n            return 0;\n\n        if ((got_subtitle = decoder_decode_frame(ffp, &is->subdec, NULL, &sp->sub)) < 0)\n            break;\n\n        pts = 0;\n#ifdef FFP_MERGE\n        if (got_subtitle && sp->sub.format == 0) {\n#else\n        if (got_subtitle) {\n#endif\n            if (sp->sub.pts != AV_NOPTS_VALUE)\n                pts = sp->sub.pts / (double)AV_TIME_BASE;\n            sp->pts = pts;\n            sp->serial = is->subdec.pkt_serial;\n            sp->width = is->subdec.avctx->width;\n            sp->height = is->subdec.avctx->height;\n            sp->uploaded = 0;\n\n            /* now we can update the picture count */\n            frame_queue_push(&is->subpq);\n#ifdef FFP_MERGE\n        } else if (got_subtitle) {\n            avsubtitle_free(&sp->sub);\n#endif\n        }\n    }\n    return 0;\n}\n\n/* copy samples for viewing in editor window */\nstatic void update_sample_display(VideoState *is, short *samples, int samples_size)\n{\n    int size, len;\n\n    size = samples_size / sizeof(short);\n    while (size > 0) {\n        len = SAMPLE_ARRAY_SIZE - is->sample_array_index;\n        if (len > size)\n            len = size;\n        memcpy(is->sample_array + is->sample_array_index, samples, len * sizeof(short));\n        samples += len;\n        is->sample_array_index += len;\n        if (is->sample_array_index >= SAMPLE_ARRAY_SIZE)\n            is->sample_array_index = 0;\n        size -= len;\n    }\n}\n\n/* return the wanted number of samples to get better sync if sync_type is video\n * or external master clock */\nstatic int synchronize_audio(VideoState *is, int nb_samples)\n{\n    int wanted_nb_samples = nb_samples;\n\n    /* if not master, then we try to remove or add samples to correct the clock */\n    if (get_master_sync_type(is) != AV_SYNC_AUDIO_MASTER) {\n        double diff, avg_diff;\n        int min_nb_samples, max_nb_samples;\n\n        diff = get_clock(&is->audclk) - get_master_clock(is);\n\n        if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD) {\n            is->audio_diff_cum = diff + is->audio_diff_avg_coef * is->audio_diff_cum;\n            if (is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) {\n                /* not enough measures to have a correct estimate */\n                is->audio_diff_avg_count++;\n            } else {\n                /* estimate the A-V difference */\n                avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef);\n\n                if (fabs(avg_diff) >= is->audio_diff_threshold) {\n                    wanted_nb_samples = nb_samples + (int)(diff * is->audio_src.freq);\n                    min_nb_samples = ((nb_samples * (100 - SAMPLE_CORRECTION_PERCENT_MAX) / 100));\n                    max_nb_samples = ((nb_samples * (100 + SAMPLE_CORRECTION_PERCENT_MAX) / 100));\n                    wanted_nb_samples = av_clip(wanted_nb_samples, min_nb_samples, max_nb_samples);\n                }\n                av_log(NULL, AV_LOG_TRACE, \"diff=%f adiff=%f sample_diff=%d apts=%0.3f %f\\n\",\n                        diff, avg_diff, wanted_nb_samples - nb_samples,\n                        is->audio_clock, is->audio_diff_threshold);\n            }\n        } else {\n            /* too big difference : may be initial PTS errors, so\n               reset A-V filter */\n            is->audio_diff_avg_count = 0;\n            is->audio_diff_cum       = 0;\n        }\n    }\n\n    return wanted_nb_samples;\n}\n\n/**\n * Decode one audio frame and return its uncompressed size.\n *\n * The processed audio frame is decoded, converted if required, and\n * stored in is->audio_buf, with size in bytes given by the return\n * value.\n */\nstatic int audio_decode_frame(FFPlayer *ffp)\n{\n    VideoState *is = ffp->is;\n    int data_size, resampled_data_size;\n    int64_t dec_channel_layout;\n    av_unused double audio_clock0;\n    int wanted_nb_samples;\n    Frame *af;\n#if defined(__ANDROID__)\n    int translate_time = 1;\n#endif\n\n    if (is->paused || is->step)\n        return -1;\n\n    if (ffp->sync_av_start &&                       /* sync enabled */\n        is->video_st &&                             /* has video stream */\n        !is->viddec.first_frame_decoded &&          /* not hot */\n        is->viddec.finished != is->videoq.serial) { /* not finished */\n        /* waiting for first video frame */\n        Uint64 now = SDL_GetTickHR();\n        if (now < is->viddec.first_frame_decoded_time ||\n            now > is->viddec.first_frame_decoded_time + 2000) {\n            is->viddec.first_frame_decoded = 1;\n        } else {\n            /* video pipeline is not ready yet */\n            return -1;\n        }\n    }\nreload:\n    do {\n#if defined(_WIN32) || defined(__APPLE__)\n        while (frame_queue_nb_remaining(&is->sampq) == 0) {\n            if ((av_gettime_relative() - ffp->audio_callback_time) > 1000000LL * is->audio_hw_buf_size / is->audio_tgt.bytes_per_sec / 2)\n                return -1;\n            av_usleep (1000);\n        }\n#endif\n        if (!(af = frame_queue_peek_readable(&is->sampq)))\n            return -1;\n        frame_queue_next(&is->sampq);\n    } while (af->serial != is->audioq.serial);\n\n    data_size = av_samples_get_buffer_size(NULL, af->frame->channels,\n                                           af->frame->nb_samples,\n                                           af->frame->format, 1);\n\n    dec_channel_layout =\n        (af->frame->channel_layout && af->frame->channels == av_get_channel_layout_nb_channels(af->frame->channel_layout)) ?\n        af->frame->channel_layout : av_get_default_channel_layout(af->frame->channels);\n    wanted_nb_samples = synchronize_audio(is, af->frame->nb_samples);\n\n    if (af->frame->format        != is->audio_src.fmt            ||\n        dec_channel_layout       != is->audio_src.channel_layout ||\n        af->frame->sample_rate   != is->audio_src.freq           ||\n        (wanted_nb_samples       != af->frame->nb_samples && !is->swr_ctx)) {\n        AVDictionary *swr_opts = NULL;\n        swr_free(&is->swr_ctx);\n        is->swr_ctx = swr_alloc_set_opts(NULL,\n                                         is->audio_tgt.channel_layout, is->audio_tgt.fmt, is->audio_tgt.freq,\n                                         dec_channel_layout,           af->frame->format, af->frame->sample_rate,\n                                         0, NULL);\n        if (!is->swr_ctx) {\n            av_log(NULL, AV_LOG_ERROR,\n                   \"Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\\n\",\n                    af->frame->sample_rate, av_get_sample_fmt_name(af->frame->format), af->frame->channels,\n                    is->audio_tgt.freq, av_get_sample_fmt_name(is->audio_tgt.fmt), is->audio_tgt.channels);\n            return -1;\n        }\n        av_dict_copy(&swr_opts, ffp->swr_opts, 0);\n        if (af->frame->channel_layout == AV_CH_LAYOUT_5POINT1_BACK)\n            av_opt_set_double(is->swr_ctx, \"center_mix_level\", ffp->preset_5_1_center_mix_level, 0);\n        av_opt_set_dict(is->swr_ctx, &swr_opts);\n        av_dict_free(&swr_opts);\n\n        if (swr_init(is->swr_ctx) < 0) {\n            av_log(NULL, AV_LOG_ERROR,\n                   \"Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\\n\",\n                    af->frame->sample_rate, av_get_sample_fmt_name(af->frame->format), af->frame->channels,\n                    is->audio_tgt.freq, av_get_sample_fmt_name(is->audio_tgt.fmt), is->audio_tgt.channels);\n            swr_free(&is->swr_ctx);\n            return -1;\n        }\n        is->audio_src.channel_layout = dec_channel_layout;\n        is->audio_src.channels       = af->frame->channels;\n        is->audio_src.freq = af->frame->sample_rate;\n        is->audio_src.fmt = af->frame->format;\n    }\n\n    if (is->swr_ctx) {\n        const uint8_t **in = (const uint8_t **)af->frame->extended_data;\n        uint8_t **out = &is->audio_buf1;\n        int out_count = (int)((int64_t)wanted_nb_samples * is->audio_tgt.freq / af->frame->sample_rate + 256);\n        int out_size  = av_samples_get_buffer_size(NULL, is->audio_tgt.channels, out_count, is->audio_tgt.fmt, 0);\n        int len2;\n        if (out_size < 0) {\n            av_log(NULL, AV_LOG_ERROR, \"av_samples_get_buffer_size() failed\\n\");\n            return -1;\n        }\n        if (wanted_nb_samples != af->frame->nb_samples) {\n            if (swr_set_compensation(is->swr_ctx, (wanted_nb_samples - af->frame->nb_samples) * is->audio_tgt.freq / af->frame->sample_rate,\n                                        wanted_nb_samples * is->audio_tgt.freq / af->frame->sample_rate) < 0) {\n                av_log(NULL, AV_LOG_ERROR, \"swr_set_compensation() failed\\n\");\n                return -1;\n            }\n        }\n        av_fast_malloc(&is->audio_buf1, &is->audio_buf1_size, out_size);\n\n        if (!is->audio_buf1)\n            return AVERROR(ENOMEM);\n        len2 = swr_convert(is->swr_ctx, out, out_count, in, af->frame->nb_samples);\n        if (len2 < 0) {\n            av_log(NULL, AV_LOG_ERROR, \"swr_convert() failed\\n\");\n            return -1;\n        }\n        if (len2 == out_count) {\n            av_log(NULL, AV_LOG_WARNING, \"audio buffer is probably too small\\n\");\n            if (swr_init(is->swr_ctx) < 0)\n                swr_free(&is->swr_ctx);\n        }\n        is->audio_buf = is->audio_buf1;\n        int bytes_per_sample = av_get_bytes_per_sample(is->audio_tgt.fmt);\n        resampled_data_size = len2 * is->audio_tgt.channels * bytes_per_sample;\n#if defined(__ANDROID__)\n        if (ffp->soundtouch_enable && ffp->pf_playback_rate != 1.0f && !is->abort_request) {\n            av_fast_malloc(&is->audio_new_buf, &is->audio_new_buf_size, out_size * translate_time);\n            for (int i = 0; i < (resampled_data_size / 2); i++)\n            {\n                is->audio_new_buf[i] = (is->audio_buf1[i * 2] | (is->audio_buf1[i * 2 + 1] << 8));\n            }\n\n            int ret_len = ijk_soundtouch_translate(is->handle, is->audio_new_buf, (float)(ffp->pf_playback_rate), (float)(1.0f/ffp->pf_playback_rate),\n                    resampled_data_size / 2, bytes_per_sample, is->audio_tgt.channels, af->frame->sample_rate);\n            if (ret_len > 0) {\n                is->audio_buf = (uint8_t*)is->audio_new_buf;\n                resampled_data_size = ret_len;\n            } else {\n                translate_time++;\n                goto reload;\n            }\n        }\n#endif\n    } else {\n        is->audio_buf = af->frame->data[0];\n        resampled_data_size = data_size;\n    }\n\n    audio_clock0 = is->audio_clock;\n    /* update the audio clock with the pts */\n    if (!isnan(af->pts))\n        is->audio_clock = af->pts + (double) af->frame->nb_samples / af->frame->sample_rate;\n    else\n        is->audio_clock = NAN;\n    is->audio_clock_serial = af->serial;\n#ifdef FFP_SHOW_AUDIO_DELAY\n    {\n        static double last_clock;\n        printf(\"audio: delay=%0.3f clock=%0.3f clock0=%0.3f\\n\",\n               is->audio_clock - last_clock,\n               is->audio_clock, audio_clock0);\n        last_clock = is->audio_clock;\n    }\n#endif\n    if (!is->auddec.first_frame_decoded) {\n        ALOGD(\"avcodec/Audio: first frame decoded\\n\");\n        ffp_notify_msg1(ffp, FFP_MSG_AUDIO_DECODED_START);\n        is->auddec.first_frame_decoded_time = SDL_GetTickHR();\n        is->auddec.first_frame_decoded = 1;\n    }\n    return resampled_data_size;\n}\n\n/* prepare a new audio buffer */\nstatic void sdl_audio_callback(void *opaque, Uint8 *stream, int len)\n{\n    FFPlayer *ffp = opaque;\n    VideoState *is = ffp->is;\n    int audio_size, len1;\n    if (!ffp || !is) {\n        memset(stream, 0, len);\n        return;\n    }\n\n    ffp->audio_callback_time = av_gettime_relative();\n\n    if (ffp->pf_playback_rate_changed) {\n        ffp->pf_playback_rate_changed = 0;\n#if defined(__ANDROID__)\n        if (!ffp->soundtouch_enable) {\n            SDL_AoutSetPlaybackRate(ffp->aout, ffp->pf_playback_rate);\n        }\n#else\n        SDL_AoutSetPlaybackRate(ffp->aout, ffp->pf_playback_rate);\n#endif\n    }\n    if (ffp->pf_playback_volume_changed) {\n        ffp->pf_playback_volume_changed = 0;\n        SDL_AoutSetPlaybackVolume(ffp->aout, ffp->pf_playback_volume);\n    }\n\n    while (len > 0) {\n        if (is->audio_buf_index >= is->audio_buf_size) {\n           audio_size = audio_decode_frame(ffp);\n           if (audio_size < 0) {\n                /* if error, just output silence */\n               is->audio_buf = NULL;\n               is->audio_buf_size = SDL_AUDIO_MIN_BUFFER_SIZE / is->audio_tgt.frame_size * is->audio_tgt.frame_size;\n           } else {\n               if (is->show_mode != SHOW_MODE_VIDEO)\n                   update_sample_display(is, (int16_t *)is->audio_buf, audio_size);\n               is->audio_buf_size = audio_size;\n           }\n           is->audio_buf_index = 0;\n        }\n        if (is->auddec.pkt_serial != is->audioq.serial) {\n            is->audio_buf_index = is->audio_buf_size;\n            memset(stream, 0, len);\n            // stream += len;\n            // len = 0;\n            SDL_AoutFlushAudio(ffp->aout);\n            break;\n        }\n        len1 = is->audio_buf_size - is->audio_buf_index;\n        if (len1 > len)\n            len1 = len;\n        if (!is->muted && is->audio_buf && is->audio_volume == SDL_MIX_MAXVOLUME)\n            memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);\n        else {\n            memset(stream, 0, len1);\n            if (!is->muted && is->audio_buf)\n                SDL_MixAudio(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1, is->audio_volume);\n        }\n        len -= len1;\n        stream += len1;\n        is->audio_buf_index += len1;\n    }\n    is->audio_write_buf_size = is->audio_buf_size - is->audio_buf_index;\n    /* Let's assume the audio driver that is used by SDL has two periods. */\n    if (!isnan(is->audio_clock)) {\n        set_clock_at(&is->audclk, is->audio_clock - (double)(is->audio_write_buf_size) / is->audio_tgt.bytes_per_sec - SDL_AoutGetLatencySeconds(ffp->aout), is->audio_clock_serial, ffp->audio_callback_time / 1000000.0);\n        sync_clock_to_slave(&is->extclk, &is->audclk);\n    }\n    if (!ffp->first_audio_frame_rendered) {\n        ffp->first_audio_frame_rendered = 1;\n        ffp_notify_msg1(ffp, FFP_MSG_AUDIO_RENDERING_START);\n    }\n\n    if (is->latest_audio_seek_load_serial == is->audio_clock_serial) {\n        int latest_audio_seek_load_serial = __atomic_exchange_n(&(is->latest_audio_seek_load_serial), -1, memory_order_seq_cst);\n        if (latest_audio_seek_load_serial == is->audio_clock_serial) {\n            if (ffp->av_sync_type == AV_SYNC_AUDIO_MASTER) {\n                ffp_notify_msg2(ffp, FFP_MSG_AUDIO_SEEK_RENDERING_START, 1);\n            } else {\n                ffp_notify_msg2(ffp, FFP_MSG_AUDIO_SEEK_RENDERING_START, 0);\n            }\n        }\n    }\n\n    if (ffp->render_wait_start && !ffp->start_on_prepared && is->pause_req) {\n        while (is->pause_req && !is->abort_request) {\n            SDL_Delay(20);\n        }\n    }\n}\n\nstatic int audio_open(FFPlayer *opaque, int64_t wanted_channel_layout, int wanted_nb_channels, int wanted_sample_rate, struct AudioParams *audio_hw_params)\n{\n    FFPlayer *ffp = opaque;\n    VideoState *is = ffp->is;\n    SDL_AudioSpec wanted_spec, spec;\n    const char *env;\n    static const int next_nb_channels[] = {0, 0, 1, 6, 2, 6, 4, 6};\n#ifdef FFP_MERGE\n    static const int next_sample_rates[] = {0, 44100, 48000, 96000, 192000};\n#endif\n    static const int next_sample_rates[] = {0, 44100, 48000};\n    int next_sample_rate_idx = FF_ARRAY_ELEMS(next_sample_rates) - 1;\n\n    env = SDL_getenv(\"SDL_AUDIO_CHANNELS\");\n    if (env) {\n        wanted_nb_channels = atoi(env);\n        wanted_channel_layout = av_get_default_channel_layout(wanted_nb_channels);\n    }\n    if (!wanted_channel_layout || wanted_nb_channels != av_get_channel_layout_nb_channels(wanted_channel_layout)) {\n        wanted_channel_layout = av_get_default_channel_layout(wanted_nb_channels);\n        wanted_channel_layout &= ~AV_CH_LAYOUT_STEREO_DOWNMIX;\n    }\n    wanted_nb_channels = av_get_channel_layout_nb_channels(wanted_channel_layout);\n    wanted_spec.channels = wanted_nb_channels;\n    wanted_spec.freq = wanted_sample_rate;\n    if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) {\n        av_log(NULL, AV_LOG_ERROR, \"Invalid sample rate or channel count!\\n\");\n        return -1;\n    }\n    while (next_sample_rate_idx && next_sample_rates[next_sample_rate_idx] >= wanted_spec.freq)\n        next_sample_rate_idx--;\n    wanted_spec.format = AUDIO_S16SYS;\n    wanted_spec.silence = 0;\n    wanted_spec.samples = FFMAX(SDL_AUDIO_MIN_BUFFER_SIZE, 2 << av_log2(wanted_spec.freq / SDL_AoutGetAudioPerSecondCallBacks(ffp->aout)));\n    wanted_spec.callback = sdl_audio_callback;\n    wanted_spec.userdata = opaque;\n    while (SDL_AoutOpenAudio(ffp->aout, &wanted_spec, &spec) < 0) {\n        /* avoid infinity loop on exit. --by bbcallen */\n        if (is->abort_request)\n            return -1;\n        av_log(NULL, AV_LOG_WARNING, \"SDL_OpenAudio (%d channels, %d Hz): %s\\n\",\n               wanted_spec.channels, wanted_spec.freq, SDL_GetError());\n        wanted_spec.channels = next_nb_channels[FFMIN(7, wanted_spec.channels)];\n        if (!wanted_spec.channels) {\n            wanted_spec.freq = next_sample_rates[next_sample_rate_idx--];\n            wanted_spec.channels = wanted_nb_channels;\n            if (!wanted_spec.freq) {\n                av_log(NULL, AV_LOG_ERROR,\n                       \"No more combinations to try, audio open failed\\n\");\n                return -1;\n            }\n        }\n        wanted_channel_layout = av_get_default_channel_layout(wanted_spec.channels);\n    }\n    if (spec.format != AUDIO_S16SYS) {\n        av_log(NULL, AV_LOG_ERROR,\n               \"SDL advised audio format %d is not supported!\\n\", spec.format);\n        return -1;\n    }\n    if (spec.channels != wanted_spec.channels) {\n        wanted_channel_layout = av_get_default_channel_layout(spec.channels);\n        if (!wanted_channel_layout) {\n            av_log(NULL, AV_LOG_ERROR,\n                   \"SDL advised channel count %d is not supported!\\n\", spec.channels);\n            return -1;\n        }\n    }\n\n    audio_hw_params->fmt = AV_SAMPLE_FMT_S16;\n    audio_hw_params->freq = spec.freq;\n    audio_hw_params->channel_layout = wanted_channel_layout;\n    audio_hw_params->channels =  spec.channels;\n    audio_hw_params->frame_size = av_samples_get_buffer_size(NULL, audio_hw_params->channels, 1, audio_hw_params->fmt, 1);\n    audio_hw_params->bytes_per_sec = av_samples_get_buffer_size(NULL, audio_hw_params->channels, audio_hw_params->freq, audio_hw_params->fmt, 1);\n    if (audio_hw_params->bytes_per_sec <= 0 || audio_hw_params->frame_size <= 0) {\n        av_log(NULL, AV_LOG_ERROR, \"av_samples_get_buffer_size failed\\n\");\n        return -1;\n    }\n\n    SDL_AoutSetDefaultLatencySeconds(ffp->aout, ((double)(2 * spec.size)) / audio_hw_params->bytes_per_sec);\n    return spec.size;\n}\n\n/* open a given stream. Return 0 if OK */\nstatic int stream_component_open(FFPlayer *ffp, int stream_index)\n{\n    VideoState *is = ffp->is;\n    AVFormatContext *ic = is->ic;\n    AVCodecContext *avctx;\n    AVCodec *codec = NULL;\n    const char *forced_codec_name = NULL;\n    AVDictionary *opts = NULL;\n    AVDictionaryEntry *t = NULL;\n    int sample_rate, nb_channels;\n    int64_t channel_layout;\n    int ret = 0;\n    int stream_lowres = ffp->lowres;\n\n    if (stream_index < 0 || stream_index >= ic->nb_streams)\n        return -1;\n    avctx = avcodec_alloc_context3(NULL);\n    if (!avctx)\n        return AVERROR(ENOMEM);\n\n    ret = avcodec_parameters_to_context(avctx, ic->streams[stream_index]->codecpar);\n    if (ret < 0)\n        goto fail;\n    av_codec_set_pkt_timebase(avctx, ic->streams[stream_index]->time_base);\n\n    codec = avcodec_find_decoder(avctx->codec_id);\n\n    switch (avctx->codec_type) {\n        case AVMEDIA_TYPE_AUDIO   : is->last_audio_stream    = stream_index; forced_codec_name = ffp->audio_codec_name; break;\n        case AVMEDIA_TYPE_SUBTITLE: is->last_subtitle_stream = stream_index; forced_codec_name = ffp->subtitle_codec_name; break;\n        case AVMEDIA_TYPE_VIDEO   : is->last_video_stream    = stream_index; forced_codec_name = ffp->video_codec_name; break;\n        default: break;\n    }\n    if (forced_codec_name)\n        codec = avcodec_find_decoder_by_name(forced_codec_name);\n    if (!codec) {\n        if (forced_codec_name) av_log(NULL, AV_LOG_WARNING,\n                                      \"No codec could be found with name '%s'\\n\", forced_codec_name);\n        else                   av_log(NULL, AV_LOG_WARNING,\n                                      \"No codec could be found with id %d\\n\", avctx->codec_id);\n        ret = AVERROR(EINVAL);\n        goto fail;\n    }\n\n    avctx->codec_id = codec->id;\n    if(stream_lowres > av_codec_get_max_lowres(codec)){\n        av_log(avctx, AV_LOG_WARNING, \"The maximum value for lowres supported by the decoder is %d\\n\",\n                av_codec_get_max_lowres(codec));\n        stream_lowres = av_codec_get_max_lowres(codec);\n    }\n    av_codec_set_lowres(avctx, stream_lowres);\n\n#if FF_API_EMU_EDGE\n    if(stream_lowres) avctx->flags |= CODEC_FLAG_EMU_EDGE;\n#endif\n    if (ffp->fast)\n        avctx->flags2 |= AV_CODEC_FLAG2_FAST;\n#if FF_API_EMU_EDGE\n    if(codec->capabilities & AV_CODEC_CAP_DR1)\n        avctx->flags |= CODEC_FLAG_EMU_EDGE;\n#endif\n\n    opts = filter_codec_opts(ffp->codec_opts, avctx->codec_id, ic, ic->streams[stream_index], codec);\n    if (!av_dict_get(opts, \"threads\", NULL, 0))\n        av_dict_set(&opts, \"threads\", \"auto\", 0);\n    if (stream_lowres)\n        av_dict_set_int(&opts, \"lowres\", stream_lowres, 0);\n    if (avctx->codec_type == AVMEDIA_TYPE_VIDEO || avctx->codec_type == AVMEDIA_TYPE_AUDIO)\n        av_dict_set(&opts, \"refcounted_frames\", \"1\", 0);\n    if ((ret = avcodec_open2(avctx, codec, &opts)) < 0) {\n        goto fail;\n    }\n    if ((t = av_dict_get(opts, \"\", NULL, AV_DICT_IGNORE_SUFFIX))) {\n        av_log(NULL, AV_LOG_ERROR, \"Option %s not found.\\n\", t->key);\n#ifdef FFP_MERGE\n        ret =  AVERROR_OPTION_NOT_FOUND;\n        goto fail;\n#endif\n    }\n\n    is->eof = 0;\n    ic->streams[stream_index]->discard = AVDISCARD_DEFAULT;\n    switch (avctx->codec_type) {\n    case AVMEDIA_TYPE_AUDIO:\n#if CONFIG_AVFILTER\n        {\n            AVFilterContext *sink;\n\n            is->audio_filter_src.freq           = avctx->sample_rate;\n            is->audio_filter_src.channels       = avctx->channels;\n            is->audio_filter_src.channel_layout = get_valid_channel_layout(avctx->channel_layout, avctx->channels);\n            is->audio_filter_src.fmt            = avctx->sample_fmt;\n            SDL_LockMutex(ffp->af_mutex);\n            if ((ret = configure_audio_filters(ffp, ffp->afilters, 0)) < 0) {\n                SDL_UnlockMutex(ffp->af_mutex);\n                goto fail;\n            }\n            ffp->af_changed = 0;\n            SDL_UnlockMutex(ffp->af_mutex);\n            sink = is->out_audio_filter;\n            sample_rate    = av_buffersink_get_sample_rate(sink);\n            nb_channels    = av_buffersink_get_channels(sink);\n            channel_layout = av_buffersink_get_channel_layout(sink);\n        }\n#else\n        sample_rate    = avctx->sample_rate;\n        nb_channels    = avctx->channels;\n        channel_layout = avctx->channel_layout;\n#endif\n\n        /* prepare audio output */\n        if ((ret = audio_open(ffp, channel_layout, nb_channels, sample_rate, &is->audio_tgt)) < 0)\n            goto fail;\n        ffp_set_audio_codec_info(ffp, AVCODEC_MODULE_NAME, avcodec_get_name(avctx->codec_id));\n        is->audio_hw_buf_size = ret;\n        is->audio_src = is->audio_tgt;\n        is->audio_buf_size  = 0;\n        is->audio_buf_index = 0;\n\n        /* init averaging filter */\n        is->audio_diff_avg_coef  = exp(log(0.01) / AUDIO_DIFF_AVG_NB);\n        is->audio_diff_avg_count = 0;\n        /* since we do not have a precise anough audio FIFO fullness,\n           we correct audio sync only if larger than this threshold */\n        is->audio_diff_threshold = 2.0 * is->audio_hw_buf_size / is->audio_tgt.bytes_per_sec;\n\n        is->audio_stream = stream_index;\n        is->audio_st = ic->streams[stream_index];\n\n        decoder_init(&is->auddec, avctx, &is->audioq, is->continue_read_thread);\n        if ((is->ic->iformat->flags & (AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK)) && !is->ic->iformat->read_seek) {\n            is->auddec.start_pts = is->audio_st->start_time;\n            is->auddec.start_pts_tb = is->audio_st->time_base;\n        }\n        if ((ret = decoder_start(&is->auddec, audio_thread, ffp, \"ff_audio_dec\")) < 0)\n            goto out;\n        SDL_AoutPauseAudio(ffp->aout, 0);\n        break;\n    case AVMEDIA_TYPE_VIDEO:\n        is->video_stream = stream_index;\n        is->video_st = ic->streams[stream_index];\n\n        if (ffp->async_init_decoder) {\n            while (!is->initialized_decoder) {\n                SDL_Delay(5);\n            }\n            if (ffp->node_vdec) {\n                is->viddec.avctx = avctx;\n                ret = ffpipeline_config_video_decoder(ffp->pipeline, ffp);\n            }\n            if (ret || !ffp->node_vdec) {\n                decoder_init(&is->viddec, avctx, &is->videoq, is->continue_read_thread);\n                ffp->node_vdec = ffpipeline_open_video_decoder(ffp->pipeline, ffp);\n                if (!ffp->node_vdec)\n                    goto fail;\n            }\n        } else {\n            decoder_init(&is->viddec, avctx, &is->videoq, is->continue_read_thread);\n            ffp->node_vdec = ffpipeline_open_video_decoder(ffp->pipeline, ffp);\n            if (!ffp->node_vdec)\n                goto fail;\n        }\n        if ((ret = decoder_start(&is->viddec, video_thread, ffp, \"ff_video_dec\")) < 0)\n            goto out;\n\n        is->queue_attachments_req = 1;\n\n        if (ffp->max_fps >= 0) {\n            if(is->video_st->avg_frame_rate.den && is->video_st->avg_frame_rate.num) {\n                double fps = av_q2d(is->video_st->avg_frame_rate);\n                SDL_ProfilerReset(&is->viddec.decode_profiler, fps + 0.5);\n                if (fps > ffp->max_fps && fps < 130.0) {\n                    is->is_video_high_fps = 1;\n                    av_log(ffp, AV_LOG_WARNING, \"fps: %lf (too high)\\n\", fps);\n                } else {\n                    av_log(ffp, AV_LOG_WARNING, \"fps: %lf (normal)\\n\", fps);\n                }\n            }\n            if(is->video_st->r_frame_rate.den && is->video_st->r_frame_rate.num) {\n                double tbr = av_q2d(is->video_st->r_frame_rate);\n                if (tbr > ffp->max_fps && tbr < 130.0) {\n                    is->is_video_high_fps = 1;\n                    av_log(ffp, AV_LOG_WARNING, \"fps: %lf (too high)\\n\", tbr);\n                } else {\n                    av_log(ffp, AV_LOG_WARNING, \"fps: %lf (normal)\\n\", tbr);\n                }\n            }\n        }\n\n        if (is->is_video_high_fps) {\n            avctx->skip_frame       = FFMAX(avctx->skip_frame, AVDISCARD_NONREF);\n            avctx->skip_loop_filter = FFMAX(avctx->skip_loop_filter, AVDISCARD_NONREF);\n            avctx->skip_idct        = FFMAX(avctx->skip_loop_filter, AVDISCARD_NONREF);\n        }\n\n        break;\n    case AVMEDIA_TYPE_SUBTITLE:\n        if (!ffp->subtitle) break;\n\n        is->subtitle_stream = stream_index;\n        is->subtitle_st = ic->streams[stream_index];\n\n        ffp_set_subtitle_codec_info(ffp, AVCODEC_MODULE_NAME, avcodec_get_name(avctx->codec_id));\n\n        decoder_init(&is->subdec, avctx, &is->subtitleq, is->continue_read_thread);\n        if ((ret = decoder_start(&is->subdec, subtitle_thread, ffp, \"ff_subtitle_dec\")) < 0)\n            goto out;\n        break;\n    default:\n        break;\n    }\n    goto out;\n\nfail:\n    avcodec_free_context(&avctx);\nout:\n    av_dict_free(&opts);\n\n    return ret;\n}\n\nstatic int decode_interrupt_cb(void *ctx)\n{\n    VideoState *is = ctx;\n    return is->abort_request;\n}\n\nstatic int stream_has_enough_packets(AVStream *st, int stream_id, PacketQueue *queue, int min_frames) {\n    return stream_id < 0 ||\n           queue->abort_request ||\n           (st->disposition & AV_DISPOSITION_ATTACHED_PIC) ||\n#ifdef FFP_MERGE\n           queue->nb_packets > MIN_FRAMES && (!queue->duration || av_q2d(st->time_base) * queue->duration > 1.0);\n#endif\n           queue->nb_packets > min_frames;\n}\n\nstatic int is_realtime(AVFormatContext *s)\n{\n    if(   !strcmp(s->iformat->name, \"rtp\")\n       || !strcmp(s->iformat->name, \"rtsp\")\n       || !strcmp(s->iformat->name, \"sdp\")\n    )\n        return 1;\n\n    if(s->pb && (   !strncmp(s->filename, \"rtp:\", 4)\n                 || !strncmp(s->filename, \"udp:\", 4)\n                )\n    )\n        return 1;\n    return 0;\n}\n\n/* this thread gets the stream from the disk or the network */\nstatic int read_thread(void *arg)\n{\n    FFPlayer *ffp = arg;\n    VideoState *is = ffp->is;\n    AVFormatContext *ic = NULL;\n    int err, i, ret __unused;\n    int st_index[AVMEDIA_TYPE_NB];\n    AVPacket pkt1, *pkt = &pkt1;\n    int64_t stream_start_time;\n    int completed = 0;\n    int pkt_in_play_range = 0;\n    AVDictionaryEntry *t;\n    SDL_mutex *wait_mutex = SDL_CreateMutex();\n    int scan_all_pmts_set = 0;\n    int64_t pkt_ts;\n    int last_error = 0;\n    int64_t prev_io_tick_counter = 0;\n    int64_t io_tick_counter = 0;\n    int init_ijkmeta = 0;\n\n    if (!wait_mutex) {\n        av_log(NULL, AV_LOG_FATAL, \"SDL_CreateMutex(): %s\\n\", SDL_GetError());\n        ret = AVERROR(ENOMEM);\n        goto fail;\n    }\n\n    memset(st_index, -1, sizeof(st_index));\n    is->last_video_stream = is->video_stream = -1;\n    is->last_audio_stream = is->audio_stream = -1;\n    is->last_subtitle_stream = is->subtitle_stream = -1;\n    is->eof = 0;\n\n    ic = avformat_alloc_context();\n    if (!ic) {\n        av_log(NULL, AV_LOG_FATAL, \"Could not allocate context.\\n\");\n        ret = AVERROR(ENOMEM);\n        goto fail;\n    }\n    ic->interrupt_callback.callback = decode_interrupt_cb;\n    ic->interrupt_callback.opaque = is;\n    if (!av_dict_get(ffp->format_opts, \"scan_all_pmts\", NULL, AV_DICT_MATCH_CASE)) {\n        av_dict_set(&ffp->format_opts, \"scan_all_pmts\", \"1\", AV_DICT_DONT_OVERWRITE);\n        scan_all_pmts_set = 1;\n    }\n    if (av_stristart(is->filename, \"rtmp\", NULL) ||\n        av_stristart(is->filename, \"rtsp\", NULL)) {\n        // There is total different meaning for 'timeout' option in rtmp\n        av_log(ffp, AV_LOG_WARNING, \"remove 'timeout' option for rtmp.\\n\");\n        av_dict_set(&ffp->format_opts, \"timeout\", NULL, 0);\n    }\n\n    if (ffp->skip_calc_frame_rate) {\n        av_dict_set_int(&ic->metadata, \"skip-calc-frame-rate\", ffp->skip_calc_frame_rate, 0);\n        av_dict_set_int(&ffp->format_opts, \"skip-calc-frame-rate\", ffp->skip_calc_frame_rate, 0);\n    }\n\n    if (ffp->iformat_name)\n        is->iformat = av_find_input_format(ffp->iformat_name);\n\n    av_dict_set_intptr(&ffp->format_opts, \"video_cache_ptr\", (intptr_t)&ffp->stat.video_cache, 0);\n    av_dict_set_intptr(&ffp->format_opts, \"audio_cache_ptr\", (intptr_t)&ffp->stat.audio_cache, 0);\n    err = avformat_open_input(&ic, is->filename, is->iformat, &ffp->format_opts);\n    if (err < 0) {\n        print_error(is->filename, err);\n        ret = -1;\n        goto fail;\n    }\n    ffp_notify_msg1(ffp, FFP_MSG_OPEN_INPUT);\n\n    if (scan_all_pmts_set)\n        av_dict_set(&ffp->format_opts, \"scan_all_pmts\", NULL, AV_DICT_MATCH_CASE);\n\n    if ((t = av_dict_get(ffp->format_opts, \"\", NULL, AV_DICT_IGNORE_SUFFIX))) {\n        av_log(NULL, AV_LOG_ERROR, \"Option %s not found.\\n\", t->key);\n#ifdef FFP_MERGE\n        ret = AVERROR_OPTION_NOT_FOUND;\n        goto fail;\n#endif\n    }\n    is->ic = ic;\n\n    if (ffp->genpts)\n        ic->flags |= AVFMT_FLAG_GENPTS;\n\n    av_format_inject_global_side_data(ic);\n    //\n    //AVDictionary **opts;\n    //int orig_nb_streams;\n    //opts = setup_find_stream_info_opts(ic, ffp->codec_opts);\n    //orig_nb_streams = ic->nb_streams;\n\n\n    if (ffp->find_stream_info) {\n        AVDictionary **opts = setup_find_stream_info_opts(ic, ffp->codec_opts);\n        int orig_nb_streams = ic->nb_streams;\n\n        do {\n            if (av_stristart(is->filename, \"data:\", NULL) && orig_nb_streams > 0) {\n                for (i = 0; i < orig_nb_streams; i++) {\n                    if (!ic->streams[i] || !ic->streams[i]->codecpar || ic->streams[i]->codecpar->profile == FF_PROFILE_UNKNOWN) {\n                        break;\n                    }\n                }\n\n                if (i == orig_nb_streams) {\n                    break;\n                }\n            }\n            err = avformat_find_stream_info(ic, opts);\n        } while(0);\n        ffp_notify_msg1(ffp, FFP_MSG_FIND_STREAM_INFO);\n\n        for (i = 0; i < orig_nb_streams; i++)\n            av_dict_free(&opts[i]);\n        av_freep(&opts);\n\n        if (err < 0) {\n            av_log(NULL, AV_LOG_WARNING,\n                   \"%s: could not find codec parameters\\n\", is->filename);\n            ret = -1;\n            goto fail;\n        }\n    }\n    if (ic->pb)\n        ic->pb->eof_reached = 0; // FIXME hack, ffplay maybe should not use avio_feof() to test for the end\n\n    if (ffp->seek_by_bytes < 0)\n        ffp->seek_by_bytes = !!(ic->iformat->flags & AVFMT_TS_DISCONT) && strcmp(\"ogg\", ic->iformat->name);\n\n    is->max_frame_duration = (ic->iformat->flags & AVFMT_TS_DISCONT) ? 10.0 : 3600.0;\n    is->max_frame_duration = 10.0;\n    av_log(ffp, AV_LOG_INFO, \"max_frame_duration: %.3f\\n\", is->max_frame_duration);\n\n#ifdef FFP_MERGE\n    if (!window_title && (t = av_dict_get(ic->metadata, \"title\", NULL, 0)))\n        window_title = av_asprintf(\"%s - %s\", t->value, input_filename);\n\n#endif\n    /* if seeking requested, we execute it */\n    if (ffp->start_time != AV_NOPTS_VALUE) {\n        int64_t timestamp;\n\n        timestamp = ffp->start_time;\n        /* add the stream start time */\n        if (ic->start_time != AV_NOPTS_VALUE)\n            timestamp += ic->start_time;\n        ret = avformat_seek_file(ic, -1, INT64_MIN, timestamp, INT64_MAX, 0);\n        if (ret < 0) {\n            av_log(NULL, AV_LOG_WARNING, \"%s: could not seek to position %0.3f\\n\",\n                    is->filename, (double)timestamp / AV_TIME_BASE);\n        }\n    }\n\n    is->realtime = is_realtime(ic);\n\n    av_dump_format(ic, 0, is->filename, 0);\n\n    int video_stream_count = 0;\n    int h264_stream_count = 0;\n    int first_h264_stream = -1;\n    for (i = 0; i < ic->nb_streams; i++) {\n        AVStream *st = ic->streams[i];\n        enum AVMediaType type = st->codecpar->codec_type;\n        st->discard = AVDISCARD_ALL;\n        if (type >= 0 && ffp->wanted_stream_spec[type] && st_index[type] == -1)\n            if (avformat_match_stream_specifier(ic, st, ffp->wanted_stream_spec[type]) > 0)\n                st_index[type] = i;\n\n        // choose first h264\n\n        if (type == AVMEDIA_TYPE_VIDEO) {\n            enum AVCodecID codec_id = st->codecpar->codec_id;\n            video_stream_count++;\n            if (codec_id == AV_CODEC_ID_H264) {\n                h264_stream_count++;\n                if (first_h264_stream < 0)\n                    first_h264_stream = i;\n            }\n        }\n    }\n    if (video_stream_count > 1 && st_index[AVMEDIA_TYPE_VIDEO] < 0) {\n        st_index[AVMEDIA_TYPE_VIDEO] = first_h264_stream;\n        av_log(NULL, AV_LOG_WARNING, \"multiple video stream found, prefer first h264 stream: %d\\n\", first_h264_stream);\n    }\n    if (!ffp->video_disable)\n        st_index[AVMEDIA_TYPE_VIDEO] =\n            av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO,\n                                st_index[AVMEDIA_TYPE_VIDEO], -1, NULL, 0);\n    if (!ffp->audio_disable)\n        st_index[AVMEDIA_TYPE_AUDIO] =\n            av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO,\n                                st_index[AVMEDIA_TYPE_AUDIO],\n                                st_index[AVMEDIA_TYPE_VIDEO],\n                                NULL, 0);\n    if (!ffp->video_disable && !ffp->subtitle_disable)\n        st_index[AVMEDIA_TYPE_SUBTITLE] =\n            av_find_best_stream(ic, AVMEDIA_TYPE_SUBTITLE,\n                                st_index[AVMEDIA_TYPE_SUBTITLE],\n                                (st_index[AVMEDIA_TYPE_AUDIO] >= 0 ?\n                                 st_index[AVMEDIA_TYPE_AUDIO] :\n                                 st_index[AVMEDIA_TYPE_VIDEO]),\n                                NULL, 0);\n\n    is->show_mode = ffp->show_mode;\n#ifdef FFP_MERGE // bbc: dunno if we need this\n    if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {\n        AVStream *st = ic->streams[st_index[AVMEDIA_TYPE_VIDEO]];\n        AVCodecParameters *codecpar = st->codecpar;\n        AVRational sar = av_guess_sample_aspect_ratio(ic, st, NULL);\n        if (codecpar->width)\n            set_default_window_size(codecpar->width, codecpar->height, sar);\n    }\n#endif\n\n    /* open the streams */\n    if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) {\n        stream_component_open(ffp, st_index[AVMEDIA_TYPE_AUDIO]);\n    } else {\n        ffp->av_sync_type = AV_SYNC_VIDEO_MASTER;\n        is->av_sync_type  = ffp->av_sync_type;\n    }\n\n    ret = -1;\n    if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {\n        ret = stream_component_open(ffp, st_index[AVMEDIA_TYPE_VIDEO]);\n    }\n    if (is->show_mode == SHOW_MODE_NONE)\n        is->show_mode = ret >= 0 ? SHOW_MODE_VIDEO : SHOW_MODE_RDFT;\n\n    if (st_index[AVMEDIA_TYPE_SUBTITLE] >= 0) {\n        stream_component_open(ffp, st_index[AVMEDIA_TYPE_SUBTITLE]);\n    }\n    ffp_notify_msg1(ffp, FFP_MSG_COMPONENT_OPEN);\n\n    if (!ffp->ijkmeta_delay_init) {\n        ijkmeta_set_avformat_context_l(ffp->meta, ic);\n    }\n\n    ffp->stat.bit_rate = ic->bit_rate;\n    if (st_index[AVMEDIA_TYPE_VIDEO] >= 0)\n        ijkmeta_set_int64_l(ffp->meta, IJKM_KEY_VIDEO_STREAM, st_index[AVMEDIA_TYPE_VIDEO]);\n    if (st_index[AVMEDIA_TYPE_AUDIO] >= 0)\n        ijkmeta_set_int64_l(ffp->meta, IJKM_KEY_AUDIO_STREAM, st_index[AVMEDIA_TYPE_AUDIO]);\n    if (st_index[AVMEDIA_TYPE_SUBTITLE] >= 0)\n        ijkmeta_set_int64_l(ffp->meta, IJKM_KEY_TIMEDTEXT_STREAM, st_index[AVMEDIA_TYPE_SUBTITLE]);\n\n    if (is->video_stream < 0 && is->audio_stream < 0) {\n        av_log(NULL, AV_LOG_FATAL, \"Failed to open file '%s' or configure filtergraph\\n\",\n               is->filename);\n        ret = -1;\n        goto fail;\n    }\n    if (is->audio_stream >= 0) {\n        is->audioq.is_buffer_indicator = 1;\n        is->buffer_indicator_queue = &is->audioq;\n    } else if (is->video_stream >= 0) {\n        is->videoq.is_buffer_indicator = 1;\n        is->buffer_indicator_queue = &is->videoq;\n    } else {\n        assert(\"invalid streams\");\n    }\n\n    if (ffp->infinite_buffer < 0 && is->realtime)\n        ffp->infinite_buffer = 1;\n\n    if (!ffp->render_wait_start && !ffp->start_on_prepared)\n        toggle_pause(ffp, 1);\n    if (is->video_st && is->video_st->codecpar) {\n        AVCodecParameters *codecpar = is->video_st->codecpar;\n        ffp_notify_msg3(ffp, FFP_MSG_VIDEO_SIZE_CHANGED, codecpar->width, codecpar->height);\n        ffp_notify_msg3(ffp, FFP_MSG_SAR_CHANGED, codecpar->sample_aspect_ratio.num, codecpar->sample_aspect_ratio.den);\n    }\n    ffp->prepared = true;\n    ffp_notify_msg1(ffp, FFP_MSG_PREPARED);\n    if (!ffp->render_wait_start && !ffp->start_on_prepared) {\n        while (is->pause_req && !is->abort_request) {\n            SDL_Delay(20);\n        }\n    }\n    if (ffp->auto_resume) {\n        ffp_notify_msg1(ffp, FFP_REQ_START);\n        ffp->auto_resume = 0;\n    }\n    /* offset should be seeked*/\n    if (ffp->seek_at_start > 0) {\n        ffp_seek_to_l(ffp, (long)(ffp->seek_at_start));\n    }\n\n    for (;;) {\n        if (is->abort_request)\n            break;\n#ifdef FFP_MERGE\n        if (is->paused != is->last_paused) {\n            is->last_paused = is->paused;\n            if (is->paused)\n                is->read_pause_return = av_read_pause(ic);\n            else\n                av_read_play(ic);\n        }\n#endif\n#if CONFIG_RTSP_DEMUXER || CONFIG_MMSH_PROTOCOL\n        if (is->paused &&\n                (!strcmp(ic->iformat->name, \"rtsp\") ||\n                 (ic->pb && !strncmp(ffp->input_filename, \"mmsh:\", 5)))) {\n            /* wait 10 ms to avoid trying to get another packet */\n            /* XXX: horrible */\n            SDL_Delay(10);\n            continue;\n        }\n#endif\n        if (is->seek_req) {\n            int64_t seek_target = is->seek_pos;\n            int64_t seek_min    = is->seek_rel > 0 ? seek_target - is->seek_rel + 2: INT64_MIN;\n            int64_t seek_max    = is->seek_rel < 0 ? seek_target - is->seek_rel - 2: INT64_MAX;\n// FIXME the +-2 is due to rounding being not done in the correct direction in generation\n//      of the seek_pos/seek_rel variables\n\n            ffp_toggle_buffering(ffp, 1);\n            ffp_notify_msg3(ffp, FFP_MSG_BUFFERING_UPDATE, 0, 0);\n            ret = avformat_seek_file(is->ic, -1, seek_min, seek_target, seek_max, is->seek_flags);\n            if (ret < 0) {\n                av_log(NULL, AV_LOG_ERROR,\n                       \"%s: error while seeking\\n\", is->ic->filename);\n            } else {\n                if (is->audio_stream >= 0) {\n                    packet_queue_flush(&is->audioq);\n                    packet_queue_put(&is->audioq, &flush_pkt);\n                    // TODO: clear invaild audio data\n                    // SDL_AoutFlushAudio(ffp->aout);\n                }\n                if (is->subtitle_stream >= 0) {\n                    packet_queue_flush(&is->subtitleq);\n                    packet_queue_put(&is->subtitleq, &flush_pkt);\n                }\n                if (is->video_stream >= 0) {\n                    if (ffp->node_vdec) {\n                        ffpipenode_flush(ffp->node_vdec);\n                    }\n                    packet_queue_flush(&is->videoq);\n                    packet_queue_put(&is->videoq, &flush_pkt);\n                }\n                if (is->seek_flags & AVSEEK_FLAG_BYTE) {\n                   set_clock(&is->extclk, NAN, 0);\n                } else {\n                   set_clock(&is->extclk, seek_target / (double)AV_TIME_BASE, 0);\n                }\n\n                is->latest_video_seek_load_serial = is->videoq.serial;\n                is->latest_audio_seek_load_serial = is->audioq.serial;\n                is->latest_seek_load_start_at = av_gettime();\n            }\n            ffp->dcc.current_high_water_mark_in_ms = ffp->dcc.first_high_water_mark_in_ms;\n            is->seek_req = 0;\n            is->queue_attachments_req = 1;\n            is->eof = 0;\n#ifdef FFP_MERGE\n            if (is->paused)\n                step_to_next_frame(is);\n#endif\n            completed = 0;\n            SDL_LockMutex(ffp->is->play_mutex);\n            if (ffp->auto_resume) {\n                is->pause_req = 0;\n                if (ffp->packet_buffering)\n                    is->buffering_on = 1;\n                ffp->auto_resume = 0;\n                stream_update_pause_l(ffp);\n            }\n            if (is->pause_req)\n                step_to_next_frame_l(ffp);\n            SDL_UnlockMutex(ffp->is->play_mutex);\n\n            if (ffp->enable_accurate_seek) {\n                is->drop_aframe_count = 0;\n                is->drop_vframe_count = 0;\n                SDL_LockMutex(is->accurate_seek_mutex);\n                if (is->video_stream >= 0) {\n                    is->video_accurate_seek_req = 1;\n                }\n                if (is->audio_stream >= 0) {\n                    is->audio_accurate_seek_req = 1;\n                }\n                SDL_CondSignal(is->audio_accurate_seek_cond);\n                SDL_CondSignal(is->video_accurate_seek_cond);\n                SDL_UnlockMutex(is->accurate_seek_mutex);\n            }\n\n            ffp_notify_msg3(ffp, FFP_MSG_SEEK_COMPLETE, (int)fftime_to_milliseconds(seek_target), ret);\n            ffp_toggle_buffering(ffp, 1);\n        }\n        if (is->queue_attachments_req) {\n            if (is->video_st && (is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC)) {\n                AVPacket copy = { 0 };\n                if ((ret = av_packet_ref(&copy, &is->video_st->attached_pic)) < 0)\n                    goto fail;\n                packet_queue_put(&is->videoq, &copy);\n                packet_queue_put_nullpacket(&is->videoq, is->video_stream);\n            }\n            is->queue_attachments_req = 0;\n        }\n\n        /* if the queue are full, no need to read more */\n        if (ffp->infinite_buffer<1 && !is->seek_req &&\n#ifdef FFP_MERGE\n              (is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE\n#else\n              (is->audioq.size + is->videoq.size + is->subtitleq.size > ffp->dcc.max_buffer_size\n#endif\n            || (   stream_has_enough_packets(is->audio_st, is->audio_stream, &is->audioq, MIN_FRAMES)\n                && stream_has_enough_packets(is->video_st, is->video_stream, &is->videoq, MIN_FRAMES)\n                && stream_has_enough_packets(is->subtitle_st, is->subtitle_stream, &is->subtitleq, MIN_FRAMES)))) {\n            if (!is->eof) {\n                ffp_toggle_buffering(ffp, 0);\n            }\n            /* wait 10 ms */\n            SDL_LockMutex(wait_mutex);\n            SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10);\n            SDL_UnlockMutex(wait_mutex);\n            continue;\n        }\n        if ((!is->paused || completed) &&\n            (!is->audio_st || (is->auddec.finished == is->audioq.serial && frame_queue_nb_remaining(&is->sampq) == 0)) &&\n            (!is->video_st || (is->viddec.finished == is->videoq.serial && frame_queue_nb_remaining(&is->pictq) == 0))) {\n            if (ffp->loop != 1 && (!ffp->loop || --ffp->loop)) {\n                stream_seek(is, ffp->start_time != AV_NOPTS_VALUE ? ffp->start_time : 0, 0, 0);\n            } else if (ffp->autoexit) {\n                ret = AVERROR_EOF;\n                goto fail;\n            } else {\n                ffp_statistic_l(ffp);\n                if (completed) {\n                    av_log(ffp, AV_LOG_INFO, \"ffp_toggle_buffering: eof\\n\");\n                    SDL_LockMutex(wait_mutex);\n                    // infinite wait may block shutdown\n                    while(!is->abort_request && !is->seek_req)\n                        SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 100);\n                    SDL_UnlockMutex(wait_mutex);\n                    if (!is->abort_request)\n                        continue;\n                } else {\n                    completed = 1;\n                    ffp->auto_resume = 0;\n\n                    // TODO: 0 it's a bit early to notify complete here\n                    ffp_toggle_buffering(ffp, 0);\n                    toggle_pause(ffp, 1);\n                    if (ffp->error) {\n                        av_log(ffp, AV_LOG_INFO, \"ffp_toggle_buffering: error: %d\\n\", ffp->error);\n                        ffp_notify_msg1(ffp, FFP_MSG_ERROR);\n                    } else {\n                        av_log(ffp, AV_LOG_INFO, \"ffp_toggle_buffering: completed: OK\\n\");\n                        ffp_notify_msg1(ffp, FFP_MSG_COMPLETED);\n                    }\n                }\n            }\n        }\n        pkt->flags = 0;\n        ret = av_read_frame(ic, pkt);\n        if (ret < 0) {\n            int pb_eof = 0;\n            int pb_error = 0;\n            if ((ret == AVERROR_EOF || avio_feof(ic->pb)) && !is->eof) {\n                ffp_check_buffering_l(ffp);\n                pb_eof = 1;\n                // check error later\n            }\n            if (ic->pb && ic->pb->error) {\n                pb_eof = 1;\n                pb_error = ic->pb->error;\n            }\n            if (ret == AVERROR_EXIT) {\n                pb_eof = 1;\n                pb_error = AVERROR_EXIT;\n            }\n\n            if (pb_eof) {\n                if (is->video_stream >= 0)\n                    packet_queue_put_nullpacket(&is->videoq, is->video_stream);\n                if (is->audio_stream >= 0)\n                    packet_queue_put_nullpacket(&is->audioq, is->audio_stream);\n                if (is->subtitle_stream >= 0)\n                    packet_queue_put_nullpacket(&is->subtitleq, is->subtitle_stream);\n                is->eof = 1;\n            }\n            if (pb_error) {\n                if (is->video_stream >= 0)\n                    packet_queue_put_nullpacket(&is->videoq, is->video_stream);\n                if (is->audio_stream >= 0)\n                    packet_queue_put_nullpacket(&is->audioq, is->audio_stream);\n                if (is->subtitle_stream >= 0)\n                    packet_queue_put_nullpacket(&is->subtitleq, is->subtitle_stream);\n                is->eof = 1;\n                ffp->error = pb_error;\n                av_log(ffp, AV_LOG_ERROR, \"av_read_frame error: %s\\n\", ffp_get_error_string(ffp->error));\n                // break;\n            } else {\n                ffp->error = 0;\n            }\n            if (is->eof) {\n                ffp_toggle_buffering(ffp, 0);\n                SDL_Delay(100);\n            }\n            SDL_LockMutex(wait_mutex);\n            SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10);\n            SDL_UnlockMutex(wait_mutex);\n            ffp_statistic_l(ffp);\n            continue;\n        } else {\n            is->eof = 0;\n        }\n\n        if (pkt->flags & AV_PKT_FLAG_DISCONTINUITY) {\n            if (is->audio_stream >= 0) {\n                packet_queue_put(&is->audioq, &flush_pkt);\n            }\n            if (is->subtitle_stream >= 0) {\n                packet_queue_put(&is->subtitleq, &flush_pkt);\n            }\n            if (is->video_stream >= 0) {\n                packet_queue_put(&is->videoq, &flush_pkt);\n            }\n        }\n\n        /* check if packet is in play range specified by user, then queue, otherwise discard */\n        stream_start_time = ic->streams[pkt->stream_index]->start_time;\n        pkt_ts = pkt->pts == AV_NOPTS_VALUE ? pkt->dts : pkt->pts;\n        pkt_in_play_range = ffp->duration == AV_NOPTS_VALUE ||\n                (pkt_ts - (stream_start_time != AV_NOPTS_VALUE ? stream_start_time : 0)) *\n                av_q2d(ic->streams[pkt->stream_index]->time_base) -\n                (double)(ffp->start_time != AV_NOPTS_VALUE ? ffp->start_time : 0) / 1000000\n                <= ((double)ffp->duration / 1000000);\n        if (pkt->stream_index == is->audio_stream && pkt_in_play_range) {\n            packet_queue_put(&is->audioq, pkt);\n        } else if (pkt->stream_index == is->video_stream && pkt_in_play_range\n                   && !(is->video_st && (is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC))) {\n            packet_queue_put(&is->videoq, pkt);\n        } else if (pkt->stream_index == is->subtitle_stream && pkt_in_play_range) {\n            packet_queue_put(&is->subtitleq, pkt);\n        } else {\n            av_packet_unref(pkt);\n        }\n\n        ffp_statistic_l(ffp);\n\n        if (ffp->ijkmeta_delay_init && !init_ijkmeta &&\n                (ffp->first_video_frame_rendered || !is->video_st) && (ffp->first_audio_frame_rendered || !is->audio_st)) {\n            ijkmeta_set_avformat_context_l(ffp->meta, ic);\n            init_ijkmeta = 1;\n        }\n\n        if (ffp->packet_buffering) {\n            io_tick_counter = SDL_GetTickHR();\n            if ((!ffp->first_video_frame_rendered && is->video_st) || (!ffp->first_audio_frame_rendered && is->audio_st)) {\n                if (abs((int)(io_tick_counter - prev_io_tick_counter)) > FAST_BUFFERING_CHECK_PER_MILLISECONDS) {\n                    prev_io_tick_counter = io_tick_counter;\n                    ffp->dcc.current_high_water_mark_in_ms = ffp->dcc.first_high_water_mark_in_ms;\n                    ffp_check_buffering_l(ffp);\n                }\n            } else {\n                if (abs((int)(io_tick_counter - prev_io_tick_counter)) > BUFFERING_CHECK_PER_MILLISECONDS) {\n                    prev_io_tick_counter = io_tick_counter;\n                    ffp_check_buffering_l(ffp);\n                }\n            }\n        }\n    }\n\n    ret = 0;\n fail:\n    if (ic && !is->ic)\n        avformat_close_input(&ic);\n\n    if (!ffp->prepared || !is->abort_request) {\n        ffp->last_error = last_error;\n        ffp_notify_msg2(ffp, FFP_MSG_ERROR, last_error);\n    }\n    SDL_DestroyMutex(wait_mutex);\n    return 0;\n}\n\nstatic int video_refresh_thread(void *arg);\nstatic VideoState *stream_open(FFPlayer *ffp, const char *filename, AVInputFormat *iformat)\n{\n    assert(!ffp->is);\n    VideoState *is;\n\n    is = av_mallocz(sizeof(VideoState));\n    if (!is)\n        return NULL;\n    is->filename = av_strdup(filename);\n    if (!is->filename)\n        goto fail;\n    is->iformat = iformat;\n    is->ytop    = 0;\n    is->xleft   = 0;\n#if defined(__ANDROID__)\n    if (ffp->soundtouch_enable) {\n        is->handle = ijk_soundtouch_create();\n    }\n#endif\n\n    /* start video display */\n    if (frame_queue_init(&is->pictq, &is->videoq, ffp->pictq_size, 1) < 0)\n        goto fail;\n    if (frame_queue_init(&is->subpq, &is->subtitleq, SUBPICTURE_QUEUE_SIZE, 0) < 0)\n        goto fail;\n    if (frame_queue_init(&is->sampq, &is->audioq, SAMPLE_QUEUE_SIZE, 1) < 0)\n        goto fail;\n\n    if (packet_queue_init(&is->videoq) < 0 ||\n        packet_queue_init(&is->audioq) < 0 ||\n        packet_queue_init(&is->subtitleq) < 0)\n        goto fail;\n\n    if (!(is->continue_read_thread = SDL_CreateCond())) {\n        av_log(NULL, AV_LOG_FATAL, \"SDL_CreateCond(): %s\\n\", SDL_GetError());\n        goto fail;\n    }\n\n    if (!(is->video_accurate_seek_cond = SDL_CreateCond())) {\n        av_log(NULL, AV_LOG_FATAL, \"SDL_CreateCond(): %s\\n\", SDL_GetError());\n        ffp->enable_accurate_seek = 0;\n    }\n\n    if (!(is->audio_accurate_seek_cond = SDL_CreateCond())) {\n        av_log(NULL, AV_LOG_FATAL, \"SDL_CreateCond(): %s\\n\", SDL_GetError());\n        ffp->enable_accurate_seek = 0;\n    }\n\n    init_clock(&is->vidclk, &is->videoq.serial);\n    init_clock(&is->audclk, &is->audioq.serial);\n    init_clock(&is->extclk, &is->extclk.serial);\n    is->audio_clock_serial = -1;\n    if (ffp->startup_volume < 0)\n        av_log(NULL, AV_LOG_WARNING, \"-volume=%d < 0, setting to 0\\n\", ffp->startup_volume);\n    if (ffp->startup_volume > 100)\n        av_log(NULL, AV_LOG_WARNING, \"-volume=%d > 100, setting to 100\\n\", ffp->startup_volume);\n    ffp->startup_volume = av_clip(ffp->startup_volume, 0, 100);\n    ffp->startup_volume = av_clip(SDL_MIX_MAXVOLUME * ffp->startup_volume / 100, 0, SDL_MIX_MAXVOLUME);\n    is->audio_volume = ffp->startup_volume;\n    is->muted = 0;\n    is->av_sync_type = ffp->av_sync_type;\n\n    is->play_mutex = SDL_CreateMutex();\n    is->accurate_seek_mutex = SDL_CreateMutex();\n    ffp->is = is;\n    is->pause_req = !ffp->start_on_prepared;\n\n    is->video_refresh_tid = SDL_CreateThreadEx(&is->_video_refresh_tid, video_refresh_thread, ffp, \"ff_vout\");\n    if (!is->video_refresh_tid) {\n        av_freep(&ffp->is);\n        return NULL;\n    }\n\n    is->initialized_decoder = 0;\n    is->read_tid = SDL_CreateThreadEx(&is->_read_tid, read_thread, ffp, \"ff_read\");\n    if (!is->read_tid) {\n        av_log(NULL, AV_LOG_FATAL, \"SDL_CreateThread(): %s\\n\", SDL_GetError());\n        goto fail;\n    }\n\n    if (ffp->async_init_decoder && !ffp->video_disable && ffp->video_mime_type && strlen(ffp->video_mime_type) > 0\n                    && ffp->mediacodec_default_name && strlen(ffp->mediacodec_default_name) > 0) {\n        if (ffp->mediacodec_all_videos || ffp->mediacodec_avc || ffp->mediacodec_hevc || ffp->mediacodec_mpeg2) {\n            decoder_init(&is->viddec, NULL, &is->videoq, is->continue_read_thread);\n            ffp->node_vdec = ffpipeline_init_video_decoder(ffp->pipeline, ffp);\n        }\n    }\n    is->initialized_decoder = 1;\n\n    return is;\nfail:\n    is->initialized_decoder = 1;\n    is->abort_request = true;\n    if (is->video_refresh_tid)\n        SDL_WaitThread(is->video_refresh_tid, NULL);\n    stream_close(ffp);\n    return NULL;\n}\n\n// FFP_MERGE: stream_cycle_channel\n// FFP_MERGE: toggle_full_screen\n// FFP_MERGE: toggle_audio_display\n// FFP_MERGE: refresh_loop_wait_event\n// FFP_MERGE: event_loop\n// FFP_MERGE: opt_frame_size\n// FFP_MERGE: opt_width\n// FFP_MERGE: opt_height\n// FFP_MERGE: opt_format\n// FFP_MERGE: opt_frame_pix_fmt\n// FFP_MERGE: opt_sync\n// FFP_MERGE: opt_seek\n// FFP_MERGE: opt_duration\n// FFP_MERGE: opt_show_mode\n// FFP_MERGE: opt_input_file\n// FFP_MERGE: opt_codec\n// FFP_MERGE: dummy\n// FFP_MERGE: options\n// FFP_MERGE: show_usage\n// FFP_MERGE: show_help_default\nstatic int video_refresh_thread(void *arg)\n{\n    FFPlayer *ffp = arg;\n    VideoState *is = ffp->is;\n    double remaining_time = 0.0;\n    while (!is->abort_request) {\n        if (remaining_time > 0.0)\n            av_usleep((int)(int64_t)(remaining_time * 1000000.0));\n        remaining_time = REFRESH_RATE;\n        if (is->show_mode != SHOW_MODE_NONE && (!is->paused || is->force_refresh))\n            video_refresh(ffp, &remaining_time);\n    }\n\n    return 0;\n}\n\nstatic int lockmgr(void **mtx, enum AVLockOp op)\n{\n    switch (op) {\n    case AV_LOCK_CREATE:\n        *mtx = SDL_CreateMutex();\n        if (!*mtx) {\n            av_log(NULL, AV_LOG_FATAL, \"SDL_CreateMutex(): %s\\n\", SDL_GetError());\n            return 1;\n        }\n        return 0;\n    case AV_LOCK_OBTAIN:\n        return !!SDL_LockMutex(*mtx);\n    case AV_LOCK_RELEASE:\n        return !!SDL_UnlockMutex(*mtx);\n    case AV_LOCK_DESTROY:\n        SDL_DestroyMutex(*mtx);\n        return 0;\n    }\n    return 1;\n}\n\n// FFP_MERGE: main\n\n/*****************************************************************************\n * end last line in ffplay.c\n ****************************************************************************/\n\nstatic bool g_ffmpeg_global_inited = false;\n\ninline static int log_level_av_to_ijk(int av_level)\n{\n    int ijk_level = IJK_LOG_VERBOSE;\n    if      (av_level <= AV_LOG_PANIC)      ijk_level = IJK_LOG_FATAL;\n    else if (av_level <= AV_LOG_FATAL)      ijk_level = IJK_LOG_FATAL;\n    else if (av_level <= AV_LOG_ERROR)      ijk_level = IJK_LOG_ERROR;\n    else if (av_level <= AV_LOG_WARNING)    ijk_level = IJK_LOG_WARN;\n    else if (av_level <= AV_LOG_INFO)       ijk_level = IJK_LOG_INFO;\n    // AV_LOG_VERBOSE means detailed info\n    else if (av_level <= AV_LOG_VERBOSE)    ijk_level = IJK_LOG_INFO;\n    else if (av_level <= AV_LOG_DEBUG)      ijk_level = IJK_LOG_DEBUG;\n    else if (av_level <= AV_LOG_TRACE)      ijk_level = IJK_LOG_VERBOSE;\n    else                                    ijk_level = IJK_LOG_VERBOSE;\n    return ijk_level;\n}\n\ninline static int log_level_ijk_to_av(int ijk_level)\n{\n    int av_level = IJK_LOG_VERBOSE;\n    if      (ijk_level >= IJK_LOG_SILENT)   av_level = AV_LOG_QUIET;\n    else if (ijk_level >= IJK_LOG_FATAL)    av_level = AV_LOG_FATAL;\n    else if (ijk_level >= IJK_LOG_ERROR)    av_level = AV_LOG_ERROR;\n    else if (ijk_level >= IJK_LOG_WARN)     av_level = AV_LOG_WARNING;\n    else if (ijk_level >= IJK_LOG_INFO)     av_level = AV_LOG_INFO;\n    // AV_LOG_VERBOSE means detailed info\n    else if (ijk_level >= IJK_LOG_DEBUG)    av_level = AV_LOG_DEBUG;\n    else if (ijk_level >= IJK_LOG_VERBOSE)  av_level = AV_LOG_TRACE;\n    else if (ijk_level >= IJK_LOG_DEFAULT)  av_level = AV_LOG_TRACE;\n    else if (ijk_level >= IJK_LOG_UNKNOWN)  av_level = AV_LOG_TRACE;\n    else                                    av_level = AV_LOG_TRACE;\n    return av_level;\n}\n\nstatic void ffp_log_callback_brief(void *ptr, int level, const char *fmt, va_list vl)\n{\n    if (level > av_log_get_level())\n        return;\n\n    int ffplv __unused = log_level_av_to_ijk(level);\n    VLOG(ffplv, IJK_LOG_TAG, fmt, vl);\n}\n\nstatic void ffp_log_callback_report(void *ptr, int level, const char *fmt, va_list vl)\n{\n    if (level > av_log_get_level())\n        return;\n\n    int ffplv __unused = log_level_av_to_ijk(level);\n\n    va_list vl2;\n    char line[1024];\n    static int print_prefix = 1;\n\n    va_copy(vl2, vl);\n    // av_log_default_callback(ptr, level, fmt, vl);\n    av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix);\n    va_end(vl2);\n\n    ALOG(ffplv, IJK_LOG_TAG, \"%s\", line);\n}\n\nint ijkav_register_all(void);\nvoid ffp_global_init()\n{\n    if (g_ffmpeg_global_inited)\n        return;\n\n    ALOGD(\"ijkmediaplayer version : %s\", ijkmp_version());\n    /* register all codecs, demux and protocols */\n    avcodec_register_all();\n#if CONFIG_AVDEVICE\n    avdevice_register_all();\n#endif\n#if CONFIG_AVFILTER\n    avfilter_register_all();\n#endif\n    av_register_all();\n\n    ijkav_register_all();\n\n    avformat_network_init();\n\n    av_lockmgr_register(lockmgr);\n    av_log_set_callback(ffp_log_callback_brief);\n\n    av_init_packet(&flush_pkt);\n    flush_pkt.data = (uint8_t *)&flush_pkt;\n\n    g_ffmpeg_global_inited = true;\n}\n\nvoid ffp_global_uninit()\n{\n    if (!g_ffmpeg_global_inited)\n        return;\n\n    av_lockmgr_register(NULL);\n\n    // FFP_MERGE: uninit_opts\n\n    avformat_network_deinit();\n\n    g_ffmpeg_global_inited = false;\n}\n\nvoid ffp_global_set_log_report(int use_report)\n{\n    if (use_report) {\n        av_log_set_callback(ffp_log_callback_report);\n    } else {\n        av_log_set_callback(ffp_log_callback_brief);\n    }\n}\n\nvoid ffp_global_set_log_level(int log_level)\n{\n    int av_level = log_level_ijk_to_av(log_level);\n    av_log_set_level(av_level);\n}\n\nstatic ijk_inject_callback s_inject_callback;\nint inject_callback(void *opaque, int type, void *data, size_t data_size)\n{\n    if (s_inject_callback)\n        return s_inject_callback(opaque, type, data, data_size);\n    return 0;\n}\n\nvoid ffp_global_set_inject_callback(ijk_inject_callback cb)\n{\n    s_inject_callback = cb;\n}\n\nvoid ffp_io_stat_register(void (*cb)(const char *url, int type, int bytes))\n{\n    // avijk_io_stat_register(cb);\n}\n\nvoid ffp_io_stat_complete_register(void (*cb)(const char *url,\n                                              int64_t read_bytes, int64_t total_size,\n                                              int64_t elpased_time, int64_t total_duration))\n{\n    // avijk_io_stat_complete_register(cb);\n}\n\nstatic const char *ffp_context_to_name(void *ptr)\n{\n    return \"FFPlayer\";\n}\n\n\nstatic void *ffp_context_child_next(void *obj, void *prev)\n{\n    return NULL;\n}\n\nstatic const AVClass *ffp_context_child_class_next(const AVClass *prev)\n{\n    return NULL;\n}\n\nconst AVClass ffp_context_class = {\n    .class_name       = \"FFPlayer\",\n    .item_name        = ffp_context_to_name,\n    .option           = ffp_context_options,\n    .version          = LIBAVUTIL_VERSION_INT,\n    .child_next       = ffp_context_child_next,\n    .child_class_next = ffp_context_child_class_next,\n};\n\nstatic const char *ijk_version_info()\n{\n    return IJKPLAYER_VERSION;\n}\n\nFFPlayer *ffp_create()\n{\n    av_log(NULL, AV_LOG_INFO, \"av_version_info: %s\\n\", av_version_info());\n    av_log(NULL, AV_LOG_INFO, \"ijk_version_info: %s\\n\", ijk_version_info());\n\n    FFPlayer* ffp = (FFPlayer*) av_mallocz(sizeof(FFPlayer));\n    if (!ffp)\n        return NULL;\n\n    msg_queue_init(&ffp->msg_queue);\n    ffp->af_mutex = SDL_CreateMutex();\n    ffp->vf_mutex = SDL_CreateMutex();\n\n    ffp_reset_internal(ffp);\n    ffp->av_class = &ffp_context_class;\n    ffp->meta = ijkmeta_create();\n\n    av_opt_set_defaults(ffp);\n    return ffp;\n}\n\nvoid ffp_destroy(FFPlayer *ffp)\n{\n    if (!ffp)\n        return;\n\n    if (ffp->is) {\n        av_log(NULL, AV_LOG_WARNING, \"ffp_destroy_ffplayer: force stream_close()\");\n        stream_close(ffp);\n        ffp->is = NULL;\n    }\n\n    SDL_VoutFreeP(&ffp->vout);\n    SDL_AoutFreeP(&ffp->aout);\n    ffpipenode_free_p(&ffp->node_vdec);\n    ffpipeline_free_p(&ffp->pipeline);\n    ijkmeta_destroy_p(&ffp->meta);\n    ffp_reset_internal(ffp);\n\n    SDL_DestroyMutexP(&ffp->af_mutex);\n    SDL_DestroyMutexP(&ffp->vf_mutex);\n\n    msg_queue_destroy(&ffp->msg_queue);\n\n\n    av_free(ffp);\n}\n\nvoid ffp_destroy_p(FFPlayer **pffp)\n{\n    if (!pffp)\n        return;\n\n    ffp_destroy(*pffp);\n    *pffp = NULL;\n}\n\nstatic AVDictionary **ffp_get_opt_dict(FFPlayer *ffp, int opt_category)\n{\n    assert(ffp);\n\n    switch (opt_category) {\n        case FFP_OPT_CATEGORY_FORMAT:   return &ffp->format_opts;\n        case FFP_OPT_CATEGORY_CODEC:    return &ffp->codec_opts;\n        case FFP_OPT_CATEGORY_SWS:      return &ffp->sws_dict;\n        case FFP_OPT_CATEGORY_PLAYER:   return &ffp->player_opts;\n        case FFP_OPT_CATEGORY_SWR:      return &ffp->swr_opts;\n        default:\n            av_log(ffp, AV_LOG_ERROR, \"unknown option category %d\\n\", opt_category);\n            return NULL;\n    }\n}\n\nstatic int app_func_event(AVApplicationContext *h, int message ,void *data, size_t size)\n{\n    if (!h || !h->opaque || !data)\n        return 0;\n\n    FFPlayer *ffp = (FFPlayer *)h->opaque;\n    if (!ffp->inject_opaque)\n        return 0;\n    if (message == AVAPP_EVENT_IO_TRAFFIC && sizeof(AVAppIOTraffic) == size) {\n        AVAppIOTraffic *event = (AVAppIOTraffic *)(intptr_t)data;\n        if (event->bytes > 0) {\n            ffp->stat.byte_count += event->bytes;\n            SDL_SpeedSampler2Add(&ffp->stat.tcp_read_sampler, event->bytes);\n        }\n    } else if (message == AVAPP_EVENT_ASYNC_STATISTIC && sizeof(AVAppAsyncStatistic) == size) {\n        AVAppAsyncStatistic *statistic =  (AVAppAsyncStatistic *) (intptr_t)data;\n        ffp->stat.buf_backwards = statistic->buf_backwards;\n        ffp->stat.buf_forwards = statistic->buf_forwards;\n        ffp->stat.buf_capacity = statistic->buf_capacity;\n    }\n    return inject_callback(ffp->inject_opaque, message , data, size);\n}\n\nstatic int ijkio_app_func_event(IjkIOApplicationContext *h, int message ,void *data, size_t size)\n{\n    if (!h || !h->opaque || !data)\n        return 0;\n\n    FFPlayer *ffp = (FFPlayer *)h->opaque;\n    if (!ffp->ijkio_inject_opaque)\n        return 0;\n\n    if (message == IJKIOAPP_EVENT_CACHE_STATISTIC && sizeof(IjkIOAppCacheStatistic) == size) {\n        IjkIOAppCacheStatistic *statistic =  (IjkIOAppCacheStatistic *) (intptr_t)data;\n        ffp->stat.cache_physical_pos      = statistic->cache_physical_pos;\n        ffp->stat.cache_file_forwards     = statistic->cache_file_forwards;\n        ffp->stat.cache_file_pos          = statistic->cache_file_pos;\n        ffp->stat.cache_count_bytes       = statistic->cache_count_bytes;\n        ffp->stat.logical_file_size       = statistic->logical_file_size;\n    }\n\n    return 0;\n}\n\nvoid ffp_set_frame_at_time(FFPlayer *ffp, const char *path, int64_t start_time, int64_t end_time, int num, int definition) {\n    if (!ffp->get_img_info) {\n        ffp->get_img_info = av_mallocz(sizeof(GetImgInfo));\n        if (!ffp->get_img_info) {\n            ffp_notify_msg3(ffp, FFP_MSG_GET_IMG_STATE, 0, -1);\n            return;\n        }\n    }\n\n    if (start_time >= 0 && num > 0 && end_time >= 0 && end_time >= start_time) {\n        ffp->get_img_info->img_path   = av_strdup(path);\n        ffp->get_img_info->start_time = start_time;\n        ffp->get_img_info->end_time   = end_time;\n        ffp->get_img_info->num        = num;\n        ffp->get_img_info->count      = num;\n        if (definition== HD_IMAGE) {\n            ffp->get_img_info->width  = 640;\n            ffp->get_img_info->height = 360;\n        } else if (definition == SD_IMAGE) {\n            ffp->get_img_info->width  = 320;\n            ffp->get_img_info->height = 180;\n        } else {\n            ffp->get_img_info->width  = 160;\n            ffp->get_img_info->height = 90;\n        }\n    } else {\n        ffp->get_img_info->count = 0;\n        ffp_notify_msg3(ffp, FFP_MSG_GET_IMG_STATE, 0, -1);\n    }\n}\n\nvoid *ffp_set_ijkio_inject_opaque(FFPlayer *ffp, void *opaque)\n{\n    if (!ffp)\n        return NULL;\n    void *prev_weak_thiz = ffp->ijkio_inject_opaque;\n    ffp->ijkio_inject_opaque = opaque;\n\n    ijkio_manager_destroyp(&ffp->ijkio_manager_ctx);\n    ijkio_manager_create(&ffp->ijkio_manager_ctx, ffp);\n    ijkio_manager_set_callback(ffp->ijkio_manager_ctx, ijkio_app_func_event);\n    ffp_set_option_intptr(ffp, FFP_OPT_CATEGORY_FORMAT, \"ijkiomanager\", (uintptr_t)ffp->ijkio_manager_ctx);\n\n    return prev_weak_thiz;\n}\n\nvoid *ffp_set_inject_opaque(FFPlayer *ffp, void *opaque)\n{\n    if (!ffp)\n        return NULL;\n    void *prev_weak_thiz = ffp->inject_opaque;\n    ffp->inject_opaque = opaque;\n\n    av_application_closep(&ffp->app_ctx);\n    av_application_open(&ffp->app_ctx, ffp);\n    ffp_set_option_intptr(ffp, FFP_OPT_CATEGORY_FORMAT, \"ijkapplication\", (uint64_t)(intptr_t)ffp->app_ctx);\n\n    ffp->app_ctx->func_on_app_event = app_func_event;\n    return prev_weak_thiz;\n}\n\nvoid ffp_set_option(FFPlayer *ffp, int opt_category, const char *name, const char *value)\n{\n    if (!ffp)\n        return;\n\n    AVDictionary **dict = ffp_get_opt_dict(ffp, opt_category);\n    av_dict_set(dict, name, value, 0);\n}\n\nvoid ffp_set_option_int(FFPlayer *ffp, int opt_category, const char *name, int64_t value)\n{\n    if (!ffp)\n        return;\n\n    AVDictionary **dict = ffp_get_opt_dict(ffp, opt_category);\n    av_dict_set_int(dict, name, value, 0);\n}\n\nvoid ffp_set_option_intptr(FFPlayer *ffp, int opt_category, const char *name, uintptr_t value)\n{\n    if (!ffp)\n        return;\n\n    AVDictionary **dict = ffp_get_opt_dict(ffp, opt_category);\n    av_dict_set_intptr(dict, name, value, 0);\n}\n\nvoid ffp_set_overlay_format(FFPlayer *ffp, int chroma_fourcc)\n{\n    switch (chroma_fourcc) {\n        case SDL_FCC__GLES2:\n        case SDL_FCC_I420:\n        case SDL_FCC_YV12:\n        case SDL_FCC_RV16:\n        case SDL_FCC_RV24:\n        case SDL_FCC_RV32:\n            ffp->overlay_format = chroma_fourcc;\n            break;\n#ifdef __APPLE__\n        case SDL_FCC_I444P10LE:\n            ffp->overlay_format = chroma_fourcc;\n            break;\n#endif\n        default:\n            av_log(ffp, AV_LOG_ERROR, \"ffp_set_overlay_format: unknown chroma fourcc: %d\\n\", chroma_fourcc);\n            break;\n    }\n}\n\nint ffp_get_video_codec_info(FFPlayer *ffp, char **codec_info)\n{\n    if (!codec_info)\n        return -1;\n\n    // FIXME: not thread-safe\n    if (ffp->video_codec_info) {\n        *codec_info = strdup(ffp->video_codec_info);\n    } else {\n        *codec_info = NULL;\n    }\n    return 0;\n}\n\nint ffp_get_audio_codec_info(FFPlayer *ffp, char **codec_info)\n{\n    if (!codec_info)\n        return -1;\n\n    // FIXME: not thread-safe\n    if (ffp->audio_codec_info) {\n        *codec_info = strdup(ffp->audio_codec_info);\n    } else {\n        *codec_info = NULL;\n    }\n    return 0;\n}\n\nstatic void ffp_show_dict(FFPlayer *ffp, const char *tag, AVDictionary *dict)\n{\n    AVDictionaryEntry *t = NULL;\n\n    while ((t = av_dict_get(dict, \"\", t, AV_DICT_IGNORE_SUFFIX))) {\n        av_log(ffp, AV_LOG_INFO, \"%-*s: %-*s = %s\\n\", 12, tag, 28, t->key, t->value);\n    }\n}\n\n#define FFP_VERSION_MODULE_NAME_LENGTH 13\nstatic void ffp_show_version_str(FFPlayer *ffp, const char *module, const char *version)\n{\n        av_log(ffp, AV_LOG_INFO, \"%-*s: %s\\n\", FFP_VERSION_MODULE_NAME_LENGTH, module, version);\n}\n\nstatic void ffp_show_version_int(FFPlayer *ffp, const char *module, unsigned version)\n{\n    av_log(ffp, AV_LOG_INFO, \"%-*s: %u.%u.%u\\n\",\n           FFP_VERSION_MODULE_NAME_LENGTH, module,\n           (unsigned int)IJKVERSION_GET_MAJOR(version),\n           (unsigned int)IJKVERSION_GET_MINOR(version),\n           (unsigned int)IJKVERSION_GET_MICRO(version));\n}\n\nint ffp_prepare_async_l(FFPlayer *ffp, const char *file_name)\n{\n    assert(ffp);\n    assert(!ffp->is);\n    assert(file_name);\n\n    if (av_stristart(file_name, \"rtmp\", NULL) ||\n        av_stristart(file_name, \"rtsp\", NULL)) {\n        // There is total different meaning for 'timeout' option in rtmp\n        av_log(ffp, AV_LOG_WARNING, \"remove 'timeout' option for rtmp.\\n\");\n        av_dict_set(&ffp->format_opts, \"timeout\", NULL, 0);\n    }\n\n    /* there is a length limit in avformat */\n    if (strlen(file_name) + 1 > 1024) {\n        av_log(ffp, AV_LOG_ERROR, \"%s too long url\\n\", __func__);\n        if (avio_find_protocol_name(\"ijklongurl:\")) {\n            av_dict_set(&ffp->format_opts, \"ijklongurl-url\", file_name, 0);\n            file_name = \"ijklongurl:\";\n        }\n    }\n\n    av_log(NULL, AV_LOG_INFO, \"===== versions =====\\n\");\n    ffp_show_version_str(ffp, \"ijkplayer\",      ijk_version_info());\n    ffp_show_version_str(ffp, \"FFmpeg\",         av_version_info());\n    ffp_show_version_int(ffp, \"libavutil\",      avutil_version());\n    ffp_show_version_int(ffp, \"libavcodec\",     avcodec_version());\n    ffp_show_version_int(ffp, \"libavformat\",    avformat_version());\n    ffp_show_version_int(ffp, \"libswscale\",     swscale_version());\n    ffp_show_version_int(ffp, \"libswresample\",  swresample_version());\n    av_log(NULL, AV_LOG_INFO, \"===== options =====\\n\");\n    ffp_show_dict(ffp, \"player-opts\", ffp->player_opts);\n    ffp_show_dict(ffp, \"format-opts\", ffp->format_opts);\n    ffp_show_dict(ffp, \"codec-opts \", ffp->codec_opts);\n    ffp_show_dict(ffp, \"sws-opts   \", ffp->sws_dict);\n    ffp_show_dict(ffp, \"swr-opts   \", ffp->swr_opts);\n    av_log(NULL, AV_LOG_INFO, \"===================\\n\");\n\n    av_opt_set_dict(ffp, &ffp->player_opts);\n    if (!ffp->aout) {\n        ffp->aout = ffpipeline_open_audio_output(ffp->pipeline, ffp);\n        if (!ffp->aout)\n            return -1;\n    }\n\n#if CONFIG_AVFILTER\n    if (ffp->vfilter0) {\n        GROW_ARRAY(ffp->vfilters_list, ffp->nb_vfilters);\n        ffp->vfilters_list[ffp->nb_vfilters - 1] = ffp->vfilter0;\n    }\n#endif\n\n    VideoState *is = stream_open(ffp, file_name, NULL);\n    if (!is) {\n        av_log(NULL, AV_LOG_WARNING, \"ffp_prepare_async_l: stream_open failed OOM\");\n        return EIJK_OUT_OF_MEMORY;\n    }\n\n    ffp->is = is;\n    ffp->input_filename = av_strdup(file_name);\n    return 0;\n}\n\nint ffp_start_from_l(FFPlayer *ffp, long msec)\n{\n    assert(ffp);\n    VideoState *is = ffp->is;\n    if (!is)\n        return EIJK_NULL_IS_PTR;\n\n    ffp->auto_resume = 1;\n    ffp_toggle_buffering(ffp, 1);\n    ffp_seek_to_l(ffp, msec);\n    return 0;\n}\n\nint ffp_start_l(FFPlayer *ffp)\n{\n    assert(ffp);\n    VideoState *is = ffp->is;\n    if (!is)\n        return EIJK_NULL_IS_PTR;\n\n    toggle_pause(ffp, 0);\n    return 0;\n}\n\nint ffp_pause_l(FFPlayer *ffp)\n{\n    assert(ffp);\n    VideoState *is = ffp->is;\n    if (!is)\n        return EIJK_NULL_IS_PTR;\n\n    toggle_pause(ffp, 1);\n    return 0;\n}\n\nint ffp_is_paused_l(FFPlayer *ffp)\n{\n    assert(ffp);\n    VideoState *is = ffp->is;\n    if (!is)\n        return 1;\n\n    return is->paused;\n}\n\nint ffp_stop_l(FFPlayer *ffp)\n{\n    assert(ffp);\n    VideoState *is = ffp->is;\n    if (is) {\n        is->abort_request = 1;\n        toggle_pause(ffp, 1);\n    }\n\n    msg_queue_abort(&ffp->msg_queue);\n    if (ffp->enable_accurate_seek && is && is->accurate_seek_mutex\n        && is->audio_accurate_seek_cond && is->video_accurate_seek_cond) {\n        SDL_LockMutex(is->accurate_seek_mutex);\n        is->audio_accurate_seek_req = 0;\n        is->video_accurate_seek_req = 0;\n        SDL_CondSignal(is->audio_accurate_seek_cond);\n        SDL_CondSignal(is->video_accurate_seek_cond);\n        SDL_UnlockMutex(is->accurate_seek_mutex);\n    }\n    return 0;\n}\n\nint ffp_wait_stop_l(FFPlayer *ffp)\n{\n    assert(ffp);\n\n    if (ffp->is) {\n        ffp_stop_l(ffp);\n        stream_close(ffp);\n        ffp->is = NULL;\n    }\n    return 0;\n}\n\nint ffp_seek_to_l(FFPlayer *ffp, long msec)\n{\n    assert(ffp);\n    VideoState *is = ffp->is;\n    int64_t start_time = 0;\n    int64_t seek_pos = milliseconds_to_fftime(msec);\n    int64_t duration = milliseconds_to_fftime(ffp_get_duration_l(ffp));\n\n    if (!is)\n        return EIJK_NULL_IS_PTR;\n\n    if (duration > 0 && seek_pos >= duration && ffp->enable_accurate_seek) {\n        toggle_pause(ffp, 1);\n        ffp_notify_msg1(ffp, FFP_MSG_COMPLETED);\n        return 0;\n    }\n\n    start_time = is->ic->start_time;\n    if (start_time > 0 && start_time != AV_NOPTS_VALUE)\n        seek_pos += start_time;\n\n    // FIXME: 9 seek by bytes\n    // FIXME: 9 seek out of range\n    // FIXME: 9 seekable\n    av_log(ffp, AV_LOG_DEBUG, \"stream_seek %\"PRId64\"(%d) + %\"PRId64\", \\n\", seek_pos, (int)msec, start_time);\n    stream_seek(is, seek_pos, 0, 0);\n    return 0;\n}\n\nlong ffp_get_current_position_l(FFPlayer *ffp)\n{\n    assert(ffp);\n    VideoState *is = ffp->is;\n    if (!is || !is->ic)\n        return 0;\n\n    int64_t start_time = is->ic->start_time;\n    int64_t start_diff = 0;\n    if (start_time > 0 && start_time != AV_NOPTS_VALUE)\n        start_diff = fftime_to_milliseconds(start_time);\n\n    int64_t pos = 0;\n    double pos_clock = get_master_clock(is);\n    if (isnan(pos_clock)) {\n        pos = fftime_to_milliseconds(is->seek_pos);\n    } else {\n        pos = pos_clock * 1000;\n    }\n\n    // If using REAL time and not ajusted, then return the real pos as calculated from the stream\n    // the use case for this is primarily when using a custom non-seekable data source that starts\n    // with a buffer that is NOT the start of the stream.  We want the get_current_position to\n    // return the time in the stream, and not the player's internal clock.\n    if (ffp->no_time_adjust) {\n        return (long)pos;\n    }\n\n    if (pos < 0 || pos < start_diff)\n        return 0;\n\n    int64_t adjust_pos = pos - start_diff;\n    return (long)adjust_pos;\n}\n\nlong ffp_get_duration_l(FFPlayer *ffp)\n{\n    assert(ffp);\n    VideoState *is = ffp->is;\n    if (!is || !is->ic)\n        return 0;\n\n    int64_t duration = fftime_to_milliseconds(is->ic->duration);\n    if (duration < 0)\n        return 0;\n\n    return (long)duration;\n}\n\nlong ffp_get_playable_duration_l(FFPlayer *ffp)\n{\n    assert(ffp);\n    if (!ffp)\n        return 0;\n\n    return (long)ffp->playable_duration_ms;\n}\n\nvoid ffp_set_loop(FFPlayer *ffp, int loop)\n{\n    assert(ffp);\n    if (!ffp)\n        return;\n    ffp->loop = loop;\n}\n\nint ffp_get_loop(FFPlayer *ffp)\n{\n    assert(ffp);\n    if (!ffp)\n        return 1;\n    return ffp->loop;\n}\n\nint ffp_packet_queue_init(PacketQueue *q)\n{\n    return packet_queue_init(q);\n}\n\nvoid ffp_packet_queue_destroy(PacketQueue *q)\n{\n    return packet_queue_destroy(q);\n}\n\nvoid ffp_packet_queue_abort(PacketQueue *q)\n{\n    return packet_queue_abort(q);\n}\n\nvoid ffp_packet_queue_start(PacketQueue *q)\n{\n    return packet_queue_start(q);\n}\n\nvoid ffp_packet_queue_flush(PacketQueue *q)\n{\n    return packet_queue_flush(q);\n}\n\nint ffp_packet_queue_get(PacketQueue *q, AVPacket *pkt, int block, int *serial)\n{\n    return packet_queue_get(q, pkt, block, serial);\n}\n\nint ffp_packet_queue_get_or_buffering(FFPlayer *ffp, PacketQueue *q, AVPacket *pkt, int *serial, int *finished)\n{\n    return packet_queue_get_or_buffering(ffp, q, pkt, serial, finished);\n}\n\nint ffp_packet_queue_put(PacketQueue *q, AVPacket *pkt)\n{\n    return packet_queue_put(q, pkt);\n}\n\nbool ffp_is_flush_packet(AVPacket *pkt)\n{\n    if (!pkt)\n        return false;\n\n    return pkt->data == flush_pkt.data;\n}\n\nFrame *ffp_frame_queue_peek_writable(FrameQueue *f)\n{\n    return frame_queue_peek_writable(f);\n}\n\nvoid ffp_frame_queue_push(FrameQueue *f)\n{\n    return frame_queue_push(f);\n}\n\nint ffp_queue_picture(FFPlayer *ffp, AVFrame *src_frame, double pts, double duration, int64_t pos, int serial)\n{\n    return queue_picture(ffp, src_frame, pts, duration, pos, serial);\n}\n\nint ffp_get_master_sync_type(VideoState *is)\n{\n    return get_master_sync_type(is);\n}\n\ndouble ffp_get_master_clock(VideoState *is)\n{\n    return get_master_clock(is);\n}\n\nvoid ffp_toggle_buffering_l(FFPlayer *ffp, int buffering_on)\n{\n    if (!ffp->packet_buffering)\n        return;\n\n    VideoState *is = ffp->is;\n    if (buffering_on && !is->buffering_on) {\n        av_log(ffp, AV_LOG_DEBUG, \"ffp_toggle_buffering_l: start\\n\");\n        is->buffering_on = 1;\n        stream_update_pause_l(ffp);\n        if (is->seek_req) {\n            is->seek_buffering = 1;\n            ffp_notify_msg2(ffp, FFP_MSG_BUFFERING_START, 1);\n        } else {\n            ffp_notify_msg2(ffp, FFP_MSG_BUFFERING_START, 0);\n        }\n    } else if (!buffering_on && is->buffering_on){\n        av_log(ffp, AV_LOG_DEBUG, \"ffp_toggle_buffering_l: end\\n\");\n        is->buffering_on = 0;\n        stream_update_pause_l(ffp);\n        if (is->seek_buffering) {\n            is->seek_buffering = 0;\n            ffp_notify_msg2(ffp, FFP_MSG_BUFFERING_END, 1);\n        } else {\n            ffp_notify_msg2(ffp, FFP_MSG_BUFFERING_END, 0);\n        }\n    }\n}\n\nvoid ffp_toggle_buffering(FFPlayer *ffp, int start_buffering)\n{\n    SDL_LockMutex(ffp->is->play_mutex);\n    ffp_toggle_buffering_l(ffp, start_buffering);\n    SDL_UnlockMutex(ffp->is->play_mutex);\n}\n\nvoid ffp_track_statistic_l(FFPlayer *ffp, AVStream *st, PacketQueue *q, FFTrackCacheStatistic *cache)\n{\n    assert(cache);\n\n    if (q) {\n        cache->bytes   = q->size;\n        cache->packets = q->nb_packets;\n    }\n\n    if (q && st && st->time_base.den > 0 && st->time_base.num > 0) {\n        cache->duration = q->duration * av_q2d(st->time_base) * 1000;\n    }\n}\n\nvoid ffp_audio_statistic_l(FFPlayer *ffp)\n{\n    VideoState *is = ffp->is;\n    ffp_track_statistic_l(ffp, is->audio_st, &is->audioq, &ffp->stat.audio_cache);\n}\n\nvoid ffp_video_statistic_l(FFPlayer *ffp)\n{\n    VideoState *is = ffp->is;\n    ffp_track_statistic_l(ffp, is->video_st, &is->videoq, &ffp->stat.video_cache);\n}\n\nvoid ffp_statistic_l(FFPlayer *ffp)\n{\n    ffp_audio_statistic_l(ffp);\n    ffp_video_statistic_l(ffp);\n}\n\nvoid ffp_check_buffering_l(FFPlayer *ffp)\n{\n    VideoState *is            = ffp->is;\n    int hwm_in_ms             = ffp->dcc.current_high_water_mark_in_ms; // use fast water mark for first loading\n    int buf_size_percent      = -1;\n    int buf_time_percent      = -1;\n    int hwm_in_bytes          = ffp->dcc.high_water_mark_in_bytes;\n    int need_start_buffering  = 0;\n    int audio_time_base_valid = 0;\n    int video_time_base_valid = 0;\n    int64_t buf_time_position = -1;\n\n    if(is->audio_st)\n        audio_time_base_valid = is->audio_st->time_base.den > 0 && is->audio_st->time_base.num > 0;\n    if(is->video_st)\n        video_time_base_valid = is->video_st->time_base.den > 0 && is->video_st->time_base.num > 0;\n\n    if (hwm_in_ms > 0) {\n        int     cached_duration_in_ms = -1;\n        int64_t audio_cached_duration = -1;\n        int64_t video_cached_duration = -1;\n\n        if (is->audio_st && audio_time_base_valid) {\n            audio_cached_duration = ffp->stat.audio_cache.duration;\n#ifdef FFP_SHOW_DEMUX_CACHE\n            int audio_cached_percent = (int)av_rescale(audio_cached_duration, 1005, hwm_in_ms * 10);\n            av_log(ffp, AV_LOG_DEBUG, \"audio cache=%%%d milli:(%d/%d) bytes:(%d/%d) packet:(%d/%d)\\n\", audio_cached_percent,\n                  (int)audio_cached_duration, hwm_in_ms,\n                  is->audioq.size, hwm_in_bytes,\n                  is->audioq.nb_packets, MIN_FRAMES);\n#endif\n        }\n\n        if (is->video_st && video_time_base_valid) {\n            video_cached_duration = ffp->stat.video_cache.duration;\n#ifdef FFP_SHOW_DEMUX_CACHE\n            int video_cached_percent = (int)av_rescale(video_cached_duration, 1005, hwm_in_ms * 10);\n            av_log(ffp, AV_LOG_DEBUG, \"video cache=%%%d milli:(%d/%d) bytes:(%d/%d) packet:(%d/%d)\\n\", video_cached_percent,\n                  (int)video_cached_duration, hwm_in_ms,\n                  is->videoq.size, hwm_in_bytes,\n                  is->videoq.nb_packets, MIN_FRAMES);\n#endif\n        }\n\n        if (video_cached_duration > 0 && audio_cached_duration > 0) {\n            cached_duration_in_ms = (int)IJKMIN(video_cached_duration, audio_cached_duration);\n        } else if (video_cached_duration > 0) {\n            cached_duration_in_ms = (int)video_cached_duration;\n        } else if (audio_cached_duration > 0) {\n            cached_duration_in_ms = (int)audio_cached_duration;\n        }\n\n        if (cached_duration_in_ms >= 0) {\n            buf_time_position = ffp_get_current_position_l(ffp) + cached_duration_in_ms;\n            ffp->playable_duration_ms = buf_time_position;\n\n            buf_time_percent = (int)av_rescale(cached_duration_in_ms, 1005, hwm_in_ms * 10);\n#ifdef FFP_SHOW_DEMUX_CACHE\n            av_log(ffp, AV_LOG_DEBUG, \"time cache=%%%d (%d/%d)\\n\", buf_time_percent, cached_duration_in_ms, hwm_in_ms);\n#endif\n#ifdef FFP_NOTIFY_BUF_TIME\n            ffp_notify_msg3(ffp, FFP_MSG_BUFFERING_TIME_UPDATE, cached_duration_in_ms, hwm_in_ms);\n#endif\n        }\n    }\n\n    int cached_size = is->audioq.size + is->videoq.size;\n    if (hwm_in_bytes > 0) {\n        buf_size_percent = (int)av_rescale(cached_size, 1005, hwm_in_bytes * 10);\n#ifdef FFP_SHOW_DEMUX_CACHE\n        av_log(ffp, AV_LOG_DEBUG, \"size cache=%%%d (%d/%d)\\n\", buf_size_percent, cached_size, hwm_in_bytes);\n#endif\n#ifdef FFP_NOTIFY_BUF_BYTES\n        ffp_notify_msg3(ffp, FFP_MSG_BUFFERING_BYTES_UPDATE, cached_size, hwm_in_bytes);\n#endif\n    }\n\n    int buf_percent = -1;\n    if (buf_time_percent >= 0) {\n        // alwas depend on cache duration if valid\n        if (buf_time_percent >= 100)\n            need_start_buffering = 1;\n        buf_percent = buf_time_percent;\n    } else {\n        if (buf_size_percent >= 100)\n            need_start_buffering = 1;\n        buf_percent = buf_size_percent;\n    }\n\n    if (buf_time_percent >= 0 && buf_size_percent >= 0) {\n        buf_percent = FFMIN(buf_time_percent, buf_size_percent);\n    }\n    if (buf_percent) {\n#ifdef FFP_SHOW_BUF_POS\n        av_log(ffp, AV_LOG_DEBUG, \"buf pos=%\"PRId64\", %%%d\\n\", buf_time_position, buf_percent);\n#endif\n        ffp_notify_msg3(ffp, FFP_MSG_BUFFERING_UPDATE, (int)buf_time_position, buf_percent);\n    }\n\n    if (need_start_buffering) {\n        if (hwm_in_ms < ffp->dcc.next_high_water_mark_in_ms) {\n            hwm_in_ms = ffp->dcc.next_high_water_mark_in_ms;\n        } else {\n            hwm_in_ms *= 2;\n        }\n\n        if (hwm_in_ms > ffp->dcc.last_high_water_mark_in_ms)\n            hwm_in_ms = ffp->dcc.last_high_water_mark_in_ms;\n\n        ffp->dcc.current_high_water_mark_in_ms = hwm_in_ms;\n\n        if (is->buffer_indicator_queue && is->buffer_indicator_queue->nb_packets > 0) {\n            if (   (is->audioq.nb_packets >= MIN_MIN_FRAMES || is->audio_stream < 0 || is->audioq.abort_request)\n                && (is->videoq.nb_packets >= MIN_MIN_FRAMES || is->video_stream < 0 || is->videoq.abort_request)) {\n                ffp_toggle_buffering(ffp, 0);\n            }\n        }\n    }\n}\n\nint ffp_video_thread(FFPlayer *ffp)\n{\n    return ffplay_video_thread(ffp);\n}\n\nvoid ffp_set_video_codec_info(FFPlayer *ffp, const char *module, const char *codec)\n{\n    av_freep(&ffp->video_codec_info);\n    ffp->video_codec_info = av_asprintf(\"%s, %s\", module ? module : \"\", codec ? codec : \"\");\n    av_log(ffp, AV_LOG_INFO, \"VideoCodec: %s\\n\", ffp->video_codec_info);\n}\n\nvoid ffp_set_audio_codec_info(FFPlayer *ffp, const char *module, const char *codec)\n{\n    av_freep(&ffp->audio_codec_info);\n    ffp->audio_codec_info = av_asprintf(\"%s, %s\", module ? module : \"\", codec ? codec : \"\");\n    av_log(ffp, AV_LOG_INFO, \"AudioCodec: %s\\n\", ffp->audio_codec_info);\n}\n\nvoid ffp_set_subtitle_codec_info(FFPlayer *ffp, const char *module, const char *codec)\n{\n    av_freep(&ffp->subtitle_codec_info);\n    ffp->subtitle_codec_info = av_asprintf(\"%s, %s\", module ? module : \"\", codec ? codec : \"\");\n    av_log(ffp, AV_LOG_INFO, \"SubtitleCodec: %s\\n\", ffp->subtitle_codec_info);\n}\n\nvoid ffp_set_playback_rate(FFPlayer *ffp, float rate)\n{\n    if (!ffp)\n        return;\n\n    av_log(ffp, AV_LOG_INFO, \"Playback rate: %f\\n\", rate);\n    ffp->pf_playback_rate = rate;\n    ffp->pf_playback_rate_changed = 1;\n}\n\nvoid ffp_set_playback_volume(FFPlayer *ffp, float volume)\n{\n    if (!ffp)\n        return;\n    ffp->pf_playback_volume = volume;\n    ffp->pf_playback_volume_changed = 1;\n}\n\nint ffp_get_video_rotate_degrees(FFPlayer *ffp)\n{\n    VideoState *is = ffp->is;\n    if (!is)\n        return 0;\n\n    int theta  = abs((int)((int64_t)round(fabs(get_rotation(is->video_st))) % 360));\n    switch (theta) {\n        case 0:\n        case 90:\n        case 180:\n        case 270:\n            break;\n        case 360:\n            theta = 0;\n            break;\n        default:\n            ALOGW(\"Unknown rotate degress: %d\\n\", theta);\n            theta = 0;\n            break;\n    }\n\n    return theta;\n}\n\nint ffp_set_stream_selected(FFPlayer *ffp, int stream, int selected)\n{\n    VideoState        *is = ffp->is;\n    AVFormatContext   *ic = NULL;\n    AVCodecParameters *codecpar = NULL;\n    if (!is)\n        return -1;\n    ic = is->ic;\n    if (!ic)\n        return -1;\n\n    if (stream < 0 || stream >= ic->nb_streams) {\n        av_log(ffp, AV_LOG_ERROR, \"invalid stream index %d >= stream number (%d)\\n\", stream, ic->nb_streams);\n        return -1;\n    }\n\n    codecpar = ic->streams[stream]->codecpar;\n\n    if (selected) {\n        switch (codecpar->codec_type) {\n            case AVMEDIA_TYPE_VIDEO:\n                if (stream != is->video_stream && is->video_stream >= 0)\n                    stream_component_close(ffp, is->video_stream);\n                break;\n            case AVMEDIA_TYPE_AUDIO:\n                if (stream != is->audio_stream && is->audio_stream >= 0)\n                    stream_component_close(ffp, is->audio_stream);\n                break;\n            case AVMEDIA_TYPE_SUBTITLE:\n                if (stream != is->subtitle_stream && is->subtitle_stream >= 0)\n                    stream_component_close(ffp, is->subtitle_stream);\n                break;\n            default:\n                av_log(ffp, AV_LOG_ERROR, \"select invalid stream %d of video type %d\\n\", stream, codecpar->codec_type);\n                return -1;\n        }\n        return stream_component_open(ffp, stream);\n    } else {\n        switch (codecpar->codec_type) {\n            case AVMEDIA_TYPE_VIDEO:\n                if (stream == is->video_stream)\n                    stream_component_close(ffp, is->video_stream);\n                break;\n            case AVMEDIA_TYPE_AUDIO:\n                if (stream == is->audio_stream)\n                    stream_component_close(ffp, is->audio_stream);\n                break;\n            case AVMEDIA_TYPE_SUBTITLE:\n                if (stream == is->subtitle_stream)\n                    stream_component_close(ffp, is->subtitle_stream);\n                break;\n            default:\n                av_log(ffp, AV_LOG_ERROR, \"select invalid stream %d of audio type %d\\n\", stream, codecpar->codec_type);\n                return -1;\n        }\n        return 0;\n    }\n}\n\nfloat ffp_get_property_float(FFPlayer *ffp, int id, float default_value)\n{\n    switch (id) {\n        case FFP_PROP_FLOAT_VIDEO_DECODE_FRAMES_PER_SECOND:\n            return ffp ? ffp->stat.vdps : default_value;\n        case FFP_PROP_FLOAT_VIDEO_OUTPUT_FRAMES_PER_SECOND:\n            return ffp ? ffp->stat.vfps : default_value;\n        case FFP_PROP_FLOAT_PLAYBACK_RATE:\n            return ffp ? ffp->pf_playback_rate : default_value;\n        case FFP_PROP_FLOAT_AVDELAY:\n            return ffp ? ffp->stat.avdelay : default_value;\n        case FFP_PROP_FLOAT_AVDIFF:\n            return ffp ? ffp->stat.avdiff : default_value;\n        case FFP_PROP_FLOAT_PLAYBACK_VOLUME:\n            return ffp ? ffp->pf_playback_volume : default_value;\n        case FFP_PROP_FLOAT_DROP_FRAME_RATE:\n            return ffp ? ffp->stat.drop_frame_rate : default_value;\n        default:\n            return default_value;\n    }\n}\n\nvoid ffp_set_property_float(FFPlayer *ffp, int id, float value)\n{\n    switch (id) {\n        case FFP_PROP_FLOAT_PLAYBACK_RATE:\n            ffp_set_playback_rate(ffp, value);\n            break;\n        case FFP_PROP_FLOAT_PLAYBACK_VOLUME:\n            ffp_set_playback_volume(ffp, value);\n            break;\n        default:\n            return;\n    }\n}\n\nint64_t ffp_get_property_int64(FFPlayer *ffp, int id, int64_t default_value)\n{\n    switch (id) {\n        case FFP_PROP_INT64_SELECTED_VIDEO_STREAM:\n            if (!ffp || !ffp->is)\n                return default_value;\n            return ffp->is->video_stream;\n        case FFP_PROP_INT64_SELECTED_AUDIO_STREAM:\n            if (!ffp || !ffp->is)\n                return default_value;\n            return ffp->is->audio_stream;\n        case FFP_PROP_INT64_SELECTED_TIMEDTEXT_STREAM:\n            if (!ffp || !ffp->is)\n                return default_value;\n            return ffp->is->subtitle_stream;\n        case FFP_PROP_INT64_VIDEO_DECODER:\n            if (!ffp)\n                return default_value;\n            return ffp->stat.vdec_type;\n        case FFP_PROP_INT64_AUDIO_DECODER:\n            return FFP_PROPV_DECODER_AVCODEC;\n\n        case FFP_PROP_INT64_VIDEO_CACHED_DURATION:\n            if (!ffp)\n                return default_value;\n            return ffp->stat.video_cache.duration;\n        case FFP_PROP_INT64_AUDIO_CACHED_DURATION:\n            if (!ffp)\n                return default_value;\n            return ffp->stat.audio_cache.duration;\n        case FFP_PROP_INT64_VIDEO_CACHED_BYTES:\n            if (!ffp)\n                return default_value;\n            return ffp->stat.video_cache.bytes;\n        case FFP_PROP_INT64_AUDIO_CACHED_BYTES:\n            if (!ffp)\n                return default_value;\n            return ffp->stat.audio_cache.bytes;\n        case FFP_PROP_INT64_VIDEO_CACHED_PACKETS:\n            if (!ffp)\n                return default_value;\n            return ffp->stat.video_cache.packets;\n        case FFP_PROP_INT64_AUDIO_CACHED_PACKETS:\n            if (!ffp)\n                return default_value;\n            return ffp->stat.audio_cache.packets;\n        case FFP_PROP_INT64_BIT_RATE:\n            return ffp ? ffp->stat.bit_rate : default_value;\n        case FFP_PROP_INT64_TCP_SPEED:\n            return ffp ? SDL_SpeedSampler2GetSpeed(&ffp->stat.tcp_read_sampler) : default_value;\n        case FFP_PROP_INT64_ASYNC_STATISTIC_BUF_BACKWARDS:\n            if (!ffp)\n                return default_value;\n            return ffp->stat.buf_backwards;\n        case FFP_PROP_INT64_ASYNC_STATISTIC_BUF_FORWARDS:\n            if (!ffp)\n                return default_value;\n            return ffp->stat.buf_forwards;\n        case FFP_PROP_INT64_ASYNC_STATISTIC_BUF_CAPACITY:\n            if (!ffp)\n                return default_value;\n            return ffp->stat.buf_capacity;\n        case FFP_PROP_INT64_LATEST_SEEK_LOAD_DURATION:\n            return ffp ? ffp->stat.latest_seek_load_duration : default_value;\n        case FFP_PROP_INT64_TRAFFIC_STATISTIC_BYTE_COUNT:\n            return ffp ? ffp->stat.byte_count : default_value;\n        case FFP_PROP_INT64_CACHE_STATISTIC_PHYSICAL_POS:\n            if (!ffp)\n                return default_value;\n            return ffp->stat.cache_physical_pos;\n       case FFP_PROP_INT64_CACHE_STATISTIC_FILE_FORWARDS:\n            if (!ffp)\n                return default_value;\n            return ffp->stat.cache_file_forwards;\n       case FFP_PROP_INT64_CACHE_STATISTIC_FILE_POS:\n            if (!ffp)\n                return default_value;\n            return ffp->stat.cache_file_pos;\n       case FFP_PROP_INT64_CACHE_STATISTIC_COUNT_BYTES:\n            if (!ffp)\n                return default_value;\n            return ffp->stat.cache_count_bytes;\n       case FFP_PROP_INT64_LOGICAL_FILE_SIZE:\n            if (!ffp)\n                return default_value;\n            return ffp->stat.logical_file_size;\n        default:\n            return default_value;\n    }\n}\n\nvoid ffp_set_property_int64(FFPlayer *ffp, int id, int64_t value)\n{\n    switch (id) {\n        // case FFP_PROP_INT64_SELECTED_VIDEO_STREAM:\n        // case FFP_PROP_INT64_SELECTED_AUDIO_STREAM:\n        case FFP_PROP_INT64_SHARE_CACHE_DATA:\n            if (ffp) {\n                if (value) {\n                    ijkio_manager_will_share_cache_map(ffp->ijkio_manager_ctx);\n                } else {\n                    ijkio_manager_did_share_cache_map(ffp->ijkio_manager_ctx);\n                }\n            }\n            break;\n        case FFP_PROP_INT64_IMMEDIATE_RECONNECT:\n            if (ffp) {\n                ijkio_manager_immediate_reconnect(ffp->ijkio_manager_ctx);\n            }\n        default:\n            break;\n    }\n}\n\nIjkMediaMeta *ffp_get_meta_l(FFPlayer *ffp)\n{\n    if (!ffp)\n        return NULL;\n\n    return ffp->meta;\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ff_ffplay.h",
    "content": "/*\n * ff_ffplay.h\n *\n * Copyright (c) 2003 Bilibili\n * Copyright (c) 2003 Fabrice Bellard\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef FFPLAY__FF_FFPLAY_H\n#define FFPLAY__FF_FFPLAY_H\n\n#include \"ff_ffplay_def.h\"\n#include \"ff_fferror.h\"\n#include \"ff_ffmsg.h\"\n\nvoid      ffp_global_init();\nvoid      ffp_global_uninit();\nvoid      ffp_global_set_log_report(int use_report);\nvoid      ffp_global_set_log_level(int log_level);\nvoid      ffp_global_set_inject_callback(ijk_inject_callback cb);\nvoid      ffp_io_stat_register(void (*cb)(const char *url, int type, int bytes));\nvoid      ffp_io_stat_complete_register(void (*cb)(const char *url,\n                                                   int64_t read_bytes, int64_t total_size,\n                                                   int64_t elpased_time, int64_t total_duration));\n\nFFPlayer *ffp_create();\nvoid      ffp_destroy(FFPlayer *ffp);\nvoid      ffp_destroy_p(FFPlayer **pffp);\nvoid      ffp_reset(FFPlayer *ffp);\n\n/* set options before ffp_prepare_async_l() */\n\nvoid     ffp_set_frame_at_time(FFPlayer *ffp, const char *path, int64_t start_time, int64_t end_time, int num, int definition);\nvoid     *ffp_set_inject_opaque(FFPlayer *ffp, void *opaque);\nvoid     *ffp_set_ijkio_inject_opaque(FFPlayer *ffp, void *opaque);\nvoid      ffp_set_option(FFPlayer *ffp, int opt_category, const char *name, const char *value);\nvoid      ffp_set_option_int(FFPlayer *ffp, int opt_category, const char *name, int64_t value);\nvoid      ffp_set_option_intptr(FFPlayer *ffp, int opt_category, const char *name, uintptr_t value);\n\nint       ffp_get_video_codec_info(FFPlayer *ffp, char **codec_info);\nint       ffp_get_audio_codec_info(FFPlayer *ffp, char **codec_info);\n\n/* playback controll */\nint       ffp_prepare_async_l(FFPlayer *ffp, const char *file_name);\nint       ffp_start_from_l(FFPlayer *ffp, long msec);\nint       ffp_start_l(FFPlayer *ffp);\nint       ffp_pause_l(FFPlayer *ffp);\nint       ffp_is_paused_l(FFPlayer *ffp);\nint       ffp_stop_l(FFPlayer *ffp);\nint       ffp_wait_stop_l(FFPlayer *ffp);\n\n/* all in milliseconds */\nint       ffp_seek_to_l(FFPlayer *ffp, long msec);\nlong      ffp_get_current_position_l(FFPlayer *ffp);\nlong      ffp_get_duration_l(FFPlayer *ffp);\nlong      ffp_get_playable_duration_l(FFPlayer *ffp);\nvoid      ffp_set_loop(FFPlayer *ffp, int loop);\nint       ffp_get_loop(FFPlayer *ffp);\n\n/* for internal usage */\nint       ffp_packet_queue_init(PacketQueue *q);\nvoid      ffp_packet_queue_destroy(PacketQueue *q);\nvoid      ffp_packet_queue_abort(PacketQueue *q);\nvoid      ffp_packet_queue_start(PacketQueue *q);\nvoid      ffp_packet_queue_flush(PacketQueue *q);\nint       ffp_packet_queue_get(PacketQueue *q, AVPacket *pkt, int block, int *serial);\nint       ffp_packet_queue_get_or_buffering(FFPlayer *ffp, PacketQueue *q, AVPacket *pkt, int *serial, int *finished);\nint       ffp_packet_queue_put(PacketQueue *q, AVPacket *pkt);\nbool      ffp_is_flush_packet(AVPacket *pkt);\n\nFrame    *ffp_frame_queue_peek_writable(FrameQueue *f);\nvoid      ffp_frame_queue_push(FrameQueue *f);\n\nint       ffp_queue_picture(FFPlayer *ffp, AVFrame *src_frame, double pts, double duration, int64_t pos, int serial);\n\nint       ffp_get_master_sync_type(VideoState *is);\ndouble    ffp_get_master_clock(VideoState *is);\n\nvoid      ffp_toggle_buffering_l(FFPlayer *ffp, int start_buffering);\nvoid      ffp_toggle_buffering(FFPlayer *ffp, int start_buffering);\nvoid      ffp_check_buffering_l(FFPlayer *ffp);\nvoid      ffp_track_statistic_l(FFPlayer *ffp, AVStream *st, PacketQueue *q, FFTrackCacheStatistic *cache);\nvoid      ffp_audio_statistic_l(FFPlayer *ffp);\nvoid      ffp_video_statistic_l(FFPlayer *ffp);\nvoid      ffp_statistic_l(FFPlayer *ffp);\n\nint       ffp_video_thread(FFPlayer *ffp);\n\nvoid      ffp_set_video_codec_info(FFPlayer *ffp, const char *module, const char *codec);\nvoid      ffp_set_audio_codec_info(FFPlayer *ffp, const char *module, const char *codec);\nvoid      ffp_set_subtitle_codec_info(FFPlayer *ffp, const char *module, const char *codec);\n\nvoid      ffp_set_playback_rate(FFPlayer *ffp, float rate);\nvoid      ffp_set_playback_volume(FFPlayer *ffp, float volume);\nint       ffp_get_video_rotate_degrees(FFPlayer *ffp);\nint       ffp_set_stream_selected(FFPlayer *ffp, int stream, int selected);\n\nfloat     ffp_get_property_float(FFPlayer *ffp, int id, float default_value);\nvoid      ffp_set_property_float(FFPlayer *ffp, int id, float value);\nint64_t   ffp_get_property_int64(FFPlayer *ffp, int id, int64_t default_value);\nvoid      ffp_set_property_int64(FFPlayer *ffp, int id, int64_t value);\n\n// must be freed with free();\nstruct IjkMediaMeta *ffp_get_meta_l(FFPlayer *ffp);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ff_ffplay_debug.h",
    "content": "/*\n * ff_ffplaye_debug.h\n *\n * Copyright (c) 2015 Bilibili\n * Copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef FFPLAY__FF_FFPLAY_DEBUG_H\n#define FFPLAY__FF_FFPLAY_DEBUG_H\n\n#define FFP_XPS_PERIOD (3)\n\n#define FFP_SHOW_VPS_DPS            (0)\n#define FFP_SHOW_VFPS_FFPLAY        (FFP_SHOW_VPS_DPS)\n#define FFP_SHOW_VDPS_AVCODEC       (FFP_SHOW_VPS_DPS)\n#define FFP_SHOW_VDPS_VIDEOTOOLBOX  (FFP_SHOW_VPS_DPS)\n#define FFP_SHOW_VDPS_MEDIACODEC    (FFP_SHOW_VPS_DPS)\n\n// #define FFP_SHOW_AUDIO_DELAY\n// #define FFP_SHOW_DEMUX_CACHE\n// #define FFP_SHOW_BUF_POS\n// #define FFP_SHOW_PKT_RECYCLE\n\n// #define FFP_NOTIFY_BUF_TIME\n// #define FFP_NOTIFY_BUF_BYTES\n\n// #define FFP_SHOW_VTB_IN_DECODING\n// #define FFP_VTB_DISABLE_OUTPUT\n\n// #define FFP_SHOW_AMC_DROPS\n// #define FFP_AMC_DISABLE_OUTPUT\n\n// #define FFP_AVFILTER_PLAYBACK_RATE\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ff_ffplay_def.h",
    "content": "/*\n * Copyright (c) 2003 Bilibili\n * Copyright (c) 2003 Fabrice Bellard\n * Copyright (c) 2013-2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef FFPLAY__FF_FFPLAY_DEF_H\n#define FFPLAY__FF_FFPLAY_DEF_H\n\n/**\n * @file\n * simple media player based on the FFmpeg libraries\n */\n\n#include \"config.h\"\n#include <inttypes.h>\n#include <math.h>\n#include <limits.h>\n#include <signal.h>\n#include <stdint.h>\n\n#include \"libavutil/avstring.h\"\n#include \"libavutil/eval.h\"\n#include \"libavutil/mathematics.h\"\n#include \"libavutil/pixdesc.h\"\n#include \"libavutil/imgutils.h\"\n#include \"libavutil/dict.h\"\n#include \"libavutil/parseutils.h\"\n#include \"libavutil/samplefmt.h\"\n#include \"libavutil/avassert.h\"\n#include \"libavutil/time.h\"\n#include \"libavformat/avformat.h\"\n// FFP_MERGE: #include \"libavdevice/avdevice.h\"\n#include \"libswscale/swscale.h\"\n#include \"libavutil/opt.h\"\n#include \"libavcodec/avfft.h\"\n#include \"libswresample/swresample.h\"\n\n#if CONFIG_AVFILTER\n# include \"libavfilter/avfilter.h\"\n# include \"libavfilter/buffersink.h\"\n# include \"libavfilter/buffersrc.h\"\n#endif\n\n#include <stdbool.h>\n#include \"ijkavformat/ijkiomanager.h\"\n#include \"ijkavformat/ijkioapplication.h\"\n#include \"ff_ffinc.h\"\n#include \"ff_ffmsg_queue.h\"\n#include \"ff_ffpipenode.h\"\n#include \"ijkmeta.h\"\n\n#define DEFAULT_HIGH_WATER_MARK_IN_BYTES        (256 * 1024)\n\n/*\n * START: buffering after prepared/seeked\n * NEXT:  buffering for the second time after START\n * MAX:   ...\n */\n#define DEFAULT_FIRST_HIGH_WATER_MARK_IN_MS     (100)\n#define DEFAULT_NEXT_HIGH_WATER_MARK_IN_MS      (1 * 1000)\n#define DEFAULT_LAST_HIGH_WATER_MARK_IN_MS      (5 * 1000)\n\n#define BUFFERING_CHECK_PER_BYTES               (512)\n#define BUFFERING_CHECK_PER_MILLISECONDS        (500)\n#define FAST_BUFFERING_CHECK_PER_MILLISECONDS   (50)\n#define MAX_RETRY_CONVERT_IMAGE                 (3)\n\n#define MAX_QUEUE_SIZE (15 * 1024 * 1024)\n#define MAX_ACCURATE_SEEK_TIMEOUT (5000)\n#ifdef FFP_MERGE\n#define MIN_FRAMES 25\n#endif\n#define DEFAULT_MIN_FRAMES  50000\n#define MIN_MIN_FRAMES      2\n#define MAX_MIN_FRAMES      50000\n#define MIN_FRAMES (ffp->dcc.min_frames)\n#define EXTERNAL_CLOCK_MIN_FRAMES 2\n#define EXTERNAL_CLOCK_MAX_FRAMES 10\n\n/* Minimum SDL audio buffer size, in samples. */\n#define SDL_AUDIO_MIN_BUFFER_SIZE 512\n/* Calculate actual buffer size keeping in mind not cause too frequent audio callbacks */\n#define SDL_AUDIO_MAX_CALLBACKS_PER_SEC 30\n\n/* Step size for volume control */\n#define SDL_VOLUME_STEP (SDL_MIX_MAXVOLUME / 50)\n\n/* no AV sync correction is done if below the minimum AV sync threshold */\n#define AV_SYNC_THRESHOLD_MIN 0.04\n/* AV sync correction is done if above the maximum AV sync threshold */\n#define AV_SYNC_THRESHOLD_MAX 0.1\n/* If a frame duration is longer than this, it will not be duplicated to compensate AV sync */\n#define AV_SYNC_FRAMEDUP_THRESHOLD 0.15\n/* no AV correction is done if too big error */\n#define AV_NOSYNC_THRESHOLD 100.0\n\n/* maximum audio speed change to get correct sync */\n#define SAMPLE_CORRECTION_PERCENT_MAX 10\n\n/* external clock speed adjustment constants for realtime sources based on buffer fullness */\n#define EXTERNAL_CLOCK_SPEED_MIN  0.900\n#define EXTERNAL_CLOCK_SPEED_MAX  1.010\n#define EXTERNAL_CLOCK_SPEED_STEP 0.001\n\n/* we use about AUDIO_DIFF_AVG_NB A-V differences to make the average */\n#define AUDIO_DIFF_AVG_NB   20\n\n/* polls for possible required screen refresh at least this often, should be less than 1/fps */\n#define REFRESH_RATE 0.01\n\n/* NOTE: the size must be big enough to compensate the hardware audio buffersize size */\n/* TODO: We assume that a decoded and resampled frame fits into this buffer */\n#define SAMPLE_ARRAY_SIZE (8 * 65536)\n\n#define MIN_PKT_DURATION 15\n\n#ifdef FFP_MERGE\n#define CURSOR_HIDE_DELAY 1000000\n\n#define USE_ONEPASS_SUBTITLE_RENDER 1\n\nstatic unsigned sws_flags = SWS_BICUBIC;\n#endif\n\n#define HD_IMAGE 2  // 640*360\n#define SD_IMAGE 1  // 320*180\n#define LD_IMAGE 0  // 160*90\n#define MAX_DEVIATION 1200000   // 1200ms\n\ntypedef struct GetImgInfo {\n    char *img_path;\n    int64_t start_time;\n    int64_t end_time;\n    int64_t frame_interval;\n    int num;\n    int count;\n    int width;\n    int height;\n    AVCodecContext *frame_img_codec_ctx;\n    struct SwsContext *frame_img_convert_ctx;\n} GetImgInfo;\n\ntypedef struct MyAVPacketList {\n    AVPacket pkt;\n    struct MyAVPacketList *next;\n    int serial;\n} MyAVPacketList;\n\ntypedef struct PacketQueue {\n    MyAVPacketList *first_pkt, *last_pkt;\n    int nb_packets;\n    int size;\n    int64_t duration;\n    int abort_request;\n    int serial;\n    SDL_mutex *mutex;\n    SDL_cond *cond;\n    MyAVPacketList *recycle_pkt;\n    int recycle_count;\n    int alloc_count;\n\n    int is_buffer_indicator;\n} PacketQueue;\n\n// #define VIDEO_PICTURE_QUEUE_SIZE 3\n#define VIDEO_PICTURE_QUEUE_SIZE_MIN        (3)\n#define VIDEO_PICTURE_QUEUE_SIZE_MAX        (16)\n#define VIDEO_PICTURE_QUEUE_SIZE_DEFAULT    (VIDEO_PICTURE_QUEUE_SIZE_MIN)\n#define SUBPICTURE_QUEUE_SIZE 16\n#define SAMPLE_QUEUE_SIZE 9\n#define FRAME_QUEUE_SIZE FFMAX(SAMPLE_QUEUE_SIZE, FFMAX(VIDEO_PICTURE_QUEUE_SIZE_MAX, SUBPICTURE_QUEUE_SIZE))\n\n#define VIDEO_MAX_FPS_DEFAULT 30\n\ntypedef struct AudioParams {\n    int freq;\n    int channels;\n    int64_t channel_layout;\n    enum AVSampleFormat fmt;\n    int frame_size;\n    int bytes_per_sec;\n} AudioParams;\n\ntypedef struct Clock {\n    double pts;           /* clock base */\n    double pts_drift;     /* clock base minus time at which we updated the clock */\n    double last_updated;\n    double speed;\n    int serial;           /* clock is based on a packet with this serial */\n    int paused;\n    int *queue_serial;    /* pointer to the current packet queue serial, used for obsolete clock detection */\n} Clock;\n\n/* Common struct for handling all types of decoded data and allocated render buffers. */\ntypedef struct Frame {\n    AVFrame *frame;\n    AVSubtitle sub;\n    int serial;\n    double pts;           /* presentation timestamp for the frame */\n    double duration;      /* estimated duration of the frame */\n    int64_t pos;          /* byte position of the frame in the input file */\n#ifdef FFP_MERGE\n    SDL_Texture *bmp;\n#else\n    SDL_VoutOverlay *bmp;\n#endif\n    int allocated;\n    int width;\n    int height;\n    int format;\n    AVRational sar;\n    int uploaded;\n} Frame;\n\ntypedef struct FrameQueue {\n    Frame queue[FRAME_QUEUE_SIZE];\n    int rindex;\n    int windex;\n    int size;\n    int max_size;\n    int keep_last;\n    int rindex_shown;\n    SDL_mutex *mutex;\n    SDL_cond *cond;\n    PacketQueue *pktq;\n} FrameQueue;\n\nenum {\n    AV_SYNC_AUDIO_MASTER, /* default choice */\n    AV_SYNC_VIDEO_MASTER,\n    AV_SYNC_EXTERNAL_CLOCK, /* synchronize to an external clock */\n};\n\ntypedef struct Decoder {\n    AVPacket pkt;\n    AVPacket pkt_temp;\n    PacketQueue *queue;\n    AVCodecContext *avctx;\n    int pkt_serial;\n    int finished;\n    int packet_pending;\n    int bfsc_ret;\n    uint8_t *bfsc_data;\n\n    SDL_cond *empty_queue_cond;\n    int64_t start_pts;\n    AVRational start_pts_tb;\n    int64_t next_pts;\n    AVRational next_pts_tb;\n    SDL_Thread *decoder_tid;\n    SDL_Thread _decoder_tid;\n\n    SDL_Profiler decode_profiler;\n    Uint64 first_frame_decoded_time;\n    int    first_frame_decoded;\n} Decoder;\n\ntypedef struct VideoState {\n    SDL_Thread *read_tid;\n    SDL_Thread _read_tid;\n    AVInputFormat *iformat;\n    int abort_request;\n    int force_refresh;\n    int paused;\n    int last_paused;\n    int queue_attachments_req;\n    int seek_req;\n    int seek_flags;\n    int64_t seek_pos;\n    int64_t seek_rel;\n#ifdef FFP_MERGE\n    int read_pause_return;\n#endif\n    AVFormatContext *ic;\n    int realtime;\n\n    Clock audclk;\n    Clock vidclk;\n    Clock extclk;\n\n    FrameQueue pictq;\n    FrameQueue subpq;\n    FrameQueue sampq;\n\n    Decoder auddec;\n    Decoder viddec;\n    Decoder subdec;\n\n    int audio_stream;\n\n    int av_sync_type;\n    void *handle;\n    double audio_clock;\n    int audio_clock_serial;\n    double audio_diff_cum; /* used for AV difference average computation */\n    double audio_diff_avg_coef;\n    double audio_diff_threshold;\n    int audio_diff_avg_count;\n    AVStream *audio_st;\n    PacketQueue audioq;\n    int audio_hw_buf_size;\n    uint8_t *audio_buf;\n    uint8_t *audio_buf1;\n    short *audio_new_buf;  /* for soundtouch buf */\n    unsigned int audio_buf_size; /* in bytes */\n    unsigned int audio_buf1_size;\n    unsigned int audio_new_buf_size;\n    int audio_buf_index; /* in bytes */\n    int audio_write_buf_size;\n    int audio_volume;\n    int muted;\n    struct AudioParams audio_src;\n#if CONFIG_AVFILTER\n    struct AudioParams audio_filter_src;\n#endif\n    struct AudioParams audio_tgt;\n    struct SwrContext *swr_ctx;\n    int frame_drops_early;\n    int frame_drops_late;\n    int continuous_frame_drops_early;\n\n    enum ShowMode {\n        SHOW_MODE_NONE = -1, SHOW_MODE_VIDEO = 0, SHOW_MODE_WAVES, SHOW_MODE_RDFT, SHOW_MODE_NB\n    } show_mode;\n    int16_t sample_array[SAMPLE_ARRAY_SIZE];\n    int sample_array_index;\n    int last_i_start;\n#ifdef FFP_MERGE\n    RDFTContext *rdft;\n    int rdft_bits;\n    FFTSample *rdft_data;\n    int xpos;\n#endif\n    double last_vis_time;\n#ifdef FFP_MERGE\n    SDL_Texture *vis_texture;\n    SDL_Texture *sub_texture;\n#endif\n\n    int subtitle_stream;\n    AVStream *subtitle_st;\n    PacketQueue subtitleq;\n\n    double frame_timer;\n    double frame_last_returned_time;\n    double frame_last_filter_delay;\n    int video_stream;\n    AVStream *video_st;\n    PacketQueue videoq;\n    double max_frame_duration;      // maximum duration of a frame - above this, we consider the jump a timestamp discontinuity\n    struct SwsContext *img_convert_ctx;\n#ifdef FFP_SUB\n    struct SwsContext *sub_convert_ctx;\n#endif\n    int eof;\n\n    char *filename;\n    int width, height, xleft, ytop;\n    int step;\n\n#if CONFIG_AVFILTER\n    int vfilter_idx;\n    AVFilterContext *in_video_filter;   // the first filter in the video chain\n    AVFilterContext *out_video_filter;  // the last filter in the video chain\n    AVFilterContext *in_audio_filter;   // the first filter in the audio chain\n    AVFilterContext *out_audio_filter;  // the last filter in the audio chain\n    AVFilterGraph *agraph;              // audio filter graph\n#endif\n\n    int last_video_stream, last_audio_stream, last_subtitle_stream;\n\n    SDL_cond *continue_read_thread;\n\n    /* extra fields */\n    SDL_mutex  *play_mutex; // only guard state, do not block any long operation\n    SDL_Thread *video_refresh_tid;\n    SDL_Thread _video_refresh_tid;\n\n    int buffering_on;\n    int pause_req;\n\n    int dropping_frame;\n    int is_video_high_fps; // above 30fps\n    int is_video_high_res; // above 1080p\n\n    PacketQueue *buffer_indicator_queue;\n\n    volatile int latest_video_seek_load_serial;\n    volatile int latest_audio_seek_load_serial;\n    volatile int64_t latest_seek_load_start_at;\n\n    int drop_aframe_count;\n    int drop_vframe_count;\n    int64_t accurate_seek_start_time;\n    volatile int64_t accurate_seek_vframe_pts;\n    volatile int64_t accurate_seek_aframe_pts;\n    int audio_accurate_seek_req;\n    int video_accurate_seek_req;\n    SDL_mutex *accurate_seek_mutex;\n    SDL_cond  *video_accurate_seek_cond;\n    SDL_cond  *audio_accurate_seek_cond;\n    volatile int initialized_decoder;\n    int seek_buffering;\n} VideoState;\n\n/* options specified by the user */\n#ifdef FFP_MERGE\nstatic AVInputFormat *file_iformat;\nstatic const char *input_filename;\nstatic const char *window_title;\nstatic int default_width  = 640;\nstatic int default_height = 480;\nstatic int screen_width  = 0;\nstatic int screen_height = 0;\nstatic int audio_disable;\nstatic int video_disable;\nstatic int subtitle_disable;\nstatic const char* wanted_stream_spec[AVMEDIA_TYPE_NB] = {0};\nstatic int seek_by_bytes = -1;\nstatic int display_disable;\nstatic int show_status = 1;\nstatic int av_sync_type = AV_SYNC_AUDIO_MASTER;\nstatic int64_t start_time = AV_NOPTS_VALUE;\nstatic int64_t duration = AV_NOPTS_VALUE;\nstatic int fast = 0;\nstatic int genpts = 0;\nstatic int lowres = 0;\nstatic int decoder_reorder_pts = -1;\nstatic int autoexit;\nstatic int exit_on_keydown;\nstatic int exit_on_mousedown;\nstatic int loop = 1;\nstatic int framedrop = -1;\nstatic int infinite_buffer = -1;\nstatic enum ShowMode show_mode = SHOW_MODE_NONE;\nstatic const char *audio_codec_name;\nstatic const char *subtitle_codec_name;\nstatic const char *video_codec_name;\ndouble rdftspeed = 0.02;\nstatic int64_t cursor_last_shown;\nstatic int cursor_hidden = 0;\n#if CONFIG_AVFILTER\nstatic const char **vfilters_list = NULL;\nstatic int nb_vfilters = 0;\nstatic char *afilters = NULL;\n#endif\nstatic int autorotate = 1;\nstatic int find_stream_info = 1;\n\n/* current context */\nstatic int is_full_screen;\nstatic int64_t audio_callback_time;\n\nstatic AVPacket flush_pkt;\nstatic AVPacket eof_pkt;\n\n#define FF_ALLOC_EVENT   (SDL_USEREVENT)\n#define FF_QUIT_EVENT    (SDL_USEREVENT + 2)\n\nstatic SDL_Window *window;\nstatic SDL_Renderer *renderer;\n#endif\n\n/*****************************************************************************\n * end at line 330 in ffplay.c\n * near packet_queue_put\n ****************************************************************************/\ntypedef struct FFTrackCacheStatistic\n{\n    int64_t duration;\n    int64_t bytes;\n    int64_t packets;\n} FFTrackCacheStatistic;\n\ntypedef struct FFStatistic\n{\n    int64_t vdec_type;\n\n    float vfps;\n    float vdps;\n    float avdelay;\n    float avdiff;\n    int64_t bit_rate;\n\n    FFTrackCacheStatistic video_cache;\n    FFTrackCacheStatistic audio_cache;\n\n    int64_t buf_backwards;\n    int64_t buf_forwards;\n    int64_t buf_capacity;\n    SDL_SpeedSampler2 tcp_read_sampler;\n    int64_t latest_seek_load_duration;\n    int64_t byte_count;\n    int64_t cache_physical_pos;\n    int64_t cache_file_forwards;\n    int64_t cache_file_pos;\n    int64_t cache_count_bytes;\n    int64_t logical_file_size;\n    int drop_frame_count;\n    int decode_frame_count;\n    float drop_frame_rate;\n} FFStatistic;\n\n#define FFP_TCP_READ_SAMPLE_RANGE 2000\ninline static void ffp_reset_statistic(FFStatistic *dcc)\n{\n    memset(dcc, 0, sizeof(FFStatistic));\n    SDL_SpeedSampler2Reset(&dcc->tcp_read_sampler, FFP_TCP_READ_SAMPLE_RANGE);\n}\n\ntypedef struct FFDemuxCacheControl\n{\n    int min_frames;\n    int max_buffer_size;\n    int high_water_mark_in_bytes;\n\n    int first_high_water_mark_in_ms;\n    int next_high_water_mark_in_ms;\n    int last_high_water_mark_in_ms;\n    int current_high_water_mark_in_ms;\n} FFDemuxCacheControl;\n\ninline static void ffp_reset_demux_cache_control(FFDemuxCacheControl *dcc)\n{\n    dcc->min_frames                = DEFAULT_MIN_FRAMES;\n    dcc->max_buffer_size           = MAX_QUEUE_SIZE;\n    dcc->high_water_mark_in_bytes  = DEFAULT_HIGH_WATER_MARK_IN_BYTES;\n\n    dcc->first_high_water_mark_in_ms    = DEFAULT_FIRST_HIGH_WATER_MARK_IN_MS;\n    dcc->next_high_water_mark_in_ms     = DEFAULT_NEXT_HIGH_WATER_MARK_IN_MS;\n    dcc->last_high_water_mark_in_ms     = DEFAULT_LAST_HIGH_WATER_MARK_IN_MS;\n    dcc->current_high_water_mark_in_ms  = DEFAULT_FIRST_HIGH_WATER_MARK_IN_MS;\n}\n\n/* ffplayer */\nstruct IjkMediaMeta;\nstruct IJKFF_Pipeline;\ntypedef struct FFPlayer {\n    const AVClass *av_class;\n\n    /* ffplay context */\n    VideoState *is;\n\n    /* format/codec options */\n    AVDictionary *format_opts;\n    AVDictionary *codec_opts;\n    AVDictionary *sws_dict;\n    AVDictionary *player_opts;\n    AVDictionary *swr_opts;\n    AVDictionary *swr_preset_opts;\n\n    /* ffplay options specified by the user */\n#ifdef FFP_MERGE\n    AVInputFormat *file_iformat;\n#endif\n    char *input_filename;\n#ifdef FFP_MERGE\n    const char *window_title;\n    int fs_screen_width;\n    int fs_screen_height;\n    int default_width;\n    int default_height;\n    int screen_width;\n    int screen_height;\n#endif\n    int audio_disable;\n    int video_disable;\n    int subtitle_disable;\n    const char* wanted_stream_spec[AVMEDIA_TYPE_NB];\n    int seek_by_bytes;\n    int display_disable;\n    int show_status;\n    int av_sync_type;\n    int64_t start_time;\n    int64_t duration;\n    int fast;\n    int genpts;\n    int lowres;\n    int decoder_reorder_pts;\n    int autoexit;\n#ifdef FFP_MERGE\n    int exit_on_keydown;\n    int exit_on_mousedown;\n#endif\n    int loop;\n    int framedrop;\n    int64_t seek_at_start;\n    int subtitle;\n    int infinite_buffer;\n    enum ShowMode show_mode;\n    char *audio_codec_name;\n    char *subtitle_codec_name;\n    char *video_codec_name;\n    double rdftspeed;\n#ifdef FFP_MERGE\n    int64_t cursor_last_shown;\n    int cursor_hidden;\n#endif\n#if CONFIG_AVFILTER\n    const char **vfilters_list;\n    int nb_vfilters;\n    char *afilters;\n    char *vfilter0;\n#endif\n    int autorotate;\n    int find_stream_info;\n    unsigned sws_flags;\n\n    /* current context */\n#ifdef FFP_MERGE\n    int is_full_screen;\n#endif\n    int64_t audio_callback_time;\n#ifdef FFP_MERGE\n    SDL_Surface *screen;\n#endif\n\n    /* extra fields */\n    SDL_Aout *aout;\n    SDL_Vout *vout;\n    struct IJKFF_Pipeline *pipeline;\n    struct IJKFF_Pipenode *node_vdec;\n    int sar_num;\n    int sar_den;\n\n    char *video_codec_info;\n    char *audio_codec_info;\n    char *subtitle_codec_info;\n    Uint32 overlay_format;\n\n    int last_error;\n    int prepared;\n    int auto_resume;\n    int error;\n    int error_count;\n    int start_on_prepared;\n    int first_video_frame_rendered;\n    int first_audio_frame_rendered;\n    int sync_av_start;\n\n    MessageQueue msg_queue;\n\n    int64_t playable_duration_ms;\n\n    int packet_buffering;\n    int pictq_size;\n    int max_fps;\n    int startup_volume;\n\n    int videotoolbox;\n    int vtb_max_frame_width;\n    int vtb_async;\n    int vtb_wait_async;\n    int vtb_handle_resolution_change;\n\n    int mediacodec_all_videos;\n    int mediacodec_avc;\n    int mediacodec_hevc;\n    int mediacodec_mpeg2;\n    int mediacodec_mpeg4;\n    int mediacodec_handle_resolution_change;\n    int mediacodec_auto_rotate;\n\n    int opensles;\n    int soundtouch_enable;\n\n    char *iformat_name;\n\n    int no_time_adjust;\n    double preset_5_1_center_mix_level;\n\n    struct IjkMediaMeta *meta;\n\n    SDL_SpeedSampler vfps_sampler;\n    SDL_SpeedSampler vdps_sampler;\n\n    /* filters */\n    SDL_mutex  *vf_mutex;\n    SDL_mutex  *af_mutex;\n    int         vf_changed;\n    int         af_changed;\n    float       pf_playback_rate;\n    int         pf_playback_rate_changed;\n    float       pf_playback_volume;\n    int         pf_playback_volume_changed;\n\n    void               *inject_opaque;\n    void               *ijkio_inject_opaque;\n    FFStatistic         stat;\n    FFDemuxCacheControl dcc;\n\n    AVApplicationContext *app_ctx;\n    IjkIOManagerContext *ijkio_manager_ctx;\n\n    int enable_accurate_seek;\n    int accurate_seek_timeout;\n    int mediacodec_sync;\n    int skip_calc_frame_rate;\n    int get_frame_mode;\n    GetImgInfo *get_img_info;\n    int async_init_decoder;\n    char *video_mime_type;\n    char *mediacodec_default_name;\n    int ijkmeta_delay_init;\n    int render_wait_start;\n} FFPlayer;\n\n#define fftime_to_milliseconds(ts) (av_rescale(ts, 1000, AV_TIME_BASE))\n#define milliseconds_to_fftime(ms) (av_rescale(ms, AV_TIME_BASE, 1000))\n\ninline static void ffp_reset_internal(FFPlayer *ffp)\n{\n    /* ffp->is closed in stream_close() */\n    av_opt_free(ffp);\n\n    /* format/codec options */\n    av_dict_free(&ffp->format_opts);\n    av_dict_free(&ffp->codec_opts);\n    av_dict_free(&ffp->sws_dict);\n    av_dict_free(&ffp->player_opts);\n    av_dict_free(&ffp->swr_opts);\n    av_dict_free(&ffp->swr_preset_opts);\n\n    /* ffplay options specified by the user */\n    av_freep(&ffp->input_filename);\n    ffp->audio_disable          = 0;\n    ffp->video_disable          = 0;\n    memset(ffp->wanted_stream_spec, 0, sizeof(ffp->wanted_stream_spec));\n    ffp->seek_by_bytes          = -1;\n    ffp->display_disable        = 0;\n    ffp->show_status            = 0;\n    ffp->av_sync_type           = AV_SYNC_AUDIO_MASTER;\n    ffp->start_time             = AV_NOPTS_VALUE;\n    ffp->duration               = AV_NOPTS_VALUE;\n    ffp->fast                   = 1;\n    ffp->genpts                 = 0;\n    ffp->lowres                 = 0;\n    ffp->decoder_reorder_pts    = -1;\n    ffp->autoexit               = 0;\n    ffp->loop                   = 1;\n    ffp->framedrop              = 0; // option\n    ffp->seek_at_start          = 0;\n    ffp->infinite_buffer        = -1;\n    ffp->show_mode              = SHOW_MODE_NONE;\n    av_freep(&ffp->audio_codec_name);\n    av_freep(&ffp->video_codec_name);\n    ffp->rdftspeed              = 0.02;\n#if CONFIG_AVFILTER\n    av_freep(&ffp->vfilters_list);\n    ffp->nb_vfilters            = 0;\n    ffp->afilters               = NULL;\n    ffp->vfilter0               = NULL;\n#endif\n    ffp->autorotate             = 1;\n    ffp->find_stream_info       = 1;\n\n    ffp->sws_flags              = SWS_FAST_BILINEAR;\n\n    /* current context */\n    ffp->audio_callback_time    = 0;\n\n    /* extra fields */\n    ffp->aout                   = NULL; /* reset outside */\n    ffp->vout                   = NULL; /* reset outside */\n    ffp->pipeline               = NULL;\n    ffp->node_vdec              = NULL;\n    ffp->sar_num                = 0;\n    ffp->sar_den                = 0;\n\n    av_freep(&ffp->video_codec_info);\n    av_freep(&ffp->audio_codec_info);\n    av_freep(&ffp->subtitle_codec_info);\n    ffp->overlay_format         = SDL_FCC_RV32;\n\n    ffp->last_error             = 0;\n    ffp->prepared               = 0;\n    ffp->auto_resume            = 0;\n    ffp->error                  = 0;\n    ffp->error_count            = 0;\n    ffp->start_on_prepared      = 1;\n    ffp->first_video_frame_rendered = 0;\n    ffp->sync_av_start          = 1;\n    ffp->enable_accurate_seek   = 0;\n    ffp->accurate_seek_timeout  = MAX_ACCURATE_SEEK_TIMEOUT;\n\n    ffp->playable_duration_ms           = 0;\n\n    ffp->packet_buffering               = 1;\n    ffp->pictq_size                     = VIDEO_PICTURE_QUEUE_SIZE_DEFAULT; // option\n    ffp->max_fps                        = 31; // option\n\n    ffp->videotoolbox                   = 0; // option\n    ffp->vtb_max_frame_width            = 0; // option\n    ffp->vtb_async                      = 0; // option\n    ffp->vtb_handle_resolution_change   = 0; // option\n    ffp->vtb_wait_async                 = 0; // option\n\n    ffp->mediacodec_all_videos          = 0; // option\n    ffp->mediacodec_avc                 = 0; // option\n    ffp->mediacodec_hevc                = 0; // option\n    ffp->mediacodec_mpeg2               = 0; // option\n    ffp->mediacodec_handle_resolution_change = 0; // option\n    ffp->mediacodec_auto_rotate         = 0; // option\n\n    ffp->opensles                       = 0; // option\n    ffp->soundtouch_enable              = 0; // option\n\n    ffp->iformat_name                   = NULL; // option\n\n    ffp->no_time_adjust                 = 0; // option\n    ffp->async_init_decoder             = 0; // option\n    ffp->video_mime_type                = NULL; // option\n    ffp->mediacodec_default_name        = NULL; // option\n    ffp->ijkmeta_delay_init             = 0; // option\n    ffp->render_wait_start              = 0;\n\n    ijkmeta_reset(ffp->meta);\n\n    SDL_SpeedSamplerReset(&ffp->vfps_sampler);\n    SDL_SpeedSamplerReset(&ffp->vdps_sampler);\n\n    /* filters */\n    ffp->vf_changed                     = 0;\n    ffp->af_changed                     = 0;\n    ffp->pf_playback_rate               = 1.0f;\n    ffp->pf_playback_rate_changed       = 0;\n    ffp->pf_playback_volume             = 1.0f;\n    ffp->pf_playback_volume_changed     = 0;\n\n    av_application_closep(&ffp->app_ctx);\n    ijkio_manager_destroyp(&ffp->ijkio_manager_ctx);\n\n    msg_queue_flush(&ffp->msg_queue);\n\n    ffp->inject_opaque = NULL;\n    ffp->ijkio_inject_opaque = NULL;\n    ffp_reset_statistic(&ffp->stat);\n    ffp_reset_demux_cache_control(&ffp->dcc);\n}\n\ninline static void ffp_notify_msg1(FFPlayer *ffp, int what) {\n    msg_queue_put_simple3(&ffp->msg_queue, what, 0, 0);\n}\n\ninline static void ffp_notify_msg2(FFPlayer *ffp, int what, int arg1) {\n    msg_queue_put_simple3(&ffp->msg_queue, what, arg1, 0);\n}\n\ninline static void ffp_notify_msg3(FFPlayer *ffp, int what, int arg1, int arg2) {\n    msg_queue_put_simple3(&ffp->msg_queue, what, arg1, arg2);\n}\n\ninline static void ffp_notify_msg4(FFPlayer *ffp, int what, int arg1, int arg2, void *obj, int obj_len) {\n    msg_queue_put_simple4(&ffp->msg_queue, what, arg1, arg2, obj, obj_len);\n}\n\ninline static void ffp_remove_msg(FFPlayer *ffp, int what) {\n    msg_queue_remove(&ffp->msg_queue, what);\n}\n\ninline static const char *ffp_get_error_string(int error) {\n    switch (error) {\n        case AVERROR(ENOMEM):       return \"AVERROR(ENOMEM)\";       // 12\n        case AVERROR(EINVAL):       return \"AVERROR(EINVAL)\";       // 22\n        case AVERROR(EAGAIN):       return \"AVERROR(EAGAIN)\";       // 35\n        case AVERROR(ETIMEDOUT):    return \"AVERROR(ETIMEDOUT)\";    // 60\n        case AVERROR_EOF:           return \"AVERROR_EOF\";\n        case AVERROR_EXIT:          return \"AVERROR_EXIT\";\n    }\n    return \"unknown\";\n}\n\n#define FFTRACE ALOGW\n\n#define AVCODEC_MODULE_NAME    \"avcodec\"\n#define MEDIACODEC_MODULE_NAME \"MediaCodec\"\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ff_ffplay_options.h",
    "content": "/*\n * ff_ffplaye_options.h\n *\n * Copyright (c) 2015 Bilibili\n * Copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef FFPLAY__FF_FFPLAY_OPTIONS_H\n#define FFPLAY__FF_FFPLAY_OPTIONS_H\n\n#define OPTION_OFFSET(x) offsetof(FFPlayer, x)\n#define OPTION_INT(default__, min__, max__) \\\n    .type = AV_OPT_TYPE_INT, \\\n    { .i64 = default__ }, \\\n    .min = min__, \\\n    .max = max__, \\\n    .flags = AV_OPT_FLAG_DECODING_PARAM\n#define OPTION_INT64(default__, min__, max__) \\\n    .type = AV_OPT_TYPE_INT64, \\\n    { .i64 = default__ }, \\\n    .min = min__, \\\n    .max = max__, \\\n    .flags = AV_OPT_FLAG_DECODING_PARAM\n#define OPTION_DOUBLE(default__, min__, max__) \\\n    .type = AV_OPT_TYPE_DOUBLE, \\\n    { .dbl = default__ }, \\\n    .min = min__, \\\n    .max = max__, \\\n    .flags = AV_OPT_FLAG_DECODING_PARAM\n#define OPTION_CONST(default__) \\\n    .type = AV_OPT_TYPE_CONST, \\\n    { .i64 = default__ }, \\\n    .min = INT_MIN, \\\n    .max = INT_MAX, \\\n    .flags = AV_OPT_FLAG_DECODING_PARAM\n\n#define OPTION_STR(default__) \\\n    .type = AV_OPT_TYPE_STRING, \\\n    { .str = default__ }, \\\n    .min = 0, \\\n    .max = 0, \\\n    .flags = AV_OPT_FLAG_DECODING_PARAM\n\nstatic const AVOption ffp_context_options[] = {\n    // original options in ffplay.c\n    // FFP_MERGE: x, y, s, fs\n    { \"an\",                             \"disable audio\",\n        OPTION_OFFSET(audio_disable),   OPTION_INT(0, 0, 1) },\n    { \"vn\",                             \"disable video\",\n        OPTION_OFFSET(video_disable),   OPTION_INT(0, 0, 1) },\n    // FFP_MERGE: sn, ast, vst, sst\n    // TODO: ss\n    { \"nodisp\",                         \"disable graphical display\",\n        OPTION_OFFSET(display_disable), OPTION_INT(0, 0, 1) },\n    { \"volume\",                         \"set startup volume 0=min 100=max\",\n        OPTION_OFFSET(startup_volume),   OPTION_INT(100, 0, 100) },\n    // FFP_MERGE: f, pix_fmt, stats\n    { \"fast\",                           \"non spec compliant optimizations\",\n        OPTION_OFFSET(fast),            OPTION_INT(0, 0, 1) },\n    // FFP_MERGE: genpts, drp, lowres, sync, autoexit, exitonkeydown, exitonmousedown\n    { \"loop\",                           \"set number of times the playback shall be looped\",\n        OPTION_OFFSET(loop),            OPTION_INT(1, INT_MIN, INT_MAX) },\n    { \"infbuf\",                         \"don't limit the input buffer size (useful with realtime streams)\",\n        OPTION_OFFSET(infinite_buffer), OPTION_INT(0, 0, 1) },\n    { \"framedrop\",                      \"drop frames when cpu is too slow\",\n        OPTION_OFFSET(framedrop),       OPTION_INT(0, -1, 120) },\n    { \"seek-at-start\",                  \"set offset of player should be seeked\",\n        OPTION_OFFSET(seek_at_start),       OPTION_INT64(0, 0, INT_MAX) },\n    { \"subtitle\",                       \"decode subtitle stream\",\n        OPTION_OFFSET(subtitle),        OPTION_INT(0, 0, 1) },\n    // FFP_MERGE: window_title\n#if CONFIG_AVFILTER\n    { \"af\",                             \"audio filters\",\n        OPTION_OFFSET(afilters),        OPTION_STR(NULL) },\n    { \"vf0\",                            \"video filters 0\",\n        OPTION_OFFSET(vfilter0),        OPTION_STR(NULL) },\n#endif\n    { \"rdftspeed\",                      \"rdft speed, in msecs\",\n        OPTION_OFFSET(rdftspeed),       OPTION_INT(0, 0, INT_MAX) },\n    // FFP_MERGE: showmode, default, i, codec, acodec, scodec, vcodec\n    // TODO: autorotate\n\n    { \"find_stream_info\",               \"read and decode the streams to fill missing information with heuristics\" ,\n        OPTION_OFFSET(find_stream_info),    OPTION_INT(1, 0, 1) },\n\n    // extended options in ff_ffplay.c\n    { \"max-fps\",                        \"drop frames in video whose fps is greater than max-fps\",\n        OPTION_OFFSET(max_fps),         OPTION_INT(31, -1, 121) },\n\n    { \"overlay-format\",                 \"fourcc of overlay format\",\n        OPTION_OFFSET(overlay_format),  OPTION_INT(SDL_FCC_RV32, INT_MIN, INT_MAX),\n        .unit = \"overlay-format\" },\n    { \"fcc-_es2\",                       \"\", 0, OPTION_CONST(SDL_FCC__GLES2), .unit = \"overlay-format\" },\n    { \"fcc-i420\",                       \"\", 0, OPTION_CONST(SDL_FCC_I420), .unit = \"overlay-format\" },\n    { \"fcc-yv12\",                       \"\", 0, OPTION_CONST(SDL_FCC_YV12), .unit = \"overlay-format\" },\n    { \"fcc-rv16\",                       \"\", 0, OPTION_CONST(SDL_FCC_RV16), .unit = \"overlay-format\" },\n    { \"fcc-rv24\",                       \"\", 0, OPTION_CONST(SDL_FCC_RV24), .unit = \"overlay-format\" },\n    { \"fcc-rv32\",                       \"\", 0, OPTION_CONST(SDL_FCC_RV32), .unit = \"overlay-format\" },\n\n    { \"start-on-prepared\",                  \"automatically start playing on prepared\",\n        OPTION_OFFSET(start_on_prepared),   OPTION_INT(1, 0, 1) },\n\n    { \"video-pictq-size\",                   \"max picture queue frame count\",\n        OPTION_OFFSET(pictq_size),          OPTION_INT(VIDEO_PICTURE_QUEUE_SIZE_DEFAULT,\n                                                       VIDEO_PICTURE_QUEUE_SIZE_MIN,\n                                                       VIDEO_PICTURE_QUEUE_SIZE_MAX) },\n\n    { \"max-buffer-size\",                    \"max buffer size should be pre-read\",\n        OPTION_OFFSET(dcc.max_buffer_size), OPTION_INT(MAX_QUEUE_SIZE, 0, MAX_QUEUE_SIZE) },\n    { \"min-frames\",                         \"minimal frames to stop pre-reading\",\n        OPTION_OFFSET(dcc.min_frames),      OPTION_INT(DEFAULT_MIN_FRAMES, MIN_MIN_FRAMES, MAX_MIN_FRAMES) },\n    { \"first-high-water-mark-ms\",           \"first chance to wakeup read_thread\",\n        OPTION_OFFSET(dcc.first_high_water_mark_in_ms),\n        OPTION_INT(DEFAULT_FIRST_HIGH_WATER_MARK_IN_MS,\n                   DEFAULT_FIRST_HIGH_WATER_MARK_IN_MS,\n                   DEFAULT_LAST_HIGH_WATER_MARK_IN_MS) },\n    { \"next-high-water-mark-ms\",            \"second chance to wakeup read_thread\",\n        OPTION_OFFSET(dcc.next_high_water_mark_in_ms),\n        OPTION_INT(DEFAULT_NEXT_HIGH_WATER_MARK_IN_MS,\n                   DEFAULT_FIRST_HIGH_WATER_MARK_IN_MS,\n                   DEFAULT_LAST_HIGH_WATER_MARK_IN_MS) },\n    { \"last-high-water-mark-ms\",            \"last chance to wakeup read_thread\",\n        OPTION_OFFSET(dcc.last_high_water_mark_in_ms),\n        OPTION_INT(DEFAULT_LAST_HIGH_WATER_MARK_IN_MS,\n                   DEFAULT_FIRST_HIGH_WATER_MARK_IN_MS,\n                   DEFAULT_LAST_HIGH_WATER_MARK_IN_MS) },\n\n    { \"packet-buffering\",                   \"pause output until enough packets have been read after stalling\",\n        OPTION_OFFSET(packet_buffering),    OPTION_INT(1, 0, 1) },\n    { \"sync-av-start\",                      \"synchronise a/v start time\",\n        OPTION_OFFSET(sync_av_start),       OPTION_INT(1, 0, 1) },\n    { \"iformat\",                            \"force format\",\n        OPTION_OFFSET(iformat_name),        OPTION_STR(NULL) },\n    { \"no-time-adjust\",                     \"return player's real time from the media stream instead of the adjusted time\",\n        OPTION_OFFSET(no_time_adjust),      OPTION_INT(0, 0, 1) },\n    { \"preset-5-1-center-mix-level\",        \"preset center-mix-level for 5.1 channel\",\n        OPTION_OFFSET(preset_5_1_center_mix_level), OPTION_DOUBLE(M_SQRT1_2, -32, 32) },\n\n    { \"enable-accurate-seek\",                      \"enable accurate seek\",\n        OPTION_OFFSET(enable_accurate_seek),       OPTION_INT(0, 0, 1) },\n    { \"accurate-seek-timeout\",                      \"accurate seek timeout\",\n        OPTION_OFFSET(accurate_seek_timeout),       OPTION_INT(MAX_ACCURATE_SEEK_TIMEOUT, 0, MAX_ACCURATE_SEEK_TIMEOUT) },\n    { \"skip-calc-frame-rate\",                      \"don't calculate real frame rate\",\n        OPTION_OFFSET(skip_calc_frame_rate),       OPTION_INT(0, 0, 1) },\n    { \"get-frame-mode\",                      \"warning, this option only for get frame\",\n        OPTION_OFFSET(get_frame_mode),       OPTION_INT(0, 0, 1) },\n    { \"async-init-decoder\",                  \"async create decoder\",\n        OPTION_OFFSET(async_init_decoder),   OPTION_INT(0, 0, 1) },\n    { \"video-mime-type\",                    \"default video mime type\",\n        OPTION_OFFSET(video_mime_type),     OPTION_STR(NULL) },\n\n        // iOS only options\n    { \"videotoolbox\",                       \"VideoToolbox: enable\",\n        OPTION_OFFSET(videotoolbox),        OPTION_INT(0, 0, 1) },\n    { \"videotoolbox-max-frame-width\",       \"VideoToolbox: max width of output frame\",\n        OPTION_OFFSET(vtb_max_frame_width), OPTION_INT(0, 0, INT_MAX) },\n    { \"videotoolbox-async\",                 \"VideoToolbox: use kVTDecodeFrame_EnableAsynchronousDecompression()\",\n        OPTION_OFFSET(vtb_async),           OPTION_INT(0, 0, 1) },\n    { \"videotoolbox-wait-async\",            \"VideoToolbox: call VTDecompressionSessionWaitForAsynchronousFrames()\",\n        OPTION_OFFSET(vtb_wait_async),      OPTION_INT(1, 0, 1) },\n    { \"videotoolbox-handle-resolution-change\",          \"VideoToolbox: handle resolution change automatically\",\n        OPTION_OFFSET(vtb_handle_resolution_change),    OPTION_INT(0, 0, 1) },\n\n    // Android only options\n    { \"mediacodec\",                             \"MediaCodec: enable H264 (deprecated by 'mediacodec-avc')\",\n        OPTION_OFFSET(mediacodec_avc),          OPTION_INT(0, 0, 1) },\n    { \"mediacodec-auto-rotate\",                 \"MediaCodec: auto rotate frame depending on meta\",\n        OPTION_OFFSET(mediacodec_auto_rotate),  OPTION_INT(0, 0, 1) },\n    { \"mediacodec-all-videos\",                  \"MediaCodec: enable all videos\",\n        OPTION_OFFSET(mediacodec_all_videos),   OPTION_INT(0, 0, 1) },\n    { \"mediacodec-avc\",                         \"MediaCodec: enable H264\",\n        OPTION_OFFSET(mediacodec_avc),          OPTION_INT(0, 0, 1) },\n    { \"mediacodec-hevc\",                        \"MediaCodec: enable HEVC\",\n        OPTION_OFFSET(mediacodec_hevc),         OPTION_INT(0, 0, 1) },\n    { \"mediacodec-mpeg2\",                       \"MediaCodec: enable MPEG2VIDEO\",\n        OPTION_OFFSET(mediacodec_mpeg2),        OPTION_INT(0, 0, 1) },\n    { \"mediacodec-mpeg4\",                       \"MediaCodec: enable MPEG4\",\n        OPTION_OFFSET(mediacodec_mpeg4),        OPTION_INT(0, 0, 1) },\n    { \"mediacodec-handle-resolution-change\",                    \"MediaCodec: handle resolution change automatically\",\n        OPTION_OFFSET(mediacodec_handle_resolution_change),     OPTION_INT(0, 0, 1) },\n    { \"opensles\",                           \"OpenSL ES: enable\",\n        OPTION_OFFSET(opensles),            OPTION_INT(0, 0, 1) },\n    { \"soundtouch\",                           \"SoundTouch: enable\",\n        OPTION_OFFSET(soundtouch_enable),            OPTION_INT(0, 0, 1) },\n    { \"mediacodec-sync\",                 \"mediacodec: use msg_queue for synchronise\",\n        OPTION_OFFSET(mediacodec_sync),           OPTION_INT(0, 0, 1) },\n    { \"mediacodec-default-name\",          \"mediacodec default name\",\n        OPTION_OFFSET(mediacodec_default_name),      OPTION_STR(NULL) },\n    { \"ijkmeta-delay-init\",          \"ijkmeta delay init\",\n        OPTION_OFFSET(ijkmeta_delay_init),      OPTION_INT(0, 0, 1) },\n    { \"render-wait-start\",          \"render wait start\",\n        OPTION_OFFSET(render_wait_start),      OPTION_INT(0, 0, 1) },\n    { NULL }\n};\n\n#undef OPTION_STR\n#undef OPTION_CONST\n#undef OPTION_INT\n#undef OPTION_OFFSET\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavformat/allformats.c",
    "content": "/*\n * Copyright (c) 2003 Bilibili\n * Copyright (c) 2003 Fabrice Bellard\n * Copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n * Based on libavformat/allformats.c\n *\n * FFmpeg is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * FFmpeg is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"libavformat/avformat.h\"\n#include \"libavformat/url.h\"\n#include \"libavformat/version.h\"\n\n#define IJK_REGISTER_DEMUXER(x)                                         \\\n    {                                                                   \\\n        extern AVInputFormat ijkff_##x##_demuxer;                       \\\n        int ijkav_register_##x##_demuxer(AVInputFormat *demuxer, int demuxer_size);   \\\n        ijkav_register_##x##_demuxer(&ijkff_##x##_demuxer, sizeof(AVInputFormat));    \\\n    }\n\n#define IJK_REGISTER_PROTOCOL(x)                                        \\\n    {                                                                   \\\n        extern URLProtocol ijkimp_ff_##x##_protocol;                        \\\n        int ijkav_register_##x##_protocol(URLProtocol *protocol, int protocol_size);\\\n        ijkav_register_##x##_protocol(&ijkimp_ff_##x##_protocol, sizeof(URLProtocol));  \\\n    }\n\nstatic struct AVInputFormat *ijkav_find_input_format(const char *iformat_name)\n{\n    AVInputFormat *fmt = NULL;\n    if (!iformat_name)\n        return NULL;\n    while ((fmt = av_iformat_next(fmt))) {\n        if (!fmt->name)\n            continue;\n        if (!strcmp(iformat_name, fmt->name))\n            return fmt;\n    }\n    return NULL;\n}\n\nstatic void ijkav_register_input_format(AVInputFormat *iformat)\n{\n    if (ijkav_find_input_format(iformat->name)) {\n        av_log(NULL, AV_LOG_WARNING, \"skip     demuxer : %s (duplicated)\\n\", iformat->name);\n    } else {\n        av_log(NULL, AV_LOG_INFO,    \"register demuxer : %s\\n\", iformat->name);\n        av_register_input_format(iformat);\n    }\n}\n\n\nvoid ijkav_register_all(void)\n{\n    static int initialized;\n\n    if (initialized)\n        return;\n    initialized = 1;\n\n    av_register_all();\n\n    /* protocols */\n    av_log(NULL, AV_LOG_INFO, \"===== custom modules begin =====\\n\");\n#ifdef __ANDROID__\n    IJK_REGISTER_PROTOCOL(ijkmediadatasource);\n#endif\n    IJK_REGISTER_PROTOCOL(ijkio);\n    IJK_REGISTER_PROTOCOL(async);\n    IJK_REGISTER_PROTOCOL(ijklongurl);\n    IJK_REGISTER_PROTOCOL(ijktcphook);\n    IJK_REGISTER_PROTOCOL(ijkhttphook);\n    IJK_REGISTER_PROTOCOL(ijksegment);\n    /* demuxers */\n    IJK_REGISTER_DEMUXER(ijklivehook);\n    IJK_REGISTER_DEMUXER(ijklas);\n    av_log(NULL, AV_LOG_INFO, \"===== custom modules end =====\\n\");\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavformat/cJSON.c",
    "content": "/*\n  Copyright (c) 2009-2017 Dave Gamble and cJSON contributors\n\n  Permission is hereby granted, free of charge, to any person obtaining a copy\n  of this software and associated documentation files (the \"Software\"), to deal\n  in the Software without restriction, including without limitation the rights\n  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  copies of the Software, and to permit persons to whom the Software is\n  furnished to do so, subject to the following conditions:\n\n  The above copyright notice and this permission notice shall be included in\n  all copies or substantial portions of the Software.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  THE SOFTWARE.\n*/\n\n/* cJSON */\n/* JSON parser in C. */\n\n/* disable warnings about old C89 functions in MSVC */\n#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER)\n#define _CRT_SECURE_NO_DEPRECATE\n#endif\n\n#ifdef __GNUC__\n#pragma GCC visibility push(default)\n#endif\n#if defined(_MSC_VER)\n#pragma warning (push)\n/* disable warning about single line comments in system headers */\n#pragma warning (disable : 4001)\n#endif\n\n#include <string.h>\n#include <stdio.h>\n#include <math.h>\n#include <stdlib.h>\n#include <float.h>\n#include <limits.h>\n#include <ctype.h>\n\n#ifdef ENABLE_LOCALES\n#include <locale.h>\n#endif\n\n#if defined(_MSC_VER)\n#pragma warning (pop)\n#endif\n#ifdef __GNUC__\n#pragma GCC visibility pop\n#endif\n\n#include \"cJSON.h\"\n\n/* define our own boolean type */\n#define true ((cJSON_bool)1)\n#define false ((cJSON_bool)0)\n\ntypedef struct {\n    const unsigned char *json;\n    size_t position;\n} error;\nstatic error global_error = { NULL, 0 };\n\nCJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void)\n{\n    return (const char*) (global_error.json + global_error.position);\n}\n\n/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */\n#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 6) || (CJSON_VERSION_PATCH != 0)\n    #error cJSON.h and cJSON.c have different versions. Make sure that both have the same.\n#endif\n\nCJSON_PUBLIC(const char*) cJSON_Version(void)\n{\n    static char version[15];\n    sprintf(version, \"%i.%i.%i\", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH);\n\n    return version;\n}\n\n/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */\nstatic int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2)\n{\n    if ((string1 == NULL) || (string2 == NULL))\n    {\n        return 1;\n    }\n\n    if (string1 == string2)\n    {\n        return 0;\n    }\n\n    for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++)\n    {\n        if (*string1 == '\\0')\n        {\n            return 0;\n        }\n    }\n\n    return tolower(*string1) - tolower(*string2);\n}\n\ntypedef struct internal_hooks\n{\n    void *(*allocate)(size_t size);\n    void (*deallocate)(void *pointer);\n    void *(*reallocate)(void *pointer, size_t size);\n} internal_hooks;\n\n#if defined(_MSC_VER)\n/* work around MSVC error C2322: '...' address of dillimport '...' is not static */\nstatic void *internal_malloc(size_t size)\n{\n    return malloc(size);\n}\nstatic void internal_free(void *pointer)\n{\n    free(pointer);\n}\nstatic void *internal_realloc(void *pointer, size_t size)\n{\n    return realloc(pointer, size);\n}\n#else\n#define internal_malloc malloc\n#define internal_free free\n#define internal_realloc realloc\n#endif\n\nstatic internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc };\n\nstatic unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks)\n{\n    size_t length = 0;\n    unsigned char *copy = NULL;\n\n    if (string == NULL)\n    {\n        return NULL;\n    }\n\n    length = strlen((const char*)string) + sizeof(\"\");\n    copy = (unsigned char*)hooks->allocate(length);\n    if (copy == NULL)\n    {\n        return NULL;\n    }\n    memcpy(copy, string, length);\n\n    return copy;\n}\n\nCJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks)\n{\n    if (hooks == NULL)\n    {\n        /* Reset hooks */\n        global_hooks.allocate = malloc;\n        global_hooks.deallocate = free;\n        global_hooks.reallocate = realloc;\n        return;\n    }\n\n    global_hooks.allocate = malloc;\n    if (hooks->malloc_fn != NULL)\n    {\n        global_hooks.allocate = hooks->malloc_fn;\n    }\n\n    global_hooks.deallocate = free;\n    if (hooks->free_fn != NULL)\n    {\n        global_hooks.deallocate = hooks->free_fn;\n    }\n\n    /* use realloc only if both free and malloc are used */\n    global_hooks.reallocate = NULL;\n    if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free))\n    {\n        global_hooks.reallocate = realloc;\n    }\n}\n\n/* Internal constructor. */\nstatic cJSON *cJSON_New_Item(const internal_hooks * const hooks)\n{\n    cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON));\n    if (node)\n    {\n        memset(node, '\\0', sizeof(cJSON));\n    }\n\n    return node;\n}\n\n/* Delete a cJSON structure. */\nCJSON_PUBLIC(void) cJSON_Delete(cJSON *item)\n{\n    cJSON *next = NULL;\n    while (item != NULL)\n    {\n        next = item->next;\n        if (!(item->type & cJSON_IsReference) && (item->child != NULL))\n        {\n            cJSON_Delete(item->child);\n        }\n        if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))\n        {\n            global_hooks.deallocate(item->valuestring);\n        }\n        if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))\n        {\n            global_hooks.deallocate(item->string);\n        }\n        global_hooks.deallocate(item);\n        item = next;\n    }\n}\n\n/* get the decimal point character of the current locale */\nstatic unsigned char get_decimal_point(void)\n{\n#ifdef ENABLE_LOCALES\n    struct lconv *lconv = localeconv();\n    return (unsigned char) lconv->decimal_point[0];\n#else\n    return '.';\n#endif\n}\n\ntypedef struct\n{\n    const unsigned char *content;\n    size_t length;\n    size_t offset;\n    size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */\n    internal_hooks hooks;\n} parse_buffer;\n\n/* check if the given size is left to read in a given parse buffer (starting with 1) */\n#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))\n/* check if the buffer can be accessed at the given index (starting with 0) */\n#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))\n#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))\n/* get a pointer to the buffer at the position */\n#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)\n\n/* Parse the input text to generate a number, and populate the result into item. */\nstatic cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer)\n{\n    double number = 0;\n    unsigned char *after_end = NULL;\n    unsigned char number_c_string[64];\n    unsigned char decimal_point = get_decimal_point();\n    size_t i = 0;\n\n    if ((input_buffer == NULL) || (input_buffer->content == NULL))\n    {\n        return false;\n    }\n\n    /* copy the number into a temporary buffer and replace '.' with the decimal point\n     * of the current locale (for strtod)\n     * This also takes care of '\\0' not necessarily being available for marking the end of the input */\n    for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++)\n    {\n        switch (buffer_at_offset(input_buffer)[i])\n        {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            case '+':\n            case '-':\n            case 'e':\n            case 'E':\n                number_c_string[i] = buffer_at_offset(input_buffer)[i];\n                break;\n\n            case '.':\n                number_c_string[i] = decimal_point;\n                break;\n\n            default:\n                goto loop_end;\n        }\n    }\nloop_end:\n    number_c_string[i] = '\\0';\n\n    number = strtod((const char*)number_c_string, (char**)&after_end);\n    if (number_c_string == after_end)\n    {\n        return false; /* parse_error */\n    }\n\n    item->valuedouble = number;\n\n    /* use saturation in case of overflow */\n    if (number >= INT_MAX)\n    {\n        item->valueint = INT_MAX;\n    }\n    else if (number <= INT_MIN)\n    {\n        item->valueint = INT_MIN;\n    }\n    else\n    {\n        item->valueint = (int)number;\n    }\n\n    item->type = cJSON_Number;\n\n    input_buffer->offset += (size_t)(after_end - number_c_string);\n    return true;\n}\n\n/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */\nCJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)\n{\n    if (number >= INT_MAX)\n    {\n        object->valueint = INT_MAX;\n    }\n    else if (number <= INT_MIN)\n    {\n        object->valueint = INT_MIN;\n    }\n    else\n    {\n        object->valueint = (int)number;\n    }\n\n    return object->valuedouble = number;\n}\n\ntypedef struct\n{\n    unsigned char *buffer;\n    size_t length;\n    size_t offset;\n    size_t depth; /* current nesting depth (for formatted printing) */\n    cJSON_bool noalloc;\n    cJSON_bool format; /* is this print a formatted print */\n    internal_hooks hooks;\n} printbuffer;\n\n/* realloc printbuffer if necessary to have at least \"needed\" bytes more */\nstatic unsigned char* ensure(printbuffer * const p, size_t needed)\n{\n    unsigned char *newbuffer = NULL;\n    size_t newsize = 0;\n\n    if ((p == NULL) || (p->buffer == NULL))\n    {\n        return NULL;\n    }\n\n    if ((p->length > 0) && (p->offset >= p->length))\n    {\n        /* make sure that offset is valid */\n        return NULL;\n    }\n\n    if (needed > INT_MAX)\n    {\n        /* sizes bigger than INT_MAX are currently not supported */\n        return NULL;\n    }\n\n    needed += p->offset + 1;\n    if (needed <= p->length)\n    {\n        return p->buffer + p->offset;\n    }\n\n    if (p->noalloc) {\n        return NULL;\n    }\n\n    /* calculate new buffer size */\n    if (needed > (INT_MAX / 2))\n    {\n        /* overflow of int, use INT_MAX if possible */\n        if (needed <= INT_MAX)\n        {\n            newsize = INT_MAX;\n        }\n        else\n        {\n            return NULL;\n        }\n    }\n    else\n    {\n        newsize = needed * 2;\n    }\n\n    if (p->hooks.reallocate != NULL)\n    {\n        /* reallocate with realloc if available */\n        newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize);\n        if (newbuffer == NULL)\n        {\n            p->hooks.deallocate(p->buffer);\n            p->length = 0;\n            p->buffer = NULL;\n\n            return NULL;\n        }\n    }\n    else\n    {\n        /* otherwise reallocate manually */\n        newbuffer = (unsigned char*)p->hooks.allocate(newsize);\n        if (!newbuffer)\n        {\n            p->hooks.deallocate(p->buffer);\n            p->length = 0;\n            p->buffer = NULL;\n\n            return NULL;\n        }\n        if (newbuffer)\n        {\n            memcpy(newbuffer, p->buffer, p->offset + 1);\n        }\n        p->hooks.deallocate(p->buffer);\n    }\n    p->length = newsize;\n    p->buffer = newbuffer;\n\n    return newbuffer + p->offset;\n}\n\n/* calculate the new length of the string in a printbuffer and update the offset */\nstatic void update_offset(printbuffer * const buffer)\n{\n    const unsigned char *buffer_pointer = NULL;\n    if ((buffer == NULL) || (buffer->buffer == NULL))\n    {\n        return;\n    }\n    buffer_pointer = buffer->buffer + buffer->offset;\n\n    buffer->offset += strlen((const char*)buffer_pointer);\n}\n\n/* Render the number nicely from the given item into a string. */\nstatic cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)\n{\n    unsigned char *output_pointer = NULL;\n    double d = item->valuedouble;\n    int length = 0;\n    size_t i = 0;\n    unsigned char number_buffer[26]; /* temporary buffer to print the number into */\n    unsigned char decimal_point = get_decimal_point();\n    double test;\n\n    if (output_buffer == NULL)\n    {\n        return false;\n    }\n\n    /* This checks for NaN and Infinity */\n    if ((d * 0) != 0)\n    {\n        length = sprintf((char*)number_buffer, \"null\");\n    }\n    else\n    {\n        /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */\n        length = sprintf((char*)number_buffer, \"%1.15g\", d);\n\n        /* Check whether the original double can be recovered */\n        if ((sscanf((char*)number_buffer, \"%lg\", &test) != 1) || ((double)test != d))\n        {\n            /* If not, print with 17 decimal places of precision */\n            length = sprintf((char*)number_buffer, \"%1.17g\", d);\n        }\n    }\n\n    /* sprintf failed or buffer overrun occured */\n    if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1)))\n    {\n        return false;\n    }\n\n    /* reserve appropriate space in the output */\n    output_pointer = ensure(output_buffer, (size_t)length);\n    if (output_pointer == NULL)\n    {\n        return false;\n    }\n\n    /* copy the printed number to the output and replace locale\n     * dependent decimal point with '.' */\n    for (i = 0; i < ((size_t)length); i++)\n    {\n        if (number_buffer[i] == decimal_point)\n        {\n            output_pointer[i] = '.';\n            continue;\n        }\n\n        output_pointer[i] = number_buffer[i];\n    }\n    output_pointer[i] = '\\0';\n\n    output_buffer->offset += (size_t)length;\n\n    return true;\n}\n\n/* parse 4 digit hexadecimal number */\nstatic unsigned parse_hex4(const unsigned char * const input)\n{\n    unsigned int h = 0;\n    size_t i = 0;\n\n    for (i = 0; i < 4; i++)\n    {\n        /* parse digit */\n        if ((input[i] >= '0') && (input[i] <= '9'))\n        {\n            h += (unsigned int) input[i] - '0';\n        }\n        else if ((input[i] >= 'A') && (input[i] <= 'F'))\n        {\n            h += (unsigned int) 10 + input[i] - 'A';\n        }\n        else if ((input[i] >= 'a') && (input[i] <= 'f'))\n        {\n            h += (unsigned int) 10 + input[i] - 'a';\n        }\n        else /* invalid */\n        {\n            return 0;\n        }\n\n        if (i < 3)\n        {\n            /* shift left to make place for the next nibble */\n            h = h << 4;\n        }\n    }\n\n    return h;\n}\n\n/* converts a UTF-16 literal to UTF-8\n * A literal can be one or two sequences of the form \\uXXXX */\nstatic unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer)\n{\n    long unsigned int codepoint = 0;\n    unsigned int first_code = 0;\n    const unsigned char *first_sequence = input_pointer;\n    unsigned char utf8_length = 0;\n    unsigned char utf8_position = 0;\n    unsigned char sequence_length = 0;\n    unsigned char first_byte_mark = 0;\n\n    if ((input_end - first_sequence) < 6)\n    {\n        /* input ends unexpectedly */\n        goto fail;\n    }\n\n    /* get the first utf16 sequence */\n    first_code = parse_hex4(first_sequence + 2);\n\n    /* check that the code is valid */\n    if (((first_code >= 0xDC00) && (first_code <= 0xDFFF)))\n    {\n        goto fail;\n    }\n\n    /* UTF16 surrogate pair */\n    if ((first_code >= 0xD800) && (first_code <= 0xDBFF))\n    {\n        const unsigned char *second_sequence = first_sequence + 6;\n        unsigned int second_code = 0;\n        sequence_length = 12; /* \\uXXXX\\uXXXX */\n\n        if ((input_end - second_sequence) < 6)\n        {\n            /* input ends unexpectedly */\n            goto fail;\n        }\n\n        if ((second_sequence[0] != '\\\\') || (second_sequence[1] != 'u'))\n        {\n            /* missing second half of the surrogate pair */\n            goto fail;\n        }\n\n        /* get the second utf16 sequence */\n        second_code = parse_hex4(second_sequence + 2);\n        /* check that the code is valid */\n        if ((second_code < 0xDC00) || (second_code > 0xDFFF))\n        {\n            /* invalid second half of the surrogate pair */\n            goto fail;\n        }\n\n\n        /* calculate the unicode codepoint from the surrogate pair */\n        codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));\n    }\n    else\n    {\n        sequence_length = 6; /* \\uXXXX */\n        codepoint = first_code;\n    }\n\n    /* encode as UTF-8\n     * takes at maximum 4 bytes to encode:\n     * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */\n    if (codepoint < 0x80)\n    {\n        /* normal ascii, encoding 0xxxxxxx */\n        utf8_length = 1;\n    }\n    else if (codepoint < 0x800)\n    {\n        /* two bytes, encoding 110xxxxx 10xxxxxx */\n        utf8_length = 2;\n        first_byte_mark = 0xC0; /* 11000000 */\n    }\n    else if (codepoint < 0x10000)\n    {\n        /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */\n        utf8_length = 3;\n        first_byte_mark = 0xE0; /* 11100000 */\n    }\n    else if (codepoint <= 0x10FFFF)\n    {\n        /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */\n        utf8_length = 4;\n        first_byte_mark = 0xF0; /* 11110000 */\n    }\n    else\n    {\n        /* invalid unicode codepoint */\n        goto fail;\n    }\n\n    /* encode as utf8 */\n    for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--)\n    {\n        /* 10xxxxxx */\n        (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);\n        codepoint >>= 6;\n    }\n    /* encode first byte */\n    if (utf8_length > 1)\n    {\n        (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);\n    }\n    else\n    {\n        (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);\n    }\n\n    *output_pointer += utf8_length;\n\n    return sequence_length;\n\nfail:\n    return 0;\n}\n\n/* Parse the input text into an unescaped cinput, and populate item. */\nstatic cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer)\n{\n    const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;\n    const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;\n    unsigned char *output_pointer = NULL;\n    unsigned char *output = NULL;\n\n    /* not a string */\n    if (buffer_at_offset(input_buffer)[0] != '\\\"')\n    {\n        goto fail;\n    }\n\n    {\n        /* calculate approximate size of the output (overestimate) */\n        size_t allocation_length = 0;\n        size_t skipped_bytes = 0;\n        while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\\\"'))\n        {\n            /* is escape sequence */\n            if (input_end[0] == '\\\\')\n            {\n                if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length)\n                {\n                    /* prevent buffer overflow when last input character is a backslash */\n                    goto fail;\n                }\n                skipped_bytes++;\n                input_end++;\n            }\n            input_end++;\n        }\n        if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\\\"'))\n        {\n            goto fail; /* string ended unexpectedly */\n        }\n\n        /* This is at most how much we need for the output */\n        allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes;\n        output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof(\"\"));\n        if (output == NULL)\n        {\n            goto fail; /* allocation failure */\n        }\n    }\n\n    output_pointer = output;\n    /* loop through the string literal */\n    while (input_pointer < input_end)\n    {\n        if (*input_pointer != '\\\\')\n        {\n            *output_pointer++ = *input_pointer++;\n        }\n        /* escape sequence */\n        else\n        {\n            unsigned char sequence_length = 2;\n            if ((input_end - input_pointer) < 1)\n            {\n                goto fail;\n            }\n\n            switch (input_pointer[1])\n            {\n                case 'b':\n                    *output_pointer++ = '\\b';\n                    break;\n                case 'f':\n                    *output_pointer++ = '\\f';\n                    break;\n                case 'n':\n                    *output_pointer++ = '\\n';\n                    break;\n                case 'r':\n                    *output_pointer++ = '\\r';\n                    break;\n                case 't':\n                    *output_pointer++ = '\\t';\n                    break;\n                case '\\\"':\n                case '\\\\':\n                case '/':\n                    *output_pointer++ = input_pointer[1];\n                    break;\n\n                /* UTF-16 literal */\n                case 'u':\n                    sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);\n                    if (sequence_length == 0)\n                    {\n                        /* failed to convert UTF16-literal to UTF-8 */\n                        goto fail;\n                    }\n                    break;\n\n                default:\n                    goto fail;\n            }\n            input_pointer += sequence_length;\n        }\n    }\n\n    /* zero terminate the output */\n    *output_pointer = '\\0';\n\n    item->type = cJSON_String;\n    item->valuestring = (char*)output;\n\n    input_buffer->offset = (size_t) (input_end - input_buffer->content);\n    input_buffer->offset++;\n\n    return true;\n\nfail:\n    if (output != NULL)\n    {\n        input_buffer->hooks.deallocate(output);\n    }\n\n    if (input_pointer != NULL)\n    {\n        input_buffer->offset = (size_t)(input_pointer - input_buffer->content);\n    }\n\n    return false;\n}\n\n/* Render the cstring provided to an escaped version that can be printed. */\nstatic cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer)\n{\n    const unsigned char *input_pointer = NULL;\n    unsigned char *output = NULL;\n    unsigned char *output_pointer = NULL;\n    size_t output_length = 0;\n    /* numbers of additional characters needed for escaping */\n    size_t escape_characters = 0;\n\n    if (output_buffer == NULL)\n    {\n        return false;\n    }\n\n    /* empty string */\n    if (input == NULL)\n    {\n        output = ensure(output_buffer, sizeof(\"\\\"\\\"\"));\n        if (output == NULL)\n        {\n            return false;\n        }\n        strcpy((char*)output, \"\\\"\\\"\");\n\n        return true;\n    }\n\n    /* set \"flag\" to 1 if something needs to be escaped */\n    for (input_pointer = input; *input_pointer; input_pointer++)\n    {\n        switch (*input_pointer)\n        {\n            case '\\\"':\n            case '\\\\':\n            case '\\b':\n            case '\\f':\n            case '\\n':\n            case '\\r':\n            case '\\t':\n                /* one character escape sequence */\n                escape_characters++;\n                break;\n            default:\n                if (*input_pointer < 32)\n                {\n                    /* UTF-16 escape sequence uXXXX */\n                    escape_characters += 5;\n                }\n                break;\n        }\n    }\n    output_length = (size_t)(input_pointer - input) + escape_characters;\n\n    output = ensure(output_buffer, output_length + sizeof(\"\\\"\\\"\"));\n    if (output == NULL)\n    {\n        return false;\n    }\n\n    /* no characters have to be escaped */\n    if (escape_characters == 0)\n    {\n        output[0] = '\\\"';\n        memcpy(output + 1, input, output_length);\n        output[output_length + 1] = '\\\"';\n        output[output_length + 2] = '\\0';\n\n        return true;\n    }\n\n    output[0] = '\\\"';\n    output_pointer = output + 1;\n    /* copy the string */\n    for (input_pointer = input; *input_pointer != '\\0'; (void)input_pointer++, output_pointer++)\n    {\n        if ((*input_pointer > 31) && (*input_pointer != '\\\"') && (*input_pointer != '\\\\'))\n        {\n            /* normal character, copy */\n            *output_pointer = *input_pointer;\n        }\n        else\n        {\n            /* character needs to be escaped */\n            *output_pointer++ = '\\\\';\n            switch (*input_pointer)\n            {\n                case '\\\\':\n                    *output_pointer = '\\\\';\n                    break;\n                case '\\\"':\n                    *output_pointer = '\\\"';\n                    break;\n                case '\\b':\n                    *output_pointer = 'b';\n                    break;\n                case '\\f':\n                    *output_pointer = 'f';\n                    break;\n                case '\\n':\n                    *output_pointer = 'n';\n                    break;\n                case '\\r':\n                    *output_pointer = 'r';\n                    break;\n                case '\\t':\n                    *output_pointer = 't';\n                    break;\n                default:\n                    /* escape and print as unicode codepoint */\n                    sprintf((char*)output_pointer, \"u%04x\", *input_pointer);\n                    output_pointer += 4;\n                    break;\n            }\n        }\n    }\n    output[output_length + 1] = '\\\"';\n    output[output_length + 2] = '\\0';\n\n    return true;\n}\n\n/* Invoke print_string_ptr (which is useful) on an item. */\nstatic cJSON_bool print_string(const cJSON * const item, printbuffer * const p)\n{\n    return print_string_ptr((unsigned char*)item->valuestring, p);\n}\n\n/* Predeclare these prototypes. */\nstatic cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer);\nstatic cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer);\nstatic cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer);\nstatic cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer);\nstatic cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer);\nstatic cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer);\n\n/* Utility to jump whitespace and cr/lf */\nstatic parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer)\n{\n    if ((buffer == NULL) || (buffer->content == NULL))\n    {\n        return NULL;\n    }\n\n    while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32))\n    {\n       buffer->offset++;\n    }\n\n    if (buffer->offset == buffer->length)\n    {\n        buffer->offset--;\n    }\n\n    return buffer;\n}\n\n/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */\nstatic parse_buffer *skip_utf8_bom(parse_buffer * const buffer)\n{\n    if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0))\n    {\n        return NULL;\n    }\n\n    if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), \"\\xEF\\xBB\\xBF\", 3) == 0))\n    {\n        buffer->offset += 3;\n    }\n\n    return buffer;\n}\n\n/* Parse an object - create a new root, and populate. */\nCJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)\n{\n    parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };\n    cJSON *item = NULL;\n\n    /* reset error position */\n    global_error.json = NULL;\n    global_error.position = 0;\n\n    if (value == NULL)\n    {\n        goto fail;\n    }\n\n    buffer.content = (const unsigned char*)value;\n    buffer.length = strlen((const char*)value) + sizeof(\"\");\n    buffer.offset = 0;\n    buffer.hooks = global_hooks;\n\n    item = cJSON_New_Item(&global_hooks);\n    if (item == NULL) /* memory fail */\n    {\n        goto fail;\n    }\n\n    if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer))))\n    {\n        /* parse failure. ep is set. */\n        goto fail;\n    }\n\n    /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */\n    if (require_null_terminated)\n    {\n        buffer_skip_whitespace(&buffer);\n        if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\\0')\n        {\n            goto fail;\n        }\n    }\n    if (return_parse_end)\n    {\n        *return_parse_end = (const char*)buffer_at_offset(&buffer);\n    }\n\n    return item;\n\nfail:\n    if (item != NULL)\n    {\n        cJSON_Delete(item);\n    }\n\n    if (value != NULL)\n    {\n        error local_error;\n        local_error.json = (const unsigned char*)value;\n        local_error.position = 0;\n\n        if (buffer.offset < buffer.length)\n        {\n            local_error.position = buffer.offset;\n        }\n        else if (buffer.length > 0)\n        {\n            local_error.position = buffer.length - 1;\n        }\n\n        if (return_parse_end != NULL)\n        {\n            *return_parse_end = (const char*)local_error.json + local_error.position;\n        }\n\n        global_error = local_error;\n    }\n\n    return NULL;\n}\n\n/* Default options for cJSON_Parse */\nCJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)\n{\n    return cJSON_ParseWithOpts(value, 0, 0);\n}\n\n#define cjson_min(a, b) ((a < b) ? a : b)\n\nstatic unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks)\n{\n    printbuffer buffer[1];\n    unsigned char *printed = NULL;\n\n    memset(buffer, 0, sizeof(buffer));\n\n    /* create buffer */\n    buffer->buffer = (unsigned char*) hooks->allocate(256);\n    buffer->format = format;\n    buffer->hooks = *hooks;\n    if (buffer->buffer == NULL)\n    {\n        goto fail;\n    }\n\n    /* print the value */\n    if (!print_value(item, buffer))\n    {\n        goto fail;\n    }\n    update_offset(buffer);\n\n    /* check if reallocate is available */\n    if (hooks->reallocate != NULL)\n    {\n        printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->length);\n        buffer->buffer = NULL;\n        if (printed == NULL) {\n            goto fail;\n        }\n    }\n    else /* otherwise copy the JSON over to a new buffer */\n    {\n        printed = (unsigned char*) hooks->allocate(buffer->offset + 1);\n        if (printed == NULL)\n        {\n            goto fail;\n        }\n        memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1));\n        printed[buffer->offset] = '\\0'; /* just to be sure */\n\n        /* free the buffer */\n        hooks->deallocate(buffer->buffer);\n    }\n\n    return printed;\n\nfail:\n    if (buffer->buffer != NULL)\n    {\n        hooks->deallocate(buffer->buffer);\n    }\n\n    if (printed != NULL)\n    {\n        hooks->deallocate(printed);\n    }\n\n    return NULL;\n}\n\n/* Render a cJSON item/entity/structure to text. */\nCJSON_PUBLIC(char *) cJSON_Print(const cJSON *item)\n{\n    return (char*)print(item, true, &global_hooks);\n}\n\nCJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item)\n{\n    return (char*)print(item, false, &global_hooks);\n}\n\nCJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)\n{\n    printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };\n\n    if (prebuffer < 0)\n    {\n        return NULL;\n    }\n\n    p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer);\n    if (!p.buffer)\n    {\n        return NULL;\n    }\n\n    p.length = (size_t)prebuffer;\n    p.offset = 0;\n    p.noalloc = false;\n    p.format = fmt;\n    p.hooks = global_hooks;\n\n    if (!print_value(item, &p))\n    {\n        global_hooks.deallocate(p.buffer);\n        return NULL;\n    }\n\n    return (char*)p.buffer;\n}\n\nCJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt)\n{\n    printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };\n\n    if ((len < 0) || (buf == NULL))\n    {\n        return false;\n    }\n\n    p.buffer = (unsigned char*)buf;\n    p.length = (size_t)len;\n    p.offset = 0;\n    p.noalloc = true;\n    p.format = fmt;\n    p.hooks = global_hooks;\n\n    return print_value(item, &p);\n}\n\n/* Parser core - when encountering text, process appropriately. */\nstatic cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer)\n{\n    if ((input_buffer == NULL) || (input_buffer->content == NULL))\n    {\n        return false; /* no input */\n    }\n\n    /* parse the different types of values */\n    /* null */\n    if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), \"null\", 4) == 0))\n    {\n        item->type = cJSON_NULL;\n        input_buffer->offset += 4;\n        return true;\n    }\n    /* false */\n    if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), \"false\", 5) == 0))\n    {\n        item->type = cJSON_False;\n        input_buffer->offset += 5;\n        return true;\n    }\n    /* true */\n    if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), \"true\", 4) == 0))\n    {\n        item->type = cJSON_True;\n        item->valueint = 1;\n        input_buffer->offset += 4;\n        return true;\n    }\n    /* string */\n    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\\\"'))\n    {\n        return parse_string(item, input_buffer);\n    }\n    /* number */\n    if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9'))))\n    {\n        return parse_number(item, input_buffer);\n    }\n    /* array */\n    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '['))\n    {\n        return parse_array(item, input_buffer);\n    }\n    /* object */\n    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{'))\n    {\n        return parse_object(item, input_buffer);\n    }\n\n    return false;\n}\n\n/* Render a value to text. */\nstatic cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer)\n{\n    unsigned char *output = NULL;\n\n    if ((item == NULL) || (output_buffer == NULL))\n    {\n        return false;\n    }\n\n    switch ((item->type) & 0xFF)\n    {\n        case cJSON_NULL:\n            output = ensure(output_buffer, 5);\n            if (output == NULL)\n            {\n                return false;\n            }\n            strcpy((char*)output, \"null\");\n            return true;\n\n        case cJSON_False:\n            output = ensure(output_buffer, 6);\n            if (output == NULL)\n            {\n                return false;\n            }\n            strcpy((char*)output, \"false\");\n            return true;\n\n        case cJSON_True:\n            output = ensure(output_buffer, 5);\n            if (output == NULL)\n            {\n                return false;\n            }\n            strcpy((char*)output, \"true\");\n            return true;\n\n        case cJSON_Number:\n            return print_number(item, output_buffer);\n\n        case cJSON_Raw:\n        {\n            size_t raw_length = 0;\n            if (item->valuestring == NULL)\n            {\n                if (!output_buffer->noalloc)\n                {\n                    output_buffer->hooks.deallocate(output_buffer->buffer);\n                }\n                return false;\n            }\n\n            raw_length = strlen(item->valuestring) + sizeof(\"\");\n            output = ensure(output_buffer, raw_length);\n            if (output == NULL)\n            {\n                return false;\n            }\n            memcpy(output, item->valuestring, raw_length);\n            return true;\n        }\n\n        case cJSON_String:\n            return print_string(item, output_buffer);\n\n        case cJSON_Array:\n            return print_array(item, output_buffer);\n\n        case cJSON_Object:\n            return print_object(item, output_buffer);\n\n        default:\n            return false;\n    }\n}\n\n/* Build an array from input text. */\nstatic cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer)\n{\n    cJSON *head = NULL; /* head of the linked list */\n    cJSON *current_item = NULL;\n\n    if (input_buffer->depth >= CJSON_NESTING_LIMIT)\n    {\n        return false; /* to deeply nested */\n    }\n    input_buffer->depth++;\n\n    if (buffer_at_offset(input_buffer)[0] != '[')\n    {\n        /* not an array */\n        goto fail;\n    }\n\n    input_buffer->offset++;\n    buffer_skip_whitespace(input_buffer);\n    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']'))\n    {\n        /* empty array */\n        goto success;\n    }\n\n    /* check if we skipped to the end of the buffer */\n    if (cannot_access_at_index(input_buffer, 0))\n    {\n        input_buffer->offset--;\n        goto fail;\n    }\n\n    /* step back to character in front of the first element */\n    input_buffer->offset--;\n    /* loop through the comma separated array elements */\n    do\n    {\n        /* allocate next item */\n        cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));\n        if (new_item == NULL)\n        {\n            goto fail; /* allocation failure */\n        }\n\n        /* attach next item to list */\n        if (head == NULL)\n        {\n            /* start the linked list */\n            current_item = head = new_item;\n        }\n        else\n        {\n            /* add to the end and advance */\n            current_item->next = new_item;\n            new_item->prev = current_item;\n            current_item = new_item;\n        }\n\n        /* parse next value */\n        input_buffer->offset++;\n        buffer_skip_whitespace(input_buffer);\n        if (!parse_value(current_item, input_buffer))\n        {\n            goto fail; /* failed to parse value */\n        }\n        buffer_skip_whitespace(input_buffer);\n    }\n    while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));\n\n    if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']')\n    {\n        goto fail; /* expected end of array */\n    }\n\nsuccess:\n    input_buffer->depth--;\n\n    item->type = cJSON_Array;\n    item->child = head;\n\n    input_buffer->offset++;\n\n    return true;\n\nfail:\n    if (head != NULL)\n    {\n        cJSON_Delete(head);\n    }\n\n    return false;\n}\n\n/* Render an array to text */\nstatic cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer)\n{\n    unsigned char *output_pointer = NULL;\n    size_t length = 0;\n    cJSON *current_element = item->child;\n\n    if (output_buffer == NULL)\n    {\n        return false;\n    }\n\n    /* Compose the output array. */\n    /* opening square bracket */\n    output_pointer = ensure(output_buffer, 1);\n    if (output_pointer == NULL)\n    {\n        return false;\n    }\n\n    *output_pointer = '[';\n    output_buffer->offset++;\n    output_buffer->depth++;\n\n    while (current_element != NULL)\n    {\n        if (!print_value(current_element, output_buffer))\n        {\n            return false;\n        }\n        update_offset(output_buffer);\n        if (current_element->next)\n        {\n            length = (size_t) (output_buffer->format ? 2 : 1);\n            output_pointer = ensure(output_buffer, length + 1);\n            if (output_pointer == NULL)\n            {\n                return false;\n            }\n            *output_pointer++ = ',';\n            if(output_buffer->format)\n            {\n                *output_pointer++ = ' ';\n            }\n            *output_pointer = '\\0';\n            output_buffer->offset += length;\n        }\n        current_element = current_element->next;\n    }\n\n    output_pointer = ensure(output_buffer, 2);\n    if (output_pointer == NULL)\n    {\n        return false;\n    }\n    *output_pointer++ = ']';\n    *output_pointer = '\\0';\n    output_buffer->depth--;\n\n    return true;\n}\n\n/* Build an object from the text. */\nstatic cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer)\n{\n    cJSON *head = NULL; /* linked list head */\n    cJSON *current_item = NULL;\n\n    if (input_buffer->depth >= CJSON_NESTING_LIMIT)\n    {\n        return false; /* to deeply nested */\n    }\n    input_buffer->depth++;\n\n    if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{'))\n    {\n        goto fail; /* not an object */\n    }\n\n    input_buffer->offset++;\n    buffer_skip_whitespace(input_buffer);\n    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}'))\n    {\n        goto success; /* empty object */\n    }\n\n    /* check if we skipped to the end of the buffer */\n    if (cannot_access_at_index(input_buffer, 0))\n    {\n        input_buffer->offset--;\n        goto fail;\n    }\n\n    /* step back to character in front of the first element */\n    input_buffer->offset--;\n    /* loop through the comma separated array elements */\n    do\n    {\n        /* allocate next item */\n        cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));\n        if (new_item == NULL)\n        {\n            goto fail; /* allocation failure */\n        }\n\n        /* attach next item to list */\n        if (head == NULL)\n        {\n            /* start the linked list */\n            current_item = head = new_item;\n        }\n        else\n        {\n            /* add to the end and advance */\n            current_item->next = new_item;\n            new_item->prev = current_item;\n            current_item = new_item;\n        }\n\n        /* parse the name of the child */\n        input_buffer->offset++;\n        buffer_skip_whitespace(input_buffer);\n        if (!parse_string(current_item, input_buffer))\n        {\n            goto fail; /* faile to parse name */\n        }\n        buffer_skip_whitespace(input_buffer);\n\n        /* swap valuestring and string, because we parsed the name */\n        current_item->string = current_item->valuestring;\n        current_item->valuestring = NULL;\n\n        if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':'))\n        {\n            goto fail; /* invalid object */\n        }\n\n        /* parse the value */\n        input_buffer->offset++;\n        buffer_skip_whitespace(input_buffer);\n        if (!parse_value(current_item, input_buffer))\n        {\n            goto fail; /* failed to parse value */\n        }\n        buffer_skip_whitespace(input_buffer);\n    }\n    while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));\n\n    if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}'))\n    {\n        goto fail; /* expected end of object */\n    }\n\nsuccess:\n    input_buffer->depth--;\n\n    item->type = cJSON_Object;\n    item->child = head;\n\n    input_buffer->offset++;\n    return true;\n\nfail:\n    if (head != NULL)\n    {\n        cJSON_Delete(head);\n    }\n\n    return false;\n}\n\n/* Render an object to text. */\nstatic cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer)\n{\n    unsigned char *output_pointer = NULL;\n    size_t length = 0;\n    cJSON *current_item = item->child;\n\n    if (output_buffer == NULL)\n    {\n        return false;\n    }\n\n    /* Compose the output: */\n    length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\\n */\n    output_pointer = ensure(output_buffer, length + 1);\n    if (output_pointer == NULL)\n    {\n        return false;\n    }\n\n    *output_pointer++ = '{';\n    output_buffer->depth++;\n    if (output_buffer->format)\n    {\n        *output_pointer++ = '\\n';\n    }\n    output_buffer->offset += length;\n\n    while (current_item)\n    {\n        if (output_buffer->format)\n        {\n            size_t i;\n            output_pointer = ensure(output_buffer, output_buffer->depth);\n            if (output_pointer == NULL)\n            {\n                return false;\n            }\n            for (i = 0; i < output_buffer->depth; i++)\n            {\n                *output_pointer++ = '\\t';\n            }\n            output_buffer->offset += output_buffer->depth;\n        }\n\n        /* print key */\n        if (!print_string_ptr((unsigned char*)current_item->string, output_buffer))\n        {\n            return false;\n        }\n        update_offset(output_buffer);\n\n        length = (size_t) (output_buffer->format ? 2 : 1);\n        output_pointer = ensure(output_buffer, length);\n        if (output_pointer == NULL)\n        {\n            return false;\n        }\n        *output_pointer++ = ':';\n        if (output_buffer->format)\n        {\n            *output_pointer++ = '\\t';\n        }\n        output_buffer->offset += length;\n\n        /* print value */\n        if (!print_value(current_item, output_buffer))\n        {\n            return false;\n        }\n        update_offset(output_buffer);\n\n        /* print comma if not last */\n        length = (size_t) ((output_buffer->format ? 1 : 0) + (current_item->next ? 1 : 0));\n        output_pointer = ensure(output_buffer, length + 1);\n        if (output_pointer == NULL)\n        {\n            return false;\n        }\n        if (current_item->next)\n        {\n            *output_pointer++ = ',';\n        }\n\n        if (output_buffer->format)\n        {\n            *output_pointer++ = '\\n';\n        }\n        *output_pointer = '\\0';\n        output_buffer->offset += length;\n\n        current_item = current_item->next;\n    }\n\n    output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2);\n    if (output_pointer == NULL)\n    {\n        return false;\n    }\n    if (output_buffer->format)\n    {\n        size_t i;\n        for (i = 0; i < (output_buffer->depth - 1); i++)\n        {\n            *output_pointer++ = '\\t';\n        }\n    }\n    *output_pointer++ = '}';\n    *output_pointer = '\\0';\n    output_buffer->depth--;\n\n    return true;\n}\n\n/* Get Array size/item / object item. */\nCJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array)\n{\n    cJSON *child = NULL;\n    size_t size = 0;\n\n    if (array == NULL)\n    {\n        return 0;\n    }\n\n    child = array->child;\n\n    while(child != NULL)\n    {\n        size++;\n        child = child->next;\n    }\n\n    /* FIXME: Can overflow here. Cannot be fixed without breaking the API */\n\n    return (int)size;\n}\n\nstatic cJSON* get_array_item(const cJSON *array, size_t index)\n{\n    cJSON *current_child = NULL;\n\n    if (array == NULL)\n    {\n        return NULL;\n    }\n\n    current_child = array->child;\n    while ((current_child != NULL) && (index > 0))\n    {\n        index--;\n        current_child = current_child->next;\n    }\n\n    return current_child;\n}\n\nCJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index)\n{\n    if (index < 0)\n    {\n        return NULL;\n    }\n\n    return get_array_item(array, (size_t)index);\n}\n\nstatic cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive)\n{\n    cJSON *current_element = NULL;\n\n    if ((object == NULL) || (name == NULL))\n    {\n        return NULL;\n    }\n\n    current_element = object->child;\n    if (case_sensitive)\n    {\n        while ((current_element != NULL) && (strcmp(name, current_element->string) != 0))\n        {\n            current_element = current_element->next;\n        }\n    }\n    else\n    {\n        while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0))\n        {\n            current_element = current_element->next;\n        }\n    }\n\n    return current_element;\n}\n\nCJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string)\n{\n    return get_object_item(object, string, false);\n}\n\nCJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string)\n{\n    return get_object_item(object, string, true);\n}\n\nCJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string)\n{\n    return cJSON_GetObjectItem(object, string) ? 1 : 0;\n}\n\n/* Utility for array list handling. */\nstatic void suffix_object(cJSON *prev, cJSON *item)\n{\n    prev->next = item;\n    item->prev = prev;\n}\n\n/* Utility for handling references. */\nstatic cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks)\n{\n    cJSON *reference = NULL;\n    if (item == NULL)\n    {\n        return NULL;\n    }\n\n    reference = cJSON_New_Item(hooks);\n    if (reference == NULL)\n    {\n        return NULL;\n    }\n\n    memcpy(reference, item, sizeof(cJSON));\n    reference->string = NULL;\n    reference->type |= cJSON_IsReference;\n    reference->next = reference->prev = NULL;\n    return reference;\n}\n\n/* Add item to array/object. */\nCJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item)\n{\n    cJSON *child = NULL;\n\n    if ((item == NULL) || (array == NULL))\n    {\n        return;\n    }\n\n    child = array->child;\n\n    if (child == NULL)\n    {\n        /* list is empty, start new one */\n        array->child = item;\n    }\n    else\n    {\n        /* append to the end */\n        while (child->next)\n        {\n            child = child->next;\n        }\n        suffix_object(child, item);\n    }\n}\n\nCJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)\n{\n    if (item == NULL)\n    {\n        return;\n    }\n\n    /* call cJSON_AddItemToObjectCS for code reuse */\n    cJSON_AddItemToObjectCS(object, (char*)cJSON_strdup((const unsigned char*)string, &global_hooks), item);\n    /* remove cJSON_StringIsConst flag */\n    item->type &= ~cJSON_StringIsConst;\n}\n\n#if defined(__clang__) || (defined(__GNUC__)  && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))\n    #pragma GCC diagnostic push\n#endif\n#ifdef __GNUC__\n#pragma GCC diagnostic ignored \"-Wcast-qual\"\n#endif\n\n/* Add an item to an object with constant string as key */\nCJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)\n{\n    if ((item == NULL) || (string == NULL))\n    {\n        return;\n    }\n    if (!(item->type & cJSON_StringIsConst) && item->string)\n    {\n        global_hooks.deallocate(item->string);\n    }\n    item->string = (char*)string;\n    item->type |= cJSON_StringIsConst;\n    cJSON_AddItemToArray(object, item);\n}\n#if defined(__clang__) || (defined(__GNUC__)  && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))\n    #pragma GCC diagnostic pop\n#endif\n\nCJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)\n{\n    if (array == NULL)\n    {\n        return;\n    }\n\n    cJSON_AddItemToArray(array, create_reference(item, &global_hooks));\n}\n\nCJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)\n{\n    if ((object == NULL) || (string == NULL))\n    {\n        return;\n    }\n\n    cJSON_AddItemToObject(object, string, create_reference(item, &global_hooks));\n}\n\nCJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item)\n{\n    if ((parent == NULL) || (item == NULL))\n    {\n        return NULL;\n    }\n\n    if (item->prev != NULL)\n    {\n        /* not the first element */\n        item->prev->next = item->next;\n    }\n    if (item->next != NULL)\n    {\n        /* not the last element */\n        item->next->prev = item->prev;\n    }\n\n    if (item == parent->child)\n    {\n        /* first element */\n        parent->child = item->next;\n    }\n    /* make sure the detached item doesn't point anywhere anymore */\n    item->prev = NULL;\n    item->next = NULL;\n\n    return item;\n}\n\nCJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which)\n{\n    if (which < 0)\n    {\n        return NULL;\n    }\n\n    return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which));\n}\n\nCJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which)\n{\n    cJSON_Delete(cJSON_DetachItemFromArray(array, which));\n}\n\nCJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string)\n{\n    cJSON *to_detach = cJSON_GetObjectItem(object, string);\n\n    return cJSON_DetachItemViaPointer(object, to_detach);\n}\n\nCJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string)\n{\n    cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string);\n\n    return cJSON_DetachItemViaPointer(object, to_detach);\n}\n\nCJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string)\n{\n    cJSON_Delete(cJSON_DetachItemFromObject(object, string));\n}\n\nCJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string)\n{\n    cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string));\n}\n\n/* Replace array/object items with new ones. */\nCJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)\n{\n    cJSON *after_inserted = NULL;\n\n    if (which < 0)\n    {\n        return;\n    }\n\n    after_inserted = get_array_item(array, (size_t)which);\n    if (after_inserted == NULL)\n    {\n        cJSON_AddItemToArray(array, newitem);\n        return;\n    }\n\n    newitem->next = after_inserted;\n    newitem->prev = after_inserted->prev;\n    after_inserted->prev = newitem;\n    if (after_inserted == array->child)\n    {\n        array->child = newitem;\n    }\n    else\n    {\n        newitem->prev->next = newitem;\n    }\n}\n\nCJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement)\n{\n    if ((parent == NULL) || (replacement == NULL) || (item == NULL))\n    {\n        return false;\n    }\n\n    if (replacement == item)\n    {\n        return true;\n    }\n\n    replacement->next = item->next;\n    replacement->prev = item->prev;\n\n    if (replacement->next != NULL)\n    {\n        replacement->next->prev = replacement;\n    }\n    if (replacement->prev != NULL)\n    {\n        replacement->prev->next = replacement;\n    }\n    if (parent->child == item)\n    {\n        parent->child = replacement;\n    }\n\n    item->next = NULL;\n    item->prev = NULL;\n    cJSON_Delete(item);\n\n    return true;\n}\n\nCJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)\n{\n    if (which < 0)\n    {\n        return;\n    }\n\n    cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem);\n}\n\nstatic cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive)\n{\n    if ((replacement == NULL) || (string == NULL))\n    {\n        return false;\n    }\n\n    /* replace the name in the replacement */\n    if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL))\n    {\n        cJSON_free(replacement->string);\n    }\n    replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);\n    replacement->type &= ~cJSON_StringIsConst;\n\n    cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement);\n\n    return true;\n}\n\nCJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)\n{\n    replace_item_in_object(object, string, newitem, false);\n}\n\nCJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem)\n{\n    replace_item_in_object(object, string, newitem, true);\n}\n\n/* Create basic types: */\nCJSON_PUBLIC(cJSON *) cJSON_CreateNull(void)\n{\n    cJSON *item = cJSON_New_Item(&global_hooks);\n    if(item)\n    {\n        item->type = cJSON_NULL;\n    }\n\n    return item;\n}\n\nCJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void)\n{\n    cJSON *item = cJSON_New_Item(&global_hooks);\n    if(item)\n    {\n        item->type = cJSON_True;\n    }\n\n    return item;\n}\n\nCJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void)\n{\n    cJSON *item = cJSON_New_Item(&global_hooks);\n    if(item)\n    {\n        item->type = cJSON_False;\n    }\n\n    return item;\n}\n\nCJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b)\n{\n    cJSON *item = cJSON_New_Item(&global_hooks);\n    if(item)\n    {\n        item->type = b ? cJSON_True : cJSON_False;\n    }\n\n    return item;\n}\n\nCJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)\n{\n    cJSON *item = cJSON_New_Item(&global_hooks);\n    if(item)\n    {\n        item->type = cJSON_Number;\n        item->valuedouble = num;\n\n        /* use saturation in case of overflow */\n        if (num >= INT_MAX)\n        {\n            item->valueint = INT_MAX;\n        }\n        else if (num <= INT_MIN)\n        {\n            item->valueint = INT_MIN;\n        }\n        else\n        {\n            item->valueint = (int)num;\n        }\n    }\n\n    return item;\n}\n\nCJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string)\n{\n    cJSON *item = cJSON_New_Item(&global_hooks);\n    if(item)\n    {\n        item->type = cJSON_String;\n        item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);\n        if(!item->valuestring)\n        {\n            cJSON_Delete(item);\n            return NULL;\n        }\n    }\n\n    return item;\n}\n\nCJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw)\n{\n    cJSON *item = cJSON_New_Item(&global_hooks);\n    if(item)\n    {\n        item->type = cJSON_Raw;\n        item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks);\n        if(!item->valuestring)\n        {\n            cJSON_Delete(item);\n            return NULL;\n        }\n    }\n\n    return item;\n}\n\nCJSON_PUBLIC(cJSON *) cJSON_CreateArray(void)\n{\n    cJSON *item = cJSON_New_Item(&global_hooks);\n    if(item)\n    {\n        item->type=cJSON_Array;\n    }\n\n    return item;\n}\n\nCJSON_PUBLIC(cJSON *) cJSON_CreateObject(void)\n{\n    cJSON *item = cJSON_New_Item(&global_hooks);\n    if (item)\n    {\n        item->type = cJSON_Object;\n    }\n\n    return item;\n}\n\n/* Create Arrays: */\nCJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count)\n{\n    size_t i = 0;\n    cJSON *n = NULL;\n    cJSON *p = NULL;\n    cJSON *a = NULL;\n\n    if ((count < 0) || (numbers == NULL))\n    {\n        return NULL;\n    }\n\n    a = cJSON_CreateArray();\n    for(i = 0; a && (i < (size_t)count); i++)\n    {\n        n = cJSON_CreateNumber(numbers[i]);\n        if (!n)\n        {\n            cJSON_Delete(a);\n            return NULL;\n        }\n        if(!i)\n        {\n            a->child = n;\n        }\n        else\n        {\n            suffix_object(p, n);\n        }\n        p = n;\n    }\n\n    return a;\n}\n\nCJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count)\n{\n    size_t i = 0;\n    cJSON *n = NULL;\n    cJSON *p = NULL;\n    cJSON *a = NULL;\n\n    if ((count < 0) || (numbers == NULL))\n    {\n        return NULL;\n    }\n\n    a = cJSON_CreateArray();\n\n    for(i = 0; a && (i < (size_t)count); i++)\n    {\n        n = cJSON_CreateNumber((double)numbers[i]);\n        if(!n)\n        {\n            cJSON_Delete(a);\n            return NULL;\n        }\n        if(!i)\n        {\n            a->child = n;\n        }\n        else\n        {\n            suffix_object(p, n);\n        }\n        p = n;\n    }\n\n    return a;\n}\n\nCJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count)\n{\n    size_t i = 0;\n    cJSON *n = NULL;\n    cJSON *p = NULL;\n    cJSON *a = NULL;\n\n    if ((count < 0) || (numbers == NULL))\n    {\n        return NULL;\n    }\n\n    a = cJSON_CreateArray();\n\n    for(i = 0;a && (i < (size_t)count); i++)\n    {\n        n = cJSON_CreateNumber(numbers[i]);\n        if(!n)\n        {\n            cJSON_Delete(a);\n            return NULL;\n        }\n        if(!i)\n        {\n            a->child = n;\n        }\n        else\n        {\n            suffix_object(p, n);\n        }\n        p = n;\n    }\n\n    return a;\n}\n\nCJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count)\n{\n    size_t i = 0;\n    cJSON *n = NULL;\n    cJSON *p = NULL;\n    cJSON *a = NULL;\n\n    if ((count < 0) || (strings == NULL))\n    {\n        return NULL;\n    }\n\n    a = cJSON_CreateArray();\n\n    for (i = 0; a && (i < (size_t)count); i++)\n    {\n        n = cJSON_CreateString(strings[i]);\n        if(!n)\n        {\n            cJSON_Delete(a);\n            return NULL;\n        }\n        if(!i)\n        {\n            a->child = n;\n        }\n        else\n        {\n            suffix_object(p,n);\n        }\n        p = n;\n    }\n\n    return a;\n}\n\n/* Duplication */\nCJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)\n{\n    cJSON *newitem = NULL;\n    cJSON *child = NULL;\n    cJSON *next = NULL;\n    cJSON *newchild = NULL;\n\n    /* Bail on bad ptr */\n    if (!item)\n    {\n        goto fail;\n    }\n    /* Create new item */\n    newitem = cJSON_New_Item(&global_hooks);\n    if (!newitem)\n    {\n        goto fail;\n    }\n    /* Copy over all vars */\n    newitem->type = item->type & (~cJSON_IsReference);\n    newitem->valueint = item->valueint;\n    newitem->valuedouble = item->valuedouble;\n    if (item->valuestring)\n    {\n        newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks);\n        if (!newitem->valuestring)\n        {\n            goto fail;\n        }\n    }\n    if (item->string)\n    {\n        newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks);\n        if (!newitem->string)\n        {\n            goto fail;\n        }\n    }\n    /* If non-recursive, then we're done! */\n    if (!recurse)\n    {\n        return newitem;\n    }\n    /* Walk the ->next chain for the child. */\n    child = item->child;\n    while (child != NULL)\n    {\n        newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */\n        if (!newchild)\n        {\n            goto fail;\n        }\n        if (next != NULL)\n        {\n            /* If newitem->child already set, then crosswire ->prev and ->next and move on */\n            next->next = newchild;\n            newchild->prev = next;\n            next = newchild;\n        }\n        else\n        {\n            /* Set newitem->child and move to it */\n            newitem->child = newchild;\n            next = newchild;\n        }\n        child = child->next;\n    }\n\n    return newitem;\n\nfail:\n    if (newitem != NULL)\n    {\n        cJSON_Delete(newitem);\n    }\n\n    return NULL;\n}\n\nCJSON_PUBLIC(void) cJSON_Minify(char *json)\n{\n    unsigned char *into = (unsigned char*)json;\n\n    if (json == NULL)\n    {\n        return;\n    }\n\n    while (*json)\n    {\n        if (*json == ' ')\n        {\n            json++;\n        }\n        else if (*json == '\\t')\n        {\n            /* Whitespace characters. */\n            json++;\n        }\n        else if (*json == '\\r')\n        {\n            json++;\n        }\n        else if (*json=='\\n')\n        {\n            json++;\n        }\n        else if ((*json == '/') && (json[1] == '/'))\n        {\n            /* double-slash comments, to end of line. */\n            while (*json && (*json != '\\n'))\n            {\n                json++;\n            }\n        }\n        else if ((*json == '/') && (json[1] == '*'))\n        {\n            /* multiline comments. */\n            while (*json && !((*json == '*') && (json[1] == '/')))\n            {\n                json++;\n            }\n            json += 2;\n        }\n        else if (*json == '\\\"')\n        {\n            /* string literals, which are \\\" sensitive. */\n            *into++ = (unsigned char)*json++;\n            while (*json && (*json != '\\\"'))\n            {\n                if (*json == '\\\\')\n                {\n                    *into++ = (unsigned char)*json++;\n                }\n                *into++ = (unsigned char)*json++;\n            }\n            *into++ = (unsigned char)*json++;\n        }\n        else\n        {\n            /* All other characters. */\n            *into++ = (unsigned char)*json++;\n        }\n    }\n\n    /* and null-terminate. */\n    *into = '\\0';\n}\n\nCJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item)\n{\n    if (item == NULL)\n    {\n        return false;\n    }\n\n    return (item->type & 0xFF) == cJSON_Invalid;\n}\n\nCJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item)\n{\n    if (item == NULL)\n    {\n        return false;\n    }\n\n    return (item->type & 0xFF) == cJSON_False;\n}\n\nCJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item)\n{\n    if (item == NULL)\n    {\n        return false;\n    }\n\n    return (item->type & 0xff) == cJSON_True;\n}\n\n\nCJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item)\n{\n    if (item == NULL)\n    {\n        return false;\n    }\n\n    return (item->type & (cJSON_True | cJSON_False)) != 0;\n}\nCJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item)\n{\n    if (item == NULL)\n    {\n        return false;\n    }\n\n    return (item->type & 0xFF) == cJSON_NULL;\n}\n\nCJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item)\n{\n    if (item == NULL)\n    {\n        return false;\n    }\n\n    return (item->type & 0xFF) == cJSON_Number;\n}\n\nCJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item)\n{\n    if (item == NULL)\n    {\n        return false;\n    }\n\n    return (item->type & 0xFF) == cJSON_String;\n}\n\nCJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item)\n{\n    if (item == NULL)\n    {\n        return false;\n    }\n\n    return (item->type & 0xFF) == cJSON_Array;\n}\n\nCJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item)\n{\n    if (item == NULL)\n    {\n        return false;\n    }\n\n    return (item->type & 0xFF) == cJSON_Object;\n}\n\nCJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item)\n{\n    if (item == NULL)\n    {\n        return false;\n    }\n\n    return (item->type & 0xFF) == cJSON_Raw;\n}\n\nCJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive)\n{\n    if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a))\n    {\n        return false;\n    }\n\n    /* check if type is valid */\n    switch (a->type & 0xFF)\n    {\n        case cJSON_False:\n        case cJSON_True:\n        case cJSON_NULL:\n        case cJSON_Number:\n        case cJSON_String:\n        case cJSON_Raw:\n        case cJSON_Array:\n        case cJSON_Object:\n            break;\n\n        default:\n            return false;\n    }\n\n    /* identical objects are equal */\n    if (a == b)\n    {\n        return true;\n    }\n\n    switch (a->type & 0xFF)\n    {\n        /* in these cases and equal type is enough */\n        case cJSON_False:\n        case cJSON_True:\n        case cJSON_NULL:\n            return true;\n\n        case cJSON_Number:\n            if (a->valuedouble == b->valuedouble)\n            {\n                return true;\n            }\n            return false;\n\n        case cJSON_String:\n        case cJSON_Raw:\n            if ((a->valuestring == NULL) || (b->valuestring == NULL))\n            {\n                return false;\n            }\n            if (strcmp(a->valuestring, b->valuestring) == 0)\n            {\n                return true;\n            }\n\n            return false;\n\n        case cJSON_Array:\n        {\n            cJSON *a_element = a->child;\n            cJSON *b_element = b->child;\n\n            for (; (a_element != NULL) && (b_element != NULL);)\n            {\n                if (!cJSON_Compare(a_element, b_element, case_sensitive))\n                {\n                    return false;\n                }\n\n                a_element = a_element->next;\n                b_element = b_element->next;\n            }\n\n            /* one of the arrays is longer than the other */\n            if (a_element != b_element) {\n                return false;\n            }\n\n            return true;\n        }\n\n        case cJSON_Object:\n        {\n            cJSON *a_element = NULL;\n            cJSON *b_element = NULL;\n            cJSON_ArrayForEach(a_element, a)\n            {\n                /* TODO This has O(n^2) runtime, which is horrible! */\n                b_element = get_object_item(b, a_element->string, case_sensitive);\n                if (b_element == NULL)\n                {\n                    return false;\n                }\n\n                if (!cJSON_Compare(a_element, b_element, case_sensitive))\n                {\n                    return false;\n                }\n            }\n\n            /* doing this twice, once on a and b to prevent true comparison if a subset of b\n             * TODO: Do this the proper way, this is just a fix for now */\n            cJSON_ArrayForEach(b_element, b)\n            {\n                a_element = get_object_item(a, b_element->string, case_sensitive);\n                if (a_element == NULL)\n                {\n                    return false;\n                }\n\n                if (!cJSON_Compare(b_element, a_element, case_sensitive))\n                {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n        default:\n            return false;\n    }\n}\n\nCJSON_PUBLIC(void *) cJSON_malloc(size_t size)\n{\n    return global_hooks.allocate(size);\n}\n\nCJSON_PUBLIC(void) cJSON_free(void *object)\n{\n    global_hooks.deallocate(object);\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavformat/cJSON.h",
    "content": "/*\n  Copyright (c) 2009-2017 Dave Gamble and cJSON contributors\n\n  Permission is hereby granted, free of charge, to any person obtaining a copy\n  of this software and associated documentation files (the \"Software\"), to deal\n  in the Software without restriction, including without limitation the rights\n  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  copies of the Software, and to permit persons to whom the Software is\n  furnished to do so, subject to the following conditions:\n\n  The above copyright notice and this permission notice shall be included in\n  all copies or substantial portions of the Software.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  THE SOFTWARE.\n*/\n\n#ifndef cJSON__h\n#define cJSON__h\n\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif\n\n/* project version */\n#define CJSON_VERSION_MAJOR 1\n#define CJSON_VERSION_MINOR 6\n#define CJSON_VERSION_PATCH 0\n\n#include <stddef.h>\n\n/* cJSON Types: */\n#define cJSON_Invalid (0)\n#define cJSON_False  (1 << 0)\n#define cJSON_True   (1 << 1)\n#define cJSON_NULL   (1 << 2)\n#define cJSON_Number (1 << 3)\n#define cJSON_String (1 << 4)\n#define cJSON_Array  (1 << 5)\n#define cJSON_Object (1 << 6)\n#define cJSON_Raw    (1 << 7) /* raw json */\n\n#define cJSON_IsReference 256\n#define cJSON_StringIsConst 512\n\n/* The cJSON structure: */\ntypedef struct cJSON\n{\n    /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */\n    struct cJSON *next;\n    struct cJSON *prev;\n    /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */\n    struct cJSON *child;\n\n    /* The type of the item, as above. */\n    int type;\n\n    /* The item's string, if type==cJSON_String  and type == cJSON_Raw */\n    char *valuestring;\n    /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */\n    int valueint;\n    /* The item's number, if type==cJSON_Number */\n    double valuedouble;\n\n    /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */\n    char *string;\n} cJSON;\n\ntypedef struct cJSON_Hooks\n{\n      void *(*malloc_fn)(size_t sz);\n      void (*free_fn)(void *ptr);\n} cJSON_Hooks;\n\ntypedef int cJSON_bool;\n\n#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))\n#define __WINDOWS__\n#endif\n#ifdef __WINDOWS__\n\n/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention.  For windows you have 2 define options:\n\nCJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols\nCJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)\nCJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol\n\nFor *nix builds that support visibility attribute, you can define similar behavior by\n\nsetting default visibility to hidden by adding\n-fvisibility=hidden (for gcc)\nor\n-xldscope=hidden (for sun cc)\nto CFLAGS\n\nthen using the CJSON_API_VISIBILITY flag to \"export\" the same symbols the way CJSON_EXPORT_SYMBOLS does\n\n*/\n\n/* export symbols by default, this is necessary for copy pasting the C and header file */\n#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)\n#define CJSON_EXPORT_SYMBOLS\n#endif\n\n#if defined(CJSON_HIDE_SYMBOLS)\n#define CJSON_PUBLIC(type)   type __stdcall\n#elif defined(CJSON_EXPORT_SYMBOLS)\n#define CJSON_PUBLIC(type)   __declspec(dllexport) type __stdcall\n#elif defined(CJSON_IMPORT_SYMBOLS)\n#define CJSON_PUBLIC(type)   __declspec(dllimport) type __stdcall\n#endif\n#else /* !WIN32 */\n#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)\n#define CJSON_PUBLIC(type)   __attribute__((visibility(\"default\"))) type\n#else\n#define CJSON_PUBLIC(type) type\n#endif\n#endif\n\n/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.\n * This is to prevent stack overflows. */\n#ifndef CJSON_NESTING_LIMIT\n#define CJSON_NESTING_LIMIT 1000\n#endif\n\n/* returns the version of cJSON as a string */\nCJSON_PUBLIC(const char*) cJSON_Version(void);\n\n/* Supply malloc, realloc and free functions to cJSON */\nCJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);\n\n/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */\n/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */\nCJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);\n/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */\n/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */\nCJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);\n\n/* Render a cJSON entity to text for transfer/storage. */\nCJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);\n/* Render a cJSON entity to text for transfer/storage without any formatting. */\nCJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);\n/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */\nCJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);\n/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */\n/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */\nCJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);\n/* Delete a cJSON entity and all subentities. */\nCJSON_PUBLIC(void) cJSON_Delete(cJSON *c);\n\n/* Returns the number of items in an array (or object). */\nCJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);\n/* Retrieve item number \"item\" from array \"array\". Returns NULL if unsuccessful. */\nCJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);\n/* Get item \"string\" from object. Case insensitive. */\nCJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);\nCJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);\nCJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);\n/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */\nCJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);\n\n/* These functions check the type of an item */\nCJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);\nCJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);\nCJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);\nCJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);\nCJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);\nCJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);\nCJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);\nCJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);\nCJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);\nCJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);\n\n/* These calls create a cJSON item of the appropriate type. */\nCJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);\nCJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);\nCJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);\nCJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);\nCJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);\nCJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);\n/* raw json */\nCJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);\nCJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);\nCJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);\n\n/* These utilities create an Array of count items. */\nCJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);\nCJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);\nCJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);\nCJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count);\n\n/* Append item to the specified array/object. */\nCJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item);\nCJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);\n/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.\n * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before\n * writing to `item->string` */\nCJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);\n/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */\nCJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);\nCJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);\n\n/* Remove/Detatch items from Arrays/Objects. */\nCJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);\nCJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);\nCJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);\nCJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);\nCJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);\nCJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);\nCJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);\n\n/* Update array items. */\nCJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */\nCJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);\nCJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);\nCJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);\nCJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);\n\n/* Duplicate a cJSON item */\nCJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);\n/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will\nneed to be released. With recurse!=0, it will duplicate any children connected to the item.\nThe item->next and ->prev pointers are always zero on return from Duplicate. */\n/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.\n * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */\nCJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);\n\n\nCJSON_PUBLIC(void) cJSON_Minify(char *json);\n\n/* Macros for creating things quickly. */\n#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())\n#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())\n#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())\n#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))\n#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))\n#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))\n#define cJSON_AddRawToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateRaw(s))\n\n/* When assigning an integer value, it needs to be propagated to valuedouble too. */\n#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))\n/* helper for the cJSON_SetNumberValue macro */\nCJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);\n#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))\n\n/* Macro for iterating over an array or object */\n#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)\n\n/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */\nCJSON_PUBLIC(void *) cJSON_malloc(size_t size);\nCJSON_PUBLIC(void) cJSON_free(void *object);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavformat/ijkasync.c",
    "content": "/*\n * Input async protocol.\n * Copyright (c) 2015 Bilibili\n * Copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of FFmpeg.\n *\n * FFmpeg is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * FFmpeg is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n *\n * Based on libavformat/cache.c by Michael Niedermayer\n */\n\n /**\n * @TODO\n *      support timeout\n *      support work with concatdec, hls\n */\n\n#include \"libavutil/avassert.h\"\n#include \"libavutil/avstring.h\"\n#include \"libavutil/error.h\"\n#include \"libavutil/fifo.h\"\n#include \"libavutil/log.h\"\n#include \"libavutil/opt.h\"\n#include \"libavutil/thread.h\"\n#include \"libavutil/time.h\"\n#include \"libavformat/url.h\"\n#include <stdint.h>\n\n#include \"libavutil/application.h\"\n\n#if HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n\n#define SHORT_SEEK_THRESHOLD    (256 * 1024)\n\ntypedef struct RingBuffer\n{\n    AVFifoBuffer *fifo;\n    int           read_back_capacity;\n\n    int           read_pos;\n} RingBuffer;\n\ntypedef struct Context {\n    AVClass        *class;\n    URLContext     *inner;\n\n    int             seek_request;\n    int64_t         seek_pos;\n    int             seek_whence;\n    int             seek_completed;\n    int64_t         seek_ret;\n\n    int             inner_io_error;\n    int             io_error;\n    int             io_eof_reached;\n\n    int64_t         logical_pos;\n    int64_t         logical_size;\n    RingBuffer      ring;\n\n    pthread_cond_t  cond_wakeup_main;\n    pthread_cond_t  cond_wakeup_background;\n    pthread_mutex_t mutex;\n    pthread_t       async_buffer_thread;\n\n    int             abort_request;\n    AVIOInterruptCB interrupt_callback;\n\n    /* options */\n    int64_t         forwards_capacity;\n    int64_t         backwards_capacity;\n    char *          app_ctx_intptr;\n    AVApplicationContext *app_ctx;\n} Context;\n\nstatic int ring_init(RingBuffer *ring, int64_t capacity, int64_t read_back_capacity)\n{\n    memset(ring, 0, sizeof(RingBuffer));\n    ring->fifo = av_fifo_alloc((unsigned int)(capacity + read_back_capacity));\n    if (!ring->fifo)\n        return AVERROR(ENOMEM);\n\n    ring->read_back_capacity = (int)read_back_capacity;\n    return 0;\n}\n\nstatic void ring_destroy(RingBuffer *ring)\n{\n    av_fifo_freep(&ring->fifo);\n}\n\nstatic void ring_reset(RingBuffer *ring)\n{\n    av_fifo_reset(ring->fifo);\n    ring->read_pos = 0;\n}\n\nstatic int ring_size(RingBuffer *ring)\n{\n    return av_fifo_size(ring->fifo) - ring->read_pos;\n}\n\nstatic int ring_space(RingBuffer *ring)\n{\n    return av_fifo_space(ring->fifo);\n}\n\nstatic int ring_generic_read(RingBuffer *ring, void *dest, int buf_size, void (*func)(void*, void*, int))\n{\n    int ret;\n\n    av_assert2(buf_size <= ring_size(ring));\n    ret = av_fifo_generic_peek_at(ring->fifo, dest, ring->read_pos, buf_size, func);\n    ring->read_pos += buf_size;\n\n    if (ring->read_pos > ring->read_back_capacity) {\n        av_fifo_drain(ring->fifo, ring->read_pos - ring->read_back_capacity);\n        ring->read_pos = ring->read_back_capacity;\n    }\n\n    return ret;\n}\n\nstatic int ring_generic_write(RingBuffer *ring, void *src, int size, int (*func)(void*, void*, int))\n{\n    av_assert2(size <= ring_space(ring));\n    return av_fifo_generic_write(ring->fifo, src, size, func);\n}\n\nstatic int ring_size_of_read_back(RingBuffer *ring)\n{\n    return ring->read_pos;\n}\n\nstatic int ring_drain(RingBuffer *ring, int offset)\n{\n    av_assert2(offset >= -ring_size_of_read_back(ring));\n    av_assert2(offset <= -ring_size(ring));\n    ring->read_pos += offset;\n    return 0;\n}\n\nstatic int async_check_interrupt(void *arg)\n{\n    URLContext *h   = arg;\n    Context    *c   = h->priv_data;\n\n    if (c->abort_request)\n        return 1;\n\n    if (ff_check_interrupt(&c->interrupt_callback))\n        c->abort_request = 1;\n\n    return c->abort_request;\n}\n\nstatic int wrapped_url_read(void *src, void *dst, int size)\n{\n    URLContext *h   = src;\n    Context    *c   = h->priv_data;\n    int         ret;\n\n    ret = ffurl_read(c->inner, dst, size);\n    c->inner_io_error = ret < 0 ? ret : 0;\n\n    return ret;\n}\n\nstatic void call_inject_statistic(URLContext *h)\n{\n    Context *c = h->priv_data;\n\n    if (c->app_ctx) {\n        AVAppAsyncStatistic statistic = {0};\n        statistic.size = sizeof(statistic);\n        statistic.buf_forwards  = ring_size(&c->ring);\n        statistic.buf_backwards = ring_size_of_read_back(&c->ring);\n        statistic.buf_capacity  = c->forwards_capacity + c->backwards_capacity;\n        av_application_on_async_statistic(c->app_ctx, &statistic);\n    }\n}\n\nstatic void call_inject_async_fill_speed(URLContext *h, int is_full_speed, int64_t bytes, int64_t elapsed_micro)\n{\n    Context *c = h->priv_data;\n    int64_t elapsed_milli = elapsed_micro / 1000;\n\n    if (c->app_ctx && bytes > 0 && elapsed_milli > 0) {\n        AVAppAsyncReadSpeed speed = {0};\n        speed.size = sizeof(speed);\n        speed.is_full_speed = is_full_speed;\n        speed.io_bytes      = bytes;\n        speed.elapsed_milli = elapsed_milli;\n        av_application_on_async_read_speed(c->app_ctx, &speed);\n    }\n}\n\nstatic void *async_buffer_task(void *arg)\n{\n    URLContext   *h    = arg;\n    Context      *c    = h->priv_data;\n    RingBuffer   *ring = &c->ring;\n    int           ret  = 0;\n    int64_t       seek_ret;\n    int           is_full_speed = 1;\n    int64_t       count_bytes = 0;\n    int64_t       count_start_time_micro = av_gettime_relative();\n\n    while (1) {\n        int fifo_space, to_copy;\n\n        pthread_mutex_lock(&c->mutex);\n        if (async_check_interrupt(h)) {\n            c->io_eof_reached = 1;\n            c->io_error       = AVERROR_EXIT;\n            pthread_cond_signal(&c->cond_wakeup_main);\n            pthread_mutex_unlock(&c->mutex);\n            break;\n        }\n\n        if (c->seek_request) {\n            seek_ret = ffurl_seek(c->inner, c->seek_pos, c->seek_whence);\n            if (seek_ret < 0) {\n                c->io_eof_reached = 1;\n                c->io_error       = (int)seek_ret;\n            } else {\n                c->io_eof_reached = 0;\n                c->io_error       = 0;\n            }\n\n            c->seek_completed = 1;\n            c->seek_ret       = seek_ret;\n            c->seek_request   = 0;\n\n            ring_reset(ring);\n\n            pthread_cond_signal(&c->cond_wakeup_main);\n            pthread_mutex_unlock(&c->mutex);\n\n            is_full_speed = 0;\n            continue;\n        }\n\n        fifo_space = ring_space(ring);\n        if (c->io_eof_reached || fifo_space <= 0) {\n            pthread_cond_signal(&c->cond_wakeup_main);\n            pthread_cond_wait(&c->cond_wakeup_background, &c->mutex);\n            pthread_mutex_unlock(&c->mutex);\n            is_full_speed = 0;\n            continue;\n        }\n        pthread_mutex_unlock(&c->mutex);\n\n        to_copy = FFMIN(4096, fifo_space);\n        ret = ring_generic_write(ring, (void *)h, to_copy, (void *)wrapped_url_read);\n        if (ret > 0) {\n            count_bytes += ret;\n            if (count_bytes > FFMIN((1 * 1024 * 1024), c->forwards_capacity)) {\n                int64_t now = av_gettime_relative();\n                call_inject_async_fill_speed(h, is_full_speed, count_bytes, now - count_start_time_micro);\n                is_full_speed = 1;\n                count_bytes = 0;\n                count_start_time_micro = now;\n            }\n        }\n\n        pthread_mutex_lock(&c->mutex);\n        if (ret <= 0) {\n            c->io_eof_reached = 1;\n            if (c->inner_io_error < 0)\n                c->io_error = c->inner_io_error;\n        }\n\n        pthread_cond_signal(&c->cond_wakeup_main);\n        pthread_mutex_unlock(&c->mutex);\n\n        call_inject_statistic(h);\n    }\n\n    return NULL;\n}\n\nstatic int async_open(URLContext *h, const char *arg, int flags, AVDictionary **options)\n{\n    Context         *c = h->priv_data;\n    int              ret;\n    AVIOInterruptCB  interrupt_callback = {.callback = async_check_interrupt, .opaque = h};\n\n    av_strstart(arg, \"async:\", &arg);\n\n    ret = ring_init(&c->ring, c->forwards_capacity, c->backwards_capacity);\n    if (ret < 0)\n        goto fifo_fail;\n\n    if (c->app_ctx_intptr) {\n        c->app_ctx = (AVApplicationContext *)av_dict_strtoptr(c->app_ctx_intptr);\n        av_dict_set_intptr(options, \"ijkapplication\", (uintptr_t )c->app_ctx, 0);\n    }\n    /* wrap interrupt callback */\n    c->interrupt_callback = h->interrupt_callback;\n    ret = ffurl_open_whitelist(&c->inner, arg, flags, &interrupt_callback, options, h->protocol_whitelist, h->protocol_blacklist, h);\n    if (ret != 0) {\n        av_log(h, AV_LOG_ERROR, \"ffurl_open_whitelist failed : %s, %s\\n\", av_err2str(ret), arg);\n        goto url_fail;\n    }\n\n    c->logical_size = ffurl_size(c->inner);\n    h->is_streamed  = c->inner->is_streamed;\n\n    ret = pthread_mutex_init(&c->mutex, NULL);\n    if (ret != 0) {\n        av_log(h, AV_LOG_ERROR, \"pthread_mutex_init failed : %s\\n\", av_err2str(ret));\n        goto mutex_fail;\n    }\n\n    ret = pthread_cond_init(&c->cond_wakeup_main, NULL);\n    if (ret != 0) {\n        av_log(h, AV_LOG_ERROR, \"pthread_cond_init failed : %s\\n\", av_err2str(ret));\n        goto cond_wakeup_main_fail;\n    }\n\n    ret = pthread_cond_init(&c->cond_wakeup_background, NULL);\n    if (ret != 0) {\n        av_log(h, AV_LOG_ERROR, \"pthread_cond_init failed : %s\\n\", av_err2str(ret));\n        goto cond_wakeup_background_fail;\n    }\n\n    ret = pthread_create(&c->async_buffer_thread, NULL, async_buffer_task, h);\n    if (ret) {\n        av_log(h, AV_LOG_ERROR, \"pthread_create failed : %s\\n\", av_err2str(ret));\n        goto thread_fail;\n    }\n\n    return 0;\n\nthread_fail:\n    pthread_cond_destroy(&c->cond_wakeup_background);\ncond_wakeup_background_fail:\n    pthread_cond_destroy(&c->cond_wakeup_main);\ncond_wakeup_main_fail:\n    pthread_mutex_destroy(&c->mutex);\nmutex_fail:\n    ffurl_close(c->inner);\nurl_fail:\n    ring_destroy(&c->ring);\nfifo_fail:\n    return ret;\n}\n\nstatic int async_close(URLContext *h)\n{\n    Context *c = h->priv_data;\n    int      ret;\n\n    pthread_mutex_lock(&c->mutex);\n    c->abort_request = 1;\n    pthread_cond_signal(&c->cond_wakeup_background);\n    pthread_mutex_unlock(&c->mutex);\n\n    ret = pthread_join(c->async_buffer_thread, NULL);\n    if (ret != 0)\n        av_log(h, AV_LOG_ERROR, \"pthread_join(): %s\\n\", av_err2str(ret));\n\n    pthread_cond_destroy(&c->cond_wakeup_background);\n    pthread_cond_destroy(&c->cond_wakeup_main);\n    pthread_mutex_destroy(&c->mutex);\n    ffurl_close(c->inner);\n    ring_destroy(&c->ring);\n\n    return 0;\n}\n\nstatic int async_read_internal(URLContext *h, void *dest, int size, int read_complete,\n                               void (*func)(void*, void*, int))\n{\n    Context      *c       = h->priv_data;\n    RingBuffer   *ring    = &c->ring;\n    int           to_read = size;\n    int           ret     = 0;\n\n    pthread_mutex_lock(&c->mutex);\n\n    while (to_read > 0) {\n        int fifo_size, to_copy;\n        if (async_check_interrupt(h)) {\n            ret = AVERROR_EXIT;\n            break;\n        }\n        fifo_size = ring_size(ring);\n        to_copy   = FFMIN(to_read, fifo_size);\n        if (to_copy > 0) {\n            ring_generic_read(ring, dest, to_copy, func);\n            if (!func)\n                dest = (uint8_t *)dest + to_copy;\n            c->logical_pos += to_copy;\n            to_read        -= to_copy;\n            ret             = size - to_read;\n\n            if (to_read <= 0 || !read_complete)\n                break;\n        } else if (c->io_eof_reached) {\n            if (ret <= 0) {\n                if (c->io_error)\n                    ret = c->io_error;\n                else\n                    ret = AVERROR_EOF;\n            }\n            break;\n        }\n        pthread_cond_signal(&c->cond_wakeup_background);\n        pthread_cond_wait(&c->cond_wakeup_main, &c->mutex);\n    }\n\n    pthread_cond_signal(&c->cond_wakeup_background);\n    pthread_mutex_unlock(&c->mutex);\n\n    call_inject_statistic(h);\n    return ret;\n}\n\nstatic int async_read(URLContext *h, unsigned char *buf, int size)\n{\n    return async_read_internal(h, buf, size, 0, NULL);\n}\n\nstatic void fifo_do_not_copy_func(void* dest, void* src, int size) {\n    // do not copy\n}\n\nstatic int64_t async_seek(URLContext *h, int64_t pos, int whence)\n{\n    Context      *c    = h->priv_data;\n    RingBuffer   *ring = &c->ring;\n    int64_t       ret;\n    int64_t       new_logical_pos;\n    int fifo_size;\n    int fifo_size_of_read_back;\n\n    if (whence == AVSEEK_SIZE) {\n        av_log(h, AV_LOG_TRACE, \"async_seek: AVSEEK_SIZE: %\"PRId64\"\\n\", (int64_t)c->logical_size);\n        return c->logical_size;\n    } else if (whence == SEEK_CUR) {\n        av_log(h, AV_LOG_TRACE, \"async_seek: %\"PRId64\"\\n\", pos);\n        new_logical_pos = pos + c->logical_pos;\n    } else if (whence == SEEK_SET){\n        av_log(h, AV_LOG_TRACE, \"async_seek: %\"PRId64\"\\n\", pos);\n        new_logical_pos = pos;\n    } else {\n        return AVERROR(EINVAL);\n    }\n    if (new_logical_pos < 0)\n        return AVERROR(EINVAL);\n\n    fifo_size = ring_size(ring);\n    fifo_size_of_read_back = ring_size_of_read_back(ring);\n    if (new_logical_pos == c->logical_pos) {\n        /* current position */\n        return c->logical_pos;\n    } else if ((new_logical_pos >= (c->logical_pos - fifo_size_of_read_back)) &&\n               (new_logical_pos < (c->logical_pos + fifo_size + SHORT_SEEK_THRESHOLD))) {\n        int pos_delta = (int)(new_logical_pos - c->logical_pos);\n        /* fast seek */\n        av_log(h, AV_LOG_TRACE, \"async_seek: fask_seek %\"PRId64\" from %d dist:%d/%d\\n\",\n                new_logical_pos, (int)c->logical_pos,\n                (int)(new_logical_pos - c->logical_pos), fifo_size);\n\n        if (pos_delta > 0) {\n            // fast seek forwards\n            async_read_internal(h, NULL, pos_delta, 1, fifo_do_not_copy_func);\n        } else {\n            // fast seek backwards\n            ring_drain(ring, pos_delta);\n            call_inject_statistic(h);\n            c->logical_pos = new_logical_pos;\n        }\n\n        return c->logical_pos;\n    } else if (c->logical_size <= 0) {\n        /* can not seek */\n        return AVERROR(EINVAL);\n    } else if (new_logical_pos > c->logical_size) {\n        /* beyond end */\n        return AVERROR(EINVAL);\n    }\n\n    pthread_mutex_lock(&c->mutex);\n\n    c->seek_request   = 1;\n    c->seek_pos       = new_logical_pos;\n    c->seek_whence    = SEEK_SET;\n    c->seek_completed = 0;\n    c->seek_ret       = 0;\n\n    while (1) {\n        if (async_check_interrupt(h)) {\n            ret = AVERROR_EXIT;\n            break;\n        }\n        if (c->seek_completed) {\n            if (c->seek_ret >= 0)\n                c->logical_pos  = c->seek_ret;\n            ret = c->seek_ret;\n            break;\n        }\n        pthread_cond_signal(&c->cond_wakeup_background);\n        pthread_cond_wait(&c->cond_wakeup_main, &c->mutex);\n    }\n\n    pthread_mutex_unlock(&c->mutex);\n\n    call_inject_statistic(h);\n    return ret;\n}\n\n#define OFFSET(x) offsetof(Context, x)\n#define D AV_OPT_FLAG_DECODING_PARAM\n\nstatic const AVOption options[] = {\n    { \"async-forwards-capacity\",    \"max bytes that may be read forward in background\",\n        OFFSET(forwards_capacity),  AV_OPT_TYPE_INT64, {.i64 = 128 * 1024}, 128 * 1024, 128 * 1024 * 1024, D },\n    { \"async-backwards-capacity\",   \"max bytes that may be seek backward without seeking in inner protocol\",\n        OFFSET(backwards_capacity), AV_OPT_TYPE_INT64, {.i64 = 128 * 1024}, 128 * 1024, 128 * 1024 * 1024, D },\n    { \"ijkapplication\", \"AVApplicationContext\", OFFSET(app_ctx_intptr), AV_OPT_TYPE_STRING, { .str = 0 }, 0, 0, .flags = D },\n    {NULL},\n};\n\n#undef D\n#undef OFFSET\n\nstatic const AVClass async_context_class = {\n    .class_name = \"Async\",\n    .item_name  = av_default_item_name,\n    .option     = options,\n    .version    = LIBAVUTIL_VERSION_INT,\n};\n\nconst URLProtocol ijkimp_ff_async_protocol = {\n    .name                = \"async\",\n    .url_open2           = async_open,\n    .url_read            = async_read,\n    .url_seek            = async_seek,\n    .url_close           = async_close,\n    .priv_data_size      = sizeof(Context),\n    .priv_data_class     = &async_context_class,\n};\n\n#if 0\n\n#define TEST_SEEK_POS    (1536)\n#define TEST_STREAM_SIZE (2048)\n\ntypedef struct TestContext {\n    AVClass        *class;\n    int64_t         logical_pos;\n    int64_t         logical_size;\n\n    /* options */\n    int             opt_read_error;\n} TestContext;\n\nstatic int async_test_open(URLContext *h, const char *arg, int flags, AVDictionary **options)\n{\n    TestContext *c = h->priv_data;\n    c->logical_pos  = 0;\n    c->logical_size = TEST_STREAM_SIZE;\n    return 0;\n}\n\nstatic int async_test_close(URLContext *h)\n{\n    return 0;\n}\n\nstatic int async_test_read(URLContext *h, unsigned char *buf, int size)\n{\n    TestContext *c = h->priv_data;\n    int          i;\n    int          read_len = 0;\n\n    if (c->opt_read_error)\n        return c->opt_read_error;\n\n    if (c->logical_pos >= c->logical_size)\n        return AVERROR_EOF;\n\n    for (i = 0; i < size; ++i) {\n        buf[i] = c->logical_pos & 0xFF;\n\n        c->logical_pos++;\n        read_len++;\n\n        if (c->logical_pos >= c->logical_size)\n            break;\n    }\n\n    return read_len;\n}\n\nstatic int64_t async_test_seek(URLContext *h, int64_t pos, int whence)\n{\n    TestContext *c = h->priv_data;\n    int64_t      new_logical_pos;\n\n    if (whence == AVSEEK_SIZE) {\n        return c->logical_size;\n    } else if (whence == SEEK_CUR) {\n        new_logical_pos = pos + c->logical_pos;\n    } else if (whence == SEEK_SET){\n        new_logical_pos = pos;\n    } else {\n        return AVERROR(EINVAL);\n    }\n    if (new_logical_pos < 0)\n        return AVERROR(EINVAL);\n\n    c->logical_pos = new_logical_pos;\n    return new_logical_pos;\n}\n\n#define OFFSET(x) offsetof(TestContext, x)\n#define D AV_OPT_FLAG_DECODING_PARAM\n\nstatic const AVOption async_test_options[] = {\n    { \"async-test-read-error\",      \"cause read fail\",\n        OFFSET(opt_read_error),     AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, .flags = D },\n    {NULL},\n};\n\n#undef D\n#undef OFFSET\n\nstatic const AVClass async_test_context_class = {\n    .class_name = \"Async-Test\",\n    .item_name  = av_default_item_name,\n    .option     = async_test_options,\n    .version    = LIBAVUTIL_VERSION_INT,\n};\n\nconst URLProtocol ff_async_test_protocol = {\n    .name                = \"async-test\",\n    .url_open2           = async_test_open,\n    .url_read            = async_test_read,\n    .url_seek            = async_test_seek,\n    .url_close           = async_test_close,\n    .priv_data_size      = sizeof(TestContext),\n    .priv_data_class     = &async_test_context_class,\n};\n\nint main(void)\n{\n    URLContext   *h = NULL;\n    int           i;\n    int           ret;\n    int64_t       size;\n    int64_t       pos;\n    int64_t       read_len;\n    unsigned char buf[4096];\n    AVDictionary *opts = NULL;\n\n    ffurl_register_protocol(&ijkimp_ff_async_protocol);\n    ffurl_register_protocol(&ff_async_test_protocol);\n\n    /*\n     * test normal read\n     */\n    ret = ffurl_open(&h, \"async:async-test:\", AVIO_FLAG_READ, NULL, NULL);\n    printf(\"open: %d\\n\", ret);\n\n    size = ffurl_size(h);\n    printf(\"size: %\"PRId64\"\\n\", size);\n\n    pos = ffurl_seek(h, 0, SEEK_CUR);\n    read_len = 0;\n    while (1) {\n        ret = ffurl_read(h, buf, sizeof(buf));\n        if (ret == AVERROR_EOF) {\n            printf(\"read-error: AVERROR_EOF at %\"PRId64\"\\n\", ffurl_seek(h, 0, SEEK_CUR));\n            break;\n        }\n        else if (ret == 0)\n            break;\n        else if (ret < 0) {\n            printf(\"read-error: %d at %\"PRId64\"\\n\", ret, ffurl_seek(h, 0, SEEK_CUR));\n            goto fail;\n        } else {\n            for (i = 0; i < ret; ++i) {\n                if (buf[i] != (pos & 0xFF)) {\n                    printf(\"read-mismatch: actual %d, expecting %d, at %\"PRId64\"\\n\",\n                           (int)buf[i], (int)(pos & 0xFF), pos);\n                    break;\n                }\n                pos++;\n            }\n        }\n\n        read_len += ret;\n    }\n    printf(\"read: %\"PRId64\"\\n\", read_len);\n\n    /*\n     * test normal seek\n     */\n    ret = ffurl_read(h, buf, 1);\n    printf(\"read: %d\\n\", ret);\n\n    pos = ffurl_seek(h, TEST_SEEK_POS, SEEK_SET);\n    printf(\"seek: %\"PRId64\"\\n\", pos);\n\n    read_len = 0;\n    while (1) {\n        ret = ffurl_read(h, buf, sizeof(buf));\n        if (ret == AVERROR_EOF)\n            break;\n        else if (ret == 0)\n            break;\n        else if (ret < 0) {\n            printf(\"read-error: %d at %\"PRId64\"\\n\", ret, ffurl_seek(h, 0, SEEK_CUR));\n            goto fail;\n        } else {\n            for (i = 0; i < ret; ++i) {\n                if (buf[i] != (pos & 0xFF)) {\n                    printf(\"read-mismatch: actual %d, expecting %d, at %\"PRId64\"\\n\",\n                           (int)buf[i], (int)(pos & 0xFF), pos);\n                    break;\n                }\n                pos++;\n            }\n        }\n\n        read_len += ret;\n    }\n    printf(\"read: %\"PRId64\"\\n\", read_len);\n\n    ret = ffurl_read(h, buf, 1);\n    printf(\"read: %d\\n\", ret);\n\n    /*\n     * test read error\n     */\n    ffurl_close(h);\n    av_dict_set_int(&opts, \"async-test-read-error\", -10000, 0);\n    ret = ffurl_open(&h, \"async:async-test:\", AVIO_FLAG_READ, NULL, &opts);\n    printf(\"open: %d\\n\", ret);\n\n    ret = ffurl_read(h, buf, 1);\n    printf(\"read: %d\\n\", ret);\n\nfail:\n    av_dict_free(&opts);\n    ffurl_close(h);\n    return 0;\n}\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavformat/ijkavformat.h",
    "content": "/*\n * ijkavformat.h\n *\n * Copyright (c) 2003 Bilibili\n * Copyright (c) 2003 Fabrice Bellard\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef AVFORMAT_IJKAVFORMAT_H\n#define AVFORMAT_IJKAVFORMAT_H\n\n#define AV_PKT_FLAG_DISCONTINUITY 0x0100\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavformat/ijkio.c",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * Copyright (c) 2016 Raymond Zheng <raymondzheng1412@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include <assert.h>\n#include \"libavformat/avformat.h\"\n#include \"libavformat/url.h\"\n#include \"libavutil/avstring.h\"\n#include \"libavutil/log.h\"\n#include \"libavutil/opt.h\"\n\n#include \"ijkiomanager.h\"\n#include \"ijkplayer/ijkavutil/ijkdict.h\"\n\ntypedef struct Context {\n    AVClass *class;\n    char *io_manager_ctx_intptr;\n} Context;\n\nstatic int ijkio_copy_options(IjkAVDictionary **dst, AVDictionary *src) {\n    AVDictionaryEntry *t = NULL;\n\n    while ((t = av_dict_get(src, \"\", t, AV_DICT_IGNORE_SUFFIX))) {\n        int ret = ijk_av_dict_set(dst, t->key, t->value, 0);\n        if (ret < 0)\n            return ret;\n    }\n\n    return 0;\n}\n\nstatic int ijkio_open(URLContext *h, const char *arg, int flags, AVDictionary **options)\n{\n    Context *c = h->priv_data;\n    int ret = -1;\n\n    if (!c || !c->io_manager_ctx_intptr)\n        return -1;\n\n    IjkIOManagerContext *manager_ctx = (IjkIOManagerContext *)av_dict_strtoptr(c->io_manager_ctx_intptr);\n    manager_ctx->ijkio_interrupt_callback = (IjkAVIOInterruptCB *)&(h->interrupt_callback);\n\n    av_strstart(arg, \"ijkio:\", &arg);\n    IjkAVDictionary *opts = NULL;\n    ijkio_copy_options(&opts, *options);\n\n    manager_ctx->cur_ffmpeg_ctx = c;\n\n    ret = ijkio_manager_io_open(manager_ctx, arg, flags, &opts);\n    ijk_av_dict_free(&opts);\n\n    if (ret != 0) {\n        ijkio_manager_io_close(manager_ctx);\n    }\n\n    return ret;\n}\n\nstatic int ijkio_read(URLContext *h, unsigned char *buf, int size)\n{\n    Context *c = h->priv_data;\n\n    if (!c || !c->io_manager_ctx_intptr)\n        return -1;\n\n    ((IjkIOManagerContext *)(av_dict_strtoptr(c->io_manager_ctx_intptr)))->cur_ffmpeg_ctx  = c;\n    return ijkio_manager_io_read((IjkIOManagerContext *)(av_dict_strtoptr(c->io_manager_ctx_intptr)), buf, size);\n}\n\nstatic int64_t ijkio_seek(URLContext *h, int64_t offset, int whence)\n{\n    Context *c = h->priv_data;\n\n    if (!c || !c->io_manager_ctx_intptr)\n        return -1;\n\n    ((IjkIOManagerContext *)(av_dict_strtoptr(c->io_manager_ctx_intptr)))->cur_ffmpeg_ctx  = c;\n    return ijkio_manager_io_seek((IjkIOManagerContext *)(av_dict_strtoptr(c->io_manager_ctx_intptr)), offset, whence);\n}\n\nstatic int ijkio_close(URLContext *h)\n{\n    Context *c = h->priv_data;\n\n    if (!c || !c->io_manager_ctx_intptr)\n        return -1;\n\n    ((IjkIOManagerContext *)(av_dict_strtoptr(c->io_manager_ctx_intptr)))->cur_ffmpeg_ctx  = c;\n    return ijkio_manager_io_close((IjkIOManagerContext *)(av_dict_strtoptr(c->io_manager_ctx_intptr)));\n}\n\n#define OFFSET(x) offsetof(Context, x)\n#define D AV_OPT_FLAG_DECODING_PARAM\n\nstatic const AVOption options[] = {\n    { \"ijkiomanager\", \"IjkIOManagerContext\", OFFSET(io_manager_ctx_intptr), AV_OPT_TYPE_STRING, { .i64 = 0 }, 0, 0, .flags = D },\n    { NULL }\n};\n\n#undef D\n#undef OFFSET\n\nstatic const AVClass ijkio_context_class = {\n    .class_name = \"IjkIo\",\n    .item_name  = av_default_item_name,\n    .option     = options,\n    .version    = LIBAVUTIL_VERSION_INT,\n};\n\nURLProtocol ijkimp_ff_ijkio_protocol = {\n    .name                = \"ijkio\",\n    .url_open2           = ijkio_open,\n    .url_read            = ijkio_read,\n    .url_seek            = ijkio_seek,\n    .url_close           = ijkio_close,\n    .priv_data_size      = sizeof(Context),\n    .priv_data_class     = &ijkio_context_class,\n};\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavformat/ijkioandroidio.c",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * Copyright (c) 2016 Raymond Zheng <raymondzheng1412@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n#include \"ijkiourl.h\"\n#include \"libavformat/avformat.h\"\n#include \"libavformat/url.h\"\n#include \"libavutil/avstring.h\"\n#include \"libavutil/log.h\"\n#include \"libavutil/opt.h\"\n\n#include \"ijkavformat/ijkavformat.h\"\n#include \"ijkplayer/ijkavutil/opt.h\"\n#include \"ijkplayer/ijkavutil/ijkutils.h\"\n\n#include \"j4a/class/tv/danmaku/ijk/media/player/misc/IAndroidIO.h\"\n#include \"ijksdl/android/ijksdl_android_jni.h\"\n#include <assert.h>\n\ntypedef struct IjkIOAndroidioContext {\n    jobject         ijkio_androidio;\n    jbyteArray      jbuffer;\n    int             jbuffer_capacity;\n    URLContext *inner;\n} IjkIOAndroidioContext;\n\nstatic int ijkio_androidio_open(IjkURLContext *h, const char *url, int flags, IjkAVDictionary **options) {\n    IjkIOAndroidioContext *c= h->priv_data;\n    JNIEnv *env = NULL;\n    jobject ijkio_androidio = NULL;\n    char *final = NULL;\n\n    if (!c)\n        return -1;\n\n    av_strstart(url, \"androidio:\", &url);\n\n    IjkAVDictionaryEntry *t = NULL;\n    t = ijk_av_dict_get(*options, \"androidio-inject-callback\", NULL, IJK_AV_DICT_IGNORE_SUFFIX);\n    if (t) {\n        ijkio_androidio = (jobject) (intptr_t) strtoll(t->value, &final, 10);\n    } else {\n        return -1;\n    }\n\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        av_log(h, AV_LOG_ERROR, \"%s: SDL_JNI_SetupThreadEnv: failed\", __func__);\n        return AVERROR(EINVAL);\n    }\n\n    if (!ijkio_androidio)\n        return AVERROR(EINVAL);\n\n    c->ijkio_androidio = (*env)->NewGlobalRef(env, ijkio_androidio);\n    if (J4A_ExceptionCheck__catchAll(env) || !c->ijkio_androidio) {\n        return AVERROR(ENOMEM);\n    }\n\n    jstring urlString = NULL;\n    urlString = (*env)->NewStringUTF(env, url);\n\n    jint ret = J4AC_IAndroidIO__open(env, c->ijkio_androidio, urlString);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return AVERROR(EINVAL);\n    } else if (ret < 0) {\n        return ret;\n    }\n\n    return 0;\n}\n\nstatic jobject jbuffer_grow(JNIEnv *env, IjkURLContext *h, int new_capacity) {\n    IjkIOAndroidioContext *c = h->priv_data;\n    if (!c)\n        return NULL;\n\n    if (c->jbuffer && c->jbuffer_capacity >= new_capacity)\n        return c->jbuffer;\n\n    new_capacity = FFMAX(new_capacity, c->jbuffer_capacity * 2);\n\n    J4A_DeleteGlobalRef__p(env, &c->jbuffer);\n    c->jbuffer_capacity = 0;\n\n    c->jbuffer = J4A_NewByteArray__asGlobalRef__catchAll(env, new_capacity);\n    if (J4A_ExceptionCheck__catchAll(env) || !c->jbuffer) {\n        c->jbuffer = NULL;\n        return NULL;\n    }\n\n    c->jbuffer_capacity = new_capacity;\n    return c->jbuffer;\n}\n\nstatic int ijkio_androidio_read(IjkURLContext *h, unsigned char *buf, int size) {\n    IjkIOAndroidioContext    *c = h->priv_data;\n    JNIEnv     *env = NULL;\n    jbyteArray  jbuffer = NULL;\n    jint        ret = 0;\n\n    if (!c || !c->ijkio_androidio)\n        return AVERROR(EINVAL);\n\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        av_log(h, AV_LOG_ERROR, \"%s: SDL_JNI_SetupThreadEnv: failed\", __func__);\n        return AVERROR(EINVAL);\n    }\n\n    jbuffer = jbuffer_grow(env, h, size);\n    if (!jbuffer)\n        return AVERROR(ENOMEM);\n\n    ret = J4AC_IAndroidIO__read(env, c->ijkio_androidio, jbuffer, size);\n    if (J4A_ExceptionCheck__catchAll(env))\n        return AVERROR(EIO);\n    else if (ret < 0)\n        return AVERROR_EOF;\n    else if (ret == 0)\n        return AVERROR(EAGAIN);\n\n    (*env)->GetByteArrayRegion(env, jbuffer, 0, ret, (jbyte*)buf);\n    if (J4A_ExceptionCheck__catchAll(env))\n        return AVERROR(EIO);\n\n    return ret;\n}\n\nstatic int64_t ijkio_androidio_seek(IjkURLContext *h, int64_t offset, int whence) {\n    IjkIOAndroidioContext *c = h->priv_data;\n    int64_t  ret;\n    JNIEnv  *env = NULL;\n\n    if (!c || !c->ijkio_androidio)\n        return AVERROR(EINVAL);\n\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        av_log(h, AV_LOG_ERROR, \"%s: SDL_JNI_SetupThreadEnv: failed\", __func__);\n        return AVERROR(EINVAL);\n    }\n\n    ret = J4AC_IAndroidIO__seek(env, c->ijkio_androidio, offset, whence);\n    if (J4A_ExceptionCheck__catchAll(env))\n        return AVERROR(EIO);\n\n    return ret;\n}\n\nstatic int ijkio_androidio_close(IjkURLContext *h) {\n    IjkIOAndroidioContext *c = h->priv_data;\n    JNIEnv *env = NULL;\n\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        av_log(h, AV_LOG_ERROR, \"%s: SDL_JNI_SetupThreadEnv: failed\", __func__);\n        return AVERROR(EINVAL);\n    }\n\n    if (!c || !c->ijkio_androidio)\n        return AVERROR(EINVAL);\n\n    J4A_DeleteGlobalRef__p(env, &c->jbuffer);\n\n    if (c->ijkio_androidio) {\n        J4AC_IAndroidIO__close__catchAll(env, c->ijkio_androidio);\n        J4A_DeleteGlobalRef__p(env, &c->ijkio_androidio);\n    }\n\n    return 0;\n}\n\nIjkURLProtocol ijkio_androidio_protocol = {\n    .name                = \"ijkioandroidio\",\n    .url_open2           = ijkio_androidio_open,\n    .url_read            = ijkio_androidio_read,\n    .url_seek            = ijkio_androidio_seek,\n    .url_close           = ijkio_androidio_close,\n    .priv_data_size      = sizeof(IjkIOAndroidioContext),\n};\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavformat/ijkioapplication.c",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * Copyright (c) 2016 Raymond Zheng <raymondzheng1412@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n#include \"ijkioapplication.h\"\n\n#include <stdlib.h>\n\nint  ijkio_application_alloc(IjkIOApplicationContext **ph, void *opaque) {\n    IjkIOApplicationContext *h = NULL;\n\n    h = calloc(1, sizeof(IjkIOApplicationContext));\n    if (!h)\n        return -1;\n\n    h->opaque = opaque;\n\n    *ph = h;\n    return 0;\n}\n\nint  ijkio_application_open(IjkIOApplicationContext **ph, void *opaque) {\n    int ret = ijkio_application_alloc(ph, opaque);\n    if (ret)\n        return ret;\n\n    return 0;\n}\n\nvoid ijkio_application_close(IjkIOApplicationContext *h) {\n    free(h);\n}\n\nvoid ijkio_application_closep(IjkIOApplicationContext **ph) {\n    if (!ph || !*ph)\n        return;\n\n    ijkio_application_close(*ph);\n    *ph = NULL;\n}\n\nvoid ijkio_application_on_cache_statistic(IjkIOApplicationContext *h, IjkIOAppCacheStatistic *statistic) {\n    if (h && h->func_ijkio_on_app_event)\n        h->func_ijkio_on_app_event(h, IJKIOAPP_EVENT_CACHE_STATISTIC, (void *)statistic, sizeof(IjkIOAppCacheStatistic));\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavformat/ijkioapplication.h",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * Copyright (c) 2016 Raymond Zheng <raymondzheng1412@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKAVFORMAT_IJKIOAPPLICATION_H\n#define IJKAVFORMAT_IJKIOAPPLICATION_H\n\n#include \"ijkplayer/ijkavutil/ijkutils.h\"\n#include \"ijkplayer/ijkavutil/ijkthreadpool.h\"\n\n#include <stdint.h>\n\n#define CACHE_FILE_PATH_MAX_LEN        512\n#define IJKIOAPP_EVENT_CACHE_STATISTIC 0x1003  //IJKIOAppCacheStatistic share with avutil/application.h\n\ntypedef struct IjkIOAppCacheStatistic {\n    int64_t cache_physical_pos;\n    int64_t cache_file_forwards;\n    int64_t cache_file_pos;\n    int64_t cache_count_bytes;\n    int64_t logical_file_size;\n} IjkIOAppCacheStatistic;\n\ntypedef struct IjkCacheEntry {\n    int64_t logical_pos;\n    int64_t physical_pos;\n    int64_t size;\n} IjkCacheEntry;\n\ntypedef struct IjkIOApplicationContext IjkIOApplicationContext;\nstruct IjkIOApplicationContext {\n    IjkThreadPoolContext *threadpool_ctx;\n    IjkAVIOInterruptCB *ijkio_interrupt_callback;\n    char cache_file_path[CACHE_FILE_PATH_MAX_LEN];\n    int64_t last_physical_pos;\n    void *cache_info_map;\n    void *opaque;\n    int64_t cache_count_bytes;\n    int fd;\n    pthread_mutex_t mutex;\n    int shared;\n    int active_reconnect;\n    int (*func_ijkio_on_app_event)(IjkIOApplicationContext *h, int event_type ,void *obj, int size);\n};\n\nint  ijkio_application_alloc(IjkIOApplicationContext **ph, void *opaque);\nint  ijkio_application_open(IjkIOApplicationContext **ph, void *opaque);\nvoid ijkio_application_close(IjkIOApplicationContext *h);\nvoid ijkio_application_closep(IjkIOApplicationContext **ph);\n\nvoid ijkio_application_on_cache_statistic(IjkIOApplicationContext *h, IjkIOAppCacheStatistic *statistic);\n\n#endif /* IJKAVFORMAT_IJKIOAPPLICATION_H */\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavformat/ijkiocache.c",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * Copyright (c) 2016 Raymond Zheng <raymondzheng1412@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n#include \"ijkiourl.h\"\n#include \"ijkioprotocol.h\"\n#include \"ijkioapplication.h\"\n#include \"ijkplayer/ijkavutil/ijktree.h\"\n#include \"ijkplayer/ijkavutil/ijkutils.h\"\n#include \"ijkplayer/ijkavutil/ijkthreadpool.h\"\n#include \"ijkplayer/ijkavutil/ijkstl.h\"\n#include \"libavutil/log.h\"\n\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <stddef.h>\n#include <string.h>\n#include <fcntl.h>\n#include <sys/stat.h>\n#include <unistd.h>\n#include <assert.h>\n\n#define DEFAULT_CACHE_MAX_CAPACITY            (512 * 1024 * 1024)\n#define DEFAULT_CACHE_FILE_FORWARDS_CAPACITY  (8 * 1024 * 1024)\n#   ifndef O_BINARY\n#       define O_BINARY 0\n#   endif\n#define FILE_RW_ERROR  (-100)\n\ntypedef struct IjkIOCacheContext {\n    char *cache_file_path;\n    int fd;\n    IjkCacheTreeInfo *tree_info;\n    int64_t logical_size;\n    int64_t read_logical_pos;\n    int64_t read_inner_pos;\n    int64_t file_logical_pos;\n    int64_t cache_physical_pos;\n    int64_t file_inner_pos;\n    int64_t file_logical_end;\n    int64_t cache_max_capacity;\n    int64_t cache_file_forwards_capacity;\n    int cache_file_close;\n    int io_eof_reached;\n    int io_error;\n    int inner_io_error;\n    int read_file_inner_error;\n    int file_handle_retry_count;\n    int file_error_count;\n    int seek_request;\n    int seek_completed;\n    int seek_whence;\n    int64_t seek_pos;\n    int64_t seek_ret;\n\n    int cur_file_no;\n    void *cache_info_map;\n    int64_t *last_physical_pos;\n    int64_t *cache_count_bytes;\n\n    pthread_cond_t     cond_wakeup_main;\n    pthread_cond_t     cond_wakeup_file_background;\n    pthread_cond_t     cond_wakeup_exit;\n    pthread_cond_t     cond_wakeup_write_file_exit;\n    pthread_mutex_t    file_mutex;\n    int                abort_request;\n    IjkAVIOInterruptCB *ijkio_interrupt_callback;\n    int task_is_running;\n\n    IjkURLContext *inner;\n    IjkThreadPoolContext *threadpool_ctx;\n    IjkIOApplicationContext *ijkio_app_ctx;\n    int async_open;\n    IjkAVDictionary *inner_options;\n    char inner_url[4096];\n    int inner_flags;\n    int only_read_file;\n} IjkIOCacheContext;\n\nstatic int cmp(const void *key, const void *node)\n{\n    return FFDIFFSIGN(*(const int64_t *)key, ((const IjkCacheEntry *) node)->logical_pos);\n}\n\nstatic void call_inject_statistic(IjkURLContext *h)\n{\n    IjkIOCacheContext *c = h->priv_data;\n\n    if (c->ijkio_app_ctx) {\n        IjkIOAppCacheStatistic statistic = {0};\n        statistic.cache_physical_pos  = c->cache_physical_pos;\n        statistic.cache_file_forwards = c->file_logical_pos - c->read_logical_pos;\n        statistic.cache_file_pos      = c->file_logical_pos;\n        statistic.cache_count_bytes   = *c->cache_count_bytes;\n        statistic.logical_file_size   = c->logical_size;\n        ijkio_application_on_cache_statistic(c->ijkio_app_ctx, &statistic);\n    }\n}\n\nstatic int ijkio_cache_check_interrupt(IjkURLContext *h)\n{\n    IjkIOCacheContext *c = h->priv_data;\n    if (!c)\n        return 1;\n\n    if (c->abort_request)\n        return 1;\n\n    if (c->ijkio_interrupt_callback && c->ijkio_interrupt_callback->callback &&\n                    c->ijkio_interrupt_callback->callback(c->ijkio_interrupt_callback->opaque)) {\n        c->abort_request = 1;\n    }\n\n    if (c->abort_request)\n        return 1;\n\n    return c->abort_request;\n}\n\nstatic int enu_free(void *opaque, void *elem)\n{\n    free(elem);\n    return 0;\n}\n\nstatic int tree_destroy(void *parm, int64_t key, void *elem)\n{\n    IjkCacheTreeInfo *info = elem;\n    ijk_av_tree_enumerate(info->root, NULL, NULL, enu_free);\n    ijk_av_tree_destroy(info->root);\n    free(info);\n    return 0;\n}\n\nstatic int ijkio_cache_file_error(IjkURLContext *h) {\n    IjkIOCacheContext *c = h->priv_data;\n\n    av_log(NULL, AV_LOG_WARNING, \"ijkio_cache_file_error\\n\");\n    if (c && c->file_handle_retry_count > 3) {\n        pthread_mutex_lock(&h->ijkio_app_ctx->mutex);\n        c->file_error_count++;\n        if (!c->ijkio_app_ctx->shared) {\n            ijk_map_traversal_handle(c->cache_info_map, NULL, tree_destroy);\n            ijk_map_clear(c->cache_info_map);\n            c->tree_info = NULL;\n            *c->last_physical_pos    = 0;\n            c->cache_physical_pos    = 0;\n            c->file_inner_pos        = 0;\n            c->io_eof_reached        = 0;\n            c->file_logical_pos      = c->read_logical_pos;\n            close(c->fd);\n            c->fd = -1;\n            c->ijkio_app_ctx->fd = -1;\n            if (c->file_error_count > 3) {\n                c->cache_file_close = 1;\n                remove(c->cache_file_path);\n                av_log(NULL, AV_LOG_WARNING, \"ijkio_cache_file_error will remove file\\n\");\n                goto fail;\n            }\n            c->fd = open(c->cache_file_path, O_RDWR | O_BINARY | O_CREAT | O_TRUNC, 0600);\n            c->ijkio_app_ctx->fd = c->fd;\n            if (c->fd >= 0) {\n                c->file_handle_retry_count = 0;\n                c->tree_info = calloc(1, sizeof(IjkCacheTreeInfo));\n                if (!c->tree_info) {\n                    c->cache_file_close = 1;\n                    goto fail;\n                }\n                ijk_map_put(c->cache_info_map, (int64_t)c->cur_file_no, c->tree_info);\n            } else {\n                av_log(NULL, AV_LOG_WARNING, \"ijkio_cache_file_error will cache_file_close\\n\");\n                c->cache_file_close = 1;\n                goto fail;\n            }\n        }\n        pthread_mutex_unlock(&h->ijkio_app_ctx->mutex);\n    }\n\n    return 0;\n\nfail:\n    pthread_mutex_unlock(&h->ijkio_app_ctx->mutex);\n    return FILE_RW_ERROR;\n}\n\nstatic int64_t ijkio_cache_file_overrang(IjkURLContext *h, int64_t *cur_pos, int size) {\n    IjkIOCacheContext *c = h->priv_data;\n    av_log(NULL, AV_LOG_WARNING, \"ijkio_cache_file_overrang will flush file\\n\");\n\n    pthread_mutex_lock(&h->ijkio_app_ctx->mutex);\n\n    if (!c->ijkio_app_ctx->shared) {\n        ijk_map_remove(c->cache_info_map, (int64_t)c->cur_file_no);\n        ijk_map_traversal_handle(c->cache_info_map, NULL, tree_destroy);\n        ijk_map_clear(c->cache_info_map);\n        memset(c->tree_info, 0, sizeof(IjkCacheTreeInfo));\n        ijk_map_put(c->cache_info_map, (int64_t)c->cur_file_no, c->tree_info);\n        *c->last_physical_pos    = 0;\n        c->cache_physical_pos    = 0;\n        c->io_eof_reached        = 0;\n        c->file_logical_pos      = c->read_logical_pos;\n        *cur_pos = lseek(c->fd, 0, SEEK_SET);\n        if (*cur_pos < 0) {\n            goto fail;\n        }\n    } else {\n        goto fail;\n    }\n\n    pthread_mutex_unlock(&h->ijkio_app_ctx->mutex);\n    return c->cache_max_capacity;\n\nfail:\n    pthread_mutex_unlock(&h->ijkio_app_ctx->mutex);\n    return FILE_RW_ERROR;\n}\n\nstatic int64_t add_entry(IjkURLContext *h, const unsigned char *buf, int size)\n{\n    IjkIOCacheContext *c= h->priv_data;\n    int64_t pos = -1;\n    int64_t ret = 0;\n    IjkCacheEntry *entry = NULL, *next[2] = {NULL, NULL};\n    IjkCacheEntry *entry_ret = NULL;\n    struct IjkAVTreeNode *node = NULL;\n    int64_t free_space = 0;\n\n    //FIXME avoid lseek\n    pos = lseek(c->fd, *c->last_physical_pos, SEEK_SET);\n\n    if (pos < 0) {\n        c->file_handle_retry_count++;\n        return ijkio_cache_file_error(h);\n    } else {\n        c->cache_physical_pos = pos;\n        *c->last_physical_pos = pos;\n    }\n\n    if (pos + size >= c->cache_max_capacity) {\n        free_space = ijkio_cache_file_overrang(h, &pos, size);\n        if (free_space < size) {\n            c->cache_file_close = 1;\n            return FILE_RW_ERROR;\n        }\n        if (pos < 0) {\n            c->file_handle_retry_count++;\n            return ijkio_cache_file_error(h);\n        }\n        if (free_space == c->cache_max_capacity)\n            return 0;\n    }\n\n    ret = write(c->fd, buf, size);\n    if (ret < 0) {\n        c->file_handle_retry_count++;\n        return ijkio_cache_file_error(h);\n    } else {\n        c->file_handle_retry_count = 0;\n    }\n\n    c->cache_physical_pos       += ret;\n    *c->last_physical_pos       += ret;\n    c->tree_info->physical_size += ret;\n\n    entry = ijk_av_tree_find(c->tree_info->root, &c->file_logical_pos, cmp, (void**)next);\n\n    if (!entry)\n        entry = next[0];\n\n    if (!entry ||\n        entry->logical_pos  + entry->size != c->file_logical_pos ||\n        entry->physical_pos + entry->size != pos) {\n        entry = malloc(sizeof(*entry));\n        node = ijk_av_tree_node_alloc();\n        if (!entry || !node) {\n            ret = IJKAVERROR(ENOMEM);\n            goto fail;\n        }\n        entry->logical_pos = c->file_logical_pos;\n        entry->physical_pos = pos;\n        entry->size = ret;\n\n        entry_ret = ijk_av_tree_insert(&c->tree_info->root, entry, cmp, &node);\n        if (entry_ret && entry_ret != entry) {\n            ret = -1;\n            av_log(NULL, AV_LOG_ERROR, \"av_tree_insert failed\\n\");\n            goto fail;\n        }\n    } else\n        entry->size += ret;\n\n    return ret;\nfail:\n    //we could truncate the file to pos here if pos >=0 but ftruncate isn't available in VS so\n    //for simplicty we just leave the file a bit larger\n    free(entry);\n    free(node);\n    return ret;\n}\n\nstatic int wrapped_file_read(IjkURLContext *h, void *dst, int size)\n{\n    IjkIOCacheContext *c   = h->priv_data;\n    int ret;\n\n    ret = (int)read(c->fd, dst, size);\n    c->read_file_inner_error = ret < 0 ? ret : 0;\n    return ret;\n}\n\nstatic int wrapped_url_read(IjkURLContext *h, void *dst, int size)\n{\n    IjkIOCacheContext *c   = h->priv_data;\n    int ret;\n\n    ret = c->inner->prot->url_read(c->inner, dst, size);\n\n    if (ret > 0)\n        *c->cache_count_bytes += ret;\n\n    c->inner_io_error = ret < 0 ? ret : 0;\n\n    return ret;\n}\n\nstatic int64_t ijkio_cache_ffurl_size(IjkURLContext *h) {\n    int64_t pos, size;\n    IjkIOCacheContext *c= ((IjkURLContext *)h)->priv_data;\n    if (!c || !c->inner || !c->inner->prot)\n        return IJKAVERROR(ENOSYS);\n    size = c->inner->prot->url_seek(c->inner, 0, IJKAVSEEK_SIZE);\n    if (size < 0) {\n        pos = c->inner->prot->url_seek(c->inner, 0, SEEK_CUR);\n        if ((size = c->inner->prot->url_seek(c->inner, -1, SEEK_END)) < 0)\n            return size;\n        size++;\n        c->inner->prot->url_seek(c->inner, pos, SEEK_SET);\n    }\n    return size;\n}\n\nstatic int ijkio_cache_io_open(IjkURLContext *h, const char *url, int flags, IjkAVDictionary **options) {\n    int ret = 0;\n    IjkIOCacheContext *c= h->priv_data;\n    ret = c->inner->prot->url_open2(c->inner, url, flags, options);\n    if (ret != 0) {\n        return ret;\n    } else {\n        c->logical_size = ijkio_cache_ffurl_size(h);\n        if (c->tree_info && !c->cache_file_close) {\n            c->tree_info->file_size = c->logical_size;\n        }\n    }\n\n    call_inject_statistic(h);\n    return ret;\n}\n\nstatic int64_t ijkio_cache_write_file(IjkURLContext *h) {\n    IjkIOCacheContext *c= h->priv_data;\n    int64_t r;\n    unsigned char buf[4096] = {0};\n    int to_read = 4096;\n    int64_t to_copy = (int64_t)to_read;\n\n    IjkCacheEntry *root = NULL ,*l_entry = NULL, *r_entry = NULL, *next[2] = {NULL, NULL};\n\n    if (!c || !c->inner || !c->inner->prot)\n        return IJKAVERROR(ENOSYS);\n\n    root = ijk_av_tree_find(c->tree_info->root, &c->file_logical_pos, cmp, (void**)next);\n\n    if (!root)\n        l_entry = next[0];\n\n    if (l_entry) {\n        int64_t in_block_pos = c->file_logical_pos - l_entry->logical_pos;\n        assert(l_entry->logical_pos <= c->file_logical_pos);\n        if (in_block_pos < l_entry->size) {\n            c->file_logical_pos = l_entry->logical_pos + l_entry->size;\n        }\n    } else if (root) {\n        int64_t in_block_pos = c->file_logical_pos - root->logical_pos;\n        assert(root->logical_pos <= c->file_logical_pos);\n        if (in_block_pos < root->size) {\n            c->file_logical_pos = root->logical_pos + root->size;\n        }\n    }\n\n    r_entry = next[1];\n\n    if (r_entry) {\n        to_copy = r_entry->logical_pos - c->file_logical_pos;\n        to_copy = FFMIN(to_copy, to_read);\n    }\n\n    if (to_copy == 0) {\n        return 0;\n    }\n\n    if (c->file_logical_end > 0 && c->file_logical_pos == c->file_logical_end) {\n        c->io_eof_reached = 1;\n        return 0;\n    }\n\n    if (c->file_logical_pos >= c->logical_size) {\n        c->io_eof_reached = 1;\n        return 0;\n    }\n    if (c->file_logical_pos != c->file_inner_pos) {\n        if (c->async_open > 0) {\n            r = ijkio_cache_io_open(h, c->inner_url, c->inner_flags, &c->inner_options);\n            if (r != 0) {\n                c->io_eof_reached = 1;\n                c->io_error = (int)r;\n                return r;\n            }\n            c->async_open = 0;\n        }\n\n        r = c->inner->prot->url_seek(c->inner, c->file_logical_pos, SEEK_SET);\n\n        if (r < 0) {\n            c->io_eof_reached = 1;\n            if (c->file_logical_end == c->file_logical_pos) {\n                c->file_inner_pos = c->file_logical_end;\n            }\n            return r;\n        }\n        c->file_inner_pos = r;\n    }\n    if (c->async_open > 0) {\n        r = ijkio_cache_io_open(h, c->inner_url, c->inner_flags, &c->inner_options);\n        if (r != 0) {\n            c->io_eof_reached = 1;\n            c->io_error = (int)r;\n            return r;\n        }\n        c->async_open = 0;\n    }\n    r = c->inner->prot->url_read(c->inner, buf, (int)to_copy);\n    if (r == 0 && to_copy > 0) {\n        c->file_logical_end = c->file_logical_pos;\n    }\n    if (r <= 0) {\n        c->io_eof_reached = 1;\n        c->io_error = (int)r;\n        return r;\n    }\n    *c->cache_count_bytes += r;\n    c->file_inner_pos += r;\n\n    pthread_mutex_lock(&c->file_mutex);\n    r = add_entry(h, buf, (int)r);\n\n    if (r > 0) {\n        c->file_logical_pos += r;\n        pthread_cond_signal(&c->cond_wakeup_file_background);\n    }\n    pthread_mutex_unlock(&c->file_mutex);\n\n    return r;\n}\n\nstatic void ijkio_cache_task(void *h, void *r) {\n    IjkIOCacheContext *c= ((IjkURLContext *)h)->priv_data;\n    c->task_is_running = 1;\n    int64_t ret = 0;\n\n    while(1) {\n        if (c->cache_file_close) {\n            break;\n        }\n        if (ijkio_cache_check_interrupt(h)) {\n            c->io_eof_reached   = 1;\n            c->io_error         = IJKAVERROR_EXIT;\n            break;\n        }\n\n        if (c->seek_request) {\n            pthread_mutex_lock(&c->file_mutex);\n            c->io_eof_reached    = 0;\n            c->io_error          = 0;\n            c->seek_completed    = 1;\n            c->seek_request      = 0;\n            c->read_logical_pos  = c->seek_pos;\n            c->file_logical_pos  = c->seek_pos;\n            c->seek_ret          = c->seek_pos;\n            pthread_cond_signal(&c->cond_wakeup_main);\n            pthread_mutex_unlock(&c->file_mutex);\n        }\n\n        if (((c->file_logical_pos - c->read_logical_pos > c->cache_file_forwards_capacity)\n            || c->io_eof_reached)) {\n            pthread_mutex_lock(&c->file_mutex);\n            pthread_cond_signal(&c->cond_wakeup_main);\n            pthread_cond_wait(&c->cond_wakeup_file_background, &c->file_mutex);\n            pthread_mutex_unlock(&c->file_mutex);\n        } else {\n            ret = ijkio_cache_write_file(h);\n            if (ret > 0) {\n                pthread_mutex_lock(&c->file_mutex);\n                pthread_cond_signal(&c->cond_wakeup_main);\n                pthread_mutex_unlock(&c->file_mutex);\n            } else if (ret == FILE_RW_ERROR) {\n                break;\n            }\n        }\n\n        call_inject_statistic(h);\n    }\n    pthread_mutex_lock(&c->file_mutex);\n    c->task_is_running = 0;\n    pthread_cond_signal(&c->cond_wakeup_main);\n    pthread_cond_signal(&c->cond_wakeup_exit);\n    pthread_mutex_unlock(&c->file_mutex);\n}\n\nstatic int ijkio_cache_open(IjkURLContext *h, const char *url, int flags, IjkAVDictionary **options) {\n    IjkIOCacheContext *c= h->priv_data;\n    int ret = 0;\n    int64_t cur_exist_file_size = 0;\n    if (!c)\n        return IJKAVERROR(ENOSYS);\n\n    c->ijkio_app_ctx = h->ijkio_app_ctx;\n    if (c->ijkio_app_ctx == NULL) {\n        return -1;\n    }\n\n    c->async_open = 0;\n    c->ijkio_interrupt_callback = h->ijkio_app_ctx->ijkio_interrupt_callback;\n    c->cache_file_forwards_capacity = 0;\n\n    ijk_av_strstart(url, \"cache:\", &url);\n    c->cache_max_capacity = DEFAULT_CACHE_MAX_CAPACITY;\n\n    IjkAVDictionaryEntry *t = NULL;\n    t = ijk_av_dict_get(*options, \"cache_max_capacity\", NULL, IJK_AV_DICT_MATCH_CASE);\n    if (t) {\n        c->cache_max_capacity = strtoll(t->value, NULL, 10);\n    }\n\n    t = ijk_av_dict_get(*options, \"cache_file_forwards_capacity\", NULL, IJK_AV_DICT_MATCH_CASE);\n    if (t) {\n        c->cache_file_forwards_capacity = strtoll(t->value, NULL, 10);\n    }\n\n    t = ijk_av_dict_get(*options, \"cache_file_close\", NULL, IJK_AV_DICT_MATCH_CASE);\n    if (t) {\n        c->cache_file_close = (int)strtol(t->value, NULL, 10);\n        c->cache_file_close = c->cache_file_close != 0 ? 1 : 0;\n    }\n\n    t = ijk_av_dict_get(*options, \"cur_file_no\", NULL, IJK_AV_DICT_MATCH_CASE);\n    if (t) {\n        c->cur_file_no = (int)strtol(t->value, NULL, 10);\n    }\n\n    t = ijk_av_dict_get(*options, \"only_read_file\", NULL, IJK_AV_DICT_MATCH_CASE);\n    if (t) {\n        c->only_read_file = (int)strtol(t->value, NULL, 10);\n        if (c->only_read_file) {\n            c->cache_file_forwards_capacity = 0;\n        }\n    }\n\n    c->cache_file_path = c->ijkio_app_ctx->cache_file_path;\n\n    if (c->cache_file_path == NULL || 0 == strlen(c->cache_file_path)) {\n        c->cache_file_close = 1;\n    }\n\n    c->threadpool_ctx       = c->ijkio_app_ctx->threadpool_ctx;\n    c->cache_info_map       = c->ijkio_app_ctx->cache_info_map;\n    c->last_physical_pos    = &c->ijkio_app_ctx->last_physical_pos;\n    c->cache_count_bytes    = &c->ijkio_app_ctx->cache_count_bytes;\n    if (!c->last_physical_pos || !c->threadpool_ctx || !c->cache_info_map) {\n        return -1;\n    }\n\n    if (!c->cache_file_close) {\n        do {\n            if (c->ijkio_app_ctx->fd >= 0) {\n                c->fd = c->ijkio_app_ctx->fd;\n            } else {\n                if (ijk_map_size(c->cache_info_map) > 0) {\n                    av_log(NULL, AV_LOG_INFO, \"ijkio cache will use the data that already exists\\n\");\n                    c->fd = open(c->cache_file_path, O_RDWR | O_BINARY, 0600);\n                    c->async_open = 1;\n                    cur_exist_file_size = lseek(c->fd, 0, SEEK_END);\n                    if (cur_exist_file_size < *c->last_physical_pos) {\n                        av_log(NULL, AV_LOG_WARNING, \"ijkio cache exist is error, will delete last_physical_pos = %lld, cur_exist_file_size = %lld\\n\", *c->last_physical_pos, cur_exist_file_size);\n                        ijk_map_traversal_handle(c->cache_info_map, NULL, tree_destroy);\n                        ijk_map_clear(c->cache_info_map);\n                        *c->last_physical_pos    = 0;\n                        c->cache_physical_pos    = 0;\n                    }\n                } else {\n                    c->fd = open(c->cache_file_path, O_RDWR | O_BINARY | O_CREAT | O_TRUNC, 0600);\n                }\n                c->ijkio_app_ctx->fd = c->fd;\n            }\n            if (c->fd < 0) {\n                c->cache_file_close = 1;\n                break;\n            }\n\n            int64_t seek_ret = lseek(c->fd, *c->last_physical_pos, SEEK_SET);\n            if (seek_ret < 0) {\n                c->cache_file_close = 1;\n                close(c->fd);\n                c->fd = -1;\n                c->ijkio_app_ctx->fd = -1;\n                break;\n            } else {\n                c->cache_physical_pos = *c->last_physical_pos;\n            }\n\n            c->tree_info = ijk_map_get(c->cache_info_map, (int64_t)c->cur_file_no);\n            if (c->tree_info == NULL) {\n                c->tree_info = calloc(1, sizeof(IjkCacheTreeInfo));\n                c->tree_info->physical_init_pos = *c->last_physical_pos;\n                ijk_map_put(c->cache_info_map, (int64_t)c->cur_file_no, c->tree_info);\n            } else {\n                if (c->tree_info->physical_size > 200 * 1024 && c->tree_info->file_size > 0) {\n                    c->logical_size = c->tree_info->file_size;\n                    c->async_open = 1;\n                } else {\n                    c->async_open = 0;\n                }\n            }\n        } while(0);\n    }\n\n    ret = ijkio_alloc_url(&(c->inner), url);\n    if (c->inner && !ret) {\n        c->inner->ijkio_app_ctx = c->ijkio_app_ctx;\n        if (c->logical_size <= 0 || c->async_open == 0) {\n            c->async_open = 0;\n            ret = ijkio_cache_io_open(h, url, flags, options);\n            if (ret != 0)\n                goto url_fail;\n        } else {\n            c->tree_info->file_size = c->logical_size;\n            ijk_av_dict_copy(&c->inner_options, *options, 0);\n            strcpy(c->inner_url, url);\n            c->inner_flags = flags;\n            call_inject_statistic(h);\n        }\n    }\n\n    ret = pthread_mutex_init(&c->file_mutex, NULL);\n    if (ret != 0) {\n        av_log(NULL, AV_LOG_ERROR, \"pthread_mutex_init failed : %s\\n\", av_err2str(ret));\n        goto file_mutex_fail;\n    }\n\n    ret = pthread_cond_init(&c->cond_wakeup_main, NULL);\n    if (ret != 0) {\n        av_log(NULL, AV_LOG_ERROR, \"pthread_cond_init failed : %s\\n\", av_err2str(ret));\n        goto cond_wakeup_main_fail;\n    }\n\n    ret = pthread_cond_init(&c->cond_wakeup_file_background, NULL);\n    if (ret != 0) {\n        av_log(NULL, AV_LOG_ERROR, \"pthread_cond_init failed : %s\\n\", av_err2str(ret));\n        goto cond_wakeup_file_background_fail;\n    }\n\n    ret = pthread_cond_init(&c->cond_wakeup_exit, NULL);\n    if (ret != 0) {\n        av_log(NULL, AV_LOG_ERROR, \"pthread_cond_init failed : %s\\n\", av_err2str(ret));\n        goto cond_wakeup_exit_fail;\n    }\n\n    if (!c->cache_file_close && c->cache_file_forwards_capacity) {\n        c->task_is_running = 1;\n        ret = ijk_threadpool_add(c->threadpool_ctx, ijkio_cache_task, h, NULL, 0);\n        if (ret) {\n            c->task_is_running = 0;\n            pthread_cond_signal(&c->cond_wakeup_exit);\n            goto thread_fail;\n        }\n    }\n\n    return 0;\n\nthread_fail:\n    pthread_cond_destroy(&c->cond_wakeup_exit);\ncond_wakeup_exit_fail:\n    pthread_cond_destroy(&c->cond_wakeup_file_background);\ncond_wakeup_file_background_fail:\n    pthread_cond_destroy(&c->cond_wakeup_main);\ncond_wakeup_main_fail:\n    pthread_mutex_destroy(&c->file_mutex);\nfile_mutex_fail:\n    if (c->async_open) {\n        if (c->inner_options) {\n            ijk_av_dict_free(&c->inner_options);\n        }\n    } else {\n        if (c->inner) {\n            if (c->inner->prot && c->inner->prot->url_close) {\n                c->inner->prot->url_close(c->inner);\n            }\n        }\n    }\nurl_fail:\n    if (c->inner) {\n        ijk_av_freep(&c->inner->priv_data);\n        ijk_av_freep(&c->inner);\n    }\n    return ret;\n}\n\nstatic int ijkio_file_read(IjkURLContext *h, void *dest, int to_read)\n{\n    IjkIOCacheContext *c   = h->priv_data;\n    IjkCacheEntry *entry   = NULL;\n    IjkCacheEntry *next[2] = {NULL, NULL};\n    int64_t ret            = 0;\n    int to_copy            = 0;\n\n    if (!c->tree_info)\n        return 0;\n\n    entry = ijk_av_tree_find(c->tree_info->root, &c->read_logical_pos, cmp, (void**)next);\n    if (!entry)\n        entry = next[0];\n\n    if (entry) {\n        int64_t in_block_pos = c->read_logical_pos - entry->logical_pos;\n        if (in_block_pos < entry->size && entry->logical_pos <= c->read_logical_pos) {\n            int64_t physical_target = entry->physical_pos + in_block_pos;\n            if (c->cache_physical_pos != physical_target) {\n                ret = lseek(c->fd, physical_target, SEEK_SET);\n                if (ret < 0) {\n                    c->file_handle_retry_count++;\n                    ijkio_cache_file_error(h);\n                }\n            } else {\n                ret = c->cache_physical_pos;\n            }\n\n            if (ret >= 0) {\n                to_copy = (int)FFMIN(to_read, entry->size - in_block_pos);\n                ret = wrapped_file_read(h, dest, to_copy);\n                if (ret < 0) {\n                    if(c->read_file_inner_error) {\n                        c->file_handle_retry_count++;\n                        ijkio_cache_file_error(h);\n                    }\n                }\n            }\n        }\n    }\n    return (int)ret;\n}\n\nstatic int64_t sync_add_entry(IjkURLContext *h, const unsigned char *buf, int size)\n{\n    IjkIOCacheContext *c= h->priv_data;\n    int64_t pos = -1;\n    int64_t ret = 0;\n    IjkCacheEntry *entry = NULL, *next[2] = {NULL, NULL};\n    IjkCacheEntry *entry_ret = NULL;\n    struct IjkAVTreeNode *node = NULL;\n    int64_t free_space = 0;\n\n    if (*c->last_physical_pos != c->cache_physical_pos) {\n        pos = lseek(c->fd, *c->last_physical_pos, SEEK_SET);\n        if (pos < 0) {\n            return FILE_RW_ERROR;\n        } else {\n            c->cache_physical_pos = pos;\n            *c->last_physical_pos = pos;\n        }\n    } else {\n        pos = *c->last_physical_pos;\n    }\n\n    if (*c->last_physical_pos + size >= c->cache_max_capacity) {\n        free_space = ijkio_cache_file_overrang(h, &pos, size);\n        if (free_space < size || pos < 0) {\n            return FILE_RW_ERROR;\n        }\n        c->cache_physical_pos = pos;\n        *c->last_physical_pos = pos;\n    }\n\n    ret = write(c->fd, buf, size);\n    if (ret < 0) {\n        return FILE_RW_ERROR;\n    }\n\n    c->cache_physical_pos       += ret;\n    *c->last_physical_pos       += ret;\n    c->tree_info->physical_size += ret;\n\n    entry = ijk_av_tree_find(c->tree_info->root, &c->read_logical_pos, cmp, (void**)next);\n\n    if (!entry)\n        entry = next[0];\n\n    if (!entry ||\n        entry->logical_pos  + entry->size != c->read_logical_pos ||\n        entry->physical_pos + entry->size != pos) {\n        entry = malloc(sizeof(*entry));\n        node = ijk_av_tree_node_alloc();\n        if (!entry || !node) {\n            ret = IJKAVERROR(ENOMEM);\n            goto fail;\n        }\n        entry->logical_pos = c->read_logical_pos;\n        entry->physical_pos = pos;\n        entry->size = ret;\n\n        entry_ret = ijk_av_tree_insert(&c->tree_info->root, entry, cmp, &node);\n        if (entry_ret && entry_ret != entry) {\n            ret = -1;\n            av_log(NULL, AV_LOG_ERROR, \"sync_add_entry av_tree_insert failed\\n\");\n            goto fail;\n        }\n    } else {\n        entry->size += ret;\n    }\n\n    return ret;\nfail:\n    //we could truncate the file to pos here if pos >=0 but ftruncate isn't available in VS so\n    //for simplicty we just leave the file a bit larger\n    free(entry);\n    free(node);\n    return ret;\n}\n\nstatic int ijkio_cache_sync_read(IjkURLContext *h, unsigned char *buf, int size) {\n    IjkIOCacheContext *c= h->priv_data;\n    int64_t ret = 0;\n    int to_read = size;\n    int to_copy = 0;\n    IjkCacheEntry *entry = NULL, *next_entry = NULL, *next[2] = {NULL, NULL};\n\n    if (!c || !c->inner || !c->inner->prot)\n        return IJKAVERROR(ENOSYS);\n\n    if (to_read <= 0) {\n        return to_read;\n    }\n\n    if (c->tree_info) {\n        entry = ijk_av_tree_find(c->tree_info->root, &c->read_logical_pos, cmp, (void**)next);\n    }\n\n    if (!entry)\n        entry = next[0];\n\n    if (entry) {\n        int64_t in_block_pos = c->read_logical_pos - entry->logical_pos;\n        if (in_block_pos < entry->size && entry->logical_pos <= c->read_logical_pos) {\n            int64_t physical_target = entry->physical_pos + in_block_pos;\n            if (c->cache_physical_pos != physical_target) {\n                ret = lseek(c->fd, physical_target, SEEK_SET);\n            } else {\n                ret = c->cache_physical_pos;\n            }\n\n            if (ret >= 0) {\n                c->cache_physical_pos = ret;\n                to_copy = (int)FFMIN(to_read, entry->size - in_block_pos);\n                ret = wrapped_file_read(h, buf, to_copy);\n                if (ret >= 0) {\n                    c->cache_physical_pos += ret;\n                    return (int)ret;\n                }\n            }\n\n            av_log(NULL, AV_LOG_ERROR, \"%s cache file is bad, will try recreate\\n\", __func__);\n            ijk_map_traversal_handle(c->cache_info_map, NULL, tree_destroy);\n            ijk_map_clear(c->cache_info_map);\n            c->tree_info             = NULL;\n            *c->last_physical_pos    = 0;\n            c->cache_physical_pos    = 0;\n            c->io_eof_reached        = 0;\n            close(c->fd);\n            c->fd = open(c->cache_file_path, O_RDWR | O_BINARY | O_CREAT | O_TRUNC, 0600);\n            c->ijkio_app_ctx->fd = c->fd;\n            if (c->fd >= 0) {\n                c->tree_info = calloc(1, sizeof(IjkCacheTreeInfo));\n                if (c->tree_info) {\n                    ijk_map_put(c->cache_info_map, (int64_t)c->cur_file_no, c->tree_info);\n                }\n            }\n        }\n    }\n\n    if (c->read_logical_pos >= c->logical_size) {\n        c->io_eof_reached = 1;\n        return 0;\n    }\n\n    if (c->async_open > 0) {\n        ret = ijkio_cache_io_open(h, c->inner_url, c->inner_flags, &c->inner_options);\n        if (ret != 0) {\n            return (int)ret;\n        }\n        c->async_open = 0;\n    }\n\n    if (c->read_inner_pos != c->read_logical_pos) {\n        ret = c->inner->prot->url_seek(c->inner, c->read_logical_pos, SEEK_SET);\n        if (ret < 0) {\n            return (int)ret;\n        }\n        c->read_inner_pos = ret;\n    }\n\n    next_entry = next[1];\n    if (next_entry && next_entry->logical_pos > c->read_logical_pos) {\n        to_copy = (int)FFMIN(to_read, next_entry->logical_pos - c->read_logical_pos);\n    } else {\n        to_copy = to_read;\n    }\n\n    ret = wrapped_url_read(h, buf, to_copy);\n    if (ret <= 0)\n        return (int)ret;\n\n    c->read_inner_pos   += ret;\n\n    if (c->fd >= 0 && c->tree_info && !c->only_read_file) {\n        sync_add_entry(h, buf, (int)ret);\n    }\n\n    return (int)ret;\n}\n\nstatic int ijkio_cache_read(IjkURLContext *h, unsigned char *buf, int size) {\n    IjkIOCacheContext *c = h->priv_data;\n    int64_t          ret = 0;\n    int          to_read = size;\n    unsigned char  *dest = buf;\n    int          to_copy = 0;\n\n    if (!c || !c->inner || !c->inner->prot)\n        return IJKAVERROR(ENOSYS);\n\n    if (c->cache_file_close) {\n        return wrapped_url_read(h, dest, to_read);\n    }\n\n    if (!c->cache_file_forwards_capacity) {\n        ret = ijkio_cache_sync_read(h, buf, size);\n        if (ret >= 0) {\n            c->read_logical_pos += ret;\n        }\n        call_inject_statistic(h);\n        return (int)ret;\n    }\n\n    pthread_mutex_lock(&c->file_mutex);\n    while (to_read > 0) {\n        if (ijkio_cache_check_interrupt(h)) {\n            ret = IJKAVERROR_EXIT;\n            break;\n        }\n\n        if (c->cache_file_close) {\n            ret = c->inner->prot->url_seek(c->inner, c->read_logical_pos, SEEK_SET);\n            if (ret < 0) {\n                pthread_mutex_unlock(&c->file_mutex);\n                return (int)ret;\n            }\n\n            to_copy  = wrapped_url_read(h, dest, to_read);\n            to_read -= to_copy;\n            ret      = size - to_read;\n            pthread_mutex_unlock(&c->file_mutex);\n            return (int)ret;\n        }\n\n        to_copy = ijkio_file_read(h, dest, to_read);\n        if (to_copy > 0) {\n            to_read             -= to_copy;\n            ret                  = size - to_read;\n            dest                += to_copy;\n            c->read_logical_pos += to_copy;\n            if (to_read <= 0)\n                break;\n        } else if (c->io_eof_reached) {\n            if (ret <= 0) {\n                if (c->io_error)\n                    ret = c->io_error;\n                else\n                    ret = IJKAVERROR_EOF;\n            }\n            break;\n        }\n        pthread_cond_signal(&c->cond_wakeup_file_background);\n        pthread_cond_wait(&c->cond_wakeup_main, &c->file_mutex);\n    }\n\n    if (ret != size || (!c->io_eof_reached && (c->file_logical_pos - c->read_logical_pos) <= c->cache_file_forwards_capacity)) {\n        pthread_cond_signal(&c->cond_wakeup_file_background);\n    }\n    pthread_mutex_unlock(&c->file_mutex);\n    return (int)ret;\n}\n\nstatic int64_t ijkio_cache_seek(IjkURLContext *h, int64_t pos, int whence) {\n    IjkIOCacheContext *c= h->priv_data;\n    int64_t ret = 0;\n    int64_t new_logical_pos = 0;\n    if (!c || !c->inner || !c->inner->prot)\n        return IJKAVERROR(ENOSYS);\n\n    if (whence == IJKAVSEEK_SIZE) {\n        return c->logical_size;\n    } else if (whence == SEEK_CUR) {\n        new_logical_pos = pos + c->read_logical_pos;\n    } else if (whence == SEEK_SET){\n        new_logical_pos = pos;\n    } else {\n        return IJKAVERROR(EINVAL);\n    }\n    if (new_logical_pos < 0)\n        return IJKAVERROR(EINVAL);\n\n    if (c->cache_file_close) {\n        return c->inner->prot->url_seek(c->inner, new_logical_pos, SEEK_SET);\n    }\n\n    if (!c->cache_file_forwards_capacity) {\n        c->read_logical_pos = new_logical_pos;\n        return new_logical_pos;\n    }\n\n    pthread_mutex_lock(&c->file_mutex);\n    c->seek_request   = 1;\n    c->seek_pos       = new_logical_pos;\n    c->seek_whence    = SEEK_SET;\n    c->seek_completed = 0;\n\n    while (1) {\n        if (ijkio_cache_check_interrupt(h)) {\n            ret = IJKAVERROR_EXIT;\n            break;\n        }\n        if (c->seek_completed) {\n            ret = c->seek_ret;\n            break;\n        }\n        pthread_cond_signal(&c->cond_wakeup_file_background);\n        pthread_cond_wait(&c->cond_wakeup_main, &c->file_mutex);\n    }\n\n    pthread_mutex_unlock(&c->file_mutex);\n    return ret;\n}\n\nstatic int ijkio_cache_close(IjkURLContext *h) {\n    IjkIOCacheContext *c = h->priv_data;\n    int              ret = 0;\n\n    if (!c || !c->inner || !c->inner->prot)\n        return IJKAVERROR(ENOSYS);\n\n    if (c->cache_file_forwards_capacity) {\n        pthread_mutex_lock(&c->file_mutex);\n        c->abort_request = 1;\n        pthread_cond_signal(&c->cond_wakeup_file_background);\n        while (c->task_is_running) {\n            pthread_cond_wait(&c->cond_wakeup_exit, &c->file_mutex);\n        }\n        pthread_mutex_unlock(&c->file_mutex);\n    } else {\n        c->abort_request = 1;\n    }\n\n    pthread_cond_destroy(&c->cond_wakeup_file_background);\n    pthread_cond_destroy(&c->cond_wakeup_main);\n    pthread_cond_destroy(&c->cond_wakeup_exit);\n    pthread_mutex_destroy(&c->file_mutex);\n\n    ret = c->inner->prot->url_close(c->inner);\n\n    if (c->inner_options) {\n        ijk_av_dict_free(&c->inner_options);\n    }\n    ijk_av_freep(&c->inner->priv_data);\n\n    ijk_av_freep(&c->inner);\n    return ret;\n}\n\nstatic int ijkio_cache_pause(IjkURLContext *h) {\n    IjkIOCacheContext *c = h->priv_data;\n    int             ret  = 0;\n    if (!c || !c->inner || !c->inner->prot)\n        return IJKAVERROR(ENOSYS);\n\n    if (c->inner->prot->url_pause) {\n        ret = c->inner->prot->url_pause(c->inner);\n    }\n\n    if (!c->cache_file_forwards_capacity) {\n        c->abort_request = 1;\n    } else {\n        pthread_mutex_lock(&c->file_mutex);\n        c->abort_request = 1;\n        pthread_cond_signal(&c->cond_wakeup_file_background);\n        while (c->task_is_running) {\n            pthread_cond_wait(&c->cond_wakeup_exit, &c->file_mutex);\n        }\n        pthread_mutex_unlock(&c->file_mutex);\n    }\n\n    return ret;\n}\n\nstatic int ijkio_cache_resume(IjkURLContext *h) {\n    IjkIOCacheContext *c = h->priv_data;\n    int             ret  = 0;\n    if (!c || !c->inner || !c->inner->prot)\n        return IJKAVERROR(ENOSYS);\n\n    if (!c->cache_file_path || 0 == strlen(c->cache_file_path) || c->cache_file_close) {\n        c->cache_file_close = 1;\n    } else {\n        if (c->cache_file_forwards_capacity) {\n            int64_t seek_ret = lseek(c->fd, *c->last_physical_pos, SEEK_SET);\n            if (seek_ret < 0) {\n                c->cache_file_close = 1;\n                close(c->fd);\n                c->fd = -1;\n                c->ijkio_app_ctx->fd = -1;\n            } else {\n                c->cache_physical_pos = *c->last_physical_pos;\n            }\n        }\n    }\n\n    if (c->inner->prot->url_resume) {\n        ret = c->inner->prot->url_resume(c->inner);\n        if (ret != 0) {\n            return ret;\n        }\n    }\n\n    c->abort_request = 0;\n\n    if (!c->cache_file_close && c->cache_file_forwards_capacity) {\n        c->task_is_running = 1;\n        ret = ijk_threadpool_add(c->threadpool_ctx, ijkio_cache_task, h, NULL, 0);\n        if (ret) {\n            c->task_is_running = 0;\n            pthread_cond_signal(&c->cond_wakeup_exit);\n        }\n    }\n    return ret;\n}\n\nIjkURLProtocol ijkio_cache_protocol = {\n    .name                = \"ijkiocache\",\n    .url_open2           = ijkio_cache_open,\n    .url_read            = ijkio_cache_read,\n    .url_seek            = ijkio_cache_seek,\n    .url_close           = ijkio_cache_close,\n    .url_pause           = ijkio_cache_pause,\n    .url_resume          = ijkio_cache_resume,\n    .priv_data_size      = sizeof(IjkIOCacheContext),\n};\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavformat/ijkioffio.c",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * Copyright (c) 2016 Raymond Zheng <raymondzheng1412@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n#include \"libavformat/url.h\"\n#include \"libavutil/avstring.h\"\n#include \"ijkplayer/ijkavutil/ijkutils.h\"\n#include \"ijkiourl.h\"\n\n#include <stdint.h>\n\ntypedef struct IjkIOFFioContext {\n    URLContext *inner;\n} IjkIOFFioContext;\n\nstatic int ijkio_copy_options(AVDictionary **dst, IjkAVDictionary *src) {\n    IjkAVDictionaryEntry *t = NULL;\n\n    while ((t = ijk_av_dict_get(src, \"\", t, IJK_AV_DICT_IGNORE_SUFFIX))) {\n        int ret = av_dict_set(dst, t->key, t->value, 0);\n        if (ret < 0)\n            return ret;\n    }\n\n    return 0;\n}\n\nstatic int ijkio_ffio_open(IjkURLContext *h, const char *url, int flags, IjkAVDictionary **options) {\n    int ret = -1;\n\n    IjkIOFFioContext *c= h->priv_data;\n    if (!c)\n        return -1;\n\n    AVDictionary *opts = NULL;\n    ijkio_copy_options(&opts, *options);\n\n    av_strstart(url, \"ffio:\", &url);\n    if (h->ijkio_app_ctx) {\n        ret = ffurl_open_whitelist(&c->inner, url, flags, (AVIOInterruptCB *)h->ijkio_app_ctx->ijkio_interrupt_callback,\n                                &opts, NULL, NULL, NULL);\n    } else {\n        ret = -1;\n    }\n\n    av_dict_free(&opts);\n\n    return ret;\n}\n\nstatic int ijkio_ffio_read(IjkURLContext *h, unsigned char *buf, int size) {\n    if (!h)\n        return -1;\n\n    IjkIOFFioContext *c= h->priv_data;\n    if (!c || !c->inner)\n        return -1;\n\n    return ffurl_read(c->inner, buf, size);\n}\n\nstatic int64_t ijkio_ffio_seek(IjkURLContext *h, int64_t offset, int whence) {\n    if (!h)\n        return -1;\n\n    IjkIOFFioContext *c= h->priv_data;\n\n    if (!c || !c->inner)\n        return -1;\n\n    return ffurl_seek(c->inner, offset, whence);\n}\n\nstatic int ijkio_ffio_close(IjkURLContext *h) {\n    if (!h)\n        return -1;\n\n    IjkIOFFioContext *c= h->priv_data;\n\n    if (!c || !c->inner)\n        return -1;\n\n    return ffurl_close(c->inner);\n}\n\nIjkURLProtocol ijkio_ffio_protocol = {\n    .name                = \"ijkffio\",\n    .url_open2           = ijkio_ffio_open,\n    .url_read            = ijkio_ffio_read,\n    .url_seek            = ijkio_ffio_seek,\n    .url_close           = ijkio_ffio_close,\n    .priv_data_size      = sizeof(IjkIOFFioContext),\n};\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavformat/ijkiomanager.c",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * Copyright (c) 2016 Raymond Zheng <raymondzheng1412@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijkiomanager.h\"\n#include \"ijkioprotocol.h\"\n#include \"ijkplayer/ijkavutil/ijkutils.h\"\n#include \"ijkplayer/ijkavutil/ijktree.h\"\n#include \"ijkplayer/ijkavutil/ijkstl.h\"\n#include \"libavutil/log.h\"\n\n#include <stdlib.h>\n#include <string.h>\n#include <stdio.h>\n#include <unistd.h>\n\n#define CONFIG_MAX_LINE 1024\n\nstatic int ijkio_manager_alloc(IjkIOManagerContext **ph, void *opaque)\n{\n    IjkIOManagerContext *h = NULL;\n\n    h = (IjkIOManagerContext *)calloc(1, sizeof(IjkIOManagerContext));\n    if (!h)\n        return -1;\n\n    h->opaque = opaque;\n    h->ijk_ctx_map = ijk_map_create();\n\n    ijkio_application_open(&h->ijkio_app_ctx, opaque);\n\n    pthread_mutex_init(&h->ijkio_app_ctx->mutex, NULL);\n    h->ijkio_app_ctx->threadpool_ctx = ijk_threadpool_create(5, 5, 0);\n    h->ijkio_app_ctx->cache_info_map = ijk_map_create();\n    h->ijkio_app_ctx->fd             = -1;\n    *ph = h;\n    return 0;\n}\n\nint ijkio_manager_create(IjkIOManagerContext **ph, void *opaque)\n{\n    return ijkio_manager_alloc(ph, opaque);\n}\n\nstatic int enu_free(void *opaque, void *elem)\n{\n    free(elem);\n    return 0;\n}\n\nstatic int tree_destroy(void *parm, int64_t key, void *elem)\n{\n    IjkCacheTreeInfo *info = elem;\n    ijk_av_tree_enumerate(info->root, NULL, NULL, enu_free);\n    ijk_av_tree_destroy(info->root);\n    free(info);\n    return 0;\n}\n\nstatic int enu_save(void *opaque, void *elem) {\n    FILE *fp = opaque;\n    IjkCacheEntry *entry = elem;\n    char string[CONFIG_MAX_LINE] = {0};\n\n    if (entry && fp) {\n        memset(string, 0, CONFIG_MAX_LINE);\n        snprintf(string, CONFIG_MAX_LINE, \"entry_logical_pos:%lld\\n\", entry->logical_pos);\n        fwrite(string, strlen(string), 1, fp);\n\n        memset(string, 0, CONFIG_MAX_LINE);\n        snprintf(string, CONFIG_MAX_LINE, \"entry_physical_pos:%lld\\n\", entry->physical_pos);\n        fwrite(string, strlen(string), 1, fp);\n\n        memset(string, 0, CONFIG_MAX_LINE);\n        snprintf(string, CONFIG_MAX_LINE, \"entry_size:%lld\\n\", entry->size);\n        fwrite(string, strlen(string), 1, fp);\n\n        memset(string, 0, CONFIG_MAX_LINE);\n        snprintf(string, CONFIG_MAX_LINE, \"entry-info-flush\\n\");\n        fwrite(string, strlen(string), 1, fp);\n    }\n    return 0;\n}\n\nstatic int ijkio_manager_save_tree_to_file(void *parm, int64_t key, void *elem)\n{\n    IjkCacheTreeInfo *info = elem;\n    FILE *fp = parm;\n    char string[CONFIG_MAX_LINE] = {0};\n    if (key >= 0 && info) {\n        memset(string, 0, CONFIG_MAX_LINE);\n        snprintf(string, CONFIG_MAX_LINE, \"tree_index:%lld\\n\", key);\n        fwrite(string, strlen(string), 1, fp);\n\n        memset(string, 0, CONFIG_MAX_LINE);\n        snprintf(string, CONFIG_MAX_LINE, \"tree_physical_init_pos:%lld\\n\", info->physical_init_pos);\n        fwrite(string, strlen(string), 1, fp);\n\n        memset(string, 0, CONFIG_MAX_LINE);\n        snprintf(string, CONFIG_MAX_LINE, \"tree_physical_size:%lld\\n\", info->physical_size);\n        fwrite(string, strlen(string), 1, fp);\n\n        memset(string, 0, CONFIG_MAX_LINE);\n        snprintf(string, CONFIG_MAX_LINE, \"tree_file_size:%lld\\n\", info->file_size);\n        fwrite(string, strlen(string), 1, fp);\n\n        memset(string, 0, CONFIG_MAX_LINE);\n        snprintf(string, CONFIG_MAX_LINE, \"tree-info-flush\\n\");\n        fwrite(string, strlen(string), 1, fp);\n\n        ijk_av_tree_enumerate(info->root, parm, NULL, enu_save);\n    }\n    return 0;\n}\n\nvoid ijkio_manager_destroy(IjkIOManagerContext *h)\n{\n    FILE *map_tree_info_fp = NULL;\n\n    if (h->ijkio_app_ctx) {\n        if (h->auto_save_map) {\n            map_tree_info_fp = fopen(h->cache_map_path, \"w\");\n            if (map_tree_info_fp) {\n                ijk_map_traversal_handle(h->ijkio_app_ctx->cache_info_map, map_tree_info_fp, ijkio_manager_save_tree_to_file);\n                fclose(map_tree_info_fp);\n            }\n        }\n\n        ijk_map_traversal_handle(h->ijkio_app_ctx->cache_info_map, NULL, tree_destroy);\n        ijk_map_destroy(h->ijkio_app_ctx->cache_info_map);\n        h->ijkio_app_ctx->cache_info_map = NULL;\n\n        if (h->ijkio_app_ctx->threadpool_ctx) {\n            ijk_threadpool_destroy(h->ijkio_app_ctx->threadpool_ctx, IJK_IMMEDIATE_SHUTDOWN);\n        }\n\n        if (0 != strlen(h->ijkio_app_ctx->cache_file_path)) {\n            if (h->ijkio_app_ctx->fd >= 0) {\n                close(h->ijkio_app_ctx->fd);\n            }\n        }\n        pthread_mutex_destroy(&h->ijkio_app_ctx->mutex);\n\n        ijkio_application_closep(&h->ijkio_app_ctx);\n    }\n\n    ijk_map_destroy(h->ijk_ctx_map);\n    h->ijk_ctx_map = NULL;\n\n    free(h);\n}\n\nvoid ijkio_manager_destroyp(IjkIOManagerContext **ph)\n{\n    if (!ph || !*ph)\n        return;\n\n    ijkio_manager_destroy(*ph);\n    *ph = NULL;\n}\n\nint ijkio_manager_set_callback(IjkIOManagerContext *h, void *callback) {\n    if (!h)\n        return -1;\n\n    h->ijkio_app_ctx->func_ijkio_on_app_event = callback;\n\n    return 0;\n}\n\n\n\nstatic void ijkio_manager_set_all_ctx_pause(IjkIOManagerContext *h) {\n    IjkURLContext *url_ctx;\n    int size = ijk_map_size(h->ijk_ctx_map);\n\n    for(int i = 0; i < size; i++) {\n        url_ctx = ijk_map_index_get(h->ijk_ctx_map, i);\n        if (url_ctx == NULL || url_ctx->prot == NULL)\n            break;\n\n        if (url_ctx->prot->url_pause)\n            url_ctx->prot->url_pause(url_ctx);\n        url_ctx->state = IJKURL_PAUSED;\n    }\n}\n\nstatic int cmp(const void *key, const void *node)\n{\n    return FFDIFFSIGN(*(const int64_t *)key, ((const IjkCacheEntry *) node)->logical_pos);\n}\n\nstatic void ijkio_manager_parse_cache_info(IjkIOApplicationContext *app_ctx, char *file_path) {\n    char string_line[CONFIG_MAX_LINE] = {0};\n    char **ptr = (char **)&string_line;\n    uint64_t str_len                = 0;\n    int tree_index                  = 0;\n    int64_t tree_physical_init_pos  = 0;\n    int64_t tree_physical_size      = 0;\n    int64_t tree_file_size          = 0;\n    int64_t entry_logical_pos       = 0;\n    int64_t entry_physical_pos      = 0;\n    int64_t entry_size              = 0;\n    void *cache_info_map            = app_ctx->cache_info_map;\n    IjkCacheTreeInfo *cur_tree_info = NULL;\n    IjkCacheEntry *cur_entry        = NULL;\n    IjkCacheEntry *entry_ret        = NULL;\n    struct IjkAVTreeNode *cur_node  = NULL;\n\n    FILE *fp = fopen(file_path, \"r\");\n    if (!fp) {\n        return;\n    }\n\n    while (!feof(fp)) {\n        memset(string_line, 0 , CONFIG_MAX_LINE);\n        fgets(string_line, CONFIG_MAX_LINE, fp);\n\n        av_log(NULL, AV_LOG_INFO, \"cache config info: %s\\n\", string_line);\n\n        if (ijk_av_strstart(string_line, \"tree_index:\", (const char **)ptr)) {\n            str_len = strlen(*ptr);\n            for (int i = 0; i < str_len; i++) {\n                if ((*ptr)[i] < '0' || (*ptr)[i] > '9') {\n                    (*ptr)[i] = '\\0';\n                    break;\n                }\n            }\n            tree_index = (int)strtol(*ptr, NULL, 10);\n        } else if (ijk_av_strstart(string_line, \"tree_physical_init_pos:\", (const char **)ptr)) {\n            str_len = strlen(*ptr);\n            for (int i = 0; i < str_len; i++) {\n                if ((*ptr)[i] < '0' || (*ptr)[i] > '9') {\n                    (*ptr)[i] = '\\0';\n                    break;\n                }\n            }\n            tree_physical_init_pos = strtoll(*ptr, NULL, 10);\n        } else if (ijk_av_strstart(string_line, \"tree_physical_size:\", (const char **)ptr)) {\n            str_len = strlen(*ptr);\n            for (int i = 0; i < str_len; i++) {\n                if ((*ptr)[i] < '0' || (*ptr)[i] > '9') {\n                    (*ptr)[i] = '\\0';\n                    break;\n                }\n            }\n            tree_physical_size = strtoll(*ptr, NULL, 10);\n            app_ctx->last_physical_pos += tree_physical_size;\n        } else if (ijk_av_strstart(string_line, \"tree_file_size:\", (const char **)ptr)) {\n            str_len = strlen(*ptr);\n            for (int i = 0; i < str_len; i++) {\n                if ((*ptr)[i] < '0' || (*ptr)[i] > '9') {\n                    (*ptr)[i] = '\\0';\n                    break;\n                }\n            }\n            tree_file_size = strtoll(*ptr, NULL, 10);\n        } else if (ijk_av_strstart(string_line, \"tree-info-flush\", (const char **)ptr)) {\n            cur_tree_info = calloc(1, sizeof(IjkCacheTreeInfo));\n            if (cur_tree_info) {\n                cur_tree_info->physical_init_pos  = tree_physical_init_pos;\n                cur_tree_info->physical_size      = tree_physical_size;\n                cur_tree_info->file_size          = tree_file_size;\n                ijk_map_put(cache_info_map, tree_index, cur_tree_info);\n            } else {\n                break;\n            }\n            tree_index             = 0;\n            tree_physical_init_pos = 0;\n            tree_physical_size     = 0;\n            tree_file_size         = 0;\n        } else if (ijk_av_strstart(string_line, \"entry_logical_pos:\", (const char **)ptr)) {\n            str_len = strlen(*ptr);\n            for (int i = 0; i < str_len; i++) {\n                if ((*ptr)[i] < '0' || (*ptr)[i] > '9') {\n                    (*ptr)[i] = '\\0';\n                    break;\n                }\n            }\n            entry_logical_pos = strtoll(*ptr, NULL, 10);\n        } else if (ijk_av_strstart(string_line, \"entry_physical_pos:\", (const char **)ptr)) {\n            str_len = strlen(*ptr);\n            for (int i = 0; i < str_len; i++) {\n                if ((*ptr)[i] < '0' || (*ptr)[i] > '9') {\n                    (*ptr)[i] = '\\0';\n                    break;\n                }\n            }\n            entry_physical_pos = strtoll(*ptr, NULL, 10);\n        } else if (ijk_av_strstart(string_line, \"entry_size:\", (const char **)ptr)) {\n            str_len = strlen(*ptr);\n            for (int i = 0; i < str_len; i++) {\n                if ((*ptr)[i] < '0' || (*ptr)[i] > '9') {\n                    (*ptr)[i] = '\\0';\n                    break;\n                }\n            }\n            entry_size = strtoll(*ptr, NULL, 10);\n        } else if (ijk_av_strstart(string_line, \"entry-info-flush\", (const char **)ptr)) {\n            if (cur_tree_info) {\n                cur_entry = calloc(1, sizeof(IjkCacheEntry));\n                cur_node  = ijk_av_tree_node_alloc();\n                if (!cur_entry || !cur_node) {\n                    break;\n                }\n\n                cur_entry->logical_pos  = entry_logical_pos;\n                cur_entry->physical_pos = entry_physical_pos;\n                cur_entry->size         = entry_size;\n\n                entry_ret = ijk_av_tree_insert(&cur_tree_info->root, cur_entry, cmp, &cur_node);\n                if (entry_ret && entry_ret != cur_entry) {\n                    break;\n                }\n            }\n        }\n    }\n\n    fclose(fp);\n}\n\nvoid ijkio_manager_will_share_cache_map(IjkIOManagerContext *h) {\n    av_log(NULL, AV_LOG_INFO, \"will share cache\\n\");\n    if (!h || !h->ijkio_app_ctx || !strlen(h->cache_map_path)) {\n        return;\n    }\n\n    pthread_mutex_lock(&h->ijkio_app_ctx->mutex);\n    FILE *map_tree_info_fp = fopen(h->cache_map_path, \"w\");\n    if (!map_tree_info_fp) {\n        pthread_mutex_unlock(&h->ijkio_app_ctx->mutex);\n        return;\n    }\n    h->ijkio_app_ctx->shared = 1;\n    ijk_map_traversal_handle(h->ijkio_app_ctx->cache_info_map, map_tree_info_fp, ijkio_manager_save_tree_to_file);\n    fclose(map_tree_info_fp);\n    if (h->ijkio_app_ctx->fd >= 0) {\n        fsync(h->ijkio_app_ctx->fd);\n    }\n    pthread_mutex_unlock(&h->ijkio_app_ctx->mutex);\n}\n\nvoid ijkio_manager_immediate_reconnect(IjkIOManagerContext *h) {\n    av_log(NULL, AV_LOG_INFO, \"ijkio manager immediate reconnect\\n\");\n    if (!h || !h->ijkio_app_ctx) {\n        return;\n    }\n    h->ijkio_app_ctx->active_reconnect = 1;\n}\n\nvoid ijkio_manager_did_share_cache_map(IjkIOManagerContext *h) {\n    av_log(NULL, AV_LOG_INFO, \"did share cache\\n\");\n    if (!h || !h->ijkio_app_ctx) {\n        return;\n    }\n    pthread_mutex_lock(&h->ijkio_app_ctx->mutex);\n    h->ijkio_app_ctx->shared = 0;\n    pthread_mutex_unlock(&h->ijkio_app_ctx->mutex);\n}\n\nint ijkio_manager_io_open(IjkIOManagerContext *h, const char *url, int flags, IjkAVDictionary **options) {\n    int ret = -1;\n    int parse_cache_map_file = 0;\n    if (!h)\n        return ret;\n\n    if (!h->ijkio_app_ctx) {\n        return -1;\n    }\n\n    IjkAVDictionaryEntry *t = NULL;\n    t = ijk_av_dict_get(*options, \"cache_file_path\", NULL, IJK_AV_DICT_MATCH_CASE);\n    if (t) {\n        strcpy(h->ijkio_app_ctx->cache_file_path, t->value);\n    }\n\n    t = ijk_av_dict_get(*options, \"cache_map_path\", NULL, IJK_AV_DICT_MATCH_CASE);\n    if (t) {\n        strcpy(h->cache_map_path, t->value);\n\n        t = ijk_av_dict_get(*options, \"auto_save_map\", NULL, IJK_AV_DICT_MATCH_CASE);\n        if (t) {\n            h->auto_save_map = (int)strtol(t->value, NULL, 10);\n        }\n\n        if (h->ijkio_app_ctx->cache_info_map && !ijk_map_size(h->ijkio_app_ctx->cache_info_map)) {\n            t = ijk_av_dict_get(*options, \"parse_cache_map\", NULL, IJK_AV_DICT_MATCH_CASE);\n            if (t) {\n                parse_cache_map_file = (int)strtol(t->value, NULL, 10);\n                if (parse_cache_map_file) {\n                    ijkio_manager_parse_cache_info(h->ijkio_app_ctx, h->cache_map_path);\n                }\n            }\n        }\n    }\n\n    h->ijkio_app_ctx->ijkio_interrupt_callback = h->ijkio_interrupt_callback;\n\n    IjkURLContext *inner = NULL;\n    ijkio_alloc_url(&inner, url);\n    if (inner) {\n        inner->ijkio_app_ctx = h->ijkio_app_ctx;\n        if (h->ijk_ctx_map) {\n            ijkio_manager_set_all_ctx_pause(h);\n            inner->state = IJKURL_STARTED;\n            ijk_map_put(h->ijk_ctx_map, (int64_t)(intptr_t)h->cur_ffmpeg_ctx, inner);\n        }\n        ret = inner->prot->url_open2(inner, url, flags, options);\n        if (ret != 0)\n            goto fail;\n\n        return ret;\n    }\n\nfail:\n    if (inner) {\n        if (inner->prot && inner->prot->url_close)\n            ret = inner->prot->url_close(inner);\n\n        if (h->ijk_ctx_map) {\n            ijk_map_remove(h->ijk_ctx_map, (int64_t)(intptr_t)h->cur_ffmpeg_ctx);\n        }\n        ijk_av_freep(&inner->priv_data);\n        ijk_av_freep(&inner);\n    }\n    return -1;\n}\n\nint ijkio_manager_io_read(IjkIOManagerContext *h, unsigned char *buf, int size) {\n    int ret = -1;\n    if (!h)\n        return ret;\n\n    IjkURLContext *inner = ijk_map_get(h->ijk_ctx_map, (int64_t)(intptr_t)h->cur_ffmpeg_ctx);\n    if (inner && inner->prot && inner->prot->url_read) {\n        if (inner->state == IJKURL_PAUSED) {\n            if (inner->prot->url_resume) {\n                ret = inner->prot->url_resume(inner);\n                if (ret != 0) {\n                    return ret;\n                }\n            }\n            inner->state = IJKURL_STARTED;\n        }\n        ret = inner->prot->url_read(inner, buf, size);\n    }\n\n    return ret;\n}\n\nint64_t ijkio_manager_io_seek(IjkIOManagerContext *h, int64_t offset, int whence) {\n    int64_t ret = -1;\n\n    if (!h)\n        return ret;\n\n    IjkURLContext *inner = ijk_map_get(h->ijk_ctx_map, (int64_t)(intptr_t)h->cur_ffmpeg_ctx);\n    if (inner && inner->prot && inner->prot->url_seek) {\n        if (inner->state == IJKURL_PAUSED) {\n            if (inner->prot->url_resume) {\n                ret = (int64_t)inner->prot->url_resume(inner);\n                if (ret < 0) {\n                    return ret;\n                }\n            }\n            inner->state = IJKURL_STARTED;\n        }\n        ret = inner->prot->url_seek(inner, offset, whence & ~IJKAVSEEK_FORCE);\n    }\n\n    return ret;\n}\n\nint ijkio_manager_io_close(IjkIOManagerContext *h) {\n    int ret = -1;\n    if (!h)\n        return ret;\n\n    IjkURLContext *inner = ijk_map_get(h->ijk_ctx_map, (int64_t)(intptr_t)h->cur_ffmpeg_ctx);\n    if (inner) {\n        if (inner->prot && inner->prot->url_close) {\n            ret = inner->prot->url_close(inner);\n        }\n        ijk_map_remove(h->ijk_ctx_map, (int64_t)(intptr_t)h->cur_ffmpeg_ctx);\n        ijk_av_freep(&inner->priv_data);\n        ijk_av_freep(&inner);\n    }\n\n    return ret;\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavformat/ijkiomanager.h",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * Copyright (c) 2016 Raymond Zheng <raymondzheng1412@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKAVFORMAT_IJKIOMANAGER_H\n#define IJKAVFORMAT_IJKIOMANAGER_H\n\n#include \"ijkiourl.h\"\n#include \"ijkioapplication.h\"\n\n#include <stdint.h>\n\n#define CACHE_MAP_PATH_MAX_LEN        512\ntypedef struct IjkIOManagerContext IjkIOManagerContext;\nstruct IjkIOManagerContext {\n    IjkAVIOInterruptCB *ijkio_interrupt_callback;\n    IjkIOApplicationContext *ijkio_app_ctx;\n    int auto_save_map;\n    void *cur_ffmpeg_ctx;\n    void *ijk_ctx_map;\n    void *opaque;\n    char cache_map_path[CACHE_MAP_PATH_MAX_LEN];\n};\n\nint ijkio_manager_create(IjkIOManagerContext **ph, void *opaque);\nvoid ijkio_manager_destroy(IjkIOManagerContext *h);\nvoid ijkio_manager_destroyp(IjkIOManagerContext **ph);\nint ijkio_manager_set_callback(IjkIOManagerContext *h, void *callback);\nvoid ijkio_manager_will_share_cache_map(IjkIOManagerContext *h);\nvoid ijkio_manager_did_share_cache_map(IjkIOManagerContext *h);\nvoid ijkio_manager_immediate_reconnect(IjkIOManagerContext *h);\n\nint ijkio_manager_io_open(IjkIOManagerContext *h, const char *url, int flags, IjkAVDictionary **options);\nint ijkio_manager_io_read(IjkIOManagerContext *h, unsigned char *buf, int size);\nint64_t ijkio_manager_io_seek(IjkIOManagerContext *h, int64_t offset, int whence);\nint ijkio_manager_io_close(IjkIOManagerContext *h);\n\n#endif  // IJKAVFORMAT_IJKIOMANAGER_H\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavformat/ijkioprotocol.c",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * Copyright (c) 2016 Raymond Zheng <raymondzheng1412@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n#include \"ijkioprotocol.h\"\n#include <stdlib.h>\n#include <string.h>\n\nextern IjkURLProtocol ijkio_ffio_protocol;\n#ifdef __ANDROID__\nextern IjkURLProtocol ijkio_androidio_protocol;\n#endif\nextern IjkURLProtocol ijkio_cache_protocol;\nextern IjkURLProtocol ijkio_httphook_protocol;\n\nint ijkio_alloc_url(IjkURLContext **ph, const char *url) {\n    if (!ph) {\n        return -1;\n    }\n\n    IjkURLContext *h = NULL;\n    if (!strncmp(url, \"cache:\", strlen(\"cache:\"))) {\n        h = (IjkURLContext *)calloc(1, sizeof(IjkURLContext));\n        h->prot = &ijkio_cache_protocol;\n        h->priv_data = calloc(1, ijkio_cache_protocol.priv_data_size);\n    } else if (!strncmp(url, \"ffio:\", strlen(\"ffio:\"))) {\n        h = (IjkURLContext *)calloc(1, sizeof(IjkURLContext));\n        h->prot = &ijkio_ffio_protocol;\n        h->priv_data = calloc(1, ijkio_ffio_protocol.priv_data_size);\n    } else if (!strncmp(url, \"httphook:\", strlen(\"httphook:\"))) {\n        h = (IjkURLContext *)calloc(1, sizeof(IjkURLContext));\n        h->prot = &ijkio_httphook_protocol;\n        h->priv_data = calloc(1, ijkio_httphook_protocol.priv_data_size);\n    }\n#ifdef __ANDROID__\n      else if (!strncmp(url, \"androidio:\", strlen(\"androidio:\"))) {\n        h = (IjkURLContext *)calloc(1, sizeof(IjkURLContext));\n        h->prot = &ijkio_androidio_protocol;\n        h->priv_data = calloc(1, ijkio_androidio_protocol.priv_data_size);\n    }\n#endif\n      else {\n        return -1;\n    }\n\n    *ph = h;\n\n    return 0;\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavformat/ijkioprotocol.h",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * Copyright (c) 2016 Raymond Zheng <raymondzheng1412@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n#include \"ijkiourl.h\"\n\nint ijkio_alloc_url(IjkURLContext **inner, const char *url);\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavformat/ijkiourl.h",
    "content": "/*\n * This file is part of ijkplayer.\n *\n * ijkplayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkplayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n/**\n * @file\n * unbuffered private I/O API\n */\n\n#ifndef IJKAVFORMAT_IJKIOURL_H\n#define IJKAVFORMAT_IJKIOURL_H\n\n#include <stdint.h>\n#include \"ijkplayer/ijkavutil/ijkdict.h\"\n#include \"ijkioapplication.h\"\n\nstruct IjkURLProtocol;\n\n#define IJKURL_PAUSED  0x10\n#define IJKURL_STARTED 0x20\n\ntypedef struct IjkURLContext {\n    const struct IjkURLProtocol *prot;\n    IjkIOApplicationContext *ijkio_app_ctx;\n    int state;\n    void *priv_data;\n} IjkURLContext;\n\ntypedef struct IjkURLProtocol {\n    const char *name;\n    int     (*url_open2)(IjkURLContext *h, const char *url, int flags, IjkAVDictionary **options);\n    int     (*url_read)( IjkURLContext *h, unsigned char *buf, int size);\n    int64_t (*url_seek)( IjkURLContext *h, int64_t pos, int whence);\n    int     (*url_close)(IjkURLContext *h);\n    int     (*url_pause)(IjkURLContext *h);  // option\n    int     (*url_resume)(IjkURLContext *h);  // option\n    int priv_data_size;\n    int flags;\n} IjkURLProtocol;\n\n#endif  // IJKAVFORMAT_IJKIOURL_H\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavformat/ijkiourlhook.c",
    "content": "/*\n * Copyright (c) 2015 Bilibili\n * Copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include <assert.h>\n#include \"ijkiourl.h\"\n#include \"ijkioprotocol.h\"\n#include \"ijkplayer/ijkavutil/ijkutils.h\"\n#include \"libavutil/log.h\"\n\n#include \"libavutil/application.h\"\n\ntypedef struct Context {\n    IjkURLContext   *inner;\n\n    int64_t         logical_pos;\n    int64_t         logical_size;\n    int             io_error;\n\n    AVAppIOControl  app_io_ctrl;\n    const char     *scheme;\n    const char     *inner_scheme;\n    IjkAVIOInterruptCB *ijkio_interrupt_callback;\n\n    /* options */\n    int             inner_flags;\n    IjkAVDictionary *inner_options;\n    int             segment_index;\n    int64_t         test_fail_point;\n    int64_t         test_fail_point_next;\n    int             abort_request;\n    AVApplicationContext *app_ctx;\n    IjkIOApplicationContext *ijkio_app_ctx;\n} Context;\n\nstatic int ijkio_cache_check_interrupt(IjkURLContext *h)\n{\n    Context *c = h->priv_data;\n    if (!c)\n        return 1;\n\n    if (c->abort_request)\n        return 1;\n\n    if (c->ijkio_interrupt_callback && c->ijkio_interrupt_callback->callback &&\n                    c->ijkio_interrupt_callback->callback(c->ijkio_interrupt_callback->opaque)) {\n        c->abort_request = 1;\n    }\n\n    if (c->abort_request)\n        return 1;\n\n    return c->abort_request;\n}\n\nstatic int ijkio_urlhook_call_inject(IjkURLContext *h)\n{\n    Context *c = h->priv_data;\n    int ret = 0;\n\n    if (ijkio_cache_check_interrupt(h)) {\n        ret = IJKAVERROR_EXIT;\n        goto fail;\n    }\n\n    if (c->app_ctx) {\n        AVAppIOControl control_data_backup = c->app_io_ctrl;\n\n        c->app_io_ctrl.is_handled = 0;\n        c->app_io_ctrl.is_url_changed = 0;\n        ret = av_application_on_io_control(c->app_ctx, AVAPP_CTRL_WILL_HTTP_OPEN, &c->app_io_ctrl);\n        if (ret || !c->app_io_ctrl.url[0]) {\n            ret = IJKAVERROR_EXIT;\n            goto fail;\n        }\n\n        AVAppIOControl user_control_data = c->app_io_ctrl;\n        if (strncmp(c->app_io_ctrl.url, \"ffio:\", strlen(\"ffio:\"))) {\n            snprintf(c->app_io_ctrl.url, sizeof(c->app_io_ctrl.url), \"%s%s\", \"ffio:\", user_control_data.url);\n        }\n\n        if (!c->app_io_ctrl.is_url_changed && strcmp(control_data_backup.url, c->app_io_ctrl.url)) {\n            // force a url compare\n            c->app_io_ctrl.is_url_changed = 1;\n        }\n\n        av_log(NULL, AV_LOG_INFO, \"%s %s (%s)\\n\", h->prot->name, c->app_io_ctrl.url, c->app_io_ctrl.is_url_changed ? \"changed\" : \"remain\");\n    }\n\n    if (ijkio_cache_check_interrupt(h)) {\n        ret = IJKAVERROR_EXIT;\n        av_log(NULL, AV_LOG_ERROR, \"%s %s (%s)\\n\", h->prot->name, c->app_io_ctrl.url, c->app_io_ctrl.is_url_changed ? \"changed\" : \"remain\");\n        goto fail;\n    }\n\nfail:\n    return ret;\n}\n\nstatic int ijkio_urlhook_reconnect(IjkURLContext *h, IjkAVDictionary *extra)\n{\n    Context *c = h->priv_data;\n    int ret = 0;\n    IjkURLContext *new_url = NULL;\n    IjkAVDictionary *inner_options = NULL;\n\n    c->test_fail_point_next += c->test_fail_point;\n\n    assert(c->inner_options);\n    ijk_av_dict_copy(&inner_options, c->inner_options, 0);\n    if (extra)\n        ijk_av_dict_copy(&inner_options, extra, 0);\n\n    ret = ijkio_alloc_url(&new_url, c->app_io_ctrl.url);\n    new_url->ijkio_app_ctx = c->ijkio_app_ctx;\n    if (ret)\n        goto fail0;\n\n    ret = new_url->prot->url_open2(new_url, c->app_io_ctrl.url, c->inner_flags, &inner_options);\n    if (ret)\n        goto fail1;\n\n    if (c->inner) {\n        c->inner->prot->url_close(c->inner);\n        ijk_av_freep(&c->inner->priv_data);\n        ijk_av_freep(&c->inner);\n    }\n\n    c->inner        = new_url;\n    c->logical_pos  = c->inner->prot->url_seek(c->inner, 0, SEEK_CUR);\n    c->logical_size = c->inner->prot->url_seek(c->inner, 0, IJKAVSEEK_SIZE);\n    c->io_error     = 0;\n    if (inner_options) {\n        ijk_av_dict_free(&inner_options);\n    }\n    return ret;\n\nfail1:\n    ijk_av_freep(&new_url->priv_data);\n    ijk_av_freep(&new_url);\nfail0:\n    if (inner_options) {\n        ijk_av_dict_free(&inner_options);\n    }\n    return ret;\n}\n\nstatic int ijkio_urlhook_init(IjkURLContext *h, const char *arg, int flags, IjkAVDictionary **options)\n{\n    Context *c = h->priv_data;\n    int ret = 0;\n\n    // ijk_av_strstart(arg, c->scheme, &arg);\n\n    c->inner_flags = flags;\n\n    if (options)\n        ijk_av_dict_copy(&c->inner_options, *options, 0);\n\n    ijk_av_dict_set_intptr(&c->inner_options, \"ijkapplication\", (uintptr_t )c->app_ctx, 0);\n    ijk_av_dict_set_int(&c->inner_options, \"ijkinject-segment-index\", c->segment_index, 0);\n\n    c->app_io_ctrl.size = sizeof(c->app_io_ctrl);\n    c->app_io_ctrl.segment_index = c->segment_index;\n    c->app_io_ctrl.retry_counter = 0;\n\n    snprintf(c->app_io_ctrl.url, sizeof(c->app_io_ctrl.url), \"%s\", arg);\n\n    return ret;\n}\n\nstatic int ijkio_httphook_close(IjkURLContext *h)\n{\n    Context *c = h->priv_data;\n    int ret = 0;\n    if (!c || !c->inner || !c->inner->prot)\n        return IJKAVERROR(ENOSYS);\n\n    ret = c->inner->prot->url_close(c->inner);\n    if (c->inner_options) {\n        ijk_av_dict_free(&c->inner_options);\n    }\n    ijk_av_freep(&c->inner->priv_data);\n    ijk_av_freep(&c->inner);\n\n    return ret;\n}\n\nstatic int ijkio_urlhook_read(IjkURLContext *h, unsigned char *buf, int size)\n{\n    Context *c = h->priv_data;\n    int ret = 0;\n\n    if (c->io_error < 0)\n        return c->io_error;\n\n    if (c->test_fail_point_next > 0 && c->logical_pos >= c->test_fail_point_next) {\n        av_log(NULL, AV_LOG_ERROR, \"test fail point:%\"PRId64\"\\n\", c->test_fail_point_next);\n        c->io_error = IJKAVERROR(EIO);\n        return IJKAVERROR(EIO);\n    }\n\n    ret = c->inner->prot->url_read(c->inner, buf, size);\n    if (ret > 0)\n        c->logical_pos += ret;\n    else\n        c->io_error = ret;\n\n    return ret;\n}\n\nstatic int64_t ijkio_urlhook_seek(IjkURLContext *h, int64_t pos, int whence)\n{\n    Context *c = h->priv_data;\n    int64_t seek_ret = 0;\n\n    seek_ret = c->inner->prot->url_seek(c->inner, pos, whence);\n    if (seek_ret < 0) {\n        c->io_error = (int)seek_ret;\n        return seek_ret;\n    }\n\n    c->logical_pos = seek_ret;\n    if (c->test_fail_point)\n        c->test_fail_point_next = c->logical_pos + c->test_fail_point;\n\n    c->io_error = 0;\n    return seek_ret;\n}\n\nstatic int ijkio_httphook_reconnect_at(IjkURLContext *h, int64_t offset)\n{\n    int ret = 0;\n    IjkAVDictionary *extra_opts = NULL;\n\n    ijk_av_dict_set_int(&extra_opts, \"offset\", offset, 0);\n    ijk_av_dict_set_int(&extra_opts, \"dns_cache_clear\", 1, 0);\n    ret = ijkio_urlhook_reconnect(h, extra_opts);\n    ijk_av_dict_free(&extra_opts);\n    return ret;\n}\n\nstatic int ijkio_httphook_open(IjkURLContext *h, const char *arg, int flags, IjkAVDictionary **options)\n{\n    Context *c = h->priv_data;\n    int ret = 0;\n    IjkAVDictionaryEntry *t = NULL;\n    c->ijkio_app_ctx = h->ijkio_app_ctx;\n    c->ijkio_interrupt_callback = h->ijkio_app_ctx->ijkio_interrupt_callback;\n\n    c->app_ctx = (AVApplicationContext *)ijk_av_dict_get_intptr(*options, \"ijkapplication\");\n\n    if (!c->app_ctx) {\n        goto fail;\n    }\n\n    t = ijk_av_dict_get(*options, \"ijkinject-segment-index\", NULL, IJK_AV_DICT_MATCH_CASE);\n    if (t) {\n        c->segment_index = (int)strtoll(t->value, NULL, 10);\n    }\n\n    t = ijk_av_dict_get(*options, \"ijkhttphook-test-fail-point\", NULL, IJK_AV_DICT_MATCH_CASE);\n    if (t) {\n        c->test_fail_point = (int64_t)strtoll(t->value, NULL, 10);\n    }\n    ijk_av_strstart(arg, \"httphook:\", &arg);\n    ret = ijkio_urlhook_init(h, arg, flags, options);\n    if (ret)\n        goto fail;\n\n    ret = ijkio_urlhook_call_inject(h);\n    if (ret)\n        goto fail;\n\n    ret = ijkio_urlhook_reconnect(h, NULL);\n\n    while (ret && c->abort_request == 0) {\n        int inject_ret = 0;\n\n        switch (ret) {\n            case IJKAVERROR_EXIT:\n                goto fail;\n        }\n\n        c->app_io_ctrl.retry_counter++;\n        inject_ret = ijkio_urlhook_call_inject(h);\n        if (inject_ret) {\n            ret = IJKAVERROR_EXIT;\n            goto fail;\n        }\n\n        if (!c->app_io_ctrl.is_handled)\n            goto fail;\n\n        av_log(NULL, AV_LOG_INFO, \"%s: will reconnect at start\\n\", __func__);\n        ret = ijkio_httphook_reconnect_at(h, 0);\n        av_log(NULL, AV_LOG_INFO, \"%s: did reconnect at start: %d\\n\", __func__, ret);\n    }\n\nfail:\n    return ret;\n}\n\nstatic int ijkio_httphook_read(IjkURLContext *h, unsigned char *buf, int size)\n{\n    Context *c = h->priv_data;\n    int ret = 0;\n    int active_reconnect = c->ijkio_app_ctx->active_reconnect;\n\n    c->app_io_ctrl.retry_counter = 0;\n\n    if (active_reconnect == 0) {\n        ret = ijkio_urlhook_read(h, buf, size);\n    }\n\n    while ((active_reconnect || ret < 0) && c->logical_pos < c->logical_size && c->abort_request == 0) {\n        switch (ret) {\n            case IJKAVERROR_EXIT:\n                goto fail;\n        }\n\n        c->app_io_ctrl.retry_counter++;\n        ret = ijkio_urlhook_call_inject(h);\n        c->ijkio_app_ctx->active_reconnect = active_reconnect = 0;\n        if (ret)\n            goto fail;\n\n        if (!c->app_io_ctrl.is_handled)\n            goto fail;\n\n        av_log(NULL, AV_LOG_INFO, \"%s: will reconnect(%d) at %\"PRId64\"\\n\", __func__, c->app_io_ctrl.retry_counter, c->logical_pos);\n        ret = ijkio_httphook_reconnect_at(h, c->logical_pos);\n        av_log(NULL, AV_LOG_INFO, \"%s: did reconnect(%d) at %\"PRId64\": %d\\n\", __func__, c->app_io_ctrl.retry_counter, c->logical_pos, ret);\n        if (ret < 0)\n            continue;\n\n        ret = ijkio_urlhook_read(h, buf, size);\n    }\n\nfail:\n    if (ret <= 0) {\n        c->io_error = ret;\n    }\n    return ret;\n}\n\nstatic int64_t ijkio_httphook_reseek_at(IjkURLContext *h, int64_t pos, int whence, int force_reconnect)\n{\n    Context *c = h->priv_data;\n    int ret = 0;\n\n    if (!force_reconnect)\n        return ijkio_urlhook_seek(h, pos, whence);\n\n    if (whence == SEEK_CUR)\n        pos += c->logical_pos;\n    else if (whence == SEEK_END)\n        pos += c->logical_size;\n    else if (whence != SEEK_SET)\n        return IJKAVERROR(EINVAL);\n    if (pos < 0)\n        return IJKAVERROR(EINVAL);\n\n    ret = ijkio_httphook_reconnect_at(h, pos);\n    if (ret) {\n        c->io_error = ret;\n        return ret;\n    }\n\n    c->io_error = 0;\n    return c->logical_pos;\n}\n\nstatic int64_t ijkio_httphook_seek(IjkURLContext *h, int64_t pos, int whence)\n{\n    Context *c = h->priv_data;\n    int     ret      = 0;\n    int64_t seek_ret = -1;\n\n    if (whence == IJKAVSEEK_SIZE)\n        return c->logical_size;\n    else if ((whence == SEEK_CUR && pos == 0) ||\n             (whence == SEEK_SET && pos == c->logical_pos))\n        return c->logical_pos;\n    else if ((c->logical_size < 0 && whence == SEEK_END))\n        return IJKAVERROR(ENOSYS);\n\n    c->app_io_ctrl.retry_counter = 0;\n    ret = ijkio_urlhook_call_inject(h);\n    if (ret) {\n        ret = IJKAVERROR_EXIT;\n        goto fail;\n    }\n\n    seek_ret = ijkio_httphook_reseek_at(h, pos, whence, c->app_io_ctrl.is_url_changed);\n    while (seek_ret < 0 && c->abort_request == 0) {\n        switch (seek_ret) {\n            case IJKAVERROR_EXIT:\n            case IJKAVERROR_EOF:\n                goto fail;\n        }\n\n        c->app_io_ctrl.retry_counter++;\n        ret = ijkio_urlhook_call_inject(h);\n        if (ret) {\n            ret = IJKAVERROR_EXIT;\n            goto fail;\n        }\n\n        if (!c->app_io_ctrl.is_handled)\n            goto fail;\n\n        av_log(NULL, AV_LOG_INFO, \"%s: will reseek(%d) at pos=%\"PRId64\", whence=%d\\n\", __func__, c->app_io_ctrl.retry_counter, pos, whence);\n        seek_ret = ijkio_httphook_reseek_at(h, pos, whence, c->app_io_ctrl.is_url_changed);\n        av_log(NULL, AV_LOG_INFO, \"%s: did reseek(%d) at pos=%\"PRId64\", whence=%d: %\"PRId64\"\\n\", __func__, c->app_io_ctrl.retry_counter, pos, whence, seek_ret);\n    }\n\n    if (c->test_fail_point)\n        c->test_fail_point_next = c->logical_pos + c->test_fail_point;\n    c->io_error = 0;\n    if (seek_ret < 0) {\n        return seek_ret;\n    }\n    return c->logical_pos;\nfail:\n    return ret;\n}\n\nstatic int ijkio_httphook_pause(IjkURLContext *h) {\n    Context *c = h->priv_data;\n    int             ret  = 0;\n    if (!c || !c->inner || !c->inner->prot)\n        return IJKAVERROR(ENOSYS);\n    c->abort_request = 1;\n\n    if (c->inner->prot->url_pause) {\n        ret = c->inner->prot->url_pause(c->inner);\n    }\n\n    return ret;\n}\n\nstatic int ijkio_httphook_resume(IjkURLContext *h) {\n    Context *c = h->priv_data;\n    int             ret  = 0;\n    if (!c || !c->inner || !c->inner->prot)\n        return IJKAVERROR(ENOSYS);\n\n    if (c->inner->prot->url_resume) {\n        ret = c->inner->prot->url_resume(c->inner);\n        if (ret != 0) {\n            return ret;\n        }\n    }\n    c->abort_request = 0;\n    return ret;\n}\n\nIjkURLProtocol ijkio_httphook_protocol = {\n    .name                = \"ijkiohttphook\",\n    .url_open2           = ijkio_httphook_open,\n    .url_read            = ijkio_httphook_read,\n    .url_seek            = ijkio_httphook_seek,\n    .url_close           = ijkio_httphook_close,\n    .url_pause           = ijkio_httphook_pause,\n    .url_resume          = ijkio_httphook_resume,\n    .priv_data_size      = sizeof(Context),\n};\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavformat/ijklas.c",
    "content": "/**\n * @file\n * LAS demuxer\n * https://github.com/KwaiVideoTeam/las\n */\n\n#include <errno.h>\n#include <stdlib.h>\n#ifdef __ANDROID__\n#include <sys/prctl.h>\n#endif\n#ifdef __APPLE__\n#include \"TargetConditionals.h\"\n#endif\n#include \"libavutil/avstring.h\"\n#include \"libavutil/avassert.h\"\n#include \"libavutil/intreadwrite.h\"\n#include \"libavutil/mathematics.h\"\n#include \"libavutil/opt.h\"\n#include \"libavutil/dict.h\"\n#include \"libavutil/time.h\"\n#include \"libavformat/avformat.h\"\n#include \"libavformat/url.h\"\n#include \"libavformat/avio_internal.h\"\n#include \"libavformat/id3v2.h\"\n#include \"libavformat/flv.h\"\n\n#include \"ijksdl/ijksdl_thread.h\"\n#include \"ijksdl/ijksdl_mutex.h\"\n#include \"cJSON.h\"\n#include \"ff_ffplay_def.h\"\n\n#include \"ijklas.h\"\n\n#define LAS_ERROR_BASE                        (-30000)\n#define LAS_ERROR_MUTEX_CREATE                (-1 + LAS_ERROR_BASE)\n#define LAS_ERROR_THREAD_CREATE               (-2 + LAS_ERROR_BASE)\n#define LAS_ERROR_MANIFEST_JSON               (-3 + LAS_ERROR_BASE)\n#define LAS_ERROR_ADAPT_CONFIG_JSON           (-4 + LAS_ERROR_BASE)\n#define LAS_ERROR_INVALID_REP_INDEX           (-6 + LAS_ERROR_BASE)\n#define LAS_ERROR_SOCKET_CLOSED_BY_PEER       (-11 + LAS_ERROR_BASE)\n#define LAS_ERROR_GET_WHOLE_TAG               (-12 + LAS_ERROR_BASE)\n#define LAS_ERROR_ABORT_BY_USER               (-14 + LAS_ERROR_BASE)\n#define LAS_ERROR_ABR_HISTORY_DATA_JSON       (-15 + LAS_ERROR_BASE)\n#define LAS_ERROR_COND_CREATE                 (-16 + LAS_ERROR_BASE)\n\n#define INITIAL_BUFFER_SIZE             32768\n\n#define FLV_HEADER_LEN 9\n#define TAG_HEADER_LEN 11\n#define PRE_TAG_SIZE_LEN 4\n\n//las 2.0 Tag based\n#define AV_TAG_HEADER_LEN 16 // 11+1+1+3, 1 bytes for av parameters, 1 bytes for AVCPacketType, 3 bytes for CompositionTime\n#define TIME_ALGO_UPDATE_INTERVAL_MS (500)\n#define INIT_BUFFER_THRESHOLD_MAX_MS (8*1000)\n#define MAX_BUFFER_TIME 10000\n#define MAX_STATE_CNT 30\n#define NALU_HEAD_LEN 4\n#define H264_NAL_SPS 7\n#define H264_NAL_PPS 8\n\ntypedef struct AdaptiveConfig {\n    int32_t buffer_init;\n    double stable_buffer_diff_threshold_second;\n    int32_t stable_buffer_interval_ms;\n    int32_t generate_speed_gap_ms;\n    int32_t buffer_check_interval_ms;\n    double smoothed_speed_utilization_ratio;\n    double small_speed_to_bitrate_ratio;\n    double enough_speed_to_bitrate_ratio;\n    double buffer_lower_limit_second;\n    int32_t recent_buffered_size;\n    double smoothed_speed_ratio;\n} AdaptiveConfig;\n\ntypedef struct MultiRateAdaption {\n    int32_t n_bitrates;\n    int32_t bitrate_table_origin_order[MAX_STREAM_NUM];\n    int32_t disable_adaptive_table[MAX_STREAM_NUM];\n    int32_t next_expected_rep_index;\n    struct PlayList* playlist;\n    unsigned session_id;\n\n    // algorithm related\n    AdaptiveConfig conf;\n    double past_buffer[MAX_STATE_CNT];\n    int64_t buffer_index;\n    int32_t levels[MAX_STREAM_NUM];\n    int32_t current;\n    int64_t stable_buffer_start_time;\n    double generated_speed;\n    double last_check_buffer;\n    int64_t last_speed;\n    int32_t buffer_init;\n} MultiRateAdaption;\n\ntypedef struct FlvTag {\n    uint8_t* buf;\n    uint32_t tag_size;\n    uint32_t buf_write_offset;\n    uint32_t buf_read_offset;\n    uint32_t av_tag_ts;\n    enum FlvTagType type;\n    int rep_index;\n    int audio_only;\n    int switch_index;\n} FlvTag;\n\ntypedef struct Representation {\n    char url[MAX_URL_SIZE];\n    int id;\n    int bitrate;\n    int disabled_from_adaptive;\n    int default_selected;\n    int index;\n} Representation;\n\ntypedef struct AdaptationSet {\n    int duration;\n    Representation* representations[MAX_STREAM_NUM];\n    int n_representation;\n} AdaptationSet;\n\ntypedef struct TagListNode {\n    FlvTag tag;\n    struct TagListNode* next;\n} TagListNode;\n\ntypedef struct TagQueue {\n    TagListNode* first_tag, *last_tag;\n    int nb_tags;\n    uint32_t last_video_ts;\n    int64_t total_tag_bytes;\n    int abort_request;\n    SDL_mutex* mutex;\n    SDL_cond* cond;\n} TagQueue;\n\ntypedef struct GopReader {\n    // real read context\n    char realtime_url[MAX_URL_SIZE];\n    URLContext* input;\n    int abort_request;\n    int64_t last_gop_start_ts;\n\n    int rep_index;\n    int is_audio_only;\n    int switch_index;\n    AVFormatContext* parent;\n} GopReader;\n\ntypedef struct PlayList {\n    struct AdaptationSet adaptation_set;\n    AVFormatContext* outermost_ctx;\n\n    // demuxer related\n    AVFormatContext* parent;\n    uint8_t* read_buffer;\n    AVIOContext pb;\n    AVFormatContext* ctx;\n    AVPacket pkt;\n\n    int cur_rep_index;\n    int cur_switch_index;\n    int stream_index_map[MAX_STREAM_NUM];\n    int error_code;\n    int read_abort_request;\n    SDL_Thread _read_thread;\n    SDL_Thread* read_thread;\n\n    SDL_Thread _algo_thread;\n    SDL_Thread* algo_thread;\n    SDL_cond* algo_cond;\n\n    SDL_mutex* rw_mutex;\n    SDL_mutex* reading_tag_mutex;\n    // las_mutex is privately used inside of #pragma PlayListLock's setters and getters\n    SDL_mutex* las_mutex;\n\n    MultiRateAdaption multi_rate_adaption;\n    GopReader gop_reader;\n    FlvTag reading_tag;\n    TagQueue tag_queue;\n\n    // cur playlist Qos\n    LasStatistic* las_statistic;\n    bool is_stream_ever_opened;\n    int64_t bytes_read;\n    unsigned session_id;\n    FFTrackCacheStatistic* video_cache;\n    FFTrackCacheStatistic* audio_cache;\n} PlayList;\n\ntypedef struct LasContext {\n    AVClass* class;\n    // the outermost context\n    AVFormatContext* ctx;\n\n    AVIOInterruptCB* interrupt_callback;\n    char* user_agent;                    ///< holds HTTP user agent set as an AVOption to the HTTP protocol context\n    char* cookies;                       ///< holds HTTP cookie values set in either the initial response or as an AVOption to the HTTP protocol context\n    char* headers;                       ///< holds HTTP headers set as an AVOption to the HTTP protocol context\n    char* http_proxy;                    ///< holds the address of the HTTP proxy server\n    char* server_ip;                     ///< holds the HTTP server ip\n    char* manifest_string;\n    int64_t network;\n    char* abr_history_data;\n    char* live_adapt_config;\n    AVDictionary* avio_opts;\n\n    // all info of las is in it\n    PlayList playlist;\n    LasStatistic las_statistic;\n    unsigned session_id;\n    int64_t video_cache_ptr;\n    int64_t audio_cache_ptr;\n    int las_switch_mode;\n    int64_t first_audio_packet_pts;\n    int block_duration;\n    int audio_only_request;\n    int audio_only_response;\n    bool stream_reopened;\n} LasContext;\n\n#pragma mark common util\ninline static int64_t get_current_time_ms() {\n    return av_gettime_relative() / 1000;\n}\n\n#pragma mark log util\n#define LOG_THREAD 1\n// ------------------------------------ log util start------------------------------------\nstatic inline void _log(unsigned session_id, const char* func_name, int av_log_level, ...) {\n    va_list args;\n    va_start(args, av_log_level);\n    const char* fmt = va_arg(args, const char*);\n    char tmp[1024] = {0};\n    vsprintf(tmp, fmt, args);\n    va_end(args);\n#if LOG_THREAD\n    av_log(NULL, av_log_level, \"[%u][las][%s] %s\\n\", session_id, func_name, tmp);\n#endif\n}\n\n#define log_debug_tag(session_id, av_log_level, ...) _log(session_id, __func__, av_log_level, __VA_ARGS__)\n#define log_debug(...) log_debug_tag(playlist->session_id, AV_LOG_DEBUG, __VA_ARGS__)\n#define log_info(...) log_debug_tag(playlist->session_id, AV_LOG_INFO, __VA_ARGS__)\n#define log_error(...) log_debug_tag(playlist->session_id, AV_LOG_ERROR, __VA_ARGS__)\n#define algo_debug(...) log_debug_tag(thiz->session_id, AV_LOG_DEBUG, __VA_ARGS__)\n#define algo_info(...) log_debug_tag(thiz->session_id, AV_LOG_INFO, __VA_ARGS__)\n#define algo_error(...) log_debug_tag(thiz->session_id, AV_LOG_ERROR, __VA_ARGS__)\n\n#pragma mark PlayerControl\nint get_switch_mode(AVFormatContext* format) {\n    LasContext* c = format->priv_data;\n    return c->las_switch_mode;\n}\n\nint64_t get_first_audio_packet_pts(AVFormatContext* format) {\n    LasContext* c = format->priv_data;\n    return c->first_audio_packet_pts;\n}\n\nint get_audio_only_request(AVFormatContext* format) {\n    LasContext* c = format->priv_data;\n    return c->audio_only_request;\n}\n\nvoid set_audio_only_response(AVFormatContext* format, int audio_only) {\n    LasContext* c = format->priv_data;\n    c->audio_only_response = audio_only;\n}\n\nvoid set_stream_reopened(AVFormatContext* format, bool stream_reopened) {\n    LasContext* c = format->priv_data;\n    c->stream_reopened = stream_reopened;\n}\n\nint64_t get_cache_duration_ms(FFTrackCacheStatistic* cache) {\n    if (cache) {\n        return cache->duration;\n    }\n    return 0;\n}\n\n#pragma mark PlayListLock\nstatic int64_t get_bytes_read(PlayList* p) {\n    SDL_LockMutex(p->las_mutex);\n    int64_t ret = p->bytes_read;\n    SDL_UnlockMutex(p->las_mutex);\n    return ret;\n}\n\nstatic void add_bytes_read(PlayList* p, int64_t bytes_read) {\n    SDL_LockMutex(p->las_mutex);\n    p->bytes_read += bytes_read;\n    SDL_UnlockMutex(p->las_mutex);\n}\n\nstatic void algo_cond_wait(PlayList* p) {\n    SDL_LockMutex(p->las_mutex);\n    SDL_CondWaitTimeout(p->algo_cond, p->las_mutex, TIME_ALGO_UPDATE_INTERVAL_MS);\n    SDL_UnlockMutex(p->las_mutex);\n}\n\nstatic void algo_cond_signal(PlayList* p) {\n    SDL_LockMutex(p->las_mutex);\n    SDL_CondSignal(p->algo_cond);\n    SDL_UnlockMutex(p->las_mutex);\n}\n\n#pragma mark TagQueue\nstatic int FlvTag_has_consume_all_data_l(struct FlvTag* tag) {\n    if (tag->tag_size <= 0) {\n        return 1;\n    }\n\n    // if reader->buf_size = 0 or reader->gop_size = 0, means that the reader is going to download data ,but not stared yet\n    int ret = (tag->tag_size == tag->buf_read_offset);\n    return ret;\n}\n\nint FlvTag_get_data_from_buffer(PlayList* playlist, struct FlvTag* tag, uint8_t* buf, uint32_t buf_size) {\n    if (FlvTag_has_consume_all_data_l(tag)) {\n        log_error(\"FlvTag_has_consume_all_data_l, illegal state\");\n        return -1;\n    }\n\n    int to_read = FFMIN(buf_size, tag->buf_write_offset - tag->buf_read_offset);\n\n    memcpy(buf, tag->buf + tag->buf_read_offset, to_read);\n    tag->buf_read_offset += to_read;\n\n    return to_read;\n}\n\nint FlvTag_alloc_buffer(PlayList* playlist, struct FlvTag* tag, int32_t tag_size) {\n    tag->buf = av_malloc(tag_size);\n    if (!tag->buf) {\n        log_error(\"alloc tag->buf fail\");\n        return AVERROR(ENOMEM);\n    }\n\n    tag->tag_size = tag_size;\n    tag->buf_read_offset = tag->buf_write_offset = 0;\n    return 0;\n}\n\nvoid FlvTag_dealloc(struct FlvTag* tag) {\n    if (!tag) {\n        return;\n    }\n\n    if (tag->buf) {\n        av_freep(&tag->buf);\n    }\n    tag->tag_size = tag->buf_read_offset = tag->buf_write_offset = 0;\n}\n\nstatic int TagQueue_init(PlayList* playlist, TagQueue* q) {\n    memset(q, 0, sizeof(TagQueue));\n    q->mutex = SDL_CreateMutex();\n    if (!q->mutex) {\n        log_error(\"SDL_CreateMutex():fail\");\n        return AVERROR(ENOMEM);\n    }\n    q->cond = SDL_CreateCond();\n    if (!q->cond) {\n        log_error(\"SDL_CreateCond():fail\");\n        return AVERROR(ENOMEM);\n    }\n    q->abort_request = 1;\n    return 0;\n}\n\nstatic void TagQueue_start(TagQueue* q) {\n    SDL_LockMutex(q->mutex);\n    q->abort_request = 0;\n    SDL_UnlockMutex(q->mutex);\n}\n\nstatic int TagQueue_put_private(TagQueue* q, FlvTag* tag) {\n    TagListNode* tag1;\n\n    if (q->abort_request)\n        return -1;\n\n    tag1 = av_malloc(sizeof(TagListNode));\n    if (!tag1)\n        return -1;\n\n    tag1->tag = *tag;\n    tag1->next = NULL;\n\n    if (!q->last_tag)\n        q->first_tag = tag1;\n    else\n        q->last_tag->next = tag1;\n\n    q->last_tag = tag1;\n    q->nb_tags++;\n    if (tag->type == FLV_TAG_TYPE_VIDEO)\n        q->last_video_ts = tag->av_tag_ts;\n    q->total_tag_bytes += tag->tag_size;\n    SDL_CondSignal(q->cond);\n    return 0;\n}\n\nstatic int TagQueue_put(TagQueue* q, FlvTag* tag) {\n    int ret;\n\n    SDL_LockMutex(q->mutex);\n    ret = TagQueue_put_private(q, tag);\n    SDL_UnlockMutex(q->mutex);\n\n    if (ret < 0) {\n        FlvTag_dealloc(tag);\n    }\n\n    return ret;\n}\n\nstatic int TagQueue_peek_first_video_ts(TagQueue* q) {\n    TagListNode* tag_node, *tag_node1;\n    int ret = -1;\n\n    SDL_LockMutex(q->mutex);\n    for (tag_node = q->first_tag; tag_node; tag_node = tag_node1) {\n        tag_node1 = tag_node->next;\n        if (tag_node->tag.type == FLV_TAG_TYPE_VIDEO) {\n            ret = tag_node->tag.av_tag_ts;\n            break;\n        }\n    }\n    SDL_UnlockMutex(q->mutex);\n\n    return ret;\n}\n\n\n/* return < 0 if aborted, 0 if no tag and > 0 if has tag.  */\nstatic int TagQueue_get(TagQueue* q, FlvTag* tag, int block) {\n    TagListNode* tag_node;\n    int ret;\n\n    SDL_LockMutex(q->mutex);\n\n    for (;;) {\n        if (q->abort_request) {\n            ret = -1;\n            break;\n        }\n\n        tag_node = q->first_tag;\n        if (tag_node) {\n            q->first_tag = tag_node->next;\n            if (!q->first_tag)\n                q->last_tag = NULL;\n            q->nb_tags--;\n            *tag = tag_node->tag;\n            // q->total_tag_bytes -= tag->tag_size;\n            av_free(tag_node);\n            ret = 1;\n            break;\n        } else if (!block) {\n            ret = 0;\n            break;\n        } else {\n            SDL_CondWait(q->cond, q->mutex);\n        }\n    }\n\n    SDL_UnlockMutex(q->mutex);\n    return ret;\n}\n\n\nstatic void TagQueue_flush(TagQueue* q) {\n    TagListNode* tag_node, *tag_node_next;\n\n    SDL_LockMutex(q->mutex);\n    for (tag_node = q->first_tag; tag_node; tag_node = tag_node_next) {\n        tag_node_next = tag_node->next;\n        FlvTag_dealloc(&tag_node->tag);\n        av_freep(&tag_node);\n    }\n    q->last_tag = NULL;\n    q->first_tag = NULL;\n    q->nb_tags = 0;\n    q->last_video_ts = 0;\n    SDL_UnlockMutex(q->mutex);\n}\n\nstatic void TagQueue_destroy(TagQueue* q) {\n    TagQueue_flush(q);\n    SDL_DestroyMutex(q->mutex);\n    SDL_DestroyCond(q->cond);\n}\n\nstatic void TagQueue_abort(TagQueue* q) {\n    SDL_LockMutex(q->mutex);\n    q->abort_request = 1;\n    SDL_CondSignal(q->cond);\n    SDL_UnlockMutex(q->mutex);\n}\n\nstatic int32_t TagQueue_get_duration_ms(TagQueue* q) {\n    int32_t ret = 0;\n\n    int first_ts = TagQueue_peek_first_video_ts(q);\n\n    if (first_ts >= 0) {\n        SDL_LockMutex(q->mutex);\n        ret = q->last_video_ts - first_ts;\n        SDL_UnlockMutex(q->mutex);\n    }\n\n    return ret > 0 ? ret : 0;\n}\n\nstatic int64_t TagQueue_get_total_bytes(TagQueue* q) {\n    int64_t ret = 0;\n\n    SDL_LockMutex(q->mutex);\n    ret = q->total_tag_bytes;\n    SDL_UnlockMutex(q->mutex);\n\n    return ret > 0 ? ret : 0;\n}\n\n\n#pragma mark LasStatistic\nint32_t get_video_bitrate(MultiRateAdaption* thiz) {\n    return thiz->levels[thiz->current];\n}\n\nint32_t get_buffer_current(MultiRateAdaption* thiz) {\n    return thiz->last_check_buffer;\n}\n\nint32_t get_bw_fragment(MultiRateAdaption* thiz) {\n    return thiz->last_speed;\n}\n\nvoid LasStatistic_reset(LasStatistic* stat) {\n    if (stat) {\n        memset(stat, 0, sizeof(LasStatistic));\n    }\n}\n\nvoid LasStatistic_init(LasStatistic* stat, PlayList* playlist) {\n    LasStatistic_reset(stat);\n\n    stat->flv_nb = playlist->adaptation_set.n_representation;\n    for (int i = 0; i < playlist->adaptation_set.n_representation; i++) {\n        stat->flvs[i].total_bandwidth_kbps = playlist->adaptation_set.representations[i]->bitrate;\n        strncpy(stat->flvs[i].url, playlist->adaptation_set.representations[i]->url, MAX_URL_SIZE - 1);\n    }\n}\n\nvoid LasStatistic_on_rep_http_url(LasStatistic* stat, char* request_url) {\n    if (stat) {\n        strncpy(stat->cur_playing_url, request_url, MAX_URL_SIZE - 1);\n    }\n}\n\nvoid LasStatistic_on_rep_http_start(LasStatistic* stat, int64_t start_time) {\n    if (stat) {\n        stat->cur_rep_read_start_time = start_time;\n    }\n}\n\nvoid LasStatistic_on_rep_http_open(LasStatistic* stat, int64_t open_time) {\n    if (stat) {\n        stat->cur_rep_http_open_time = open_time;\n    }\n}\n\nvoid LasStatistic_on_rep_flv_header(LasStatistic* stat, int64_t header_time) {\n    if (stat) {\n        stat->cur_rep_read_header_time = header_time;\n    }\n}\n\nvoid LasStatistic_on_rep_http_first_data(LasStatistic* stat, int64_t first_data_time) {\n    if (stat) {\n        stat->cur_rep_first_data_time = first_data_time;\n    }\n}\n\nvoid LasStatistic_on_rep_start_timestamp(PlayList* playlist, int64_t start_time, int64_t request_time) {\n    LasStatistic* stat = playlist->las_statistic;\n    if (stat) {\n        stat->cur_rep_start_time = start_time;\n        stat->rep_switch_gap_time = request_time <= 0 ? 0 : start_time - request_time;\n        log_info(\"rep_switch_gap_time=%lld\", stat->rep_switch_gap_time);\n    }\n}\n\nvoid LasStatistic_on_rep_read_error(LasStatistic* stat, int error) {\n    if (stat) {\n        stat->cur_rep_http_reading_error = error;\n    }\n}\n\nvoid LasStatistic_on_read_packet(LasStatistic* stat, PlayList* playlist) {\n    if (stat && playlist) {\n        stat->cur_decoding_flv_index = playlist->cur_rep_index;\n    }\n}\n\nvoid LasStatistic_on_buffer_time(LasStatistic* stat, PlayList* playlist) {\n    if (stat && playlist) {\n        stat->cached_a_dur_ms = get_cache_duration_ms(playlist->audio_cache);\n        stat->cached_v_dur_ms = get_cache_duration_ms(playlist->video_cache);;\n        stat->cached_tag_dur_ms = TagQueue_get_duration_ms(&playlist->tag_queue);\n        log_info(\"a_buffer_time_ms=%lld, v_buffer_time_ms=%lld, CachedTagQueue_ms=%lld\",\n                 stat->cached_a_dur_ms, stat->cached_v_dur_ms, stat->cached_tag_dur_ms);\n    }\n}\n\nvoid LasStatistic_on_adaption_adapted(PlayList* playlist, MultiRateAdaption* adaption) {\n    LasStatistic* stat = playlist->las_statistic;\n    if (stat && adaption) {\n        stat->bitrate_downloading = get_video_bitrate(adaption);\n    }\n}\n\nvoid LasStatistic_on_bytes_downloaded(LasStatistic* stat, int64_t bytes) {\n    if (stat) {\n        stat->total_bytes_read += bytes;\n    }\n}\n\nvoid LasStatistic_on_bandwidth_update(PlayList* playlist, MultiRateAdaption* adaption) {\n    LasStatistic* stat = playlist->las_statistic;\n    if (stat && adaption) {\n        stat->bandwidth_fragment = get_bw_fragment(adaption);\n        stat->current_buffer_ms = get_buffer_current(adaption);\n    }\n}\n\nvoid LasStatistic_on_rep_switch_count(LasStatistic* stat, PlayList* playlist) {\n    if (stat) {\n        stat->rep_switch_cnt++;\n        stat->switch_point_a_buffer_ms = get_cache_duration_ms(playlist->audio_cache);\n        stat->switch_point_v_buffer_ms = get_cache_duration_ms(playlist->video_cache);\n    }\n}\n\n#pragma mark MultiRateAdaption\nint32_t local_index_2_rep_index(MultiRateAdaption* thiz, int32_t local_index) {\n    int32_t rep_index = 0;\n    for (int i = 0; i < thiz->n_bitrates; i++) {\n        if (thiz->levels[local_index] == thiz->bitrate_table_origin_order[i]) {\n            rep_index = i;\n            break;\n        }\n    }\n    return rep_index;\n}\n\nint32_t rep_index_2_local_index(MultiRateAdaption* thiz, int32_t rep_index) {\n    int32_t local_index = 0;\n    for (int i = 0; i < thiz->n_bitrates; i++) {\n        if (thiz->levels[i] == thiz->bitrate_table_origin_order[rep_index]) {\n            local_index = i;\n            break;\n        }\n    }\n    return local_index;\n\n}\n\nint get_local_index_from_bitrate(MultiRateAdaption* thiz, int64_t bitrate) {\n    for (int32_t i = thiz->n_bitrates - 1; i > 0; --i) {\n        if (thiz->levels[i] <= bitrate) {\n            return i;\n        }\n    }\n    return 0;\n}\n\nint compare(const void* a, const void* b) {\n    return (*(int32_t*)a - * (int32_t*)b);\n}\n\nvoid RateAdaptConfig_default_init(AdaptiveConfig* config, PlayList* playlist) {\n    config->buffer_init = 2000;\n    config->stable_buffer_diff_threshold_second = 0.15;\n    config->stable_buffer_interval_ms = 2000;\n    config->generate_speed_gap_ms = 3000;\n    config->buffer_check_interval_ms = 500;\n    config->smoothed_speed_utilization_ratio = 0.8;\n    config->small_speed_to_bitrate_ratio = 0.4;\n    config->enough_speed_to_bitrate_ratio = 0.9;\n    config->buffer_lower_limit_second = 0.6;\n    config->recent_buffered_size = 16;\n    config->smoothed_speed_ratio = 0.9;\n}\n\n\n// return index of optimized Representation\nvoid MultiRateAdaption_init(MultiRateAdaption* thiz, AdaptiveConfig config,\n                            struct PlayList* playlist) {\n    if (!thiz || !playlist || playlist->adaptation_set.n_representation <= 0) {\n        log_error(\"thiz:%p, p:%p\", thiz, playlist);\n        return;\n    }\n    thiz->conf = config;\n    thiz->n_bitrates = 0;\n    thiz->playlist = playlist;\n    thiz->session_id = playlist->session_id;\n    int64_t default_select_bitrate = -1;\n    for (int i = 0; i < playlist->adaptation_set.n_representation; i++) {\n        Representation* rep = playlist->adaptation_set.representations[i];\n        thiz->bitrate_table_origin_order[i] = rep->bitrate;\n        thiz->levels[i] = rep->bitrate;\n        if (rep->default_selected) {\n            default_select_bitrate = rep->bitrate;\n        }\n        thiz->disable_adaptive_table[i] = rep->disabled_from_adaptive;\n        thiz->n_bitrates++;\n    }\n    qsort(thiz->levels, thiz->n_bitrates, sizeof(int32_t), compare);\n\n    thiz->buffer_init = config.buffer_init;\n    if (thiz->buffer_init > INIT_BUFFER_THRESHOLD_MAX_MS) {\n        thiz->buffer_init = INIT_BUFFER_THRESHOLD_MAX_MS;\n    }\n\n    if (default_select_bitrate >= 0) {\n        thiz->current = get_local_index_from_bitrate(thiz, default_select_bitrate);\n    } else {\n        thiz->current = (thiz->n_bitrates - 1) / 2;\n    }\n    while (thiz->current >= thiz->n_bitrates) {\n        thiz->current -= 1;\n    }\n\n    int switch_mode = get_switch_mode(playlist->outermost_ctx);\n    if (switch_mode >= 0 && switch_mode < thiz->n_bitrates) {\n        thiz->current = rep_index_2_local_index(thiz, switch_mode);\n    }\n\n    LasStatistic_on_adaption_adapted(thiz->playlist, thiz);\n    thiz->next_expected_rep_index = local_index_2_rep_index(thiz, thiz->current);\n    thiz->past_buffer[0] = 0.1;\n    thiz->buffer_index = 1;\n    thiz->stable_buffer_start_time = get_current_time_ms();\n    thiz->generated_speed = 0;\n    thiz->last_check_buffer = 0;\n    thiz->last_speed = 0;\n}\n\nbool update_stable_buffer(MultiRateAdaption* thiz, double buffered) {\n    double diff = buffered - thiz->last_check_buffer;\n    double diff_ratio = diff / buffered;\n    double now = get_current_time_ms();\n    if (diff < -thiz->conf.stable_buffer_diff_threshold_second || diff_ratio < -0.2) {\n        algo_info(\"buffer_diff_down: %.2fs, diff_ratio: %.2f\", diff, diff_ratio);\n        thiz->stable_buffer_start_time = FFMAX(now, thiz->stable_buffer_start_time);\n    }\n    if (diff > thiz->conf.stable_buffer_diff_threshold_second\n        && now - thiz->stable_buffer_start_time + thiz->conf.buffer_check_interval_ms > thiz->conf.stable_buffer_interval_ms) {\n        thiz->stable_buffer_start_time = FFMAX(\n            now - thiz->conf.buffer_check_interval_ms * 2,\n            thiz->stable_buffer_start_time + thiz->conf.buffer_check_interval_ms * 2\n        );\n        algo_info(\"buffer_diff_up: %.2fs\", diff);\n    }\n    thiz->last_check_buffer = buffered;\n    return now - thiz->stable_buffer_start_time > thiz->conf.stable_buffer_interval_ms;\n}\n\n/**\n * check buffer periodically\n */\nvoid check_buffer(MultiRateAdaption* thiz, PlayList* playlist) {\n    double buffered = get_cache_duration_ms(playlist->audio_cache) / 1000.0;\n    bool is_buffer_stable = update_stable_buffer(thiz, buffered);\n    if (is_buffer_stable && thiz->current + 1 < thiz->n_bitrates) {\n        thiz->generated_speed = thiz->levels[thiz->current + 1];\n    } else {\n        thiz->generated_speed = 0;\n    }\n\n    thiz->past_buffer[thiz->buffer_index % thiz->conf.recent_buffered_size] = buffered;\n    thiz->buffer_index += 1;\n}\n\nint32_t quantization(MultiRateAdaption* thiz, double speed) {\n    int32_t index = 0;\n    for (int i = thiz->n_bitrates - 1; i >= 0; i--) {\n        if (speed >= thiz->levels[i]) {\n            index = i;\n            break;\n        }\n    }\n    return index;\n}\n\ndouble get_past_buffer(MultiRateAdaption* thiz) {\n    double max_buffer = 0.1;\n    for (int i = 0; i < thiz->conf.recent_buffered_size && i < thiz->buffer_index; ++i) {\n        double buffered = thiz->past_buffer[(thiz->buffer_index - 1 - i) % thiz->conf.recent_buffered_size];\n        if (buffered > max_buffer) {\n            max_buffer = buffered;\n        }\n    }\n    return max_buffer;\n}\n\ndouble get_smoothed_speed(MultiRateAdaption* thiz, double speed) {\n    if (thiz->last_speed > 0) {\n        return speed * (1 - thiz->conf.smoothed_speed_ratio) + thiz->last_speed * thiz->conf.smoothed_speed_ratio;\n    }\n    return speed;\n}\n\ndouble get_predicted_buffer(MultiRateAdaption* thiz, double buffered) {\n    double past_buffer = get_past_buffer(thiz);\n    return buffered + (buffered - past_buffer);\n}\n\ndouble get_buffer_speed(MultiRateAdaption* thiz, double buffered) {\n    double past_buffer = get_past_buffer(thiz);\n    double buffer_speed_ratio = 1 + (buffered - past_buffer) / FFMAX(past_buffer, 0.1);\n    return buffer_speed_ratio * thiz->levels[thiz->current];\n}\n\nbool is_speed_too_small(MultiRateAdaption* thiz, double speed) {\n    return speed / thiz->levels[thiz->current] < thiz->conf.small_speed_to_bitrate_ratio;\n}\n\nbool is_speed_enough(MultiRateAdaption* thiz, double speed) {\n    return speed / thiz->levels[thiz->current] > thiz->conf.enough_speed_to_bitrate_ratio;\n}\n\nint32_t next_local_rate_index(MultiRateAdaption* thiz, double speed, double buffered) {\n    if (thiz->buffer_index <= 1 && buffered <= 0.1) {\n        algo_info(\"empty past buffer\");\n        return thiz->current;\n    }\n    double buffer_speed = get_buffer_speed(thiz, buffered);\n    double smoothed_speed = get_smoothed_speed(thiz, speed);\n    algo_info(\"gop_speed: %.0f, smoothed_speed: %.0f\", speed, smoothed_speed);\n\n    double predicted_buffered = get_predicted_buffer(thiz, buffered);\n    algo_info(\"buffer_speed: %.0f, buffered: %.1f, predicted_buffered: %.1f\", buffer_speed, buffered, predicted_buffered);\n\n    int32_t next_index = thiz->current;\n    if (predicted_buffered < thiz->conf.buffer_lower_limit_second\n        || is_speed_too_small(thiz, buffer_speed)) {\n        next_index = FFMIN(thiz->current, quantization(thiz, buffer_speed));\n    } else if (is_speed_enough(thiz, buffer_speed)) {\n        if (thiz->generated_speed > 0) {\n            algo_info(\"generated_speed used\");\n            next_index = quantization(thiz, thiz->generated_speed);\n            thiz->generated_speed = 0;\n        } else {\n            next_index = quantization(thiz, smoothed_speed * thiz->conf.smoothed_speed_utilization_ratio);\n        }\n        next_index = FFMIN(thiz->current + 1, FFMAX(next_index, thiz->current));\n    }\n    algo_info(\"target_index = %u\", next_index);\n    return next_index;\n}\n\nint32_t next_representation_id(MultiRateAdaption* thiz, int switch_mode, double speed, double buffered) {\n    if (switch_mode >= 0 && switch_mode < thiz->n_bitrates) {\n        thiz->current = rep_index_2_local_index(thiz, switch_mode);\n        return switch_mode;\n    }\n\n    int local_index = next_local_rate_index(thiz, speed, buffered);\n    int rep_index = local_index_2_rep_index(thiz, local_index);\n    while (local_index > 0 && thiz->disable_adaptive_table[rep_index]) {\n        local_index -= 1;\n        rep_index = local_index_2_rep_index(thiz, local_index);\n    }\n\n    if (local_index != thiz->current) {\n        thiz->stable_buffer_start_time = get_current_time_ms() + thiz->conf.generate_speed_gap_ms;\n    }\n    if (local_index < thiz->current) {\n        thiz->generated_speed = 0;\n        thiz->last_speed = speed;\n        thiz->buffer_index = 1;\n        thiz->past_buffer[0] = buffered;\n    } else {\n        thiz->last_speed = get_smoothed_speed(thiz, speed);\n    }\n\n    thiz->current = local_index;\n    return rep_index;\n}\n\n#pragma mark Download\nstatic void update_options(char** dest, const char* name, void* src) {\n    av_freep(dest);\n    av_opt_get(src, name, 0, (uint8_t**)dest);\n    if (*dest && !strlen(*dest))\n        av_freep(dest);\n}\n\nstatic int open_url(LasContext* c, URLContext** uc, const char* url,\n                    AVDictionary* opts, AVDictionary* opts2, PlayList* playlist) {\n    AVDictionary* tmp = NULL;\n    const char* proto_name = NULL;\n    int ret;\n\n    av_dict_copy(&tmp, opts, 0);\n    av_dict_copy(&tmp, opts2, 0);\n\n    if (!proto_name) {\n        proto_name = avio_find_protocol_name(url);\n    }\n\n    if (!proto_name)\n        return AVERROR_INVALIDDATA;\n\n    ret = ffurl_open_whitelist(uc, url,  AVIO_FLAG_READ, c->interrupt_callback, &tmp, c->ctx->protocol_whitelist, c->ctx->protocol_blacklist, c->ctx);\n    if (ret >= 0) {\n        log_info(\"ffurl_open_whitelist succeeds\");\n        // update cookies on http response with setcookies.\n        char* new_cookies = NULL;\n        if (!(c->ctx->flags & AVFMT_FLAG_CUSTOM_IO))\n            av_opt_get(*uc, \"cookies\", AV_OPT_SEARCH_CHILDREN, (uint8_t**)&new_cookies);\n        if (new_cookies) {\n            if (c->cookies) {\n                av_free(c->cookies);\n            }\n            c->cookies = new_cookies;\n        }\n\n        // update cookies on http response with setcookies.\n        URLContext* u = *uc;\n        update_options(&c->cookies, \"cookies\", u->priv_data);\n        av_dict_set(&opts, \"cookies\", c->cookies, 0);\n    } else {\n        log_error(\"ffurl_open_whitelist fails: %s(0x%x)\", av_err2str(ret), ret);\n    }\n\n    av_dict_copy(&c->ctx->metadata, tmp, 0);\n    av_dict_free(&tmp);\n    return ret;\n}\n\nenum ReadFromURLMode {\n    READ_NORMAL,\n    READ_COMPLETE,\n};\n\n/*\n * This is actually read from the network, there is no buffer.\n * There are 12 bytes of redundancy in a 4096-byte tcp packet at most,\n * and other non-4096-byte packets are not redundant.\n*/\nstatic int read_from_url(URLContext* url_ctx,\n                         uint8_t* buf, int buf_size,\n                         enum ReadFromURLMode mode,\n                         PlayList* playlist) {\n    int ret;\n\n    if (mode == READ_COMPLETE)\n        ret = ffurl_read_complete(url_ctx, buf, buf_size);\n    else\n        ret = ffurl_read(url_ctx, buf, buf_size);\n\n    if (ret > 0) {\n        add_bytes_read(playlist, ret);\n        LasStatistic_on_bytes_downloaded(playlist->las_statistic, ret);\n    }\n\n    return ret;\n}\n\nstatic int url_block_read(URLContext* url_ctx, uint8_t* buf, int want_len, PlayList* playlist) {\n    int offset = 0;\n    int ret;\n\n    int remain = want_len;\n    while (remain > 0) {\n        ret = read_from_url(url_ctx, buf + offset, remain, READ_NORMAL, playlist);\n        if (ret <= 0) {\n            if (ret < 0) {\n                log_error(\"read_from_url fails: %s(0x%x)\", av_err2str(ret), ret);\n            } else {\n                //ffurl_read means socket was closed by peer\n                ret = LAS_ERROR_SOCKET_CLOSED_BY_PEER;\n                log_error(\"read_from_url socket closed by peer\");\n            }\n            return ret;\n        }\n        offset += ret;\n        remain -= ret;\n    }\n\n    if (remain != 0) {\n        log_error(\"block_read fail, remain:%d\", remain);\n        return -1;\n    } else {\n        return want_len;\n    }\n}\n\n#pragma mark Gop\nvoid GopReader_init(GopReader* reader, Representation* rep, AVFormatContext* s, PlayList* playlist) {\n    memset(reader->realtime_url, 0, sizeof(reader->realtime_url));\n    strcat(reader->realtime_url, rep->url);\n\n    if (strstr(reader->realtime_url, \"?\") != NULL) {\n        strcat(reader->realtime_url, \"&\");\n    } else {\n        strcat(reader->realtime_url, \"?\");\n    }\n    // Tag based\n    char str_starttime[256] = \"\\0\";\n    sprintf(str_starttime, \"startPts=%\" PRId64, reader->last_gop_start_ts);\n    strcat(reader->realtime_url, str_starttime);\n\n    if (reader->is_audio_only) {\n        strcat(reader->realtime_url, \"&audioOnly=true\");\n    }\n    reader->rep_index = rep->index;\n    reader->parent = s;\n    log_error(\"rep->index:%d, realtime_url:%s\", rep->index, reader->realtime_url);\n}\n\nint GopReader_open_input(GopReader* reader, LasContext* c, PlayList* playlist) {\n    AVDictionary* opts = NULL;\n    int ret = 0;\n\n    // broker prior HTTP options that should be consistent across requests\n    av_dict_set(&opts, \"user_agent\", c->user_agent, 0);\n    av_dict_set(&opts, \"cookies\", c->cookies, 0);\n    av_dict_set(&opts, \"headers\", c->headers, 0);\n    av_dict_set(&opts, \"http_proxy\", c->http_proxy, 0);\n    av_dict_set(&opts, \"seekable\", \"0\", 0);\n\n    LasStatistic_on_rep_http_url(c->playlist.las_statistic, reader->realtime_url);\n    ret = open_url(c, &reader->input, reader->realtime_url, c->avio_opts, opts, playlist);\n\n    av_dict_free(&opts);\n    return ret;\n}\n\nvoid GopReader_close(GopReader* reader, PlayList* playlist) {\n    if (reader->rep_index < 0) {\n        return;\n    }\n    ffurl_closep(&reader->input);\n    log_info(\"ffurl_closep(rep_index: %d)\", reader->rep_index);\n    reader->switch_index += 1;\n}\n\nstatic int PlayList_algo_statistic_thread(void* data);\nint64_t GopReader_download_gop(GopReader* reader, MultiRateAdaption* adaption, PlayList* playlist) {\n    LasContext* c = reader->parent->priv_data;\n\n    uint8_t flv_header[FLV_HEADER_LEN + PRE_TAG_SIZE_LEN];\n\n    int ret = -1;\n    bool rep_changed = true;\n    bool first_video_tag = true;\n    int to_read;\n\n    int64_t start_time = 0;\n    int64_t http_open_time = 0;\n    int64_t first_data_time = 0;  // got first tag time\n\n    start_time = get_current_time_ms();\n    LasStatistic_on_rep_http_start(playlist->las_statistic, start_time);\n    LasStatistic_on_rep_http_first_data(playlist->las_statistic, 0);\n\n    if (!reader->input) {\n        ret = GopReader_open_input(reader, c, playlist);\n        if (ret < 0) {\n            return ret;\n        }\n\n        http_open_time = get_current_time_ms();\n        LasStatistic_on_rep_http_open(playlist->las_statistic, http_open_time - start_time);\n\n        memset(flv_header, 0, FLV_HEADER_LEN + PRE_TAG_SIZE_LEN);\n        ret = url_block_read(reader->input, flv_header, FLV_HEADER_LEN + PRE_TAG_SIZE_LEN, playlist);\n        LasStatistic_on_rep_flv_header(playlist->las_statistic, get_current_time_ms() - http_open_time);\n        if (ret < 0) {\n            return ret;\n        }\n    }\n\n    // start algo update thread\n    if (!playlist->algo_thread) {\n        playlist->algo_thread = SDL_CreateThreadEx(&playlist->_algo_thread, PlayList_algo_statistic_thread, playlist, \"playlist-algo-statistic-thread\");\n    }\n\n    //las 2.0 Tag based reading\n    uint8_t av_tag_header[AV_TAG_HEADER_LEN];\n    int gop_duration = playlist->adaptation_set.duration;\n    int64_t bytes_last = get_bytes_read(playlist);\n    int64_t time_last = get_current_time_ms();\n\n    while (1) {\n        if (playlist->read_abort_request || playlist->tag_queue.abort_request) {\n            return LAS_ERROR_ABORT_BY_USER;\n        }\n        ret = playlist->error_code;\n        if (ret < 0) {\n            playlist->error_code = 0;\n            return ret;\n        }\n\n        int request = get_audio_only_request(playlist->outermost_ctx);\n        if (reader->is_audio_only != request) {\n            reader->is_audio_only = request;\n            int64_t current_playing_audio_ts = get_first_audio_packet_pts(playlist->outermost_ctx);\n            log_info(\"current_playing_audio_ts: %lld\", current_playing_audio_ts);\n            int64_t request_ts = current_playing_audio_ts - playlist->adaptation_set.duration / 2;\n            reader->last_gop_start_ts = request_ts > 0 ? request_ts : 0;\n            return 0;\n        }\n\n        memset(av_tag_header, 0, AV_TAG_HEADER_LEN);\n        to_read = AV_TAG_HEADER_LEN;\n        ret = url_block_read(reader->input, av_tag_header, to_read, playlist);\n        if (ret < 0) {\n            return ret;\n        }\n\n        if (av_tag_header[0] == FLV_TAG_TYPE_VIDEO && ((av_tag_header[AV_TAG_HEADER_LEN - 5] >> 4) & 0x0F) == 1\n            && av_tag_header[AV_TAG_HEADER_LEN - 4] == 1) {\n            //IDR, switch edge\n            uint32_t new_rep_start_pts = AV_RB24(av_tag_header + 4);\n            new_rep_start_pts |= (unsigned)AV_RB8(av_tag_header + 7) << 24;\n            uint32_t cts = (AV_RB24(av_tag_header + 13) + 0xff800000) ^ 0xff800000;\n            new_rep_start_pts += cts;\n            log_info(\"video key Frame, pts=%lld, parameters=0x%x, video packet_type=0x%x\",\n                     new_rep_start_pts, av_tag_header[AV_TAG_HEADER_LEN - 5], av_tag_header[AV_TAG_HEADER_LEN - 4]);\n            if (!first_video_tag) {\n                reader->last_gop_start_ts = new_rep_start_pts;\n                int64_t bytes_now = get_bytes_read(playlist);\n                int64_t time_now = get_current_time_ms();\n                int64_t speed = (bytes_now - bytes_last) * 8 / FFMAX(time_now - time_last, 50);\n                bytes_last = bytes_now;\n                time_last = time_now;\n\n                adaption->next_expected_rep_index = next_representation_id(\n                        adaption,\n                        get_switch_mode(playlist->outermost_ctx),\n                        speed,\n                        get_cache_duration_ms(playlist->audio_cache) / 1000.0);\n                if (reader->rep_index != adaption->next_expected_rep_index) {\n                    LasStatistic_on_adaption_adapted(playlist, adaption);\n                    LasStatistic_on_rep_switch_count(playlist->las_statistic, playlist);\n                    return 0; // switch url\n                }\n            } else {\n                first_video_tag = false;\n                LasStatistic_on_rep_start_timestamp(playlist, new_rep_start_pts, reader->last_gop_start_ts);\n            }\n        }\n\n        //av_malloc tag size, -1(av parameter bytes) + -1(video packet_type) + -3(CompositionTime) + 4(pre tag size)\n        to_read = AV_RB24(av_tag_header + 1) - 1;\n\n        FlvTag tag;\n        memset(&tag, 0, sizeof(FlvTag));\n\n        if (av_tag_header[0] == FLV_TAG_TYPE_VIDEO || av_tag_header[0] == FLV_TAG_TYPE_AUDIO) {\n            tag.av_tag_ts = AV_RB24(av_tag_header + 4);\n            tag.av_tag_ts |= (unsigned)AV_RB8(av_tag_header + 7) << 24;\n            tag.type = av_tag_header[0];\n        }\n\n        int tag_size = 0;\n        if (rep_changed)\n            tag_size = to_read + AV_TAG_HEADER_LEN + FLV_HEADER_LEN + PRE_TAG_SIZE_LEN;\n        else\n            tag_size = to_read + AV_TAG_HEADER_LEN;\n\n        ret = FlvTag_alloc_buffer(playlist, &tag, tag_size);\n        if (ret) {\n            return ret;\n        }\n\n        if (rep_changed) {\n            memcpy(tag.buf + tag.buf_write_offset, flv_header, FLV_HEADER_LEN + PRE_TAG_SIZE_LEN);\n            tag.buf_write_offset += FLV_HEADER_LEN + PRE_TAG_SIZE_LEN;\n        }\n\n        memcpy(tag.buf + tag.buf_write_offset, av_tag_header, AV_TAG_HEADER_LEN);\n        tag.buf_write_offset += AV_TAG_HEADER_LEN;\n\n        if (playlist->read_abort_request || playlist->tag_queue.abort_request) {\n            FlvTag_dealloc(&tag);\n            return LAS_ERROR_ABORT_BY_USER;\n        }\n        ret = url_block_read(reader->input, tag.buf + tag.buf_write_offset, to_read, playlist);\n        if (ret < 0) {\n            FlvTag_dealloc(&tag);\n            return ret;\n        } else {\n            tag.buf_write_offset += to_read;\n        }\n\n        if (tag.buf_write_offset != tag.tag_size) {\n            log_error(\"ERROR! tag.buf_write_offset(%d) != tag.tag_size(%d)\", tag.buf_write_offset, tag.tag_size);\n            FlvTag_dealloc(&tag);\n            return LAS_ERROR_GET_WHOLE_TAG;\n        }\n\n        if (first_data_time == 0) {\n            first_data_time = get_current_time_ms();\n            LasStatistic_on_rep_http_first_data(playlist->las_statistic, first_data_time);\n        }\n\n        tag.rep_index = playlist->gop_reader.rep_index;\n        tag.audio_only = playlist->gop_reader.is_audio_only;\n        tag.switch_index = playlist->gop_reader.switch_index;\n\n        TagQueue_put(&playlist->tag_queue, &tag);\n\n        if (rep_changed) {\n            rep_changed = false;\n        }\n    }\n}\n\n\n#pragma mark PlayList\nstatic int PlayList_prepare_reading_tag(PlayList* playlist) {\n    SDL_LockMutex(playlist->reading_tag_mutex);\n    int ret = 0;\n    if (FlvTag_has_consume_all_data_l(&playlist->reading_tag)) {\n        FlvTag_dealloc(&playlist->reading_tag);\n        SDL_UnlockMutex(playlist->reading_tag_mutex);\n\n        FlvTag tag;\n        ret = TagQueue_get(&playlist->tag_queue, &tag, 1);\n        if (ret < 0) {\n            log_error(\"TagQueue_get fail\");\n        } else {\n            SDL_LockMutex(playlist->reading_tag_mutex);\n            playlist->reading_tag = tag;\n            SDL_UnlockMutex(playlist->reading_tag_mutex);\n        }\n        return ret;\n    } else {\n        SDL_UnlockMutex(playlist->reading_tag_mutex);\n        return 0;\n    }\n}\n\nstatic int PlayList_read_from_reading_tag(PlayList* playlist, uint8_t* buf, uint32_t buf_size) {\n    SDL_LockMutex(playlist->reading_tag_mutex);\n    int ret = FlvTag_get_data_from_buffer(playlist, &playlist->reading_tag, buf, buf_size);\n    SDL_UnlockMutex(playlist->reading_tag_mutex);\n    return ret;\n}\n\nstatic int PlayList_read_data(void* opaque, uint8_t* buf, int buf_size) {\n    PlayList* playlist = opaque;\n    int ret;\n\n    ret = PlayList_prepare_reading_tag(playlist);\n    if (ret < 0) {\n        return ret;\n    }\n\n    if (playlist->reading_tag.switch_index != playlist->cur_switch_index) {\n        return AVERROR_EOF;\n    }\n\n    ret = PlayList_read_from_reading_tag(playlist, buf, buf_size);\n    if (ret < 0) {\n        return ret;\n    }\n\n    return ret;\n}\n\nstatic void PlayList_reset_state(PlayList* p) {\n    p->parent = NULL;\n    p->read_buffer = NULL;\n    p->cur_switch_index = 0;\n    p->cur_rep_index = p->multi_rate_adaption.next_expected_rep_index;\n}\n\nstatic int PlayList_algo_statistic_thread(void* data) {\n    PlayList* playlist = (PlayList*)data;\n    TagQueue* tag_queue = &playlist->tag_queue;\n    while (!tag_queue->abort_request) {\n        algo_cond_wait(playlist);\n        if (tag_queue->abort_request || playlist->read_abort_request) {\n            break;\n        }\n        check_buffer(&playlist->multi_rate_adaption, playlist);\n        LasStatistic_on_bandwidth_update(playlist, &playlist->multi_rate_adaption);\n    }\n    return 0;\n}\n\nint PlayList_is_valid_index_l(PlayList* playlist, int index) {\n    if (!playlist)\n        return 0;\n    return index >= 0 && index < playlist->adaptation_set.n_representation;\n}\n\nstatic int PlayList_read_thread(void* data) {\n    PlayList* playlist = (PlayList*)data;\n    log_info(\"Start las reading\");\n\n    AVFormatContext* s = playlist->outermost_ctx;\n    GopReader* gop_reader = &playlist->gop_reader;\n    TagQueue* tag_queue = &playlist->tag_queue;\n\n    int64_t ret = 0;\n\n    while (!tag_queue->abort_request) {\n        // change GopReader if needed\n        int new_index = playlist->multi_rate_adaption.next_expected_rep_index;\n        if (!PlayList_is_valid_index_l(playlist, new_index)) {\n            log_error(\"invalid rep index:%d, IGNORE!!!\", new_index);\n            break;\n        }\n        GopReader_close(gop_reader, playlist);\n        Representation* rep = playlist->adaptation_set.representations[new_index];\n        if (ff_check_interrupt(&s->interrupt_callback)) {\n            break;\n        }\n        GopReader_init(gop_reader, rep, s, playlist);\n        ret = GopReader_download_gop(gop_reader, &playlist->multi_rate_adaption, playlist);\n        if (ret < 0) {\n            LasStatistic_on_rep_read_error(playlist->las_statistic, ret);\n            break;\n        }\n    }\n\n    TagQueue_abort(&playlist->tag_queue);\n    if (playlist->algo_thread) {\n        log_info(\"Signals algo_thread\");\n        algo_cond_signal(playlist);\n    }\n\n    if (gop_reader->input) {\n        log_info(\"Calls GopReader_close\");\n        GopReader_close(gop_reader, playlist);\n    }\n\n    log_error(\"Thread is over, playlist->read_abort_request=%d, ret:%s(0x%x)\", playlist->read_abort_request, av_err2str(ret), ret);\n    return playlist->read_abort_request ? 0 : ret;\n}\n\nint PlayList_open_rep(PlayList* playlist, FlvTag* tag, AVFormatContext* s) {\n    int ret = 0;\n    Representation* rep = NULL;\n\n    if (!PlayList_is_valid_index_l(playlist, tag->rep_index)) {\n        ret = LAS_ERROR_INVALID_REP_INDEX;\n        goto fail;\n    }\n\n    rep = playlist->adaptation_set.representations[tag->rep_index];\n    if (!(playlist->ctx = avformat_alloc_context())) {\n        ret = AVERROR(ENOMEM);\n        goto fail;\n    }\n\n    playlist->read_buffer = av_malloc(INITIAL_BUFFER_SIZE);\n    if (!playlist->read_buffer) {\n        ret = AVERROR(ENOMEM);\n        avformat_free_context(playlist->ctx);\n        playlist->ctx = NULL;\n        goto fail;\n    }\n\n    ffio_init_context(&playlist->pb, playlist->read_buffer, INITIAL_BUFFER_SIZE, 0, playlist,\n                      PlayList_read_data, NULL, NULL);\n\n    playlist->ctx->pb = &playlist->pb;\n    playlist->ctx->flags |= s->flags & ~AVFMT_FLAG_CUSTOM_IO;\n\n    SDL_LockMutex(playlist->rw_mutex);\n    playlist->cur_switch_index = tag->switch_index;\n    SDL_UnlockMutex(playlist->rw_mutex);\n\n    playlist->ctx->fps_probe_size = 0;\n\n    // fix me ,url should be read reading_gop 's url\n    ret = avformat_open_input(&playlist->ctx, playlist->gop_reader.realtime_url, NULL, NULL);\n    if (ret < 0) {\n        if (playlist->read_thread && playlist->read_thread->retval) {\n            log_error(\"PlayList_read_thread() already Fails!\");\n            ret = playlist->read_thread->retval;\n        }\n        log_error(\"avformat_open_input() ret:%s(0x%x)\", av_err2str(ret), ret);\n        goto fail;\n    }\n\n    ret = avformat_find_stream_info(playlist->ctx, NULL);\n    if (ret < 0) {\n        goto fail;\n    }\n\n    // transcoder_group used in current flv stream\n    AVDictionaryEntry* tsc_group = av_dict_get(playlist->ctx->metadata, \"tsc_group\", NULL, 0);\n    if (tsc_group && tsc_group->value) {\n        av_dict_set(&playlist->outermost_ctx->metadata, \"tsc_group\", tsc_group->value, 0);\n    }\n\n    if (!playlist->is_stream_ever_opened) {\n        // first inited, add streams to outermost AVFormatContext\n        /* Create new AVStreams for each stream in this playlist */\n        for (int j = 0; j < playlist->ctx->nb_streams; j++) {\n            AVStream* st = avformat_new_stream(s, NULL);\n            AVStream* ist = playlist->ctx->streams[j];\n            if (!st) {\n                ret = AVERROR(ENOMEM);\n                goto fail;\n            }\n\n            st->id = 0;\n\n            avcodec_parameters_copy(st->codecpar, playlist->ctx->streams[j]->codecpar);\n            avpriv_set_pts_info(st, ist->pts_wrap_bits, ist->time_base.num, ist->time_base.den);\n        }\n        playlist->is_stream_ever_opened = true;\n    } else {\n        set_stream_reopened(playlist->outermost_ctx, true);\n    }\n\n    for (int j = 0; j < playlist->ctx->nb_streams && j < MAX_STREAM_NUM; j++) {\n        AVCodecParameters* new_codec = playlist->ctx->streams[j]->codecpar;\n        for (int k = 0; k < s->nb_streams; k++) {\n            AVCodecParameters* old_codec = s->streams[k]->codecpar;\n            if (new_codec->codec_type == old_codec->codec_type) {\n                playlist->stream_index_map[j] = k;\n                break;\n            }\n        }\n    }\n\n    playlist->cur_rep_index = tag->rep_index;\n    set_audio_only_response(playlist->outermost_ctx, tag->audio_only);\n    log_info(\"open_index:%d, audio_only:%d finished\", tag->rep_index, tag->audio_only);\n    return 0;\n\nfail:\n    return ret;\n}\n\nint PlayList_open_read_thread(PlayList* playlist) {\n    int ret;\n    AVFormatContext* s = playlist->outermost_ctx;\n    playlist->read_abort_request = 0;\n\n    playlist->rw_mutex = SDL_CreateMutex();\n    if (!playlist->rw_mutex) {\n        log_error(\"SDL_CreateMutex playlist->rw_mutex fail\");\n        return LAS_ERROR_MUTEX_CREATE;\n    }\n\n    playlist->reading_tag_mutex = SDL_CreateMutex();\n    if (!playlist->reading_tag_mutex) {\n        log_error(\"SDL_CreateMutex playlist->reading_tag_mutex fail\");\n        return LAS_ERROR_MUTEX_CREATE;\n    }\n\n    playlist->las_mutex = SDL_CreateMutex();\n    if (!playlist->las_mutex) {\n        log_error(\"SDL_CreateMutex playlist->las_mutex fail\");\n        return LAS_ERROR_MUTEX_CREATE;\n    }\n\n    playlist->algo_cond = SDL_CreateCond();\n    if (!playlist->algo_cond) {\n        log_error(\"SDL_CreateCond playlist->algo_cond fail\");\n        return LAS_ERROR_COND_CREATE;\n    }\n\n    // init and start TagQueue\n    TagQueue_init(playlist, &playlist->tag_queue);\n    TagQueue_start(&playlist->tag_queue);\n\n    // init GopReader\n    playlist->gop_reader.switch_index = 0;\n    playlist->gop_reader.rep_index = -1;\n    playlist->gop_reader.last_gop_start_ts = (int)(playlist->multi_rate_adaption.buffer_init) * (-1);\n\n    // start downloading thread\n    playlist->read_thread = SDL_CreateThreadEx(&playlist->_read_thread, PlayList_read_thread, playlist, \"playlist-read-thread\");\n    if (!playlist->read_thread) {\n        log_error(\"SDL_CreateThreadEx fail\");\n        return LAS_ERROR_THREAD_CREATE;\n    }\n\n    if (playlist->read_thread->retval) {\n        log_error(\"PlayList_read_thread() fails: %s(0x%x)\", av_err2str(playlist->read_thread->retval), playlist->read_thread->retval);\n        return playlist->read_thread->retval;\n    }\n\n    ret = PlayList_prepare_reading_tag(playlist);\n    if (ret < 0) {\n        return ret;\n    }\n    ret = PlayList_open_rep(playlist, &playlist->reading_tag, s);\n    if (ret) {\n        log_error(\"PlayList_open_rep() fails: %s(0x%x)\", av_err2str(ret), ret);\n        return ret;\n    }\n\n\n    return 0;\n}\nstatic void PlayList_abort(PlayList* playlist) {\n    TagQueue_abort(&playlist->tag_queue);\n\n    SDL_LockMutex(playlist->rw_mutex);\n    playlist->read_abort_request = 1;\n    SDL_UnlockMutex(playlist->rw_mutex);\n}\n\nvoid PlayList_close_rep(PlayList* playlist) {\n    SDL_LockMutex(playlist->rw_mutex);\n    avformat_close_input(&playlist->ctx);\n    av_freep(&playlist->pb.buffer);\n    log_info(\"close_index:%d finished\", playlist->cur_rep_index);\n    SDL_UnlockMutex(playlist->rw_mutex);\n}\n\nvoid PlayList_close_read_thread(PlayList* playlist) {\n    // abort request\n    if (playlist->rw_mutex) {\n        PlayList_abort(playlist);\n        PlayList_close_rep(playlist);\n    }\n\n    SDL_WaitThread(playlist->read_thread, NULL);\n    playlist->read_thread = NULL;\n\n    SDL_WaitThread(playlist->algo_thread, NULL);\n    playlist->algo_thread = NULL;\n\n    SDL_DestroyMutexP(&playlist->rw_mutex);\n    SDL_DestroyMutexP(&playlist->reading_tag_mutex);\n    SDL_DestroyMutexP(&playlist->las_mutex);\n    TagQueue_destroy(&playlist->tag_queue);\n    SDL_DestroyCondP(&playlist->algo_cond);\n}\n\n\n#pragma mark parser\nvoid free_multi_rate_flv_context(PlayList* c) {\n    if (!c)\n        return;\n    AdaptationSet* adaptation_set_item = &c->adaptation_set;\n    for (int j = 0; j < adaptation_set_item->n_representation; j++) {\n        if (adaptation_set_item->representations[j]) {\n            av_freep(&adaptation_set_item->representations[j]);\n        }\n    }\n}\n\nstatic void dump_multi_rate_flv_context(PlayList* c) {\n    if (!c)\n        return;\n    AdaptationSet* adaptation_set_item = &c->adaptation_set;\n    for (int j = 0; j < adaptation_set_item->n_representation; j++) {\n        Representation* representation_item = adaptation_set_item->representations[j];\n        av_log(NULL, AV_LOG_DEBUG, \"{\\n\");\n        av_log(NULL, AV_LOG_DEBUG, \"    id: %d \\n\", representation_item->id);\n        av_log(NULL, AV_LOG_DEBUG, \"    bitrate: %d \\n\", representation_item->bitrate);\n        av_log(NULL, AV_LOG_DEBUG, \"    url: \\\"%s\\\" \\n\", representation_item->url);\n        av_log(NULL, AV_LOG_DEBUG, \"}\\n\");\n    }\n}\n\nstatic int parse_representation_set(Representation* c, cJSON* root) {\n    int len = cJSON_GetArraySize(root);\n    for (int i = 0; i < len; i++) {\n        cJSON* child_json = cJSON_GetArrayItem(root, i);\n        switch (child_json->type) {\n            case cJSON_Number:\n                if (!strcmp(child_json->string, \"id\")) {\n                    c->id = (int)child_json->valuedouble;\n                } else if (!strcmp(child_json->string, \"maxBitrate\")) {\n                    c->bitrate = (int)child_json->valuedouble;\n                }\n                break;\n            case cJSON_String:\n                if (!strcmp(child_json->string, \"url\")) {\n                    strcpy(c->url, child_json->valuestring);\n                }\n                break;\n            case cJSON_NULL:\n            case cJSON_True:\n                if (!strcmp(child_json->string, \"defaultSelected\")) {\n                    c->default_selected = 1;\n                } else if (!strcmp(child_json->string, \"disabledFromAdaptive\")) {\n                    c->disabled_from_adaptive = 1;\n                }\n                break;\n            case cJSON_Array:\n            case cJSON_Object:\n            case cJSON_False:\n                break;\n        }\n    }\n    return 0;\n}\n\nstatic int parse_adaptation_set(AdaptationSet* c, cJSON* root) {\n    int len = cJSON_GetArraySize(root);\n    for (int i = 0; i < len; i++) {\n        cJSON* child_json = cJSON_GetArrayItem(root, i);\n        switch (child_json->type) {\n            case cJSON_Number:\n                if (!strcmp(child_json->string, \"duration\")) {\n                    c->duration = (int)child_json->valuedouble;\n                }\n                break;\n            case cJSON_Array:\n                if (child_json->string && !strcmp(child_json->string, \"representation\")) {\n                    int len = cJSON_GetArraySize(child_json);\n                    for (int i = 0; i < len; i++) {\n                        Representation* representation_item = NULL;\n                        representation_item = av_mallocz(sizeof(Representation));\n                        if (!representation_item) {\n                            return -1;\n                        }\n                        c->representations[c->n_representation] = representation_item;\n                        representation_item->index = c->n_representation;\n                        representation_item->disabled_from_adaptive = 0;\n                        representation_item->default_selected = 0;\n                        c->n_representation++;\n\n                        cJSON* root_json = cJSON_GetArrayItem(child_json, i);\n                        parse_representation_set(representation_item, root_json);\n                    }\n                }\n                break;\n            case cJSON_False:\n            case cJSON_True:\n            case cJSON_String:\n            case cJSON_NULL:\n            case cJSON_Object:\n                break;\n        }\n    }\n    return 0;\n}\n\nint parse_root(char* file_name, PlayList* c) {\n    cJSON* root = cJSON_Parse(file_name);\n    if (!root)\n        return LAS_ERROR_MANIFEST_JSON;\n    if (cJSON_Object == root->type) {\n        int len = cJSON_GetArraySize(root);\n        for (int i = 0; i < len; i++) {\n            cJSON* child_json = cJSON_GetArrayItem(root, i);\n            switch (child_json->type) {\n                case cJSON_Array:\n                    if (child_json->string && !strcmp(child_json->string, \"adaptationSet\")) {\n                        cJSON* adaptation_set = cJSON_GetArrayItem(child_json, 0);\n                        if (adaptation_set) {\n                            parse_adaptation_set(&c->adaptation_set, adaptation_set);\n                        }\n                    }\n                    break;\n                case cJSON_Number:\n                case cJSON_String:\n                case cJSON_NULL:\n                case cJSON_False:\n                case cJSON_True:\n                case cJSON_Object:\n                    break;\n            }\n            printf(\"\\n\");\n        }\n    }\n    cJSON_Delete(root);\n    dump_multi_rate_flv_context(c);\n    return 0;\n}\n\nint parse_adapt_config(char* config_string, AdaptiveConfig* config, PlayList* playlist) {\n    cJSON* root = cJSON_Parse(config_string);\n    if (!root)\n        return LAS_ERROR_ADAPT_CONFIG_JSON;\n    if (cJSON_Object == root->type) {\n        int len = cJSON_GetArraySize(root);\n        for (int i = 0; i < len; i++) {\n            cJSON* child_json = cJSON_GetArrayItem(root, i);\n            switch (child_json->type) {\n                case cJSON_Number:\n                    if (!strcmp(child_json->string, \"bufferInit\")) {\n                        config->buffer_init = child_json->valueint;\n                    } else if (!strcmp(child_json->string, \"stableBufferDiffThresholdSecond\")) {\n                        config->stable_buffer_diff_threshold_second = child_json->valuedouble;\n                    } else if (!strcmp(child_json->string, \"stableBufferIntervalMs\")) {\n                        config->stable_buffer_interval_ms = child_json->valuedouble;\n                    } else if (!strcmp(child_json->string, \"generateSpeedGapMs\")) {\n                        config->generate_speed_gap_ms = child_json->valuedouble;\n                    } else if (!strcmp(child_json->string, \"bufferCheckIntervalMs\")) {\n                        config->buffer_check_interval_ms = child_json->valuedouble;\n                    } else if (!strcmp(child_json->string, \"smoothedSpeedUtilizationRatio\")) {\n                        config->smoothed_speed_utilization_ratio = child_json->valuedouble;\n                    } else if (!strcmp(child_json->string, \"smallSpeedToBitrateRatio\")) {\n                        config->small_speed_to_bitrate_ratio = child_json->valuedouble;\n                    } else if (!strcmp(child_json->string, \"enoughSpeedToBitrateRatio\")) {\n                        config->enough_speed_to_bitrate_ratio = child_json->valuedouble;\n                    } else if (!strcmp(child_json->string, \"bufferLowerLimitSecond\")) {\n                        config->buffer_lower_limit_second = child_json->valuedouble;\n                    } else if (!strcmp(child_json->string, \"recentBufferedSize\")) {\n                        config->recent_buffered_size = child_json->valuedouble;\n                    } else if (!strcmp(child_json->string, \"smoothedSpeedRatio\")) {\n                        config->smoothed_speed_ratio = child_json->valuedouble;\n                    }\n                    break;\n                case cJSON_Object:\n                case cJSON_False:\n                case cJSON_NULL:\n                case cJSON_Array:\n                case cJSON_True:\n                    break;\n            }\n        }\n    }\n    cJSON_Delete(root);\n    return 0;\n}\n\nstatic int parse_int_from(cJSON* json, const char* key) {\n    cJSON* entry = cJSON_GetObjectItemCaseSensitive(json, key);\n    if (cJSON_IsNumber(entry)) {\n        return entry->valueint;\n    }\n    return 0;\n}\n\n#pragma mark las\nstatic int las_close(AVFormatContext* s) {\n    LasContext* c = s->priv_data;\n    PlayList* playlist = &c->playlist;\n    PlayList_close_read_thread(playlist);\n    free_multi_rate_flv_context(playlist);\n    av_freep(&c->user_agent);\n    av_freep(&c->cookies);\n    av_freep(&c->headers);\n    av_freep(&c->server_ip);\n    av_freep(&c->manifest_string);\n    av_freep(&c->live_adapt_config);\n    av_dict_free(&c->avio_opts);\n    return 0;\n}\n\nstatic int las_probe(AVProbeData* p) {\n    if (p->filename && av_strstart(p->filename, \"ijklas:\", NULL))\n        return AVPROBE_SCORE_MAX;\n\n    return 0;\n}\n\nstatic int las_read_header(AVFormatContext* s) {\n    // for debug\n#ifdef __ANDROID__\n    pthread_setname_np(pthread_self(), \"ffplay_read_thread\");\n#elif defined(__APPLE__)\n    pthread_setname_np(\"ffplay_read_thread\");\n#endif\n\n    LasContext* c = s->priv_data;\n    PlayList* playlist = &c->playlist;\n    AdaptiveConfig config;\n    AVDictionaryEntry* entry;\n    int ret = 0;\n\n    c->ctx = s;\n    c->interrupt_callback = &s->interrupt_callback;\n    c->server_ip = NULL;\n    playlist->session_id = c->session_id;\n\n    av_dict_set(&c->avio_opts, \"timeout\", \"10000000\", 0);\n    if ((ret = parse_root(c->manifest_string, playlist)) < 0) {\n        log_error(\"Illegal manifest Json String\");\n        goto fail;\n    }\n    log_info(\"Finish parsing las manifest, switch_mode:%d\", c->las_switch_mode);\n    if (c->audio_cache_ptr && c->video_cache_ptr) {\n        playlist->video_cache = (FFTrackCacheStatistic*)c->video_cache_ptr;\n        playlist->audio_cache = (FFTrackCacheStatistic*)c->audio_cache_ptr;\n    } else {\n        log_error(\"FFTrackCacheStatistic is null\");\n        goto fail;\n    }\n    playlist->las_statistic = &c->las_statistic;\n    LasStatistic_init(playlist->las_statistic, playlist);\n\n    RateAdaptConfig_default_init(&config, playlist);\n    if (parse_adapt_config(c->live_adapt_config, &config, playlist) < 0) {\n        log_error(\"Illegal adaptation Configure Json String\");\n    }\n    playlist->outermost_ctx = s;\n    MultiRateAdaption_init(&playlist->multi_rate_adaption, config, playlist);\n    PlayList_reset_state(playlist);\n    ret = PlayList_open_read_thread(playlist);\n    if (ret  != 0) {\n        goto fail;\n    }\n    return ret;\n\nfail:\n    las_close(s);\n    return ret == 0 ? 0 : AVERROR_EXIT;\n}\n\n/*\n * Used to reset a statically allocated AVPacket to a clean slate,\n * containing no data.\n */\nstatic void reset_packet(AVPacket* pkt) {\n    if (pkt) {\n        av_init_packet(pkt);\n        pkt->data = NULL;\n    }\n}\n\nstatic bool h264_check_sps_pps(const AVPacket* pkt) {\n    if (pkt && pkt->data && pkt->size >= 5) {\n        int offset = 0;\n\n        while (offset >= 0 && offset + 5 <= pkt->size) {\n            uint8_t* nal_start = pkt->data + offset;\n            int nal_size = AV_RB32(nal_start);\n            int nal_type = nal_start[4] & 0x1f;\n\n            if (nal_type == H264_NAL_SPS || nal_type == H264_NAL_PPS) {\n                return true;\n            }\n\n            offset += nal_size + 4;\n        }\n    }\n    return false;\n}\n\nstatic bool read_sps_pps_by_avcc(uint8_t* extradata, uint32_t extrasize,\n                                 uint8_t** sps, int* sps_len,\n                                 uint8_t** pps, int* pps_len) {\n    uint8_t* spc = extradata + 6;\n    uint32_t sps_size = AV_RB16(spc);\n    if (sps_size) {\n        *sps_len = sps_size;\n        *sps = (uint8_t*)av_mallocz(sps_size);\n        if (!*sps) {\n            return false;\n        }\n        spc += 2;\n        memcpy(*sps, spc, sps_size);\n        spc += sps_size;\n    }\n    spc += 1;\n    uint32_t  pps_size = AV_RB16(spc);\n    if (pps_size) {\n        *pps_len = pps_size;\n        *pps = (uint8_t*)av_mallocz(pps_size);\n        if (!*pps) {\n            if (*sps) {\n                free(*sps);\n            }\n            return false;\n        }\n        spc += 2;\n        memcpy(*pps, spc, pps_size);\n    }\n    return true;\n}\n\nstatic void insert_sps_pps_into_avpacket(AVPacket* packet, uint8_t* new_extradata, int new_extradata_size, PlayList* playlist) {\n    uint8_t* sps = NULL, *pps = NULL;\n    int sps_len = 0, pps_len = 0;\n\n    if (read_sps_pps_by_avcc(new_extradata, new_extradata_size, &sps, &sps_len, &pps, &pps_len)) {\n        int size = packet->size;\n        if (sps) {\n            size += NALU_HEAD_LEN + sps_len;\n        }\n        if (pps) {\n            size += NALU_HEAD_LEN + pps_len;\n        }\n        if (size == packet->size) {\n            return;\n        }\n        AVPacket new_pack;\n        int res = av_new_packet(&new_pack, size);\n        if (res < 0) {\n            log_error(\"Failed memory allocation\");\n        } else {\n            av_packet_copy_props(&new_pack, packet);\n            uint8_t* data = new_pack.data;\n\n            if (sps) {\n                AV_WB32(data, sps_len);\n                data += NALU_HEAD_LEN;\n                memcpy(data, sps, sps_len);\n                data += sps_len;\n                log_info(\"insert sps, size:%d\", sps_len);\n            } else {\n                log_info(\"sps is null\");\n            }\n            if (pps) {\n                AV_WB32(data, pps_len);\n                data += NALU_HEAD_LEN;\n                memcpy(data, pps, pps_len);\n                data += pps_len;\n                log_info(\"insert pps, size:%d\", pps_len);\n            } else {\n                log_info(\"pps is null\");\n            }\n            memcpy(data, packet->data, packet->size);\n            av_packet_unref(packet);\n            *packet = new_pack;\n        }\n    }\n}\n\nstatic int las_read_packet(AVFormatContext* s, AVPacket* pkt) {\n    LasContext* c = s->priv_data;\n    PlayList* playlist = &c->playlist;\n    int ret = 0;\n\n    while (1) {\n        if (!playlist->ctx) {\n            log_error(\"playlist->ctx is null\");\n            ret = AVERROR_EOF;\n            goto fail;\n        }\n        ret = av_read_frame(playlist->ctx, &playlist->pkt);\n        if (ret < 0) {\n            reset_packet(&playlist->pkt);\n            if (avio_feof(&playlist->pb) || ret == AVERROR_EOF) {\n                // change rep if needed\n                if (playlist->cur_switch_index != playlist->reading_tag.switch_index) {\n                    PlayList_close_rep(playlist);\n                    PlayList_open_rep(playlist, &playlist->reading_tag, s);\n                    continue;\n                }\n            }\n            break;\n        } else if (!playlist->pkt.data) {\n            // success, but no packet data yet\n            continue;\n        } else {\n            // go packet\n            *pkt = playlist->pkt;\n            if (pkt->stream_index >= 0 && pkt->stream_index < MAX_STREAM_NUM) {\n                pkt->stream_index = playlist->stream_index_map[pkt->stream_index];\n            }\n            AVCodecParameters* codec = playlist->ctx->streams[pkt->stream_index]->codecpar;\n            if (codec->extradata) {\n                if (codec->codec_id == AV_CODEC_ID_H264\n                    && !h264_check_sps_pps(pkt)) {\n                    insert_sps_pps_into_avpacket(pkt, codec->extradata, codec->extradata_size, playlist);\n                }\n                uint8_t *side = av_packet_new_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, codec->extradata_size);\n                if (side) {\n                    memcpy(side, codec->extradata, codec->extradata_size);\n                    av_freep(&codec->extradata);\n                    codec->extradata_size = 0;\n                }\n            }\n            break;\n        }\n    }\n    reset_packet(&playlist->pkt);\n    LasStatistic_on_read_packet(playlist->las_statistic, playlist);\n\nfail:\n    return ret == 0 ? 0 : AVERROR_EXIT;\n}\n\nstatic int las_read_seek(AVFormatContext* s, int stream_index,\n                          int64_t timestamp, int flags) {\n//    LasContext *c = s->priv_data;\n    return 0;\n}\n\n#define OFFSET(x) offsetof(LasContext, x)\n#define FLAGS AV_OPT_FLAG_DECODING_PARAM\nstatic const AVOption las_options[] = {\n    {\n        \"user-agent\", \"user agent\",\n        OFFSET(user_agent), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, FLAGS\n    },\n    {\n        \"headers\", \"headers\",\n        OFFSET(headers), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, FLAGS\n    },\n    {\n        \"manifest_string\", \"manifest_string\",\n        OFFSET(manifest_string), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, FLAGS\n    },\n    {\n        \"abr_history_data\", \"abr_history_data\",\n        OFFSET(abr_history_data), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, FLAGS\n    },\n    {\n        \"device-network-type\", \"device-network-type\",\n        OFFSET(network), AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, FLAGS\n    },\n    {\n        \"liveAdaptConfig\", \"liveAdaptConfig\",\n        OFFSET(live_adapt_config), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, FLAGS\n    },\n    {\n        \"session_id\", \"session_id\",\n        OFFSET(session_id), AV_OPT_TYPE_INT, {.i64 = 0}, INT32_MIN, INT32_MAX, FLAGS\n    },\n    {\n        \"video_cache_ptr\", \"video_cache_ptr\",\n        OFFSET(video_cache_ptr), AV_OPT_TYPE_INT64, {.i64 = 0}, INT64_MIN, INT64_MAX, FLAGS\n    },\n    {\n        \"audio_cache_ptr\", \"audio_cache_ptr\",\n        OFFSET(audio_cache_ptr), AV_OPT_TYPE_INT64, {.i64 = 0}, INT64_MIN, INT64_MAX, FLAGS\n    },\n    {\n        \"las_switch_mode\", \"las_switch_mode\",\n        OFFSET(las_switch_mode), AV_OPT_TYPE_INT, {.i64 = LAS_AUTO_MODE}, INT_MIN, INT_MAX, FLAGS\n    },\n    {\n        \"first_audio_packet_pts\", \"first_audio_packet_pts\",\n        OFFSET(first_audio_packet_pts), AV_OPT_TYPE_INT64, {.i64 = 0}, INT64_MIN, INT64_MAX, FLAGS\n    },\n    {\n        \"block_duration\", \"block_duration\",\n        OFFSET(block_duration), AV_OPT_TYPE_INT, {.i64 = 0}, INT64_MIN, INT64_MAX, FLAGS\n    },\n    {\n        \"audio_only_request\", \"audio_only_request\",\n        OFFSET(audio_only_request), AV_OPT_TYPE_INT, {.i64 = 0}, INT64_MIN, INT64_MAX, FLAGS\n    },\n    {\n        \"audio_only_response\", \"audio_only_response\",\n        OFFSET(audio_only_response), AV_OPT_TYPE_INT, {.i64 = 0}, INT64_MIN, INT64_MAX, FLAGS\n    },\n    {\n        \"stream_reopened\", \"stream_reopened\",\n        OFFSET(stream_reopened), AV_OPT_TYPE_INT, {.i64 = 0}, INT64_MIN, INT64_MAX, FLAGS\n    },\n    {NULL}\n};\n\nstatic const AVClass ijklas_class = {\n    .class_name = \"las demuxer\",\n    .item_name  = av_default_item_name,\n    .option     = las_options,\n    .version    = LIBAVUTIL_VERSION_INT,\n};\n\nAVInputFormat ijkff_ijklas_demuxer = {\n    .name           = \"ijklas\",\n    .long_name      = \"Live Adaptive Streaming\",\n    .priv_class     = &ijklas_class,\n    .priv_data_size = sizeof(LasContext),\n    .read_probe     = las_probe,\n    .read_header    = las_read_header,\n    .read_packet    = las_read_packet,\n    .read_close     = las_close,\n    .read_seek      = las_read_seek,\n    .extensions     = \"las\",\n    .flags          = AVFMT_NOFILE\n};\n\n\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavformat/ijklas.h",
    "content": "#ifndef LAS_DEMUX\n#define LAS_DEMUX\n\n#include <stdint.h>\n#include <pthread.h>\n#include <stdbool.h>\n\n#define MAX_URL_SIZE 4096\n#define MAX_STREAM_NUM 10\n#define LAS_AUTO_MODE (-1)\n\ntypedef struct FlvInfo {\n    int total_bandwidth_kbps;\n    char url[MAX_URL_SIZE];\n} FlvInfo;\n\ntypedef struct LasStatistic {\n    // info from manifest.json\n    FlvInfo flvs[MAX_STREAM_NUM];\n    int flv_nb;\n\n    // algo specific\n    int64_t bandwidth_fragment;\n    int64_t bitrate_downloading;\n    int64_t current_buffer_ms;\n\n    // status\n    int cur_decoding_flv_index;\n    int64_t switch_point_a_buffer_ms;\n    int64_t switch_point_v_buffer_ms;\n    char cur_playing_url[MAX_URL_SIZE];\n\n    // rep switch speed\n    int64_t cur_rep_read_start_time;\n    int64_t cur_rep_http_open_time;\n    int64_t cur_rep_read_header_time;\n    int64_t cur_rep_first_data_time;  // first tag time\n    int64_t cur_rep_start_time;\n    int64_t rep_switch_gap_time;  //new_rep_start_pts - request_pts\n    int64_t rep_switch_cnt;\n\n    int cur_rep_http_reading_error;  // errors during gop reading\n    int64_t cached_tag_dur_ms;\n    int64_t cached_a_dur_ms; // 上层播放器packet_queue长度\n    int64_t cached_v_dur_ms;\n    int64_t total_bytes_read;\n} LasStatistic;\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavformat/ijklivehook.c",
    "content": "/*\n * Copyright (c) 2015 Bilibili\n * Copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"libavformat/avformat.h\"\n#include \"libavformat/url.h\"\n#include \"libavutil/avstring.h\"\n#include \"libavutil/opt.h\"\n\n#include \"ijkplayer/ijkavutil/opt.h\"\n\n#include \"ijkavformat.h\"\n#include \"libavutil/application.h\"\n\ntypedef struct {\n    AVClass         *class;\n    AVFormatContext *inner;\n\n    AVAppIOControl   io_control;\n    int              discontinuity;\n    int              error;\n\n    /* options */\n    AVDictionary   *open_opts;\n    char *         app_ctx_intptr;\n    AVApplicationContext *app_ctx;\n} Context;\n\nstatic int ijkurlhook_call_inject(AVFormatContext *h)\n{\n    Context *c = h->priv_data;\n    int ret = 0;\n\n    if (ff_check_interrupt(&h->interrupt_callback)) {\n        ret = AVERROR_EXIT;\n        goto fail;\n    }\n\n    if (c->app_ctx) {\n        av_log(h, AV_LOG_INFO, \"livehook %s\\n\", c->io_control.url);\n        c->io_control.is_handled = 0;\n        ret = av_application_on_io_control(c->app_ctx, AVAPP_CTRL_WILL_LIVE_OPEN, &c->io_control);\n        if (ret || !c->io_control.url[0]) {\n            ret = AVERROR_EXIT;\n            goto fail;\n        }\n    }\n\n    if (ff_check_interrupt(&h->interrupt_callback)) {\n        ret = AVERROR_EXIT;\n        goto fail;\n    }\n\nfail:\n    return ret;\n}\n\nstatic int ijklivehook_probe(AVProbeData *probe)\n{\n    if (av_strstart(probe->filename, \"ijklivehook:\", NULL))\n        return AVPROBE_SCORE_MAX;\n\n    return 0;\n}\n\nstatic int ijklivehook_read_close(AVFormatContext *avf)\n{\n    Context *c = avf->priv_data;\n\n    avformat_close_input(&c->inner);\n    return 0;\n}\n\n// FIXME: install libavformat/internal.h\nint ff_alloc_extradata(AVCodecParameters *par, int size);\n\nstatic int copy_stream_props(AVStream *st, AVStream *source_st)\n{\n    int ret;\n\n    if (st->codecpar->codec_id || !source_st->codecpar->codec_id) {\n        if (st->codecpar->extradata_size < source_st->codecpar->extradata_size) {\n            if (st->codecpar->extradata) {\n                av_freep(&st->codecpar->extradata);\n                st->codecpar->extradata_size = 0;\n            }\n            ret = ff_alloc_extradata(st->codecpar,\n                                     source_st->codecpar->extradata_size);\n            if (ret < 0)\n                return ret;\n        }\n        memcpy(st->codecpar->extradata, source_st->codecpar->extradata,\n               source_st->codecpar->extradata_size);\n        return 0;\n    }\n    if ((ret = avcodec_parameters_copy(st->codecpar, source_st->codecpar)) < 0)\n        return ret;\n    st->r_frame_rate        = source_st->r_frame_rate;\n    st->avg_frame_rate      = source_st->avg_frame_rate;\n    st->time_base           = source_st->time_base;\n    st->sample_aspect_ratio = source_st->sample_aspect_ratio;\n\n    av_dict_copy(&st->metadata, source_st->metadata, 0);\n    return 0;\n}\n\nstatic int open_inner(AVFormatContext *avf)\n{\n    Context         *c          = avf->priv_data;\n    AVDictionary    *tmp_opts   = NULL;\n    AVFormatContext *new_avf    = NULL;\n    int ret = -1;\n    int i   = 0;\n    AVDictionaryEntry *t = NULL;\n    int fps_flag = 0;\n\n    new_avf = avformat_alloc_context();\n    if (!new_avf) {\n        ret = AVERROR(ENOMEM);\n        goto fail;\n    }\n\n    if (c->open_opts)\n        av_dict_copy(&tmp_opts, c->open_opts, 0);\n\n    av_dict_set_int(&tmp_opts, \"probesize\",         avf->probesize, 0);\n    av_dict_set_int(&tmp_opts, \"formatprobesize\",   avf->format_probesize, 0);\n    av_dict_set_int(&tmp_opts, \"analyzeduration\",   avf->max_analyze_duration, 0);\n    av_dict_set_int(&tmp_opts, \"fpsprobesize\",      avf->fps_probe_size, 0);\n    av_dict_set_int(&tmp_opts, \"max_ts_probe\",      avf->max_ts_probe, 0);\n\n    t = av_dict_get(tmp_opts, \"skip-calc-frame-rate\", NULL, AV_DICT_MATCH_CASE);\n    if (t) {\n        fps_flag = (int) strtol(t->value, NULL, 10);\n        if (fps_flag > 0) {\n            av_dict_set_int(&new_avf->metadata, \"skip-calc-frame-rate\", fps_flag, 0);\n        }\n    }\n\n    new_avf->interrupt_callback = avf->interrupt_callback;\n    ret = avformat_open_input(&new_avf, c->io_control.url, NULL, &tmp_opts);\n    if (ret < 0)\n        goto fail;\n\n    ret = avformat_find_stream_info(new_avf, NULL);\n    if (ret < 0)\n        goto fail;\n\n    for (i = 0; i < new_avf->nb_streams; i++) {\n        AVStream *st = avformat_new_stream(avf, NULL);\n        if (!st) {\n            ret = AVERROR(ENOMEM);\n            goto fail;\n        }\n\n        ret = copy_stream_props(st, new_avf->streams[i]);\n        if (ret < 0)\n            goto fail;\n    }\n\n    avformat_close_input(&c->inner);\n    c->inner = new_avf;\n    new_avf = NULL;\n    ret = 0;\nfail:\n    av_dict_free(&tmp_opts);\n    avformat_close_input(&new_avf);\n    return ret;\n}\n\nstatic int ijklivehook_read_header(AVFormatContext *avf, AVDictionary **options)\n{\n    Context    *c           = avf->priv_data;\n    const char *inner_url   = NULL;\n    int         ret         = -1;\n\n    c->app_ctx = (AVApplicationContext *)av_dict_strtoptr(c->app_ctx_intptr);\n    av_strstart(avf->filename, \"ijklivehook:\", &inner_url);\n\n    c->io_control.size = sizeof(c->io_control);\n    strlcpy(c->io_control.url, inner_url, sizeof(c->io_control.url));\n\n    if (av_stristart(c->io_control.url, \"rtmp\", NULL) ||\n        av_stristart(c->io_control.url, \"rtsp\", NULL)) {\n        // There is total different meaning for 'timeout' option in rtmp\n        av_log(avf, AV_LOG_WARNING, \"remove 'timeout' option for rtmp.\\n\");\n        av_dict_set(options, \"timeout\", NULL, 0);\n    }\n\n    if (options)\n        av_dict_copy(&c->open_opts, *options, 0);\n\n    c->io_control.retry_counter = 0;\n    ret = ijkurlhook_call_inject(avf);\n    if (ret) {\n        ret = AVERROR_EXIT;\n        goto fail;\n    }\n    ret = open_inner(avf);\n    while (ret < 0) {\n        // no EOF in live mode\n        switch (ret) {\n            case AVERROR_EXIT:\n                goto fail;\n        }\n\n        c->io_control.retry_counter++;\n        ret = ijkurlhook_call_inject(avf);\n        if (ret) {\n            ret = AVERROR_EXIT;\n            goto fail;\n        }\n\n        c->discontinuity = 1;\n        ret = open_inner(avf);\n    }\n\n    return 0;\nfail:\n    return ret;\n}\n\nstatic int ijklivehook_read_packet(AVFormatContext *avf, AVPacket *pkt)\n{\n    Context *c   = avf->priv_data;\n    int      ret = -1;\n\n    if (c->error)\n        return c->error;\n\n    if (c->inner)\n        ret = av_read_frame(c->inner, pkt);\n\n    c->io_control.retry_counter = 0;\n    while (ret < 0) {\n        if (c->inner && c->inner->pb && c->inner->pb->error && avf->pb)\n            avf->pb->error = c->inner->pb->error;\n\n        // no EOF in live mode\n        switch (ret) {\n            case AVERROR_EXIT:\n                c->error = AVERROR_EXIT;\n                goto fail;\n            case AVERROR(EAGAIN):\n                goto continue_read;\n        }\n\n        c->io_control.retry_counter++;\n        ret = ijkurlhook_call_inject(avf);\n        if (ret) {\n            ret = AVERROR_EXIT;\n            goto fail;\n        }\n\n        c->discontinuity = 1;\n        ret = open_inner(avf);\n        if (ret)\n            continue;\n\ncontinue_read:\n        ret = av_read_frame(c->inner, pkt);\n    }\n\n    if (c->discontinuity) {\n        pkt->flags |= AV_PKT_FLAG_DISCONTINUITY;\n        c->discontinuity = 0;\n    }\n\n    return 0;\nfail:\n    return ret;\n}\n\n#define OFFSET(x) offsetof(Context, x)\n#define D AV_OPT_FLAG_DECODING_PARAM\n\nstatic const AVOption options[] = {\n    { \"ijkapplication\", \"AVApplicationContext\", OFFSET(app_ctx_intptr), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, .flags = D },\n    { NULL }\n};\n\n#undef D\n#undef OFFSET\n\nstatic const AVClass ijklivehook_class = {\n    .class_name = \"LiveHook demuxer\",\n    .item_name  = av_default_item_name,\n    .option     = options,\n    .version    = LIBAVUTIL_VERSION_INT,\n};\n\nAVInputFormat ijkff_ijklivehook_demuxer = {\n    .name           = \"ijklivehook\",\n    .long_name      = \"Live Hook Controller\",\n    .flags          = AVFMT_NOFILE | AVFMT_TS_DISCONT,\n    .priv_data_size = sizeof(Context),\n    .read_probe     = ijklivehook_probe,\n    .read_header2   = ijklivehook_read_header,\n    .read_packet    = ijklivehook_read_packet,\n    .read_close     = ijklivehook_read_close,\n    .priv_class     = &ijklivehook_class,\n};\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavformat/ijklongurl.c",
    "content": "/*\n * Copyright (c) 2015 Bilibili\n * Copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include <assert.h>\n#include \"libavformat/avformat.h\"\n#include \"libavformat/url.h\"\n#include \"libavutil/avstring.h\"\n#include \"libavutil/log.h\"\n#include \"libavutil/opt.h\"\n\ntypedef struct Context {\n    AVClass        *class;\n    URLContext     *inner;\n\n    /* options */\n    char           *url;\n} Context;\n\nstatic int ijklongurl_open(URLContext *h, const char *arg, int flags, AVDictionary **options)\n{\n    Context *c = h->priv_data;\n\n    if (!c->url || !*c->url)\n        return AVERROR_EXTERNAL;\n\n    return ffurl_open_whitelist(&c->inner,\n                                c->url,\n                                flags,\n                                &h->interrupt_callback,\n                                options,\n                                h->protocol_whitelist,\n                                h->protocol_blacklist,\n                                h);\n}\n\nstatic int ijklongurl_close(URLContext *h)\n{\n    Context *c = h->priv_data;\n\n    return ffurl_close(c->inner);\n}\n\nstatic int ijklongurl_read(URLContext *h, unsigned char *buf, int size)\n{\n    Context *c = h->priv_data;\n\n    return ffurl_read(c->inner, buf, size);\n}\n\nstatic int64_t ijklongurl_seek(URLContext *h, int64_t pos, int whence)\n{\n    Context *c = h->priv_data;\n\n    return ffurl_seek(c->inner, pos, whence);\n}\n\n#define OFFSET(x) offsetof(Context, x)\n#define D AV_OPT_FLAG_DECODING_PARAM\n\nstatic const AVOption options[] = {\n    { \"ijklongurl-url\",         \"real url to access\",\n        OFFSET(url),            AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, D },\n    { NULL }\n};\n\n#undef D\n#undef OFFSET\n\nstatic const AVClass ijklongurl_context_class = {\n    .class_name = \"LongUrl\",\n    .item_name  = av_default_item_name,\n    .option     = options,\n    .version    = LIBAVUTIL_VERSION_INT,\n};\n\nURLProtocol ijkimp_ff_ijklongurl_protocol = {\n    .name                = \"ijklongurl\",\n    .url_open2           = ijklongurl_open,\n    .url_read            = ijklongurl_read,\n    .url_seek            = ijklongurl_seek,\n    .url_close           = ijklongurl_close,\n    .priv_data_size      = sizeof(Context),\n    .priv_data_class     = &ijklongurl_context_class,\n};\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavformat/ijkmediadatasource.c",
    "content": "/*\n * Copyright (c) 2015 Bilibili\n * Copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifdef __ANDROID__\n\n#include <assert.h>\n#include \"libavformat/avformat.h\"\n#include \"libavformat/url.h\"\n#include \"libavutil/avstring.h\"\n#include \"libavutil/log.h\"\n#include \"libavutil/opt.h\"\n\n#include \"ijkavformat/ijkavformat.h\"\n#include \"ijkplayer/ijkavutil/opt.h\"\n\n#include \"j4a/class/tv/danmaku/ijk/media/player/misc/IMediaDataSource.h\"\n#include \"ijksdl/android/ijksdl_android_jni.h\"\n\ntypedef struct Context {\n    AVClass        *class;\n\n    /* options */\n    int64_t         logical_pos;\n    int64_t         logical_size;\n\n    int64_t         media_data_source_ptr;\n    jobject         media_data_source;\n    jbyteArray      jbuffer;\n    int             jbuffer_capacity;\n} Context;\n\nstatic int ijkmds_open(URLContext *h, const char *arg, int flags, AVDictionary **options)\n{\n    Context *c = h->priv_data;\n    JNIEnv *env = NULL;\n    jobject media_data_source = NULL;\n    char *final = NULL;\n\n    av_strstart(arg, \"ijkmediadatasource:\", &arg);\n\n    media_data_source = (jobject) (intptr_t) strtoll(arg, &final, 10);\n    if (!media_data_source)\n        return AVERROR(EINVAL);\n\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        av_log(h, AV_LOG_ERROR, \"%s: SDL_JNI_SetupThreadEnv: failed\", __func__);\n        return AVERROR(EINVAL);\n    }\n\n    c->logical_size = J4AC_IMediaDataSource__getSize(env, media_data_source);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return AVERROR(EINVAL);\n    } else if (c->logical_size < 0) {\n        h->is_streamed = 1;\n        c->logical_size = -1;\n    }\n\n    c->media_data_source = (*env)->NewGlobalRef(env, media_data_source);\n    if (J4A_ExceptionCheck__catchAll(env) || !c->media_data_source) {\n        return AVERROR(ENOMEM);\n    }\n\n    return 0;\n}\n\nstatic int ijkmds_close(URLContext *h)\n{\n    Context *c = h->priv_data;\n    JNIEnv *env = NULL;\n\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        av_log(h, AV_LOG_ERROR, \"%s: SDL_JNI_SetupThreadEnv: failed\", __func__);\n        return AVERROR(EINVAL);\n    }\n\n    J4A_DeleteGlobalRef__p(env, &c->jbuffer);\n\n    if (c->media_data_source) {\n        J4AC_IMediaDataSource__close__catchAll(env, c->media_data_source);\n        J4A_DeleteGlobalRef__p(env, &c->media_data_source);\n    }\n    c->media_data_source_ptr = 0;\n\n    return 0;\n}\n\nstatic jobject jbuffer_grow(JNIEnv *env, URLContext *h, int new_capacity) {\n    Context *c = h->priv_data;\n\n    if (c->jbuffer && c->jbuffer_capacity >= new_capacity)\n        return c->jbuffer;\n\n    new_capacity = FFMAX(new_capacity, c->jbuffer_capacity * 2);\n\n    J4A_DeleteGlobalRef__p(env, &c->jbuffer);\n    c->jbuffer_capacity = 0;\n\n    c->jbuffer = J4A_NewByteArray__asGlobalRef__catchAll(env, new_capacity);\n    if (J4A_ExceptionCheck__catchAll(env) || !c->jbuffer) {\n        c->jbuffer = NULL;\n        return NULL;\n    }\n\n    c->jbuffer_capacity = new_capacity;\n    return c->jbuffer;\n}\n\nstatic int ijkmds_read(URLContext *h, unsigned char *buf, int size)\n{\n    Context    *c = h->priv_data;\n    JNIEnv     *env = NULL;\n    jbyteArray  jbuffer = NULL;\n    jint        ret = 0;\n\n    if (!c->media_data_source) \n        return AVERROR(EINVAL);\n\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        av_log(h, AV_LOG_ERROR, \"%s: SDL_JNI_SetupThreadEnv: failed\", __func__);\n        return AVERROR(EINVAL);\n    }\n\n    jbuffer = jbuffer_grow(env, h, size);\n    if (!jbuffer)\n        return AVERROR(ENOMEM);\n\n    ret = J4AC_IMediaDataSource__readAt(env, c->media_data_source, c->logical_pos, jbuffer, 0, size);\n    if (J4A_ExceptionCheck__catchAll(env))\n        return AVERROR(EIO);\n    else if (ret < 0)\n        return AVERROR_EOF;\n    else if (ret == 0)\n        return AVERROR(EAGAIN);\n\n    (*env)->GetByteArrayRegion(env, jbuffer, 0, ret, (jbyte*)buf);\n    if (J4A_ExceptionCheck__catchAll(env))\n        return AVERROR(EIO);\n\n    c->logical_pos += ret;\n    return ret;\n}\n\nstatic int64_t ijkmds_seek(URLContext *h, int64_t pos, int whence)\n{\n    Context *c = h->priv_data;\n    int64_t  ret;\n    int64_t  new_logical_pos;\n    JNIEnv  *env = NULL;\n    jobject  jbuffer = NULL;\n\n    if (!c->media_data_source) \n        return AVERROR(EINVAL);\n\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        av_log(h, AV_LOG_ERROR, \"%s: SDL_JNI_SetupThreadEnv: failed\", __func__);\n        return AVERROR(EINVAL);\n    }\n\n    if (whence == AVSEEK_SIZE) {\n        av_log(h, AV_LOG_TRACE, \"%s: AVSEEK_SIZE: %\"PRId64\"\\n\", __func__, (int64_t)c->logical_size);\n        return c->logical_size;\n    } else if (whence == SEEK_CUR) {\n        av_log(h, AV_LOG_TRACE, \"%s: %\"PRId64\"\\n\", __func__, pos);\n        new_logical_pos = pos + c->logical_pos;\n    } else if (whence == SEEK_SET){\n        av_log(h, AV_LOG_TRACE, \"%s: %\"PRId64\"\\n\", __func__, pos);\n        new_logical_pos = pos;\n    } else {\n        return AVERROR(EINVAL);\n    }\n    if (new_logical_pos < 0)\n        return AVERROR(EINVAL);\n\n    jbuffer = jbuffer_grow(env, h, 0);\n    if (!jbuffer)\n        return AVERROR(ENOMEM);\n\n    ret = J4AC_IMediaDataSource__readAt(env, c->media_data_source, new_logical_pos, jbuffer, 0, 0);\n    if (J4A_ExceptionCheck__catchAll(env))\n        return AVERROR(EIO);\n    else if (ret < 0)\n        return AVERROR_EOF;\n\n    c->logical_pos = new_logical_pos;\n    return c->logical_pos;\n}\n\n#define OFFSET(x) offsetof(Context, x)\n#define D AV_OPT_FLAG_DECODING_PARAM\n\nstatic const AVOption options[] = {\n    { NULL }\n};\n\n#undef D\n#undef OFFSET\n\nstatic const AVClass ijkmediadatasource_context_class = {\n    .class_name = \"IjkMediaDataSource\",\n    .item_name  = av_default_item_name,\n    .option     = options,\n    .version    = LIBAVUTIL_VERSION_INT,\n};\n\nURLProtocol ijkimp_ff_ijkmediadatasource_protocol = {\n    .name                = \"ijkmediadatasource\",\n    .url_open2           = ijkmds_open,\n    .url_read            = ijkmds_read,\n    .url_seek            = ijkmds_seek,\n    .url_close           = ijkmds_close,\n    .priv_data_size      = sizeof(Context),\n    .priv_data_class     = &ijkmediadatasource_context_class,\n};\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavformat/ijksegment.c",
    "content": "/*\n * Copyright (c) 2015 Bilibili\n * Copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include <assert.h>\n#include \"libavformat/avformat.h\"\n#include \"libavformat/url.h\"\n#include \"libavutil/avstring.h\"\n#include \"libavutil/log.h\"\n#include \"libavutil/opt.h\"\n\n#include \"libavutil/application.h\"\n\ntypedef struct Context {\n    AVClass        *class;\n    URLContext     *inner;\n\n    /* options */\n    char           *http_hook;\n    char *         app_ctx_intptr;\n} Context;\n\nstatic int ijksegment_open(URLContext *h, const char *arg, int flags, AVDictionary **options)\n{\n    Context *c = h->priv_data;\n    AVAppIOControl io_control = {0};\n    AVApplicationContext *app_ctx = (AVApplicationContext *)av_dict_strtoptr(c->app_ctx_intptr);\n    int ret = -1;\n    int segment_index = -1;\n\n    av_strstart(arg, \"ijksegment:\", &arg);\n\n    if (!arg || !*arg)\n        return AVERROR_EXTERNAL;\n\n    segment_index = (int)strtol(arg, NULL, 0);\n    io_control.size = sizeof(io_control);\n    io_control.segment_index = segment_index;\n    strlcpy(io_control.url,    arg,    sizeof(io_control.url));\n\n    if (app_ctx && io_control.segment_index < 0) {\n        ret = AVERROR_EXTERNAL;\n        goto fail;\n    }\n    ret = av_application_on_io_control(app_ctx, AVAPP_CTRL_WILL_CONCAT_SEGMENT_OPEN, &io_control);\n    if (ret || !io_control.url[0]) {\n        ret = AVERROR_EXIT;\n        goto fail;\n    }\n\n    av_dict_set_intptr(options, \"ijkapplication\", (uintptr_t )app_ctx, 0);\n    av_dict_set_int(options, \"ijkinject-segment-index\", segment_index, 0);\n\n    ret = ffurl_open_whitelist(&c->inner,\n                               io_control.url,\n                               flags,\n                               &h->interrupt_callback,\n                               options,\n                               h->protocol_whitelist,\n                               h->protocol_blacklist,\n                               h);\n    if (ret)\n        goto fail;\n\n    return 0;\nfail:\n    return ret;\n}\n\nstatic int ijksegment_close(URLContext *h)\n{\n    Context *c = h->priv_data;\n\n    return ffurl_close(c->inner);\n}\n\nstatic int ijksegment_read(URLContext *h, unsigned char *buf, int size)\n{\n    Context *c = h->priv_data;\n\n    return ffurl_read(c->inner, buf, size);\n}\n\nstatic int64_t ijksegment_seek(URLContext *h, int64_t pos, int whence)\n{\n    Context *c = h->priv_data;\n\n    return ffurl_seek(c->inner, pos, whence);\n}\n\n#define OFFSET(x) offsetof(Context, x)\n#define D AV_OPT_FLAG_DECODING_PARAM\n\nstatic const AVOption options[] = {\n    { \"ijkapplication\", \"AVApplicationContext\", OFFSET(app_ctx_intptr), AV_OPT_TYPE_INT64, { .i64 = 0 }, INT64_MIN, INT64_MAX, .flags = D },\n    { NULL }\n};\n\n#undef D\n#undef OFFSET\n\nstatic const AVClass ijksegment_context_class = {\n    .class_name = \"Inject\",\n    .item_name  = av_default_item_name,\n    .option     = options,\n    .version    = LIBAVUTIL_VERSION_INT,\n};\n\nURLProtocol ijkimp_ff_ijksegment_protocol = {\n    .name                = \"ijksegment\",\n    .url_open2           = ijksegment_open,\n    .url_read            = ijksegment_read,\n    .url_seek            = ijksegment_seek,\n    .url_close           = ijksegment_close,\n    .priv_data_size      = sizeof(Context),\n    .priv_data_class     = &ijksegment_context_class,\n};\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavformat/ijkurlhook.c",
    "content": "/*\n * Copyright (c) 2015 Bilibili\n * Copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include <assert.h>\n#include \"libavformat/avformat.h\"\n#include \"libavformat/url.h\"\n#include \"libavutil/avstring.h\"\n#include \"libavutil/log.h\"\n#include \"libavutil/opt.h\"\n\n#include \"libavutil/application.h\"\n\ntypedef struct Context {\n    AVClass        *class;\n    URLContext     *inner;\n\n    int64_t         logical_pos;\n    int64_t         logical_size;\n    int             io_error;\n\n    AVAppIOControl  app_io_ctrl;\n    const char     *scheme;\n    const char     *inner_scheme;\n\n    /* options */\n    int             inner_flags;\n    AVDictionary   *inner_options;\n    int             segment_index;\n    int64_t         test_fail_point;\n    int64_t         test_fail_point_next;\n    char*         app_ctx_intptr;\n    AVApplicationContext *app_ctx;\n} Context;\n\nstatic int ijkurlhook_call_inject(URLContext *h)\n{\n    Context *c = h->priv_data;\n    int ret = 0;\n\n    if (ff_check_interrupt(&h->interrupt_callback)) {\n        ret = AVERROR_EXIT;\n        goto fail;\n    }\n\n    if (c->app_ctx) {\n        AVAppIOControl control_data_backup = c->app_io_ctrl;\n\n        c->app_io_ctrl.is_handled = 0;\n        c->app_io_ctrl.is_url_changed = 0;\n        ret = av_application_on_io_control(c->app_ctx, AVAPP_CTRL_WILL_HTTP_OPEN, &c->app_io_ctrl);\n        if (ret || !c->app_io_ctrl.url[0]) {\n            ret = AVERROR_EXIT;\n            goto fail;\n        }\n        if (!c->app_io_ctrl.is_url_changed && strcmp(control_data_backup.url, c->app_io_ctrl.url)) {\n            // force a url compare\n            c->app_io_ctrl.is_url_changed = 1;\n        }\n\n        av_log(h, AV_LOG_INFO, \"%s %s (%s)\\n\", h->prot->name, c->app_io_ctrl.url, c->app_io_ctrl.is_url_changed ? \"changed\" : \"remain\");\n    }\n\n    if (ff_check_interrupt(&h->interrupt_callback)) {\n        ret = AVERROR_EXIT;\n        av_log(h, AV_LOG_ERROR, \"%s %s (%s)\\n\", h->prot->name, c->app_io_ctrl.url, c->app_io_ctrl.is_url_changed ? \"changed\" : \"remain\");\n        goto fail;\n    }\n\nfail:\n    return ret;\n}\n\nstatic int ijkurlhook_reconnect(URLContext *h, AVDictionary *extra)\n{\n    Context *c = h->priv_data;\n    int ret = 0;\n    URLContext *new_url = NULL;\n    AVDictionary *inner_options = NULL;\n\n    c->test_fail_point_next += c->test_fail_point;\n\n    assert(c->inner_options);\n    av_dict_copy(&inner_options, c->inner_options, 0);\n    if (extra)\n        av_dict_copy(&inner_options, extra, 0);\n\n    ret = ffurl_open_whitelist(&new_url,\n                               c->app_io_ctrl.url,\n                               c->inner_flags,\n                               &h->interrupt_callback,\n                               &inner_options,\n                               h->protocol_whitelist,\n                               h->protocol_blacklist,\n                               h);\n    if (ret)\n        goto fail;\n\n    ffurl_closep(&c->inner);\n\n    c->inner        = new_url;\n    h->is_streamed  = c->inner->is_streamed;\n    c->logical_pos  = ffurl_seek(c->inner, 0, SEEK_CUR);\n    if (c->inner->is_streamed)\n        c->logical_size = -1;\n    else\n        c->logical_size = ffurl_seek(c->inner, 0, AVSEEK_SIZE);\n\n    c->io_error = 0;\nfail:\n    av_dict_free(&inner_options);\n    return ret;\n}\n\nstatic int ijkurlhook_init(URLContext *h, const char *arg, int flags, AVDictionary **options)\n{\n    Context *c = h->priv_data;\n    int ret = 0;\n\n    av_strstart(arg, c->scheme, &arg);\n\n    c->inner_flags = flags;\n\n    if (options)\n        av_dict_copy(&c->inner_options, *options, 0);\n\n    av_dict_set_intptr(&c->inner_options, \"ijkapplication\", (uintptr_t )c->app_ctx, 0);\n    av_dict_set_int(&c->inner_options, \"ijkinject-segment-index\", c->segment_index, 0);\n\n    c->app_io_ctrl.size = sizeof(c->app_io_ctrl);\n    c->app_io_ctrl.segment_index = c->segment_index;\n    c->app_io_ctrl.retry_counter = 0;\n\n    if (av_strstart(arg, c->inner_scheme, NULL)) {\n        snprintf(c->app_io_ctrl.url, sizeof(c->app_io_ctrl.url), \"%s\", arg);\n    } else {\n        snprintf(c->app_io_ctrl.url, sizeof(c->app_io_ctrl.url), \"%s%s\", c->inner_scheme, arg);\n    }\n\n    return ret;\n}\n\nstatic int ijktcphook_open(URLContext *h, const char *arg, int flags, AVDictionary **options)\n{\n    Context *c = h->priv_data;\n    int ret = 0;\n\n    c->app_ctx = (AVApplicationContext *)av_dict_strtoptr(c->app_ctx_intptr);\n    c->scheme = \"ijktcphook:\";\n    c->inner_scheme = \"tcp:\";\n    ret = ijkurlhook_init(h, arg, flags, options);\n    if (ret)\n        goto fail;\n\n    ret = ijkurlhook_reconnect(h, NULL);\n    if (ret)\n        goto fail;\n\nfail:\n    return ret;\n}\n\nstatic int ijkurlhook_close(URLContext *h)\n{\n    Context *c = h->priv_data;\n\n    av_dict_free(&c->inner_options);\n    return ffurl_closep(&c->inner);\n}\n\nstatic int ijkurlhook_read(URLContext *h, unsigned char *buf, int size)\n{\n    Context *c = h->priv_data;\n    int ret = 0;\n\n    if (c->io_error < 0)\n        return c->io_error;\n\n    if (c->test_fail_point_next > 0 && c->logical_pos >= c->test_fail_point_next) {\n        av_log(h, AV_LOG_ERROR, \"test fail point:%\"PRId64\"\\n\", c->test_fail_point_next);\n        c->io_error = AVERROR(EIO);\n        return AVERROR(EIO);\n    }\n\n    ret = ffurl_read(c->inner, buf, size);\n    if (ret > 0)\n        c->logical_pos += ret;\n    else\n        c->io_error = ret;\n\n    return ret;\n}\n\nstatic int ijkurlhook_write(URLContext *h, const unsigned char *buf, int size)\n{\n    Context *c = h->priv_data;\n\n    return ffurl_write(c->inner, buf, size);\n}\n\nstatic int64_t ijkurlhook_seek(URLContext *h, int64_t pos, int whence)\n{\n    Context *c = h->priv_data;\n    int64_t seek_ret = 0;\n\n    seek_ret = ffurl_seek(c->inner, pos, whence);\n    if (seek_ret < 0) {\n        c->io_error = (int)seek_ret;\n        return seek_ret;\n    }\n\n    c->logical_pos = seek_ret;\n    if (c->test_fail_point)\n        c->test_fail_point_next = c->logical_pos + c->test_fail_point;\n\n    c->io_error = 0;\n    return seek_ret;\n}\n\nstatic int ijkhttphook_reconnect_at(URLContext *h, int64_t offset)\n{\n    int           ret        = 0;\n    AVDictionary *extra_opts = NULL;\n\n    av_dict_set_int(&extra_opts, \"offset\", offset, 0);\n    av_dict_set_int(&extra_opts, \"dns_cache_clear\", 1, 0);\n    ret = ijkurlhook_reconnect(h, extra_opts);\n    av_dict_free(&extra_opts);\n    return ret;\n}\n\nstatic int ijkhttphook_open(URLContext *h, const char *arg, int flags, AVDictionary **options)\n{\n    Context *c = h->priv_data;\n    int ret = 0;\n\n    c->app_ctx = (AVApplicationContext *)av_dict_strtoptr(c->app_ctx_intptr);\n    c->scheme = \"ijkhttphook:\";\n    if (av_stristart(arg, \"ijkhttphook:https:\", NULL))\n        c->inner_scheme = \"https:\";\n    else\n        c->inner_scheme = \"http:\";\n\n    ret = ijkurlhook_init(h, arg, flags, options);\n    if (ret)\n        goto fail;\n\n    ret = ijkurlhook_call_inject(h);\n    if (ret)\n        goto fail;\n\n    ret = ijkurlhook_reconnect(h, NULL);\n    while (ret) {\n        int inject_ret = 0;\n\n        switch (ret) {\n            case AVERROR_EXIT:\n                goto fail;\n        }\n\n        c->app_io_ctrl.retry_counter++;\n        inject_ret = ijkurlhook_call_inject(h);\n        if (inject_ret) {\n            ret = AVERROR_EXIT;\n            goto fail;\n        }\n\n        if (!c->app_io_ctrl.is_handled)\n            goto fail;\n\n        av_log(h, AV_LOG_INFO, \"%s: will reconnect at start\\n\", __func__);\n        ret = ijkhttphook_reconnect_at(h, 0);\n        av_log(h, AV_LOG_INFO, \"%s: did reconnect at start: %d\\n\", __func__, ret);\n    }\n\nfail:\n    return ret;\n}\n\nstatic int ijkhttphook_read(URLContext *h, unsigned char *buf, int size)\n{\n    Context *c = h->priv_data;\n    int ret = 0;\n\n    c->app_io_ctrl.retry_counter = 0;\n\n    ret = ijkurlhook_read(h, buf, size);\n    while (ret < 0 && !h->is_streamed && c->logical_pos < c->logical_size) {\n        switch (ret) {\n            case AVERROR_EXIT:\n                goto fail;\n        }\n\n        c->app_io_ctrl.retry_counter++;\n        ret = ijkurlhook_call_inject(h);\n        if (ret)\n            goto fail;\n\n        if (!c->app_io_ctrl.is_handled)\n            goto fail;\n\n        av_log(h, AV_LOG_INFO, \"%s: will reconnect(%d) at %\"PRId64\"\\n\", __func__, c->app_io_ctrl.retry_counter, c->logical_pos);\n        ret = ijkhttphook_reconnect_at(h, c->logical_pos);\n        av_log(h, AV_LOG_INFO, \"%s: did reconnect(%d) at %\"PRId64\": %d\\n\", __func__, c->app_io_ctrl.retry_counter, c->logical_pos, ret);\n        if (ret < 0)\n            continue;\n\n        ret = ijkurlhook_read(h, buf, size);\n    }\n\nfail:\n    if (ret <= 0) {\n        c->io_error = ret;\n    }\n    return ret;\n}\n\nstatic int64_t ijkhttphook_reseek_at(URLContext *h, int64_t pos, int whence, int force_reconnect)\n{\n    Context *c = h->priv_data;\n    int ret = 0;\n\n    if (!force_reconnect)\n        return ijkurlhook_seek(h, pos, whence);\n\n    if (whence == SEEK_CUR)\n        pos += c->logical_pos;\n    else if (whence == SEEK_END)\n        pos += c->logical_size;\n    else if (whence != SEEK_SET)\n        return AVERROR(EINVAL);\n    if (pos < 0)\n        return AVERROR(EINVAL);\n\n    ret = ijkhttphook_reconnect_at(h, pos);\n    if (ret) {\n        c->io_error = ret;\n        return ret;\n    }\n\n    c->io_error = 0;\n    return c->logical_pos;\n}\n\nstatic int64_t ijkhttphook_seek(URLContext *h, int64_t pos, int whence)\n{\n    Context *c = h->priv_data;\n    int     ret      = 0;\n    int64_t seek_ret = -1;\n\n    if (whence == AVSEEK_SIZE)\n        return c->logical_size;\n    else if ((whence == SEEK_CUR && pos == 0) ||\n             (whence == SEEK_SET && pos == c->logical_pos))\n        return c->logical_pos;\n    else if ((c->logical_size < 0 && whence == SEEK_END) || h->is_streamed)\n        return AVERROR(ENOSYS);\n\n    c->app_io_ctrl.retry_counter = 0;\n    ret = ijkurlhook_call_inject(h);\n    if (ret) {\n        ret = AVERROR_EXIT;\n        goto fail;\n    }\n\n    seek_ret = ijkhttphook_reseek_at(h, pos, whence, c->app_io_ctrl.is_url_changed);\n    while (seek_ret < 0) {\n        switch (seek_ret) {\n            case AVERROR_EXIT:\n            case AVERROR_EOF:\n                goto fail;\n        }\n\n        c->app_io_ctrl.retry_counter++;\n        ret = ijkurlhook_call_inject(h);\n        if (ret) {\n            ret = AVERROR_EXIT;\n            goto fail;\n        }\n\n        if (!c->app_io_ctrl.is_handled)\n            goto fail;\n\n        av_log(h, AV_LOG_INFO, \"%s: will reseek(%d) at pos=%\"PRId64\", whence=%d\\n\", __func__, c->app_io_ctrl.retry_counter, pos, whence);\n        seek_ret = ijkhttphook_reseek_at(h, pos, whence, c->app_io_ctrl.is_url_changed);\n        av_log(h, AV_LOG_INFO, \"%s: did reseek(%d) at pos=%\"PRId64\", whence=%d: %\"PRId64\"\\n\", __func__, c->app_io_ctrl.retry_counter, pos, whence, seek_ret);\n    }\n\n    if (c->test_fail_point)\n        c->test_fail_point_next = c->logical_pos + c->test_fail_point;\n    c->io_error = 0;\n    return c->logical_pos;\nfail:\n    return ret;\n}\n\n#define OFFSET(x) offsetof(Context, x)\n#define D AV_OPT_FLAG_DECODING_PARAM\n\nstatic const AVOption ijktcphook_options[] = {\n    { \"ijktcphook-test-fail-point\",     \"test fail point, in bytes\",\n        OFFSET(test_fail_point),        AV_OPT_TYPE_INT,   {.i64 = 0}, 0,         INT_MAX, D },\n    { \"ijkapplication\", \"AVApplicationContext\", OFFSET(app_ctx_intptr), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, .flags = D },\n\n    { NULL }\n};\n\nstatic const AVOption ijkhttphook_options[] = {\n    { \"ijkinject-segment-index\",        \"segment index of current url\",\n        OFFSET(segment_index),          AV_OPT_TYPE_INT,   {.i64 = 0}, 0,         INT_MAX, D },\n    { \"ijkhttphook-test-fail-point\",    \"test fail point, in bytes\",\n        OFFSET(test_fail_point),        AV_OPT_TYPE_INT,   {.i64 = 0}, 0,         INT_MAX, D },\n    { \"ijkapplication\", \"AVApplicationContext\", OFFSET(app_ctx_intptr), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, .flags = D },\n    { NULL }\n};\n\n#undef D\n#undef OFFSET\n\nstatic const AVClass ijktcphook_context_class = {\n    .class_name = \"TcpHook\",\n    .item_name  = av_default_item_name,\n    .option     = ijktcphook_options,\n    .version    = LIBAVUTIL_VERSION_INT,\n};\n\nURLProtocol ijkimp_ff_ijktcphook_protocol = {\n    .name                = \"ijktcphook\",\n    .url_open2           = ijktcphook_open,\n    .url_read            = ijkurlhook_read,\n    .url_write           = ijkurlhook_write,\n    .url_close           = ijkurlhook_close,\n    .priv_data_size      = sizeof(Context),\n    .priv_data_class     = &ijktcphook_context_class,\n};\n\nstatic const AVClass ijkhttphook_context_class = {\n    .class_name = \"HttpHook\",\n    .item_name  = av_default_item_name,\n    .option     = ijkhttphook_options,\n    .version    = LIBAVUTIL_VERSION_INT,\n};\n\nURLProtocol ijkimp_ff_ijkhttphook_protocol = {\n    .name                = \"ijkhttphook\",\n    .url_open2           = ijkhttphook_open,\n    .url_read            = ijkhttphook_read,\n    .url_write           = ijkurlhook_write,\n    .url_seek            = ijkhttphook_seek,\n    .url_close           = ijkurlhook_close,\n    .priv_data_size      = sizeof(Context),\n    .priv_data_class     = &ijkhttphook_context_class,\n};\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavutil/ijkdict.c",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * Copyright (c) 2016 Raymond Zheng <raymondzheng1412@gmail.com>\n *\n * This file is part of FFmpeg.\n *\n * FFmpeg is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * FFmpeg is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijkdict.h\"\n#include \"ijkutils.h\"\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <ctype.h>\n#include <inttypes.h>\n\nstruct IjkAVDictionary {\n    int count;\n    IjkAVDictionaryEntry *elems;\n};\n\nint ijk_av_dict_count(const IjkAVDictionary *m)\n{\n    return m ? m->count : 0;\n}\n\nIjkAVDictionaryEntry *ijk_av_dict_get(const IjkAVDictionary *m, const char *key,\n                               const IjkAVDictionaryEntry *prev, int flags)\n{\n    unsigned int i, j;\n\n    if (!m)\n        return NULL;\n\n    if (prev)\n        i = prev - m->elems + 1;\n    else\n        i = 0;\n\n    for (; i < m->count; i++) {\n        const char *s = m->elems[i].key;\n        if (flags & IJK_AV_DICT_MATCH_CASE)\n            for (j = 0; s[j] == key[j] && key[j]; j++)\n                ;\n        else\n            for (j = 0; toupper(s[j]) == toupper(key[j]) && key[j]; j++)\n                ;\n        if (key[j])\n            continue;\n        if (s[j] && !(flags & IJK_AV_DICT_IGNORE_SUFFIX))\n            continue;\n        return &m->elems[i];\n    }\n    return NULL;\n}\n\nint ijk_av_dict_set(IjkAVDictionary **pm, const char *key, const char *value,\n                int flags)\n{\n    IjkAVDictionary *m = *pm;\n    IjkAVDictionaryEntry *tag = NULL;\n    char *oldval = NULL, *copy_key = NULL, *copy_value = NULL;\n\n    if (!(flags & IJK_AV_DICT_MULTIKEY)) {\n        tag = ijk_av_dict_get(m, key, NULL, flags);\n    }\n    if (flags & IJK_AV_DICT_DONT_STRDUP_KEY)\n        copy_key = (void *)key;\n    else\n        copy_key = strdup(key);\n    if (flags & IJK_AV_DICT_DONT_STRDUP_VAL)\n        copy_value = (void *)value;\n    else if (copy_key)\n        copy_value = strdup(value);\n    if (!m)\n        m = *pm = (IjkAVDictionary *)calloc(1, sizeof(*m));\n    if (!m || (key && !copy_key) || (value && !copy_value))\n        goto err_out;\n\n    if (tag) {\n        if (flags & IJK_AV_DICT_DONT_OVERWRITE) {\n            free(copy_key);\n            free(copy_value);\n            return 0;\n        }\n        if (flags & IJK_AV_DICT_APPEND)\n            oldval = tag->value;\n        else\n            free(tag->value);\n            free(tag->key);\n        *tag = m->elems[--m->count];\n    } else if (copy_value) {\n        IjkAVDictionaryEntry *tmp = (IjkAVDictionaryEntry *)realloc(m->elems,\n                                            (m->count + 1) * sizeof(*m->elems));\n        if (!tmp)\n            goto err_out;\n        m->elems = tmp;\n    }\n    if (copy_value) {\n        m->elems[m->count].key = copy_key;\n        m->elems[m->count].value = copy_value;\n        if (oldval && flags & IJK_AV_DICT_APPEND) {\n            size_t len = strlen(oldval) + strlen(copy_value) + 1;\n            char *newval = (char *)calloc(1, len);\n            if (!newval)\n                goto err_out;\n            strlcat(newval, oldval, len);\n            ijk_av_freep(&oldval);\n            strlcat(newval, copy_value, len);\n            m->elems[m->count].value = newval;\n            ijk_av_freep(&copy_value);\n        }\n        m->count++;\n    } else {\n        ijk_av_freep(&copy_key);\n    }\n    if (!m->count) {\n        ijk_av_freep(&m->elems);\n        ijk_av_freep(pm);\n    }\n\n    return 0;\n\nerr_out:\n    if (m && !m->count) {\n        ijk_av_freep(&m->elems);\n        ijk_av_freep(pm);\n    }\n    free(copy_key);\n    free(copy_value);\n    return -1;\n}\n\nint ijk_av_dict_set_int(IjkAVDictionary **pm, const char *key, int64_t value,\n                int flags)\n{\n    char valuestr[22];\n    snprintf(valuestr, sizeof(valuestr), \"%\"PRId64, value);\n    flags &= ~IJK_AV_DICT_DONT_STRDUP_VAL;\n    return ijk_av_dict_set(pm, key, valuestr, flags);\n}\n\nint ijk_av_dict_set_intptr(IjkAVDictionary **pm, const char *key, uintptr_t value, int flags) {\n    char valuestr[22];\n    snprintf(valuestr, sizeof(valuestr), \"%p\", value);\n    flags &= ~IJK_AV_DICT_DONT_STRDUP_VAL;\n    return ijk_av_dict_set(pm, key, valuestr, flags);\n}\n\nuintptr_t ijk_av_dict_strtoptr(char * value) {\n    uintptr_t ptr = NULL;\n    char *next = NULL;\n    if(value[0] !='0' || (value[1]|0x20)!='x') {\n        return NULL;\n    }\n    ptr = strtoll(value, &next, 16);\n    if (next == value) {\n        return NULL;\n    }\n    return ptr;\n}\n\nuintptr_t ijk_av_dict_get_intptr(const IjkAVDictionary *m, const char* key) {\n    uintptr_t ptr = NULL;\n    IjkAVDictionaryEntry *t = NULL;\n    if ((t = av_dict_get(m, key, NULL, 0))) {\n        return ijk_av_dict_strtoptr(t->value);\n    }\n    return NULL;\n}\n\nvoid ijk_av_dict_free(IjkAVDictionary **pm)\n{\n    IjkAVDictionary *m = *pm;\n\n    if (m) {\n        while (m->count--) {\n            ijk_av_freep(&m->elems[m->count].key);\n            ijk_av_freep(&m->elems[m->count].value);\n        }\n        ijk_av_freep(&m->elems);\n    }\n    ijk_av_freep(pm);\n}\n\nint ijk_av_dict_copy(IjkAVDictionary **dst, const IjkAVDictionary *src, int flags)\n{\n    IjkAVDictionaryEntry *t = NULL;\n\n    while ((t = ijk_av_dict_get(src, \"\", t, IJK_AV_DICT_IGNORE_SUFFIX))) {\n        int ret = ijk_av_dict_set(dst, t->key, t->value, flags);\n        if (ret < 0)\n            return ret;\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavutil/ijkdict.h",
    "content": "/*\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have ijkPlayer a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n/**\n * @file\n * Public dictionary API.\n * @deprecated\n *  AVDictionary is provided for compatibility with libav. It is both in\n *  implementation as well as API inefficient. It does not scale and is\n *  extremely slow with large dictionaries.\n *  It is recommended that new code uses our tree container from tree.c/h\n *  where applicable, which uses AVL trees to achieve O(log n) performance.\n */\n\n#ifndef IJKAVUTIL_IJKDICT_H\n#define IJKAVUTIL_IJKDICT_H\n\n#include <stdint.h>\n\n#define IJK_AV_DICT_MATCH_CASE      1   /**< Only get an entry with exact-case key match. Only relevant in av_dict_get(). */\n#define IJK_AV_DICT_IGNORE_SUFFIX   2   /**< Return first entry in a dictionary whose first part corresponds to the search key,\n                                         ignoring the suffix of the found key string. Only relevant in av_dict_get(). */\n#define IJK_AV_DICT_DONT_STRDUP_KEY 4   /**< Take ownership of a key that's been\n                                         allocated with av_malloc() or another memory allocation function. */\n#define IJK_AV_DICT_DONT_STRDUP_VAL 8   /**< Take ownership of a value that's been\n                                         allocated with av_malloc() or another memory allocation function. */\n#define IJK_AV_DICT_DONT_OVERWRITE 16   ///< Don't overwrite existing entries.\n#define IJK_AV_DICT_APPEND         32   /**< If the entry already exists, append to it.  Note that no\n                                      delimiter is added, the strings are simply concatenated. */\n#define IJK_AV_DICT_MULTIKEY       64   /**< Allow to store several equal keys in the dictionary */\n\ntypedef struct IjkAVDictionaryEntry {\n    char *key;\n    char *value;\n} IjkAVDictionaryEntry;\n\ntypedef struct IjkAVDictionary IjkAVDictionary;\n\n/**\n * Get a dictionary entry with matching key.\n *\n * The returned entry key or value must not be changed, or it will\n * cause undefined behavior.\n *\n * To iterate through all the dictionary entries, you can set the matching key\n * to the null string \"\" and set the AV_DICT_IGNORE_SUFFIX flag.\n *\n * @param prev Set to the previous matching element to find the next.\n *             If set to NULL the first matching element is returned.\n * @param key matching key\n * @param flags a collection of AV_DICT_* flags controlling how the entry is retrieved\n * @return found entry or NULL in case no matching entry was found in the dictionary\n */\nIjkAVDictionaryEntry *ijk_av_dict_get(const IjkAVDictionary *m, const char *key,\n                               const IjkAVDictionaryEntry *prev, int flags);\n\n/**\n * Get number of entries in dictionary.\n *\n * @param m dictionary\n * @return  number of entries in dictionary\n */\nint ijk_av_dict_count(const IjkAVDictionary *m);\n\n/**\n * Set the given entry in *pm, overwriting an existing entry.\n *\n * Note: If AV_DICT_DONT_STRDUP_KEY or AV_DICT_DONT_STRDUP_VAL is set,\n * these arguments will be freed on error.\n *\n * Warning: Adding a new entry to a dictionary invalidates all existing entries\n * previously returned with av_dict_get.\n *\n * @param pm pointer to a pointer to a dictionary struct. If *pm is NULL\n * a dictionary struct is allocated and put in *pm.\n * @param key entry key to add to *pm (will either be av_strduped or added as a new key depending on flags)\n * @param value entry value to add to *pm (will be av_strduped or added as a new key depending on flags).\n *        Passing a NULL value will cause an existing entry to be deleted.\n * @return >= 0 on success otherwise an error code <0\n */\nint ijk_av_dict_set(IjkAVDictionary **pm, const char *key, const char *value, int flags);\n\n/**\n * Convenience wrapper for av_dict_set that converts the value to a string\n * and stores it.\n *\n * Note: If AV_DICT_DONT_STRDUP_KEY is set, key will be freed on error.\n */\nint ijk_av_dict_set_int(IjkAVDictionary **pm, const char *key, int64_t value, int flags);\n\nint ijk_av_dict_set_intptr(IjkAVDictionary **pm, const char *key, uintptr_t value, int flags);\n\nuintptr_t ijk_av_dict_get_intptr(const IjkAVDictionary *m, const char* key);\n\n/**\n * Copy entries from one AVDictionary struct into another.\n * @param dst pointer to a pointer to a AVDictionary struct. If *dst is NULL,\n *            this function will allocate a struct for you and put it in *dst\n * @param src pointer to source AVDictionary struct\n * @param flags flags to use when setting entries in *dst\n * @note metadata is read using the AV_DICT_IGNORE_SUFFIX flag\n * @return 0 on success, negative AVERROR code on failure. If dst was allocated\n *           by this function, callers should free the associated memory.\n */\nint ijk_av_dict_copy(IjkAVDictionary **dst, const IjkAVDictionary *src, int flags);\n\n/**\n * Free all the memory allocated for an AVDictionary struct\n * and all keys and values.\n */\nvoid ijk_av_dict_free(IjkAVDictionary **m);\n\n\n/**\n * @}\n */\n\n#endif /* IJKAVUTIL_IJKDICT_H */\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavutil/ijkfifo.c",
    "content": "/*\n * a very simple circular buffer FIFO implementation\n * Copyright (c) 2000, 2001, 2002 Fabrice Bellard\n * Copyright (c) 2006 Roman Shaposhnik\n *\n * This file is part of Ijkplayer.\n *\n * Ijkplayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * Ijkplayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with Ijkplayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijkfifo.h\"\n#include \"ijkutils.h\"\n#include <stdlib.h>\n#include <assert.h>\n#include <string.h>\n\nstatic IjkFifoBuffer *fifo_alloc_common(void *buffer, size_t size)\n{\n    IjkFifoBuffer *f;\n    if (!buffer)\n        return NULL;\n    f = calloc(1, sizeof(IjkFifoBuffer));\n    if (!f) {\n        free(buffer);\n        return NULL;\n    }\n    f->buffer = buffer;\n    f->end    = f->buffer + size;\n    ijk_av_fifo_reset(f);\n    return f;\n}\n\nIjkFifoBuffer *ijk_av_fifo_alloc(unsigned int size)\n{\n    void *buffer = malloc(size);\n    return fifo_alloc_common(buffer, size);\n}\n\nIjkFifoBuffer *ijk_av_fifo_alloc_array(size_t nmemb, size_t size)\n{\n    void *buffer = calloc(nmemb, size);\n    return fifo_alloc_common(buffer, nmemb * size);\n}\n\nvoid ijk_av_fifo_free(IjkFifoBuffer *f)\n{\n    if (f) {\n        ijk_av_freep(&f->buffer);\n        free(f);\n    }\n}\n\nvoid ijk_av_fifo_freep(IjkFifoBuffer **f)\n{\n    if (f) {\n        ijk_av_fifo_free(*f);\n        *f = NULL;\n    }\n}\n\nvoid ijk_av_fifo_reset(IjkFifoBuffer *f)\n{\n    f->wptr = f->rptr = f->buffer;\n    f->wndx = f->rndx = 0;\n}\n\nint ijk_av_fifo_size(const IjkFifoBuffer *f)\n{\n    return (uint32_t)(f->wndx - f->rndx);\n}\n\nint ijk_av_fifo_space(const IjkFifoBuffer *f)\n{\n    return f->end - f->buffer - ijk_av_fifo_size(f);\n}\n\nint ijk_av_fifo_realloc2(IjkFifoBuffer *f, unsigned int new_size)\n{\n    unsigned int old_size = f->end - f->buffer;\n\n    if (old_size < new_size) {\n        int len          = ijk_av_fifo_size(f);\n        IjkFifoBuffer *f2 = ijk_av_fifo_alloc(new_size);\n\n        if (!f2)\n            return -1;\n        ijk_av_fifo_generic_read(f, f2->buffer, len, NULL);\n        f2->wptr += len;\n        f2->wndx += len;\n        free(f->buffer);\n        *f = *f2;\n        free(f2);\n    }\n    return 0;\n}\n\nint ijk_av_fifo_grow(IjkFifoBuffer *f, unsigned int size)\n{\n    unsigned int old_size = f->end - f->buffer;\n    if(size + (unsigned)ijk_av_fifo_size(f) < size)\n        return -1;\n\n    size += ijk_av_fifo_size(f);\n\n    if (old_size < size)\n        return ijk_av_fifo_realloc2(f, FFMAX(size, 2*old_size));\n    return 0;\n}\n\n/* src must NOT be const as it can be a context for func that may need\n * updating (like a pointer or byte counter) */\nint ijk_av_fifo_generic_write(IjkFifoBuffer *f, void *src, int size,\n                          int (*func)(void *, void *, int))\n{\n    int total = size;\n    uint32_t wndx= f->wndx;\n    uint8_t *wptr= f->wptr;\n\n    do {\n        int len = FFMIN(f->end - wptr, size);\n        if (func) {\n            len = func(src, wptr, len);\n            if (len <= 0)\n                break;\n        } else {\n            memcpy(wptr, src, len);\n            src = (uint8_t *)src + len;\n        }\n// Write memory barrier needed for SMP here in theory\n        wptr += len;\n        if (wptr >= f->end)\n            wptr = f->buffer;\n        wndx    += len;\n        size    -= len;\n    } while (size > 0);\n    f->wndx= wndx;\n    f->wptr= wptr;\n    return total - size;\n}\n\nint ijk_av_fifo_generic_peek_at(IjkFifoBuffer *f, void *dest, int offset, int buf_size, void (*func)(void*, void*, int))\n{\n    uint8_t *rptr = f->rptr;\n\n    assert(offset >= 0);\n\n    /*\n     * *ndx are indexes modulo 2^32, they are intended to overflow,\n     * to handle *ndx greater than 4gb.\n     */\n    assert(buf_size + (unsigned)offset <= f->wndx - f->rndx);\n\n    if (offset >= f->end - rptr)\n        rptr += offset - (f->end - f->buffer);\n    else\n        rptr += offset;\n\n    while (buf_size > 0) {\n        int len;\n\n        if (rptr >= f->end)\n            rptr -= f->end - f->buffer;\n\n        len = FFMIN(f->end - rptr, buf_size);\n        if (func)\n            func(dest, rptr, len);\n        else {\n            memcpy(dest, rptr, len);\n            dest = (uint8_t *)dest + len;\n        }\n\n        buf_size -= len;\n        rptr     += len;\n    }\n\n    return 0;\n}\n\nint ijk_av_fifo_generic_peek(IjkFifoBuffer *f, void *dest, int buf_size,\n                         void (*func)(void *, void *, int))\n{\n// Read memory barrier needed for SMP here in theory\n    uint8_t *rptr = f->rptr;\n\n    do {\n        int len = FFMIN(f->end - rptr, buf_size);\n        if (func)\n            func(dest, rptr, len);\n        else {\n            memcpy(dest, rptr, len);\n            dest = (uint8_t *)dest + len;\n        }\n// memory barrier needed for SMP here in theory\n        rptr += len;\n        if (rptr >= f->end)\n            rptr -= f->end - f->buffer;\n        buf_size -= len;\n    } while (buf_size > 0);\n\n    return 0;\n}\n\nint ijk_av_fifo_generic_read(IjkFifoBuffer *f, void *dest, int buf_size,\n                         void (*func)(void *, void *, int))\n{\n// Read memory barrier needed for SMP here in theory\n    do {\n        int len = FFMIN(f->end - f->rptr, buf_size);\n        if (func)\n            func(dest, f->rptr, len);\n        else {\n            memcpy(dest, f->rptr, len);\n            dest = (uint8_t *)dest + len;\n        }\n// memory barrier needed for SMP here in theory\n        ijk_av_fifo_drain(f, len);\n        buf_size -= len;\n    } while (buf_size > 0);\n    return 0;\n}\n\n/** Discard data from the FIFO. */\nvoid ijk_av_fifo_drain(IjkFifoBuffer *f, int size)\n{\n    assert(ijk_av_fifo_size(f) >= size);\n    f->rptr += size;\n    if (f->rptr >= f->end)\n        f->rptr -= f->end - f->buffer;\n    f->rndx += size;\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavutil/ijkfifo.h",
    "content": "/*\n * This file is part of Ijkplayer.\n *\n * Ijkplayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * Ijkplayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with Ijkplayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n/**\n * @file\n * a very simple circular buffer FIFO implementation\n */\n\n#ifndef IJKUTIL_IJKFIFO_H\n#define IJKUTIL_IJKFIFO_H\n\n#include <stdint.h>\n#include <stddef.h>\n\ntypedef struct IjkFifoBuffer {\n    uint8_t *buffer;\n    uint8_t *rptr, *wptr, *end;\n    uint64_t rndx, wndx;\n} IjkFifoBuffer;\n\n/**\n * Initialize an IjkFifoBuffer.\n * @param size of FIFO\n * @return IjkFifoBuffer or NULL in case of memory allocation failure\n */\nIjkFifoBuffer *ijk_av_fifo_alloc(unsigned int size);\n\n/**\n * Initialize an IjkFifoBuffer.\n * @param nmemb number of elements\n * @param size  size of the single element\n * @return IjkFifoBuffer or NULL in case of memory allocation failure\n */\nIjkFifoBuffer *ijk_av_fifo_alloc_array(size_t nmemb, size_t size);\n\n/**\n * Free an IjkFifoBuffer.\n * @param f IjkFifoBuffer to free\n */\nvoid ijk_av_fifo_free(IjkFifoBuffer *f);\n\n/**\n * Free an IjkFifoBuffer and reset pointer to NULL.\n * @param f IjkFifoBuffer to free\n */\nvoid ijk_av_fifo_freep(IjkFifoBuffer **f);\n\n/**\n * Reset the IjkFifoBuffer to the state right after ijk_av_fifo_alloc, in particular it is emptied.\n * @param f IjkFifoBuffer to reset\n */\nvoid ijk_av_fifo_reset(IjkFifoBuffer *f);\n\n/**\n * Return the amount of data in bytes in the IjkFifoBuffer, that is the\n * amount of data you can read from it.\n * @param f IjkFifoBuffer to read from\n * @return size\n */\nint ijk_av_fifo_size(const IjkFifoBuffer *f);\n\n/**\n * Return the amount of space in bytes in the IjkFifoBuffer, that is the\n * amount of data you can write into it.\n * @param f IjkFifoBuffer to write into\n * @return size\n */\nint ijk_av_fifo_space(const IjkFifoBuffer *f);\n\n/**\n * Feed data at specific position from an IjkFifoBuffer to a user-supplied callback.\n * Similar as ijk_av_fifo_gereric_read but without discarding data.\n * @param f IjkFifoBuffer to read from\n * @param offset offset from current read position\n * @param buf_size number of bytes to read\n * @param func generic read function\n * @param dest data destination\n */\nint ijk_av_fifo_generic_peek_at(IjkFifoBuffer *f, void *dest, int offset, int buf_size, void (*func)(void*, void*, int));\n\n/**\n * Feed data from an IjkFifoBuffer to a user-supplied callback.\n * Similar as ijk_av_fifo_gereric_read but without discarding data.\n * @param f IjkFifoBuffer to read from\n * @param buf_size number of bytes to read\n * @param func generic read function\n * @param dest data destination\n */\nint ijk_av_fifo_generic_peek(IjkFifoBuffer *f, void *dest, int buf_size, void (*func)(void*, void*, int));\n\n/**\n * Feed data from an IjkFifoBuffer to a user-supplied callback.\n * @param f IjkFifoBuffer to read from\n * @param buf_size number of bytes to read\n * @param func generic read function\n * @param dest data destination\n */\nint ijk_av_fifo_generic_read(IjkFifoBuffer *f, void *dest, int buf_size, void (*func)(void*, void*, int));\n\n/**\n * Feed data from a user-supplied callback to an IjkFifoBuffer.\n * @param f IjkFifoBuffer to write to\n * @param src data source; non-const since it may be used as a\n * modifiable context by the function defined in func\n * @param size number of bytes to write\n * @param func generic write function; the first parameter is src,\n * the second is dest_buf, the third is dest_buf_size.\n * func must return the number of bytes written to dest_buf, or <= 0 to\n * indicate no more data available to write.\n * If func is NULL, src is interpreted as a simple byte array for source data.\n * @return the number of bytes written to the FIFO\n */\nint ijk_av_fifo_generic_write(IjkFifoBuffer *f, void *src, int size, int (*func)(void*, void*, int));\n\n/**\n * Resize an IjkFifoBuffer.\n * In case of reallocation failure, the old FIFO is kept unchanged.\n *\n * @param f IjkFifoBuffer to resize\n * @param size new IjkFifoBuffer size in bytes\n * @return <0 for failure, >=0 otherwise\n */\nint ijk_av_fifo_realloc2(IjkFifoBuffer *f, unsigned int size);\n\n/**\n * Enlarge an IjkFifoBuffer.\n * In case of reallocation failure, the old FIFO is kept unchanged.\n * The new fifo size may be larger than the requested size.\n *\n * @param f IjkFifoBuffer to resize\n * @param additional_space the amount of space in bytes to allocate in addition to ijk_av_fifo_size()\n * @return <0 for failure, >=0 otherwise\n */\nint ijk_av_fifo_grow(IjkFifoBuffer *f, unsigned int additional_space);\n\n/**\n * Read and discard the specified amount of data from an IjkFifoBuffer.\n * @param f IjkFifoBuffer to read from\n * @param size amount of data to read in bytes\n */\nvoid ijk_av_fifo_drain(IjkFifoBuffer *f, int size);\n\n/**\n * Return a pointer to the data stored in a FIFO buffer at a certain offset.\n * The FIFO buffer is not modified.\n *\n * @param f    IjkFifoBuffer to peek at, f must be non-NULL\n * @param offs an offset in bytes, its absolute value must be less\n *             than the used buffer size or the returned pointer will\n *             point outside to the buffer data.\n *             The used buffer size can be checked with ijk_av_fifo_size().\n */\nstatic inline uint8_t *ijk_av_fifo_peek2(const IjkFifoBuffer *f, int offs)\n{\n    uint8_t *ptr = f->rptr + offs;\n    if (ptr >= f->end)\n        ptr = f->buffer + (ptr - f->end);\n    else if (ptr < f->buffer)\n        ptr = f->end - (f->buffer - ptr);\n    return ptr;\n}\n\n#endif /* IJKUTIL_IJKFIFO_H */\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavutil/ijkstl.cpp",
    "content": "/*\n * Copyright (c) 2016 Raymond Zheng <raymondzheng1412@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n#include <map>\n\nusing namespace std;\n\ntypedef map<int64_t, void *> IjkMap;\n\nextern \"C\" void* ijk_map_create();\nextern \"C\" void ijk_map_put(void *data, int64_t key, void *value);\nextern \"C\" void* ijk_map_get(void *data, int64_t key);\nextern \"C\" int ijk_map_remove(void *data, int64_t key);\nextern \"C\" int ijk_map_size(void *data);\nextern \"C\" int ijk_map_max_size(void *data);\nextern \"C\" void* ijk_map_index_get(void *data, int index);\nextern \"C\" int64_t ijk_map_get_min_key(void *data);\nextern \"C\" void ijk_map_clear(void *data);\nextern \"C\" void ijk_map_destroy(void *data);\nextern \"C\" void ijk_map_traversal_handle(void *data, void *parm, int (*enu)(void *parm, int64_t key, void *elem));\n\nvoid* ijk_map_create() {\n    IjkMap *data = new IjkMap();\n    return data;\n}\n\nvoid ijk_map_put(void *data, int64_t key, void *value) {\n    IjkMap *map_data = reinterpret_cast<IjkMap *>(data);\n    if (!map_data)\n        return;\n    (*map_data)[key] = value;\n}\n\nvoid* ijk_map_get(void *data, int64_t key) {\n    IjkMap *map_data = reinterpret_cast<IjkMap *>(data);\n    if (!map_data)\n        return NULL;\n\n    IjkMap::iterator it = map_data->find(key);\n    if (it != map_data->end()) {\n        return it->second;\n    }\n    return NULL;\n}\n\nint ijk_map_remove(void *data, int64_t key) {\n    IjkMap *map_data = reinterpret_cast<IjkMap *>(data);\n    if (!map_data)\n        return -1;\n    map_data->erase(key);\n    return 0;\n}\n\nint ijk_map_size(void *data) {\n    IjkMap *map_data = reinterpret_cast<IjkMap *>(data);\n    if (!map_data)\n        return 0;\n\n    return map_data->size();\n}\n\nint ijk_map_max_size(void *data) {\n    IjkMap *map_data = reinterpret_cast<IjkMap *>(data);\n    if (!map_data)\n        return 0;\n\n    return map_data->max_size();\n}\n\nvoid* ijk_map_index_get(void *data, int index) {\n    IjkMap *map_data = reinterpret_cast<IjkMap *>(data);\n    if (!map_data || map_data->empty())\n        return NULL;\n\n    IjkMap::iterator it;\n    it = map_data->begin();\n\n    for (int i = 0; i < index; i++) {\n        it = it++;\n        if (it == map_data->end()) {\n            return NULL;\n        }\n    }\n\n    return it->second;\n}\n\nvoid ijk_map_traversal_handle(void *data, void *parm, int (*enu)(void *parm, int64_t key, void *elem)) {\n    IjkMap *map_data = reinterpret_cast<IjkMap *>(data);\n    if (!map_data || map_data->empty())\n        return;\n\n    IjkMap::iterator it;\n\n    for (it = map_data->begin(); it != map_data->end(); it++) {\n        enu(parm, it->first, it->second);\n    }\n}\n\nint64_t ijk_map_get_min_key(void *data) {\n    IjkMap *map_data = reinterpret_cast<IjkMap *>(data);\n    if (!map_data || map_data->empty())\n        return -1;\n\n    IjkMap::iterator it = map_data->begin();\n\n    int64_t min_key = it->first;\n\n    for (; it != map_data->end(); it++) {\n        min_key = min_key < it->first ? min_key : it->first;\n    }\n\n    return min_key;\n}\n\nvoid ijk_map_clear(void *data) {\n    IjkMap *map_data = reinterpret_cast<IjkMap *>(data);\n    if (!map_data)\n        return;\n\n    map_data->clear();\n}\n\nvoid ijk_map_destroy(void *data) {\n    IjkMap *map_data = reinterpret_cast<IjkMap *>(data);\n    if (!map_data)\n        return;\n\n    map_data->clear();\n    delete(map_data);\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavutil/ijkstl.h",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * Copyright (c) 2016 Raymond Zheng <raymondzheng1412@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n#ifndef IJKAVUTIL_IJKSTL_H\n#define IJKAVUTIL_IJKSTL_H\n\n#include <stdint.h>\n\nvoid* ijk_map_create();\nvoid ijk_map_put(void *data, int64_t key, void *value);\nvoid* ijk_map_get(void *data, int64_t key);\nint ijk_map_remove(void *data, int64_t key);\nint ijk_map_size(void *data);\nint ijk_map_max_size(void *data);\nvoid* ijk_map_index_get(void *data, int index);\nvoid ijk_map_traversal_handle(void *data, void *parm, int (*enu)(void *parm, int64_t key, void *elem));\nint64_t ijk_map_get_min_key(void *data);\nvoid ijk_map_clear(void *data);\nvoid ijk_map_destroy(void *data);\n\n#endif /* IJKAVUTIL_IJKSTL_H */\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavutil/ijkthreadpool.c",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * Copyright (c) 2016 Raymond Zheng <raymondzheng1412@gmail.com>\n *\n * This file is part of ijkplayer.\n *\n * ijkplayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkplayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkplayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijkthreadpool.h\"\n#include \"libavutil/log.h\"\n\n#include <stdlib.h>\n#include <unistd.h>\n\n/**\n * @function void *threadpool_thread(void *threadpool)\n * @brief the worker thread\n * @param threadpool the pool which own the thread\n */\nstatic void *ijk_threadpool_thread(void *pool_ctx)\n{\n    IjkThreadPoolContext *ctx = (IjkThreadPoolContext *)pool_ctx;\n    IjkThreadPoolTask task;\n\n    for(;;) {\n        pthread_mutex_lock(&(ctx->lock));\n\n        while((ctx->pending_count == 0) && (!ctx->shutdown)) {\n            pthread_cond_wait(&(ctx->notify), &(ctx->lock));\n        }\n\n        if((ctx->shutdown == IJK_IMMEDIATE_SHUTDOWN) ||\n           ((ctx->shutdown == IJK_LEISURELY_SHUTDOWN) &&\n            (ctx->pending_count == 0))) {\n               break;\n           }\n\n        /* Grab our task */\n        task.function = ctx->queue[ctx->queue_head].function;\n        task.in_arg   = ctx->queue[ctx->queue_head].in_arg;\n        task.out_arg  = ctx->queue[ctx->queue_head].out_arg;\n        ctx->queue_head = (ctx->queue_head + 1) % ctx->queue_size;\n        ctx->pending_count -= 1;\n\n        pthread_mutex_unlock(&(ctx->lock));\n\n        (*(task.function))(task.in_arg, task.out_arg);\n    }\n\n    ctx->started_count--;\n\n    pthread_mutex_unlock(&(ctx->lock));\n    pthread_exit(NULL);\n    return(NULL);\n}\n\nint ijk_threadpool_free(IjkThreadPoolContext *ctx)\n{\n    if(ctx == NULL || ctx->started_count > 0) {\n        return -1;\n    }\n\n    /* Did we manage to allocate ? */\n    if(ctx->threads) {\n        free(ctx->threads);\n        free(ctx->queue);\n\n        /* Because we allocate pool->threads after initializing the\n         mutex and condition variable, we're sure they're\n         initialized. Let's lock the mutex just in case. */\n        pthread_mutex_lock(&(ctx->lock));\n        pthread_mutex_destroy(&(ctx->lock));\n        pthread_cond_destroy(&(ctx->notify));\n    }\n    free(ctx);\n    return 0;\n}\n\nIjkThreadPoolContext *ijk_threadpool_create(int thread_count, int queue_size, int flags)\n{\n    IjkThreadPoolContext *ctx;\n    int i;\n\n    if(thread_count <= 0 || thread_count > MAX_THREADS || queue_size <= 0 || queue_size > MAX_QUEUE) {\n        return NULL;\n    }\n\n    if((ctx = (IjkThreadPoolContext *)calloc(1, sizeof(IjkThreadPoolContext))) == NULL) {\n        goto err;\n    }\n\n    ctx->queue_size = queue_size;\n\n    /* Allocate thread and task queue */\n    ctx->threads = (pthread_t *)calloc(1, sizeof(pthread_t) * thread_count);\n    ctx->queue = (IjkThreadPoolTask *)calloc\n        (queue_size, sizeof(IjkThreadPoolTask));\n\n    /* Initialize mutex and conditional variable first */\n    if((pthread_mutex_init(&(ctx->lock), NULL) != 0) ||\n       (pthread_cond_init(&(ctx->notify), NULL) != 0) ||\n       (ctx->threads == NULL) ||\n       (ctx->queue == NULL)) {\n        goto err;\n    }\n\n    /* Start worker threads */\n    for(i = 0; i < thread_count; i++) {\n        if(pthread_create(&(ctx->threads[i]), NULL,\n                          ijk_threadpool_thread, (void*)ctx) != 0) {\n            ijk_threadpool_destroy(ctx, 0);\n            return NULL;\n        }\n        ctx->thread_count++;\n        ctx->started_count++;\n    }\n\n    return ctx;\n\n err:\n    if(ctx) {\n        ijk_threadpool_free(ctx);\n    }\n    return NULL;\n}\n\nint ijk_threadpool_add(IjkThreadPoolContext *ctx, Runable function,\n                   void *in_arg, void *out_arg, int flags)\n{\n    int err = 0;\n    int next;\n\n    if(ctx == NULL || function == NULL) {\n        return IJK_THREADPOOL_INVALID;\n    }\n\n    if(pthread_mutex_lock(&(ctx->lock)) != 0) {\n        return IJK_THREADPOOL_LOCK_FAILURE;\n    }\n\n    if (ctx->pending_count == MAX_QUEUE || ctx->pending_count == ctx->queue_size) {\n        pthread_mutex_unlock(&ctx->lock);\n        return IJK_THREADPOOL_QUEUE_FULL;\n    }\n\n    if(ctx->pending_count == ctx->queue_size - 1) {\n        int new_pueue_size = (ctx->queue_size * 2) > MAX_QUEUE ? MAX_QUEUE : (ctx->queue_size * 2);\n        IjkThreadPoolTask *new_queue = (IjkThreadPoolTask *)realloc(ctx->queue, sizeof(IjkThreadPoolTask) * new_pueue_size);\n        if (new_queue) {\n            ctx->queue = new_queue;\n            ctx->queue_size = new_pueue_size;\n        }\n    }\n\n    next = (ctx->queue_tail + 1) % ctx->queue_size;\n    do {\n        /* Are we shutting down ? */\n        if(ctx->shutdown) {\n            err = IJK_THREADPOOL_SHUTDOWN;\n            break;\n        }\n\n        /* Add task to queue */\n        ctx->queue[ctx->queue_tail].function = function;\n        ctx->queue[ctx->queue_tail].in_arg   = in_arg;\n        ctx->queue[ctx->queue_tail].out_arg  = out_arg;\n        ctx->queue_tail = next;\n        ctx->pending_count += 1;\n\n        /* pthread_cond_broadcast */\n        if(pthread_cond_signal(&(ctx->notify)) != 0) {\n            err = IJK_THREADPOOL_LOCK_FAILURE;\n            break;\n        }\n    } while(0);\n\n    if(pthread_mutex_unlock(&ctx->lock) != 0) {\n        err = IJK_THREADPOOL_LOCK_FAILURE;\n    }\n\n    return err;\n}\n\nstatic int ijk_threadpool_freep(IjkThreadPoolContext **ctx)\n{\n    int ret = 0;\n\n    if (!ctx || !*ctx)\n        return -1;\n\n    ret = ijk_threadpool_free(*ctx);\n    *ctx = NULL;\n    return ret;\n}\n\nint ijk_threadpool_destroy(IjkThreadPoolContext *ctx, int flags)\n{\n    int i, err = 0;\n\n    if(ctx == NULL) {\n        return IJK_THREADPOOL_INVALID;\n    }\n\n    if(pthread_mutex_lock(&(ctx->lock)) != 0) {\n        return IJK_THREADPOOL_LOCK_FAILURE;\n    }\n\n    do {\n        /* Already shutting down */\n        if(ctx->shutdown) {\n            err = IJK_THREADPOOL_SHUTDOWN;\n            break;\n        }\n\n        ctx->shutdown = flags;\n\n        /* Wake up all worker threads */\n        if((pthread_cond_broadcast(&(ctx->notify)) != 0) ||\n           (pthread_mutex_unlock(&(ctx->lock)) != 0)) {\n            err = IJK_THREADPOOL_LOCK_FAILURE;\n            break;\n        }\n\n        /* Join all worker thread */\n        for(i = 0; i < ctx->thread_count; i++) {\n            if(pthread_join(ctx->threads[i], NULL) != 0) {\n                err = IJK_THREADPOOL_THREAD_FAILURE;\n            }\n        }\n    } while(0);\n\n    /* Only if everything went well do we deallocate the pool */\n    if(!err) {\n        return ijk_threadpool_freep(&ctx);\n    }\n    return err;\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavutil/ijkthreadpool.h",
    "content": "/*\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have ijkPlayer a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef _IJK_THREADPOOL_H_\n#define _IJK_THREADPOOL_H_\n\n#include <pthread.h>\n\n#define MAX_THREADS 100\n#define MAX_QUEUE 1024\n\ntypedef enum {\n    IJK_THREADPOOL_INVALID        = -1,\n    IJK_THREADPOOL_LOCK_FAILURE   = -2,\n    IJK_THREADPOOL_QUEUE_FULL     = -3,\n    IJK_THREADPOOL_SHUTDOWN       = -4,\n    IJK_THREADPOOL_THREAD_FAILURE = -5\n} IjkThreadPoolErrorType;\n\ntypedef enum {\n    IJK_IMMEDIATE_SHUTDOWN = 1,\n    IJK_LEISURELY_SHUTDOWN = 2\n} IjkThreadPoolShutdownType;\n\ntypedef void (*Runable)(void *, void *);\n/**\n *  @struct ThreadPoolTask\n *  @brief the work struct\n *\n *  @var function Pointer to the function that will perform the task.\n *  @var in_arg Argument to be passed to the function.\n *  @var out_arg Argument to be passed to the call function.\n */\n\ntypedef struct IjkThreadPoolTask {\n    Runable function;\n    void *in_arg;\n    void *out_arg;\n} IjkThreadPoolTask;\n\n/**\n *  @struct ThreadPoolContext\n *  @brief The threadpool context struct\n *\n *  @var notify        Condition variable to notify worker threads.\n *  @var threads       Array containing worker threads ID.\n *  @var thread_count  Number of threads\n *  @var queue         Array containing the task queue.\n *  @var queue_size    Size of the task queue.\n *  @var queue_head    Index of the first element.\n *  @var queue_tail    Index of the next element.\n *  @var pending_count Number of pending tasks\n *  @var shutdown      Flag indicating if the pool is shutting down\n *  @var started       Number of started threads\n */\ntypedef struct IjkThreadPoolContext {\n    pthread_mutex_t lock;\n    pthread_cond_t notify;\n    pthread_t *threads;\n    IjkThreadPoolTask *queue;\n    int thread_count;\n    int queue_size;\n    int queue_head;\n    int queue_tail;\n    int pending_count;\n    int shutdown;\n    int started_count;\n} IjkThreadPoolContext;\n\nIjkThreadPoolContext *ijk_threadpool_create(int thread_count, int queue_size, int flags);\n\nint ijk_threadpool_add(IjkThreadPoolContext *ctx, Runable function,\n                   void *in_arg, void *out_arg, int flags);\n\nint ijk_threadpool_destroy(IjkThreadPoolContext *ctx, int flags);\n\n#endif /* _IJK_THREADPOOL_H_ */\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavutil/ijktree.c",
    "content": "/*\n * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>\n *\n * This file is part of FFmpeg.\n *\n * FFmpeg is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * FFmpeg is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijktree.h\"\n#include <stdio.h>\n#include <stdlib.h>\n#include <stddef.h>\n#include <string.h>\n\ntypedef struct IjkAVTreeNode {\n    struct IjkAVTreeNode *child[2];\n    void *elem;\n    int state;\n} IjkAVTreeNode;\n\nconst int ijk_av_tree_node_size = sizeof(IjkAVTreeNode);\n\nstruct IjkAVTreeNode *ijk_av_tree_node_alloc(void)\n{\n    return calloc(1, sizeof(struct IjkAVTreeNode));\n}\n\nvoid *ijk_av_tree_find(const IjkAVTreeNode *t, void *key,\n                   int (*cmp)(const void *key, const void *b), void *next[2])\n{\n    if (t) {\n        unsigned int v = cmp(key, t->elem);\n        if (v) {\n            if (next)\n                next[v >> 31] = t->elem;\n            return ijk_av_tree_find(t->child[(v >> 31) ^ 1], key, cmp, next);\n        } else {\n            if (next) {\n                ijk_av_tree_find(t->child[0], key, cmp, next);\n                ijk_av_tree_find(t->child[1], key, cmp, next);\n            }\n            return t->elem;\n        }\n    }\n    return NULL;\n}\n\nvoid *ijk_av_tree_insert(IjkAVTreeNode **tp, void *key,\n                     int (*cmp)(const void *key, const void *b), IjkAVTreeNode **next)\n{\n    IjkAVTreeNode *t = *tp;\n    if (t) {\n        unsigned int v = cmp(t->elem, key);\n        void *ret;\n        if (!v) {\n            if (*next)\n                return t->elem;\n            else if (t->child[0] || t->child[1]) {\n                int i = !t->child[0];\n                void *next_elem[2];\n                ijk_av_tree_find(t->child[i], key, cmp, next_elem);\n                key = t->elem = next_elem[i];\n                v   = -i;\n            } else {\n                *next = t;\n                *tp   = NULL;\n                return NULL;\n            }\n        }\n        ret = ijk_av_tree_insert(&t->child[v >> 31], key, cmp, next);\n        if (!ret) {\n            int i              = (v >> 31) ^ !!*next;\n            IjkAVTreeNode **child = &t->child[i];\n            t->state += 2 * i - 1;\n\n            if (!(t->state & 1)) {\n                if (t->state) {\n                    /* The following code is equivalent to\n                     * if ((*child)->state * 2 == -t->state)\n                     *     rotate(child, i ^ 1);\n                     * rotate(tp, i);\n                     *\n                     * with rotate():\n                     * static void rotate(AVTreeNode **tp, int i)\n                     * {\n                     *     AVTreeNode *t= *tp;\n                     *\n                     *     *tp = t->child[i];\n                     *     t->child[i] = t->child[i]->child[i ^ 1];\n                     *     (*tp)->child[i ^ 1] = t;\n                     *     i = 4 * t->state + 2 * (*tp)->state + 12;\n                     *     t->state     = ((0x614586 >> i) & 3) - 1;\n                     *     (*tp)->state = ((0x400EEA >> i) & 3) - 1 +\n                     *                    ((*tp)->state >> 1);\n                     * }\n                     * but such a rotate function is both bigger and slower\n                     */\n                    if ((*child)->state * 2 == -t->state) {\n                        *tp                    = (*child)->child[i ^ 1];\n                        (*child)->child[i ^ 1] = (*tp)->child[i];\n                        (*tp)->child[i]        = *child;\n                        *child                 = (*tp)->child[i ^ 1];\n                        (*tp)->child[i ^ 1]    = t;\n\n                        (*tp)->child[0]->state = -((*tp)->state > 0);\n                        (*tp)->child[1]->state = (*tp)->state < 0;\n                        (*tp)->state           = 0;\n                    } else {\n                        *tp                 = *child;\n                        *child              = (*child)->child[i ^ 1];\n                        (*tp)->child[i ^ 1] = t;\n                        if ((*tp)->state)\n                            t->state = 0;\n                        else\n                            t->state >>= 1;\n                        (*tp)->state = -t->state;\n                    }\n                }\n            }\n            if (!(*tp)->state ^ !!*next)\n                return key;\n        }\n        return ret;\n    } else {\n        *tp   = *next;\n        *next = NULL;\n        if (*tp) {\n            (*tp)->elem = key;\n            return NULL;\n        } else\n            return key;\n    }\n}\n\nvoid ijk_av_tree_destroy(IjkAVTreeNode *t)\n{\n    if (t) {\n        ijk_av_tree_destroy(t->child[0]);\n        ijk_av_tree_destroy(t->child[1]);\n        free(t);\n    }\n}\n\nvoid ijk_av_tree_enumerate(IjkAVTreeNode *t, void *opaque,\n                       int (*cmp)(void *opaque, void *elem),\n                       int (*enu)(void *opaque, void *elem))\n{\n    if (t) {\n        int v = cmp ? cmp(opaque, t->elem) : 0;\n        if (v >= 0)\n            ijk_av_tree_enumerate(t->child[0], opaque, cmp, enu);\n        if (v == 0)\n            enu(opaque, t->elem);\n        if (v <= 0)\n            ijk_av_tree_enumerate(t->child[1], opaque, cmp, enu);\n    }\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavutil/ijktree.h",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * Copyright (c) 2016 Raymond Zheng <raymondzheng1412@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKAVUTIL_IJKTREE_H\n#define IJKAVUTIL_IJKTREE_H\n\n/**\n * @addtogroup lavu_tree IjkAVTree\n * @ingroup lavu_data\n *\n * Low-complexity tree container\n *\n * Insertion, removal, finding equal, largest which is smaller than and\n * smallest which is larger than, all have O(log n) worst-case complexity.\n * @{\n */\n\n\nstruct IjkAVTreeNode;\nextern const int ijk_av_tree_node_size;\n\n/**\n * Allocate an IjkAVTreeNode.\n */\nstruct IjkAVTreeNode *ijk_av_tree_node_alloc(void);\n\n/**\n * Find an element.\n * @param root a pointer to the root node of the tree\n * @param next If next is not NULL, then next[0] will contain the previous\n *             element and next[1] the next element. If either does not exist,\n *             then the corresponding entry in next is unchanged.\n * @param cmp compare function used to compare elements in the tree,\n *            API identical to that of Standard C's qsort\n *            It is guranteed that the first and only the first argument to cmp()\n *            will be the key parameter to av_tree_find(), thus it could if the\n *            user wants, be a different type (like an opaque context).\n * @return An element with cmp(key, elem) == 0 or NULL if no such element\n *         exists in the tree.\n */\nvoid *ijk_av_tree_find(const struct IjkAVTreeNode *root, void *key,\n                   int (*cmp)(const void *key, const void *b), void *next[2]);\n\n/**\n * Insert or remove an element.\n *\n * If *next is NULL, then the supplied element will be removed if it exists.\n * If *next is non-NULL, then the supplied element will be inserted, unless\n * it already exists in the tree.\n *\n * @param rootp A pointer to a pointer to the root node of the tree; note that\n *              the root node can change during insertions, this is required\n *              to keep the tree balanced.\n * @param key  pointer to the element key to insert in the tree\n * @param next Used to allocate and free AVTreeNodes. For insertion the user\n *             must set it to an allocated and zeroed object of at least\n *             av_tree_node_size bytes size. av_tree_insert() will set it to\n *             NULL if it has been consumed.\n *             For deleting elements *next is set to NULL by the user and\n *             av_tree_insert() will set it to the AVTreeNode which was\n *             used for the removed element.\n *             This allows the use of flat arrays, which have\n *             lower overhead compared to many malloced elements.\n *             You might want to define a function like:\n *             @code\n *             void *tree_insert(struct AVTreeNode **rootp, void *key,\n *                               int (*cmp)(void *key, const void *b),\n *                               AVTreeNode **next)\n *             {\n *                 if (!*next)\n *                     *next = av_mallocz(av_tree_node_size);\n *                 return av_tree_insert(rootp, key, cmp, next);\n *             }\n *             void *tree_remove(struct AVTreeNode **rootp, void *key,\n *                               int (*cmp)(void *key, const void *b, AVTreeNode **next))\n *             {\n *                 av_freep(next);\n *                 return av_tree_insert(rootp, key, cmp, next);\n *             }\n *             @endcode\n * @param cmp compare function used to compare elements in the tree, API identical\n *            to that of Standard C's qsort\n * @return If no insertion happened, the found element; if an insertion or\n *         removal happened, then either key or NULL will be returned.\n *         Which one it is depends on the tree state and the implementation. You\n *         should make no assumptions that it's one or the other in the code.\n */\nvoid *ijk_av_tree_insert(struct IjkAVTreeNode **rootp, void *key,\n                     int (*cmp)(const void *key, const void *b),\n                     struct IjkAVTreeNode **next);\n\nvoid ijk_av_tree_destroy(struct IjkAVTreeNode *t);\n\n/**\n * Apply enu(opaque, &elem) to all the elements in the tree in a given range.\n *\n * @param cmp a comparison function that returns < 0 for an element below the\n *            range, > 0 for an element above the range and == 0 for an\n *            element inside the range\n *\n * @note The cmp function should use the same ordering used to construct the\n *       tree.\n */\nvoid ijk_av_tree_enumerate(struct IjkAVTreeNode *t, void *opaque,\n                       int (*cmp)(void *opaque, void *elem),\n                       int (*enu)(void *opaque, void *elem));\n\n/**\n * @}\n */\n\n#endif /* IJKAVUTIL_IJKTREE_H */\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavutil/ijkutils.c",
    "content": "\n#include \"ijkutils.h\"\n\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <ctype.h>\n#include <inttypes.h>\n\nvoid ijk_av_freep(void *arg)\n{\n    void *val;\n\n    memcpy(&val, arg, sizeof(val));\n    memcpy(arg, &(void *){ NULL }, sizeof(val));\n    free(val);\n}\n\nint ijk_av_strstart(const char *str, const char *pfx, const char **ptr)\n{\n    while (*pfx && *pfx == *str) {\n        pfx++;\n        str++;\n    }\n    if (!*pfx && ptr)\n        *ptr = str;\n    return !*pfx;\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavutil/ijkutils.h",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * Copyright (c) 2016 Raymond Zheng <raymondzheng1412@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKAVUTIL_IJKUTILS_H\n#define IJKAVUTIL_IJKUTILS_H\n\n#include \"ijktree.h\"\n\n#include <errno.h>\n#include <stddef.h>\n#include <stdint.h>\n\ntypedef struct IjkAVIOInterruptCB {\n    int (*callback)(void*);\n    void *opaque;\n} IjkAVIOInterruptCB;\n\ntypedef struct IjkCacheTreeInfo {\n    struct IjkAVTreeNode *root;\n    int64_t physical_init_pos;\n    int64_t physical_size;\n    int64_t file_size;\n} IjkCacheTreeInfo;\n\n#define FFDIFFSIGN(x,y) (((x)>(y)) - ((x)<(y)))\n\n#define FFMAX(a,b) ((a) > (b) ? (a) : (b))\n#define FFMAX3(a,b,c) FFMAX(FFMAX(a,b),c)\n#define FFMIN(a,b) ((a) > (b) ? (b) : (a))\n#define FFMIN3(a,b,c) FFMIN(FFMIN(a,b),c)\n\n#define MKTAG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((unsigned)(d) << 24))\n\n/* error handling */\n#if EDOM > 0\n#define IJKAVERROR(e) (-(e))   ///< Returns a negative error code from a POSIX error code, to return from library functions.\n#define IJKAVUNERROR(e) (-(e)) ///< Returns a POSIX error code from a library function error return value.\n#else\n/* Some platforms have E* and errno already negated. */\n#define IJKAVERROR(e) (e)\n#define IJKAVUNERROR(e) (e)\n#endif\n\n#define FFERRTAG(a, b, c, d) (-(int)MKTAG(a, b, c, d))\n#define IJKAVERROR_BSF_NOT_FOUND      FFERRTAG(0xF8,'B','S','F') ///< Bitstream filter not found\n#define IJKAVERROR_BUG                FFERRTAG( 'B','U','G','!') ///< Internal bug, also see AVERROR_BUG2\n#define IJKAVERROR_BUFFER_TOO_SMALL   FFERRTAG( 'B','U','F','S') ///< Buffer too small\n#define IJKAVERROR_DECODER_NOT_FOUND  FFERRTAG(0xF8,'D','E','C') ///< Decoder not found\n#define IJKAVERROR_DEMUXER_NOT_FOUND  FFERRTAG(0xF8,'D','E','M') ///< Demuxer not found\n#define IJKAVERROR_ENCODER_NOT_FOUND  FFERRTAG(0xF8,'E','N','C') ///< Encoder not found\n#define IJKAVERROR_EOF                FFERRTAG( 'E','O','F',' ') ///< End of file\n#define IJKAVERROR_EXIT               FFERRTAG( 'E','X','I','T') ///< Immediate exit was requested; the called function should not be restarted\n#define IJKAVERROR_EXTERNAL           FFERRTAG( 'E','X','T',' ') ///< Generic error in an external library\n#define IJKAVERROR_FILTER_NOT_FOUND   FFERRTAG(0xF8,'F','I','L') ///< Filter not found\n#define IJKAVERROR_INVALIDDATA        FFERRTAG( 'I','N','D','A') ///< Invalid data found when processing input\n#define IJKAVERROR_MUXER_NOT_FOUND    FFERRTAG(0xF8,'M','U','X') ///< Muxer not found\n#define IJKAVERROR_OPTION_NOT_FOUND   FFERRTAG(0xF8,'O','P','T') ///< Option not found\n#define IJKAVERROR_PATCHWELCOME       FFERRTAG( 'P','A','W','E') ///< Not yet implemented in FFmpeg, patches welcome\n#define IJKAVERROR_PROTOCOL_NOT_FOUND FFERRTAG(0xF8,'P','R','O') ///< Protocol not found\n#define IJKAVERROR_STREAM_NOT_FOUND   FFERRTAG(0xF8,'S','T','R') ///< Stream not found\n\n/**\n * ORing this as the \"whence\" parameter to a seek function causes it to\n * return the filesize without seeking anywhere. Supporting this is optional.\n * If it is not supported then the seek function will return <0.\n */\n#define IJKAVSEEK_SIZE 0x10000\n\n/**\n * Passing this flag as the \"whence\" parameter to a seek function causes it to\n * seek by any means (like reopening and linear reading) or other normally unreasonable\n * means that can be extremely slow.\n * This may be ignored by the seek code.\n */\n#define IJKAVSEEK_FORCE 0x20000\n\nvoid ijk_av_freep(void *arg);\n\nint ijk_av_strstart(const char *str, const char *pfx, const char **ptr);\n#endif  // IJKAVUTIL_IJKUTILS_H\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkavutil/opt.h",
    "content": "/*\n * opt.h\n *\n * Copyright (c) 2015 Bilibili\n * Copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef FFPLAY__IJKOPT_H\n#define FFPLAY__IJKOPT_H\n\n#include \"libavutil/opt.h\"\n\n#define IJKAV_OPTION_INT(default__, min__, max__) \\\n    .type = AV_OPT_TYPE_INT, \\\n    { .i64 = default__ }, \\\n    .min = min__, \\\n    .max = max__, \\\n    .flags = AV_OPT_FLAG_DECODING_PARAM\n\n#define IJKAV_OPTION_INT64(default__, min__, max__) \\\n    .type = AV_OPT_TYPE_INT64, \\\n    { .i64 = default__ }, \\\n    .min = min__, \\\n    .max = max__, \\\n    .flags = AV_OPT_FLAG_DECODING_PARAM\n\n#define IJKAV_OPTION_CONST(default__) \\\n    .type = AV_OPT_TYPE_CONST, \\\n    { .i64 = default__ }, \\\n    .min = INT_MIN, \\\n    .max = INT_MAX, \\\n    .flags = AV_OPT_FLAG_DECODING_PARAM\n\n#define IJKAV_OPTION_STR(default__) \\\n    .type = AV_OPT_TYPE_STRING, \\\n    { .str = default__ }, \\\n    .min = 0, \\\n    .max = 0, \\\n    .flags = AV_OPT_FLAG_DECODING_PARAM\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkmeta.c",
    "content": "/*\n * ijkmeta.c\n *\n * Copyright (c) 2014 Bilibili\n * Copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijkmeta.h\"\n#include \"ff_ffinc.h\"\n#include \"ijksdl/ijksdl_misc.h\"\n\n#define IJK_META_INIT_CAPACITY 13\n\nstruct IjkMediaMeta {\n    SDL_mutex *mutex;\n\n    AVDictionary *dict;\n\n    size_t children_count;\n    size_t children_capacity;\n    IjkMediaMeta **children;\n};\n\nIjkMediaMeta *ijkmeta_create()\n{\n    IjkMediaMeta *meta = (IjkMediaMeta *)calloc(1, sizeof(IjkMediaMeta));\n    if (!meta)\n        return NULL;\n\n    meta->mutex = SDL_CreateMutex();\n    if (!meta->mutex)\n        goto fail;\n\n    return meta;\nfail:\n    ijkmeta_destroy(meta);\n    return NULL;\n}\n\nvoid ijkmeta_reset(IjkMediaMeta *meta)\n{\n    if (meta && meta->dict)\n        av_dict_free(&meta->dict);\n}\n\nvoid ijkmeta_destroy(IjkMediaMeta *meta)\n{\n    if (!meta)\n        return;\n\n    if (meta->dict) {\n        av_dict_free(&meta->dict);\n    }\n\n    if (meta->children) {\n        for(int i = 0; i < meta->children_count; ++i) {\n            IjkMediaMeta *child = meta->children[i];\n            if (child) {\n                ijkmeta_destroy(child);\n            }\n        }\n        free(meta->children);\n        meta->children = NULL;\n    }\n\n    SDL_DestroyMutexP(&meta->mutex);\n    free(meta);\n}\n\nvoid ijkmeta_destroy_p(IjkMediaMeta **meta)\n{\n    if (!meta)\n        return;\n\n    ijkmeta_destroy(*meta);\n    *meta = NULL;\n}\n\nvoid ijkmeta_lock(IjkMediaMeta *meta)\n{\n    if (!meta || !meta->mutex)\n        return;\n\n    SDL_LockMutex(meta->mutex);\n}\n\nvoid ijkmeta_unlock(IjkMediaMeta *meta)\n{\n    if (!meta || !meta->mutex)\n        return;\n\n    SDL_UnlockMutex(meta->mutex);\n}\n\nvoid ijkmeta_append_child_l(IjkMediaMeta *meta, IjkMediaMeta *child)\n{\n    if (!meta || !child)\n        return;\n\n    if (!meta->children) {\n        meta->children = (IjkMediaMeta **)calloc(IJK_META_INIT_CAPACITY, sizeof(IjkMediaMeta *));\n        if (!meta->children)\n            return;\n        meta->children_count    = 0;\n        meta->children_capacity = IJK_META_INIT_CAPACITY;\n    } else if (meta->children_count >= meta->children_capacity) {\n        size_t new_capacity = meta->children_capacity * 2;\n        IjkMediaMeta **new_children = (IjkMediaMeta **)calloc(new_capacity, sizeof(IjkMediaMeta *));\n        if (!new_children)\n            return;\n\n        memcpy(new_children, meta->children, meta->children_capacity * sizeof(IjkMediaMeta *));\n        free(meta->children);\n        meta->children          = new_children;\n        meta->children_capacity = new_capacity;\n    }\n\n    meta->children[meta->children_count] = child;\n    meta->children_count++;\n}\n\nvoid ijkmeta_set_int64_l(IjkMediaMeta *meta, const char *name, int64_t value)\n{\n    if (!meta)\n        return;\n\n    av_dict_set_int(&meta->dict, name, value, 0);\n}\n\nvoid ijkmeta_set_string_l(IjkMediaMeta *meta, const char *name, const char *value)\n{\n    if (!meta)\n        return;\n\n    av_dict_set(&meta->dict, name, value, 0);\n}\n\nstatic int64_t get_bit_rate(AVCodecParameters *codecpar)\n{\n    int64_t bit_rate;\n    int bits_per_sample;\n\n    switch (codecpar->codec_type) {\n        case AVMEDIA_TYPE_VIDEO:\n        case AVMEDIA_TYPE_DATA:\n        case AVMEDIA_TYPE_SUBTITLE:\n        case AVMEDIA_TYPE_ATTACHMENT:\n            bit_rate = codecpar->bit_rate;\n            break;\n        case AVMEDIA_TYPE_AUDIO:\n            bits_per_sample = av_get_bits_per_sample(codecpar->codec_id);\n            bit_rate = bits_per_sample ? codecpar->sample_rate * codecpar->channels * bits_per_sample : codecpar->bit_rate;\n            break;\n        default:\n            bit_rate = 0;\n            break;\n    }\n    return bit_rate;\n}\n\nvoid ijkmeta_set_avformat_context_l(IjkMediaMeta *meta, AVFormatContext *ic)\n{\n    if (!meta || !ic)\n        return;\n\n    if (ic->iformat && ic->iformat->name)\n        ijkmeta_set_string_l(meta, IJKM_KEY_FORMAT, ic->iformat->name);\n\n    if (ic->duration != AV_NOPTS_VALUE)\n        ijkmeta_set_int64_l(meta, IJKM_KEY_DURATION_US, ic->duration);\n\n    if (ic->start_time != AV_NOPTS_VALUE)\n        ijkmeta_set_int64_l(meta, IJKM_KEY_START_US, ic->start_time);\n\n    if (ic->bit_rate)\n        ijkmeta_set_int64_l(meta, IJKM_KEY_BITRATE, ic->bit_rate);\n\n    IjkMediaMeta *stream_meta = NULL;\n    for (int i = 0; i < ic->nb_streams; i++) {\n        if (!stream_meta)\n            ijkmeta_destroy_p(&stream_meta);\n\n        AVStream *st = ic->streams[i];\n        if (!st || !st->codecpar)\n            continue;\n\n        stream_meta = ijkmeta_create();\n        if (!stream_meta)\n            continue;\n\n        AVCodecParameters *codecpar = st->codecpar;\n        const char *codec_name = avcodec_get_name(codecpar->codec_id);\n        if (codec_name)\n            ijkmeta_set_string_l(stream_meta, IJKM_KEY_CODEC_NAME, codec_name);\n        if (codecpar->profile != FF_PROFILE_UNKNOWN) {\n            const AVCodec *codec = avcodec_find_decoder(codecpar->codec_id);\n            if (codec) {\n                ijkmeta_set_int64_l(stream_meta, IJKM_KEY_CODEC_PROFILE_ID, codecpar->profile);\n                const char *profile = av_get_profile_name(codec, codecpar->profile);\n                if (profile)\n                    ijkmeta_set_string_l(stream_meta, IJKM_KEY_CODEC_PROFILE, profile);\n                if (codec->long_name)\n                    ijkmeta_set_string_l(stream_meta, IJKM_KEY_CODEC_LONG_NAME, codec->long_name);\n                ijkmeta_set_int64_l(stream_meta, IJKM_KEY_CODEC_LEVEL, codecpar->level);\n                if (codecpar->format != AV_PIX_FMT_NONE)\n                    ijkmeta_set_string_l(stream_meta, IJKM_KEY_CODEC_PIXEL_FORMAT, av_get_pix_fmt_name(codecpar->format));\n            }\n        }\n\n        int64_t bitrate = get_bit_rate(codecpar);\n        if (bitrate > 0) {\n            ijkmeta_set_int64_l(stream_meta, IJKM_KEY_BITRATE, bitrate);\n        }\n\n        switch (codecpar->codec_type) {\n            case AVMEDIA_TYPE_VIDEO: {\n                ijkmeta_set_string_l(stream_meta, IJKM_KEY_TYPE, IJKM_VAL_TYPE__VIDEO);\n\n                if (codecpar->width > 0)\n                    ijkmeta_set_int64_l(stream_meta, IJKM_KEY_WIDTH, codecpar->width);\n                if (codecpar->height > 0)\n                    ijkmeta_set_int64_l(stream_meta, IJKM_KEY_HEIGHT, codecpar->height);\n                if (st->sample_aspect_ratio.num > 0 && st->sample_aspect_ratio.den > 0) {\n                    ijkmeta_set_int64_l(stream_meta, IJKM_KEY_SAR_NUM, codecpar->sample_aspect_ratio.num);\n                    ijkmeta_set_int64_l(stream_meta, IJKM_KEY_SAR_DEN, codecpar->sample_aspect_ratio.den);\n                }\n\n                if (st->avg_frame_rate.num > 0 && st->avg_frame_rate.den > 0) {\n                    ijkmeta_set_int64_l(stream_meta, IJKM_KEY_FPS_NUM, st->avg_frame_rate.num);\n                    ijkmeta_set_int64_l(stream_meta, IJKM_KEY_FPS_DEN, st->avg_frame_rate.den);\n                }\n                if (st->r_frame_rate.num > 0 && st->r_frame_rate.den > 0) {\n                    ijkmeta_set_int64_l(stream_meta, IJKM_KEY_TBR_NUM, st->avg_frame_rate.num);\n                    ijkmeta_set_int64_l(stream_meta, IJKM_KEY_TBR_DEN, st->avg_frame_rate.den);\n                }\n                break;\n            }\n            case AVMEDIA_TYPE_AUDIO: {\n                ijkmeta_set_string_l(stream_meta, IJKM_KEY_TYPE, IJKM_VAL_TYPE__AUDIO);\n\n                if (codecpar->sample_rate)\n                    ijkmeta_set_int64_l(stream_meta, IJKM_KEY_SAMPLE_RATE, codecpar->sample_rate);\n                if (codecpar->channel_layout)\n                    ijkmeta_set_int64_l(stream_meta, IJKM_KEY_CHANNEL_LAYOUT, codecpar->channel_layout);\n                break;\n            }\n            case AVMEDIA_TYPE_SUBTITLE: {\n                ijkmeta_set_string_l(stream_meta, IJKM_KEY_TYPE, IJKM_VAL_TYPE__TIMEDTEXT);\n                break;\n            }\n            default: {\n                ijkmeta_set_string_l(stream_meta, IJKM_KEY_TYPE, IJKM_VAL_TYPE__UNKNOWN);\n                break;\n            }\n        }\n\n        AVDictionaryEntry *lang = av_dict_get(st->metadata, \"language\", NULL, 0);\n        if (lang && lang->value)\n            ijkmeta_set_string_l(stream_meta, IJKM_KEY_LANGUAGE, lang->value);\n\n        ijkmeta_append_child_l(meta, stream_meta);\n        stream_meta = NULL;\n    }\n\n    if (!stream_meta)\n        ijkmeta_destroy_p(&stream_meta);\n}\n\nconst char *ijkmeta_get_string_l(IjkMediaMeta *meta, const char *name)\n{\n    if (!meta || !meta->dict || !name)\n        return NULL;\n\n    AVDictionaryEntry *entry = av_dict_get(meta->dict, name, NULL, 0);\n    if (!entry)\n        return NULL;\n\n    return entry->value;\n}\n\nint64_t ijkmeta_get_int64_l(IjkMediaMeta *meta, const char *name, int64_t defaultValue)\n{\n    if (!meta || !meta->dict)\n        return defaultValue;\n\n    AVDictionaryEntry *entry = av_dict_get(meta->dict, name, NULL, 0);\n    if (!entry || !entry->value)\n        return defaultValue;\n\n    return atoll(entry->value);\n}\n\nsize_t ijkmeta_get_children_count_l(IjkMediaMeta *meta)\n{\n    if (!meta || !meta->children)\n        return 0;\n\n    return meta->children_count;\n}\n\nIjkMediaMeta *ijkmeta_get_child_l(IjkMediaMeta *meta, size_t index)\n{\n    if (!meta)\n        return NULL;\n\n    if (index >= meta->children_count)\n        return NULL;\n\n    return meta->children[index];\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkmeta.h",
    "content": "/*\n * ijkmeta.h\n *\n * Copyright (c) 2014 Bilibili\n * Copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKPLAYER__IJKMETA_H\n#define IJKPLAYER__IJKMETA_H\n\n#include <stdint.h>\n#include <stdlib.h>\n\n// media meta\n#define IJKM_KEY_FORMAT         \"format\"\n#define IJKM_KEY_DURATION_US    \"duration_us\"\n#define IJKM_KEY_START_US       \"start_us\"\n#define IJKM_KEY_BITRATE        \"bitrate\"\n#define IJKM_KEY_VIDEO_STREAM   \"video\"\n#define IJKM_KEY_AUDIO_STREAM   \"audio\"\n#define IJKM_KEY_TIMEDTEXT_STREAM \"timedtext\"\n\n// stream meta\n#define IJKM_KEY_TYPE           \"type\"\n#define IJKM_VAL_TYPE__VIDEO    \"video\"\n#define IJKM_VAL_TYPE__AUDIO    \"audio\"\n#define IJKM_VAL_TYPE__TIMEDTEXT \"timedtext\"\n#define IJKM_VAL_TYPE__UNKNOWN  \"unknown\"\n#define IJKM_KEY_LANGUAGE       \"language\"\n\n#define IJKM_KEY_CODEC_NAME         \"codec_name\"\n#define IJKM_KEY_CODEC_PROFILE      \"codec_profile\"\n#define IJKM_KEY_CODEC_LEVEL        \"codec_level\"\n#define IJKM_KEY_CODEC_LONG_NAME    \"codec_long_name\"\n#define IJKM_KEY_CODEC_PIXEL_FORMAT \"codec_pixel_format\"\n#define IJKM_KEY_CODEC_PROFILE_ID   \"codec_profile_id\"\n\n// stream: video\n#define IJKM_KEY_WIDTH          \"width\"\n#define IJKM_KEY_HEIGHT         \"height\"\n#define IJKM_KEY_FPS_NUM        \"fps_num\"\n#define IJKM_KEY_FPS_DEN        \"fps_den\"\n#define IJKM_KEY_TBR_NUM        \"tbr_num\"\n#define IJKM_KEY_TBR_DEN        \"tbr_den\"\n#define IJKM_KEY_SAR_NUM        \"sar_num\"\n#define IJKM_KEY_SAR_DEN        \"sar_den\"\n// stream: audio\n#define IJKM_KEY_SAMPLE_RATE    \"sample_rate\"\n#define IJKM_KEY_CHANNEL_LAYOUT \"channel_layout\"\n\n// reserved for user\n#define IJKM_KEY_STREAMS        \"streams\"\n\nstruct AVFormatContext;\ntypedef struct IjkMediaMeta IjkMediaMeta;\n\nIjkMediaMeta *ijkmeta_create();\nvoid ijkmeta_reset(IjkMediaMeta *meta);\nvoid ijkmeta_destroy(IjkMediaMeta *meta);\nvoid ijkmeta_destroy_p(IjkMediaMeta **meta);\n\nvoid ijkmeta_lock(IjkMediaMeta *meta);\nvoid ijkmeta_unlock(IjkMediaMeta *meta);\n\nvoid ijkmeta_append_child_l(IjkMediaMeta *meta, IjkMediaMeta *child);\nvoid ijkmeta_set_int64_l(IjkMediaMeta *meta, const char *name, int64_t value);\nvoid ijkmeta_set_string_l(IjkMediaMeta *meta, const char *name, const char *value);\nvoid ijkmeta_set_avformat_context_l(IjkMediaMeta *meta, struct AVFormatContext *ic);\n\n// must be freed with free();\nconst char   *ijkmeta_get_string_l(IjkMediaMeta *meta, const char *name);\nint64_t       ijkmeta_get_int64_l(IjkMediaMeta *meta, const char *name, int64_t defaultValue);\nsize_t        ijkmeta_get_children_count_l(IjkMediaMeta *meta);\n// do not free\nIjkMediaMeta *ijkmeta_get_child_l(IjkMediaMeta *meta, size_t index);\n\n#endif//IJKPLAYER__IJKMETA_H\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkplayer.c",
    "content": "/*\n * ijkplayer.c\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijkplayer.h\"\n#include \"ijkplayer_internal.h\"\n#include \"ijkversion.h\"\n\n#define MP_RET_IF_FAILED(ret) \\\n    do { \\\n        int retval = ret; \\\n        if (retval != 0) return (retval); \\\n    } while(0)\n\n#define MPST_RET_IF_EQ_INT(real, expected, errcode) \\\n    do { \\\n        if ((real) == (expected)) return (errcode); \\\n    } while(0)\n\n#define MPST_RET_IF_EQ(real, expected) \\\n    MPST_RET_IF_EQ_INT(real, expected, EIJK_INVALID_STATE)\n\ninline static void ijkmp_destroy(IjkMediaPlayer *mp)\n{\n    if (!mp)\n        return;\n\n    ffp_destroy_p(&mp->ffplayer);\n    if (mp->msg_thread) {\n        SDL_WaitThread(mp->msg_thread, NULL);\n        mp->msg_thread = NULL;\n    }\n\n    pthread_mutex_destroy(&mp->mutex);\n\n    freep((void**)&mp->data_source);\n    memset(mp, 0, sizeof(IjkMediaPlayer));\n    freep((void**)&mp);\n}\n\ninline static void ijkmp_destroy_p(IjkMediaPlayer **pmp)\n{\n    if (!pmp)\n        return;\n\n    ijkmp_destroy(*pmp);\n    *pmp = NULL;\n}\n\nvoid ijkmp_global_init()\n{\n    ffp_global_init();\n}\n\nvoid ijkmp_global_uninit()\n{\n    ffp_global_uninit();\n}\n\nvoid ijkmp_global_set_log_report(int use_report)\n{\n    ffp_global_set_log_report(use_report);\n}\n\nvoid ijkmp_global_set_log_level(int log_level)\n{\n    ffp_global_set_log_level(log_level);\n}\n\nvoid ijkmp_global_set_inject_callback(ijk_inject_callback cb)\n{\n    ffp_global_set_inject_callback(cb);\n}\n\nconst char *ijkmp_version()\n{\n    return IJKPLAYER_VERSION;\n}\n\nvoid ijkmp_io_stat_register(void (*cb)(const char *url, int type, int bytes))\n{\n    ffp_io_stat_register(cb);\n}\n\nvoid ijkmp_io_stat_complete_register(void (*cb)(const char *url,\n                                                int64_t read_bytes, int64_t total_size,\n                                                int64_t elpased_time, int64_t total_duration))\n{\n    ffp_io_stat_complete_register(cb);\n}\n\nvoid ijkmp_change_state_l(IjkMediaPlayer *mp, int new_state)\n{\n    mp->mp_state = new_state;\n    ffp_notify_msg1(mp->ffplayer, FFP_MSG_PLAYBACK_STATE_CHANGED);\n}\n\nIjkMediaPlayer *ijkmp_create(int (*msg_loop)(void*))\n{\n    IjkMediaPlayer *mp = (IjkMediaPlayer *) mallocz(sizeof(IjkMediaPlayer));\n    if (!mp)\n        goto fail;\n\n    mp->ffplayer = ffp_create();\n    if (!mp->ffplayer)\n        goto fail;\n\n    mp->msg_loop = msg_loop;\n\n    ijkmp_inc_ref(mp);\n    pthread_mutex_init(&mp->mutex, NULL);\n\n    return mp;\n\n    fail:\n    ijkmp_destroy_p(&mp);\n    return NULL;\n}\n\nvoid *ijkmp_set_inject_opaque(IjkMediaPlayer *mp, void *opaque)\n{\n    assert(mp);\n\n    MPTRACE(\"%s(%p)\\n\", __func__, opaque);\n    void *prev_weak_thiz = ffp_set_inject_opaque(mp->ffplayer, opaque);\n    MPTRACE(\"%s()=void\\n\", __func__);\n    return prev_weak_thiz;\n}\n\nvoid ijkmp_set_frame_at_time(IjkMediaPlayer *mp, const char *path, int64_t start_time, int64_t end_time, int num, int definition)\n{\n    assert(mp);\n\n    MPTRACE(\"%s(%s,%lld,%lld,%d,%d)\\n\", __func__, path, start_time, end_time, num, definition);\n    ffp_set_frame_at_time(mp->ffplayer, path, start_time, end_time, num, definition);\n    MPTRACE(\"%s()=void\\n\", __func__);\n}\n\n\nvoid *ijkmp_set_ijkio_inject_opaque(IjkMediaPlayer *mp, void *opaque)\n{\n    assert(mp);\n\n    MPTRACE(\"%s(%p)\\n\", __func__, opaque);\n    void *prev_weak_thiz = ffp_set_ijkio_inject_opaque(mp->ffplayer, opaque);\n    MPTRACE(\"%s()=void\\n\", __func__);\n    return prev_weak_thiz;\n}\n\nvoid ijkmp_set_option(IjkMediaPlayer *mp, int opt_category, const char *name, const char *value)\n{\n    assert(mp);\n\n    // MPTRACE(\"%s(%s, %s)\\n\", __func__, name, value);\n    pthread_mutex_lock(&mp->mutex);\n    ffp_set_option(mp->ffplayer, opt_category, name, value);\n    pthread_mutex_unlock(&mp->mutex);\n    // MPTRACE(\"%s()=void\\n\", __func__);\n}\n\nvoid ijkmp_set_option_int(IjkMediaPlayer *mp, int opt_category, const char *name, int64_t value)\n{\n    assert(mp);\n\n    // MPTRACE(\"%s(%s, %\"PRId64\")\\n\", __func__, name, value);\n    pthread_mutex_lock(&mp->mutex);\n    ffp_set_option_int(mp->ffplayer, opt_category, name, value);\n    pthread_mutex_unlock(&mp->mutex);\n    // MPTRACE(\"%s()=void\\n\", __func__);\n}\n\nint ijkmp_get_video_codec_info(IjkMediaPlayer *mp, char **codec_info)\n{\n    assert(mp);\n\n    MPTRACE(\"%s\\n\", __func__);\n    pthread_mutex_lock(&mp->mutex);\n    int ret = ffp_get_video_codec_info(mp->ffplayer, codec_info);\n    pthread_mutex_unlock(&mp->mutex);\n    MPTRACE(\"%s()=void\\n\", __func__);\n    return ret;\n}\n\nint ijkmp_get_audio_codec_info(IjkMediaPlayer *mp, char **codec_info)\n{\n    assert(mp);\n\n    MPTRACE(\"%s\\n\", __func__);\n    pthread_mutex_lock(&mp->mutex);\n    int ret = ffp_get_audio_codec_info(mp->ffplayer, codec_info);\n    pthread_mutex_unlock(&mp->mutex);\n    MPTRACE(\"%s()=void\\n\", __func__);\n    return ret;\n}\n\nvoid ijkmp_set_playback_rate(IjkMediaPlayer *mp, float rate)\n{\n    assert(mp);\n\n    MPTRACE(\"%s(%f)\\n\", __func__, rate);\n    pthread_mutex_lock(&mp->mutex);\n    ffp_set_playback_rate(mp->ffplayer, rate);\n    pthread_mutex_unlock(&mp->mutex);\n    MPTRACE(\"%s()=void\\n\", __func__);\n}\n\nvoid ijkmp_set_playback_volume(IjkMediaPlayer *mp, float volume)\n{\n    assert(mp);\n\n    MPTRACE(\"%s(%f)\\n\", __func__, volume);\n    pthread_mutex_lock(&mp->mutex);\n    ffp_set_playback_volume(mp->ffplayer, volume);\n    pthread_mutex_unlock(&mp->mutex);\n    MPTRACE(\"%s()=void\\n\", __func__);\n}\n\nint ijkmp_set_stream_selected(IjkMediaPlayer *mp, int stream, int selected)\n{\n    assert(mp);\n\n    MPTRACE(\"%s(%d, %d)\\n\", __func__, stream, selected);\n    pthread_mutex_lock(&mp->mutex);\n    int ret = ffp_set_stream_selected(mp->ffplayer, stream, selected);\n    pthread_mutex_unlock(&mp->mutex);\n    MPTRACE(\"%s(%d, %d)=%d\\n\", __func__, stream, selected, ret);\n    return ret;\n}\n\nfloat ijkmp_get_property_float(IjkMediaPlayer *mp, int id, float default_value)\n{\n    assert(mp);\n\n    pthread_mutex_lock(&mp->mutex);\n    float ret = ffp_get_property_float(mp->ffplayer, id, default_value);\n    pthread_mutex_unlock(&mp->mutex);\n    return ret;\n}\n\nvoid ijkmp_set_property_float(IjkMediaPlayer *mp, int id, float value)\n{\n    assert(mp);\n\n    pthread_mutex_lock(&mp->mutex);\n    ffp_set_property_float(mp->ffplayer, id, value);\n    pthread_mutex_unlock(&mp->mutex);\n}\n\nint64_t ijkmp_get_property_int64(IjkMediaPlayer *mp, int id, int64_t default_value)\n{\n    assert(mp);\n\n    pthread_mutex_lock(&mp->mutex);\n    int64_t ret = ffp_get_property_int64(mp->ffplayer, id, default_value);\n    pthread_mutex_unlock(&mp->mutex);\n    return ret;\n}\n\nvoid ijkmp_set_property_int64(IjkMediaPlayer *mp, int id, int64_t value)\n{\n    assert(mp);\n\n    pthread_mutex_lock(&mp->mutex);\n    ffp_set_property_int64(mp->ffplayer, id, value);\n    pthread_mutex_unlock(&mp->mutex);\n}\n\nIjkMediaMeta *ijkmp_get_meta_l(IjkMediaPlayer *mp)\n{\n    assert(mp);\n\n    MPTRACE(\"%s\\n\", __func__);\n    IjkMediaMeta *ret = ffp_get_meta_l(mp->ffplayer);\n    MPTRACE(\"%s()=void\\n\", __func__);\n    return ret;\n}\n\nvoid ijkmp_shutdown_l(IjkMediaPlayer *mp)\n{\n    assert(mp);\n\n    MPTRACE(\"ijkmp_shutdown_l()\\n\");\n    if (mp->ffplayer) {\n        ffp_stop_l(mp->ffplayer);\n        ffp_wait_stop_l(mp->ffplayer);\n    }\n    MPTRACE(\"ijkmp_shutdown_l()=void\\n\");\n}\n\nvoid ijkmp_shutdown(IjkMediaPlayer *mp)\n{\n    return ijkmp_shutdown_l(mp);\n}\n\nvoid ijkmp_inc_ref(IjkMediaPlayer *mp)\n{\n    assert(mp);\n    __sync_fetch_and_add(&mp->ref_count, 1);\n}\n\nvoid ijkmp_dec_ref(IjkMediaPlayer *mp)\n{\n    if (!mp)\n        return;\n\n    int ref_count = __sync_sub_and_fetch(&mp->ref_count, 1);\n    if (ref_count == 0) {\n        MPTRACE(\"ijkmp_dec_ref(): ref=0\\n\");\n        ijkmp_shutdown(mp);\n        ijkmp_destroy_p(&mp);\n    }\n}\n\nvoid ijkmp_dec_ref_p(IjkMediaPlayer **pmp)\n{\n    if (!pmp)\n        return;\n\n    ijkmp_dec_ref(*pmp);\n    *pmp = NULL;\n}\n\nstatic int ijkmp_set_data_source_l(IjkMediaPlayer *mp, const char *url)\n{\n    assert(mp);\n    assert(url);\n\n    // MPST_RET_IF_EQ(mp->mp_state, MP_STATE_IDLE);\n    MPST_RET_IF_EQ(mp->mp_state, MP_STATE_INITIALIZED);\n    MPST_RET_IF_EQ(mp->mp_state, MP_STATE_ASYNC_PREPARING);\n    MPST_RET_IF_EQ(mp->mp_state, MP_STATE_PREPARED);\n    MPST_RET_IF_EQ(mp->mp_state, MP_STATE_STARTED);\n    MPST_RET_IF_EQ(mp->mp_state, MP_STATE_PAUSED);\n    MPST_RET_IF_EQ(mp->mp_state, MP_STATE_COMPLETED);\n    MPST_RET_IF_EQ(mp->mp_state, MP_STATE_STOPPED);\n    MPST_RET_IF_EQ(mp->mp_state, MP_STATE_ERROR);\n    MPST_RET_IF_EQ(mp->mp_state, MP_STATE_END);\n\n    freep((void**)&mp->data_source);\n    mp->data_source = strdup(url);\n    if (!mp->data_source)\n        return EIJK_OUT_OF_MEMORY;\n\n    ijkmp_change_state_l(mp, MP_STATE_INITIALIZED);\n    return 0;\n}\n\nint ijkmp_set_data_source(IjkMediaPlayer *mp, const char *url)\n{\n    assert(mp);\n    assert(url);\n    MPTRACE(\"ijkmp_set_data_source(url=\\\"%s\\\")\\n\", url);\n    pthread_mutex_lock(&mp->mutex);\n    int retval = ijkmp_set_data_source_l(mp, url);\n    pthread_mutex_unlock(&mp->mutex);\n    MPTRACE(\"ijkmp_set_data_source(url=\\\"%s\\\")=%d\\n\", url, retval);\n    return retval;\n}\n\nstatic int ijkmp_msg_loop(void *arg)\n{\n    IjkMediaPlayer *mp = arg;\n    int ret = mp->msg_loop(arg);\n    return ret;\n}\n\nstatic int ijkmp_prepare_async_l(IjkMediaPlayer *mp)\n{\n    assert(mp);\n\n    MPST_RET_IF_EQ(mp->mp_state, MP_STATE_IDLE);\n    // MPST_RET_IF_EQ(mp->mp_state, MP_STATE_INITIALIZED);\n    MPST_RET_IF_EQ(mp->mp_state, MP_STATE_ASYNC_PREPARING);\n    MPST_RET_IF_EQ(mp->mp_state, MP_STATE_PREPARED);\n    MPST_RET_IF_EQ(mp->mp_state, MP_STATE_STARTED);\n    MPST_RET_IF_EQ(mp->mp_state, MP_STATE_PAUSED);\n    MPST_RET_IF_EQ(mp->mp_state, MP_STATE_COMPLETED);\n    // MPST_RET_IF_EQ(mp->mp_state, MP_STATE_STOPPED);\n    MPST_RET_IF_EQ(mp->mp_state, MP_STATE_ERROR);\n    MPST_RET_IF_EQ(mp->mp_state, MP_STATE_END);\n\n    assert(mp->data_source);\n\n    ijkmp_change_state_l(mp, MP_STATE_ASYNC_PREPARING);\n\n    msg_queue_start(&mp->ffplayer->msg_queue);\n\n    // released in msg_loop\n    ijkmp_inc_ref(mp);\n    mp->msg_thread = SDL_CreateThreadEx(&mp->_msg_thread, ijkmp_msg_loop, mp, \"ff_msg_loop\");\n    // msg_thread is detached inside msg_loop\n    // TODO: 9 release weak_thiz if pthread_create() failed;\n\n    int retval = ffp_prepare_async_l(mp->ffplayer, mp->data_source);\n    if (retval < 0) {\n        ijkmp_change_state_l(mp, MP_STATE_ERROR);\n        return retval;\n    }\n\n    return 0;\n}\n\nint ijkmp_prepare_async(IjkMediaPlayer *mp)\n{\n    assert(mp);\n    MPTRACE(\"ijkmp_prepare_async()\\n\");\n    pthread_mutex_lock(&mp->mutex);\n    int retval = ijkmp_prepare_async_l(mp);\n    pthread_mutex_unlock(&mp->mutex);\n    MPTRACE(\"ijkmp_prepare_async()=%d\\n\", retval);\n    return retval;\n}\n\nstatic int ikjmp_chkst_start_l(int mp_state)\n{\n    MPST_RET_IF_EQ(mp_state, MP_STATE_IDLE);\n    MPST_RET_IF_EQ(mp_state, MP_STATE_INITIALIZED);\n    MPST_RET_IF_EQ(mp_state, MP_STATE_ASYNC_PREPARING);\n    // MPST_RET_IF_EQ(mp_state, MP_STATE_PREPARED);\n    // MPST_RET_IF_EQ(mp_state, MP_STATE_STARTED);\n    // MPST_RET_IF_EQ(mp_state, MP_STATE_PAUSED);\n    // MPST_RET_IF_EQ(mp_state, MP_STATE_COMPLETED);\n    MPST_RET_IF_EQ(mp_state, MP_STATE_STOPPED);\n    MPST_RET_IF_EQ(mp_state, MP_STATE_ERROR);\n    MPST_RET_IF_EQ(mp_state, MP_STATE_END);\n\n    return 0;\n}\n\nstatic int ijkmp_start_l(IjkMediaPlayer *mp)\n{\n    assert(mp);\n\n    MP_RET_IF_FAILED(ikjmp_chkst_start_l(mp->mp_state));\n\n    ffp_remove_msg(mp->ffplayer, FFP_REQ_START);\n    ffp_remove_msg(mp->ffplayer, FFP_REQ_PAUSE);\n    ffp_notify_msg1(mp->ffplayer, FFP_REQ_START);\n\n    return 0;\n}\n\nint ijkmp_start(IjkMediaPlayer *mp)\n{\n    assert(mp);\n    MPTRACE(\"ijkmp_start()\\n\");\n    pthread_mutex_lock(&mp->mutex);\n    int retval = ijkmp_start_l(mp);\n    pthread_mutex_unlock(&mp->mutex);\n    MPTRACE(\"ijkmp_start()=%d\\n\", retval);\n    return retval;\n}\n\nstatic int ikjmp_chkst_pause_l(int mp_state)\n{\n    MPST_RET_IF_EQ(mp_state, MP_STATE_IDLE);\n    MPST_RET_IF_EQ(mp_state, MP_STATE_INITIALIZED);\n    MPST_RET_IF_EQ(mp_state, MP_STATE_ASYNC_PREPARING);\n    // MPST_RET_IF_EQ(mp_state, MP_STATE_PREPARED);\n    // MPST_RET_IF_EQ(mp_state, MP_STATE_STARTED);\n    // MPST_RET_IF_EQ(mp_state, MP_STATE_PAUSED);\n    // MPST_RET_IF_EQ(mp_state, MP_STATE_COMPLETED);\n    MPST_RET_IF_EQ(mp_state, MP_STATE_STOPPED);\n    MPST_RET_IF_EQ(mp_state, MP_STATE_ERROR);\n    MPST_RET_IF_EQ(mp_state, MP_STATE_END);\n\n    return 0;\n}\n\nstatic int ijkmp_pause_l(IjkMediaPlayer *mp)\n{\n    assert(mp);\n\n    MP_RET_IF_FAILED(ikjmp_chkst_pause_l(mp->mp_state));\n\n    ffp_remove_msg(mp->ffplayer, FFP_REQ_START);\n    ffp_remove_msg(mp->ffplayer, FFP_REQ_PAUSE);\n    ffp_notify_msg1(mp->ffplayer, FFP_REQ_PAUSE);\n\n    return 0;\n}\n\nint ijkmp_pause(IjkMediaPlayer *mp)\n{\n    assert(mp);\n    MPTRACE(\"ijkmp_pause()\\n\");\n    pthread_mutex_lock(&mp->mutex);\n    int retval = ijkmp_pause_l(mp);\n    pthread_mutex_unlock(&mp->mutex);\n    MPTRACE(\"ijkmp_pause()=%d\\n\", retval);\n    return retval;\n}\n\nstatic int ijkmp_stop_l(IjkMediaPlayer *mp)\n{\n    assert(mp);\n\n    MPST_RET_IF_EQ(mp->mp_state, MP_STATE_IDLE);\n    MPST_RET_IF_EQ(mp->mp_state, MP_STATE_INITIALIZED);\n    // MPST_RET_IF_EQ(mp->mp_state, MP_STATE_ASYNC_PREPARING);\n    // MPST_RET_IF_EQ(mp->mp_state, MP_STATE_PREPARED);\n    // MPST_RET_IF_EQ(mp->mp_state, MP_STATE_STARTED);\n    // MPST_RET_IF_EQ(mp->mp_state, MP_STATE_PAUSED);\n    // MPST_RET_IF_EQ(mp->mp_state, MP_STATE_COMPLETED);\n    // MPST_RET_IF_EQ(mp->mp_state, MP_STATE_STOPPED);\n    MPST_RET_IF_EQ(mp->mp_state, MP_STATE_ERROR);\n    MPST_RET_IF_EQ(mp->mp_state, MP_STATE_END);\n\n    ffp_remove_msg(mp->ffplayer, FFP_REQ_START);\n    ffp_remove_msg(mp->ffplayer, FFP_REQ_PAUSE);\n    int retval = ffp_stop_l(mp->ffplayer);\n    if (retval < 0) {\n        return retval;\n    }\n\n    ijkmp_change_state_l(mp, MP_STATE_STOPPED);\n    return 0;\n}\n\nint ijkmp_stop(IjkMediaPlayer *mp)\n{\n    assert(mp);\n    MPTRACE(\"ijkmp_stop()\\n\");\n    pthread_mutex_lock(&mp->mutex);\n    int retval = ijkmp_stop_l(mp);\n    pthread_mutex_unlock(&mp->mutex);\n    MPTRACE(\"ijkmp_stop()=%d\\n\", retval);\n    return retval;\n}\n\nbool ijkmp_is_playing(IjkMediaPlayer *mp)\n{\n    assert(mp);\n    if (mp->mp_state == MP_STATE_PREPARED ||\n        mp->mp_state == MP_STATE_STARTED) {\n        return true;\n    }\n\n    return false;\n}\n\nstatic int ikjmp_chkst_seek_l(int mp_state)\n{\n    MPST_RET_IF_EQ(mp_state, MP_STATE_IDLE);\n    MPST_RET_IF_EQ(mp_state, MP_STATE_INITIALIZED);\n    MPST_RET_IF_EQ(mp_state, MP_STATE_ASYNC_PREPARING);\n    // MPST_RET_IF_EQ(mp_state, MP_STATE_PREPARED);\n    // MPST_RET_IF_EQ(mp_state, MP_STATE_STARTED);\n    // MPST_RET_IF_EQ(mp_state, MP_STATE_PAUSED);\n    // MPST_RET_IF_EQ(mp_state, MP_STATE_COMPLETED);\n    MPST_RET_IF_EQ(mp_state, MP_STATE_STOPPED);\n    MPST_RET_IF_EQ(mp_state, MP_STATE_ERROR);\n    MPST_RET_IF_EQ(mp_state, MP_STATE_END);\n\n    return 0;\n}\n\nint ijkmp_seek_to_l(IjkMediaPlayer *mp, long msec)\n{\n    assert(mp);\n\n    MP_RET_IF_FAILED(ikjmp_chkst_seek_l(mp->mp_state));\n\n    mp->seek_req = 1;\n    mp->seek_msec = msec;\n    ffp_remove_msg(mp->ffplayer, FFP_REQ_SEEK);\n    ffp_notify_msg2(mp->ffplayer, FFP_REQ_SEEK, (int)msec);\n    // TODO: 9 64-bit long?\n\n    return 0;\n}\n\nint ijkmp_seek_to(IjkMediaPlayer *mp, long msec)\n{\n    assert(mp);\n    MPTRACE(\"ijkmp_seek_to(%ld)\\n\", msec);\n    pthread_mutex_lock(&mp->mutex);\n    int retval = ijkmp_seek_to_l(mp, msec);\n    pthread_mutex_unlock(&mp->mutex);\n    MPTRACE(\"ijkmp_seek_to(%ld)=%d\\n\", msec, retval);\n\n    return retval;\n}\n\nint ijkmp_get_state(IjkMediaPlayer *mp)\n{\n    return mp->mp_state;\n}\n\nstatic long ijkmp_get_current_position_l(IjkMediaPlayer *mp)\n{\n    if (mp->seek_req)\n        return mp->seek_msec;\n    return ffp_get_current_position_l(mp->ffplayer);\n}\n\nlong ijkmp_get_current_position(IjkMediaPlayer *mp)\n{\n    assert(mp);\n    pthread_mutex_lock(&mp->mutex);\n    long retval;\n    if (mp->seek_req)\n        retval = mp->seek_msec;\n    else\n        retval = ijkmp_get_current_position_l(mp);\n    pthread_mutex_unlock(&mp->mutex);\n    return retval;\n}\n\nstatic long ijkmp_get_duration_l(IjkMediaPlayer *mp)\n{\n    return ffp_get_duration_l(mp->ffplayer);\n}\n\nlong ijkmp_get_duration(IjkMediaPlayer *mp)\n{\n    assert(mp);\n    pthread_mutex_lock(&mp->mutex);\n    long retval = ijkmp_get_duration_l(mp);\n    pthread_mutex_unlock(&mp->mutex);\n    return retval;\n}\n\nstatic long ijkmp_get_playable_duration_l(IjkMediaPlayer *mp)\n{\n    return ffp_get_playable_duration_l(mp->ffplayer);\n}\n\nlong ijkmp_get_playable_duration(IjkMediaPlayer *mp)\n{\n    assert(mp);\n    pthread_mutex_lock(&mp->mutex);\n    long retval = ijkmp_get_playable_duration_l(mp);\n    pthread_mutex_unlock(&mp->mutex);\n    return retval;\n}\n\nvoid ijkmp_set_loop(IjkMediaPlayer *mp, int loop)\n{\n    assert(mp);\n    pthread_mutex_lock(&mp->mutex);\n    ffp_set_loop(mp->ffplayer, loop);\n    pthread_mutex_unlock(&mp->mutex);\n}\n\nint ijkmp_get_loop(IjkMediaPlayer *mp)\n{\n    assert(mp);\n    pthread_mutex_lock(&mp->mutex);\n    int loop = ffp_get_loop(mp->ffplayer);\n    pthread_mutex_unlock(&mp->mutex);\n    return loop;\n}\n\nvoid *ijkmp_get_weak_thiz(IjkMediaPlayer *mp)\n{\n    return mp->weak_thiz;\n}\n\nvoid *ijkmp_set_weak_thiz(IjkMediaPlayer *mp, void *weak_thiz)\n{\n    void *prev_weak_thiz = mp->weak_thiz;\n\n    mp->weak_thiz = weak_thiz;\n\n    return prev_weak_thiz;\n}\n\n/* need to call msg_free_res for freeing the resouce obtained in msg */\nint ijkmp_get_msg(IjkMediaPlayer *mp, AVMessage *msg, int block)\n{\n    assert(mp);\n    while (1) {\n        int continue_wait_next_msg = 0;\n        int retval = msg_queue_get(&mp->ffplayer->msg_queue, msg, block);\n        if (retval <= 0)\n            return retval;\n\n        switch (msg->what) {\n        case FFP_MSG_PREPARED:\n            MPTRACE(\"ijkmp_get_msg: FFP_MSG_PREPARED\\n\");\n            pthread_mutex_lock(&mp->mutex);\n            if (mp->mp_state == MP_STATE_ASYNC_PREPARING) {\n                ijkmp_change_state_l(mp, MP_STATE_PREPARED);\n            } else {\n                // FIXME: 1: onError() ?\n                av_log(mp->ffplayer, AV_LOG_DEBUG, \"FFP_MSG_PREPARED: expecting mp_state==MP_STATE_ASYNC_PREPARING\\n\");\n            }\n            if (!mp->ffplayer->start_on_prepared) {\n                ijkmp_change_state_l(mp, MP_STATE_PAUSED);\n            }\n            pthread_mutex_unlock(&mp->mutex);\n            break;\n\n        case FFP_MSG_COMPLETED:\n            MPTRACE(\"ijkmp_get_msg: FFP_MSG_COMPLETED\\n\");\n\n            pthread_mutex_lock(&mp->mutex);\n            mp->restart = 1;\n            mp->restart_from_beginning = 1;\n            ijkmp_change_state_l(mp, MP_STATE_COMPLETED);\n            pthread_mutex_unlock(&mp->mutex);\n            break;\n\n        case FFP_MSG_SEEK_COMPLETE:\n            MPTRACE(\"ijkmp_get_msg: FFP_MSG_SEEK_COMPLETE\\n\");\n\n            pthread_mutex_lock(&mp->mutex);\n            mp->seek_req = 0;\n            mp->seek_msec = 0;\n            pthread_mutex_unlock(&mp->mutex);\n            break;\n\n        case FFP_REQ_START:\n            MPTRACE(\"ijkmp_get_msg: FFP_REQ_START\\n\");\n            continue_wait_next_msg = 1;\n            pthread_mutex_lock(&mp->mutex);\n            if (0 == ikjmp_chkst_start_l(mp->mp_state)) {\n                // FIXME: 8 check seekable\n                if (mp->restart) {\n                    if (mp->restart_from_beginning) {\n                        av_log(mp->ffplayer, AV_LOG_DEBUG, \"ijkmp_get_msg: FFP_REQ_START: restart from beginning\\n\");\n                        retval = ffp_start_from_l(mp->ffplayer, 0);\n                        if (retval == 0)\n                            ijkmp_change_state_l(mp, MP_STATE_STARTED);\n                    } else {\n                        av_log(mp->ffplayer, AV_LOG_DEBUG, \"ijkmp_get_msg: FFP_REQ_START: restart from seek pos\\n\");\n                        retval = ffp_start_l(mp->ffplayer);\n                        if (retval == 0)\n                            ijkmp_change_state_l(mp, MP_STATE_STARTED);\n                    }\n                    mp->restart = 0;\n                    mp->restart_from_beginning = 0;\n                } else {\n                    av_log(mp->ffplayer, AV_LOG_DEBUG, \"ijkmp_get_msg: FFP_REQ_START: start on fly\\n\");\n                    retval = ffp_start_l(mp->ffplayer);\n                    if (retval == 0)\n                        ijkmp_change_state_l(mp, MP_STATE_STARTED);\n                }\n            }\n            pthread_mutex_unlock(&mp->mutex);\n            break;\n\n        case FFP_REQ_PAUSE:\n            MPTRACE(\"ijkmp_get_msg: FFP_REQ_PAUSE\\n\");\n            continue_wait_next_msg = 1;\n            pthread_mutex_lock(&mp->mutex);\n            if (0 == ikjmp_chkst_pause_l(mp->mp_state)) {\n                int pause_ret = ffp_pause_l(mp->ffplayer);\n                if (pause_ret == 0)\n                    ijkmp_change_state_l(mp, MP_STATE_PAUSED);\n            }\n            pthread_mutex_unlock(&mp->mutex);\n            break;\n\n        case FFP_REQ_SEEK:\n            MPTRACE(\"ijkmp_get_msg: FFP_REQ_SEEK\\n\");\n            continue_wait_next_msg = 1;\n\n            pthread_mutex_lock(&mp->mutex);\n            if (0 == ikjmp_chkst_seek_l(mp->mp_state)) {\n                mp->restart_from_beginning = 0;\n                if (0 == ffp_seek_to_l(mp->ffplayer, msg->arg1)) {\n                    av_log(mp->ffplayer, AV_LOG_DEBUG, \"ijkmp_get_msg: FFP_REQ_SEEK: seek to %d\\n\", (int)msg->arg1);\n                }\n            }\n            pthread_mutex_unlock(&mp->mutex);\n            break;\n        }\n        if (continue_wait_next_msg) {\n            msg_free_res(msg);\n            continue;\n        }\n\n        return retval;\n    }\n\n    return -1;\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkplayer.h",
    "content": "/*\n * ijkplayer.h\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKPLAYER_ANDROID__IJKPLAYER_H\n#define IJKPLAYER_ANDROID__IJKPLAYER_H\n\n#include <stdbool.h>\n#include \"ff_ffmsg_queue.h\"\n\n#include \"ijkmeta.h\"\n\n#ifndef MPTRACE\n#define MPTRACE ALOGD\n#endif\n\ntypedef struct IjkMediaPlayer IjkMediaPlayer;\nstruct FFPlayer;\nstruct SDL_Vout;\n\n/*-\n MPST_CHECK_NOT_RET(mp->mp_state, MP_STATE_IDLE);\n MPST_CHECK_NOT_RET(mp->mp_state, MP_STATE_INITIALIZED);\n MPST_CHECK_NOT_RET(mp->mp_state, MP_STATE_ASYNC_PREPARING);\n MPST_CHECK_NOT_RET(mp->mp_state, MP_STATE_PREPARED);\n MPST_CHECK_NOT_RET(mp->mp_state, MP_STATE_STARTED);\n MPST_CHECK_NOT_RET(mp->mp_state, MP_STATE_PAUSED);\n MPST_CHECK_NOT_RET(mp->mp_state, MP_STATE_COMPLETED);\n MPST_CHECK_NOT_RET(mp->mp_state, MP_STATE_STOPPED);\n MPST_CHECK_NOT_RET(mp->mp_state, MP_STATE_ERROR);\n MPST_CHECK_NOT_RET(mp->mp_state, MP_STATE_END);\n */\n\n/*-\n * ijkmp_set_data_source()  -> MP_STATE_INITIALIZED\n *\n * ijkmp_reset              -> self\n * ijkmp_release            -> MP_STATE_END\n */\n#define MP_STATE_IDLE               0\n\n/*-\n * ijkmp_prepare_async()    -> MP_STATE_ASYNC_PREPARING\n *\n * ijkmp_reset              -> MP_STATE_IDLE\n * ijkmp_release            -> MP_STATE_END\n */\n#define MP_STATE_INITIALIZED        1\n\n/*-\n *                   ...    -> MP_STATE_PREPARED\n *                   ...    -> MP_STATE_ERROR\n *\n * ijkmp_reset              -> MP_STATE_IDLE\n * ijkmp_release            -> MP_STATE_END\n */\n#define MP_STATE_ASYNC_PREPARING    2\n\n/*-\n * ijkmp_seek_to()          -> self\n * ijkmp_start()            -> MP_STATE_STARTED\n *\n * ijkmp_reset              -> MP_STATE_IDLE\n * ijkmp_release            -> MP_STATE_END\n */\n#define MP_STATE_PREPARED           3\n\n/*-\n * ijkmp_seek_to()          -> self\n * ijkmp_start()            -> self\n * ijkmp_pause()            -> MP_STATE_PAUSED\n * ijkmp_stop()             -> MP_STATE_STOPPED\n *                   ...    -> MP_STATE_COMPLETED\n *                   ...    -> MP_STATE_ERROR\n *\n * ijkmp_reset              -> MP_STATE_IDLE\n * ijkmp_release            -> MP_STATE_END\n */\n#define MP_STATE_STARTED            4\n\n/*-\n * ijkmp_seek_to()          -> self\n * ijkmp_start()            -> MP_STATE_STARTED\n * ijkmp_pause()            -> self\n * ijkmp_stop()             -> MP_STATE_STOPPED\n *\n * ijkmp_reset              -> MP_STATE_IDLE\n * ijkmp_release            -> MP_STATE_END\n */\n#define MP_STATE_PAUSED             5\n\n/*-\n * ijkmp_seek_to()          -> self\n * ijkmp_start()            -> MP_STATE_STARTED (from beginning)\n * ijkmp_pause()            -> self\n * ijkmp_stop()             -> MP_STATE_STOPPED\n *\n * ijkmp_reset              -> MP_STATE_IDLE\n * ijkmp_release            -> MP_STATE_END\n */\n#define MP_STATE_COMPLETED          6\n\n/*-\n * ijkmp_stop()             -> self\n * ijkmp_prepare_async()    -> MP_STATE_ASYNC_PREPARING\n *\n * ijkmp_reset              -> MP_STATE_IDLE\n * ijkmp_release            -> MP_STATE_END\n */\n#define MP_STATE_STOPPED            7\n\n/*-\n * ijkmp_reset              -> MP_STATE_IDLE\n * ijkmp_release            -> MP_STATE_END\n */\n#define MP_STATE_ERROR              8\n\n/*-\n * ijkmp_release            -> self\n */\n#define MP_STATE_END                9\n\n\n\n#define IJKMP_IO_STAT_READ 1\n\n\n#define IJKMP_OPT_CATEGORY_FORMAT FFP_OPT_CATEGORY_FORMAT\n#define IJKMP_OPT_CATEGORY_CODEC  FFP_OPT_CATEGORY_CODEC\n#define IJKMP_OPT_CATEGORY_SWS    FFP_OPT_CATEGORY_SWS\n#define IJKMP_OPT_CATEGORY_PLAYER FFP_OPT_CATEGORY_PLAYER\n#define IJKMP_OPT_CATEGORY_SWR    FFP_OPT_CATEGORY_SWR\n\n\nvoid            ijkmp_global_init();\nvoid            ijkmp_global_uninit();\nvoid            ijkmp_global_set_log_report(int use_report);\nvoid            ijkmp_global_set_log_level(int log_level);   // log_level = AV_LOG_xxx\nvoid            ijkmp_global_set_inject_callback(ijk_inject_callback cb);\nconst char     *ijkmp_version();\nvoid            ijkmp_io_stat_register(void (*cb)(const char *url, int type, int bytes));\nvoid            ijkmp_io_stat_complete_register(void (*cb)(const char *url,\n                                                           int64_t read_bytes, int64_t total_size,\n                                                           int64_t elpased_time, int64_t total_duration));\n\n// ref_count is 1 after open\nIjkMediaPlayer *ijkmp_create(int (*msg_loop)(void*));\nvoid*            ijkmp_set_inject_opaque(IjkMediaPlayer *mp, void *opaque);\nvoid*            ijkmp_set_ijkio_inject_opaque(IjkMediaPlayer *mp, void *opaque);\n\nvoid            ijkmp_set_option(IjkMediaPlayer *mp, int opt_category, const char *name, const char *value);\nvoid            ijkmp_set_option_int(IjkMediaPlayer *mp, int opt_category, const char *name, int64_t value);\n\nint             ijkmp_get_video_codec_info(IjkMediaPlayer *mp, char **codec_info);\nint             ijkmp_get_audio_codec_info(IjkMediaPlayer *mp, char **codec_info);\nvoid            ijkmp_set_playback_rate(IjkMediaPlayer *mp, float rate);\nvoid            ijkmp_set_playback_volume(IjkMediaPlayer *mp, float rate);\n\nint             ijkmp_set_stream_selected(IjkMediaPlayer *mp, int stream, int selected);\n\nfloat           ijkmp_get_property_float(IjkMediaPlayer *mp, int id, float default_value);\nvoid            ijkmp_set_property_float(IjkMediaPlayer *mp, int id, float value);\nint64_t         ijkmp_get_property_int64(IjkMediaPlayer *mp, int id, int64_t default_value);\nvoid            ijkmp_set_property_int64(IjkMediaPlayer *mp, int id, int64_t value);\n\n// must be freed with free();\nIjkMediaMeta   *ijkmp_get_meta_l(IjkMediaPlayer *mp);\n\n// preferred to be called explicity, can be called multiple times\n// NOTE: ijkmp_shutdown may block thread\nvoid            ijkmp_shutdown(IjkMediaPlayer *mp);\n\nvoid            ijkmp_inc_ref(IjkMediaPlayer *mp);\n\n// call close at last release, also free memory\n// NOTE: ijkmp_dec_ref may block thread\nvoid            ijkmp_dec_ref(IjkMediaPlayer *mp);\nvoid            ijkmp_dec_ref_p(IjkMediaPlayer **pmp);\n\nint             ijkmp_set_data_source(IjkMediaPlayer *mp, const char *url);\nint             ijkmp_prepare_async(IjkMediaPlayer *mp);\nint             ijkmp_start(IjkMediaPlayer *mp);\nint             ijkmp_pause(IjkMediaPlayer *mp);\nint             ijkmp_stop(IjkMediaPlayer *mp);\nint             ijkmp_seek_to(IjkMediaPlayer *mp, long msec);\nint             ijkmp_get_state(IjkMediaPlayer *mp);\nbool            ijkmp_is_playing(IjkMediaPlayer *mp);\nlong            ijkmp_get_current_position(IjkMediaPlayer *mp);\nlong            ijkmp_get_duration(IjkMediaPlayer *mp);\nlong            ijkmp_get_playable_duration(IjkMediaPlayer *mp);\nvoid            ijkmp_set_loop(IjkMediaPlayer *mp, int loop);\nint             ijkmp_get_loop(IjkMediaPlayer *mp);\n\nvoid           *ijkmp_get_weak_thiz(IjkMediaPlayer *mp);\nvoid           *ijkmp_set_weak_thiz(IjkMediaPlayer *mp, void *weak_thiz);\n\n/* return < 0 if aborted, 0 if no packet and > 0 if packet.  */\n/* need to call msg_free_res for freeing the resouce obtained in msg */\nint             ijkmp_get_msg(IjkMediaPlayer *mp, AVMessage *msg, int block);\nvoid            ijkmp_set_frame_at_time(IjkMediaPlayer *mp, const char *path, int64_t start_time, int64_t end_time, int num, int definition);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/ijkplayer_internal.h",
    "content": "/*\n * ijkplayer_internal.h\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKPLAYER_ANDROID__IJKPLAYER_INTERNAL_H\n#define IJKPLAYER_ANDROID__IJKPLAYER_INTERNAL_H\n\n#include <assert.h>\n#include \"ijksdl/ijksdl.h\"\n#include \"ff_fferror.h\"\n#include \"ff_ffplay.h\"\n#include \"ijkplayer.h\"\n\nstruct IjkMediaPlayer {\n    volatile int ref_count;\n    pthread_mutex_t mutex;\n    FFPlayer *ffplayer;\n\n    int (*msg_loop)(void*);\n    SDL_Thread *msg_thread;\n    SDL_Thread _msg_thread;\n\n    int mp_state;\n    char *data_source;\n    void *weak_thiz;\n\n    int restart;\n    int restart_from_beginning;\n    int seek_req;\n    long seek_msec;\n};\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/pipeline/ffpipeline_ffplay.c",
    "content": "/*\n * ffpipeline_ffplay.c\n *\n * Copyright (c) 2014 Bilibili\n * Copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ffpipeline_ffplay.h\"\n#include \"ffpipenode_ffplay_vdec.h\"\n#include \"../ff_ffplay.h\"\n\nstatic SDL_Class g_pipeline_class = {\n    .name = \"ffpipeline_ffplay\",\n};\n\nstruct IJKFF_Pipeline_Opaque {\n    FFPlayer *ffp;\n};\n\nstatic void func_destroy(IJKFF_Pipeline *pipeline)\n{\n    // do nothing\n}\n\nstatic IJKFF_Pipenode *func_open_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp)\n{\n    return ffpipenode_create_video_decoder_from_ffplay(ffp);\n}\n\nstatic SDL_Aout *func_open_audio_output(IJKFF_Pipeline *pipeline, FFPlayer *ffp)\n{\n    return NULL;\n}\n\nIJKFF_Pipeline *ffpipeline_create_from_ffplay(FFPlayer *ffp)\n{\n    IJKFF_Pipeline *pipeline = ffpipeline_alloc(&g_pipeline_class, sizeof(IJKFF_Pipeline_Opaque));\n    if (!pipeline)\n        return pipeline;\n\n    IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;\n    opaque->ffp                   = ffp;\n\n    pipeline->func_destroy            = func_destroy;\n    pipeline->func_open_video_decoder = func_open_video_decoder;\n    pipeline->func_open_audio_output  = func_open_audio_output;\n\n    return pipeline;\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/pipeline/ffpipeline_ffplay.h",
    "content": "/*\n * ffpipeline_ffplay.h\n *\n * Copyright (c) 2014 Bilibili\n * Copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef FFPLAY__FF_FFPIPELINE_FFPLAY_H\n#define FFPLAY__FF_FFPIPELINE_FFPLAY_H\n\n#include \"../ff_ffpipeline.h\"\n\n// There is no default aout for ffplay.\n// IJKFF_Pipeline *ffpipeline_create_from_ffplay(FFPlayer *ffp);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/pipeline/ffpipenode_ffplay_vdec.c",
    "content": "/*\n * ffpipenode_ffplay_vdec.c\n *\n * Copyright (c) 2014 Bilibili\n * Copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ffpipenode_ffplay_vdec.h\"\n#include \"../ff_ffpipenode.h\"\n#include \"../ff_ffplay.h\"\n\nstruct IJKFF_Pipenode_Opaque {\n    FFPlayer *ffp;\n};\n\nstatic void func_destroy(IJKFF_Pipenode *node)\n{\n    // do nothing\n}\n\nstatic int func_run_sync(IJKFF_Pipenode *node)\n{\n    IJKFF_Pipenode_Opaque *opaque = node->opaque;\n\n    return ffp_video_thread(opaque->ffp);\n}\n\nIJKFF_Pipenode *ffpipenode_create_video_decoder_from_ffplay(FFPlayer *ffp)\n{\n    IJKFF_Pipenode *node = ffpipenode_alloc(sizeof(IJKFF_Pipenode_Opaque));\n    if (!node)\n        return node;\n\n    IJKFF_Pipenode_Opaque *opaque = node->opaque;\n    opaque->ffp         = ffp;\n\n    node->func_destroy  = func_destroy;\n    node->func_run_sync = func_run_sync;\n\n    ffp_set_video_codec_info(ffp, AVCODEC_MODULE_NAME, avcodec_get_name(ffp->is->viddec.avctx->codec_id));\n    ffp->stat.vdec_type = FFP_PROPV_DECODER_AVCODEC;\n    return node;\n}\n"
  },
  {
    "path": "ijkmedia/ijkplayer/pipeline/ffpipenode_ffplay_vdec.h",
    "content": "/*\n * ffpipenode_ffplay_vdec.h\n *\n * Copyright (c) 2014 Bilibili\n * Copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef FFPLAY__FF_FFPIPENODE_FFPLAY_VDEC_H\n#define FFPLAY__FF_FFPIPENODE_FFPLAY_VDEC_H\n\n#include \"../ff_ffpipenode.h\"\n\nstruct FFPlayer;\n\nIJKFF_Pipenode *ffpipenode_create_video_decoder_from_ffplay(struct FFPlayer *ffp);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijkplayer/version.sh",
    "content": "#!/bin/sh\n\n# Usage: version.sh <ijplayer-root-dir> <output-version.h>\n\n# check for git short hash\n\nif ! test \"$revision\"; then\n    if (cd \"$1\" && grep git RELEASE 2> /dev/null >/dev/null) ; then\n        revision=$(cd \"$1\" && git describe --tags --match N 2> /dev/null)\n    else\n        revision=$(cd \"$1\" && git describe --tags --always 2> /dev/null)\n    fi\nfi\n\n# Shallow Git clones (--depth) do not have the N tag:\n# use 'git-YYYY-MM-DD-hhhhhhh'.\ntest \"$revision\" || revision=$(cd \"$1\" &&\n  git log -1 --pretty=format:\"git-%cd-%h\" --date=short 2> /dev/null)\n\n# Snapshots from gitweb are in a directory called ijkplayer-hhhhhhh or\n# ijkplayer-HEAD-hhhhhhh.\nif [ -z \"$revision\" ]; then\n  srcdir=$(cd \"$1\" && pwd)\n  case \"$srcdir\" in\n    */ijkplayer-[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f])\n      git_hash=\"${srcdir##*-}\";;\n    */ijkplayer-HEAD-[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f])\n      git_hash=\"${srcdir##*-}\";;\n  esac\nfi\n\n# no revision number found\ntest \"$revision\" || revision=$(cd \"$1\" && cat RELEASE 2> /dev/null)\n\n# Append the Git hash if we have one\ntest \"$revision\" && test \"$git_hash\" && revision=\"$revision-$git_hash\"\n\n# releases extract the version number from the VERSION file\nversion=$(cd \"$1\" && cat VERSION 2> /dev/null)\ntest \"$version\" || version=$revision\n\nif [ -z \"$2\" ]; then\n    echo \"$version\"\n    exit\nfi\n\ncd $1\n\nNEW_REVISION=\"#define IJKPLAYER_VERSION \\\"$version\\\"\"\nOLD_REVISION=$(cat \"$2\" 2> /dev/null | head -4 | tail -1)\n\n# String used for preprocessor guard\nGUARD=$(echo \"$2\" | sed 's/\\//_/' | sed 's/\\./_/' | tr '[:lower:]' '[:upper:]' | sed 's/LIB//')\n\n# Update version header only on revision changes to avoid spurious rebuilds\nif test \"$NEW_REVISION\" != \"$OLD_REVISION\"; then\n    cat << EOF > \"$2\"\n/* Automatically generated by version.sh, do not manually edit! */\n#ifndef $GUARD\n#define $GUARD\n$NEW_REVISION\n#endif /* $GUARD */\nEOF\nfi\n"
  },
  {
    "path": "ijkmedia/ijksdl/Android.mk",
    "content": "# Copyright (c) 2013 Bilibili\n# copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n#\n# This file is part of ijkPlayer.\n#\n# ijkPlayer is free software; you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation; either\n# version 2.1 of the License, or (at your option) any later version.\n#\n# ijkPlayer is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# Lesser General Public License for more details.\n#\n# You should have received a copy of the GNU Lesser General Public\n# License along with ijkPlayer; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n\nLOCAL_PATH := $(call my-dir)\n\ninclude $(CLEAR_VARS)\nLOCAL_CFLAGS += -std=c99\nLOCAL_LDLIBS += -llog -landroid -lOpenSLES -lEGL -lGLESv2\n\nLOCAL_C_INCLUDES += $(LOCAL_PATH)\nLOCAL_C_INCLUDES += $(realpath $(LOCAL_PATH)/..)\nLOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH)\nLOCAL_C_INCLUDES += $(realpath $(LOCAL_PATH)/../ijkyuv/include)\nLOCAL_C_INCLUDES += $(realpath $(LOCAL_PATH)/../ijkj4a)\n\nLOCAL_SRC_FILES += ijksdl_aout.c\nLOCAL_SRC_FILES += ijksdl_audio.c\nLOCAL_SRC_FILES += ijksdl_egl.c\nLOCAL_SRC_FILES += ijksdl_error.c\nLOCAL_SRC_FILES += ijksdl_mutex.c\nLOCAL_SRC_FILES += ijksdl_stdinc.c\nLOCAL_SRC_FILES += ijksdl_thread.c\nLOCAL_SRC_FILES += ijksdl_timer.c\nLOCAL_SRC_FILES += ijksdl_vout.c\nLOCAL_SRC_FILES += ijksdl_extra_log.c\nLOCAL_SRC_FILES += gles2/color.c\nLOCAL_SRC_FILES += gles2/common.c\nLOCAL_SRC_FILES += gles2/renderer.c\nLOCAL_SRC_FILES += gles2/renderer_rgb.c\nLOCAL_SRC_FILES += gles2/renderer_yuv420p.c\nLOCAL_SRC_FILES += gles2/renderer_yuv444p10le.c\nLOCAL_SRC_FILES += gles2/shader.c\nLOCAL_SRC_FILES += gles2/fsh/rgb.fsh.c\nLOCAL_SRC_FILES += gles2/fsh/yuv420p.fsh.c\nLOCAL_SRC_FILES += gles2/fsh/yuv444p10le.fsh.c\nLOCAL_SRC_FILES += gles2/vsh/mvp.vsh.c\n\nLOCAL_SRC_FILES += dummy/ijksdl_vout_dummy.c\n\nLOCAL_SRC_FILES += ffmpeg/ijksdl_vout_overlay_ffmpeg.c\nLOCAL_SRC_FILES += ffmpeg/abi_all/image_convert.c\n\nLOCAL_SRC_FILES += android/android_audiotrack.c\nLOCAL_SRC_FILES += android/android_nativewindow.c\nLOCAL_SRC_FILES += android/ijksdl_android_jni.c\nLOCAL_SRC_FILES += android/ijksdl_aout_android_audiotrack.c\nLOCAL_SRC_FILES += android/ijksdl_aout_android_opensles.c\nLOCAL_SRC_FILES += android/ijksdl_codec_android_mediacodec_dummy.c\nLOCAL_SRC_FILES += android/ijksdl_codec_android_mediacodec_internal.c\nLOCAL_SRC_FILES += android/ijksdl_codec_android_mediacodec_java.c\nLOCAL_SRC_FILES += android/ijksdl_codec_android_mediacodec.c\nLOCAL_SRC_FILES += android/ijksdl_codec_android_mediadef.c\nLOCAL_SRC_FILES += android/ijksdl_codec_android_mediaformat_java.c\nLOCAL_SRC_FILES += android/ijksdl_codec_android_mediaformat.c\nLOCAL_SRC_FILES += android/ijksdl_vout_android_nativewindow.c\nLOCAL_SRC_FILES += android/ijksdl_vout_android_surface.c\nLOCAL_SRC_FILES += android/ijksdl_vout_overlay_android_mediacodec.c\n\nLOCAL_SHARED_LIBRARIES := ijkffmpeg\nLOCAL_STATIC_LIBRARIES := cpufeatures yuv_static ijkj4a\n\nLOCAL_MODULE := ijksdl\ninclude $(BUILD_SHARED_LIBRARY)\n\n$(call import-module,android/cpufeatures)\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/android_audiotrack.c",
    "content": "/*****************************************************************************\n * android_audiotrack.c\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"android_audiotrack.h\"\n\n#include <assert.h>\n#include \"j4au/class/android/media/AudioTrack.util.h\"\n#include \"ijksdl_android_jni.h\"\n#include \"../ijksdl_inc_internal.h\"\n#include \"../ijksdl_audio.h\"\n\n#ifdef SDLTRACE\n#undef SDLTRACE\n#define SDLTRACE(...)\n#endif\n\ntypedef struct AudioChannelMapEntry {\n    Uint8 sdl_channel;\n    int android_channel;\n    const char *sdl_name;\n    const char *android_name;\n} AudioChannelMapEntry;\nstatic AudioChannelMapEntry g_audio_channel_map[] = {\n    { 2, CHANNEL_OUT_STEREO, \"2-chan\", \"CHANNEL_OUT_STEREO\" },\n    { 1, CHANNEL_OUT_MONO, \"1-chan\", \"CHANNEL_OUT_MONO\" },\n};\n\ntypedef struct AudioFormatMapEntry {\n    SDL_AudioFormat sdl_format;\n    int android_format;\n    const char *sdl_name;\n    const char *android_name;\n} AudioFormatMapEntry;\nstatic AudioFormatMapEntry g_audio_format_map[] = {\n    { AUDIO_S16SYS, ENCODING_PCM_16BIT, \"AUDIO_S16SYS\", \"ENCODING_PCM_16BIT\" },\n    { AUDIO_U8,     ENCODING_PCM_8BIT,  \"AUDIO_U8\",     \"ENCODING_PCM_8BIT\" },\n    { AUDIO_F32,    ENCODING_PCM_FLOAT, \"AUDIO_F32\",    \"ENCODING_PCM_FLOAT\" },\n};\n\nstatic Uint8 find_sdl_channel(int android_channel)\n{\n    for (int i = 0; i < NELEM(g_audio_channel_map); ++i) {\n        AudioChannelMapEntry *entry = &g_audio_channel_map[i];\n        if (entry->android_channel == android_channel)\n            return entry->sdl_channel;\n    }\n    return 0;\n}\n\nstatic int find_android_channel(int sdl_channel)\n{\n    for (int i = 0; i < NELEM(g_audio_channel_map); ++i) {\n        AudioChannelMapEntry *entry = &g_audio_channel_map[i];\n        if (entry->sdl_channel == sdl_channel)\n            return entry->android_channel;\n    }\n    return CHANNEL_OUT_INVALID;\n}\n\nstatic SDL_AudioFormat find_sdl_format(int android_format)\n{\n    for (int i = 0; i < NELEM(g_audio_format_map); ++i) {\n        AudioFormatMapEntry *entry = &g_audio_format_map[i];\n        if (entry->android_format == android_format)\n            return entry->sdl_format;\n    }\n    return AUDIO_INVALID;\n}\n\nstatic int find_android_format(int sdl_format)\n{\n    for (int i = 0; i < NELEM(g_audio_format_map); ++i) {\n        AudioFormatMapEntry *entry = &g_audio_format_map[i];\n        if (entry->sdl_format == sdl_format)\n            return entry->android_format;\n    }\n    return ENCODING_INVALID;\n}\n\ntypedef struct SDL_Android_AudioTrack {\n    jobject thiz;\n\n    SDL_Android_AudioTrack_Spec spec;\n\n    jbyteArray  byte_buffer;\n    int         byte_buffer_capacity;\n    int         min_buffer_size;\n    float       max_volume;\n    float       min_volume;\n} SDL_Android_AudioTrack;\n\nstatic void SDL_Android_AudioTrack_get_default_spec(SDL_Android_AudioTrack_Spec *spec)\n{\n    assert(spec);\n    spec->stream_type = STREAM_MUSIC;\n    spec->sample_rate_in_hz = 0;\n    spec->channel_config = CHANNEL_OUT_STEREO;\n    spec->audio_format = ENCODING_PCM_16BIT;\n    spec->buffer_size_in_bytes = 0;\n    spec->mode = MODE_STREAM;\n}\n\n#define STREAM_MUSIC 3\nint audiotrack_get_native_output_sample_rate(JNIEnv *env)\n{\n    if (!env) {\n        if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n            ALOGE(\"%s: SetupThreadEnv failed\", __func__);\n            return -1;\n        }\n    }\n\n    jint retval = J4AC_AudioTrack__getNativeOutputSampleRate(env, STREAM_MUSIC);\n    if (J4A_ExceptionCheck__catchAll(env) || retval <= 0)\n        return -1;\n\n    return retval;\n}\n\nvoid SDL_Android_AudioTrack_set_volume(JNIEnv *env, SDL_Android_AudioTrack *atrack, float left_volume, float right_volume)\n{\n    J4AC_AudioTrack__setStereoVolume__catchAll(env, atrack->thiz, left_volume, right_volume);\n}\n\nSDL_Android_AudioTrack *SDL_Android_AudioTrack_new_from_spec(JNIEnv *env, SDL_Android_AudioTrack_Spec *spec)\n{\n    assert(spec);\n\n    switch (spec->channel_config) {\n    case CHANNEL_OUT_MONO:\n        ALOGI(\"SDL_Android_AudioTrack: %s\", \"CHANNEL_OUT_MONO\");\n        break;\n    case CHANNEL_OUT_STEREO:\n        ALOGI(\"SDL_Android_AudioTrack: %s\", \"CHANNEL_OUT_STEREO\");\n        break;\n    default:\n        ALOGE(\"%s: invalid channel %d\", __func__, spec->channel_config);\n        return NULL;\n    }\n\n    switch (spec->audio_format) {\n    case ENCODING_PCM_16BIT:\n        ALOGI(\"SDL_Android_AudioTrack: %s\", \"ENCODING_PCM_16BIT\");\n        break;\n    case ENCODING_PCM_8BIT:\n        ALOGI(\"SDL_Android_AudioTrack: %s\", \"ENCODING_PCM_8BIT\");\n        break;\n#if 0\n    case ENCODING_PCM_FLOAT:\n        ALOGI(\"SDL_Android_AudioTrack: %s\", \"ENCODING_PCM_FLOAT\");\n        if (sdk_int < IJK_API_21_LOLLIPOP) {\n            ALOGI(\"SDL_Android_AudioTrack: %s need API 21 or above\", \"ENCODING_PCM_FLOAT\");\n            return NULL;\n        }\n        break;\n#endif\n    default:\n        ALOGE(\"%s: invalid format %d\", __func__, spec->audio_format);\n        return NULL;\n    }\n\n    if (spec->sample_rate_in_hz <= 0) {\n        ALOGE(\"%s: invalid sample rate %d\", __func__, spec->sample_rate_in_hz);\n        return NULL;\n    }\n\n    SDL_Android_AudioTrack *atrack = (SDL_Android_AudioTrack*) mallocz(sizeof(SDL_Android_AudioTrack));\n    if (!atrack) {\n        ALOGE(\"%s: mallocz faild.\\n\", __func__);\n        return NULL;\n    }\n    atrack->spec = *spec;\n\n    // libswresample is ugly, depending on native resampler\n    while (atrack->spec.sample_rate_in_hz < 4000) {\n        atrack->spec.sample_rate_in_hz *= 2;\n    }\n    while (atrack->spec.sample_rate_in_hz > 48000) {\n        atrack->spec.sample_rate_in_hz /= 2;   \n    }\n\n    int min_buffer_size = J4AC_AudioTrack__getMinBufferSize(env,\n        atrack->spec.sample_rate_in_hz,\n        atrack->spec.channel_config,\n        atrack->spec.audio_format);\n    if (J4A_ExceptionCheck__catchAll(env) || min_buffer_size <= 0) {\n        ALOGE(\"%s: J4AC_AudioTrack__getMinBufferSize: return %d:\", __func__, min_buffer_size);\n        free(atrack);\n        return NULL;\n    }\n\n    // for fast playback\n    min_buffer_size *= AUDIOTRACK_PLAYBACK_MAXSPEED;\n\n    atrack->thiz = J4AC_AudioTrack__AudioTrack__asGlobalRef__catchAll(env, \n        atrack->spec.stream_type,\n        atrack->spec.sample_rate_in_hz,\n        atrack->spec.channel_config,\n        atrack->spec.audio_format,\n        min_buffer_size,\n        atrack->spec.mode);\n    if (!atrack->thiz) {\n        free(atrack);\n        return NULL;\n    }\n\n    atrack->min_buffer_size = min_buffer_size;\n    atrack->spec.buffer_size_in_bytes = min_buffer_size;\n    // atrack->max_volume = J4AC_AudioTrack__getMaxVolume__catchAll(env);\n    // atrack->min_volume = J4AC_AudioTrack__getMinVolume__catchAll(env);\n    atrack->max_volume = 1.0f;\n    atrack->min_volume = 0.0f;\n\n    // extra init\n    float init_volume = 1.0f;\n    init_volume = IJKMIN(init_volume, atrack->max_volume);\n    init_volume = IJKMAX(init_volume, atrack->min_volume);\n    ALOGI(\"%s: init volume as %f/(%f,%f)\", __func__, init_volume, atrack->min_volume, atrack->max_volume);\n    J4AC_AudioTrack__setStereoVolume__catchAll(env, atrack->thiz, init_volume, init_volume);\n\n    return atrack;\n}\n\nSDL_Android_AudioTrack *SDL_Android_AudioTrack_new_from_sdl_spec(JNIEnv *env, const SDL_AudioSpec *sdl_spec)\n{\n    SDL_Android_AudioTrack_Spec atrack_spec;\n\n    SDL_Android_AudioTrack_get_default_spec(&atrack_spec);\n    atrack_spec.sample_rate_in_hz = sdl_spec->freq;\n    atrack_spec.channel_config = find_android_channel(sdl_spec->channels);\n    atrack_spec.audio_format = find_android_format(sdl_spec->format);\n    atrack_spec.buffer_size_in_bytes = sdl_spec->size;\n\n    return SDL_Android_AudioTrack_new_from_spec(env, &atrack_spec);\n}\n\nvoid SDL_Android_AudioTrack_free(JNIEnv *env, SDL_Android_AudioTrack* atrack)\n{\n    J4A_DeleteGlobalRef__p(env, &atrack->byte_buffer);\n    atrack->byte_buffer_capacity = 0;\n\n    if (atrack->thiz) {\n        J4AC_AudioTrack__release(env, atrack->thiz);\n        J4A_DeleteGlobalRef__p(env, &atrack->thiz);\n    }\n\n    free(atrack);\n}\n\nvoid SDL_Android_AudioTrack_get_target_spec(SDL_Android_AudioTrack *atrack, SDL_AudioSpec *sdl_spec)\n{\n    SDL_Android_AudioTrack_Spec *atrack_spec = &atrack->spec;\n\n    sdl_spec->freq = atrack_spec->sample_rate_in_hz;\n    sdl_spec->channels = find_sdl_channel(atrack_spec->channel_config);\n    sdl_spec->format = find_sdl_format(atrack_spec->audio_format);\n    sdl_spec->size = atrack_spec->buffer_size_in_bytes;\n    sdl_spec->silence = 0;\n    sdl_spec->padding = 0;\n}\n\nint SDL_Android_AudioTrack_get_min_buffer_size(SDL_Android_AudioTrack* atrack)\n{\n    return atrack->min_buffer_size;\n}\n\nvoid SDL_Android_AudioTrack_play(JNIEnv *env, SDL_Android_AudioTrack *atrack)\n{\n    SDLTRACE(\"%s\", __func__);\n    J4AC_AudioTrack__play__catchAll(env, atrack->thiz);\n}\n\nvoid SDL_Android_AudioTrack_pause(JNIEnv *env, SDL_Android_AudioTrack *atrack)\n{\n    SDLTRACE(\"%s\", __func__);\n    J4AC_AudioTrack__pause__catchAll(env, atrack->thiz);\n}\n\nvoid SDL_Android_AudioTrack_flush(JNIEnv *env, SDL_Android_AudioTrack *atrack)\n{\n    SDLTRACE(\"%s\", __func__);\n    J4AC_AudioTrack__flush__catchAll(env, atrack->thiz);\n}\n\nvoid SDL_Android_AudioTrack_stop(JNIEnv *env, SDL_Android_AudioTrack *atrack)\n{\n    SDLTRACE(\"%s\", __func__);\n    J4AC_AudioTrack__stop__catchAll(env, atrack->thiz);\n}\n\nint SDL_Android_AudioTrack_reserve_byte_buffer(JNIEnv *env, SDL_Android_AudioTrack *atrack, int size_in_byte)\n{\n    if (atrack->byte_buffer && size_in_byte <= atrack->byte_buffer_capacity)\n        return size_in_byte;\n\n    J4A_DeleteGlobalRef__p(env, &atrack->byte_buffer);\n    atrack->byte_buffer_capacity = 0;\n\n    int capacity = IJKMAX(size_in_byte, atrack->min_buffer_size);\n    atrack->byte_buffer = J4A_NewByteArray__asGlobalRef__catchAll(env, capacity);\n    if (!atrack->byte_buffer)\n        return -1;\n\n    atrack->byte_buffer_capacity = capacity;\n    return capacity;\n}\n\nint SDL_Android_AudioTrack_write(JNIEnv *env, SDL_Android_AudioTrack *atrack, uint8_t *data, int size_in_byte)\n{\n    if (size_in_byte <= 0)\n        return size_in_byte;\n\n    int reserved = SDL_Android_AudioTrack_reserve_byte_buffer(env, atrack, size_in_byte);\n    if (reserved < size_in_byte) {\n        ALOGE(\"%s failed %d < %d\\n\", __func__, reserved, size_in_byte);\n        return -1;\n    }\n\n    (*env)->SetByteArrayRegion(env, atrack->byte_buffer, 0, (int)size_in_byte, (jbyte*) data);\n    if (J4A_ExceptionCheck__catchAll(env))\n        return -1;\n\n    int retval = J4AC_AudioTrack__write(env, atrack->thiz, atrack->byte_buffer, 0, (int)size_in_byte);\n    if (J4A_ExceptionCheck__catchAll(env))\n        return -1;\n\n    return retval;\n}\n\nint SDL_Android_AudioTrack_getAudioSessionId(JNIEnv *env, SDL_Android_AudioTrack *atrack)\n{\n    SDLTRACE(\"%s\", __func__);\n    int audioSessionId = J4AC_AudioTrack__getAudioSessionId(env, atrack->thiz);\n    if (J4A_ExceptionCheck__catchAll(env))\n        return 0;\n\n    return audioSessionId;\n}\n\nvoid SDL_Android_AudioTrack_setSpeed(JNIEnv *env, SDL_Android_AudioTrack *atrack, float speed)\n{\n    J4AC_AudioTrack__setSpeed(env, atrack->thiz, speed);\n    if (J4A_ExceptionCheck__catchAll(env))\n        return;\n\n    return;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/android_audiotrack.h",
    "content": "/*****************************************************************************\n * android_audiotrack.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL_ANDROID__ANDROID_AUDIOTRACK_H\n#define IJKSDL_ANDROID__ANDROID_AUDIOTRACK_H\n\n#include <stdint.h>\n#include <jni.h>\n#include \"../ijksdl_audio.h\"\n#include \"../ijksdl_aout.h\"\n\n#define AUDIOTRACK_PLAYBACK_MAXSPEED (2)\n\ntypedef struct SDL_Android_AudioTrack_Spec {\n    enum StreamType {\n        STREAM_VOICE_CALL = 0,\n        STREAM_SYSTEM = 1,\n        STREAM_RING = 2,\n        STREAM_MUSIC = 3,\n        STREAM_ALARM = 4,\n        STREAM_NOTIFICATION = 5,\n    } stream_type;\n\n    int sample_rate_in_hz;\n\n    enum ChannelConfig {\n        CHANNEL_OUT_INVALID = 0x0,\n        CHANNEL_OUT_DEFAULT = 0x1, /* f-l */\n        CHANNEL_OUT_MONO = 0x4, /* f-l, f-r */\n        CHANNEL_OUT_STEREO = 0xc, /* f-l, f-r, b-l, b-r */\n        CHANNEL_OUT_QUAD = 0xcc, /* f-l, f-r, b-l, b-r */\n        CHANNEL_OUT_SURROUND = 0x41c, /* f-l, f-r, f-c, b-c */\n        CHANNEL_OUT_5POINT1 = 0xfc, /* f-l, f-r, b-l, b-r, f-c, low */\n        CHANNEL_OUT_7POINT1 = 0x3fc, /* f-l, f-r, b-l, b-r, f-c, low, f-lc, f-rc */\n\n        CHANNEL_OUT_FRONT_LEFT = 0x4,\n        CHANNEL_OUT_FRONT_RIGHT = 0x8,\n        CHANNEL_OUT_BACK_LEFT = 0x40,\n        CHANNEL_OUT_BACK_RIGHT = 0x80,\n        CHANNEL_OUT_FRONT_CENTER = 0x10,\n        CHANNEL_OUT_LOW_FREQUENCY = 0x20,\n        CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x100,\n        CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x200,\n        CHANNEL_OUT_BACK_CENTER = 0x400,\n    } channel_config;\n\n    enum AudioFormat {\n        ENCODING_INVALID = 0,\n        ENCODING_DEFAULT = 1,\n        ENCODING_PCM_16BIT = 2, // signed, guaranteed to be supported by devices.\n        ENCODING_PCM_8BIT = 3, // unsigned, not guaranteed to be supported by devices.\n        ENCODING_PCM_FLOAT = 4, // single-precision floating-point per sample\n    } audio_format;\n    int buffer_size_in_bytes;\n\n    enum Mode {\n        MODE_STATIC = 0,\n        MODE_STREAM = 1,\n    } mode;\n\n    enum WriteMode {\n        WRITE_BLOCKING     = 0,\n        WRITE_NON_BLOCKING = 1,\n    } write_mode; // not used\n\n    // extra field\n    int sdl_samples;\n} SDL_Android_AudioTrack_Spec;\n\ntypedef struct SDL_Android_AudioTrack SDL_Android_AudioTrack;\n\nSDL_Android_AudioTrack *SDL_Android_AudioTrack_new_from_spec(JNIEnv *env, SDL_Android_AudioTrack_Spec *spec);\nSDL_Android_AudioTrack *SDL_Android_AudioTrack_new_from_sdl_spec(JNIEnv *env, const SDL_AudioSpec *sdl_spec);\nvoid SDL_Android_AudioTrack_free(JNIEnv *env, SDL_Android_AudioTrack* atrack);\n\nvoid SDL_Android_AudioTrack_get_target_spec(SDL_Android_AudioTrack* atrack, SDL_AudioSpec *spec);\nint SDL_Android_AudioTrack_get_min_buffer_size(SDL_Android_AudioTrack* atrack);\nint audiotrack_get_native_output_sample_rate(JNIEnv *env/* = NULL */);\n\nvoid SDL_Android_AudioTrack_play(JNIEnv *env, SDL_Android_AudioTrack *atrack);\nvoid SDL_Android_AudioTrack_pause(JNIEnv *env, SDL_Android_AudioTrack *atrack);\nvoid SDL_Android_AudioTrack_flush(JNIEnv *env, SDL_Android_AudioTrack *atrack);\nvoid SDL_Android_AudioTrack_set_volume(JNIEnv *env, SDL_Android_AudioTrack *atrack, float left_volume, float right_volume);\nvoid SDL_Android_AudioTrack_stop(JNIEnv *env, SDL_Android_AudioTrack *atrack);\nvoid SDL_Android_AudioTrack_release(JNIEnv *env, SDL_Android_AudioTrack *atrack);\nint SDL_Android_AudioTrack_write(JNIEnv *env, SDL_Android_AudioTrack *atrack, uint8_t *data, int size_in_byte);\n\nint  SDL_Android_AudioTrack_getAudioSessionId(JNIEnv *env, SDL_Android_AudioTrack *atrack);\nvoid SDL_Android_AudioTrack_setSpeed(JNIEnv *env, SDL_Android_AudioTrack *atrack, float speed);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/android_nativewindow.c",
    "content": "/*****************************************************************************\n * android_nativewindow.c\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"android_nativewindow.h\"\n\n#include <assert.h>\n#include <android/native_window.h>\n#include \"../ijksdl_vout.h\"\n#include \"../ijksdl_vout_internal.h\"\n#include \"../ffmpeg/ijksdl_inc_ffmpeg.h\"\n#include \"ijksdl_inc_internal_android.h\"\n\n#ifdef SDLTRACE\n#undef SDLTRACE\n#define SDLTRACE(...)\n#endif\n\nstatic int android_render_yv12_on_yv12(ANativeWindow_Buffer *out_buffer, const SDL_VoutOverlay *overlay)\n{\n    // SDLTRACE(\"SDL_VoutAndroid: android_render_yv12_on_yv12(%p)\", overlay);\n    assert(overlay->format == SDL_FCC_YV12);\n    assert(overlay->planes == 3);\n\n    int min_height = IJKMIN(out_buffer->height, overlay->h);\n    int dst_y_stride = out_buffer->stride;\n    int dst_c_stride = IJKALIGN(out_buffer->stride / 2, 16);\n    int dst_y_size = dst_y_stride * out_buffer->height;\n    int dst_c_size = dst_c_stride * out_buffer->height / 2;\n\n    // ALOGE(\"stride:%d/%d, size:%d/%d\", dst_y_stride, dst_c_stride, dst_y_size, dst_c_size);\n\n    uint8_t *dst_pixels_array[] = {\n        out_buffer->bits,\n        out_buffer->bits + dst_y_size,\n        out_buffer->bits + dst_y_size + dst_c_size,\n    };\n    int dst_line_height[] = { min_height, min_height / 2, min_height / 2 };\n    int dst_line_size_array[] = { dst_y_stride, dst_c_stride, dst_c_stride };\n\n    for (int i = 0; i < 3; ++i) {\n        int dst_line_size = dst_line_size_array[i];\n        int src_line_size = overlay->pitches[i];\n        int line_height = dst_line_height[i];\n        uint8_t *dst_pixels = dst_pixels_array[i];\n        const uint8_t *src_pixels = overlay->pixels[i];\n\n        if (dst_line_size == src_line_size) {\n            int plane_size = src_line_size * line_height;\n\n            // ALOGE(\"sdl_image_copy_plane %p %p %d\", dst_pixels, src_pixels, dst_plane_size);\n            memcpy(dst_pixels, src_pixels, plane_size);\n        } else {\n            // TODO: 9 padding\n            int bytewidth = IJKMIN(dst_line_size, src_line_size);\n\n            // ALOGE(\"av_image_copy_plane %p %d %p %d %d %d\", dst_pixels, dst_line_size, src_pixels, src_line_size, bytewidth, line_height);\n            av_image_copy_plane(dst_pixels, dst_line_size, src_pixels, src_line_size, bytewidth, line_height);\n        }\n    }\n\n    return 0;\n}\n\nstatic int android_render_on_yv12(ANativeWindow_Buffer *out_buffer, const SDL_VoutOverlay *overlay)\n{\n    assert(out_buffer);\n    assert(overlay);\n\n    switch (overlay->format) {\n    case SDL_FCC_YV12: {\n        return android_render_yv12_on_yv12(out_buffer, overlay);\n    }\n    }\n\n    return -1;\n}\n\nstatic int android_render_rgb_on_rgb(ANativeWindow_Buffer *out_buffer, const SDL_VoutOverlay *overlay, int bpp)\n{\n    // SDLTRACE(\"SDL_VoutAndroid: android_render_rgb_on_rgb(%p)\", overlay);\n    assert(overlay->format == SDL_FCC_RV16);\n    assert(overlay->planes == 1);\n\n    int min_height = IJKMIN(out_buffer->height, overlay->h);\n    int dst_stride = out_buffer->stride;\n    int src_line_size = overlay->pitches[0];\n    int dst_line_size = dst_stride * bpp / 8;\n\n    uint8_t *dst_pixels = out_buffer->bits;\n    const uint8_t *src_pixels = overlay->pixels[0];\n\n    if (dst_line_size == src_line_size) {\n        int plane_size = src_line_size * min_height;\n        // ALOGE(\"android_render_rgb_on_rgb (pix-match) %p %p %d\", dst_pixels, src_pixels, plane_size);\n        memcpy(dst_pixels, src_pixels, plane_size);\n    } else {\n        // TODO: 9 padding\n        int bytewidth = IJKMIN(dst_line_size, src_line_size);\n\n        // ALOGE(\"android_render_rgb_on_rgb (pix-mismatch) %p %d %p %d %d %d\", dst_pixels, dst_line_size, src_pixels, src_line_size, bytewidth, min_height);\n        av_image_copy_plane(dst_pixels, dst_line_size, src_pixels, src_line_size, bytewidth, min_height);\n    }\n\n    return 0;\n}\n\nstatic int android_render_rgb565_on_rgb565(ANativeWindow_Buffer *out_buffer, const SDL_VoutOverlay *overlay)\n{\n    return android_render_rgb_on_rgb(out_buffer, overlay, 16);\n}\n\nstatic int android_render_on_rgb565(ANativeWindow_Buffer *out_buffer, const SDL_VoutOverlay *overlay)\n{\n    assert(out_buffer);\n    assert(overlay);\n\n    switch (overlay->format) {\n    case SDL_FCC_RV16: {\n        return android_render_rgb565_on_rgb565(out_buffer, overlay);\n    }\n    }\n\n    return -1;\n}\n\nstatic int android_render_rgb32_on_rgb8888(ANativeWindow_Buffer *out_buffer, const SDL_VoutOverlay *overlay)\n{\n    return android_render_rgb_on_rgb(out_buffer, overlay, 32);\n}\n\nstatic int android_render_on_rgb8888(ANativeWindow_Buffer *out_buffer, const SDL_VoutOverlay *overlay)\n{\n    assert(out_buffer);\n    assert(overlay);\n\n    switch (overlay->format) {\n    case SDL_FCC_RV32: {\n        return android_render_rgb32_on_rgb8888(out_buffer, overlay);\n    }\n    }\n\n    return -1;\n}\n\ntypedef struct AndroidHalFourccDescriptor {\n    Uint32 fcc_or_hal;\n    const char* name;\n\n    int hal_format;\n\n    int (*render)(ANativeWindow_Buffer *native_buffer, const SDL_VoutOverlay *overlay);\n} AndroidHalFourccDescriptor;\n\nstatic AndroidHalFourccDescriptor g_hal_fcc_map[] = {\n    // YV12\n    { HAL_PIXEL_FORMAT_YV12, \"HAL_YV12\", HAL_PIXEL_FORMAT_YV12, android_render_on_yv12 },\n    { SDL_FCC_YV12, \"YV12\", HAL_PIXEL_FORMAT_YV12, android_render_on_yv12 },\n\n    // RGB565\n    { HAL_PIXEL_FORMAT_RGB_565, \"HAL_RGB_565\", HAL_PIXEL_FORMAT_RGB_565, android_render_on_rgb565 },\n    { SDL_FCC_RV16, \"RV16\", HAL_PIXEL_FORMAT_RGB_565, android_render_on_rgb565 },\n\n    // RGB8888\n    { HAL_PIXEL_FORMAT_RGBX_8888, \"HAL_RGBX_8888\", HAL_PIXEL_FORMAT_RGBX_8888, android_render_on_rgb8888 },\n    { HAL_PIXEL_FORMAT_RGBA_8888, \"HAL_RGBA_8888\", HAL_PIXEL_FORMAT_RGBA_8888, android_render_on_rgb8888 },\n    { HAL_PIXEL_FORMAT_BGRA_8888, \"HAL_BGRA_8888\", HAL_PIXEL_FORMAT_BGRA_8888, android_render_on_rgb8888 },\n    { SDL_FCC_RV32, \"RV32\", HAL_PIXEL_FORMAT_RGBX_8888, android_render_on_rgb8888 },\n};\n\nAndroidHalFourccDescriptor *native_window_get_desc(int fourcc_or_hal)\n{\n    for (int i = 0; i < NELEM(g_hal_fcc_map); ++i) {\n        AndroidHalFourccDescriptor *desc = &g_hal_fcc_map[i];\n        if (desc->fcc_or_hal == fourcc_or_hal)\n            return desc;\n    }\n\n    return NULL;\n}\n\nint SDL_Android_NativeWindow_display_l(ANativeWindow *native_window, SDL_VoutOverlay *overlay)\n{\n    int retval;\n\n    if (!native_window)\n        return -1;\n\n    if (!overlay) {\n        ALOGE(\"SDL_Android_NativeWindow_display_l: NULL overlay\");\n        return -1;\n    }\n\n    if (overlay->w <= 0 || overlay->h <= 0) {\n        ALOGE(\"SDL_Android_NativeWindow_display_l: invalid overlay dimensions(%d, %d)\", overlay->w, overlay->h);\n        return -1;\n    }\n\n    int curr_w = ANativeWindow_getWidth(native_window);\n    int curr_h = ANativeWindow_getHeight(native_window);\n    int curr_format = ANativeWindow_getFormat(native_window);\n    int buff_w = IJKALIGN(overlay->w, 2);\n    int buff_h = IJKALIGN(overlay->h, 2);\n\n    AndroidHalFourccDescriptor *overlayDesc = native_window_get_desc(overlay->format);\n    if (!overlayDesc) {\n        ALOGE(\"SDL_Android_NativeWindow_display_l: unknown overlay format: %d\", overlay->format);\n        return -1;\n    }\n\n    AndroidHalFourccDescriptor *voutDesc = native_window_get_desc(curr_format);\n    if (!voutDesc || voutDesc->hal_format != overlayDesc->hal_format) {\n        ALOGD(\"ANativeWindow_setBuffersGeometry: w=%d, h=%d, f=%.4s(0x%x) => w=%d, h=%d, f=%.4s(0x%x)\",\n            curr_w, curr_h, (char*) &curr_format, curr_format,\n            buff_w, buff_h, (char*) &overlay->format, overlay->format);\n        retval = ANativeWindow_setBuffersGeometry(native_window, buff_w, buff_h, overlayDesc->hal_format);\n        if (retval < 0) {\n            ALOGE(\"SDL_Android_NativeWindow_display_l: ANativeWindow_setBuffersGeometry: failed %d\", retval);\n            return retval;\n        }\n\n        if (!voutDesc) {\n            ALOGE(\"SDL_Android_NativeWindow_display_l: unknown hal format %d\", curr_format);\n            return -1;\n        }\n    }\n\n    ANativeWindow_Buffer out_buffer;\n    retval = ANativeWindow_lock(native_window, &out_buffer, NULL);\n    if (retval < 0) {\n        ALOGE(\"SDL_Android_NativeWindow_display_l: ANativeWindow_lock: failed %d\", retval);\n        return retval;\n    }\n\n    if (out_buffer.width != buff_w || out_buffer.height != buff_h) {\n        ALOGE(\"unexpected native window buffer (%p)(w:%d, h:%d, fmt:'%.4s'0x%x), expecting (w:%d, h:%d, fmt:'%.4s'0x%x)\",\n            native_window,\n            out_buffer.width, out_buffer.height, (char*)&out_buffer.format, out_buffer.format,\n            buff_w, buff_h, (char*)&overlay->format, overlay->format);\n        // TODO: 8 set all black\n        ANativeWindow_unlockAndPost(native_window);\n        ANativeWindow_setBuffersGeometry(native_window, buff_w, buff_h, overlayDesc->hal_format);\n        return -1;\n    }\n\n    int render_ret = voutDesc->render(&out_buffer, overlay);\n    if (render_ret < 0) {\n        // TODO: 8 set all black\n        // return after unlock image;\n    }\n\n    retval = ANativeWindow_unlockAndPost(native_window);\n    if (retval < 0) {\n        ALOGE(\"SDL_Android_NativeWindow_display_l: ANativeWindow_unlockAndPost: failed %d\", retval);\n        return retval;\n    }\n\n    return render_ret;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/android_nativewindow.h",
    "content": "/*****************************************************************************\n * android_nativewindow.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL_ANDROID__ANDROID_NATIVEWINDOW_H\n#define IJKSDL_ANDROID__ANDROID_NATIVEWINDOW_H\n\ntypedef struct ANativeWindow ANativeWindow;\ntypedef struct SDL_VoutOverlay SDL_VoutOverlay;\n\nint SDL_Android_NativeWindow_display_l(ANativeWindow* native_window, SDL_VoutOverlay *overlay);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_android.h",
    "content": "/*****************************************************************************\n * ijksdl_android.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL_ANDROID__IJKSDL_ANDROID_H\n#define IJKSDL_ANDROID__IJKSDL_ANDROID_H\n\n#include \"../ijksdl.h\"\n\n#include \"ijksdl_aout_android_audiotrack.h\"\n#include \"ijksdl_aout_android_opensles.h\"\n\n#include \"ijksdl_vout_android_nativewindow.h\"\n#include \"ijksdl_vout_android_surface.h\"\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_android_jni.c",
    "content": "/*****************************************************************************\n * ijksdl_android.c\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl_android_jni.h\"\n\n#include <unistd.h>\n#include \"j4a/class/android/os/Build.h\"\n#include \"ijksdl_inc_internal_android.h\"\n#include \"ijksdl_codec_android_mediaformat_java.h\"\n#include \"ijksdl_codec_android_mediacodec_java.h\"\n\nstatic JavaVM *g_jvm;\n\nstatic pthread_key_t g_thread_key;\nstatic pthread_once_t g_key_once = PTHREAD_ONCE_INIT;\n\nJavaVM *SDL_JNI_GetJvm()\n{\n    return g_jvm;\n}\n\nstatic void SDL_JNI_ThreadDestroyed(void* value)\n{\n    JNIEnv *env = (JNIEnv*) value;\n    if (env != NULL) {\n        ALOGE(\"%s: [%d] didn't call SDL_JNI_DetachThreadEnv() explicity\\n\", __func__, (int)gettid());\n        (*g_jvm)->DetachCurrentThread(g_jvm);\n        pthread_setspecific(g_thread_key, NULL);\n    }\n}\n\nstatic void make_thread_key()\n{\n    pthread_key_create(&g_thread_key, SDL_JNI_ThreadDestroyed);\n}\n\njint SDL_JNI_SetupThreadEnv(JNIEnv **p_env)\n{\n    JavaVM *jvm = g_jvm;\n    if (!jvm) {\n        ALOGE(\"SDL_JNI_GetJvm: AttachCurrentThread: NULL jvm\");\n        return -1;\n    }\n\n    pthread_once(&g_key_once, make_thread_key);\n\n    JNIEnv *env = (JNIEnv*) pthread_getspecific(g_thread_key);\n    if (env) {\n        *p_env = env;\n        return 0;\n    }\n\n    if ((*jvm)->AttachCurrentThread(jvm, &env, NULL) == JNI_OK) {\n        pthread_setspecific(g_thread_key, env);\n        *p_env = env;\n        return 0;\n    }\n\n    return -1;\n}\n\nvoid SDL_JNI_DetachThreadEnv()\n{\n    JavaVM *jvm = g_jvm;\n\n    ALOGI(\"%s: [%d]\\n\", __func__, (int)gettid());\n\n    pthread_once(&g_key_once, make_thread_key);\n\n    JNIEnv *env = pthread_getspecific(g_thread_key);\n    if (!env)\n        return;\n    pthread_setspecific(g_thread_key, NULL);\n\n    if ((*jvm)->DetachCurrentThread(jvm) == JNI_OK)\n        return;\n\n    return;\n}\n\nint SDL_JNI_ThrowException(JNIEnv* env, const char* className, const char* msg)\n{\n    if ((*env)->ExceptionCheck(env)) {\n        jthrowable exception = (*env)->ExceptionOccurred(env);\n        (*env)->ExceptionClear(env);\n\n        if (exception != NULL) {\n            ALOGW(\"Discarding pending exception (%s) to throw\", className);\n            (*env)->DeleteLocalRef(env, exception);\n        }\n    }\n\n    jclass exceptionClass = (*env)->FindClass(env, className);\n    if (exceptionClass == NULL) {\n        ALOGE(\"Unable to find exception class %s\", className);\n        /* ClassNotFoundException now pending */\n        goto fail;\n    }\n\n    if ((*env)->ThrowNew(env, exceptionClass, msg) != JNI_OK) {\n        ALOGE(\"Failed throwing '%s' '%s'\", className, msg);\n        /* an exception, most likely OOM, will now be pending */\n        goto fail;\n    }\n\n    return 0;\nfail:\n    if (exceptionClass)\n        (*env)->DeleteLocalRef(env, exceptionClass);\n    return -1;\n}\n\nint SDL_JNI_ThrowIllegalStateException(JNIEnv *env, const char* msg)\n{\n    return SDL_JNI_ThrowException(env, \"java/lang/IllegalStateException\", msg);\n}\n\njobject SDL_JNI_NewObjectAsGlobalRef(JNIEnv *env, jclass clazz, jmethodID methodID, ...)\n{\n    va_list args;\n    va_start(args, methodID);\n\n    jobject global_object = NULL;\n    jobject local_object = (*env)->NewObjectV(env, clazz, methodID, args);\n    if (!J4A_ExceptionCheck__throwAny(env) && local_object) {\n        global_object = (*env)->NewGlobalRef(env, local_object);\n        SDL_JNI_DeleteLocalRefP(env, &local_object);\n    }\n\n    va_end(args);\n    return global_object;\n}\n\nvoid SDL_JNI_DeleteGlobalRefP(JNIEnv *env, jobject *obj_ptr)\n{\n    if (!obj_ptr || !*obj_ptr)\n        return;\n\n    (*env)->DeleteGlobalRef(env, *obj_ptr);\n    *obj_ptr = NULL;\n}\n\nvoid SDL_JNI_DeleteLocalRefP(JNIEnv *env, jobject *obj_ptr)\n{\n    if (!obj_ptr || !*obj_ptr)\n        return;\n\n    (*env)->DeleteLocalRef(env, *obj_ptr);\n    *obj_ptr = NULL;\n}\n\n\nint SDL_Android_GetApiLevel()\n{\n    static int SDK_INT = 0;\n    if (SDK_INT > 0)\n        return SDK_INT;\n\n    JNIEnv *env = NULL;\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"SDL_Android_GetApiLevel: SetupThreadEnv failed\");\n        return 0;\n    }\n\n    SDK_INT = J4AC_android_os_Build__VERSION__SDK_INT__get__catchAll(env);\n    ALOGI(\"API-Level: %d\\n\", SDK_INT);\n    return SDK_INT;\n#if 0\n    char value[PROP_VALUE_MAX];\n    memset(value, 0, sizeof(value));\n    __system_property_get(\"ro.build.version.sdk\", value);\n    SDK_INT = atoi(value);\n    return SDK_INT;\n#endif\n}\n\n\nJNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)\n{\n    int retval;\n    JNIEnv* env = NULL;\n\n    g_jvm = vm;\n    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {\n        return -1;\n    }\n\n    retval = J4A_LoadAll__catchAll(env);\n    JNI_CHECK_RET(retval == 0, env, NULL, NULL, -1);\n\n    return JNI_VERSION_1_4;\n}\n\nJNIEXPORT void JNICALL JNI_OnUnload(JavaVM *jvm, void *reserved)\n{\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_android_jni.h",
    "content": "/*****************************************************************************\n * ijksdl_android_jni.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL_ANDROID__IJKSDL_ANDROID_JNI_H\n#define IJKSDL_ANDROID__IJKSDL_ANDROID_JNI_H\n\n#include <jni.h>\n#include \"j4a/j4a_base.h\"\n#include \"j4a/j4a_allclasses.h\"\n\n#define IJK_API_1_BASE                      1   // 1.0\n#define IJK_API_2_BASE_1_1                  2   // 1.1\n#define IJK_API_3_CUPCAKE                   3   // 1.5\n#define IJK_API_4_DONUT                     4   // 1.6\n#define IJK_API_5_ECLAIR                    5   // 2.0\n#define IJK_API_6_ECLAIR_0_1                6   // 2.0.1\n#define IJK_API_7_ECLAIR_MR1                7   // 2.1\n#define IJK_API_8_FROYO                     8   // 2.2\n#define IJK_API_9_GINGERBREAD               9   // 2.3\n#define IJK_API_10_GINGERBREAD_MR1          10  // 2.3.3\n#define IJK_API_11_HONEYCOMB                11  // 3.0\n#define IJK_API_12_HONEYCOMB_MR1            12  // 3.1\n#define IJK_API_13_HONEYCOMB_MR2            13  // 3.2\n#define IJK_API_14_ICE_CREAM_SANDWICH       14  // 4.0\n#define IJK_API_15_ICE_CREAM_SANDWICH_MR1   15  // 4.0.3\n#define IJK_API_16_JELLY_BEAN               16  // 4.1\n#define IJK_API_17_JELLY_BEAN_MR1           17  // 4.2\n#define IJK_API_18_JELLY_BEAN_MR2           18  // 4.3\n#define IJK_API_19_KITKAT                   19  // 4.4\n#define IJK_API_20_KITKAT_WATCH             20  // 4.4W\n#define IJK_API_21_LOLLIPOP                 21  // 5.0\n#define IJK_API_22_LOLLIPOP_MR1             22  // 5.1\n#define IJK_API_23_M                        23  // 6.0\n\nJavaVM *SDL_JNI_GetJvm();\n\njint    SDL_JNI_SetupThreadEnv(JNIEnv **p_env);\nvoid    SDL_JNI_DetachThreadEnv();\n\nint      SDL_JNI_ThrowException(JNIEnv *env, const char *exception, const char* msg);\nint      SDL_JNI_ThrowIllegalStateException(JNIEnv *env, const char* msg);\n\njobject SDL_JNI_NewObjectAsGlobalRef(JNIEnv *env, jclass clazz, jmethodID methodID, ...);\n\nvoid    SDL_JNI_DeleteGlobalRefP(JNIEnv *env, jobject *obj_ptr);\nvoid    SDL_JNI_DeleteLocalRefP(JNIEnv *env, jobject *obj_ptr);\n\nint     SDL_Android_GetApiLevel();\n\n#define IJK_FIND_JAVA_CLASS(env__, var__, classsign__) \\\n    do { \\\n        jclass clazz = (*env__)->FindClass(env__, classsign__); \\\n        if (J4A_ExceptionCheck__catchAll(env) || !(clazz)) { \\\n            ALOGE(\"FindClass failed: %s\", classsign__); \\\n            return -1; \\\n        } \\\n        var__ = (*env__)->NewGlobalRef(env__, clazz); \\\n        if (J4A_ExceptionCheck__catchAll(env) || !(var__)) { \\\n            ALOGE(\"FindClass::NewGlobalRef failed: %s\", classsign__); \\\n            (*env__)->DeleteLocalRef(env__, clazz); \\\n            return -1; \\\n        } \\\n        (*env__)->DeleteLocalRef(env__, clazz); \\\n    } while(0);\n\n#define JNI_CHECK_GOTO(condition__, env__, exception__, msg__, label__) \\\n    do { \\\n        if (!(condition__)) { \\\n            if (exception__) { \\\n                SDL_JNI_ThrowException(env__, exception__, msg__); \\\n            } \\\n            goto label__; \\\n        } \\\n    }while(0)\n\n#define JNI_CHECK_RET_VOID(condition__, env__, exception__, msg__) \\\n    do { \\\n        if (!(condition__)) { \\\n            if (exception__) { \\\n                SDL_JNI_ThrowException(env__, exception__, msg__); \\\n            } \\\n            return; \\\n        } \\\n    }while(0)\n\n#define JNI_CHECK_RET(condition__, env__, exception__, msg__, ret__) \\\n    do { \\\n        if (!(condition__)) { \\\n            if (exception__) { \\\n                SDL_JNI_ThrowException(env__, exception__, msg__); \\\n            } \\\n            return ret__; \\\n        } \\\n    }while(0)\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_aout_android_audiotrack.c",
    "content": "/*****************************************************************************\n * ijksdl_aout_android_audiotrack.c\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl_aout_android_audiotrack.h\"\n\n#include <stdbool.h>\n#include <assert.h>\n#include <jni.h>\n#include \"../ijksdl_inc_internal.h\"\n#include \"../ijksdl_thread.h\"\n#include \"../ijksdl_aout_internal.h\"\n#include \"ijksdl_android_jni.h\"\n#include \"android_audiotrack.h\"\n\n#ifdef SDLTRACE\n#undef SDLTRACE\n#define SDLTRACE(...)\n//#define SDLTRACE ALOGE\n#endif\n\nstatic SDL_Class g_audiotrack_class = {\n    .name = \"AudioTrack\",\n};\n\ntypedef struct SDL_Aout_Opaque {\n    SDL_cond *wakeup_cond;\n    SDL_mutex *wakeup_mutex;\n\n    SDL_AudioSpec spec;\n    SDL_Android_AudioTrack* atrack;\n    uint8_t *buffer;\n    int buffer_size;\n\n    volatile bool need_flush;\n    volatile bool pause_on;\n    volatile bool abort_request;\n\n    volatile bool need_set_volume;\n    volatile float left_volume;\n    volatile float right_volume;\n\n    SDL_Thread *audio_tid;\n    SDL_Thread _audio_tid;\n\n    int audio_session_id;\n\n    volatile float speed;\n    volatile bool speed_changed;\n} SDL_Aout_Opaque;\n\nstatic int aout_thread_n(JNIEnv *env, SDL_Aout *aout)\n{\n    SDL_Aout_Opaque *opaque = aout->opaque;\n    SDL_Android_AudioTrack *atrack = opaque->atrack;\n    SDL_AudioCallback audio_cblk = opaque->spec.callback;\n    void *userdata = opaque->spec.userdata;\n    uint8_t *buffer = opaque->buffer;\n    int copy_size = 256;\n\n    assert(atrack);\n    assert(buffer);\n\n    SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);\n\n    if (!opaque->abort_request && !opaque->pause_on)\n        SDL_Android_AudioTrack_play(env, atrack);\n\n    while (!opaque->abort_request) {\n        SDL_LockMutex(opaque->wakeup_mutex);\n        if (!opaque->abort_request && opaque->pause_on) {\n            SDL_Android_AudioTrack_pause(env, atrack);\n            while (!opaque->abort_request && opaque->pause_on) {\n                SDL_CondWaitTimeout(opaque->wakeup_cond, opaque->wakeup_mutex, 1000);\n            }\n            if (!opaque->abort_request && !opaque->pause_on) {\n                if (opaque->need_flush) {\n                    opaque->need_flush = 0;\n                    SDL_Android_AudioTrack_flush(env, atrack);\n                }\n                SDL_Android_AudioTrack_play(env, atrack);\n            }\n        }\n        if (opaque->need_flush) {\n            opaque->need_flush = 0;\n            SDL_Android_AudioTrack_flush(env, atrack);\n        }\n        if (opaque->need_set_volume) {\n            opaque->need_set_volume = 0;\n            SDL_Android_AudioTrack_set_volume(env, atrack, opaque->left_volume, opaque->right_volume);\n        }\n        if (opaque->speed_changed) {\n            opaque->speed_changed = 0;\n            SDL_Android_AudioTrack_setSpeed(env, atrack, opaque->speed);\n        }\n        SDL_UnlockMutex(opaque->wakeup_mutex);\n\n        audio_cblk(userdata, buffer, copy_size);\n        if (opaque->need_flush) {\n            SDL_Android_AudioTrack_flush(env, atrack);\n            opaque->need_flush = false;\n        }\n\n        if (opaque->need_flush) {\n            opaque->need_flush = 0;\n            SDL_Android_AudioTrack_flush(env, atrack);\n        } else {\n            int written = SDL_Android_AudioTrack_write(env, atrack, buffer, copy_size);\n            if (written != copy_size) {\n                ALOGW(\"AudioTrack: not all data copied %d/%d\", (int)written, (int)copy_size);\n            }\n        }\n\n        // TODO: 1 if callback return -1 or 0\n    }\n\n    SDL_Android_AudioTrack_free(env, atrack);\n    return 0;\n}\n\nstatic int aout_thread(void *arg)\n{\n    SDL_Aout *aout = arg;\n    // SDL_Aout_Opaque *opaque = aout->opaque;\n    JNIEnv *env = NULL;\n\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"aout_thread: SDL_AndroidJni_SetupEnv: failed\");\n        return -1;\n    }\n\n    return aout_thread_n(env, aout);\n}\n\nstatic int aout_open_audio_n(JNIEnv *env, SDL_Aout *aout, const SDL_AudioSpec *desired, SDL_AudioSpec *obtained)\n{\n    assert(desired);\n    SDL_Aout_Opaque *opaque = aout->opaque;\n\n    opaque->spec = *desired;\n    opaque->atrack = SDL_Android_AudioTrack_new_from_sdl_spec(env, desired);\n    if (!opaque->atrack) {\n        ALOGE(\"aout_open_audio_n: failed to new AudioTrcak()\");\n        return -1;\n    }\n\n    opaque->buffer_size = SDL_Android_AudioTrack_get_min_buffer_size(opaque->atrack);\n    if (opaque->buffer_size <= 0) {\n        ALOGE(\"aout_open_audio_n: failed to getMinBufferSize()\");\n        SDL_Android_AudioTrack_free(env, opaque->atrack);\n        opaque->atrack = NULL;\n        return -1;\n    }\n\n    opaque->buffer = malloc(opaque->buffer_size);\n    if (!opaque->buffer) {\n        ALOGE(\"aout_open_audio_n: failed to allocate buffer\");\n        SDL_Android_AudioTrack_free(env, opaque->atrack);\n        opaque->atrack = NULL;\n        return -1;\n    }\n\n    if (obtained) {\n        SDL_Android_AudioTrack_get_target_spec(opaque->atrack, obtained);\n        SDLTRACE(\"audio target format fmt:0x%x, channel:0x%x\", (int)obtained->format, (int)obtained->channels);\n    }\n\n    opaque->audio_session_id = SDL_Android_AudioTrack_getAudioSessionId(env, opaque->atrack);\n    ALOGI(\"audio_session_id = %d\\n\", opaque->audio_session_id);\n\n    opaque->pause_on = 1;\n    opaque->abort_request = 0;\n    opaque->audio_tid = SDL_CreateThreadEx(&opaque->_audio_tid, aout_thread, aout, \"ff_aout_android\");\n    if (!opaque->audio_tid) {\n        ALOGE(\"aout_open_audio_n: failed to create audio thread\");\n        SDL_Android_AudioTrack_free(env, opaque->atrack);\n        opaque->atrack = NULL;\n        return -1;\n    }\n\n    return 0;\n}\n\nstatic int aout_open_audio(SDL_Aout *aout, const SDL_AudioSpec *desired, SDL_AudioSpec *obtained)\n{\n    // SDL_Aout_Opaque *opaque = aout->opaque;\n    JNIEnv *env = NULL;\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"aout_open_audio: AttachCurrentThread: failed\");\n        return -1;\n    }\n\n    return aout_open_audio_n(env, aout, desired, obtained);\n}\n\nstatic void aout_pause_audio(SDL_Aout *aout, int pause_on)\n{\n    SDL_Aout_Opaque *opaque = aout->opaque;\n\n    SDL_LockMutex(opaque->wakeup_mutex);\n    SDLTRACE(\"aout_pause_audio(%d)\", pause_on);\n    opaque->pause_on = pause_on;\n    if (!pause_on)\n        SDL_CondSignal(opaque->wakeup_cond);\n    SDL_UnlockMutex(opaque->wakeup_mutex);\n}\n\nstatic void aout_flush_audio(SDL_Aout *aout)\n{\n    SDL_Aout_Opaque *opaque = aout->opaque;\n    SDL_LockMutex(opaque->wakeup_mutex);\n    SDLTRACE(\"aout_flush_audio()\");\n    opaque->need_flush = 1;\n    SDL_CondSignal(opaque->wakeup_cond);\n    SDL_UnlockMutex(opaque->wakeup_mutex);\n}\n\nstatic void aout_set_volume(SDL_Aout *aout, float left_volume, float right_volume)\n{\n    SDL_Aout_Opaque *opaque = aout->opaque;\n    SDL_LockMutex(opaque->wakeup_mutex);\n    SDLTRACE(\"aout_flush_audio()\");\n    opaque->left_volume = left_volume;\n    opaque->right_volume = right_volume;\n    opaque->need_set_volume = 1;\n    SDL_CondSignal(opaque->wakeup_cond);\n    SDL_UnlockMutex(opaque->wakeup_mutex);\n}\n\nstatic void aout_close_audio(SDL_Aout *aout)\n{\n    SDL_Aout_Opaque *opaque = aout->opaque;\n\n    SDL_LockMutex(opaque->wakeup_mutex);\n    opaque->abort_request = true;\n    SDL_CondSignal(opaque->wakeup_cond);\n    SDL_UnlockMutex(opaque->wakeup_mutex);\n\n    SDL_WaitThread(opaque->audio_tid, NULL);\n\n    opaque->audio_tid = NULL;\n}\n\nstatic int aout_get_audio_session_id(SDL_Aout *aout)\n{\n    SDL_Aout_Opaque *opaque = aout->opaque;\n\n    return opaque->audio_session_id;\n}\n\nstatic void aout_free_l(SDL_Aout *aout)\n{\n    if (!aout)\n        return;\n\n    aout_close_audio(aout);\n\n    SDL_Aout_Opaque *opaque = aout->opaque;\n    if (opaque) {\n        free(opaque->buffer);\n        opaque->buffer = NULL;\n        opaque->buffer_size = 0;\n\n        SDL_DestroyCond(opaque->wakeup_cond);\n        SDL_DestroyMutex(opaque->wakeup_mutex);\n    }\n\n    SDL_Aout_FreeInternal(aout);\n}\n\nstatic void func_set_playback_rate(SDL_Aout *aout, float speed)\n{\n    if (!aout)\n        return;\n\n    SDL_Aout_Opaque *opaque = aout->opaque;\n    SDL_LockMutex(opaque->wakeup_mutex);\n    SDLTRACE(\"%s %f\", __func__, (double)speed);\n    opaque->speed = speed;\n    opaque->speed_changed = 1;\n    SDL_CondSignal(opaque->wakeup_cond);\n    SDL_UnlockMutex(opaque->wakeup_mutex);\n}\n\nSDL_Aout *SDL_AoutAndroid_CreateForAudioTrack()\n{\n    SDL_Aout *aout = SDL_Aout_CreateInternal(sizeof(SDL_Aout_Opaque));\n    if (!aout)\n        return NULL;\n\n    SDL_Aout_Opaque *opaque = aout->opaque;\n    opaque->wakeup_cond  = SDL_CreateCond();\n    opaque->wakeup_mutex = SDL_CreateMutex();\n    opaque->speed        = 1.0f;\n\n    aout->opaque_class = &g_audiotrack_class;\n    aout->free_l       = aout_free_l;\n    aout->open_audio   = aout_open_audio;\n    aout->pause_audio  = aout_pause_audio;\n    aout->flush_audio  = aout_flush_audio;\n    aout->set_volume   = aout_set_volume;\n    aout->close_audio  = aout_close_audio;\n    aout->func_get_audio_session_id = aout_get_audio_session_id;\n    aout->func_set_playback_rate    = func_set_playback_rate;\n\n    return aout;\n}\n\nbool SDL_AoutAndroid_IsObjectOfAudioTrack(SDL_Aout *aout)\n{\n    if (aout)\n        return false;\n\n    return aout->opaque_class == &g_audiotrack_class;\n}\n\nvoid SDL_Init_AoutAndroid(JNIEnv *env)\n{\n\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_aout_android_audiotrack.h",
    "content": "/*****************************************************************************\n * ijksdl_aout_android_audiotrack.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL_ANDROID__IJKSDL_AOUT_ANDROID_AUDIOTRACK_H\n#define IJKSDL_ANDROID__IJKSDL_AOUT_ANDROID_AUDIOTRACK_H\n\n#include \"../ijksdl_aout.h\"\n\nSDL_Aout *SDL_AoutAndroid_CreateForAudioTrack();\nbool      SDL_AoutAndroid_IsObjectOfAudioTrack(SDL_Aout *aout);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_aout_android_opensles.c",
    "content": "/*****************************************************************************\n * ijksdl_aout_android_opensles.c\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include <stdbool.h>\n#include <assert.h>\n#include <math.h>\n#include <inttypes.h>\n#include <jni.h>\n#include <SLES/OpenSLES.h>\n#include <SLES/OpenSLES_Android.h>\n#include \"../ijksdl_inc_internal.h\"\n#include \"../ijksdl_thread.h\"\n#include \"../ijksdl_aout_internal.h\"\n#include \"ijksdl_android_jni.h\"\n#include \"android_audiotrack.h\"\n\n#ifdef SDLTRACE\n#undef SDLTRACE\n#define SDLTRACE(...)\n//#define SDLTRACE ALOGW\n#endif\n\n#define OPENSLES_BUFFERS 255 /* maximum number of buffers */\n#define OPENSLES_BUFLEN  10 /* ms */\n\nstatic SDL_Class g_opensles_class = {\n    .name = \"OpenSLES\",\n};\n\ntypedef struct SDL_Aout_Opaque {\n    SDL_cond   *wakeup_cond;\n    SDL_mutex  *wakeup_mutex;\n\n    SDL_Thread *audio_tid;\n    SDL_Thread _audio_tid;\n\n    SDL_AudioSpec    spec;\n    SLDataFormat_PCM format_pcm;\n    int              bytes_per_frame;\n    int              milli_per_buffer;\n    int              frames_per_buffer;\n    int              bytes_per_buffer;\n\n    SLObjectItf                     slObject;\n    SLEngineItf                     slEngine;\n\n    SLObjectItf                     slOutputMixObject;\n\n    SLObjectItf                     slPlayerObject;\n    SLAndroidSimpleBufferQueueItf   slBufferQueueItf;\n    SLVolumeItf                     slVolumeItf;\n    SLPlayItf                       slPlayItf;\n\n    volatile bool  need_set_volume;\n    volatile float left_volume;\n    volatile float right_volume;\n\n    volatile bool  abort_request;\n    volatile bool  pause_on;\n    volatile bool  need_flush;\n    volatile bool  is_running;\n\n    uint8_t       *buffer;\n    size_t         buffer_capacity;\n} SDL_Aout_Opaque;\n\n#define CHECK_OPENSL_ERROR(ret__, ...) \\\n    do { \\\n    \tif ((ret__) != SL_RESULT_SUCCESS) \\\n    \t{ \\\n    \t\tALOGE(__VA_ARGS__); \\\n    \t\tgoto fail; \\\n    \t} \\\n    } while (0)\n\n#define CHECK_COND_ERROR(cond__, ...) \\\n    do { \\\n        if (!(cond__)) \\\n        { \\\n            ALOGE(__VA_ARGS__); \\\n            goto fail; \\\n        } \\\n    } while (0)\n\nstatic inline SLmillibel android_amplification_to_sles(float volumeLevel) {\n    // FIXME use the FX Framework conversions\n    if (volumeLevel < 0.00000001)\n        return SL_MILLIBEL_MIN;\n\n    SLmillibel mb = lroundf(2000.f * log10f(volumeLevel));\n    if (mb < SL_MILLIBEL_MIN)\n        mb = SL_MILLIBEL_MIN;\n    else if (mb > 0)\n        mb = 0; /* maximum supported level could be higher: GetMaxVolumeLevel */\n    return mb;\n}\n\nstatic int aout_thread_n(SDL_Aout *aout)\n{\n    SDL_Aout_Opaque               *opaque           = aout->opaque;\n    SLPlayItf                      slPlayItf        = opaque->slPlayItf;\n    SLAndroidSimpleBufferQueueItf  slBufferQueueItf = opaque->slBufferQueueItf;\n    SLVolumeItf                    slVolumeItf      = opaque->slVolumeItf;\n    SDL_AudioCallback              audio_cblk       = opaque->spec.callback;\n    void                          *userdata         = opaque->spec.userdata;\n    uint8_t                       *next_buffer      = NULL;\n    int                            next_buffer_index = 0;\n    size_t                         bytes_per_buffer = opaque->bytes_per_buffer;\n\n    SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);\n\n    if (!opaque->abort_request && !opaque->pause_on)\n        (*slPlayItf)->SetPlayState(slPlayItf, SL_PLAYSTATE_PLAYING);\n\n    while (!opaque->abort_request) {\n        SLAndroidSimpleBufferQueueState slState = {0};\n\n        SLresult slRet = (*slBufferQueueItf)->GetState(slBufferQueueItf, &slState);\n        if (slRet != SL_RESULT_SUCCESS) {\n            ALOGE(\"%s: slBufferQueueItf->GetState() failed\\n\", __func__);\n            SDL_UnlockMutex(opaque->wakeup_mutex);\n        }\n\n        SDL_LockMutex(opaque->wakeup_mutex);\n        if (!opaque->abort_request && (opaque->pause_on || slState.count >= OPENSLES_BUFFERS)) {\n            while (!opaque->abort_request && (opaque->pause_on || slState.count >= OPENSLES_BUFFERS)) {\n                if (!opaque->pause_on) {\n                    (*slPlayItf)->SetPlayState(slPlayItf, SL_PLAYSTATE_PLAYING);\n                }\n                SDL_CondWaitTimeout(opaque->wakeup_cond, opaque->wakeup_mutex, 1000);\n                SLresult slRet = (*slBufferQueueItf)->GetState(slBufferQueueItf, &slState);\n                if (slRet != SL_RESULT_SUCCESS) {\n                    ALOGE(\"%s: slBufferQueueItf->GetState() failed\\n\", __func__);\n                    SDL_UnlockMutex(opaque->wakeup_mutex);\n                }\n\n                if (opaque->pause_on)\n                    (*slPlayItf)->SetPlayState(slPlayItf, SL_PLAYSTATE_PAUSED);\n            }\n            if (!opaque->abort_request && !opaque->pause_on) {\n                (*slPlayItf)->SetPlayState(slPlayItf, SL_PLAYSTATE_PLAYING);\n            }\n        }\n        if (opaque->need_flush) {\n            opaque->need_flush = 0;\n            (*slBufferQueueItf)->Clear(slBufferQueueItf);\n        }\n#if 0\n        if (opaque->need_set_volume) {\n            opaque->need_set_volume = 0;\n            // FIXME: set volume here\n        }\n#endif\n        if (opaque->need_set_volume) {\n            opaque->need_set_volume = 0;\n            SLmillibel level = android_amplification_to_sles((opaque->left_volume + opaque->right_volume) / 2);\n            ALOGI(\"slVolumeItf->SetVolumeLevel((%f, %f) -> %d)\\n\", opaque->left_volume, opaque->right_volume, (int)level);\n            slRet = (*slVolumeItf)->SetVolumeLevel(slVolumeItf, level);\n            if (slRet != SL_RESULT_SUCCESS) {\n                ALOGE(\"slVolumeItf->SetVolumeLevel failed %d\\n\", (int)slRet);\n                // just ignore error\n            }\n        }\n        SDL_UnlockMutex(opaque->wakeup_mutex);\n\n        next_buffer = opaque->buffer + next_buffer_index * bytes_per_buffer;\n        next_buffer_index = (next_buffer_index + 1) % OPENSLES_BUFFERS;\n        audio_cblk(userdata, next_buffer, bytes_per_buffer);\n        if (opaque->need_flush) {\n            (*slBufferQueueItf)->Clear(slBufferQueueItf);\n            opaque->need_flush = false;\n        }\n\n        if (opaque->need_flush) {\n            ALOGE(\"flush\");\n            opaque->need_flush = 0;\n            (*slBufferQueueItf)->Clear(slBufferQueueItf);\n        } else {\n            slRet = (*slBufferQueueItf)->Enqueue(slBufferQueueItf, next_buffer, bytes_per_buffer);\n            if (slRet == SL_RESULT_SUCCESS) {\n                // do nothing\n            } else if (slRet == SL_RESULT_BUFFER_INSUFFICIENT) {\n                // don't retry, just pass through\n                ALOGE(\"SL_RESULT_BUFFER_INSUFFICIENT\\n\");\n            } else {\n                ALOGE(\"slBufferQueueItf->Enqueue() = %d\\n\", (int)slRet);\n                break;\n            }\n        }\n\n        // TODO: 1 if callback return -1 or 0\n    }\n\n    return 0;\n}\n\nstatic int aout_thread(void *arg)\n{\n    return aout_thread_n(arg);\n}\n\nstatic void aout_opensles_callback(SLAndroidSimpleBufferQueueItf caller, void *pContext)\n{\n    SDLTRACE(\"%s\\n\", __func__);\n    SDL_Aout        *aout   = pContext;\n    SDL_Aout_Opaque *opaque = aout->opaque;\n\n    if (opaque) {\n        SDL_LockMutex(opaque->wakeup_mutex);\n        opaque->is_running = true;\n        SDL_CondSignal(opaque->wakeup_cond);\n        SDL_UnlockMutex(opaque->wakeup_mutex);\n    }\n}\n\nstatic void aout_close_audio(SDL_Aout *aout)\n{\n    SDLTRACE(\"aout_close_audio()\\n\");\n    SDL_Aout_Opaque *opaque = aout->opaque;\n    if (!opaque)\n        return;\n\n    SDL_LockMutex(opaque->wakeup_mutex);\n    opaque->abort_request = true;\n    SDL_CondSignal(opaque->wakeup_cond);\n    SDL_UnlockMutex(opaque->wakeup_mutex);\n\n    SDL_WaitThread(opaque->audio_tid, NULL);\n    opaque->audio_tid = NULL;\n\n    if (opaque->slPlayItf)\n        (*opaque->slPlayItf)->SetPlayState(opaque->slPlayItf, SL_PLAYSTATE_STOPPED);\n    if (opaque->slBufferQueueItf)\n        (*opaque->slBufferQueueItf)->Clear(opaque->slBufferQueueItf);\n\n    if (opaque->slBufferQueueItf)\n        opaque->slBufferQueueItf = NULL;\n    if (opaque->slVolumeItf)\n        opaque->slVolumeItf      = NULL;\n    if (opaque->slPlayItf)\n        opaque->slPlayItf        = NULL;\n\n    if (opaque->slPlayerObject) {\n        (*opaque->slPlayerObject)->Destroy(opaque->slPlayerObject);\n        opaque->slPlayerObject = NULL;\n    }\n\n    freep((void **)&opaque->buffer);\n}\n\nstatic void aout_free_l(SDL_Aout *aout)\n{\n    SDLTRACE(\"%s\\n\", __func__);\n    if (!aout)\n        return;\n\n    aout_close_audio(aout);\n\n    SDL_Aout_Opaque *opaque = aout->opaque;\n\n    if (opaque->slOutputMixObject) {\n        (*opaque->slOutputMixObject)->Destroy(opaque->slOutputMixObject);\n        opaque->slOutputMixObject = NULL;\n    }\n\n    opaque->slEngine = NULL;\n    if (opaque->slObject) {\n        (*opaque->slObject)->Destroy(opaque->slObject);\n        opaque->slObject = NULL;\n    }\n\n    SDL_DestroyCondP(&opaque->wakeup_cond);\n    SDL_DestroyMutexP(&opaque->wakeup_mutex);\n\n    SDL_Aout_FreeInternal(aout);\n}\n\nstatic int aout_open_audio(SDL_Aout *aout, const SDL_AudioSpec *desired, SDL_AudioSpec *obtained)\n{\n    SDLTRACE(\"%s\\n\", __func__);\n    assert(desired);\n    SDLTRACE(\"aout_open_audio()\\n\");\n    SDL_Aout_Opaque  *opaque     = aout->opaque;\n    SLEngineItf       slEngine   = opaque->slEngine;\n    SLDataFormat_PCM *format_pcm = &opaque->format_pcm;\n    int               ret = 0;\n\n    opaque->spec = *desired;\n\n    // config audio src\n    SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {\n        SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,\n        OPENSLES_BUFFERS\n    };\n\n    int native_sample_rate = audiotrack_get_native_output_sample_rate(NULL);\n    ALOGI(\"OpenSL-ES: native sample rate %d Hz\\n\", native_sample_rate);\n\n    CHECK_COND_ERROR((desired->format == AUDIO_S16SYS), \"%s: not AUDIO_S16SYS\", __func__);\n    CHECK_COND_ERROR((desired->channels == 2 || desired->channels == 1), \"%s: not 1,2 channel\", __func__);\n    CHECK_COND_ERROR((desired->freq >= 8000 && desired->freq <= 48000), \"%s: unsupport freq %d Hz\", __func__, desired->freq);\n    if (SDL_Android_GetApiLevel() < IJK_API_21_LOLLIPOP &&\n        native_sample_rate > 0 &&\n        desired->freq < native_sample_rate) {\n        // Don't try to play back a sample rate higher than the native one,\n        // since OpenSL ES will try to use the fast path, which AudioFlinger\n        // will reject (fast path can't do resampling), and will end up with\n        // too small buffers for the resampling. See http://b.android.com/59453\n        // for details. This bug is still present in 4.4. If it is fixed later\n        // this workaround could be made conditional.\n        //\n        // by VLC/android_opensles.c\n        ALOGW(\"OpenSL-ES: force resample %lu to native sample rate %d\\n\",\n              (unsigned long) format_pcm->samplesPerSec / 1000,\n              (int) native_sample_rate);\n        format_pcm->samplesPerSec = native_sample_rate * 1000;\n    }\n\n    format_pcm->formatType       = SL_DATAFORMAT_PCM;\n    format_pcm->numChannels      = desired->channels;\n    format_pcm->samplesPerSec    = desired->freq * 1000; // milli Hz\n    // format_pcm->numChannels      = 2;\n    // format_pcm->samplesPerSec    = SL_SAMPLINGRATE_44_1;\n\n    format_pcm->bitsPerSample    = SL_PCMSAMPLEFORMAT_FIXED_16;\n    format_pcm->containerSize    = SL_PCMSAMPLEFORMAT_FIXED_16;\n    switch (desired->channels) {\n    case 2:\n        format_pcm->channelMask  = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;\n        break;\n    case 1:\n        format_pcm->channelMask  = SL_SPEAKER_FRONT_CENTER;\n        break;\n    default:\n        ALOGE(\"%s, invalid channel %d\", __func__, desired->channels);\n        goto fail;\n    }\n    format_pcm->endianness       = SL_BYTEORDER_LITTLEENDIAN;\n\n    SLDataSource audio_source = {&loc_bufq, format_pcm};\n\n    // config audio sink\n    SLDataLocator_OutputMix loc_outmix = {\n        SL_DATALOCATOR_OUTPUTMIX,\n        opaque->slOutputMixObject\n    };\n    SLDataSink audio_sink = {&loc_outmix, NULL};\n\n    SLObjectItf slPlayerObject = NULL;\n    const SLInterfaceID ids2[] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_VOLUME, SL_IID_PLAY };\n    static const SLboolean req2[] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };\n    ret = (*slEngine)->CreateAudioPlayer(slEngine, &slPlayerObject, &audio_source,\n                                &audio_sink, sizeof(ids2) / sizeof(*ids2),\n                                ids2, req2);\n    CHECK_OPENSL_ERROR(ret, \"%s: slEngine->CreateAudioPlayer() failed\", __func__);\n    opaque->slPlayerObject = slPlayerObject;\n\n    ret = (*slPlayerObject)->Realize(slPlayerObject, SL_BOOLEAN_FALSE);\n    CHECK_OPENSL_ERROR(ret, \"%s: slPlayerObject->Realize() failed\", __func__);\n\n    ret = (*slPlayerObject)->GetInterface(slPlayerObject, SL_IID_PLAY, &opaque->slPlayItf);\n    CHECK_OPENSL_ERROR(ret, \"%s: slPlayerObject->GetInterface(SL_IID_PLAY) failed\", __func__);\n\n    ret = (*slPlayerObject)->GetInterface(slPlayerObject, SL_IID_VOLUME, &opaque->slVolumeItf);\n    CHECK_OPENSL_ERROR(ret, \"%s: slPlayerObject->GetInterface(SL_IID_VOLUME) failed\", __func__);\n\n    ret = (*slPlayerObject)->GetInterface(slPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &opaque->slBufferQueueItf);\n    CHECK_OPENSL_ERROR(ret, \"%s: slPlayerObject->GetInterface(SL_IID_ANDROIDSIMPLEBUFFERQUEUE) failed\", __func__);\n\n    ret = (*opaque->slBufferQueueItf)->RegisterCallback(opaque->slBufferQueueItf, aout_opensles_callback, (void*)aout);\n    CHECK_OPENSL_ERROR(ret, \"%s: slBufferQueueItf->RegisterCallback() failed\", __func__);\n\n    // set the player's state to playing\n    // ret = (*opaque->slPlayItf)->SetPlayState(opaque->slPlayItf, SL_PLAYSTATE_PLAYING);\n    // CHECK_OPENSL_ERROR(ret, \"%s: slBufferQueueItf->slPlayItf() failed\", __func__);\n\n    opaque->bytes_per_frame   = format_pcm->numChannels * format_pcm->bitsPerSample / 8;\n    opaque->milli_per_buffer  = OPENSLES_BUFLEN;\n    opaque->frames_per_buffer = opaque->milli_per_buffer * format_pcm->samplesPerSec / 1000000; // samplesPerSec is in milli\n    opaque->bytes_per_buffer  = opaque->bytes_per_frame * opaque->frames_per_buffer;\n    opaque->buffer_capacity   = OPENSLES_BUFFERS * opaque->bytes_per_buffer;\n    ALOGI(\"OpenSL-ES: bytes_per_frame  = %d bytes\\n\",  (int)opaque->bytes_per_frame);\n    ALOGI(\"OpenSL-ES: milli_per_buffer = %d ms\\n\",     (int)opaque->milli_per_buffer);\n    ALOGI(\"OpenSL-ES: frame_per_buffer = %d frames\\n\", (int)opaque->frames_per_buffer);\n    ALOGI(\"OpenSL-ES: bytes_per_buffer = %d bytes\\n\",  (int)opaque->bytes_per_buffer);\n    ALOGI(\"OpenSL-ES: buffer_capacity  = %d bytes\\n\",  (int)opaque->buffer_capacity);\n    opaque->buffer          = malloc(opaque->buffer_capacity);\n    CHECK_COND_ERROR(opaque->buffer, \"%s: failed to alloc buffer %d\\n\", __func__, (int)opaque->buffer_capacity);\n\n    // (*opaque->slPlayItf)->SetPositionUpdatePeriod(opaque->slPlayItf, 1000);\n\n    // enqueue empty buffer to start play\n    memset(opaque->buffer, 0, opaque->buffer_capacity);\n    for(int i = 0; i < OPENSLES_BUFFERS; ++i) {\n        ret = (*opaque->slBufferQueueItf)->Enqueue(opaque->slBufferQueueItf, opaque->buffer + i * opaque->bytes_per_buffer, opaque->bytes_per_buffer);\n        CHECK_OPENSL_ERROR(ret, \"%s: slBufferQueueItf->Enqueue(000...) failed\", __func__);\n    }\n\n    opaque->pause_on = 1;\n    opaque->abort_request = 0;\n    opaque->audio_tid = SDL_CreateThreadEx(&opaque->_audio_tid, aout_thread, aout, \"ff_aout_opensles\");\n    CHECK_COND_ERROR(opaque->audio_tid, \"%s: failed to SDL_CreateThreadEx\", __func__);\n\n    if (obtained) {\n        *obtained      = *desired;\n        obtained->size = opaque->buffer_capacity;\n        obtained->freq = format_pcm->samplesPerSec / 1000;\n    }\n\n    return opaque->buffer_capacity;\nfail:\n    aout_close_audio(aout);\n    return -1;\n}\n\nstatic void aout_pause_audio(SDL_Aout *aout, int pause_on)\n{\n    SDL_Aout_Opaque *opaque = aout->opaque;\n\n    SDL_LockMutex(opaque->wakeup_mutex);\n    SDLTRACE(\"aout_pause_audio(%d)\", pause_on);\n    opaque->pause_on = pause_on;\n    if (!pause_on)\n        SDL_CondSignal(opaque->wakeup_cond);\n    SDL_UnlockMutex(opaque->wakeup_mutex);\n}\n\nstatic void aout_flush_audio(SDL_Aout *aout)\n{\n    SDL_Aout_Opaque *opaque = aout->opaque;\n    SDL_LockMutex(opaque->wakeup_mutex);\n    SDLTRACE(\"aout_flush_audio()\");\n    opaque->need_flush = 1;\n    SDL_CondSignal(opaque->wakeup_cond);\n    SDL_UnlockMutex(opaque->wakeup_mutex);\n}\n\nstatic void aout_set_volume(SDL_Aout *aout, float left_volume, float right_volume)\n{\n    SDL_Aout_Opaque *opaque = aout->opaque;\n    SDL_LockMutex(opaque->wakeup_mutex);\n    ALOGI(\"aout_set_volume(%f, %f)\", left_volume, right_volume);\n    opaque->left_volume = left_volume;\n    opaque->right_volume = right_volume;\n    opaque->need_set_volume = 1;\n    SDL_CondSignal(opaque->wakeup_cond);\n    SDL_UnlockMutex(opaque->wakeup_mutex);\n}\n\nstatic double aout_get_latency_seconds(SDL_Aout *aout)\n{\n    SDL_Aout_Opaque *opaque = aout->opaque;\n\n    SLAndroidSimpleBufferQueueState state = {0};\n    SLresult slRet = (*opaque->slBufferQueueItf)->GetState(opaque->slBufferQueueItf, &state);\n    if (slRet != SL_RESULT_SUCCESS) {\n        ALOGE(\"%s failed\\n\", __func__);\n        return ((double)opaque->milli_per_buffer) * OPENSLES_BUFFERS / 1000;\n    }\n\n    // assume there is always a buffer in coping\n    double latency = ((double)opaque->milli_per_buffer) * state.count / 1000;\n    return latency;\n}\n\nSDL_Aout *SDL_AoutAndroid_CreateForOpenSLES()\n{\n    SDLTRACE(\"%s\\n\", __func__);\n    SDL_Aout *aout = SDL_Aout_CreateInternal(sizeof(SDL_Aout_Opaque));\n    if (!aout)\n        return NULL;\n\n    SDL_Aout_Opaque *opaque = aout->opaque;\n    opaque->wakeup_cond = SDL_CreateCond();\n    opaque->wakeup_mutex = SDL_CreateMutex();\n\n    int ret = 0;\n\n    SLObjectItf slObject = NULL;\n    ret = slCreateEngine(&slObject, 0, NULL, 0, NULL, NULL);\n    CHECK_OPENSL_ERROR(ret, \"%s: slCreateEngine() failed\", __func__);\n    opaque->slObject = slObject;\n\n    ret = (*slObject)->Realize(slObject, SL_BOOLEAN_FALSE);\n    CHECK_OPENSL_ERROR(ret, \"%s: slObject->Realize() failed\", __func__);\n\n    SLEngineItf slEngine = NULL;\n    ret = (*slObject)->GetInterface(slObject, SL_IID_ENGINE, &slEngine);\n    CHECK_OPENSL_ERROR(ret, \"%s: slObject->GetInterface() failed\", __func__);\n    opaque->slEngine = slEngine;\n\n    SLObjectItf slOutputMixObject = NULL;\n    const SLInterfaceID ids1[] = {SL_IID_VOLUME};\n    const SLboolean req1[] = {SL_BOOLEAN_FALSE};\n    ret = (*slEngine)->CreateOutputMix(slEngine, &slOutputMixObject, 1, ids1, req1);\n    CHECK_OPENSL_ERROR(ret, \"%s: slEngine->CreateOutputMix() failed\", __func__);\n    opaque->slOutputMixObject = slOutputMixObject;\n\n    ret = (*slOutputMixObject)->Realize(slOutputMixObject, SL_BOOLEAN_FALSE);\n    CHECK_OPENSL_ERROR(ret, \"%s: slOutputMixObject->Realize() failed\", __func__);\n\n    aout->free_l       = aout_free_l;\n    aout->opaque_class = &g_opensles_class;\n    aout->open_audio   = aout_open_audio;\n    aout->pause_audio  = aout_pause_audio;\n    aout->flush_audio  = aout_flush_audio;\n    aout->close_audio  = aout_close_audio;\n    aout->set_volume   = aout_set_volume;\n    aout->func_get_latency_seconds = aout_get_latency_seconds;\n\n    return aout;\nfail:\n    aout_free_l(aout);\n    return NULL;\n}\n\nbool SDL_AoutAndroid_IsObjectOfOpenSLES(SDL_Aout *aout)\n{\n    if (aout)\n        return false;\n\n    return aout->opaque_class == &g_opensles_class;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_aout_android_opensles.h",
    "content": "/*****************************************************************************\n * ijksdl_aout_android_opensles.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL_ANDROID__IJKSDL_AOUT_ANDROID_OPENSLES_H\n#define IJKSDL_ANDROID__IJKSDL_AOUT_ANDROID_OPENSLES_H\n\n#include \"../ijksdl_aout.h\"\n\nSDL_Aout *SDL_AoutAndroid_CreateForOpenSLES();\nbool      SDL_AoutAndroid_IsObjectOfOpenSLES(SDL_Aout *aout);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_codec_android_mediacodec.c",
    "content": "/*****************************************************************************\n * ijksdl_codec_android_mediacodec.c\n *****************************************************************************\n *\n * Copyright (c) 2014 Bilibili\n * copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl_codec_android_mediacodec.h\"\n#include <assert.h>\n#include \"ijksdl/ijksdl_log.h\"\n#include \"ijksdl_codec_android_mediacodec_internal.h\"\n\nstatic volatile int g_amediacodec_object_serial;\n\ntypedef struct SDL_AMediaCodec_Common\n{\n    SDL_AMediaCodec_FakeFifo fake_fifo;\n} SDL_AMediaCodec_Common;\n\nint SDL_AMediaCodec_create_object_serial()\n{\n    int object_serial = __sync_add_and_fetch(&g_amediacodec_object_serial, 1);\n    if (object_serial == 0)\n        object_serial = __sync_add_and_fetch(&g_amediacodec_object_serial, 1);\n    return object_serial;\n}\n\n// FIXME: release SDL_AMediaCodec\nsdl_amedia_status_t SDL_AMediaCodec_delete(SDL_AMediaCodec* acodec)\n{\n    if (!acodec)\n        return SDL_AMEDIA_OK;\n\n    assert(acodec->func_delete);\n    return acodec->func_delete(acodec);\n}\n\nsdl_amedia_status_t SDL_AMediaCodec_deleteP(SDL_AMediaCodec** acodec)\n{\n    if (!acodec)\n        return SDL_AMEDIA_OK;\n    sdl_amedia_status_t ret = SDL_AMediaCodec_delete(*acodec);\n    *acodec = NULL;\n    return ret;\n}\n\nsdl_amedia_status_t SDL_AMediaCodec_configure(\n    SDL_AMediaCodec* acodec,\n    const SDL_AMediaFormat* aformat,\n    ANativeWindow* surface,\n    SDL_AMediaCrypto *crypto,\n    uint32_t flags)\n{\n    assert(acodec->func_configure);\n    sdl_amedia_status_t ret = acodec->func_configure(acodec, aformat, surface, crypto, flags);\n    acodec->is_configured = true;\n    acodec->is_started    = false;\n    return ret;\n}\n\nsdl_amedia_status_t SDL_AMediaCodec_configure_surface(\n    JNIEnv*env,\n    SDL_AMediaCodec* acodec,\n    const SDL_AMediaFormat* aformat,\n    jobject android_surface,\n    SDL_AMediaCrypto *crypto,\n    uint32_t flags)\n{\n    assert(acodec->func_configure_surface);\n    sdl_amedia_status_t ret = acodec->func_configure_surface(env, acodec, aformat, android_surface, crypto, flags);\n    acodec->is_configured = true;\n    acodec->is_started    = false;\n    return ret;\n}\n\nvoid SDL_AMediaCodec_increaseReference(SDL_AMediaCodec *acodec)\n{\n    assert(acodec);\n    int ref_count = __sync_add_and_fetch(&acodec->ref_count, 1);\n    ALOGD(\"%s(): ref=%d\\n\", __func__, ref_count);\n}\n\nvoid SDL_AMediaCodec_decreaseReference(SDL_AMediaCodec *acodec)\n{\n    if (!acodec)\n        return;\n\n    int ref_count = __sync_sub_and_fetch(&acodec->ref_count, 1);\n    ALOGD(\"%s(): ref=%d\\n\", __func__, ref_count);\n    if (ref_count == 0) {\n        if (SDL_AMediaCodec_isStarted(acodec)) {\n            SDL_AMediaCodec_stop(acodec);\n        }\n        SDL_AMediaCodec_delete(acodec);\n    }\n}\n\nvoid SDL_AMediaCodec_decreaseReferenceP(SDL_AMediaCodec **acodec)\n{\n    if (!acodec)\n        return;\n\n    SDL_AMediaCodec_decreaseReference(*acodec);\n    *acodec = NULL;\n}\n\nbool SDL_AMediaCodec_isConfigured(SDL_AMediaCodec *acodec)\n{\n    return acodec->is_configured;\n}\n\nbool SDL_AMediaCodec_isStarted(SDL_AMediaCodec *acodec)\n{\n    return acodec->is_started;\n}\n\nsdl_amedia_status_t SDL_AMediaCodec_start(SDL_AMediaCodec* acodec)\n{\n    assert(acodec->func_start);\n    sdl_amedia_status_t amc_ret = acodec->func_start(acodec);\n    if (amc_ret == SDL_AMEDIA_OK) {\n        acodec->is_started = true;\n    }\n    return amc_ret;\n}\n\nsdl_amedia_status_t SDL_AMediaCodec_stop(SDL_AMediaCodec* acodec)\n{\n    assert(acodec->func_stop);\n    acodec->is_started = false;\n    SDL_AMediaCodec_FakeFifo_abort(&acodec->common->fake_fifo);\n    return acodec->func_stop(acodec);\n}\n\nsdl_amedia_status_t SDL_AMediaCodec_flush(SDL_AMediaCodec* acodec)\n{\n    assert(acodec->func_flush);\n    SDL_AMediaCodec_FakeFifo_flush(&acodec->common->fake_fifo);\n    return acodec->func_flush(acodec);\n}\n\nssize_t SDL_AMediaCodec_writeInputData(SDL_AMediaCodec* acodec, size_t idx, const uint8_t *data, size_t size)\n{\n    assert(acodec->func_writeInputData);\n    return acodec->func_writeInputData(acodec, idx, data, size);\n}\n\nssize_t SDL_AMediaCodec_dequeueInputBuffer(SDL_AMediaCodec* acodec, int64_t timeoutUs)\n{\n    assert(acodec->func_dequeueInputBuffer);\n    return acodec->func_dequeueInputBuffer(acodec, timeoutUs);\n}\n\nsdl_amedia_status_t SDL_AMediaCodec_queueInputBuffer(SDL_AMediaCodec* acodec, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags)\n{\n    assert(acodec->func_queueInputBuffer);\n    if (flags & AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME) {\n        return SDL_AMediaCodec_FakeFifo_queueInputBuffer(&acodec->common->fake_fifo, idx, offset, size, time, flags);\n    }\n\n    return acodec->func_queueInputBuffer(acodec, idx, offset, size, time, flags);\n}\n\nssize_t SDL_AMediaCodec_dequeueOutputBuffer(SDL_AMediaCodec* acodec, SDL_AMediaCodecBufferInfo *info, int64_t timeoutUs)\n{\n    assert(acodec->func_dequeueOutputBuffer);\n    return acodec->func_dequeueOutputBuffer(acodec, info, timeoutUs);\n}\n\nSDL_AMediaFormat* SDL_AMediaCodec_getOutputFormat(SDL_AMediaCodec* acodec)\n{\n    assert(acodec->func_getOutputFormat);\n    return acodec->func_getOutputFormat(acodec);\n}\n\nsdl_amedia_status_t SDL_AMediaCodec_releaseOutputBuffer(SDL_AMediaCodec* acodec, size_t idx, bool render)\n{\n    assert(acodec->func_releaseOutputBuffer);\n    return acodec->func_releaseOutputBuffer(acodec, idx, render);\n}\n\nbool SDL_AMediaCodec_isInputBuffersValid(SDL_AMediaCodec* acodec)\n{\n    assert(acodec->func_isInputBuffersValid);\n    return acodec->func_isInputBuffersValid(acodec);\n}\n\nint SDL_AMediaCodec_getSerial(SDL_AMediaCodec* acodec)\n{\n    if (!acodec)\n        return 0;\n    return acodec->object_serial;\n}\n\nbool SDL_AMediaCodec_isSameSerial(SDL_AMediaCodec* acodec, int acodec_serial)\n{\n    if (acodec == NULL)\n        return false;\n    return acodec->object_serial == acodec_serial;\n}\n\nSDL_AMediaCodec *SDL_AMediaCodec_CreateInternal(size_t opaque_size)\n{\n    SDL_AMediaCodec *acodec = (SDL_AMediaCodec*) mallocz(sizeof(SDL_AMediaCodec));\n    if (!acodec)\n        return NULL;\n\n    acodec->mutex = SDL_CreateMutex();\n    if (acodec->mutex == NULL)\n        goto fail;\n\n    acodec->opaque = mallocz(opaque_size);\n    if (!acodec->opaque)\n        goto fail;\n\n    acodec->common = mallocz(sizeof(SDL_AMediaCodec_Common));\n    if (!acodec->common)\n        goto fail;\n\n    SDL_AMediaCodec_FakeFifo_init(&acodec->common->fake_fifo);\n\n    return acodec;\nfail:\n    SDL_AMediaCodec_FreeInternal(acodec);\n    return NULL;\n}\n\nvoid SDL_AMediaCodec_FreeInternal(SDL_AMediaCodec *acodec)\n{\n    if (!acodec)\n        return;\n\n    if (acodec->common) {\n        SDL_AMediaCodec_FakeFifo_destroy(&acodec->common->fake_fifo);\n        free(acodec->common);\n    }\n\n    free(acodec->opaque);\n\n    if (acodec->mutex)\n        SDL_DestroyMutexP(&acodec->mutex);\n\n    memset(acodec, 0, sizeof(SDL_AMediaCodec));\n    free(acodec);\n}\n\nvoid SDL_AMediaCodecFake_abort(SDL_AMediaCodec* acodec)\n{\n    SDL_AMediaCodec_FakeFifo_abort(&acodec->common->fake_fifo);\n}\n\nvoid SDL_AMediaCodecFake_flushFakeFrames(SDL_AMediaCodec* acodec)\n{\n    SDL_AMediaCodec_FakeFifo_flush(&acodec->common->fake_fifo);\n}\n\nsdl_amedia_status_t SDL_AMediaCodecFake_queueFakeFrame(SDL_AMediaCodec* acodec, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags)\n{\n    return SDL_AMediaCodec_FakeFifo_queueInputBuffer(&acodec->common->fake_fifo, idx, offset, size, time, flags);\n}\n\nssize_t SDL_AMediaCodecFake_dequeueOutputBuffer(SDL_AMediaCodec* acodec, SDL_AMediaCodecBufferInfo *info, int64_t timeoutUs)\n{    \n    if (SDL_AMediaCodec_FakeFifo_size(&acodec->common->fake_fifo) > 0) {\n        ssize_t ret = SDL_AMediaCodec_FakeFifo_dequeueOutputBuffer(&acodec->common->fake_fifo, info, 0);\n        if (ret >= 0)\n            return ret;\n    }\n\n    assert(acodec->func_dequeueOutputBuffer);\n    return acodec->func_dequeueOutputBuffer(acodec, info, timeoutUs);\n}\n\nssize_t SDL_AMediaCodecFake_dequeueFakeFrameOnly(SDL_AMediaCodec* acodec, SDL_AMediaCodecBufferInfo *info, int64_t timeoutUs)\n{\n    return SDL_AMediaCodec_FakeFifo_dequeueOutputBuffer(&acodec->common->fake_fifo, info, 0);\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_codec_android_mediacodec.h",
    "content": "/*****************************************************************************\n * ijksdl_codec_android_mediacodec.h\n *****************************************************************************\n *\n * Copyright (c) 2014 Bilibili\n * copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIACODEC_H\n#define IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIACODEC_H\n\n#include \"../ijksdl_stdinc.h\"\n#include <stdbool.h>\n#include <jni.h>\n#include <sys/types.h>\n#include \"../ijksdl_class.h\"\n#include \"../ijksdl_mutex.h\"\n#include \"ijksdl_codec_android_mediadef.h\"\n#include \"android_nativewindow.h\"\n\ntypedef struct SDL_AMediaCodecBufferInfo {\n    int32_t offset;\n    int32_t size;\n    int64_t presentationTimeUs;\n    uint32_t flags;\n} SDL_AMediaCodecBufferInfo;\n\ntypedef struct SDL_AMediaFormat             SDL_AMediaFormat;\ntypedef struct SDL_AMediaCrypto             SDL_AMediaCrypto;\n\ntypedef struct SDL_AMediaCodec_Common       SDL_AMediaCodec_Common;\ntypedef struct SDL_AMediaCodec_Opaque       SDL_AMediaCodec_Opaque;\ntypedef struct SDL_AMediaCodec              SDL_AMediaCodec;\ntypedef struct SDL_AMediaCodec\n{\n    SDL_mutex    *mutex;\n    volatile int  ref_count;\n\n    SDL_Class              *opaque_class;\n    SDL_AMediaCodec_Common *common;\n    SDL_AMediaCodec_Opaque *opaque;\n    bool                    is_configured;\n    bool                    is_started;\n    int                     object_serial;\n\n    sdl_amedia_status_t (*func_delete)(SDL_AMediaCodec *acodec);\n\n    sdl_amedia_status_t (*func_configure)(\n        SDL_AMediaCodec* acodec,\n        const SDL_AMediaFormat* aformat,\n        ANativeWindow* surface,\n        SDL_AMediaCrypto *crypto,\n        uint32_t flags);\n    sdl_amedia_status_t (*func_configure_surface)(\n        JNIEnv*env,\n        SDL_AMediaCodec* acodec,\n        const SDL_AMediaFormat* aformat,\n        jobject android_surface,\n        SDL_AMediaCrypto *crypto,\n        uint32_t flags);\n\n    sdl_amedia_status_t     (*func_start)(SDL_AMediaCodec* acodec);\n    sdl_amedia_status_t     (*func_stop)(SDL_AMediaCodec* acodec);\n    sdl_amedia_status_t     (*func_flush)(SDL_AMediaCodec* acodec);\n\n    ssize_t                 (*func_writeInputData)(SDL_AMediaCodec* acodec, size_t idx, const uint8_t *data, size_t size);\n\n    ssize_t                 (*func_dequeueInputBuffer)(SDL_AMediaCodec* acodec, int64_t timeoutUs);\n    sdl_amedia_status_t     (*func_queueInputBuffer)(SDL_AMediaCodec* acodec, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags);\n\n    ssize_t                 (*func_dequeueOutputBuffer)(SDL_AMediaCodec* acodec, SDL_AMediaCodecBufferInfo *info, int64_t timeoutUs);\n    SDL_AMediaFormat*       (*func_getOutputFormat)(SDL_AMediaCodec* acodec);\n    sdl_amedia_status_t     (*func_releaseOutputBuffer)(SDL_AMediaCodec* acodec, size_t idx, bool render);\n\n    bool                    (*func_isInputBuffersValid)(SDL_AMediaCodec* acodec);\n} SDL_AMediaCodec;\n\nint                     SDL_AMediaCodec_create_object_serial();\n\nsdl_amedia_status_t     SDL_AMediaCodec_configure(\n    SDL_AMediaCodec* acodec,\n    const SDL_AMediaFormat* aformat,\n    ANativeWindow* surface,\n    SDL_AMediaCrypto *crypto,\n    uint32_t flags);\n\nsdl_amedia_status_t     SDL_AMediaCodec_configure_surface(\n    JNIEnv*env,\n    SDL_AMediaCodec* acodec,\n    const SDL_AMediaFormat* aformat,\n    jobject android_surface,\n    SDL_AMediaCrypto *crypto,\n    uint32_t flags);\n\nvoid                    SDL_AMediaCodec_increaseReference(SDL_AMediaCodec *acodec);\nvoid                    SDL_AMediaCodec_decreaseReference(SDL_AMediaCodec *acodec);\nvoid                    SDL_AMediaCodec_decreaseReferenceP(SDL_AMediaCodec **acodec);\n\nbool                    SDL_AMediaCodec_isConfigured(SDL_AMediaCodec *acodec);\nbool                    SDL_AMediaCodec_isStarted(SDL_AMediaCodec *acodec);\n\nsdl_amedia_status_t     SDL_AMediaCodec_start(SDL_AMediaCodec* acodec);\nsdl_amedia_status_t     SDL_AMediaCodec_stop(SDL_AMediaCodec* acodec);\nsdl_amedia_status_t     SDL_AMediaCodec_flush(SDL_AMediaCodec* acodec);\n\nssize_t                 SDL_AMediaCodec_writeInputData(SDL_AMediaCodec* acodec, size_t idx, const uint8_t *data, size_t size);\n\nssize_t                 SDL_AMediaCodec_dequeueInputBuffer(SDL_AMediaCodec* acodec, int64_t timeoutUs);\nsdl_amedia_status_t     SDL_AMediaCodec_queueInputBuffer(SDL_AMediaCodec* acodec, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags);\n\nssize_t                 SDL_AMediaCodec_dequeueOutputBuffer(SDL_AMediaCodec* acodec, SDL_AMediaCodecBufferInfo *info, int64_t timeoutUs);\nSDL_AMediaFormat*       SDL_AMediaCodec_getOutputFormat(SDL_AMediaCodec* acodec);\nsdl_amedia_status_t     SDL_AMediaCodec_releaseOutputBuffer(SDL_AMediaCodec* acodec, size_t idx, bool render);\n\nbool                    SDL_AMediaCodec_isInputBuffersValid(SDL_AMediaCodec* acodec);\n\nint                     SDL_AMediaCodec_getSerial(SDL_AMediaCodec* acodec);\nbool                    SDL_AMediaCodec_isSameSerial(SDL_AMediaCodec* acodec, int acodec_serial);\n\n// extended\nvoid                    SDL_AMediaCodecFake_abort(SDL_AMediaCodec* acodec);\nvoid                    SDL_AMediaCodecFake_flushFakeFrames(SDL_AMediaCodec* acodec);\nsdl_amedia_status_t     SDL_AMediaCodecFake_queueFakeFrame(SDL_AMediaCodec* acodec, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags);\nssize_t                 SDL_AMediaCodecFake_dequeueOutputBuffer(SDL_AMediaCodec* acodec, SDL_AMediaCodecBufferInfo *info, int64_t timeoutUs);\nssize_t                 SDL_AMediaCodecFake_dequeueFakeFrameOnly(SDL_AMediaCodec* acodec, SDL_AMediaCodecBufferInfo *info, int64_t timeoutUs);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_codec_android_mediacodec_dummy.c",
    "content": "/*\n * Copyright (c) 2014 Bilibili\n * copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl_codec_android_mediacodec_dummy.h\"\n#include <assert.h>\n#include \"ijksdl/ijksdl_log.h\"\n#include \"ijksdl_codec_android_mediadef.h\"\n#include \"ijksdl_codec_android_mediacodec.h\"\n#include \"ijksdl_codec_android_mediacodec_internal.h\"\n\n#define DMY_TRACE(...)\n//#define DMY_TRACE ALOGE\n\nstatic SDL_Class g_amediacodec_class = {\n    .name = \"AMediaCodecDummy\",\n};\n\ntypedef struct SDL_AMediaCodec_Opaque {\n    bool request_stop;\n    SDL_AMediaCodec_FakeFifo dummy_fifo;\n} SDL_AMediaCodec_Opaque;\n\nstatic SDL_AMediaFormat *SDL_AMediaCodecDummy_getOutputFormat(SDL_AMediaCodec *thiz)\n{\n    return NULL;\n}\n\nstatic sdl_amedia_status_t SDL_AMediaCodecDummy_delete(SDL_AMediaCodec* acodec)\n{\n    SDL_AMediaCodec_FakeFifo_destroy(&acodec->opaque->dummy_fifo);\n\n    SDL_AMediaCodec_FreeInternal(acodec);\n    return SDL_AMEDIA_OK;\n}\n\nstatic sdl_amedia_status_t SDL_AMediaCodecDummy_configure_surface(\n    JNIEnv*env,\n    SDL_AMediaCodec* acodec,\n    const SDL_AMediaFormat* aformat,\n    jobject android_surface,\n    SDL_AMediaCrypto *crypto,\n    uint32_t flags)\n{\n    return SDL_AMEDIA_OK;\n}\n\nstatic sdl_amedia_status_t SDL_AMediaCodecDummy_start(SDL_AMediaCodec* acodec)\n{\n    acodec->opaque->request_stop = false;\n    return SDL_AMEDIA_OK;\n}\n\nstatic sdl_amedia_status_t SDL_AMediaCodecDummy_stop(SDL_AMediaCodec* acodec)\n{\n    acodec->opaque->request_stop = true;\n    SDL_AMediaCodec_FakeFifo_abort(&acodec->opaque->dummy_fifo);\n    return SDL_AMEDIA_OK;\n}\n\nstatic sdl_amedia_status_t SDL_AMediaCodecDummy_flush(SDL_AMediaCodec* acodec)\n{\n    SDL_AMediaCodec_FakeFifo_flush(&acodec->opaque->dummy_fifo);\n    return SDL_AMEDIA_OK;\n}\n\nstatic ssize_t SDL_AMediaCodecDummy_writeInputData(SDL_AMediaCodec* acodec, size_t idx, const uint8_t *data, size_t size)\n{\n    return size;\n}\n\nstatic ssize_t SDL_AMediaCodecDummy_dequeueInputBuffer(SDL_AMediaCodec* acodec, int64_t timeoutUs)\n{\n    DMY_TRACE(\"%s\", __func__);\n    return SDL_AMediaCodec_FakeFifo_dequeueInputBuffer(&acodec->opaque->dummy_fifo, timeoutUs);\n}\n\nstatic sdl_amedia_status_t SDL_AMediaCodecDummy_queueInputBuffer(SDL_AMediaCodec* acodec, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags)\n{\n    DMY_TRACE(\"%s\", __func__);\n    return SDL_AMediaCodec_FakeFifo_queueInputBuffer(&acodec->opaque->dummy_fifo, idx, offset, size, time, flags | AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME);\n}\n\nstatic ssize_t SDL_AMediaCodecDummy_dequeueOutputBuffer(SDL_AMediaCodec* acodec, SDL_AMediaCodecBufferInfo *info, int64_t timeoutUs)\n{\n    DMY_TRACE(\"%s\", __func__);\n    return SDL_AMediaCodec_FakeFifo_dequeueOutputBuffer(&acodec->opaque->dummy_fifo, info, timeoutUs);\n}\n\nstatic sdl_amedia_status_t SDL_AMediaCodecDummy_releaseOutputBuffer(SDL_AMediaCodec* acodec, size_t idx, bool render)\n{\n    DMY_TRACE(\"%s\", __func__);\n    return SDL_AMEDIA_OK;\n}\n\nstatic bool SDL_AMediaCodecDummy_isInputBuffersValid(SDL_AMediaCodec* acodec)\n{\n    return !acodec->opaque->request_stop;\n}\n\nSDL_AMediaCodec* SDL_AMediaCodecDummy_create()\n{\n    ALOGI(\"%s\\n\", __func__);\n\n    SDL_AMediaCodec *acodec = SDL_AMediaCodec_CreateInternal(sizeof(SDL_AMediaCodec_Opaque));\n    if (!acodec)\n        return NULL;\n\n    SDL_AMediaCodec_Opaque *opaque = acodec->opaque;\n    SDL_AMediaCodec_FakeFifo_init(&opaque->dummy_fifo);\n\n    acodec->opaque_class                = &g_amediacodec_class;\n    acodec->func_delete                 = SDL_AMediaCodecDummy_delete;\n    acodec->func_configure              = NULL;\n    acodec->func_configure_surface      = SDL_AMediaCodecDummy_configure_surface;\n\n    acodec->func_start                  = SDL_AMediaCodecDummy_start;\n    acodec->func_stop                   = SDL_AMediaCodecDummy_stop;\n    acodec->func_flush                  = SDL_AMediaCodecDummy_flush;\n\n    acodec->func_writeInputData         = SDL_AMediaCodecDummy_writeInputData;\n\n    acodec->func_dequeueInputBuffer     = SDL_AMediaCodecDummy_dequeueInputBuffer;\n    acodec->func_queueInputBuffer       = SDL_AMediaCodecDummy_queueInputBuffer;\n\n    acodec->func_dequeueOutputBuffer    = SDL_AMediaCodecDummy_dequeueOutputBuffer;\n    acodec->func_getOutputFormat        = SDL_AMediaCodecDummy_getOutputFormat;\n    acodec->func_releaseOutputBuffer    = SDL_AMediaCodecDummy_releaseOutputBuffer;\n\n    acodec->func_isInputBuffersValid    = SDL_AMediaCodecDummy_isInputBuffersValid;\n\n    SDL_AMediaCodec_increaseReference(acodec);\n    return acodec;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_codec_android_mediacodec_dummy.h",
    "content": "/*\n * Copyright (c) 2014 Bilibili\n * copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIACODEC_DUMMY_H\n#define IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIACODEC_DUMMY_H\n\n#include \"ijksdl_codec_android_mediacodec.h\"\n\nSDL_AMediaCodec *SDL_AMediaCodecDummy_create();\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_codec_android_mediacodec_internal.c",
    "content": "/*\n * Copyright (c) 2015 Bilibili\n * copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl_codec_android_mediacodec_internal.h\"\n#include \"ijksdl/ijksdl_log.h\"\n#include \"ijksdl/ijksdl_mutex.h\"\n#include \"ijksdl/ijksdl_timer.h\"\n#include \"ijksdl_codec_android_mediadef.h\"\n\n#define FAK_TRACE(...)\n//#define FAK_TRACE ALOGE\n\nsdl_amedia_status_t SDL_AMediaCodec_FakeFifo_init(SDL_AMediaCodec_FakeFifo *fifo)\n{\n    memset(fifo, 0, sizeof(SDL_AMediaCodec_FakeFifo));\n\n    fifo->mutex = SDL_CreateMutex();\n    fifo->wakeup_enqueue_cond = SDL_CreateCond();\n    fifo->wakeup_dequeue_cond = SDL_CreateCond();\n\n    return SDL_AMEDIA_OK;\n}\n\nvoid SDL_AMediaCodec_FakeFifo_abort(SDL_AMediaCodec_FakeFifo *fifo)\n{\n    SDL_LockMutex(fifo->mutex);\n    fifo->should_abort = 1;\n    SDL_CondSignal(fifo->wakeup_enqueue_cond);\n    SDL_CondSignal(fifo->wakeup_dequeue_cond);\n    SDL_UnlockMutex(fifo->mutex);\n}\n\nvoid SDL_AMediaCodec_FakeFifo_destroy(SDL_AMediaCodec_FakeFifo *fifo)\n{\n    if (!fifo)\n        return;\n\n    if (fifo->mutex)\n        SDL_AMediaCodec_FakeFifo_abort(fifo);\n\n    SDL_DestroyMutexP(&fifo->mutex);\n    SDL_DestroyCondP(&fifo->wakeup_enqueue_cond);\n    SDL_DestroyCondP(&fifo->wakeup_dequeue_cond);\n\n    memset(fifo, 0, sizeof(SDL_AMediaCodec_FakeFifo));\n}\n\nssize_t SDL_AMediaCodec_FakeFifo_dequeueInputBuffer(SDL_AMediaCodec_FakeFifo* fifo, int64_t timeoutUs)\n{\n    int ret_index = -1;\n    if (fifo->should_abort)\n        return SDL_AMEDIA_ERROR_UNKNOWN;\n\n    SDL_LockMutex(fifo->mutex);\n    if (!fifo->should_abort) {\n        if (fifo->size >= FAKE_BUFFER_QUEUE_SIZE) {\n            SDL_CondWaitTimeout(fifo->wakeup_enqueue_cond, fifo->mutex, timeoutUs / 1000);\n        }\n\n        if (fifo->size < FAKE_BUFFER_QUEUE_SIZE) {\n            ret_index = fifo->end;\n        }\n    }\n    SDL_UnlockMutex(fifo->mutex);\n\n    if (fifo->should_abort)\n        return -1;\n\n    return ret_index;\n}\n\nsdl_amedia_status_t SDL_AMediaCodec_FakeFifo_queueInputBuffer(SDL_AMediaCodec_FakeFifo *fifo, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags)\n{\n    if (fifo->should_abort)\n        return SDL_AMEDIA_ERROR_UNKNOWN;\n\n    SDL_LockMutex(fifo->mutex);\n    if (fifo->size >= FAKE_BUFFER_QUEUE_SIZE) {\n        SDL_UnlockMutex(fifo->mutex);\n        return SDL_AMEDIA_ERROR_UNKNOWN;\n    }\n\n    SDL_AMediaCodec_FakeFrame *fake = &fifo->fakes[fifo->end];\n    fake->info.offset = offset;\n    fake->info.size   = size;\n    fake->info.presentationTimeUs = time;\n    fake->info.flags  = flags;\n    fake->index       = fifo->end;\n\n    FAK_TRACE(\"%s, %d, %lld\", __func__, fifo->end, time);\n\n    fifo->end = (fifo->end + 1) % FAKE_BUFFER_QUEUE_SIZE;\n    fifo->size++;\n    SDL_CondSignal(fifo->wakeup_dequeue_cond);\n    SDL_UnlockMutex(fifo->mutex);\n\n    return SDL_AMEDIA_OK;\n}\n\nssize_t SDL_AMediaCodec_FakeFifo_dequeueOutputBuffer(SDL_AMediaCodec_FakeFifo *fifo, SDL_AMediaCodecBufferInfo *info, int64_t timeoutUs)\n{\n    if (fifo->should_abort)\n        return -1;\n\n    int64_t  timeoutMs  = (timeoutUs + 999) / 1000;    \n    ssize_t  dequeue_ret = -1;\n    uint64_t wait_start = SDL_GetTickHR();\n    int64_t  to_wait    = timeoutMs;\n\n    SDL_LockMutex(fifo->mutex);\n    while (!fifo->should_abort) {\n        if (fifo->size > 0) {\n            SDL_AMediaCodec_FakeFrame *fake = &fifo->fakes[fifo->begin];\n            *info        = fake->info;\n            info->flags |= AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME;\n            dequeue_ret  = fake->index;\n\n            FAK_TRACE(\"%s, [%d]%lld\", __func__, fifo->begin, info->presentationTimeUs);\n\n            fifo->begin = (fifo->begin + 1) % FAKE_BUFFER_QUEUE_SIZE;\n            fifo->size--;\n            SDL_CondSignal(fifo->wakeup_enqueue_cond);\n            break;\n        }\n\n        SDL_CondWaitTimeout(fifo->wakeup_dequeue_cond, fifo->mutex, to_wait);\n        if (to_wait >= 0) {\n            uint64_t now = SDL_GetTickHR();\n            if (now < wait_start) {\n                // tick overflow\n                dequeue_ret = -1;\n                break;\n            } else {\n                uint64_t elapsed = now - wait_start;\n                if (elapsed >= timeoutMs) {\n                    // timeout\n                    dequeue_ret = -1;\n                    break;\n                } else {\n                    to_wait = timeoutMs - elapsed;\n                }\n            }\n        }\n    }\n    SDL_UnlockMutex(fifo->mutex);\n\n    if (fifo->should_abort)\n        return -1;\n\n    return dequeue_ret;\n}\n\nvoid SDL_AMediaCodec_FakeFifo_flush(SDL_AMediaCodec_FakeFifo *fifo)\n{\n    if (fifo->should_abort)\n        return;\n\n    SDL_LockMutex(fifo->mutex);\n    fifo->begin = 0;\n    fifo->end   = 0;\n    fifo->size  = 0;\n    SDL_UnlockMutex(fifo->mutex);\n}\n\nint SDL_AMediaCodec_FakeFifo_size(SDL_AMediaCodec_FakeFifo *fifo)\n{\n    return fifo->size;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_codec_android_mediacodec_internal.h",
    "content": "/*****************************************************************************\n * ijksdl_codec_android_mediacodec_internal.h\n *****************************************************************************\n *\n * Copyright (c) 2014 Bilibili\n * copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIACODEC_INTERNAL_H\n#define IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIACODEC_INTERNAL_H\n\n#include \"ijksdl_codec_android_mediacodec.h\"\n\nSDL_AMediaCodec *SDL_AMediaCodec_CreateInternal(size_t opaque_size);\nvoid             SDL_AMediaCodec_FreeInternal(SDL_AMediaCodec *acodec);\n\n#define FAKE_BUFFER_QUEUE_SIZE 5\n\ntypedef struct SDL_AMediaCodec_FakeFrame {\n    size_t index;\n    SDL_AMediaCodecBufferInfo info;\n} SDL_AMediaCodec_FakeFrame;\n\ntypedef struct SDL_AMediaCodec_FakeFifo {\n    SDL_AMediaCodec_FakeFrame fakes[FAKE_BUFFER_QUEUE_SIZE];\n    int begin;\n    int end;\n    int size;\n    int should_abort;\n\n    SDL_mutex *mutex;\n    SDL_cond  *wakeup_enqueue_cond;\n    SDL_cond  *wakeup_dequeue_cond;\n} SDL_AMediaCodec_FakeFifo;\n\nsdl_amedia_status_t SDL_AMediaCodec_FakeFifo_init(SDL_AMediaCodec_FakeFifo *fifo);\nvoid                SDL_AMediaCodec_FakeFifo_abort(SDL_AMediaCodec_FakeFifo *fifo);\nvoid                SDL_AMediaCodec_FakeFifo_destroy(SDL_AMediaCodec_FakeFifo *fifo);\nssize_t             SDL_AMediaCodec_FakeFifo_dequeueInputBuffer(SDL_AMediaCodec_FakeFifo* fifo, int64_t timeoutUs);\nsdl_amedia_status_t SDL_AMediaCodec_FakeFifo_queueInputBuffer(SDL_AMediaCodec_FakeFifo *fifo, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags);\nssize_t             SDL_AMediaCodec_FakeFifo_dequeueOutputBuffer(SDL_AMediaCodec_FakeFifo *fifo, SDL_AMediaCodecBufferInfo *info, int64_t timeoutUs);\nvoid                SDL_AMediaCodec_FakeFifo_flush(SDL_AMediaCodec_FakeFifo *fifo);\nint                 SDL_AMediaCodec_FakeFifo_size(SDL_AMediaCodec_FakeFifo *fifo);\n\n#endif\n\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_codec_android_mediacodec_java.c",
    "content": "/*****************************************************************************\n * ijksdl_codec_android_mediacodec_java.c\n *****************************************************************************\n *\n * Copyright (c) 2014 Bilibili\n * copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl_codec_android_mediacodec_java.h\"\n#include <assert.h>\n#include \"j4a/class/android/media/MediaCodec.h\"\n#include \"ijksdl_android_jni.h\"\n#include \"ijksdl_codec_android_mediacodec_internal.h\"\n#include \"ijksdl_codec_android_mediaformat_java.h\"\n#include \"ijksdl_inc_internal_android.h\"\n\nstatic SDL_Class g_amediacodec_class = {\n    .name = \"AMediaCodecJava\",\n};\n\ntypedef struct SDL_AMediaCodec_Opaque {\n    jobject android_media_codec;\n\n    jobject         output_buffer_info;\n\n    bool            is_input_buffer_valid;\n} SDL_AMediaCodec_Opaque;\n\njobject SDL_AMediaCodecJava_getObject(JNIEnv *env, const SDL_AMediaCodec *thiz)\n{\n    if (!thiz || !thiz->opaque)\n        return NULL;\n\n    SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)thiz->opaque;\n    return opaque->android_media_codec;\n}\n\nSDL_AMediaFormat *SDL_AMediaCodecJava_getOutputFormat(SDL_AMediaCodec *thiz)\n{\n    if (!thiz || !thiz->opaque)\n        return NULL;\n\n    JNIEnv *env = NULL;\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"%s: SetupThreadEnv failed\", __func__);\n        return NULL;\n    }\n\n    SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)thiz->opaque;\n    jobject local_android_format = J4AC_MediaCodec__getOutputFormat__catchAll(env, opaque->android_media_codec);\n    if (!local_android_format) {\n        return NULL;\n    }\n\n    SDL_AMediaFormat *aformat = SDL_AMediaFormatJava_init(env, local_android_format);\n    SDL_JNI_DeleteLocalRefP(env, &local_android_format);\n    return aformat;\n}\n\nstatic sdl_amedia_status_t SDL_AMediaCodecJava_delete(SDL_AMediaCodec* acodec)\n{\n    ALOGI(\"%s\\n\", __func__);\n    if (!acodec)\n        return SDL_AMEDIA_OK;\n\n    JNIEnv *env = NULL;\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"SDL_AMediaCodecJava_delete: SetupThreadEnv failed\");\n        return SDL_AMEDIA_ERROR_UNKNOWN;\n    }\n\n    SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque;\n    if (opaque) {\n        if (opaque->android_media_codec) {\n            J4AC_MediaCodec__release__catchAll(env, opaque->android_media_codec);\n        }\n\n        SDL_JNI_DeleteGlobalRefP(env, &opaque->output_buffer_info);\n        SDL_JNI_DeleteGlobalRefP(env, &opaque->android_media_codec);\n    }\n\n    SDL_AMediaCodec_FreeInternal(acodec);\n    return SDL_AMEDIA_OK;\n}\n\nstatic sdl_amedia_status_t SDL_AMediaCodecJava_configure_surface(\n    JNIEnv*env,\n    SDL_AMediaCodec* acodec,\n    const SDL_AMediaFormat* aformat,\n    jobject android_surface,\n    SDL_AMediaCrypto *crypto,\n    uint32_t flags)\n{\n    SDLTRACE(\"%s\", __func__);\n\n    SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque;\n    jobject android_media_format = SDL_AMediaFormatJava_getObject(env, aformat);\n    jobject android_media_codec  = SDL_AMediaCodecJava_getObject(env, acodec);\n    ALOGE(\"configure acodec:%p format:%p: surface:%p\", android_media_codec, android_media_format, android_surface);\n    J4AC_MediaCodec__configure(env, android_media_codec, android_media_format, android_surface, crypto, flags);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return SDL_AMEDIA_ERROR_UNKNOWN;\n    }\n\n    opaque->is_input_buffer_valid = true;\n    return SDL_AMEDIA_OK;\n}\n\nstatic sdl_amedia_status_t SDL_AMediaCodecJava_start(SDL_AMediaCodec* acodec)\n{\n    SDLTRACE(\"%s\", __func__);\n\n    JNIEnv *env = NULL;\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"%s: SetupThreadEnv failed\", __func__);\n        return SDL_AMEDIA_ERROR_UNKNOWN;\n    }\n\n    SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque;\n    jobject android_media_codec    = opaque->android_media_codec;\n    J4AC_MediaCodec__start(env, android_media_codec);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        ALOGE(\"%s: start failed\", __func__);\n        return SDL_AMEDIA_ERROR_UNKNOWN;\n    }\n\n    return SDL_AMEDIA_OK;\n}\n\nstatic sdl_amedia_status_t SDL_AMediaCodecJava_stop(SDL_AMediaCodec* acodec)\n{\n    SDLTRACE(\"%s\", __func__);\n\n    JNIEnv *env = NULL;\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"%s: SetupThreadEnv failed\", __func__);\n        return SDL_AMEDIA_ERROR_UNKNOWN;\n    }\n\n    jobject android_media_codec = SDL_AMediaCodecJava_getObject(env, acodec);\n    J4AC_MediaCodec__stop(env, android_media_codec);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        ALOGE(\"%s: stop\", __func__);\n        return SDL_AMEDIA_ERROR_UNKNOWN;\n    }\n\n    acodec->object_serial = SDL_AMediaCodec_create_object_serial();\n    return SDL_AMEDIA_OK;\n}\n\nstatic sdl_amedia_status_t SDL_AMediaCodecJava_flush(SDL_AMediaCodec* acodec)\n{\n    SDLTRACE(\"%s\", __func__);\n\n    JNIEnv *env = NULL;\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"%s: SetupThreadEnv failed\", __func__);\n        return SDL_AMEDIA_ERROR_UNKNOWN;\n    }\n\n    jobject android_media_codec = SDL_AMediaCodecJava_getObject(env, acodec);\n    J4AC_MediaCodec__flush(env, android_media_codec);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        ALOGE(\"%s: flush\", __func__);\n        return SDL_AMEDIA_ERROR_UNKNOWN;\n    }\n\n    acodec->object_serial = SDL_AMediaCodec_create_object_serial();\n    return SDL_AMEDIA_OK;\n}\n\nstatic ssize_t SDL_AMediaCodecJava_writeInputData(SDL_AMediaCodec* acodec, size_t idx, const uint8_t *data, size_t size)\n{\n    AMCTRACE(\"%s\", __func__);\n    ssize_t write_ret = -1;\n    jobject input_buffer_array = NULL;\n    jobject input_buffer = NULL;\n\n    JNIEnv *env = NULL;\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"%s: SetupThreadEnv failed\", __func__);\n        return -1;\n    }\n\n    SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque;\n    input_buffer_array = J4AC_MediaCodec__getInputBuffers__catchAll(env, opaque->android_media_codec);\n    if (!input_buffer_array)\n        return -1;\n\n    int buffer_count = (*env)->GetArrayLength(env, input_buffer_array);\n    if (J4A_ExceptionCheck__catchAll(env) || idx < 0 || idx >= buffer_count) {\n        ALOGE(\"%s: idx(%d) < count(%d)\\n\", __func__, (int)idx, (int)buffer_count);\n        goto fail;\n    }\n\n    input_buffer = (*env)->GetObjectArrayElement(env, input_buffer_array, idx);\n    if (J4A_ExceptionCheck__catchAll(env) || !input_buffer) {\n        ALOGE(\"%s: GetObjectArrayElement failed\\n\", __func__);\n        goto fail;\n    }\n\n    {\n        jlong buf_size = (*env)->GetDirectBufferCapacity(env, input_buffer);\n        void *buf_ptr  = (*env)->GetDirectBufferAddress(env, input_buffer);\n\n        write_ret = size < buf_size ? size : buf_size;\n        memcpy(buf_ptr, data, write_ret);\n    }\n\nfail:\n    SDL_JNI_DeleteLocalRefP(env, &input_buffer);\n    SDL_JNI_DeleteLocalRefP(env, &input_buffer_array);\n    return write_ret;\n}\n\nssize_t SDL_AMediaCodecJava_dequeueInputBuffer(SDL_AMediaCodec* acodec, int64_t timeoutUs)\n{\n    AMCTRACE(\"%s(%d)\", __func__, (int)timeoutUs);\n\n    JNIEnv *env = NULL;\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"%s: SetupThreadEnv failed\", __func__);\n        return -1;\n    }\n\n    SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque;\n    // docs lie, getInputBuffers should be good after\n    // m_codec->start() but the internal refs are not\n    // setup until much later on some devices.\n    //if (-1 == getInputBuffers(env, acodec)) {\n    //    ALOGE(\"%s: getInputBuffers failed\", __func__);\n    //    return -1;\n    //}\n\n    jobject android_media_codec = opaque->android_media_codec;\n    jint idx = J4AC_MediaCodec__dequeueInputBuffer(env, android_media_codec, (jlong)timeoutUs);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        ALOGE(\"%s: dequeueInputBuffer failed\", __func__);\n        opaque->is_input_buffer_valid = false;\n        return -1;\n    }\n\n    return idx;\n}\n\nsdl_amedia_status_t SDL_AMediaCodecJava_queueInputBuffer(SDL_AMediaCodec* acodec, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags)\n{\n    AMCTRACE(\"%s: %d\", __func__, (int)idx);\n\n    JNIEnv *env = NULL;\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"SDL_AMediaCodecJava_queueInputBuffer: SetupThreadEnv failed\");\n        return SDL_AMEDIA_ERROR_UNKNOWN;\n    }\n\n    SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque;\n    jobject android_media_codec = opaque->android_media_codec;\n    J4AC_MediaCodec__queueInputBuffer(env, android_media_codec, (jint)idx, (jint)offset, (jint)size, (jlong)time, (jint)flags);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        return SDL_AMEDIA_ERROR_UNKNOWN;\n    }\n\n    return SDL_AMEDIA_OK;\n}\n\nssize_t SDL_AMediaCodecJava_dequeueOutputBuffer(SDL_AMediaCodec* acodec, SDL_AMediaCodecBufferInfo *info, int64_t timeoutUs)\n{\n    AMCTRACE(\"%s(%d)\", __func__, (int)timeoutUs);\n\n    JNIEnv *env = NULL;\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"%s: SetupThreadEnv failed\", __func__);\n        return AMEDIACODEC__UNKNOWN_ERROR;\n    }\n\n    SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque;\n    jobject android_media_codec = opaque->android_media_codec;\n    if (!opaque->output_buffer_info) {\n        opaque->output_buffer_info = J4AC_MediaCodec__BufferInfo__BufferInfo__asGlobalRef__catchAll(env);\n        if (!opaque->output_buffer_info)\n            return AMEDIACODEC__UNKNOWN_ERROR;\n    }\n\n    jint idx = AMEDIACODEC__UNKNOWN_ERROR;\n    while (1) {\n        idx = J4AC_MediaCodec__dequeueOutputBuffer(env, android_media_codec, opaque->output_buffer_info, (jlong)timeoutUs);\n        if (J4A_ExceptionCheck__catchAll(env)) {\n            ALOGI(\"%s: Exception\\n\", __func__);\n            return AMEDIACODEC__UNKNOWN_ERROR;\n        }\n        if (idx == AMEDIACODEC__INFO_OUTPUT_BUFFERS_CHANGED) {\n            ALOGI(\"%s: INFO_OUTPUT_BUFFERS_CHANGED\\n\", __func__);\n            continue;\n        } else if (idx == AMEDIACODEC__INFO_OUTPUT_FORMAT_CHANGED) {\n            ALOGI(\"%s: INFO_OUTPUT_FORMAT_CHANGED\\n\", __func__);\n        } else if (idx >= 0) {\n            AMCTRACE(\"%s: buffer ready (%d) ====================\\n\", __func__, idx);\n            if (info) {\n                info->offset              = J4AC_MediaCodec__BufferInfo__offset__get__catchAll(env, opaque->output_buffer_info);\n                info->size                = J4AC_MediaCodec__BufferInfo__size__get__catchAll(env, opaque->output_buffer_info);\n                info->presentationTimeUs  = J4AC_MediaCodec__BufferInfo__presentationTimeUs__get__catchAll(env, opaque->output_buffer_info);\n                info->flags               = J4AC_MediaCodec__BufferInfo__flags__get__catchAll(env, opaque->output_buffer_info);\n            }\n        }\n        break;\n    }\n\n    return idx;\n}\n\nsdl_amedia_status_t SDL_AMediaCodecJava_releaseOutputBuffer(SDL_AMediaCodec* acodec, size_t idx, bool render)\n{\n    AMCTRACE(\"%s\", __func__);\n\n    JNIEnv *env = NULL;\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"%s(%d, %s): SetupThreadEnv failed\", __func__, (int)idx, render ? \"true\" : \"false\");\n        return SDL_AMEDIA_ERROR_UNKNOWN;\n    }\n\n    SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque;\n    jobject android_media_codec = opaque->android_media_codec;\n    J4AC_MediaCodec__releaseOutputBuffer(env, android_media_codec, (jint)idx, (jboolean)render);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        ALOGE(\"%s: releaseOutputBuffer\\n\", __func__);\n        return SDL_AMEDIA_ERROR_UNKNOWN;\n    }\n\n    return SDL_AMEDIA_OK;\n}\n\nbool SDL_AMediaCodecJava_isInputBuffersValid(SDL_AMediaCodec* acodec)\n{\n    SDL_AMediaCodec_Opaque *opaque = acodec->opaque;\n    return opaque->is_input_buffer_valid;\n}\n\nstatic SDL_AMediaCodec* SDL_AMediaCodecJava_init(JNIEnv *env, jobject android_media_codec)\n{\n    SDLTRACE(\"%s\", __func__);\n\n    jobject global_android_media_codec = (*env)->NewGlobalRef(env, android_media_codec);\n    if (J4A_ExceptionCheck__catchAll(env) || !global_android_media_codec) {\n        return NULL;\n    }\n\n    SDL_AMediaCodec *acodec = SDL_AMediaCodec_CreateInternal(sizeof(SDL_AMediaCodec_Opaque));\n    if (!acodec) {\n        SDL_JNI_DeleteGlobalRefP(env, &global_android_media_codec);\n        return NULL;\n    }\n\n    SDL_AMediaCodec_Opaque *opaque = acodec->opaque;\n    opaque->android_media_codec         = global_android_media_codec;\n\n    acodec->opaque_class                = &g_amediacodec_class;\n    acodec->func_delete                 = SDL_AMediaCodecJava_delete;\n    acodec->func_configure              = NULL;\n    acodec->func_configure_surface      = SDL_AMediaCodecJava_configure_surface;\n\n    acodec->func_start                  = SDL_AMediaCodecJava_start;\n    acodec->func_stop                   = SDL_AMediaCodecJava_stop;\n    acodec->func_flush                  = SDL_AMediaCodecJava_flush;\n\n    acodec->func_writeInputData         = SDL_AMediaCodecJava_writeInputData;\n\n    acodec->func_dequeueInputBuffer     = SDL_AMediaCodecJava_dequeueInputBuffer;\n    acodec->func_queueInputBuffer       = SDL_AMediaCodecJava_queueInputBuffer;\n\n    acodec->func_dequeueOutputBuffer    = SDL_AMediaCodecJava_dequeueOutputBuffer;\n    acodec->func_getOutputFormat        = SDL_AMediaCodecJava_getOutputFormat;\n    acodec->func_releaseOutputBuffer    = SDL_AMediaCodecJava_releaseOutputBuffer;\n\n    acodec->func_isInputBuffersValid    = SDL_AMediaCodecJava_isInputBuffersValid;\n\n    SDL_AMediaCodec_increaseReference(acodec);\n    return acodec;\n}\n\nSDL_AMediaCodec* SDL_AMediaCodecJava_createByCodecName(JNIEnv *env, const char *codec_name)\n{\n    SDLTRACE(\"%s\", __func__);\n\n    jobject android_media_codec = J4AC_MediaCodec__createByCodecName__withCString__catchAll(env, codec_name);\n    if (J4A_ExceptionCheck__catchAll(env) || !android_media_codec) {\n        return NULL;\n    }\n\n    SDL_AMediaCodec* acodec = SDL_AMediaCodecJava_init(env, android_media_codec);\n    acodec->object_serial = SDL_AMediaCodec_create_object_serial();\n    SDL_JNI_DeleteLocalRefP(env, &android_media_codec);\n    return acodec;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_codec_android_mediacodec_java.h",
    "content": "/*****************************************************************************\n * ijksdl_codec_android_mediacodec_java.h\n *****************************************************************************\n *\n * Copyright (c) 2014 Bilibili\n * copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIACODEC_JAVA_H\n#define IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIACODEC_JAVA_H\n\n#include \"ijksdl_codec_android_mediacodec.h\"\n\ntypedef struct ASDK_MediaCodec ASDK_MediaCodec;\n\nSDL_AMediaCodec  *SDL_AMediaCodecJava_createByCodecName(JNIEnv *env, const char *codec_name);\njobject           SDL_AMediaCodecJava_getObject(JNIEnv *env, const SDL_AMediaCodec *thiz);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_codec_android_mediadef.c",
    "content": "/*****************************************************************************\n * ijksdl_codec_android_mediadef.h\n *****************************************************************************\n *\n * Copyright (c) 2014 Bilibili\n * copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl_codec_android_mediadef.h\"\n\nconst char *SDL_AMediaCodec_getColorFormatName(int colorFormat)\n{\n    switch (colorFormat) {\n    case AMEDIACODEC__OMX_COLOR_FormatMonochrome:\n        return \"Format8bitRGB332\";\n    case AMEDIACODEC__OMX_COLOR_Format8bitRGB332:\n        return \"Format8bitRGB332\";\n    case AMEDIACODEC__OMX_COLOR_Format12bitRGB444:\n        return \"Format12bitRGB444\";\n    case AMEDIACODEC__OMX_COLOR_Format16bitARGB4444:\n        return \"Format16bitARGB4444\";\n    case AMEDIACODEC__OMX_COLOR_Format16bitARGB1555:\n        return \"Format16bitARGB1555\";\n    case AMEDIACODEC__OMX_COLOR_Format16bitRGB565:\n        return \"Format16bitRGB565\";\n    case AMEDIACODEC__OMX_COLOR_Format16bitBGR565:\n        return \"Format16bitBGR565\";\n    case AMEDIACODEC__OMX_COLOR_Format18bitRGB666:\n        return \"Format18bitRGB666\";\n    case AMEDIACODEC__OMX_COLOR_Format18bitARGB1665:\n        return \"Format18bitARGB1665\";\n    case AMEDIACODEC__OMX_COLOR_Format19bitARGB1666:\n        return \"Format19bitARGB1666\";\n    case AMEDIACODEC__OMX_COLOR_Format24bitRGB888:\n        return \"Format24bitRGB888\";\n    case AMEDIACODEC__OMX_COLOR_Format24bitBGR888:\n        return \"Format24bitBGR888\";\n    case AMEDIACODEC__OMX_COLOR_Format24bitARGB1887:\n        return \"Format24bitARGB1887\";\n    case AMEDIACODEC__OMX_COLOR_Format25bitARGB1888:\n        return \"Format25bitARGB1888\";\n    case AMEDIACODEC__OMX_COLOR_Format32bitBGRA8888:\n        return \"Format32bitBGRA8888\";\n    case AMEDIACODEC__OMX_COLOR_Format32bitARGB8888:\n        return \"Format32bitARGB8888\";\n    case AMEDIACODEC__OMX_COLOR_FormatYUV411Planar:\n        return \"FormatYUV411Planar\";\n    case AMEDIACODEC__OMX_COLOR_FormatYUV411PackedPlanar:\n        return \"FormatYUV411PackedPlanar\";\n    case AMEDIACODEC__OMX_COLOR_FormatYUV420Planar:\n        return \"FormatYUV420Planar\";\n    case AMEDIACODEC__OMX_COLOR_FormatYUV420PackedPlanar:\n        return \"FormatYUV420PackedPlanar\";\n    case AMEDIACODEC__OMX_COLOR_FormatYUV420SemiPlanar:\n        return \"FormatYUV420SemiPlanar\";\n    case AMEDIACODEC__OMX_COLOR_FormatYUV422Planar:\n        return \"FormatYUV422Planar\";\n    case AMEDIACODEC__OMX_COLOR_FormatYUV422PackedPlanar:\n        return \"FormatYUV422PackedPlanar\";\n    case AMEDIACODEC__OMX_COLOR_FormatYUV422SemiPlanar:\n        return \"FormatYUV422SemiPlanar\";\n    case AMEDIACODEC__OMX_COLOR_FormatYCbYCr:\n        return \"FormatYCbYCr\";\n    case AMEDIACODEC__OMX_COLOR_FormatYCrYCb:\n        return \"FormatYCrYCb\";\n    case AMEDIACODEC__OMX_COLOR_FormatCbYCrY:\n        return \"FormatCbYCrY\";\n    case AMEDIACODEC__OMX_COLOR_FormatCrYCbY:\n        return \"FormatCrYCbY\";\n    case AMEDIACODEC__OMX_COLOR_FormatYUV444Interleaved:\n        return \"FormatYUV444Interleaved\";\n    case AMEDIACODEC__OMX_COLOR_FormatRawBayer8bit:\n        return \"FormatRawBayer8bit\";\n    case AMEDIACODEC__OMX_COLOR_FormatRawBayer10bit:\n        return \"FormatRawBayer10bit\";\n    case AMEDIACODEC__OMX_COLOR_FormatRawBayer8bitcompressed:\n        return \"FormatRawBayer8bitcompressed\";\n    case AMEDIACODEC__OMX_COLOR_FormatL2:\n        return \"FormatL2\";\n    case AMEDIACODEC__OMX_COLOR_FormatL4:\n        return \"FormatL4\";\n    case AMEDIACODEC__OMX_COLOR_FormatL8:\n        return \"FormatL8\";\n    case AMEDIACODEC__OMX_COLOR_FormatL16:\n        return \"FormatL16\";\n    case AMEDIACODEC__OMX_COLOR_FormatL24:\n        return \"FormatL24\";\n    case AMEDIACODEC__OMX_COLOR_FormatL32:\n        return \"FormatL32\";\n    case AMEDIACODEC__OMX_COLOR_FormatYUV420PackedSemiPlanar:\n        return \"FormatYUV420PackedSemiPlanar\";\n    case AMEDIACODEC__OMX_COLOR_FormatYUV422PackedSemiPlanar:\n        return \"FormatYUV422PackedSemiPlanar\";\n    case AMEDIACODEC__OMX_COLOR_Format18BitBGR666:\n        return \"Format18BitBGR666\";\n    case AMEDIACODEC__OMX_COLOR_Format24BitARGB6666:\n        return \"Format24BitARGB6666\";\n    case AMEDIACODEC__OMX_COLOR_Format24BitABGR6666:\n        return \"Format24BitABGR6666\";\n\n#if 0\n        // duplicated\n    case AMEDIACODEC__OMX_COLOR_TI_FormatYUV420PackedSemiPlanar:\n        return \"TI_FormatYUV420PackedSemiPlanar\";\n#endif\n    case AMEDIACODEC__OMX_COLOR_FormatSurface:\n        return \"FormatSurface\";\n    case AMEDIACODEC__OMX_COLOR_FormatYUV420Flexible:\n        return \"FormatYUV420Flexible\";\n#if 0\n        // duplicated\n    case AMEDIACODEC__OMX_COLOR_QCOM_FormatYUV420SemiPlanar:\n        return \"QCOM_FormatYUV420SemiPlanar\";\n#endif\n\n        // from hardware intel\n    case _AMEDIACODEC__OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar:\n        return \"INTEL_FormatYUV420PackedSemiPlanar\";\n    case _AMEDIACODEC__OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled:\n        return \"INTEL_FormatYUV420PackedSemiPlanar_Tiled\";\n\n        // from hardware qcom\n    case _AMEDIACODEC__OMX_QCOM_COLOR_FormatYVU420SemiPlanar:\n        return \"QCOM_FormatYVU420SemiPlanar\";\n    case _AMEDIACODEC__OMX_QCOM_COLOR_FormatYVU420PackedSemiPlanar32m4ka:\n        return \"QCOM_FormatYVU420PackedSemiPlanar32m4ka\";\n    case _AMEDIACODEC__OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar16m2ka:\n        return \"QCOM_FormatYUV420PackedSemiPlanar16m2ka\";\n    case _AMEDIACODEC__OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka:\n        return \"QCOM_FormatYUV420PackedSemiPlanar64x32Tile2m8ka\";\n    case _AMEDIACODEC__OMX_QCOM_COLOR_FORMATYUV420PackedSemiPlanar32m:\n        return \"QCOM_FORMATYUV420PackedSemiPlanar32m\";\n    case _AMEDIACODEC__OMX_QCOM_COLOR_FORMATYUV420PackedSemiPlanar32mMultiView:\n        return \"QCOM_FORMATYUV420PackedSemiPlanar32mMultiView\";\n\n        // from hardware samsung_slsi\n    case _AMEDIACODEC__OMX_SEC_COLOR_FormatNV12TPhysicalAddress:\n        return \"SEC_FormatNV12TPhysicalAddress\";\n    case _AMEDIACODEC__OMX_SEC_COLOR_FormatNV12LPhysicalAddress:\n        return \"SEC_FormatNV12LPhysicalAddress\";\n    case _AMEDIACODEC__OMX_SEC_COLOR_FormatNV12LVirtualAddress:\n        return \"SEC_FormatNV12LVirtualAddress\";\n    case _AMEDIACODEC__OMX_SEC_COLOR_FormatNV12Tiled:\n        return \"SEC_FormatNV12Tiled\";\n    case _AMEDIACODEC__OMX_SEC_COLOR_FormatNV21LPhysicalAddress:\n        return \"SEC_FormatNV21LPhysicalAddress\";\n    case _AMEDIACODEC__OMX_SEC_COLOR_FormatNV21Linear:\n        return \"SEC_FormatNV21Linear\";\n\n        // from hardware ti\n    case _AMEDIACODEC__OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:\n        return \"TI_FormatYUV420PackedSemiPlanar\";\n\n    default:\n        return \"FormatUnknown\";\n    }\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_codec_android_mediadef.h",
    "content": "/*****************************************************************************\n * ijksdl_codec_android_mediadef.h\n *****************************************************************************\n *\n * Copyright (c) 2014 Bilibili\n * copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIADEF_H\n#define IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIADEF_H\n\n#include \"../ijksdl_misc.h\"\n\ntypedef enum sdl_amedia_status_t {\n    SDL_AMEDIA_OK = 0,\n\n    SDL_AMEDIA_ERROR_BASE                  = -10000,\n    SDL_AMEDIA_ERROR_UNKNOWN               = SDL_AMEDIA_ERROR_BASE,\n    SDL_AMEDIA_ERROR_MALFORMED             = SDL_AMEDIA_ERROR_BASE - 1,\n    SDL_AMEDIA_ERROR_UNSUPPORTED           = SDL_AMEDIA_ERROR_BASE - 2,\n    SDL_AMEDIA_ERROR_INVALID_OBJECT        = SDL_AMEDIA_ERROR_BASE - 3,\n    SDL_AMEDIA_ERROR_INVALID_PARAMETER     = SDL_AMEDIA_ERROR_BASE - 4,\n\n    SDL_AMEDIA_DRM_ERROR_BASE              = -20000,\n    SDL_AMEDIA_DRM_NOT_PROVISIONED         = SDL_AMEDIA_DRM_ERROR_BASE - 1,\n    SDL_AMEDIA_DRM_RESOURCE_BUSY           = SDL_AMEDIA_DRM_ERROR_BASE - 2,\n    SDL_AMEDIA_DRM_DEVICE_REVOKED          = SDL_AMEDIA_DRM_ERROR_BASE - 3,\n    SDL_AMEDIA_DRM_SHORT_BUFFER            = SDL_AMEDIA_DRM_ERROR_BASE - 4,\n    SDL_AMEDIA_DRM_SESSION_NOT_OPENED      = SDL_AMEDIA_DRM_ERROR_BASE - 5,\n    SDL_AMEDIA_DRM_TAMPER_DETECTED         = SDL_AMEDIA_DRM_ERROR_BASE - 6,\n    SDL_AMEDIA_DRM_VERIFY_FAILED           = SDL_AMEDIA_DRM_ERROR_BASE - 7,\n    SDL_AMEDIA_DRM_NEED_KEY                = SDL_AMEDIA_DRM_ERROR_BASE - 8,\n    SDL_AMEDIA_DRM_LICENSE_EXPIRED         = SDL_AMEDIA_DRM_ERROR_BASE - 9,\n} sdl_amedia_status_t;\n\n#define SDL_AMIME_VIDEO_VP8         \"video/x-vnd.on2.vp8\"   //- VP8 video (i.e. video in .webm)\n#define SDL_AMIME_VIDEO_VP9         \"video/x-vnd.on2.vp9\"   //- VP9 video (i.e. video in .webm)\n#define SDL_AMIME_VIDEO_AVC         \"video/avc\"             //- H.264/AVC video\n#define SDL_AMIME_VIDEO_HEVC        \"video/hevc\"            //- H.265/HEVC video\n#define SDL_AMIME_VIDEO_MPEG2VIDEO  \"video/mpeg2\"           //- MPEG2 video\n#define SDL_AMIME_VIDEO_MPEG4       \"video/mp4v-es\"         //- MPEG4 video\n#define SDL_AMIME_VIDEO_H263        \"video/3gpp\"            //- H.263 video\n#define SDL_AMIME_AUDIO_AMR_NB      \"audio/3gpp\"            //- AMR narrowband audio\n#define SDL_AMIME_AUDIO_AMR_WB      \"audio/amr-wb\"          //- AMR wideband audio\n#define SDL_AMIME_AUDIO_MP3         \"audio/mpeg\"            //- MPEG1/2 audio layer III\n#define SDL_AMIME_AUDIO_RAW_AAC     \"audio/mp4a-latm\"       //- AAC audio (note, this is raw AAC packets, not packaged in LATM!)\n#define SDL_AMIME_AUDIO_VORBIS      \"audio/vorbis\"          //- vorbis audio\n#define SDL_AMIME_AUDIO_G711_ALAW   \"audio/g711-alaw\"       //- G.711 alaw audio\n#define SDL_AMIME_AUDIO_G711_MLAW   \"audio/g711-mlaw\"       //- G.711 ulaw audio\n\n#if 0\ntypedef enum sdl_amedia_format_key_t {\n    AMEDIAFORMAT_KEY_AAC_PROFILE,\n    AMEDIAFORMAT_KEY_BIT_RATE,\n    AMEDIAFORMAT_KEY_CHANNEL_COUNT,\n    AMEDIAFORMAT_KEY_CHANNEL_MASK,\n    AMEDIAFORMAT_KEY_COLOR_FORMAT,\n    AMEDIAFORMAT_KEY_DURATION,\n    AMEDIAFORMAT_KEY_FLAC_COMPRESSION_LEVEL,\n    AMEDIAFORMAT_KEY_FRAME_RATE,\n    AMEDIAFORMAT_KEY_HEIGHT,\n    AMEDIAFORMAT_KEY_IS_ADTS,\n    AMEDIAFORMAT_KEY_IS_AUTOSELECT,\n    AMEDIAFORMAT_KEY_IS_DEFAULT,\n    AMEDIAFORMAT_KEY_IS_FORCED_SUBTITLE,\n    AMEDIAFORMAT_KEY_I_FRAME_INTERVAL,\n    AMEDIAFORMAT_KEY_LANGUAGE,\n    AMEDIAFORMAT_KEY_MAX_HEIGHT,\n    AMEDIAFORMAT_KEY_MAX_INPUT_SIZE,\n    AMEDIAFORMAT_KEY_MAX_WIDTH,\n    AMEDIAFORMAT_KEY_MIME,\n    AMEDIAFORMAT_KEY_PUSH_BLANK_BUFFERS_ON_STOP,\n    AMEDIAFORMAT_KEY_REPEAT_PREVIOUS_FRAME_AFTER,\n    AMEDIAFORMAT_KEY_SAMPLE_RATE,\n    AMEDIAFORMAT_KEY_WIDTH,\n    AMEDIAFORMAT_KEY_STRIDE,\n} sdl_amedia_format_key_t;\n#else\n\n#define AMEDIAFORMAT_KEY_AAC_PROFILE            \"aac-profile\"\n#define AMEDIAFORMAT_KEY_BIT_RATE               \"bitrate\"\n#define AMEDIAFORMAT_KEY_CHANNEL_COUNT          \"channel-count\"\n#define AMEDIAFORMAT_KEY_CHANNEL_MASK           \"channel-mask\"\n#define AMEDIAFORMAT_KEY_COLOR_FORMAT           \"color-format\"\n#define AMEDIAFORMAT_KEY_DURATION               \"durationUs\"\n#define AMEDIAFORMAT_KEY_FLAC_COMPRESSION_LEVEL \"flac-compression-level\"\n#define AMEDIAFORMAT_KEY_FRAME_RATE             \"frame-rate\"\n#define AMEDIAFORMAT_KEY_HEIGHT                 \"height\"\n#define AMEDIAFORMAT_KEY_IS_ADTS                \"is-adts\"\n//#define AMEDIAFORMAT_KEY_IS_AUTOSELECT\n//#define AMEDIAFORMAT_KEY_IS_DEFAULT\n//#define AMEDIAFORMAT_KEY_IS_FORCED_SUBTITLE\n#define AMEDIAFORMAT_KEY_I_FRAME_INTERVAL       \"i-frame-interval\"\n//#define AMEDIAFORMAT_KEY_LANGUAGE\n//#define AMEDIAFORMAT_KEY_MAX_HEIGHT\n#define AMEDIAFORMAT_KEY_MAX_INPUT_SIZE         \"max-input-size\"\n//#define AMEDIAFORMAT_KEY_MAX_WIDTH\n#define AMEDIAFORMAT_KEY_MIME                   \"mime\"\n//#define AMEDIAFORMAT_KEY_PUSH_BLANK_BUFFERS_ON_STOP,\n//#define AMEDIAFORMAT_KEY_REPEAT_PREVIOUS_FRAME_AFTER,\n#define AMEDIAFORMAT_KEY_SAMPLE_RATE            \"sample-rate\"\n#define AMEDIAFORMAT_KEY_WIDTH                  \"width\"\n//#define AMEDIAFORMAT_KEY_STRIDE\n#endif\n\nenum {\n    AMEDIACODEC__INFO_OUTPUT_BUFFERS_CHANGED = -3,\n    AMEDIACODEC__INFO_OUTPUT_FORMAT_CHANGED  = -2,\n    AMEDIACODEC__INFO_TRY_AGAIN_LATER        = -1,\n\n    AMEDIACODEC__UNKNOWN_ERROR               = -1000,\n};\n\nenum {\n    AMEDIACODEC__BUFFER_FLAG_KEY_FRAME       = 0x01,\n    AMEDIACODEC__BUFFER_FLAG_CODEC_CONFIG    = 0x02,\n    AMEDIACODEC__BUFFER_FLAG_END_OF_STREAM   = 0x04,\n\n    // extended\n    AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME      = 0x1000,\n};\n\nenum {\n    AMEDIACODEC__OMX_COLOR_FormatMonochrome              = 1,\n    AMEDIACODEC__OMX_COLOR_Format8bitRGB332              = 2,\n    AMEDIACODEC__OMX_COLOR_Format12bitRGB444             = 3,\n    AMEDIACODEC__OMX_COLOR_Format16bitARGB4444           = 4,\n    AMEDIACODEC__OMX_COLOR_Format16bitARGB1555           = 5,\n    AMEDIACODEC__OMX_COLOR_Format16bitRGB565             = 6,\n    AMEDIACODEC__OMX_COLOR_Format16bitBGR565             = 7,\n    AMEDIACODEC__OMX_COLOR_Format18bitRGB666             = 8,\n    AMEDIACODEC__OMX_COLOR_Format18bitARGB1665           = 9,\n    AMEDIACODEC__OMX_COLOR_Format19bitARGB1666           = 10,\n    AMEDIACODEC__OMX_COLOR_Format24bitRGB888             = 11,\n    AMEDIACODEC__OMX_COLOR_Format24bitBGR888             = 12,\n    AMEDIACODEC__OMX_COLOR_Format24bitARGB1887           = 13,\n    AMEDIACODEC__OMX_COLOR_Format25bitARGB1888           = 14,\n    AMEDIACODEC__OMX_COLOR_Format32bitBGRA8888           = 15,\n    AMEDIACODEC__OMX_COLOR_Format32bitARGB8888           = 16,\n    AMEDIACODEC__OMX_COLOR_FormatYUV411Planar            = 17,\n    AMEDIACODEC__OMX_COLOR_FormatYUV411PackedPlanar      = 18,\n    AMEDIACODEC__OMX_COLOR_FormatYUV420Planar            = 19,\n    AMEDIACODEC__OMX_COLOR_FormatYUV420PackedPlanar      = 20,\n    AMEDIACODEC__OMX_COLOR_FormatYUV420SemiPlanar        = 21,\n    AMEDIACODEC__OMX_COLOR_FormatYUV422Planar            = 22,\n    AMEDIACODEC__OMX_COLOR_FormatYUV422PackedPlanar      = 23,\n    AMEDIACODEC__OMX_COLOR_FormatYUV422SemiPlanar        = 24,\n    AMEDIACODEC__OMX_COLOR_FormatYCbYCr                  = 25,\n    AMEDIACODEC__OMX_COLOR_FormatYCrYCb                  = 26,\n    AMEDIACODEC__OMX_COLOR_FormatCbYCrY                  = 27,\n    AMEDIACODEC__OMX_COLOR_FormatCrYCbY                  = 28,\n    AMEDIACODEC__OMX_COLOR_FormatYUV444Interleaved       = 29,\n    AMEDIACODEC__OMX_COLOR_FormatRawBayer8bit            = 30,\n    AMEDIACODEC__OMX_COLOR_FormatRawBayer10bit           = 31,\n    AMEDIACODEC__OMX_COLOR_FormatRawBayer8bitcompressed  = 32,\n    AMEDIACODEC__OMX_COLOR_FormatL2                      = 33,\n    AMEDIACODEC__OMX_COLOR_FormatL4                      = 34,\n    AMEDIACODEC__OMX_COLOR_FormatL8                      = 35,\n    AMEDIACODEC__OMX_COLOR_FormatL16                     = 36,\n    AMEDIACODEC__OMX_COLOR_FormatL24                     = 37,\n    AMEDIACODEC__OMX_COLOR_FormatL32                     = 38,\n    AMEDIACODEC__OMX_COLOR_FormatYUV420PackedSemiPlanar  = 39,\n    AMEDIACODEC__OMX_COLOR_FormatYUV422PackedSemiPlanar  = 40,\n    AMEDIACODEC__OMX_COLOR_Format18BitBGR666             = 41,\n    AMEDIACODEC__OMX_COLOR_Format24BitARGB6666           = 42,\n    AMEDIACODEC__OMX_COLOR_Format24BitABGR6666           = 43,\n\n    // AMEDIACODEC__OMX_COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7f000100,\n    AMEDIACODEC__OMX_COLOR_FormatSurface                   = 0x7f000789,\n    AMEDIACODEC__OMX_COLOR_FormatYUV420Flexible            = 0x7f420888,\n    // AMEDIACODEC__OMX_COLOR_QCOM_FormatYUV420SemiPlanar     = 0x7fa30c00,\n\n    // from hardware intel\n    _AMEDIACODEC__OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar              = 0x7FA00E00,\n    _AMEDIACODEC__OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled        = 0x7FA00F00,\n\n    // from hardware qcom\n    _AMEDIACODEC__OMX_QCOM_COLOR_FormatYVU420SemiPlanar                     = 0x7FA30C00,\n    _AMEDIACODEC__OMX_QCOM_COLOR_FormatYVU420PackedSemiPlanar32m4ka         = 0x7FA30C01,\n    _AMEDIACODEC__OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar16m2ka         = 0x7FA30C02,\n    _AMEDIACODEC__OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka = 0x7FA30C03,\n    _AMEDIACODEC__OMX_QCOM_COLOR_FORMATYUV420PackedSemiPlanar32m            = 0x7FA30C04,\n    _AMEDIACODEC__OMX_QCOM_COLOR_FORMATYUV420PackedSemiPlanar32mMultiView   = 0x7FA30C05,\n\n    // from hardware samsung_slsi\n    _AMEDIACODEC__OMX_SEC_COLOR_FormatNV12TPhysicalAddress  = 0x7F000001,\n    _AMEDIACODEC__OMX_SEC_COLOR_FormatNV12LPhysicalAddress  = 0x7F000002,\n    _AMEDIACODEC__OMX_SEC_COLOR_FormatNV12LVirtualAddress   = 0x7F000003,\n    _AMEDIACODEC__OMX_SEC_COLOR_FormatNV12Tiled             = 0x7FC00002,\n    _AMEDIACODEC__OMX_SEC_COLOR_FormatNV21LPhysicalAddress  = 0x7F000010,\n    _AMEDIACODEC__OMX_SEC_COLOR_FormatNV21Linear            = 0x7F000011,\n\n    // from hardware ti\n    // _AMEDIACODEC__OMX_TI_COLOR_FormatRawBayer10bitStereo    = 0x7F000002,\n    _AMEDIACODEC__OMX_TI_COLOR_FormatYUV420PackedSemiPlanar = 0x7F000100,\n};\n\nconst char *SDL_AMediaCodec_getColorFormatName(int colorFormat);\n\n//#define AMCTRACE ALOGI\n#define AMCTRACE(...)\n\n#endif\n\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_codec_android_mediaformat.c",
    "content": "/*****************************************************************************\n * ijksdl_codec_android_mediaformat.c\n *****************************************************************************\n *\n * Copyright (c) 2014 Bilibili\n * copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl_codec_android_mediaformat.h\"\n#include <assert.h>\n\n// FIXME: release SDL_AMediaFormat\nsdl_amedia_status_t SDL_AMediaFormat_delete(SDL_AMediaFormat* aformat)\n{\n    if (!aformat)\n        return SDL_AMEDIA_OK;\n    assert(aformat->func_delete);\n    return aformat->func_delete(aformat);\n}\n\nsdl_amedia_status_t SDL_AMediaFormat_deleteP(SDL_AMediaFormat** aformat)\n{\n    if (!aformat)\n        return SDL_AMEDIA_OK;\n    sdl_amedia_status_t amc_ret = SDL_AMediaFormat_delete(*aformat);\n    *aformat = NULL;\n    return amc_ret;\n}\n\nbool SDL_AMediaFormat_getInt32(SDL_AMediaFormat* aformat, const char* name, int32_t *out)\n{\n    assert(aformat->func_getInt32);\n    return aformat->func_getInt32(aformat, name, out);\n}\n\nvoid SDL_AMediaFormat_setInt32(SDL_AMediaFormat* aformat, const char* name, int32_t value)\n{\n    assert(aformat->func_setInt32);\n    aformat->func_setInt32(aformat, name, value);\n}\n\nvoid SDL_AMediaFormat_setBuffer(SDL_AMediaFormat* aformat, const char* name, void* data, size_t size)\n{\n    assert(aformat->func_setInt32);\n    aformat->func_setBuffer(aformat, name, data, size);\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_codec_android_mediaformat.h",
    "content": "/*****************************************************************************\n * ijksdl_codec_android_mediaformat.h\n *****************************************************************************\n *\n * Copyright (c) 2014 Bilibili\n * copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIAFORMAT_H\n#define IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIAFORMAT_H\n\n#include \"../ijksdl_stdinc.h\"\n#include <stdbool.h>\n#include <jni.h>\n#include <sys/types.h>\n#include \"../ijksdl_mutex.h\"\n#include \"ijksdl_codec_android_mediadef.h\"\n\ntypedef struct SDL_AMediaFormat_Opaque      SDL_AMediaFormat_Opaque;\ntypedef struct SDL_AMediaFormat             SDL_AMediaFormat;\ntypedef struct SDL_AMediaFormat\n{\n    SDL_mutex *mutex;\n\n    SDL_AMediaFormat_Opaque *opaque;\n\n    sdl_amedia_status_t (*func_delete)(SDL_AMediaFormat *aformat);\n\n    bool (*func_getInt32)(SDL_AMediaFormat* aformat, const char* name, int32_t *out);\n    void (*func_setInt32)(SDL_AMediaFormat* aformat, const char* name, int32_t value);\n\n    void (*func_setBuffer)(SDL_AMediaFormat* aformat, const char* name, void* data, size_t size);\n} SDL_AMediaFormat;\n\nsdl_amedia_status_t SDL_AMediaFormat_delete(SDL_AMediaFormat* aformat);\nsdl_amedia_status_t SDL_AMediaFormat_deleteP(SDL_AMediaFormat** aformat);\n\nbool SDL_AMediaFormat_getInt32(SDL_AMediaFormat* aformat, const char* name, int32_t *out);\nvoid SDL_AMediaFormat_setInt32(SDL_AMediaFormat* aformat, const char* name, int32_t value);\n\nvoid SDL_AMediaFormat_setBuffer(SDL_AMediaFormat* aformat, const char* name, void* data, size_t size);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_codec_android_mediaformat_internal.h",
    "content": "/*****************************************************************************\n * ijksdl_codec_android_mediaformat_internal.h\n *****************************************************************************\n *\n * Copyright (c) 2014 Bilibili\n * copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIAFORMAT_INTERNAL_H\n#define IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIAFORMAT_INTERNAL_H\n\n#include \"ijksdl_codec_android_mediaformat.h\"\n\ninline static SDL_AMediaFormat *SDL_AMediaFormat_CreateInternal(size_t opaque_size)\n{\n    SDL_AMediaFormat *aformat = (SDL_AMediaFormat*) mallocz(sizeof(SDL_AMediaFormat));\n    if (!aformat)\n        return NULL;\n\n    aformat->opaque = mallocz(opaque_size);\n    if (!aformat->opaque) {\n        free(aformat);\n        return NULL;\n    }\n\n    aformat->mutex = SDL_CreateMutex();\n    if (aformat->mutex == NULL) {\n        free(aformat->opaque);\n        free(aformat);\n        return NULL;\n    }\n\n    return aformat;\n}\n\ninline static void SDL_AMediaFormat_FreeInternal(SDL_AMediaFormat *aformat)\n{\n    if (!aformat)\n        return;\n\n    if (aformat->mutex) {\n        SDL_DestroyMutexP(&aformat->mutex);\n    }\n\n    free(aformat->opaque);\n    memset(aformat, 0, sizeof(SDL_AMediaFormat));\n    free(aformat);\n}\n\n#endif\n\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_codec_android_mediaformat_java.c",
    "content": "/*****************************************************************************\n * ijksdl_codec_android_mediaformat_java.c\n *****************************************************************************\n *\n * Copyright (c) 2014 Bilibili\n * copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl_codec_android_mediaformat_java.h\"\n\n#include \"j4a/class/android/media/MediaFormat.h\"\n#include \"j4au/class/java/nio/ByteBuffer.util.h\"\n#include \"ijksdl_android_jni.h\"\n#include \"ijksdl_codec_android_mediaformat_internal.h\"\n#include \"ijksdl_inc_internal_android.h\"\n\ntypedef struct SDL_AMediaFormat_Opaque {\n    jobject android_media_format;\n\n    jobject android_byte_buffer;\n} SDL_AMediaFormat_Opaque;\n\njobject SDL_AMediaFormatJava_getObject(JNIEnv *env, const SDL_AMediaFormat *thiz)\n{\n    if (!thiz || !thiz->opaque)\n        return NULL;\n\n    SDL_AMediaFormat_Opaque *opaque = (SDL_AMediaFormat_Opaque *)thiz->opaque;\n    return opaque->android_media_format;\n}\n\nstatic jobject getAndroidMediaFormat(JNIEnv *env, const SDL_AMediaFormat* thiz) {\n    if (!thiz)\n        return NULL;\n\n    SDL_AMediaFormat_Opaque *opaque = (SDL_AMediaFormat_Opaque *)thiz->opaque;\n    if (!opaque)\n        return NULL;\n\n    return opaque->android_media_format;\n}\n\nstatic sdl_amedia_status_t SDL_AMediaFormatJava_delete(SDL_AMediaFormat* aformat)\n{\n    if (!aformat)\n        return SDL_AMEDIA_OK;\n\n    JNIEnv *env = NULL;\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"%s: SetupThreadEnv failed\", __func__);\n        return SDL_AMEDIA_ERROR_UNKNOWN;\n    }\n\n    SDL_AMediaFormat_Opaque *opaque = (SDL_AMediaFormat_Opaque *)aformat->opaque;\n    if (opaque) {\n        SDL_JNI_DeleteGlobalRefP(env, &opaque->android_byte_buffer);\n        SDL_JNI_DeleteGlobalRefP(env, &opaque->android_media_format);\n    }\n\n    SDL_AMediaFormat_FreeInternal(aformat);\n    return SDL_AMEDIA_OK;\n}\n\nstatic bool SDL_AMediaFormatJava_getInt32(SDL_AMediaFormat* aformat, const char* name, int32_t *out)\n{\n    JNIEnv *env = NULL;\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"%s: SDL_JNI_SetupThreadEnv: failed\", __func__);\n        return false;\n    }\n\n    jobject android_media_format = getAndroidMediaFormat(env, aformat);\n    if (!android_media_format) {\n        ALOGE(\"%s: getAndroidMediaFormat: failed\", __func__);\n        return false;\n    }\n\n    jint ret = J4AC_MediaFormat__getInteger__withCString(env, android_media_format, name);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        ALOGE(\"%s: CallIntMethod: failed\", __func__);\n        return false;\n    }\n\n    if (out)\n        *out = ret;\n    return true;\n}\n\nstatic void SDL_AMediaFormatJava_setInt32(SDL_AMediaFormat* aformat, const char* name, int32_t value)\n{\n    JNIEnv *env = NULL;\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"%s: SDL_JNI_SetupThreadEnv: failed\", __func__);\n        return;\n    }\n\n    jobject android_media_format = getAndroidMediaFormat(env, aformat);\n    if (!android_media_format) {\n        ALOGE(\"%s: getAndroidMediaFormat: failed\", __func__);\n        return;\n    }\n\n    J4AC_MediaFormat__setInteger__withCString(env, android_media_format, name, value);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        ALOGE(\"%s: CallVoidMethod: failed\", __func__);\n        return;\n    }\n}\n\nstatic void SDL_AMediaFormatJava_setBuffer(SDL_AMediaFormat* aformat, const char* name, void* data, size_t size)\n{\n    int    ret  = -1;\n    JNIEnv *env = NULL;\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        ALOGE(\"%s: SDL_JNI_SetupThreadEnv: failed\", __func__);\n        return;\n    }\n\n    SDL_AMediaFormat_Opaque *opaque = (SDL_AMediaFormat_Opaque *)aformat->opaque;\n    jobject android_media_format = opaque->android_media_format;\n    if (!opaque->android_byte_buffer) {\n        opaque->android_byte_buffer = J4AC_ByteBuffer__allocateDirect__asGlobalRef__catchAll(env, size);\n        if (!opaque->android_byte_buffer) {\n            J4A_FUNC_FAIL_TRACE();\n            return;\n        }\n    }\n\n    ret = J4AC_ByteBuffer__assignData__catchAll(env, opaque->android_byte_buffer, data, size);\n    if (ret < 0) {\n        J4A_FUNC_FAIL_TRACE();\n        return;\n    }\n\n    J4AC_MediaFormat__setByteBuffer__withCString(env, android_media_format, name, opaque->android_byte_buffer);\n    if (J4A_ExceptionCheck__catchAll(env)) {\n        ALOGE(\"%s: call jmid_setByteBuffer: failed\", __func__);\n        return;\n    }\n}\n\nstatic void setup_aformat(SDL_AMediaFormat *aformat, jobject android_media_format) {\n    SDL_AMediaFormat_Opaque *opaque = aformat->opaque;\n    opaque->android_media_format = android_media_format;\n\n    aformat->func_delete    = SDL_AMediaFormatJava_delete;\n    aformat->func_getInt32  = SDL_AMediaFormatJava_getInt32;\n    aformat->func_setInt32  = SDL_AMediaFormatJava_setInt32;\n    aformat->func_setBuffer = SDL_AMediaFormatJava_setBuffer;\n}\n\nSDL_AMediaFormat *SDL_AMediaFormatJava_init(JNIEnv *env, jobject android_format)\n{\n    SDLTRACE(\"%s\", __func__);\n    jobject global_android_media_format = (*env)->NewGlobalRef(env, android_format);\n    if (J4A_ExceptionCheck__catchAll(env) || !global_android_media_format) {\n        return NULL;\n    }\n\n    SDL_AMediaFormat *aformat = SDL_AMediaFormat_CreateInternal(sizeof(SDL_AMediaFormat_Opaque));\n    if (!aformat) {\n        SDL_JNI_DeleteGlobalRefP(env, &global_android_media_format);\n        return NULL;\n    }\n\n    setup_aformat(aformat, global_android_media_format);\n    return aformat;\n}\n\nSDL_AMediaFormat *SDL_AMediaFormatJava_createVideoFormat(JNIEnv *env, const char *mime, int width, int height)\n{\n    SDLTRACE(\"%s\", __func__);\n\n    jobject android_media_format = J4AC_MediaFormat__createVideoFormat__withCString__asGlobalRef__catchAll(env, mime, width, height);\n    if (J4A_ExceptionCheck__catchAll(env) || !android_media_format) {\n        return NULL;\n    }\n\n    SDL_AMediaFormat *aformat = SDL_AMediaFormat_CreateInternal(sizeof(SDL_AMediaFormat_Opaque));\n    if (!aformat) {\n        SDL_JNI_DeleteGlobalRefP(env, &android_media_format);\n        return NULL;\n    }\n\n    setup_aformat(aformat, android_media_format);\n    SDL_AMediaFormat_setInt32(aformat, AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, 0);\n    return aformat;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_codec_android_mediaformat_java.h",
    "content": "/*****************************************************************************\n * ijksdl_codec_android_mediaformat_java.h\n *****************************************************************************\n *\n * Copyright (c) 2014 Bilibili\n * copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIAFORMAT_JAVA_H\n#define IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIAFORMAT_JAVA_H\n\n#include \"ijksdl_codec_android_mediaformat.h\"\n\nSDL_AMediaFormat *SDL_AMediaFormatJava_init(JNIEnv *env, jobject android_format);\nSDL_AMediaFormat *SDL_AMediaFormatJava_createVideoFormat(JNIEnv *env, const char *mime, int width, int height);\njobject           SDL_AMediaFormatJava_getObject(JNIEnv *env, const SDL_AMediaFormat *thiz);\n\n#endif\n\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_inc_internal_android.h",
    "content": "/*\n * ijksdl_inc_internal_android.h\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKPLAYER__IJKSDL_INC_INTERNAL_ANDROID_H\n#define IJKPLAYER__IJKSDL_INC_INTERNAL_ANDROID_H\n\n#include <stdint.h>\n#include <jni.h>\n\n#include \"../ijksdl_inc_internal.h\"\n#include \"../ijksdl_misc.h\"\n#include \"../ijksdl_log.h\"\n\nenum {\n    HAL_PIXEL_FORMAT_RGBA_8888 = 1,\n    HAL_PIXEL_FORMAT_RGBX_8888 = 2,\n    HAL_PIXEL_FORMAT_RGB_888 = 3,\n    HAL_PIXEL_FORMAT_RGB_565 = 4,\n    HAL_PIXEL_FORMAT_BGRA_8888 = 5,\n    HAL_PIXEL_FORMAT_RGBA_5551 = 6,\n    HAL_PIXEL_FORMAT_RGBA_4444 = 7,\n\n    /* 0x8 - 0xFF range unavailable */\n    /* 0x100 - 0x1FF HAL implement */\n    HAL_PIXEL_FORMAT_YV12 = 0x32315659, // YCrCb 4:2:0 Planar\n\n    HAL_PIXEL_FORMAT_RAW_SENSOR = 0x20,\n    HAL_PIXEL_FORMAT_BLOB = 0x21,\n    HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22,\n\n    /* Legacy formats (deprecated), used by ImageFormat.java */\n    HAL_PIXEL_FORMAT_YCbCr_422_SP = 0x10, // NV16\n    HAL_PIXEL_FORMAT_YCrCb_420_SP = 0x11, // NV21\n    HAL_PIXEL_FORMAT_YCbCr_422_I = 0x14, // YUY2\n\n};\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_vout_android_nativewindow.c",
    "content": "/*****************************************************************************\n * ijksdl_vout_android_nativewindow.c\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl_vout_android_nativewindow.h\"\n\n#include <assert.h>\n#include <android/native_window.h>\n#include \"ijksdl/ijksdl_vout.h\"\n#include \"ijksdl/ijksdl_vout_internal.h\"\n#include \"ijksdl/ijksdl_container.h\"\n#include \"ijksdl/ijksdl_egl.h\"\n#include \"ijksdl/ffmpeg/ijksdl_vout_overlay_ffmpeg.h\"\n#include \"ijksdl_codec_android_mediacodec.h\"\n#include \"ijksdl_inc_internal_android.h\"\n#include \"ijksdl_vout_overlay_android_mediacodec.h\"\n#include \"android_nativewindow.h\"\n\n#ifndef AMCTRACE\n#define AMCTRACE(...)\n#endif\n\nstruct SDL_AMediaCodecBufferProxy\n{\n    int buffer_id;\n    int buffer_index;\n    int acodec_serial;\n    SDL_AMediaCodecBufferInfo buffer_info;\n};\n\nstatic void SDL_AMediaCodecBufferProxy_reset(SDL_AMediaCodecBufferProxy *proxy)\n{\n    memset(proxy, 0, sizeof(SDL_AMediaCodecBufferProxy));\n    proxy->buffer_index  = -1;\n    proxy->acodec_serial = 0;\n}\n\nstatic void SDL_AMediaCodecBufferProxy_init(SDL_AMediaCodecBufferProxy *proxy)\n{\n    assert(proxy);\n    SDL_AMediaCodecBufferProxy_reset(proxy);\n}\n\nstatic void SDL_AMediaCodecBufferProxy_destroy(SDL_AMediaCodecBufferProxy *proxy)\n{\n    if (!proxy)\n        return;\n    SDL_AMediaCodecBufferProxy_reset(proxy);\n}\n\nstatic void SDL_AMediaCodecBufferProxy_destroyP(SDL_AMediaCodecBufferProxy **proxy)\n{\n    if (!proxy)\n        return;\n    SDL_AMediaCodecBufferProxy_destroy(*proxy);\n    *proxy = NULL;\n}\n\nstatic void SDL_AMediaCodecBufferProxy_invalidate(SDL_AMediaCodecBufferProxy *proxy)\n{\n    SDL_AMediaCodecBufferProxy_reset(proxy);\n}\n\ntypedef struct SDL_Vout_Opaque {\n    ANativeWindow   *native_window;\n    SDL_AMediaCodec *acodec;\n    int              null_native_window_warned; // reduce log for null window\n    int              next_buffer_id;\n\n    ISDL_Array       overlay_manager;\n    ISDL_Array       overlay_pool;\n\n    IJK_EGL         *egl;\n} SDL_Vout_Opaque;\n\nstatic SDL_VoutOverlay *func_create_overlay_l(int width, int height, int frame_format, SDL_Vout *vout)\n{\n    switch (frame_format) {\n    case IJK_AV_PIX_FMT__ANDROID_MEDIACODEC:\n        return SDL_VoutAMediaCodec_CreateOverlay(width, height, vout);\n    default:\n        return SDL_VoutFFmpeg_CreateOverlay(width, height, frame_format, vout);\n    }\n}\n\nstatic SDL_VoutOverlay *func_create_overlay(int width, int height, int frame_format, SDL_Vout *vout)\n{\n    SDL_LockMutex(vout->mutex);\n    SDL_VoutOverlay *overlay = func_create_overlay_l(width, height, frame_format, vout);\n    SDL_UnlockMutex(vout->mutex);\n    return overlay;\n}\n\nstatic void func_free_l(SDL_Vout *vout)\n{\n    if (!vout)\n        return;\n\n    SDL_Vout_Opaque *opaque = vout->opaque;\n    if (opaque) {\n        SDL_AMediaCodecBufferProxy **begin = (SDL_AMediaCodecBufferProxy **)ISDL_Array__begin(&opaque->overlay_manager);\n        SDL_AMediaCodecBufferProxy **end   = (SDL_AMediaCodecBufferProxy **)ISDL_Array__end(&opaque->overlay_manager);\n        for (; begin < end; ++begin) {\n            SDL_AMediaCodecBufferProxy_destroyP(begin);\n        }\n        ISDL_Array__clear(&opaque->overlay_pool);\n        ISDL_Array__clear(&opaque->overlay_manager);\n\n        if (opaque->native_window) {\n            ANativeWindow_release(opaque->native_window);\n            opaque->native_window = NULL;\n        }\n\n        IJK_EGL_freep(&opaque->egl);\n\n        SDL_AMediaCodec_decreaseReferenceP(&opaque->acodec);\n    }\n\n    SDL_Vout_FreeInternal(vout);\n}\n\nstatic int func_display_overlay_l(SDL_Vout *vout, SDL_VoutOverlay *overlay)\n{\n    SDL_Vout_Opaque *opaque = vout->opaque;\n    ANativeWindow *native_window = opaque->native_window;\n\n    if (!native_window) {\n        if (!opaque->null_native_window_warned) {\n            opaque->null_native_window_warned = 1;\n            ALOGW(\"func_display_overlay_l: NULL native_window\");\n        }\n        return -1;\n    } else {\n        opaque->null_native_window_warned = 1;\n    }\n\n    if (!overlay) {\n        ALOGE(\"func_display_overlay_l: NULL overlay\");\n        return -1;\n    }\n\n    if (overlay->w <= 0 || overlay->h <= 0) {\n        ALOGE(\"func_display_overlay_l: invalid overlay dimensions(%d, %d)\", overlay->w, overlay->h);\n        return -1;\n    }\n\n    switch(overlay->format) {\n    case SDL_FCC__AMC: {\n        // only ANativeWindow support\n        IJK_EGL_terminate(opaque->egl);\n        return SDL_VoutOverlayAMediaCodec_releaseFrame_l(overlay, NULL, true);\n    }\n    case SDL_FCC_RV24:\n    case SDL_FCC_I420:\n    case SDL_FCC_I444P10LE: {\n        // only GLES support\n        if (opaque->egl)\n            return IJK_EGL_display(opaque->egl, native_window, overlay);\n        break;\n    }\n    case SDL_FCC_YV12:\n    case SDL_FCC_RV16:\n    case SDL_FCC_RV32: {\n        // both GLES & ANativeWindow support\n        if (vout->overlay_format == SDL_FCC__GLES2 && opaque->egl)\n            return IJK_EGL_display(opaque->egl, native_window, overlay);\n        break;\n    }\n    }\n\n    // fallback to ANativeWindow\n    IJK_EGL_terminate(opaque->egl);\n    return SDL_Android_NativeWindow_display_l(native_window, overlay); \n}\n\nstatic int func_display_overlay(SDL_Vout *vout, SDL_VoutOverlay *overlay)\n{\n    SDL_LockMutex(vout->mutex);\n    int retval = func_display_overlay_l(vout, overlay);\n    SDL_UnlockMutex(vout->mutex);\n    return retval;\n}\n\nstatic SDL_Class g_nativewindow_class = {\n    .name = \"ANativeWindow_Vout\",\n};\n\nSDL_Vout *SDL_VoutAndroid_CreateForANativeWindow()\n{\n    SDL_Vout *vout = SDL_Vout_CreateInternal(sizeof(SDL_Vout_Opaque));\n    if (!vout)\n        return NULL;\n\n    SDL_Vout_Opaque *opaque = vout->opaque;\n    opaque->native_window = NULL;\n    if (ISDL_Array__init(&opaque->overlay_manager, 32))\n        goto fail;\n    if (ISDL_Array__init(&opaque->overlay_pool, 32))\n        goto fail;\n\n    opaque->egl = IJK_EGL_create();\n    if (!opaque->egl)\n        goto fail;\n\n    vout->opaque_class    = &g_nativewindow_class;\n    vout->create_overlay  = func_create_overlay;\n    vout->free_l          = func_free_l;\n    vout->display_overlay = func_display_overlay;\n\n    return vout;\nfail:\n    func_free_l(vout);\n    return NULL;\n}\n\nstatic void SDL_VoutAndroid_invalidateAllBuffers_l(SDL_Vout *vout)\n{\n    AMCTRACE(\"%s\\n\", __func__);\n    SDL_Vout_Opaque *opaque = vout->opaque;\n\n    SDL_AMediaCodecBufferProxy **begin = (SDL_AMediaCodecBufferProxy **)ISDL_Array__begin(&opaque->overlay_manager);\n    SDL_AMediaCodecBufferProxy **end   = (SDL_AMediaCodecBufferProxy **)ISDL_Array__end(&opaque->overlay_manager);\n    for (; begin < end; ++begin) {\n        SDL_AMediaCodecBufferProxy_invalidate(*begin);\n    }\n}\n\nvoid SDL_VoutAndroid_invalidateAllBuffers(SDL_Vout *vout)\n{\n    SDL_LockMutex(vout->mutex);\n    SDL_VoutAndroid_invalidateAllBuffers_l(vout);\n    SDL_UnlockMutex(vout->mutex);\n}\n\nstatic void SDL_VoutAndroid_SetNativeWindow_l(SDL_Vout *vout, ANativeWindow *native_window)\n{\n    AMCTRACE(\"%s(%p, %p)\\n\", __func__, vout, native_window);\n    SDL_Vout_Opaque *opaque = vout->opaque;\n\n    if (opaque->native_window == native_window) {\n        if (native_window == NULL) {\n            // always invalidate buffers, if native_window is changed\n            SDL_VoutAndroid_invalidateAllBuffers_l(vout);\n        }\n        return;\n    }\n\n    IJK_EGL_terminate(opaque->egl);\n    SDL_VoutAndroid_invalidateAllBuffers_l(vout);\n\n    if (opaque->native_window)\n        ANativeWindow_release(opaque->native_window);\n\n    if (native_window)\n        ANativeWindow_acquire(native_window);\n\n    opaque->native_window = native_window;\n    opaque->null_native_window_warned = 0;\n}\n\nvoid SDL_VoutAndroid_SetNativeWindow(SDL_Vout *vout, ANativeWindow *native_window)\n{\n    SDL_LockMutex(vout->mutex);\n    SDL_VoutAndroid_SetNativeWindow_l(vout, native_window);\n    SDL_UnlockMutex(vout->mutex);\n}\n\nstatic void SDL_VoutAndroid_setAMediaCodec_l(SDL_Vout *vout, SDL_AMediaCodec *acodec)\n{\n    AMCTRACE(\"%s(%p)\\n\", __func__, acodec);\n    SDL_Vout_Opaque *opaque = vout->opaque;\n    if (opaque->acodec == acodec)\n        return;\n\n    SDL_VoutAndroid_invalidateAllBuffers_l(vout);\n\n    SDL_AMediaCodec_decreaseReferenceP(&opaque->acodec);\n    opaque->acodec = acodec;\n    if (opaque->acodec)\n        SDL_AMediaCodec_increaseReference(opaque->acodec);\n}\n\nvoid SDL_VoutAndroid_setAMediaCodec(SDL_Vout *vout, SDL_AMediaCodec *acodec)\n{\n    SDL_LockMutex(vout->mutex);\n    SDL_VoutAndroid_setAMediaCodec_l(vout, acodec);\n    SDL_UnlockMutex(vout->mutex);\n}\n\nSDL_AMediaCodec *SDL_VoutAndroid_peekAMediaCodec(SDL_Vout *vout)\n{\n    SDL_Vout_Opaque *opaque = vout->opaque;\n    SDL_AMediaCodec *acodec = NULL;\n\n    SDL_LockMutex(vout->mutex);\n    acodec = opaque->acodec;\n    SDL_UnlockMutex(vout->mutex);\n    return acodec;\n}\n\nstatic SDL_AMediaCodecBufferProxy *SDL_VoutAndroid_obtainBufferProxy_l(SDL_Vout *vout, int acodec_serial, int buffer_index, SDL_AMediaCodecBufferInfo *buffer_info)\n{\n    SDL_Vout_Opaque *opaque = vout->opaque;\n    SDL_AMediaCodecBufferProxy *proxy = NULL;\n\n    if (ISDL_Array__size(&opaque->overlay_pool) > 0) {\n        proxy = ISDL_Array__pop_back(&opaque->overlay_pool);\n        SDL_AMediaCodecBufferProxy_reset(proxy);\n    } else {\n        proxy = (SDL_AMediaCodecBufferProxy *)mallocz(sizeof(SDL_AMediaCodecBufferProxy));\n        if (!proxy)\n            return NULL;\n        SDL_AMediaCodecBufferProxy_init(proxy);\n        ISDL_Array__push_back(&opaque->overlay_manager, proxy);\n    }\n\n    proxy->buffer_id     = opaque->next_buffer_id++;\n    proxy->acodec_serial = acodec_serial;\n    proxy->buffer_index  = buffer_index;\n    proxy->buffer_info   = *buffer_info;\n    AMCTRACE(\"%s: [%d] ++++++++ proxy %d: vout: %d idx: %d fake: %s\",\n        __func__,\n        proxy->buffer_id,\n        proxy->acodec_serial,\n        SDL_AMediaCodec_getSerial(opaque->acodec),\n        proxy->buffer_index,\n        (proxy->buffer_info.flags & AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME) ? \"YES\" : \"NO\");\n    return proxy;\n}\n\nSDL_AMediaCodecBufferProxy *SDL_VoutAndroid_obtainBufferProxy(SDL_Vout *vout, int acodec_serial, int buffer_index, SDL_AMediaCodecBufferInfo *buffer_info)\n{\n    SDL_AMediaCodecBufferProxy *proxy = NULL;\n    SDL_LockMutex(vout->mutex);\n    proxy = SDL_VoutAndroid_obtainBufferProxy_l(vout, acodec_serial, buffer_index, buffer_info);\n    SDL_UnlockMutex(vout->mutex);\n    return proxy;\n}\n\nstatic int SDL_VoutAndroid_releaseBufferProxy_l(SDL_Vout *vout, SDL_AMediaCodecBufferProxy *proxy, bool render)\n{\n    SDL_Vout_Opaque *opaque = vout->opaque;\n\n    if (!proxy)\n        return 0;\n\n    AMCTRACE(\"%s: [%d] -------- proxy %d: vout: %d idx: %d render: %s fake: %s\",\n        __func__,\n        proxy->buffer_id,\n        proxy->acodec_serial,\n        SDL_AMediaCodec_getSerial(opaque->acodec),\n        proxy->buffer_index,\n        render ? \"true\" : \"false\",\n        (proxy->buffer_info.flags & AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME) ? \"YES\" : \"NO\");\n    ISDL_Array__push_back(&opaque->overlay_pool, proxy);\n\n    if (!SDL_AMediaCodec_isSameSerial(opaque->acodec, proxy->acodec_serial)) {\n        ALOGW(\"%s: [%d] ???????? proxy %d: vout: %d idx: %d render: %s fake: %s\",\n            __func__,\n            proxy->buffer_id,\n            proxy->acodec_serial,\n            SDL_AMediaCodec_getSerial(opaque->acodec),\n            proxy->buffer_index, \n            render ? \"true\" : \"false\",\n            (proxy->buffer_info.flags & AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME) ? \"YES\" : \"NO\");\n        return 0;\n    }\n\n    if (proxy->buffer_index < 0) {\n        ALOGE(\"%s: [%d] invalid AMediaCodec buffer index %d\\n\", __func__, proxy->buffer_id, proxy->buffer_index);\n        return 0;\n    } else if (proxy->buffer_info.flags & AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME) {\n        proxy->buffer_index = -1;\n        return 0;\n    }\n\n    sdl_amedia_status_t amc_ret = SDL_AMediaCodec_releaseOutputBuffer(opaque->acodec, proxy->buffer_index, render);    \n    if (amc_ret != SDL_AMEDIA_OK) {\n        ALOGW(\"%s: [%d] !!!!!!!! proxy %d: vout: %d idx: %d render: %s, fake: %s\",\n            __func__,\n            proxy->buffer_id,\n            proxy->acodec_serial,\n            SDL_AMediaCodec_getSerial(opaque->acodec),\n            proxy->buffer_index, \n            render ? \"true\" : \"false\",\n            (proxy->buffer_info.flags & AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME) ? \"YES\" : \"NO\");\n        proxy->buffer_index = -1;\n        return -1;\n    }\n    proxy->buffer_index = -1;\n\n    return 0;\n}\n\nstatic int SDL_VoutAndroid_releaseBufferProxy(SDL_Vout *vout, SDL_AMediaCodecBufferProxy *proxy, bool render)\n{\n    int ret = 0;\n\n    if (!proxy)\n        return 0;\n\n    SDL_LockMutex(vout->mutex);\n    ret = SDL_VoutAndroid_releaseBufferProxy_l(vout, proxy, render);\n    SDL_UnlockMutex(vout->mutex);\n    return ret;\n}\n\nint SDL_VoutAndroid_releaseBufferProxyP(SDL_Vout *vout, SDL_AMediaCodecBufferProxy **proxy, bool render)\n{\n    int ret = 0;\n\n    if (!proxy)\n        return 0;\n\n    ret = SDL_VoutAndroid_releaseBufferProxy(vout, *proxy, render);\n    *proxy = NULL;\n    return ret;\n}\n\nint SDL_VoutAndroid_releaseBufferProxyP_l(SDL_Vout *vout, SDL_AMediaCodecBufferProxy **proxy, bool render)\n{\n    int ret = 0;\n\n    if (!proxy)\n        return 0;\n\n    ret = SDL_VoutAndroid_releaseBufferProxy_l(vout, *proxy, render);\n    *proxy = NULL;\n    return ret;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_vout_android_nativewindow.h",
    "content": "/*****************************************************************************\n * ijksdl_vout_android_nativewindow.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL_ANDROID__IJKSDL_VOUT_ANDROID_NATIVEWINDOW_H\n#define IJKSDL_ANDROID__IJKSDL_VOUT_ANDROID_NATIVEWINDOW_H\n\n#include \"../ijksdl_stdinc.h\"\n#include \"../ijksdl_vout.h\"\n\ntypedef struct ANativeWindow   ANativeWindow;\ntypedef struct SDL_AMediaCodec SDL_AMediaCodec;\n\nSDL_Vout *SDL_VoutAndroid_CreateForANativeWindow();\nvoid SDL_VoutAndroid_SetNativeWindow(SDL_Vout *vout, ANativeWindow *native_window);\nvoid             SDL_VoutAndroid_setAMediaCodec(SDL_Vout *vout, SDL_AMediaCodec *acodec);\nSDL_AMediaCodec *SDL_VoutAndroid_peekAMediaCodec(SDL_Vout *vout);\nvoid             SDL_VoutAndroid_invalidateAllBuffers(SDL_Vout *vout);\n\n/*\n * MediaCodec buffer proxy\n */\n\ntypedef struct SDL_AMediaCodecBufferInfo SDL_AMediaCodecBufferInfo;\ntypedef struct SDL_AMediaCodecBufferProxy SDL_AMediaCodecBufferProxy;\nvoid SDL_AMediaCodecBufferProxy_lock(SDL_AMediaCodecBufferProxy *proxy);\nvoid SDL_AMediaCodecBufferProxy_unlock(SDL_AMediaCodecBufferProxy *proxy);\n\nSDL_AMediaCodecBufferProxy *SDL_VoutAndroid_obtainBufferProxy(SDL_Vout *vout, int acodec_serial, int buffer_index, SDL_AMediaCodecBufferInfo *buffer_info);\nint SDL_VoutAndroid_releaseBufferProxyP(SDL_Vout *vout, SDL_AMediaCodecBufferProxy **proxy, bool render);\nint SDL_VoutAndroid_releaseBufferProxyP_l(SDL_Vout *vout, SDL_AMediaCodecBufferProxy **proxy, bool render);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_vout_android_surface.c",
    "content": "/*****************************************************************************\n * ijksdl_vout_android_surface.c\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl_vout_android_surface.h\"\n\n#include <android/native_window_jni.h>\n#include \"../ijksdl_inc_internal.h\"\n#include \"ijksdl_android_jni.h\"\n#include \"ijksdl_vout_android_nativewindow.h\"\n\nSDL_Vout *SDL_VoutAndroid_CreateForAndroidSurface()\n{\n    return SDL_VoutAndroid_CreateForANativeWindow();\n}\n\nvoid SDL_VoutAndroid_SetAndroidSurface(JNIEnv *env, SDL_Vout *vout, jobject android_surface)\n{\n    ANativeWindow *native_window = NULL;\n    if (android_surface) {\n        native_window = ANativeWindow_fromSurface(env, android_surface);\n        if (!native_window) {\n            ALOGE(\"%s: ANativeWindow_fromSurface: failed\\n\", __func__);\n            // do not return fail here;\n        }\n    }\n\n    SDL_VoutAndroid_SetNativeWindow(vout, native_window);\n    if (native_window)\n        ANativeWindow_release(native_window);\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_vout_android_surface.h",
    "content": "/*****************************************************************************\n * ijksdl_vout_android_surface.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL_ANDROID__IJKSDL_VOUT_ANDROID_SURFACE_H\n#define IJKSDL_ANDROID__IJKSDL_VOUT_ANDROID_SURFACE_H\n\n#include <jni.h>\n#include \"../ijksdl_stdinc.h\"\n#include \"../ijksdl_vout.h\"\n\nSDL_Vout *SDL_VoutAndroid_CreateForAndroidSurface();\nvoid SDL_VoutAndroid_SetAndroidSurface(JNIEnv*env, SDL_Vout *vout, jobject android_surface);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_vout_overlay_android_mediacodec.c",
    "content": "/*****************************************************************************\n * ijksdl_vout_overlay_android_mediacodec.c\n *****************************************************************************\n *\n * Copyright (c) 2014 Bilibili\n * copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl_vout_overlay_android_mediacodec.h\"\n#include <assert.h>\n#include \"ijksdl/ijksdl_stdinc.h\"\n#include \"ijksdl/ijksdl_mutex.h\"\n#include \"ijksdl/ijksdl_vout_internal.h\"\n#include \"ijksdl/ijksdl_video.h\"\n#include \"ijksdl_vout_android_nativewindow.h\"\n#include \"ijksdl_codec_android_mediacodec.h\"\n#include \"ijksdl_inc_internal_android.h\"\n\n#ifndef AMCTRACE\n#define AMCTRACE(...)\n#endif\n\ntypedef struct SDL_VoutOverlay_Opaque {\n    SDL_mutex *mutex;\n\n    SDL_Vout                   *vout;\n    SDL_AMediaCodec            *acodec;\n\n    SDL_AMediaCodecBufferProxy *buffer_proxy;\n\n    Uint16 pitches[AV_NUM_DATA_POINTERS];\n    Uint8 *pixels[AV_NUM_DATA_POINTERS];\n} SDL_VoutOverlay_Opaque;\n\nstatic int overlay_lock(SDL_VoutOverlay *overlay)\n{\n    SDL_VoutOverlay_Opaque *opaque = overlay->opaque;\n    return SDL_LockMutex(opaque->mutex);\n}\n\nstatic int overlay_unlock(SDL_VoutOverlay *overlay)\n{\n    SDL_VoutOverlay_Opaque *opaque = overlay->opaque;\n    return SDL_UnlockMutex(opaque->mutex);\n}\n\nstatic void overlay_unref(SDL_VoutOverlay *overlay)\n{\n    SDL_VoutOverlay_Opaque *opaque = overlay->opaque;\n\n    SDL_VoutAndroid_releaseBufferProxyP(opaque->vout, &opaque->buffer_proxy, false);\n}\n\nstatic void overlay_free_l(SDL_VoutOverlay *overlay)\n{\n    AMCTRACE(\"SDL_Overlay(mediacodec): overlay_free_l(%p)\\n\", overlay);\n    if (!overlay)\n        return;\n\n    SDL_VoutOverlay_Opaque *opaque = overlay->opaque;\n    if (!opaque)\n        return;\n\n    overlay_unref(overlay);\n\n    if (opaque->mutex)\n        SDL_DestroyMutex(opaque->mutex);\n\n    SDL_VoutOverlay_FreeInternal(overlay);\n}\n\nstatic SDL_Class g_vout_overlay_amediacodec_class = {\n    .name = \"AndroidMediaCodecVoutOverlay\",\n};\n\ninline static bool check_object(SDL_VoutOverlay* object, const char *func_name)\n{\n    if (!object || !object->opaque || !object->opaque_class) {\n        ALOGE(\"%s.%s: invalid pipeline\\n\", object->opaque_class->name, func_name);\n        return false;\n    }\n\n    if (object->opaque_class != &g_vout_overlay_amediacodec_class) {\n        ALOGE(\"%s.%s: unsupported method\\n\", object->opaque_class->name, func_name);\n        return false;\n    }\n\n    return true;\n}\n\nstatic int func_fill_frame(SDL_VoutOverlay *overlay, const AVFrame *frame)\n{\n    assert(frame->format == IJK_AV_PIX_FMT__ANDROID_MEDIACODEC);\n\n    SDL_VoutOverlay_Opaque *opaque = overlay->opaque;\n\n    if (!check_object(overlay, __func__))\n        return -1;\n\n    if (opaque->buffer_proxy)\n        SDL_VoutAndroid_releaseBufferProxyP(opaque->vout, (SDL_AMediaCodecBufferProxy **)&opaque->buffer_proxy, false);\n\n    opaque->acodec       = SDL_VoutAndroid_peekAMediaCodec(opaque->vout);\n    // TODO: ref-count buffer_proxy?\n    opaque->buffer_proxy = (SDL_AMediaCodecBufferProxy *)frame->opaque;\n\n    overlay->opaque_class = &g_vout_overlay_amediacodec_class;\n    overlay->format     = SDL_FCC__AMC;\n    overlay->planes     = 1;\n    overlay->pixels[0]  = NULL;\n    overlay->pixels[1]  = NULL;\n    overlay->pitches[0] = 0;\n    overlay->pitches[1] = 0;\n    overlay->is_private = 1;\n\n    overlay->w = (int)frame->width;\n    overlay->h = (int)frame->height;\n    return 0;\n}\n\nSDL_VoutOverlay *SDL_VoutAMediaCodec_CreateOverlay(int width, int height, SDL_Vout *vout)\n{\n    SDLTRACE(\"SDL_VoutAMediaCodec_CreateOverlay(w=%d, h=%d, fmt=_AMC vout=%p)\\n\",\n        width, height, vout);\n    SDL_VoutOverlay *overlay = SDL_VoutOverlay_CreateInternal(sizeof(SDL_VoutOverlay_Opaque));\n    if (!overlay) {\n        ALOGE(\"overlay allocation failed\");\n        return NULL;\n    }\n\n    SDL_VoutOverlay_Opaque *opaque = overlay->opaque;\n    opaque->mutex         = SDL_CreateMutex();\n    opaque->vout          = vout;\n    opaque->acodec        = NULL;\n    opaque->buffer_proxy  = NULL;\n\n    overlay->opaque_class = &g_vout_overlay_amediacodec_class;\n    overlay->format       = SDL_FCC__AMC;\n    overlay->pitches      = opaque->pitches;\n    overlay->pixels       = opaque->pixels;\n    overlay->w            = width;\n    overlay->h            = height;\n    overlay->is_private   = 1;\n\n    overlay->free_l       = overlay_free_l;\n    overlay->lock         = overlay_lock;\n    overlay->unlock       = overlay_unlock;\n    overlay->unref        = overlay_unref;\n    overlay->func_fill_frame = func_fill_frame;\n\n    if (!opaque->mutex) {\n        ALOGE(\"SDL_CreateMutex failed\");\n        goto fail;\n    }\n\n    return overlay;\n\nfail:\n    overlay_free_l(overlay);\n    return NULL;\n}\n\nbool SDL_VoutOverlayAMediaCodec_isKindOf(SDL_VoutOverlay *overlay)\n{\n    return check_object(overlay, __func__);\n}\n\nint  SDL_VoutOverlayAMediaCodec_releaseFrame_l(SDL_VoutOverlay *overlay, SDL_AMediaCodec *acodec, bool render)\n{\n    if (!check_object(overlay, __func__))\n        return -1;\n\n    SDL_VoutOverlay_Opaque *opaque = overlay->opaque;\n    return SDL_VoutAndroid_releaseBufferProxyP_l(opaque->vout, &opaque->buffer_proxy, render);\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/android/ijksdl_vout_overlay_android_mediacodec.h",
    "content": "/*****************************************************************************\n * ijksdl_vout_overlay_android_mediacodec.h\n *****************************************************************************\n *\n * Copyright (c) 2014 Bilibili\n * copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL_ANDROID__IJKSDL_VOUT_OVERLAY_ANDROID_MEDIACODEC_H\n#define IJKSDL_ANDROID__IJKSDL_VOUT_OVERLAY_ANDROID_MEDIACODEC_H\n\n#include \"../ijksdl_stdinc.h\"\n#include \"../ijksdl_vout.h\"\n\ntypedef struct SDL_AMediaCodec           SDL_AMediaCodec;\ntypedef struct SDL_AMediaCodecBufferInfo SDL_AMediaCodecBufferInfo;\n\nSDL_VoutOverlay *SDL_VoutAMediaCodec_CreateOverlay(int width, int height, SDL_Vout *vout);\n\nbool SDL_VoutOverlayAMediaCodec_isKindOf(SDL_VoutOverlay *overlay);\nint  SDL_VoutOverlayAMediaCodec_releaseFrame_l(SDL_VoutOverlay *overlay, SDL_AMediaCodec *acodec, bool render);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/dummy/ijksdl_dummy.h",
    "content": "/*****************************************************************************\n * ijksdl_dummy.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL_DUMMY__IJKSDL_DUMMY_H\n#define IJKSDL_DUMMY__IJKSDL_DUMMY_H\n\n#include \"../ijksdl.h\"\n\n// #include \"ijksdl_aout_dummy.h\"\n\n#include \"ijksdl_vout_dummy.h\"\n\n#endif\n\n"
  },
  {
    "path": "ijkmedia/ijksdl/dummy/ijksdl_vout_dummy.c",
    "content": "/*****************************************************************************\n * ijksdl_vout_dummy.c\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl_vout_dummy.h\"\n\n#include \"../ijksdl_vout.h\"\n#include \"../ijksdl_vout_internal.h\"\n\ntypedef struct SDL_VoutSurface_Opaque {\n    SDL_Vout *vout;\n} SDL_VoutSurface_Opaque;\n\nstruct SDL_Vout_Opaque {\n    char dummy;\n};\n\nstatic void func_free_l(SDL_Vout *vout)\n{\n    if (!vout)\n        return;\n\n    SDL_Vout_Opaque *opaque = vout->opaque;\n    if (opaque) {\n    }\n\n    SDL_Vout_FreeInternal(vout);\n}\n\nstatic int func_display_overlay_l(SDL_Vout *vout, SDL_VoutOverlay *overlay)\n{\n    return 0;\n}\n\nstatic int func_display_overlay(SDL_Vout *vout, SDL_VoutOverlay *overlay)\n{\n    SDL_LockMutex(vout->mutex);\n    int retval = func_display_overlay_l(vout, overlay);\n    SDL_UnlockMutex(vout->mutex);\n    return retval;\n}\n\nSDL_Vout *SDL_VoutDummy_Create()\n{\n    SDL_Vout *vout = SDL_Vout_CreateInternal(sizeof(SDL_Vout_Opaque));\n    if (!vout)\n        return NULL;\n\n    // SDL_Vout_Opaque *opaque = vout->opaque;\n\n    vout->free_l = func_free_l;\n    vout->display_overlay = func_display_overlay;\n\n    return vout;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/dummy/ijksdl_vout_dummy.h",
    "content": "/*****************************************************************************\n * ijksdl_vout_dummy.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL_DUMMY__IJKSDL_VOUT_DUMMY_H\n#define IJKSDL_DUMMY__IJKSDL_VOUT_DUMMY_H\n\n#include \"../ijksdl_stdinc.h\"\n#include \"../ijksdl_vout.h\"\n\nSDL_Vout *SDL_VoutDummy_Create();\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/ffmpeg/abi_all/image_convert.c",
    "content": "/*****************************************************************************\n * yuv_rgb.c : ARM NEONv1 YUV to RGB32 chroma conversion for VLC\n *****************************************************************************\n * Copyright (C) 2011 Bilibili\n * Copyright (C) 2011 Sébastien Toque\n *                    Rémi Denis-Courmont\n * Copyright (C) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms of the GNU Lesser General Public License as published by\n * the Free Software Foundation; either version 2.1 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public License\n * along with this program; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.\n *****************************************************************************/\n\n#include \"../ijksdl_image_convert.h\"\n#if defined(__ANDROID__)\n#include \"libyuv.h\"\n#endif\n\nint ijk_image_convert(int width, int height,\n    enum AVPixelFormat dst_format, uint8_t **dst_data, int *dst_linesize,\n    enum AVPixelFormat src_format, const uint8_t **src_data, const int *src_linesize)\n{\n#if defined(__ANDROID__)\n    switch (src_format) {\n        case AV_PIX_FMT_YUV420P:\n        case AV_PIX_FMT_YUVJ420P: // FIXME: 9 not equal to AV_PIX_FMT_YUV420P, but a workaround\n            switch (dst_format) {\n            case AV_PIX_FMT_RGB565:\n                return I420ToRGB565(\n                    src_data[0], src_linesize[0],\n                    src_data[1], src_linesize[1],\n                    src_data[2], src_linesize[2],\n                    dst_data[0], dst_linesize[0],\n                    width, height);\n            case AV_PIX_FMT_0BGR32:\n                return I420ToABGR(\n                    src_data[0], src_linesize[0],\n                    src_data[1], src_linesize[1],\n                    src_data[2], src_linesize[2],\n                    dst_data[0], dst_linesize[0],\n                    width, height);\n            default:\n                break;\n            }\n            break;\n        default:\n            break;\n    }\n#endif\n    return -1;\n}\n\n"
  },
  {
    "path": "ijkmedia/ijksdl/ffmpeg/ijksdl_image_convert.h",
    "content": "/*\n * ijksdl_ffinc.h\n *      ffmpeg headers\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL__FFMPEG__IJKSDL_IMAGE_CONVERT_H\n#define IJKSDL__FFMPEG__IJKSDL_IMAGE_CONVERT_H\n\n#include <stdint.h>\n#include \"ijksdl_inc_ffmpeg.h\"\n\nint ijk_image_convert(int width, int height,\n    enum AVPixelFormat dst_format, uint8_t **dst_data, int *dst_linesize,\n    enum AVPixelFormat src_format, const uint8_t **src_data, const int *src_linesize);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/ffmpeg/ijksdl_inc_ffmpeg.h",
    "content": "/*\n * ijksdl_ffinc.h\n *      ffmpeg headers\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL__FFMPEG__IJKSDL_FFINC_H\n#define IJKSDL__FFMPEG__IJKSDL_FFINC_H\n\n#include \"libavutil/imgutils.h\"\n#include \"libavutil/pixfmt.h\"\n#include \"libavutil/frame.h\"\n#include \"libavutil/common.h\"\n#include \"libavcodec/avcodec.h\"\n#include \"libswscale/swscale.h\"\n\n#include \"../ijksdl_inc_internal.h\"\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/ffmpeg/ijksdl_vout_overlay_ffmpeg.c",
    "content": "/*****************************************************************************\n * ijksdl_vout_overlay_ffmpeg.c\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl_vout_overlay_ffmpeg.h\"\n\n#include <stdbool.h>\n#include <assert.h>\n#include \"../ijksdl_stdinc.h\"\n#include \"../ijksdl_misc.h\"\n#include \"../ijksdl_mutex.h\"\n#include \"../ijksdl_vout_internal.h\"\n#include \"../ijksdl_video.h\"\n#include \"ijksdl_inc_ffmpeg.h\"\n#include \"ijksdl_image_convert.h\"\n\nstruct SDL_VoutOverlay_Opaque {\n    SDL_mutex *mutex;\n\n    AVFrame *managed_frame;\n    AVBufferRef *frame_buffer;\n    int planes;\n\n    AVFrame *linked_frame;\n\n    Uint16 pitches[AV_NUM_DATA_POINTERS];\n    Uint8 *pixels[AV_NUM_DATA_POINTERS];\n\n    int no_neon_warned;\n\n    struct SwsContext *img_convert_ctx;\n    int sws_flags;\n};\n\n/* Always assume a linesize alignment of 1 here */\n// TODO: 9 alignment to speed up memcpy when display\nstatic AVFrame *opaque_setup_frame(SDL_VoutOverlay_Opaque* opaque, enum AVPixelFormat format, int width, int height)\n{\n    AVFrame *managed_frame = av_frame_alloc();\n    if (!managed_frame) {\n        return NULL;\n    }\n\n    AVFrame *linked_frame = av_frame_alloc();\n    if (!linked_frame) {\n        av_frame_free(&managed_frame);\n        return NULL;\n    }\n\n    /*-\n     * Lazily allocate frame buffer in opaque_obtain_managed_frame_buffer\n     *\n     * For refererenced frame management, we use buffer allocated by decoder\n     *\n    int frame_bytes = avpicture_get_size(format, width, height);\n    AVBufferRef *frame_buffer_ref = av_buffer_alloc(frame_bytes);\n    if (!frame_buffer_ref)\n        return NULL;\n    opaque->frame_buffer  = frame_buffer_ref;\n     */\n\n    managed_frame->format = format;\n    managed_frame->width  = width;\n    managed_frame->height = height;\n    av_image_fill_arrays(managed_frame->data, managed_frame->linesize ,NULL,\n                         format, width, height, 1);\n    opaque->managed_frame = managed_frame;\n    opaque->linked_frame  = linked_frame;\n    return managed_frame;\n}\n\nstatic AVFrame *opaque_obtain_managed_frame_buffer(SDL_VoutOverlay_Opaque* opaque)\n{\n    if (opaque->frame_buffer != NULL)\n        return opaque->managed_frame;\n\n    AVFrame *managed_frame = opaque->managed_frame;\n    int frame_bytes = av_image_get_buffer_size(managed_frame->format, managed_frame->width, managed_frame->height, 1);\n    AVBufferRef *frame_buffer_ref = av_buffer_alloc(frame_bytes);\n    if (!frame_buffer_ref)\n        return NULL;\n\n    av_image_fill_arrays(managed_frame->data, managed_frame->linesize,\n                         frame_buffer_ref->data, managed_frame->format, managed_frame->width, managed_frame->height, 1);\n    opaque->frame_buffer  = frame_buffer_ref;\n    return opaque->managed_frame;\n}\n\nstatic void func_free_l(SDL_VoutOverlay *overlay)\n{\n    ALOGE(\"SDL_Overlay(ffmpeg): overlay_free_l(%p)\\n\", overlay);\n    if (!overlay)\n        return;\n\n    SDL_VoutOverlay_Opaque *opaque = overlay->opaque;\n    if (!opaque)\n        return;\n\n    sws_freeContext(opaque->img_convert_ctx);\n\n    if (opaque->managed_frame)\n        av_frame_free(&opaque->managed_frame);\n\n    if (opaque->linked_frame) {\n        av_frame_unref(opaque->linked_frame);\n        av_frame_free(&opaque->linked_frame);\n    }\n\n    if (opaque->frame_buffer)\n        av_buffer_unref(&opaque->frame_buffer);\n\n    if (opaque->mutex)\n        SDL_DestroyMutex(opaque->mutex);\n\n    SDL_VoutOverlay_FreeInternal(overlay);\n}\n\nstatic void overlay_fill(SDL_VoutOverlay *overlay, AVFrame *frame, int planes)\n{\n    overlay->planes = planes;\n\n    for (int i = 0; i < AV_NUM_DATA_POINTERS; ++i) {\n        overlay->pixels[i] = frame->data[i];\n        overlay->pitches[i] = frame->linesize[i];\n    }\n}\n\nstatic int func_lock(SDL_VoutOverlay *overlay)\n{\n    SDL_VoutOverlay_Opaque *opaque = overlay->opaque;\n    return SDL_LockMutex(opaque->mutex);\n}\n\nstatic int func_unlock(SDL_VoutOverlay *overlay)\n{\n    SDL_VoutOverlay_Opaque *opaque = overlay->opaque;\n    return SDL_UnlockMutex(opaque->mutex);\n}\n\nstatic int func_fill_frame(SDL_VoutOverlay *overlay, const AVFrame *frame)\n{\n    assert(overlay);\n    SDL_VoutOverlay_Opaque *opaque = overlay->opaque;\n    AVFrame swscale_dst_pic = { { 0 } };\n\n    av_frame_unref(opaque->linked_frame);\n\n    int need_swap_uv = 0;\n    int use_linked_frame = 0;\n    enum AVPixelFormat dst_format = AV_PIX_FMT_NONE;\n    switch (overlay->format) {\n        case SDL_FCC_YV12:\n            need_swap_uv = 1;\n            // no break;\n        case SDL_FCC_I420:\n            if (frame->format == AV_PIX_FMT_YUV420P || frame->format == AV_PIX_FMT_YUVJ420P) {\n                // ALOGE(\"direct draw frame\");\n                use_linked_frame = 1;\n                dst_format = frame->format;\n            } else {\n                // ALOGE(\"copy draw frame\");\n                dst_format = AV_PIX_FMT_YUV420P;\n            }\n            break;\n        case SDL_FCC_I444P10LE:\n            if (frame->format == AV_PIX_FMT_YUV444P10LE) {\n                // ALOGE(\"direct draw frame\");\n                use_linked_frame = 1;\n                dst_format = frame->format;\n            } else {\n                // ALOGE(\"copy draw frame\");\n                dst_format = AV_PIX_FMT_YUV444P10LE;\n            }\n            break;\n        case SDL_FCC_RV32:\n            dst_format = AV_PIX_FMT_0BGR32;\n            break;\n        case SDL_FCC_RV24:\n            dst_format = AV_PIX_FMT_RGB24;\n            break;\n        case SDL_FCC_RV16:\n            dst_format = AV_PIX_FMT_RGB565;\n            break;\n        default:\n            ALOGE(\"SDL_VoutFFmpeg_ConvertPicture: unexpected overlay format %s(%d)\",\n                  (char*)&overlay->format, overlay->format);\n            return -1;\n    }\n\n\n    // setup frame\n    if (use_linked_frame) {\n        // linked frame\n        av_frame_ref(opaque->linked_frame, frame);\n\n        overlay_fill(overlay, opaque->linked_frame, opaque->planes);\n\n        if (need_swap_uv)\n            FFSWAP(Uint8*, overlay->pixels[1], overlay->pixels[2]);\n    } else {\n        // managed frame\n        AVFrame* managed_frame = opaque_obtain_managed_frame_buffer(opaque);\n        if (!managed_frame) {\n            ALOGE(\"OOM in opaque_obtain_managed_frame_buffer\");\n            return -1;\n        }\n\n        overlay_fill(overlay, opaque->managed_frame, opaque->planes);\n\n        // setup frame managed\n        for (int i = 0; i < overlay->planes; ++i) {\n            swscale_dst_pic.data[i] = overlay->pixels[i];\n            swscale_dst_pic.linesize[i] = overlay->pitches[i];\n        }\n\n        if (need_swap_uv)\n            FFSWAP(Uint8*, swscale_dst_pic.data[1], swscale_dst_pic.data[2]);\n    }\n\n\n    // swscale / direct draw\n    /*\n     ALOGE(\"ijk_image_convert w=%d, h=%d, df=%d, dd=%d, dl=%d, sf=%d, sd=%d, sl=%d\",\n     (int)frame->width,\n     (int)frame->height,\n     (int)dst_format,\n     (int)swscale_dst_pic.data[0],\n     (int)swscale_dst_pic.linesize[0],\n     (int)frame->format,\n     (int)(const uint8_t**) frame->data,\n     (int)frame->linesize);\n     */\n    if (use_linked_frame) {\n        // do nothing\n    } else if (ijk_image_convert(frame->width, frame->height,\n                                 dst_format, swscale_dst_pic.data, swscale_dst_pic.linesize,\n                                 frame->format, (const uint8_t**) frame->data, frame->linesize)) {\n        opaque->img_convert_ctx = sws_getCachedContext(opaque->img_convert_ctx,\n                                                       frame->width, frame->height, frame->format, frame->width, frame->height,\n                                                       dst_format, opaque->sws_flags, NULL, NULL, NULL);\n        if (opaque->img_convert_ctx == NULL) {\n            ALOGE(\"sws_getCachedContext failed\");\n            return -1;\n        }\n\n        sws_scale(opaque->img_convert_ctx, (const uint8_t**) frame->data, frame->linesize,\n                  0, frame->height, swscale_dst_pic.data, swscale_dst_pic.linesize);\n\n        if (!opaque->no_neon_warned) {\n            opaque->no_neon_warned = 1;\n            ALOGE(\"non-neon image convert %s -> %s\", av_get_pix_fmt_name(frame->format), av_get_pix_fmt_name(dst_format));\n        }\n    }\n    \n    // TODO: 9 draw black if overlay is larger than screen\n    return 0;\n}\n\nstatic SDL_Class g_vout_overlay_ffmpeg_class = {\n    .name = \"FFmpegVoutOverlay\",\n};\n\n#ifndef __clang_analyzer__\nSDL_VoutOverlay *SDL_VoutFFmpeg_CreateOverlay(int width, int height, int frame_format, SDL_Vout *display)\n{\n    Uint32 overlay_format = display->overlay_format;\n    switch (overlay_format) {\n        case SDL_FCC__GLES2: {\n            switch (frame_format) {\n                case AV_PIX_FMT_YUV444P10LE:\n                    overlay_format = SDL_FCC_I444P10LE;\n                    break;\n                case AV_PIX_FMT_YUV420P:\n                case AV_PIX_FMT_YUVJ420P:\n                default:\n#if defined(__ANDROID__)\n                    overlay_format = SDL_FCC_YV12;\n#else\n                    overlay_format = SDL_FCC_I420;\n#endif\n                    break;\n            }\n            break;\n        }\n    }\n\n    SDLTRACE(\"SDL_VoutFFmpeg_CreateOverlay(w=%d, h=%d, fmt=%.4s(0x%x, dp=%p)\\n\",\n        width, height, (const char*) &overlay_format, overlay_format, display);\n\n    SDL_VoutOverlay *overlay = SDL_VoutOverlay_CreateInternal(sizeof(SDL_VoutOverlay_Opaque));\n    if (!overlay) {\n        ALOGE(\"overlay allocation failed\");\n        return NULL;\n    }\n\n    SDL_VoutOverlay_Opaque *opaque = overlay->opaque;\n    opaque->mutex         = SDL_CreateMutex();\n    opaque->sws_flags     = SWS_BILINEAR;\n\n    overlay->opaque_class = &g_vout_overlay_ffmpeg_class;\n    overlay->format       = overlay_format;\n    overlay->pitches      = opaque->pitches;\n    overlay->pixels       = opaque->pixels;\n    overlay->w            = width;\n    overlay->h            = height;\n    overlay->free_l             = func_free_l;\n    overlay->lock               = func_lock;\n    overlay->unlock             = func_unlock;\n    overlay->func_fill_frame    = func_fill_frame;\n\n    enum AVPixelFormat ff_format = AV_PIX_FMT_NONE;\n    int buf_width = width;\n    int buf_height = height;\n    switch (overlay_format) {\n    case SDL_FCC_I420:\n    case SDL_FCC_YV12: {\n        ff_format = AV_PIX_FMT_YUV420P;\n        // FIXME: need runtime config\n#if defined(__ANDROID__)\n        // 16 bytes align pitch for arm-neon image-convert\n        buf_width = IJKALIGN(width, 16); // 1 bytes per pixel for Y-plane\n#elif defined(__APPLE__)\n        // 2^n align for width\n        buf_width = width;\n        if (width > 0)\n            buf_width = 1 << (sizeof(int) * 8 - __builtin_clz(width));\n#else\n        buf_width = IJKALIGN(width, 16); // unknown platform\n#endif\n        opaque->planes = 3;\n        break;\n    }\n    case SDL_FCC_I444P10LE: {\n        ff_format = AV_PIX_FMT_YUV444P10LE;\n        // FIXME: need runtime config\n#if defined(__ANDROID__)\n        // 16 bytes align pitch for arm-neon image-convert\n        buf_width = IJKALIGN(width, 16); // 1 bytes per pixel for Y-plane\n#elif defined(__APPLE__)\n        // 2^n align for width\n        buf_width = width;\n        if (width > 0)\n            buf_width = 1 << (sizeof(int) * 8 - __builtin_clz(width));\n#else\n        buf_width = IJKALIGN(width, 16); // unknown platform\n#endif\n        opaque->planes = 3;\n        break;\n    }\n    case SDL_FCC_RV16: {\n        ff_format = AV_PIX_FMT_RGB565;\n        buf_width = IJKALIGN(width, 8); // 2 bytes per pixel\n        opaque->planes = 1;\n        break;\n    }\n    case SDL_FCC_RV24: {\n        ff_format = AV_PIX_FMT_RGB24;\n#if defined(__ANDROID__)\n        // 16 bytes align pitch for arm-neon image-convert\n        buf_width = IJKALIGN(width, 16); // 1 bytes per pixel for Y-plane\n#elif defined(__APPLE__)\n        buf_width = width;\n#else\n        buf_width = IJKALIGN(width, 16); // unknown platform\n#endif\n        opaque->planes = 1;\n        break;\n    }\n    case SDL_FCC_RV32: {\n        ff_format = AV_PIX_FMT_0BGR32;\n        buf_width = IJKALIGN(width, 4); // 4 bytes per pixel\n        opaque->planes = 1;\n        break;\n    }\n    default:\n        ALOGE(\"SDL_VoutFFmpeg_CreateOverlay(...): unknown format %.4s(0x%x)\\n\", (char*)&overlay_format, overlay_format);\n        goto fail;\n    }\n\n    opaque->managed_frame = opaque_setup_frame(opaque, ff_format, buf_width, buf_height);\n    if (!opaque->managed_frame) {\n        ALOGE(\"overlay->opaque->frame allocation failed\\n\");\n        goto fail;\n    }\n    overlay_fill(overlay, opaque->managed_frame, opaque->planes);\n\n    return overlay;\n\nfail:\n    func_free_l(overlay);\n    return NULL;\n}\n#endif//__clang_analyzer__\n"
  },
  {
    "path": "ijkmedia/ijksdl/ffmpeg/ijksdl_vout_overlay_ffmpeg.h",
    "content": "/*****************************************************************************\n * ijksdl_vout_overlay_ffmpeg.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL__FFMPEG__IJKSDL_VOUT_OVERLAY_FFMPEG_H\n#define IJKSDL__FFMPEG__IJKSDL_VOUT_OVERLAY_FFMPEG_H\n\n#include \"../ijksdl_stdinc.h\"\n#include \"../ijksdl_vout.h\"\n#include \"ijksdl_inc_ffmpeg.h\"\n\n// TODO: 9 alignment to speed up memcpy when display\nSDL_VoutOverlay *SDL_VoutFFmpeg_CreateOverlay(int width, int height, int frame_format, SDL_Vout *vout);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/gles2/color.c",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"internal.h\"\n\n// BT.709, which is the standard for HDTV.\nstatic const GLfloat g_bt709[] = {\n    1.164,  1.164,  1.164,\n    0.0,   -0.213,  2.112,\n    1.793, -0.533,  0.0,\n};\nconst GLfloat *IJK_GLES2_getColorMatrix_bt709()\n{\n    return g_bt709;\n}\n\nstatic const GLfloat g_bt601[] = {\n    1.164,  1.164, 1.164,\n    0.0,   -0.392, 2.017,\n    1.596, -0.813, 0.0,\n};\nconst GLfloat *IJK_GLES2_getColorMatrix_bt601()\n{\n    return g_bt601;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/gles2/common.c",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"internal.h\"\n\nvoid IJK_GLES2_checkError(const char* op) {\n    for (GLint error = glGetError(); error; error = glGetError()) {\n        ALOGE(\"[GLES2] after %s() glError (0x%x)\\n\", op, error);\n    }\n}\n\nvoid IJK_GLES2_printString(const char *name, GLenum s) {\n    const char *v = (const char *) glGetString(s);\n    ALOGI(\"[GLES2] %s = %s\\n\", name, v);\n}\n\nvoid IJK_GLES2_loadOrtho(IJK_GLES_Matrix *matrix, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far)\n{\n    GLfloat r_l = right - left;\n    GLfloat t_b = top - bottom;\n    GLfloat f_n = far - near;\n    GLfloat tx = - (right + left) / (right - left);\n    GLfloat ty = - (top + bottom) / (top - bottom);\n    GLfloat tz = - (far + near) / (far - near);\n\n    matrix->m[0] = 2.0f / r_l;\n    matrix->m[1] = 0.0f;\n    matrix->m[2] = 0.0f;\n    matrix->m[3] = 0.0f;\n\n    matrix->m[4] = 0.0f;\n    matrix->m[5] = 2.0f / t_b;\n    matrix->m[6] = 0.0f;\n    matrix->m[7] = 0.0f;\n\n    matrix->m[8] = 0.0f;\n    matrix->m[9] = 0.0f;\n    matrix->m[10] = -2.0f / f_n;\n    matrix->m[11] = 0.0f;\n\n    matrix->m[12] = tx;\n    matrix->m[13] = ty;\n    matrix->m[14] = tz;\n    matrix->m[15] = 1.0f;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/gles2/fsh/rgb.fsh.c",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl/gles2/internal.h\"\n\nstatic const char g_shader[] = IJK_GLES_STRING(\n    precision highp float;\n    varying   highp vec2 vv2_Texcoord;\n    uniform   lowp  sampler2D us2_SamplerX;\n\n    void main()\n    {\n        gl_FragColor = vec4(texture2D(us2_SamplerX, vv2_Texcoord).rgb, 1);\n    }\n);\n\nconst char *IJK_GLES2_getFragmentShader_rgb()\n{\n    return g_shader;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/gles2/fsh/yuv420p.fsh.c",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl/gles2/internal.h\"\n\nstatic const char g_shader[] = IJK_GLES_STRING(\n    precision highp float;\n    varying   highp vec2 vv2_Texcoord;\n    uniform         mat3 um3_ColorConversion;\n    uniform   lowp  sampler2D us2_SamplerX;\n    uniform   lowp  sampler2D us2_SamplerY;\n    uniform   lowp  sampler2D us2_SamplerZ;\n\n    void main()\n    {\n        mediump vec3 yuv;\n        lowp    vec3 rgb;\n\n        yuv.x = (texture2D(us2_SamplerX, vv2_Texcoord).r - (16.0 / 255.0));\n        yuv.y = (texture2D(us2_SamplerY, vv2_Texcoord).r - 0.5);\n        yuv.z = (texture2D(us2_SamplerZ, vv2_Texcoord).r - 0.5);\n        rgb = um3_ColorConversion * yuv;\n        gl_FragColor = vec4(rgb, 1);\n    }\n);\n\nconst char *IJK_GLES2_getFragmentShader_yuv420p()\n{\n    return g_shader;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/gles2/fsh/yuv420sp.fsh.c",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl/gles2/internal.h\"\n\nstatic const char g_shader[] = IJK_GLES_STRING(\n    precision highp float;\n    varying   highp vec2 vv2_Texcoord;\n    uniform         mat3 um3_ColorConversion;\n    uniform   lowp  sampler2D us2_SamplerX;\n    uniform   lowp  sampler2D us2_SamplerY;\n\n    void main()\n    {\n        mediump vec3 yuv;\n        lowp    vec3 rgb;\n\n        yuv.x  = (texture2D(us2_SamplerX,  vv2_Texcoord).r  - (16.0 / 255.0));\n        yuv.yz = (texture2D(us2_SamplerY,  vv2_Texcoord).rg - vec2(0.5, 0.5));\n        rgb = um3_ColorConversion * yuv;\n        gl_FragColor = vec4(rgb, 1);\n    }\n);\n\nconst char *IJK_GLES2_getFragmentShader_yuv420sp()\n{\n    return g_shader;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/gles2/fsh/yuv444p10le.fsh.c",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl/gles2/internal.h\"\n\nstatic const char g_shader[] = IJK_GLES_STRING(\n    precision highp float;\n    varying   highp vec2 vv2_Texcoord;\n    uniform         mat3 um3_ColorConversion;\n    uniform   lowp  sampler2D us2_SamplerX;\n    uniform   lowp  sampler2D us2_SamplerY;\n    uniform   lowp  sampler2D us2_SamplerZ;\n\n    void main()\n    {\n        mediump vec3 yuv_l;\n        mediump vec3 yuv_h;\n        mediump vec3 yuv;\n        lowp    vec3 rgb;\n\n        yuv_l.x = texture2D(us2_SamplerX, vv2_Texcoord).r;\n        yuv_h.x = texture2D(us2_SamplerX, vv2_Texcoord).a;\n        yuv_l.y = texture2D(us2_SamplerY, vv2_Texcoord).r;\n        yuv_h.y = texture2D(us2_SamplerY, vv2_Texcoord).a;\n        yuv_l.z = texture2D(us2_SamplerZ, vv2_Texcoord).r;\n        yuv_h.z = texture2D(us2_SamplerZ, vv2_Texcoord).a;\n\n        yuv = (yuv_l * 255.0 + yuv_h * 255.0 * 256.0) / (1023.0) - vec3(16.0 / 255.0, 0.5, 0.5);\n\n        rgb = um3_ColorConversion * yuv;\n        gl_FragColor = vec4(rgb, 1);\n    }\n);\n\nconst char *IJK_GLES2_getFragmentShader_yuv444p10le()\n{\n    return g_shader;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/gles2/internal.h",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL__IJKSDL_GLES2__INTERNAL__H\n#define IJKSDL__IJKSDL_GLES2__INTERNAL__H\n\n#include <assert.h>\n#include <stdlib.h>\n#include \"ijksdl/ijksdl_fourcc.h\"\n#include \"ijksdl/ijksdl_log.h\"\n#include \"ijksdl/ijksdl_gles2.h\"\n#include \"ijksdl/ijksdl_vout.h\"\n\n#define IJK_GLES_STRINGIZE(x)   #x\n#define IJK_GLES_STRINGIZE2(x)  IJK_GLES_STRINGIZE(x)\n#define IJK_GLES_STRING(x)      IJK_GLES_STRINGIZE2(x)\n\ntypedef struct IJK_GLES2_Renderer_Opaque IJK_GLES2_Renderer_Opaque;\n\ntypedef struct IJK_GLES2_Renderer\n{\n    IJK_GLES2_Renderer_Opaque *opaque;\n\n    GLuint program;\n\n    GLuint vertex_shader;\n    GLuint fragment_shader;\n    GLuint plane_textures[IJK_GLES2_MAX_PLANE];\n\n    GLuint av4_position;\n    GLuint av2_texcoord;\n    GLuint um4_mvp;\n\n    GLuint us2_sampler[IJK_GLES2_MAX_PLANE];\n    GLuint um3_color_conversion;\n\n    GLboolean (*func_use)(IJK_GLES2_Renderer *renderer);\n    GLsizei   (*func_getBufferWidth)(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay);\n    GLboolean (*func_uploadTexture)(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay);\n    GLvoid    (*func_destroy)(IJK_GLES2_Renderer *renderer);\n\n    GLsizei buffer_width;\n    GLsizei visible_width;\n\n    GLfloat texcoords[8];\n\n    GLfloat vertices[8];\n    int     vertices_changed;\n\n    int     format;\n    int     gravity;\n    GLsizei layer_width;\n    GLsizei layer_height;\n    int     frame_width;\n    int     frame_height;\n    int     frame_sar_num;\n    int     frame_sar_den;\n\n    GLsizei last_buffer_width;\n} IJK_GLES2_Renderer;\n\ntypedef struct IJK_GLES_Matrix\n{\n    GLfloat m[16];\n} IJK_GLES_Matrix;\nvoid IJK_GLES2_loadOrtho(IJK_GLES_Matrix *matrix, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far);\n\nconst char *IJK_GLES2_getVertexShader_default();\nconst char *IJK_GLES2_getFragmentShader_yuv420p();\nconst char *IJK_GLES2_getFragmentShader_yuv444p10le();\nconst char *IJK_GLES2_getFragmentShader_yuv420sp();\nconst char *IJK_GLES2_getFragmentShader_rgb();\n\nconst GLfloat *IJK_GLES2_getColorMatrix_bt709();\nconst GLfloat *IJK_GLES2_getColorMatrix_bt601();\n\nIJK_GLES2_Renderer *IJK_GLES2_Renderer_create_base(const char *fragment_shader_source);\nIJK_GLES2_Renderer *IJK_GLES2_Renderer_create_yuv420p();\nIJK_GLES2_Renderer *IJK_GLES2_Renderer_create_yuv444p10le();\nIJK_GLES2_Renderer *IJK_GLES2_Renderer_create_yuv420sp();\nIJK_GLES2_Renderer *IJK_GLES2_Renderer_create_yuv420sp_vtb(SDL_VoutOverlay *overlay);\nIJK_GLES2_Renderer *IJK_GLES2_Renderer_create_rgb565();\nIJK_GLES2_Renderer *IJK_GLES2_Renderer_create_rgb888();\nIJK_GLES2_Renderer *IJK_GLES2_Renderer_create_rgbx8888();\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/gles2/renderer.c",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"internal.h\"\n\nstatic void IJK_GLES2_printProgramInfo(GLuint program)\n{\n    if (!program)\n        return;\n\n    GLint info_len = 0;\n    glGetProgramiv(program, GL_INFO_LOG_LENGTH, &info_len);\n    if (!info_len) {\n        ALOGE(\"[GLES2][Program] empty info\\n\");\n        return;\n    }\n\n    char    buf_stack[32];\n    char   *buf_heap = NULL;\n    char   *buf      = buf_stack;\n    GLsizei buf_len  = sizeof(buf_stack) - 1;\n    if (info_len > sizeof(buf_stack)) {\n        buf_heap = (char*) malloc(info_len + 1);\n        if (buf_heap) {\n            buf     = buf_heap;\n            buf_len = info_len;\n        }\n    }\n\n    glGetProgramInfoLog(program, buf_len, NULL, buf);\n    ALOGE(\"[GLES2][Program] error %s\\n\", buf);\n\n    if (buf_heap)\n        free(buf_heap);\n}\n\nvoid IJK_GLES2_Renderer_reset(IJK_GLES2_Renderer *renderer)\n{\n    if (!renderer)\n        return;\n\n    if (renderer->vertex_shader)\n        glDeleteShader(renderer->vertex_shader);\n    if (renderer->fragment_shader)\n        glDeleteShader(renderer->fragment_shader);\n    if (renderer->program)\n        glDeleteProgram(renderer->program);\n\n    renderer->vertex_shader   = 0;\n    renderer->fragment_shader = 0;\n    renderer->program         = 0;\n\n    for (int i = 0; i < IJK_GLES2_MAX_PLANE; ++i) {\n        if (renderer->plane_textures[i]) {\n            glDeleteTextures(1, &renderer->plane_textures[i]);\n            renderer->plane_textures[i] = 0;\n        }\n    }\n}\n\nvoid IJK_GLES2_Renderer_free(IJK_GLES2_Renderer *renderer)\n{\n    if (!renderer)\n        return;\n\n    if (renderer->func_destroy)\n        renderer->func_destroy(renderer);\n\n#if 0\n    if (renderer->vertex_shader)    ALOGW(\"[GLES2] renderer: vertex_shader not deleted.\\n\");\n    if (renderer->fragment_shader)  ALOGW(\"[GLES2] renderer: fragment_shader not deleted.\\n\");\n    if (renderer->program)          ALOGW(\"[GLES2] renderer: program not deleted.\\n\");\n\n    for (int i = 0; i < IJK_GLES2_MAX_PLANE; ++i) {\n        if (renderer->plane_textures[i])\n            ALOGW(\"[GLES2] renderer: plane texture[%d] not deleted.\\n\", i);\n    }\n#endif\n\n    free(renderer);\n}\n\nvoid IJK_GLES2_Renderer_freeP(IJK_GLES2_Renderer **renderer)\n{\n    if (!renderer || !*renderer)\n        return;\n\n    IJK_GLES2_Renderer_free(*renderer);\n    *renderer = NULL;\n}\n\nIJK_GLES2_Renderer *IJK_GLES2_Renderer_create_base(const char *fragment_shader_source)\n{\n    assert(fragment_shader_source);\n\n    IJK_GLES2_Renderer *renderer = (IJK_GLES2_Renderer *)calloc(1, sizeof(IJK_GLES2_Renderer));\n    if (!renderer)\n        goto fail;\n\n    renderer->vertex_shader = IJK_GLES2_loadShader(GL_VERTEX_SHADER, IJK_GLES2_getVertexShader_default());\n    if (!renderer->vertex_shader)\n        goto fail;\n\n    renderer->fragment_shader = IJK_GLES2_loadShader(GL_FRAGMENT_SHADER, fragment_shader_source);\n    if (!renderer->fragment_shader)\n        goto fail;\n\n    renderer->program = glCreateProgram();                          IJK_GLES2_checkError(\"glCreateProgram\");\n    if (!renderer->program)\n        goto fail;\n\n    glAttachShader(renderer->program, renderer->vertex_shader);     IJK_GLES2_checkError(\"glAttachShader(vertex)\");\n    glAttachShader(renderer->program, renderer->fragment_shader);   IJK_GLES2_checkError(\"glAttachShader(fragment)\");\n    glLinkProgram(renderer->program);                               IJK_GLES2_checkError(\"glLinkProgram\");\n    GLint link_status = GL_FALSE;\n    glGetProgramiv(renderer->program, GL_LINK_STATUS, &link_status);\n    if (!link_status)\n        goto fail;\n\n\n    renderer->av4_position = glGetAttribLocation(renderer->program, \"av4_Position\");                IJK_GLES2_checkError_TRACE(\"glGetAttribLocation(av4_Position)\");\n    renderer->av2_texcoord = glGetAttribLocation(renderer->program, \"av2_Texcoord\");                IJK_GLES2_checkError_TRACE(\"glGetAttribLocation(av2_Texcoord)\");\n    renderer->um4_mvp      = glGetUniformLocation(renderer->program, \"um4_ModelViewProjection\");    IJK_GLES2_checkError_TRACE(\"glGetUniformLocation(um4_ModelViewProjection)\");\n\n    return renderer;\n\nfail:\n\n    if (renderer && renderer->program)\n        IJK_GLES2_printProgramInfo(renderer->program);\n\n    IJK_GLES2_Renderer_free(renderer);\n    return NULL;\n}\n\n\nIJK_GLES2_Renderer *IJK_GLES2_Renderer_create(SDL_VoutOverlay *overlay)\n{\n    if (!overlay)\n        return NULL;\n\n    IJK_GLES2_printString(\"Version\", GL_VERSION);\n    IJK_GLES2_printString(\"Vendor\", GL_VENDOR);\n    IJK_GLES2_printString(\"Renderer\", GL_RENDERER);\n    IJK_GLES2_printString(\"Extensions\", GL_EXTENSIONS);\n\n    IJK_GLES2_Renderer *renderer = NULL;\n    switch (overlay->format) {\n        case SDL_FCC_RV16:      renderer = IJK_GLES2_Renderer_create_rgb565(); break;\n        case SDL_FCC_RV24:      renderer = IJK_GLES2_Renderer_create_rgb888(); break;\n        case SDL_FCC_RV32:      renderer = IJK_GLES2_Renderer_create_rgbx8888(); break;\n#ifdef __APPLE__\n        case SDL_FCC_NV12:      renderer = IJK_GLES2_Renderer_create_yuv420sp(); break;\n        case SDL_FCC__VTB:      renderer = IJK_GLES2_Renderer_create_yuv420sp_vtb(overlay); break;\n#endif\n        case SDL_FCC_YV12:      renderer = IJK_GLES2_Renderer_create_yuv420p(); break;\n        case SDL_FCC_I420:      renderer = IJK_GLES2_Renderer_create_yuv420p(); break;\n        case SDL_FCC_I444P10LE: renderer = IJK_GLES2_Renderer_create_yuv444p10le(); break;\n        default:\n            ALOGE(\"[GLES2] unknown format %4s(%d)\\n\", (char *)&overlay->format, overlay->format);\n            return NULL;\n    }\n\n    renderer->format = overlay->format;\n    return renderer;\n}\n\nGLboolean IJK_GLES2_Renderer_isValid(IJK_GLES2_Renderer *renderer)\n{\n    return renderer && renderer->program ? GL_TRUE : GL_FALSE;\n}\n\nGLboolean IJK_GLES2_Renderer_isFormat(IJK_GLES2_Renderer *renderer, int format)\n{\n    if (!IJK_GLES2_Renderer_isValid(renderer))\n        return GL_FALSE;\n\n    return renderer->format == format ? GL_TRUE : GL_FALSE;\n}\n\n/*\n * Per-Context routine\n */\nGLboolean IJK_GLES2_Renderer_setupGLES()\n{\n    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);       IJK_GLES2_checkError_TRACE(\"glClearColor\");\n    glEnable(GL_CULL_FACE);                     IJK_GLES2_checkError_TRACE(\"glEnable(GL_CULL_FACE)\");\n    glCullFace(GL_BACK);                        IJK_GLES2_checkError_TRACE(\"glCullFace\");\n    glDisable(GL_DEPTH_TEST);\n\n    return GL_TRUE;\n}\n\nstatic void IJK_GLES2_Renderer_Vertices_reset(IJK_GLES2_Renderer *renderer)\n{\n    renderer->vertices[0] = -1.0f;\n    renderer->vertices[1] = -1.0f;\n    renderer->vertices[2] =  1.0f;\n    renderer->vertices[3] = -1.0f;\n    renderer->vertices[4] = -1.0f;\n    renderer->vertices[5] =  1.0f;\n    renderer->vertices[6] =  1.0f;\n    renderer->vertices[7] =  1.0f;\n}\n\nstatic void IJK_GLES2_Renderer_Vertices_apply(IJK_GLES2_Renderer *renderer)\n{\n    switch (renderer->gravity) {\n        case IJK_GLES2_GRAVITY_RESIZE_ASPECT:\n            break;\n        case IJK_GLES2_GRAVITY_RESIZE_ASPECT_FILL:\n            break;\n        case IJK_GLES2_GRAVITY_RESIZE:\n            IJK_GLES2_Renderer_Vertices_reset(renderer);\n            return;\n        default:\n            ALOGE(\"[GLES2] unknown gravity %d\\n\", renderer->gravity);\n            IJK_GLES2_Renderer_Vertices_reset(renderer);\n            return;\n    }\n\n    if (renderer->layer_width <= 0 ||\n        renderer->layer_height <= 0 ||\n        renderer->frame_width <= 0 ||\n        renderer->frame_height <= 0)\n    {\n        ALOGE(\"[GLES2] invalid width/height for gravity aspect\\n\");\n        IJK_GLES2_Renderer_Vertices_reset(renderer);\n        return;\n    }\n\n    float width     = renderer->frame_width;\n    float height    = renderer->frame_height;\n\n    if (renderer->frame_sar_num > 0 && renderer->frame_sar_den > 0) {\n        width = width * renderer->frame_sar_num / renderer->frame_sar_den;\n    }\n\n    const float dW  = (float)renderer->layer_width\t/ width;\n    const float dH  = (float)renderer->layer_height / height;\n    float dd        = 1.0f;\n    float nW        = 1.0f;\n    float nH        = 1.0f;\n\n    switch (renderer->gravity) {\n        case IJK_GLES2_GRAVITY_RESIZE_ASPECT_FILL:  dd = FFMAX(dW, dH); break;\n        case IJK_GLES2_GRAVITY_RESIZE_ASPECT:       dd = FFMIN(dW, dH); break;\n    }\n\n    nW = (width  * dd / (float)renderer->layer_width);\n    nH = (height * dd / (float)renderer->layer_height);\n\n    renderer->vertices[0] = - nW;\n    renderer->vertices[1] = - nH;\n    renderer->vertices[2] =   nW;\n    renderer->vertices[3] = - nH;\n    renderer->vertices[4] = - nW;\n    renderer->vertices[5] =   nH;\n    renderer->vertices[6] =   nW;\n    renderer->vertices[7] =   nH;\n}\n\nstatic void IJK_GLES2_Renderer_Vertices_reloadVertex(IJK_GLES2_Renderer *renderer)\n{\n    glVertexAttribPointer(renderer->av4_position, 2, GL_FLOAT, GL_FALSE, 0, renderer->vertices);    IJK_GLES2_checkError_TRACE(\"glVertexAttribPointer(av2_texcoord)\");\n    glEnableVertexAttribArray(renderer->av4_position);                                      IJK_GLES2_checkError_TRACE(\"glEnableVertexAttribArray(av2_texcoord)\");\n}\n\n#define IJK_GLES2_GRAVITY_MIN                   (0)\n#define IJK_GLES2_GRAVITY_RESIZE                (0) // Stretch to fill layer bounds.\n#define IJK_GLES2_GRAVITY_RESIZE_ASPECT         (1) // Preserve aspect ratio; fit within layer bounds.\n#define IJK_GLES2_GRAVITY_RESIZE_ASPECT_FILL    (2) // Preserve aspect ratio; fill layer bounds.\n#define IJK_GLES2_GRAVITY_MAX                   (2)\n\nGLboolean IJK_GLES2_Renderer_setGravity(IJK_GLES2_Renderer *renderer, int gravity, GLsizei layer_width, GLsizei layer_height)\n{\n    if (renderer->gravity != gravity && gravity >= IJK_GLES2_GRAVITY_MIN && gravity <= IJK_GLES2_GRAVITY_MAX)\n        renderer->vertices_changed = 1;\n    else if (renderer->layer_width != layer_width)\n        renderer->vertices_changed = 1;\n    else if (renderer->layer_height != layer_height)\n        renderer->vertices_changed = 1;\n    else\n        return GL_TRUE;\n\n    renderer->gravity      = gravity;\n    renderer->layer_width  = layer_width;\n    renderer->layer_height = layer_height;\n    return GL_TRUE;\n}\n\nstatic void IJK_GLES2_Renderer_TexCoords_reset(IJK_GLES2_Renderer *renderer)\n{\n    renderer->texcoords[0] = 0.0f;\n    renderer->texcoords[1] = 1.0f;\n    renderer->texcoords[2] = 1.0f;\n    renderer->texcoords[3] = 1.0f;\n    renderer->texcoords[4] = 0.0f;\n    renderer->texcoords[5] = 0.0f;\n    renderer->texcoords[6] = 1.0f;\n    renderer->texcoords[7] = 0.0f;\n}\n\nstatic void IJK_GLES2_Renderer_TexCoords_cropRight(IJK_GLES2_Renderer *renderer, GLfloat cropRight)\n{\n    ALOGE(\"IJK_GLES2_Renderer_TexCoords_cropRight\\n\");\n    renderer->texcoords[0] = 0.0f;\n    renderer->texcoords[1] = 1.0f;\n    renderer->texcoords[2] = 1.0f - cropRight;\n    renderer->texcoords[3] = 1.0f;\n    renderer->texcoords[4] = 0.0f;\n    renderer->texcoords[5] = 0.0f;\n    renderer->texcoords[6] = 1.0f - cropRight;\n    renderer->texcoords[7] = 0.0f;\n}\n\nstatic void IJK_GLES2_Renderer_TexCoords_reloadVertex(IJK_GLES2_Renderer *renderer)\n{\n    glVertexAttribPointer(renderer->av2_texcoord, 2, GL_FLOAT, GL_FALSE, 0, renderer->texcoords);   IJK_GLES2_checkError_TRACE(\"glVertexAttribPointer(av2_texcoord)\");\n    glEnableVertexAttribArray(renderer->av2_texcoord);                                              IJK_GLES2_checkError_TRACE(\"glEnableVertexAttribArray(av2_texcoord)\");\n}\n\n/*\n * Per-Renderer routine\n */\nGLboolean IJK_GLES2_Renderer_use(IJK_GLES2_Renderer *renderer)\n{\n    if (!renderer)\n        return GL_FALSE;\n\n    assert(renderer->func_use);\n    if (!renderer->func_use(renderer))\n        return GL_FALSE;\n\n    IJK_GLES_Matrix modelViewProj;\n    IJK_GLES2_loadOrtho(&modelViewProj, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);\n    glUniformMatrix4fv(renderer->um4_mvp, 1, GL_FALSE, modelViewProj.m);                    IJK_GLES2_checkError_TRACE(\"glUniformMatrix4fv(um4_mvp)\");\n\n    IJK_GLES2_Renderer_TexCoords_reset(renderer);\n    IJK_GLES2_Renderer_TexCoords_reloadVertex(renderer);\n\n    IJK_GLES2_Renderer_Vertices_reset(renderer);\n    IJK_GLES2_Renderer_Vertices_reloadVertex(renderer);\n\n    return GL_TRUE;\n}\n\n/*\n * Per-Frame routine\n */\nGLboolean IJK_GLES2_Renderer_renderOverlay(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay)\n{\n    if (!renderer || !renderer->func_uploadTexture)\n        return GL_FALSE;\n\n    glClear(GL_COLOR_BUFFER_BIT);               IJK_GLES2_checkError_TRACE(\"glClear\");\n\n    GLsizei visible_width  = renderer->frame_width;\n    GLsizei visible_height = renderer->frame_height;\n    if (overlay) {\n        visible_width  = overlay->w;\n        visible_height = overlay->h;\n        if (renderer->frame_width   != visible_width    ||\n            renderer->frame_height  != visible_height   ||\n            renderer->frame_sar_num != overlay->sar_num ||\n            renderer->frame_sar_den != overlay->sar_den) {\n\n            renderer->frame_width   = visible_width;\n            renderer->frame_height  = visible_height;\n            renderer->frame_sar_num = overlay->sar_num;\n            renderer->frame_sar_den = overlay->sar_den;\n\n            renderer->vertices_changed = 1;\n        }\n\n        renderer->last_buffer_width = renderer->func_getBufferWidth(renderer, overlay);\n\n        if (!renderer->func_uploadTexture(renderer, overlay))\n            return GL_FALSE;\n    } else {\n        // NULL overlay means force reload vertice\n        renderer->vertices_changed = 1;\n    }\n\n    GLsizei buffer_width = renderer->last_buffer_width;\n    if (renderer->vertices_changed ||\n        (buffer_width > 0 &&\n         buffer_width > visible_width &&\n         buffer_width != renderer->buffer_width &&\n         visible_width != renderer->visible_width)){\n\n        renderer->vertices_changed = 0;\n\n        IJK_GLES2_Renderer_Vertices_apply(renderer);\n        IJK_GLES2_Renderer_Vertices_reloadVertex(renderer);\n\n        renderer->buffer_width  = buffer_width;\n        renderer->visible_width = visible_width;\n\n        GLsizei padding_pixels     = buffer_width - visible_width;\n        GLfloat padding_normalized = ((GLfloat)padding_pixels) / buffer_width;\n\n        IJK_GLES2_Renderer_TexCoords_reset(renderer);\n        IJK_GLES2_Renderer_TexCoords_cropRight(renderer, padding_normalized);\n        IJK_GLES2_Renderer_TexCoords_reloadVertex(renderer);\n    }\n\n    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);      IJK_GLES2_checkError_TRACE(\"glDrawArrays\");\n\n    return GL_TRUE;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/gles2/renderer_rgb.c",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"internal.h\"\n\nstatic GLboolean rgb_use(IJK_GLES2_Renderer *renderer)\n{\n    ALOGI(\"use render rgb\\n\");\n    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);\n\n    glUseProgram(renderer->program);            IJK_GLES2_checkError_TRACE(\"glUseProgram\");\n\n    if (0 == renderer->plane_textures[0])\n        glGenTextures(1, renderer->plane_textures);\n\n    for (int i = 0; i < 1; ++i) {\n        glActiveTexture(GL_TEXTURE0 + i);\n        glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[i]);\n\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n\n        glUniform1i(renderer->us2_sampler[i], i);\n    }\n\n    return GL_TRUE;\n}\n\nstatic GLsizei rgb565_getBufferWidth(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay)\n{\n    if (!overlay)\n        return 0;\n\n    return overlay->pitches[0] / 2;\n}\n\nstatic GLboolean rgb565_uploadTexture(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay)\n{\n    if (!renderer || !overlay)\n        return GL_FALSE;\n\n    int     planes[1]    = { 0 };\n    const GLsizei widths[1]    = { overlay->pitches[0] / 2 };\n    const GLsizei heights[3]   = { overlay->h };\n    const GLubyte *pixels[3]   = { overlay->pixels[0] };\n\n    switch (overlay->format) {\n        case SDL_FCC_RV16:\n            break;\n        default:\n            ALOGE(\"[rgb565] unexpected format %x\\n\", overlay->format);\n            return GL_FALSE;\n    }\n\n    for (int i = 0; i < 1; ++i) {\n        int plane = planes[i];\n\n        glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[i]);\n\n        glTexImage2D(GL_TEXTURE_2D,\n                     0,\n                     GL_RGB,\n                     widths[plane],\n                     heights[plane],\n                     0,\n                     GL_RGB,\n                     GL_UNSIGNED_SHORT_5_6_5,\n                     pixels[plane]);\n    }\n\n    return GL_TRUE;\n}\n\nIJK_GLES2_Renderer *IJK_GLES2_Renderer_create_rgb565()\n{\n    ALOGI(\"create render rgb565\\n\");\n    IJK_GLES2_Renderer *renderer = IJK_GLES2_Renderer_create_base(IJK_GLES2_getFragmentShader_rgb());\n    if (!renderer)\n        goto fail;\n\n    renderer->us2_sampler[0] = glGetUniformLocation(renderer->program, \"us2_SamplerX\"); IJK_GLES2_checkError_TRACE(\"glGetUniformLocation(us2_SamplerX)\");\n\n    renderer->func_use            = rgb_use;\n    renderer->func_getBufferWidth = rgb565_getBufferWidth;\n    renderer->func_uploadTexture  = rgb565_uploadTexture;\n\n    return renderer;\nfail:\n    IJK_GLES2_Renderer_free(renderer);\n    return NULL;\n}\n\n\n\nstatic GLsizei rgb888_getBufferWidth(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay)\n{\n    if (!overlay)\n        return 0;\n\n    return overlay->pitches[0] / 3;\n}\n\nstatic GLboolean rgb888_uploadTexture(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay)\n{\n    if (!renderer || !overlay)\n        return GL_FALSE;\n\n    int     planes[1]    = { 0 };\n    const GLsizei widths[1]    = { overlay->pitches[0] / 3 };\n    const GLsizei heights[3]   = { overlay->h };\n    const GLubyte *pixels[3]   = { overlay->pixels[0] };\n\n    switch (overlay->format) {\n        case SDL_FCC_RV24:\n            break;\n        default:\n            ALOGE(\"[rgb888] unexpected format %x\\n\", overlay->format);\n            return GL_FALSE;\n    }\n\n    for (int i = 0; i < 1; ++i) {\n        int plane = planes[i];\n\n        glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[i]);\n\n        glTexImage2D(GL_TEXTURE_2D,\n                     0,\n                     GL_RGB,\n                     widths[plane],\n                     heights[plane],\n                     0,\n                     GL_RGB,\n                     GL_UNSIGNED_BYTE,\n                     pixels[plane]);\n    }\n\n    return GL_TRUE;\n}\n\nIJK_GLES2_Renderer *IJK_GLES2_Renderer_create_rgb888()\n{\n    ALOGI(\"create render rgb888\\n\");\n    IJK_GLES2_Renderer *renderer = IJK_GLES2_Renderer_create_base(IJK_GLES2_getFragmentShader_rgb());\n    if (!renderer)\n        goto fail;\n\n    renderer->us2_sampler[0] = glGetUniformLocation(renderer->program, \"us2_SamplerX\"); IJK_GLES2_checkError_TRACE(\"glGetUniformLocation(us2_SamplerX)\");\n\n    renderer->func_use            = rgb_use;\n    renderer->func_getBufferWidth = rgb888_getBufferWidth;\n    renderer->func_uploadTexture  = rgb888_uploadTexture;\n\n    return renderer;\nfail:\n    IJK_GLES2_Renderer_free(renderer);\n    return NULL;\n}\n\n\n\nstatic GLsizei rgbx8888_getBufferWidth(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay)\n{\n    if (!overlay)\n        return 0;\n\n    return overlay->pitches[0] / 4;\n}\n\nstatic GLboolean rgbx8888_uploadTexture(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay)\n{\n    if (!renderer || !overlay)\n        return GL_FALSE;\n\n          int     planes[1]    = { 0 };\n    const GLsizei widths[1]    = { overlay->pitches[0] / 4 };\n    const GLsizei heights[3]   = { overlay->h };\n    const GLubyte *pixels[3]   = { overlay->pixels[0] };\n\n    switch (overlay->format) {\n        case SDL_FCC_RV32:\n            break;\n        default:\n            ALOGE(\"[rgbx8888] unexpected format %x\\n\", overlay->format);\n            return GL_FALSE;\n    }\n\n    for (int i = 0; i < 1; ++i) {\n        int plane = planes[i];\n\n        glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[i]);\n\n        glTexImage2D(GL_TEXTURE_2D,\n                     0,\n                     GL_RGBA,\n                     widths[plane],\n                     heights[plane],\n                     0,\n                     GL_RGBA,\n                     GL_UNSIGNED_BYTE,\n                     pixels[plane]);\n    }\n\n    return GL_TRUE;\n}\n\nIJK_GLES2_Renderer *IJK_GLES2_Renderer_create_rgbx8888()\n{\n    ALOGI(\"create render rgbx8888\\n\");\n    IJK_GLES2_Renderer *renderer = IJK_GLES2_Renderer_create_base(IJK_GLES2_getFragmentShader_rgb());\n    if (!renderer)\n        goto fail;\n\n    renderer->us2_sampler[0] = glGetUniformLocation(renderer->program, \"us2_SamplerX\"); IJK_GLES2_checkError_TRACE(\"glGetUniformLocation(us2_SamplerX)\");\n\n    renderer->func_use            = rgb_use;\n    renderer->func_getBufferWidth = rgbx8888_getBufferWidth;\n    renderer->func_uploadTexture  = rgbx8888_uploadTexture;\n\n    return renderer;\nfail:\n    IJK_GLES2_Renderer_free(renderer);\n    return NULL;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/gles2/renderer_yuv420p.c",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"internal.h\"\n\nstatic GLboolean yuv420p_use(IJK_GLES2_Renderer *renderer)\n{\n    ALOGI(\"use render yuv420p\\n\");\n    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);\n\n    glUseProgram(renderer->program);            IJK_GLES2_checkError_TRACE(\"glUseProgram\");\n\n    if (0 == renderer->plane_textures[0])\n        glGenTextures(3, renderer->plane_textures);\n\n    for (int i = 0; i < 3; ++i) {\n        glActiveTexture(GL_TEXTURE0 + i);\n        glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[i]);\n\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n\n        glUniform1i(renderer->us2_sampler[i], i);\n    }\n\n    glUniformMatrix3fv(renderer->um3_color_conversion, 1, GL_FALSE, IJK_GLES2_getColorMatrix_bt709());\n\n    return GL_TRUE;\n}\n\nstatic GLsizei yuv420p_getBufferWidth(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay)\n{\n    if (!overlay)\n        return 0;\n\n    return overlay->pitches[0] / 1;\n}\n\nstatic GLboolean yuv420p_uploadTexture(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay)\n{\n    if (!renderer || !overlay)\n        return GL_FALSE;\n\n          int     planes[3]    = { 0, 1, 2 };\n    const GLsizei widths[3]    = { overlay->pitches[0], overlay->pitches[1], overlay->pitches[2] };\n    const GLsizei heights[3]   = { overlay->h,          overlay->h / 2,      overlay->h / 2 };\n    const GLubyte *pixels[3]   = { overlay->pixels[0],  overlay->pixels[1],  overlay->pixels[2] };\n\n    switch (overlay->format) {\n        case SDL_FCC_I420:\n            break;\n        case SDL_FCC_YV12:\n            planes[1] = 2;\n            planes[2] = 1;\n            break;\n        default:\n            ALOGE(\"[yuv420p] unexpected format %x\\n\", overlay->format);\n            return GL_FALSE;\n    }\n\n    for (int i = 0; i < 3; ++i) {\n        int plane = planes[i];\n\n        glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[i]);\n\n        glTexImage2D(GL_TEXTURE_2D,\n                     0,\n                     GL_LUMINANCE,\n                     widths[plane],\n                     heights[plane],\n                     0,\n                     GL_LUMINANCE,\n                     GL_UNSIGNED_BYTE,\n                     pixels[plane]);\n    }\n\n    return GL_TRUE;\n}\n\nIJK_GLES2_Renderer *IJK_GLES2_Renderer_create_yuv420p()\n{\n    ALOGI(\"create render yuv420p\\n\");\n    IJK_GLES2_Renderer *renderer = IJK_GLES2_Renderer_create_base(IJK_GLES2_getFragmentShader_yuv420p());\n    if (!renderer)\n        goto fail;\n\n    renderer->us2_sampler[0] = glGetUniformLocation(renderer->program, \"us2_SamplerX\"); IJK_GLES2_checkError_TRACE(\"glGetUniformLocation(us2_SamplerX)\");\n    renderer->us2_sampler[1] = glGetUniformLocation(renderer->program, \"us2_SamplerY\"); IJK_GLES2_checkError_TRACE(\"glGetUniformLocation(us2_SamplerY)\");\n    renderer->us2_sampler[2] = glGetUniformLocation(renderer->program, \"us2_SamplerZ\"); IJK_GLES2_checkError_TRACE(\"glGetUniformLocation(us2_SamplerZ)\");\n\n    renderer->um3_color_conversion = glGetUniformLocation(renderer->program, \"um3_ColorConversion\"); IJK_GLES2_checkError_TRACE(\"glGetUniformLocation(um3_ColorConversionMatrix)\");\n\n    renderer->func_use            = yuv420p_use;\n    renderer->func_getBufferWidth = yuv420p_getBufferWidth;\n    renderer->func_uploadTexture  = yuv420p_uploadTexture;\n\n    return renderer;\nfail:\n    IJK_GLES2_Renderer_free(renderer);\n    return NULL;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/gles2/renderer_yuv420sp.c",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"internal.h\"\n#ifdef __APPLE__\n#import <CoreVideo/CoreVideo.h>\n#include \"ijksdl_vout_overlay_videotoolbox.h\"\n#endif\n\nstatic GLboolean yuv420sp_use(IJK_GLES2_Renderer *renderer)\n{\n    ALOGI(\"use render yuv420sp\\n\");\n    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);\n\n    glUseProgram(renderer->program);            IJK_GLES2_checkError_TRACE(\"glUseProgram\");\n\n    if (0 == renderer->plane_textures[0])\n        glGenTextures(2, renderer->plane_textures);\n\n    for (int i = 0; i < 2; ++i) {\n        glActiveTexture(GL_TEXTURE0 + i);\n        glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[i]);\n\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n\n        glUniform1i(renderer->us2_sampler[i], i);\n    }\n\n    glUniformMatrix3fv(renderer->um3_color_conversion, 1, GL_FALSE, IJK_GLES2_getColorMatrix_bt709());\n\n    return GL_TRUE;\n}\n\nstatic GLsizei yuv420sp_getBufferWidth(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay)\n{\n    if (!overlay)\n        return 0;\n\n    return overlay->pitches[0] / 1;\n}\n\nstatic GLboolean yuv420sp_uploadTexture(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay)\n{\n    if (!renderer || !overlay)\n        return GL_FALSE;\n\n    const GLsizei widths[2]    = { overlay->pitches[0], overlay->pitches[1] / 2 };\n    const GLsizei heights[2]   = { overlay->h,          overlay->h / 2 };\n    const GLubyte *pixels[2]   = { overlay->pixels[0],  overlay->pixels[1] };\n\n    switch (overlay->format) {\n        case SDL_FCC__VTB:\n            break;\n        default:\n            ALOGE(\"[yuv420sp] unexpected format %x\\n\", overlay->format);\n            return GL_FALSE;\n    }\n\n    glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[0]);\n    glTexImage2D(GL_TEXTURE_2D,\n                 0,\n                 GL_RED_EXT,\n                 widths[0],\n                 heights[0],\n                 0,\n                 GL_RED_EXT,\n                 GL_UNSIGNED_BYTE,\n                 pixels[0]);\n\n    glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[1]);\n    glTexImage2D(GL_TEXTURE_2D,\n                 0,\n                 GL_RG_EXT,\n                 widths[1],\n                 heights[1],\n                 0,\n                 GL_RG_EXT,\n                 GL_UNSIGNED_BYTE,\n                 pixels[1]);\n\n    return GL_TRUE;\n}\n\nIJK_GLES2_Renderer *IJK_GLES2_Renderer_create_yuv420sp()\n{\n    IJK_GLES2_Renderer *renderer = IJK_GLES2_Renderer_create_base(IJK_GLES2_getFragmentShader_yuv420sp());\n    if (!renderer)\n        goto fail;\n\n    renderer->us2_sampler[0] = glGetUniformLocation(renderer->program, \"us2_SamplerX\"); IJK_GLES2_checkError_TRACE(\"glGetUniformLocation(us2_SamplerX)\");\n    renderer->us2_sampler[1] = glGetUniformLocation(renderer->program, \"us2_SamplerY\"); IJK_GLES2_checkError_TRACE(\"glGetUniformLocation(us2_SamplerY)\");\n\n    renderer->um3_color_conversion = glGetUniformLocation(renderer->program, \"um3_ColorConversion\"); IJK_GLES2_checkError_TRACE(\"glGetUniformLocation(um3_ColorConversionMatrix)\");\n\n    renderer->func_use            = yuv420sp_use;\n    renderer->func_getBufferWidth = yuv420sp_getBufferWidth;\n    renderer->func_uploadTexture  = yuv420sp_uploadTexture;\n\n    return renderer;\nfail:\n    IJK_GLES2_Renderer_free(renderer);\n    return NULL;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/gles2/renderer_yuv420sp_vtb.m",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"internal.h\"\n#import <OpenGLES/EAGL.h>\n#import <CoreVideo/CoreVideo.h>\n#include \"ijksdl_vout_overlay_videotoolbox.h\"\n\ntypedef struct IJK_GLES2_Renderer_Opaque\n{\n    CVOpenGLESTextureCacheRef cv_texture_cache;\n    CVOpenGLESTextureRef      cv_texture[2];\n\n    CFTypeRef                 color_attachments;\n} IJK_GLES2_Renderer_Opaque;\n\nstatic GLboolean yuv420sp_vtb_use(IJK_GLES2_Renderer *renderer)\n{\n    ALOGI(\"use render yuv420sp_vtb\\n\");\n    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);\n\n    glUseProgram(renderer->program);            IJK_GLES2_checkError_TRACE(\"glUseProgram\");\n\n    for (int i = 0; i < 2; ++i) {\n        glUniform1i(renderer->us2_sampler[i], i);\n    }\n\n    glUniformMatrix3fv(renderer->um3_color_conversion, 1, GL_FALSE, IJK_GLES2_getColorMatrix_bt709());\n    \n    return GL_TRUE;\n}\n\nstatic GLvoid yuv420sp_vtb_clean_textures(IJK_GLES2_Renderer *renderer)\n{\n    if (!renderer || !renderer->opaque)\n        return;\n\n    IJK_GLES2_Renderer_Opaque *opaque = renderer->opaque;\n\n    for (int i = 0; i < 2; ++i) {\n        if (opaque->cv_texture[i]) {\n            CFRelease(opaque->cv_texture[i]);\n            opaque->cv_texture[i] = nil;\n        }\n    }\n\n    // Periodic texture cache flush every frame\n    if (opaque->cv_texture_cache)\n        CVOpenGLESTextureCacheFlush(opaque->cv_texture_cache, 0);\n}\n\nstatic GLsizei yuv420sp_vtb_getBufferWidth(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay)\n{\n    if (!overlay)\n        return 0;\n\n    return overlay->pitches[0] / 1;\n}\n\nstatic GLboolean yuv420sp_vtb_uploadTexture(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay)\n{\n    if (!renderer || !renderer->opaque || !overlay)\n        return GL_FALSE;\n\n    if (!overlay->is_private)\n        return GL_FALSE;\n\n    switch (overlay->format) {\n        case SDL_FCC__VTB:\n            break;\n        default:\n            ALOGE(\"[yuv420sp_vtb] unexpected format %x\\n\", overlay->format);\n            return GL_FALSE;\n    }\n\n    IJK_GLES2_Renderer_Opaque *opaque = renderer->opaque;\n    if (!opaque->cv_texture_cache) {\n        ALOGE(\"nil textureCache\\n\");\n        return GL_FALSE;\n    }\n\n    CVPixelBufferRef pixel_buffer = SDL_VoutOverlayVideoToolBox_GetCVPixelBufferRef(overlay);\n    if (!pixel_buffer) {\n        ALOGE(\"nil pixelBuffer in overlay\\n\");\n        return GL_FALSE;\n    }\n\n    CFTypeRef color_attachments = CVBufferGetAttachment(pixel_buffer, kCVImageBufferYCbCrMatrixKey, NULL);\n    if (color_attachments != opaque->color_attachments) {\n        if (color_attachments == nil) {\n            glUniformMatrix3fv(renderer->um3_color_conversion, 1, GL_FALSE, IJK_GLES2_getColorMatrix_bt709());\n        } else if (opaque->color_attachments != nil &&\n                   CFStringCompare(color_attachments, opaque->color_attachments, 0) == kCFCompareEqualTo) {\n            // remain prvious color attachment\n        } else if (CFStringCompare(color_attachments, kCVImageBufferYCbCrMatrix_ITU_R_709_2, 0) == kCFCompareEqualTo) {\n            glUniformMatrix3fv(renderer->um3_color_conversion, 1, GL_FALSE, IJK_GLES2_getColorMatrix_bt709());\n        } else if (CFStringCompare(color_attachments, kCVImageBufferYCbCrMatrix_ITU_R_601_4, 0) == kCFCompareEqualTo) {\n            glUniformMatrix3fv(renderer->um3_color_conversion, 1, GL_FALSE, IJK_GLES2_getColorMatrix_bt601());\n        } else {\n            glUniformMatrix3fv(renderer->um3_color_conversion, 1, GL_FALSE, IJK_GLES2_getColorMatrix_bt709());\n        }\n\n        if (opaque->color_attachments != nil) {\n            CFRelease(opaque->color_attachments);\n            opaque->color_attachments = nil;\n        }\n        if (color_attachments != nil) {\n            opaque->color_attachments = CFRetain(color_attachments);\n        }\n    }\n\n    yuv420sp_vtb_clean_textures(renderer);\n\n    GLsizei frame_width  = (GLsizei)CVPixelBufferGetWidth(pixel_buffer);\n    GLsizei frame_height = (GLsizei)CVPixelBufferGetHeight(pixel_buffer);\n\n    glActiveTexture(GL_TEXTURE0);\n    CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault,\n                                                 opaque->cv_texture_cache,\n                                                 pixel_buffer,\n                                                 NULL,\n                                                 GL_TEXTURE_2D,\n                                                 GL_RED_EXT,\n                                                 (GLsizei)frame_width,\n                                                 (GLsizei)frame_height,\n                                                 GL_RED_EXT,\n                                                 GL_UNSIGNED_BYTE,\n                                                 0,\n                                                 &opaque->cv_texture[0]);\n    glBindTexture(CVOpenGLESTextureGetTarget(opaque->cv_texture[0]), CVOpenGLESTextureGetName(opaque->cv_texture[0]));\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n\n\n    glActiveTexture(GL_TEXTURE1);\n    CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault,\n                                                 opaque->cv_texture_cache,\n                                                 pixel_buffer,\n                                                 NULL,\n                                                 GL_TEXTURE_2D,\n                                                 GL_RG_EXT,\n                                                 (GLsizei)frame_width / 2,\n                                                 (GLsizei)frame_height / 2,\n                                                 GL_RG_EXT,\n                                                 GL_UNSIGNED_BYTE,\n                                                 1,\n                                                 &opaque->cv_texture[1]);\n    glBindTexture(CVOpenGLESTextureGetTarget(opaque->cv_texture[1]), CVOpenGLESTextureGetName(opaque->cv_texture[1]));\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n\n\n    return GL_TRUE;\n}\n\nstatic GLvoid yuv420sp_vtb_destroy(IJK_GLES2_Renderer *renderer)\n{\n    if (!renderer || !renderer->opaque)\n        return;\n\n    yuv420sp_vtb_clean_textures(renderer);\n\n    IJK_GLES2_Renderer_Opaque *opaque = renderer->opaque;\n    if (opaque->cv_texture_cache) {\n        CFRelease(opaque->cv_texture_cache);\n        opaque->cv_texture_cache = nil;\n    }\n\n    if (opaque->color_attachments != nil) {\n        CFRelease(opaque->color_attachments);\n        opaque->color_attachments = nil;\n    }\n    free(renderer->opaque);\n    renderer->opaque = nil;\n}\n\nIJK_GLES2_Renderer *IJK_GLES2_Renderer_create_yuv420sp_vtb(SDL_VoutOverlay *overlay)\n{\n    CVReturn err = 0;\n    EAGLContext *context = [EAGLContext currentContext];\n\n    if (!overlay) {\n        ALOGW(\"invalid overlay, fall back to yuv420sp renderer\\n\");\n        return IJK_GLES2_Renderer_create_yuv420sp();\n    }\n\n    if (!overlay) {\n        ALOGW(\"non-private overlay, fall back to yuv420sp renderer\\n\");\n        return IJK_GLES2_Renderer_create_yuv420sp();\n    }\n\n    if (!context) {\n        ALOGW(\"nil EAGLContext, fall back to yuv420sp renderer\\n\");\n        return IJK_GLES2_Renderer_create_yuv420sp();\n    }\n\n    ALOGI(\"create render yuv420sp_vtb\\n\");\n    IJK_GLES2_Renderer *renderer = IJK_GLES2_Renderer_create_base(IJK_GLES2_getFragmentShader_yuv420sp());\n    if (!renderer)\n        goto fail;\n\n    renderer->us2_sampler[0] = glGetUniformLocation(renderer->program, \"us2_SamplerX\"); IJK_GLES2_checkError_TRACE(\"glGetUniformLocation(us2_SamplerX)\");\n    renderer->us2_sampler[1] = glGetUniformLocation(renderer->program, \"us2_SamplerY\"); IJK_GLES2_checkError_TRACE(\"glGetUniformLocation(us2_SamplerY)\");\n\n    renderer->um3_color_conversion = glGetUniformLocation(renderer->program, \"um3_ColorConversion\"); IJK_GLES2_checkError_TRACE(\"glGetUniformLocation(um3_ColorConversionMatrix)\");\n\n    renderer->func_use            = yuv420sp_vtb_use;\n    renderer->func_getBufferWidth = yuv420sp_vtb_getBufferWidth;\n    renderer->func_uploadTexture  = yuv420sp_vtb_uploadTexture;\n    renderer->func_destroy        = yuv420sp_vtb_destroy;\n\n    renderer->opaque = calloc(1, sizeof(IJK_GLES2_Renderer_Opaque));\n    if (!renderer->opaque)\n        goto fail;\n\n    err = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, context, NULL, &renderer->opaque->cv_texture_cache);\n    if (err || renderer->opaque->cv_texture_cache == nil) {\n        ALOGE(\"Error at CVOpenGLESTextureCacheCreate %d\\n\", err);\n        goto fail;\n    }\n\n    renderer->opaque->color_attachments = CFRetain(kCVImageBufferYCbCrMatrix_ITU_R_709_2);\n    \n    return renderer;\nfail:\n    IJK_GLES2_Renderer_free(renderer);\n    return NULL;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/gles2/renderer_yuv444p10le.c",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"internal.h\"\n\nstatic GLboolean yuv444p10le_use(IJK_GLES2_Renderer *renderer)\n{\n    ALOGI(\"use render yuv420p10le\\n\");\n    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);\n\n    glUseProgram(renderer->program);            IJK_GLES2_checkError_TRACE(\"glUseProgram\");\n\n    if (0 == renderer->plane_textures[0])\n        glGenTextures(3, renderer->plane_textures);\n\n    for (int i = 0; i < 3; ++i) {\n        glActiveTexture(GL_TEXTURE0 + i);\n        glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[i]);\n\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n\n        glUniform1i(renderer->us2_sampler[i], i);\n    }\n\n    glUniformMatrix3fv(renderer->um3_color_conversion, 1, GL_FALSE, IJK_GLES2_getColorMatrix_bt709());\n\n    return GL_TRUE;\n}\n\nstatic GLsizei yuv444p10le_getBufferWidth(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay)\n{\n    if (!overlay)\n        return 0;\n\n    return overlay->pitches[0] / 2;\n}\n\nstatic GLboolean yuv444p10le_uploadTexture(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay)\n{\n    if (!renderer || !overlay)\n        return GL_FALSE;\n\n          int     planes[3]    = { 0, 1, 2 };\n    const GLsizei widths[3]    = { overlay->pitches[0] / 2, overlay->pitches[1] / 2, overlay->pitches[2] / 2 };\n    const GLsizei heights[3]   = { overlay->h,              overlay->h,              overlay->h };\n    const GLubyte *pixels[3]   = { overlay->pixels[0],      overlay->pixels[1],      overlay->pixels[2] };\n\n    switch (overlay->format) {\n        case SDL_FCC_I444P10LE:\n            break;\n        default:\n            ALOGE(\"[yuv420p10le] unexpected format %x\\n\", overlay->format);\n            return GL_FALSE;\n    }\n\n    for (int i = 0; i < 3; ++i) {\n        int plane = planes[i];\n\n        glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[i]);  IJK_GLES2_checkError_TRACE(\"glBindTexture\");\n\n        glTexImage2D(GL_TEXTURE_2D,\n                     0,\n                     GL_LUMINANCE_ALPHA,\n                     widths[plane],\n                     heights[plane],\n                     0,\n                     GL_LUMINANCE_ALPHA,\n                     GL_UNSIGNED_BYTE,\n                     pixels[plane]);    IJK_GLES2_checkError_TRACE(\"glTexImage2D\");\n    }\n\n    return GL_TRUE;\n}\n\nIJK_GLES2_Renderer *IJK_GLES2_Renderer_create_yuv444p10le()\n{\n    ALOGI(\"create render yuv444p10le\\n\");\n    IJK_GLES2_Renderer *renderer = IJK_GLES2_Renderer_create_base(IJK_GLES2_getFragmentShader_yuv444p10le());\n    if (!renderer)\n        goto fail;\n\n    renderer->us2_sampler[0] = glGetUniformLocation(renderer->program, \"us2_SamplerX\"); IJK_GLES2_checkError_TRACE(\"glGetUniformLocation(us2_SamplerX)\");\n    renderer->us2_sampler[1] = glGetUniformLocation(renderer->program, \"us2_SamplerY\"); IJK_GLES2_checkError_TRACE(\"glGetUniformLocation(us2_SamplerY)\");\n    renderer->us2_sampler[2] = glGetUniformLocation(renderer->program, \"us2_SamplerZ\"); IJK_GLES2_checkError_TRACE(\"glGetUniformLocation(us2_SamplerZ)\");\n\n    renderer->um3_color_conversion = glGetUniformLocation(renderer->program, \"um3_ColorConversion\"); IJK_GLES2_checkError_TRACE(\"glGetUniformLocation(um3_ColorConversionMatrix)\");\n\n    renderer->func_use            = yuv444p10le_use;\n    renderer->func_getBufferWidth = yuv444p10le_getBufferWidth;\n    renderer->func_uploadTexture  = yuv444p10le_uploadTexture;\n\n    return renderer;\nfail:\n    IJK_GLES2_Renderer_free(renderer);\n    return NULL;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/gles2/shader.c",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"internal.h\"\n\nstatic void IJK_GLES2_printShaderInfo(GLuint shader)\n{\n    if (!shader)\n        return;\n\n    GLint info_len = 0;\n    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_len);\n    if (!info_len) {\n        ALOGE(\"[GLES2][Shader] empty info\\n\");\n        return;\n    }\n\n    char    buf_stack[32];\n    char   *buf_heap = NULL;\n    char   *buf      = buf_stack;\n    GLsizei buf_len  = sizeof(buf_stack) - 1;\n    if (info_len > sizeof(buf_stack)) {\n        buf_heap = (char*) malloc(info_len + 1);\n        if (buf_heap) {\n            buf     = buf_heap;\n            buf_len = info_len;\n        }\n    }\n\n    glGetShaderInfoLog(shader, buf_len, NULL, buf);\n    ALOGE(\"[GLES2][Shader] error %s\\n\", buf);\n\n    if (buf_heap)\n        free(buf_heap);\n}\n\nGLuint IJK_GLES2_loadShader(GLenum shader_type, const char *shader_source)\n{\n    assert(shader_source);\n\n    GLuint shader = glCreateShader(shader_type);        IJK_GLES2_checkError(\"glCreateShader\");\n    if (!shader)\n        return 0;\n\n    assert(shader_source);\n\n    glShaderSource(shader, 1, &shader_source, NULL);    IJK_GLES2_checkError_TRACE(\"glShaderSource\");\n    glCompileShader(shader);                            IJK_GLES2_checkError_TRACE(\"glCompileShader\");\n\n    GLint compile_status = 0;\n    glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);\n    if (!compile_status)\n        goto fail;\n\n    return shader;\n\nfail:\n\n    if (shader) {\n        IJK_GLES2_printShaderInfo(shader);\n        glDeleteShader(shader);\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/gles2/vsh/mvp.vsh.c",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl/gles2/internal.h\"\n\nstatic const char g_shader[] = IJK_GLES_STRING(\n    precision highp float;\n    varying   highp vec2 vv2_Texcoord;\n    attribute highp vec4 av4_Position;\n    attribute highp vec2 av2_Texcoord;\n    uniform         mat4 um4_ModelViewProjection;\n\n    void main()\n    {\n        gl_Position  = um4_ModelViewProjection * av4_Position;\n        vv2_Texcoord = av2_Texcoord.xy;\n    }\n);\n\nconst char *IJK_GLES2_getVertexShader_default()\n{\n    return g_shader;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl.h",
    "content": "/*****************************************************************************\n * ijksdl.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL__IJKSDL_H\n#define IJKSDL__IJKSDL_H\n\n#include \"ijksdl_audio.h\"\n#include \"ijksdl_aout.h\"\n#include \"ijksdl_class.h\"\n#include \"ijksdl_error.h\"\n#include \"ijksdl_log.h\"\n#include \"ijksdl_misc.h\"\n#include \"ijksdl_mutex.h\"\n#include \"ijksdl_thread.h\"\n#include \"ijksdl_timer.h\"\n#include \"ijksdl_video.h\"\n#include \"ijksdl_vout.h\"\n\n#include \"ffmpeg/ijksdl_vout_overlay_ffmpeg.h\"\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_aout.c",
    "content": "/*****************************************************************************\n * ijksdl_aout.c\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl_aout.h\"\n#include <stdlib.h>\n#include \"ijkplayer/ff_ffplay_def.h\"\n\nint SDL_AoutOpenAudio(SDL_Aout *aout, const SDL_AudioSpec *desired, SDL_AudioSpec *obtained)\n{\n    if (aout && desired && aout->open_audio)\n        return aout->open_audio(aout, desired, obtained);\n\n    return -1;\n}\n\nvoid SDL_AoutPauseAudio(SDL_Aout *aout, int pause_on)\n{\n    if (aout && aout->pause_audio)\n        aout->pause_audio(aout, pause_on);\n}\n\nvoid SDL_AoutFlushAudio(SDL_Aout *aout)\n{\n    if (aout && aout->flush_audio)\n        aout->flush_audio(aout);\n}\n\nvoid SDL_AoutSetStereoVolume(SDL_Aout *aout, float left_volume, float right_volume)\n{\n    if (aout && aout->set_volume)\n        aout->set_volume(aout, left_volume, right_volume);\n}\n\nvoid SDL_AoutCloseAudio(SDL_Aout *aout)\n{\n    if (aout && aout->close_audio)\n        return aout->close_audio(aout);\n}\n\nvoid SDL_AoutFree(SDL_Aout *aout)\n{\n    if (!aout)\n        return;\n\n    if (aout->free_l)\n        aout->free_l(aout);\n    else\n        free(aout);\n}\n\nvoid SDL_AoutFreeP(SDL_Aout **paout)\n{\n    if (!paout)\n        return;\n\n    SDL_AoutFree(*paout);\n    *paout = NULL;\n}\n\ndouble SDL_AoutGetLatencySeconds(SDL_Aout *aout)\n{\n    if (!aout)\n        return 0;\n\n    if (aout->func_get_latency_seconds)\n        return aout->func_get_latency_seconds(aout);\n\n    return aout->minimal_latency_seconds;\n}\n\nvoid SDL_AoutSetDefaultLatencySeconds(SDL_Aout *aout, double latency)\n{\n    if (aout) {\n        if (aout->func_set_default_latency_seconds)\n            aout->func_set_default_latency_seconds(aout, latency);\n        aout->minimal_latency_seconds = latency;\n    }\n}\n\nvoid SDL_AoutSetPlaybackRate(SDL_Aout *aout, float playbackRate)\n{\n    if (aout) {\n        if (aout->func_set_playback_rate)\n            aout->func_set_playback_rate(aout, playbackRate);\n    }\n}\n\nvoid SDL_AoutSetPlaybackVolume(SDL_Aout *aout, float volume)\n{\n    if (aout) {\n        if (aout->func_set_playback_volume)\n            aout->func_set_playback_volume(aout, volume);\n    }\n}\n\nint SDL_AoutGetAudioSessionId(SDL_Aout *aout)\n{\n    if (aout) {\n        if (aout->func_get_audio_session_id) {\n            return aout->func_get_audio_session_id(aout);\n        }\n    }\n    return 0;\n}\n\nint SDL_AoutGetAudioPerSecondCallBacks(SDL_Aout *aout)\n{\n    if (aout) {\n        if (aout->func_get_audio_persecond_callbacks) {\n            return aout->func_get_audio_persecond_callbacks(aout);\n        }\n    }\n    return SDL_AUDIO_MAX_CALLBACKS_PER_SEC;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_aout.h",
    "content": "/*****************************************************************************\n * ijksdl_aout.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL__IJKSDL_AOUT_H\n#define IJKSDL__IJKSDL_AOUT_H\n\n#include \"ijksdl_audio.h\"\n#include \"ijksdl_class.h\"\n#include \"ijksdl_mutex.h\"\n\ntypedef struct SDL_Aout_Opaque SDL_Aout_Opaque;\ntypedef struct SDL_Aout SDL_Aout;\nstruct SDL_Aout {\n    SDL_mutex *mutex;\n    double     minimal_latency_seconds;\n\n    SDL_Class       *opaque_class;\n    SDL_Aout_Opaque *opaque;\n    void (*free_l)(SDL_Aout *vout);\n    int (*open_audio)(SDL_Aout *aout, const SDL_AudioSpec *desired, SDL_AudioSpec *obtained);\n    void (*pause_audio)(SDL_Aout *aout, int pause_on);\n    void (*flush_audio)(SDL_Aout *aout);\n    void (*set_volume)(SDL_Aout *aout, float left, float right);\n    void (*close_audio)(SDL_Aout *aout);\n\n    double (*func_get_latency_seconds)(SDL_Aout *aout);\n    void   (*func_set_default_latency_seconds)(SDL_Aout *aout, double latency);\n\n    // optional\n    void   (*func_set_playback_rate)(SDL_Aout *aout, float playbackRate);\n    void   (*func_set_playback_volume)(SDL_Aout *aout, float playbackVolume);\n    int    (*func_get_audio_persecond_callbacks)(SDL_Aout *aout);\n\n    // Android only\n    int    (*func_get_audio_session_id)(SDL_Aout *aout);\n};\n\nint SDL_AoutOpenAudio(SDL_Aout *aout, const SDL_AudioSpec *desired, SDL_AudioSpec *obtained);\nvoid SDL_AoutPauseAudio(SDL_Aout *aout, int pause_on);\nvoid SDL_AoutFlushAudio(SDL_Aout *aout);\nvoid SDL_AoutSetStereoVolume(SDL_Aout *aout, float left_volume, float right_volume);\nvoid SDL_AoutCloseAudio(SDL_Aout *aout);\nvoid SDL_AoutFree(SDL_Aout *aout);\nvoid SDL_AoutFreeP(SDL_Aout **paout);\n\ndouble SDL_AoutGetLatencySeconds(SDL_Aout *aout);\nvoid   SDL_AoutSetDefaultLatencySeconds(SDL_Aout *aout, double latency);\nint    SDL_AoutGetAudioPerSecondCallBacks(SDL_Aout *aout);\n\n// optional\nvoid   SDL_AoutSetPlaybackRate(SDL_Aout *aout, float playbackRate);\nvoid   SDL_AoutSetPlaybackVolume(SDL_Aout *aout, float volume);\n\n// android only\nint    SDL_AoutGetAudioSessionId(SDL_Aout *aout);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_aout_internal.h",
    "content": "/*****************************************************************************\n * ijksdl_aout_internal.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL__IJKSDL_AOUT_INTERNAL_H\n#define IJKSDL__IJKSDL_AOUT_INTERNAL_H\n\n#include \"ijksdl_mutex.h\"\n#include \"ijksdl_aout.h\"\n\ninline static SDL_Aout *SDL_Aout_CreateInternal(size_t opaque_size)\n{\n    SDL_Aout *aout = (SDL_Aout*) mallocz(sizeof(SDL_Aout));\n    if (!aout)\n        return NULL;\n\n    aout->opaque = mallocz(opaque_size);\n    if (!aout->opaque) {\n        free(aout);\n        return NULL;\n    }\n\n    aout->mutex = SDL_CreateMutex();\n    if (aout->mutex == NULL) {\n        free(aout->opaque);\n        free(aout);\n        return NULL;\n    }\n\n    return aout;\n}\n\ninline static void SDL_Aout_FreeInternal(SDL_Aout *aout)\n{\n    if (!aout)\n        return;\n\n    if (aout->mutex) {\n        SDL_DestroyMutex(aout->mutex);\n    }\n\n    free(aout->opaque);\n    memset(aout, 0, sizeof(SDL_Aout));\n    free(aout);\n}\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_audio.c",
    "content": "/*****************************************************************************\n * ijksdl_audio.c\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl_audio.h\"\n\nvoid SDL_CalculateAudioSpec(SDL_AudioSpec * spec)\n{\n    switch (spec->format) {\n    case AUDIO_U8:\n        spec->silence = 0x80;\n        break;\n    default:\n        spec->silence = 0x00;\n        break;\n    }\n    spec->size = SDL_AUDIO_BITSIZE(spec->format) / 8;\n    spec->size *= spec->channels;\n    spec->size *= spec->samples;\n}\n\nvoid SDL_MixAudio(Uint8*       dst,\n                  const Uint8* src,\n                  Uint32       len,\n                  int          volume)\n{\n    // do nothing;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_audio.h",
    "content": "/*****************************************************************************\n * ijksdl_audio.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL__IJKSDL_AUDIO_H\n#define IJKSDL__IJKSDL_AUDIO_H\n\n#include \"ijksdl_stdinc.h\"\n#include \"ijksdl_endian.h\"\n\ntypedef uint16_t SDL_AudioFormat;\n\n#define SDL_AUDIO_MASK_BITSIZE       (0xFF)\n#define SDL_AUDIO_MASK_DATATYPE      (1<<8)\n#define SDL_AUDIO_MASK_ENDIAN        (1<<12)\n#define SDL_AUDIO_MASK_SIGNED        (1<<15)\n#define SDL_AUDIO_BITSIZE(x)         (x & SDL_AUDIO_MASK_BITSIZE)\n#define SDL_AUDIO_ISFLOAT(x)         (x & SDL_AUDIO_MASK_DATATYPE)\n#define SDL_AUDIO_ISBIGENDIAN(x)     (x & SDL_AUDIO_MASK_ENDIAN)\n#define SDL_AUDIO_ISSIGNED(x)        (x & SDL_AUDIO_MASK_SIGNED)\n#define SDL_AUDIO_ISINT(x)           (!SDL_AUDIO_ISFLOAT(x))\n#define SDL_AUDIO_ISLITTLEENDIAN(x)  (!SDL_AUDIO_ISBIGENDIAN(x))\n#define SDL_AUDIO_ISUNSIGNED(x)      (!SDL_AUDIO_ISSIGNED(x))\n\n#define AUDIO_INVALID   0x0000\n#define AUDIO_U8        0x0008  /**< Unsigned 8-bit samples */\n#define AUDIO_S8        0x8008  /**< Signed 8-bit samples */\n#define AUDIO_U16LSB    0x0010  /**< Unsigned 16-bit samples */\n#define AUDIO_S16LSB    0x8010  /**< Signed 16-bit samples */\n#define AUDIO_U16MSB    0x1010  /**< As above, but big-endian byte order */\n#define AUDIO_S16MSB    0x9010  /**< As above, but big-endian byte order */\n#define AUDIO_U16       AUDIO_U16LSB\n#define AUDIO_S16       AUDIO_S16LSB\n\n#define AUDIO_S32LSB    0x8020  /**< 32-bit integer samples */\n#define AUDIO_S32MSB    0x9020  /**< As above, but big-endian byte order */\n#define AUDIO_S32       AUDIO_S32LSB\n\n#define AUDIO_F32LSB    0x8120  /**< 32-bit floating point samples */\n#define AUDIO_F32MSB    0x9120  /**< As above, but big-endian byte order */\n#define AUDIO_F32       AUDIO_F32LSB\n\n#if SDL_BYTEORDER == SDL_LIL_ENDIAN\n#define AUDIO_U16SYS    AUDIO_U16LSB\n#define AUDIO_S16SYS    AUDIO_S16LSB\n#define AUDIO_S32SYS    AUDIO_S32LSB\n#define AUDIO_F32SYS    AUDIO_F32LSB\n#else\n#define AUDIO_U16SYS    AUDIO_U16MSB\n#define AUDIO_S16SYS    AUDIO_S16MSB\n#define AUDIO_S32SYS    AUDIO_S32MSB\n#define AUDIO_F32SYS    AUDIO_F32MSB\n#endif\n\n#define SDL_MIX_MAXVOLUME (128)\n\ntypedef void (*SDL_AudioCallback) (void *userdata, Uint8 * stream,\n                                   int len);\n\ntypedef struct SDL_AudioSpec\n{\n    int freq;                   /**< DSP frequency -- samples per second */\n    SDL_AudioFormat format;     /**< Audio data format */\n    Uint8 channels;             /**< Number of channels: 1 mono, 2 stereo */\n    Uint8 silence;              /**< Audio buffer silence value (calculated) */\n    Uint16 samples;             /**< Audio buffer size in samples (power of 2) */\n    Uint16 padding;             /**< NOT USED. Necessary for some compile environments */\n    Uint32 size;                /**< Audio buffer size in bytes (calculated) */\n    SDL_AudioCallback callback;\n    void *userdata;\n} SDL_AudioSpec;\n\nvoid SDL_CalculateAudioSpec(SDL_AudioSpec * spec);\n\nvoid SDL_MixAudio(Uint8*       dst,\n                  const Uint8* src,\n                  Uint32       len,\n                  int          volume);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_class.h",
    "content": "/*****************************************************************************\n * ijksdl_class.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL__IJKSDL_CLASS_H\n#define IJKSDL__IJKSDL_CLASS_H\n\ntypedef struct SDL_Class {\n    const char *name;\n} SDL_Class;\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_container.h",
    "content": "/*\n * Copyright (c) 2015 Bilibili\n * copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL__IJKSDL_CONTAINER_H\n#define IJKSDL__IJKSDL_CONTAINER_H\n\n#include <stdlib.h>\n\ntypedef int isdl_error;\n\n/*\n * Array\n */\n\ntypedef struct ISDL_Array\n{\n    void   **elements;\n    size_t   capacity;\n    size_t   size;\n} ISDL_Array;\n\ninline static isdl_error ISDL_Array__grow(ISDL_Array *array, size_t new_capacity)\n{\n    assert(array);\n    if (array->capacity >= new_capacity)\n        return 0;\n\n    void **new_elements = realloc(array->elements, sizeof(void *) * new_capacity);\n    if (!new_elements)\n        return -1;\n\n    array->elements = new_elements;\n    array->capacity = new_capacity;\n    return 0;\n}\n\ninline static isdl_error ISDL_Array__init(ISDL_Array *array, size_t capacity)\n{\n    assert(array);\n    memset(array, 0, sizeof(ISDL_Array));\n    if (ISDL_Array__grow(array, capacity))\n        return -1;\n\n    return 0;\n}\n\ninline static isdl_error ISDL_Array__push_back(ISDL_Array *array, void *val)\n{\n    assert(array);\n    if (array->size >= array->capacity) {\n        if (ISDL_Array__grow(array, array->capacity * 2))\n            return -1;\n    }\n\n    array->elements[array->size++] = val;\n    return 0;\n}\n\ninline static void *ISDL_Array__pop_back(ISDL_Array *array)\n{\n    assert(array);\n    assert(array->size >= 1);\n    return array->elements[--array->size];\n}\n\ninline static void ISDL_Array__clear(ISDL_Array *array)\n{\n    assert(array);\n    array->size = 0;\n}\n\ninline static void *ISDL_Array__at(ISDL_Array *array, int pos)\n{\n    assert(array);\n    assert(pos >= 0);\n    assert(pos < array->size);\n    return array->elements[pos];\n}\n\ninline static size_t ISDL_Array__size(ISDL_Array *array)\n{\n    assert(array);\n    return array->size;\n}\n\ninline static void **ISDL_Array__begin(ISDL_Array *array)\n{\n    assert(array);\n    return array->elements;\n}\n\ninline static void **ISDL_Array__end(ISDL_Array *array)\n{\n    assert(array);\n    return array->elements + array->size;\n}\n\ninline static void *ISDL_Array__back(ISDL_Array *array)\n{\n    assert(array);\n    assert(array->size >= 1);\n    return array->elements[array->size - 1];\n}\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_egl.c",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef __APPLE__\n\n#include \"ijksdl_egl.h\"\n\n#include <stdlib.h>\n#include <stdbool.h>\n#include \"ijksdl/ijksdl_gles2.h\"\n#include \"ijksdl/ijksdl_log.h\"\n#include \"ijksdl/ijksdl_vout.h\"\n#include \"ijksdl/gles2/internal.h\"\n\n#define IJK_EGL_RENDER_BUFFER 0\n\ntypedef struct IJK_EGL_Opaque {\n    IJK_GLES2_Renderer *renderer;\n} IJK_EGL_Opaque;\n\nstatic EGLBoolean IJK_EGL_isValid(IJK_EGL* egl)\n{\n    if (egl &&\n        egl->window &&\n        egl->display &&\n        egl->surface &&\n        egl->context) {\n        return EGL_TRUE;\n    }\n\n    return EGL_FALSE;\n}\n\nvoid IJK_EGL_terminate(IJK_EGL* egl)\n{\n    if (!IJK_EGL_isValid(egl))\n        return;\n\n    if (egl->opaque)\n        IJK_GLES2_Renderer_freeP(&egl->opaque->renderer);\n\n    if (egl->display) {\n        eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);\n        if (egl->context)\n            eglDestroyContext(egl->display, egl->context);\n        if (egl->surface)\n            eglDestroySurface(egl->display, egl->surface);\n        eglTerminate(egl->display);\n        eglReleaseThread(); // FIXME: call at thread exit\n    }\n\n    egl->context = EGL_NO_CONTEXT;\n    egl->surface = EGL_NO_SURFACE;\n    egl->display = EGL_NO_DISPLAY;\n}\n\nstatic int IJK_EGL_getSurfaceWidth(IJK_EGL* egl)\n{\n    EGLint width = 0;\n    if (!eglQuerySurface(egl->display, egl->surface, EGL_WIDTH, &width)) {\n        ALOGE(\"[EGL] eglQuerySurface(EGL_WIDTH) returned error %d\", eglGetError());\n        return 0;\n    }\n\n    return width;\n}\n\nstatic int IJK_EGL_getSurfaceHeight(IJK_EGL* egl)\n{\n    EGLint height = 0;\n    if (!eglQuerySurface(egl->display, egl->surface, EGL_HEIGHT, &height)) {\n        ALOGE(\"[EGL] eglQuerySurface(EGL_HEIGHT) returned error %d\", eglGetError());\n        return 0;\n    }\n\n    return height;\n}\n\nstatic EGLBoolean IJK_EGL_setSurfaceSize(IJK_EGL* egl, int width, int height)\n{\n    if (!IJK_EGL_isValid(egl))\n        return EGL_FALSE;\n\n#ifdef __ANDROID__\n    egl->width  = IJK_EGL_getSurfaceWidth(egl);\n    egl->height = IJK_EGL_getSurfaceHeight(egl);\n\n    if (width != egl->width || height != egl->height) {\n        int format = ANativeWindow_getFormat(egl->window);\n        ALOGI(\"ANativeWindow_setBuffersGeometry(w=%d,h=%d) -> (w=%d,h=%d);\",\n            egl->width, egl->height,\n            width, height);\n        int ret = ANativeWindow_setBuffersGeometry(egl->window, width, height, format);\n        if (ret) {\n            ALOGE(\"[EGL] ANativeWindow_setBuffersGeometry() returned error %d\", ret);\n            return EGL_FALSE;\n        }\n\n        egl->width  = IJK_EGL_getSurfaceWidth(egl);\n        egl->height = IJK_EGL_getSurfaceHeight(egl);\n        return (egl->width && egl->height) ? EGL_TRUE : EGL_FALSE;\n    }\n\n    return EGL_TRUE;\n#else\n    // FIXME: other platform?\n#endif\n    return EGL_FALSE;\n}\n\nstatic EGLBoolean IJK_EGL_makeCurrent(IJK_EGL* egl, EGLNativeWindowType window)\n{\n    if (window && window == egl->window &&\n        egl->display &&\n        egl->surface &&\n        egl->context) {\n\n        if (!eglMakeCurrent(egl->display, egl->surface, egl->surface, egl->context)) {\n            ALOGE(\"[EGL] elgMakeCurrent() failed (cached)\\n\");\n            return EGL_FALSE;\n        }\n\n        return EGL_TRUE;\n    }\n\n    IJK_EGL_terminate(egl);\n    egl->window = window;\n\n    if (!window)\n        return EGL_FALSE;\n\n    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);\n    if (display == EGL_NO_DISPLAY) {\n        ALOGE(\"[EGL] eglGetDisplay failed\\n\");\n        return EGL_FALSE;\n    }\n\n\n    EGLint major, minor;\n    if (!eglInitialize(display, &major, &minor)) {\n        ALOGE(\"[EGL] eglInitialize failed\\n\");\n        return EGL_FALSE;   \n    }\n    ALOGI(\"[EGL] eglInitialize %d.%d\\n\", (int)major, (int)minor);\n\n\n    static const EGLint configAttribs[] = {\n        EGL_RENDERABLE_TYPE,    EGL_OPENGL_ES2_BIT,\n        EGL_SURFACE_TYPE,       EGL_WINDOW_BIT,\n        EGL_BLUE_SIZE,          8,\n        EGL_GREEN_SIZE,         8,\n        EGL_RED_SIZE,           8,\n        EGL_NONE\n    };\n\n    static const EGLint contextAttribs[] = {\n        EGL_CONTEXT_CLIENT_VERSION, 2,\n        EGL_NONE\n    };\n\n    EGLConfig config;\n    EGLint numConfig;\n    if (!eglChooseConfig(display, configAttribs, &config, 1, &numConfig)) {\n        ALOGE(\"[EGL] eglChooseConfig failed\\n\");\n        eglTerminate(display);\n        return EGL_FALSE;\n    }\n\n#ifdef __ANDROID__\n    {\n        EGLint native_visual_id = 0;\n        if (!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &native_visual_id)) {\n            ALOGE(\"[EGL] eglGetConfigAttrib() returned error %d\", eglGetError());\n            eglTerminate(display);\n            return EGL_FALSE;\n        }\n\n        int32_t width  = ANativeWindow_getWidth(window);\n        int32_t height = ANativeWindow_getWidth(window);\n        ALOGI(\"[EGL] ANativeWindow_setBuffersGeometry(f=%d);\", native_visual_id);\n        int ret = ANativeWindow_setBuffersGeometry(window, width, height, native_visual_id);\n        if (ret) {\n            ALOGE(\"[EGL] ANativeWindow_setBuffersGeometry(format) returned error %d\", ret);\n            eglTerminate(display);\n            return EGL_FALSE;\n        }\n    }\n#endif\n\n    EGLSurface surface = eglCreateWindowSurface(display, config, window, NULL);\n    if (surface == EGL_NO_SURFACE) {\n        ALOGE(\"[EGL] eglCreateWindowSurface failed\\n\");\n        eglTerminate(display);\n        return EGL_FALSE;\n    }\n\n    EGLSurface context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);\n    if (context == EGL_NO_CONTEXT) {\n        ALOGE(\"[EGL] eglCreateContext failed\\n\");\n        eglDestroySurface(display, surface);\n        eglTerminate(display);\n        return EGL_FALSE;\n    }\n\n    if (!eglMakeCurrent(display, surface, surface, context)) {\n        ALOGE(\"[EGL] elgMakeCurrent() failed (new)\\n\");\n        eglDestroyContext(display, context);\n        eglDestroySurface(display, surface);\n        eglTerminate(display);\n        return EGL_FALSE;\n    }\n\n#if 0\n#if defined(__ANDROID__)\n    {\n        const char *extensions = (const char *) glGetString(GL_EXTENSIONS);\n        if (extensions) {\n            char *dup_extensions = strdup(extensions);\n            if (dup_extensions) {\n                char *brk = NULL;\n                char *ext = strtok_r(dup_extensions, \" \", &brk);\n                while (ext) {\n                    if (0 == strcmp(ext, \"GL_EXT_texture_rg\"))\n                        egl->gles2_extensions[IJK_GLES2__GL_EXT_texture_rg] = 1;\n\n                    ext = strtok_r(NULL, \" \", &brk);\n                }\n\n                free(dup_extensions);\n            }\n        }\n    }\n#elif defined(__APPLE__)\n    egl->gles2_extensions[IJK_GLES2__GL_EXT_texture_rg] = 1;\n#endif\n\n    ALOGI(\"[EGL] GLES2 extensions begin:\\n\");\n    ALOGI(\"[EGL]     GL_EXT_texture_rg: %d\\n\", egl->gles2_extensions[IJK_GLES2__GL_EXT_texture_rg]);\n    ALOGI(\"[EGL] GLES2 extensions end.\\n\");\n#endif\n\n    IJK_GLES2_Renderer_setupGLES();\n\n    egl->context = context;\n    egl->surface = surface;\n    egl->display = display;\n    return EGL_TRUE;\n}\n\nstatic EGLBoolean IJK_EGL_prepareRenderer(IJK_EGL* egl, SDL_VoutOverlay *overlay)\n{\n    assert(egl);\n    assert(egl->opaque);\n\n    IJK_EGL_Opaque *opaque = egl->opaque;\n\n    if (!IJK_GLES2_Renderer_isValid(opaque->renderer) ||\n        !IJK_GLES2_Renderer_isFormat(opaque->renderer, overlay->format)) {\n\n        IJK_GLES2_Renderer_reset(opaque->renderer);\n        IJK_GLES2_Renderer_freeP(&opaque->renderer);\n\n        opaque->renderer = IJK_GLES2_Renderer_create(overlay);\n        if (!opaque->renderer) {\n            ALOGE(\"[EGL] Could not create render.\");\n            return EGL_FALSE;\n        }\n\n        if (!IJK_GLES2_Renderer_use(opaque->renderer)) {\n            ALOGE(\"[EGL] Could not use render.\");\n            IJK_GLES2_Renderer_freeP(&opaque->renderer);\n            return EGL_FALSE;\n        }\n    }\n\n    if (!IJK_EGL_setSurfaceSize(egl, overlay->w, overlay->h)) {\n        ALOGE(\"[EGL] IJK_EGL_setSurfaceSize(%d, %d) failed\\n\", overlay->w, overlay->h);\n        return EGL_FALSE;\n    }\n\n    glViewport(0, 0, egl->width, egl->height);  IJK_GLES2_checkError_TRACE(\"glViewport\");\n    return EGL_TRUE;\n}\n\nstatic EGLBoolean IJK_EGL_display_internal(IJK_EGL* egl, EGLNativeWindowType window, SDL_VoutOverlay *overlay)\n{\n    IJK_EGL_Opaque *opaque = egl->opaque;\n\n    if (!IJK_EGL_prepareRenderer(egl, overlay)) {\n        ALOGE(\"[EGL] IJK_EGL_prepareRenderer failed\\n\");\n        return EGL_FALSE;\n    }\n\n    if (!IJK_GLES2_Renderer_renderOverlay(opaque->renderer, overlay)) {\n        ALOGE(\"[EGL] IJK_GLES2_render failed\\n\");\n        return EGL_FALSE; \n    }\n\n    eglSwapBuffers(egl->display, egl->surface);\n\n    return EGL_TRUE;\n}\n\nEGLBoolean IJK_EGL_display(IJK_EGL* egl, EGLNativeWindowType window, SDL_VoutOverlay *overlay)\n{\n    EGLBoolean ret = EGL_FALSE;\n    if (!egl)\n        return EGL_FALSE;\n\n    IJK_EGL_Opaque *opaque = egl->opaque;\n    if (!opaque)\n        return EGL_FALSE;\n\n    if (!IJK_EGL_makeCurrent(egl, window))\n        return EGL_FALSE;\n\n    ret = IJK_EGL_display_internal(egl, window, overlay);\n    eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);\n    eglReleaseThread(); // FIXME: call at thread exit\n    return ret;\n}\n\nvoid IJK_EGL_releaseWindow(IJK_EGL* egl)\n{\n    if (!egl || !egl->opaque || !egl->opaque->renderer)\n        return;\n\n    IJK_EGL_terminate(egl);\n}\n\nvoid IJK_EGL_free(IJK_EGL *egl)\n{\n    if (!egl)\n        return;\n\n    IJK_EGL_terminate(egl);\n\n    memset(egl, 0, sizeof(IJK_EGL));\n    free(egl);\n}\n\nvoid IJK_EGL_freep(IJK_EGL **egl)\n{\n    if (!egl || !*egl)\n        return;\n\n    IJK_EGL_free(*egl);\n    *egl = NULL;\n}\n\nstatic SDL_Class g_class = {\n    .name = \"EGL\",\n};\n\nIJK_EGL *IJK_EGL_create()\n{\n    IJK_EGL *egl = (IJK_EGL*) mallocz(sizeof(IJK_EGL));\n    if (!egl)\n        return NULL;\n\n    egl->opaque_class = &g_class;\n    egl->opaque = mallocz(sizeof(IJK_EGL_Opaque));\n    if (!egl->opaque) {\n        free(egl);\n        return NULL;\n    }\n\n    return egl;\n}\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_egl.h",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL__IJKSDL_EGL_H\n#define IJKSDL__IJKSDL_EGL_H\n\n#ifdef __APPLE__\n#include \"ijksdl/ios/EGL/egl.h\"\n#include \"ijksdl/ios/EGL/eglplatform.h\"\n#else\n#include <EGL/egl.h>\n#include <EGL/eglext.h>\n#include <EGL/eglplatform.h>\n#endif\n#include \"ijksdl_class.h\"\n\ntypedef struct SDL_VoutOverlay SDL_VoutOverlay;\ntypedef struct IJK_EGL_Opaque  IJK_EGL_Opaque;\n\n#if 0\nenum {\n    IJK_GLES2__GL_EXT_texture_rg,\n    IJK_GLES2__MAX_EXT,\n};\n#endif\n\ntypedef struct IJK_EGL\n{\n    SDL_Class      *opaque_class;\n    IJK_EGL_Opaque *opaque;\n\n    EGLNativeWindowType window;\n\n    EGLDisplay display;\n    EGLSurface surface;\n    EGLContext context;\n\n    EGLint width;\n    EGLint height;\n\n#if 0\n    uint8_t gles2_extensions[IJK_GLES2__MAX_EXT];\n#endif\n} IJK_EGL;\n\nIJK_EGL    *IJK_EGL_create();\nvoid        IJK_EGL_free(IJK_EGL *egl);\nvoid        IJK_EGL_freep(IJK_EGL **egl);\n\nEGLBoolean  IJK_EGL_display(IJK_EGL* egl, EGLNativeWindowType window, SDL_VoutOverlay *overlay);\nvoid        IJK_EGL_terminate(IJK_EGL* egl);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_endian.h",
    "content": "/*****************************************************************************\n * ijksdl_endian.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL__IJKSDL_ENDIAN_H\n#define IJKSDL__IJKSDL_ENDIAN_H\n\n#define SDL_LIL_ENDIAN  1234\n#define SDL_BIG_ENDIAN  4321\n\n#ifndef SDL_BYTEORDER           /* Not defined in SDL_config.h? */\n#ifdef __linux__\n#include <endian.h>\n#define SDL_BYTEORDER  __BYTE_ORDER\n#else /* __linux __ */\n#if defined(__hppa__) || \\\n    defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \\\n    (defined(__MIPS__) && defined(__MISPEB__)) || \\\n    defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) || \\\n    defined(__sparc__)\n#define SDL_BYTEORDER   SDL_BIG_ENDIAN\n#else\n#define SDL_BYTEORDER   SDL_LIL_ENDIAN\n#endif\n#endif /* __linux __ */\n#endif /* !SDL_BYTEORDER */\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_error.c",
    "content": "/*****************************************************************************\n * ijksdl_error.c\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl_error.h\"\n#include \"ijksdl_stdinc.h\"\n\nconst char *SDL_GetError(void)\n{\n    return NULL;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_error.h",
    "content": "/*****************************************************************************\n * ijksdl_error.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL__IJKSDL_ERROR_H\n#define IJKSDL__IJKSDL_ERROR_H\n\nconst char *SDL_GetError(void);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_extra_log.c",
    "content": "/*****************************************************************************\n * ijksdl_extra_log.c\n *****************************************************************************\n *\n * Copyright (c) 2017 Bilibili\n * copyright (c) 2017 Raymond Zheng <raymondzheng1412@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n#include \"ijksdl_extra_log.h\"\n#include \"ijksdl/android/ijksdl_android_jni.h\"\n#include <stdio.h>\n\n#define LOG_BUF_SIZE\t1024\n\n#ifdef EXTRA_LOG_PRINT\nvoid ffp_log_extra_print(int level, const char *tag, const char *fmt, ...)\n{\n    JNIEnv *env = NULL;\n\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        return;\n    }\n    va_list ap;\n    char log_buffer[LOG_BUF_SIZE] = {0};\n\n    va_start(ap, fmt);\n    vsnprintf(log_buffer, LOG_BUF_SIZE, fmt, ap);\n    va_end(ap);\n    switch (level) {\n        case ANDROID_LOG_UNKNOWN:\n        case ANDROID_LOG_DEFAULT:\n        case ANDROID_LOG_VERBOSE:\n            J4AC_BLog__v__withCString__catchAll(env, tag, log_buffer);\n            break;\n        case ANDROID_LOG_DEBUG:\n            J4AC_BLog__d__withCString__catchAll(env, tag, log_buffer);\n            break;\n        case ANDROID_LOG_INFO:\n            J4AC_BLog__i__withCString__catchAll(env, tag, log_buffer);\n            break;\n        case ANDROID_LOG_WARN:\n            J4AC_BLog__w__withCString__catchAll(env, tag, log_buffer);\n            break;\n        case ANDROID_LOG_FATAL:\n        case ANDROID_LOG_SILENT:\n        case ANDROID_LOG_ERROR:\n            J4AC_BLog__e__withCString__catchAll(env, tag, log_buffer);\n            break;\n        default:\n            break;\n    }\n}\n\nvoid ffp_log_extra_vprint(int level, const char *tag, const char *fmt, va_list ap)\n{\n    JNIEnv *env = NULL;\n    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {\n        return;\n    }\n    char log_buffer[LOG_BUF_SIZE] = {0};\n\n    vsnprintf(log_buffer, LOG_BUF_SIZE, fmt, ap);\n    switch (level) {\n        case ANDROID_LOG_UNKNOWN:\n        case ANDROID_LOG_DEFAULT:\n        case ANDROID_LOG_VERBOSE:\n            J4AC_BLog__v__withCString__catchAll(env, tag, log_buffer);\n            break;\n        case ANDROID_LOG_DEBUG:\n            J4AC_BLog__d__withCString__catchAll(env, tag, log_buffer);\n            break;\n        case ANDROID_LOG_INFO:\n            J4AC_BLog__i__withCString__catchAll(env, tag, log_buffer);\n            break;\n        case ANDROID_LOG_WARN:\n            J4AC_BLog__w__withCString__catchAll(env, tag, log_buffer);\n            break;\n        case ANDROID_LOG_FATAL:\n        case ANDROID_LOG_SILENT:\n        case ANDROID_LOG_ERROR:\n            J4AC_BLog__e__withCString__catchAll(env, tag, log_buffer);\n            break;\n        default:\n            break;\n    }\n}\n#endif  // EXTRA_LOG_PRINT"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_extra_log.h",
    "content": "/*****************************************************************************\n * ijksdl_extra_log.h\n *****************************************************************************\n *\n * Copyright (c) 2017 Bilibili\n * copyright (c) 2017 Raymond Zheng <raymondzheng1412@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL__IJKSDL_EXTRA_LOG_H\n#define IJKSDL__IJKSDL_EXTRA_LOG_H\n\n#ifdef __ANDROID__\n#include <android/log.h>\n\nvoid ffp_log_extra_print(int level, const char *tag, const char *fmt, ...);\nvoid ffp_log_extra_vprint(int level, const char *tag, const char *fmt, va_list ap);\n#endif\n\n#endif  // IJKSDL__IJKSDL_EXTRA_LOG_H\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_fourcc.h",
    "content": "/*****************************************************************************\n * ijksdl_fourcc.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL__IJKSDL_FOURCC_H\n#define IJKSDL__IJKSDL_FOURCC_H\n\n#include \"ijksdl_stdinc.h\"\n#include \"ijksdl_endian.h\"\n\n#if SDL_BYTEORDER == SDL_LIL_ENDIAN\n#   define SDL_FOURCC(a, b, c, d) \\\n        (((uint32_t)a) | (((uint32_t)b) << 8) | (((uint32_t)c) << 16) | (((uint32_t)d) << 24))\n#   define SDL_TWOCC(a, b) \\\n        ((uint16_t)(a) | ((uint16_t)(b) << 8))\n#else\n#   define SDL_FOURCC(a, b, c, d) \\\n        (((uint32_t)d) | (((uint32_t)c) << 8) | (((uint32_t)b) << 16) | (((uint32_t)a) << 24))\n#   define SDL_TWOCC( a, b ) \\\n        ((uint16_t)(b) | ((uint16_t)(a) << 8))\n#endif\n\n/*-\n *  http://www.webartz.com/fourcc/indexyuv.htm\n *  http://www.neuro.sfc.keio.ac.jp/~aly/polygon/info/color-space-faq.html\n *  http://www.fourcc.org/yuv.php\n */\n\n// YUV formats\n#define SDL_FCC_YV12    SDL_FOURCC('Y', 'V', '1', '2')  /**< bpp=12, Planar mode: Y + V + U  (3 planes) */\n#define SDL_FCC_IYUV    SDL_FOURCC('I', 'Y', 'U', 'V')  /**< bpp=12, Planar mode: Y + U + V  (3 planes) */\n#define SDL_FCC_I420    SDL_FOURCC('I', '4', '2', '0')  /**< bpp=12, Planar mode: Y + U + V  (3 planes) */\n#define SDL_FCC_I444P10LE   SDL_FOURCC('I', '4', 'A', 'L')\n\n#define SDL_FCC_YUV2    SDL_FOURCC('Y', 'U', 'V', '2')  /**< bpp=16, Packed mode: Y0+U0+Y1+V0 (1 plane) */\n#define SDL_FCC_UYVY    SDL_FOURCC('U', 'Y', 'V', 'Y')  /**< bpp=16, Packed mode: U0+Y0+V0+Y1 (1 plane) */\n#define SDL_FCC_YVYU    SDL_FOURCC('Y', 'V', 'Y', 'U')  /**< bpp=16, Packed mode: Y0+V0+Y1+U0 (1 plane) */\n\n#define SDL_FCC_NV12    SDL_FOURCC('N', 'V', '1', '2')\n\n// RGB formats\n#define SDL_FCC_RV16    SDL_FOURCC('R', 'V', '1', '6')    /**< bpp=16, RGB565 */\n#define SDL_FCC_RV24    SDL_FOURCC('R', 'V', '2', '4')    /**< bpp=24, RGB888 */\n#define SDL_FCC_RV32    SDL_FOURCC('R', 'V', '3', '2')    /**< bpp=32, RGBX8888 */\n\n// opaque formats\n#define SDL_FCC__AMC    SDL_FOURCC('_', 'A', 'M', 'C')    /**< Android MediaCodec */\n#define SDL_FCC__VTB    SDL_FOURCC('_', 'V', 'T', 'B')    /**< iOS VideoToolbox */\n#define SDL_FCC__GLES2  SDL_FOURCC('_', 'E', 'S', '2')    /**< let Vout choose format */\n\n// undefine\n#define SDL_FCC_UNDF    SDL_FOURCC('U', 'N', 'D', 'F')    /**< undefined */\n\nenum {\n    IJK_AV_PIX_FMT__START = 10000,\n    IJK_AV_PIX_FMT__ANDROID_MEDIACODEC,\n    IJK_AV_PIX_FMT__VIDEO_TOOLBOX,\n};\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_gles2.h",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL__IJKSDL_GLES2_H\n#define IJKSDL__IJKSDL_GLES2_H\n\n#ifdef __APPLE__\n#include <OpenGLES/ES2/gl.h>\n#include <OpenGLES/ES2/glext.h>\n#else\n#include <GLES2/gl2.h>\n#include <GLES2/gl2ext.h>\n#include <GLES2/gl2platform.h>\n#endif\n\ntypedef struct SDL_VoutOverlay SDL_VoutOverlay;\n\n/*\n * Common\n */\n\n#ifdef DEBUG\n#define IJK_GLES2_checkError_TRACE(op)\n#define IJK_GLES2_checkError_DEBUG(op)\n#else\n#define IJK_GLES2_checkError_TRACE(op) IJK_GLES2_checkError(op) \n#define IJK_GLES2_checkError_DEBUG(op) IJK_GLES2_checkError(op)\n#endif\n\nvoid IJK_GLES2_printString(const char *name, GLenum s);\nvoid IJK_GLES2_checkError(const char *op);\n\nGLuint IJK_GLES2_loadShader(GLenum shader_type, const char *shader_source);\n\n\n/*\n * Renderer\n */\n#define IJK_GLES2_MAX_PLANE 3\ntypedef struct IJK_GLES2_Renderer IJK_GLES2_Renderer;\n\nIJK_GLES2_Renderer *IJK_GLES2_Renderer_create(SDL_VoutOverlay *overlay);\nvoid      IJK_GLES2_Renderer_reset(IJK_GLES2_Renderer *renderer);\nvoid      IJK_GLES2_Renderer_free(IJK_GLES2_Renderer *renderer);\nvoid      IJK_GLES2_Renderer_freeP(IJK_GLES2_Renderer **renderer);\n\nGLboolean IJK_GLES2_Renderer_setupGLES();\nGLboolean IJK_GLES2_Renderer_isValid(IJK_GLES2_Renderer *renderer);\nGLboolean IJK_GLES2_Renderer_isFormat(IJK_GLES2_Renderer *renderer, int format);\nGLboolean IJK_GLES2_Renderer_use(IJK_GLES2_Renderer *renderer);\nGLboolean IJK_GLES2_Renderer_renderOverlay(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay);\n\n#define IJK_GLES2_GRAVITY_RESIZE                (0) // Stretch to fill view bounds.\n#define IJK_GLES2_GRAVITY_RESIZE_ASPECT         (1) // Preserve aspect ratio; fit within view bounds.\n#define IJK_GLES2_GRAVITY_RESIZE_ASPECT_FILL    (2) // Preserve aspect ratio; fill view bounds.\nGLboolean IJK_GLES2_Renderer_setGravity(IJK_GLES2_Renderer *renderer, int gravity, GLsizei view_width, GLsizei view_height);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_inc_internal.h",
    "content": "/*\n * ijksdl_inc_internal.h\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKPLAYER__IJKSDL_INC_INTERNAL_H\n#define IJKPLAYER__IJKSDL_INC_INTERNAL_H\n\n#include <stdint.h>\n\n#include \"ijksdl_log.h\"\n#include \"ijksdl_misc.h\"\n#include \"ijksdl_stdinc.h\"\n\n#define SDLTRACE ALOGD\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_log.h",
    "content": "/*****************************************************************************\n * ijksdl_log.h\n *****************************************************************************\n *\n * Copyright (c) 2015 Bilibili\n * copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL__IJKSDL_LOG_H\n#define IJKSDL__IJKSDL_LOG_H\n\n#include <stdio.h>\n\n#ifdef __ANDROID__\n\n#include <android/log.h>\n#include \"ijksdl_extra_log.h\"\n\n#define IJK_LOG_UNKNOWN     ANDROID_LOG_UNKNOWN\n#define IJK_LOG_DEFAULT     ANDROID_LOG_DEFAULT\n\n#define IJK_LOG_VERBOSE     ANDROID_LOG_VERBOSE\n#define IJK_LOG_DEBUG       ANDROID_LOG_DEBUG\n#define IJK_LOG_INFO        ANDROID_LOG_INFO\n#define IJK_LOG_WARN        ANDROID_LOG_WARN\n#define IJK_LOG_ERROR       ANDROID_LOG_ERROR\n#define IJK_LOG_FATAL       ANDROID_LOG_FATAL\n#define IJK_LOG_SILENT      ANDROID_LOG_SILENT\n\n#ifdef EXTRA_LOG_PRINT\n#define VLOG(level, TAG, ...)    ffp_log_extra_vprint(level, TAG, __VA_ARGS__)\n#define ALOG(level, TAG, ...)    ffp_log_extra_print(level, TAG, __VA_ARGS__)\n#else\n#define VLOG(level, TAG, ...)    ((void)__android_log_vprint(level, TAG, __VA_ARGS__))\n#define ALOG(level, TAG, ...)    ((void)__android_log_print(level, TAG, __VA_ARGS__))\n#endif\n\n#else\n\n#define IJK_LOG_UNKNOWN     0\n#define IJK_LOG_DEFAULT     1\n\n#define IJK_LOG_VERBOSE     2\n#define IJK_LOG_DEBUG       3\n#define IJK_LOG_INFO        4\n#define IJK_LOG_WARN        5\n#define IJK_LOG_ERROR       6\n#define IJK_LOG_FATAL       7\n#define IJK_LOG_SILENT      8\n\n#define VLOG(level, TAG, ...)    ((void)vprintf(__VA_ARGS__))\n#define ALOG(level, TAG, ...)    ((void)printf(__VA_ARGS__))\n\n#endif\n\n#define IJK_LOG_TAG \"IJKMEDIA\"\n\n#define VLOGV(...)  VLOG(IJK_LOG_VERBOSE,   IJK_LOG_TAG, __VA_ARGS__)\n#define VLOGD(...)  VLOG(IJK_LOG_DEBUG,     IJK_LOG_TAG, __VA_ARGS__)\n#define VLOGI(...)  VLOG(IJK_LOG_INFO,      IJK_LOG_TAG, __VA_ARGS__)\n#define VLOGW(...)  VLOG(IJK_LOG_WARN,      IJK_LOG_TAG, __VA_ARGS__)\n#define VLOGE(...)  VLOG(IJK_LOG_ERROR,     IJK_LOG_TAG, __VA_ARGS__)\n\n#define ALOGV(...)  ALOG(IJK_LOG_VERBOSE,   IJK_LOG_TAG, __VA_ARGS__)\n#define ALOGD(...)  ALOG(IJK_LOG_DEBUG,     IJK_LOG_TAG, __VA_ARGS__)\n#define ALOGI(...)  ALOG(IJK_LOG_INFO,      IJK_LOG_TAG, __VA_ARGS__)\n#define ALOGW(...)  ALOG(IJK_LOG_WARN,      IJK_LOG_TAG, __VA_ARGS__)\n#define ALOGE(...)  ALOG(IJK_LOG_ERROR,     IJK_LOG_TAG, __VA_ARGS__)\n#define LOG_ALWAYS_FATAL(...)   do { ALOGE(__VA_ARGS__); exit(1); } while (0)\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_misc.h",
    "content": "/*****************************************************************************\n * ijksdl_misc.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL__IJKSDL_MISC_H\n#define IJKSDL__IJKSDL_MISC_H\n\n#include <stdlib.h>\n#include <memory.h>\n\n#ifndef IJKMAX\n#define IJKMAX(a, b)    ((a) > (b) ? (a) : (b))\n#endif\n\n#ifndef IJKMIN\n#define IJKMIN(a, b)    ((a) < (b) ? (a) : (b))\n#endif\n\n#ifndef IJKALIGN\n#define IJKALIGN(x, align) ((( x ) + (align) - 1) / (align) * (align))\n#endif\n\n#define IJK_CHECK_RET(condition__, retval__, ...) \\\n    if (!(condition__)) { \\\n        ALOGE(__VA_ARGS__); \\\n        return (retval__); \\\n    }\n\n#ifndef NELEM\n#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))\n#endif\n\ninline static void *mallocz(size_t size)\n{\n    void *mem = malloc(size);\n    if (!mem)\n        return mem;\n\n    memset(mem, 0, size);\n    return mem;\n}\n\ninline static void freep(void **mem)\n{\n    if (mem && *mem) {\n        free(*mem);\n        *mem = NULL;\n    }\n}\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_mutex.c",
    "content": "/*****************************************************************************\n * ijksdl_mutex.c\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl_mutex.h\"\n#include <errno.h>\n#include <assert.h>\n#include <sys/time.h>\n#include \"ijksdl_inc_internal.h\"\n\nSDL_mutex *SDL_CreateMutex(void)\n{\n    SDL_mutex *mutex;\n    mutex = (SDL_mutex *) mallocz(sizeof(SDL_mutex));\n    if (!mutex)\n        return NULL;\n\n    if (pthread_mutex_init(&mutex->id, NULL) != 0) {\n        free(mutex);\n        return NULL;\n    }\n\n    return mutex;\n}\n\nvoid SDL_DestroyMutex(SDL_mutex *mutex)\n{\n    if (mutex) {\n        pthread_mutex_destroy(&mutex->id);\n        free(mutex);\n    }\n}\n\nvoid SDL_DestroyMutexP(SDL_mutex **mutex)\n{\n    if (mutex) {\n        SDL_DestroyMutex(*mutex);\n        *mutex = NULL;\n    }\n}\n\nint SDL_LockMutex(SDL_mutex *mutex)\n{\n    assert(mutex);\n    if (!mutex)\n        return -1;\n\n    return pthread_mutex_lock(&mutex->id);\n}\n\nint SDL_UnlockMutex(SDL_mutex *mutex)\n{\n    assert(mutex);\n    if (!mutex)\n        return -1;\n\n    return pthread_mutex_unlock(&mutex->id);\n}\n\nSDL_cond *SDL_CreateCond(void)\n{\n    SDL_cond *cond;\n    cond = (SDL_cond *) mallocz(sizeof(SDL_cond));\n    if (!cond)\n        return NULL;\n\n    if (pthread_cond_init(&cond->id, NULL) != 0) {\n        free(cond);\n        return NULL;\n    }\n\n    return cond;\n}\n\nvoid SDL_DestroyCond(SDL_cond *cond)\n{\n    if (cond) {\n        pthread_cond_destroy(&cond->id);\n        free(cond);\n    }\n}\n\nvoid SDL_DestroyCondP(SDL_cond **cond)\n{\n\n    if (cond) {\n        SDL_DestroyCond(*cond);\n        *cond = NULL;\n    }\n}\n\nint SDL_CondSignal(SDL_cond *cond)\n{\n    assert(cond);\n    if (!cond)\n        return -1;\n\n    return pthread_cond_signal(&cond->id);\n}\n\nint SDL_CondBroadcast(SDL_cond *cond)\n{\n    assert(cond);\n    if (!cond)\n        return -1;\n\n    return pthread_cond_broadcast(&cond->id);\n}\n\nint SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, uint32_t ms)\n{\n    int retval;\n    struct timeval delta;\n    struct timespec abstime;\n\n    assert(cond);\n    assert(mutex);\n    if (!cond || !mutex) {\n        return -1;\n    }\n\n    gettimeofday(&delta, NULL);\n\n    abstime.tv_sec = delta.tv_sec + (ms / 1000);\n    abstime.tv_nsec = (delta.tv_usec + (ms % 1000) * 1000) * 1000;\n    if (abstime.tv_nsec > 1000000000) {\n        abstime.tv_sec += 1;\n        abstime.tv_nsec -= 1000000000;\n    }\n\n    while (1) {\n        retval = pthread_cond_timedwait(&cond->id, &mutex->id, &abstime);\n        if (retval == 0)\n            return 0;\n        else if (retval == EINTR)\n            continue;\n        else if (retval == ETIMEDOUT)\n            return SDL_MUTEX_TIMEDOUT;\n        else\n            break;\n    }\n\n    return -1;\n}\n\nint SDL_CondWait(SDL_cond *cond, SDL_mutex *mutex)\n{\n    assert(cond);\n    assert(mutex);\n    if (!cond || !mutex)\n        return -1;\n\n    return pthread_cond_wait(&cond->id, &mutex->id);\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_mutex.h",
    "content": "/*****************************************************************************\n * ijksdl_mutex.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL__IJKSDL_MUTEX_H\n#define IJKSDL__IJKSDL_MUTEX_H\n\n#include <stdint.h>\n#include <pthread.h>\n\n#define SDL_MUTEX_TIMEDOUT  1\n#define SDL_MUTEX_MAXWAIT   (~(uint32_t)0)\n\ntypedef struct SDL_mutex {\n    pthread_mutex_t id;\n} SDL_mutex;\n\nSDL_mutex  *SDL_CreateMutex(void);\nvoid        SDL_DestroyMutex(SDL_mutex *mutex);\nvoid        SDL_DestroyMutexP(SDL_mutex **mutex);\nint         SDL_LockMutex(SDL_mutex *mutex);\nint         SDL_UnlockMutex(SDL_mutex *mutex);\n\ntypedef struct SDL_cond {\n    pthread_cond_t id;\n} SDL_cond;\n\nSDL_cond   *SDL_CreateCond(void);\nvoid        SDL_DestroyCond(SDL_cond *cond);\nvoid        SDL_DestroyCondP(SDL_cond **mutex);\nint         SDL_CondSignal(SDL_cond *cond);\nint         SDL_CondBroadcast(SDL_cond *cond);\nint         SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, uint32_t ms);\nint         SDL_CondWait(SDL_cond *cond, SDL_mutex *mutex);\n\n#endif\n\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_stdinc.c",
    "content": "/*****************************************************************************\n * ijksdl_stdinc.c\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl_stdinc.h\"\n\nchar *SDL_getenv(const char *name)\n{\n    return NULL;\n}\n\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_stdinc.h",
    "content": "/*****************************************************************************\n * ijksdl_stdinc.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL__IJKSDL_STDINC_H\n#define IJKSDL__IJKSDL_STDINC_H\n\n#include <stddef.h>\n#include <stdint.h>\n#include <stdbool.h>\n\ntypedef int8_t      Sint8;\ntypedef uint8_t     Uint8;\ntypedef int16_t     Sint16;\ntypedef uint16_t    Uint16;\ntypedef int32_t     Sint32;\ntypedef uint32_t    Uint32;\ntypedef int64_t     Sint64;\ntypedef uint64_t    Uint64;\n\nchar *SDL_getenv(const char *name);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_thread.c",
    "content": "/*****************************************************************************\n * ijksdl_thread.c\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include <errno.h>\n#include <assert.h>\n#include <unistd.h>\n#include \"ijksdl_inc_internal.h\"\n#include \"ijksdl_thread.h\"\n#ifdef __ANDROID__\n#include \"ijksdl/android/ijksdl_android_jni.h\"\n#endif\n\n#if !defined(__APPLE__)\n// using ios implement for autorelease\nstatic void *SDL_RunThread(void *data)\n{\n    SDL_Thread *thread = data;\n    ALOGI(\"SDL_RunThread: [%d] %s\\n\", (int)gettid(), thread->name);\n    pthread_setname_np(pthread_self(), thread->name);\n    thread->retval = thread->func(thread->data);\n#ifdef __ANDROID__\n    SDL_JNI_DetachThreadEnv();\n#endif\n    return NULL;\n}\n\nSDL_Thread *SDL_CreateThreadEx(SDL_Thread *thread, int (*fn)(void *), void *data, const char *name)\n{\n    thread->func = fn;\n    thread->data = data;\n    strlcpy(thread->name, name, sizeof(thread->name) - 1);\n    int retval = pthread_create(&thread->id, NULL, SDL_RunThread, thread);\n    if (retval)\n        return NULL;\n\n    return thread;\n}\n#endif\n\nint SDL_SetThreadPriority(SDL_ThreadPriority priority)\n{\n    struct sched_param sched;\n    int policy;\n    pthread_t thread = pthread_self();\n\n    if (pthread_getschedparam(thread, &policy, &sched) < 0) {\n        ALOGE(\"pthread_getschedparam() failed\");\n        return -1;\n    }\n    if (priority == SDL_THREAD_PRIORITY_LOW) {\n        sched.sched_priority = sched_get_priority_min(policy);\n    } else if (priority == SDL_THREAD_PRIORITY_HIGH) {\n        sched.sched_priority = sched_get_priority_max(policy);\n    } else {\n        int min_priority = sched_get_priority_min(policy);\n        int max_priority = sched_get_priority_max(policy);\n        sched.sched_priority = (min_priority + (max_priority - min_priority) / 2);\n    }\n    if (pthread_setschedparam(thread, policy, &sched) < 0) {\n        ALOGE(\"pthread_setschedparam() failed\");\n        return -1;\n    }\n    return 0;\n}\n\nvoid SDL_WaitThread(SDL_Thread *thread, int *status)\n{\n    assert(thread);\n    if (!thread)\n        return;\n\n    pthread_join(thread->id, NULL);\n\n    if (status)\n        *status = thread->retval;\n}\n\nvoid SDL_DetachThread(SDL_Thread *thread)\n{\n    assert(thread);\n    if (!thread)\n        return;\n\n    pthread_detach(thread->id);\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_thread.h",
    "content": "/*****************************************************************************\n * ijksdl_thread.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL__IJKSDL_THREAD_H\n#define IJKSDL__IJKSDL_THREAD_H\n\n#include <stdint.h>\n#include <pthread.h>\n\ntypedef enum {\n    SDL_THREAD_PRIORITY_LOW,\n    SDL_THREAD_PRIORITY_NORMAL,\n    SDL_THREAD_PRIORITY_HIGH\n} SDL_ThreadPriority;\n\ntypedef struct SDL_Thread\n{\n    pthread_t id;\n    int (*func)(void *);\n    void *data;\n    char name[32];\n    int retval;\n} SDL_Thread;\n\nSDL_Thread *SDL_CreateThreadEx(SDL_Thread *thread, int (*fn)(void *), void *data, const char *name);\nint         SDL_SetThreadPriority(SDL_ThreadPriority priority);\nvoid        SDL_WaitThread(SDL_Thread *thread, int *status);\nvoid        SDL_DetachThread(SDL_Thread *thread);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_timer.c",
    "content": "/*****************************************************************************\n * ijksdl_thread.c\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl_timer.h\"\n#include <unistd.h>\n#include <string.h>\n#include <stdlib.h>\n#include <time.h>\n#include <sys/time.h>\n\n#if defined(__APPLE__)\n#include <mach/mach_time.h>\n\nstatic int g_is_mach_base_info_inited = 0;\nstatic kern_return_t g_mach_base_info_ret = 0;\nstatic mach_timebase_info_data_t g_mach_base_info;\n\n/* nanosleep is not included in c99, just a workaround for CocoaPods */\nint nanosleep(const struct timespec *, struct timespec *) __DARWIN_ALIAS_C(nanosleep);\n#endif\n\n#include \"ijksdl_log.h\"\n\nvoid SDL_Delay(Uint32 ms)\n{\n    int was_error;\n    struct timespec elapsed, tv;\n\n    /* Set the timeout interval */\n    elapsed.tv_sec = ms / 1000;\n    elapsed.tv_nsec = (ms % 1000) * 1000000;\n    do {\n        tv.tv_sec = elapsed.tv_sec;\n        tv.tv_nsec = elapsed.tv_nsec;\n        was_error = nanosleep(&tv, &elapsed);\n    } while (was_error);\n}\n\nUint64 SDL_GetTickHR(void)\n{\n    Uint64 clock;\n#if defined(__ANDROID__)\n    struct timespec now;\n#ifdef CLOCK_MONOTONIC_COARSE\n    clock_gettime(CLOCK_MONOTONIC_COARSE, &now);\n#else\n    clock_gettime(CLOCK_MONOTONIC_HR, &now);\n#endif\n    clock = now.tv_sec * 1000 + now.tv_nsec / 1000000;\n#elif defined(__APPLE__)\n    if (!g_is_mach_base_info_inited) {\n        g_mach_base_info_ret = mach_timebase_info(&g_mach_base_info);\n        g_is_mach_base_info_inited = 1;\n    }\n    if (g_mach_base_info_ret == 0) {\n        uint64_t now = mach_absolute_time();\n        clock = now * g_mach_base_info.numer / g_mach_base_info.denom / 1000000;\n    } else {\n        struct timeval now;\n        gettimeofday(&now, NULL);\n        clock = now.tv_sec  * 1000 + now.tv_usec / 1000;\n    }\n#endif\n    return (clock);\n}\n\nvoid SDL_ProfilerReset(SDL_Profiler* profiler, int max_sample)\n{\n    memset(profiler, 0, sizeof(SDL_Profiler));\n    if (max_sample < 0)\n        profiler->max_sample = 3;\n    else\n        profiler->max_sample = max_sample;\n}\n\nvoid SDL_ProfilerBegin(SDL_Profiler* profiler)\n{\n    profiler->begin_time = SDL_GetTickHR();\n}\n\nint64_t SDL_ProfilerEnd(SDL_Profiler* profiler)\n{\n    int64_t delta = SDL_GetTickHR() - profiler->begin_time;\n\n    if (profiler->max_sample > 0) {\n        profiler->total_elapsed += delta;\n        profiler->total_counter += 1;\n\n        profiler->sample_elapsed += delta;\n        profiler->sample_counter  += 1;\n\n        if (profiler->sample_counter > profiler->max_sample) {\n            profiler->sample_elapsed -= profiler->average_elapsed;\n            profiler->sample_counter -= 1;\n        }\n\n        if (profiler->sample_counter > 0) {\n            profiler->average_elapsed = profiler->sample_elapsed / profiler->sample_counter;\n        }\n        if (profiler->sample_elapsed > 0) {\n            profiler->sample_per_seconds = profiler->sample_counter * 1000.f / profiler->sample_elapsed;\n        }\n    }\n\n    return delta;\n}\n\nvoid SDL_SpeedSamplerReset(SDL_SpeedSampler *sampler)\n{\n    memset(sampler, 0, sizeof(SDL_SpeedSampler));\n    sampler->capacity = sizeof(sampler->samples) / sizeof(Uint64);\n}\n\nfloat SDL_SpeedSamplerAdd(SDL_SpeedSampler *sampler, int enable_log, const char *log_tag)\n{\n    Uint64 current = SDL_GetTickHR();\n    sampler->samples[sampler->next_index] = current;\n    sampler->next_index++;\n    sampler->next_index %= sampler->capacity;\n    if (sampler->count + 1 >= sampler->capacity) {\n        sampler->first_index++;\n        sampler->first_index %= sampler->capacity;\n    } else {\n        sampler->count++;\n    }\n\n    if (sampler->count < 2)\n        return 0;\n\n    float samples_per_second = 1000.0f * (sampler->count - 1) / (current - sampler->samples[sampler->first_index]);\n\n    if (enable_log && (sampler->last_log_time + 1000 < current || sampler->last_log_time > current)) {\n        sampler->last_log_time = current;\n        ALOGW(\"%s: %.2f\\n\", log_tag ? log_tag : \"N/A\", samples_per_second);\n    }\n\n    return samples_per_second;\n}\n\n\n\nvoid SDL_SpeedSampler2Reset(SDL_SpeedSampler2 *sampler, int sample_range)\n{\n    memset(sampler, 0, sizeof(SDL_SpeedSampler2));\n    sampler->sample_range      = sample_range;\n    sampler->last_profile_tick = (int64_t)SDL_GetTickHR();\n}\n\nint64_t SDL_SpeedSampler2Add(SDL_SpeedSampler2 *sampler, int quantity)\n{\n    if (quantity < 0)\n        return 0;\n\n    int64_t sample_range  = sampler->sample_range;\n    int64_t last_tick     = sampler->last_profile_tick;\n    int64_t last_duration = sampler->last_profile_duration;\n    int64_t last_quantity = sampler->last_profile_quantity;\n    int64_t now           = (int64_t)SDL_GetTickHR();\n    int64_t elapsed       = (int64_t)llabs(now - last_tick);\n    if (elapsed < 0 || elapsed >= sample_range) {\n        // overflow, reset to initialized state\n        sampler->last_profile_tick     = now;\n        sampler->last_profile_duration = sample_range;\n        sampler->last_profile_quantity = quantity;\n        sampler->last_profile_speed    = quantity * 1000 / sample_range;\n        return sampler->last_profile_speed;\n    }\n\n    int64_t new_quantity = last_quantity + quantity;\n    int64_t new_duration = last_duration + elapsed;\n    if (new_duration > sample_range) {\n        new_quantity = new_quantity * sample_range / new_duration;\n        new_duration = sample_range;\n    }\n\n    sampler->last_profile_tick     = now;\n    sampler->last_profile_duration = new_duration;\n    sampler->last_profile_quantity = new_quantity;\n    if (new_duration > 0)\n        sampler->last_profile_speed = new_quantity * 1000 / new_duration;\n    return sampler->last_profile_speed;\n}\n\nint64_t SDL_SpeedSampler2GetSpeed(SDL_SpeedSampler2 *sampler)\n{\n    int64_t sample_range  = sampler->sample_range;\n    int64_t last_tick     = sampler->last_profile_tick;\n    int64_t last_quantity = sampler->last_profile_quantity;\n    int64_t last_duration = sampler->last_profile_duration;\n    int64_t now           = (int64_t)SDL_GetTickHR();\n    int64_t elapsed       = (int64_t)llabs(now - last_tick);\n    if (elapsed < 0 || elapsed >= sample_range)\n        return 0;\n\n    int64_t new_quantity = last_quantity;\n    int64_t new_duration = last_duration + elapsed;\n    if (new_duration > sample_range) {\n        new_quantity = new_quantity * sample_range / new_duration;\n        new_duration = sample_range;\n    }\n\n    if (new_duration <= 0)\n        return 0;\n\n    return new_quantity * 1000 / new_duration;\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_timer.h",
    "content": "/*****************************************************************************\n * ijksdl_thread.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL__IJKSDL_TIMER_H\n#define IJKSDL__IJKSDL_TIMER_H\n\n#include \"ijksdl_stdinc.h\"\n\nvoid SDL_Delay(Uint32 ms);\n\nUint64 SDL_GetTickHR(void);\n\n\ntypedef struct SDL_Profiler\n{\n    int64_t total_elapsed;\n    int     total_counter;\n\n    int64_t sample_elapsed;\n    int     sample_counter;\n    float   sample_per_seconds;\n    int64_t average_elapsed;\n\n    int64_t begin_time;\n\n    int     max_sample;\n} SDL_Profiler;\n\nvoid    SDL_ProfilerReset(SDL_Profiler* profiler, int max_sample);\nvoid    SDL_ProfilerBegin(SDL_Profiler* profiler);\nint64_t SDL_ProfilerEnd(SDL_Profiler* profiler);\n\ntypedef struct SDL_SpeedSampler\n{\n    Uint64  samples[10];\n\n    int     capacity;\n    int     count;\n    int     first_index;\n    int     next_index;\n\n    Uint64  last_log_time;\n} SDL_SpeedSampler;\n\nvoid  SDL_SpeedSamplerReset(SDL_SpeedSampler *sampler);\n// return samples per seconds\nfloat SDL_SpeedSamplerAdd(SDL_SpeedSampler *sampler, int enable_log, const char *log_tag);\n\n\n\ntypedef struct SDL_SpeedSampler2\n{\n    int64_t sample_range;\n    int64_t last_profile_tick;\n    int64_t last_profile_duration;\n    int64_t last_profile_quantity;\n    int64_t last_profile_speed;\n} SDL_SpeedSampler2;\n\nvoid    SDL_SpeedSampler2Reset(SDL_SpeedSampler2 *sampler, int sample_range);\nint64_t SDL_SpeedSampler2Add(SDL_SpeedSampler2 *sampler, int quantity);\nint64_t SDL_SpeedSampler2GetSpeed(SDL_SpeedSampler2 *sampler);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_video.h",
    "content": "/*****************************************************************************\n * ijksdl_video.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL__IJKSDL_VIDEO_H\n#define IJKSDL__IJKSDL_VIDEO_H\n\n#include \"ijksdl_stdinc.h\"\n#include \"ijksdl_fourcc.h\"\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_vout.c",
    "content": "/*****************************************************************************\n * ijksdl_vout.c\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl_vout.h\"\n#include <stdlib.h>\n\n#include <assert.h>\n#if defined(__ANDROID__)\n#include <android/native_window_jni.h>\n#endif\n\nvoid SDL_VoutFree(SDL_Vout *vout)\n{\n    if (!vout)\n        return;\n\n    if (vout->free_l) {\n        vout->free_l(vout);\n    } else {\n        free(vout);\n    }\n}\n\nvoid SDL_VoutFreeP(SDL_Vout **pvout)\n{\n    if (!pvout)\n        return;\n\n    SDL_VoutFree(*pvout);\n    *pvout = NULL;\n}\n\nint SDL_VoutDisplayYUVOverlay(SDL_Vout *vout, SDL_VoutOverlay *overlay)\n{\n    if (vout && overlay && vout->display_overlay)\n        return vout->display_overlay(vout, overlay);\n\n    return -1;\n}\n\nint SDL_VoutSetOverlayFormat(SDL_Vout *vout, Uint32 overlay_format)\n{\n    if (!vout)\n        return -1;\n\n    vout->overlay_format = overlay_format;\n    return 0;\n}\n\nSDL_VoutOverlay *SDL_Vout_CreateOverlay(int width, int height, int frame_format, SDL_Vout *vout)\n{\n    if (vout && vout->create_overlay)\n        return vout->create_overlay(width, height, frame_format, vout);\n\n    return NULL;\n}\n\nint SDL_VoutLockYUVOverlay(SDL_VoutOverlay *overlay)\n{\n    if (overlay && overlay->lock)\n        return overlay->lock(overlay);\n\n    return -1;\n}\n\nint SDL_VoutUnlockYUVOverlay(SDL_VoutOverlay *overlay)\n{\n    if (overlay && overlay->unlock)\n        return overlay->unlock(overlay);\n\n    return -1;\n}\n\nvoid SDL_VoutFreeYUVOverlay(SDL_VoutOverlay *overlay)\n{\n    if (!overlay)\n        return;\n\n    if (overlay->free_l) {\n        overlay->free_l(overlay);\n    } else {\n        free(overlay);\n    }\n}\n\nvoid SDL_VoutUnrefYUVOverlay(SDL_VoutOverlay *overlay)\n{\n    if (overlay && overlay->unref)\n        overlay->unref(overlay);\n}\n\nint SDL_VoutFillFrameYUVOverlay(SDL_VoutOverlay *overlay, const AVFrame *frame)\n{\n    if (!overlay || !overlay->func_fill_frame)\n        return -1;\n\n    return overlay->func_fill_frame(overlay, frame);\n}\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_vout.h",
    "content": "/*****************************************************************************\n * ijksdl_vout.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL__IJKSDL_VOUT_H\n#define IJKSDL__IJKSDL_VOUT_H\n\n#include \"ijksdl_stdinc.h\"\n#include \"ijksdl_class.h\"\n#include \"ijksdl_mutex.h\"\n#include \"ijksdl_video.h\"\n#include \"ffmpeg/ijksdl_inc_ffmpeg.h\"\n\ntypedef struct SDL_VoutOverlay_Opaque SDL_VoutOverlay_Opaque;\ntypedef struct SDL_VoutOverlay SDL_VoutOverlay;\nstruct SDL_VoutOverlay {\n    int w; /**< Read-only */\n    int h; /**< Read-only */\n    Uint32 format; /**< Read-only */\n    int planes; /**< Read-only */\n    Uint16 *pitches; /**< in bytes, Read-only */\n    Uint8 **pixels; /**< Read-write */\n\n    int is_private;\n\n    int sar_num;\n    int sar_den;\n\n    SDL_Class               *opaque_class;\n    SDL_VoutOverlay_Opaque  *opaque;\n\n    void    (*free_l)(SDL_VoutOverlay *overlay);\n    int     (*lock)(SDL_VoutOverlay *overlay);\n    int     (*unlock)(SDL_VoutOverlay *overlay);\n    void    (*unref)(SDL_VoutOverlay *overlay);\n\n    int     (*func_fill_frame)(SDL_VoutOverlay *overlay, const AVFrame *frame);\n};\n\ntypedef struct SDL_Vout_Opaque SDL_Vout_Opaque;\ntypedef struct SDL_Vout SDL_Vout;\nstruct SDL_Vout {\n    SDL_mutex *mutex;\n\n    SDL_Class       *opaque_class;\n    SDL_Vout_Opaque *opaque;\n    SDL_VoutOverlay *(*create_overlay)(int width, int height, int frame_format, SDL_Vout *vout);\n    void (*free_l)(SDL_Vout *vout);\n    int (*display_overlay)(SDL_Vout *vout, SDL_VoutOverlay *overlay);\n\n    Uint32 overlay_format;\n};\n\nvoid SDL_VoutFree(SDL_Vout *vout);\nvoid SDL_VoutFreeP(SDL_Vout **pvout);\nint  SDL_VoutDisplayYUVOverlay(SDL_Vout *vout, SDL_VoutOverlay *overlay);\nint  SDL_VoutSetOverlayFormat(SDL_Vout *vout, Uint32 overlay_format);\n\nSDL_VoutOverlay *SDL_Vout_CreateOverlay(int width, int height, int frame_format, SDL_Vout *vout);\nint     SDL_VoutLockYUVOverlay(SDL_VoutOverlay *overlay);\nint     SDL_VoutUnlockYUVOverlay(SDL_VoutOverlay *overlay);\nvoid    SDL_VoutFreeYUVOverlay(SDL_VoutOverlay *overlay);\nvoid    SDL_VoutUnrefYUVOverlay(SDL_VoutOverlay *overlay);\nint     SDL_VoutFillFrameYUVOverlay(SDL_VoutOverlay *overlay, const AVFrame *frame);\n\n#endif\n"
  },
  {
    "path": "ijkmedia/ijksdl/ijksdl_vout_internal.h",
    "content": "/*****************************************************************************\n * ijksdl_vout_internal.h\n *****************************************************************************\n *\n * Copyright (c) 2013 Bilibili\n * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDL__IJKSDL_VOUT_INTERNAL_H\n#define IJKSDL__IJKSDL_VOUT_INTERNAL_H\n\n#include <stdlib.h>\n#include <string.h>\n#include \"ijksdl_vout.h\"\n\ninline static SDL_Vout *SDL_Vout_CreateInternal(size_t opaque_size)\n{\n    SDL_Vout *vout = (SDL_Vout*) calloc(1, sizeof(SDL_Vout));\n    if (!vout)\n        return NULL;\n\n    vout->opaque = calloc(1, opaque_size);\n    if (!vout->opaque) {\n        free(vout);\n        return NULL;\n    }\n\n    vout->mutex = SDL_CreateMutex();\n    if (vout->mutex == NULL) {\n        free(vout->opaque);\n        free(vout);\n        return NULL;\n    }\n\n    return vout;\n}\n\ninline static void SDL_Vout_FreeInternal(SDL_Vout *vout)\n{\n    if (!vout)\n        return;\n\n    if (vout->mutex) {\n        SDL_DestroyMutex(vout->mutex);\n    }\n\n    free(vout->opaque);\n    memset(vout, 0, sizeof(SDL_Vout));\n    free(vout);\n}\n\ninline static SDL_VoutOverlay *SDL_VoutOverlay_CreateInternal(size_t opaque_size)\n{\n    SDL_VoutOverlay *overlay = (SDL_VoutOverlay*) calloc(1, sizeof(SDL_VoutOverlay));\n    if (!overlay)\n        return NULL;\n\n    overlay->opaque = calloc(1, opaque_size);\n    if (!overlay->opaque) {\n        free(overlay);\n        return NULL;\n    }\n    return overlay;\n}\n\ninline static void SDL_VoutOverlay_FreeInternal(SDL_VoutOverlay *overlay)\n{\n    if (!overlay)\n        return;\n\n    if (overlay->opaque)\n        free(overlay->opaque);\n\n    memset(overlay, 0, sizeof(SDL_VoutOverlay));\n    free(overlay);\n}\n\n#endif\n"
  },
  {
    "path": "ijkprof/android-ndk-profiler-dummy/jni/Android-include.mk",
    "content": "# Copyright (c) 2013 Bilibili\n# copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n#\n# This file is part of ijkPlayer.\n#\n# ijkPlayer is free software; you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation; either\n# version 2.1 of the License, or (at your option) any later version.\n#\n# ijkPlayer is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# Lesser General Public License for more details.\n#\n# You should have received a copy of the GNU Lesser General Public\n# License along with ijkPlayer; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n\n# do nothing here"
  },
  {
    "path": "ijkprof/android-ndk-profiler-dummy/jni/Android.mk",
    "content": "# Copyright (c) 2015 Bilibili\n# copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>\n#\n# This file is part of ijkPlayer.\n#\n# ijkPlayer is free software; you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation; either\n# version 2.1 of the License, or (at your option) any later version.\n#\n# ijkPlayer is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# Lesser General Public License for more details.\n#\n# You should have received a copy of the GNU Lesser General Public\n# License along with ijkPlayer; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n\nLOCAL_PATH := $(call my-dir)\n\ninclude $(CLEAR_VARS)\n\nLOCAL_MODULE    := android-ndk-profiler\nLOCAL_SRC_FILES := prof.c\n\ninclude $(BUILD_STATIC_LIBRARY)\n"
  },
  {
    "path": "ijkprof/android-ndk-profiler-dummy/jni/prof.c",
    "content": "/*****************************************************************************\n * prof.c\n *****************************************************************************\n *\n * Copyright (c) 2015 Bilibili\n * copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"prof.h\"\n#include <android/log.h>\n\nextern void monstartup(const char *libname)\n{\n    __android_log_print(ANDROID_LOG_DEBUG, \"aprof-fake\", \"fake-monstartup %s\\n\", libname);\n}\n\nextern void moncleanup(void)\n{\n    __android_log_print(ANDROID_LOG_DEBUG, \"aprof-fake\", \"fake-momcleanup\\n\");\n}\n"
  },
  {
    "path": "ijkprof/android-ndk-profiler-dummy/jni/prof.h",
    "content": "/*****************************************************************************\n * prof.c\n *****************************************************************************\n *\n * Copyright (c) 2015 Bilibili\n * copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef ANDROID_NDK_PROF__PROF_H\n#define ANDROID_NDK_PROF__PROF_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nvoid monstartup(const char *libname);\nvoid moncleanup(void);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif//ANDROID_NDK_PROF__PROF_H\n"
  },
  {
    "path": "init-android-exo.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2015 Bilibili\n# Copyright (C) 2013-2015 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nIJK_EXO_UPSTREAM=https://github.com/google/ExoPlayer.git\nIJK_EXO_FORK=https://github.com/google/ExoPlayer.git\nIJK_EXO_COMMIT=r1.5.11\nIJK_EXO_LOCAL_REPO=extra/ExoPlayer\n\nset -e\nTOOLS=tools\n\necho \"== pull ExoPlayer base ==\"\nsh $TOOLS/pull-repo-base.sh $IJK_EXO_UPSTREAM $IJK_EXO_LOCAL_REPO\n\necho \"== pull ExoPlayer fork ==\"\ncd extra/ExoPlayer\ngit checkout ${IJK_EXO_COMMIT} -B ijkplayer\ncd -\n\nSRC_EXO_DIR=extra/ExoPlayer/demo/src/main/java/com/google/android/exoplayer/demo\nDST_EXO_DIR=android/ijkplayer/ijkplayer-exo/src/main/java/tv/danmaku/ijk/media/exo/demo\n\nmkdir -p $DST_EXO_DIR/player\n\nfunction install_java()\n{\n    JAVA_FILE=$1\n    cat $SRC_EXO_DIR/$JAVA_FILE \\\n    | sed \"s/^package com.google.android.exoplayer.demo/package tv.danmaku.ijk.media.exo.demo/g\" \\\n    | sed \"s/^import com.google.android.exoplayer.demo/import tv.danmaku.ijk.media.exo.demo/g\" \\\n    | sed \"s/@link/link/g\" \\\n    > $DST_EXO_DIR/$JAVA_FILE\n}\n\ninstall_java player/DashRendererBuilder.java\ninstall_java player/DemoPlayer.java\ninstall_java player/ExtractorRendererBuilder.java\ninstall_java player/HlsRendererBuilder.java\ninstall_java player/SmoothStreamingRendererBuilder.java\ninstall_java EventLogger.java\ninstall_java SmoothStreamingTestMediaDrmCallback.java\n# install_java WidevineTestMediaDrmCallback.java\n"
  },
  {
    "path": "init-android-j4a.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2016 Bilibili\n# Copyright (C) 2016 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nIJK_J4A_UPSTREAM=https://github.com/Bilibili/jni4android.git\nIJK_J4A_FORK=https://github.com/Bilibili/jni4android.git\nIJK_J4A_COMMIT=v0.0.2\nIJK_J4A_LOCAL_REPO=extra/jni4android\n\nset -e\nTOOLS=tools\n\necho \"== pull j4a base ==\"\nsh $TOOLS/pull-repo-base.sh $IJK_J4A_UPSTREAM $IJK_J4A_LOCAL_REPO\n\necho \"== pull j4a fork ==\"\nsh $TOOLS/pull-repo-ref.sh $IJK_J4A_FORK extra/jni4android-fork ${IJK_J4A_LOCAL_REPO}\ncd extra/jni4android-fork\ngit checkout ${IJK_J4A_COMMIT}\ncd -\n"
  },
  {
    "path": "init-android-libsoxr.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2015 Bilibili\n# Copyright (C) 2013-2015 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nIJK_LIBSOXR_UPSTREAM=http://git.code.sf.net/p/soxr/code\nIJK_LIBSOXR_FORK=http://git.code.sf.net/p/soxr/code\nIJK_LIBSOXR_COMMIT=0.1.2\nIJK_LIBSOXR_COMMIT_64=master\nIJK_LIBSOXR_LOCAL_REPO=extra/soxr\n\nset -e\nTOOLS=tools\n\necho \"== pull soxr base ==\"\nsh $TOOLS/pull-repo-base.sh $IJK_LIBSOXR_UPSTREAM $IJK_LIBSOXR_LOCAL_REPO\n\nfunction pull_fork()\n{\n    echo \"== pull soxr fork $1 ==\"\n    sh $TOOLS/pull-repo-ref.sh $IJK_LIBSOXR_FORK android/contrib/libsoxr-$1 ${IJK_LIBSOXR_LOCAL_REPO}\n    cp extra/android-cmake/android.toolchain.cmake android/contrib/libsoxr-$1\n    cd android/contrib/libsoxr-$1\n    case \"$1\" in\n        arm64|x86_64)\n            git checkout ${IJK_LIBSOXR_COMMIT_64} -B ijkplayer\n            ;;\n        *)\n            git checkout ${IJK_LIBSOXR_COMMIT} -B ijkplayer\n            ;;\n    esac\n    cd -\n}\n\nfunction pull_android_toolchain_cmake()\n{\n    ANDROID_TOOLCHAIN_CMAKE_UPSTREAM=https://github.com/taka-no-me/android-cmake.git\n    echo \"== pull android toolchain cmake from $ANDROID_TOOLCHAIN_CMAKE_UPSTREAM ==\"\n    sh $TOOLS/pull-repo-base.sh $ANDROID_TOOLCHAIN_CMAKE_UPSTREAM extra/android-cmake\n}\n\npull_android_toolchain_cmake\n\npull_fork \"armv5\"\npull_fork \"armv7a\"\npull_fork \"arm64\"\npull_fork \"x86\"\npull_fork \"x86_64\"\n"
  },
  {
    "path": "init-android-libyuv.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2015 Bilibili\n# Copyright (C) 2013-2015 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n\nIJK_LIBYUV_UPSTREAM=https://github.com/Bilibili/libyuv.git\nIJK_LIBYUV_FORK=https://github.com/Bilibili/libyuv.git\nIJK_LIBYUV_COMMIT=ijk-r0.2.1-dev\nIJK_LIBYUV_LOCAL_REPO=extra/libyuv\n\nset -e\nTOOLS=tools\n\necho \"== pull libyuv base ==\"\nsh $TOOLS/pull-repo-base.sh $IJK_LIBYUV_UPSTREAM $IJK_LIBYUV_LOCAL_REPO\n\necho \"== pull libyuv fork ==\"\nsh $TOOLS/pull-repo-ref.sh $IJK_LIBYUV_FORK ijkmedia/ijkyuv ${IJK_LIBYUV_LOCAL_REPO}\ncd ijkmedia/ijkyuv\ngit checkout ${IJK_LIBYUV_COMMIT}\ncd -\n"
  },
  {
    "path": "init-android-openssl.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2015 Bilibili\n# Copyright (C) 2013-2015 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n#IJK_OPENSSL_UPSTREAM=https://github.com/openssl/openssl\nIJK_OPENSSL_UPSTREAM=https://github.com/Bilibili/openssl.git\nIJK_OPENSSL_FORK=https://github.com/Bilibili/openssl.git\nIJK_OPENSSL_COMMIT=OpenSSL_1_0_2q\nIJK_OPENSSL_LOCAL_REPO=extra/openssl\n\nset -e\nTOOLS=tools\n\necho \"== pull openssl base ==\"\nsh $TOOLS/pull-repo-base.sh $IJK_OPENSSL_UPSTREAM $IJK_OPENSSL_LOCAL_REPO\n\nfunction pull_fork()\n{\n    echo \"== pull openssl fork $1 ==\"\n    sh $TOOLS/pull-repo-ref.sh $IJK_OPENSSL_FORK android/contrib/openssl-$1 ${IJK_OPENSSL_LOCAL_REPO}\n    cd android/contrib/openssl-$1\n    git checkout ${IJK_OPENSSL_COMMIT} -B ijkplayer\n    cd -\n}\n\npull_fork \"armv5\"\npull_fork \"armv7a\"\npull_fork \"arm64\"\npull_fork \"x86\"\npull_fork \"x86_64\"\n"
  },
  {
    "path": "init-android-prof.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2015 Bilibili\n# Copyright (C) 2013-2015 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nIJK_LIB_NAME=android-ndk-profiler\nIJK_LIB_UPSTREAM=https://github.com/Bilibili/android-ndk-profiler.git\nIJK_LIB_FORK=https://github.com/Bilibili/android-ndk-profiler.git\nIJK_LIB_COMMIT=ijk-r0.3.0-dev\nIJK_LIB_LOCAL_REPO=extra/android-ndk-profiler\n\nset -e\nTOOLS=tools\n\necho \"== pull $IJK_LIB_NAME base ==\"\nsh $TOOLS/pull-repo-base.sh $IJK_LIB_UPSTREAM $IJK_LIB_LOCAL_REPO\n\necho \"== pull $IJK_LIB_NAME fork ==\"\nsh $TOOLS/pull-repo-ref.sh $IJK_LIB_FORK ijkprof/$IJK_LIB_NAME ${IJK_LIB_LOCAL_REPO}\ncd ijkprof/$IJK_LIB_NAME\ngit checkout ${IJK_LIB_COMMIT}\ncd -\n"
  },
  {
    "path": "init-android-soundtouch.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2015 Bilibili\n# Copyright (C) 2013-2015 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n\nIJK_SOUNDTOUCH_UPSTREAM=https://github.com/Bilibili/soundtouch.git\nIJK_SOUNDTOUCH_FORK=https://github.com/Bilibili/soundtouch.git\nIJK_SOUNDTOUCH_COMMIT=ijk-r0.1.2-dev\nIJK_SOUNDTOUCH_LOCAL_REPO=extra/soundtouch\n\nset -e\nTOOLS=tools\n\necho \"== pull soundtouch base ==\"\nsh $TOOLS/pull-repo-base.sh $IJK_SOUNDTOUCH_UPSTREAM $IJK_SOUNDTOUCH_LOCAL_REPO\n\necho \"== pull soundtouch fork ==\"\nsh $TOOLS/pull-repo-ref.sh $IJK_SOUNDTOUCH_FORK ijkmedia/ijksoundtouch ${IJK_SOUNDTOUCH_LOCAL_REPO}\ncd ijkmedia/ijksoundtouch\ngit checkout ${IJK_SOUNDTOUCH_COMMIT}\ncd -\n"
  },
  {
    "path": "init-android.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2015 Bilibili\n# Copyright (C) 2013-2015 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# IJK_FFMPEG_UPSTREAM=git://git.videolan.org/ffmpeg.git\nIJK_FFMPEG_UPSTREAM=https://github.com/Bilibili/FFmpeg.git\nIJK_FFMPEG_FORK=https://github.com/Bilibili/FFmpeg.git\nIJK_FFMPEG_COMMIT=ff4.0--ijk0.8.8--20210426--001\nIJK_FFMPEG_LOCAL_REPO=extra/ffmpeg\n\nset -e\nTOOLS=tools\n\ngit --version\n\necho \"== pull ffmpeg base ==\"\nsh $TOOLS/pull-repo-base.sh $IJK_FFMPEG_UPSTREAM $IJK_FFMPEG_LOCAL_REPO\n\nfunction pull_fork()\n{\n    echo \"== pull ffmpeg fork $1 ==\"\n    sh $TOOLS/pull-repo-ref.sh $IJK_FFMPEG_FORK android/contrib/ffmpeg-$1 ${IJK_FFMPEG_LOCAL_REPO}\n    cd android/contrib/ffmpeg-$1\n    git checkout ${IJK_FFMPEG_COMMIT} -B ijkplayer\n    cd -\n}\n\npull_fork \"armv5\"\npull_fork \"armv7a\"\npull_fork \"arm64\"\npull_fork \"x86\"\npull_fork \"x86_64\"\n\n./init-config.sh\n./init-android-libyuv.sh\n./init-android-soundtouch.sh\n"
  },
  {
    "path": "init-config.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2015 Bilibili\n# Copyright (C) 2013-2015 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nif [ ! -f 'config/module.sh' ]; then\n    cp config/module-lite.sh config/module.sh\nfi"
  },
  {
    "path": "init-ios-openssl.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2015 Bilibili\n# Copyright (C) 2013-2015 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nIJK_OPENSSL_UPSTREAM=https://github.com/openssl/openssl\nIJK_OPENSSL_FORK=https://github.com/Bilibili/openssl.git\nIJK_OPENSSL_COMMIT=OpenSSL_1_0_2q\nIJK_OPENSSL_LOCAL_REPO=extra/openssl\n\nset -e\nTOOLS=tools\n\necho \"== pull openssl base ==\"\nsh $TOOLS/pull-repo-base.sh $IJK_OPENSSL_UPSTREAM $IJK_OPENSSL_LOCAL_REPO\n\nfunction pull_fork()\n{\n    echo \"== pull openssl fork $1 ==\"\n    sh $TOOLS/pull-repo-ref.sh $IJK_OPENSSL_FORK ios/openssl-$1 ${IJK_OPENSSL_LOCAL_REPO}\n    cd ios/openssl-$1\n    git checkout ${IJK_OPENSSL_COMMIT} -B ijkplayer\n    cd -\n}\n\npull_fork \"armv7\"\npull_fork \"armv7s\"\npull_fork \"arm64\"\npull_fork \"i386\"\npull_fork \"x86_64\"\n\n"
  },
  {
    "path": "init-ios.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2015 Bilibili\n# Copyright (C) 2013-2015 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# IJK_FFMPEG_UPSTREAM=git://git.videolan.org/ffmpeg.git\nIJK_FFMPEG_UPSTREAM=https://github.com/Bilibili/FFmpeg.git\nIJK_FFMPEG_FORK=https://github.com/Bilibili/FFmpeg.git\nIJK_FFMPEG_COMMIT=ff4.0--ijk0.8.8--20210426--001\nIJK_FFMPEG_LOCAL_REPO=extra/ffmpeg\n\nIJK_GASP_UPSTREAM=https://github.com/Bilibili/gas-preprocessor.git\n\n# gas-preprocessor backup\n# https://github.com/Bilibili/gas-preprocessor.git\n\nif [ \"$IJK_FFMPEG_REPO_URL\" != \"\" ]; then\n    IJK_FFMPEG_UPSTREAM=$IJK_FFMPEG_REPO_URL\n    IJK_FFMPEG_FORK=$IJK_FFMPEG_REPO_URL\nfi\n\nif [ \"$IJK_GASP_REPO_URL\" != \"\" ]; then\n    IJK_GASP_UPSTREAM=$IJK_GASP_REPO_URL\nfi\n\nset -e\nTOOLS=tools\n\nFF_ALL_ARCHS_IOS6_SDK=\"armv7 armv7s i386\"\nFF_ALL_ARCHS_IOS7_SDK=\"armv7 armv7s arm64 i386 x86_64\"\nFF_ALL_ARCHS_IOS8_SDK=\"armv7 arm64 i386 x86_64\"\nFF_ALL_ARCHS=$FF_ALL_ARCHS_IOS8_SDK\nFF_TARGET=$1\n\nfunction echo_ffmpeg_version() {\n    echo $IJK_FFMPEG_COMMIT\n}\n\nfunction pull_common() {\n    git --version\n    echo \"== pull gas-preprocessor base ==\"\n    sh $TOOLS/pull-repo-base.sh $IJK_GASP_UPSTREAM extra/gas-preprocessor\n\n    echo \"== pull ffmpeg base ==\"\n    sh $TOOLS/pull-repo-base.sh $IJK_FFMPEG_UPSTREAM $IJK_FFMPEG_LOCAL_REPO\n}\n\nfunction pull_fork() {\n    echo \"== pull ffmpeg fork $1 ==\"\n    sh $TOOLS/pull-repo-ref.sh $IJK_FFMPEG_FORK ios/ffmpeg-$1 ${IJK_FFMPEG_LOCAL_REPO}\n    cd ios/ffmpeg-$1\n    git checkout ${IJK_FFMPEG_COMMIT} -B ijkplayer\n    cd -\n}\n\nfunction pull_fork_all() {\n    for ARCH in $FF_ALL_ARCHS\n    do\n        pull_fork $ARCH\n    done\n}\n\nfunction sync_ff_version() {\n    sed -i '' \"s/static const char \\*kIJKFFRequiredFFmpegVersion\\ \\=\\ .*/static const char *kIJKFFRequiredFFmpegVersion = \\\"${IJK_FFMPEG_COMMIT}\\\";/g\" ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerController.m\n}\n\n#----------\ncase \"$FF_TARGET\" in\n    ffmpeg-version)\n        echo_ffmpeg_version\n    ;;\n    armv7|armv7s|arm64|i386|x86_64)\n        pull_common\n        pull_fork $FF_TARGET\n    ;;\n    all|*)\n        pull_common\n        pull_fork_all\n    ;;\nesac\n\nsync_ff_version\n\n"
  },
  {
    "path": "ios/.gitignore",
    "content": "xcuserdata\nxcshareddata\n*.xccheckout\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/AppIcons.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"57x57\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"57x57\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/Barcode.h",
    "content": "//\n//  Barcode.h\n//  featurebuild\n//\n//  Created by Jake Widmer on 10/5/13.\n//  Copyright (c) 2013 Jake Widmer. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import <AVFoundation/AVFoundation.h>\n\n@interface Barcode : NSObject\n\n+ (Barcode * )processMetadataObject:(AVMetadataMachineReadableCodeObject*) code;\n- (NSString *) getBarcodeType;\n- (NSString *) getBarcodeData;\n- (void) printBarcodeData;\n@end\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/Barcode.m",
    "content": "//\n//  Barcode.m\n//  featurebuild\n//\n//  Created by Jake Widmer on 10/5/13.\n//  Copyright (c) 2013 Jake Widmer. All rights reserved.\n//\n\n#import \"Barcode.h\"\n\n@interface Barcode() \n\n@property (nonatomic, strong) AVMetadataMachineReadableCodeObject *metadataObject;\n@property (nonatomic, strong) NSString * barcodeType;\n@property (nonatomic, strong) NSString * barcodeData;\n@property (nonatomic, strong) UIBezierPath *cornersPath;\n@property (nonatomic, strong) UIBezierPath *boundingBoxPath;\n\n@end\n@implementation Barcode\n\n+ (Barcode * )processMetadataObject: (AVMetadataMachineReadableCodeObject*)code\n{\n    // 1 create the obj\n    Barcode * barcode=[[Barcode alloc]init];\n    // 2 store code type and string\n    barcode.barcodeType = [NSString stringWithString:code.type];\n    barcode.barcodeData = [NSString stringWithString:code.stringValue];\n    barcode.metadataObject = code;\n    // 3 & 4 Create the path joining code's corners\n    CGMutablePathRef cornersPath = CGPathCreateMutable();\n    // 5 Make point\n    CGPoint point;\n    CGPointMakeWithDictionaryRepresentation(\n                                            (CFDictionaryRef)code.corners[0], &point);\n    // 6 Make path\n    CGPathMoveToPoint(cornersPath, nil, point.x, point.y);\n    // 7\n    for (int i = 1; i < code.corners.count; i++) {\n        CGPointMakeWithDictionaryRepresentation(\n                                                (CFDictionaryRef)code.corners[i], &point);\n        CGPathAddLineToPoint(cornersPath, nil,\n                             point.x, point.y);\n    }\n    // 8 Finish box\n    CGPathCloseSubpath(cornersPath);\n    // 9 Set path\n    barcode.cornersPath =\n    [UIBezierPath bezierPathWithCGPath:cornersPath];\n    CGPathRelease(cornersPath);\n    // Create the path for the code's bounding box\n    // 10\n    barcode.boundingBoxPath =\n    [UIBezierPath bezierPathWithRect:code.bounds];\n    // 11 return\n    return barcode;\n    \n}\n- (NSString *) getBarcodeType{\n    return self.barcodeType;\n}\n- (NSString *) getBarcodeData{\n    return self.barcodeData;\n}\n- (void) printBarcodeData{\n    NSLog(@\"Barcode of type: %@ and data: %@\",self.metadataObject.type, self.barcodeData);\n}\n@end\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/IJKAppDelegate.h",
    "content": "/*\n * Copyright (C) 2013-2015 Bilibili\n * Copyright (C) 2013-2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <UIKit/UIKit.h>\n\n@interface IJKAppDelegate : UIResponder <UIApplicationDelegate>\n\n@property (strong, nonatomic) UIWindow *window;\n@property (strong, nonatomic) UIViewController *viewController;\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/IJKAppDelegate.m",
    "content": "/*\n * Copyright (C) 2013-2015 Bilibili\n * Copyright (C) 2013-2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import \"IJKAppDelegate.h\"\n#import \"IJKDemoMainViewController.h\"\n\n@implementation IJKAppDelegate\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions\n{\n    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];\n    \n    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:[[IJKDemoMainViewController alloc] init]];\n    \n    self.viewController = navigationController;\n    self.window.rootViewController = self.viewController;\n\n    [self.window makeKeyAndVisible];\n    \n    return YES;\n}\n\n- (void)applicationWillResignActive:(UIApplication *)application\n{\n    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.\n    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.\n}\n\n- (void)applicationDidEnterBackground:(UIApplication *)application\n{\n    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. \n    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.\n}\n\n- (void)applicationWillEnterForeground:(UIApplication *)application\n{\n    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.\n}\n\n- (void)applicationDidBecomeActive:(UIApplication *)application\n{\n    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.\n}\n\n- (void)applicationWillTerminate:(UIApplication *)application\n{\n    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/IJKCommon.h",
    "content": "/*\n * Copyright (C) 2013-2015 Bilibili\n * Copyright (C) 2013-2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <Foundation/Foundation.h>\n\n#define IOS_OLDER_THAN_6 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] < 6.0 )\n#define IOS_NEWER_OR_EQUAL_TO_6 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] >= 6.0 )\n#define IOS_NEWER_OR_EQUAL_TO_7 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] >= 7.0 )\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/IJKDemoHistory.h",
    "content": "/*\n * Copyright (C) 2015 Gdier\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <Foundation/Foundation.h>\n\n@interface IJKDemoHistoryItem : NSObject <NSCoding>\n\n@property(nonatomic,strong) NSString *title;\n@property(nonatomic,strong) NSURL *url;\n\n@end\n\n@interface IJKDemoHistory : NSObject\n\n+ (instancetype)instance;\n\n@property(nonatomic,strong,readonly) NSArray *list;\n\n- (void)removeAtIndex:(NSUInteger)index;\n- (void)add:(IJKDemoHistoryItem *)item;\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/IJKDemoHistory.m",
    "content": "/*\n * Copyright (C) 2015 Gdier\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import \"IJKDemoHistory.h\"\n\n@implementation IJKDemoHistoryItem\n\n- (void)encodeWithCoder:(NSCoder *)aCoder {\n    [aCoder encodeObject:self.url forKey:@\"url\"];\n    [aCoder encodeObject:self.title forKey:@\"title\"];\n}\n\n- (instancetype)initWithCoder:(NSCoder *)coder {\n    self = [super init];\n    if (self) {\n        self.title = [coder decodeObjectForKey:@\"title\"];\n        self.url = [coder decodeObjectForKey:@\"url\"];\n    }\n    return self;\n}\n\n@end\n\n@interface IJKDemoHistory ()\n\n@end\n\n@implementation IJKDemoHistory {\n    NSMutableArray *_list;\n}\n\n+ (instancetype)instance {\n    static IJKDemoHistory *s_obj = nil;\n    static dispatch_once_t onceToken;\n    dispatch_once(&onceToken, ^{\n        s_obj = [[IJKDemoHistory alloc] init];\n    });\n    \n    return s_obj;\n}\n\n- (instancetype)init {\n    self = [super init];\n    if (self) {\n        _list = [NSKeyedUnarchiver unarchiveObjectWithFile:[self dbfilePath]];\n        if (nil == _list)\n            _list = [NSMutableArray array];\n    }\n    return self;\n}\n\n- (NSString *)dbfilePath {\n    NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSAllDomainsMask, YES) firstObject];\n    libraryPath = [libraryPath stringByAppendingPathComponent:@\"ijkhistory.plist\"];\n    \n    return libraryPath;\n}\n\n- (NSArray *)list {\n    return _list;\n}\n\n- (void)removeAtIndex:(NSUInteger)index {\n    [_list removeObjectAtIndex:index];\n    \n    [NSKeyedArchiver archiveRootObject:_list toFile:[self dbfilePath]];\n}\n\n- (void)add:(IJKDemoHistoryItem *)item {\n    __block NSUInteger findIdx = NSNotFound;\n    \n    [_list enumerateObjectsUsingBlock:^(IJKDemoHistoryItem *enumItem, NSUInteger idx, BOOL *stop) {\n        if ([enumItem.url isEqual:item.url]) {\n            findIdx = idx;\n            *stop = YES;\n        }\n    }];\n    \n    if (NSNotFound != findIdx) {\n        [_list removeObjectAtIndex:findIdx];\n    }\n    \n    [_list insertObject:item atIndex:0];\n    \n    [NSKeyedArchiver archiveRootObject:_list toFile:[self dbfilePath]];\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/IJKDemoInputURLViewController.h",
    "content": "/*\n * Copyright (C) 2015 Gdier\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <UIKit/UIKit.h>\n\n@interface IJKDemoInputURLViewController : UIViewController\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/IJKDemoInputURLViewController.m",
    "content": "/*\n * Copyright (C) 2015 Gdier\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import \"IJKDemoInputURLViewController.h\"\n#import \"IJKMoviePlayerViewController.h\"\n\n@interface IJKDemoInputURLViewController () <UITextViewDelegate>\n\n@property(nonatomic,strong) IBOutlet UITextView *textView;\n\n@end\n\n@implementation IJKDemoInputURLViewController\n\n- (instancetype)init {\n    self = [super init];\n    if (self) {\n        self.title = @\"Input URL\";\n        \n        [self.navigationItem setRightBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:@\"Play\" style:UIBarButtonItemStyleDone target:self action:@selector(onClickPlayButton)]];\n    }\n    return self;\n}\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n}\n\n- (void)onClickPlayButton {\n    NSURL *url = [NSURL URLWithString:self.textView.text];\n    NSString *scheme = [[url scheme] lowercaseString];\n    \n    if ([scheme isEqualToString:@\"http\"]\n        || [scheme isEqualToString:@\"https\"]\n        || [scheme isEqualToString:@\"rtmp\"]) {\n        [IJKVideoViewController presentFromViewController:self withTitle:[NSString stringWithFormat:@\"URL: %@\", url] URL:url completion:^{\n//            [self.navigationController popViewControllerAnimated:NO];\n        }];\n    }\n}\n\n- (void)textViewDidEndEditing:(UITextView *)textView {\n    [self onClickPlayButton];\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/IJKDemoInputURLViewController.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVersion=\"7531\" systemVersion=\"14A389\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\">\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"7520\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\" customClass=\"IJKDemoInputURLViewController\">\n            <connections>\n                <outlet property=\"textView\" destination=\"umQ-0P-p2z\" id=\"uhq-2S-7Pb\"/>\n                <outlet property=\"view\" destination=\"i5M-Pr-FkT\" id=\"sfx-zR-JGt\"/>\n            </connections>\n        </placeholder>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view clearsContextBeforeDrawing=\"NO\" contentMode=\"scaleToFill\" id=\"i5M-Pr-FkT\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"600\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <textView clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" showsHorizontalScrollIndicator=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"umQ-0P-p2z\">\n                    <rect key=\"frame\" x=\"8\" y=\"8\" width=\"584\" height=\"584\"/>\n                    <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"18\"/>\n                    <textInputTraits key=\"textInputTraits\" autocorrectionType=\"no\" spellCheckingType=\"no\" keyboardType=\"URL\" returnKeyType=\"go\" enablesReturnKeyAutomatically=\"YES\"/>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-1\" id=\"qOq-wA-HFo\"/>\n                    </connections>\n                </textView>\n            </subviews>\n            <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n            <constraints>\n                <constraint firstItem=\"umQ-0P-p2z\" firstAttribute=\"leading\" secondItem=\"i5M-Pr-FkT\" secondAttribute=\"leading\" constant=\"8\" id=\"2zf-bJ-LK8\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"umQ-0P-p2z\" secondAttribute=\"bottom\" constant=\"8\" id=\"ENy-rQ-9YF\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"umQ-0P-p2z\" secondAttribute=\"trailing\" constant=\"8\" id=\"N7V-Kf-ayr\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"umQ-0P-p2z\" secondAttribute=\"bottom\" id=\"UXz-GP-DN9\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"umQ-0P-p2z\" secondAttribute=\"trailing\" id=\"YgQ-xw-l1l\"/>\n                <constraint firstItem=\"umQ-0P-p2z\" firstAttribute=\"top\" secondItem=\"i5M-Pr-FkT\" secondAttribute=\"top\" constant=\"8\" id=\"gAV-yS-4Tt\"/>\n                <constraint firstItem=\"umQ-0P-p2z\" firstAttribute=\"leading\" secondItem=\"i5M-Pr-FkT\" secondAttribute=\"leading\" id=\"vah-gr-VK9\"/>\n                <constraint firstItem=\"umQ-0P-p2z\" firstAttribute=\"top\" secondItem=\"i5M-Pr-FkT\" secondAttribute=\"top\" id=\"wZS-sX-ly5\"/>\n            </constraints>\n            <variation key=\"default\">\n                <mask key=\"constraints\">\n                    <exclude reference=\"UXz-GP-DN9\"/>\n                    <exclude reference=\"YgQ-xw-l1l\"/>\n                    <exclude reference=\"vah-gr-VK9\"/>\n                    <exclude reference=\"wZS-sX-ly5\"/>\n                </mask>\n            </variation>\n        </view>\n    </objects>\n</document>\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/IJKDemoLocalFolderViewController.h",
    "content": "/*\n * Copyright (C) 2015 Gdier\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <UIKit/UIKit.h>\n\n@interface IJKDemoLocalFolderViewController : UITableViewController\n\n- (instancetype)initWithFolderPath:(NSString *)folderPath;\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/IJKDemoLocalFolderViewController.m",
    "content": "/*\n * Copyright (C) 2015 Gdier\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import \"IJKDemoLocalFolderViewController.h\"\n#import \"IJKMoviePlayerViewController.h\"\n\n@interface IJKDemoLocalFolderViewController ()\n\n@end\n\n@implementation IJKDemoLocalFolderViewController {\n    NSString *_folderPath;\n    NSMutableArray *_subpaths;\n    NSMutableArray *_files;\n}\n\n- (instancetype)initWithFolderPath:(NSString *)folderPath {\n    self = [super init];\n    if (self) {\n        folderPath = [folderPath stringByStandardizingPath];\n        self.title = [folderPath lastPathComponent];\n        \n        _folderPath = folderPath;\n        _subpaths = [NSMutableArray array];\n        _files = [NSMutableArray array];\n    }\n    return self;\n}\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n    \n    NSError *error = nil;\n    BOOL isDirectory = NO;\n    NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:_folderPath error:&error];\n\n    [_subpaths addObject:@\"..\"];\n\n    for (NSString *fileName in files) {\n        NSString *fullFileName = [_folderPath stringByAppendingPathComponent:fileName];\n        \n        [[NSFileManager defaultManager] fileExistsAtPath:fullFileName isDirectory:&isDirectory];\n        if (isDirectory) {\n            [_subpaths addObject:fileName];\n        } else {\n            [_files addObject:fileName];\n        }\n    }\n}\n\n- (void)didReceiveMemoryWarning {\n    [super didReceiveMemoryWarning];\n    // Dispose of any resources that can be recreated.\n}\n\n#pragma mark - Table view data source\n\n- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {\n    return 2;\n}\n\n- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {\n    switch (section) {\n        case 0:\n            return _subpaths.count;\n            \n        case 1:\n            return _files.count;\n            \n        default:\n            break;\n    }\n\n    return 0;\n}\n\n- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {\n    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@\"abc\"];\n    if (nil == cell) {\n        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@\"abc\"];\n        cell.textLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;\n    }\n    \n    switch (indexPath.section) {\n        case 0: {\n            cell.textLabel.text = [NSString stringWithFormat:@\"[%@]\", _subpaths[indexPath.row]];\n            cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;\n        } break;\n        case 1: {\n            cell.textLabel.text = _files[indexPath.row];\n            cell.accessoryType = UITableViewCellAccessoryNone;\n        } break;\n        default:\n            break;\n    }\n    \n    return cell;\n}\n\n- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {\n    [tableView deselectRowAtIndexPath:indexPath animated:YES];\n    \n    switch (indexPath.section) {\n        case 0: {\n            NSString *fileName = [_folderPath stringByAppendingPathComponent:_subpaths[indexPath.row]];\n\n            IJKDemoLocalFolderViewController *viewController = [[IJKDemoLocalFolderViewController alloc] initWithFolderPath:fileName];\n            \n            [self.navigationController pushViewController:viewController animated:YES];\n        } break;\n        case 1: {\n            NSString *fileName = [_folderPath stringByAppendingPathComponent:_files[indexPath.row]];\n\n            fileName = [fileName stringByStandardizingPath];\n            \n            [IJKVideoViewController presentFromViewController:self withTitle:[NSString stringWithFormat:@\"File: %@\", fileName] URL:[NSURL fileURLWithPath:fileName] completion:^{\n            }];\n            \n        } break;\n        default:\n            break;\n    }\n}\n\n/*\n// Override to support conditional editing of the table view.\n- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {\n    // Return NO if you do not want the specified item to be editable.\n    return YES;\n}\n*/\n\n/*\n// Override to support editing the table view.\n- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {\n    if (editingStyle == UITableViewCellEditingStyleDelete) {\n        // Delete the row from the data source\n        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];\n    } else if (editingStyle == UITableViewCellEditingStyleInsert) {\n        // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view\n    }   \n}\n*/\n\n/*\n// Override to support rearranging the table view.\n- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {\n}\n*/\n\n/*\n// Override to support conditional rearranging of the table view.\n- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {\n    // Return NO if you do not want the item to be re-orderable.\n    return YES;\n}\n*/\n\n/*\n#pragma mark - Navigation\n\n// In a storyboard-based application, you will often want to do a little preparation before navigation\n- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {\n    // Get the new view controller using [segue destinationViewController].\n    // Pass the selected object to the new view controller.\n}\n*/\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/IJKDemoMainViewController.h",
    "content": "/*\n * Copyright (C) 2015 Gdier\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <UIKit/UIKit.h>\n\n@interface IJKDemoMainViewController : UIViewController\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/IJKDemoMainViewController.m",
    "content": "/*\n * Copyright (C) 2015 Gdier\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import \"IJKDemoMainViewController.h\"\n#import \"IJKDemoInputURLViewController.h\"\n#import \"IJKQRCodeScanViewController.h\"\n#import \"IJKCommon.h\"\n#import \"IJKDemoHistory.h\"\n#import \"IJKMoviePlayerViewController.h\"\n#import \"IJKDemoLocalFolderViewController.h\"\n#import \"IJKDemoSampleViewController.h\"\n#import <MobileCoreServices/MobileCoreServices.h>\n\n@interface IJKDemoMainViewController () <UITableViewDataSource, UITableViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate>\n\n@property(nonatomic,strong) IBOutlet UITableView *tableView;\n@property(nonatomic,strong) NSArray *tableViewCellTitles;\n@property(nonatomic,strong) NSArray *historyList;\n\n@end\n\n@implementation IJKDemoMainViewController\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n    \n    self.title = @\"Main\";\n    \n    self.tableViewCellTitles = @[\n                                 @\"Local Folder\",\n                                 @\"Movie Picker\",\n                                 @\"Input URL\",\n                                 @\"Scan QRCode\",\n                                 @\"Online Samples\",\n                                 ];\n    \n    NSURL *documentsUrl = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject];\n    \n    NSError *error = nil;\n    \n    [documentsUrl setResourceValue:[NSNumber numberWithBool:YES]\n                            forKey:NSURLIsExcludedFromBackupKey\n                             error:&error];\n}\n\n- (void)viewWillAppear:(BOOL)animated {\n    [super viewWillAppear:animated];\n    \n    self.historyList = [[IJKDemoHistory instance] list];\n\n    [self.tableView reloadData];\n}\n\n- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {\n    return 2;\n}\n\n- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {\n    switch (section) {\n        case 0:\n            return @\"Open from\";\n            \n        case 1:\n            return @\"History\";\n            \n        default:\n            return nil;\n    }\n}\n\n- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {\n    switch (section) {\n        case 0:\n            if (IOS_NEWER_OR_EQUAL_TO_7) {\n                return self.tableViewCellTitles.count;\n            } else {\n                return self.tableViewCellTitles.count - 1;\n            }\n            \n        case 1:\n            return self.historyList.count;\n            \n        default:\n            return 0;\n    }\n}\n\n- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {\n    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@\"abc\"];\n    if (nil == cell) {\n        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@\"abc\"];\n        cell.textLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;\n    }\n    \n    switch (indexPath.section) {\n        case 0:\n            cell.textLabel.text = self.tableViewCellTitles[indexPath.row];\n            break;\n            \n        case 1:\n            cell.textLabel.text = [self.historyList[indexPath.row] title];\n            break;\n            \n        default:\n            break;\n    }\n    \n    return cell;\n}\n\n- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {\n    [tableView deselectRowAtIndexPath:indexPath animated:YES];\n    \n    switch (indexPath.section) {\n        case 0: {\n            switch (indexPath.row) {\n                case 0: {\n                    NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];\n\n                    IJKDemoLocalFolderViewController *viewController = [[IJKDemoLocalFolderViewController alloc] initWithFolderPath:documentsPath];\n                    \n                    [self.navigationController pushViewController:viewController animated:YES];\n                } break;\n\n                case 1:\n                    [self startMediaBrowserFromViewController: self\n                                                usingDelegate: self];\n                    break;\n\n                case 2:\n                    [self.navigationController pushViewController:[[IJKDemoInputURLViewController alloc] init] animated:YES];\n                    break;\n\n                case 3:\n                    [self.navigationController pushViewController:[[IJKQRCodeScanViewController alloc] init] animated:YES];\n                    break;\n\n                case 4:\n                    [self.navigationController pushViewController:[[IJKDemoSampleViewController alloc] init] animated:YES];\n                    break;\n\n                default:\n                    break;\n            }\n        } break;\n            \n        case 1: {\n            IJKDemoHistoryItem *historyItem = self.historyList[indexPath.row];\n            \n            [IJKVideoViewController presentFromViewController:self withTitle:historyItem.title URL:historyItem.url completion:^{\n                [self.navigationController popViewControllerAnimated:NO];\n            }];\n        } break;\n            \n        default:\n            break;\n    }\n}\n\n- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {\n    return (indexPath.section == 1);\n}\n\n- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {\n    if (indexPath.section == 1) {\n        return UITableViewCellEditingStyleDelete;\n    }\n\n    return UITableViewCellEditingStyleNone;\n}\n\n- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {\n    if (indexPath.section == 1 && editingStyle == UITableViewCellEditingStyleDelete) {\n        [[IJKDemoHistory instance] removeAtIndex:indexPath.row];\n        self.historyList = [[IJKDemoHistory instance] list];\n\n        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];\n    }\n}\n\n#pragma mark UIImagePickerControllerDelegate\n\n- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info\n{\n    NSString *mediaType = [info objectForKey: UIImagePickerControllerMediaType];\n    NSURL *movieUrl;\n\n    // Handle a movied picked from a photo album\n    if (CFStringCompare ((CFStringRef) mediaType, kUTTypeMovie, 0)\n        == kCFCompareEqualTo) {\n\n        NSString *moviePath = [[info objectForKey:\n                                UIImagePickerControllerMediaURL] path];\n        movieUrl = [NSURL URLWithString:moviePath];\n    }\n\n    [self dismissViewControllerAnimated:YES completion:^(void){\n        [self.navigationController pushViewController:[[IJKVideoViewController alloc]   initWithURL:movieUrl] animated:YES];\n    }];\n}\n\n- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker\n{\n    [self dismissViewControllerAnimated:YES completion:NULL];\n}\n\n#pragma mark misc\n\n- (BOOL) startMediaBrowserFromViewController: (UIViewController*) controller\n                               usingDelegate: (id <UIImagePickerControllerDelegate,\n                                               UINavigationControllerDelegate>) delegate {\n\n    if (([UIImagePickerController isSourceTypeAvailable:\n          UIImagePickerControllerSourceTypeSavedPhotosAlbum] == NO)\n        || (delegate == nil)\n        || (controller == nil))\n        return NO;\n\n    UIImagePickerController *mediaUI = [[UIImagePickerController alloc] init];\n    mediaUI.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;\n\n    // Displays saved pictures and movies, if both are available, from the\n    // Camera Roll album.\n    mediaUI.mediaTypes = [[NSArray alloc] initWithObjects: (NSString *) kUTTypeMovie, nil];\n\n    // Hides the controls for moving & scaling pictures, or for\n    // trimming movies. To instead show the controls, use YES.\n    mediaUI.allowsEditing = NO;\n\n    mediaUI.delegate = delegate;\n\n    [controller presentViewController:mediaUI animated:YES completion:nil];\n    return YES;\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/IJKDemoMainViewController.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVersion=\"7531\" systemVersion=\"14A389\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\">\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"7520\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\" customClass=\"IJKDemoMainViewController\">\n            <connections>\n                <outlet property=\"tableView\" destination=\"hFv-Sg-rxl\" id=\"OuB-AJ-cvM\"/>\n                <outlet property=\"view\" destination=\"iN0-l3-epB\" id=\"d8B-6e-hY8\"/>\n            </connections>\n        </placeholder>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"iN0-l3-epB\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"600\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <tableView clipsSubviews=\"YES\" contentMode=\"scaleToFill\" alwaysBounceVertical=\"YES\" style=\"plain\" separatorStyle=\"default\" rowHeight=\"44\" sectionHeaderHeight=\"22\" sectionFooterHeight=\"22\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hFv-Sg-rxl\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"600\"/>\n                    <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                    <connections>\n                        <outlet property=\"dataSource\" destination=\"-1\" id=\"Sct-ml-94e\"/>\n                        <outlet property=\"delegate\" destination=\"-1\" id=\"6Si-jf-dml\"/>\n                    </connections>\n                </tableView>\n            </subviews>\n            <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n            <constraints>\n                <constraint firstItem=\"hFv-Sg-rxl\" firstAttribute=\"top\" secondItem=\"iN0-l3-epB\" secondAttribute=\"top\" id=\"44f-8U-Nl9\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"hFv-Sg-rxl\" secondAttribute=\"bottom\" id=\"JWM-jK-2fA\"/>\n                <constraint firstItem=\"hFv-Sg-rxl\" firstAttribute=\"leading\" secondItem=\"iN0-l3-epB\" secondAttribute=\"leading\" id=\"MYB-hY-tK5\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"hFv-Sg-rxl\" secondAttribute=\"trailing\" id=\"s3E-4P-8xx\"/>\n            </constraints>\n        </view>\n    </objects>\n</document>\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/IJKDemoSampleViewController.h",
    "content": "/*\n * Copyright (C) 2013-2015 Bilibili\n * Copyright (C) 2013-2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <UIKit/UIKit.h>\n\n@interface IJKDemoSampleViewController : UIViewController\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/IJKDemoSampleViewController.m",
    "content": "/*\n * Copyright (C) 2013-2015 Bilibili\n * Copyright (C) 2013-2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import \"IJKDemoSampleViewController.h\"\n\n#import \"IJKCommon.h\"\n#import \"IJKMoviePlayerViewController.h\"\n\n@interface IJKDemoSampleViewController () <UITableViewDataSource, UITableViewDelegate>\n\n@property(nonatomic,strong) IBOutlet UITableView *tableView;\n@property(nonatomic,strong) NSArray *sampleList;\n\n@end\n\n@implementation IJKDemoSampleViewController\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n\n    self.title = @\"M3U8\";\n\n    NSMutableArray *sampleList = [[NSMutableArray alloc] init];\n\n    [sampleList addObject:@[@\"las url\",\n    @\"{\\\"version\\\":\\\"1.0.0\\\",\\\"adaptationSet\\\":[{\\\"duration\\\":1000,\\\"id\\\":1,\\\"representation\\\":[{\\\"id\\\":1,\\\"codec\\\":\\\"avc1.64001e,mp4a.40.5\\\",\\\"url\\\":\\\"http://las-tech.org.cn/kwai/las-test_ld500d.flv\\\",\\\"backupUrl\\\":[],\\\"host\\\":\\\"las-tech.org.cn\\\",\\\"maxBitrate\\\":700,\\\"width\\\":640,\\\"height\\\":360,\\\"frameRate\\\":25,\\\"qualityType\\\":\\\"SMOOTH\\\",\\\"qualityTypeName\\\":\\\"流畅\\\",\\\"hidden\\\":false,\\\"disabledFromAdaptive\\\":false,\\\"defaultSelected\\\":false},{\\\"id\\\":2,\\\"codec\\\":\\\"avc1.64001f,mp4a.40.5\\\",\\\"url\\\":\\\"http://las-tech.org.cn/kwai/las-test_sd1000d.flv\\\",\\\"backupUrl\\\":[],\\\"host\\\":\\\"las-tech.org.cn\\\",\\\"maxBitrate\\\":1300,\\\"width\\\":960,\\\"height\\\":540,\\\"frameRate\\\":25,\\\"qualityType\\\":\\\"STANDARD\\\",\\\"qualityTypeName\\\":\\\"标清\\\",\\\"hidden\\\":false,\\\"disabledFromAdaptive\\\":false,\\\"defaultSelected\\\":true},{\\\"id\\\":3,\\\"codec\\\":\\\"avc1.64001f,mp4a.40.5\\\",\\\"url\\\":\\\"http://las-tech.org.cn/kwai/las-test.flv\\\",\\\"backupUrl\\\":[],\\\"host\\\":\\\"las-tech.org.cn\\\",\\\"maxBitrate\\\":2300,\\\"width\\\":1280,\\\"height\\\":720,\\\"frameRate\\\":30,\\\"qualityType\\\":\\\"HIGH\\\",\\\"qualityTypeName\\\":\\\"高清\\\",\\\"hidden\\\":false,\\\"disabledFromAdaptive\\\":false,\\\"defaultSelected\\\":false}]}]}\"]];\n    [sampleList addObject:@[@\"bipbop basic master playlist\",\n                            @\"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8\"]];\n    [sampleList addObject:@[@\"bipbop basic 400x300 @ 232 kbps\",\n                            @\"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/prog_index.m3u8\"]];\n    [sampleList addObject:@[@\"bipbop basic 640x480 @ 650 kbps\",\n                            @\"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear2/prog_index.m3u8\"]];\n    [sampleList addObject:@[@\"bipbop basic 640x480 @ 1 Mbps\",\n                            @\"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear3/prog_index.m3u8\"]];\n    [sampleList addObject:@[@\"bipbop basic 960x720 @ 2 Mbps\",\n                            @\"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear4/prog_index.m3u8\"]];\n    [sampleList addObject:@[@\"bipbop basic 22.050Hz stereo @ 40 kbps\",\n                            @\"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear0/prog_index.m3u8\"]];\n\n    [sampleList addObject:@[@\"bipbop advanced master playlist\",\n                            @\"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8\"]];\n    [sampleList addObject:@[@\"bipbop advanced 416x234 @ 265 kbps\",\n                            @\"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/gear1/prog_index.m3u8\"]];\n    [sampleList addObject:@[@\"bipbop advanced 640x360 @ 580 kbps\",\n                            @\"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/gear2/prog_index.m3u8\"]];\n    [sampleList addObject:@[@\"bipbop advanced 960x540 @ 910 kbps\",\n                            @\"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/gear3/prog_index.m3u8\"]];\n    [sampleList addObject:@[@\"bipbop advanced 1280x720 @ 1 Mbps\",\n                            @\"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/gear4/prog_index.m3u8\"]];\n    [sampleList addObject:@[@\"bipbop advanced 1920x1080 @ 2 Mbps\",\n                            @\"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/gear5/prog_index.m3u8\"]];\n    [sampleList addObject:@[@\"bipbop advanced 22.050Hz stereo @ 40 kbps\",\n                            @\"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/gear0/prog_index.m3u8\"]];\n\n    self.sampleList = sampleList;\n}\n\n- (void)viewWillAppear:(BOOL)animated {\n    [super viewWillAppear:animated];\n\n    [self.tableView reloadData];\n}\n\n- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {\n    return 1;\n}\n\n- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {\n    return @\"Samples\";\n}\n\n- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {\n    if (IOS_NEWER_OR_EQUAL_TO_7) {\n        return self.sampleList.count;\n    } else {\n        return self.sampleList.count - 1;\n    }\n}\n\n- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {\n    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@\"abc\"];\n    if (nil == cell) {\n        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@\"abc\"];\n        cell.textLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;\n    }\n\n    cell.textLabel.text = self.sampleList[indexPath.row][0];\n\n    return cell;\n}\n\n- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {\n    [tableView deselectRowAtIndexPath:indexPath animated:YES];\n\n    NSArray *item = self.sampleList[indexPath.row];\n    NSString *url_str = item[1];\n    \n    if ([url_str containsString:@\"adaptationSet\"]) {\n        [self.navigationController presentViewController:[[IJKVideoViewController alloc] initWithManifest:url_str] animated:YES completion:^{}];\n    } else{\n        NSURL   *url  = [NSURL URLWithString:item[1]];\n        [self.navigationController presentViewController:[[IJKVideoViewController alloc] initWithURL:url] animated:YES completion:^{}];\n    }\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/IJKDemoSampleViewController.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVersion=\"7706\" systemVersion=\"14D136\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\">\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"7703\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\" customClass=\"IJKDemoSampleViewController\">\n            <connections>\n                <outlet property=\"tableView\" destination=\"OPe-Bw-4Ug\" id=\"RHh-ue-gY0\"/>\n                <outlet property=\"view\" destination=\"i5M-Pr-FkT\" id=\"sfx-zR-JGt\"/>\n            </connections>\n        </placeholder>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view clearsContextBeforeDrawing=\"NO\" contentMode=\"scaleToFill\" id=\"i5M-Pr-FkT\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"600\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <tableView clipsSubviews=\"YES\" contentMode=\"scaleToFill\" alwaysBounceVertical=\"YES\" style=\"plain\" separatorStyle=\"default\" rowHeight=\"44\" sectionHeaderHeight=\"22\" sectionFooterHeight=\"22\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"OPe-Bw-4Ug\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"600\"/>\n                    <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                    <connections>\n                        <outlet property=\"dataSource\" destination=\"-1\" id=\"Vn3-yn-pFZ\"/>\n                        <outlet property=\"delegate\" destination=\"-1\" id=\"4A7-s4-qIV\"/>\n                    </connections>\n                </tableView>\n            </subviews>\n            <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n            <constraints>\n                <constraint firstItem=\"OPe-Bw-4Ug\" firstAttribute=\"top\" secondItem=\"i5M-Pr-FkT\" secondAttribute=\"top\" id=\"3YI-7X-hIX\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"OPe-Bw-4Ug\" secondAttribute=\"bottom\" id=\"GmF-d0-HRA\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"OPe-Bw-4Ug\" secondAttribute=\"trailing\" id=\"KZZ-Ye-kdF\"/>\n                <constraint firstItem=\"OPe-Bw-4Ug\" firstAttribute=\"leading\" secondItem=\"i5M-Pr-FkT\" secondAttribute=\"leading\" id=\"Por-08-xPx\"/>\n            </constraints>\n        </view>\n    </objects>\n</document>\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/IJKMediaControl.h",
    "content": "/*\n * Copyright (C) 2013-2015 Bilibili\n * Copyright (C) 2013-2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <UIKit/UIKit.h>\n\n@protocol IJKMediaPlayback;\n\n@interface IJKMediaControl : UIControl\n\n- (void)showNoFade;\n- (void)showAndFade;\n- (void)hide;\n- (void)refreshMediaControl;\n\n- (void)beginDragMediaSlider;\n- (void)endDragMediaSlider;\n- (void)continueDragMediaSlider;\n\n@property(nonatomic,weak) id<IJKMediaPlayback> delegatePlayer;\n\n@property(nonatomic,strong) IBOutlet UIView *overlayPanel;\n@property(nonatomic,strong) IBOutlet UIView *topPanel;\n@property(nonatomic,strong) IBOutlet UIView *bottomPanel;\n\n@property(nonatomic,strong) IBOutlet UIButton *playButton;\n@property(nonatomic,strong) IBOutlet UIButton *pauseButton;\n\n@property(nonatomic,strong) IBOutlet UILabel *currentTimeLabel;\n@property(nonatomic,strong) IBOutlet UILabel *totalDurationLabel;\n@property(nonatomic,strong) IBOutlet UISlider *mediaProgressSlider;\n\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/IJKMediaControl.m",
    "content": "/*\n * Copyright (C) 2013-2015 Bilibili\n * Copyright (C) 2013-2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import \"IJKMediaControl.h\"\n#import <IJKMediaFramework/IJKMediaFramework.h>\n\n@implementation IJKMediaControl\n{\n    BOOL _isMediaSliderBeingDragged;\n}\n\n- (id)initWithFrame:(CGRect)frame\n{\n    self = [super initWithFrame:frame];\n    if (self) {\n        // Initialization code\n    }\n    return self;\n}\n\n- (void)awakeFromNib\n{\n    [self refreshMediaControl];\n}\n\n- (void)showNoFade\n{\n    self.overlayPanel.hidden = NO;\n    [self cancelDelayedHide];\n    [self refreshMediaControl];\n}\n\n- (void)showAndFade\n{\n    [self showNoFade];\n    [self performSelector:@selector(hide) withObject:nil afterDelay:5];\n}\n\n- (void)hide\n{\n    self.overlayPanel.hidden = YES;\n    [self cancelDelayedHide];\n}\n\n- (void)cancelDelayedHide\n{\n    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hide) object:nil];\n}\n\n- (void)beginDragMediaSlider\n{\n    _isMediaSliderBeingDragged = YES;\n}\n\n- (void)endDragMediaSlider\n{\n    _isMediaSliderBeingDragged = NO;\n}\n\n- (void)continueDragMediaSlider\n{\n    [self refreshMediaControl];\n}\n\n- (void)refreshMediaControl\n{\n    // duration\n    NSTimeInterval duration = self.delegatePlayer.duration;\n    NSInteger intDuration = duration + 0.5;\n    if (intDuration > 0) {\n        self.mediaProgressSlider.maximumValue = duration;\n        self.totalDurationLabel.text = [NSString stringWithFormat:@\"%02d:%02d\", (int)(intDuration / 60), (int)(intDuration % 60)];\n    } else {\n        self.totalDurationLabel.text = @\"--:--\";\n        self.mediaProgressSlider.maximumValue = 1.0f;\n    }\n\n\n    // position\n    NSTimeInterval position;\n    if (_isMediaSliderBeingDragged) {\n        position = self.mediaProgressSlider.value;\n    } else {\n        position = self.delegatePlayer.currentPlaybackTime;\n    }\n    NSInteger intPosition = position + 0.5;\n    if (intDuration > 0) {\n        self.mediaProgressSlider.value = position;\n    } else {\n        self.mediaProgressSlider.value = 0.0f;\n    }\n    self.currentTimeLabel.text = [NSString stringWithFormat:@\"%02d:%02d\", (int)(intPosition / 60), (int)(intPosition % 60)];\n\n\n    // status\n    BOOL isPlaying = [self.delegatePlayer isPlaying];\n    self.playButton.hidden = isPlaying;\n    self.pauseButton.hidden = !isPlaying;\n\n\n    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(refreshMediaControl) object:nil];\n    if (!self.overlayPanel.hidden) {\n        [self performSelector:@selector(refreshMediaControl) withObject:nil afterDelay:0.5];\n    }\n}\n\n#pragma mark IBAction\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/IJKMediaDemo-Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>${PRODUCT_NAME}</string>\n\t<key>CFBundleExecutable</key>\n\t<string>${EXECUTABLE_NAME}</string>\n\t<key>CFBundleIcons</key>\n\t<dict/>\n\t<key>CFBundleIcons~ipad</key>\n\t<dict/>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>${PRODUCT_NAME}</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>0.4.2</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>402</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UIFileSharingEnabled</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/IJKMediaDemo-Prefix.pch",
    "content": "//\n// Prefix header for all source files of the 'test' target in the 'test' project\n//\n\n#import <Availability.h>\n\n#ifndef __IPHONE_3_0\n#warning \"This project uses features only available in iOS SDK 3.0 and later.\"\n#endif\n\n#ifdef __OBJC__\n    #import <UIKit/UIKit.h>\n    #import <Foundation/Foundation.h>\n#endif"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/IJKMoviePlayerViewController.h",
    "content": "/*\n * Copyright (C) 2013-2015 Bilibili\n * Copyright (C) 2013-2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <UIKit/UIKit.h>\n#import <IJKMediaFramework/IJKMediaFramework.h>\n@class IJKMediaControl;\n\n@interface IJKVideoViewController : UIViewController\n\n@property(atomic,strong) NSURL *url;\n@property(strong,nonatomic) NSString* manifest;\n@property(atomic, retain) id<IJKMediaPlayback> player;\n\n- (id)initWithURL:(NSURL *)url;\n- (id)initWithManifest:(NSString*)manifest_string;\n\n+ (void)presentFromViewController:(UIViewController *)viewController withTitle:(NSString *)title URL:(NSURL *)url completion:(void(^)())completion;\n\n- (IBAction)onClickMediaControl:(id)sender;\n- (IBAction)onClickOverlay:(id)sender;\n- (IBAction)onClickDone:(id)sender;\n- (IBAction)onClickPlay:(id)sender;\n- (IBAction)onClickPause:(id)sender;\n\n- (IBAction)didSliderTouchDown;\n- (IBAction)didSliderTouchCancel;\n- (IBAction)didSliderTouchUpOutside;\n- (IBAction)didSliderTouchUpInside;\n- (IBAction)didSliderValueChanged;\n\n@property(nonatomic,strong) IBOutlet IJKMediaControl *mediaControl;\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/IJKMoviePlayerViewController.m",
    "content": "/*\n * Copyright (C) 2013-2015 Bilibili\n * Copyright (C) 2013-2015 Zhang Rui <bbcallen@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import \"IJKMoviePlayerViewController.h\"\n#import \"IJKMediaControl.h\"\n#import \"IJKCommon.h\"\n#import \"IJKDemoHistory.h\"\n\n@implementation IJKVideoViewController\n\n- (void)dealloc\n{\n}\n\n+ (void)presentFromViewController:(UIViewController *)viewController withTitle:(NSString *)title URL:(NSURL *)url completion:(void (^)())completion {\n    IJKDemoHistoryItem *historyItem = [[IJKDemoHistoryItem alloc] init];\n    \n    historyItem.title = title;\n    historyItem.url = url;\n    [[IJKDemoHistory instance] add:historyItem];\n    \n    [viewController presentViewController:[[IJKVideoViewController alloc] initWithURL:url] animated:YES completion:completion];\n}\n\n- (instancetype)initWithManifest: (NSString*)manifest_string {\n    self = [self initWithNibName:@\"IJKMoviePlayerViewController\" bundle:nil];\n    if (self) {\n        self.url = [NSURL URLWithString:@\"ijklas:\"];\n        self.manifest = manifest_string;\n    }\n    return self;\n}\n\n- (instancetype)initWithURL:(NSURL *)url {\n    self = [self initWithNibName:@\"IJKMoviePlayerViewController\" bundle:nil];\n    if (self) {\n        self.url = url;\n    }\n    return self;\n}\n\n- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil\n{\n    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];\n    if (self) {\n        // Custom initialization\n    }\n    return self;\n}\n\n#define EXPECTED_IJKPLAYER_VERSION (1 << 16) & 0xFF) | \n- (void)viewDidLoad\n{\n    [super viewDidLoad];\n    // Do any additional setup after loading the view from its nib.\n\n//    [[UIApplication sharedApplication] setStatusBarHidden:YES];\n//    [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeLeft animated:NO];\n\n#ifdef DEBUG\n    [IJKFFMoviePlayerController setLogReport:YES];\n    [IJKFFMoviePlayerController setLogLevel:k_IJK_LOG_DEBUG];\n#else\n    [IJKFFMoviePlayerController setLogReport:NO];\n    [IJKFFMoviePlayerController setLogLevel:k_IJK_LOG_INFO];\n#endif\n\n    [IJKFFMoviePlayerController checkIfFFmpegVersionMatch:YES];\n    // [IJKFFMoviePlayerController checkIfPlayerVersionMatch:YES major:1 minor:0 micro:0];\n\n    IJKFFOptions *options = [IJKFFOptions optionsByDefault];\n\n    if (self.manifest != nil){\n        [options setPlayerOptionValue:@\"ijklas\"         forKey:@\"iformat\"];\n        [options setPlayerOptionIntValue:0              forKey:@\"find_stream_info\"];\n        [options setFormatOptionValue:self.manifest     forKey:@\"manifest_string\"];\n    }\n    self.player = [[IJKFFMoviePlayerController alloc] initWithContentURL:self.url withOptions:options];\n    self.player.view.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;\n    self.player.view.frame = self.view.bounds;\n    self.player.scalingMode = IJKMPMovieScalingModeAspectFit;\n    self.player.shouldAutoplay = YES;\n\n    self.view.autoresizesSubviews = YES;\n    [self.view addSubview:self.player.view];\n    [self.view addSubview:self.mediaControl];\n\n    self.mediaControl.delegatePlayer = self.player;\n}\n\n- (void)viewWillAppear:(BOOL)animated {\n    [super viewWillAppear:animated];\n    \n    [self installMovieNotificationObservers];\n\n    [self.player prepareToPlay];\n}\n\n- (void)viewDidDisappear:(BOOL)animated {\n    [super viewDidDisappear:animated];\n    \n    [self.player shutdown];\n    [self removeMovieNotificationObservers];\n}\n\n- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{\n    return UIInterfaceOrientationIsLandscape(toInterfaceOrientation);\n}\n\n- (UIInterfaceOrientationMask)supportedInterfaceOrientations\n{\n    return UIInterfaceOrientationMaskLandscape;\n}\n\n- (void)didReceiveMemoryWarning\n{\n    [super didReceiveMemoryWarning];\n    // Dispose of any resources that can be recreated.\n}\n\n#pragma mark IBAction\n\n- (IBAction)onClickMediaControl:(id)sender\n{\n    [self.mediaControl showAndFade];\n}\n\n- (IBAction)onClickOverlay:(id)sender\n{\n    [self.mediaControl hide];\n}\n\n- (IBAction)onClickDone:(id)sender\n{\n    [self.presentingViewController dismissViewControllerAnimated:YES completion:nil];\n}\n\n- (IBAction)onClickHUD:(UIBarButtonItem *)sender\n{\n    if ([self.player isKindOfClass:[IJKFFMoviePlayerController class]]) {\n        IJKFFMoviePlayerController *player = self.player;\n        player.shouldShowHudView = !player.shouldShowHudView;\n        \n        sender.title = (player.shouldShowHudView ? @\"HUD On\" : @\"HUD Off\");\n    }\n}\n\n- (IBAction)onClickPlay:(id)sender\n{\n    [self.player play];\n    [self.mediaControl refreshMediaControl];\n}\n\n- (IBAction)onClickPause:(id)sender\n{\n    [self.player pause];\n    [self.mediaControl refreshMediaControl];\n}\n\n- (IBAction)didSliderTouchDown\n{\n    [self.mediaControl beginDragMediaSlider];\n}\n\n- (IBAction)didSliderTouchCancel\n{\n    [self.mediaControl endDragMediaSlider];\n}\n\n- (IBAction)didSliderTouchUpOutside\n{\n    [self.mediaControl endDragMediaSlider];\n}\n\n- (IBAction)didSliderTouchUpInside\n{\n    self.player.currentPlaybackTime = self.mediaControl.mediaProgressSlider.value;\n    [self.mediaControl endDragMediaSlider];\n}\n\n- (IBAction)didSliderValueChanged\n{\n    [self.mediaControl continueDragMediaSlider];\n}\n\n- (void)loadStateDidChange:(NSNotification*)notification\n{\n    //    MPMovieLoadStateUnknown        = 0,\n    //    MPMovieLoadStatePlayable       = 1 << 0,\n    //    MPMovieLoadStatePlaythroughOK  = 1 << 1, // Playback will be automatically started in this state when shouldAutoplay is YES\n    //    MPMovieLoadStateStalled        = 1 << 2, // Playback will be automatically paused in this state, if started\n\n    IJKMPMovieLoadState loadState = _player.loadState;\n\n    if ((loadState & IJKMPMovieLoadStatePlaythroughOK) != 0) {\n        NSLog(@\"loadStateDidChange: IJKMPMovieLoadStatePlaythroughOK: %d\\n\", (int)loadState);\n    } else if ((loadState & IJKMPMovieLoadStateStalled) != 0) {\n        NSLog(@\"loadStateDidChange: IJKMPMovieLoadStateStalled: %d\\n\", (int)loadState);\n    } else {\n        NSLog(@\"loadStateDidChange: ???: %d\\n\", (int)loadState);\n    }\n}\n\n- (void)moviePlayBackDidFinish:(NSNotification*)notification\n{\n    //    MPMovieFinishReasonPlaybackEnded,\n    //    MPMovieFinishReasonPlaybackError,\n    //    MPMovieFinishReasonUserExited\n    int reason = [[[notification userInfo] valueForKey:IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey] intValue];\n\n    switch (reason)\n    {\n        case IJKMPMovieFinishReasonPlaybackEnded:\n            NSLog(@\"playbackStateDidChange: IJKMPMovieFinishReasonPlaybackEnded: %d\\n\", reason);\n            break;\n\n        case IJKMPMovieFinishReasonUserExited:\n            NSLog(@\"playbackStateDidChange: IJKMPMovieFinishReasonUserExited: %d\\n\", reason);\n            break;\n\n        case IJKMPMovieFinishReasonPlaybackError:\n            NSLog(@\"playbackStateDidChange: IJKMPMovieFinishReasonPlaybackError: %d\\n\", reason);\n            break;\n\n        default:\n            NSLog(@\"playbackPlayBackDidFinish: ???: %d\\n\", reason);\n            break;\n    }\n}\n\n- (void)mediaIsPreparedToPlayDidChange:(NSNotification*)notification\n{\n    NSLog(@\"mediaIsPreparedToPlayDidChange\\n\");\n}\n\n- (void)moviePlayBackStateDidChange:(NSNotification*)notification\n{\n    //    MPMoviePlaybackStateStopped,\n    //    MPMoviePlaybackStatePlaying,\n    //    MPMoviePlaybackStatePaused,\n    //    MPMoviePlaybackStateInterrupted,\n    //    MPMoviePlaybackStateSeekingForward,\n    //    MPMoviePlaybackStateSeekingBackward\n\n    switch (_player.playbackState)\n    {\n        case IJKMPMoviePlaybackStateStopped: {\n            NSLog(@\"IJKMPMoviePlayBackStateDidChange %d: stoped\", (int)_player.playbackState);\n            break;\n        }\n        case IJKMPMoviePlaybackStatePlaying: {\n            NSLog(@\"IJKMPMoviePlayBackStateDidChange %d: playing\", (int)_player.playbackState);\n            break;\n        }\n        case IJKMPMoviePlaybackStatePaused: {\n            NSLog(@\"IJKMPMoviePlayBackStateDidChange %d: paused\", (int)_player.playbackState);\n            break;\n        }\n        case IJKMPMoviePlaybackStateInterrupted: {\n            NSLog(@\"IJKMPMoviePlayBackStateDidChange %d: interrupted\", (int)_player.playbackState);\n            break;\n        }\n        case IJKMPMoviePlaybackStateSeekingForward:\n        case IJKMPMoviePlaybackStateSeekingBackward: {\n            NSLog(@\"IJKMPMoviePlayBackStateDidChange %d: seeking\", (int)_player.playbackState);\n            break;\n        }\n        default: {\n            NSLog(@\"IJKMPMoviePlayBackStateDidChange %d: unknown\", (int)_player.playbackState);\n            break;\n        }\n    }\n}\n\n#pragma mark Install Movie Notifications\n\n/* Register observers for the various movie object notifications. */\n-(void)installMovieNotificationObservers\n{\n\t[[NSNotificationCenter defaultCenter] addObserver:self\n                                             selector:@selector(loadStateDidChange:)\n                                                 name:IJKMPMoviePlayerLoadStateDidChangeNotification\n                                               object:_player];\n\n\t[[NSNotificationCenter defaultCenter] addObserver:self\n                                             selector:@selector(moviePlayBackDidFinish:)\n                                                 name:IJKMPMoviePlayerPlaybackDidFinishNotification\n                                               object:_player];\n\n\t[[NSNotificationCenter defaultCenter] addObserver:self\n                                             selector:@selector(mediaIsPreparedToPlayDidChange:)\n                                                 name:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification\n                                               object:_player];\n\n\t[[NSNotificationCenter defaultCenter] addObserver:self\n                                             selector:@selector(moviePlayBackStateDidChange:)\n                                                 name:IJKMPMoviePlayerPlaybackStateDidChangeNotification\n                                               object:_player];\n}\n\n#pragma mark Remove Movie Notification Handlers\n\n/* Remove the movie notification observers from the movie object. */\n-(void)removeMovieNotificationObservers\n{\n    [[NSNotificationCenter defaultCenter]removeObserver:self name:IJKMPMoviePlayerLoadStateDidChangeNotification object:_player];\n    [[NSNotificationCenter defaultCenter]removeObserver:self name:IJKMPMoviePlayerPlaybackDidFinishNotification object:_player];\n    [[NSNotificationCenter defaultCenter]removeObserver:self name:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification object:_player];\n    [[NSNotificationCenter defaultCenter]removeObserver:self name:IJKMPMoviePlayerPlaybackStateDidChangeNotification object:_player];\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/IJKMoviePlayerViewController.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVersion=\"9531\" systemVersion=\"15C50\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\">\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"9529\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\" customClass=\"IJKVideoViewController\">\n            <connections>\n                <outlet property=\"mediaControl\" destination=\"6\" id=\"24\"/>\n                <outlet property=\"view\" destination=\"1\" id=\"53\"/>\n            </connections>\n        </placeholder>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"1\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"480\" height=\"320\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <color key=\"backgroundColor\" red=\"0.43529411764705883\" green=\"0.44313725490196076\" blue=\"0.47450980392156861\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n            <nil key=\"simulatedStatusBarMetrics\"/>\n            <simulatedOrientationMetrics key=\"simulatedOrientationMetrics\" orientation=\"landscapeRight\"/>\n            <freeformSimulatedSizeMetrics key=\"simulatedDestinationMetrics\"/>\n        </view>\n        <view contentMode=\"scaleToFill\" id=\"6\" customClass=\"IJKMediaControl\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"480\" height=\"320\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <view contentMode=\"scaleToFill\" id=\"54\" userLabel=\"Overlay\" customClass=\"UIControl\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"480\" height=\"320\"/>\n                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                    <subviews>\n                        <view contentMode=\"scaleToFill\" id=\"38\" userLabel=\"Panel: Bottom\">\n                            <rect key=\"frame\" x=\"40\" y=\"200\" width=\"400\" height=\"100\"/>\n                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" flexibleMinY=\"YES\"/>\n                            <subviews>\n                                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" image=\"player_bottom_control_bg.png\" id=\"39\" userLabel=\"View: Background\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"400\" height=\"100\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\"/>\n                                </imageView>\n                                <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" lineBreakMode=\"middleTruncation\" id=\"40\" userLabel=\"Button: Play\">\n                                    <rect key=\"frame\" x=\"170\" y=\"2\" width=\"60\" height=\"50\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                    <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"15\"/>\n                                    <state key=\"normal\" image=\"btn_player_play.png\">\n                                        <color key=\"titleColor\" red=\"0.19607843459999999\" green=\"0.30980393290000002\" blue=\"0.52156865600000002\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                        <color key=\"titleShadowColor\" white=\"0.5\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                    </state>\n                                    <state key=\"highlighted\">\n                                        <color key=\"titleColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                    </state>\n                                    <connections>\n                                        <action selector=\"onClickPlay:\" destination=\"-1\" eventType=\"touchUpInside\" id=\"45\"/>\n                                    </connections>\n                                </button>\n                                <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" lineBreakMode=\"middleTruncation\" id=\"41\" userLabel=\"Button: Pause\">\n                                    <rect key=\"frame\" x=\"170\" y=\"2\" width=\"60\" height=\"50\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                    <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"15\"/>\n                                    <state key=\"normal\" image=\"btn_player_pause.png\">\n                                        <color key=\"titleColor\" red=\"0.19607843459999999\" green=\"0.30980393290000002\" blue=\"0.52156865600000002\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                        <color key=\"titleShadowColor\" white=\"0.5\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                    </state>\n                                    <state key=\"highlighted\">\n                                        <color key=\"titleColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                    </state>\n                                    <connections>\n                                        <action selector=\"onClickPause:\" destination=\"-1\" eventType=\"touchUpInside\" id=\"46\"/>\n                                    </connections>\n                                </button>\n                                <slider opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" minValue=\"0.0\" maxValue=\"100\" id=\"42\" userLabel=\"Slider: Video Progress\">\n                                    <rect key=\"frame\" x=\"68\" y=\"55\" width=\"264\" height=\"29\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" flexibleMinY=\"YES\"/>\n                                    <connections>\n                                        <action selector=\"didSliderTouchCancel\" destination=\"-1\" eventType=\"touchCancel\" id=\"uRn-za-g7e\"/>\n                                        <action selector=\"didSliderTouchDown\" destination=\"-1\" eventType=\"touchDown\" id=\"H8O-Ig-c5b\"/>\n                                        <action selector=\"didSliderTouchUpInside\" destination=\"-1\" eventType=\"touchUpInside\" id=\"vLS-zl-CBo\"/>\n                                        <action selector=\"didSliderTouchUpOutside\" destination=\"-1\" eventType=\"touchUpOutside\" id=\"sT2-dJ-Ff0\"/>\n                                        <action selector=\"didSliderValueChanged\" destination=\"-1\" eventType=\"valueChanged\" id=\"d2y-5f-s9f\"/>\n                                    </connections>\n                                </slider>\n                                <label opaque=\"NO\" clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"left\" text=\"10:00\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" id=\"43\" userLabel=\"Label: Current Time\">\n                                    <rect key=\"frame\" x=\"20\" y=\"61\" width=\"50\" height=\"21\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                    <color key=\"textColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedRGB\"/>\n                                    <nil key=\"highlightedColor\"/>\n                                </label>\n                                <label opaque=\"NO\" clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"left\" text=\"20:00\" textAlignment=\"right\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" id=\"44\" userLabel=\"Label: Total Duration\">\n                                    <rect key=\"frame\" x=\"330\" y=\"61\" width=\"50\" height=\"21\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMinY=\"YES\"/>\n                                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                    <color key=\"textColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedRGB\"/>\n                                    <nil key=\"highlightedColor\"/>\n                                </label>\n                            </subviews>\n                            <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"calibratedWhite\"/>\n                        </view>\n                        <toolbar opaque=\"NO\" clearsContextBeforeDrawing=\"NO\" contentMode=\"scaleToFill\" id=\"4ZI-0o-F2w\">\n                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"480\" height=\"44\"/>\n                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" flexibleMinY=\"YES\"/>\n                            <items>\n                                <barButtonItem systemItem=\"done\" id=\"1XF-Pk-v6Z\">\n                                    <connections>\n                                        <action selector=\"onClickDone:\" destination=\"-1\" id=\"Lbg-xk-WzB\"/>\n                                    </connections>\n                                </barButtonItem>\n                                <barButtonItem systemItem=\"flexibleSpace\" id=\"pST-nN-ULY\"/>\n                                <barButtonItem title=\"HUD Off\" id=\"hpK-Ob-7Cx\">\n                                    <connections>\n                                        <action selector=\"onClickHUD:\" destination=\"-1\" id=\"xtO-DF-OuD\"/>\n                                    </connections>\n                                </barButtonItem>\n                            </items>\n                        </toolbar>\n                    </subviews>\n                    <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"calibratedWhite\"/>\n                    <connections>\n                        <action selector=\"onClickOverlay:\" destination=\"-1\" eventType=\"touchDown\" id=\"58\"/>\n                    </connections>\n                </view>\n            </subviews>\n            <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"calibratedWhite\"/>\n            <nil key=\"simulatedStatusBarMetrics\"/>\n            <simulatedOrientationMetrics key=\"simulatedOrientationMetrics\" orientation=\"landscapeRight\"/>\n            <freeformSimulatedSizeMetrics key=\"simulatedDestinationMetrics\"/>\n            <connections>\n                <action selector=\"onClickMediaControl:\" destination=\"-1\" eventType=\"touchDown\" id=\"59\"/>\n                <outlet property=\"bottomPanel\" destination=\"38\" id=\"50\"/>\n                <outlet property=\"currentTimeLabel\" destination=\"43\" id=\"60\"/>\n                <outlet property=\"mediaProgressSlider\" destination=\"42\" id=\"64\"/>\n                <outlet property=\"overlayPanel\" destination=\"54\" id=\"106\"/>\n                <outlet property=\"pauseButton\" destination=\"41\" id=\"65\"/>\n                <outlet property=\"playButton\" destination=\"40\" id=\"66\"/>\n                <outlet property=\"topPanel\" destination=\"4ZI-0o-F2w\" id=\"igp-Gq-Qk0\"/>\n                <outlet property=\"totalDurationLabel\" destination=\"44\" id=\"63\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"386\" y=\"448\"/>\n        </view>\n        <navigationItem title=\"Title\" id=\"wNK-Og-f4q\"/>\n    </objects>\n    <resources>\n        <image name=\"btn_player_pause.png\" width=\"36\" height=\"37\"/>\n        <image name=\"btn_player_play.png\" width=\"36\" height=\"36\"/>\n        <image name=\"player_bottom_control_bg.png\" width=\"400\" height=\"100\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/IJKQRCodeScanViewController.h",
    "content": "/*\n * Copyright (C) 2015 Gdier\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <UIKit/UIKit.h>\n\n@interface IJKQRCodeScanViewController : UIViewController\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/IJKQRCodeScanViewController.m",
    "content": "/*\n * Copyright (C) 2015 Gdier\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import \"IJKQRCodeScanViewController.h\"\n#import \"IJKMoviePlayerViewController.h\"\n#import \"Barcode.h\"\n#import <AVFoundation/AVFoundation.h>\n\n@interface IJKQRCodeScanViewController () <AVCaptureMetadataOutputObjectsDelegate>\n\n@property (weak, nonatomic) IBOutlet UIView *previewView;\n@property (strong, nonatomic) NSMutableArray * allowedBarcodeTypes;\n\n//@property (strong, nonatomic) SettingsViewController * settingsVC;\n\n@end\n\n@implementation IJKQRCodeScanViewController {\n\n    AVCaptureSession *_captureSession;\n    AVCaptureDevice *_videoDevice;\n    AVCaptureDeviceInput *_videoInput;\n    AVCaptureVideoPreviewLayer *_previewLayer;\n    BOOL _running;\n    AVCaptureMetadataOutput *_metadataOutput;\n}\n\n- (instancetype)init {\n    self = [super init];\n    if (self) {\n        self.title = @\"Scan QRCode\";\n    }\n    return self;\n}\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n    \n    [self setupCaptureSession];\n    _previewLayer.frame = _previewView.bounds;\n    [_previewView.layer addSublayer:_previewLayer];\n    \n    // listen for going into the background and stop the session\n    \n    // set default allowed barcode types, remove types via setings menu if you don't want them to be able to be scanned\n    self.allowedBarcodeTypes = [NSMutableArray new];\n    [self.allowedBarcodeTypes addObject:@\"org.iso.QRCode\"];\n}\n\n- (void)viewWillAppear:(BOOL)animated {\n    [super viewWillAppear:animated];\n\n    [[NSNotificationCenter defaultCenter] addObserver:self\n                                             selector:@selector(applicationWillEnterForeground:)\n                                                 name:UIApplicationWillEnterForegroundNotification\n                                               object:nil];\n    [[NSNotificationCenter defaultCenter] addObserver:self\n                                             selector:@selector(applicationDidEnterBackground:)\n                                                 name:UIApplicationDidEnterBackgroundNotification\n                                               object:nil];\n\n    _previewLayer.frame = _previewView.bounds;\n    \n    [self setupCaptureOrientation];\n}\n\n- (void)viewDidAppear:(BOOL)animated {\n    [super viewDidAppear:animated];\n    [self startRunning];\n}\n\n\n- (void)viewWillDisappear:(BOOL)animated {\n    [super viewWillDisappear:animated];\n    [self stopRunning];\n    \n    [[NSNotificationCenter defaultCenter] removeObserver:self];\n}\n\n#pragma mark - AV capture methods\n\n- (void)setupCaptureSession {\n\n    if (_captureSession) {\n        return;\n    }\n\n    _videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];\n    if (!_videoDevice) {\n        return;\n    }\n\n    _captureSession = [[AVCaptureSession alloc] init];\n    _videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:_videoDevice error:nil];\n\n    if ([_captureSession canAddInput:_videoInput]) {\n        [_captureSession addInput:_videoInput];\n    }\n    _previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];\n    _previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;\n    \n    // capture and process the metadata\n    _metadataOutput = [[AVCaptureMetadataOutput alloc] init];\n\n    [_metadataOutput setMetadataObjectsDelegate:self\n                                          queue:dispatch_get_main_queue()];\n    \n    if ([_captureSession canAddOutput:_metadataOutput]) {\n        [_captureSession addOutput:_metadataOutput];\n    }\n}\n\n- (void)setupCaptureOrientation {\n    if([_previewLayer.connection isVideoOrientationSupported]) {\n        AVCaptureVideoOrientation orientation;\n        \n        switch ([[UIApplication sharedApplication] statusBarOrientation]) {\n            case UIInterfaceOrientationLandscapeLeft:\n                orientation = AVCaptureVideoOrientationLandscapeLeft;\n                break;\n                \n            case UIInterfaceOrientationLandscapeRight:\n                orientation = AVCaptureVideoOrientationLandscapeRight;\n                break;\n                \n            default:\n                orientation = AVCaptureVideoOrientationLandscapeLeft;\n                break;\n        }\n        \n        [_previewLayer.connection setVideoOrientation:orientation];\n    }\n}\n\n- (void)startRunning {\n    if (_running) return;\n    [_captureSession startRunning];\n    _metadataOutput.metadataObjectTypes = @[AVMetadataObjectTypeQRCode];//_metadataOutput.availableMetadataObjectTypes;\n\n    _running = YES;\n}\n\n- (void)stopRunning {\n    if (!_running) return;\n    [_captureSession stopRunning];\n    _running = NO;\n}\n\n- (void)applicationWillEnterForeground:(NSNotification*)note {\n    [self startRunning];\n}\n- (void)applicationDidEnterBackground:(NSNotification*)note {\n    [self stopRunning];\n}\n\n#pragma mark - Delegate functions\n\n- (void)captureOutput:(AVCaptureOutput *)captureOutput\ndidOutputMetadataObjects:(NSArray *)metadataObjects\n       fromConnection:(AVCaptureConnection *)connection {\n    \n    [metadataObjects enumerateObjectsUsingBlock:^(AVMetadataObject *obj, NSUInteger idx, BOOL *stop) {\n         if ([obj isKindOfClass:[AVMetadataMachineReadableCodeObject class]]) {\n\n             AVMetadataMachineReadableCodeObject *code = (AVMetadataMachineReadableCodeObject *) [_previewLayer transformedMetadataObjectForMetadataObject:obj];\n\n             Barcode * barcode = [Barcode processMetadataObject:code];\n             \n             for(NSString * str in self.allowedBarcodeTypes) {\n                 if([barcode.getBarcodeType isEqualToString:str]) {\n                     [self validBarcodeFound:barcode];\n                     return;\n                 }\n             }\n         }\n     }];\n}\n\n- (void) validBarcodeFound:(Barcode *)barcode {\n    [self stopRunning];\n    [self showBarcodeAlert:barcode];\n}\n\n- (void) showBarcodeAlert:(Barcode *)barcode {\n    UIAlertView *message = [[UIAlertView alloc] initWithTitle:nil\n                                                      message:[barcode getBarcodeData]\n                                                     delegate:self\n                                            cancelButtonTitle:@\"Scan Again\"\n                                            otherButtonTitles:@\"Play\", nil];\n    \n    [message show];\n}\n\n- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {\n    if(buttonIndex == alertView.cancelButtonIndex) {\n        [self startRunning];\n    } else {\n        NSURL *url = [NSURL URLWithString:alertView.message];\n        \n        [IJKVideoViewController presentFromViewController:self withTitle:[NSString stringWithFormat:@\"URL: %@\", url] URL:url completion:^{\n            [self.navigationController popViewControllerAnimated:NO];\n        }];\n    }\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/IJKQRCodeScanViewController.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVersion=\"7531\" systemVersion=\"14A389\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\">\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"7520\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\" customClass=\"IJKQRCodeScanViewController\">\n            <connections>\n                <outlet property=\"previewView\" destination=\"iN0-l3-epB\" id=\"hed-3u-VkP\"/>\n                <outlet property=\"view\" destination=\"iN0-l3-epB\" id=\"jd3-Hf-Ktc\"/>\n            </connections>\n        </placeholder>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"iN0-l3-epB\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"600\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <color key=\"backgroundColor\" white=\"0.0\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n        </view>\n    </objects>\n</document>\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/Images.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"57x57\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"57x57\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/Images.xcassets/LaunchImage.launchimage/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Default@2x.png\",\n      \"minimum-system-version\" : \"7.0\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Default-568h@2x.png\",\n      \"minimum-system-version\" : \"7.0\",\n      \"subtype\" : \"retina4\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Default.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Default@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Default-568h@2x.png\",\n      \"subtype\" : \"retina4\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/LaunchScreen.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVersion=\"7531\" systemVersion=\"14A389\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\">\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"7520\"/>\n        <capability name=\"Constraints with non-1.0 multipliers\" minToolsVersion=\"5.1\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\"/>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"iN0-l3-epB\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"480\" height=\"480\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <label opaque=\"NO\" clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"  Copyright (c) 2015 bilibili. All rights reserved.\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" minimumFontSize=\"9\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"8ie-xW-0ye\">\n                    <rect key=\"frame\" x=\"20\" y=\"439\" width=\"441\" height=\"21\"/>\n                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                    <color key=\"textColor\" cocoaTouchSystemColor=\"darkTextColor\"/>\n                    <nil key=\"highlightedColor\"/>\n                    <variation key=\"widthClass=compact\">\n                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"11\"/>\n                    </variation>\n                </label>\n                <label opaque=\"NO\" clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"IJKMediaDemo\" textAlignment=\"center\" lineBreakMode=\"middleTruncation\" baselineAdjustment=\"alignBaselines\" minimumFontSize=\"18\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"kId-c2-rCX\">\n                    <rect key=\"frame\" x=\"20\" y=\"140\" width=\"441\" height=\"43\"/>\n                    <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"36\"/>\n                    <color key=\"textColor\" cocoaTouchSystemColor=\"darkTextColor\"/>\n                    <nil key=\"highlightedColor\"/>\n                </label>\n            </subviews>\n            <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n            <constraints>\n                <constraint firstItem=\"kId-c2-rCX\" firstAttribute=\"centerY\" secondItem=\"iN0-l3-epB\" secondAttribute=\"bottom\" multiplier=\"1/3\" constant=\"1\" id=\"Kid-kn-2rF\"/>\n                <constraint firstAttribute=\"centerX\" secondItem=\"kId-c2-rCX\" secondAttribute=\"centerX\" id=\"Koa-jz-hwk\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"8ie-xW-0ye\" secondAttribute=\"bottom\" constant=\"20\" id=\"Kzo-t9-V3l\"/>\n                <constraint firstItem=\"8ie-xW-0ye\" firstAttribute=\"leading\" secondItem=\"iN0-l3-epB\" secondAttribute=\"leading\" constant=\"20\" symbolic=\"YES\" id=\"MfP-vx-nX0\"/>\n                <constraint firstAttribute=\"centerX\" secondItem=\"8ie-xW-0ye\" secondAttribute=\"centerX\" id=\"ZEH-qu-HZ9\"/>\n                <constraint firstItem=\"kId-c2-rCX\" firstAttribute=\"leading\" secondItem=\"iN0-l3-epB\" secondAttribute=\"leading\" constant=\"20\" symbolic=\"YES\" id=\"fvb-Df-36g\"/>\n            </constraints>\n            <nil key=\"simulatedStatusBarMetrics\"/>\n            <freeformSimulatedSizeMetrics key=\"simulatedDestinationMetrics\"/>\n            <point key=\"canvasLocation\" x=\"404\" y=\"445\"/>\n        </view>\n    </objects>\n</document>\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/en.lproj/InfoPlist.strings",
    "content": "/* Localized versions of Info.plist keys */\n\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo/main.m",
    "content": "//\n//  main.m\n//  IJKMediaDemo\n//\n//  Created by ZhangRui on 13-9-19.\n//  Copyright (c) 2013年 bilibili. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n#import \"IJKAppDelegate.h\"\n\nint main(int argc, char *argv[])\n{\n    @autoreleasepool {\n        return UIApplicationMain(argc, argv, nil, NSStringFromClass([IJKAppDelegate class]));\n    }\n}\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t45D57D611A53233200BDD389 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 45D57D601A53233200BDD389 /* CoreVideo.framework */; };\n\t\t45D57D631A53233800BDD389 /* VideoToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 45D57D621A53233800BDD389 /* VideoToolbox.framework */; };\n\t\t546736C41E2371AE00FEE0DF /* libstdc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 546736C31E2371AE00FEE0DF /* libstdc++.tbd */; };\n\t\t55E809E21B143C47003E98A5 /* IJKDemoMainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 55E809E11B143C47003E98A5 /* IJKDemoMainViewController.m */; };\n\t\t55E809E41B143C85003E98A5 /* IJKDemoMainViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 55E809E31B143C85003E98A5 /* IJKDemoMainViewController.xib */; };\n\t\t55E809E61B145B55003E98A5 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 55E809E51B145B55003E98A5 /* LaunchScreen.xib */; };\n\t\t55E809EA1B145BC2003E98A5 /* IJKDemoInputURLViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 55E809E81B145BC2003E98A5 /* IJKDemoInputURLViewController.m */; };\n\t\t55E809EB1B145BC2003E98A5 /* IJKDemoInputURLViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 55E809E91B145BC2003E98A5 /* IJKDemoInputURLViewController.xib */; };\n\t\t55E809EE1B146C1E003E98A5 /* IJKQRCodeScanViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 55E809ED1B146C1E003E98A5 /* IJKQRCodeScanViewController.m */; };\n\t\t55E809F11B146C80003E98A5 /* Barcode.m in Sources */ = {isa = PBXBuildFile; fileRef = 55E809F01B146C80003E98A5 /* Barcode.m */; };\n\t\t55E809F31B146DE8003E98A5 /* IJKQRCodeScanViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 55E809F21B146DE8003E98A5 /* IJKQRCodeScanViewController.xib */; };\n\t\t55E809F61B1480BC003E98A5 /* IJKDemoHistory.m in Sources */ = {isa = PBXBuildFile; fileRef = 55E809F51B1480BC003E98A5 /* IJKDemoHistory.m */; };\n\t\t55E809F91B15A1DB003E98A5 /* IJKDemoLocalFolderViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 55E809F81B15A1DB003E98A5 /* IJKDemoLocalFolderViewController.m */; };\n\t\tE60E8C2A19EF70BB005B5B6E /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E60E8C2919EF70BB005B5B6E /* CoreMedia.framework */; };\n\t\tE612EAE517F7E0F800BEE660 /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E612EAE417F7E0F800BEE660 /* MediaPlayer.framework */; };\n\t\tE6166C9C17EDA4A20006B956 /* IJKMediaDemo-Prefix.pch in Resources */ = {isa = PBXBuildFile; fileRef = E6166C9B17EDA4A20006B956 /* IJKMediaDemo-Prefix.pch */; };\n\t\tE61B45AE19EF7021002792EC /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E61B45AD19EF7021002792EC /* AVFoundation.framework */; };\n\t\tE63FC29117F04C83003551EB /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E63FC28F17F04C83003551EB /* AudioToolbox.framework */; };\n\t\tE63FC2B417F172EA003551EB /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E63FC2B317F172E9003551EB /* OpenGLES.framework */; };\n\t\tE64D4F4E1938CCCC00F1C75D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E64D4F4D1938CCCC00F1C75D /* CoreGraphics.framework */; };\n\t\tE64D4F4F1938CD2100F1C75D /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E63FC2B717F17362003551EB /* QuartzCore.framework */; };\n\t\tE654EAF01B6B2A7900B0F2D0 /* IJKMediaFramework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E654EAD71B6B28B100B0F2D0 /* IJKMediaFramework.framework */; };\n\t\tE66F8DCB17EEDD8B00354D80 /* IJKMediaControl.m in Sources */ = {isa = PBXBuildFile; fileRef = E66F8DCA17EEDD8B00354D80 /* IJKMediaControl.m */; };\n\t\tE67323A71B69E6F800CB9036 /* AppIcons.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E67323A51B69E6F800CB9036 /* AppIcons.xcassets */; };\n\t\tE67323A81B69E6F800CB9036 /* LaunchImages.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E67323A61B69E6F800CB9036 /* LaunchImages.xcassets */; };\n\t\tE67323AC1B69E76100CB9036 /* MoviePlayerImages.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E67323AB1B69E76100CB9036 /* MoviePlayerImages.xcassets */; };\n\t\tE67323B11B69ECF500CB9036 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E67323B01B69ECF500CB9036 /* MobileCoreServices.framework */; };\n\t\tE6903F0017EAF70200CFD954 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E6903EFF17EAF70200CFD954 /* UIKit.framework */; };\n\t\tE6903F0A17EAF70200CFD954 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = E6903F0817EAF70200CFD954 /* InfoPlist.strings */; };\n\t\tE6903F0C17EAF70200CFD954 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E6903F0B17EAF70200CFD954 /* main.m */; };\n\t\tE6903F1017EAF70200CFD954 /* IJKAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E6903F0F17EAF70200CFD954 /* IJKAppDelegate.m */; };\n\t\tE6903F1217EAF70200CFD954 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = E6903F1117EAF70200CFD954 /* Default.png */; };\n\t\tE6903F1417EAF70200CFD954 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = E6903F1317EAF70200CFD954 /* Default@2x.png */; };\n\t\tE6903F1617EAF70200CFD954 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = E6903F1517EAF70200CFD954 /* Default-568h@2x.png */; };\n\t\tE6A9B56417EDA72C00A1A500 /* IJKMoviePlayerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E6A9B56217EDA72C00A1A500 /* IJKMoviePlayerViewController.m */; };\n\t\tE6A9B56517EDA72C00A1A500 /* IJKMoviePlayerViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = E6A9B56317EDA72C00A1A500 /* IJKMoviePlayerViewController.xib */; };\n\t\tE6F1D4BE1D38F29800E8665B /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = E6F1D4BD1D38F29800E8665B /* libz.tbd */; };\n\t\tE6F1D4C01D38F29D00E8665B /* libbz2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = E6F1D4BF1D38F29D00E8665B /* libbz2.tbd */; };\n\t\tE6F524EB1B183A0700B69DC7 /* IJKDemoSampleViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E6F524E91B183A0700B69DC7 /* IJKDemoSampleViewController.m */; };\n\t\tE6F524EC1B183A0700B69DC7 /* IJKDemoSampleViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = E6F524EA1B183A0700B69DC7 /* IJKDemoSampleViewController.xib */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\tE654EAD61B6B28B100B0F2D0 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = E6D74F2918A5F94B00165BFD /* IJKMediaPlayer.xcodeproj */;\n\t\t\tproxyType = 2;\n\t\t\tremoteGlobalIDString = E654EA8A1B6B27E600B0F2D0;\n\t\t\tremoteInfo = IJKMediaFramework;\n\t\t};\n\t\tE654EAD81B6B28B100B0F2D0 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = E6D74F2918A5F94B00165BFD /* IJKMediaPlayer.xcodeproj */;\n\t\t\tproxyType = 2;\n\t\t\tremoteGlobalIDString = E654EA941B6B27E600B0F2D0;\n\t\t\tremoteInfo = IJKMediaFrameworkTests;\n\t\t};\n\t\tE654EAEE1B6B2A1500B0F2D0 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = E6D74F2918A5F94B00165BFD /* IJKMediaPlayer.xcodeproj */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = E654EA891B6B27E600B0F2D0;\n\t\t\tremoteInfo = IJKMediaFramework;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXFileReference section */\n\t\t45D57D601A53233200BDD389 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; };\n\t\t45D57D621A53233800BDD389 /* VideoToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VideoToolbox.framework; path = System/Library/Frameworks/VideoToolbox.framework; sourceTree = SDKROOT; };\n\t\t546736C31E2371AE00FEE0DF /* libstdc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = \"sourcecode.text-based-dylib-definition\"; name = \"libstdc++.tbd\"; path = \"usr/lib/libstdc++.tbd\"; sourceTree = SDKROOT; };\n\t\t55E809E01B143C47003E98A5 /* IJKDemoMainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKDemoMainViewController.h; sourceTree = \"<group>\"; };\n\t\t55E809E11B143C47003E98A5 /* IJKDemoMainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKDemoMainViewController.m; sourceTree = \"<group>\"; };\n\t\t55E809E31B143C85003E98A5 /* IJKDemoMainViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = IJKDemoMainViewController.xib; sourceTree = \"<group>\"; };\n\t\t55E809E51B145B55003E98A5 /* LaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LaunchScreen.xib; sourceTree = \"<group>\"; };\n\t\t55E809E71B145BC2003E98A5 /* IJKDemoInputURLViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKDemoInputURLViewController.h; sourceTree = \"<group>\"; };\n\t\t55E809E81B145BC2003E98A5 /* IJKDemoInputURLViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKDemoInputURLViewController.m; sourceTree = \"<group>\"; };\n\t\t55E809E91B145BC2003E98A5 /* IJKDemoInputURLViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = IJKDemoInputURLViewController.xib; sourceTree = \"<group>\"; };\n\t\t55E809EC1B146C1E003E98A5 /* IJKQRCodeScanViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKQRCodeScanViewController.h; sourceTree = \"<group>\"; };\n\t\t55E809ED1B146C1E003E98A5 /* IJKQRCodeScanViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKQRCodeScanViewController.m; sourceTree = \"<group>\"; };\n\t\t55E809EF1B146C80003E98A5 /* Barcode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Barcode.h; sourceTree = \"<group>\"; };\n\t\t55E809F01B146C80003E98A5 /* Barcode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Barcode.m; sourceTree = \"<group>\"; };\n\t\t55E809F21B146DE8003E98A5 /* IJKQRCodeScanViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = IJKQRCodeScanViewController.xib; sourceTree = \"<group>\"; };\n\t\t55E809F41B1480BC003E98A5 /* IJKDemoHistory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKDemoHistory.h; sourceTree = \"<group>\"; };\n\t\t55E809F51B1480BC003E98A5 /* IJKDemoHistory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKDemoHistory.m; sourceTree = \"<group>\"; };\n\t\t55E809F71B15A1DB003E98A5 /* IJKDemoLocalFolderViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKDemoLocalFolderViewController.h; sourceTree = \"<group>\"; };\n\t\t55E809F81B15A1DB003E98A5 /* IJKDemoLocalFolderViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKDemoLocalFolderViewController.m; sourceTree = \"<group>\"; };\n\t\tE60E8C2919EF70BB005B5B6E /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };\n\t\tE612EAE417F7E0F800BEE660 /* MediaPlayer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaPlayer.framework; path = System/Library/Frameworks/MediaPlayer.framework; sourceTree = SDKROOT; };\n\t\tE6166C9B17EDA4A20006B956 /* IJKMediaDemo-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = \"IJKMediaDemo-Prefix.pch\"; sourceTree = \"<group>\"; };\n\t\tE61B45AD19EF7021002792EC /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };\n\t\tE63FC27817F032FD003551EB /* IJKCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKCommon.h; sourceTree = \"<group>\"; };\n\t\tE63FC28F17F04C83003551EB /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };\n\t\tE63FC2B317F172E9003551EB /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; };\n\t\tE63FC2B717F17362003551EB /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };\n\t\tE64D4F4D1938CCCC00F1C75D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };\n\t\tE66F8DC917EEDD8B00354D80 /* IJKMediaControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKMediaControl.h; sourceTree = \"<group>\"; };\n\t\tE66F8DCA17EEDD8B00354D80 /* IJKMediaControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKMediaControl.m; sourceTree = \"<group>\"; };\n\t\tE67323A51B69E6F800CB9036 /* AppIcons.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = AppIcons.xcassets; sourceTree = \"<group>\"; };\n\t\tE67323A61B69E6F800CB9036 /* LaunchImages.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = LaunchImages.xcassets; sourceTree = \"<group>\"; };\n\t\tE67323AB1B69E76100CB9036 /* MoviePlayerImages.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = MoviePlayerImages.xcassets; sourceTree = \"<group>\"; };\n\t\tE67323B01B69ECF500CB9036 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };\n\t\tE6903EFC17EAF70200CFD954 /* IJKMediaDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = IJKMediaDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tE6903EFF17EAF70200CFD954 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };\n\t\tE6903F0717EAF70200CFD954 /* IJKMediaDemo-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = \"IJKMediaDemo-Info.plist\"; sourceTree = \"<group>\"; };\n\t\tE6903F0917EAF70200CFD954 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = \"<group>\"; };\n\t\tE6903F0B17EAF70200CFD954 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = \"<group>\"; };\n\t\tE6903F0E17EAF70200CFD954 /* IJKAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJKAppDelegate.h; sourceTree = \"<group>\"; };\n\t\tE6903F0F17EAF70200CFD954 /* IJKAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJKAppDelegate.m; sourceTree = \"<group>\"; };\n\t\tE6903F1117EAF70200CFD954 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = \"<group>\"; };\n\t\tE6903F1317EAF70200CFD954 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = \"Default@2x.png\"; sourceTree = \"<group>\"; };\n\t\tE6903F1517EAF70200CFD954 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = \"Default-568h@2x.png\"; sourceTree = \"<group>\"; };\n\t\tE6A9B56117EDA72C00A1A500 /* IJKMoviePlayerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKMoviePlayerViewController.h; sourceTree = \"<group>\"; };\n\t\tE6A9B56217EDA72C00A1A500 /* IJKMoviePlayerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKMoviePlayerViewController.m; sourceTree = \"<group>\"; };\n\t\tE6A9B56317EDA72C00A1A500 /* IJKMoviePlayerViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = IJKMoviePlayerViewController.xib; sourceTree = \"<group>\"; };\n\t\tE6D74F2918A5F94B00165BFD /* IJKMediaPlayer.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = \"wrapper.pb-project\"; name = IJKMediaPlayer.xcodeproj; path = ../IJKMediaPlayer/IJKMediaPlayer.xcodeproj; sourceTree = \"<group>\"; };\n\t\tE6F1D4BD1D38F29800E8665B /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = \"sourcecode.text-based-dylib-definition\"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };\n\t\tE6F1D4BF1D38F29D00E8665B /* libbz2.tbd */ = {isa = PBXFileReference; lastKnownFileType = \"sourcecode.text-based-dylib-definition\"; name = libbz2.tbd; path = usr/lib/libbz2.tbd; sourceTree = SDKROOT; };\n\t\tE6F524E81B183A0700B69DC7 /* IJKDemoSampleViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKDemoSampleViewController.h; sourceTree = \"<group>\"; };\n\t\tE6F524E91B183A0700B69DC7 /* IJKDemoSampleViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKDemoSampleViewController.m; sourceTree = \"<group>\"; };\n\t\tE6F524EA1B183A0700B69DC7 /* IJKDemoSampleViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = IJKDemoSampleViewController.xib; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tE6903EF917EAF70200CFD954 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t546736C41E2371AE00FEE0DF /* libstdc++.tbd in Frameworks */,\n\t\t\t\tE63FC29117F04C83003551EB /* AudioToolbox.framework in Frameworks */,\n\t\t\t\tE61B45AE19EF7021002792EC /* AVFoundation.framework in Frameworks */,\n\t\t\t\tE64D4F4E1938CCCC00F1C75D /* CoreGraphics.framework in Frameworks */,\n\t\t\t\tE60E8C2A19EF70BB005B5B6E /* CoreMedia.framework in Frameworks */,\n\t\t\t\t45D57D611A53233200BDD389 /* CoreVideo.framework in Frameworks */,\n\t\t\t\tE6F1D4C01D38F29D00E8665B /* libbz2.tbd in Frameworks */,\n\t\t\t\tE6F1D4BE1D38F29800E8665B /* libz.tbd in Frameworks */,\n\t\t\t\tE654EAF01B6B2A7900B0F2D0 /* IJKMediaFramework.framework in Frameworks */,\n\t\t\t\tE612EAE517F7E0F800BEE660 /* MediaPlayer.framework in Frameworks */,\n\t\t\t\tE67323B11B69ECF500CB9036 /* MobileCoreServices.framework in Frameworks */,\n\t\t\t\tE63FC2B417F172EA003551EB /* OpenGLES.framework in Frameworks */,\n\t\t\t\tE64D4F4F1938CD2100F1C75D /* QuartzCore.framework in Frameworks */,\n\t\t\t\tE6903F0017EAF70200CFD954 /* UIKit.framework in Frameworks */,\n\t\t\t\t45D57D631A53233800BDD389 /* VideoToolbox.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\tE63FC27717F032D9003551EB /* Misc */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE63FC27817F032FD003551EB /* IJKCommon.h */,\n\t\t\t\t55E809EF1B146C80003E98A5 /* Barcode.h */,\n\t\t\t\t55E809F01B146C80003E98A5 /* Barcode.m */,\n\t\t\t\t55E809F41B1480BC003E98A5 /* IJKDemoHistory.h */,\n\t\t\t\t55E809F51B1480BC003E98A5 /* IJKDemoHistory.m */,\n\t\t\t);\n\t\t\tname = Misc;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE67323A01B69E6B800CB9036 /* XCAssets */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE67323A51B69E6F800CB9036 /* AppIcons.xcassets */,\n\t\t\t\tE67323A61B69E6F800CB9036 /* LaunchImages.xcassets */,\n\t\t\t\tE67323AB1B69E76100CB9036 /* MoviePlayerImages.xcassets */,\n\t\t\t);\n\t\t\tpath = XCAssets;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE6903EF317EAF70200CFD954 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE6D74F2918A5F94B00165BFD /* IJKMediaPlayer.xcodeproj */,\n\t\t\t\tE6903EFE17EAF70200CFD954 /* Frameworks */,\n\t\t\t\tE6903F0517EAF70200CFD954 /* IJKMediaDemo */,\n\t\t\t\tE6903EFD17EAF70200CFD954 /* Products */,\n\t\t\t\tE67323A01B69E6B800CB9036 /* XCAssets */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE6903EFD17EAF70200CFD954 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE6903EFC17EAF70200CFD954 /* IJKMediaDemo.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE6903EFE17EAF70200CFD954 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t546736C31E2371AE00FEE0DF /* libstdc++.tbd */,\n\t\t\t\tE63FC28F17F04C83003551EB /* AudioToolbox.framework */,\n\t\t\t\tE61B45AD19EF7021002792EC /* AVFoundation.framework */,\n\t\t\t\tE64D4F4D1938CCCC00F1C75D /* CoreGraphics.framework */,\n\t\t\t\tE60E8C2919EF70BB005B5B6E /* CoreMedia.framework */,\n\t\t\t\t45D57D601A53233200BDD389 /* CoreVideo.framework */,\n\t\t\t\tE6F1D4BF1D38F29D00E8665B /* libbz2.tbd */,\n\t\t\t\tE6F1D4BD1D38F29800E8665B /* libz.tbd */,\n\t\t\t\tE612EAE417F7E0F800BEE660 /* MediaPlayer.framework */,\n\t\t\t\tE67323B01B69ECF500CB9036 /* MobileCoreServices.framework */,\n\t\t\t\tE63FC2B317F172E9003551EB /* OpenGLES.framework */,\n\t\t\t\tE63FC2B717F17362003551EB /* QuartzCore.framework */,\n\t\t\t\tE6903EFF17EAF70200CFD954 /* UIKit.framework */,\n\t\t\t\t45D57D621A53233800BDD389 /* VideoToolbox.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE6903F0517EAF70200CFD954 /* IJKMediaDemo */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE6903F0E17EAF70200CFD954 /* IJKAppDelegate.h */,\n\t\t\t\tE6903F0F17EAF70200CFD954 /* IJKAppDelegate.m */,\n\t\t\t\tE6A9B55C17EDA6AC00A1A500 /* View Controllers */,\n\t\t\t\tE63FC27717F032D9003551EB /* Misc */,\n\t\t\t\tE6903F0617EAF70200CFD954 /* Supporting Files */,\n\t\t\t);\n\t\t\tpath = IJKMediaDemo;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE6903F0617EAF70200CFD954 /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE6903F0717EAF70200CFD954 /* IJKMediaDemo-Info.plist */,\n\t\t\t\tE6903F0817EAF70200CFD954 /* InfoPlist.strings */,\n\t\t\t\tE6903F0B17EAF70200CFD954 /* main.m */,\n\t\t\t\tE6903F1117EAF70200CFD954 /* Default.png */,\n\t\t\t\tE6903F1317EAF70200CFD954 /* Default@2x.png */,\n\t\t\t\tE6903F1517EAF70200CFD954 /* Default-568h@2x.png */,\n\t\t\t\tE6166C9B17EDA4A20006B956 /* IJKMediaDemo-Prefix.pch */,\n\t\t\t\t55E809E51B145B55003E98A5 /* LaunchScreen.xib */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE6A9B55C17EDA6AC00A1A500 /* View Controllers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t55E809E71B145BC2003E98A5 /* IJKDemoInputURLViewController.h */,\n\t\t\t\t55E809E81B145BC2003E98A5 /* IJKDemoInputURLViewController.m */,\n\t\t\t\t55E809E91B145BC2003E98A5 /* IJKDemoInputURLViewController.xib */,\n\t\t\t\t55E809F71B15A1DB003E98A5 /* IJKDemoLocalFolderViewController.h */,\n\t\t\t\t55E809F81B15A1DB003E98A5 /* IJKDemoLocalFolderViewController.m */,\n\t\t\t\t55E809E01B143C47003E98A5 /* IJKDemoMainViewController.h */,\n\t\t\t\t55E809E11B143C47003E98A5 /* IJKDemoMainViewController.m */,\n\t\t\t\t55E809E31B143C85003E98A5 /* IJKDemoMainViewController.xib */,\n\t\t\t\tE6F524E81B183A0700B69DC7 /* IJKDemoSampleViewController.h */,\n\t\t\t\tE6F524E91B183A0700B69DC7 /* IJKDemoSampleViewController.m */,\n\t\t\t\tE6F524EA1B183A0700B69DC7 /* IJKDemoSampleViewController.xib */,\n\t\t\t\tE66F8DC917EEDD8B00354D80 /* IJKMediaControl.h */,\n\t\t\t\tE66F8DCA17EEDD8B00354D80 /* IJKMediaControl.m */,\n\t\t\t\tE6A9B56117EDA72C00A1A500 /* IJKMoviePlayerViewController.h */,\n\t\t\t\tE6A9B56217EDA72C00A1A500 /* IJKMoviePlayerViewController.m */,\n\t\t\t\tE6A9B56317EDA72C00A1A500 /* IJKMoviePlayerViewController.xib */,\n\t\t\t\t55E809EC1B146C1E003E98A5 /* IJKQRCodeScanViewController.h */,\n\t\t\t\t55E809ED1B146C1E003E98A5 /* IJKQRCodeScanViewController.m */,\n\t\t\t\t55E809F21B146DE8003E98A5 /* IJKQRCodeScanViewController.xib */,\n\t\t\t);\n\t\t\tname = \"View Controllers\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE6D74F2A18A5F94B00165BFD /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE654EAD71B6B28B100B0F2D0 /* IJKMediaFramework.framework */,\n\t\t\t\tE654EAD91B6B28B100B0F2D0 /* IJKMediaFrameworkTests.xctest */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\tE6903EFB17EAF70200CFD954 /* IJKMediaDemo */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = E6903F1917EAF70200CFD954 /* Build configuration list for PBXNativeTarget \"IJKMediaDemo\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tE6903EF817EAF70200CFD954 /* Sources */,\n\t\t\t\tE6903EF917EAF70200CFD954 /* Frameworks */,\n\t\t\t\tE6903EFA17EAF70200CFD954 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\tE654EAEF1B6B2A1500B0F2D0 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = IJKMediaDemo;\n\t\t\tproductName = IJKMediaDemo;\n\t\t\tproductReference = E6903EFC17EAF70200CFD954 /* IJKMediaDemo.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tE6903EF417EAF70200CFD954 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tCLASSPREFIX = IJK;\n\t\t\t\tLastUpgradeCheck = 0700;\n\t\t\t\tORGANIZATIONNAME = bilibili;\n\t\t\t};\n\t\t\tbuildConfigurationList = E6903EF717EAF70200CFD954 /* Build configuration list for PBXProject \"IJKMediaDemo\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = English;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t);\n\t\t\tmainGroup = E6903EF317EAF70200CFD954;\n\t\t\tproductRefGroup = E6903EFD17EAF70200CFD954 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectReferences = (\n\t\t\t\t{\n\t\t\t\t\tProductGroup = E6D74F2A18A5F94B00165BFD /* Products */;\n\t\t\t\t\tProjectRef = E6D74F2918A5F94B00165BFD /* IJKMediaPlayer.xcodeproj */;\n\t\t\t\t},\n\t\t\t);\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tE6903EFB17EAF70200CFD954 /* IJKMediaDemo */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXReferenceProxy section */\n\t\tE654EAD71B6B28B100B0F2D0 /* IJKMediaFramework.framework */ = {\n\t\t\tisa = PBXReferenceProxy;\n\t\t\tfileType = wrapper.framework;\n\t\t\tpath = IJKMediaFramework.framework;\n\t\t\tremoteRef = E654EAD61B6B28B100B0F2D0 /* PBXContainerItemProxy */;\n\t\t\tsourceTree = BUILT_PRODUCTS_DIR;\n\t\t};\n\t\tE654EAD91B6B28B100B0F2D0 /* IJKMediaFrameworkTests.xctest */ = {\n\t\t\tisa = PBXReferenceProxy;\n\t\t\tfileType = wrapper.cfbundle;\n\t\t\tpath = IJKMediaFrameworkTests.xctest;\n\t\t\tremoteRef = E654EAD81B6B28B100B0F2D0 /* PBXContainerItemProxy */;\n\t\t\tsourceTree = BUILT_PRODUCTS_DIR;\n\t\t};\n/* End PBXReferenceProxy section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tE6903EFA17EAF70200CFD954 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tE6903F0A17EAF70200CFD954 /* InfoPlist.strings in Resources */,\n\t\t\t\tE67323AC1B69E76100CB9036 /* MoviePlayerImages.xcassets in Resources */,\n\t\t\t\tE6903F1217EAF70200CFD954 /* Default.png in Resources */,\n\t\t\t\tE6903F1417EAF70200CFD954 /* Default@2x.png in Resources */,\n\t\t\t\tE6903F1617EAF70200CFD954 /* Default-568h@2x.png in Resources */,\n\t\t\t\tE67323A71B69E6F800CB9036 /* AppIcons.xcassets in Resources */,\n\t\t\t\tE6166C9C17EDA4A20006B956 /* IJKMediaDemo-Prefix.pch in Resources */,\n\t\t\t\tE6A9B56517EDA72C00A1A500 /* IJKMoviePlayerViewController.xib in Resources */,\n\t\t\t\tE6F524EC1B183A0700B69DC7 /* IJKDemoSampleViewController.xib in Resources */,\n\t\t\t\t55E809E41B143C85003E98A5 /* IJKDemoMainViewController.xib in Resources */,\n\t\t\t\t55E809F31B146DE8003E98A5 /* IJKQRCodeScanViewController.xib in Resources */,\n\t\t\t\t55E809E61B145B55003E98A5 /* LaunchScreen.xib in Resources */,\n\t\t\t\tE67323A81B69E6F800CB9036 /* LaunchImages.xcassets in Resources */,\n\t\t\t\t55E809EB1B145BC2003E98A5 /* IJKDemoInputURLViewController.xib in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tE6903EF817EAF70200CFD954 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t55E809F91B15A1DB003E98A5 /* IJKDemoLocalFolderViewController.m in Sources */,\n\t\t\t\t55E809F61B1480BC003E98A5 /* IJKDemoHistory.m in Sources */,\n\t\t\t\tE6903F0C17EAF70200CFD954 /* main.m in Sources */,\n\t\t\t\t55E809E21B143C47003E98A5 /* IJKDemoMainViewController.m in Sources */,\n\t\t\t\tE6903F1017EAF70200CFD954 /* IJKAppDelegate.m in Sources */,\n\t\t\t\tE6F524EB1B183A0700B69DC7 /* IJKDemoSampleViewController.m in Sources */,\n\t\t\t\tE6A9B56417EDA72C00A1A500 /* IJKMoviePlayerViewController.m in Sources */,\n\t\t\t\t55E809F11B146C80003E98A5 /* Barcode.m in Sources */,\n\t\t\t\tE66F8DCB17EEDD8B00354D80 /* IJKMediaControl.m in Sources */,\n\t\t\t\t55E809EA1B145BC2003E98A5 /* IJKDemoInputURLViewController.m in Sources */,\n\t\t\t\t55E809EE1B146C1E003E98A5 /* IJKQRCodeScanViewController.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\tE654EAEF1B6B2A1500B0F2D0 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\tname = IJKMediaFramework;\n\t\t\ttargetProxy = E654EAEE1B6B2A1500B0F2D0 /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin PBXVariantGroup section */\n\t\tE6903F0817EAF70200CFD954 /* InfoPlist.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tE6903F0917EAF70200CFD954 /* en */,\n\t\t\t);\n\t\t\tname = InfoPlist.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\tE6903F1717EAF70200CFD954 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_SYMBOLS_PRIVATE_EXTERN = NO;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 7.0;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tE6903F1817EAF70200CFD954 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 7.0;\n\t\t\t\tOTHER_CFLAGS = \"-DNS_BLOCK_ASSERTIONS=1\";\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tE6903F1A17EAF70200CFD954 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tGCC_PRECOMPILE_PREFIX_HEADER = YES;\n\t\t\t\tGCC_PREFIX_HEADER = \"IJKMediaDemo/IJKMediaDemo-Prefix.pch\";\n\t\t\t\tINFOPLIST_FILE = \"IJKMediaDemo/IJKMediaDemo-Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 7.0;\n\t\t\t\tLIBRARY_SEARCH_PATHS = \"$(inherited)\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"tv.danmaku.${PRODUCT_NAME:rfc1034identifier}\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE = \"\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = 1;\n\t\t\t\tWRAPPER_EXTENSION = app;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tE6903F1B17EAF70200CFD954 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tGCC_PRECOMPILE_PREFIX_HEADER = YES;\n\t\t\t\tGCC_PREFIX_HEADER = \"IJKMediaDemo/IJKMediaDemo-Prefix.pch\";\n\t\t\t\tINFOPLIST_FILE = \"IJKMediaDemo/IJKMediaDemo-Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 7.0;\n\t\t\t\tLIBRARY_SEARCH_PATHS = \"$(inherited)\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"tv.danmaku.${PRODUCT_NAME:rfc1034identifier}\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE = \"\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = 1;\n\t\t\t\tWRAPPER_EXTENSION = app;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tE6903EF717EAF70200CFD954 /* Build configuration list for PBXProject \"IJKMediaDemo\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tE6903F1717EAF70200CFD954 /* Debug */,\n\t\t\t\tE6903F1817EAF70200CFD954 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tE6903F1917EAF70200CFD954 /* Build configuration list for PBXNativeTarget \"IJKMediaDemo\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tE6903F1A17EAF70200CFD954 /* Debug */,\n\t\t\t\tE6903F1B17EAF70200CFD954 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = E6903EF417EAF70200CFD954 /* Project object */;\n}\n"
  },
  {
    "path": "ios/IJKMediaDemo/IJKMediaDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:IJKMediaDemo.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "ios/IJKMediaDemo/XCAssets/AppIcons.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"icset_iphone_iosu_29pt.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"icset_iphone_iosu_29pt@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"icset_iphone_iosu_29pt@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"icset_iphone_ios7_40pt@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"icset_iphone_ios7_40pt@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"57x57\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"icapp_iphone_ios5_57pt.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"57x57\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"icapp_iphone_ios5_57pt@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"60x60\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"icapp_iphone_ios7_60pt@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"60x60\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"icapp_iphone_ios7_60pt@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"icset_ipad_iosu_29pt.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"icset_ipad_iosu_29pt@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"icset_ipad_ios7_40pt.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"icset_ipad_ios7_40pt@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"50x50\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"icset_ipad_ios5_50pt.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"50x50\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"icset_ipad_ios5_50pt@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"72x72\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"icapp_ipad_ios5_72pt.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"72x72\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"icapp_ipad_ios5_72pt@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"76x76\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"icapp_ipad_ios7_76pt.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"76x76\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"icapp_ipad_ios7_76pt@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"83.5x83.5\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/IJKMediaDemo/XCAssets/LaunchImages.xcassets/LaunchImage.launchimage/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"iphone_ios7_640_960.png\",\n      \"extent\" : \"full-screen\",\n      \"minimum-system-version\" : \"7.0\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"extent\" : \"full-screen\",\n      \"idiom\" : \"iphone\",\n      \"subtype\" : \"retina4\",\n      \"filename\" : \"iphone_ios7_640_1136.png\",\n      \"minimum-system-version\" : \"7.0\",\n      \"orientation\" : \"portrait\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"iphone_ios5_320_480.png\",\n      \"extent\" : \"full-screen\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"iphone_ios5_640_960.png\",\n      \"extent\" : \"full-screen\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"iphone_ios5_640_1136.png\",\n      \"extent\" : \"full-screen\",\n      \"subtype\" : \"retina4\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/IJKMediaDemo/XCAssets/MoviePlayerImages.xcassets/MoviePlayer/btn_player_back_highlighted.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"btn_player_back_highlighted.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"btn_player_back_highlighted@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/IJKMediaDemo/XCAssets/MoviePlayerImages.xcassets/MoviePlayer/btn_player_pause.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"btn_player_pause.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"btn_player_pause@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/IJKMediaDemo/XCAssets/MoviePlayerImages.xcassets/MoviePlayer/btn_player_play.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"btn_player_play.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"btn_player_play@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/IJKMediaDemo/XCAssets/MoviePlayerImages.xcassets/MoviePlayer/player_bottom_control_bg.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"player_bottom_control_bg.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"player_bottom_control_bg@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/IJKMediaDemo/XCAssets/MoviePlayerImages.xcassets/MoviePlayer/player_top_control_bg.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"player_top_control_bg.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"player_top_control_bg@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaFramework/IJKMediaFramework.h",
    "content": "/*\n * IJKMediaFramework.h\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import <UIKit/UIKit.h>\n\n//! Project version number for IJKMediaFramework.\nFOUNDATION_EXPORT double IJKMediaFrameworkVersionNumber;\n\n//! Project version string for IJKMediaFramework.\nFOUNDATION_EXPORT const unsigned char IJKMediaFrameworkVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <IJKMediaFrameworkWithSSL/PublicHeader.h>\n#import <IJKMediaFramework/IJKMediaPlayback.h>\n#import <IJKMediaFramework/IJKMPMoviePlayerController.h>\n#import <IJKMediaFramework/IJKFFOptions.h>\n#import <IJKMediaFramework/IJKFFMoviePlayerController.h>\n#import <IJKMediaFramework/IJKAVMoviePlayerController.h>\n#import <IJKMediaFramework/IJKMediaModule.h>\n#import <IJKMediaFramework/IJKMediaPlayer.h>\n#import <IJKMediaFramework/IJKNotificationManager.h>\n#import <IJKMediaFramework/IJKKVOController.h>\n#import <IJKMediaFramework/IJKSDLGLViewProtocol.h>\n\n// backward compatible for old names\n#define IJKMediaPlaybackIsPreparedToPlayDidChangeNotification IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification\n#define IJKMoviePlayerLoadStateDidChangeNotification IJKMPMoviePlayerLoadStateDidChangeNotification\n#define IJKMoviePlayerPlaybackDidFinishNotification IJKMPMoviePlayerPlaybackDidFinishNotification\n#define IJKMoviePlayerPlaybackDidFinishReasonUserInfoKey IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey\n#define IJKMoviePlayerPlaybackStateDidChangeNotification IJKMPMoviePlayerPlaybackStateDidChangeNotification\n#define IJKMoviePlayerIsAirPlayVideoActiveDidChangeNotification IJKMPMoviePlayerIsAirPlayVideoActiveDidChangeNotification\n#define IJKMoviePlayerVideoDecoderOpenNotification IJKMPMoviePlayerVideoDecoderOpenNotification\n#define IJKMoviePlayerFirstVideoFrameRenderedNotification IJKMPMoviePlayerFirstVideoFrameRenderedNotification\n#define IJKMoviePlayerFirstAudioFrameRenderedNotification IJKMPMoviePlayerFirstAudioFrameRenderedNotification\n#define IJKMoviePlayerFirstAudioFrameDecodedNotification IJKMPMoviePlayerFirstAudioFrameDecodedNotification\n#define IJKMoviePlayerFirstVideoFrameDecodedNotification IJKMPMoviePlayerFirstVideoFrameDecodedNotification\n#define IJKMoviePlayerOpenInputNotification IJKMPMoviePlayerOpenInputNotification\n#define IJKMoviePlayerFindStreamInfoNotification IJKMPMoviePlayerFindStreamInfoNotification\n#define IJKMoviePlayerComponentOpenNotification IJKMPMoviePlayerComponentOpenNotification\n\n#define IJKMPMoviePlayerAccurateSeekCompleteNotification IJKMPMoviePlayerAccurateSeekCompleteNotification\n#define IJKMoviePlayerSeekAudioStartNotification IJKMPMoviePlayerSeekAudioStartNotification\n#define IJKMoviePlayerSeekVideoStartNotification IJKMPMoviePlayerSeekVideoStartNotification\n\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaFramework/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>FMWK</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>NSPrincipalClass</key>\n\t<string></string>\n</dict>\n</plist>\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaFrameworkTests/IJKMediaFrameworkTests.m",
    "content": "//\n//  IJKMediaFrameworkTests.m\n//  IJKMediaFrameworkTests\n//\n//  Created by Zhang Rui on 15/7/31.\n//  Copyright (c) 2015年 bilibili. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n#import <XCTest/XCTest.h>\n\n@interface IJKMediaFrameworkTests : XCTestCase\n\n@end\n\n@implementation IJKMediaFrameworkTests\n\n- (void)setUp {\n    [super setUp];\n    // Put setup code here. This method is called before the invocation of each test method in the class.\n}\n\n- (void)tearDown {\n    // Put teardown code here. This method is called after the invocation of each test method in the class.\n    [super tearDown];\n}\n\n- (void)testExample {\n    // This is an example of a functional test case.\n    XCTAssert(YES, @\"Pass\");\n}\n\n- (void)testPerformanceExample {\n    // This is an example of a performance test case.\n    [self measureBlock:^{\n        // Put the code you want to measure the time of here.\n    }];\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaFrameworkTests/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaFrameworkWithSSL/IJKMediaFrameworkWithSSL.h",
    "content": "//\n//  IJKMediaFrameworkWithSSL.h\n//  IJKMediaFrameworkWithSSL\n//\n//  Created by zhangxinzheng on 27/02/2017.\n//  Copyright © 2017 bilibili. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n//! Project version number for IJKMediaFrameworkWithSSL.\nFOUNDATION_EXPORT double IJKMediaFrameworkWithSSLVersionNumber;\n\n//! Project version string for IJKMediaFrameworkWithSSL.\nFOUNDATION_EXPORT const unsigned char IJKMediaFrameworkWithSSLVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <IJKMediaFrameworkWithSSL/PublicHeader.h>\n\n#import <IJKMediaFrameworkWithSSL/IJKMediaPlayback.h>\n#import <IJKMediaFrameworkWithSSL/IJKMPMoviePlayerController.h>\n#import <IJKMediaFrameworkWithSSL/IJKFFOptions.h>\n#import <IJKMediaFrameworkWithSSL/IJKFFMoviePlayerController.h>\n#import <IJKMediaFrameworkWithSSL/IJKAVMoviePlayerController.h>\n#import <IJKMediaFrameworkWithSSL/IJKMediaModule.h>\n#import <IJKMediaFrameworkWithSSL/IJKMediaPlayer.h>\n#import <IJKMediaFrameworkWithSSL/IJKNotificationManager.h>\n#import <IJKMediaFrameworkWithSSL/IJKKVOController.h>\n\n// backward compatible for old names\n#define IJKMediaPlaybackIsPreparedToPlayDidChangeNotification IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification\n#define IJKMoviePlayerLoadStateDidChangeNotification IJKMPMoviePlayerLoadStateDidChangeNotification\n#define IJKMoviePlayerPlaybackDidFinishNotification IJKMPMoviePlayerPlaybackDidFinishNotification\n#define IJKMoviePlayerPlaybackDidFinishReasonUserInfoKey IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey\n#define IJKMoviePlayerPlaybackStateDidChangeNotification IJKMPMoviePlayerPlaybackStateDidChangeNotification\n#define IJKMoviePlayerIsAirPlayVideoActiveDidChangeNotification IJKMPMoviePlayerIsAirPlayVideoActiveDidChangeNotification\n#define IJKMoviePlayerVideoDecoderOpenNotification IJKMPMoviePlayerVideoDecoderOpenNotification\n#define IJKMoviePlayerFirstVideoFrameRenderedNotification IJKMPMoviePlayerFirstVideoFrameRenderedNotification\n#define IJKMoviePlayerFirstAudioFrameRenderedNotification IJKMPMoviePlayerFirstAudioFrameRenderedNotification\n#define IJKMoviePlayerFirstAudioFrameDecodedNotification IJKMPMoviePlayerFirstAudioFrameDecodedNotification\n#define IJKMoviePlayerFirstVideoFrameDecodedNotification IJKMPMoviePlayerFirstVideoFrameDecodedNotification\n#define IJKMoviePlayerOpenInputNotification IJKMPMoviePlayerOpenInputNotification\n#define IJKMoviePlayerFindStreamInfoNotification IJKMPMoviePlayerFindStreamInfoNotification\n#define IJKMoviePlayerComponentOpenNotification IJKMPMoviePlayerComponentOpenNotification\n#define IJKMPMoviePlayerAccurateSeekCompleteNotification IJKMPMoviePlayerAccurateSeekCompleteNotification\n#define IJKMoviePlayerSeekAudioStartNotification IJKMPMoviePlayerSeekAudioStartNotification\n#define IJKMoviePlayerSeekVideoStartNotification IJKMPMoviePlayerSeekVideoStartNotification\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaFrameworkWithSSL.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>FMWK</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>NSPrincipalClass</key>\n\t<string></string>\n</dict>\n</plist>\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKAVMoviePlayerController.h",
    "content": "/*\n * IJKAVMoviePlayerController.h\n *\n * Copyright (c) 2014 Bilibili\n * Copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n/*\n File: AVPlayerDemoPlaybackViewController.h\n Abstract: UIViewController managing a playback view, thumbnail view, and associated playback UI.\n Version: 1.3\n\n Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple\n Inc. (\"Apple\") in consideration of your agreement to the following\n terms, and your use, installation, modification or redistribution of\n this Apple software constitutes acceptance of these terms.  If you do\n not agree with these terms, please do not use, install, modify or\n redistribute this Apple software.\n\n In consideration of your agreement to abide by the following terms, and\n subject to these terms, Apple grants you a personal, non-exclusive\n license, under Apple's copyrights in this original Apple software (the\n \"Apple Software\"), to use, reproduce, modify and redistribute the Apple\n Software, with or without modifications, in source and/or binary forms;\n provided that if you redistribute the Apple Software in its entirety and\n without modifications, you must retain this notice and the following\n text and disclaimers in all such redistributions of the Apple Software.\n Neither the name, trademarks, service marks or logos of Apple Inc. may\n be used to endorse or promote products derived from the Apple Software\n without specific prior written permission from Apple.  Except as\n expressly stated in this notice, no other rights or licenses, express or\n implied, are granted by Apple herein, including but not limited to any\n patent rights that may be infringed by your derivative works or by other\n works in which the Apple Software may be incorporated.\n\n The Apple Software is provided by Apple on an \"AS IS\" basis.  APPLE\n MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION\n THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS\n FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND\n OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.\n\n IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL\n OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,\n MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED\n AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),\n STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE\n POSSIBILITY OF SUCH DAMAGE.\n\n Copyright (C) 2014 Apple Inc. All Rights Reserved.\n\n */\n\n#import \"IJKMediaPlayback.h\"\n\n@interface IJKAVMoviePlayerController : NSObject <IJKMediaPlayback>\n\n- (id)initWithContentURL:(NSURL *)aUrl;\n- (id)initWithContentURLString:(NSString *)aUrl;\n+ (id)getInstance:(NSString *)aUrl;\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKAVMoviePlayerController.m",
    "content": "/*\n * IJKAVMoviePlayerController.m\n *\n * Copyright (c) 2014 Bilibili\n * Copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n/*\n File: AVPlayerDemoPlaybackViewController.m\n Abstract: UIViewController managing a playback view, thumbnail view, and associated playback UI.\n Version: 1.3\n \n Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple\n Inc. (\"Apple\") in consideration of your agreement to the following\n terms, and your use, installation, modification or redistribution of\n this Apple software constitutes acceptance of these terms.  If you do\n not agree with these terms, please do not use, install, modify or\n redistribute this Apple software.\n \n In consideration of your agreement to abide by the following terms, and\n subject to these terms, Apple grants you a personal, non-exclusive\n license, under Apple's copyrights in this original Apple software (the\n \"Apple Software\"), to use, reproduce, modify and redistribute the Apple\n Software, with or without modifications, in source and/or binary forms;\n provided that if you redistribute the Apple Software in its entirety and\n without modifications, you must retain this notice and the following\n text and disclaimers in all such redistributions of the Apple Software.\n Neither the name, trademarks, service marks or logos of Apple Inc. may\n be used to endorse or promote products derived from the Apple Software\n without specific prior written permission from Apple.  Except as\n expressly stated in this notice, no other rights or licenses, express or\n implied, are granted by Apple herein, including but not limited to any\n patent rights that may be infringed by your derivative works or by other\n works in which the Apple Software may be incorporated.\n \n The Apple Software is provided by Apple on an \"AS IS\" basis.  APPLE\n MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION\n THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS\n FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND\n OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.\n \n IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL\n OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,\n MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED\n AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),\n STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE\n POSSIBILITY OF SUCH DAMAGE.\n \n Copyright (C) 2014 Apple Inc. All Rights Reserved.\n \n */\n\n#import \"IJKAVMoviePlayerController.h\"\n#import \"IJKAVPlayerLayerView.h\"\n#import \"IJKAudioKit.h\"\n#import \"IJKMediaModule.h\"\n#import \"IJKMediaUtils.h\"\n#import \"IJKKVOController.h\"\n#import \"IJKNotificationManager.h\"\n#include \"ijksdl/ios/ijksdl_ios.h\"\n\n// avoid float equal compare\ninline static bool isFloatZero(float value)\n{\n    return fabsf(value) <= 0.00001f;\n}\n\n// resume play after stall\nstatic const float kMaxHighWaterMarkMilli   = 15 * 1000;\n\nstatic NSString *kErrorDomain = @\"IJKAVMoviePlayer\";\nstatic const NSInteger kEC_CurrentPlayerItemIsNil   = 5001;\nstatic const NSInteger kEC_PlayerItemCancelled      = 5002;\n\nstatic void *KVO_AVPlayer_rate          = &KVO_AVPlayer_rate;\nstatic void *KVO_AVPlayer_currentItem   = &KVO_AVPlayer_currentItem;\nstatic void *KVO_AVPlayer_airplay   = &KVO_AVPlayer_airplay;\n\nstatic void *KVO_AVPlayerItem_state                     = &KVO_AVPlayerItem_state;\nstatic void *KVO_AVPlayerItem_loadedTimeRanges          = &KVO_AVPlayerItem_loadedTimeRanges;\nstatic void *KVO_AVPlayerItem_playbackLikelyToKeepUp    = &KVO_AVPlayerItem_playbackLikelyToKeepUp;\nstatic void *KVO_AVPlayerItem_playbackBufferFull        = &KVO_AVPlayerItem_playbackBufferFull;\nstatic void *KVO_AVPlayerItem_playbackBufferEmpty       = &KVO_AVPlayerItem_playbackBufferEmpty;\n\n@interface IJKAVMoviePlayerController()\n\n// Redeclare property\n@property(nonatomic, readwrite) UIView *view;\n\n@property(nonatomic, readwrite) NSTimeInterval duration;\n@property(nonatomic, readwrite) NSTimeInterval playableDuration;\n@property(nonatomic, readwrite) NSInteger bufferingProgress;\n\n@property(nonatomic, readwrite)  BOOL isPreparedToPlay;\n\n@end\n\n@implementation IJKAVMoviePlayerController {\n    NSURL           *_playUrl;\n    AVURLAsset      *_playAsset;\n    AVPlayerItem    *_playerItem;\n    AVPlayer        *_player;\n    IJKAVPlayerLayerView * _avView;\n    \n    IJKKVOController *_playerKVO;\n    IJKKVOController *_playerItemKVO;\n    \n    id _timeObserver;\n    dispatch_once_t _readyToPlayToken;\n    // while AVPlayer is prerolling, it could resume itself.\n    // foring start could\n    BOOL _isPrerolling;\n\n    NSTimeInterval _seekingTime;\n    BOOL _isSeeking;\n    BOOL _isError;\n    BOOL _isCompleted;\n    BOOL _isShutdown;\n    \n    BOOL _pauseInBackground;\n    \n    BOOL _playbackLikelyToKeeyUp;\n    BOOL _playbackBufferEmpty;\n    BOOL _playbackBufferFull;\n    \n    BOOL _playingBeforeInterruption;\n\n    IJKNotificationManager *_notificationManager;\n\n    float _playbackRate;\n    float _playbackVolume;\n}\n\n@synthesize view                        = _view;\n@synthesize currentPlaybackTime         = _currentPlaybackTime;\n@synthesize duration                    = _duration;\n@synthesize playableDuration            = _playableDuration;\n@synthesize bufferingProgress           = _bufferingProgress;\n\n@synthesize numberOfBytesTransferred    = _numberOfBytesTransferred;\n\n@synthesize playbackState               = _playbackState;\n@synthesize loadState                   = _loadState;\n\n@synthesize scalingMode                 = _scalingMode;\n@synthesize shouldAutoplay              = _shouldAutoplay;\n@synthesize isDanmakuMediaAirPlay       = _isDanmakuMediaAirPlay;\n\nstatic IJKAVMoviePlayerController* instance;\n\n- (id)initWithContentURL:(NSURL *)aUrl\n{\n    self = [super init];\n    if (self != nil) {\n        self.scalingMode = IJKMPMovieScalingModeAspectFit;\n        self.shouldAutoplay = NO;\n\n        _playUrl = aUrl;\n\n        _avView = [[IJKAVPlayerLayerView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];\n        self.view = _avView;\n\n        // TODO:\n        [[IJKAudioKit sharedInstance] setupAudioSession];\n\n        _isPrerolling           = NO;\n\n        _isSeeking              = NO;\n        _isError                = NO;\n        _isCompleted            = NO;\n        self.bufferingProgress  = 0;\n\n        _playbackLikelyToKeeyUp = NO;\n        _playbackBufferEmpty    = YES;\n        _playbackBufferFull     = NO;\n\n        _playbackRate           = 1.0f;\n        _playbackVolume         = 1.0f;\n        // init extra\n        [self setScreenOn:YES];\n\n        _notificationManager = [[IJKNotificationManager alloc] init];\n    }\n    return self;\n}\n\n+ (id)getInstance:(NSString *)aUrl\n{\n    if (instance == nil) {\n        instance = [[IJKAVMoviePlayerController alloc] initWithContentURLString:aUrl];\n    } else {\n        instance = [instance initWithContentURLString:aUrl];\n    }\n    return instance;\n}\n\n- (id)initWithContentURLString:(NSString *)aUrl\n{\n    NSURL *url;\n    if (aUrl == nil) {\n        aUrl = @\"\";\n    }\n    if ([aUrl rangeOfString:@\"/\"].location == 0) {\n        //本地\n        url = [NSURL fileURLWithPath:aUrl];\n    }\n    else {\n        url = [NSURL URLWithString:aUrl];\n    }\n    self = [self initWithContentURL:url];\n    if (self != nil) {\n        \n    }\n    return self;\n}\n\n- (void)setScreenOn: (BOOL)on\n{\n    [IJKMediaModule sharedModule].mediaModuleIdleTimerDisabled = on;\n}\n\n- (void)dealloc\n{\n    [self shutdown];\n}\n\n- (void)prepareToPlay\n{\n    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:_playUrl options:nil];\n    NSArray *requestedKeys = @[@\"playable\"];\n    \n    _playAsset = asset;\n    [asset loadValuesAsynchronouslyForKeys:requestedKeys\n                         completionHandler:^{\n                             dispatch_async( dispatch_get_main_queue(), ^{\n                                 [self didPrepareToPlayAsset:asset withKeys:requestedKeys];\n                                 [[NSNotificationCenter defaultCenter]\n                                  postNotificationName:IJKMPMovieNaturalSizeAvailableNotification\n                                  object:self];\n\n                                 [self setPlaybackVolume:_playbackVolume];\n                             });\n                         }];\n}\n\n- (void)play\n{\n    if (_isCompleted)\n    {\n        _isCompleted = NO;\n        [_player seekToTime:kCMTimeZero];\n    }\n    \n    [_player play];\n}\n\n- (void)pause\n{\n    _isPrerolling = NO;\n    [_player pause];\n}\n\n- (void)stop\n{\n    [_player pause];\n    [self setScreenOn:NO];\n    _isCompleted = YES;\n}\n\n- (BOOL)isPlaying\n{\n    if (!isFloatZero(_player.rate)) {\n        return YES;\n    } else {\n        if (_isPrerolling) {\n            return YES;\n        } else {\n            return NO;\n        }\n    }\n}\n\n- (void)shutdown\n{\n    _isShutdown = YES;\n    [self stop];\n    \n    if (_playerItem != nil) {\n        [_playerItem cancelPendingSeeks];\n    }\n    \n    [_playerItemKVO safelyRemoveAllObservers];\n    [[NSNotificationCenter defaultCenter] removeObserver:self\n                                                    name:nil\n                                                  object:_playerItem];\n    \n    [_playerKVO safelyRemoveAllObservers];\n    \n    [self unregisterApplicationObservers];\n    \n    if (_avView != nil) {\n        [_avView setPlayer:nil];\n    }\n    \n    self.view = nil;\n}\n\n- (UIImage *)thumbnailImageAtCurrentTime\n{\n    AVAssetImageGenerator *imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:_playAsset];\n    CMTime expectedTime = _playerItem.currentTime;\n    CGImageRef cgImage = NULL;\n    \n    imageGenerator.requestedTimeToleranceBefore = kCMTimeZero;\n    imageGenerator.requestedTimeToleranceAfter = kCMTimeZero;\n    cgImage = [imageGenerator copyCGImageAtTime:expectedTime actualTime:NULL error:NULL];\n    \n    if (!cgImage) {\n        imageGenerator.requestedTimeToleranceBefore = kCMTimePositiveInfinity;\n        imageGenerator.requestedTimeToleranceAfter = kCMTimePositiveInfinity;\n        cgImage = [imageGenerator copyCGImageAtTime:expectedTime actualTime:NULL error:NULL];\n    }\n    \n    UIImage *image = [UIImage imageWithCGImage:cgImage];\n    return image;\n}\n\n- (void)setCurrentPlaybackTime:(NSTimeInterval)aCurrentPlaybackTime\n{\n    if (!_player)\n        return;\n\n    _seekingTime = aCurrentPlaybackTime;\n    _isSeeking = YES;\n    _bufferingProgress = 0;\n    [self didPlaybackStateChange];\n    [self didLoadStateChange];\n    if (_isPrerolling) {\n        [_player pause];\n    }\n\n    [_player seekToTime:CMTimeMakeWithSeconds(aCurrentPlaybackTime, NSEC_PER_SEC)\n      completionHandler:^(BOOL finished) {\n          dispatch_async(dispatch_get_main_queue(), ^{\n              _isSeeking = NO;\n              if (_isPrerolling) {\n                  [_player play];\n              }\n              [self didPlaybackStateChange];\n              [self didLoadStateChange];\n          });\n      }];\n}\n\n- (NSTimeInterval)currentPlaybackTime\n{\n    if (!_player)\n        return 0.0f;\n\n    if (_isSeeking)\n        return _seekingTime;\n\n    return CMTimeGetSeconds([_player currentTime]);\n}\n\n-(int64_t)numberOfBytesTransferred\n{\n#if 0\n    if (_player == nil)\n        return 0;\n\n    AVPlayerItem *playerItem = [_player currentItem];\n    if (playerItem == nil)\n        return 0;\n\n    NSArray *events = playerItem.accessLog.events;\n    if (events != nil && events.count > 0) {\n        MPMovieAccessLogEvent *currentEvent = [events objectAtIndex:events.count -1];\n        return currentEvent.numberOfBytesTransferred;\n    }\n#endif\n    return 0;\n}\n\n- (IJKMPMoviePlaybackState)playbackState\n{\n    if (!_player)\n        return IJKMPMoviePlaybackStateStopped;\n    \n    IJKMPMoviePlaybackState mpState = IJKMPMoviePlaybackStateStopped;\n    if (_isCompleted) {\n        mpState = IJKMPMoviePlaybackStateStopped;\n    } else if (_isSeeking) {\n        mpState = IJKMPMoviePlaybackStateSeekingForward;\n    } else if ([self isPlaying]) {\n        mpState = IJKMPMoviePlaybackStatePlaying;\n    } else {\n        mpState = IJKMPMoviePlaybackStatePaused;\n    }\n    return mpState;\n}\n\n- (IJKMPMovieLoadState)loadState\n{\n    if (_player == nil)\n        return IJKMPMovieLoadStateUnknown;\n    \n    if (_isSeeking)\n        return IJKMPMovieLoadStateStalled;\n    \n    AVPlayerItem *playerItem = [_player currentItem];\n    if (playerItem == nil)\n        return IJKMPMovieLoadStateUnknown;\n    \n    if (_player != nil && !isFloatZero(_player.rate)) {\n        // NSLog(@\"loadState: playing\");\n        return IJKMPMovieLoadStatePlayable | IJKMPMovieLoadStatePlaythroughOK;\n    } else if ([playerItem isPlaybackBufferFull]) {\n        // NSLog(@\"loadState: isPlaybackBufferFull\");\n        return IJKMPMovieLoadStatePlayable | IJKMPMovieLoadStatePlaythroughOK;\n    } else if ([playerItem isPlaybackLikelyToKeepUp]) {\n        // NSLog(@\"loadState: isPlaybackLikelyToKeepUp\");\n        return IJKMPMovieLoadStatePlayable | IJKMPMovieLoadStatePlaythroughOK;\n    } else if ([playerItem isPlaybackBufferEmpty]) {\n        // NSLog(@\"loadState: isPlaybackBufferEmpty\");\n        return IJKMPMovieLoadStateStalled;\n    } else {\n        NSLog(@\"loadState: unknown\");\n        return IJKMPMovieLoadStateUnknown;\n    }\n}\n\n-(void)setPlaybackRate:(float)playbackRate\n{\n    _playbackRate = playbackRate;\n    if (_player != nil && !isFloatZero(_player.rate)) {\n        _player.rate = _playbackRate;\n    }\n}\n\n-(float)playbackRate\n{\n    return _playbackRate;\n}\n\n-(void)setPlaybackVolume:(float)playbackVolume\n{\n    _playbackVolume = playbackVolume;\n    if (_player != nil && _player.volume != playbackVolume) {\n        _player.volume = playbackVolume;\n    }\n    BOOL muted = fabs(playbackVolume) < 1e-6;\n    if (_player != nil && _player.muted != muted) {\n        _player.muted = muted;\n    }\n}\n\n-(float)playbackVolume\n{\n    return _playbackVolume;\n}\n\n- (void)didPrepareToPlayAsset:(AVURLAsset *)asset withKeys:(NSArray *)requestedKeys\n{\n    if (_isShutdown)\n        return;\n    \n    /* Make sure that the value of each key has loaded successfully. */\n    for (NSString *thisKey in requestedKeys)\n    {\n        NSError *error = nil;\n        AVKeyValueStatus keyStatus = [asset statusOfValueForKey:thisKey error:&error];\n        if (keyStatus == AVKeyValueStatusFailed)\n        {\n            [self assetFailedToPrepareForPlayback:error];\n            return;\n        } else if (keyStatus == AVKeyValueStatusCancelled) {\n            // TODO [AVAsset cancelLoading]\n            error = [self createErrorWithCode:kEC_PlayerItemCancelled\n                                  description:@\"player item cancelled\"\n                                       reason:nil];\n            [self assetFailedToPrepareForPlayback:error];\n            return;\n        }\n    }\n    \n    /* Use the AVAsset playable property to detect whether the asset can be played. */\n    if (!asset.playable)\n    {\n        NSError *assetCannotBePlayedError = [NSError errorWithDomain:@\"AVMoviePlayer\"\n                                                                code:0\n                                                            userInfo:nil];\n        \n        [self assetFailedToPrepareForPlayback:assetCannotBePlayedError];\n        return;\n    }\n    \n    /* At this point we're ready to set up for playback of the asset. */\n    \n    /* Stop observing our prior AVPlayerItem, if we have one. */\n    [_playerItemKVO safelyRemoveAllObservers];\n    [[NSNotificationCenter defaultCenter] removeObserver:self\n                                                    name:nil\n                                                  object:_playerItem];\n    \n    /* Create a new instance of AVPlayerItem from the now successfully loaded AVAsset. */\n    _playerItem = [AVPlayerItem playerItemWithAsset:asset];\n    _playerItemKVO = [[IJKKVOController alloc] initWithTarget:_playerItem];\n    [self registerApplicationObservers];\n    /* Observe the player item \"status\" key to determine when it is ready to play. */\n    [_playerItemKVO safelyAddObserver:self\n                           forKeyPath:@\"status\"\n                              options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew\n                              context:KVO_AVPlayerItem_state];\n    \n    [_playerItemKVO safelyAddObserver:self\n                           forKeyPath:@\"loadedTimeRanges\"\n                              options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew\n                              context:KVO_AVPlayerItem_loadedTimeRanges];\n    \n    [_playerItemKVO safelyAddObserver:self\n                           forKeyPath:@\"playbackLikelyToKeepUp\"\n                              options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew\n                              context:KVO_AVPlayerItem_playbackLikelyToKeepUp];\n    \n    [_playerItemKVO safelyAddObserver:self\n                           forKeyPath:@\"playbackBufferEmpty\"\n                              options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew\n                              context:KVO_AVPlayerItem_playbackBufferEmpty];\n    \n    [_playerItemKVO safelyAddObserver:self\n                           forKeyPath:@\"playbackBufferFull\"\n                              options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew\n                              context:KVO_AVPlayerItem_playbackBufferFull];\n    \n    [[NSNotificationCenter defaultCenter] addObserver:self\n                                             selector:@selector(playerItemDidReachEnd:)\n                                                 name:AVPlayerItemDidPlayToEndTimeNotification\n                                               object:_playerItem];\n    \n    [[NSNotificationCenter defaultCenter] addObserver:self\n                                             selector:@selector(playerItemFailedToPlayToEndTime:)\n                                                 name:AVPlayerItemFailedToPlayToEndTimeNotification\n                                               object:_playerItem];\n    \n    _isCompleted = NO;\n    \n    /* Create new player, if we don't already have one. */\n    if (!_player)\n    {\n        /* Get a new AVPlayer initialized to play the specified player item. */\n        _player = [AVPlayer playerWithPlayerItem:_playerItem];\n        _playerKVO = [[IJKKVOController alloc] initWithTarget:_player];\n        \n        /* Observe the AVPlayer \"currentItem\" property to find out when any\n         AVPlayer replaceCurrentItemWithPlayerItem: replacement will/did\n         occur.*/\n        [_playerKVO safelyAddObserver:self\n                           forKeyPath:@\"currentItem\"\n                              options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew\n                              context:KVO_AVPlayer_currentItem];\n        \n        /* Observe the AVPlayer \"rate\" property to update the scrubber control. */\n        [_playerKVO safelyAddObserver:self\n                           forKeyPath:@\"rate\"\n                              options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew\n                              context:KVO_AVPlayer_rate];\n        \n        [_playerKVO safelyAddObserver:self\n                           forKeyPath:@\"airPlayVideoActive\"\n                              options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew\n                              context:KVO_AVPlayer_airplay];\n    }\n    \n    /* Make our new AVPlayerItem the AVPlayer's current item. */\n    if (_player.currentItem != _playerItem)\n    {\n        /* Replace the player item with a new player item. The item replacement occurs\n         asynchronously; observe the currentItem property to find out when the\n         replacement will/did occur\n         \n         If needed, configure player item here (example: adding outputs, setting text style rules,\n         selecting media options) before associating it with a player\n         */\n        [_player replaceCurrentItemWithPlayerItem:_playerItem];\n        \n        // TODO: notify state change\n    }\n    \n    // TODO: set time to 0;\n}\n\n- (void)didPlaybackStateChange\n{\n    if (_playbackState != self.playbackState) {\n        _playbackState = self.playbackState;\n        [[NSNotificationCenter defaultCenter]\n         postNotificationName:IJKMPMoviePlayerPlaybackStateDidChangeNotification\n         object:self];\n    }\n    \n}\n\n- (void)fetchLoadStateFromItem:(AVPlayerItem*)playerItem\n{\n    if (playerItem == nil)\n        return;\n    \n    _playbackLikelyToKeeyUp = playerItem.isPlaybackLikelyToKeepUp;\n    _playbackBufferEmpty    = playerItem.isPlaybackBufferEmpty;\n    _playbackBufferFull     = playerItem.isPlaybackBufferFull;\n}\n\n- (void)didLoadStateChange\n{\n    // NOTE: do not force play after stall,\n    // which may cause AVPlayer get into wrong state\n    //\n    // Rely on AVPlayer's auto resume.\n    \n    [[NSNotificationCenter defaultCenter]\n     postNotificationName:IJKMPMoviePlayerLoadStateDidChangeNotification\n     object:self];\n}\n\n- (void)didPlayableDurationUpdate\n{\n    NSTimeInterval currentPlaybackTime = self.currentPlaybackTime;\n    int playableDurationMilli    = (int)(self.playableDuration * 1000);\n    int currentPlaybackTimeMilli = (int)(currentPlaybackTime * 1000);\n    \n    int bufferedDurationMilli = playableDurationMilli - currentPlaybackTimeMilli;\n    if (bufferedDurationMilli > 0) {\n        self.bufferingProgress = bufferedDurationMilli * 100 / kMaxHighWaterMarkMilli;\n        \n        if (self.bufferingProgress > 100) {\n            dispatch_async(dispatch_get_main_queue(), ^{\n                if (self.bufferingProgress > 100) {\n                    if ([self isPlaying]) {\n                        _player.rate = _playbackRate;\n                    }\n                }\n            });\n        }\n        \n    }\n    \n    NSLog(@\"KVO_AVPlayerItem_loadedTimeRanges: %d / %d\\n\",\n          bufferedDurationMilli,\n          (int)kMaxHighWaterMarkMilli);\n}\n\n- (void)onError:(NSError *)error\n{\n    _isError = YES;\n    \n    __block NSError *blockError = error;\n    \n    NSLog(@\"AVPlayer: onError\\n\");\n    dispatch_async(dispatch_get_main_queue(), ^{\n        [self didPlaybackStateChange];\n        [self didLoadStateChange];\n        [self setScreenOn:NO];\n \n        if (blockError == nil) {\n            blockError = [[NSError alloc] init];\n        }\n        \n        [[NSNotificationCenter defaultCenter]\n         postNotificationName:IJKMPMoviePlayerPlaybackDidFinishNotification\n         object:self\n         userInfo:@{\n                    IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey: @(IJKMPMovieFinishReasonPlaybackError),\n                    @\"error\": blockError\n                    }];\n    });\n}\n\n- (void)assetFailedToPrepareForPlayback:(NSError *)error\n{\n    if (_isShutdown)\n        return;\n    \n    [self onError:error];\n}\n\n- (void)playerItemFailedToPlayToEndTime:(NSNotification *)notification\n{\n    if (_isShutdown)\n        return;\n    \n    [self onError:[notification.userInfo objectForKey:@\"error\"]];\n}\n\n- (void)playerItemDidReachEnd:(NSNotification *)notification\n{\n    if (_isShutdown)\n        return;\n    \n    _isCompleted = YES;\n    \n    dispatch_async(dispatch_get_main_queue(), ^{\n        [self didPlaybackStateChange];\n        [self didLoadStateChange];\n        [self setScreenOn:NO];\n \n        [[NSNotificationCenter defaultCenter]\n         postNotificationName:IJKMPMoviePlayerPlaybackDidFinishNotification\n         object:self\n         userInfo:@{\n                    IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey: @(IJKMPMovieFinishReasonPlaybackEnded)\n                    }];\n    });\n}\n\n\n#pragma mark KVO\n\n- (void)observeValueForKeyPath:(NSString*)path\n                      ofObject:(id)object\n                        change:(NSDictionary*)change\n                       context:(void*)context\n{\n    if (_isShutdown)\n        return;\n    \n    if (context == KVO_AVPlayerItem_state)\n    {\n        /* AVPlayerItem \"status\" property value observer. */\n        AVPlayerItemStatus status = [[change objectForKey:NSKeyValueChangeNewKey] integerValue];\n        switch (status)\n        {\n            case AVPlayerItemStatusUnknown:\n            {\n                /* Indicates that the status of the player is not yet known because\n                 it has not tried to load new media resources for playback */\n            }\n                break;\n                \n            case AVPlayerItemStatusReadyToPlay:\n            {\n                /* Once the AVPlayerItem becomes ready to play, i.e.\n                 [playerItem status] == AVPlayerItemStatusReadyToPlay,\n                 its duration can be fetched from the item. */\n                dispatch_once(&_readyToPlayToken, ^{\n                    [_avView setPlayer:_player];\n                    \n                    self.isPreparedToPlay = YES;\n                    AVPlayerItem *playerItem = (AVPlayerItem *)object;\n                    NSTimeInterval duration = CMTimeGetSeconds(playerItem.duration);\n                    if (duration <= 0)\n                        self.duration = 0.0f;\n                    else\n                        self.duration = duration;\n                    \n                    [[NSNotificationCenter defaultCenter]\n                     postNotificationName:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification\n                     object:self];\n                    \n                    if (_shouldAutoplay && (!_pauseInBackground || [UIApplication sharedApplication].applicationState == UIApplicationStateActive))\n                        [_player play];\n                });\n            }\n                break;\n                \n            case AVPlayerItemStatusFailed:\n            {\n                AVPlayerItem *playerItem = (AVPlayerItem *)object;\n                [self assetFailedToPrepareForPlayback:playerItem.error];\n            }\n                break;\n        }\n        \n        [self didPlaybackStateChange];\n        [self didLoadStateChange];\n    }\n    else if (context == KVO_AVPlayerItem_loadedTimeRanges)\n    {\n        AVPlayerItem *playerItem = (AVPlayerItem *)object;\n        if (_player != nil && playerItem.status == AVPlayerItemStatusReadyToPlay) {\n            NSArray *timeRangeArray = playerItem.loadedTimeRanges;\n            CMTime currentTime = [_player currentTime];\n            \n            BOOL foundRange = NO;\n            CMTimeRange aTimeRange = {0};\n            \n            if (timeRangeArray.count) {\n                aTimeRange = [[timeRangeArray objectAtIndex:0] CMTimeRangeValue];\n                if(CMTimeRangeContainsTime(aTimeRange, currentTime)) {\n                    foundRange = YES;\n                }\n            }\n            \n            if (foundRange) {\n                CMTime maxTime = CMTimeRangeGetEnd(aTimeRange);\n                NSTimeInterval playableDuration = CMTimeGetSeconds(maxTime);\n                if (playableDuration > 0) {\n                    self.playableDuration = playableDuration;\n                    [self didPlayableDurationUpdate];\n                }\n            }\n        }\n        else\n        {\n            self.playableDuration = 0;\n        }\n    }\n    else if (context == KVO_AVPlayerItem_playbackLikelyToKeepUp) {\n        AVPlayerItem *playerItem = (AVPlayerItem *)object;\n        NSLog(@\"KVO_AVPlayerItem_playbackLikelyToKeepUp: %@\\n\", playerItem.isPlaybackLikelyToKeepUp ? @\"YES\" : @\"NO\");\n        [self fetchLoadStateFromItem:playerItem];\n        [self didLoadStateChange];\n    }\n    else if (context == KVO_AVPlayerItem_playbackBufferEmpty) {\n        AVPlayerItem *playerItem = (AVPlayerItem *)object;\n        BOOL isPlaybackBufferEmpty = playerItem.isPlaybackBufferEmpty;\n        NSLog(@\"KVO_AVPlayerItem_playbackBufferEmpty: %@\\n\", isPlaybackBufferEmpty ? @\"YES\" : @\"NO\");\n        if (isPlaybackBufferEmpty)\n            _isPrerolling = YES;\n        [self fetchLoadStateFromItem:playerItem];\n        [self didLoadStateChange];\n    }\n    else if (context == KVO_AVPlayerItem_playbackBufferFull) {\n        AVPlayerItem *playerItem = (AVPlayerItem *)object;\n        NSLog(@\"KVO_AVPlayerItem_playbackBufferFull: %@\\n\", playerItem.isPlaybackBufferFull ? @\"YES\" : @\"NO\");\n        [self fetchLoadStateFromItem:playerItem];\n        [self didLoadStateChange];\n    }\n    else if (context == KVO_AVPlayer_rate)\n    {\n        if (_player != nil && !isFloatZero(_player.rate))\n            _isPrerolling = NO;\n        /* AVPlayer \"rate\" property value observer. */\n        [self didPlaybackStateChange];\n        [self didLoadStateChange];\n    }\n    else if (context == KVO_AVPlayer_currentItem)\n    {\n        _isPrerolling = NO;\n        /* AVPlayer \"currentItem\" property observer.\n         Called when the AVPlayer replaceCurrentItemWithPlayerItem:\n         replacement will/did occur. */\n        AVPlayerItem *newPlayerItem = [change objectForKey:NSKeyValueChangeNewKey];\n        \n        /* Is the new player item null? */\n        if (newPlayerItem == (id)[NSNull null])\n        {\n            NSError *error = [self createErrorWithCode:kEC_CurrentPlayerItemIsNil\n                                           description:@\"current player item is nil\"\n                                                reason:nil];\n            [self assetFailedToPrepareForPlayback:error];\n        }\n        else /* Replacement of player currentItem has occurred */\n        {\n            [_avView setPlayer:_player];\n            \n            [self didPlaybackStateChange];\n            [self didLoadStateChange];\n        }\n    }\n    else if (context == KVO_AVPlayer_airplay)\n    {\n        [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerIsAirPlayVideoActiveDidChangeNotification object:nil userInfo:nil];\n    }\n    else\n    {\n        [super observeValueForKeyPath:path ofObject:object change:change context:context];\n    }\n}\n\n\n- (NSError*)createErrorWithCode: (NSInteger)code\n                    description: (NSString*)description\n                         reason: (NSString*)reason\n{\n    NSError *error = [IJKMediaUtils createErrorWithDomain:kErrorDomain\n                                                     code:code\n                                              description:description\n                                                   reason:reason];\n    return error;\n}\n\n#pragma mark app state changed\n\n- (void)registerApplicationObservers\n{\n    [_notificationManager addObserver:self\n                             selector:@selector(audioSessionInterrupt:)\n                                 name:AVAudioSessionInterruptionNotification\n                               object:nil];\n\n    [_notificationManager addObserver:self\n                             selector:@selector(applicationWillEnterForeground)\n                                 name:UIApplicationWillEnterForegroundNotification\n                               object:nil];\n\n    [_notificationManager addObserver:self\n                             selector:@selector(applicationDidBecomeActive)\n                                 name:UIApplicationDidBecomeActiveNotification\n                               object:nil];\n\n    [_notificationManager addObserver:self\n                             selector:@selector(applicationWillResignActive)\n                                 name:UIApplicationWillResignActiveNotification\n                               object:nil];\n\n    [_notificationManager addObserver:self\n                             selector:@selector(applicationDidEnterBackground)\n                                 name:UIApplicationDidEnterBackgroundNotification\n                               object:nil];\n\n    [_notificationManager addObserver:self\n                             selector:@selector(applicationWillTerminate)\n                                 name:UIApplicationWillTerminateNotification\n                               object:nil];\n}\n\n- (void)unregisterApplicationObservers\n{\n    [_notificationManager removeAllObservers:self];\n}\n\n-(BOOL)allowsMediaAirPlay\n{\n    if (!_player)\n        return NO;\n    return _player.allowsExternalPlayback;\n}\n\n-(void)setAllowsMediaAirPlay:(BOOL)b\n{\n    if (!_player)\n        return;\n    _player.allowsExternalPlayback = b;\n}\n\n-(BOOL)airPlayMediaActive\n{\n    if (!_player)\n        return NO;\n    return _player.externalPlaybackActive || self.isDanmakuMediaAirPlay;\n}\n\n- (CGSize)naturalSize\n{\n    if (_playAsset == nil)\n        return CGSizeZero;\n\n    NSArray<AVAssetTrack *> *videoTracks = [_playAsset tracksWithMediaType:AVMediaTypeVideo];\n    if (videoTracks == nil || videoTracks.count <= 0)\n        return CGSizeZero;\n\n    return [videoTracks objectAtIndex:0].naturalSize;\n}\n\n- (void)setScalingMode: (IJKMPMovieScalingMode) aScalingMode\n{\n    IJKMPMovieScalingMode newScalingMode = aScalingMode;\n    switch (aScalingMode) {\n        case IJKMPMovieScalingModeNone:\n            [_view setContentMode:UIViewContentModeCenter];\n            break;\n        case IJKMPMovieScalingModeAspectFit:\n            [_view setContentMode:UIViewContentModeScaleAspectFit];\n            break;\n        case IJKMPMovieScalingModeAspectFill:\n            [_view setContentMode:UIViewContentModeScaleAspectFill];\n            break;\n        case IJKMPMovieScalingModeFill:\n            [_view setContentMode:UIViewContentModeScaleToFill];\n            break;\n        default:\n            newScalingMode = _scalingMode;\n    }\n    \n    _scalingMode = newScalingMode;\n}\n\n- (void)setPauseInBackground:(BOOL)pause\n{\n    _pauseInBackground = pause;\n}\n\n-(BOOL)isDanmakuMediaAirPlay\n{\n    return _isDanmakuMediaAirPlay;\n}\n\n-(void)setIsDanmakuMediaAirPlay:(BOOL)isDanmakuMediaAirPlay\n{\n    _isDanmakuMediaAirPlay = isDanmakuMediaAirPlay;\n    [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerIsAirPlayVideoActiveDidChangeNotification object:nil userInfo:nil];\n}\n\n- (void)audioSessionInterrupt:(NSNotification *)notification\n{\n    int reason = [[[notification userInfo] valueForKey:AVAudioSessionInterruptionTypeKey] intValue];\n    switch (reason) {\n        case AVAudioSessionInterruptionTypeBegan: {\n            NSLog(@\"IJKAVMoviePlayerController:audioSessionInterrupt: begin\\n\");\n            switch (self.playbackState) {\n                case IJKMPMoviePlaybackStatePaused:\n                case IJKMPMoviePlaybackStateStopped:\n                    _playingBeforeInterruption = NO;\n                    break;\n                default:\n                    _playingBeforeInterruption = YES;\n                    break;\n            }\n            [self pause];\n            [[IJKAudioKit sharedInstance] setActive:NO];\n            break;\n        }\n        case AVAudioSessionInterruptionTypeEnded: {\n            NSLog(@\"IJKAVMoviePlayerController:audioSessionInterrupt: end\\n\");\n            [[IJKAudioKit sharedInstance] setActive:YES];\n            if (_playingBeforeInterruption) {\n                [self play];\n            }\n            break;\n        }\n    }\n}\n\n- (void)applicationWillEnterForeground\n{\n    NSLog(@\"IJKAVMoviePlayerController:applicationWillEnterForeground: %d\\n\", (int)[UIApplication sharedApplication].applicationState);\n}\n\n- (void)applicationDidBecomeActive\n{\n    NSLog(@\"IJKAVMoviePlayerController:applicationDidBecomeActive: %d\\n\", (int)[UIApplication sharedApplication].applicationState);\n    [_avView setPlayer:_player];\n}\n\n- (void)applicationWillResignActive\n{\n    NSLog(@\"IJKAVMoviePlayerController:applicationWillResignActive: %d\\n\", (int)[UIApplication sharedApplication].applicationState);\n}\n\n- (void)applicationDidEnterBackground\n{\n    NSLog(@\"IJKAVMoviePlayerController:applicationDidEnterBackground: %d\\n\", (int)[UIApplication sharedApplication].applicationState);\n    if (_pauseInBackground && ![self airPlayMediaActive]) {\n        [self pause];\n    } else {\n        if (![self airPlayMediaActive]) {\n            [_avView setPlayer:nil];\n            if (isIOS9OrLater()) {\n                if ([self isPlaying]) {\n                    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{\n                        [self play];\n                    });\n                }\n            }\n        }\n    }\n}\n\n- (void)applicationWillTerminate\n{\n    NSLog(@\"IJKAVMoviePlayerController:applicationWillTerminate: %d\\n\", (int)[UIApplication sharedApplication].applicationState);\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKAVPlayerLayerView.h",
    "content": "/*\n * IJKAVPlayerLayerView.h\n *\n * Copyright (c) 2014 Bilibili\n * Copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n/*\n File: AVPlayerDemoPlaybackView.h\n Abstract: UIView subclass to display the content associated with an AVPlayer\n Version: 1.3\n\n Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple\n Inc. (\"Apple\") in consideration of your agreement to the following\n terms, and your use, installation, modification or redistribution of\n this Apple software constitutes acceptance of these terms.  If you do\n not agree with these terms, please do not use, install, modify or\n redistribute this Apple software.\n\n In consideration of your agreement to abide by the following terms, and\n subject to these terms, Apple grants you a personal, non-exclusive\n license, under Apple's copyrights in this original Apple software (the\n \"Apple Software\"), to use, reproduce, modify and redistribute the Apple\n Software, with or without modifications, in source and/or binary forms;\n provided that if you redistribute the Apple Software in its entirety and\n without modifications, you must retain this notice and the following\n text and disclaimers in all such redistributions of the Apple Software.\n Neither the name, trademarks, service marks or logos of Apple Inc. may\n be used to endorse or promote products derived from the Apple Software\n without specific prior written permission from Apple.  Except as\n expressly stated in this notice, no other rights or licenses, express or\n implied, are granted by Apple herein, including but not limited to any\n patent rights that may be infringed by your derivative works or by other\n works in which the Apple Software may be incorporated.\n\n The Apple Software is provided by Apple on an \"AS IS\" basis.  APPLE\n MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION\n THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS\n FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND\n OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.\n\n IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL\n OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,\n MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED\n AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),\n STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE\n POSSIBILITY OF SUCH DAMAGE.\n\n Copyright (C) 2014 Apple Inc. All Rights Reserved.\n\n */\n\n#import <UIKit/UIKit.h>\n\n@class AVPlayer;\n\n@interface IJKAVPlayerLayerView: UIView\n\n@property (nonatomic, strong) AVPlayer* player;\n\n- (void)setPlayer:(AVPlayer*)player;\n- (void)setVideoFillMode:(NSString *)fillMode;\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKAVPlayerLayerView.m",
    "content": "/*\n * IJKAVPlayerLayerView.m\n *\n * Copyright (c) 2014 Bilibili\n * Copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n/*\n File: AVPlayerDemoPlaybackView.m\n Abstract: UIView subclass to display the content associated with an AVPlayer\n Version: 1.3\n\n Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple\n Inc. (\"Apple\") in consideration of your agreement to the following\n terms, and your use, installation, modification or redistribution of\n this Apple software constitutes acceptance of these terms.  If you do\n not agree with these terms, please do not use, install, modify or\n redistribute this Apple software.\n\n In consideration of your agreement to abide by the following terms, and\n subject to these terms, Apple grants you a personal, non-exclusive\n license, under Apple's copyrights in this original Apple software (the\n \"Apple Software\"), to use, reproduce, modify and redistribute the Apple\n Software, with or without modifications, in source and/or binary forms;\n provided that if you redistribute the Apple Software in its entirety and\n without modifications, you must retain this notice and the following\n text and disclaimers in all such redistributions of the Apple Software.\n Neither the name, trademarks, service marks or logos of Apple Inc. may\n be used to endorse or promote products derived from the Apple Software\n without specific prior written permission from Apple.  Except as\n expressly stated in this notice, no other rights or licenses, express or\n implied, are granted by Apple herein, including but not limited to any\n patent rights that may be infringed by your derivative works or by other\n works in which the Apple Software may be incorporated.\n\n The Apple Software is provided by Apple on an \"AS IS\" basis.  APPLE\n MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION\n THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS\n FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND\n OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.\n\n IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL\n OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,\n MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED\n AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),\n STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE\n POSSIBILITY OF SUCH DAMAGE.\n\n Copyright (C) 2014 Apple Inc. All Rights Reserved.\n\n */\n\n#import \"IJKAVPlayerLayerView.h\"\n#import <AVFoundation/AVFoundation.h>\n\n@implementation IJKAVPlayerLayerView {\n    NSString* _videoFillMode;\n}\n\n- (id)initWithFrame:(CGRect)frame\n{\n    self = [super initWithFrame:frame];\n    if (self) {\n        _videoFillMode = @\"AVLayerVideoGravityResizeAspect\";\n        // Initialization code\n    }\n    return self;\n}\n\n+ (Class)layerClass\n{\n    return [AVPlayerLayer class];\n}\n\n- (AVPlayer*)player\n{\n    return [(AVPlayerLayer*)[self layer] player];\n}\n\n- (void)setPlayer:(AVPlayer*)player\n{\n    [(AVPlayerLayer*)[self layer] setPlayer:player];\n    [self setVideoFillMode:_videoFillMode];\n}\n\n/* Specifies how the video is displayed within a player layer’s bounds.\n (AVLayerVideoGravityResizeAspect is default) */\n- (void)setVideoFillMode:(NSString *)fillMode\n{\n    _videoFillMode = fillMode;\n\n    AVPlayerLayer *playerLayer = (AVPlayerLayer*)[self layer];\n    playerLayer.videoGravity = fillMode;\n}\n\n- (void)setContentMode:(UIViewContentMode)contentMode\n{\n    [super setContentMode:contentMode];\n\n    switch (contentMode) {\n        case UIViewContentModeScaleToFill:\n            [self setVideoFillMode:AVLayerVideoGravityResize];\n            break;\n        case UIViewContentModeCenter:\n            [self setVideoFillMode:AVLayerVideoGravityResizeAspect];\n            break;\n        case UIViewContentModeScaleAspectFill:\n            [self setVideoFillMode:AVLayerVideoGravityResizeAspectFill];\n            break;\n        case UIViewContentModeScaleAspectFit:\n            [self setVideoFillMode:AVLayerVideoGravityResizeAspect];\n        default:\n            break;\n    }\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKAudioKit.h",
    "content": "/*\n * IJKAudioKit.h\n *\n * Copyright (c) 2013-2014 Bilibili\n * Copyright (c) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n *\n * based on https://github.com/kolyvan/kxmovie\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import <Foundation/Foundation.h>\n#import <AVFoundation/AVFoundation.h>\n\n@interface IJKAudioKit : NSObject\n\n+ (IJKAudioKit *)sharedInstance;\n- (void)setupAudioSession;\n- (BOOL)setActive:(BOOL)active;\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKAudioKit.m",
    "content": "/*\n * IJKAudioKit.m\n *\n * Copyright (c) 2013-2014 Bilibili\n * Copyright (c) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n *\n * based on https://github.com/kolyvan/kxmovie\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import \"IJKAudioKit.h\"\n\n@implementation IJKAudioKit {\n    BOOL _audioSessionInitialized;\n}\n\n+ (IJKAudioKit *)sharedInstance\n{\n    static IJKAudioKit *sAudioKit = nil;\n    static dispatch_once_t onceToken;\n    dispatch_once(&onceToken, ^{\n        sAudioKit = [[IJKAudioKit alloc] init];\n    });\n    return sAudioKit;\n}\n\n- (void)setupAudioSession\n{\n    if (!_audioSessionInitialized) {\n        [[NSNotificationCenter defaultCenter] addObserver: self\n                                                 selector: @selector(handleInterruption:)\n                                                     name: AVAudioSessionInterruptionNotification\n                                                   object: [AVAudioSession sharedInstance]];\n        _audioSessionInitialized = YES;\n    }\n\n    /* Set audio session to mediaplayback */\n    NSError *error = nil;\n    if (NO == [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error]) {\n        NSLog(@\"IJKAudioKit: AVAudioSession.setCategory() failed: %@\\n\", error ? [error localizedDescription] : @\"nil\");\n        return;\n    }\n\n    error = nil;\n    if (NO == [[AVAudioSession sharedInstance] setActive:YES error:&error]) {\n        NSLog(@\"IJKAudioKit: AVAudioSession.setActive(YES) failed: %@\\n\", error ? [error localizedDescription] : @\"nil\");\n        return;\n    }\n\n    return ;\n}\n\n- (BOOL)setActive:(BOOL)active\n{\n    if (active != NO) {\n        [[AVAudioSession sharedInstance] setActive:YES error:nil];\n    } else {\n        @try {\n            [[AVAudioSession sharedInstance] setActive:NO error:nil];\n        } @catch (NSException *exception) {\n            NSLog(@\"failed to inactive AVAudioSession\\n\");\n        }\n    }\n}\n\n- (void)handleInterruption:(NSNotification *)notification\n{\n    int reason = [[[notification userInfo] valueForKey:AVAudioSessionInterruptionTypeKey] intValue];\n    switch (reason) {\n        case AVAudioSessionInterruptionTypeBegan: {\n            NSLog(@\"AVAudioSessionInterruptionTypeBegan\\n\");\n            [self setActive:NO];\n            break;\n        }\n        case AVAudioSessionInterruptionTypeEnded: {\n            NSLog(@\"AVAudioSessionInterruptionTypeEnded\\n\");\n            [self setActive:YES];\n            break;\n        }\n    }\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKDeviceModel.h",
    "content": "/*\n * IJKDeviceModel.h\n *\n * Copyright (c) 2015 Bilibili\n * Copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import <Foundation/Foundation.h>\n\n#define kIJKDeviceRank_Baseline                         10\n#define kIJKDeviceRank_AppleA4Class                     20   // Cortex-A8 class\n#define kIJKDeviceRank_AppleA5Class                     30   // Cortex-A9 class\n#define kIJKDeviceRank_AppleA5RAClass                   31   // Cortex-A9 class\n#define kIJKDeviceRank_AppleA5XClass                    35   // Cortex-A9 class\n#define kIJKDeviceRank_AppleA6Class                     40   // ARMv7s class\n#define kIJKDeviceRank_AppleA6XClass                    41   // ARMv7s class\n#define kIJKDeviceRank_AppleA7Class                     50   // ARM64 class\n#define kIJKDeviceRank_AppleA8LowClass                  55   // ARM64 class\n#define kIJKDeviceRank_AppleA8Class                     60   // ARM64 class\n#define kIJKDeviceRank_AppleA8XClass                    61   // ARM64 class\n#define kIJKDeviceRank_AppleA9Class                     70   // ARM64 class\n#define kIJKDeviceRank_AppleA9XClass                    71   // ARM64 class\n#define kIJKDeviceRank_LatestUnknown                    90\n#define kIJKDeviceRank_Simulator                        100\n\n@interface IJKDeviceModel : NSObject\n\n@property(nonatomic) NSString   *platform;\n@property(nonatomic) NSString   *name;\n@property(nonatomic) NSInteger  rank;\n\n+ (instancetype)currentModel;\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKDeviceModel.m",
    "content": "/*\n * IJKDeviceModel.m\n *\n * Copyright (c) 2015 Bilibili\n * Copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import \"IJKDeviceModel.h\"\n\n#include <sys/utsname.h>\n\n@implementation IJKDeviceModel\n\n- (instancetype)initWithPlatform:(NSString *)platform\n                        withName:(NSString *)name\n                        withRank:(NSInteger)rank\n{\n    self = [super init];\n    if (self) {\n        _platform = platform;\n        _name     = name;\n        _rank     = rank;\n    }\n    return self;\n}\n\ninline static void IJKDeviceRegister(NSMutableDictionary *dict,\n                                    NSString *platform,\n                                    NSString *name,\n                                    NSInteger rank)\n{\n    IJKDeviceModel *model = [[IJKDeviceModel alloc] initWithPlatform:platform\n                                                            withName:name\n                                                            withRank:rank];\n    [dict setObject:model forKey:platform];\n}\n\n+ (instancetype)modelWithName:(NSString *)name\n{\n    static IJKDeviceModel  *sLatestModel = nil;\n    static NSDictionary    *sModelDictionary = nil;\n    static dispatch_once_t  sOnceToken = 0;\n    dispatch_once(&sOnceToken, ^{\n        NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];\n\n        // http://en.wikipedia.org/wiki/List_of_iOS_devices\n        // http://www.everyiphone.com\n        // Simulator\n        IJKDeviceRegister(dict, @\"i386\",        @\"Simulator\",       kIJKDeviceRank_Simulator);\n        IJKDeviceRegister(dict, @\"x86_64\",      @\"Simulator 64\",    kIJKDeviceRank_Simulator);\n\n        // iPhone\n        IJKDeviceRegister(dict, @\"iPhone1,1\",   @\"iPhone\",          kIJKDeviceRank_Baseline);\n        IJKDeviceRegister(dict, @\"iPhone1,2\",   @\"iPhone 3G\",       kIJKDeviceRank_Baseline);\n\n        IJKDeviceRegister(dict, @\"iPhone2,1\",   @\"iPhone 3GS\",      kIJKDeviceRank_Baseline);\n\n        IJKDeviceRegister(dict, @\"iPhone3,1\",   @\"iPhone 4\",        kIJKDeviceRank_AppleA4Class);\n        IJKDeviceRegister(dict, @\"iPhone3,2\",   @\"iPhone 4\",        kIJKDeviceRank_AppleA4Class);\n        IJKDeviceRegister(dict, @\"iPhone3,3\",   @\"iPhone 4\",        kIJKDeviceRank_AppleA4Class);\n\n        IJKDeviceRegister(dict, @\"iPhone4,1\",   @\"iPhone 4s\",       kIJKDeviceRank_AppleA5Class);\n\n        IJKDeviceRegister(dict, @\"iPhone5,1\",   @\"iPhone 5\",        kIJKDeviceRank_AppleA6Class);\n        IJKDeviceRegister(dict, @\"iPhone5,2\",   @\"iPhone 5\",        kIJKDeviceRank_AppleA6Class);\n        IJKDeviceRegister(dict, @\"iPhone5,3\",   @\"iPhone 5c\",       kIJKDeviceRank_AppleA6Class);\n        IJKDeviceRegister(dict, @\"iPhone5,4\",   @\"iPhone 5c\",       kIJKDeviceRank_AppleA6Class);\n\n        IJKDeviceRegister(dict, @\"iPhone6,1\",   @\"iPhone 5s\",       kIJKDeviceRank_AppleA7Class);\n        IJKDeviceRegister(dict, @\"iPhone6,2\",   @\"iPhone 5s\",       kIJKDeviceRank_AppleA7Class);\n\n        IJKDeviceRegister(dict, @\"iPhone7,1\",   @\"iPhone 6 Plus\",   kIJKDeviceRank_AppleA8Class);\n        IJKDeviceRegister(dict, @\"iPhone7,2\",   @\"iPhone 6\",        kIJKDeviceRank_AppleA8Class);\n\n        IJKDeviceRegister(dict, @\"iPhone8,1\",   @\"iPhone 6S\",       kIJKDeviceRank_AppleA9Class);\n        IJKDeviceRegister(dict, @\"iPhone8,2\",   @\"iPhone 6S Plus\",  kIJKDeviceRank_AppleA9Class);\n        IJKDeviceRegister(dict, @\"iPhone8,4\",   @\"iPhone SE\",       kIJKDeviceRank_AppleA9Class);\n\n\n        // iPod Touch\n        IJKDeviceRegister(dict, @\"iPod1,1\",     @\"iPod Touch\",      kIJKDeviceRank_Baseline);\n        IJKDeviceRegister(dict, @\"iPod2,1\",     @\"iPod Touch 2G\",   kIJKDeviceRank_Baseline);\n        IJKDeviceRegister(dict, @\"iPod3,1\",     @\"iPod Touch 3G\",   kIJKDeviceRank_Baseline);\n\n        IJKDeviceRegister(dict, @\"iPod4,1\",     @\"iPod Touch 4G\",   kIJKDeviceRank_AppleA4Class);\n\n        IJKDeviceRegister(dict, @\"iPod5,1\",     @\"iPod Touch 5G\",   kIJKDeviceRank_AppleA5Class);\n\n        IJKDeviceRegister(dict, @\"iPod7,1\",     @\"iPod Touch 6G\",   kIJKDeviceRank_AppleA8LowClass);\n\n        // iPad / iPad mini\n        IJKDeviceRegister(dict, @\"iPad1,1\",     @\"iPad\",            kIJKDeviceRank_AppleA4Class);\n\n        IJKDeviceRegister(dict, @\"iPad2,1\",     @\"iPad 2\",          kIJKDeviceRank_AppleA5Class);\n        IJKDeviceRegister(dict, @\"iPad2,2\",     @\"iPad 2\",          kIJKDeviceRank_AppleA5Class);\n        IJKDeviceRegister(dict, @\"iPad2,3\",     @\"iPad 2\",          kIJKDeviceRank_AppleA5Class);\n\n        IJKDeviceRegister(dict, @\"iPad2,4\",     @\"iPad 2\",          kIJKDeviceRank_AppleA5RAClass);\n        IJKDeviceRegister(dict, @\"iPad2,5\",     @\"iPad mini\",       kIJKDeviceRank_AppleA5RAClass);\n        IJKDeviceRegister(dict, @\"iPad2,6\",     @\"iPad mini\",       kIJKDeviceRank_AppleA5RAClass);\n        IJKDeviceRegister(dict, @\"iPad2,7\",     @\"iPad mini\",       kIJKDeviceRank_AppleA5RAClass);\n\n        IJKDeviceRegister(dict, @\"iPad3,1\",     @\"iPad 3G\",         kIJKDeviceRank_AppleA5XClass);\n        IJKDeviceRegister(dict, @\"iPad3,2\",     @\"iPad 3G\",         kIJKDeviceRank_AppleA5XClass);\n        IJKDeviceRegister(dict, @\"iPad3,3\",     @\"iPad 3G\",         kIJKDeviceRank_AppleA5XClass);\n\n        IJKDeviceRegister(dict, @\"iPad3,4\",     @\"iPad 4G\",         kIJKDeviceRank_AppleA6XClass);\n        IJKDeviceRegister(dict, @\"iPad3,5\",     @\"iPad 4G\",         kIJKDeviceRank_AppleA6XClass);\n        IJKDeviceRegister(dict, @\"iPad3,6\",     @\"iPad 4G\",         kIJKDeviceRank_AppleA6XClass);\n\n        IJKDeviceRegister(dict, @\"iPad4,1\",     @\"iPad Air\",        kIJKDeviceRank_AppleA7Class);\n        IJKDeviceRegister(dict, @\"iPad4,2\",     @\"iPad Air\",        kIJKDeviceRank_AppleA7Class);\n        IJKDeviceRegister(dict, @\"iPad4,3\",     @\"iPad Air\",        kIJKDeviceRank_AppleA7Class);\n        IJKDeviceRegister(dict, @\"iPad4,4\",     @\"iPad mini 2G\",    kIJKDeviceRank_AppleA7Class);\n        IJKDeviceRegister(dict, @\"iPad4,5\",     @\"iPad mini 2G\",    kIJKDeviceRank_AppleA7Class);\n        IJKDeviceRegister(dict, @\"iPad4,6\",     @\"iPad mini 2G\",    kIJKDeviceRank_AppleA7Class);\n\n        IJKDeviceRegister(dict, @\"iPad4,7\",     @\"iPad mini 3\",     kIJKDeviceRank_AppleA7Class);\n        IJKDeviceRegister(dict, @\"iPad4,8\",     @\"iPad mini 3\",     kIJKDeviceRank_AppleA7Class);\n        IJKDeviceRegister(dict, @\"iPad4,9\",     @\"iPad mini 3\",     kIJKDeviceRank_AppleA7Class);\n\n        IJKDeviceRegister(dict, @\"iPad5,1\",     @\"iPad mini 4\",     kIJKDeviceRank_AppleA8XClass);\n        IJKDeviceRegister(dict, @\"iPad5,2\",     @\"iPad mini 4\",     kIJKDeviceRank_AppleA8XClass);\n        IJKDeviceRegister(dict, @\"iPad5,3\",     @\"iPad Air 2\",      kIJKDeviceRank_AppleA8XClass);\n        IJKDeviceRegister(dict, @\"iPad5,4\",     @\"iPad Air 2\",      kIJKDeviceRank_AppleA8XClass);\n\n        IJKDeviceRegister(dict, @\"iPad6,3\",     @\"iPad Pro\",        kIJKDeviceRank_AppleA9XClass);\n        IJKDeviceRegister(dict, @\"iPad6,4\",     @\"iPad Pro\",        kIJKDeviceRank_AppleA9XClass);\n\n        IJKDeviceRegister(dict, @\"iPad6,7\",     @\"iPad Pro\",        kIJKDeviceRank_AppleA9XClass);\n        IJKDeviceRegister(dict, @\"iPad6,8\",     @\"iPad Pro\",        kIJKDeviceRank_AppleA9XClass);\n\n        sModelDictionary = dict;\n\n        sLatestModel = [[IJKDeviceModel alloc] initWithPlatform:name\n                                                       withName:name\n                                                       withRank:kIJKDeviceRank_LatestUnknown];\n    });\n\n    IJKDeviceModel *model = [sModelDictionary objectForKey:name];\n    if (model == nil) {\n        if (model == nil) {\n            model = sLatestModel;\n        }\n\n        NSArray *components = [name componentsSeparatedByString:@\",\"];\n        if (components != nil && components.count > 0) {\n            NSString *majorName = components[0];\n            if (majorName != nil) {\n                majorName = [majorName stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];\n                model = [sModelDictionary objectForKey:majorName];\n            }\n        }\n    }\n\n    return model;\n}\n\n+ (NSString *)currentModelName\n{\n    struct utsname systemInfo;\n    uname(&systemInfo);\n\n    return [NSString stringWithUTF8String:systemInfo.machine];\n}\n\n+ (instancetype)currentModel\n{\n    return [IJKDeviceModel modelWithName:[IJKDeviceModel currentModelName]];\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMonitor.h",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * Copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import <Foundation/Foundation.h>\n\n@interface IJKFFMonitor : NSObject\n\n- (instancetype)init;\n\n@property(nonatomic) NSDictionary *mediaMeta;\n@property(nonatomic) NSDictionary *videoMeta;\n@property(nonatomic) NSDictionary *audioMeta;\n\n@property(nonatomic, readonly) int64_t   duration;   // milliseconds\n@property(nonatomic, readonly) int64_t   bitrate;    // bit / sec\n@property(nonatomic, readonly) float     fps;        // frame / sec\n@property(nonatomic, readonly) int       width;      // width\n@property(nonatomic, readonly) int       height;     // height\n@property(nonatomic, readonly) NSString *vcodec;     // video codec\n@property(nonatomic, readonly) NSString *acodec;     // audio codec\n@property(nonatomic, readonly) int       sampleRate;\n@property(nonatomic, readonly) int64_t   channelLayout;\n\n@property(nonatomic) NSString *vdecoder;\n\n@property(nonatomic) int       tcpError;\n@property(nonatomic) NSString *remoteIp;\n\n@property(nonatomic) int       httpError;\n@property(nonatomic) NSString *httpUrl;\n@property(nonatomic) NSString *httpHost;\n@property(nonatomic) int       httpCode;\n@property(nonatomic) int64_t   httpOpenTick;\n@property(nonatomic) int64_t   httpSeekTick;\n@property(nonatomic) int       httpOpenCount;\n@property(nonatomic) int       httpSeekCount;\n@property(nonatomic) int64_t   lastHttpOpenDuration;\n@property(nonatomic) int64_t   lastHttpSeekDuration;\n@property(nonatomic) int64_t   filesize;\n\n@property(nonatomic) int64_t   prepareStartTick;\n@property(nonatomic) int64_t   prepareDuration;\n@property(nonatomic) int64_t   firstVideoFrameLatency;\n@property(nonatomic) int64_t   lastPrerollStartTick;\n@property(nonatomic) int64_t   lastPrerollDuration;\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMonitor.m",
    "content": "/*\n * Copyright (c) 2016 Bilibili\n * Copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import \"IJKFFMonitor.h\"\n#include \"ijksdl/ijksdl_timer.h\"\n#include \"ijkplayer/ijkmeta.h\"\n#import \"NSString+IJKMedia.h\"\n\n#define IJK_FFM_SAMPLE_RANGE 2000\n\n@implementation IJKFFMonitor\n{\n    SDL_SpeedSampler2 _tcpSpeedSampler;\n}\n\n- (instancetype)init\n{\n    self = [super init];\n    if (self) {\n        SDL_SpeedSampler2Reset(&_tcpSpeedSampler, IJK_FFM_SAMPLE_RANGE);\n    }\n    return self;\n}\n\n- (float)fps\n{\n    int fpsNum = [_videoMeta[@IJKM_KEY_FPS_NUM] intValue];\n    int fpsDen = [_videoMeta[@IJKM_KEY_FPS_DEN] intValue];\n\n    if (fpsNum <= 0 || fpsDen <= 0)\n        return 0;\n\n    return ((float)fpsNum) / fpsDen;\n}\n\n- (int64_t)     duration    {return [_mediaMeta[@IJKM_KEY_DURATION_US] longLongValue] / 1000;}\n- (int64_t)     bitrate     {return [_mediaMeta[@IJKM_KEY_BITRATE] longLongValue];}\n- (int)         width       {return [_videoMeta[@IJKM_KEY_WIDTH] intValue];}\n- (int)         height      {return [_videoMeta[@IJKM_KEY_HEIGHT] intValue];}\n- (NSString *)  vcodec      {return [NSString ijk_stringBeEmptyIfNil:_videoMeta[@IJKM_KEY_CODEC_NAME]];}\n- (NSString *)  acodec      {return [NSString ijk_stringBeEmptyIfNil:_audioMeta[@IJKM_KEY_CODEC_NAME]];}\n- (int)         sampleRate    {return [_audioMeta[@IJKM_KEY_SAMPLE_RATE] intValue];}\n- (int64_t)     channelLayout {return [_audioMeta[@IJKM_KEY_CHANNEL_LAYOUT] longLongValue];}\n\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerController.h",
    "content": "/*\n * IJKFFMoviePlayerController.h\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import \"IJKMediaPlayback.h\"\n#import \"IJKFFMonitor.h\"\n#import \"IJKFFOptions.h\"\n#import \"IJKSDLGLViewProtocol.h\"\n\n// media meta\n#define k_IJKM_KEY_FORMAT         @\"format\"\n#define k_IJKM_KEY_DURATION_US    @\"duration_us\"\n#define k_IJKM_KEY_START_US       @\"start_us\"\n#define k_IJKM_KEY_BITRATE        @\"bitrate\"\n\n// stream meta\n#define k_IJKM_KEY_TYPE           @\"type\"\n#define k_IJKM_VAL_TYPE__VIDEO    @\"video\"\n#define k_IJKM_VAL_TYPE__AUDIO    @\"audio\"\n#define k_IJKM_VAL_TYPE__UNKNOWN  @\"unknown\"\n\n#define k_IJKM_KEY_CODEC_NAME      @\"codec_name\"\n#define k_IJKM_KEY_CODEC_PROFILE   @\"codec_profile\"\n#define k_IJKM_KEY_CODEC_LONG_NAME @\"codec_long_name\"\n\n// stream: video\n#define k_IJKM_KEY_WIDTH          @\"width\"\n#define k_IJKM_KEY_HEIGHT         @\"height\"\n#define k_IJKM_KEY_FPS_NUM        @\"fps_num\"\n#define k_IJKM_KEY_FPS_DEN        @\"fps_den\"\n#define k_IJKM_KEY_TBR_NUM        @\"tbr_num\"\n#define k_IJKM_KEY_TBR_DEN        @\"tbr_den\"\n#define k_IJKM_KEY_SAR_NUM        @\"sar_num\"\n#define k_IJKM_KEY_SAR_DEN        @\"sar_den\"\n// stream: audio\n#define k_IJKM_KEY_SAMPLE_RATE    @\"sample_rate\"\n#define k_IJKM_KEY_CHANNEL_LAYOUT @\"channel_layout\"\n\n#define kk_IJKM_KEY_STREAMS       @\"streams\"\n\ntypedef enum IJKLogLevel {\n    k_IJK_LOG_UNKNOWN = 0,\n    k_IJK_LOG_DEFAULT = 1,\n\n    k_IJK_LOG_VERBOSE = 2,\n    k_IJK_LOG_DEBUG   = 3,\n    k_IJK_LOG_INFO    = 4,\n    k_IJK_LOG_WARN    = 5,\n    k_IJK_LOG_ERROR   = 6,\n    k_IJK_LOG_FATAL   = 7,\n    k_IJK_LOG_SILENT  = 8,\n} IJKLogLevel;\n\n@interface IJKFFMoviePlayerController : NSObject <IJKMediaPlayback>\n\n- (id)initWithContentURL:(NSURL *)aUrl\n             withOptions:(IJKFFOptions *)options;\n\n- (id)initWithContentURLString:(NSString *)aUrlString\n                   withOptions:(IJKFFOptions *)options;\n\n- (id)initWithMoreContent:(NSURL *)aUrl\n             withOptions:(IJKFFOptions *)options\n              withGLView:(UIView<IJKSDLGLViewProtocol> *)glView;\n\n- (id)initWithMoreContentString:(NSString *)aUrlString\n                 withOptions:(IJKFFOptions *)options\n                  withGLView:(UIView<IJKSDLGLViewProtocol> *)glView;\n\n- (void)prepareToPlay;\n- (void)play;\n- (void)pause;\n- (void)stop;\n- (BOOL)isPlaying;\n- (int64_t)trafficStatistic;\n- (float)dropFrameRate;\n\n- (void)setPauseInBackground:(BOOL)pause;\n- (BOOL)isVideoToolboxOpen;\n\n- (void)setHudValue:(NSString *)value forKey:(NSString *)key;\n\n+ (void)setLogReport:(BOOL)preferLogReport;\n+ (void)setLogLevel:(IJKLogLevel)logLevel;\n+ (BOOL)checkIfFFmpegVersionMatch:(BOOL)showAlert;\n+ (BOOL)checkIfPlayerVersionMatch:(BOOL)showAlert\n                            version:(NSString *)version;\n\n@property(nonatomic, readonly) CGFloat fpsInMeta;\n@property(nonatomic, readonly) CGFloat fpsAtOutput;\n@property(nonatomic) BOOL shouldShowHudView;\n\n- (void)setOptionValue:(NSString *)value\n                forKey:(NSString *)key\n            ofCategory:(IJKFFOptionCategory)category;\n\n- (void)setOptionIntValue:(int64_t)value\n                   forKey:(NSString *)key\n               ofCategory:(IJKFFOptionCategory)category;\n\n\n\n- (void)setFormatOptionValue:       (NSString *)value forKey:(NSString *)key;\n- (void)setCodecOptionValue:        (NSString *)value forKey:(NSString *)key;\n- (void)setSwsOptionValue:          (NSString *)value forKey:(NSString *)key;\n- (void)setPlayerOptionValue:       (NSString *)value forKey:(NSString *)key;\n\n- (void)setFormatOptionIntValue:    (int64_t)value forKey:(NSString *)key;\n- (void)setCodecOptionIntValue:     (int64_t)value forKey:(NSString *)key;\n- (void)setSwsOptionIntValue:       (int64_t)value forKey:(NSString *)key;\n- (void)setPlayerOptionIntValue:    (int64_t)value forKey:(NSString *)key;\n\n@property (nonatomic, retain) id<IJKMediaUrlOpenDelegate> segmentOpenDelegate;\n@property (nonatomic, retain) id<IJKMediaUrlOpenDelegate> tcpOpenDelegate;\n@property (nonatomic, retain) id<IJKMediaUrlOpenDelegate> httpOpenDelegate;\n@property (nonatomic, retain) id<IJKMediaUrlOpenDelegate> liveOpenDelegate;\n\n@property (nonatomic, retain) id<IJKMediaNativeInvokeDelegate> nativeInvokeDelegate;\n\n- (void)didShutdown;\n\n#pragma mark KVO properties\n@property (nonatomic, readonly) IJKFFMonitor *monitor;\n\n@end\n\n#define IJK_FF_IO_TYPE_READ (1)\nvoid IJKFFIOStatDebugCallback(const char *url, int type, int bytes);\nvoid IJKFFIOStatRegister(void (*cb)(const char *url, int type, int bytes));\n\nvoid IJKFFIOStatCompleteDebugCallback(const char *url,\n                                      int64_t read_bytes, int64_t total_size,\n                                      int64_t elpased_time, int64_t total_duration);\nvoid IJKFFIOStatCompleteRegister(void (*cb)(const char *url,\n                                            int64_t read_bytes, int64_t total_size,\n                                            int64_t elpased_time, int64_t total_duration));\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerController.m",
    "content": "/*\n * IJKFFMoviePlayerController.m\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import \"IJKFFMoviePlayerController.h\"\n\n#import <UIKit/UIKit.h>\n#import \"IJKSDLHudViewController.h\"\n#import \"IJKFFMoviePlayerDef.h\"\n#import \"IJKMediaPlayback.h\"\n#import \"IJKMediaModule.h\"\n#import \"IJKAudioKit.h\"\n#import \"IJKNotificationManager.h\"\n#import \"NSString+IJKMedia.h\"\n#import \"ijkioapplication.h\"\n#include \"string.h\"\n\nstatic const char *kIJKFFRequiredFFmpegVersion = \"ff4.0--ijk0.8.8--20201130--001\";\n\n// It means you didn't call shutdown if you found this object leaked.\n@interface IJKWeakHolder : NSObject\n@property (nonatomic, weak) id object;\n@end\n\n@implementation IJKWeakHolder\n@end\n\n@interface IJKFFMoviePlayerController()\n\n@end\n\n@implementation IJKFFMoviePlayerController {\n    IjkMediaPlayer *_mediaPlayer;\n    IJKSDLGLView *_glView;\n    IJKFFMoviePlayerMessagePool *_msgPool;\n    NSString *_urlString;\n\n    NSInteger _videoWidth;\n    NSInteger _videoHeight;\n    NSInteger _sampleAspectRatioNumerator;\n    NSInteger _sampleAspectRatioDenominator;\n\n    BOOL      _seeking;\n    NSInteger _bufferingTime;\n    NSInteger _bufferingPosition;\n\n    BOOL _keepScreenOnWhilePlaying;\n    BOOL _pauseInBackground;\n    BOOL _isVideoToolboxOpen;\n    BOOL _playingBeforeInterruption;\n\n    IJKNotificationManager *_notificationManager;\n\n    AVAppAsyncStatistic _asyncStat;\n    IjkIOAppCacheStatistic _cacheStat;\n    NSTimer *_hudTimer;\n    IJKSDLHudViewController *_hudViewController;\n}\n\n@synthesize view = _view;\n@synthesize currentPlaybackTime;\n@synthesize duration;\n@synthesize playableDuration;\n@synthesize bufferingProgress = _bufferingProgress;\n\n@synthesize numberOfBytesTransferred = _numberOfBytesTransferred;\n\n@synthesize isPreparedToPlay = _isPreparedToPlay;\n@synthesize playbackState = _playbackState;\n@synthesize loadState = _loadState;\n\n@synthesize naturalSize = _naturalSize;\n@synthesize scalingMode = _scalingMode;\n@synthesize shouldAutoplay = _shouldAutoplay;\n\n@synthesize allowsMediaAirPlay = _allowsMediaAirPlay;\n@synthesize airPlayMediaActive = _airPlayMediaActive;\n\n@synthesize isDanmakuMediaAirPlay = _isDanmakuMediaAirPlay;\n\n@synthesize monitor = _monitor;\n@synthesize shouldShowHudView           = _shouldShowHudView;\n@synthesize isSeekBuffering = _isSeekBuffering;\n@synthesize isAudioSync = _isAudioSync;\n@synthesize isVideoSync = _isVideoSync;\n\n#define FFP_IO_STAT_STEP (50 * 1024)\n\n// as an example\nvoid IJKFFIOStatDebugCallback(const char *url, int type, int bytes)\n{\n    static int64_t s_ff_io_stat_check_points = 0;\n    static int64_t s_ff_io_stat_bytes = 0;\n    if (!url)\n        return;\n\n    if (type != IJKMP_IO_STAT_READ)\n        return;\n\n    if (!av_strstart(url, \"http:\", NULL))\n        return;\n\n    s_ff_io_stat_bytes += bytes;\n    if (s_ff_io_stat_bytes < s_ff_io_stat_check_points ||\n        s_ff_io_stat_bytes > s_ff_io_stat_check_points + FFP_IO_STAT_STEP) {\n        s_ff_io_stat_check_points = s_ff_io_stat_bytes;\n        NSLog(@\"io-stat: %s, +%d = %\"PRId64\"\\n\", url, bytes, s_ff_io_stat_bytes);\n    }\n}\n\nvoid IJKFFIOStatRegister(void (*cb)(const char *url, int type, int bytes))\n{\n    ijkmp_io_stat_register(cb);\n}\n\nvoid IJKFFIOStatCompleteDebugCallback(const char *url,\n                                      int64_t read_bytes, int64_t total_size,\n                                      int64_t elpased_time, int64_t total_duration)\n{\n    if (!url)\n        return;\n\n    if (!av_strstart(url, \"http:\", NULL))\n        return;\n\n    NSLog(@\"io-stat-complete: %s, %\"PRId64\"/%\"PRId64\", %\"PRId64\"/%\"PRId64\"\\n\",\n          url, read_bytes, total_size, elpased_time, total_duration);\n}\n\nvoid IJKFFIOStatCompleteRegister(void (*cb)(const char *url,\n                                            int64_t read_bytes, int64_t total_size,\n                                            int64_t elpased_time, int64_t total_duration))\n{\n    ijkmp_io_stat_complete_register(cb);\n}\n\n- (id)initWithContentURL:(NSURL *)aUrl\n             withOptions:(IJKFFOptions *)options\n{\n    if (aUrl == nil)\n        return nil;\n\n    // Detect if URL is file path and return proper string for it\n    NSString *aUrlString = [aUrl isFileURL] ? [aUrl path] : [aUrl absoluteString];\n\n    return [self initWithContentURLString:aUrlString\n                              withOptions:options];\n}\n\n- (void)setScreenOn: (BOOL)on\n{\n    [IJKMediaModule sharedModule].mediaModuleIdleTimerDisabled = on;\n    // [UIApplication sharedApplication].idleTimerDisabled = on;\n}\n\n- (id)initWithContentURLString:(NSString *)aUrlString\n                   withOptions:(IJKFFOptions *)options\n{\n    if (aUrlString == nil)\n        return nil;\n\n    self = [super init];\n    if (self) {\n        ijkmp_global_init();\n        ijkmp_global_set_inject_callback(ijkff_inject_callback);\n\n        [IJKFFMoviePlayerController checkIfFFmpegVersionMatch:NO];\n\n        if (options == nil)\n            options = [IJKFFOptions optionsByDefault];\n\n        // IJKFFIOStatRegister(IJKFFIOStatDebugCallback);\n        // IJKFFIOStatCompleteRegister(IJKFFIOStatCompleteDebugCallback);\n\n        // init fields\n        _scalingMode = IJKMPMovieScalingModeAspectFit;\n        _shouldAutoplay = YES;\n        memset(&_asyncStat, 0, sizeof(_asyncStat));\n        memset(&_cacheStat, 0, sizeof(_cacheStat));\n        _monitor = [[IJKFFMonitor alloc] init];\n\n        // init media resource\n        _urlString = aUrlString;\n\n        // init player\n        _mediaPlayer = ijkmp_ios_create(media_player_msg_loop);\n        _msgPool = [[IJKFFMoviePlayerMessagePool alloc] init];\n        IJKWeakHolder *weakHolder = [IJKWeakHolder new];\n        weakHolder.object = self;\n\n        ijkmp_set_weak_thiz(_mediaPlayer, (__bridge_retained void *) self);\n        ijkmp_set_inject_opaque(_mediaPlayer, (__bridge_retained void *) weakHolder);\n        ijkmp_set_ijkio_inject_opaque(_mediaPlayer, (__bridge_retained void *)weakHolder);\n        ijkmp_set_option_int(_mediaPlayer, IJKMP_OPT_CATEGORY_PLAYER, \"start-on-prepared\", _shouldAutoplay ? 1 : 0);\n\n        // init video sink\n        _glView = [[IJKSDLGLView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];\n        _glView.isThirdGLView = NO;\n        _view = _glView;\n        _hudViewController = [[IJKSDLHudViewController alloc] init];\n        [_hudViewController setRect:_glView.frame];\n        _shouldShowHudView = NO;\n        _hudViewController.tableView.hidden = YES;\n        [_view addSubview:_hudViewController.tableView];\n\n        [self setHudValue:nil forKey:@\"scheme\"];\n        [self setHudValue:nil forKey:@\"host\"];\n        [self setHudValue:nil forKey:@\"path\"];\n        [self setHudValue:nil forKey:@\"ip\"];\n        [self setHudValue:nil forKey:@\"tcp-info\"];\n        [self setHudValue:nil forKey:@\"http\"];\n        [self setHudValue:nil forKey:@\"tcp-spd\"];\n        [self setHudValue:nil forKey:@\"t-prepared\"];\n        [self setHudValue:nil forKey:@\"t-render\"];\n        [self setHudValue:nil forKey:@\"t-preroll\"];\n        [self setHudValue:nil forKey:@\"t-http-open\"];\n        [self setHudValue:nil forKey:@\"t-http-seek\"];\n        \n        self.shouldShowHudView = options.showHudView;\n\n        ijkmp_ios_set_glview(_mediaPlayer, _glView);\n        ijkmp_set_option(_mediaPlayer, IJKMP_OPT_CATEGORY_PLAYER, \"overlay-format\", \"fcc-_es2\");\n#ifdef DEBUG\n        [IJKFFMoviePlayerController setLogLevel:k_IJK_LOG_DEBUG];\n#else\n        [IJKFFMoviePlayerController setLogLevel:k_IJK_LOG_SILENT];\n#endif\n        // init audio sink\n        [[IJKAudioKit sharedInstance] setupAudioSession];\n\n        [options applyTo:_mediaPlayer];\n        _pauseInBackground = NO;\n\n        // init extra\n        _keepScreenOnWhilePlaying = YES;\n        [self setScreenOn:YES];\n\n        _notificationManager = [[IJKNotificationManager alloc] init];\n        [self registerApplicationObservers];\n    }\n    return self;\n}\n\n- (id)initWithMoreContent:(NSURL *)aUrl\n              withOptions:(IJKFFOptions *)options\n               withGLView:(UIView<IJKSDLGLViewProtocol> *)glView\n{\n    if (aUrl == nil)\n        return nil;\n\n    // Detect if URL is file path and return proper string for it\n    NSString *aUrlString = [aUrl isFileURL] ? [aUrl path] : [aUrl absoluteString];\n\n    return [self initWithMoreContentString:aUrlString\n                              withOptions:options\n                               withGLView:glView];\n}\n\n- (id)initWithMoreContentString:(NSString *)aUrlString\n                 withOptions:(IJKFFOptions *)options\n                  withGLView:(UIView <IJKSDLGLViewProtocol> *)glView\n{\n    if (aUrlString == nil || glView == nil)\n        return nil;\n\n    self = [super init];\n    if (self) {\n        ijkmp_global_init();\n        ijkmp_global_set_inject_callback(ijkff_inject_callback);\n\n        [IJKFFMoviePlayerController checkIfFFmpegVersionMatch:NO];\n\n        if (options == nil)\n            options = [IJKFFOptions optionsByDefault];\n\n        // IJKFFIOStatRegister(IJKFFIOStatDebugCallback);\n        // IJKFFIOStatCompleteRegister(IJKFFIOStatCompleteDebugCallback);\n\n        // init fields\n        _scalingMode = IJKMPMovieScalingModeAspectFit;\n        _shouldAutoplay = YES;\n        memset(&_asyncStat, 0, sizeof(_asyncStat));\n        memset(&_cacheStat, 0, sizeof(_cacheStat));\n        _monitor = [[IJKFFMonitor alloc] init];\n\n        // init media resource\n        _urlString = aUrlString;\n\n        // init player\n        _mediaPlayer = ijkmp_ios_create(media_player_msg_loop);\n        _msgPool = [[IJKFFMoviePlayerMessagePool alloc] init];\n        IJKWeakHolder *weakHolder = [IJKWeakHolder new];\n        weakHolder.object = self;\n\n        ijkmp_set_weak_thiz(_mediaPlayer, (__bridge_retained void *) self);\n        ijkmp_set_inject_opaque(_mediaPlayer, (__bridge_retained void *) weakHolder);\n        ijkmp_set_ijkio_inject_opaque(_mediaPlayer, (__bridge_retained void *)weakHolder);\n        ijkmp_set_option_int(_mediaPlayer, IJKMP_OPT_CATEGORY_PLAYER, \"start-on-prepared\", _shouldAutoplay ? 1 : 0);\n\n        self.shouldShowHudView = options.showHudView;\n        glView.isThirdGLView = YES;\n        _view = _glView = (IJKSDLGLView *)glView;\n        _hudViewController = [[IJKSDLHudViewController alloc] init];\n        [_hudViewController setRect:_glView.frame];\n        _shouldShowHudView = NO;\n        _hudViewController.tableView.hidden = YES;\n        [_view addSubview:_hudViewController.tableView];\n\n        [self setHudValue:nil forKey:@\"scheme\"];\n        [self setHudValue:nil forKey:@\"host\"];\n        [self setHudValue:nil forKey:@\"path\"];\n        [self setHudValue:nil forKey:@\"ip\"];\n        [self setHudValue:nil forKey:@\"tcp-info\"];\n        [self setHudValue:nil forKey:@\"http\"];\n        [self setHudValue:nil forKey:@\"tcp-spd\"];\n        [self setHudValue:nil forKey:@\"t-prepared\"];\n        [self setHudValue:nil forKey:@\"t-render\"];\n        [self setHudValue:nil forKey:@\"t-preroll\"];\n        [self setHudValue:nil forKey:@\"t-http-open\"];\n        [self setHudValue:nil forKey:@\"t-http-seek\"];\n        self.shouldShowHudView = options.showHudView;\n\n        ijkmp_ios_set_glview(_mediaPlayer, _glView);\n\n        ijkmp_set_option(_mediaPlayer, IJKMP_OPT_CATEGORY_PLAYER, \"overlay-format\", \"fcc-_es2\");\n#ifdef DEBUG\n        [IJKFFMoviePlayerController setLogLevel:k_IJK_LOG_DEBUG];\n#else\n        [IJKFFMoviePlayerController setLogLevel:k_IJK_LOG_SILENT];\n#endif\n        // init audio sink\n        [[IJKAudioKit sharedInstance] setupAudioSession];\n\n        [options applyTo:_mediaPlayer];\n        _pauseInBackground = NO;\n\n        // init extra\n        _keepScreenOnWhilePlaying = YES;\n        [self setScreenOn:YES];\n\n        _notificationManager = [[IJKNotificationManager alloc] init];\n        [self registerApplicationObservers];\n    }\n    return self;\n}\n\n- (void)dealloc\n{\n//    [self unregisterApplicationObservers];\n}\n\n- (void)setShouldAutoplay:(BOOL)shouldAutoplay\n{\n    _shouldAutoplay = shouldAutoplay;\n\n    if (!_mediaPlayer)\n        return;\n\n    ijkmp_set_option_int(_mediaPlayer, IJKMP_OPT_CATEGORY_PLAYER, \"start-on-prepared\", _shouldAutoplay ? 1 : 0);\n}\n\n- (BOOL)shouldAutoplay\n{\n    return _shouldAutoplay;\n}\n\n- (void)prepareToPlay\n{\n    if (!_mediaPlayer)\n        return;\n\n    [self setScreenOn:_keepScreenOnWhilePlaying];\n\n    ijkmp_set_data_source(_mediaPlayer, [_urlString UTF8String]);\n    ijkmp_set_option(_mediaPlayer, IJKMP_OPT_CATEGORY_FORMAT, \"safe\", \"0\"); // for concat demuxer\n\n    _monitor.prepareStartTick = (int64_t)SDL_GetTickHR();\n    ijkmp_prepare_async(_mediaPlayer);\n}\n\n- (void)setHudUrl:(NSString *)urlString\n{\n    if ([[NSThread currentThread] isMainThread]) {\n        NSURL *url = [NSURL URLWithString:urlString];\n        [self setHudValue:url.scheme forKey:@\"scheme\"];\n        [self setHudValue:url.host   forKey:@\"host\"];\n        [self setHudValue:url.path   forKey:@\"path\"];\n    } else {\n        dispatch_async(dispatch_get_main_queue(), ^{\n            [self setHudUrl:urlString];\n        });\n    }\n}\n\n- (void)play\n{\n    if (!_mediaPlayer)\n        return;\n\n    [self setScreenOn:_keepScreenOnWhilePlaying];\n\n    [self startHudTimer];\n    ijkmp_start(_mediaPlayer);\n}\n\n- (void)pause\n{\n    if (!_mediaPlayer)\n        return;\n\n//    [self stopHudTimer];\n    ijkmp_pause(_mediaPlayer);\n}\n\n- (void)stop\n{\n    if (!_mediaPlayer)\n        return;\n\n    [self setScreenOn:NO];\n\n    [self stopHudTimer];\n    ijkmp_stop(_mediaPlayer);\n}\n\n- (BOOL)isPlaying\n{\n    if (!_mediaPlayer)\n        return NO;\n\n    return ijkmp_is_playing(_mediaPlayer);\n}\n\n- (void)setPauseInBackground:(BOOL)pause\n{\n    _pauseInBackground = pause;\n}\n\n- (BOOL)isVideoToolboxOpen\n{\n    if (!_mediaPlayer)\n        return NO;\n\n    return _isVideoToolboxOpen;\n}\n\ninline static int getPlayerOption(IJKFFOptionCategory category)\n{\n    int mp_category = -1;\n    switch (category) {\n        case kIJKFFOptionCategoryFormat:\n            mp_category = IJKMP_OPT_CATEGORY_FORMAT;\n            break;\n        case kIJKFFOptionCategoryCodec:\n            mp_category = IJKMP_OPT_CATEGORY_CODEC;\n            break;\n        case kIJKFFOptionCategorySws:\n            mp_category = IJKMP_OPT_CATEGORY_SWS;\n            break;\n        case kIJKFFOptionCategoryPlayer:\n            mp_category = IJKMP_OPT_CATEGORY_PLAYER;\n            break;\n        default:\n            NSLog(@\"unknown option category: %d\\n\", category);\n    }\n    return mp_category;\n}\n\n- (void)setOptionValue:(NSString *)value\n                forKey:(NSString *)key\n            ofCategory:(IJKFFOptionCategory)category\n{\n    assert(_mediaPlayer);\n    if (!_mediaPlayer)\n        return;\n\n    ijkmp_set_option(_mediaPlayer, getPlayerOption(category), [key UTF8String], [value UTF8String]);\n}\n\n- (void)setOptionIntValue:(int64_t)value\n                   forKey:(NSString *)key\n               ofCategory:(IJKFFOptionCategory)category\n{\n    assert(_mediaPlayer);\n    if (!_mediaPlayer)\n        return;\n\n    ijkmp_set_option_int(_mediaPlayer, getPlayerOption(category), [key UTF8String], value);\n}\n\n+ (void)setLogReport:(BOOL)preferLogReport\n{\n    ijkmp_global_set_log_report(preferLogReport ? 1 : 0);\n}\n\n+ (void)setLogLevel:(IJKLogLevel)logLevel\n{\n    ijkmp_global_set_log_level(logLevel);\n}\n\n+ (BOOL)checkIfFFmpegVersionMatch:(BOOL)showAlert;\n{\n    const char *actualVersion = av_version_info();\n    const char *expectVersion = kIJKFFRequiredFFmpegVersion;\n    if (0 == strcmp(actualVersion, expectVersion)) {\n        return YES;\n    } else {\n        NSString *message = [NSString stringWithFormat:@\"actual: %s\\n expect: %s\\n\", actualVersion, expectVersion];\n        NSLog(@\"\\n!!!!!!!!!!\\n%@\\n!!!!!!!!!!\\n\", message);\n        if (showAlert) {\n            UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@\"Unexpected FFmpeg version\"\n                                                                message:message\n                                                               delegate:nil\n                                                      cancelButtonTitle:@\"OK\"\n                                                      otherButtonTitles:nil];\n            [alertView show];\n        }\n        return NO;\n    }\n}\n\n+ (BOOL)checkIfPlayerVersionMatch:(BOOL)showAlert\n                          version:(NSString *)version\n{\n    const char *actualVersion = ijkmp_version();\n    const char *expectVersion = version.UTF8String;\n    if (0 == strcmp(actualVersion, expectVersion)) {\n        return YES;\n    } else {\n        if (showAlert) {\n            NSString *message = [NSString stringWithFormat:@\"actual: %s\\n expect: %s\\n\",\n                                 actualVersion, expectVersion];\n            UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@\"Unexpected ijkplayer version\"\n                                                                message:message\n                                                               delegate:nil\n                                                      cancelButtonTitle:@\"OK\"\n                                                      otherButtonTitles:nil];\n            [alertView show];\n        }\n        return NO;\n    }\n}\n\n- (void)shutdown\n{\n    if (!_mediaPlayer)\n        return;\n\n    [self stopHudTimer];\n    [self unregisterApplicationObservers];\n    [self setScreenOn:NO];\n\n    [self performSelectorInBackground:@selector(shutdownWaitStop:) withObject:self];\n}\n\n- (void)shutdownWaitStop:(IJKFFMoviePlayerController *) mySelf\n{\n    if (!_mediaPlayer)\n        return;\n\n    ijkmp_stop(_mediaPlayer);\n    ijkmp_shutdown(_mediaPlayer);\n\n    [self performSelectorOnMainThread:@selector(shutdownClose:) withObject:self waitUntilDone:YES];\n}\n\n- (void)shutdownClose:(IJKFFMoviePlayerController *) mySelf\n{\n    if (!_mediaPlayer)\n        return;\n\n    _segmentOpenDelegate    = nil;\n    _tcpOpenDelegate        = nil;\n    _httpOpenDelegate       = nil;\n    _liveOpenDelegate       = nil;\n    _nativeInvokeDelegate   = nil;\n\n    __unused id weakPlayer = (__bridge_transfer IJKFFMoviePlayerController*)ijkmp_set_weak_thiz(_mediaPlayer, NULL);\n    __unused id weakHolder = (__bridge_transfer IJKWeakHolder*)ijkmp_set_inject_opaque(_mediaPlayer, NULL);\n    __unused id weakijkHolder = (__bridge_transfer IJKWeakHolder*)ijkmp_set_ijkio_inject_opaque(_mediaPlayer, NULL);\n    ijkmp_dec_ref_p(&_mediaPlayer);\n\n    [self didShutdown];\n}\n\n- (void)didShutdown\n{\n}\n\n- (IJKMPMoviePlaybackState)playbackState\n{\n    if (!_mediaPlayer)\n        return NO;\n\n    IJKMPMoviePlaybackState mpState = IJKMPMoviePlaybackStateStopped;\n    int state = ijkmp_get_state(_mediaPlayer);\n    switch (state) {\n        case MP_STATE_STOPPED:\n        case MP_STATE_COMPLETED:\n        case MP_STATE_ERROR:\n        case MP_STATE_END:\n            mpState = IJKMPMoviePlaybackStateStopped;\n            break;\n        case MP_STATE_IDLE:\n        case MP_STATE_INITIALIZED:\n        case MP_STATE_ASYNC_PREPARING:\n        case MP_STATE_PAUSED:\n            mpState = IJKMPMoviePlaybackStatePaused;\n            break;\n        case MP_STATE_PREPARED:\n        case MP_STATE_STARTED: {\n            if (_seeking)\n                mpState = IJKMPMoviePlaybackStateSeekingForward;\n            else\n                mpState = IJKMPMoviePlaybackStatePlaying;\n            break;\n        }\n    }\n    // IJKMPMoviePlaybackStatePlaying,\n    // IJKMPMoviePlaybackStatePaused,\n    // IJKMPMoviePlaybackStateStopped,\n    // IJKMPMoviePlaybackStateInterrupted,\n    // IJKMPMoviePlaybackStateSeekingForward,\n    // IJKMPMoviePlaybackStateSeekingBackward\n    return mpState;\n}\n\n- (void)setCurrentPlaybackTime:(NSTimeInterval)aCurrentPlaybackTime\n{\n    if (!_mediaPlayer)\n        return;\n\n    _seeking = YES;\n    [[NSNotificationCenter defaultCenter]\n     postNotificationName:IJKMPMoviePlayerPlaybackStateDidChangeNotification\n     object:self];\n\n    _bufferingPosition = 0;\n    ijkmp_seek_to(_mediaPlayer, aCurrentPlaybackTime * 1000);\n}\n\n- (NSTimeInterval)currentPlaybackTime\n{\n    if (!_mediaPlayer)\n        return 0.0f;\n\n    NSTimeInterval ret = ijkmp_get_current_position(_mediaPlayer);\n    if (isnan(ret) || isinf(ret))\n        return -1;\n\n    return ret / 1000;\n}\n\n- (NSTimeInterval)duration\n{\n    if (!_mediaPlayer)\n        return 0.0f;\n\n    NSTimeInterval ret = ijkmp_get_duration(_mediaPlayer);\n    if (isnan(ret) || isinf(ret))\n        return -1;\n\n    return ret / 1000;\n}\n\n- (NSTimeInterval)playableDuration\n{\n    if (!_mediaPlayer)\n        return 0.0f;\n\n    NSTimeInterval demux_cache = ((NSTimeInterval)ijkmp_get_playable_duration(_mediaPlayer)) / 1000;\n\n    int64_t buf_forwards = _asyncStat.buf_forwards;\n    int64_t bit_rate = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_BIT_RATE, 0);\n\n    if (buf_forwards > 0 && bit_rate > 0) {\n        NSTimeInterval io_cache = ((float)buf_forwards) * 8 / bit_rate;\n        demux_cache += io_cache;\n    }\n\n    return demux_cache;\n}\n\n- (CGSize)naturalSize\n{\n    return _naturalSize;\n}\n\n- (void)changeNaturalSize\n{\n    [self willChangeValueForKey:@\"naturalSize\"];\n    if (_sampleAspectRatioNumerator > 0 && _sampleAspectRatioDenominator > 0) {\n        self->_naturalSize = CGSizeMake(1.0f * _videoWidth * _sampleAspectRatioNumerator / _sampleAspectRatioDenominator, _videoHeight);\n    } else {\n        self->_naturalSize = CGSizeMake(_videoWidth, _videoHeight);\n    }\n    [self didChangeValueForKey:@\"naturalSize\"];\n\n    if (self->_naturalSize.width > 0 && self->_naturalSize.height > 0) {\n        [[NSNotificationCenter defaultCenter]\n         postNotificationName:IJKMPMovieNaturalSizeAvailableNotification\n         object:self];\n    }\n}\n\n- (void)setScalingMode: (IJKMPMovieScalingMode) aScalingMode\n{\n    IJKMPMovieScalingMode newScalingMode = aScalingMode;\n    switch (aScalingMode) {\n        case IJKMPMovieScalingModeNone:\n            [_view setContentMode:UIViewContentModeCenter];\n            break;\n        case IJKMPMovieScalingModeAspectFit:\n            [_view setContentMode:UIViewContentModeScaleAspectFit];\n            break;\n        case IJKMPMovieScalingModeAspectFill:\n            [_view setContentMode:UIViewContentModeScaleAspectFill];\n            break;\n        case IJKMPMovieScalingModeFill:\n            [_view setContentMode:UIViewContentModeScaleToFill];\n            break;\n        default:\n            newScalingMode = _scalingMode;\n    }\n\n    _scalingMode = newScalingMode;\n}\n\n// deprecated, for MPMoviePlayerController compatiable\n- (UIImage *)thumbnailImageAtTime:(NSTimeInterval)playbackTime timeOption:(IJKMPMovieTimeOption)option\n{\n    return nil;\n}\n\n- (UIImage *)thumbnailImageAtCurrentTime\n{\n    if ([_view conformsToProtocol:@protocol(IJKSDLGLViewProtocol)]) {\n        id<IJKSDLGLViewProtocol> glView = (id<IJKSDLGLViewProtocol>)_view;\n        return [glView snapshot];\n    }\n\n    return nil;\n}\n\n- (CGFloat)fpsAtOutput\n{\n    return _glView.fps;\n}\n\ninline static NSString *formatedDurationMilli(int64_t duration) {\n    if (duration >=  1000) {\n        return [NSString stringWithFormat:@\"%.2f sec\", ((float)duration) / 1000];\n    } else {\n        return [NSString stringWithFormat:@\"%ld msec\", (long)duration];\n    }\n}\n\ninline static NSString *formatedDurationBytesAndBitrate(int64_t bytes, int64_t bitRate) {\n    if (bitRate <= 0) {\n        return @\"inf\";\n    }\n    return formatedDurationMilli(((float)bytes) * 8 * 1000 / bitRate);\n}\n\ninline static NSString *formatedSize(int64_t bytes) {\n    if (bytes >= 100 * 1024) {\n        return [NSString stringWithFormat:@\"%.2f MB\", ((float)bytes) / 1000 / 1024];\n    } else if (bytes >= 100) {\n        return [NSString stringWithFormat:@\"%.1f KB\", ((float)bytes) / 1000];\n    } else {\n        return [NSString stringWithFormat:@\"%ld B\", (long)bytes];\n    }\n}\n\ninline static NSString *formatedSpeed(int64_t bytes, int64_t elapsed_milli) {\n    if (elapsed_milli <= 0) {\n        return @\"N/A\";\n    }\n\n    if (bytes <= 0) {\n        return @\"0\";\n    }\n\n    float bytes_per_sec = ((float)bytes) * 1000.f /  elapsed_milli;\n    if (bytes_per_sec >= 1000 * 1000) {\n        return [NSString stringWithFormat:@\"%.2f MB/s\", ((float)bytes_per_sec) / 1000 / 1000];\n    } else if (bytes_per_sec >= 1000) {\n        return [NSString stringWithFormat:@\"%.1f KB/s\", ((float)bytes_per_sec) / 1000];\n    } else {\n        return [NSString stringWithFormat:@\"%ld B/s\", (long)bytes_per_sec];\n    }\n}\n\n- (void)refreshHudView\n{\n    if (_mediaPlayer == nil)\n        return;\n\n    int64_t vdec = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_VIDEO_DECODER, FFP_PROPV_DECODER_UNKNOWN);\n    float   vdps = ijkmp_get_property_float(_mediaPlayer, FFP_PROP_FLOAT_VIDEO_DECODE_FRAMES_PER_SECOND, .0f);\n    float   vfps = ijkmp_get_property_float(_mediaPlayer, FFP_PROP_FLOAT_VIDEO_OUTPUT_FRAMES_PER_SECOND, .0f);\n\n    switch (vdec) {\n        case FFP_PROPV_DECODER_VIDEOTOOLBOX:\n            [self setHudValue:@\"VideoToolbox\" forKey:@\"vdec\"];\n            break;\n        case FFP_PROPV_DECODER_AVCODEC:\n            [self setHudValue:[NSString stringWithFormat:@\"avcodec %d.%d.%d\",\n                                  LIBAVCODEC_VERSION_MAJOR,\n                                  LIBAVCODEC_VERSION_MINOR,\n                                  LIBAVCODEC_VERSION_MICRO]\n                          forKey:@\"vdec\"];\n            break;\n        default:\n            [self setHudValue:@\"N/A\" forKey:@\"vdec\"];\n            break;\n    }\n\n    [self setHudValue:[NSString stringWithFormat:@\"%.2f / %.2f\", vdps, vfps] forKey:@\"fps\"];\n\n    int64_t vcacheb = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_VIDEO_CACHED_BYTES, 0);\n    int64_t acacheb = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_AUDIO_CACHED_BYTES, 0);\n    int64_t vcached = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_VIDEO_CACHED_DURATION, 0);\n    int64_t acached = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_AUDIO_CACHED_DURATION, 0);\n    int64_t vcachep = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_VIDEO_CACHED_PACKETS, 0);\n    int64_t acachep = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_AUDIO_CACHED_PACKETS, 0);\n    [self setHudValue:[NSString stringWithFormat:@\"%@, %@, %\"PRId64\" packets\",\n                          formatedDurationMilli(vcached),\n                          formatedSize(vcacheb),\n                          vcachep]\n                  forKey:@\"v-cache\"];\n    [self setHudValue:[NSString stringWithFormat:@\"%@, %@, %\"PRId64\" packets\",\n                          formatedDurationMilli(acached),\n                          formatedSize(acacheb),\n                          acachep]\n                  forKey:@\"a-cache\"];\n\n    float avdelay = ijkmp_get_property_float(_mediaPlayer, FFP_PROP_FLOAT_AVDELAY, .0f);\n    float avdiff  = ijkmp_get_property_float(_mediaPlayer, FFP_PROP_FLOAT_AVDIFF, .0f);\n    [self setHudValue:[NSString stringWithFormat:@\"%.3f %.3f\", avdelay, -avdiff] forKey:@\"delay\"];\n\n    int64_t bitRate = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_BIT_RATE, 0);\n    [self setHudValue:[NSString stringWithFormat:@\"-%@, %@\",\n                         formatedSize(_cacheStat.cache_file_forwards),\n                          formatedDurationBytesAndBitrate(_cacheStat.cache_file_forwards, bitRate)] forKey:@\"cache-forwards\"];\n    [self setHudValue:formatedSize(_cacheStat.cache_physical_pos) forKey:@\"cache-physical-pos\"];\n    [self setHudValue:formatedSize(_cacheStat.cache_file_pos) forKey:@\"cache-file-pos\"];\n    [self setHudValue:formatedSize(_cacheStat.cache_count_bytes) forKey:@\"cache-bytes\"];\n    [self setHudValue:[NSString stringWithFormat:@\"-%@, %@\",\n                          formatedSize(_asyncStat.buf_backwards),\n                          formatedDurationBytesAndBitrate(_asyncStat.buf_backwards, bitRate)]\n                  forKey:@\"async-backward\"];\n    [self setHudValue:[NSString stringWithFormat:@\"+%@, %@\",\n                          formatedSize(_asyncStat.buf_forwards),\n                          formatedDurationBytesAndBitrate(_asyncStat.buf_forwards, bitRate)]\n                  forKey:@\"async-forward\"];\n\n    int64_t tcpSpeed = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_TCP_SPEED, 0);\n    [self setHudValue:[NSString stringWithFormat:@\"%@\", formatedSpeed(tcpSpeed, 1000)]\n                  forKey:@\"tcp-spd\"];\n\n    [self setHudValue:formatedDurationMilli(_monitor.prepareDuration) forKey:@\"t-prepared\"];\n    [self setHudValue:formatedDurationMilli(_monitor.firstVideoFrameLatency) forKey:@\"t-render\"];\n    [self setHudValue:formatedDurationMilli(_monitor.lastPrerollDuration) forKey:@\"t-preroll\"];\n    [self setHudValue:[NSString stringWithFormat:@\"%@ / %d\",\n                          formatedDurationMilli(_monitor.lastHttpOpenDuration),\n                          _monitor.httpOpenCount]\n                  forKey:@\"t-http-open\"];\n    [self setHudValue:[NSString stringWithFormat:@\"%@ / %d\",\n                          formatedDurationMilli(_monitor.lastHttpSeekDuration),\n                          _monitor.httpSeekCount]\n                  forKey:@\"t-http-seek\"];\n}\n\n- (void)startHudTimer\n{\n    if (!_shouldShowHudView)\n        return;\n\n    if (_hudTimer != nil)\n        return;\n\n    if ([[NSThread currentThread] isMainThread]) {\n        _hudViewController.tableView.hidden = NO;\n        _hudTimer = [NSTimer scheduledTimerWithTimeInterval:.5f\n                                                     target:self\n                                                   selector:@selector(refreshHudView)\n                                                   userInfo:nil\n                                                    repeats:YES];\n    } else {\n        dispatch_async(dispatch_get_main_queue(), ^{\n            [self startHudTimer];\n        });\n    }\n}\n\n- (void)stopHudTimer\n{\n    if (_hudTimer == nil)\n        return;\n\n    if ([[NSThread currentThread] isMainThread]) {\n        _hudViewController.tableView.hidden = YES;\n        [_hudTimer invalidate];\n        _hudTimer = nil;\n    } else {\n        dispatch_async(dispatch_get_main_queue(), ^{\n            [self stopHudTimer];\n        });\n    }\n}\n\n- (void)setShouldShowHudView:(BOOL)shouldShowHudView\n{\n    if (shouldShowHudView == _shouldShowHudView) {\n        return;\n    }\n    _shouldShowHudView = shouldShowHudView;\n    if (shouldShowHudView)\n        [self startHudTimer];\n    else\n        [self stopHudTimer];\n}\n\n- (BOOL)shouldShowHudView\n{\n    return _shouldShowHudView;\n}\n\n- (void)setPlaybackRate:(float)playbackRate\n{\n    if (!_mediaPlayer)\n        return;\n\n    return ijkmp_set_playback_rate(_mediaPlayer, playbackRate);\n}\n\n- (float)playbackRate\n{\n    if (!_mediaPlayer)\n        return 0.0f;\n\n    return ijkmp_get_property_float(_mediaPlayer, FFP_PROP_FLOAT_PLAYBACK_RATE, 0.0f);\n}\n\n- (void)setPlaybackVolume:(float)volume\n{\n    if (!_mediaPlayer)\n        return;\n    return ijkmp_set_playback_volume(_mediaPlayer, volume);\n}\n\n- (float)playbackVolume\n{\n    if (!_mediaPlayer)\n        return 0.0f;\n    return ijkmp_get_property_float(_mediaPlayer, FFP_PROP_FLOAT_PLAYBACK_VOLUME, 1.0f);\n}\n\n- (int64_t)getFileSize\n{\n    if (!_mediaPlayer)\n        return 0;\n    return ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_LOGICAL_FILE_SIZE, 0);\n}\n\n- (int64_t)trafficStatistic\n{\n    if (!_mediaPlayer)\n        return 0;\n    return ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_TRAFFIC_STATISTIC_BYTE_COUNT, 0);\n}\n\n- (float)dropFrameRate\n{\n    if (!_mediaPlayer)\n        return 0;\n    return ijkmp_get_property_float(_mediaPlayer, FFP_PROP_FLOAT_DROP_FRAME_RATE, 0.0f);\n}\n\ninline static void fillMetaInternal(NSMutableDictionary *meta, IjkMediaMeta *rawMeta, const char *name, NSString *defaultValue)\n{\n    if (!meta || !rawMeta || !name)\n        return;\n\n    NSString *key = [NSString stringWithUTF8String:name];\n    const char *value = ijkmeta_get_string_l(rawMeta, name);\n    if (value) {\n        [meta setObject:[NSString stringWithUTF8String:value] forKey:key];\n    } else if (defaultValue) {\n        [meta setObject:defaultValue forKey:key];\n    } else {\n        [meta removeObjectForKey:key];\n    }\n}\n\n- (void)postEvent: (IJKFFMoviePlayerMessage *)msg\n{\n    if (!msg)\n        return;\n\n    AVMessage *avmsg = &msg->_msg;\n    switch (avmsg->what) {\n        case FFP_MSG_FLUSH:\n            break;\n        case FFP_MSG_ERROR: {\n            NSLog(@\"FFP_MSG_ERROR: %d\\n\", avmsg->arg1);\n\n            [self setScreenOn:NO];\n\n            [[NSNotificationCenter defaultCenter]\n             postNotificationName:IJKMPMoviePlayerPlaybackStateDidChangeNotification\n             object:self];\n\n            [[NSNotificationCenter defaultCenter]\n                postNotificationName:IJKMPMoviePlayerPlaybackDidFinishNotification\n                object:self\n                userInfo:@{\n                    IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey: @(IJKMPMovieFinishReasonPlaybackError),\n                    @\"error\": @(avmsg->arg1)}];\n            break;\n        }\n        case FFP_MSG_PREPARED: {\n            NSLog(@\"FFP_MSG_PREPARED:\\n\");\n\n            _monitor.prepareDuration = (int64_t)SDL_GetTickHR() - _monitor.prepareStartTick;\n            int64_t vdec = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_VIDEO_DECODER, FFP_PROPV_DECODER_UNKNOWN);\n            switch (vdec) {\n                case FFP_PROPV_DECODER_VIDEOTOOLBOX:\n                    _monitor.vdecoder = @\"VideoToolbox\";\n                    break;\n                case FFP_PROPV_DECODER_AVCODEC:\n                    _monitor.vdecoder = [NSString stringWithFormat:@\"avcodec %d.%d.%d\",\n                                         LIBAVCODEC_VERSION_MAJOR,\n                                         LIBAVCODEC_VERSION_MINOR,\n                                         LIBAVCODEC_VERSION_MICRO];\n                    break;\n                default:\n                    _monitor.vdecoder = @\"Unknown\";\n                    break;\n            }\n\n            IjkMediaMeta *rawMeta = ijkmp_get_meta_l(_mediaPlayer);\n            if (rawMeta) {\n                ijkmeta_lock(rawMeta);\n\n                NSMutableDictionary *newMediaMeta = [[NSMutableDictionary alloc] init];\n\n                fillMetaInternal(newMediaMeta, rawMeta, IJKM_KEY_FORMAT, nil);\n                fillMetaInternal(newMediaMeta, rawMeta, IJKM_KEY_DURATION_US, nil);\n                fillMetaInternal(newMediaMeta, rawMeta, IJKM_KEY_START_US, nil);\n                fillMetaInternal(newMediaMeta, rawMeta, IJKM_KEY_BITRATE, nil);\n\n                fillMetaInternal(newMediaMeta, rawMeta, IJKM_KEY_VIDEO_STREAM, nil);\n                fillMetaInternal(newMediaMeta, rawMeta, IJKM_KEY_AUDIO_STREAM, nil);\n\n                int64_t video_stream = ijkmeta_get_int64_l(rawMeta, IJKM_KEY_VIDEO_STREAM, -1);\n                int64_t audio_stream = ijkmeta_get_int64_l(rawMeta, IJKM_KEY_AUDIO_STREAM, -1);\n\n                NSMutableArray *streams = [[NSMutableArray alloc] init];\n\n                size_t count = ijkmeta_get_children_count_l(rawMeta);\n                for(size_t i = 0; i < count; ++i) {\n                    IjkMediaMeta *streamRawMeta = ijkmeta_get_child_l(rawMeta, i);\n                    NSMutableDictionary *streamMeta = [[NSMutableDictionary alloc] init];\n\n                    if (streamRawMeta) {\n                        fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_TYPE, k_IJKM_VAL_TYPE__UNKNOWN);\n                        const char *type = ijkmeta_get_string_l(streamRawMeta, IJKM_KEY_TYPE);\n                        if (type) {\n                            fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_CODEC_NAME, nil);\n                            fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_CODEC_PROFILE, nil);\n                            fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_CODEC_LONG_NAME, nil);\n                            fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_BITRATE, nil);\n\n                            if (0 == strcmp(type, IJKM_VAL_TYPE__VIDEO)) {\n                                fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_WIDTH, nil);\n                                fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_HEIGHT, nil);\n                                fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_FPS_NUM, nil);\n                                fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_FPS_DEN, nil);\n                                fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_TBR_NUM, nil);\n                                fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_TBR_DEN, nil);\n                                fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_SAR_NUM, nil);\n                                fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_SAR_DEN, nil);\n\n                                if (video_stream == i) {\n                                    _monitor.videoMeta = streamMeta;\n\n                                    int64_t fps_num = ijkmeta_get_int64_l(streamRawMeta, IJKM_KEY_FPS_NUM, 0);\n                                    int64_t fps_den = ijkmeta_get_int64_l(streamRawMeta, IJKM_KEY_FPS_DEN, 0);\n                                    if (fps_num > 0 && fps_den > 0) {\n                                        _fpsInMeta = ((CGFloat)(fps_num)) / fps_den;\n                                        NSLog(@\"fps in meta %f\\n\", _fpsInMeta);\n                                    }\n                                }\n\n                            } else if (0 == strcmp(type, IJKM_VAL_TYPE__AUDIO)) {\n                                fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_SAMPLE_RATE, nil);\n                                fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_CHANNEL_LAYOUT, nil);\n\n                                if (audio_stream == i) {\n                                    _monitor.audioMeta = streamMeta;\n                                }\n                            }\n                        }\n                    }\n\n                    [streams addObject:streamMeta];\n                }\n\n                [newMediaMeta setObject:streams forKey:kk_IJKM_KEY_STREAMS];\n\n                ijkmeta_unlock(rawMeta);\n                _monitor.mediaMeta = newMediaMeta;\n            }\n            ijkmp_set_playback_rate(_mediaPlayer, [self playbackRate]);\n            ijkmp_set_playback_volume(_mediaPlayer, [self playbackVolume]);\n\n            [self startHudTimer];\n            _isPreparedToPlay = YES;\n\n            [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification object:self];\n            _loadState = IJKMPMovieLoadStatePlayable | IJKMPMovieLoadStatePlaythroughOK;\n\n            [[NSNotificationCenter defaultCenter]\n             postNotificationName:IJKMPMoviePlayerLoadStateDidChangeNotification\n             object:self];\n\n            break;\n        }\n        case FFP_MSG_COMPLETED: {\n\n            [self setScreenOn:NO];\n\n            [[NSNotificationCenter defaultCenter]\n             postNotificationName:IJKMPMoviePlayerPlaybackStateDidChangeNotification\n             object:self];\n\n            [[NSNotificationCenter defaultCenter]\n             postNotificationName:IJKMPMoviePlayerPlaybackDidFinishNotification\n             object:self\n             userInfo:@{IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey: @(IJKMPMovieFinishReasonPlaybackEnded)}];\n            break;\n        }\n        case FFP_MSG_VIDEO_SIZE_CHANGED:\n            NSLog(@\"FFP_MSG_VIDEO_SIZE_CHANGED: %d, %d\\n\", avmsg->arg1, avmsg->arg2);\n            if (avmsg->arg1 > 0)\n                _videoWidth = avmsg->arg1;\n            if (avmsg->arg2 > 0)\n                _videoHeight = avmsg->arg2;\n            [self changeNaturalSize];\n            break;\n        case FFP_MSG_SAR_CHANGED:\n            NSLog(@\"FFP_MSG_SAR_CHANGED: %d, %d\\n\", avmsg->arg1, avmsg->arg2);\n            if (avmsg->arg1 > 0)\n                _sampleAspectRatioNumerator = avmsg->arg1;\n            if (avmsg->arg2 > 0)\n                _sampleAspectRatioDenominator = avmsg->arg2;\n            [self changeNaturalSize];\n            break;\n        case FFP_MSG_BUFFERING_START: {\n            NSLog(@\"FFP_MSG_BUFFERING_START:\\n\");\n\n            _monitor.lastPrerollStartTick = (int64_t)SDL_GetTickHR();\n\n            _loadState = IJKMPMovieLoadStateStalled;\n            _isSeekBuffering = avmsg->arg1;\n\n            [[NSNotificationCenter defaultCenter]\n             postNotificationName:IJKMPMoviePlayerLoadStateDidChangeNotification\n             object:self];\n            _isSeekBuffering = 0;\n            break;\n        }\n        case FFP_MSG_BUFFERING_END: {\n            NSLog(@\"FFP_MSG_BUFFERING_END:\\n\");\n\n            _monitor.lastPrerollDuration = (int64_t)SDL_GetTickHR() - _monitor.lastPrerollStartTick;\n\n            _loadState = IJKMPMovieLoadStatePlayable | IJKMPMovieLoadStatePlaythroughOK;\n            _isSeekBuffering = avmsg->arg1;\n\n            [[NSNotificationCenter defaultCenter]\n             postNotificationName:IJKMPMoviePlayerLoadStateDidChangeNotification\n             object:self];\n            [[NSNotificationCenter defaultCenter]\n             postNotificationName:IJKMPMoviePlayerPlaybackStateDidChangeNotification\n             object:self];\n            _isSeekBuffering = 0;\n            break;\n        }\n        case FFP_MSG_BUFFERING_UPDATE:\n            _bufferingPosition = avmsg->arg1;\n            _bufferingProgress = avmsg->arg2;\n            // NSLog(@\"FFP_MSG_BUFFERING_UPDATE: %d, %%%d\\n\", _bufferingPosition, _bufferingProgress);\n            break;\n        case FFP_MSG_BUFFERING_BYTES_UPDATE:\n            // NSLog(@\"FFP_MSG_BUFFERING_BYTES_UPDATE: %d\\n\", avmsg->arg1);\n            break;\n        case FFP_MSG_BUFFERING_TIME_UPDATE:\n            _bufferingTime       = avmsg->arg1;\n            // NSLog(@\"FFP_MSG_BUFFERING_TIME_UPDATE: %d\\n\", avmsg->arg1);\n            break;\n        case FFP_MSG_PLAYBACK_STATE_CHANGED:\n            [[NSNotificationCenter defaultCenter]\n             postNotificationName:IJKMPMoviePlayerPlaybackStateDidChangeNotification\n             object:self];\n            break;\n        case FFP_MSG_SEEK_COMPLETE: {\n            NSLog(@\"FFP_MSG_SEEK_COMPLETE:\\n\");\n            [[NSNotificationCenter defaultCenter]\n             postNotificationName:IJKMPMoviePlayerDidSeekCompleteNotification\n             object:self\n             userInfo:@{IJKMPMoviePlayerDidSeekCompleteTargetKey: @(avmsg->arg1),\n                        IJKMPMoviePlayerDidSeekCompleteErrorKey: @(avmsg->arg2)}];\n            _seeking = NO;\n            break;\n        }\n        case FFP_MSG_VIDEO_DECODER_OPEN: {\n            _isVideoToolboxOpen = avmsg->arg1;\n            NSLog(@\"FFP_MSG_VIDEO_DECODER_OPEN: %@\\n\", _isVideoToolboxOpen ? @\"true\" : @\"false\");\n            [[NSNotificationCenter defaultCenter]\n             postNotificationName:IJKMPMoviePlayerVideoDecoderOpenNotification\n             object:self];\n            break;\n        }\n        case FFP_MSG_VIDEO_RENDERING_START: {\n            NSLog(@\"FFP_MSG_VIDEO_RENDERING_START:\\n\");\n            _monitor.firstVideoFrameLatency = (int64_t)SDL_GetTickHR() - _monitor.prepareStartTick;\n            [[NSNotificationCenter defaultCenter]\n             postNotificationName:IJKMPMoviePlayerFirstVideoFrameRenderedNotification\n             object:self];\n            break;\n        }\n        case FFP_MSG_AUDIO_RENDERING_START: {\n            NSLog(@\"FFP_MSG_AUDIO_RENDERING_START:\\n\");\n            [[NSNotificationCenter defaultCenter]\n             postNotificationName:IJKMPMoviePlayerFirstAudioFrameRenderedNotification\n             object:self];\n            break;\n        }\n        case FFP_MSG_AUDIO_DECODED_START: {\n            NSLog(@\"FFP_MSG_AUDIO_DECODED_START:\\n\");\n            [[NSNotificationCenter defaultCenter]\n             postNotificationName:IJKMPMoviePlayerFirstAudioFrameDecodedNotification\n             object:self];\n            break;\n        }\n        case FFP_MSG_VIDEO_DECODED_START: {\n            NSLog(@\"FFP_MSG_VIDEO_DECODED_START:\\n\");\n            [[NSNotificationCenter defaultCenter]\n             postNotificationName:IJKMPMoviePlayerFirstVideoFrameDecodedNotification\n             object:self];\n            break;\n        }\n        case FFP_MSG_OPEN_INPUT: {\n            NSLog(@\"FFP_MSG_OPEN_INPUT:\\n\");\n            [[NSNotificationCenter defaultCenter]\n             postNotificationName:IJKMPMoviePlayerOpenInputNotification\n             object:self];\n            break;\n        }\n        case FFP_MSG_FIND_STREAM_INFO: {\n            NSLog(@\"FFP_MSG_FIND_STREAM_INFO:\\n\");\n            [[NSNotificationCenter defaultCenter]\n             postNotificationName:IJKMPMoviePlayerFindStreamInfoNotification\n             object:self];\n            break;\n        }\n        case FFP_MSG_COMPONENT_OPEN: {\n            NSLog(@\"FFP_MSG_COMPONENT_OPEN:\\n\");\n            [[NSNotificationCenter defaultCenter]\n             postNotificationName:IJKMPMoviePlayerComponentOpenNotification\n             object:self];\n            break;\n        }\n        case FFP_MSG_ACCURATE_SEEK_COMPLETE: {\n            NSLog(@\"FFP_MSG_ACCURATE_SEEK_COMPLETE:\\n\");\n            [[NSNotificationCenter defaultCenter]\n             postNotificationName:IJKMPMoviePlayerAccurateSeekCompleteNotification\n             object:self\n             userInfo:@{IJKMPMoviePlayerDidAccurateSeekCompleteCurPos: @(avmsg->arg1)}];\n            break;\n        }\n        case FFP_MSG_VIDEO_SEEK_RENDERING_START: {\n            NSLog(@\"FFP_MSG_VIDEO_SEEK_RENDERING_START:\\n\");\n            _isVideoSync = avmsg->arg1;\n            [[NSNotificationCenter defaultCenter]\n             postNotificationName:IJKMPMoviePlayerSeekVideoStartNotification\n             object:self];\n            _isVideoSync = 0;\n            break;\n        }\n        case FFP_MSG_AUDIO_SEEK_RENDERING_START: {\n            NSLog(@\"FFP_MSG_AUDIO_SEEK_RENDERING_START:\\n\");\n            _isAudioSync = avmsg->arg1;\n            [[NSNotificationCenter defaultCenter]\n             postNotificationName:IJKMPMoviePlayerSeekAudioStartNotification\n             object:self];\n            _isAudioSync = 0;\n            break;\n        }\n        default:\n            // NSLog(@\"unknown FFP_MSG_xxx(%d)\\n\", avmsg->what);\n            break;\n    }\n\n    [_msgPool recycle:msg];\n}\n\n- (IJKFFMoviePlayerMessage *) obtainMessage {\n    return [_msgPool obtain];\n}\n\ninline static IJKFFMoviePlayerController *ffplayerRetain(void *arg) {\n    return (__bridge_transfer IJKFFMoviePlayerController *) arg;\n}\n\nint media_player_msg_loop(void* arg)\n{\n    @autoreleasepool {\n        IjkMediaPlayer *mp = (IjkMediaPlayer*)arg;\n        __weak IJKFFMoviePlayerController *ffpController = ffplayerRetain(ijkmp_set_weak_thiz(mp, NULL));\n        while (ffpController) {\n            @autoreleasepool {\n                IJKFFMoviePlayerMessage *msg = [ffpController obtainMessage];\n                if (!msg)\n                    break;\n\n                int retval = ijkmp_get_msg(mp, &msg->_msg, 1);\n                if (retval < 0)\n                    break;\n\n                // block-get should never return 0\n                assert(retval > 0);\n                [ffpController performSelectorOnMainThread:@selector(postEvent:) withObject:msg waitUntilDone:NO];\n            }\n        }\n\n        // retained in prepare_async, before SDL_CreateThreadEx\n        ijkmp_dec_ref_p(&mp);\n        return 0;\n    }\n}\n\n#pragma mark av_format_control_message\n\nstatic int onInjectIOControl(IJKFFMoviePlayerController *mpc, id<IJKMediaUrlOpenDelegate> delegate, int type, void *data, size_t data_size)\n{\n    AVAppIOControl *realData = data;\n    assert(realData);\n    assert(sizeof(AVAppIOControl) == data_size);\n    realData->is_handled     = NO;\n    realData->is_url_changed = NO;\n\n    if (delegate == nil)\n        return 0;\n\n    NSString *urlString = [NSString stringWithUTF8String:realData->url];\n\n    IJKMediaUrlOpenData *openData =\n    [[IJKMediaUrlOpenData alloc] initWithUrl:urlString\n                                       event:(IJKMediaEvent)type\n                                segmentIndex:realData->segment_index\n                                retryCounter:realData->retry_counter];\n\n    [delegate willOpenUrl:openData];\n    if (openData.error < 0)\n        return -1;\n\n    if (openData.isHandled) {\n        realData->is_handled = YES;\n        if (openData.isUrlChanged && openData.url != nil) {\n            realData->is_url_changed = YES;\n            const char *newUrlUTF8 = [openData.url UTF8String];\n            strlcpy(realData->url, newUrlUTF8, sizeof(realData->url));\n            realData->url[sizeof(realData->url) - 1] = 0;\n        }\n    }\n    \n    return 0;\n}\n\nstatic int onInjectTcpIOControl(IJKFFMoviePlayerController *mpc, id<IJKMediaUrlOpenDelegate> delegate, int type, void *data, size_t data_size)\n{\n    AVAppTcpIOControl *realData = data;\n    assert(realData);\n    assert(sizeof(AVAppTcpIOControl) == data_size);\n\n    switch (type) {\n        case IJKMediaCtrl_WillTcpOpen:\n\n            break;\n        case IJKMediaCtrl_DidTcpOpen:\n            mpc->_monitor.tcpError = realData->error;\n            mpc->_monitor.remoteIp = [NSString stringWithUTF8String:realData->ip];\n            [mpc setHudValue: mpc->_monitor.remoteIp forKey:@\"ip\"];\n            break;\n        default:\n            assert(!\"unexcepted type for tcp io control\");\n            break;\n    }\n\n    if (delegate == nil)\n        return 0;\n\n    NSString *urlString = [NSString stringWithUTF8String:realData->ip];\n\n    IJKMediaUrlOpenData *openData =\n    [[IJKMediaUrlOpenData alloc] initWithUrl:urlString\n                                       event:(IJKMediaEvent)type\n                                segmentIndex:0\n                                retryCounter:0];\n    openData.fd = realData->fd;\n\n    [delegate willOpenUrl:openData];\n    if (openData.error < 0)\n        return -1;\n    [mpc setHudValue: [NSString stringWithFormat:@\"fd:%d %@\", openData.fd, openData.msg?:@\"unknown\"] forKey:@\"tcp-info\"];\n    return 0;\n}\n\nstatic int onInjectAsyncStatistic(IJKFFMoviePlayerController *mpc, int type, void *data, size_t data_size)\n{\n    AVAppAsyncStatistic *realData = data;\n    assert(realData);\n    assert(sizeof(AVAppAsyncStatistic) == data_size);\n\n    mpc->_asyncStat = *realData;\n    return 0;\n}\n\nstatic int onInectIJKIOStatistic(IJKFFMoviePlayerController *mpc, int type, void *data, size_t data_size)\n{\n    IjkIOAppCacheStatistic *realData = data;\n    assert(realData);\n    assert(sizeof(IjkIOAppCacheStatistic) == data_size);\n\n    mpc->_cacheStat = *realData;\n    return 0;\n}\n\nstatic int64_t calculateElapsed(int64_t begin, int64_t end)\n{\n    if (begin <= 0)\n        return -1;\n\n    if (end < begin)\n        return -1;\n\n    return end - begin;\n}\n\nstatic int onInjectOnHttpEvent(IJKFFMoviePlayerController *mpc, int type, void *data, size_t data_size)\n{\n    AVAppHttpEvent *realData = data;\n    assert(realData);\n    assert(sizeof(AVAppHttpEvent) == data_size);\n\n    NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];\n    NSURL        *nsurl   = nil;\n    IJKFFMonitor *monitor = mpc->_monitor;\n    NSString     *url  = monitor.httpUrl;\n    NSString     *host = monitor.httpHost;\n    int64_t       elapsed = 0;\n\n    id<IJKMediaNativeInvokeDelegate> delegate = mpc.nativeInvokeDelegate;\n\n    switch (type) {\n        case AVAPP_EVENT_WILL_HTTP_OPEN:\n            url   = [NSString stringWithUTF8String:realData->url];\n            nsurl = [NSURL URLWithString:url];\n            host  = nsurl.host;\n\n            monitor.httpUrl      = url;\n            monitor.httpHost     = host;\n            monitor.httpOpenTick = SDL_GetTickHR();\n            [mpc setHudUrl:url];\n\n            if (delegate != nil) {\n                dict[IJKMediaEventAttrKey_host]         = [NSString ijk_stringBeEmptyIfNil:host];\n                dict[IJKMediaEventAttrKey_url]          = [NSString ijk_stringBeEmptyIfNil:monitor.httpUrl];\n                [delegate invoke:type attributes:dict];\n            }\n            break;\n        case AVAPP_EVENT_DID_HTTP_OPEN:\n            elapsed = calculateElapsed(monitor.httpOpenTick, SDL_GetTickHR());\n            monitor.httpError = realData->error;\n            monitor.httpCode  = realData->http_code;\n            monitor.filesize  = realData->filesize;\n            monitor.httpOpenCount++;\n            monitor.httpOpenTick = 0;\n            monitor.lastHttpOpenDuration = elapsed;\n            [mpc setHudValue:@(realData->http_code).stringValue forKey:@\"http\"];\n\n            if (delegate != nil) {\n                dict[IJKMediaEventAttrKey_time_of_event]    = @(elapsed).stringValue;\n                dict[IJKMediaEventAttrKey_url]              = [NSString ijk_stringBeEmptyIfNil:monitor.httpUrl];\n                dict[IJKMediaEventAttrKey_host]             = [NSString ijk_stringBeEmptyIfNil:host];\n                dict[IJKMediaEventAttrKey_error]            = @(realData->error).stringValue;\n                dict[IJKMediaEventAttrKey_http_code]        = @(realData->http_code).stringValue;\n                dict[IJKMediaEventAttrKey_file_size]        = @(realData->filesize).stringValue;\n                [delegate invoke:type attributes:dict];\n            }\n            break;\n        case AVAPP_EVENT_WILL_HTTP_SEEK:\n            monitor.httpSeekTick = SDL_GetTickHR();\n\n            if (delegate != nil) {\n                dict[IJKMediaEventAttrKey_host]         = [NSString ijk_stringBeEmptyIfNil:host];\n                dict[IJKMediaEventAttrKey_offset]       = @(realData->offset).stringValue;\n                [delegate invoke:type attributes:dict];\n            }\n            break;\n        case AVAPP_EVENT_DID_HTTP_SEEK:\n            elapsed = calculateElapsed(monitor.httpSeekTick, SDL_GetTickHR());\n            monitor.httpError = realData->error;\n            monitor.httpCode  = realData->http_code;\n            monitor.httpSeekCount++;\n            monitor.httpSeekTick = 0;\n            monitor.lastHttpSeekDuration = elapsed;\n            [mpc setHudValue:@(realData->http_code).stringValue forKey:@\"http\"];\n\n            if (delegate != nil) {\n                dict[IJKMediaEventAttrKey_time_of_event]    = @(elapsed).stringValue;\n                dict[IJKMediaEventAttrKey_url]              = [NSString ijk_stringBeEmptyIfNil:monitor.httpUrl];\n                dict[IJKMediaEventAttrKey_host]             = [NSString ijk_stringBeEmptyIfNil:host];\n                dict[IJKMediaEventAttrKey_offset]           = @(realData->offset).stringValue;\n                dict[IJKMediaEventAttrKey_error]            = @(realData->error).stringValue;\n                dict[IJKMediaEventAttrKey_http_code]        = @(realData->http_code).stringValue;\n                [delegate invoke:type attributes:dict];\n            }\n            break;\n    }\n\n    return 0;\n}\n\n// NOTE: could be called from multiple thread\nstatic int ijkff_inject_callback(void *opaque, int message, void *data, size_t data_size)\n{\n    IJKWeakHolder *weakHolder = (__bridge IJKWeakHolder*)opaque;\n    IJKFFMoviePlayerController *mpc = weakHolder.object;\n    if (!mpc)\n        return 0;\n\n    switch (message) {\n        case AVAPP_CTRL_WILL_CONCAT_SEGMENT_OPEN:\n            return onInjectIOControl(mpc, mpc.segmentOpenDelegate, message, data, data_size);\n        case AVAPP_CTRL_WILL_TCP_OPEN:\n            return onInjectTcpIOControl(mpc, mpc.tcpOpenDelegate, message, data, data_size);\n        case AVAPP_CTRL_WILL_HTTP_OPEN:\n            return onInjectIOControl(mpc, mpc.httpOpenDelegate, message, data, data_size);\n        case AVAPP_CTRL_WILL_LIVE_OPEN:\n            return onInjectIOControl(mpc, mpc.liveOpenDelegate, message, data, data_size);\n        case AVAPP_EVENT_ASYNC_STATISTIC:\n            return onInjectAsyncStatistic(mpc, message, data, data_size);\n        case IJKIOAPP_EVENT_CACHE_STATISTIC:\n            return onInectIJKIOStatistic(mpc, message, data, data_size);\n        case AVAPP_CTRL_DID_TCP_OPEN:\n            return onInjectTcpIOControl(mpc, mpc.tcpOpenDelegate, message, data, data_size);\n        case AVAPP_EVENT_WILL_HTTP_OPEN:\n        case AVAPP_EVENT_DID_HTTP_OPEN:\n        case AVAPP_EVENT_WILL_HTTP_SEEK:\n        case AVAPP_EVENT_DID_HTTP_SEEK:\n            return onInjectOnHttpEvent(mpc, message, data, data_size);\n        default: {\n            return 0;\n        }\n    }\n}\n\n#pragma mark Airplay\n\n-(BOOL)allowsMediaAirPlay\n{\n    if (!self)\n        return NO;\n    return _allowsMediaAirPlay;\n}\n\n-(void)setAllowsMediaAirPlay:(BOOL)b\n{\n    if (!self)\n        return;\n    _allowsMediaAirPlay = b;\n}\n\n-(BOOL)airPlayMediaActive\n{\n    if (!self)\n        return NO;\n    if (_isDanmakuMediaAirPlay) {\n        return YES;\n    }\n    return NO;\n}\n\n-(BOOL)isDanmakuMediaAirPlay\n{\n    return _isDanmakuMediaAirPlay;\n}\n\n-(void)setIsDanmakuMediaAirPlay:(BOOL)isDanmakuMediaAirPlay\n{\n    _isDanmakuMediaAirPlay = isDanmakuMediaAirPlay;\n    if (_isDanmakuMediaAirPlay) {\n        _glView.scaleFactor = 1.0f;\n    }\n    else {\n        CGFloat scale = [[UIScreen mainScreen] scale];\n        if (scale < 0.1f)\n            scale = 1.0f;\n        _glView.scaleFactor = scale;\n    }\n     [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerIsAirPlayVideoActiveDidChangeNotification object:nil userInfo:nil];\n}\n\n\n#pragma mark Option Conventionce\n\n- (void)setFormatOptionValue:(NSString *)value forKey:(NSString *)key\n{\n    [self setOptionValue:value forKey:key ofCategory:kIJKFFOptionCategoryFormat];\n}\n\n- (void)setCodecOptionValue:(NSString *)value forKey:(NSString *)key\n{\n    [self setOptionValue:value forKey:key ofCategory:kIJKFFOptionCategoryCodec];\n}\n\n- (void)setSwsOptionValue:(NSString *)value forKey:(NSString *)key\n{\n    [self setOptionValue:value forKey:key ofCategory:kIJKFFOptionCategorySws];\n}\n\n- (void)setPlayerOptionValue:(NSString *)value forKey:(NSString *)key\n{\n    [self setOptionValue:value forKey:key ofCategory:kIJKFFOptionCategoryPlayer];\n}\n\n- (void)setFormatOptionIntValue:(int64_t)value forKey:(NSString *)key\n{\n    [self setOptionIntValue:value forKey:key ofCategory:kIJKFFOptionCategoryFormat];\n}\n\n- (void)setCodecOptionIntValue:(int64_t)value forKey:(NSString *)key\n{\n    [self setOptionIntValue:value forKey:key ofCategory:kIJKFFOptionCategoryCodec];\n}\n\n- (void)setSwsOptionIntValue:(int64_t)value forKey:(NSString *)key\n{\n    [self setOptionIntValue:value forKey:key ofCategory:kIJKFFOptionCategorySws];\n}\n\n- (void)setPlayerOptionIntValue:(int64_t)value forKey:(NSString *)key\n{\n    [self setOptionIntValue:value forKey:key ofCategory:kIJKFFOptionCategoryPlayer];\n}\n\n- (void)setMaxBufferSize:(int)maxBufferSize\n{\n    [self setPlayerOptionIntValue:maxBufferSize forKey:@\"max-buffer-size\"];\n}\n\n#pragma mark app state changed\n\n- (void)registerApplicationObservers\n{\n    [_notificationManager addObserver:self\n                             selector:@selector(audioSessionInterrupt:)\n                                 name:AVAudioSessionInterruptionNotification\n                               object:nil];\n\n    [_notificationManager addObserver:self\n                             selector:@selector(applicationWillEnterForeground)\n                                 name:UIApplicationWillEnterForegroundNotification\n                               object:nil];\n\n    [_notificationManager addObserver:self\n                             selector:@selector(applicationDidBecomeActive)\n                                 name:UIApplicationDidBecomeActiveNotification\n                               object:nil];\n\n    [_notificationManager addObserver:self\n                             selector:@selector(applicationWillResignActive)\n                                 name:UIApplicationWillResignActiveNotification\n                               object:nil];\n\n    [_notificationManager addObserver:self\n                             selector:@selector(applicationDidEnterBackground)\n                                 name:UIApplicationDidEnterBackgroundNotification\n                               object:nil];\n\n    [_notificationManager addObserver:self\n                             selector:@selector(applicationWillTerminate)\n                                 name:UIApplicationWillTerminateNotification\n                               object:nil];\n}\n\n- (void)unregisterApplicationObservers\n{\n    [_notificationManager removeAllObservers:self];\n}\n\n- (void)audioSessionInterrupt:(NSNotification *)notification\n{\n    int reason = [[[notification userInfo] valueForKey:AVAudioSessionInterruptionTypeKey] intValue];\n    switch (reason) {\n        case AVAudioSessionInterruptionTypeBegan: {\n            NSLog(@\"IJKFFMoviePlayerController:audioSessionInterrupt: begin\\n\");\n            switch (self.playbackState) {\n                case IJKMPMoviePlaybackStatePaused:\n                case IJKMPMoviePlaybackStateStopped:\n                    _playingBeforeInterruption = NO;\n                    break;\n                default:\n                    _playingBeforeInterruption = YES;\n                    break;\n            }\n            [self pause];\n            [[IJKAudioKit sharedInstance] setActive:NO];\n            break;\n        }\n        case AVAudioSessionInterruptionTypeEnded: {\n            NSLog(@\"IJKFFMoviePlayerController:audioSessionInterrupt: end\\n\");\n            [[IJKAudioKit sharedInstance] setActive:YES];\n            if (_playingBeforeInterruption) {\n                [self play];\n            }\n            break;\n        }\n    }\n}\n\n- (void)applicationWillEnterForeground\n{\n    NSLog(@\"IJKFFMoviePlayerController:applicationWillEnterForeground: %d\", (int)[UIApplication sharedApplication].applicationState);\n}\n\n- (void)applicationDidBecomeActive\n{\n    NSLog(@\"IJKFFMoviePlayerController:applicationDidBecomeActive: %d\", (int)[UIApplication sharedApplication].applicationState);\n}\n\n- (void)applicationWillResignActive\n{\n    NSLog(@\"IJKFFMoviePlayerController:applicationWillResignActive: %d\", (int)[UIApplication sharedApplication].applicationState);\n    dispatch_async(dispatch_get_main_queue(), ^{\n        if (_pauseInBackground) {\n            [self pause];\n        }\n    });\n}\n\n- (void)applicationDidEnterBackground\n{\n    NSLog(@\"IJKFFMoviePlayerController:applicationDidEnterBackground: %d\", (int)[UIApplication sharedApplication].applicationState);\n    dispatch_async(dispatch_get_main_queue(), ^{\n        if (_pauseInBackground) {\n            [self pause];\n        }\n    });\n}\n\n- (void)applicationWillTerminate\n{\n    NSLog(@\"IJKFFMoviePlayerController:applicationWillTerminate: %d\", (int)[UIApplication sharedApplication].applicationState);\n    dispatch_async(dispatch_get_main_queue(), ^{\n        if (_pauseInBackground) {\n            [self pause];\n        }\n    });\n}\n\n#pragma mark IJKFFHudController\n- (void)setHudValue:(NSString *)value forKey:(NSString *)key\n{\n    if ([[NSThread currentThread] isMainThread]) {\n        [_hudViewController setHudValue:value forKey:key];\n    } else {\n        dispatch_async(dispatch_get_main_queue(), ^{\n            [self setHudValue:value forKey:key];\n        });\n    }\n}\n\n@end\n\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerDef.h",
    "content": "/*\n * IJKFFMoviePlayerDef.h\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import <Foundation/Foundation.h>\n#include \"ijkplayer/ios/ijkplayer_ios.h\"\n#include \"ijkplayer/ijkmeta.h\"\n\n\nstruct IJKSize {\n    NSInteger width;\n    NSInteger height;\n};\ntypedef struct IJKSize IJKSize;\n\nCG_INLINE IJKSize\nIJKSizeMake(NSInteger width, NSInteger height)\n{\n    IJKSize size;\n    size.width = width;\n    size.height = height;\n    return size;\n}\n\n\n\nstruct IJKSampleAspectRatio {\n    NSInteger numerator;\n    NSInteger denominator;\n};\ntypedef struct IJKSampleAspectRatio IJKSampleAspectRatio;\n\nCG_INLINE IJKSampleAspectRatio\nIJKSampleAspectRatioMake(NSInteger numerator, NSInteger denominator)\n{\n    IJKSampleAspectRatio sampleAspectRatio;\n    sampleAspectRatio.numerator = numerator;\n    sampleAspectRatio.denominator = denominator;\n    return sampleAspectRatio;\n}\n\n\n\n@interface IJKFFMoviePlayerMessage : NSObject {\n@public\n    AVMessage _msg;\n}\n@end\n\n\n@interface IJKFFMoviePlayerMessagePool : NSObject\n\n- (IJKFFMoviePlayerMessagePool *)init;\n- (IJKFFMoviePlayerMessage *) obtain;\n- (void) recycle:(IJKFFMoviePlayerMessage *)msg;\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerDef.m",
    "content": "/*\n * IJKFFMoviePlayerDef.m\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import \"IJKFFMoviePlayerDef.h\"\n\n@implementation IJKFFMoviePlayerMessage\n@end\n\n@implementation IJKFFMoviePlayerMessagePool{\n    NSMutableArray *_array;\n}\n\n- (IJKFFMoviePlayerMessagePool *)init\n{\n    self = [super init];\n    if (self) {\n        _array = [[NSMutableArray alloc] init];\n    }\n    return self;\n}\n\n- (IJKFFMoviePlayerMessage *) obtain\n{\n    IJKFFMoviePlayerMessage *msg = nil;\n\n    @synchronized(self) {\n        NSUInteger count = [_array count];\n        if (count > 0) {\n            msg = [_array objectAtIndex:count - 1];\n            [_array removeLastObject];\n        }\n    }\n\n    if (!msg)\n        msg = [[IJKFFMoviePlayerMessage alloc] init];\n\n    return msg;\n}\n\n- (void) recycle:(IJKFFMoviePlayerMessage *)msg\n{\n    if (!msg)\n        return;\n    msg_free_res(&msg->_msg);\n    @synchronized(self) {\n        if ([_array count] <= 10)\n            [_array addObject:msg];\n    }\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFOptions.h",
    "content": "/*\n * IJKFFOptions.h\n *\n * Copyright (c) 2013-2015 Bilibili\n * Copyright (c) 2013-2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import <Foundation/Foundation.h>\n\ntypedef enum IJKFFOptionCategory {\n    kIJKFFOptionCategoryFormat = 1,\n    kIJKFFOptionCategoryCodec  = 2,\n    kIJKFFOptionCategorySws    = 3,\n    kIJKFFOptionCategoryPlayer = 4,\n    kIJKFFOptionCategorySwr    = 5,\n} IJKFFOptionCategory;\n\n// for codec option 'skip_loop_filter' and 'skip_frame'\ntypedef enum IJKAVDiscard {\n    /* We leave some space between them for extensions (drop some\n     * keyframes for intra-only or drop just some bidir frames). */\n    IJK_AVDISCARD_NONE    =-16, ///< discard nothing\n    IJK_AVDISCARD_DEFAULT =  0, ///< discard useless packets like 0 size packets in avi\n    IJK_AVDISCARD_NONREF  =  8, ///< discard all non reference\n    IJK_AVDISCARD_BIDIR   = 16, ///< discard all bidirectional frames\n    IJK_AVDISCARD_NONKEY  = 32, ///< discard all frames except keyframes\n    IJK_AVDISCARD_ALL     = 48, ///< discard all\n} IJKAVDiscard;\n\nstruct IjkMediaPlayer;\n\n@interface IJKFFOptions : NSObject\n\n+(IJKFFOptions *)optionsByDefault;\n\n-(void)applyTo:(struct IjkMediaPlayer *)mediaPlayer;\n\n- (void)setOptionValue:(NSString *)value\n                forKey:(NSString *)key\n            ofCategory:(IJKFFOptionCategory)category;\n\n- (void)setOptionIntValue:(int64_t)value\n                   forKey:(NSString *)key\n               ofCategory:(IJKFFOptionCategory)category;\n\n\n-(void)setFormatOptionValue:       (NSString *)value forKey:(NSString *)key;\n-(void)setCodecOptionValue:        (NSString *)value forKey:(NSString *)key;\n-(void)setSwsOptionValue:          (NSString *)value forKey:(NSString *)key;\n-(void)setPlayerOptionValue:       (NSString *)value forKey:(NSString *)key;\n\n-(void)setFormatOptionIntValue:    (int64_t)value forKey:(NSString *)key;\n-(void)setCodecOptionIntValue:     (int64_t)value forKey:(NSString *)key;\n-(void)setSwsOptionIntValue:       (int64_t)value forKey:(NSString *)key;\n-(void)setPlayerOptionIntValue:    (int64_t)value forKey:(NSString *)key;\n\n@property(nonatomic) BOOL showHudView;\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFOptions.m",
    "content": "/*\n * IJKFFOptions.m\n *\n * Copyright (c) 2013-2015 Bilibili\n * Copyright (c) 2013-2015 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import \"IJKFFOptions.h\"\n#include \"ijkplayer/ios/ijkplayer_ios.h\"\n\n@implementation IJKFFOptions {\n    NSMutableDictionary *_optionCategories;\n\n    NSMutableDictionary *_playerOptions;\n    NSMutableDictionary *_formatOptions;\n    NSMutableDictionary *_codecOptions;\n    NSMutableDictionary *_swsOptions;\n    NSMutableDictionary *_swrOptions;\n}\n\n+ (IJKFFOptions *)optionsByDefault\n{\n    IJKFFOptions *options = [[IJKFFOptions alloc] init];\n\n    [options setPlayerOptionIntValue:30     forKey:@\"max-fps\"];\n    [options setPlayerOptionIntValue:0      forKey:@\"framedrop\"];\n    [options setPlayerOptionIntValue:3      forKey:@\"video-pictq-size\"];\n    [options setPlayerOptionIntValue:0      forKey:@\"videotoolbox\"];\n    [options setPlayerOptionIntValue:960    forKey:@\"videotoolbox-max-frame-width\"];\n\n    [options setFormatOptionIntValue:0                  forKey:@\"auto_convert\"];\n    [options setFormatOptionIntValue:1                  forKey:@\"reconnect\"];\n    [options setFormatOptionIntValue:30 * 1000 * 1000   forKey:@\"timeout\"];\n    [options setFormatOptionValue:@\"ijkplayer\"          forKey:@\"user-agent\"];\n\n    options.showHudView   = NO;\n\n    return options;\n}\n\n- (id)init\n{\n    self = [super init];\n    if (self) {\n        _playerOptions      = [[NSMutableDictionary alloc] init];\n        _formatOptions      = [[NSMutableDictionary alloc] init];\n        _codecOptions       = [[NSMutableDictionary alloc] init];\n        _swsOptions         = [[NSMutableDictionary alloc] init];\n        _swrOptions         = [[NSMutableDictionary alloc] init];\n\n        _optionCategories   = [[NSMutableDictionary alloc] init];\n        _optionCategories[@(IJKMP_OPT_CATEGORY_PLAYER)] = _playerOptions;\n        _optionCategories[@(IJKMP_OPT_CATEGORY_FORMAT)] = _formatOptions;\n        _optionCategories[@(IJKMP_OPT_CATEGORY_CODEC)]  = _codecOptions;\n        _optionCategories[@(IJKMP_OPT_CATEGORY_SWS)]    = _swsOptions;\n        _optionCategories[@(IJKMP_OPT_CATEGORY_SWR)]    = _swrOptions;\n    }\n    return self;\n}\n\n- (void)applyTo:(IjkMediaPlayer *)mediaPlayer\n{\n    [_optionCategories enumerateKeysAndObjectsUsingBlock:^(id categoryKey, id categoryDict, BOOL *stopOuter) {\n        [categoryDict enumerateKeysAndObjectsUsingBlock:^(id optKey, id optValue, BOOL *stop) {\n            if ([optValue isKindOfClass:[NSNumber class]]) {\n                ijkmp_set_option_int(mediaPlayer,\n                                     (int)[categoryKey integerValue],\n                                     [optKey UTF8String],\n                                     [optValue longLongValue]);\n            } else if ([optValue isKindOfClass:[NSString class]]) {\n                ijkmp_set_option(mediaPlayer,\n                                 (int)[categoryKey integerValue],\n                                 [optKey UTF8String],\n                                 [optValue UTF8String]);\n            }\n        }];\n    }];\n}\n\n- (void)setOptionValue:(NSString *)value\n                forKey:(NSString *)key\n            ofCategory:(IJKFFOptionCategory)category\n{\n    if (!key)\n        return;\n\n    NSMutableDictionary *options = [_optionCategories objectForKey:@(category)];\n    if (options) {\n        if (value) {\n            [options setObject:value forKey:key];\n        } else {\n            [options removeObjectForKey:key];\n        }\n    }\n}\n\n- (void)setOptionIntValue:(int64_t)value\n                   forKey:(NSString *)key\n               ofCategory:(IJKFFOptionCategory)category\n{\n    if (!key)\n        return;\n\n    NSMutableDictionary *options = [_optionCategories objectForKey:@(category)];\n    if (options) {\n        [options setObject:@(value) forKey:key];\n    }\n}\n\n\n#pragma mark Common Helper\n\n-(void)setFormatOptionValue:(NSString *)value forKey:(NSString *)key\n{\n    [self setOptionValue:value forKey:key ofCategory:kIJKFFOptionCategoryFormat];\n}\n\n-(void)setCodecOptionValue:(NSString *)value forKey:(NSString *)key\n{\n    [self setOptionValue:value forKey:key ofCategory:kIJKFFOptionCategoryCodec];\n}\n\n-(void)setSwsOptionValue:(NSString *)value forKey:(NSString *)key\n{\n    [self setOptionValue:value forKey:key ofCategory:kIJKFFOptionCategorySws];\n}\n\n-(void)setPlayerOptionValue:(NSString *)value forKey:(NSString *)key\n{\n    [self setOptionValue:value forKey:key ofCategory:kIJKFFOptionCategoryPlayer];\n}\n\n-(void)setFormatOptionIntValue:(int64_t)value forKey:(NSString *)key\n{\n    [self setOptionIntValue:value forKey:key ofCategory:kIJKFFOptionCategoryFormat];\n}\n\n-(void)setCodecOptionIntValue:(int64_t)value forKey:(NSString *)key\n{\n    [self setOptionIntValue:value forKey:key ofCategory:kIJKFFOptionCategoryCodec];\n}\n\n-(void)setSwsOptionIntValue:(int64_t)value forKey:(NSString *)key\n{\n    [self setOptionIntValue:value forKey:key ofCategory:kIJKFFOptionCategorySws];\n}\n\n-(void)setPlayerOptionIntValue:(int64_t)value forKey:(NSString *)key\n{\n    [self setOptionIntValue:value forKey:key ofCategory:kIJKFFOptionCategoryPlayer];\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKKVOController.h",
    "content": "/*\n * IJKKVOController.h\n *\n * Copyright (c) 2014 Bilibili\n * Copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import <Foundation/Foundation.h>\n\n@interface IJKKVOController : NSObject\n\n- (id)initWithTarget:(NSObject *)target;\n\n- (void)safelyAddObserver:(NSObject *)observer\n               forKeyPath:(NSString *)keyPath\n                  options:(NSKeyValueObservingOptions)options\n                  context:(void *)context;\n- (void)safelyRemoveObserver:(NSObject *)observer\n                  forKeyPath:(NSString *)keyPath;\n\n- (void)safelyRemoveAllObservers;\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKKVOController.m",
    "content": "/*\n * IJKKVOController.m\n *\n * Copyright (c) 2014 Bilibili\n * Copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import \"IJKKVOController.h\"\n\n@interface IJKKVOEntry : NSObject\n@property(nonatomic, weak)   NSObject *observer;\n@property(nonatomic, strong) NSString *keyPath;\n@end\n\n@implementation IJKKVOEntry\n@synthesize observer;\n@synthesize keyPath;\n@end\n\n@implementation IJKKVOController {\n    __weak NSObject *_target;\n    NSMutableArray  *_observerArray;\n}\n\n- (id)initWithTarget:(NSObject *)target\n{\n    self = [super init];\n    if (self) {\n        _target = target;\n        _observerArray = [[NSMutableArray alloc] init];\n    }\n    return self;\n}\n\n- (void)safelyAddObserver:(NSObject *)observer\n               forKeyPath:(NSString *)keyPath\n                  options:(NSKeyValueObservingOptions)options\n                  context:(void *)context\n{\n    NSObject *target = _target;\n    if (target == nil)\n        return;\n\n    BOOL removed = [self removeEntryOfObserver:observer forKeyPath:keyPath];\n    if (removed) {\n        // duplicated register\n        NSLog(@\"duplicated observer\");\n    }\n\n    @try {\n        [target addObserver:observer\n                 forKeyPath:keyPath\n                    options:options\n                    context:context];\n        \n        IJKKVOEntry *entry = [[IJKKVOEntry alloc] init];\n        entry.observer = observer;\n        entry.keyPath  = keyPath;\n        [_observerArray addObject:entry];\n    } @catch (NSException *e) {\n        NSLog(@\"IJKKVO: failed to add observer for %@\\n\", keyPath);\n    }\n}\n\n- (void)safelyRemoveObserver:(NSObject *)observer\n                  forKeyPath:(NSString *)keyPath\n{\n    NSObject *target = _target;\n    if (target == nil)\n        return;\n\n    BOOL removed = [self removeEntryOfObserver:observer forKeyPath:keyPath];\n    if (removed) {\n        // duplicated register\n        NSLog(@\"duplicated observer\");\n    }\n\n    @try {\n        if (removed) {\n            [target removeObserver:observer\n                        forKeyPath:keyPath];\n        }\n    } @catch (NSException *e) {\n        NSLog(@\"IJKKVO: failed to remove observer for %@\\n\", keyPath);\n    }\n}\n\n- (void)safelyRemoveAllObservers\n{\n    __block NSObject *target = _target;\n    if (target == nil)\n        return;\n\n    [_observerArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {\n        IJKKVOEntry *entry = obj;\n        if (entry == nil)\n            return;\n\n        NSObject *observer = entry.observer;\n        if (observer == nil)\n            return;\n\n        @try {\n            [target removeObserver:observer\n                        forKeyPath:entry.keyPath];\n        } @catch (NSException *e) {\n            NSLog(@\"IJKKVO: failed to remove observer for %@\\n\", entry.keyPath);\n        }\n    }];\n\n    [_observerArray removeAllObjects];\n}\n\n- (BOOL)removeEntryOfObserver:(NSObject *)observer\n                   forKeyPath:(NSString *)keyPath\n{\n    __block NSInteger foundIndex = -1;\n    [_observerArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {\n        IJKKVOEntry *entry = (IJKKVOEntry *)obj;\n        if (entry.observer == observer &&\n            [entry.keyPath isEqualToString:keyPath]) {\n            foundIndex = idx;\n            *stop = YES;\n        }\n    }];\n\n    if (foundIndex >= 0) {\n        [_observerArray removeObjectAtIndex:foundIndex];\n        return YES;\n    }\n\n    return NO;\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKMPMoviePlayerController.h",
    "content": "/*\n * IJKMPMoviePlayerController.h\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import \"IJKMediaPlayback.h\"\n#import <MediaPlayer/MediaPlayer.h>\n\n@interface IJKMPMoviePlayerController : MPMoviePlayerController <IJKMediaPlayback>\n\n- (id)initWithContentURL:(NSURL *)aUrl;\n- (id)initWithContentURLString:(NSString *)aUrl;\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKMPMoviePlayerController.m",
    "content": "/*\n * IJKMPMoviePlayerController.m\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import \"IJKMPMoviePlayerController.h\"\n#import \"IJKAudioKit.h\"\n#import \"IJKNotificationManager.h\"\n\n@implementation IJKMPMoviePlayerController\n{\n    IJKNotificationManager *_notificationManager;\n}\n\n@dynamic view;\n@dynamic currentPlaybackTime;\n@dynamic duration;\n@dynamic playableDuration;\n@synthesize bufferingProgress = _bufferingProgress;\n\n@dynamic isPreparedToPlay;\n@dynamic playbackState;\n@dynamic loadState;\n\n@dynamic naturalSize;\n@dynamic scalingMode;\n@dynamic shouldAutoplay;\n@synthesize isDanmakuMediaAirPlay = _isDanmakuMediaAirPlay;\n\n@synthesize numberOfBytesTransferred = _numberOfBytesTransferred;\n\n- (id)initWithContentURL:(NSURL *)aUrl\n{\n    self = [super initWithContentURL:aUrl];\n    if (self) {\n        self.scalingMode = MPMovieScalingModeAspectFit;\n        self.shouldAutoplay = YES;\n\n        _notificationManager = [[IJKNotificationManager alloc] init];\n        [self IJK_installMovieNotificationObservers];\n\n        [[IJKAudioKit sharedInstance] setupAudioSession];\n        \n        _bufferingProgress = -1;\n    }\n    return self;\n}\n\n- (id)initWithContentURLString:(NSString *)aUrl\n{\n    NSURL *url;\n    if ([aUrl rangeOfString:@\"/\"].location == 0) {\n        //本地\n        url = [NSURL fileURLWithPath:aUrl];\n    }\n    else {\n        url = [NSURL URLWithString:aUrl];\n    }\n    \n    self = [self initWithContentURL:url];\n    if (self) {\n        \n    }\n    return self;\n}\n\n- (void)dealloc\n{\n    [self IJK_removeMovieNotificationObservers];\n}\n\n- (BOOL)isPlaying\n{\n    switch (self.playbackState) {\n        case MPMoviePlaybackStatePlaying:\n            return YES;\n        default:\n            return NO;\n    }\n}\n\n- (void)shutdown\n{\n    // do nothing\n}\n\n-(int64_t)numberOfBytesTransferred\n{\n    NSArray *events = self.accessLog.events;\n    if (events.count>0) {\n        MPMovieAccessLogEvent *currentEvent = [events objectAtIndex:events.count -1];\n        return currentEvent.numberOfBytesTransferred;\n    }\n    return 0;\n}\n\n- (UIImage *)thumbnailImageAtCurrentTime\n{\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n    return [super thumbnailImageAtTime:self.currentPlaybackTime timeOption:MPMovieTimeOptionExact];\n#pragma clang diagnostic pop\n}\n\n-(BOOL)allowsMediaAirPlay\n{\n    if (!self)\n        return NO;\n    return [self allowsAirPlay];\n}\n\n-(void)setAllowsMediaAirPlay:(BOOL)b\n{\n    if (!self)\n        return;\n    [self setAllowsAirPlay:b];\n}\n\n-(BOOL)airPlayMediaActive\n{\n    if (!self)\n        return NO;\n    \n    return self.airPlayVideoActive || self.isDanmakuMediaAirPlay;\n}\n\n-(BOOL)isDanmakuMediaAirPlay\n{\n    return _isDanmakuMediaAirPlay;\n}\n\n-(void)setIsDanmakuMediaAirPlay:(BOOL)isDanmakuMediaAirPlay\n{\n    _isDanmakuMediaAirPlay = isDanmakuMediaAirPlay;\n    [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerIsAirPlayVideoActiveDidChangeNotification object:nil userInfo:nil];\n}\n\n-(void)setPlaybackRate:(float)playbackRate\n{\n    NSLog(@\"[MPMoviePlayerController setPlaybackRate] is not supported\\n\");\n}\n\n-(float)playbackRate\n{\n    return 1.0f;\n}\n\n-(void)setPlaybackVolume:(float)playbackVolume\n{\n    NSLog(@\"[MPMoviePlayerController setPlaybackVolume] is not supported\\n\");\n}\n\n-(float)playbackVolume\n{\n    return 1.0f;\n}\n\n#pragma mark Movie Notification Handlers\n\n/* Register observers for the various movie object notifications. */\n-(void)IJK_installMovieNotificationObservers\n{\n    [_notificationManager addObserver:self\n                             selector:@selector(IJK_dispatchMPMediaPlaybackIsPreparedToPlayDidChangeNotification:)\n                                 name:MPMediaPlaybackIsPreparedToPlayDidChangeNotification\n                               object:self];\n\n    [_notificationManager addObserver:self\n                             selector:@selector(IJK_dispatchMPMoviePlayerLoadStateDidChangeNotification:)\n                                 name:MPMoviePlayerLoadStateDidChangeNotification\n                               object:self];\n\n    [_notificationManager addObserver:self\n                             selector:@selector(IJK_dispatchMPMoviePlayerPlaybackDidFinishNotification:)\n                                 name:MPMoviePlayerPlaybackDidFinishNotification\n                               object:self];\n\n    [_notificationManager addObserver:self\n                             selector:@selector(IJK_dispatchMPMoviePlayerPlaybackStateDidChangeNotification:)\n                                 name:MPMoviePlayerPlaybackStateDidChangeNotification\n                               object:self];\n\n    [_notificationManager addObserver:self\n                             selector:@selector(IJK_dispatchMoviePlayerIsAirPlayVideoActiveDidChangeNotification:)\n                                 name:MPMoviePlayerIsAirPlayVideoActiveDidChangeNotification\n                               object:self];\n    [_notificationManager addObserver:self\n                             selector:@selector(IJK_dispatchMoviePlayerNaturalSizeAvailableNotification:)\n                                 name:MPMovieNaturalSizeAvailableNotification\n                               object:self];\n}\n\n- (void)IJK_removeMovieNotificationObservers\n{\n    [_notificationManager removeAllObservers:self];\n}\n\n- (void)IJK_dispatchMPMediaPlaybackIsPreparedToPlayDidChangeNotification:(NSNotification*)notification\n{\n    [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification object:notification.object userInfo:notification.userInfo];\n}\n\n- (void)IJK_dispatchMPMoviePlayerLoadStateDidChangeNotification:(NSNotification*)notification\n{\n    [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerLoadStateDidChangeNotification object:notification.object userInfo:notification.userInfo];\n}\n\n- (void)IJK_dispatchMPMoviePlayerPlaybackDidFinishNotification:(NSNotification*)notification\n{\n    [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerPlaybackDidFinishNotification object:notification.object userInfo:notification.userInfo];\n}\n\n- (void)IJK_dispatchMPMoviePlayerPlaybackStateDidChangeNotification:(NSNotification*)notification\n{\n    [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerPlaybackStateDidChangeNotification object:notification.object userInfo:notification.userInfo];\n}\n\n- (void)IJK_dispatchMoviePlayerIsAirPlayVideoActiveDidChangeNotification:(NSNotification*)notification\n{\n    [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerIsAirPlayVideoActiveDidChangeNotification object:notification.object userInfo:notification.userInfo];\n}\n\n- (void)IJK_dispatchMoviePlayerNaturalSizeAvailableNotification:(NSNotification*)notification\n{\n    [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMovieNaturalSizeAvailableNotification object:notification.object userInfo:notification.userInfo];\n}\n\n- (void)setPauseInBackground:(BOOL)pause\n{\n    //mpPlayer还未找到方法实现\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaModule.h",
    "content": "/*\n * IJKMediaModule.h\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import <Foundation/Foundation.h>\n\n@interface IJKMediaModule : NSObject\n\n+ (IJKMediaModule *)sharedModule;\n\n@property(atomic, getter=isAppIdleTimerDisabled)            BOOL appIdleTimerDisabled;\n@property(atomic, getter=isMediaModuleIdleTimerDisabled)    BOOL mediaModuleIdleTimerDisabled;\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaModule.m",
    "content": "/*\n * IJKMediaModule.m\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import \"IJKMediaModule.h\"\n#import <UIKit/UIKit.h>\n\n@implementation IJKMediaModule\n\n@synthesize appIdleTimerDisabled         = _appIdleTimerDisabled;\n@synthesize mediaModuleIdleTimerDisabled = _mediaModuleIdleTimerDisabled;\n\n+ (IJKMediaModule *)sharedModule\n{\n    static IJKMediaModule *obj = nil;\n    static dispatch_once_t onceToken;\n    dispatch_once(&onceToken, ^{\n        obj = [[IJKMediaModule alloc] init];\n    });\n    return obj;\n}\n\n- (void)setAppIdleTimerDisabled:(BOOL) idleTimerDisabled\n{\n    _appIdleTimerDisabled = idleTimerDisabled;\n    [self updateIdleTimer];\n}\n\n- (BOOL)isAppIdleTimerDisabled\n{\n    return _appIdleTimerDisabled;\n}\n\n- (void)setMediaModuleIdleTimerDisabled:(BOOL) idleTimerDisabled\n{\n    _mediaModuleIdleTimerDisabled = idleTimerDisabled;\n    [self updateIdleTimer];\n}\n\n- (BOOL)isMediaModuleIdleTimerDisabled\n{\n    return _mediaModuleIdleTimerDisabled;\n}\n\n- (void)updateIdleTimer\n{\n    if (self.appIdleTimerDisabled || self.mediaModuleIdleTimerDisabled) {\n        [UIApplication sharedApplication].idleTimerDisabled = YES;\n    } else {\n        [UIApplication sharedApplication].idleTimerDisabled = NO;\n    }\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaPlayback.h",
    "content": "/*\n * IJKMediaPlayback.h\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n\ntypedef NS_ENUM(NSInteger, IJKMPMovieScalingMode) {\n    IJKMPMovieScalingModeNone,       // No scaling\n    IJKMPMovieScalingModeAspectFit,  // Uniform scale until one dimension fits\n    IJKMPMovieScalingModeAspectFill, // Uniform scale until the movie fills the visible bounds. One dimension may have clipped contents\n    IJKMPMovieScalingModeFill        // Non-uniform scale. Both render dimensions will exactly match the visible bounds\n};\n\ntypedef NS_ENUM(NSInteger, IJKMPMoviePlaybackState) {\n    IJKMPMoviePlaybackStateStopped,\n    IJKMPMoviePlaybackStatePlaying,\n    IJKMPMoviePlaybackStatePaused,\n    IJKMPMoviePlaybackStateInterrupted,\n    IJKMPMoviePlaybackStateSeekingForward,\n    IJKMPMoviePlaybackStateSeekingBackward\n};\n\ntypedef NS_OPTIONS(NSUInteger, IJKMPMovieLoadState) {\n    IJKMPMovieLoadStateUnknown        = 0,\n    IJKMPMovieLoadStatePlayable       = 1 << 0,\n    IJKMPMovieLoadStatePlaythroughOK  = 1 << 1, // Playback will be automatically started in this state when shouldAutoplay is YES\n    IJKMPMovieLoadStateStalled        = 1 << 2, // Playback will be automatically paused in this state, if started\n};\n\ntypedef NS_ENUM(NSInteger, IJKMPMovieFinishReason) {\n    IJKMPMovieFinishReasonPlaybackEnded,\n    IJKMPMovieFinishReasonPlaybackError,\n    IJKMPMovieFinishReasonUserExited\n};\n\n// -----------------------------------------------------------------------------\n// Thumbnails\n\ntypedef NS_ENUM(NSInteger, IJKMPMovieTimeOption) {\n    IJKMPMovieTimeOptionNearestKeyFrame,\n    IJKMPMovieTimeOptionExact\n};\n\n@protocol IJKMediaPlayback;\n\n#pragma mark IJKMediaPlayback\n\n@protocol IJKMediaPlayback <NSObject>\n\n- (void)prepareToPlay;\n- (void)play;\n- (void)pause;\n- (void)stop;\n- (BOOL)isPlaying;\n- (void)shutdown;\n- (void)setPauseInBackground:(BOOL)pause;\n\n@property(nonatomic, readonly)  UIView *view;\n@property(nonatomic)            NSTimeInterval currentPlaybackTime;\n@property(nonatomic, readonly)  NSTimeInterval duration;\n@property(nonatomic, readonly)  NSTimeInterval playableDuration;\n@property(nonatomic, readonly)  NSInteger bufferingProgress;\n\n@property(nonatomic, readonly)  BOOL isPreparedToPlay;\n@property(nonatomic, readonly)  IJKMPMoviePlaybackState playbackState;\n@property(nonatomic, readonly)  IJKMPMovieLoadState loadState;\n@property(nonatomic, readonly) int isSeekBuffering;\n@property(nonatomic, readonly) int isAudioSync;\n@property(nonatomic, readonly) int isVideoSync;\n\n@property(nonatomic, readonly) int64_t numberOfBytesTransferred;\n\n@property(nonatomic, readonly) CGSize naturalSize;\n@property(nonatomic) IJKMPMovieScalingMode scalingMode;\n@property(nonatomic) BOOL shouldAutoplay;\n\n@property (nonatomic) BOOL allowsMediaAirPlay;\n@property (nonatomic) BOOL isDanmakuMediaAirPlay;\n@property (nonatomic, readonly) BOOL airPlayMediaActive;\n\n@property (nonatomic) float playbackRate;\n@property (nonatomic) float playbackVolume;\n\n- (UIImage *)thumbnailImageAtCurrentTime;\n\n#pragma mark Notifications\n\n#ifdef __cplusplus\n#define IJK_EXTERN extern \"C\" __attribute__((visibility (\"default\")))\n#else\n#define IJK_EXTERN extern __attribute__((visibility (\"default\")))\n#endif\n\n// -----------------------------------------------------------------------------\n//  MPMediaPlayback.h\n\n// Posted when the prepared state changes of an object conforming to the MPMediaPlayback protocol changes.\n// This supersedes MPMoviePlayerContentPreloadDidFinishNotification.\nIJK_EXTERN NSString *const IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification;\n\n// -----------------------------------------------------------------------------\n//  MPMoviePlayerController.h\n//  Movie Player Notifications\n\n// Posted when the scaling mode changes.\nIJK_EXTERN NSString* const IJKMPMoviePlayerScalingModeDidChangeNotification;\n\n// Posted when movie playback ends or a user exits playback.\nIJK_EXTERN NSString* const IJKMPMoviePlayerPlaybackDidFinishNotification;\nIJK_EXTERN NSString* const IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey; // NSNumber (IJKMPMovieFinishReason)\n\n// Posted when the playback state changes, either programatically or by the user.\nIJK_EXTERN NSString* const IJKMPMoviePlayerPlaybackStateDidChangeNotification;\n\n// Posted when the network load state changes.\nIJK_EXTERN NSString* const IJKMPMoviePlayerLoadStateDidChangeNotification;\n\n// Posted when the movie player begins or ends playing video via AirPlay.\nIJK_EXTERN NSString* const IJKMPMoviePlayerIsAirPlayVideoActiveDidChangeNotification;\n\n// -----------------------------------------------------------------------------\n// Movie Property Notifications\n\n// Calling -prepareToPlay on the movie player will begin determining movie properties asynchronously.\n// These notifications are posted when the associated movie property becomes available.\nIJK_EXTERN NSString* const IJKMPMovieNaturalSizeAvailableNotification;\n\n// -----------------------------------------------------------------------------\n//  Extend Notifications\n\nIJK_EXTERN NSString *const IJKMPMoviePlayerVideoDecoderOpenNotification;\nIJK_EXTERN NSString *const IJKMPMoviePlayerFirstVideoFrameRenderedNotification;\nIJK_EXTERN NSString *const IJKMPMoviePlayerFirstAudioFrameRenderedNotification;\nIJK_EXTERN NSString *const IJKMPMoviePlayerFirstAudioFrameDecodedNotification;\nIJK_EXTERN NSString *const IJKMPMoviePlayerFirstVideoFrameDecodedNotification;\nIJK_EXTERN NSString *const IJKMPMoviePlayerOpenInputNotification;\nIJK_EXTERN NSString *const IJKMPMoviePlayerFindStreamInfoNotification;\nIJK_EXTERN NSString *const IJKMPMoviePlayerComponentOpenNotification;\n\nIJK_EXTERN NSString *const IJKMPMoviePlayerDidSeekCompleteNotification;\nIJK_EXTERN NSString *const IJKMPMoviePlayerDidSeekCompleteTargetKey;\nIJK_EXTERN NSString *const IJKMPMoviePlayerDidSeekCompleteErrorKey;\nIJK_EXTERN NSString *const IJKMPMoviePlayerDidAccurateSeekCompleteCurPos;\nIJK_EXTERN NSString *const IJKMPMoviePlayerAccurateSeekCompleteNotification;\nIJK_EXTERN NSString *const IJKMPMoviePlayerSeekAudioStartNotification;\nIJK_EXTERN NSString *const IJKMPMoviePlayerSeekVideoStartNotification;\n\n@end\n\n#pragma mark IJKMediaUrlOpenDelegate\n\n// Must equal to the defination in ijkavformat/ijkavformat.h\ntypedef NS_ENUM(NSInteger, IJKMediaEvent) {\n\n    // Notify Events\n    IJKMediaEvent_WillHttpOpen         = 1,       // attr: url\n    IJKMediaEvent_DidHttpOpen          = 2,       // attr: url, error, http_code\n    IJKMediaEvent_WillHttpSeek         = 3,       // attr: url, offset\n    IJKMediaEvent_DidHttpSeek          = 4,       // attr: url, offset, error, http_code\n    // Control Message\n    IJKMediaCtrl_WillTcpOpen           = 0x20001, // IJKMediaUrlOpenData: no args\n    IJKMediaCtrl_DidTcpOpen            = 0x20002, // IJKMediaUrlOpenData: error, family, ip, port, fd\n    IJKMediaCtrl_WillHttpOpen          = 0x20003, // IJKMediaUrlOpenData: url, segmentIndex, retryCounter\n    IJKMediaCtrl_WillLiveOpen          = 0x20005, // IJKMediaUrlOpenData: url, retryCounter\n    IJKMediaCtrl_WillConcatSegmentOpen = 0x20007, // IJKMediaUrlOpenData: url, segmentIndex, retryCounter\n};\n\n#define IJKMediaEventAttrKey_url            @\"url\"\n#define IJKMediaEventAttrKey_host           @\"host\"\n#define IJKMediaEventAttrKey_error          @\"error\"\n#define IJKMediaEventAttrKey_time_of_event  @\"time_of_event\"\n#define IJKMediaEventAttrKey_http_code      @\"http_code\"\n#define IJKMediaEventAttrKey_offset         @\"offset\"\n#define IJKMediaEventAttrKey_file_size      @\"file_size\"\n\n// event of IJKMediaUrlOpenEvent_xxx\n@interface IJKMediaUrlOpenData: NSObject\n\n- (id)initWithUrl:(NSString *)url\n            event:(IJKMediaEvent)event\n     segmentIndex:(int)segmentIndex\n     retryCounter:(int)retryCounter;\n\n@property(nonatomic, readonly) IJKMediaEvent event;\n@property(nonatomic, readonly) int segmentIndex;\n@property(nonatomic, readonly) int retryCounter;\n\n@property(nonatomic, retain) NSString *url;\n@property(nonatomic, assign) int fd;\n@property(nonatomic, strong) NSString *msg;\n@property(nonatomic) int error; // set a negative value to indicate an error has occured.\n@property(nonatomic, getter=isHandled)    BOOL handled;     // auto set to YES if url changed\n@property(nonatomic, getter=isUrlChanged) BOOL urlChanged;  // auto set to YES by url changed\n\n@end\n\n@protocol IJKMediaUrlOpenDelegate <NSObject>\n\n- (void)willOpenUrl:(IJKMediaUrlOpenData*) urlOpenData;\n\n@end\n\n@protocol IJKMediaNativeInvokeDelegate <NSObject>\n\n- (int)invoke:(IJKMediaEvent)event attributes:(NSDictionary *)attributes;\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaPlayback.m",
    "content": "/*\n * IJKMediaPlayback.m\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import \"IJKMediaPlayback.h\"\n\nNSString *const IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification = @\"IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification\";\n\nNSString *const IJKMPMoviePlayerPlaybackDidFinishNotification = @\"IJKMPMoviePlayerPlaybackDidFinishNotification\";\nNSString *const IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey =\n    @\"IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey\";\nNSString *const IJKMPMoviePlayerPlaybackStateDidChangeNotification = @\"IJKMPMoviePlayerPlaybackStateDidChangeNotification\";\nNSString *const IJKMPMoviePlayerLoadStateDidChangeNotification = @\"IJKMPMoviePlayerLoadStateDidChangeNotification\";\n\nNSString *const IJKMPMoviePlayerIsAirPlayVideoActiveDidChangeNotification = @\"IJKMPMoviePlayerIsAirPlayVideoActiveDidChangeNotification\";\n\nNSString *const IJKMPMovieNaturalSizeAvailableNotification = @\"IJKMPMovieNaturalSizeAvailableNotification\";\n\nNSString *const IJKMPMoviePlayerVideoDecoderOpenNotification = @\"IJKMPMoviePlayerVideoDecoderOpenNotification\";\n\nNSString *const IJKMPMoviePlayerFirstVideoFrameRenderedNotification = @\"IJKMPMoviePlayerFirstVideoFrameRenderedNotification\";\nNSString *const IJKMPMoviePlayerFirstAudioFrameRenderedNotification = @\"IJKMPMoviePlayerFirstAudioFrameRenderedNotification\";\nNSString *const IJKMPMoviePlayerFirstAudioFrameDecodedNotification  = @\"IJKMPMoviePlayerFirstAudioFrameDecodedNotification\";\nNSString *const IJKMPMoviePlayerFirstVideoFrameDecodedNotification  = @\"IJKMPMoviePlayerFirstVideoFrameDecodedNotification\";\nNSString *const IJKMPMoviePlayerOpenInputNotification               = @\"IJKMPMoviePlayerOpenInputNotification\";\nNSString *const IJKMPMoviePlayerFindStreamInfoNotification          = @\"IJKMPMoviePlayerFindStreamInfoNotification\";\nNSString *const IJKMPMoviePlayerComponentOpenNotification           = @\"IJKMPMoviePlayerComponentOpenNotification\";\n\nNSString *const IJKMPMoviePlayerAccurateSeekCompleteNotification = @\"IJKMPMoviePlayerAccurateSeekCompleteNotification\";\n\nNSString *const IJKMPMoviePlayerDidSeekCompleteNotification = @\"IJKMPMoviePlayerDidSeekCompleteNotification\";\nNSString *const IJKMPMoviePlayerDidSeekCompleteTargetKey = @\"IJKMPMoviePlayerDidSeekCompleteTargetKey\";\nNSString *const IJKMPMoviePlayerDidSeekCompleteErrorKey = @\"IJKMPMoviePlayerDidSeekCompleteErrorKey\";\nNSString *const IJKMPMoviePlayerDidAccurateSeekCompleteCurPos = @\"IJKMPMoviePlayerDidAccurateSeekCompleteCurPos\";\n\nNSString *const IJKMPMoviePlayerSeekAudioStartNotification  = @\"IJKMPMoviePlayerSeekAudioStartNotification\";\nNSString *const IJKMPMoviePlayerSeekVideoStartNotification  = @\"IJKMPMoviePlayerSeekVideoStartNotification\";\n\n@implementation IJKMediaUrlOpenData {\n    NSString *_url;\n    BOOL _handled;\n    BOOL _urlChanged;\n}\n\n- (id)initWithUrl:(NSString *)url\n            event:(IJKMediaEvent)event\n     segmentIndex:(int)segmentIndex\n     retryCounter:(int)retryCounter\n{\n    self = [super init];\n    if (self) {\n        self->_url          = url;\n        self->_event        = event;\n        self->_segmentIndex = segmentIndex;\n        self->_retryCounter = retryCounter;\n\n        self->_error        = 0;\n        self->_handled      = NO;\n        self->_urlChanged   = NO;\n    }\n    return self;\n}\n\n- (void)setHandled:(BOOL)handled\n{\n    _handled = handled;\n}\n\n- (BOOL)isHandled\n{\n    return _handled;\n}\n\n- (BOOL)isUrlChanged\n{\n    return _urlChanged;\n}\n\n- (NSString *)url\n{\n    return _url;\n}\n\n- (void)setUrl:(NSString *)url\n{\n    assert(url);\n\n    _handled = YES;\n\n    if (![self.url isEqualToString:url]) {\n        _urlChanged = YES;\n        _url = url;\n    }\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaPlayer-Prefix.pch",
    "content": "//\n// Prefix header for all source files of the 'IJKMediaPlayer' target in the 'IJKMediaPlayer' project\n//\n\n#ifdef __OBJC__\n    #import <Foundation/Foundation.h>\n\n    #import <AudioUnit/AudioUnit.h>\n    #import <CoreAudio/CoreAudioTypes.h>\n    #import <AudioToolbox/AudioToolbox.h>\n\n    #import <QuartzCore/QuartzCore.h>\n    #import <OpenGLES/EAGLDrawable.h>\n    #import <OpenGLES/EAGL.h>\n    #import <OpenGLES/ES2/gl.h>\n    #import <OpenGLES/ES2/glext.h>\n#endif\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaPlayer.h",
    "content": "/*\n * IJKMediaPlayer.h\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import \"IJKMediaPlayback.h\"\n#import \"IJKMPMoviePlayerController.h\"\n\n#import \"IJKFFOptions.h\"\n#import \"IJKFFMoviePlayerController.h\"\n\n#import \"IJKAVMoviePlayerController.h\"\n\n#import \"IJKMediaModule.h\"\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaUtils.h",
    "content": "/*\n * IJKMediaUtils.h\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import <Foundation/Foundation.h>\n\n@interface IJKMediaUtils : NSObject\n\n+ (NSError*)createErrorWithDomain: (NSString*)domain\n                             code: (NSInteger)code\n                      description: (NSString*)description\n                           reason: (NSString*)reason;\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaUtils.m",
    "content": "/*\n * IJKMediaUtils.m\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import \"IJKMediaUtils.h\"\n\n@implementation IJKMediaUtils\n\n+ (NSError*)createErrorWithDomain: (NSString*)domain\n                             code: (NSInteger)code\n                      description: (NSString*)description\n                           reason: (NSString*)reason\n{\n    /* Generate an error describing the failure. */\n    if (description == nil)\n        description = @\"\";\n    if (reason == nil)\n        reason = @\"\";\n\n    NSString *localizedDescription = NSLocalizedString(description, description);\n    NSString *localizedFailureReason = NSLocalizedString(reason, reason);\n    NSDictionary *errorDict = [NSDictionary dictionaryWithObjectsAndKeys:\n                               localizedDescription, NSLocalizedDescriptionKey,\n                               localizedFailureReason, NSLocalizedFailureReasonErrorKey,\n                               nil];\n    NSError *error = [NSError errorWithDomain:domain\n                                         code:0\n                                     userInfo:errorDict];\n    return error;\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKNotificationManager.h",
    "content": "/*\n * IJKNotificationManager.h\n *\n * Copyright (c) 2016 Bilibili\n * Copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import <Foundation/Foundation.h>\n\n@interface IJKNotificationManager : NSObject\n\n- (nullable instancetype)init;\n\n- (void)addObserver:(nonnull id)observer\n           selector:(nonnull SEL)aSelector\n               name:(nullable NSString *)aName\n             object:(nullable id)anObject;\n\n- (void)removeAllObservers:(nonnull id)observer;\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKNotificationManager.m",
    "content": "/*\n * IJKNotificationManager.m\n *\n * Copyright (c) 2016 Bilibili\n * Copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import \"IJKNotificationManager.h\"\n\n@implementation IJKNotificationManager\n{\n    NSMutableDictionary *_registeredNotifications;\n}\n\n- (instancetype)init\n{\n    self = [super init];\n    if (self) {\n        _registeredNotifications = [[NSMutableDictionary alloc] init];\n    }\n    return self;\n}\n\n- (void)addObserver:(nonnull id)observer\n           selector:(nonnull SEL)aSelector\n               name:(nullable NSString *)aName\n             object:(nullable id)anObject\n{\n    [[NSNotificationCenter defaultCenter] addObserver:observer\n                                             selector:aSelector\n                                                 name:aName\n                                               object:anObject];\n\n    [_registeredNotifications setValue:aName forKey:aName];\n}\n\n- (void)removeAllObservers:(nonnull id)observer\n{\n    for (NSString *name in [_registeredNotifications allKeys]) {\n        [[NSNotificationCenter defaultCenter] removeObserver:observer\n                                                        name:name\n                                                      object:nil];\n    }\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/IJKSDLGLViewProtocol.h",
    "content": "/*\n * IJKSDLGLViewProtocol.h\n *\n * Copyright (c) 2017 Bilibili\n * Copyright (c) 2017 raymond <raymondzheng1412@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKSDLGLViewProtocol_h\n#define IJKSDLGLViewProtocol_h\n\n#import <UIKit/UIKit.h>\n\ntypedef struct IJKOverlay IJKOverlay;\nstruct IJKOverlay {\n    int w;\n    int h;\n    UInt32 format;\n    int planes;\n    UInt16 *pitches;\n    UInt8 **pixels;\n    int sar_num;\n    int sar_den;\n    CVPixelBufferRef pixel_buffer;\n};\n\n@protocol IJKSDLGLViewProtocol <NSObject>\n- (UIImage*) snapshot;\n@property(nonatomic, readonly) CGFloat  fps;\n@property(nonatomic)        CGFloat  scaleFactor;\n@property(nonatomic)        BOOL  isThirdGLView;\n- (void) display_pixels: (IJKOverlay *) overlay;\n@end\n\n#endif /* IJKSDLGLViewProtocol_h */\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/NSString+IJKMedia.h",
    "content": "/*\n * NSString+IJKMedia.h\n *\n * Copyright (c) 2016 Bilibili\n * Copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import <Foundation/Foundation.h>\n\n@interface NSString (IJKMedia)\n\n+ (NSString *) ijk_stringBeEmptyIfNil:(NSString *)src;\n\n- (BOOL) ijk_isIpv4;\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/NSString+IJKMedia.m",
    "content": "/*\n * NSString+IJKMedia.m\n *\n * Copyright (c) 2016 Bilibili\n * Copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import \"NSString+IJKMedia.h\"\n\n@implementation NSString (IJKMedia)\n\n- (BOOL) ijk_isIpv4\n{\n    NSString *regexp =\n    @\"^(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\\\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\\\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\\\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])$\";\n\n    NSRange range = [self rangeOfString:regexp options:NSRegularExpressionSearch];\n    return range.location != NSNotFound;\n}\n\n+ (NSString *) ijk_stringBeEmptyIfNil:(NSString *)src\n{\n    if (src == nil)\n        return @\"\";\n\n    return src;\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/ijkplayer_ios.h",
    "content": "/*\n * ijkplayer_ios.h\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijkplayer/ijkplayer.h\"\n#import \"IJKSDLGLView.h\"\n\n// ref_count is 1 after open\nIjkMediaPlayer *ijkmp_ios_create(int (*msg_loop)(void*));\n\nvoid            ijkmp_ios_set_glview(IjkMediaPlayer *mp, IJKSDLGLView *glView);\nbool            ijkmp_ios_is_videotoolbox_open(IjkMediaPlayer *mp);\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/ijkplayer_ios.m",
    "content": "/*\n * ijkplayer_ios.c\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import \"ijkplayer_ios.h\"\n\n#import \"ijksdl/ios/ijksdl_ios.h\"\n\n#include <stdio.h>\n#include <assert.h>\n#include \"ijkplayer/ff_fferror.h\"\n#include \"ijkplayer/ff_ffplay.h\"\n#include \"ijkplayer/ijkplayer_internal.h\"\n#include \"ijkplayer/pipeline/ffpipeline_ffplay.h\"\n#include \"pipeline/ffpipeline_ios.h\"\n\nIjkMediaPlayer *ijkmp_ios_create(int (*msg_loop)(void*))\n{\n    IjkMediaPlayer *mp = ijkmp_create(msg_loop);\n    if (!mp)\n        goto fail;\n\n    mp->ffplayer->vout = SDL_VoutIos_CreateForGLES2();\n    if (!mp->ffplayer->vout)\n        goto fail;\n\n    mp->ffplayer->pipeline = ffpipeline_create_from_ios(mp->ffplayer);\n    if (!mp->ffplayer->pipeline)\n        goto fail;\n\n    return mp;\n\nfail:\n    ijkmp_dec_ref_p(&mp);\n    return NULL;\n}\n\nvoid ijkmp_ios_set_glview_l(IjkMediaPlayer *mp, IJKSDLGLView *glView)\n{\n    assert(mp);\n    assert(mp->ffplayer);\n    assert(mp->ffplayer->vout);\n\n    SDL_VoutIos_SetGLView(mp->ffplayer->vout, glView);\n}\n\nvoid ijkmp_ios_set_glview(IjkMediaPlayer *mp, IJKSDLGLView *glView)\n{\n    assert(mp);\n    MPTRACE(\"ijkmp_ios_set_view(glView=%p)\\n\", (void*)glView);\n    pthread_mutex_lock(&mp->mutex);\n    ijkmp_ios_set_glview_l(mp, glView);\n    pthread_mutex_unlock(&mp->mutex);\n    MPTRACE(\"ijkmp_ios_set_view(glView=%p)=void\\n\", (void*)glView);\n}\n\nbool ijkmp_ios_is_videotoolbox_open_l(IjkMediaPlayer *mp)\n{\n    assert(mp);\n    assert(mp->ffplayer);\n\n    return false;\n}\n\nbool ijkmp_ios_is_videotoolbox_open(IjkMediaPlayer *mp)\n{\n    assert(mp);\n    MPTRACE(\"%s()\\n\", __func__);\n    pthread_mutex_lock(&mp->mutex);\n    bool ret = ijkmp_ios_is_videotoolbox_open_l(mp);\n    pthread_mutex_unlock(&mp->mutex);\n    MPTRACE(\"%s()=%d\\n\", __func__, ret ? 1 : 0);\n    return ret;\n}\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBox.h",
    "content": "/*****************************************************************************\n * IJKVideoToolBox.h\n *****************************************************************************\n *\n * copyright (c) 2014 Zhou Quan <zhouqicy@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKMediaPlayer_videotoolbox_h\n#define IJKMediaPlayer_videotoolbox_h\n\n#include \"ff_ffplay.h\"\n\ntypedef struct Ijk_VideoToolBox_Opaque Ijk_VideoToolBox_Opaque;\ntypedef struct Ijk_VideoToolBox Ijk_VideoToolBox;\n\nstruct Ijk_VideoToolBox {\n\n    Ijk_VideoToolBox_Opaque *opaque;\n\n    int  (*decode_frame)(Ijk_VideoToolBox_Opaque *opaque);\n    void (*free)(Ijk_VideoToolBox_Opaque *opaque);\n};\n\nIjk_VideoToolBox *Ijk_VideoToolbox_Async_Create(FFPlayer* ffp, AVCodecContext* ic);\nIjk_VideoToolBox *Ijk_VideoToolbox_Sync_Create(FFPlayer* ffp, AVCodecContext* ic);\n\n#endif\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBox.m",
    "content": "/*****************************************************************************\n * IJKVideoToolBox.m\n *****************************************************************************\n *\n * copyright (c) 2014 Zhou Quan <zhouqicy@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"IJKVideoToolBox.h\"\n#include \"ijksdl/ijksdl_inc_internal.h\"\n#include \"IJKVideoToolBoxAsync.h\"\n#include \"IJKVideoToolBoxSync.h\"\n\ninline static Ijk_VideoToolBox *Ijk_VideoToolbox_CreateInternal(int async, FFPlayer* ffp, AVCodecContext* ic)\n{\n    Ijk_VideoToolBox *vtb = (Ijk_VideoToolBox*) mallocz(sizeof(Ijk_VideoToolBox));\n    if (!vtb)\n        return NULL;\n    if (async) {\n        vtb->opaque = videotoolbox_async_create(ffp, ic);\n        vtb->decode_frame = videotoolbox_async_decode_frame;\n        vtb->free = videotoolbox_async_free;\n    } else {\n        vtb->opaque = videotoolbox_sync_create(ffp, ic);\n        vtb->decode_frame = videotoolbox_sync_decode_frame;\n        vtb->free = videotoolbox_sync_free;\n    }\n\n    if (!vtb->opaque) {\n        freep((void **)&vtb);\n        return NULL;\n    }\n    return vtb;\n}\n\nIjk_VideoToolBox *Ijk_VideoToolbox_Async_Create(FFPlayer* ffp, AVCodecContext* ic) {\n    return Ijk_VideoToolbox_CreateInternal(1, ffp, ic);\n}\n\nIjk_VideoToolBox *Ijk_VideoToolbox_Sync_Create(FFPlayer* ffp, AVCodecContext* ic) {\n    return Ijk_VideoToolbox_CreateInternal(0, ffp, ic);\n}\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBoxAsync.h",
    "content": "/*****************************************************************************\n * IJKVideoToolBox.h\n *****************************************************************************\n *\n * copyright (c) 2014 Zhou Quan <zhouqicy@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKMediaPlayer_videotoolbox_async_h\n#define IJKMediaPlayer_videotoolbox_async_h\n\n#include \"ff_ffplay.h\"\n\ntypedef struct Ijk_VideoToolBox_Opaque Ijk_VideoToolBox_Opaque;\n\nIjk_VideoToolBox_Opaque* videotoolbox_async_create(FFPlayer* ffp, AVCodecContext* ic);\n\nint videotoolbox_async_decode_frame(Ijk_VideoToolBox_Opaque* opaque);\n\nvoid videotoolbox_async_free(Ijk_VideoToolBox_Opaque* opaque);\n\n#endif\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBoxAsync.m",
    "content": "/*****************************************************************************\n * IJKVideoToolBox.m\n *****************************************************************************\n *\n * copyright (c) 2014 Zhou Quan <zhouqicy@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"IJKVideoToolBoxAsync.h\"\n#include \"ijksdl_vout_overlay_videotoolbox.h\"\n#include \"ffpipeline_ios.h\"\n#include <mach/mach_time.h>\n#include \"libavformat/avc.h\"\n#include \"ijksdl_vout_ios_gles2.h\"\n#include \"h264_sps_parser.h\"\n#include \"ijkplayer/ff_ffplay_debug.h\"\n#import <CoreMedia/CoreMedia.h>\n#import <CoreFoundation/CoreFoundation.h>\n#import <CoreVideo/CVHostTime.h>\n#import <Foundation/Foundation.h>\n#import \"IJKDeviceModel.h\"\n#include <stdatomic.h>\n#import <VideoToolbox/VideoToolbox.h>\n#include \"ff_ffinc.h\"\n#include \"ff_fferror.h\"\n#include \"ff_ffmsg.h\"\n#include \"ijksdl/ios/ijksdl_vout_overlay_videotoolbox.h\"\n\n#define IJK_VTB_FCC_AVCC   SDL_FOURCC('C', 'c', 'v', 'a')\n\n#define MAX_PKT_QUEUE_DEEP   350\n#define VTB_MAX_DECODING_SAMPLES 3\n\ntypedef struct sample_info {\n    int     sample_id;\n\n    double  sort;\n    double  dts;\n    double  pts;\n    int     serial;\n\n    int     sar_num;\n    int     sar_den;\n\n    volatile int is_decoding;\n} sample_info;\n\ntypedef struct sort_queue {\n    AVFrame pic;\n    int serial;\n    int64_t sort;\n    volatile struct sort_queue *nextframe;\n} sort_queue;\n\ntypedef struct VTBFormatDesc\n{\n    CMFormatDescriptionRef      fmt_desc;\n    int32_t                     max_ref_frames;\n    bool                        convert_bytestream;\n    bool                        convert_3byteTo4byteNALSize;\n} VTBFormatDesc;\n\nstruct Ijk_VideoToolBox_Opaque {\n    FFPlayer                   *ffp;\n    volatile bool               refresh_request;\n    volatile bool               new_seg_flag;\n    volatile bool               idr_based_identified;\n    volatile bool               refresh_session;\n    volatile bool               recovery_drop_packet;\n\n    AVCodecParameters          *codecpar;\n    VTBFormatDesc               fmt_desc;\n    VTDecompressionSessionRef   vt_session;\n    pthread_mutex_t             m_queue_mutex;\n    volatile sort_queue        *m_sort_queue;\n    volatile int32_t            m_queue_depth;\n    int                         serial;\n    bool                        dealloced;\n    int                         m_buffer_deep;\n    AVPacket                    m_buffer_packet[MAX_PKT_QUEUE_DEEP];\n\n    SDL_mutex                  *sample_info_mutex;\n    SDL_cond                   *sample_info_cond;\n    sample_info                 sample_info_array[VTB_MAX_DECODING_SAMPLES];\n    volatile int                sample_info_index;\n    volatile int                sample_info_id_generator;\n    volatile int                sample_infos_in_decoding;\n\n    SDL_SpeedSampler            sampler;\n};\n\n\nstatic void vtbformat_destroy(VTBFormatDesc *fmt_desc);\nstatic int  vtbformat_init(VTBFormatDesc *fmt_desc, AVCodecParameters *codecpar);\n\nstatic const char *vtb_get_error_string(OSStatus status) {\n    switch (status) {\n        case kVTInvalidSessionErr:                      return \"kVTInvalidSessionErr\";\n        case kVTVideoDecoderBadDataErr:                 return \"kVTVideoDecoderBadDataErr\";\n        case kVTVideoDecoderUnsupportedDataFormatErr:   return \"kVTVideoDecoderUnsupportedDataFormatErr\";\n        case kVTVideoDecoderMalfunctionErr:             return \"kVTVideoDecoderMalfunctionErr\";\n        default:                                        return \"UNKNOWN\";\n    }\n}\n\nstatic void SortQueuePop(Ijk_VideoToolBox_Opaque* context)\n{\n    if (!context->m_sort_queue || context->m_queue_depth == 0) {\n        return;\n    }\n    pthread_mutex_lock(&context->m_queue_mutex);\n    volatile sort_queue *top_frame = context->m_sort_queue;\n    context->m_sort_queue = context->m_sort_queue->nextframe;\n    context->m_queue_depth--;\n    pthread_mutex_unlock(&context->m_queue_mutex);\n    CVBufferRelease(top_frame->pic.opaque);\n    free((void*)top_frame);\n}\n\nstatic void CFDictionarySetSInt32(CFMutableDictionaryRef dictionary, CFStringRef key, SInt32 numberSInt32)\n{\n    CFNumberRef number;\n    number = CFNumberCreate(NULL, kCFNumberSInt32Type, &numberSInt32);\n    CFDictionarySetValue(dictionary, key, number);\n    CFRelease(number);\n}\n\nstatic void CFDictionarySetBoolean(CFMutableDictionaryRef dictionary, CFStringRef key, BOOL value)\n{\n    CFDictionarySetValue(dictionary, key, value ? kCFBooleanTrue : kCFBooleanFalse);\n}\n\n\ninline static void sample_info_flush(Ijk_VideoToolBox_Opaque* context, int wait_ms)\n{\n    int total_wait = 0;\n    SDL_LockMutex(context->sample_info_mutex);\n\n    while (wait_ms < 0 || total_wait < wait_ms) {\n        if (context->sample_infos_in_decoding <= 0)\n            break;\n\n        int wait_step = 10;\n        SDL_CondWaitTimeout(context->sample_info_cond, context->sample_info_mutex, wait_step);\n        total_wait += wait_step;\n    }\n\n    SDL_UnlockMutex(context->sample_info_mutex);\n}\n\ninline static sample_info* sample_info_peek(Ijk_VideoToolBox_Opaque* context)\n{\n    FFPlayer   *ffp = context->ffp;\n    VideoState *is  = ffp->is;\n\n    SDL_LockMutex(context->sample_info_mutex);\n\n    sample_info *sample_info = &context->sample_info_array[context->sample_info_index];\n    while (sample_info->is_decoding) {\n        if (is->videoq.abort_request) {\n            sample_info = NULL;\n            goto abort;\n        }\n\n        SDL_CondWaitTimeout(context->sample_info_cond, context->sample_info_mutex, 10);\n    }\n\nabort:\n    SDL_UnlockMutex(context->sample_info_mutex);\n    return sample_info;\n}\n\ninline static void sample_info_push(Ijk_VideoToolBox_Opaque* context)\n{\n    FFPlayer   *ffp = context->ffp;\n    VideoState *is  = ffp->is;\n\n    SDL_LockMutex(context->sample_info_mutex);\n\n    sample_info *sample_info = &context->sample_info_array[context->sample_info_index];\n    while (sample_info->is_decoding) {\n        if (is->videoq.abort_request)\n            goto abort;\n\n        SDL_CondWaitTimeout(context->sample_info_cond, context->sample_info_mutex, 10);\n    }\n\n    if (sample_info->is_decoding) {\n        ALOGW(\"%s, reallocate sample in decoding %d -> %d /%d\\n\", __FUNCTION__,\n              sample_info->sample_id,\n              context->sample_info_id_generator,\n              context->sample_infos_in_decoding);\n    } else {\n        sample_info->is_decoding = 1;\n        context->sample_infos_in_decoding++;\n    }\n\n    sample_info->sample_id = context->sample_info_id_generator++;\n    context->sample_info_index++;\n    context->sample_info_index %= VTB_MAX_DECODING_SAMPLES;\n\nabort:\n    SDL_UnlockMutex(context->sample_info_mutex);\n}\n\ninline static void sample_info_drop_last_push(Ijk_VideoToolBox_Opaque* context)\n{\n    SDL_LockMutex(context->sample_info_mutex);\n\n    int last_index = context->sample_info_index + VTB_MAX_DECODING_SAMPLES - 1;\n    last_index %= VTB_MAX_DECODING_SAMPLES;\n\n    sample_info *sample_info = &context->sample_info_array[last_index];\n    if (sample_info->is_decoding) {\n        sample_info->is_decoding = 0;\n        context->sample_infos_in_decoding--;\n    }\n\n    SDL_UnlockMutex(context->sample_info_mutex);\n}\n\ninline static void sample_info_recycle(Ijk_VideoToolBox_Opaque* context, sample_info *sample_info)\n{\n    SDL_LockMutex(context->sample_info_mutex);\n\n    if (sample_info->is_decoding) {\n        sample_info->is_decoding = 0;\n        if (context->sample_infos_in_decoding > 0)\n            context->sample_infos_in_decoding--;\n    } else {\n        ALOGW(\"%s, multiple frames in same sample %d / %d\\n\", __FUNCTION__,\n              sample_info->sample_id,\n              context->sample_info_id_generator);\n    }\n\n    SDL_CondSignal(context->sample_info_cond);\n    SDL_UnlockMutex(context->sample_info_mutex);\n}\n\nstatic CMSampleBufferRef CreateSampleBufferFrom(CMFormatDescriptionRef fmt_desc, void *demux_buff, size_t demux_size)\n{\n    OSStatus status;\n    CMBlockBufferRef newBBufOut = NULL;\n    CMSampleBufferRef sBufOut = NULL;\n\n    status = CMBlockBufferCreateWithMemoryBlock(\n                                                NULL,\n                                                demux_buff,\n                                                demux_size,\n                                                kCFAllocatorNull,\n                                                NULL,\n                                                0,\n                                                demux_size,\n                                                FALSE,\n                                                &newBBufOut);\n\n    if (!status) {\n        status = CMSampleBufferCreate(\n                                      NULL,\n                                      newBBufOut,\n                                      TRUE,\n                                      0,\n                                      0,\n                                      fmt_desc,\n                                      1,\n                                      0,\n                                      NULL,\n                                      0,\n                                      NULL,\n                                      &sBufOut);\n    }\n\n    if (newBBufOut)\n        CFRelease(newBBufOut);\n    if (status == 0) {\n        return sBufOut;\n    } else {\n        return NULL;\n    }\n}\n\n\n\n\nstatic bool GetVTBPicture(Ijk_VideoToolBox_Opaque* context, AVFrame* pVTBPicture)\n{\n    if (context->m_sort_queue == NULL) {\n        return false;\n    }\n    pthread_mutex_lock(&context->m_queue_mutex);\n\n    volatile sort_queue *sort_queue = context->m_sort_queue;\n    *pVTBPicture        = sort_queue->pic;\n    pVTBPicture->opaque = CVBufferRetain(sort_queue->pic.opaque);\n\n    pthread_mutex_unlock(&context->m_queue_mutex);\n\n    return true;\n}\n\nstatic void QueuePicture(Ijk_VideoToolBox_Opaque* ctx) {\n    AVFrame picture = {0};\n    if (true == GetVTBPicture(ctx, &picture)) {\n        AVRational tb = ctx->ffp->is->video_st->time_base;\n        AVRational frame_rate = av_guess_frame_rate(ctx->ffp->is->ic, ctx->ffp->is->video_st, NULL);\n        double duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational) {frame_rate.den, frame_rate.num}) : 0);\n        double pts = (picture.pts == AV_NOPTS_VALUE) ? NAN : picture.pts * av_q2d(tb);\n\n        picture.format = IJK_AV_PIX_FMT__VIDEO_TOOLBOX;\n\n        ffp_queue_picture(ctx->ffp, &picture, pts, duration, 0, ctx->ffp->is->viddec.pkt_serial);\n\n        CVBufferRelease(picture.opaque);\n\n        SortQueuePop(ctx);\n    } else {\n        ALOGI(\"Get Picture failure!!!\\n\");\n    }\n}\n\n\nstatic void VTDecoderCallback(void *decompressionOutputRefCon,\n                       void *sourceFrameRefCon,\n                       OSStatus status,\n                       VTDecodeInfoFlags infoFlags,\n                       CVImageBufferRef imageBuffer,\n                       CMTime presentationTimeStamp,\n                       CMTime presentationDuration)\n{\n    @autoreleasepool {\n        Ijk_VideoToolBox_Opaque *ctx = (Ijk_VideoToolBox_Opaque*)decompressionOutputRefCon;\n        if (!ctx)\n            return;\n\n        FFPlayer   *ffp         = ctx->ffp;\n        VideoState *is          = ffp->is;\n        sort_queue *newFrame    = NULL;\n\n        sample_info *sample_info = sourceFrameRefCon;\n        if (!sample_info->is_decoding) {\n            ALOGD(\"VTB: frame out of date: id=%d\\n\", sample_info->sample_id);\n            goto failed;\n        }\n\n        newFrame = (sort_queue *)mallocz(sizeof(sort_queue));\n        if (!newFrame) {\n            ALOGE(\"VTB: create new frame fail: out of memory\\n\");\n            goto failed;\n        }\n\n        newFrame->pic.pts        = sample_info->pts;\n        newFrame->pic.pkt_dts    = sample_info->dts;\n        newFrame->pic.sample_aspect_ratio.num = sample_info->sar_num;\n        newFrame->pic.sample_aspect_ratio.den = sample_info->sar_den;\n        newFrame->serial     = sample_info->serial;\n        newFrame->nextframe  = NULL;\n\n        if (newFrame->pic.pts != AV_NOPTS_VALUE) {\n            newFrame->sort    = newFrame->pic.pts;\n        } else {\n            newFrame->sort    = newFrame->pic.pkt_dts;\n            newFrame->pic.pts = newFrame->pic.pkt_dts;\n        }\n\n        if (ctx->dealloced || is->abort_request || is->viddec.queue->abort_request)\n            goto failed;\n\n        if (status != 0) {\n            ALOGE(\"decode callback %d %s\\n\", (int)status, vtb_get_error_string(status));\n            goto failed;\n        }\n\n        if (ctx->refresh_session) {\n            goto failed;\n        }\n\n        if (newFrame->serial != ctx->serial) {\n            goto failed;\n        }\n\n        if (imageBuffer == NULL) {\n            ALOGI(\"imageBuffer null\\n\");\n            goto failed;\n        }\n\n        ffp->stat.vdps = SDL_SpeedSamplerAdd(&ctx->sampler, FFP_SHOW_VDPS_VIDEOTOOLBOX, \"vdps[VideoToolbox]\");\n#ifdef FFP_VTB_DISABLE_OUTPUT\n        goto failed;\n#endif\n\n        OSType format_type = CVPixelBufferGetPixelFormatType(imageBuffer);\n        if (format_type != kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) {\n            ALOGI(\"format_type error \\n\");\n            goto failed;\n        }\n        if (kVTDecodeInfo_FrameDropped & infoFlags) {\n            ALOGI(\"droped\\n\");\n            goto failed;\n        }\n\n        if (ctx->new_seg_flag) {\n            ALOGI(\"new seg process!!!!\");\n            while (ctx->m_queue_depth > 0) {\n                QueuePicture(ctx);\n            }\n            ctx->new_seg_flag = false;\n        }\n\n        if (ctx->m_sort_queue && newFrame->pic.pts < ctx->m_sort_queue->pic.pts) {\n            goto failed;\n        }\n\n        // FIXME: duplicated code\n        {\n            double dpts = NAN;\n\n            if (newFrame->pic.pts != AV_NOPTS_VALUE)\n                dpts = av_q2d(is->video_st->time_base) * newFrame->pic.pts;\n\n            if (ffp->framedrop>0 || (ffp->framedrop && ffp_get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) {\n                ffp->stat.decode_frame_count++;\n                if (newFrame->pic.pts != AV_NOPTS_VALUE) {\n                    double diff = dpts - ffp_get_master_clock(is);\n                    if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD &&\n                        diff - is->frame_last_filter_delay < 0 &&\n                        is->viddec.pkt_serial == is->vidclk.serial &&\n                        is->videoq.nb_packets) {\n                        is->frame_drops_early++;\n                        is->continuous_frame_drops_early++;\n                        if (is->continuous_frame_drops_early > ffp->framedrop) {\n                            is->continuous_frame_drops_early = 0;\n                        } else {\n                            ffp->stat.drop_frame_count++;\n                            ffp->stat.drop_frame_rate = (float)(ffp->stat.drop_frame_count) / (float)(ffp->stat.decode_frame_count);\n                            // drop too late frame\n                            goto failed;\n                        }\n                    }\n                }\n            }\n        }\n\n        if (CVPixelBufferIsPlanar(imageBuffer)) {\n            newFrame->pic.width  = (int)CVPixelBufferGetWidthOfPlane(imageBuffer, 0);\n            newFrame->pic.height = (int)CVPixelBufferGetHeightOfPlane(imageBuffer, 0);\n        } else {\n            newFrame->pic.width  = (int)CVPixelBufferGetWidth(imageBuffer);\n            newFrame->pic.height = (int)CVPixelBufferGetHeight(imageBuffer);\n        }\n\n\n        newFrame->pic.opaque = CVBufferRetain(imageBuffer);\n        pthread_mutex_lock(&ctx->m_queue_mutex);\n        volatile sort_queue *queueWalker = ctx->m_sort_queue;\n        if (!queueWalker || (newFrame->sort < queueWalker->sort)) {\n            newFrame->nextframe = queueWalker;\n            ctx->m_sort_queue = newFrame;\n        } else {\n            bool frameInserted = false;\n            volatile sort_queue *nextFrame = NULL;\n            while (!frameInserted) {\n                nextFrame = queueWalker->nextframe;\n                if (!nextFrame || (newFrame->sort < nextFrame->sort)) {\n                    newFrame->nextframe = nextFrame;\n                    queueWalker->nextframe = newFrame;\n                    frameInserted = true;\n                }\n                queueWalker = nextFrame;\n            }\n        }\n        ctx->m_queue_depth++;\n        pthread_mutex_unlock(&ctx->m_queue_mutex);\n\n        //ALOGI(\"%lf %lf %lf \\n\", newFrame->sort,newFrame->pts, newFrame->dts);\n        //ALOGI(\"display queue deep %d\\n\", ctx->m_queue_depth);\n\n        if (ctx->ffp->is == NULL || ctx->ffp->is->abort_request || ctx->ffp->is->viddec.queue->abort_request) {\n            while (ctx->m_queue_depth > 0) {\n                SortQueuePop(ctx);\n            }\n            goto successed;\n        }\n        //ALOGI(\"depth %d  %d\\n\", ctx->m_queue_depth, ctx->m_max_ref_frames);\n        if ((ctx->m_queue_depth > ctx->fmt_desc.max_ref_frames)) {\n            QueuePicture(ctx);\n        }\n    successed:\n        sample_info_recycle(ctx, sample_info);\n        return;\n    failed:\n        sample_info_recycle(ctx, sample_info);\n        if (newFrame) {\n            free(newFrame);\n        }\n        return;\n    }\n}\n\n\nstatic void vtbsession_destroy(Ijk_VideoToolBox_Opaque *context)\n{\n    if (!context)\n        return;\n\n    vtbformat_destroy(&context->fmt_desc);\n\n    if (context->vt_session) {\n        VTDecompressionSessionWaitForAsynchronousFrames(context->vt_session);\n        VTDecompressionSessionInvalidate(context->vt_session);\n        CFRelease(context->vt_session);\n        context->vt_session = NULL;\n    }\n}\n\nstatic VTDecompressionSessionRef vtbsession_create(Ijk_VideoToolBox_Opaque* context)\n{\n    FFPlayer *ffp = context->ffp;\n    int       ret = 0;\n    int       width  = context->codecpar->width;\n    int       height = context->codecpar->height;\n\n    VTDecompressionSessionRef vt_session = NULL;\n    CFMutableDictionaryRef destinationPixelBufferAttributes;\n    VTDecompressionOutputCallbackRecord outputCallback;\n    OSStatus status;\n\n    ret = vtbformat_init(&context->fmt_desc, context->codecpar);\n\n    if (ffp->vtb_max_frame_width > 0 && width > ffp->vtb_max_frame_width) {\n        double w_scaler = (float)ffp->vtb_max_frame_width / width;\n        width = ffp->vtb_max_frame_width;\n        height = height * w_scaler;\n    }\n\n    ALOGI(\"after scale width %d height %d \\n\", width, height);\n\n    destinationPixelBufferAttributes = CFDictionaryCreateMutable(\n                                                                 NULL,\n                                                                 0,\n                                                                 &kCFTypeDictionaryKeyCallBacks,\n                                                                 &kCFTypeDictionaryValueCallBacks);\n    CFDictionarySetSInt32(destinationPixelBufferAttributes,\n                          kCVPixelBufferPixelFormatTypeKey, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange);\n    CFDictionarySetSInt32(destinationPixelBufferAttributes,\n                          kCVPixelBufferWidthKey, width);\n    CFDictionarySetSInt32(destinationPixelBufferAttributes,\n                          kCVPixelBufferHeightKey, height);\n    CFDictionarySetBoolean(destinationPixelBufferAttributes,\n                          kCVPixelBufferOpenGLESCompatibilityKey, YES);\n    outputCallback.decompressionOutputCallback = VTDecoderCallback;\n    outputCallback.decompressionOutputRefCon = context  ;\n    status = VTDecompressionSessionCreate(\n                                          kCFAllocatorDefault,\n                                          context->fmt_desc.fmt_desc,\n                                          NULL,\n                                          destinationPixelBufferAttributes,\n                                          &outputCallback,\n                                          &vt_session);\n\n    if (status != noErr) {\n        NSError* error = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil];\n        NSLog(@\"Error %@\", [error description]);\n        ALOGI(\"%s - failed with status = (%d)\", __FUNCTION__, (int)status);\n    }\n    CFRelease(destinationPixelBufferAttributes);\n\n    memset(context->sample_info_array, 0, sizeof(context->sample_info_array));\n    context->sample_infos_in_decoding = 0;\n    return vt_session;\n}\n\n\n\nstatic int decode_video_internal(Ijk_VideoToolBox_Opaque* context, AVCodecContext *avctx, const AVPacket *avpkt, int* got_picture_ptr)\n{\n    FFPlayer *ffp                   = context->ffp;\n    OSStatus status                 = 0;\n    uint32_t decoder_flags          = 0;\n    sample_info *sample_info        = NULL;\n    CMSampleBufferRef sample_buff   = NULL;\n    AVIOContext *pb                 = NULL;\n    int demux_size                  = 0;\n    uint8_t *demux_buff             = NULL;\n    uint8_t *pData                  = avpkt->data;\n    int iSize                       = avpkt->size;\n    double pts                      = avpkt->pts;\n    double dts                      = avpkt->dts;\n\n    if (!context) {\n        goto failed;\n    }\n\n    if (ffp->vtb_async) {\n        decoder_flags |= kVTDecodeFrame_EnableAsynchronousDecompression;\n    }\n\n    if (context->refresh_session) {\n        decoder_flags |= kVTDecodeFrame_DoNotOutputFrame;\n        // ALOGI(\"flag :%d flag %d \\n\", decoderFlags,avpkt->flags);\n    }\n\n    if (context->refresh_request) {\n        while (context->m_queue_depth > 0) {\n            SortQueuePop(context);\n        }\n\n        sample_info_flush(context, 1000);\n        vtbsession_destroy(context);\n        memset(context->sample_info_array, 0, sizeof(context->sample_info_array));\n        context->sample_infos_in_decoding = 0;\n\n        context->vt_session = vtbsession_create(context);\n        if (!context->vt_session)\n            goto failed;\n        context->refresh_request = false;\n    }\n\n    if (pts == AV_NOPTS_VALUE) {\n        pts = dts;\n    }\n\n    if (context->fmt_desc.convert_bytestream) {\n        // ALOGI(\"the buffer should m_convert_byte\\n\");\n        if(avio_open_dyn_buf(&pb) < 0) {\n            goto failed;\n        }\n        ff_avc_parse_nal_units(pb, pData, iSize);\n        demux_size = avio_close_dyn_buf(pb, &demux_buff);\n        // ALOGI(\"demux_size:%d\\n\", demux_size);\n        if (demux_size == 0) {\n            goto failed;\n        }\n        sample_buff = CreateSampleBufferFrom(context->fmt_desc.fmt_desc, demux_buff, demux_size);\n    } else if (context->fmt_desc.convert_3byteTo4byteNALSize) {\n        // ALOGI(\"3byteto4byte\\n\");\n        if (avio_open_dyn_buf(&pb) < 0) {\n            goto failed;\n        }\n\n        uint32_t nal_size;\n        uint8_t *end = avpkt->data + avpkt->size;\n        uint8_t *nal_start = pData;\n        while (nal_start < end) {\n            nal_size = AV_RB24(nal_start);\n            avio_wb32(pb, nal_size);\n            nal_start += 3;\n            avio_write(pb, nal_start, nal_size);\n            nal_start += nal_size;\n        }\n        demux_size = avio_close_dyn_buf(pb, &demux_buff);\n        sample_buff = CreateSampleBufferFrom(context->fmt_desc.fmt_desc, demux_buff, demux_size);\n    } else {\n        sample_buff = CreateSampleBufferFrom(context->fmt_desc.fmt_desc, pData, iSize);\n    }\n    if (!sample_buff) {\n        if (demux_size) {\n            av_free(demux_buff);\n        }\n        ALOGI(\"%s - CreateSampleBufferFrom failed\", __FUNCTION__);\n        goto failed;\n    }\n\n    if (avpkt->flags & AV_PKT_FLAG_NEW_SEG) {\n        context->new_seg_flag = true;\n    }\n\n    sample_info = sample_info_peek(context);\n    if (!sample_info) {\n        ALOGE(\"%s, failed to peek frame_info\\n\", __FUNCTION__);\n        goto failed;\n    }\n\n    sample_info->pts    = pts;\n    sample_info->dts    = dts;\n    sample_info->serial = context->serial;\n    sample_info->sar_num = avctx->sample_aspect_ratio.num;\n    sample_info->sar_den = avctx->sample_aspect_ratio.den;\n    sample_info_push(context);\n\n    status = VTDecompressionSessionDecodeFrame(context->vt_session, sample_buff, decoder_flags, (void*)sample_info, 0);\n    if (status == noErr) {\n        if (context->ffp->is->videoq.abort_request)\n            goto failed;\n\n        // Wait for delayed frames even if kVTDecodeInfo_Asynchronous is not set.\n        if (ffp->vtb_wait_async) {\n            status = VTDecompressionSessionWaitForAsynchronousFrames(context->vt_session);\n        }\n    }\n\n    if (status != 0) {\n        sample_info_drop_last_push(context);\n\n        ALOGE(\"decodeFrame %d %s\\n\", (int)status, vtb_get_error_string(status));\n\n        if (status == kVTInvalidSessionErr) {\n            context->refresh_session = true;\n        }\n        if (status == kVTVideoDecoderMalfunctionErr) {\n            context->recovery_drop_packet = true;\n            context->refresh_session = true;\n        }\n        goto failed;\n    }\n\n\n\n    if (sample_buff) {\n        CFRelease(sample_buff);\n    }\n    if (demux_size) {\n        av_free(demux_buff);\n    }\n\n    *got_picture_ptr = 1;\n    return 0;\nfailed:\n    if (sample_buff) {\n        CFRelease(sample_buff);\n    }\n    if (demux_size) {\n        av_free(demux_buff);\n    }\n    *got_picture_ptr = 0;\n    return -1;\n}\n\nstatic inline void ResetPktBuffer(Ijk_VideoToolBox_Opaque* context) {\n    for (int i = 0 ; i < context->m_buffer_deep; i++) {\n        av_packet_unref(&context->m_buffer_packet[i]);\n    }\n    context->m_buffer_deep = 0;\n    memset(context->m_buffer_packet, 0, sizeof(context->m_buffer_packet));\n}\n\nstatic inline void DuplicatePkt(Ijk_VideoToolBox_Opaque* context, const AVPacket* pkt) {\n    if (context->m_buffer_deep >= MAX_PKT_QUEUE_DEEP) {\n        context->idr_based_identified = false;\n        ResetPktBuffer(context);\n    }\n    AVPacket* avpkt = &context->m_buffer_packet[context->m_buffer_deep];\n    av_copy_packet(avpkt, pkt);\n    context->m_buffer_deep++;\n}\n\n\n\nstatic int decode_video(Ijk_VideoToolBox_Opaque* context, AVCodecContext *avctx, AVPacket *avpkt, int* got_picture_ptr)\n{\n    int      ret            = 0;\n    uint8_t *size_data      = NULL;\n    int      size_data_size = 0;\n\n    if (!avpkt || !avpkt->data) {\n        return 0;\n    }\n\n    if (context->ffp->vtb_handle_resolution_change &&\n        context->codecpar->codec_id == AV_CODEC_ID_H264) {\n        size_data = av_packet_get_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, &size_data_size);\n        // minimum avcC(sps,pps) = 7\n        if (size_data && size_data_size > 7) {\n            int             got_picture = 0;\n            AVFrame        *frame      = av_frame_alloc();\n            AVDictionary   *codec_opts = NULL;\n            AVCodecContext *new_avctx  = avcodec_alloc_context3(avctx->codec);\n            if (!new_avctx)\n                return AVERROR(ENOMEM);\n\n            avcodec_parameters_to_context(new_avctx, context->codecpar);\n            av_freep(&new_avctx->extradata);\n            new_avctx->extradata = av_mallocz(size_data_size + AV_INPUT_BUFFER_PADDING_SIZE);\n            if (!new_avctx->extradata)\n                return AVERROR(ENOMEM);\n            memcpy(new_avctx->extradata, size_data, size_data_size);\n            new_avctx->extradata_size = size_data_size;\n\n            av_dict_set(&codec_opts, \"threads\", \"1\", 0);\n            ret = avcodec_open2(new_avctx, avctx->codec, &codec_opts);\n            av_dict_free(&codec_opts);\n            if (ret < 0) {\n                avcodec_free_context(&new_avctx);\n                return ret;\n            }\n\n            ret = avcodec_decode_video2(new_avctx, frame, &got_picture, avpkt);\n            if (ret < 0) {\n                avcodec_free_context(&new_avctx);\n                return ret;\n            } else {\n                if (context->codecpar->width  != new_avctx->width &&\n                    context->codecpar->height != new_avctx->height) {\n                    avcodec_parameters_from_context(context->codecpar, new_avctx);\n                    context->refresh_request = true;\n                }\n            }\n\n            av_frame_unref(frame);\n            avcodec_free_context(&new_avctx);\n        }\n    } else {\n        if (ff_avpacket_is_idr(avpkt) == true) {\n            context->idr_based_identified = true;\n        }\n        if (ff_avpacket_i_or_idr(avpkt, context->idr_based_identified) == true) {\n            ResetPktBuffer(context);\n            context->recovery_drop_packet = false;\n        }\n        if (context->recovery_drop_packet == true) {\n            return -1;\n        }\n    }\n\n    DuplicatePkt(context, avpkt);\n\n    if (context->refresh_session) {\n        ret = 0;\n\n        sample_info_flush(context, 1000);\n        vtbsession_destroy(context);\n        memset(context->sample_info_array, 0, sizeof(context->sample_info_array));\n        context->sample_infos_in_decoding = 0;\n\n        context->vt_session = vtbsession_create(context);\n        if (!context->vt_session)\n            return -1;\n\n        if ((context->m_buffer_deep > 0) &&\n            ff_avpacket_i_or_idr(&context->m_buffer_packet[0], context->idr_based_identified) == true ) {\n            for (int i = 0; i < context->m_buffer_deep; i++) {\n                AVPacket* pkt = &context->m_buffer_packet[i];\n                ret = decode_video_internal(context, avctx, pkt, got_picture_ptr);\n            }\n        } else {\n            context->recovery_drop_packet = true;\n            ret = -1;\n            ALOGE(\"recovery error!!!!\\n\");\n        }\n        context->refresh_session = false;\n        return ret;\n    }\n    return decode_video_internal(context, avctx, avpkt, got_picture_ptr);\n}\n\n\nstatic void dict_set_string(CFMutableDictionaryRef dict, CFStringRef key, const char * value)\n{\n    CFStringRef string;\n    string = CFStringCreateWithCString(NULL, value, kCFStringEncodingASCII);\n    CFDictionarySetValue(dict, key, string);\n    CFRelease(string);\n}\n\nstatic void dict_set_boolean(CFMutableDictionaryRef dict, CFStringRef key, BOOL value)\n{\n    CFDictionarySetValue(dict, key, value ? kCFBooleanTrue: kCFBooleanFalse);\n}\n\n\nstatic void dict_set_object(CFMutableDictionaryRef dict, CFStringRef key, CFTypeRef *value)\n{\n    CFDictionarySetValue(dict, key, value);\n}\n\nstatic void dict_set_data(CFMutableDictionaryRef dict, CFStringRef key, uint8_t * value, uint64_t length)\n{\n    CFDataRef data;\n    data = CFDataCreate(NULL, value, (CFIndex)length);\n    CFDictionarySetValue(dict, key, data);\n    CFRelease(data);\n}\n\nstatic void dict_set_i32(CFMutableDictionaryRef dict, CFStringRef key,\n                         int32_t value)\n{\n    CFNumberRef number;\n    number = CFNumberCreate(NULL, kCFNumberSInt32Type, &value);\n    CFDictionarySetValue(dict, key, number);\n    CFRelease(number);\n}\n\nstatic CMFormatDescriptionRef CreateFormatDescriptionFromCodecData(CMVideoCodecType format_id, int width, int height, const uint8_t *extradata, int extradata_size, uint32_t atom)\n{\n    CMFormatDescriptionRef fmt_desc = NULL;\n    OSStatus status;\n\n    CFMutableDictionaryRef par = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,&kCFTypeDictionaryValueCallBacks);\n    CFMutableDictionaryRef atoms = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,&kCFTypeDictionaryValueCallBacks);\n    CFMutableDictionaryRef extensions = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);\n\n    /* CVPixelAspectRatio dict */\n    dict_set_i32(par, CFSTR (\"HorizontalSpacing\"), 0);\n    dict_set_i32(par, CFSTR (\"VerticalSpacing\"), 0);\n    \n    /* SampleDescriptionExtensionAtoms dict */\n    switch (format_id) {\n        case kCMVideoCodecType_H264:\n            dict_set_data(atoms, CFSTR (\"avcC\"), (uint8_t *)extradata, extradata_size);\n            break;\n        case kCMVideoCodecType_HEVC:\n            dict_set_data(atoms, CFSTR (\"hvcC\"), (uint8_t *)extradata, extradata_size);\n            break;\n        default:\n            break;\n    }\n\n\n      /* Extensions dict */\n    dict_set_string(extensions, CFSTR (\"CVImageBufferChromaLocationBottomField\"), \"left\");\n    dict_set_string(extensions, CFSTR (\"CVImageBufferChromaLocationTopField\"), \"left\");\n    dict_set_boolean(extensions, CFSTR(\"FullRangeVideo\"), FALSE);\n    dict_set_object(extensions, CFSTR (\"CVPixelAspectRatio\"), (CFTypeRef *) par);\n    dict_set_object(extensions, CFSTR (\"SampleDescriptionExtensionAtoms\"), (CFTypeRef *) atoms);\n    status = CMVideoFormatDescriptionCreate(NULL, format_id, width, height, extensions, &fmt_desc);\n\n    CFRelease(extensions);\n    CFRelease(atoms);\n    CFRelease(par);\n\n    if (status == 0)\n        return fmt_desc;\n    else\n        return NULL;\n}\n\nvoid videotoolbox_async_free(Ijk_VideoToolBox_Opaque* context)\n{\n    context->dealloced = true;\n\n    while (context && context->m_queue_depth > 0) {\n        SortQueuePop(context);\n    }\n\n    sample_info_flush(context, 3000);\n    vtbsession_destroy(context);\n\n    if (context) {\n        ResetPktBuffer(context);\n        SDL_DestroyCondP(&context->sample_info_cond);\n        SDL_DestroyMutexP(&context->sample_info_mutex);\n    }\n\n    vtbformat_destroy(&context->fmt_desc);\n\n    avcodec_parameters_free(&context->codecpar);\n}\n\nint videotoolbox_async_decode_frame(Ijk_VideoToolBox_Opaque* context)\n{\n    FFPlayer *ffp = context->ffp;\n    VideoState *is = ffp->is;\n    Decoder *d = &is->viddec;\n    int got_frame = 0;\n    do {\n        int ret = -1;\n        if (is->abort_request || d->queue->abort_request) {\n            return -1;\n        }\n\n        if (!d->packet_pending || d->queue->serial != d->pkt_serial) {\n            AVPacket pkt;\n            do {\n                if (d->queue->nb_packets == 0)\n                    SDL_CondSignal(d->empty_queue_cond);\n                ffp_video_statistic_l(ffp);\n                if (ffp_packet_queue_get_or_buffering(ffp, d->queue, &pkt, &d->pkt_serial, &d->finished) < 0)\n                    return -1;\n                if (ffp_is_flush_packet(&pkt)) {\n                    avcodec_flush_buffers(d->avctx);\n                    context->refresh_request = true;\n                    context->serial += 1;\n                    d->finished = 0;\n                    ALOGI(\"flushed last keyframe pts %lld \\n\",d->pkt.pts);\n                    d->next_pts = d->start_pts;\n                    d->next_pts_tb = d->start_pts_tb;\n                }\n            } while (ffp_is_flush_packet(&pkt) || d->queue->serial != d->pkt_serial);\n\n            av_packet_split_side_data(&pkt);\n\n            av_packet_unref(&d->pkt);\n            d->pkt_temp = d->pkt = pkt;\n            d->packet_pending = 1;\n        }\n\n        ret = decode_video(context, d->avctx, &d->pkt_temp, &got_frame);\n        if (ret < 0) {\n            d->packet_pending = 0;\n        } else {\n            d->pkt_temp.dts =\n            d->pkt_temp.pts = AV_NOPTS_VALUE;\n            if (d->pkt_temp.data) {\n                if (d->avctx->codec_type != AVMEDIA_TYPE_AUDIO)\n                    ret = d->pkt_temp.size;\n                d->pkt_temp.data += ret;\n                d->pkt_temp.size -= ret;\n                if (d->pkt_temp.size <= 0)\n                    d->packet_pending = 0;\n            } else {\n                if (!got_frame) {\n                    d->packet_pending = 0;\n                    d->finished = d->pkt_serial;\n                }\n            }\n        }\n    } while (!got_frame && !d->finished);\n    return got_frame;\n}\n\nstatic void vtbformat_destroy(VTBFormatDesc *fmt_desc)\n{\n    if (!fmt_desc || !fmt_desc->fmt_desc)\n        return;\n\n    CFRelease(fmt_desc->fmt_desc);\n    fmt_desc->fmt_desc = NULL;\n}\n\nstatic int vtbformat_init(VTBFormatDesc *fmt_desc, AVCodecParameters *codecpar)\n{\n    int width           = codecpar->width;\n    int height          = codecpar->height;\n    int level           = codecpar->level;\n    int profile         = codecpar->profile;\n    int sps_level       = 0;\n    int sps_profile     = 0;\n    int extrasize       = codecpar->extradata_size;\n    int codec           = codecpar->codec_id;\n    uint8_t* extradata  = codecpar->extradata;\n\n    bool isHevcSupported = false;\n    CMVideoCodecType format_id = 0;\n    \n#if 0\n    switch (profile) {\n        case FF_PROFILE_H264_HIGH_10:\n            if ([IJKDeviceModel currentModel].rank >= kIJKDeviceRank_AppleA7Class) {\n                // Apple A7 SoC\n                // Hi10p can be decoded into NV12 ('420v')\n                break;\n            }\n        case FF_PROFILE_H264_HIGH_10_INTRA:\n        case FF_PROFILE_H264_HIGH_422:\n        case FF_PROFILE_H264_HIGH_422_INTRA:\n        case FF_PROFILE_H264_HIGH_444_PREDICTIVE:\n        case FF_PROFILE_H264_HIGH_444_INTRA:\n        case FF_PROFILE_H264_CAVLC_444:\n            goto failed;\n    }\n#endif\n    if (width < 0 || height < 0) {\n        goto fail;\n    }\n\n    if (extrasize < 7 || extradata == NULL) {\n        ALOGI(\"%s - avcC or hvcC atom data too small or missing\", __FUNCTION__);\n        goto fail;\n    }\n\n    switch (codec) {\n        case AV_CODEC_ID_HEVC:\n            format_id = kCMVideoCodecType_HEVC;\n            if (@available(iOS 11.0, *)) {\n                isHevcSupported = VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC);\n            } else {\n                // Fallback on earlier versions\n                isHevcSupported = false;\n            }\n            if (!isHevcSupported) {\n                goto fail;\n            }\n            break;\n            \n        case AV_CODEC_ID_H264:\n            format_id = kCMVideoCodecType_H264;\n            break;\n            \n        default:\n            goto fail;\n    }\n    \n    if (extradata[0] == 1) {\n//                if (!validate_avcC_spc(extradata, extrasize, &fmt_desc->max_ref_frames, &sps_level, &sps_profile)) {\n            //goto failed;\n//                }\n        if (level == 0 && sps_level > 0)\n            level = sps_level;\n\n                if (profile == 0 && sps_profile > 0)\n                    profile = sps_profile;\n                if (profile == FF_PROFILE_H264_MAIN && level == 32 && fmt_desc->max_ref_frames > 4) {\n                    ALOGE(\"%s - Main@L3.2 detected, VTB cannot decode with %d ref frames\", __FUNCTION__, fmt_desc->max_ref_frames);\n                    goto fail;\n                }\n\n                if (extradata[4] == 0xFE) {\n                    extradata[4] = 0xFF;\n                    fmt_desc->convert_3byteTo4byteNALSize = true;\n                }\n\n        fmt_desc->fmt_desc = CreateFormatDescriptionFromCodecData(format_id, width, height, extradata, extrasize,  IJK_VTB_FCC_AVCC);\n        if (fmt_desc->fmt_desc == NULL) {\n            goto fail;\n        }\n\n                ALOGI(\"%s - using avcC atom of size(%d), ref_frames(%d)\", __FUNCTION__, extrasize, fmt_desc->max_ref_frames);\n            } else {\n                if ((extradata[0] == 0 && extradata[1] == 0 && extradata[2] == 0 && extradata[3] == 1) ||\n                    (extradata[0] == 0 && extradata[1] == 0 && extradata[2] == 1)) {\n                    AVIOContext *pb;\n                    if (avio_open_dyn_buf(&pb) < 0) {\n                        goto fail;\n                    }\n\n                    fmt_desc->convert_bytestream = true;\n                    ff_isom_write_avcc(pb, extradata, extrasize);\n                    extradata = NULL;\n\n                    extrasize = avio_close_dyn_buf(pb, &extradata);\n\n                    if (!validate_avcC_spc(extradata, extrasize, &fmt_desc->max_ref_frames, &sps_level, &sps_profile)) {\n                        av_free(extradata);\n                        goto fail;\n                    }\n\n            fmt_desc->fmt_desc = CreateFormatDescriptionFromCodecData(format_id, width, height, extradata, extrasize, IJK_VTB_FCC_AVCC);\n            if (fmt_desc->fmt_desc == NULL) {\n                goto fail;\n            }\n\n            av_free(extradata);\n        } else {\n            ALOGI(\"%s - invalid avcC atom data\", __FUNCTION__);\n            goto fail;\n        }\n    }\n\n    fmt_desc->max_ref_frames = FFMAX(fmt_desc->max_ref_frames, 2);\n    fmt_desc->max_ref_frames = FFMIN(fmt_desc->max_ref_frames, 5);\n\n    ALOGI(\"m_max_ref_frames %d \\n\", fmt_desc->max_ref_frames);\n\n    return 0;\nfail:\n    vtbformat_destroy(fmt_desc);\n    return -1;\n}\n\nIjk_VideoToolBox_Opaque* videotoolbox_async_create(FFPlayer* ffp, AVCodecContext* avctx)\n{\n    int ret = 0;\n\n    if (ret) {\n        ALOGW(\"%s - videotoolbox can not exists twice at the same time\", __FUNCTION__);\n        return NULL;\n    }\n\n    Ijk_VideoToolBox_Opaque *context_vtb = (Ijk_VideoToolBox_Opaque *)mallocz(sizeof(Ijk_VideoToolBox_Opaque));\n\n    context_vtb->sample_info_mutex = SDL_CreateMutex();\n    context_vtb->sample_info_cond  = SDL_CreateCond();\n\n    if (!context_vtb) {\n        goto fail;\n    }\n\n    context_vtb->codecpar = avcodec_parameters_alloc();\n    if (!context_vtb->codecpar)\n        goto fail;\n\n    ret = avcodec_parameters_from_context(context_vtb->codecpar, avctx);\n    if (ret)\n        goto fail;\n\n    context_vtb->ffp = ffp;\n    context_vtb->idr_based_identified = true;\n\n    ret = vtbformat_init(&context_vtb->fmt_desc, context_vtb->codecpar);\n    if (ret)\n        goto fail;\n    assert(context_vtb->fmt_desc.fmt_desc);\n    vtbformat_destroy(&context_vtb->fmt_desc);\n\n    context_vtb->vt_session = vtbsession_create(context_vtb);\n    if (context_vtb->vt_session == NULL)\n        goto fail;\n\n    context_vtb->m_sort_queue = 0;\n    context_vtb->m_queue_depth = 0;\n\n    SDL_SpeedSamplerReset(&context_vtb->sampler);\n    return context_vtb;\n\nfail:\n    videotoolbox_async_free(context_vtb);\n    return NULL;\n}\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBoxSync.h",
    "content": "/*****************************************************************************\n * IJKVideoToolBox.h\n *****************************************************************************\n *\n * copyright (c) 2014 Zhou Quan <zhouqicy@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef IJKMediaPlayer_videotoolbox_sync_h\n#define IJKMediaPlayer_videotoolbox_sync_h\n\n#include \"ff_ffplay.h\"\n\ntypedef struct Ijk_VideoToolBox_Opaque Ijk_VideoToolBox_Opaque;\n\nIjk_VideoToolBox_Opaque* videotoolbox_sync_create(FFPlayer* ffp, AVCodecContext* ic);\n\nint videotoolbox_sync_decode_frame(Ijk_VideoToolBox_Opaque* opaque);\n\nvoid videotoolbox_sync_free(Ijk_VideoToolBox_Opaque* opaque);\n\n#endif\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBoxSync.m",
    "content": "/*****************************************************************************\n * IJKVideoToolBox.m\n *****************************************************************************\n *\n * copyright (c) 2014 Zhou Quan <zhouqicy@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"IJKVideoToolBoxSync.h\"\n#include \"ijksdl_vout_overlay_videotoolbox.h\"\n#include \"ffpipeline_ios.h\"\n#include <mach/mach_time.h>\n#include \"libavformat/avc.h\"\n#include \"ijksdl_vout_ios_gles2.h\"\n#include \"h264_sps_parser.h\"\n#include \"ijkplayer/ff_ffplay_debug.h\"\n#import <CoreMedia/CoreMedia.h>\n#import <CoreFoundation/CoreFoundation.h>\n#import <CoreVideo/CVHostTime.h>\n#import <Foundation/Foundation.h>\n#import \"IJKDeviceModel.h\"\n#include <stdatomic.h>\n#import <VideoToolbox/VideoToolbox.h>\n#include \"ff_ffinc.h\"\n#include \"ff_fferror.h\"\n#include \"ff_ffmsg.h\"\n#include \"ijksdl/ios/ijksdl_vout_overlay_videotoolbox.h\"\n\n#define IJK_VTB_FCC_AVCC   SDL_FOURCC('C', 'c', 'v', 'a')\n\n#define MAX_PKT_QUEUE_DEEP   350\n\ntypedef struct sample_info {\n\n    double  sort;\n    double  dts;\n    double  pts;\n    int     serial;\n\n    int     sar_num;\n    int     sar_den;\n\n} sample_info;\n\ntypedef struct sort_queue {\n    AVFrame pic;\n    int serial;\n    int64_t sort;\n    volatile struct sort_queue *nextframe;\n} sort_queue;\n\ntypedef struct VTBFormatDesc\n{\n    CMFormatDescriptionRef      fmt_desc;\n    int32_t                     max_ref_frames;\n    bool                        convert_bytestream;\n    bool                        convert_3byteTo4byteNALSize;\n} VTBFormatDesc;\n\nstruct Ijk_VideoToolBox_Opaque {\n    FFPlayer                   *ffp;\n    VTDecompressionSessionRef   vt_session;\n\n    AVCodecParameters          *codecpar;\n    VTBFormatDesc               fmt_desc;\n\n\n    volatile bool               refresh_request;\n    volatile bool               new_seg_flag;\n    volatile bool               idr_based_identified;\n    volatile bool               refresh_session;\n    volatile bool               recovery_drop_packet;\n\n    pthread_mutex_t             m_queue_mutex;\n    volatile sort_queue        *m_sort_queue;\n    volatile int32_t            m_queue_depth;\n\n    int                         m_buffer_deep;\n    AVPacket                    m_buffer_packet[MAX_PKT_QUEUE_DEEP];\n\n    sample_info                 sample_info;\n\n    SDL_SpeedSampler            sampler;\n\n    int                         serial;\n    bool                        dealloced;\n\n};\n\nstatic void vtbformat_destroy(VTBFormatDesc *fmt_desc);\nstatic int  vtbformat_init(VTBFormatDesc *fmt_desc, AVCodecParameters *codecpar);\n\nstatic const char *vtb_get_error_string(OSStatus status) {\n    switch (status) {\n        case kVTInvalidSessionErr:                      return \"kVTInvalidSessionErr\";\n        case kVTVideoDecoderBadDataErr:                 return \"kVTVideoDecoderBadDataErr\";\n        case kVTVideoDecoderUnsupportedDataFormatErr:   return \"kVTVideoDecoderUnsupportedDataFormatErr\";\n        case kVTVideoDecoderMalfunctionErr:             return \"kVTVideoDecoderMalfunctionErr\";\n        default:                                        return \"UNKNOWN\";\n    }\n}\n\nstatic void SortQueuePop(Ijk_VideoToolBox_Opaque* context)\n{\n    if (!context->m_sort_queue || context->m_queue_depth == 0) {\n        return;\n    }\n    pthread_mutex_lock(&context->m_queue_mutex);\n    volatile sort_queue *top_frame = context->m_sort_queue;\n    context->m_sort_queue = context->m_sort_queue->nextframe;\n    context->m_queue_depth--;\n    pthread_mutex_unlock(&context->m_queue_mutex);\n    CVBufferRelease(top_frame->pic.opaque);\n    free((void*)top_frame);\n}\n\nstatic void SortQueuePush(Ijk_VideoToolBox_Opaque *ctx, sort_queue *newFrame)\n{\n    pthread_mutex_lock(&ctx->m_queue_mutex);\n    volatile sort_queue *queueWalker = ctx->m_sort_queue;\n    if (!queueWalker || (newFrame->sort < queueWalker->sort)) {\n        newFrame->nextframe = queueWalker;\n        ctx->m_sort_queue = newFrame;\n    } else {\n        bool frameInserted = false;\n        volatile sort_queue *nextFrame = NULL;\n        while (!frameInserted) {\n            nextFrame = queueWalker->nextframe;\n            if (!nextFrame || (newFrame->sort < nextFrame->sort)) {\n                newFrame->nextframe = nextFrame;\n                queueWalker->nextframe = newFrame;\n                frameInserted = true;\n            }\n            queueWalker = nextFrame;\n        }\n    }\n    ctx->m_queue_depth++;\n    pthread_mutex_unlock(&ctx->m_queue_mutex);\n}\n\nstatic void CFDictionarySetSInt32(CFMutableDictionaryRef dictionary, CFStringRef key, SInt32 numberSInt32)\n{\n    CFNumberRef number;\n    number = CFNumberCreate(NULL, kCFNumberSInt32Type, &numberSInt32);\n    CFDictionarySetValue(dictionary, key, number);\n    CFRelease(number);\n}\n\nstatic void CFDictionarySetBoolean(CFMutableDictionaryRef dictionary, CFStringRef key, BOOL value)\n{\n    CFDictionarySetValue(dictionary, key, value ? kCFBooleanTrue : kCFBooleanFalse);\n}\n\nstatic CMSampleBufferRef CreateSampleBufferFrom(CMFormatDescriptionRef fmt_desc, void *demux_buff, size_t demux_size)\n{\n    OSStatus status;\n    CMBlockBufferRef newBBufOut = NULL;\n    CMSampleBufferRef sBufOut = NULL;\n\n    status = CMBlockBufferCreateWithMemoryBlock(\n                                                NULL,\n                                                demux_buff,\n                                                demux_size,\n                                                kCFAllocatorNull,\n                                                NULL,\n                                                0,\n                                                demux_size,\n                                                FALSE,\n                                                &newBBufOut);\n\n    if (!status) {\n        status = CMSampleBufferCreate(\n                                      NULL,\n                                      newBBufOut,\n                                      TRUE,\n                                      0,\n                                      0,\n                                      fmt_desc,\n                                      1,\n                                      0,\n                                      NULL,\n                                      0,\n                                      NULL,\n                                      &sBufOut);\n    }\n\n    if (newBBufOut)\n        CFRelease(newBBufOut);\n    if (status == 0) {\n        return sBufOut;\n    } else {\n        return NULL;\n    }\n}\n\nstatic bool GetVTBPicture(Ijk_VideoToolBox_Opaque* context, AVFrame* pVTBPicture)\n{\n    if (context->m_sort_queue == NULL) {\n        return false;\n    }\n    pthread_mutex_lock(&context->m_queue_mutex);\n\n    volatile sort_queue *sort_queue = context->m_sort_queue;\n    *pVTBPicture        = sort_queue->pic;\n    pVTBPicture->opaque = CVBufferRetain(sort_queue->pic.opaque);\n\n    pthread_mutex_unlock(&context->m_queue_mutex);\n\n    return true;\n}\n\nstatic void QueuePicture(Ijk_VideoToolBox_Opaque* ctx) {\n    AVFrame picture = {0};\n    if (true == GetVTBPicture(ctx, &picture)) {\n        AVRational tb = ctx->ffp->is->video_st->time_base;\n        AVRational frame_rate = av_guess_frame_rate(ctx->ffp->is->ic, ctx->ffp->is->video_st, NULL);\n        double duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational) {frame_rate.den, frame_rate.num}) : 0);\n        double pts = (picture.pts == AV_NOPTS_VALUE) ? NAN : picture.pts * av_q2d(tb);\n\n        picture.format = IJK_AV_PIX_FMT__VIDEO_TOOLBOX;\n\n        ffp_queue_picture(ctx->ffp, &picture, pts, duration, 0, ctx->ffp->is->viddec.pkt_serial);\n\n        CVBufferRelease(picture.opaque);\n\n        SortQueuePop(ctx);\n    } else {\n        ALOGI(\"Get Picture failure!!!\\n\");\n    }\n}\n\n\nstatic void VTDecoderCallback(void *decompressionOutputRefCon,\n                       void *sourceFrameRefCon,\n                       OSStatus status,\n                       VTDecodeInfoFlags infoFlags,\n                       CVImageBufferRef imageBuffer,\n                       CMTime presentationTimeStamp,\n                       CMTime presentationDuration)\n{\n    @autoreleasepool {\n        Ijk_VideoToolBox_Opaque *ctx = (Ijk_VideoToolBox_Opaque*)decompressionOutputRefCon;\n        if (!ctx)\n            return;\n\n        FFPlayer   *ffp         = ctx->ffp;\n        VideoState *is          = ffp->is;\n        sort_queue *newFrame    = NULL;\n\n        sample_info *sample_info = &ctx->sample_info;\n\n        newFrame = (sort_queue *)mallocz(sizeof(sort_queue));\n        if (!newFrame) {\n            ALOGE(\"VTB: create new frame fail: out of memory\\n\");\n            goto failed;\n        }\n\n        newFrame->pic.pts        = sample_info->pts;\n        newFrame->pic.pkt_dts    = sample_info->dts;\n        newFrame->pic.sample_aspect_ratio.num = sample_info->sar_num;\n        newFrame->pic.sample_aspect_ratio.den = sample_info->sar_den;\n        newFrame->serial     = sample_info->serial;\n        newFrame->nextframe  = NULL;\n\n        if (newFrame->pic.pts != AV_NOPTS_VALUE) {\n            newFrame->sort    = newFrame->pic.pts;\n        } else {\n            newFrame->sort    = newFrame->pic.pkt_dts;\n            newFrame->pic.pts = newFrame->pic.pkt_dts;\n        }\n\n        if (ctx->dealloced || is->abort_request || is->viddec.queue->abort_request)\n            goto failed;\n\n        if (status != 0) {\n            ALOGE(\"decode callback %d %s\\n\", (int)status, vtb_get_error_string(status));\n            goto failed;\n        }\n\n        if (ctx->refresh_session) {\n            goto failed;\n        }\n\n        if (newFrame->serial != ctx->serial) {\n            goto failed;\n        }\n\n        if (imageBuffer == NULL) {\n            ALOGI(\"imageBuffer null\\n\");\n            goto failed;\n        }\n\n        ffp->stat.vdps = SDL_SpeedSamplerAdd(&ctx->sampler, FFP_SHOW_VDPS_VIDEOTOOLBOX, \"vdps[VideoToolbox]\");\n#ifdef FFP_VTB_DISABLE_OUTPUT\n        goto failed;\n#endif\n\n        OSType format_type = CVPixelBufferGetPixelFormatType(imageBuffer);\n        if (format_type != kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) {\n            ALOGI(\"format_type error \\n\");\n            goto failed;\n        }\n        if (kVTDecodeInfo_FrameDropped & infoFlags) {\n            ALOGI(\"droped\\n\");\n            goto failed;\n        }\n\n        if (ctx->new_seg_flag) {\n            ALOGI(\"new seg process!!!!\");\n            while (ctx->m_queue_depth > 0) {\n                QueuePicture(ctx);\n            }\n            ctx->new_seg_flag = false;\n        }\n\n        if (ctx->m_sort_queue && newFrame->pic.pts < ctx->m_sort_queue->pic.pts) {\n            goto failed;\n        }\n\n        // FIXME: duplicated code\n        {\n            double dpts = NAN;\n\n            if (newFrame->pic.pts != AV_NOPTS_VALUE)\n                dpts = av_q2d(is->video_st->time_base) * newFrame->pic.pts;\n\n            if (ffp->framedrop>0 || (ffp->framedrop && ffp_get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) {\n                ffp->stat.decode_frame_count++;\n                if (newFrame->pic.pts != AV_NOPTS_VALUE) {\n                    double diff = dpts - ffp_get_master_clock(is);\n                    if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD &&\n                        diff - is->frame_last_filter_delay < 0 &&\n                        is->viddec.pkt_serial == is->vidclk.serial &&\n                        is->videoq.nb_packets) {\n                        is->frame_drops_early++;\n                        is->continuous_frame_drops_early++;\n                        if (is->continuous_frame_drops_early > ffp->framedrop) {\n                            is->continuous_frame_drops_early = 0;\n                        } else {\n                            ffp->stat.drop_frame_count++;\n                            ffp->stat.drop_frame_rate = (float)(ffp->stat.drop_frame_count) / (float)(ffp->stat.decode_frame_count);\n                            // drop too late frame\n                            goto failed;\n                        }\n                    }\n                }\n            }\n        }\n\n        if (CVPixelBufferIsPlanar(imageBuffer)) {\n            newFrame->pic.width  = (int)CVPixelBufferGetWidthOfPlane(imageBuffer, 0);\n            newFrame->pic.height = (int)CVPixelBufferGetHeightOfPlane(imageBuffer, 0);\n        } else {\n            newFrame->pic.width  = (int)CVPixelBufferGetWidth(imageBuffer);\n            newFrame->pic.height = (int)CVPixelBufferGetHeight(imageBuffer);\n        }\n\n\n        newFrame->pic.opaque = CVBufferRetain(imageBuffer);\n        SortQueuePush(ctx, newFrame);\n\n        if (ctx->ffp->is == NULL || ctx->ffp->is->abort_request || ctx->ffp->is->viddec.queue->abort_request) {\n            while (ctx->m_queue_depth > 0) {\n                SortQueuePop(ctx);\n            }\n            goto successed;\n        }\n\n        if ((ctx->m_queue_depth > ctx->fmt_desc.max_ref_frames)) {\n            QueuePicture(ctx);\n        }\n    successed:\n        return;\n    failed:\n        if (newFrame) {\n            free(newFrame);\n        }\n        return;\n    }\n}\n\nstatic void vtbsession_destroy(Ijk_VideoToolBox_Opaque *context)\n{\n    if (!context)\n        return;\n\n    vtbformat_destroy(&context->fmt_desc);\n\n    if (context->vt_session) {\n        VTDecompressionSessionWaitForAsynchronousFrames(context->vt_session);\n        VTDecompressionSessionInvalidate(context->vt_session);\n        CFRelease(context->vt_session);\n        context->vt_session = NULL;\n    }\n}\n\nstatic VTDecompressionSessionRef vtbsession_create(Ijk_VideoToolBox_Opaque* context)\n{\n    FFPlayer *ffp = context->ffp;\n    int       ret = 0;\n    int       width  = context->codecpar->width;\n    int       height = context->codecpar->height;\n\n    VTDecompressionSessionRef vt_session = NULL;\n    CFMutableDictionaryRef destinationPixelBufferAttributes;\n    VTDecompressionOutputCallbackRecord outputCallback;\n    OSStatus status;\n\n    ret = vtbformat_init(&context->fmt_desc, context->codecpar);\n\n    if (ffp->vtb_max_frame_width > 0 && width > ffp->vtb_max_frame_width) {\n        double w_scaler = (float)ffp->vtb_max_frame_width / width;\n        width = ffp->vtb_max_frame_width;\n        height = height * w_scaler;\n    }\n\n    ALOGI(\"after scale width %d height %d \\n\", width, height);\n\n    destinationPixelBufferAttributes = CFDictionaryCreateMutable(\n                                                                 NULL,\n                                                                 0,\n                                                                 &kCFTypeDictionaryKeyCallBacks,\n                                                                 &kCFTypeDictionaryValueCallBacks);\n    CFDictionarySetSInt32(destinationPixelBufferAttributes,\n                          kCVPixelBufferPixelFormatTypeKey, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange);\n    CFDictionarySetSInt32(destinationPixelBufferAttributes,\n                          kCVPixelBufferWidthKey, width);\n    CFDictionarySetSInt32(destinationPixelBufferAttributes,\n                          kCVPixelBufferHeightKey, height);\n    CFDictionarySetBoolean(destinationPixelBufferAttributes,\n                          kCVPixelBufferOpenGLESCompatibilityKey, YES);\n    outputCallback.decompressionOutputCallback = VTDecoderCallback;\n    outputCallback.decompressionOutputRefCon = context  ;\n    status = VTDecompressionSessionCreate(\n                                          kCFAllocatorDefault,\n                                          context->fmt_desc.fmt_desc,\n                                          NULL,\n                                          destinationPixelBufferAttributes,\n                                          &outputCallback,\n                                          &vt_session);\n\n    if (status != noErr) {\n        NSError* error = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil];\n        NSLog(@\"Error %@\", [error description]);\n        ALOGI(\"%s - failed with status = (%d)\", __FUNCTION__, (int)status);\n    }\n    CFRelease(destinationPixelBufferAttributes);\n\n    memset(&context->sample_info, 0, sizeof(struct sample_info));\n\n    return vt_session;\n}\n\n\n\nstatic int decode_video_internal(Ijk_VideoToolBox_Opaque* context, AVCodecContext *avctx, const AVPacket *avpkt, int* got_picture_ptr)\n{\n    FFPlayer *ffp                   = context->ffp;\n    OSStatus status                 = 0;\n    uint32_t decoder_flags          = 0;\n    sample_info *sample_info        = NULL;\n    CMSampleBufferRef sample_buff   = NULL;\n    AVIOContext *pb                 = NULL;\n    int demux_size                  = 0;\n    uint8_t *demux_buff             = NULL;\n    uint8_t *pData                  = avpkt->data;\n    int iSize                       = avpkt->size;\n    double pts                      = avpkt->pts;\n    double dts                      = avpkt->dts;\n\n    if (!context) {\n        goto failed;\n    }\n\n    if (context->refresh_session) {\n        decoder_flags |= kVTDecodeFrame_DoNotOutputFrame;\n        // ALOGI(\"flag :%d flag %d \\n\", decoderFlags,avpkt->flags);\n    }\n\n    if (context->refresh_request) {\n        while (context->m_queue_depth > 0) {\n            SortQueuePop(context);\n        }\n\n        vtbsession_destroy(context);\n        memset(&context->sample_info, 0, sizeof(struct sample_info));\n\n        context->vt_session = vtbsession_create(context);\n        if (!context->vt_session)\n            goto failed;\n        context->refresh_request = false;\n    }\n\n    if (pts == AV_NOPTS_VALUE) {\n        pts = dts;\n    }\n\n    if (context->fmt_desc.convert_bytestream) {\n        // ALOGI(\"the buffer should m_convert_byte\\n\");\n        if(avio_open_dyn_buf(&pb) < 0) {\n            goto failed;\n        }\n        ff_avc_parse_nal_units(pb, pData, iSize);\n        demux_size = avio_close_dyn_buf(pb, &demux_buff);\n        // ALOGI(\"demux_size:%d\\n\", demux_size);\n        if (demux_size == 0) {\n            goto failed;\n        }\n        sample_buff = CreateSampleBufferFrom(context->fmt_desc.fmt_desc, demux_buff, demux_size);\n    } else if (context->fmt_desc.convert_3byteTo4byteNALSize) {\n        // ALOGI(\"3byteto4byte\\n\");\n        if (avio_open_dyn_buf(&pb) < 0) {\n            goto failed;\n        }\n\n        uint32_t nal_size;\n        uint8_t *end = avpkt->data + avpkt->size;\n        uint8_t *nal_start = pData;\n        while (nal_start < end) {\n            nal_size = AV_RB24(nal_start);\n            avio_wb32(pb, nal_size);\n            nal_start += 3;\n            avio_write(pb, nal_start, nal_size);\n            nal_start += nal_size;\n        }\n        demux_size = avio_close_dyn_buf(pb, &demux_buff);\n        sample_buff = CreateSampleBufferFrom(context->fmt_desc.fmt_desc, demux_buff, demux_size);\n    } else {\n        sample_buff = CreateSampleBufferFrom(context->fmt_desc.fmt_desc, pData, iSize);\n    }\n    if (!sample_buff) {\n        if (demux_size) {\n            av_free(demux_buff);\n        }\n        ALOGI(\"%s - CreateSampleBufferFrom failed\", __FUNCTION__);\n        goto failed;\n    }\n\n    if (avpkt->flags & AV_PKT_FLAG_NEW_SEG) {\n        context->new_seg_flag = true;\n    }\n\n    sample_info = &context->sample_info;\n    if (!sample_info) {\n        ALOGE(\"%s, failed to peek frame_info\\n\", __FUNCTION__);\n        goto failed;\n    }\n\n    sample_info->pts    = pts;\n    sample_info->dts    = dts;\n    sample_info->serial = context->serial;\n    sample_info->sar_num = avctx->sample_aspect_ratio.num;\n    sample_info->sar_den = avctx->sample_aspect_ratio.den;\n\n    status = VTDecompressionSessionDecodeFrame(context->vt_session, sample_buff, decoder_flags, (void*)sample_info, 0);\n    if (status == noErr) {\n        if (ffp->is->videoq.abort_request)\n            goto failed;\n    }\n\n    if (status != 0) {\n\n        ALOGE(\"decodeFrame %d %s\\n\", (int)status, vtb_get_error_string(status));\n\n        if (status == kVTInvalidSessionErr) {\n            context->refresh_session = true;\n        }\n        if (status == kVTVideoDecoderMalfunctionErr) {\n            context->recovery_drop_packet = true;\n            context->refresh_session = true;\n        }\n        goto failed;\n    }\n\n\n\n    if (sample_buff) {\n        CFRelease(sample_buff);\n    }\n    if (demux_size) {\n        av_free(demux_buff);\n    }\n\n    *got_picture_ptr = 1;\n    return 0;\nfailed:\n    if (sample_buff) {\n        CFRelease(sample_buff);\n    }\n    if (demux_size) {\n        av_free(demux_buff);\n    }\n    *got_picture_ptr = 0;\n    return -1;\n}\n\nstatic inline void ResetPktBuffer(Ijk_VideoToolBox_Opaque* context) {\n    for (int i = 0 ; i < context->m_buffer_deep; i++) {\n        av_packet_unref(&context->m_buffer_packet[i]);\n    }\n    context->m_buffer_deep = 0;\n    memset(context->m_buffer_packet, 0, sizeof(context->m_buffer_packet));\n}\n\nstatic inline void DuplicatePkt(Ijk_VideoToolBox_Opaque* context, const AVPacket* pkt) {\n    if (context->m_buffer_deep >= MAX_PKT_QUEUE_DEEP) {\n        context->idr_based_identified = false;\n        ResetPktBuffer(context);\n    }\n    AVPacket* avpkt = &context->m_buffer_packet[context->m_buffer_deep];\n    av_copy_packet(avpkt, pkt);\n    context->m_buffer_deep++;\n}\n\n\n\nstatic int decode_video(Ijk_VideoToolBox_Opaque* context, AVCodecContext *avctx, AVPacket *avpkt, int* got_picture_ptr)\n{\n    int      ret            = 0;\n    uint8_t *size_data      = NULL;\n    int      size_data_size = 0;\n\n    if (!avpkt || !avpkt->data) {\n        return 0;\n    }\n\n    if (context->ffp->vtb_handle_resolution_change &&\n        context->codecpar->codec_id == AV_CODEC_ID_H264) {\n        size_data = av_packet_get_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, &size_data_size);\n        // minimum avcC(sps,pps) = 7\n        if (size_data && size_data_size > 7) {\n            int             got_picture = 0;\n            AVFrame        *frame      = av_frame_alloc();\n            AVDictionary   *codec_opts = NULL;\n            AVCodecContext *new_avctx  = avcodec_alloc_context3(avctx->codec);\n            if (!new_avctx)\n                return AVERROR(ENOMEM);\n\n            avcodec_parameters_to_context(new_avctx, context->codecpar);\n            av_freep(&new_avctx->extradata);\n            new_avctx->extradata = av_mallocz(size_data_size + AV_INPUT_BUFFER_PADDING_SIZE);\n            if (!new_avctx->extradata)\n                return AVERROR(ENOMEM);\n            memcpy(new_avctx->extradata, size_data, size_data_size);\n            new_avctx->extradata_size = size_data_size;\n\n            av_dict_set(&codec_opts, \"threads\", \"1\", 0);\n            ret = avcodec_open2(new_avctx, avctx->codec, &codec_opts);\n            av_dict_free(&codec_opts);\n            if (ret < 0) {\n                avcodec_free_context(&new_avctx);\n                return ret;\n            }\n\n            ret = avcodec_decode_video2(new_avctx, frame, &got_picture, avpkt);\n            if (ret < 0) {\n                avcodec_free_context(&new_avctx);\n                return ret;\n            } else {\n                if (context->codecpar->width  != new_avctx->width &&\n                    context->codecpar->height != new_avctx->height) {\n                    avcodec_parameters_from_context(context->codecpar, new_avctx);\n                    context->refresh_request = true;\n                }\n            }\n\n            av_frame_unref(frame);\n            avcodec_free_context(&new_avctx);\n        }\n    } else {\n        if (ff_avpacket_is_idr(avpkt) == true) {\n            context->idr_based_identified = true;\n        }\n        if (ff_avpacket_i_or_idr(avpkt, context->idr_based_identified) == true) {\n            ResetPktBuffer(context);\n            context->recovery_drop_packet = false;\n        }\n        if (context->recovery_drop_packet == true) {\n            return -1;\n        }\n    }\n\n    DuplicatePkt(context, avpkt);\n\n    if (context->refresh_session) {\n        ret = 0;\n\n        vtbsession_destroy(context);\n        memset(&context->sample_info, 0, sizeof(struct sample_info));\n\n        context->vt_session = vtbsession_create(context);\n        if (!context->vt_session)\n            return -1;\n\n        if ((context->m_buffer_deep > 0) &&\n            ff_avpacket_i_or_idr(&context->m_buffer_packet[0], context->idr_based_identified) == true ) {\n            for (int i = 0; i < context->m_buffer_deep; i++) {\n                AVPacket* pkt = &context->m_buffer_packet[i];\n                ret = decode_video_internal(context, avctx, pkt, got_picture_ptr);\n            }\n        } else {\n            context->recovery_drop_packet = true;\n            ret = -1;\n            ALOGE(\"recovery error!!!!\\n\");\n        }\n        context->refresh_session = false;\n        return ret;\n    }\n    return decode_video_internal(context, avctx, avpkt, got_picture_ptr);\n}\n\n\nstatic void dict_set_string(CFMutableDictionaryRef dict, CFStringRef key, const char * value)\n{\n    CFStringRef string;\n    string = CFStringCreateWithCString(NULL, value, kCFStringEncodingASCII);\n    CFDictionarySetValue(dict, key, string);\n    CFRelease(string);\n}\n\nstatic void dict_set_boolean(CFMutableDictionaryRef dict, CFStringRef key, BOOL value)\n{\n    CFDictionarySetValue(dict, key, value ? kCFBooleanTrue: kCFBooleanFalse);\n}\n\n\nstatic void dict_set_object(CFMutableDictionaryRef dict, CFStringRef key, CFTypeRef *value)\n{\n    CFDictionarySetValue(dict, key, value);\n}\n\nstatic void dict_set_data(CFMutableDictionaryRef dict, CFStringRef key, uint8_t * value, uint64_t length)\n{\n    CFDataRef data;\n    data = CFDataCreate(NULL, value, (CFIndex)length);\n    CFDictionarySetValue(dict, key, data);\n    CFRelease(data);\n}\n\nstatic void dict_set_i32(CFMutableDictionaryRef dict, CFStringRef key,\n                         int32_t value)\n{\n    CFNumberRef number;\n    number = CFNumberCreate(NULL, kCFNumberSInt32Type, &value);\n    CFDictionarySetValue(dict, key, number);\n    CFRelease(number);\n}\n\nstatic CMFormatDescriptionRef CreateFormatDescriptionFromCodecData(CMVideoCodecType format_id, int width, int height, const uint8_t *extradata, int extradata_size, uint32_t atom)\n{\n    CMFormatDescriptionRef fmt_desc = NULL;\n    OSStatus status;\n\n    CFMutableDictionaryRef par = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,&kCFTypeDictionaryValueCallBacks);\n    CFMutableDictionaryRef atoms = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,&kCFTypeDictionaryValueCallBacks);\n    CFMutableDictionaryRef extensions = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);\n\n    /* CVPixelAspectRatio dict */\n    dict_set_i32(par, CFSTR (\"HorizontalSpacing\"), 0);\n    dict_set_i32(par, CFSTR (\"VerticalSpacing\"), 0);\n    \n    /* SampleDescriptionExtensionAtoms dict */\n    switch (format_id) {\n        case kCMVideoCodecType_H264:\n            dict_set_data(atoms, CFSTR (\"avcC\"), (uint8_t *)extradata, extradata_size);\n            break;\n        case kCMVideoCodecType_HEVC:\n            dict_set_data(atoms, CFSTR (\"hvcC\"), (uint8_t *)extradata, extradata_size);\n            break;\n        default:\n            break;\n    }\n\n\n      /* Extensions dict */\n    dict_set_string(extensions, CFSTR (\"CVImageBufferChromaLocationBottomField\"), \"left\");\n    dict_set_string(extensions, CFSTR (\"CVImageBufferChromaLocationTopField\"), \"left\");\n    dict_set_boolean(extensions, CFSTR(\"FullRangeVideo\"), FALSE);\n    dict_set_object(extensions, CFSTR (\"CVPixelAspectRatio\"), (CFTypeRef *) par);\n    dict_set_object(extensions, CFSTR (\"SampleDescriptionExtensionAtoms\"), (CFTypeRef *) atoms);\n    status = CMVideoFormatDescriptionCreate(NULL, format_id, width, height, extensions, &fmt_desc);\n\n    CFRelease(extensions);\n    CFRelease(atoms);\n    CFRelease(par);\n\n    if (status == 0)\n        return fmt_desc;\n    else\n        return NULL;\n}\n\nvoid videotoolbox_sync_free(Ijk_VideoToolBox_Opaque* context)\n{\n    context->dealloced = true;\n\n    while (context && context->m_queue_depth > 0) {\n        SortQueuePop(context);\n    }\n\n    vtbsession_destroy(context);\n\n    if (context) {\n        ResetPktBuffer(context);\n    }\n\n    vtbformat_destroy(&context->fmt_desc);\n\n    avcodec_parameters_free(&context->codecpar);\n}\n\nint videotoolbox_sync_decode_frame(Ijk_VideoToolBox_Opaque* context)\n{\n    FFPlayer *ffp = context->ffp;\n    VideoState *is = ffp->is;\n    Decoder *d = &is->viddec;\n    int got_frame = 0;\n    do {\n        int ret = -1;\n        if (is->abort_request || d->queue->abort_request) {\n            return -1;\n        }\n\n        if (!d->packet_pending || d->queue->serial != d->pkt_serial) {\n            AVPacket pkt;\n            do {\n                if (d->queue->nb_packets == 0)\n                    SDL_CondSignal(d->empty_queue_cond);\n                ffp_video_statistic_l(ffp);\n                if (ffp_packet_queue_get_or_buffering(ffp, d->queue, &pkt, &d->pkt_serial, &d->finished) < 0)\n                    return -1;\n                if (ffp_is_flush_packet(&pkt)) {\n                    avcodec_flush_buffers(d->avctx);\n                    context->refresh_request = true;\n                    context->serial += 1;\n                    d->finished = 0;\n                    ALOGI(\"flushed last keyframe pts %lld \\n\",d->pkt.pts);\n                    d->next_pts = d->start_pts;\n                    d->next_pts_tb = d->start_pts_tb;\n                }\n            } while (ffp_is_flush_packet(&pkt) || d->queue->serial != d->pkt_serial);\n\n            av_packet_split_side_data(&pkt);\n\n            av_packet_unref(&d->pkt);\n            d->pkt_temp = d->pkt = pkt;\n            d->packet_pending = 1;\n        }\n\n        ret = decode_video(context, d->avctx, &d->pkt_temp, &got_frame);\n        if (ret < 0) {\n            d->packet_pending = 0;\n        } else {\n            d->pkt_temp.dts =\n            d->pkt_temp.pts = AV_NOPTS_VALUE;\n            if (d->pkt_temp.data) {\n                if (d->avctx->codec_type != AVMEDIA_TYPE_AUDIO)\n                    ret = d->pkt_temp.size;\n                d->pkt_temp.data += ret;\n                d->pkt_temp.size -= ret;\n                if (d->pkt_temp.size <= 0)\n                    d->packet_pending = 0;\n            } else {\n                if (!got_frame) {\n                    d->packet_pending = 0;\n                    d->finished = d->pkt_serial;\n                }\n            }\n        }\n    } while (!got_frame && !d->finished);\n    return got_frame;\n}\n\nstatic void vtbformat_destroy(VTBFormatDesc *fmt_desc)\n{\n    if (!fmt_desc || !fmt_desc->fmt_desc)\n        return;\n\n    CFRelease(fmt_desc->fmt_desc);\n    fmt_desc->fmt_desc = NULL;\n}\n\nstatic int vtbformat_init(VTBFormatDesc *fmt_desc, AVCodecParameters *codecpar)\n{\n    int width           = codecpar->width;\n    int height          = codecpar->height;\n    int level           = codecpar->level;\n    int profile         = codecpar->profile;\n    int sps_level       = 0;\n    int sps_profile     = 0;\n    int extrasize       = codecpar->extradata_size;\n    int codec           = codecpar->codec_id;\n    uint8_t* extradata  = codecpar->extradata;\n\n    bool isHevcSupported = false;\n    CMVideoCodecType format_id = 0;\n    \n#if 0\n    switch (profile) {\n        case FF_PROFILE_H264_HIGH_10:\n            if ([IJKDeviceModel currentModel].rank >= kIJKDeviceRank_AppleA7Class) {\n                // Apple A7 SoC\n                // Hi10p can be decoded into NV12 ('420v')\n                break;\n            }\n        case FF_PROFILE_H264_HIGH_10_INTRA:\n        case FF_PROFILE_H264_HIGH_422:\n        case FF_PROFILE_H264_HIGH_422_INTRA:\n        case FF_PROFILE_H264_HIGH_444_PREDICTIVE:\n        case FF_PROFILE_H264_HIGH_444_INTRA:\n        case FF_PROFILE_H264_CAVLC_444:\n            goto failed;\n    }\n#endif\n    if (width < 0 || height < 0) {\n        goto fail;\n    }\n\n    if (extrasize < 7 || extradata == NULL) {\n        ALOGI(\"%s - avcC or hvcC atom data too small or missing\", __FUNCTION__);\n        goto fail;\n    }\n\n    switch (codec) {\n        case AV_CODEC_ID_HEVC:\n            format_id = kCMVideoCodecType_HEVC;\n            if (@available(iOS 11.0, *)) {\n                isHevcSupported = VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC);\n            } else {\n                // Fallback on earlier versions\n                isHevcSupported = false;\n            }\n            if (!isHevcSupported) {\n                goto fail;\n            }\n            break;\n            \n        case AV_CODEC_ID_H264:\n            format_id = kCMVideoCodecType_H264;\n            break;\n            \n        default:\n            goto fail;\n    }\n    \n    if (extradata[0] == 1) {\n//                if (!validate_avcC_spc(extradata, extrasize, &fmt_desc->max_ref_frames, &sps_level, &sps_profile)) {\n            //goto failed;\n//                }\n        if (level == 0 && sps_level > 0)\n            level = sps_level;\n\n                if (profile == 0 && sps_profile > 0)\n                    profile = sps_profile;\n                if (profile == FF_PROFILE_H264_MAIN && level == 32 && fmt_desc->max_ref_frames > 4) {\n                    ALOGE(\"%s - Main@L3.2 detected, VTB cannot decode with %d ref frames\", __FUNCTION__, fmt_desc->max_ref_frames);\n                    goto fail;\n                }\n\n                if (extradata[4] == 0xFE) {\n                    extradata[4] = 0xFF;\n                    fmt_desc->convert_3byteTo4byteNALSize = true;\n                }\n\n        fmt_desc->fmt_desc = CreateFormatDescriptionFromCodecData(format_id, width, height, extradata, extrasize,  IJK_VTB_FCC_AVCC);\n        if (fmt_desc->fmt_desc == NULL) {\n            goto fail;\n        }\n\n                ALOGI(\"%s - using avcC atom of size(%d), ref_frames(%d)\", __FUNCTION__, extrasize, fmt_desc->max_ref_frames);\n            } else {\n                if ((extradata[0] == 0 && extradata[1] == 0 && extradata[2] == 0 && extradata[3] == 1) ||\n                    (extradata[0] == 0 && extradata[1] == 0 && extradata[2] == 1)) {\n                    AVIOContext *pb;\n                    if (avio_open_dyn_buf(&pb) < 0) {\n                        goto fail;\n                    }\n\n                    fmt_desc->convert_bytestream = true;\n                    ff_isom_write_avcc(pb, extradata, extrasize);\n                    extradata = NULL;\n\n                    extrasize = avio_close_dyn_buf(pb, &extradata);\n\n                    if (!validate_avcC_spc(extradata, extrasize, &fmt_desc->max_ref_frames, &sps_level, &sps_profile)) {\n                        av_free(extradata);\n                        goto fail;\n                    }\n\n            fmt_desc->fmt_desc = CreateFormatDescriptionFromCodecData(format_id, width, height, extradata, extrasize, IJK_VTB_FCC_AVCC);\n            if (fmt_desc->fmt_desc == NULL) {\n                goto fail;\n            }\n\n            av_free(extradata);\n        } else {\n            ALOGI(\"%s - invalid avcC atom data\", __FUNCTION__);\n            goto fail;\n        }\n    }\n\n    fmt_desc->max_ref_frames = FFMAX(fmt_desc->max_ref_frames, 2);\n    fmt_desc->max_ref_frames = FFMIN(fmt_desc->max_ref_frames, 5);\n\n    ALOGI(\"m_max_ref_frames %d \\n\", fmt_desc->max_ref_frames);\n\n    return 0;\nfail:\n    vtbformat_destroy(fmt_desc);\n    return -1;\n}\n\nIjk_VideoToolBox_Opaque* videotoolbox_sync_create(FFPlayer* ffp, AVCodecContext* avctx)\n{\n    int ret = 0;\n\n    if (ret) {\n        ALOGW(\"%s - videotoolbox can not exists twice at the same time\", __FUNCTION__);\n        return NULL;\n    }\n\n    Ijk_VideoToolBox_Opaque *context_vtb = (Ijk_VideoToolBox_Opaque *)mallocz(sizeof(Ijk_VideoToolBox_Opaque));\n\n    if (!context_vtb) {\n        goto fail;\n    }\n\n    context_vtb->codecpar = avcodec_parameters_alloc();\n    if (!context_vtb->codecpar)\n        goto fail;\n\n    ret = avcodec_parameters_from_context(context_vtb->codecpar, avctx);\n    if (ret)\n        goto fail;\n\n    context_vtb->ffp = ffp;\n    context_vtb->idr_based_identified = true;\n\n    ret = vtbformat_init(&context_vtb->fmt_desc, context_vtb->codecpar);\n    if (ret)\n        goto fail;\n    assert(context_vtb->fmt_desc.fmt_desc);\n    vtbformat_destroy(&context_vtb->fmt_desc);\n\n    context_vtb->vt_session = vtbsession_create(context_vtb);\n    if (context_vtb->vt_session == NULL)\n        goto fail;\n\n    context_vtb->m_sort_queue = 0;\n    context_vtb->m_queue_depth = 0;\n\n    SDL_SpeedSamplerReset(&context_vtb->sampler);\n    return context_vtb;\n\nfail:\n    videotoolbox_sync_free(context_vtb);\n    return NULL;\n}\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/ffpipeline_ios.c",
    "content": "/*\n * ffpipeline_ios.c\n *\n * Copyright (c) 2014 Zhou Quan <zhouqicy@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ffpipeline_ios.h\"\n#include \"ffpipenode_ios_videotoolbox_vdec.h\"\n#include \"ffpipenode_ffplay_vdec.h\"\n#include \"ff_ffplay.h\"\n#import \"ijksdl/ios/ijksdl_aout_ios_audiounit.h\"\n\nstruct IJKFF_Pipeline_Opaque {\n    FFPlayer    *ffp;\n    bool         is_videotoolbox_open;\n};\n\nstatic void func_destroy(IJKFF_Pipeline *pipeline)\n{\n}\n\nstatic IJKFF_Pipenode *func_open_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp)\n{\n    IJKFF_Pipenode* node = NULL;\n    IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;\n    if (ffp->videotoolbox) {\n        node = ffpipenode_create_video_decoder_from_ios_videotoolbox(ffp);\n        if (!node)\n            ALOGE(\"vtb fail!!! switch to ffmpeg decode!!!! \\n\");\n    }\n    if (node == NULL) {\n        node = ffpipenode_create_video_decoder_from_ffplay(ffp);\n        ffp->stat.vdec_type = FFP_PROPV_DECODER_AVCODEC;\n        opaque->is_videotoolbox_open = false;\n    } else {\n        ffp->stat.vdec_type = FFP_PROPV_DECODER_VIDEOTOOLBOX;\n        opaque->is_videotoolbox_open = true;\n    }\n    ffp_notify_msg2(ffp, FFP_MSG_VIDEO_DECODER_OPEN, opaque->is_videotoolbox_open);\n    return node;\n}\n\nstatic SDL_Aout *func_open_audio_output(IJKFF_Pipeline *pipeline, FFPlayer *ffp)\n{\n    return SDL_AoutIos_CreateForAudioUnit();\n}\n\nstatic SDL_Class g_pipeline_class = {\n    .name = \"ffpipeline_ios\",\n};\n\nIJKFF_Pipeline *ffpipeline_create_from_ios(FFPlayer *ffp)\n{\n    IJKFF_Pipeline *pipeline = ffpipeline_alloc(&g_pipeline_class, sizeof(IJKFF_Pipeline_Opaque));\n    if (!pipeline)\n        return pipeline;\n\n    IJKFF_Pipeline_Opaque *opaque     = pipeline->opaque;\n    opaque->ffp                       = ffp;\n    pipeline->func_destroy            = func_destroy;\n    pipeline->func_open_video_decoder = func_open_video_decoder;\n    pipeline->func_open_audio_output  = func_open_audio_output;\n\n    return pipeline;\n}\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/ffpipeline_ios.h",
    "content": "/*\n * ffpipeline_ios.h\n *\n * Copyright (c) 2014 Zhou Quan <zhouqicy@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef FFPLAY__FF_FFPIPELINE_IOS_H\n#define FFPLAY__FF_FFPIPELINE_IOS_H\n\n#include \"ijkplayer/ff_ffpipeline.h\"\n\nstruct FFPlayer;\n\nIJKFF_Pipeline *ffpipeline_create_from_ios(struct FFPlayer *ffp);\n\n#endif\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/ffpipenode_ios_videotoolbox_vdec.h",
    "content": "/*\n * ffpipenode_ios_videotoolbox_vdec.h\n *\n * Copyright (c) 2014 Zhou Quan <zhouqicy@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef FFPLAY__FF_FFPIPENODE_IOS_VIDEOTOOLBOX_DEC_H\n#define FFPLAY__FF_FFPIPENODE_IOS_VIDEOTOOLBOX_DEC_H\n\n#include \"ijkplayer/ff_ffpipenode.h\"\n\nstruct FFPlayer;\n\nIJKFF_Pipenode *ffpipenode_create_video_decoder_from_ios_videotoolbox(struct FFPlayer *ffp);\n\n#endif\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/ffpipenode_ios_videotoolbox_vdec.m",
    "content": "/*\n * ffpipenode_ios_videotoolbox_vdec.m\n *\n * Copyright (c) 2014 Zhou Quan <zhouqicy@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ffpipenode_ios_videotoolbox_vdec.h\"\n#include \"IJKVideoToolBox.h\"\n#include \"ijksdl_vout_overlay_videotoolbox.h\"\n#include \"ijkplayer/ff_ffpipeline.h\"\n#include \"ijkplayer/ff_ffpipenode.h\"\n#include \"ijkplayer/ff_ffplay.h\"\n#include \"ijksdl_mutex.h\"\n#include \"ijksdl_vout_ios_gles2.h\"\n#import <UIKit/UIKit.h>\n\nstruct IJKFF_Pipenode_Opaque {\n    IJKFF_Pipeline           *pipeline;\n    FFPlayer                 *ffp;\n    Decoder                  *decoder;\n    Ijk_VideoToolBox         *context;\n    AVCodecContext           *avctx; // not own\n    SDL_Thread*              video_fill_thread;\n    SDL_Thread              _video_fill_thread;\n};\n\nint videotoolbox_video_thread(void *arg)\n{\n    IJKFF_Pipenode_Opaque* opaque = (IJKFF_Pipenode_Opaque*) arg;\n    FFPlayer *ffp = opaque->ffp;\n    VideoState *is = ffp->is;\n    Decoder   *d = &is->viddec;\n    int ret = 0;\n\n    for (;;) {\n\n        if (is->abort_request || d->queue->abort_request) {\n            return -1;\n        }\n        @autoreleasepool {\n            ret = opaque->context->decode_frame(opaque->context->opaque);\n        }\n        if (ret < 0)\n            goto the_end;\n        if (!ret)\n            continue;\n\n        if (ret < 0)\n            goto the_end;\n    }\nthe_end:\n    return 0;\n}\n\n\n\nstatic void func_destroy(IJKFF_Pipenode *node)\n{\n    // do nothing\n}\n\nstatic int func_run_sync(IJKFF_Pipenode *node)\n{\n    IJKFF_Pipenode_Opaque *opaque = node->opaque;\n    int ret = videotoolbox_video_thread(opaque);\n\n    if (opaque->context) {\n        opaque->context->free(opaque->context->opaque);\n        free(opaque->context);\n        opaque->context = NULL;\n    }\n\n    return ret;\n}\n\n\n\nIJKFF_Pipenode *ffpipenode_create_video_decoder_from_ios_videotoolbox(FFPlayer *ffp)\n{\n    if (!ffp || !ffp->is)\n        return NULL;\n    if ([[[UIDevice currentDevice] systemVersion] floatValue]  < 8.0){\n        return NULL;\n    }\n    IJKFF_Pipenode *node = ffpipenode_alloc(sizeof(IJKFF_Pipenode_Opaque));\n    if (!node)\n        return node;\n    memset(node, sizeof(IJKFF_Pipenode), 0);\n\n    VideoState            *is         = ffp->is;\n    IJKFF_Pipenode_Opaque *opaque     = node->opaque;\n    node->func_destroy  = func_destroy;\n    node->func_run_sync = func_run_sync;\n    opaque->ffp         = ffp;\n    opaque->decoder     = &is->viddec;\n    opaque->avctx = opaque->decoder->avctx;\n    switch (opaque->avctx->codec_id) {\n    case AV_CODEC_ID_H264:\n    case AV_CODEC_ID_HEVC:\n        if (ffp->vtb_async)\n            opaque->context = Ijk_VideoToolbox_Async_Create(ffp, opaque->avctx);\n        else\n            opaque->context = Ijk_VideoToolbox_Sync_Create(ffp, opaque->avctx);\n        break;\n    default:\n        ALOGI(\"Videotoolbox-pipeline:open_video_decoder: not H264 or H265\\n\");\n        goto fail;\n    }\n    if (opaque->context == NULL) {\n        ALOGE(\"could not init video tool box decoder !!!\");\n        goto fail;\n    }\n    return node;\n\nfail:\n    ffpipenode_free_p(&node);\n    return NULL;\n}\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/h264_sps_parser.h",
    "content": "/*\n * h264_sps_parser.h\n *\n * Copyright (c) 2014 Zhou Quan <zhouqicy@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n#ifndef IJKMediaPlayer_h264_sps_parser_h\n#define IJKMediaPlayer_h264_sps_parser_h\n\n#define AV_RB16(x)                          \\\n((((const uint8_t*)(x))[0] <<  8) |        \\\n((const uint8_t*)(x)) [1])\n\n#define AV_RB24(x)                          \\\n((((const uint8_t*)(x))[0] << 16) |        \\\n(((const uint8_t*)(x))[1] <<  8) |        \\\n((const uint8_t*)(x))[2])\n\n#define AV_RB32(x)                          \\\n((((const uint8_t*)(x))[0] << 24) |        \\\n(((const uint8_t*)(x))[1] << 16) |        \\\n(((const uint8_t*)(x))[2] <<  8) |        \\\n((const uint8_t*)(x))[3])\n\n\n/* NAL unit types */\nenum {\n    NAL_SLICE           = 1,\n    NAL_DPA             = 2,\n    NAL_DPB             = 3,\n    NAL_DPC             = 4,\n    NAL_IDR_SLICE       = 5,\n    NAL_SEI             = 6,\n    NAL_SPS             = 7,\n    NAL_PPS             = 8,\n    NAL_AUD             = 9,\n    NAL_END_SEQUENCE    = 10,\n    NAL_END_STREAM      = 11,\n    NAL_FILLER_DATA     = 12,\n    NAL_SPS_EXT         = 13,\n    NAL_AUXILIARY_SLICE = 19,\n    NAL_FF_IGNORE       = 0xff0f001,\n};\n\n\ntypedef struct\n{\n    const uint8_t *data;\n    const uint8_t *end;\n    int head;\n    uint64_t cache;\n} nal_bitstream;\n\nstatic void\nnal_bs_init(nal_bitstream *bs, const uint8_t *data, size_t size)\n{\n    bs->data = data;\n    bs->end  = data + size;\n    bs->head = 0;\n    // fill with something other than 0 to detect\n    //  emulation prevention bytes\n    bs->cache = 0xffffffff;\n}\n\nstatic uint64_t\nnal_bs_read(nal_bitstream *bs, int n)\n{\n    uint64_t res = 0;\n    int shift;\n\n    if (n == 0)\n        return res;\n\n    // fill up the cache if we need to\n    while (bs->head < n) {\n        uint8_t a_byte;\n        bool check_three_byte;\n\n        check_three_byte = true;\n    next_byte:\n        if (bs->data >= bs->end) {\n            // we're at the end, can't produce more than head number of bits\n            n = bs->head;\n            break;\n        }\n        // get the byte, this can be an emulation_prevention_three_byte that we need\n        // to ignore.\n        a_byte = *bs->data++;\n        if (check_three_byte && a_byte == 0x03 && ((bs->cache & 0xffff) == 0)) {\n            // next byte goes unconditionally to the cache, even if it's 0x03\n            check_three_byte = false;\n            goto next_byte;\n        }\n        // shift bytes in cache, moving the head bits of the cache left\n        bs->cache = (bs->cache << 8) | a_byte;\n        bs->head += 8;\n    }\n\n    // bring the required bits down and truncate\n    if ((shift = bs->head - n) > 0)\n        res = bs->cache >> shift;\n    else\n        res = bs->cache;\n\n    // mask out required bits\n    if (n < 32)\n        res &= (1 << n) - 1;\n\n    bs->head = shift;\n\n    return res;\n}\n\nstatic bool\nnal_bs_eos(nal_bitstream *bs)\n{\n    return (bs->data >= bs->end) && (bs->head == 0);\n}\n\n// read unsigned Exp-Golomb code\nstatic int64_t\nnal_bs_read_ue(nal_bitstream *bs)\n{\n    int i = 0;\n\n    while (nal_bs_read(bs, 1) == 0 && !nal_bs_eos(bs) && i < 32)\n        i++;\n\n    return ((1 << i) - 1 + nal_bs_read(bs, i));\n}\n\ntypedef struct\n{\n    uint64_t profile_idc;\n    uint64_t level_idc;\n    uint64_t sps_id;\n\n    uint64_t chroma_format_idc;\n    uint64_t separate_colour_plane_flag;\n    uint64_t bit_depth_luma_minus8;\n    uint64_t bit_depth_chroma_minus8;\n    uint64_t qpprime_y_zero_transform_bypass_flag;\n    uint64_t seq_scaling_matrix_present_flag;\n\n    uint64_t log2_max_frame_num_minus4;\n    uint64_t pic_order_cnt_type;\n    uint64_t log2_max_pic_order_cnt_lsb_minus4;\n\n    uint64_t max_num_ref_frames;\n    uint64_t gaps_in_frame_num_value_allowed_flag;\n    uint64_t pic_width_in_mbs_minus1;\n    uint64_t pic_height_in_map_units_minus1;\n\n    uint64_t frame_mbs_only_flag;\n    uint64_t mb_adaptive_frame_field_flag;\n\n    uint64_t direct_8x8_inference_flag;\n\n    uint64_t frame_cropping_flag;\n    uint64_t frame_crop_left_offset;\n    uint64_t frame_crop_right_offset;\n    uint64_t frame_crop_top_offset;\n    uint64_t frame_crop_bottom_offset;\n} sps_info_struct;\n\nstatic void parseh264_sps(uint8_t *sps, uint32_t sps_size,  int *level, int *profile, bool *interlaced, int32_t *max_ref_frames)\n{\n    nal_bitstream bs;\n    sps_info_struct sps_info = {0};\n\n    nal_bs_init(&bs, sps, sps_size);\n\n    sps_info.profile_idc  = nal_bs_read(&bs, 8);\n    nal_bs_read(&bs, 1);  // constraint_set0_flag\n    nal_bs_read(&bs, 1);  // constraint_set1_flag\n    nal_bs_read(&bs, 1);  // constraint_set2_flag\n    nal_bs_read(&bs, 1);  // constraint_set3_flag\n    nal_bs_read(&bs, 4);  // reserved\n    sps_info.level_idc    = nal_bs_read(&bs, 8);\n    sps_info.sps_id       = nal_bs_read_ue(&bs);\n\n    if (sps_info.profile_idc == 100 ||\n        sps_info.profile_idc == 110 ||\n        sps_info.profile_idc == 122 ||\n        sps_info.profile_idc == 244 ||\n        sps_info.profile_idc == 44  ||\n        sps_info.profile_idc == 83  ||\n        sps_info.profile_idc == 86)\n    {\n            sps_info.chroma_format_idc                    = nal_bs_read_ue(&bs);\n            if (sps_info.chroma_format_idc == 3)\n                sps_info.separate_colour_plane_flag         = nal_bs_read(&bs, 1);\n            sps_info.bit_depth_luma_minus8                = nal_bs_read_ue(&bs);\n            sps_info.bit_depth_chroma_minus8              = nal_bs_read_ue(&bs);\n            sps_info.qpprime_y_zero_transform_bypass_flag = nal_bs_read(&bs, 1);\n\n            sps_info.seq_scaling_matrix_present_flag = nal_bs_read (&bs, 1);\n            if (sps_info.seq_scaling_matrix_present_flag)\n            {\n                /* TODO: unfinished */\n            }\n    }\n    sps_info.log2_max_frame_num_minus4 = nal_bs_read_ue(&bs);\n    if (sps_info.log2_max_frame_num_minus4 > 12) {\n        // must be between 0 and 12\n        // don't early return here - the bits we are using (profile/level/interlaced/ref frames)\n        // might still be valid - let the parser go on and pray.\n        //return;\n    }\n\n    sps_info.pic_order_cnt_type = nal_bs_read_ue(&bs);\n    if (sps_info.pic_order_cnt_type == 0) {\n        sps_info.log2_max_pic_order_cnt_lsb_minus4 = nal_bs_read_ue(&bs);\n    }\n    else if (sps_info.pic_order_cnt_type == 1) { // TODO: unfinished\n        /*\n         delta_pic_order_always_zero_flag = gst_nal_bs_read (bs, 1);\n         offset_for_non_ref_pic = gst_nal_bs_read_se (bs);\n         offset_for_top_to_bottom_field = gst_nal_bs_read_se (bs);\n\n         num_ref_frames_in_pic_order_cnt_cycle = gst_nal_bs_read_ue (bs);\n         for( i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ )\n         offset_for_ref_frame[i] = gst_nal_bs_read_se (bs);\n         */\n    }\n\n    sps_info.max_num_ref_frames             = nal_bs_read_ue(&bs);\n    sps_info.gaps_in_frame_num_value_allowed_flag = nal_bs_read(&bs, 1);\n    sps_info.pic_width_in_mbs_minus1        = nal_bs_read_ue(&bs);\n    sps_info.pic_height_in_map_units_minus1 = nal_bs_read_ue(&bs);\n\n    sps_info.frame_mbs_only_flag            = nal_bs_read(&bs, 1);\n    if (!sps_info.frame_mbs_only_flag)\n        sps_info.mb_adaptive_frame_field_flag = nal_bs_read(&bs, 1);\n\n    sps_info.direct_8x8_inference_flag      = nal_bs_read(&bs, 1);\n\n    sps_info.frame_cropping_flag            = nal_bs_read(&bs, 1);\n    if (sps_info.frame_cropping_flag) {\n        sps_info.frame_crop_left_offset       = nal_bs_read_ue(&bs);\n        sps_info.frame_crop_right_offset      = nal_bs_read_ue(&bs);\n        sps_info.frame_crop_top_offset        = nal_bs_read_ue(&bs);\n        sps_info.frame_crop_bottom_offset     = nal_bs_read_ue(&bs);\n    }\n\n    *level = (int)sps_info.level_idc;\n    *profile = (int)sps_info.profile_idc;\n    *interlaced = (int)!sps_info.frame_mbs_only_flag;\n    *max_ref_frames = (int)sps_info.max_num_ref_frames;\n}\n\nstatic bool validate_avcC_spc(uint8_t *extradata, uint32_t extrasize, int32_t *max_ref_frames, int *level, int *profile)\n{\n    // check the avcC atom's sps for number of reference frames and\n    // bail if interlaced, VDA does not handle interlaced h264.\n    bool interlaced = true;\n    uint8_t *spc = extradata + 6;\n    uint32_t sps_size = AV_RB16(spc);\n    if (sps_size)\n        parseh264_sps(spc+3, sps_size-1, level, profile, &interlaced, max_ref_frames);\n    if (interlaced)\n        return false;\n    return true;\n}\n\n\n\n\nstatic inline int ff_get_nal_units_type(const uint8_t * const data) {\n    return   data[4] & 0x1f;\n}\n\nstatic uint32_t bytesToInt(uint8_t* src) {\n    uint32_t value;\n    value = (uint32_t)((src[0] & 0xFF)<<24|(src[1]&0xFF)<<16|(src[2]&0xFF)<<8|(src[3]&0xFF));\n    return value;\n}\n\n\n\nstatic bool ff_avpacket_is_idr(const AVPacket* pkt) {\n\n    int state = -1;\n\n    if (pkt->data && pkt->size >= 5) {\n        int offset = 0;\n        while (offset >= 0 && offset + 5 <= pkt->size) {\n            void* nal_start = pkt->data+offset;\n            state = ff_get_nal_units_type(nal_start);\n            if (state == NAL_IDR_SLICE) {\n                return true;\n            }\n            //            ALOGI(\"offset %d \\n\", bytesToInt(nal_start));\n            offset+=(bytesToInt(nal_start) + 4);\n        }\n    }\n    return false;\n}\n\nstatic bool ff_avpacket_is_key(const AVPacket* pkt) {\n    if (pkt->flags & AV_PKT_FLAG_KEY) {\n        return true;\n    } else {\n        return false;\n    }\n}\n\nstatic bool ff_avpacket_i_or_idr(const AVPacket* pkt,bool isIdr) {\n    if (isIdr == true) {\n        return ff_avpacket_is_idr(pkt);\n    } else {\n        return ff_avpacket_is_key(pkt);\n    }\n}\n\n\n\n#endif\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLAudioKit.h",
    "content": "/*\n * IJKSDLAudioKit.h\n *\n * Copyright (c) 2013-2014 Bilibili\n * Copyright (c) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n *\n * based on https://github.com/kolyvan/kxmovie\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import <AVFoundation/AVFoundation.h>\n#include \"ijksdl/ijksdl_aout.h\"\n\nextern void IJKSDLGetAudioComponentDescriptionFromSpec(const SDL_AudioSpec *spec, AudioComponentDescription *desc);\nextern void IJKSDLGetAudioStreamBasicDescriptionFromSpec(const SDL_AudioSpec *spec, AudioStreamBasicDescription *desc);\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLAudioKit.m",
    "content": "/*\n * IJKSDLAudioKit.m\n *\n * Copyright (c) 2013-2014 Bilibili\n * Copyright (c) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n *\n * based on https://github.com/kolyvan/kxmovie\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import \"IJKSDLAudioKit.h\"\n\nextern void IJKSDLGetAudioComponentDescriptionFromSpec(const SDL_AudioSpec *spec, AudioComponentDescription *desc)\n{\n    desc->componentType = kAudioUnitType_Output;\n    desc->componentSubType = kAudioUnitSubType_RemoteIO;\n    desc->componentManufacturer = kAudioUnitManufacturer_Apple;\n    desc->componentFlags = 0;\n    desc->componentFlagsMask = 0;\n}\n\nextern void IJKSDLGetAudioStreamBasicDescriptionFromSpec(const SDL_AudioSpec *spec, AudioStreamBasicDescription *desc)\n{\n    desc->mSampleRate = spec->freq;\n    desc->mFormatID = kAudioFormatLinearPCM;\n    desc->mFormatFlags = kLinearPCMFormatFlagIsPacked;\n    desc->mChannelsPerFrame = spec->channels;\n    desc->mFramesPerPacket = 1;\n\n    desc->mBitsPerChannel = SDL_AUDIO_BITSIZE(spec->format);\n    if (SDL_AUDIO_ISBIGENDIAN(spec->format))\n        desc->mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;\n    if (SDL_AUDIO_ISFLOAT(spec->format))\n        desc->mFormatFlags |= kLinearPCMFormatFlagIsFloat;\n    if (SDL_AUDIO_ISSIGNED(spec->format))\n        desc->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;\n\n    desc->mBytesPerFrame = desc->mBitsPerChannel * desc->mChannelsPerFrame / 8;\n    desc->mBytesPerPacket = desc->mBytesPerFrame * desc->mFramesPerPacket;\n}\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLAudioQueueController.h",
    "content": "/*\n * IJKSDLAudioQueueController.h\n *\n * Copyright (c) 2013-2014 Bilibili\n * Copyright (c) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n *\n * based on https://github.com/kolyvan/kxmovie\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import <Foundation/Foundation.h>\n\n#include \"ijksdl/ijksdl_aout.h\"\n\n@interface IJKSDLAudioQueueController : NSObject\n\n- (id)initWithAudioSpec:(const SDL_AudioSpec *)aSpec;\n\n- (void)play;\n- (void)pause;\n- (void)flush;\n- (void)stop;\n- (void)close;\n- (void)setPlaybackRate:(float)playbackRate;\n- (void)setPlaybackVolume:(float)playbackVolume;\n- (double)get_latency_seconds;\n\n@property (nonatomic, readonly) SDL_AudioSpec spec;\n    \n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLAudioQueueController.m",
    "content": "/*\n * IJKSDLAudioQueueController.m\n *\n * Copyright (c) 2013-2014 Bilibili\n * Copyright (c) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n *\n * based on https://github.com/kolyvan/kxmovie\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import \"IJKSDLAudioQueueController.h\"\n#import \"IJKSDLAudioKit.h\"\n#import \"ijksdl_log.h\"\n\n#import <AVFoundation/AVFoundation.h>\n\n#define kIJKAudioQueueNumberBuffers (3)\n\n@implementation IJKSDLAudioQueueController {\n    AudioQueueRef _audioQueueRef;\n    AudioQueueBufferRef _audioQueueBufferRefArray[kIJKAudioQueueNumberBuffers];\n    BOOL _isPaused;\n    BOOL _isStopped;\n\n    volatile BOOL _isAborted;\n    NSLock *_lock;\n}\n\n- (id)initWithAudioSpec:(const SDL_AudioSpec *)aSpec\n{\n    self = [super init];\n    if (self) {\n        if (aSpec == NULL) {\n            self = nil;\n            return nil;\n        }\n        _spec = *aSpec;\n\n        if (aSpec->format != AUDIO_S16SYS) {\n            NSLog(@\"aout_open_audio: unsupported format %d\\n\", (int)aSpec->format);\n            return nil;\n        }\n\n        if (aSpec->channels > 2) {\n            NSLog(@\"aout_open_audio: unsupported channels %d\\n\", (int)aSpec->channels);\n            return nil;\n        }\n\n        /* Get the current format */\n        AudioStreamBasicDescription streamDescription;\n        IJKSDLGetAudioStreamBasicDescriptionFromSpec(&_spec, &streamDescription);\n\n        SDL_CalculateAudioSpec(&_spec);\n\n        if (_spec.size == 0) {\n            NSLog(@\"aout_open_audio: unexcepted audio spec size %u\", _spec.size);\n            return nil;\n        }\n\n        /* Set the desired format */\n        AudioQueueRef audioQueueRef;\n        OSStatus status = AudioQueueNewOutput(&streamDescription,\n                                              IJKSDLAudioQueueOuptutCallback,\n                                              (__bridge void *) self,\n                                              NULL,\n                                              kCFRunLoopCommonModes,\n                                              0,\n                                              &audioQueueRef);\n        if (status != noErr) {\n            NSLog(@\"AudioQueue: AudioQueueNewOutput failed (%d)\\n\", (int)status);\n            self = nil;\n            return nil;\n        }\n\n        UInt32 propValue = 1;\n        AudioQueueSetProperty(audioQueueRef, kAudioQueueProperty_EnableTimePitch, &propValue, sizeof(propValue));\n        propValue = 1;\n        AudioQueueSetProperty(_audioQueueRef, kAudioQueueProperty_TimePitchBypass, &propValue, sizeof(propValue));\n        propValue = kAudioQueueTimePitchAlgorithm_Spectral;\n        AudioQueueSetProperty(_audioQueueRef, kAudioQueueProperty_TimePitchAlgorithm, &propValue, sizeof(propValue));\n\n        status = AudioQueueStart(audioQueueRef, NULL);\n        if (status != noErr) {\n            NSLog(@\"AudioQueue: AudioQueueStart failed (%d)\\n\", (int)status);\n            self = nil;\n            return nil;\n        }\n\n        _audioQueueRef = audioQueueRef;\n\n        for (int i = 0;i < kIJKAudioQueueNumberBuffers; i++)\n        {\n            AudioQueueAllocateBuffer(audioQueueRef, _spec.size, &_audioQueueBufferRefArray[i]);\n            _audioQueueBufferRefArray[i]->mAudioDataByteSize = _spec.size;\n            memset(_audioQueueBufferRefArray[i]->mAudioData, 0, _spec.size);\n            AudioQueueEnqueueBuffer(audioQueueRef, _audioQueueBufferRefArray[i], 0, NULL);\n        }\n        /*-\n        status = AudioQueueStart(audioQueueRef, NULL);\n        if (status != noErr) {\n            NSLog(@\"AudioQueue: AudioQueueStart failed (%d)\\n\", (int)status);\n            self = nil;\n            return nil;\n        }\n         */\n\n        _isStopped = NO;\n\n        _lock = [[NSLock alloc] init];\n    }\n    return self;\n}\n\n- (void)dealloc\n{\n    [self close];\n}\n\n- (void)play\n{\n    if (!_audioQueueRef)\n        return;\n\n    self.spec.callback(self.spec.userdata, NULL, 0);\n\n    @synchronized(_lock) {\n        _isPaused = NO;\n        NSError *error = nil;\n        if (NO == [[AVAudioSession sharedInstance] setActive:YES error:&error]) {\n            NSLog(@\"AudioQueue: AVAudioSession.setActive(YES) failed: %@\\n\", error ? [error localizedDescription] : @\"nil\");\n        }\n\n        OSStatus status = AudioQueueStart(_audioQueueRef, NULL);\n        if (status != noErr)\n            NSLog(@\"AudioQueue: AudioQueueStart failed (%d)\\n\", (int)status);\n    }\n}\n\n- (void)pause\n{\n    if (!_audioQueueRef)\n        return;\n\n    @synchronized(_lock) {\n        if (_isStopped)\n            return;\n\n        _isPaused = YES;\n        OSStatus status = AudioQueuePause(_audioQueueRef);\n        if (status != noErr)\n            NSLog(@\"AudioQueue: AudioQueuePause failed (%d)\\n\", (int)status);\n    }\n}\n\n- (void)flush\n{\n    if (!_audioQueueRef)\n        return;\n\n    @synchronized(_lock) {\n        if (_isStopped)\n            return;\n\n        if (_isPaused == YES) {\n            for (int i = 0; i < kIJKAudioQueueNumberBuffers; i++)\n            {\n                if (_audioQueueBufferRefArray[i] && _audioQueueBufferRefArray[i]->mAudioData) {\n                    _audioQueueBufferRefArray[i]->mAudioDataByteSize = _spec.size;\n                    memset(_audioQueueBufferRefArray[i]->mAudioData, 0, _spec.size);\n                }\n            }\n        } else {\n            AudioQueueFlush(_audioQueueRef);\n        }\n    }\n}\n\n- (void)stop\n{\n    if (!_audioQueueRef)\n        return;\n\n    @synchronized(_lock) {\n        if (_isStopped)\n            return;\n\n        _isStopped = YES;\n    }\n\n    // do not lock AudioQueueStop, or may be run into deadlock\n    AudioQueueStop(_audioQueueRef, true);\n    AudioQueueDispose(_audioQueueRef, true);\n}\n\n- (void)close\n{\n    [self stop];\n    _audioQueueRef = nil;\n}\n\n- (void)setPlaybackRate:(float)playbackRate\n{\n    if (fabsf(playbackRate - 1.0f) <= 0.000001) {\n        UInt32 propValue = 1;\n        AudioQueueSetProperty(_audioQueueRef, kAudioQueueProperty_TimePitchBypass, &propValue, sizeof(propValue));\n        AudioQueueSetParameter(_audioQueueRef, kAudioQueueParam_PlayRate, 1.0f);\n    } else {\n        UInt32 propValue = 0;\n        AudioQueueSetProperty(_audioQueueRef, kAudioQueueProperty_TimePitchBypass, &propValue, sizeof(propValue));\n        AudioQueueSetParameter(_audioQueueRef, kAudioQueueParam_PlayRate, playbackRate);\n    }\n}\n\n- (void)setPlaybackVolume:(float)playbackVolume\n{\n    float aq_volume = playbackVolume;\n    if (fabsf(aq_volume - 1.0f) <= 0.000001) {\n        AudioQueueSetParameter(_audioQueueRef, kAudioQueueParam_Volume, 1.f);\n    } else {\n        AudioQueueSetParameter(_audioQueueRef, kAudioQueueParam_Volume, aq_volume);\n    }\n}\n\n- (double)get_latency_seconds\n{\n    return ((double)(kIJKAudioQueueNumberBuffers)) * _spec.samples / _spec.freq;\n}\n\nstatic void IJKSDLAudioQueueOuptutCallback(void * inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) {\n    @autoreleasepool {\n        IJKSDLAudioQueueController* aqController = (__bridge IJKSDLAudioQueueController *) inUserData;\n\n        if (!aqController) {\n            // do nothing;\n        } else if (aqController->_isPaused || aqController->_isStopped) {\n            memset(inBuffer->mAudioData, aqController.spec.silence, inBuffer->mAudioDataByteSize);\n        } else {\n            (*aqController.spec.callback)(aqController.spec.userdata, inBuffer->mAudioData, inBuffer->mAudioDataByteSize);\n        }\n\n        AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL);\n    }\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLAudioUnitController.h",
    "content": "/*\n * IJKSDLAudioUnitController.h\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * based on https://github.com/kolyvan/kxmovie\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import <Foundation/Foundation.h>\n\n#include \"ijksdl/ijksdl_aout.h\"\n\n@interface IJKSDLAudioUnitController : NSObject\n\n- (id)initWithAudioSpec:(const SDL_AudioSpec *)aSpec;\n\n- (void)play;\n- (void)pause;\n- (void)flush;\n- (void)stop;\n- (void)close;\n\n@property (nonatomic, readonly) SDL_AudioSpec spec;\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLAudioUnitController.m",
    "content": "/*\n * IJKSDLAudioUnitController.m\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * based on https://github.com/kolyvan/kxmovie\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import \"IJKSDLAudioUnitController.h\"\n#import \"IJKSDLAudioKit.h\"\n#include \"ijksdl/ijksdl_log.h\"\n\n#import <AVFoundation/AVFoundation.h>\n\n@implementation IJKSDLAudioUnitController {\n    AudioUnit _auUnit;\n    BOOL _isPaused;\n}\n\n- (id)initWithAudioSpec:(const SDL_AudioSpec *)aSpec\n{\n    self = [super init];\n    if (self) {\n        if (aSpec == NULL) {\n            self = nil;\n            return nil;\n        }\n        _spec = *aSpec;\n\n        if (aSpec->format != AUDIO_S16SYS) {\n            NSLog(@\"aout_open_audio: unsupported format %d\\n\", (int)aSpec->format);\n            return nil;\n        }\n\n        if (aSpec->channels > 6) {\n            NSLog(@\"aout_open_audio: unsupported channels %d\\n\", (int)aSpec->channels);\n            return nil;\n        }\n\n        AudioComponentDescription desc;\n        IJKSDLGetAudioComponentDescriptionFromSpec(&_spec, &desc);\n\n        AudioComponent auComponent = AudioComponentFindNext(NULL, &desc);\n        if (auComponent == NULL) {\n            ALOGE(\"AudioUnit: AudioComponentFindNext failed\");\n            self = nil;\n            return nil;\n        }\n\n        AudioUnit auUnit;\n        OSStatus status = AudioComponentInstanceNew(auComponent, &auUnit);\n        if (status != noErr) {\n            ALOGE(\"AudioUnit: AudioComponentInstanceNew failed\");\n            self = nil;\n            return nil;\n        }\n\n        UInt32 flag = 1;\n        status = AudioUnitSetProperty(auUnit,\n                                      kAudioOutputUnitProperty_EnableIO,\n                                      kAudioUnitScope_Output,\n                                      0,\n                                      &flag,\n                                      sizeof(flag));\n        if (status != noErr) {\n            ALOGE(\"AudioUnit: failed to set IO mode (%d)\", (int)status);\n        }\n\n        /* Get the current format */\n        _spec.format = AUDIO_S16SYS;\n        _spec.channels = 2;\n        AudioStreamBasicDescription streamDescription;\n        IJKSDLGetAudioStreamBasicDescriptionFromSpec(&_spec, &streamDescription);\n\n        /* Set the desired format */\n        UInt32 i_param_size = sizeof(streamDescription);\n        status = AudioUnitSetProperty(auUnit,\n                                      kAudioUnitProperty_StreamFormat,\n                                      kAudioUnitScope_Input,\n                                      0,\n                                      &streamDescription,\n                                      i_param_size);\n        if (status != noErr) {\n            ALOGE(\"AudioUnit: failed to set stream format (%d)\", (int)status);\n            self = nil;\n            return nil;\n        }\n\n        /* Retrieve actual format */\n        status = AudioUnitGetProperty(auUnit,\n                                      kAudioUnitProperty_StreamFormat,\n                                      kAudioUnitScope_Input,\n                                      0,\n                                      &streamDescription,\n                                      &i_param_size);\n        if (status != noErr) {\n            ALOGE(\"AudioUnit: failed to verify stream format (%d)\\n\", (int)status);\n        }\n\n        AURenderCallbackStruct callback;\n        callback.inputProc = (AURenderCallback) RenderCallback;\n        callback.inputProcRefCon = (__bridge void*) self;\n        status = AudioUnitSetProperty(auUnit,\n                                      kAudioUnitProperty_SetRenderCallback,\n                                      kAudioUnitScope_Input,\n                                      0, &callback, sizeof(callback));\n        if (status != noErr) {\n            ALOGE(\"AudioUnit: render callback setup failed (%d)\\n\", (int)status);\n            self = nil;\n            return nil;\n        }\n\n        SDL_CalculateAudioSpec(&_spec);\n\n        /* AU initiliaze */\n        status = AudioUnitInitialize(auUnit);\n        if (status != noErr) {\n            ALOGE(\"AudioUnit: AudioUnitInitialize failed (%d)\\n\", (int)status);\n            self = nil;\n            return nil;\n        }\n\n        _auUnit = auUnit;\n    }\n    return self;\n}\n\n- (void)dealloc\n{\n    [self close];\n}\n\n- (void)play\n{\n    if (!_auUnit)\n        return;\n\n    _isPaused = NO;\n    NSError *error = nil;\n    if (NO == [[AVAudioSession sharedInstance] setActive:YES error:&error]) {\n        NSLog(@\"AudioUnit: AVAudioSession.setActive(YES) failed: %@\\n\", error ? [error localizedDescription] : @\"nil\");\n    }\n\n    OSStatus status = AudioOutputUnitStart(_auUnit);\n    if (status != noErr)\n        NSLog(@\"AudioUnit: AudioOutputUnitStart failed (%d)\\n\", (int)status);\n}\n\n- (void)pause\n{\n    if (!_auUnit)\n        return;\n\n    _isPaused = YES;\n    OSStatus status = AudioOutputUnitStop(_auUnit);\n    if (status != noErr)\n        ALOGE(\"AudioUnit: failed to stop AudioUnit (%d)\\n\", (int)status);\n}\n\n- (void)flush\n{\n    if (!_auUnit)\n        return;\n\n    AudioUnitReset(_auUnit, kAudioUnitScope_Global, 0);\n}\n\n- (void)stop\n{\n    if (!_auUnit)\n        return;\n\n    OSStatus status = AudioOutputUnitStop(_auUnit);\n    if (status != noErr)\n        ALOGE(\"AudioUnit: failed to stop AudioUnit (%d)\", (int)status);\n}\n\n- (void)close\n{\n    [self stop];\n\n    if (!_auUnit)\n        return;\n\n    AURenderCallbackStruct callback;\n    memset(&callback, 0, sizeof(AURenderCallbackStruct));\n    AudioUnitSetProperty(_auUnit,\n                         kAudioUnitProperty_SetRenderCallback,\n                         kAudioUnitScope_Input, 0, &callback,\n                         sizeof(callback));\n\n    AudioComponentInstanceDispose(_auUnit);\n    _auUnit = NULL;\n}\n\nstatic OSStatus RenderCallback(void                        *inRefCon,\n                               AudioUnitRenderActionFlags  *ioActionFlags,\n                               const AudioTimeStamp        *inTimeStamp,\n                               UInt32                      inBusNumber,\n                               UInt32                      inNumberFrames,\n                               AudioBufferList             *ioData)\n{\n    @autoreleasepool {\n        IJKSDLAudioUnitController* auController = (__bridge IJKSDLAudioUnitController *) inRefCon;\n\n        if (!auController || auController->_isPaused) {\n            for (UInt32 i = 0; i < ioData->mNumberBuffers; i++) {\n                AudioBuffer *ioBuffer = &ioData->mBuffers[i];\n                memset(ioBuffer->mData, auController.spec.silence, ioBuffer->mDataByteSize);\n            }\n            return noErr;\n        }\n\n        for (int i = 0; i < (int)ioData->mNumberBuffers; i++) {\n            AudioBuffer *ioBuffer = &ioData->mBuffers[i];\n            (*auController.spec.callback)(auController.spec.userdata, ioBuffer->mData, ioBuffer->mDataByteSize);\n        }\n\n        return noErr;\n    }\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLGLView.h",
    "content": "/*\n * IJKSDLGLView.h\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * based on https://github.com/kolyvan/kxmovie\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import <UIKit/UIKit.h>\n#import \"IJKSDLGLViewProtocol.h\"\n\n#include \"ijksdl/ijksdl_vout.h\"\n\n@interface IJKSDLGLView : UIView <IJKSDLGLViewProtocol>\n\n- (id) initWithFrame:(CGRect)frame;\n- (void) display: (SDL_VoutOverlay *) overlay;\n\n- (UIImage*) snapshot;\n- (void)setShouldLockWhileBeingMovedToWindow:(BOOL)shouldLockWhiteBeingMovedToWindow __attribute__((deprecated(\"unused\")));\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLGLView.m",
    "content": "/*\n * IJKSDLGLView.m\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * based on https://github.com/kolyvan/kxmovie\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import \"IJKSDLGLView.h\"\n#include \"ijksdl/ijksdl_timer.h\"\n#include \"ijksdl/ios/ijksdl_ios.h\"\n#include \"ijksdl/ijksdl_gles2.h\"\n\ntypedef NS_ENUM(NSInteger, IJKSDLGLViewApplicationState) {\n    IJKSDLGLViewApplicationUnknownState = 0,\n    IJKSDLGLViewApplicationForegroundState = 1,\n    IJKSDLGLViewApplicationBackgroundState = 2\n};\n\n@interface IJKSDLGLView()\n@property(atomic,strong) NSRecursiveLock *glActiveLock;\n@property(atomic) BOOL glActivePaused;\n@end\n\n@implementation IJKSDLGLView {\n    EAGLContext     *_context;\n    GLuint          _framebuffer;\n    GLuint          _renderbuffer;\n    GLint           _backingWidth;\n    GLint           _backingHeight;\n\n    int             _frameCount;\n    \n    int64_t         _lastFrameTime;\n\n    IJK_GLES2_Renderer *_renderer;\n    int                 _rendererGravity;\n\n    BOOL            _isRenderBufferInvalidated;\n\n    int             _tryLockErrorCount;\n    BOOL            _didSetupGL;\n    BOOL            _didStopGL;\n    BOOL            _didLockedDueToMovedToWindow;\n    BOOL            _shouldLockWhileBeingMovedToWindow;\n    NSMutableArray *_registeredNotifications;\n\n    IJKSDLGLViewApplicationState _applicationState;\n}\n\n@synthesize isThirdGLView              = _isThirdGLView;\n@synthesize scaleFactor                = _scaleFactor;\n@synthesize fps                        = _fps;\n\n+ (Class) layerClass\n{\n\treturn [CAEAGLLayer class];\n}\n\n- (id) initWithFrame:(CGRect)frame\n{\n    self = [super initWithFrame:frame];\n    if (self) {\n        _tryLockErrorCount = 0;\n        _shouldLockWhileBeingMovedToWindow = YES;\n        self.glActiveLock = [[NSRecursiveLock alloc] init];\n        _registeredNotifications = [[NSMutableArray alloc] init];\n        [self registerApplicationObservers];\n\n        _didSetupGL = NO;\n        if ([self isApplicationActive] == YES)\n            [self setupGLOnce];\n    }\n\n    return self;\n}\n\n- (void)willMoveToWindow:(UIWindow *)newWindow\n{\n    if (!_shouldLockWhileBeingMovedToWindow) {\n        [super willMoveToWindow:newWindow];\n        return;\n    }\n    if (newWindow && !_didLockedDueToMovedToWindow) {\n        [self lockGLActive];\n        _didLockedDueToMovedToWindow = YES;\n    }\n    [super willMoveToWindow:newWindow];\n}\n\n- (void)didMoveToWindow\n{\n    [super didMoveToWindow];\n    if (self.window && _didLockedDueToMovedToWindow) {\n        [self unlockGLActive];\n        _didLockedDueToMovedToWindow = NO;\n    }\n}\n\n- (BOOL)setupEAGLContext:(EAGLContext *)context\n{\n    glGenFramebuffers(1, &_framebuffer);\n    glGenRenderbuffers(1, &_renderbuffer);\n    glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer);\n    glBindRenderbuffer(GL_RENDERBUFFER, _renderbuffer);\n    [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)self.layer];\n    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_backingWidth);\n    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_backingHeight);\n    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _renderbuffer);\n\n    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);\n    if (status != GL_FRAMEBUFFER_COMPLETE) {\n        NSLog(@\"failed to make complete framebuffer object %x\\n\", status);\n        return NO;\n    }\n\n    GLenum glError = glGetError();\n    if (GL_NO_ERROR != glError) {\n        NSLog(@\"failed to setup GL %x\\n\", glError);\n        return NO;\n    }\n\n    return YES;\n}\n\n- (CAEAGLLayer *)eaglLayer\n{\n    return (CAEAGLLayer*) self.layer;\n}\n\n- (BOOL)setupGL\n{\n    if (_didSetupGL)\n        return YES;\n\n    CAEAGLLayer *eaglLayer = (CAEAGLLayer*) self.layer;\n    eaglLayer.opaque = YES;\n    eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:\n                                    [NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking,\n                                    kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat,\n                                    nil];\n\n    _scaleFactor = [[UIScreen mainScreen] scale];\n    if (_scaleFactor < 0.1f)\n        _scaleFactor = 1.0f;\n\n    [eaglLayer setContentsScale:_scaleFactor];\n\n    _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];\n    if (_context == nil) {\n        NSLog(@\"failed to setup EAGLContext\\n\");\n        return NO;\n    }\n\n    EAGLContext *prevContext = [EAGLContext currentContext];\n    [EAGLContext setCurrentContext:_context];\n\n    _didSetupGL = NO;\n    if ([self setupEAGLContext:_context]) {\n        NSLog(@\"OK setup GL\\n\");\n        _didSetupGL = YES;\n    }\n\n    [EAGLContext setCurrentContext:prevContext];\n    return _didSetupGL;\n}\n\n- (BOOL)setupGLOnce\n{\n    if (_didSetupGL)\n        return YES;\n\n    if (![self tryLockGLActive])\n        return NO;\n\n    BOOL didSetupGL = [self setupGL];\n    [self unlockGLActive];\n    return didSetupGL;\n}\n\n- (BOOL)isApplicationActive\n{\n    switch (_applicationState) {\n        case IJKSDLGLViewApplicationForegroundState:\n            return YES;\n        case IJKSDLGLViewApplicationBackgroundState:\n            return NO;\n        default: {\n            UIApplicationState appState = [UIApplication sharedApplication].applicationState;\n            switch (appState) {\n                case UIApplicationStateActive:\n                    return YES;\n                case UIApplicationStateInactive:\n                case UIApplicationStateBackground:\n                default:\n                    return NO;\n            }\n        }\n    }\n}\n\n- (void)dealloc\n{\n    [self lockGLActive];\n\n    _didStopGL = YES;\n\n    EAGLContext *prevContext = [EAGLContext currentContext];\n    [EAGLContext setCurrentContext:_context];\n    \n    IJK_GLES2_Renderer_reset(_renderer);\n    IJK_GLES2_Renderer_freeP(&_renderer);\n\n    if (_framebuffer) {\n        glDeleteFramebuffers(1, &_framebuffer);\n        _framebuffer = 0;\n    }\n\n    if (_renderbuffer) {\n        glDeleteRenderbuffers(1, &_renderbuffer);\n        _renderbuffer = 0;\n    }\n\n    glFinish();\n\n    [EAGLContext setCurrentContext:prevContext];\n\n    _context = nil;\n\n    [self unregisterApplicationObservers];\n\n    [self unlockGLActive];\n}\n\n- (void)setScaleFactor:(CGFloat)scaleFactor\n{\n    _scaleFactor = scaleFactor;\n    [self invalidateRenderBuffer];\n}\n\n- (void)layoutSubviews\n{\n    [super layoutSubviews];\n    if (self.window.screen != nil) {\n        _scaleFactor = self.window.screen.scale;\n    }\n    [self invalidateRenderBuffer];\n}\n\n- (void)setContentMode:(UIViewContentMode)contentMode\n{\n    [super setContentMode:contentMode];\n\n    switch (contentMode) {\n        case UIViewContentModeScaleToFill:\n            _rendererGravity = IJK_GLES2_GRAVITY_RESIZE;\n            break;\n        case UIViewContentModeScaleAspectFit:\n            _rendererGravity = IJK_GLES2_GRAVITY_RESIZE_ASPECT;\n            break;\n        case UIViewContentModeScaleAspectFill:\n            _rendererGravity = IJK_GLES2_GRAVITY_RESIZE_ASPECT_FILL;\n            break;\n        default:\n            _rendererGravity = IJK_GLES2_GRAVITY_RESIZE_ASPECT;\n            break;\n    }\n    [self invalidateRenderBuffer];\n}\n\n- (BOOL)setupRenderer: (SDL_VoutOverlay *) overlay\n{\n    if (overlay == nil)\n        return _renderer != nil;\n\n    if (!IJK_GLES2_Renderer_isValid(_renderer) ||\n        !IJK_GLES2_Renderer_isFormat(_renderer, overlay->format)) {\n\n        IJK_GLES2_Renderer_reset(_renderer);\n        IJK_GLES2_Renderer_freeP(&_renderer);\n\n        _renderer = IJK_GLES2_Renderer_create(overlay);\n        if (!IJK_GLES2_Renderer_isValid(_renderer))\n            return NO;\n\n        if (!IJK_GLES2_Renderer_use(_renderer))\n            return NO;\n\n        IJK_GLES2_Renderer_setGravity(_renderer, _rendererGravity, _backingWidth, _backingHeight);\n    }\n\n    return YES;\n}\n\n- (void)invalidateRenderBuffer\n{\n    NSLog(@\"invalidateRenderBuffer\\n\");\n    [self lockGLActive];\n\n    _isRenderBufferInvalidated = YES;\n\n    if ([[NSThread currentThread] isMainThread]) {\n        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{\n            if (_isRenderBufferInvalidated)\n                [self display:nil];\n        });\n    } else {\n        [self display:nil];\n    }\n\n    [self unlockGLActive];\n}\n\n- (void) display_pixels: (IJKOverlay *) overlay {\n    return;\n}\n\n- (void)display: (SDL_VoutOverlay *) overlay\n{\n    if (_didSetupGL == NO)\n        return;\n\n    if ([self isApplicationActive] == NO)\n        return;\n\n    if (![self tryLockGLActive]) {\n        if (0 == (_tryLockErrorCount % 100)) {\n            NSLog(@\"IJKSDLGLView:display: unable to tryLock GL active: %d\\n\", _tryLockErrorCount);\n        }\n        _tryLockErrorCount++;\n        return;\n    }\n\n    _tryLockErrorCount = 0;\n    if (_context && !_didStopGL) {\n        EAGLContext *prevContext = [EAGLContext currentContext];\n        [EAGLContext setCurrentContext:_context];\n        [self displayInternal:overlay];\n        [EAGLContext setCurrentContext:prevContext];\n    }\n\n    [self unlockGLActive];\n}\n\n// NOTE: overlay could be NULl\n- (void)displayInternal: (SDL_VoutOverlay *) overlay\n{\n    if (![self setupRenderer:overlay]) {\n        if (!overlay && !_renderer) {\n            NSLog(@\"IJKSDLGLView: setupDisplay not ready\\n\");\n        } else {\n            NSLog(@\"IJKSDLGLView: setupDisplay failed\\n\");\n        }\n        return;\n    }\n\n    [[self eaglLayer] setContentsScale:_scaleFactor];\n\n    if (_isRenderBufferInvalidated) {\n        NSLog(@\"IJKSDLGLView: renderbufferStorage fromDrawable\\n\");\n        _isRenderBufferInvalidated = NO;\n\n        glBindRenderbuffer(GL_RENDERBUFFER, _renderbuffer);\n        [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)self.layer];\n        glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_backingWidth);\n        glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_backingHeight);\n        IJK_GLES2_Renderer_setGravity(_renderer, _rendererGravity, _backingWidth, _backingHeight);\n    }\n\n    glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer);\n    glViewport(0, 0, _backingWidth, _backingHeight);\n\n    if (!IJK_GLES2_Renderer_renderOverlay(_renderer, overlay))\n        ALOGE(\"[EGL] IJK_GLES2_render failed\\n\");\n\n    glBindRenderbuffer(GL_RENDERBUFFER, _renderbuffer);\n    [_context presentRenderbuffer:GL_RENDERBUFFER];\n\n    int64_t current = (int64_t)SDL_GetTickHR();\n    int64_t delta   = (current > _lastFrameTime) ? current - _lastFrameTime : 0;\n    if (delta <= 0) {\n        _lastFrameTime = current;\n    } else if (delta >= 1000) {\n        _fps = ((CGFloat)_frameCount) * 1000 / delta;\n        _frameCount = 0;\n        _lastFrameTime = current;\n    } else {\n        _frameCount++;\n    }\n}\n\n#pragma mark AppDelegate\n\n- (void) lockGLActive\n{\n    [self.glActiveLock lock];\n}\n\n- (void) unlockGLActive\n{\n    [self.glActiveLock unlock];\n}\n\n- (BOOL) tryLockGLActive\n{\n    if (![self.glActiveLock tryLock])\n        return NO;\n\n    /*-\n    if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive &&\n        [UIApplication sharedApplication].applicationState != UIApplicationStateInactive) {\n        [self.appLock unlock];\n        return NO;\n    }\n     */\n\n    if (self.glActivePaused) {\n        [self.glActiveLock unlock];\n        return NO;\n    }\n    \n    return YES;\n}\n\n- (void)toggleGLPaused:(BOOL)paused\n{\n    [self lockGLActive];\n    if (!self.glActivePaused && paused) {\n        if (_context != nil) {\n            EAGLContext *prevContext = [EAGLContext currentContext];\n            [EAGLContext setCurrentContext:_context];\n            glFinish();\n            [EAGLContext setCurrentContext:prevContext];\n        }\n    }\n    self.glActivePaused = paused;\n    [self unlockGLActive];\n}\n\n- (void)registerApplicationObservers\n{\n\n    [[NSNotificationCenter defaultCenter] addObserver:self\n                                             selector:@selector(applicationWillEnterForeground)\n                                                 name:UIApplicationWillEnterForegroundNotification\n                                               object:nil];\n    [_registeredNotifications addObject:UIApplicationWillEnterForegroundNotification];\n\n    [[NSNotificationCenter defaultCenter] addObserver:self\n                                             selector:@selector(applicationDidBecomeActive)\n                                                 name:UIApplicationDidBecomeActiveNotification\n                                               object:nil];\n    [_registeredNotifications addObject:UIApplicationDidBecomeActiveNotification];\n\n    [[NSNotificationCenter defaultCenter] addObserver:self\n                                             selector:@selector(applicationWillResignActive)\n                                                 name:UIApplicationWillResignActiveNotification\n                                               object:nil];\n    [_registeredNotifications addObject:UIApplicationWillResignActiveNotification];\n\n    [[NSNotificationCenter defaultCenter] addObserver:self\n                                             selector:@selector(applicationDidEnterBackground)\n                                                 name:UIApplicationDidEnterBackgroundNotification\n                                               object:nil];\n    [_registeredNotifications addObject:UIApplicationDidEnterBackgroundNotification];\n\n    [[NSNotificationCenter defaultCenter] addObserver:self\n                                             selector:@selector(applicationWillTerminate)\n                                                 name:UIApplicationWillTerminateNotification\n                                               object:nil];\n    [_registeredNotifications addObject:UIApplicationWillTerminateNotification];\n}\n\n- (void)unregisterApplicationObservers\n{\n    for (NSString *name in _registeredNotifications) {\n        [[NSNotificationCenter defaultCenter] removeObserver:self\n                                                        name:name\n                                                      object:nil];\n    }\n}\n\n- (void)applicationWillEnterForeground\n{\n    NSLog(@\"IJKSDLGLView:applicationWillEnterForeground: %d\", (int)[UIApplication sharedApplication].applicationState);\n    [self setupGLOnce];\n    _applicationState = IJKSDLGLViewApplicationForegroundState;\n    [self toggleGLPaused:NO];\n}\n\n- (void)applicationDidBecomeActive\n{\n    NSLog(@\"IJKSDLGLView:applicationDidBecomeActive: %d\", (int)[UIApplication sharedApplication].applicationState);\n    [self setupGLOnce];\n    [self toggleGLPaused:NO];\n}\n\n- (void)applicationWillResignActive\n{\n    NSLog(@\"IJKSDLGLView:applicationWillResignActive: %d\", (int)[UIApplication sharedApplication].applicationState);\n    [self toggleGLPaused:YES];\n    glFinish();\n}\n\n- (void)applicationDidEnterBackground\n{\n    NSLog(@\"IJKSDLGLView:applicationDidEnterBackground: %d\", (int)[UIApplication sharedApplication].applicationState);\n    _applicationState = IJKSDLGLViewApplicationBackgroundState;\n    [self toggleGLPaused:YES];\n    glFinish();\n}\n\n- (void)applicationWillTerminate\n{\n    NSLog(@\"IJKSDLGLView:applicationWillTerminate: %d\", (int)[UIApplication sharedApplication].applicationState);\n    [self toggleGLPaused:YES];\n}\n\n#pragma mark snapshot\n\n- (UIImage*)snapshot\n{\n    [self lockGLActive];\n\n    UIImage *image = [self snapshotInternal];\n\n    [self unlockGLActive];\n\n    return image;\n}\n\n- (UIImage*)snapshotInternal\n{\n    if (isIOS7OrLater()) {\n        return [self snapshotInternalOnIOS7AndLater];\n    } else {\n        return [self snapshotInternalOnIOS6AndBefore];\n    }\n}\n\n- (UIImage*)snapshotInternalOnIOS7AndLater\n{\n    if (CGSizeEqualToSize(self.bounds.size, CGSizeZero)) {\n        return nil;\n    }\n    UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0);\n    // Render our snapshot into the image context\n    [self drawViewHierarchyInRect:self.bounds afterScreenUpdates:NO];\n\n    // Grab the image from the context\n    UIImage *complexViewImage = UIGraphicsGetImageFromCurrentImageContext();\n    // Finish using the context\n    UIGraphicsEndImageContext();\n\n    return complexViewImage;\n}\n\n- (UIImage*)snapshotInternalOnIOS6AndBefore\n{\n    EAGLContext *prevContext = [EAGLContext currentContext];\n    [EAGLContext setCurrentContext:_context];\n\n    GLint backingWidth, backingHeight;\n\n    // Bind the color renderbuffer used to render the OpenGL ES view\n    // If your application only creates a single color renderbuffer which is already bound at this point,\n    // this call is redundant, but it is needed if you're dealing with multiple renderbuffers.\n    // Note, replace \"viewRenderbuffer\" with the actual name of the renderbuffer object defined in your class.\n    glBindRenderbuffer(GL_RENDERBUFFER, _renderbuffer);\n\n    // Get the size of the backing CAEAGLLayer\n    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth);\n    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight);\n\n    NSInteger x = 0, y = 0, width = backingWidth, height = backingHeight;\n    NSInteger dataLength = width * height * 4;\n    GLubyte *data = (GLubyte*)malloc(dataLength * sizeof(GLubyte));\n\n    // Read pixel data from the framebuffer\n    glPixelStorei(GL_PACK_ALIGNMENT, 4);\n    glReadPixels((int)x, (int)y, (int)width, (int)height, GL_RGBA, GL_UNSIGNED_BYTE, data);\n\n    // Create a CGImage with the pixel data\n    // If your OpenGL ES content is opaque, use kCGImageAlphaNoneSkipLast to ignore the alpha channel\n    // otherwise, use kCGImageAlphaPremultipliedLast\n    CGDataProviderRef ref = CGDataProviderCreateWithData(NULL, data, dataLength, NULL);\n    CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();\n    CGImageRef iref = CGImageCreate(width, height, 8, 32, width * 4, colorspace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast,\n                                    ref, NULL, true, kCGRenderingIntentDefault);\n\n    [EAGLContext setCurrentContext:prevContext];\n\n    // OpenGL ES measures data in PIXELS\n    // Create a graphics context with the target size measured in POINTS\n    UIGraphicsBeginImageContext(CGSizeMake(width, height));\n\n    CGContextRef cgcontext = UIGraphicsGetCurrentContext();\n    // UIKit coordinate system is upside down to GL/Quartz coordinate system\n    // Flip the CGImage by rendering it to the flipped bitmap context\n    // The size of the destination area is measured in POINTS\n    CGContextSetBlendMode(cgcontext, kCGBlendModeCopy);\n    CGContextDrawImage(cgcontext, CGRectMake(0.0, 0.0, width, height), iref);\n\n    // Retrieve the UIImage from the current context\n    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();\n    UIGraphicsEndImageContext();\n\n    // Clean up\n    free(data);\n    CFRelease(ref);\n    CFRelease(colorspace);\n    CGImageRelease(iref);\n\n    return image;\n}\n\n- (void)setShouldLockWhileBeingMovedToWindow:(BOOL)shouldLockWhileBeingMovedToWindow\n{\n    _shouldLockWhileBeingMovedToWindow = shouldLockWhileBeingMovedToWindow;\n}\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLHudViewCell.h",
    "content": "//\n//  IJKSDLHudViewCell.h\n//  IJKMediaPlayer\n//\n//  Created by Zhang Rui on 15/12/14.\n//  Copyright © 2015年 bilibili. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface IJKSDLHudViewCell : UITableViewCell\n\n- (id)init;\n\n- (void)setHudValue:(NSString *)value forKey:(NSString *)key;\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLHudViewCell.m",
    "content": "//\n//  IJKSDLHudViewCell.m\n//  IJKMediaPlayer\n//\n//  Created by Zhang Rui on 15/12/14.\n//  Copyright © 2015年 bilibili. All rights reserved.\n//\n\n#import \"IJKSDLHudViewCell.h\"\n\n#define COLUMN_COUNT    2\n#define CELL_MARGIN     8\n\n@interface IJKSDLHudViewCell()\n\n@end\n\n@implementation IJKSDLHudViewCell\n{\n    UILabel *_column[COLUMN_COUNT];\n}\n\n- (id)init\n{\n    self = [super init];\n    if (self) {\n        self.backgroundColor = [UIColor clearColor];\n        self.contentView.backgroundColor = [UIColor clearColor];\n\n        for (int i = 0; i < COLUMN_COUNT; ++i) {\n            _column[i] = [[UILabel alloc] init];\n            _column[i].textColor = [UIColor whiteColor];\n            _column[i].font = [UIFont fontWithName:@\"Menlo\" size:9];\n            _column[i].adjustsFontSizeToFitWidth = YES;\n            _column[i].numberOfLines = 1;\n            _column[i].minimumScaleFactor = 0.5;\n            [self.contentView addSubview:_column[i]];\n        }\n    }\n    return self;\n}\n\n- (void)setHudValue:(NSString *)value forKey:(NSString *)key\n{\n    _column[0].text = key;\n    _column[1].text = value;\n}\n\n- (void)layoutSubviews\n{\n    [super layoutSubviews];\n\n    CGRect parentFrame = self.contentView.frame;\n    CGRect newFrame    = parentFrame;\n    CGFloat nextX      = CELL_MARGIN;\n\n    newFrame.origin.x   = nextX;\n    newFrame.size.width = parentFrame.size.width * 0.3;\n    _column[0].frame    = newFrame;\n    nextX               = newFrame.origin.x + newFrame.size.width + CELL_MARGIN;\n\n    newFrame.origin.x   = nextX;\n    newFrame.size.width = parentFrame.size.width - nextX - CELL_MARGIN;\n    _column[1].frame = newFrame;\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLHudViewController.h",
    "content": "//\n//  IJKSDLHudViewController.h\n//  IJKMediaPlayer\n//\n//  Created by Zhang Rui on 15/12/14.\n//  Copyright © 2015年 bilibili. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface IJKSDLHudViewController : UITableViewController\n\n- (id)init;\n\n- (void)setHudValue:(NSString *)value forKey:(NSString *)key;\n\n- (void)setRect:(CGRect) rect;\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLHudViewController.m",
    "content": "//\n//  IJKSDLHudViewController.m\n//  IJKMediaPlayer\n//\n//  Created by Zhang Rui on 15/12/14.\n//  Copyright © 2015年 bilibili. All rights reserved.\n//\n\n#import \"IJKSDLHudViewController.h\"\n#import \"IJKSDLHudViewCell.h\"\n\n@interface HudViewCellData : NSObject\n@property(nonatomic) NSString *key;\n@property(nonatomic) NSString *value;\n@end\n\n@implementation HudViewCellData\n@end\n\n@interface IJKSDLHudViewController() <UITableViewDataSource, UITableViewDelegate>\n\n@end\n\n@implementation IJKSDLHudViewController\n{\n    NSMutableDictionary *_keyIndexes;\n    NSMutableArray      *_hudDataArray;\n    CGRect _rect;\n}\n\n- (id)init\n{\n    self = [super init];\n    if (self) {\n        _keyIndexes = [[NSMutableDictionary alloc] init];\n        _hudDataArray = [[NSMutableArray alloc] init];\n\n        self.tableView.backgroundColor = [[UIColor alloc] initWithRed:.5f green:.5f blue:.5f alpha:.5f];\n        self.tableView.separatorStyle  = UITableViewCellSeparatorStyleNone;\n    }\n    return self;\n}\n\n- (void)setHudValue:(NSString *)value forKey:(NSString *)key\n{\n    HudViewCellData *data = nil;\n    NSNumber *index = [_keyIndexes objectForKey:key];\n    if (index == nil) {\n        data = [[HudViewCellData alloc] init];\n        data.key = key;\n        [_keyIndexes setObject:[NSNumber numberWithUnsignedInteger:_hudDataArray.count]\n                        forKey:key];\n        [_hudDataArray addObject:data];\n    } else {\n        data = [_hudDataArray objectAtIndex:[index unsignedIntegerValue]];\n    }\n\n    data.value = value;\n    [self.tableView reloadData];\n}\n\n#pragma mark UITableViewDataSource\n\n- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section\n{\n    assert(section == 0);\n    return _hudDataArray.count;\n}\n\n- (UITableViewCell *)tableView:(UITableView *)tableView\n         cellForRowAtIndexPath:(NSIndexPath *)indexPath\n{\n    assert(indexPath.section == 0);\n\n    IJKSDLHudViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@\"hud\"];\n    if (cell == nil) {\n        cell = [[IJKSDLHudViewCell alloc] init];\n    }\n\n    HudViewCellData *data = [_hudDataArray objectAtIndex:indexPath.item];\n\n    [cell setHudValue:data.value forKey:data.key];\n\n    return cell;\n}\n\n- (void)setRect:(CGRect) rect {\n    _rect = rect;\n}\n\n- (void)viewWillLayoutSubviews {\n    [super viewWillLayoutSubviews];\n\n    CGRect selfFrame = _rect;\n    CGRect newFrame  = selfFrame;\n\n    newFrame.size.width   = selfFrame.size.width * 1 / 3;\n    newFrame.origin.x     = selfFrame.size.width * 2 / 3;\n\n    newFrame.size.height  = selfFrame.size.height * 8 / 8;\n    newFrame.origin.y    += selfFrame.size.height * 0 / 8;\n\n    self.tableView.frame = newFrame;\n}\n\n#pragma mark UITableViewDelegate\n\n- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath\n{\n    return 16.f;\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/ijksdl_aout_ios_audiounit.h",
    "content": "/*\n * ijksdl_aout_ios_audiounit.h\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl/ijksdl_aout.h\"\n\nSDL_Aout *SDL_AoutIos_CreateForAudioUnit();\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/ijksdl_aout_ios_audiounit.m",
    "content": "/*\n * ijksdl_aout_ios_audiounit.m\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl_aout_ios_audiounit.h\"\n\n#include <stdbool.h>\n#include <assert.h>\n#include \"ijksdl/ijksdl_inc_internal.h\"\n#include \"ijksdl/ijksdl_thread.h\"\n#include \"ijksdl/ijksdl_aout_internal.h\"\n#import \"IJKSDLAudioUnitController.h\"\n#import \"IJKSDLAudioQueueController.h\"\n\n#define SDL_IOS_AUDIO_MAX_CALLBACKS_PER_SEC 15\n\nstruct SDL_Aout_Opaque {\n    IJKSDLAudioQueueController *aoutController;\n};\n\nstatic int aout_open_audio(SDL_Aout *aout, const SDL_AudioSpec *desired, SDL_AudioSpec *obtained)\n{\n    assert(desired);\n    SDLTRACE(\"aout_open_audio()\\n\");\n    SDL_Aout_Opaque *opaque = aout->opaque;\n\n    opaque->aoutController = [[IJKSDLAudioQueueController alloc] initWithAudioSpec:desired];\n    if (!opaque->aoutController) {\n        ALOGE(\"aout_open_audio_n: failed to new AudioTrcak()\\n\");\n        return -1;\n    }\n\n    if (obtained)\n        *obtained = opaque->aoutController.spec;\n\n    return 0;\n}\n\nstatic void aout_pause_audio(SDL_Aout *aout, int pause_on)\n{\n    SDLTRACE(\"aout_pause_audio(%d)\\n\", pause_on);\n    SDL_Aout_Opaque *opaque = aout->opaque;\n\n    if (pause_on) {\n        [opaque->aoutController pause];\n    } else {\n        [opaque->aoutController play];\n    }\n}\n\nstatic void aout_flush_audio(SDL_Aout *aout)\n{\n    SDLTRACE(\"aout_flush_audio()\\n\");\n    SDL_Aout_Opaque *opaque = aout->opaque;\n\n    [opaque->aoutController flush];\n}\n\nstatic void aout_close_audio(SDL_Aout *aout)\n{\n    SDLTRACE(\"aout_close_audio()\\n\");\n    SDL_Aout_Opaque *opaque = aout->opaque;\n\n    [opaque->aoutController close];\n}\n\nstatic void aout_set_playback_rate(SDL_Aout *aout, float playbackRate)\n{\n    SDLTRACE(\"aout_close_audio()\\n\");\n    SDL_Aout_Opaque *opaque = aout->opaque;\n\n    [opaque->aoutController setPlaybackRate:playbackRate];\n}\n\nstatic void aout_set_playback_volume(SDL_Aout *aout, float volume)\n{\n    SDLTRACE(\"aout_set_volume()\\n\");\n    SDL_Aout_Opaque *opaque = aout->opaque;\n\n    [opaque->aoutController setPlaybackVolume:volume];\n}\n\nstatic double auout_get_latency_seconds(SDL_Aout *aout)\n{\n    SDL_Aout_Opaque *opaque = aout->opaque;\n    return [opaque->aoutController get_latency_seconds];\n}\n\nstatic int aout_get_persecond_callbacks(SDL_Aout *aout)\n{\n    return SDL_IOS_AUDIO_MAX_CALLBACKS_PER_SEC;\n}\n\nstatic void aout_free_l(SDL_Aout *aout)\n{\n    if (!aout)\n        return;\n\n    aout_close_audio(aout);\n\n    SDL_Aout_Opaque *opaque = aout->opaque;\n    if (opaque) {\n        [opaque->aoutController release];\n        opaque->aoutController = nil;\n    }\n\n    SDL_Aout_FreeInternal(aout);\n}\n\nSDL_Aout *SDL_AoutIos_CreateForAudioUnit()\n{\n    SDL_Aout *aout = SDL_Aout_CreateInternal(sizeof(SDL_Aout_Opaque));\n    if (!aout)\n        return NULL;\n\n    // SDL_Aout_Opaque *opaque = aout->opaque;\n\n    aout->free_l = aout_free_l;\n    aout->open_audio  = aout_open_audio;\n    aout->pause_audio = aout_pause_audio;\n    aout->flush_audio = aout_flush_audio;\n    aout->close_audio = aout_close_audio;\n\n    aout->func_set_playback_rate = aout_set_playback_rate;\n    aout->func_set_playback_volume = aout_set_playback_volume;\n    aout->func_get_latency_seconds = auout_get_latency_seconds;\n    aout->func_get_audio_persecond_callbacks = aout_get_persecond_callbacks;\n    return aout;\n}\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/ijksdl_ios.h",
    "content": "/*\n * ijksdl_ios.h\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl/ijksdl.h\"\n#include \"ijksdl_aout_ios_audiounit.h\"\n#include \"ijksdl_vout_ios_gles2.h\"\n#import <UIKit/UIKit.h>\n\n\n\n#define SYSTEM_VERSION_EQUAL_TO(v)                  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)\n#define SYSTEM_VERSION_GREATER_THAN(v)              ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)\n#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)\n#define SYSTEM_VERSION_LESS_THAN(v)                 ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)\n#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v)     ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)\n\ninline static BOOL isIOS9OrLater()\n{\n    return SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@\"9.0\");\n}\n\ninline static BOOL isIOS8OrLater()\n{\n    return SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@\"8.0\");\n}\n\ninline static BOOL isIOS7OrLater()\n{\n    return SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@\"7.0\");\n}\n\ninline static BOOL isIOS6OrLater()\n{\n    return SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@\"6.0\");\n}\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/ijksdl_thread_ios.h",
    "content": "/*\n * ijksdl_thread_ios.h\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import <Foundation/Foundation.h>\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/ijksdl_thread_ios.m",
    "content": "/*\n * ijksdl_thread_ios.m\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import \"ijksdl_thread_ios.h\"\n#include \"ijksdl/ijksdl_thread.h\"\n\nstatic void *SDL_RunThread(void *data)\n{\n    @autoreleasepool {\n        SDL_Thread *thread = data;\n        pthread_setname_np(thread->name);\n        thread->retval = thread->func(thread->data);\n        return NULL;\n    }\n}\n\nSDL_Thread *SDL_CreateThreadEx(SDL_Thread *thread, int (*fn)(void *), void *data, const char *name)\n{\n    thread->func = fn;\n    thread->data = data;\n    strlcpy(thread->name, name, sizeof(thread->name) - 1);\n    int retval = pthread_create(&thread->id, NULL, SDL_RunThread, thread);\n    if (retval)\n        return NULL;\n\n    return thread;\n}\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/ijksdl_vout_ios_gles2.h",
    "content": "/*\n * ijksdl_vout_ios_gles2.h\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl/ijksdl_stdinc.h\"\n#include \"ijksdl/ijksdl_vout.h\"\n\n@class IJKSDLGLView;\n\nSDL_Vout *SDL_VoutIos_CreateForGLES2();\nvoid SDL_VoutIos_SetGLView(SDL_Vout *vout, IJKSDLGLView *view);\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/ijksdl_vout_ios_gles2.m",
    "content": "/*\n * ijksdl_vout_ios_gles2.c\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#import \"ijksdl_vout_ios_gles2.h\"\n\n#include <assert.h>\n#include \"ijksdl/ijksdl_vout.h\"\n#include \"ijksdl/ijksdl_vout_internal.h\"\n#include \"ijksdl/ffmpeg/ijksdl_vout_overlay_ffmpeg.h\"\n#include \"ijksdl_vout_overlay_videotoolbox.h\"\n#import \"IJKSDLGLView.h\"\n\ntypedef struct SDL_VoutSurface_Opaque {\n    SDL_Vout *vout;\n} SDL_VoutSurface_Opaque;\n\nstruct SDL_Vout_Opaque {\n    IJKSDLGLView *gl_view;\n};\n\nstatic SDL_VoutOverlay *vout_create_overlay_l(int width, int height, int frame_format, SDL_Vout *vout)\n{\n    switch (frame_format) {\n        case IJK_AV_PIX_FMT__VIDEO_TOOLBOX:\n            return SDL_VoutVideoToolBox_CreateOverlay(width, height, vout);\n        default:\n            return SDL_VoutFFmpeg_CreateOverlay(width, height, frame_format, vout);\n    }\n}\n\nstatic SDL_VoutOverlay *vout_create_overlay(int width, int height, int frame_format, SDL_Vout *vout)\n{\n    SDL_LockMutex(vout->mutex);\n    SDL_VoutOverlay *overlay = vout_create_overlay_l(width, height, frame_format, vout);\n    SDL_UnlockMutex(vout->mutex);\n    return overlay;\n}\n\nstatic void vout_free_l(SDL_Vout *vout)\n{\n    if (!vout)\n        return;\n\n    SDL_Vout_Opaque *opaque = vout->opaque;\n    if (opaque) {\n        if (opaque->gl_view) {\n            // TODO: post to MainThread?\n            [opaque->gl_view release];\n            opaque->gl_view = nil;\n        }\n    }\n\n    SDL_Vout_FreeInternal(vout);\n}\n\nstatic int vout_display_overlay_l(SDL_Vout *vout, SDL_VoutOverlay *overlay)\n{\n    SDL_Vout_Opaque *opaque = vout->opaque;\n    IJKSDLGLView *gl_view = opaque->gl_view;\n\n    if (!gl_view) {\n        ALOGE(\"vout_display_overlay_l: NULL gl_view\\n\");\n        return -1;\n    }\n\n    if (!overlay) {\n        ALOGE(\"vout_display_overlay_l: NULL overlay\\n\");\n        return -1;\n    }\n\n    if (overlay->w <= 0 || overlay->h <= 0) {\n        ALOGE(\"vout_display_overlay_l: invalid overlay dimensions(%d, %d)\\n\", overlay->w, overlay->h);\n        return -1;\n    }\n\n    if (gl_view.isThirdGLView) {\n        IJKOverlay ijk_overlay;\n\n        ijk_overlay.w = overlay->w;\n        ijk_overlay.h = overlay->h;\n        ijk_overlay.format = overlay->format;\n        ijk_overlay.planes = overlay->planes;\n        ijk_overlay.pitches = overlay->pitches;\n        ijk_overlay.pixels = overlay->pixels;\n        ijk_overlay.sar_num = overlay->sar_num;\n        ijk_overlay.sar_den = overlay->sar_den;\n#ifdef __APPLE__\n        if (ijk_overlay.format == SDL_FCC__VTB) {\n            ijk_overlay.pixel_buffer = SDL_VoutOverlayVideoToolBox_GetCVPixelBufferRef(overlay);\n        }\n#endif\n        if ([gl_view respondsToSelector:@selector(display_pixels:)]) {\n             [gl_view display_pixels:&ijk_overlay];\n        }\n    } else {\n        [gl_view display:overlay];\n    }\n    return 0;\n}\n\nstatic int vout_display_overlay(SDL_Vout *vout, SDL_VoutOverlay *overlay)\n{\n    @autoreleasepool {\n        SDL_LockMutex(vout->mutex);\n        int retval = vout_display_overlay_l(vout, overlay);\n        SDL_UnlockMutex(vout->mutex);\n        return retval;\n    }\n}\n\nSDL_Vout *SDL_VoutIos_CreateForGLES2()\n{\n    SDL_Vout *vout = SDL_Vout_CreateInternal(sizeof(SDL_Vout_Opaque));\n    if (!vout)\n        return NULL;\n\n    SDL_Vout_Opaque *opaque = vout->opaque;\n    opaque->gl_view = nil;\n    vout->create_overlay = vout_create_overlay;\n    vout->free_l = vout_free_l;\n    vout->display_overlay = vout_display_overlay;\n\n    return vout;\n}\n\nstatic void SDL_VoutIos_SetGLView_l(SDL_Vout *vout, IJKSDLGLView *view)\n{\n    SDL_Vout_Opaque *opaque = vout->opaque;\n\n    if (opaque->gl_view == view)\n        return;\n\n    if (opaque->gl_view) {\n        [opaque->gl_view release];\n        opaque->gl_view = nil;\n    }\n\n    if (view)\n        opaque->gl_view = [view retain];\n}\n\nvoid SDL_VoutIos_SetGLView(SDL_Vout *vout, IJKSDLGLView *view)\n{\n    SDL_LockMutex(vout->mutex);\n    SDL_VoutIos_SetGLView_l(vout, view);\n    SDL_UnlockMutex(vout->mutex);\n}\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/ijksdl_vout_overlay_videotoolbox.h",
    "content": "/*****************************************************************************\n * ijksdl_vout_overlay_videotoolbox.h\n *****************************************************************************\n *\n * copyright (c) 2014 ZhouQuan <zhouqicy@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef __IJKMediaPlayer__ijksdl_vout_overlay_videotoolbox__\n#define __IJKMediaPlayer__ijksdl_vout_overlay_videotoolbox__\n\n#import <CoreVideo/CoreVideo.h>\n#include \"ijksdl_stdinc.h\"\n#include \"ijksdl_vout.h\"\n#include \"ijksdl_inc_ffmpeg.h\"\n\nSDL_VoutOverlay *SDL_VoutVideoToolBox_CreateOverlay(int width, int height, SDL_Vout *vout);\nCVPixelBufferRef SDL_VoutOverlayVideoToolBox_GetCVPixelBufferRef(SDL_VoutOverlay *overlay);\n\n#endif\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/ijksdl_vout_overlay_videotoolbox.m",
    "content": "/*****************************************************************************\n * ijksdl_vout_overlay_videotoolbox.m\n *****************************************************************************\n *\n * copyright (c) 2014 ZhouQuan <zhouqicy@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"ijksdl_vout_overlay_videotoolbox.h\"\n\n#include <assert.h>\n#include \"ijksdl_stdinc.h\"\n#include \"ijksdl_mutex.h\"\n#include \"ijksdl_vout_internal.h\"\n#include \"ijksdl_video.h\"\n\n\nstruct SDL_VoutOverlay_Opaque {\n    SDL_mutex *mutex;\n    CVPixelBufferRef pixel_buffer;\n    Uint16 pitches[AV_NUM_DATA_POINTERS];\n    Uint8 *pixels[AV_NUM_DATA_POINTERS];\n};\n\n\nstatic void func_free_l(SDL_VoutOverlay *overlay)\n{\n    if (!overlay)\n        return;\n    SDL_VoutOverlay_Opaque *opaque = overlay->opaque;\n    if (!opaque)\n        return;\n    overlay->unref(overlay);\n    if (opaque->mutex)\n        SDL_DestroyMutex(opaque->mutex);\n\n    SDL_VoutOverlay_FreeInternal(overlay);\n}\n\nstatic int func_lock(SDL_VoutOverlay *overlay)\n{\n    SDL_VoutOverlay_Opaque *opaque = overlay->opaque;\n    return SDL_LockMutex(opaque->mutex);\n}\n\nstatic int func_unlock(SDL_VoutOverlay *overlay)\n{\n    SDL_VoutOverlay_Opaque *opaque = overlay->opaque;\n    return SDL_UnlockMutex(opaque->mutex);\n}\n\nstatic void func_unref(SDL_VoutOverlay *overlay)\n{\n    if (!overlay) {\n        return;\n    }\n    SDL_VoutOverlay_Opaque *opaque = overlay->opaque;\n    if (!opaque) {\n        return;\n    }\n\n    CVBufferRelease(opaque->pixel_buffer);\n\n    opaque->pixel_buffer = NULL;\n    overlay->pixels[0] = NULL;\n    overlay->pixels[1] = NULL;\n\n    return;\n}\n\nstatic int func_fill_frame(SDL_VoutOverlay *overlay, const AVFrame *frame)\n{\n    assert(frame->format == IJK_AV_PIX_FMT__VIDEO_TOOLBOX);\n\n    CVBufferRef pixel_buffer = CVBufferRetain(frame->opaque);\n    SDL_VoutOverlay_Opaque *opaque = overlay->opaque;\n    if (opaque->pixel_buffer != NULL) {\n        CVBufferRelease(opaque->pixel_buffer);\n    }\n    opaque->pixel_buffer = pixel_buffer;\n    overlay->format = SDL_FCC__VTB;\n    overlay->planes = 2;\n\n#if 1\n    if (CVPixelBufferLockBaseAddress(pixel_buffer, 0) != kCVReturnSuccess) {\n        overlay->pixels[0]  = NULL;\n        overlay->pixels[1]  = NULL;\n        overlay->pitches[0] = 0;\n        overlay->pitches[1] = 0;\n        overlay->w = 0;\n        overlay->h = 0;\n        CVBufferRelease(pixel_buffer);\n        opaque->pixel_buffer = NULL;\n        return -1;\n    }\n    // overlay->pixels[0]  = CVPixelBufferGetBaseAddressOfPlane(pixel_buffer, 0);\n    // overlay->pixels[1]  = CVPixelBufferGetBaseAddressOfPlane(pixel_buffer, 1);\n    overlay->pixels[0]  = NULL;\n    overlay->pixels[1]  = NULL;\n    overlay->pitches[0] = CVPixelBufferGetWidthOfPlane(pixel_buffer, 0);\n    overlay->pitches[1] = CVPixelBufferGetWidthOfPlane(pixel_buffer, 1);\n    CVPixelBufferUnlockBaseAddress(pixel_buffer, 0);\n#else\n    overlay->pixels[0]  = NULL;\n    overlay->pixels[1]  = NULL;\n    overlay->pitches[0] = 0;\n    overlay->pitches[1] = 0;\n#endif\n    overlay->is_private = 1;\n\n    overlay->w = (int)frame->width;\n    overlay->h = (int)frame->height;\n    return 0;\n}\n\nstatic SDL_Class g_vout_overlay_videotoolbox_class = {\n    .name = \"VideoToolboxVoutOverlay\",\n};\n\nstatic bool check_object(SDL_VoutOverlay* object, const char *func_name)\n{\n    if (!object || !object->opaque || !object->opaque_class) {\n        ALOGE(\"%s: invalid pipeline\\n\", func_name);\n        return false;\n    }\n\n    if (object->opaque_class != &g_vout_overlay_videotoolbox_class) {\n        ALOGE(\"%s.%s: unsupported method\\n\", object->opaque_class->name, func_name);\n        return false;\n    }\n\n    return true;\n}\n\nCVPixelBufferRef SDL_VoutOverlayVideoToolBox_GetCVPixelBufferRef(SDL_VoutOverlay *overlay)\n{\n    if (!check_object(overlay, __func__))\n        return NULL;\n\n    SDL_VoutOverlay_Opaque *opaque = overlay->opaque;\n    return opaque->pixel_buffer;\n}\n\nSDL_VoutOverlay *SDL_VoutVideoToolBox_CreateOverlay(int width, int height, SDL_Vout *display)\n{\n    SDLTRACE(\"SDL_VoutVideoToolBox_CreateOverlay(w=%d, h=%d, fmt=_VTB, dp=%p)\\n\",\n             width, height, display);\n    SDL_VoutOverlay *overlay = SDL_VoutOverlay_CreateInternal(sizeof(SDL_VoutOverlay_Opaque));\n    if (!overlay) {\n        ALOGE(\"overlay allocation failed\");\n        return NULL;\n    }\n    SDL_VoutOverlay_Opaque *opaque = overlay->opaque;\n    overlay->opaque_class = &g_vout_overlay_videotoolbox_class;\n    overlay->format     = SDL_FCC__VTB;\n    overlay->w          = width;\n    overlay->h          = height;\n    overlay->pitches    = opaque->pitches;\n    overlay->pixels     = opaque->pixels;\n    overlay->is_private = 1;\n\n    overlay->free_l             = func_free_l;\n    overlay->lock               = func_lock;\n    overlay->unlock             = func_unlock;\n    overlay->unref              = func_unref;\n    overlay->func_fill_frame    = func_fill_frame;\n\n    opaque->mutex = SDL_CreateMutex();\n    return overlay;\n}\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t33BA6FBF254BC4D7004EB9F2 /* ijklas.c in Sources */ = {isa = PBXBuildFile; fileRef = B4449BD5250095700074CEDC /* ijklas.c */; };\n\t\t33BA6FC0254BC4D9004EB9F2 /* ijklas.h in Headers */ = {isa = PBXBuildFile; fileRef = B4449BD4250095700074CEDC /* ijklas.h */; };\n\t\t33BA6FC1254BC4DC004EB9F2 /* cJSON.c in Sources */ = {isa = PBXBuildFile; fileRef = B417F8E124F7C56C00D159BB /* cJSON.c */; };\n\t\t33BA6FC2254BC4DE004EB9F2 /* cJSON.h in Headers */ = {isa = PBXBuildFile; fileRef = B417F8DB24F7C3B400D159BB /* cJSON.h */; };\n\t\t4D32BC811F906E3A00CE9F03 /* IJKSDLGLViewProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D32BC801F906E3600CE9F03 /* IJKSDLGLViewProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4D32BC821F906E3B00CE9F03 /* IJKSDLGLViewProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D32BC801F906E3600CE9F03 /* IJKSDLGLViewProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4DA7F6891F2B1E270032A499 /* ijkiourlhook.c in Sources */ = {isa = PBXBuildFile; fileRef = 4DA7F6881F2B1E270032A499 /* ijkiourlhook.c */; };\n\t\t4DA7F68A1F2B1E270032A499 /* ijkiourlhook.c in Sources */ = {isa = PBXBuildFile; fileRef = 4DA7F6881F2B1E270032A499 /* ijkiourlhook.c */; };\n\t\t5407EC291DF7F93B00457BFE /* IJKVideoToolBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 5407EC271DF7F93B00457BFE /* IJKVideoToolBox.h */; };\n\t\t5407EC2A1DF7F93B00457BFE /* IJKVideoToolBox.m in Sources */ = {isa = PBXBuildFile; fileRef = 5407EC281DF7F93B00457BFE /* IJKVideoToolBox.m */; };\n\t\t5407EC2D1DF81D2600457BFE /* IJKVideoToolBoxSync.h in Headers */ = {isa = PBXBuildFile; fileRef = 5407EC2B1DF81D2600457BFE /* IJKVideoToolBoxSync.h */; };\n\t\t5407EC2E1DF81D2600457BFE /* IJKVideoToolBoxSync.m in Sources */ = {isa = PBXBuildFile; fileRef = 5407EC2C1DF81D2600457BFE /* IJKVideoToolBoxSync.m */; };\n\t\t5450AFC41E63EA4300568494 /* IJKKVOController.m in Sources */ = {isa = PBXBuildFile; fileRef = E65DC3B819D93D5F004F8A08 /* IJKKVOController.m */; };\n\t\t5450AFC51E63EA4300568494 /* ijksdl_vout.c in Sources */ = {isa = PBXBuildFile; fileRef = E690401117EAFC6100CFD954 /* ijksdl_vout.c */; };\n\t\t5450AFC61E63EA4300568494 /* yuv444p10le.fsh.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C4598A1C7030B6004831EC /* yuv444p10le.fsh.c */; };\n\t\t5450AFC71E63EA4300568494 /* allformats.c in Sources */ = {isa = PBXBuildFile; fileRef = E69BE54A1B93FED300AFBA3F /* allformats.c */; };\n\t\t5450AFC81E63EA4300568494 /* ffpipenode_ffplay_vdec.c in Sources */ = {isa = PBXBuildFile; fileRef = E67B91B41A3801E600717EA9 /* ffpipenode_ffplay_vdec.c */; };\n\t\t5450AFC91E63EA4300568494 /* renderer_yuv420p.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C4598D1C7030B6004831EC /* renderer_yuv420p.c */; };\n\t\t5450AFCA1E63EA4300568494 /* ijkthreadpool.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A431E15287D00309DD5 /* ijkthreadpool.c */; };\n\t\t5450AFCB1E63EA4300568494 /* IJKAVMoviePlayerController.m in Sources */ = {isa = PBXBuildFile; fileRef = E67C4E0719D15EEA00415CEE /* IJKAVMoviePlayerController.m */; };\n\t\t5450AFCC1E63EA4300568494 /* IJKFFMoviePlayerDef.m in Sources */ = {isa = PBXBuildFile; fileRef = E6F727BA17F2D9D30043623F /* IJKFFMoviePlayerDef.m */; };\n\t\t5450AFCD1E63EA4300568494 /* ijkplayer_ios.m in Sources */ = {isa = PBXBuildFile; fileRef = E66F8E0117EFEEA400354D80 /* ijkplayer_ios.m */; settings = {COMPILER_FLAGS = \"-fno-objc-arc\"; }; };\n\t\t5450AFCE1E63EA4300568494 /* ffpipeline_ios.c in Sources */ = {isa = PBXBuildFile; fileRef = 454316201A66493700676070 /* ffpipeline_ios.c */; };\n\t\t5450AFCF1E63EA4300568494 /* ijkioprotocol.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A301E1526F800309DD5 /* ijkioprotocol.c */; };\n\t\t5450AFD01E63EA4300568494 /* ijksdl_vout_dummy.c in Sources */ = {isa = PBXBuildFile; fileRef = E63FC27417F013DE003551EB /* ijksdl_vout_dummy.c */; };\n\t\t5450AFD11E63EA4300568494 /* renderer_yuv420sp.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459CA1C70967F004831EC /* renderer_yuv420sp.c */; };\n\t\t5450AFD21E63EA4300568494 /* yuv420p.fsh.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459891C7030B6004831EC /* yuv420p.fsh.c */; };\n\t\t5450AFD31E63EA4300568494 /* ijksdl_error.c in Sources */ = {isa = PBXBuildFile; fileRef = E690400417EAFC6100CFD954 /* ijksdl_error.c */; };\n\t\t5450AFD41E63EA4300568494 /* IJKDeviceModel.m in Sources */ = {isa = PBXBuildFile; fileRef = E607FFDF1B7B60F9005F11A6 /* IJKDeviceModel.m */; };\n\t\t5450AFD51E63EA4300568494 /* ijkiocache.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A2C1E1526F800309DD5 /* ijkiocache.c */; };\n\t\t5450AFD61E63EA4300568494 /* ijksdl_egl.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459B81C706A13004831EC /* ijksdl_egl.c */; };\n\t\t5450AFD71E63EA4300568494 /* ijkio.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A291E1526F800309DD5 /* ijkio.c */; };\n\t\t5450AFD81E63EA4300568494 /* IJKAudioKit.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92A2187810C5009EAB56 /* IJKAudioKit.m */; };\n\t\t5450AFD91E63EA4300568494 /* IJKMPMoviePlayerController.m in Sources */ = {isa = PBXBuildFile; fileRef = E66F8DC017EEC65200354D80 /* IJKMPMoviePlayerController.m */; };\n\t\t5450AFDA1E63EA4300568494 /* IJKSDLHudViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = E68B7ACE1C1E97B0001DE241 /* IJKSDLHudViewCell.m */; };\n\t\t5450AFDB1E63EA4300568494 /* ijksdl_vout_overlay_videotoolbox.m in Sources */ = {isa = PBXBuildFile; fileRef = 45DB4AA81A5D52AE005CAD41 /* ijksdl_vout_overlay_videotoolbox.m */; };\n\t\t5450AFDC1E63EA4300568494 /* ff_ffpipenode.c in Sources */ = {isa = PBXBuildFile; fileRef = E67B91AD1A3801DB00717EA9 /* ff_ffpipenode.c */; };\n\t\t5450AFDD1E63EA4300568494 /* ijksdl_stdinc.c in Sources */ = {isa = PBXBuildFile; fileRef = E690400A17EAFC6100CFD954 /* ijksdl_stdinc.c */; };\n\t\t5450AFDE1E63EA4300568494 /* IJKVideoToolBox.m in Sources */ = {isa = PBXBuildFile; fileRef = 5407EC281DF7F93B00457BFE /* IJKVideoToolBox.m */; };\n\t\t5450AFDF1E63EA4300568494 /* ijksegment.c in Sources */ = {isa = PBXBuildFile; fileRef = 54A029B41D4700E6001C61C1 /* ijksegment.c */; };\n\t\t5450AFE01E63EA4300568494 /* IJKMediaUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = E6716E4A1807E5FC00B3FBC1 /* IJKMediaUtils.m */; };\n\t\t5450AFE11E63EA4300568494 /* common.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459871C7030B6004831EC /* common.c */; };\n\t\t5450AFE21E63EA4300568494 /* ijksdl_aout_ios_audiounit.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92A71878230C009EAB56 /* ijksdl_aout_ios_audiounit.m */; settings = {COMPILER_FLAGS = \"-fno-objc-arc\"; }; };\n\t\t5450AFE31E63EA4300568494 /* ijklivehook.c in Sources */ = {isa = PBXBuildFile; fileRef = E69BE5701B946FF600AFBA3F /* ijklivehook.c */; };\n\t\t5450AFE41E63EA4300568494 /* ijkurlhook.c in Sources */ = {isa = PBXBuildFile; fileRef = 54A029B51D4700E6001C61C1 /* ijkurlhook.c */; };\n\t\t5450AFE51E63EA4300568494 /* IJKVideoToolBoxSync.m in Sources */ = {isa = PBXBuildFile; fileRef = 5407EC2C1DF81D2600457BFE /* IJKVideoToolBoxSync.m */; };\n\t\t5450AFE61E63EA4300568494 /* IJKMediaPlayback.m in Sources */ = {isa = PBXBuildFile; fileRef = E6F727C117F7C9B90043623F /* IJKMediaPlayback.m */; };\n\t\t5450AFE71E63EA4300568494 /* ijkdict.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A3D1E15287D00309DD5 /* ijkdict.c */; settings = {COMPILER_FLAGS = \"-w\"; }; };\n\t\t5450AFE81E63EA4300568494 /* ff_ffpipeline.c in Sources */ = {isa = PBXBuildFile; fileRef = E67B91AB1A3801DB00717EA9 /* ff_ffpipeline.c */; };\n\t\t5450AFE91E63EA4300568494 /* IJKSDLAudioKit.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92C718782770009EAB56 /* IJKSDLAudioKit.m */; };\n\t\t5450AFEA1E63EA4300568494 /* mvp.vsh.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459911C7030B6004831EC /* mvp.vsh.c */; };\n\t\t5450AFEB1E63EA4300568494 /* NSString+IJKMedia.m in Sources */ = {isa = PBXBuildFile; fileRef = E698089A1C7EB13A0048A46C /* NSString+IJKMedia.m */; };\n\t\t5450AFEC1E63EA4300568494 /* ijksdl_vout_overlay_ffmpeg.c in Sources */ = {isa = PBXBuildFile; fileRef = E6903FFB17EAFC6100CFD954 /* ijksdl_vout_overlay_ffmpeg.c */; };\n\t\t5450AFED1E63EA4300568494 /* ijksdl_mutex.c in Sources */ = {isa = PBXBuildFile; fileRef = E690400817EAFC6100CFD954 /* ijksdl_mutex.c */; };\n\t\t5450AFEE1E63EA4300568494 /* ijktree.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A451E15287D00309DD5 /* ijktree.c */; };\n\t\t5450AFEF1E63EA4300568494 /* IJKSDLAudioQueueController.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92C11878236A009EAB56 /* IJKSDLAudioQueueController.m */; };\n\t\t5450AFF01E63EA4300568494 /* ijksdl_thread.c in Sources */ = {isa = PBXBuildFile; fileRef = E690400C17EAFC6100CFD954 /* ijksdl_thread.c */; };\n\t\t5450AFF11E63EA4300568494 /* yuv420sp.fsh.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459C61C7095E5004831EC /* yuv420sp.fsh.c */; };\n\t\t5450AFF21E63EA4300568494 /* ff_ffplay.c in Sources */ = {isa = PBXBuildFile; fileRef = E6903FDB17EAFC6100CFD954 /* ff_ffplay.c */; };\n\t\t5450AFF31E63EA4300568494 /* ijksdl_aout.c in Sources */ = {isa = PBXBuildFile; fileRef = E6903FFF17EAFC6100CFD954 /* ijksdl_aout.c */; };\n\t\t5450AFF41E63EA4300568494 /* color.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459861C7030B6004831EC /* color.c */; };\n\t\t5450AFF51E63EA4300568494 /* ijksdl_audio.c in Sources */ = {isa = PBXBuildFile; fileRef = E63FC27017F01143003551EB /* ijksdl_audio.c */; };\n\t\t5450AFF61E63EA4300568494 /* ijksdl_thread_ios.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92AA1878230C009EAB56 /* ijksdl_thread_ios.m */; };\n\t\t5450AFF71E63EA4300568494 /* ijkmeta.c in Sources */ = {isa = PBXBuildFile; fileRef = E6FAD9551A515CE300725002 /* ijkmeta.c */; };\n\t\t5450AFF81E63EA4300568494 /* ijkasync.c in Sources */ = {isa = PBXBuildFile; fileRef = 54A029B11D4700E6001C61C1 /* ijkasync.c */; };\n\t\t5450AFF91E63EA4300568494 /* renderer_yuv420sp_vtb.m in Sources */ = {isa = PBXBuildFile; fileRef = E6E1B9A71C741F72000C6C72 /* renderer_yuv420sp_vtb.m */; };\n\t\t5450AFFA1E63EA4300568494 /* ijkutils.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A471E15287D00309DD5 /* ijkutils.c */; };\n\t\t5450AFFB1E63EA4300568494 /* IJKSDLGLView.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92B71878230C009EAB56 /* IJKSDLGLView.m */; };\n\t\t5450AFFC1E63EA4300568494 /* ijksdl_timer.c in Sources */ = {isa = PBXBuildFile; fileRef = E690400E17EAFC6100CFD954 /* ijksdl_timer.c */; };\n\t\t5450AFFD1E63EA4300568494 /* ijkfifo.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A3F1E15287D00309DD5 /* ijkfifo.c */; settings = {COMPILER_FLAGS = \"-w\"; }; };\n\t\t5450AFFE1E63EA4300568494 /* shader.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C4598F1C7030B6004831EC /* shader.c */; };\n\t\t5450AFFF1E63EA4300568494 /* ijkioffio.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A2D1E1526F800309DD5 /* ijkioffio.c */; };\n\t\t5450B0001E63EA4300568494 /* renderer.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C4598C1C7030B6004831EC /* renderer.c */; };\n\t\t5450B0011E63EA4300568494 /* ijkioapplication.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A2A1E1526F800309DD5 /* ijkioapplication.c */; };\n\t\t5450B0021E63EA4300568494 /* ijkiomanager.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A2E1E1526F800309DD5 /* ijkiomanager.c */; };\n\t\t5450B0031E63EA4300568494 /* ijkplayer.c in Sources */ = {isa = PBXBuildFile; fileRef = E66F8DEF17EFEA9400354D80 /* ijkplayer.c */; };\n\t\t5450B0041E63EA4300568494 /* IJKFFOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = E62139BD180FA89A00553533 /* IJKFFOptions.m */; };\n\t\t5450B0051E63EA4300568494 /* IJKSDLAudioUnitController.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92AE1878230C009EAB56 /* IJKSDLAudioUnitController.m */; };\n\t\t5450B0061E63EA4300568494 /* IJKFFMonitor.m in Sources */ = {isa = PBXBuildFile; fileRef = E6DBD3881C8941EB0058E4FB /* IJKFFMonitor.m */; };\n\t\t5450B0071E63EA4300568494 /* IJKFFMoviePlayerController.m in Sources */ = {isa = PBXBuildFile; fileRef = E66F8DE617EFD9C300354D80 /* IJKFFMoviePlayerController.m */; };\n\t\t5450B0081E63EA4300568494 /* IJKNotificationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E698089F1C7EB2040048A46C /* IJKNotificationManager.m */; };\n\t\t5450B0091E63EA4300568494 /* IJKMediaModule.m in Sources */ = {isa = PBXBuildFile; fileRef = E672D6F218D3445100C51FF9 /* IJKMediaModule.m */; };\n\t\t5450B00A1E63EA4300568494 /* ff_cmdutils.c in Sources */ = {isa = PBXBuildFile; fileRef = E6903FD517EAFC6100CFD954 /* ff_cmdutils.c */; };\n\t\t5450B00B1E63EA4300568494 /* IJKVideoToolBoxAsync.m in Sources */ = {isa = PBXBuildFile; fileRef = 4543162A1A66497900676070 /* IJKVideoToolBoxAsync.m */; };\n\t\t5450B00C1E63EA4300568494 /* renderer_yuv444p10le.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C4598E1C7030B6004831EC /* renderer_yuv444p10le.c */; };\n\t\t5450B00D1E63EA4300568494 /* ijkstl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A411E15287D00309DD5 /* ijkstl.cpp */; settings = {COMPILER_FLAGS = \"-w\"; }; };\n\t\t5450B00E1E63EA4300568494 /* image_convert.c in Sources */ = {isa = PBXBuildFile; fileRef = E6903FF117EAFC6100CFD954 /* image_convert.c */; };\n\t\t5450B00F1E63EA4300568494 /* rgb.fsh.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459C21C708E60004831EC /* rgb.fsh.c */; };\n\t\t5450B0101E63EA4300568494 /* ffpipenode_ios_videotoolbox_vdec.m in Sources */ = {isa = PBXBuildFile; fileRef = 454316231A66493700676070 /* ffpipenode_ios_videotoolbox_vdec.m */; };\n\t\t5450B0111E63EA4300568494 /* IJKAVPlayerLayerView.m in Sources */ = {isa = PBXBuildFile; fileRef = E67C4E0419D15B3200415CEE /* IJKAVPlayerLayerView.m */; };\n\t\t5450B0121E63EA4300568494 /* IJKSDLHudViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E68B7AC41C1E7F20001DE241 /* IJKSDLHudViewController.m */; };\n\t\t5450B0131E63EA4300568494 /* ijksdl_vout_ios_gles2.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92AC1878230C009EAB56 /* ijksdl_vout_ios_gles2.m */; settings = {COMPILER_FLAGS = \"-fno-objc-arc\"; }; };\n\t\t5450B0141E63EA4300568494 /* ijklongurl.c in Sources */ = {isa = PBXBuildFile; fileRef = 54A029B31D4700E6001C61C1 /* ijklongurl.c */; };\n\t\t5450B0151E63EA4300568494 /* renderer_rgb.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459BE1C708CAF004831EC /* renderer_rgb.c */; };\n\t\t5450B0161E63EA4300568494 /* ffpipeline_ffplay.c in Sources */ = {isa = PBXBuildFile; fileRef = E67B91B21A3801E600717EA9 /* ffpipeline_ffplay.c */; };\n\t\t5450B0181E63EA4300568494 /* libavcodec.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E653C6EF1BCE5A750016835A /* libavcodec.a */; };\n\t\t5450B0191E63EA4300568494 /* libavfilter.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E653C6F01BCE5A750016835A /* libavfilter.a */; };\n\t\t5450B01A1E63EA4300568494 /* libavformat.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E653C6F11BCE5A750016835A /* libavformat.a */; };\n\t\t5450B01B1E63EA4300568494 /* libavutil.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E653C6F21BCE5A750016835A /* libavutil.a */; };\n\t\t5450B01C1E63EA4300568494 /* libswresample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E653C6F31BCE5A750016835A /* libswresample.a */; };\n\t\t5450B01D1E63EA4300568494 /* libswscale.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E653C6F41BCE5A750016835A /* libswscale.a */; };\n\t\t5450B01F1E63EA4300568494 /* IJKFFMonitor.h in Headers */ = {isa = PBXBuildFile; fileRef = E6DBD3871C8941EB0058E4FB /* IJKFFMonitor.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t5450B0201E63EA4300568494 /* ijkiourl.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A321E1526F800309DD5 /* ijkiourl.h */; };\n\t\t5450B0211E63EA4300568494 /* IJKFFMoviePlayerController.h in Headers */ = {isa = PBXBuildFile; fileRef = E66F8DE517EFD9C300354D80 /* IJKFFMoviePlayerController.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t5450B0221E63EA4300568494 /* IJKSDLHudViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = E68B7AC31C1E7F20001DE241 /* IJKSDLHudViewController.h */; };\n\t\t5450B0231E63EA4300568494 /* IJKFFOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = E62139BC180FA89A00553533 /* IJKFFOptions.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t5450B0241E63EA4300568494 /* ijkutils.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A481E15287D00309DD5 /* ijkutils.h */; };\n\t\t5450B0251E63EA4300568494 /* ijkdict.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A3E1E15287D00309DD5 /* ijkdict.h */; };\n\t\t5450B0261E63EA4300568494 /* IJKAVMoviePlayerController.h in Headers */ = {isa = PBXBuildFile; fileRef = E67C4E0619D15EEA00415CEE /* IJKAVMoviePlayerController.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t5450B0271E63EA4300568494 /* ijksdl_gles2.h in Headers */ = {isa = PBXBuildFile; fileRef = E6C459831C7030AA004831EC /* ijksdl_gles2.h */; };\n\t\t5450B0281E63EA4300568494 /* ijksdl_egl.h in Headers */ = {isa = PBXBuildFile; fileRef = E6C459B91C706A13004831EC /* ijksdl_egl.h */; };\n\t\t5450B0291E63EA4300568494 /* ff_ffplay_options.h in Headers */ = {isa = PBXBuildFile; fileRef = E6C459BC1C7089AB004831EC /* ff_ffplay_options.h */; };\n\t\t5450B02B1E63EA4300568494 /* IJKKVOController.h in Headers */ = {isa = PBXBuildFile; fileRef = E65DC3B719D93D5F004F8A08 /* IJKKVOController.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t5450B02C1E63EA4300568494 /* IJKNotificationManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E698089E1C7EB2040048A46C /* IJKNotificationManager.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t5450B02D1E63EA4300568494 /* ijkthreadpool.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A441E15287D00309DD5 /* ijkthreadpool.h */; };\n\t\t5450B02E1E63EA4300568494 /* ijkiomanager.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A2F1E1526F800309DD5 /* ijkiomanager.h */; };\n\t\t5450B02F1E63EA4300568494 /* ijkstl.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A421E15287D00309DD5 /* ijkstl.h */; };\n\t\t5450B0301E63EA4300568494 /* IJKMediaModule.h in Headers */ = {isa = PBXBuildFile; fileRef = E672D6F118D3445100C51FF9 /* IJKMediaModule.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t5450B0311E63EA4300568494 /* ijkfifo.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A401E15287D00309DD5 /* ijkfifo.h */; };\n\t\t5450B0321E63EA4300568494 /* ijktree.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A461E15287D00309DD5 /* ijktree.h */; };\n\t\t5450B0331E63EA4300568494 /* opt.h in Headers */ = {isa = PBXBuildFile; fileRef = E69BE54F1B93FED300AFBA3F /* opt.h */; };\n\t\t5450B0341E63EA4300568494 /* ijkioapplication.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A2B1E1526F800309DD5 /* ijkioapplication.h */; };\n\t\t5450B0351E63EA4300568494 /* ijkioprotocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A311E1526F800309DD5 /* ijkioprotocol.h */; };\n\t\t5450B0361E63EA4300568494 /* IJKMediaPlayback.h in Headers */ = {isa = PBXBuildFile; fileRef = E6903EC117EAF6C500CFD954 /* IJKMediaPlayback.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t5450B0371E63EA4300568494 /* IJKMediaPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = E66F8DC217EECB1E00354D80 /* IJKMediaPlayer.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t5450B0381E63EA4300568494 /* internal.h in Headers */ = {isa = PBXBuildFile; fileRef = E6C4598B1C7030B6004831EC /* internal.h */; };\n\t\t5450B0391E63EA4300568494 /* IJKVideoToolBoxSync.h in Headers */ = {isa = PBXBuildFile; fileRef = 5407EC2B1DF81D2600457BFE /* IJKVideoToolBoxSync.h */; };\n\t\t5450B03A1E63EA4300568494 /* IJKMPMoviePlayerController.h in Headers */ = {isa = PBXBuildFile; fileRef = E66F8DBF17EEC65200354D80 /* IJKMPMoviePlayerController.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t5450B03B1E63EA4300568494 /* ijkavformat.h in Headers */ = {isa = PBXBuildFile; fileRef = 54A029B21D4700E6001C61C1 /* ijkavformat.h */; };\n\t\t5450B03C1E63EA4300568494 /* IJKSDLHudViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = E68B7ACD1C1E97B0001DE241 /* IJKSDLHudViewCell.h */; };\n\t\t5450B03D1E63EA4300568494 /* IJKVideoToolBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 5407EC271DF7F93B00457BFE /* IJKVideoToolBox.h */; };\n\t\t5450B03E1E63EA4300568494 /* NSString+IJKMedia.h in Headers */ = {isa = PBXBuildFile; fileRef = E69808991C7EB13A0048A46C /* NSString+IJKMedia.h */; };\n\t\t5450B0451E63EAB700568494 /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5450AF8B1E63E59300568494 /* libcrypto.a */; };\n\t\t5450B0461E63EAB700568494 /* libssl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5450AF8C1E63E59300568494 /* libssl.a */; };\n\t\t5450B0471E63EABC00568494 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 5450AF8F1E63E59800568494 /* libz.tbd */; };\n\t\t549385C41E640456001AE08D /* IJKMediaFrameworkWithSSL.h in Headers */ = {isa = PBXBuildFile; fileRef = 5450AF9B1E63E65700568494 /* IJKMediaFrameworkWithSSL.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t54A029B61D4700E6001C61C1 /* ijkasync.c in Sources */ = {isa = PBXBuildFile; fileRef = 54A029B11D4700E6001C61C1 /* ijkasync.c */; };\n\t\t54A029B71D4700E6001C61C1 /* ijkavformat.h in Headers */ = {isa = PBXBuildFile; fileRef = 54A029B21D4700E6001C61C1 /* ijkavformat.h */; };\n\t\t54A029B81D4700E6001C61C1 /* ijklongurl.c in Sources */ = {isa = PBXBuildFile; fileRef = 54A029B31D4700E6001C61C1 /* ijklongurl.c */; };\n\t\t54A029B91D4700E6001C61C1 /* ijksegment.c in Sources */ = {isa = PBXBuildFile; fileRef = 54A029B41D4700E6001C61C1 /* ijksegment.c */; };\n\t\t54A029BA1D4700E6001C61C1 /* ijkurlhook.c in Sources */ = {isa = PBXBuildFile; fileRef = 54A029B51D4700E6001C61C1 /* ijkurlhook.c */; };\n\t\t54CF8A331E1526F800309DD5 /* ijkio.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A291E1526F800309DD5 /* ijkio.c */; };\n\t\t54CF8A341E1526F800309DD5 /* ijkioapplication.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A2A1E1526F800309DD5 /* ijkioapplication.c */; };\n\t\t54CF8A351E1526F800309DD5 /* ijkioapplication.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A2B1E1526F800309DD5 /* ijkioapplication.h */; };\n\t\t54CF8A361E1526F800309DD5 /* ijkiocache.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A2C1E1526F800309DD5 /* ijkiocache.c */; };\n\t\t54CF8A371E1526F800309DD5 /* ijkioffio.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A2D1E1526F800309DD5 /* ijkioffio.c */; };\n\t\t54CF8A381E1526F800309DD5 /* ijkiomanager.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A2E1E1526F800309DD5 /* ijkiomanager.c */; };\n\t\t54CF8A391E1526F800309DD5 /* ijkiomanager.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A2F1E1526F800309DD5 /* ijkiomanager.h */; };\n\t\t54CF8A3A1E1526F800309DD5 /* ijkioprotocol.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A301E1526F800309DD5 /* ijkioprotocol.c */; };\n\t\t54CF8A3B1E1526F800309DD5 /* ijkioprotocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A311E1526F800309DD5 /* ijkioprotocol.h */; };\n\t\t54CF8A3C1E1526F800309DD5 /* ijkiourl.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A321E1526F800309DD5 /* ijkiourl.h */; };\n\t\t54CF8A491E15287D00309DD5 /* ijkdict.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A3D1E15287D00309DD5 /* ijkdict.c */; settings = {COMPILER_FLAGS = \"-w\"; }; };\n\t\t54CF8A4A1E15287D00309DD5 /* ijkdict.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A3E1E15287D00309DD5 /* ijkdict.h */; };\n\t\t54CF8A4B1E15287D00309DD5 /* ijkfifo.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A3F1E15287D00309DD5 /* ijkfifo.c */; settings = {COMPILER_FLAGS = \"-w\"; }; };\n\t\t54CF8A4C1E15287D00309DD5 /* ijkfifo.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A401E15287D00309DD5 /* ijkfifo.h */; };\n\t\t54CF8A4D1E15287D00309DD5 /* ijkstl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A411E15287D00309DD5 /* ijkstl.cpp */; settings = {COMPILER_FLAGS = \"-w\"; }; };\n\t\t54CF8A4E1E15287D00309DD5 /* ijkstl.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A421E15287D00309DD5 /* ijkstl.h */; };\n\t\t54CF8A4F1E15287D00309DD5 /* ijkthreadpool.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A431E15287D00309DD5 /* ijkthreadpool.c */; };\n\t\t54CF8A501E15287D00309DD5 /* ijkthreadpool.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A441E15287D00309DD5 /* ijkthreadpool.h */; };\n\t\t54CF8A511E15287D00309DD5 /* ijktree.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A451E15287D00309DD5 /* ijktree.c */; };\n\t\t54CF8A521E15287D00309DD5 /* ijktree.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A461E15287D00309DD5 /* ijktree.h */; };\n\t\t54CF8A531E15287D00309DD5 /* ijkutils.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A471E15287D00309DD5 /* ijkutils.c */; };\n\t\t54CF8A541E15287D00309DD5 /* ijkutils.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A481E15287D00309DD5 /* ijkutils.h */; };\n\t\tB417F8DE24F7C3B500D159BB /* cJSON.h in Headers */ = {isa = PBXBuildFile; fileRef = B417F8DB24F7C3B400D159BB /* cJSON.h */; };\n\t\tB417F8E224F7C56C00D159BB /* cJSON.c in Sources */ = {isa = PBXBuildFile; fileRef = B417F8E124F7C56C00D159BB /* cJSON.c */; };\n\t\tB4449BD6250095700074CEDC /* ijklas.h in Headers */ = {isa = PBXBuildFile; fileRef = B4449BD4250095700074CEDC /* ijklas.h */; };\n\t\tB4449BD7250095700074CEDC /* ijklas.c in Sources */ = {isa = PBXBuildFile; fileRef = B4449BD5250095700074CEDC /* ijklas.c */; };\n\t\tE607FFE11B7B62E3005F11A6 /* IJKDeviceModel.m in Sources */ = {isa = PBXBuildFile; fileRef = E607FFDF1B7B60F9005F11A6 /* IJKDeviceModel.m */; };\n\t\tE653C6F61BCE5A750016835A /* libavcodec.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E653C6EF1BCE5A750016835A /* libavcodec.a */; };\n\t\tE653C6F81BCE5A750016835A /* libavfilter.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E653C6F01BCE5A750016835A /* libavfilter.a */; };\n\t\tE653C6FA1BCE5A750016835A /* libavformat.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E653C6F11BCE5A750016835A /* libavformat.a */; };\n\t\tE653C6FC1BCE5A750016835A /* libavutil.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E653C6F21BCE5A750016835A /* libavutil.a */; };\n\t\tE653C6FE1BCE5A750016835A /* libswresample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E653C6F31BCE5A750016835A /* libswresample.a */; };\n\t\tE653C7001BCE5A750016835A /* libswscale.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E653C6F41BCE5A750016835A /* libswscale.a */; };\n\t\tE654EA8F1B6B27E600B0F2D0 /* IJKMediaFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = E654EA8E1B6B27E600B0F2D0 /* IJKMediaFramework.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\tE654EA951B6B27E600B0F2D0 /* IJKMediaFramework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E654EA8A1B6B27E600B0F2D0 /* IJKMediaFramework.framework */; };\n\t\tE654EA9C1B6B27E600B0F2D0 /* IJKMediaFrameworkTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E654EA9B1B6B27E600B0F2D0 /* IJKMediaFrameworkTests.m */; };\n\t\tE654EAA31B6B283700B0F2D0 /* IJKAudioKit.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92A2187810C5009EAB56 /* IJKAudioKit.m */; };\n\t\tE654EAA41B6B283700B0F2D0 /* IJKMediaModule.m in Sources */ = {isa = PBXBuildFile; fileRef = E672D6F218D3445100C51FF9 /* IJKMediaModule.m */; };\n\t\tE654EAA51B6B283700B0F2D0 /* IJKMediaPlayback.m in Sources */ = {isa = PBXBuildFile; fileRef = E6F727C117F7C9B90043623F /* IJKMediaPlayback.m */; };\n\t\tE654EAA61B6B283700B0F2D0 /* IJKMediaUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = E6716E4A1807E5FC00B3FBC1 /* IJKMediaUtils.m */; };\n\t\tE654EAA71B6B283700B0F2D0 /* IJKKVOController.m in Sources */ = {isa = PBXBuildFile; fileRef = E65DC3B819D93D5F004F8A08 /* IJKKVOController.m */; };\n\t\tE654EAA81B6B283D00B0F2D0 /* IJKAVPlayerLayerView.m in Sources */ = {isa = PBXBuildFile; fileRef = E67C4E0419D15B3200415CEE /* IJKAVPlayerLayerView.m */; };\n\t\tE654EAA91B6B283D00B0F2D0 /* IJKAVMoviePlayerController.m in Sources */ = {isa = PBXBuildFile; fileRef = E67C4E0719D15EEA00415CEE /* IJKAVMoviePlayerController.m */; };\n\t\tE654EAAA1B6B284300B0F2D0 /* IJKMPMoviePlayerController.m in Sources */ = {isa = PBXBuildFile; fileRef = E66F8DC017EEC65200354D80 /* IJKMPMoviePlayerController.m */; };\n\t\tE654EAAB1B6B284C00B0F2D0 /* IJKFFMoviePlayerController.m in Sources */ = {isa = PBXBuildFile; fileRef = E66F8DE617EFD9C300354D80 /* IJKFFMoviePlayerController.m */; };\n\t\tE654EAAC1B6B284C00B0F2D0 /* IJKFFMoviePlayerDef.m in Sources */ = {isa = PBXBuildFile; fileRef = E6F727BA17F2D9D30043623F /* IJKFFMoviePlayerDef.m */; };\n\t\tE654EAAE1B6B284C00B0F2D0 /* IJKFFOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = E62139BD180FA89A00553533 /* IJKFFOptions.m */; };\n\t\tE654EAAF1B6B285900B0F2D0 /* ff_cmdutils.c in Sources */ = {isa = PBXBuildFile; fileRef = E6903FD517EAFC6100CFD954 /* ff_cmdutils.c */; };\n\t\tE654EAB01B6B285900B0F2D0 /* ff_ffpipeline.c in Sources */ = {isa = PBXBuildFile; fileRef = E67B91AB1A3801DB00717EA9 /* ff_ffpipeline.c */; };\n\t\tE654EAB11B6B285900B0F2D0 /* ff_ffpipenode.c in Sources */ = {isa = PBXBuildFile; fileRef = E67B91AD1A3801DB00717EA9 /* ff_ffpipenode.c */; };\n\t\tE654EAB21B6B285900B0F2D0 /* ff_ffplay.c in Sources */ = {isa = PBXBuildFile; fileRef = E6903FDB17EAFC6100CFD954 /* ff_ffplay.c */; };\n\t\tE654EAB31B6B285900B0F2D0 /* ijkmeta.c in Sources */ = {isa = PBXBuildFile; fileRef = E6FAD9551A515CE300725002 /* ijkmeta.c */; };\n\t\tE654EAB41B6B285900B0F2D0 /* ijkplayer.c in Sources */ = {isa = PBXBuildFile; fileRef = E66F8DEF17EFEA9400354D80 /* ijkplayer.c */; };\n\t\tE654EAB51B6B286400B0F2D0 /* ffpipeline_ios.c in Sources */ = {isa = PBXBuildFile; fileRef = 454316201A66493700676070 /* ffpipeline_ios.c */; };\n\t\tE654EAB61B6B286400B0F2D0 /* ffpipenode_ios_videotoolbox_vdec.m in Sources */ = {isa = PBXBuildFile; fileRef = 454316231A66493700676070 /* ffpipenode_ios_videotoolbox_vdec.m */; };\n\t\tE654EAB81B6B286400B0F2D0 /* IJKVideoToolBoxAsync.m in Sources */ = {isa = PBXBuildFile; fileRef = 4543162A1A66497900676070 /* IJKVideoToolBoxAsync.m */; };\n\t\tE654EAB91B6B286700B0F2D0 /* ijkplayer_ios.m in Sources */ = {isa = PBXBuildFile; fileRef = E66F8E0117EFEEA400354D80 /* ijkplayer_ios.m */; settings = {COMPILER_FLAGS = \"-fno-objc-arc\"; }; };\n\t\tE654EABA1B6B286B00B0F2D0 /* ffpipeline_ffplay.c in Sources */ = {isa = PBXBuildFile; fileRef = E67B91B21A3801E600717EA9 /* ffpipeline_ffplay.c */; };\n\t\tE654EABB1B6B286B00B0F2D0 /* ffpipenode_ffplay_vdec.c in Sources */ = {isa = PBXBuildFile; fileRef = E67B91B41A3801E600717EA9 /* ffpipenode_ffplay_vdec.c */; };\n\t\tE654EABD1B6B287000B0F2D0 /* ijksdl_vout_dummy.c in Sources */ = {isa = PBXBuildFile; fileRef = E63FC27417F013DE003551EB /* ijksdl_vout_dummy.c */; };\n\t\tE654EABE1B6B287400B0F2D0 /* image_convert.c in Sources */ = {isa = PBXBuildFile; fileRef = E6903FF117EAFC6100CFD954 /* image_convert.c */; };\n\t\tE654EABF1B6B287600B0F2D0 /* ijksdl_vout_overlay_ffmpeg.c in Sources */ = {isa = PBXBuildFile; fileRef = E6903FFB17EAFC6100CFD954 /* ijksdl_vout_overlay_ffmpeg.c */; };\n\t\tE654EAC01B6B287E00B0F2D0 /* ijksdl_aout.c in Sources */ = {isa = PBXBuildFile; fileRef = E6903FFF17EAFC6100CFD954 /* ijksdl_aout.c */; };\n\t\tE654EAC11B6B287E00B0F2D0 /* ijksdl_audio.c in Sources */ = {isa = PBXBuildFile; fileRef = E63FC27017F01143003551EB /* ijksdl_audio.c */; };\n\t\tE654EAC21B6B287E00B0F2D0 /* ijksdl_error.c in Sources */ = {isa = PBXBuildFile; fileRef = E690400417EAFC6100CFD954 /* ijksdl_error.c */; };\n\t\tE654EAC31B6B287E00B0F2D0 /* ijksdl_mutex.c in Sources */ = {isa = PBXBuildFile; fileRef = E690400817EAFC6100CFD954 /* ijksdl_mutex.c */; };\n\t\tE654EAC41B6B287E00B0F2D0 /* ijksdl_stdinc.c in Sources */ = {isa = PBXBuildFile; fileRef = E690400A17EAFC6100CFD954 /* ijksdl_stdinc.c */; };\n\t\tE654EAC51B6B287E00B0F2D0 /* ijksdl_thread.c in Sources */ = {isa = PBXBuildFile; fileRef = E690400C17EAFC6100CFD954 /* ijksdl_thread.c */; };\n\t\tE654EAC61B6B287E00B0F2D0 /* ijksdl_timer.c in Sources */ = {isa = PBXBuildFile; fileRef = E690400E17EAFC6100CFD954 /* ijksdl_timer.c */; };\n\t\tE654EAC71B6B287E00B0F2D0 /* ijksdl_vout.c in Sources */ = {isa = PBXBuildFile; fileRef = E690401117EAFC6100CFD954 /* ijksdl_vout.c */; };\n\t\tE654EAC81B6B288A00B0F2D0 /* ijksdl_aout_ios_audiounit.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92A71878230C009EAB56 /* ijksdl_aout_ios_audiounit.m */; settings = {COMPILER_FLAGS = \"-fno-objc-arc\"; }; };\n\t\tE654EAC91B6B288A00B0F2D0 /* ijksdl_thread_ios.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92AA1878230C009EAB56 /* ijksdl_thread_ios.m */; };\n\t\tE654EACA1B6B288A00B0F2D0 /* ijksdl_vout_ios_gles2.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92AC1878230C009EAB56 /* ijksdl_vout_ios_gles2.m */; settings = {COMPILER_FLAGS = \"-fno-objc-arc\"; }; };\n\t\tE654EACB1B6B288A00B0F2D0 /* ijksdl_vout_overlay_videotoolbox.m in Sources */ = {isa = PBXBuildFile; fileRef = 45DB4AA81A5D52AE005CAD41 /* ijksdl_vout_overlay_videotoolbox.m */; };\n\t\tE654EACC1B6B288A00B0F2D0 /* IJKSDLAudioKit.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92C718782770009EAB56 /* IJKSDLAudioKit.m */; };\n\t\tE654EACD1B6B288A00B0F2D0 /* IJKSDLAudioQueueController.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92C11878236A009EAB56 /* IJKSDLAudioQueueController.m */; };\n\t\tE654EACE1B6B288A00B0F2D0 /* IJKSDLAudioUnitController.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92AE1878230C009EAB56 /* IJKSDLAudioUnitController.m */; };\n\t\tE654EAD31B6B288A00B0F2D0 /* IJKSDLGLView.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92B71878230C009EAB56 /* IJKSDLGLView.m */; };\n\t\tE654EAE61B6B295200B0F2D0 /* IJKMediaModule.h in Headers */ = {isa = PBXBuildFile; fileRef = E672D6F118D3445100C51FF9 /* IJKMediaModule.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\tE654EAE71B6B295200B0F2D0 /* IJKMediaPlayback.h in Headers */ = {isa = PBXBuildFile; fileRef = E6903EC117EAF6C500CFD954 /* IJKMediaPlayback.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\tE654EAE81B6B295200B0F2D0 /* IJKAVMoviePlayerController.h in Headers */ = {isa = PBXBuildFile; fileRef = E67C4E0619D15EEA00415CEE /* IJKAVMoviePlayerController.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\tE654EAE91B6B295200B0F2D0 /* IJKMPMoviePlayerController.h in Headers */ = {isa = PBXBuildFile; fileRef = E66F8DBF17EEC65200354D80 /* IJKMPMoviePlayerController.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\tE654EAEA1B6B295200B0F2D0 /* IJKFFMoviePlayerController.h in Headers */ = {isa = PBXBuildFile; fileRef = E66F8DE517EFD9C300354D80 /* IJKFFMoviePlayerController.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\tE654EAEC1B6B295200B0F2D0 /* IJKFFOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = E62139BC180FA89A00553533 /* IJKFFOptions.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\tE654EAED1B6B29C100B0F2D0 /* IJKMediaPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = E66F8DC217EECB1E00354D80 /* IJKMediaPlayer.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\tE68B7AC51C1E7F20001DE241 /* IJKSDLHudViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = E68B7AC31C1E7F20001DE241 /* IJKSDLHudViewController.h */; };\n\t\tE68B7AC61C1E7F20001DE241 /* IJKSDLHudViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E68B7AC41C1E7F20001DE241 /* IJKSDLHudViewController.m */; };\n\t\tE68B7ACF1C1E97B0001DE241 /* IJKSDLHudViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = E68B7ACD1C1E97B0001DE241 /* IJKSDLHudViewCell.h */; };\n\t\tE68B7AD01C1E97B0001DE241 /* IJKSDLHudViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = E68B7ACE1C1E97B0001DE241 /* IJKSDLHudViewCell.m */; };\n\t\tE698089B1C7EB13A0048A46C /* NSString+IJKMedia.h in Headers */ = {isa = PBXBuildFile; fileRef = E69808991C7EB13A0048A46C /* NSString+IJKMedia.h */; };\n\t\tE698089C1C7EB13A0048A46C /* NSString+IJKMedia.m in Sources */ = {isa = PBXBuildFile; fileRef = E698089A1C7EB13A0048A46C /* NSString+IJKMedia.m */; };\n\t\tE69808A01C7EB2040048A46C /* IJKNotificationManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E698089E1C7EB2040048A46C /* IJKNotificationManager.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\tE69808A11C7EB2040048A46C /* IJKNotificationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E698089F1C7EB2040048A46C /* IJKNotificationManager.m */; };\n\t\tE69BE5511B93FED300AFBA3F /* allformats.c in Sources */ = {isa = PBXBuildFile; fileRef = E69BE54A1B93FED300AFBA3F /* allformats.c */; };\n\t\tE69BE5571B93FED300AFBA3F /* opt.h in Headers */ = {isa = PBXBuildFile; fileRef = E69BE54F1B93FED300AFBA3F /* opt.h */; };\n\t\tE69BE5721B946FF600AFBA3F /* ijklivehook.c in Sources */ = {isa = PBXBuildFile; fileRef = E69BE5701B946FF600AFBA3F /* ijklivehook.c */; };\n\t\tE6C2E7BE1C92BD3600E59229 /* IJKKVOController.h in Headers */ = {isa = PBXBuildFile; fileRef = E65DC3B719D93D5F004F8A08 /* IJKKVOController.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\tE6C459841C7030AA004831EC /* ijksdl_gles2.h in Headers */ = {isa = PBXBuildFile; fileRef = E6C459831C7030AA004831EC /* ijksdl_gles2.h */; };\n\t\tE6C459921C7030B6004831EC /* color.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459861C7030B6004831EC /* color.c */; };\n\t\tE6C459931C7030B6004831EC /* common.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459871C7030B6004831EC /* common.c */; };\n\t\tE6C459941C7030B6004831EC /* yuv420p.fsh.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459891C7030B6004831EC /* yuv420p.fsh.c */; };\n\t\tE6C459951C7030B6004831EC /* yuv444p10le.fsh.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C4598A1C7030B6004831EC /* yuv444p10le.fsh.c */; };\n\t\tE6C459961C7030B6004831EC /* internal.h in Headers */ = {isa = PBXBuildFile; fileRef = E6C4598B1C7030B6004831EC /* internal.h */; };\n\t\tE6C459971C7030B6004831EC /* renderer.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C4598C1C7030B6004831EC /* renderer.c */; };\n\t\tE6C459981C7030B6004831EC /* renderer_yuv420p.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C4598D1C7030B6004831EC /* renderer_yuv420p.c */; };\n\t\tE6C459991C7030B6004831EC /* renderer_yuv444p10le.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C4598E1C7030B6004831EC /* renderer_yuv444p10le.c */; };\n\t\tE6C4599A1C7030B6004831EC /* shader.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C4598F1C7030B6004831EC /* shader.c */; };\n\t\tE6C4599B1C7030B6004831EC /* mvp.vsh.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459911C7030B6004831EC /* mvp.vsh.c */; };\n\t\tE6C459BA1C706A13004831EC /* ijksdl_egl.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459B81C706A13004831EC /* ijksdl_egl.c */; };\n\t\tE6C459BB1C706A13004831EC /* ijksdl_egl.h in Headers */ = {isa = PBXBuildFile; fileRef = E6C459B91C706A13004831EC /* ijksdl_egl.h */; };\n\t\tE6C459BD1C7089AB004831EC /* ff_ffplay_options.h in Headers */ = {isa = PBXBuildFile; fileRef = E6C459BC1C7089AB004831EC /* ff_ffplay_options.h */; };\n\t\tE6C459C01C708CAF004831EC /* renderer_rgb.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459BE1C708CAF004831EC /* renderer_rgb.c */; };\n\t\tE6C459C41C708E60004831EC /* rgb.fsh.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459C21C708E60004831EC /* rgb.fsh.c */; };\n\t\tE6C459C81C7095E5004831EC /* yuv420sp.fsh.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459C61C7095E5004831EC /* yuv420sp.fsh.c */; };\n\t\tE6C459CC1C70967F004831EC /* renderer_yuv420sp.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459CA1C70967F004831EC /* renderer_yuv420sp.c */; };\n\t\tE6DBD3891C8941EB0058E4FB /* IJKFFMonitor.h in Headers */ = {isa = PBXBuildFile; fileRef = E6DBD3871C8941EB0058E4FB /* IJKFFMonitor.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\tE6DBD38A1C8941EB0058E4FB /* IJKFFMonitor.m in Sources */ = {isa = PBXBuildFile; fileRef = E6DBD3881C8941EB0058E4FB /* IJKFFMonitor.m */; };\n\t\tE6E1B9A81C741F72000C6C72 /* renderer_yuv420sp_vtb.m in Sources */ = {isa = PBXBuildFile; fileRef = E6E1B9A71C741F72000C6C72 /* renderer_yuv420sp_vtb.m */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\tE654EA961B6B27E600B0F2D0 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = E6903EB117EAF6C500CFD954 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = E654EA891B6B27E600B0F2D0;\n\t\t\tremoteInfo = IJKMediaFramework;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXFileReference section */\n\t\t454316201A66493700676070 /* ffpipeline_ios.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ffpipeline_ios.c; path = ijkmedia/ijkplayer/ios/pipeline/ffpipeline_ios.c; sourceTree = \"<group>\"; };\n\t\t454316211A66493700676070 /* ffpipeline_ios.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ffpipeline_ios.h; path = ijkmedia/ijkplayer/ios/pipeline/ffpipeline_ios.h; sourceTree = \"<group>\"; };\n\t\t454316221A66493700676070 /* ffpipenode_ios_videotoolbox_vdec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ffpipenode_ios_videotoolbox_vdec.h; path = ijkmedia/ijkplayer/ios/pipeline/ffpipenode_ios_videotoolbox_vdec.h; sourceTree = \"<group>\"; };\n\t\t454316231A66493700676070 /* ffpipenode_ios_videotoolbox_vdec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ffpipenode_ios_videotoolbox_vdec.m; path = ijkmedia/ijkplayer/ios/pipeline/ffpipenode_ios_videotoolbox_vdec.m; sourceTree = \"<group>\"; };\n\t\t454316291A66497900676070 /* IJKVideoToolBoxAsync.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKVideoToolBoxAsync.h; path = ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBoxAsync.h; sourceTree = \"<group>\"; };\n\t\t4543162A1A66497900676070 /* IJKVideoToolBoxAsync.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKVideoToolBoxAsync.m; path = ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBoxAsync.m; sourceTree = \"<group>\"; };\n\t\t45DB4AA71A5D52AE005CAD41 /* ijksdl_vout_overlay_videotoolbox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_vout_overlay_videotoolbox.h; sourceTree = \"<group>\"; };\n\t\t45DB4AA81A5D52AE005CAD41 /* ijksdl_vout_overlay_videotoolbox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ijksdl_vout_overlay_videotoolbox.m; sourceTree = \"<group>\"; };\n\t\t4D32BC801F906E3600CE9F03 /* IJKSDLGLViewProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJKSDLGLViewProtocol.h; sourceTree = \"<group>\"; };\n\t\t4DA7F6881F2B1E270032A499 /* ijkiourlhook.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkiourlhook.c; sourceTree = \"<group>\"; };\n\t\t5407EC271DF7F93B00457BFE /* IJKVideoToolBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKVideoToolBox.h; path = ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBox.h; sourceTree = \"<group>\"; };\n\t\t5407EC281DF7F93B00457BFE /* IJKVideoToolBox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKVideoToolBox.m; path = ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBox.m; sourceTree = \"<group>\"; };\n\t\t5407EC2B1DF81D2600457BFE /* IJKVideoToolBoxSync.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKVideoToolBoxSync.h; path = ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBoxSync.h; sourceTree = \"<group>\"; };\n\t\t5407EC2C1DF81D2600457BFE /* IJKVideoToolBoxSync.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKVideoToolBoxSync.m; path = ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBoxSync.m; sourceTree = \"<group>\"; };\n\t\t5450AF8B1E63E59300568494 /* libcrypto.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcrypto.a; path = \"../../../.warehouse/ff3.2--ijk0.7.6--20170203--001/build/universal/lib/libcrypto.a\"; sourceTree = \"<group>\"; };\n\t\t5450AF8C1E63E59300568494 /* libssl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libssl.a; path = \"../../../.warehouse/ff3.2--ijk0.7.6--20170203--001/build/universal/lib/libssl.a\"; sourceTree = \"<group>\"; };\n\t\t5450AF8F1E63E59800568494 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = \"sourcecode.text-based-dylib-definition\"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };\n\t\t5450AF9B1E63E65700568494 /* IJKMediaFrameworkWithSSL.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJKMediaFrameworkWithSSL.h; sourceTree = \"<group>\"; };\n\t\t5450B0431E63EA4300568494 /* IJKMediaFrameworkWithSSL.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = IJKMediaFrameworkWithSSL.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t5450B0441E63EA4300568494 /* IJKMediaFrameworkWithSSL.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = IJKMediaFrameworkWithSSL.plist; path = /Users/zhangxinzheng/Documents/bilibili/BiliShell/contrib/ijkplayer/ios/IJKMediaPlayer/IJKMediaFrameworkWithSSL.plist; sourceTree = \"<absolute>\"; };\n\t\t54A029B11D4700E6001C61C1 /* ijkasync.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkasync.c; sourceTree = \"<group>\"; };\n\t\t54A029B21D4700E6001C61C1 /* ijkavformat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijkavformat.h; sourceTree = \"<group>\"; };\n\t\t54A029B31D4700E6001C61C1 /* ijklongurl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijklongurl.c; sourceTree = \"<group>\"; };\n\t\t54A029B41D4700E6001C61C1 /* ijksegment.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijksegment.c; sourceTree = \"<group>\"; };\n\t\t54A029B51D4700E6001C61C1 /* ijkurlhook.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkurlhook.c; sourceTree = \"<group>\"; };\n\t\t54CF8A291E1526F800309DD5 /* ijkio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkio.c; sourceTree = \"<group>\"; };\n\t\t54CF8A2A1E1526F800309DD5 /* ijkioapplication.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkioapplication.c; sourceTree = \"<group>\"; };\n\t\t54CF8A2B1E1526F800309DD5 /* ijkioapplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijkioapplication.h; sourceTree = \"<group>\"; };\n\t\t54CF8A2C1E1526F800309DD5 /* ijkiocache.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkiocache.c; sourceTree = \"<group>\"; };\n\t\t54CF8A2D1E1526F800309DD5 /* ijkioffio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkioffio.c; sourceTree = \"<group>\"; };\n\t\t54CF8A2E1E1526F800309DD5 /* ijkiomanager.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkiomanager.c; sourceTree = \"<group>\"; };\n\t\t54CF8A2F1E1526F800309DD5 /* ijkiomanager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijkiomanager.h; sourceTree = \"<group>\"; };\n\t\t54CF8A301E1526F800309DD5 /* ijkioprotocol.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkioprotocol.c; sourceTree = \"<group>\"; };\n\t\t54CF8A311E1526F800309DD5 /* ijkioprotocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijkioprotocol.h; sourceTree = \"<group>\"; };\n\t\t54CF8A321E1526F800309DD5 /* ijkiourl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijkiourl.h; sourceTree = \"<group>\"; };\n\t\t54CF8A3D1E15287D00309DD5 /* ijkdict.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkdict.c; sourceTree = \"<group>\"; };\n\t\t54CF8A3E1E15287D00309DD5 /* ijkdict.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijkdict.h; sourceTree = \"<group>\"; };\n\t\t54CF8A3F1E15287D00309DD5 /* ijkfifo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkfifo.c; sourceTree = \"<group>\"; };\n\t\t54CF8A401E15287D00309DD5 /* ijkfifo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijkfifo.h; sourceTree = \"<group>\"; };\n\t\t54CF8A411E15287D00309DD5 /* ijkstl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ijkstl.cpp; sourceTree = \"<group>\"; };\n\t\t54CF8A421E15287D00309DD5 /* ijkstl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijkstl.h; sourceTree = \"<group>\"; };\n\t\t54CF8A431E15287D00309DD5 /* ijkthreadpool.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkthreadpool.c; sourceTree = \"<group>\"; };\n\t\t54CF8A441E15287D00309DD5 /* ijkthreadpool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijkthreadpool.h; sourceTree = \"<group>\"; };\n\t\t54CF8A451E15287D00309DD5 /* ijktree.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijktree.c; sourceTree = \"<group>\"; };\n\t\t54CF8A461E15287D00309DD5 /* ijktree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijktree.h; sourceTree = \"<group>\"; };\n\t\t54CF8A471E15287D00309DD5 /* ijkutils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkutils.c; sourceTree = \"<group>\"; };\n\t\t54CF8A481E15287D00309DD5 /* ijkutils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijkutils.h; sourceTree = \"<group>\"; };\n\t\tB417F8DB24F7C3B400D159BB /* cJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cJSON.h; sourceTree = \"<group>\"; };\n\t\tB417F8E124F7C56C00D159BB /* cJSON.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cJSON.c; sourceTree = \"<group>\"; };\n\t\tB4449BD4250095700074CEDC /* ijklas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijklas.h; sourceTree = \"<group>\"; };\n\t\tB4449BD5250095700074CEDC /* ijklas.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijklas.c; sourceTree = \"<group>\"; };\n\t\tE607FFDE1B7B60F9005F11A6 /* IJKDeviceModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKDeviceModel.h; path = IJKMediaPlayer/IJKDeviceModel.h; sourceTree = \"<group>\"; };\n\t\tE607FFDF1B7B60F9005F11A6 /* IJKDeviceModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKDeviceModel.m; path = IJKMediaPlayer/IJKDeviceModel.m; sourceTree = \"<group>\"; };\n\t\tE62139BC180FA89A00553533 /* IJKFFOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKFFOptions.h; sourceTree = \"<group>\"; };\n\t\tE62139BD180FA89A00553533 /* IJKFFOptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKFFOptions.m; sourceTree = \"<group>\"; };\n\t\tE63FC27017F01143003551EB /* ijksdl_audio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijksdl_audio.c; sourceTree = \"<group>\"; };\n\t\tE63FC27317F013DE003551EB /* ijksdl_dummy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_dummy.h; sourceTree = \"<group>\"; };\n\t\tE63FC27417F013DE003551EB /* ijksdl_vout_dummy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijksdl_vout_dummy.c; sourceTree = \"<group>\"; };\n\t\tE63FC27517F013DE003551EB /* ijksdl_vout_dummy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_vout_dummy.h; sourceTree = \"<group>\"; };\n\t\tE653C6EF1BCE5A750016835A /* libavcodec.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libavcodec.a; sourceTree = \"<group>\"; };\n\t\tE653C6F01BCE5A750016835A /* libavfilter.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libavfilter.a; sourceTree = \"<group>\"; };\n\t\tE653C6F11BCE5A750016835A /* libavformat.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libavformat.a; sourceTree = \"<group>\"; };\n\t\tE653C6F21BCE5A750016835A /* libavutil.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libavutil.a; sourceTree = \"<group>\"; };\n\t\tE653C6F31BCE5A750016835A /* libswresample.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libswresample.a; sourceTree = \"<group>\"; };\n\t\tE653C6F41BCE5A750016835A /* libswscale.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libswscale.a; sourceTree = \"<group>\"; };\n\t\tE654EA8A1B6B27E600B0F2D0 /* IJKMediaFramework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = IJKMediaFramework.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tE654EA8D1B6B27E600B0F2D0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tE654EA8E1B6B27E600B0F2D0 /* IJKMediaFramework.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJKMediaFramework.h; sourceTree = \"<group>\"; };\n\t\tE654EA941B6B27E600B0F2D0 /* IJKMediaFrameworkTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = IJKMediaFrameworkTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tE654EA9A1B6B27E600B0F2D0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tE654EA9B1B6B27E600B0F2D0 /* IJKMediaFrameworkTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJKMediaFrameworkTests.m; sourceTree = \"<group>\"; };\n\t\tE65DC3B719D93D5F004F8A08 /* IJKKVOController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKKVOController.h; path = IJKMediaPlayer/IJKKVOController.h; sourceTree = \"<group>\"; };\n\t\tE65DC3B819D93D5F004F8A08 /* IJKKVOController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKKVOController.m; path = IJKMediaPlayer/IJKKVOController.m; sourceTree = \"<group>\"; };\n\t\tE66F8DBF17EEC65200354D80 /* IJKMPMoviePlayerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKMPMoviePlayerController.h; path = IJKMediaPlayer/IJKMPMoviePlayerController.h; sourceTree = \"<group>\"; };\n\t\tE66F8DC017EEC65200354D80 /* IJKMPMoviePlayerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKMPMoviePlayerController.m; path = IJKMediaPlayer/IJKMPMoviePlayerController.m; sourceTree = \"<group>\"; };\n\t\tE66F8DC217EECB1E00354D80 /* IJKMediaPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKMediaPlayer.h; path = IJKMediaPlayer/IJKMediaPlayer.h; sourceTree = \"<group>\"; };\n\t\tE66F8DE517EFD9C300354D80 /* IJKFFMoviePlayerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKFFMoviePlayerController.h; sourceTree = \"<group>\"; };\n\t\tE66F8DE617EFD9C300354D80 /* IJKFFMoviePlayerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKFFMoviePlayerController.m; sourceTree = \"<group>\"; };\n\t\tE66F8DEE17EFEA9400354D80 /* ijkplayer_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijkplayer_internal.h; sourceTree = \"<group>\"; };\n\t\tE66F8DEF17EFEA9400354D80 /* ijkplayer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkplayer.c; sourceTree = \"<group>\"; };\n\t\tE66F8DF017EFEA9400354D80 /* ijkplayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijkplayer.h; sourceTree = \"<group>\"; };\n\t\tE66F8E0117EFEEA400354D80 /* ijkplayer_ios.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ijkplayer_ios.m; path = ijkmedia/ijkplayer/ios/ijkplayer_ios.m; sourceTree = \"<group>\"; };\n\t\tE66F8E0217EFEEA400354D80 /* ijkplayer_ios.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ijkplayer_ios.h; path = ijkmedia/ijkplayer/ios/ijkplayer_ios.h; sourceTree = \"<group>\"; };\n\t\tE6716E491807E5FC00B3FBC1 /* IJKMediaUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKMediaUtils.h; path = IJKMediaPlayer/IJKMediaUtils.h; sourceTree = \"<group>\"; };\n\t\tE6716E4A1807E5FC00B3FBC1 /* IJKMediaUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKMediaUtils.m; path = IJKMediaPlayer/IJKMediaUtils.m; sourceTree = \"<group>\"; };\n\t\tE672D6F118D3445100C51FF9 /* IJKMediaModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKMediaModule.h; path = IJKMediaPlayer/IJKMediaModule.h; sourceTree = \"<group>\"; };\n\t\tE672D6F218D3445100C51FF9 /* IJKMediaModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKMediaModule.m; path = IJKMediaPlayer/IJKMediaModule.m; sourceTree = \"<group>\"; };\n\t\tE67B91AB1A3801DB00717EA9 /* ff_ffpipeline.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ff_ffpipeline.c; sourceTree = \"<group>\"; };\n\t\tE67B91AC1A3801DB00717EA9 /* ff_ffpipeline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ff_ffpipeline.h; sourceTree = \"<group>\"; };\n\t\tE67B91AD1A3801DB00717EA9 /* ff_ffpipenode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ff_ffpipenode.c; sourceTree = \"<group>\"; };\n\t\tE67B91AE1A3801DB00717EA9 /* ff_ffpipenode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ff_ffpipenode.h; sourceTree = \"<group>\"; };\n\t\tE67B91B21A3801E600717EA9 /* ffpipeline_ffplay.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffpipeline_ffplay.c; sourceTree = \"<group>\"; };\n\t\tE67B91B31A3801E600717EA9 /* ffpipeline_ffplay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffpipeline_ffplay.h; sourceTree = \"<group>\"; };\n\t\tE67B91B41A3801E600717EA9 /* ffpipenode_ffplay_vdec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffpipenode_ffplay_vdec.c; sourceTree = \"<group>\"; };\n\t\tE67B91B51A3801E600717EA9 /* ffpipenode_ffplay_vdec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffpipenode_ffplay_vdec.h; sourceTree = \"<group>\"; };\n\t\tE67C4E0319D15B3200415CEE /* IJKAVPlayerLayerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKAVPlayerLayerView.h; path = IJKMediaPlayer/IJKAVPlayerLayerView.h; sourceTree = \"<group>\"; };\n\t\tE67C4E0419D15B3200415CEE /* IJKAVPlayerLayerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKAVPlayerLayerView.m; path = IJKMediaPlayer/IJKAVPlayerLayerView.m; sourceTree = \"<group>\"; };\n\t\tE67C4E0619D15EEA00415CEE /* IJKAVMoviePlayerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKAVMoviePlayerController.h; path = IJKMediaPlayer/IJKAVMoviePlayerController.h; sourceTree = \"<group>\"; };\n\t\tE67C4E0719D15EEA00415CEE /* IJKAVMoviePlayerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKAVMoviePlayerController.m; path = IJKMediaPlayer/IJKAVMoviePlayerController.m; sourceTree = \"<group>\"; };\n\t\tE67FB4AC1B4A766F00AA94AA /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = \"<group>\"; };\n\t\tE68B7AC31C1E7F20001DE241 /* IJKSDLHudViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKSDLHudViewController.h; sourceTree = \"<group>\"; };\n\t\tE68B7AC41C1E7F20001DE241 /* IJKSDLHudViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKSDLHudViewController.m; sourceTree = \"<group>\"; };\n\t\tE68B7ACD1C1E97B0001DE241 /* IJKSDLHudViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKSDLHudViewCell.h; sourceTree = \"<group>\"; };\n\t\tE68B7ACE1C1E97B0001DE241 /* IJKSDLHudViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKSDLHudViewCell.m; sourceTree = \"<group>\"; };\n\t\tE6903EC017EAF6C500CFD954 /* IJKMediaPlayer-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = \"IJKMediaPlayer-Prefix.pch\"; sourceTree = \"<group>\"; };\n\t\tE6903EC117EAF6C500CFD954 /* IJKMediaPlayback.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IJKMediaPlayback.h; path = IJKMediaPlayer/IJKMediaPlayback.h; sourceTree = \"<group>\"; };\n\t\tE6903FD517EAFC6100CFD954 /* ff_cmdutils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ff_cmdutils.c; sourceTree = \"<group>\"; };\n\t\tE6903FD617EAFC6100CFD954 /* ff_cmdutils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ff_cmdutils.h; sourceTree = \"<group>\"; };\n\t\tE6903FD717EAFC6100CFD954 /* ff_fferror.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ff_fferror.h; sourceTree = \"<group>\"; };\n\t\tE6903FD817EAFC6100CFD954 /* ff_ffinc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ff_ffinc.h; sourceTree = \"<group>\"; };\n\t\tE6903FD917EAFC6100CFD954 /* ff_ffmsg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ff_ffmsg.h; sourceTree = \"<group>\"; };\n\t\tE6903FDA17EAFC6100CFD954 /* ff_ffmsg_queue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ff_ffmsg_queue.h; sourceTree = \"<group>\"; };\n\t\tE6903FDB17EAFC6100CFD954 /* ff_ffplay.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ff_ffplay.c; sourceTree = \"<group>\"; };\n\t\tE6903FDC17EAFC6100CFD954 /* ff_ffplay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ff_ffplay.h; sourceTree = \"<group>\"; };\n\t\tE6903FDE17EAFC6100CFD954 /* ff_ffplay_def.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ff_ffplay_def.h; sourceTree = \"<group>\"; };\n\t\tE6903FF117EAFC6100CFD954 /* image_convert.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = image_convert.c; sourceTree = \"<group>\"; };\n\t\tE6903FF917EAFC6100CFD954 /* ijksdl_image_convert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_image_convert.h; sourceTree = \"<group>\"; };\n\t\tE6903FFA17EAFC6100CFD954 /* ijksdl_inc_ffmpeg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_inc_ffmpeg.h; sourceTree = \"<group>\"; };\n\t\tE6903FFB17EAFC6100CFD954 /* ijksdl_vout_overlay_ffmpeg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijksdl_vout_overlay_ffmpeg.c; sourceTree = \"<group>\"; };\n\t\tE6903FFC17EAFC6100CFD954 /* ijksdl_vout_overlay_ffmpeg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_vout_overlay_ffmpeg.h; sourceTree = \"<group>\"; };\n\t\tE6903FFD17EAFC6100CFD954 /* ijksdl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl.h; sourceTree = \"<group>\"; };\n\t\tE6903FFF17EAFC6100CFD954 /* ijksdl_aout.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijksdl_aout.c; sourceTree = \"<group>\"; };\n\t\tE690400017EAFC6100CFD954 /* ijksdl_aout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_aout.h; sourceTree = \"<group>\"; };\n\t\tE690400117EAFC6100CFD954 /* ijksdl_aout_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_aout_internal.h; sourceTree = \"<group>\"; };\n\t\tE690400217EAFC6100CFD954 /* ijksdl_audio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_audio.h; sourceTree = \"<group>\"; };\n\t\tE690400317EAFC6100CFD954 /* ijksdl_endian.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_endian.h; sourceTree = \"<group>\"; };\n\t\tE690400417EAFC6100CFD954 /* ijksdl_error.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijksdl_error.c; sourceTree = \"<group>\"; };\n\t\tE690400517EAFC6100CFD954 /* ijksdl_error.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_error.h; sourceTree = \"<group>\"; };\n\t\tE690400617EAFC6100CFD954 /* ijksdl_fourcc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_fourcc.h; sourceTree = \"<group>\"; };\n\t\tE690400717EAFC6100CFD954 /* ijksdl_inc_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_inc_internal.h; sourceTree = \"<group>\"; };\n\t\tE690400817EAFC6100CFD954 /* ijksdl_mutex.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijksdl_mutex.c; sourceTree = \"<group>\"; };\n\t\tE690400917EAFC6100CFD954 /* ijksdl_mutex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_mutex.h; sourceTree = \"<group>\"; };\n\t\tE690400A17EAFC6100CFD954 /* ijksdl_stdinc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijksdl_stdinc.c; sourceTree = \"<group>\"; };\n\t\tE690400B17EAFC6100CFD954 /* ijksdl_stdinc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_stdinc.h; sourceTree = \"<group>\"; };\n\t\tE690400C17EAFC6100CFD954 /* ijksdl_thread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijksdl_thread.c; sourceTree = \"<group>\"; };\n\t\tE690400D17EAFC6100CFD954 /* ijksdl_thread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_thread.h; sourceTree = \"<group>\"; };\n\t\tE690400E17EAFC6100CFD954 /* ijksdl_timer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijksdl_timer.c; sourceTree = \"<group>\"; };\n\t\tE690400F17EAFC6100CFD954 /* ijksdl_timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_timer.h; sourceTree = \"<group>\"; };\n\t\tE690401017EAFC6100CFD954 /* ijksdl_video.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_video.h; sourceTree = \"<group>\"; };\n\t\tE690401117EAFC6100CFD954 /* ijksdl_vout.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijksdl_vout.c; sourceTree = \"<group>\"; };\n\t\tE690401217EAFC6100CFD954 /* ijksdl_vout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_vout.h; sourceTree = \"<group>\"; };\n\t\tE690401317EAFC6100CFD954 /* ijksdl_vout_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_vout_internal.h; sourceTree = \"<group>\"; };\n\t\tE69808991C7EB13A0048A46C /* NSString+IJKMedia.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"NSString+IJKMedia.h\"; path = \"IJKMediaPlayer/NSString+IJKMedia.h\"; sourceTree = \"<group>\"; };\n\t\tE698089A1C7EB13A0048A46C /* NSString+IJKMedia.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = \"NSString+IJKMedia.m\"; path = \"IJKMediaPlayer/NSString+IJKMedia.m\"; sourceTree = \"<group>\"; };\n\t\tE698089E1C7EB2040048A46C /* IJKNotificationManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKNotificationManager.h; path = IJKMediaPlayer/IJKNotificationManager.h; sourceTree = \"<group>\"; };\n\t\tE698089F1C7EB2040048A46C /* IJKNotificationManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKNotificationManager.m; path = IJKMediaPlayer/IJKNotificationManager.m; sourceTree = \"<group>\"; };\n\t\tE69BE54A1B93FED300AFBA3F /* allformats.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = allformats.c; sourceTree = \"<group>\"; };\n\t\tE69BE54F1B93FED300AFBA3F /* opt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opt.h; sourceTree = \"<group>\"; };\n\t\tE69BE5701B946FF600AFBA3F /* ijklivehook.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijklivehook.c; sourceTree = \"<group>\"; };\n\t\tE6C2FD391B300A390081D321 /* ff_ffplay_debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ff_ffplay_debug.h; sourceTree = \"<group>\"; };\n\t\tE6C459831C7030AA004831EC /* ijksdl_gles2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_gles2.h; sourceTree = \"<group>\"; };\n\t\tE6C459861C7030B6004831EC /* color.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = color.c; sourceTree = \"<group>\"; };\n\t\tE6C459871C7030B6004831EC /* common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = common.c; sourceTree = \"<group>\"; };\n\t\tE6C459891C7030B6004831EC /* yuv420p.fsh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = yuv420p.fsh.c; sourceTree = \"<group>\"; };\n\t\tE6C4598A1C7030B6004831EC /* yuv444p10le.fsh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = yuv444p10le.fsh.c; sourceTree = \"<group>\"; };\n\t\tE6C4598B1C7030B6004831EC /* internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = internal.h; sourceTree = \"<group>\"; };\n\t\tE6C4598C1C7030B6004831EC /* renderer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = renderer.c; sourceTree = \"<group>\"; };\n\t\tE6C4598D1C7030B6004831EC /* renderer_yuv420p.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = renderer_yuv420p.c; sourceTree = \"<group>\"; };\n\t\tE6C4598E1C7030B6004831EC /* renderer_yuv444p10le.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = renderer_yuv444p10le.c; sourceTree = \"<group>\"; };\n\t\tE6C4598F1C7030B6004831EC /* shader.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = shader.c; sourceTree = \"<group>\"; };\n\t\tE6C459911C7030B6004831EC /* mvp.vsh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mvp.vsh.c; sourceTree = \"<group>\"; };\n\t\tE6C459B81C706A13004831EC /* ijksdl_egl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijksdl_egl.c; sourceTree = \"<group>\"; };\n\t\tE6C459B91C706A13004831EC /* ijksdl_egl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_egl.h; sourceTree = \"<group>\"; };\n\t\tE6C459BC1C7089AB004831EC /* ff_ffplay_options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ff_ffplay_options.h; sourceTree = \"<group>\"; };\n\t\tE6C459BE1C708CAF004831EC /* renderer_rgb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = renderer_rgb.c; sourceTree = \"<group>\"; };\n\t\tE6C459C21C708E60004831EC /* rgb.fsh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rgb.fsh.c; sourceTree = \"<group>\"; };\n\t\tE6C459C61C7095E5004831EC /* yuv420sp.fsh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = yuv420sp.fsh.c; sourceTree = \"<group>\"; };\n\t\tE6C459CA1C70967F004831EC /* renderer_yuv420sp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = renderer_yuv420sp.c; sourceTree = \"<group>\"; };\n\t\tE6CA1EE71B4FAFCF00BCAF89 /* ijksdl_class.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_class.h; sourceTree = \"<group>\"; };\n\t\tE6CA1EE81B4FAFCF00BCAF89 /* ijksdl_misc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_misc.h; sourceTree = \"<group>\"; };\n\t\tE6CA1EE91B4FB04500BCAF89 /* ijksdl_log.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_log.h; sourceTree = \"<group>\"; };\n\t\tE6D5FFF71B5F445E00E1E328 /* h264_sps_parser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = h264_sps_parser.h; path = ijkmedia/ijkplayer/ios/pipeline/h264_sps_parser.h; sourceTree = \"<group>\"; };\n\t\tE6DBD3871C8941EB0058E4FB /* IJKFFMonitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKFFMonitor.h; sourceTree = \"<group>\"; };\n\t\tE6DBD3881C8941EB0058E4FB /* IJKFFMonitor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKFFMonitor.m; sourceTree = \"<group>\"; };\n\t\tE6E1B9A71C741F72000C6C72 /* renderer_yuv420sp_vtb.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = renderer_yuv420sp_vtb.m; sourceTree = \"<group>\"; };\n\t\tE6EE92A1187810C5009EAB56 /* IJKAudioKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKAudioKit.h; path = IJKMediaPlayer/IJKAudioKit.h; sourceTree = \"<group>\"; };\n\t\tE6EE92A2187810C5009EAB56 /* IJKAudioKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKAudioKit.m; path = IJKMediaPlayer/IJKAudioKit.m; sourceTree = \"<group>\"; };\n\t\tE6EE92A61878230C009EAB56 /* ijksdl_aout_ios_audiounit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_aout_ios_audiounit.h; sourceTree = \"<group>\"; };\n\t\tE6EE92A71878230C009EAB56 /* ijksdl_aout_ios_audiounit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ijksdl_aout_ios_audiounit.m; sourceTree = \"<group>\"; };\n\t\tE6EE92A81878230C009EAB56 /* ijksdl_ios.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_ios.h; sourceTree = \"<group>\"; };\n\t\tE6EE92A91878230C009EAB56 /* ijksdl_thread_ios.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_thread_ios.h; sourceTree = \"<group>\"; };\n\t\tE6EE92AA1878230C009EAB56 /* ijksdl_thread_ios.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ijksdl_thread_ios.m; sourceTree = \"<group>\"; };\n\t\tE6EE92AB1878230C009EAB56 /* ijksdl_vout_ios_gles2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_vout_ios_gles2.h; sourceTree = \"<group>\"; };\n\t\tE6EE92AC1878230C009EAB56 /* ijksdl_vout_ios_gles2.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ijksdl_vout_ios_gles2.m; sourceTree = \"<group>\"; };\n\t\tE6EE92AD1878230C009EAB56 /* IJKSDLAudioUnitController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKSDLAudioUnitController.h; sourceTree = \"<group>\"; };\n\t\tE6EE92AE1878230C009EAB56 /* IJKSDLAudioUnitController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKSDLAudioUnitController.m; sourceTree = \"<group>\"; };\n\t\tE6EE92B61878230C009EAB56 /* IJKSDLGLView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKSDLGLView.h; sourceTree = \"<group>\"; };\n\t\tE6EE92B71878230C009EAB56 /* IJKSDLGLView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKSDLGLView.m; sourceTree = \"<group>\"; };\n\t\tE6EE92C01878236A009EAB56 /* IJKSDLAudioQueueController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKSDLAudioQueueController.h; sourceTree = \"<group>\"; };\n\t\tE6EE92C11878236A009EAB56 /* IJKSDLAudioQueueController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKSDLAudioQueueController.m; sourceTree = \"<group>\"; };\n\t\tE6EE92C618782770009EAB56 /* IJKSDLAudioKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKSDLAudioKit.h; sourceTree = \"<group>\"; };\n\t\tE6EE92C718782770009EAB56 /* IJKSDLAudioKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKSDLAudioKit.m; sourceTree = \"<group>\"; };\n\t\tE6F727B917F2D9D30043623F /* IJKFFMoviePlayerDef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKFFMoviePlayerDef.h; sourceTree = \"<group>\"; };\n\t\tE6F727BA17F2D9D30043623F /* IJKFFMoviePlayerDef.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKFFMoviePlayerDef.m; sourceTree = \"<group>\"; };\n\t\tE6F727C117F7C9B90043623F /* IJKMediaPlayback.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKMediaPlayback.m; path = IJKMediaPlayer/IJKMediaPlayback.m; sourceTree = \"<group>\"; };\n\t\tE6FAD9551A515CE300725002 /* ijkmeta.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkmeta.c; sourceTree = \"<group>\"; };\n\t\tE6FAD9561A515CE300725002 /* ijkmeta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijkmeta.h; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t5450B0171E63EA4300568494 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t5450B0471E63EABC00568494 /* libz.tbd in Frameworks */,\n\t\t\t\t5450B0451E63EAB700568494 /* libcrypto.a in Frameworks */,\n\t\t\t\t5450B0461E63EAB700568494 /* libssl.a in Frameworks */,\n\t\t\t\t5450B0181E63EA4300568494 /* libavcodec.a in Frameworks */,\n\t\t\t\t5450B0191E63EA4300568494 /* libavfilter.a in Frameworks */,\n\t\t\t\t5450B01A1E63EA4300568494 /* libavformat.a in Frameworks */,\n\t\t\t\t5450B01B1E63EA4300568494 /* libavutil.a in Frameworks */,\n\t\t\t\t5450B01C1E63EA4300568494 /* libswresample.a in Frameworks */,\n\t\t\t\t5450B01D1E63EA4300568494 /* libswscale.a in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tE654EA861B6B27E600B0F2D0 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tE653C6F61BCE5A750016835A /* libavcodec.a in Frameworks */,\n\t\t\t\tE653C6F81BCE5A750016835A /* libavfilter.a in Frameworks */,\n\t\t\t\tE653C6FA1BCE5A750016835A /* libavformat.a in Frameworks */,\n\t\t\t\tE653C6FC1BCE5A750016835A /* libavutil.a in Frameworks */,\n\t\t\t\tE653C6FE1BCE5A750016835A /* libswresample.a in Frameworks */,\n\t\t\t\tE653C7001BCE5A750016835A /* libswscale.a in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tE654EA911B6B27E600B0F2D0 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tE654EA951B6B27E600B0F2D0 /* IJKMediaFramework.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t4543161F1A66481600676070 /* pipeline */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t454316201A66493700676070 /* ffpipeline_ios.c */,\n\t\t\t\t454316211A66493700676070 /* ffpipeline_ios.h */,\n\t\t\t\t454316221A66493700676070 /* ffpipenode_ios_videotoolbox_vdec.h */,\n\t\t\t\t454316231A66493700676070 /* ffpipenode_ios_videotoolbox_vdec.m */,\n\t\t\t\tE6D5FFF71B5F445E00E1E328 /* h264_sps_parser.h */,\n\t\t\t\t5407EC271DF7F93B00457BFE /* IJKVideoToolBox.h */,\n\t\t\t\t5407EC281DF7F93B00457BFE /* IJKVideoToolBox.m */,\n\t\t\t\t454316291A66497900676070 /* IJKVideoToolBoxAsync.h */,\n\t\t\t\t4543162A1A66497900676070 /* IJKVideoToolBoxAsync.m */,\n\t\t\t\t5407EC2B1DF81D2600457BFE /* IJKVideoToolBoxSync.h */,\n\t\t\t\t5407EC2C1DF81D2600457BFE /* IJKVideoToolBoxSync.m */,\n\t\t\t);\n\t\t\tname = pipeline;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5450AF9A1E63E65700568494 /* IJKMediaFrameworkWithSSL */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t5450AF9B1E63E65700568494 /* IJKMediaFrameworkWithSSL.h */,\n\t\t\t\t5450B0441E63EA4300568494 /* IJKMediaFrameworkWithSSL.plist */,\n\t\t\t);\n\t\t\tpath = IJKMediaFrameworkWithSSL;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE63FC27217F013DE003551EB /* dummy */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE63FC27317F013DE003551EB /* ijksdl_dummy.h */,\n\t\t\t\tE63FC27417F013DE003551EB /* ijksdl_vout_dummy.c */,\n\t\t\t\tE63FC27517F013DE003551EB /* ijksdl_vout_dummy.h */,\n\t\t\t);\n\t\t\tpath = dummy;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE654EA8B1B6B27E600B0F2D0 /* IJKMediaFramework */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE654EA8E1B6B27E600B0F2D0 /* IJKMediaFramework.h */,\n\t\t\t\tE654EA8C1B6B27E600B0F2D0 /* Supporting Files */,\n\t\t\t);\n\t\t\tpath = IJKMediaFramework;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE654EA8C1B6B27E600B0F2D0 /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE654EA8D1B6B27E600B0F2D0 /* Info.plist */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE654EA981B6B27E600B0F2D0 /* IJKMediaFrameworkTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE654EA9B1B6B27E600B0F2D0 /* IJKMediaFrameworkTests.m */,\n\t\t\t\tE654EA991B6B27E600B0F2D0 /* Supporting Files */,\n\t\t\t);\n\t\t\tpath = IJKMediaFrameworkTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE654EA991B6B27E600B0F2D0 /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE654EA9A1B6B27E600B0F2D0 /* Info.plist */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE66F8DBC17EEC2CF00354D80 /* Classes */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE6F727B517F2B1690043623F /* IJKMediaPlayer */,\n\t\t\t\tE67C4E0219D15B0600415CEE /* IJKAVMoviePlayerController */,\n\t\t\t\tE66F8DBE17EEC5DE00354D80 /* IJKMPMoviePlayerController */,\n\t\t\t\tE6903EBE17EAF6C500CFD954 /* IJKFFMoviePlayerController */,\n\t\t\t);\n\t\t\tname = Classes;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE66F8DBE17EEC5DE00354D80 /* IJKMPMoviePlayerController */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE66F8DBF17EEC65200354D80 /* IJKMPMoviePlayerController.h */,\n\t\t\t\tE66F8DC017EEC65200354D80 /* IJKMPMoviePlayerController.m */,\n\t\t\t);\n\t\t\tname = IJKMPMoviePlayerController;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE66F8DF817EFEC1300354D80 /* ios */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4543161F1A66481600676070 /* pipeline */,\n\t\t\t\tE66F8E0117EFEEA400354D80 /* ijkplayer_ios.m */,\n\t\t\t\tE66F8E0217EFEEA400354D80 /* ijkplayer_ios.h */,\n\t\t\t);\n\t\t\tname = ios;\n\t\t\tpath = ../../ios/IJKMediaPlayer/IJKMediaPlayer;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE67B91B11A3801E600717EA9 /* pipeline */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE67B91B21A3801E600717EA9 /* ffpipeline_ffplay.c */,\n\t\t\t\tE67B91B31A3801E600717EA9 /* ffpipeline_ffplay.h */,\n\t\t\t\tE67B91B41A3801E600717EA9 /* ffpipenode_ffplay_vdec.c */,\n\t\t\t\tE67B91B51A3801E600717EA9 /* ffpipenode_ffplay_vdec.h */,\n\t\t\t);\n\t\t\tpath = pipeline;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE67C4E0219D15B0600415CEE /* IJKAVMoviePlayerController */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE67C4E0319D15B3200415CEE /* IJKAVPlayerLayerView.h */,\n\t\t\t\tE67C4E0419D15B3200415CEE /* IJKAVPlayerLayerView.m */,\n\t\t\t\tE67C4E0619D15EEA00415CEE /* IJKAVMoviePlayerController.h */,\n\t\t\t\tE67C4E0719D15EEA00415CEE /* IJKAVMoviePlayerController.m */,\n\t\t\t);\n\t\t\tname = IJKAVMoviePlayerController;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE6903EB017EAF6C500CFD954 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE66F8DBC17EEC2CF00354D80 /* Classes */,\n\t\t\t\tE654EA8B1B6B27E600B0F2D0 /* IJKMediaFramework */,\n\t\t\t\tE654EA981B6B27E600B0F2D0 /* IJKMediaFrameworkTests */,\n\t\t\t\t5450AF9A1E63E65700568494 /* IJKMediaFrameworkWithSSL */,\n\t\t\t\tE6903EBB17EAF6C500CFD954 /* Frameworks */,\n\t\t\t\tE6903EBA17EAF6C500CFD954 /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE6903EBA17EAF6C500CFD954 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE654EA8A1B6B27E600B0F2D0 /* IJKMediaFramework.framework */,\n\t\t\t\tE654EA941B6B27E600B0F2D0 /* IJKMediaFrameworkTests.xctest */,\n\t\t\t\t5450B0431E63EA4300568494 /* IJKMediaFrameworkWithSSL.framework */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE6903EBB17EAF6C500CFD954 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t5450AF8F1E63E59800568494 /* libz.tbd */,\n\t\t\t\t5450AF8B1E63E59300568494 /* libcrypto.a */,\n\t\t\t\t5450AF8C1E63E59300568494 /* libssl.a */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE6903EBE17EAF6C500CFD954 /* IJKFFMoviePlayerController */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE6903F7617EAFC2C00CFD954 /* ffmpeg */,\n\t\t\t\tE6DBD3871C8941EB0058E4FB /* IJKFFMonitor.h */,\n\t\t\t\tE6DBD3881C8941EB0058E4FB /* IJKFFMonitor.m */,\n\t\t\t\t4D32BC801F906E3600CE9F03 /* IJKSDLGLViewProtocol.h */,\n\t\t\t\tE66F8DE517EFD9C300354D80 /* IJKFFMoviePlayerController.h */,\n\t\t\t\tE66F8DE617EFD9C300354D80 /* IJKFFMoviePlayerController.m */,\n\t\t\t\tE6F727B917F2D9D30043623F /* IJKFFMoviePlayerDef.h */,\n\t\t\t\tE6F727BA17F2D9D30043623F /* IJKFFMoviePlayerDef.m */,\n\t\t\t\tE62139BC180FA89A00553533 /* IJKFFOptions.h */,\n\t\t\t\tE62139BD180FA89A00553533 /* IJKFFOptions.m */,\n\t\t\t\tE6903FCC17EAFC6100CFD954 /* ijkmedia */,\n\t\t\t\tE6903EBF17EAF6C500CFD954 /* Supporting Files */,\n\t\t\t);\n\t\t\tname = IJKFFMoviePlayerController;\n\t\t\tpath = IJKMediaPlayer;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE6903EBF17EAF6C500CFD954 /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE6903EC017EAF6C500CFD954 /* IJKMediaPlayer-Prefix.pch */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE6903F7617EAFC2C00CFD954 /* ffmpeg */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE6903FC117EAFC2C00CFD954 /* lib */,\n\t\t\t);\n\t\t\tname = ffmpeg;\n\t\t\tpath = ../../build/universal;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE6903FC117EAFC2C00CFD954 /* lib */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE653C6EF1BCE5A750016835A /* libavcodec.a */,\n\t\t\t\tE653C6F01BCE5A750016835A /* libavfilter.a */,\n\t\t\t\tE653C6F11BCE5A750016835A /* libavformat.a */,\n\t\t\t\tE653C6F21BCE5A750016835A /* libavutil.a */,\n\t\t\t\tE653C6F31BCE5A750016835A /* libswresample.a */,\n\t\t\t\tE653C6F41BCE5A750016835A /* libswscale.a */,\n\t\t\t);\n\t\t\tpath = lib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE6903FCC17EAFC6100CFD954 /* ijkmedia */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE6903FCE17EAFC6100CFD954 /* ijkplayer */,\n\t\t\t\tE6903FDF17EAFC6100CFD954 /* ijksdl */,\n\t\t\t);\n\t\t\tname = ijkmedia;\n\t\t\tpath = ../../../ijkmedia;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE6903FCE17EAFC6100CFD954 /* ijkplayer */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE67FB4AC1B4A766F00AA94AA /* config.h */,\n\t\t\t\tE6903FD517EAFC6100CFD954 /* ff_cmdutils.c */,\n\t\t\t\tE6903FD617EAFC6100CFD954 /* ff_cmdutils.h */,\n\t\t\t\tE6903FD717EAFC6100CFD954 /* ff_fferror.h */,\n\t\t\t\tE6903FD817EAFC6100CFD954 /* ff_ffinc.h */,\n\t\t\t\tE6903FDA17EAFC6100CFD954 /* ff_ffmsg_queue.h */,\n\t\t\t\tE6903FD917EAFC6100CFD954 /* ff_ffmsg.h */,\n\t\t\t\tE67B91AB1A3801DB00717EA9 /* ff_ffpipeline.c */,\n\t\t\t\tE67B91AC1A3801DB00717EA9 /* ff_ffpipeline.h */,\n\t\t\t\tE67B91AD1A3801DB00717EA9 /* ff_ffpipenode.c */,\n\t\t\t\tE67B91AE1A3801DB00717EA9 /* ff_ffpipenode.h */,\n\t\t\t\tE6C2FD391B300A390081D321 /* ff_ffplay_debug.h */,\n\t\t\t\tE6903FDE17EAFC6100CFD954 /* ff_ffplay_def.h */,\n\t\t\t\tE6C459BC1C7089AB004831EC /* ff_ffplay_options.h */,\n\t\t\t\tE6903FDB17EAFC6100CFD954 /* ff_ffplay.c */,\n\t\t\t\tE6903FDC17EAFC6100CFD954 /* ff_ffplay.h */,\n\t\t\t\tE69BE5491B93FED300AFBA3F /* ijkavformat */,\n\t\t\t\tE69BE54E1B93FED300AFBA3F /* ijkavutil */,\n\t\t\t\tE6FAD9551A515CE300725002 /* ijkmeta.c */,\n\t\t\t\tE6FAD9561A515CE300725002 /* ijkmeta.h */,\n\t\t\t\tE66F8DEE17EFEA9400354D80 /* ijkplayer_internal.h */,\n\t\t\t\tE66F8DEF17EFEA9400354D80 /* ijkplayer.c */,\n\t\t\t\tE66F8DF017EFEA9400354D80 /* ijkplayer.h */,\n\t\t\t\tE66F8DF817EFEC1300354D80 /* ios */,\n\t\t\t\tE67B91B11A3801E600717EA9 /* pipeline */,\n\t\t\t);\n\t\t\tpath = ijkplayer;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE6903FDF17EAFC6100CFD954 /* ijksdl */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE63FC27217F013DE003551EB /* dummy */,\n\t\t\t\tE6903FEF17EAFC6100CFD954 /* ffmpeg */,\n\t\t\t\tE6C459851C7030B6004831EC /* gles2 */,\n\t\t\t\tE690400117EAFC6100CFD954 /* ijksdl_aout_internal.h */,\n\t\t\t\tE6903FFF17EAFC6100CFD954 /* ijksdl_aout.c */,\n\t\t\t\tE690400017EAFC6100CFD954 /* ijksdl_aout.h */,\n\t\t\t\tE63FC27017F01143003551EB /* ijksdl_audio.c */,\n\t\t\t\tE690400217EAFC6100CFD954 /* ijksdl_audio.h */,\n\t\t\t\tE6CA1EE71B4FAFCF00BCAF89 /* ijksdl_class.h */,\n\t\t\t\tE6C459B81C706A13004831EC /* ijksdl_egl.c */,\n\t\t\t\tE6C459B91C706A13004831EC /* ijksdl_egl.h */,\n\t\t\t\tE690400317EAFC6100CFD954 /* ijksdl_endian.h */,\n\t\t\t\tE690400417EAFC6100CFD954 /* ijksdl_error.c */,\n\t\t\t\tE690400517EAFC6100CFD954 /* ijksdl_error.h */,\n\t\t\t\tE690400617EAFC6100CFD954 /* ijksdl_fourcc.h */,\n\t\t\t\tE6C459831C7030AA004831EC /* ijksdl_gles2.h */,\n\t\t\t\tE690400717EAFC6100CFD954 /* ijksdl_inc_internal.h */,\n\t\t\t\tE6CA1EE91B4FB04500BCAF89 /* ijksdl_log.h */,\n\t\t\t\tE6CA1EE81B4FAFCF00BCAF89 /* ijksdl_misc.h */,\n\t\t\t\tE690400817EAFC6100CFD954 /* ijksdl_mutex.c */,\n\t\t\t\tE690400917EAFC6100CFD954 /* ijksdl_mutex.h */,\n\t\t\t\tE690400A17EAFC6100CFD954 /* ijksdl_stdinc.c */,\n\t\t\t\tE690400B17EAFC6100CFD954 /* ijksdl_stdinc.h */,\n\t\t\t\tE690400C17EAFC6100CFD954 /* ijksdl_thread.c */,\n\t\t\t\tE690400D17EAFC6100CFD954 /* ijksdl_thread.h */,\n\t\t\t\tE690400E17EAFC6100CFD954 /* ijksdl_timer.c */,\n\t\t\t\tE690400F17EAFC6100CFD954 /* ijksdl_timer.h */,\n\t\t\t\tE690401017EAFC6100CFD954 /* ijksdl_video.h */,\n\t\t\t\tE690401317EAFC6100CFD954 /* ijksdl_vout_internal.h */,\n\t\t\t\tE690401117EAFC6100CFD954 /* ijksdl_vout.c */,\n\t\t\t\tE690401217EAFC6100CFD954 /* ijksdl_vout.h */,\n\t\t\t\tE6903FFD17EAFC6100CFD954 /* ijksdl.h */,\n\t\t\t\tE6EE92A51878230C009EAB56 /* ios */,\n\t\t\t);\n\t\t\tpath = ijksdl;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE6903FEF17EAFC6100CFD954 /* ffmpeg */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE6903FF017EAFC6100CFD954 /* abi_all */,\n\t\t\t\tE6903FF917EAFC6100CFD954 /* ijksdl_image_convert.h */,\n\t\t\t\tE6903FFA17EAFC6100CFD954 /* ijksdl_inc_ffmpeg.h */,\n\t\t\t\tE6903FFB17EAFC6100CFD954 /* ijksdl_vout_overlay_ffmpeg.c */,\n\t\t\t\tE6903FFC17EAFC6100CFD954 /* ijksdl_vout_overlay_ffmpeg.h */,\n\t\t\t);\n\t\t\tpath = ffmpeg;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE6903FF017EAFC6100CFD954 /* abi_all */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE6903FF117EAFC6100CFD954 /* image_convert.c */,\n\t\t\t);\n\t\t\tpath = abi_all;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE69BE5491B93FED300AFBA3F /* ijkavformat */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB4449BD5250095700074CEDC /* ijklas.c */,\n\t\t\t\tB4449BD4250095700074CEDC /* ijklas.h */,\n\t\t\t\tB417F8E124F7C56C00D159BB /* cJSON.c */,\n\t\t\t\tB417F8DB24F7C3B400D159BB /* cJSON.h */,\n\t\t\t\t54A029B11D4700E6001C61C1 /* ijkasync.c */,\n\t\t\t\t4DA7F6881F2B1E270032A499 /* ijkiourlhook.c */,\n\t\t\t\t54A029B21D4700E6001C61C1 /* ijkavformat.h */,\n\t\t\t\t54A029B31D4700E6001C61C1 /* ijklongurl.c */,\n\t\t\t\t54A029B41D4700E6001C61C1 /* ijksegment.c */,\n\t\t\t\t54A029B51D4700E6001C61C1 /* ijkurlhook.c */,\n\t\t\t\tE69BE54A1B93FED300AFBA3F /* allformats.c */,\n\t\t\t\tE69BE5701B946FF600AFBA3F /* ijklivehook.c */,\n\t\t\t\t54CF8A291E1526F800309DD5 /* ijkio.c */,\n\t\t\t\t54CF8A2A1E1526F800309DD5 /* ijkioapplication.c */,\n\t\t\t\t54CF8A2B1E1526F800309DD5 /* ijkioapplication.h */,\n\t\t\t\t54CF8A2C1E1526F800309DD5 /* ijkiocache.c */,\n\t\t\t\t54CF8A2D1E1526F800309DD5 /* ijkioffio.c */,\n\t\t\t\t54CF8A2E1E1526F800309DD5 /* ijkiomanager.c */,\n\t\t\t\t54CF8A2F1E1526F800309DD5 /* ijkiomanager.h */,\n\t\t\t\t54CF8A301E1526F800309DD5 /* ijkioprotocol.c */,\n\t\t\t\t54CF8A311E1526F800309DD5 /* ijkioprotocol.h */,\n\t\t\t\t54CF8A321E1526F800309DD5 /* ijkiourl.h */,\n\t\t\t);\n\t\t\tpath = ijkavformat;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE69BE54E1B93FED300AFBA3F /* ijkavutil */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t54CF8A3D1E15287D00309DD5 /* ijkdict.c */,\n\t\t\t\t54CF8A3E1E15287D00309DD5 /* ijkdict.h */,\n\t\t\t\t54CF8A3F1E15287D00309DD5 /* ijkfifo.c */,\n\t\t\t\t54CF8A401E15287D00309DD5 /* ijkfifo.h */,\n\t\t\t\t54CF8A411E15287D00309DD5 /* ijkstl.cpp */,\n\t\t\t\t54CF8A421E15287D00309DD5 /* ijkstl.h */,\n\t\t\t\t54CF8A431E15287D00309DD5 /* ijkthreadpool.c */,\n\t\t\t\t54CF8A441E15287D00309DD5 /* ijkthreadpool.h */,\n\t\t\t\t54CF8A451E15287D00309DD5 /* ijktree.c */,\n\t\t\t\t54CF8A461E15287D00309DD5 /* ijktree.h */,\n\t\t\t\t54CF8A471E15287D00309DD5 /* ijkutils.c */,\n\t\t\t\t54CF8A481E15287D00309DD5 /* ijkutils.h */,\n\t\t\t\tE69BE54F1B93FED300AFBA3F /* opt.h */,\n\t\t\t);\n\t\t\tpath = ijkavutil;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE6C459851C7030B6004831EC /* gles2 */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE6C459861C7030B6004831EC /* color.c */,\n\t\t\t\tE6C459871C7030B6004831EC /* common.c */,\n\t\t\t\tE6C459881C7030B6004831EC /* fsh */,\n\t\t\t\tE6C4598B1C7030B6004831EC /* internal.h */,\n\t\t\t\tE6C459BE1C708CAF004831EC /* renderer_rgb.c */,\n\t\t\t\tE6C4598D1C7030B6004831EC /* renderer_yuv420p.c */,\n\t\t\t\tE6E1B9A71C741F72000C6C72 /* renderer_yuv420sp_vtb.m */,\n\t\t\t\tE6C459CA1C70967F004831EC /* renderer_yuv420sp.c */,\n\t\t\t\tE6C4598E1C7030B6004831EC /* renderer_yuv444p10le.c */,\n\t\t\t\tE6C4598C1C7030B6004831EC /* renderer.c */,\n\t\t\t\tE6C4598F1C7030B6004831EC /* shader.c */,\n\t\t\t\tE6C459901C7030B6004831EC /* vsh */,\n\t\t\t);\n\t\t\tpath = gles2;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE6C459881C7030B6004831EC /* fsh */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE6C459C21C708E60004831EC /* rgb.fsh.c */,\n\t\t\t\tE6C459891C7030B6004831EC /* yuv420p.fsh.c */,\n\t\t\t\tE6C459C61C7095E5004831EC /* yuv420sp.fsh.c */,\n\t\t\t\tE6C4598A1C7030B6004831EC /* yuv444p10le.fsh.c */,\n\t\t\t);\n\t\t\tpath = fsh;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE6C459901C7030B6004831EC /* vsh */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE6C459911C7030B6004831EC /* mvp.vsh.c */,\n\t\t\t);\n\t\t\tpath = vsh;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE6EE92A51878230C009EAB56 /* ios */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE6EE92A61878230C009EAB56 /* ijksdl_aout_ios_audiounit.h */,\n\t\t\t\tE6EE92A71878230C009EAB56 /* ijksdl_aout_ios_audiounit.m */,\n\t\t\t\tE6EE92A81878230C009EAB56 /* ijksdl_ios.h */,\n\t\t\t\tE6EE92A91878230C009EAB56 /* ijksdl_thread_ios.h */,\n\t\t\t\tE6EE92AA1878230C009EAB56 /* ijksdl_thread_ios.m */,\n\t\t\t\tE6EE92AB1878230C009EAB56 /* ijksdl_vout_ios_gles2.h */,\n\t\t\t\tE6EE92AC1878230C009EAB56 /* ijksdl_vout_ios_gles2.m */,\n\t\t\t\t45DB4AA71A5D52AE005CAD41 /* ijksdl_vout_overlay_videotoolbox.h */,\n\t\t\t\t45DB4AA81A5D52AE005CAD41 /* ijksdl_vout_overlay_videotoolbox.m */,\n\t\t\t\tE6EE92C618782770009EAB56 /* IJKSDLAudioKit.h */,\n\t\t\t\tE6EE92C718782770009EAB56 /* IJKSDLAudioKit.m */,\n\t\t\t\tE6EE92C01878236A009EAB56 /* IJKSDLAudioQueueController.h */,\n\t\t\t\tE6EE92C11878236A009EAB56 /* IJKSDLAudioQueueController.m */,\n\t\t\t\tE6EE92AD1878230C009EAB56 /* IJKSDLAudioUnitController.h */,\n\t\t\t\tE6EE92AE1878230C009EAB56 /* IJKSDLAudioUnitController.m */,\n\t\t\t\tE6EE92B61878230C009EAB56 /* IJKSDLGLView.h */,\n\t\t\t\tE6EE92B71878230C009EAB56 /* IJKSDLGLView.m */,\n\t\t\t\tE68B7ACD1C1E97B0001DE241 /* IJKSDLHudViewCell.h */,\n\t\t\t\tE68B7ACE1C1E97B0001DE241 /* IJKSDLHudViewCell.m */,\n\t\t\t\tE68B7AC31C1E7F20001DE241 /* IJKSDLHudViewController.h */,\n\t\t\t\tE68B7AC41C1E7F20001DE241 /* IJKSDLHudViewController.m */,\n\t\t\t);\n\t\t\tname = ios;\n\t\t\tpath = ../../ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE6F727B517F2B1690043623F /* IJKMediaPlayer */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE6EE92A1187810C5009EAB56 /* IJKAudioKit.h */,\n\t\t\t\tE6EE92A2187810C5009EAB56 /* IJKAudioKit.m */,\n\t\t\t\tE607FFDE1B7B60F9005F11A6 /* IJKDeviceModel.h */,\n\t\t\t\tE607FFDF1B7B60F9005F11A6 /* IJKDeviceModel.m */,\n\t\t\t\tE65DC3B719D93D5F004F8A08 /* IJKKVOController.h */,\n\t\t\t\tE65DC3B819D93D5F004F8A08 /* IJKKVOController.m */,\n\t\t\t\tE672D6F118D3445100C51FF9 /* IJKMediaModule.h */,\n\t\t\t\tE672D6F218D3445100C51FF9 /* IJKMediaModule.m */,\n\t\t\t\tE6903EC117EAF6C500CFD954 /* IJKMediaPlayback.h */,\n\t\t\t\tE6F727C117F7C9B90043623F /* IJKMediaPlayback.m */,\n\t\t\t\tE66F8DC217EECB1E00354D80 /* IJKMediaPlayer.h */,\n\t\t\t\tE6716E491807E5FC00B3FBC1 /* IJKMediaUtils.h */,\n\t\t\t\tE6716E4A1807E5FC00B3FBC1 /* IJKMediaUtils.m */,\n\t\t\t\tE698089E1C7EB2040048A46C /* IJKNotificationManager.h */,\n\t\t\t\tE698089F1C7EB2040048A46C /* IJKNotificationManager.m */,\n\t\t\t\tE69808991C7EB13A0048A46C /* NSString+IJKMedia.h */,\n\t\t\t\tE698089A1C7EB13A0048A46C /* NSString+IJKMedia.m */,\n\t\t\t);\n\t\t\tname = IJKMediaPlayer;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXHeadersBuildPhase section */\n\t\t5450B01E1E63EA4300568494 /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t5450B01F1E63EA4300568494 /* IJKFFMonitor.h in Headers */,\n\t\t\t\t5450B0201E63EA4300568494 /* ijkiourl.h in Headers */,\n\t\t\t\t5450B0211E63EA4300568494 /* IJKFFMoviePlayerController.h in Headers */,\n\t\t\t\t5450B0221E63EA4300568494 /* IJKSDLHudViewController.h in Headers */,\n\t\t\t\t5450B0231E63EA4300568494 /* IJKFFOptions.h in Headers */,\n\t\t\t\t5450B0241E63EA4300568494 /* ijkutils.h in Headers */,\n\t\t\t\t5450B0251E63EA4300568494 /* ijkdict.h in Headers */,\n\t\t\t\t5450B0261E63EA4300568494 /* IJKAVMoviePlayerController.h in Headers */,\n\t\t\t\t5450B0271E63EA4300568494 /* ijksdl_gles2.h in Headers */,\n\t\t\t\t5450B0281E63EA4300568494 /* ijksdl_egl.h in Headers */,\n\t\t\t\t549385C41E640456001AE08D /* IJKMediaFrameworkWithSSL.h in Headers */,\n\t\t\t\t5450B0291E63EA4300568494 /* ff_ffplay_options.h in Headers */,\n\t\t\t\t5450B02B1E63EA4300568494 /* IJKKVOController.h in Headers */,\n\t\t\t\t5450B02C1E63EA4300568494 /* IJKNotificationManager.h in Headers */,\n\t\t\t\t5450B02D1E63EA4300568494 /* ijkthreadpool.h in Headers */,\n\t\t\t\t5450B02E1E63EA4300568494 /* ijkiomanager.h in Headers */,\n\t\t\t\t33BA6FC0254BC4D9004EB9F2 /* ijklas.h in Headers */,\n\t\t\t\t5450B02F1E63EA4300568494 /* ijkstl.h in Headers */,\n\t\t\t\t4D32BC821F906E3B00CE9F03 /* IJKSDLGLViewProtocol.h in Headers */,\n\t\t\t\t5450B0301E63EA4300568494 /* IJKMediaModule.h in Headers */,\n\t\t\t\t5450B0311E63EA4300568494 /* ijkfifo.h in Headers */,\n\t\t\t\t5450B0321E63EA4300568494 /* ijktree.h in Headers */,\n\t\t\t\t5450B0331E63EA4300568494 /* opt.h in Headers */,\n\t\t\t\t5450B0341E63EA4300568494 /* ijkioapplication.h in Headers */,\n\t\t\t\t5450B0351E63EA4300568494 /* ijkioprotocol.h in Headers */,\n\t\t\t\t5450B0361E63EA4300568494 /* IJKMediaPlayback.h in Headers */,\n\t\t\t\t5450B0371E63EA4300568494 /* IJKMediaPlayer.h in Headers */,\n\t\t\t\t5450B0381E63EA4300568494 /* internal.h in Headers */,\n\t\t\t\t5450B0391E63EA4300568494 /* IJKVideoToolBoxSync.h in Headers */,\n\t\t\t\t5450B03A1E63EA4300568494 /* IJKMPMoviePlayerController.h in Headers */,\n\t\t\t\t5450B03B1E63EA4300568494 /* ijkavformat.h in Headers */,\n\t\t\t\t5450B03C1E63EA4300568494 /* IJKSDLHudViewCell.h in Headers */,\n\t\t\t\t5450B03D1E63EA4300568494 /* IJKVideoToolBox.h in Headers */,\n\t\t\t\t33BA6FC2254BC4DE004EB9F2 /* cJSON.h in Headers */,\n\t\t\t\t5450B03E1E63EA4300568494 /* NSString+IJKMedia.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tE654EA871B6B27E600B0F2D0 /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tE6DBD3891C8941EB0058E4FB /* IJKFFMonitor.h in Headers */,\n\t\t\t\t54CF8A3C1E1526F800309DD5 /* ijkiourl.h in Headers */,\n\t\t\t\tE654EAEA1B6B295200B0F2D0 /* IJKFFMoviePlayerController.h in Headers */,\n\t\t\t\tE68B7AC51C1E7F20001DE241 /* IJKSDLHudViewController.h in Headers */,\n\t\t\t\tE654EAEC1B6B295200B0F2D0 /* IJKFFOptions.h in Headers */,\n\t\t\t\t54CF8A541E15287D00309DD5 /* ijkutils.h in Headers */,\n\t\t\t\t54CF8A4A1E15287D00309DD5 /* ijkdict.h in Headers */,\n\t\t\t\tE654EAE81B6B295200B0F2D0 /* IJKAVMoviePlayerController.h in Headers */,\n\t\t\t\tE6C459841C7030AA004831EC /* ijksdl_gles2.h in Headers */,\n\t\t\t\tE6C459BB1C706A13004831EC /* ijksdl_egl.h in Headers */,\n\t\t\t\tE6C459BD1C7089AB004831EC /* ff_ffplay_options.h in Headers */,\n\t\t\t\tE654EA8F1B6B27E600B0F2D0 /* IJKMediaFramework.h in Headers */,\n\t\t\t\tE6C2E7BE1C92BD3600E59229 /* IJKKVOController.h in Headers */,\n\t\t\t\tE69808A01C7EB2040048A46C /* IJKNotificationManager.h in Headers */,\n\t\t\t\tB417F8DE24F7C3B500D159BB /* cJSON.h in Headers */,\n\t\t\t\t54CF8A501E15287D00309DD5 /* ijkthreadpool.h in Headers */,\n\t\t\t\t54CF8A391E1526F800309DD5 /* ijkiomanager.h in Headers */,\n\t\t\t\t54CF8A4E1E15287D00309DD5 /* ijkstl.h in Headers */,\n\t\t\t\t4D32BC811F906E3A00CE9F03 /* IJKSDLGLViewProtocol.h in Headers */,\n\t\t\t\tE654EAE61B6B295200B0F2D0 /* IJKMediaModule.h in Headers */,\n\t\t\t\t54CF8A4C1E15287D00309DD5 /* ijkfifo.h in Headers */,\n\t\t\t\t54CF8A521E15287D00309DD5 /* ijktree.h in Headers */,\n\t\t\t\tE69BE5571B93FED300AFBA3F /* opt.h in Headers */,\n\t\t\t\t54CF8A351E1526F800309DD5 /* ijkioapplication.h in Headers */,\n\t\t\t\t54CF8A3B1E1526F800309DD5 /* ijkioprotocol.h in Headers */,\n\t\t\t\tB4449BD6250095700074CEDC /* ijklas.h in Headers */,\n\t\t\t\tE654EAE71B6B295200B0F2D0 /* IJKMediaPlayback.h in Headers */,\n\t\t\t\tE654EAED1B6B29C100B0F2D0 /* IJKMediaPlayer.h in Headers */,\n\t\t\t\tE6C459961C7030B6004831EC /* internal.h in Headers */,\n\t\t\t\t5407EC2D1DF81D2600457BFE /* IJKVideoToolBoxSync.h in Headers */,\n\t\t\t\tE654EAE91B6B295200B0F2D0 /* IJKMPMoviePlayerController.h in Headers */,\n\t\t\t\t54A029B71D4700E6001C61C1 /* ijkavformat.h in Headers */,\n\t\t\t\tE68B7ACF1C1E97B0001DE241 /* IJKSDLHudViewCell.h in Headers */,\n\t\t\t\t5407EC291DF7F93B00457BFE /* IJKVideoToolBox.h in Headers */,\n\t\t\t\tE698089B1C7EB13A0048A46C /* NSString+IJKMedia.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXHeadersBuildPhase section */\n\n/* Begin PBXNativeTarget section */\n\t\t5450AFC11E63EA4300568494 /* IJKMediaFrameworkWithSSL */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 5450B0401E63EA4300568494 /* Build configuration list for PBXNativeTarget \"IJKMediaFrameworkWithSSL\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t5450AFC21E63EA4300568494 /* ijkversion.h */,\n\t\t\t\t5450AFC31E63EA4300568494 /* Sources */,\n\t\t\t\t5450B0171E63EA4300568494 /* Frameworks */,\n\t\t\t\t5450B01E1E63EA4300568494 /* Headers */,\n\t\t\t\t5450B03F1E63EA4300568494 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = IJKMediaFrameworkWithSSL;\n\t\t\tproductName = IJKMediaFramework;\n\t\t\tproductReference = 5450B0431E63EA4300568494 /* IJKMediaFrameworkWithSSL.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\tE654EA891B6B27E600B0F2D0 /* IJKMediaFramework */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = E654EAA11B6B27E600B0F2D0 /* Build configuration list for PBXNativeTarget \"IJKMediaFramework\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t544E73271D93DEF4005CA5D9 /* ijkversion.h */,\n\t\t\t\tE654EA851B6B27E600B0F2D0 /* Sources */,\n\t\t\t\tE654EA861B6B27E600B0F2D0 /* Frameworks */,\n\t\t\t\tE654EA871B6B27E600B0F2D0 /* Headers */,\n\t\t\t\tE654EA881B6B27E600B0F2D0 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = IJKMediaFramework;\n\t\t\tproductName = IJKMediaFramework;\n\t\t\tproductReference = E654EA8A1B6B27E600B0F2D0 /* IJKMediaFramework.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\tE654EA931B6B27E600B0F2D0 /* IJKMediaFrameworkTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = E654EAA21B6B27E600B0F2D0 /* Build configuration list for PBXNativeTarget \"IJKMediaFrameworkTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tE654EA901B6B27E600B0F2D0 /* Sources */,\n\t\t\t\tE654EA911B6B27E600B0F2D0 /* Frameworks */,\n\t\t\t\tE654EA921B6B27E600B0F2D0 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\tE654EA971B6B27E600B0F2D0 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = IJKMediaFrameworkTests;\n\t\t\tproductName = IJKMediaFrameworkTests;\n\t\t\tproductReference = E654EA941B6B27E600B0F2D0 /* IJKMediaFrameworkTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tE6903EB117EAF6C500CFD954 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 0700;\n\t\t\t\tORGANIZATIONNAME = bilibili;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tE654EA891B6B27E600B0F2D0 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.4;\n\t\t\t\t\t};\n\t\t\t\t\tE654EA931B6B27E600B0F2D0 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.4;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = E6903EB417EAF6C500CFD954 /* Build configuration list for PBXProject \"IJKMediaPlayer\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = English;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\tEnglish,\n\t\t\t\ten,\n\t\t\t);\n\t\t\tmainGroup = E6903EB017EAF6C500CFD954;\n\t\t\tproductRefGroup = E6903EBA17EAF6C500CFD954 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tE654EA891B6B27E600B0F2D0 /* IJKMediaFramework */,\n\t\t\t\t5450AFC11E63EA4300568494 /* IJKMediaFrameworkWithSSL */,\n\t\t\t\tE654EA931B6B27E600B0F2D0 /* IJKMediaFrameworkTests */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t5450B03F1E63EA4300568494 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tE654EA881B6B27E600B0F2D0 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tE654EA921B6B27E600B0F2D0 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t544E73271D93DEF4005CA5D9 /* ijkversion.h */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = ijkversion.h;\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"sh \\\"${PROJECT_DIR}/../../ijkmedia/ijkplayer/version.sh\\\" \\\"${PROJECT_DIR}/../../ijkmedia/ijkplayer\\\" \\\"ijkversion.h\\\"\";\n\t\t};\n\t\t5450AFC21E63EA4300568494 /* ijkversion.h */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = ijkversion.h;\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"sh \\\"${PROJECT_DIR}/../../ijkmedia/ijkplayer/version.sh\\\" \\\"${PROJECT_DIR}/../../ijkmedia/ijkplayer\\\" \\\"ijkversion.h\\\"\";\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t5450AFC31E63EA4300568494 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t5450AFC41E63EA4300568494 /* IJKKVOController.m in Sources */,\n\t\t\t\t5450AFC51E63EA4300568494 /* ijksdl_vout.c in Sources */,\n\t\t\t\t5450AFC61E63EA4300568494 /* yuv444p10le.fsh.c in Sources */,\n\t\t\t\t5450AFC71E63EA4300568494 /* allformats.c in Sources */,\n\t\t\t\t5450AFC81E63EA4300568494 /* ffpipenode_ffplay_vdec.c in Sources */,\n\t\t\t\t5450AFC91E63EA4300568494 /* renderer_yuv420p.c in Sources */,\n\t\t\t\t5450AFCA1E63EA4300568494 /* ijkthreadpool.c in Sources */,\n\t\t\t\t5450AFCB1E63EA4300568494 /* IJKAVMoviePlayerController.m in Sources */,\n\t\t\t\t5450AFCC1E63EA4300568494 /* IJKFFMoviePlayerDef.m in Sources */,\n\t\t\t\t5450AFCD1E63EA4300568494 /* ijkplayer_ios.m in Sources */,\n\t\t\t\t5450AFCE1E63EA4300568494 /* ffpipeline_ios.c in Sources */,\n\t\t\t\t5450AFCF1E63EA4300568494 /* ijkioprotocol.c in Sources */,\n\t\t\t\t5450AFD01E63EA4300568494 /* ijksdl_vout_dummy.c in Sources */,\n\t\t\t\t5450AFD11E63EA4300568494 /* renderer_yuv420sp.c in Sources */,\n\t\t\t\t5450AFD21E63EA4300568494 /* yuv420p.fsh.c in Sources */,\n\t\t\t\t5450AFD31E63EA4300568494 /* ijksdl_error.c in Sources */,\n\t\t\t\t5450AFD41E63EA4300568494 /* IJKDeviceModel.m in Sources */,\n\t\t\t\t5450AFD51E63EA4300568494 /* ijkiocache.c in Sources */,\n\t\t\t\t5450AFD61E63EA4300568494 /* ijksdl_egl.c in Sources */,\n\t\t\t\t5450AFD71E63EA4300568494 /* ijkio.c in Sources */,\n\t\t\t\t5450AFD81E63EA4300568494 /* IJKAudioKit.m in Sources */,\n\t\t\t\t5450AFD91E63EA4300568494 /* IJKMPMoviePlayerController.m in Sources */,\n\t\t\t\t5450AFDA1E63EA4300568494 /* IJKSDLHudViewCell.m in Sources */,\n\t\t\t\t5450AFDB1E63EA4300568494 /* ijksdl_vout_overlay_videotoolbox.m in Sources */,\n\t\t\t\t5450AFDC1E63EA4300568494 /* ff_ffpipenode.c in Sources */,\n\t\t\t\t5450AFDD1E63EA4300568494 /* ijksdl_stdinc.c in Sources */,\n\t\t\t\t5450AFDE1E63EA4300568494 /* IJKVideoToolBox.m in Sources */,\n\t\t\t\t5450AFDF1E63EA4300568494 /* ijksegment.c in Sources */,\n\t\t\t\t5450AFE01E63EA4300568494 /* IJKMediaUtils.m in Sources */,\n\t\t\t\t5450AFE11E63EA4300568494 /* common.c in Sources */,\n\t\t\t\t5450AFE21E63EA4300568494 /* ijksdl_aout_ios_audiounit.m in Sources */,\n\t\t\t\t5450AFE31E63EA4300568494 /* ijklivehook.c in Sources */,\n\t\t\t\t5450AFE41E63EA4300568494 /* ijkurlhook.c in Sources */,\n\t\t\t\t5450AFE51E63EA4300568494 /* IJKVideoToolBoxSync.m in Sources */,\n\t\t\t\t5450AFE61E63EA4300568494 /* IJKMediaPlayback.m in Sources */,\n\t\t\t\t5450AFE71E63EA4300568494 /* ijkdict.c in Sources */,\n\t\t\t\t5450AFE81E63EA4300568494 /* ff_ffpipeline.c in Sources */,\n\t\t\t\t4DA7F68A1F2B1E270032A499 /* ijkiourlhook.c in Sources */,\n\t\t\t\t5450AFE91E63EA4300568494 /* IJKSDLAudioKit.m in Sources */,\n\t\t\t\t5450AFEA1E63EA4300568494 /* mvp.vsh.c in Sources */,\n\t\t\t\t5450AFEB1E63EA4300568494 /* NSString+IJKMedia.m in Sources */,\n\t\t\t\t5450AFEC1E63EA4300568494 /* ijksdl_vout_overlay_ffmpeg.c in Sources */,\n\t\t\t\t5450AFED1E63EA4300568494 /* ijksdl_mutex.c in Sources */,\n\t\t\t\t33BA6FC1254BC4DC004EB9F2 /* cJSON.c in Sources */,\n\t\t\t\t5450AFEE1E63EA4300568494 /* ijktree.c in Sources */,\n\t\t\t\t5450AFEF1E63EA4300568494 /* IJKSDLAudioQueueController.m in Sources */,\n\t\t\t\t5450AFF01E63EA4300568494 /* ijksdl_thread.c in Sources */,\n\t\t\t\t5450AFF11E63EA4300568494 /* yuv420sp.fsh.c in Sources */,\n\t\t\t\t5450AFF21E63EA4300568494 /* ff_ffplay.c in Sources */,\n\t\t\t\t5450AFF31E63EA4300568494 /* ijksdl_aout.c in Sources */,\n\t\t\t\t5450AFF41E63EA4300568494 /* color.c in Sources */,\n\t\t\t\t5450AFF51E63EA4300568494 /* ijksdl_audio.c in Sources */,\n\t\t\t\t5450AFF61E63EA4300568494 /* ijksdl_thread_ios.m in Sources */,\n\t\t\t\t5450AFF71E63EA4300568494 /* ijkmeta.c in Sources */,\n\t\t\t\t5450AFF81E63EA4300568494 /* ijkasync.c in Sources */,\n\t\t\t\t5450AFF91E63EA4300568494 /* renderer_yuv420sp_vtb.m in Sources */,\n\t\t\t\t5450AFFA1E63EA4300568494 /* ijkutils.c in Sources */,\n\t\t\t\t5450AFFB1E63EA4300568494 /* IJKSDLGLView.m in Sources */,\n\t\t\t\t33BA6FBF254BC4D7004EB9F2 /* ijklas.c in Sources */,\n\t\t\t\t5450AFFC1E63EA4300568494 /* ijksdl_timer.c in Sources */,\n\t\t\t\t5450AFFD1E63EA4300568494 /* ijkfifo.c in Sources */,\n\t\t\t\t5450AFFE1E63EA4300568494 /* shader.c in Sources */,\n\t\t\t\t5450AFFF1E63EA4300568494 /* ijkioffio.c in Sources */,\n\t\t\t\t5450B0001E63EA4300568494 /* renderer.c in Sources */,\n\t\t\t\t5450B0011E63EA4300568494 /* ijkioapplication.c in Sources */,\n\t\t\t\t5450B0021E63EA4300568494 /* ijkiomanager.c in Sources */,\n\t\t\t\t5450B0031E63EA4300568494 /* ijkplayer.c in Sources */,\n\t\t\t\t5450B0041E63EA4300568494 /* IJKFFOptions.m in Sources */,\n\t\t\t\t5450B0051E63EA4300568494 /* IJKSDLAudioUnitController.m in Sources */,\n\t\t\t\t5450B0061E63EA4300568494 /* IJKFFMonitor.m in Sources */,\n\t\t\t\t5450B0071E63EA4300568494 /* IJKFFMoviePlayerController.m in Sources */,\n\t\t\t\t5450B0081E63EA4300568494 /* IJKNotificationManager.m in Sources */,\n\t\t\t\t5450B0091E63EA4300568494 /* IJKMediaModule.m in Sources */,\n\t\t\t\t5450B00A1E63EA4300568494 /* ff_cmdutils.c in Sources */,\n\t\t\t\t5450B00B1E63EA4300568494 /* IJKVideoToolBoxAsync.m in Sources */,\n\t\t\t\t5450B00C1E63EA4300568494 /* renderer_yuv444p10le.c in Sources */,\n\t\t\t\t5450B00D1E63EA4300568494 /* ijkstl.cpp in Sources */,\n\t\t\t\t5450B00E1E63EA4300568494 /* image_convert.c in Sources */,\n\t\t\t\t5450B00F1E63EA4300568494 /* rgb.fsh.c in Sources */,\n\t\t\t\t5450B0101E63EA4300568494 /* ffpipenode_ios_videotoolbox_vdec.m in Sources */,\n\t\t\t\t5450B0111E63EA4300568494 /* IJKAVPlayerLayerView.m in Sources */,\n\t\t\t\t5450B0121E63EA4300568494 /* IJKSDLHudViewController.m in Sources */,\n\t\t\t\t5450B0131E63EA4300568494 /* ijksdl_vout_ios_gles2.m in Sources */,\n\t\t\t\t5450B0141E63EA4300568494 /* ijklongurl.c in Sources */,\n\t\t\t\t5450B0151E63EA4300568494 /* renderer_rgb.c in Sources */,\n\t\t\t\t5450B0161E63EA4300568494 /* ffpipeline_ffplay.c in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tE654EA851B6B27E600B0F2D0 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tE654EAA71B6B283700B0F2D0 /* IJKKVOController.m in Sources */,\n\t\t\t\tE654EAC71B6B287E00B0F2D0 /* ijksdl_vout.c in Sources */,\n\t\t\t\tE6C459951C7030B6004831EC /* yuv444p10le.fsh.c in Sources */,\n\t\t\t\tE69BE5511B93FED300AFBA3F /* allformats.c in Sources */,\n\t\t\t\tE654EABB1B6B286B00B0F2D0 /* ffpipenode_ffplay_vdec.c in Sources */,\n\t\t\t\tE6C459981C7030B6004831EC /* renderer_yuv420p.c in Sources */,\n\t\t\t\t54CF8A4F1E15287D00309DD5 /* ijkthreadpool.c in Sources */,\n\t\t\t\tE654EAA91B6B283D00B0F2D0 /* IJKAVMoviePlayerController.m in Sources */,\n\t\t\t\tB417F8E224F7C56C00D159BB /* cJSON.c in Sources */,\n\t\t\t\tE654EAAC1B6B284C00B0F2D0 /* IJKFFMoviePlayerDef.m in Sources */,\n\t\t\t\tE654EAB91B6B286700B0F2D0 /* ijkplayer_ios.m in Sources */,\n\t\t\t\tE654EAB51B6B286400B0F2D0 /* ffpipeline_ios.c in Sources */,\n\t\t\t\t54CF8A3A1E1526F800309DD5 /* ijkioprotocol.c in Sources */,\n\t\t\t\tE654EABD1B6B287000B0F2D0 /* ijksdl_vout_dummy.c in Sources */,\n\t\t\t\tE6C459CC1C70967F004831EC /* renderer_yuv420sp.c in Sources */,\n\t\t\t\tE6C459941C7030B6004831EC /* yuv420p.fsh.c in Sources */,\n\t\t\t\tE654EAC21B6B287E00B0F2D0 /* ijksdl_error.c in Sources */,\n\t\t\t\tE607FFE11B7B62E3005F11A6 /* IJKDeviceModel.m in Sources */,\n\t\t\t\t54CF8A361E1526F800309DD5 /* ijkiocache.c in Sources */,\n\t\t\t\tE6C459BA1C706A13004831EC /* ijksdl_egl.c in Sources */,\n\t\t\t\t54CF8A331E1526F800309DD5 /* ijkio.c in Sources */,\n\t\t\t\tE654EAA31B6B283700B0F2D0 /* IJKAudioKit.m in Sources */,\n\t\t\t\tE654EAAA1B6B284300B0F2D0 /* IJKMPMoviePlayerController.m in Sources */,\n\t\t\t\tE68B7AD01C1E97B0001DE241 /* IJKSDLHudViewCell.m in Sources */,\n\t\t\t\tE654EACB1B6B288A00B0F2D0 /* ijksdl_vout_overlay_videotoolbox.m in Sources */,\n\t\t\t\tE654EAB11B6B285900B0F2D0 /* ff_ffpipenode.c in Sources */,\n\t\t\t\tE654EAC41B6B287E00B0F2D0 /* ijksdl_stdinc.c in Sources */,\n\t\t\t\t5407EC2A1DF7F93B00457BFE /* IJKVideoToolBox.m in Sources */,\n\t\t\t\t54A029B91D4700E6001C61C1 /* ijksegment.c in Sources */,\n\t\t\t\tE654EAA61B6B283700B0F2D0 /* IJKMediaUtils.m in Sources */,\n\t\t\t\tE6C459931C7030B6004831EC /* common.c in Sources */,\n\t\t\t\tE654EAC81B6B288A00B0F2D0 /* ijksdl_aout_ios_audiounit.m in Sources */,\n\t\t\t\tE69BE5721B946FF600AFBA3F /* ijklivehook.c in Sources */,\n\t\t\t\t54A029BA1D4700E6001C61C1 /* ijkurlhook.c in Sources */,\n\t\t\t\t5407EC2E1DF81D2600457BFE /* IJKVideoToolBoxSync.m in Sources */,\n\t\t\t\tE654EAA51B6B283700B0F2D0 /* IJKMediaPlayback.m in Sources */,\n\t\t\t\t54CF8A491E15287D00309DD5 /* ijkdict.c in Sources */,\n\t\t\t\tE654EAB01B6B285900B0F2D0 /* ff_ffpipeline.c in Sources */,\n\t\t\t\t4DA7F6891F2B1E270032A499 /* ijkiourlhook.c in Sources */,\n\t\t\t\tE654EACC1B6B288A00B0F2D0 /* IJKSDLAudioKit.m in Sources */,\n\t\t\t\tE6C4599B1C7030B6004831EC /* mvp.vsh.c in Sources */,\n\t\t\t\tE698089C1C7EB13A0048A46C /* NSString+IJKMedia.m in Sources */,\n\t\t\t\tE654EABF1B6B287600B0F2D0 /* ijksdl_vout_overlay_ffmpeg.c in Sources */,\n\t\t\t\tE654EAC31B6B287E00B0F2D0 /* ijksdl_mutex.c in Sources */,\n\t\t\t\t54CF8A511E15287D00309DD5 /* ijktree.c in Sources */,\n\t\t\t\tE654EACD1B6B288A00B0F2D0 /* IJKSDLAudioQueueController.m in Sources */,\n\t\t\t\tE654EAC51B6B287E00B0F2D0 /* ijksdl_thread.c in Sources */,\n\t\t\t\tE6C459C81C7095E5004831EC /* yuv420sp.fsh.c in Sources */,\n\t\t\t\tE654EAB21B6B285900B0F2D0 /* ff_ffplay.c in Sources */,\n\t\t\t\tE654EAC01B6B287E00B0F2D0 /* ijksdl_aout.c in Sources */,\n\t\t\t\tE6C459921C7030B6004831EC /* color.c in Sources */,\n\t\t\t\tE654EAC11B6B287E00B0F2D0 /* ijksdl_audio.c in Sources */,\n\t\t\t\tE654EAC91B6B288A00B0F2D0 /* ijksdl_thread_ios.m in Sources */,\n\t\t\t\tE654EAB31B6B285900B0F2D0 /* ijkmeta.c in Sources */,\n\t\t\t\t54A029B61D4700E6001C61C1 /* ijkasync.c in Sources */,\n\t\t\t\tE6E1B9A81C741F72000C6C72 /* renderer_yuv420sp_vtb.m in Sources */,\n\t\t\t\t54CF8A531E15287D00309DD5 /* ijkutils.c in Sources */,\n\t\t\t\tE654EAD31B6B288A00B0F2D0 /* IJKSDLGLView.m in Sources */,\n\t\t\t\tE654EAC61B6B287E00B0F2D0 /* ijksdl_timer.c in Sources */,\n\t\t\t\t54CF8A4B1E15287D00309DD5 /* ijkfifo.c in Sources */,\n\t\t\t\tE6C4599A1C7030B6004831EC /* shader.c in Sources */,\n\t\t\t\t54CF8A371E1526F800309DD5 /* ijkioffio.c in Sources */,\n\t\t\t\tE6C459971C7030B6004831EC /* renderer.c in Sources */,\n\t\t\t\t54CF8A341E1526F800309DD5 /* ijkioapplication.c in Sources */,\n\t\t\t\t54CF8A381E1526F800309DD5 /* ijkiomanager.c in Sources */,\n\t\t\t\tE654EAB41B6B285900B0F2D0 /* ijkplayer.c in Sources */,\n\t\t\t\tE654EAAE1B6B284C00B0F2D0 /* IJKFFOptions.m in Sources */,\n\t\t\t\tE654EACE1B6B288A00B0F2D0 /* IJKSDLAudioUnitController.m in Sources */,\n\t\t\t\tE6DBD38A1C8941EB0058E4FB /* IJKFFMonitor.m in Sources */,\n\t\t\t\tE654EAAB1B6B284C00B0F2D0 /* IJKFFMoviePlayerController.m in Sources */,\n\t\t\t\tE69808A11C7EB2040048A46C /* IJKNotificationManager.m in Sources */,\n\t\t\t\tE654EAA41B6B283700B0F2D0 /* IJKMediaModule.m in Sources */,\n\t\t\t\tE654EAAF1B6B285900B0F2D0 /* ff_cmdutils.c in Sources */,\n\t\t\t\tE654EAB81B6B286400B0F2D0 /* IJKVideoToolBoxAsync.m in Sources */,\n\t\t\t\tE6C459991C7030B6004831EC /* renderer_yuv444p10le.c in Sources */,\n\t\t\t\t54CF8A4D1E15287D00309DD5 /* ijkstl.cpp in Sources */,\n\t\t\t\tE654EABE1B6B287400B0F2D0 /* image_convert.c in Sources */,\n\t\t\t\tB4449BD7250095700074CEDC /* ijklas.c in Sources */,\n\t\t\t\tE6C459C41C708E60004831EC /* rgb.fsh.c in Sources */,\n\t\t\t\tE654EAB61B6B286400B0F2D0 /* ffpipenode_ios_videotoolbox_vdec.m in Sources */,\n\t\t\t\tE654EAA81B6B283D00B0F2D0 /* IJKAVPlayerLayerView.m in Sources */,\n\t\t\t\tE68B7AC61C1E7F20001DE241 /* IJKSDLHudViewController.m in Sources */,\n\t\t\t\tE654EACA1B6B288A00B0F2D0 /* ijksdl_vout_ios_gles2.m in Sources */,\n\t\t\t\t54A029B81D4700E6001C61C1 /* ijklongurl.c in Sources */,\n\t\t\t\tE6C459C01C708CAF004831EC /* renderer_rgb.c in Sources */,\n\t\t\t\tE654EABA1B6B286B00B0F2D0 /* ffpipeline_ffplay.c in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tE654EA901B6B27E600B0F2D0 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tE654EA9C1B6B27E600B0F2D0 /* IJKMediaFrameworkTests.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\tE654EA971B6B27E600B0F2D0 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = E654EA891B6B27E600B0F2D0 /* IJKMediaFramework */;\n\t\t\ttargetProxy = E654EA961B6B27E600B0F2D0 /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin XCBuildConfiguration section */\n\t\t5450B0411E63EA4300568494 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"\";\n\t\t\t\tCURRENT_PROJECT_VERSION = 0.8.8;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tHEADER_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t../build/universal/include,\n\t\t\t\t\tIJKMediaPlayer/ijkmedia,\n\t\t\t\t\t../../ijkmedia,\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/IJKMediaFrameworkWithSSL.plist\";\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tLIBRARY_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"\\\"$(SRCROOT)/../build/universal/lib\\\"\",\n\t\t\t\t);\n\t\t\t\tMACH_O_TYPE = mh_dylib;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tOTHER_LDFLAGS = (\n\t\t\t\t\t\"-read_only_relocs\",\n\t\t\t\t\tsuppress,\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"tv.danmaku.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t5450B0421E63EA4300568494 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"\";\n\t\t\t\tCURRENT_PROJECT_VERSION = 0.8.8;\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tHEADER_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t../build/universal/include,\n\t\t\t\t\tIJKMediaPlayer/ijkmedia,\n\t\t\t\t\t../../ijkmedia,\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/IJKMediaFrameworkWithSSL.plist\";\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tLIBRARY_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"\\\"$(SRCROOT)/../build/universal/lib\\\"\",\n\t\t\t\t);\n\t\t\t\tMACH_O_TYPE = mh_dylib;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tOTHER_LDFLAGS = (\n\t\t\t\t\t\"-read_only_relocs\",\n\t\t\t\t\tsuppress,\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"tv.danmaku.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tE654EA9D1B6B27E600B0F2D0 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCURRENT_PROJECT_VERSION = 0.8.8;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tHEADER_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t../build/universal/include,\n\t\t\t\t\tIJKMediaPlayer/ijkmedia,\n\t\t\t\t\t../../ijkmedia,\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = IJKMediaFramework/Info.plist;\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 7.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tLIBRARY_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"\\\"$(SRCROOT)/../build/universal/lib\\\"\",\n\t\t\t\t);\n\t\t\t\tMACH_O_TYPE = staticlib;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"tv.danmaku.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tE654EA9E1B6B27E600B0F2D0 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCURRENT_PROJECT_VERSION = 0.8.8;\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tHEADER_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t../build/universal/include,\n\t\t\t\t\tIJKMediaPlayer/ijkmedia,\n\t\t\t\t\t../../ijkmedia,\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = IJKMediaFramework/Info.plist;\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 7.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tLIBRARY_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"\\\"$(SRCROOT)/../build/universal/lib\\\"\",\n\t\t\t\t);\n\t\t\t\tMACH_O_TYPE = staticlib;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"tv.danmaku.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tE654EA9F1B6B27E600B0F2D0 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(SDKROOT)/Developer/Library/Frameworks\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tINFOPLIST_FILE = IJKMediaFrameworkTests/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.4;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"tv.danmaku.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tE654EAA01B6B27E600B0F2D0 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(SDKROOT)/Developer/Library/Frameworks\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tINFOPLIST_FILE = IJKMediaFrameworkTests/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.4;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"tv.danmaku.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tE6903EC517EAF6C500CFD954 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_SYMBOLS_PRIVATE_EXTERN = NO;\n\t\t\t\tGCC_WARN_ABOUT_MISSING_NEWLINE = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES;\n\t\t\t\tGCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;\n\t\t\t\tGCC_WARN_SHADOW = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 7.0;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSTRIP_INSTALLED_PRODUCT = NO;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tE6903EC617EAF6C500CFD954 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_WARN_ABOUT_MISSING_NEWLINE = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES;\n\t\t\t\tGCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;\n\t\t\t\tGCC_WARN_SHADOW = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 7.0;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSTRIP_INSTALLED_PRODUCT = NO;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t5450B0401E63EA4300568494 /* Build configuration list for PBXNativeTarget \"IJKMediaFrameworkWithSSL\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t5450B0411E63EA4300568494 /* Debug */,\n\t\t\t\t5450B0421E63EA4300568494 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tE654EAA11B6B27E600B0F2D0 /* Build configuration list for PBXNativeTarget \"IJKMediaFramework\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tE654EA9D1B6B27E600B0F2D0 /* Debug */,\n\t\t\t\tE654EA9E1B6B27E600B0F2D0 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tE654EAA21B6B27E600B0F2D0 /* Build configuration list for PBXNativeTarget \"IJKMediaFrameworkTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tE654EA9F1B6B27E600B0F2D0 /* Debug */,\n\t\t\t\tE654EAA01B6B27E600B0F2D0 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tE6903EB417EAF6C500CFD954 /* Build configuration list for PBXProject \"IJKMediaPlayer\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tE6903EC517EAF6C500CFD954 /* Debug */,\n\t\t\t\tE6903EC617EAF6C500CFD954 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = E6903EB117EAF6C500CFD954 /* Project object */;\n}\n"
  },
  {
    "path": "ios/IJKMediaPlayer/IJKMediaPlayer.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "ios/IJKMediaPodDemo/.gitignore",
    "content": "IJKMediaPodDemo.xcworkspace\nPods\nPodfile.lock\n"
  },
  {
    "path": "ios/IJKMediaPodDemo/IJKMediaPodDemo/AppDelegate.h",
    "content": "//\n//  AppDelegate.h\n//  IJKMediaPodDemo\n//\n//  Created by Zhang Rui on 15/7/23.\n//  Copyright (c) 2015年 Zhang Rui. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface AppDelegate : UIResponder <UIApplicationDelegate>\n\n@property (strong, nonatomic) UIWindow *window;\n\n\n@end\n\n"
  },
  {
    "path": "ios/IJKMediaPodDemo/IJKMediaPodDemo/AppDelegate.m",
    "content": "//\n//  AppDelegate.m\n//  IJKMediaPodDemo\n//\n//  Created by Zhang Rui on 15/7/23.\n//  Copyright (c) 2015年 Zhang Rui. All rights reserved.\n//\n\n#import \"AppDelegate.h\"\n\n@interface AppDelegate ()\n\n@end\n\n@implementation AppDelegate\n\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {\n    // Override point for customization after application launch.\n    return YES;\n}\n\n- (void)applicationWillResignActive:(UIApplication *)application {\n    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.\n    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.\n}\n\n- (void)applicationDidEnterBackground:(UIApplication *)application {\n    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.\n    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.\n}\n\n- (void)applicationWillEnterForeground:(UIApplication *)application {\n    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.\n}\n\n- (void)applicationDidBecomeActive:(UIApplication *)application {\n    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.\n}\n\n- (void)applicationWillTerminate:(UIApplication *)application {\n    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPodDemo/IJKMediaPodDemo/Base.lproj/LaunchScreen.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVersion=\"6214\" systemVersion=\"14A314h\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"6207\"/>\n        <capability name=\"Constraints with non-1.0 multipliers\" minToolsVersion=\"5.1\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\"/>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"iN0-l3-epB\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"480\" height=\"480\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <label opaque=\"NO\" clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"  Copyright (c) 2015年 Zhang Rui. All rights reserved.\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" minimumFontSize=\"9\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"8ie-xW-0ye\">\n                    <rect key=\"frame\" x=\"20\" y=\"439\" width=\"441\" height=\"21\"/>\n                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                    <color key=\"textColor\" cocoaTouchSystemColor=\"darkTextColor\"/>\n                    <nil key=\"highlightedColor\"/>\n                </label>\n                <label opaque=\"NO\" clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"IJKMediaPodDemo\" textAlignment=\"center\" lineBreakMode=\"middleTruncation\" baselineAdjustment=\"alignBaselines\" minimumFontSize=\"18\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"kId-c2-rCX\">\n                    <rect key=\"frame\" x=\"20\" y=\"140\" width=\"441\" height=\"43\"/>\n                    <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"36\"/>\n                    <color key=\"textColor\" cocoaTouchSystemColor=\"darkTextColor\"/>\n                    <nil key=\"highlightedColor\"/>\n                </label>\n            </subviews>\n            <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n            <constraints>\n                <constraint firstItem=\"kId-c2-rCX\" firstAttribute=\"centerY\" secondItem=\"iN0-l3-epB\" secondAttribute=\"bottom\" multiplier=\"1/3\" constant=\"1\" id=\"5cJ-9S-tgC\"/>\n                <constraint firstAttribute=\"centerX\" secondItem=\"kId-c2-rCX\" secondAttribute=\"centerX\" id=\"Koa-jz-hwk\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"8ie-xW-0ye\" secondAttribute=\"bottom\" constant=\"20\" id=\"Kzo-t9-V3l\"/>\n                <constraint firstItem=\"8ie-xW-0ye\" firstAttribute=\"leading\" secondItem=\"iN0-l3-epB\" secondAttribute=\"leading\" constant=\"20\" symbolic=\"YES\" id=\"MfP-vx-nX0\"/>\n                <constraint firstAttribute=\"centerX\" secondItem=\"8ie-xW-0ye\" secondAttribute=\"centerX\" id=\"ZEH-qu-HZ9\"/>\n                <constraint firstItem=\"kId-c2-rCX\" firstAttribute=\"leading\" secondItem=\"iN0-l3-epB\" secondAttribute=\"leading\" constant=\"20\" symbolic=\"YES\" id=\"fvb-Df-36g\"/>\n            </constraints>\n            <nil key=\"simulatedStatusBarMetrics\"/>\n            <freeformSimulatedSizeMetrics key=\"simulatedDestinationMetrics\"/>\n            <point key=\"canvasLocation\" x=\"548\" y=\"455\"/>\n        </view>\n    </objects>\n</document>\n"
  },
  {
    "path": "ios/IJKMediaPodDemo/IJKMediaPodDemo/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"6211\" systemVersion=\"14A298i\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"6204\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" customModuleProvider=\"\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"y3c-jy-aDJ\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"wfy-db-euE\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"600\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "ios/IJKMediaPodDemo/IJKMediaPodDemo/Images.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/IJKMediaPodDemo/IJKMediaPodDemo/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>tv.danmaku.$(PRODUCT_NAME:rfc1034identifier)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "ios/IJKMediaPodDemo/IJKMediaPodDemo/ViewController.h",
    "content": "//\n//  ViewController.h\n//  IJKMediaPodDemo\n//\n//  Created by Zhang Rui on 15/7/23.\n//  Copyright (c) 2015年 Zhang Rui. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface ViewController : UIViewController\n\n\n@end\n\n"
  },
  {
    "path": "ios/IJKMediaPodDemo/IJKMediaPodDemo/ViewController.m",
    "content": "//\n//  ViewController.m\n//  IJKMediaPodDemo\n//\n//  Created by Zhang Rui on 15/7/23.\n//  Copyright (c) 2015年 Zhang Rui. All rights reserved.\n//\n\n#import \"ViewController.h\"\n#import <IJKMediaPlayer/IJKMediaPlayer.h>\n\n@interface ViewController ()\n\n@end\n\n@implementation ViewController\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n    // Do any additional setup after loading the view, typically from a nib.\n\n    id<IJKMediaPlayback> playback = [[IJKFFMoviePlayerController alloc] initWithContentURL:nil  withOptions:nil];\n\n    [playback shutdown];\n}\n\n- (void)didReceiveMemoryWarning {\n    [super didReceiveMemoryWarning];\n    // Dispose of any resources that can be recreated.\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPodDemo/IJKMediaPodDemo/main.m",
    "content": "//\n//  main.m\n//  IJKMediaPodDemo\n//\n//  Created by Zhang Rui on 15/7/23.\n//  Copyright (c) 2015年 Zhang Rui. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n#import \"AppDelegate.h\"\n\nint main(int argc, char * argv[]) {\n    @autoreleasepool {\n        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));\n    }\n}\n"
  },
  {
    "path": "ios/IJKMediaPodDemo/IJKMediaPodDemo.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t3254039E620E12D7E1E62FC4 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7E676A9CBD9C96C0D97C7071 /* libPods.a */; };\n\t\tE63399A51B60E790008F50CE /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E63399A41B60E790008F50CE /* main.m */; };\n\t\tE63399A81B60E790008F50CE /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E63399A71B60E790008F50CE /* AppDelegate.m */; };\n\t\tE63399AB1B60E790008F50CE /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E63399AA1B60E790008F50CE /* ViewController.m */; };\n\t\tE63399AE1B60E790008F50CE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E63399AC1B60E790008F50CE /* Main.storyboard */; };\n\t\tE63399B01B60E790008F50CE /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E63399AF1B60E790008F50CE /* Images.xcassets */; };\n\t\tE63399B31B60E790008F50CE /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = E63399B11B60E790008F50CE /* LaunchScreen.xib */; };\n\t\tE63399BF1B60E790008F50CE /* IJKMediaPodDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E63399BE1B60E790008F50CE /* IJKMediaPodDemoTests.m */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\tE63399B91B60E790008F50CE /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = E63399971B60E790008F50CE /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = E633999E1B60E790008F50CE;\n\t\t\tremoteInfo = IJKMediaPodDemo;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXFileReference section */\n\t\t47C5C1BCE477FD39847AD2F8 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = \"Pods/Target Support Files/Pods/Pods.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t7E676A9CBD9C96C0D97C7071 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tE633999F1B60E790008F50CE /* IJKMediaPodDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = IJKMediaPodDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tE63399A31B60E790008F50CE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tE63399A41B60E790008F50CE /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = \"<group>\"; };\n\t\tE63399A61B60E790008F50CE /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = \"<group>\"; };\n\t\tE63399A71B60E790008F50CE /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = \"<group>\"; };\n\t\tE63399A91B60E790008F50CE /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = \"<group>\"; };\n\t\tE63399AA1B60E790008F50CE /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = \"<group>\"; };\n\t\tE63399AD1B60E790008F50CE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\tE63399AF1B60E790008F50CE /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = \"<group>\"; };\n\t\tE63399B21B60E790008F50CE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = \"<group>\"; };\n\t\tE63399B81B60E790008F50CE /* IJKMediaPodDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = IJKMediaPodDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tE63399BD1B60E790008F50CE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tE63399BE1B60E790008F50CE /* IJKMediaPodDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJKMediaPodDemoTests.m; sourceTree = \"<group>\"; };\n\t\tEAB805C5FAE107E60F65BC10 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = \"Pods/Target Support Files/Pods/Pods.release.xcconfig\"; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tE633999C1B60E790008F50CE /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t3254039E620E12D7E1E62FC4 /* libPods.a in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tE63399B51B60E790008F50CE /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\tA58489F820FCBD11F986D498 /* Pods */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t47C5C1BCE477FD39847AD2F8 /* Pods.debug.xcconfig */,\n\t\t\t\tEAB805C5FAE107E60F65BC10 /* Pods.release.xcconfig */,\n\t\t\t);\n\t\t\tname = Pods;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE63399961B60E790008F50CE = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE63399A11B60E790008F50CE /* IJKMediaPodDemo */,\n\t\t\t\tE63399BB1B60E790008F50CE /* IJKMediaPodDemoTests */,\n\t\t\t\tE63399A01B60E790008F50CE /* Products */,\n\t\t\t\tA58489F820FCBD11F986D498 /* Pods */,\n\t\t\t\tE9A894D41E27E605A44A8673 /* Frameworks */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE63399A01B60E790008F50CE /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE633999F1B60E790008F50CE /* IJKMediaPodDemo.app */,\n\t\t\t\tE63399B81B60E790008F50CE /* IJKMediaPodDemoTests.xctest */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE63399A11B60E790008F50CE /* IJKMediaPodDemo */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE63399A61B60E790008F50CE /* AppDelegate.h */,\n\t\t\t\tE63399A71B60E790008F50CE /* AppDelegate.m */,\n\t\t\t\tE63399A91B60E790008F50CE /* ViewController.h */,\n\t\t\t\tE63399AA1B60E790008F50CE /* ViewController.m */,\n\t\t\t\tE63399AC1B60E790008F50CE /* Main.storyboard */,\n\t\t\t\tE63399AF1B60E790008F50CE /* Images.xcassets */,\n\t\t\t\tE63399B11B60E790008F50CE /* LaunchScreen.xib */,\n\t\t\t\tE63399A21B60E790008F50CE /* Supporting Files */,\n\t\t\t);\n\t\t\tpath = IJKMediaPodDemo;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE63399A21B60E790008F50CE /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE63399A31B60E790008F50CE /* Info.plist */,\n\t\t\t\tE63399A41B60E790008F50CE /* main.m */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE63399BB1B60E790008F50CE /* IJKMediaPodDemoTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE63399BE1B60E790008F50CE /* IJKMediaPodDemoTests.m */,\n\t\t\t\tE63399BC1B60E790008F50CE /* Supporting Files */,\n\t\t\t);\n\t\t\tpath = IJKMediaPodDemoTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE63399BC1B60E790008F50CE /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE63399BD1B60E790008F50CE /* Info.plist */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE9A894D41E27E605A44A8673 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t7E676A9CBD9C96C0D97C7071 /* libPods.a */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\tE633999E1B60E790008F50CE /* IJKMediaPodDemo */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = E63399C21B60E790008F50CE /* Build configuration list for PBXNativeTarget \"IJKMediaPodDemo\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t4F73080015A4CAFB5E66E708 /* Check Pods Manifest.lock */,\n\t\t\t\tE633999B1B60E790008F50CE /* Sources */,\n\t\t\t\tE633999C1B60E790008F50CE /* Frameworks */,\n\t\t\t\tE633999D1B60E790008F50CE /* Resources */,\n\t\t\t\t82155C5704F0DE61754A7A12 /* Copy Pods Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = IJKMediaPodDemo;\n\t\t\tproductName = IJKMediaPodDemo;\n\t\t\tproductReference = E633999F1B60E790008F50CE /* IJKMediaPodDemo.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\tE63399B71B60E790008F50CE /* IJKMediaPodDemoTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = E63399C51B60E790008F50CE /* Build configuration list for PBXNativeTarget \"IJKMediaPodDemoTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tE63399B41B60E790008F50CE /* Sources */,\n\t\t\t\tE63399B51B60E790008F50CE /* Frameworks */,\n\t\t\t\tE63399B61B60E790008F50CE /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\tE63399BA1B60E790008F50CE /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = IJKMediaPodDemoTests;\n\t\t\tproductName = IJKMediaPodDemoTests;\n\t\t\tproductReference = E63399B81B60E790008F50CE /* IJKMediaPodDemoTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tE63399971B60E790008F50CE /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 0640;\n\t\t\t\tORGANIZATIONNAME = \"Zhang Rui\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tE633999E1B60E790008F50CE = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.4;\n\t\t\t\t\t};\n\t\t\t\t\tE63399B71B60E790008F50CE = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.4;\n\t\t\t\t\t\tTestTargetID = E633999E1B60E790008F50CE;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = E633999A1B60E790008F50CE /* Build configuration list for PBXProject \"IJKMediaPodDemo\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = English;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = E63399961B60E790008F50CE;\n\t\t\tproductRefGroup = E63399A01B60E790008F50CE /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tE633999E1B60E790008F50CE /* IJKMediaPodDemo */,\n\t\t\t\tE63399B71B60E790008F50CE /* IJKMediaPodDemoTests */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tE633999D1B60E790008F50CE /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tE63399AE1B60E790008F50CE /* Main.storyboard in Resources */,\n\t\t\t\tE63399B31B60E790008F50CE /* LaunchScreen.xib in Resources */,\n\t\t\t\tE63399B01B60E790008F50CE /* Images.xcassets in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tE63399B61B60E790008F50CE /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t4F73080015A4CAFB5E66E708 /* Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"Check Pods Manifest.lock\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_ROOT}/../Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [[ $? != 0 ]] ; then\\n    cat << EOM\\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\nEOM\\n    exit 1\\nfi\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t82155C5704F0DE61754A7A12 /* Copy Pods Resources */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"Copy Pods Resources\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tE633999B1B60E790008F50CE /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tE63399AB1B60E790008F50CE /* ViewController.m in Sources */,\n\t\t\t\tE63399A81B60E790008F50CE /* AppDelegate.m in Sources */,\n\t\t\t\tE63399A51B60E790008F50CE /* main.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tE63399B41B60E790008F50CE /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tE63399BF1B60E790008F50CE /* IJKMediaPodDemoTests.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\tE63399BA1B60E790008F50CE /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = E633999E1B60E790008F50CE /* IJKMediaPodDemo */;\n\t\t\ttargetProxy = E63399B91B60E790008F50CE /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin PBXVariantGroup section */\n\t\tE63399AC1B60E790008F50CE /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tE63399AD1B60E790008F50CE /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE63399B11B60E790008F50CE /* LaunchScreen.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tE63399B21B60E790008F50CE /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\tE63399C01B60E790008F50CE /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_SYMBOLS_PRIVATE_EXTERN = NO;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.4;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tE63399C11B60E790008F50CE /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.4;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tE63399C31B60E790008F50CE /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 47C5C1BCE477FD39847AD2F8 /* Pods.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tINFOPLIST_FILE = IJKMediaPodDemo/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tE63399C41B60E790008F50CE /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = EAB805C5FAE107E60F65BC10 /* Pods.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tINFOPLIST_FILE = IJKMediaPodDemo/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tE63399C61B60E790008F50CE /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(SDKROOT)/Developer/Library/Frameworks\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = IJKMediaPodDemoTests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/IJKMediaPodDemo.app/IJKMediaPodDemo\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tE63399C71B60E790008F50CE /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(SDKROOT)/Developer/Library/Frameworks\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = IJKMediaPodDemoTests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/IJKMediaPodDemo.app/IJKMediaPodDemo\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tE633999A1B60E790008F50CE /* Build configuration list for PBXProject \"IJKMediaPodDemo\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tE63399C01B60E790008F50CE /* Debug */,\n\t\t\t\tE63399C11B60E790008F50CE /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tE63399C21B60E790008F50CE /* Build configuration list for PBXNativeTarget \"IJKMediaPodDemo\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tE63399C31B60E790008F50CE /* Debug */,\n\t\t\t\tE63399C41B60E790008F50CE /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tE63399C51B60E790008F50CE /* Build configuration list for PBXNativeTarget \"IJKMediaPodDemoTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tE63399C61B60E790008F50CE /* Debug */,\n\t\t\t\tE63399C71B60E790008F50CE /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = E63399971B60E790008F50CE /* Project object */;\n}\n"
  },
  {
    "path": "ios/IJKMediaPodDemo/IJKMediaPodDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:IJKMediaPodDemo.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "ios/IJKMediaPodDemo/IJKMediaPodDemoTests/IJKMediaPodDemoTests.m",
    "content": "//\n//  IJKMediaPodDemoTests.m\n//  IJKMediaPodDemoTests\n//\n//  Created by Zhang Rui on 15/7/23.\n//  Copyright (c) 2015年 Zhang Rui. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n#import <XCTest/XCTest.h>\n\n@interface IJKMediaPodDemoTests : XCTestCase\n\n@end\n\n@implementation IJKMediaPodDemoTests\n\n- (void)setUp {\n    [super setUp];\n    // Put setup code here. This method is called before the invocation of each test method in the class.\n}\n\n- (void)tearDown {\n    // Put teardown code here. This method is called after the invocation of each test method in the class.\n    [super tearDown];\n}\n\n- (void)testExample {\n    // This is an example of a functional test case.\n    XCTAssert(YES, @\"Pass\");\n}\n\n- (void)testPerformanceExample {\n    // This is an example of a performance test case.\n    [self measureBlock:^{\n        // Put the code you want to measure the time of here.\n    }];\n}\n\n@end\n"
  },
  {
    "path": "ios/IJKMediaPodDemo/IJKMediaPodDemoTests/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>tv.danmaku.$(PRODUCT_NAME:rfc1034identifier)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "ios/IJKMediaPodDemo/Podfile",
    "content": "source 'https://github.com/CocoaPods/Specs.git'\n# source <your private repo containing ijkplayer, FFmpeg4ijkplayer-ios-bin>\n\nplatform :ios, '8.0'\n\npod 'ijkplayer', '~> 0.3.2-rc.2'\n"
  },
  {
    "path": "ios/compile-ffmpeg.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2014 Bilibili\n# Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n#----------\n# modify for your build tool\n\nFF_ALL_ARCHS_IOS6_SDK=\"armv7 armv7s i386\"\nFF_ALL_ARCHS_IOS7_SDK=\"armv7 armv7s arm64 i386 x86_64\"\nFF_ALL_ARCHS_IOS8_SDK=\"armv7 arm64 i386 x86_64\"\n\nFF_ALL_ARCHS=$FF_ALL_ARCHS_IOS8_SDK\n\n#----------\nUNI_BUILD_ROOT=`pwd`\nUNI_TMP=\"$UNI_BUILD_ROOT/tmp\"\nUNI_TMP_LLVM_VER_FILE=\"$UNI_TMP/llvm.ver.txt\"\nFF_TARGET=$1\nFF_TARGET_EXTRA=$2\nset -e\n\n#----------\necho_archs() {\n    echo \"====================\"\n    echo \"[*] check xcode version\"\n    echo \"====================\"\n    echo \"FF_ALL_ARCHS = $FF_ALL_ARCHS\"\n}\n\nFF_LIBS=\"libavcodec libavfilter libavformat libavutil libswscale libswresample\"\ndo_lipo_ffmpeg () {\n    LIB_FILE=$1\n    LIPO_FLAGS=\n    for ARCH in $FF_ALL_ARCHS\n    do\n        ARCH_LIB_FILE=\"$UNI_BUILD_ROOT/build/ffmpeg-$ARCH/output/lib/$LIB_FILE\"\n        if [ -f \"$ARCH_LIB_FILE\" ]; then\n            LIPO_FLAGS=\"$LIPO_FLAGS $ARCH_LIB_FILE\"\n        else\n            echo \"skip $LIB_FILE of $ARCH\";\n        fi\n    done\n\n    xcrun lipo -create $LIPO_FLAGS -output $UNI_BUILD_ROOT/build/universal/lib/$LIB_FILE\n    xcrun lipo -info $UNI_BUILD_ROOT/build/universal/lib/$LIB_FILE\n}\n\nSSL_LIBS=\"libcrypto libssl\"\ndo_lipo_ssl () {\n    LIB_FILE=$1\n    LIPO_FLAGS=\n    for ARCH in $FF_ALL_ARCHS\n    do\n        ARCH_LIB_FILE=\"$UNI_BUILD_ROOT/build/openssl-$ARCH/output/lib/$LIB_FILE\"\n        if [ -f \"$ARCH_LIB_FILE\" ]; then\n            LIPO_FLAGS=\"$LIPO_FLAGS $ARCH_LIB_FILE\"\n        else\n            echo \"skip $LIB_FILE of $ARCH\";\n        fi\n    done\n\n    if [ \"$LIPO_FLAGS\" != \"\" ]; then\n        xcrun lipo -create $LIPO_FLAGS -output $UNI_BUILD_ROOT/build/universal/lib/$LIB_FILE\n        xcrun lipo -info $UNI_BUILD_ROOT/build/universal/lib/$LIB_FILE\n    fi\n}\n\ndo_lipo_all () {\n    mkdir -p $UNI_BUILD_ROOT/build/universal/lib\n    echo \"lipo archs: $FF_ALL_ARCHS\"\n    for FF_LIB in $FF_LIBS\n    do\n        do_lipo_ffmpeg \"$FF_LIB.a\";\n    done\n\n    ANY_ARCH=\n    for ARCH in $FF_ALL_ARCHS\n    do\n        ARCH_INC_DIR=\"$UNI_BUILD_ROOT/build/ffmpeg-$ARCH/output/include\"\n        if [ -d \"$ARCH_INC_DIR\" ]; then\n            if [ -z \"$ANY_ARCH\" ]; then\n                ANY_ARCH=$ARCH\n                cp -R \"$ARCH_INC_DIR\" \"$UNI_BUILD_ROOT/build/universal/\"\n            fi\n\n            UNI_INC_DIR=\"$UNI_BUILD_ROOT/build/universal/include\"\n\n            mkdir -p \"$UNI_INC_DIR/libavutil/$ARCH\"\n            cp -f \"$ARCH_INC_DIR/libavutil/avconfig.h\"  \"$UNI_INC_DIR/libavutil/$ARCH/avconfig.h\"\n            cp -f tools/avconfig.h                      \"$UNI_INC_DIR/libavutil/avconfig.h\"\n            cp -f \"$ARCH_INC_DIR/libavutil/ffversion.h\" \"$UNI_INC_DIR/libavutil/$ARCH/ffversion.h\"\n            cp -f tools/ffversion.h                     \"$UNI_INC_DIR/libavutil/ffversion.h\"\n            mkdir -p \"$UNI_INC_DIR/libffmpeg/$ARCH\"\n            cp -f \"$ARCH_INC_DIR/libffmpeg/config.h\"    \"$UNI_INC_DIR/libffmpeg/$ARCH/config.h\"\n            cp -f tools/config.h                        \"$UNI_INC_DIR/libffmpeg/config.h\"\n        fi\n    done\n\n    for SSL_LIB in $SSL_LIBS\n    do\n        do_lipo_ssl \"$SSL_LIB.a\";\n    done\n}\n\n#----------\nif [ \"$FF_TARGET\" = \"armv7\" -o \"$FF_TARGET\" = \"armv7s\" -o \"$FF_TARGET\" = \"arm64\" ]; then\n    echo_archs\n    sh tools/do-compile-ffmpeg.sh $FF_TARGET $FF_TARGET_EXTRA\n    do_lipo_all\nelif [ \"$FF_TARGET\" = \"i386\" -o \"$FF_TARGET\" = \"x86_64\" ]; then\n    echo_archs\n    sh tools/do-compile-ffmpeg.sh $FF_TARGET $FF_TARGET_EXTRA\n    do_lipo_all\nelif [ \"$FF_TARGET\" = \"lipo\" ]; then\n    echo_archs\n    do_lipo_all\nelif [ \"$FF_TARGET\" = \"all\" ]; then\n    echo_archs\n    for ARCH in $FF_ALL_ARCHS\n    do\n        sh tools/do-compile-ffmpeg.sh $ARCH $FF_TARGET_EXTRA\n    done\n\n    do_lipo_all\nelif [ \"$FF_TARGET\" = \"check\" ]; then\n    echo_archs\nelif [ \"$FF_TARGET\" = \"clean\" ]; then\n    echo_archs\n    echo \"==================\"\n    for ARCH in $FF_ALL_ARCHS\n    do\n        echo \"clean ffmpeg-$ARCH\"\n        echo \"==================\"\n        cd ffmpeg-$ARCH && git clean -xdf && cd -\n    done\n    echo \"clean build cache\"\n    echo \"=================\"\n    rm -rf build/ffmpeg-*\n    rm -rf build/openssl-*\n    rm -rf build/universal/include\n    rm -rf build/universal/lib\n    echo \"clean success\"\nelse\n    echo \"Usage:\"\n    echo \"  compile-ffmpeg.sh armv7|arm64|i386|x86_64\"\n    echo \"  compile-ffmpeg.sh armv7s (obselete)\"\n    echo \"  compile-ffmpeg.sh lipo\"\n    echo \"  compile-ffmpeg.sh all\"\n    echo \"  compile-ffmpeg.sh clean\"\n    echo \"  compile-ffmpeg.sh check\"\n    exit 1\nfi\n"
  },
  {
    "path": "ios/compile-openssl.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2014 Bilibili\n# Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n#----------\n# modify for your build tool\n\nFF_ALL_ARCHS_IOS6_SDK=\"armv7 armv7s i386\"\nFF_ALL_ARCHS_IOS7_SDK=\"armv7 armv7s arm64 i386 x86_64\"\nFF_ALL_ARCHS_IOS8_SDK=\"armv7 arm64 i386 x86_64\"\n\nFF_ALL_ARCHS=$FF_ALL_ARCHS_IOS8_SDK\n\n#----------\nUNI_BUILD_ROOT=`pwd`\nUNI_TMP=\"$UNI_BUILD_ROOT/tmp\"\nUNI_TMP_LLVM_VER_FILE=\"$UNI_TMP/llvm.ver.txt\"\nFF_TARGET=$1\nset -e\n\n#----------\nFF_LIBS=\"libssl libcrypto\"\n\n#----------\necho_archs() {\n    echo \"====================\"\n    echo \"[*] check xcode version\"\n    echo \"====================\"\n    echo \"FF_ALL_ARCHS = $FF_ALL_ARCHS\"\n}\n\ndo_lipo () {\n    LIB_FILE=$1\n    LIPO_FLAGS=\n    for ARCH in $FF_ALL_ARCHS\n    do\n        LIPO_FLAGS=\"$LIPO_FLAGS $UNI_BUILD_ROOT/build/openssl-$ARCH/output/lib/$LIB_FILE\"\n    done\n\n    xcrun lipo -create $LIPO_FLAGS -output $UNI_BUILD_ROOT/build/universal/lib/$LIB_FILE\n    xcrun lipo -info $UNI_BUILD_ROOT/build/universal/lib/$LIB_FILE\n}\n\ndo_lipo_all () {\n    mkdir -p $UNI_BUILD_ROOT/build/universal/lib\n    echo \"lipo archs: $FF_ALL_ARCHS\"\n    for FF_LIB in $FF_LIBS\n    do\n        do_lipo \"$FF_LIB.a\";\n    done\n\n    cp -R $UNI_BUILD_ROOT/build/openssl-armv7/output/include $UNI_BUILD_ROOT/build/universal/\n}\n\n#----------\nif [ \"$FF_TARGET\" = \"armv7\" -o \"$FF_TARGET\" = \"armv7s\" -o \"$FF_TARGET\" = \"arm64\" ]; then\n    echo_archs\n    sh tools/do-compile-openssl.sh $FF_TARGET\nelif [ \"$FF_TARGET\" = \"i386\" -o \"$FF_TARGET\" = \"x86_64\" ]; then\n    echo_archs\n    sh tools/do-compile-openssl.sh $FF_TARGET\nelif [ \"$FF_TARGET\" = \"lipo\" ]; then\n    echo_archs\n    do_lipo_all\nelif [ \"$FF_TARGET\" = \"all\" ]; then\n    echo_archs\n    for ARCH in $FF_ALL_ARCHS\n    do\n        sh tools/do-compile-openssl.sh $ARCH\n    done\n\n    do_lipo_all\nelif [ \"$FF_TARGET\" = \"check\" ]; then\n    echo_archs\nelif [ \"$FF_TARGET\" = \"clean\" ]; then\n    echo_archs\n    for ARCH in $FF_ALL_ARCHS\n    do\n        cd openssl-$ARCH && git clean -xdf && cd -\n    done\nelse\n    echo \"Usage:\"\n    echo \"  compile-openssl.sh armv7|arm64|i386|x86_64\"\n    echo \"  compile-openssl.sh armv7s (obselete)\"\n    echo \"  compile-openssl.sh lipo\"\n    echo \"  compile-openssl.sh all\"\n    echo \"  compile-openssl.sh clean\"\n    echo \"  compile-openssl.sh check\"\n    exit 1\nfi\n"
  },
  {
    "path": "ios/tools/avconfig.h",
    "content": "/*\n * avconfig.h\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#if   defined(__aarch64__)\n#   include \"arm64/avconfig.h\"\n#elif defined(__x86_64__)\n#   include \"x86_64/avconfig.h\"\n#elif defined(__arm__)\n\n#   if   defined(__ARM_ARCH_7S__)\n#       include \"armv7s/avconfig.h\"\n#   elif defined(__ARM_ARCH)\n#       if __ARM_ARCH == 7\n#           include \"armv7/avconfig.h\"\n#       else\n#           error Unsupport ARM architecture\n#       endif\n#   else\n#       error Unsupport ARM architecture\n#   endif\n\n#elif defined(__i386__)\n#   include \"i386/avconfig.h\"\n#else\n#   error Unsupport architecture\n#endif\n"
  },
  {
    "path": "ios/tools/config.h",
    "content": "/*\n * config.h\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#if   defined(__aarch64__)\n#   include \"arm64/config.h\"\n#elif defined(__x86_64__)\n#   include \"x86_64/config.h\"\n#elif defined(__arm__)\n\n#   if   defined(__ARM_ARCH_7S__)\n#       include \"armv7s/config.h\"\n#   elif defined(__ARM_ARCH)\n#       if __ARM_ARCH == 7\n#           include \"armv7/config.h\"\n#       else\n#           error Unsupport ARM architecture\n#       endif\n#   else\n#       error Unsupport ARM architecture\n#   endif\n\n#elif defined(__i386__)\n#   include \"i386/config.h\"\n#else\n#   error Unsupport architecture\n#endif\n"
  },
  {
    "path": "ios/tools/do-compile-ffmpeg.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2014 Bilibili\n# Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# This script is based on projects below\n# https://github.com/kolyvan/kxmovie\n# https://github.com/yixia/FFmpeg-Android\n# http://git.videolan.org/?p=vlc-ports/android.git;a=summary\n# https://github.com/kewlbear/FFmpeg-iOS-build-script/\n\n#--------------------\necho \"====================\"\necho \"[*] check host\"\necho \"====================\"\nset -e\n\n#--------------------\n# include\n\n\n#--------------------\n# common defines\nFF_ARCH=$1\nFF_BUILD_OPT=$2\necho \"FF_ARCH=$FF_ARCH\"\necho \"FF_BUILD_OPT=$FF_BUILD_OPT\"\nif [ -z \"$FF_ARCH\" ]; then\n    echo \"You must specific an architecture 'armv7, armv7s, arm64, i386, x86_64, ...'.\\n\"\n    exit 1\nfi\n\n\nFF_BUILD_ROOT=`pwd`\nFF_TAGET_OS=\"darwin\"\n\n\n# ffmpeg build params\nexport COMMON_FF_CFG_FLAGS=\nsource $FF_BUILD_ROOT/../config/module.sh\n\nFFMPEG_CFG_FLAGS=\nFFMPEG_CFG_FLAGS=\"$FFMPEG_CFG_FLAGS $COMMON_FF_CFG_FLAGS\"\n\n# Optimization options (experts only):\n# FFMPEG_CFG_FLAGS=\"$FFMPEG_CFG_FLAGS --disable-armv5te\"\n# FFMPEG_CFG_FLAGS=\"$FFMPEG_CFG_FLAGS --disable-armv6\"\n# FFMPEG_CFG_FLAGS=\"$FFMPEG_CFG_FLAGS --disable-armv6t2\"\n\n# Advanced options (experts only):\nFFMPEG_CFG_FLAGS=\"$FFMPEG_CFG_FLAGS --enable-cross-compile\"\n# --disable-symver may indicate a bug\n# FFMPEG_CFG_FLAGS=\"$FFMPEG_CFG_FLAGS --disable-symver\"\n\n# Developer options (useful when working on FFmpeg itself):\nFFMPEG_CFG_FLAGS=\"$FFMPEG_CFG_FLAGS --disable-stripping\"\n\n##\nFFMPEG_CFG_FLAGS=\"$FFMPEG_CFG_FLAGS --arch=$FF_ARCH\"\nFFMPEG_CFG_FLAGS=\"$FFMPEG_CFG_FLAGS --target-os=$FF_TAGET_OS\"\nFFMPEG_CFG_FLAGS=\"$FFMPEG_CFG_FLAGS --enable-static\"\nFFMPEG_CFG_FLAGS=\"$FFMPEG_CFG_FLAGS --disable-shared\"\nFFMPEG_EXTRA_CFLAGS=\n\n# i386, x86_64\nFFMPEG_CFG_FLAGS_SIMULATOR=\nFFMPEG_CFG_FLAGS_SIMULATOR=\"$FFMPEG_CFG_FLAGS_SIMULATOR --disable-asm\"\nFFMPEG_CFG_FLAGS_SIMULATOR=\"$FFMPEG_CFG_FLAGS_SIMULATOR --disable-mmx\"\nFFMPEG_CFG_FLAGS_SIMULATOR=\"$FFMPEG_CFG_FLAGS_SIMULATOR --assert-level=2\"\n\n# armv7, armv7s, arm64\nFFMPEG_CFG_FLAGS_ARM=\nFFMPEG_CFG_FLAGS_ARM=\"$FFMPEG_CFG_FLAGS_ARM --enable-pic\"\nFFMPEG_CFG_FLAGS_ARM=\"$FFMPEG_CFG_FLAGS_ARM --enable-neon\"\ncase \"$FF_BUILD_OPT\" in\n    debug)\n        FFMPEG_CFG_FLAGS_ARM=\"$FFMPEG_CFG_FLAGS_ARM --disable-optimizations\"\n        FFMPEG_CFG_FLAGS_ARM=\"$FFMPEG_CFG_FLAGS_ARM --enable-debug\"\n        FFMPEG_CFG_FLAGS_ARM=\"$FFMPEG_CFG_FLAGS_ARM --disable-small\"\n    ;;\n    *)\n        FFMPEG_CFG_FLAGS_ARM=\"$FFMPEG_CFG_FLAGS_ARM --enable-optimizations\"\n        FFMPEG_CFG_FLAGS_ARM=\"$FFMPEG_CFG_FLAGS_ARM --enable-debug\"\n        FFMPEG_CFG_FLAGS_ARM=\"$FFMPEG_CFG_FLAGS_ARM --enable-small\"\n    ;;\nesac\n\necho \"build_root: $FF_BUILD_ROOT\"\n\n#--------------------\necho \"====================\"\necho \"[*] check gas-preprocessor\"\necho \"====================\"\nFF_TOOLS_ROOT=\"$FF_BUILD_ROOT/../extra\"\nexport PATH=\"$FF_TOOLS_ROOT/gas-preprocessor:$PATH\"\n\necho \"gasp: $FF_TOOLS_ROOT/gas-preprocessor/gas-preprocessor.pl\"\n\n#--------------------\necho \"====================\"\necho \"[*] config arch $FF_ARCH\"\necho \"====================\"\n\nFF_BUILD_NAME=\"unknown\"\nFF_XCRUN_PLATFORM=\"iPhoneOS\"\nFF_XCRUN_OSVERSION=\nFF_GASPP_EXPORT=\nFF_DEP_OPENSSL_INC=\nFF_DEP_OPENSSL_LIB=\nFF_XCODE_BITCODE=\n\nif [ \"$FF_ARCH\" = \"i386\" ]; then\n    FF_BUILD_NAME=\"ffmpeg-i386\"\n    FF_BUILD_NAME_OPENSSL=openssl-i386\n    FF_XCRUN_PLATFORM=\"iPhoneSimulator\"\n    FF_XCRUN_OSVERSION=\"-mios-simulator-version-min=6.0\"\n    FFMPEG_CFG_FLAGS=\"$FFMPEG_CFG_FLAGS $FFMPEG_CFG_FLAGS_SIMULATOR\"\nelif [ \"$FF_ARCH\" = \"x86_64\" ]; then\n    FF_BUILD_NAME=\"ffmpeg-x86_64\"\n    FF_BUILD_NAME_OPENSSL=openssl-x86_64\n    FF_XCRUN_PLATFORM=\"iPhoneSimulator\"\n    FF_XCRUN_OSVERSION=\"-mios-simulator-version-min=7.0\"\n    FFMPEG_CFG_FLAGS=\"$FFMPEG_CFG_FLAGS $FFMPEG_CFG_FLAGS_SIMULATOR\"\nelif [ \"$FF_ARCH\" = \"armv7\" ]; then\n    FF_BUILD_NAME=\"ffmpeg-armv7\"\n    FF_BUILD_NAME_OPENSSL=openssl-armv7\n    FF_XCRUN_OSVERSION=\"-miphoneos-version-min=6.0\"\n    FF_XCODE_BITCODE=\"-fembed-bitcode\"\n    FFMPEG_CFG_FLAGS_ARM=\"$FFMPEG_CFG_FLAGS_ARM --disable-asm\"\n    FFMPEG_CFG_FLAGS=\"$FFMPEG_CFG_FLAGS $FFMPEG_CFG_FLAGS_ARM\"\n#    FFMPEG_CFG_CPU=\"--cpu=cortex-a8\"\nelif [ \"$FF_ARCH\" = \"armv7s\" ]; then\n    FF_BUILD_NAME=\"ffmpeg-armv7s\"\n    FF_BUILD_NAME_OPENSSL=openssl-armv7s\n    FFMPEG_CFG_CPU=\"--cpu=swift\"\n    FF_XCRUN_OSVERSION=\"-miphoneos-version-min=6.0\"\n    FF_XCODE_BITCODE=\"-fembed-bitcode\"\n    FFMPEG_CFG_FLAGS_ARM=\"$FFMPEG_CFG_FLAGS_ARM --disable-asm\"\n    FFMPEG_CFG_FLAGS=\"$FFMPEG_CFG_FLAGS $FFMPEG_CFG_FLAGS_ARM\"\nelif [ \"$FF_ARCH\" = \"arm64\" ]; then\n    FF_BUILD_NAME=\"ffmpeg-arm64\"\n    FF_BUILD_NAME_OPENSSL=openssl-arm64\n    FF_XCRUN_OSVERSION=\"-miphoneos-version-min=7.0\"\n    FF_XCODE_BITCODE=\"-fembed-bitcode\"\n    FFMPEG_CFG_FLAGS=\"$FFMPEG_CFG_FLAGS $FFMPEG_CFG_FLAGS_ARM\"\n    FF_GASPP_EXPORT=\"GASPP_FIX_XCODE5=1\"\nelse\n    echo \"unknown architecture $FF_ARCH\";\n    exit 1\nfi\n\necho \"build_name: $FF_BUILD_NAME\"\necho \"platform:   $FF_XCRUN_PLATFORM\"\necho \"osversion:  $FF_XCRUN_OSVERSION\"\n\n#--------------------\necho \"====================\"\necho \"[*] make ios toolchain $FF_BUILD_NAME\"\necho \"====================\"\n\nFF_BUILD_SOURCE=\"$FF_BUILD_ROOT/$FF_BUILD_NAME\"\nFF_BUILD_PREFIX=\"$FF_BUILD_ROOT/build/$FF_BUILD_NAME/output\"\n\nFFMPEG_CFG_FLAGS=\"$FFMPEG_CFG_FLAGS --prefix=$FF_BUILD_PREFIX\"\n\nmkdir -p $FF_BUILD_PREFIX\n\necho \"build_source: $FF_BUILD_SOURCE\"\necho \"build_prefix: $FF_BUILD_PREFIX\"\n\n#--------------------\necho \"\\n--------------------\"\necho \"[*] configurate ffmpeg\"\necho \"--------------------\"\nFF_XCRUN_SDK=`echo $FF_XCRUN_PLATFORM | tr '[:upper:]' '[:lower:]'`\nFF_XCRUN_CC=\"xcrun -sdk $FF_XCRUN_SDK clang\"\n\nFFMPEG_CFG_FLAGS=\"$FFMPEG_CFG_FLAGS $FFMPEG_CFG_CPU\"\n\nFFMPEG_CFLAGS=\nFFMPEG_CFLAGS=\"$FFMPEG_CFLAGS -arch $FF_ARCH\"\nFFMPEG_CFLAGS=\"$FFMPEG_CFLAGS $FF_XCRUN_OSVERSION\"\nFFMPEG_CFLAGS=\"$FFMPEG_CFLAGS $FFMPEG_EXTRA_CFLAGS\"\nFFMPEG_CFLAGS=\"$FFMPEG_CFLAGS $FF_XCODE_BITCODE\"\nFFMPEG_LDFLAGS=\"$FFMPEG_CFLAGS\"\nFFMPEG_DEP_LIBS=\n\n#--------------------\necho \"\\n--------------------\"\necho \"[*] check OpenSSL\"\necho \"----------------------\"\nFFMPEG_DEP_OPENSSL_INC=$FF_BUILD_ROOT/build/$FF_BUILD_NAME_OPENSSL/output/include\nFFMPEG_DEP_OPENSSL_LIB=$FF_BUILD_ROOT/build/$FF_BUILD_NAME_OPENSSL/output/lib\n#--------------------\n# with openssl\nif [ -f \"${FFMPEG_DEP_OPENSSL_LIB}/libssl.a\" ]; then\n    FFMPEG_CFG_FLAGS=\"$FFMPEG_CFG_FLAGS --enable-openssl\"\n\n    FFMPEG_CFLAGS=\"$FFMPEG_CFLAGS -I${FFMPEG_DEP_OPENSSL_INC}\"\n    FFMPEG_DEP_LIBS=\"$FFMPEG_CFLAGS -L${FFMPEG_DEP_OPENSSL_LIB} -lssl -lcrypto\"\nfi\n\n#--------------------\necho \"\\n--------------------\"\necho \"[*] configure\"\necho \"----------------------\"\n\nif [ ! -d $FF_BUILD_SOURCE ]; then\n    echo \"\"\n    echo \"!! ERROR\"\n    echo \"!! Can not find FFmpeg directory for $FF_BUILD_NAME\"\n    echo \"!! Run 'sh init-ios.sh' first\"\n    echo \"\"\n    exit 1\nfi\n\n# xcode configuration\nexport DEBUG_INFORMATION_FORMAT=dwarf-with-dsym\n\ncd $FF_BUILD_SOURCE\nif [ -f \"./config.h\" ]; then\n    echo 'reuse configure'\nelse\n    echo \"config: $FFMPEG_CFG_FLAGS $FF_XCRUN_CC\"\n    ./configure \\\n        $FFMPEG_CFG_FLAGS \\\n        --cc=\"$FF_XCRUN_CC\" \\\n        $FFMPEG_CFG_CPU \\\n        --extra-cflags=\"$FFMPEG_CFLAGS\" \\\n        --extra-cxxflags=\"$FFMPEG_CFLAGS\" \\\n        --extra-ldflags=\"$FFMPEG_LDFLAGS $FFMPEG_DEP_LIBS\"\n    make clean\nfi\n\n#--------------------\necho \"\\n--------------------\"\necho \"[*] compile ffmpeg\"\necho \"--------------------\"\ncp config.* $FF_BUILD_PREFIX\nmake -j3 $FF_GASPP_EXPORT\nmake install\nmkdir -p $FF_BUILD_PREFIX/include/libffmpeg\ncp -f config.h $FF_BUILD_PREFIX/include/libffmpeg/config.h\n"
  },
  {
    "path": "ios/tools/do-compile-openssl.sh",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2014 Bilibili\n# Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# This script is based on projects below\n# https://github.com/x2on/OpenSSL-for-iPhone\n\n#--------------------\necho \"====================\"\necho \"[*] check host\"\necho \"====================\"\nset -e\n\n\nFF_XCRUN_DEVELOPER=`xcode-select -print-path`\nif [ ! -d \"$FF_XCRUN_DEVELOPER\" ]; then\n  echo \"xcode path is not set correctly $FF_XCRUN_DEVELOPER does not exist (most likely because of xcode > 4.3)\"\n  echo \"run\"\n  echo \"sudo xcode-select -switch <xcode path>\"\n  echo \"for default installation:\"\n  echo \"sudo xcode-select -switch /Applications/Xcode.app/Contents/Developer\"\n  exit 1\nfi\n\ncase $FF_XCRUN_DEVELOPER in  \n     *\\ * )\n           echo \"Your Xcode path contains whitespaces, which is not supported.\"\n           exit 1\n          ;;\nesac\n\n\n#--------------------\n# include\n\n\n#--------------------\n# common defines\nFF_ARCH=$1\nif [ -z \"$FF_ARCH\" ]; then\n    echo \"You must specific an architecture 'armv7, armv7s, arm64, i386, x86_64, ...'.\\n\"\n    exit 1\nfi\n\n\nFF_BUILD_ROOT=`pwd`\nFF_TAGET_OS=\"darwin\"\n\n\n# openssl build params\nexport COMMON_FF_CFG_FLAGS=\n\nOPENSSL_CFG_FLAGS=\nOPENSSL_EXTRA_CFLAGS=\nOPENSSL_CFG_CPU=\n\n# i386, x86_64\nOPENSSL_CFG_FLAGS_SIMULATOR=\n\n# armv7, armv7s, arm64\nOPENSSL_CFG_FLAGS_ARM=\nOPENSSL_CFG_FLAGS_ARM=\"iphoneos-cross\"\n\necho \"build_root: $FF_BUILD_ROOT\"\n\n#--------------------\necho \"====================\"\necho \"[*] config arch $FF_ARCH\"\necho \"====================\"\n\nFF_BUILD_NAME=\"unknown\"\nFF_XCRUN_PLATFORM=\"iPhoneOS\"\nFF_XCRUN_OSVERSION=\nFF_GASPP_EXPORT=\nFF_XCODE_BITCODE=\n\nif [ \"$FF_ARCH\" = \"i386\" ]; then\n    FF_BUILD_NAME=\"openssl-i386\"\n    FF_XCRUN_PLATFORM=\"iPhoneSimulator\"\n    FF_XCRUN_OSVERSION=\"-mios-simulator-version-min=6.0\"\n    OPENSSL_CFG_FLAGS=\"darwin-i386-cc $OPENSSL_CFG_FLAGS\"\nelif [ \"$FF_ARCH\" = \"x86_64\" ]; then\n    FF_BUILD_NAME=\"openssl-x86_64\"\n    FF_XCRUN_PLATFORM=\"iPhoneSimulator\"\n    FF_XCRUN_OSVERSION=\"-mios-simulator-version-min=7.0\"\n    OPENSSL_CFG_FLAGS=\"darwin64-x86_64-cc $OPENSSL_CFG_FLAGS\"\nelif [ \"$FF_ARCH\" = \"armv7\" ]; then\n    FF_BUILD_NAME=\"openssl-armv7\"\n    FF_XCRUN_OSVERSION=\"-miphoneos-version-min=6.0\"\n    FF_XCODE_BITCODE=\"-fembed-bitcode\"\n    OPENSSL_CFG_FLAGS=\"$OPENSSL_CFG_FLAGS_ARM $OPENSSL_CFG_FLAGS\"\n#    OPENSSL_CFG_CPU=\"--cpu=cortex-a8\"\nelif [ \"$FF_ARCH\" = \"armv7s\" ]; then\n    FF_BUILD_NAME=\"openssl-armv7s\"\n    OPENSSL_CFG_CPU=\"--cpu=swift\"\n    FF_XCRUN_OSVERSION=\"-miphoneos-version-min=6.0\"\n    FF_XCODE_BITCODE=\"-fembed-bitcode\"\n    OPENSSL_CFG_FLAGS=\"$OPENSSL_CFG_FLAGS_ARM $OPENSSL_CFG_FLAGS\"\nelif [ \"$FF_ARCH\" = \"arm64\" ]; then\n    FF_BUILD_NAME=\"openssl-arm64\"\n    FF_XCRUN_OSVERSION=\"-miphoneos-version-min=7.0\"\n    FF_XCODE_BITCODE=\"-fembed-bitcode\"\n    OPENSSL_CFG_FLAGS=\"$OPENSSL_CFG_FLAGS_ARM $OPENSSL_CFG_FLAGS\"\n    FF_GASPP_EXPORT=\"GASPP_FIX_XCODE5=1\"\nelse\n    echo \"unknown architecture $FF_ARCH\";\n    exit 1\nfi\n\necho \"build_name: $FF_BUILD_NAME\"\necho \"platform:   $FF_XCRUN_PLATFORM\"\necho \"osversion:  $FF_XCRUN_OSVERSION\"\n\n#--------------------\necho \"====================\"\necho \"[*] make ios toolchain $FF_BUILD_NAME\"\necho \"====================\"\n\n\nFF_BUILD_SOURCE=\"$FF_BUILD_ROOT/$FF_BUILD_NAME\"\nFF_BUILD_PREFIX=\"$FF_BUILD_ROOT/build/$FF_BUILD_NAME/output\"\n\nmkdir -p $FF_BUILD_PREFIX\n\n\nFF_XCRUN_SDK=`echo $FF_XCRUN_PLATFORM | tr '[:upper:]' '[:lower:]'`\nFF_XCRUN_SDK_PLATFORM_PATH=`xcrun -sdk $FF_XCRUN_SDK --show-sdk-platform-path`\nFF_XCRUN_SDK_PATH=`xcrun -sdk $FF_XCRUN_SDK --show-sdk-path`\nFF_XCRUN_CC=\"xcrun -sdk $FF_XCRUN_SDK clang\"\n\nexport CROSS_TOP=\"$FF_XCRUN_SDK_PLATFORM_PATH/Developer\"\nexport CROSS_SDK=`echo ${FF_XCRUN_SDK_PATH/#$CROSS_TOP\\/SDKs\\//}`\nexport BUILD_TOOL=\"$FF_XCRUN_DEVELOPER\"\nexport CC=\"$FF_XCRUN_CC -arch $FF_ARCH $FF_XCRUN_OSVERSION\"\n\necho \"build_source: $FF_BUILD_SOURCE\"\necho \"build_prefix: $FF_BUILD_PREFIX\"\necho \"CROSS_TOP: $CROSS_TOP\"\necho \"CROSS_SDK: $CROSS_SDK\"\necho \"BUILD_TOOL: $BUILD_TOOL\"\necho \"CC: $CC\"\n\n#--------------------\necho \"\\n--------------------\"\necho \"[*] configurate openssl\"\necho \"--------------------\"\n\nOPENSSL_CFG_FLAGS=\"$OPENSSL_CFG_FLAGS $FF_XCODE_BITCODE\"\nOPENSSL_CFG_FLAGS=\"$OPENSSL_CFG_FLAGS --openssldir=$FF_BUILD_PREFIX\"\n\n# xcode configuration\nexport DEBUG_INFORMATION_FORMAT=dwarf-with-dsym\n\ncd $FF_BUILD_SOURCE\nif [ -f \"./Makefile\" ]; then\n    echo 'reuse configure'\nelse\n    echo \"config: $OPENSSL_CFG_FLAGS\"\n    ./Configure \\\n        $OPENSSL_CFG_FLAGS\n    make clean\nfi\n\n#--------------------\necho \"\\n--------------------\"\necho \"[*] compile openssl\"\necho \"--------------------\"\nset +e\nmake\nmake install_sw\n"
  },
  {
    "path": "ios/tools/ffversion.h",
    "content": "/*\n * ffversion.h\n *\n * Copyright (c) 2013 Bilibili\n * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>\n *\n * This file is part of ijkPlayer.\n *\n * ijkPlayer is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * ijkPlayer is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with ijkPlayer; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#if   defined(__aarch64__)\n#   include \"arm64/ffversion.h\"\n#elif defined(__x86_64__)\n#   include \"x86_64/ffversion.h\"\n#elif defined(__arm__)\n\n#   if   defined(__ARM_ARCH_7S__)\n#       include \"armv7s/ffversion.h\"\n#   elif defined(__ARM_ARCH_7__)\n#       include \"armv7/ffversion.h\"\n#   else\n#       error Unsupport ARM architecture\n#   endif\n\n#elif defined(__i386__)\n#   include \"i386/ffversion.h\"\n#else\n#   error Unsupport architecture\n#endif\n"
  },
  {
    "path": "tools/.gitignore",
    "content": "####################\n# from gitignore/Python.gitignore\n####################\n# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nenv/\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\n*.egg-info/\n.installed.cfg\n*.egg\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*,cover\n.hypothesis/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\nlocal_settings.py\n\n# Flask stuff:\ninstance/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n# Jupyter Notebook\n.ipynb_checkpoints\n\n# pyenv\n.python-version\n\n# celery beat schedule file\ncelerybeat-schedule\n\n# dotenv\n.env\n\n# virtualenv\n.venv/\nvenv/\nENV/\n\n# Spyder project settings\n.spyderproject\n\n# Rope project settings\n.ropeproject\n\n"
  },
  {
    "path": "tools/copyrighter/CRContext.py",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2017 Bilibili\n# Copyright (C) 2013-2017 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nimport datetime\nimport os\nimport fnmatch\nfrom sets import Set\n\nfrom copyrighter.CRCopyright import CRCopyright\n\nclass CRContext:\n    file_ext_white_list = Set([\n        # '*',\n        'c',\n        'h',\n        'java',\n        'm',\n        'mk',\n        'py',\n        'sh',\n        ])\n\n    rel_path_black_list = Set([\n        '*.a',\n        '*.d',\n        '*.jar',\n        '*.lib',\n        '*.lproj',\n        '*.o',\n        '*.patch',\n        '*.pbxproj',\n        '*.pch',\n        '*.png',\n        '*.pyc',\n        '*.so',\n        '*.strings',\n        '*.xcassets',\n        '*.xcodeproj',\n        '*.xcuserdatad',\n        '*.xcworkspace',\n        '*.xib',\n\n        'android/contrib',\n        'android/ijkplayer/build',\n        'android/ijkplayer/*/build',\n        'android/ijkplayer/*/libs',\n        'android/ijkplayer/*/obj',\n        'android/ijkplayer/*/res',\n        'android/patches',\n        'extra',\n        'ijkmedia/ijkyuv',\n        'ijkmedia/ijkj4a',\n        'ijkprof/android-ndk-profiler',\n        'ios/build',\n        'ios/contrib',\n        'ios/ffmpeg-*',\n        'ios/openssl-*',\n        ])\n\n    def __init__(self, verbose = True, dryrun = True):\n        self.verbose    = verbose\n        self.dryrun     = dryrun\n        self.root_path  = os.path.realpath(os.path.join(__file__, '../../..'))\n        self.year       = datetime.date.today().year\n\n    def get_path_of_file(self, file):\n        if not os.path.isabs(file):\n            file = os.path.realpath(os.path.join(self.root_path, file))\n        return file\n\n    def get_relpath(self, file):\n        return os.path.relpath(file, self.root_path)\n\n    def is_black_path(self, path):\n        rel_path = self.get_relpath(path)\n        for black_item in CRContext.rel_path_black_list:\n            if fnmatch.fnmatch(rel_path, black_item):\n                # print '  + fnmatch %s %s' % (rel_path, black_item)\n                return True\n            # else:\n                # print '  - fnmatch %s %s' % (rel_path, black_item)\n        return False\n\n    def need_copyright(self, file):\n        if '*' in CRContext.file_ext_white_list:\n            return True\n        ext = os.path.splitext(file)[1][1:]\n        return ext in CRContext.file_ext_white_list\n\n    def log_file(self, tag, file):\n        if self.verbose:\n            rel_path = self.get_relpath(file)\n            print '%-10s %s' % (tag, rel_path)\n"
  },
  {
    "path": "tools/copyrighter/CRCopyright.py",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2017 Bilibili\n# Copyright (C) 2013-2017 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nimport re\n\nclass CRCopyright:\n    regexp = None\n\n    def __init__(self, name, url = None, prefix = None, symbol = None, years = None):\n        self.name   = name\n        self.url    = url\n        self.prefix = prefix\n        self.symbol = symbol\n        self.years  = years\n        assert prefix\n        assert symbol\n        assert years\n        assert name\n\n    def duplicate(self):\n        return CRCopyright(\n            name   = self.name,\n            url    = self.url,\n            prefix = self.prefix,\n            symbol = self.symbol,\n            years  = self.years,\n            )\n\n    def get_line(self):\n        line = '%sCopyright %s %s %s' % (self.prefix, self.symbol, self.years, self.name)\n        if self.url:\n            line += ' <%s>' % self.url\n        return line\n\n    def match_name(self, name):\n        if not self.name or not name:\n            return False\n        return self.name.lower() == name.lower()\n\n    def match_name(self, url):\n        if not self.url or not url:\n            return False\n        return self.url.lower() == url.lower()\n\n    @staticmethod\n    def scan_line(context, line):\n        if line[-1] == '\\n':\n            line = line[0:-1]\n        if not CRCopyright.regexp:\n            # CRCopyright.regexp = re.compile(\"^([#\\*\\/\\s]+)Copyright(?:\\s+)([\\(\\)\\w]+)(?:\\s+)([\\d]+|[\\d]+-[\\d]+)(?:\\s+)([\\w\\s]+)[$|(<[\\w\\.@]+>)$]\")\n            # 1 prefix\n            # 3 symbol\n            # 5 year\n            # 6 name\n            # 7 url\n            CRCopyright.regexp = re.compile(\n                pattern = \"^([#\\*\\/\\s]+)Copyright(\\s+)([\\(\\)\\w]+)(\\s+)([0-9\\-]+)([^<]+)(.*)$\",\n                flags = re.IGNORECASE,\n                )\n        m = CRCopyright.regexp.match(line)\n        if m:\n            prefix = m.group(1)\n            symbol = m.group(3).strip()\n            years  = m.group(5).strip()\n            name   = m.group(6).strip()\n            url    = m.group(7).strip().strip('<>')\n            if prefix and symbol and years and name:\n                cr = CRCopyright(\n                    prefix = prefix,\n                    symbol = symbol,\n                    years  = years,\n                    name   = name,\n                    url    = url,\n                    )\n                return cr\n            # print '>====='\n            # for i in range(1, 8):\n            #     print '> %d \"%s\"' % (i, match.group(i))\n            # print '>====='\n        return None\n"
  },
  {
    "path": "tools/copyrighter/CRFile.py",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2017 Bilibili\n# Copyright (C) 2013-2017 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nimport os\nimport shutil\n\nfrom copyrighter.CRCopyright import CRCopyright\n\nclass CRFile:\n    def __init__(self, context, file):\n        self.dirty           = False\n        self.context         = context\n        self.abs_path        = context.get_path_of_file(file)\n        self.file_ext        = os.path.splitext(self.abs_path)[1][1:]\n        self.copyright_names = {}\n        self.copyright_urls  = {}\n        self.need_insert_bilibili_copyright = True\n\n    def update(self):\n        if not self.dirty:\n            self.context.log_file('~ remain', self.abs_path)\n            return\n        tmp_path = self.abs_path + '.tmp'\n        if self.context.dryrun:\n            src = open(self.abs_path, 'r')\n        else:\n            shutil.copy2(self.abs_path, tmp_path)\n            src = open(tmp_path, 'r')\n            tmp = open(self.abs_path, 'w')\n        did_insert_bilibili_copyright = False\n        for line in src:\n            if self.need_insert_bilibili_copyright and not did_insert_bilibili_copyright:\n                copyright = CRCopyright.scan_line(self.context, line)\n                if copyright:\n                    copyright.name = 'Bilibili'\n                    copyright.url  = None\n                    if not self.context.dryrun:\n                        tmp.write(copyright.get_line())\n                        tmp.write(\"\\n\")\n                    # print '    insert %s' % copyright.get_line()\n                    did_insert_bilibili_copyright = True\n            if not self.context.dryrun:\n                tmp.write(line)    \n        src.close()\n        if not self.context.dryrun:\n            tmp.close()\n            os.remove(tmp_path)\n\n        if self.need_insert_bilibili_copyright and did_insert_bilibili_copyright:\n            self.context.log_file('+ update', self.abs_path)\n        else:\n            self.context.log_file('~ missing', self.abs_path)\n\n    def copyright_names(self):\n        return self.copyright_names.keys()\n\n    def copyright_urls(self):\n        return self.copyright_urls.keys()\n\n    def __parse_line(self, line):\n        copyright = CRCopyright.scan_line(self.context, line)\n        if copyright:\n            # print \"match %s\" % copyright.name\n            self.copyright_names[copyright.name.lower()] = copyright\n            self.copyright_urls[copyright.url.lower()]   = copyright\n        return True\n\n    @staticmethod\n    def load_from_file(context, file):\n        parsed_lines = 0;\n        crf          = CRFile(context = context, file = file)\n        f            = open(crf.abs_path, 'r')\n        for line in f:\n            if parsed_lines > 20:\n                break\n            parsed_lines += 1\n            crf.__parse_line(line)\n        f.close()\n        # TODO: use a visitor\n        if 'bilibili' not in crf.copyright_names:\n            if 'zhang rui' in crf.copyright_names or 'bbcallen@gmail.com' in crf.copyright_urls:\n                crf.need_insert_bilibili_copyright = True\n                crf.dirty                          = True\n        return crf\n\n    @staticmethod\n    def update_path(context, file):\n        base_name = os.path.basename(file)\n        abs_path  = context.get_path_of_file(file)\n        if   base_name.startswith('.'):\n            context.log_file('- hidden', abs_path)\n            return\n        elif context.is_black_path(abs_path):\n            context.log_file('- black', abs_path)\n            return\n        elif os.path.islink(abs_path):\n            context.log_file('- link', abs_path)\n            return\n        elif os.path.isdir(abs_path):\n            for sub_file in os.listdir(abs_path):\n                sub_path = os.path.realpath(os.path.join(abs_path, sub_file))\n                CRFile.update_path(context, sub_path)\n        elif not context.need_copyright(abs_path):\n            context.log_file('- nohead', abs_path)\n            return\n        elif os.path.isfile(abs_path):\n            src_file = CRFile.load_from_file(context, abs_path)\n            src_file.update()\n"
  },
  {
    "path": "tools/copyrighter/__init__.py",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2017 Bilibili\n# Copyright (C) 2013-2017 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n"
  },
  {
    "path": "tools/copyrighter/__main__.py",
    "content": "#! /usr/bin/env bash\n#\n# Copyright (C) 2013-2017 Bilibili\n# Copyright (C) 2013-2017 Zhang Rui <bbcallen@gmail.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nimport sys\nimport os\nimport fnmatch\nfrom sets import Set\n\nif not __package__:\n    path = os.path.join(os.path.dirname(__file__), os.pardir)\n    sys.path.insert(0, path)\n\nfrom copyrighter.CRContext import CRContext\nfrom copyrighter.CRFile import CRFile\n\ncontext = CRContext();\n\ntarget_list = Set([\n    'ijkmedia',\n    'extra/init-extra.sh'\n    ])\n\nfor target in Set(['']):\n# for target in target_list:\n    CRFile.update_path(context, target)\n"
  },
  {
    "path": "tools/pull-repo-base.sh",
    "content": "#! /usr/bin/env bash\n\nREMOTE_REPO=$1\nLOCAL_WORKSPACE=$2\n\n\nif [ -z $REMOTE_REPO -o -z $LOCAL_WORKSPACE ]; then\n    echo \"invalid call pull-repo.sh '$REMOTE_REPO' '$LOCAL_WORKSPACE'\"\nelif [ ! -d $LOCAL_WORKSPACE ]; then\n    git clone $REMOTE_REPO $LOCAL_WORKSPACE\nelse\n    cd $LOCAL_WORKSPACE\n    git fetch --all --tags\n    cd -\nfi\n"
  },
  {
    "path": "tools/pull-repo-ref.sh",
    "content": "#! /usr/bin/env bash\n\nREMOTE_REPO=$1\nLOCAL_WORKSPACE=$2\nREF_REPO=$3\n\nif [ -z $1 -o -z $2 -o -z $3 ]; then\n    echo \"invalid call pull-repo.sh '$1' '$2' '$3'\"\nelif [ ! -d $LOCAL_WORKSPACE ]; then\n    git clone --reference $REF_REPO $REMOTE_REPO $LOCAL_WORKSPACE\n    cd $LOCAL_WORKSPACE\n    git repack -a\nelse\n    cd $LOCAL_WORKSPACE\n    git fetch --all --tags\n    cd -\nfi\n"
  },
  {
    "path": "tools/setup-as-commiter.sh",
    "content": "#! /usr/bin/env bash\n\ngit remote add gitcafe git@gitcafe.com:bbcallen/ijkplayer.git\ngit remote add oschina git@git.oschina.net:bbcallen/ijkplayer.git\ngit remote add csdn git@code.csdn.net:bbcallen/ijkplayer.git\ngit fetch --all\n\n"
  },
  {
    "path": "tools/sync-mirrors.sh",
    "content": "#! /usr/bin/env bash\n\ngit push origin --all --follow-tags\ngit push gitcafe --all --follow-tags\ngit push oschina --all --follow-tags\ngit push csdn --all --follow-tags\n\n"
  },
  {
    "path": "version.sh",
    "content": "#!/bin/sh\n\nset -e\n\nVERSION_CODE=800800\nVERSION_NAME=0.8.8\nVERSION_TARGET=$1\n\ndo_version_readme() {\n    # README.md\n    # cat README.md \\\n    # | sed \"s/\\(#compile 'tv.danmaku.ijk.media:ijkplayer-java:#\\)[[:digit:]][[:digit:].]*\\(#'#\\)/\\1:$VERSION_NAME\\2/\" \\\n    # > README.md.new\n\n    cat README.md \\\n    | sed \"s/\\(compile \\'tv.danmaku.ijk.media:ijkplayer-[[:alnum:]_]*:\\)[[:digit:].]*[[:digit:]]/\\1$VERSION_NAME/g\" \\\n    | sed \"s/\\(git checkout -B latest k\\)[[:digit:]][[:digit:].]*/\\1$VERSION_NAME/g\" \\\n    > README.md.new\n\n    mv -f README.md.new README.md\n}\n\ndo_version_gradle() {\n    # android/ijkplayer/build.gradle\n    cat android/ijkplayer/build.gradle \\\n    | sed \"s/\\(versionCode[[:space:]]*=[[:space:]]*\\)[[:digit:]][[:digit:]]*/\\1$VERSION_CODE/\" \\\n    | sed \"s/\\(versionName[[:space:]]*=[[:space:]]*\\)\\\"[[:digit:].]*[[:digit:]]\\\"/\\1\\\"$VERSION_NAME\\\"/\" \\\n    > android/ijkplayer/build.gradle.new\n\n    mv -f android/ijkplayer/build.gradle.new android/ijkplayer/build.gradle\n\n\n\n    # android/ijkplayer/gradle.properties\n    cat android/ijkplayer/gradle.properties \\\n    | sed \"s/\\(VERSION_NAME=\\)[[:digit:].]*[[:digit:]]/\\1$VERSION_NAME/\" \\\n    | sed \"s/\\(VERSION_CODE=\\)[[:digit:]][[:digit:]]*/\\1$VERSION_CODE/\" \\\n    > android/ijkplayer/gradle.properties.new\n\n    mv -f android/ijkplayer/gradle.properties.new android/ijkplayer/gradle.properties\n\n\n\n    # android/ijkplayer/ijkplayer-exo/build.gradle\n    cat android/ijkplayer/ijkplayer-exo/build.gradle \\\n    | sed \"s/\\(compile \\'tv.danmaku.ijk.media:ijkplayer-[-_[:alpha:][:digit:]]*:\\)[[:digit:].]*[[:digit:]]/\\1$VERSION_NAME/g\" \\\n    > android/ijkplayer/ijkplayer-exo/build.gradle.new\n\n    mv -f android/ijkplayer/ijkplayer-exo/build.gradle.new android/ijkplayer/ijkplayer-exo/build.gradle\n\n\n\n    # android/ijkplayer/ijkplayer-example/build.gradle\n    cat android/ijkplayer/ijkplayer-example/build.gradle \\\n    | sed \"s/\\(ompile \\'tv.danmaku.ijk.media:ijkplayer-[-_[:alpha:][:digit:]]*:\\)[[:digit:].]*[[:digit:]]/\\1$VERSION_NAME/g\" \\\n    > android/ijkplayer/ijkplayer-example/build.gradle.new\n\n    mv -f android/ijkplayer/ijkplayer-example/build.gradle.new android/ijkplayer/ijkplayer-example/build.gradle\n}\n\ndo_version_xcode() {\n    # ios/IJKMediaPlayer/IJKMediaPlayer.xcodeproj/project.pbxproj\n\n    cat ios/IJKMediaPlayer/IJKMediaPlayer.xcodeproj/project.pbxproj \\\n    | sed \"s/\\(CURRENT_PROJECT_VERSION = \\).*;/\\1$VERSION_NAME;/g\" \\\n    > ios/IJKMediaPlayer/IJKMediaPlayer.xcodeproj/project.pbxproj.new\n\n    mv -f ios/IJKMediaPlayer/IJKMediaPlayer.xcodeproj/project.pbxproj.new ios/IJKMediaPlayer/IJKMediaPlayer.xcodeproj/project.pbxproj\n}\n\nif [ \"$VERSION_TARGET\" = \"readme\" ]; then\n    do_version_readme\nelif [ \"$VERSION_TARGET\" = \"gradle\" ]; then\n    do_version_gradle\nelif [ \"$VERSION_TARGET\" = \"show\" ]; then\n    echo $VERSION_NAME\nelif [ \"$VERSION_TARGET\" = \"xcode\" ]; then\n    do_version_xcode\nelse\n    do_version_readme\n    do_version_gradle\n    do_version_xcode\nfi\n\n"
  }
]