diff options
Diffstat (limited to 'Src/external_dependencies/libmp4v2')
150 files changed, 32656 insertions, 0 deletions
diff --git a/Src/external_dependencies/libmp4v2/3gp.cpp b/Src/external_dependencies/libmp4v2/3gp.cpp new file mode 100644 index 00000000..963de6d7 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/3gp.cpp @@ -0,0 +1,128 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Ximpo Group Ltd. mp4v2@ximpo.com + */ + +#include "mp4common.h" + +#define _3GP_MAJOR_BRAND "3gp5" +#define _3GP_MINOR_VERSION 0x0001 + +void MP4File::Make3GPCompliant(const MP4_FILENAME_CHAR* fileName, char* majorBrand, u_int32_t minorVersion, char** supportedBrands, u_int32_t supportedBrandsCount, bool deleteIodsAtom) +{ + char brand[5] = "3gp5"; + char* _3gpSupportedBrands[1] = { (char*)&brand }; + + if (majorBrand) { + if (!supportedBrands || !supportedBrandsCount) { + throw new MP4Error("Invalid parameters", "MP4File::Make3GPCompliant"); + } + } + + MakeFtypAtom( + majorBrand ? majorBrand : (char*)brand, + majorBrand ? minorVersion : _3GP_MINOR_VERSION, + majorBrand ? supportedBrands : (char**)_3gpSupportedBrands, + majorBrand ? supportedBrandsCount : 1); + + if (deleteIodsAtom) { + // Delete the iods atom, if it exists.... + MP4Atom* iodsAtom = m_pRootAtom->FindAtomMP4("moov.iods"); + if (iodsAtom) { + MP4Atom* moovAtom = m_pRootAtom->FindAtomMP4("moov"); + ASSERT(moovAtom); + + moovAtom->DeleteChildAtom(iodsAtom); + } + } + +} + +void MP4File::MakeFtypAtom(char* majorBrand, u_int32_t minorVersion, char** supportedBrands, u_int32_t supportedBrandsCount) +{ + bool rewriteNeeded = false; + u_int32_t currentSupportedBrandsCount; + u_int32_t i; + + + MP4Atom* ftypAtom = m_pRootAtom->FindAtomMP4("ftyp"); + if (ftypAtom == NULL) { + ftypAtom = InsertChildAtom(m_pRootAtom, "ftyp", 0); + } + if (majorBrand == NULL) + return; + MP4StringProperty* pMajorBrandProperty; + if (!ftypAtom->FindProperty( + "ftyp.majorBrand", + (MP4Property**)&pMajorBrandProperty)) + return; + + pMajorBrandProperty->SetValue(majorBrand); + + + MP4Integer32Property* pMinorVersionProperty; + if (!ftypAtom->FindProperty( + "ftype.minorVersion", + (MP4Property**)&pMinorVersionProperty)) + return; + + pMinorVersionProperty->SetValue(minorVersion); + + MP4Integer32Property* pCompatibleBrandsCountProperty; + if (!ftypAtom->FindProperty( + "ftyp.compatibleBrandsCount", + (MP4Property**)&pCompatibleBrandsCountProperty)) return; + + currentSupportedBrandsCount = pCompatibleBrandsCountProperty->GetValue(); + + MP4TableProperty* pCompatibleBrandsProperty; + if (!ftypAtom->FindProperty( + "ftyp.compatibleBrands", + (MP4Property**)&pCompatibleBrandsProperty)) return; + + MP4StringProperty* pBrandProperty = (MP4StringProperty*) + pCompatibleBrandsProperty->GetProperty(0); + ASSERT(pBrandProperty); + + for (i = 0 ; i < ((currentSupportedBrandsCount > supportedBrandsCount) ? supportedBrandsCount : currentSupportedBrandsCount) ; i++) { + pBrandProperty->SetValue(supportedBrands[i], i); + + } + + if (i < supportedBrandsCount) { + for ( ; i < supportedBrandsCount ; i++) { + pBrandProperty->AddValue(supportedBrands[i]); + } + } + + if (currentSupportedBrandsCount != supportedBrandsCount) { + rewriteNeeded = true; + pBrandProperty->SetCount(supportedBrandsCount); + pCompatibleBrandsCountProperty->SetReadOnly(false); + pCompatibleBrandsCountProperty->SetValue(supportedBrandsCount); + pCompatibleBrandsCountProperty->SetReadOnly(true); + } + +} diff --git a/Src/external_dependencies/libmp4v2/3gpmeta.cpp b/Src/external_dependencies/libmp4v2/3gpmeta.cpp new file mode 100644 index 00000000..a74c59be --- /dev/null +++ b/Src/external_dependencies/libmp4v2/3gpmeta.cpp @@ -0,0 +1,179 @@ +#include "mp4common.h" + +size_t utf16len(const uint16_t *str) +{ + size_t size=0; + while (*str++) size++; + return size; +} + +void utf16swap(uint16_t *str) +{ + while (*str) + { + *str = htons(*str); + str++; + } +} + +bool MP4File::Get3GPMetadataString(const char *atom, uint16_t **value) +{ + char atomstring[60]; + snprintf(atomstring, 60, "moov.udta.%s.metadata", atom); + const uint8_t *str = (const uint8_t *)this->GetStringProperty(atomstring); + + if (str) + { + bool reverse=false; + bool utf16=false; + if ((str[0] == 0xFE && str[1] == 0xFF)) + { + reverse=true; + utf16=true; + } + if ((str[0] == 0xFF && str[1] == 0xFE)) + { + utf16=true; + } + + if (utf16) + { + uint16_t *utf16 = (uint16_t *)str; + size_t len = utf16len(utf16); + *value = (uint16_t *)malloc(len*sizeof(uint16_t)); + if (!*value) + return false; + memcpy(*value, utf16+1, len*sizeof(uint16_t)); + + if (reverse) + utf16swap(*value); + } + else + { + int len = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)str, -1, 0, 0); + *value = (uint16_t *)malloc(len * sizeof(uint16_t)); + if (*value == NULL) + { + return false; + } + MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)str, -1, (LPWSTR)*value, len); + } + + + + return true; + } + return false; +} + + +bool MP4File::Set3GPMetadataString(const char *atom, const uint16_t *value) +{ + char atomstring[60]; + MP4Atom *pMetaAtom; + MP4StringProperty *pMetadataProperty = NULL; + MP4Integer16Property *unknown = NULL; + snprintf(atomstring, 60, "moov.udta.%s", atom); + + pMetaAtom = m_pRootAtom->FindAtomMP4(atomstring); + + if (!pMetaAtom) + { + (void)AddDescendantAtoms("moov", atomstring+5); + + //if (!CreateMetadataAtom(atom)) + //return false; + + pMetaAtom = m_pRootAtom->FindAtomMP4(atomstring); + if (pMetaAtom == NULL) return false; + } + + snprintf(atomstring, 60, "%s.language", atom); + ASSERT(pMetaAtom->FindProperty(atomstring, + (MP4Property**)&unknown)); + ASSERT(unknown); + unknown->SetValue(0x15C7); + + + snprintf(atomstring, 60, "%s.metadata", atom); + ASSERT(pMetaAtom->FindProperty(atomstring, + (MP4Property**)&pMetadataProperty)); + ASSERT(pMetadataProperty); + + pMetadataProperty->SetUnicode(true); + size_t lenWithBOM = utf16len(value) + 1; + uint16_t *newVal = (uint16_t *)malloc((lenWithBOM+1) * sizeof(uint16_t)); + newVal[0]=0xFEFF; + memcpy(newVal+1, value, lenWithBOM*sizeof(uint16_t)); + pMetadataProperty->SetValue((char *)newVal, 0); + free(newVal); + + return true; +} + +bool MP4File::Get3GPMetadataInteger(const char *atom, uint64_t *value) +{ + char atomstring[60]; + snprintf(atomstring, 60, "moov.udta.%s.metadata", atom); + + MP4Property* pProperty; + u_int32_t index; + + FindIntegerProperty(atomstring, &pProperty, &index); + if (pProperty) + { + *value = ((MP4IntegerProperty*)pProperty)->GetValue(index); + return true; + } + return false; +} + +bool MP4File::Set3GPMetadataInteger(const char *atom, uint64_t value) +{ + char atomstring[60] = {0}; + MP4Atom *pMetaAtom; + MP4IntegerProperty *pMetadataProperty = NULL; + snprintf(atomstring, 60, "moov.udta.%s", atom); + + pMetaAtom = m_pRootAtom->FindAtomMP4(atomstring); + + if (!pMetaAtom) + { + (void)AddDescendantAtoms("moov", atomstring+5); + //if (!CreateMetadataAtom(atom)) + //return false; + + pMetaAtom = m_pRootAtom->FindAtomMP4(atomstring); + if (pMetaAtom == NULL) return false; + } + + snprintf(atomstring, 60, "%s.metadata", atom); + ASSERT(pMetaAtom->FindProperty(atomstring, + (MP4Property**)&pMetadataProperty)); + ASSERT(pMetadataProperty); + + pMetadataProperty->SetValue(value, 0); + return true; +} + +bool MP4File::Delete3GPMetadataAtom(const char* name) +{ + MP4Atom *pMetaAtom = NULL; + char s[256]; + + snprintf(s, 256, "moov.udta.%s", name); + pMetaAtom = m_pRootAtom->FindAtomMP4(s); + /* if it exists, delete it */ + if (pMetaAtom) + { + MP4Atom *pParent = pMetaAtom->GetParentAtom(); + + pParent->DeleteChildAtom(pMetaAtom); + + delete pMetaAtom; + + return true; + } + + return false; +}
\ No newline at end of file diff --git a/Src/external_dependencies/libmp4v2/API_CHANGES b/Src/external_dependencies/libmp4v2/API_CHANGES new file mode 100644 index 00000000..f8377bc5 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/API_CHANGES @@ -0,0 +1,124 @@ +Changes in xxxx +--------------- +Change to MP4Create and MP4Modify to allow flags to be set for 64 bit +to allow Quicktime compatibility +Change to MP4CloneTrack and MP4CopyTrack for when you copy a hint +track - you must now specify the track ID in the new file for the +reference track. + +Changes in 0.9.9 +--------------------------- +Added support for ISMA's Ismacrypt specification: + MP4GetTrackEsdsObjectTypeId replaces MP4GetTrackAudioType + and MP4GetTrackVideoType. + MP4EncAndCloneTrack is used instead of MP4CloneTrack to encrypt a track + while cloning it. + MP4EncAndCopyTrack is used instead of MP4CopyTrack to encrypt a track + while copying it. + MP4AddEncAudioTrack adds an encrypted audio track. + MP4AddEncVideoTrack adds an encrypted video track. + + +Changes in 0.9.8 +--------------------------- + MP4WriteSample - changed "uint8_t * data" to "const uint8_t *data" + +Changes from 0.9.6 +--------------------------- +Modified + MP4SetHintTrackRtpPayload + payload parameter to get a dynamic payload is MP4_SET_DYNAMIC_PAYLOAD + (value 0xff) instead of 0. + +Changes from 0.9.5 to 0.9.6 +--------------------------- +Modified + MP4GetHintTrackRtpPayload + MP4SetHintTrackRtpPayload + get/set the encoding params (a=rtpmap <payloadname>/<timescale>[/<encoding params>]) + +Changes from 0.9.4 to 0.9.5 +--------------------------- +Added + MP4GetTrackAudioMpeg4Type() + Returns MPEG-4 Audio type (e.g. AAC, CELP, HXVC, MIDI, etc.) + MP4ReadSampleFromTime() + Variant of MP4ReadSample() that uses time instead of sample id + (basically MP4GetSampleIdFromTime() + MP4ReadSample()) + MP4Info() + MP4FileInfo() + Returns summary info on tracks in file (from util/mp4info.cpp) + + The following functions add support for mp4 authoring/editting: + + MP4CloneTrack() + Make a copy of a specified track, without media samples + MP4CopyTrack() + Make a copy of a specified track, with or without media samples + MP4CopySample() + Make a copy of a specified media sample + + MP4AddTrackEdit() + Add a track edit list element + MP4DeleteTrackEdit() + Delete a track edit list element + MP4GetTrackNumberOfEdits() + Return the number of track edit list elements + MP4GetTrackEditTotalDuration() + Return the total duration of the track edit list + MP4GetTrackEditStart() + Return the edit start time for the edit list element + MP4GetTrackEditMediaStart() + Return the media start time for the edit list element + MP4SetTrackEditMediaStart() + Set the media start time for the edit list element + MP4GetTrackEditDuration() + Return the edit list element duration + MP4SetTrackEditDuration() + Set the edit list element duration + MP4GetTrackEditDwell() + Return the edit list element dwell parameter, see man page + MP4SetTrackEditDwell() + Set the edit list element dwell parameter, see man page + MP4ReadSampleFromEditTime() + Apply the edit list timeline to reading a sample + MP4GetSampleIdFromEditTime() + Return the sample id for a specified time on the edit list timeline + +Modified + MP4GetSampleIdFromTime() + Semantic change - now returns sample id corresponding + to specified time, not the sample id with the smallest positive + start time difference from the specified time. + + +Changes from 0.9.3 to 0.9.4 +--------------------------- +Added + MP4GetTrackVideoFrameRate() + Returns video frame rate (average rate if video is variable rate). + + MP4GetTrackBitRate() + Returns track average bit rate in bits-per-second. + +Changes from 0.9.2 to 0.9.3 +--------------------------- +Modified + MP4Optimize() + Second argument, newFileName, can now be NULL in which case + a temporary file is created for the results of the optimization. + Upon success, the existing file specified with the first argument + is overwritten with the optimized file. + + MP4GetNumberOfTracks() + MP4FindTrackId() + Both have a new optional argument, subType, with default value 0. + The subType can be specified for audio and video tracks to + match only a specific encoding type. See man page for more details. + +Added + MP4GetTrackVideoWidth() + Returns video width in pixels. See man page for caveat. + + MP4GetTrackVideoHeight() + Returns video height in pixels. See man page for caveat. diff --git a/Src/external_dependencies/libmp4v2/INTERNALS b/Src/external_dependencies/libmp4v2/INTERNALS new file mode 100644 index 00000000..5d34de77 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/INTERNALS @@ -0,0 +1,223 @@ +January 7, 2002 + +MP4V2 LIBRARY INTERNALS +======================= + +This document provides an overview of the internals of the mp4v2 library +to aid those who wish to modify and extend it. Before reading this document, +I recommend familiarizing yourself with the MP4 (or Quicktime) file format +standard and the mp4v2 library API. The API is described in a set of man pages +in mpeg4ip/doc/mp4v2, or if you prefer by looking at mp4.h. + +All the library code is written in C++, however the library API follows uses +C calling conventions hence is linkable by both C and C++ programs. The +library has been compiled and used on Linux, BSD, Windows, and Mac OS X. +Other than libc, the library has no external dependencies, and hence can +be used independently of the mpeg4ip package if desired. The library is +used for both real-time recording and playback in mpeg4ip, and its runtime +performance is up to those tasks. On the IA32 architecture compiled with gcc, +the stripped library is approximately 600 KB code and initialized data. + +It is useful to think of the mp4v2 library as consisting of four layers: +infrastructure, file format, generic tracks, and type specific track helpers. +A description of each layer follows, from the fundamental to the optional. + + +Infrastructure +============== + +The infrastructure layer provides basic file I/O, memory allocation, +error handling, string utilities, and protected arrays. The source files +for this layer are mp4file_io, mp4util, and mp4array. + +Note that the array classes uses preprocessor macros instead of C++ +templates. The rationale for this is to increase portability given the +sometimes incomplete support by some compilers for templates. + + +File Format +=========== + +The file format layer provides the translation from the on-disk MP4 file +format to in-memory C++ structures and back to disk. It is intended +to exactly match the MP4 specification in syntax and semantics. It +represents the majority of the code. + +There are three key structures at the file format layer: atoms, properties, +and descriptors. + +Atoms are the primary containers within an mp4 file. They can contain +any combination of properties, other atoms, or descriptors. + +The mp4atom files contain the base class for all the atoms, and provide +generic functions that cover most cases. Most atoms are covered in +atom_standard.cpp. Atoms that have a special read, generation or +write needs are contained in their subclass contained in file atom_<name>.cpp, + where <name> is the four letter name of the atom defined in the MP4 +specification. + +Atoms that only specifies the properties of the atom or the possible child +atoms in the case of a container atom are located in atom_standard.cpp. + +In more specialized cases the atom specific file provides routines to +initialize, read, or write the atom. + +Properties are the atomic pieces of information. The basic types of +properties are integers, floats, strings, and byte arrays. For integers +and floats there are subclasses that represent the different storage sizes, +e.g. 8, 16, 24, 32, and 64 bit integers. For strings, there is 1 property +class with a number of options regarding exact storage details, e.g. null +terminated, fixed length, counted. + +For implementation reasons, there are also two special properties, table +and descriptor, that are actually containers for groups of properties. +I.e by making these containers provide a property interface much code can +be written in a generic fashion. + +The mp4property files contain all the property related classes. + +Descriptors are containers that derive from the MPEG conventions and use +different encoding rules than the atoms derived from the QuickTime file +format. This means more use of bitfields and conditional existence with +an emphasis on bit efficiency at the cost of encoding/decoding complexity. +Descriptors can contain other descriptors and/or properties. + +The mp4descriptor files contain the generic base class for descriptors. +Also the mp4property files have a descriptor wrapper class that allows a +descriptor to behave as if it were a property. The specific descriptors +are implemented as subclasses of the base class descriptor in manner similar +to that of atoms. The descriptors, ocidescriptors, and qosqualifiers files +contain these implementations. + +Each atom/property/descriptor has a name closely related to that in the +MP4 specification. The difference being that the mp4v2 library doesn't +use '-' or '_' in property names and capitalizes the first letter of each +word, e.g. "thisIsAPropertyName". A complete name specifies the complete +container path. The names follow the C/C++ syntax for elements and array +indices. + +Examples are: + "moov.mvhd.duration" + "moov.trak[2].tkhd.duration" + "moov.trak[3].minf.mdia.stbl.stsz[101].sampleSize" + +Note "*" can be used as a wildcard for an atom name (only). This is most +useful when dealing with the stsd atom which contains child atoms with +various names, but shared property names. + +Note that internally when performance matters the code looks up a property +by name once, and then stores the returned pointer to the property class. + +To add an atom, first you should see if an existing atom exists that +can be used. If not, you need to decide if special read/write or +generate properties need to be established; for example a property in the atom +changes other properties (adds, or subtracts). If there are no +special cases, add the atom properties to atom_standard.cpp. If there +are special properties, add a new file, add a new class to atoms.h, and +add the class to MP4Atom::CreateAtom in mp4atom.cpp. + + + +Generic Tracks +============== + +The two entities at this level are the mp4 file as a whole and the tracks +which are contained with it. The mp4file and mp4track files contain the +implementation. + +The critical work done by this layer is to map the collection of atoms, +properties, and descriptors that represent a media track into a useful, +and consistent set of operations. For example, reading or writing a media +sample of a track is a relatively simple operation from the library API +perspective. However there are numerous pieces of information in the mp4 +file that need to be properly used and updated to do this. This layer +handles all those details. + +Given familiarity with the mp4 spec, the code should be straight-forward. +What may not be immediately obvious are the functions to handle chunks of +media samples. These exist to allow optimization of the mp4 file layout by +reordering the chunks on disk to interleave the media sample chunks of +multiple tracks in time order. (See MP4Optimize API doc). + + +Type Specific Track Helpers +=========================== + +This specialized code goes beyond the meta-information about tracks in +the mp4 file to understanding and manipulating the information in the +track samples. There are currently two helpers in the library: +the MPEG-4 Systems Helper, and the RTP Hint Track Helper. + +The MPEG-4 Systems Helper is currently limited to creating the OD, BIFS, +and SDP information about a minimal audio/video scene consistent with +the Internet Streaming Media Alliance (ISMA) specifications. We will be +evaluating how best to generalize the library's helper functions for +MPEG-4 Systems without overburdening the implementation. The code for +this helper is found in the isma and odcommands files. + +The RTP Hint Track Helper is more extensive in its support. The hint +tracks contain the track packetization information needed to build +RTP packets for streaming. The library can construct RTP packets based +on the hint track making RTP based servers significantly easier to write. + +All code related to rtp hint tracks is in the rtphint files. It would also +be useful to look at test/mp4broadcaster and mpeg4ip/server/mp4creator for +examples of how this part of the library API can be used. + + +Library API +=========== + +The library API is defined and implemented in the mp4 files. The API uses +C linkage conventions, and the mp4.h file adapts itself according to whether +C or C++ is the compilation mode. + +All API calls are implemented in mp4.cpp and basically pass thru's to the +MP4File member functions. This ensures that the library has internal access +to the same functions as available via the API. All the calls in mp4.cpp use +C++ try/catch blocks to protect against any runtime errors in the library. +Upon error the library will print a diagnostic message if the verbostiy level +has MP4_DETAILS_ERROR set, and return a distinguished error value, typically +0 or -1. + +The test and util subdirectories contain useful examples of how to +use the library. Also the mp4creator and mp4live programs within +mpeg4ip demonstrate more complete usage of the library API. + + +Debugging +========= + +Since mp4 files are fairly complicated, extensive debugging support is +built into the library. Multi-level diagnostic messages are available +under the control of a verbosity bitmask described in the API. + +Also the library provides the MP4Dump() call which provides an ASCII +version of the mp4 file meta-information. The mp4dump utilitity is a +wrapper executable around this function. + +The mp4extract program is also provided in the utilities directory +which is useful for extracting a track from an mp4file and putting the +media data back into it's own file. It can also extract each sample of +a track into its own file it that is desired. + +When all else fails, mp4 files are amenable to debugging by direct +examination. Since the atom names are four letter ASCII codes finding +reference points in a hex dump is feasible. On UNIX, the od command +is your friend: "od -t x1z -A x [-j 0xXXXXXX] foo.mp4" will print +a hex and ASCII dump, with hex addresses, starting optionally from +a specified offset. The library diagnostic messages can provide +information on where the library is reading or writing. + + +General caveats +=============== + +The coding convention is to use the C++ throw operator whenever an +unrecoverable error occurs. This throw is caught at the API layer +in mp4.cpp and translated into an error value. + +Be careful about indices. Internally, we follow the C/C++ convention +to use zero-based indices. However the MP4 spec uses one-based indices +for things like samples and hence the library API uses this convention. + diff --git a/Src/external_dependencies/libmp4v2/Makefile.am b/Src/external_dependencies/libmp4v2/Makefile.am new file mode 100644 index 00000000..9de4c1c1 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/Makefile.am @@ -0,0 +1,97 @@ +SUBDIRS = . test util + +INCLUDES = -I$(top_srcdir)/include + +AM_CXXFLAGS = @BILLS_CPPWARNINGS@ + +lib_LTLIBRARIES = libmp4v2.la + +include_HEADERS = mp4.h + +libmp4v2_la_SOURCES = \ + 3gp.cpp \ + atom_amr.cpp \ + atom_avc1.cpp \ + atom_avcC.cpp \ + atom_d263.cpp \ + atom_damr.cpp \ + atom_dref.cpp \ + atom_elst.cpp \ + atom_enca.cpp \ + atom_encv.cpp \ + atom_free.cpp \ + atom_ftyp.cpp \ + atom_gmin.cpp \ + atom_hdlr.cpp \ + atom_hinf.cpp \ + atom_hnti.cpp \ + atom_href.cpp \ + atom_mdat.cpp \ + atom_mdhd.cpp \ + atom_meta.cpp \ + atom_mp4s.cpp \ + atom_mp4v.cpp \ + atom_mvhd.cpp \ + atom_ohdr.cpp \ + atom_root.cpp \ + atom_rtp.cpp \ + atom_s263.cpp \ + atom_sdp.cpp \ + atoms.h \ + atom_smi.cpp \ + atom_sound.cpp \ + atom_standard.cpp \ + atom_stbl.cpp \ + atom_stdp.cpp \ + atom_stsc.cpp \ + atom_stsd.cpp \ + atom_stsz.cpp \ + atom_stz2.cpp \ + atom_text.cpp \ + atom_tfhd.cpp \ + atom_tkhd.cpp \ + atom_treftype.cpp \ + atom_trun.cpp \ + atom_udta.cpp \ + atom_url.cpp \ + atom_urn.cpp \ + atom_video.cpp \ + atom_vmhd.cpp \ + descriptors.cpp \ + descriptors.h \ + isma.cpp \ + mp4array.h \ + mp4atom.cpp \ + mp4atom.h \ + mp4common.h \ + mp4container.cpp \ + mp4container.h \ + mp4.cpp \ + mp4descriptor.cpp \ + mp4descriptor.h \ + mp4file.cpp \ + mp4file.h \ + mp4file_io.cpp \ + mp4info.cpp \ + mp4meta.cpp \ + mp4property.cpp \ + mp4property.h \ + mp4track.cpp \ + mp4track.h \ + mp4util.cpp \ + mp4util.h \ + ocidescriptors.cpp \ + ocidescriptors.h \ + odcommands.cpp \ + odcommands.h \ + qosqualifiers.cpp \ + qosqualifiers.h \ + rtphint.cpp \ + rtphint.h \ + virtual_io.cpp \ + virtual_io.h + +EXTRA_DIST = API_CHANGES \ + INTERNALS \ + libmp4v260.dsp \ + TODO diff --git a/Src/external_dependencies/libmp4v2/Makefile.in b/Src/external_dependencies/libmp4v2/Makefile.in new file mode 100644 index 00000000..5f0624ad --- /dev/null +++ b/Src/external_dependencies/libmp4v2/Makefile.in @@ -0,0 +1,833 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = lib/mp4v2 +DIST_COMMON = README $(include_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in TODO +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/mpeg4ip_config.h +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)" +libLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(lib_LTLIBRARIES) +libmp4v2_la_LIBADD = +am_libmp4v2_la_OBJECTS = 3gp.lo atom_amr.lo atom_avc1.lo atom_avcC.lo \ + atom_d263.lo atom_damr.lo atom_dref.lo atom_elst.lo \ + atom_enca.lo atom_encv.lo atom_free.lo atom_ftyp.lo \ + atom_hdlr.lo atom_hinf.lo atom_hnti.lo atom_href.lo \ + atom_mdat.lo atom_mdhd.lo atom_meta.lo atom_mp4s.lo \ + atom_mp4v.lo atom_mvhd.lo atom_ohdr.lo atom_root.lo \ + atom_rtp.lo atom_s263.lo atom_sdp.lo atom_smi.lo atom_sound.lo \ + atom_standard.lo atom_stbl.lo atom_stdp.lo atom_stsc.lo \ + atom_stsd.lo atom_stsz.lo atom_tfhd.lo atom_tkhd.lo \ + atom_treftype.lo atom_trun.lo atom_udta.lo atom_url.lo \ + atom_urn.lo atom_video.lo atom_vmhd.lo descriptors.lo isma.lo \ + mp4atom.lo mp4container.lo mp4.lo mp4descriptor.lo mp4file.lo \ + mp4file_io.lo mp4info.lo mp4meta.lo mp4property.lo mp4track.lo \ + mp4util.lo ocidescriptors.lo odcommands.lo qosqualifiers.lo \ + rtphint.lo +libmp4v2_la_OBJECTS = $(am_libmp4v2_la_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libmp4v2_la_SOURCES) +DIST_SOURCES = $(libmp4v2_la_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-exec-recursive install-info-recursive \ + install-recursive installcheck-recursive installdirs-recursive \ + pdf-recursive ps-recursive uninstall-info-recursive \ + uninstall-recursive +includeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(include_HEADERS) +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +ALIGN_FUNCS = @ALIGN_FUNCS@ +ALIGN_JUMPS = @ALIGN_JUMPS@ +ALIGN_LOOPS = @ALIGN_LOOPS@ +ALSA_CFLAGS = @ALSA_CFLAGS@ +ALSA_LIBS = @ALSA_LIBS@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +ASFLAGS = @ASFLAGS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BILLS_CPPWARNINGS = @BILLS_CPPWARNINGS@ +BILLS_CWARNINGS = @BILLS_CWARNINGS@ +CC = @CC@ +CCAS = @CCAS@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FAAC_LIB = @FAAC_LIB@ +FFLAGS = @FFLAGS@ +FFMPEG_INC = @FFMPEG_INC@ +FFMPEG_LIB = @FFMPEG_LIB@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ +GLIB_LIBS = @GLIB_LIBS@ +GLIB_MKENUMS = @GLIB_MKENUMS@ +GOBJECT_QUERY = @GOBJECT_QUERY@ +GTK_CFLAGS = @GTK_CFLAGS@ +GTK_LIBS = @GTK_LIBS@ +HAVE_A52DEC_LIB_FALSE = @HAVE_A52DEC_LIB_FALSE@ +HAVE_A52DEC_LIB_TRUE = @HAVE_A52DEC_LIB_TRUE@ +HAVE_ALIGN_FUNCS_FALSE = @HAVE_ALIGN_FUNCS_FALSE@ +HAVE_ALIGN_FUNCS_TRUE = @HAVE_ALIGN_FUNCS_TRUE@ +HAVE_ALIGN_JUMPS_FALSE = @HAVE_ALIGN_JUMPS_FALSE@ +HAVE_ALIGN_JUMPS_TRUE = @HAVE_ALIGN_JUMPS_TRUE@ +HAVE_ALIGN_LOOPS_FALSE = @HAVE_ALIGN_LOOPS_FALSE@ +HAVE_ALIGN_LOOPS_TRUE = @HAVE_ALIGN_LOOPS_TRUE@ +HAVE_FFMPEG_FALSE = @HAVE_FFMPEG_FALSE@ +HAVE_FFMPEG_TRUE = @HAVE_FFMPEG_TRUE@ +HAVE_ID3_TAG_FALSE = @HAVE_ID3_TAG_FALSE@ +HAVE_ID3_TAG_TRUE = @HAVE_ID3_TAG_TRUE@ +HAVE_LIBMAD_FALSE = @HAVE_LIBMAD_FALSE@ +HAVE_LIBMAD_TRUE = @HAVE_LIBMAD_TRUE@ +HAVE_LIBMPEG2_FALSE = @HAVE_LIBMPEG2_FALSE@ +HAVE_LIBMPEG2_TRUE = @HAVE_LIBMPEG2_TRUE@ +HAVE_MAC_OSX_FALSE = @HAVE_MAC_OSX_FALSE@ +HAVE_MAC_OSX_TRUE = @HAVE_MAC_OSX_TRUE@ +HAVE_X264_FALSE = @HAVE_X264_FALSE@ +HAVE_X264_TRUE = @HAVE_X264_TRUE@ +HAVE_XVID_1_0_FALSE = @HAVE_XVID_1_0_FALSE@ +HAVE_XVID_1_0_TRUE = @HAVE_XVID_1_0_TRUE@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LAME_LIB = @LAME_LIB@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_C_TAG = @LIBTOOL_C_TAG@ +LIBVORBIS_LIB = @LIBVORBIS_LIB@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MP4LIVE_FALSE = @MP4LIVE_FALSE@ +MP4LIVE_TRUE = @MP4LIVE_TRUE@ +NASM = @NASM@ +NASMFLAGS = @NASMFLAGS@ +NO_GLIB_GTK_FALSE = @NO_GLIB_GTK_FALSE@ +NO_GLIB_GTK_TRUE = @NO_GLIB_GTK_TRUE@ +NO_XVID_FALSE = @NO_XVID_FALSE@ +NO_XVID_TRUE = @NO_XVID_TRUE@ +OBJC = @OBJC@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PLAYER_FALSE = @PLAYER_FALSE@ +PLAYER_PLUGIN_DIR = @PLAYER_PLUGIN_DIR@ +PLAYER_TRUE = @PLAYER_TRUE@ +RANLIB = @RANLIB@ +SDL_LIBS = @SDL_LIBS@ +SDL_LIB_LIBS = @SDL_LIB_LIBS@ +SERVER_FALSE = @SERVER_FALSE@ +SERVER_TRUE = @SERVER_TRUE@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SRTPLIB = @SRTPLIB@ +STRIP = @STRIP@ +SUN_LIBS = @SUN_LIBS@ +USENASM = @USENASM@ +USE_MMX_FALSE = @USE_MMX_FALSE@ +USE_MMX_TRUE = @USE_MMX_TRUE@ +USE_PPC_FALSE = @USE_PPC_FALSE@ +USE_PPC_TRUE = @USE_PPC_TRUE@ +VERSION = @VERSION@ +X264_LIB = @X264_LIB@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +SUBDIRS = . test util +INCLUDES = -I$(top_srcdir)/include +AM_CXXFLAGS = @BILLS_CPPWARNINGS@ +lib_LTLIBRARIES = libmp4v2.la +include_HEADERS = mp4.h +libmp4v2_la_SOURCES = \ + 3gp.cpp \ + atom_amr.cpp \ + atom_avc1.cpp \ + atom_avcC.cpp \ + atom_d263.cpp \ + atom_damr.cpp \ + atom_dref.cpp \ + atom_elst.cpp \ + atom_enca.cpp \ + atom_encv.cpp \ + atom_free.cpp \ + atom_ftyp.cpp \ + atom_hdlr.cpp \ + atom_hinf.cpp \ + atom_hnti.cpp \ + atom_href.cpp \ + atom_mdat.cpp \ + atom_mdhd.cpp \ + atom_meta.cpp \ + atom_mp4s.cpp \ + atom_mp4v.cpp \ + atom_mvhd.cpp \ + atom_ohdr.cpp \ + atom_root.cpp \ + atom_rtp.cpp \ + atom_s263.cpp \ + atom_sdp.cpp \ + atoms.h \ + atom_smi.cpp \ + atom_sound.cpp \ + atom_standard.cpp \ + atom_stbl.cpp \ + atom_stdp.cpp \ + atom_stsc.cpp \ + atom_stsd.cpp \ + atom_stsz.cpp \ + atom_tfhd.cpp \ + atom_tkhd.cpp \ + atom_treftype.cpp \ + atom_trun.cpp \ + atom_udta.cpp \ + atom_url.cpp \ + atom_urn.cpp \ + atom_video.cpp \ + atom_vmhd.cpp \ + descriptors.cpp \ + descriptors.h \ + isma.cpp \ + mp4array.h \ + mp4atom.cpp \ + mp4atom.h \ + mp4common.h \ + mp4container.cpp \ + mp4container.h \ + mp4.cpp \ + mp4descriptor.cpp \ + mp4descriptor.h \ + mp4file.cpp \ + mp4file.h \ + mp4file_io.cpp \ + mp4info.cpp \ + mp4meta.cpp \ + mp4property.cpp \ + mp4property.h \ + mp4track.cpp \ + mp4track.h \ + mp4util.cpp \ + mp4util.h \ + ocidescriptors.cpp \ + ocidescriptors.h \ + odcommands.cpp \ + odcommands.h \ + qosqualifiers.cpp \ + qosqualifiers.h \ + rtphint.cpp \ + rtphint.h + +EXTRA_DIST = API_CHANGES \ + INTERNALS \ + libmp4v260.dsp \ + TODO + +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/mp4v2/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/mp4v2/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ + else :; fi; \ + done + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ + $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libmp4v2.la: $(libmp4v2_la_OBJECTS) $(libmp4v2_la_DEPENDENCIES) + $(CXXLINK) -rpath $(libdir) $(libmp4v2_la_LDFLAGS) $(libmp4v2_la_OBJECTS) $(libmp4v2_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3gp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_amr.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_avc1.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_avcC.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_d263.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_damr.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_dref.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_elst.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_enca.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_encv.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_free.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_ftyp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_hdlr.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_hinf.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_hnti.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_href.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_mdat.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_mdhd.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_meta.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_mp4s.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_mp4v.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_mvhd.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_ohdr.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_root.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_rtp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_s263.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_sdp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_smi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_sound.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_standard.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_stbl.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_stdp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_stsc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_stsd.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_stsz.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_tfhd.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_tkhd.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_treftype.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_trun.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_udta.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_url.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_urn.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_video.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom_vmhd.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/descriptors.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isma.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mp4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mp4atom.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mp4container.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mp4descriptor.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mp4file.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mp4file_io.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mp4info.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mp4meta.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mp4property.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mp4track.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mp4util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ocidescriptors.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/odcommands.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qosqualifiers.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtphint.Plo@am__quote@ + +.cpp.o: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cpp.lo: +@am__fastdepCXX_TRUE@ if $(LTCXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: +install-includeHEADERS: $(include_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(includedir)" || $(mkdir_p) "$(DESTDIR)$(includedir)" + @list='$(include_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(includeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(includedir)/$$f'"; \ + $(includeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(includedir)/$$f"; \ + done + +uninstall-includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(include_HEADERS)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(includedir)/$$f'"; \ + rm -f "$(DESTDIR)$(includedir)/$$f"; \ + done + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(mkdir_p) "$(distdir)/$$subdir" \ + || exit 1; \ + distdir=`$(am__cd) $(distdir) && pwd`; \ + top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$top_distdir" \ + distdir="$$distdir/$$subdir" \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-libtool distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +info: info-recursive + +info-am: + +install-data-am: install-includeHEADERS + +install-exec-am: install-libLTLIBRARIES + +install-info: install-info-recursive + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-includeHEADERS uninstall-info-am \ + uninstall-libLTLIBRARIES + +uninstall-info: uninstall-info-recursive + +.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am \ + clean clean-generic clean-libLTLIBRARIES clean-libtool \ + clean-recursive ctags ctags-recursive distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-recursive distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am \ + install-includeHEADERS install-info install-info-am \ + install-libLTLIBRARIES install-man install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic maintainer-clean-recursive \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool mostlyclean-recursive pdf pdf-am ps ps-am \ + tags tags-recursive uninstall uninstall-am \ + uninstall-includeHEADERS uninstall-info-am \ + uninstall-libLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/Src/external_dependencies/libmp4v2/README b/Src/external_dependencies/libmp4v2/README new file mode 100644 index 00000000..c8094ac6 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/README @@ -0,0 +1,28 @@ +July 18, 2002 + +MP4V2 Library +============= + +This library provides functions to read, create, and modify mp4 files. + +The detailed documentation of the library is available as a set of man pages +in mpeg4ip/doc/mp4v2. The MP4.3 man page gives an overview of the library. + +Alternately mp4.h in this directory specifies the complete API. + +The file INTERNALS provides an overview of what is happening behind the API. +Note that although we using C++ object oriented features internally, that's +all hidden behind a flat C style API (with C linkage conventions). + +The test and util subdirectories contain some simple programs that use +this library. + +Once make install is run, to use this library, you should: +To use this library in your application, it should be sufficient to: + +1) add the installed library to your final link: + e.g. gcc ... -o foo foo.cpp -lmp4v2 + +2) include mp4.h into your code, + e.g. #include <mp4.h> + diff --git a/Src/external_dependencies/libmp4v2/atom_alac.cpp b/Src/external_dependencies/libmp4v2/atom_alac.cpp new file mode 100644 index 00000000..642f050c --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_alac.cpp @@ -0,0 +1,61 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4AlacAtom::MP4AlacAtom() + : MP4Atom("alac") +{ + AddReserved("reserved1", 6); /* 0 */ + + AddProperty( /* 1 */ + new MP4Integer16Property("dataReferenceIndex")); + + AddReserved("reserved2", 16); /* 2 */ + + AddProperty( /* 3 */ + new MP4Integer16Property("timeScale")); + + AddReserved("reserved3", 2); /* 4 */ + + AddProperty( + new MP4BytesProperty("alacInfo", 36)); /* 5 */ + //ExpectChildAtom("alac", Required, OnlyOne); +} + +void MP4AlacAtom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); + + // property reserved2 has non-zero fixed values + static u_int8_t reserved2[16] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, + }; + m_pProperties[2]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[2])-> + SetValue(reserved2, sizeof(reserved2)); + m_pProperties[2]->SetReadOnly(true); +} diff --git a/Src/external_dependencies/libmp4v2/atom_amr.cpp b/Src/external_dependencies/libmp4v2/atom_amr.cpp new file mode 100644 index 00000000..db474202 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_amr.cpp @@ -0,0 +1,65 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Ximpo Group Ltd. mp4v2@ximpo.com + */ + +#include "mp4common.h" + +MP4AmrAtom::MP4AmrAtom(const char *type) + : MP4Atom(type) +{ + AddReserved("reserved1", 6); /* 0 */ + + AddProperty( /* 1 */ + new MP4Integer16Property("dataReferenceIndex")); + + AddReserved("reserved2", 16); /* 2 */ + + AddProperty( /* 3 */ + new MP4Integer16Property("timeScale")); + + AddReserved("reserved3", 2); /* 4 */ + + ExpectChildAtom("damr", Required, OnlyOne); +} + +void MP4AmrAtom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); + + // property reserved2 has non-zero fixed values + static u_int8_t reserved2[16] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, + }; + m_pProperties[2]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[2])-> + SetValue(reserved2, sizeof(reserved2)); + m_pProperties[2]->SetReadOnly(true); +} diff --git a/Src/external_dependencies/libmp4v2/atom_avc1.cpp b/Src/external_dependencies/libmp4v2/atom_avc1.cpp new file mode 100644 index 00000000..d696f989 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_avc1.cpp @@ -0,0 +1,81 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2004. All Rights Reserved. + * + * Contributor(s): + * Bill May wmay@cisco.com + */ + +#include "mp4common.h" + +MP4Avc1Atom::MP4Avc1Atom() + : MP4Atom("avc1") +{ + AddReserved("reserved1", 6); /* 0 */ + + AddProperty( /* 1 */ + new MP4Integer16Property("dataReferenceIndex")); + + AddReserved("reserved2", 16); /* 2 */ + + AddProperty( /* 3 */ + new MP4Integer16Property("width")); + AddProperty( /* 4 */ + new MP4Integer16Property("height")); + + AddReserved("reserved3", 14); /* 5 */ + + MP4StringProperty* pProp = + new MP4StringProperty("compressorName"); + pProp->SetFixedLength(32); + pProp->SetValue("AVC Coding"); + AddProperty(pProp); /* 6 */ + + AddReserved("reserved4", 4); /* 7 */ + + ExpectChildAtom("avcC", Required, OnlyOne); + ExpectChildAtom("btrt", Optional, OnlyOne); + // for now ExpectChildAtom("m4ds", Optional, OnlyOne); +} + +void MP4Avc1Atom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); + + // property reserved3 has non-zero fixed values + static u_int8_t reserved3[14] = { + 0x00, 0x48, 0x00, 0x00, + 0x00, 0x48, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + }; + m_pProperties[5]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[5])-> + SetValue(reserved3, sizeof(reserved3)); + m_pProperties[5]->SetReadOnly(true); + + // property reserved4 has non-zero fixed values + static u_int8_t reserved4[4] = { + 0x00, 0x18, 0xFF, 0xFF, + }; + m_pProperties[7]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[7])-> + SetValue(reserved4, sizeof(reserved4)); + m_pProperties[7]->SetReadOnly(true); +} + diff --git a/Src/external_dependencies/libmp4v2/atom_avcC.cpp b/Src/external_dependencies/libmp4v2/atom_avcC.cpp new file mode 100644 index 00000000..f62368ce --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_avcC.cpp @@ -0,0 +1,261 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2004. All Rights Reserved. + * + * Contributor(s): + * Bill May wmay@cisco.com + */ + +#include "mp4common.h" + +/* + * SizeTableProperty is a special version of the MP4TableProperty - + * the BytesProperty will need to set the value before it can read + * from the file + */ +class SizeTableProperty : public MP4TableProperty +{ + public: + SizeTableProperty(char *name, MP4IntegerProperty *pCountProperty) : + MP4TableProperty(name, pCountProperty) {}; + protected: + void ReadEntry(MP4File *pFile, u_int32_t index) { + // Each table has a size, followed by the length field + // first, read the length + m_pProperties[0]->Read(pFile, index); + MP4IntegerProperty *pIntProp = (MP4IntegerProperty *)m_pProperties[0]; + // set the size in the bytes property + MP4BytesProperty *pBytesProp = (MP4BytesProperty *)m_pProperties[1]; + pBytesProp->SetValueSize(pIntProp->GetValue(index), index); + // And read the bytes + m_pProperties[1]->Read(pFile, index); + }; +}; + +MP4AvcCAtom::MP4AvcCAtom() + : MP4Atom("avcC") +{ + MP4BitfieldProperty *pCount; + MP4TableProperty *pTable; + + AddProperty( new MP4Integer8Property("configurationVersion")); /* 0 */ + + AddProperty( new MP4Integer8Property("AVCProfileIndication")); /* 1 */ + + AddProperty( new MP4Integer8Property("profile_compatibility")); /* 2 */ + + AddProperty( new MP4Integer8Property("AVCLevelIndication")); /* 3 */ + + AddProperty( new MP4BitfieldProperty("reserved", 6)); /* 4 */ + AddProperty( new MP4BitfieldProperty("lengthSizeMinusOne", 2)); /* 5 */ + AddProperty( new MP4BitfieldProperty("reserved1", 3)); /* 6 */ + pCount = new MP4BitfieldProperty("numOfSequenceParameterSets", 5); + AddProperty(pCount); /* 7 */ + + pTable = new SizeTableProperty("sequenceEntries", pCount); + AddProperty(pTable); /* 8 */ + pTable->AddProperty(new MP4Integer16Property("sequenceParameterSetLength")); + pTable->AddProperty(new MP4BytesProperty("sequenceParameterSetNALUnit")); + + MP4Integer8Property *pCount2 = new MP4Integer8Property("numOfPictureParameterSets"); + AddProperty(pCount2); /* 9 */ + + pTable = new SizeTableProperty("pictureEntries", pCount2); + AddProperty(pTable); /* 10 */ + pTable->AddProperty(new MP4Integer16Property("pictureParameterSetLength")); + pTable->AddProperty(new MP4BytesProperty("pictureParameterSetNALUnit")); +} + +void MP4AvcCAtom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer8Property*)m_pProperties[0])->SetValue(1); + + m_pProperties[4]->SetReadOnly(false); + ((MP4BitfieldProperty*)m_pProperties[4])->SetValue(0x3f); + m_pProperties[4]->SetReadOnly(true); + + m_pProperties[6]->SetReadOnly(false); + ((MP4BitfieldProperty*)m_pProperties[6])->SetValue(0x7); + m_pProperties[6]->SetReadOnly(true); +#if 0 + // property reserved4 has non-zero fixed values + static u_int8_t reserved4[4] = { + 0x00, 0x18, 0xFF, 0xFF, + }; + m_pProperties[7]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[7])-> + SetValue(reserved4, sizeof(reserved4)); + m_pProperties[7]->SetReadOnly(true); +#endif +} + +// +// Clone - clone my properties to destination atom +// +// this method simplifies duplicating avcC atom properties from +// source to destination file using a single API rather than +// having to copy each property. This API encapsulates the object +// so the application layer need not concern with each property +// thereby isolating any future changes to atom properties. +// +// ---------------------------------------- +// property description +// ---------------------------------------- +// +// 0 configurationVersion +// 1 AVCProfileIndication +// 2 profile_compatibility +// 3 AVCLevelIndication +// 4 reserved +// 5 lengthSizeMinusOne +// 6 reserved +// 7 number of SPS +// 8 SPS entries +// 9 number of PPS +// 10 PPS entries +// +// +void MP4AvcCAtom::Clone(MP4AvcCAtom *dstAtom) +{ + + MP4Property *dstProperty; + MP4TableProperty *pTable; + u_int16_t i16; + u_int64_t i32; + u_int64_t i64; + u_int8_t *tmp; + + // source pointer Property I16 + MP4Integer16Property *spPI16; + // source pointer Property Bytes + MP4BytesProperty *spPB; + + // dest pointer Property I16 + MP4Integer16Property *dpPI16; + // dest pointer Property Bytes + MP4BytesProperty *dpPB; + + + // start with defaults and reserved fields + dstAtom->Generate(); + + // 0, 4, 6 are now generated from defaults + // leaving 1, 2, 3, 5, 7, 8, 9, 10 to export + + dstProperty=dstAtom->GetProperty(1); + ((MP4Integer8Property *)dstProperty)->SetValue( + ((MP4Integer8Property *)m_pProperties[1])->GetValue()); + + dstProperty=dstAtom->GetProperty(2); + ((MP4Integer8Property *)dstProperty)->SetValue( + ((MP4Integer8Property *)m_pProperties[2])->GetValue()); + + dstProperty=dstAtom->GetProperty(3); + ((MP4Integer8Property *)dstProperty)->SetValue( + ((MP4Integer8Property *)m_pProperties[3])->GetValue()); + + dstProperty=dstAtom->GetProperty(5); + ((MP4BitfieldProperty *)dstProperty)->SetValue( + ((MP4BitfieldProperty *)m_pProperties[5])->GetValue()); + + // + // 7 and 8 are related SPS (one set of sequence parameters) + // + // first the count bitfield + // + dstProperty=dstAtom->GetProperty(7); + dstProperty->SetReadOnly(false); + ((MP4BitfieldProperty *)dstProperty)->SetValue( + ((MP4BitfieldProperty *)m_pProperties[7])->GetValue()); + dstProperty->SetReadOnly(true); + + // next export SPS Length and NAL bytes */ + + // first source pointers + pTable = (MP4TableProperty *) m_pProperties[8]; + spPI16 = (MP4Integer16Property *)pTable->GetProperty(0); + spPB = (MP4BytesProperty *)pTable->GetProperty(1); + + // now dest pointers + dstProperty=dstAtom->GetProperty(8); + pTable = (MP4TableProperty *) dstProperty; + dpPI16 = (MP4Integer16Property *)pTable->GetProperty(0); + dpPB = (MP4BytesProperty *)pTable->GetProperty(1); + + // sps length + i16 = spPI16->GetValue(); + i64 = i16; + // FIXME - this leaves m_maxNumElements =2 + // but src atom m_maxNumElements is 1 + dpPI16->InsertValue(i64, 0); + + // export byte array + i32 = i16; + // copy bytes to local buffer + tmp = (u_int8_t *)MP4Malloc(i32); + ASSERT(tmp != NULL); + spPB->CopyValue(tmp, 0); + // set element count + dpPB->SetCount(1); + // copy bytes + dpPB->SetValue(tmp, i32, 0); + MP4Free((void *)tmp); + + // + // 9 and 10 are related PPS (one set of picture parameters) + // + // first the integer8 count + // + dstProperty=dstAtom->GetProperty(9); + dstProperty->SetReadOnly(false); + ((MP4Integer8Property *)dstProperty)->SetValue( + ((MP4Integer8Property *)m_pProperties[9])->GetValue()); + dstProperty->SetReadOnly(true); + + // next export PPS Length and NAL bytes */ + + // first source pointers + pTable = (MP4TableProperty *) m_pProperties[10]; + spPI16 = (MP4Integer16Property *)pTable->GetProperty(0); + spPB = (MP4BytesProperty *)pTable->GetProperty(1); + + // now dest pointers + dstProperty=dstAtom->GetProperty(10); + pTable = (MP4TableProperty *) dstProperty; + dpPI16 = (MP4Integer16Property *)pTable->GetProperty(0); + dpPB = (MP4BytesProperty *)pTable->GetProperty(1); + + // pps length + i16 = spPI16->GetValue(); + i64 = i16; + dpPI16->InsertValue(i64, 0); + + // export byte array + i32 = i16; + // copy bytes to local buffer + tmp = (u_int8_t *)MP4Malloc(i32); + ASSERT(tmp != NULL); + spPB->CopyValue(tmp, 0); + // set element count + dpPB->SetCount(1); + // copy bytes + dpPB->SetValue(tmp, i32, 0); + MP4Free((void *)tmp); +} + + diff --git a/Src/external_dependencies/libmp4v2/atom_bitr.cpp b/Src/external_dependencies/libmp4v2/atom_bitr.cpp new file mode 100644 index 00000000..aab7a0a0 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_bitr.cpp @@ -0,0 +1,41 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Ximpo Group Ltd. mp4v2@ximpo.com + */ + +#include "mp4common.h" + +MP4BitrAtom::MP4BitrAtom() + : MP4Atom("bitr") +{ + AddProperty( /* 0 */ + new MP4Integer32Property("avgBitrate")); + + AddProperty( /* 1 */ + new MP4Integer32Property("maxBitrate")); + + +} + diff --git a/Src/external_dependencies/libmp4v2/atom_btrt.cpp b/Src/external_dependencies/libmp4v2/atom_btrt.cpp new file mode 100644 index 00000000..54e71556 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_btrt.cpp @@ -0,0 +1,30 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2004. All Rights Reserved. + * + * Contributor(s): + * Bill May wmay@cisco.com + */ + +#include "mp4common.h" + +MP4BtrtAtom::MP4BtrtAtom() + : MP4Atom("btrt") +{ + AddProperty( new MP4Integer32Property("bufferSizeDB")); /* 0 */ + AddProperty( new MP4Integer32Property("avgBitrate")); /* 1 */ + AddProperty( new MP4Integer32Property("maxBitrate")); /* 2 */ +} diff --git a/Src/external_dependencies/libmp4v2/atom_chpl.cpp b/Src/external_dependencies/libmp4v2/atom_chpl.cpp new file mode 100644 index 00000000..c4e459a9 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_chpl.cpp @@ -0,0 +1,59 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributed to MPEG4IP + * by Ullrich Pollaehne <pollaehne at users.sourceforge.net> + * + * Nero chapter atom + */ + +#include "mp4common.h" + +// MP4ChplAtom is for Nero chapter list atom which is a child of udta +MP4ChplAtom::MP4ChplAtom () : MP4Atom("chpl") +{ + // it is not completely clear if version, flags, reserved and chaptercount + // have the right sizes but + // one thing is clear: chaptercount is not only 8-bit it is at least 16-bit + + // add the version + AddVersionAndFlags(); + + // add reserved bytes + AddReserved("reserved", 1); + + // define the chaptercount + MP4Integer32Property * counter = new MP4Integer32Property("chaptercount"); + AddProperty(counter); + + // define the chapterlist + MP4TableProperty * list = new MP4TableProperty("chapters", counter); + + // the start time as 100 nanoseconds units + list->AddProperty(new MP4Integer64Property("starttime")); + + // the chapter name as UTF-8 + list->AddProperty(new MP4StringProperty("name", true)); + + // add the chapterslist + AddProperty(list); +} + +void MP4ChplAtom::Generate () +{ + SetVersion(1); +} diff --git a/Src/external_dependencies/libmp4v2/atom_co64.cpp b/Src/external_dependencies/libmp4v2/atom_co64.cpp new file mode 100644 index 00000000..28f18abf --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_co64.cpp @@ -0,0 +1,38 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4Co64Atom::MP4Co64Atom() + : MP4Atom("co64") +{ + AddVersionAndFlags(); + + MP4Integer32Property* pCount = + new MP4Integer32Property("entryCount"); + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty("entries", pCount); + AddProperty(pTable); + + pTable->AddProperty( + new MP4Integer64Property("chunkOffset")); +} diff --git a/Src/external_dependencies/libmp4v2/atom_cprt.cpp b/Src/external_dependencies/libmp4v2/atom_cprt.cpp new file mode 100644 index 00000000..b6e56664 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_cprt.cpp @@ -0,0 +1,32 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4CprtAtom::MP4CprtAtom() + : MP4Atom("cprt") +{ + AddVersionAndFlags(); + AddProperty( + new MP4Integer16Property("language")); + AddProperty( + new MP4StringProperty("notice")); +} diff --git a/Src/external_dependencies/libmp4v2/atom_ctts.cpp b/Src/external_dependencies/libmp4v2/atom_ctts.cpp new file mode 100644 index 00000000..14627173 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_ctts.cpp @@ -0,0 +1,40 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4CttsAtom::MP4CttsAtom() + : MP4Atom("ctts") +{ + AddVersionAndFlags(); + + MP4Integer32Property* pCount = + new MP4Integer32Property("entryCount"); + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty("entries", pCount); + AddProperty(pTable); + + pTable->AddProperty( + new MP4Integer32Property("sampleCount")); + pTable->AddProperty( + new MP4Integer32Property("sampleOffset")); +} diff --git a/Src/external_dependencies/libmp4v2/atom_d263.cpp b/Src/external_dependencies/libmp4v2/atom_d263.cpp new file mode 100644 index 00000000..c9dcc4a2 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_d263.cpp @@ -0,0 +1,88 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Ximpo Group Ltd. mp4v2@ximpo.com + */ + +#include "mp4common.h" + +#define H263_VENDOR 0x6d346970 + +MP4D263Atom::MP4D263Atom() + : MP4Atom("d263") +{ + AddProperty( /* 0 */ + new MP4Integer32Property("vendor")); + + AddProperty( /* 1 */ + new MP4Integer8Property("decoderVersion")); + + AddProperty( /* 2 */ + new MP4Integer8Property("h263Level")); + + AddProperty( /* 3 */ + new MP4Integer8Property("h263Profile")); + + ExpectChildAtom("bitr", Optional, OnlyOne); + +} + +void MP4D263Atom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer32Property*)m_pProperties[0])->SetValue(H263_VENDOR); + ((MP4Integer8Property*)m_pProperties[1])->SetValue(1); + +} + +void MP4D263Atom::Write() +{ + // Check whether we have valid values in the bitr atom + // (if it exists, of course) + MP4Atom* bitrAtom = FindAtomMP4("d263.bitr"); + if (bitrAtom) { + u_int32_t avgBitrate; + u_int32_t maxBitrate; + + MP4Integer32Property* pProp; + bitrAtom->FindProperty("bitr.avgBitrate", + (MP4Property**)&pProp, + NULL); + ASSERT(pProp); + avgBitrate = pProp->GetValue(); + + bitrAtom->FindProperty("bitr.maxBitrate", + (MP4Property**)&pProp, + NULL); + ASSERT(pProp); + maxBitrate = pProp->GetValue(); + + if(!maxBitrate && !avgBitrate) { + DeleteChildAtom(bitrAtom); + } + } + + MP4Atom::Write(); +} diff --git a/Src/external_dependencies/libmp4v2/atom_damr.cpp b/Src/external_dependencies/libmp4v2/atom_damr.cpp new file mode 100644 index 00000000..ed255724 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_damr.cpp @@ -0,0 +1,59 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Ximpo Group Ltd. mp4v2@ximpo.com + */ + +#include "mp4common.h" + +#define AMR_VENDOR 0x6d346970 + +MP4DamrAtom::MP4DamrAtom() + : MP4Atom("damr") +{ + AddProperty( /* 0 */ + new MP4Integer32Property("vendor")); + + AddProperty( /* 1 */ + new MP4Integer8Property("decoderVersion")); + + AddProperty( /* 2 */ + new MP4Integer16Property("modeSet")); + + AddProperty( /* 3 */ + new MP4Integer8Property("modeChangePeriod")); + + AddProperty( /* 4 */ + new MP4Integer8Property("framesPerSample")); + +} + +void MP4DamrAtom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer32Property*)m_pProperties[0])->SetValue(AMR_VENDOR); + ((MP4Integer8Property*)m_pProperties[1])->SetValue(1); + +} diff --git a/Src/external_dependencies/libmp4v2/atom_dimm.cpp b/Src/external_dependencies/libmp4v2/atom_dimm.cpp new file mode 100644 index 00000000..e64c4283 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_dimm.cpp @@ -0,0 +1,29 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4DimmAtom::MP4DimmAtom() + : MP4Atom("dimm") +{ + AddProperty( // bytes of immediate data + new MP4Integer64Property("bytes")); +} diff --git a/Src/external_dependencies/libmp4v2/atom_dinf.cpp b/Src/external_dependencies/libmp4v2/atom_dinf.cpp new file mode 100644 index 00000000..b03b9e27 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_dinf.cpp @@ -0,0 +1,28 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4DinfAtom::MP4DinfAtom() + : MP4Atom("dinf") +{ + ExpectChildAtom("dref", Required, OnlyOne); +} diff --git a/Src/external_dependencies/libmp4v2/atom_dmax.cpp b/Src/external_dependencies/libmp4v2/atom_dmax.cpp new file mode 100644 index 00000000..43d83a46 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_dmax.cpp @@ -0,0 +1,29 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4DmaxAtom::MP4DmaxAtom() + : MP4Atom("dmax") +{ + AddProperty( // max packet duration + new MP4Integer32Property("milliSecs")); +} diff --git a/Src/external_dependencies/libmp4v2/atom_dmed.cpp b/Src/external_dependencies/libmp4v2/atom_dmed.cpp new file mode 100644 index 00000000..a2709a5b --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_dmed.cpp @@ -0,0 +1,29 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4DmedAtom::MP4DmedAtom() + : MP4Atom("dmed") +{ + AddProperty( // bytes sent from media data + new MP4Integer64Property("bytes")); +} diff --git a/Src/external_dependencies/libmp4v2/atom_dref.cpp b/Src/external_dependencies/libmp4v2/atom_dref.cpp new file mode 100644 index 00000000..133b3ee8 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_dref.cpp @@ -0,0 +1,56 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4DrefAtom::MP4DrefAtom() + : MP4Atom("dref") +{ + AddVersionAndFlags(); + + MP4Integer32Property* pCount = + new MP4Integer32Property("entryCount"); + pCount->SetReadOnly(); + AddProperty(pCount); + + ExpectChildAtom("url ", Optional, Many); + ExpectChildAtom("urn ", Optional, Many); + ExpectChildAtom("alis", Optional, Many); +} + +void MP4DrefAtom::Read() +{ + /* do the usual read */ + MP4Atom::Read(); + + // check that number of children == entryCount + MP4Integer32Property* pCount = + (MP4Integer32Property*)m_pProperties[2]; + + if (m_pChildAtoms.Size() != pCount->GetValue()) { + //VERBOSE_READ(GetVerbosity(), MP4Printf("Warning: dref inconsistency with number of entries")); + + /* fix it */ + pCount->SetReadOnly(false); + pCount->SetValue(m_pChildAtoms.Size()); + pCount->SetReadOnly(true); + } +} diff --git a/Src/external_dependencies/libmp4v2/atom_drep.cpp b/Src/external_dependencies/libmp4v2/atom_drep.cpp new file mode 100644 index 00000000..16ad4e7b --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_drep.cpp @@ -0,0 +1,29 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4DrepAtom::MP4DrepAtom() + : MP4Atom("drep") +{ + AddProperty( // bytes of repeated data + new MP4Integer64Property("bytes")); +} diff --git a/Src/external_dependencies/libmp4v2/atom_edts.cpp b/Src/external_dependencies/libmp4v2/atom_edts.cpp new file mode 100644 index 00000000..d1727019 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_edts.cpp @@ -0,0 +1,28 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4EdtsAtom::MP4EdtsAtom() + : MP4Atom("edts") +{ + ExpectChildAtom("elst", Required, OnlyOne); +} diff --git a/Src/external_dependencies/libmp4v2/atom_elst.cpp b/Src/external_dependencies/libmp4v2/atom_elst.cpp new file mode 100644 index 00000000..12b98a08 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_elst.cpp @@ -0,0 +1,80 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4ElstAtom::MP4ElstAtom() + : MP4Atom("elst") +{ + AddVersionAndFlags(); + + MP4Integer32Property* pCount = + new MP4Integer32Property("entryCount"); + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty("entries", pCount); + AddProperty(pTable); +} + +void MP4ElstAtom::AddProperties(u_int8_t version) +{ + MP4TableProperty* pTable = (MP4TableProperty*)m_pProperties[3]; + + if (version == 1) { + pTable->AddProperty( + new MP4Integer64Property("segmentDuration")); + pTable->AddProperty( + new MP4Integer64Property("mediaTime")); + } else { + pTable->AddProperty( + new MP4Integer32Property("segmentDuration")); + pTable->AddProperty( + new MP4Integer32Property("mediaTime")); + } + + pTable->AddProperty( + new MP4Integer16Property("mediaRate")); + pTable->AddProperty( + new MP4Integer16Property("reserved")); +} + +void MP4ElstAtom::Generate() +{ + SetVersion(0); + AddProperties(GetVersion()); + + MP4Atom::Generate(); +} + +void MP4ElstAtom::Read() +{ + /* read atom version */ + ReadProperties(0, 1); + + /* need to create the properties based on the atom version */ + AddProperties(GetVersion()); + + /* now we can read the remaining properties */ + ReadProperties(1); + + Skip(); // to end of atom +} + diff --git a/Src/external_dependencies/libmp4v2/atom_enca.cpp b/Src/external_dependencies/libmp4v2/atom_enca.cpp new file mode 100644 index 00000000..3a8e9e03 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_enca.cpp @@ -0,0 +1,61 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + * Alix Marchandise-Franquet alix@cisco.com + */ + +#include "mp4common.h" + +MP4EncaAtom::MP4EncaAtom() + : MP4Atom("enca") +{ + AddReserved("reserved1", 6); /* 0 */ + + AddProperty( /* 1 */ + new MP4Integer16Property("dataReferenceIndex")); + + AddReserved("reserved2", 16); /* 2 */ + + AddProperty( /* 3 */ + new MP4Integer16Property("timeScale")); + + AddReserved("reserved3", 2); /* 4 */ + + ExpectChildAtom("esds", Required, OnlyOne); + ExpectChildAtom("sinf", Required, OnlyOne); +} + +void MP4EncaAtom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); + + // property reserved2 has non-zero fixed values + static u_int8_t reserved2[16] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, + }; + m_pProperties[2]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[2])-> + SetValue(reserved2, sizeof(reserved2)); + m_pProperties[2]->SetReadOnly(true); +} diff --git a/Src/external_dependencies/libmp4v2/atom_encv.cpp b/Src/external_dependencies/libmp4v2/atom_encv.cpp new file mode 100644 index 00000000..be719690 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_encv.cpp @@ -0,0 +1,81 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + * Alix Marchandise-Franquet alix@cisco.com + */ + +#include "mp4common.h" + +MP4EncvAtom::MP4EncvAtom() + : MP4Atom("encv") +{ + AddReserved("reserved1", 6); /* 0 */ + + AddProperty( /* 1 */ + new MP4Integer16Property("dataReferenceIndex")); + + AddReserved("reserved2", 16); /* 2 */ + + AddProperty( /* 3 */ + new MP4Integer16Property("width")); + AddProperty( /* 4 */ + new MP4Integer16Property("height")); + + AddReserved("reserved3", 14); /* 5 */ + + MP4StringProperty* pProp = + new MP4StringProperty("compressorName"); + pProp->SetFixedLength(32); + pProp->SetValue(""); + AddProperty(pProp); /* 6 */ + AddReserved("reserved4", 4); /* 7 */ + + ExpectChildAtom("esds", Required, OnlyOne); + ExpectChildAtom("sinf", Required, OnlyOne); + ExpectChildAtom("avcC", Optional, OnlyOne); +} + +void MP4EncvAtom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); + + // property reserved3 has non-zero fixed values + static u_int8_t reserved3[14] = { + 0x00, 0x48, 0x00, 0x00, + 0x00, 0x48, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + }; + m_pProperties[5]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[5])-> + SetValue(reserved3, sizeof(reserved3)); + m_pProperties[5]->SetReadOnly(true); + + // property reserved4 has non-zero fixed values + static u_int8_t reserved4[4] = { + 0x00, 0x18, 0xFF, 0xFF, + }; + m_pProperties[7]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[7])-> + SetValue(reserved4, sizeof(reserved4)); + m_pProperties[7]->SetReadOnly(true); +} + diff --git a/Src/external_dependencies/libmp4v2/atom_esds.cpp b/Src/external_dependencies/libmp4v2/atom_esds.cpp new file mode 100644 index 00000000..c1b6d946 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_esds.cpp @@ -0,0 +1,31 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4EsdsAtom::MP4EsdsAtom() + : MP4Atom("esds") +{ + AddVersionAndFlags(); + AddProperty( + new MP4DescriptorProperty(NULL, + MP4ESDescrTag, 0, Required, OnlyOne)); +} diff --git a/Src/external_dependencies/libmp4v2/atom_free.cpp b/Src/external_dependencies/libmp4v2/atom_free.cpp new file mode 100644 index 00000000..0a812a6b --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_free.cpp @@ -0,0 +1,49 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4FreeAtom::MP4FreeAtom() + : MP4Atom("free") +{ +} + +void MP4FreeAtom::Read() +{ + Skip(); +} + +void MP4FreeAtom::Write() +{ + ASSERT(m_pFile); + + bool use64 = (GetSize() > (0xFFFFFFFF - 8)); + BeginWrite(use64); +#if 1 + for (uint64_t ix = 0; ix < GetSize(); ix++) { + m_pFile->WriteUInt8(0); + } +#else + m_pFile->SetPosition(m_pFile->GetPosition() + GetSize()); +#endif + FinishWrite(use64); +} + diff --git a/Src/external_dependencies/libmp4v2/atom_frma.cpp b/Src/external_dependencies/libmp4v2/atom_frma.cpp new file mode 100644 index 00000000..e2c804e4 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_frma.cpp @@ -0,0 +1,32 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Alix Marchandise-Franquet alix@cisco.com + * + * Add the OriginalFormatBox for ISMACrypt + * contains the original format of the data (i.e. decrypted format) + */ + +#include "mp4common.h" + +MP4FrmaAtom::MP4FrmaAtom() + : MP4Atom("frma") +{ + AddProperty( /* 0 */ + new MP4Integer32Property("data-format")); +} diff --git a/Src/external_dependencies/libmp4v2/atom_ftyp.cpp b/Src/external_dependencies/libmp4v2/atom_ftyp.cpp new file mode 100644 index 00000000..8b9858bb --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_ftyp.cpp @@ -0,0 +1,71 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4FtypAtom::MP4FtypAtom() + : MP4Atom("ftyp") +{ + MP4StringProperty* pProp = new MP4StringProperty("majorBrand"); + pProp->SetFixedLength(4); + AddProperty(pProp); /* 0 */ + + AddProperty( /* 1 */ + new MP4Integer32Property("minorVersion")); + + MP4Integer32Property* pCount = + new MP4Integer32Property("compatibleBrandsCount"); + pCount->SetImplicit(); + AddProperty(pCount); /* 2 */ + + MP4TableProperty* pTable = + new MP4TableProperty("compatibleBrands", pCount); + AddProperty(pTable); /* 3 */ + + pProp = new MP4StringProperty("brand"); + pProp->SetFixedLength(4); + pTable->AddProperty(pProp); +} + +void MP4FtypAtom::Generate() +{ + MP4Atom::Generate(); + + ((MP4StringProperty*)m_pProperties[0])->SetValue("mp42"); + + MP4StringProperty* pBrandProperty = (MP4StringProperty*) + ((MP4TableProperty*)m_pProperties[3])->GetProperty(0); + ASSERT(pBrandProperty); + pBrandProperty->AddValue("mp42"); + pBrandProperty->AddValue("isom"); + ((MP4Integer32Property*)m_pProperties[2])->IncrementValue(); + ((MP4Integer32Property*)m_pProperties[2])->IncrementValue(); +} + +void MP4FtypAtom::Read() +{ + // table entry count computed from atom size + ((MP4Integer32Property*)m_pProperties[2])->SetReadOnly(false); + ((MP4Integer32Property*)m_pProperties[2])->SetValue((m_size - 8) / 4); + ((MP4Integer32Property*)m_pProperties[2])->SetReadOnly(true); + + MP4Atom::Read(); +} diff --git a/Src/external_dependencies/libmp4v2/atom_gmin.cpp b/Src/external_dependencies/libmp4v2/atom_gmin.cpp new file mode 100644 index 00000000..6d33685f --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_gmin.cpp @@ -0,0 +1,49 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * Contributer has declined to give copyright information, and gives + * it freely to the world. + * + * Contributor(s): + */ + +#include "mp4common.h" + +MP4GminAtom::MP4GminAtom() + : MP4Atom("gmin") +{ + + AddVersionAndFlags(); /* 0, 1 */ + + AddProperty(new MP4Integer16Property("graphicsMode")); /* 2 */ + AddProperty(new MP4Integer16Property("opColorRed")); /* 3 */ + AddProperty(new MP4Integer16Property("opColorGreen")); /* 4 */ + AddProperty(new MP4Integer16Property("opColorBlue")); /* 5 */ + AddProperty(new MP4Integer16Property("balance")); /* 6 */ + AddReserved("reserved", 2); /* 7 */ + +} + +void MP4GminAtom::Generate() +{ + + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[2])->SetValue(0x0040); + ((MP4Integer16Property*)m_pProperties[3])->SetValue(0x8000); + ((MP4Integer16Property*)m_pProperties[4])->SetValue(0x8000); + ((MP4Integer16Property*)m_pProperties[5])->SetValue(0x8000); + ((MP4Integer16Property*)m_pProperties[6])->SetValue(0x0000); + +} + diff --git a/Src/external_dependencies/libmp4v2/atom_hdlr.cpp b/Src/external_dependencies/libmp4v2/atom_hdlr.cpp new file mode 100644 index 00000000..8461f45a --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_hdlr.cpp @@ -0,0 +1,66 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4HdlrAtom::MP4HdlrAtom() + : MP4Atom("hdlr") +{ + AddVersionAndFlags(); /* 0, 1 */ + AddReserved("reserved1", 4); /* 2 */ + MP4StringProperty* pProp = new MP4StringProperty("handlerType"); + pProp->SetFixedLength(4); + AddProperty(pProp); /* 3 */ + AddReserved("reserved2", 12); /* 4 */ + AddProperty( /* 5 */ + new MP4StringProperty("name")); +} + +// There is a spec incompatiblity between QT and MP4 +// QT says name field is a counted string +// MP4 says name field is a null terminated string +// Here we attempt to make all things work +void MP4HdlrAtom::Read() +{ + // read all the properties but the "name" field + ReadProperties(0, 5); + uint64_t pos = m_pFile->GetPosition(); + uint64_t end = GetEnd(); + if (pos == end) return; + + // take a peek at the next byte + u_int8_t strLength; + m_pFile->PeekBytes(&strLength, 1); + // if the value matches the remaining atom length + if (pos + strLength + 1 == end) { + // read a counted string + MP4StringProperty* pNameProp = + (MP4StringProperty*)m_pProperties[5]; + pNameProp->SetCountedFormat(true); + ReadProperties(5); + pNameProp->SetCountedFormat(false); + } else { + // read a null terminated string + ReadProperties(5); + } + + Skip(); // to end of atom +} diff --git a/Src/external_dependencies/libmp4v2/atom_hinf.cpp b/Src/external_dependencies/libmp4v2/atom_hinf.cpp new file mode 100644 index 00000000..20130ba8 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_hinf.cpp @@ -0,0 +1,57 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4HinfAtom::MP4HinfAtom() + : MP4Atom("hinf") +{ + ExpectChildAtom("trpy", Optional, OnlyOne); + ExpectChildAtom("nump", Optional, OnlyOne); + ExpectChildAtom("tpyl", Optional, OnlyOne); + ExpectChildAtom("maxr", Optional, Many); + ExpectChildAtom("dmed", Optional, OnlyOne); + ExpectChildAtom("dimm", Optional, OnlyOne); + ExpectChildAtom("drep", Optional, OnlyOne); + ExpectChildAtom("tmin", Optional, OnlyOne); + ExpectChildAtom("tmax", Optional, OnlyOne); + ExpectChildAtom("pmax", Optional, OnlyOne); + ExpectChildAtom("dmax", Optional, OnlyOne); + ExpectChildAtom("payt", Optional, OnlyOne); +} + +void MP4HinfAtom::Generate() +{ + // hinf is special in that although all it's child atoms + // are optional (on read), if we generate it for writing + // we really want all the children + + for (u_int32_t i = 0; i < m_pChildAtomInfos.Size(); i++) { + MP4Atom* pChildAtom = + CreateAtom(m_pChildAtomInfos[i]->m_name); + + AddChildAtom(pChildAtom); + + // and ask it to self generate + pChildAtom->Generate(); + } +} + diff --git a/Src/external_dependencies/libmp4v2/atom_hmhd.cpp b/Src/external_dependencies/libmp4v2/atom_hmhd.cpp new file mode 100644 index 00000000..12afb6a4 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_hmhd.cpp @@ -0,0 +1,39 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4HmhdAtom::MP4HmhdAtom() + : MP4Atom("hmhd") +{ + AddVersionAndFlags(); + + AddProperty( + new MP4Integer16Property("maxPduSize")); + AddProperty( + new MP4Integer16Property("avgPduSize")); + AddProperty( + new MP4Integer32Property("maxBitRate")); + AddProperty( + new MP4Integer32Property("avgBitRate")); + AddProperty( + new MP4Integer32Property("slidingAvgBitRate")); +} diff --git a/Src/external_dependencies/libmp4v2/atom_hnti.cpp b/Src/external_dependencies/libmp4v2/atom_hnti.cpp new file mode 100644 index 00000000..fc080cc4 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_hnti.cpp @@ -0,0 +1,40 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4HntiAtom::MP4HntiAtom() + : MP4Atom("hnti") +{ +} + +void MP4HntiAtom::Read() +{ + MP4Atom* grandParent = m_pParentAtom->GetParentAtom(); + ASSERT(grandParent); + if (ATOMID(grandParent->GetType()) == ATOMID("trak")) { + ExpectChildAtom("sdp ", Optional, OnlyOne); + } else { + ExpectChildAtom("rtp ", Optional, OnlyOne); + } + + MP4Atom::Read(); +} diff --git a/Src/external_dependencies/libmp4v2/atom_href.cpp b/Src/external_dependencies/libmp4v2/atom_href.cpp new file mode 100644 index 00000000..a431af53 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_href.cpp @@ -0,0 +1,40 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2005. All Rights Reserved. + * + * Contributor(s): + * Bill May wmay@cisco.com + */ + +#include "mp4common.h" + +MP4HrefAtom::MP4HrefAtom() + : MP4Atom("href") +{ + AddReserved("reserved1", 6); /* 0 */ + + AddProperty( /* 1 */ + new MP4Integer16Property("dataReferenceIndex")); + ExpectChildAtom("burl", Optional, OnlyOne); +} + +void MP4HrefAtom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); + +} diff --git a/Src/external_dependencies/libmp4v2/atom_iKMS.cpp b/Src/external_dependencies/libmp4v2/atom_iKMS.cpp new file mode 100644 index 00000000..b880a318 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_iKMS.cpp @@ -0,0 +1,34 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Alix Marchandise-Franquet alix@cisco.com + * + * ISMAKMSBox for ISMACrypt + * Do we care about the string length? Do we need to handle the null-term + * issue like in the hdlr atom? + */ + +#include "mp4common.h" + +MP4IKMSAtom::MP4IKMSAtom() + : MP4Atom("iKMS") +{ + AddVersionAndFlags(); /* 0, 1 */ + MP4StringProperty* pProp = new MP4StringProperty("kms_URI"); + AddProperty(pProp); /* 2 */ +} diff --git a/Src/external_dependencies/libmp4v2/atom_iSFM.cpp b/Src/external_dependencies/libmp4v2/atom_iSFM.cpp new file mode 100644 index 00000000..1eadf7d7 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_iSFM.cpp @@ -0,0 +1,38 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Alix Marchandise-Franquet alix@cisco.com + * + * ISMASampleFormatBox for ISMACrypt + */ + +#include "mp4common.h" + +MP4ISFMAtom::MP4ISFMAtom() + : MP4Atom("iSFM") +{ + AddVersionAndFlags(); /* 0, 1 */ + AddProperty( /* 2 */ + new MP4BitfieldProperty("selective-encryption", 1)); + AddProperty( /* 3 */ + new MP4BitfieldProperty("reserved", 7)); + AddProperty( /* 4 */ + new MP4Integer8Property("key-indicator-length")); + AddProperty( /* 5 */ + new MP4Integer8Property("IV-length")); +} diff --git a/Src/external_dependencies/libmp4v2/atom_iods.cpp b/Src/external_dependencies/libmp4v2/atom_iods.cpp new file mode 100644 index 00000000..124e61a7 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_iods.cpp @@ -0,0 +1,31 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4IodsAtom::MP4IodsAtom() + : MP4Atom("iods") +{ + AddVersionAndFlags(); + AddProperty( + new MP4DescriptorProperty(NULL, + MP4FileIODescrTag, MP4FileODescrTag, Required, OnlyOne)); +} diff --git a/Src/external_dependencies/libmp4v2/atom_maxr.cpp b/Src/external_dependencies/libmp4v2/atom_maxr.cpp new file mode 100644 index 00000000..1dedca39 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_maxr.cpp @@ -0,0 +1,31 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4MaxrAtom::MP4MaxrAtom() + : MP4Atom("maxr") +{ + AddProperty( + new MP4Integer32Property("granularity")); + AddProperty( + new MP4Integer32Property("bytes")); +} diff --git a/Src/external_dependencies/libmp4v2/atom_mdat.cpp b/Src/external_dependencies/libmp4v2/atom_mdat.cpp new file mode 100644 index 00000000..b0e1cca5 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_mdat.cpp @@ -0,0 +1,38 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4MdatAtom::MP4MdatAtom() + : MP4Atom("mdat") +{ +} + +void MP4MdatAtom::Read() +{ + Skip(); +} + +void MP4MdatAtom::Write() +{ + // should never get here + ASSERT(false); +} diff --git a/Src/external_dependencies/libmp4v2/atom_mdhd.cpp b/Src/external_dependencies/libmp4v2/atom_mdhd.cpp new file mode 100644 index 00000000..87894bb5 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_mdhd.cpp @@ -0,0 +1,91 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4MdhdAtom::MP4MdhdAtom() + : MP4Atom("mdhd") +{ + AddVersionAndFlags(); +} + +void MP4MdhdAtom::AddProperties(u_int8_t version) +{ + if (version == 1) { + AddProperty( + new MP4Integer64Property("creationTime")); + AddProperty( + new MP4Integer64Property("modificationTime")); + } else { + AddProperty( + new MP4Integer32Property("creationTime")); + AddProperty( + new MP4Integer32Property("modificationTime")); + } + + AddProperty( + new MP4Integer32Property("timeScale")); + + if (version == 1) { + AddProperty( + new MP4Integer64Property("duration")); + } else { + AddProperty( + new MP4Integer32Property("duration")); + } + + AddProperty( + new MP4Integer16Property("language")); + AddReserved("reserved", 2); +} + +void MP4MdhdAtom::Generate() +{ + u_int8_t version = m_pFile->Use64Bits(GetType()) ? 1 : 0; + SetVersion(version); + AddProperties(version); + + MP4Atom::Generate(); + + // set creation and modification times + MP4Timestamp now = MP4GetAbsTimestamp(); + if (version == 1) { + ((MP4Integer64Property*)m_pProperties[2])->SetValue(now); + ((MP4Integer64Property*)m_pProperties[3])->SetValue(now); + } else { + ((MP4Integer32Property*)m_pProperties[2])->SetValue(now); + ((MP4Integer32Property*)m_pProperties[3])->SetValue(now); + } +} + +void MP4MdhdAtom::Read() +{ + /* read atom version */ + ReadProperties(0, 1); + + /* need to create the properties based on the atom version */ + AddProperties(GetVersion()); + + /* now we can read the remaining properties */ + ReadProperties(1); + + Skip(); // to end of atom +} diff --git a/Src/external_dependencies/libmp4v2/atom_mdia.cpp b/Src/external_dependencies/libmp4v2/atom_mdia.cpp new file mode 100644 index 00000000..921f6f81 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_mdia.cpp @@ -0,0 +1,30 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4MdiaAtom::MP4MdiaAtom() + : MP4Atom("mdia") +{ + ExpectChildAtom("mdhd", Required, OnlyOne); + ExpectChildAtom("hdlr", Required, OnlyOne); + ExpectChildAtom("minf", Required, OnlyOne); +} diff --git a/Src/external_dependencies/libmp4v2/atom_meta.cpp b/Src/external_dependencies/libmp4v2/atom_meta.cpp new file mode 100644 index 00000000..d2d3a5b8 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_meta.cpp @@ -0,0 +1,117 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * M. Bakker mbakker at nero.com + * + * Apple iTunes META data + */ + +#include "mp4common.h" + +MP4Meta1Atom::MP4Meta1Atom(const char *name) + : MP4Atom(name) +{ + AddVersionAndFlags(); /* 0, 1 */ + + AddProperty(new MP4BytesProperty("metadata")); /* 2 */ +} + +void MP4Meta1Atom::Read() +{ + // calculate size of the metadata from the atom size + ((MP4BytesProperty*)m_pProperties[2])->SetValueSize(m_size - 4); + + MP4Atom::Read(); +} + +MP4DataAtom::MP4DataAtom() + : MP4Atom("data") +{ + AddVersionAndFlags(); /* 0, 1 */ + AddReserved("reserved2", 4); /* 2 */ + + AddProperty( + new MP4BytesProperty("metadata")); /* 3 */ +} + +void MP4DataAtom::Read() +{ + // calculate size of the metadata from the atom size + ((MP4BytesProperty*)m_pProperties[3])->SetValueSize(m_size - 8); + + MP4Atom::Read(); +} + + +// MP4Meta2Atom is for \251nam and \251cmt flags, which appear differently +// in .mov and in itunes file. In .movs, they appear under udata, in +// itunes, they appear under ilst. +MP4Meta2Atom::MP4Meta2Atom (const char *name) : MP4Atom(name) +{ +} + +void MP4Meta2Atom::Read () +{ + MP4Atom *parent = GetParentAtom(); + if (ATOMID(parent->GetType()) == ATOMID("udta")) { + // add data property + AddReserved("reserved2", 4); /* 0 */ + + AddProperty( + new MP4BytesProperty("metadata")); /* 1 */ + ((MP4BytesProperty*)m_pProperties[1])->SetValueSize(m_size - 4); + } else { + ExpectChildAtom("data", Required, OnlyOne); + } + MP4Atom::Read(); +} + + +MP4Meta3Atom::MP4Meta3Atom (const char *name) : MP4Atom(name) +{ + // add data property + AddReserved("reserved2", 4); /* 0 */ + AddProperty(new MP4Integer16Property("language")); + + MP4StringProperty *strProp = new MP4StringProperty("metadata"); + strProp->SetUnicode(true); + AddProperty(strProp); /* 3 */ +} + +void MP4Meta3Atom::Read () +{ + + + MP4Atom::Read(); +} + +MP4Meta4Atom::MP4Meta4Atom (const char *name) : MP4Atom(name) +{ + + // add data property + AddReserved("reserved2", 4); /* 0 */ + + AddProperty(new MP4Integer16Property("metadata")); /* 1 */ + +} + +void MP4Meta4Atom::Read () +{ + + MP4Atom::Read(); +} diff --git a/Src/external_dependencies/libmp4v2/atom_mfhd.cpp b/Src/external_dependencies/libmp4v2/atom_mfhd.cpp new file mode 100644 index 00000000..08ecb982 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_mfhd.cpp @@ -0,0 +1,31 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4MfhdAtom::MP4MfhdAtom() + : MP4Atom("mfhd") +{ + AddVersionAndFlags(); /* 0, 1 */ + AddProperty( /* 2 */ + new MP4Integer32Property("sequenceNumber")); +} + diff --git a/Src/external_dependencies/libmp4v2/atom_minf.cpp b/Src/external_dependencies/libmp4v2/atom_minf.cpp new file mode 100644 index 00000000..979a2152 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_minf.cpp @@ -0,0 +1,33 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4MinfAtom::MP4MinfAtom() + : MP4Atom("minf") +{ + ExpectChildAtom("vmhd", Optional, OnlyOne); + ExpectChildAtom("smhd", Optional, OnlyOne); + ExpectChildAtom("hmhd", Optional, OnlyOne); + ExpectChildAtom("nmhd", Optional, OnlyOne); + ExpectChildAtom("dinf", Required, OnlyOne); + ExpectChildAtom("stbl", Required, OnlyOne); +} diff --git a/Src/external_dependencies/libmp4v2/atom_moof.cpp b/Src/external_dependencies/libmp4v2/atom_moof.cpp new file mode 100644 index 00000000..195da1ab --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_moof.cpp @@ -0,0 +1,30 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4MoofAtom::MP4MoofAtom() + : MP4Atom("moof") +{ + ExpectChildAtom("mfhd", Required, OnlyOne); + ExpectChildAtom("traf", Optional, Many); +} + diff --git a/Src/external_dependencies/libmp4v2/atom_moov.cpp b/Src/external_dependencies/libmp4v2/atom_moov.cpp new file mode 100644 index 00000000..cd0f52db --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_moov.cpp @@ -0,0 +1,33 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4MoovAtom::MP4MoovAtom() + : MP4Atom("moov") +{ + ExpectChildAtom("mvhd", Required, OnlyOne); + ExpectChildAtom("iods", Required, OnlyOne); + ExpectChildAtom("trak", Required, Many); + ExpectChildAtom("udta", Optional, Many); + ExpectChildAtom("mvex", Optional, OnlyOne); +} + diff --git a/Src/external_dependencies/libmp4v2/atom_mp4a.cpp b/Src/external_dependencies/libmp4v2/atom_mp4a.cpp new file mode 100644 index 00000000..f4685a1c --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_mp4a.cpp @@ -0,0 +1,59 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4Mp4aAtom::MP4Mp4aAtom() + : MP4Atom("mp4a") +{ + AddReserved("reserved1", 6); /* 0 */ + + AddProperty( /* 1 */ + new MP4Integer16Property("dataReferenceIndex")); + + AddReserved("reserved2", 16); /* 2 */ + + AddProperty( /* 3 */ + new MP4Integer16Property("timeScale")); + + AddReserved("reserved3", 2); /* 4 */ + + ExpectChildAtom("esds", Required, OnlyOne); +} + +void MP4Mp4aAtom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); + + // property reserved2 has non-zero fixed values + static u_int8_t reserved2[16] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, + }; + m_pProperties[2]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[2])-> + SetValue(reserved2, sizeof(reserved2)); + m_pProperties[2]->SetReadOnly(true); +} diff --git a/Src/external_dependencies/libmp4v2/atom_mp4s.cpp b/Src/external_dependencies/libmp4v2/atom_mp4s.cpp new file mode 100644 index 00000000..f647dd53 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_mp4s.cpp @@ -0,0 +1,40 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4Mp4sAtom::MP4Mp4sAtom() + : MP4Atom("mp4s") +{ + AddReserved("reserved1", 6); + AddProperty( + new MP4Integer16Property("dataReferenceIndex")); + + ExpectChildAtom("esds", Required, OnlyOne); +} + +void MP4Mp4sAtom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); +} + diff --git a/Src/external_dependencies/libmp4v2/atom_mp4v.cpp b/Src/external_dependencies/libmp4v2/atom_mp4v.cpp new file mode 100644 index 00000000..a229fac4 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_mp4v.cpp @@ -0,0 +1,79 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4Mp4vAtom::MP4Mp4vAtom() + : MP4Atom("mp4v") +{ + AddReserved("reserved1", 6); /* 0 */ + + AddProperty( /* 1 */ + new MP4Integer16Property("dataReferenceIndex")); + + AddReserved("reserved2", 16); /* 2 */ + + AddProperty( /* 3 */ + new MP4Integer16Property("width")); + AddProperty( /* 4 */ + new MP4Integer16Property("height")); + + AddReserved("reserved3", 14); /* 5 */ + + MP4StringProperty* pProp = + new MP4StringProperty("compressorName"); + pProp->SetFixedLength(32); + pProp->SetValue(""); + AddProperty(pProp); /* 6 */ + + AddReserved("reserved4", 4); /* 7 */ + + ExpectChildAtom("esds", Required, OnlyOne); +} + +void MP4Mp4vAtom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); + + // property reserved3 has non-zero fixed values + static u_int8_t reserved3[14] = { + 0x00, 0x48, 0x00, 0x00, + 0x00, 0x48, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + }; + m_pProperties[5]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[5])-> + SetValue(reserved3, sizeof(reserved3)); + m_pProperties[5]->SetReadOnly(true); + + // property reserved4 has non-zero fixed values + static u_int8_t reserved4[4] = { + 0x00, 0x18, 0xFF, 0xFF, + }; + m_pProperties[7]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[7])-> + SetValue(reserved4, sizeof(reserved4)); + m_pProperties[7]->SetReadOnly(true); +} + diff --git a/Src/external_dependencies/libmp4v2/atom_mvex.cpp b/Src/external_dependencies/libmp4v2/atom_mvex.cpp new file mode 100644 index 00000000..ea79f49d --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_mvex.cpp @@ -0,0 +1,28 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4MvexAtom::MP4MvexAtom() + : MP4Atom("mvex") +{ + ExpectChildAtom("trex", Required, Many); +} diff --git a/Src/external_dependencies/libmp4v2/atom_mvhd.cpp b/Src/external_dependencies/libmp4v2/atom_mvhd.cpp new file mode 100644 index 00000000..c4764db9 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_mvhd.cpp @@ -0,0 +1,136 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4MvhdAtom::MP4MvhdAtom() + : MP4Atom("mvhd") +{ + AddVersionAndFlags(); +} + +void MP4MvhdAtom::AddProperties(u_int8_t version) +{ + if (version == 1) { + AddProperty( /* 2 */ + new MP4Integer64Property("creationTime")); + AddProperty( /* 3 */ + new MP4Integer64Property("modificationTime")); + } else { + AddProperty( /* 2 */ + new MP4Integer32Property("creationTime")); + AddProperty( /* 3 */ + new MP4Integer32Property("modificationTime")); + } + + AddProperty( /* 4 */ + new MP4Integer32Property("timeScale")); + + if (version == 1) { + AddProperty( /* 5 */ + new MP4Integer64Property("duration")); + } else { + AddProperty( /* 5 */ + new MP4Integer32Property("duration")); + } + + MP4Float32Property* pProp; + + pProp = new MP4Float32Property("rate"); + pProp->SetFixed32Format(); + AddProperty(pProp); /* 6 */ + + pProp = new MP4Float32Property("volume"); + pProp->SetFixed16Format(); + AddProperty(pProp); /* 7 */ + + AddReserved("reserved1", 70); /* 8 */ + + AddProperty( /* 9 */ + new MP4Integer32Property("nextTrackId")); +} + +void MP4MvhdAtom::Generate() +{ + u_int8_t version = m_pFile->Use64Bits(GetType()) ? 1 : 0; + SetVersion(version); + AddProperties(version); + + MP4Atom::Generate(); + + // set creation and modification times + MP4Timestamp now = MP4GetAbsTimestamp(); + if (version == 1) { + ((MP4Integer64Property*)m_pProperties[2])->SetValue(now); + ((MP4Integer64Property*)m_pProperties[3])->SetValue(now); + } else { + ((MP4Integer32Property*)m_pProperties[2])->SetValue(now); + ((MP4Integer32Property*)m_pProperties[3])->SetValue(now); + } + + ((MP4Integer32Property*)m_pProperties[4])->SetValue(1000); + + ((MP4Float32Property*)m_pProperties[6])->SetValue(1.0); + ((MP4Float32Property*)m_pProperties[7])->SetValue(1.0); + + // property reserved has non-zero fixed values + static u_int8_t reserved[70] = { + 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + }; + m_pProperties[8]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[8])-> + SetValue(reserved, sizeof(reserved)); + m_pProperties[8]->SetReadOnly(true); + + // set next track id + ((MP4Integer32Property*)m_pProperties[9])->SetValue(1); +} + +void MP4MvhdAtom::Read() +{ + /* read atom version */ + ReadProperties(0, 1); + + /* need to create the properties based on the atom version */ + AddProperties(GetVersion()); + + /* now we can read the remaining properties */ + ReadProperties(1); + + Skip(); // to end of atom +} diff --git a/Src/external_dependencies/libmp4v2/atom_nmhd.cpp b/Src/external_dependencies/libmp4v2/atom_nmhd.cpp new file mode 100644 index 00000000..d65e3196 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_nmhd.cpp @@ -0,0 +1,28 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4NmhdAtom::MP4NmhdAtom() + : MP4Atom("nmhd") +{ + AddVersionAndFlags(); +} diff --git a/Src/external_dependencies/libmp4v2/atom_nump.cpp b/Src/external_dependencies/libmp4v2/atom_nump.cpp new file mode 100644 index 00000000..8d218d1f --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_nump.cpp @@ -0,0 +1,29 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4NumpAtom::MP4NumpAtom() + : MP4Atom("nump") +{ + AddProperty( // packets sent + new MP4Integer64Property("packets")); +} diff --git a/Src/external_dependencies/libmp4v2/atom_ohdr.cpp b/Src/external_dependencies/libmp4v2/atom_ohdr.cpp new file mode 100644 index 00000000..301090fd --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_ohdr.cpp @@ -0,0 +1,92 @@ +/** \file atom_ohdr.cpp + + \author Danijel Kopcinovic (danijel.kopcinovic@adnecto.net) +*/ + +#include "mp4common.h" + +/*! \brief Patch class for read/write operations when string is 0-length. + + We want to use string property, but mpeg4ip doesn't support ohdr way of + encoding of string (in ohdr atom we first have 3 lengths of 3 strings and + then their string values, and it cannot be simulated with any of the + current mpeg4ip string property parameters), so we have to write our own + Read() and Write() routines. +*/ +class OhdrMP4StringProperty: public MP4StringProperty { +public: + /*! \brief Constructor. + + \param name name of the property. + \param useCountedFormat counted format flag. + \param useUnicode unicode flag. + */ + OhdrMP4StringProperty(char* name, bool useCountedFormat = false, + bool useUnicode = false): MP4StringProperty(name, useCountedFormat, + useUnicode) { + } + + /*! \brief Read property from file. + + \param pFile input, file handle. + \param index input, index to read. + */ + void Read(MP4File* pFile, u_int32_t index = 0) { + MP4Free(m_values[index]); + m_values[index] = (char*)MP4Calloc(m_fixedLength + 1); + (void)pFile->ReadBytes((u_int8_t*)m_values[index], m_fixedLength); + } + + /*! \brief Write property to file. + + \param pFile input, file handle. + \param index input, index to write. + */ + void Write(MP4File* pFile, u_int32_t index = 0) { + pFile->WriteBytes((u_int8_t*)m_values[index], m_fixedLength); + } +}; + +/*! \brief OMA DRM headers atom. + + Contained in OMA DRM key management atom. It must contain content identifier. +*/ +/*! \brief Constructor. +*/ +MP4OhdrAtom::MP4OhdrAtom(): MP4Atom("ohdr") { + AddVersionAndFlags(); + + AddProperty(new MP4Integer8Property("EncryptionMethod")); + AddProperty(new MP4Integer8Property("EncryptionPadding")); + AddProperty(new MP4Integer64Property("PlaintextLength")); + AddProperty(new MP4Integer16Property("ContentIDLength")); + AddProperty(new MP4Integer16Property("RightsIssuerURLLength")); + AddProperty(new MP4Integer16Property("TextualHeadersLength")); + AddProperty(new OhdrMP4StringProperty("ContentID")); + AddProperty(new OhdrMP4StringProperty("RightsIssuerURL")); + AddProperty(new MP4BytesProperty("TextualHeaders")); +} + +MP4OhdrAtom::~MP4OhdrAtom() { +} + +/*! \brief Read atom. +*/ +void MP4OhdrAtom::Read() { + ReadProperties(0, 8); + MP4Property* lProperty; + MP4Property* property; + lProperty = GetProperty(5); + property = GetProperty(8); + ((OhdrMP4StringProperty*)property)->SetFixedLength( + ((MP4Integer16Property*)lProperty)->GetValue()); + lProperty = GetProperty(6); + property = GetProperty(9); + ((OhdrMP4StringProperty*)property)->SetFixedLength( + ((MP4Integer16Property*)lProperty)->GetValue()); + lProperty = GetProperty(7); + property = GetProperty(10); + ((MP4BytesProperty*)property)->SetFixedSize( + ((MP4Integer16Property*)lProperty)->GetValue()); + ReadProperties(8, 3); +} diff --git a/Src/external_dependencies/libmp4v2/atom_payt.cpp b/Src/external_dependencies/libmp4v2/atom_payt.cpp new file mode 100644 index 00000000..615cf256 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_payt.cpp @@ -0,0 +1,31 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4PaytAtom::MP4PaytAtom() + : MP4Atom("payt") +{ + AddProperty( + new MP4Integer32Property("payloadNumber")); + AddProperty( + new MP4StringProperty("rtpMap", Counted)); +} diff --git a/Src/external_dependencies/libmp4v2/atom_pmax.cpp b/Src/external_dependencies/libmp4v2/atom_pmax.cpp new file mode 100644 index 00000000..c3d40882 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_pmax.cpp @@ -0,0 +1,29 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4PmaxAtom::MP4PmaxAtom() + : MP4Atom("pmax") +{ + AddProperty( // max packet size + new MP4Integer32Property("bytes")); +} diff --git a/Src/external_dependencies/libmp4v2/atom_root.cpp b/Src/external_dependencies/libmp4v2/atom_root.cpp new file mode 100644 index 00000000..5efb1add --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_root.cpp @@ -0,0 +1,124 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4RootAtom::MP4RootAtom() + : MP4Atom(NULL) +{ + ExpectChildAtom("moov", Required, OnlyOne); + ExpectChildAtom("ftyp", Optional, OnlyOne); + ExpectChildAtom("mdat", Optional, Many); + ExpectChildAtom("free", Optional, Many); + ExpectChildAtom("skip", Optional, Many); + ExpectChildAtom("udta", Optional, Many); + ExpectChildAtom("moof", Optional, Many); +} + +void MP4RootAtom::BeginWrite(bool use64) +{ + // only call under MP4Create() control + WriteAtomType("ftyp", OnlyOne); + + m_pChildAtoms[GetLastMdatIndex()]->BeginWrite(m_pFile->Use64Bits("mdat")); +} + +void MP4RootAtom::Write() +{ + // no-op +} + +void MP4RootAtom::FinishWrite(bool use64) +{ + // finish writing last mdat atom + u_int32_t mdatIndex = GetLastMdatIndex(); + m_pChildAtoms[mdatIndex]->FinishWrite(m_pFile->Use64Bits("mdat")); + + // write all atoms after last mdat + u_int32_t size = m_pChildAtoms.Size(); + for (u_int32_t i = mdatIndex + 1; i < size; i++) { + m_pChildAtoms[i]->Write(); + } +} + +void MP4RootAtom::BeginOptimalWrite() +{ + WriteAtomType("ftyp", OnlyOne); + WriteAtomType("moov", OnlyOne); + WriteAtomType("udta", Many); + + m_pChildAtoms[GetLastMdatIndex()]->BeginWrite(m_pFile->Use64Bits("mdat")); +} + +void MP4RootAtom::FinishOptimalWrite() +{ + // finish writing mdat + m_pChildAtoms[GetLastMdatIndex()]->FinishWrite(m_pFile->Use64Bits("mdat")); + + // find moov atom + u_int32_t size = m_pChildAtoms.Size(); + MP4Atom* pMoovAtom = NULL; + + u_int32_t i; + for (i = 0; i < size; i++) { + if (!strcmp("moov", m_pChildAtoms[i]->GetType())) { + pMoovAtom = m_pChildAtoms[i]; + break; + } + } + ASSERT(i < size); + ASSERT(pMoovAtom != NULL); + + // rewrite moov so that updated chunkOffsets are written to disk + m_pFile->SetPosition(pMoovAtom->GetStart()); + u_int64_t oldSize = pMoovAtom->GetSize(); + + pMoovAtom->Write(); + + // sanity check + u_int64_t newSize = pMoovAtom->GetSize(); + ASSERT(oldSize == newSize); +} + +u_int32_t MP4RootAtom::GetLastMdatIndex() +{ + for (int32_t i = m_pChildAtoms.Size() - 1; i >= 0; i--) { + if (!strcmp("mdat", m_pChildAtoms[i]->GetType())) { + return i; + } + } + ASSERT(false); + return (u_int32_t)-1; +} + +void MP4RootAtom::WriteAtomType(const char* type, bool onlyOne) +{ + u_int32_t size = m_pChildAtoms.Size(); + + for (u_int32_t i = 0; i < size; i++) { + if (!strcmp(type, m_pChildAtoms[i]->GetType())) { + m_pChildAtoms[i]->Write(); + if (onlyOne) { + break; + } + } + } +} diff --git a/Src/external_dependencies/libmp4v2/atom_rtp.cpp b/Src/external_dependencies/libmp4v2/atom_rtp.cpp new file mode 100644 index 00000000..e90a9032 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_rtp.cpp @@ -0,0 +1,148 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4RtpAtom::MP4RtpAtom() + : MP4Atom("rtp ") +{ + // The atom type "rtp " is used in two complete unrelated ways + // i.e. it's real two atoms with the same name + // To handle that we need to postpone property creation until + // we know who our parent atom is (stsd or hnti) which gives us + // the context info we need to know who we are +} + +void MP4RtpAtom::AddPropertiesStsdType() +{ + AddReserved("reserved1", 6); /* 0 */ + + AddProperty( /* 1 */ + new MP4Integer16Property("dataReferenceIndex")); + + AddProperty( /* 2 */ + new MP4Integer16Property("hintTrackVersion")); + AddProperty( /* 3 */ + new MP4Integer16Property("highestCompatibleVersion")); + AddProperty( /* 4 */ + new MP4Integer32Property("maxPacketSize")); + + ExpectChildAtom("tims", Required, OnlyOne); + ExpectChildAtom("tsro", Optional, OnlyOne); + ExpectChildAtom("snro", Optional, OnlyOne); +} + +void MP4RtpAtom::AddPropertiesHntiType() +{ + MP4StringProperty* pProp = + new MP4StringProperty("descriptionFormat"); + pProp->SetFixedLength(4); + AddProperty(pProp); /* 0 */ + + AddProperty( /* 1 */ + new MP4StringProperty("sdpText")); +} + +void MP4RtpAtom::Generate() +{ + if (!strcmp(m_pParentAtom->GetType(), "stsd")) { + AddPropertiesStsdType(); + GenerateStsdType(); + } else if (!strcmp(m_pParentAtom->GetType(), "hnti")) { + AddPropertiesHntiType(); + GenerateHntiType(); + } else { + VERBOSE_WARNING(m_pFile->GetVerbosity(), + printf("Warning: rtp atom in unexpected context, can not generate")); + } +} + +void MP4RtpAtom::GenerateStsdType() +{ + // generate children + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); + ((MP4Integer16Property*)m_pProperties[2])->SetValue(1); + ((MP4Integer16Property*)m_pProperties[3])->SetValue(1); +} + +void MP4RtpAtom::GenerateHntiType() +{ + MP4Atom::Generate(); + + ((MP4StringProperty*)m_pProperties[0])->SetValue("sdp "); +} + +void MP4RtpAtom::Read() +{ + if (!strcmp(m_pParentAtom->GetType(), "stsd")) { + AddPropertiesStsdType(); + ReadStsdType(); + } else if (!strcmp(m_pParentAtom->GetType(), "hnti")) { + AddPropertiesHntiType(); + ReadHntiType(); + } else { + VERBOSE_READ(m_pFile->GetVerbosity(), + printf("rtp atom in unexpected context, can not read")); + } + + Skip(); // to end of atom +} + +void MP4RtpAtom::ReadStsdType() +{ + MP4Atom::Read(); +} + +void MP4RtpAtom::ReadHntiType() +{ + ReadProperties(0, 1); + + // read sdp string, length is implicit in size of atom + u_int64_t size = GetEnd() - m_pFile->GetPosition(); + char* data = (char*)MP4Malloc(size + 1); + ASSERT(data != NULL); + m_pFile->ReadBytes((u_int8_t*)data, size); + data[size] = '\0'; + ((MP4StringProperty*)m_pProperties[1])->SetValue(data); + MP4Free(data); +} + +void MP4RtpAtom::Write() +{ + if (!strcmp(m_pParentAtom->GetType(), "hnti")) { + WriteHntiType(); + } else { + MP4Atom::Write(); + } +} + +void MP4RtpAtom::WriteHntiType() +{ + // since length of string is implicit in size of atom + // we need to handle this specially, and not write the terminating \0 + MP4StringProperty* pSdp = (MP4StringProperty*)m_pProperties[1]; + pSdp->SetFixedLength((u_int32_t)strlen(pSdp->GetValue())); + MP4Atom::Write(); + pSdp->SetFixedLength(0); +} + diff --git a/Src/external_dependencies/libmp4v2/atom_s263.cpp b/Src/external_dependencies/libmp4v2/atom_s263.cpp new file mode 100644 index 00000000..7f232a91 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_s263.cpp @@ -0,0 +1,78 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Ximpo Group Ltd. mp4v2@ximpo.com + */ + +#include "mp4common.h" + +MP4S263Atom::MP4S263Atom() + : MP4Atom("s263") +{ + AddReserved("reserved1", 6); /* 0 */ + + AddProperty( /* 1 */ + new MP4Integer16Property("dataReferenceIndex")); + + AddReserved("reserved2", 16); /* 2 */ + + AddProperty( /* 3 */ + new MP4Integer16Property("width")); + + AddProperty( /* 4 */ + new MP4Integer16Property("height")); + + AddReserved("reserved3", 50); /* 5 */ + + + ExpectChildAtom("d263", Required, OnlyOne); +} + +void MP4S263Atom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); + + // property reserved2 has non-zero fixed values + static u_int8_t reserved3[50] = { + 0x00, 0x48, 0x00, 0x00, + 0x00, 0x48, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x24, + 0xFF, 0xFF + }; + m_pProperties[5]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[5])-> + SetValue(reserved3, sizeof(reserved3)); + m_pProperties[5]->SetReadOnly(true); +} diff --git a/Src/external_dependencies/libmp4v2/atom_schi.cpp b/Src/external_dependencies/libmp4v2/atom_schi.cpp new file mode 100644 index 00000000..b5f925b8 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_schi.cpp @@ -0,0 +1,33 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Alix Marchandise-Franquet alix@cisco.com + * + * SchemeInformationBox for ISMACrypt + */ + +#include "mp4common.h" + +MP4SchiAtom::MP4SchiAtom() + : MP4Atom("schi") +{ + // not sure if this is child atoms or table of boxes + // get clarification on spec 9.1.2.5 + ExpectChildAtom("iKMS", Required, OnlyOne); + ExpectChildAtom("iSFM", Required, OnlyOne); +} diff --git a/Src/external_dependencies/libmp4v2/atom_schm.cpp b/Src/external_dependencies/libmp4v2/atom_schm.cpp new file mode 100644 index 00000000..191f5bce --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_schm.cpp @@ -0,0 +1,35 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Alix Marchandise-Franquet alix@cisco.com + * + * Add the SchemeTypeBox for ISMACrypt + */ + +#include "mp4common.h" + +MP4SchmAtom::MP4SchmAtom() + : MP4Atom("schm") +{ + AddVersionAndFlags(); /* 0, 1 */ + AddProperty( /* 2 */ + new MP4Integer32Property("scheme_type")); + AddProperty( /* 3 */ + new MP4Integer32Property("scheme_version")); + // browser URI if flags set, TODO +} diff --git a/Src/external_dependencies/libmp4v2/atom_sdp.cpp b/Src/external_dependencies/libmp4v2/atom_sdp.cpp new file mode 100644 index 00000000..dc4ac7b7 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_sdp.cpp @@ -0,0 +1,54 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4SdpAtom::MP4SdpAtom() : MP4Atom("sdp ") +{ + AddProperty( + new MP4StringProperty("sdpText")); +} + +void MP4SdpAtom::Read() +{ + // read sdp string, length is implicit in size of atom + u_int64_t size = GetEnd() - m_pFile->GetPosition(); + char* data = (char*)MP4Malloc(size + 1); + ASSERT(data != NULL); + m_pFile->ReadBytes((u_int8_t*)data, size); + data[size] = '\0'; + ((MP4StringProperty*)m_pProperties[0])->SetValue(data); + MP4Free(data); +} + +void MP4SdpAtom::Write() +{ + // since length of string is implicit in size of atom + // we need to handle this specially, and not write the terminating \0 + MP4StringProperty* pSdp = (MP4StringProperty*)m_pProperties[0]; + const char* sdpText = pSdp->GetValue(); + if (sdpText) { + pSdp->SetFixedLength((u_int32_t)strlen(sdpText)); + } + MP4Atom::Write(); + pSdp->SetFixedLength(0); +} + diff --git a/Src/external_dependencies/libmp4v2/atom_sinf.cpp b/Src/external_dependencies/libmp4v2/atom_sinf.cpp new file mode 100644 index 00000000..e5120eb4 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_sinf.cpp @@ -0,0 +1,33 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + * Alix Marchandise-Franquet alix@cisco.com + * + * Add the ProtectionInfoBox for ISMACrypt + */ + +#include "mp4common.h" + +MP4SinfAtom::MP4SinfAtom() + : MP4Atom("sinf") +{ + ExpectChildAtom("frma", Required, OnlyOne); + ExpectChildAtom("schm", Required, OnlyOne); + ExpectChildAtom("schi", Required, OnlyOne); +} diff --git a/Src/external_dependencies/libmp4v2/atom_smhd.cpp b/Src/external_dependencies/libmp4v2/atom_smhd.cpp new file mode 100644 index 00000000..72923753 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_smhd.cpp @@ -0,0 +1,29 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4SmhdAtom::MP4SmhdAtom() + : MP4Atom("smhd") +{ + AddVersionAndFlags(); + AddReserved("reserved", 4); +} diff --git a/Src/external_dependencies/libmp4v2/atom_smi.cpp b/Src/external_dependencies/libmp4v2/atom_smi.cpp new file mode 100644 index 00000000..604ec2de --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_smi.cpp @@ -0,0 +1,41 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2004. All Rights Reserved. + * + * Contributor(s): + * Bill May wmay@cisco.com + * + * Apple iTunes META data + */ + +#include "mp4common.h" + +MP4SmiAtom::MP4SmiAtom() + : MP4Atom("meta") +{ + + AddProperty( new MP4BytesProperty("metadata")); + +} + +void MP4SmiAtom::Read() +{ + // calculate size of the metadata from the atom size + ((MP4BytesProperty*)m_pProperties[0])->SetValueSize(m_size); + + MP4Atom::Read(); +} + diff --git a/Src/external_dependencies/libmp4v2/atom_snro.cpp b/Src/external_dependencies/libmp4v2/atom_snro.cpp new file mode 100644 index 00000000..077d2cc0 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_snro.cpp @@ -0,0 +1,30 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4SnroAtom::MP4SnroAtom() + : MP4Atom("snro") +{ + AddProperty( + new MP4Integer32Property("offset")); +} + diff --git a/Src/external_dependencies/libmp4v2/atom_sound.cpp b/Src/external_dependencies/libmp4v2/atom_sound.cpp new file mode 100644 index 00000000..668134ae --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_sound.cpp @@ -0,0 +1,125 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2004. All Rights Reserved. + * + * Contributor(s): + * Bill May wmay@cisco.com + */ + +#include "mp4common.h" + +MP4SoundAtom::MP4SoundAtom(const char *atomid) + : MP4Atom(atomid) +{ + AddReserved("reserved1", 6); /* 0 */ + + AddProperty( /* 1 */ + new MP4Integer16Property("dataReferenceIndex")); + AddProperty( /* 2 */ + new MP4Integer16Property("soundVersion")); + AddReserved( "reserved2", 6); /* 3 */ + + AddProperty( /* 4 */ + new MP4Integer16Property("channels")); + AddProperty( /* 5 */ + new MP4Integer16Property("sampleSize")); + AddProperty( /* 6 */ + new MP4Integer16Property("packetSize")); + AddProperty( /* 7 */ + new MP4Integer32Property("timeScale")); + + if (ATOMID(atomid) == ATOMID("mp4a")) { + AddReserved("reserved3", 2); /* 8 */ + ExpectChildAtom("esds", Required, OnlyOne); + ExpectChildAtom("wave", Optional, OnlyOne); + } else if (ATOMID(atomid) == ATOMID("alac")) { + AddReserved("reserved3", 2); /* 8 */ + ExpectChildAtom("alac", Optional, Optional); + //AddProperty( new MP4BytesProperty("alacInfo", 36)); + } +} + +void MP4SoundAtom::AddProperties (uint8_t version) +{ + if (version > 0) { + AddProperty( /* 8 */ + new MP4Integer32Property("samplesPerPacket")); + AddProperty( /* 9 */ + new MP4Integer32Property("bytesPerPacket")); + AddProperty( /* 10 */ + new MP4Integer32Property("bytesPerFrame")); + AddProperty( /* 11 */ + new MP4Integer32Property("bytesPerSample")); + } + if (version == 2) { + AddReserved("reserved4", 20); + } +} +void MP4SoundAtom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); + + // property reserved2 has non-zero fixed values + ((MP4Integer16Property*)m_pProperties[2])->SetValue(0); + static const u_int8_t reserved2[6] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, + }; + m_pProperties[3]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[3])-> + SetValue(reserved2, sizeof(reserved2)); + m_pProperties[3]->SetReadOnly(true); + ((MP4Integer16Property*)m_pProperties[4])->SetValue(2); + ((MP4Integer16Property*)m_pProperties[5])->SetValue(0x0010); + ((MP4Integer16Property*)m_pProperties[6])->SetValue(0); + +} + +void MP4SoundAtom::Read() +{ + MP4Atom *parent = GetParentAtom(); + if (ATOMID(parent->GetType()) != ATOMID("stsd")) { + // Quicktime has an interesting thing - they'll put an mp4a atom + // which is blank inside a wave atom, which is inside an mp4a atom + // we have a mp4a inside an wave inside an mp4a - delete all properties + m_pProperties.Delete(8); + m_pProperties.Delete(7); + m_pProperties.Delete(6); + m_pProperties.Delete(5); + m_pProperties.Delete(4); + m_pProperties.Delete(3); + m_pProperties.Delete(2); + m_pProperties.Delete(1); + m_pProperties.Delete(0); + if (ATOMID(GetType()) == ATOMID("alac")) { + AddProperty(new MP4BytesProperty("decoderConfig", m_size)); + ReadProperties(); + } + if (m_pChildAtomInfos.Size() > 0) { + ReadChildAtoms(); + } + } else { + ReadProperties(0, 3); // read first 3 properties + AddProperties(((MP4IntegerProperty *)m_pProperties[2])->GetValue()); + ReadProperties(3); // continue + if (m_pChildAtomInfos.Size() > 0) { + ReadChildAtoms(); + } + } + Skip(); +} diff --git a/Src/external_dependencies/libmp4v2/atom_standard.cpp b/Src/external_dependencies/libmp4v2/atom_standard.cpp new file mode 100644 index 00000000..a18d7f36 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_standard.cpp @@ -0,0 +1,466 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2004. All Rights Reserved. + * + * Contributor(s): + * Bill May (from others work). + */ + +#include "mp4common.h" +#include "atoms.h" + +static const char name[5]={'\xA9','n', 'a', 'm', '\0'}; +static const char art[5]={'\xA9','A', 'R', 'T', '\0'}; +static const char wrt[5]={'\xA9','w', 'r', 't', '\0'}; +static const char alb[5]={'\xA9','a', 'l', 'b', '\0'}; +static const char day[5]={'\xA9','d', 'a', 'y', '\0'}; +static const char too[5]={'\xA9','t', 'o', 'o', '\0'}; +static const char cmt[5]={'\xA9','c', 'm', 't', '\0'}; +static const char gen[5]={'\xA9','g', 'e', 'n', '\0'}; +static const char grp[5]={'\xA9','g', 'r', 'p', '\0'}; + +MP4StandardAtom::MP4StandardAtom (const char *type) : MP4Atom(type) +{ + /* + * This is a big if else loop. Make sure that you don't break it + * when adding new atoms, or you will set the unknown type flag + * + * Try to keep it in alphabetical order - it should only be called + * 1 time per atom, so it's not that urgent. + */ + if (ATOMID(type) == ATOMID("aART") || + ATOMID(type) == ATOMID("akID") || + ATOMID(type) == ATOMID("apID") || + ATOMID(type) == ATOMID("atID")) { + ExpectChildAtom("data", Required, OnlyOne); + /* + * b??? + */ + } else if (ATOMID(type) == ATOMID("bitr")) { + AddProperty( /* 0 */ + new MP4Integer32Property("avgBitrate")); + + AddProperty( /* 1 */ + new MP4Integer32Property("maxBitrate")); + + } else if (ATOMID(type) == ATOMID("btrt")) { + AddProperty( new MP4Integer32Property("bufferSizeDB")); /* 0 */ + AddProperty( new MP4Integer32Property("avgBitrate")); /* 1 */ + AddProperty( new MP4Integer32Property("maxBitrate")); /* 2 */ + } else if (ATOMID(type) == ATOMID("burl")) { + AddProperty( new MP4StringProperty("base_url")); + /* + * c??? + */ + } else if (ATOMID(type) == ATOMID("co64")) { + AddVersionAndFlags(); + + MP4Integer32Property* pCount = + new MP4Integer32Property("entryCount"); + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty("entries", pCount); + AddProperty(pTable); + + pTable->AddProperty( + new MP4Integer64Property("chunkOffset")); + + } else if (ATOMID(type) == ATOMID("cpil")) { + ExpectChildAtom("data", Required, OnlyOne); + } else if (ATOMID(type) == ATOMID("covr")) { /* Apple iTunes */ + ExpectChildAtom("data", Required, Many); + } else if (ATOMID(type) == ATOMID("cprt") || + ATOMID(type) == ATOMID("cnID")) { +#if 0 + AddVersionAndFlags(); + AddProperty( + new MP4Integer16Property("language")); + AddProperty( + new MP4StringProperty("notice")); +#else + ExpectChildAtom("data", Required, OnlyOne); +#endif + + } else if (ATOMID(type) == ATOMID("ctts")) { + AddVersionAndFlags(); + + MP4Integer32Property* pCount = + new MP4Integer32Property("entryCount"); + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty("entries", pCount); + AddProperty(pTable); + + pTable->AddProperty(new MP4Integer32Property("sampleCount")); + pTable->AddProperty(new MP4Integer32Property("sampleOffset")); + /* + * d??? + */ + } else if (ATOMID(type) == ATOMID("dinf")) { + ExpectChildAtom("dref", Required, OnlyOne); + + } else if (ATOMID(type) == ATOMID("dimm")) { + AddProperty( // bytes of immediate data + new MP4Integer64Property("bytes")); + + } else if (ATOMID(type) == ATOMID("disk")) { /* Apple iTunes */ + ExpectChildAtom("data", Required, OnlyOne); + + } else if (ATOMID(type) == ATOMID("dmax")) { + AddProperty( // max packet duration + new MP4Integer32Property("milliSecs")); + + } else if (ATOMID(type) == ATOMID("dmed")) { + AddProperty( // bytes sent from media data + new MP4Integer64Property("bytes")); + + } else if (ATOMID(type) == ATOMID("drep")) { + AddProperty( // bytes of repeated data + new MP4Integer64Property("bytes")); + /* + * e??? + */ + } else if (ATOMID(type) == ATOMID("edts")) { + ExpectChildAtom("elst", Required, OnlyOne); + + } else if (ATOMID(type) == ATOMID("esds")) { + AddVersionAndFlags(); + AddProperty( + new MP4DescriptorProperty(NULL, MP4ESDescrTag, 0, + Required, OnlyOne)); + /* + * f??? + */ + } else if (ATOMID(type) == ATOMID("frma")) { + AddProperty( /* 0 */ + new MP4Integer32Property("data-format")); + /* + * g??? + */ + } else if (ATOMID(type) == ATOMID("gmhd")) { + ExpectChildAtom("gmin", Required, OnlyOne); + ExpectChildAtom("tmcd", Optional, OnlyOne); + ExpectChildAtom("text", Optional, OnlyOne); + } else if (ATOMID(type) == ATOMID("gnre") || + ATOMID(type) == ATOMID("geID")) { // Apple iTunes + ExpectChildAtom("data", Optional, OnlyOne); + + /* + * h??? + */ + } else if (ATOMID(type) == ATOMID("hmhd")) { + AddVersionAndFlags(); + + AddProperty(new MP4Integer16Property("maxPduSize")); + AddProperty(new MP4Integer16Property("avgPduSize")); + AddProperty(new MP4Integer32Property("maxBitRate")); + AddProperty(new MP4Integer32Property("avgBitRate")); + AddProperty(new MP4Integer32Property("slidingAvgBitRate")); + /* + * i??? + */ + } else if (ATOMID(type) == ATOMID("iKMS")) { + AddVersionAndFlags(); /* 0, 1 */ + MP4StringProperty* pProp = new MP4StringProperty("kms_URI"); + AddProperty(pProp); /* 2 */ + + } else if (ATOMID(type) == ATOMID("iSFM")) { + AddVersionAndFlags(); /* 0, 1 */ + AddProperty( /* 2 */ + new MP4BitfieldProperty("selective-encryption", 1)); + AddProperty( /* 3 */ + new MP4BitfieldProperty("reserved", 7)); + AddProperty( /* 4 */ + new MP4Integer8Property("key-indicator-length")); + AddProperty( /* 5 */ + new MP4Integer8Property("IV-length")); + + } else if (ATOMID(type) == ATOMID("ilst")) { + ExpectChildAtom("\251nam", Optional, OnlyOne); /* name */ + ExpectChildAtom("\251ART", Optional, OnlyOne); /* artist */ + ExpectChildAtom("\251wrt", Optional, OnlyOne); /* writer */ + ExpectChildAtom("\251alb", Optional, OnlyOne); /* album */ + ExpectChildAtom("\251day", Optional, OnlyOne); /* date */ + ExpectChildAtom("\251too", Optional, OnlyOne); /* tool */ + ExpectChildAtom("\251cmt", Optional, OnlyOne); /* comment */ + ExpectChildAtom("\251gen", Optional, OnlyOne); /* custom genre */ + ExpectChildAtom("trkn", Optional, OnlyOne); /* tracknumber */ + ExpectChildAtom("disk", Optional, OnlyOne); /* disknumber */ + ExpectChildAtom("gnre", Optional, OnlyOne); /* genre (ID3v1 index + 1) */ + ExpectChildAtom("cpil", Optional, OnlyOne); /* compilation */ + ExpectChildAtom("tmpo", Optional, OnlyOne); /* BPM */ + ExpectChildAtom("covr", Optional, OnlyOne); /* cover art */ + ExpectChildAtom("aART", Optional, OnlyOne); /* album artist */ + ExpectChildAtom("----", Optional, Many); /* ---- free form */ + ExpectChildAtom("pgap", Optional, OnlyOne); /* part of gapless album */ + ExpectChildAtom("rate", Optional, OnlyOne); /* rating 0-100 */ + } else if (ATOMID(type) == ATOMID("imif")) { + AddVersionAndFlags(); + AddProperty(new MP4DescriptorProperty("ipmp_desc", MP4IPMPDescrTag, + MP4IPMPDescrTag, Required, Many)); + } else if (ATOMID(type) == ATOMID("iods")) { + AddVersionAndFlags(); + AddProperty( + new MP4DescriptorProperty(NULL, MP4FileIODescrTag, + MP4FileODescrTag, + Required, OnlyOne)); + /* + * m??? + */ + } else if (ATOMID(type) == ATOMID("maxr")) { + AddProperty(new MP4Integer32Property("granularity")); + AddProperty(new MP4Integer32Property("bytes")); + + } else if (ATOMID(type) == ATOMID("mdia")) { + ExpectChildAtom("mdhd", Required, OnlyOne); + ExpectChildAtom("hdlr", Required, OnlyOne); + ExpectChildAtom("minf", Required, OnlyOne); + + } else if (ATOMID(type) == ATOMID("meta")) { // iTunes + AddVersionAndFlags(); /* 0, 1 */ + ExpectChildAtom("hdlr", Required, OnlyOne); + ExpectChildAtom("ilst", Required, OnlyOne); + + } else if (ATOMID(type) == ATOMID("mfhd")) { + AddVersionAndFlags(); /* 0, 1 */ + AddProperty( /* 2 */ + new MP4Integer32Property("sequenceNumber")); + + } else if (ATOMID(type) == ATOMID("minf")) { + ExpectChildAtom("vmhd", Optional, OnlyOne); + ExpectChildAtom("smhd", Optional, OnlyOne); + ExpectChildAtom("hmhd", Optional, OnlyOne); + ExpectChildAtom("nmhd", Optional, OnlyOne); + ExpectChildAtom("gmhd", Optional, OnlyOne); + ExpectChildAtom("dinf", Required, OnlyOne); + ExpectChildAtom("stbl", Required, OnlyOne); + + } else if (ATOMID(type) == ATOMID("moof")) { + ExpectChildAtom("mfhd", Required, OnlyOne); + ExpectChildAtom("traf", Optional, Many); + + } else if (ATOMID(type) == ATOMID("moov")) { + ExpectChildAtom("mvhd", Required, OnlyOne); + ExpectChildAtom("iods", Optional, OnlyOne); + ExpectChildAtom("trak", Required, Many); + ExpectChildAtom("udta", Optional, Many); + ExpectChildAtom("mvex", Optional, OnlyOne); + + } else if (ATOMID(type) == ATOMID("mvex")) { + ExpectChildAtom("trex", Required, Many); + + /* + * n??? + */ + } else if (ATOMID(type) == ATOMID("nmhd")) { + AddVersionAndFlags(); + + } else if (ATOMID(type) == ATOMID("nump")) { + AddProperty( // packets sent + new MP4Integer64Property("packets")); + /* + * o??? + */ + } else if (ATOMID(type) == ATOMID("odkm")) { + AddVersionAndFlags(); + ExpectChildAtom("ohdr", Required, OnlyOne); + /* + * p??? + */ + } else if (ATOMID(type) == ATOMID("payt")) { + AddProperty(new MP4Integer32Property("payloadNumber")); + AddProperty(new MP4StringProperty("rtpMap", Counted)); + + } else if (ATOMID(type) == ATOMID("pinf")) { + ExpectChildAtom("frma", Required, OnlyOne); + } else if (ATOMID(type) == ATOMID("pmax")) { + AddProperty( // max packet size + new MP4Integer32Property("bytes")); + } else if (ATOMID(type) == ATOMID("pgap") || + ATOMID(type) == ATOMID("plID") || + ATOMID(type) == ATOMID("purd") || + ATOMID(type) == ATOMID("rtng")) { + ExpectChildAtom("data", Required, OnlyOne); + /* + * s??? + */ + } else if (ATOMID(type) == ATOMID("schi")) { + // not sure if this is child atoms or table of boxes + // get clarification on spec 9.1.2.5 + ExpectChildAtom("odkm", Optional, OnlyOne); + ExpectChildAtom("iKMS", Optional, OnlyOne); + ExpectChildAtom("iSFM", Optional, OnlyOne); + + } else if (ATOMID(type) == ATOMID("schm")) { + AddVersionAndFlags(); /* 0, 1 */ + AddProperty( /* 2 */ + new MP4Integer32Property("scheme_type")); + AddProperty( /* 3 */ + new MP4Integer32Property("scheme_version")); + // browser URI if flags set, TODO + + } else if (ATOMID(type) == ATOMID("sinf")) { + ExpectChildAtom("frma", Required, OnlyOne); + ExpectChildAtom("imif", Optional, OnlyOne); + ExpectChildAtom("schm", Optional, OnlyOne); + ExpectChildAtom("schi", Optional, OnlyOne); + + } else if (ATOMID(type) == ATOMID("smhd")) { + AddVersionAndFlags(); + AddReserved("reserved", 4); + + } else if (ATOMID(type) == ATOMID("snro")) { + AddProperty(new MP4Integer32Property("offset")); + + } else if (ATOMID(type) == ATOMID("stco")) { + AddVersionAndFlags(); + + MP4Integer32Property* pCount = new MP4Integer32Property("entryCount"); + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty("entries", pCount); + AddProperty(pTable); + + pTable->AddProperty(new MP4Integer32Property("chunkOffset")); + + } else if (ATOMID(type) == ATOMID("stsh")) { + AddVersionAndFlags(); + + MP4Integer32Property* pCount = new MP4Integer32Property("entryCount"); + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty("entries", pCount); + AddProperty(pTable); + + pTable->AddProperty(new MP4Integer32Property("shadowedSampleNumber")); + pTable->AddProperty(new MP4Integer32Property("syncSampleNumber")); + + } else if (ATOMID(type) == ATOMID("stss")) { + AddVersionAndFlags(); + + MP4Integer32Property* pCount = new MP4Integer32Property("entryCount"); + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty("entries", pCount); + AddProperty(pTable); + + pTable->AddProperty(new MP4Integer32Property("sampleNumber")); + + } else if (ATOMID(type) == ATOMID("stts")) { + AddVersionAndFlags(); + MP4Integer32Property* pCount = new MP4Integer32Property("entryCount"); + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty("entries", pCount); + AddProperty(pTable); + + pTable->AddProperty(new MP4Integer32Property("sampleCount")); + pTable->AddProperty(new MP4Integer32Property("sampleDelta")); + } else if (ATOMID(type) == ATOMID("sfID") || + ATOMID(type) == ATOMID("stik")) { + ExpectChildAtom("data", Required, OnlyOne); + /* + * t??? + */ + } else if (ATOMID(type) == ATOMID("tims")) { + AddProperty( + new MP4Integer32Property("timeScale")); + + } else if (ATOMID(type) == ATOMID("tmin")) { + AddProperty( // min relative xmit time + new MP4Integer32Property("milliSecs")); + + } else if (ATOMID(type) == ATOMID("tmax")) { + AddProperty( // max relative xmit time + new MP4Integer32Property("milliSecs")); + + } else if (ATOMID(type) == ATOMID("tmpo")) { // iTunes + ExpectChildAtom("data", Required, OnlyOne); + + } else if (ATOMID(type) == ATOMID("traf")) { + ExpectChildAtom("tfhd", Required, OnlyOne); + ExpectChildAtom("trun", Optional, Many); + + } else if (ATOMID(type) == ATOMID("trak")) { + ExpectChildAtom("tkhd", Required, OnlyOne); + ExpectChildAtom("tref", Optional, OnlyOne); + ExpectChildAtom("edts", Optional, OnlyOne); + ExpectChildAtom("mdia", Required, OnlyOne); + ExpectChildAtom("udta", Optional, Many); + + } else if (ATOMID(type) == ATOMID("tref")) { + ExpectChildAtom("chap", Optional, OnlyOne); + ExpectChildAtom("dpnd", Optional, OnlyOne); + ExpectChildAtom("hint", Optional, OnlyOne); + ExpectChildAtom("ipir", Optional, OnlyOne); + ExpectChildAtom("mpod", Optional, OnlyOne); + ExpectChildAtom("sync", Optional, OnlyOne); + + } else if (ATOMID(type) == ATOMID("trex")) { + AddVersionAndFlags(); /* 0, 1 */ + AddProperty( /* 2 */ + new MP4Integer32Property("trackId")); + AddProperty( /* 3 */ + new MP4Integer32Property("defaultSampleDesriptionIndex")); + AddProperty( /* 4 */ + new MP4Integer32Property("defaultSampleDuration")); + AddProperty( /* 5 */ + new MP4Integer32Property("defaultSampleSize")); + AddProperty( /* 6 */ + new MP4Integer32Property("defaultSampleFlags")); + + } else if (ATOMID(type) == ATOMID("rate")) { + ExpectChildAtom("data", Optional, OnlyOne); + + } else if (ATOMID(type) == ATOMID("trkn")) { // iTunes + ExpectChildAtom("data", Required, OnlyOne); + + } else if (ATOMID(type) == ATOMID("trpy") || + ATOMID(type) == ATOMID("tpyl")) { + AddProperty( // bytes sent including RTP headers + new MP4Integer64Property("bytes")); + + } else if (ATOMID(type) == ATOMID("tsro")) { + AddProperty( + new MP4Integer32Property("offset")); + } else if (ATOMID(type) == ATOMID("wave")) { + ExpectChildAtom("esds", Required, OnlyOne); + /* + * copyright??? + */ + } else if (ATOMID(type) == ATOMID(art) || + ATOMID(type) == ATOMID(wrt) || + ATOMID(type) == ATOMID(alb) || + ATOMID(type) == ATOMID(day) || + ATOMID(type) == ATOMID(too) || + ATOMID(type) == ATOMID(gen) || + ATOMID(type) == ATOMID(grp)) { /* Apple iTunes */ + ExpectChildAtom("data", Required, OnlyOne); + /* + * ---- + */ + } else if (ATOMID(type) == ATOMID("----")) { /* Apple iTunes */ + ExpectChildAtom("mean", Required, OnlyOne); + ExpectChildAtom("name", Required, OnlyOne); + ExpectChildAtom("data", Required, OnlyOne); + } else { + /* + * default - unknown type + */ + SetUnknownType(true); + } + +} diff --git a/Src/external_dependencies/libmp4v2/atom_stbl.cpp b/Src/external_dependencies/libmp4v2/atom_stbl.cpp new file mode 100644 index 00000000..b051d27f --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_stbl.cpp @@ -0,0 +1,58 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4StblAtom::MP4StblAtom() + : MP4Atom("stbl") +{ + ExpectChildAtom("stsd", Required, OnlyOne); + ExpectChildAtom("stts", Required, OnlyOne); + ExpectChildAtom("ctts", Optional, OnlyOne); + ExpectChildAtom("stsz", Required, OnlyOne); + ExpectChildAtom("stz2", Optional, OnlyOne); + ExpectChildAtom("stsc", Required, OnlyOne); + ExpectChildAtom("stco", Optional, OnlyOne); + ExpectChildAtom("co64", Optional, OnlyOne); + ExpectChildAtom("stss", Optional, OnlyOne); + ExpectChildAtom("stsh", Optional, OnlyOne); + ExpectChildAtom("stdp", Optional, OnlyOne); +} + +void MP4StblAtom::Generate() +{ + // as usual + MP4Atom::Generate(); + + // but we also need one of the chunk offset atoms + MP4Atom* pChunkOffsetAtom; + if (m_pFile->Use64Bits(GetType())) { + pChunkOffsetAtom = CreateAtom("co64"); + } else { + pChunkOffsetAtom = CreateAtom("stco"); + } + + AddChildAtom(pChunkOffsetAtom); + + // and ask it to self generate + pChunkOffsetAtom->Generate(); +} + diff --git a/Src/external_dependencies/libmp4v2/atom_stco.cpp b/Src/external_dependencies/libmp4v2/atom_stco.cpp new file mode 100644 index 00000000..7cedf4cf --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_stco.cpp @@ -0,0 +1,38 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4StcoAtom::MP4StcoAtom() + : MP4Atom("stco") +{ + AddVersionAndFlags(); + + MP4Integer32Property* pCount = + new MP4Integer32Property("entryCount"); + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty("entries", pCount); + AddProperty(pTable); + + pTable->AddProperty( + new MP4Integer32Property("chunkOffset")); +} diff --git a/Src/external_dependencies/libmp4v2/atom_stdp.cpp b/Src/external_dependencies/libmp4v2/atom_stdp.cpp new file mode 100644 index 00000000..ea821217 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_stdp.cpp @@ -0,0 +1,49 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4StdpAtom::MP4StdpAtom() + : MP4Atom("stdp") +{ + AddVersionAndFlags(); + + MP4Integer32Property* pCount = + new MP4Integer32Property("entryCount"); + pCount->SetImplicit(); + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty("entries", pCount); + AddProperty(pTable); + + pTable->AddProperty( + new MP4Integer16Property("priority")); +} + +void MP4StdpAtom::Read() +{ + // table entry count computed from atom size + ((MP4Integer32Property*)m_pProperties[2])->SetReadOnly(false); + ((MP4Integer32Property*)m_pProperties[2])->SetValue((m_size - 4) / 2); + ((MP4Integer32Property*)m_pProperties[2])->SetReadOnly(true); + + MP4Atom::Read(); +} diff --git a/Src/external_dependencies/libmp4v2/atom_stsc.cpp b/Src/external_dependencies/libmp4v2/atom_stsc.cpp new file mode 100644 index 00000000..d6aeff55 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_stsc.cpp @@ -0,0 +1,78 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4StscAtom::MP4StscAtom() + : MP4Atom("stsc") +{ + AddVersionAndFlags(); + + MP4Integer32Property* pCount = + new MP4Integer32Property("entryCount"); + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty("entries", pCount); + AddProperty(pTable); + + pTable->AddProperty( + new MP4Integer32Property("firstChunk")); + pTable->AddProperty( + new MP4Integer32Property("samplesPerChunk")); + pTable->AddProperty( + new MP4Integer32Property("sampleDescriptionIndex")); + + // As an optimization we add an implicit property to this table, + // "firstSample" that corresponds to the first sample of the firstChunk + MP4Integer32Property* pSample = + new MP4Integer32Property("firstSample"); + pSample->SetImplicit(); + pTable->AddProperty(pSample); +} + +void MP4StscAtom::Read() +{ + // Read as usual + MP4Atom::Read(); + + // Compute the firstSample values for later use + u_int32_t count = + ((MP4Integer32Property*)m_pProperties[2])->GetValue(); + + MP4Integer32Property* pFirstChunk = (MP4Integer32Property*) + ((MP4TableProperty*)m_pProperties[3])->GetProperty(0); + MP4Integer32Property* pSamplesPerChunk = (MP4Integer32Property*) + ((MP4TableProperty*)m_pProperties[3])->GetProperty(1); + MP4Integer32Property* pFirstSample = (MP4Integer32Property*) + ((MP4TableProperty*)m_pProperties[3])->GetProperty(3); + + MP4SampleId sampleId = 1; + + for (u_int32_t i = 0; i < count; i++) { + pFirstSample->SetValue(sampleId, i); + + if (i < count - 1) { + sampleId += + (pFirstChunk->GetValue(i+1) - pFirstChunk->GetValue(i)) + * pSamplesPerChunk->GetValue(i); + } + } +} diff --git a/Src/external_dependencies/libmp4v2/atom_stsd.cpp b/Src/external_dependencies/libmp4v2/atom_stsd.cpp new file mode 100644 index 00000000..442549ef --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_stsd.cpp @@ -0,0 +1,74 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001 - 2004. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + * Alix Marchandise-Franquet alix@cisco.com + * Ximpo Group Ltd. mp4v2@ximpo.com + */ + +#include "mp4common.h" + +MP4StsdAtom::MP4StsdAtom() + : MP4Atom("stsd") +{ + AddVersionAndFlags(); + + MP4Integer32Property* pCount = + new MP4Integer32Property("entryCount"); + pCount->SetReadOnly(); + AddProperty(pCount); + + ExpectChildAtom("mp4a", Optional, Many); + ExpectChildAtom("enca", Optional, Many); + ExpectChildAtom("mp4s", Optional, Many); + ExpectChildAtom("mp4v", Optional, Many); + ExpectChildAtom("encv", Optional, Many); + ExpectChildAtom("rtp ", Optional, Many); + ExpectChildAtom("samr", Optional, Many); // For AMR-NB + ExpectChildAtom("sawb", Optional, Many); // For AMR-WB + ExpectChildAtom("s263", Optional, Many); // For H.263 + ExpectChildAtom("avc1", Optional, Many); + ExpectChildAtom("alac", Optional, Many); + ExpectChildAtom("text", Optional, Many); +} + +void MP4StsdAtom::Read() +{ + /* do the usual read */ + MP4Atom::Read(); + + // check that number of children == entryCount + MP4Integer32Property* pCount = + (MP4Integer32Property*)m_pProperties[2]; + + if (m_pChildAtoms.Size() != pCount->GetValue()) { + VERBOSE_READ(GetVerbosity(), + printf("Warning: stsd inconsistency with number of entries")); + + /* fix it */ + pCount->SetReadOnly(false); + pCount->SetValue(m_pChildAtoms.Size()); + pCount->SetReadOnly(true); + } +} diff --git a/Src/external_dependencies/libmp4v2/atom_stsh.cpp b/Src/external_dependencies/libmp4v2/atom_stsh.cpp new file mode 100644 index 00000000..89ecaeab --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_stsh.cpp @@ -0,0 +1,40 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4StshAtom::MP4StshAtom() + : MP4Atom("stsh") +{ + AddVersionAndFlags(); + + MP4Integer32Property* pCount = + new MP4Integer32Property("entryCount"); + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty("entries", pCount); + AddProperty(pTable); + + pTable->AddProperty( + new MP4Integer32Property("shadowedSampleNumber")); + pTable->AddProperty( + new MP4Integer32Property("syncSampleNumber")); +} diff --git a/Src/external_dependencies/libmp4v2/atom_stss.cpp b/Src/external_dependencies/libmp4v2/atom_stss.cpp new file mode 100644 index 00000000..d1632194 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_stss.cpp @@ -0,0 +1,38 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4StssAtom::MP4StssAtom() + : MP4Atom("stss") +{ + AddVersionAndFlags(); + + MP4Integer32Property* pCount = + new MP4Integer32Property("entryCount"); + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty("entries", pCount); + AddProperty(pTable); + + pTable->AddProperty( + new MP4Integer32Property("sampleNumber")); +} diff --git a/Src/external_dependencies/libmp4v2/atom_stsz.cpp b/Src/external_dependencies/libmp4v2/atom_stsz.cpp new file mode 100644 index 00000000..572e4ba1 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_stsz.cpp @@ -0,0 +1,69 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4StszAtom::MP4StszAtom() + : MP4Atom("stsz") +{ + AddVersionAndFlags(); /* 0, 1 */ + + AddProperty( /* 2 */ + new MP4Integer32Property("sampleSize")); + + MP4Integer32Property* pCount = + new MP4Integer32Property("sampleCount"); + AddProperty(pCount); /* 3 */ + + MP4TableProperty* pTable = new MP4TableProperty("entries", pCount); + AddProperty(pTable); /* 4 */ + + pTable->AddProperty( /* 4/0 */ + new MP4Integer32Property("entrySize")); +} + +void MP4StszAtom::Read() +{ + ReadProperties(0, 4); + + u_int32_t sampleSize = + ((MP4Integer32Property*)m_pProperties[2])->GetValue(); + + // only attempt to read entries table if sampleSize is zero + // i.e sample size is not constant + m_pProperties[4]->SetImplicit(sampleSize != 0); + + ReadProperties(4); + + Skip(); // to end of atom +} + +void MP4StszAtom::Write() +{ + u_int32_t sampleSize = + ((MP4Integer32Property*)m_pProperties[2])->GetValue(); + + // only attempt to write entries table if sampleSize is zero + // i.e sample size is not constant + m_pProperties[4]->SetImplicit(sampleSize != 0); + + MP4Atom::Write(); +} diff --git a/Src/external_dependencies/libmp4v2/atom_stts.cpp b/Src/external_dependencies/libmp4v2/atom_stts.cpp new file mode 100644 index 00000000..93861c8b --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_stts.cpp @@ -0,0 +1,40 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4SttsAtom::MP4SttsAtom() + : MP4Atom("stts") +{ + AddVersionAndFlags(); + + MP4Integer32Property* pCount = + new MP4Integer32Property("entryCount"); + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty("entries", pCount); + AddProperty(pTable); + + pTable->AddProperty( + new MP4Integer32Property("sampleCount")); + pTable->AddProperty( + new MP4Integer32Property("sampleDelta")); +} diff --git a/Src/external_dependencies/libmp4v2/atom_stz2.cpp b/Src/external_dependencies/libmp4v2/atom_stz2.cpp new file mode 100644 index 00000000..5bbaa5ab --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_stz2.cpp @@ -0,0 +1,95 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +/* + * This is used for the 4 bit sample size below. We need the sampleCount + * to be correct for the number of samples, but the table size needs to + * be correct to read and write it. + */ + +class MP4HalfSizeTableProperty : public MP4TableProperty +{ +public: + MP4HalfSizeTableProperty(char *name, MP4IntegerProperty *pCountProperty) : + MP4TableProperty(name, pCountProperty) {}; + + // The count is half the actual size + u_int32_t GetCount() { + return (m_pCountProperty->GetValue() + 1)/ 2; + }; + void SetCount(u_int32_t count) { + m_pCountProperty->SetValue(count * 2); + }; +}; + + +MP4Stz2Atom::MP4Stz2Atom() + : MP4Atom("stz2") +{ + AddVersionAndFlags(); /* 0, 1 */ + + AddReserved("reserved", 3); /* 2 */ + + AddProperty( /* 3 */ + new MP4Integer8Property("fieldSize")); + + MP4Integer32Property* pCount = + new MP4Integer32Property("sampleCount"); + AddProperty(pCount); /* 4 */ + +} + +void MP4Stz2Atom::Read() +{ + ReadProperties(0, 4); + + uint8_t fieldSize = + ((MP4Integer8Property *)m_pProperties[3])->GetValue(); + // uint32_t sampleCount = 0; + + MP4Integer32Property* pCount = + (MP4Integer32Property *)m_pProperties[4]; + + MP4TableProperty *pTable; + if (fieldSize != 4) { + pTable = new MP4TableProperty("entries", pCount); + } else { + // 4 bit field size uses a special table. + pTable = new MP4HalfSizeTableProperty("entries", pCount); + } + + AddProperty(pTable); + + if (fieldSize == 16) { + pTable->AddProperty( /* 5/0 */ + new MP4Integer16Property("entrySize")); + } else { + pTable->AddProperty( /* 5/0 */ + new MP4Integer8Property("entrySize")); + } + + ReadProperties(4); + + Skip(); // to end of atom +} + diff --git a/Src/external_dependencies/libmp4v2/atom_text.cpp b/Src/external_dependencies/libmp4v2/atom_text.cpp new file mode 100644 index 00000000..290e73d7 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_text.cpp @@ -0,0 +1,128 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * Contributer has declined to give copyright information, and gives + * it freely to the world. + */ + +#include "mp4common.h" + +MP4TextAtom::MP4TextAtom() + : MP4Atom("text") +{ + // The atom type "text" is used in two complete unrelated ways + // i.e. it's real two atoms with the same name + // To handle that we need to postpone property creation until + // we know who our parent atom is (stsd or gmhd) which gives us + // the context info we need to know who we are +} + +void MP4TextAtom::AddPropertiesStsdType() +{ + + AddReserved("reserved1", 6); /* 0 */ + + AddProperty(new MP4Integer16Property("dataReferenceIndex"));/* 1 */ + + AddProperty(new MP4Integer32Property("displayFlags")); /* 2 */ + AddProperty(new MP4Integer32Property("textJustification")); /* 3 */ + + AddProperty(new MP4Integer16Property("bgColorRed")); /* 4 */ + AddProperty(new MP4Integer16Property("bgColorGreen")); /* 5 */ + AddProperty(new MP4Integer16Property("bgColorBlue")); /* 6 */ + + AddProperty(new MP4Integer16Property("defTextBoxTop")); /* 7 */ + AddProperty(new MP4Integer16Property("defTextBoxLeft")); /* 8 */ + AddProperty(new MP4Integer16Property("defTextBoxBottom")); /* 9 */ + AddProperty(new MP4Integer16Property("defTextBoxRight")); /* 10 */ + + AddReserved("reserved2", 8); /* 11 */ + + AddProperty(new MP4Integer16Property("fontNumber")); /* 12 */ + AddProperty(new MP4Integer16Property("fontFace")); /* 13 */ + + AddReserved("reserved3", 1); /* 14 */ + AddReserved("reserved4", 2); /* 15 */ + + AddProperty(new MP4Integer16Property("foreColorRed")); /* 16 */ + AddProperty(new MP4Integer16Property("foreColorGreen")); /* 17 */ + AddProperty(new MP4Integer16Property("foreColorBlue")); /* 18 */ + +} + +void MP4TextAtom::AddPropertiesGmhdType() +{ + + AddProperty(new MP4BytesProperty("textData", 36)); /* 0 */ + +} + + +void MP4TextAtom::Generate() +{ + + if (!strcmp(m_pParentAtom->GetType(), "stsd")) { + AddPropertiesStsdType(); + GenerateStsdType(); + } else if (!strcmp(m_pParentAtom->GetType(), "gmhd")) { + AddPropertiesGmhdType(); + GenerateGmhdType(); + } else { + VERBOSE_WARNING(m_pFile->GetVerbosity(), + printf("Warning: text atom in unexpected context, can not generate")); + } + +} + +void MP4TextAtom::GenerateStsdType() +{ + // generate children + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); + + ((MP4Integer32Property*)m_pProperties[2])->SetValue(1); + ((MP4Integer32Property*)m_pProperties[3])->SetValue(1); + +} + +void MP4TextAtom::GenerateGmhdType() +{ + MP4Atom::Generate(); + + // property 0 has non-zero fixed values + static u_int8_t textData[36] = { + 0x00, 0x01, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x01, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x40, 0x00, + 0x00, 0x00, + }; + ((MP4BytesProperty*)m_pProperties[0])->SetValue(textData, sizeof(textData)); + +} + + diff --git a/Src/external_dependencies/libmp4v2/atom_tfhd.cpp b/Src/external_dependencies/libmp4v2/atom_tfhd.cpp new file mode 100644 index 00000000..394f6a47 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_tfhd.cpp @@ -0,0 +1,69 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4TfhdAtom::MP4TfhdAtom() + : MP4Atom("tfhd") +{ + AddVersionAndFlags(); /* 0, 1 */ + AddProperty( /* 2 */ + new MP4Integer32Property("trackId")); +} + +void MP4TfhdAtom::AddProperties(u_int32_t flags) +{ + if (flags & 0x01) { + // note this property is signed 64! + AddProperty( + new MP4Integer64Property("baseDataOffset")); + } + if (flags & 0x02) { + AddProperty( + new MP4Integer32Property("sampleDescriptionIndex")); + } + if (flags & 0x08) { + AddProperty( + new MP4Integer32Property("defaultSampleDuration")); + } + if (flags & 0x10) { + AddProperty( + new MP4Integer32Property("defaultSampleSize")); + } + if (flags & 0x20) { + AddProperty( + new MP4Integer32Property("defaultSampleFlags")); + } +} + +void MP4TfhdAtom::Read() +{ + /* read atom version, flags, and trackId */ + ReadProperties(0, 3); + + /* need to create the properties based on the atom flags */ + AddProperties(GetFlags()); + + /* now we can read the remaining properties */ + ReadProperties(3); + + Skip(); // to end of atom +} diff --git a/Src/external_dependencies/libmp4v2/atom_tims.cpp b/Src/external_dependencies/libmp4v2/atom_tims.cpp new file mode 100644 index 00000000..c70027fc --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_tims.cpp @@ -0,0 +1,30 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4TimsAtom::MP4TimsAtom() + : MP4Atom("tims") +{ + AddProperty( + new MP4Integer32Property("timeScale")); +} + diff --git a/Src/external_dependencies/libmp4v2/atom_tkhd.cpp b/Src/external_dependencies/libmp4v2/atom_tkhd.cpp new file mode 100644 index 00000000..373f475f --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_tkhd.cpp @@ -0,0 +1,130 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4TkhdAtom::MP4TkhdAtom() + : MP4Atom("tkhd") +{ + AddVersionAndFlags(); +} + +void MP4TkhdAtom::AddProperties(u_int8_t version) +{ + if (version == 1) { + AddProperty( /* 2 */ + new MP4Integer64Property("creationTime")); + AddProperty( /* 3 */ + new MP4Integer64Property("modificationTime")); + } else { // version == 0 + AddProperty( /* 2 */ + new MP4Integer32Property("creationTime")); + AddProperty( /* 3 */ + new MP4Integer32Property("modificationTime")); + } + + AddProperty( /* 4 */ + new MP4Integer32Property("trackId")); + AddReserved("reserved1", 4); /* 5 */ + + if (version == 1) { + AddProperty( /* 6 */ + new MP4Integer64Property("duration")); + } else { + AddProperty( /* 6 */ + new MP4Integer32Property("duration")); + } + + AddReserved("reserved2", 12); /* 7 */ + + MP4Float32Property* pProp; + + pProp = new MP4Float32Property("volume"); + pProp->SetFixed16Format(); + AddProperty(pProp); /* 8 */ + + AddReserved("reserved3", 2); /* 9 */ + + AddProperty(new MP4BytesProperty("matrix", 36)); /* 10 */ + + pProp = new MP4Float32Property("width"); + pProp->SetFixed32Format(); + AddProperty(pProp); /* 11 */ + + pProp = new MP4Float32Property("height"); + pProp->SetFixed32Format(); + AddProperty(pProp); /* 12 */ +} + +void MP4TkhdAtom::Generate() +{ + u_int8_t version = m_pFile->Use64Bits(GetType()) ? 1 : 0; + SetVersion(version); + AddProperties(version); + + MP4Atom::Generate(); + + // set creation and modification times + MP4Timestamp now = MP4GetAbsTimestamp(); + if (version == 1) { + ((MP4Integer64Property*)m_pProperties[2])->SetValue(now); + ((MP4Integer64Property*)m_pProperties[3])->SetValue(now); + } else { + ((MP4Integer32Property*)m_pProperties[2])->SetValue(now); + ((MP4Integer32Property*)m_pProperties[3])->SetValue(now); + } + + // property "matrix" has non-zero fixed values + // this default identity matrix indicates no transformation, i.e. + // 1, 0, 0 + // 0, 1, 0 + // 0, 0, 1 + // see http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap4/chapter_5_section_4.html + + static u_int8_t matrix[36] = { + 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, + }; + + ((MP4BytesProperty*)m_pProperties[10])-> + SetValue(matrix, sizeof(matrix)); +} + +void MP4TkhdAtom::Read() +{ + /* read atom version */ + ReadProperties(0, 1); + + /* need to create the properties based on the atom version */ + AddProperties(GetVersion()); + + /* now we can read the remaining properties */ + ReadProperties(1); + + Skip(); // to end of atom +} diff --git a/Src/external_dependencies/libmp4v2/atom_tmax.cpp b/Src/external_dependencies/libmp4v2/atom_tmax.cpp new file mode 100644 index 00000000..5b787830 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_tmax.cpp @@ -0,0 +1,29 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4TmaxAtom::MP4TmaxAtom() + : MP4Atom("tmax") +{ + AddProperty( // max relative xmit time + new MP4Integer32Property("milliSecs")); +} diff --git a/Src/external_dependencies/libmp4v2/atom_tmin.cpp b/Src/external_dependencies/libmp4v2/atom_tmin.cpp new file mode 100644 index 00000000..cb4bd968 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_tmin.cpp @@ -0,0 +1,29 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4TminAtom::MP4TminAtom() + : MP4Atom("tmin") +{ + AddProperty( // min relative xmit time + new MP4Integer32Property("milliSecs")); +} diff --git a/Src/external_dependencies/libmp4v2/atom_tpyl.cpp b/Src/external_dependencies/libmp4v2/atom_tpyl.cpp new file mode 100644 index 00000000..fba87e8f --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_tpyl.cpp @@ -0,0 +1,29 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4TpylAtom::MP4TpylAtom() + : MP4Atom("tpyl") +{ + AddProperty( // bytes sent of RTP payload data + new MP4Integer64Property("bytes")); +} diff --git a/Src/external_dependencies/libmp4v2/atom_traf.cpp b/Src/external_dependencies/libmp4v2/atom_traf.cpp new file mode 100644 index 00000000..cda8d2ab --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_traf.cpp @@ -0,0 +1,30 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4TrafAtom::MP4TrafAtom() + : MP4Atom("traf") +{ + ExpectChildAtom("tfhd", Required, OnlyOne); + ExpectChildAtom("trun", Optional, Many); +} + diff --git a/Src/external_dependencies/libmp4v2/atom_trak.cpp b/Src/external_dependencies/libmp4v2/atom_trak.cpp new file mode 100644 index 00000000..d11999d5 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_trak.cpp @@ -0,0 +1,32 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4TrakAtom::MP4TrakAtom() + : MP4Atom("trak") +{ + ExpectChildAtom("tkhd", Required, OnlyOne); + ExpectChildAtom("tref", Optional, OnlyOne); + ExpectChildAtom("edts", Optional, OnlyOne); + ExpectChildAtom("mdia", Required, OnlyOne); + ExpectChildAtom("udta", Optional, Many); +} diff --git a/Src/external_dependencies/libmp4v2/atom_tref.cpp b/Src/external_dependencies/libmp4v2/atom_tref.cpp new file mode 100644 index 00000000..4bd7803a --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_tref.cpp @@ -0,0 +1,32 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4TrefAtom::MP4TrefAtom() + : MP4Atom("tref") +{ + ExpectChildAtom("dpnd", Optional, OnlyOne); + ExpectChildAtom("hint", Optional, OnlyOne); + ExpectChildAtom("ipir", Optional, OnlyOne); + ExpectChildAtom("mpod", Optional, OnlyOne); + ExpectChildAtom("sync", Optional, OnlyOne); +} diff --git a/Src/external_dependencies/libmp4v2/atom_treftype.cpp b/Src/external_dependencies/libmp4v2/atom_treftype.cpp new file mode 100644 index 00000000..c8c88231 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_treftype.cpp @@ -0,0 +1,47 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4TrefTypeAtom::MP4TrefTypeAtom(const char* type) + : MP4Atom(type) +{ + MP4Integer32Property* pCount = + new MP4Integer32Property("entryCount"); + pCount->SetImplicit(); + AddProperty(pCount); /* 0 */ + + MP4TableProperty* pTable = new MP4TableProperty("entries", pCount); + AddProperty(pTable); /* 1 */ + + pTable->AddProperty( /* 1, 0 */ + new MP4Integer32Property("trackId")); +} + +void MP4TrefTypeAtom::Read() +{ + // table entry count computed from atom size + ((MP4Integer32Property*)m_pProperties[0])->SetReadOnly(false); + ((MP4Integer32Property*)m_pProperties[0])->SetValue(m_size / 4); + ((MP4Integer32Property*)m_pProperties[0])->SetReadOnly(true); + + MP4Atom::Read(); +} diff --git a/Src/external_dependencies/libmp4v2/atom_trex.cpp b/Src/external_dependencies/libmp4v2/atom_trex.cpp new file mode 100644 index 00000000..0c46070f --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_trex.cpp @@ -0,0 +1,39 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4TrexAtom::MP4TrexAtom() + : MP4Atom("trex") +{ + AddVersionAndFlags(); /* 0, 1 */ + AddProperty( /* 2 */ + new MP4Integer32Property("trackId")); + AddProperty( /* 3 */ + new MP4Integer32Property("defaultSampleDesriptionIndex")); + AddProperty( /* 4 */ + new MP4Integer32Property("defaultSampleDuration")); + AddProperty( /* 5 */ + new MP4Integer32Property("defaultSampleSize")); + AddProperty( /* 6 */ + new MP4Integer32Property("defaultSampleFlags")); +} + diff --git a/Src/external_dependencies/libmp4v2/atom_trpy.cpp b/Src/external_dependencies/libmp4v2/atom_trpy.cpp new file mode 100644 index 00000000..871d9a4d --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_trpy.cpp @@ -0,0 +1,29 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4TrpyAtom::MP4TrpyAtom() + : MP4Atom("trpy") +{ + AddProperty( // bytes sent including RTP headers + new MP4Integer64Property("bytes")); +} diff --git a/Src/external_dependencies/libmp4v2/atom_trun.cpp b/Src/external_dependencies/libmp4v2/atom_trun.cpp new file mode 100644 index 00000000..1580ae1e --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_trun.cpp @@ -0,0 +1,79 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4TrunAtom::MP4TrunAtom() + : MP4Atom("trun") +{ + AddVersionAndFlags(); /* 0, 1 */ + AddProperty( /* 2 */ + new MP4Integer32Property("sampleCount")); +} + +void MP4TrunAtom::AddProperties(u_int32_t flags) +{ + if (flags & 0x01) { + // Note this is a signed 32 value + AddProperty( + new MP4Integer32Property("dataOffset")); + } + if (flags & 0x04) { + AddProperty( + new MP4Integer32Property("firstSampleFlags")); + } + + MP4TableProperty* pTable = + new MP4TableProperty("samples", + (MP4Integer32Property *)m_pProperties[2]); + AddProperty(pTable); + + if (flags & 0x100) { + pTable->AddProperty( + new MP4Integer32Property("sampleDuration")); + } + if (flags & 0x200) { + pTable->AddProperty( + new MP4Integer32Property("sampleSize")); + } + if (flags & 0x400) { + pTable->AddProperty( + new MP4Integer32Property("sampleFlags")); + } + if (flags & 0x800) { + pTable->AddProperty( + new MP4Integer32Property("sampleCompositionTimeOffset")); + } +} + +void MP4TrunAtom::Read() +{ + /* read atom version, flags, and sampleCount */ + ReadProperties(0, 3); + + /* need to create the properties based on the atom flags */ + AddProperties(GetFlags()); + + /* now we can read the remaining properties */ + ReadProperties(3); + + Skip(); // to end of atom +} diff --git a/Src/external_dependencies/libmp4v2/atom_tsro.cpp b/Src/external_dependencies/libmp4v2/atom_tsro.cpp new file mode 100644 index 00000000..b582cbb1 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_tsro.cpp @@ -0,0 +1,30 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4TsroAtom::MP4TsroAtom() + : MP4Atom("tsro") +{ + AddProperty( + new MP4Integer32Property("offset")); +} + diff --git a/Src/external_dependencies/libmp4v2/atom_udta.cpp b/Src/external_dependencies/libmp4v2/atom_udta.cpp new file mode 100644 index 00000000..f8a43a57 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_udta.cpp @@ -0,0 +1,50 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4UdtaAtom::MP4UdtaAtom() + : MP4Atom("udta") +{ + ExpectChildAtom("chpl", Optional, OnlyOne); + ExpectChildAtom("cprt", Optional, Many); + ExpectChildAtom("hnti", Optional, OnlyOne); + ExpectChildAtom("meta", Optional, OnlyOne); + ExpectChildAtom("\251cpy", Optional, OnlyOne); + ExpectChildAtom("\251des", Optional, OnlyOne); + ExpectChildAtom("\251nam", Optional, OnlyOne); + ExpectChildAtom("\251cmt", Optional, OnlyOne); + ExpectChildAtom("\251prd", Optional, OnlyOne); + /* + ExpectChildAtom("titl", Optional, OnlyOne); + ExpectChildAtom("gnre", Optional, OnlyOne); + ExpectChildAtom("perf", Optional, OnlyOne); + ExpectChildAtom("albm", Optional, OnlyOne);*/ +} + +void MP4UdtaAtom::Read() +{ + if (ATOMID(m_pParentAtom->GetType()) == ATOMID("trak")) { + ExpectChildAtom("hinf", Optional, OnlyOne); + } + + MP4Atom::Read(); +} diff --git a/Src/external_dependencies/libmp4v2/atom_url.cpp b/Src/external_dependencies/libmp4v2/atom_url.cpp new file mode 100644 index 00000000..c644b592 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_url.cpp @@ -0,0 +1,63 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4UrlAtom::MP4UrlAtom(const char *type) + : MP4Atom(type) +{ + AddVersionAndFlags(); + AddProperty(new MP4StringProperty("location")); +} + +void MP4UrlAtom::Read() +{ + // read the version and flags properties + ReadProperties(0, 2); + + // check if self-contained flag is set + if (!(GetFlags() & 1)) { + // if not then read url location + ReadProperties(2); + } + + Skip(); // to end of atom +} + +void MP4UrlAtom::Write() +{ + MP4StringProperty* pLocationProp = + (MP4StringProperty*)m_pProperties[2]; + + // if no url location has been set + // then set self-contained flag + // and don't attempt to write anything + if (pLocationProp->GetValue() == NULL) { + SetFlags(GetFlags() | 1); + pLocationProp->SetImplicit(true); + } else { + SetFlags(GetFlags() & 0xFFFFFE); + pLocationProp->SetImplicit(false); + } + + // write atom as usual + MP4Atom::Write(); +} diff --git a/Src/external_dependencies/libmp4v2/atom_urn.cpp b/Src/external_dependencies/libmp4v2/atom_urn.cpp new file mode 100644 index 00000000..609c29ed --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_urn.cpp @@ -0,0 +1,44 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4UrnAtom::MP4UrnAtom() + : MP4Atom("urn ") +{ + AddVersionAndFlags(); + AddProperty(new MP4StringProperty("name")); + AddProperty(new MP4StringProperty("location")); +} + +void MP4UrnAtom::Read() +{ + // read the version, flags, and name properties + ReadProperties(0, 3); + + // check if location is present + if (m_pFile->GetPosition() < GetEnd()) { + // read it + ReadProperties(3); + } + + Skip(); // to end of atom +} diff --git a/Src/external_dependencies/libmp4v2/atom_video.cpp b/Src/external_dependencies/libmp4v2/atom_video.cpp new file mode 100644 index 00000000..e91d1a00 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_video.cpp @@ -0,0 +1,78 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2004. All Rights Reserved. + * + * Contributor(s): + * Bill May wmay@cisco.com + */ + +#include "mp4common.h" + +MP4VideoAtom::MP4VideoAtom (const char *type) + : MP4Atom(type) +{ + AddReserved("reserved1", 6); /* 0 */ + + AddProperty( /* 1 */ + new MP4Integer16Property("dataReferenceIndex")); + + AddReserved("reserved2", 16); /* 2 */ + + AddProperty( /* 3 */ + new MP4Integer16Property("width")); + AddProperty( /* 4 */ + new MP4Integer16Property("height")); + + AddReserved("reserved3", 14); /* 5 */ + + MP4StringProperty* pProp = + new MP4StringProperty("compressorName"); + pProp->SetFixedLength(32); + pProp->SetValue(""); + AddProperty(pProp); /* 6 */ + + AddProperty(/* 7 */ + new MP4Integer16Property("depth")); + AddProperty(/* 8 */ + new MP4Integer16Property("colorTableId")); + ExpectChildAtom("smi ", Optional, OnlyOne); +} + +void MP4VideoAtom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); + + // property reserved3 has non-zero fixed values + static u_int8_t reserved3[14] = { + 0x00, 0x48, 0x00, 0x00, + 0x00, 0x48, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + }; + m_pProperties[5]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[5])-> + SetValue(reserved3, sizeof(reserved3)); + m_pProperties[5]->SetReadOnly(true); + + // depth and color table id values - should be set later + // as far as depth - color table is most likely 0xff + ((MP4IntegerProperty *)m_pProperties[7])->SetValue(0x18); + ((MP4IntegerProperty *)m_pProperties[8])->SetValue(0xffff); + +} + diff --git a/Src/external_dependencies/libmp4v2/atom_vmhd.cpp b/Src/external_dependencies/libmp4v2/atom_vmhd.cpp new file mode 100644 index 00000000..b3347efe --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atom_vmhd.cpp @@ -0,0 +1,37 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4VmhdAtom::MP4VmhdAtom() + : MP4Atom("vmhd") +{ + AddVersionAndFlags(); + AddReserved("reserved", 8); +} + +void MP4VmhdAtom::Generate() +{ + MP4Atom::Generate(); + + SetFlags(1); +} + diff --git a/Src/external_dependencies/libmp4v2/atoms.h b/Src/external_dependencies/libmp4v2/atoms.h new file mode 100644 index 00000000..e1eaf78c --- /dev/null +++ b/Src/external_dependencies/libmp4v2/atoms.h @@ -0,0 +1,426 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001 - 2005. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + * Ximpo Group Ltd. mp4v2@ximpo.com + * Bill May wmay@cisco.com + */ + +#ifndef __MP4_ATOMS_INCLUDED__ +#define __MP4_ATOMS_INCLUDED__ + +// declare all the atom subclasses +// i.e. spare us atom_xxxx.h for all the atoms +// +// The majority of atoms just need their own constructor declared +// Some atoms have a few special needs +// A small minority of atoms need lots of special handling + +class MP4RootAtom : public MP4Atom { +public: + MP4RootAtom(); + void BeginWrite(bool use64 = false); + void Write(); + void FinishWrite(bool use64 = false); + + void BeginOptimalWrite(); + void FinishOptimalWrite(); + +protected: + u_int32_t GetLastMdatIndex(); + void WriteAtomType(const char* type, bool onlyOne); +}; + +/*********************************************************************** + * Common atom classes - standard for anything that just contains atoms + * and non-maleable properties, treftype and url + ***********************************************************************/ +class MP4StandardAtom : public MP4Atom { + public: + MP4StandardAtom(const char *name); +}; + +class MP4TrefTypeAtom : public MP4Atom { +public: + MP4TrefTypeAtom(const char* type); + void Read(); +}; + +class MP4UrlAtom : public MP4Atom { +public: + MP4UrlAtom(const char *type="url "); + void Read(); + void Write(); +}; + +/*********************************************************************** + * Sound and Video atoms - use the generic atoms when possible + * (MP4SoundAtom and MP4VideoAtom) + ***********************************************************************/ +class MP4SoundAtom : public MP4Atom { + public: + MP4SoundAtom(const char *atomid); + void Generate(); + void Read(); +protected: + void AddProperties(u_int8_t version); +}; + +class MP4VideoAtom : public MP4Atom { + public: + MP4VideoAtom(const char *atomid); + void Generate(); +}; + +class MP4AmrAtom : public MP4Atom { + public: + MP4AmrAtom(const char *type); + void Generate(); +}; + +// H.264 atoms + +class MP4Avc1Atom : public MP4Atom { + public: + MP4Avc1Atom(); + void Generate(); +}; + +class MP4AvcCAtom : public MP4Atom { + public: + MP4AvcCAtom(); + void Generate(); + void Clone(MP4AvcCAtom *dstAtom); +}; + + +class MP4D263Atom : public MP4Atom { + public: + MP4D263Atom(); + void Generate(); + void Write(); +}; + +class MP4DamrAtom : public MP4Atom { + public: + MP4DamrAtom(); + void Generate(); +}; + +class MP4EncaAtom : public MP4Atom { +public: + MP4EncaAtom(); + void Generate(); +}; + +class MP4EncvAtom : public MP4Atom { +public: + MP4EncvAtom(); + void Generate(); +}; + +class MP4Mp4aAtom : public MP4Atom { +public: + MP4Mp4aAtom(); + void Generate(); +}; + +class MP4Mp4sAtom : public MP4Atom { +public: + MP4Mp4sAtom(); + void Generate(); +}; + +class MP4Mp4vAtom : public MP4Atom { +public: + MP4Mp4vAtom(); + void Generate(); +}; + + +class MP4S263Atom : public MP4Atom { + public: + MP4S263Atom(); + void Generate(); +}; + + + +/************************************************************************ + * Specialized Atoms + ************************************************************************/ + +class MP4DataAtom : public MP4Atom { +public: + MP4DataAtom(); + void Read(); +}; + +class MP4DrefAtom : public MP4Atom { +public: + MP4DrefAtom(); + void Read(); +}; + +class MP4ElstAtom : public MP4Atom { +public: + MP4ElstAtom(); + void Generate(); + void Read(); +protected: + void AddProperties(u_int8_t version); +}; + +class MP4FreeAtom : public MP4Atom { +public: + MP4FreeAtom(); + void Read(); + void Write(); +}; + +class MP4FtypAtom : public MP4Atom { +public: + MP4FtypAtom(); + void Generate(); + void Read(); +}; + +class MP4GminAtom : public MP4Atom { +public: + MP4GminAtom(); + void Generate(); +}; + +class MP4HdlrAtom : public MP4Atom { +public: + MP4HdlrAtom(); + void Read(); +}; + +class MP4HinfAtom : public MP4Atom { +public: + MP4HinfAtom(); + void Generate(); +}; + +class MP4HntiAtom : public MP4Atom { +public: + MP4HntiAtom(); + void Read(); +}; + + +class MP4MdatAtom : public MP4Atom { +public: + MP4MdatAtom(); + void Read(); + void Write(); +}; + +class MP4MdhdAtom : public MP4Atom { +public: + MP4MdhdAtom(); + void Generate(); + void Read(); +protected: + void AddProperties(u_int8_t version); +}; + +class MP4Meta1Atom : public MP4Atom { + public: + MP4Meta1Atom(const char *name); + void Read(); +}; + +class MP4Meta2Atom : public MP4Atom { + public: + MP4Meta2Atom(const char *name); + void Read(); +}; + +class MP4Meta3Atom : public MP4Atom { + public: + MP4Meta3Atom(const char *name); + void Read(); +}; + +class MP4Meta4Atom : public MP4Atom { + public: + MP4Meta4Atom(const char *name); + void Read(); +}; + +class MP4MvhdAtom : public MP4Atom { +public: + MP4MvhdAtom(); + void Generate(); + void Read(); +protected: + void AddProperties(u_int8_t version); +}; + +class MP4OhdrAtom : public MP4Atom { + public: + MP4OhdrAtom(); + ~MP4OhdrAtom(); + void Read(); +}; + +class MP4RtpAtom : public MP4Atom { +public: + MP4RtpAtom(); + void Generate(); + void Read(); + void Write(); + +protected: + void AddPropertiesStsdType(); + void AddPropertiesHntiType(); + + void GenerateStsdType(); + void GenerateHntiType(); + + void ReadStsdType(); + void ReadHntiType(); + + void WriteHntiType(); +}; + +class MP4SdpAtom : public MP4Atom { +public: + MP4SdpAtom(); + void Read(); + void Write(); +}; + +class MP4SmiAtom : public MP4Atom { + public: + MP4SmiAtom(void); + void Read(); +}; + +class MP4StblAtom : public MP4Atom { +public: + MP4StblAtom(); + void Generate(); +}; + +class MP4StdpAtom : public MP4Atom { +public: + MP4StdpAtom(); + void Read(); +}; + +class MP4StscAtom : public MP4Atom { +public: + MP4StscAtom(); + void Read(); +}; + +class MP4StsdAtom : public MP4Atom { +public: + MP4StsdAtom(); + void Read(); +}; + +class MP4StszAtom : public MP4Atom { +public: + MP4StszAtom(); + void Read(); + void Write(); +}; + +class MP4Stz2Atom : public MP4Atom { +public: + MP4Stz2Atom(); + void Read(); +}; + +class MP4TextAtom : public MP4Atom { +public: + MP4TextAtom(); + void Generate(); + +protected: + void AddPropertiesStsdType(); + void AddPropertiesGmhdType(); + + void GenerateStsdType(); + void GenerateGmhdType(); +}; + +class MP4TfhdAtom : public MP4Atom { +public: + MP4TfhdAtom(); + void Read(); +protected: + void AddProperties(u_int32_t flags); +}; + +class MP4TkhdAtom : public MP4Atom { +public: + MP4TkhdAtom(); + void Generate(); + void Read(); +protected: + void AddProperties(u_int8_t version); +}; +class MP4TrunAtom : public MP4Atom { +public: + MP4TrunAtom(); + void Read(); +protected: + void AddProperties(u_int32_t flags); +}; + +class MP4UdtaAtom : public MP4Atom { +public: + MP4UdtaAtom(); + void Read(); +}; + +class MP4UrnAtom : public MP4Atom { +public: + MP4UrnAtom(); + void Read(); +}; +class MP4VmhdAtom : public MP4Atom { +public: + MP4VmhdAtom(); + void Generate(); +}; + +class MP4HrefAtom : public MP4Atom { + public: + MP4HrefAtom(); + void Generate(void); +}; + +class MP4ChplAtom : public MP4Atom { + public: + MP4ChplAtom(); + void Generate(void); +}; + +#endif /* __MP4_ATOMS_INCLUDED__ */ diff --git a/Src/external_dependencies/libmp4v2/descriptors.cpp b/Src/external_dependencies/libmp4v2/descriptors.cpp new file mode 100644 index 00000000..e31f6708 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/descriptors.cpp @@ -0,0 +1,606 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4BaseDescriptor::MP4BaseDescriptor (u_int8_t tag) : MP4Descriptor(tag) +{ + switch (tag) { + case MP4ESIDIncDescrTag: + AddProperty( /* 0 */ + new MP4Integer32Property("id")); + break; + case MP4ESIDRefDescrTag: + AddProperty( /* 0 */ + new MP4Integer16Property("refIndex")); + break; + case MP4IPIPtrDescrTag: + AddProperty( /* 0 */ + new MP4Integer16Property("IPIESId")); + break; + case MP4SupplContentIdDescrTag: + AddProperty( /* 0 */ + new MP4BytesProperty("languageCode", 3)); + AddProperty( /* 1 */ + new MP4StringProperty("title", Counted)); + AddProperty( /* 2 */ + new MP4StringProperty("value", Counted)); + break; + case MP4IPMPPtrDescrTag: + AddProperty( /* 0 */ + new MP4Integer8Property("IPMPDescriptorId")); + break; + case MP4ExtProfileLevelDescrTag: + AddProperty( /* 0 */ + new MP4Integer8Property("profileLevelIndicationIndex")); + AddProperty( /* 1 */ + new MP4Integer8Property("ODProfileLevelIndication")); + AddProperty( /* 2 */ + new MP4Integer8Property("sceneProfileLevelIndication")); + AddProperty( /* 3 */ + new MP4Integer8Property("audioProfileLevelIndication")); + AddProperty( /* 4 */ + new MP4Integer8Property("visualProfileLevelIndication")); + AddProperty( /* 5 */ + new MP4Integer8Property("graphicsProfileLevelIndication")); + AddProperty( /* 6 */ + new MP4Integer8Property("MPEGJProfileLevelIndication")); + break; + default: + //MP4Printf("error in base descriptor - tag %u", tag); + break; + + } +} + +MP4BytesDescriptor::MP4BytesDescriptor (u_int8_t tag) : MP4Descriptor(tag) +{ + m_size_offset = 0; + m_bytes_index = 0; + if (tag >= MP4ExtDescrTagsStart && tag <= MP4ExtDescrTagsEnd) { + AddProperty( /* 0 */ + new MP4BytesProperty("data")); + } else { + switch (tag) { + case MP4DecSpecificDescrTag: + AddProperty( /* 0 */ + new MP4BytesProperty("info")); + // no change to m_size + break; + case MP4IPMPDescrTag: + AddProperty( /* 0 */ + new MP4Integer8Property("IPMPDescriptorId")); + AddProperty( /* 1 */ + new MP4Integer16Property("IPMPSType")); + AddProperty( /* 2 */ + new MP4BytesProperty("IPMPData")); + /* note: if IPMPSType == 0, IPMPData is an URL */ + m_size_offset = 3; + m_bytes_index = 2; + break; + case MP4RegistrationDescrTag: + AddProperty( /* 0 */ + new MP4Integer32Property("formatIdentifier")); + AddProperty( /* 1 */ + new MP4BytesProperty("additionalIdentificationInfo")); + m_size_offset = 4; + m_bytes_index = 1; + break; + default: + //MP4Printf("error in bytes descriptor - tag %u", tag); + break; + } + } +} + +void MP4BytesDescriptor::Read(MP4File *pFile) +{ + ReadHeader(pFile); + + /* byte properties need to know how long they are before reading */ + ((MP4BytesProperty*)m_pProperties[m_bytes_index])->SetValueSize(m_size - m_size_offset); + + ReadProperties(pFile); +} +MP4IODescriptor::MP4IODescriptor() + : MP4Descriptor(MP4FileIODescrTag) +{ + /* N.B. other member functions depend on the property indicies */ + AddProperty( /* 0 */ + new MP4BitfieldProperty("objectDescriptorId", 10)); + AddProperty( /* 1 */ + new MP4BitfieldProperty("URLFlag", 1)); + AddProperty( /* 2 */ + new MP4BitfieldProperty("includeInlineProfileLevelFlag", 1)); + AddProperty( /* 3 */ + new MP4BitfieldProperty("reserved", 4)); + AddProperty( /* 4 */ + new MP4StringProperty("URL", Counted)); + AddProperty( /* 5 */ + new MP4Integer8Property("ODProfileLevelId")); + AddProperty( /* 6 */ + new MP4Integer8Property("sceneProfileLevelId")); + AddProperty( /* 7 */ + new MP4Integer8Property("audioProfileLevelId")); + AddProperty( /* 8 */ + new MP4Integer8Property("visualProfileLevelId")); + AddProperty( /* 9 */ + new MP4Integer8Property("graphicsProfileLevelId")); + AddProperty( /* 10 */ + new MP4DescriptorProperty("esIds", + MP4ESIDIncDescrTag, 0, Required, Many)); + AddProperty( /* 11 */ + new MP4DescriptorProperty("ociDescr", + MP4OCIDescrTagsStart, MP4OCIDescrTagsEnd, Optional, Many)); + AddProperty( /* 12 */ + new MP4DescriptorProperty("ipmpDescrPtr", + MP4IPMPPtrDescrTag, 0, Optional, Many)); + AddProperty( /* 13 */ + new MP4DescriptorProperty("extDescr", + MP4ExtDescrTagsStart, MP4ExtDescrTagsEnd, Optional, Many)); + + SetReadMutate(2); +} + +void MP4IODescriptor::Generate() +{ + ((MP4BitfieldProperty*)m_pProperties[0])->SetValue(1); + ((MP4BitfieldProperty*)m_pProperties[3])->SetValue(0xF); + for (u_int32_t i = 5; i <= 9; i++) { + ((MP4Integer8Property*)m_pProperties[i])->SetValue(0xFF); + } +} + +void MP4IODescriptor::Mutate() +{ + bool urlFlag = ((MP4BitfieldProperty*)m_pProperties[1])->GetValue(); + + m_pProperties[4]->SetImplicit(!urlFlag); + for (u_int32_t i = 5; i <= 12; i++) { + m_pProperties[i]->SetImplicit(urlFlag); + } +} + +MP4ODescriptor::MP4ODescriptor() + : MP4Descriptor(MP4FileODescrTag) +{ + /* N.B. other member functions depend on the property indicies */ + AddProperty( /* 0 */ + new MP4BitfieldProperty("objectDescriptorId", 10)); + AddProperty( /* 1 */ + new MP4BitfieldProperty("URLFlag", 1)); + AddProperty( /* 2 */ + new MP4BitfieldProperty("reserved", 5)); + AddProperty( /* 3 */ + new MP4StringProperty("URL", Counted)); + AddProperty( /* 4 */ + new MP4DescriptorProperty("esIds", + MP4ESIDRefDescrTag, 0, Required, Many)); + AddProperty( /* 5 */ + new MP4DescriptorProperty("ociDescr", + MP4OCIDescrTagsStart, MP4OCIDescrTagsEnd, Optional, Many)); + AddProperty( /* 6 */ + new MP4DescriptorProperty("ipmpDescrPtr", + MP4IPMPPtrDescrTag, 0, Optional, Many)); + AddProperty( /* 7 */ + new MP4DescriptorProperty("extDescr", + MP4ExtDescrTagsStart, MP4ExtDescrTagsEnd, Optional, Many)); + + SetReadMutate(2); +} + +void MP4ODescriptor::Generate() +{ + ((MP4BitfieldProperty*)m_pProperties[2])->SetValue(0x1F); +} + +void MP4ODescriptor::Mutate() +{ + bool urlFlag = ((MP4BitfieldProperty*)m_pProperties[1])->GetValue(); + + m_pProperties[3]->SetImplicit(!urlFlag); + for (u_int32_t i = 4; i <= 6; i++) { + m_pProperties[i]->SetImplicit(urlFlag); + } +} + +MP4ESDescriptor::MP4ESDescriptor() + : MP4Descriptor(MP4ESDescrTag) +{ + /* N.B. other class functions depend on the property indicies */ + AddProperty( /* 0 */ + new MP4Integer16Property("ESID")); + AddProperty( /* 1 */ + new MP4BitfieldProperty("streamDependenceFlag", 1)); + AddProperty( /* 2 */ + new MP4BitfieldProperty("URLFlag", 1)); + AddProperty( /* 3 */ + new MP4BitfieldProperty("OCRstreamFlag", 1)); + AddProperty( /* 4 */ + new MP4BitfieldProperty("streamPriority", 5)); + AddProperty( /* 5 */ + new MP4Integer16Property("dependsOnESID")); + AddProperty( /* 6 */ + new MP4StringProperty("URL", Counted)); + AddProperty( /* 7 */ + new MP4Integer16Property("OCRESID")); + AddProperty( /* 8 */ + new MP4DescriptorProperty("decConfigDescr", + MP4DecConfigDescrTag, 0, Required, OnlyOne)); + AddProperty( /* 9 */ + new MP4DescriptorProperty("slConfigDescr", + MP4SLConfigDescrTag, 0, Required, OnlyOne)); + AddProperty( /* 10 */ + new MP4DescriptorProperty("ipiPtr", + MP4IPIPtrDescrTag, 0, Optional, OnlyOne)); + AddProperty( /* 11 */ + new MP4DescriptorProperty("ipIds", + MP4ContentIdDescrTag, MP4SupplContentIdDescrTag, Optional, Many)); + AddProperty( /* 12 */ + new MP4DescriptorProperty("ipmpDescrPtr", + MP4IPMPPtrDescrTag, 0, Optional, Many)); + AddProperty( /* 13 */ + new MP4DescriptorProperty("langDescr", + MP4LanguageDescrTag, 0, Optional, Many)); + AddProperty( /* 14 */ + new MP4DescriptorProperty("qosDescr", + MP4QosDescrTag, 0, Optional, OnlyOne)); + AddProperty( /* 15 */ + new MP4DescriptorProperty("regDescr", + MP4RegistrationDescrTag, 0, Optional, OnlyOne)); + AddProperty( /* 16 */ + new MP4DescriptorProperty("extDescr", + MP4ExtDescrTagsStart, MP4ExtDescrTagsEnd, Optional, Many)); + + SetReadMutate(5); +} + +void MP4ESDescriptor::Mutate() +{ + bool streamDependFlag = + ((MP4BitfieldProperty*)m_pProperties[1])->GetValue(); + m_pProperties[5]->SetImplicit(!streamDependFlag); + + bool urlFlag = + ((MP4BitfieldProperty*)m_pProperties[2])->GetValue(); + m_pProperties[6]->SetImplicit(!urlFlag); + + bool ocrFlag = + ((MP4BitfieldProperty*)m_pProperties[3])->GetValue(); + m_pProperties[7]->SetImplicit(!ocrFlag); +} + +MP4DecConfigDescriptor::MP4DecConfigDescriptor() + : MP4Descriptor(MP4DecConfigDescrTag) +{ + AddProperty( /* 0 */ + new MP4Integer8Property("objectTypeId")); + AddProperty( /* 1 */ + new MP4BitfieldProperty("streamType", 6)); + AddProperty( /* 2 */ + new MP4BitfieldProperty("upStream", 1)); + AddProperty( /* 3 */ + new MP4BitfieldProperty("reserved", 1)); + AddProperty( /* 4 */ + new MP4BitfieldProperty("bufferSizeDB", 24)); + AddProperty( /* 5 */ + new MP4Integer32Property("maxBitrate")); + AddProperty( /* 6 */ + new MP4Integer32Property("avgBitrate")); + AddProperty( /* 7 */ + new MP4DescriptorProperty("decSpecificInfo", + MP4DecSpecificDescrTag, 0, Optional, OnlyOne)); + AddProperty( /* 8 */ + new MP4DescriptorProperty("profileLevelIndicationIndexDescr", + MP4ExtProfileLevelDescrTag, 0, Optional, Many)); +} + +void MP4DecConfigDescriptor::Generate() +{ + ((MP4BitfieldProperty*)m_pProperties[3])->SetValue(1); +} + +MP4SLConfigDescriptor::MP4SLConfigDescriptor() + : MP4Descriptor(MP4SLConfigDescrTag) +{ + AddProperty( /* 0 */ + new MP4Integer8Property("predefined")); + AddProperty( /* 1 */ + new MP4BitfieldProperty("useAccessUnitStartFlag", 1)); + AddProperty( /* 2 */ + new MP4BitfieldProperty("useAccessUnitEndFlag", 1)); + AddProperty( /* 3 */ + new MP4BitfieldProperty("useRandomAccessPointFlag", 1)); + AddProperty( /* 4 */ + new MP4BitfieldProperty("hasRandomAccessUnitsOnlyFlag", 1)); + AddProperty( /* 5 */ + new MP4BitfieldProperty("usePaddingFlag", 1)); + AddProperty( /* 6 */ + new MP4BitfieldProperty("useTimeStampsFlag", 1)); + AddProperty( /* 7 */ + new MP4BitfieldProperty("useIdleFlag", 1)); + AddProperty( /* 8 */ + new MP4BitfieldProperty("durationFlag", 1)); + AddProperty( /* 9 */ + new MP4Integer32Property("timeStampResolution")); + AddProperty( /* 10 */ + new MP4Integer32Property("OCRResolution")); + AddProperty( /* 11 */ + new MP4Integer8Property("timeStampLength")); + AddProperty( /* 12 */ + new MP4Integer8Property("OCRLength")); + AddProperty( /* 13 */ + new MP4Integer8Property("AULength")); + AddProperty( /* 14 */ + new MP4Integer8Property("instantBitrateLength")); + AddProperty( /* 15 */ + new MP4BitfieldProperty("degradationPriortyLength", 4)); + AddProperty( /* 16 */ + new MP4BitfieldProperty("AUSeqNumLength", 5)); + AddProperty( /* 17 */ + new MP4BitfieldProperty("packetSeqNumLength", 5)); + AddProperty( /* 18 */ + new MP4BitfieldProperty("reserved", 2)); + + // if durationFlag + AddProperty( /* 19 */ + new MP4Integer32Property("timeScale")); + AddProperty( /* 20 */ + new MP4Integer16Property("accessUnitDuration")); + AddProperty( /* 21 */ + new MP4Integer16Property("compositionUnitDuration")); + + // if !useTimeStampsFlag + AddProperty( /* 22 */ + new MP4BitfieldProperty("startDecodingTimeStamp", 64)); + AddProperty( /* 23 */ + new MP4BitfieldProperty("startCompositionTimeStamp", 64)); +} + +void MP4SLConfigDescriptor::Generate() +{ + // by default all tracks in an mp4 file + // use predefined SLConfig descriptor == 2 + ((MP4Integer8Property*)m_pProperties[0])->SetValue(2); + + // which implies UseTimestampsFlag = 1 + ((MP4BitfieldProperty*)m_pProperties[6])->SetValue(1); + + // reserved = 3 + ((MP4BitfieldProperty*)m_pProperties[18])->SetValue(3); +} + +void MP4SLConfigDescriptor::Read(MP4File* pFile) +{ + ReadHeader(pFile); + + // read the first property, 'predefined' + ReadProperties(pFile, 0, 1); + + // if predefined == 0 + if (((MP4Integer8Property*)m_pProperties[0])->GetValue() == 0) { + + /* read the next 18 properties */ + ReadProperties(pFile, 1, 18); + } + + // now mutate + Mutate(); + + // and read the remaining properties + ReadProperties(pFile, 19); +} + +void MP4SLConfigDescriptor::Mutate() +{ + u_int32_t i; + u_int8_t predefined = + ((MP4Integer8Property*)m_pProperties[0])->GetValue(); + + if (predefined) { + // properties 1-18 are implicit + for (i = 1; i < m_pProperties.Size(); i++) { + m_pProperties[i]->SetImplicit(true); + } + + if (predefined == 1) { + // UseTimestampsFlag = 0 + ((MP4BitfieldProperty*)m_pProperties[6])->SetValue(0); + + // TimestampResolution = 1000 + ((MP4Integer32Property*)m_pProperties[9])->SetValue(1000); + + // TimeStampLength = 32 + ((MP4Integer8Property*)m_pProperties[11])->SetValue(32); + + } else if (predefined == 2) { + // UseTimestampsFlag = 1 + ((MP4BitfieldProperty*)m_pProperties[6])->SetValue(1); + } + } else { +#if 1 + for (i = 1; i <= 18; i++) { + m_pProperties[i]->SetImplicit(false); + } + ((MP4BitfieldProperty*)m_pProperties[18])->SetValue(3); +#endif + } + + bool durationFlag = + ((MP4BitfieldProperty*)m_pProperties[8])->GetValue(); + + for (i = 19; i <= 21; i++) { + m_pProperties[i]->SetImplicit(!durationFlag); + } + + bool useTimeStampsFlag = + ((MP4BitfieldProperty*)m_pProperties[6])->GetValue(); + + for (i = 22; i <= 23; i++) { + m_pProperties[i]->SetImplicit(useTimeStampsFlag); + + u_int8_t timeStampLength = MIN(64, + ((MP4Integer8Property*)m_pProperties[11])->GetValue()); + + ((MP4BitfieldProperty*)m_pProperties[i])->SetNumBits(timeStampLength); + + // handle a nonsensical situation gracefully + if (timeStampLength == 0) { + m_pProperties[i]->SetImplicit(true); + } + } +} + +MP4ContentIdDescriptor::MP4ContentIdDescriptor() + : MP4Descriptor(MP4ContentIdDescrTag) +{ + AddProperty( /* 0 */ + new MP4BitfieldProperty("compatibility", 2)); + AddProperty( /* 1 */ + new MP4BitfieldProperty("contentTypeFlag", 1)); + AddProperty( /* 2 */ + new MP4BitfieldProperty("contentIdFlag", 1)); + AddProperty( /* 3 */ + new MP4BitfieldProperty("protectedContent", 1)); + AddProperty( /* 4 */ + new MP4BitfieldProperty("reserved", 3)); + AddProperty( /* 5 */ + new MP4Integer8Property("contentType")); + AddProperty( /* 6 */ + new MP4Integer8Property("contentIdType")); + AddProperty( /* 7 */ + new MP4BytesProperty("contentId")); +} + +void MP4ContentIdDescriptor::Read(MP4File* pFile) +{ + ReadHeader(pFile); + + /* read the first property, 'compatiblity' */ + ReadProperties(pFile, 0, 1); + + /* if compatiblity != 0 */ + if (((MP4Integer8Property*)m_pProperties[0])->GetValue() != 0) { + /* we don't understand it */ + VERBOSE_READ(pFile->GetVerbosity(), + printf("incompatible content id descriptor\n")); + return; + } + + /* read the next four properties */ + ReadProperties(pFile, 1, 4); + + /* which allows us to reconfigure ourselves */ + Mutate(); + + bool contentTypeFlag = ((MP4BitfieldProperty*)m_pProperties[1])->GetValue(); + + bool contentIdFlag = ((MP4BitfieldProperty*)m_pProperties[2])->GetValue(); + + if (contentIdFlag) { + + u_int32_t cIdOffset = 2; + + if (contentTypeFlag) { + + cIdOffset++; + + } + + ((MP4BytesProperty*)m_pProperties[7])->SetValueSize(m_size - cIdOffset); + + } + + + + /* read the remaining properties */ + ReadProperties(pFile, 5); +} + +void MP4ContentIdDescriptor::Mutate() +{ + bool contentTypeFlag = ((MP4BitfieldProperty*)m_pProperties[1])->GetValue(); + m_pProperties[5]->SetImplicit(!contentTypeFlag); + + bool contentIdFlag = ((MP4BitfieldProperty*)m_pProperties[2])->GetValue(); + m_pProperties[6]->SetImplicit(!contentIdFlag); + m_pProperties[7]->SetImplicit(!contentIdFlag); + +} + +MP4Descriptor* MP4DescriptorProperty::CreateDescriptor(u_int8_t tag) +{ + MP4Descriptor* pDescriptor = NULL; + + switch (tag) { + case MP4ESDescrTag: + pDescriptor = new MP4ESDescriptor(); + break; + case MP4DecConfigDescrTag: + pDescriptor = new MP4DecConfigDescriptor(); + break; + case MP4DecSpecificDescrTag: + case MP4IPMPDescrTag: + case MP4RegistrationDescrTag: + pDescriptor = new MP4BytesDescriptor(tag); + break; + case MP4SLConfigDescrTag: + pDescriptor = new MP4SLConfigDescriptor(); + break; + case MP4ContentIdDescrTag: + pDescriptor = new MP4ContentIdDescriptor(); + break; + case MP4ESIDIncDescrTag: + case MP4ESIDRefDescrTag: + case MP4IPIPtrDescrTag: + case MP4SupplContentIdDescrTag: + case MP4IPMPPtrDescrTag: + case MP4ExtProfileLevelDescrTag: + pDescriptor = new MP4BaseDescriptor(tag); + break; + case MP4QosDescrTag: + pDescriptor = new MP4QosDescriptorBase(MP4QosDescrTag); + break; + case MP4IODescrTag: + case MP4FileIODescrTag: + pDescriptor = new MP4IODescriptor(); + pDescriptor->SetTag(tag); + break; + case MP4ODescrTag: + case MP4FileODescrTag: + pDescriptor = new MP4ODescriptor(); + pDescriptor->SetTag(tag); + break; + } + + if (pDescriptor == NULL) { + if (tag >= MP4OCIDescrTagsStart && tag <= MP4OCIDescrTagsEnd) { + pDescriptor = CreateOCIDescriptor(tag); + } + + if (tag >= MP4ExtDescrTagsStart && tag <= MP4ExtDescrTagsEnd) { + pDescriptor = new MP4BytesDescriptor(tag); + } + } + + return pDescriptor; +} + diff --git a/Src/external_dependencies/libmp4v2/descriptors.h b/Src/external_dependencies/libmp4v2/descriptors.h new file mode 100644 index 00000000..edf245d8 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/descriptors.h @@ -0,0 +1,131 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#ifndef __DESCRIPTORS_INCLUDED__ +#define __DESCRIPTORS_INCLUDED__ + +const u_int8_t MP4ODescrTag = 0x01; +const u_int8_t MP4IODescrTag = 0x02; +const u_int8_t MP4ESDescrTag = 0x03; +const u_int8_t MP4DecConfigDescrTag = 0x04; +const u_int8_t MP4DecSpecificDescrTag = 0x05; +const u_int8_t MP4SLConfigDescrTag = 0x06; +const u_int8_t MP4ContentIdDescrTag = 0x07; +const u_int8_t MP4SupplContentIdDescrTag = 0x08; +const u_int8_t MP4IPIPtrDescrTag = 0x09; +const u_int8_t MP4IPMPPtrDescrTag = 0x0A; +const u_int8_t MP4IPMPDescrTag = 0x0B; +const u_int8_t MP4RegistrationDescrTag = 0x0D; +const u_int8_t MP4ESIDIncDescrTag = 0x0E; +const u_int8_t MP4ESIDRefDescrTag = 0x0F; +const u_int8_t MP4FileIODescrTag = 0x10; +const u_int8_t MP4FileODescrTag = 0x11; +const u_int8_t MP4ExtProfileLevelDescrTag = 0x13; +const u_int8_t MP4ExtDescrTagsStart = 0x80; +const u_int8_t MP4ExtDescrTagsEnd = 0xFE; + +class MP4BaseDescriptor : public MP4Descriptor { + public: + MP4BaseDescriptor(u_int8_t tag); +}; + +class MP4BytesDescriptor : public MP4Descriptor { + public: + MP4BytesDescriptor(u_int8_t tag); + void Read(MP4File* pFile); + protected: + uint m_size_offset; // size to adjust the size for the bytes property + uint m_bytes_index; // index into properties for bytes property +}; + +class MP4IODescriptor : public MP4Descriptor { +public: + MP4IODescriptor(); + void Generate(); +protected: + void Mutate(); +}; + +class MP4ODescriptor : public MP4Descriptor { +public: + MP4ODescriptor(); + void Generate(); +protected: + void Mutate(); +}; + + +class MP4ESDescriptor : public MP4Descriptor { +public: + MP4ESDescriptor(); +protected: + void Mutate(); +}; + +class MP4DecConfigDescriptor : public MP4Descriptor { +public: + MP4DecConfigDescriptor(); + void Generate(); +}; + + +class MP4SLConfigDescriptor : public MP4Descriptor { +public: + MP4SLConfigDescriptor(); + void Generate(); + void Read(MP4File* pFile); + protected: + void Mutate(); +}; + +class MP4IPIPtrDescriptor : public MP4Descriptor { +public: + MP4IPIPtrDescriptor(); +}; + +class MP4ContentIdDescriptor : public MP4Descriptor { +public: + MP4ContentIdDescriptor(); + void Read(MP4File* pFile); +protected: + void Mutate(); +}; + +// associated values in descriptors + +// ES objectTypeId +const u_int8_t MP4SystemsV1ObjectType = 0x01; +const u_int8_t MP4SystemsV2ObjectType = 0x02; + +// ES streamType +const u_int8_t MP4ObjectDescriptionStreamType = 0x01; +const u_int8_t MP4ClockReferenceStreamType = 0x02; +const u_int8_t MP4SceneDescriptionStreamType = 0x03; +const u_int8_t MP4VisualStreamType = 0x04; +const u_int8_t MP4AudioStreamType = 0x05; +const u_int8_t MP4Mpeg7StreamType = 0x06; +const u_int8_t MP4IPMPStreamType = 0x07; +const u_int8_t MP4OCIStreamType = 0x08; +const u_int8_t MP4MPEGJStreamType = 0x09; +const u_int8_t MP4UserPrivateStreamType = 0x20; + +#endif /* __DESCRIPTORS_INCLUDED__ */ + diff --git a/Src/external_dependencies/libmp4v2/include/mpeg4ip.h b/Src/external_dependencies/libmp4v2/include/mpeg4ip.h new file mode 100644 index 00000000..94d22c72 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/include/mpeg4ip.h @@ -0,0 +1,340 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2000-2005. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + * Bill May wmay@cisco.com + */ + +#ifndef __MPEG4IP_INCLUDED__ +#define __MPEG4IP_INCLUDED__ + +/* project wide applicable stuff here */ +#ifndef _WIN32 +#ifdef PACKAGE_BUGREPORT +#define TEMP_PACKAGE_BUGREPORT PACKAGE_BUGREPORT +#define TEMP_PACKAGE_NAME PACKAGE_NAME +#define TEMP_PACKAGE_STRING PACKAGE_STRING +#define TEMP_PACKAGE_TARNAME PACKAGE_TARNAME +#define TEMP_PACKAGE_VERSION PACKAGE_VERSION +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION +#include <mpeg4ip_config.h> +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION +#define PACKAGE_BUGREPORT TEMP_PACKAGE_BUGREPORT +#define PACKAGE_NAME TEMP_PACKAGE_NAME +#define PACKAGE_STRING TEMP_PACKAGE_STRING +#define PACKAGE_TARNAME TEMP_PACKAGE_TARNAME +#define PACKAGE_VERSION TEMP_PACKAGE_VERSION +#else +#include <mpeg4ip_config.h> +#endif +#endif + +// the mpeg4ip_package and mpeg4ip_version are always in this +// file +#include "mpeg4ip_version.h" + +#ifdef _WIN32 +#include "mpeg4ip_win32.h" +#include "mpeg4ip_version.h" +#include "stdint.h" +#else /* UNIX */ +/***************************************************************************** + * UNIX LIKE DEFINES BELOW THIS POINT + *****************************************************************************/ +#ifdef sun +#include <sys/feature_tests.h> +#endif + +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#else +#ifndef sun +#if _FILE_OFFSET_BITS < 64 + #error File offset bits is already set to non-64 value +#endif +#endif +#endif + +#ifndef _LARGEFILE_SOURCE +#define _LARGEFILE_SOURCE +#endif +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> + +#ifdef HAVE_INTTYPES_H +#include <inttypes.h> +#endif +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif +#if !defined(HAVE_INTTYPES_H) && !defined(HAVE_STDINT_H) +#error "Don't have stdint.h or inttypes.h - no way to get uint8_t" +#endif + +#include <unistd.h> +#include <fcntl.h> +#include <netinet/in.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <syslog.h> +#include <string.h> +#include <ctype.h> +#include <netdb.h> +#include <sys/stat.h> +#ifdef TIME_WITH_SYS_TIME +#include <sys/time.h> +#include <time.h> +#else +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#else +#include <time.h> +#endif +#endif +#include <sys/param.h> + +#ifdef __cplusplus +extern "C" { +#endif +char *strcasestr(const char *haystack, const char *needle); +#ifdef __cplusplus +} +#endif + +#define OPEN_RDWR O_RDWR +#define OPEN_CREAT O_CREAT +#define OPEN_RDONLY O_RDONLY + +#define closesocket close +#define IOSBINARY ios::bin + +#if SIZEOF_LONG == 8 +#define MAX_UINT64 -1LU +#define D64F "ld" +#define U64F "lu" +#define X64F "lx" + +#define TO_D64(a) (a##L) +#define TO_U64(a) (a##LU) +#else +#define MAX_UINT64 -1LLU +#define D64F "lld" +#define U64F "llu" +#define X64F "llx" + +#define TO_D64(a) (a##LL) +#define TO_U64(a) (a##LLU) +#endif + +#ifdef HAVE_FPOS_T___POS +#define FPOS_TO_VAR(fpos, typed, var) (var) = (typed)((fpos).__pos) +#define VAR_TO_FPOS(fpos, var) (fpos).__pos = (var) +#else +#define FPOS_TO_VAR(fpos, typed, var) (var) = (typed)(fpos) +#define VAR_TO_FPOS(fpos, var) (fpos) = (var) +#endif + +#define FOPEN_READ_BINARY "r" +#define FOPEN_WRITE_BINARY "w" +#define UINT64_TO_DOUBLE(a) ((double)(a)) +#endif /* define unix */ + +/***************************************************************************** + * Generic type includes used in the whole package * + *****************************************************************************/ +#define D64 "%"D64F +#define U64 "%"U64F +#define X64 "%"X64F + +#define M_LLU TO_U64(1000) +#define M_64 TO_U64(1000) +#define LLU U64 + +#include <stdarg.h> +typedef void (*error_msg_func_t)(int loglevel, + const char *lib, + const char *fmt, + va_list ap); +typedef void (*lib_message_func_t)(int loglevel, + const char *lib, + const char *fmt, + ...); +#ifndef HAVE_IN_PORT_T +typedef uint16_t in_port_t; +#endif + +#ifndef HAVE_SOCKLEN_T +typedef unsigned int socklen_t; +#endif + +#ifdef sun +#include <limits.h> +#define u_int8_t uint8_t +#define u_int16_t uint16_t +#define u_int32_t uint32_t +#define u_int64_t uint64_t +#define __STRING(expr) #expr +#endif + +#ifndef HAVE_STRSEP +#ifdef __cplusplus +extern "C" { +#endif +char *strsep(char **strp, const char *delim); +#ifdef __cplusplus +} +#endif +#endif + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef INADDR_NONE +#define INADDR_NONE (-1) +#endif + +#define MALLOC_STRUCTURE(a) ((a *)malloc(sizeof(a))) + +#define CHECK_AND_FREE(a) if ((a) != NULL) { free((void *)(a)); (a) = NULL;} + +#define NUM_ELEMENTS_IN_ARRAY(name) ((sizeof((name))) / (sizeof(*(name)))) + +#define ADV_SPACE(a) {while (isspace(*(a)) && (*(a) != '\0'))(a)++;} + +#ifndef HAVE_GTK +typedef char gchar; +typedef unsigned char guchar; + +typedef int gint; +typedef unsigned int guint; + +typedef long glong; +typedef unsigned long gulong; + +typedef double gdouble; + +typedef int gboolean; + +typedef int16_t gint16; +typedef uint16_t guint16; + +typedef int32_t gint32; +typedef uint32_t guint32; + +typedef int64_t gint64; +typedef uint64_t guint64; + +typedef uint8_t guint8; +typedef int8_t gint8; + +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef __cplusplus + +#ifndef bool + #if SIZEOF_BOOL == 8 + typedef uint64_t bool; + #else + #if SIZEOF_BOOL == 4 + typedef uint32_t bool; + #else + #if SIZEOF_BOOL == 2 + typedef uint16_t bool; + #else + typedef unsigned char bool; + #endif + #endif + #endif + #ifndef false + #define false FALSE + #endif + #ifndef true + #define true TRUE + #endif +#endif + +#endif + +#ifndef ROUND +# ifdef HAVE_RINT +# define ROUND(f) rint(f) +# else +# define ROUND(f) (int)(floor((f) + 0.5)) +# endif +#endif + +#ifndef INT16_MAX +# define INT16_MAX (32767) +#endif +#ifndef INT16_MIN +# define INT16_MIN (-32767-1) +#endif + +#ifndef UINT32_MAX +# define UINT32_MAX (4294967295U) +#endif + +#ifndef UINT64_MAX +# define UINT64_MAX TO_U64(0xffffffffffffffff) +#endif + +typedef enum audio_format_t { + AUDIO_FMT_U8 = 0, + AUDIO_FMT_S8, + AUDIO_FMT_U16LSB, + AUDIO_FMT_S16LSB, + AUDIO_FMT_U16MSB, + AUDIO_FMT_S16MSB, + AUDIO_FMT_U16, + AUDIO_FMT_S16, + AUDIO_FMT_FLOAT, + AUDIO_FMT_HW_AC3, +} audio_format_t; + +#ifdef _WIN32 +#define MP4_FILENAME_CHAR wchar_t +#else +#define MP4_FILENAME_CHAR char +#endif + +#endif /* __MPEG4IP_INCLUDED__ */ + diff --git a/Src/external_dependencies/libmp4v2/include/mpeg4ip_byteswap.h b/Src/external_dependencies/libmp4v2/include/mpeg4ip_byteswap.h new file mode 100644 index 00000000..6121893d --- /dev/null +++ b/Src/external_dependencies/libmp4v2/include/mpeg4ip_byteswap.h @@ -0,0 +1,89 @@ +/** + * Copyright (C) 2000, 2001 Billy Biggs <vektor@dumbterm.net>, + * Han Hjort <d95hjort@dtek.chalmers.se> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef BSWAP_H_INCLUDED +#define BSWAP_H_INCLUDED + +#ifdef _WIN32 +#include <config.h> +#endif + +#if defined(WORDS_BIGENDIAN) +/* All bigendian systems are fine, just ignore the swaps. */ +#define B2N_16(x) (x) +#define B2N_32(x) (x) +#define B2N_64(x) (x) + +#else + +#if defined(__linux__) +#include <byteswap.h> +#define B2N_16(x) x = bswap_16(x) +#define B2N_32(x) x = bswap_32(x) +#define B2N_64(x) x = bswap_64(x) + +#elif defined(__NetBSD__) +#include <sys/endian.h> +#define B2N_16(x) BE16TOH(x) +#define B2N_32(x) BE32TOH(x) +#define B2N_64(x) BE64TOH(x) + +#elif defined(__OpenBSD__) +#include <sys/endian.h> +#define B2N_16(x) x = swap16(x) +#define B2N_32(x) x = swap32(x) +#define B2N_64(x) x = swap64(x) + +/* This is a slow but portable implementation, it has multiple evaluation + * problems so beware. + * FreeBSD and Solaris don't have <byteswap.h> or any other such + * functionality! + */ + +#elif defined(__FreeBSD__) || defined(__sun) || defined(__bsdi__) || defined(_WIN32) +#define B2N_16(x) \ + x = ((((x) & 0xff00) >> 8) | \ + (((x) & 0x00ff) << 8)) +#define B2N_32(x) \ + x = ((((x) & 0xff000000) >> 24) | \ + (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0x0000ff00) << 8) | \ + (((x) & 0x000000ff) << 24)) +#define B2N_64(x) \ + x = ((((x) & 0xff00000000000000) >> 56) | \ + (((x) & 0x00ff000000000000) >> 40) | \ + (((x) & 0x0000ff0000000000) >> 24) | \ + (((x) & 0x000000ff00000000) >> 8) | \ + (((x) & 0x00000000ff000000) << 8) | \ + (((x) & 0x0000000000ff0000) << 24) | \ + (((x) & 0x000000000000ff00) << 40) | \ + (((x) & 0x00000000000000ff) << 56)) + +#else + +/* If there isn't a header provided with your system with this functionality + * add the relevant || define( ) to the portable implementation above. + */ +#error "You need to add endian swap macros for you're system" + +#endif + +#endif /* WORDS_BIGENDIAN */ + +#endif /* BSWAP_H_INCLUDED */ diff --git a/Src/external_dependencies/libmp4v2/include/mpeg4ip_getopt.h b/Src/external_dependencies/libmp4v2/include/mpeg4ip_getopt.h new file mode 100644 index 00000000..f905691e --- /dev/null +++ b/Src/external_dependencies/libmp4v2/include/mpeg4ip_getopt.h @@ -0,0 +1,156 @@ +#ifdef WIN32 +#define HAVE_IN_PORT_T +#define HAVE_SOCKLEN_T +#define __STDC__ 1 +#else +#include "mpeg4ip.h" +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef HAVE_GETOPT_H +#include <getopt.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(HAVE_GETOPT) && !defined(HAVE_GETOPT_LONG) && !defined(HAVE_GETOPT_LONG_ONLY) + + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; +#endif + +#if !defined(HAVE_GETOPT_LONG) && !defined(HAVE_GETOPT_LONG_ONLY) +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +# if defined __STDC__ && __STDC__ + const char *name; +# else + char *name; +# endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +#ifndef no_argument +# define no_argument 0 +# define required_argument 1 +# define optional_argument 2 +#endif + +#endif /* no HAVE_GETOPT defines */ + +#ifndef HAVE_GETOPT +/* Get definitions and prototypes for functions to process the + arguments in ARGV (ARGC of them, minus the program name) for + options given in OPTS. + + Return the option character from OPTS just read. Return -1 when + there are no more options. For unrecognized options, or options + missing arguments, `optopt' is set to the option letter, and '?' is + returned. + + The OPTS string is a list of characters which are recognized option + letters, optionally followed by colons, specifying that that letter + takes an argument, to be placed in `optarg'. + + If a letter in OPTS is followed by two colons, its argument is + optional. This behavior is specific to the GNU `getopt'. + + The argument `--' causes premature termination of argument + scanning, explicitly telling `getopt' that there are no more + options. + + If OPTS begins with `--', then non-option arguments are treated as + arguments to the option '\0'. This behavior is specific to the GNU + `getopt'. */ + +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int ___argc, char *const *___argv, const char *__shortopts); + + +#endif /* HAVE_GETOPT */ + +#ifndef HAVE_GETOPT_LONG + +extern int getopt_long (int ___argc, char *const *___argv, const char *__shortopts, + const struct option *__longopts, int *__longind); + +#endif /* HAVE_GETOPT_LONG */ + +#ifndef HAVE_GETOPT_LONG_ONLY +extern int getopt_long_only (int ___argc, char *const *___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind); +#endif /* HAVE_GETOPT_LONG */ + +#if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_LONG) || !defined(HAVE_GETOPT_LONG_ONLY) + + extern int _getopt_internal (int ___argc, char *const *argv, + const char *optstring, + const struct option *longopts, + int *longind, int long_only); +#endif +#ifdef __cplusplus +} +#endif diff --git a/Src/external_dependencies/libmp4v2/include/mpeg4ip_version.h b/Src/external_dependencies/libmp4v2/include/mpeg4ip_version.h new file mode 100644 index 00000000..0966d329 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/include/mpeg4ip_version.h @@ -0,0 +1,6 @@ +#define MPEG4IP_PACKAGE "mpeg4ip" +#define MPEG4IP_VERSION "1.5" +#define MPEG4IP_MAJOR_VERSION 0x1 +#define MPEG4IP_MINOR_VERSION 0x5 +#define MPEG4IP_CVS_VERSION 0x +#define MPEG4IP_HEX_VERSION ((MPEG4IP_MAJOR_VERSION << 16) | (MPEG4IP_MINOR_VERSION << 8) | MPEG4IP_CVS_VERSION) diff --git a/Src/external_dependencies/libmp4v2/include/mpeg4ip_win32.h b/Src/external_dependencies/libmp4v2/include/mpeg4ip_win32.h new file mode 100644 index 00000000..5f14fb39 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/include/mpeg4ip_win32.h @@ -0,0 +1,141 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2005. All Rights Reserved. + * + * Contributor(s): + * Bill May wmay@cisco.com + */ +/* windows defines */ +#ifndef __MPEG4IP_WIN32_H__ +#define __MPEG4IP_WIN32_H__ +#define HAVE_IN_PORT_T +#define HAVE_SOCKLEN_T +#define NEED_SDL_VIDEO_IN_MAIN_THREAD +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <winsock2.h> +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <time.h> +#include <limits.h> + +#ifdef __GNUC__ +#include <stdint.h> +#include <ctype.h> +typedef uint64_t u_int64_t; +typedef uint32_t u_int32_t; +typedef uint16_t u_int16_t; +typedef uint8_t u_int8_t; +#else +#include <bfc/platform/types.h> +typedef unsigned __int64 u_int64_t; +typedef unsigned __int32 u_int32_t; +typedef unsigned __int16 u_int16_t; +typedef unsigned __int8 u_int8_t; +typedef unsigned short in_port_t; +typedef int socklen_t; +typedef unsigned int uint; +#define snprintf _snprintf +#define strncasecmp _strnicmp +#ifndef strcasecmp +#define strcasecmp _stricmp +#endif +#endif + +#include <io.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +//#define write _write +#define close _close +#define open _open +#define access _access +#define vsnprintf _vsnprintf +#define stat _stati64 +#define fstat _fstati64 +#define F_OK 0 +#define OPEN_RDWR (_O_RDWR | _O_BINARY) +#define OPEN_CREAT (_O_CREAT | _O_BINARY) +#define OPEN_RDONLY (_O_RDONLY | _O_BINARY) +#define srandom srand +#define random rand + +#define IOSBINARY ios::binary + +#ifdef __cplusplus +extern "C" { +#endif +int gettimeofday(struct timeval *t, void *); +#ifdef __cplusplus +} +#endif + +#undef PATH_MAX +#define PATH_MAX MAX_PATH + +#define MAX_UINT64 -1 +#ifdef __GNUC__ +#define D64F "lld" +#define U64F "llu" +#define X64F "llx" +#define TO_D64(a) (a##LL) +#define TO_U64(a) (a##LLU) +#else +#define D64F "I64d" +#define U64F "I64u" +#define X64F "I64x" +#define TO_D64(a) (a##I64) +#define TO_U64(a) (a##UI64) +#endif + + + +#define LOG_EMERG 0 +#define LOG_ALERT 1 +#define LOG_CRIT 2 +#define LOG_ERR 3 +#define LOG_WARNING 4 +#define LOG_NOTICE 5 +#define LOG_INFO 6 +#define LOG_DEBUG 7 + +#if defined(__GNUC__) || (!__STDC__ && _INTEGRAL_MAX_BITS >= 64) +#define VAR_TO_FPOS(fpos, var) (fpos) = (var) +#define FPOS_TO_VAR(fpos, typed, var) (var) = (typed)(fpos) +#else +#define VAR_TO_FPOS(fpos, var) (fpos).lopart = ((var) & UINT_MAX); (fpos).hipart = ((var) >> 32) +#define FPOS_TO_VAR(fpos, typed, var) (var) = (typed)((uint64_t)((fpos).hipart ) << 32 | (fpos).lopart) +#endif + +#define __STRING(expr) #expr + +#define FOPEN_READ_BINARY "rb" +#define FOPEN_WRITE_BINARY "wb" + +#define UINT64_TO_DOUBLE(a) ((double)((int64_t)(a))) +#ifdef __cplusplus +extern "C" { +#endif +char *strcasestr(const char *haystack, const char *needle); +#ifdef __cplusplus +} +#endif + + +#define SIZEOF_BOOL 1 + +#endif diff --git a/Src/external_dependencies/libmp4v2/isma.cpp b/Src/external_dependencies/libmp4v2/isma.cpp new file mode 100644 index 00000000..b366a408 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/isma.cpp @@ -0,0 +1,942 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001 - 2004. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + * Alix Marchandise-Franquet alix@cisco.com + * Ximpo Group Ltd. mp4v2@ximpo.com + */ + +#include "mp4common.h" + +static const u_int8_t BifsV2Config[3] = { + 0x00, 0x00, 0x60 // IsCommandStream = 1, PixelMetric = 1 +}; + +void MP4File::MakeIsmaCompliant(bool addIsmaComplianceSdp) +{ + ProtectWriteOperation("MP4MakeIsmaCompliant"); + + if (m_useIsma) { + // already done + return; + } + + // find first audio and/or video tracks + + MP4TrackId audioTrackId = MP4_INVALID_TRACK_ID; + try { + audioTrackId = FindTrackId(0, MP4_AUDIO_TRACK_TYPE); + } + catch (MP4Error* e) { + delete e; + } + + MP4TrackId videoTrackId = MP4_INVALID_TRACK_ID; + try { + videoTrackId = FindTrackId(0, MP4_VIDEO_TRACK_TYPE); + } + catch (MP4Error* e) { + delete e; + } + if (audioTrackId == MP4_INVALID_TRACK_ID && + videoTrackId == MP4_INVALID_TRACK_ID) return; + + const char *audio_media_data_name, *video_media_data_name; + uint8_t videoProfile = 0xff; + if (audioTrackId != MP4_INVALID_TRACK_ID) { + audio_media_data_name = MP4GetTrackMediaDataName(this, audioTrackId); + if (!(ATOMID(audio_media_data_name) == ATOMID("mp4a") || + ATOMID(audio_media_data_name) == ATOMID("enca"))) { + VERBOSE_ERROR(m_verbosity, + printf("MakeIsmaCompliant:can't make ISMA compliant when file contains an %s track\n", audio_media_data_name); + ); + return; + } + } + // + // Note - might have to check for avc1 here... + if (videoTrackId != MP4_INVALID_TRACK_ID) { + video_media_data_name = MP4GetTrackMediaDataName(this, videoTrackId); + if (!(ATOMID(video_media_data_name) == ATOMID("mp4v") || + ATOMID(video_media_data_name) == ATOMID("encv"))) { + VERBOSE_ERROR(m_verbosity, + printf("MakeIsmaCompliant:can't make ISMA compliant when file contains an %s track\n", video_media_data_name); + ); + return; + } + uint32_t verb = GetVerbosity(); + SetVerbosity(verb & ~MP4_DETAILS_ERROR); + videoProfile = MP4GetVideoProfileLevel(this, videoTrackId); + SetVerbosity(verb); + } + + m_useIsma = true; + + u_int64_t fileMsDuration = 0; + fileMsDuration = + ConvertFromMovieDuration(GetDuration(), MP4_MSECS_TIME_SCALE); + + // delete any existing OD track + if (m_odTrackId != MP4_INVALID_TRACK_ID) { + DeleteTrack(m_odTrackId); + } + + if (m_pRootAtom->FindAtomMP4("moov.iods") == NULL) { + (void)AddChildAtom("moov", "iods"); + } + (void)AddODTrack(); + SetODProfileLevel(0xFF); + + if (audioTrackId != MP4_INVALID_TRACK_ID) { + AddTrackToOd(audioTrackId); + MP4SetAudioProfileLevel(this, 0xf); + } + if (videoTrackId != MP4_INVALID_TRACK_ID) { + AddTrackToOd(videoTrackId); + MP4SetVideoProfileLevel(this, videoProfile); + } + + // delete any existing scene track + MP4TrackId sceneTrackId = MP4_INVALID_TRACK_ID; + try { + sceneTrackId = FindTrackId(0, MP4_SCENE_TRACK_TYPE); + } + catch (MP4Error *e) { + delete e; + } + if (sceneTrackId != MP4_INVALID_TRACK_ID) { + DeleteTrack(sceneTrackId); + } + + // add scene track + sceneTrackId = AddSceneTrack(); + SetSceneProfileLevel(0xFF); + SetGraphicsProfileLevel(0xFF); + SetTrackIntegerProperty(sceneTrackId, + "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr.objectTypeId", + MP4SystemsV2ObjectType); + + SetTrackESConfiguration(sceneTrackId, + BifsV2Config, sizeof(BifsV2Config)); + + u_int8_t* pBytes = NULL; + u_int64_t numBytes = 0; + + // write OD Update Command + CreateIsmaODUpdateCommandFromFileForFile( + m_odTrackId, + audioTrackId, + videoTrackId, + &pBytes, + &numBytes); + + WriteSample(m_odTrackId, pBytes, numBytes, fileMsDuration); + + MP4Free(pBytes); + pBytes = NULL; + + // write BIFS Scene Replace Command + CreateIsmaSceneCommand( + MP4_IS_VALID_TRACK_ID(audioTrackId), + MP4_IS_VALID_TRACK_ID(videoTrackId), + &pBytes, + &numBytes); + + WriteSample(sceneTrackId, pBytes, numBytes, fileMsDuration); + + MP4Free(pBytes); + pBytes = NULL; + + // add session level sdp + CreateIsmaIodFromFile( + m_odTrackId, + sceneTrackId, + audioTrackId, + videoTrackId, + &pBytes, + &numBytes); + + char* iodBase64 = MP4ToBase64(pBytes, numBytes); + + uint sdpBufLen = (uint)strlen(iodBase64) + 256; + uint used; + char* sdpBuf = (char*)MP4Calloc(sdpBufLen); + + if (addIsmaComplianceSdp) { + strncpy(sdpBuf, "a=isma-compliance:1,1.0,1\015\012", sdpBufLen); + } + + used = (uint)strlen(sdpBuf); + sdpBufLen -= used; + snprintf(&sdpBuf[used], sdpBufLen, + "a=mpeg4-iod: \042data:application/mpeg4-iod;base64,%s\042\015\012", + iodBase64); + + SetSessionSdp(sdpBuf); + + VERBOSE_ISMA(GetVerbosity(), + printf("IOD SDP = %s\n", sdpBuf)); + + MP4Free(iodBase64); + iodBase64 = NULL; + MP4Free(pBytes); + pBytes = NULL; + MP4Free(sdpBuf); + sdpBuf = NULL; +} + +static void CloneIntegerProperty( + MP4Descriptor* pDest, + MP4DescriptorProperty* pSrc, + const char* name) +{ + MP4IntegerProperty* pGetProperty; + MP4IntegerProperty* pSetProperty; + + if (!pSrc->FindProperty(name, (MP4Property**)&pGetProperty)) return; + if (!pDest->FindProperty(name, (MP4Property**)&pSetProperty)) return; + pSetProperty->SetValue(pGetProperty->GetValue()); +} + +void MP4File::CreateIsmaIodFromFile( + MP4TrackId odTrackId, + MP4TrackId sceneTrackId, + MP4TrackId audioTrackId, + MP4TrackId videoTrackId, + u_int8_t** ppBytes, + u_int64_t* pNumBytes) +{ + MP4Descriptor* pIod = new MP4IODescriptor(); + pIod->SetTag(MP4IODescrTag); + pIod->Generate(); + + MP4Atom* pIodsAtom = FindAtomMP4File("moov.iods"); + ASSERT(pIodsAtom); + MP4DescriptorProperty* pSrcIod = + (MP4DescriptorProperty*)pIodsAtom->GetProperty(2); + + CloneIntegerProperty(pIod, pSrcIod, "objectDescriptorId"); + CloneIntegerProperty(pIod, pSrcIod, "ODProfileLevelId"); + CloneIntegerProperty(pIod, pSrcIod, "sceneProfileLevelId"); + CloneIntegerProperty(pIod, pSrcIod, "audioProfileLevelId"); + CloneIntegerProperty(pIod, pSrcIod, "visualProfileLevelId"); + CloneIntegerProperty(pIod, pSrcIod, "graphicsProfileLevelId"); + + // mutate esIds from MP4ESIDIncDescrTag to MP4ESDescrTag + MP4DescriptorProperty* pEsProperty; + if (!pIod->FindProperty("esIds", (MP4Property**)&pEsProperty)) return; + pEsProperty->SetTags(MP4ESDescrTag); + + MP4IntegerProperty* pSetProperty; + MP4IntegerProperty* pSceneESID; + MP4IntegerProperty* pOdESID; + + // OD + MP4Descriptor* pOdEsd = + pEsProperty->AddDescriptor(MP4ESDescrTag); + pOdEsd->Generate(); + + if (!pOdEsd->FindProperty("ESID", (MP4Property**)&pOdESID)) return; + + // we set the OD ESID to a non-zero unique value + pOdESID->SetValue(m_odTrackId); + + if (pOdEsd->FindProperty("URLFlag", + (MP4Property**)&pSetProperty)) + pSetProperty->SetValue(1); + + u_int8_t* pBytes; + u_int64_t numBytes; + + CreateIsmaODUpdateCommandFromFileForStream( + audioTrackId, + videoTrackId, + &pBytes, + &numBytes); + + VERBOSE_ISMA(GetVerbosity(), + printf("OD data =\n"); MP4HexDump(pBytes, numBytes)); + + char* odCmdBase64 = MP4ToBase64(pBytes, numBytes); + + uint urlBufLen = (uint)strlen(odCmdBase64) + 64; + char* urlBuf = (char*)MP4Malloc(urlBufLen); + + snprintf(urlBuf, urlBufLen, + "data:application/mpeg4-od-au;base64,%s", + odCmdBase64); + + MP4StringProperty* pUrlProperty; + if (pOdEsd->FindProperty("URL", + (MP4Property**)&pUrlProperty)) + pUrlProperty->SetValue(urlBuf); + + VERBOSE_ISMA(GetVerbosity(), + printf("OD data URL = \042%s\042\n", urlBuf)); + + MP4Free(odCmdBase64); + odCmdBase64 = NULL; + MP4Free(pBytes); + pBytes = NULL; + MP4Free(urlBuf); + urlBuf = NULL; + + MP4DescriptorProperty* pSrcDcd = NULL; + + // HACK temporarily point to scene decoder config + (void)FindProperty(MakeTrackName(odTrackId, + "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr"), + (MP4Property**)&pSrcDcd); + ASSERT(pSrcDcd); + MP4Property* pOrgOdEsdProperty = + pOdEsd->GetProperty(8); + pOdEsd->SetProperty(8, pSrcDcd); + + // bufferSizeDB needs to be set appropriately + MP4BitfieldProperty* pBufferSizeProperty = NULL; + if (pOdEsd->FindProperty("decConfigDescr.bufferSizeDB", + (MP4Property**)&pBufferSizeProperty)) { + ASSERT(pBufferSizeProperty); + pBufferSizeProperty->SetValue(numBytes); + } + + // SL config needs to change from 2 (file) to 1 (null) + if (pOdEsd->FindProperty("slConfigDescr.predefined", + (MP4Property**)&pSetProperty)) + pSetProperty->SetValue(1); + + + // Scene + MP4Descriptor* pSceneEsd = + pEsProperty->AddDescriptor(MP4ESDescrTag); + pSceneEsd->Generate(); + + if (pSceneEsd->FindProperty("ESID", + (MP4Property**)&pSceneESID)) { + // we set the Scene ESID to a non-zero unique value + pSceneESID->SetValue(sceneTrackId); + } + + if (pSceneEsd->FindProperty("URLFlag", + (MP4Property**)&pSetProperty)) + pSetProperty->SetValue(1); + + CreateIsmaSceneCommand( + MP4_IS_VALID_TRACK_ID(audioTrackId), + MP4_IS_VALID_TRACK_ID(videoTrackId), + &pBytes, + &numBytes); + + VERBOSE_ISMA(GetVerbosity(), + printf("Scene data =\n"); MP4HexDump(pBytes, numBytes)); + + char *sceneCmdBase64 = MP4ToBase64(pBytes, numBytes); + + urlBuf = (char*)MP4Malloc(strlen(sceneCmdBase64) + 64); + snprintf(urlBuf, strlen(sceneCmdBase64) + 64, + "data:application/mpeg4-bifs-au;base64,%s", + sceneCmdBase64); + + if (pSceneEsd->FindProperty("URL", + (MP4Property**)&pUrlProperty)) + pUrlProperty->SetValue(urlBuf); + + VERBOSE_ISMA(GetVerbosity(), + printf("Scene data URL = \042%s\042\n", urlBuf)); + + MP4Free(sceneCmdBase64); + sceneCmdBase64 = NULL; + MP4Free(urlBuf); + urlBuf = NULL; + MP4Free(pBytes); + pBytes = NULL; + + // HACK temporarily point to scene decoder config + ASSERT(FindProperty(MakeTrackName(sceneTrackId, + "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr"), + (MP4Property**)&pSrcDcd)); + ASSERT(pSrcDcd); + MP4Property* pOrgSceneEsdProperty = + pSceneEsd->GetProperty(8); + pSceneEsd->SetProperty(8, pSrcDcd); + + // bufferSizeDB needs to be set + pBufferSizeProperty = NULL; + if (pSceneEsd->FindProperty("decConfigDescr.bufferSizeDB", + (MP4Property**)&pBufferSizeProperty)) { + ASSERT(pBufferSizeProperty); + pBufferSizeProperty->SetValue(numBytes); + } + + // SL config needs to change from 2 (file) to 1 (null) + if (pSceneEsd->FindProperty("slConfigDescr.predefined", + (MP4Property**)&pSetProperty)) + pSetProperty->SetValue(1); + + + // finally get the whole thing written to a memory + pIod->WriteToMemory(this, ppBytes, pNumBytes); + + + // now carefully replace esd properties before destroying + pOdEsd->SetProperty(8, pOrgOdEsdProperty); + pSceneEsd->SetProperty(8, pOrgSceneEsdProperty); + pSceneESID->SetValue(0); // restore 0 value + pOdESID->SetValue(0); + + delete pIod; + + VERBOSE_ISMA(GetVerbosity(), + printf("IOD data =\n"); MP4HexDump(*ppBytes, *pNumBytes)); +} + +void MP4File::CreateIsmaIodFromParams( + u_int8_t videoProfile, + u_int32_t videoBitrate, + u_int8_t* videoConfig, + u_int32_t videoConfigLength, + u_int8_t audioProfile, + u_int32_t audioBitrate, + u_int8_t* audioConfig, + u_int32_t audioConfigLength, + u_int8_t** ppIodBytes, + u_int64_t* pIodNumBytes) +{ + MP4IntegerProperty* pInt; + u_int8_t* pBytes = NULL; + u_int64_t numBytes; + + // Create the IOD + MP4Descriptor* pIod = new MP4IODescriptor(); + pIod->SetTag(MP4IODescrTag); + pIod->Generate(); + + // Set audio and video profileLevels + if (pIod->FindProperty("audioProfileLevelId", + (MP4Property**)&pInt)) + pInt->SetValue(audioProfile); + + if (pIod->FindProperty("visualProfileLevelId", + (MP4Property**)&pInt)) + pInt->SetValue(videoProfile); + + // Mutate esIds from MP4ESIDIncDescrTag to MP4ESDescrTag + MP4DescriptorProperty* pEsProperty; + if (!pIod->FindProperty("esIds", (MP4Property**)&pEsProperty)) return; + pEsProperty->SetTags(MP4ESDescrTag); + + // Add ES Descriptors + + // Scene + CreateIsmaSceneCommand( + (audioProfile != 0xFF), + (videoProfile != 0xFF), + &pBytes, + &numBytes); + + VERBOSE_ISMA(GetVerbosity(), + printf("Scene data =\n"); MP4HexDump(pBytes, numBytes)); + + char* sceneCmdBase64 = MP4ToBase64(pBytes, numBytes); + + char* urlBuf = + (char*)MP4Malloc(strlen(sceneCmdBase64) + 64); + snprintf(urlBuf, strlen(sceneCmdBase64) + 64, + "data:application/mpeg4-bifs-au;base64,%s", + sceneCmdBase64); + + VERBOSE_ISMA(GetVerbosity(), + printf("Scene data URL = \042%s\042\n", urlBuf)); + + /* MP4Descriptor* pSceneEsd = */ + CreateESD( + pEsProperty, + 201, // esid + MP4SystemsV2ObjectType, + MP4SceneDescriptionStreamType, + numBytes, // bufferSize + numBytes * 8, // bitrate + BifsV2Config, + sizeof(BifsV2Config), + urlBuf); + MP4Free(urlBuf); + urlBuf = NULL; + + MP4Free(sceneCmdBase64); + sceneCmdBase64 = NULL; + MP4Free(pBytes); + pBytes = NULL; + + // OD + + // Video + MP4DescriptorProperty* pVideoEsdProperty = + new MP4DescriptorProperty(); + pVideoEsdProperty->SetTags(MP4ESDescrTag); + + /* MP4Descriptor* pVideoEsd = */ + CreateESD( + pVideoEsdProperty, + 20, // esid + MP4_MPEG4_VIDEO_TYPE, + MP4VisualStreamType, + videoBitrate / 8, // bufferSize + videoBitrate, + videoConfig, + videoConfigLength, + NULL); + + // Audio + MP4DescriptorProperty* pAudioEsdProperty = + new MP4DescriptorProperty(); + pAudioEsdProperty->SetTags(MP4ESDescrTag); + + /* MP4Descriptor* pAudioEsd = */ + CreateESD( + pAudioEsdProperty, + 10, // esid + MP4_MPEG4_AUDIO_TYPE, + MP4AudioStreamType, + audioBitrate / 8, // bufferSize + audioBitrate, + audioConfig, + audioConfigLength, + NULL); + + CreateIsmaODUpdateCommandForStream( + pAudioEsdProperty, + pVideoEsdProperty, + &pBytes, + &numBytes); + + // cleanup temporary descriptor properties + delete pAudioEsdProperty; + delete pVideoEsdProperty; + + VERBOSE_ISMA(GetVerbosity(), + printf("OD data = "U64" bytes\n", numBytes); MP4HexDump(pBytes, numBytes)); + + char* odCmdBase64 = MP4ToBase64(pBytes, numBytes); + + urlBuf = (char*)MP4Malloc(strlen(odCmdBase64) + 64); + if (urlBuf != NULL) { + snprintf(urlBuf, strlen(odCmdBase64) + 64, + "data:application/mpeg4-od-au;base64,%s", + odCmdBase64); + + VERBOSE_ISMA(GetVerbosity(), + printf("OD data URL = \042%s\042\n", urlBuf)); + + /* MP4Descriptor* pOdEsd = */ + CreateESD( + pEsProperty, + 101, + MP4SystemsV1ObjectType, + MP4ObjectDescriptionStreamType, + numBytes, // bufferSize + numBytes * 8, // bitrate + NULL, // config + 0, // configLength + urlBuf); + + MP4Free(urlBuf); + urlBuf = NULL; + } + MP4Free(odCmdBase64); + odCmdBase64 = NULL; + MP4Free(pBytes); + pBytes = NULL; + + // finally get the whole thing written to a memory + pIod->WriteToMemory(this, ppIodBytes, pIodNumBytes); + + delete pIod; + + VERBOSE_ISMA(GetVerbosity(), + printf("IOD data =\n"); MP4HexDump(*ppIodBytes, *pIodNumBytes)); +} + +void MP4File::CreateESD( + MP4DescriptorProperty* pEsProperty, + u_int32_t esid, + u_int8_t objectType, + u_int8_t streamType, + u_int32_t bufferSize, + u_int32_t bitrate, + const u_int8_t* pConfig, + u_int32_t configLength, + char* url) +{ + MP4IntegerProperty* pInt; + MP4StringProperty* pString; + MP4BytesProperty* pBytes; + MP4BitfieldProperty* pBits; + + MP4Descriptor* pEsd = + pEsProperty->AddDescriptor(MP4ESDescrTag); + pEsd->Generate(); + + if (pEsd->FindProperty("ESID", + (MP4Property**)&pInt)) + pInt->SetValue(esid); + + if (pEsd->FindProperty("decConfigDescr.objectTypeId", + (MP4Property**)&pInt)) + pInt->SetValue(objectType); + + if (pEsd->FindProperty("decConfigDescr.streamType", + (MP4Property**)&pInt)) + pInt->SetValue(streamType); + + if (pEsd->FindProperty("decConfigDescr.bufferSizeDB", + (MP4Property**)&pInt)) + pInt->SetValue(bufferSize); + + if (pEsd->FindProperty("decConfigDescr.maxBitrate", + (MP4Property**)&pInt)) + pInt->SetValue(bitrate); + + if (pEsd->FindProperty("decConfigDescr.avgBitrate", + (MP4Property**)&pInt)) + pInt->SetValue(bitrate); + + MP4DescriptorProperty* pConfigDescrProperty; + if (pEsd->FindProperty("decConfigDescr.decSpecificInfo", + (MP4Property**)&pConfigDescrProperty)) { + + MP4Descriptor* pConfigDescr = + pConfigDescrProperty->AddDescriptor(MP4DecSpecificDescrTag); + pConfigDescr->Generate(); + + if (pConfigDescrProperty->FindProperty("decSpecificInfo[0].info", + (MP4Property**)&pBytes)) + pBytes->SetValue(pConfig, configLength); + } + + if (pEsd->FindProperty("slConfigDescr.predefined", + (MP4Property**)&pInt)) + // changed 12/5/02 from plugfest to value 0 + pInt->SetValue(0); + + if (pEsd->FindProperty("slConfig.useAccessUnitEndFlag", + (MP4Property **)&pBits)) + pBits->SetValue(1); + + if (url) { + if (pEsd->FindProperty("URLFlag", + (MP4Property**)&pInt)) + pInt->SetValue(1); + + if (pEsd->FindProperty("URL", + (MP4Property**)&pString)) + pString->SetValue(url); + } + + //return pEsd; +} + +void MP4File::CreateIsmaODUpdateCommandFromFileForFile( + MP4TrackId odTrackId, + MP4TrackId audioTrackId, + MP4TrackId videoTrackId, + u_int8_t** ppBytes, + u_int64_t* pNumBytes) +{ + MP4Descriptor* pCommand = CreateODCommand(MP4ODUpdateODCommandTag); + pCommand->Generate(); + + for (u_int8_t i = 0; i < 2; i++) { + MP4TrackId trackId; + u_int16_t odId; + + if (i == 0) { + trackId = audioTrackId; + odId = 10; + } else { + trackId = videoTrackId; + odId = 20; + } + + if (trackId == MP4_INVALID_TRACK_ID) { + continue; + } + + MP4DescriptorProperty* pOdDescrProperty = + (MP4DescriptorProperty*)(pCommand->GetProperty(0)); + + pOdDescrProperty->SetTags(MP4FileODescrTag); + + MP4Descriptor* pOd = + pOdDescrProperty->AddDescriptor(MP4FileODescrTag); + + pOd->Generate(); + + MP4BitfieldProperty* pOdIdProperty = NULL; + if (pOd->FindProperty("objectDescriptorId", + (MP4Property**)&pOdIdProperty)) + pOdIdProperty->SetValue(odId); + + MP4DescriptorProperty* pEsIdsDescriptorProperty = NULL; + ASSERT(pOd->FindProperty("esIds", + (MP4Property**)&pEsIdsDescriptorProperty)); + ASSERT(pEsIdsDescriptorProperty); + + pEsIdsDescriptorProperty->SetTags(MP4ESIDRefDescrTag); + + MP4Descriptor *pRefDescriptor = + pEsIdsDescriptorProperty->AddDescriptor(MP4ESIDRefDescrTag); + pRefDescriptor->Generate(); + + MP4Integer16Property* pRefIndexProperty = NULL; + ASSERT(pRefDescriptor->FindProperty("refIndex", + (MP4Property**)&pRefIndexProperty)); + ASSERT(pRefIndexProperty); + + u_int32_t mpodIndex = FindTrackReference( + MakeTrackName(odTrackId, "tref.mpod"), trackId); + ASSERT(mpodIndex != 0); + + pRefIndexProperty->SetValue(mpodIndex); + } + + pCommand->WriteToMemory(this, ppBytes, pNumBytes); + + delete pCommand; +} + +void MP4File::CreateIsmaODUpdateCommandFromFileForStream( + MP4TrackId audioTrackId, + MP4TrackId videoTrackId, + u_int8_t** ppBytes, + u_int64_t* pNumBytes) +{ + MP4DescriptorProperty* pAudioEsd = NULL; + MP4Integer8Property* pAudioSLConfigPredef = NULL; + MP4BitfieldProperty* pAudioAccessUnitEndFlag = NULL; + int oldAudioUnitEndFlagValue = 0; + MP4DescriptorProperty* pVideoEsd = NULL; + MP4Integer8Property* pVideoSLConfigPredef = NULL; + MP4BitfieldProperty* pVideoAccessUnitEndFlag = NULL; + int oldVideoUnitEndFlagValue = 0; + MP4IntegerProperty* pAudioEsdId = NULL; + MP4IntegerProperty* pVideoEsdId = NULL; + + if (audioTrackId != MP4_INVALID_TRACK_ID) { + // changed mp4a to * to handle enca case + MP4Atom* pEsdsAtom = + FindAtomMP4File(MakeTrackName(audioTrackId, + "mdia.minf.stbl.stsd.*.esds")); + ASSERT(pEsdsAtom); + + pAudioEsd = (MP4DescriptorProperty*)(pEsdsAtom->GetProperty(2)); + // ESID is 0 for file, stream needs to be non-ze + ASSERT(pAudioEsd->FindProperty("ESID", + (MP4Property**)&pAudioEsdId)); + + ASSERT(pAudioEsdId); + pAudioEsdId->SetValue(audioTrackId); + + // SL config needs to change from 2 (file) to 1 (null) + if (pAudioEsd->FindProperty("slConfigDescr.predefined", + (MP4Property**)&pAudioSLConfigPredef)) { + ASSERT(pAudioSLConfigPredef); + pAudioSLConfigPredef->SetValue(0); + } + + if (pAudioEsd->FindProperty("slConfigDescr.useAccessUnitEndFlag", + (MP4Property **)&pAudioAccessUnitEndFlag)) { + oldAudioUnitEndFlagValue = + pAudioAccessUnitEndFlag->GetValue(); + pAudioAccessUnitEndFlag->SetValue(1); + } + } + + if (videoTrackId != MP4_INVALID_TRACK_ID) { + // changed mp4v to * to handle encv case + MP4Atom* pEsdsAtom = + FindAtomMP4File(MakeTrackName(videoTrackId, + "mdia.minf.stbl.stsd.*.esds")); + ASSERT(pEsdsAtom); + + pVideoEsd = (MP4DescriptorProperty*)(pEsdsAtom->GetProperty(2)); + ASSERT(pVideoEsd->FindProperty("ESID", + (MP4Property**)&pVideoEsdId)); + + ASSERT(pVideoEsdId); + pVideoEsdId->SetValue(videoTrackId); + + // SL config needs to change from 2 (file) to 1 (null) + ASSERT(pVideoEsd->FindProperty("slConfigDescr.predefined", + (MP4Property **)&pVideoSLConfigPredef)); + ASSERT(pVideoSLConfigPredef); + pVideoSLConfigPredef->SetValue(0); + + if (pVideoEsd->FindProperty("slConfigDescr.useAccessUnitEndFlag", + (MP4Property **)&pVideoAccessUnitEndFlag)) { + oldVideoUnitEndFlagValue = + pVideoAccessUnitEndFlag->GetValue(); + pVideoAccessUnitEndFlag->SetValue(1); + } + } + + CreateIsmaODUpdateCommandForStream( + pAudioEsd, pVideoEsd, ppBytes, pNumBytes); + VERBOSE_ISMA(GetVerbosity(), + printf("After CreateImsaODUpdateCommandForStream len "U64" =\n", *pNumBytes); MP4HexDump(*ppBytes, *pNumBytes)); + // return SL config values to 2 (file) + // return ESID values to 0 + if (pAudioSLConfigPredef) { + pAudioSLConfigPredef->SetValue(2); + } + if (pAudioEsdId) { + pAudioEsdId->SetValue(0); + } + if (pAudioAccessUnitEndFlag) { + pAudioAccessUnitEndFlag->SetValue(oldAudioUnitEndFlagValue ); + } + if (pVideoEsdId) { + pVideoEsdId->SetValue(0); + } + if (pVideoSLConfigPredef) { + pVideoSLConfigPredef->SetValue(2); + } + if (pVideoAccessUnitEndFlag) { + pVideoAccessUnitEndFlag->SetValue(oldVideoUnitEndFlagValue ); + } +} + +void MP4File::CreateIsmaODUpdateCommandForStream( + MP4DescriptorProperty* pAudioEsdProperty, + MP4DescriptorProperty* pVideoEsdProperty, + u_int8_t** ppBytes, + u_int64_t* pNumBytes) +{ + MP4Descriptor* pAudioOd = NULL; + MP4Descriptor* pVideoOd = NULL; + + MP4Descriptor* pCommand = + CreateODCommand(MP4ODUpdateODCommandTag); + pCommand->Generate(); + + for (u_int8_t i = 0; i < 2; i++) { + u_int16_t odId; + MP4DescriptorProperty* pEsdProperty = NULL; + + if (i == 0) { + odId = 10; + pEsdProperty = pAudioEsdProperty; + } else { + odId = 20; + pEsdProperty = pVideoEsdProperty; + } + + if (pEsdProperty == NULL) { + continue; + } + + MP4DescriptorProperty* pOdDescrProperty = + (MP4DescriptorProperty*)(pCommand->GetProperty(0)); + + pOdDescrProperty->SetTags(MP4ODescrTag); + + MP4Descriptor* pOd = + pOdDescrProperty->AddDescriptor(MP4ODescrTag); + pOd->Generate(); + + if (i == 0) { + pAudioOd = pOd; + } else { + pVideoOd = pOd; + } + + MP4BitfieldProperty* pOdIdProperty = NULL; + if (pOd->FindProperty("objectDescriptorId", + (MP4Property**)&pOdIdProperty)) { + pOdIdProperty->SetValue(odId); + } + + delete (MP4DescriptorProperty*)pOd->GetProperty(4); + pOd->SetProperty(4, pEsdProperty); + } + + // serialize OD command + pCommand->WriteToMemory(this, ppBytes, pNumBytes); + + // detach from esd descriptor params + if (pAudioOd) { + pAudioOd->SetProperty(4, NULL); + } + if (pVideoOd) { + pVideoOd->SetProperty(4, NULL); + } + + // then destroy + delete pCommand; +} + +void MP4File::CreateIsmaSceneCommand( + bool hasAudio, + bool hasVideo, + u_int8_t** ppBytes, + u_int64_t* pNumBytes) +{ + // from ISMA 1.0 Tech Spec Appendix E + static const u_int8_t bifsAudioOnly[] = { + 0xC0, 0x10, 0x12, + 0x81, 0x30, 0x2A, 0x05, 0x6D, 0xC0 + }; + static const u_int8_t bifsVideoOnly[] = { + 0xC0, 0x10, 0x12, + 0x61, 0x04, + 0x1F, 0xC0, 0x00, 0x00, + 0x1F, 0xC0, 0x00, 0x00, + 0x44, 0x28, 0x22, 0x82, 0x9F, 0x80 + }; + static const u_int8_t bifsAudioVideo[] = { + 0xC0, 0x10, 0x12, + 0x81, 0x30, 0x2A, 0x05, 0x6D, 0x26, + 0x10, 0x41, 0xFC, 0x00, 0x00, 0x01, 0xFC, 0x00, 0x00, + 0x04, 0x42, 0x82, 0x28, 0x29, 0xF8 + }; + + if (hasAudio && hasVideo) { + *pNumBytes = sizeof(bifsAudioVideo); + *ppBytes = (u_int8_t*)MP4Malloc(*pNumBytes); + memcpy(*ppBytes, bifsAudioVideo, sizeof(bifsAudioVideo)); + + } else if (hasAudio) { + *pNumBytes = sizeof(bifsAudioOnly); + *ppBytes = (u_int8_t*)MP4Malloc(*pNumBytes); + memcpy(*ppBytes, bifsAudioOnly, sizeof(bifsAudioOnly)); + + } else if (hasVideo) { + *pNumBytes = sizeof(bifsVideoOnly); + *ppBytes = (u_int8_t*)MP4Malloc(*pNumBytes); + memcpy(*ppBytes, bifsVideoOnly, sizeof(bifsVideoOnly)); + } else { + *pNumBytes = 0; + *ppBytes = NULL; + } +} + diff --git a/Src/external_dependencies/libmp4v2/libmp4v2.def b/Src/external_dependencies/libmp4v2/libmp4v2.def new file mode 100644 index 00000000..f92a9f1f --- /dev/null +++ b/Src/external_dependencies/libmp4v2/libmp4v2.def @@ -0,0 +1,105 @@ +LIBRARY libmp4v2 +EXPORTS + MP4Modify + MP4GetSampleIdFromTime + MP4ConvertToTrackDuration + MP4GetTrackDuration + MP4GetTrackNumberOfSamples + MP4GetTrackTimeScale + MP4Optimize + MP4ReadSample + MP4Read + MP4ReadEx + MP4Close + MP4GetTrackBytesProperty + MP4GetTrackAudioMpeg4Type + MP4GetTrackType + MP4GetTrackEsdsObjectTypeId + MP4FindTrackId + MP4GetNumberOfTracks + MP4GetTrackBitRate + MP4GetTrackMediaDataName + MP4GetMetadataCompilation + MP4SetMetadataCompilation + MP4GetMetadataTempo + MP4SetMetadataTempo + MP4DeleteMetadataTempo + MP4GetMetadataDisk + MP4SetMetadataDisk + MP4DeleteMetadataDisk + MP4GetMetadataTrack + MP4SetMetadataTrack + MP4DeleteMetadataTrack + MP4SetMetadataYear + MP4GetMetadataYear + MP4DeleteMetadataYear + MP4GetMetadataAlbum + MP4SetMetadataAlbum + MP4DeleteMetadataAlbum + MP4SetMetadataGenre + MP4GetMetadataGenre + MP4DeleteMetadataGenre + MP4DeleteMetadataWriter + MP4GetMetadataWriter + MP4SetMetadataWriter + MP4GetMetadataArtist + MP4SetMetadataArtist + MP4DeleteMetadataArtist + MP4GetMetadataComment + MP4GetMetadataName + MP4SetMetadataName + MP4DeleteMetadataName + MP4SetMetadataComment + MP4GetMetadataFreeForm + MP4SetMetadataFreeForm + MP4DeleteMetadataFreeForm + MP4GetMetadataTool + MP4SetMetadataTool + MP4DeleteMetadataTool + MP4Create + MP4MakeIsmaCompliant + MP4SetTrackESConfiguration + MP4WriteSample + MP4SetAudioProfileLevel + MP4AddAudioTrack + MP4SetTimeScale + MP4SetMetadataAlbumArtist + MP4GetMetadataAlbumArtist + MP4DeleteMetadataComment + MP4DeleteMetadataAlbumArtist + MP4Free + MP4GetTrackMaxSampleSize + MP4GetTrackVideoWidth + MP4GetTrackVideoHeight + MP4GetVideoProfileLevel + MP4GetTrackESConfiguration + MP4GetTrackH264SeqPictHeaders + MP4GetTrackVideoMetadata + MP4GetTrackH264ProfileLevel + MP4GetTrackIntegerProperty + MP4GetMetadataCoverArt + MP4SetMetadataCoverArt + MP4DeleteMetadataCoverArt + MP4GetTrackH264LengthSize + MP4Get3GPMetadata + MP4GetStringProperty + MP4Set3GPMetadata + MP4Get3GPMetadataInteger + MP4Delete3GPMetadata + MP4Set3GPMetadataInteger + MP4SetMetadataGrouping + MP4GetMetadataGrouping + MP4DeleteMetadataGrouping + MP4ConvertFromTrackTimestamp + MP4GetSampleTime + MP4PrintVideoInfo + MP4PrintAudioInfo + MP4ReadChunk + MP4GetTrackNumberOfChunks + MP4GetChunkIdFromTime + MP4GetMetadataRating + MP4SetMetadataRating + MP4DeleteMetadataRating + MP4ConvertToTrackTimestamp + MP4GetAudioProfileLevel + MP4GetTrackAudioChannels diff --git a/Src/external_dependencies/libmp4v2/libmp4v2.rc b/Src/external_dependencies/libmp4v2/libmp4v2.rc new file mode 100644 index 00000000..fcff7711 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/libmp4v2.rc @@ -0,0 +1,76 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#include ""version.rc2""\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#include "version.rc2" + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Src/external_dependencies/libmp4v2/libmp4v2.vcxproj b/Src/external_dependencies/libmp4v2/libmp4v2.vcxproj new file mode 100644 index 00000000..269cc78e --- /dev/null +++ b/Src/external_dependencies/libmp4v2/libmp4v2.vcxproj @@ -0,0 +1,396 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{EFB9B882-6A8B-463D-A8E3-A2807AFC5D9F}</ProjectGuid> + <RootNamespace>libmp4v2</RootNamespace> + <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + <IncludePath>$(IncludePath)</IncludePath> + <LibraryPath>$(LibraryPath)</LibraryPath> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + <IncludePath>$(IncludePath)</IncludePath> + <LibraryPath>$(LibraryPath)</LibraryPath> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + <IncludePath>$(IncludePath)</IncludePath> + <LibraryPath>$(LibraryPath)</LibraryPath> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + <IncludePath>$(IncludePath)</IncludePath> + <LibraryPath>$(LibraryPath)</LibraryPath> + </PropertyGroup> + <PropertyGroup Label="Vcpkg"> + <VcpkgEnableManifest>false</VcpkgEnableManifest> + </PropertyGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <VcpkgInstalledDir> + </VcpkgInstalledDir> + <VcpkgUseStatic>false</VcpkgUseStatic> + <VcpkgConfiguration>Debug</VcpkgConfiguration> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + </PropertyGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <VcpkgInstalledDir> + </VcpkgInstalledDir> + <VcpkgUseStatic>false</VcpkgUseStatic> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + </PropertyGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <VcpkgInstalledDir> + </VcpkgInstalledDir> + <VcpkgUseStatic>false</VcpkgUseStatic> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + <VcpkgConfiguration>Debug</VcpkgConfiguration> + </PropertyGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <VcpkgInstalledDir> + </VcpkgInstalledDir> + <VcpkgUseStatic>false</VcpkgUseStatic> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>include;.;../../Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;LIBMP4V2_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <BufferSecurityCheck>true</BufferSecurityCheck> + <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> + <ObjectFileName>$(IntDir)</ObjectFileName> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <CompileAs>Default</CompileAs> + <DisableSpecificWarnings>4244;4800;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + </ClCompile> + <ResourceCompile> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <Culture>0x040c</Culture> + </ResourceCompile> + <Link> + <AdditionalDependencies>odbc32.lib;odbccp32.lib;wsock32.lib;kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <ModuleDefinitionFile>$(ProjectName).def</ModuleDefinitionFile> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(IntDir)$(ProjectName).lib</ImportLibrary> + <TargetMachine>MachineX86</TargetMachine> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <SubSystem>Windows</SubSystem> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\ +xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\ </Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\'</Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>include;.;../Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN64;_DEBUG;_WINDOWS;_MBCS;_USRDLL;LIBMP4V2_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <BufferSecurityCheck>true</BufferSecurityCheck> + <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> + <ObjectFileName>$(IntDir)</ObjectFileName> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <CompileAs>Default</CompileAs> + <DisableSpecificWarnings>4244;4800;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + </ClCompile> + <ResourceCompile> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <Culture>0x040c</Culture> + </ResourceCompile> + <Link> + <AdditionalDependencies>odbc32.lib;odbccp32.lib;wsock32.lib;kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <ModuleDefinitionFile>$(ProjectName).def</ModuleDefinitionFile> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(IntDir)$(ProjectName).lib</ImportLibrary> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <SubSystem>Windows</SubSystem> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\ +xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\ </Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\'</Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <Optimization>MinSpace</Optimization> + <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> + <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> + <AdditionalIncludeDirectories>include;.;../../Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;LIBMP4V2_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <StringPooling>true</StringPooling> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <BufferSecurityCheck>false</BufferSecurityCheck> + <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> + <ObjectFileName>$(IntDir)</ObjectFileName> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>None</DebugInformationFormat> + <DisableSpecificWarnings>4244;4800;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + </ClCompile> + <ResourceCompile> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <Culture>0x040c</Culture> + </ResourceCompile> + <Link> + <AdditionalDependencies>odbc32.lib;odbccp32.lib;wsock32.lib;kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <ModuleDefinitionFile>$(ProjectName).def</ModuleDefinitionFile> + <GenerateDebugInformation>false</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(IntDir)$(ProjectName).lib</ImportLibrary> + <TargetMachine>MachineX86</TargetMachine> + <SubSystem>Windows</SubSystem> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\ </Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\'</Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <Optimization>MinSpace</Optimization> + <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> + <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> + <AdditionalIncludeDirectories>include;.;../Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_MBCS;_USRDLL;LIBMP4V2_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <StringPooling>true</StringPooling> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <BufferSecurityCheck>false</BufferSecurityCheck> + <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> + <ObjectFileName>$(IntDir)</ObjectFileName> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>None</DebugInformationFormat> + <CompileAs>Default</CompileAs> + <DisableSpecificWarnings>4244;4800;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + </ClCompile> + <ResourceCompile> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <Culture>0x040c</Culture> + </ResourceCompile> + <Link> + <AdditionalDependencies>odbc32.lib;odbccp32.lib;wsock32.lib;kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <ModuleDefinitionFile>$(ProjectName).def</ModuleDefinitionFile> + <GenerateDebugInformation>false</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(IntDir)$(ProjectName).lib</ImportLibrary> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <SubSystem>Windows</SubSystem> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\ </Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\'</Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemGroup> + <None Include="libmp4v2.def" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="3gp.cpp" /> + <ClCompile Include="3gpmeta.cpp" /> + <ClCompile Include="atom_amr.cpp" /> + <ClCompile Include="atom_avc1.cpp" /> + <ClCompile Include="atom_avcC.cpp" /> + <ClCompile Include="atom_chpl.cpp" /> + <ClCompile Include="atom_d263.cpp" /> + <ClCompile Include="atom_damr.cpp" /> + <ClCompile Include="atom_dref.cpp" /> + <ClCompile Include="atom_elst.cpp" /> + <ClCompile Include="atom_enca.cpp" /> + <ClCompile Include="atom_encv.cpp" /> + <ClCompile Include="atom_free.cpp" /> + <ClCompile Include="atom_ftyp.cpp" /> + <ClCompile Include="atom_gmin.cpp" /> + <ClCompile Include="atom_hdlr.cpp" /> + <ClCompile Include="atom_hinf.cpp" /> + <ClCompile Include="atom_hnti.cpp" /> + <ClCompile Include="atom_href.cpp" /> + <ClCompile Include="atom_mdat.cpp" /> + <ClCompile Include="atom_mdhd.cpp" /> + <ClCompile Include="atom_meta.cpp" /> + <ClCompile Include="atom_mp4a.cpp" /> + <ClCompile Include="atom_mp4s.cpp" /> + <ClCompile Include="atom_mp4v.cpp" /> + <ClCompile Include="atom_mvhd.cpp" /> + <ClCompile Include="atom_ohdr.cpp" /> + <ClCompile Include="atom_root.cpp" /> + <ClCompile Include="atom_rtp.cpp" /> + <ClCompile Include="atom_s263.cpp" /> + <ClCompile Include="atom_sdp.cpp" /> + <ClCompile Include="atom_smi.cpp" /> + <ClCompile Include="atom_sound.cpp" /> + <ClCompile Include="atom_standard.cpp" /> + <ClCompile Include="atom_stbl.cpp" /> + <ClCompile Include="atom_stdp.cpp" /> + <ClCompile Include="atom_stsc.cpp" /> + <ClCompile Include="atom_stsd.cpp" /> + <ClCompile Include="atom_stsz.cpp" /> + <ClCompile Include="atom_stz2.cpp" /> + <ClCompile Include="atom_text.cpp" /> + <ClCompile Include="atom_tfhd.cpp" /> + <ClCompile Include="atom_tkhd.cpp" /> + <ClCompile Include="atom_treftype.cpp" /> + <ClCompile Include="atom_trun.cpp" /> + <ClCompile Include="atom_udta.cpp" /> + <ClCompile Include="atom_url.cpp" /> + <ClCompile Include="atom_urn.cpp" /> + <ClCompile Include="atom_video.cpp" /> + <ClCompile Include="atom_vmhd.cpp" /> + <ClCompile Include="descriptors.cpp" /> + <ClCompile Include="isma.cpp" /> + <ClCompile Include="mp4.cpp" /> + <ClCompile Include="mp4atom.cpp" /> + <ClCompile Include="mp4container.cpp" /> + <ClCompile Include="mp4descriptor.cpp" /> + <ClCompile Include="mp4file.cpp" /> + <ClCompile Include="mp4file_io.cpp" /> + <ClCompile Include="mp4info.cpp" /> + <ClCompile Include="mp4meta.cpp" /> + <ClCompile Include="mp4property.cpp" /> + <ClCompile Include="mp4track.cpp" /> + <ClCompile Include="mp4util.cpp" /> + <ClCompile Include="need_for_win32.c" /> + <ClCompile Include="ocidescriptors.cpp" /> + <ClCompile Include="odcommands.cpp" /> + <ClCompile Include="qosqualifiers.cpp" /> + <ClCompile Include="rtphint.cpp" /> + <ClCompile Include="virtual_io.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="atoms.h" /> + <ClInclude Include="descriptors.h" /> + <ClInclude Include="mp4.h" /> + <ClInclude Include="mp4array.h" /> + <ClInclude Include="mp4atom.h" /> + <ClInclude Include="mp4common.h" /> + <ClInclude Include="mp4container.h" /> + <ClInclude Include="mp4descriptor.h" /> + <ClInclude Include="mp4file.h" /> + <ClInclude Include="mp4property.h" /> + <ClInclude Include="mp4track.h" /> + <ClInclude Include="mp4util.h" /> + <ClInclude Include="ocidescriptors.h" /> + <ClInclude Include="odcommands.h" /> + <ClInclude Include="qosqualifiers.h" /> + <ClInclude Include="resource.h" /> + <ClInclude Include="rtphint.h" /> + <ClInclude Include="virtual_io.h" /> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="libmp4v2.rc" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\..\replicant\nu\nu.vcxproj"> + <Project>{f1f5cd60-0d5b-4cea-9eeb-2f87ff9aa915}</Project> + </ProjectReference> + <ProjectReference Include="..\..\Wasabi\bfc\bfc.vcxproj"> + <Project>{d0ec862e-dddd-4f4f-934f-b75dc9062dc1}</Project> + </ProjectReference> + <ProjectReference Include="..\..\Wasabi\Wasabi.vcxproj"> + <Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/Src/external_dependencies/libmp4v2/libmp4v2.vcxproj.filters b/Src/external_dependencies/libmp4v2/libmp4v2.vcxproj.filters new file mode 100644 index 00000000..fa3c62e8 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/libmp4v2.vcxproj.filters @@ -0,0 +1,289 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <ClCompile Include="3gp.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="3gpmeta.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_amr.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_avc1.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_avcC.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_chpl.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_d263.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_damr.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_dref.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_elst.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_enca.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_encv.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_free.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_ftyp.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_gmin.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_hdlr.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_hinf.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_hnti.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_href.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_mdat.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_mdhd.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_meta.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_mp4a.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_mp4s.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_mp4v.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_mvhd.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_ohdr.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_root.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_rtp.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_s263.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_sdp.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_smi.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_sound.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_standard.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_stbl.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_stdp.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_stsc.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_stsd.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_stsz.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_stz2.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_text.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_tfhd.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_tkhd.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_treftype.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_trun.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_udta.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_url.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_urn.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_video.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="atom_vmhd.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="descriptors.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="isma.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="mp4.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="mp4atom.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="mp4container.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="mp4descriptor.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="mp4file.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="mp4file_io.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="mp4info.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="mp4meta.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="mp4property.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="mp4track.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="mp4util.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="need_for_win32.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ocidescriptors.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="odcommands.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="qosqualifiers.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="rtphint.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="virtual_io.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="atoms.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="mp4.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="mp4array.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="mp4atom.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="mp4common.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="mp4container.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="mp4descriptor.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="mp4file.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="mp4property.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="mp4track.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="mp4util.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="ocidescriptors.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="odcommands.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="qosqualifiers.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="resource.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="rtphint.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="virtual_io.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="descriptors.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <Filter Include="Header Files"> + <UniqueIdentifier>{67a0c719-1a06-41a1-aeb1-ad5ed39591b3}</UniqueIdentifier> + </Filter> + <Filter Include="Ressource Files"> + <UniqueIdentifier>{de2c7031-36a6-41f3-b001-5a9c6090a097}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files"> + <UniqueIdentifier>{7569046e-c8b9-4fa1-938c-d579139c640b}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="libmp4v2.rc"> + <Filter>Ressource Files</Filter> + </ResourceCompile> + </ItemGroup> + <ItemGroup> + <None Include="libmp4v2.def"> + <Filter>Ressource Files</Filter> + </None> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/Src/external_dependencies/libmp4v2/mp4.cpp b/Src/external_dependencies/libmp4v2/mp4.cpp new file mode 100644 index 00000000..2f7ff236 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/mp4.cpp @@ -0,0 +1,4642 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001 - 2005. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + * Alix Marchandise-Franquet alix@cisco.com + * Ximpo Group Ltd. mp4v2@ximpo.com + * Bill May wmay@cisco.com + */ + +/* + * MP4 library API functions + * + * These are wrapper functions that provide C linkage conventions + * to the library, and catch any internal errors, ensuring that + * a proper return value is given. + */ + +#include "mp4common.h" + +#define PRINT_ERROR(e) \ + VERBOSE_ERROR(((MP4File*)hFile)->GetVerbosity(), e->Print()); + +/* file operations */ +// benski> + extern "C" MP4FileHandle MP4ReadEx (const MP4_FILENAME_CHAR *fileName, + void *user, + struct Virtual_IO *virtual_IO, + u_int32_t verbosity) +{ + MP4File* pFile = NULL; + try { + pFile = new MP4File(verbosity); + + pFile->ReadEx(fileName, user, virtual_IO); + return (MP4FileHandle)pFile; + } catch (MP4Error* e) { + VERBOSE_ERROR(verbosity, e->Print()); + delete e; + delete pFile; + return MP4_INVALID_FILE_HANDLE; + } +} + +extern "C" MP4FileHandle MP4Read(const MP4_FILENAME_CHAR *fileName, u_int32_t verbosity) +{ + MP4File* pFile = NULL; + try { + pFile = new MP4File(verbosity); + pFile->Read(fileName); + return (MP4FileHandle)pFile; + } + catch (MP4Error* e) { + VERBOSE_ERROR(verbosity, e->Print()); + delete e; + delete pFile; + return MP4_INVALID_FILE_HANDLE; + } +} + +extern "C" MP4FileHandle MP4Create (const MP4_FILENAME_CHAR *fileName, + u_int32_t verbosity, + u_int32_t flags) +{ + return MP4CreateEx(fileName, verbosity, flags); +} + +extern "C" MP4FileHandle MP4CreateEx (const MP4_FILENAME_CHAR *fileName, + u_int32_t verbosity, + u_int32_t flags, + int add_ftyp, + int add_iods, + char* majorBrand, + u_int32_t minorVersion, + char** supportedBrands, + u_int32_t supportedBrandsCount) +{ + MP4File* pFile = NULL; + try { + pFile = new MP4File(verbosity); + // LATER useExtensibleFormat, moov first, then mvex's + pFile->Create(fileName, flags, add_ftyp, add_iods, + majorBrand, minorVersion, + supportedBrands, supportedBrandsCount); + return (MP4FileHandle)pFile; + } + catch (MP4Error* e) { + VERBOSE_ERROR(verbosity, e->Print()); + delete e; + delete pFile; + return MP4_INVALID_FILE_HANDLE; + } +} + +extern "C" MP4FileHandle MP4Modify(const MP4_FILENAME_CHAR *fileName, + u_int32_t verbosity, u_int32_t flags) +{ + MP4File* pFile = NULL; + try { + pFile = new MP4File(verbosity); + // LATER useExtensibleFormat, moov first, then mvex's + pFile->Modify(fileName); + return (MP4FileHandle)pFile; + } + catch (MP4Error* e) { + VERBOSE_ERROR(verbosity, e->Print()); + delete e; + delete pFile; + return MP4_INVALID_FILE_HANDLE; + } +} + +extern "C" bool MP4Optimize(const MP4_FILENAME_CHAR* existingFileName, + const MP4_FILENAME_CHAR* newFileName, + u_int32_t verbosity) +{ + try { + MP4File* pFile = new MP4File(verbosity); + pFile->Optimize(existingFileName, newFileName); + delete pFile; + return true; + } + catch (MP4Error* e) { + VERBOSE_ERROR(verbosity, e->Print()); + delete e; + } + return false; +} + +extern "C" void MP4Close(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->Close(); + delete (MP4File*)hFile; + return; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return ; +} + +/* specific file properties */ + +extern "C" u_int32_t MP4GetVerbosity(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetVerbosity(); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return 0; +} + +extern "C" void MP4SetVerbosity(MP4FileHandle hFile, u_int32_t verbosity) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetVerbosity(verbosity); + return; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return; +} + +extern "C" MP4Duration MP4GetDuration(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetDuration(); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_DURATION; +} + +extern "C" u_int32_t MP4GetTimeScale(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTimeScale(); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return 0; +} + +extern "C" bool MP4SetTimeScale(MP4FileHandle hFile, u_int32_t value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetTimeScale(value); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" u_int8_t MP4GetODProfileLevel(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetODProfileLevel(); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return 0; +} + +extern "C" bool MP4SetODProfileLevel(MP4FileHandle hFile, u_int8_t value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetODProfileLevel(value); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" u_int8_t MP4GetSceneProfileLevel(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetSceneProfileLevel(); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return 0; +} + +extern "C" bool MP4SetSceneProfileLevel(MP4FileHandle hFile, u_int8_t value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetSceneProfileLevel(value); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" u_int8_t MP4GetVideoProfileLevel(MP4FileHandle hFile, + MP4TrackId trackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetVideoProfileLevel(); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + if (MP4_IS_VALID_TRACK_ID(trackId)) { + uint8_t *foo; + uint32_t bufsize; + uint8_t type; + // for mpeg4 video tracks, try to look for the VOSH header, + // which has this info. + type = MP4GetTrackEsdsObjectTypeId(hFile, trackId); + if (type == MP4_MPEG4_VIDEO_TYPE) { + if (MP4GetTrackESConfiguration(hFile, + trackId, + &foo, + &bufsize)) { + uint8_t *ptr = foo; + while (bufsize > 0) { + if (htonl(*(uint32_t *)ptr) == 0x1b0) { + uint8_t ret = ptr[4]; + free(foo); + return ret; + } + ptr++; + bufsize--; + } + free(foo); + } + } + } + + } + return 0; +} + +extern "C" void MP4SetVideoProfileLevel(MP4FileHandle hFile, u_int8_t value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetVideoProfileLevel(value); + return ; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return ; +} + +extern "C" u_int8_t MP4GetAudioProfileLevel(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetAudioProfileLevel(); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return 0; +} + +extern "C" void MP4SetAudioProfileLevel(MP4FileHandle hFile, u_int8_t value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetAudioProfileLevel(value); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } +} + +extern "C" u_int8_t MP4GetGraphicsProfileLevel(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetGraphicsProfileLevel(); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return 0; +} + +extern "C" bool MP4SetGraphicsProfileLevel(MP4FileHandle hFile, u_int8_t value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetGraphicsProfileLevel(value); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +/* generic file properties */ + +extern "C" bool MP4HaveAtom (MP4FileHandle hFile, const char *atomName) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File *)hFile)->FindAtomMP4File(atomName) != NULL; + } catch (MP4Error *e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetIntegerProperty( + MP4FileHandle hFile, const char* propName, u_int64_t *retvalue) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + *retvalue = ((MP4File*)hFile)->GetIntegerProperty(propName); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetFloatProperty( + MP4FileHandle hFile, const char* propName, float *retvalue) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + *retvalue = ((MP4File*)hFile)->GetFloatProperty(propName); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetStringProperty( + MP4FileHandle hFile, const char* propName, + const char **retvalue) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + *retvalue = ((MP4File*)hFile)->GetStringProperty(propName); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetBytesProperty( + MP4FileHandle hFile, const char* propName, + u_int8_t** ppValue, u_int32_t* pValueSize) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->GetBytesProperty(propName, ppValue, pValueSize); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + *ppValue = NULL; + *pValueSize = 0; + return false; +} + +extern "C" bool MP4SetIntegerProperty( + MP4FileHandle hFile, const char* propName, int64_t value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetIntegerProperty(propName, value); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4SetFloatProperty( + MP4FileHandle hFile, const char* propName, float value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetFloatProperty(propName, value); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4SetStringProperty( + MP4FileHandle hFile, const char* propName, const char* value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetStringProperty(propName, value); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4SetBytesProperty( + MP4FileHandle hFile, const char* propName, + const u_int8_t* pValue, u_int32_t valueSize) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetBytesProperty(propName, pValue, valueSize); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +/* track operations */ + +extern "C" MP4TrackId MP4AddTrack( + MP4FileHandle hFile, const char* type) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->AddSystemsTrack(type); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_TRACK_ID; +} + +extern "C" MP4TrackId MP4AddSystemsTrack( + MP4FileHandle hFile, const char* type) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->AddSystemsTrack(type); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_TRACK_ID; +} + +extern "C" MP4TrackId MP4AddODTrack(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->AddODTrack(); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_TRACK_ID; +} + +extern "C" MP4TrackId MP4AddSceneTrack(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->AddSceneTrack(); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_TRACK_ID; +} + +extern "C" MP4TrackId MP4AddAudioTrack( + MP4FileHandle hFile, + u_int32_t timeScale, + MP4Duration sampleDuration, + u_int8_t audioType) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)-> + AddAudioTrack(timeScale, sampleDuration, audioType); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_TRACK_ID; +} + +// +// API to initialize ismacryp properties to sensible defaults. +// if the input pointer is null then an ismacryp params is malloc'd. +// caller must see to it that it is properly disposed of. +// +extern "C" mp4v2_ismacrypParams *MP4DefaultISMACrypParams(mp4v2_ismacrypParams *ptr) +{ + try + { + if (ptr == NULL) { + ptr = (mp4v2_ismacrypParams *)MP4Malloc(sizeof(mp4v2_ismacrypParams)); + } + memset(ptr, 0, sizeof(*ptr)); + return ptr; + } + + catch (...) { + return 0; + } +} + + +extern "C" MP4TrackId MP4AddEncAudioTrack(MP4FileHandle hFile, + u_int32_t timeScale, + MP4Duration sampleDuration, + mp4v2_ismacrypParams *icPp, + u_int8_t audioType) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + if (icPp == NULL) { + return ((MP4File*)hFile)-> + AddEncAudioTrack(timeScale, sampleDuration, audioType, + 0, 0, + 0, 0, + false, NULL, false); + } else { + return ((MP4File*)hFile)-> + AddEncAudioTrack(timeScale, sampleDuration, audioType, + icPp->scheme_type, icPp->scheme_version, + icPp->key_ind_len, icPp->iv_len, + icPp->selective_enc, icPp->kms_uri, true); + } + } catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_TRACK_ID; +} +extern "C" MP4TrackId MP4AddAmrAudioTrack( + MP4FileHandle hFile, + u_int32_t timeScale, + u_int16_t modeSet, + u_int8_t modeChangePeriod, + u_int8_t framesPerSample, + bool isAmrWB) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)-> + AddAmrAudioTrack(timeScale, modeSet, modeChangePeriod, framesPerSample, isAmrWB); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_TRACK_ID; +} + +extern "C" void MP4SetAmrVendor( + MP4FileHandle hFile, + MP4TrackId trackId, + u_int32_t vendor) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)-> + SetAmrVendor(trackId, vendor); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } +} + +extern "C" void MP4SetAmrDecoderVersion( + MP4FileHandle hFile, + MP4TrackId trackId, + u_int8_t decoderVersion) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)-> + SetAmrDecoderVersion(trackId, decoderVersion); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } +} + +extern "C" void MP4SetAmrModeSet( + MP4FileHandle hFile, + MP4TrackId trackId, + u_int16_t modeSet) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)-> + SetAmrModeSet(trackId, modeSet); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } +} + +extern "C" uint16_t MP4GetAmrModeSet( + MP4FileHandle hFile, + MP4TrackId trackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)-> + GetAmrModeSet(trackId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return 0; +} + +extern "C" MP4TrackId MP4AddHrefTrack (MP4FileHandle hFile, + uint32_t timeScale, + MP4Duration sampleDuration, + const char *base_url) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + MP4File *pFile = (MP4File *)hFile; + + return pFile->AddHrefTrack(timeScale, + sampleDuration, + base_url); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_TRACK_ID; +} + +extern "C" const char *MP4GetHrefTrackBaseUrl (MP4FileHandle hFile, + MP4TrackId trackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackStringProperty(trackId, + "mdia.minf.stbl.stsd.href.burl.base_url"); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return NULL; +} + +extern "C" MP4TrackId MP4AddVideoTrack( + MP4FileHandle hFile, + u_int32_t timeScale, + MP4Duration sampleDuration, + u_int16_t width, + u_int16_t height, + u_int8_t videoType) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + MP4File *pFile = (MP4File *)hFile; + + return pFile->AddMP4VideoTrack(timeScale, + sampleDuration, + width, + height, + videoType); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_TRACK_ID; +} + +extern "C" MP4TrackId MP4AddEncVideoTrack(MP4FileHandle hFile, + u_int32_t timeScale, + MP4Duration sampleDuration, + u_int16_t width, + u_int16_t height, + mp4v2_ismacrypParams *icPp, + u_int8_t videoType, + const char *oFormat) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + + // test for valid ismacrypt session descriptor + if (icPp == NULL) { + return MP4_INVALID_TRACK_ID; + } + MP4File *pFile = (MP4File *)hFile; + + return pFile->AddEncVideoTrack(timeScale, + sampleDuration, + width, + height, + videoType, + icPp, + oFormat); + + } catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_TRACK_ID; +} + + +extern "C" MP4TrackId MP4AddH264VideoTrack(MP4FileHandle hFile, + u_int32_t timeScale, + MP4Duration sampleDuration, + u_int16_t width, + u_int16_t height, + uint8_t AVCProfileIndication, + uint8_t profile_compat, + uint8_t AVCLevelIndication, + uint8_t sampleLenFieldSizeMinusOne) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + MP4File *pFile = (MP4File *)hFile; + + return pFile->AddH264VideoTrack(timeScale, + sampleDuration, + width, + height, + AVCProfileIndication, + profile_compat, + AVCLevelIndication, + sampleLenFieldSizeMinusOne); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_TRACK_ID; +} + +extern "C" MP4TrackId MP4AddEncH264VideoTrack( + MP4FileHandle hFile, + u_int32_t timeScale, + MP4Duration sampleDuration, + u_int16_t width, + u_int16_t height, + MP4FileHandle srcFile, + MP4TrackId srcTrackId, + mp4v2_ismacrypParams *icPp +) + +{ + MP4Atom *srcAtom; + MP4File *pFile; + + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + + pFile = (MP4File *)srcFile; + srcAtom = pFile->FindTrackAtom(srcTrackId, "mdia.minf.stbl.stsd.avc1.avcC"); + if (srcAtom == NULL) + return MP4_INVALID_TRACK_ID; + + pFile = (MP4File *)hFile; + + return pFile->AddEncH264VideoTrack(timeScale, + sampleDuration, + width, + height, + srcAtom, + icPp); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_TRACK_ID; +} + +extern "C" void MP4AddH264SequenceParameterSet (MP4FileHandle hFile, + MP4TrackId trackId, + const uint8_t *pSequence, + uint16_t sequenceLen) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + MP4File *pFile = (MP4File *)hFile; + + pFile->AddH264SequenceParameterSet(trackId, + pSequence, + sequenceLen); + return; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return; +} +extern "C" void MP4AddH264PictureParameterSet (MP4FileHandle hFile, + MP4TrackId trackId, + const uint8_t *pPict, + uint16_t pictLen) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + MP4File *pFile = (MP4File *)hFile; + + pFile->AddH264PictureParameterSet(trackId, + pPict, + pictLen); + return; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return; +} + +extern "C" MP4TrackId MP4AddH263VideoTrack( + MP4FileHandle hFile, + u_int32_t timeScale, + MP4Duration sampleDuration, + u_int16_t width, + u_int16_t height, + u_int8_t h263Level, + u_int8_t h263Profile, + u_int32_t avgBitrate, + u_int32_t maxBitrate) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)-> + AddH263VideoTrack(timeScale, sampleDuration, width, height, h263Level, h263Profile, avgBitrate, maxBitrate); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + + return MP4_INVALID_TRACK_ID; +} + +extern "C" void MP4SetH263Vendor( + MP4FileHandle hFile, + MP4TrackId trackId, + u_int32_t vendor) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)-> + SetH263Vendor(trackId, vendor); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } +} + +extern "C" void MP4SetH263DecoderVersion( + MP4FileHandle hFile, + MP4TrackId trackId, + u_int8_t decoderVersion) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + + try { + ((MP4File*)hFile)-> + SetH263DecoderVersion(trackId, decoderVersion); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } +} + +extern "C" void MP4SetH263Bitrates( + MP4FileHandle hFile, + MP4TrackId trackId, + u_int32_t avgBitrate, + u_int32_t maxBitrate) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + + try { + ((MP4File*)hFile)-> + SetH263Bitrates(trackId, avgBitrate, maxBitrate); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } +} + +extern "C" MP4TrackId MP4AddHintTrack( + MP4FileHandle hFile, MP4TrackId refTrackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->AddHintTrack(refTrackId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_TRACK_ID; +} + +extern "C" MP4TrackId MP4AddTextTrack( + MP4FileHandle hFile, MP4TrackId refTrackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->AddTextTrack(refTrackId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_TRACK_ID; +} + +extern "C" MP4TrackId MP4AddChapterTextTrack(MP4FileHandle hFile, MP4TrackId refTrackId, u_int32_t timescale) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->AddChapterTextTrack(refTrackId, timescale); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_TRACK_ID; +} +extern "C" void MP4AddQTChapter( + MP4FileHandle hFile, + MP4TrackId chapterTrackId, + MP4Duration chapterDuration, + u_int32_t chapterNr, + const char * chapterTitle) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->AddChapter(chapterTrackId, chapterDuration, chapterNr, chapterTitle); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } +} + + +extern "C" void MP4AddChapter( + MP4FileHandle hFile, + MP4Timestamp chapterStart, + const char * chapterTitle) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->AddChapter(chapterStart, chapterTitle); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } +} + + +extern "C" void MP4ConvertChapters( + MP4FileHandle hFile, + bool toQT) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->ConvertChapters(toQT); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } +} + + +extern "C" void MP4DeleteChapters( + MP4FileHandle hFile, + MP4TrackId chapterTrackId, + bool deleteQT) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->DeleteChapters(chapterTrackId, deleteQT); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } +} + + +extern "C" void MP4GetChaptersList( + MP4FileHandle hFile, + MP4Chapters_t ** chapterList, + u_int32_t * chapterCount, + bool getQT) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->GetChaptersList(chapterList, chapterCount, getQT); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } +} + + + +extern "C" MP4TrackId MP4CloneTrack (MP4FileHandle srcFile, + MP4TrackId srcTrackId, + MP4FileHandle dstFile, + MP4TrackId dstHintTrackReferenceTrack) +{ + MP4TrackId dstTrackId = MP4_INVALID_TRACK_ID; + + if (dstFile == NULL) { + dstFile = srcFile; + } + + const char* trackType = + MP4GetTrackType(srcFile, srcTrackId); + + if (!trackType) { + return dstTrackId; + } + + const char *media_data_name = + MP4GetTrackMediaDataName(srcFile, srcTrackId); + if (media_data_name == NULL) return dstTrackId; + + if (MP4_IS_VIDEO_TRACK_TYPE(trackType)) { + if (ATOMID(media_data_name) == ATOMID("mp4v")) { + MP4SetVideoProfileLevel(dstFile, + MP4GetVideoProfileLevel(srcFile)); + dstTrackId = MP4AddVideoTrack( + dstFile, + MP4GetTrackTimeScale(srcFile, + srcTrackId), + MP4GetTrackFixedSampleDuration(srcFile, + srcTrackId), + MP4GetTrackVideoWidth(srcFile, + srcTrackId), + MP4GetTrackVideoHeight(srcFile, + srcTrackId), + MP4GetTrackEsdsObjectTypeId(srcFile, + srcTrackId)); + } else if (ATOMID(media_data_name) == ATOMID("avc1")) { + uint8_t AVCProfileIndication; + uint8_t profile_compat; + uint8_t AVCLevelIndication; + uint32_t sampleLenFieldSizeMinusOne; + uint64_t temp; + + if (MP4GetTrackH264ProfileLevel(srcFile, srcTrackId, + &AVCProfileIndication, + &AVCLevelIndication) == false) { + return dstTrackId; + } + if (MP4GetTrackH264LengthSize(srcFile, srcTrackId, + &sampleLenFieldSizeMinusOne) == false) { + return dstTrackId; + } + sampleLenFieldSizeMinusOne--; + if (MP4GetTrackIntegerProperty(srcFile, srcTrackId, + "mdia.minf.stbl.stsd.*[0].avcC.profile_compatibility", + &temp) == false) return dstTrackId; + profile_compat = temp & 0xff; + + dstTrackId = MP4AddH264VideoTrack(dstFile, + MP4GetTrackTimeScale(srcFile, + srcTrackId), + MP4GetTrackFixedSampleDuration(srcFile, + srcTrackId), + MP4GetTrackVideoWidth(srcFile, + srcTrackId), + MP4GetTrackVideoHeight(srcFile, + srcTrackId), + AVCProfileIndication, + profile_compat, + AVCLevelIndication, + sampleLenFieldSizeMinusOne); + uint8_t **seqheader, **pictheader; + uint32_t *pictheadersize, *seqheadersize; + uint32_t ix; + MP4GetTrackH264SeqPictHeaders(srcFile, srcTrackId, + &seqheader, &seqheadersize, + &pictheader, &pictheadersize); + for (ix = 0; seqheadersize[ix] != 0; ix++) { + MP4AddH264SequenceParameterSet(dstFile, dstTrackId, + seqheader[ix], seqheadersize[ix]); + free(seqheader[ix]); + } + free(seqheader); + free(seqheadersize); + for (ix = 0; pictheadersize[ix] != 0; ix++) { + MP4AddH264PictureParameterSet(dstFile, dstTrackId, + pictheader[ix], pictheadersize[ix]); + free(pictheader[ix]); + } + free(pictheader); + free(pictheadersize); + } else + return dstTrackId; + } else if (MP4_IS_AUDIO_TRACK_TYPE(trackType)) { + if (ATOMID(media_data_name) != ATOMID("mp4a")) return dstTrackId; + MP4SetAudioProfileLevel(dstFile, + MP4GetAudioProfileLevel(srcFile)); + dstTrackId = MP4AddAudioTrack( + dstFile, + MP4GetTrackTimeScale(srcFile, srcTrackId), + MP4GetTrackFixedSampleDuration(srcFile, srcTrackId), + MP4GetTrackEsdsObjectTypeId(srcFile, srcTrackId)); + + } else if (MP4_IS_OD_TRACK_TYPE(trackType)) { + dstTrackId = MP4AddODTrack(dstFile); + + } else if (MP4_IS_SCENE_TRACK_TYPE(trackType)) { + dstTrackId = MP4AddSceneTrack(dstFile); + + } else if (MP4_IS_HINT_TRACK_TYPE(trackType)) { + if (dstHintTrackReferenceTrack == MP4_INVALID_TRACK_ID) { + dstTrackId = MP4_INVALID_TRACK_ID; + } else { + dstTrackId = MP4AddHintTrack( + dstFile, + dstHintTrackReferenceTrack); + } + + } else if (MP4_IS_SYSTEMS_TRACK_TYPE(trackType)) { + dstTrackId = MP4AddSystemsTrack(dstFile, trackType); + + } else { + dstTrackId = MP4AddTrack(dstFile, trackType); + } + + if (dstTrackId == MP4_INVALID_TRACK_ID) { + return dstTrackId; + } + + MP4SetTrackTimeScale( + dstFile, + dstTrackId, + MP4GetTrackTimeScale(srcFile, srcTrackId)); + + if (MP4_IS_AUDIO_TRACK_TYPE(trackType) + || MP4_IS_VIDEO_TRACK_TYPE(trackType)) { + // copy track ES configuration + u_int8_t* pConfig = NULL; + u_int32_t configSize = 0; + + if (MP4GetTrackESConfiguration( + srcFile, + srcTrackId, + &pConfig, + &configSize) && + pConfig != NULL && configSize != 0) { + if (!MP4SetTrackESConfiguration( + dstFile, + dstTrackId, + pConfig, + configSize)) { + free(pConfig); + MP4DeleteTrack(dstFile, dstTrackId); + return MP4_INVALID_TRACK_ID; + } + + free(pConfig); + } + } + + if (MP4_IS_HINT_TRACK_TYPE(trackType)) { + // probably not exactly what is wanted + // but caller can adjust later to fit their desires + + char* payloadName = NULL; + char *encodingParms = NULL; + u_int8_t payloadNumber; + u_int16_t maxPayloadSize; + + if (MP4GetHintTrackRtpPayload( + srcFile, + srcTrackId, + &payloadName, + &payloadNumber, + &maxPayloadSize, + &encodingParms)) { + + if (MP4SetHintTrackRtpPayload( + dstFile, + dstTrackId, + payloadName, + &payloadNumber, + maxPayloadSize, + encodingParms) == false) { + MP4DeleteTrack(dstFile, dstTrackId); + return MP4_INVALID_TRACK_ID; + } + } +#if 0 + MP4SetHintTrackSdp( + dstFile, + dstTrackId, + MP4GetHintTrackSdp(srcFile, srcTrackId)); +#endif + } + + return dstTrackId; +} + +// Given a track, make an encrypted clone of it in the dest. file +extern "C" MP4TrackId MP4EncAndCloneTrack(MP4FileHandle srcFile, + MP4TrackId srcTrackId, + mp4v2_ismacrypParams *icPp, + MP4FileHandle dstFile, + MP4TrackId dstHintTrackReferenceTrack + ) +{ + const char *oFormat; + + MP4TrackId dstTrackId = MP4_INVALID_TRACK_ID; + + if (dstFile == NULL) { + dstFile = srcFile; + } + + const char* trackType = MP4GetTrackType(srcFile, srcTrackId); + + if (!trackType) { + return dstTrackId; + } + + if (MP4_IS_VIDEO_TRACK_TYPE(trackType)) { + + // test source file format for avc1 + oFormat = MP4GetTrackMediaDataName(srcFile, srcTrackId); + if (!strcasecmp(oFormat, "avc1")) + { + dstTrackId = MP4AddEncH264VideoTrack(dstFile, + MP4GetTrackTimeScale(srcFile, srcTrackId), + MP4GetTrackFixedSampleDuration(srcFile, srcTrackId), + MP4GetTrackVideoWidth(srcFile, srcTrackId), + MP4GetTrackVideoHeight(srcFile, srcTrackId), + srcFile, + srcTrackId, + icPp + ); + } + else + { + MP4SetVideoProfileLevel(dstFile, MP4GetVideoProfileLevel(srcFile)); + dstTrackId = MP4AddEncVideoTrack(dstFile, + MP4GetTrackTimeScale(srcFile, srcTrackId), + MP4GetTrackFixedSampleDuration(srcFile, srcTrackId), + MP4GetTrackVideoWidth(srcFile, srcTrackId), + MP4GetTrackVideoHeight(srcFile, srcTrackId), + icPp, + MP4GetTrackEsdsObjectTypeId(srcFile, srcTrackId), + oFormat + ); + } + + } else if (MP4_IS_AUDIO_TRACK_TYPE(trackType)) { + MP4SetAudioProfileLevel(dstFile, MP4GetAudioProfileLevel(srcFile)); + dstTrackId = MP4AddEncAudioTrack(dstFile, + MP4GetTrackTimeScale(srcFile, srcTrackId), + MP4GetTrackFixedSampleDuration(srcFile, + srcTrackId), + icPp, + MP4GetTrackEsdsObjectTypeId(srcFile, + srcTrackId) + ); + + } else if (MP4_IS_OD_TRACK_TYPE(trackType)) { + dstTrackId = MP4AddODTrack(dstFile); + + } else if (MP4_IS_SCENE_TRACK_TYPE(trackType)) { + dstTrackId = MP4AddSceneTrack(dstFile); + + } else if (MP4_IS_HINT_TRACK_TYPE(trackType)) { + if (dstHintTrackReferenceTrack == MP4_INVALID_TRACK_ID) { + dstTrackId = MP4_INVALID_TRACK_ID; + } else { + dstTrackId = MP4AddHintTrack(dstFile, + MP4GetHintTrackReferenceTrackId(srcFile, + srcTrackId)); + } + } else if (MP4_IS_SYSTEMS_TRACK_TYPE(trackType)) { + dstTrackId = MP4AddSystemsTrack(dstFile, trackType); + + } else { + dstTrackId = MP4AddTrack(dstFile, trackType); + } + + if (dstTrackId == MP4_INVALID_TRACK_ID) { + return dstTrackId; + } + + MP4SetTrackTimeScale(dstFile, + dstTrackId, + MP4GetTrackTimeScale(srcFile, srcTrackId)); + + if (MP4_IS_AUDIO_TRACK_TYPE(trackType) + || MP4_IS_VIDEO_TRACK_TYPE(trackType)) { + // copy track ES configuration + u_int8_t* pConfig = NULL; + u_int32_t configSize = 0; + if (MP4GetTrackESConfiguration(srcFile, srcTrackId, + &pConfig, &configSize)) { + + if (pConfig != NULL) { + MP4SetTrackESConfiguration(dstFile, dstTrackId, + pConfig, configSize); + } + } + if (pConfig != NULL) + free(pConfig); + } + + // Bill's change to MP4CloneTrack + if (MP4_IS_HINT_TRACK_TYPE(trackType)) { + // probably not exactly what is wanted + // but caller can adjust later to fit their desires + + char* payloadName = NULL; + char *encodingParms = NULL; + u_int8_t payloadNumber; + u_int16_t maxPayloadSize; + + if (MP4GetHintTrackRtpPayload( + srcFile, + srcTrackId, + &payloadName, + &payloadNumber, + &maxPayloadSize, + &encodingParms)) { + + (void)MP4SetHintTrackRtpPayload( + dstFile, + dstTrackId, + payloadName, + &payloadNumber, + maxPayloadSize, + encodingParms); + } +#if 0 + MP4SetHintTrackSdp( + dstFile, + dstTrackId, + MP4GetHintTrackSdp(srcFile, srcTrackId)); +#endif + } + + return dstTrackId; +} + +extern "C" MP4TrackId MP4CopyTrack(MP4FileHandle srcFile, + MP4TrackId srcTrackId, + MP4FileHandle dstFile, + bool applyEdits, + MP4TrackId dstHintTrackReferenceTrack) +{ + bool copySamples = true; // LATER allow false => reference samples + + MP4TrackId dstTrackId = + MP4CloneTrack(srcFile, srcTrackId, dstFile, dstHintTrackReferenceTrack); + + if (dstTrackId == MP4_INVALID_TRACK_ID) { + return dstTrackId; + } + + bool viaEdits = + applyEdits && MP4GetTrackNumberOfEdits(srcFile, srcTrackId); + + MP4SampleId sampleId = 0; + MP4SampleId numSamples = + MP4GetTrackNumberOfSamples(srcFile, srcTrackId); + + MP4Timestamp when = 0; + MP4Duration editsDuration = + MP4GetTrackEditTotalDuration(srcFile, srcTrackId); + + while (true) { + MP4Duration sampleDuration = MP4_INVALID_DURATION; + + if (viaEdits) { + sampleId = MP4GetSampleIdFromEditTime( + srcFile, + srcTrackId, + when, + NULL, + &sampleDuration); + + // in theory, this shouldn't happen + if (sampleId == MP4_INVALID_SAMPLE_ID) { + MP4DeleteTrack(dstFile, dstTrackId); + return MP4_INVALID_TRACK_ID; + } + + when += sampleDuration; + + if (when >= editsDuration) { + break; + } + } else { + sampleId++; + if (sampleId > numSamples) { + break; + } + } + + bool rc = false; + + if (copySamples) { + rc = MP4CopySample( + srcFile, + srcTrackId, + sampleId, + dstFile, + dstTrackId, + sampleDuration); + + } else { + rc = MP4ReferenceSample( + srcFile, + srcTrackId, + sampleId, + dstFile, + dstTrackId, + sampleDuration); + } + + if (!rc) { + MP4DeleteTrack(dstFile, dstTrackId); + return MP4_INVALID_TRACK_ID; + } + } + + return dstTrackId; +} + +// Given a source track in a source file, make an encrypted copy of +// the track in the destination file, including sample encryption +extern "C" MP4TrackId MP4EncAndCopyTrack(MP4FileHandle srcFile, + MP4TrackId srcTrackId, + mp4v2_ismacrypParams *icPp, + encryptFunc_t encfcnp, + u_int32_t encfcnparam1, + MP4FileHandle dstFile, + bool applyEdits, + MP4TrackId dstHintTrackReferenceTrack + ) +{ + bool copySamples = true; // LATER allow false => reference samples + + MP4TrackId dstTrackId = + MP4EncAndCloneTrack(srcFile, srcTrackId, + icPp, + dstFile, dstHintTrackReferenceTrack); + + if (dstTrackId == MP4_INVALID_TRACK_ID) { + return dstTrackId; + } + + bool viaEdits = + applyEdits && MP4GetTrackNumberOfEdits(srcFile, srcTrackId); + + MP4SampleId sampleId = 0; + MP4SampleId numSamples = + MP4GetTrackNumberOfSamples(srcFile, srcTrackId); + + MP4Timestamp when = 0; + MP4Duration editsDuration = + MP4GetTrackEditTotalDuration(srcFile, srcTrackId); + + while (true) { + MP4Duration sampleDuration = MP4_INVALID_DURATION; + + if (viaEdits) { + sampleId = MP4GetSampleIdFromEditTime(srcFile, + srcTrackId, + when, + NULL, + &sampleDuration); + + // in theory, this shouldn't happen + if (sampleId == MP4_INVALID_SAMPLE_ID) { + MP4DeleteTrack(dstFile, dstTrackId); + return MP4_INVALID_TRACK_ID; + } + + when += sampleDuration; + + if (when >= editsDuration) { + break; + } + } else { + sampleId++; + if (sampleId > numSamples) { + break; + } + } + + bool rc = false; + + if (copySamples) { + // encrypt and copy + rc = MP4EncAndCopySample(srcFile, + srcTrackId, + sampleId, + encfcnp, + encfcnparam1, + dstFile, + dstTrackId, + sampleDuration); + + } else { + // not sure what these are - encrypt? + rc = MP4ReferenceSample(srcFile, + srcTrackId, + sampleId, + dstFile, + dstTrackId, + sampleDuration); + } + + if (!rc) { + MP4DeleteTrack(dstFile, dstTrackId); + return MP4_INVALID_TRACK_ID; + } + } + + return dstTrackId; +} + +extern "C" void MP4DeleteTrack( + MP4FileHandle hFile, + MP4TrackId trackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->DeleteTrack(trackId); + return ; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return; +} + +extern "C" u_int32_t MP4GetNumberOfTracks( + MP4FileHandle hFile, + const char* type, + u_int8_t subType) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetNumberOfTracks(type, subType); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return 0; +} + +extern "C" MP4TrackId MP4FindTrackId( + MP4FileHandle hFile, + u_int16_t index, + const char* type, + u_int8_t subType) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->FindTrackId(index, type, subType); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_TRACK_ID; +} + +extern "C" u_int16_t MP4FindTrackIndex( + MP4FileHandle hFile, MP4TrackId trackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->FindTrackIndex(trackId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return (u_int16_t)-1; +} + +/* specific track properties */ + +extern "C" const char* MP4GetTrackType( + MP4FileHandle hFile, MP4TrackId trackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackType(trackId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return NULL; +} +extern "C" const char* MP4GetTrackMediaDataName( + MP4FileHandle hFile, MP4TrackId trackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackMediaDataName(trackId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return NULL; +} + +extern "C" bool MP4GetTrackMediaDataOriginalFormat( + MP4FileHandle hFile, MP4TrackId trackId, char *originalFormat, + u_int32_t buflen) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + + return ((MP4File*)hFile)->GetTrackMediaDataOriginalFormat(trackId, + originalFormat, buflen); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" MP4Duration MP4GetTrackDuration( + MP4FileHandle hFile, MP4TrackId trackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackDuration(trackId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_DURATION; +} + +extern "C" u_int32_t MP4GetTrackTimeScale( + MP4FileHandle hFile, MP4TrackId trackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackTimeScale(trackId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return 0; +} + +extern "C" void MP4SetTrackTimeScale( + MP4FileHandle hFile, MP4TrackId trackId, u_int32_t value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetTrackTimeScale(trackId, value); + return; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return; +} + +extern "C" u_int8_t MP4GetTrackAudioMpeg4Type( + MP4FileHandle hFile, MP4TrackId trackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackAudioMpeg4Type(trackId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_MPEG4_INVALID_AUDIO_TYPE; +} + + + +// Replacement to MP4GetTrackVideoType and MP4GetTrackAudioType +// Basically does the same thing but with a more self-explanatory name +extern "C" u_int8_t MP4GetTrackEsdsObjectTypeId( + MP4FileHandle hFile, MP4TrackId trackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + + return ((MP4File*)hFile)->GetTrackEsdsObjectTypeId(trackId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_AUDIO_TYPE; +} + +extern "C" MP4Duration MP4GetTrackFixedSampleDuration( + MP4FileHandle hFile, MP4TrackId trackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackFixedSampleDuration(trackId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_DURATION; +} + +extern "C" u_int32_t MP4GetTrackBitRate( + MP4FileHandle hFile, MP4TrackId trackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + uint32_t br = 0; + MP4File *pFile = (MP4File *)hFile; + try { + br = pFile->GetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.esds.decConfigDescr.avgBitrate"); + if (br > 16000) + return br; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + // if we're here, we can't get the bitrate from above - + // lets calculate it + try { + MP4Duration trackDur; + trackDur = MP4GetTrackDuration(hFile, trackId); + uint64_t msDuration = + pFile->ConvertFromTrackDuration(trackId, trackDur, + MP4_MSECS_TIME_SCALE); + if (msDuration == 0) return 0; + + MP4Track *pTrack = pFile->GetTrack(trackId); + double bytes = pTrack->GetTotalOfSampleSizes(); + //bytes *= TO_U64(8 * 1000); + //bytes /= msDuration; + //return (uint32_t)bytes; + + // divide first !!! + bytes /= (double)msDuration; + bytes *= TO_U64(8 * 1000); + return (uint32_t)bytes; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + + } + return 0; +} + +extern "C" bool MP4GetTrackESConfiguration( + MP4FileHandle hFile, MP4TrackId trackId, + u_int8_t** ppConfig, u_int32_t* pConfigSize) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->GetTrackESConfiguration( + trackId, ppConfig, pConfigSize); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + *ppConfig = NULL; + *pConfigSize = 0; + return false; +} +extern "C" bool MP4GetTrackVideoMetadata( + MP4FileHandle hFile, MP4TrackId trackId, + u_int8_t** ppConfig, u_int32_t* pConfigSize) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->GetTrackVideoMetadata( + trackId, ppConfig, pConfigSize); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + *ppConfig = NULL; + *pConfigSize = 0; + return false; +} + +extern "C" bool MP4SetTrackESConfiguration( + MP4FileHandle hFile, MP4TrackId trackId, + const u_int8_t* pConfig, u_int32_t configSize) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetTrackESConfiguration( + trackId, pConfig, configSize); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetTrackH264ProfileLevel (MP4FileHandle hFile, + MP4TrackId trackId, + uint8_t *pProfile, + uint8_t *pLevel) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + *pProfile = + ((MP4File *)hFile)->GetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*[0].avcC.AVCProfileIndication"); + *pLevel = + ((MP4File *)hFile)->GetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*[0].avcC.AVCLevelIndication"); + + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} +extern "C" void MP4GetTrackH264SeqPictHeaders (MP4FileHandle hFile, + MP4TrackId trackId, + uint8_t ***pSeqHeader, + uint32_t **pSeqHeaderSize, + uint8_t ***pPictHeader, + uint32_t **pPictHeaderSize) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->GetTrackH264SeqPictHeaders(trackId, + pSeqHeader, + pSeqHeaderSize, + pPictHeader, + pPictHeaderSize); + return; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return; +} +extern "C" bool MP4GetTrackH264LengthSize (MP4FileHandle hFile, + MP4TrackId trackId, + uint32_t *pLength) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + *pLength = 1 + + ((MP4File*) hFile)->GetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*[0].avcC.lengthSizeMinusOne"); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" MP4SampleId MP4GetTrackNumberOfSamples( + MP4FileHandle hFile, MP4TrackId trackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackNumberOfSamples(trackId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return 0; +} + +extern "C" MP4ChunkId MP4GetTrackNumberOfChunks( + MP4FileHandle hFile, MP4TrackId trackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackNumberOfChunks(trackId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return 0; +} + +extern "C" u_int16_t MP4GetTrackVideoWidth( + MP4FileHandle hFile, MP4TrackId trackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.width"); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return 0; +} + +extern "C" u_int16_t MP4GetTrackVideoHeight( + MP4FileHandle hFile, MP4TrackId trackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.height"); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return 0; +} + +extern "C" double MP4GetTrackVideoFrameRate( + MP4FileHandle hFile, MP4TrackId trackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackVideoFrameRate(trackId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return 0.0; +} + +extern "C" int MP4GetTrackAudioChannels (MP4FileHandle hFile, + MP4TrackId trackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackAudioChannels(trackId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return -1; +} + +// returns true if the track is a media track encrypted according to ismacryp +extern "C" bool MP4IsIsmaCrypMediaTrack( + MP4FileHandle hFile, MP4TrackId trackId) +{ + bool retval = false; + uint32_t verb = MP4GetVerbosity(hFile); + MP4SetVerbosity(hFile, verb & ~(MP4_DETAILS_ERROR)); + + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + retval = ((MP4File*)hFile)->IsIsmaCrypMediaTrack(trackId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + MP4SetVerbosity(hFile, verb); + return retval; +} + + +/* generic track properties */ + +extern "C" bool MP4HaveTrackAtom (MP4FileHandle hFile, + MP4TrackId trackId, + const char *atomName) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->FindTrackAtom(trackId, atomName) != NULL; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetTrackIntegerProperty ( + MP4FileHandle hFile, MP4TrackId trackId, + const char* propName, + u_int64_t *retvalue) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + *retvalue = ((MP4File*)hFile)->GetTrackIntegerProperty(trackId, + propName); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetTrackFloatProperty( + MP4FileHandle hFile, MP4TrackId trackId, + const char* propName, + float *retvalue) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + *retvalue = ((MP4File*)hFile)->GetTrackFloatProperty(trackId, propName); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetTrackStringProperty( + MP4FileHandle hFile, MP4TrackId trackId, + const char* propName, + const char **retvalue) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + *retvalue = ((MP4File*)hFile)->GetTrackStringProperty(trackId, propName); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetTrackBytesProperty( + MP4FileHandle hFile, MP4TrackId trackId, const char* propName, + u_int8_t** ppValue, u_int32_t* pValueSize) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->GetTrackBytesProperty( + trackId, propName, ppValue, pValueSize); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + *ppValue = NULL; + *pValueSize = 0; + return false; +} + +extern "C" bool MP4SetTrackIntegerProperty( + MP4FileHandle hFile, MP4TrackId trackId, + const char* propName, int64_t value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetTrackIntegerProperty(trackId, + propName, value); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4SetTrackFloatProperty( + MP4FileHandle hFile, MP4TrackId trackId, + const char* propName, float value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetTrackFloatProperty(trackId, propName, value); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4SetTrackStringProperty( + MP4FileHandle hFile, MP4TrackId trackId, + const char* propName, const char* value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetTrackStringProperty(trackId, propName, value); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4SetTrackBytesProperty( + MP4FileHandle hFile, MP4TrackId trackId, + const char* propName, const u_int8_t* pValue, u_int32_t valueSize) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetTrackBytesProperty( + trackId, propName, pValue, valueSize); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +/* sample operations */ + +extern "C" bool MP4ReadSample( + /* input parameters */ + MP4FileHandle hFile, + MP4TrackId trackId, + MP4SampleId sampleId, + /* output parameters */ + u_int8_t** ppBytes, + u_int32_t* pNumBytes, + MP4Timestamp* pStartTime, + MP4Duration* pDuration, + MP4Duration* pRenderingOffset, + bool* pIsSyncSample) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->ReadSample( + trackId, + sampleId, + ppBytes, + pNumBytes, + pStartTime, + pDuration, + pRenderingOffset, + pIsSyncSample); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + *pNumBytes = 0; + return false; +} + +extern "C" bool MP4ReadChunk( + /* input parameters */ + MP4FileHandle hFile, + MP4ChunkId trackId, + MP4SampleId sampleId, + /* output parameters */ + u_int8_t** ppBytes, + u_int32_t* pNumBytes, + MP4Timestamp* pStartTime, + MP4Duration* pDuration) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) + { + try + { + ((MP4File*)hFile)->ReadChunk( + trackId, + sampleId, + ppBytes, + pNumBytes, + pStartTime, + pDuration); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + *pNumBytes = 0; + return false; +} + +extern "C" bool MP4ReadSampleFromTime( + /* input parameters */ + MP4FileHandle hFile, + MP4TrackId trackId, + MP4Timestamp when, + /* output parameters */ + u_int8_t** ppBytes, + u_int32_t* pNumBytes, + MP4Timestamp* pStartTime, + MP4Duration* pDuration, + MP4Duration* pRenderingOffset, + bool* pIsSyncSample) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + MP4SampleId sampleId = + ((MP4File*)hFile)->GetSampleIdFromTime( + trackId, when, false); + + ((MP4File*)hFile)->ReadSample( + trackId, + sampleId, + ppBytes, + pNumBytes, + pStartTime, + pDuration, + pRenderingOffset, + pIsSyncSample); + + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + *pNumBytes = 0; + return false; +} + +extern "C" bool MP4WriteSample( + MP4FileHandle hFile, + MP4TrackId trackId, + const u_int8_t* pBytes, + u_int32_t numBytes, + MP4Duration duration, + MP4Duration renderingOffset, + bool isSyncSample) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->WriteSample( + trackId, + pBytes, + numBytes, + duration, + renderingOffset, + isSyncSample); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4CopySample( + MP4FileHandle srcFile, + MP4TrackId srcTrackId, + MP4SampleId srcSampleId, + MP4FileHandle dstFile, + MP4TrackId dstTrackId, + MP4Duration dstSampleDuration) +{ + bool rc; + u_int8_t* pBytes = NULL; + u_int32_t numBytes = 0; + MP4Duration sampleDuration; + MP4Duration renderingOffset; + bool isSyncSample; + + // Note: we leave it up to the caller to ensure that the + // source and destination tracks are compatible. + // i.e. copying audio samples into a video track + // is unlikely to do anything useful + + rc = MP4ReadSample( + srcFile, + srcTrackId, + srcSampleId, + &pBytes, + &numBytes, + NULL, + &sampleDuration, + &renderingOffset, + &isSyncSample); + + if (!rc) { + return false; + } + + if (dstFile == MP4_INVALID_FILE_HANDLE) { + dstFile = srcFile; + } + if (dstTrackId == MP4_INVALID_TRACK_ID) { + dstTrackId = srcTrackId; + } + if (dstSampleDuration != MP4_INVALID_DURATION) { + sampleDuration = dstSampleDuration; + } + + rc = MP4WriteSample( + dstFile, + dstTrackId, + pBytes, + numBytes, + sampleDuration, + renderingOffset, + isSyncSample); + + free(pBytes); + + return rc; +} + +extern "C" bool MP4EncAndCopySample( + MP4FileHandle srcFile, + MP4TrackId srcTrackId, + MP4SampleId srcSampleId, + encryptFunc_t encfcnp, + u_int32_t encfcnparam1, + MP4FileHandle dstFile, + MP4TrackId dstTrackId, + MP4Duration dstSampleDuration) +{ + bool rc; + u_int8_t* pBytes = NULL; + u_int32_t numBytes = 0; + u_int8_t* encSampleData = NULL; + u_int32_t encSampleLength = 0; + MP4Duration sampleDuration; + MP4Duration renderingOffset; + bool isSyncSample; + + // Note: we leave it up to the caller to ensure that the + // source and destination tracks are compatible. + // i.e. copying audio samples into a video track + // is unlikely to do anything useful + + rc = MP4ReadSample( + srcFile, + srcTrackId, + srcSampleId, + &pBytes, + &numBytes, + NULL, + &sampleDuration, + &renderingOffset, + &isSyncSample); + + if (!rc) { + return false; + } + + if (dstFile == MP4_INVALID_FILE_HANDLE) { + dstFile = srcFile; + } + if (dstTrackId == MP4_INVALID_TRACK_ID) { + dstTrackId = srcTrackId; + } + if (dstSampleDuration != MP4_INVALID_DURATION) { + sampleDuration = dstSampleDuration; + } + + //if (ismacrypEncryptSampleAddHeader(ismaCryptSId, numBytes, pBytes, + // &encSampleLength, &encSampleData) != 0) { + if (encfcnp(encfcnparam1, numBytes, pBytes, + &encSampleLength, &encSampleData) != 0) { + fprintf(stderr, + "Can't encrypt the sample and add its header %u\n", + srcSampleId); + } + + rc = MP4WriteSample( + dstFile, + dstTrackId, + encSampleData, + encSampleLength, + sampleDuration, + renderingOffset, + isSyncSample); + + free(pBytes); + + if (encSampleData != NULL) { + free(encSampleData); + } + + return rc; +} + +extern "C" bool MP4ReferenceSample( + MP4FileHandle srcFile, + MP4TrackId srcTrackId, + MP4SampleId srcSampleId, + MP4FileHandle dstFile, + MP4TrackId dstTrackId, + MP4Duration dstSampleDuration) +{ + // LATER Not yet implemented + return false; +} + +extern "C" u_int32_t MP4GetSampleSize( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4SampleId sampleId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetSampleSize( + trackId, sampleId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return 0; +} + +extern "C" u_int32_t MP4GetTrackMaxSampleSize( + MP4FileHandle hFile, + MP4TrackId trackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackMaxSampleSize(trackId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return 0; +} + +extern "C" MP4SampleId MP4GetSampleIdFromTime( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4Timestamp when, + bool wantSyncSample, + bool rewind) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetSampleIdFromTime( + trackId, when, wantSyncSample, rewind); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_SAMPLE_ID; +} + +extern "C" MP4ChunkId MP4GetChunkIdFromTime( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4Timestamp when) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetChunkIdFromTime( + trackId, when); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_SAMPLE_ID; +} + +extern "C" MP4Timestamp MP4GetSampleTime( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4SampleId sampleId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetSampleTime( + trackId, sampleId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_TIMESTAMP; +} + +extern "C" MP4Duration MP4GetSampleDuration( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4SampleId sampleId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetSampleDuration( + trackId, sampleId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_DURATION; +} + +extern "C" MP4Duration MP4GetSampleRenderingOffset( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4SampleId sampleId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetSampleRenderingOffset( + trackId, sampleId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_DURATION; +} + +extern "C" bool MP4SetSampleRenderingOffset( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4SampleId sampleId, + MP4Duration renderingOffset) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetSampleRenderingOffset( + trackId, sampleId, renderingOffset); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" int8_t MP4GetSampleSync( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4SampleId sampleId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetSampleSync( + trackId, sampleId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return -1; +} + + +extern "C" u_int64_t MP4ConvertFromMovieDuration( + MP4FileHandle hFile, + MP4Duration duration, + u_int32_t timeScale) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->ConvertFromMovieDuration( + duration, timeScale); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return (u_int64_t)MP4_INVALID_DURATION; +} + +extern "C" u_int64_t MP4ConvertFromTrackTimestamp( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4Timestamp timeStamp, + u_int32_t timeScale) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->ConvertFromTrackTimestamp( + trackId, timeStamp, timeScale); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return (u_int64_t)MP4_INVALID_TIMESTAMP; +} + +extern "C" MP4Timestamp MP4ConvertToTrackTimestamp( + MP4FileHandle hFile, + MP4TrackId trackId, + u_int64_t timeStamp, + u_int32_t timeScale) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->ConvertToTrackTimestamp( + trackId, timeStamp, timeScale); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_TIMESTAMP; +} + +extern "C" u_int64_t MP4ConvertFromTrackDuration( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4Duration duration, + u_int32_t timeScale) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->ConvertFromTrackDuration( + trackId, duration, timeScale); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return (u_int64_t)MP4_INVALID_DURATION; +} + +extern "C" MP4Duration MP4ConvertToTrackDuration( + MP4FileHandle hFile, + MP4TrackId trackId, + u_int64_t duration, + u_int32_t timeScale) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->ConvertToTrackDuration( + trackId, duration, timeScale); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_DURATION; +} + +extern "C" bool MP4GetHintTrackRtpPayload( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + char** ppPayloadName, + u_int8_t* pPayloadNumber, + u_int16_t* pMaxPayloadSize, + char **ppEncodingParams) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->GetHintTrackRtpPayload( + hintTrackId, ppPayloadName, pPayloadNumber, pMaxPayloadSize, + ppEncodingParams); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4SetHintTrackRtpPayload( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + const char* pPayloadName, + u_int8_t* pPayloadNumber, + u_int16_t maxPayloadSize, + const char *encode_params, + bool include_rtp_map, + bool include_mpeg4_esid) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetHintTrackRtpPayload( + hintTrackId, pPayloadName, pPayloadNumber, maxPayloadSize, encode_params, + include_rtp_map, include_mpeg4_esid); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" const char* MP4GetSessionSdp( + MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetSessionSdp(); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return NULL; +} + +extern "C" bool MP4SetSessionSdp( + MP4FileHandle hFile, + const char* sdpString) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetSessionSdp(sdpString); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4AppendSessionSdp( + MP4FileHandle hFile, + const char* sdpString) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->AppendSessionSdp(sdpString); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" const char* MP4GetHintTrackSdp( + MP4FileHandle hFile, + MP4TrackId hintTrackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetHintTrackSdp(hintTrackId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return NULL; +} + +extern "C" bool MP4SetHintTrackSdp( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + const char* sdpString) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetHintTrackSdp(hintTrackId, sdpString); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4AppendHintTrackSdp( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + const char* sdpString) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->AppendHintTrackSdp(hintTrackId, sdpString); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" MP4TrackId MP4GetHintTrackReferenceTrackId( + MP4FileHandle hFile, + MP4TrackId hintTrackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)-> + GetHintTrackReferenceTrackId(hintTrackId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_TRACK_ID; +} + +extern "C" bool MP4ReadRtpHint( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + MP4SampleId hintSampleId, + u_int16_t* pNumPackets) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->ReadRtpHint( + hintTrackId, hintSampleId, pNumPackets); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" u_int16_t MP4GetRtpHintNumberOfPackets( + MP4FileHandle hFile, + MP4TrackId hintTrackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetRtpHintNumberOfPackets(hintTrackId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return 0; +} + +extern "C" int8_t MP4GetRtpPacketBFrame( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + u_int16_t packetIndex) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)-> + GetRtpPacketBFrame(hintTrackId, packetIndex); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return -1; +} + +extern "C" int32_t MP4GetRtpPacketTransmitOffset( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + u_int16_t packetIndex) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)-> + GetRtpPacketTransmitOffset(hintTrackId, packetIndex); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return 0; +} + +extern "C" bool MP4ReadRtpPacket( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + u_int16_t packetIndex, + u_int8_t** ppBytes, + u_int32_t* pNumBytes, + u_int32_t ssrc, + bool includeHeader, + bool includePayload) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->ReadRtpPacket( + hintTrackId, packetIndex, + ppBytes, pNumBytes, + ssrc, includeHeader, includePayload); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" MP4Timestamp MP4GetRtpTimestampStart( + MP4FileHandle hFile, + MP4TrackId hintTrackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetRtpTimestampStart(hintTrackId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_TIMESTAMP; +} + +extern "C" bool MP4SetRtpTimestampStart( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + MP4Timestamp rtpStart) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetRtpTimestampStart( + hintTrackId, rtpStart); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4AddRtpHint( + MP4FileHandle hFile, + MP4TrackId hintTrackId) +{ + return MP4AddRtpVideoHint(hFile, hintTrackId, false, 0); +} + +extern "C" bool MP4AddRtpVideoHint( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + bool isBframe, + u_int32_t timestampOffset) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->AddRtpHint(hintTrackId, + isBframe, timestampOffset); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4AddRtpPacket( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + bool setMbit, + int32_t transmitOffset) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->AddRtpPacket( + hintTrackId, setMbit, transmitOffset); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4AddRtpImmediateData( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + const u_int8_t* pBytes, + u_int32_t numBytes) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->AddRtpImmediateData(hintTrackId, + pBytes, numBytes); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4AddRtpSampleData( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + MP4SampleId sampleId, + u_int32_t dataOffset, + u_int32_t dataLength) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->AddRtpSampleData( + hintTrackId, sampleId, dataOffset, dataLength); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4AddRtpESConfigurationPacket( + MP4FileHandle hFile, + MP4TrackId hintTrackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->AddRtpESConfigurationPacket(hintTrackId); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4WriteRtpHint( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + MP4Duration duration, + bool isSyncSample) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->WriteRtpHint( + hintTrackId, duration, isSyncSample); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} +/* 3GPP specific operations */ + +extern "C" bool MP4Make3GPCompliant( + const MP4_FILENAME_CHAR* fileName, + u_int32_t verbosity, + char* majorBrand, + u_int32_t minorVersion, + char** supportedBrands, + u_int32_t supportedBrandsCount, + bool deleteIodsAtom) +{ + MP4File* pFile; + pFile = NULL; + + try { + pFile = new MP4File(verbosity); + pFile->Modify(fileName); + pFile->Make3GPCompliant(fileName, majorBrand, minorVersion, supportedBrands, supportedBrandsCount, deleteIodsAtom); + pFile->Close(); + delete pFile; + return true; + } + catch (MP4Error* e) { + VERBOSE_ERROR(verbosity, e->Print()); + delete e; + } + delete pFile; + return false; +} + +/* ISMA specific operations */ + +extern "C" bool MP4MakeIsmaCompliant( + const MP4_FILENAME_CHAR* fileName, + u_int32_t verbosity, + bool addIsmaComplianceSdp) +{ + MP4File* pFile; + pFile = NULL; + + try { + pFile = new MP4File(verbosity); + pFile->Modify(fileName); + pFile->MakeIsmaCompliant(addIsmaComplianceSdp); + pFile->Close(); + delete pFile; + return true; + } + catch (MP4Error* e) { + VERBOSE_ERROR(verbosity, e->Print()); + delete e; + } + delete pFile; + return false; +} + +extern "C" char* MP4MakeIsmaSdpIod( + u_int8_t videoProfile, + u_int32_t videoBitrate, + u_int8_t* videoConfig, + u_int32_t videoConfigLength, + u_int8_t audioProfile, + u_int32_t audioBitrate, + u_int8_t* audioConfig, + u_int32_t audioConfigLength, + u_int32_t verbosity) +{ + MP4File* pFile = NULL; + + try { + pFile = new MP4File(verbosity); + + u_int8_t* pBytes = NULL; + u_int64_t numBytes = 0; + + pFile->CreateIsmaIodFromParams( + videoProfile, + videoBitrate, + videoConfig, + videoConfigLength, + audioProfile, + audioBitrate, + audioConfig, + audioConfigLength, + &pBytes, + &numBytes); + + char* iodBase64 = + MP4ToBase64(pBytes, numBytes); + MP4Free(pBytes); + + char* sdpIod = + (char*)MP4Malloc(strlen(iodBase64) + 64); + snprintf(sdpIod, strlen(iodBase64) + 64, + "a=mpeg4-iod: \042data:application/mpeg4-iod;base64,%s\042", + iodBase64); + MP4Free(iodBase64); + + delete pFile; + + return sdpIod; + } + catch (MP4Error* e) { + VERBOSE_ERROR(verbosity, e->Print()); + delete e; + } + return NULL; +} + +/* Edit list */ + +extern "C" MP4EditId MP4AddTrackEdit( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId, + MP4Timestamp startTime, + MP4Duration duration, + bool dwell) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + MP4EditId newEditId = + ((MP4File*)hFile)->AddTrackEdit(trackId, editId); + + if (newEditId != MP4_INVALID_EDIT_ID) { + ((MP4File*)hFile)->SetTrackEditMediaStart( + trackId, newEditId, startTime); + ((MP4File*)hFile)->SetTrackEditDuration( + trackId, newEditId, duration); + ((MP4File*)hFile)->SetTrackEditDwell( + trackId, newEditId, dwell); + } + + return newEditId; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_EDIT_ID; +} + +extern "C" bool MP4DeleteTrackEdit( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->DeleteTrackEdit(trackId, editId); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" u_int32_t MP4GetTrackNumberOfEdits( + MP4FileHandle hFile, + MP4TrackId trackId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackNumberOfEdits(trackId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return 0; +} + +extern "C" MP4Timestamp MP4GetTrackEditMediaStart( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackEditMediaStart( + trackId, editId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_TIMESTAMP; +} + +extern "C" MP4Duration MP4GetTrackEditTotalDuration( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackEditTotalDuration( + trackId, editId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_DURATION; +} + +extern "C" bool MP4SetTrackEditMediaStart( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId, + MP4Timestamp startTime) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetTrackEditMediaStart( + trackId, editId, startTime); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" MP4Duration MP4GetTrackEditDuration( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackEditDuration(trackId, editId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_DURATION; +} + +extern "C" bool MP4SetTrackEditDuration( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId, + MP4Duration duration) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetTrackEditDuration(trackId, editId, duration); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" int8_t MP4GetTrackEditDwell( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackEditDwell(trackId, editId); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return -1; +} + +extern "C" bool MP4SetTrackEditDwell( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId, + bool dwell) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetTrackEditDwell(trackId, editId, dwell); + return true; + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4ReadSampleFromEditTime( + /* input parameters */ + MP4FileHandle hFile, + MP4TrackId trackId, + MP4Timestamp when, + /* output parameters */ + u_int8_t** ppBytes, + u_int32_t* pNumBytes, + MP4Timestamp* pStartTime, + MP4Duration* pDuration, + MP4Duration* pRenderingOffset, + bool* pIsSyncSample) +{ + MP4SampleId sampleId = + MP4GetSampleIdFromEditTime( + hFile, + trackId, + when, + pStartTime, + pDuration); + + return MP4ReadSample( + hFile, + trackId, + sampleId, + ppBytes, + pNumBytes, + NULL, + NULL, + pRenderingOffset, + pIsSyncSample); +} + +extern "C" MP4SampleId MP4GetSampleIdFromEditTime( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4Timestamp when, + MP4Timestamp* pStartTime, + MP4Duration* pDuration) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetSampleIdFromEditTime( + trackId, when, pStartTime, pDuration); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return MP4_INVALID_SAMPLE_ID; +} + +/* Utlities */ + +extern "C" char* MP4BinaryToBase16( + const u_int8_t* pData, + u_int32_t dataSize) +{ + if (pData || dataSize == 0) { + try { + return MP4ToBase16(pData, dataSize); + } + catch (MP4Error* e) { + delete e; + } + } + return NULL; +} + +extern "C" char* MP4BinaryToBase64( + const u_int8_t* pData, + u_int32_t dataSize) +{ + if (pData || dataSize == 0) { + try { + return MP4ToBase64(pData, dataSize); + } + catch (MP4Error* e) { + delete e; + } + } + return NULL; +} + +/* iTunes meta data handling */ +extern "C" bool MP4GetMetadataByIndex(MP4FileHandle hFile, u_int32_t index, + char** ppName, + u_int8_t** ppValue, u_int32_t* pValueSize) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetMetadataByIndex( + index, ppName, ppValue, pValueSize); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4MetadataDelete(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->MetadataDelete(); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4SetMetadataName(MP4FileHandle hFile, + const char* value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->SetMetadataString("\251nam", value); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetMetadataName(MP4FileHandle hFile, + char** value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetMetadataString("\251nam", value); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4DeleteMetadataName(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->DeleteMetadataAtom("\251nam"); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4SetMetadataWriter(MP4FileHandle hFile, + const char* value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->SetMetadataString("\251wrt", value); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetMetadataWriter(MP4FileHandle hFile, + char** value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetMetadataString("\251wrt", value); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4DeleteMetadataWriter(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->DeleteMetadataAtom("\251wrt"); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4SetMetadataAlbum(MP4FileHandle hFile, + const char* value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->SetMetadataString("\251alb", value); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetMetadataAlbum(MP4FileHandle hFile, + char** value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetMetadataString("\251alb", value); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4DeleteMetadataAlbum(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->DeleteMetadataAtom("\251alb"); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4SetMetadataArtist(MP4FileHandle hFile, + const char* value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->SetMetadataString("\251ART", value); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetMetadataArtist(MP4FileHandle hFile, + char** value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetMetadataString("\251ART", value); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4DeleteMetadataArtist(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->DeleteMetadataAtom("\251ART"); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4SetMetadataRating(MP4FileHandle hFile, + const char* value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->SetMetadataString("rate", value); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetMetadataRating(MP4FileHandle hFile, + char** value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetMetadataString("rate", value); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4DeleteMetadataRating(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->DeleteMetadataAtom("rate"); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4SetMetadataTool(MP4FileHandle hFile, + const char* value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->SetMetadataString("\251too", value); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetMetadataTool(MP4FileHandle hFile, + char** value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetMetadataString("\251too", value); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4DeleteMetadataTool(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->DeleteMetadataAtom("\251too"); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4SetMetadataComment(MP4FileHandle hFile, + const char* value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->SetMetadataString("\251cmt", value); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetMetadataComment(MP4FileHandle hFile, + char** value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetMetadataString("\251cmt", value); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4DeleteMetadataComment(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->DeleteMetadataAtom("\251cmt"); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4SetMetadataYear(MP4FileHandle hFile, + const char* value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->SetMetadataString("\251day", value); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetMetadataYear(MP4FileHandle hFile, + char** value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetMetadataString("\251day", value); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4DeleteMetadataYear(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->DeleteMetadataAtom("\251day"); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4SetMetadataTrack(MP4FileHandle hFile, + u_int16_t track, u_int16_t totalTracks) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->SetMetadataTrack(track, totalTracks); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetMetadataTrack(MP4FileHandle hFile, + u_int16_t* track, u_int16_t* totalTracks) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetMetadataTrack(track, totalTracks); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4DeleteMetadataTrack(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->DeleteMetadataAtom("trkn"); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4SetMetadataDisk(MP4FileHandle hFile, + u_int16_t disk, u_int16_t totalDisks) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->SetMetadataDisk(disk, totalDisks); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetMetadataDisk(MP4FileHandle hFile, + u_int16_t* disk, u_int16_t* totalDisks) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetMetadataDisk(disk, totalDisks); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4DeleteMetadataDisk(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->DeleteMetadataAtom("disk"); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4SetMetadataGenre(MP4FileHandle hFile, const char *genre) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->SetMetadataGenre(genre); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetMetadataGenre(MP4FileHandle hFile, char **genre) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetMetadataGenre(genre); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4DeleteMetadataGenre(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->DeleteMetadataGenre(); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4SetMetadataGrouping(MP4FileHandle hFile, const char *grouping) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->SetMetadataString("\251grp", grouping); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetMetadataGrouping(MP4FileHandle hFile, char **grouping) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetMetadataString("\251grp", grouping); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4DeleteMetadataGrouping(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->DeleteMetadataAtom("\251grp"); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4SetMetadataTempo(MP4FileHandle hFile, u_int16_t tempo) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->SetMetadataTempo(tempo); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetMetadataTempo(MP4FileHandle hFile, u_int16_t* tempo) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetMetadataTempo(tempo); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4DeleteMetadataTempo(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->DeleteMetadataAtom("tmpo"); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4SetMetadataCompilation(MP4FileHandle hFile, u_int8_t cpl) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->SetMetadataUint8("cpil", cpl & 0x1); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetMetadataCompilation(MP4FileHandle hFile, u_int8_t* cpl) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetMetadataUint8("cpil", cpl); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4DeleteMetadataCompilation(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->DeleteMetadataAtom("cpil"); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4SetMetadataPartOfGaplessAlbum (MP4FileHandle hFile, + u_int8_t pgap) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->SetMetadataUint8("pgap", pgap & 0x1); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetMetadataPartOfGaplessAlbum (MP4FileHandle hFile, + u_int8_t* pgap) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetMetadataUint8("pgap", pgap); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4DeleteMetadataPartOfGaplessAlbum (MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->DeleteMetadataAtom("pgap"); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4SetMetadataCoverArt(MP4FileHandle hFile, u_int8_t *coverArt, u_int32_t size, int flags) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->SetMetadataCoverArt(coverArt, size, flags); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetMetadataCoverArt(MP4FileHandle hFile, u_int8_t **coverArt, u_int32_t* size, int *flags, uint32_t index) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetMetadataCoverArt(coverArt, size, index); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" u_int32_t MP4GetMetadataCoverArtCount(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetMetadataCoverArtCount(); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4DeleteMetadataCoverArt(MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->DeleteMetadataAtom("covr"); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} +extern "C" bool MP4SetMetadataAlbumArtist (MP4FileHandle hFile, + const char* value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->SetMetadataString("aART", value); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetMetadataAlbumArtist (MP4FileHandle hFile, + char** value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetMetadataString("aART", value); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4DeleteMetadataAlbumArtist (MP4FileHandle hFile) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->DeleteMetadataAtom("aART"); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4SetMetadataFreeForm(MP4FileHandle hFile, + const char *name, + const u_int8_t* pValue, + u_int32_t valueSize, + const char *owner) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->SetMetadataFreeForm(name, pValue, valueSize, owner); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4GetMetadataFreeForm(MP4FileHandle hFile, const char *name, + u_int8_t** pValue, u_int32_t* valueSize, const char *owner) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetMetadataFreeForm(name, pValue, valueSize, owner); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4DeleteMetadataFreeForm(MP4FileHandle hFile, const char *name, const char *owner) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->DeleteMetadataFreeForm(name, owner); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4Get3GPMetadata(MP4FileHandle hFile, const char *name, uint16_t **value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->Get3GPMetadataString(name, value); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4Set3GPMetadata(MP4FileHandle hFile, const char *name, const uint16_t* value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->Set3GPMetadataString(name, value); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" bool MP4Get3GPMetadataInteger(MP4FileHandle hFile, const char *name, uint64_t *value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->Get3GPMetadataInteger(name, value); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +bool MP4Set3GPMetadataInteger(MP4FileHandle hFile, const char *name, uint64_t value) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->Set3GPMetadataInteger(name, value); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} +extern "C" bool MP4Delete3GPMetadata(MP4FileHandle hFile, const char *name) +{ + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->Delete3GPMetadataAtom(name); + } + catch (MP4Error* e) { + PRINT_ERROR(e); + delete e; + } + } + return false; +} + +extern "C" void MP4Free (void *p) +{ + if (p != NULL) + free(p); +} diff --git a/Src/external_dependencies/libmp4v2/mp4.h b/Src/external_dependencies/libmp4v2/mp4.h new file mode 100644 index 00000000..de474f8f --- /dev/null +++ b/Src/external_dependencies/libmp4v2/mp4.h @@ -0,0 +1,1373 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001 - 2005. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + * Alix Marchandise-Franquet alix@cisco.com + * Ximpo Group Ltd. mp4v2@ximpo.com + * Bill May wmay@cisco.com + */ + +#ifndef __MP4_INCLUDED__ +#define __MP4_INCLUDED__ + +/* include system and project specific headers */ +#include "include/mpeg4ip.h" +#include <math.h> /* to define float HUGE_VAL and/or NAN */ +#ifndef NAN +#define NAN HUGE_VAL +#endif + +#ifdef __cplusplus +/* exploit C++ ability of default values for function parameters */ +#define DEFAULT(x) =x +#else +#define DEFAULT(x) +#endif + +/* MP4 API types */ +typedef void* MP4FileHandle; +typedef u_int32_t MP4TrackId; +typedef u_int32_t MP4SampleId; +typedef u_int32_t MP4ChunkId; +typedef u_int64_t MP4Timestamp; +typedef u_int64_t MP4Duration; +typedef u_int32_t MP4EditId; + +typedef u_int64_t (*VIRTUALIO_GETFILELENGTH)(void *user); // return file length in bytes +typedef int (*VIRTUALIO_SETPOSITION)(void *user, u_int64_t position); // return 0 on success +typedef int (*VIRTUALIO_GETPOSITION)(void *user, u_int64_t *position); // fill position, return 0 on success +typedef size_t (*VIRTUALIO_READ)(void *user, void *buffer, size_t size); // return number of bytes actually read +typedef size_t (*VIRTUALIO_WRITE)(void *user, void *buffer, size_t size); // return number of bytes actually written +typedef int (*VIRTUALIO_ENDOFFILE)(void *user); // return 1 if file hit EOF +typedef int (*VIRTUALIO_CLOSE)(void *user); // return 0 on success + +typedef struct Virtual_IO +{ + VIRTUALIO_GETFILELENGTH GetFileLength; + VIRTUALIO_SETPOSITION SetPosition; + VIRTUALIO_GETPOSITION GetPosition; + VIRTUALIO_READ Read; + VIRTUALIO_WRITE Write; + VIRTUALIO_ENDOFFILE EndOfFile; + VIRTUALIO_CLOSE Close; +} Virtual_IO_t; + + +/* Invalid values for API types */ +#define MP4_INVALID_FILE_HANDLE ((MP4FileHandle)NULL) +#define MP4_INVALID_TRACK_ID ((MP4TrackId)0) +#define MP4_INVALID_SAMPLE_ID ((MP4SampleId)0) +#define MP4_INVALID_TIMESTAMP ((MP4Timestamp)-1) +#define MP4_INVALID_DURATION ((MP4Duration)-1) +#define MP4_INVALID_EDIT_ID ((MP4EditId)0) + +/* Macros to test for API type validity */ +#define MP4_IS_VALID_FILE_HANDLE(x) ((x) != MP4_INVALID_FILE_HANDLE) +#define MP4_IS_VALID_TRACK_ID(x) ((x) != MP4_INVALID_TRACK_ID) +#define MP4_IS_VALID_SAMPLE_ID(x) ((x) != MP4_INVALID_SAMPLE_ID) +#define MP4_IS_VALID_TIMESTAMP(x) ((x) != MP4_INVALID_TIMESTAMP) +#define MP4_IS_VALID_DURATION(x) ((x) != MP4_INVALID_DURATION) +#define MP4_IS_VALID_EDIT_ID(x) ((x) != MP4_INVALID_EDIT_ID) + +/* MP4 verbosity levels - e.g. MP4SetVerbosity() */ +#define MP4_DETAILS_ALL 0xFFFFFFFF +#define MP4_DETAILS_ERROR 0x00000001 +#define MP4_DETAILS_WARNING 0x00000002 +#define MP4_DETAILS_READ 0x00000004 +#define MP4_DETAILS_WRITE 0x00000008 +#define MP4_DETAILS_FIND 0x00000010 +#define MP4_DETAILS_TABLE 0x00000020 +#define MP4_DETAILS_SAMPLE 0x00000040 +#define MP4_DETAILS_HINT 0x00000080 +#define MP4_DETAILS_ISMA 0x00000100 +#define MP4_DETAILS_EDIT 0x00000200 + +#define MP4_DETAILS_READ_ALL \ + (MP4_DETAILS_READ | MP4_DETAILS_TABLE | MP4_DETAILS_SAMPLE) +#define MP4_DETAILS_WRITE_ALL \ + (MP4_DETAILS_WRITE | MP4_DETAILS_TABLE | MP4_DETAILS_SAMPLE) + +/* + * MP4 Known track type names - e.g. MP4GetNumberOfTracks(type) + * + * Note this first group of track types should be created + * via the MP4Add<Type>Track() functions, and not MP4AddTrack(type) + */ +#define MP4_OD_TRACK_TYPE "odsm" +#define MP4_SCENE_TRACK_TYPE "sdsm" +#define MP4_AUDIO_TRACK_TYPE "soun" +#define MP4_VIDEO_TRACK_TYPE "vide" +#define MP4_HINT_TRACK_TYPE "hint" +#define MP4_CNTL_TRACK_TYPE "cntl" +#define MP4_TEXT_TRACK_TYPE "text" +/* + * This second set of track types should be created + * via MP4AddSystemsTrack(type) + */ +#define MP4_CLOCK_TRACK_TYPE "crsm" +#define MP4_MPEG7_TRACK_TYPE "m7sm" +#define MP4_OCI_TRACK_TYPE "ocsm" +#define MP4_IPMP_TRACK_TYPE "ipsm" +#define MP4_MPEGJ_TRACK_TYPE "mjsm" + +#define MP4_IS_VIDEO_TRACK_TYPE(type) \ + (!strcasecmp(type, MP4_VIDEO_TRACK_TYPE)) + +#define MP4_IS_AUDIO_TRACK_TYPE(type) \ + (!strcasecmp(type, MP4_AUDIO_TRACK_TYPE)) + +#define MP4_IS_CNTL_TRACK_TYPE(type) \ + (!strcasecmp(type, MP4_CNTL_TRACK_TYPE)) + +#define MP4_IS_OD_TRACK_TYPE(type) \ + (!strcasecmp(type, MP4_OD_TRACK_TYPE)) + +#define MP4_IS_SCENE_TRACK_TYPE(type) \ + (!strcasecmp(type, MP4_SCENE_TRACK_TYPE)) + +#define MP4_IS_HINT_TRACK_TYPE(type) \ + (!strcasecmp(type, MP4_HINT_TRACK_TYPE)) + +#define MP4_IS_SYSTEMS_TRACK_TYPE(type) \ + (!strcasecmp(type, MP4_CLOCK_TRACK_TYPE) \ + || !strcasecmp(type, MP4_MPEG7_TRACK_TYPE) \ + || !strcasecmp(type, MP4_OCI_TRACK_TYPE) \ + || !strcasecmp(type, MP4_IPMP_TRACK_TYPE) \ + || !strcasecmp(type, MP4_MPEGJ_TRACK_TYPE)) + +/* MP4 Audio track types - see MP4AddAudioTrack()*/ +#define MP4_INVALID_AUDIO_TYPE 0x00 +#define MP4_MPEG1_AUDIO_TYPE 0x6B +#define MP4_MPEG2_AUDIO_TYPE 0x69 +#define MP4_MP3_AUDIO_TYPE MP4_MPEG2_AUDIO_TYPE +#define MP4_MPEG2_AAC_MAIN_AUDIO_TYPE 0x66 +#define MP4_MPEG2_AAC_LC_AUDIO_TYPE 0x67 +#define MP4_MPEG2_AAC_SSR_AUDIO_TYPE 0x68 +#define MP4_MPEG2_AAC_AUDIO_TYPE MP4_MPEG2_AAC_MAIN_AUDIO_TYPE +#define MP4_MPEG4_AUDIO_TYPE 0x40 +#define MP4_PRIVATE_AUDIO_TYPE 0xC0 +#define MP4_PCM16_LITTLE_ENDIAN_AUDIO_TYPE 0xE0 /* a private definition */ +#define MP4_VORBIS_AUDIO_TYPE 0xE1 /* a private definition */ +#define MP4_AC3_AUDIO_TYPE 0xE2 /* a private definition */ +#define MP4_ALAW_AUDIO_TYPE 0xE3 /* a private definition */ +#define MP4_ULAW_AUDIO_TYPE 0xE4 /* a private definition */ +#define MP4_G723_AUDIO_TYPE 0xE5 /* a private definition */ +#define MP4_PCM16_BIG_ENDIAN_AUDIO_TYPE 0xE6 /* a private definition */ + +/* MP4 MPEG-4 Audio types from 14496-3 Table 1.5.1 */ +#define MP4_MPEG4_INVALID_AUDIO_TYPE 0 +#define MP4_MPEG4_AAC_MAIN_AUDIO_TYPE 1 +#define MP4_MPEG4_AAC_LC_AUDIO_TYPE 2 +#define MP4_MPEG4_AAC_SSR_AUDIO_TYPE 3 +#define MP4_MPEG4_AAC_LTP_AUDIO_TYPE 4 +#define MP4_MPEG4_AAC_HE_AUDIO_TYPE 5 +#define MP4_MPEG4_AAC_SCALABLE_AUDIO_TYPE 6 +#define MP4_MPEG4_CELP_AUDIO_TYPE 8 +#define MP4_MPEG4_HVXC_AUDIO_TYPE 9 +#define MP4_MPEG4_TTSI_AUDIO_TYPE 12 +#define MP4_MPEG4_MAIN_SYNTHETIC_AUDIO_TYPE 13 +#define MP4_MPEG4_WAVETABLE_AUDIO_TYPE 14 +#define MP4_MPEG4_MIDI_AUDIO_TYPE 15 +#define MP4_MPEG4_ALGORITHMIC_FX_AUDIO_TYPE 16 +#define MP4_MPEG4_PARAMETRIC_STEREO 29 +#define MP4_MPEG4_ALS_AUDIO_TYPE 31 +#define MP4_MPEG4_LAYER1_AUDIO_TYPE 32 +#define MP4_MPEG4_LAYER2_AUDIO_TYPE 33 +#define MP4_MPEG4_LAYER3_AUDIO_TYPE 34 +#define MP4_MPEG4_SLS_AUDIO_TYPE 35 + +/* MP4 Audio type utilities following common usage */ +#define MP4_IS_MP3_AUDIO_TYPE(type) \ + ((type) == MP4_MPEG1_AUDIO_TYPE || (type) == MP4_MPEG2_AUDIO_TYPE) + +#define MP4_IS_MPEG2_AAC_AUDIO_TYPE(type) \ + (((type) >= MP4_MPEG2_AAC_MAIN_AUDIO_TYPE \ + && (type) <= MP4_MPEG2_AAC_SSR_AUDIO_TYPE)) + +#define MP4_IS_MPEG4_AAC_AUDIO_TYPE(mpeg4Type) \ + (((mpeg4Type) >= MP4_MPEG4_AAC_MAIN_AUDIO_TYPE \ + && (mpeg4Type) <= MP4_MPEG4_AAC_HE_AUDIO_TYPE) \ + || (mpeg4Type) == MP4_MPEG4_AAC_SCALABLE_AUDIO_TYPE \ + || (mpeg4Type) == 17) + +#define MP4_IS_AAC_AUDIO_TYPE(type) \ + (MP4_IS_MPEG2_AAC_AUDIO_TYPE(type) \ + || (type) == MP4_MPEG4_AUDIO_TYPE) + +/* MP4 Video track types - see MP4AddVideoTrack() */ +#define MP4_INVALID_VIDEO_TYPE 0x00 +#define MP4_MPEG1_VIDEO_TYPE 0x6A +#define MP4_MPEG2_SIMPLE_VIDEO_TYPE 0x60 +#define MP4_MPEG2_MAIN_VIDEO_TYPE 0x61 +#define MP4_MPEG2_SNR_VIDEO_TYPE 0x62 +#define MP4_MPEG2_SPATIAL_VIDEO_TYPE 0x63 +#define MP4_MPEG2_HIGH_VIDEO_TYPE 0x64 +#define MP4_MPEG2_442_VIDEO_TYPE 0x65 +#define MP4_MPEG2_VIDEO_TYPE MP4_MPEG2_MAIN_VIDEO_TYPE +#define MP4_MPEG4_VIDEO_TYPE 0x20 +#define MP4_JPEG_VIDEO_TYPE 0x6C +#define MP4_PRIVATE_VIDEO_TYPE 0xD0 +#define MP4_YUV12_VIDEO_TYPE 0xF0 /* a private definition */ +#define MP4_H263_VIDEO_TYPE 0xF2 /* a private definition */ +#define MP4_H261_VIDEO_TYPE 0xF3 /* a private definition */ + +/* MP4 Video type utilities */ +#define MP4_IS_MPEG1_VIDEO_TYPE(type) \ + ((type) == MP4_MPEG1_VIDEO_TYPE) + +#define MP4_IS_MPEG2_VIDEO_TYPE(type) \ + (((type) >= MP4_MPEG2_SIMPLE_VIDEO_TYPE \ + && (type) <= MP4_MPEG2_442_VIDEO_TYPE) \ + || MP4_IS_MPEG1_VIDEO_TYPE(type)) + +#define MP4_IS_MPEG4_VIDEO_TYPE(type) \ + ((type) == MP4_MPEG4_VIDEO_TYPE) + +/* Mpeg4 Visual Profile Defines - ISO/IEC 14496-2:2001/Amd.2:2002(E) */ +#define MPEG4_SP_L1 (0x1) +#define MPEG4_SP_L2 (0x2) +#define MPEG4_SP_L3 (0x3) +#define MPEG4_SP_L0 (0x8) +#define MPEG4_SSP_L1 (0x11) +#define MPEG4_SSP_L2 (0x12) +#define MPEG4_CP_L1 (0x21) +#define MPEG4_CP_L2 (0x22) +#define MPEG4_MP_L2 (0x32) +#define MPEG4_MP_L3 (0x33) +#define MPEG4_MP_L4 (0x34) +#define MPEG4_NBP_L2 (0x42) +#define MPEG4_STP_L1 (0x51) +#define MPEG4_SFAP_L1 (0x61) +#define MPEG4_SFAP_L2 (0x62) +#define MPEG4_SFBAP_L1 (0x63) +#define MPEG4_SFBAP_L2 (0x64) +#define MPEG4_BATP_L1 (0x71) +#define MPEG4_BATP_L2 (0x72) +#define MPEG4_HP_L1 (0x81) +#define MPEG4_HP_L2 (0x82) +#define MPEG4_ARTSP_L1 (0x91) +#define MPEG4_ARTSP_L2 (0x92) +#define MPEG4_ARTSP_L3 (0x93) +#define MPEG4_ARTSP_L4 (0x94) +#define MPEG4_CSP_L1 (0xa1) +#define MPEG4_CSP_L2 (0xa2) +#define MPEG4_CSP_L3 (0xa3) +#define MPEG4_ACEP_L1 (0xb1) +#define MPEG4_ACEP_L2 (0xb2) +#define MPEG4_ACEP_L3 (0xb3) +#define MPEG4_ACEP_L4 (0xb4) +#define MPEG4_ACP_L1 (0xc1) +#define MPEG4_ACP_L2 (0xc2) +#define MPEG4_AST_L1 (0xd1) +#define MPEG4_AST_L2 (0xd2) +#define MPEG4_AST_L3 (0xd3) +#define MPEG4_S_STUDIO_P_L1 (0xe1) +#define MPEG4_S_STUDIO_P_L2 (0xe2) +#define MPEG4_S_STUDIO_P_L3 (0xe3) +#define MPEG4_S_STUDIO_P_L4 (0xe4) +#define MPEG4_C_STUDIO_P_L1 (0xe5) +#define MPEG4_C_STUDIO_P_L2 (0xe6) +#define MPEG4_C_STUDIO_P_L3 (0xe7) +#define MPEG4_C_STUDIO_P_L4 (0xe8) +#define MPEG4_ASP_L0 (0xF0) +#define MPEG4_ASP_L1 (0xF1) +#define MPEG4_ASP_L2 (0xF2) +#define MPEG4_ASP_L3 (0xF3) +#define MPEG4_ASP_L4 (0xF4) +#define MPEG4_ASP_L5 (0xF5) +#define MPEG4_ASP_L3B (0xF7) +#define MPEG4_FGSP_L0 (0xf8) +#define MPEG4_FGSP_L1 (0xf9) +#define MPEG4_FGSP_L2 (0xfa) +#define MPEG4_FGSP_L3 (0xfb) +#define MPEG4_FGSP_L4 (0xfc) +#define MPEG4_FGSP_L5 (0xfd) + +/* chapter related definitions */ +#define CHAPTERTITLELEN 1023 +typedef struct MP4ChapterStruct { + MP4Duration duration; /* duration of a chapter in milliseconds*/ + char title[CHAPTERTITLELEN+1]; /* title of the chapter */ +} MP4Chapters_t; +/* milliseconds to 100 nanoseconds */ +#define MILLI2HUNDREDNANO 10000 + + +/* MP4 API declarations */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* file operations */ +#define MP4_CREATE_64BIT_DATA (0x01) +#define MP4_CREATE_64BIT_TIME (0x02) // Quicktime is not compatible with this +#define MP4_CREATE_64BIT (MP4_CREATE_64BIT_DATA | MP4_CREATE_64BIT_TIME) +#define MP4_CREATE_EXTENSIBLE_FORMAT (0x04) + +MP4FileHandle MP4Create( + const MP4_FILENAME_CHAR *fileName, + u_int32_t verbosity DEFAULT(0), + u_int32_t flags DEFAULT(0)); +MP4FileHandle MP4CreateEx( + const MP4_FILENAME_CHAR *fileName, + u_int32_t verbosity DEFAULT(0), + u_int32_t flags DEFAULT(0), + int add_ftyp DEFAULT(1), + int add_iods DEFAULT(1), + char* majorBrand DEFAULT(0), + u_int32_t minorVersion DEFAULT(0), + char** supportedBrands DEFAULT(0), + u_int32_t supportedBrandsCount DEFAULT(0)); + +MP4FileHandle MP4Modify( + const MP4_FILENAME_CHAR *fileName, + u_int32_t verbosity DEFAULT(0), + u_int32_t flags DEFAULT(0)); + +MP4FileHandle MP4Read( + const MP4_FILENAME_CHAR *fileName, + u_int32_t verbosity DEFAULT(0)); + +// benski> +MP4FileHandle MP4ReadEx(const MP4_FILENAME_CHAR *fileName, + void *user, + Virtual_IO_t *virtual_IO, + u_int32_t verbosity DEFAULT(0)); + +void MP4Close( + MP4FileHandle hFile); + +bool MP4Optimize( + const MP4_FILENAME_CHAR *existingFileName, + const MP4_FILENAME_CHAR *newFileName DEFAULT(NULL), + u_int32_t verbosity DEFAULT(0)); + +bool MP4Dump( + MP4FileHandle hFile, + FILE* pDumpFile DEFAULT(NULL), + bool dumpImplicits DEFAULT(0)); + +#if 0 +char* MP4Info( + MP4FileHandle hFile, + MP4TrackId trackId DEFAULT(MP4_INVALID_TRACK_ID)); + +char* MP4FileInfo( + const MP4_FILENAME_CHAR* fileName, + MP4TrackId trackId DEFAULT(MP4_INVALID_TRACK_ID)); +#endif + +/* file properties */ + +/* specific file properties */ + +u_int32_t MP4GetVerbosity(MP4FileHandle hFile); + +void MP4SetVerbosity(MP4FileHandle hFile, u_int32_t verbosity); + +MP4Duration MP4GetDuration(MP4FileHandle hFile); + +u_int32_t MP4GetTimeScale(MP4FileHandle hFile); + +bool MP4SetTimeScale(MP4FileHandle hFile, u_int32_t value); + +u_int8_t MP4GetODProfileLevel(MP4FileHandle hFile); + +bool MP4SetODProfileLevel(MP4FileHandle hFile, u_int8_t value); + +u_int8_t MP4GetSceneProfileLevel(MP4FileHandle hFile); + +bool MP4SetSceneProfileLevel(MP4FileHandle hFile, u_int8_t value); + +u_int8_t MP4GetVideoProfileLevel(MP4FileHandle hFile, + MP4TrackId trackId DEFAULT(MP4_INVALID_TRACK_ID)); + +void MP4SetVideoProfileLevel(MP4FileHandle hFile, u_int8_t value); + +u_int8_t MP4GetAudioProfileLevel(MP4FileHandle hFile); + +void MP4SetAudioProfileLevel(MP4FileHandle hFile, u_int8_t value); + +u_int8_t MP4GetGraphicsProfileLevel(MP4FileHandle hFile); + +bool MP4SetGraphicsProfileLevel(MP4FileHandle hFile, u_int8_t value); + +/* generic file properties */ +bool MP4HaveAtom(MP4FileHandle hFile, + const char *atomName); + +bool MP4GetIntegerProperty( + MP4FileHandle hFile, + const char* propName, + u_int64_t *retval ); + + +bool MP4GetFloatProperty( + MP4FileHandle hFile, + const char* propName, + float *retvalue); + +bool MP4GetStringProperty( + MP4FileHandle hFile, + const char* propName, + const char **retvalue); + +bool MP4GetBytesProperty( + MP4FileHandle hFile, + const char* propName, + u_int8_t** ppValue, + u_int32_t* pValueSize); + +bool MP4SetIntegerProperty( + MP4FileHandle hFile, + const char* propName, + int64_t value); + +bool MP4SetFloatProperty( + MP4FileHandle hFile, + const char* propName, + float value); + +bool MP4SetStringProperty( + MP4FileHandle hFile, const char* propName, const char* value); + +bool MP4SetBytesProperty( + MP4FileHandle hFile, const char* propName, + const u_int8_t* pValue, u_int32_t valueSize); + +/* track operations */ + +MP4TrackId MP4AddTrack( + MP4FileHandle hFile, + const char* type); + +MP4TrackId MP4AddSystemsTrack( + MP4FileHandle hFile, + const char* type); + +MP4TrackId MP4AddODTrack( + MP4FileHandle hFile); + +MP4TrackId MP4AddSceneTrack( + MP4FileHandle hFile); + +MP4TrackId MP4AddAudioTrack( + MP4FileHandle hFile, + u_int32_t timeScale, + MP4Duration sampleDuration, + u_int8_t audioType DEFAULT(MP4_MPEG4_AUDIO_TYPE)); + +typedef struct mp4v2_ismacryp_session_params { + u_int32_t scheme_type; + u_int16_t scheme_version; + u_int8_t key_ind_len; + u_int8_t iv_len; + u_int8_t selective_enc; + const char *kms_uri; +} mp4v2_ismacrypParams; + +// API to initialize ismacryp properties to sensible defaults +// if input param is null then mallocs a params struct +mp4v2_ismacrypParams *MP4DefaultISMACrypParams(mp4v2_ismacrypParams *ptr); + +MP4TrackId MP4AddEncAudioTrack( + MP4FileHandle hFile, + u_int32_t timeScale, + MP4Duration sampleDuration, + mp4v2_ismacrypParams *icPp, + u_int8_t audioType DEFAULT(MP4_MPEG4_AUDIO_TYPE)); + +MP4TrackId MP4AddAmrAudioTrack( + MP4FileHandle hFile, + u_int32_t timeScale, + u_int16_t modeSet, + u_int8_t modeChangePeriod, + u_int8_t framesPerSample, + bool isAmrWB); + +void MP4SetAmrVendor( + MP4FileHandle hFile, + MP4TrackId trackId, + u_int32_t vendor); + +void MP4SetAmrDecoderVersion( + MP4FileHandle hFile, + MP4TrackId trackId, + u_int8_t decoderVersion); + +void MP4SetAmrModeSet(MP4FileHandle hFile, MP4TrackId trakId, uint16_t modeSet); +uint16_t MP4GetAmrModeSet(MP4FileHandle hFile, MP4TrackId trackId); + +MP4TrackId MP4AddHrefTrack(MP4FileHandle hFile, + uint32_t timeScale, + MP4Duration sampleDuration, + const char *base_url DEFAULT(NULL)); + +const char *MP4GetHrefTrackBaseUrl(MP4FileHandle hFile, + MP4TrackId trackId); +MP4TrackId MP4AddVideoTrack( + MP4FileHandle hFile, + u_int32_t timeScale, + MP4Duration sampleDuration, + u_int16_t width, + u_int16_t height, + u_int8_t videoType DEFAULT(MP4_MPEG4_VIDEO_TYPE)); + +MP4TrackId MP4AddEncVideoTrack( + MP4FileHandle hFile, + u_int32_t timeScale, + MP4Duration sampleDuration, + u_int16_t width, + u_int16_t height, + mp4v2_ismacrypParams *icPp, + u_int8_t videoType DEFAULT(MP4_MPEG4_VIDEO_TYPE), + const char *oFormat DEFAULT(NULL)); + +MP4TrackId MP4AddH264VideoTrack( + MP4FileHandle hFile, + u_int32_t timeScale, + MP4Duration sampleDuration, + u_int16_t width, + u_int16_t height, + uint8_t AVCProfileIndication, + uint8_t profile_compat, + uint8_t AVCLevelIndication, + uint8_t sampleLenFieldSizeMinusOne); + +MP4TrackId MP4AddEncH264VideoTrack( + MP4FileHandle dstFile, + u_int32_t timeScale, + MP4Duration sampleDuration, + u_int16_t width, + u_int16_t height, + MP4FileHandle srcFile, + MP4TrackId srcTrackId, + mp4v2_ismacrypParams *icPp); + +void MP4AddH264SequenceParameterSet(MP4FileHandle hFile, + MP4TrackId trackId, + const uint8_t *pSequence, + uint16_t sequenceLen); +void MP4AddH264PictureParameterSet(MP4FileHandle hFile, + MP4TrackId trackId, + const uint8_t *pPict, + uint16_t pictLen); +void MP4SetH263Vendor( + MP4FileHandle hFile, + MP4TrackId trackId, + u_int32_t vendor); + +void MP4SetH263DecoderVersion( + MP4FileHandle hFile, + MP4TrackId trackId, + u_int8_t decoderVersion); + +void MP4SetH263Bitrates( + MP4FileHandle hFile, + MP4TrackId trackId, + u_int32_t avgBitrate, + u_int32_t maxBitrate); + +MP4TrackId MP4AddH263VideoTrack( + MP4FileHandle hFile, + u_int32_t timeScale, + MP4Duration sampleDuration, + u_int16_t width, + u_int16_t height, + u_int8_t h263Level, + u_int8_t h263Profile, + u_int32_t avgBitrate, + u_int32_t maxBitrate); + +MP4TrackId MP4AddHintTrack( + MP4FileHandle hFile, + MP4TrackId refTrackId); + +MP4TrackId MP4AddTextTrack( + MP4FileHandle hFile, + MP4TrackId refTrackId); + +MP4TrackId MP4AddChapterTextTrack( +MP4FileHandle hFile, + MP4TrackId refTrackId, + u_int32_t timescale DEFAULT(0)); + +void MP4AddQTChapter( + MP4FileHandle hFile, + MP4TrackId chapterTrackId, + MP4Duration chapterDuration, + u_int32_t chapterNr, + const char * chapterTitle DEFAULT(0)); + +void MP4AddChapter( + MP4FileHandle hFile, + MP4Timestamp chapterStart, + const char * chapterTitle DEFAULT(0)); + +void MP4ConvertChapters( + MP4FileHandle hFile, + bool toQT DEFAULT(true)); + +void MP4DeleteChapters( + MP4FileHandle hFile, + MP4TrackId chapterTrackId DEFAULT(MP4_INVALID_TRACK_ID), + bool deleteQT DEFAULT(true)); + +void MP4GetChaptersList( + MP4FileHandle hFile, + MP4Chapters_t ** chapterList, + u_int32_t * chapterCount, + bool getQT DEFAULT(true)); + +MP4TrackId MP4CloneTrack( + MP4FileHandle srcFile, + MP4TrackId srcTrackId, + MP4FileHandle dstFile DEFAULT(MP4_INVALID_FILE_HANDLE), + MP4TrackId dstHintTrackReferenceTrack DEFAULT(MP4_INVALID_TRACK_ID)); + +MP4TrackId MP4EncAndCloneTrack( + MP4FileHandle srcFile, + MP4TrackId srcTrackId, + mp4v2_ismacrypParams *icPp, + MP4FileHandle dstFile DEFAULT(MP4_INVALID_FILE_HANDLE), + MP4TrackId dstHintTrackReferenceTrack DEFAULT(MP4_INVALID_TRACK_ID)); + +MP4TrackId MP4CopyTrack( + MP4FileHandle srcFile, + MP4TrackId srcTrackId, + MP4FileHandle dstFile DEFAULT(MP4_INVALID_FILE_HANDLE), + bool applyEdits DEFAULT(false), + MP4TrackId dstHintTrackReferenceTrack DEFAULT(MP4_INVALID_TRACK_ID)); + +typedef u_int32_t (*encryptFunc_t)(u_int32_t, u_int32_t, u_int8_t*, u_int32_t*, u_int8_t **); + +MP4TrackId MP4EncAndCopyTrack( + MP4FileHandle srcFile, + MP4TrackId srcTrackId, + mp4v2_ismacrypParams *icPp, + encryptFunc_t encfcnp, + u_int32_t encfcnparam1, + MP4FileHandle dstFile DEFAULT(MP4_INVALID_FILE_HANDLE), + bool applyEdits DEFAULT(false), + MP4TrackId dstHintTrackReferenceTrack DEFAULT(MP4_INVALID_TRACK_ID)); + +void MP4DeleteTrack( + MP4FileHandle hFile, + MP4TrackId trackId); + +u_int32_t MP4GetNumberOfTracks( + MP4FileHandle hFile, + const char* type DEFAULT(NULL), + u_int8_t subType DEFAULT(0)); + +MP4TrackId MP4FindTrackId( + MP4FileHandle hFile, + u_int16_t index, + const char* type DEFAULT(NULL), + u_int8_t subType DEFAULT(0)); + +u_int16_t MP4FindTrackIndex( + MP4FileHandle hFile, + MP4TrackId trackId); + +/* track properties */ + +/* specific track properties */ + +bool MP4HaveTrackAtom(MP4FileHandle hFile, + MP4TrackId trackId, + const char *atomname); + +const char* MP4GetTrackType( + MP4FileHandle hFile, + MP4TrackId trackId); + +const char *MP4GetTrackMediaDataName(MP4FileHandle hFile, + MP4TrackId trackId); + +// MP4GetTrackMediaDataOriginalFormat is to be used to get the original +// MediaDataName if a track has been encrypted. +bool MP4GetTrackMediaDataOriginalFormat(MP4FileHandle hFile, + MP4TrackId trackId, char *originalFormat, u_int32_t buflen); + +MP4Duration MP4GetTrackDuration( + MP4FileHandle hFile, + MP4TrackId trackId); + +u_int32_t MP4GetTrackTimeScale( + MP4FileHandle hFile, + MP4TrackId trackId); + +void MP4SetTrackTimeScale( + MP4FileHandle hFile, + MP4TrackId trackId, + u_int32_t value); + +u_int8_t MP4GetTrackAudioMpeg4Type( + MP4FileHandle hFile, + MP4TrackId trackId); + +u_int8_t MP4GetTrackEsdsObjectTypeId( + MP4FileHandle hFile, + MP4TrackId trackId); + +/* returns MP4_INVALID_DURATION if track samples do not have a fixed duration */ +MP4Duration MP4GetTrackFixedSampleDuration( + MP4FileHandle hFile, + MP4TrackId trackId); + +u_int32_t MP4GetTrackBitRate( + MP4FileHandle hFile, + MP4TrackId trackId); + +bool MP4GetTrackVideoMetadata(MP4FileHandle hFile, + MP4TrackId trackId, + uint8_t **ppConfig, + uint32_t *pConfigSize); + +bool MP4GetTrackESConfiguration( + MP4FileHandle hFile, + MP4TrackId trackId, + u_int8_t** ppConfig, + u_int32_t* pConfigSize); + +bool MP4SetTrackESConfiguration( + MP4FileHandle hFile, + MP4TrackId trackId, + const u_int8_t* pConfig, + u_int32_t configSize); + +/* h264 information routines */ +bool MP4GetTrackH264ProfileLevel(MP4FileHandle hFile, + MP4TrackId trackId, + uint8_t *pProfile, + uint8_t *pLevel); +void MP4GetTrackH264SeqPictHeaders(MP4FileHandle hFile, + MP4TrackId trackId, + uint8_t ***pSeqHeaders, + uint32_t **pSeqHeaderSize, + uint8_t ***pPictHeader, + uint32_t **pPictHeaderSize); +bool MP4GetTrackH264LengthSize(MP4FileHandle hFile, + MP4TrackId trackId, + uint32_t *pLength); +MP4SampleId MP4GetTrackNumberOfSamples( + MP4FileHandle hFile, + MP4TrackId trackId); + +MP4ChunkId MP4GetTrackNumberOfChunks( + MP4FileHandle hFile, + MP4TrackId trackId); + +u_int16_t MP4GetTrackVideoWidth( + MP4FileHandle hFile, + MP4TrackId trackId); + +u_int16_t MP4GetTrackVideoHeight( + MP4FileHandle hFile, + MP4TrackId trackId); + +double MP4GetTrackVideoFrameRate( + MP4FileHandle hFile, + MP4TrackId trackId); + +int MP4GetTrackAudioChannels(MP4FileHandle hFile, + MP4TrackId trackId); + +bool MP4IsIsmaCrypMediaTrack( + MP4FileHandle hFile, + MP4TrackId trackId); + +/* generic track properties */ + +bool MP4HaveTrackAtom(MP4FileHandle hFile, + MP4TrackId trackId, + const char *atomName); + +bool MP4GetTrackIntegerProperty( + MP4FileHandle hFile, + MP4TrackId trackId, + const char* propName, + u_int64_t *retvalue); + +bool MP4GetTrackFloatProperty( + MP4FileHandle hFile, + MP4TrackId trackId, + const char* propName, + float *ret_value); + +bool MP4GetTrackStringProperty( + MP4FileHandle hFile, + MP4TrackId trackId, + const char* propName, + const char **retvalue); + +bool MP4GetTrackBytesProperty( + MP4FileHandle hFile, + MP4TrackId trackId, + const char* propName, + u_int8_t** ppValue, + u_int32_t* pValueSize); + +bool MP4SetTrackIntegerProperty( + MP4FileHandle hFile, + MP4TrackId trackId, + const char* propName, + int64_t value); + +bool MP4SetTrackFloatProperty( + MP4FileHandle hFile, + MP4TrackId trackId, + const char* propName, + float value); + +bool MP4SetTrackStringProperty( + MP4FileHandle hFile, + MP4TrackId trackId, + const char* propName, + const char* value); + +bool MP4SetTrackBytesProperty( + MP4FileHandle hFile, + MP4TrackId trackId, + const char* propName, + const u_int8_t* pValue, + u_int32_t valueSize); + +/* sample operations */ + +bool MP4ReadSample( + /* input parameters */ + MP4FileHandle hFile, + MP4TrackId trackId, + MP4SampleId sampleId, + /* input/output parameters */ + u_int8_t** ppBytes, + u_int32_t* pNumBytes, + /* output parameters */ + MP4Timestamp* pStartTime DEFAULT(NULL), + MP4Duration* pDuration DEFAULT(NULL), + MP4Duration* pRenderingOffset DEFAULT(NULL), + bool* pIsSyncSample DEFAULT(NULL)); + +bool MP4ReadChunk( + /* input parameters */ + MP4FileHandle hFile, + MP4TrackId trackId, + MP4ChunkId sampleId, + /* input/output parameters */ + u_int8_t** ppBytes, + u_int32_t* pNumBytes, + MP4Timestamp* pStartTime DEFAULT(NULL), + MP4Duration* pDuration DEFAULT(NULL)); + +/* uses (unedited) time to specify sample instead of sample id */ +bool MP4ReadSampleFromTime( + /* input parameters */ + MP4FileHandle hFile, + MP4TrackId trackId, + MP4Timestamp when, + /* input/output parameters */ + u_int8_t** ppBytes, + u_int32_t* pNumBytes, + /* output parameters */ + MP4Timestamp* pStartTime DEFAULT(NULL), + MP4Duration* pDuration DEFAULT(NULL), + MP4Duration* pRenderingOffset DEFAULT(NULL), + bool* pIsSyncSample DEFAULT(NULL)); + +bool MP4WriteSample( + MP4FileHandle hFile, + MP4TrackId trackId, + const u_int8_t* pBytes, + u_int32_t numBytes, + MP4Duration duration DEFAULT(MP4_INVALID_DURATION), + MP4Duration renderingOffset DEFAULT(0), + bool isSyncSample DEFAULT(true)); + +bool MP4CopySample( + MP4FileHandle srcFile, + MP4TrackId srcTrackId, + MP4SampleId srcSampleId, + MP4FileHandle dstFile DEFAULT(MP4_INVALID_FILE_HANDLE), + MP4TrackId dstTrackId DEFAULT(MP4_INVALID_TRACK_ID), + MP4Duration dstSampleDuration DEFAULT(MP4_INVALID_DURATION)); + +bool MP4EncAndCopySample( + MP4FileHandle srcFile, + MP4TrackId srcTrackId, + MP4SampleId srcSampleId, + encryptFunc_t encfcnp, + u_int32_t encfcnparam1, + MP4FileHandle dstFile DEFAULT(MP4_INVALID_FILE_HANDLE), + MP4TrackId dstTrackId DEFAULT(MP4_INVALID_TRACK_ID), + MP4Duration dstSampleDuration DEFAULT(MP4_INVALID_DURATION)); + +/* Note this function is not yet implemented */ +bool MP4ReferenceSample( + MP4FileHandle srcFile, + MP4TrackId srcTrackId, + MP4SampleId srcSampleId, + MP4FileHandle dstFile, + MP4TrackId dstTrackId, + MP4Duration dstSampleDuration DEFAULT(MP4_INVALID_DURATION)); + +u_int32_t MP4GetSampleSize( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4SampleId sampleId); + +u_int32_t MP4GetTrackMaxSampleSize( + MP4FileHandle hFile, + MP4TrackId trackId); + +MP4SampleId MP4GetSampleIdFromTime( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4Timestamp when, + bool wantSyncSample DEFAULT(false), + bool rewind DEFAULT(false)); + +MP4ChunkId MP4GetChunkIdFromTime( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4Timestamp when); + +MP4Timestamp MP4GetSampleTime( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4SampleId sampleId); + +MP4Duration MP4GetSampleDuration( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4SampleId sampleId); + +MP4Duration MP4GetSampleRenderingOffset( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4SampleId sampleId); + +bool MP4SetSampleRenderingOffset( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4SampleId sampleId, + MP4Duration renderingOffset); + +int8_t MP4GetSampleSync( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4SampleId sampleId); + +/* rtp hint track operations */ + +bool MP4GetHintTrackRtpPayload( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + char** ppPayloadName DEFAULT(NULL), + u_int8_t* pPayloadNumber DEFAULT(NULL), + u_int16_t* pMaxPayloadSize DEFAULT(NULL), + char **ppEncodingParams DEFAULT(NULL)); + +#define MP4_SET_DYNAMIC_PAYLOAD 0xff + +bool MP4SetHintTrackRtpPayload( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + const char* pPayloadName, + u_int8_t* pPayloadNumber, + u_int16_t maxPayloadSize DEFAULT(0), + const char *encode_params DEFAULT(NULL), + bool include_rtp_map DEFAULT(true), + bool include_mpeg4_esid DEFAULT(true)); + +const char* MP4GetSessionSdp( + MP4FileHandle hFile); + +bool MP4SetSessionSdp( + MP4FileHandle hFile, + const char* sdpString); + +bool MP4AppendSessionSdp( + MP4FileHandle hFile, + const char* sdpString); + +const char* MP4GetHintTrackSdp( + MP4FileHandle hFile, + MP4TrackId hintTrackId); + +bool MP4SetHintTrackSdp( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + const char* sdpString); + +bool MP4AppendHintTrackSdp( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + const char* sdpString); + +MP4TrackId MP4GetHintTrackReferenceTrackId( + MP4FileHandle hFile, + MP4TrackId hintTrackId); + +bool MP4ReadRtpHint( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + MP4SampleId hintSampleId, + u_int16_t* pNumPackets DEFAULT(NULL)); + +u_int16_t MP4GetRtpHintNumberOfPackets( + MP4FileHandle hFile, + MP4TrackId hintTrackId); + +int8_t MP4GetRtpPacketBFrame( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + u_int16_t packetIndex); + +int32_t MP4GetRtpPacketTransmitOffset( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + u_int16_t packetIndex); + +bool MP4ReadRtpPacket( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + u_int16_t packetIndex, + u_int8_t** ppBytes, + u_int32_t* pNumBytes, + u_int32_t ssrc DEFAULT(0), + bool includeHeader DEFAULT(true), + bool includePayload DEFAULT(true)); + +MP4Timestamp MP4GetRtpTimestampStart( + MP4FileHandle hFile, + MP4TrackId hintTrackId); + +bool MP4SetRtpTimestampStart( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + MP4Timestamp rtpStart); + +bool MP4AddRtpHint( + MP4FileHandle hFile, + MP4TrackId hintTrackId); + +bool MP4AddRtpVideoHint( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + bool isBframe DEFAULT(false), + u_int32_t timestampOffset DEFAULT(0)); + +bool MP4AddRtpPacket( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + bool setMbit DEFAULT(false), + int32_t transmitOffset DEFAULT(0)); + +bool MP4AddRtpImmediateData( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + const u_int8_t* pBytes, + u_int32_t numBytes); + +bool MP4AddRtpSampleData( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + MP4SampleId sampleId, + u_int32_t dataOffset, + u_int32_t dataLength); + +bool MP4AddRtpESConfigurationPacket( + MP4FileHandle hFile, + MP4TrackId hintTrackId); + +bool MP4WriteRtpHint( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + MP4Duration duration, + bool isSyncSample DEFAULT(true)); + +/* 3GP specific utilities */ + +bool MP4Make3GPCompliant( + const MP4_FILENAME_CHAR* fileName, + u_int32_t verbosity DEFAULT(0), + char* majorBrand DEFAULT(0), + u_int32_t minorVersion DEFAULT(0), + char** supportedBrands DEFAULT(NULL), + u_int32_t supportedBrandsCount DEFAULT(0), + bool deleteIodsAtom DEFAULT(true)); + +/* ISMA specific utilities */ + +bool MP4MakeIsmaCompliant(const MP4_FILENAME_CHAR* fileName, + u_int32_t verbosity DEFAULT(0), + bool addIsmaComplianceSdp DEFAULT(true)); + +char* MP4MakeIsmaSdpIod( + u_int8_t videoProfile, + u_int32_t videoBitrate, + u_int8_t* videoConfig, + u_int32_t videoConfigLength, + u_int8_t audioProfile, + u_int32_t audioBitrate, + u_int8_t* audioConfig, + u_int32_t audioConfigLength, + u_int32_t verbosity DEFAULT(0)); + +/* edit list */ + +/* NOTE this section of functionality + * has not yet been fully tested + */ + +MP4EditId MP4AddTrackEdit( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId DEFAULT(MP4_INVALID_EDIT_ID), + MP4Timestamp startTime DEFAULT(0), + MP4Duration duration DEFAULT(0), + bool dwell DEFAULT(false)); + +bool MP4DeleteTrackEdit( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId); + +u_int32_t MP4GetTrackNumberOfEdits( + MP4FileHandle hFile, + MP4TrackId trackId); + +MP4Timestamp MP4GetTrackEditStart( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId); + +MP4Duration MP4GetTrackEditTotalDuration( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId DEFAULT(MP4_INVALID_EDIT_ID)); + +MP4Timestamp MP4GetTrackEditMediaStart( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId); + +bool MP4SetTrackEditMediaStart( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId, + MP4Timestamp startTime); + +MP4Duration MP4GetTrackEditDuration( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId); + +bool MP4SetTrackEditDuration( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId, + MP4Duration duration); + +int8_t MP4GetTrackEditDwell( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId); + +bool MP4SetTrackEditDwell( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId, + bool dwell); + +bool MP4ReadSampleFromEditTime( + /* input parameters */ + MP4FileHandle hFile, + MP4TrackId trackId, + MP4Timestamp when, + /* input/output parameters */ + u_int8_t** ppBytes, + u_int32_t* pNumBytes, + /* output parameters */ + MP4Timestamp* pStartTime DEFAULT(NULL), + MP4Duration* pDuration DEFAULT(NULL), + MP4Duration* pRenderingOffset DEFAULT(NULL), + bool* pIsSyncSample DEFAULT(NULL)); + +MP4SampleId MP4GetSampleIdFromEditTime( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4Timestamp when, + MP4Timestamp* pStartTime DEFAULT(NULL), + MP4Duration* pDuration DEFAULT(NULL)); +/* iTunes metadata handling */ +bool MP4MetadataDelete(MP4FileHandle hFile); +bool MP4GetMetadataByIndex(MP4FileHandle hFile, u_int32_t index, + char** ppName, // need to free memory + u_int8_t** ppValue, // need to free + u_int32_t* pValueSize); +bool MP4SetMetadataName(MP4FileHandle hFile, const char* value); +bool MP4GetMetadataName(MP4FileHandle hFile, char** value); +bool MP4DeleteMetadataName(MP4FileHandle hFile); +bool MP4SetMetadataArtist(MP4FileHandle hFile, const char* value); +bool MP4GetMetadataArtist(MP4FileHandle hFile, char** value); +bool MP4DeleteMetadataArtist(MP4FileHandle hFile); +bool MP4SetMetadataRating(MP4FileHandle hFile, const char* value); +bool MP4GetMetadataRating(MP4FileHandle hFile, char** value); +bool MP4DeleteMetadataRating(MP4FileHandle hFile); +bool MP4SetMetadataWriter(MP4FileHandle hFile, const char* value); +bool MP4GetMetadataWriter(MP4FileHandle hFile, char** value); +bool MP4DeleteMetadataWriter(MP4FileHandle hFile); +bool MP4SetMetadataComment(MP4FileHandle hFile, const char* value); +bool MP4GetMetadataComment(MP4FileHandle hFile, char** value); +bool MP4DeleteMetadataComment(MP4FileHandle hFile); +bool MP4SetMetadataTool(MP4FileHandle hFile, const char* value); +bool MP4GetMetadataTool(MP4FileHandle hFile, char** value); +bool MP4DeleteMetadataTool(MP4FileHandle hFile); +bool MP4SetMetadataYear(MP4FileHandle hFile, const char* value); +bool MP4GetMetadataYear(MP4FileHandle hFile, char** value); +bool MP4DeleteMetadataYear(MP4FileHandle hFile); +bool MP4SetMetadataAlbum(MP4FileHandle hFile, const char* value); +bool MP4GetMetadataAlbum(MP4FileHandle hFile, char** value); +bool MP4DeleteMetadataAlbum(MP4FileHandle hFile); +bool MP4SetMetadataTrack(MP4FileHandle hFile, + u_int16_t track, u_int16_t totalTracks); +bool MP4GetMetadataTrack(MP4FileHandle hFile, + u_int16_t* track, u_int16_t* totalTracks); +bool MP4DeleteMetadataTrack(MP4FileHandle hFile); +bool MP4SetMetadataDisk(MP4FileHandle hFile, + u_int16_t disk, u_int16_t totalDisks); +bool MP4GetMetadataDisk(MP4FileHandle hFile, + u_int16_t* disk, u_int16_t* totalDisks); +bool MP4DeleteMetadataDisk(MP4FileHandle hFile); +bool MP4SetMetadataGenre(MP4FileHandle hFile, const char *genre); +bool MP4GetMetadataGenre(MP4FileHandle hFile, char **genre); +bool MP4DeleteMetadataGenre(MP4FileHandle hFile); +bool MP4SetMetadataGrouping(MP4FileHandle hFile, const char *grouping); +bool MP4GetMetadataGrouping(MP4FileHandle hFile, char **grouping); +bool MP4DeleteMetadataGrouping(MP4FileHandle hFile); +bool MP4SetMetadataTempo(MP4FileHandle hFile, u_int16_t tempo); +bool MP4GetMetadataTempo(MP4FileHandle hFile, u_int16_t* tempo); +bool MP4DeleteMetadataTempo(MP4FileHandle hFile); +bool MP4SetMetadataCompilation(MP4FileHandle hFile, u_int8_t cpl); +bool MP4GetMetadataCompilation(MP4FileHandle hFile, u_int8_t* cpl); +bool MP4DeleteMetadataCompilation(MP4FileHandle hFile); +bool MP4SetMetadataPartOfGaplessAlbum(MP4FileHandle hFile, uint8_t pgap); +bool MP4GetMetadataPartOfGaplessAlbum(MP4FileHandle hFile, uint8_t *pgap); +bool MP4DeleteMetadataPartOfGaplessAlbum(MP4FileHandle hFile); +bool MP4SetMetadataCoverArt(MP4FileHandle hFile, u_int8_t *coverArt, u_int32_t size, int flags); +bool MP4GetMetadataCoverArt(MP4FileHandle hFile, u_int8_t **coverArt, u_int32_t* size, int *flags, uint32_t index DEFAULT(0)); +u_int32_t MP4GetMetadataCoverArtCount(MP4FileHandle hFile); +bool MP4DeleteMetadataCoverArt(MP4FileHandle hFile); +bool MP4SetMetadataAlbumArtist(MP4FileHandle hFile, const char* value); +bool MP4GetMetadataAlbumArtist(MP4FileHandle hFile, char** value); +bool MP4DeleteMetadataAlbumArtist(MP4FileHandle hFile); + + +bool MP4SetMetadataFreeForm(MP4FileHandle hFile, const char *name, + const u_int8_t* pValue, u_int32_t valueSize, const char *owner DEFAULT(NULL)); +bool MP4GetMetadataFreeForm(MP4FileHandle hFile, const char *name, + u_int8_t** pValue, u_int32_t* valueSize, const char *owner DEFAULT(NULL)); +bool MP4DeleteMetadataFreeForm(MP4FileHandle hFile, const char *name, const char *owner DEFAULT(NULL)); + +bool MP4Get3GPMetadata(MP4FileHandle hFile, const char *name, uint16_t **value); +bool MP4Set3GPMetadata(MP4FileHandle hFile, const char *name, const uint16_t* value); +bool MP4Get3GPMetadataInteger(MP4FileHandle hFile, const char *name, uint64_t *value); +bool MP4Set3GPMetadataInteger(MP4FileHandle hFile, const char *name, uint64_t value); +bool MP4Delete3GPMetadata(MP4FileHandle hFile, const char *name); + +/* time conversion utilties */ + +/* predefined values for timeScale parameter below */ +#define MP4_SECONDS_TIME_SCALE 1 +#define MP4_MILLISECONDS_TIME_SCALE 1000 +#define MP4_MICROSECONDS_TIME_SCALE 1000000 +#define MP4_NANOSECONDS_TIME_SCALE 1000000000 + +#define MP4_SECS_TIME_SCALE MP4_SECONDS_TIME_SCALE +#define MP4_MSECS_TIME_SCALE MP4_MILLISECONDS_TIME_SCALE +#define MP4_USECS_TIME_SCALE MP4_MICROSECONDS_TIME_SCALE +#define MP4_NSECS_TIME_SCALE MP4_NANOSECONDS_TIME_SCALE + +u_int64_t MP4ConvertFromMovieDuration( + MP4FileHandle hFile, + MP4Duration duration, + u_int32_t timeScale); + +u_int64_t MP4ConvertFromTrackTimestamp( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4Timestamp timeStamp, + u_int32_t timeScale); + +MP4Timestamp MP4ConvertToTrackTimestamp( + MP4FileHandle hFile, + MP4TrackId trackId, + u_int64_t timeStamp, + u_int32_t timeScale); + +u_int64_t MP4ConvertFromTrackDuration( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4Duration duration, + u_int32_t timeScale); + +MP4Duration MP4ConvertToTrackDuration( + MP4FileHandle hFile, + MP4TrackId trackId, + u_int64_t duration, + u_int32_t timeScale); + +char* MP4BinaryToBase16( + const u_int8_t* pData, + u_int32_t dataSize); + +char* MP4BinaryToBase64( + const u_int8_t* pData, + u_int32_t dataSize); + +uint8_t *Base64ToBinary(const char *pData, + uint32_t decodeSize, + uint32_t *pDataSize); +void MP4Free(void *p); + +char* MP4PrintAudioInfo( + MP4FileHandle mp4File, + MP4TrackId trackId); + +char* MP4PrintVideoInfo( + MP4FileHandle mp4File, + MP4TrackId trackId); + +#ifdef __cplusplus +} +#endif + +/* undefined our utlity macro to avoid conflicts */ +#undef DEFAULT + +#endif /* __MP4_INCLUDED__ */ diff --git a/Src/external_dependencies/libmp4v2/mp4array.h b/Src/external_dependencies/libmp4v2/mp4array.h new file mode 100644 index 00000000..9c6861a5 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/mp4array.h @@ -0,0 +1,136 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#ifndef __MP4_ARRAY_INCLUDED__ +#define __MP4_ARRAY_INCLUDED__ + +typedef u_int32_t MP4ArrayIndex; + +class MP4Array { +public: + MP4Array() { + m_numElements = 0; + m_maxNumElements = 0; + } + + inline bool ValidIndex(MP4ArrayIndex index) { + if (m_numElements == 0 || index > m_numElements - 1) { + return false; + } + return true; + } + + inline MP4ArrayIndex Size(void) { + return m_numElements; + } + + inline MP4ArrayIndex MaxSize(void) { + return m_maxNumElements; + } + +protected: + MP4ArrayIndex m_numElements; + MP4ArrayIndex m_maxNumElements; +}; + +// macro to generate subclasses +// we use this as an alternative to templates +// due to the excessive compile time price of extensive template usage + +template <class type> + class MP4TArray : public MP4Array + { + public: + MP4TArray() { + m_elements = NULL; + } + + ~MP4TArray() { + MP4Free(m_elements); + } + + inline void Add(type newElement) { + Insert(newElement, m_numElements); + } + + void Insert(type newElement, MP4ArrayIndex newIndex) { + if (newIndex > m_numElements) { + throw new MP4Error(ERANGE, "MP4Array::Insert"); + } + if (m_numElements == m_maxNumElements) { + m_maxNumElements = MAX(m_maxNumElements, 1) * 2; + m_elements = (type*)MP4ReallocArray(m_elements, + m_maxNumElements, sizeof(type)); + } + memmove(&m_elements[newIndex + 1], &m_elements[newIndex], + (m_numElements - newIndex) * sizeof(type)); + m_elements[newIndex] = newElement; + m_numElements++; + } + + void Delete(MP4ArrayIndex index) { + if (!ValidIndex(index)) { + throw new MP4Error(ERANGE, "MP4Array::Delete"); + } + m_numElements--; + if (index < m_numElements) { + memmove(&m_elements[index], &m_elements[index + 1], + (m_numElements - index) * sizeof(type)); + } + } + + void Resize(MP4ArrayIndex newSize) { + m_numElements = newSize; + m_maxNumElements = newSize; + m_elements = (type*)MP4ReallocArray(m_elements, + m_maxNumElements, sizeof(type)); + } + + type& operator[](MP4ArrayIndex index) { + if (!ValidIndex(index)) { + throw new MP4Error(ERANGE, "index %u of %u", "MP4Array::[]", index, m_numElements); + } + return m_elements[index]; + } + + protected: + type* m_elements; + }; + +#define MP4ARRAY_DECL(name, type) typedef MP4TArray<type> name##Array; + +MP4ARRAY_DECL(MP4Integer8, u_int8_t) + +MP4ARRAY_DECL(MP4Integer16, u_int16_t) + +MP4ARRAY_DECL(MP4Integer32, u_int32_t) + +MP4ARRAY_DECL(MP4Integer64, u_int64_t) + +MP4ARRAY_DECL(MP4Float32, float) + +MP4ARRAY_DECL(MP4Float64, double) + +MP4ARRAY_DECL(MP4String, char*) + +MP4ARRAY_DECL(MP4Bytes, u_int8_t*) + +#endif /* __MP4_ARRAY_INCLUDED__ */ diff --git a/Src/external_dependencies/libmp4v2/mp4atom.cpp b/Src/external_dependencies/libmp4v2/mp4atom.cpp new file mode 100644 index 00000000..9df1a6f8 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/mp4atom.cpp @@ -0,0 +1,884 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001 - 2004. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Portions created by Adnecto d.o.o. are + * Copyright (C) Adnecto d.o.o. 2005. All Rights Reserved + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + * Alix Marchandise-Franquet alix@cisco.com + * Ximpo Group Ltd. mp4v2@ximpo.com + * Danijel Kopcinovic danijel.kopcinovic@adnecto.net + */ + +#include "mp4common.h" +#include "atoms.h" + +MP4AtomInfo::MP4AtomInfo(const char* name, bool mandatory, bool onlyOne) +{ + m_name = name; + m_mandatory = mandatory; + m_onlyOne = onlyOne; + m_count = 0; +} + +MP4Atom::MP4Atom(const char* type) +{ + SetType(type); + m_unknownType = FALSE; + m_pFile = NULL; + m_start = 0; + m_end = 0; + m_size = 0; + m_pParentAtom = NULL; + m_depth = 0xFF; + memset(m_extendedType, 0, sizeof(m_extendedType)); +} + +MP4Atom::~MP4Atom() +{ + u_int32_t i; + + for (i = 0; i < m_pProperties.Size(); i++) { + delete m_pProperties[i]; + } + for (i = 0; i < m_pChildAtomInfos.Size(); i++) { + delete m_pChildAtomInfos[i]; + } + for (i = 0; i < m_pChildAtoms.Size(); i++) { + delete m_pChildAtoms[i]; + } +} + +MP4Atom* MP4Atom::CreateAtom(const char* type) +{ + MP4Atom* pAtom = NULL; + + if (type == NULL) { + pAtom = new MP4RootAtom(); + } else { + switch((uint8_t)type[0]) { + case 'a': + if (ATOMID(type) == ATOMID("avc1")) { + pAtom = new MP4Avc1Atom(); + } else if (ATOMID(type) == ATOMID("avcC")) { + pAtom = new MP4AvcCAtom(); + } else if (ATOMID(type) == ATOMID("alis")) { + pAtom = new MP4UrlAtom("alis"); + } else if (ATOMID(type) == ATOMID("alaw")) { + pAtom = new MP4SoundAtom(type); + } else if (ATOMID(type) == ATOMID("alac")) { + pAtom = new MP4SoundAtom(type); + } else if (ATOMID(type) == ATOMID("albm")) { + pAtom = new MP4Meta3Atom(type); + } + break; + case 'c': + if (ATOMID(type) == ATOMID("chap")) { + pAtom = new MP4TrefTypeAtom(type); + } else if (ATOMID(type) == ATOMID("chpl")) { + pAtom = new MP4ChplAtom(); + } + break; + case 'd': + if (ATOMID(type) == ATOMID("d263")) { + pAtom = new MP4D263Atom(); + } else if (ATOMID(type) == ATOMID("damr")) { + pAtom = new MP4DamrAtom(); + } else if (ATOMID(type) == ATOMID("dref")) { + pAtom = new MP4DrefAtom(); + } else if (ATOMID(type) == ATOMID("dpnd")) { + pAtom = new MP4TrefTypeAtom(type); + } else if (ATOMID(type) == ATOMID("data")) { /* Apple iTunes */ + pAtom = new MP4DataAtom(); + } + break; + case 'e': + if (ATOMID(type) == ATOMID("elst")) { + pAtom = new MP4ElstAtom(); + } else if (ATOMID(type) == ATOMID("enca")) { + pAtom = new MP4EncaAtom(); + } else if (ATOMID(type) == ATOMID("encv")) { + pAtom = new MP4EncvAtom(); + } + break; + case 'f': + if (ATOMID(type) == ATOMID("free")) { + pAtom = new MP4FreeAtom(); + } else if (ATOMID(type) == ATOMID("ftyp")) { + pAtom = new MP4FtypAtom(); + } + break; + case 'g': + if (ATOMID(type) == ATOMID("gmin")) { + pAtom = new MP4GminAtom(); + }/* else if (ATOMID(type) == ATOMID("gnre")) { // TODO: benski look at atom_rtp for implementation of two atom types with same name + pAtom = new MP4Meta3Atom(type); + } */ + break; + case 'h': + if (ATOMID(type) == ATOMID("hdlr")) { + pAtom = new MP4HdlrAtom(); + } else if (ATOMID(type) == ATOMID("hint")) { + pAtom = new MP4TrefTypeAtom(type); + } else if (ATOMID(type) == ATOMID("hnti")) { + pAtom = new MP4HntiAtom(); + } else if (ATOMID(type) == ATOMID("hinf")) { + pAtom = new MP4HinfAtom(); + } else if (ATOMID(type) == ATOMID("h263")) { + pAtom = new MP4VideoAtom("h263"); + } else if (ATOMID(type) == ATOMID("href")) { + pAtom = new MP4HrefAtom(); + } + break; + case 'i': + if (ATOMID(type) == ATOMID("ipir")) { + pAtom = new MP4TrefTypeAtom(type); + } else if (ATOMID(type) == ATOMID("ima4")) { + pAtom = new MP4SoundAtom("ima4"); + } + break; + case 'j': + if (ATOMID(type) == ATOMID("jpeg")) { + pAtom = new MP4VideoAtom("jpeg"); + } + break; + case 'm': + if (ATOMID(type) == ATOMID("mdhd")) { + pAtom = new MP4MdhdAtom(); + } else if (ATOMID(type) == ATOMID("mvhd")) { + pAtom = new MP4MvhdAtom(); + } else if (ATOMID(type) == ATOMID("mdat")) { + pAtom = new MP4MdatAtom(); + } else if (ATOMID(type) == ATOMID("mpod")) { + pAtom = new MP4TrefTypeAtom(type); + } else if (ATOMID(type) == ATOMID("mp4a")) { + pAtom = new MP4SoundAtom("mp4a"); + } else if (ATOMID(type) == ATOMID("mp4s")) { + pAtom = new MP4Mp4sAtom(); + } else if (ATOMID(type) == ATOMID("mp4v")) { + pAtom = new MP4Mp4vAtom(); + } else if (ATOMID(type) == ATOMID("mean")) { // iTunes + pAtom = new MP4Meta1Atom(type); + } + break; + case 'n': + if (ATOMID(type) == ATOMID("name")) { // iTunes + pAtom = new MP4Meta1Atom(type); + } + break; + case 'o': + if (ATOMID(type) == ATOMID("ohdr")) { + pAtom = new MP4OhdrAtom(); + } + break; + case 'p': + if (ATOMID(type) == ATOMID("perf")) { + pAtom = new MP4Meta3Atom(type); + } + break; + case 'r': + if (ATOMID(type) == ATOMID("rtp ")) { + pAtom = new MP4RtpAtom(); + } else if (ATOMID(type) == ATOMID("raw ")) { + pAtom = new MP4VideoAtom("raw "); + } + break; + case 's': + if (ATOMID(type) == ATOMID("s263")) { + pAtom = new MP4S263Atom(); + } else if (ATOMID(type) == ATOMID("samr")) { + pAtom = new MP4AmrAtom("samr"); + } else if (ATOMID(type) == ATOMID("sawb")) { + pAtom = new MP4AmrAtom("sawb"); + } else if (ATOMID(type) == ATOMID("stbl")) { + pAtom = new MP4StblAtom(); + } else if (ATOMID(type) == ATOMID("stsd")) { + pAtom = new MP4StsdAtom(); + } else if (ATOMID(type) == ATOMID("stsz")) { + pAtom = new MP4StszAtom(); + } else if (ATOMID(type) == ATOMID("stsc")) { + pAtom = new MP4StscAtom(); + } else if (ATOMID(type) == ATOMID("stz2")) { + pAtom = new MP4Stz2Atom(); + } else if (ATOMID(type) == ATOMID("stdp")) { + pAtom = new MP4StdpAtom(); + } else if (ATOMID(type) == ATOMID("sdp ")) { + pAtom = new MP4SdpAtom(); + } else if (ATOMID(type) == ATOMID("sync")) { + pAtom = new MP4TrefTypeAtom(type); + } else if (ATOMID(type) == ATOMID("skip")) { + pAtom = new MP4FreeAtom(); + pAtom->SetType("skip"); + } else if (ATOMID(type) == ATOMID("sowt")) { + pAtom = new MP4SoundAtom("sowt"); + } + break; + case 't': + if (ATOMID(type) == ATOMID("text")) { + pAtom = new MP4TextAtom(); + } else if (ATOMID(type) == ATOMID("tkhd")) { + pAtom = new MP4TkhdAtom(); + } else if (ATOMID(type) == ATOMID("tfhd")) { + pAtom = new MP4TfhdAtom(); + } else if (ATOMID(type) == ATOMID("trun")) { + pAtom = new MP4TrunAtom(); + } else if (ATOMID(type) == ATOMID("twos")) { + pAtom = new MP4SoundAtom("twos"); + } else if (ATOMID(type) == ATOMID("titl")) { + pAtom = new MP4Meta3Atom(type); + } + break; + case 'u': + if (ATOMID(type) == ATOMID("udta")) { + pAtom = new MP4UdtaAtom(); + } else if (ATOMID(type) == ATOMID("url ")) { + pAtom = new MP4UrlAtom(); + } else if (ATOMID(type) == ATOMID("urn ")) { + pAtom = new MP4UrnAtom(); + } else if (ATOMID(type) == ATOMID("ulaw")) { + pAtom = new MP4SoundAtom("ulaw"); + } + break; + case 'v': + if (ATOMID(type) == ATOMID("vmhd")) { + pAtom = new MP4VmhdAtom(); + } + break; + case 'y': + if (ATOMID(type) == ATOMID("yuv2")) { + pAtom = new MP4VideoAtom("yuv2"); + } + else if (ATOMID(type) == ATOMID("yrrc")) { + pAtom = new MP4Meta4Atom(type); + } + break; + case 'S': + if (ATOMID(type) == ATOMID("SVQ3")) { + pAtom = new MP4VideoAtom("SVQ3"); + } else if (ATOMID(type) == ATOMID("SMI ")) { + pAtom = new MP4SmiAtom(); + } + break; + case 0251: + static const char name[5]={'\xA9','n', 'a', 'm', '\0'}; + static const char cmt[5]={'\xA9','c', 'm', 't', '\0'}; + static const char cpy[5]={'\xA9','c', 'p', 'y', '\0'}; + static const char des[5]={'\xA9','d', 'e', 's','\0'}; + static const char prd[5]={'\xA9', 'p', 'r', 'd', '\0'}; + static const char lyr[5]={'\xA9', 'l', 'y', 'r', '\0'}; + if (ATOMID(type) == ATOMID(name) || + ATOMID(type) == ATOMID(cmt) || + ATOMID(type) == ATOMID(cpy) || + ATOMID(type) == ATOMID(prd) || + ATOMID(type) == ATOMID(des) || + ATOMID(type) == ATOMID(lyr)) { + pAtom = new MP4Meta2Atom(type); + } + break; + } + } + + if (pAtom == NULL) { + pAtom = new MP4StandardAtom(type); + // unknown type is set by StandardAtom type + } + + ASSERT(pAtom); + return pAtom; +} + +// generate a skeletal self + +void MP4Atom::Generate() +{ + u_int32_t i; + + // for all properties + for (i = 0; i < m_pProperties.Size(); i++) { + // ask it to self generate + m_pProperties[i]->Generate(); + } + + // for all mandatory, single child atom types + for (i = 0; i < m_pChildAtomInfos.Size(); i++) { + if (m_pChildAtomInfos[i]->m_mandatory + && m_pChildAtomInfos[i]->m_onlyOne) { + + // create the mandatory, single child atom + MP4Atom* pChildAtom = + CreateAtom(m_pChildAtomInfos[i]->m_name); + + AddChildAtom(pChildAtom); + + // and ask it to self generate + pChildAtom->Generate(); + } + } +} + +MP4Atom* MP4Atom::ReadAtom(MP4File* pFile, MP4Atom* pParentAtom) +{ + u_int8_t hdrSize = 8; + u_int8_t extendedType[16]; + + u_int64_t pos = pFile->GetPosition(); + + VERBOSE_READ(pFile->GetVerbosity(), + printf("ReadAtom: pos = 0x"X64"\n", pos)); + + u_int64_t dataSize = pFile->ReadUInt32(); + + char type[5]; + pFile->ReadBytes((u_int8_t*)&type[0], 4); + type[4] = '\0'; + + // extended size + if (dataSize == 1) { + dataSize = pFile->ReadUInt64(); + hdrSize += 8; + pFile->Check64BitStatus(type); + } + + // extended type + if (ATOMID(type) == ATOMID("uuid")) { + pFile->ReadBytes(extendedType, sizeof(extendedType)); + hdrSize += sizeof(extendedType); + } + + if (dataSize == 0) { + // extends to EOF + dataSize = pFile->GetSize() - pos; + } + + dataSize -= hdrSize; + + VERBOSE_READ(pFile->GetVerbosity(), + printf("ReadAtom: type = \"%s\" data-size = "U64" (0x"X64") hdr %u\n", + type, dataSize, dataSize, hdrSize)); + + if (pos + hdrSize + dataSize > pParentAtom->GetEnd()) { + VERBOSE_ERROR(pFile->GetVerbosity(), + printf("ReadAtom: invalid atom size, extends outside parent atom - skipping to end of \"%s\" \"%s\" "U64" vs "U64"\n", + pParentAtom->GetType(), type, + pos + hdrSize + dataSize, + pParentAtom->GetEnd())); + VERBOSE_READ(pFile->GetVerbosity(), + printf("parent %s ("U64") pos "U64" hdr %d data "U64" sum "U64"\n", + pParentAtom->GetType(), + pParentAtom->GetEnd(), + pos, + hdrSize, + dataSize, + pos + hdrSize + dataSize)); +#if 0 + throw new MP4Error("invalid atom size", "ReadAtom"); +#else + //pFile->SetPosition(pParentAtom->GetEnd()); + //return 0; + // TODO: benski> we should re-enable this if we can find a good way to very that the datasize might be correct. + // skip to end of atom + dataSize = pParentAtom->GetEnd() - pos - hdrSize; +#endif + } + + + MP4Atom* pAtom = CreateAtom(type); + pAtom->SetFile(pFile); + pAtom->SetStart(pos); + pAtom->SetEnd(pos + hdrSize + dataSize); + pAtom->SetSize(dataSize); + if (ATOMID(type) == ATOMID("uuid")) { + pAtom->SetExtendedType(extendedType); + } + if (pAtom->IsUnknownType()) { + if (!IsReasonableType(pAtom->GetType())) { + VERBOSE_READ(pFile->GetVerbosity(), + printf("Warning: atom type %s is suspect\n", pAtom->GetType())); + } else { + VERBOSE_READ(pFile->GetVerbosity(), + printf("Info: atom type %s is unknown\n", pAtom->GetType())); + } + + if (dataSize > 0) { + pAtom->AddProperty( + new MP4BytesProperty("data", dataSize)); + } + } + + pAtom->SetParentAtom(pParentAtom); + + pAtom->Read(); + + return pAtom; +} + +bool MP4Atom::IsReasonableType(const char* type) +{ + for (u_int8_t i = 0; i < 4; i++) { + if (iscntrl((unsigned char)type[i])) { + return false; + } + if (i == 3 && type[i] == ' ') { + continue; + } + return false; + } + return true; +} + +// generic read +void MP4Atom::Read() +{ + ASSERT(m_pFile); + + if (ATOMID(m_type) != 0 && m_size > 1000000) { + VERBOSE_READ(GetVerbosity(), + printf("Warning: %s atom size "U64" is suspect\n", + m_type, m_size)); + } + + ReadProperties(); + + // read child atoms, if we expect there to be some + if (m_pChildAtomInfos.Size() > 0) { + ReadChildAtoms(); + } + + Skip(); // to end of atom +} + +void MP4Atom::Skip() +{ + if (m_pFile->GetPosition() != m_end) { + VERBOSE_READ(m_pFile->GetVerbosity(), + printf("Skip: "U64" bytes\n", m_end - m_pFile->GetPosition())); + } + m_pFile->SetPosition(m_end); +} + +MP4Atom* MP4Atom::FindAtomMP4(const char* name) +{ + if (!IsMe(name)) { + return NULL; + } + + if (!IsRootAtom()) { + VERBOSE_FIND(m_pFile->GetVerbosity(), + printf("FindAtomMP4: matched %s\n", name)); + + name = MP4NameAfterFirst(name); + + // I'm the sought after atom + if (name == NULL) { + return this; + } + } + + // else it's one of my children + return FindChildAtom(name); +} + +bool MP4Atom::FindProperty(const char *name, + MP4Property** ppProperty, u_int32_t* pIndex) +{ + if (!IsMe(name)) { + return false; + } + + if (!IsRootAtom()) { + VERBOSE_FIND(m_pFile->GetVerbosity(), + printf("FindProperty: matched %s\n", name)); + + name = MP4NameAfterFirst(name); + + // no property name given + if (name == NULL) { + return false; + } + } + + return FindContainedProperty(name, ppProperty, pIndex); +} + +bool MP4Atom::IsMe(const char* name) +{ + if (name == NULL) { + return false; + } + + // root atom always matches + if (!strcmp(m_type, "")) { + return true; + } + + // check if our atom name is specified as the first component + if (!MP4NameFirstMatches(m_type, name)) { + return false; + } + + return true; +} + +MP4Atom* MP4Atom::FindChildAtom(const char* name) +{ + u_int32_t atomIndex = 0; + + // get the index if we have one, e.g. moov.trak[2].mdia... + (void)MP4NameFirstIndex(name, &atomIndex); + + // need to get to the index'th child atom of the right type + for (u_int32_t i = 0; i < m_pChildAtoms.Size(); i++) { + if (MP4NameFirstMatches(m_pChildAtoms[i]->GetType(), name)) { + if (atomIndex == 0) { + // this is the one, ask it to match + return m_pChildAtoms[i]->FindAtomMP4(name); + } + atomIndex--; + } + } + + return NULL; +} + +bool MP4Atom::FindContainedProperty(const char *name, + MP4Property** ppProperty, u_int32_t* pIndex) +{ + u_int32_t numProperties = m_pProperties.Size(); + u_int32_t i; + // check all of our properties + for (i = 0; i < numProperties; i++) { + if (m_pProperties[i]->FindProperty(name, ppProperty, pIndex)) { + return true; + } + } + + // not one of our properties, + // presumably one of our children's properties + // check child atoms... + + // check if we have an index, e.g. trak[2].mdia... + u_int32_t atomIndex = 0; + (void)MP4NameFirstIndex(name, &atomIndex); + + // need to get to the index'th child atom of the right type + for (i = 0; i < m_pChildAtoms.Size(); i++) { + if (MP4NameFirstMatches(m_pChildAtoms[i]->GetType(), name)) { + if (atomIndex == 0) { + // this is the one, ask it to match + return m_pChildAtoms[i]->FindProperty(name, ppProperty, pIndex); + } + atomIndex--; + } + } + + VERBOSE_FIND(m_pFile->GetVerbosity(), + printf("FindProperty: no match for %s\n", name)); + return false; +} + +void MP4Atom::ReadProperties(u_int32_t startIndex, u_int32_t count) +{ + u_int32_t numProperties = MIN(count, m_pProperties.Size() - startIndex); + + // read any properties of the atom + for (u_int32_t i = startIndex; i < startIndex + numProperties; i++) { + + m_pProperties[i]->Read(m_pFile); + + if (m_pFile->GetPosition() > m_end) { + VERBOSE_READ(GetVerbosity(), + printf("ReadProperties: insufficient data for property: %s pos 0x"X64" atom end 0x"X64"\n", + m_pProperties[i]->GetName(), + m_pFile->GetPosition(), m_end)); + + // benski> throw new MP4Error("atom is too small", "Atom ReadProperties"); + return; + } + } +} + +void MP4Atom::ReadChildAtoms() +{ + bool this_is_udta = ATOMID(m_type) == ATOMID("udta"); + + VERBOSE_READ(GetVerbosity(), + printf("ReadChildAtoms: of %s\n", m_type[0] ? m_type : "root")); + for (u_int64_t position = m_pFile->GetPosition(); + position < m_end; + position = m_pFile->GetPosition()) { + // make sure that we have enough to read at least 8 bytes + // size and type. + if (m_end - position < 2 * sizeof(uint32_t)) { + // if we're reading udta, it's okay to have 4 bytes of 0 + if (this_is_udta && + m_end - position == sizeof(uint32_t)) { + u_int32_t mbz = m_pFile->ReadUInt32(); + if (mbz != 0) { + VERBOSE_WARNING(GetVerbosity(), + printf("Error: In udta atom, end value is not zero %x\n", + mbz)); + } + continue; + } + // otherwise, output a warning, but don't care + VERBOSE_WARNING(GetVerbosity(), + printf("Error: In %s atom, extra "D64" bytes at end of atom\n", + m_type, (m_end - position))); + for (uint64_t ix = 0; ix < m_end - position; ix++) { + (void)m_pFile->ReadUInt8(); + } + continue; + } + MP4Atom* pChildAtom = MP4Atom::ReadAtom(m_pFile, this); + + if (pChildAtom) + { + AddChildAtom(pChildAtom); + + MP4AtomInfo* pChildAtomInfo = FindAtomInfo(pChildAtom->GetType()); + + // if child atom is of known type + // but not expected here print warning + if (pChildAtomInfo == NULL && !pChildAtom->IsUnknownType()) { + VERBOSE_READ(GetVerbosity(), + printf("Warning: In atom %s unexpected child atom %s\n", + GetType(), pChildAtom->GetType())); + } + + // if child atoms should have just one instance + // and this is more than one, print warning + if (pChildAtomInfo) { + pChildAtomInfo->m_count++; + + if (pChildAtomInfo->m_onlyOne && pChildAtomInfo->m_count > 1) { + VERBOSE_READ(GetVerbosity(), + printf("Warning: In atom %s multiple child atoms %s\n", + GetType(), pChildAtom->GetType())); + } + } + + } + } + + // if mandatory child atom doesn't exist, print warning + u_int32_t numAtomInfo = m_pChildAtomInfos.Size(); + for (u_int32_t i = 0; i < numAtomInfo; i++) { + if (m_pChildAtomInfos[i]->m_mandatory + && m_pChildAtomInfos[i]->m_count == 0) { + VERBOSE_READ(GetVerbosity(), + printf("Warning: In atom %s missing child atom %s\n", + GetType(), m_pChildAtomInfos[i]->m_name)); + } + } + + VERBOSE_READ(GetVerbosity(), + printf("ReadChildAtoms: finished %s\n", m_type)); +} + +MP4AtomInfo* MP4Atom::FindAtomInfo(const char* name) +{ + u_int32_t numAtomInfo = m_pChildAtomInfos.Size(); + for (u_int32_t i = 0; i < numAtomInfo; i++) { + if (ATOMID(m_pChildAtomInfos[i]->m_name) == ATOMID(name)) { + return m_pChildAtomInfos[i]; + } + } + return NULL; +} + +// generic write +void MP4Atom::Write() +{ + ASSERT(m_pFile); + + BeginWrite(); + + WriteProperties(); + + WriteChildAtoms(); + + FinishWrite(); +} + +void MP4Atom::Rewrite() +{ + ASSERT(m_pFile); + + if (!m_end) { + // This atom hasn't been written yet... + return; + } + + u_int64_t fPos = m_pFile->GetPosition(); + m_pFile->SetPosition(GetStart()); + Write(); + m_pFile->SetPosition(fPos); +} + +void MP4Atom::BeginWrite(bool use64) +{ + m_start = m_pFile->GetPosition(); + //use64 = m_pFile->Use64Bits(); + if (use64) { + m_pFile->WriteUInt32(1); + } else { + m_pFile->WriteUInt32(0); + } + m_pFile->WriteBytes((u_int8_t*)&m_type[0], 4); + if (use64) { + m_pFile->WriteUInt64(0); + } + if (ATOMID(m_type) == ATOMID("uuid")) { + m_pFile->WriteBytes(m_extendedType, sizeof(m_extendedType)); + } +} + +void MP4Atom::FinishWrite(bool use64) +{ + m_end = m_pFile->GetPosition(); + m_size = (m_end - m_start); + VERBOSE_WRITE(GetVerbosity(), + printf("end: type %s "U64" "U64" size "U64"\n", m_type, + m_start, m_end, + m_size)); + //use64 = m_pFile->Use64Bits(); + if (use64) { + m_pFile->SetPosition(m_start + 8); + m_pFile->WriteUInt64(m_size); + } else { + ASSERT(m_size <= (u_int64_t)0xFFFFFFFF); + m_pFile->SetPosition(m_start); + m_pFile->WriteUInt32(m_size); + } + m_pFile->SetPosition(m_end); + + // adjust size to just reflect data portion of atom + m_size -= (use64 ? 16 : 8); + if (ATOMID(m_type) == ATOMID("uuid")) { + m_size -= sizeof(m_extendedType); + } +} + +void MP4Atom::WriteProperties(u_int32_t startIndex, u_int32_t count) +{ + u_int32_t numProperties = MIN(count, m_pProperties.Size() - startIndex); + + VERBOSE_WRITE(GetVerbosity(), + printf("Write: type %s\n", m_type)); + + for (u_int32_t i = startIndex; i < startIndex + numProperties; i++) { + m_pProperties[i]->Write(m_pFile); + } +} + +void MP4Atom::WriteChildAtoms() +{ + u_int32_t size = m_pChildAtoms.Size(); + for (u_int32_t i = 0; i < size; i++) { + m_pChildAtoms[i]->Write(); + } + + VERBOSE_WRITE(GetVerbosity(), + printf("Write: finished %s\n", m_type)); +} + +void MP4Atom::AddProperty(MP4Property* pProperty) +{ + ASSERT(pProperty); + m_pProperties.Add(pProperty); + pProperty->SetParentAtom(this); +} + +void MP4Atom::AddVersionAndFlags() +{ + AddProperty(new MP4Integer8Property("version")); + AddProperty(new MP4Integer24Property("flags")); +} + +void MP4Atom::AddReserved(char* name, u_int32_t size) +{ + MP4BytesProperty* pReserved = new MP4BytesProperty(name, size); + pReserved->SetReadOnly(); + AddProperty(pReserved); +} + +void MP4Atom::ExpectChildAtom(const char* name, bool mandatory, bool onlyOne) +{ + m_pChildAtomInfos.Add(new MP4AtomInfo(name, mandatory, onlyOne)); +} + +u_int8_t MP4Atom::GetVersion() +{ + if (strcmp("version", m_pProperties[0]->GetName())) { + return 0; + } + return ((MP4Integer8Property*)m_pProperties[0])->GetValue(); +} + +void MP4Atom::SetVersion(u_int8_t version) +{ + if (strcmp("version", m_pProperties[0]->GetName())) { + return; + } + ((MP4Integer8Property*)m_pProperties[0])->SetValue(version); +} + +u_int32_t MP4Atom::GetFlags() +{ + if (strcmp("flags", m_pProperties[1]->GetName())) { + return 0; + } + return ((MP4Integer24Property*)m_pProperties[1])->GetValue(); +} + +void MP4Atom::SetFlags(u_int32_t flags) +{ + if (strcmp("flags", m_pProperties[1]->GetName())) { + return; + } + ((MP4Integer24Property*)m_pProperties[1])->SetValue(flags); +} + +u_int32_t MP4Atom::GetVerbosity() +{ + ASSERT(m_pFile); + return m_pFile->GetVerbosity(); +} + +u_int8_t MP4Atom::GetDepth() +{ + if (m_depth < 0xFF) { + return m_depth; + } + + MP4Atom *pAtom = this; + m_depth = 0; + + while ((pAtom = pAtom->GetParentAtom()) != NULL) { + m_depth++; + ASSERT(m_depth < 255); + } + return m_depth; +} + diff --git a/Src/external_dependencies/libmp4v2/mp4atom.h b/Src/external_dependencies/libmp4v2/mp4atom.h new file mode 100644 index 00000000..c27b2b5a --- /dev/null +++ b/Src/external_dependencies/libmp4v2/mp4atom.h @@ -0,0 +1,261 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001 - 2004. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + * Ximpo Group Ltd. mp4v2@ximpo.com + */ + +#ifndef __MP4_ATOM_INCLUDED__ +#define __MP4_ATOM_INCLUDED__ + +class MP4Atom; +MP4ARRAY_DECL(MP4Atom, MP4Atom*); + +#define Required true +#define Optional false +#define OnlyOne true +#define Many false +#define Counted true + +/* helper class */ +class MP4AtomInfo { +public: + MP4AtomInfo() { + m_name = NULL; + m_mandatory = false; + m_onlyOne = false; + m_count = 0; + } + MP4AtomInfo(const char* name, bool mandatory, bool onlyOne); + + const char* m_name; + bool m_mandatory; + bool m_onlyOne; + u_int32_t m_count; +}; + +MP4ARRAY_DECL(MP4AtomInfo, MP4AtomInfo*); + +class MP4Atom { +public: + MP4Atom(const char* type = NULL); + virtual ~MP4Atom(); + + static MP4Atom* ReadAtom(MP4File* pFile, MP4Atom* pParentAtom); + static MP4Atom* CreateAtom(const char* type); + static bool IsReasonableType(const char* type); + + MP4File* GetFile() { + return m_pFile; + }; + void SetFile(MP4File* pFile) { + m_pFile = pFile; + }; + + u_int64_t GetStart() { + return m_start; + }; + void SetStart(u_int64_t pos) { + m_start = pos; + }; + + u_int64_t GetEnd() { + return m_end; + }; + void SetEnd(u_int64_t pos) { + m_end = pos; + }; + + u_int64_t GetSize() { + return m_size; + } + void SetSize(u_int64_t size) { + m_size = size; + } + + const char* GetType() { + return m_type; + }; + void SetType(const char* type) { + if (type && *type != '\0') { + // not needed ASSERT(strlen(type) == 4); + memcpy(m_type, type, 4); + m_type[4] = '\0'; + } else { + memset(m_type, 0, 5); + } + } + + void GetExtendedType(u_int8_t* pExtendedType) { + memcpy(pExtendedType, m_extendedType, sizeof(m_extendedType)); + }; + void SetExtendedType(u_int8_t* pExtendedType) { + memcpy(m_extendedType, pExtendedType, sizeof(m_extendedType)); + }; + + bool IsUnknownType() { + return m_unknownType; + } + void SetUnknownType(bool unknownType = true) { + m_unknownType = unknownType; + } + + bool IsRootAtom() { + return m_type[0] == '\0'; + } + + MP4Atom* GetParentAtom() { + return m_pParentAtom; + } + void SetParentAtom(MP4Atom* pParentAtom) { + m_pParentAtom = pParentAtom; + } + + void AddChildAtom(MP4Atom* pChildAtom) { + pChildAtom->SetFile(m_pFile); + pChildAtom->SetParentAtom(this); + m_pChildAtoms.Add(pChildAtom); + } + + void InsertChildAtom(MP4Atom* pChildAtom, u_int32_t index) { + pChildAtom->SetFile(m_pFile); + pChildAtom->SetParentAtom(this); + m_pChildAtoms.Insert(pChildAtom, index); + } + + void DeleteChildAtom(MP4Atom* pChildAtom) { + for (MP4ArrayIndex i = 0; i < m_pChildAtoms.Size(); i++) { + if (m_pChildAtoms[i] == pChildAtom) { + m_pChildAtoms.Delete(i); + return; + } + } + } + + u_int32_t GetNumberOfChildAtoms() { + return m_pChildAtoms.Size(); + } + + MP4Atom* GetChildAtom(u_int32_t index) { + return m_pChildAtoms[index]; + } + + MP4Property* GetProperty(u_int32_t index) { + return m_pProperties[index]; + } + + u_int32_t GetCount() { + return m_pProperties.Size(); + } + +#if 0 + void SetProperty(u_int32_t index, MP4Property *property) { + u_int64_t t; + if (index > m_pProperties.Size()) + return; + + t = property->Get(index); + m_pProperties[index]->Set(t, index); + } +#endif + + MP4Atom* FindAtomMP4(const char* name); + + MP4Atom* FindChildAtom(const char* name); + + bool FindProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex = NULL); + + u_int32_t GetFlags(); + void SetFlags(u_int32_t flags); + + u_int8_t GetDepth(); + + void Skip(); + + virtual void Generate(); + virtual void Read(); + virtual void BeginWrite(bool use64 = false); + virtual void Write(); + virtual void Rewrite(); + virtual void FinishWrite(bool use64 = false); + +protected: + void AddProperty(MP4Property* pProperty); + + void AddVersionAndFlags(); + + void AddReserved(char* name, u_int32_t size); + + void ExpectChildAtom(const char* name, + bool mandatory, bool onlyOne = true); + + MP4AtomInfo* FindAtomInfo(const char* name); + + bool IsMe(const char* name); + + bool FindContainedProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex); + + void ReadProperties( + u_int32_t startIndex = 0, u_int32_t count = 0xFFFFFFFF); + void ReadChildAtoms(); + + void WriteProperties( + u_int32_t startIndex = 0, u_int32_t count = 0xFFFFFFFF); + void WriteChildAtoms(); + + u_int8_t GetVersion(); + void SetVersion(u_int8_t version); + + /* debugging aid */ + u_int32_t GetVerbosity(); + +protected: + MP4File* m_pFile; + u_int64_t m_start; + u_int64_t m_end; + u_int64_t m_size; + char m_type[5]; + bool m_unknownType; + u_int8_t m_extendedType[16]; + + MP4Atom* m_pParentAtom; + u_int8_t m_depth; + + MP4PropertyArray m_pProperties; + MP4AtomInfoArray m_pChildAtomInfos; + MP4AtomArray m_pChildAtoms; +}; + +inline u_int32_t ATOMID(const char* type) { + return STRTOINT32(type); +} + +// inverse ATOMID - 32 bit id to string +inline void IDATOM(u_int32_t type, char *s) { + INT32TOSTR(type, s); +} + +#endif /* __MP4_ATOM_INCLUDED__ */ diff --git a/Src/external_dependencies/libmp4v2/mp4common.h b/Src/external_dependencies/libmp4v2/mp4common.h new file mode 100644 index 00000000..b4db21b3 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/mp4common.h @@ -0,0 +1,50 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#ifndef __MP4_COMMON_INCLUDED__ +#define __MP4_COMMON_INCLUDED__ + +// common includes for everything +// with an internal view of the library +// i.e. all the .cpp's just #include "mp4common.h" + +#include "mpeg4ip.h" + +#include "mp4.h" +#include "mp4util.h" +#include "mp4array.h" +#include "mp4track.h" +#include "mp4file.h" +#include "mp4property.h" +#include "mp4container.h" +#include "mp4descriptor.h" +#include "mp4atom.h" + +#include "atoms.h" +#include "descriptors.h" +#include "ocidescriptors.h" +#include "qosqualifiers.h" + +#include "odcommands.h" + +#include "rtphint.h" +#include "virtual_io.h" +#endif /* __MP4_COMMON_INCLUDED__ */ diff --git a/Src/external_dependencies/libmp4v2/mp4container.cpp b/Src/external_dependencies/libmp4v2/mp4container.cpp new file mode 100644 index 00000000..dc3a9120 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/mp4container.cpp @@ -0,0 +1,217 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4Container::~MP4Container() +{ + for (u_int32_t i = 0; i < m_pProperties.Size(); i++) { + delete m_pProperties[i]; + } +} + +void MP4Container::AddProperty(MP4Property* pProperty) +{ + ASSERT(pProperty); + m_pProperties.Add(pProperty); +} + +bool MP4Container::FindProperty(const char *name, + MP4Property** ppProperty, u_int32_t* pIndex) +{ + if (pIndex) { + *pIndex = 0; // set the default answer for index + } + + u_int32_t numProperties = m_pProperties.Size(); + + for (u_int32_t i = 0; i < numProperties; i++) { + if (m_pProperties[i]->FindProperty(name, ppProperty, pIndex)) { + return true; + } + } + return false; +} + +void MP4Container::FindIntegerProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex) +{ + if (!FindProperty(name, ppProperty, pIndex)) { + throw new MP4Error("no such property", + "MP4Container::FindIntegerProperty"); + } + + switch ((*ppProperty)->GetType()) { + case Integer8Property: + case Integer16Property: + case Integer24Property: + case Integer32Property: + case Integer64Property: + break; + default: + throw new MP4Error("type mismatch", + "MP4Container::FindIntegerProperty"); + } +} + +u_int64_t MP4Container::GetIntegerProperty(const char* name) +{ + MP4Property* pProperty; + u_int32_t index; + + FindIntegerProperty(name, &pProperty, &index); + + return ((MP4IntegerProperty*)pProperty)->GetValue(index); +} + +void MP4Container::SetIntegerProperty(const char* name, u_int64_t value) +{ + MP4Property* pProperty = NULL; + u_int32_t index = 0; + + FindIntegerProperty(name, &pProperty, &index); + + ((MP4IntegerProperty*)pProperty)->SetValue(value, index); +} + +void MP4Container::FindFloatProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex) +{ + if (!FindProperty(name, ppProperty, pIndex)) { + throw new MP4Error("no such property", + "MP4Container::FindFloatProperty"); + } + if ((*ppProperty)->GetType() != Float32Property) { + throw new MP4Error("type mismatch", + "MP4Container::FindFloatProperty"); + } +} + +float MP4Container::GetFloatProperty(const char* name) +{ + MP4Property* pProperty; + u_int32_t index; + + FindFloatProperty(name, &pProperty, &index); + + return ((MP4Float32Property*)pProperty)->GetValue(index); +} + +void MP4Container::SetFloatProperty(const char* name, float value) +{ + MP4Property* pProperty; + u_int32_t index; + + FindFloatProperty(name, &pProperty, &index); + + ((MP4Float32Property*)pProperty)->SetValue(value, index); +} + +void MP4Container::FindStringProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex) +{ + if (!FindProperty(name, ppProperty, pIndex)) { + throw new MP4Error("no such property", + "MP4Container::FindStringProperty"); + } + if ((*ppProperty)->GetType() != StringProperty) { + throw new MP4Error("type mismatch", + "MP4Container::FindStringProperty"); + } +} + +const char* MP4Container::GetStringProperty(const char* name) +{ + MP4Property* pProperty; + u_int32_t index; + + FindStringProperty(name, &pProperty, &index); + + return ((MP4StringProperty*)pProperty)->GetValue(index); +} + +void MP4Container::SetStringProperty(const char* name, const char* value) +{ + MP4Property* pProperty; + u_int32_t index; + + FindStringProperty(name, &pProperty, &index); + + ((MP4StringProperty*)pProperty)->SetValue(value, index); +} + +void MP4Container::FindBytesProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex) +{ + if (!FindProperty(name, ppProperty, pIndex)) { + throw new MP4Error("no such property", + "MP4Container::FindBytesProperty"); + } + if ((*ppProperty)->GetType() != BytesProperty) { + throw new MP4Error("type mismatch", + "MP4Container::FindBytesProperty"); + } +} + +void MP4Container::GetBytesProperty(const char* name, + u_int8_t** ppValue, u_int32_t* pValueSize) +{ + MP4Property* pProperty; + u_int32_t index; + + FindBytesProperty(name, &pProperty, &index); + + ((MP4BytesProperty*)pProperty)->GetValue(ppValue, pValueSize, index); +} + +void MP4Container::SetBytesProperty(const char* name, + const u_int8_t* pValue, u_int32_t valueSize) +{ + MP4Property* pProperty; + u_int32_t index; + + FindBytesProperty(name, &pProperty, &index); + + ((MP4BytesProperty*)pProperty)->SetValue(pValue, valueSize, index); +} + +void MP4Container::Read(MP4File* pFile) +{ + u_int32_t numProperties = m_pProperties.Size(); + + for (u_int32_t i = 0; i < numProperties; i++) { + m_pProperties[i]->Read(pFile); + } +} + +void MP4Container::Write(MP4File* pFile) +{ + u_int32_t numProperties = m_pProperties.Size(); + + if (numProperties == 0) { + WARNING(numProperties == 0); + return; + } + + for (u_int32_t i = 0; i < numProperties; i++) { + m_pProperties[i]->Write(pFile); + } +} diff --git a/Src/external_dependencies/libmp4v2/mp4container.h b/Src/external_dependencies/libmp4v2/mp4container.h new file mode 100644 index 00000000..7cbcb8a3 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/mp4container.h @@ -0,0 +1,82 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#ifndef __MP4_CONTAINER_INCLUDED__ +#define __MP4_CONTAINER_INCLUDED__ + +// base class - container of mp4 properties +class MP4Container { +public: + MP4Container() { } + + virtual ~MP4Container(); + + void AddProperty(MP4Property* pProperty); + + virtual void Read(MP4File* pFile); + + virtual void Write(MP4File* pFile); + + MP4Property* GetProperty(u_int32_t index) { + return m_pProperties[index]; + } + + // LATER MP4Property* GetProperty(const char* name); throw on error + // LATER MP4Property* FindProperty(const char* name, u_int32_t* pIndex = NULL); returns NULL on error + + bool FindProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex = NULL); + + void FindIntegerProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex = NULL); + + u_int64_t GetIntegerProperty(const char* name); + + void SetIntegerProperty(const char* name, u_int64_t value); + + void FindFloatProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex = NULL); + + float GetFloatProperty(const char* name); + + void SetFloatProperty(const char* name, float value); + + void FindStringProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex = NULL); + + const char* GetStringProperty(const char* name); + + void SetStringProperty(const char* name, const char* value); + + void FindBytesProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex = NULL); + + void GetBytesProperty(const char* name, + u_int8_t** ppValue, u_int32_t* pValueSize); + + void SetBytesProperty(const char* name, + const u_int8_t* pValue, u_int32_t valueSize); + +protected: + MP4PropertyArray m_pProperties; +}; + +#endif /* __MP4_CONTAINER_INCLUDED__ */ diff --git a/Src/external_dependencies/libmp4v2/mp4descriptor.cpp b/Src/external_dependencies/libmp4v2/mp4descriptor.cpp new file mode 100644 index 00000000..ecde7dcd --- /dev/null +++ b/Src/external_dependencies/libmp4v2/mp4descriptor.cpp @@ -0,0 +1,188 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4Descriptor::MP4Descriptor(u_int8_t tag) { + m_tag = tag; + m_pParentAtom = NULL; + m_start = 0; + m_size = 0; + m_readMutatePoint = 0; +} + +MP4Descriptor::~MP4Descriptor() +{ + for (u_int32_t i = 0; i < m_pProperties.Size(); i++) { + delete m_pProperties[i]; + } +} + +void MP4Descriptor::AddProperty(MP4Property* pProperty) +{ + ASSERT(pProperty); + m_pProperties.Add(pProperty); + pProperty->SetParentAtom(m_pParentAtom); +} + +bool MP4Descriptor::FindContainedProperty(const char *name, + MP4Property** ppProperty, u_int32_t* pIndex) +{ + u_int32_t numProperties = m_pProperties.Size(); + + for (u_int32_t i = 0; i < numProperties; i++) { + if (m_pProperties[i]->FindProperty(name, ppProperty, pIndex)) { + return true; + } + } + return false; +} + +void MP4Descriptor::Generate() +{ + // generate properties + for (u_int32_t i = 0; i < m_pProperties.Size(); i++) { + m_pProperties[i]->Generate(); + } +} + +void MP4Descriptor::Read(MP4File* pFile) +{ + ReadHeader(pFile); + + ReadProperties(pFile, 0, m_readMutatePoint); + + Mutate(); + + ReadProperties(pFile, m_readMutatePoint); + + // flush any leftover read bits + pFile->FlushReadBits(); +} + +void MP4Descriptor::ReadHeader(MP4File* pFile) +{ + VERBOSE_READ(pFile->GetVerbosity(), + printf("ReadDescriptor: pos = 0x"X64"\n", + pFile->GetPosition())); + + // read tag and length + u_int8_t tag = pFile->ReadUInt8(); + if (m_tag) { + ASSERT(tag == m_tag); + } else { + m_tag = tag; + } + m_size = pFile->ReadMpegLength(); + m_start = pFile->GetPosition(); + + VERBOSE_READ(pFile->GetVerbosity(), + printf("ReadDescriptor: tag 0x%02x data size %u (0x%x)\n", + m_tag, m_size, m_size)); +} + +void MP4Descriptor::ReadProperties(MP4File* pFile, + u_int32_t propStartIndex, u_int32_t propCount) +{ + u_int32_t numProperties = MIN(propCount, + m_pProperties.Size() - propStartIndex); + + for (u_int32_t i = propStartIndex; + i < propStartIndex + numProperties; i++) { + + MP4Property* pProperty = m_pProperties[i]; + + int32_t remaining = m_size - (pFile->GetPosition() - m_start); + + if (pProperty->GetType() == DescriptorProperty) { + if (remaining > 0) { + // place a limit on how far this sub-descriptor looks + ((MP4DescriptorProperty*)pProperty)->SetSizeLimit(remaining); + pProperty->Read(pFile); + } // else do nothing, empty descriptor + } else { + // non-descriptor property + if (remaining >= 0) { + pProperty->Read(pFile); + + } else { + VERBOSE_ERROR(pFile->GetVerbosity(), + printf("Overran descriptor, tag %u data size %u property %u\n", + m_tag, m_size, i)); + throw new MP4Error("overran descriptor", + "MP4Descriptor::ReadProperties"); + } + } + } +} + +void MP4Descriptor::Write(MP4File* pFile) +{ + // call virtual function to adapt properties before writing + Mutate(); + + u_int32_t numProperties = m_pProperties.Size(); + + if (numProperties == 0) { + WARNING(numProperties == 0); + return; + } + + // write tag and length placeholder + pFile->WriteUInt8(m_tag); + u_int64_t lengthPos = pFile->GetPosition(); + pFile->WriteMpegLength(0); + u_int64_t startPos = pFile->GetPosition(); + + for (u_int32_t i = 0; i < numProperties; i++) { + m_pProperties[i]->Write(pFile); + } + + // align with byte boundary (rarely necessary) + pFile->PadWriteBits(); + + // go back and write correct length + u_int64_t endPos = pFile->GetPosition(); + pFile->SetPosition(lengthPos); + pFile->WriteMpegLength(endPos - startPos); + pFile->SetPosition(endPos); +} + +void MP4Descriptor::WriteToMemory(MP4File* pFile, + u_int8_t** ppBytes, u_int64_t* pNumBytes) +{ + // use memory buffer to save descriptor in memory + // instead of going directly to disk + + pFile->EnableMemoryBuffer(); + + Write(pFile); + + pFile->DisableMemoryBuffer(ppBytes, pNumBytes); +} + +u_int8_t MP4Descriptor::GetDepth() +{ + if (m_pParentAtom) { + return m_pParentAtom->GetDepth(); + } + return 0; +} diff --git a/Src/external_dependencies/libmp4v2/mp4descriptor.h b/Src/external_dependencies/libmp4v2/mp4descriptor.h new file mode 100644 index 00000000..7243bd5a --- /dev/null +++ b/Src/external_dependencies/libmp4v2/mp4descriptor.h @@ -0,0 +1,95 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#ifndef __MP4_DESCRIPTOR_INCLUDED__ +#define __MP4_DESCRIPTOR_INCLUDED__ + +class MP4Descriptor { +public: + MP4Descriptor(u_int8_t tag = 0); + + virtual ~MP4Descriptor(); + + u_int8_t GetTag() { + return m_tag; + } + void SetTag(u_int8_t tag) { + m_tag = tag; + } + + void SetParentAtom(MP4Atom* pParentAtom) { + m_pParentAtom = pParentAtom; + for (u_int32_t i = 0; i < m_pProperties.Size(); i++) { + m_pProperties[i]->SetParentAtom(pParentAtom); + } + } + + void AddProperty(MP4Property* pProperty); + + virtual void Generate(); + virtual void Read(MP4File* pFile); + virtual void Write(MP4File* pFile); + + MP4Property* GetProperty(u_int32_t index) { + return m_pProperties[index]; + } + + // use with extreme caution + void SetProperty(u_int32_t index, MP4Property* pProperty) { + m_pProperties[index] = pProperty; + } + + bool FindProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex = NULL) { + return FindContainedProperty(name, ppProperty, pIndex); + } + + void WriteToMemory(MP4File* pFile, + u_int8_t** ppBytes, u_int64_t* pNumBytes); + +protected: + void SetReadMutate(u_int32_t propIndex) { + m_readMutatePoint = propIndex; + } + + void ReadHeader(MP4File* pFile); + void ReadProperties(MP4File* pFile, + u_int32_t startIndex = 0, u_int32_t count = 0xFFFFFFFF); + + virtual void Mutate() { + // default is a no-op + }; + + bool FindContainedProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex); + + u_int8_t GetDepth(); + +protected: + MP4Atom* m_pParentAtom; + u_int8_t m_tag; + u_int64_t m_start; + u_int32_t m_size; + MP4PropertyArray m_pProperties; + u_int32_t m_readMutatePoint; +}; + +#endif /* __MP4_DESCRIPTOR_INCLUDED__ */ diff --git a/Src/external_dependencies/libmp4v2/mp4file.cpp b/Src/external_dependencies/libmp4v2/mp4file.cpp new file mode 100644 index 00000000..e12ccf51 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/mp4file.cpp @@ -0,0 +1,3728 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001 - 2005. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + * Alix Marchandise-Franquet alix@cisco.com + * Ximpo Group Ltd. mp4v2@ximpo.com + * Bill May wmay@cisco.com + */ + +#include "mp4common.h" + +MP4File::MP4File(u_int32_t verbosity) +{ + m_fileName = NULL; + m_pFile = NULL; + m_virtual_IO = NULL; + m_orgFileSize = 0; + m_fileSize = 0; + m_pRootAtom = NULL; + m_odTrackId = MP4_INVALID_TRACK_ID; + + m_verbosity = verbosity; + m_mode = 0; + m_createFlags = 0; + m_useIsma = false; + + m_pModificationProperty = NULL; + m_pTimeScaleProperty = NULL; + m_pDurationProperty = NULL; + + m_memoryBuffer = NULL; + m_memoryBufferSize = 0; + m_memoryBufferPosition = 0; + + m_numReadBits = 0; + m_bufReadBits = 0; + m_numWriteBits = 0; + m_bufWriteBits = 0; + m_editName = NULL; +#ifndef _WIN32 + m_tempFileName[0] = '\0'; +#endif + m_trakName[0] = '\0'; + m_tempFileName[0] = '\0'; +} + +MP4File::~MP4File() +{ + MP4Free(m_fileName); + if (m_pFile != NULL) { + // not closed ? + m_virtual_IO->Close(m_pFile); + m_pFile = NULL; + } + delete m_pRootAtom; + for (u_int32_t i = 0; i < m_pTracks.Size(); i++) { + delete m_pTracks[i]; + } + MP4Free(m_memoryBuffer); // just in case + CHECK_AND_FREE(m_editName); + +} + +void MP4File::Read(const MP4_FILENAME_CHAR* fileName) +{ + m_fileName = MP4Stralloc(fileName); + m_mode = 'r'; + +#ifdef _WIN32 + Open(L"rb"); +#else + Open("rb"); +#endif + + ReadFromFile(); + + CacheProperties(); +} + +// benski> +void MP4File::ReadEx(const MP4_FILENAME_CHAR *fileName, void *user, Virtual_IO *virtual_IO) +{ + m_fileName = MP4Stralloc(fileName); + m_mode = 'r'; + + m_pFile = user; + m_virtual_IO = virtual_IO; + + ASSERT(m_pFile); + ASSERT(m_virtual_IO) + + m_orgFileSize = m_fileSize = m_virtual_IO->GetFileLength(m_pFile); + + ReadFromFile(); + + CacheProperties(); +} + + +void MP4File::Create(const MP4_FILENAME_CHAR *fileName, u_int32_t flags, + int add_ftyp, int add_iods, + char* majorBrand, u_int32_t minorVersion, + char** supportedBrands, u_int32_t supportedBrandsCount) +{ + m_fileName = MP4Stralloc(fileName); + m_mode = 'w'; + m_createFlags = flags; + +#ifdef _WIN32 + Open(L"wb+"); +#else + Open("wb+"); +#endif + + // generate a skeletal atom tree + m_pRootAtom = MP4Atom::CreateAtom(NULL); + m_pRootAtom->SetFile(this); + m_pRootAtom->Generate(); + + if (add_ftyp != 0) { + MakeFtypAtom(majorBrand, minorVersion, + supportedBrands, supportedBrandsCount); + } + + CacheProperties(); + + // create mdat, and insert it after ftyp, and before moov + (void)InsertChildAtom(m_pRootAtom, "mdat", + add_ftyp != 0 ? 1 : 0); + + // start writing + m_pRootAtom->BeginWrite(); + if (add_iods != 0) { + (void)AddChildAtom("moov", "iods"); + } +} + +bool MP4File::Use64Bits (const char *atomName) +{ + uint32_t atomid = ATOMID(atomName); + if (atomid == ATOMID("mdat") || atomid == ATOMID("stbl")) { + return (m_createFlags & MP4_CREATE_64BIT_DATA) == MP4_CREATE_64BIT_DATA; + } + if (atomid == ATOMID("mvhd") || + atomid == ATOMID("tkhd") || + atomid == ATOMID("mdhd")) { + return (m_createFlags & MP4_CREATE_64BIT_TIME) == MP4_CREATE_64BIT_TIME; + } + return false; +} + +void MP4File::Check64BitStatus (const char *atomName) +{ + uint32_t atomid = ATOMID(atomName); + + if (atomid == ATOMID("mdat") || atomid == ATOMID("stbl")) { + m_createFlags |= MP4_CREATE_64BIT_DATA; + } else if (atomid == ATOMID("mvhd") || + atomid == ATOMID("tkhd") || + atomid == ATOMID("mdhd")) { + m_createFlags |= MP4_CREATE_64BIT_TIME; + } +} + + +void MP4File::Modify(const MP4_FILENAME_CHAR* fileName) +{ + m_fileName = MP4Stralloc(fileName); + m_mode = 'r'; + +#ifdef _WIN32 + Open(L"rb+"); +#else + Open("rb+"); +#endif + ReadFromFile(); + + m_mode = 'w'; + + // find the moov atom + MP4Atom* pMoovAtom = m_pRootAtom->FindAtomMP4("moov"); + u_int32_t numAtoms; + + if (pMoovAtom == NULL) { + // there isn't one, odd but we can still proceed + pMoovAtom = AddChildAtom(m_pRootAtom, "moov"); + } else { + numAtoms = m_pRootAtom->GetNumberOfChildAtoms(); + + // work backwards thru the top level atoms + int32_t i; + bool lastAtomIsMoov = true; + MP4Atom* pLastAtom = NULL; + + for (i = numAtoms - 1; i >= 0; i--) { + MP4Atom* pAtom = m_pRootAtom->GetChildAtom(i); + const char* type = pAtom->GetType(); + + // get rid of any trailing free or skips + if (!strcmp(type, "free") || !strcmp(type, "skip")) { + m_pRootAtom->DeleteChildAtom(pAtom); + continue; + } + + if (strcmp(type, "moov")) { + if (pLastAtom == NULL) { + pLastAtom = pAtom; + lastAtomIsMoov = false; + } + continue; + } + + // now at moov atom + + // multiple moov atoms?!? + if (pAtom != pMoovAtom) { + throw new MP4Error( + "Badly formed mp4 file, multiple moov atoms", + "MP4Modify"); + } + + if (lastAtomIsMoov) { + // position to start of moov atom, + // effectively truncating file + // prior to adding new mdat + SetPosition(pMoovAtom->GetStart()); + + } else { // last atom isn't moov + // need to place a free atom + MP4Atom* pFreeAtom = MP4Atom::CreateAtom("free"); + + // in existing position of the moov atom + m_pRootAtom->InsertChildAtom(pFreeAtom, i); + m_pRootAtom->DeleteChildAtom(pMoovAtom); + m_pRootAtom->AddChildAtom(pMoovAtom); + + // write free atom to disk + SetPosition(pMoovAtom->GetStart()); + pFreeAtom->SetSize(pMoovAtom->GetSize()); + pFreeAtom->Write(); + + // finally set our file position to the end of the last atom + SetPosition(pLastAtom->GetEnd()); + } + + break; + } + ASSERT(i != -1); + } + + CacheProperties(); // of moov atom + + numAtoms = m_pRootAtom->GetNumberOfChildAtoms(); + + // insert another mdat prior to moov atom (the last atom) + MP4Atom* pMdatAtom = InsertChildAtom(m_pRootAtom, "mdat", numAtoms - 1); + + // start writing new mdat + pMdatAtom->BeginWrite(Use64Bits("mdat")); +} + +void MP4File::Optimize(const MP4_FILENAME_CHAR* orgFileName, const MP4_FILENAME_CHAR* newFileName) +{ + m_fileName = MP4Stralloc(orgFileName); + m_mode = 'r'; + + // first load meta-info into memory +#ifdef _WIN32 + Open(L"rb"); +#else + Open("rb"); +#endif + ReadFromFile(); + + CacheProperties(); // of moov atom + + // now switch over to writing the new file + MP4Free(m_fileName); + + // create a temporary file if necessary + if (newFileName == NULL) { + m_fileName = MP4Stralloc(TempFileName()); + } else { + m_fileName = MP4Stralloc(newFileName); + } + + void* pReadFile = m_pFile; + Virtual_IO *pReadIO = m_virtual_IO; + m_pFile = NULL; + m_mode = 'w'; +#ifdef _WIN32 + Open(L"wb"); +#else + Open("wb"); +#endif + + SetIntegerProperty("moov.mvhd.modificationTime", + MP4GetAbsTimestamp()); + + // writing meta info in the optimal order + ((MP4RootAtom*)m_pRootAtom)->BeginOptimalWrite(); + + // write data in optimal order + RewriteMdat(pReadFile, m_pFile, pReadIO, m_virtual_IO); + + // finish writing + ((MP4RootAtom*)m_pRootAtom)->FinishOptimalWrite(); + + // cleanup + m_virtual_IO->Close(m_pFile); + m_pFile = NULL; + pReadIO->Close(pReadFile); + + // move temporary file into place + if (newFileName == NULL) { + Rename(m_fileName, orgFileName); + } +} + +void MP4File::RewriteMdat(void* pReadFile, void* pWriteFile, + Virtual_IO *readIO, Virtual_IO *writeIO) +{ + u_int32_t numTracks = m_pTracks.Size(); + + MP4ChunkId* chunkIds = new MP4ChunkId[numTracks]; + MP4ChunkId* maxChunkIds = new MP4ChunkId[numTracks]; + MP4Timestamp* nextChunkTimes = new MP4Timestamp[numTracks]; + + for (u_int32_t i = 0; i < numTracks; i++) { + chunkIds[i] = 1; + maxChunkIds[i] = m_pTracks[i]->GetNumberOfChunks(); + nextChunkTimes[i] = MP4_INVALID_TIMESTAMP; + } + + while (true) { + u_int32_t nextTrackIndex = (u_int32_t)-1; + MP4Timestamp nextTime = MP4_INVALID_TIMESTAMP; + + for (u_int32_t i = 0; i < numTracks; i++) { + if (chunkIds[i] > maxChunkIds[i]) { + continue; + } + + if (nextChunkTimes[i] == MP4_INVALID_TIMESTAMP) { + MP4Timestamp chunkTime = + m_pTracks[i]->GetChunkTime(chunkIds[i]); + + nextChunkTimes[i] = MP4ConvertTime(chunkTime, + m_pTracks[i]->GetTimeScale(), GetTimeScale()); + } + + // time is not earliest so far + if (nextChunkTimes[i] > nextTime) { + continue; + } + + // prefer hint tracks to media tracks if times are equal + if (nextChunkTimes[i] == nextTime + && strcmp(m_pTracks[i]->GetType(), MP4_HINT_TRACK_TYPE)) { + continue; + } + + // this is our current choice of tracks + nextTime = nextChunkTimes[i]; + nextTrackIndex = i; + } + + if (nextTrackIndex == (u_int32_t)-1) { + break; + } + + // point into original mp4 file for read chunk call + m_pFile = pReadFile; + m_virtual_IO = readIO; + m_mode = 'r'; + + u_int8_t* pChunk=0; + u_int32_t chunkSize; + + m_pTracks[nextTrackIndex]-> + ReadChunk(chunkIds[nextTrackIndex], &pChunk, &chunkSize); + + // point back at the new mp4 file for write chunk + m_pFile = pWriteFile; + m_virtual_IO = writeIO; + m_mode = 'w'; + + m_pTracks[nextTrackIndex]-> + RewriteChunk(chunkIds[nextTrackIndex], pChunk, chunkSize); + + MP4Free(pChunk); + + chunkIds[nextTrackIndex]++; + nextChunkTimes[nextTrackIndex] = MP4_INVALID_TIMESTAMP; + } + + delete [] chunkIds; + delete [] maxChunkIds; + delete [] nextChunkTimes; +} + +void MP4File::Open(const MP4_FILENAME_CHAR *fmode) +{ + ASSERT(m_pFile == NULL); + FILE *openFile = NULL; + +#ifdef O_LARGEFILE + // UGH! fopen doesn't open a file in 64-bit mode, period. + // So we need to use open() and then fdopen() + int fd; + int flags = O_LARGEFILE; + + if (strchr(fmode, '+')) { + flags |= O_CREAT | O_RDWR; + if (fmode[0] == 'w') { + flags |= O_TRUNC; + } + } else { + if (fmode[0] == 'w') { + flags |= O_CREAT | O_TRUNC | O_WRONLY; + } else { + flags |= O_RDONLY; + } + } + fd = open(m_fileName, flags, 0666); + + if (fd >= 0) { + openFile = fdopen(fd, fmode); + } +#elif defined(_WIN32) + openFile = _wfopen(m_fileName, fmode); +#else + openFile = fopen(m_fileName, fmode); +#endif + m_pFile = openFile; + + if (m_pFile == NULL) { + throw new MP4Error(errno, "failed", "MP4Open"); + } + + m_virtual_IO = &FILE_virtual_IO; + if (m_mode == 'r') { + m_orgFileSize = m_fileSize = m_virtual_IO->GetFileLength(m_pFile); // benski + } else { + m_orgFileSize = m_fileSize = 0; + } +} + +void MP4File::ReadFromFile() +{ + // ensure we start at beginning of file + SetPosition(0); + + // create a new root atom + ASSERT(m_pRootAtom == NULL); + m_pRootAtom = MP4Atom::CreateAtom(NULL); + + u_int64_t fileSize = GetSize(); + + m_pRootAtom->SetFile(this); + m_pRootAtom->SetStart(0); + m_pRootAtom->SetSize(fileSize); + m_pRootAtom->SetEnd(fileSize); + + m_pRootAtom->Read(); + + // create MP4Track's for any tracks in the file + GenerateTracks(); +} + +void MP4File::GenerateTracks() +{ + u_int32_t trackIndex = 0; + + while (true) { + char trackName[32]; + snprintf(trackName, sizeof(trackName), "moov.trak[%u]", trackIndex); + + // find next trak atom + MP4Atom* pTrakAtom = m_pRootAtom->FindAtomMP4(trackName); + + // done, no more trak atoms + if (pTrakAtom == NULL) { + break; + } + + // find track id property + MP4Integer32Property* pTrackIdProperty = NULL; + (void)pTrakAtom->FindProperty( + "trak.tkhd.trackId", + (MP4Property**)&pTrackIdProperty); + + // find track type property + MP4StringProperty* pTypeProperty = NULL; + (void)pTrakAtom->FindProperty( + "trak.mdia.hdlr.handlerType", + (MP4Property**)&pTypeProperty); + + // ensure we have the basics properties + if (pTrackIdProperty && pTypeProperty) { + + m_trakIds.Add(pTrackIdProperty->GetValue()); + + MP4Track* pTrack = NULL; + try { + const char* value = pTypeProperty->GetValue(); + if (value && !strcmp(value, MP4_HINT_TRACK_TYPE)) { + pTrack = new MP4RtpHintTrack(this, pTrakAtom); + } else { + pTrack = new MP4Track(this, pTrakAtom); + } + m_pTracks.Add(pTrack); + } + catch (MP4Error* e) { + VERBOSE_ERROR(m_verbosity, e->Print()); + delete e; + } + + // remember when we encounter the OD track + const char* track = (pTrack ? pTrack->GetType() : 0); + if (pTrack && !strcmp(track, MP4_OD_TRACK_TYPE)) { + if (m_odTrackId == MP4_INVALID_TRACK_ID) { + m_odTrackId = pTrackIdProperty->GetValue(); + } else { + VERBOSE_READ(GetVerbosity(), + printf("Warning: multiple OD tracks present\n")); + } + } + } else { + m_trakIds.Add(0); + } + + trackIndex++; + } +} + +void MP4File::CacheProperties() +{ + FindIntegerProperty("moov.mvhd.modificationTime", + (MP4Property**)&m_pModificationProperty); + + FindIntegerProperty("moov.mvhd.timeScale", + (MP4Property**)&m_pTimeScaleProperty); + + FindIntegerProperty("moov.mvhd.duration", + (MP4Property**)&m_pDurationProperty); +} + +void MP4File::BeginWrite() +{ + m_pRootAtom->BeginWrite(); +} + +void MP4File::FinishWrite() +{ + // for all tracks, flush chunking buffers + for (u_int32_t i = 0; i < m_pTracks.Size(); i++) { + ASSERT(m_pTracks[i]); + m_pTracks[i]->FinishWrite(); + } + + // ask root atom to write + m_pRootAtom->FinishWrite(); + + // check if file shrunk, e.g. we deleted a track + if (GetSize() < m_orgFileSize) { + // just use a free atom to mark unused space + // MP4Optimize() should be used to clean up this space + MP4Atom* pFreeAtom = MP4Atom::CreateAtom("free"); + ASSERT(pFreeAtom); + pFreeAtom->SetFile(this); + int64_t size = m_orgFileSize - (m_fileSize + 8); + if (size < 0) size = 0; + pFreeAtom->SetSize(size); + pFreeAtom->Write(); + delete pFreeAtom; + } +} + +void MP4File::UpdateDuration(MP4Duration duration) +{ + MP4Duration currentDuration = GetDuration(); + if (duration > currentDuration) { + SetDuration(duration); + } +} + +void MP4File::Close() +{ + if (m_mode == 'w') { + SetIntegerProperty("moov.mvhd.modificationTime", + MP4GetAbsTimestamp()); + + FinishWrite(); + } + + m_virtual_IO->Close(m_pFile); + m_pFile = NULL; +} + +const MP4_FILENAME_CHAR* MP4File::TempFileName() +{ + // there are so many attempts in libc to get this right + // that for portablity reasons, it's best just to roll our own +#ifndef _WIN32 + u_int32_t i; + for (i = getpid(); i < 0xFFFFFFFF; i++) { + snprintf(m_tempFileName, sizeof(m_tempFileName), + "./tmp%u.mp4", i); + if (access(m_tempFileName, F_OK) != 0) { + break; + } + } + if (i == 0xFFFFFFFF) { + throw new MP4Error("can't create temporary file", "TempFileName"); + } +#else + wchar_t tmppath[MAX_PATH-14]; + GetTempPathW(MAX_PATH-14,tmppath); + GetTempFileNameW(tmppath, // dir. for temp. files + L"mp4", // temp. filename prefix + 0, // create unique name + m_tempFileName); // buffer for name +#endif + + return m_tempFileName; +} + +void MP4File::Rename(const MP4_FILENAME_CHAR* oldFileName, const MP4_FILENAME_CHAR* newFileName) +{ + int rc; + +#ifdef _WIN32 + rc=0; + DeleteFileW(newFileName); + if (MoveFileW(oldFileName,newFileName) == 0) // if the function fails + { + if (!CopyFileW(oldFileName,newFileName, FALSE)) + rc=1; + else + DeleteFileW(oldFileName); + } + /* benski> CUT: + rc = remove(newFileName); + if (rc == 0) { + rc = rename(oldFileName, newFileName); + } + */ +#else + rc = rename(oldFileName, newFileName); +#endif + if (rc != 0) { + throw new MP4Error(errno, "can't overwrite existing file", "Rename"); + } +} + +void MP4File::ProtectWriteOperation(char* where) +{ + if (m_mode == 'r') { + throw new MP4Error("operation not permitted in read mode", where); + } +} + +MP4Track* MP4File::GetTrack(MP4TrackId trackId) +{ + return m_pTracks[FindTrackIndex(trackId)]; +} + +MP4Atom* MP4File::FindAtomMP4File(const char* name) +{ + MP4Atom* pAtom = NULL; + if (!name || !strcmp(name, "")) { + pAtom = m_pRootAtom; + } else { + pAtom = m_pRootAtom->FindAtomMP4(name); + } + return pAtom; +} + +MP4Atom* MP4File::AddChildAtom( + const char* parentName, + const char* childName) +{ + return AddChildAtom(FindAtomMP4File(parentName), childName); +} + +MP4Atom* MP4File::AddChildAtom( + MP4Atom* pParentAtom, + const char* childName) +{ + return InsertChildAtom(pParentAtom, childName, + pParentAtom->GetNumberOfChildAtoms()); +} + +MP4Atom* MP4File::InsertChildAtom( + const char* parentName, + const char* childName, + u_int32_t index) +{ + return InsertChildAtom(FindAtomMP4File(parentName), childName, index); +} + +MP4Atom* MP4File::InsertChildAtom( + MP4Atom* pParentAtom, + const char* childName, + u_int32_t index) +{ + MP4Atom* pChildAtom = MP4Atom::CreateAtom(childName); + + ASSERT(pParentAtom); + pParentAtom->InsertChildAtom(pChildAtom, index); + + pChildAtom->Generate(); + + return pChildAtom; +} + +MP4Atom* MP4File::AddDescendantAtoms( + const char* ancestorName, + const char* descendantNames) +{ + return AddDescendantAtoms(FindAtomMP4File(ancestorName), descendantNames); +} + +MP4Atom* MP4File::AddDescendantAtoms( + MP4Atom* pAncestorAtom, const char* descendantNames) +{ + ASSERT(pAncestorAtom); + + MP4Atom* pParentAtom = pAncestorAtom; + MP4Atom* pChildAtom = NULL; + + while (true) { + char* childName = MP4NameFirst(descendantNames); + + if (childName == NULL) { + break; + } + + descendantNames = MP4NameAfterFirst(descendantNames); + + pChildAtom = pParentAtom->FindChildAtom(childName); + + if (pChildAtom == NULL) { + pChildAtom = AddChildAtom(pParentAtom, childName); + } + + pParentAtom = pChildAtom; + + MP4Free(childName); + } + + return pChildAtom; +} + +bool MP4File::FindProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex) +{ + if (pIndex) { + *pIndex = 0; // set the default answer for index + } + + return m_pRootAtom->FindProperty(name, ppProperty, pIndex); +} + +void MP4File::FindIntegerProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex) +{ + if (!FindProperty(name, ppProperty, pIndex)) { + throw new MP4Error("no such property - %s", "MP4File::FindIntegerProperty", name); + } + + switch ((*ppProperty)->GetType()) { + case Integer8Property: + case Integer16Property: + case Integer24Property: + case Integer32Property: + case Integer64Property: + break; + default: + throw new MP4Error("type mismatch - property %s type %d", "MP4File::FindIntegerProperty", name, (*ppProperty)->GetType()); + } +} + +u_int64_t MP4File::GetIntegerProperty(const char* name) +{ + MP4Property* pProperty; + u_int32_t index; + + FindIntegerProperty(name, &pProperty, &index); + + return ((MP4IntegerProperty*)pProperty)->GetValue(index); +} + +void MP4File::SetIntegerProperty(const char* name, u_int64_t value) +{ + ProtectWriteOperation("SetIntegerProperty"); + + MP4Property* pProperty = NULL; + u_int32_t index = 0; + + FindIntegerProperty(name, &pProperty, &index); + + ((MP4IntegerProperty*)pProperty)->SetValue(value, index); +} + +void MP4File::FindFloatProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex) +{ + if (!FindProperty(name, ppProperty, pIndex)) { + throw new MP4Error("no such property - %s", "MP4File::FindFloatProperty", name); + } + if ((*ppProperty)->GetType() != Float32Property) { + throw new MP4Error("type mismatch - property %s type %d", + "MP4File::FindFloatProperty", + name, + (*ppProperty)->GetType()); + } +} + +float MP4File::GetFloatProperty(const char* name) +{ + MP4Property* pProperty; + u_int32_t index; + + FindFloatProperty(name, &pProperty, &index); + + return ((MP4Float32Property*)pProperty)->GetValue(index); +} + +void MP4File::SetFloatProperty(const char* name, float value) +{ + ProtectWriteOperation("SetFloatProperty"); + + MP4Property* pProperty; + u_int32_t index; + + FindFloatProperty(name, &pProperty, &index); + + ((MP4Float32Property*)pProperty)->SetValue(value, index); +} + +void MP4File::FindStringProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex) +{ + if (!FindProperty(name, ppProperty, pIndex)) { + throw new MP4Error("no such property - %s", "MP4File::FindStringProperty", name); + } + if ((*ppProperty)->GetType() != StringProperty) { + throw new MP4Error("type mismatch - property %s type %d", "MP4File::FindStringProperty", + name, (*ppProperty)->GetType()); + } +} + +const char* MP4File::GetStringProperty(const char* name) +{ + MP4Property* pProperty; + u_int32_t index; + + FindStringProperty(name, &pProperty, &index); + + return ((MP4StringProperty*)pProperty)->GetValue(index); +} + +void MP4File::SetStringProperty(const char* name, const char* value) +{ + ProtectWriteOperation("SetStringProperty"); + + MP4Property* pProperty; + u_int32_t index; + + FindStringProperty(name, &pProperty, &index); + + ((MP4StringProperty*)pProperty)->SetValue(value, index); +} + +void MP4File::FindBytesProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex) +{ + if (!FindProperty(name, ppProperty, pIndex)) { + throw new MP4Error("no such property %s", "MP4File::FindBytesProperty", name); + } + if ((*ppProperty)->GetType() != BytesProperty) { + throw new MP4Error("type mismatch - property %s - type %d", "MP4File::FindBytesProperty", name, (*ppProperty)->GetType()); + } +} + +void MP4File::GetBytesProperty(const char* name, + u_int8_t** ppValue, u_int32_t* pValueSize) +{ + MP4Property* pProperty; + u_int32_t index; + + FindBytesProperty(name, &pProperty, &index); + + ((MP4BytesProperty*)pProperty)->GetValue(ppValue, pValueSize, index); +} + +void MP4File::SetBytesProperty(const char* name, + const u_int8_t* pValue, u_int32_t valueSize) +{ + ProtectWriteOperation("SetBytesProperty"); + + MP4Property* pProperty; + u_int32_t index; + + FindBytesProperty(name, &pProperty, &index); + + ((MP4BytesProperty*)pProperty)->SetValue(pValue, valueSize, index); +} + + +// track functions + +MP4TrackId MP4File::AddTrack(const char* type, u_int32_t timeScale) +{ + ProtectWriteOperation("AddTrack"); + + // create and add new trak atom + MP4Atom* pTrakAtom = AddChildAtom("moov", "trak"); + + // allocate a new track id + MP4TrackId trackId = AllocTrackId(); + + m_trakIds.Add(trackId); + + // set track id + MP4Integer32Property* pInteger32Property = NULL; + (void)pTrakAtom->FindProperty("trak.tkhd.trackId", + (MP4Property**)&pInteger32Property); + ASSERT(pInteger32Property); + pInteger32Property->SetValue(trackId); + + // set track type + const char* normType = MP4NormalizeTrackType(type, m_verbosity); + + // sanity check for user defined types + if (strlen(normType) > 4) { + VERBOSE_WARNING(m_verbosity, + printf("AddTrack: type truncated to four characters\n")); + // StringProperty::SetValue() will do the actual truncation + } + + MP4StringProperty* pStringProperty = NULL; + (void)pTrakAtom->FindProperty("trak.mdia.hdlr.handlerType", + (MP4Property**)&pStringProperty); + ASSERT(pStringProperty); + pStringProperty->SetValue(normType); + + // set track time scale + pInteger32Property = NULL; + (void)pTrakAtom->FindProperty("trak.mdia.mdhd.timeScale", + (MP4Property**)&pInteger32Property); + ASSERT(pInteger32Property); + pInteger32Property->SetValue(timeScale ? timeScale : 1000); + + // now have enough to create MP4Track object + MP4Track* pTrack = NULL; + if (!strcmp(normType, MP4_HINT_TRACK_TYPE)) { + pTrack = new MP4RtpHintTrack(this, pTrakAtom); + } else { + pTrack = new MP4Track(this, pTrakAtom); + } + m_pTracks.Add(pTrack); + + // mark non-hint tracks as enabled + if (strcmp(normType, MP4_HINT_TRACK_TYPE)) { + SetTrackIntegerProperty(trackId, "tkhd.flags", 1); + } + + // mark track as contained in this file + // LATER will provide option for external data references + AddDataReference(trackId, NULL); + + return trackId; +} + +void MP4File::AddTrackToIod(MP4TrackId trackId) +{ + MP4DescriptorProperty* pDescriptorProperty = NULL; + (void)m_pRootAtom->FindProperty("moov.iods.esIds", + (MP4Property**)&pDescriptorProperty); + ASSERT(pDescriptorProperty); + + MP4Descriptor* pDescriptor = + pDescriptorProperty->AddDescriptor(MP4ESIDIncDescrTag); + ASSERT(pDescriptor); + + MP4Integer32Property* pIdProperty = NULL; + (void)pDescriptor->FindProperty("id", + (MP4Property**)&pIdProperty); + ASSERT(pIdProperty); + + pIdProperty->SetValue(trackId); +} + + void MP4File::RemoveTrackFromIod(MP4TrackId trackId, bool shallHaveIods) +{ + MP4DescriptorProperty* pDescriptorProperty = NULL; + if (!m_pRootAtom->FindProperty("moov.iods.esIds", + (MP4Property**)&pDescriptorProperty)) + return; +#if 0 + // we may not have iods + if (shallHaveIods) { + ASSERT(pDescriptorProperty); + } else { + if (!pDescriptorProperty) { + return; + } + } +#else + if (pDescriptorProperty == NULL) { + return; + } +#endif + + for (u_int32_t i = 0; i < pDescriptorProperty->GetCount(); i++) { + /* static */char name[32]; + snprintf(name, sizeof(name), "esIds[%u].id", i); + + MP4Integer32Property* pIdProperty = NULL; + (void)pDescriptorProperty->FindProperty(name, + (MP4Property**)&pIdProperty); + // wmay ASSERT(pIdProperty); + + if (pIdProperty != NULL && + pIdProperty->GetValue() == trackId) { + pDescriptorProperty->DeleteDescriptor(i); + break; + } + } +} + +void MP4File::AddTrackToOd(MP4TrackId trackId) +{ + if (!m_odTrackId) { + return; + } + + AddTrackReference(MakeTrackName(m_odTrackId, "tref.mpod"), trackId); +} + +void MP4File::RemoveTrackFromOd(MP4TrackId trackId) +{ + if (!m_odTrackId) { + return; + } + + RemoveTrackReference(MakeTrackName(m_odTrackId, "tref.mpod"), trackId); +} + +void MP4File::GetTrackReferenceProperties(const char* trefName, + MP4Property** ppCountProperty, MP4Property** ppTrackIdProperty) +{ + char propName[1024]; + + snprintf(propName, sizeof(propName), "%s.%s", trefName, "entryCount"); + (void)m_pRootAtom->FindProperty(propName, ppCountProperty); + ASSERT(*ppCountProperty); + + snprintf(propName, sizeof(propName), "%s.%s", trefName, "entries.trackId"); + (void)m_pRootAtom->FindProperty(propName, ppTrackIdProperty); + ASSERT(*ppTrackIdProperty); +} + +void MP4File::AddTrackReference(const char* trefName, MP4TrackId refTrackId) +{ + MP4Integer32Property* pCountProperty = NULL; + MP4Integer32Property* pTrackIdProperty = NULL; + + GetTrackReferenceProperties(trefName, + (MP4Property**)&pCountProperty, + (MP4Property**)&pTrackIdProperty); + + pTrackIdProperty->AddValue(refTrackId); + pCountProperty->IncrementValue(); +} + +u_int32_t MP4File::FindTrackReference(const char* trefName, + MP4TrackId refTrackId) +{ + MP4Integer32Property* pCountProperty = NULL; + MP4Integer32Property* pTrackIdProperty = NULL; + + GetTrackReferenceProperties(trefName, + (MP4Property**)&pCountProperty, + (MP4Property**)&pTrackIdProperty); + + for (u_int32_t i = 0; i < pCountProperty->GetValue(); i++) { + if (refTrackId == pTrackIdProperty->GetValue(i)) { + return i + 1; // N.B. 1 not 0 based index + } + } + return 0; +} + +void MP4File::RemoveTrackReference(const char* trefName, MP4TrackId refTrackId) +{ + MP4Integer32Property* pCountProperty = NULL; + MP4Integer32Property* pTrackIdProperty = NULL; + + GetTrackReferenceProperties(trefName, + (MP4Property**)&pCountProperty, + (MP4Property**)&pTrackIdProperty); + + for (u_int32_t i = 0; i < pCountProperty->GetValue(); i++) { + if (refTrackId == pTrackIdProperty->GetValue(i)) { + pTrackIdProperty->DeleteValue(i); + pCountProperty->IncrementValue(-1); + } + } +} + +void MP4File::AddDataReference(MP4TrackId trackId, const char* url) +{ + MP4Atom* pDrefAtom = + FindAtomMP4File(MakeTrackName(trackId, "mdia.minf.dinf.dref")); + ASSERT(pDrefAtom); + + MP4Integer32Property* pCountProperty = NULL; + (void)pDrefAtom->FindProperty("dref.entryCount", + (MP4Property**)&pCountProperty); + ASSERT(pCountProperty); + pCountProperty->IncrementValue(); + + MP4Atom* pUrlAtom = AddChildAtom(pDrefAtom, "url "); + + if (url && url[0] != '\0') { + pUrlAtom->SetFlags(pUrlAtom->GetFlags() & 0xFFFFFE); + + MP4StringProperty* pUrlProperty = NULL; + (void)pUrlAtom->FindProperty("url .location", + (MP4Property**)&pUrlProperty); + ASSERT(pUrlProperty); + pUrlProperty->SetValue(url); + } else { + pUrlAtom->SetFlags(pUrlAtom->GetFlags() | 1); + } +} + +MP4TrackId MP4File::AddSystemsTrack(const char* type) +{ + const char* normType = MP4NormalizeTrackType(type, m_verbosity); + + // TBD if user type, fix name to four chars, and warn + + MP4TrackId trackId = AddTrack(type, MP4_MSECS_TIME_SCALE); + + (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "nmhd", 0); + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "mp4s"); + + // stsd is a unique beast in that it has a count of the number + // of child atoms that needs to be incremented after we add the mp4s atom + MP4Integer32Property* pStsdCountProperty; + FindIntegerProperty( + MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"), + (MP4Property**)&pStsdCountProperty); + pStsdCountProperty->IncrementValue(); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4s.esds.ESID", +#if 0 + // note - for a file, these values need to + // be 0 - wmay - 04/16/2003 + trackId +#else + 0 +#endif + ); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr.objectTypeId", + MP4SystemsV1ObjectType); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr.streamType", + ConvertTrackTypeToStreamType(normType)); + + return trackId; +} + +MP4TrackId MP4File::AddODTrack() +{ + // until a demonstrated need emerges + // we limit ourselves to one object description track + if (m_odTrackId != MP4_INVALID_TRACK_ID) { + throw new MP4Error("object description track already exists", + "AddObjectDescriptionTrack"); + } + + m_odTrackId = AddSystemsTrack(MP4_OD_TRACK_TYPE); + + AddTrackToIod(m_odTrackId); + + (void)AddDescendantAtoms(MakeTrackName(m_odTrackId, NULL), "tref.mpod"); + + return m_odTrackId; +} + +MP4TrackId MP4File::AddSceneTrack() +{ + MP4TrackId trackId = AddSystemsTrack(MP4_SCENE_TRACK_TYPE); + + AddTrackToIod(trackId); + AddTrackToOd(trackId); + + return trackId; +} + +// NULL terminated list of brands which require the IODS atom +char *brandsWithIods[] = { "mp42", + "isom", + NULL}; + +bool MP4File::ShallHaveIods() +{ + u_int32_t compatibleBrandsCount; + MP4StringProperty *pMajorBrandProperty; + + MP4Atom* ftypAtom = m_pRootAtom->FindAtomMP4("ftyp"); + if (ftypAtom == NULL) return false; + + // Check the major brand + (void)ftypAtom->FindProperty( + "ftyp.majorBrand", + (MP4Property**)&pMajorBrandProperty); + ASSERT(pMajorBrandProperty); + for(u_int32_t j = 0 ; brandsWithIods[j] != NULL ; j++) { + if (!strcasecmp( ((MP4StringProperty*)pMajorBrandProperty)->GetValue(), + brandsWithIods[j])) + return true; + } + + // Check the compatible brands + MP4Integer32Property* pCompatibleBrandsCountProperty; + (void)ftypAtom->FindProperty( + "ftyp.compatibleBrandsCount", + (MP4Property**)&pCompatibleBrandsCountProperty); + ASSERT(pCompatibleBrandsCountProperty); + + compatibleBrandsCount = pCompatibleBrandsCountProperty->GetValue(); + + MP4TableProperty* pCompatibleBrandsProperty; + (void)ftypAtom->FindProperty( + "ftyp.compatibleBrands", + (MP4Property**)&pCompatibleBrandsProperty); + + MP4StringProperty* pBrandProperty = (MP4StringProperty*)pCompatibleBrandsProperty->GetProperty(0); + ASSERT(pBrandProperty); + + for(u_int32_t i = 0 ; i < compatibleBrandsCount ; i++) { + for(u_int32_t j = 0 ; brandsWithIods[j] != NULL ; j++) { + if (!strcasecmp(pBrandProperty->GetValue(i), brandsWithIods[j])) + return true; + } + } + + return false; +} + +void MP4File::SetAmrVendor( + MP4TrackId trackId, + u_int32_t vendor) +{ + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.damr.vendor", + vendor); +} + +void MP4File::SetAmrDecoderVersion( + MP4TrackId trackId, + u_int8_t decoderVersion) +{ + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.damr.decoderVersion", + decoderVersion); +} + +void MP4File::SetAmrModeSet( + MP4TrackId trackId, + u_int16_t modeSet) +{ + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.damr.modeSet", + modeSet); +} +uint16_t MP4File::GetAmrModeSet(MP4TrackId trackId) +{ + return GetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.damr.modeSet"); +} + +MP4TrackId MP4File::AddAmrAudioTrack( + u_int32_t timeScale, + u_int16_t modeSet, + u_int8_t modeChangePeriod, + u_int8_t framesPerSample, + bool isAmrWB) +{ + + u_int32_t fixedSampleDuration = (timeScale * 20)/1000; // 20mSec/Sample + + MP4TrackId trackId = AddTrack(MP4_AUDIO_TRACK_TYPE, timeScale); + + AddTrackToOd(trackId); + + SetTrackFloatProperty(trackId, "tkhd.volume", 1.0); + + (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "smhd", 0); + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), isAmrWB ? "sawb" : "samr"); + + // stsd is a unique beast in that it has a count of the number + // of child atoms that needs to be incremented after we add the mp4a atom + MP4Integer32Property* pStsdCountProperty; + FindIntegerProperty( + MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"), + (MP4Property**)&pStsdCountProperty); + pStsdCountProperty->IncrementValue(); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.timeScale", + timeScale); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.damr.modeSet", + modeSet); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.damr.modeChangePeriod", + modeChangePeriod); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.damr.framesPerSample", + framesPerSample); + + + m_pTracks[FindTrackIndex(trackId)]-> + SetFixedSampleDuration(fixedSampleDuration); + + return trackId; +} + +MP4TrackId MP4File::AddAudioTrack( + u_int32_t timeScale, + MP4Duration sampleDuration, + u_int8_t audioType) +{ + MP4TrackId trackId = AddTrack(MP4_AUDIO_TRACK_TYPE, timeScale); + + AddTrackToOd(trackId); + + SetTrackFloatProperty(trackId, "tkhd.volume", 1.0); + + (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "smhd", 0); + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "mp4a"); + + // stsd is a unique beast in that it has a count of the number + // of child atoms that needs to be incremented after we add the mp4a atom + MP4Integer32Property* pStsdCountProperty; + FindIntegerProperty( + MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"), + (MP4Property**)&pStsdCountProperty); + pStsdCountProperty->IncrementValue(); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4a.timeScale", timeScale); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4a.esds.ESID", +#if 0 + // note - for a file, these values need to + // be 0 - wmay - 04/16/2003 + trackId +#else + 0 +#endif + ); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4a.esds.decConfigDescr.objectTypeId", + audioType); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4a.esds.decConfigDescr.streamType", + MP4AudioStreamType); + + m_pTracks[FindTrackIndex(trackId)]-> + SetFixedSampleDuration(sampleDuration); + + return trackId; +} + +MP4TrackId MP4File::AddEncAudioTrack(u_int32_t timeScale, + MP4Duration sampleDuration, + u_int8_t audioType, + u_int32_t scheme_type, + u_int16_t scheme_version, + u_int8_t key_ind_len, + u_int8_t iv_len, + bool selective_enc, + const char *kms_uri, + bool use_ismacryp + ) +{ + u_int32_t original_fmt = 0; + + MP4TrackId trackId = AddTrack(MP4_AUDIO_TRACK_TYPE, timeScale); + + AddTrackToOd(trackId); + + SetTrackFloatProperty(trackId, "tkhd.volume", 1.0); + + (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "smhd", 0); + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "enca"); + + // stsd is a unique beast in that it has a count of the number + // of child atoms that needs to be incremented after we add the enca atom + MP4Integer32Property* pStsdCountProperty; + FindIntegerProperty(MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"), + (MP4Property**)&pStsdCountProperty); + pStsdCountProperty->IncrementValue(); + + + /* set all the ismacryp-specific values */ + // original format is mp4a + if (use_ismacryp) { + original_fmt = ATOMID("mp4a"); + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.enca.sinf.frma.data-format", + original_fmt); + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.enca.sinf"), + "schm"); + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.enca.sinf"), + "schi"); + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.enca.sinf.schi"), + "iKMS"); + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.enca.sinf.schi"), + "iSFM"); + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.enca.sinf.schm.scheme_type", + scheme_type); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.enca.sinf.schm.scheme_version", + scheme_version); + + SetTrackStringProperty(trackId, + "mdia.minf.stbl.stsd.enca.sinf.schi.iKMS.kms_URI", + kms_uri); + #if 0 + if (kms_uri != NULL) { + free((void *)kms_uri); + } + #endif + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.enca.sinf.schi.iSFM.selective-encryption", + selective_enc); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.enca.sinf.schi.iSFM.key-indicator-length", + key_ind_len); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.enca.sinf.schi.iSFM.IV-length", + iv_len); + /* end ismacryp */ + } + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.enca.timeScale", timeScale); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.enca.esds.ESID", +#if 0 + // note - for a file, these values need to + // be 0 - wmay - 04/16/2003 + trackId +#else + 0 +#endif + ); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.enca.esds.decConfigDescr.objectTypeId", + audioType); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.enca.esds.decConfigDescr.streamType", + MP4AudioStreamType); + + m_pTracks[FindTrackIndex(trackId)]-> + SetFixedSampleDuration(sampleDuration); + + return trackId; +} + +MP4TrackId MP4File::AddCntlTrackDefault (uint32_t timeScale, + MP4Duration sampleDuration, + const char *type) +{ + MP4TrackId trackId = AddTrack(MP4_CNTL_TRACK_TYPE, timeScale); + + (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "nmhd", 0); + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), type); + + // stsd is a unique beast in that it has a count of the number + // of child atoms that needs to be incremented after we add the mp4v atom + MP4Integer32Property* pStsdCountProperty; + FindIntegerProperty( + MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"), + (MP4Property**)&pStsdCountProperty); + pStsdCountProperty->IncrementValue(); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsz.sampleSize", sampleDuration); + + m_pTracks[FindTrackIndex(trackId)]-> + SetFixedSampleDuration(sampleDuration); + + return trackId; +} + +MP4TrackId MP4File::AddHrefTrack (uint32_t timeScale, + MP4Duration sampleDuration, + const char *base_url) +{ + MP4TrackId trackId = AddCntlTrackDefault(timeScale, sampleDuration, "href"); + + if (base_url != NULL) { + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.href"), + "burl"); + SetTrackStringProperty(trackId, "mdia.minf.stbl.stsd.href.burl.base_url", + base_url); + } + + return trackId; +} + +MP4TrackId MP4File::AddVideoTrackDefault( + u_int32_t timeScale, + MP4Duration sampleDuration, + u_int16_t width, + u_int16_t height, + const char *videoType) +{ + MP4TrackId trackId = AddTrack(MP4_VIDEO_TRACK_TYPE, timeScale); + + AddTrackToOd(trackId); + + SetTrackFloatProperty(trackId, "tkhd.width", width); + SetTrackFloatProperty(trackId, "tkhd.height", height); + + (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "vmhd", 0); + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), videoType); + + // stsd is a unique beast in that it has a count of the number + // of child atoms that needs to be incremented after we add the mp4v atom + MP4Integer32Property* pStsdCountProperty; + FindIntegerProperty( + MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"), + (MP4Property**)&pStsdCountProperty); + pStsdCountProperty->IncrementValue(); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsz.sampleSize", sampleDuration); + + m_pTracks[FindTrackIndex(trackId)]-> + SetFixedSampleDuration(sampleDuration); + + return trackId; +} +MP4TrackId MP4File::AddMP4VideoTrack( + u_int32_t timeScale, + MP4Duration sampleDuration, + u_int16_t width, + u_int16_t height, + u_int8_t videoType) +{ + MP4TrackId trackId = AddVideoTrackDefault(timeScale, + sampleDuration, + width, + height, + "mp4v"); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4v.width", width); + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4v.height", height); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4v.esds.ESID", +#if 0 + // note - for a file, these values need to + // be 0 - wmay - 04/16/2003 + trackId +#else + 0 +#endif + ); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4v.esds.decConfigDescr.objectTypeId", + videoType); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4v.esds.decConfigDescr.streamType", + MP4VisualStreamType); + + return trackId; +} + +// ismacrypted +MP4TrackId MP4File::AddEncVideoTrack(u_int32_t timeScale, + MP4Duration sampleDuration, + u_int16_t width, + u_int16_t height, + u_int8_t videoType, + mp4v2_ismacrypParams *icPp, + const char *oFormat + ) +{ + u_int32_t original_fmt = 0; + + MP4TrackId trackId = AddVideoTrackDefault(timeScale, + sampleDuration, + width, + height, + "encv"); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.encv.width", width); + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.encv.height", height); + + /* set all the ismacryp-specific values */ + + original_fmt = ATOMID(oFormat); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.encv.sinf.frma.data-format", + original_fmt); + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.sinf"), + "schm"); + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.sinf"), + "schi"); + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.sinf.schi"), + "iKMS"); + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.sinf.schi"), + "iSFM"); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.encv.sinf.schm.scheme_type", + icPp->scheme_type); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.encv.sinf.schm.scheme_version", + icPp->scheme_version); + + SetTrackStringProperty(trackId, + "mdia.minf.stbl.stsd.encv.sinf.schi.iKMS.kms_URI", + icPp->kms_uri); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.encv.sinf.schi.iSFM.selective-encryption", + icPp->selective_enc); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.encv.sinf.schi.iSFM.key-indicator-length", + icPp->key_ind_len); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.encv.sinf.schi.iSFM.IV-length", + icPp->iv_len); + + #if 0 + if (icPp->kms_uri != NULL) { + free(icPp->kms_uri); + } + #endif + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.encv.esds.ESID", +#if 0 + // note - for a file, these values need to + // be 0 - wmay - 04/16/2003 + trackId +#else + 0 +#endif + ); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.encv.esds.decConfigDescr.objectTypeId", + videoType); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.encv.esds.decConfigDescr.streamType", + MP4VisualStreamType); + + return trackId; +} + +MP4TrackId MP4File::AddH264VideoTrack( + u_int32_t timeScale, + MP4Duration sampleDuration, + u_int16_t width, + u_int16_t height, + uint8_t AVCProfileIndication, + uint8_t profile_compat, + uint8_t AVCLevelIndication, + uint8_t sampleLenFieldSizeMinusOne) +{ + MP4TrackId trackId = AddVideoTrackDefault(timeScale, + sampleDuration, + width, + height, + "avc1"); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.avc1.width", width); + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.avc1.height", height); + + //FIXME - check this + // shouldn't need this + #if 0 + AddChildAtom(MakeTrackName(trackId, + "mdia.minf.stbl.stsd.avc1"), + "avcC"); + #endif + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.avc1.avcC.AVCProfileIndication", + AVCProfileIndication); + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.avc1.avcC.profile_compatibility", + profile_compat); + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.avc1.avcC.AVCLevelIndication", + AVCLevelIndication); + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.avc1.avcC.lengthSizeMinusOne", + sampleLenFieldSizeMinusOne); + + + return trackId; +} + +MP4TrackId MP4File::AddEncH264VideoTrack( + u_int32_t timeScale, + MP4Duration sampleDuration, + u_int16_t width, + u_int16_t height, + MP4Atom *srcAtom, + mp4v2_ismacrypParams *icPp) + +{ + + u_int32_t original_fmt = 0; + MP4Atom *avcCAtom; + + MP4TrackId trackId = AddVideoTrackDefault(timeScale, + sampleDuration, + width, + height, + "encv"); + + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.encv.width", width); + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.encv.height", height); + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv"), "avcC"); + + // create default values + avcCAtom = FindAtomMP4File(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.avcC")); + + // export source atom + ((MP4AvcCAtom *) srcAtom)->Clone((MP4AvcCAtom *)avcCAtom); + + /* set all the ismacryp-specific values */ + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.sinf"), "schm"); + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.sinf"), "schi"); + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.sinf.schi"), "iKMS"); + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.sinf.schi"), "iSFM"); + + // per ismacrypt E&A V1.1 section 9.1.2.1 'avc1' is renamed '264b' + // avc1 must not appear as a sample entry name or original format name + original_fmt = ATOMID("264b"); + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.encv.sinf.frma.data-format", + original_fmt); + + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.encv.sinf.schm.scheme_type", + icPp->scheme_type); + + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.encv.sinf.schm.scheme_version", + icPp->scheme_version); + + SetTrackStringProperty(trackId, "mdia.minf.stbl.stsd.encv.sinf.schi.iKMS.kms_URI", + icPp->kms_uri); + + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.encv.sinf.schi.iSFM.selective-encryption", + icPp->selective_enc); + + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.encv.sinf.schi.iSFM.key-indicator-length", + icPp->key_ind_len); + + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.encv.sinf.schi.iSFM.IV-length", + icPp->iv_len); + + + return trackId; +} + + +void MP4File::AddH264SequenceParameterSet (MP4TrackId trackId, + const uint8_t *pSequence, + uint16_t sequenceLen) +{ + const char *format; + MP4Atom *avcCAtom; + + // get 4cc media format - can be avc1 or encv for ismacrypted track + format = GetTrackMediaDataName(trackId); + + if (!strcasecmp(format, "avc1")) + avcCAtom = FindAtomMP4File(MakeTrackName(trackId, "mdia.minf.stbl.stsd.avc1.avcC")); + else if (!strcasecmp(format, "encv")) + avcCAtom = FindAtomMP4File(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.avcC")); + else + // huh? unknown track format + return; + + + MP4BitfieldProperty *pCount; + MP4Integer16Property *pLength; + MP4BytesProperty *pUnit; + if ((avcCAtom->FindProperty("avcC.numOfSequenceParameterSets", + (MP4Property **)&pCount) == false) || + (avcCAtom->FindProperty("avcC.sequenceEntries.sequenceParameterSetLength", + (MP4Property **)&pLength) == false) || + (avcCAtom->FindProperty("avcC.sequenceEntries.sequenceParameterSetNALUnit", + (MP4Property **)&pUnit) == false)) { + VERBOSE_ERROR(m_verbosity, WARNING("Could not find avcC properties")); + return; + } + uint32_t count = pCount->GetValue(); + + if (count > 0) { + // see if we already exist + for (uint32_t index = 0; index < count; index++) { + if (pLength->GetValue(index) == sequenceLen) { + uint8_t *seq; + uint32_t seqlen; + pUnit->GetValue(&seq, &seqlen, index); + if (memcmp(seq, pSequence, sequenceLen) == 0) { + free(seq); + return; + } + free(seq); + } + } + } + pLength->AddValue(sequenceLen); + pUnit->AddValue(pSequence, sequenceLen); + pCount->IncrementValue(); + + return; +} +void MP4File::AddH264PictureParameterSet (MP4TrackId trackId, + const uint8_t *pPict, + uint16_t pictLen) +{ + MP4Atom *avcCAtom = + FindAtomMP4File(MakeTrackName(trackId, + "mdia.minf.stbl.stsd.avc1.avcC")); + MP4Integer8Property *pCount; + MP4Integer16Property *pLength; + MP4BytesProperty *pUnit; + if ((avcCAtom->FindProperty("avcC.numOfPictureParameterSets", + (MP4Property **)&pCount) == false) || + (avcCAtom->FindProperty("avcC.pictureEntries.pictureParameterSetLength", + (MP4Property **)&pLength) == false) || + (avcCAtom->FindProperty("avcC.pictureEntries.pictureParameterSetNALUnit", + (MP4Property **)&pUnit) == false)) { + VERBOSE_ERROR(m_verbosity, + WARNING("Could not find avcC picture table properties")); + return; + } + uint32_t count = pCount->GetValue(); + + if (count > 0) { + // see if we already exist + for (uint32_t index = 0; index < count; index++) { + if (pLength->GetValue(index) == pictLen) { + uint8_t *seq; + uint32_t seqlen; + pUnit->GetValue(&seq, &seqlen, index); + if (memcmp(seq, pPict, pictLen) == 0) { + VERBOSE_WRITE(m_verbosity, + fprintf(stderr, "picture matches %d\n", index)); + free(seq); + return; + } + free(seq); + } + } + } + pLength->AddValue(pictLen); + pUnit->AddValue(pPict, pictLen); + pCount->IncrementValue(); + VERBOSE_WRITE(m_verbosity, + fprintf(stderr, "new picture added %d\n", pCount->GetValue())); + + return; +} +void MP4File::SetH263Vendor( + MP4TrackId trackId, + u_int32_t vendor) +{ + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.s263.d263.vendor", + vendor); +} + +void MP4File::SetH263DecoderVersion( + MP4TrackId trackId, + u_int8_t decoderVersion) +{ + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.s263.d263.decoderVersion", + decoderVersion); +} + +void MP4File::SetH263Bitrates( + MP4TrackId trackId, + u_int32_t avgBitrate, + u_int32_t maxBitrate) +{ + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.s263.d263.bitr.avgBitrate", + avgBitrate); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.s263.d263.bitr.maxBitrate", + maxBitrate); + +} + +MP4TrackId MP4File::AddH263VideoTrack( + u_int32_t timeScale, + MP4Duration sampleDuration, + u_int16_t width, + u_int16_t height, + u_int8_t h263Level, + u_int8_t h263Profile, + u_int32_t avgBitrate, + u_int32_t maxBitrate) + +{ + MP4TrackId trackId = AddVideoTrackDefault(timeScale, + sampleDuration, + width, + height, + "s263"); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.s263.width", width); + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.s263.height", height); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.s263.d263.h263Level", h263Level); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.s263.d263.h263Profile", h263Profile); + + // Add the bitr atom + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.s263.d263"), + "bitr"); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.s263.d263.bitr.avgBitrate", avgBitrate); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.s263.d263.bitr.maxBitrate", maxBitrate); + + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsz.sampleSize", sampleDuration); + + return trackId; + +} + +MP4TrackId MP4File::AddHintTrack(MP4TrackId refTrackId) +{ + // validate reference track id + (void)FindTrackIndex(refTrackId); + + MP4TrackId trackId = + AddTrack(MP4_HINT_TRACK_TYPE, GetTrackTimeScale(refTrackId)); + + (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "hmhd", 0); + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "rtp "); + + // stsd is a unique beast in that it has a count of the number + // of child atoms that needs to be incremented after we add the rtp atom + MP4Integer32Property* pStsdCountProperty; + FindIntegerProperty( + MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"), + (MP4Property**)&pStsdCountProperty); + pStsdCountProperty->IncrementValue(); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.rtp .tims.timeScale", + GetTrackTimeScale(trackId)); + + (void)AddDescendantAtoms(MakeTrackName(trackId, NULL), "tref.hint"); + + AddTrackReference(MakeTrackName(trackId, "tref.hint"), refTrackId); + + (void)AddDescendantAtoms(MakeTrackName(trackId, NULL), "udta.hnti.sdp "); + + (void)AddDescendantAtoms(MakeTrackName(trackId, NULL), "udta.hinf"); + + return trackId; +} + +MP4TrackId MP4File::AddTextTrack(MP4TrackId refTrackId) +{ + // validate reference track id + (void)FindTrackIndex(refTrackId); + + MP4TrackId trackId = + AddTrack(MP4_TEXT_TRACK_TYPE, GetTrackTimeScale(refTrackId)); + + (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "gmhd", 0); + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "text"); + + // stsd is a unique beast in that it has a count of the number + // of child atoms that needs to be incremented after we add the text atom + MP4Integer32Property* pStsdCountProperty; + FindIntegerProperty( + MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"), + (MP4Property**)&pStsdCountProperty); + pStsdCountProperty->IncrementValue(); + + return trackId; +} + +MP4TrackId MP4File::AddChapterTextTrack(MP4TrackId refTrackId, u_int32_t timescale) +{ + // validate reference track id + (void)FindTrackIndex(refTrackId); + + if (0 == timescale) { + timescale = GetTrackTimeScale(refTrackId); + } + + MP4TrackId trackId = AddTrack(MP4_TEXT_TRACK_TYPE, timescale); + + (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "gmhd", 0); + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "text"); + + // stsd is a unique beast in that it has a count of the number + // of child atoms that needs to be incremented after we add the text atom + MP4Integer32Property* pStsdCountProperty; + FindIntegerProperty( + MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"), + (MP4Property**)&pStsdCountProperty); + pStsdCountProperty->IncrementValue(); + + // add a "text" atom to the generic media header + // this is different to the stsd "text" atom added above + // truth be told, it's not clear what this second "text" atom does, + // but all iTunes Store movies (with chapter markers) have it, + // as do all movies with chapter tracks made by hand in QuickTime Pro + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.gmhd"), "text"); + + // disable the chapter text track + // it won't display anyway, as it has zero display size, + // but nonetheless it's good to disable it + // the track still operates as a chapter track when disabled + MP4Atom *pTkhdAtom = FindAtomMP4File(MakeTrackName(trackId, "tkhd")); + if (pTkhdAtom) { + pTkhdAtom->SetFlags(0xE); + } + + // add a "chapter" track reference to our reference track, + // pointing to this new chapter track + (void)AddDescendantAtoms(MakeTrackName(refTrackId, NULL), "tref.chap"); + AddTrackReference(MakeTrackName(refTrackId, "tref.chap"), trackId); + + return trackId; +} + + +void MP4File::AddChapter(MP4TrackId chapterTrackId, MP4Duration chapterDuration, u_int32_t chapterNr, const char * chapterTitle) +{ + if (0 == chapterTrackId) { + throw new MP4Error("No chapter track given","AddChapter"); + } + + uint32_t sampleLength = 0; + uint8_t sample[1040] = {0}; + int stringLen = 0; + char *string = (char *)&(sample[2]); + + if( chapterTitle != NULL ) + { + stringLen = (int)strlen(chapterTitle); + strncpy( string, chapterTitle, MIN(stringLen, 1023) ); + } + + if( stringLen == 0 || stringLen >= 1024 ) + { + snprintf( string, 1023, "Chapter %03i", chapterNr ); + stringLen = (int)strlen(string); + } + + sampleLength = stringLen + 2 + 12; // Account for text length code and other marker + + // 2-byte length marker + sample[0] = (stringLen >> 8) & 0xff; + sample[1] = stringLen & 0xff; + + int x = 2 + stringLen; + + // Modifier Length Marker + sample[x] = 0x00; + sample[x+1] = 0x00; + sample[x+2] = 0x00; + sample[x+3] = 0x0C; + + // Modifier Type Code + sample[x+4] = 'e'; + sample[x+5] = 'n'; + sample[x+6] = 'c'; + sample[x+7] = 'd'; + + // Modifier Value + sample[x+8] = 0x00; + sample[x+9] = 0x00; + sample[x+10] = (256 >> 8) & 0xff; + sample[x+11] = 256 & 0xff; + + WriteSample(chapterTrackId, sample, sampleLength, chapterDuration); +} + +void MP4File::AddChapter(MP4Timestamp chapterStart, const char * chapterTitle) +{ + MP4Atom * pChpl = FindAtomMP4File("moov.udta.chpl"); + if (!pChpl) { + pChpl = AddDescendantAtoms("", "moov.udta.chpl"); + } + + char buffer[256]; + int bufferLen = 0; + + MP4Integer32Property * pCount = (MP4Integer32Property*)pChpl->GetProperty(3); + pCount->IncrementValue(); + u_int32_t count = pCount->GetValue(); + + if (0 == chapterTitle) { + snprintf( buffer, 255, "Chapter %03i", count ); + } else { + int len = MIN(255, (int)strlen(chapterTitle)); + strncpy( buffer, chapterTitle, len ); + buffer[len] = 0; + } + bufferLen = (int)strlen(buffer); + + MP4TableProperty * pTable; + if (pChpl->FindProperty("chpl.chapters", (MP4Property **)&pTable)) { + MP4Integer64Property * pStartTime = (MP4Integer64Property *) pTable->GetProperty(0); + MP4StringProperty * pName = (MP4StringProperty *) pTable->GetProperty(1); + if (pStartTime && pTable) { + pStartTime->AddValue(chapterStart); + pName->AddValue(buffer); + } + } +} + +void MP4File::ConvertChapters(boolean toQT) +{ + if (toQT) { + MP4Chapters_t * chapters = 0; + u_int32_t chapterCount = 0; + const char * name = 0; + MP4Duration chapterDurationSum = 0; + + GetChaptersList(&chapters, &chapterCount, false); + if (0 == chapterCount) { + throw new MP4Error("Could not find chapter markers", "ConvertChapters"); + } + + // remove chapter track if there is an existing one + DeleteChapters(); + + // create the chapter track + MP4TrackId refTrack = FindTrackId(0, MP4_AUDIO_TRACK_TYPE); + MP4TrackId chapterTrack = AddChapterTextTrack(refTrack, MP4_MILLISECONDS_TIME_SCALE); + + // calculate the duration of the chapter track + MP4Duration chapterTrackDuration = MP4ConvertTime(GetTrackDuration(refTrack), + GetTrackTimeScale(refTrack), + MP4_MILLISECONDS_TIME_SCALE); + + for (u_int32_t chapterIndex = 0 ; chapterIndex < chapterCount; ++chapterIndex) { + // calculate the duration + MP4Duration duration = chapters[chapterIndex].duration; + + // sum up the chapter duration + chapterDurationSum += duration; + + // create and write the chapter track sample for the previous chapter + AddChapter( chapterTrack, duration, chapterIndex+1, chapters[chapterIndex].title ); + } + + MP4Free(chapters); + } else { + MP4Chapters_t * chapters = 0; + u_int32_t chapterCount = 0; + + GetChaptersList(&chapters, &chapterCount); + if (0 == chapterCount) { + throw new MP4Error("Could not find chapter markers", "ConvertChapters"); + } + + // remove existing chapters + DeleteChapters(0, false); + + MP4Duration startTime = 0; + for (u_int32_t i = 0; i < chapterCount; ++i) { + const char * title = chapters[i].title; + MP4Duration duration = chapters[i].duration; + + AddChapter(startTime, title); + startTime += duration * MILLI2HUNDREDNANO; + } + + MP4Free(chapters); + } +} + +void MP4File::DeleteChapters(MP4TrackId chapterTrackId, boolean deleteQT) +{ + if (!deleteQT) { + MP4Atom * pChpl = FindAtomMP4File("moov.udta.chpl"); + if (pChpl) { + MP4Atom * pParent = pChpl->GetParentAtom(); + pParent->DeleteChildAtom(pChpl); + } + return; + } + + char trackName[128] = {0}; + + // no text track given, find a suitable + if (0 == chapterTrackId) { + chapterTrackId = FindChapterTrack(trackName, 127); + } else { + FindChapterReferenceTrack(chapterTrackId, trackName, 127); + } + + if (0 != chapterTrackId && 0 != trackName[0]) { + // remove the reference + RemoveTrackReference(trackName, chapterTrackId); + + // remove the chapter track + DeleteTrack(chapterTrackId); + } +} + +void MP4File::GetChaptersList(MP4Chapters_t ** chapterList, + u_int32_t * chapterCount, + boolean getQT) +{ + *chapterList = 0; + *chapterCount = 0; + + if (!getQT) { + MP4Atom * pChpl = FindAtomMP4File("moov.udta.chpl"); + if (!pChpl) { + throw new MP4Error("Atom moov.udta.chpl does not exist ", "GetChaptersList"); + } + + MP4Integer32Property * pCounter = 0; + MP4TableProperty * pTable = 0; + MP4Integer64Property * pStartTime = 0; + MP4StringProperty * pName = 0; + MP4Duration chapterDurationSum = 0; + const char * name = 0; + + if (!pChpl->FindProperty("chpl.chaptercount", (MP4Property **)&pCounter)) { + throw new MP4Error("Chapter count does not exist ", "GetChaptersList"); + } + + u_int32_t counter = pCounter->GetValue(); + if (0 == counter) { + return; + } + + if (!pChpl->FindProperty("chpl.chapters", (MP4Property **)&pTable)) { + throw new MP4Error("Chapter list does not exist ", "GetChaptersList"); + } + + if (0 == (pStartTime = (MP4Integer64Property *) pTable->GetProperty(0))) { + throw new MP4Error("List of Chapter starttimes does not exist ", "GetChaptersList"); + } + if (0 == (pName = (MP4StringProperty *) pTable->GetProperty(1))) { + throw new MP4Error("List of Chapter titles does not exist ", "GetChaptersList"); + } + + MP4Chapters_t * chapters = (MP4Chapters_t*)MP4Malloc(sizeof(MP4Chapters_t) * counter); + + // get the name of the first chapter + name = pName->GetValue(); + + // process remaining chapters + u_int32_t i, j; + for (i = 0, j = 1; i < counter; ++i, ++j) { + // insert the chapter title + u_int32_t len = MIN((u_int32_t)strlen(name), CHAPTERTITLELEN); + strncpy(chapters[i].title, name, len); + chapters[i].title[len] = 0; + + // calculate the duration + MP4Duration duration = 0; + if (j < counter) { + duration = MP4ConvertTime(pStartTime->GetValue(j), + (MP4_NANOSECONDS_TIME_SCALE / 100), + MP4_MILLISECONDS_TIME_SCALE) - chapterDurationSum; + + // now get the name of the chapter (to be written next) + name = pName->GetValue(j); + } else { + // last chapter + duration = MP4ConvertTime(GetDuration(), GetTimeScale(), MP4_MILLISECONDS_TIME_SCALE) - chapterDurationSum; + } + + // sum up the chapter duration + chapterDurationSum += duration; + + // insert the chapter duration + chapters[i].duration = duration; + } + + *chapterList = chapters; + *chapterCount = counter; + + // ok, we're done + return; + } + + + u_int8_t * sample = 0; + u_int32_t sampleSize = 0; + MP4Timestamp startTime = 0; + MP4Duration duration = 0; + + // get the chapter track + MP4TrackId chapterTrackId = FindChapterTrack(); + if (0 == chapterTrackId) { + throw new MP4Error("Could not find a chapter track", "GetChaptersList"); + } + + // get infos about the chapters + MP4Track * pChapterTrack = GetTrack(chapterTrackId); + u_int32_t counter = pChapterTrack->GetNumberOfSamples(); + u_int32_t timescale = pChapterTrack->GetTimeScale(); + + MP4Chapters_t * chapters = (MP4Chapters_t*)MP4Malloc(sizeof(MP4Chapters_t) * counter); + + // process all chapter sample + for (u_int32_t i = 0; i < counter; ++i) { + // get the sample corresponding to the starttime + MP4SampleId sampleId = pChapterTrack->GetSampleIdFromTime(startTime + duration, true); + pChapterTrack->ReadSample(sampleId, &sample, &sampleSize); + + // get the starttime and duration + pChapterTrack->GetSampleTimes(sampleId, &startTime, &duration); + + // we know that sample+2 contains the title + const char * title = (const char *)&(sample[2]); + int len = MIN((int)strlen(title), CHAPTERTITLELEN); + strncpy(chapters[i].title, title, len); + chapters[i].title[len] = 0; + + // write the duration (in milliseconds) + chapters[i].duration = MP4ConvertTime(duration, timescale, MP4_MILLISECONDS_TIME_SCALE); + + // we're done with this sample + MP4Free(sample); + sample = 0; + } + + *chapterList = chapters; + *chapterCount = counter; +} + +MP4TrackId MP4File::FindChapterTrack(char * trackName, int trackNameSize) +{ + for (u_int32_t i = 0; i < m_pTracks.Size(); i++) { + if (!strcmp(MP4_TEXT_TRACK_TYPE, m_pTracks[i]->GetType())) { + MP4TrackId refTrackId = FindChapterReferenceTrack(m_pTracks[i]->GetId(), trackName, trackNameSize); + if (0 != refTrackId) { + return m_pTracks[i]->GetId(); + } + } + } + return 0; +} + +MP4TrackId MP4File::FindChapterReferenceTrack(MP4TrackId chapterTrackId, char * trackName, size_t trackNameSize) +{ + for (u_int32_t i = 0; i < m_pTracks.Size(); i++) { + if (!strcmp(MP4_AUDIO_TRACK_TYPE, m_pTracks[i]->GetType())) { + MP4TrackId refTrackId = m_pTracks[i]->GetId(); + char * name = MakeTrackName(refTrackId, "tref.chap"); + if (FindTrackReference(name, chapterTrackId)) { + if (0 != trackName) { + strncpy(trackName, name, MIN(strlen(name),trackNameSize)); + } + return m_pTracks[i]->GetId(); + } + } + } + return 0; +} + + +void MP4File::DeleteTrack(MP4TrackId trackId) +{ + ProtectWriteOperation("MP4DeleteTrack"); + + u_int32_t trakIndex = FindTrakAtomIndex(trackId); + u_int16_t trackIndex = FindTrackIndex(trackId); + MP4Track* pTrack = m_pTracks[trackIndex]; + + MP4Atom* pTrakAtom = pTrack->GetTrakAtom(); + ASSERT(pTrakAtom); + + MP4Atom* pMoovAtom = FindAtomMP4File("moov"); + ASSERT(pMoovAtom); + + RemoveTrackFromIod(trackId, ShallHaveIods()); + RemoveTrackFromOd(trackId); + + if (trackId == m_odTrackId) { + m_odTrackId = 0; + } + + pMoovAtom->DeleteChildAtom(pTrakAtom); + + m_trakIds.Delete(trakIndex); + + m_pTracks.Delete(trackIndex); + + delete pTrack; + delete pTrakAtom; +} + +u_int32_t MP4File::GetNumberOfTracks(const char* type, u_int8_t subType) +{ + if (type == NULL) { + return m_pTracks.Size(); + } + + u_int32_t typeSeen = 0; + const char* normType = MP4NormalizeTrackType(type, m_verbosity); + + for (u_int32_t i = 0; i < m_pTracks.Size(); i++) { + if (!strcmp(normType, m_pTracks[i]->GetType())) { + if (subType) { + if (normType == MP4_AUDIO_TRACK_TYPE) { + if (subType != GetTrackEsdsObjectTypeId(m_pTracks[i]->GetId())) { + continue; + } + } else if (normType == MP4_VIDEO_TRACK_TYPE) { + if (subType != GetTrackEsdsObjectTypeId(m_pTracks[i]->GetId())) { + continue; + } + } + // else unknown subtype, ignore it + } + typeSeen++; + } + } + return typeSeen; +} + +MP4TrackId MP4File::AllocTrackId() +{ + MP4TrackId trackId = + GetIntegerProperty("moov.mvhd.nextTrackId"); + + if (trackId <= 0xFFFF) { + // check that nextTrackid is correct + try { + (void)FindTrackIndex(trackId); + // ERROR, this trackId is in use + } + catch (MP4Error* e) { + // OK, this trackId is not in use, proceed + delete e; + SetIntegerProperty("moov.mvhd.nextTrackId", trackId + 1); + return trackId; + } + } + + // we need to search for a track id + for (trackId = 1; trackId <= 0xFFFF; trackId++) { + try { + (void)FindTrackIndex(trackId); + // KEEP LOOKING, this trackId is in use + } + catch (MP4Error* e) { + // OK, this trackId is not in use, proceed + delete e; + return trackId; + } + } + + // extreme case where mp4 file has 2^16 tracks in it + throw new MP4Error("too many existing tracks", "AddTrack"); + return MP4_INVALID_TRACK_ID; // to keep MSVC happy +} + +MP4TrackId MP4File::FindTrackId(u_int16_t trackIndex, + const char* type, u_int8_t subType) +{ + if (type == NULL) { + return m_pTracks[trackIndex]->GetId(); + } + + u_int32_t typeSeen = 0; + const char* normType = MP4NormalizeTrackType(type, m_verbosity); + + for (u_int32_t i = 0; i < m_pTracks.Size(); i++) { + if (!strcmp(normType, m_pTracks[i]->GetType())) { + if (subType) { + if (normType == MP4_AUDIO_TRACK_TYPE) { + if (subType != GetTrackEsdsObjectTypeId(m_pTracks[i]->GetId())) { + continue; + } + } else if (normType == MP4_VIDEO_TRACK_TYPE) { + if (subType != GetTrackEsdsObjectTypeId(m_pTracks[i]->GetId())) { + continue; + } + } + // else unknown subtype, ignore it + } + + if (trackIndex == typeSeen) { + return m_pTracks[i]->GetId(); + } + + typeSeen++; + } + } + + throw new MP4Error("Track index doesn't exist - track %d type %s", + "FindTrackId", + trackIndex, type); + return MP4_INVALID_TRACK_ID; // satisfy MS compiler +} + +u_int16_t MP4File::FindTrackIndex(MP4TrackId trackId) +{ + for (u_int32_t i = 0; i < m_pTracks.Size() && i <= 0xFFFF; i++) { + if (m_pTracks[i]->GetId() == trackId) { + return (u_int16_t)i; + } + } + + throw new MP4Error("Track id %d doesn't exist", "FindTrackIndex", trackId); + return (u_int16_t)-1; // satisfy MS compiler +} + +u_int16_t MP4File::FindTrakAtomIndex(MP4TrackId trackId) +{ + if (trackId) { + for (u_int32_t i = 0; i < m_trakIds.Size(); i++) { + if (m_trakIds[i] == trackId) { + return i; + } + } + } + + throw new MP4Error("Track id %d doesn't exist", "FindTrakAtomIndex", + trackId); + return (u_int16_t)-1; // satisfy MS compiler +} + +u_int32_t MP4File::GetSampleSize(MP4TrackId trackId, MP4SampleId sampleId) +{ + return m_pTracks[FindTrackIndex(trackId)]->GetSampleSize(sampleId); +} + +u_int32_t MP4File::GetTrackMaxSampleSize(MP4TrackId trackId) +{ + return m_pTracks[FindTrackIndex(trackId)]->GetMaxSampleSize(); +} + +MP4SampleId MP4File::GetSampleIdFromTime(MP4TrackId trackId, + MP4Timestamp when, bool wantSyncSample, bool rewind) +{ + return m_pTracks[FindTrackIndex(trackId)]-> + GetSampleIdFromTime(when, wantSyncSample, rewind); +} + +MP4ChunkId MP4File::GetChunkIdFromTime(MP4TrackId trackId, MP4Timestamp when) +{ + return m_pTracks[FindTrackIndex(trackId)]-> + GetChunkIdFromTime(when); +} + +MP4Timestamp MP4File::GetSampleTime( + MP4TrackId trackId, MP4SampleId sampleId) +{ + MP4Timestamp timestamp; + m_pTracks[FindTrackIndex(trackId)]-> + GetSampleTimes(sampleId, ×tamp, NULL); + return timestamp; +} + +MP4Duration MP4File::GetSampleDuration( + MP4TrackId trackId, MP4SampleId sampleId) +{ + MP4Duration duration; + m_pTracks[FindTrackIndex(trackId)]-> + GetSampleTimes(sampleId, NULL, &duration); + return duration; +} + +MP4Duration MP4File::GetSampleRenderingOffset( + MP4TrackId trackId, MP4SampleId sampleId) +{ + return m_pTracks[FindTrackIndex(trackId)]-> + GetSampleRenderingOffset(sampleId); +} + +bool MP4File::GetSampleSync(MP4TrackId trackId, MP4SampleId sampleId) +{ + return m_pTracks[FindTrackIndex(trackId)]->IsSyncSample(sampleId); +} + +void MP4File::ReadSample(MP4TrackId trackId, MP4SampleId sampleId, + u_int8_t** ppBytes, u_int32_t* pNumBytes, + MP4Timestamp* pStartTime, MP4Duration* pDuration, + MP4Duration* pRenderingOffset, bool* pIsSyncSample) +{ + m_pTracks[FindTrackIndex(trackId)]-> + ReadSample(sampleId, ppBytes, pNumBytes, + pStartTime, pDuration, pRenderingOffset, pIsSyncSample); +} + +void MP4File::ReadChunk(MP4TrackId trackId, MP4ChunkId sampleId, + u_int8_t** ppBytes, u_int32_t* pNumBytes, + MP4Timestamp* pStartTime, MP4Duration* pDuration) +{ + m_pTracks[FindTrackIndex(trackId)]-> + ReadChunk(sampleId, ppBytes, pNumBytes, pStartTime, pDuration); +} + +void MP4File::WriteSample(MP4TrackId trackId, + const u_int8_t* pBytes, u_int32_t numBytes, + MP4Duration duration, MP4Duration renderingOffset, bool isSyncSample) +{ + ProtectWriteOperation("MP4WriteSample"); + + m_pTracks[FindTrackIndex(trackId)]-> + WriteSample(pBytes, numBytes, duration, renderingOffset, isSyncSample); + + m_pModificationProperty->SetValue(MP4GetAbsTimestamp()); +} + +void MP4File::SetSampleRenderingOffset(MP4TrackId trackId, + MP4SampleId sampleId, MP4Duration renderingOffset) +{ + ProtectWriteOperation("MP4SetSampleRenderingOffset"); + + m_pTracks[FindTrackIndex(trackId)]-> + SetSampleRenderingOffset(sampleId, renderingOffset); + + m_pModificationProperty->SetValue(MP4GetAbsTimestamp()); +} + +char* MP4File::MakeTrackName(MP4TrackId trackId, const char* name) +{ + u_int16_t trakIndex = FindTrakAtomIndex(trackId); + + if (name == NULL || name[0] == '\0') { + snprintf(m_trakName, sizeof(m_trakName), + "moov.trak[%u]", trakIndex); + } else { + snprintf(m_trakName, sizeof(m_trakName), + "moov.trak[%u].%s", trakIndex, name); + } + return m_trakName; +} + +MP4Atom *MP4File::FindTrackAtom (MP4TrackId trackId, const char *name) +{ + return FindAtomMP4File(MakeTrackName(trackId, name)); +} + +u_int64_t MP4File::GetTrackIntegerProperty(MP4TrackId trackId, const char* name) +{ + return GetIntegerProperty(MakeTrackName(trackId, name)); +} + +void MP4File::SetTrackIntegerProperty(MP4TrackId trackId, const char* name, + int64_t value) +{ + SetIntegerProperty(MakeTrackName(trackId, name), value); +} + +float MP4File::GetTrackFloatProperty(MP4TrackId trackId, const char* name) +{ + return GetFloatProperty(MakeTrackName(trackId, name)); +} + +void MP4File::SetTrackFloatProperty(MP4TrackId trackId, const char* name, + float value) +{ + SetFloatProperty(MakeTrackName(trackId, name), value); +} + +const char* MP4File::GetTrackStringProperty(MP4TrackId trackId, const char* name) +{ + return GetStringProperty(MakeTrackName(trackId, name)); +} + +void MP4File::SetTrackStringProperty(MP4TrackId trackId, const char* name, + const char* value) +{ + SetStringProperty(MakeTrackName(trackId, name), value); +} + +void MP4File::GetTrackBytesProperty(MP4TrackId trackId, const char* name, + u_int8_t** ppValue, u_int32_t* pValueSize) +{ + GetBytesProperty(MakeTrackName(trackId, name), ppValue, pValueSize); +} + +void MP4File::SetTrackBytesProperty(MP4TrackId trackId, const char* name, + const u_int8_t* pValue, u_int32_t valueSize) +{ + SetBytesProperty(MakeTrackName(trackId, name), pValue, valueSize); +} + + +// file level convenience functions + +MP4Duration MP4File::GetDuration() +{ + return m_pDurationProperty->GetValue(); +} + +void MP4File::SetDuration(MP4Duration value) +{ + m_pDurationProperty->SetValue(value); +} + +u_int32_t MP4File::GetTimeScale() +{ + return m_pTimeScaleProperty->GetValue(); +} + +void MP4File::SetTimeScale(u_int32_t value) +{ + if (value == 0) { + throw new MP4Error("invalid value", "SetTimeScale"); + } + m_pTimeScaleProperty->SetValue(value); +} + +u_int8_t MP4File::GetODProfileLevel() +{ + return GetIntegerProperty("moov.iods.ODProfileLevelId"); +} + +void MP4File::SetODProfileLevel(u_int8_t value) +{ + SetIntegerProperty("moov.iods.ODProfileLevelId", value); +} + +u_int8_t MP4File::GetSceneProfileLevel() +{ + return GetIntegerProperty("moov.iods.sceneProfileLevelId"); +} + +void MP4File::SetSceneProfileLevel(u_int8_t value) +{ + SetIntegerProperty("moov.iods.sceneProfileLevelId", value); +} + +u_int8_t MP4File::GetVideoProfileLevel() +{ + return GetIntegerProperty("moov.iods.visualProfileLevelId"); +} + +void MP4File::SetVideoProfileLevel(u_int8_t value) +{ + SetIntegerProperty("moov.iods.visualProfileLevelId", value); +} + +u_int8_t MP4File::GetAudioProfileLevel() +{ + return GetIntegerProperty("moov.iods.audioProfileLevelId"); +} + +void MP4File::SetAudioProfileLevel(u_int8_t value) +{ + SetIntegerProperty("moov.iods.audioProfileLevelId", value); +} + +u_int8_t MP4File::GetGraphicsProfileLevel() +{ + return GetIntegerProperty("moov.iods.graphicsProfileLevelId"); +} + +void MP4File::SetGraphicsProfileLevel(u_int8_t value) +{ + SetIntegerProperty("moov.iods.graphicsProfileLevelId", value); +} + +const char* MP4File::GetSessionSdp() +{ + return GetStringProperty("moov.udta.hnti.rtp .sdpText"); +} + +void MP4File::SetSessionSdp(const char* sdpString) +{ + (void)AddDescendantAtoms("moov", "udta.hnti.rtp "); + + SetStringProperty("moov.udta.hnti.rtp .sdpText", sdpString); +} + +void MP4File::AppendSessionSdp(const char* sdpFragment) +{ + const char* oldSdpString = NULL; + try { + oldSdpString = GetSessionSdp(); + } + catch (MP4Error* e) { + delete e; + SetSessionSdp(sdpFragment); + return; + } + + char* newSdpString = + (char*)MP4Malloc(strlen(oldSdpString) + strlen(sdpFragment) + 1); + strcpy(newSdpString, oldSdpString); + strcat(newSdpString, sdpFragment); + SetSessionSdp(newSdpString); + MP4Free(newSdpString); +} + +// +// ismacrypt API - retrieve OriginalFormatBox +// +// parameters are assumed to have been sanity tested in mp4.cpp +// don't call this unless media data name is 'encv', +// results may otherwise be unpredictable. +// +// input: +// trackID - valid encv track ID for this file +// buflen - length of oFormat, minimum is 5 (4cc plus null terminator) +// +// output: +// oFormat - buffer to return null terminated string containing +// track original format +// return: +// 0 - original format returned OK +// 1 - buffer length error or problem retrieving track property +// +// +bool MP4File::GetTrackMediaDataOriginalFormat(MP4TrackId trackId, + char *originalFormat, u_int32_t buflen) +{ + u_int32_t format; + + if (buflen < 5) + return false; + + format = GetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.sinf.frma.data-format"); + + IDATOM(format, originalFormat); + return true; + +} + + +// track level convenience functions + +MP4SampleId MP4File::GetTrackNumberOfSamples(MP4TrackId trackId) +{ + return m_pTracks[FindTrackIndex(trackId)]->GetNumberOfSamples(); +} + +MP4ChunkId MP4File::GetTrackNumberOfChunks(MP4TrackId trackId) +{ + return m_pTracks[FindTrackIndex(trackId)]->GetNumberOfChunks(); +} + +const char* MP4File::GetTrackType(MP4TrackId trackId) +{ + return m_pTracks[FindTrackIndex(trackId)]->GetType(); +} + +const char *MP4File::GetTrackMediaDataName (MP4TrackId trackId) +{ + MP4Atom *pChild; + MP4Atom *pAtom = + FindAtomMP4File(MakeTrackName(trackId, + "mdia.minf.stbl.stsd")); + if (!pAtom || pAtom->GetNumberOfChildAtoms() != 1) { + VERBOSE_ERROR(m_verbosity, + fprintf(stderr, "track %d has more than 1 child atoms in stsd\n", trackId)); + return NULL; + } + pChild = pAtom->GetChildAtom(0); + return pChild->GetType(); +} + + +u_int32_t MP4File::GetTrackTimeScale(MP4TrackId trackId) +{ + return m_pTracks[FindTrackIndex(trackId)]->GetTimeScale(); +} + +void MP4File::SetTrackTimeScale(MP4TrackId trackId, u_int32_t value) +{ + if (value == 0) { + throw new MP4Error("invalid value", "SetTrackTimeScale"); + } + SetTrackIntegerProperty(trackId, "mdia.mdhd.timeScale", value); +} + +MP4Duration MP4File::GetTrackDuration(MP4TrackId trackId) +{ + return GetTrackIntegerProperty(trackId, "mdia.mdhd.duration"); +} + +u_int8_t MP4File::GetTrackEsdsObjectTypeId(MP4TrackId trackId) +{ + // changed mp4a to * to handle enca case + try { + return GetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.esds.decConfigDescr.objectTypeId"); + } catch (MP4Error *e) { + delete e; + return GetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.*.esds.decConfigDescr.objectTypeId"); + } +} + +u_int8_t MP4File::GetTrackAudioMpeg4Type(MP4TrackId trackId) +{ + // verify that track is an MPEG-4 audio track + if (GetTrackEsdsObjectTypeId(trackId) != MP4_MPEG4_AUDIO_TYPE) { + return MP4_MPEG4_INVALID_AUDIO_TYPE; + } + + u_int8_t* pEsConfig = NULL; + u_int32_t esConfigSize; + + // The Mpeg4 audio type (AAC, CELP, HXVC, ...) + // is the first 5 bits of the ES configuration + + GetTrackESConfiguration(trackId, &pEsConfig, &esConfigSize); + + if (esConfigSize < 1) { + free(pEsConfig); + return MP4_MPEG4_INVALID_AUDIO_TYPE; + } + + u_int8_t mpeg4Type = ((pEsConfig[0] >> 3) & 0x1f); + // TTTT TXXX XXX potentially 6 bits of extension. + if (mpeg4Type == 0x1f) { + if (esConfigSize < 2) { + free(pEsConfig); + return MP4_MPEG4_INVALID_AUDIO_TYPE; + } + mpeg4Type = 32 + + (((pEsConfig[0] & 0x7) << 3) | ((pEsConfig[1] >> 5) & 0x7)); + } + + free(pEsConfig); + + return mpeg4Type; +} + + +MP4Duration MP4File::GetTrackFixedSampleDuration(MP4TrackId trackId) +{ + return m_pTracks[FindTrackIndex(trackId)]->GetFixedSampleDuration(); +} + +double MP4File::GetTrackVideoFrameRate(MP4TrackId trackId) +{ + MP4SampleId numSamples = + GetTrackNumberOfSamples(trackId); + u_int64_t + msDuration = + ConvertFromTrackDuration(trackId, + GetTrackDuration(trackId), MP4_MSECS_TIME_SCALE); + + if (msDuration == 0) { + return 0.0; + } + + return ((double)numSamples / UINT64_TO_DOUBLE(msDuration)) * MP4_MSECS_TIME_SCALE; +} + +int MP4File::GetTrackAudioChannels (MP4TrackId trackId) +{ + return GetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*[0].channels"); +} + +// true if media track encrypted according to ismacryp +bool MP4File::IsIsmaCrypMediaTrack(MP4TrackId trackId) +{ + if (GetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.sinf.frma.data-format") + != (u_int64_t)-1) { + return true; + } + return false; +} + + +void MP4File::GetTrackESConfiguration(MP4TrackId trackId, + u_int8_t** ppConfig, u_int32_t* pConfigSize) +{ + try { + GetTrackBytesProperty(trackId, + "mdia.minf.stbl.stsd.*[0].esds.decConfigDescr.decSpecificInfo[0].info", + ppConfig, pConfigSize); + } catch (MP4Error *e) { + delete e; + GetTrackBytesProperty(trackId, + "mdia.minf.stbl.stsd.*[0].*.esds.decConfigDescr.decSpecificInfo[0].info", + ppConfig, pConfigSize); + } +} + +void MP4File::GetTrackVideoMetadata(MP4TrackId trackId, + u_int8_t** ppConfig, u_int32_t* pConfigSize) +{ + GetTrackBytesProperty(trackId, + "mdia.minf.stbl.stsd.*[0].*.metadata", + ppConfig, pConfigSize); +} + +void MP4File::SetTrackESConfiguration(MP4TrackId trackId, + const u_int8_t* pConfig, u_int32_t configSize) +{ + // get a handle on the track decoder config descriptor + MP4DescriptorProperty* pConfigDescrProperty = NULL; + if (FindProperty(MakeTrackName(trackId, + "mdia.minf.stbl.stsd.*[0].esds.decConfigDescr.decSpecificInfo"), + (MP4Property**)&pConfigDescrProperty) == false || + pConfigDescrProperty == NULL) { + // probably trackId refers to a hint track + throw new MP4Error("no such property", "MP4SetTrackESConfiguration"); + } + + // lookup the property to store the configuration + MP4BytesProperty* pInfoProperty = NULL; + (void)pConfigDescrProperty->FindProperty("decSpecificInfo[0].info", + (MP4Property**)&pInfoProperty); + + // configuration being set for the first time + if (pInfoProperty == NULL) { + // need to create a new descriptor to hold it + MP4Descriptor* pConfigDescr = + pConfigDescrProperty->AddDescriptor(MP4DecSpecificDescrTag); + pConfigDescr->Generate(); + + (void)pConfigDescrProperty->FindProperty( + "decSpecificInfo[0].info", + (MP4Property**)&pInfoProperty); + ASSERT(pInfoProperty); + } + + // set the value + pInfoProperty->SetValue(pConfig, configSize); +} + + +void MP4File::GetTrackH264SeqPictHeaders (MP4TrackId trackId, + uint8_t ***pppSeqHeader, + uint32_t **ppSeqHeaderSize, + uint8_t ***pppPictHeader, + uint32_t **ppPictHeaderSize) +{ + uint32_t count; + const char *format; + MP4Atom *avcCAtom; + + *pppSeqHeader = NULL; *pppPictHeader = NULL; + *ppSeqHeaderSize = NULL; *ppPictHeaderSize = NULL; + + // get 4cc media format - can be avc1 or encv for ismacrypted track + format = GetTrackMediaDataName (trackId); + + if (!strcasecmp(format, "avc1")) + avcCAtom = FindAtomMP4File(MakeTrackName(trackId, "mdia.minf.stbl.stsd.avc1.avcC")); + else if (!strcasecmp(format, "encv")) + avcCAtom = FindAtomMP4File(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.avcC")); + else + // huh? unknown track format + return; + + MP4BitfieldProperty *pSeqCount; + MP4IntegerProperty *pSeqLen, *pPictCount, *pPictLen; + MP4BytesProperty *pSeqVal, *pPictVal; + + if ((avcCAtom->FindProperty("avcC.numOfSequenceParameterSets", + (MP4Property **)&pSeqCount) == false) || + (avcCAtom->FindProperty("avcC.sequenceEntries.sequenceParameterSetLength", + (MP4Property **)&pSeqLen) == false) || + (avcCAtom->FindProperty("avcC.sequenceEntries.sequenceParameterSetNALUnit", + (MP4Property **)&pSeqVal) == false)) { + VERBOSE_ERROR(m_verbosity, WARNING("Could not find avcC properties")); + return ; + } + uint8_t **ppSeqHeader = + (uint8_t **)malloc((pSeqCount->GetValue() + 1) * sizeof(uint8_t *)); + if (ppSeqHeader == NULL) return; + *pppSeqHeader = ppSeqHeader; + + uint32_t *pSeqHeaderSize = + (uint32_t *)malloc((pSeqCount->GetValue() + 1) * sizeof(uint32_t *)); + + if (pSeqHeaderSize == NULL) return; + + *ppSeqHeaderSize = pSeqHeaderSize; + for (count = 0; count < pSeqCount->GetValue(); count++) { + pSeqVal->GetValue(&(ppSeqHeader[count]), &(pSeqHeaderSize[count]), + count); + } + ppSeqHeader[count] = NULL; + pSeqHeaderSize[count] = 0; + + if ((avcCAtom->FindProperty("avcC.numOfPictureParameterSets", + (MP4Property **)&pPictCount) == false) || + (avcCAtom->FindProperty("avcC.pictureEntries.pictureParameterSetLength", + (MP4Property **)&pPictLen) == false) || + (avcCAtom->FindProperty("avcC.pictureEntries.pictureParameterSetNALUnit", + (MP4Property **)&pPictVal) == false)) { + VERBOSE_ERROR(m_verbosity, + WARNING("Could not find avcC picture table properties")); + return ; + } + uint8_t + **ppPictHeader = + (uint8_t **)malloc((pPictCount->GetValue() + 1) * sizeof(uint8_t *)); + if (ppPictHeader == NULL) return; + uint32_t *pPictHeaderSize = + (uint32_t *)malloc((pPictCount->GetValue() + 1)* sizeof(uint32_t *)); + if (pPictHeaderSize == NULL) { + free(ppPictHeader); + return; + } + *pppPictHeader = ppPictHeader; + *ppPictHeaderSize = pPictHeaderSize; + + for (count = 0; count < pPictCount->GetValue(); count++) { + pPictVal->GetValue(&(ppPictHeader[count]), &(pPictHeaderSize[count]), + count); + } + ppPictHeader[count] = NULL; + pPictHeaderSize[count] = 0; + return ; +} + + + +const char* MP4File::GetHintTrackSdp(MP4TrackId hintTrackId) +{ + return GetTrackStringProperty(hintTrackId, "udta.hnti.sdp .sdpText"); +} + +void MP4File::SetHintTrackSdp(MP4TrackId hintTrackId, const char* sdpString) +{ + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new MP4Error("track is not a hint track", + "MP4SetHintTrackSdp"); + } + + (void)AddDescendantAtoms( + MakeTrackName(hintTrackId, NULL), "udta.hnti.sdp "); + + SetTrackStringProperty(hintTrackId, "udta.hnti.sdp .sdpText", sdpString); +} + +void MP4File::AppendHintTrackSdp(MP4TrackId hintTrackId, + const char* sdpFragment) +{ + const char* oldSdpString = NULL; + try { + oldSdpString = GetHintTrackSdp(hintTrackId); + } + catch (MP4Error* e) { + delete e; + SetHintTrackSdp(hintTrackId, sdpFragment); + return; + } + + char* newSdpString = + (char*)MP4Malloc(strlen(oldSdpString) + strlen(sdpFragment) + 1); + strcpy(newSdpString, oldSdpString); + strcat(newSdpString, sdpFragment); + SetHintTrackSdp(hintTrackId, newSdpString); + MP4Free(newSdpString); +} + +void MP4File::GetHintTrackRtpPayload( + MP4TrackId hintTrackId, + char** ppPayloadName, + u_int8_t* pPayloadNumber, + u_int16_t* pMaxPayloadSize, + char **ppEncodingParams) +{ + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new MP4Error("track is not a hint track", + "MP4GetHintTrackRtpPayload"); + } + + ((MP4RtpHintTrack*)pTrack)->GetPayload( + ppPayloadName, pPayloadNumber, pMaxPayloadSize, ppEncodingParams); +} + +void MP4File::SetHintTrackRtpPayload(MP4TrackId hintTrackId, + const char* payloadName, u_int8_t* pPayloadNumber, u_int16_t maxPayloadSize, + const char *encoding_params, + bool include_rtp_map, + bool include_mpeg4_esid) +{ + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new MP4Error("track is not a hint track", + "MP4SetHintTrackRtpPayload"); + } + + u_int8_t payloadNumber; + if (pPayloadNumber && *pPayloadNumber != MP4_SET_DYNAMIC_PAYLOAD) { + payloadNumber = *pPayloadNumber; + } else { + payloadNumber = AllocRtpPayloadNumber(); + if (pPayloadNumber) { + *pPayloadNumber = payloadNumber; + } + } + + ((MP4RtpHintTrack*)pTrack)->SetPayload( + payloadName, payloadNumber, maxPayloadSize, encoding_params, + include_rtp_map, include_mpeg4_esid); +} + +u_int8_t MP4File::AllocRtpPayloadNumber() +{ + MP4Integer32Array usedPayloads; + u_int32_t i; + + // collect rtp payload numbers in use by existing tracks + for (i = 0; i < m_pTracks.Size(); i++) { + MP4Atom* pTrakAtom = m_pTracks[i]->GetTrakAtom(); + + MP4Integer32Property* pPayloadProperty = NULL; + if (pTrakAtom->FindProperty("trak.udta.hinf.payt.payloadNumber", + (MP4Property**)&pPayloadProperty) && + pPayloadProperty) { + usedPayloads.Add(pPayloadProperty->GetValue()); + } + } + + // search dynamic payload range for an available slot + u_int8_t payload; + for (payload = 96; payload < 128; payload++) { + for (i = 0; i < usedPayloads.Size(); i++) { + if (payload == usedPayloads[i]) { + break; + } + } + if (i == usedPayloads.Size()) { + break; + } + } + + if (payload >= 128) { + throw new MP4Error("no more available rtp payload numbers", + "AllocRtpPayloadNumber"); + } + + return payload; +} + +MP4TrackId MP4File::GetHintTrackReferenceTrackId( + MP4TrackId hintTrackId) +{ + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new MP4Error("track is not a hint track", + "MP4GetHintTrackReferenceTrackId"); + } + + MP4Track* pRefTrack = ((MP4RtpHintTrack*)pTrack)->GetRefTrack(); + + if (pRefTrack == NULL) { + return MP4_INVALID_TRACK_ID; + } + return pRefTrack->GetId(); +} + +void MP4File::ReadRtpHint( + MP4TrackId hintTrackId, + MP4SampleId hintSampleId, + u_int16_t* pNumPackets) +{ + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new MP4Error("track is not a hint track", "MP4ReadRtpHint"); + } + ((MP4RtpHintTrack*)pTrack)-> + ReadHint(hintSampleId, pNumPackets); +} + +u_int16_t MP4File::GetRtpHintNumberOfPackets( + MP4TrackId hintTrackId) +{ + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new MP4Error("track is not a hint track", + "MP4GetRtpHintNumberOfPackets"); + } + return ((MP4RtpHintTrack*)pTrack)->GetHintNumberOfPackets(); +} + +int8_t MP4File::GetRtpPacketBFrame( + MP4TrackId hintTrackId, + u_int16_t packetIndex) +{ + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new MP4Error("track is not a hint track", + "MP4GetRtpHintBFrame"); + } + return ((MP4RtpHintTrack*)pTrack)->GetPacketBFrame(packetIndex); +} + +int32_t MP4File::GetRtpPacketTransmitOffset( + MP4TrackId hintTrackId, + u_int16_t packetIndex) +{ + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new MP4Error("track is not a hint track", + "MP4GetRtpPacketTransmitOffset"); + } + return ((MP4RtpHintTrack*)pTrack)->GetPacketTransmitOffset(packetIndex); +} + +void MP4File::ReadRtpPacket( + MP4TrackId hintTrackId, + u_int16_t packetIndex, + u_int8_t** ppBytes, + u_int32_t* pNumBytes, + u_int32_t ssrc, + bool includeHeader, + bool includePayload) +{ + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new MP4Error("track is not a hint track", "MP4ReadPacket"); + } + ((MP4RtpHintTrack*)pTrack)->ReadPacket( + packetIndex, ppBytes, pNumBytes, + ssrc, includeHeader, includePayload); +} + +MP4Timestamp MP4File::GetRtpTimestampStart( + MP4TrackId hintTrackId) +{ + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new MP4Error("track is not a hint track", + "MP4GetRtpTimestampStart"); + } + return ((MP4RtpHintTrack*)pTrack)->GetRtpTimestampStart(); +} + +void MP4File::SetRtpTimestampStart( + MP4TrackId hintTrackId, + MP4Timestamp rtpStart) +{ + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new MP4Error("track is not a hint track", + "MP4SetRtpTimestampStart"); + } + ((MP4RtpHintTrack*)pTrack)->SetRtpTimestampStart(rtpStart); +} + +void MP4File::AddRtpHint(MP4TrackId hintTrackId, + bool isBframe, u_int32_t timestampOffset) +{ + ProtectWriteOperation("MP4AddRtpHint"); + + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new MP4Error("track is not a hint track", "MP4AddRtpHint"); + } + ((MP4RtpHintTrack*)pTrack)->AddHint(isBframe, timestampOffset); +} + +void MP4File::AddRtpPacket( + MP4TrackId hintTrackId, bool setMbit, int32_t transmitOffset) +{ + ProtectWriteOperation("MP4AddRtpPacket"); + + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new MP4Error("track is not a hint track", "MP4AddRtpPacket"); + } + ((MP4RtpHintTrack*)pTrack)->AddPacket(setMbit, transmitOffset); +} + +void MP4File::AddRtpImmediateData(MP4TrackId hintTrackId, + const u_int8_t* pBytes, u_int32_t numBytes) +{ + ProtectWriteOperation("MP4AddRtpImmediateData"); + + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new MP4Error("track is not a hint track", + "MP4AddRtpImmediateData"); + } + ((MP4RtpHintTrack*)pTrack)->AddImmediateData(pBytes, numBytes); +} + +void MP4File::AddRtpSampleData(MP4TrackId hintTrackId, + MP4SampleId sampleId, u_int32_t dataOffset, u_int32_t dataLength) +{ + ProtectWriteOperation("MP4AddRtpSampleData"); + + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new MP4Error("track is not a hint track", + "MP4AddRtpSampleData"); + } + ((MP4RtpHintTrack*)pTrack)->AddSampleData( + sampleId, dataOffset, dataLength); +} + +void MP4File::AddRtpESConfigurationPacket(MP4TrackId hintTrackId) +{ + ProtectWriteOperation("MP4AddRtpESConfigurationPacket"); + + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new MP4Error("track is not a hint track", + "MP4AddRtpESConfigurationPacket"); + } + ((MP4RtpHintTrack*)pTrack)->AddESConfigurationPacket(); +} + +void MP4File::WriteRtpHint(MP4TrackId hintTrackId, + MP4Duration duration, bool isSyncSample) +{ + ProtectWriteOperation("MP4WriteRtpHint"); + + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new MP4Error("track is not a hint track", + "MP4WriteRtpHint"); + } + ((MP4RtpHintTrack*)pTrack)->WriteHint(duration, isSyncSample); +} + +u_int64_t MP4File::ConvertFromMovieDuration( + MP4Duration duration, + u_int32_t timeScale) +{ + return MP4ConvertTime((u_int64_t)duration, + GetTimeScale(), timeScale); +} + +u_int64_t MP4File::ConvertFromTrackTimestamp( + MP4TrackId trackId, + MP4Timestamp timeStamp, + u_int32_t timeScale) +{ + return MP4ConvertTime(timeStamp, + GetTrackTimeScale(trackId), timeScale); +} + +MP4Timestamp MP4File::ConvertToTrackTimestamp( + MP4TrackId trackId, + u_int64_t timeStamp, + u_int32_t timeScale) +{ + return (MP4Timestamp)MP4ConvertTime(timeStamp, + timeScale, GetTrackTimeScale(trackId)); +} + +u_int64_t MP4File::ConvertFromTrackDuration( + MP4TrackId trackId, + MP4Duration duration, + u_int32_t timeScale) +{ + return MP4ConvertTime((u_int64_t)duration, + GetTrackTimeScale(trackId), timeScale); +} + +MP4Duration MP4File::ConvertToTrackDuration( + MP4TrackId trackId, + u_int64_t duration, + u_int32_t timeScale) +{ + return (MP4Duration)MP4ConvertTime(duration, + timeScale, GetTrackTimeScale(trackId)); +} + +u_int8_t MP4File::ConvertTrackTypeToStreamType(const char* trackType) +{ + u_int8_t streamType; + + if (!strcmp(trackType, MP4_OD_TRACK_TYPE)) { + streamType = MP4ObjectDescriptionStreamType; + } else if (!strcmp(trackType, MP4_SCENE_TRACK_TYPE)) { + streamType = MP4SceneDescriptionStreamType; + } else if (!strcmp(trackType, MP4_CLOCK_TRACK_TYPE)) { + streamType = MP4ClockReferenceStreamType; + } else if (!strcmp(trackType, MP4_MPEG7_TRACK_TYPE)) { + streamType = MP4Mpeg7StreamType; + } else if (!strcmp(trackType, MP4_OCI_TRACK_TYPE)) { + streamType = MP4OCIStreamType; + } else if (!strcmp(trackType, MP4_IPMP_TRACK_TYPE)) { + streamType = MP4IPMPStreamType; + } else if (!strcmp(trackType, MP4_MPEGJ_TRACK_TYPE)) { + streamType = MP4MPEGJStreamType; + } else { + streamType = MP4UserPrivateStreamType; + } + + return streamType; +} + +// edit list + +char* MP4File::MakeTrackEditName( + MP4TrackId trackId, + MP4EditId editId, + const char* name) +{ + char* trakName = MakeTrackName(trackId, NULL); + + if (m_editName == NULL) { + m_editName = (char *)malloc(1024); + if (m_editName == NULL) return NULL; + } + snprintf(m_editName, 1024, + "%s.edts.elst.entries[%u].%s", + trakName, editId - 1, name); + return m_editName; +} + +MP4EditId MP4File::AddTrackEdit( + MP4TrackId trackId, + MP4EditId editId) +{ + ProtectWriteOperation("AddTrackEdit"); + return m_pTracks[FindTrackIndex(trackId)]->AddEdit(editId); +} + +void MP4File::DeleteTrackEdit( + MP4TrackId trackId, + MP4EditId editId) +{ + ProtectWriteOperation("DeleteTrackEdit"); + m_pTracks[FindTrackIndex(trackId)]->DeleteEdit(editId); +} + +u_int32_t MP4File::GetTrackNumberOfEdits( + MP4TrackId trackId) +{ + return GetTrackIntegerProperty(trackId, "edts.elst.entryCount"); +} + +MP4Duration MP4File::GetTrackEditTotalDuration( + MP4TrackId trackId, + MP4EditId editId) +{ + return m_pTracks[FindTrackIndex(trackId)]->GetEditTotalDuration(editId); +} + +MP4Timestamp MP4File::GetTrackEditStart( + MP4TrackId trackId, + MP4EditId editId) +{ + return m_pTracks[FindTrackIndex(trackId)]->GetEditStart(editId); +} + +MP4Timestamp MP4File::GetTrackEditMediaStart( + MP4TrackId trackId, + MP4EditId editId) +{ + return GetIntegerProperty( + MakeTrackEditName(trackId, editId, "mediaTime")); +} + +void MP4File::SetTrackEditMediaStart( + MP4TrackId trackId, + MP4EditId editId, + MP4Timestamp startTime) +{ + SetIntegerProperty( + MakeTrackEditName(trackId, editId, "mediaTime"), + startTime); +} + +MP4Duration MP4File::GetTrackEditDuration( + MP4TrackId trackId, + MP4EditId editId) +{ + return GetIntegerProperty( + MakeTrackEditName(trackId, editId, "segmentDuration")); +} + +void MP4File::SetTrackEditDuration( + MP4TrackId trackId, + MP4EditId editId, + MP4Duration duration) +{ + SetIntegerProperty( + MakeTrackEditName(trackId, editId, "segmentDuration"), + duration); +} + +bool MP4File::GetTrackEditDwell( + MP4TrackId trackId, + MP4EditId editId) +{ + return (GetIntegerProperty( + MakeTrackEditName(trackId, editId, "mediaRate")) == 0); +} + +void MP4File::SetTrackEditDwell( + MP4TrackId trackId, + MP4EditId editId, + bool dwell) +{ + SetIntegerProperty( + MakeTrackEditName(trackId, editId, "mediaRate"), + (dwell ? 0 : 1)); +} + +MP4SampleId MP4File::GetSampleIdFromEditTime( + MP4TrackId trackId, + MP4Timestamp when, + MP4Timestamp* pStartTime, + MP4Duration* pDuration) +{ + return m_pTracks[FindTrackIndex(trackId)]->GetSampleIdFromEditTime( + when, pStartTime, pDuration); +} + diff --git a/Src/external_dependencies/libmp4v2/mp4file.h b/Src/external_dependencies/libmp4v2/mp4file.h new file mode 100644 index 00000000..dc4d65b1 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/mp4file.h @@ -0,0 +1,864 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001 - 2005. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + * Alix Marchandise-Franquet alix@cisco.com + * Ximpo Group Ltd. mp4v2@ximpo.com + */ + +#ifndef __MP4_FILE_INCLUDED__ +#define __MP4_FILE_INCLUDED__ + +// forward declarations +class MP4Atom; +class MP4Property; +class MP4Float32Property; +class MP4StringProperty; +class MP4BytesProperty; +class MP4Descriptor; +class MP4DescriptorProperty; +struct Virtual_IO; + +class MP4File { +public: /* equivalent to MP4 library API */ + MP4File(u_int32_t verbosity = 0); + ~MP4File(); + + /* file operations */ + void Read(const MP4_FILENAME_CHAR *fileName); + void ReadEx(const MP4_FILENAME_CHAR *fileName, void *user, Virtual_IO *virtual_IO); //benski> + void Create(const MP4_FILENAME_CHAR *fileName, u_int32_t flags, + int add_ftyp = 1, int add_iods = 1, + char* majorBrand = NULL, + u_int32_t minorVersion = 0, char** supportedBrands = NULL, + u_int32_t supportedBrandsCount = 0); + void Modify(const MP4_FILENAME_CHAR *fileName); + void Optimize(const MP4_FILENAME_CHAR *orgFileName, + const MP4_FILENAME_CHAR *newFileName = NULL); + void Close(); + + /* library property per file */ + + u_int32_t GetVerbosity() { + return m_verbosity; + } + void SetVerbosity(u_int32_t verbosity) { + m_verbosity = verbosity; + } + + bool Use64Bits(const char *atomName); + void Check64BitStatus(const char *atomName); + /* file properties */ + + u_int64_t GetIntegerProperty(const char* name); + float GetFloatProperty(const char* name); + const char* GetStringProperty(const char* name); + void GetBytesProperty(const char* name, + u_int8_t** ppValue, u_int32_t* pValueSize); + + void SetIntegerProperty(const char* name, u_int64_t value); + void SetFloatProperty(const char* name, float value); + void SetStringProperty(const char* name, const char* value); + void SetBytesProperty(const char* name, + const u_int8_t* pValue, u_int32_t valueSize); + + // file level convenience functions + + MP4Duration GetDuration(); + void SetDuration(MP4Duration value); + + u_int32_t GetTimeScale(); + void SetTimeScale(u_int32_t value); + + u_int8_t GetODProfileLevel(); + void SetODProfileLevel(u_int8_t value); + + u_int8_t GetSceneProfileLevel(); + void SetSceneProfileLevel(u_int8_t value); + + u_int8_t GetVideoProfileLevel(); + void SetVideoProfileLevel(u_int8_t value); + + u_int8_t GetAudioProfileLevel(); + void SetAudioProfileLevel(u_int8_t value); + + u_int8_t GetGraphicsProfileLevel(); + void SetGraphicsProfileLevel(u_int8_t value); + + const char* GetSessionSdp(); + void SetSessionSdp(const char* sdpString); + void AppendSessionSdp(const char* sdpString); + + /* track operations */ + + MP4TrackId AddTrack(const char* type, u_int32_t timeScale = 1000); + void DeleteTrack(MP4TrackId trackId); + + u_int32_t GetNumberOfTracks(const char* type = NULL, u_int8_t subType = 0); + + MP4TrackId AllocTrackId(); + MP4TrackId FindTrackId(u_int16_t trackIndex, + const char* type = NULL, u_int8_t subType = 0); + u_int16_t FindTrackIndex(MP4TrackId trackId); + u_int16_t FindTrakAtomIndex(MP4TrackId trackId); + + /* track properties */ + MP4Atom *FindTrackAtom(MP4TrackId trackId, const char *name); + u_int64_t GetTrackIntegerProperty( + MP4TrackId trackId, const char* name); + float GetTrackFloatProperty( + MP4TrackId trackId, const char* name); + const char* GetTrackStringProperty( + MP4TrackId trackId, const char* name); + void GetTrackBytesProperty( + MP4TrackId trackId, const char* name, + u_int8_t** ppValue, u_int32_t* pValueSize); + + void SetTrackIntegerProperty( + MP4TrackId trackId, const char* name, int64_t value); + void SetTrackFloatProperty( + MP4TrackId trackId, const char* name, float value); + void SetTrackStringProperty( + MP4TrackId trackId, const char* name, const char* value); + void SetTrackBytesProperty( + MP4TrackId trackId, const char* name, + const u_int8_t* pValue, u_int32_t valueSize); + + /* sample operations */ + + u_int32_t GetSampleSize(MP4TrackId trackId, MP4SampleId sampleId); + + u_int32_t GetTrackMaxSampleSize(MP4TrackId trackId); + + MP4SampleId GetSampleIdFromTime(MP4TrackId trackId, + MP4Timestamp when, bool wantSyncSample = false, bool rewind = false); + + MP4ChunkId GetChunkIdFromTime(MP4TrackId trackId, MP4Timestamp when); + + MP4Timestamp GetSampleTime( + MP4TrackId trackId, MP4SampleId sampleId); + + MP4Duration GetSampleDuration( + MP4TrackId trackId, MP4SampleId sampleId); + + MP4Duration GetSampleRenderingOffset( + MP4TrackId trackId, MP4SampleId sampleId); + + bool GetSampleSync( + MP4TrackId trackId, MP4SampleId sampleId); + + void ReadSample( + // input parameters + MP4TrackId trackId, + MP4SampleId sampleId, + // output parameters + u_int8_t** ppBytes, + u_int32_t* pNumBytes, + MP4Timestamp* pStartTime = NULL, + MP4Duration* pDuration = NULL, + MP4Duration* pRenderingOffset = NULL, + bool* pIsSyncSample = NULL); + + void ReadChunk( + // input parameters + MP4TrackId trackId, + MP4ChunkId sampleId, + // output parameters + u_int8_t** ppBytes, + u_int32_t* pNumBytes, + MP4Timestamp* pStartTime = NULL, + MP4Duration* pDuration = NULL); + + void WriteSample( + MP4TrackId trackId, + const u_int8_t* pBytes, + u_int32_t numBytes, + MP4Duration duration = 0, + MP4Duration renderingOffset = 0, + bool isSyncSample = true); + + void SetSampleRenderingOffset( + MP4TrackId trackId, + MP4SampleId sampleId, + MP4Duration renderingOffset); + + /* track level convenience functions */ + + MP4TrackId AddSystemsTrack(const char* type); + + MP4TrackId AddODTrack(); + + MP4TrackId AddSceneTrack(); + + MP4TrackId AddAudioTrack( + u_int32_t timeScale, + MP4Duration sampleDuration, + u_int8_t audioType); + + MP4TrackId AddEncAudioTrack( // ismacryp + u_int32_t timeScale, + MP4Duration sampleDuration, + u_int8_t audioType, + u_int32_t scheme_type, + u_int16_t scheme_version, + u_int8_t key_ind_len, + u_int8_t iv_len, + bool selective_enc, + const char *kms_uri, + bool use_ismacryp); + + void SetAmrVendor( + MP4TrackId trackId, + u_int32_t vendor); + + void SetAmrDecoderVersion( + MP4TrackId trackId, + u_int8_t decoderVersion); + + void SetAmrModeSet( + MP4TrackId trackId, + u_int16_t modeSet); + uint16_t GetAmrModeSet(MP4TrackId trackId); + + MP4TrackId AddAmrAudioTrack( + u_int32_t timeScale, + u_int16_t modeSet, + u_int8_t modeChangePeriod, + u_int8_t framesPerSample, + bool isAmrWB); + + MP4TrackId AddHrefTrack(uint32_t timeScale, + MP4Duration sampleDuration, + const char *base_url); + + MP4TrackId AddMP4VideoTrack( + u_int32_t timeScale, + MP4Duration sampleDuration, + u_int16_t width, + u_int16_t height, + u_int8_t videoType); + + MP4TrackId AddEncVideoTrack( // ismacryp + u_int32_t timeScale, + MP4Duration sampleDuration, + u_int16_t width, + u_int16_t height, + u_int8_t videoType, + mp4v2_ismacrypParams *icPp, + const char *oFormat); + + void SetH263Vendor( + MP4TrackId trackId, + u_int32_t vendor); + + void SetH263DecoderVersion( + MP4TrackId trackId, + u_int8_t decoderVersion); + + void SetH263Bitrates( + MP4TrackId, + u_int32_t avgBitrate, + u_int32_t maxBitrate); + + MP4TrackId AddH263VideoTrack( + u_int32_t timeScale, + MP4Duration sampleDuration, + u_int16_t width, + u_int16_t height, + u_int8_t h263Level, + u_int8_t h263Profile, + u_int32_t avgBitrate, + u_int32_t maxBitrate); + + MP4TrackId AddH264VideoTrack( + u_int32_t timeScale, + MP4Duration sampleDuration, + u_int16_t width, + u_int16_t height, + uint8_t AVCProfileIndication, + uint8_t profile_compat, + uint8_t AVCLevelIndication, + uint8_t sampleLenFieldSizeMinusOne); + + MP4TrackId AddEncH264VideoTrack( + u_int32_t timeScale, + MP4Duration sampleDuration, + u_int16_t width, + u_int16_t height, + MP4Atom *srcAtom, + mp4v2_ismacrypParams *icPp); + + void AddH264SequenceParameterSet(MP4TrackId trackId, + const uint8_t *pSequence, + uint16_t sequenceLen); + void AddH264PictureParameterSet(MP4TrackId trackId, + const uint8_t *pPicture, + uint16_t pictureLen); + MP4TrackId AddHintTrack(MP4TrackId refTrackId); + + MP4TrackId AddTextTrack(MP4TrackId refTrackId); + MP4TrackId AddChapterTextTrack(MP4TrackId refTrackId, u_int32_t timescale = 0); + void AddChapter(MP4TrackId chapterTrackId, + MP4Duration chapterDuration, + u_int32_t chapterNr, + const char * chapterTitle = 0); + void AddChapter(MP4Timestamp chapterStart, + const char * chapterTitle = 0); + void ConvertChapters(boolean toQT = true); + void DeleteChapters(MP4TrackId chapterTrackId = 0, boolean deleteQT = true); + void GetChaptersList(MP4Chapters_t ** chapterList, + u_int32_t * chapterCount, + boolean getQT = true); + MP4TrackId FindChapterTrack(char * trackName = 0, int trackNameSize = 0); + MP4TrackId FindChapterReferenceTrack(MP4TrackId chapterTrackId, char * trackName = 0, size_t trackNameSize = 0); + + MP4SampleId GetTrackNumberOfSamples(MP4TrackId trackId); + MP4ChunkId GetTrackNumberOfChunks(MP4TrackId trackId); + + const char* GetTrackType(MP4TrackId trackId); + + const char *GetTrackMediaDataName(MP4TrackId trackId); + bool GetTrackMediaDataOriginalFormat(MP4TrackId trackId, + char *originalFormat, u_int32_t buflen); + MP4Duration GetTrackDuration(MP4TrackId trackId); + + u_int32_t GetTrackTimeScale(MP4TrackId trackId); + void SetTrackTimeScale(MP4TrackId trackId, u_int32_t value); + + // replacement to GetTrackAudioType and GetTrackVideoType + u_int8_t GetTrackEsdsObjectTypeId(MP4TrackId trackId); + + u_int8_t GetTrackAudioMpeg4Type(MP4TrackId trackId); + + MP4Duration GetTrackFixedSampleDuration(MP4TrackId trackId); + + double GetTrackVideoFrameRate(MP4TrackId trackId); + + int GetTrackAudioChannels(MP4TrackId trackId); + void GetTrackESConfiguration(MP4TrackId trackId, + u_int8_t** ppConfig, u_int32_t* pConfigSize); + void SetTrackESConfiguration(MP4TrackId trackId, + const u_int8_t* pConfig, u_int32_t configSize); + + void GetTrackVideoMetadata(MP4TrackId trackId, + u_int8_t** ppConfig, u_int32_t* pConfigSize); + void GetTrackH264SeqPictHeaders(MP4TrackId trackId, + uint8_t ***pSeqHeader, + uint32_t **pSeqHeaderSize, + uint8_t ***pPictHeader, + uint32_t **pPictHeaderSize); + const char* GetHintTrackSdp(MP4TrackId hintTrackId); + void SetHintTrackSdp(MP4TrackId hintTrackId, const char* sdpString); + void AppendHintTrackSdp(MP4TrackId hintTrackId, const char* sdpString); + + // 3GPP specific functions + void MakeFtypAtom(char* majorBrand, + u_int32_t minorVersion, + char** supportedBrands, + u_int32_t supportedBrandsCount); + void Make3GPCompliant(const MP4_FILENAME_CHAR* fileName, + char* majorBrand, + u_int32_t minorVersion, + char** supportedBrands, + u_int32_t supportedBrandsCount, + bool deleteIodsAtom); + + // ISMA specific functions + + // true if media track encrypted according to ismacryp + bool IsIsmaCrypMediaTrack(MP4TrackId trackId); + + void MakeIsmaCompliant(bool addIsmaComplianceSdp = true); + + void CreateIsmaIodFromParams( + u_int8_t videoProfile, + u_int32_t videoBitrate, + u_int8_t* videoConfig, + u_int32_t videoConfigLength, + u_int8_t audioProfile, + u_int32_t audioBitrate, + u_int8_t* audioConfig, + u_int32_t audioConfigLength, + u_int8_t** ppBytes, + u_int64_t* pNumBytes); + + // time convenience functions + + u_int64_t ConvertFromMovieDuration( + MP4Duration duration, + u_int32_t timeScale); + + u_int64_t ConvertFromTrackTimestamp( + MP4TrackId trackId, + MP4Timestamp timeStamp, + u_int32_t timeScale); + + MP4Timestamp ConvertToTrackTimestamp( + MP4TrackId trackId, + u_int64_t timeStamp, + u_int32_t timeScale); + + u_int64_t ConvertFromTrackDuration( + MP4TrackId trackId, + MP4Duration duration, + u_int32_t timeScale); + + MP4Duration ConvertToTrackDuration( + MP4TrackId trackId, + u_int64_t duration, + u_int32_t timeScale); + + // specialized operations + + void GetHintTrackRtpPayload( + MP4TrackId hintTrackId, + char** ppPayloadName = NULL, + u_int8_t* pPayloadNumber = NULL, + u_int16_t* pMaxPayloadSize = NULL, + char **ppEncodingParams = NULL); + + void SetHintTrackRtpPayload( + MP4TrackId hintTrackId, + const char* payloadName, + u_int8_t* pPayloadNumber, + u_int16_t maxPayloadSize, + const char *encoding_params, + bool include_rtp_map, + bool include_mpeg4_esid); + + MP4TrackId GetHintTrackReferenceTrackId( + MP4TrackId hintTrackId); + + void ReadRtpHint( + MP4TrackId hintTrackId, + MP4SampleId hintSampleId, + u_int16_t* pNumPackets = NULL); + + u_int16_t GetRtpHintNumberOfPackets( + MP4TrackId hintTrackId); + + int8_t GetRtpPacketBFrame( + MP4TrackId hintTrackId, + u_int16_t packetIndex); + + int32_t GetRtpPacketTransmitOffset( + MP4TrackId hintTrackId, + u_int16_t packetIndex); + + void ReadRtpPacket( + MP4TrackId hintTrackId, + u_int16_t packetIndex, + u_int8_t** ppBytes, + u_int32_t* pNumBytes, + u_int32_t ssrc = 0, + bool includeHeader = true, + bool includePayload = true); + + MP4Timestamp GetRtpTimestampStart( + MP4TrackId hintTrackId); + + void SetRtpTimestampStart( + MP4TrackId hintTrackId, + MP4Timestamp rtpStart); + + void AddRtpHint( + MP4TrackId hintTrackId, + bool isBframe, + u_int32_t timestampOffset); + + void AddRtpPacket( + MP4TrackId hintTrackId, + bool setMbit, + int32_t transmitOffset); + + void AddRtpImmediateData( + MP4TrackId hintTrackId, + const u_int8_t* pBytes, + u_int32_t numBytes); + + void AddRtpSampleData( + MP4TrackId hintTrackId, + MP4SampleId sampleId, + u_int32_t dataOffset, + u_int32_t dataLength); + + void AddRtpESConfigurationPacket( + MP4TrackId hintTrackId); + + void WriteRtpHint( + MP4TrackId hintTrackId, + MP4Duration duration, + bool isSyncSample); + + u_int8_t AllocRtpPayloadNumber(); + + // edit list related + + char* MakeTrackEditName( + MP4TrackId trackId, + MP4EditId editId, + const char* name); + + MP4EditId AddTrackEdit( + MP4TrackId trackId, + MP4EditId editId = MP4_INVALID_EDIT_ID); + + void DeleteTrackEdit( + MP4TrackId trackId, + MP4EditId editId); + + u_int32_t GetTrackNumberOfEdits( + MP4TrackId trackId); + + MP4Timestamp GetTrackEditStart( + MP4TrackId trackId, + MP4EditId editId); + + MP4Duration GetTrackEditTotalDuration( + MP4TrackId trackId, + MP4EditId editId); + + MP4Timestamp GetTrackEditMediaStart( + MP4TrackId trackId, + MP4EditId editId); + + void SetTrackEditMediaStart( + MP4TrackId trackId, + MP4EditId editId, + MP4Timestamp startTime); + + MP4Duration GetTrackEditDuration( + MP4TrackId trackId, + MP4EditId editId); + + void SetTrackEditDuration( + MP4TrackId trackId, + MP4EditId editId, + MP4Duration duration); + + bool GetTrackEditDwell( + MP4TrackId trackId, + MP4EditId editId); + + void SetTrackEditDwell( + MP4TrackId trackId, + MP4EditId editId, + bool dwell); + + MP4SampleId GetSampleIdFromEditTime( + MP4TrackId trackId, + MP4Timestamp when, + MP4Timestamp* pStartTime = NULL, + MP4Duration* pDuration = NULL); + + /* iTunes metadata handling */ + protected: + bool CreateMetadataAtom(const char* name); + public: + // these are public to remove a lot of unnecessary routines + bool DeleteMetadataAtom(const char* name, bool try_udta = false); + bool GetMetadataString(const char *atom, char **value, bool try_udta = false); + bool SetMetadataString(const char *atom, const char *value); + bool MetadataDelete(void); + + bool SetMetadataUint8(const char *atom, u_int8_t compilation); + bool GetMetadataUint8(const char *atom, u_int8_t* compilation); + + /* set metadata */ + bool SetMetadataTrack(u_int16_t track, u_int16_t totalTracks); + bool SetMetadataDisk(u_int16_t disk, u_int16_t totalDisks); + bool SetMetadataGenre(const char *value); + bool SetMetadataTempo(u_int16_t tempo); + bool SetMetadataCoverArt(u_int8_t *coverArt, u_int32_t size, int flags); + bool SetMetadataFreeForm(const char *name, + const u_int8_t* pValue, + u_int32_t valueSize, + const char *owner = NULL); + + /* get metadata */ + bool GetMetadataByIndex(u_int32_t index, + char** ppName, // free memory when done + u_int8_t** ppValue, // free memory when done + u_int32_t* pValueSize); + bool GetMetadataTrack(u_int16_t* track, u_int16_t* totalTracks); + bool GetMetadataDisk(u_int16_t* disk, u_int16_t* totalDisks); + bool GetMetadataGenre(char **value); + bool GetMetadataTempo(u_int16_t* tempo); + bool GetMetadataCoverArt(u_int8_t **coverArt, u_int32_t* size, + uint32_t index = 0); + u_int32_t GetMetadataCoverArtCount(void); + bool GetMetadataFreeForm(const char *name, + u_int8_t** pValue, + u_int32_t* valueSize, + const char *owner = NULL); + + /* delete metadata */ + bool DeleteMetadataGenre(); + bool DeleteMetadataFreeForm(const char *name, const char *owner = NULL); + +/* 3GP metadata */ + bool Get3GPMetadataString(const char *atom, uint16_t **value); + bool Set3GPMetadataString(const char *atom, const uint16_t *value); + bool Get3GPMetadataInteger(const char *atom, uint64_t *value); + bool Set3GPMetadataInteger(const char *atom, uint64_t value); + bool Delete3GPMetadataAtom(const char* name); + + /* end of MP4 API */ + + /* "protected" interface to be used only by friends in library */ + + u_int64_t GetPosition(FILE* pFile = NULL); + void SetPosition(u_int64_t pos, FILE* pFile = NULL); + + u_int64_t GetSize(); + + void ReadBytes( + u_int8_t* pBytes, u_int32_t numBytes, FILE* pFile = NULL); + u_int64_t ReadUInt(u_int8_t size); + u_int8_t ReadUInt8(); + u_int16_t ReadUInt16(); + u_int32_t ReadUInt24(); + u_int32_t ReadUInt32(); + u_int64_t ReadUInt64(); + float ReadFixed16(); + float ReadFixed32(); + float ReadFloat(); + char* ReadString(); + uint16_t *ReadUnicodeString(); + char* ReadCountedString( + u_int8_t charSize = 1, bool allowExpandedCount = false); + u_int64_t ReadBits(u_int8_t numBits); + void FlushReadBits(); + u_int32_t ReadMpegLength(); + + void PeekBytes( + u_int8_t* pBytes, u_int32_t numBytes, FILE* pFile = NULL); + + void WriteBytes(u_int8_t* pBytes, u_int32_t numBytes, FILE* pFile = NULL); + void WriteUInt(u_int64_t value, u_int8_t bytes); + void WriteUInt8(u_int8_t value); + void WriteUInt16(u_int16_t value); + void WriteUInt24(u_int32_t value); + void WriteUInt32(u_int32_t value); + void WriteUInt64(u_int64_t value); + void WriteFixed16(float value); + void WriteFixed32(float value); + void WriteFloat(float value); + void WriteString(char* string); + void WriteUnicodeString(const uint16_t *string); + void WriteCountedString(char* string, + u_int8_t charSize = 1, bool allowExpandedCount = false); + void WriteBits(u_int64_t bits, u_int8_t numBits); + void PadWriteBits(u_int8_t pad = 0); + void FlushWriteBits(); + void WriteMpegLength(u_int32_t value, bool compact = false); + + void EnableMemoryBuffer( + u_int8_t* pBytes = NULL, u_int64_t numBytes = 0); + void DisableMemoryBuffer( + u_int8_t** ppBytes = NULL, u_int64_t* pNumBytes = NULL); + + char GetMode() { + return m_mode; + } + + MP4Track* GetTrack(MP4TrackId trackId); + + void UpdateDuration(MP4Duration duration); + + MP4Atom* FindAtomMP4File(const char* name); + + MP4Atom* AddChildAtom( + const char* parentName, + const char* childName); + + MP4Atom* AddChildAtom( + MP4Atom* pParentAtom, + const char* childName); + + MP4Atom* InsertChildAtom( + const char* parentName, + const char* childName, + u_int32_t index); + + MP4Atom* InsertChildAtom( + MP4Atom* pParentAtom, + const char* childName, + u_int32_t index); + + MP4Atom* AddDescendantAtoms( + const char* ancestorName, + const char* childName); + + MP4Atom* AddDescendantAtoms( + MP4Atom* pAncestorAtom, + const char* childName); + +protected: + void Open(const MP4_FILENAME_CHAR* fmode); + void ReadFromFile(); + void GenerateTracks(); + void BeginWrite(); + void FinishWrite(); + void CacheProperties(); + void RewriteMdat(void* pReadFile, void* pWriteFile, + Virtual_IO *readIO, Virtual_IO *writeIO); + bool ShallHaveIods(); + + const wchar_t *TempFileName(); + void Rename(const MP4_FILENAME_CHAR* existingFileName, const MP4_FILENAME_CHAR* newFileName); + + void ProtectWriteOperation(char* where); + + void FindIntegerProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex = NULL); + void FindFloatProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex = NULL); + void FindStringProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex = NULL); + void FindBytesProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex = NULL); + + bool FindProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex = NULL); + + MP4TrackId AddVideoTrackDefault( + u_int32_t timeScale, + MP4Duration sampleDuration, + u_int16_t width, + u_int16_t height, + const char *videoType); + MP4TrackId AddCntlTrackDefault( + u_int32_t timeScale, + MP4Duration sampleDuration, + const char *videoType); + void AddTrackToIod(MP4TrackId trackId); + + void RemoveTrackFromIod(MP4TrackId trackId, bool shallHaveIods = true); + + void AddTrackToOd(MP4TrackId trackId); + + void RemoveTrackFromOd(MP4TrackId trackId); + + void GetTrackReferenceProperties(const char* trefName, + MP4Property** ppCountProperty, MP4Property** ppTrackIdProperty); + + void AddTrackReference(const char* trefName, MP4TrackId refTrackId); + + u_int32_t FindTrackReference(const char* trefName, MP4TrackId refTrackId); + + void RemoveTrackReference(const char* trefName, MP4TrackId refTrackId); + + void AddDataReference(MP4TrackId trackId, const char* url); + + char* MakeTrackName(MP4TrackId trackId, const char* name); + + u_int8_t ConvertTrackTypeToStreamType(const char* trackType); + + void CreateIsmaIodFromFile( + MP4TrackId odTrackId, + MP4TrackId sceneTrackId, + MP4TrackId audioTrackId, + MP4TrackId videoTrackId, + u_int8_t** ppBytes, + u_int64_t* pNumBytes); + + void CreateESD( + MP4DescriptorProperty* pEsProperty, + u_int32_t esid, + u_int8_t objectType, + u_int8_t streamType, + u_int32_t bufferSize, + u_int32_t bitrate, + const u_int8_t* pConfig, + u_int32_t configLength, + char* url); + + void CreateIsmaODUpdateCommandFromFileForFile( + MP4TrackId odTrackId, + MP4TrackId audioTrackId, + MP4TrackId videoTrackId, + u_int8_t** ppBytes, + u_int64_t* pNumBytes); + + void CreateIsmaODUpdateCommandFromFileForStream( + MP4TrackId audioTrackId, + MP4TrackId videoTrackId, + u_int8_t** ppBytes, + u_int64_t* pNumBytes); + + void CreateIsmaODUpdateCommandForStream( + MP4DescriptorProperty* pAudioEsdProperty, + MP4DescriptorProperty* pVideoEsdProperty, + u_int8_t** ppBytes, + u_int64_t* pNumBytes); + + void CreateIsmaSceneCommand( + bool hasAudio, + bool hasVideo, + u_int8_t** ppBytes, + u_int64_t* pNumBytes); + +protected: + MP4_FILENAME_CHAR *m_fileName; + + void* m_pFile; + Virtual_IO *m_virtual_IO; + u_int64_t m_orgFileSize; + u_int64_t m_fileSize; + MP4Atom* m_pRootAtom; + MP4Integer32Array m_trakIds; + MP4TrackArray m_pTracks; + MP4TrackId m_odTrackId; + u_int32_t m_verbosity; + char m_mode; + u_int32_t m_createFlags; + bool m_useIsma; + + // cached properties + MP4IntegerProperty* m_pModificationProperty; + MP4Integer32Property* m_pTimeScaleProperty; + MP4IntegerProperty* m_pDurationProperty; + + // read/write in memory + u_int8_t* m_memoryBuffer; + u_int64_t m_memoryBufferPosition; + u_int64_t m_memoryBufferSize; + + // bit read/write buffering + u_int8_t m_numReadBits; + u_int8_t m_bufReadBits; + u_int8_t m_numWriteBits; + u_int8_t m_bufWriteBits; + +#ifndef _WIN32 + char m_tempFileName[64]; +#else + wchar_t m_tempFileName[MAX_PATH]; +#endif + char m_trakName[1024]; + char *m_editName; +}; + +#endif /* __MP4_FILE_INCLUDED__ */ diff --git a/Src/external_dependencies/libmp4v2/mp4file_io.cpp b/Src/external_dependencies/libmp4v2/mp4file_io.cpp new file mode 100644 index 00000000..688470ac --- /dev/null +++ b/Src/external_dependencies/libmp4v2/mp4file_io.cpp @@ -0,0 +1,655 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +// MP4File low level IO support + +u_int64_t MP4File::GetPosition(FILE* pFile) +{ + if (m_memoryBuffer == NULL) { + if (pFile == NULL) { + ASSERT(m_pFile); + u_int64_t fpos; + if (m_virtual_IO->GetPosition(m_pFile, &fpos) != 0) { + throw new MP4Error("getting position via Virtual I/O", "MP4GetPosition"); + } + return fpos; + } else { + fpos_t fpos; + if (fgetpos(pFile, &fpos) < 0) { + throw new MP4Error(errno, "MP4GetPosition"); + } + uint64_t ret; + FPOS_TO_VAR(fpos, uint64_t, ret); + return ret; + } + } else { + return m_memoryBufferPosition; + } +} + +void MP4File::SetPosition(u_int64_t pos, FILE* pFile) +{ + if (m_memoryBuffer == NULL) { + if (pFile == NULL) { + ASSERT(m_pFile); + if (m_virtual_IO->SetPosition(m_pFile, pos) != 0) { + throw new MP4Error("setting position via Virtual I/O", "MP4SetPosition"); + } + } else { + fpos_t fpos; + VAR_TO_FPOS(fpos, pos); + if (fsetpos(pFile, &fpos) < 0) { + throw new MP4Error(errno, "MP4SetPosition"); + } + } + } else { + if (pos >= m_memoryBufferSize) { + // abort(); + throw new MP4Error("position out of range", "MP4SetPosition"); + } + m_memoryBufferPosition = pos; + } +} + +u_int64_t MP4File::GetSize() +{ + if (m_mode == 'w') { + // we're always positioned at the end of file in write mode + // except for short intervals in ReadSample and FinishWrite routines + // so we rely on the faster approach of GetPosition() + // instead of flushing to disk, and then stat'ing the file + m_fileSize = GetPosition(); + } // else read mode, fileSize was determined at Open() + + return m_fileSize; +} + +void MP4File::ReadBytes(u_int8_t* pBytes, u_int32_t numBytes, FILE* pFile) +{ + // handle degenerate cases + if (numBytes == 0) { + return; + } + + ASSERT(pBytes); + WARNING(m_numReadBits > 0); + + if (m_memoryBuffer == NULL) { + if (pFile == NULL) { + ASSERT(m_pFile); + if (m_virtual_IO->Read(m_pFile, pBytes, numBytes) != numBytes) { + throw new MP4Error("not enough bytes, reached end-of-file", "MP4ReadBytes"); + } + } else { + if (fread(pBytes, 1, numBytes, pFile) != numBytes) { + if (feof(pFile)) { + throw new MP4Error( + "not enough bytes, reached end-of-file", + "MP4ReadBytes"); + } else { + throw new MP4Error(errno, "MP4ReadBytes"); + } + } + } + } else { + if (m_memoryBufferPosition + numBytes > m_memoryBufferSize) { + throw new MP4Error( + "not enough bytes, reached end-of-memory", + "MP4ReadBytes"); + } + memcpy(pBytes, &m_memoryBuffer[m_memoryBufferPosition], numBytes); + m_memoryBufferPosition += numBytes; + } + return; +} + +void MP4File::PeekBytes(u_int8_t* pBytes, u_int32_t numBytes, FILE* pFile) +{ + u_int64_t pos = GetPosition(pFile); + ReadBytes(pBytes, numBytes, pFile); + SetPosition(pos, pFile); +} + +void MP4File::EnableMemoryBuffer(u_int8_t* pBytes, u_int64_t numBytes) +{ + ASSERT(m_memoryBuffer == NULL); + + if (pBytes) { + m_memoryBuffer = pBytes; + m_memoryBufferSize = numBytes; + } else { + if (numBytes) { + m_memoryBufferSize = numBytes; + } else { + m_memoryBufferSize = 4096; + } + m_memoryBuffer = (u_int8_t*)MP4Malloc(m_memoryBufferSize); + } + m_memoryBufferPosition = 0; +} + +void MP4File::DisableMemoryBuffer(u_int8_t** ppBytes, u_int64_t* pNumBytes) +{ + ASSERT(m_memoryBuffer != NULL); + + if (ppBytes) { + *ppBytes = m_memoryBuffer; + } + if (pNumBytes) { + *pNumBytes = m_memoryBufferPosition; + } + + m_memoryBuffer = NULL; + m_memoryBufferSize = 0; + m_memoryBufferPosition = 0; +} + +void MP4File::WriteBytes(u_int8_t* pBytes, u_int32_t numBytes, FILE* pFile) +{ + ASSERT(m_numWriteBits == 0 || m_numWriteBits >= 8); + + if (pBytes == NULL || numBytes == 0) { + return; + } + + if (m_memoryBuffer == NULL) { + if (pFile == NULL) { + ASSERT(m_pFile); + if (m_virtual_IO->Write(m_pFile, pBytes, numBytes) != numBytes) { + throw new MP4Error("error writing bytes via virtual I/O", "MP4WriteBytes"); + } + } else { + u_int32_t rc = (u_int32_t)fwrite(pBytes, 1, numBytes, pFile); + if (rc != numBytes) { + throw new MP4Error(errno, "MP4WriteBytes"); + } + } + } else { + if (m_memoryBufferPosition + numBytes > m_memoryBufferSize) { + m_memoryBufferSize = 2 * (m_memoryBufferSize + numBytes); + m_memoryBuffer = (u_int8_t*) + MP4Realloc(m_memoryBuffer, m_memoryBufferSize); + } + memcpy(&m_memoryBuffer[m_memoryBufferPosition], pBytes, numBytes); + m_memoryBufferPosition += numBytes; + } +} + +u_int64_t MP4File::ReadUInt(u_int8_t size) +{ + switch (size) { + case 1: + return ReadUInt8(); + case 2: + return ReadUInt16(); + case 3: + return ReadUInt24(); + case 4: + return ReadUInt32(); + case 8: + return ReadUInt64(); + default: + ASSERT(false); + return 0; + } +} + +void MP4File::WriteUInt(u_int64_t val, u_int8_t size) +{ + switch (size) { + case 1: + WriteUInt8((u_int8_t)val); + break; + case 2: + WriteUInt16((u_int16_t)val); + break; + case 3: + WriteUInt24((u_int32_t)val); + break; + case 4: + WriteUInt32((u_int32_t)val); + break; + case 8: + WriteUInt64((u_int64_t)val); + break; + default: + ASSERT(false); + break; + } +} + +#if 0 +void MP4File::WriteUInt(u_int64_t value, u_int8_t size) +{ + switch (size) { + case 1: + WriteUInt8(value); + case 2: + WriteUInt16(value); + case 3: + WriteUInt24(value); + case 4: + WriteUInt32(value); + case 8: + WriteUInt64(value); + default: + ASSERT(false); + } +} +#endif + +u_int8_t MP4File::ReadUInt8() +{ + u_int8_t data; + ReadBytes(&data, 1); + return data; +} + +void MP4File::WriteUInt8(u_int8_t value) +{ + WriteBytes(&value, 1); +} + +u_int16_t MP4File::ReadUInt16() +{ + u_int8_t data[2]; + ReadBytes(&data[0], 2); + return ((data[0] << 8) | data[1]); +} + +void MP4File::WriteUInt16(u_int16_t value) +{ + u_int8_t data[2]; + data[0] = (value >> 8) & 0xFF; + data[1] = value & 0xFF; + WriteBytes(data, 2); +} + +u_int32_t MP4File::ReadUInt24() +{ + u_int8_t data[3]; + ReadBytes(&data[0], 3); + return ((data[0] << 16) | (data[1] << 8) | data[2]); +} + +void MP4File::WriteUInt24(u_int32_t value) +{ + u_int8_t data[3]; + data[0] = (value >> 16) & 0xFF; + data[1] = (value >> 8) & 0xFF; + data[2] = value & 0xFF; + WriteBytes(data, 3); +} + +u_int32_t MP4File::ReadUInt32() +{ + u_int8_t data[4]; + ReadBytes(&data[0], 4); + return ((data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]); +} + +void MP4File::WriteUInt32(u_int32_t value) +{ + u_int8_t data[4]; + data[0] = (value >> 24) & 0xFF; + data[1] = (value >> 16) & 0xFF; + data[2] = (value >> 8) & 0xFF; + data[3] = value & 0xFF; + WriteBytes(data, 4); +} + +u_int64_t MP4File::ReadUInt64() +{ + u_int8_t data[8]; + u_int64_t result = 0; + u_int64_t temp; + + ReadBytes(&data[0], 8); + + for (int i = 0; i < 8; i++) { + temp = data[i]; + result |= temp << ((7 - i) * 8); + } + return result; +} + +void MP4File::WriteUInt64(u_int64_t value) +{ + u_int8_t data[8]; + + for (int i = 7; i >= 0; i--) { + data[i] = value & 0xFF; + value >>= 8; + } + WriteBytes(data, 8); +} + +float MP4File::ReadFixed16() +{ + u_int8_t iPart = ReadUInt8(); + u_int8_t fPart = ReadUInt8(); + + return iPart + (((float)fPart) / 0x100); +} + +void MP4File::WriteFixed16(float value) +{ + if (value >= 0x100) { + throw new MP4Error(ERANGE, "MP4WriteFixed16"); + } + + u_int8_t iPart = (u_int8_t)value; + u_int8_t fPart = (u_int8_t)((value - iPart) * 0x100); + + WriteUInt8(iPart); + WriteUInt8(fPart); +} + +float MP4File::ReadFixed32() +{ + u_int16_t iPart = ReadUInt16(); + u_int16_t fPart = ReadUInt16(); + + return iPart + (((float)fPart) / 0x10000); +} + +void MP4File::WriteFixed32(float value) +{ + if (value >= 0x10000) { + throw new MP4Error(ERANGE, "MP4WriteFixed32"); + } + + u_int16_t iPart = (u_int16_t)value; + u_int16_t fPart = (u_int16_t)((value - iPart) * 0x10000); + + WriteUInt16(iPart); + WriteUInt16(fPart); +} + +float MP4File::ReadFloat() +{ + union { + float f; + u_int32_t i; + } u; + + u.i = ReadUInt32(); + return u.f; +} + +void MP4File::WriteFloat(float value) +{ + union { + float f; + u_int32_t i; + } u; + + u.f = value; + WriteUInt32(u.i); +} + +char* MP4File::ReadString() +{ + uint32_t readSize=1; + u_int32_t length = 0; + u_int32_t alloced = 64; + uint8_t* data = (uint8_t*)MP4Malloc(alloced); + + ReadBytes((u_int8_t*)&data[length++], 1); + if (data[0] == 0xFF || data[0] == 0xFE) + { + ReadBytes((u_int8_t*)&data[length++], 1); + if ((data[0] == 0xFF && data[1] == 0xFE) + || (data[0] == 0xFE && data[1] == 0xFF)) + readSize=2; // Unicode + } + + while (1) + { + if (readSize == 1 && data[length - 1] == 0) + break; + if (readSize == 2) + { + uint16_t *utf16 = (uint16_t *)data; + if (utf16[length/2 - 1] == 0) + break; + } + + if (length == alloced) { + data = (uint8_t*)MP4Realloc(data, alloced * 2); + if (data == NULL) return NULL; + alloced *= 2; + } + ReadBytes((u_int8_t*)&data[length], readSize); + length+=readSize; + } + + data = (uint8_t*)MP4Realloc(data, length); + return (char *)data; +} + +uint16_t *MP4File::ReadUnicodeString() +{ + u_int32_t length = 0; + u_int32_t alloced = 64; + uint16_t *data = (uint16_t *)MP4Malloc(alloced*sizeof(uint16_t)); + + do { + if (length == alloced) { + data = (uint16_t *)MP4Realloc(data, (alloced * 2)*sizeof(uint16_t)); + if (data == NULL) return NULL; + alloced *= 2; + } + ReadBytes((u_int8_t *)&data[length], 2); + length++; + } while (data[length - 1] != 0); + + data = (uint16_t *)MP4Realloc(data, length*sizeof(uint16_t)); + return data; +} + +void MP4File::WriteString(char* string) +{ + if (string == NULL) { + u_int8_t zero = 0; + WriteBytes(&zero, 1); + } else { + WriteBytes((u_int8_t*)string, (u_int32_t)strlen(string) + 1); + } +} + +void MP4File::WriteUnicodeString(const uint16_t *string) +{ + if (string == NULL) { + u_int8_t zero = 0; + WriteBytes(&zero, 1); + } else { + const uint16_t *itr = string; + int len=0; + while (*itr) + { + itr++; + len++; + } + WriteBytes((u_int8_t*)string, (len + 1)*sizeof(uint16_t)); + } +} + +char* MP4File::ReadCountedString(u_int8_t charSize, bool allowExpandedCount) +{ + u_int32_t charLength; + if (allowExpandedCount) { + u_int8_t b; + uint ix = 0; + charLength = 0; + do { + b = ReadUInt8(); + charLength += b; + ix++; + if (ix > 25) + throw new MP4Error(ERANGE, + "Counted string too long 25 * 255"); + } while (b == 255); + } else { + charLength = ReadUInt8(); + } + + u_int32_t byteLength = charLength * charSize; + char* data = (char*)MP4Malloc(byteLength + 1); + if (byteLength > 0) { + ReadBytes((u_int8_t*)data, byteLength); + } + data[byteLength] = '\0'; + return data; +} + +void MP4File::WriteCountedString(char* string, + u_int8_t charSize, bool allowExpandedCount) +{ + u_int32_t byteLength; + if (string) { + byteLength = (u_int32_t)strlen(string); + } else { + byteLength = 0; + } + u_int32_t charLength = byteLength / charSize; + + if (allowExpandedCount) { + while (charLength >= 0xFF) { + WriteUInt8(0xFF); + charLength -= 0xFF; + } + WriteUInt8(charLength); + } else { + if (charLength > 255) { + throw new MP4Error(ERANGE, "Length is %d", "MP4WriteCountedString", charLength); + } + WriteUInt8(charLength); + } + + if (byteLength > 0) { + WriteBytes((u_int8_t*)string, byteLength); + } +} + +u_int64_t MP4File::ReadBits(u_int8_t numBits) +{ + ASSERT(numBits > 0); + ASSERT(numBits <= 64); + + u_int64_t bits = 0; + + for (u_int8_t i = numBits; i > 0; i--) { + if (m_numReadBits == 0) { + ReadBytes(&m_bufReadBits, 1); + m_numReadBits = 8; + } + bits = (bits << 1) | ((m_bufReadBits >> (--m_numReadBits)) & 1); + } + + return bits; +} + +void MP4File::FlushReadBits() +{ + // eat any remaining bits in the read buffer + m_numReadBits = 0; +} + +void MP4File::WriteBits(u_int64_t bits, u_int8_t numBits) +{ + ASSERT(numBits <= 64); + + for (u_int8_t i = numBits; i > 0; i--) { + m_bufWriteBits |= + (((bits >> (i - 1)) & 1) << (8 - ++m_numWriteBits)); + + if (m_numWriteBits == 8) { + FlushWriteBits(); + } + } +} + +void MP4File::PadWriteBits(u_int8_t pad) +{ + if (m_numWriteBits) { + WriteBits(pad ? 0xFF : 0x00, 8 - m_numWriteBits); + } +} + +void MP4File::FlushWriteBits() +{ + if (m_numWriteBits > 0) { + WriteBytes(&m_bufWriteBits, 1); + m_numWriteBits = 0; + m_bufWriteBits = 0; + } +} + +u_int32_t MP4File::ReadMpegLength() +{ + u_int32_t length = 0; + u_int8_t numBytes = 0; + u_int8_t b; + + do { + b = ReadUInt8(); + length = (length << 7) | (b & 0x7F); + numBytes++; + } while ((b & 0x80) && numBytes < 4); + + return length; +} + +void MP4File::WriteMpegLength(u_int32_t value, bool compact) +{ + if (value > 0x0FFFFFFF) { + throw new MP4Error(ERANGE, "MP4WriteMpegLength"); + } + + int8_t numBytes; + + if (compact) { + if (value <= 0x7F) { + numBytes = 1; + } else if (value <= 0x3FFF) { + numBytes = 2; + } else if (value <= 0x1FFFFF) { + numBytes = 3; + } else { + numBytes = 4; + } + } else { + numBytes = 4; + } + + int8_t i = numBytes; + do { + i--; + u_int8_t b = (value >> (i * 7)) & 0x7F; + if (i > 0) { + b |= 0x80; + } + WriteUInt8(b); + } while (i > 0); +} diff --git a/Src/external_dependencies/libmp4v2/mp4info.cpp b/Src/external_dependencies/libmp4v2/mp4info.cpp new file mode 100644 index 00000000..a9981620 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/mp4info.cpp @@ -0,0 +1,688 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001-2002. All Rights Reserved. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + * Bill May wmay@cisco.com + * Alix Marchandise-Franquet alix@cisco.com + * Ximpo Group Ltd. mp4v2@ximpo.com + */ + +#include "mp4common.h" + +extern "C" char* MP4PrintAudioInfo( + MP4FileHandle mp4File, + MP4TrackId trackId) +{ + static const char* mpeg4AudioNames[] = + { + "MPEG-4 AAC main", + "MPEG-4 AAC LC", + "MPEG-4 AAC SSR", + "MPEG-4 AAC LTP", + "MPEG-4 AAC HE", + "MPEG-4 AAC Scalable", + "MPEG-4 TwinVQ", + "MPEG-4 CELP", + "MPEG-4 HVXC", + NULL, NULL, + "MPEG-4 TTSI", + "MPEG-4 Main Synthetic", + "MPEG-4 Wavetable Syn", + "MPEG-4 General MIDI", + "MPEG-4 Algo Syn and Audio FX", + "MPEG-4 ER AAC LC", + NULL, + "MPEG-4 ER AAC LTP", + "MPEG-4 ER AAC Scalable", + "MPEG-4 ER TwinVQ", + "MPEG-4 ER BSAC", + "MPEG-4 ER ACC LD", + "MPEG-4 ER CELP", + "MPEG-4 ER HVXC", + "MPEG-4 ER HILN", + "MPEG-4 ER Parametric", + "MPEG-4 SSC", + "MPEG-4 PS", + "MPEG-4 MPEG Surround", + NULL, + "MPEG-4 Layer-1", + "MPEG-4 Layer-2", + "MPEG-4 Layer-3", + "MPEG-4 DST", + "MPEG-4 Audio Lossless", + "MPEG-4 SLS", + "MPEG-4 SLS non-core", + }; + + static const u_int8_t mpegAudioTypes[] = + { + MP4_MPEG2_AAC_MAIN_AUDIO_TYPE, // 0x66 + MP4_MPEG2_AAC_LC_AUDIO_TYPE, // 0x67 + MP4_MPEG2_AAC_SSR_AUDIO_TYPE, // 0x68 + MP4_MPEG2_AUDIO_TYPE, // 0x69 + MP4_MPEG1_AUDIO_TYPE, // 0x6B + // private types + MP4_PCM16_LITTLE_ENDIAN_AUDIO_TYPE, + MP4_VORBIS_AUDIO_TYPE, + MP4_ALAW_AUDIO_TYPE, + MP4_ULAW_AUDIO_TYPE, + MP4_G723_AUDIO_TYPE, + MP4_PCM16_BIG_ENDIAN_AUDIO_TYPE, + }; + static const char* mpegAudioNames[] = + { + "MPEG-2 AAC Main", + "MPEG-2 AAC LC", + "MPEG-2 AAC SSR", + "MPEG-2 Audio (13818-3)", + "MPEG-1 Audio (11172-3)", + // private types + "PCM16 (little endian)", + "Vorbis", + "G.711 aLaw", + "G.711 uLaw", + "G.723.1", + "PCM16 (big endian)", + }; + u_int8_t numMpegAudioTypes = + sizeof(mpegAudioTypes) / sizeof(u_int8_t); + + const char* typeName = "Unknown"; + bool foundType = false; + u_int8_t type = 0; + const char *media_data_name; + + media_data_name = MP4GetTrackMediaDataName(mp4File, trackId); + u_int32_t timeScale = 0; + if (media_data_name == NULL) + { + typeName = "Unknown - no media data name"; + } + else if (strcasecmp(media_data_name, "samr") == 0) + { + typeName = "AMR"; + foundType = true; + } + else if (strcasecmp(media_data_name, "sawb") == 0) + { + typeName = "AMR-WB"; + foundType = true; + } + else if (strcasecmp(media_data_name, "mp4a") == 0) + { + + type = MP4GetTrackEsdsObjectTypeId(mp4File, trackId); + switch (type) + { + case MP4_INVALID_AUDIO_TYPE: + typeName = "AAC from .mov"; + foundType = true; + break; + case MP4_MPEG4_AUDIO_TYPE: + { + type = MP4GetTrackAudioMpeg4Type(mp4File, trackId); + if (type == MP4_MPEG4_INVALID_AUDIO_TYPE || + type > NUM_ELEMENTS_IN_ARRAY(mpeg4AudioNames) || + mpeg4AudioNames[type - 1] == NULL) + { + typeName = "MPEG-4 Unknown Profile"; + } + else + { + if (type == 2) + { + u_int8_t* pAacConfig = NULL; + u_int32_t aacConfigLength; + + MP4GetTrackESConfiguration(mp4File, + trackId, + &pAacConfig, + &aacConfigLength); + + if (aacConfigLength >= 5 && (pAacConfig[4] >> 7) == 1) + { + int samplingRates[]={96000,88200,64000,48000,44100,32000,24000,22050,16000,12000,11025,8000,-1}; + type = 5; + int index = (pAacConfig[4] >> 3) & 0x7; + timeScale = samplingRates[index]; + } + MP4Free(pAacConfig); + } + typeName = mpeg4AudioNames[type - 1]; + foundType = true; + } + break; + } + // fall through + default: + for (u_int8_t i = 0; i < numMpegAudioTypes; i++) + { + if (type == mpegAudioTypes[i]) + { + typeName = mpegAudioNames[i]; + foundType = true; + break; + } + } + } + } + else + { + typeName = media_data_name; + foundType = true; + } + + if (!timeScale) + timeScale = MP4GetTrackTimeScale(mp4File, trackId); + + MP4Duration trackDuration = + MP4GetTrackDuration(mp4File, trackId); + + double msDuration = + UINT64_TO_DOUBLE(MP4ConvertFromTrackDuration(mp4File, trackId, + trackDuration, MP4_MSECS_TIME_SCALE)); + + + char *sInfo = (char*)MP4Malloc(256); + + // type duration avgBitrate samplingFrequency + if (foundType) + snprintf(sInfo, 256, + "%s", + typeName); + else + snprintf(sInfo, 256, + "%s(%u)", + typeName, + type); + + return sInfo; +} +static const struct +{ + uint8_t profile; + const char *name; +} +VisualProfileToName[] = { + { MPEG4_SP_L1, "MPEG-4 Simple @ L1"}, + { MPEG4_SP_L2, "MPEG-4 Simple @ L2" }, + { MPEG4_SP_L3, "MPEG-4 Simple @ L3" }, + { MPEG4_SP_L0, "MPEG-4 Simple @ L0" }, + { MPEG4_SSP_L1, "MPEG-4 Simple Scalable @ L1"}, + { MPEG4_SSP_L2, "MPEG-4 Simple Scalable @ L2" }, + { MPEG4_CP_L1, "MPEG-4 Core @ L1"}, + { MPEG4_CP_L2, "MPEG-4 Core @ L2"}, + { MPEG4_MP_L2, "MPEG-4 Main @ L2"}, + { MPEG4_MP_L3, "MPEG-4 Main @ L3"}, + { MPEG4_MP_L4, "MPEG-4 Main @ L4"}, + { MPEG4_NBP_L2, "MPEG-4 N-bit @ L2"}, + { MPEG4_STP_L1, "MPEG-4 Scalable Texture @ L1"}, + { MPEG4_SFAP_L1, "MPEG-4 Simple Face Anim @ L1"}, + { MPEG4_SFAP_L2, "MPEG-4 Simple Face Anim @ L2"}, + { MPEG4_SFBAP_L1, "MPEG-4 Simple FBA @ L1"}, + { MPEG4_SFBAP_L2, "MPEG-4 Simple FBA @ L2"}, + { MPEG4_BATP_L1, "MPEG-4 Basic Anim Text @ L1"}, + { MPEG4_BATP_L2, "MPEG-4 Basic Anim Text @ L2"}, + { MPEG4_HP_L1, "MPEG-4 Hybrid @ L1"}, + { MPEG4_HP_L2, "MPEG-4 Hybrid @ L2"}, + { MPEG4_ARTSP_L1, "MPEG-4 Adv RT Simple @ L1"}, + { MPEG4_ARTSP_L2, "MPEG-4 Adv RT Simple @ L2"}, + { MPEG4_ARTSP_L3, "MPEG-4 Adv RT Simple @ L3"}, + { MPEG4_ARTSP_L4, "MPEG-4 Adv RT Simple @ L4"}, + { MPEG4_CSP_L1, "MPEG-4 Core Scalable @ L1"}, + { MPEG4_CSP_L2, "MPEG-4 Core Scalable @ L2"}, + { MPEG4_CSP_L3, "MPEG-4 Core Scalable @ L3"}, + { MPEG4_ACEP_L1, "MPEG-4 Adv Coding Efficieny @ L1"}, + { MPEG4_ACEP_L2, "MPEG-4 Adv Coding Efficieny @ L2"}, + { MPEG4_ACEP_L3, "MPEG-4 Adv Coding Efficieny @ L3"}, + { MPEG4_ACEP_L4, "MPEG-4 Adv Coding Efficieny @ L4"}, + { MPEG4_ACP_L1, "MPEG-4 Adv Core Profile @ L1"}, + { MPEG4_ACP_L2, "MPEG-4 Adv Core Profile @ L2"}, + { MPEG4_AST_L1, "MPEG-4 Adv Scalable Texture @ L1"}, + { MPEG4_AST_L2, "MPEG-4 Adv Scalable Texture @ L2"}, + { MPEG4_AST_L3, "MPEG-4 Adv Scalable Texture @ L3"}, + { MPEG4_S_STUDIO_P_L1, "MPEG-4 Simple Studio @ L1"}, + { MPEG4_S_STUDIO_P_L2, "MPEG-4 Simple Studio @ L2"}, + { MPEG4_S_STUDIO_P_L3, "MPEG-4 Simple Studio @ L3"}, + { MPEG4_S_STUDIO_P_L4, "MPEG-4 Simple Studio @ L4"}, + { MPEG4_C_STUDIO_P_L1, "MPEG-4 Core Studio @ L1"}, + { MPEG4_C_STUDIO_P_L2, "MPEG-4 Core Studio @ L2"}, + { MPEG4_C_STUDIO_P_L3, "MPEG-4 Core Studio @ L3"}, + { MPEG4_C_STUDIO_P_L4, "MPEG-4 Core Studio @ L4"}, + { MPEG4_ASP_L0, "MPEG-4 Adv Simple@L0"}, + { MPEG4_ASP_L1, "MPEG-4 Adv Simple@L1"}, + { MPEG4_ASP_L2, "MPEG-4 Adv Simple@L2"}, + { MPEG4_ASP_L3, "MPEG-4 Adv Simple@L3"}, + { MPEG4_ASP_L4, "MPEG-4 Adv Simple@L4"}, + { MPEG4_ASP_L5, "MPEG-4 Adv Simple@L5"}, + { MPEG4_ASP_L3B, "MPEG-4 Adv Simple@L3b"}, + { MPEG4_FGSP_L0, "MPEG-4 FGS @ L0" }, + { MPEG4_FGSP_L1, "MPEG-4 FGS @ L1" }, + { MPEG4_FGSP_L2, "MPEG-4 FGS @ L2" }, + { MPEG4_FGSP_L3, "MPEG-4 FGS @ L3" }, + { MPEG4_FGSP_L4, "MPEG-4 FGS @ L4" }, + { MPEG4_FGSP_L5, "MPEG-4 FGS @ L5" } + }; + +static const char *Mpeg4VisualProfileName(uint8_t visual_profile) +{ + size_t size = sizeof(VisualProfileToName) / sizeof(*VisualProfileToName); + + for (size_t ix = 0; ix < size; ix++) + { + if (visual_profile == VisualProfileToName[ix].profile) + { + return (VisualProfileToName[ix].name); + } + } + return (NULL); +} +extern "C" char* MP4PrintVideoInfo( + MP4FileHandle mp4File, + MP4TrackId trackId) +{ + + static const u_int8_t mpegVideoTypes[] = + { + MP4_MPEG2_SIMPLE_VIDEO_TYPE, // 0x60 + MP4_MPEG2_MAIN_VIDEO_TYPE, // 0x61 + MP4_MPEG2_SNR_VIDEO_TYPE, // 0x62 + MP4_MPEG2_SPATIAL_VIDEO_TYPE, // 0x63 + MP4_MPEG2_HIGH_VIDEO_TYPE, // 0x64 + MP4_MPEG2_442_VIDEO_TYPE, // 0x65 + MP4_MPEG1_VIDEO_TYPE, // 0x6A + MP4_JPEG_VIDEO_TYPE, // 0x6C + MP4_YUV12_VIDEO_TYPE, + MP4_H263_VIDEO_TYPE, + MP4_H261_VIDEO_TYPE, + }; + static const char* mpegVideoNames[] = + { + "MPEG-2 Simple", + "MPEG-2 Main", + "MPEG-2 SNR", + "MPEG-2 Spatial", + "MPEG-2 High", + "MPEG-2 4:2:2", + "MPEG-1", + "JPEG", + "YUV12", + "H.263", + "H.261", + }; + u_int8_t numMpegVideoTypes = + sizeof(mpegVideoTypes) / sizeof(u_int8_t); + bool foundTypeName = false; + const char* typeName = "Unknown"; + + const char *media_data_name; + char originalFormat[8]; + char oformatbuffer[32]; + originalFormat[0] = 0; + *oformatbuffer = 0; + uint8_t type = 0; + + media_data_name = MP4GetTrackMediaDataName(mp4File, trackId); + // encv 264b + if (media_data_name && strcasecmp(media_data_name, "encv") == 0) + { + if (MP4GetTrackMediaDataOriginalFormat(mp4File, + trackId, + originalFormat, + sizeof(originalFormat)) == false) + media_data_name = NULL; + } + + char typebuffer[80]; + if (media_data_name == NULL) + { + typeName = "Unknown - no media data name"; + foundTypeName = true; + } + else if ((strcasecmp(media_data_name, "avc1") == 0) || + (strcasecmp(originalFormat, "264b") == 0)) + { + // avc + uint8_t profile, level; + char profileb[20], levelb[20]; + if (MP4GetTrackH264ProfileLevel(mp4File, trackId, + &profile, &level)) + { + if (profile == 44) + { + strcpy(profileb, "CAVLC 4:4:4"); + } + else if (profile == 66) + { + strcpy(profileb, "Baseline"); + } + else if (profile == 77) + { + strcpy(profileb, "Main"); + } + else if (profile == 88) + { + strcpy(profileb, "Extended"); + } + else if (profile == 100) + { + strcpy(profileb, "High"); + } + else if (profile == 110) + { + strcpy(profileb, "High 10"); + } + else if (profile == 122) + { + strcpy(profileb, "High 4:2:2"); + } + else if (profile == 144 || profile == 244) + { + strcpy(profileb, "High 4:4:4"); + } + else + { + snprintf(profileb, 20, "Unknown Profile %x", profile); + } + switch (level) + { +case 10: case 20: case 30: case 40: case 50: + snprintf(levelb, 20, "%u", level / 10); + break; + case 11: case 12: case 13: + case 21: case 22: + case 31: case 32: + case 41: case 42: + case 51: + snprintf(levelb, 20, "%u.%u", level / 10, level % 10); + break; + default: + snprintf(levelb, 20, "unknown level %x", level); + break; + } + if (originalFormat != NULL && originalFormat[0] != '\0') + snprintf(oformatbuffer, 32, "(%s) ", originalFormat); + snprintf(typebuffer, sizeof(typebuffer), "H.264 %s%s@%s", + oformatbuffer, profileb, levelb); + typeName = typebuffer; + } + else + { + typeName = "H.264 - profile/level error"; + } + foundTypeName = true; + } + else if (strcasecmp(media_data_name, "s263") == 0) + { + // 3gp h.263 + typeName = "H.263"; + foundTypeName = true; + } + else if ((strcasecmp(media_data_name, "mp4v") == 0) || + (strcasecmp(media_data_name, "encv") == 0)) + { + // note encv might needs it's own field eventually. + type = MP4GetTrackEsdsObjectTypeId(mp4File, trackId); + if (type == MP4_MPEG4_VIDEO_TYPE) + { + type = MP4GetVideoProfileLevel(mp4File, trackId); + typeName = Mpeg4VisualProfileName(type); + if (typeName == NULL) + { + typeName = "MPEG-4 Unknown Profile"; + } + else + { + foundTypeName = true; + } + } + else + { + for (u_int8_t i = 0; i < numMpegVideoTypes; i++) + { + if (type == mpegVideoTypes[i]) + { + typeName = mpegVideoNames[i]; + foundTypeName = true; + break; + } + } + } + } + else + { + typeName = media_data_name; + foundTypeName = true; // we don't have a type value to display + } + + MP4Duration trackDuration = + MP4GetTrackDuration(mp4File, trackId); + + double msDuration = + UINT64_TO_DOUBLE(MP4ConvertFromTrackDuration(mp4File, trackId, + trackDuration, MP4_MSECS_TIME_SCALE)); + + + // Note not all mp4 implementations set width and height correctly + // The real answer can be buried inside the ES configuration info + u_int16_t width = MP4GetTrackVideoWidth(mp4File, trackId); + + u_int16_t height = MP4GetTrackVideoHeight(mp4File, trackId); + + double fps = MP4GetTrackVideoFrameRate(mp4File, trackId); + + char *sInfo = (char*)MP4Malloc(256); + + // type duration avgBitrate frameSize frameRate + if (foundTypeName) + { + sprintf(sInfo, + "%s", + typeName); + } + else + { + sprintf(sInfo, + "%s(%u)", + typeName, + type); + } + + return sInfo; +} +static char* PrintCntlInfo( + MP4FileHandle mp4File, + MP4TrackId trackId) +{ + const char *media_data_name = MP4GetTrackMediaDataName(mp4File, trackId); + const char *typeName = "Unknown"; + + if (media_data_name == NULL) + { + typeName = "Unknown - no media data name"; + } + else if (strcasecmp(media_data_name, "href") == 0) + { + typeName = "ISMA Href"; + } + else + { + typeName = media_data_name; + } + + MP4Duration trackDuration = + MP4GetTrackDuration(mp4File, trackId); + + double msDuration = + UINT64_TO_DOUBLE(MP4ConvertFromTrackDuration(mp4File, trackId, + trackDuration, MP4_MSECS_TIME_SCALE)); + char *sInfo = (char *)MP4Malloc(256); + + snprintf(sInfo, 256, + "%u\tcontrol\t%s, %.3f secs\r\n", + trackId, + typeName, + msDuration / 1000.0); + return sInfo; +} + + +static char* PrintHintInfo( + MP4FileHandle mp4File, + MP4TrackId trackId) +{ + MP4TrackId referenceTrackId = + MP4GetHintTrackReferenceTrackId(mp4File, trackId); + + char* payloadName = NULL; + if (!MP4GetHintTrackRtpPayload(mp4File, trackId, &payloadName)) + return NULL; + + char *sInfo = (char*)MP4Malloc(256); + + snprintf(sInfo, 256, + "%u\thint\tPayload %s for track %u\r\n", + trackId, + payloadName, + referenceTrackId); + + free(payloadName); + + return sInfo; +} +#if 0 +static char* PrintTrackInfo( + MP4FileHandle mp4File, + MP4TrackId trackId) +{ + char* trackInfo = NULL; + + const char* trackType = + MP4GetTrackType(mp4File, trackId); + if (trackType == NULL) return NULL; + + if (!strcmp(trackType, MP4_AUDIO_TRACK_TYPE)) + { + trackInfo = PrintAudioInfo(mp4File, trackId); + } + else if (!strcmp(trackType, MP4_VIDEO_TRACK_TYPE)) + { + trackInfo = PrintVideoInfo(mp4File, trackId); + } + else if (!strcmp(trackType, MP4_HINT_TRACK_TYPE)) + { + trackInfo = PrintHintInfo(mp4File, trackId); + } + else if (strcmp(trackType, MP4_CNTL_TRACK_TYPE) == 0) + { + trackInfo = PrintCntlInfo(mp4File, trackId); + } + else + { + trackInfo = (char*)MP4Malloc(256); + if (!strcmp(trackType, MP4_OD_TRACK_TYPE)) + { + snprintf(trackInfo, 256, + "%u\tod\tObject Descriptors\r\n", + trackId); + } + else if (!strcmp(trackType, MP4_SCENE_TRACK_TYPE)) + { + snprintf(trackInfo, 256, + "%u\tscene\tBIFS\r\n", + trackId); + } + else + { + snprintf(trackInfo, 256, + "%u\t%s\r\n", + trackId, trackType); + } + } + + return trackInfo; +} + +extern "C" char* MP4Info( + MP4FileHandle mp4File, + MP4TrackId trackId) +{ + char* info = NULL; + + if (MP4_IS_VALID_FILE_HANDLE(mp4File)) + { + try + { + if (trackId == MP4_INVALID_TRACK_ID) + { + uint buflen = 4 * 1024; + info = (char*)MP4Calloc(buflen); + + buflen -= snprintf(info, buflen, + "Track\tType\tInfo\r\n"); + + u_int32_t numTracks = MP4GetNumberOfTracks(mp4File); + + for (u_int32_t i = 0; i < numTracks; i++) + { + trackId = MP4FindTrackId(mp4File, i); + char* trackInfo = PrintTrackInfo(mp4File, trackId); + strncat(info, trackInfo, buflen); + uint newlen = strlen(trackInfo); + if (newlen > buflen) buflen = 0; + else buflen -= newlen; + MP4Free(trackInfo); + } + } + else + { + info = PrintTrackInfo(mp4File, trackId); + } + } + catch (MP4Error* e) + { + delete e; + } + } + + return info; +} + +extern "C" char* MP4FileInfo( + const MP4_FILENAME_CHAR* fileName, + MP4TrackId trackId) +{ + MP4FileHandle mp4File = + MP4Read(fileName); + + if (!mp4File) + { + return NULL; + } + + char* info = MP4Info(mp4File, trackId); + + MP4Close(mp4File); + + return info; // caller should free this +} + +#endif
\ No newline at end of file diff --git a/Src/external_dependencies/libmp4v2/mp4meta.cpp b/Src/external_dependencies/libmp4v2/mp4meta.cpp new file mode 100644 index 00000000..ee4bfbad --- /dev/null +++ b/Src/external_dependencies/libmp4v2/mp4meta.cpp @@ -0,0 +1,993 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * M. Bakker mbakker at nero.com + * + * Apple iTunes Metadata handling + */ + +/** + + The iTunes tagging seems to support any tag field name + but there are some predefined fields, also known from the QuickTime format + + predefined fields (the ones I know of until now): + - ©nam : Name of the song/movie (string) + - ©ART : Name of the artist/performer (string) + - aART : Album artist + - ©wrt : Name of the writer (string) + - ©alb : Name of the album (string) + - ©day : Year (4 bytes, e.g. "2003") (string) + - ©too : Tool(s) used to create the file (string) + - ©cmt : Comment (string) + - ©gen : Custom genre (string) + - ©grp : Grouping (string) + - trkn : Tracknumber (8 byte string) + 16 bit: empty + 16 bit: tracknumber + 16 bit: total tracks on album + 16 bit: empty + - disk : Disknumber (8 byte string) + 16 bit: empty + 16 bit: disknumber + 16 bit: total number of disks + 16 bit: empty + - gnre : Genre (16 bit genre) (ID3v1 index + 1) + - cpil : Part of a compilation (1 byte, 1 or 0) + - tmpo : Tempo in BPM (16 bit) + - covr : Cover art (xx bytes binary data) + - ---- : Free form metadata, can have any name and any data + - pgap : gapless - 8 bit boolean + + - apID : purchaser name. + - cprt : copyright + - purd : purchase date. + +**/ + +#include "mp4common.h" + +bool MP4File::GetMetadataByIndex(u_int32_t index, + char** ppName, + u_int8_t** ppValue, u_int32_t* pValueSize) +{ + char s[256]; + + snprintf(s, 256, "moov.udta.meta.ilst.*[%u].data.metadata", index); + GetBytesProperty(s, ppValue, pValueSize); + + snprintf(s, 256, "moov.udta.meta.ilst.*[%u]", index); + MP4Atom* pParent = m_pRootAtom->FindAtomMP4(s); + if (pParent == NULL) return false; + + /* check for free form tagfield */ + if (memcmp(*ppName, "----", 4) == 0) + { + u_int8_t* pV; + u_int32_t VSize = 0; + char *pN; + + snprintf(s, 256, "moov.udta.meta.ilst.*[%u].name.metadata", index); + GetBytesProperty(s, &pV, &VSize); + + pN = (char*)malloc((VSize+1)*sizeof(char)); + if (pN != NULL) { + memset(pN, 0, (VSize+1)*sizeof(char)); + memcpy(pN, pV, VSize*sizeof(char)); + } + free(pV); + *ppName = pN; + } else { + *ppName = _strdup(pParent->GetType()); + } + + return true; +} + +bool MP4File::CreateMetadataAtom(const char* name) +{ + char s[256]; + char t[256]; + + snprintf(t, 256, "udta.meta.ilst.%s.data", name); + snprintf(s, 256, "moov.udta.meta.ilst.%s.data", name); + (void)AddDescendantAtoms("moov", t); + MP4Atom *pMetaAtom = m_pRootAtom->FindAtomMP4(s); + + if (!pMetaAtom) + return false; + + /* some fields need special flags set */ + if ((uint8_t)name[0] == 0251 || ATOMID(name) == ATOMID("aART")) + { + pMetaAtom->SetFlags(0x1); + } else if ((memcmp(name, "cpil", 4) == 0) || (memcmp(name, "tmpo", 4) == 0)) { + pMetaAtom->SetFlags(0x15); + } + + MP4Atom *pHdlrAtom = m_pRootAtom->FindAtomMP4("moov.udta.meta.hdlr"); + MP4StringProperty *pStringProperty = NULL; + MP4BytesProperty *pBytesProperty = NULL; + ASSERT(pHdlrAtom); + + ASSERT(pHdlrAtom->FindProperty("hdlr.handlerType", + (MP4Property**)&pStringProperty)); + ASSERT(pStringProperty); + pStringProperty->SetValue("mdir"); + + u_int8_t val[12]; + memset(val, 0, 12*sizeof(u_int8_t)); + val[0] = 0x61; + val[1] = 0x70; + val[2] = 0x70; + val[3] = 0x6c; + ASSERT(pHdlrAtom->FindProperty("hdlr.reserved2", + (MP4Property**)&pBytesProperty)); + ASSERT(pBytesProperty); + pBytesProperty->SetReadOnly(false); + pBytesProperty->SetValue(val, 12); + pBytesProperty->SetReadOnly(true); + + return true; +} + +bool MP4File::DeleteMetadataAtom(const char* name, bool try_udta) +{ + MP4Atom *pMetaAtom = NULL; + char s[256]; + + snprintf(s, 256, "moov.udta.meta.ilst.%s", name); + pMetaAtom = m_pRootAtom->FindAtomMP4(s); + + if (pMetaAtom == NULL && try_udta) { + snprintf(s, 256, "moov.udta.%s", name); + pMetaAtom = m_pRootAtom->FindAtomMP4(s); + } + /* if it exists, delete it */ + if (pMetaAtom) + { + MP4Atom *pParent = pMetaAtom->GetParentAtom(); + + pParent->DeleteChildAtom(pMetaAtom); + + delete pMetaAtom; + + return true; + } + + return false; +} + +bool MP4File::SetMetadataString (const char *atom, const char *value) +{ + char atomstring[40]; + MP4Atom *pMetaAtom; + MP4BytesProperty *pMetadataProperty = NULL; + snprintf(atomstring, 40, "moov.udta.meta.ilst.%s.data", atom); + + pMetaAtom = m_pRootAtom->FindAtomMP4(atomstring); + + if (!pMetaAtom) + { + if (!CreateMetadataAtom(atom)) + return false; + + pMetaAtom = m_pRootAtom->FindAtomMP4(atomstring); + if (pMetaAtom == NULL) return false; + } + + ASSERT(pMetaAtom->FindProperty("data.metadata", + (MP4Property**)&pMetadataProperty)); + ASSERT(pMetadataProperty); + + pMetadataProperty->SetValue((u_int8_t*)value, (u_int32_t)strlen(value)); + + return true; +} + +bool MP4File::GetMetadataString (const char *atom, char **value, bool try_udta) +{ + unsigned char *val = NULL; + u_int32_t valSize = 0; + char atomstring[60]; + snprintf(atomstring, 60, "moov.udta.meta.ilst.%s.data.metadata", atom); + + *value = NULL; + if (try_udta == false) { + GetBytesProperty(atomstring, (u_int8_t**)&val, &valSize); + } else { + bool got_it = false; + try { + GetBytesProperty(atomstring, (u_int8_t**)&val, &valSize); + got_it = true; + } + catch (MP4Error* e) { + delete e; + } + if (got_it == false) { + snprintf(atomstring, 60, "moov.udta.%s.metadata", atom); + GetBytesProperty(atomstring, (u_int8_t**)&val, &valSize); + } + } + if (valSize > 0) + { + *value = (char*)malloc((valSize+1)*sizeof(char)); + if (*value == NULL) { + free(val); + return false; + } + memcpy(*value, val, valSize*sizeof(unsigned char)); + free(val); + (*value)[valSize] = '\0'; + return true; + } + return false; +} + +bool MP4File::SetMetadataTrack(u_int16_t track, u_int16_t totalTracks) +{ + unsigned char t[9]; + const char *s = "moov.udta.meta.ilst.trkn.data"; + MP4BytesProperty *pMetadataProperty = NULL; + MP4Atom *pMetaAtom = NULL; + + pMetaAtom = m_pRootAtom->FindAtomMP4(s); + + if (!pMetaAtom) + { + if (!CreateMetadataAtom("trkn")) + return false; + + pMetaAtom = m_pRootAtom->FindAtomMP4(s); + if (pMetaAtom == NULL) return false; + } + + memset(t, 0, 9*sizeof(unsigned char)); + t[2] = (unsigned char)(track>>8)&0xFF; + t[3] = (unsigned char)(track)&0xFF; + t[4] = (unsigned char)(totalTracks>>8)&0xFF; + t[5] = (unsigned char)(totalTracks)&0xFF; + + ASSERT(pMetaAtom->FindProperty("data.metadata", + (MP4Property**)&pMetadataProperty)); + ASSERT(pMetadataProperty); + + pMetadataProperty->SetValue((u_int8_t*)t, 8); + + return true; +} + +bool MP4File::GetMetadataTrack(u_int16_t* track, u_int16_t* totalTracks) +{ + unsigned char *val = NULL; + u_int32_t valSize = 0; + const char *s = "moov.udta.meta.ilst.trkn.data.metadata"; + + *track = 0; + *totalTracks = 0; + + GetBytesProperty(s, (u_int8_t**)&val, &valSize); + + if (valSize == 8) { + *track = (u_int16_t)(val[3]); + *track += (u_int16_t)(val[2]<<8); + *totalTracks = (u_int16_t)(val[5]); + *totalTracks += (u_int16_t)(val[4]<<8); + CHECK_AND_FREE(val); + return true; + } + CHECK_AND_FREE(val); + return false; +} + +bool MP4File::SetMetadataDisk(u_int16_t disk, u_int16_t totalDisks) +{ + unsigned char t[7]; + const char *s = "moov.udta.meta.ilst.disk.data"; + MP4BytesProperty *pMetadataProperty = NULL; + MP4Atom *pMetaAtom = NULL; + + pMetaAtom = m_pRootAtom->FindAtomMP4(s); + + if (!pMetaAtom) + { + if (!CreateMetadataAtom("disk")) + return false; + + pMetaAtom = m_pRootAtom->FindAtomMP4(s); + if (pMetaAtom == NULL) return false; + } + + memset(t, 0, 7*sizeof(unsigned char)); + t[2] = (unsigned char)(disk>>8)&0xFF; + t[3] = (unsigned char)(disk)&0xFF; + t[4] = (unsigned char)(totalDisks>>8)&0xFF; + t[5] = (unsigned char)(totalDisks)&0xFF; + + ASSERT(pMetaAtom->FindProperty("data.metadata", + (MP4Property**)&pMetadataProperty)); + ASSERT(pMetadataProperty); + + pMetadataProperty->SetValue((u_int8_t*)t, 6); + + return true; +} + +bool MP4File::GetMetadataDisk(u_int16_t* disk, u_int16_t* totalDisks) +{ + unsigned char *val = NULL; + u_int32_t valSize = 0; + const char *s = "moov.udta.meta.ilst.disk.data.metadata"; + + *disk = 0; + *totalDisks = 0; + + GetBytesProperty(s, (u_int8_t**)&val, &valSize); + + if (valSize == 6 || valSize == 8) { + *disk = (u_int16_t)(val[3]); + *disk += (u_int16_t)(val[2]<<8); + *totalDisks = (u_int16_t)(val[5]); + *totalDisks += (u_int16_t)(val[4]<<8); + free(val); + return true; + } + CHECK_AND_FREE(val); + return true; +} + +static const char* ID3v1GenreList[] = { + "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", + "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", + "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", + "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks", + "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk", + "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House", + "Game", "Sound Clip", "Gospel", "Noise", "Alt Rock", "Bass", + "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", + "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", + "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta", + "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret", + "New Wave", "Psychedelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", + "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", + "Rock & Roll", "Hard Rock", "Folk", "Folk-Rock", "National Folk", "Swing", + "Fast-Fusion", "Bebop", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", + "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", + "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson", + "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", + "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba", + "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet", + "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall", + "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror", + "Indie", "BritPop", "Afro-Punk", "Polsk Punk", "Beat", + "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover", "Contemporary Christian", + "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", + "SynthPop", "Abstract", "Art Rock", "Baroque", "Bhangra", "Big Beat", "Breakbeat", "Chillout", "Downtempo", "Dub", "EBM", "Eclectic", "Electro", + "Electroclash", "Emo", "Experimental", "Garage", "Global", "IDM", "Illbient", "Industro-Goth", "Jam Band", "Krautrock", "Leftfield", "Lounge", + "Math Rock", "New Romantic", "Nu-Breakz", "Post-Punk", "Post-Rock", "Psytrance", "Shoegaze", "Space Rock", "Trop Rock", "World Music", "Neoclassical", + "Audiobook", "Audio Theatre", "Neue Deutsche Welle", "Podcast", "Indie Rock", "G-Funk", "Dubstep", "Garage Rock", "Psybient", "Glam Rock", "Dream Pop", + "Merseybeat", "K-Pop", "Chiptune", "Grime", "Grindcore", "Indietronic", "Indietronica", "Jazz Rock", "Jazz Fusion", "Post-Punk Revival", "Electronica", + "Psychill", "Ethnotronic", "Americana", "Ambient Dub", "Digital Dub", "Chillwave", "Stoner Rock", "Slowcore", "Softcore", "Flamenco", "Hi-NRG", "Ethereal", + "Drone", "Doom Metal", "Doom Jazz", "Mainstream", "Glitch", "Balearic", "Modern Classical", "Mod", "Contemporary Classical", "Psybreaks", "Psystep", + "Psydub", "Chillstep", "Berlin School", "Future Jazz", "Djent", "Musique Concrète", "Electroacoustic", "Folktronica", "Texas Country", "Red Dirt", + "Arabic", "Asian", "Bachata", "Bollywood", "Cajun", "Calypso", "Creole", "Darkstep", "Jewish", "Reggaeton", "Smooth Jazz", "Soca", "Spiritual", + "Turntablism", "Zouk","Neofolk", "Nu Jazz", "Psychobilly", "Rockabilly", "Schlager & Volksmusik", +}; + +void GenreToString(char** GenreStr, const int genre) +{ + if (genre > 0 && + genre <= (int)(sizeof(ID3v1GenreList)/sizeof(*ID3v1GenreList))) + { + uint len = (uint)strlen(ID3v1GenreList[genre-1])+1; + *GenreStr = (char*)malloc(len); + if (*GenreStr == NULL) return; + // no need for strncpy; enough was malloced + strcpy(*GenreStr, ID3v1GenreList[genre-1]); + return; + } + *GenreStr = (char*)malloc(2*sizeof(char)); + if (*GenreStr == NULL) return; + memset(*GenreStr, 0, 2*sizeof(char)); + return; +} + +int StringToGenre(const char* GenreStr) +{ + unsigned int i; + + for (i = 0; i < sizeof(ID3v1GenreList)/sizeof(*ID3v1GenreList); i++) + { + if (strcasecmp(GenreStr, ID3v1GenreList[i]) == 0) + return i+1; + } + return 0; +} + +bool MP4File::SetMetadataGenre(const char* value) +{ + u_int16_t genreIndex = 0; + unsigned char t[3]; + MP4BytesProperty *pMetadataProperty = NULL; + MP4Atom *pMetaAtom = NULL; + + genreIndex = StringToGenre(value); + + const char *s = "moov.udta.meta.ilst.gnre.data"; + const char *sroot = "moov.udta.meta.ilst.gnre"; + const char *s2 = "moov.udta.meta.ilst.\251gen.data"; + const char *s2root = "moov.udta.meta.ilst.\251gen"; + if (genreIndex != 0) + { + pMetaAtom = m_pRootAtom->FindAtomMP4(s); + if (!pMetaAtom) + { + if (!CreateMetadataAtom("gnre")) + return false; + + pMetaAtom = m_pRootAtom->FindAtomMP4(s); + if (pMetaAtom == NULL) return false; + } + + memset(t, 0, 3*sizeof(unsigned char)); + t[0] = (unsigned char)(genreIndex>>8)&0xFF; + t[1] = (unsigned char)(genreIndex)&0xFF; + + ASSERT(pMetaAtom->FindProperty("data.metadata", + (MP4Property**)&pMetadataProperty)); + ASSERT(pMetadataProperty); + + pMetadataProperty->SetValue((u_int8_t*)t, 2); + + // remove other style of genre atom, if this one is added + pMetaAtom = m_pRootAtom->FindAtomMP4(s2root); + if (pMetaAtom != NULL) { + MP4Atom *pParent = pMetaAtom->GetParentAtom(); + if (pParent != NULL) { + pParent->DeleteChildAtom(pMetaAtom); + delete pMetaAtom; + } + } + + + (void)DeleteMetadataAtom( "\251gen" ); + + return true; + } else { + pMetaAtom = m_pRootAtom->FindAtomMP4(s2); + + if (!pMetaAtom) + { + if (!CreateMetadataAtom("\251gen")) + return false; + + pMetaAtom = m_pRootAtom->FindAtomMP4(s2); + } + + ASSERT(pMetaAtom->FindProperty("data.metadata", + (MP4Property**)&pMetadataProperty)); + ASSERT(pMetadataProperty); + + pMetadataProperty->SetValue((u_int8_t*)value, (u_int32_t)strlen(value)); + + // remove other gnre atom if this one is entered + pMetaAtom = m_pRootAtom->FindAtomMP4(sroot); + if (pMetaAtom != NULL) { + MP4Atom *pParent = pMetaAtom->GetParentAtom(); + pParent->DeleteChildAtom(pMetaAtom); + delete pMetaAtom; + } + return true; + } + + return false; +} + +bool MP4File::GetMetadataGenre(char** value) +{ + u_int16_t genreIndex = 0; + unsigned char *val = NULL; + u_int32_t valSize = 0; + const char *t = "moov.udta.meta.ilst.gnre"; + const char *s = "moov.udta.meta.ilst.gnre.data.metadata"; + + *value = NULL; + + MP4Atom *gnre = FindAtomMP4File(t); + + if (gnre) + { + GetBytesProperty(s, (u_int8_t**)&val, &valSize); + + if (valSize != 2) { + CHECK_AND_FREE(val); + return false; + } + + genreIndex = (u_int16_t)(val[1]); + genreIndex += (u_int16_t)(val[0]<<8); + + GenreToString(value, genreIndex); + +// (void)DeleteMetadataAtom( "gnre" ); + free(val); + return true; + } else { + const char *s2 = "moov.udta.meta.ilst.\251gen.data.metadata"; + + val = NULL; + valSize = 0; + + GetBytesProperty(s2, (u_int8_t**)&val, &valSize); + + if (valSize > 0) + { + *value = (char*)malloc((valSize+1)*sizeof(unsigned char)); + if (*value != NULL) { + memset(*value, 0, (valSize+1)*sizeof(unsigned char)); + memcpy(*value, val, valSize*sizeof(unsigned char)); + } + free(val); + return true; + } else { + CHECK_AND_FREE(val); + } + } + + return false; +} + +bool MP4File::DeleteMetadataGenre() +{ + bool val1 = DeleteMetadataAtom("\251gen"); + bool val2 = DeleteMetadataAtom("gnre"); + return val1 || val2; +} + +bool MP4File::SetMetadataTempo(u_int16_t tempo) +{ + unsigned char t[3]; + const char *s = "moov.udta.meta.ilst.tmpo.data"; + MP4BytesProperty *pMetadataProperty = NULL; + MP4Atom *pMetaAtom = NULL; + + pMetaAtom = m_pRootAtom->FindAtomMP4(s); + + if (!pMetaAtom) + { + if (!CreateMetadataAtom("tmpo")) + return false; + + pMetaAtom = m_pRootAtom->FindAtomMP4(s); + if (pMetaAtom == NULL) return false; + } + + memset(t, 0, 3*sizeof(unsigned char)); + t[0] = (unsigned char)(tempo>>8)&0xFF; + t[1] = (unsigned char)(tempo)&0xFF; + + ASSERT(pMetaAtom->FindProperty("data.metadata", + (MP4Property**)&pMetadataProperty)); + ASSERT(pMetadataProperty); + + pMetadataProperty->SetValue((u_int8_t*)t, 2); + + return true; +} + +bool MP4File::GetMetadataTempo(u_int16_t* tempo) +{ + unsigned char *val = NULL; + u_int32_t valSize = 0; + const char *s = "moov.udta.meta.ilst.tmpo.data.metadata"; + + *tempo = 0; + + GetBytesProperty(s, (u_int8_t**)&val, &valSize); + + if (valSize != 2) { + CHECK_AND_FREE(val); + return false; + } + + *tempo = (u_int16_t)(val[1]); + *tempo += (u_int16_t)(val[0]<<8); + free(val); + return true; +} +bool MP4File::SetMetadataUint8 (const char *atom, uint8_t value) +{ + char atompath[36]; + MP4BytesProperty *pMetadataProperty = NULL; + MP4Atom *pMetaAtom = NULL; + + snprintf(atompath, 36, "moov.udta.meta.ilst.%s.data", atom); + + pMetaAtom = m_pRootAtom->FindAtomMP4(atompath); + + if (pMetaAtom == NULL) { + if (!CreateMetadataAtom(atom)) + return false; + + pMetaAtom = m_pRootAtom->FindAtomMP4(atompath); + if (pMetaAtom == NULL) return false; + } + + ASSERT(pMetaAtom->FindProperty("data.metadata", + (MP4Property**)&pMetadataProperty)); + ASSERT(pMetadataProperty); + + pMetadataProperty->SetValue(&value, 1); + + return true; +} + + +bool MP4File::GetMetadataUint8(const char *atom, u_int8_t* retvalue) +{ + unsigned char *val = NULL; + u_int32_t valSize = 0; + char atompath[80]; + snprintf(atompath, 80, "moov.udta.meta.ilst.%s.data.metadata", atom); + + *retvalue = 0; + + GetBytesProperty(atompath, (u_int8_t**)&val, &valSize); + + if (valSize != 1) { + CHECK_AND_FREE(val); + return false; + } + + *retvalue = val[0]; + free(val); + return true; +} + +bool MP4File::SetMetadataCoverArt(u_int8_t *coverArt, u_int32_t size, int flags) +{ + const char *s = "moov.udta.meta.ilst.covr.data"; + MP4BytesProperty *pMetadataProperty = NULL; + MP4Atom *pMetaAtom = NULL; + + pMetaAtom = m_pRootAtom->FindAtomMP4(s); + + if (!pMetaAtom) + { + if (!CreateMetadataAtom("covr")) + return false; + + pMetaAtom = m_pRootAtom->FindAtomMP4(s); + if (pMetaAtom == NULL) return false; + } + + pMetaAtom->SetFlags(flags); + + ASSERT(pMetaAtom->FindProperty("data.metadata", + (MP4Property**)&pMetadataProperty)); + ASSERT(pMetadataProperty); + + pMetadataProperty->SetValue(coverArt, size); + + return true; +} + +bool MP4File::GetMetadataCoverArt(u_int8_t **coverArt, u_int32_t *size, + uint32_t index) +{ + char buffer[256]; + if (size == NULL || coverArt == NULL) return false; + + if (index > 0 && index > GetMetadataCoverArtCount()) return false; + + snprintf(buffer, 256, "moov.udta.meta.ilst.covr.data[%d].metadata", index); + + *coverArt = NULL; + *size = 0; + + GetBytesProperty(buffer, coverArt, size); + + if (*size == 0) + return false; + + return true; +} + +u_int32_t MP4File::GetMetadataCoverArtCount (void) +{ + MP4Atom *pMetaAtom = m_pRootAtom->FindAtomMP4("moov.udta.meta.ilst.covr"); + if (!pMetaAtom) + return 0; + + return pMetaAtom->GetNumberOfChildAtoms(); +} + +bool MP4File::SetMetadataFreeForm (const char *name, + const u_int8_t* pValue, + u_int32_t valueSize, + const char *owner) +{ + MP4Atom *pMetaAtom = NULL; + MP4BytesProperty *pMetadataProperty = NULL; + char s[256]; + int i = 0; + size_t nameLen = strlen(name); + size_t ownerLen = owner != NULL ? strlen(owner) : 0; + + while (1) + { + MP4BytesProperty *pMetadataProperty; + + snprintf(s, 256, "moov.udta.meta.ilst.----[%u].name", i); + + MP4Atom *pTagAtom = m_pRootAtom->FindAtomMP4(s); + + if (!pTagAtom) + break; + + snprintf(s, 256, "moov.udta.meta.ilst.----[%u].mean", i); + + MP4Atom *pMeanAtom = m_pRootAtom->FindAtomMP4(s); + + if (pTagAtom->FindProperty("name.metadata", + (MP4Property**)&pMetadataProperty) && + pMetadataProperty) { + u_int8_t* pV; + u_int32_t VSize = 0; + + pMetadataProperty->GetValue(&pV, &VSize); + + if (VSize == nameLen && memcmp(pV, name, VSize) == 0) { + u_int8_t* pOwner=0; + u_int32_t ownerSize = 0; + + if (pMeanAtom && + pMeanAtom->FindProperty("mean.metadata", + (MP4Property**)&pMetadataProperty) && + pMetadataProperty) { + pMetadataProperty->GetValue(&pOwner, &ownerSize); + } + + if (owner == NULL|| + (pOwner && + ownerLen == ownerSize && + !memcmp(owner, pOwner, ownerSize))) { + snprintf(s, 256, "moov.udta.meta.ilst.----[%u].data.metadata", i); + SetBytesProperty(s, pValue, valueSize); + CHECK_AND_FREE(pV); + CHECK_AND_FREE(pOwner); + + return true; + } + CHECK_AND_FREE(pOwner); + } + CHECK_AND_FREE(pV); + } + + i++; + } + + /* doesn't exist yet, create it */ + char t[256]; + + snprintf(t, 256, "udta.meta.ilst.----[%u]", i); + snprintf(s, 256, "moov.udta.meta.ilst.----[%u].data", i); + AddDescendantAtoms("moov", t); + + pMetaAtom = m_pRootAtom->FindAtomMP4(s); + + if (!pMetaAtom) + return false; + + pMetaAtom->SetFlags(0x1); + + MP4Atom *pHdlrAtom = m_pRootAtom->FindAtomMP4("moov.udta.meta.hdlr"); + MP4StringProperty *pStringProperty = NULL; + MP4BytesProperty *pBytesProperty = NULL; + ASSERT(pHdlrAtom); + + ASSERT(pHdlrAtom->FindProperty("hdlr.handlerType", + (MP4Property**)&pStringProperty)); + ASSERT(pStringProperty); + pStringProperty->SetValue("mdir"); + + u_int8_t val[12]; + memset(val, 0, 12*sizeof(u_int8_t)); + val[0] = 0x61; + val[1] = 0x70; + val[2] = 0x70; + val[3] = 0x6c; + ASSERT(pHdlrAtom->FindProperty("hdlr.reserved2", + (MP4Property**)&pBytesProperty)); + ASSERT(pBytesProperty); + pBytesProperty->SetReadOnly(false); + pBytesProperty->SetValue(val, 12); + pBytesProperty->SetReadOnly(true); + + pMetaAtom = m_pRootAtom->FindAtomMP4(s); + ASSERT(pMetaAtom); + ASSERT(pMetaAtom->FindProperty("data.metadata", + (MP4Property**)&pMetadataProperty)); + ASSERT(pMetadataProperty); + pMetadataProperty->SetValue(pValue, valueSize); + + snprintf(s, 256, "moov.udta.meta.ilst.----[%u].name", i); + pMetaAtom = m_pRootAtom->FindAtomMP4(s); + ASSERT(pMetaAtom->FindProperty("name.metadata", + (MP4Property**)&pMetadataProperty)); + ASSERT(pMetadataProperty); + pMetadataProperty->SetValue((const u_int8_t*)name, (u_int32_t)strlen(name)); + + snprintf(s, 256, "moov.udta.meta.ilst.----[%u].mean", i); + pMetaAtom = m_pRootAtom->FindAtomMP4(s); + ASSERT(pMetaAtom->FindProperty("mean.metadata", + (MP4Property**)&pMetadataProperty)); + ASSERT(pMetadataProperty); + if (!owner || !*owner) + pMetadataProperty->SetValue((u_int8_t*)"com.apple.iTunes", 16); /* com.apple.iTunes is the default*/ + else + pMetadataProperty->SetValue((const u_int8_t*)owner, (u_int32_t)strlen((const char *)owner)); + + return true; +} + +bool MP4File::GetMetadataFreeForm(const char *name, + u_int8_t** ppValue, + u_int32_t *pValueSize, + const char *owner) +{ + char s[256]; + int i = 0; + + *ppValue = NULL; + *pValueSize = 0; + + size_t nameLen = strlen(name); + size_t ownerLen = owner?strlen(owner):0; + + while (1) + { + MP4BytesProperty *pMetadataProperty; + + snprintf(s, 256,"moov.udta.meta.ilst.----[%u].name", i); + MP4Atom *pTagAtom = m_pRootAtom->FindAtomMP4(s); + + snprintf(s, 256,"moov.udta.meta.ilst.----[%u].mean", i); + MP4Atom *pMeanAtom = m_pRootAtom->FindAtomMP4(s); + + if (!pTagAtom) + return false; + + if (pTagAtom->FindProperty("name.metadata", + (MP4Property**)&pMetadataProperty) && + pMetadataProperty) { + u_int8_t* pV; + u_int32_t VSize = 0; + + pMetadataProperty->GetValue(&pV, &VSize); + + if (VSize == nameLen && !memcmp(pV, name, VSize)) { + u_int8_t* pOwner=0; + u_int32_t ownerSize = 0; + + if (pMeanAtom && pMeanAtom->FindProperty("mean.metadata", + (MP4Property**)&pMetadataProperty) && + pMetadataProperty) { + pMetadataProperty->GetValue(&pOwner, &ownerSize); + } + + if (!owner || (pOwner && ownerLen == ownerSize && !memcmp(owner, pOwner, ownerSize))) { + snprintf(s, 256, "moov.udta.meta.ilst.----[%u].data.metadata", i); + GetBytesProperty(s, ppValue, pValueSize); + CHECK_AND_FREE(pV); + CHECK_AND_FREE(pOwner); + return true; + } + CHECK_AND_FREE(pOwner); + } + CHECK_AND_FREE(pV); + } + + i++; + } +} + +bool MP4File::DeleteMetadataFreeForm(const char *name, const char *owner) +{ + char s[256]; + int i = 0; + + size_t nameLen = strlen(name); + size_t ownerLen = owner?strlen(owner):0; + + while (1) + { + MP4BytesProperty *pMetadataProperty; + + snprintf(s, 256, "moov.udta.meta.ilst.----[%u].name", i); + MP4Atom *pTagAtom = m_pRootAtom->FindAtomMP4(s); + + snprintf(s, 256,"moov.udta.meta.ilst.----[%u].mean", i); + MP4Atom *pMeanAtom = m_pRootAtom->FindAtomMP4(s); + + + if (!pTagAtom) + return false; + + if (pTagAtom->FindProperty("name.metadata", + (MP4Property**)&pMetadataProperty) && + pMetadataProperty) { + u_int8_t* pV; + u_int32_t VSize = 0; + + pMetadataProperty->GetValue(&pV, &VSize); + + if (VSize != 0) + { + if (VSize == nameLen && !memcmp(pV, name, VSize)) + { + u_int8_t* pOwner=0; + u_int32_t ownerSize = 0; + + if (pMeanAtom && pMeanAtom->FindProperty("mean.metadata", + (MP4Property**)&pMetadataProperty) && + pMetadataProperty) + { + pMetadataProperty->GetValue(&pOwner, &ownerSize); + } + + if (!owner || (pOwner && ownerLen == ownerSize && !memcmp(owner, pOwner, ownerSize))) + { + snprintf(s, 256, "----[%u]", i); + CHECK_AND_FREE(pOwner); + CHECK_AND_FREE(pV); + return DeleteMetadataAtom(s); + } + CHECK_AND_FREE(pOwner); + + } + } + CHECK_AND_FREE(pV); + } + + i++; + } +} + +bool MP4File::MetadataDelete() +{ + MP4Atom *pMetaAtom = NULL; + char s[256]; + + snprintf(s, 256, "moov.udta.meta"); + pMetaAtom = m_pRootAtom->FindAtomMP4(s); + + /* if it exists, delete it */ + if (pMetaAtom) + { + MP4Atom *pParent = pMetaAtom->GetParentAtom(); + + pParent->DeleteChildAtom(pMetaAtom); + + delete pMetaAtom; + + return true; + } + + return false; +} diff --git a/Src/external_dependencies/libmp4v2/mp4property.cpp b/Src/external_dependencies/libmp4v2/mp4property.cpp new file mode 100644 index 00000000..9b5ac3e6 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/mp4property.cpp @@ -0,0 +1,733 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4Property::MP4Property(const char* name) +{ + m_name = name; + m_pParentAtom = NULL; + m_readOnly = false; + m_implicit = false; +} + +bool MP4Property::FindProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex) +{ + if (name == NULL) { + return false; + } + + if (!strcasecmp(m_name, name)) { + if (m_pParentAtom) { + VERBOSE_FIND(m_pParentAtom->GetFile()->GetVerbosity(), + printf("FindProperty: matched %s\n", name)); + } + + *ppProperty = this; + return true; + } + return false; +} + +// Integer Property + +u_int64_t MP4IntegerProperty::GetValue(u_int32_t index) +{ + switch (this->GetType()) { + case Integer8Property: + return ((MP4Integer8Property*)this)->GetValue(index); + case Integer16Property: + return ((MP4Integer16Property*)this)->GetValue(index); + case Integer24Property: + return ((MP4Integer24Property*)this)->GetValue(index); + case Integer32Property: + return ((MP4Integer32Property*)this)->GetValue(index); + case Integer64Property: + return ((MP4Integer64Property*)this)->GetValue(index); + default: + ASSERT(FALSE); + } + return (0); +} + +void MP4IntegerProperty::SetValue(u_int64_t value, u_int32_t index) +{ + switch (this->GetType()) { + case Integer8Property: + ((MP4Integer8Property*)this)->SetValue(value, index); + break; + case Integer16Property: + ((MP4Integer16Property*)this)->SetValue(value, index); + break; + case Integer24Property: + ((MP4Integer24Property*)this)->SetValue(value, index); + break; + case Integer32Property: + ((MP4Integer32Property*)this)->SetValue(value, index); + break; + case Integer64Property: + ((MP4Integer64Property*)this)->SetValue(value, index); + break; + default: + ASSERT(FALSE); + } +} + +void MP4IntegerProperty::InsertValue(u_int64_t value, u_int32_t index) +{ + switch (this->GetType()) { + case Integer8Property: + ((MP4Integer8Property*)this)->InsertValue(value, index); + break; + case Integer16Property: + ((MP4Integer16Property*)this)->InsertValue(value, index); + break; + case Integer24Property: + ((MP4Integer24Property*)this)->InsertValue(value, index); + break; + case Integer32Property: + ((MP4Integer32Property*)this)->InsertValue(value, index); + break; + case Integer64Property: + ((MP4Integer64Property*)this)->InsertValue(value, index); + break; + default: + ASSERT(FALSE); + } +} + +void MP4IntegerProperty::DeleteValue(u_int32_t index) +{ + switch (this->GetType()) { + case Integer8Property: + ((MP4Integer8Property*)this)->DeleteValue(index); + break; + case Integer16Property: + ((MP4Integer16Property*)this)->DeleteValue(index); + break; + case Integer24Property: + ((MP4Integer24Property*)this)->DeleteValue(index); + break; + case Integer32Property: + ((MP4Integer32Property*)this)->DeleteValue(index); + break; + case Integer64Property: + ((MP4Integer64Property*)this)->DeleteValue(index); + break; + default: + ASSERT(FALSE); + } +} + +void MP4IntegerProperty::IncrementValue(int32_t increment, u_int32_t index) +{ + SetValue(GetValue() + increment); +} + +// MP4BitfieldProperty + +void MP4BitfieldProperty::Read(MP4File* pFile, u_int32_t index) +{ + if (m_implicit) { + return; + } + m_values[index] = pFile->ReadBits(m_numBits); +} + +void MP4BitfieldProperty::Write(MP4File* pFile, u_int32_t index) +{ + if (m_implicit) { + return; + } + pFile->WriteBits(m_values[index], m_numBits); +} + +// MP4Float32Property + +void MP4Float32Property::Read(MP4File* pFile, u_int32_t index) +{ + if (m_implicit) { + return; + } + if (m_useFixed16Format) { + m_values[index] = pFile->ReadFixed16(); + } else if (m_useFixed32Format) { + m_values[index] = pFile->ReadFixed32(); + } else { + m_values[index] = pFile->ReadFloat(); + } +} + +void MP4Float32Property::Write(MP4File* pFile, u_int32_t index) +{ + if (m_implicit) { + return; + } + if (m_useFixed16Format) { + pFile->WriteFixed16(m_values[index]); + } else if (m_useFixed32Format) { + pFile->WriteFixed32(m_values[index]); + } else { + pFile->WriteFloat(m_values[index]); + } +} + +// MP4StringProperty + +MP4StringProperty::MP4StringProperty(char* name, + bool useCountedFormat, bool useUnicode) + : MP4Property(name) +{ + SetCount(1); + m_values[0] = NULL; + m_useCountedFormat = useCountedFormat; + m_useExpandedCount = false; + m_useUnicode = useUnicode; + m_fixedLength = 0; // length not fixed +} + +MP4StringProperty::~MP4StringProperty() +{ + u_int32_t count = GetCount(); + for (u_int32_t i = 0; i < count; i++) { + MP4Free(m_values[i]); + } +} + +void MP4StringProperty::SetCount(u_int32_t count) +{ + u_int32_t oldCount = m_values.Size(); + + m_values.Resize(count); + + for (u_int32_t i = oldCount; i < count; i++) { + m_values[i] = NULL; + } +} + +void MP4StringProperty::SetValue(const char* value, u_int32_t index) +{ + if (m_readOnly) { + throw new MP4Error(EACCES, "property is read-only", m_name); + } + + MP4Free(m_values[index]); + + if (m_fixedLength) { + m_values[index] = (char*)MP4Calloc(m_fixedLength + 1); + if (value) { + strncpy(m_values[index], value, m_fixedLength); + } + } else { + if (value) { + if (m_useUnicode) + m_values[index] = (char *)MP4Stralloc((const uint16_t *)value); + else + m_values[index] = MP4Stralloc(value); + } else { + m_values[index] = NULL; + } + } +} + +void MP4StringProperty::Read(MP4File* pFile, u_int32_t index) +{ + if (m_implicit) { + return; + } + if (m_useCountedFormat) { + m_values[index] = pFile->ReadCountedString( + (m_useUnicode ? 2 : 1), m_useExpandedCount); + } else if (m_fixedLength) { + MP4Free(m_values[index]); + m_values[index] = (char*)MP4Calloc(m_fixedLength + 1); + pFile->ReadBytes((u_int8_t*)m_values[index], m_fixedLength); + } else { + if (m_useUnicode) + { + m_values[index] = (char *)pFile->ReadUnicodeString(); + } + else + { + char *str = pFile->ReadString(); + if (str && str[0] == 0xFF && str[1] == 0xFE) + m_useUnicode = true; + if (str && str[0] == 0xFE && str[1] == 0xFF) + m_useUnicode = true; + m_values[index] = str; + } + } +} + +void MP4StringProperty::Write(MP4File* pFile, u_int32_t index) +{ + if (m_implicit) { + return; + } + if (m_useCountedFormat) { + pFile->WriteCountedString(m_values[index], + (m_useUnicode ? 2 : 1), m_useExpandedCount); + } else if (m_fixedLength) { + pFile->WriteBytes((u_int8_t*)m_values[index], m_fixedLength); + } else { + if (m_useUnicode) + pFile->WriteUnicodeString((const uint16_t *)m_values[index]); + else + pFile->WriteString(m_values[index]); + } +} + +// MP4BytesProperty + +MP4BytesProperty::MP4BytesProperty(char* name, u_int32_t valueSize, + u_int32_t defaultValueSize) + : MP4Property(name) +{ + SetCount(1); + m_values[0] = (u_int8_t*)MP4Calloc(valueSize); + m_valueSizes[0] = valueSize; + m_fixedValueSize = 0; + m_defaultValueSize = defaultValueSize; +} + +MP4BytesProperty::~MP4BytesProperty() +{ + u_int32_t count = GetCount(); + for (u_int32_t i = 0; i < count; i++) { + MP4Free(m_values[i]); + } +} + +void MP4BytesProperty::SetCount(u_int32_t count) +{ + u_int32_t oldCount = m_values.Size(); + + m_values.Resize(count); + m_valueSizes.Resize(count); + + for (u_int32_t i = oldCount; i < count; i++) { + m_values[i] = NULL; + m_valueSizes[i] = m_defaultValueSize; + } +} + +void MP4BytesProperty::SetValue(const u_int8_t* pValue, u_int32_t valueSize, + u_int32_t index) +{ + if (m_readOnly) { + throw new MP4Error(EACCES, "property is read-only", m_name); + } + if (m_fixedValueSize) { + if (valueSize > m_fixedValueSize) { + throw new MP4Error("%s.%s value size %d exceeds fixed value size %d", + "MP4BytesProperty::SetValue", + GetParentAtom()->GetType(), + GetName(), + valueSize, + m_fixedValueSize); + } + if (m_values[index] == NULL) { + m_values[index] = (u_int8_t*)MP4Calloc(m_fixedValueSize); + m_valueSizes[index] = m_fixedValueSize; + } + if (pValue) { + memcpy(m_values[index], pValue, valueSize); + } + } else { + MP4Free(m_values[index]); + if (pValue) { + m_values[index] = (u_int8_t*)MP4Malloc(valueSize); + memcpy(m_values[index], pValue, valueSize); + m_valueSizes[index] = valueSize; + } else { + m_values[index] = NULL; + m_valueSizes[index] = 0; + } + } +} + +void MP4BytesProperty::SetValueSize(u_int32_t valueSize, u_int32_t index) +{ + if (m_fixedValueSize) { + throw new MP4Error("can't change size of fixed sized property", + "MP4BytesProperty::SetValueSize"); + } + if (m_values[index] != NULL) { + m_values[index] = (u_int8_t*)MP4Realloc(m_values[index], valueSize); + } + m_valueSizes[index] = valueSize; +} + +void MP4BytesProperty::SetFixedSize(u_int32_t fixedSize) +{ + m_fixedValueSize = 0; + for (u_int32_t i = 0; i < GetCount(); i++) { + SetValueSize(fixedSize, i); + } + m_fixedValueSize = fixedSize; +} + +void MP4BytesProperty::Read(MP4File* pFile, u_int32_t index) +{ + if (m_implicit) { + return; + } + MP4Free(m_values[index]); + m_values[index] = (u_int8_t*)MP4Malloc(m_valueSizes[index]); + pFile->ReadBytes(m_values[index], m_valueSizes[index]); +} + +void MP4BytesProperty::Write(MP4File* pFile, u_int32_t index) +{ + if (m_implicit) { + return; + } + pFile->WriteBytes(m_values[index], m_valueSizes[index]); +} + +// MP4TableProperty + +MP4TableProperty::MP4TableProperty(char* name, MP4IntegerProperty* pCountProperty) + : MP4Property(name) +{ + m_pCountProperty = pCountProperty; + m_pCountProperty->SetReadOnly(); +} + +MP4TableProperty::~MP4TableProperty() +{ + for (u_int32_t i = 0; i < m_pProperties.Size(); i++) { + delete m_pProperties[i]; + } +} + +void MP4TableProperty::AddProperty(MP4Property* pProperty) +{ + ASSERT(pProperty); + ASSERT(pProperty->GetType() != TableProperty); + ASSERT(pProperty->GetType() != DescriptorProperty); + m_pProperties.Add(pProperty); + pProperty->SetParentAtom(m_pParentAtom); + pProperty->SetCount(0); +} + +bool MP4TableProperty::FindProperty(const char *name, + MP4Property** ppProperty, u_int32_t* pIndex) +{ + ASSERT(m_name); + + // check if first component of name matches ourselves + if (!MP4NameFirstMatches(m_name, name)) { + return false; + } + + // check if the specified table entry exists + u_int32_t index; + bool haveIndex = MP4NameFirstIndex(name, &index); + if (haveIndex) { + if (index >= GetCount()) { + return false; + } + if (pIndex) { + *pIndex = index; + } + } + + VERBOSE_FIND(m_pParentAtom->GetFile()->GetVerbosity(), + printf("FindProperty: matched %s\n", name)); + + // get name of table property + const char *tablePropName = MP4NameAfterFirst(name); + if (tablePropName == NULL) { + if (!haveIndex) { + *ppProperty = this; + return true; + } + return false; + } + + // check if this table property exists + return FindContainedProperty(tablePropName, ppProperty, pIndex); +} + +bool MP4TableProperty::FindContainedProperty(const char *name, + MP4Property** ppProperty, u_int32_t* pIndex) +{ + u_int32_t numProperties = m_pProperties.Size(); + + for (u_int32_t i = 0; i < numProperties; i++) { + if (m_pProperties[i]->FindProperty(name, ppProperty, pIndex)) { + return true; + } + } + return false; +} + +void MP4TableProperty::Read(MP4File* pFile, u_int32_t index) +{ + ASSERT(index == 0); + + if (m_implicit) { + return; + } + + u_int32_t numProperties = m_pProperties.Size(); + + if (numProperties == 0) { + WARNING(numProperties == 0); + return; + } + + u_int32_t numEntries = GetCount(); + + /* for each property set size */ + for (u_int32_t j = 0; j < numProperties; j++) { + m_pProperties[j]->SetCount(numEntries); + } + + for (u_int32_t i = 0; i < numEntries; i++) { + ReadEntry(pFile, i); + } +} + +void MP4TableProperty::ReadEntry(MP4File* pFile, u_int32_t index) +{ + for (u_int32_t j = 0; j < m_pProperties.Size(); j++) { + m_pProperties[j]->Read(pFile, index); + } +} + +void MP4TableProperty::Write(MP4File* pFile, u_int32_t index) +{ + ASSERT(index == 0); + + if (m_implicit) { + return; + } + + u_int32_t numProperties = m_pProperties.Size(); + + if (numProperties == 0) { + WARNING(numProperties == 0); + return; + } + + u_int32_t numEntries = GetCount(); + + if (m_pProperties[0]->GetCount() != numEntries) { + fprintf(stderr, "%s %s \"%s\"table entries %u doesn't match count %u\n", + GetParentAtom() != NULL ? GetParentAtom()->GetType() : "", + GetName(), m_pProperties[0]->GetName(), + m_pProperties[0]->GetCount(), numEntries); + + ASSERT(m_pProperties[0]->GetCount() == numEntries); + } + + for (u_int32_t i = 0; i < numEntries; i++) { + WriteEntry(pFile, i); + } +} + +void MP4TableProperty::WriteEntry(MP4File* pFile, u_int32_t index) +{ + for (u_int32_t j = 0; j < m_pProperties.Size(); j++) { + m_pProperties[j]->Write(pFile, index); + } +} + +// MP4DescriptorProperty + +MP4DescriptorProperty::MP4DescriptorProperty(char* name, + u_int8_t tagsStart, u_int8_t tagsEnd, bool mandatory, bool onlyOne) + : MP4Property(name) +{ + SetTags(tagsStart, tagsEnd); + m_sizeLimit = 0; + m_mandatory = mandatory; + m_onlyOne = onlyOne; +} + +MP4DescriptorProperty::~MP4DescriptorProperty() +{ + for (u_int32_t i = 0; i < m_pDescriptors.Size(); i++) { + delete m_pDescriptors[i]; + } +} + +void MP4DescriptorProperty::SetParentAtom(MP4Atom* pParentAtom) { + m_pParentAtom = pParentAtom; + for (u_int32_t i = 0; i < m_pDescriptors.Size(); i++) { + m_pDescriptors[i]->SetParentAtom(pParentAtom); + } +} + +MP4Descriptor* MP4DescriptorProperty::AddDescriptor(u_int8_t tag) +{ + // check that tag is in expected range + ASSERT(tag >= m_tagsStart && tag <= m_tagsEnd); + + MP4Descriptor* pDescriptor = CreateDescriptor(tag); + ASSERT(pDescriptor); + + m_pDescriptors.Add(pDescriptor); + pDescriptor->SetParentAtom(m_pParentAtom); + + return pDescriptor; +} + +void MP4DescriptorProperty::DeleteDescriptor(u_int32_t index) +{ + delete m_pDescriptors[index]; + m_pDescriptors.Delete(index); +} + +void MP4DescriptorProperty::Generate() +{ + // generate a default descriptor + // if it is mandatory, and single + if (m_mandatory && m_onlyOne) { + MP4Descriptor* pDescriptor = + AddDescriptor(m_tagsStart); + pDescriptor->Generate(); + } +} + +bool MP4DescriptorProperty::FindProperty(const char *name, + MP4Property** ppProperty, u_int32_t* pIndex) +{ + // we're unnamed, so just check contained properties + if (m_name == NULL || !strcmp(m_name, "")) { + return FindContainedProperty(name, ppProperty, pIndex); + } + + // check if first component of name matches ourselves + if (!MP4NameFirstMatches(m_name, name)) { + return false; + } + + // check if the specific descriptor entry exists + u_int32_t descrIndex; + bool haveDescrIndex = MP4NameFirstIndex(name, &descrIndex); + + if (haveDescrIndex && descrIndex >= GetCount()) { + return false; + } + + if (m_pParentAtom) { + VERBOSE_FIND(m_pParentAtom->GetFile()->GetVerbosity(), + printf("FindProperty: matched %s\n", name)); + } + + // get name of descriptor property + name = MP4NameAfterFirst(name); + if (name == NULL) { + if (!haveDescrIndex) { + *ppProperty = this; + return true; + } + return false; + } + + /* check rest of name */ + if (haveDescrIndex) { + return m_pDescriptors[descrIndex]->FindProperty(name, + ppProperty, pIndex); + } else { + return FindContainedProperty(name, ppProperty, pIndex); + } +} + +bool MP4DescriptorProperty::FindContainedProperty(const char *name, + MP4Property** ppProperty, u_int32_t* pIndex) +{ + for (u_int32_t i = 0; i < m_pDescriptors.Size(); i++) { + if (m_pDescriptors[i]->FindProperty(name, ppProperty, pIndex)) { + return true; + } + } + return false; +} + +void MP4DescriptorProperty::Read(MP4File* pFile, u_int32_t index) +{ + ASSERT(index == 0); + + if (m_implicit) { + return; + } + + u_int64_t start = pFile->GetPosition(); + + while (true) { + // enforce size limitation + if (m_sizeLimit && pFile->GetPosition() >= start + m_sizeLimit) { + break; + } + + u_int8_t tag; + try { + pFile->PeekBytes(&tag, 1); + } + catch (MP4Error* e) { + if (pFile->GetPosition() >= pFile->GetSize()) { + // EOF + delete e; + break; + } + throw e; + } + + // check if tag is in desired range + if (tag < m_tagsStart || tag > m_tagsEnd) { + break; + } + + MP4Descriptor* pDescriptor = + AddDescriptor(tag); + + pDescriptor->Read(pFile); + } + + // warnings + if (m_mandatory && m_pDescriptors.Size() == 0) { + VERBOSE_READ(pFile->GetVerbosity(), + printf("Warning: Mandatory descriptor 0x%02x missing\n", + m_tagsStart)); + } else if (m_onlyOne && m_pDescriptors.Size() > 1) { + VERBOSE_READ(pFile->GetVerbosity(), + printf("Warning: Descriptor 0x%02x has more than one instance\n", + m_tagsStart)); + } +} + +void MP4DescriptorProperty::Write(MP4File* pFile, u_int32_t index) +{ + ASSERT(index == 0); + + if (m_implicit) { + return; + } + + for (u_int32_t i = 0; i < m_pDescriptors.Size(); i++) { + m_pDescriptors[i]->Write(pFile); + } +} diff --git a/Src/external_dependencies/libmp4v2/mp4property.h b/Src/external_dependencies/libmp4v2/mp4property.h new file mode 100644 index 00000000..c98ff122 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/mp4property.h @@ -0,0 +1,529 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#ifndef __MP4_PROPERTY_INCLUDED__ +#define __MP4_PROPERTY_INCLUDED__ + +// forward declarations +class MP4Atom; +class MP4File; + +class MP4Descriptor; +MP4ARRAY_DECL(MP4Descriptor, MP4Descriptor*); + +enum MP4PropertyType { + Integer8Property, + Integer16Property, + Integer24Property, + Integer32Property, + Integer64Property, + Float32Property, + StringProperty, + BytesProperty, + TableProperty, + DescriptorProperty, +}; + +class MP4Property { +public: + MP4Property(const char *name = NULL); + + virtual ~MP4Property() { } + + MP4Atom* GetParentAtom() { + return m_pParentAtom; + } + virtual void SetParentAtom(MP4Atom* pParentAtom) { + m_pParentAtom = pParentAtom; + } + + const char *GetName() { + return m_name; + } + + virtual MP4PropertyType GetType() = 0; + + bool IsReadOnly() { + return m_readOnly; + } + void SetReadOnly(bool value = true) { + m_readOnly = value; + } + + bool IsImplicit() { + return m_implicit; + } + void SetImplicit(bool value = true) { + m_implicit = value; + } + + virtual u_int32_t GetCount() = 0; + virtual void SetCount(u_int32_t count) = 0; + + virtual void Generate() { /* default is a no-op */ }; + + virtual void Read(MP4File* pFile, u_int32_t index = 0) = 0; + + virtual void Write(MP4File* pFile, u_int32_t index = 0) = 0; + + virtual bool FindProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex = NULL); + +protected: + MP4Atom* m_pParentAtom; + const char* m_name; + bool m_readOnly; + bool m_implicit; +}; + +MP4ARRAY_DECL(MP4Property, MP4Property*); + +class MP4IntegerProperty : public MP4Property { +protected: + MP4IntegerProperty(char* name) + : MP4Property(name) { }; + +public: + u_int64_t GetValue(u_int32_t index = 0); + + void SetValue(u_int64_t value, u_int32_t index = 0); + + void InsertValue(u_int64_t value, u_int32_t index = 0); + + void DeleteValue(u_int32_t index = 0); + + void IncrementValue(int32_t increment = 1, u_int32_t index = 0); +}; + +template <class val_t, u_int8_t size, MP4PropertyType prop_type> +class MP4IntegerPropertyT : public MP4IntegerProperty { + public: + MP4IntegerPropertyT(char* name) + : MP4IntegerProperty(name) { + SetCount(1); + m_values[0] = 0; + } + + MP4PropertyType GetType() { + //return Integer##xsize##Property; + return prop_type; + } + + u_int32_t GetCount() { + return m_values.Size(); + } + + void SetCount(u_int32_t count) { + m_values.Resize(count); + } + + val_t GetValue(u_int32_t index = 0) { + return m_values[index]; + } + + void SetValue(val_t value, u_int32_t index = 0) + { + if (m_readOnly) { + throw new MP4Error(EACCES, "property is read-only", m_name); \ + } + m_values[index] = value; + } + void AddValue(val_t value) { + m_values.Add(value); + } + void InsertValue(val_t value, u_int32_t index) { + m_values.Insert(value, index); + } + void DeleteValue(u_int32_t index) { + m_values.Delete(index); + } + void IncrementValue(int32_t increment = 1, u_int32_t index = 0) { + m_values[index] += increment; + } + void Read(MP4File* pFile, u_int32_t index = 0) { + if (m_implicit) { + return; + } + m_values[index] = (val_t)pFile->ReadUInt(size/8); + } + + void Write(MP4File* pFile, u_int32_t index = 0) { + if (m_implicit) { + return; + } + pFile->WriteUInt((u_int64_t)m_values[index], size/8); + } + + protected: + MP4TArray<val_t> m_values; + }; + +#define MP4INTEGER_PROPERTY_DECL(val_t, xsize) typedef MP4IntegerPropertyT<val_t, xsize, Integer##xsize##Property> MP4Integer##xsize##Property; + +MP4INTEGER_PROPERTY_DECL(u_int8_t, 8); +MP4INTEGER_PROPERTY_DECL(u_int16_t, 16); +MP4INTEGER_PROPERTY_DECL(u_int32_t, 24); +MP4INTEGER_PROPERTY_DECL(u_int32_t, 32); +MP4INTEGER_PROPERTY_DECL(u_int64_t, 64); + +class MP4BitfieldProperty : public MP4Integer64Property { +public: + MP4BitfieldProperty(char* name, u_int8_t numBits) + : MP4Integer64Property(name) { + ASSERT(numBits != 0); + ASSERT(numBits <= 64); + m_numBits = numBits; + } + + u_int8_t GetNumBits() { + return m_numBits; + } + void SetNumBits(u_int8_t numBits) { + m_numBits = numBits; + } + + void Read(MP4File* pFile, u_int32_t index = 0); + void Write(MP4File* pFile, u_int32_t index = 0); + +protected: + u_int8_t m_numBits; +}; + +class MP4Float32Property : public MP4Property { +public: + MP4Float32Property(char* name) + : MP4Property(name) { + m_useFixed16Format = false; + m_useFixed32Format = false; + SetCount(1); + m_values[0] = 0.0; + } + + MP4PropertyType GetType() { + return Float32Property; + } + + u_int32_t GetCount() { + return m_values.Size(); + } + void SetCount(u_int32_t count) { + m_values.Resize(count); + } + + float GetValue(u_int32_t index = 0) { + return m_values[index]; + } + + void SetValue(float value, u_int32_t index = 0) { + if (m_readOnly) { + throw new MP4Error(EACCES, "property is read-only", m_name); + } + m_values[index] = value; + } + + void AddValue(float value) { + m_values.Add(value); + } + + void InsertValue(float value, u_int32_t index) { + m_values.Insert(value, index); + } + + bool IsFixed16Format() { + return m_useFixed16Format; + } + + void SetFixed16Format(bool useFixed16Format = true) { + m_useFixed16Format = useFixed16Format; + } + + bool IsFixed32Format() { + return m_useFixed32Format; + } + + void SetFixed32Format(bool useFixed32Format = true) { + m_useFixed32Format = useFixed32Format; + } + + void Read(MP4File* pFile, u_int32_t index = 0); + void Write(MP4File* pFile, u_int32_t index = 0); + +protected: + bool m_useFixed16Format; + bool m_useFixed32Format; + MP4Float32Array m_values; +}; + +class MP4StringProperty : public MP4Property { +public: + MP4StringProperty(char* name, + bool useCountedFormat = false, bool useUnicode = false); + + ~MP4StringProperty(); + + MP4PropertyType GetType() { + return StringProperty; + } + + u_int32_t GetCount() { + return m_values.Size(); + } + + void SetCount(u_int32_t count); + + const char* GetValue(u_int32_t index = 0) { + return m_values[index]; + } + + void SetValue(const char* value, u_int32_t index = 0); + + void AddValue(const char* value) { + u_int32_t count = GetCount(); + SetCount(count + 1); + SetValue(value, count); + } + + bool IsCountedFormat() { + return m_useCountedFormat; + } + + void SetCountedFormat(bool useCountedFormat) { + m_useCountedFormat = useCountedFormat; + } + + bool IsExpandedCountedFormat() { + return m_useExpandedCount; + } + + void SetExpandedCountedFormat(bool useExpandedCount) { + m_useExpandedCount = useExpandedCount; + } + + bool IsUnicode() { + return m_useUnicode; + } + + void SetUnicode(bool useUnicode) { + m_useUnicode = useUnicode; + } + + u_int32_t GetFixedLength() { + return m_fixedLength; + } + + void SetFixedLength(u_int32_t fixedLength) { + m_fixedLength = fixedLength; + } + + void Read(MP4File* pFile, u_int32_t index = 0); + void Write(MP4File* pFile, u_int32_t index = 0); + +protected: + bool m_useCountedFormat; + bool m_useExpandedCount; + bool m_useUnicode; + u_int32_t m_fixedLength; + + MP4StringArray m_values; +}; + +class MP4BytesProperty : public MP4Property { +public: + MP4BytesProperty(char* name, u_int32_t valueSize = 0, + u_int32_t defaultValueSize = 0); + + ~MP4BytesProperty(); + + MP4PropertyType GetType() { + return BytesProperty; + } + + u_int32_t GetCount() { + return m_values.Size(); + } + + void SetCount(u_int32_t count); + + void GetValue(u_int8_t** ppValue, u_int32_t* pValueSize, + u_int32_t index = 0) { + // N.B. caller must free memory + *ppValue = (u_int8_t*)MP4Malloc(m_valueSizes[index]); + memcpy(*ppValue, m_values[index], m_valueSizes[index]); + *pValueSize = m_valueSizes[index]; + } + + void CopyValue(u_int8_t* pValue, u_int32_t index = 0) { + // N.B. caller takes responsbility for valid pointer + // and sufficient memory at the destination + memcpy(pValue, m_values[index], m_valueSizes[index]); + } + + void SetValue(const u_int8_t* pValue, u_int32_t valueSize, + u_int32_t index = 0); + + void AddValue(const u_int8_t* pValue, u_int32_t valueSize) { + u_int32_t count = GetCount(); + SetCount(count + 1); + SetValue(pValue, valueSize, count); + } + + u_int32_t GetValueSize(u_int32_t valueSize, u_int32_t index = 0) { + return m_valueSizes[index]; + } + + void SetValueSize(u_int32_t valueSize, u_int32_t index = 0); + + u_int32_t GetFixedSize() { + return m_fixedValueSize; + } + + void SetFixedSize(u_int32_t fixedSize); + + void Read(MP4File* pFile, u_int32_t index = 0); + void Write(MP4File* pFile, u_int32_t index = 0); + +protected: + u_int32_t m_fixedValueSize; + u_int32_t m_defaultValueSize; + MP4Integer32Array m_valueSizes; + MP4BytesArray m_values; +}; + +class MP4TableProperty : public MP4Property { +public: + MP4TableProperty(char* name, MP4IntegerProperty* pCountProperty); + + ~MP4TableProperty(); + + MP4PropertyType GetType() { + return TableProperty; + } + + void SetParentAtom(MP4Atom* pParentAtom) { + m_pParentAtom = pParentAtom; + for (u_int32_t i = 0; i < m_pProperties.Size(); i++) { + m_pProperties[i]->SetParentAtom(pParentAtom); + } + } + + void AddProperty(MP4Property* pProperty); + + MP4Property* GetProperty(u_int32_t index) { + return m_pProperties[index]; + } + + virtual u_int32_t GetCount() { + return m_pCountProperty->GetValue(); + } + virtual void SetCount(u_int32_t count) { + m_pCountProperty->SetValue(count); + } + + void Read(MP4File* pFile, u_int32_t index = 0); + void Write(MP4File* pFile, u_int32_t index = 0); + + bool FindProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex = NULL); + +protected: + virtual void ReadEntry(MP4File* pFile, u_int32_t index); + virtual void WriteEntry(MP4File* pFile, u_int32_t index); + + bool FindContainedProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex); + +protected: + MP4IntegerProperty* m_pCountProperty; + MP4PropertyArray m_pProperties; +}; + +class MP4DescriptorProperty : public MP4Property { +public: + MP4DescriptorProperty(char* name = NULL, + u_int8_t tagsStart = 0, u_int8_t tagsEnd = 0, + bool mandatory = false, bool onlyOne = false); + + ~MP4DescriptorProperty(); + + MP4PropertyType GetType() { + return DescriptorProperty; + } + + void SetParentAtom(MP4Atom* pParentAtom); + + void SetSizeLimit(u_int64_t sizeLimit) { + m_sizeLimit = sizeLimit; + } + + u_int32_t GetCount() { + return m_pDescriptors.Size(); + } + void SetCount(u_int32_t count) { + m_pDescriptors.Resize(count); + } + + void SetTags(u_int8_t tagsStart, u_int8_t tagsEnd = 0) { + m_tagsStart = tagsStart; + m_tagsEnd = tagsEnd ? tagsEnd : tagsStart; + } + + MP4Descriptor* AddDescriptor(u_int8_t tag); + + void AppendDescriptor(MP4Descriptor* pDescriptor) { + m_pDescriptors.Add(pDescriptor); + } + + void DeleteDescriptor(u_int32_t index); + + void Generate(); + void Read(MP4File* pFile, u_int32_t index = 0); + void Write(MP4File* pFile, u_int32_t index = 0); + + bool FindProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex = NULL); + +protected: + virtual MP4Descriptor* CreateDescriptor(u_int8_t tag); + + bool FindContainedProperty(const char* name, + MP4Property** ppProperty, u_int32_t* pIndex); + +protected: + u_int8_t m_tagsStart; + u_int8_t m_tagsEnd; + u_int64_t m_sizeLimit; + bool m_mandatory; + bool m_onlyOne; + MP4DescriptorArray m_pDescriptors; +}; + +class MP4QosQualifierProperty : public MP4DescriptorProperty { +public: + MP4QosQualifierProperty(char* name = NULL, + u_int8_t tagsStart = 0, u_int8_t tagsEnd = 0, + bool mandatory = false, bool onlyOne = false) : + MP4DescriptorProperty(name, tagsStart, tagsEnd, mandatory, onlyOne) { } + +protected: + MP4Descriptor* CreateDescriptor(u_int8_t tag); +}; + +#endif /* __MP4_PROPERTY_INCLUDED__ */ diff --git a/Src/external_dependencies/libmp4v2/mp4track.cpp b/Src/external_dependencies/libmp4v2/mp4track.cpp new file mode 100644 index 00000000..764e0e37 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/mp4track.cpp @@ -0,0 +1,1929 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001 - 2004. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + * Alix Marchandise-Franquet alix@cisco.com + * Ximpo Group Ltd. mp4v2@ximpo.com + */ + +#include "mp4common.h" +#include <limits.h> + +#define AMR_UNINITIALIZED -1 +#define AMR_TRUE 0 +#define AMR_FALSE 1 + +static uint32_t SafeMultiply(uint32_t bytesPerSample, uint32_t numSamples) +{ + if (_UI32_MAX/bytesPerSample < numSamples) + return 0; + else + return numSamples * bytesPerSample; +} + +static bool TrySafeMultiply(uint32_t bytesPerSample, uint32_t numSamples, uint32_t *value) +{ + if (_UI32_MAX/bytesPerSample < numSamples) + return false; + else + *value = numSamples * bytesPerSample; + return true; +} + +static bool TrySafeAdd(uint32_t val1, uint32_t val2, uint32_t *value) +{ + if (_UI32_MAX - val1 < val2) + return false; + else + *value = val1 + val2; + return true; +} + +MP4Track::MP4Track(MP4File* pFile, MP4Atom* pTrakAtom) +{ + m_pFile = pFile; + m_pTrakAtom = pTrakAtom; + m_pTypeProperty = NULL; + m_lastStsdIndex = 0; + m_lastSampleFile = NULL; + + m_cachedReadSampleId = MP4_INVALID_SAMPLE_ID; + m_pCachedReadSample = NULL; + m_cachedReadSampleSize = 0; + + m_writeSampleId = 1; + m_fixedSampleDuration = 0; + m_pChunkBuffer = NULL; + m_chunkBufferSize = 0; + m_chunkSamples = 0; + m_chunkDuration = 0; + + // m_bytesPerSample should be set to 1, except for the + // quicktime audio constant bit rate samples, which have non-1 values + m_bytesPerSample = 1; + m_samplesPerChunk = 0; + m_durationPerChunk = 0; + m_isAmr = AMR_UNINITIALIZED; + m_curMode = 0; + + m_pTimeScaleProperty = NULL; + m_pTrackDurationProperty = NULL; + m_pMediaDurationProperty = NULL; + m_pTrackModificationProperty = NULL; + m_pMediaModificationProperty = NULL; + m_pStszFixedSampleSizeProperty = NULL; + m_pStszSampleCountProperty = NULL; + m_pStszSampleSizeProperty = NULL; + m_pStscCountProperty = NULL; + m_pStscFirstChunkProperty = NULL; + m_pStscSamplesPerChunkProperty = NULL; + m_pStscSampleDescrIndexProperty = NULL; + m_pStscFirstSampleProperty = NULL; + m_pChunkCountProperty = NULL; + m_pChunkOffsetProperty = NULL; + m_pSttsCountProperty = NULL; + m_pSttsSampleCountProperty = NULL; + m_pSttsSampleDeltaProperty = NULL; + m_pCttsCountProperty = NULL; + m_pCttsSampleCountProperty = NULL; + m_pCttsSampleOffsetProperty = NULL; + m_pStssCountProperty = NULL; + m_pStssSampleProperty = NULL; + m_pElstCountProperty = NULL; + m_pElstMediaTimeProperty = NULL; + m_pElstDurationProperty = NULL; + m_pElstRateProperty = NULL; + m_pElstReservedProperty = NULL; + + m_cachedSttsIndex = 0; + m_cachedSttsElapsed = 0; + m_cachedSttsSid = MP4_INVALID_SAMPLE_ID; + + bool success = true; + + MP4Integer32Property* pTrackIdProperty; + success &= m_pTrakAtom->FindProperty( + "trak.tkhd.trackId", + (MP4Property**)&pTrackIdProperty); + if (success) { + m_trackId = pTrackIdProperty->GetValue(); + } + + success &= m_pTrakAtom->FindProperty( + "trak.mdia.mdhd.timeScale", + (MP4Property**)&m_pTimeScaleProperty); + if (success) { + // default chunking is 1 second of samples + m_durationPerChunk = m_pTimeScaleProperty->GetValue(); + } + + success &= m_pTrakAtom->FindProperty( + "trak.tkhd.duration", + (MP4Property**)&m_pTrackDurationProperty); + + success &= m_pTrakAtom->FindProperty( + "trak.mdia.mdhd.duration", + (MP4Property**)&m_pMediaDurationProperty); + + success &= m_pTrakAtom->FindProperty( + "trak.tkhd.modificationTime", + (MP4Property**)&m_pTrackModificationProperty); + + success &= m_pTrakAtom->FindProperty( + "trak.mdia.mdhd.modificationTime", + (MP4Property**)&m_pMediaModificationProperty); + + success &= m_pTrakAtom->FindProperty( + "trak.mdia.hdlr.handlerType", + (MP4Property**)&m_pTypeProperty); + + // get handles on sample size information + + + m_pStszFixedSampleSizeProperty = NULL; + bool have_stsz = + m_pTrakAtom->FindProperty("trak.mdia.minf.stbl.stsz.sampleSize", + (MP4Property**)&m_pStszFixedSampleSizeProperty); + + if (have_stsz) { + success &= m_pTrakAtom->FindProperty( + "trak.mdia.minf.stbl.stsz.sampleCount", + (MP4Property**)&m_pStszSampleCountProperty); + + success &= m_pTrakAtom->FindProperty( + "trak.mdia.minf.stbl.stsz.entries.entrySize", + (MP4Property**)&m_pStszSampleSizeProperty); + m_stsz_sample_bits = 32; + } else { + success &= m_pTrakAtom->FindProperty( + "trak.mdia.minf.stbl.stz2.sampleCount", + (MP4Property**)&m_pStszSampleCountProperty); + success &= m_pTrakAtom->FindProperty( + "trak.mdia.minf.stbl.stz2.entries.entrySize", + (MP4Property**)&m_pStszSampleSizeProperty); + MP4Integer8Property *stz2_field_size; + if (m_pTrakAtom->FindProperty( + "trak.mdia.minf.stbl.stz2.fieldSize", + (MP4Property **)&stz2_field_size)) { + m_stsz_sample_bits = stz2_field_size->GetValue(); + m_have_stz2_4bit_sample = false; + } else success = false; + } + + + // get handles on information needed to map sample id's to file offsets + + success &= m_pTrakAtom->FindProperty( + "trak.mdia.minf.stbl.stsc.entryCount", + (MP4Property**)&m_pStscCountProperty); + + success &= m_pTrakAtom->FindProperty( + "trak.mdia.minf.stbl.stsc.entries.firstChunk", + (MP4Property**)&m_pStscFirstChunkProperty); + + success &= m_pTrakAtom->FindProperty( + "trak.mdia.minf.stbl.stsc.entries.samplesPerChunk", + (MP4Property**)&m_pStscSamplesPerChunkProperty); + + success &= m_pTrakAtom->FindProperty( + "trak.mdia.minf.stbl.stsc.entries.sampleDescriptionIndex", + (MP4Property**)&m_pStscSampleDescrIndexProperty); + + success &= m_pTrakAtom->FindProperty( + "trak.mdia.minf.stbl.stsc.entries.firstSample", + (MP4Property**)&m_pStscFirstSampleProperty); + + bool haveStco = m_pTrakAtom->FindProperty( + "trak.mdia.minf.stbl.stco.entryCount", + (MP4Property**)&m_pChunkCountProperty); + + if (haveStco) { + success &= m_pTrakAtom->FindProperty( + "trak.mdia.minf.stbl.stco.entries.chunkOffset", + (MP4Property**)&m_pChunkOffsetProperty); + } else { + success &= m_pTrakAtom->FindProperty( + "trak.mdia.minf.stbl.co64.entryCount", + (MP4Property**)&m_pChunkCountProperty); + + success &= m_pTrakAtom->FindProperty( + "trak.mdia.minf.stbl.co64.entries.chunkOffset", + (MP4Property**)&m_pChunkOffsetProperty); + } + + // get handles on sample timing info + + success &= m_pTrakAtom->FindProperty( + "trak.mdia.minf.stbl.stts.entryCount", + (MP4Property**)&m_pSttsCountProperty); + + success &= m_pTrakAtom->FindProperty( + "trak.mdia.minf.stbl.stts.entries.sampleCount", + (MP4Property**)&m_pSttsSampleCountProperty); + + success &= m_pTrakAtom->FindProperty( + "trak.mdia.minf.stbl.stts.entries.sampleDelta", + (MP4Property**)&m_pSttsSampleDeltaProperty); + + // get handles on rendering offset info if it exists + + m_pCttsCountProperty = NULL; + m_pCttsSampleCountProperty = NULL; + m_pCttsSampleOffsetProperty = NULL; + + bool haveCtts = m_pTrakAtom->FindProperty( + "trak.mdia.minf.stbl.ctts.entryCount", + (MP4Property**)&m_pCttsCountProperty); + + if (haveCtts) { + success &= m_pTrakAtom->FindProperty( + "trak.mdia.minf.stbl.ctts.entries.sampleCount", + (MP4Property**)&m_pCttsSampleCountProperty); + + success &= m_pTrakAtom->FindProperty( + "trak.mdia.minf.stbl.ctts.entries.sampleOffset", + (MP4Property**)&m_pCttsSampleOffsetProperty); + } + + // get handles on sync sample info if it exists + + m_pStssCountProperty = NULL; + m_pStssSampleProperty = NULL; + + bool haveStss = m_pTrakAtom->FindProperty( + "trak.mdia.minf.stbl.stss.entryCount", + (MP4Property**)&m_pStssCountProperty); + + if (haveStss) { + success &= m_pTrakAtom->FindProperty( + "trak.mdia.minf.stbl.stss.entries.sampleNumber", + (MP4Property**)&m_pStssSampleProperty); + } + + // edit list + (void)InitEditListProperties(); + + // was everything found? + if (!success) { + throw new MP4Error("invalid track", "MP4Track::MP4Track"); + } + CalculateBytesPerSample(); +} + +MP4Track::~MP4Track() +{ + MP4Free(m_pCachedReadSample); + MP4Free(m_pChunkBuffer); +} + +const char* MP4Track::GetType() +{ + return m_pTypeProperty->GetValue(); +} + +void MP4Track::SetType(const char* type) +{ + m_pTypeProperty->SetValue(MP4NormalizeTrackType(type, + m_pFile->GetVerbosity())); +} + +void MP4Track::ReadSample( + MP4SampleId sampleId, + u_int8_t** ppBytes, + u_int32_t* pNumBytes, + MP4Timestamp* pStartTime, + MP4Duration* pDuration, + MP4Duration* pRenderingOffset, + bool* pIsSyncSample) +{ + if (sampleId == MP4_INVALID_SAMPLE_ID) { + throw new MP4Error("sample id can't be zero", + "MP4Track::ReadSample"); + } + + // handle unusual case of wanting to read a sample + // that is still sitting in the write chunk buffer + if (m_pChunkBuffer && sampleId >= m_writeSampleId - m_chunkSamples) { + WriteChunkBuffer(); + } + + FILE *pFile = 0; + try { + pFile = GetSampleFile(sampleId); + + } + catch (MP4Error* e) + { +// PRINT_ERROR(e); + delete e; + pFile = 0; + } + + if (pFile == (FILE*)-1) { + throw new MP4Error("sample is located in an inaccessible file", + "MP4Track::ReadSample"); + } + + u_int64_t fileOffset = GetSampleFileOffset(sampleId); + + u_int32_t sampleSize = GetSampleSize(sampleId); + if (*ppBytes != NULL && *pNumBytes < sampleSize) { + throw new MP4Error("sample buffer is too small", + "MP4Track::ReadSample"); + } + *pNumBytes = sampleSize; + + VERBOSE_READ_SAMPLE(m_pFile->GetVerbosity(), + printf("ReadSample: track %u id %u offset 0x"X64" size %u (0x%x)\n", + m_trackId, sampleId, fileOffset, *pNumBytes, *pNumBytes)); + + bool bufferMalloc = false; + if (*ppBytes == NULL) { + *ppBytes = (u_int8_t*)MP4Malloc(*pNumBytes); + bufferMalloc = true; + } + + u_int64_t oldPos = m_pFile->GetPosition(pFile); // only used in mode == 'w' + try { + m_pFile->SetPosition(fileOffset, pFile); + m_pFile->ReadBytes(*ppBytes, *pNumBytes, pFile); + + if (pStartTime || pDuration) { + GetSampleTimes(sampleId, pStartTime, pDuration); + + VERBOSE_READ_SAMPLE(m_pFile->GetVerbosity(), + printf("ReadSample: start "U64" duration "D64"\n", + (pStartTime ? *pStartTime : 0), + (pDuration ? *pDuration : 0))); + } + if (pRenderingOffset) { + *pRenderingOffset = GetSampleRenderingOffset(sampleId); + + VERBOSE_READ_SAMPLE(m_pFile->GetVerbosity(), + printf("ReadSample: renderingOffset "D64"\n", + *pRenderingOffset)); + } + if (pIsSyncSample) { + *pIsSyncSample = IsSyncSample(sampleId); + + VERBOSE_READ_SAMPLE(m_pFile->GetVerbosity(), + printf("ReadSample: isSyncSample %u\n", + *pIsSyncSample)); + } + } + + catch (MP4Error* e) { + if (bufferMalloc) { + // let's not leak memory + MP4Free(*ppBytes); + *ppBytes = NULL; + } + if (m_pFile->GetMode() == 'w') { + m_pFile->SetPosition(oldPos, pFile); + } + throw e; + } + + if (m_pFile->GetMode() == 'w') { + m_pFile->SetPosition(oldPos, pFile); + } +} + +void MP4Track::ReadSampleFragment( + MP4SampleId sampleId, + u_int32_t sampleOffset, + u_int16_t sampleLength, + u_int8_t* pDest) +{ + if (sampleId == MP4_INVALID_SAMPLE_ID) { + throw new MP4Error("invalid sample id", + "MP4Track::ReadSampleFragment"); + } + + if (sampleId != m_cachedReadSampleId) { + MP4Free(m_pCachedReadSample); + m_pCachedReadSample = NULL; + m_cachedReadSampleSize = 0; + m_cachedReadSampleId = MP4_INVALID_SAMPLE_ID; + + ReadSample( + sampleId, + &m_pCachedReadSample, + &m_cachedReadSampleSize); + + m_cachedReadSampleId = sampleId; + } + + if (sampleOffset + sampleLength > m_cachedReadSampleSize) { + throw new MP4Error("offset and/or length are too large", + "MP4Track::ReadSampleFragment"); + } + + memcpy(pDest, &m_pCachedReadSample[sampleOffset], sampleLength); +} + +void MP4Track::WriteSample( + const u_int8_t* pBytes, + u_int32_t numBytes, + MP4Duration duration, + MP4Duration renderingOffset, + bool isSyncSample) +{ + u_int8_t curMode = 0; + + VERBOSE_WRITE_SAMPLE(m_pFile->GetVerbosity(), + printf("WriteSample: track %u id %u size %u (0x%x) ", + m_trackId, m_writeSampleId, numBytes, numBytes)); + + if (pBytes == NULL && numBytes > 0) { + throw new MP4Error("no sample data", "MP4WriteSample"); + } + + if (m_isAmr == AMR_UNINITIALIZED ) { + // figure out if this is an AMR audio track + if (m_pTrakAtom->FindAtomMP4("trak.mdia.minf.stbl.stsd.samr") || + m_pTrakAtom->FindAtomMP4("trak.mdia.minf.stbl.stsd.sawb")) { + m_isAmr = AMR_TRUE; + m_curMode = (pBytes[0] >> 3) & 0x000F; + } else { + m_isAmr = AMR_FALSE; + } + } + + if (m_isAmr == AMR_TRUE) { + curMode = (pBytes[0] >> 3) &0x000F; // The mode is in the first byte + } + + if (duration == MP4_INVALID_DURATION) { + duration = GetFixedSampleDuration(); + } + + VERBOSE_WRITE_SAMPLE(m_pFile->GetVerbosity(), + printf("duration "U64"\n", duration)); + + if ((m_isAmr == AMR_TRUE) && + (m_curMode != curMode)) { + WriteChunkBuffer(); + m_curMode = curMode; + } + + // append sample bytes to chunk buffer + m_pChunkBuffer = (u_int8_t*)MP4Realloc(m_pChunkBuffer, + m_chunkBufferSize + numBytes); + if (m_pChunkBuffer == NULL) return; + memcpy(&m_pChunkBuffer[m_chunkBufferSize], pBytes, numBytes); + m_chunkBufferSize += numBytes; + m_chunkSamples++; + m_chunkDuration += duration; + + UpdateSampleSizes(m_writeSampleId, numBytes); + + UpdateSampleTimes(duration); + + UpdateRenderingOffsets(m_writeSampleId, renderingOffset); + + UpdateSyncSamples(m_writeSampleId, isSyncSample); + + if (IsChunkFull(m_writeSampleId)) { + WriteChunkBuffer(); + m_curMode = curMode; + } + + UpdateDurations(duration); + + UpdateModificationTimes(); + + m_writeSampleId++; +} + +void MP4Track::WriteChunkBuffer() +{ + if (m_chunkBufferSize == 0) { + return; + } + + u_int64_t chunkOffset = m_pFile->GetPosition(); + + // write chunk buffer + m_pFile->WriteBytes(m_pChunkBuffer, m_chunkBufferSize); + + VERBOSE_WRITE_SAMPLE(m_pFile->GetVerbosity(), + printf("WriteChunk: track %u offset 0x"X64" size %u (0x%x) numSamples %u\n", + m_trackId, chunkOffset, m_chunkBufferSize, + m_chunkBufferSize, m_chunkSamples)); + + UpdateSampleToChunk(m_writeSampleId, + m_pChunkCountProperty->GetValue() + 1, + m_chunkSamples); + + UpdateChunkOffsets(chunkOffset); + + // clean up chunk buffer + MP4Free(m_pChunkBuffer); + m_pChunkBuffer = NULL; + m_chunkBufferSize = 0; + m_chunkSamples = 0; + m_chunkDuration = 0; +} + +void MP4Track::FinishWrite() +{ + // write out any remaining samples in chunk buffer + WriteChunkBuffer(); + if (m_pStszFixedSampleSizeProperty == NULL && + m_stsz_sample_bits == 4) { + if (m_have_stz2_4bit_sample) { + ((MP4Integer8Property *)m_pStszSampleSizeProperty)->AddValue(m_stz2_4bit_sample_value); + m_pStszSampleSizeProperty->IncrementValue(); + } + } + + // record buffer size and bitrates + MP4BitfieldProperty* pBufferSizeProperty; + + if (m_pTrakAtom->FindProperty( + "trak.mdia.minf.stbl.stsd.*.esds.decConfigDescr.bufferSizeDB", + (MP4Property**)&pBufferSizeProperty)) { + pBufferSizeProperty->SetValue(GetMaxSampleSize()); + } + + MP4Integer32Property* pBitrateProperty; + + if (m_pTrakAtom->FindProperty( + "trak.mdia.minf.stbl.stsd.*.esds.decConfigDescr.maxBitrate", + (MP4Property**)&pBitrateProperty)) { + pBitrateProperty->SetValue(GetMaxBitrate()); + } + + if (m_pTrakAtom->FindProperty( + "trak.mdia.minf.stbl.stsd.*.esds.decConfigDescr.avgBitrate", + (MP4Property**)&pBitrateProperty)) { + pBitrateProperty->SetValue(GetAvgBitrate()); + } +} + +bool MP4Track::IsChunkFull(MP4SampleId sampleId) +{ + if (m_samplesPerChunk) { + return m_chunkSamples >= m_samplesPerChunk; + } + + ASSERT(m_durationPerChunk); + return m_chunkDuration >= m_durationPerChunk; +} + +u_int32_t MP4Track::GetNumberOfSamples() +{ + return m_pStszSampleCountProperty->GetValue(); +} + +u_int32_t MP4Track::GetSampleSize(MP4SampleId sampleId) +{ + if (m_pStszFixedSampleSizeProperty != NULL) + { + u_int32_t fixedSampleSize = + m_pStszFixedSampleSizeProperty->GetValue(); + + if (fixedSampleSize != 0) + { + return SafeMultiply(m_bytesPerSample, fixedSampleSize); + } + } + // will have to check for 4 bit sample size here + if (m_stsz_sample_bits == 4) { + uint8_t value = m_pStszSampleSizeProperty->GetValue((sampleId - 1) / 2); + if ((sampleId - 1) / 2 == 0) { + value >>= 4; + } else value &= 0xf; + return SafeMultiply(m_bytesPerSample, value); + } + return SafeMultiply(m_bytesPerSample, m_pStszSampleSizeProperty->GetValue(sampleId - 1)); +} + +u_int32_t MP4Track::GetMaxSampleSize() +{ + if (m_pStszFixedSampleSizeProperty != NULL) + { + u_int32_t fixedSampleSize = + m_pStszFixedSampleSizeProperty->GetValue(); + + if (fixedSampleSize != 0) + { + return SafeMultiply(m_bytesPerSample, fixedSampleSize); + } + } + + u_int32_t maxSampleSize = 0; + u_int32_t numSamples = m_pStszSampleSizeProperty->GetCount(); + for (MP4SampleId sid = 1; sid <= numSamples; sid++) { + u_int32_t sampleSize = + m_pStszSampleSizeProperty->GetValue(sid - 1); + if (sampleSize > maxSampleSize) { + maxSampleSize = sampleSize; + } + } + + return SafeMultiply(m_bytesPerSample, maxSampleSize); +} + +u_int64_t MP4Track::GetTotalOfSampleSizes() +{ + uint64_t retval; + if (m_pStszFixedSampleSizeProperty != NULL) { + u_int32_t fixedSampleSize = + m_pStszFixedSampleSizeProperty->GetValue(); + + // if fixed sample size, just need to multiply by number of samples + if (fixedSampleSize != 0) { + retval = m_bytesPerSample; + retval *= fixedSampleSize; + retval *= GetNumberOfSamples(); + return retval; + } + } + + // else non-fixed sample size, sum them + u_int64_t totalSampleSizes = 0; + u_int32_t numSamples = m_pStszSampleSizeProperty->GetCount(); + for (MP4SampleId sid = 1; sid <= numSamples; sid++) { + u_int32_t sampleSize = + m_pStszSampleSizeProperty->GetValue(sid - 1); + totalSampleSizes += sampleSize; + } + return totalSampleSizes * m_bytesPerSample; +} + +void MP4Track::SampleSizePropertyAddValue (uint32_t size) +{ + // this has to deal with different sample size values + switch (m_pStszSampleSizeProperty->GetType()) { + case Integer32Property: + ((MP4Integer32Property *)m_pStszSampleSizeProperty)->AddValue(size); + break; + case Integer16Property: + ((MP4Integer16Property *)m_pStszSampleSizeProperty)->AddValue(size); + break; + case Integer8Property: + if (m_stsz_sample_bits == 4) { + if (m_have_stz2_4bit_sample == false) { + m_have_stz2_4bit_sample = true; + m_stz2_4bit_sample_value = size << 4; + return; + } else { + m_have_stz2_4bit_sample = false; + size &= 0xf; + size |= m_stz2_4bit_sample_value; + } + } + ((MP4Integer8Property *)m_pStszSampleSizeProperty)->AddValue(size); + break; + default: break; + } + + + // m_pStszSampleSizeProperty->IncrementValue(); +} + +void MP4Track::UpdateSampleSizes(MP4SampleId sampleId, u_int32_t numBytes) +{ + if (m_bytesPerSample > 1) { + if ((numBytes % m_bytesPerSample) != 0) { + // error + VERBOSE_ERROR(m_pFile->GetVerbosity(), + printf("UpdateSampleSize: numBytes %u not divisible by bytesPerSample %u sampleId %u\n", + numBytes, m_bytesPerSample, sampleId); + ); + } + numBytes /= m_bytesPerSample; + } + // for first sample + if (sampleId == 1) { + if (m_pStszFixedSampleSizeProperty == NULL || + numBytes == 0) { + // special case of first sample is zero bytes in length + // leave m_pStszFixedSampleSizeProperty at 0 + // start recording variable sample sizes + if (m_pStszFixedSampleSizeProperty != NULL) + m_pStszFixedSampleSizeProperty->SetValue(0); + SampleSizePropertyAddValue(0); + } else { + // presume sample size is fixed + m_pStszFixedSampleSizeProperty->SetValue(numBytes); + } + } else { // sampleId > 1 + + u_int32_t fixedSampleSize = 0; + if (m_pStszFixedSampleSizeProperty != NULL) { + fixedSampleSize = m_pStszFixedSampleSizeProperty->GetValue(); + } + + // if we don't have a fixed size, or the current sample size + // doesn't match our sample size, we need to write the current + // sample size into the table + if (fixedSampleSize == 0 || numBytes != fixedSampleSize) { + + if (fixedSampleSize != 0) { + // fixed size was set; we need to clear fixed sample size + if (m_pStszFixedSampleSizeProperty != NULL) { + m_pStszFixedSampleSizeProperty->SetValue(0); + } + + // and create sizes for all previous samples + for (MP4SampleId sid = 1; sid < sampleId; sid++) { + SampleSizePropertyAddValue(fixedSampleSize); + } + } + // add size value for this sample + SampleSizePropertyAddValue(numBytes); + } + } + // either way, we increment the number of samples. + m_pStszSampleCountProperty->IncrementValue(); +#if 0 + printf("track %u sample id %u bytes %u fixed %u count %u prop %u\n", + m_trackId, sampleId, numBytes, + m_pStszFixedSampleSizeProperty->GetValue(), + m_pStszSampleSizeProperty->GetCount(), + m_pStszSampleCountProperty->GetValue()); +#endif +} + +u_int32_t MP4Track::GetAvgBitrate() +{ + if (GetDuration() == 0) { + return 0; + } + + double calc = UINT64_TO_DOUBLE(GetTotalOfSampleSizes()); + // this is a bit better - we use the whole duration + calc *= 8.0; + calc *= GetTimeScale(); + calc /= UINT64_TO_DOUBLE(GetDuration()); + // we might want to think about rounding to the next 100 or 1000 + return (uint32_t) ceil(calc); +} + +u_int32_t MP4Track::GetMaxBitrate() +{ + u_int32_t timeScale = GetTimeScale(); + MP4SampleId numSamples = GetNumberOfSamples(); + u_int32_t maxBytesPerSec = 0; + u_int32_t bytesThisSec = 0; + MP4Timestamp thisSecStart = 0; + MP4Timestamp lastSampleTime = 0; + uint32_t lastSampleSize = 0; + + MP4SampleId thisSecStartSid = 1; + for (MP4SampleId sid = 1; sid <= numSamples; sid++) { + uint32_t sampleSize; + MP4Timestamp sampleTime; + + sampleSize = GetSampleSize(sid); + GetSampleTimes(sid, &sampleTime, NULL); + + if (sampleTime < thisSecStart + timeScale) { + bytesThisSec += sampleSize; + lastSampleSize = sampleSize; + lastSampleTime = sampleTime; + } else { + // we've already written the last sample and sampleSize. + // this means that we've probably overflowed the last second + // calculate the time we've overflowed + MP4Duration overflow_dur = + (thisSecStart + timeScale) - lastSampleTime; + // calculate the duration of the last sample + MP4Duration lastSampleDur = sampleTime - lastSampleTime; + uint32_t overflow_bytes; + // now, calculate the number of bytes we overflowed. Round up. + overflow_bytes = + ((lastSampleSize * overflow_dur) + (lastSampleDur - 1)) / lastSampleDur; + + if (bytesThisSec - overflow_bytes > maxBytesPerSec) { + maxBytesPerSec = bytesThisSec - overflow_bytes; + } + + // now adjust the values for this sample. Remove the bytes + // from the first sample in this time frame + lastSampleTime = sampleTime; + lastSampleSize = sampleSize; + bytesThisSec += sampleSize; + bytesThisSec -= GetSampleSize(thisSecStartSid); + thisSecStartSid++; + GetSampleTimes(thisSecStartSid, &thisSecStart, NULL); + } + } + + return maxBytesPerSec * 8; +} + +u_int32_t MP4Track::GetSampleStscIndex(MP4SampleId sampleId) +{ + u_int32_t stscIndex; + u_int32_t numStscs = m_pStscCountProperty->GetValue(); + + if (numStscs == 0) { + throw new MP4Error("No data chunks exist", "GetSampleStscIndex"); + } + + for (stscIndex = 0; stscIndex < numStscs; stscIndex++) { + if (sampleId < m_pStscFirstSampleProperty->GetValue(stscIndex)) { + ASSERT(stscIndex != 0); + stscIndex -= 1; + break; + } + } + if (stscIndex == numStscs) { + ASSERT(stscIndex != 0); + stscIndex -= 1; + } + + return stscIndex; +} + +FILE* MP4Track::GetSampleFile(MP4SampleId sampleId) +{ + u_int32_t stscIndex = + GetSampleStscIndex(sampleId); + + u_int32_t stsdIndex = + m_pStscSampleDescrIndexProperty->GetValue(stscIndex); + + // check if the answer will be the same as last time + if (m_lastStsdIndex && stsdIndex == m_lastStsdIndex) { + return m_lastSampleFile; + } + + MP4Atom* pStsdAtom = + m_pTrakAtom->FindAtomMP4("trak.mdia.minf.stbl.stsd"); + ASSERT(pStsdAtom); + + MP4Atom* pStsdEntryAtom = + pStsdAtom->GetChildAtom(stsdIndex - 1); + ASSERT(pStsdEntryAtom); + + MP4Integer16Property* pDrefIndexProperty = NULL; + if (!pStsdEntryAtom->FindProperty( + "*.dataReferenceIndex", + (MP4Property**)&pDrefIndexProperty) || + + pDrefIndexProperty == NULL) { +return 0; + } + + u_int32_t drefIndex = + pDrefIndexProperty->GetValue(); + + MP4Atom* pDrefAtom = + m_pTrakAtom->FindAtomMP4("trak.mdia.minf.dinf.dref"); + ASSERT(pDrefAtom); + + MP4Atom* pUrlAtom = + pDrefAtom->GetChildAtom(drefIndex - 1); + ASSERT(pUrlAtom); + + FILE* pFile; + + if (pUrlAtom->GetFlags() & 1) { + pFile = NULL; // self-contained + } else { + MP4StringProperty* pLocationProperty = NULL; + ASSERT(pUrlAtom->FindProperty( + "*.location", + (MP4Property**)&pLocationProperty)); + ASSERT(pLocationProperty); + + const char* url = pLocationProperty->GetValue(); + + VERBOSE_READ_SAMPLE(m_pFile->GetVerbosity(), + printf("dref url = %s\n", url)); + + pFile = (FILE*)-1; + + // attempt to open url if it's a file url + // currently this is the only thing we understand + if (!strncmp(url, "file:", 5)) { + const char* fileName = url + 5; + if (!strncmp(fileName, "//", 2)) { + fileName = strchr(fileName + 2, '/'); + } + if (fileName) { + pFile = fopen(fileName, "rb"); + if (!pFile) { + pFile = (FILE*)-1; + } + } + } + } + + if (m_lastSampleFile) { + fclose(m_lastSampleFile); + } + + // cache the answer + m_lastStsdIndex = stsdIndex; + m_lastSampleFile = pFile; + + return pFile; +} + +u_int64_t MP4Track::GetSampleFileOffset(MP4SampleId sampleId) +{ + u_int32_t stscIndex = GetSampleStscIndex(sampleId); + + // firstChunk is the chunk index of the first chunk with + // samplesPerChunk samples in the chunk. There may be multiples - + // ie: several chunks with the same number of samples per chunk. + u_int64_t firstChunk = m_pStscFirstChunkProperty->GetValue(stscIndex); + + MP4SampleId firstSample = m_pStscFirstSampleProperty->GetValue(stscIndex); + + u_int64_t samplesPerChunk = m_pStscSamplesPerChunkProperty->GetValue(stscIndex); + + // chunkId tells which is the absolute chunk number that this sample + // is stored in. + MP4ChunkId chunkId = firstChunk + ((static_cast<unsigned long long>(sampleId) - firstSample) / samplesPerChunk); + + // chunkOffset is the file offset (absolute) for the start of the chunk + u_int64_t chunkOffset = m_pChunkOffsetProperty->GetValue(chunkId - 1); + + MP4SampleId firstSampleInChunk = sampleId - ((static_cast<unsigned long long>(sampleId) - firstSample) % samplesPerChunk); + + // need cumulative samples sizes from firstSample to sampleId - 1 + u_int64_t sampleOffset = 0; + for (MP4SampleId i = firstSampleInChunk; i < sampleId; i++) { + sampleOffset += GetSampleSize(i); + } + + return chunkOffset + sampleOffset; +} + +void MP4Track::UpdateSampleToChunk(MP4SampleId sampleId, + MP4ChunkId chunkId, u_int32_t samplesPerChunk) +{ + u_int32_t numStsc = m_pStscCountProperty->GetValue(); + + // if samplesPerChunk == samplesPerChunk of last entry + if (numStsc && samplesPerChunk == + m_pStscSamplesPerChunkProperty->GetValue(numStsc-1)) { + + // nothing to do + + } else { + // add stsc entry + m_pStscFirstChunkProperty->AddValue(chunkId); + m_pStscSamplesPerChunkProperty->AddValue(samplesPerChunk); + m_pStscSampleDescrIndexProperty->AddValue(1); + m_pStscFirstSampleProperty->AddValue(sampleId - samplesPerChunk + 1); + + m_pStscCountProperty->IncrementValue(); + } +} + +void MP4Track::UpdateChunkOffsets(u_int64_t chunkOffset) +{ + if (m_pChunkOffsetProperty->GetType() == Integer32Property) { + ((MP4Integer32Property*)m_pChunkOffsetProperty)->AddValue(chunkOffset); + } else { + ((MP4Integer64Property*)m_pChunkOffsetProperty)->AddValue(chunkOffset); + } + m_pChunkCountProperty->IncrementValue(); +} + +MP4Duration MP4Track::GetFixedSampleDuration() +{ + u_int32_t numStts = m_pSttsCountProperty->GetValue(); + + if (numStts == 0) { + return m_fixedSampleDuration; + } + if (numStts != 1) { + return MP4_INVALID_DURATION; // sample duration is not fixed + } + return m_pSttsSampleDeltaProperty->GetValue(0); +} + +void MP4Track::SetFixedSampleDuration(MP4Duration duration) +{ + u_int32_t numStts = m_pSttsCountProperty->GetValue(); + + // setting this is only allowed before samples have been written + if (numStts != 0) { + return; + } + m_fixedSampleDuration = duration; + return; +} + +void MP4Track::GetSampleTimes(MP4SampleId sampleId, + MP4Timestamp* pStartTime, MP4Duration* pDuration) +{ + u_int32_t numStts = m_pSttsCountProperty->GetValue(); + MP4SampleId sid; + MP4Duration elapsed; + + + if (m_cachedSttsSid != MP4_INVALID_SAMPLE_ID && sampleId >= m_cachedSttsSid) { + sid = m_cachedSttsSid; + elapsed = m_cachedSttsElapsed; + } else { + m_cachedSttsIndex = 0; + sid = 1; + elapsed = 0; + } + + for (u_int32_t sttsIndex = m_cachedSttsIndex; sttsIndex < numStts; sttsIndex++) { + MP4SampleId sampleCount = + m_pSttsSampleCountProperty->GetValue(sttsIndex); + MP4Duration sampleDelta = + m_pSttsSampleDeltaProperty->GetValue(sttsIndex); + + if (sampleId <= sid + sampleCount - 1) { + if (pStartTime) { + *pStartTime = (static_cast<MP4Timestamp>(sampleId) - sid); + *pStartTime *= sampleDelta; + *pStartTime += elapsed; + } + if (pDuration) { + *pDuration = sampleDelta; + } + + m_cachedSttsIndex = sttsIndex; + m_cachedSttsSid = sid; + m_cachedSttsElapsed = elapsed; + + return; + } + sid += sampleCount; + elapsed += sampleCount * sampleDelta; + } + + throw new MP4Error("sample id out of range", + "MP4Track::GetSampleTimes"); +} + +MP4SampleId MP4Track::GetSampleIdFromTime( + MP4Timestamp when, + bool wantSyncSample, + bool rewind) +{ + u_int32_t numStts = m_pSttsCountProperty->GetValue(); + MP4SampleId sid = 1; + MP4Duration elapsed = 0; + + for (u_int32_t sttsIndex = 0; sttsIndex < numStts; sttsIndex++) { + MP4SampleId sampleCount = + m_pSttsSampleCountProperty->GetValue(sttsIndex); + MP4Duration sampleDelta = + m_pSttsSampleDeltaProperty->GetValue(sttsIndex); + + if (sampleDelta == 0 && sttsIndex < numStts - 1) { + VERBOSE_READ(m_pFile->GetVerbosity(), + printf("Warning: Zero sample duration, stts entry %u\n", + sttsIndex)); + } + + MP4Duration d = when - elapsed; + + if (d <= sampleCount * sampleDelta) { + MP4SampleId sampleId = sid; + if (sampleDelta) { + sampleId += (d / sampleDelta); + } + + if (wantSyncSample) { + return GetSyncSample(sampleId, rewind); + } + return sampleId; + } + + sid += sampleCount; + elapsed += sampleCount * sampleDelta; + } + + throw new MP4Error("time out of range", + "MP4Track::GetSampleIdFromTime"); + + return 0; // satisfy MS compiler +} + +MP4ChunkId MP4Track::GetChunkIdFromTime( + MP4Timestamp when) +{ + MP4ChunkId numChunks = GetNumberOfChunks(); + for (MP4ChunkId chunk = 1; chunk <= numChunks; chunk++) + { + MP4Timestamp d = GetChunkTime(chunk); + if (d == when) + return chunk; + else if (d > when) + return chunk==1?1:(chunk-1); + } + return numChunks; +} + + +void MP4Track::UpdateSampleTimes(MP4Duration duration) +{ + u_int32_t numStts = m_pSttsCountProperty->GetValue(); + + // if duration == duration of last entry + if (numStts + && duration == m_pSttsSampleDeltaProperty->GetValue(numStts-1)) { + // increment last entry sampleCount + m_pSttsSampleCountProperty->IncrementValue(1, numStts-1); + + } else { + // add stts entry, sampleCount = 1, sampleDuration = duration + m_pSttsSampleCountProperty->AddValue(1); + m_pSttsSampleDeltaProperty->AddValue(duration); + m_pSttsCountProperty->IncrementValue();; + } +} + +u_int32_t MP4Track::GetSampleCttsIndex(MP4SampleId sampleId, + MP4SampleId* pFirstSampleId) +{ + u_int32_t numCtts = m_pCttsCountProperty->GetValue(); + + MP4SampleId sid = 1; + + for (u_int32_t cttsIndex = 0; cttsIndex < numCtts; cttsIndex++) { + u_int32_t sampleCount = + m_pCttsSampleCountProperty->GetValue(cttsIndex); + + if (sampleId <= sid + sampleCount - 1) { + if (pFirstSampleId) { + *pFirstSampleId = sid; + } + return cttsIndex; + } + sid += sampleCount; + } + + throw new MP4Error("sample id out of range", + "MP4Track::GetSampleCttsIndex"); + return 0; // satisfy MS compiler +} + +MP4Duration MP4Track::GetSampleRenderingOffset(MP4SampleId sampleId) +{ + if (m_pCttsCountProperty == NULL) { + return 0; + } + if (m_pCttsCountProperty->GetValue() == 0) { + return 0; + } + + u_int32_t cttsIndex = GetSampleCttsIndex(sampleId); + + return m_pCttsSampleOffsetProperty->GetValue(cttsIndex); +} + +void MP4Track::UpdateRenderingOffsets(MP4SampleId sampleId, + MP4Duration renderingOffset) +{ + // if ctts atom doesn't exist + if (m_pCttsCountProperty == NULL) { + + // no rendering offset, so nothing to do + if (renderingOffset == 0) { + return; + } + + // else create a ctts atom + MP4Atom* pCttsAtom = AddAtom("trak.mdia.minf.stbl", "ctts"); + + // and get handles on the properties + ASSERT(pCttsAtom->FindProperty( + "ctts.entryCount", + (MP4Property**)&m_pCttsCountProperty)); + + ASSERT(pCttsAtom->FindProperty( + "ctts.entries.sampleCount", + (MP4Property**)&m_pCttsSampleCountProperty)); + + ASSERT(pCttsAtom->FindProperty( + "ctts.entries.sampleOffset", + (MP4Property**)&m_pCttsSampleOffsetProperty)); + + // if this is not the first sample + if (sampleId > 1) { + // add a ctts entry for all previous samples + // with rendering offset equal to zero + m_pCttsSampleCountProperty->AddValue(sampleId - 1); + m_pCttsSampleOffsetProperty->AddValue(0); + m_pCttsCountProperty->IncrementValue();; + } + } + + // ctts atom exists (now) + + u_int32_t numCtts = m_pCttsCountProperty->GetValue(); + + // if renderingOffset == renderingOffset of last entry + if (numCtts && renderingOffset + == m_pCttsSampleOffsetProperty->GetValue(numCtts-1)) { + + // increment last entry sampleCount + m_pCttsSampleCountProperty->IncrementValue(1, numCtts-1); + + } else { + // add ctts entry, sampleCount = 1, sampleOffset = renderingOffset + m_pCttsSampleCountProperty->AddValue(1); + m_pCttsSampleOffsetProperty->AddValue(renderingOffset); + m_pCttsCountProperty->IncrementValue(); + } +} + +void MP4Track::SetSampleRenderingOffset(MP4SampleId sampleId, + MP4Duration renderingOffset) +{ + // check if any ctts entries exist + if (m_pCttsCountProperty == NULL + || m_pCttsCountProperty->GetValue() == 0) { + // if not then Update routine can be used + // to create a ctts entry for samples before this one + // and a ctts entry for this sample + UpdateRenderingOffsets(sampleId, renderingOffset); + + // but we also need a ctts entry + // for all samples after this one + u_int32_t afterSamples = GetNumberOfSamples() - sampleId; + + if (afterSamples) { + m_pCttsSampleCountProperty->AddValue(afterSamples); + m_pCttsSampleOffsetProperty->AddValue(0); + m_pCttsCountProperty->IncrementValue();; + } + + return; + } + + MP4SampleId firstSampleId; + u_int32_t cttsIndex = GetSampleCttsIndex(sampleId, &firstSampleId); + + // do nothing in the degenerate case + if (renderingOffset == + m_pCttsSampleOffsetProperty->GetValue(cttsIndex)) { + return; + } + + u_int32_t sampleCount = + m_pCttsSampleCountProperty->GetValue(cttsIndex); + + // if this sample has it's own ctts entry + if (sampleCount == 1) { + // then just set the value, + // note we don't attempt to collapse entries + m_pCttsSampleOffsetProperty->SetValue(renderingOffset, cttsIndex); + return; + } + + MP4SampleId lastSampleId = firstSampleId + sampleCount - 1; + + // else we share this entry with other samples + // we need to insert our own entry + if (sampleId == firstSampleId) { + // our sample is the first one + m_pCttsSampleCountProperty-> + InsertValue(1, cttsIndex); + m_pCttsSampleOffsetProperty-> + InsertValue(renderingOffset, cttsIndex); + + m_pCttsSampleCountProperty-> + SetValue(sampleCount - 1, cttsIndex + 1); + + m_pCttsCountProperty->IncrementValue(); + + } else if (sampleId == lastSampleId) { + // our sample is the last one + m_pCttsSampleCountProperty-> + InsertValue(1, cttsIndex + 1); + m_pCttsSampleOffsetProperty-> + InsertValue(renderingOffset, cttsIndex + 1); + + m_pCttsSampleCountProperty-> + SetValue(sampleCount - 1, cttsIndex); + + m_pCttsCountProperty->IncrementValue(); + + } else { + // our sample is in the middle, UGH! + + // insert our new entry + m_pCttsSampleCountProperty-> + InsertValue(1, cttsIndex + 1); + m_pCttsSampleOffsetProperty-> + InsertValue(renderingOffset, cttsIndex + 1); + + // adjust count of previous entry + m_pCttsSampleCountProperty-> + SetValue(sampleId - firstSampleId, cttsIndex); + + // insert new entry for those samples beyond our sample + m_pCttsSampleCountProperty-> + InsertValue(lastSampleId - sampleId, cttsIndex + 2); + u_int32_t oldRenderingOffset = + m_pCttsSampleOffsetProperty->GetValue(cttsIndex); + m_pCttsSampleOffsetProperty-> + InsertValue(oldRenderingOffset, cttsIndex + 2); + + m_pCttsCountProperty->IncrementValue(2); + } +} + +bool MP4Track::IsSyncSample(MP4SampleId sampleId) +{ + if (m_pStssCountProperty == NULL) { + return true; + } + + u_int32_t numStss = m_pStssCountProperty->GetValue(); + u_int32_t stssLIndex = 0; + u_int32_t stssRIndex = numStss - 1; + + while (stssRIndex >= stssLIndex){ + u_int32_t stssIndex = (stssRIndex + stssLIndex) >> 1; + MP4SampleId syncSampleId = + m_pStssSampleProperty->GetValue(stssIndex); + + if (sampleId == syncSampleId) { + return true; + } + + if (sampleId > syncSampleId) { + stssLIndex = stssIndex + 1; + } else { + stssRIndex = stssIndex - 1; + } + } + + return false; +} + +// N.B. "next" is inclusive of this sample id +MP4SampleId MP4Track::GetNextSyncSample(MP4SampleId sampleId) +{ + if (m_pStssCountProperty == NULL) { + return sampleId; + } + + u_int32_t numStss = m_pStssCountProperty->GetValue(); + for (uint32_t stssIndex = 0; stssIndex < numStss; stssIndex++) + { + MP4SampleId syncSampleId = m_pStssSampleProperty->GetValue(stssIndex); + + if (sampleId > syncSampleId) { + continue; + } + return syncSampleId; + } + + // LATER check stsh for alternate sample + + return MP4_INVALID_SAMPLE_ID; +} + +MP4SampleId MP4Track::GetSyncSample(MP4SampleId sampleId, bool rewind) +{ + if (m_pStssCountProperty == NULL) { + return sampleId; + } + + u_int32_t numStss = m_pStssCountProperty->GetValue(); + MP4SampleId prevSampleId = 1; + for (uint32_t stssIndex = 0; stssIndex < numStss; stssIndex++) + { + MP4SampleId syncSampleId = m_pStssSampleProperty->GetValue(stssIndex); + + if (sampleId > syncSampleId) { + prevSampleId = syncSampleId; + continue; + } + return rewind ? prevSampleId : syncSampleId; + } + + // LATER check stsh for alternate sample + + return MP4_INVALID_SAMPLE_ID; +} + +void MP4Track::UpdateSyncSamples(MP4SampleId sampleId, bool isSyncSample) +{ + if (isSyncSample) { + // if stss atom exists, add entry + if (m_pStssCountProperty) { + m_pStssSampleProperty->AddValue(sampleId); + m_pStssCountProperty->IncrementValue(); + } // else nothing to do (yet) + + } else { // !isSyncSample + // if stss atom doesn't exist, create one + if (m_pStssCountProperty == NULL) { + + MP4Atom* pStssAtom = AddAtom("trak.mdia.minf.stbl", "stss"); + + ASSERT(pStssAtom->FindProperty( + "stss.entryCount", + (MP4Property**)&m_pStssCountProperty)); + + ASSERT(pStssAtom->FindProperty( + "stss.entries.sampleNumber", + (MP4Property**)&m_pStssSampleProperty)); + + // set values for all samples that came before this one + for (MP4SampleId sid = 1; sid < sampleId; sid++) { + m_pStssSampleProperty->AddValue(sid); + m_pStssCountProperty->IncrementValue(); + } + } // else nothing to do + } +} + +MP4Atom* MP4Track::AddAtom(char* parentName, char* childName) +{ + MP4Atom* pChildAtom = MP4Atom::CreateAtom(childName); + + MP4Atom* pParentAtom = m_pTrakAtom->FindAtomMP4(parentName); + ASSERT(pParentAtom); + + pParentAtom->AddChildAtom(pChildAtom); + + pChildAtom->Generate(); + + return pChildAtom; +} + +u_int64_t MP4Track::GetDuration() +{ + return m_pMediaDurationProperty->GetValue(); +} + +u_int32_t MP4Track::GetTimeScale() +{ + return m_pTimeScaleProperty->GetValue(); +} + +void MP4Track::UpdateDurations(MP4Duration duration) +{ + // update media, track, and movie durations + m_pMediaDurationProperty->SetValue( + m_pMediaDurationProperty->GetValue() + duration); + + MP4Duration movieDuration = ToMovieDuration(duration); + m_pTrackDurationProperty->SetValue( + m_pTrackDurationProperty->GetValue() + movieDuration); + + m_pFile->UpdateDuration(m_pTrackDurationProperty->GetValue()); +} + +MP4Duration MP4Track::ToMovieDuration(MP4Duration trackDuration) +{ + return (trackDuration * m_pFile->GetTimeScale()) + / m_pTimeScaleProperty->GetValue(); +} + +void MP4Track::UpdateModificationTimes() +{ + // update media and track modification times + MP4Timestamp now = MP4GetAbsTimestamp(); + m_pMediaModificationProperty->SetValue(now); + m_pTrackModificationProperty->SetValue(now); +} + +u_int32_t MP4Track::GetNumberOfChunks() +{ + return m_pChunkOffsetProperty->GetCount(); +} + +u_int32_t MP4Track::GetChunkStscIndex(MP4ChunkId chunkId) +{ + u_int32_t stscIndex; + u_int32_t numStscs = m_pStscCountProperty->GetValue(); + + ASSERT(chunkId); + ASSERT(numStscs > 0); + + for (stscIndex = 0; stscIndex < numStscs; stscIndex++) { + if (chunkId < m_pStscFirstChunkProperty->GetValue(stscIndex)) { + ASSERT(stscIndex != 0); + break; + } + } + return stscIndex - 1; +} + +MP4Timestamp MP4Track::GetChunkTime(MP4ChunkId chunkId) +{ + u_int32_t stscIndex = GetChunkStscIndex(chunkId); + + MP4ChunkId firstChunkId = + m_pStscFirstChunkProperty->GetValue(stscIndex); + + MP4SampleId firstSample = + m_pStscFirstSampleProperty->GetValue(stscIndex); + + u_int32_t samplesPerChunk = + m_pStscSamplesPerChunkProperty->GetValue(stscIndex); + + MP4SampleId firstSampleInChunk = + firstSample + ((chunkId - firstChunkId) * samplesPerChunk); + + MP4Timestamp chunkTime; + + GetSampleTimes(firstSampleInChunk, &chunkTime, NULL); + + return chunkTime; +} + +u_int32_t MP4Track::GetChunkSize(MP4ChunkId chunkId) +{ + u_int32_t stscIndex = GetChunkStscIndex(chunkId); + + MP4ChunkId firstChunkId = + m_pStscFirstChunkProperty->GetValue(stscIndex); + + MP4SampleId firstSample = + m_pStscFirstSampleProperty->GetValue(stscIndex); + + u_int32_t samplesPerChunk = + m_pStscSamplesPerChunkProperty->GetValue(stscIndex); + + uint32_t chunkOffsetBytes; + if (!TrySafeMultiply(samplesPerChunk, chunkId - firstChunkId, &chunkOffsetBytes)) + return 0; + + MP4SampleId firstSampleInChunk; + if (!TrySafeAdd(firstSample, chunkOffsetBytes, &firstSampleInChunk)) + return 0; + + // need cumulative sizes of samples in chunk + u_int32_t chunkSize = 0; + for (u_int32_t i = 0; i < samplesPerChunk; i++) + { + if (!TrySafeAdd(chunkSize, GetSampleSize(firstSampleInChunk + i), &chunkSize)) + return 0; + } + + return chunkSize; +} + +void MP4Track::ReadChunk(MP4ChunkId chunkId, + u_int8_t** ppChunk, u_int32_t* pChunkSize, + MP4Timestamp* pStartTime, MP4Duration* pDuration) +{ + ASSERT(chunkId); + ASSERT(ppChunk); + ASSERT(pChunkSize); + + bool do_free=false; + u_int64_t chunkOffset = + m_pChunkOffsetProperty->GetValue(chunkId - 1); + + *pChunkSize = GetChunkSize(chunkId); + if (!*ppChunk) + { + do_free=true; + *ppChunk = (u_int8_t*)MP4Malloc(*pChunkSize); + } + + VERBOSE_READ_SAMPLE(m_pFile->GetVerbosity(), + printf("ReadChunk: track %u id %u offset 0x"X64" size %u (0x%x)\n", + m_trackId, chunkId, chunkOffset, *pChunkSize, *pChunkSize)); + + u_int64_t oldPos = m_pFile->GetPosition(); // only used in mode == 'w' + try { + m_pFile->SetPosition(chunkOffset); + m_pFile->ReadBytes(*ppChunk, *pChunkSize); + if (pStartTime) + *pStartTime = GetChunkTime(chunkId); + if (pDuration) + *pDuration = m_durationPerChunk; + } + catch (MP4Error* e) { + // let's not leak memory + if (do_free) + MP4Free(*ppChunk); + *ppChunk = NULL; + + if (m_pFile->GetMode() == 'w') { + m_pFile->SetPosition(oldPos); + } + throw e; + } + + if (m_pFile->GetMode() == 'w') { + m_pFile->SetPosition(oldPos); + } +} + +void MP4Track::RewriteChunk(MP4ChunkId chunkId, + u_int8_t* pChunk, u_int32_t chunkSize) +{ + u_int64_t chunkOffset = m_pFile->GetPosition(); + + m_pFile->WriteBytes(pChunk, chunkSize); + + m_pChunkOffsetProperty->SetValue(chunkOffset, chunkId - 1); + + VERBOSE_WRITE_SAMPLE(m_pFile->GetVerbosity(), + printf("RewriteChunk: track %u id %u offset 0x"X64" size %u (0x%x)\n", + m_trackId, chunkId, chunkOffset, chunkSize, chunkSize)); +} + +// map track type name aliases to official names + + +bool MP4Track::InitEditListProperties() +{ + m_pElstCountProperty = NULL; + m_pElstMediaTimeProperty = NULL; + m_pElstDurationProperty = NULL; + m_pElstRateProperty = NULL; + m_pElstReservedProperty = NULL; + + MP4Atom* pElstAtom = + m_pTrakAtom->FindAtomMP4("trak.edts.elst"); + + if (!pElstAtom) { + return false; + } + + (void)pElstAtom->FindProperty( + "elst.entryCount", + (MP4Property**)&m_pElstCountProperty); + (void)pElstAtom->FindProperty( + "elst.entries.mediaTime", + (MP4Property**)&m_pElstMediaTimeProperty); + (void)pElstAtom->FindProperty( + "elst.entries.segmentDuration", + (MP4Property**)&m_pElstDurationProperty); + (void)pElstAtom->FindProperty( + "elst.entries.mediaRate", + (MP4Property**)&m_pElstRateProperty); + + (void)pElstAtom->FindProperty( + "elst.entries.reserved", + (MP4Property**)&m_pElstReservedProperty); + + return m_pElstCountProperty + && m_pElstMediaTimeProperty + && m_pElstDurationProperty + && m_pElstRateProperty + && m_pElstReservedProperty; +} + +MP4EditId MP4Track::AddEdit(MP4EditId editId) +{ + if (!m_pElstCountProperty) { + (void)m_pFile->AddDescendantAtoms(m_pTrakAtom, "edts.elst"); + if (InitEditListProperties() == false) return MP4_INVALID_EDIT_ID; + } + + if (editId == MP4_INVALID_EDIT_ID) { + editId = m_pElstCountProperty->GetValue() + 1; + } + + m_pElstMediaTimeProperty->InsertValue(0, editId - 1); + m_pElstDurationProperty->InsertValue(0, editId - 1); + m_pElstRateProperty->InsertValue(1, editId - 1); + m_pElstReservedProperty->InsertValue(0, editId - 1); + + m_pElstCountProperty->IncrementValue(); + + return editId; +} + +void MP4Track::DeleteEdit(MP4EditId editId) +{ + if (editId == MP4_INVALID_EDIT_ID) { + throw new MP4Error("edit id can't be zero", + "MP4Track::DeleteEdit"); + } + + if (!m_pElstCountProperty + || m_pElstCountProperty->GetValue() == 0) { + throw new MP4Error("no edits exist", + "MP4Track::DeleteEdit"); + } + + m_pElstMediaTimeProperty->DeleteValue(editId - 1); + m_pElstDurationProperty->DeleteValue(editId - 1); + m_pElstRateProperty->DeleteValue(editId - 1); + m_pElstReservedProperty->DeleteValue(editId - 1); + + m_pElstCountProperty->IncrementValue(-1); + + // clean up if last edit is deleted + if (m_pElstCountProperty->GetValue() == 0) { + m_pElstCountProperty = NULL; + m_pElstMediaTimeProperty = NULL; + m_pElstDurationProperty = NULL; + m_pElstRateProperty = NULL; + m_pElstReservedProperty = NULL; + + m_pTrakAtom->DeleteChildAtom( + m_pTrakAtom->FindAtomMP4("trak.edts")); + } +} + +MP4Timestamp MP4Track::GetEditStart( + MP4EditId editId) +{ + if (editId == MP4_INVALID_EDIT_ID) { + return MP4_INVALID_TIMESTAMP; + } else if (editId == 1) { + return 0; + } + return (MP4Timestamp)GetEditTotalDuration(editId - 1); +} + +MP4Duration MP4Track::GetEditTotalDuration( + MP4EditId editId) +{ + u_int32_t numEdits = 0; + + if (m_pElstCountProperty) { + numEdits = m_pElstCountProperty->GetValue(); + } + + if (editId == MP4_INVALID_EDIT_ID) { + editId = numEdits; + } + + if (numEdits == 0 || editId > numEdits) { + return MP4_INVALID_DURATION; + } + + MP4Duration totalDuration = 0; + + for (MP4EditId eid = 1; eid <= editId; eid++) { + totalDuration += + m_pElstDurationProperty->GetValue(eid - 1); + } + + return totalDuration; +} + +MP4SampleId MP4Track::GetSampleIdFromEditTime( + MP4Timestamp editWhen, + MP4Timestamp* pStartTime, + MP4Duration* pDuration) +{ + MP4SampleId sampleId = MP4_INVALID_SAMPLE_ID; + u_int32_t numEdits = 0; + + if (m_pElstCountProperty) { + numEdits = m_pElstCountProperty->GetValue(); + } + + if (numEdits) { + MP4Duration editElapsedDuration = 0; + + for (MP4EditId editId = 1; editId <= numEdits; editId++) { + // remember edit segment's start time (in edit timeline) + MP4Timestamp editStartTime = + (MP4Timestamp)editElapsedDuration; + + // accumulate edit segment's duration + editElapsedDuration += + m_pElstDurationProperty->GetValue(editId - 1); + + // calculate difference between the specified edit time + // and the end of this edit segment + if (editElapsedDuration - editWhen <= 0) { + // the specified time has not yet been reached + continue; + } + + // 'editWhen' is within this edit segment + + // calculate the specified edit time + // relative to just this edit segment + MP4Duration editOffset = + editWhen - editStartTime; + + // calculate the media (track) time that corresponds + // to the specified edit time based on the edit list + MP4Timestamp mediaWhen = + m_pElstMediaTimeProperty->GetValue(editId - 1) + + editOffset; + + // lookup the sample id for the media time + sampleId = GetSampleIdFromTime(mediaWhen, false); + + // lookup the sample's media start time and duration + MP4Timestamp sampleStartTime; + MP4Duration sampleDuration; + + GetSampleTimes(sampleId, &sampleStartTime, &sampleDuration); + + // calculate the difference if any between when the sample + // would naturally start and when it starts in the edit timeline + MP4Duration sampleStartOffset = + mediaWhen - sampleStartTime; + + // calculate the start time for the sample in the edit time line + MP4Timestamp editSampleStartTime = + editWhen - MIN(editOffset, sampleStartOffset); + + MP4Duration editSampleDuration = 0; + + // calculate how long this sample lasts in the edit list timeline + if (m_pElstRateProperty->GetValue(editId - 1) == 0) { + // edit segment is a "dwell" + // so sample duration is that of the edit segment + editSampleDuration = + m_pElstDurationProperty->GetValue(editId - 1); + + } else { + // begin with the natural sample duration + editSampleDuration = sampleDuration; + + // now shorten that if the edit segment starts + // after the sample would naturally start + if (editOffset < sampleStartOffset) { + editSampleDuration -= sampleStartOffset - editOffset; + } + + // now shorten that if the edit segment ends + // before the sample would naturally end + if (editElapsedDuration + < editSampleStartTime + sampleDuration) { + editSampleDuration -= (editSampleStartTime + sampleDuration) + - editElapsedDuration; + } + } + + if (pStartTime) { + *pStartTime = editSampleStartTime; + } + + if (pDuration) { + *pDuration = editSampleDuration; + } + + VERBOSE_EDIT(m_pFile->GetVerbosity(), + printf("GetSampleIdFromEditTime: when "U64" " + "sampleId %u start "U64" duration "D64"\n", + editWhen, sampleId, + editSampleStartTime, editSampleDuration)); + + return sampleId; + } + + throw new MP4Error("time out of range", + "MP4Track::GetSampleIdFromEditTime"); + + } else { // no edit list + sampleId = GetSampleIdFromTime(editWhen, false); + + if (pStartTime || pDuration) { + GetSampleTimes(sampleId, pStartTime, pDuration); + } + } + + return sampleId; +} + +void MP4Track::CalculateBytesPerSample () +{ + MP4Atom *pMedia = m_pTrakAtom->FindAtomMP4("trak.mdia.minf.stbl.stsd"); + MP4Atom *pMediaData; + const char *media_data_name; + if (pMedia == NULL) return; + + if (pMedia->GetNumberOfChildAtoms() != 1) return; + + pMediaData = pMedia->GetChildAtom(0); + media_data_name = pMediaData->GetType(); + if ((ATOMID(media_data_name) == ATOMID("twos")) || + (ATOMID(media_data_name) == ATOMID("sowt"))) { + MP4IntegerProperty *chan, *sampleSize; + chan = (MP4IntegerProperty *)pMediaData->GetProperty(4); + sampleSize = (MP4IntegerProperty *)pMediaData->GetProperty(5); + m_bytesPerSample = chan->GetValue() * (sampleSize->GetValue() / 8); + } +} + diff --git a/Src/external_dependencies/libmp4v2/mp4track.h b/Src/external_dependencies/libmp4v2/mp4track.h new file mode 100644 index 00000000..720c2459 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/mp4track.h @@ -0,0 +1,263 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001 - 2004. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + * Ximpo Group Ltd. mp4v2@ximpo.com + */ + +#ifndef __MP4_TRACK_INCLUDED__ +#define __MP4_TRACK_INCLUDED__ + +#include "mp4property.h" +// forward declarations +class MP4File; +class MP4Atom; +class MP4Property; +class MP4StringProperty; + +class MP4Track { +public: + MP4Track(MP4File* pFile, MP4Atom* pTrakAtom); + + virtual ~MP4Track(); + + MP4TrackId GetId() { + return m_trackId; + } + + const char* GetType(); + + void SetType(const char* type); + + MP4File* GetFile() { + return m_pFile; + } + + MP4Atom* GetTrakAtom() { + return m_pTrakAtom; + } + + void ReadSample( + // input parameters + MP4SampleId sampleId, + // output parameters + u_int8_t** ppBytes, + u_int32_t* pNumBytes, + MP4Timestamp* pStartTime = NULL, + MP4Duration* pDuration = NULL, + MP4Duration* pRenderingOffset = NULL, + bool* pIsSyncSample = NULL); + + void WriteSample( + const u_int8_t* pBytes, + u_int32_t numBytes, + MP4Duration duration = 0, + MP4Duration renderingOffset = 0, + bool isSyncSample = true); + + virtual void FinishWrite(); + + u_int64_t GetDuration(); // in track timeScale units + u_int32_t GetTimeScale(); + u_int32_t GetNumberOfSamples(); + u_int32_t GetSampleSize(MP4SampleId sampleId); + u_int32_t GetMaxSampleSize(); + u_int64_t GetTotalOfSampleSizes(); + u_int32_t GetAvgBitrate(); // in bps + u_int32_t GetMaxBitrate(); // in bps + + MP4Duration GetFixedSampleDuration(); + void SetFixedSampleDuration(MP4Duration duration); + + void GetSampleTimes(MP4SampleId sampleId, + MP4Timestamp* pStartTime, MP4Duration* pDuration); + + bool IsSyncSample(MP4SampleId sampleId); + + MP4SampleId GetSampleIdFromTime( + MP4Timestamp when, + bool wantSyncSample = false, + bool rewind = false); + + MP4ChunkId GetChunkIdFromTime(MP4Timestamp when); + + MP4Duration GetSampleRenderingOffset(MP4SampleId sampleId); + void SetSampleRenderingOffset(MP4SampleId sampleId, + MP4Duration renderingOffset); + + MP4EditId AddEdit( + MP4EditId editId = MP4_INVALID_EDIT_ID); + + void DeleteEdit( + MP4EditId editId); + + MP4Timestamp GetEditStart( + MP4EditId editId); + + MP4Timestamp GetEditTotalDuration( + MP4EditId editId); + + MP4SampleId GetSampleIdFromEditTime( + MP4Timestamp editWhen, + MP4Timestamp* pStartTime = NULL, + MP4Duration* pDuration = NULL); + + // special operation for use during hint track packet assembly + void ReadSampleFragment( + MP4SampleId sampleId, + u_int32_t sampleOffset, + u_int16_t sampleLength, + u_int8_t* pDest); + + // special operations for use during optimization + + u_int32_t GetNumberOfChunks(); + + MP4Timestamp GetChunkTime(MP4ChunkId chunkId); + + void ReadChunk(MP4ChunkId chunkId, + u_int8_t** ppChunk, u_int32_t* pChunkSize, + MP4Timestamp* pStartTime = NULL, + MP4Duration* pDuration = NULL); + + void RewriteChunk(MP4ChunkId chunkId, + u_int8_t* pChunk, u_int32_t chunkSize); + +protected: + bool InitEditListProperties(); + + FILE* GetSampleFile(MP4SampleId sampleId); + u_int64_t GetSampleFileOffset(MP4SampleId sampleId); + u_int32_t GetSampleStscIndex(MP4SampleId sampleId); + u_int32_t GetChunkStscIndex(MP4ChunkId chunkId); + u_int32_t GetChunkSize(MP4ChunkId chunkId); + u_int32_t GetSampleCttsIndex(MP4SampleId sampleId, + MP4SampleId* pFirstSampleId = NULL); + MP4SampleId GetNextSyncSample(MP4SampleId sampleId); + MP4SampleId GetSyncSample(MP4SampleId sampleId, bool rewind = false); + + void UpdateSampleSizes(MP4SampleId sampleId, + u_int32_t numBytes); + bool IsChunkFull(MP4SampleId sampleId); + void UpdateSampleToChunk(MP4SampleId sampleId, + MP4ChunkId chunkId, u_int32_t samplesPerChunk); + void UpdateChunkOffsets(u_int64_t chunkOffset); + void UpdateSampleTimes(MP4Duration duration); + void UpdateRenderingOffsets(MP4SampleId sampleId, + MP4Duration renderingOffset); + void UpdateSyncSamples(MP4SampleId sampleId, + bool isSyncSample); + + MP4Atom* AddAtom(char* parentName, char* childName); + + void UpdateDurations(MP4Duration duration); + MP4Duration ToMovieDuration(MP4Duration trackDuration); + + void UpdateModificationTimes(); + + void WriteChunkBuffer(); + + void CalculateBytesPerSample(); +protected: + MP4File* m_pFile; + MP4Atom* m_pTrakAtom; // moov.trak[] + MP4TrackId m_trackId; // moov.trak[].tkhd.trackId + MP4StringProperty* m_pTypeProperty; // moov.trak[].mdia.hdlr.handlerType + + u_int32_t m_lastStsdIndex; + FILE* m_lastSampleFile; + + // for efficient construction of hint track packets + MP4SampleId m_cachedReadSampleId; + u_int8_t* m_pCachedReadSample; + u_int32_t m_cachedReadSampleSize; + + // for writing + MP4SampleId m_writeSampleId; + MP4Duration m_fixedSampleDuration; + u_int8_t* m_pChunkBuffer; + u_int32_t m_chunkBufferSize; + u_int32_t m_chunkSamples; + MP4Duration m_chunkDuration; + + // controls for chunking + u_int32_t m_samplesPerChunk; + MP4Duration m_durationPerChunk; + + u_int32_t m_bytesPerSample; + + // controls for AMR chunking + int m_isAmr; + u_int8_t m_curMode; + + MP4Integer32Property* m_pTimeScaleProperty; + MP4IntegerProperty* m_pTrackDurationProperty; // 32 or 64 bits + MP4IntegerProperty* m_pMediaDurationProperty; // 32 or 64 bits + MP4IntegerProperty* m_pTrackModificationProperty; // 32 or 64 bits + MP4IntegerProperty* m_pMediaModificationProperty; // 32 or 64 bits + + MP4Integer32Property* m_pStszFixedSampleSizeProperty; + MP4Integer32Property* m_pStszSampleCountProperty; + + void SampleSizePropertyAddValue(uint32_t bytes); + uint8_t m_stsz_sample_bits; + bool m_have_stz2_4bit_sample; + uint8_t m_stz2_4bit_sample_value; + MP4IntegerProperty* m_pStszSampleSizeProperty; + + MP4Integer32Property* m_pStscCountProperty; + MP4Integer32Property* m_pStscFirstChunkProperty; + MP4Integer32Property* m_pStscSamplesPerChunkProperty; + MP4Integer32Property* m_pStscSampleDescrIndexProperty; + MP4Integer32Property* m_pStscFirstSampleProperty; + + MP4Integer32Property* m_pChunkCountProperty; + MP4IntegerProperty* m_pChunkOffsetProperty; // 32 or 64 bits + + MP4Integer32Property* m_pSttsCountProperty; + MP4Integer32Property* m_pSttsSampleCountProperty; + MP4Integer32Property* m_pSttsSampleDeltaProperty; + + // for improve sequental timestamp index access + u_int32_t m_cachedSttsIndex; + MP4SampleId m_cachedSttsSid; + MP4Timestamp m_cachedSttsElapsed; + + MP4Integer32Property* m_pCttsCountProperty; + MP4Integer32Property* m_pCttsSampleCountProperty; + MP4Integer32Property* m_pCttsSampleOffsetProperty; + + MP4Integer32Property* m_pStssCountProperty; + MP4Integer32Property* m_pStssSampleProperty; + + MP4Integer32Property* m_pElstCountProperty; + MP4IntegerProperty* m_pElstMediaTimeProperty; // 32 or 64 bits + MP4IntegerProperty* m_pElstDurationProperty; // 32 or 64 bits + MP4Integer16Property* m_pElstRateProperty; + MP4Integer16Property* m_pElstReservedProperty; +}; + +MP4ARRAY_DECL(MP4Track, MP4Track*); + +#endif /* __MP4_TRACK_INCLUDED__ */ diff --git a/Src/external_dependencies/libmp4v2/mp4util.cpp b/Src/external_dependencies/libmp4v2/mp4util.cpp new file mode 100644 index 00000000..3214295d --- /dev/null +++ b/Src/external_dependencies/libmp4v2/mp4util.cpp @@ -0,0 +1,354 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001-2005. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + * Bill May wmay@cisco.com + */ + +#include "mp4common.h" + +void MP4Error::Print(FILE* pFile) +{ + fprintf(pFile, "MP4ERROR: "); + if (m_where) { + fprintf(pFile, "%s", m_where); + } + if (m_errstring) { + if (m_where) { + fprintf(pFile, ": "); + } + fprintf(pFile, "%s", m_errstring); + } + if (m_errno) { + if (m_where || m_errstring) { + fprintf(pFile, ": "); + } + fprintf(pFile, "%s", strerror(m_errno)); + } + fprintf(pFile, "\n"); +} + +void MP4HexDump( + u_int8_t* pBytes, u_int32_t numBytes, + FILE* pFile, u_int8_t indent) +{ + if (pFile == NULL) { + pFile = stdout; + } + Indent(pFile, indent); + fprintf(pFile, "<%u bytes> ", numBytes); + for (u_int32_t i = 0; i < numBytes; i++) { + if ((i % 16) == 0 && numBytes > 16) { + fprintf(pFile, "\n"); + Indent(pFile, indent); + } + fprintf(pFile, "%02x ", pBytes[i]); + } + fprintf(pFile, "\n"); +} + +bool MP4NameFirstMatches(const char* s1, const char* s2) +{ + if (s1 == NULL || *s1 == '\0' || s2 == NULL || *s2 == '\0') { + return false; + } + + if (*s2 == '*') { + return true; + } + + while (*s1 != '\0') { + if (*s2 == '\0' || strchr("[.", *s2)) { + break; + } + if (tolower(*s1) != tolower(*s2)) { + return false; + } + s1++; + s2++; + } + return true; +} + +bool MP4NameFirstIndex(const char* s, u_int32_t* pIndex) +{ + if (s == NULL) { + return false; + } + + while (*s != '\0' && *s != '.') { + if (*s == '[') { + s++; + ASSERT(pIndex); + if (sscanf(s, "%u", pIndex) != 1) { + return false; + } + return true; + } + s++; + } + return false; +} + +char* MP4NameFirst(const char *s) +{ + if (s == NULL) { + return NULL; + } + + const char* end = s; + + while (*end != '\0' && *end != '.') { + end++; + } + + char* first = (char*)MP4Calloc((end - s) + 1); + + if (first) { + strncpy(first, s, end - s); + } + + return first; +} + +const char* MP4NameAfterFirst(const char *s) +{ + if (s == NULL) { + return NULL; + } + + while (*s != '\0') { + if (*s == '.') { + s++; + if (*s == '\0') { + return NULL; + } + return s; + } + s++; + } + return NULL; +} + +char* MP4ToBase16(const u_int8_t* pData, u_int32_t dataSize) +{ + if (dataSize) { + ASSERT(pData); + } + uint size = 2 * dataSize + 1; + char* s = (char*)MP4Calloc(size); + + u_int32_t i, j; + for (i = 0, j = 0; i < dataSize; i++) { + size -= snprintf(&s[j], size, "%02x", pData[i]); + j += 2; + } + + return s; /* N.B. caller is responsible for free'ing s */ +} + +char* MP4ToBase64(const u_int8_t* pData, u_int32_t dataSize) +{ + if (pData == NULL || dataSize == 0) return NULL; + + static const char encoding[64] = { + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', + 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', + 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', + 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' + }; + + char* s = (char*)MP4Calloc((((dataSize + 2) * 4) / 3) + 1); + + const u_int8_t* src = pData; + if (pData == NULL) return NULL; + char* dest = s; + u_int32_t numGroups = dataSize / 3; + + for (u_int32_t i = 0; i < numGroups; i++) { + *dest++ = encoding[src[0] >> 2]; + *dest++ = encoding[((src[0] & 0x03) << 4) | (src[1] >> 4)]; + *dest++ = encoding[((src[1] & 0x0F) << 2) | (src[2] >> 6)]; + *dest++ = encoding[src[2] & 0x3F]; + src += 3; + } + + if (dataSize % 3 == 1) { + *dest++ = encoding[src[0] >> 2]; + *dest++ = encoding[((src[0] & 0x03) << 4)]; + *dest++ = '='; + *dest++ = '='; + } else if (dataSize % 3 == 2) { + *dest++ = encoding[src[0] >> 2]; + *dest++ = encoding[((src[0] & 0x03) << 4) | (src[1] >> 4)]; + *dest++ = encoding[((src[1] & 0x0F) << 2)]; + *dest++ = '='; + } + *dest = '\0'; + return s; /* N.B. caller is responsible for free'ing s */ +} + +static bool convertBase64 (const char data, uint8_t *value) +{ + static const uint8_t decodingarr64[128] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, + 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }; + uint8_t index = (uint8_t)data; + if ((index & 0x80) != 0) return false; + + if (decodingarr64[index] == 0xff) return false; + *value = decodingarr64[index]; + return true; +} + +uint8_t *Base64ToBinary (const char *pData, uint32_t decodeSize, uint32_t *pDataSize) +{ + uint8_t *ret; + uint32_t size, ix, groups; + if (pData == NULL || decodeSize == 0 || pDataSize == NULL) + return NULL; + + if ((decodeSize % 4) != 0) { + // must be multiples of 4 characters + return NULL; + } + size = (decodeSize * 3) / 4; + groups = decodeSize / 4; + ret = (uint8_t *)MP4Calloc(size); + if (ret == NULL) return NULL; + for (ix = 0; ix < groups; ix++) { + uint8_t value[4]; + for (uint8_t jx = 0; jx < 4; jx++) { + if (pData[jx] == '=') { + if (ix != (groups - 1)) { + free(ret); + return NULL; + } + size--; + value[jx] = 0; + } else if (convertBase64(pData[jx], &value[jx]) == false) { + free(ret); + return NULL; + } + } + ret[(ix * 3)] = value[0] << 2 | ((value[1] >> 4) & 0x3); + ret[(ix * 3) + 1] = (value[1] << 4) | (value[2] >> 2 & 0xf); + ret[(ix * 3) + 2] = ((value[2] & 0x3) << 6) | value[3]; + pData += 4; + } + *pDataSize = size; + return ret; +} + +// log2 of value, rounded up +static u_int8_t ilog2(u_int64_t value) +{ + u_int64_t powerOf2 = 1; + for (u_int8_t i = 0; i < 64; i++) { + if (value <= powerOf2) { + return i; + } + powerOf2 <<= 1; + } + return 64; +} + +u_int64_t MP4ConvertTime(u_int64_t t, + u_int32_t oldTimeScale, u_int32_t newTimeScale) +{ + // avoid float point exception + if (oldTimeScale == 0) { + throw new MP4Error("division by zero", "MP4ConvertTime"); + } + + if (oldTimeScale == newTimeScale) + return t; + + // check if we can safely use integer operations + if (ilog2(t) + ilog2(newTimeScale) <= 64) { + double d = ((double) t / (double) oldTimeScale) * (double) newTimeScale; + return (u_int64_t)d; + } + + // final resort is to use floating point + //double d = (double)newTimeScale; + //d *= UINT64_TO_DOUBLE(t); + //d /= (double)oldTimeScale; + //d += 0.5; // round up. + double d = (double)newTimeScale; + d /= (double)oldTimeScale; + d *= UINT64_TO_DOUBLE(t); + d += 0.5; // round up. + return (u_int64_t)d; +} + +const char* MP4NormalizeTrackType (const char* type, + uint32_t verbosity) +{ + if (!strcasecmp(type, "vide") + || !strcasecmp(type, "video") + || !strcasecmp(type, "mp4v") + || !strcasecmp(type, "avc1") + || !strcasecmp(type, "s263") // 3GPP H.263 + || !strcasecmp(type, "encv")) { + return MP4_VIDEO_TRACK_TYPE; + } + + if (!strcasecmp(type, "soun") + || !strcasecmp(type, "sound") + || !strcasecmp(type, "audio") + || !strcasecmp(type, "enca") + || !strcasecmp(type, "samr") // 3GPP AMR + || !strcasecmp(type, "sawb") // 3GPP AMR/WB + || !strcasecmp(type, "mp4a")) { + return MP4_AUDIO_TRACK_TYPE; + } + + if (!strcasecmp(type, "sdsm") + || !strcasecmp(type, "scene") + || !strcasecmp(type, "bifs")) { + return MP4_SCENE_TRACK_TYPE; + } + + if (!strcasecmp(type, "odsm") + || !strcasecmp(type, "od")) { + return MP4_OD_TRACK_TYPE; + } + if (strcasecmp(type, "cntl") == 0) { + return MP4_CNTL_TRACK_TYPE; + } + VERBOSE_WARNING(verbosity, + printf("Attempt to normalize %s did not match\n", + type)); + return type; +} diff --git a/Src/external_dependencies/libmp4v2/mp4util.h b/Src/external_dependencies/libmp4v2/mp4util.h new file mode 100644 index 00000000..58042993 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/mp4util.h @@ -0,0 +1,271 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#ifndef __MP4_UTIL_INCLUDED__ +#define __MP4_UTIL_INCLUDED__ +#include <assert.h> + +#ifndef ASSERT +#define ASSERT(expr) \ + if (!(expr)) { \ + assert((expr)); \ + } +#endif +#define WARNING(expr) \ + if (expr) { \ + } + +#define VERBOSE(exprverbosity, verbosity, expr) {} + +#define VERBOSE_ERROR(verbosity, expr) \ + VERBOSE(MP4_DETAILS_ERROR, verbosity, expr) + +#define VERBOSE_WARNING(verbosity, expr) \ + VERBOSE(MP4_DETAILS_WARNING, verbosity, expr) + +#define VERBOSE_READ(verbosity, expr) \ + VERBOSE(MP4_DETAILS_READ, verbosity, expr) + +#define VERBOSE_READ_TABLE(verbosity, expr) \ + VERBOSE((MP4_DETAILS_READ | MP4_DETAILS_TABLE), verbosity, expr) + +#define VERBOSE_READ_SAMPLE(verbosity, expr) \ + VERBOSE((MP4_DETAILS_READ | MP4_DETAILS_SAMPLE), verbosity, expr) + +#define VERBOSE_READ_HINT(verbosity, expr) \ + VERBOSE((MP4_DETAILS_READ | MP4_DETAILS_HINT), verbosity, expr) + +#define VERBOSE_WRITE(verbosity, expr) \ + VERBOSE(MP4_DETAILS_WRITE, verbosity, expr) + +#define VERBOSE_WRITE_TABLE(verbosity, expr) \ + VERBOSE((MP4_DETAILS_WRITE | MP4_DETAILS_TABLE), verbosity, expr) + +#define VERBOSE_WRITE_SAMPLE(verbosity, expr) \ + VERBOSE((MP4_DETAILS_WRITE | MP4_DETAILS_SAMPLE), verbosity, expr) + +#define VERBOSE_WRITE_HINT(verbosity, expr) \ + VERBOSE((MP4_DETAILS_WRITE | MP4_DETAILS_HINT), verbosity, expr) + +#define VERBOSE_FIND(verbosity, expr) \ + VERBOSE(MP4_DETAILS_FIND, verbosity, expr) + +#define VERBOSE_ISMA(verbosity, expr) \ + VERBOSE(MP4_DETAILS_ISMA, verbosity, expr) + +#define VERBOSE_EDIT(verbosity, expr) \ + VERBOSE(MP4_DETAILS_EDIT, verbosity, expr) + +inline void Indent(FILE* pFile, u_int8_t depth) { + fprintf(pFile, "%*c", depth, ' '); +} +#if 0 +static inline void MP4Printf(const char* fmt, ...) +#ifndef _WIN32 + __attribute__((format(__printf__, 1, 2))) +#endif +; + +static inline void MP4Printf(const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + // TBD API call to set error_msg_func instead of just printf + vprintf(fmt, ap); + va_end(ap); +} +#endif + + +class MP4Error { +public: + MP4Error() { + m_errno = 0; + m_errstring = NULL; + m_where = NULL; + m_free = 0; + } + ~MP4Error() { + if (m_free != 0) { + free((void *)m_errstring); + } + } + MP4Error(int err, const char* where = NULL) { + m_errno = err; + m_errstring = NULL; + m_where = where; + m_free = 0; + } + MP4Error(const char *format, const char *where, ...) { + char *string; + m_errno = 0; + string = (char *)malloc(512); + m_where = where; + if (string) { + va_list ap; + va_start(ap, where); + vsnprintf(string, 512, format, ap); + va_end(ap); + m_errstring = string; + m_free = 1; + } else { + m_errstring = format; + m_free = 0; + } + } + MP4Error(int err, const char* format, const char* where, ...) { + char *string; + m_errno = err; + string = (char *)malloc(512); + m_where = where; + if (string) { + va_list ap; + va_start(ap, where); + vsnprintf(string, 512, format, ap); + va_end(ap); + m_errstring = string; + m_free = 1; + } else { + m_errstring = format; + m_free = 0; + } + } + + void Print(FILE* pFile = stderr); + int m_free; + int m_errno; + const char* m_errstring; + const char* m_where; +}; + +void MP4HexDump( + u_int8_t* pBytes, u_int32_t numBytes, + FILE* pFile = stdout, u_int8_t indent = 0); + +inline void* MP4Malloc(size_t size) { + if (size == 0) return NULL; + void* p = malloc(size); + if (p == NULL && size > 0) { + throw new MP4Error(errno); + } + return p; +} + +inline void* MP4Calloc(size_t size) { + if (size == 0) return NULL; + return memset(MP4Malloc(size), 0, size); +} + +inline char* MP4Stralloc(const char* s1) { + char* s2 = (char*)MP4Malloc(strlen(s1) + 1); + strcpy(s2, s1); + return s2; +} + +#ifdef _NATIVE_WCHAR_T_DEFINED +inline wchar_t* MP4Stralloc(const wchar_t* s1) { + wchar_t* s2 = (wchar_t*)MP4Malloc((wcslen(s1) + 1)*sizeof(wchar_t)); + wcscpy(s2, s1); + return s2; +} +#endif + +inline uint16_t *MP4Stralloc(const uint16_t *s1) +{ + const uint16_t *itr=s1; + size_t len=0; + while (*itr) + { + itr++; + len++; + } + uint16_t* s2 = (uint16_t*)MP4Malloc((len + 1)*sizeof(uint16_t)); + memcpy(s2, s1, (len + 1)*sizeof(uint16_t)); + return s2; +} + +inline void* MP4Realloc(void* p, u_int32_t newSize) { + // workaround library bug + if (p == NULL && newSize == 0) { + return NULL; + } + p = realloc(p, newSize); + if (p == NULL && newSize > 0) { + throw new MP4Error(errno); + } + return p; +} + +inline void* MP4ReallocArray(void* p, u_int32_t numElements, u_int32_t elementSize) { + // workaround library bug + if (p == NULL && numElements == 0) { + return NULL; + } + + if (elementSize == 0 || _UI32_MAX/elementSize < numElements) + throw new MP4Error; + + p = realloc(p, numElements*elementSize); + + if (p == NULL && numElements > 0) { + throw new MP4Error(errno); + } + return p; +} + +inline u_int32_t STRTOINT32(const char* s) { + return ntohl(*(uint32_t *)s); +} + +inline void INT32TOSTR(u_int32_t i, char* s) { + *(uint32_t *)s = htonl(i); + s[4] = 0; +} + +inline MP4Timestamp MP4GetAbsTimestamp() { + struct timeval tv; + gettimeofday(&tv, NULL); + MP4Timestamp ret; + ret = tv.tv_sec; + ret += 2082844800; + return ret; // MP4 start date is 1/1/1904 + // 208284480 is (((1970 - 1904) * 365) + 17) * 24 * 60 * 60 +} + +u_int64_t MP4ConvertTime(u_int64_t t, + u_int32_t oldTimeScale, u_int32_t newTimeScale); + +bool MP4NameFirstMatches(const char* s1, const char* s2); + +bool MP4NameFirstIndex(const char* s, u_int32_t* pIndex); + +char* MP4NameFirst(const char *s); + +const char* MP4NameAfterFirst(const char *s); + +char* MP4ToBase16(const u_int8_t* pData, u_int32_t dataSize); + +char* MP4ToBase64(const u_int8_t* pData, u_int32_t dataSize); + +const char* MP4NormalizeTrackType(const char* type, + uint32_t verbosity); + +#endif /* __MP4_UTIL_INCLUDED__ */ diff --git a/Src/external_dependencies/libmp4v2/need_for_win32.c b/Src/external_dependencies/libmp4v2/need_for_win32.c new file mode 100644 index 00000000..082565dc --- /dev/null +++ b/Src/external_dependencies/libmp4v2/need_for_win32.c @@ -0,0 +1,12 @@ +#include "mpeg4ip.h" +#include <sys/timeb.h> + +int gettimeofday (struct timeval *t, void *foo) +{ + struct _timeb temp; + _ftime(&temp); + t->tv_sec = temp.time; + t->tv_usec = temp.millitm * 1000; + return (0); +} + diff --git a/Src/external_dependencies/libmp4v2/ocidescriptors.cpp b/Src/external_dependencies/libmp4v2/ocidescriptors.cpp new file mode 100644 index 00000000..29114c75 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/ocidescriptors.cpp @@ -0,0 +1,307 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4ContentClassDescriptor::MP4ContentClassDescriptor() + : MP4Descriptor() +{ + AddProperty( /* 0 */ + new MP4Integer32Property("classificationEntity")); + AddProperty( /* 1 */ + new MP4Integer16Property("classificationTable")); + AddProperty( /* 2 */ + new MP4BytesProperty("contentClassificationData")); +} + +void MP4ContentClassDescriptor::Read(MP4File* pFile) +{ + ReadHeader(pFile); + + /* byte properties need to know how long they are before reading */ + ((MP4BytesProperty*)m_pProperties[2])->SetValueSize(m_size - 6); + + ReadProperties(pFile); +} + +MP4KeywordDescriptor::MP4KeywordDescriptor() + : MP4Descriptor() +{ + AddProperty( /* 0 */ + new MP4BytesProperty("languageCode", 3)); + AddProperty( /* 1 */ + new MP4BitfieldProperty("isUTF8String", 1)); + AddProperty( /* 2 */ + new MP4BitfieldProperty("reserved", 7)); + MP4Integer8Property* pCount = + new MP4Integer8Property("keywordCount"); + AddProperty(pCount); /* 3 */ + + MP4TableProperty* pTable = new MP4TableProperty("keywords", pCount); + AddProperty(pTable); /* 4 */ + + pTable->AddProperty( /* 4, 0 */ + new MP4StringProperty("string", Counted)); + + SetReadMutate(2); +} + +void MP4KeywordDescriptor::Mutate() +{ + bool utf8Flag = ((MP4BitfieldProperty*)m_pProperties[1])->GetValue(); + MP4Property* pProperty = + ((MP4TableProperty*)m_pProperties[4])->GetProperty(0); + ASSERT(pProperty); + ((MP4StringProperty*)pProperty)->SetUnicode(!utf8Flag); +} + +MP4RatingDescriptor::MP4RatingDescriptor() + : MP4Descriptor() +{ + AddProperty( /* 0 */ + new MP4Integer32Property("ratingEntity")); + AddProperty( /* 1 */ + new MP4Integer16Property("ratingCriteria")); + AddProperty( /* 2 */ + new MP4BytesProperty("ratingInfo")); +} + +void MP4RatingDescriptor::Read(MP4File* pFile) +{ + ReadHeader(pFile); + + /* byte properties need to know how long they are before reading */ + ((MP4BytesProperty*)m_pProperties[2])->SetValueSize(m_size - 6); + + ReadProperties(pFile); +} + +MP4LanguageDescriptor::MP4LanguageDescriptor() + : MP4Descriptor() +{ + AddProperty( /* 0 */ + new MP4BytesProperty("languageCode", 3)); +} + +MP4ShortTextDescriptor::MP4ShortTextDescriptor() + : MP4Descriptor() +{ + AddProperty( /* 0 */ + new MP4BytesProperty("languageCode", 3)); + AddProperty( /* 1 */ + new MP4BitfieldProperty("isUTF8String", 1)); + AddProperty( /* 2 */ + new MP4BitfieldProperty("reserved", 7)); + AddProperty( /* 3 */ + new MP4StringProperty("eventName", Counted)); + AddProperty( /* 4 */ + new MP4StringProperty("eventText", Counted)); + + SetReadMutate(2); +} + +void MP4ShortTextDescriptor::Mutate() +{ + bool utf8Flag = ((MP4BitfieldProperty*)m_pProperties[1])->GetValue(); + ((MP4StringProperty*)m_pProperties[3])->SetUnicode(!utf8Flag); + ((MP4StringProperty*)m_pProperties[4])->SetUnicode(!utf8Flag); +} + +MP4ExpandedTextDescriptor::MP4ExpandedTextDescriptor() + : MP4Descriptor() +{ + AddProperty( /* 0 */ + new MP4BytesProperty("languageCode", 3)); + AddProperty( /* 1 */ + new MP4BitfieldProperty("isUTF8String", 1)); + AddProperty( /* 2 */ + new MP4BitfieldProperty("reserved", 7)); + MP4Integer8Property* pCount = + new MP4Integer8Property("itemCount"); + AddProperty(pCount); /* 3 */ + + MP4TableProperty* pTable = new MP4TableProperty("items", pCount); + AddProperty(pTable); /* 4 */ + + pTable->AddProperty( /* Table 0 */ + new MP4StringProperty("itemDescription", Counted)); + pTable->AddProperty( /* Table 1 */ + new MP4StringProperty("itemText", Counted)); + + AddProperty( /* 5 */ + new MP4StringProperty("nonItemText")); + ((MP4StringProperty*)m_pProperties[5])->SetExpandedCountedFormat(true); + + SetReadMutate(2); +} + +void MP4ExpandedTextDescriptor::Mutate() +{ + bool utf8Flag = ((MP4BitfieldProperty*)m_pProperties[1])->GetValue(); + + MP4Property* pProperty = + ((MP4TableProperty*)m_pProperties[4])->GetProperty(0); + ASSERT(pProperty); + ((MP4StringProperty*)pProperty)->SetUnicode(!utf8Flag); + + pProperty = ((MP4TableProperty*)m_pProperties[4])->GetProperty(1); + ASSERT(pProperty); + ((MP4StringProperty*)pProperty)->SetUnicode(!utf8Flag); + + ((MP4StringProperty*)m_pProperties[5])->SetUnicode(!utf8Flag); +} + +class MP4CreatorTableProperty : public MP4TableProperty { +public: + MP4CreatorTableProperty(char* name, MP4Integer8Property* pCountProperty) : + MP4TableProperty(name, pCountProperty) { + }; +protected: + void ReadEntry(MP4File* pFile, u_int32_t index); + void WriteEntry(MP4File* pFile, u_int32_t index); +}; + +MP4CreatorDescriptor::MP4CreatorDescriptor(u_int8_t tag) + : MP4Descriptor(tag) +{ + MP4Integer8Property* pCount = + new MP4Integer8Property("creatorCount"); + AddProperty(pCount); /* 0 */ + + MP4TableProperty* pTable = new MP4CreatorTableProperty("creators", pCount); + AddProperty(pTable); /* 1 */ + + pTable->AddProperty( /* Table 0 */ + new MP4BytesProperty("languageCode", 3, 3)); + pTable->AddProperty( /* Table 1 */ + new MP4BitfieldProperty("isUTF8String", 1)); + pTable->AddProperty( /* Table 2 */ + new MP4BitfieldProperty("reserved", 7)); + pTable->AddProperty( /* Table 3 */ + new MP4StringProperty("name", Counted)); +} + +void MP4CreatorTableProperty::ReadEntry(MP4File* pFile, u_int32_t index) +{ + m_pProperties[0]->Read(pFile, index); + m_pProperties[1]->Read(pFile, index); + + bool utf8Flag = ((MP4BitfieldProperty*)m_pProperties[1])->GetValue(index); + ((MP4StringProperty*)m_pProperties[3])->SetUnicode(!utf8Flag); + + m_pProperties[2]->Read(pFile, index); + m_pProperties[3]->Read(pFile, index); +} + +void MP4CreatorTableProperty::WriteEntry(MP4File* pFile, u_int32_t index) +{ + bool utf8Flag = ((MP4BitfieldProperty*)m_pProperties[1])->GetValue(index); + ((MP4StringProperty*)m_pProperties[3])->SetUnicode(!utf8Flag); + + MP4TableProperty::WriteEntry(pFile, index); +} + +MP4CreationDescriptor::MP4CreationDescriptor(u_int8_t tag) + : MP4Descriptor(tag) +{ + AddProperty( /* 0 */ + new MP4BitfieldProperty("contentCreationDate", 40)); +} + +MP4SmpteCameraDescriptor::MP4SmpteCameraDescriptor() + : MP4Descriptor() +{ + MP4Integer8Property* pCount = + new MP4Integer8Property("parameterCount"); + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty("parameters", pCount); + AddProperty(pTable); + + pTable->AddProperty( + new MP4Integer8Property("id")); + pTable->AddProperty( + new MP4Integer32Property("value")); +} + +MP4UnknownOCIDescriptor::MP4UnknownOCIDescriptor() + : MP4Descriptor() +{ + AddProperty( /* 0 */ + new MP4BytesProperty("data")); +} + +void MP4UnknownOCIDescriptor::Read(MP4File* pFile) +{ + ReadHeader(pFile); + + /* byte properties need to know how long they are before reading */ + ((MP4BytesProperty*)m_pProperties[0])->SetValueSize(m_size); + + ReadProperties(pFile); +} + +MP4Descriptor* CreateOCIDescriptor(u_int8_t tag) +{ + MP4Descriptor* pDescriptor = NULL; + + switch (tag) { + case MP4ContentClassDescrTag: + pDescriptor = new MP4ContentClassDescriptor(); + break; + case MP4KeywordDescrTag: + pDescriptor = new MP4KeywordDescriptor(); + break; + case MP4RatingDescrTag: + pDescriptor = new MP4RatingDescriptor(); + break; + case MP4LanguageDescrTag: + pDescriptor = new MP4LanguageDescriptor(); + break; + case MP4ShortTextDescrTag: + pDescriptor = new MP4ShortTextDescriptor(); + break; + case MP4ExpandedTextDescrTag: + pDescriptor = new MP4ExpandedTextDescriptor(); + break; + case MP4ContentCreatorDescrTag: + case MP4OCICreatorDescrTag: + pDescriptor = new MP4CreatorDescriptor(tag); + break; + case MP4ContentCreationDescrTag: + case MP4OCICreationDescrTag: + pDescriptor = new MP4CreationDescriptor(tag); + break; + case MP4SmpteCameraDescrTag: + pDescriptor = new MP4SmpteCameraDescriptor(); + break; + } + + if (pDescriptor == NULL) { + if (tag >= MP4OCIDescrTagsStart && tag <= MP4OCIDescrTagsEnd) { + pDescriptor = new MP4UnknownOCIDescriptor(); + pDescriptor->SetTag(tag); + } + } + + return pDescriptor; +} + diff --git a/Src/external_dependencies/libmp4v2/ocidescriptors.h b/Src/external_dependencies/libmp4v2/ocidescriptors.h new file mode 100644 index 00000000..d996f736 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/ocidescriptors.h @@ -0,0 +1,101 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#ifndef __OCIDESCRIPTORS_INCLUDED__ +#define __OCIDESCRIPTORS_INCLUDED__ + +const u_int8_t MP4OCIDescrTagsStart = 0x40; +const u_int8_t MP4ContentClassDescrTag = 0x40; +const u_int8_t MP4KeywordDescrTag = 0x41; +const u_int8_t MP4RatingDescrTag = 0x42; +const u_int8_t MP4LanguageDescrTag = 0x43; +const u_int8_t MP4ShortTextDescrTag = 0x44; +const u_int8_t MP4ExpandedTextDescrTag = 0x45; +const u_int8_t MP4ContentCreatorDescrTag = 0x46; +const u_int8_t MP4ContentCreationDescrTag = 0x47; +const u_int8_t MP4OCICreatorDescrTag = 0x48; +const u_int8_t MP4OCICreationDescrTag = 0x49; +const u_int8_t MP4SmpteCameraDescrTag = 0x4A; +const u_int8_t MP4OCIDescrTagsEnd = 0x5F; + +class MP4ContentClassDescriptor : public MP4Descriptor { +public: + MP4ContentClassDescriptor(); + void Read(MP4File* pFile); +}; + +class MP4KeywordDescriptor : public MP4Descriptor { +public: + MP4KeywordDescriptor(); +protected: + void Mutate(); +}; + +class MP4RatingDescriptor : public MP4Descriptor { +public: + MP4RatingDescriptor(); + void Read(MP4File* pFile); +}; + +class MP4LanguageDescriptor : public MP4Descriptor { +public: + MP4LanguageDescriptor(); +}; + +class MP4ShortTextDescriptor : public MP4Descriptor { +public: + MP4ShortTextDescriptor(); +protected: + void Mutate(); +}; + +class MP4ExpandedTextDescriptor : public MP4Descriptor { +public: + MP4ExpandedTextDescriptor(); +protected: + void Mutate(); +}; + +class MP4CreatorDescriptor : public MP4Descriptor { +public: + MP4CreatorDescriptor(u_int8_t tag); +}; + +class MP4CreationDescriptor : public MP4Descriptor { +public: + MP4CreationDescriptor(u_int8_t tag); +}; + +class MP4SmpteCameraDescriptor : public MP4Descriptor { +public: + MP4SmpteCameraDescriptor(); +}; + +class MP4UnknownOCIDescriptor : public MP4Descriptor { +public: + MP4UnknownOCIDescriptor(); + void Read(MP4File* pFile); +}; + + +extern MP4Descriptor *CreateOCIDescriptor(u_int8_t tag); + +#endif /* __OCIDESCRIPTORS_INCLUDED__ */ diff --git a/Src/external_dependencies/libmp4v2/odcommands.cpp b/Src/external_dependencies/libmp4v2/odcommands.cpp new file mode 100644 index 00000000..b6f672a3 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/odcommands.cpp @@ -0,0 +1,104 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +MP4ODUpdateDescriptor::MP4ODUpdateDescriptor() + : MP4Descriptor(MP4ODUpdateODCommandTag) +{ + // just a container for ObjectDescriptors + AddProperty( /* 0 */ + new MP4DescriptorProperty(NULL, + MP4FileODescrTag, 0, Required, Many)); +} + +MP4ODRemoveDescriptor::MP4ODRemoveDescriptor() + : MP4Descriptor(MP4ODRemoveODCommandTag) +{ + MP4Integer32Property* pCount = + new MP4Integer32Property("entryCount"); + pCount->SetImplicit(); + AddProperty(pCount); /* 0 */ + + MP4TableProperty* pTable = + new MP4TableProperty("entries", pCount); + AddProperty(pTable); /* 1 */ + + pTable->AddProperty( /* 1, 0 */ + new MP4BitfieldProperty("objectDescriptorId", 10)); +} + +void MP4ODRemoveDescriptor::Read(MP4File* pFile) +{ + // table entry count computed from descriptor size + ((MP4Integer32Property*)m_pProperties[0])->SetReadOnly(false); + ((MP4Integer32Property*)m_pProperties[0])->SetValue((m_size * 8) / 10); + ((MP4Integer32Property*)m_pProperties[0])->SetReadOnly(true); + + MP4Descriptor::Read(pFile); +} + +MP4ESUpdateDescriptor::MP4ESUpdateDescriptor() + : MP4Descriptor(MP4ESUpdateODCommandTag) +{ + AddProperty( /* 0 */ + new MP4BitfieldProperty("objectDescriptorId", 10)); + AddProperty( /* 1 */ + new MP4BitfieldProperty("pad", 6)); + AddProperty( /* 2 */ + new MP4DescriptorProperty("esIdRefs", + MP4ESIDRefDescrTag, 0, Required, Many)); +} + +// LATER might be able to combine with ESUpdateDescriptor +MP4ESRemoveDescriptor::MP4ESRemoveDescriptor() + : MP4Descriptor(MP4ESRemoveODCommandTag) +{ + AddProperty( /* 0 */ + new MP4BitfieldProperty("objectDescriptorId", 10)); + AddProperty( /* 1 */ + new MP4BitfieldProperty("pad", 6)); + AddProperty( /* 2 */ + new MP4DescriptorProperty("esIdRefs", + MP4ESIDRefDescrTag, 0, Required, Many)); +} + +MP4Descriptor* CreateODCommand(u_int8_t tag) +{ + MP4Descriptor* pDescriptor = NULL; + + switch (tag) { + case MP4ODUpdateODCommandTag: + pDescriptor = new MP4ODUpdateDescriptor(); + break; + case MP4ODRemoveODCommandTag: + pDescriptor = new MP4ODRemoveDescriptor(); + break; + case MP4ESUpdateODCommandTag: + pDescriptor = new MP4ESUpdateDescriptor(); + break; + case MP4ESRemoveODCommandTag: + pDescriptor = new MP4ESRemoveDescriptor(); + break; + } + return pDescriptor; +} + diff --git a/Src/external_dependencies/libmp4v2/odcommands.h b/Src/external_dependencies/libmp4v2/odcommands.h new file mode 100644 index 00000000..a72e6d25 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/odcommands.h @@ -0,0 +1,58 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#ifndef __ODCOMMANDS_INCLUDED__ +#define __ODCOMMANDS_INCLUDED__ + +// OD stream command descriptors +const u_int8_t MP4ODUpdateODCommandTag = 0x01; +const u_int8_t MP4ODRemoveODCommandTag = 0x02; +const u_int8_t MP4ESUpdateODCommandTag = 0x03; +const u_int8_t MP4ESRemoveODCommandTag = 0x04; +const u_int8_t MP4IPMPUpdateODCommandTag = 0x05; +const u_int8_t MP4IPMPRemoveODCommandTag = 0x06; +const u_int8_t MP4ESRemoveRefODCommandTag = 0x07; + +class MP4ODUpdateDescriptor : public MP4Descriptor { +public: + MP4ODUpdateDescriptor(); +}; + +class MP4ODRemoveDescriptor : public MP4Descriptor { +public: + MP4ODRemoveDescriptor(); + void Read(MP4File* pFile); +}; + +class MP4ESUpdateDescriptor : public MP4Descriptor { +public: + MP4ESUpdateDescriptor(); +}; + +class MP4ESRemoveDescriptor : public MP4Descriptor { +public: + MP4ESRemoveDescriptor(); +}; + +MP4Descriptor* CreateODCommand(u_int8_t tag); + +#endif /* __ODCOMMANDS_INCLUDED__ */ + diff --git a/Src/external_dependencies/libmp4v2/qosqualifiers.cpp b/Src/external_dependencies/libmp4v2/qosqualifiers.cpp new file mode 100644 index 00000000..5c286200 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/qosqualifiers.cpp @@ -0,0 +1,188 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" +#if 1 +MP4QosDescriptorBase::MP4QosDescriptorBase (u_int8_t tag) + : MP4Descriptor(tag) +{ + switch (tag) { + case MP4QosDescrTag: + AddProperty( /* 0 */ + new MP4Integer8Property("predefined")); + AddProperty( /* 1 */ + new MP4QosQualifierProperty("qualifiers", + MP4QosTagsStart, + MP4QosTagsEnd, Optional, Many)); + break; + case MP4MaxDelayQosTag: + AddProperty( /* 0 */ + new MP4Integer32Property("maxDelay")); + break; + case MP4PrefMaxDelayQosTag: + AddProperty( /* 0 */ + new MP4Integer32Property("prefMaxDelay")); + break; + case MP4LossProbQosTag: + AddProperty( /* 0 */ + new MP4Float32Property("lossProb")); + break; + case MP4MaxGapLossQosTag: + AddProperty( /* 0 */ + new MP4Integer32Property("maxGapLoss")); + break; + case MP4MaxAUSizeQosTag: + AddProperty( /* 0 */ + new MP4Integer32Property("maxAUSize")); + break; + case MP4AvgAUSizeQosTag: + AddProperty( /* 0 */ + new MP4Integer32Property("avgAUSize")); + break; + case MP4MaxAURateQosTag: + AddProperty( /* 0 */ + new MP4Integer32Property("maxAURate")); + break; + } +} + +#else +MP4QosDescriptor::MP4QosDescriptor() + : MP4Descriptor(MP4QosDescrTag) +{ + AddProperty( /* 0 */ + new MP4Integer8Property("predefined")); + AddProperty( /* 1 */ + new MP4QosQualifierProperty("qualifiers", + MP4QosTagsStart, MP4QosTagsEnd, Optional, Many)); +} + +MP4MaxDelayQosQualifier::MP4MaxDelayQosQualifier() + : MP4QosQualifier(MP4MaxDelayQosTag) +{ + AddProperty( /* 0 */ + new MP4Integer32Property("maxDelay")); +} + +MP4PrefMaxDelayQosQualifier::MP4PrefMaxDelayQosQualifier() + : MP4QosQualifier(MP4PrefMaxDelayQosTag) +{ + AddProperty( /* 0 */ + new MP4Integer32Property("prefMaxDelay")); +} + +MP4LossProbQosQualifier::MP4LossProbQosQualifier() + : MP4QosQualifier(MP4LossProbQosTag) +{ + AddProperty( /* 0 */ + new MP4Float32Property("lossProb")); +} + +MP4MaxGapLossQosQualifier::MP4MaxGapLossQosQualifier() + : MP4QosQualifier(MP4MaxGapLossQosTag) +{ + AddProperty( /* 0 */ + new MP4Integer32Property("maxGapLoss")); +} + +MP4MaxAUSizeQosQualifier::MP4MaxAUSizeQosQualifier() + : MP4QosQualifier(MP4MaxAUSizeQosTag) +{ + AddProperty( /* 0 */ + new MP4Integer32Property("maxAUSize")); +} + +MP4AvgAUSizeQosQualifier::MP4AvgAUSizeQosQualifier() + : MP4QosQualifier(MP4AvgAUSizeQosTag) +{ + AddProperty( /* 0 */ + new MP4Integer32Property("avgAUSize")); +} + +MP4MaxAURateQosQualifier::MP4MaxAURateQosQualifier() + : MP4QosQualifier(MP4MaxAURateQosTag) +{ + AddProperty( /* 0 */ + new MP4Integer32Property("maxAURate")); +} +#endif +MP4UnknownQosQualifier::MP4UnknownQosQualifier() + : MP4Descriptor() +{ + AddProperty( /* 0 */ + new MP4BytesProperty("data")); +} + +void MP4UnknownQosQualifier::Read(MP4File* pFile) +{ + ReadHeader(pFile); + + /* byte properties need to know how long they are before reading */ + ((MP4BytesProperty*)m_pProperties[0])->SetValueSize(m_size); + + ReadProperties(pFile); +} + +MP4Descriptor* MP4QosQualifierProperty::CreateDescriptor(u_int8_t tag) +{ + MP4Descriptor* pDescriptor = NULL; + switch (tag) { +#if 0 + case MP4MaxDelayQosTag: + pDescriptor = new MP4MaxDelayQosQualifier(); + break; + case MP4PrefMaxDelayQosTag: + pDescriptor = new MP4PrefMaxDelayQosQualifier(); + break; + case MP4LossProbQosTag: + pDescriptor = new MP4LossProbQosQualifier(); + break; + case MP4MaxGapLossQosTag: + pDescriptor = new MP4MaxGapLossQosQualifier(); + break; + case MP4MaxAUSizeQosTag: + pDescriptor = new MP4MaxAUSizeQosQualifier(); + break; + case MP4AvgAUSizeQosTag: + pDescriptor = new MP4AvgAUSizeQosQualifier(); + break; + case MP4MaxAURateQosTag: + pDescriptor = new MP4MaxAURateQosQualifier(); + break; +#else + case MP4MaxDelayQosTag: + case MP4PrefMaxDelayQosTag: + case MP4LossProbQosTag: + case MP4MaxGapLossQosTag: + case MP4MaxAUSizeQosTag: + case MP4AvgAUSizeQosTag: + case MP4MaxAURateQosTag: + pDescriptor = new MP4QosDescriptorBase(tag); + break; +#endif + default: + pDescriptor = new MP4UnknownQosQualifier(); + pDescriptor->SetTag(tag); + } + + return pDescriptor; +} + diff --git a/Src/external_dependencies/libmp4v2/qosqualifiers.h b/Src/external_dependencies/libmp4v2/qosqualifiers.h new file mode 100644 index 00000000..ae3822ab --- /dev/null +++ b/Src/external_dependencies/libmp4v2/qosqualifiers.h @@ -0,0 +1,94 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#ifndef __QOSQUALIFIERS_INCLUDED__ +#define __QOSQUALIFIERS_INCLUDED__ + +const u_int8_t MP4QosDescrTag = 0x0C; + +#if 0 +class MP4QosDescriptor : public MP4Descriptor { +public: + MP4QosDescriptor(); +}; + +typedef MP4Descriptor MP4QosQualifier; +#endif + +const u_int8_t MP4QosTagsStart = 0x01; +const u_int8_t MP4MaxDelayQosTag = 0x01; +const u_int8_t MP4PrefMaxDelayQosTag = 0x02; +const u_int8_t MP4LossProbQosTag = 0x03; +const u_int8_t MP4MaxGapLossQosTag = 0x04; +const u_int8_t MP4MaxAUSizeQosTag = 0x41; +const u_int8_t MP4AvgAUSizeQosTag = 0x42; +const u_int8_t MP4MaxAURateQosTag = 0x43; +const u_int8_t MP4QosTagsEnd = 0xFF; + +#if 0 +class MP4MaxDelayQosQualifier : public MP4QosQualifier { +public: + MP4MaxDelayQosQualifier(); +}; + +class MP4PrefMaxDelayQosQualifier : public MP4QosQualifier { +public: + MP4PrefMaxDelayQosQualifier(); +}; + +class MP4LossProbQosQualifier : public MP4QosQualifier { +public: + MP4LossProbQosQualifier(); +}; + +class MP4MaxGapLossQosQualifier : public MP4QosQualifier { +public: + MP4MaxGapLossQosQualifier(); +}; + +class MP4MaxAUSizeQosQualifier : public MP4QosQualifier { +public: + MP4MaxAUSizeQosQualifier(); +}; + +class MP4AvgAUSizeQosQualifier : public MP4QosQualifier { +public: + MP4AvgAUSizeQosQualifier(); +}; + +class MP4MaxAURateQosQualifier : public MP4QosQualifier { +public: + MP4MaxAURateQosQualifier(); +}; +#else +class MP4QosDescriptorBase : public MP4Descriptor { + public: + MP4QosDescriptorBase(uint8_t tag); +}; + +#endif +class MP4UnknownQosQualifier : public MP4Descriptor { +public: + MP4UnknownQosQualifier(); + void Read(MP4File* pFile); +}; + +#endif /* __QOSQUALIFIERS_INCLUDED__ */ diff --git a/Src/external_dependencies/libmp4v2/resource.h b/Src/external_dependencies/libmp4v2/resource.h new file mode 100644 index 00000000..0e840373 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by libmp4v2.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Src/external_dependencies/libmp4v2/rtphint.cpp b/Src/external_dependencies/libmp4v2/rtphint.cpp new file mode 100644 index 00000000..b0558458 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/rtphint.cpp @@ -0,0 +1,1343 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#include "mp4common.h" + +/* rtp hint track operations */ + +MP4RtpHintTrack::MP4RtpHintTrack(MP4File* pFile, MP4Atom* pTrakAtom) + : MP4Track(pFile, pTrakAtom) +{ + m_pRefTrack = NULL; + + m_pRtpMapProperty = NULL; + m_pPayloadNumberProperty = NULL; + m_pMaxPacketSizeProperty = NULL; + m_pSnroProperty = NULL; + m_pTsroProperty = NULL; + + m_rtpSequenceStart = 0; + m_rtpTimestampStart = 0; + + m_pReadHint = NULL; + m_pReadHintSample = NULL; + m_readHintSampleSize = 0; + m_readHintTimestamp = 0; + + m_pWriteHint = NULL; + m_writeHintId = MP4_INVALID_SAMPLE_ID; + m_writePacketId = 0; + + m_pTrpy = NULL; + m_pNump = NULL; + m_pTpyl = NULL; + m_pMaxr = NULL; + m_pDmed = NULL; + m_pDimm = NULL; + m_pPmax = NULL; + m_pDmax = NULL; + + m_pMaxPdu = NULL; + m_pAvgPdu = NULL; + m_pMaxBitRate = NULL; + m_pAvgBitRate = NULL; + + m_thisSec = 0; + m_bytesThisSec = 0; + m_bytesThisHint = 0; + m_bytesThisPacket = 0; +} + +MP4RtpHintTrack::~MP4RtpHintTrack() +{ + delete m_pReadHint; + delete m_pReadHintSample; + delete m_pWriteHint; +} + +void MP4RtpHintTrack::InitRefTrack() +{ + if (m_pRefTrack == NULL) { + MP4Integer32Property* pRefTrackIdProperty = NULL; + (void)m_pTrakAtom->FindProperty( + "trak.tref.hint.entries[0].trackId", + (MP4Property**)&pRefTrackIdProperty); + ASSERT(pRefTrackIdProperty); + + m_pRefTrack = m_pFile->GetTrack(pRefTrackIdProperty->GetValue()); + } +} + +void MP4RtpHintTrack::InitRtpStart() +{ + struct timeval tv; + (void)gettimeofday(&tv, NULL); + srandom((tv.tv_usec << 12) | (tv.tv_sec & 0xFFF)); + + ASSERT(m_pTrakAtom); + + (void)m_pTrakAtom->FindProperty( + "trak.udta.hnti.rtp .snro.offset", + (MP4Property**)&m_pSnroProperty); + + if (m_pSnroProperty) { + m_rtpSequenceStart = m_pSnroProperty->GetValue(); + } else { + m_rtpSequenceStart = random(); + } + + (void)m_pTrakAtom->FindProperty( + "trak.udta.hnti.rtp .tsro.offset", + (MP4Property**)&m_pTsroProperty); + + if (m_pTsroProperty) { + m_rtpTimestampStart = m_pTsroProperty->GetValue(); + } else { + m_rtpTimestampStart = random(); + } +} + +void MP4RtpHintTrack::ReadHint( + MP4SampleId hintSampleId, + u_int16_t* pNumPackets) +{ + if (m_pRefTrack == NULL) { + InitRefTrack(); + InitRtpStart(); + } + + // dispose of any old hint + delete m_pReadHint; + m_pReadHint = NULL; + delete m_pReadHintSample; + m_pReadHintSample = NULL; + m_readHintSampleSize = 0; + + // read the desired hint sample into memory + ReadSample( + hintSampleId, + &m_pReadHintSample, + &m_readHintSampleSize, + &m_readHintTimestamp); + + m_pFile->EnableMemoryBuffer(m_pReadHintSample, m_readHintSampleSize); + + m_pReadHint = new MP4RtpHint(this); + m_pReadHint->Read(m_pFile); + + m_pFile->DisableMemoryBuffer(); + + if (pNumPackets) { + *pNumPackets = GetHintNumberOfPackets(); + } +} + +u_int16_t MP4RtpHintTrack::GetHintNumberOfPackets() +{ + if (m_pReadHint == NULL) { + throw new MP4Error("no hint has been read", + "MP4GetRtpHintNumberOfPackets"); + } + return m_pReadHint->GetNumberOfPackets(); +} + +bool MP4RtpHintTrack::GetPacketBFrame(u_int16_t packetIndex) +{ + if (m_pReadHint == NULL) { + throw new MP4Error("no hint has been read", + "MP4GetRtpPacketBFrame"); + } + MP4RtpPacket* pPacket = + m_pReadHint->GetPacket(packetIndex); + + return pPacket->IsBFrame(); +} + +u_int16_t MP4RtpHintTrack::GetPacketTransmitOffset(u_int16_t packetIndex) +{ + if (m_pReadHint == NULL) { + throw new MP4Error("no hint has been read", + "MP4GetRtpPacketTransmitOffset"); + } + + MP4RtpPacket* pPacket = + m_pReadHint->GetPacket(packetIndex); + + return pPacket->GetTransmitOffset(); +} + +void MP4RtpHintTrack::ReadPacket( + u_int16_t packetIndex, + u_int8_t** ppBytes, + u_int32_t* pNumBytes, + u_int32_t ssrc, + bool addHeader, + bool addPayload) +{ + if (m_pReadHint == NULL) { + throw new MP4Error("no hint has been read", + "MP4ReadRtpPacket"); + } + if (!addHeader && !addPayload) { + throw new MP4Error("no data requested", + "MP4ReadRtpPacket"); + } + + MP4RtpPacket* pPacket = + m_pReadHint->GetPacket(packetIndex); + + *pNumBytes = 0; + if (addHeader) { + *pNumBytes += 12; + } + if (addPayload) { + *pNumBytes += pPacket->GetDataSize(); + } + + // if needed, allocate the packet memory + bool buffer_malloc = false; + + if (*ppBytes == NULL) { + *ppBytes = (u_int8_t*)MP4Malloc(*pNumBytes); + buffer_malloc = true; + } + + try { + u_int8_t* pDest = *ppBytes; + + if (addHeader) { + *pDest++ = + 0x80 | (pPacket->GetPBit() << 5) | (pPacket->GetXBit() << 4); + + *pDest++ = + (pPacket->GetMBit() << 7) | pPacket->GetPayload(); + + *((u_int16_t*)pDest) = + htons(m_rtpSequenceStart + pPacket->GetSequenceNumber()); + pDest += 2; + + *((u_int32_t*)pDest) = + htonl(m_rtpTimestampStart + (u_int32_t)m_readHintTimestamp); + pDest += 4; + + *((u_int32_t*)pDest) = + htonl(ssrc); + pDest += 4; + } + + if (addPayload) { + pPacket->GetData(pDest); + } + } + catch (MP4Error* e) { + if (buffer_malloc) { + MP4Free(*ppBytes); + *ppBytes = NULL; + } + throw e; + } + + VERBOSE_READ_HINT(m_pFile->GetVerbosity(), + printf("ReadPacket: %u ", packetIndex); + MP4HexDump(*ppBytes, *pNumBytes);); +} + +MP4Timestamp MP4RtpHintTrack::GetRtpTimestampStart() +{ + if (m_pRefTrack == NULL) { + InitRefTrack(); + InitRtpStart(); + } + + return m_rtpTimestampStart; +} + +void MP4RtpHintTrack::SetRtpTimestampStart(MP4Timestamp start) +{ + if (!m_pTsroProperty) { + MP4Atom* pTsroAtom = + m_pFile->AddDescendantAtoms(m_pTrakAtom, "udta.hnti.rtp .tsro"); + + ASSERT(pTsroAtom); + + (void)pTsroAtom->FindProperty("offset", + (MP4Property**)&m_pTsroProperty); + + ASSERT(m_pTsroProperty); + } + + m_pTsroProperty->SetValue(start); + m_rtpTimestampStart = start; +} + +void MP4RtpHintTrack::InitPayload() +{ + ASSERT(m_pTrakAtom); + + if (m_pRtpMapProperty == NULL) { + (void)m_pTrakAtom->FindProperty( + "trak.udta.hinf.payt.rtpMap", + (MP4Property**)&m_pRtpMapProperty); + } + + if (m_pPayloadNumberProperty == NULL) { + (void)m_pTrakAtom->FindProperty( + "trak.udta.hinf.payt.payloadNumber", + (MP4Property**)&m_pPayloadNumberProperty); + } + + if (m_pMaxPacketSizeProperty == NULL) { + (void)m_pTrakAtom->FindProperty( + "trak.mdia.minf.stbl.stsd.rtp .maxPacketSize", + (MP4Property**)&m_pMaxPacketSizeProperty); + } +} + +void MP4RtpHintTrack::GetPayload( + char** ppPayloadName, + u_int8_t* pPayloadNumber, + u_int16_t* pMaxPayloadSize, + char **ppEncodingParams) +{ + const char* pRtpMap; + const char* pSlash; + u_int32_t length; + InitPayload(); + + if (ppPayloadName || ppEncodingParams) { + if (ppPayloadName) + *ppPayloadName = NULL; + if (ppEncodingParams) + *ppEncodingParams = NULL; + if (m_pRtpMapProperty) { + pRtpMap = m_pRtpMapProperty->GetValue(); + pSlash = strchr(pRtpMap, '/'); + + if (pSlash) { + length = pSlash - pRtpMap; + } else { + length = (u_int32_t)strlen(pRtpMap); + } + + if (ppPayloadName) { + *ppPayloadName = (char*)MP4Calloc(length + 1); + strncpy(*ppPayloadName, pRtpMap, length); + } + if (pSlash && ppEncodingParams) { + pSlash++; + pSlash = strchr(pSlash, '/'); + if (pSlash != NULL) { + pSlash++; + if (pSlash != '\0') { + length = (u_int32_t)strlen(pRtpMap) - (pSlash - pRtpMap); + *ppEncodingParams = (char *)MP4Calloc(length + 1); + strncpy(*ppEncodingParams, pSlash, length); + } + } + } + } + } + + if (pPayloadNumber) { + if (m_pPayloadNumberProperty) { + *pPayloadNumber = m_pPayloadNumberProperty->GetValue(); + } else { + *pPayloadNumber = 0; + } + } + + if (pMaxPayloadSize) { + if (m_pMaxPacketSizeProperty) { + *pMaxPayloadSize = m_pMaxPacketSizeProperty->GetValue(); + } else { + *pMaxPayloadSize = 0; + } + } +} + +void MP4RtpHintTrack::SetPayload( + const char* payloadName, + u_int8_t payloadNumber, + u_int16_t maxPayloadSize, + const char *encoding_parms, + bool include_rtp_map, + bool include_mpeg4_esid) +{ + InitRefTrack(); + InitPayload(); + + ASSERT(m_pRtpMapProperty); + ASSERT(m_pPayloadNumberProperty); + ASSERT(m_pMaxPacketSizeProperty); + + size_t len = strlen(payloadName) + 16; + if (encoding_parms != NULL) { + size_t temp = strlen(encoding_parms); + if (temp == 0) { + encoding_parms = NULL; + } else { + len += temp; + } + } + + char* rtpMapBuf = (char*)MP4Malloc(len); + snprintf(rtpMapBuf, len, "%s/%u%c%s", + payloadName, + GetTimeScale(), + encoding_parms != NULL ? '/' : '\0', + encoding_parms == NULL ? "" : encoding_parms); + m_pRtpMapProperty->SetValue(rtpMapBuf); + + m_pPayloadNumberProperty->SetValue(payloadNumber); + + if (maxPayloadSize == 0) { + maxPayloadSize = 1460; + } + m_pMaxPacketSizeProperty->SetValue(maxPayloadSize); + + // set sdp media type + const char* sdpMediaType; + if (!strcmp(m_pRefTrack->GetType(), MP4_AUDIO_TRACK_TYPE)) { + sdpMediaType = "audio"; + } else if (!strcmp(m_pRefTrack->GetType(), MP4_VIDEO_TRACK_TYPE)) { + sdpMediaType = "video"; + } else if (!strcmp(m_pRefTrack->GetType(), MP4_CNTL_TRACK_TYPE)) { + sdpMediaType = "control"; + } else { + sdpMediaType = "application"; + } + + uint32_t maxlen = + (u_int32_t)(strlen(sdpMediaType) + strlen(rtpMapBuf) + 256); + char* sdpBuf = (char*)MP4Malloc(maxlen); + uint32_t buflen; + buflen = snprintf(sdpBuf, maxlen, + "m=%s 0 RTP/AVP %u\015\012" + "a=control:trackID=%u\015\012", + sdpMediaType, payloadNumber, + m_trackId); + if (include_rtp_map) { + buflen += snprintf(sdpBuf + buflen, maxlen - buflen, + "a=rtpmap:%u %s\015\012", + payloadNumber, rtpMapBuf); + } + if (include_mpeg4_esid) { + snprintf(sdpBuf + buflen, maxlen - buflen, + "a=mpeg4-esid:%u\015\012", + m_pRefTrack->GetId()); + } + + MP4StringProperty* pSdpProperty = NULL; + (void)m_pTrakAtom->FindProperty("trak.udta.hnti.sdp .sdpText", + (MP4Property**)&pSdpProperty); + ASSERT(pSdpProperty); + pSdpProperty->SetValue(sdpBuf); + + // cleanup + MP4Free(rtpMapBuf); + MP4Free(sdpBuf); +} + +void MP4RtpHintTrack::AddHint(bool isBFrame, u_int32_t timestampOffset) +{ + // on first hint, need to lookup the reference track + if (m_writeHintId == MP4_INVALID_SAMPLE_ID) { + InitRefTrack(); + InitStats(); + } + + if (m_pWriteHint) { + throw new MP4Error("unwritten hint is still pending", "MP4AddRtpHint"); + } + + m_pWriteHint = new MP4RtpHint(this); + m_pWriteHint->SetBFrame(isBFrame); + m_pWriteHint->SetTimestampOffset(timestampOffset); + + m_bytesThisHint = 0; + m_writeHintId++; +} + +void MP4RtpHintTrack::AddPacket(bool setMbit, int32_t transmitOffset) +{ + if (m_pWriteHint == NULL) { + throw new MP4Error("no hint pending", "MP4RtpAddPacket"); + } + + MP4RtpPacket* pPacket = m_pWriteHint->AddPacket(); + + ASSERT(m_pPayloadNumberProperty); + + pPacket->Set( + m_pPayloadNumberProperty->GetValue(), + m_writePacketId++, + setMbit); + pPacket->SetTransmitOffset(transmitOffset); + + m_bytesThisHint += 12; + if (m_bytesThisPacket > m_pPmax->GetValue()) { + m_pPmax->SetValue(m_bytesThisPacket); + } + m_bytesThisPacket = 12; + m_pNump->IncrementValue(); + m_pTrpy->IncrementValue(12); // RTP packet header size +} + +void MP4RtpHintTrack::AddImmediateData( + const u_int8_t* pBytes, + u_int32_t numBytes) +{ + if (m_pWriteHint == NULL) { + throw new MP4Error("no hint pending", "MP4RtpAddImmediateData"); + } + + MP4RtpPacket* pPacket = m_pWriteHint->GetCurrentPacket(); + if (pPacket == NULL) { + throw new MP4Error("no packet pending", "MP4RtpAddImmediateData"); + } + + if (pBytes == NULL || numBytes == 0) { + throw new MP4Error("no data", + "AddImmediateData"); + } + if (numBytes > 14) { + throw new MP4Error("data size is larger than 14 bytes", + "AddImmediateData"); + } + + MP4RtpImmediateData* pData = new MP4RtpImmediateData(pPacket); + pData->Set(pBytes, numBytes); + + pPacket->AddData(pData); + + m_bytesThisHint += numBytes; + m_bytesThisPacket += numBytes; + m_pDimm->IncrementValue(numBytes); + m_pTpyl->IncrementValue(numBytes); + m_pTrpy->IncrementValue(numBytes); +} + +void MP4RtpHintTrack::AddSampleData( + MP4SampleId sampleId, + u_int32_t dataOffset, + u_int32_t dataLength) +{ + if (m_pWriteHint == NULL) { + throw new MP4Error("no hint pending", "MP4RtpAddSampleData"); + } + + MP4RtpPacket* pPacket = m_pWriteHint->GetCurrentPacket(); + if (pPacket == NULL) { + throw new MP4Error("no packet pending", "MP4RtpAddSampleData"); + } + + MP4RtpSampleData* pData = new MP4RtpSampleData(pPacket); + + pData->SetReferenceSample(sampleId, dataOffset, dataLength); + + pPacket->AddData(pData); + + m_bytesThisHint += dataLength; + m_bytesThisPacket += dataLength; + m_pDmed->IncrementValue(dataLength); + m_pTpyl->IncrementValue(dataLength); + m_pTrpy->IncrementValue(dataLength); +} + +void MP4RtpHintTrack::AddESConfigurationPacket() +{ + if (m_pWriteHint == NULL) { + throw new MP4Error("no hint pending", + "MP4RtpAddESConfigurationPacket"); + } + + u_int8_t* pConfig = NULL; + u_int32_t configSize = 0; + + m_pFile->GetTrackESConfiguration(m_pRefTrack->GetId(), + &pConfig, &configSize); + + if (pConfig == NULL) { + return; + } + + ASSERT(m_pMaxPacketSizeProperty); + + if (configSize > m_pMaxPacketSizeProperty->GetValue()) { + throw new MP4Error("ES configuration is too large for RTP payload", + "MP4RtpAddESConfigurationPacket"); + } + + AddPacket(false); + + MP4RtpPacket* pPacket = m_pWriteHint->GetCurrentPacket(); + ASSERT(pPacket); + + // This is ugly! + // To get the ES configuration data somewhere known + // we create a sample data reference that points to + // this hint track (not the media track) + // and this sample of the hint track + // the offset into this sample is filled in during the write process + MP4RtpSampleData* pData = new MP4RtpSampleData(pPacket); + + pData->SetEmbeddedImmediate(m_writeSampleId, pConfig, configSize); + + pPacket->AddData(pData); + + m_bytesThisHint += configSize; + m_bytesThisPacket += configSize; + m_pTpyl->IncrementValue(configSize); + m_pTrpy->IncrementValue(configSize); +} + +void MP4RtpHintTrack::WriteHint(MP4Duration duration, bool isSyncSample) +{ + if (m_pWriteHint == NULL) { + throw new MP4Error("no hint pending", "MP4WriteRtpHint"); + } + + u_int8_t* pBytes; + u_int64_t numBytes; + + m_pFile->EnableMemoryBuffer(); + + m_pWriteHint->Write(m_pFile); + + m_pFile->DisableMemoryBuffer(&pBytes, &numBytes); + + WriteSample(pBytes, numBytes, duration, 0, isSyncSample); + + MP4Free(pBytes); + + // update statistics + if (m_bytesThisPacket > m_pPmax->GetValue()) { + m_pPmax->SetValue(m_bytesThisPacket); + } + + if (duration > m_pDmax->GetValue()) { + m_pDmax->SetValue(duration); + } + + MP4Timestamp startTime; + + GetSampleTimes(m_writeHintId, &startTime, NULL); + + if (startTime < m_thisSec + GetTimeScale()) { + m_bytesThisSec += m_bytesThisHint; + } else { + if (m_bytesThisSec > m_pMaxr->GetValue()) { + m_pMaxr->SetValue(m_bytesThisSec); + } + m_thisSec = startTime - (startTime % GetTimeScale()); + m_bytesThisSec = m_bytesThisHint; + } + + // cleanup + delete m_pWriteHint; + m_pWriteHint = NULL; +} + +void MP4RtpHintTrack::FinishWrite() +{ + if (m_writeHintId != MP4_INVALID_SAMPLE_ID) { + m_pMaxPdu->SetValue(m_pPmax->GetValue()); + if (m_pNump->GetValue()) { + m_pAvgPdu->SetValue(m_pTrpy->GetValue() / m_pNump->GetValue()); + } + + m_pMaxBitRate->SetValue(m_pMaxr->GetValue() * 8); + if (GetDuration()) { + m_pAvgBitRate->SetValue( + m_pTrpy->GetValue() * 8 * GetTimeScale() / GetDuration()); + } + } + + MP4Track::FinishWrite(); +} + +void MP4RtpHintTrack::InitStats() +{ + MP4Atom* pHinfAtom = m_pTrakAtom->FindAtomMP4("trak.udta.hinf"); + + ASSERT(pHinfAtom); + + (void)pHinfAtom->FindProperty("hinf.trpy.bytes", (MP4Property**)&m_pTrpy); + (void)pHinfAtom->FindProperty("hinf.nump.packets", (MP4Property**)&m_pNump); + (void)pHinfAtom->FindProperty("hinf.tpyl.bytes", (MP4Property**)&m_pTpyl); + (void)pHinfAtom->FindProperty("hinf.maxr.bytes", (MP4Property**)&m_pMaxr); + (void)pHinfAtom->FindProperty("hinf.dmed.bytes", (MP4Property**)&m_pDmed); + (void)pHinfAtom->FindProperty("hinf.dimm.bytes", (MP4Property**)&m_pDimm); + (void)pHinfAtom->FindProperty("hinf.pmax.bytes", (MP4Property**)&m_pPmax); + (void)pHinfAtom->FindProperty("hinf.dmax.milliSecs", (MP4Property**)&m_pDmax); + + MP4Atom* pHmhdAtom = m_pTrakAtom->FindAtomMP4("trak.mdia.minf.hmhd"); + + ASSERT(pHmhdAtom); + + (void)pHmhdAtom->FindProperty("hmhd.maxPduSize", (MP4Property**)&m_pMaxPdu); + (void)pHmhdAtom->FindProperty("hmhd.avgPduSize", (MP4Property**)&m_pAvgPdu); + (void)pHmhdAtom->FindProperty("hmhd.maxBitRate", (MP4Property**)&m_pMaxBitRate); + (void)pHmhdAtom->FindProperty("hmhd.avgBitRate", (MP4Property**)&m_pAvgBitRate); + + MP4Integer32Property* pMaxrPeriod = NULL; + (void)pHinfAtom->FindProperty("hinf.maxr.granularity", + (MP4Property**)&pMaxrPeriod); + if (pMaxrPeriod) { + pMaxrPeriod->SetValue(1000); // 1 second + } +} + + +MP4RtpHint::MP4RtpHint(MP4RtpHintTrack* pTrack) +{ + m_pTrack = pTrack; + m_isBFrame = false; + m_timestampOffset = 0; + + AddProperty( /* 0 */ + new MP4Integer16Property("packetCount")); + AddProperty( /* 1 */ + new MP4Integer16Property("reserved")); +} + +MP4RtpHint::~MP4RtpHint() +{ + for (u_int32_t i = 0; i < m_rtpPackets.Size(); i++) { + delete m_rtpPackets[i]; + } +} + +MP4RtpPacket* MP4RtpHint::AddPacket() +{ + MP4RtpPacket* pPacket = new MP4RtpPacket(this); + m_rtpPackets.Add(pPacket); + + // packetCount property + ((MP4Integer16Property*)m_pProperties[0])->IncrementValue(); + + pPacket->SetBFrame(m_isBFrame); + pPacket->SetTimestampOffset(m_timestampOffset); + + return pPacket; +} + +void MP4RtpHint::Read(MP4File* pFile) +{ + // call base class Read for required properties + MP4Container::Read(pFile); + + u_int16_t numPackets = + ((MP4Integer16Property*)m_pProperties[0])->GetValue(); + + for (u_int16_t i = 0; i < numPackets; i++) { + MP4RtpPacket* pPacket = new MP4RtpPacket(this); + + m_rtpPackets.Add(pPacket); + + pPacket->Read(pFile); + } + +} + +void MP4RtpHint::Write(MP4File* pFile) +{ + u_int64_t hintStartPos = pFile->GetPosition(); + + MP4Container::Write(pFile); + + u_int64_t packetStartPos = pFile->GetPosition(); + + u_int32_t i; + + // first write out packet (and data) entries + for (i = 0; i < m_rtpPackets.Size(); i++) { + m_rtpPackets[i]->Write(pFile); + } + + // now let packets write their extra data into the hint sample + for (i = 0; i < m_rtpPackets.Size(); i++) { + m_rtpPackets[i]->WriteEmbeddedData(pFile, hintStartPos); + } + + u_int64_t endPos = pFile->GetPosition(); + + pFile->SetPosition(packetStartPos); + + // finally rewrite the packet and data entries + // which now contain the correct offsets for the embedded data + for (i = 0; i < m_rtpPackets.Size(); i++) { + m_rtpPackets[i]->Write(pFile); + } + + pFile->SetPosition(endPos); +} + +MP4RtpPacket::MP4RtpPacket(MP4RtpHint* pHint) +{ + m_pHint = pHint; + + AddProperty( /* 0 */ + new MP4Integer32Property("relativeXmitTime")); + AddProperty( /* 1 */ + new MP4BitfieldProperty("reserved1", 2)); + AddProperty( /* 2 */ + new MP4BitfieldProperty("Pbit", 1)); + AddProperty( /* 3 */ + new MP4BitfieldProperty("Xbit", 1)); + AddProperty( /* 4 */ + new MP4BitfieldProperty("reserved2", 4)); + AddProperty( /* 5 */ + new MP4BitfieldProperty("Mbit", 1)); + AddProperty( /* 6 */ + new MP4BitfieldProperty("payloadType", 7)); + AddProperty( /* 7 */ + new MP4Integer16Property("sequenceNumber")); + AddProperty( /* 8 */ + new MP4BitfieldProperty("reserved3", 13)); + AddProperty( /* 9 */ + new MP4BitfieldProperty("extraFlag", 1)); + AddProperty( /* 10 */ + new MP4BitfieldProperty("bFrameFlag", 1)); + AddProperty( /* 11 */ + new MP4BitfieldProperty("repeatFlag", 1)); + AddProperty( /* 12 */ + new MP4Integer16Property("entryCount")); +} + +MP4RtpPacket::~MP4RtpPacket() +{ + for (u_int32_t i = 0; i < m_rtpData.Size(); i++) { + delete m_rtpData[i]; + } +} + +void MP4RtpPacket::AddExtraProperties() +{ + AddProperty( /* 13 */ + new MP4Integer32Property("extraInformationLength")); + + // This is a bit of a hack, since the tlv entries are really defined + // as atoms but there is only one type defined now, rtpo, and getting + // our atom code hooked up here would be a major pain with little gain + + AddProperty( /* 14 */ + new MP4Integer32Property("tlvLength")); + AddProperty( /* 15 */ + new MP4StringProperty("tlvType")); + AddProperty( /* 16 */ + new MP4Integer32Property("timestampOffset")); + + ((MP4Integer32Property*)m_pProperties[13])->SetValue(16); + ((MP4Integer32Property*)m_pProperties[14])->SetValue(12); + ((MP4StringProperty*)m_pProperties[15])->SetFixedLength(4); + ((MP4StringProperty*)m_pProperties[15])->SetValue("rtpo"); +} + +void MP4RtpPacket::Read(MP4File* pFile) +{ + // call base class Read for required properties + MP4Container::Read(pFile); + + // read extra info if present + // we only support the rtpo field! + if (((MP4BitfieldProperty*)m_pProperties[9])->GetValue() == 1) { + ReadExtra(pFile); + } + + u_int16_t numDataEntries = + ((MP4Integer16Property*)m_pProperties[12])->GetValue(); + + // read data entries + for (u_int16_t i = 0; i < numDataEntries; i++) { + u_int8_t dataType; + pFile->PeekBytes(&dataType, 1); + + MP4RtpData* pData; + + switch (dataType) { + case 0: + pData = new MP4RtpNullData(this); + break; + case 1: + pData = new MP4RtpImmediateData(this); + break; + case 2: + pData = new MP4RtpSampleData(this); + break; + case 3: + pData = new MP4RtpSampleDescriptionData(this); + break; + default: + throw new MP4Error("unknown packet data entry type", + "MP4ReadHint"); + } + + m_rtpData.Add(pData); + + // read data entry's properties + pData->Read(pFile); + } +} + +void MP4RtpPacket::ReadExtra(MP4File* pFile) +{ + AddExtraProperties(); + + int32_t extraLength = (int32_t)pFile->ReadUInt32(); + + if (extraLength < 4) { + throw new MP4Error("bad packet extra info length", + "MP4RtpPacket::ReadExtra"); + } + extraLength -= 4; + + while (extraLength > 0) { + u_int32_t entryLength = pFile->ReadUInt32(); + u_int32_t entryTag = pFile->ReadUInt32(); + + if (entryLength < 8) { + throw new MP4Error("bad packet extra info entry length", + "MP4RtpPacket::ReadExtra"); + } + + if (entryTag == STRTOINT32("rtpo") && entryLength == 12) { + // read the rtp timestamp offset + m_pProperties[16]->Read(pFile); + } else { + // ignore it, LATER carry it along + pFile->SetPosition(pFile->GetPosition() + entryLength - 8); + } + + extraLength -= entryLength; + } + + if (extraLength < 0) { + throw new MP4Error("invalid packet extra info length", + "MP4RtpPacket::ReadExtra"); + } +} + +void MP4RtpPacket::Set(u_int8_t payloadNumber, + u_int32_t packetId, bool setMbit) +{ + ((MP4BitfieldProperty*)m_pProperties[5])->SetValue(setMbit); + ((MP4BitfieldProperty*)m_pProperties[6])->SetValue(payloadNumber); + ((MP4Integer16Property*)m_pProperties[7])->SetValue(packetId); +} + +int32_t MP4RtpPacket::GetTransmitOffset() +{ + return ((MP4Integer32Property*)m_pProperties[0])->GetValue(); +} + +void MP4RtpPacket::SetTransmitOffset(int32_t transmitOffset) +{ + ((MP4Integer32Property*)m_pProperties[0])->SetValue(transmitOffset); +} + +bool MP4RtpPacket::GetPBit() +{ + return ((MP4BitfieldProperty*)m_pProperties[2])->GetValue(); +} + +bool MP4RtpPacket::GetXBit() +{ + return ((MP4BitfieldProperty*)m_pProperties[3])->GetValue(); +} + +bool MP4RtpPacket::GetMBit() +{ + return ((MP4BitfieldProperty*)m_pProperties[5])->GetValue(); +} + +u_int8_t MP4RtpPacket::GetPayload() +{ + return ((MP4BitfieldProperty*)m_pProperties[6])->GetValue(); +} + +u_int16_t MP4RtpPacket::GetSequenceNumber() +{ + return ((MP4Integer16Property*)m_pProperties[7])->GetValue(); +} + +bool MP4RtpPacket::IsBFrame() +{ + return ((MP4BitfieldProperty*)m_pProperties[10])->GetValue(); +} + +void MP4RtpPacket::SetBFrame(bool isBFrame) +{ + ((MP4BitfieldProperty*)m_pProperties[10])->SetValue(isBFrame); +} + +void MP4RtpPacket::SetTimestampOffset(u_int32_t timestampOffset) +{ + if (timestampOffset == 0) { + return; + } + + ASSERT(((MP4BitfieldProperty*)m_pProperties[9])->GetValue() == 0); + + // set X bit + ((MP4BitfieldProperty*)m_pProperties[9])->SetValue(1); + + AddExtraProperties(); + + ((MP4Integer32Property*)m_pProperties[16])->SetValue(timestampOffset); +} + +void MP4RtpPacket::AddData(MP4RtpData* pData) +{ + m_rtpData.Add(pData); + + // increment entry count property + ((MP4Integer16Property*)m_pProperties[12])->IncrementValue(); +} + +u_int32_t MP4RtpPacket::GetDataSize() +{ + u_int32_t totalDataSize = 0; + + for (u_int32_t i = 0; i < m_rtpData.Size(); i++) { + totalDataSize += m_rtpData[i]->GetDataSize(); + } + + return totalDataSize; +} + +void MP4RtpPacket::GetData(u_int8_t* pDest) +{ + for (u_int32_t i = 0; i < m_rtpData.Size(); i++) { + m_rtpData[i]->GetData(pDest); + pDest += m_rtpData[i]->GetDataSize(); + } +} + +void MP4RtpPacket::Write(MP4File* pFile) +{ + MP4Container::Write(pFile); + + for (u_int32_t i = 0; i < m_rtpData.Size(); i++) { + m_rtpData[i]->Write(pFile); + } +} + +void MP4RtpPacket::WriteEmbeddedData(MP4File* pFile, u_int64_t startPos) +{ + for (u_int32_t i = 0; i < m_rtpData.Size(); i++) { + m_rtpData[i]->WriteEmbeddedData(pFile, startPos); + } +} + +MP4RtpData::MP4RtpData(MP4RtpPacket* pPacket) +{ + m_pPacket = pPacket; + + AddProperty( /* 0 */ + new MP4Integer8Property("type")); +} + +MP4Track* MP4RtpData::FindTrackFromRefIndex(u_int8_t refIndex) +{ + MP4Track* pTrack; + + if (refIndex == (u_int8_t)-1) { + // ourselves + pTrack = GetPacket()->GetHint()->GetTrack(); + } else if (refIndex == 0) { + // our reference track + pTrack = GetPacket()->GetHint()->GetTrack()->GetRefTrack(); + } else { + // some other track + MP4RtpHintTrack* pHintTrack = + GetPacket()->GetHint()->GetTrack(); + + MP4Atom* pTrakAtom = pHintTrack->GetTrakAtom(); + ASSERT(pTrakAtom); + + MP4Integer32Property* pTrackIdProperty = NULL; + (void)pTrakAtom->FindProperty( + "trak.tref.hint.entries", + (MP4Property**)&pTrackIdProperty); + ASSERT(pTrackIdProperty); + + u_int32_t refTrackId = + pTrackIdProperty->GetValue(refIndex - 1); + + pTrack = pHintTrack->GetFile()->GetTrack(refTrackId); + } + + return pTrack; +} + +MP4RtpNullData::MP4RtpNullData(MP4RtpPacket* pPacket) + : MP4RtpData(pPacket) +{ + ((MP4Integer8Property*)m_pProperties[0])->SetValue(0); + + AddProperty( /* 1 */ + new MP4BytesProperty("pad", 15)); + + ((MP4BytesProperty*)m_pProperties[1])->SetFixedSize(15); +} + +MP4RtpImmediateData::MP4RtpImmediateData(MP4RtpPacket* pPacket) + : MP4RtpData(pPacket) +{ + ((MP4Integer8Property*)m_pProperties[0])->SetValue(1); + + AddProperty( /* 1 */ + new MP4Integer8Property("count")); + AddProperty( /* 2 */ + new MP4BytesProperty("data", 14)); + + ((MP4BytesProperty*)m_pProperties[2])->SetFixedSize(14); +} + +void MP4RtpImmediateData::Set(const u_int8_t* pBytes, u_int8_t numBytes) +{ + ((MP4Integer8Property*)m_pProperties[1])->SetValue(numBytes); + ((MP4BytesProperty*)m_pProperties[2])->SetValue(pBytes, numBytes); +} + +u_int16_t MP4RtpImmediateData::GetDataSize() +{ + return ((MP4Integer8Property*)m_pProperties[1])->GetValue(); +} + +void MP4RtpImmediateData::GetData(u_int8_t* pDest) +{ + u_int8_t* pValue; + u_int32_t valueSize; + ((MP4BytesProperty*)m_pProperties[2])->GetValue(&pValue, &valueSize); + + memcpy(pDest, pValue, GetDataSize()); + MP4Free(pValue); +} + +MP4RtpSampleData::MP4RtpSampleData(MP4RtpPacket* pPacket) + : MP4RtpData(pPacket) +{ + ((MP4Integer8Property*)m_pProperties[0])->SetValue(2); + + AddProperty( /* 1 */ + new MP4Integer8Property("trackRefIndex")); + AddProperty( /* 2 */ + new MP4Integer16Property("length")); + AddProperty( /* 3 */ + new MP4Integer32Property("sampleNumber")); + AddProperty( /* 4 */ + new MP4Integer32Property("sampleOffset")); + AddProperty( /* 5 */ + new MP4Integer16Property("bytesPerBlock")); + AddProperty( /* 6 */ + new MP4Integer16Property("samplesPerBlock")); + + ((MP4Integer16Property*)m_pProperties[5])->SetValue(1); + ((MP4Integer16Property*)m_pProperties[6])->SetValue(1); + + m_pRefData = NULL; + m_pRefTrack = NULL; + m_refSampleId = MP4_INVALID_SAMPLE_ID; + m_refSampleOffset = 0; +} + +void MP4RtpSampleData::SetEmbeddedImmediate(MP4SampleId sampleId, + u_int8_t* pData, u_int16_t dataLength) +{ + ((MP4Integer8Property*)m_pProperties[1])->SetValue((u_int8_t)-1); + ((MP4Integer16Property*)m_pProperties[2])->SetValue(dataLength); + ((MP4Integer32Property*)m_pProperties[3])->SetValue(sampleId); + ((MP4Integer32Property*)m_pProperties[4])->SetValue(0); + CHECK_AND_FREE(m_pRefData); + m_pRefData = pData; +} + +void MP4RtpSampleData::SetReferenceSample( + MP4SampleId refSampleId, u_int32_t refSampleOffset, + u_int16_t sampleLength) +{ + ((MP4Integer8Property*)m_pProperties[1])->SetValue(0); + ((MP4Integer16Property*)m_pProperties[2])->SetValue(sampleLength); + ((MP4Integer32Property*)m_pProperties[3])->SetValue(refSampleId); + ((MP4Integer32Property*)m_pProperties[4])->SetValue(refSampleOffset); +} + +void MP4RtpSampleData::SetEmbeddedSample( + MP4SampleId sampleId, MP4Track* pRefTrack, + MP4SampleId refSampleId, u_int32_t refSampleOffset, + u_int16_t sampleLength) +{ + ((MP4Integer8Property*)m_pProperties[1])->SetValue((u_int8_t)-1); + ((MP4Integer16Property*)m_pProperties[2])->SetValue(sampleLength); + ((MP4Integer32Property*)m_pProperties[3])->SetValue(sampleId); + ((MP4Integer32Property*)m_pProperties[4])->SetValue(0); + m_pRefTrack = pRefTrack; + m_refSampleId = refSampleId; + m_refSampleOffset = refSampleOffset; +} + +u_int16_t MP4RtpSampleData::GetDataSize() +{ + return ((MP4Integer16Property*)m_pProperties[2])->GetValue(); +} + +void MP4RtpSampleData::GetData(u_int8_t* pDest) +{ + u_int8_t trackRefIndex = + ((MP4Integer8Property*)m_pProperties[1])->GetValue(); + + MP4Track* pSampleTrack = + FindTrackFromRefIndex(trackRefIndex); + + pSampleTrack->ReadSampleFragment( + ((MP4Integer32Property*)m_pProperties[3])->GetValue(), // sampleId + ((MP4Integer32Property*)m_pProperties[4])->GetValue(), // sampleOffset + ((MP4Integer16Property*)m_pProperties[2])->GetValue(), // sampleLength + pDest); +} + +void MP4RtpSampleData::WriteEmbeddedData(MP4File* pFile, u_int64_t startPos) +{ + // if not using embedded data, nothing to do + if (((MP4Integer8Property*)m_pProperties[1])->GetValue() != (u_int8_t)-1) { + return; + } + + // figure out the offset within this hint sample for this embedded data + u_int64_t offset = pFile->GetPosition() - startPos; + ASSERT(offset <= 0xFFFFFFFF); + ((MP4Integer32Property*)m_pProperties[4])->SetValue((u_int32_t)offset); + + u_int16_t length = ((MP4Integer16Property*)m_pProperties[2])->GetValue(); + + if (m_pRefData) { + pFile->WriteBytes(m_pRefData, length); + return; + } + + if (m_refSampleId != MP4_INVALID_SAMPLE_ID) { + u_int8_t* pSample = NULL; + u_int32_t sampleSize = 0; + + ASSERT(m_pRefTrack); + m_pRefTrack->ReadSample(m_refSampleId, &pSample, &sampleSize); + + ASSERT(m_refSampleOffset + length <= sampleSize); + + pFile->WriteBytes(&pSample[m_refSampleOffset], length); + + MP4Free(pSample); + return; + } +} + +MP4RtpSampleDescriptionData::MP4RtpSampleDescriptionData(MP4RtpPacket* pPacket) + : MP4RtpData(pPacket) +{ + ((MP4Integer8Property*)m_pProperties[0])->SetValue(3); + + AddProperty( /* 1 */ + new MP4Integer8Property("trackRefIndex")); + AddProperty( /* 2 */ + new MP4Integer16Property("length")); + AddProperty( /* 3 */ + new MP4Integer32Property("sampleDescriptionIndex")); + AddProperty( /* 4 */ + new MP4Integer32Property("sampleDescriptionOffset")); + AddProperty( /* 5 */ + new MP4Integer32Property("reserved")); +} + +void MP4RtpSampleDescriptionData::Set(u_int32_t sampleDescrIndex, + u_int32_t offset, u_int16_t length) +{ + ((MP4Integer16Property*)m_pProperties[2])->SetValue(length); + ((MP4Integer32Property*)m_pProperties[3])->SetValue(sampleDescrIndex); + ((MP4Integer32Property*)m_pProperties[4])->SetValue(offset); +} + +u_int16_t MP4RtpSampleDescriptionData::GetDataSize() +{ + return ((MP4Integer16Property*)m_pProperties[2])->GetValue(); +} + +void MP4RtpSampleDescriptionData::GetData(u_int8_t* pDest) +{ + // we start with the index into our track references + u_int8_t trackRefIndex = + ((MP4Integer8Property*)m_pProperties[1])->GetValue(); + + // from which we can find the track structure + MP4Track* pSampleTrack = + FindTrackFromRefIndex(trackRefIndex); + + // next find the desired atom in the track's sample description table + u_int32_t sampleDescrIndex = + ((MP4Integer32Property*)m_pProperties[3])->GetValue(); + + MP4Atom* pTrakAtom = + pSampleTrack->GetTrakAtom(); + + char sdName[64]; + snprintf(sdName, 64, "trak.mdia.minf.stbl.stsd.*[%u]", sampleDescrIndex); + + MP4Atom* pSdAtom = + pTrakAtom->FindAtomMP4(sdName); + + // bad reference + if (pSdAtom == NULL) { + throw new MP4Error("invalid sample description index", + "MP4RtpSampleDescriptionData::GetData"); + } + + // check validity of the upcoming copy + u_int16_t length = + ((MP4Integer16Property*)m_pProperties[2])->GetValue(); + u_int32_t offset = + ((MP4Integer32Property*)m_pProperties[4])->GetValue(); + + if (offset + length > pSdAtom->GetSize()) { + throw new MP4Error("offset and/or length are too large", + "MP4RtpSampleDescriptionData::GetData"); + } + + // now we use the raw file to get the desired bytes + + MP4File* pFile = GetPacket()->GetHint()->GetTrack()->GetFile(); + + u_int64_t orgPos = pFile->GetPosition(); + + // It's not entirely clear from the spec whether the offset is from + // the start of the sample descirption atom, or the start of the atom's + // data. I believe it is the former, but the commented out code will + // realize the latter interpretation if I turn out to be wrong. + u_int64_t dataPos = pSdAtom->GetStart(); + //u_int64_t dataPos = pSdAtom->GetEnd() - pSdAtom->GetSize(); + + pFile->SetPosition(dataPos + offset); + + pFile->ReadBytes(pDest, length); + + pFile->SetPosition(orgPos); +} + diff --git a/Src/external_dependencies/libmp4v2/rtphint.h b/Src/external_dependencies/libmp4v2/rtphint.h new file mode 100644 index 00000000..d8db7324 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/rtphint.h @@ -0,0 +1,348 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + */ + +#ifndef __RTPHINT_INCLUDED__ +#define __RTPHINT_INCLUDED__ + +// forward declarations +class MP4RtpHintTrack; +class MP4RtpHint; +class MP4RtpPacket; + +class MP4RtpData : public MP4Container { +public: + MP4RtpData(MP4RtpPacket* pPacket); + + MP4RtpPacket* GetPacket() { + return m_pPacket; + } + + virtual u_int16_t GetDataSize() = 0; + virtual void GetData(u_int8_t* pDest) = 0; + + MP4Track* FindTrackFromRefIndex(u_int8_t refIndex); + + virtual void WriteEmbeddedData(MP4File* pFile, u_int64_t startPos) { + // default is no-op + } + +protected: + MP4RtpPacket* m_pPacket; +}; + +MP4ARRAY_DECL(MP4RtpData, MP4RtpData*) + +class MP4RtpNullData : public MP4RtpData { +public: + MP4RtpNullData(MP4RtpPacket* pPacket); + + u_int16_t GetDataSize() { + return 0; + } + + void GetData(u_int8_t* pDest) { + // no-op + } +}; + +class MP4RtpImmediateData : public MP4RtpData { +public: + MP4RtpImmediateData(MP4RtpPacket* pPacket); + + void Set(const u_int8_t* pBytes, u_int8_t numBytes); + + u_int16_t GetDataSize(); + + void GetData(u_int8_t* pDest); +}; + +class MP4RtpSampleData : public MP4RtpData { +public: + MP4RtpSampleData(MP4RtpPacket* pPacket); + + ~MP4RtpSampleData(void) { + CHECK_AND_FREE(m_pRefData); + }; + + void SetEmbeddedImmediate( + MP4SampleId sampleId, + u_int8_t* pData, u_int16_t dataLength); + + void SetReferenceSample( + MP4SampleId refSampleId, u_int32_t refSampleOffset, + u_int16_t sampleLength); + + void SetEmbeddedSample( + MP4SampleId sampleId, MP4Track* pRefTrack, + MP4SampleId refSampleId, u_int32_t refSampleOffset, + u_int16_t sampleLength); + + u_int16_t GetDataSize(); + + void GetData(u_int8_t* pDest); + + void WriteEmbeddedData(MP4File* pFile, u_int64_t startPos); + +protected: + u_int8_t* m_pRefData; + + MP4Track* m_pRefTrack; + MP4SampleId m_refSampleId; + u_int32_t m_refSampleOffset; +}; + +class MP4RtpSampleDescriptionData : public MP4RtpData { +public: + MP4RtpSampleDescriptionData(MP4RtpPacket* pPacket); + + void Set(u_int32_t sampleDescrIndex, + u_int32_t offset, u_int16_t length); + + u_int16_t GetDataSize(); + + void GetData(u_int8_t* pDest); +}; + +class MP4RtpPacket : public MP4Container { +public: + MP4RtpPacket(MP4RtpHint* pHint); + + ~MP4RtpPacket(); + + void AddExtraProperties(); + + MP4RtpHint* GetHint() { + return m_pHint; + } + + void Set(u_int8_t payloadNumber, u_int32_t packetId, bool setMbit); + + int32_t GetTransmitOffset(); + + bool GetPBit(); + + bool GetXBit(); + + bool GetMBit(); + + u_int8_t GetPayload(); + + u_int16_t GetSequenceNumber(); + + void SetTransmitOffset(int32_t transmitOffset); + + bool IsBFrame(); + + void SetBFrame(bool isBFrame); + + void SetTimestampOffset(u_int32_t timestampOffset); + + void AddData(MP4RtpData* pData); + + u_int32_t GetDataSize(); + + void GetData(u_int8_t* pDest); + + void Read(MP4File* pFile); + + void ReadExtra(MP4File* pFile); + + void Write(MP4File* pFile); + + void WriteEmbeddedData(MP4File* pFile, u_int64_t startPos); + +protected: + MP4RtpHint* m_pHint; + MP4RtpDataArray m_rtpData; +}; + +MP4ARRAY_DECL(MP4RtpPacket, MP4RtpPacket*) + +class MP4RtpHint : public MP4Container { +public: + MP4RtpHint(MP4RtpHintTrack* pTrack); + + ~MP4RtpHint(); + + MP4RtpHintTrack* GetTrack() { + return m_pTrack; + } + + u_int16_t GetNumberOfPackets() { + return m_rtpPackets.Size(); + } + + bool IsBFrame() { + return m_isBFrame; + } + void SetBFrame(bool isBFrame) { + m_isBFrame = isBFrame; + } + + u_int32_t GetTimestampOffset() { + return m_timestampOffset; + } + void SetTimestampOffset(u_int32_t timestampOffset) { + m_timestampOffset = timestampOffset; + } + + MP4RtpPacket* AddPacket(); + + MP4RtpPacket* GetPacket(u_int16_t index) { + return m_rtpPackets[index]; + } + + MP4RtpPacket* GetCurrentPacket() { + if (m_rtpPackets.Size() == 0) { + return NULL; + } + return m_rtpPackets[m_rtpPackets.Size() - 1]; + } + + void Read(MP4File* pFile); + + void Write(MP4File* pFile); + +protected: + MP4RtpHintTrack* m_pTrack; + MP4RtpPacketArray m_rtpPackets; + + // values when adding packets to a hint (write mode) + bool m_isBFrame; + u_int32_t m_timestampOffset; +}; + +class MP4RtpHintTrack : public MP4Track { +public: + MP4RtpHintTrack(MP4File* pFile, MP4Atom* pTrakAtom); + + ~MP4RtpHintTrack(); + + void InitRefTrack(); + + void InitPayload(); + + void InitRtpStart(); + + void InitStats(); + + MP4Track* GetRefTrack() { + InitRefTrack(); + return m_pRefTrack; + } + + void GetPayload( + char** ppPayloadName = NULL, + u_int8_t* pPayloadNumber = NULL, + u_int16_t* pMaxPayloadSize = NULL, + char **ppEncodingParams = NULL); + + void SetPayload( + const char* payloadName, + u_int8_t payloadNumber, + u_int16_t maxPayloadSize, + const char *encoding_parms, + bool add_rtpmap, + bool add_mpeg4_esid); + + void ReadHint( + MP4SampleId hintSampleId, + u_int16_t* pNumPackets = NULL); + + u_int16_t GetHintNumberOfPackets(); + + bool GetPacketBFrame(u_int16_t packetIndex); + + u_int16_t GetPacketTransmitOffset(u_int16_t packetIndex); + + void ReadPacket( + u_int16_t packetIndex, + u_int8_t** ppBytes, + u_int32_t* pNumBytes, + u_int32_t ssrc, + bool includeHeader = true, + bool includePayload = true); + + MP4Timestamp GetRtpTimestampStart(); + + void SetRtpTimestampStart(MP4Timestamp start); + + void AddHint(bool isBFrame, u_int32_t timestampOffset); + + void AddPacket(bool setMbit, int32_t transmitOffset = 0); + + void AddImmediateData(const u_int8_t* pBytes, u_int32_t numBytes); + + void AddSampleData(MP4SampleId sampleId, + u_int32_t dataOffset, u_int32_t dataLength); + + void AddESConfigurationPacket(); + + void WriteHint(MP4Duration duration, bool isSyncSample); + + void FinishWrite(); + +protected: + MP4Track* m_pRefTrack; + + MP4StringProperty* m_pRtpMapProperty; + MP4Integer32Property* m_pPayloadNumberProperty; + MP4Integer32Property* m_pMaxPacketSizeProperty; + MP4Integer32Property* m_pSnroProperty; + MP4Integer32Property* m_pTsroProperty; + u_int32_t m_rtpSequenceStart; + u_int32_t m_rtpTimestampStart; + + // reading + MP4RtpHint* m_pReadHint; + u_int8_t* m_pReadHintSample; + u_int32_t m_readHintSampleSize; + MP4Timestamp m_readHintTimestamp; + + // writing + MP4RtpHint* m_pWriteHint; + MP4SampleId m_writeHintId; + u_int32_t m_writePacketId; + + // statistics + // in trak.udta.hinf + MP4Integer64Property* m_pTrpy; + MP4Integer64Property* m_pNump; + MP4Integer64Property* m_pTpyl; + MP4Integer32Property* m_pMaxr; + MP4Integer64Property* m_pDmed; + MP4Integer64Property* m_pDimm; + MP4Integer32Property* m_pPmax; + MP4Integer32Property* m_pDmax; + + // in trak.mdia.minf.hmhd + MP4Integer16Property* m_pMaxPdu; + MP4Integer16Property* m_pAvgPdu; + MP4Integer32Property* m_pMaxBitRate; + MP4Integer32Property* m_pAvgBitRate; + + MP4Timestamp m_thisSec; + u_int32_t m_bytesThisSec; + u_int32_t m_bytesThisHint; + u_int32_t m_bytesThisPacket; +}; + +#endif /* __RTPHINT_INCLUDED__ */ diff --git a/Src/external_dependencies/libmp4v2/version.rc2 b/Src/external_dependencies/libmp4v2/version.rc2 new file mode 100644 index 00000000..e2d93528 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/version.rc2 @@ -0,0 +1,38 @@ + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// +#include "../../Winamp/buildType.h" +VS_VERSION_INFO VERSIONINFO + FILEVERSION WINAMP_PRODUCTVER + PRODUCTVERSION WINAMP_PRODUCTVER + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Winamp SA" + VALUE "FileDescription", "Winamp Support Library" + VALUE "FileVersion", STR_WINAMP_PRODUCTVER + VALUE "InternalName", "libmp4v2.dll" + VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA" + VALUE "OriginalFilename", "libmp4v2.dll" + VALUE "ProductName", "Winamp libmp4v2 Library" + VALUE "ProductVersion", STR_WINAMP_PRODUCTVER + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/Src/external_dependencies/libmp4v2/virtual_io.cpp b/Src/external_dependencies/libmp4v2/virtual_io.cpp new file mode 100644 index 00000000..9acfef5c --- /dev/null +++ b/Src/external_dependencies/libmp4v2/virtual_io.cpp @@ -0,0 +1,92 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001 - 2005. All Rights Reserved. + * + * Contributor(s): + * Ben Allison benski at nullsoft.com + * + * Virtual I/O support, for file support other than fopen/fread/fwrite + */ + +#include "mp4common.h" +#include "virtual_io.h" + +/* --------- Virtual IO for FILE * --------- */ + +u_int64_t FILE_GetFileLength(void *user) +{ + FILE *fp = (FILE *)user; + struct stat s; + if (fstat(fileno(fp), &s) < 0) { + throw new MP4Error(errno, "stat failed", "MP4Open"); + } + return s.st_size; +} + +int FILE_SetPosition(void *user, u_int64_t position) +{ + FILE *fp = (FILE *)user; + fpos_t fpos; + VAR_TO_FPOS(fpos, position); + return fsetpos(fp, &fpos); +} + +int FILE_GetPosition(void *user, u_int64_t *position) +{ + FILE *fp = (FILE *)user; + fpos_t fpos; + if (fgetpos(fp, &fpos) < 0) { + throw new MP4Error(errno, "MP4GetPosition"); + } + + FPOS_TO_VAR(fpos, u_int64_t, *position); + return 0; +} + +size_t FILE_Read(void *user, void *buffer, size_t size) +{ + FILE *fp = (FILE *)user; + return fread(buffer, 1, size, fp); +} + +size_t FILE_Write(void *user, void *buffer, size_t size) +{ + FILE *fp = (FILE *)user; + return fwrite(buffer, 1, size, fp); +} + +int FILE_EndOfFile(void *user) +{ + FILE *fp = (FILE *)user; + return feof(fp); +} + +int FILE_Close(void *user) +{ + FILE *fp = (FILE *)user; + return fclose(fp); +} + +Virtual_IO FILE_virtual_IO = +{ + FILE_GetFileLength, + FILE_SetPosition, + FILE_GetPosition, + FILE_Read, + FILE_Write, + FILE_EndOfFile, + FILE_Close, +}; diff --git a/Src/external_dependencies/libmp4v2/virtual_io.h b/Src/external_dependencies/libmp4v2/virtual_io.h new file mode 100644 index 00000000..b2566e86 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/virtual_io.h @@ -0,0 +1,31 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001 - 2005. All Rights Reserved. + * + * Contributor(s): + * Ben Allison benski at nullsoft.com + * + * Virtual I/O support, for file support other than fopen/fread/fwrite + */ + +#ifndef __VIRTUAL_IO_INCLUDED__ +#define __VIRTUAL_IO_INCLUDED__ + +#include "mpeg4ip.h" + +extern Virtual_IO FILE_virtual_IO; + +#endif |