diff --git a/.github/LICENSE b/.github/LICENSE new file mode 100644 index 000000000..de80a5199 --- /dev/null +++ b/.github/LICENSE @@ -0,0 +1,289 @@ +This software is available under two different licenses. +For applications that are entirely distributable under the terms of the GPL +(GPL 2.0 License, see below), the Bento4 GPL license applies. +For applications that cannot be entirely distributable under the terms of the +GPL (either the application, or code modules linked with the application are +not compatible with the terms of the GPL licence), a non-GPL commercial license +is available from Axiomatic Systems LLC. +Contact Gilles Boccon-Gibod (licensing@axiosys.com) for more information. + +GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7f7918d9d..4401cd380 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,6 +52,8 @@ jobs: # Upload the SDK - name: Upload SDK if: github.event_name == 'push' - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: path: SDK/*.zip + overwrite: true + diff --git a/Build/Makefiles/Lib.mak b/Build/Makefiles/Lib.mak index 66a46712b..ca9066c32 100644 --- a/Build/Makefiles/Lib.mak +++ b/Build/Makefiles/Lib.mak @@ -17,6 +17,7 @@ CORE_SOURCES = \ Ap4Av1cAtom.cpp \ Ap4ByteStream.cpp \ Ap4Co64Atom.cpp \ + Ap4ColrAtom.cpp \ Ap4ContainerAtom.cpp \ Ap4CttsAtom.cpp \ Ap4DataBuffer.cpp \ @@ -25,6 +26,7 @@ CORE_SOURCES = \ Ap4DecoderSpecificInfoDescriptor.cpp \ Ap4Descriptor.cpp \ Ap4DescriptorFactory.cpp \ + Ap4DmlpAtom.cpp \ Ap4DrefAtom.cpp \ Ap4EsDescriptor.cpp \ Ap4EsdsAtom.cpp \ diff --git a/Build/Targets/universal-apple-macosx/Bento4.xcodeproj/project.pbxproj b/Build/Targets/universal-apple-macosx/Bento4.xcodeproj/project.pbxproj index 4efbe9880..015b6d1b4 100644 --- a/Build/Targets/universal-apple-macosx/Bento4.xcodeproj/project.pbxproj +++ b/Build/Targets/universal-apple-macosx/Bento4.xcodeproj/project.pbxproj @@ -382,6 +382,8 @@ CAC8F17C16BE448300C49741 /* libBento4.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CAA7E6C914ACD763008AA54E /* libBento4.a */; }; CACDDD6916BF5FE500B79B20 /* Mp4AudioClip.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CACDDD6816BF5FC200B79B20 /* Mp4AudioClip.cpp */; }; CAD6A7C40F7AFFD800456513 /* Ap4DynamicCast.h in Headers */ = {isa = PBXBuildFile; fileRef = CAD6A7C30F7AFFD800456513 /* Ap4DynamicCast.h */; }; + CAD96AE12FE93E4F0061C8C7 /* Ap4ColrAtom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CAD96AE02FE93E4F0061C8C7 /* Ap4ColrAtom.cpp */; }; + CAD96AE22FE93E4F0061C8C7 /* Ap4ColrAtom.h in Headers */ = {isa = PBXBuildFile; fileRef = CAD96ADF2FE93E4F0061C8C7 /* Ap4ColrAtom.h */; }; CAE03ABF1034AE0D006FAFD7 /* Ap4Hmac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CAE03ABD1034AE0D006FAFD7 /* Ap4Hmac.cpp */; }; CAE03AC01034AE0D006FAFD7 /* Ap4Hmac.h in Headers */ = {isa = PBXBuildFile; fileRef = CAE03ABE1034AE0D006FAFD7 /* Ap4Hmac.h */; }; CAE1FBF21AF8493E00607B3C /* libBento4.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CAA7E6C914ACD763008AA54E /* libBento4.a */; }; @@ -420,6 +422,8 @@ CAF9812818DBEE640001B999 /* libBento4.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CAA7E6C914ACD763008AA54E /* libBento4.a */; }; CAF9813818DBF3640001B999 /* Mp42Hevc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CAF9812A18DBF3360001B999 /* Mp42Hevc.cpp */; }; CAF9813B18DBF3730001B999 /* libBento4.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CAA7E6C914ACD763008AA54E /* libBento4.a */; }; + CAFB87FE2ED5FDFB003070A9 /* Ap4DmlpAtom.h in Headers */ = {isa = PBXBuildFile; fileRef = CAFB87FC2ED5FDFB003070A9 /* Ap4DmlpAtom.h */; }; + CAFB87FF2ED5FDFB003070A9 /* Ap4DmlpAtom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CAFB87FD2ED5FDFB003070A9 /* Ap4DmlpAtom.cpp */; }; CAFC31CE0FEB3E7C00EF80A0 /* FragmentParserTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CAFC31CD0FEB3E7C00EF80A0 /* FragmentParserTest.cpp */; }; CAFC31D90FEB95F700EF80A0 /* Ap4MovieFragment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CAFC31D70FEB95F700EF80A0 /* Ap4MovieFragment.cpp */; }; CAFC31DA0FEB95F700EF80A0 /* Ap4MovieFragment.h in Headers */ = {isa = PBXBuildFile; fileRef = CAFC31D80FEB95F700EF80A0 /* Ap4MovieFragment.h */; }; @@ -1344,6 +1348,8 @@ CAC8F17016BE444D00C49741 /* mp4audioclip */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mp4audioclip; sourceTree = BUILT_PRODUCTS_DIR; }; CACDDD6816BF5FC200B79B20 /* Mp4AudioClip.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Mp4AudioClip.cpp; sourceTree = ""; }; CAD6A7C30F7AFFD800456513 /* Ap4DynamicCast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Ap4DynamicCast.h; sourceTree = ""; }; + CAD96ADF2FE93E4F0061C8C7 /* Ap4ColrAtom.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Ap4ColrAtom.h; sourceTree = ""; }; + CAD96AE02FE93E4F0061C8C7 /* Ap4ColrAtom.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Ap4ColrAtom.cpp; sourceTree = ""; }; CAE03ABD1034AE0D006FAFD7 /* Ap4Hmac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Ap4Hmac.cpp; sourceTree = ""; }; CAE03ABE1034AE0D006FAFD7 /* Ap4Hmac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Ap4Hmac.h; sourceTree = ""; }; CAE1FBF61AF8493E00607B3C /* mp42hls */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mp42hls; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1386,6 +1392,8 @@ CAF9811A18DBED9B0001B999 /* hevcinfo */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = hevcinfo; sourceTree = BUILT_PRODUCTS_DIR; }; CAF9812A18DBF3360001B999 /* Mp42Hevc.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Mp42Hevc.cpp; sourceTree = ""; }; CAF9812F18DBF34B0001B999 /* mp42hevc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mp42hevc; sourceTree = BUILT_PRODUCTS_DIR; }; + CAFB87FC2ED5FDFB003070A9 /* Ap4DmlpAtom.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Ap4DmlpAtom.h; sourceTree = ""; }; + CAFB87FD2ED5FDFB003070A9 /* Ap4DmlpAtom.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Ap4DmlpAtom.cpp; sourceTree = ""; }; CAFC31B90FEB3DDD00EF80A0 /* FragmentParserTest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = FragmentParserTest; sourceTree = BUILT_PRODUCTS_DIR; }; CAFC31CD0FEB3E7C00EF80A0 /* FragmentParserTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FragmentParserTest.cpp; sourceTree = ""; }; CAFC31D70FEB95F700EF80A0 /* Ap4MovieFragment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Ap4MovieFragment.cpp; sourceTree = ""; }; @@ -2070,251 +2078,257 @@ CA93660F0B437D030067D50B /* Core */ = { isa = PBXGroup; children = ( + CAD96ADF2FE93E4F0061C8C7 /* Ap4ColrAtom.h */, + CAD96AE02FE93E4F0061C8C7 /* Ap4ColrAtom.cpp */, A8DFF206222E496F006CBAE9 /* Ap4Ac4Utils.cpp */, A8DFF207222E4970006CBAE9 /* Ap4Ac4Utils.h */, CA5A8F8B13541628007C6EFC /* Ap4.cpp */, CA9366100B437D030067D50B /* Ap4.h */, - CAF0104515343D5D00CCD976 /* Ap4AinfAtom.cpp */, + A8DFF207222E4970006CBAE9 /* Ap4Ac4Utils.h */, + A8DFF206222E496F006CBAE9 /* Ap4Ac4Utils.cpp */, CAF0104615343D5D00CCD976 /* Ap4AinfAtom.h */, + CAF0104515343D5D00CCD976 /* Ap4AinfAtom.cpp */, CA9366110B437D030067D50B /* Ap4Array.h */, - CA9366120B437D030067D50B /* Ap4Atom.cpp */, CA9366130B437D030067D50B /* Ap4Atom.h */, - CA9366140B437D030067D50B /* Ap4AtomFactory.cpp */, + CA9366120B437D030067D50B /* Ap4Atom.cpp */, CA9366150B437D030067D50B /* Ap4AtomFactory.h */, - CA9366160B437D030067D50B /* Ap4AtomSampleTable.cpp */, + CA9366140B437D030067D50B /* Ap4AtomFactory.cpp */, CA9366170B437D030067D50B /* Ap4AtomSampleTable.h */, - CAAE667325F5F6F600198E64 /* Ap4Av1cAtom.cpp */, + CA9366160B437D030067D50B /* Ap4AtomSampleTable.cpp */, CAAE667425F5F6F600198E64 /* Ap4Av1cAtom.h */, - F9B1F4F90B54AD91003F147E /* Ap4AvccAtom.cpp */, + CAAE667325F5F6F600198E64 /* Ap4Av1cAtom.cpp */, F9B1F4FA0B54AD91003F147E /* Ap4AvccAtom.h */, - CAF0104715343D5D00CCD976 /* Ap4BlocAtom.cpp */, + F9B1F4F90B54AD91003F147E /* Ap4AvccAtom.cpp */, CAF0104815343D5D00CCD976 /* Ap4BlocAtom.h */, - CA9366180B437D030067D50B /* Ap4ByteStream.cpp */, + CAF0104715343D5D00CCD976 /* Ap4BlocAtom.cpp */, CA9366190B437D030067D50B /* Ap4ByteStream.h */, - CA93661A0B437D030067D50B /* Ap4Co64Atom.cpp */, + CA9366180B437D030067D50B /* Ap4ByteStream.cpp */, CA93661B0B437D030067D50B /* Ap4Co64Atom.h */, - CAEDC8FA0DFF61AE00F070A8 /* Ap4Command.cpp */, + CA93661A0B437D030067D50B /* Ap4Co64Atom.cpp */, CAA033310DF7D4CC0086EC1C /* Ap4Command.h */, - CAA0332B0DF7D3390086EC1C /* Ap4CommandFactory.cpp */, + CAEDC8FA0DFF61AE00F070A8 /* Ap4Command.cpp */, CAA0332C0DF7D3390086EC1C /* Ap4CommandFactory.h */, - CA5733E613B3AB0A00953446 /* Ap4CommonEncryption.cpp */, + CAA0332B0DF7D3390086EC1C /* Ap4CommandFactory.cpp */, CA5733E713B3AB0A00953446 /* Ap4CommonEncryption.h */, + CA5733E613B3AB0A00953446 /* Ap4CommonEncryption.cpp */, CA93661C0B437D030067D50B /* Ap4Config.h */, CA93661D0B437D030067D50B /* Ap4Constants.h */, - CA93661E0B437D030067D50B /* Ap4ContainerAtom.cpp */, CA93661F0B437D030067D50B /* Ap4ContainerAtom.h */, - CA9366200B437D040067D50B /* Ap4CttsAtom.cpp */, + CA93661E0B437D030067D50B /* Ap4ContainerAtom.cpp */, CA9366210B437D040067D50B /* Ap4CttsAtom.h */, - AC28E6B82389DE04005D9BE9 /* Ap4Dac3Atom.cpp */, + CA9366200B437D040067D50B /* Ap4CttsAtom.cpp */, AC28E6B92389DE05005D9BE9 /* Ap4Dac3Atom.h */, - CAA55DAA20F12F3C00CBAA11 /* Ap4Dac4Atom.cpp */, + AC28E6B82389DE04005D9BE9 /* Ap4Dac3Atom.cpp */, CAA55DA920F12F3C00CBAA11 /* Ap4Dac4Atom.h */, - CA9366220B437D040067D50B /* Ap4DataBuffer.cpp */, + CAA55DAA20F12F3C00CBAA11 /* Ap4Dac4Atom.cpp */, CA9366230B437D040067D50B /* Ap4DataBuffer.h */, - CA9366240B437D040067D50B /* Ap4Debug.cpp */, + CA9366220B437D040067D50B /* Ap4DataBuffer.cpp */, CA9366250B437D040067D50B /* Ap4Debug.h */, - CAB82A071859CD7000FC4944 /* Ap4Dec3Atom.cpp */, + CA9366240B437D040067D50B /* Ap4Debug.cpp */, CAB82A081859CD7000FC4944 /* Ap4Dec3Atom.h */, - CA9366260B437D040067D50B /* Ap4DecoderConfigDescriptor.cpp */, + CAB82A071859CD7000FC4944 /* Ap4Dec3Atom.cpp */, CA9366270B437D040067D50B /* Ap4DecoderConfigDescriptor.h */, - CA9366280B437D040067D50B /* Ap4DecoderSpecificInfoDescriptor.cpp */, + CA9366260B437D040067D50B /* Ap4DecoderConfigDescriptor.cpp */, CA9366290B437D040067D50B /* Ap4DecoderSpecificInfoDescriptor.h */, - CA93662A0B437D040067D50B /* Ap4Descriptor.cpp */, + CA9366280B437D040067D50B /* Ap4DecoderSpecificInfoDescriptor.cpp */, CA93662B0B437D040067D50B /* Ap4Descriptor.h */, - CA93662C0B437D040067D50B /* Ap4DescriptorFactory.cpp */, + CA93662A0B437D040067D50B /* Ap4Descriptor.cpp */, CA93662D0B437D040067D50B /* Ap4DescriptorFactory.h */, - CA93662E0B437D040067D50B /* Ap4DrefAtom.cpp */, + CA93662C0B437D040067D50B /* Ap4DescriptorFactory.cpp */, + CAFB87FC2ED5FDFB003070A9 /* Ap4DmlpAtom.h */, + CAFB87FD2ED5FDFB003070A9 /* Ap4DmlpAtom.cpp */, CA93662F0B437D040067D50B /* Ap4DrefAtom.h */, - CAEE5E781CC6972E0094DF0D /* Ap4DvccAtom.cpp */, + CA93662E0B437D040067D50B /* Ap4DrefAtom.cpp */, CAEE5E791CC6972E0094DF0D /* Ap4DvccAtom.h */, + CAEE5E781CC6972E0094DF0D /* Ap4DvccAtom.cpp */, CAD6A7C30F7AFFD800456513 /* Ap4DynamicCast.h */, - CA504D5B0C5E8A8A0060E6FE /* Ap4ElstAtom.cpp */, CA504D5C0C5E8A8A0060E6FE /* Ap4ElstAtom.h */, - CA9366300B437D040067D50B /* Ap4EsDescriptor.cpp */, + CA504D5B0C5E8A8A0060E6FE /* Ap4ElstAtom.cpp */, CA9366310B437D040067D50B /* Ap4EsDescriptor.h */, - CA9366320B437D040067D50B /* Ap4EsdsAtom.cpp */, + CA9366300B437D040067D50B /* Ap4EsDescriptor.cpp */, CA9366330B437D040067D50B /* Ap4EsdsAtom.h */, - CAEDC8E60DFF5B1100F070A8 /* Ap4Expandable.cpp */, + CA9366320B437D040067D50B /* Ap4EsdsAtom.cpp */, CAEDC8E70DFF5B1100F070A8 /* Ap4Expandable.h */, - CA9366340B437D040067D50B /* Ap4File.cpp */, + CAEDC8E60DFF5B1100F070A8 /* Ap4Expandable.cpp */, CA9366350B437D040067D50B /* Ap4File.h */, + CA9366340B437D040067D50B /* Ap4File.cpp */, CA9366360B437D040067D50B /* Ap4FileByteStream.h */, - CA1221CD0CA7192B000BEEF6 /* Ap4FileCopier.cpp */, CA1221CE0CA7192B000BEEF6 /* Ap4FileCopier.h */, - CA9366370B437D040067D50B /* Ap4FileWriter.cpp */, + CA1221CD0CA7192B000BEEF6 /* Ap4FileCopier.cpp */, CA9366380B437D040067D50B /* Ap4FileWriter.h */, - CAFC31EE0FEBAA9200EF80A0 /* Ap4FragmentSampleTable.cpp */, + CA9366370B437D040067D50B /* Ap4FileWriter.cpp */, CAFC31EF0FEBAA9200EF80A0 /* Ap4FragmentSampleTable.h */, - CA9366390B437D040067D50B /* Ap4FrmaAtom.cpp */, + CAFC31EE0FEBAA9200EF80A0 /* Ap4FragmentSampleTable.cpp */, CA93663A0B437D040067D50B /* Ap4FrmaAtom.h */, - CA93663B0B437D040067D50B /* Ap4FtypAtom.cpp */, + CA9366390B437D040067D50B /* Ap4FrmaAtom.cpp */, CA93663C0B437D040067D50B /* Ap4FtypAtom.h */, - CAEA9E970E17006D008C396D /* Ap4GrpiAtom.cpp */, + CA93663B0B437D040067D50B /* Ap4FtypAtom.cpp */, CAEA9E980E17006D008C396D /* Ap4GrpiAtom.h */, - CA93663D0B437D040067D50B /* Ap4HdlrAtom.cpp */, + CAEA9E970E17006D008C396D /* Ap4GrpiAtom.cpp */, CA93663E0B437D040067D50B /* Ap4HdlrAtom.h */, - CA93663F0B437D040067D50B /* Ap4HintTrackReader.cpp */, + CA93663D0B437D040067D50B /* Ap4HdlrAtom.cpp */, CA9366400B437D040067D50B /* Ap4HintTrackReader.h */, - CA9366410B437D040067D50B /* Ap4HmhdAtom.cpp */, + CA93663F0B437D040067D50B /* Ap4HintTrackReader.cpp */, CA9366420B437D040067D50B /* Ap4HmhdAtom.h */, - CA094DB218D80E220032290E /* Ap4HvccAtom.cpp */, + CA9366410B437D040067D50B /* Ap4HmhdAtom.cpp */, CA094DB318D80E220032290E /* Ap4HvccAtom.h */, - CA9366430B437D040067D50B /* Ap4IkmsAtom.cpp */, + CA094DB218D80E220032290E /* Ap4HvccAtom.cpp */, CA9366440B437D040067D50B /* Ap4IkmsAtom.h */, + CA9366430B437D040067D50B /* Ap4IkmsAtom.cpp */, CA9366450B437D040067D50B /* Ap4Interfaces.h */, - CA2898AF0D897F20006A758B /* Ap4IodsAtom.cpp */, CA2898B00D897F20006A758B /* Ap4IodsAtom.h */, - CAA033660DF7E2FA0086EC1C /* Ap4Ipmp.cpp */, + CA2898AF0D897F20006A758B /* Ap4IodsAtom.cpp */, CAA033670DF7E2FA0086EC1C /* Ap4Ipmp.h */, - CA9366460B437D040067D50B /* Ap4IproAtom.cpp */, + CAA033660DF7E2FA0086EC1C /* Ap4Ipmp.cpp */, CA9366470B437D040067D50B /* Ap4IproAtom.h */, - CA9366480B437D040067D50B /* Ap4IsfmAtom.cpp */, + CA9366460B437D040067D50B /* Ap4IproAtom.cpp */, CA9366490B437D040067D50B /* Ap4IsfmAtom.h */, - CA93664A0B437D040067D50B /* Ap4IsltAtom.cpp */, + CA9366480B437D040067D50B /* Ap4IsfmAtom.cpp */, CA93664B0B437D040067D50B /* Ap4IsltAtom.h */, - CA93664C0B437D040067D50B /* Ap4IsmaCryp.cpp */, + CA93664A0B437D040067D50B /* Ap4IsltAtom.cpp */, CA93664D0B437D040067D50B /* Ap4IsmaCryp.h */, - CAE723FD0FC33618008F2905 /* Ap4LinearReader.cpp */, + CA93664C0B437D040067D50B /* Ap4IsmaCryp.cpp */, CAE723FE0FC33618008F2905 /* Ap4LinearReader.h */, + CAE723FD0FC33618008F2905 /* Ap4LinearReader.cpp */, CA93664E0B437D040067D50B /* Ap4List.h */, - CA09F27D0DF62FC600C2B2DA /* Ap4Marlin.cpp */, CA09F27E0DF62FC600C2B2DA /* Ap4Marlin.h */, - CA93664F0B437D040067D50B /* Ap4MdhdAtom.cpp */, + CA09F27D0DF62FC600C2B2DA /* Ap4Marlin.cpp */, CA9366500B437D040067D50B /* Ap4MdhdAtom.h */, - CAEFE10C0FB6993D00AF6434 /* Ap4MehdAtom.cpp */, + CA93664F0B437D040067D50B /* Ap4MdhdAtom.cpp */, CAEFE10D0FB6993D00AF6434 /* Ap4MehdAtom.h */, - CA8B6A600F66D20900720A07 /* Ap4MfhdAtom.cpp */, + CAEFE10C0FB6993D00AF6434 /* Ap4MehdAtom.cpp */, CA8B6A610F66D20900720A07 /* Ap4MfhdAtom.h */, - CA91A84A10A29A56008618FE /* Ap4MfroAtom.cpp */, + CA8B6A600F66D20900720A07 /* Ap4MfhdAtom.cpp */, CA91A84B10A29A56008618FE /* Ap4MfroAtom.h */, - CA9366510B437D040067D50B /* Ap4MoovAtom.cpp */, + CA91A84A10A29A56008618FE /* Ap4MfroAtom.cpp */, CA9366520B437D040067D50B /* Ap4MoovAtom.h */, - CA9366530B437D040067D50B /* Ap4Movie.cpp */, + CA9366510B437D040067D50B /* Ap4MoovAtom.cpp */, CA9366540B437D040067D50B /* Ap4Movie.h */, - CAFC31D70FEB95F700EF80A0 /* Ap4MovieFragment.cpp */, + CA9366530B437D040067D50B /* Ap4Movie.cpp */, CAFC31D80FEB95F700EF80A0 /* Ap4MovieFragment.h */, - CA2DBC7B108165330012E204 /* Ap4Mpeg2Ts.cpp */, + CAFC31D70FEB95F700EF80A0 /* Ap4MovieFragment.cpp */, CA2DBC7C108165330012E204 /* Ap4Mpeg2Ts.h */, - CA9366550B437D040067D50B /* Ap4MvhdAtom.cpp */, + CA2DBC7B108165330012E204 /* Ap4Mpeg2Ts.cpp */, CA9366560B437D040067D50B /* Ap4MvhdAtom.h */, - CA9366570B437D040067D50B /* Ap4NmhdAtom.cpp */, + CA9366550B437D040067D50B /* Ap4MvhdAtom.cpp */, CA9366580B437D040067D50B /* Ap4NmhdAtom.h */, - CA2898840D8979B0006A758B /* Ap4ObjectDescriptor.cpp */, + CA9366570B437D040067D50B /* Ap4NmhdAtom.cpp */, CA2898850D8979B0006A758B /* Ap4ObjectDescriptor.h */, - CA9366590B437D040067D50B /* Ap4OdafAtom.cpp */, + CA2898840D8979B0006A758B /* Ap4ObjectDescriptor.cpp */, CA93665A0B437D040067D50B /* Ap4OdafAtom.h */, - CA93665B0B437D040067D50B /* Ap4OddaAtom.cpp */, + CA9366590B437D040067D50B /* Ap4OdafAtom.cpp */, CA93665C0B437D040067D50B /* Ap4OddaAtom.h */, - CA93665D0B437D040067D50B /* Ap4OdheAtom.cpp */, + CA93665B0B437D040067D50B /* Ap4OddaAtom.cpp */, CA93665E0B437D040067D50B /* Ap4OdheAtom.h */, - CA93665F0B437D040067D50B /* Ap4OhdrAtom.cpp */, + CA93665D0B437D040067D50B /* Ap4OdheAtom.cpp */, CA9366600B437D040067D50B /* Ap4OhdrAtom.h */, - CA9366610B437D040067D50B /* Ap4OmaDcf.cpp */, + CA93665F0B437D040067D50B /* Ap4OhdrAtom.cpp */, CA9366620B437D040067D50B /* Ap4OmaDcf.h */, - CA15E16B1467D01A00D4EC8B /* Ap4PdinAtom.cpp */, + CA9366610B437D040067D50B /* Ap4OmaDcf.cpp */, CA15E16C1467D01A00D4EC8B /* Ap4PdinAtom.h */, - CA8E2B401092B71E0042A0AF /* Ap4Piff.cpp */, + CA15E16B1467D01A00D4EC8B /* Ap4PdinAtom.cpp */, CA8E2B411092B71E0042A0AF /* Ap4Piff.h */, - CA9366630B437D040067D50B /* Ap4Processor.cpp */, + CA8E2B401092B71E0042A0AF /* Ap4Piff.cpp */, CA9366640B437D040067D50B /* Ap4Processor.h */, - CA9366650B437D040067D50B /* Ap4Protection.cpp */, + CA9366630B437D040067D50B /* Ap4Processor.cpp */, CA9366660B437D040067D50B /* Ap4Protection.h */, - CAF0104D15343E4000CCD976 /* Ap4PsshAtom.cpp */, + CA9366650B437D040067D50B /* Ap4Protection.cpp */, CAF0104E15343E4000CCD976 /* Ap4PsshAtom.h */, - CA0BBBA00F38D10A00DF01DD /* Ap4Results.cpp */, + CAF0104D15343E4000CCD976 /* Ap4PsshAtom.cpp */, CA9366670B437D040067D50B /* Ap4Results.h */, - CA9366680B437D040067D50B /* Ap4RtpAtom.cpp */, + CA0BBBA00F38D10A00DF01DD /* Ap4Results.cpp */, CA9366690B437D040067D50B /* Ap4RtpAtom.h */, - CA93666A0B437D040067D50B /* Ap4RtpHint.cpp */, + CA9366680B437D040067D50B /* Ap4RtpAtom.cpp */, CA93666B0B437D040067D50B /* Ap4RtpHint.h */, - CA5734E813B5DBB100953446 /* Ap4SaioAtom.cpp */, + CA93666A0B437D040067D50B /* Ap4RtpHint.cpp */, CA5734E913B5DBB100953446 /* Ap4SaioAtom.h */, - CA5734EA13B5DBB100953446 /* Ap4SaizAtom.cpp */, + CA5734E813B5DBB100953446 /* Ap4SaioAtom.cpp */, CA5734EB13B5DBB100953446 /* Ap4SaizAtom.h */, - CA93666C0B437D040067D50B /* Ap4Sample.cpp */, + CA5734EA13B5DBB100953446 /* Ap4SaizAtom.cpp */, CA93666D0B437D040067D50B /* Ap4Sample.h */, - CA93666E0B437D040067D50B /* Ap4SampleDescription.cpp */, + CA93666C0B437D040067D50B /* Ap4Sample.cpp */, CA93666F0B437D040067D50B /* Ap4SampleDescription.h */, - CA9366700B437D040067D50B /* Ap4SampleEntry.cpp */, + CA93666E0B437D040067D50B /* Ap4SampleDescription.cpp */, CA9366710B437D040067D50B /* Ap4SampleEntry.h */, - CA8FF65E1083E4500008965B /* Ap4SampleSource.cpp */, + CA9366700B437D040067D50B /* Ap4SampleEntry.cpp */, CA15CC32107DCEEF0085F329 /* Ap4SampleSource.h */, - CA9366720B437D040067D50B /* Ap4SampleTable.cpp */, + CA8FF65E1083E4500008965B /* Ap4SampleSource.cpp */, CA9366730B437D040067D50B /* Ap4SampleTable.h */, - CAEF5D2D19EB26DC007B66A8 /* Ap4SbgpAtom.cpp */, + CA9366720B437D040067D50B /* Ap4SampleTable.cpp */, CAEF5D2E19EB26DC007B66A8 /* Ap4SbgpAtom.h */, - CA9366740B437D040067D50B /* Ap4SchmAtom.cpp */, + CAEF5D2D19EB26DC007B66A8 /* Ap4SbgpAtom.cpp */, CA9366750B437D040067D50B /* Ap4SchmAtom.h */, - CA9366760B437D040067D50B /* Ap4SdpAtom.cpp */, + CA9366740B437D040067D50B /* Ap4SchmAtom.cpp */, CA9366770B437D040067D50B /* Ap4SdpAtom.h */, - CA86EECF19A95C68008A3B00 /* Ap4SegmentBuilder.cpp */, + CA9366760B437D040067D50B /* Ap4SdpAtom.cpp */, CA86EED019A95C68008A3B00 /* Ap4SegmentBuilder.h */, - CA5734FB13B5DCFA00953446 /* Ap4SencAtom.cpp */, + CA86EECF19A95C68008A3B00 /* Ap4SegmentBuilder.cpp */, CA5734FC13B5DCFA00953446 /* Ap4SencAtom.h */, - CAEF5D3119EB2CB5007B66A8 /* Ap4SgpdAtom.cpp */, + CA5734FB13B5DCFA00953446 /* Ap4SencAtom.cpp */, CAEF5D3219EB2CB5007B66A8 /* Ap4SgpdAtom.h */, - CA7B647E19D2355F00068D77 /* Ap4SidxAtom.cpp */, + CAEF5D3119EB2CB5007B66A8 /* Ap4SgpdAtom.cpp */, CA7B647F19D2355F00068D77 /* Ap4SidxAtom.h */, - CA9366780B437D040067D50B /* Ap4SLConfigDescriptor.cpp */, + CA7B647E19D2355F00068D77 /* Ap4SidxAtom.cpp */, CA9366790B437D040067D50B /* Ap4SLConfigDescriptor.h */, - CA93667A0B437D040067D50B /* Ap4SmhdAtom.cpp */, + CA9366780B437D040067D50B /* Ap4SLConfigDescriptor.cpp */, CA93667B0B437D040067D50B /* Ap4SmhdAtom.h */, - CA93667C0B437D040067D50B /* Ap4StcoAtom.cpp */, + CA93667A0B437D040067D50B /* Ap4SmhdAtom.cpp */, CA93667D0B437D040067D50B /* Ap4StcoAtom.h */, - CA91A7D51A364BE80057C7B2 /* Ap4SthdAtom.cpp */, + CA93667C0B437D040067D50B /* Ap4StcoAtom.cpp */, CA91A7D61A364BE80057C7B2 /* Ap4SthdAtom.h */, - CA93667E0B437D040067D50B /* Ap4String.cpp */, + CA91A7D51A364BE80057C7B2 /* Ap4SthdAtom.cpp */, CA93667F0B437D040067D50B /* Ap4String.h */, - CA9366800B437D040067D50B /* Ap4StscAtom.cpp */, + CA93667E0B437D040067D50B /* Ap4String.cpp */, CA9366810B437D040067D50B /* Ap4StscAtom.h */, - CA9366820B437D040067D50B /* Ap4StsdAtom.cpp */, + CA9366800B437D040067D50B /* Ap4StscAtom.cpp */, CA9366830B437D040067D50B /* Ap4StsdAtom.h */, - CA9366840B437D040067D50B /* Ap4StssAtom.cpp */, + CA9366820B437D040067D50B /* Ap4StsdAtom.cpp */, CA9366850B437D040067D50B /* Ap4StssAtom.h */, - CA9366860B437D040067D50B /* Ap4StszAtom.cpp */, + CA9366840B437D040067D50B /* Ap4StssAtom.cpp */, CA9366870B437D040067D50B /* Ap4StszAtom.h */, - CA9366880B437D040067D50B /* Ap4SttsAtom.cpp */, + CA9366860B437D040067D50B /* Ap4StszAtom.cpp */, CA9366890B437D040067D50B /* Ap4SttsAtom.h */, - CA39215C13AC0B36006718F0 /* Ap4Stz2Atom.cpp */, + CA9366880B437D040067D50B /* Ap4SttsAtom.cpp */, CA39215D13AC0B36006718F0 /* Ap4Stz2Atom.h */, - CA93668A0B437D040067D50B /* Ap4SyntheticSampleTable.cpp */, + CA39215C13AC0B36006718F0 /* Ap4Stz2Atom.cpp */, CA93668B0B437D040067D50B /* Ap4SyntheticSampleTable.h */, - CA57340913B3B9C000953446 /* Ap4TencAtom.cpp */, + CA93668A0B437D040067D50B /* Ap4SyntheticSampleTable.cpp */, CA57340A13B3B9C000953446 /* Ap4TencAtom.h */, - CA5733B513B27B7500953446 /* Ap4TfdtAtom.cpp */, + CA57340913B3B9C000953446 /* Ap4TencAtom.cpp */, CA5733B613B27B7500953446 /* Ap4TfdtAtom.h */, - CA8B6A7E0F66D82C00720A07 /* Ap4TfhdAtom.cpp */, + CA5733B513B27B7500953446 /* Ap4TfdtAtom.cpp */, CA8B6A7F0F66D82C00720A07 /* Ap4TfhdAtom.h */, - CA91A81010A24D38008618FE /* Ap4TfraAtom.cpp */, + CA8B6A7E0F66D82C00720A07 /* Ap4TfhdAtom.cpp */, CA91A81110A24D38008618FE /* Ap4TfraAtom.h */, - CA93668C0B437D040067D50B /* Ap4TimsAtom.cpp */, + CA91A81010A24D38008618FE /* Ap4TfraAtom.cpp */, CA93668D0B437D040067D50B /* Ap4TimsAtom.h */, - CA93668E0B437D040067D50B /* Ap4TkhdAtom.cpp */, + CA93668C0B437D040067D50B /* Ap4TimsAtom.cpp */, CA93668F0B437D040067D50B /* Ap4TkhdAtom.h */, - CA9366900B437D040067D50B /* Ap4Track.cpp */, + CA93668E0B437D040067D50B /* Ap4TkhdAtom.cpp */, CA9366910B437D040067D50B /* Ap4Track.h */, - CA9366920B437D040067D50B /* Ap4TrakAtom.cpp */, + CA9366900B437D040067D50B /* Ap4Track.cpp */, CA9366930B437D040067D50B /* Ap4TrakAtom.h */, - CA9366940B437D040067D50B /* Ap4TrefTypeAtom.cpp */, + CA9366920B437D040067D50B /* Ap4TrakAtom.cpp */, CA9366950B437D040067D50B /* Ap4TrefTypeAtom.h */, - CAEFE1320FB69CF600AF6434 /* Ap4TrexAtom.cpp */, + CA9366940B437D040067D50B /* Ap4TrefTypeAtom.cpp */, CAEFE1330FB69CF600AF6434 /* Ap4TrexAtom.h */, - CA8B6A9F0F66E2DC00720A07 /* Ap4TrunAtom.cpp */, + CAEFE1320FB69CF600AF6434 /* Ap4TrexAtom.cpp */, CA8B6AA00F66E2DC00720A07 /* Ap4TrunAtom.h */, + CA8B6A9F0F66E2DC00720A07 /* Ap4TrunAtom.cpp */, CA9366960B437D040067D50B /* Ap4Types.h */, - CA9366990B437D040067D50B /* Ap4UrlAtom.cpp */, CA93669A0B437D040067D50B /* Ap4UrlAtom.h */, - CA93669B0B437D040067D50B /* Ap4Utils.cpp */, + CA9366990B437D040067D50B /* Ap4UrlAtom.cpp */, CA93669C0B437D040067D50B /* Ap4Utils.h */, - CA2898180D87DA81006A758B /* Ap4UuidAtom.cpp */, + CA93669B0B437D040067D50B /* Ap4Utils.cpp */, CA2898190D87DA81006A758B /* Ap4UuidAtom.h */, + CA2898180D87DA81006A758B /* Ap4UuidAtom.cpp */, CA93669D0B437D040067D50B /* Ap4Version.h */, - CA93669E0B437D040067D50B /* Ap4VmhdAtom.cpp */, CA93669F0B437D040067D50B /* Ap4VmhdAtom.h */, - ACB4314723BF9B8F003C0A81 /* Ap4VpccAtom.cpp */, + CA93669E0B437D040067D50B /* Ap4VmhdAtom.cpp */, ACB4314623BF9B8F003C0A81 /* Ap4VpccAtom.h */, - CA9CB9BC0F86ABB400063C70 /* Ap48bdlAtom.cpp */, + ACB4314723BF9B8F003C0A81 /* Ap4VpccAtom.cpp */, CA9CB9BD0F86ABB400063C70 /* Ap48bdlAtom.h */, + CA9CB9BC0F86ABB400063C70 /* Ap48bdlAtom.cpp */, ); name = Core; path = "../../../Source/C++/Core"; @@ -2570,6 +2584,7 @@ CA9366D00B437D040067D50B /* Ap4HintTrackReader.h in Headers */, CA9366D20B437D040067D50B /* Ap4HmhdAtom.h in Headers */, CA9366D40B437D040067D50B /* Ap4IkmsAtom.h in Headers */, + CAFB87FE2ED5FDFB003070A9 /* Ap4DmlpAtom.h in Headers */, CA9366D50B437D040067D50B /* Ap4Interfaces.h in Headers */, CA9366D70B437D040067D50B /* Ap4IproAtom.h in Headers */, CA9366D90B437D040067D50B /* Ap4IsfmAtom.h in Headers */, @@ -2637,6 +2652,7 @@ CA2898B20D897F20006A758B /* Ap4IodsAtom.h in Headers */, CA09F2800DF62FC600C2B2DA /* Ap4Marlin.h in Headers */, CAA0332E0DF7D3390086EC1C /* Ap4CommandFactory.h in Headers */, + CAD96AE22FE93E4F0061C8C7 /* Ap4ColrAtom.h in Headers */, CAA55DAC20F1306400CBAA11 /* Ap4Dac4Atom.h in Headers */, CAA033320DF7D4CC0086EC1C /* Ap4Command.h in Headers */, CAA033690DF7E2FA0086EC1C /* Ap4Ipmp.h in Headers */, @@ -3842,11 +3858,13 @@ CA9367020B437D040067D50B /* Ap4SampleTable.cpp in Sources */, CAEE5E7A1CC69FED0094DF0D /* Ap4DvccAtom.cpp in Sources */, AC28E6BA2389DE05005D9BE9 /* Ap4Dac3Atom.cpp in Sources */, + CAD96AE12FE93E4F0061C8C7 /* Ap4ColrAtom.cpp in Sources */, CA9367040B437D040067D50B /* Ap4SchmAtom.cpp in Sources */, CA9367060B437D040067D50B /* Ap4SdpAtom.cpp in Sources */, CA9367080B437D040067D50B /* Ap4SLConfigDescriptor.cpp in Sources */, CA93670A0B437D040067D50B /* Ap4SmhdAtom.cpp in Sources */, CAF9811018DBE48F0001B999 /* Ap4HevcParser.cpp in Sources */, + CAFB87FF2ED5FDFB003070A9 /* Ap4DmlpAtom.cpp in Sources */, CA93670C0B437D040067D50B /* Ap4StcoAtom.cpp in Sources */, CA93670E0B437D040067D50B /* Ap4String.cpp in Sources */, CA9367100B437D040067D50B /* Ap4StscAtom.cpp in Sources */, diff --git a/Build/Targets/x86-microsoft-win32-vs2010/Bento4/Bento4.vcxproj b/Build/Targets/x86-microsoft-win32-vs2010/Bento4/Bento4.vcxproj index 6421ac524..34ea3d121 100644 --- a/Build/Targets/x86-microsoft-win32-vs2010/Bento4/Bento4.vcxproj +++ b/Build/Targets/x86-microsoft-win32-vs2010/Bento4/Bento4.vcxproj @@ -119,6 +119,7 @@ + diff --git a/Build/Targets/x86-microsoft-win32-vs2010/Bento4/Bento4.vcxproj.filters b/Build/Targets/x86-microsoft-win32-vs2010/Bento4/Bento4.vcxproj.filters index 0cccf49f4..0b3177727 100644 --- a/Build/Targets/x86-microsoft-win32-vs2010/Bento4/Bento4.vcxproj.filters +++ b/Build/Targets/x86-microsoft-win32-vs2010/Bento4/Bento4.vcxproj.filters @@ -45,6 +45,9 @@ Source Files + + Source Files + Source Files diff --git a/Build/Targets/x86_64-microsoft-win32-vs2015/Bento4/Bento4.vcxproj b/Build/Targets/x86_64-microsoft-win32-vs2015/Bento4/Bento4.vcxproj index 70c2bce46..36456fcb8 100644 --- a/Build/Targets/x86_64-microsoft-win32-vs2015/Bento4/Bento4.vcxproj +++ b/Build/Targets/x86_64-microsoft-win32-vs2015/Bento4/Bento4.vcxproj @@ -185,6 +185,7 @@ + diff --git a/Build/Targets/x86_64-microsoft-win32-vs2015/Bento4/Bento4.vcxproj.filters b/Build/Targets/x86_64-microsoft-win32-vs2015/Bento4/Bento4.vcxproj.filters index 0cccf49f4..0b3177727 100644 --- a/Build/Targets/x86_64-microsoft-win32-vs2015/Bento4/Bento4.vcxproj.filters +++ b/Build/Targets/x86_64-microsoft-win32-vs2015/Bento4/Bento4.vcxproj.filters @@ -45,6 +45,9 @@ Source Files + + Source Files + Source Files diff --git a/Build/Targets/x86_64-microsoft-win32-vs2019/Bento4/Bento4.vcxproj b/Build/Targets/x86_64-microsoft-win32-vs2019/Bento4/Bento4.vcxproj index 767c63f60..af99ae0e2 100644 --- a/Build/Targets/x86_64-microsoft-win32-vs2019/Bento4/Bento4.vcxproj +++ b/Build/Targets/x86_64-microsoft-win32-vs2019/Bento4/Bento4.vcxproj @@ -168,6 +168,7 @@ + @@ -190,6 +191,7 @@ + @@ -303,6 +305,7 @@ + diff --git a/Build/Targets/x86_64-microsoft-win32-vs2019/Bento4/Bento4.vcxproj.filters b/Build/Targets/x86_64-microsoft-win32-vs2019/Bento4/Bento4.vcxproj.filters index e99223913..6e55c1c02 100644 --- a/Build/Targets/x86_64-microsoft-win32-vs2019/Bento4/Bento4.vcxproj.filters +++ b/Build/Targets/x86_64-microsoft-win32-vs2019/Bento4/Bento4.vcxproj.filters @@ -45,6 +45,9 @@ Source Files + + Source Files + Source Files @@ -411,6 +414,9 @@ Source Files + + Source Files + @@ -833,5 +839,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/Build/pkgconfig/bento4.pc.in b/Build/pkgconfig/bento4.pc.in new file mode 100644 index 000000000..ffccf21b4 --- /dev/null +++ b/Build/pkgconfig/bento4.pc.in @@ -0,0 +1,9 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ +libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ + +Name: @PROJECT_NAME@ +Description: Full-featured MP4 format, MPEG DASH, HLS, CMAF SDK and tools +Version: @BENTO4_VERSION@ +Libs: -L${libdir} -lap4 +Cflags: -I${includedir}/bento4 diff --git a/CMakeLists.txt b/CMakeLists.txt index 45b91259d..7e334c066 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,9 @@ function(get_bento4_version) endfunction() get_bento4_version() -set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "") +if(APPLE) + set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "") +endif() project(bento4 VERSION "${BENTO4_VERSION}") # Variables @@ -34,7 +36,9 @@ if (EMSCRIPTEN) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-warn-absolute-paths") endif() -set(CMAKE_OSX_DEPLOYMENT_TARGET 10.12) +if(APPLE) + set(CMAKE_OSX_DEPLOYMENT_TARGET 10.12) +endif() if(MSVC) add_definitions(-D_CRT_SECURE_NO_WARNINGS) @@ -71,13 +75,18 @@ file(GLOB AP4_HEADERS ${SOURCE_METADATA}/*.h ) -add_library(ap4 STATIC ${AP4_SOURCES}) +option(BUILD_SHARED_LIBRARY "Build as a shared library" OFF) +if(BUILD_SHARED_LIBRARY) + add_library(ap4 SHARED ${AP4_SOURCES}) +else() + add_library(ap4 STATIC ${AP4_SOURCES}) +endif() target_include_directories(ap4 PUBLIC ${AP4_INCLUDE_DIRS} ) -# Use the statically linked C runtime library -if(MSVC) +option(MSVC_FORCE_STATIC_C_RUNTIME "Use the statically linked C runtime library when compiling with MSVC" ON) +if(MSVC AND MSVC_FORCE_STATIC_C_RUNTIME) set_property(TARGET ap4 PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") target_compile_definitions(ap4 PRIVATE -D_LIB) endif() @@ -92,7 +101,7 @@ foreach(app ${BENTO4_APPS}) add_executable(${binary_name} ${SOURCE_ROOT}/Apps/${app}/${app}.cpp) target_link_libraries(${binary_name} ap4) - if(MSVC) + if(MSVC AND MSVC_FORCE_STATIC_C_RUNTIME) set_property(TARGET ${binary_name} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") target_compile_definitions(${binary_name} PRIVATE -D_CONSOLE) endif() @@ -119,6 +128,12 @@ configure_package_config_file( INSTALL_DESTINATION "${config_install_dir}" ) +configure_file( + "Build/pkgconfig/bento4.pc.in" + "${generated_dir}/bento4.pc" + @ONLY +) + install( TARGETS ap4 ${BENTO4_APPS_LOWERCASE} EXPORT "${TARGETS_EXPORT_NAME}" @@ -138,6 +153,11 @@ install( DESTINATION "${config_install_dir}" ) +install( + FILES "${generated_dir}/bento4.pc" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig" +) + install( EXPORT "${TARGETS_EXPORT_NAME}" NAMESPACE "${namespace}" diff --git a/Source/C++/Apps/Mp42Ts/Mp42Ts.cpp b/Source/C++/Apps/Mp42Ts/Mp42Ts.cpp index 5e1b42b21..330d47230 100644 --- a/Source/C++/Apps/Mp42Ts/Mp42Ts.cpp +++ b/Source/C++/Apps/Mp42Ts/Mp42Ts.cpp @@ -301,10 +301,10 @@ WriteSamples(AP4_Mpeg2TsWriter& writer, audio_track->GetSampleDescription(audio_sample.GetDescriptionIndex()), video_track==NULL, *output); - if (AP4_FAILED(result)) return result; + if (AP4_FAILED(result)) goto end; result = ReadSample(*audio_reader, *audio_track, audio_sample, audio_sample_data, audio_ts, audio_eos); - if (AP4_FAILED(result)) return result; + if (AP4_FAILED(result)) goto end; ++audio_sample_count; } else if (chosen_track == video_track) { result = video_stream->WriteSample(video_sample, @@ -312,10 +312,10 @@ WriteSamples(AP4_Mpeg2TsWriter& writer, video_track->GetSampleDescription(video_sample.GetDescriptionIndex()), true, *output); - if (AP4_FAILED(result)) return result; + if (AP4_FAILED(result)) goto end; result = ReadSample(*video_reader, *video_track, video_sample, video_sample_data, video_ts, video_eos); - if (AP4_FAILED(result)) return result; + if (AP4_FAILED(result)) goto end; ++video_sample_count; } else { break; @@ -347,7 +347,7 @@ WriteSamples(AP4_Mpeg2TsWriter& writer, // create the playlist file if needed if (Options.playlist) { playlist = OpenOutput(Options.playlist, 0); - if (playlist == NULL) return AP4_ERROR_CANNOT_OPEN_FILE; + if (playlist == NULL) goto end; unsigned int target_duration = 0; for (unsigned int i=0; iGetMovie(); if (movie == NULL) { fprintf(stderr, "ERROR: no movie in file\n"); - delete input; delete input_file; + input->Release(); return 1; } @@ -581,7 +581,7 @@ main(int argc, char** argv) stream_id = AP4_MPEG2_TS_STREAM_ID_PRIVATE_STREAM_1; } else { fprintf(stderr, "ERROR: audio codec not supported\n"); - return 1; + goto end; } result = writer.SetAudioStream(audio_track->GetMediaTimeScale(), @@ -622,7 +622,7 @@ main(int argc, char** argv) stream_type = AP4_MPEG2_STREAM_TYPE_HEVC; } else { fprintf(stderr, "ERROR: video codec not supported\n"); - return 1; + goto end; } result = writer.SetVideoStream(video_track->GetMediaTimeScale(), stream_type, diff --git a/Source/C++/Apps/Mp4Fragment/Mp4Fragment.cpp b/Source/C++/Apps/Mp4Fragment/Mp4Fragment.cpp index 8f67ddef4..dced5e7af 100644 --- a/Source/C++/Apps/Mp4Fragment/Mp4Fragment.cpp +++ b/Source/C++/Apps/Mp4Fragment/Mp4Fragment.cpp @@ -623,7 +623,7 @@ Fragment(AP4_File& input_file, AP4_UI32 sync_sample_flags = 0; AP4_UI32 non_sync_sample_flags = 0x10000; // 0x10000 -> sample_is_non_sync if (cursor->m_Track->GetType() == AP4_Track::TYPE_VIDEO || - (cursor->m_Track->GetSampleDescriptionCount() > 0 && + (cursor->m_Track->GetSampleDescriptionCount() > 0 && cursor->m_Track->GetSampleDescription(0) && cursor->m_Track->GetSampleDescription(0)->GetFormat() == AP4_SAMPLE_FORMAT_AC_4)) { non_sync_sample_flags |= 0x1000000; // sample_depends_on=1 (not I frame) sync_sample_flags |= 0x2000000; // sample_depends_on=2 (I frame) diff --git a/Source/C++/Apps/Mp4Info/Mp4Info.cpp b/Source/C++/Apps/Mp4Info/Mp4Info.cpp index 205cd0bce..9fe5c6c95 100644 --- a/Source/C++/Apps/Mp4Info/Mp4Info.cpp +++ b/Source/C++/Apps/Mp4Info/Mp4Info.cpp @@ -653,6 +653,16 @@ ShowSampleDescription_Text(AP4_SampleDescription& description, bool verbose) break; } + case AP4_SAMPLE_FORMAT_MLPA: { + // Dolby TrueHD specifics + AP4_DmlpAtom* dmlp = AP4_DYNAMIC_CAST(AP4_DmlpAtom, desc->GetDetails().GetChild(AP4_ATOM_TYPE_DMLP)); + if (dmlp) { + printf(" Format Info: %d\n", dmlp->m_FormatInfo); + printf(" Peak Data Rate: %d\n", dmlp->m_PeakDataRate); + } + break; + } + // VPx Specifics case AP4_SAMPLE_FORMAT_VP8: case AP4_SAMPLE_FORMAT_VP9: @@ -1081,6 +1091,22 @@ ShowSampleDescription_Json(AP4_SampleDescription& description, bool verbose) printf("}"); } + // Color information from colr atom for non-VPx tracks + if (desc->GetFormat() != AP4_SAMPLE_FORMAT_VP8 && + desc->GetFormat() != AP4_SAMPLE_FORMAT_VP9 && + desc->GetFormat() != AP4_SAMPLE_FORMAT_VP10) { + AP4_ColrAtom* colr = AP4_DYNAMIC_CAST(AP4_ColrAtom, desc->GetDetails().GetChild(AP4_ATOM_TYPE_COLR)); + if (colr && colr->GetColourParameterType() == AP4_SAMPLE_COLOR_TYPE_NCLX) { + printf(",\n"); + printf("\"color_info\": {\n"); + printf(" \"colour_primaries\":%d,\n", colr->GetPrimariesIndex()); + printf(" \"transfer_characteristics\":%d,\n", colr->GetTransferFunctionIndex()); + printf(" \"matrix_coefficients\":%d,\n", colr->GetMatrixIndex()); + printf(" \"video_full_range_flag\":%s\n", colr->GetFullRangeFlag() ? "true" : "false"); + printf("}"); + } + } + printf("\n}"); } diff --git a/Source/C++/Apps/Mp4Mux/Mp4Mux.cpp b/Source/C++/Apps/Mp4Mux/Mp4Mux.cpp index 8412e7110..a83c22d89 100644 --- a/Source/C++/Apps/Mp4Mux/Mp4Mux.cpp +++ b/Source/C++/Apps/Mp4Mux/Mp4Mux.cpp @@ -667,7 +667,7 @@ AddAc3Track(AP4_Movie& movie, if (!movie.GetTimeScale()) { duration = sample_count * 1536; } else { - duration = AP4_ConvertTime(1000*sample_table->GetSampleCount(), sample_rate, movie.GetTimeScale()); + duration = AP4_ConvertTime(1536*sample_table->GetSampleCount(), sample_rate, movie.GetTimeScale()); } AP4_ElstEntry new_elst_entry = AP4_ElstEntry(duration, 0, 1); new_elst->AddEntry(new_elst_entry); @@ -814,7 +814,7 @@ AddEac3Track(AP4_Movie& movie, if (!movie.GetTimeScale()) { duration = sample_count * 1536; } else { - duration = AP4_ConvertTime(1000*sample_table->GetSampleCount(), sample_rate, movie.GetTimeScale()); + duration = AP4_ConvertTime(1536*sample_table->GetSampleCount(), sample_rate, movie.GetTimeScale()); } AP4_ElstEntry new_elst_entry = AP4_ElstEntry(duration, 0, 1); new_elst->AddEntry(new_elst_entry); @@ -962,7 +962,7 @@ AddAc4Track(AP4_Movie& movie, if (!movie.GetTimeScale()) { duration = AP4_UI64(sample_count) * sample_duration; } else { - duration = AP4_ConvertTime(1000*sample_table->GetSampleCount(), media_time_scale, movie.GetTimeScale()); + duration = AP4_ConvertTime(AP4_UI64(sample_duration)*sample_table->GetSampleCount(), media_time_scale, movie.GetTimeScale()); } AP4_ElstEntry new_elst_entry = AP4_ElstEntry(duration, 0, 1); new_elst->AddEntry(new_elst_entry); diff --git a/Source/C++/Codecs/Ap4Ac3Parser.cpp b/Source/C++/Codecs/Ap4Ac3Parser.cpp index 93f33ab62..acf4e4d38 100644 --- a/Source/C++/Codecs/Ap4Ac3Parser.cpp +++ b/Source/C++/Codecs/Ap4Ac3Parser.cpp @@ -43,6 +43,13 @@ AP4_Ac3Header::AP4_Ac3Header(const AP4_UI08* bytes) bits.SkipBits(16); // crc1 m_Fscod = bits.ReadBits(2); m_Frmsizecod = bits.ReadBits(6); // frmsizecod + if (m_Fscod >= sizeof(FRAME_SIZE_CODE_ARY_AC3)/sizeof(FRAME_SIZE_CODE_ARY_AC3[0]) || + m_Frmsizecod >= sizeof(FRAME_SIZE_CODE_ARY_AC3[0])/sizeof(FRAME_SIZE_CODE_ARY_AC3[0][0])) { + m_FrameSize = 0; + // invalid frame size code, set bsid to an invalid value to make sure the header check will fail + m_Bsid = 0xFF; + return; + } m_FrameSize = FRAME_SIZE_CODE_ARY_AC3[m_Fscod][m_Frmsizecod] * 2; m_Bsid = bits.ReadBits(5); @@ -58,6 +65,11 @@ AP4_Ac3Header::AP4_Ac3Header(const AP4_UI08* bytes) bits.SkipBits(2); //dsurmod } m_Lfeon = bits.ReadBit(); + if (m_Acmod >= sizeof(GLOBAL_CHANNEL_ARY)/sizeof(GLOBAL_CHANNEL_ARY[0])) { + // invalid acmod, set bsid to an invalid value to make sure the header check will fail + m_Bsid = 0xFF; + return; + } m_ChannelCount = GLOBAL_CHANNEL_ARY[m_Acmod] + m_Lfeon; bits.SkipBits(5); // dialnorm if(bits.ReadBit()){ // compre diff --git a/Source/C++/Codecs/Ap4Ac4Parser.cpp b/Source/C++/Codecs/Ap4Ac4Parser.cpp index 0a57299d9..cc2199e95 100644 --- a/Source/C++/Codecs/Ap4Ac4Parser.cpp +++ b/Source/C++/Codecs/Ap4Ac4Parser.cpp @@ -36,26 +36,31 @@ bool AP4_Ac4Header::m_DeprecatedV0 = true; /*----------------------------------------------------------------------+ | AP4_Ac4Header::AP4_Ac4Header +----------------------------------------------------------------------*/ -AP4_Ac4Header::AP4_Ac4Header(const AP4_UI08* bytes, unsigned int size) +AP4_Ac4Header::AP4_Ac4Header(const AP4_UI08* bytes, unsigned int size, bool header_exists) { /* Read the entire the frame */ AP4_BitReader bits(bytes, size); - m_SyncWord = bits.ReadBits(16); - m_HeaderSize = 2; - if (m_SyncWord == AP4_AC4_SYNC_WORD_CRC){ - m_CrcSize = 2; - }else { - m_CrcSize = 0; - } - m_FrameSize = bits.ReadBits(16); - m_HeaderSize += 2; - if (m_FrameSize == 0xFFFF){ - m_FrameSize = bits.ReadBits(24); - m_HeaderSize += 3; + /* Sync word and frame_size()*/ + if (header_exists) { + m_SyncWord = bits.ReadBits(16); + m_HeaderSize = 2; + if (m_SyncWord == AP4_AC4_SYNC_WORD_CRC){ + m_CrcSize = 2; + }else { + m_CrcSize = 0; + } + m_FrameSize = bits.ReadBits(16); + m_HeaderSize += 2; + if (m_FrameSize == 0xFFFF){ + m_FrameSize = bits.ReadBits(24); + m_HeaderSize += 3; + } } /* Begin to parse TOC */ + unsigned int tocStart = bits.GetBitsPosition() / 8; + m_BitstreamVersion = bits.ReadBits(2); if (m_BitstreamVersion == 3) { m_BitstreamVersion = AP4_Ac4VariableBits(bits, 2); @@ -168,32 +173,41 @@ AP4_Ac4Header::AP4_Ac4Header(const AP4_UI08* bytes, unsigned int size) m_PresentationV1[pres_idx].d.v1.dolby_atmos_indicator |= m_PresentationV1[pres_idx].d.v1.substream_groups[sg].d.v1.dolby_atmos_indicator; } } - delete [] substream_groups; + delete[] substream_groups; if (bObjorAjoc == 0){ m_ChannelCount = AP4_Ac4ChannelCountFromSpeakerGroupIndexMask(speakerGroupIndexMask); }else { - m_ChannelCount = channelCount; + m_ChannelCount = 2; } } -} -AP4_Ac4Header::~AP4_Ac4Header() -{ - if (m_PresentationV1) { - assert(m_PresentationV1 != NULL); - for (unsigned int pres_idx = 0; pres_idx < m_NPresentations; pres_idx++) { - assert(m_PresentationV1[pres_idx].d.v1.substream_groups != NULL); - for (int j = 0; j < m_PresentationV1[pres_idx].d.v1.n_substream_groups; j++) - delete[] m_PresentationV1[pres_idx].d.v1.substream_groups[j].d.v1.substreams; - delete[] m_PresentationV1[pres_idx].d.v1.substream_groups; - delete[] m_PresentationV1[pres_idx].d.v1.substream_group_indexs; + // substream_index_table + AP4_UI32 n_substreams = bits.ReadBits(2); + if (n_substreams == 0) { + n_substreams = AP4_Ac4VariableBits(bits, 2) + 4; + } + AP4_UI08 b_size_present; + if (n_substreams == 1) { + b_size_present = bits.ReadBit(); + } else { + b_size_present = 1; + } + if (b_size_present) { + for (AP4_UI32 s = 0; s < n_substreams; s++) { + AP4_UI08 b_more_bits = bits.ReadBit(); + AP4_UI32 substream_size = bits.ReadBits(10); + if (b_more_bits) { + substream_size += (AP4_Ac4VariableBits(bits, 2) << 10); + } } - delete[] m_PresentationV1; } + if (bits.GetBitsPosition() % 8) { + bits.SkipBits(8 - (bits.GetBitsPosition() % 8)); + } + m_TocSize = (AP4_UI32)(bits.GetBitsPosition() / 8 - tocStart); } - /*----------------------------------------------------------------------+ | AP4_Ac4Header::MatchFixed | @@ -368,7 +382,7 @@ AP4_Result AP4_Ac4Parser::FindFrame(AP4_Ac4Frame& frame) { unsigned int available; - unsigned char raw_header[AP4_AC4_HEADER_SIZE]; + unsigned char *raw_header = new unsigned char[AP4_AC4_HEADER_SIZE]; AP4_Result result; /* align to the start of the next byte */ @@ -385,6 +399,8 @@ AP4_Ac4Parser::FindFrame(AP4_Ac4Frame& frame) return AP4_ERROR_NOT_ENOUGH_DATA; } + delete[] raw_header; + raw_header = new unsigned char[sync_frame_size]; /* * Error handling to skip the 'fake' sync word. * - the maximum sync frame size is about (AP4_BITSTREAM_BUFFER_SIZE - 1) bytes. @@ -396,15 +412,10 @@ AP4_Ac4Parser::FindFrame(AP4_Ac4Frame& frame) } return AP4_ERROR_NOT_ENOUGH_DATA; } - - unsigned char *rawframe = new unsigned char[sync_frame_size]; - // copy the whole frame becasue toc size is unknown - m_Bits.PeekBytes(rawframe, sync_frame_size); + m_Bits.PeekBytes(raw_header, sync_frame_size); /* parse the header */ - AP4_Ac4Header ac4_header(rawframe, sync_frame_size); - - delete[] rawframe; + AP4_Ac4Header ac4_header(raw_header, sync_frame_size); // Place before goto statement to resolve Xcode compiler issue unsigned int bit_rate_mode = 0; @@ -421,33 +432,31 @@ AP4_Ac4Parser::FindFrame(AP4_Ac4Frame& frame) // TODO: find the proper AP4_AC4_MAX_TOC_SIZE or just parse what this step need ? if (available >= ac4_header.m_FrameSize + ac4_header.m_HeaderSize + ac4_header.m_CrcSize + AP4_AC4_HEADER_SIZE + AP4_AC4_MAX_TOC_SIZE) { // enough to peek at the header of the next frame + unsigned char *peek_raw_header = new unsigned char[AP4_AC4_HEADER_SIZE]; m_Bits.SkipBytes(ac4_header.m_FrameSize + ac4_header.m_HeaderSize + ac4_header.m_CrcSize); - m_Bits.PeekBytes(raw_header, AP4_AC4_HEADER_SIZE); + m_Bits.PeekBytes(peek_raw_header, AP4_AC4_HEADER_SIZE); // duplicated work, just to get the frame size - AP4_BitReader peak_tmp_bits(raw_header, AP4_AC4_HEADER_SIZE); - unsigned int next_sync_frame_size = GetSyncFrameSize(peak_tmp_bits); - - unsigned char *next_rawframe = new unsigned char[next_sync_frame_size]; + AP4_BitReader peak_tmp_bits(peek_raw_header, AP4_AC4_HEADER_SIZE); + unsigned int peak_sync_frame_size = GetSyncFrameSize(peak_tmp_bits); + delete[] peek_raw_header; + peek_raw_header = new unsigned char[peak_sync_frame_size]; // copy the whole frame becasue toc size is unknown - if (m_Bits.GetBytesAvailable() < (next_sync_frame_size)) { - next_sync_frame_size = m_Bits.GetBytesAvailable(); + if (m_Bits.GetBytesAvailable() < (peak_sync_frame_size)) { + peak_sync_frame_size = m_Bits.GetBytesAvailable(); } - m_Bits.PeekBytes(next_rawframe, next_sync_frame_size); + m_Bits.PeekBytes(peek_raw_header, peak_sync_frame_size); m_Bits.SkipBytes(-((int)(ac4_header.m_FrameSize + ac4_header.m_HeaderSize + ac4_header.m_CrcSize))); /* check the header */ - AP4_Ac4Header peek_ac4_header(next_rawframe, next_sync_frame_size); - - delete[] next_rawframe; - + AP4_Ac4Header peek_ac4_header(peek_raw_header, peak_sync_frame_size, true); result = peek_ac4_header.Check(); if (AP4_FAILED(result)) { // TODO: need to reserve current sync frame ? - m_Bits.SkipBytes(sync_frame_size + next_sync_frame_size); + m_Bits.SkipBytes(sync_frame_size + peak_sync_frame_size); goto fail; } @@ -455,7 +464,7 @@ AP4_Ac4Parser::FindFrame(AP4_Ac4Frame& frame) /* fixed part of the previous header */ if (!AP4_Ac4Header::MatchFixed(ac4_header, peek_ac4_header)) { // TODO: need to reserve current sync frame ? - m_Bits.SkipBytes(sync_frame_size + next_sync_frame_size); + m_Bits.SkipBytes(sync_frame_size + peak_sync_frame_size); goto fail; } } else if (available < (ac4_header.m_FrameSize + ac4_header.m_HeaderSize + ac4_header.m_CrcSize) || (m_Bits.m_Flags & AP4_BITSTREAM_FLAG_EOS) == 0) { @@ -494,7 +503,35 @@ AP4_Ac4Parser::FindFrame(AP4_Ac4Frame& frame) frame.m_Info.m_Ac4Dsi.d.v1.ac4_bitrate_dsi.bit_rate = 0; // unknown, fixed value now frame.m_Info.m_Ac4Dsi.d.v1.ac4_bitrate_dsi.bit_rate_precision = 0xffffffff; // unknown, fixed value now frame.m_Info.m_Ac4Dsi.d.v1.n_presentations = ac4_header.m_NPresentations; - frame.m_Info.m_Ac4Dsi.d.v1.presentations = ac4_header.m_PresentationV1; + + if (ac4_header.m_PresentationV1) { + assert(ac4_header.m_PresentationV1 != NULL); + frame.m_Info.m_Ac4Dsi.d.v1.presentations = new AP4_Dac4Atom::Ac4Dsi::PresentationV1[ac4_header.m_NPresentations]; + AP4_CopyMemory(frame.m_Info.m_Ac4Dsi.d.v1.presentations, + ac4_header.m_PresentationV1, + sizeof(AP4_Dac4Atom::Ac4Dsi::PresentationV1) * ac4_header.m_NPresentations); + for (unsigned int pres_idx = 0; pres_idx < ac4_header.m_NPresentations; pres_idx++) { + assert(ac4_header.m_PresentationV1[pres_idx].d.v1.substream_groups != NULL); + unsigned int n_substream_group = ac4_header.m_PresentationV1[pres_idx].d.v1.n_substream_groups; + frame.m_Info.m_Ac4Dsi.d.v1.presentations[pres_idx].d.v1.substream_groups = new AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1[n_substream_group]; + frame.m_Info.m_Ac4Dsi.d.v1.presentations[pres_idx].d.v1.substream_group_indexs = new AP4_UI32[n_substream_group]; + AP4_CopyMemory(frame.m_Info.m_Ac4Dsi.d.v1.presentations[pres_idx].d.v1.substream_group_indexs, + ac4_header.m_PresentationV1[pres_idx].d.v1.substream_group_indexs, + sizeof(AP4_UI32)*n_substream_group); + AP4_CopyMemory(frame.m_Info.m_Ac4Dsi.d.v1.presentations[pres_idx].d.v1.substream_groups, + ac4_header.m_PresentationV1[pres_idx].d.v1.substream_groups, + sizeof(AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1)*n_substream_group); + for (unsigned int sg_idx = 0; sg_idx < n_substream_group; sg_idx++) { + assert(ac4_header.m_PresentationV1[pres_idx].d.v1.substream_groups[sg_idx].d.v1.substreams != NULL); + int n_substreams = ac4_header.m_PresentationV1[pres_idx].d.v1.substream_groups[sg_idx].d.v1.n_substreams; + frame.m_Info.m_Ac4Dsi.d.v1.presentations[pres_idx].d.v1.substream_groups[sg_idx].d.v1.substreams + = new AP4_Dac4Atom::Ac4Dsi::SubStream[n_substreams]; + AP4_CopyMemory(frame.m_Info.m_Ac4Dsi.d.v1.presentations[pres_idx].d.v1.substream_groups[sg_idx].d.v1.substreams, + ac4_header.m_PresentationV1[pres_idx].d.v1.substream_groups[sg_idx].d.v1.substreams, + sizeof(AP4_Dac4Atom::Ac4Dsi::SubStream) * n_substreams); + } + } + } /* set the frame source */ frame.m_Source = &m_Bits; diff --git a/Source/C++/Codecs/Ap4Ac4Parser.h b/Source/C++/Codecs/Ap4Ac4Parser.h index 955eee081..1e746b7b5 100644 --- a/Source/C++/Codecs/Ap4Ac4Parser.h +++ b/Source/C++/Codecs/Ap4Ac4Parser.h @@ -50,9 +50,7 @@ class AP4_Ac4Header { public: // constructor - AP4_Ac4Header(const AP4_UI08* bytes, unsigned int size); - // destructor - ~AP4_Ac4Header(); + AP4_Ac4Header(const AP4_UI08* bytes, unsigned int size, bool header_exists=true); // methods AP4_Result Check(); @@ -84,6 +82,7 @@ class AP4_Ac4Header { AP4_UI32 m_ShortProgramId; AP4_UI32 m_BProgramUuidPresent; AP4_Byte m_ProgramUuid[16]; + AP4_UI32 m_TocSize; static bool m_DeprecatedV0; diff --git a/Source/C++/Core/Ap4.h b/Source/C++/Core/Ap4.h index dce9d97d2..c3a92ab69 100644 --- a/Source/C++/Core/Ap4.h +++ b/Source/C++/Core/Ap4.h @@ -316,6 +316,7 @@ #include "Ap4Dec3Atom.h" #include "Ap4Dac4Atom.h" #include "Ap4SidxAtom.h" +#include "Ap4ColrAtom.h" #include "Ap4AdtsParser.h" #include "Ap4Ac4Parser.h" #include "Ap4AvcParser.h" diff --git a/Source/C++/Core/Ap4Atom.h b/Source/C++/Core/Ap4Atom.h index 73d3a4142..1c61b8237 100644 --- a/Source/C++/Core/Ap4Atom.h +++ b/Source/C++/Core/Ap4Atom.h @@ -108,12 +108,12 @@ class AP4_AtomInspector { virtual void StartObject(const char* /* name */, unsigned int field_count = 0, bool compact = false) {} virtual void EndObject() {} virtual void AddField(const char* /* name */, - AP4_UI64 /* value */, + AP4_UI64 /* value */, FormatHint hint = HINT_NONE) { (void)hint; // gcc warning } - virtual void AddFieldF(const char* /* name */, - float /* value */, + virtual void AddFieldF(const char* /* name */, + float /* value */, FormatHint hint = HINT_NONE) { (void)hint; // gcc warning } @@ -559,6 +559,7 @@ const AP4_Atom::Type AP4_ATOM_TYPE_8BDL = AP4_ATOM_TYPE('8','b','d','l'); const AP4_Atom::Type AP4_ATOM_TYPE_AC_3 = AP4_ATOM_TYPE('a','c','-','3'); const AP4_Atom::Type AP4_ATOM_TYPE_EC_3 = AP4_ATOM_TYPE('e','c','-','3'); const AP4_Atom::Type AP4_ATOM_TYPE_AC_4 = AP4_ATOM_TYPE('a','c','-','4'); +const AP4_Atom::Type AP4_ATOM_TYPE_MLPA = AP4_ATOM_TYPE('m','l','p','a'); const AP4_Atom::Type AP4_ATOM_TYPE_DTSC = AP4_ATOM_TYPE('d','t','s','c'); const AP4_Atom::Type AP4_ATOM_TYPE_DTSH = AP4_ATOM_TYPE('d','t','s','h'); const AP4_Atom::Type AP4_ATOM_TYPE_DTSL = AP4_ATOM_TYPE('d','t','s','l'); @@ -584,10 +585,12 @@ const AP4_Atom::Type AP4_ATOM_TYPE_STPP = AP4_ATOM_TYPE('s','t','p','p'); const AP4_Atom::Type AP4_ATOM_TYPE_DAC3 = AP4_ATOM_TYPE('d','a','c','3'); const AP4_Atom::Type AP4_ATOM_TYPE_DEC3 = AP4_ATOM_TYPE('d','e','c','3'); const AP4_Atom::Type AP4_ATOM_TYPE_DAC4 = AP4_ATOM_TYPE('d','a','c','4'); +const AP4_Atom::Type AP4_ATOM_TYPE_DMLP = AP4_ATOM_TYPE('d','m','l','p'); const AP4_Atom::Type AP4_ATOM_TYPE_SIDX = AP4_ATOM_TYPE('s','i','d','x'); const AP4_Atom::Type AP4_ATOM_TYPE_SSIX = AP4_ATOM_TYPE('s','s','i','x'); const AP4_Atom::Type AP4_ATOM_TYPE_SBGP = AP4_ATOM_TYPE('s','b','g','p'); const AP4_Atom::Type AP4_ATOM_TYPE_SGPD = AP4_ATOM_TYPE('s','g','p','d'); +const AP4_Atom::Type AP4_ATOM_TYPE_COLR = AP4_ATOM_TYPE('c','o','l','r'); /*---------------------------------------------------------------------- | AP4_AtomListInspector diff --git a/Source/C++/Core/Ap4AtomFactory.cpp b/Source/C++/Core/Ap4AtomFactory.cpp index d689a78bb..bc33ed4e8 100644 --- a/Source/C++/Core/Ap4AtomFactory.cpp +++ b/Source/C++/Core/Ap4AtomFactory.cpp @@ -108,6 +108,7 @@ #include "Ap4SidxAtom.h" #include "Ap4SbgpAtom.h" #include "Ap4SgpdAtom.h" +#include "Ap4ColrAtom.h" /*---------------------------------------------------------------------- | AP4_AtomFactory::~AP4_AtomFactory @@ -342,6 +343,10 @@ AP4_AtomFactory::CreateAtomFromStream(AP4_ByteStream& stream, atom = new AP4_Ac4SampleEntry(type, size_32, stream, *this); break; + case AP4_ATOM_TYPE_MLPA: + atom = new AP4_MlpSampleEntry(type, size_32, stream, *this); + break; + case AP4_ATOM_TYPE_ALAC: case AP4_ATOM_TYPE_DTSC: case AP4_ATOM_TYPE_DTSH: @@ -777,6 +782,13 @@ AP4_AtomFactory::CreateAtomFromStream(AP4_ByteStream& stream, } break; + case AP4_ATOM_TYPE_DMLP: + if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; + if (GetContext() == AP4_ATOM_TYPE_MLPA || GetContext() == AP4_ATOM_TYPE_ENCA) { + atom = AP4_DmlpAtom::Create(size_32, stream); + } + break; + // track ref types case AP4_ATOM_TYPE_HINT: case AP4_ATOM_TYPE_CDSC: @@ -835,6 +847,10 @@ AP4_AtomFactory::CreateAtomFromStream(AP4_ByteStream& stream, case AP4_ATOM_TYPE_MDAT: // generic atoms break; + case AP4_ATOM_TYPE_COLR: + if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; + atom = AP4_ColrAtom::Create(size_32, stream); + break; default: { // try all the external type handlers diff --git a/Source/C++/Core/Ap4ColrAtom.cpp b/Source/C++/Core/Ap4ColrAtom.cpp new file mode 100644 index 000000000..49dd8d252 --- /dev/null +++ b/Source/C++/Core/Ap4ColrAtom.cpp @@ -0,0 +1,156 @@ +/***************************************************************** +| +| AP4 - colr Atoms +| +| Copyright 2002-2016 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4ColrAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" +#include "Ap4Types.h" +#include "Ap4HevcParser.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_ColrAtom) + + +/*---------------------------------------------------------------------- +| AP4_ColrAtom::Create ++---------------------------------------------------------------------*/ +AP4_ColrAtom* +AP4_ColrAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + // read the raw bytes in a buffer + unsigned int payload_size = size-AP4_ATOM_HEADER_SIZE; + AP4_DataBuffer payload_data(payload_size); + AP4_Result result = stream.Read(payload_data.UseData(), payload_size); + if (AP4_FAILED(result)) return NULL; + + return new AP4_ColrAtom(size, payload_data.GetData()); +} + +/*---------------------------------------------------------------------- +| AP4_ColrAtom::AP4_ColrAtom ++---------------------------------------------------------------------*/ +AP4_ColrAtom::AP4_ColrAtom() : + AP4_Atom(AP4_ATOM_TYPE_COLR, AP4_ATOM_HEADER_SIZE + 11), + m_ColourParameterType(0), + m_PrimariesIndex(0), + m_TransferFunctionIndex(0), + m_MatrixIndex(0), + m_FullRangeFlag(0), + m_PayloadSize(11) +{ +} + +/*---------------------------------------------------------------------- +| AP4_ColrAtom::AP4_ColrAtom ++---------------------------------------------------------------------*/ +AP4_ColrAtom::AP4_ColrAtom(AP4_UI32 colour_parameter_type, + AP4_UI16 primaries_index, + AP4_UI16 transfer_function_index, + AP4_UI16 matrix_index, + AP4_UI08 video_full_range_flag, + AP4_UI32 payload_size) : + AP4_Atom(AP4_ATOM_TYPE_COLR, AP4_ATOM_HEADER_SIZE + payload_size), + m_ColourParameterType(colour_parameter_type), + m_PrimariesIndex(primaries_index), + m_TransferFunctionIndex(transfer_function_index), + m_MatrixIndex(matrix_index), + m_FullRangeFlag(video_full_range_flag), + m_PayloadSize(payload_size) +{ +} + +/*---------------------------------------------------------------------- +| AP4_ColrAtom::AP4_ColrAtom ++---------------------------------------------------------------------*/ +AP4_ColrAtom::AP4_ColrAtom(AP4_UI32 size, const AP4_UI08* payload) : + AP4_Atom(AP4_ATOM_TYPE_COLR, size) +{ + // make a copy of our configuration bytes + unsigned int payload_size = size-AP4_ATOM_HEADER_SIZE; + // payload size of QuickTime colr is 10, + // payload size of ISOBMFF colr is 11. + if (payload_size != 10 && payload_size != 11) return; + + // parse the payload + m_PayloadSize = payload_size; + m_ColourParameterType = AP4_BytesToUInt32BE(&payload[0]); + m_PrimariesIndex = AP4_BytesToUInt16BE(&payload[4]); + m_TransferFunctionIndex = AP4_BytesToUInt16BE(&payload[6]); + m_MatrixIndex = AP4_BytesToUInt16BE(&payload[8]); + if (payload_size == 11) { + m_FullRangeFlag = (payload[10] >> 7) & 0x01; + } +} + +/*---------------------------------------------------------------------- +| AP4_ColrAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_ColrAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_UI08 payload[11]; + AP4_SetMemory(&payload, 0, 11); + + payload[0] = m_ColourParameterType >> 24; + payload[1] = (m_ColourParameterType >> 16) & 0xFF; + payload[2] = (m_ColourParameterType >> 8) & 0xFF; + payload[3] = m_ColourParameterType & 0xFF; + payload[4] = m_PrimariesIndex >> 8; + payload[5] = m_PrimariesIndex & 0xFF; + payload[6] = m_TransferFunctionIndex >> 8; + payload[7] = m_TransferFunctionIndex & 0xFF; + payload[8] = m_MatrixIndex >> 8; + payload[9] = m_MatrixIndex & 0xFF; + payload[10] = (m_FullRangeFlag << 7) & 0x80; + + if (GetPayloadSize() == 10) { + return stream.Write(payload, 10); + } + return stream.Write(payload, 11); +} + +/*---------------------------------------------------------------------- +| AP4_ColrAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_ColrAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("Colour Parameter Type:", m_ColourParameterType); + inspector.AddField("Primaries Index:", m_PrimariesIndex); + inspector.AddField("Transfer Funcion Index:", m_TransferFunctionIndex); + inspector.AddField("Matrix Index:", m_MatrixIndex); + if (GetPayloadSize() == 11) { + inspector.AddField("Video Full Range Flag:", m_FullRangeFlag); + } + return AP4_SUCCESS; +} diff --git a/Source/C++/Core/Ap4ColrAtom.h b/Source/C++/Core/Ap4ColrAtom.h new file mode 100644 index 000000000..124a7b421 --- /dev/null +++ b/Source/C++/Core/Ap4ColrAtom.h @@ -0,0 +1,83 @@ +/***************************************************************** +| +| AP4 - Colr Atoms +| +| Copyright 2002-2014 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_COLR_ATOM_H_ +#define _AP4_COLR_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Atom.h" +#include "Ap4Array.h" + +/*---------------------------------------------------------------------- +| AP4_ColrAtom ++---------------------------------------------------------------------*/ +class AP4_ColrAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_ColrAtom, AP4_Atom) + + // class methods + static AP4_ColrAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // constructors + AP4_ColrAtom(); + AP4_ColrAtom(AP4_UI32 colour_parameter_type, + AP4_UI16 primaries_index, + AP4_UI16 transfer_function_index, + AP4_UI16 matrix_index, + AP4_UI08 video_full_range_flag, + AP4_UI32 payload_size = 11); // default payload size is 11, unless specified + AP4_ColrAtom(AP4_UI32 size, const AP4_UI08* payload); + + // methods + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + // accessors + AP4_UI32 GetColourParameterType() { return m_ColourParameterType; } + AP4_UI16 GetPrimariesIndex() { return m_PrimariesIndex; } + AP4_UI16 GetTransferFunctionIndex() { return m_TransferFunctionIndex; } + AP4_UI16 GetMatrixIndex() { return m_MatrixIndex; } + AP4_UI08 GetFullRangeFlag() { return m_FullRangeFlag; } + AP4_UI32 GetPayloadSize() { return m_PayloadSize; } + +private: + + // members + AP4_UI32 m_ColourParameterType; + AP4_UI16 m_PrimariesIndex; + AP4_UI16 m_TransferFunctionIndex; + AP4_UI16 m_MatrixIndex; + AP4_UI08 m_FullRangeFlag; + AP4_UI32 m_PayloadSize; + +}; + +#endif // _AP4_COLR_ATOM_H_ diff --git a/Source/C++/Core/Ap4CommonEncryption.cpp b/Source/C++/Core/Ap4CommonEncryption.cpp index fbc4d1ffc..393f89318 100644 --- a/Source/C++/Core/Ap4CommonEncryption.cpp +++ b/Source/C++/Core/Ap4CommonEncryption.cpp @@ -53,6 +53,7 @@ #include "Ap4PsshAtom.h" #include "Ap4AvcParser.h" #include "Ap4HevcParser.h" +#include "Ap4Ac4Parser.h" /*---------------------------------------------------------------------- | constants @@ -107,7 +108,16 @@ AP4_CencBasicSubSampleMapper::GetSubSampleMap(AP4_DataBuffer& sample_data, // process the sample data, one NALU at a time const AP4_UI08* in_end = sample_data.GetData()+sample_data.GetDataSize(); - while ((AP4_Size)(in_end-in) > 1+m_NaluLengthSize) { + if (m_Format == AP4_SAMPLE_FORMAT_AC_4) { + AP4_Ac4Header ac4_header(in, (AP4_Size)(in_end - in), false); + // BytesOfProtectedData shall be adjusted to a multiple of 16 bytes for 'cbc1' + AP4_Size encrypted_size = ((AP4_Size)(in_end - in) - ac4_header.m_TocSize)/16*16; + AP4_Size cleartext_size = (AP4_Size)(in_end - in) - encrypted_size; + bytes_of_cleartext_data.Append(cleartext_size); + bytes_of_encrypted_data.Append(encrypted_size); + return AP4_SUCCESS; + } + while ((AP4_Size)(in_end-in) > m_NaluLengthSize) { unsigned int nalu_length; switch (m_NaluLengthSize) { case 1: @@ -159,6 +169,18 @@ AP4_CencAdvancedSubSampleMapper::GetSubSampleMap(AP4_DataBuffer& sample_dat // process the sample data, one NALU at a time const AP4_UI08* in_end = sample_data.GetData()+sample_data.GetDataSize(); + if (m_Format == AP4_SAMPLE_FORMAT_AC_4) { + // According to ISO/IEC 23001-7 2023-8, BytesOfProtectedData shall be adjusted to a multiple of 16 bytes for 'cens' and 'cenc' mode. + AP4_Ac4Header ac4_header(in, (AP4_Size)(in_end - in), false); + AP4_Size total = static_cast(in_end - in); + AP4_Size header_size = ac4_header.m_TocSize; + AP4_Size encrypt_size = total - header_size; + + AP4_Size tail = encrypt_size & 0xF; + bytes_of_cleartext_data.Append(header_size + tail); + bytes_of_encrypted_data.Append(encrypt_size - tail); + return AP4_SUCCESS; + } while ((AP4_Size)(in_end-in) > 1+m_NaluLengthSize) { unsigned int nalu_length; switch (m_NaluLengthSize) { @@ -363,6 +385,21 @@ AP4_CencCbcsSubSampleMapper::GetSubSampleMap(AP4_DataBuffer& sample_data, // process the sample data, one NALU at a time const AP4_UI08* in_end = sample_data.GetData()+sample_data.GetDataSize(); + if (m_Format == AP4_SAMPLE_FORMAT_AC_4) { + AP4_Ac4Header ac4_header(in, (AP4_Size)(in_end - in), false); + // BytesOfProtectedData is not adjusted to a multiple of 16 bytes for 'cbcs' according + // to ISO/IEC 23001-7 2023-8, however decryption model doesn't support in Bento4, need + // to revisit this code in future. + // bytes_of_cleartext_data.Append(ac4_header.m_TocSize); + // bytes_of_encrypted_data.Append((AP4_Size)(in_end - in) - ac4_header.m_TocSize); + // BytesOfProtectedData shall be adjusted to a multiple of 16 bytes for 'cbc1' + AP4_Size encrypted_size = ((AP4_Size)(in_end - in) - ac4_header.m_TocSize) / 16 * 16; + AP4_Size cleartext_size = (AP4_Size)(in_end - in) - encrypted_size; + bytes_of_cleartext_data.Append(cleartext_size); + bytes_of_encrypted_data.Append(encrypted_size); + return AP4_SUCCESS; + } + while ((AP4_Size)(in_end-in) > 1+m_NaluLengthSize) { unsigned int nalu_length; switch (m_NaluLengthSize) { @@ -1562,7 +1599,7 @@ AP4_CencEncryptingProcessor::CreateTrackHandler(AP4_TrakAtom* trak) if (m_Options & OPTION_IV_SIZE_8) { cipher_iv_size = 8; } - if (enc_format == AP4_ATOM_TYPE_ENCV) { + if (enc_format == AP4_ATOM_TYPE_ENCV || (enc_format == AP4_ATOM_TYPE_ENCA && format == AP4_ATOM_TYPE_AC_4)) { crypt_byte_block = 1; skip_byte_block = 9; } @@ -1594,7 +1631,7 @@ AP4_CencEncryptingProcessor::CreateTrackHandler(AP4_TrakAtom* trak) case AP4_CENC_VARIANT_MPEG_CBCS: cipher_mode = AP4_BlockCipher::CBC; - if (enc_format == AP4_ATOM_TYPE_ENCV) { + if (enc_format == AP4_ATOM_TYPE_ENCV || (enc_format == AP4_ATOM_TYPE_ENCA && format == AP4_ATOM_TYPE_AC_4)) { crypt_byte_block = 1; skip_byte_block = 9; } @@ -1632,24 +1669,38 @@ AP4_CencEncryptingProcessor::CreateTrackHandler(AP4_TrakAtom* trak) // compute the size of NAL units unsigned int nalu_length_size = 0; - if (format == AP4_ATOM_TYPE_AVC1 || - format == AP4_ATOM_TYPE_AVC2 || - format == AP4_ATOM_TYPE_AVC3 || - format == AP4_ATOM_TYPE_AVC4 || - format == AP4_ATOM_TYPE_DVAV || - format == AP4_ATOM_TYPE_DVA1) { - AP4_AvccAtom* avcc = AP4_DYNAMIC_CAST(AP4_AvccAtom, entries[0]->GetChild(AP4_ATOM_TYPE_AVCC)); - if (avcc) { - nalu_length_size = avcc->GetNaluLengthSize(); - } - } else if (format == AP4_ATOM_TYPE_HEV1 || - format == AP4_ATOM_TYPE_HVC1 || - format == AP4_ATOM_TYPE_DVHE || - format == AP4_ATOM_TYPE_DVH1) { - AP4_HvccAtom* hvcc = AP4_DYNAMIC_CAST(AP4_HvccAtom, entries[0]->GetChild(AP4_ATOM_TYPE_HVCC)); - if (hvcc) { - nalu_length_size = hvcc->GetNaluLengthSize(); + bool use_subsample_encryption = false; + switch (format) { + case AP4_ATOM_TYPE_AVC1: + case AP4_ATOM_TYPE_AVC2: + case AP4_ATOM_TYPE_AVC3: + case AP4_ATOM_TYPE_AVC4: + case AP4_ATOM_TYPE_DVAV: + case AP4_ATOM_TYPE_DVA1: { + AP4_AvccAtom* avcc = AP4_DYNAMIC_CAST(AP4_AvccAtom, entries[0]->GetChild(AP4_ATOM_TYPE_AVCC)); + if (avcc) { + nalu_length_size = avcc->GetNaluLengthSize(); + use_subsample_encryption = (nalu_length_size > 0); + } + break; + } + case AP4_ATOM_TYPE_HEV1: + case AP4_ATOM_TYPE_HVC1: + case AP4_ATOM_TYPE_DVHE: + case AP4_ATOM_TYPE_DVH1: { + AP4_HvccAtom* hvcc = AP4_DYNAMIC_CAST(AP4_HvccAtom, entries[0]->GetChild(AP4_ATOM_TYPE_HVCC)); + if (hvcc) { + nalu_length_size = hvcc->GetNaluLengthSize(); + use_subsample_encryption = (nalu_length_size > 0); + } + break; } + case AP4_ATOM_TYPE_AC_4: + use_subsample_encryption = true; + break; + default: + use_subsample_encryption = false; + break; } // add a new cipher state for this track @@ -1662,7 +1713,7 @@ AP4_CencEncryptingProcessor::CreateTrackHandler(AP4_TrakAtom* trak) stream_cipher = new AP4_PatternStreamCipher(stream_cipher, crypt_byte_block, skip_byte_block); } - if (nalu_length_size) { + if (use_subsample_encryption) { AP4_CencSubSampleMapper* subsample_mapper = NULL; if (m_Variant == AP4_CENC_VARIANT_MPEG_CBCS) { subsample_mapper = new AP4_CencCbcsSubSampleMapper(nalu_length_size, format, trak); @@ -1684,7 +1735,7 @@ AP4_CencEncryptingProcessor::CreateTrackHandler(AP4_TrakAtom* trak) if (crypt_byte_block && skip_byte_block) { stream_cipher = new AP4_PatternStreamCipher(stream_cipher, crypt_byte_block, skip_byte_block); } - if (nalu_length_size) { + if (use_subsample_encryption) { AP4_CencSubSampleMapper* subsample_mapper = new AP4_CencAdvancedSubSampleMapper(nalu_length_size, format); sample_encrypter = new AP4_CencCtrSubSampleEncrypter(stream_cipher, constant_iv, @@ -1709,9 +1760,11 @@ AP4_CencEncryptingProcessor::CreateTrackHandler(AP4_TrakAtom* trak) AP4_UI32 clear_fragments = 0; if (clear_lead) { clear_fragments = AP4_ParseIntegerU(clear_lead); - unsigned int sample_description_count = stsd->GetSampleDescriptionCount(); - for (unsigned int i=0; iAddChild(stsd->GetSampleEntry(i)->Clone()); + if (clear_fragments != 0) { + unsigned int sample_description_count = stsd->GetSampleDescriptionCount(); + for (unsigned int i=0; iAddChild(stsd->GetSampleEntry(i)->Clone()); + } } } @@ -2939,17 +2992,30 @@ AP4_CencSampleInfoTable::Create(AP4_UI08 flags, } else { table->SetIv(saiz_index, constant_iv); } - if (info_size < per_sample_iv_size+2) { - result = AP4_ERROR_INVALID_FORMAT; - goto end; - } - AP4_UI16 subsample_count = AP4_BytesToUInt16BE(info_data+per_sample_iv_size); - if (info_size < per_sample_iv_size+2+subsample_count*6) { - // not enough data + // Aux info layouts we must accept: + // 1) [IV][subsample_count:2][subsample_map:subsample_count*6] + // (subsample encryption, e.g. video with cleartext slice + // headers mixed with encrypted payload) + // 2) [IV] (no subsample info) + // (whole-sample encryption, common for audio where every + // byte of the sample is encrypted and there is nothing + // to describe — valid per ISO/IEC 23001-7) + AP4_UI16 subsample_count = 0; + if (info_size >= per_sample_iv_size+2) { + subsample_count = AP4_BytesToUInt16BE(info_data+per_sample_iv_size); + if (info_size < per_sample_iv_size+2+subsample_count*6) { + // not enough data + result = AP4_ERROR_INVALID_FORMAT; + goto end; + } + table->AddSubSampleData(subsample_count, info_data+per_sample_iv_size+2); + } else if (info_size == per_sample_iv_size) { + // IV-only aux info: whole sample is encrypted, no subsamples. + table->AddSubSampleData(0, NULL); + } else { result = AP4_ERROR_INVALID_FORMAT; goto end; } - table->AddSubSampleData(subsample_count, info_data+per_sample_iv_size+2); saiz_index++; } } @@ -3275,7 +3341,11 @@ AP4_CencSampleEncryption::AP4_CencSampleEncryption(AP4_Atom& outer, stream.ReadUI32(m_SampleInfoCount); - AP4_Size payload_size = size-m_Outer.GetHeaderSize()-4; + /* Prevent the payload_size from becoming negative to avoid overflow */ + AP4_Size payload_size = 0; + if(size > (m_Outer.GetHeaderSize() + 4)) + payload_size = size - m_Outer.GetHeaderSize() - 4; + m_SampleInfos.SetDataSize(payload_size); stream.Read(m_SampleInfos.UseData(), payload_size); } diff --git a/Source/C++/Core/Ap4Config.h b/Source/C++/Core/Ap4Config.h index 5b9e83e0e..eb215d87b 100644 --- a/Source/C++/Core/Ap4Config.h +++ b/Source/C++/Core/Ap4Config.h @@ -50,7 +50,9 @@ #define AP4_PLATFORM_BYTE_ORDER_LITTLE_ENDIAN 1 #if !defined(AP4_PLATFORM_BYTE_ORDER) -#if defined(__ppc__) || defined(__powerpc__) +#if defined(__ppc__) || defined(__powerpc__) || defined(__PPC__) || defined(__PPC) +#define AP4_PLATFORM_BYTE_ORDER AP4_PLATFORM_BYTE_ORDER_BIG_ENDIAN +#elif defined(__s390__) #define AP4_PLATFORM_BYTE_ORDER AP4_PLATFORM_BYTE_ORDER_BIG_ENDIAN #elif defined(_MSC_VER) #if defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM) || defined(_M_ARM64) diff --git a/Source/C++/Core/Ap4Dac4Atom.cpp b/Source/C++/Core/Ap4Dac4Atom.cpp index b9ed40608..07315f795 100644 --- a/Source/C++/Core/Ap4Dac4Atom.cpp +++ b/Source/C++/Core/Ap4Dac4Atom.cpp @@ -664,11 +664,12 @@ AP4_Dac4Atom::Ac4Dsi::SubStream::ParseSubStreamInfoAjoc(AP4_BitReader &bits, // oamd_common_data() ParseOamdCommonData(bits); } - n_umx_objects_minus1 = bits.ReadBits(4); - int nFullbandUpmixSignals = n_umx_objects_minus1 + 1; + int nFullbandUpmixSignalsMinus = bits.ReadBits(4); + int nFullbandUpmixSignals = nFullbandUpmixSignalsMinus + 1; if (nFullbandUpmixSignals == 16) { nFullbandUpmixSignals += AP4_Ac4VariableBits(bits, 3); } + n_umx_objects_minus1 = nFullbandUpmixSignals - 1; BedDynObjAssignment(bits, nFullbandUpmixSignals, true); ParseDsiSfMutiplier(bits, fs_idx); @@ -966,7 +967,7 @@ AP4_Dac4Atom::Ac4Dsi::SubStream::ParseSubstreamIdxInfo(AP4_BitReader &bits, unsi { if (b_substreams_present == 1) { if (bits.ReadBits(2) == 3) { // substream_index - AP4_Ac4VariableBits(bits, 2); + ss_idx = AP4_Ac4VariableBits(bits, 2); } } return AP4_SUCCESS; diff --git a/Source/C++/Core/Ap4Dac4Atom.h b/Source/C++/Core/Ap4Dac4Atom.h index 227c50a88..72ec7c934 100644 --- a/Source/C++/Core/Ap4Dac4Atom.h +++ b/Source/C++/Core/Ap4Dac4Atom.h @@ -81,6 +81,7 @@ class AP4_Dac4Atom : public AP4_Atom AP4_UI08 b_substream_contains_bed_objects; AP4_UI08 b_substream_contains_dynamic_objects; AP4_UI08 b_substream_contains_ISF_objects; + AP4_UI08 ss_idx; // methods AP4_Result ParseSubstreamInfoChan(AP4_BitReader &bits, @@ -277,6 +278,7 @@ class AP4_Dac4Atom : public AP4_Atom static AP4_Dac4Atom* Create(AP4_Size size, AP4_ByteStream& stream); // constructors + AP4_Dac4Atom(const AP4_Dac4Atom& other); AP4_Dac4Atom(AP4_UI32 size, const Ac4Dsi* ac4Dsi); // DSI vaiable initialize m_RawBytes (m_Dsi -> m_RawBytes) // destructor @@ -297,7 +299,6 @@ class AP4_Dac4Atom : public AP4_Atom private: // methods - AP4_Dac4Atom(const AP4_Dac4Atom& other); AP4_Dac4Atom(AP4_UI32 size, const AP4_UI08* payload); // box data initialize m_Dsi (m_RawBytes -> m_Dsi) // members diff --git a/Source/C++/Core/Ap4Dec3Atom.cpp b/Source/C++/Core/Ap4Dec3Atom.cpp index e45219d94..adbe1fcff 100644 --- a/Source/C++/Core/Ap4Dec3Atom.cpp +++ b/Source/C++/Core/Ap4Dec3Atom.cpp @@ -51,7 +51,7 @@ AP4_Dec3Atom::Create(AP4_Size size, AP4_ByteStream& stream) AP4_Result result = stream.Read(payload_data.UseData(), payload_size); if (AP4_FAILED(result)) return NULL; - // check the version + // create the atom from the raw bytes const AP4_UI08* payload = payload_data.GetData(); return new AP4_Dec3Atom(size, payload); } diff --git a/Source/C++/Core/Ap4DmlpAtom.cpp b/Source/C++/Core/Ap4DmlpAtom.cpp new file mode 100644 index 000000000..fc776180e --- /dev/null +++ b/Source/C++/Core/Ap4DmlpAtom.cpp @@ -0,0 +1,121 @@ +/***************************************************************** +| +| AP4 - dmlp Atoms +| +| Copyright 2002-2018 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Atom.h" +#include "Ap4DmlpAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" +#include "Ap4Types.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_DmlpAtom) + +/*---------------------------------------------------------------------- +| AP4_DmlpAtom::Create ++---------------------------------------------------------------------*/ +AP4_DmlpAtom* +AP4_DmlpAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + if (size < AP4_ATOM_HEADER_SIZE + 10) { + return NULL; + } + + AP4_UI32 format_info; + stream.ReadUI32(format_info); + AP4_UI16 peak_data_rate; + stream.ReadUI16(peak_data_rate); + AP4_UI32 reserved; + stream.ReadUI32(reserved); + + return new AP4_DmlpAtom(format_info, peak_data_rate); +} + +/*---------------------------------------------------------------------- +| AP4_DmlpAtom::AP4_DmlpAtom ++---------------------------------------------------------------------*/ +AP4_DmlpAtom::AP4_DmlpAtom(AP4_UI32 format_info, AP4_UI16 peak_data_rate) : + AP4_Atom(AP4_ATOM_TYPE_DMLP, AP4_ATOM_HEADER_SIZE), + m_FormatInfo(format_info), + m_PeakDataRate(peak_data_rate) +{ + m_Size32 += 10; +} + +/*---------------------------------------------------------------------- +| AP4_DmlpAtom::AP4_DmlpAtom ++---------------------------------------------------------------------*/ +AP4_DmlpAtom::AP4_DmlpAtom(const AP4_DmlpAtom& other): + AP4_Atom(AP4_ATOM_TYPE_DMLP, other.m_Size32), + m_FormatInfo(other.m_FormatInfo), + m_PeakDataRate(other.m_PeakDataRate) +{ +} + +/*---------------------------------------------------------------------- +| AP4_DmlpAtom::GetCodecString ++---------------------------------------------------------------------*/ +void +AP4_DmlpAtom::GetCodecString(AP4_String& codec) +{ + codec = "mlpa"; +} + +/*---------------------------------------------------------------------- +| AP4_DmlpAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_DmlpAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + result = stream.WriteUI32(m_FormatInfo); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI16(m_PeakDataRate << 1); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32(0); + if (AP4_FAILED(result)) return result; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_DmlpAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_DmlpAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("format_info", m_FormatInfo); + inspector.AddField("peak_data_rate", m_PeakDataRate); + return AP4_SUCCESS; +} + diff --git a/Source/C++/Core/Ap4DmlpAtom.h b/Source/C++/Core/Ap4DmlpAtom.h new file mode 100644 index 000000000..e9ebd93b1 --- /dev/null +++ b/Source/C++/Core/Ap4DmlpAtom.h @@ -0,0 +1,65 @@ +/***************************************************************** +| +| AP4 - dmlp Atoms +| +| Copyright 2002-2018 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_DMLP_ATOM_H_ +#define _AP4_DMLP_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Atom.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| AP4_DmlpAtom ++---------------------------------------------------------------------*/ +class AP4_DmlpAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_DmlpAtom, AP4_Atom) + + // class methods + static AP4_DmlpAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // constructors + AP4_DmlpAtom(const AP4_DmlpAtom& other); + AP4_DmlpAtom(AP4_UI32 format_info, AP4_UI16 peak_data_rate); + + // methods + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + // helpers + void GetCodecString(AP4_String& codec); + + // members + AP4_UI32 m_FormatInfo; + AP4_UI16 m_PeakDataRate; +}; + +#endif // _AP4_DMLP_ATOM_H_ diff --git a/Source/C++/Core/Ap4EsDescriptor.cpp b/Source/C++/Core/Ap4EsDescriptor.cpp index 1308b4568..50beed1f8 100644 --- a/Source/C++/Core/Ap4EsDescriptor.cpp +++ b/Source/C++/Core/Ap4EsDescriptor.cpp @@ -95,7 +95,7 @@ AP4_EsDescriptor::AP4_EsDescriptor(AP4_ByteStream& stream, payload_size -= url_length; } } - if (m_Flags & AP4_ES_DESCRIPTOR_FLAG_URL) { + if (m_Flags & AP4_ES_DESCRIPTOR_FLAG_OCR_STREAM) { if (payload_size < 2) return; stream.ReadUI16(m_OcrEsId); payload_size -= 2; diff --git a/Source/C++/Core/Ap4LinearReader.cpp b/Source/C++/Core/Ap4LinearReader.cpp index 08b55eeb3..b69d83132 100644 --- a/Source/C++/Core/Ap4LinearReader.cpp +++ b/Source/C++/Core/Ap4LinearReader.cpp @@ -460,6 +460,7 @@ AP4_LinearReader::Advance(bool read_data) } if (AP4_FAILED(result)) { delete buffer; + next_tracker->m_NextSample = NULL; return result; } @@ -620,6 +621,8 @@ AP4_LinearReader::FindTracker(AP4_UI32 track_id) AP4_LinearReader::Tracker::~Tracker() { if (m_SampleTableIsOwned) delete m_SampleTable; + m_Samples.DeleteReferences(); + delete m_NextSample; delete m_Reader; } diff --git a/Source/C++/Core/Ap4MdhdAtom.cpp b/Source/C++/Core/Ap4MdhdAtom.cpp index 0bbb85a9e..266cd6997 100644 --- a/Source/C++/Core/Ap4MdhdAtom.cpp +++ b/Source/C++/Core/Ap4MdhdAtom.cpp @@ -66,7 +66,7 @@ AP4_MdhdAtom::AP4_MdhdAtom(AP4_UI64 creation_time, m_TimeScale(time_scale), m_Duration(duration) { - if (strlen(language) == 3) { + if (language != 0 && strlen(language) == 3) { m_Language.Assign(language, 3); } else { m_Language = "und"; diff --git a/Source/C++/Core/Ap4SampleDescription.cpp b/Source/C++/Core/Ap4SampleDescription.cpp index 247729fba..d4557b95b 100644 --- a/Source/C++/Core/Ap4SampleDescription.cpp +++ b/Source/C++/Core/Ap4SampleDescription.cpp @@ -60,6 +60,7 @@ AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_SubtitleSampleDescription) AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_Ac3SampleDescription) AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_Eac3SampleDescription) AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_Ac4SampleDescription) +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_TrueHdSampleDescription) /*---------------------------------------------------------------------- | AP4_GetFormatName @@ -88,6 +89,7 @@ AP4_GetFormatName(AP4_UI32 format) case AP4_SAMPLE_FORMAT_AC_3: return "Dolby Digital (AC-3)"; case AP4_SAMPLE_FORMAT_EC_3: return "Dolby Digital Plus (Enhanced AC-3)"; case AP4_SAMPLE_FORMAT_AC_4: return "Dolby AC-4"; + case AP4_SAMPLE_FORMAT_MLPA: return "Dolby TrueHD"; case AP4_SAMPLE_FORMAT_DTSC: return "DTS"; case AP4_SAMPLE_FORMAT_DTSH: return "DTS-HD"; case AP4_SAMPLE_FORMAT_DTSL: return "DTS-HD Lossless"; @@ -386,12 +388,12 @@ AP4_AvcSampleDescription::AP4_AvcSampleDescription(AP4_UI32 format, { AP4_AvccAtom* avcc = AP4_DYNAMIC_CAST(AP4_AvccAtom, m_Details.GetChild(AP4_ATOM_TYPE_AVCC)); if (avcc) { - m_AvccAtom = avcc; + m_AvccAtom = new AP4_AvccAtom(*avcc); } else { // shoud never happen m_AvccAtom = new AP4_AvccAtom(); - m_Details.AddChild(m_AvccAtom); } + m_Details.AddChild(m_AvccAtom); } /*---------------------------------------------------------------------- @@ -522,12 +524,12 @@ AP4_HevcSampleDescription::AP4_HevcSampleDescription(AP4_UI32 format, { AP4_HvccAtom* hvcc = AP4_DYNAMIC_CAST(AP4_HvccAtom, m_Details.GetChild(AP4_ATOM_TYPE_HVCC)); if (hvcc) { - m_HvccAtom = hvcc; + m_HvccAtom = new AP4_HvccAtom(*hvcc); } else { // shoud never happen m_HvccAtom = new AP4_HvccAtom(); - m_Details.AddChild(m_HvccAtom); } + m_Details.AddChild(m_HvccAtom); } /*---------------------------------------------------------------------- @@ -812,12 +814,12 @@ AP4_Av1SampleDescription::AP4_Av1SampleDescription(AP4_UI32 format, { AP4_Av1cAtom* av1c = AP4_DYNAMIC_CAST(AP4_Av1cAtom, m_Details.GetChild(AP4_ATOM_TYPE_AV1C)); if (av1c) { - m_Av1cAtom = av1c; + m_Av1cAtom = new AP4_Av1cAtom(*av1c); } else { // shoud never happen m_Av1cAtom = new AP4_Av1cAtom(); - m_Details.AddChild(m_Av1cAtom); } + m_Details.AddChild(m_Av1cAtom); } /*---------------------------------------------------------------------- @@ -825,7 +827,7 @@ AP4_Av1SampleDescription::AP4_Av1SampleDescription(AP4_UI32 format, +---------------------------------------------------------------------*/ AP4_Result AP4_Av1SampleDescription::GetCodecString(AP4_String& codec) { - AP4_UI08 bit_depth = 10; + AP4_UI08 bit_depth = (this->GetHighBitDepth() == 0) ? 8: (this->GetTwelveBit() == 0 ? 10 : 12); AP4_UI08 color_primaries = 1; AP4_UI08 transfer_characteristics = 1; AP4_UI08 matrix_coefficients = 1; @@ -838,7 +840,7 @@ AP4_Av1SampleDescription::GetCodecString(AP4_String& codec) { "%s.%d.%02d%c.%02d.%d.%d%d%d.%02d.%02d.%02d.%d", coding, this->GetSeqProfile(), - this->GetSeqLevelIdx0() >> 4, + this->GetSeqLevelIdx0(), this->GetSeqTier0() == 0 ? 'M' : 'H', bit_depth, this->GetMonochrome(), @@ -1097,49 +1099,46 @@ AP4_MpegAudioSampleDescription::GetMpeg4AudioObjectType() const } /*---------------------------------------------------------------------- - | AP4_Ac3SampleDescription::AP4_Ac3SampleDescription - +---------------------------------------------------------------------*/ +| AP4_Ac3SampleDescription::AP4_Ac3SampleDescription ++---------------------------------------------------------------------*/ AP4_Ac3SampleDescription::AP4_Ac3SampleDescription(AP4_UI32 sample_rate, AP4_UI16 sample_size, AP4_UI16 channel_count, const AP4_Dac3Atom* dac3): AP4_SampleDescription(TYPE_AC3, AP4_SAMPLE_FORMAT_AC_3, NULL), - AP4_AudioSampleDescription(sample_rate, sample_size, channel_count) + AP4_AudioSampleDescription(sample_rate, sample_size, channel_count), + m_Dac3Atom(NULL) { if (dac3) { m_Dac3Atom = new AP4_Dac3Atom(*dac3); + m_Details.AddChild(m_Dac3Atom); } else { // TODO: add default construtor, m_Dac3Atom = new AP4_Dac3Atom() / should never happen - m_Dac3Atom = NULL; } - m_Details.AddChild(m_Dac3Atom); } /*---------------------------------------------------------------------- - | AP4_Ac3SampleDescription::AP4_Ac3SampleDescription - +---------------------------------------------------------------------*/ +| AP4_Ac3SampleDescription::AP4_Ac3SampleDescription ++---------------------------------------------------------------------*/ AP4_Ac3SampleDescription::AP4_Ac3SampleDescription(AP4_UI32 sample_rate, AP4_UI16 sample_size, AP4_UI16 channel_count, AP4_AtomParent* details) : AP4_SampleDescription(TYPE_AC3, AP4_SAMPLE_FORMAT_AC_3, details), AP4_AudioSampleDescription(sample_rate, sample_size, channel_count), -m_Dac3Atom(NULL) + m_Dac3Atom(NULL) { - AP4_Dac3Atom* ac3 = AP4_DYNAMIC_CAST(AP4_Dac3Atom, m_Details.GetChild(AP4_SAMPLE_FORMAT_AC_3)); - if (ac3) { - m_Dac3Atom = ac3; + AP4_Dac3Atom* dac3 = AP4_DYNAMIC_CAST(AP4_Dac3Atom, m_Details.GetChild(AP4_ATOM_TYPE_DAC3)); + if (dac3) { + m_Dac3Atom = dac3; } else { // TODO: add default construtor, m_Dac3Atom = new AP4_Dac3Atom() / should never happen - m_Dac3Atom = NULL; - m_Details.AddChild(m_Dac3Atom); } } /*---------------------------------------------------------------------- - | AP4_Ac3SampleDescription::AP4_Ac3SampleDescription - +---------------------------------------------------------------------*/ - +| AP4_Ac3SampleDescription::AP4_Ac3SampleDescription ++---------------------------------------------------------------------*/ AP4_Ac3SampleDescription::AP4_Ac3SampleDescription(AP4_UI32 sample_rate, AP4_UI16 sample_size, AP4_UI16 channel_count, @@ -1153,9 +1152,8 @@ AP4_Ac3SampleDescription::AP4_Ac3SampleDescription(AP4_UI32 } /*---------------------------------------------------------------------- - | AP4_Ac3SampleDescription::ToAtom - +---------------------------------------------------------------------*/ - +| AP4_Ac3SampleDescription::ToAtom ++---------------------------------------------------------------------*/ AP4_Atom* AP4_Ac3SampleDescription::ToAtom() const { @@ -1206,14 +1204,14 @@ AP4_Eac3SampleDescription::AP4_Eac3SampleDescription(AP4_UI32 sample_rate AP4_AudioSampleDescription(sample_rate, sample_size, channel_count), m_Dec3Atom(NULL) { - AP4_Dec3Atom* eac3 = AP4_DYNAMIC_CAST(AP4_Dec3Atom, m_Details.GetChild(AP4_SAMPLE_FORMAT_EC_3)); + AP4_Dec3Atom* eac3 = AP4_DYNAMIC_CAST(AP4_Dec3Atom, m_Details.GetChild(AP4_ATOM_TYPE_DEC3)); if (eac3) { - m_Dec3Atom = eac3; + m_Dec3Atom = new AP4_Dec3Atom(*eac3); } else { // shoud never happen m_Dec3Atom = new AP4_Dec3Atom(); - m_Details.AddChild(m_Dec3Atom); } + m_Details.AddChild(m_Dec3Atom); } /*---------------------------------------------------------------------- @@ -1255,16 +1253,15 @@ AP4_Ac4SampleDescription::AP4_Ac4SampleDescription(AP4_UI32 sample_ra AP4_UI16 channel_count, const AP4_Dac4Atom* dac4): AP4_SampleDescription(TYPE_AC4, AP4_SAMPLE_FORMAT_AC_4, NULL), - AP4_AudioSampleDescription(sample_rate, sample_size, channel_count) + AP4_AudioSampleDescription(sample_rate, sample_size, channel_count), + m_Dac4Atom(NULL) { if (dac4) { m_Dac4Atom = dac4->CloneConst(); -; + m_Details.AddChild(m_Dac4Atom); } else { // TODO: add default construtor, m_Dac4Atom = new AP4_Dac4Atom() / should never happen - m_Dac4Atom = NULL; } - m_Details.AddChild(m_Dac4Atom); } /*---------------------------------------------------------------------- @@ -1283,8 +1280,6 @@ AP4_Ac4SampleDescription::AP4_Ac4SampleDescription(AP4_UI32 sample_rate, m_Dac4Atom = ac4; } else { // TODO: add default construtor, m_Dac4Atom = new AP4_Dac4Atom() / should never happen - m_Dac4Atom = NULL; - m_Details.AddChild(m_Dac4Atom); } } @@ -1306,7 +1301,6 @@ AP4_Ac4SampleDescription::AP4_Ac4SampleDescription(AP4_UI32 s /*---------------------------------------------------------------------- | AP4_Ac4SampleDescription::ToAtom +---------------------------------------------------------------------*/ - AP4_Atom* AP4_Ac4SampleDescription::ToAtom() const { @@ -1317,6 +1311,55 @@ AP4_Ac4SampleDescription::ToAtom() const &m_Details); } +/*---------------------------------------------------------------------- +| AP4_TrueHdSampleDescription::AP4_TrueHdSampleDescription ++---------------------------------------------------------------------*/ +AP4_TrueHdSampleDescription::AP4_TrueHdSampleDescription(AP4_UI32 sample_rate, + AP4_UI16 sample_size, + AP4_UI16 channel_count, + const AP4_DmlpAtom* dmlp): + AP4_SampleDescription(TYPE_TRUEHD, AP4_SAMPLE_FORMAT_MLPA, NULL), + AP4_AudioSampleDescription(sample_rate, sample_size, channel_count), + m_DmlpAtom(NULL) +{ + if (dmlp) { + m_DmlpAtom = new AP4_DmlpAtom(*dmlp); + m_Details.AddChild(m_DmlpAtom); + } +} + +/*---------------------------------------------------------------------- +| AP4_TrueHdSampleDescription::AP4_TrueHdSampleDescription ++---------------------------------------------------------------------*/ +AP4_TrueHdSampleDescription::AP4_TrueHdSampleDescription(AP4_UI32 sample_rate, + AP4_UI16 sample_size, + AP4_UI16 channel_count, + AP4_AtomParent* details) : + AP4_SampleDescription(TYPE_TRUEHD, AP4_SAMPLE_FORMAT_MLPA, details), + AP4_AudioSampleDescription(sample_rate, sample_size, channel_count) +{ + AP4_DmlpAtom* dmlp = AP4_DYNAMIC_CAST(AP4_DmlpAtom, m_Details.GetChild(AP4_ATOM_TYPE_DMLP)); + if (dmlp) { + m_DmlpAtom = new AP4_DmlpAtom(*dmlp); + } else { + m_DmlpAtom = new AP4_DmlpAtom(0, 0); + } + m_Details.AddChild(m_DmlpAtom); +} + +/*---------------------------------------------------------------------- +| AP4_TrueHdSampleDescription::ToAtom ++---------------------------------------------------------------------*/ +AP4_Atom* +AP4_TrueHdSampleDescription::ToAtom() const +{ + return new AP4_MlpSampleEntry(m_Format, + m_SampleRate, + m_SampleSize, + m_ChannelCount, + &m_Details); +} + /*---------------------------------------------------------------------- | AP4_MpegVideoSampleDescription::AP4_MpegVideoSampleDescription +---------------------------------------------------------------------*/ diff --git a/Source/C++/Core/Ap4SampleDescription.h b/Source/C++/Core/Ap4SampleDescription.h index 27f3136c8..dfd7a96eb 100644 --- a/Source/C++/Core/Ap4SampleDescription.h +++ b/Source/C++/Core/Ap4SampleDescription.h @@ -42,6 +42,7 @@ #include "Ap4Av1cAtom.h" #include "Ap4DynamicCast.h" #include "Ap4Dac4Atom.h" +#include "Ap4DmlpAtom.h" #include "Ap4Dec3Atom.h" #include "Ap4Dac3Atom.h" #include "Ap4DvccAtom.h" @@ -78,6 +79,7 @@ const AP4_UI32 AP4_SAMPLE_FORMAT_DRA1 = AP4_ATOM_TYPE('d','r','a','1'); const AP4_UI32 AP4_SAMPLE_FORMAT_AC_3 = AP4_ATOM_TYPE('a','c','-','3'); const AP4_UI32 AP4_SAMPLE_FORMAT_AC_4 = AP4_ATOM_TYPE('a','c','-','4'); const AP4_UI32 AP4_SAMPLE_FORMAT_EC_3 = AP4_ATOM_TYPE('e','c','-','3'); +const AP4_UI32 AP4_SAMPLE_FORMAT_MLPA = AP4_ATOM_TYPE('m','l','p','a'); const AP4_UI32 AP4_SAMPLE_FORMAT_DTSC = AP4_ATOM_TYPE('d','t','s','c'); const AP4_UI32 AP4_SAMPLE_FORMAT_DTSH = AP4_ATOM_TYPE('d','t','s','h'); const AP4_UI32 AP4_SAMPLE_FORMAT_DTSL = AP4_ATOM_TYPE('d','t','s','l'); @@ -106,6 +108,7 @@ const AP4_UI32 AP4_SAMPLE_FORMAT_OPUS = AP4_ATOM_TYPE('O','p','u','s'); const AP4_UI32 AP4_SAMPLE_FORMAT_VP8 = AP4_ATOM_TYPE('v','p','0','8'); const AP4_UI32 AP4_SAMPLE_FORMAT_VP9 = AP4_ATOM_TYPE('v','p','0','9'); const AP4_UI32 AP4_SAMPLE_FORMAT_VP10 = AP4_ATOM_TYPE('v','p','1','0'); +const AP4_UI32 AP4_SAMPLE_COLOR_TYPE_NCLX = AP4_ATOM_TYPE('n','c','l','x'); const char* AP4_GetFormatName(AP4_UI32 format); @@ -129,7 +132,8 @@ class AP4_SampleDescription TYPE_AV1 = 0x06, TYPE_AC3 = 0x07, TYPE_EAC3 = 0x08, - TYPE_AC4 = 0x09 + TYPE_AC4 = 0x09, + TYPE_TRUEHD = 0x0A }; // constructors & destructor @@ -802,6 +806,37 @@ class AP4_Ac4SampleDescription : public AP4_SampleDescription, AP4_Dac4Atom* m_Dac4Atom; }; +/*---------------------------------------------------------------------- +| AP4_TrueHdSampleDescription ++---------------------------------------------------------------------*/ +class AP4_TrueHdSampleDescription : public AP4_SampleDescription, + public AP4_AudioSampleDescription +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D2(AP4_TrueHdSampleDescription, AP4_SampleDescription, AP4_AudioSampleDescription) + + // constructors + AP4_TrueHdSampleDescription(AP4_UI32 sample_rate, + AP4_UI16 sample_size, + AP4_UI16 channel_count, + const AP4_DmlpAtom* dmlpAtom); + + AP4_TrueHdSampleDescription(AP4_UI32 sample_rate, + AP4_UI16 sample_size, + AP4_UI16 channel_count, + AP4_AtomParent* details); + + // inherited from AP4_SampleDescription + virtual AP4_Result GetCodecString(AP4_String& codec) { + m_DmlpAtom->GetCodecString(codec); + return AP4_SUCCESS; + } + virtual AP4_Atom* ToAtom() const; + +private: + AP4_DmlpAtom* m_DmlpAtom; +}; + /*---------------------------------------------------------------------- | AP4_MpegVideoSampleDescription +---------------------------------------------------------------------*/ diff --git a/Source/C++/Core/Ap4SampleEntry.cpp b/Source/C++/Core/Ap4SampleEntry.cpp index 1c175a380..4f71ad20f 100644 --- a/Source/C++/Core/Ap4SampleEntry.cpp +++ b/Source/C++/Core/Ap4SampleEntry.cpp @@ -681,19 +681,18 @@ AP4_MpegAudioSampleEntry::ToSampleDescription() /*---------------------------------------------------------------------- | AP4_Ac3SampleEntry::AP4_Ac3SampleEntry +---------------------------------------------------------------------*/ -AP4_Ac3SampleEntry::AP4_Ac3SampleEntry(AP4_UI32 format, - AP4_UI32 sample_rate, - AP4_UI16 sample_size, - AP4_UI16 channel_count, - const AP4_AtomParent *details): +AP4_Ac3SampleEntry::AP4_Ac3SampleEntry(AP4_UI32 format, + AP4_UI32 sample_rate, + AP4_UI16 sample_size, + AP4_UI16 channel_count, + const AP4_AtomParent* details): AP4_AudioSampleEntry(format, sample_rate, sample_size, channel_count) { - if (details){ - AP4_AtomParent* parent = new AP4_AtomParent(); - details->CopyChildren(*parent); - AP4_Atom* child = parent->GetChild(AP4_ATOM_TYPE_DAC3); - child->Detach(); - AddChild(child); + if (details) { + AP4_Dac3Atom* dac3 = AP4_DYNAMIC_CAST(AP4_Dac3Atom, details->GetChild(AP4_ATOM_TYPE_DAC3)); + if (dac3) { + AddChild(new AP4_Dac3Atom(*dac3)); + } } } @@ -729,16 +728,18 @@ AP4_Ac3SampleEntry::ToSampleDescription() /*---------------------------------------------------------------------- | AP4_Eac3SampleEntry::AP4_Eac3SampleEntry +---------------------------------------------------------------------*/ -AP4_Eac3SampleEntry::AP4_Eac3SampleEntry(AP4_UI32 format, - AP4_UI32 sample_rate, - AP4_UI16 sample_size, - AP4_UI16 channel_count, - const AP4_AtomParent *details): +AP4_Eac3SampleEntry::AP4_Eac3SampleEntry(AP4_UI32 format, + AP4_UI32 sample_rate, + AP4_UI16 sample_size, + AP4_UI16 channel_count, + const AP4_AtomParent* details): AP4_AudioSampleEntry(format, sample_rate, sample_size, channel_count) { - if (details){ - AP4_Atom* child = details->GetChild(AP4_ATOM_TYPE_DEC3)->Clone(); - AddChild(child); + if (details) { + AP4_Dec3Atom* dec3 = AP4_DYNAMIC_CAST(AP4_Dec3Atom, details->GetChild(AP4_ATOM_TYPE_DEC3)); + if (dec3) { + AddChild(new AP4_Dec3Atom(*dec3)); + } } } @@ -782,12 +783,11 @@ AP4_Ac4SampleEntry::AP4_Ac4SampleEntry(AP4_UI32 format, const AP4_AtomParent* details): AP4_AudioSampleEntry(format, sample_rate, sample_size, channel_count) { - if (details){ - AP4_AtomParent* parent = new AP4_AtomParent(); - details->CopyChildren(*parent); - AP4_Atom* child = parent->GetChild(AP4_ATOM_TYPE_DAC4); - child->Detach(); - AddChild(child); + if (details) { + AP4_Dac4Atom* dac4 = AP4_DYNAMIC_CAST(AP4_Dac4Atom, details->GetChild(AP4_ATOM_TYPE_DAC4)); + if (dac4) { + AddChild(dac4->Clone()); + } } } @@ -820,6 +820,62 @@ AP4_Ac4SampleEntry::ToSampleDescription() } } +/*---------------------------------------------------------------------- +| AP4_MlpSampleEntry::AP4_MlpSampleEntry ++---------------------------------------------------------------------*/ +AP4_MlpSampleEntry::AP4_MlpSampleEntry(AP4_UI32 format, + AP4_UI32 sample_rate, + AP4_UI16 sample_size, + AP4_UI16 channel_count, + const AP4_AtomParent* details): + AP4_AudioSampleEntry(format, sample_rate, sample_size, channel_count) +{ + if (details) { + AP4_DmlpAtom* dmlp = AP4_DYNAMIC_CAST(AP4_DmlpAtom, details->GetChild(AP4_ATOM_TYPE_DMLP)); + if (dmlp) { + AddChild(new AP4_DmlpAtom(*dmlp)); + } + } +} + +/*---------------------------------------------------------------------- +| AP4_MlpSampleEntry::AP4_MlpSampleEntry ++---------------------------------------------------------------------*/ +AP4_MlpSampleEntry::AP4_MlpSampleEntry(AP4_UI32 type, + AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) : + AP4_AudioSampleEntry(type, size, stream, atom_factory) +{ +} + +/*---------------------------------------------------------------------- +| AP4_MlpSampleEntry::GetSampleRate ++---------------------------------------------------------------------*/ +AP4_UI32 +AP4_MlpSampleEntry::GetSampleRate() +{ + return m_SampleRate; +} + +/*---------------------------------------------------------------------- +| AP4_Ac4SampleEntry::ToSampleDescription ++---------------------------------------------------------------------*/ +AP4_SampleDescription* +AP4_MlpSampleEntry::ToSampleDescription() +{ + // find the dmlp atom + AP4_DmlpAtom* dmlp = AP4_DYNAMIC_CAST(AP4_DmlpAtom, GetChild(AP4_ATOM_TYPE_DMLP)); + if (dmlp == NULL) { + return NULL; + } + + return new AP4_TrueHdSampleDescription(GetSampleRate(), + GetSampleSize(), + GetChannelCount(), + dmlp); +} + /*---------------------------------------------------------------------- | AP4_Mp4aSampleEntry::AP4_Mp4aSampleEntry +---------------------------------------------------------------------*/ @@ -849,10 +905,10 @@ AP4_Mp4aSampleEntry::AP4_Mp4aSampleEntry(AP4_Size size, | AP4_VisualSampleEntry::AP4_VisualSampleEntry +---------------------------------------------------------------------*/ AP4_VisualSampleEntry::AP4_VisualSampleEntry( - AP4_Atom::Type format, - AP4_UI16 width, - AP4_UI16 height, - AP4_UI16 depth, + AP4_Atom::Type format, + AP4_UI16 width, + AP4_UI16 height, + AP4_UI16 depth, const char* compressor_name, const AP4_AtomParent* details) : AP4_SampleEntry(format, details), @@ -1111,11 +1167,11 @@ AP4_Mp4vSampleEntry::AP4_Mp4vSampleEntry(AP4_Size size, /*---------------------------------------------------------------------- | AP4_AvcSampleEntry::AP4_AvcSSampleEntry +---------------------------------------------------------------------*/ -AP4_AvcSampleEntry::AP4_AvcSampleEntry(AP4_UI32 format, - AP4_UI16 width, - AP4_UI16 height, - AP4_UI16 depth, - const char* compressor_name, +AP4_AvcSampleEntry::AP4_AvcSampleEntry(AP4_UI32 format, + AP4_UI16 width, + AP4_UI16 height, + AP4_UI16 depth, + const char* compressor_name, const AP4_AtomParent* details) : AP4_VisualSampleEntry(format, width, @@ -1155,11 +1211,11 @@ AP4_AvcSampleEntry::ToSampleDescription() /*---------------------------------------------------------------------- | AP4_HevcSampleEntry::AP4_HevcSampleEntry +---------------------------------------------------------------------*/ -AP4_HevcSampleEntry::AP4_HevcSampleEntry(AP4_UI32 format, - AP4_UI16 width, - AP4_UI16 height, - AP4_UI16 depth, - const char* compressor_name, +AP4_HevcSampleEntry::AP4_HevcSampleEntry(AP4_UI32 format, + AP4_UI16 width, + AP4_UI16 height, + AP4_UI16 depth, + const char* compressor_name, const AP4_AtomParent* details) : AP4_VisualSampleEntry(format, width, @@ -1199,11 +1255,11 @@ AP4_HevcSampleEntry::ToSampleDescription() /*---------------------------------------------------------------------- | AP4_Av1SampleEntry::AP4_Av1SampleEntry +---------------------------------------------------------------------*/ -AP4_Av1SampleEntry::AP4_Av1SampleEntry(AP4_UI32 format, - AP4_UI16 width, - AP4_UI16 height, - AP4_UI16 depth, - const char* compressor_name, +AP4_Av1SampleEntry::AP4_Av1SampleEntry(AP4_UI32 format, + AP4_UI16 width, + AP4_UI16 height, + AP4_UI16 depth, + const char* compressor_name, const AP4_AtomParent* details) : AP4_VisualSampleEntry(format, width, diff --git a/Source/C++/Core/Ap4SampleEntry.h b/Source/C++/Core/Ap4SampleEntry.h index 1f54ad7ca..c228bbe25 100644 --- a/Source/C++/Core/Ap4SampleEntry.h +++ b/Source/C++/Core/Ap4SampleEntry.h @@ -135,7 +135,7 @@ class AP4_AudioSampleEntry : public AP4_SampleEntry AP4_AtomFactory& atom_factory); // accessors - AP4_UI32 GetSampleRate(); + virtual AP4_UI32 GetSampleRate(); AP4_UI16 GetSampleSize() { return m_SampleSize; } AP4_UI16 GetChannelCount(); @@ -326,6 +326,27 @@ class AP4_Ac4SampleEntry : public AP4_AudioSampleEntry virtual AP4_SampleDescription* ToSampleDescription(); }; +/*---------------------------------------------------------------------- +| AP4_MlpSampleEntry ++---------------------------------------------------------------------*/ +class AP4_MlpSampleEntry : public AP4_AudioSampleEntry +{ +public: + AP4_MlpSampleEntry(AP4_UI32 format, + AP4_UI32 sample_rate, + AP4_UI16 sample_size, + AP4_UI16 channel_count, + const AP4_AtomParent* details); + AP4_MlpSampleEntry(AP4_UI32 type, + AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + + // inherited from AP4_SampleEntry + virtual AP4_UI32 GetSampleRate(); + virtual AP4_SampleDescription* ToSampleDescription(); +}; + /*---------------------------------------------------------------------- | AP4_MpegVideoSampleEntry +---------------------------------------------------------------------*/ diff --git a/Source/C++/Core/Ap4StsdAtom.cpp b/Source/C++/Core/Ap4StsdAtom.cpp index 68f4a047c..364761f28 100644 --- a/Source/C++/Core/Ap4StsdAtom.cpp +++ b/Source/C++/Core/Ap4StsdAtom.cpp @@ -72,6 +72,8 @@ AP4_StsdAtom::AP4_StsdAtom(AP4_SampleTable* sample_table) : // create an entry for the description AP4_SampleDescription* sample_description = sample_table->GetSampleDescription(i); + if (sample_description == 0) + continue; AP4_Atom* entry = sample_description->ToAtom(); AddChild(entry); } diff --git a/Source/C++/Core/Ap4TfraAtom.cpp b/Source/C++/Core/Ap4TfraAtom.cpp index 833a27ff1..d433bd497 100644 --- a/Source/C++/Core/Ap4TfraAtom.cpp +++ b/Source/C++/Core/Ap4TfraAtom.cpp @@ -150,7 +150,7 @@ AP4_TfraAtom::AP4_TfraAtom(AP4_UI32 size, } // Check that it all fits - if (((size - (AP4_FULL_ATOM_HEADER_SIZE+4+4+4)) / entry_count) < entry_size) { + if (entry_count <= 0 || ((size - (AP4_FULL_ATOM_HEADER_SIZE+4+4+4)) / entry_count) < entry_size) { return; } diff --git a/Source/C++/Core/Ap4TrunAtom.cpp b/Source/C++/Core/Ap4TrunAtom.cpp index 6784ee7b1..81c5923d1 100644 --- a/Source/C++/Core/Ap4TrunAtom.cpp +++ b/Source/C++/Core/Ap4TrunAtom.cpp @@ -37,6 +37,11 @@ +---------------------------------------------------------------------*/ AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_TrunAtom) +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +#define AP4_TRUN_MAX_SAMPLE_COUNT 0xFFFFFF + /*---------------------------------------------------------------------- | AP4_TrunAtom::Create +---------------------------------------------------------------------*/ @@ -143,14 +148,15 @@ AP4_TrunAtom::AP4_TrunAtom(AP4_UI32 size, } int record_fields_count = (int)ComputeRecordFieldsCount(flags); - if (!record_fields_count) { - // nothing to read - return; - } - - if ((bytes_left / (record_fields_count*4)) < sample_count) { - // not enough data for all samples, the format is invalid - return; + if (record_fields_count) { + if ((bytes_left / (record_fields_count*4)) < sample_count) { + // not enough data for all samples, the format is invalid + return; + } + } else { + if (sample_count > AP4_TRUN_MAX_SAMPLE_COUNT) { + return; + } } if (AP4_FAILED(m_Entries.SetItemCount(sample_count))) { @@ -308,7 +314,9 @@ AP4_TrunAtom::InspectFields(AP4_AtomInspector& inspector) } if (m_Flags & AP4_TRUN_FLAG_SAMPLE_COMPOSITION_TIME_OFFSET_PRESENT) { inspector.AddField(inspector.GetVerbosity() >= 2 ? "sample_composition_time_offset" : "c", - m_Entries[i].sample_composition_time_offset); + m_Version == 0 ? + m_Entries[i].sample_composition_time_offset : + static_cast(static_cast(m_Entries[i].sample_composition_time_offset))); } inspector.EndObject(); diff --git a/Source/C++/Core/Ap4Utils.cpp b/Source/C++/Core/Ap4Utils.cpp index 96def27a3..2adc02e77 100644 --- a/Source/C++/Core/Ap4Utils.cpp +++ b/Source/C++/Core/Ap4Utils.cpp @@ -443,6 +443,11 @@ AP4_BitReader::GetBitsRead() AP4_BitReader::BitsWord AP4_BitReader::ReadCache() const { + // stop reading past the end of the buffer when more bits are requested + // than the input contains; the missing bytes read as zero + if (m_Position+AP4_WORD_BYTES > m_Buffer.GetBufferSize()) { + return 0; + } const AP4_UI08* out_ptr = m_Buffer.GetData()+m_Position; return (((AP4_BitReader::BitsWord) out_ptr[0]) << 24) | (((AP4_BitReader::BitsWord) out_ptr[1]) << 16) | @@ -581,4 +586,13 @@ AP4_BitReader::SkipBit() } } +/*---------------------------------------------------------------------- +| AP4_BitReader::GetPosition ++---------------------------------------------------------------------*/ +unsigned int +AP4_BitReader::GetBitsPosition() +{ + return m_Position * 8 - m_BitsCached; +} + diff --git a/Source/C++/Core/Ap4Utils.h b/Source/C++/Core/Ap4Utils.h index 475bff3af..29597604a 100644 --- a/Source/C++/Core/Ap4Utils.h +++ b/Source/C++/Core/Ap4Utils.h @@ -263,6 +263,8 @@ class AP4_BitReader void SkipBit(); void SkipBits(unsigned int bit_count); + unsigned int GetBitsPosition(); + unsigned int GetBitsRead(); private: diff --git a/Source/C++/Crypto/Ap4AesBlockCipher.cpp b/Source/C++/Crypto/Ap4AesBlockCipher.cpp index 07c933046..6be120ae3 100644 --- a/Source/C++/Crypto/Ap4AesBlockCipher.cpp +++ b/Source/C++/Crypto/Ap4AesBlockCipher.cpp @@ -1964,6 +1964,150 @@ AP4_AesCtrBlockCipher::Process(const AP4_UI08* input, return AP4_SUCCESS; } +#if AP4_AES_BLOCK_SIZE == 16 && AP4_AES_KEY_LENGTH == 16 && defined(__AES__) && defined(__SSE4_2__) +#define AP4_ENABLE_AESNI + +#include + +#define cpuid(func,ax,bx,cx,dx)\ + __asm__ __volatile__ ("cpuid":\ + "=a" (ax), "=b" (bx), "=c" (cx), "=d" (dx) : "a" (func)); + +static bool g_SupportAesNI = false; +__attribute__((constructor)) static void detect_aesni() +{ + unsigned int a,b,c,d; + cpuid(1, a,b,c,d); + g_SupportAesNI = c & 0x2000000; +} + +#endif + +#ifdef AP4_ENABLE_AESNI +template +static void aesni_process_NB_blocks(AP4_UI08* Out, AP4_UI08 const* In, __m128i& CB, AP4_UI08 const* Keys) +{ + __m128i CBs[NB]; + const __m128i CB_ = CB; +#pragma unroll + for (AP4_Size i = 0; i < NB; ++i) { + CBs[i] = _mm_add_epi64(CB_, _mm_set_epi32(0,i+1,0,0)); + } + CB = CBs[NB-1]; + const __m128i Bswap64 = _mm_set_epi8(8,9,10,11,12,13,14,15,7,6,5,4,3,2,1,0); +#pragma unroll + for (AP4_Size i = 0; i < NB; ++i) { + CBs[i] = _mm_shuffle_epi8(CBs[i], Bswap64); + } + + __m128i EncrCBs[NB]; + const __m128i Key0 = _mm_loadu_si128((const __m128i*)Keys); +#pragma unroll + for (AP4_Size i = 0; i < NB; ++i) { + EncrCBs[i] = _mm_xor_si128(CBs[i], Key0); + } +#pragma unroll + for (AP4_Size R = 1; R < 10; R++) { + const __m128i Key = _mm_loadu_si128((const __m128i*)&Keys[R*AP4_AES_KEY_LENGTH]); +#pragma unroll + for (AP4_Size i = 0; i < NB; ++i) { + EncrCBs[i] = _mm_aesenc_si128(EncrCBs[i], Key); + } + } + + const __m128i KeyLast = _mm_loadu_si128((const __m128i*)&Keys[10*AP4_AES_KEY_LENGTH]); +#pragma unroll + for (AP4_Size i = 0; i < NB; ++i) { + EncrCBs[i] = _mm_aesenclast_si128(EncrCBs[i], + _mm_xor_si128(KeyLast, _mm_loadu_si128((const __m128i*)&In[i*AP4_AES_BLOCK_SIZE]))); + } + +#pragma unroll + for (AP4_Size i = 0; i < NB; ++i) { + _mm_storeu_si128((__m128i*)&Out[i*AP4_AES_BLOCK_SIZE], EncrCBs[i]); + } +} + +static void process(AP4_UI08* output, AP4_UI08 const* input, AP4_Size input_size, const AP4_UI08* iv, const AP4_UI08* Keys) +{ + union { + AP4_UI08 B[AP4_AES_BLOCK_SIZE]; + __m128i V; + } Counter; + + if (iv) { + memcpy(&Counter.B[0], iv, AP4_AES_BLOCK_SIZE); + Counter.V = _mm_shuffle_epi8(Counter.V, _mm_set_epi8(8,9,10,11,12,13,14,15,7,6,5,4,3,2,1,0)); + Counter.V = _mm_sub_epi64(Counter.V, _mm_set_epi32(0,1,0,0)); + } else { + memset(&Counter.B[0], 0, AP4_AES_BLOCK_SIZE); + } + + // First, process blocks eight by eight (Intel recommandation) + const AP4_Size Size8B = 8*AP4_AES_BLOCK_SIZE; + const AP4_Size End8B = (input_size/Size8B)*Size8B; + for (AP4_Size i = 0; i < End8B; i += Size8B) { + aesni_process_NB_blocks<8>(&output[i], &input[i], Counter.V, Keys); + } + // Process the remaining blocks! + const AP4_Size RemBlocks = (input_size-End8B)/AP4_AES_BLOCK_SIZE; + AP4_Size CurIdx = End8B; + switch (RemBlocks) { +#define FINAL_BLOCKS(N)\ + case N:\ + aesni_process_NB_blocks(&output[CurIdx], &input[CurIdx], Counter.V, Keys);\ + CurIdx += N*AP4_AES_BLOCK_SIZE;\ + break; + + FINAL_BLOCKS(7) + FINAL_BLOCKS(6) + FINAL_BLOCKS(5) + FINAL_BLOCKS(4) + FINAL_BLOCKS(3) + FINAL_BLOCKS(2) + FINAL_BLOCKS(1) +#undef FINAL_BLOCKS + } + const AP4_Size Rem = input_size-CurIdx; + assert(Rem < 16 && "too many remaining bytes!"); + if (Rem > 0) { + // Last block + AP4_UI08 LastBlock[AP4_AES_BLOCK_SIZE]; + memcpy(&LastBlock[0], &input[CurIdx], Rem); + aesni_process_NB_blocks<1>(&LastBlock[0], &LastBlock[0], Counter.V, Keys); + memcpy(&output[CurIdx], &LastBlock[0], Rem); + } +} + +class AP4_AesNICtrBlockCipher : public AP4_AesBlockCipher +{ +public: + AP4_AesNICtrBlockCipher(CipherDirection direction, + unsigned int counter_size, + aes_ctx* context) : + AP4_AesBlockCipher(direction, CTR, context) + { + assert(counter_size == 8 && "counter size must be 8 bytes!"); + } + + // AP4_BlockCipher methods + virtual AP4_Result Process(const AP4_UI08* input, + AP4_Size input_size, + AP4_UI08* output, + const AP4_UI08* iv); +}; + +AP4_Result AP4_AesNICtrBlockCipher::Process(const AP4_UI08* input, + AP4_Size input_size, + AP4_UI08* output, + const AP4_UI08* iv) +{ + assert(m_Context->n_rnd == 10 && "this only works for AES128!"); + process(output, input, input_size, iv, (const AP4_UI08*) &m_Context->k_sch[0]); + return AP4_SUCCESS; +} +#endif // AP4_ENABLE_AESNI + /*---------------------------------------------------------------------- | AP4_AesBlockCipher::Create +---------------------------------------------------------------------*/ @@ -1995,7 +2139,16 @@ AP4_AesBlockCipher::Create(const AP4_UI08* key, if (ctr_params) { counter_size = ctr_params->counter_size; } - cipher = new AP4_AesCtrBlockCipher(direction, counter_size, context); +#ifdef AP4_ENABLE_AESNI + if (g_SupportAesNI && (counter_size == 8)) { + cipher = new AP4_AesNICtrBlockCipher(direction, counter_size, context); + } + else { +#endif + cipher = new AP4_AesCtrBlockCipher(direction, counter_size, context); +#ifdef AP4_ENABLE_AESNI + } +#endif break; } diff --git a/Source/Python/utils/mp4-dash-encode.py b/Source/Python/utils/mp4-dash-encode.py index d449e5507..4d0e3ec20 100755 --- a/Source/Python/utils/mp4-dash-encode.py +++ b/Source/Python/utils/mp4-dash-encode.py @@ -2,8 +2,11 @@ from optparse import OptionParser from subprocess import check_output, CalledProcessError -from pipes import quote import sys +if not sys.version_info < (3, 13): + from shlex import quote +else: + from pipes import quote import os import os.path as path import json @@ -193,7 +196,7 @@ def main(): #x264_opts = "-x264opts keyint=%d:min-keyint=%d:scenecut=0:rc-lookahead=%d" % (options.segment_size, options.segment_size, options.segment_size) #video_opts = "-g %d" % (options.segment_size) - video_opts = "-force_key_frames 'expr:eq(mod(n,%d),0)'" % (options.segment_size) + video_opts = '-force_key_frames "expr:eq(mod(n,%d),0)"' % (options.segment_size) video_opts += " -bufsize %dk -maxrate %dk" % (bitrates[i], int(bitrates[i]*1.5)) if options.video_codec == 'libx264': video_opts += " -x264opts rc-lookahead=%d" % (options.segment_size) diff --git a/Source/Python/utils/mp4-dash.py b/Source/Python/utils/mp4-dash.py index 70ac4a605..1e70a6e56 100755 --- a/Source/Python/utils/mp4-dash.py +++ b/Source/Python/utils/mp4-dash.py @@ -106,6 +106,8 @@ PRIMETIME_PSSH_SYSTEM_ID = 'f239e769efa348509c16a903c6932efb' PRIMETIME_SCHEME_ID_URI = 'urn:uuid:F239E769-EFA3-4850-9C16-A903C6932EFB' +FAIRPLAY_SCHEME_ID_URI = 'urn:uuid:94ce86fb-07ff-4f43-adb8-93d2fa968ca2' + MPEG_COMMON_ENCRYPTION_SCHEME_ID_URI = 'urn:mpeg:dash:mp4protection:2011' EME_COMMON_ENCRYPTION_PSSH_SYSTEM_ID = '1077efecc0b24d02ace33c1e52e2fb4b' @@ -126,6 +128,8 @@ DASH_DEFAULT_ROLE_NAMESPACE = 'urn:mpeg:dash:role:2011' +SCTE_NAMESPACE = 'urn:scte:dash:scte214-extensions' + DASH_MEDIA_SEGMENT_URL_PATTERN_SMOOTH = "/QualityLevels($Bandwidth$)/Fragments(%s=$Time$)" DASH_MEDIA_SEGMENT_URL_PATTERN_HIPPO = '%s/Bitrate($Bandwidth$)/Fragment($Time$)' @@ -139,6 +143,10 @@ DOLBY_DIGITAL_AUDIO_CHANNEL_CONFIGURATION_SCHEME_ID_URI = 'tag:dolby.com,2014:dash:audio_channel_configuration:2011' DOLBY_AC4_AUDIO_CHANNEL_CONFIGURATION_SCHEME_ID_URI = 'tag:dolby.com,2015:dash:audio_channel_configuration:2015' +MPEG_DASH_MATRIX_COEFFICIENTS_SCHEME_ID_URI = 'urn:mpeg:mpegB:cicp:MatrixCoefficients' +MPEG_DASH_COLOUR_PRIMARIES_SCHEME_ID_URI = 'urn:mpeg:mpegB:cicp:ColourPrimaries' +MPEG_DASH_TRANSFER_CHARACTERISTICS_SCHEME_ID_URI = 'urn:mpeg:mpegB:cicp:TransferCharacteristics' + ISOFF_MAIN_PROFILE = 'urn:mpeg:dash:profile:isoff-main:2011' ISOFF_LIVE_PROFILE = 'urn:mpeg:dash:profile:isoff-live:2011' ISOFF_ON_DEMAND_PROFILE = 'urn:mpeg:dash:profile:isoff-on-demand:2011' @@ -368,6 +376,11 @@ def AddContentProtection(options, container, tracks, all_tracks): pssh = xml.SubElement(cp, '{' + CENC_2013_NAMESPACE + '}pssh') pssh.text = pssh_b64 + # FairPlay + if options.fairplay: + container.append(xml.Comment(' FairPlay ')) + xml.SubElement(container, 'ContentProtection', schemeIdUri=FAIRPLAY_SCHEME_ID_URI) + ############################################# def AddDescriptor(adaptation_set, set_attributes, set_name, category_name): attributes = set_attributes.get(set_name) @@ -462,7 +475,7 @@ def OutputDash(options, set_attributes, audio_sets, video_sets, subtitles_sets, AddDescriptor(adaptation_set, set_attributes, 'video', None) # setup content protection - if options.encryption_key or options.eme_signaling or options.marlin or options.playready or options.widevine or options.clearkey or options.primetime: + if options.encryption_key or options.eme_signaling or options.marlin or options.playready or options.widevine or options.clearkey or options.primetime or options.fairplay: AddContentProtection(options, adaptation_set, video_tracks, all_audio_tracks + all_video_tracks) if options.on_demand: @@ -478,15 +491,50 @@ def OutputDash(options, set_attributes, audio_sets, video_sets, subtitles_sets, AddSegmentTemplate(options, adaptation_set, init_segment_url, media_segment_url_template_prefix, video_tracks[0], 'video') for video_track in video_tracks: - representation = xml.SubElement(adaptation_set, - 'Representation', - id=video_track.representation_id, - codecs=video_track.codec, - width=str(video_track.width), - height=str(video_track.height), - scanType=video_track.scan_type, - frameRate=video_track.frame_rate_ratio, - bandwidth=str(video_track.bandwidth)) + if hasattr(video_track, 'supplemental_codec') and hasattr(video_track, 'supplemental_profile'): + #adding MatrixCoefficients + if hasattr(video_track, 'matrix_coefficients'): + xml.SubElement(adaptation_set, + 'EssentialProperty', + schemeIdUri=MPEG_DASH_MATRIX_COEFFICIENTS_SCHEME_ID_URI, + value=video_track.matrix_coefficients) + + #adding ColourPrimaries + if hasattr(video_track, 'colour_primaries'): + xml.SubElement(adaptation_set, + 'EssentialProperty', + schemeIdUri=MPEG_DASH_COLOUR_PRIMARIES_SCHEME_ID_URI, + value=video_track.colour_primaries) + + #adding TransferCharacteristics + if hasattr(video_track, 'transfer_characteristics'): + xml.SubElement(adaptation_set, + 'EssentialProperty', + schemeIdUri=MPEG_DASH_TRANSFER_CHARACTERISTICS_SCHEME_ID_URI, + value=video_track.transfer_characteristics) + + representation = xml.SubElement(adaptation_set, + 'Representation', + id=video_track.representation_id, + codecs=video_track.codec.split(',')[0], + width=str(video_track.width), + height=str(video_track.height), + scanType=video_track.scan_type, + frameRate=video_track.frame_rate_ratio, + bandwidth=str(video_track.bandwidth)) + xml.register_namespace('scte214', SCTE_NAMESPACE) + representation.set('{'+SCTE_NAMESPACE+'}supplementalCodecs', video_track.supplemental_codec) + representation.set('{'+SCTE_NAMESPACE+'}supplementalProfiles', video_track.supplemental_profile) + else: + representation = xml.SubElement(adaptation_set, + 'Representation', + id=video_track.representation_id, + codecs=video_track.codec, + width=str(video_track.width), + height=str(video_track.height), + scanType=video_track.scan_type, + frameRate=video_track.frame_rate_ratio, + bandwidth=str(video_track.bandwidth)) if hasattr(video_track, 'max_playout_rate'): representation.set('maxPlayoutRate', video_track.max_playout_rate) @@ -519,7 +567,7 @@ def OutputDash(options, set_attributes, audio_sets, video_sets, subtitles_sets, AddDescriptor(adaptation_set, set_attributes, 'audio/' + language, 'audio') # setup content protection - if options.encryption_key or options.eme_signaling or options.marlin or options.playready or options.widevine or options.clearkey or options.primetime: + if options.encryption_key or options.eme_signaling or options.marlin or options.playready or options.widevine or options.clearkey or options.primetime or options.fairplay: AddContentProtection(options, adaptation_set, audio_tracks, all_audio_tracks + all_video_tracks) if options.on_demand: @@ -727,7 +775,7 @@ def OutputHlsCommon(options, track, all_tracks, media_subdir, playlist_name, med init_segment_size = track.parent.init_segment.position + track.parent.init_segment.size playlist_file.write('#EXT-X-MAP:URI="{}",BYTERANGE="{}@0"\n'.format(media_file_name, init_segment_size)) - if options.encryption_key: + if options.encryption_key and track.key_info: key_lines = [] if options.fairplay_key_uri: key_lines.append(ComputeHlsFairplayKeyLine(options)) @@ -1864,6 +1912,8 @@ def main(): "The argument can be either: " + "(1) the character '@' followed by the name of a file containing the Primetime Metadata to use, or " "(2) the character '#' followed by the Primetime Metadata encoded in Base64") + parser.add_option('', "--fairplay", dest="fairplay", action="store_true", default=False, + help="Add FairPlay signaling to the MPD (requires an encrypted input, or the --encryption-key option)") parser.add_option('', "--fairplay-key-uri", dest="fairplay_key_uri", help="Specify the key URI to use for FairPlay Streaming key delivery (only valid with --hls option)") parser.add_option('', "--clearkey", dest="clearkey", action="store_true", @@ -1970,6 +2020,10 @@ def main(): if options.primetime_metadata: options.primetime = True + if options.fairplay: + if options.encryption_key and options.encryption_cenc_scheme != 'cbcs': + raise Exception('--fairplay requires --encryption-cenc-scheme=cbcs') + if options.fairplay_key_uri: if not options.hls: sys.stderr.write('WARNING: --fairplay-key-uri is only valid with --hls, ignoring\n') diff --git a/Source/Python/utils/mp4utils.py b/Source/Python/utils/mp4utils.py index 68c9de297..232e08a77 100644 --- a/Source/Python/utils/mp4utils.py +++ b/Source/Python/utils/mp4utils.py @@ -413,7 +413,7 @@ def __init__(self, parent, info): self.width = sample_desc['width'] self.height = sample_desc['height'] - # add dolby vision signaling if present + # add dolby vision signaling if present; otherwise detect HDR10/HLG if 'dolby_vision' in sample_desc: dv_info = sample_desc['dolby_vision'] if dv_info['profile'] == 5: @@ -427,21 +427,50 @@ def __init__(self, parent, info): brand = 'db1p' if brand in self.parent.info['file']['compatible_brands']: self.dv_brand = brand + else: + print('WARNING: missing brand "db1p" in MP4 file for Dolby Vision Profile 8.1.') + self.supplemental_profile = brand + self.transfer_characteristics = '16' + self.matrix_coefficients = '9' + self.colour_primaries = '9' elif bl_compatibility_id == 2: self.video_range = 'SDR' brand = 'db2g' if brand in self.parent.info['file']['compatible_brands']: self.dv_brand = brand + self.supplemental_profile = brand elif bl_compatibility_id == 4: self.video_range = 'HLG' + self.matrix_coefficients = '9' + self.colour_primaries = '9' if 'db4g' in self.parent.info['file']['compatible_brands']: - self.dv_brand = 'db4g' - elif 'db4h' in self.parent.info['file']['compatible_brands']: - self.dv_brand = 'db4h' + brand = 'db4g' + self.dv_brand = brand + self.supplemental_profile = brand + self.transfer_characteristics = '14' + else: + brand = 'db4h' + self.dv_brand = brand + self.supplemental_profile = brand + self.transfer_characteristics = '18' + if 'db4h' not in self.parent.info['file']['compatible_brands']: + print('WARNING: missing brand "db4g" or "db4h" in MP4 file for Dolby Vision Profile 8.4. Will use "db4h" as default.') else: PrintErrorAndExit('ERROR: unsupported ccid for Dolby Vision profile 8/9.') else: PrintErrorAndExit('ERROR: unsupported Dolby Vision profile.') + elif 'color_info' in sample_desc: + tc = sample_desc['color_info'].get('transfer_characteristics', 1) + if tc == 16: + self.video_range = 'PQ' + elif tc == 18: + self.video_range = 'HLG' + elif 'vpx_info' in sample_desc: + tc = sample_desc['vpx_info'].get('transfer_characteristics', 1) + if tc == 16: + self.video_range = 'PQ' + elif tc == 18: + self.video_range = 'HLG' if self.type == 'audio': self.sample_rate = sample_desc['sample_rate'] @@ -472,7 +501,11 @@ def __init__(self, parent, info): self.dolby_ac4_cbi = 'Yes' self.channels = self.channels + '/IMSA' elif 'mpeg_4_audio_decoder_config' in sample_desc: - self.channels = sample_desc['mpeg_4_audio_decoder_config']['channels'] + adc = sample_desc['mpeg_4_audio_decoder_config'] + self.channels = adc['channels'] + # For HE-AAC/SBR, use the output sample rate signaled in the extension config. + if 'sampling_frequency' in adc: + self.sample_rate = adc['sampling_frequency'] self.language = info['language'] self.language_name = LanguageNames.get(LanguageCodeMap.get(self.language, 'und'), '') @@ -1296,9 +1329,6 @@ def ComputeWidevineHeader(header_spec, encryption_scheme, kid_hex): if 'policy' in fields: protobuf_fields.append((6, fields['policy'])) - if encryption_scheme == 'cenc': - protobuf_fields.append((1, 1)) - four_cc = struct.unpack('>I', encryption_scheme.encode('ascii'))[0] protobuf_fields.append((9, four_cc))